#include "glheader.h"
#include "context.h"
#include "hash.h"
#include "imports.h"
#include "macros.h"
#include "mtypes.h"
#include "vpexec.h"
#include "vpparse.h"
#include "vpstate.h"
void _mesa_delete_program(GLcontext *ctx, GLuint id)
{
struct vp_program *vprog = (struct vp_program *)
_mesa_HashLookup(ctx->Shared->VertexPrograms, id);
if (vprog) {
if (vprog->String)
FREE(vprog->String);
if (vprog->Instructions)
FREE(vprog->Instructions);
_mesa_HashRemove(ctx->Shared->VertexPrograms, id);
FREE(vprog);
}
}
void _mesa_BindProgramNV(GLenum target, GLuint id)
{
struct vp_program *vprog;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target != GL_VERTEX_PROGRAM_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV");
return;
}
if (id == ctx->VertexProgram.CurrentID)
return;
if (ctx->VertexProgram.Current) {
ctx->VertexProgram.Current->RefCount--;
if (ctx->VertexProgram.Current->RefCount <= 0)
_mesa_delete_program(ctx, ctx->VertexProgram.CurrentID);
}
if (id == 0) {
vprog = NULL;
}
else {
vprog = (struct vp_program *)
_mesa_HashLookup(ctx->Shared->VertexPrograms, id);
if (!vprog && id > 0){
vprog = CALLOC_STRUCT(vp_program);
if (!vprog) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV");
return;
}
vprog->Target = target;
vprog->Resident = GL_TRUE;
vprog->RefCount = 1;
_mesa_HashInsert(ctx->Shared->VertexPrograms, id, vprog);
}
}
ctx->VertexProgram.CurrentID = id;
ctx->VertexProgram.Current = vprog;
if (vprog)
vprog->RefCount++;
}
void _mesa_DeleteProgramsNV(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, "glDeleteProgramsNV" );
return;
}
for (i = 0; i < n; i++) {
if (ids[i] != 0) {
struct vp_program *vprog = (struct vp_program *)
_mesa_HashLookup(ctx->Shared->VertexPrograms, ids[i]);
if (ctx->VertexProgram.CurrentID == ids[i]) {
_mesa_BindProgramNV(vprog->Target, 0);
}
if (vprog) {
vprog->RefCount--;
if (vprog->RefCount <= 0) {
_mesa_delete_program(ctx, ids[i]);
}
}
}
}
}
void _mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params)
{
struct vp_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;
}
vprog = (struct vp_program *)
_mesa_HashLookup(ctx->Shared->VertexPrograms, id);
if (!vprog || vprog->Target != GL_VERTEX_STATE_PROGRAM_NV) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glExecuteProgramNV");
return;
}
_mesa_init_vp_registers(ctx);
_mesa_init_tracked_matrices(ctx);
COPY_4V(ctx->VertexProgram.Machine.Registers[VP_INPUT_REG_START], params);
_mesa_exec_program(ctx, vprog);
}
void _mesa_GenProgramsNV(GLsizei n, GLuint *ids)
{
GLuint first;
GLuint i;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (n < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGenProgramsNV");
return;
}
if (!ids)
return;
first = _mesa_HashFindFreeKeyBlock(ctx->Shared->VertexPrograms, n);
for (i = 0; i < (GLuint) n; i++) {
struct vp_program *vprog = CALLOC_STRUCT(vp_program);
if (!vprog) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenProgramsNV");
return;
}
vprog->RefCount = 1;
_mesa_HashInsert(ctx->Shared->VertexPrograms, first + i, vprog);
}
for (i = 0; i < (GLuint) n; i++) {
ids[i] = first + i;
}
}
GLboolean _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 vp_program *prog;
if (ids[i] == 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV");
return GL_FALSE;
}
prog = (const struct vp_program *)
_mesa_HashLookup(ctx->Shared->VertexPrograms, 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;
}
void _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;
}
for (i = 0; i < n; i++) {
struct vp_program *vprog;
if (ids[i] == 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
return;
}
vprog = (struct vp_program *)
_mesa_HashLookup(ctx->Shared->VertexPrograms, ids[i]);
if (!vprog) {
_mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
return;
}
vprog->Resident = GL_TRUE;
}
}
void _mesa_GetProgramParameterfvNV(GLenum target, GLuint index,
GLenum pname, GLfloat *params)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target != GL_VERTEX_PROGRAM_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV");
return;
}
if (index >= VP_NUM_PROG_REGS) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramParameterfvNV");
return;
}
if (pname != GL_PROGRAM_PARAMETER_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV");
return;
}
index += VP_PROG_REG_START;
COPY_4V(params, ctx->VertexProgram.Machine.Registers[index]);
}
void _mesa_GetProgramParameterdvNV(GLenum target, GLuint index,
GLenum pname, GLdouble *params)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target != GL_VERTEX_PROGRAM_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV");
return;
}
if (index >= VP_NUM_PROG_REGS) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramParameterfvNV");
return;
}
if (pname != GL_PROGRAM_PARAMETER_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV");
return;
}
index += VP_PROG_REG_START;
COPY_4V(params, ctx->VertexProgram.Machine.Registers[index]);
}
void _mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params)
{
struct vp_program *vprog;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
vprog = (struct vp_program *)
_mesa_HashLookup(ctx->Shared->VertexPrograms, id);
if (!vprog) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV");
return;
}
switch (pname) {
case GL_PROGRAM_TARGET_NV:
*params = vprog->Target;
return;
case GL_PROGRAM_LENGTH_NV:
*params = vprog->String ? _mesa_strlen((char *) vprog->String) : 0;
return;
case GL_PROGRAM_RESIDENT_NV:
*params = vprog->Resident;
return;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)");
return;
}
}
void _mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program)
{
struct vp_program *vprog;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (pname != GL_PROGRAM_STRING_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)");
return;
}
vprog = (struct vp_program *)
_mesa_HashLookup(ctx->Shared->VertexPrograms, id);
if (!vprog) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV");
return;
}
if (vprog->String) {
MEMCPY(program, vprog->String, _mesa_strlen((char *) vprog->String));
}
else {
program[0] = 0;
}
}
void _mesa_GetTrackMatrixivNV(GLenum target, GLuint address,
GLenum pname, GLint *params)
{
GLuint i;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target != GL_VERTEX_PROGRAM_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
return;
}
if ((address & 0x3) || address > VP_NUM_PROG_REGS) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetTrackMatrixivNV(address)");
return;
}
i = address / 4;
switch (pname) {
case GL_TRACK_MATRIX_NV:
params[0] = (GLint) ctx->VertexProgram.TrackMatrix[i];
return;
case GL_TRACK_MATRIX_TRANSFORM_NV:
params[0] = (GLint) ctx->VertexProgram.TrackMatrixTransform[i];
return;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV");
return;
}
}
void _mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (index == 0 || index >= VP_NUM_INPUT_REGS) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
return;
}
switch (pname) {
case GL_ATTRIB_ARRAY_SIZE_NV:
params[0] = ctx->Array.VertexAttrib[index].Size;
break;
case GL_ATTRIB_ARRAY_STRIDE_NV:
params[0] = ctx->Array.VertexAttrib[index].Stride;
break;
case GL_ATTRIB_ARRAY_TYPE_NV:
params[0] = ctx->Array.VertexAttrib[index].Type;
break;
case GL_CURRENT_ATTRIB_NV:
FLUSH_CURRENT(ctx, 0);
COPY_4V(params, ctx->Current.Attrib[index]);
break;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
return;
}
}
void _mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (index == 0 || index >= VP_NUM_INPUT_REGS) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
return;
}
switch (pname) {
case GL_ATTRIB_ARRAY_SIZE_NV:
params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Size;
break;
case GL_ATTRIB_ARRAY_STRIDE_NV:
params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Stride;
break;
case GL_ATTRIB_ARRAY_TYPE_NV:
params[0] = (GLfloat) ctx->Array.VertexAttrib[index].Type;
break;
case GL_CURRENT_ATTRIB_NV:
FLUSH_CURRENT(ctx, 0);
COPY_4V(params, ctx->Current.Attrib[index]);
break;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
return;
}
}
void _mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (index == 0 || index >= VP_NUM_INPUT_REGS) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)");
return;
}
switch (pname) {
case GL_ATTRIB_ARRAY_SIZE_NV:
params[0] = ctx->Array.VertexAttrib[index].Size;
break;
case GL_ATTRIB_ARRAY_STRIDE_NV:
params[0] = ctx->Array.VertexAttrib[index].Stride;
break;
case GL_ATTRIB_ARRAY_TYPE_NV:
params[0] = ctx->Array.VertexAttrib[index].Type;
break;
case GL_CURRENT_ATTRIB_NV:
FLUSH_CURRENT(ctx, 0);
COPY_4V_CAST(params, ctx->Current.Attrib[index], GLint);
break;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV");
return;
}
}
void _mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (index >= VP_NUM_PROG_REGS) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerNV(index)");
return;
}
if (pname != GL_ATTRIB_ARRAY_POINTER_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerNV(pname)");
return;
}
*pointer = ctx->Array.VertexAttrib[index].Ptr;;
}
GLboolean _mesa_IsProgramNV(GLuint id)
{
struct vp_program *vprog;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
if (id == 0)
return GL_FALSE;
vprog = (struct vp_program *)
_mesa_HashLookup(ctx->Shared->VertexPrograms, id);
if (vprog && vprog->Target)
return GL_TRUE;
else
return GL_FALSE;
}
void _mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len,
const GLubyte *program)
{
struct vp_program *vprog;
GLboolean newProgram = GL_FALSE;
GLubyte *programCopy;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (id == 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)");
return;
}
vprog = (struct vp_program *)
_mesa_HashLookup(ctx->Shared->VertexPrograms, id);
if (vprog && vprog->Target != 0 && vprog->Target != target) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)");
return;
}
programCopy = (GLubyte *) MALLOC(len + 1);
if (!programCopy) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
return;
}
MEMCPY(programCopy, program, len);
programCopy[len] = 0;
if (!vprog) {
newProgram = GL_TRUE;
vprog = CALLOC_STRUCT(vp_program);
if (!vprog) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
return;
}
}
_mesa_parse_program(ctx, target, programCopy, vprog);
if (ctx->VertexProgram.ErrorPos == -1) {
if (newProgram) {
_mesa_HashInsert(ctx->Shared->VertexPrograms, id, vprog);
}
vprog->RefCount = 1;
vprog->Resident = GL_TRUE;
}
FREE(programCopy);
}
void _mesa_ProgramParameter4dNV(GLenum target, GLuint index,
GLdouble x, GLdouble y, GLdouble z, GLdouble w)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target != GL_VERTEX_PROGRAM_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameter4dNV");
return;
}
if (index >= VP_NUM_PROG_REGS) {
_mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameter4dNV");
return;
}
index += VP_PROG_REG_START;
ASSIGN_4V(ctx->VertexProgram.Machine.Registers[index],
(GLfloat)x, (GLfloat)y, (GLfloat)z, (GLfloat)w);
}
void _mesa_ProgramParameter4dvNV(GLenum target, GLuint index,
const GLdouble *params)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target != GL_VERTEX_PROGRAM_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameter4dvNV");
return;
}
if (index >= VP_NUM_PROG_REGS) {
_mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameter4dvNV");
return;
}
index += VP_PROG_REG_START;
COPY_4V_CAST(ctx->VertexProgram.Machine.Registers[index], params, GLfloat);
}
void _mesa_ProgramParameter4fNV(GLenum target, GLuint index,
GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target != GL_VERTEX_PROGRAM_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameter4fNV");
return;
}
if (index >= VP_NUM_PROG_REGS) {
_mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameter4fNV");
return;
}
index += VP_PROG_REG_START;
ASSIGN_4V(ctx->VertexProgram.Machine.Registers[index], x, y, z, w);
}
void _mesa_ProgramParameter4fvNV(GLenum target, GLuint index,
const GLfloat *params)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target != GL_VERTEX_PROGRAM_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameter4fNV");
return;
}
if (index >= VP_NUM_PROG_REGS) {
_mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameter4fNV");
return;
}
index += VP_PROG_REG_START;
COPY_4V(ctx->VertexProgram.Machine.Registers[index], params);
}
void _mesa_ProgramParameters4dvNV(GLenum target, GLuint index,
GLuint num, const GLdouble *params)
{
GLuint i;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target != GL_VERTEX_PROGRAM_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4dvNV");
return;
}
if (index + num > VP_NUM_PROG_REGS) {
_mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4dvNV");
return;
}
index += VP_PROG_REG_START;
for (i = 0; i < num; i++) {
COPY_4V_CAST(ctx->VertexProgram.Machine.Registers[index + i],
params, GLfloat);
params += 4;
};
}
void _mesa_ProgramParameters4fvNV(GLenum target, GLuint index,
GLuint num, const GLfloat *params)
{
GLuint i;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target != GL_VERTEX_PROGRAM_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4fvNV");
return;
}
if (index + num > VP_NUM_PROG_REGS) {
_mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4fvNV");
return;
}
index += VP_PROG_REG_START;
for (i = 0; i < num; i++) {
COPY_4V(ctx->VertexProgram.Machine.Registers[index + i], params);
params += 4;
};
}
void _mesa_TrackMatrixNV(GLenum target, GLuint address,
GLenum matrix, GLenum transform)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target != GL_VERTEX_PROGRAM_NV) {
_mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(target)");
return;
}
if (address & 0x3) {
_mesa_error(ctx, GL_INVALID_VALUE, "glTrackMatrixNV(address)");
return;
}
switch (matrix) {
case GL_NONE:
case GL_MODELVIEW:
case GL_PROJECTION:
case GL_TEXTURE:
case GL_COLOR:
case GL_MODELVIEW_PROJECTION_NV:
case GL_MATRIX0_NV:
case GL_MATRIX1_NV:
case GL_MATRIX2_NV:
case GL_MATRIX3_NV:
case GL_MATRIX4_NV:
case GL_MATRIX5_NV:
case GL_MATRIX6_NV:
case GL_MATRIX7_NV:
break;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(matrix)");
return;
}
switch (transform) {
case GL_IDENTITY_NV:
case GL_INVERSE_NV:
case GL_TRANSPOSE_NV:
case GL_INVERSE_TRANSPOSE_NV:
break;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(transform)");
return;
}
ctx->VertexProgram.TrackMatrix[address / 4] = matrix;
ctx->VertexProgram.TrackMatrixTransform[address / 4] = transform;
}