/** * Init context's vertex/fragment program state */ void _mesa_init_program(struct gl_context *ctx) { /* * If this assertion fails, we need to increase the field * size for register indexes (see INST_INDEX_BITS). */ assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxUniformComponents / 4 <= (1 << INST_INDEX_BITS)); assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxUniformComponents / 4 <= (1 << INST_INDEX_BITS)); assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxTemps <= (1 << INST_INDEX_BITS)); assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxLocalParams <= (1 << INST_INDEX_BITS)); assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTemps <= (1 << INST_INDEX_BITS)); assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxLocalParams <= (1 << INST_INDEX_BITS)); assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxUniformComponents <= 4 * MAX_UNIFORMS); assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxUniformComponents <= 4 * MAX_UNIFORMS); assert(ctx->Const.Program[MESA_SHADER_VERTEX].MaxAddressOffset <= (1 << INST_INDEX_BITS)); assert(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxAddressOffset <= (1 << INST_INDEX_BITS)); /* If this fails, increase prog_instruction::TexSrcUnit size */ STATIC_ASSERT(MAX_TEXTURE_UNITS <= (1 << 5)); /* If this fails, increase prog_instruction::TexSrcTarget size */ STATIC_ASSERT(NUM_TEXTURE_TARGETS <= (1 << 4)); ctx->Program.ErrorPos = -1; ctx->Program.ErrorString = strdup(""); ctx->VertexProgram.Enabled = GL_FALSE; ctx->VertexProgram.PointSizeEnabled = (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE; ctx->VertexProgram.TwoSideEnabled = GL_FALSE; _mesa_reference_program(ctx, &ctx->VertexProgram.Current, ctx->Shared->DefaultVertexProgram); assert(ctx->VertexProgram.Current); ctx->VertexProgram.Cache = _mesa_new_program_cache(); ctx->FragmentProgram.Enabled = GL_FALSE; _mesa_reference_program(ctx, &ctx->FragmentProgram.Current, ctx->Shared->DefaultFragmentProgram); assert(ctx->FragmentProgram.Current); ctx->FragmentProgram.Cache = _mesa_new_program_cache(); /* XXX probably move this stuff */ ctx->ATIFragmentShader.Enabled = GL_FALSE; ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader; assert(ctx->ATIFragmentShader.Current); ctx->ATIFragmentShader.Current->RefCount++; }
/** * Delete a shader object. */ void _mesa_delete_linked_shader(struct gl_context *ctx, struct gl_linked_shader *sh) { _mesa_reference_program(ctx, &sh->Program, NULL); ralloc_free(sh); }
/** * Delete a shader object. * Called via ctx->Driver.DeleteShader(). */ static void _mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh) { free((void *)sh->Source); _mesa_reference_program(ctx, &sh->Program, NULL); ralloc_free(sh); }
void st_delete_program(GLcontext *ctx, struct gl_program *prog) { struct st_context *st = st_context(ctx); switch( prog->Target ) { case GL_VERTEX_PROGRAM_ARB: { struct st_vertex_program *stvp = (struct st_vertex_program *) prog; if (stvp->driver_shader) { cso_delete_vertex_shader(st->cso_context, stvp->driver_shader); stvp->driver_shader = NULL; } if (stvp->draw_shader) { #if FEATURE_feedback || FEATURE_drawpix /* this would only have been allocated for the RasterPos path */ draw_delete_vertex_shader(st->draw, stvp->draw_shader); stvp->draw_shader = NULL; #endif } if (stvp->state.tokens) { st_free_tokens(stvp->state.tokens); stvp->state.tokens = NULL; } } break; case GL_FRAGMENT_PROGRAM_ARB: { struct st_fragment_program *stfp = (struct st_fragment_program *) prog; if (stfp->driver_shader) { cso_delete_fragment_shader(st->cso_context, stfp->driver_shader); stfp->driver_shader = NULL; } if (stfp->state.tokens) { st_free_tokens(stfp->state.tokens); stfp->state.tokens = NULL; } if (stfp->bitmap_program) { struct gl_program *prg = &stfp->bitmap_program->Base.Base; _mesa_reference_program(ctx, &prg, NULL); stfp->bitmap_program = NULL; } st_free_translated_vertex_programs(st, stfp->vertex_programs); } break; default: assert(0); /* problem */ } /* delete base class */ _mesa_delete_program( ctx, prog ); }
/** * Free a context's vertex/fragment program state */ void _mesa_free_program_data(struct gl_context *ctx) { _mesa_reference_program(ctx, &ctx->VertexProgram.Current, NULL); _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache); _mesa_reference_program(ctx, &ctx->FragmentProgram.Current, NULL); _mesa_delete_shader_cache(ctx, ctx->FragmentProgram.Cache); /* XXX probably move this stuff */ if (ctx->ATIFragmentShader.Current) { ctx->ATIFragmentShader.Current->RefCount--; if (ctx->ATIFragmentShader.Current->RefCount <= 0) { free(ctx->ATIFragmentShader.Current); } } free((void *) ctx->Program.ErrorString); }
/** * Update the default program objects in the given context to reference those * specified in the shared state and release those referencing the old * shared state. */ void _mesa_update_default_objects_program(struct gl_context *ctx) { _mesa_reference_program(ctx, &ctx->VertexProgram.Current, ctx->Shared->DefaultVertexProgram); assert(ctx->VertexProgram.Current); _mesa_reference_program(ctx, &ctx->FragmentProgram.Current, ctx->Shared->DefaultFragmentProgram); assert(ctx->FragmentProgram.Current); /* XXX probably move this stuff */ if (ctx->ATIFragmentShader.Current) { ctx->ATIFragmentShader.Current->RefCount--; if (ctx->ATIFragmentShader.Current->RefCount <= 0) { free(ctx->ATIFragmentShader.Current); } } ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader; assert(ctx->ATIFragmentShader.Current); ctx->ATIFragmentShader.Current->RefCount++; }
/** * Delete a list of programs. * \note Not compiled into display lists. * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB. */ void GLAPIENTRY _mesa_DeletePrograms(GLsizei n, const GLuint *ids) { GLint i; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (n < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" ); return; } for (i = 0; i < n; i++) { if (ids[i] != 0) { struct gl_program *prog = _mesa_lookup_program(ctx, ids[i]); if (prog == &_mesa_DummyProgram) { _mesa_HashRemove(ctx->Shared->Programs, ids[i]); } else if (prog) { /* Unbind program if necessary */ if (prog->Target == GL_VERTEX_PROGRAM_ARB || /* == GL_VERTEX_PROGRAM_NV */ prog->Target == GL_VERTEX_STATE_PROGRAM_NV) { if (ctx->VertexProgram.Current && ctx->VertexProgram.Current->Base.Id == ids[i]) { /* unbind this currently bound program */ _mesa_BindProgram(prog->Target, 0); } } else if (prog->Target == GL_FRAGMENT_PROGRAM_NV || prog->Target == GL_FRAGMENT_PROGRAM_ARB) { if (ctx->FragmentProgram.Current && ctx->FragmentProgram.Current->Base.Id == ids[i]) { /* unbind this currently bound program */ _mesa_BindProgram(prog->Target, 0); } } else { _mesa_problem(ctx, "bad target in glDeleteProgramsNV"); return; } /* The ID is immediately available for re-use now */ _mesa_HashRemove(ctx->Shared->Programs, ids[i]); _mesa_reference_program(ctx, &prog, NULL); } } } }
/** * Delete a list of programs. * \note Not compiled into display lists. * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB. */ void GLAPIENTRY _mesa_DeleteProgramsARB(GLsizei n, const GLuint *ids) { GLint i; GET_CURRENT_CONTEXT(ctx); FLUSH_VERTICES(ctx, 0); if (n < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" ); return; } for (i = 0; i < n; i++) { if (ids[i] != 0) { struct gl_program *prog = _mesa_lookup_program(ctx, ids[i]); if (prog == &_mesa_DummyProgram) { _mesa_HashRemove(ctx->Shared->Programs, ids[i]); } else if (prog) { /* Unbind program if necessary */ switch (prog->Target) { case GL_VERTEX_PROGRAM_ARB: if (ctx->VertexProgram.Current && ctx->VertexProgram.Current->Base.Id == ids[i]) { /* unbind this currently bound program */ _mesa_BindProgramARB(prog->Target, 0); } break; case GL_FRAGMENT_PROGRAM_ARB: if (ctx->FragmentProgram.Current && ctx->FragmentProgram.Current->Base.Id == ids[i]) { /* unbind this currently bound program */ _mesa_BindProgramARB(prog->Target, 0); } break; default: _mesa_problem(ctx, "bad target in glDeleteProgramsNV"); return; } /* The ID is immediately available for re-use now */ _mesa_HashRemove(ctx->Shared->Programs, ids[i]); _mesa_reference_program(ctx, &prog, NULL); } } } }
void r300TranslateFragmentShader(r300ContextPtr r300, struct r300_fragment_program *fp) { struct r300_fragment_program_external_state state; build_state(r300, fp, &state); if (_mesa_memcmp(&fp->state, &state, sizeof(state))) { /* TODO: cache compiled programs */ fp->translated = GL_FALSE; _mesa_memcpy(&fp->state, &state, sizeof(state)); } if (!fp->translated) { struct r300_fragment_program_compiler compiler; compiler.r300 = r300; compiler.fp = fp; compiler.code = &fp->code; compiler.program = _mesa_clone_program(r300->radeon.glCtx, &fp->mesa_program.Base); if (RADEON_DEBUG & DEBUG_PIXEL) { _mesa_printf("Fragment Program: Initial program:\n"); _mesa_print_program(compiler.program); } insert_WPOS_trailer(&compiler); struct radeon_program_transformation transformations[] = { { &transform_TEX, &compiler }, { &radeonTransformALU, 0 }, { &radeonTransformTrigSimple, 0 } }; radeonLocalTransform( r300->radeon.glCtx, compiler.program, 3, transformations); if (RADEON_DEBUG & DEBUG_PIXEL) { _mesa_printf("Fragment Program: After native rewrite:\n"); _mesa_print_program(compiler.program); } struct radeon_nqssadce_descr nqssadce = { .Init = &nqssadce_init, .IsNativeSwizzle = &r300FPIsNativeSwizzle, .BuildSwizzle = &r300FPBuildSwizzle, .RewriteDepthOut = GL_TRUE }; radeonNqssaDce(r300->radeon.glCtx, compiler.program, &nqssadce); if (RADEON_DEBUG & DEBUG_PIXEL) { _mesa_printf("Compiler: after NqSSA-DCE:\n"); _mesa_print_program(compiler.program); } if (!r300FragmentProgramEmit(&compiler)) fp->error = GL_TRUE; /* Subtle: Rescue any parameters that have been added during transformations */ _mesa_free_parameter_list(fp->mesa_program.Base.Parameters); fp->mesa_program.Base.Parameters = compiler.program->Parameters; compiler.program->Parameters = 0; _mesa_reference_program(r300->radeon.glCtx, &compiler.program, NULL); if (!fp->error) fp->translated = GL_TRUE; if (fp->error || (RADEON_DEBUG & DEBUG_PIXEL)) r300FragmentProgramDump(fp, &fp->code); r300UpdateStateParameters(r300->radeon.glCtx, _NEW_PROGRAM); } update_params(r300, fp); }
/** * Return a copy of a program. * XXX Problem here if the program object is actually OO-derivation * made by a device driver. */ struct gl_program * _mesa_clone_program(GLcontext *ctx, const struct gl_program *prog) { struct gl_program *clone; clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id); if (!clone) return NULL; assert(clone->Target == prog->Target); assert(clone->RefCount == 1); clone->String = (GLubyte *) _mesa_strdup((char *) prog->String); clone->Format = prog->Format; clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions); if (!clone->Instructions) { _mesa_reference_program(ctx, &clone, NULL); return NULL; } _mesa_copy_instructions(clone->Instructions, prog->Instructions, prog->NumInstructions); clone->InputsRead = prog->InputsRead; clone->OutputsWritten = prog->OutputsWritten; clone->SamplersUsed = prog->SamplersUsed; clone->ShadowSamplers = prog->ShadowSamplers; memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed)); if (prog->Parameters) clone->Parameters = _mesa_clone_parameter_list(prog->Parameters); memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); if (prog->Varying) clone->Varying = _mesa_clone_parameter_list(prog->Varying); if (prog->Attributes) clone->Attributes = _mesa_clone_parameter_list(prog->Attributes); memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); clone->NumInstructions = prog->NumInstructions; clone->NumTemporaries = prog->NumTemporaries; clone->NumParameters = prog->NumParameters; clone->NumAttributes = prog->NumAttributes; clone->NumAddressRegs = prog->NumAddressRegs; clone->NumNativeInstructions = prog->NumNativeInstructions; clone->NumNativeTemporaries = prog->NumNativeTemporaries; clone->NumNativeParameters = prog->NumNativeParameters; clone->NumNativeAttributes = prog->NumNativeAttributes; clone->NumNativeAddressRegs = prog->NumNativeAddressRegs; clone->NumAluInstructions = prog->NumAluInstructions; clone->NumTexInstructions = prog->NumTexInstructions; clone->NumTexIndirections = prog->NumTexIndirections; clone->NumNativeAluInstructions = prog->NumNativeAluInstructions; clone->NumNativeTexInstructions = prog->NumNativeTexInstructions; clone->NumNativeTexIndirections = prog->NumNativeTexIndirections; switch (prog->Target) { case GL_VERTEX_PROGRAM_ARB: { const struct gl_vertex_program *vp = (const struct gl_vertex_program *) prog; struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone; vpc->IsPositionInvariant = vp->IsPositionInvariant; } break; case GL_FRAGMENT_PROGRAM_ARB: { const struct gl_fragment_program *fp = (const struct gl_fragment_program *) prog; struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone; fpc->FogOption = fp->FogOption; fpc->UsesKill = fp->UsesKill; } break; default: _mesa_problem(NULL, "Unexpected target in _mesa_clone_program"); } return clone; }
/** * Update the ctx->*Program._Current pointers to point to the * current/active programs. * * Programs may come from 3 sources: GLSL shaders, ARB/NV_vertex/fragment * programs or programs derived from fixed-function state. * * This function needs to be called after texture state validation in case * we're generating a fragment program from fixed-function texture state. * * \return bitfield which will indicate _NEW_PROGRAM state if a new vertex * or fragment program is being used. */ static GLbitfield update_program(struct gl_context *ctx) { struct gl_program *vsProg = ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX]; struct gl_program *tcsProg = ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_CTRL]; struct gl_program *tesProg = ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL]; struct gl_program *gsProg = ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]; struct gl_program *fsProg = ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT]; struct gl_program *csProg = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE]; const struct gl_program *prevVP = ctx->VertexProgram._Current; const struct gl_program *prevFP = ctx->FragmentProgram._Current; const struct gl_program *prevGP = ctx->GeometryProgram._Current; const struct gl_program *prevTCP = ctx->TessCtrlProgram._Current; const struct gl_program *prevTEP = ctx->TessEvalProgram._Current; const struct gl_program *prevCP = ctx->ComputeProgram._Current; /* * Set the ctx->VertexProgram._Current and ctx->FragmentProgram._Current * pointers to the programs that should be used for rendering. If either * is NULL, use fixed-function code paths. * * These programs may come from several sources. The priority is as * follows: * 1. OpenGL 2.0/ARB vertex/fragment shaders * 2. ARB/NV vertex/fragment programs * 3. ATI fragment shader * 4. Programs derived from fixed-function state. * * Note: it's possible for a vertex shader to get used with a fragment * program (and vice versa) here, but in practice that shouldn't ever * come up, or matter. */ if (fsProg) { /* Use GLSL fragment shader */ _mesa_reference_program(ctx, &ctx->FragmentProgram._Current, fsProg); _mesa_reference_program(ctx, &ctx->FragmentProgram._TexEnvProgram, NULL); } else if (_mesa_arb_fragment_program_enabled(ctx)) { /* Use user-defined fragment program */ _mesa_reference_program(ctx, &ctx->FragmentProgram._Current, ctx->FragmentProgram.Current); _mesa_reference_program(ctx, &ctx->FragmentProgram._TexEnvProgram, NULL); } else if (_mesa_ati_fragment_shader_enabled(ctx) && ctx->ATIFragmentShader.Current->Program) { /* Use the enabled ATI fragment shader's associated program */ _mesa_reference_program(ctx, &ctx->FragmentProgram._Current, ctx->ATIFragmentShader.Current->Program); _mesa_reference_program(ctx, &ctx->FragmentProgram._TexEnvProgram, NULL); } else if (ctx->FragmentProgram._MaintainTexEnvProgram) { /* Use fragment program generated from fixed-function state */ struct gl_shader_program *f = _mesa_get_fixed_func_fragment_program(ctx); _mesa_reference_program(ctx, &ctx->FragmentProgram._Current, f->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program); _mesa_reference_program(ctx, &ctx->FragmentProgram._TexEnvProgram, f->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program); } else { /* No fragment program */ _mesa_reference_program(ctx, &ctx->FragmentProgram._Current, NULL); _mesa_reference_program(ctx, &ctx->FragmentProgram._TexEnvProgram, NULL); } if (gsProg) { /* Use GLSL geometry shader */ _mesa_reference_program(ctx, &ctx->GeometryProgram._Current, gsProg); } else { /* No geometry program */ _mesa_reference_program(ctx, &ctx->GeometryProgram._Current, NULL); } if (tesProg) { /* Use GLSL tessellation evaluation shader */ _mesa_reference_program(ctx, &ctx->TessEvalProgram._Current, tesProg); } else { /* No tessellation evaluation program */ _mesa_reference_program(ctx, &ctx->TessEvalProgram._Current, NULL); } if (tcsProg) { /* Use GLSL tessellation control shader */ _mesa_reference_program(ctx, &ctx->TessCtrlProgram._Current, tcsProg); } else { /* No tessellation control program */ _mesa_reference_program(ctx, &ctx->TessCtrlProgram._Current, NULL); } /* Examine vertex program after fragment program as * _mesa_get_fixed_func_vertex_program() needs to know active * fragprog inputs. */ if (vsProg) { /* Use GLSL vertex shader */ assert(VP_MODE_SHADER == ctx->VertexProgram._VPMode); _mesa_reference_program(ctx, &ctx->VertexProgram._Current, vsProg); } else if (_mesa_arb_vertex_program_enabled(ctx)) { /* Use user-defined vertex program */ assert(VP_MODE_SHADER == ctx->VertexProgram._VPMode); _mesa_reference_program(ctx, &ctx->VertexProgram._Current, ctx->VertexProgram.Current); } else if (ctx->VertexProgram._MaintainTnlProgram) { /* Use vertex program generated from fixed-function state */ assert(VP_MODE_FF == ctx->VertexProgram._VPMode); _mesa_reference_program(ctx, &ctx->VertexProgram._Current, _mesa_get_fixed_func_vertex_program(ctx)); _mesa_reference_program(ctx, &ctx->VertexProgram._TnlProgram, ctx->VertexProgram._Current); } else { /* no vertex program */ assert(VP_MODE_FF == ctx->VertexProgram._VPMode); _mesa_reference_program(ctx, &ctx->VertexProgram._Current, NULL); } if (csProg) { /* Use GLSL compute shader */ _mesa_reference_program(ctx, &ctx->ComputeProgram._Current, csProg); } else { /* no compute program */ _mesa_reference_program(ctx, &ctx->ComputeProgram._Current, NULL); } /* Let the driver know what's happening: */ if (ctx->FragmentProgram._Current != prevFP || ctx->VertexProgram._Current != prevVP || ctx->GeometryProgram._Current != prevGP || ctx->TessEvalProgram._Current != prevTEP || ctx->TessCtrlProgram._Current != prevTCP || ctx->ComputeProgram._Current != prevCP) return _NEW_PROGRAM; return 0; }
/** * Return a copy of a program. * XXX Problem here if the program object is actually OO-derivation * made by a device driver. */ struct gl_program * _mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog) { struct gl_program *clone; clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id); if (!clone) return NULL; assert(clone->Target == prog->Target); assert(clone->RefCount == 1); clone->String = (GLubyte *) _mesa_strdup((char *) prog->String); clone->Format = prog->Format; clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions); if (!clone->Instructions) { _mesa_reference_program(ctx, &clone, NULL); return NULL; } _mesa_copy_instructions(clone->Instructions, prog->Instructions, prog->NumInstructions); clone->InputsRead = prog->InputsRead; clone->OutputsWritten = prog->OutputsWritten; clone->SamplersUsed = prog->SamplersUsed; clone->ShadowSamplers = prog->ShadowSamplers; memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed)); if (prog->Parameters) clone->Parameters = _mesa_clone_parameter_list(prog->Parameters); memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); clone->IndirectRegisterFiles = prog->IndirectRegisterFiles; clone->NumInstructions = prog->NumInstructions; clone->NumTemporaries = prog->NumTemporaries; clone->NumParameters = prog->NumParameters; clone->NumAttributes = prog->NumAttributes; clone->NumAddressRegs = prog->NumAddressRegs; clone->NumNativeInstructions = prog->NumNativeInstructions; clone->NumNativeTemporaries = prog->NumNativeTemporaries; clone->NumNativeParameters = prog->NumNativeParameters; clone->NumNativeAttributes = prog->NumNativeAttributes; clone->NumNativeAddressRegs = prog->NumNativeAddressRegs; clone->NumAluInstructions = prog->NumAluInstructions; clone->NumTexInstructions = prog->NumTexInstructions; clone->NumTexIndirections = prog->NumTexIndirections; clone->NumNativeAluInstructions = prog->NumNativeAluInstructions; clone->NumNativeTexInstructions = prog->NumNativeTexInstructions; clone->NumNativeTexIndirections = prog->NumNativeTexIndirections; switch (prog->Target) { case GL_VERTEX_PROGRAM_ARB: { const struct gl_vertex_program *vp = gl_vertex_program_const(prog); struct gl_vertex_program *vpc = gl_vertex_program(clone); vpc->IsPositionInvariant = vp->IsPositionInvariant; vpc->IsNVProgram = vp->IsNVProgram; } break; case GL_FRAGMENT_PROGRAM_ARB: { const struct gl_fragment_program *fp = gl_fragment_program_const(prog); struct gl_fragment_program *fpc = gl_fragment_program(clone); fpc->UsesKill = fp->UsesKill; fpc->UsesDFdy = fp->UsesDFdy; fpc->OriginUpperLeft = fp->OriginUpperLeft; fpc->PixelCenterInteger = fp->PixelCenterInteger; } break; case MESA_GEOMETRY_PROGRAM: { const struct gl_geometry_program *gp = gl_geometry_program_const(prog); struct gl_geometry_program *gpc = gl_geometry_program(clone); gpc->VerticesOut = gp->VerticesOut; gpc->InputType = gp->InputType; gpc->OutputType = gp->OutputType; } break; default: _mesa_problem(NULL, "Unexpected target in _mesa_clone_program"); } return clone; }