📄 slang_link.c
字号:
else { /* No user-defined binding, choose our own attribute number. * Start at 1 since generic attribute 0 always aliases * glVertex/position. */ for (attr = 1; attr < MAX_VERTEX_ATTRIBS; attr++) { if (((1 << attr) & usedAttributes) == 0) break; } if (attr == MAX_VERTEX_ATTRIBS) { link_error(shProg, "Too many vertex attributes"); return GL_FALSE; } /* mark this attribute as used */ usedAttributes |= (1 << attr); } attribMap[k] = attr; /* Save the final name->attrib binding so it can be queried * with glGetAttributeLocation(). */ _mesa_add_attribute(linkedProg->Attributes, name, size, type, attr); } assert(attr >= 0); /* update the instruction's src reg */ inst->SrcReg[j].Index = VERT_ATTRIB_GENERIC0 + attr; } } } return GL_TRUE;}/** * Scan program instructions to update the program's NumTemporaries field. * Note: this implemenation relies on the code generator allocating * temps in increasing order (0, 1, 2, ... ). */static void_slang_count_temporaries(struct gl_program *prog){ GLuint i, j; GLint maxIndex = -1; for (i = 0; i < prog->NumInstructions; i++) { const struct prog_instruction *inst = prog->Instructions + i; const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); for (j = 0; j < numSrc; j++) { if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { if (maxIndex < inst->SrcReg[j].Index) maxIndex = inst->SrcReg[j].Index; } if (inst->DstReg.File == PROGRAM_TEMPORARY) { if (maxIndex < (GLint) inst->DstReg.Index) maxIndex = inst->DstReg.Index; } } } prog->NumTemporaries = (GLuint) (maxIndex + 1);}/** * Scan program instructions to update the program's InputsRead and * OutputsWritten fields. */static void_slang_update_inputs_outputs(struct gl_program *prog){ GLuint i, j; prog->InputsRead = 0x0; prog->OutputsWritten = 0x0; for (i = 0; i < prog->NumInstructions; i++) { const struct prog_instruction *inst = prog->Instructions + i; const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); for (j = 0; j < numSrc; j++) { if (inst->SrcReg[j].File == PROGRAM_INPUT) { prog->InputsRead |= 1 << inst->SrcReg[j].Index; } } if (inst->DstReg.File == PROGRAM_OUTPUT) { prog->OutputsWritten |= 1 << inst->DstReg.Index; } }}/** cast wrapper */static struct gl_vertex_program *vertex_program(struct gl_program *prog){ assert(prog->Target == GL_VERTEX_PROGRAM_ARB); return (struct gl_vertex_program *) prog;}/** cast wrapper */static struct gl_fragment_program *fragment_program(struct gl_program *prog){ assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB); return (struct gl_fragment_program *) prog;}/** * 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; const struct gl_fragment_program *fragProg; GLuint numSamplers = 0; GLuint i; _mesa_clear_shader_program_data(ctx, shProg); /* 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 attached vertex, fragment shaders defining main() */ vertProg = NULL; fragProg = NULL; for (i = 0; i < shProg->NumShaders; i++) { struct gl_shader *shader = shProg->Shaders[i]; if (shader->Type == GL_VERTEX_SHADER && shader->Main) vertProg = vertex_program(shader->Program); else if (shader->Type == GL_FRAGMENT_SHADER && shader->Main) fragProg = fragment_program(shader->Program); else _mesa_problem(ctx, "unexpected shader target in slang_link()"); }#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 = vertex_program(_mesa_clone_program(ctx, &vertProg->Base)); shProg->VertexProgram = linked_vprog; /* refcount OK */ ASSERT(shProg->VertexProgram->Base.RefCount == 1); } _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL); if (fragProg) { struct gl_fragment_program *linked_fprog = fragment_program(_mesa_clone_program(ctx, &fragProg->Base)); shProg->FragmentProgram = linked_fprog; /* refcount OK */ ASSERT(shProg->FragmentProgram->Base.RefCount == 1); } /* link varying vars */ if (shProg->VertexProgram) { if (!link_varying_vars(shProg, &shProg->VertexProgram->Base)) return; } if (shProg->FragmentProgram) { if (!link_varying_vars(shProg, &shProg->FragmentProgram->Base)) return; } /* link uniform vars */ if (shProg->VertexProgram) link_uniform_vars(shProg, &shProg->VertexProgram->Base, &numSamplers); if (shProg->FragmentProgram) link_uniform_vars(shProg, &shProg->FragmentProgram->Base, &numSamplers); /*_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 & (1 << 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 GLbitfield 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; } } if (fragProg && shProg->FragmentProgram) { /* notify driver that a new fragment program has been compiled/linked */ ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB, &shProg->FragmentProgram->Base);#if 0 printf("************** original fragment program\n"); _mesa_print_program(&fragProg->Base); _mesa_print_program_parameters(ctx, &fragProg->Base);#endif#if 0 printf("************** linked fragment prog\n"); _mesa_print_program(&shProg->FragmentProgram->Base); _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base);#endif } if (vertProg && shProg->VertexProgram) { /* notify driver that a new vertex program has been compiled/linked */ ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, &shProg->VertexProgram->Base);#if 0 printf("************** original vertex program\n"); _mesa_print_program(&vertProg->Base); _mesa_print_program_parameters(ctx, &vertProg->Base);#endif#if 0 printf("************** linked vertex prog\n"); _mesa_print_program(&shProg->VertexProgram->Base); _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base);#endif } shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -