/** * Print all of a program's parameters/fields to given file. */ static void _mesa_fprint_program_parameters(FILE *f, GLcontext *ctx, const struct gl_program *prog) { GLuint i; _mesa_fprintf(f, "InputsRead: 0x%x\n", prog->InputsRead); _mesa_fprintf(f, "OutputsWritten: 0x%x\n", prog->OutputsWritten); _mesa_fprintf(f, "NumInstructions=%d\n", prog->NumInstructions); _mesa_fprintf(f, "NumTemporaries=%d\n", prog->NumTemporaries); _mesa_fprintf(f, "NumParameters=%d\n", prog->NumParameters); _mesa_fprintf(f, "NumAttributes=%d\n", prog->NumAttributes); _mesa_fprintf(f, "NumAddressRegs=%d\n", prog->NumAddressRegs); _mesa_fprintf(f, "Samplers=[ "); for (i = 0; i < MAX_SAMPLERS; i++) { _mesa_fprintf(f, "%d ", prog->SamplerUnits[i]); } _mesa_fprintf(f, "]\n"); _mesa_load_state_parameters(ctx, prog->Parameters); #if 0 _mesa_fprintf(f, "Local Params:\n"); for (i = 0; i < MAX_PROGRAM_LOCAL_PARAMS; i++){ const GLfloat *p = prog->LocalParams[i]; _mesa_fprintf(f, "%2d: %f, %f, %f, %f\n", i, p[0], p[1], p[2], p[3]); } #endif _mesa_print_parameter_list(prog->Parameters); }
/** * Pass the given program parameters to the graphics pipe as a * constant buffer. * \param shader_type either PIPE_SHADER_VERTEX or PIPE_SHADER_FRAGMENT */ void st_upload_constants( struct st_context *st, struct gl_program_parameter_list *params, unsigned shader_type) { assert(shader_type == PIPE_SHADER_VERTEX || shader_type == PIPE_SHADER_FRAGMENT || shader_type == PIPE_SHADER_GEOMETRY || shader_type == PIPE_SHADER_TESS_CTRL || shader_type == PIPE_SHADER_TESS_EVAL); /* update constants */ if (params && params->NumParameters) { struct pipe_constant_buffer cb; const uint paramBytes = params->NumParameters * sizeof(GLfloat) * 4; /* Update the constants which come from fixed-function state, such as * transformation matrices, fog factors, etc. The rest of the values in * the parameters list are explicitly set by the user with glUniform, * glProgramParameter(), etc. */ if (params->StateFlags) _mesa_load_state_parameters(st->ctx, params); /* We always need to get a new buffer, to keep the drivers simple and * avoid gratuitous rendering synchronization. * Let's use a user buffer to avoid an unnecessary copy. */ if (st->constbuf_uploader) { cb.buffer = NULL; cb.user_buffer = NULL; u_upload_data(st->constbuf_uploader, 0, paramBytes, params->ParameterValues, &cb.buffer_offset, &cb.buffer); u_upload_unmap(st->constbuf_uploader); } else { cb.buffer = NULL; cb.user_buffer = params->ParameterValues; cb.buffer_offset = 0; } cb.buffer_size = paramBytes; if (ST_DEBUG & DEBUG_CONSTANTS) { debug_printf("%s(shader=%d, numParams=%d, stateFlags=0x%x)\n", __func__, shader_type, params->NumParameters, params->StateFlags); _mesa_print_parameter_list(params); } cso_set_constant_buffer(st->cso_context, shader_type, 0, &cb); pipe_resource_reference(&cb.buffer, NULL); st->state.constants[shader_type].ptr = params->ParameterValues; st->state.constants[shader_type].size = paramBytes; } else if (st->state.constants[shader_type].ptr) { /* Unbind. */ st->state.constants[shader_type].ptr = NULL; st->state.constants[shader_type].size = 0; cso_set_constant_buffer(st->cso_context, shader_type, 0, NULL); } }
/** * Make fragment shader for glDraw/CopyPixels. This shader is made * by combining the pixel transfer shader with the user-defined shader. * \param fpIn the current/incoming fragment program * \param fpOut returns the combined fragment program */ void st_make_drawpix_fragment_program(struct st_context *st, struct gl_fragment_program *fpIn, struct gl_fragment_program **fpOut) { struct gl_program *newProg; if (is_passthrough_program(fpIn)) { newProg = (struct gl_program *) _mesa_clone_fragment_program(st->ctx, &st->pixel_xfer.program->Base); } else { #if 0 /* debug */ printf("Base program:\n"); _mesa_print_program(&fpIn->Base); printf("DrawPix program:\n"); _mesa_print_program(&st->pixel_xfer.program->Base.Base); #endif newProg = _mesa_combine_programs(st->ctx, &st->pixel_xfer.program->Base.Base, &fpIn->Base); } #if 0 /* debug */ printf("Combined DrawPixels program:\n"); _mesa_print_program(newProg); printf("InputsRead: 0x%x\n", newProg->InputsRead); printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten); _mesa_print_parameter_list(newProg->Parameters); #endif *fpOut = (struct gl_fragment_program *) newProg; }
/** * Print current state. May be called from inside gdb to see currently * bound vertex/fragment shaders and associated constants. */ void st_print_current(void) { GET_CURRENT_CONTEXT(ctx); struct st_context *st = ctx->st; #if 0 int i; printf("Vertex Transform Inputs:\n"); for (i = 0; i < st->vp->state.num_inputs; i++) { printf(" Slot %d: VERT_ATTRIB_%d\n", i, st->vp->index_to_input[i]); } #endif tgsi_dump( st->vp->state.tokens, 0 ); if (st->vp->Base.Base.Parameters) _mesa_print_parameter_list(st->vp->Base.Base.Parameters); tgsi_dump( st->fp->state.tokens, 0 ); if (st->fp->Base.Base.Parameters) _mesa_print_parameter_list(st->fp->Base.Base.Parameters); }
/** * Pass the given program parameters to the graphics pipe as a * constant buffer. * \param shader_type either PIPE_SHADER_VERTEX or PIPE_SHADER_FRAGMENT */ void st_upload_constants( struct st_context *st, struct gl_program_parameter_list *params, unsigned shader_type) { struct pipe_context *pipe = st->pipe; struct pipe_resource **cbuf = &st->state.constants[shader_type]; assert(shader_type == PIPE_SHADER_VERTEX || shader_type == PIPE_SHADER_FRAGMENT || shader_type == PIPE_SHADER_GEOMETRY); /* update constants */ if (params && params->NumParameters) { const uint paramBytes = params->NumParameters * sizeof(GLfloat) * 4; _mesa_load_state_parameters(st->ctx, params); /* We always need to get a new buffer, to keep the drivers simple and * avoid gratuitous rendering synchronization. */ pipe_resource_reference(cbuf, NULL ); *cbuf = pipe_buffer_create(pipe->screen, PIPE_BIND_CONSTANT_BUFFER, paramBytes ); if (ST_DEBUG & DEBUG_CONSTANTS) { debug_printf("%s(shader=%d, numParams=%d, stateFlags=0x%x)\n", __FUNCTION__, shader_type, params->NumParameters, params->StateFlags); _mesa_print_parameter_list(params); } /* load Mesa constants into the constant buffer */ pipe_buffer_write(st->pipe, *cbuf, 0, paramBytes, params->ParameterValues); st->pipe->set_constant_buffer(st->pipe, shader_type, 0, *cbuf); } else { st->constants.tracked_state[shader_type].dirty.mesa = 0x0; } }
/** * Combine basic bitmap fragment program with the user-defined program. * \param st current context * \param fpIn the incoming fragment program * \param fpOut the new fragment program which does fragment culling * \param bitmap_sampler sampler number for the bitmap texture */ void st_make_bitmap_fragment_program(struct st_context *st, struct gl_fragment_program *fpIn, struct gl_fragment_program **fpOut, GLuint *bitmap_sampler) { struct st_fragment_program *bitmap_prog; struct st_fragment_program *stfpIn = (struct st_fragment_program *) fpIn; struct gl_program *newProg; uint sampler; /* * Generate new program which is the user-defined program prefixed * with the bitmap sampler/kill instructions. */ sampler = find_free_bit(fpIn->Base.SamplersUsed); if (stfpIn->glsl_to_tgsi) newProg = make_bitmap_fragment_program_glsl(st, stfpIn, sampler); else { bitmap_prog = make_bitmap_fragment_program(st->ctx, sampler); newProg = _mesa_combine_programs(st->ctx, &bitmap_prog->Base.Base, &fpIn->Base); /* done with this after combining */ st_reference_fragprog(st, &bitmap_prog, NULL); } #if 0 { printf("Combined bitmap program:\n"); _mesa_print_program(newProg); printf("InputsRead: 0x%x\n", newProg->InputsRead); printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten); _mesa_print_parameter_list(newProg->Parameters); } #endif /* return results */ *fpOut = (struct gl_fragment_program *) newProg; *bitmap_sampler = sampler; }
/** * Pass the given program parameters to the graphics pipe as a * constant buffer. * \param id either PIPE_SHADER_VERTEX or PIPE_SHADER_FRAGMENT */ void st_upload_constants( struct st_context *st, struct gl_program_parameter_list *params, unsigned id) { struct pipe_context *pipe = st->pipe; struct pipe_constant_buffer *cbuf = &st->state.constants[id]; assert(id == PIPE_SHADER_VERTEX || id == PIPE_SHADER_FRAGMENT); /* update constants */ if (params && params->NumParameters) { const uint paramBytes = params->NumParameters * sizeof(GLfloat) * 4; _mesa_load_state_parameters(st->ctx, params); /* We always need to get a new buffer, to keep the drivers simple and * avoid gratuitous rendering synchronization. */ pipe_buffer_reference(&cbuf->buffer, NULL ); cbuf->buffer = pipe_buffer_create(pipe->screen, 16, PIPE_BUFFER_USAGE_CONSTANT, paramBytes ); if (0) { printf("%s(shader=%d, numParams=%d, stateFlags=0x%x)\n", __FUNCTION__, id, params->NumParameters, params->StateFlags); _mesa_print_parameter_list(params); } /* load Mesa constants into the constant buffer */ if (cbuf->buffer) st_no_flush_pipe_buffer_write(st, cbuf->buffer, 0, paramBytes, params->ParameterValues); st->pipe->set_constant_buffer(st->pipe, id, 0, cbuf); } else { st->constants.tracked_state[id].dirty.mesa = 0; // st->pipe->set_constant_buffer(st->pipe, id, 0, NULL); } }
/** * Print all of a program's parameters/fields to given file. */ static void _mesa_fprint_program_parameters(FILE *f, struct gl_context *ctx, const struct gl_program *prog) { GLuint i; fprintf(f, "InputsRead: 0x%llx (0b%s)\n", (unsigned long long) prog->InputsRead, binary(prog->InputsRead)); fprintf(f, "OutputsWritten: 0x%llx (0b%s)\n", (unsigned long long)prog->OutputsWritten, binary(prog->OutputsWritten)); fprintf(f, "NumInstructions=%d\n", prog->NumInstructions); fprintf(f, "NumTemporaries=%d\n", prog->NumTemporaries); fprintf(f, "NumParameters=%d\n", prog->NumParameters); fprintf(f, "NumAttributes=%d\n", prog->NumAttributes); fprintf(f, "NumAddressRegs=%d\n", prog->NumAddressRegs); fprintf(f, "IndirectRegisterFiles: 0x%x (0b%s)\n", prog->IndirectRegisterFiles, binary(prog->IndirectRegisterFiles)); fprintf(f, "SamplersUsed: 0x%x (0b%s)\n", prog->SamplersUsed, binary(prog->SamplersUsed)); fprintf(f, "Samplers=[ "); for (i = 0; i < MAX_SAMPLERS; i++) { fprintf(f, "%d ", prog->SamplerUnits[i]); } fprintf(f, "]\n"); _mesa_load_state_parameters(ctx, prog->Parameters); #if 0 fprintf(f, "Local Params:\n"); for (i = 0; i < MAX_PROGRAM_LOCAL_PARAMS; i++){ const GLfloat *p = prog->LocalParams[i]; fprintf(f, "%2d: %f, %f, %f, %f\n", i, p[0], p[1], p[2], p[3]); } #endif _mesa_print_parameter_list(prog->Parameters); }
/** * Pass the given program parameters to the graphics pipe as a * constant buffer. */ void st_upload_constants(struct st_context *st, struct gl_program *prog) { gl_shader_stage stage = prog->info.stage; struct gl_program_parameter_list *params = prog->Parameters; enum pipe_shader_type shader_type = pipe_shader_type_from_mesa(stage); assert(shader_type == PIPE_SHADER_VERTEX || shader_type == PIPE_SHADER_FRAGMENT || shader_type == PIPE_SHADER_GEOMETRY || shader_type == PIPE_SHADER_TESS_CTRL || shader_type == PIPE_SHADER_TESS_EVAL || shader_type == PIPE_SHADER_COMPUTE); /* update the ATI constants before rendering */ if (shader_type == PIPE_SHADER_FRAGMENT && st->fp->ati_fs) { struct ati_fragment_shader *ati_fs = st->fp->ati_fs; unsigned c; for (c = 0; c < MAX_NUM_FRAGMENT_CONSTANTS_ATI; c++) { if (ati_fs->LocalConstDef & (1 << c)) memcpy(params->ParameterValues[c], ati_fs->Constants[c], sizeof(GLfloat) * 4); else memcpy(params->ParameterValues[c], st->ctx->ATIFragmentShader.GlobalConstants[c], sizeof(GLfloat) * 4); } } /* Make all bindless samplers/images bound texture/image units resident in * the context. */ st_make_bound_samplers_resident(st, prog); st_make_bound_images_resident(st, prog); /* update constants */ if (params && params->NumParameters) { struct pipe_constant_buffer cb; const uint paramBytes = params->NumParameters * sizeof(GLfloat) * 4; /* Update the constants which come from fixed-function state, such as * transformation matrices, fog factors, etc. The rest of the values in * the parameters list are explicitly set by the user with glUniform, * glProgramParameter(), etc. */ if (params->StateFlags) _mesa_load_state_parameters(st->ctx, params); _mesa_shader_write_subroutine_indices(st->ctx, stage); cb.buffer = NULL; cb.user_buffer = params->ParameterValues; cb.buffer_offset = 0; cb.buffer_size = paramBytes; if (ST_DEBUG & DEBUG_CONSTANTS) { debug_printf("%s(shader=%d, numParams=%d, stateFlags=0x%x)\n", __func__, shader_type, params->NumParameters, params->StateFlags); _mesa_print_parameter_list(params); } cso_set_constant_buffer(st->cso_context, shader_type, 0, &cb); pipe_resource_reference(&cb.buffer, NULL); st->state.constants[shader_type].ptr = params->ParameterValues; st->state.constants[shader_type].size = paramBytes; } else if (st->state.constants[shader_type].ptr) { /* Unbind. */ st->state.constants[shader_type].ptr = NULL; st->state.constants[shader_type].size = 0; cso_set_constant_buffer(st->cso_context, shader_type, 0, NULL); } }
/** * Shader linker. Currently: * * 1. The last attached vertex shader and fragment shader are linked. * 2. Varying vars in the two shaders are combined so their locations * agree between the vertex and fragment stages. They're treated as * vertex program output attribs and as fragment program input attribs. * 3. The vertex and fragment programs are cloned and modified to update * src/dst register references so they use the new, linked varying * storage locations. */ void _slang_link(GLcontext *ctx, GLhandleARB programObj, struct gl_shader_program *shProg) { const struct gl_vertex_program *vertProg = NULL; const struct gl_fragment_program *fragProg = NULL; GLboolean vertNotify = GL_TRUE, fragNotify = GL_TRUE; GLuint numSamplers = 0; GLuint i; _mesa_clear_shader_program_data(ctx, shProg); /* Initialize LinkStatus to "success". Will be cleared if error. */ shProg->LinkStatus = GL_TRUE; /* check that all programs compiled successfully */ for (i = 0; i < shProg->NumShaders; i++) { if (!shProg->Shaders[i]->CompileStatus) { link_error(shProg, "linking with uncompiled shader\n"); return; } } shProg->Uniforms = _mesa_new_uniform_list(); shProg->Varying = _mesa_new_parameter_list(); /* * Find the vertex and fragment shaders which define main() */ { struct gl_shader *vertShader, *fragShader; vertShader = get_main_shader(ctx, shProg, GL_VERTEX_SHADER); fragShader = get_main_shader(ctx, shProg, GL_FRAGMENT_SHADER); if (vertShader) vertProg = vertex_program(vertShader->Program); if (fragShader) fragProg = fragment_program(fragShader->Program); if (!shProg->LinkStatus) return; } #if FEATURE_es2_glsl /* must have both a vertex and fragment program for ES2 */ if (!vertProg) { link_error(shProg, "missing vertex shader\n"); return; } if (!fragProg) { link_error(shProg, "missing fragment shader\n"); return; } #endif /* * Make copies of the vertex/fragment programs now since we'll be * changing src/dst registers after merging the uniforms and varying vars. */ _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL); if (vertProg) { struct gl_vertex_program *linked_vprog = _mesa_clone_vertex_program(ctx, vertProg); shProg->VertexProgram = linked_vprog; /* refcount OK */ /* vertex program ID not significant; just set Id for debugging purposes */ shProg->VertexProgram->Base.Id = shProg->Name; ASSERT(shProg->VertexProgram->Base.RefCount == 1); } _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL); if (fragProg) { struct gl_fragment_program *linked_fprog = _mesa_clone_fragment_program(ctx, fragProg); shProg->FragmentProgram = linked_fprog; /* refcount OK */ /* vertex program ID not significant; just set Id for debugging purposes */ shProg->FragmentProgram->Base.Id = shProg->Name; ASSERT(shProg->FragmentProgram->Base.RefCount == 1); } /* link varying vars */ if (shProg->VertexProgram) { if (!link_varying_vars(ctx, shProg, &shProg->VertexProgram->Base)) return; } if (shProg->FragmentProgram) { if (!link_varying_vars(ctx, shProg, &shProg->FragmentProgram->Base)) return; } /* link uniform vars */ if (shProg->VertexProgram) { if (!link_uniform_vars(ctx, shProg, &shProg->VertexProgram->Base, &numSamplers)) { return; } } if (shProg->FragmentProgram) { if (!link_uniform_vars(ctx, shProg, &shProg->FragmentProgram->Base, &numSamplers)) { return; } } /*_mesa_print_uniforms(shProg->Uniforms);*/ if (shProg->VertexProgram) { if (!_slang_resolve_attributes(shProg, &vertProg->Base, &shProg->VertexProgram->Base)) { return; } } if (shProg->VertexProgram) { _slang_update_inputs_outputs(&shProg->VertexProgram->Base); _slang_count_temporaries(&shProg->VertexProgram->Base); if (!(shProg->VertexProgram->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_HPOS))) { /* the vertex program did not compute a vertex position */ link_error(shProg, "gl_Position was not written by vertex shader\n"); return; } } if (shProg->FragmentProgram) { _slang_count_temporaries(&shProg->FragmentProgram->Base); _slang_update_inputs_outputs(&shProg->FragmentProgram->Base); } /* Check that all the varying vars needed by the fragment shader are * actually produced by the vertex shader. */ if (shProg->FragmentProgram) { const GLbitfield varyingRead = shProg->FragmentProgram->Base.InputsRead >> FRAG_ATTRIB_VAR0; const GLbitfield64 varyingWritten = shProg->VertexProgram ? shProg->VertexProgram->Base.OutputsWritten >> VERT_RESULT_VAR0 : 0x0; if ((varyingRead & varyingWritten) != varyingRead) { link_error(shProg, "Fragment program using varying vars not written by vertex shader\n"); return; } } /* check that gl_FragColor and gl_FragData are not both written to */ if (shProg->FragmentProgram) { const GLbitfield64 outputsWritten = shProg->FragmentProgram->Base.OutputsWritten; if ((outputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) && (outputsWritten >= BITFIELD64_BIT(FRAG_RESULT_DATA0))) { link_error(shProg, "Fragment program cannot write both gl_FragColor" " and gl_FragData[].\n"); return; } } if (fragProg && shProg->FragmentProgram) { /* Compute initial program's TexturesUsed info */ _mesa_update_shader_textures_used(&shProg->FragmentProgram->Base); /* notify driver that a new fragment program has been compiled/linked */ vertNotify = ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB, &shProg->FragmentProgram->Base); if (ctx->Shader.Flags & GLSL_DUMP) { printf("Mesa pre-link fragment program:\n"); _mesa_print_program(&fragProg->Base); _mesa_print_program_parameters(ctx, &fragProg->Base); printf("Mesa post-link fragment program:\n"); _mesa_print_program(&shProg->FragmentProgram->Base); _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base); } } if (vertProg && shProg->VertexProgram) { /* Compute initial program's TexturesUsed info */ _mesa_update_shader_textures_used(&shProg->VertexProgram->Base); /* notify driver that a new vertex program has been compiled/linked */ fragNotify = ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, &shProg->VertexProgram->Base); if (ctx->Shader.Flags & GLSL_DUMP) { printf("Mesa pre-link vertex program:\n"); _mesa_print_program(&vertProg->Base); _mesa_print_program_parameters(ctx, &vertProg->Base); printf("Mesa post-link vertex program:\n"); _mesa_print_program(&shProg->VertexProgram->Base); _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base); } } /* Debug: */ if (0) { if (shProg->VertexProgram) _mesa_postprocess_program(ctx, &shProg->VertexProgram->Base); if (shProg->FragmentProgram) _mesa_postprocess_program(ctx, &shProg->FragmentProgram->Base); } if (ctx->Shader.Flags & GLSL_DUMP) { printf("Varying vars:\n"); _mesa_print_parameter_list(shProg->Varying); if (shProg->InfoLog) { printf("Info Log: %s\n", shProg->InfoLog); } } if (!vertNotify || !fragNotify) { /* driver rejected one/both of the vertex/fragment programs */ if (!shProg->InfoLog) { link_error(shProg, "Vertex and/or fragment program rejected by driver\n"); } } else { shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram); } }
/** * Returns a fragment program which implements the current pixel transfer ops. */ static struct gl_fragment_program * get_pixel_transfer_program(GLcontext *ctx, const struct state_key *key) { struct st_context *st = ctx->st; struct prog_instruction inst[MAX_INST]; struct gl_program_parameter_list *params; struct gl_fragment_program *fp; GLuint ic = 0; const GLuint colorTemp = 0; fp = (struct gl_fragment_program *) ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); if (!fp) return NULL; params = _mesa_new_parameter_list(); /* * Get initial pixel color from the texture. * TEX colorTemp, fragment.texcoord[0], texture[0], 2D; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_TEX; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = colorTemp; inst[ic].SrcReg[0].File = PROGRAM_INPUT; inst[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; inst[ic].TexSrcUnit = 0; inst[ic].TexSrcTarget = TEXTURE_2D_INDEX; ic++; fp->Base.InputsRead = (1 << FRAG_ATTRIB_TEX0); fp->Base.OutputsWritten = (1 << FRAG_RESULT_COLR); fp->Base.SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ if (key->scaleAndBias) { static const gl_state_index scale_state[STATE_LENGTH] = { STATE_INTERNAL, STATE_PT_SCALE, 0, 0, 0 }; static const gl_state_index bias_state[STATE_LENGTH] = { STATE_INTERNAL, STATE_PT_BIAS, 0, 0, 0 }; GLfloat scale[4], bias[4]; GLint scale_p, bias_p; scale[0] = ctx->Pixel.RedScale; scale[1] = ctx->Pixel.GreenScale; scale[2] = ctx->Pixel.BlueScale; scale[3] = ctx->Pixel.AlphaScale; bias[0] = ctx->Pixel.RedBias; bias[1] = ctx->Pixel.GreenBias; bias[2] = ctx->Pixel.BlueBias; bias[3] = ctx->Pixel.AlphaBias; scale_p = _mesa_add_state_reference(params, scale_state); bias_p = _mesa_add_state_reference(params, bias_state); /* MAD colorTemp, colorTemp, scale, bias; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_MAD; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = colorTemp; inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; inst[ic].SrcReg[0].Index = colorTemp; inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR; inst[ic].SrcReg[1].Index = scale_p; inst[ic].SrcReg[2].File = PROGRAM_STATE_VAR; inst[ic].SrcReg[2].Index = bias_p; ic++; } if (key->pixelMaps) { const GLuint temp = 1; /* create the colormap/texture now if not already done */ if (!st->pixel_xfer.pixelmap_texture) { st->pixel_xfer.pixelmap_texture = create_color_map_texture(ctx); } /* with a little effort, we can do four pixel map look-ups with * two TEX instructions: */ /* TEX temp.rg, colorTemp.rgba, texture[1], 2D; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_TEX; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = temp; inst[ic].DstReg.WriteMask = WRITEMASK_XY; /* write R,G */ inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; inst[ic].SrcReg[0].Index = colorTemp; inst[ic].TexSrcUnit = 1; inst[ic].TexSrcTarget = TEXTURE_2D_INDEX; ic++; /* TEX temp.ba, colorTemp.baba, texture[1], 2D; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_TEX; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = temp; inst[ic].DstReg.WriteMask = WRITEMASK_ZW; /* write B,A */ inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; inst[ic].SrcReg[0].Index = colorTemp; inst[ic].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W, SWIZZLE_Z, SWIZZLE_W); inst[ic].TexSrcUnit = 1; inst[ic].TexSrcTarget = TEXTURE_2D_INDEX; ic++; /* MOV colorTemp, temp; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_MOV; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = colorTemp; inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; inst[ic].SrcReg[0].Index = temp; ic++; fp->Base.SamplersUsed |= (1 << 1); /* sampler 1 is used */ } if (key->colorMatrix) { static const gl_state_index row0_state[STATE_LENGTH] = { STATE_COLOR_MATRIX, 0, 0, 0, 0 }; static const gl_state_index row1_state[STATE_LENGTH] = { STATE_COLOR_MATRIX, 0, 1, 1, 0 }; static const gl_state_index row2_state[STATE_LENGTH] = { STATE_COLOR_MATRIX, 0, 2, 2, 0 }; static const gl_state_index row3_state[STATE_LENGTH] = { STATE_COLOR_MATRIX, 0, 3, 3, 0 }; GLint row0_p = _mesa_add_state_reference(params, row0_state); GLint row1_p = _mesa_add_state_reference(params, row1_state); GLint row2_p = _mesa_add_state_reference(params, row2_state); GLint row3_p = _mesa_add_state_reference(params, row3_state); const GLuint temp = 1; /* DP4 temp.x, colorTemp, matrow0; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_DP4; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = temp; inst[ic].DstReg.WriteMask = WRITEMASK_X; inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; inst[ic].SrcReg[0].Index = colorTemp; inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR; inst[ic].SrcReg[1].Index = row0_p; ic++; /* DP4 temp.y, colorTemp, matrow1; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_DP4; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = temp; inst[ic].DstReg.WriteMask = WRITEMASK_Y; inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; inst[ic].SrcReg[0].Index = colorTemp; inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR; inst[ic].SrcReg[1].Index = row1_p; ic++; /* DP4 temp.z, colorTemp, matrow2; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_DP4; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = temp; inst[ic].DstReg.WriteMask = WRITEMASK_Z; inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; inst[ic].SrcReg[0].Index = colorTemp; inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR; inst[ic].SrcReg[1].Index = row2_p; ic++; /* DP4 temp.w, colorTemp, matrow3; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_DP4; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = temp; inst[ic].DstReg.WriteMask = WRITEMASK_W; inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; inst[ic].SrcReg[0].Index = colorTemp; inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR; inst[ic].SrcReg[1].Index = row3_p; ic++; /* MOV colorTemp, temp; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_MOV; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = colorTemp; inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; inst[ic].SrcReg[0].Index = temp; ic++; } if (key->colorMatrixPostScaleBias) { static const gl_state_index scale_state[STATE_LENGTH] = { STATE_INTERNAL, STATE_PT_SCALE, 0, 0, 0 }; static const gl_state_index bias_state[STATE_LENGTH] = { STATE_INTERNAL, STATE_PT_BIAS, 0, 0, 0 }; GLint scale_param, bias_param; scale_param = _mesa_add_state_reference(params, scale_state); bias_param = _mesa_add_state_reference(params, bias_state); _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_MAD; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = colorTemp; inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; inst[ic].SrcReg[0].Index = colorTemp; inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR; inst[ic].SrcReg[1].Index = scale_param; inst[ic].SrcReg[2].File = PROGRAM_STATE_VAR; inst[ic].SrcReg[2].Index = bias_param; ic++; } /* Modify last instruction's dst reg to write to result.color */ { struct prog_instruction *last = &inst[ic - 1]; last->DstReg.File = PROGRAM_OUTPUT; last->DstReg.Index = FRAG_RESULT_COLR; } /* END; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_END; ic++; assert(ic <= MAX_INST); fp->Base.Instructions = _mesa_alloc_instructions(ic); if (!fp->Base.Instructions) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating pixel transfer program"); return NULL; } _mesa_copy_instructions(fp->Base.Instructions, inst, ic); fp->Base.NumInstructions = ic; fp->Base.Parameters = params; #if 0 printf("========= pixel transfer prog\n"); _mesa_print_program(&fp->Base); _mesa_print_parameter_list(fp->Base.Parameters); #endif return fp; }
/** * Pass the given program parameters to the graphics pipe as a * constant buffer. * \param shader_type either PIPE_SHADER_VERTEX or PIPE_SHADER_FRAGMENT */ void st_upload_constants( struct st_context *st, struct gl_program_parameter_list *params, gl_shader_stage stage) { enum pipe_shader_type shader_type = st_shader_stage_to_ptarget(stage); assert(shader_type == PIPE_SHADER_VERTEX || shader_type == PIPE_SHADER_FRAGMENT || shader_type == PIPE_SHADER_GEOMETRY || shader_type == PIPE_SHADER_TESS_CTRL || shader_type == PIPE_SHADER_TESS_EVAL || shader_type == PIPE_SHADER_COMPUTE); /* update the ATI constants before rendering */ if (shader_type == PIPE_SHADER_FRAGMENT && st->fp->ati_fs) { struct ati_fragment_shader *ati_fs = st->fp->ati_fs; unsigned c; for (c = 0; c < MAX_NUM_FRAGMENT_CONSTANTS_ATI; c++) { if (ati_fs->LocalConstDef & (1 << c)) memcpy(params->ParameterValues[c], ati_fs->Constants[c], sizeof(GLfloat) * 4); else memcpy(params->ParameterValues[c], st->ctx->ATIFragmentShader.GlobalConstants[c], sizeof(GLfloat) * 4); } } /* update constants */ if (params && params->NumParameters) { struct pipe_constant_buffer cb; const uint paramBytes = params->NumParameters * sizeof(GLfloat) * 4; /* Update the constants which come from fixed-function state, such as * transformation matrices, fog factors, etc. The rest of the values in * the parameters list are explicitly set by the user with glUniform, * glProgramParameter(), etc. */ if (params->StateFlags) _mesa_load_state_parameters(st->ctx, params); _mesa_shader_write_subroutine_indices(st->ctx, stage); /* We always need to get a new buffer, to keep the drivers simple and * avoid gratuitous rendering synchronization. * Let's use a user buffer to avoid an unnecessary copy. */ if (st->constbuf_uploader) { cb.buffer = NULL; cb.user_buffer = NULL; u_upload_data(st->constbuf_uploader, 0, paramBytes, st->ctx->Const.UniformBufferOffsetAlignment, params->ParameterValues, &cb.buffer_offset, &cb.buffer); u_upload_unmap(st->constbuf_uploader); } else { cb.buffer = NULL; cb.user_buffer = params->ParameterValues; cb.buffer_offset = 0; } cb.buffer_size = paramBytes; if (ST_DEBUG & DEBUG_CONSTANTS) { debug_printf("%s(shader=%d, numParams=%d, stateFlags=0x%x)\n", __func__, shader_type, params->NumParameters, params->StateFlags); _mesa_print_parameter_list(params); } cso_set_constant_buffer(st->cso_context, shader_type, 0, &cb); pipe_resource_reference(&cb.buffer, NULL); st->state.constants[shader_type].ptr = params->ParameterValues; st->state.constants[shader_type].size = paramBytes; } else if (st->state.constants[shader_type].ptr) { /* Unbind. */ st->state.constants[shader_type].ptr = NULL; st->state.constants[shader_type].size = 0; cso_set_constant_buffer(st->cso_context, shader_type, 0, NULL); } }
/** * Make fragment shader for glDraw/CopyPixels. This shader is made * by combining the pixel transfer shader with the user-defined shader. */ static struct st_fragment_program * combined_drawpix_fragment_program(GLcontext *ctx) { struct st_context *st = ctx->st; struct st_fragment_program *stfp; if (st->pixel_xfer.program->serialNo == st->pixel_xfer.xfer_prog_sn && st->fp->serialNo == st->pixel_xfer.user_prog_sn) { /* the pixel tranfer program has not changed and the user-defined * program has not changed, so re-use the combined program. */ stfp = st->pixel_xfer.combined_prog; } else { /* Concatenate the pixel transfer program with the current user- * defined program. */ if (is_passthrough_program(&st->fp->Base)) { stfp = (struct st_fragment_program *) _mesa_clone_program(ctx, &st->pixel_xfer.program->Base.Base); } else { #if 0 printf("Base program:\n"); _mesa_print_program(&st->fp->Base.Base); printf("DrawPix program:\n"); _mesa_print_program(&st->pixel_xfer.program->Base.Base); #endif stfp = (struct st_fragment_program *) _mesa_combine_programs(ctx, &st->pixel_xfer.program->Base.Base, &st->fp->Base.Base); } #if 0 { struct gl_program *p = &stfp->Base.Base; printf("Combined DrawPixels program:\n"); _mesa_print_program(p); printf("InputsRead: 0x%x\n", p->InputsRead); printf("OutputsWritten: 0x%x\n", p->OutputsWritten); _mesa_print_parameter_list(p->Parameters); } #endif /* translate to TGSI tokens */ st_translate_fragment_program(st, stfp, NULL); /* save new program, update serial numbers */ st->pixel_xfer.xfer_prog_sn = st->pixel_xfer.program->serialNo; st->pixel_xfer.user_prog_sn = st->fp->serialNo; st->pixel_xfer.combined_prog_sn = stfp->serialNo; /* can't reference new program directly, already have a reference on it */ st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL); st->pixel_xfer.combined_prog = stfp; } /* Ideally we'd have updated the pipe constants during the normal * st/atom mechanism. But we can't since this is specific to glDrawPixels. */ st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT); return stfp; }