/** * Load/parse/compile a program. * \note Called from the GL API dispatcher. */ void GLAPIENTRY _mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len, const GLubyte *program) { struct gl_program *prog; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (id == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)"); return; } if (len < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(len)"); return; } FLUSH_VERTICES(ctx, _NEW_PROGRAM); prog = _mesa_lookup_program(ctx, id); if (prog && prog->Target != 0 && prog->Target != target) { _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)"); return; } if ((target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_STATE_PROGRAM_NV) && ctx->Extensions.NV_vertex_program) { struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog; if (!vprog || prog == &_mesa_DummyProgram) { vprog = (struct gl_vertex_program *) ctx->Driver.NewProgram(ctx, target, id); if (!vprog) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); return; } _mesa_HashInsert(ctx->Shared->Programs, id, vprog); } _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog); } else if (target == GL_FRAGMENT_PROGRAM_NV && ctx->Extensions.NV_fragment_program) { struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog; if (!fprog || prog == &_mesa_DummyProgram) { fprog = (struct gl_fragment_program *) ctx->Driver.NewProgram(ctx, target, id); if (!fprog) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); return; } _mesa_HashInsert(ctx->Shared->Programs, id, fprog); } _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog); } else { _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)"); } }
/** * Get the program source code. * \note Not compiled into display lists. * \note Called from the GL API dispatcher. */ void GLAPIENTRY _mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program) { struct gl_program *prog; GET_CURRENT_CONTEXT(ctx); if (!ctx->_CurrentProgram) ASSERT_OUTSIDE_BEGIN_END(ctx); if (pname != GL_PROGRAM_STRING_NV) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringNV(pname)"); return; } prog = _mesa_lookup_program(ctx, id); if (!prog) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramStringNV"); return; } if (prog->String) { MEMCPY(program, prog->String, _mesa_strlen((char *) prog->String)); } else { program[0] = 0; } }
/** * Get a program attribute. * \note Not compiled into display lists. * \note Called from the GL API dispatcher. */ void GLAPIENTRY _mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params) { struct gl_program *prog; GET_CURRENT_CONTEXT(ctx); if (!ctx->_CurrentProgram) ASSERT_OUTSIDE_BEGIN_END(ctx); prog = _mesa_lookup_program(ctx, id); if (!prog) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV"); return; } switch (pname) { case GL_PROGRAM_TARGET_NV: *params = prog->Target; return; case GL_PROGRAM_LENGTH_NV: *params = prog->String ?(GLint)_mesa_strlen((char *) prog->String) : 0; return; case GL_PROGRAM_RESIDENT_NV: *params = prog->Resident; return; default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)"); return; } }
/** * Request that a set of programs be resident in hardware. * \note Called from the GL API dispatcher. */ void GLAPIENTRY _mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids) { GLint i; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(n)"); return; } /* just error checking for now */ for (i = 0; i < n; i++) { struct gl_program *prog; if (ids[i] == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)"); return; } prog = _mesa_lookup_program(ctx, ids[i]); if (!prog) { _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)"); return; } /* XXX this is really a hardware thing we should hook out */ prog->Resident = GL_TRUE; } }
/** * Determine if id names a vertex or fragment program. * \note Not compiled into display lists. * \note Called from both glIsProgramNV and glIsProgramARB. * \param id is the program identifier * \return GL_TRUE if id is a program, else GL_FALSE. */ GLboolean GLAPIENTRY _mesa_IsProgramARB(GLuint id) { struct gl_program *prog = NULL; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); if (id == 0) return GL_FALSE; prog = _mesa_lookup_program(ctx, id); if (prog && (prog != &_mesa_DummyProgram)) return GL_TRUE; else return GL_FALSE; }
/** * 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); } } } }
/** * Determine if a set of programs is resident in hardware. * \note Not compiled into display lists. * \note Called from the GL API dispatcher. */ GLboolean GLAPIENTRY _mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids, GLboolean *residences) { GLint i, j; GLboolean allResident = GL_TRUE; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(n)"); return GL_FALSE; } for (i = 0; i < n; i++) { const struct gl_program *prog; if (ids[i] == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV"); return GL_FALSE; } prog = _mesa_lookup_program(ctx, ids[i]); if (!prog) { _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV"); return GL_FALSE; } if (prog->Resident) { if (!allResident) residences[i] = GL_TRUE; } else { if (allResident) { allResident = GL_FALSE; for (j = 0; j < i; j++) residences[j] = GL_TRUE; } residences[i] = GL_FALSE; } } return allResident; }
/** * Execute a vertex state program. * \note Called from the GL API dispatcher. */ void GLAPIENTRY _mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params) { struct gl_vertex_program *vprog; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (target != GL_VERTEX_STATE_PROGRAM_NV) { _mesa_error(ctx, GL_INVALID_ENUM, "glExecuteProgramNV"); return; } FLUSH_VERTICES(ctx, _NEW_PROGRAM); vprog = (struct gl_vertex_program *) _mesa_lookup_program(ctx, id); if (!vprog || vprog->Base.Target != GL_VERTEX_STATE_PROGRAM_NV) { _mesa_error(ctx, GL_INVALID_OPERATION, "glExecuteProgramNV"); return; } _mesa_problem(ctx, "glExecuteProgramNV() not supported"); }
void GLAPIENTRY _mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name, GLfloat *params) { struct gl_program *prog; struct gl_fragment_program *fragProg; const GLfloat *v; GET_CURRENT_CONTEXT(ctx); if (!ctx->_CurrentProgram) ASSERT_OUTSIDE_BEGIN_END(ctx); prog = _mesa_lookup_program(ctx, id); if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramNamedParameterNV"); return; } if (len <= 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV"); return; } fragProg = (struct gl_fragment_program *) prog; v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, len, (char *) name); if (v) { params[0] = v[0]; params[1] = v[1]; params[2] = v[2]; params[3] = v[3]; return; } _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV"); }
void GLAPIENTRY _mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { struct gl_program *prog; struct gl_fragment_program *fragProg; GLfloat *v; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); FLUSH_VERTICES(ctx, _NEW_PROGRAM); prog = _mesa_lookup_program(ctx, id); if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) { _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramNamedParameterNV"); return; } if (len <= 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(len)"); return; } fragProg = (struct gl_fragment_program *) prog; v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, len, (char *) name); if (v) { v[0] = x; v[1] = y; v[2] = z; v[3] = w; return; } _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(name)"); }
/** * Bind a program (make it current) * \note Called from the GL API dispatcher by both glBindProgramNV * and glBindProgramARB. */ void GLAPIENTRY _mesa_BindProgram(GLenum target, GLuint id) { struct gl_program *curProg, *newProg; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); /* Error-check target and get curProg */ if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */ (ctx->Extensions.NV_vertex_program || ctx->Extensions.ARB_vertex_program)) { curProg = &ctx->VertexProgram.Current->Base; } else if ((target == GL_FRAGMENT_PROGRAM_NV && ctx->Extensions.NV_fragment_program) || (target == GL_FRAGMENT_PROGRAM_ARB && ctx->Extensions.ARB_fragment_program)) { curProg = &ctx->FragmentProgram.Current->Base; } else { _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)"); return; } /* * Get pointer to new program to bind. * NOTE: binding to a non-existant program is not an error. * That's supposed to be caught in glBegin. */ if (id == 0) { /* Bind a default program */ newProg = NULL; if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */ newProg = &ctx->Shared->DefaultVertexProgram->Base; else newProg = &ctx->Shared->DefaultFragmentProgram->Base; } else { /* Bind a user program */ newProg = _mesa_lookup_program(ctx, id); if (!newProg || newProg == &_mesa_DummyProgram) { /* allocate a new program now */ newProg = ctx->Driver.NewProgram(ctx, target, id); if (!newProg) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB"); return; } _mesa_HashInsert(ctx->Shared->Programs, id, newProg); } else if (!compatible_program_targets(newProg->Target, target)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindProgramNV/ARB(target mismatch)"); return; } } /** All error checking is complete now **/ if (curProg->Id == id) { /* binding same program - no change */ return; } /* signal new program (and its new constants) */ FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); /* bind newProg */ if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */ _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, (struct gl_vertex_program *) newProg); } else if (target == GL_FRAGMENT_PROGRAM_NV || target == GL_FRAGMENT_PROGRAM_ARB) { _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, (struct gl_fragment_program *) newProg); } /* Never null pointers */ ASSERT(ctx->VertexProgram.Current); ASSERT(ctx->FragmentProgram.Current); if (ctx->Driver.BindProgram) ctx->Driver.BindProgram(ctx, target, newProg); }