/*
* Mesa 3-D graphics library
- * Version: 5.1
*
- * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
+ * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* \file arbprogram.c
- * \brief ARB_vertex/fragment_program state management functions.
+ * ARB_vertex/fragment_program state management functions.
* \author Brian Paul
*/
-#include "glheader.h"
-#include "arbprogram.h"
-#include "context.h"
-#include "hash.h"
-#include "imports.h"
-#include "macros.h"
-#include "mtypes.h"
-#include "nvprogram.h"
-#include "nvfragprog.h"
-#include "nvvertprog.h"
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/hash.h"
+#include "main/imports.h"
+#include "main/macros.h"
+#include "main/mtypes.h"
+#include "main/arbprogram.h"
+#include "program/arbprogparse.h"
+#include "program/program.h"
+#include "program/prog_print.h"
-/* XXX temporary */
-static void
-_mesa_parse_arb_vertex_program(GLcontext *ctx, GLenum target,
- const GLubyte *string, GLsizei len,
- struct vertex_program *prog)
+/**
+ * Bind a program (make it current)
+ * \note Called from the GL API dispatcher by both glBindProgramNV
+ * and glBindProgramARB.
+ */
+void GLAPIENTRY
+_mesa_BindProgramARB(GLenum target, GLuint id)
{
-}
+ struct gl_program *curProg, *newProg;
+ GET_CURRENT_CONTEXT(ctx);
+ /* Error-check target and get curProg */
+ if (target == GL_VERTEX_PROGRAM_ARB && ctx->Extensions.ARB_vertex_program) {
+ curProg = &ctx->VertexProgram.Current->Base;
+ }
+ else if (target == GL_FRAGMENT_PROGRAM_ARB
+ && ctx->Extensions.ARB_fragment_program) {
+ curProg = &ctx->FragmentProgram.Current->Base;
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramARB(target)");
+ return;
+ }
-static void
-_mesa_parse_arb_fragment_program(GLcontext *ctx, GLenum target,
- const GLubyte *string, GLsizei len,
- struct fragment_program *prog)
-{
-}
+ /*
+ * 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)
+ 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, "glBindProgramARB");
+ return;
+ }
+ _mesa_HashInsert(ctx->Shared->Programs, id, newProg);
+ }
+ else if (newProg->Target != target) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindProgramARB(target mismatch)");
+ return;
+ }
+ }
+ /** All error checking is complete now **/
+ if (curProg->Id == id) {
+ /* binding same program - no change */
+ return;
+ }
-void
-_mesa_EnableVertexAttribArrayARB(GLuint index)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
+ /* signal new program (and its new constants) */
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
- if (index >= ctx->Const.MaxVertexProgramAttribs) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glEnableVertexAttribArrayARB(index)");
- return;
+ /* bind newProg */
+ if (target == GL_VERTEX_PROGRAM_ARB) {
+ _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
+ gl_vertex_program(newProg));
}
+ else if (target == GL_FRAGMENT_PROGRAM_ARB) {
+ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
+ gl_fragment_program(newProg));
+ }
+
+ /* Never null pointers */
+ assert(ctx->VertexProgram.Current);
+ assert(ctx->FragmentProgram.Current);
- ctx->Array.VertexAttrib[index].Enabled = GL_TRUE;
- ctx->Array._Enabled |= _NEW_ARRAY_ATTRIB(index);
- ctx->Array.NewState |= _NEW_ARRAY_ATTRIB(index);
+ if (ctx->Driver.BindProgram)
+ ctx->Driver.BindProgram(ctx, target, newProg);
}
-void
-_mesa_DisableVertexAttribArrayARB(GLuint index)
+/**
+ * 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);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- if (index >= ctx->Const.MaxVertexProgramAttribs) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glEnableVertexAttribArrayARB(index)");
+ FLUSH_VERTICES(ctx, 0);
+
+ if (n < 0) {
+ _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
return;
}
- ctx->Array.VertexAttrib[index].Enabled = GL_FALSE;
- ctx->Array._Enabled &= ~_NEW_ARRAY_ATTRIB(index);
- ctx->Array.NewState |= _NEW_ARRAY_ATTRIB(index);
+ 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
-_mesa_GetVertexAttribdvARB(GLuint index, GLenum pname, GLdouble *params)
+/**
+ * Generate a list of new program identifiers.
+ * \note Not compiled into display lists.
+ * \note Called by both glGenProgramsNV and glGenProgramsARB.
+ */
+void GLAPIENTRY
+_mesa_GenProgramsARB(GLsizei n, GLuint *ids)
{
- GLfloat fparams[4];
+ GLuint first;
+ GLuint i;
GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- _mesa_GetVertexAttribfvARB(index, pname, fparams);
- if (ctx->ErrorValue == GL_NO_ERROR) {
- if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
- COPY_4V(params, fparams);
- }
- else {
- params[0] = fparams[0];
- }
+ if (n < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms");
+ return;
}
-}
+ if (!ids)
+ return;
+
+ _mesa_HashLockMutex(ctx->Shared->Programs);
-void
-_mesa_GetVertexAttribfvARB(GLuint index, GLenum pname, GLfloat *params)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
+ first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
- if (index == 0 || index >= VERT_ATTRIB_MAX) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribfvARB(index)");
- return;
+ /* Insert pointer to dummy program as placeholder */
+ for (i = 0; i < (GLuint) n; i++) {
+ _mesa_HashInsertLocked(ctx->Shared->Programs, first + i,
+ &_mesa_DummyProgram);
}
- switch (pname) {
- case GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB:
- params[0] = ctx->Array.VertexAttrib[index].Enabled;
- break;
- case GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB:
- params[0] = ctx->Array.VertexAttrib[index].Size;
- break;
- case GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB:
- params[0] = ctx->Array.VertexAttrib[index].Stride;
- break;
- case GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB:
- params[0] = ctx->Array.VertexAttrib[index].Type;
- break;
- case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB:
- params[0] = ctx->Array.VertexAttrib[index].Normalized;
- break;
- case GL_CURRENT_VERTEX_ATTRIB_ARB:
- COPY_4V(params, ctx->Current.Attrib[index]);
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribfvARB(pname)");
- return;
+ _mesa_HashUnlockMutex(ctx->Shared->Programs);
+
+ /* Return the program names */
+ for (i = 0; i < (GLuint) n; i++) {
+ ids[i] = first + i;
}
}
-void
-_mesa_GetVertexAttribivARB(GLuint index, GLenum pname, GLint *params)
+/**
+ * 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)
{
- GLfloat fparams[4];
+ struct gl_program *prog = NULL;
GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
- _mesa_GetVertexAttribfvARB(index, pname, fparams);
- if (ctx->ErrorValue == GL_NO_ERROR) {
- if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
- COPY_4V(params, fparams); /* float to int */
- }
- else {
- params[0] = fparams[0];
- }
- }
-}
+ if (id == 0)
+ return GL_FALSE;
+ prog = _mesa_lookup_program(ctx, id);
+ if (prog && (prog != &_mesa_DummyProgram))
+ return GL_TRUE;
+ else
+ return GL_FALSE;
+}
-void
-_mesa_GetVertexAttribPointervARB(GLuint index, GLenum pname, GLvoid **pointer)
+static GLboolean
+get_local_param_pointer(struct gl_context *ctx, const char *func,
+ GLenum target, GLuint index, GLfloat **param)
{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
+ struct gl_program *prog;
+ GLuint maxParams;
- if (index >= ctx->Const.MaxVertexProgramAttribs) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerARB(index)");
- return;
+ if (target == GL_VERTEX_PROGRAM_ARB
+ && ctx->Extensions.ARB_vertex_program) {
+ prog = &(ctx->VertexProgram.Current->Base);
+ maxParams = ctx->Const.Program[MESA_SHADER_VERTEX].MaxLocalParams;
+ }
+ else if (target == GL_FRAGMENT_PROGRAM_ARB
+ && ctx->Extensions.ARB_fragment_program) {
+ prog = &(ctx->FragmentProgram.Current->Base);
+ maxParams = ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxLocalParams;
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(target)", func);
+ return GL_FALSE;
}
- if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerARB(pname)");
- return;
+ if (index >= maxParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func);
+ return GL_FALSE;
}
- *pointer = ctx->Array.VertexAttrib[index].Ptr;;
+ if (!prog->LocalParams) {
+ prog->LocalParams = calloc(maxParams, sizeof(float[4]));
+ if (!prog->LocalParams)
+ return GL_FALSE;
+ }
+
+ *param = prog->LocalParams[index];
+ return GL_TRUE;
}
-void
+static GLboolean
+get_env_param_pointer(struct gl_context *ctx, const char *func,
+ GLenum target, GLuint index, GLfloat **param)
+{
+ if (target == GL_FRAGMENT_PROGRAM_ARB
+ && ctx->Extensions.ARB_fragment_program) {
+ if (index >= ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxEnvParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func);
+ return GL_FALSE;
+ }
+ *param = ctx->FragmentProgram.Parameters[index];
+ return GL_TRUE;
+ }
+ else if (target == GL_VERTEX_PROGRAM_ARB &&
+ ctx->Extensions.ARB_vertex_program) {
+ if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxEnvParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func);
+ return GL_FALSE;
+ }
+ *param = ctx->VertexProgram.Parameters[index];
+ return GL_TRUE;
+ } else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
+ return GL_FALSE;
+ }
+}
+
+void GLAPIENTRY
_mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len,
const GLvoid *string)
{
+ struct gl_program *base;
+ bool failed;
GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- if (target == GL_VERTEX_PROGRAM_ARB
- && ctx->Extensions.ARB_vertex_program) {
- struct vertex_program *prog = ctx->VertexProgram.Current;
- if (format != GL_PROGRAM_FORMAT_ASCII_ARB) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)");
- return;
- }
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
+
+ if (!ctx->Extensions.ARB_vertex_program
+ && !ctx->Extensions.ARB_fragment_program) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramStringARB()");
+ return;
+ }
+
+ if (format != GL_PROGRAM_FORMAT_ASCII_ARB) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)");
+ return;
+ }
+
+ if (target == GL_VERTEX_PROGRAM_ARB && ctx->Extensions.ARB_vertex_program) {
+ struct gl_vertex_program *prog = ctx->VertexProgram.Current;
_mesa_parse_arb_vertex_program(ctx, target, string, len, prog);
+
+ base = & prog->Base;
}
else if (target == GL_FRAGMENT_PROGRAM_ARB
&& ctx->Extensions.ARB_fragment_program) {
- struct fragment_program *prog = ctx->FragmentProgram.Current;
- if (format != GL_PROGRAM_FORMAT_ASCII_ARB) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)");
- return;
- }
+ struct gl_fragment_program *prog = ctx->FragmentProgram.Current;
_mesa_parse_arb_fragment_program(ctx, target, string, len, prog);
+
+ base = & prog->Base;
}
else {
_mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(target)");
+ return;
+ }
+
+ failed = ctx->Program.ErrorPos != -1;
+
+ if (!failed) {
+ /* finally, give the program to the driver for translation/checking */
+ if (!ctx->Driver.ProgramStringNotify(ctx, target, base)) {
+ failed = true;
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glProgramStringARB(rejected by driver");
+ }
+ }
+
+ if (ctx->_Shader->Flags & GLSL_DUMP) {
+ const char *shader_type =
+ target == GL_FRAGMENT_PROGRAM_ARB ? "fragment" : "vertex";
+
+ fprintf(stderr, "ARB_%s_program source for program %d:\n",
+ shader_type, base->Id);
+ fprintf(stderr, "%s\n", (const char *) string);
+
+ if (failed) {
+ fprintf(stderr, "ARB_%s_program %d failed to compile.\n",
+ shader_type, base->Id);
+ } else {
+ fprintf(stderr, "Mesa IR for ARB_%s_program %d:\n",
+ shader_type, base->Id);
+ _mesa_print_program(base);
+ fprintf(stderr, "\n");
+ }
+ fflush(stderr);
}
}
-void
+/**
+ * Set a program env parameter register.
+ * \note Called from the GL API dispatcher.
+ */
+void GLAPIENTRY
_mesa_ProgramEnvParameter4dARB(GLenum target, GLuint index,
GLdouble x, GLdouble y, GLdouble z, GLdouble w)
{
- _mesa_ProgramEnvParameter4fARB(target, index, x, y, z, w);
+ _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) x, (GLfloat) y,
+ (GLfloat) z, (GLfloat) w);
}
-void
+/**
+ * Set a program env parameter register.
+ * \note Called from the GL API dispatcher.
+ */
+void GLAPIENTRY
_mesa_ProgramEnvParameter4dvARB(GLenum target, GLuint index,
const GLdouble *params)
{
- _mesa_ProgramEnvParameter4fARB(target, index, params[0], params[1],
- params[2], params[3]);
+ _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) params[0],
+ (GLfloat) params[1], (GLfloat) params[2],
+ (GLfloat) params[3]);
}
-void
+/**
+ * Set a program env parameter register.
+ * \note Called from the GL API dispatcher.
+ */
+void GLAPIENTRY
_mesa_ProgramEnvParameter4fARB(GLenum target, GLuint index,
GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GLfloat *param;
+
+ GET_CURRENT_CONTEXT(ctx);
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
+
+ if (get_env_param_pointer(ctx, "glProgramEnvParameter",
+ target, index, ¶m)) {
+ ASSIGN_4V(param, x, y, z, w);
+ }
+}
+
+
+
+/**
+ * Set a program env parameter register.
+ * \note Called from the GL API dispatcher.
+ */
+void GLAPIENTRY
+_mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index,
+ const GLfloat *params)
+{
+ GLfloat *param;
+
+ GET_CURRENT_CONTEXT(ctx);
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
+
+ if (get_env_param_pointer(ctx, "glProgramEnvParameter4fv",
+ target, index, ¶m)) {
+ memcpy(param, params, 4 * sizeof(GLfloat));
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
+ const GLfloat *params)
{
GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
+ GLfloat * dest;
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
+
+ if (count <= 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(count)");
+ }
if (target == GL_FRAGMENT_PROGRAM_ARB
&& ctx->Extensions.ARB_fragment_program) {
- if (index >= ctx->Const.MaxFragmentProgramEnvParams) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)");
+ if ((index + count) > ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxEnvParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)");
return;
}
- index += FP_PROG_REG_START;
- ASSIGN_4V(ctx->FragmentProgram.Machine.Registers[index], x, y, z, w);
+ dest = ctx->FragmentProgram.Parameters[index];
}
- if (target == GL_VERTEX_PROGRAM_ARB
+ else if (target == GL_VERTEX_PROGRAM_ARB
&& ctx->Extensions.ARB_vertex_program) {
- if (index >= ctx->Const.MaxVertexProgramEnvParams) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)");
+ if ((index + count) > ctx->Const.Program[MESA_SHADER_VERTEX].MaxEnvParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)");
return;
}
- index += VP_PROG_REG_START;
- ASSIGN_4V(ctx->VertexProgram.Machine.Registers[index], x, y, z, w);
+ dest = ctx->VertexProgram.Parameters[index];
}
else {
- _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameter(target)");
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameters4fv(target)");
return;
}
-}
-
-void
-_mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index,
- const GLfloat *params)
-{
- _mesa_ProgramEnvParameter4fARB(target, index, params[0], params[1],
- params[2], params[3]);
+ memcpy(dest, params, count * 4 * sizeof(GLfloat));
}
-void
+void GLAPIENTRY
_mesa_GetProgramEnvParameterdvARB(GLenum target, GLuint index,
GLdouble *params)
{
GET_CURRENT_CONTEXT(ctx);
- GLfloat fparams[4];
+ GLfloat *fparam;
- _mesa_GetProgramEnvParameterfvARB(target, index, fparams);
- if (ctx->ErrorValue == GL_NO_ERROR) {
- params[0] = fparams[0];
- params[1] = fparams[1];
- params[2] = fparams[2];
- params[3] = fparams[3];
+ if (get_env_param_pointer(ctx, "glGetProgramEnvParameterdv",
+ target, index, &fparam)) {
+ COPY_4V(params, fparam);
}
}
-void
+void GLAPIENTRY
_mesa_GetProgramEnvParameterfvARB(GLenum target, GLuint index,
GLfloat *params)
{
+ GLfloat *param;
+
GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- if (target == GL_FRAGMENT_PROGRAM_ARB
- && ctx->Extensions.ARB_fragment_program) {
- if (index >= ctx->Const.MaxFragmentProgramEnvParams) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)");
- return;
- }
- index += FP_PROG_REG_START;
- COPY_4V(params, ctx->FragmentProgram.Machine.Registers[index]);
- }
- if (target == GL_VERTEX_PROGRAM_ARB
- && ctx->Extensions.ARB_vertex_program) {
- if (index >= ctx->Const.MaxVertexProgramEnvParams) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)");
- return;
- }
- index += VP_PROG_REG_START;
- COPY_4V(params, ctx->VertexProgram.Machine.Registers[index]);
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramEnvParameter(target)");
- return;
+ if (get_env_param_pointer(ctx, "glGetProgramEnvParameterfv",
+ target, index, ¶m)) {
+ COPY_4V(params, param);
}
}
-/**
- * Note, this function is also used by the GL_NV_fragment_program extension.
- */
-void
+void GLAPIENTRY
_mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index,
GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
GET_CURRENT_CONTEXT(ctx);
- struct program *prog;
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if ((target == GL_FRAGMENT_PROGRAM_NV
- && ctx->Extensions.NV_fragment_program) ||
- (target == GL_FRAGMENT_PROGRAM_ARB
- && ctx->Extensions.ARB_fragment_program)) {
- if (index >= ctx->Const.MaxFragmentProgramLocalParams) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB");
- return;
- }
- prog = &(ctx->FragmentProgram.Current->Base);
- }
- else if (target == GL_VERTEX_PROGRAM_ARB
- && ctx->Extensions.ARB_vertex_program) {
- if (index >= ctx->Const.MaxVertexProgramLocalParams) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB");
- return;
- }
- prog = &(ctx->VertexProgram.Current->Base);
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameterARB");
- return;
- }
+ GLfloat *param;
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
- ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS);
- prog->LocalParams[index][0] = x;
- prog->LocalParams[index][1] = y;
- prog->LocalParams[index][2] = z;
- prog->LocalParams[index][3] = w;
+ if (get_local_param_pointer(ctx, "glProgramLocalParameterARB",
+ target, index, ¶m)) {
+ assert(index < MAX_PROGRAM_LOCAL_PARAMS);
+ ASSIGN_4V(param, x, y, z, w);
+ }
}
-/**
- * Note, this function is also used by the GL_NV_fragment_program extension.
- */
-void
+void GLAPIENTRY
_mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index,
const GLfloat *params)
{
}
-/**
- * Note, this function is also used by the GL_NV_fragment_program extension.
- */
-void
+void GLAPIENTRY
+_mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
+ const GLfloat *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat *dest;
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
+
+ if (count <= 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fv(count)");
+ }
+
+ if (get_local_param_pointer(ctx, "glProgramLocalParameters4fvEXT",
+ target, index, &dest)) {
+ GLuint maxParams = target == GL_FRAGMENT_PROGRAM_ARB ?
+ ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxLocalParams :
+ ctx->Const.Program[MESA_SHADER_VERTEX].MaxLocalParams;
+
+ if ((index + count) > maxParams) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glProgramLocalParameters4fvEXT(index + count)");
+ return;
+ }
+
+ memcpy(dest, params, count * 4 * sizeof(GLfloat));
+ }
+}
+
+
+void GLAPIENTRY
_mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index,
GLdouble x, GLdouble y,
GLdouble z, GLdouble w)
}
-/**
- * Note, this function is also used by the GL_NV_fragment_program extension.
- */
-void
+void GLAPIENTRY
_mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index,
const GLdouble *params)
{
}
-/**
- * Note, this function is also used by the GL_NV_fragment_program extension.
- */
-void
+void GLAPIENTRY
_mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index,
GLfloat *params)
{
- const struct program *prog;
- GLuint maxParams;
+ GLfloat *param;
GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- if (target == GL_VERTEX_PROGRAM_ARB
- && ctx->Extensions.ARB_vertex_program) {
- prog = &(ctx->VertexProgram.Current->Base);
- maxParams = ctx->Const.MaxVertexProgramLocalParams;
- }
- else if (target == GL_FRAGMENT_PROGRAM_ARB
- && ctx->Extensions.ARB_fragment_program) {
- prog = &(ctx->FragmentProgram.Current->Base);
- maxParams = ctx->Const.MaxFragmentProgramLocalParams;
+ if (get_local_param_pointer(ctx, "glProgramLocalParameters4fvEXT",
+ target, index, ¶m)) {
+ COPY_4V(params, param);
}
- else if (target == GL_FRAGMENT_PROGRAM_NV
- && ctx->Extensions.NV_fragment_program) {
- prog = &(ctx->FragmentProgram.Current->Base);
- maxParams = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetProgramLocalParameterARB(target)");
- return;
- }
-
- if (index >= maxParams) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glGetProgramLocalParameterARB(index)");
- return;
- }
-
- ASSERT(prog);
- ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS);
- COPY_4V(params, prog->LocalParams[index]);
}
-/**
- * Note, this function is also used by the GL_NV_fragment_program extension.
- */
-void
+void GLAPIENTRY
_mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index,
GLdouble *params)
{
+ GLfloat *param;
GET_CURRENT_CONTEXT(ctx);
- GLfloat floatParams[4];
- _mesa_GetProgramLocalParameterfvARB(target, index, floatParams);
- if (ctx->ErrorValue == GL_NO_ERROR) {
- COPY_4V(params, floatParams);
+
+ if (get_local_param_pointer(ctx, "glProgramLocalParameters4fvEXT",
+ target, index, ¶m)) {
+ COPY_4V(params, param);
}
}
-void
+void GLAPIENTRY
_mesa_GetProgramivARB(GLenum target, GLenum pname, GLint *params)
{
- struct program *prog;
+ const struct gl_program_constants *limits;
+ struct gl_program *prog;
GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target == GL_VERTEX_PROGRAM_ARB
&& ctx->Extensions.ARB_vertex_program) {
prog = &(ctx->VertexProgram.Current->Base);
+ limits = &ctx->Const.Program[MESA_SHADER_VERTEX];
}
else if (target == GL_FRAGMENT_PROGRAM_ARB
- && ctx->Extensions.ARB_vertex_program) {
+ && ctx->Extensions.ARB_fragment_program) {
prog = &(ctx->FragmentProgram.Current->Base);
+ limits = &ctx->Const.Program[MESA_SHADER_FRAGMENT];
}
else {
_mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)");
return;
}
- ASSERT(prog);
+ assert(prog);
+ assert(limits);
+ /* Queries supported for both vertex and fragment programs */
switch (pname) {
case GL_PROGRAM_LENGTH_ARB:
- *params = prog->String ? _mesa_strlen((char *) prog->String) : 0;
- break;
+ *params
+ = prog->String ? (GLint) strlen((char *) prog->String) : 0;
+ return;
case GL_PROGRAM_FORMAT_ARB:
*params = prog->Format;
- break;
+ return;
case GL_PROGRAM_BINDING_ARB:
*params = prog->Id;
- break;
+ return;
case GL_PROGRAM_INSTRUCTIONS_ARB:
*params = prog->NumInstructions;
- break;
+ return;
case GL_MAX_PROGRAM_INSTRUCTIONS_ARB:
- if (target == GL_VERTEX_PROGRAM_ARB)
- *params = ctx->Const.MaxVertexProgramInstructions;
- else
- *params = ctx->Const.MaxFragmentProgramInstructions;
- break;
+ *params = limits->MaxInstructions;
+ return;
case GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
- *params = prog->NumInstructions;
- break;
+ *params = prog->NumNativeInstructions;
+ return;
case GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
- if (target == GL_VERTEX_PROGRAM_ARB)
- *params = ctx->Const.MaxVertexProgramInstructions;
- else
- *params = ctx->Const.MaxFragmentProgramInstructions;
- break;
+ *params = limits->MaxNativeInstructions;
+ return;
case GL_PROGRAM_TEMPORARIES_ARB:
*params = prog->NumTemporaries;
- break;
+ return;
case GL_MAX_PROGRAM_TEMPORARIES_ARB:
- if (target == GL_VERTEX_PROGRAM_ARB)
- *params = ctx->Const.MaxVertexProgramTemps;
- else
- *params = ctx->Const.MaxFragmentProgramTemps;
- break;
+ *params = limits->MaxTemps;
+ return;
case GL_PROGRAM_NATIVE_TEMPORARIES_ARB:
- /* XXX same as GL_PROGRAM_TEMPORARIES_ARB? */
- *params = prog->NumTemporaries;
- break;
+ *params = prog->NumNativeTemporaries;
+ return;
case GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB:
- /* XXX same as GL_MAX_PROGRAM_TEMPORARIES_ARB? */
- if (target == GL_VERTEX_PROGRAM_ARB)
- *params = ctx->Const.MaxVertexProgramTemps;
- else
- *params = ctx->Const.MaxFragmentProgramTemps;
- break;
+ *params = limits->MaxNativeTemps;
+ return;
case GL_PROGRAM_PARAMETERS_ARB:
*params = prog->NumParameters;
- break;
+ return;
case GL_MAX_PROGRAM_PARAMETERS_ARB:
- if (target == GL_VERTEX_PROGRAM_ARB)
- *params = ctx->Const.MaxVertexProgramLocalParams;
- else
- *params = ctx->Const.MaxFragmentProgramLocalParams;
- break;
+ *params = limits->MaxParameters;
+ return;
case GL_PROGRAM_NATIVE_PARAMETERS_ARB:
- /* XXX same as GL_MAX_PROGRAM_PARAMETERS_ARB? */
- *params = prog->NumParameters;
- break;
+ *params = prog->NumNativeParameters;
+ return;
case GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB:
- /* XXX same as GL_MAX_PROGRAM_PARAMETERS_ARB? */
- if (target == GL_VERTEX_PROGRAM_ARB)
- *params = ctx->Const.MaxVertexProgramLocalParams;
- else
- *params = ctx->Const.MaxFragmentProgramLocalParams;
- break;
+ *params = limits->MaxNativeParameters;
+ return;
case GL_PROGRAM_ATTRIBS_ARB:
*params = prog->NumAttributes;
- break;
+ return;
case GL_MAX_PROGRAM_ATTRIBS_ARB:
- if (target == GL_VERTEX_PROGRAM_ARB)
- *params = ctx->Const.MaxVertexProgramAttribs;
- else
- *params = ctx->Const.MaxFragmentProgramAttribs;
- break;
+ *params = limits->MaxAttribs;
+ return;
case GL_PROGRAM_NATIVE_ATTRIBS_ARB:
- /* XXX same as GL_PROGRAM_ATTRIBS_ARB? */
- *params = prog->NumAttributes;
- break;
+ *params = prog->NumNativeAttributes;
+ return;
case GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB:
- /* XXX same as GL_MAX_PROGRAM_ATTRIBS_ARB? */
- if (target == GL_VERTEX_PROGRAM_ARB)
- *params = ctx->Const.MaxVertexProgramAttribs;
- else
- *params = ctx->Const.MaxFragmentProgramAttribs;
- break;
+ *params = limits->MaxNativeAttribs;
+ return;
case GL_PROGRAM_ADDRESS_REGISTERS_ARB:
*params = prog->NumAddressRegs;
- break;
+ return;
case GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB:
- if (target == GL_VERTEX_PROGRAM_ARB)
- *params = ctx->Const.MaxVertexProgramAddressRegs;
- else
- *params = ctx->Const.MaxFragmentProgramAddressRegs;
- break;
+ *params = limits->MaxAddressRegs;
+ return;
case GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
- /* XXX same as GL_PROGRAM_ADDRESS_REGISTERS_ARB? */
- *params = prog->NumAddressRegs;
- break;
+ *params = prog->NumNativeAddressRegs;
+ return;
case GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
- /* XXX same as GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB? */
- if (target == GL_VERTEX_PROGRAM_ARB)
- *params = ctx->Const.MaxVertexProgramAddressRegs;
- else
- *params = ctx->Const.MaxFragmentProgramAddressRegs;
- break;
+ *params = limits->MaxNativeAddressRegs;
+ return;
case GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB:
- if (target == GL_VERTEX_PROGRAM_ARB)
- *params = ctx->Const.MaxVertexProgramLocalParams;
- else
- *params = ctx->Const.MaxFragmentProgramLocalParams;
- break;
+ *params = limits->MaxLocalParams;
+ return;
case GL_MAX_PROGRAM_ENV_PARAMETERS_ARB:
- if (target == GL_VERTEX_PROGRAM_ARB)
- *params = ctx->Const.MaxVertexProgramEnvParams;
- else
- *params = ctx->Const.MaxFragmentProgramEnvParams;
- break;
+ *params = limits->MaxEnvParams;
+ return;
case GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB:
- /* XXX ok? */
- *params = GL_TRUE;
+ /*
+ * XXX we may not really need a driver callback here.
+ * If the number of native instructions, registers, etc. used
+ * are all below the maximums, we could return true.
+ * The spec says that even if this query returns true, there's
+ * no guarantee that the program will run in hardware.
+ */
+ if (prog->Id == 0) {
+ /* default/null program */
+ *params = GL_FALSE;
+ }
+ else if (ctx->Driver.IsProgramNative) {
+ /* ask the driver */
+ *params = ctx->Driver.IsProgramNative( ctx, target, prog );
+ }
+ else {
+ /* probably running in software */
+ *params = GL_TRUE;
+ }
+ return;
+ default:
+ /* continue with fragment-program only queries below */
break;
+ }
- /*
- * The following apply to fragment programs only.
- */
- case GL_PROGRAM_ALU_INSTRUCTIONS_ARB:
- case GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
- if (target != GL_FRAGMENT_PROGRAM_ARB) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)");
+ /*
+ * The following apply to fragment programs only (at this time)
+ */
+ if (target == GL_FRAGMENT_PROGRAM_ARB) {
+ const struct gl_fragment_program *fp = ctx->FragmentProgram.Current;
+ switch (pname) {
+ case GL_PROGRAM_ALU_INSTRUCTIONS_ARB:
+ *params = fp->Base.NumNativeAluInstructions;
return;
- }
- *params = ctx->FragmentProgram.Current->NumAluInstructions;
- break;
- case GL_PROGRAM_TEX_INSTRUCTIONS_ARB:
- case GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
- if (target != GL_FRAGMENT_PROGRAM_ARB) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)");
+ case GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
+ *params = fp->Base.NumAluInstructions;
return;
- }
- *params = ctx->FragmentProgram.Current->NumTexInstructions;
- break;
- case GL_PROGRAM_TEX_INDIRECTIONS_ARB:
- case GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
- if (target != GL_FRAGMENT_PROGRAM_ARB) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)");
+ case GL_PROGRAM_TEX_INSTRUCTIONS_ARB:
+ *params = fp->Base.NumTexInstructions;
return;
- }
- *params = ctx->FragmentProgram.Current->NumTexIndirections;
- break;
- case GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB:
- case GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
- if (target != GL_FRAGMENT_PROGRAM_ARB) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)");
+ case GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
+ *params = fp->Base.NumNativeTexInstructions;
return;
- }
- *params = ctx->Const.MaxFragmentProgramAluInstructions;
- break;
- case GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB:
- case GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
- if (target != GL_FRAGMENT_PROGRAM_ARB) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)");
+ case GL_PROGRAM_TEX_INDIRECTIONS_ARB:
+ *params = fp->Base.NumTexIndirections;
return;
- }
- *params = ctx->Const.MaxFragmentProgramTexInstructions;
- break;
- case GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB:
- case GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
- if (target != GL_FRAGMENT_PROGRAM_ARB) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)");
+ case GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
+ *params = fp->Base.NumNativeTexIndirections;
return;
- }
- *params = ctx->Const.MaxFragmentProgramTexIndirections;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)");
- return;
+ case GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB:
+ *params = limits->MaxAluInstructions;
+ return;
+ case GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
+ *params = limits->MaxNativeAluInstructions;
+ return;
+ case GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB:
+ *params = limits->MaxTexInstructions;
+ return;
+ case GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
+ *params = limits->MaxNativeTexInstructions;
+ return;
+ case GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB:
+ *params = limits->MaxTexIndirections;
+ return;
+ case GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
+ *params = limits->MaxNativeTexIndirections;
+ return;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)");
+ return;
+ }
+ } else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)");
+ return;
}
}
-void
+void GLAPIENTRY
_mesa_GetProgramStringARB(GLenum target, GLenum pname, GLvoid *string)
{
- struct program *prog;
+ const struct gl_program *prog;
+ char *dst = (char *) string;
GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target == GL_VERTEX_PROGRAM_ARB) {
prog = &(ctx->VertexProgram.Current->Base);
return;
}
- ASSERT(prog);
+ assert(prog);
if (pname != GL_PROGRAM_STRING_ARB) {
_mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(pname)");
return;
}
- MEMCPY(string, prog->String, _mesa_strlen((char *) prog->String));
+ if (prog->String)
+ memcpy(dst, prog->String, strlen((char *) prog->String));
+ else
+ *dst = '\0';
}