440 lines
12 KiB
C
440 lines
12 KiB
C
|
/*
|
||
|
* GL_ARB_shader_objects & GL_ARB_vertex_shader interface test application.
|
||
|
* Neither compiler nor executor is being tested here, although some simple shader
|
||
|
* compilation tests are performed.
|
||
|
*
|
||
|
* Perfectly valid behaviour produces output that does not have a line
|
||
|
* beginning with three stars (***).
|
||
|
*
|
||
|
* Author: Michal Krol
|
||
|
*/
|
||
|
|
||
|
#include "framework.h"
|
||
|
|
||
|
enum TEST_TYPE
|
||
|
{
|
||
|
TT_GETERROR_NOERROR,
|
||
|
TT_GETERROR_INVALIDVALUE,
|
||
|
TT_GETERROR_INVALIDOPERATION,
|
||
|
TT_PARAM1_ZERO,
|
||
|
TT_PARAM1_NONZERO
|
||
|
};
|
||
|
|
||
|
static enum TEST_TYPE current_test;
|
||
|
|
||
|
static void begintest (enum TEST_TYPE type, const char *name)
|
||
|
{
|
||
|
current_test = type;
|
||
|
printf ("\n BEGIN TEST: %s\n", name);
|
||
|
while (glGetError () != GL_NO_ERROR)
|
||
|
;
|
||
|
}
|
||
|
|
||
|
static void endtest1 (GLuint param1)
|
||
|
{
|
||
|
const char *msg = NULL;
|
||
|
|
||
|
switch (current_test)
|
||
|
{
|
||
|
case TT_GETERROR_NOERROR:
|
||
|
if (glGetError () != GL_NO_ERROR)
|
||
|
msg = "glGetError () does not return GL_NO_ERROR";
|
||
|
break;
|
||
|
case TT_GETERROR_INVALIDVALUE:
|
||
|
if (glGetError () != GL_INVALID_VALUE)
|
||
|
msg = "glGetError () does not return GL_INVALID_VALUE";
|
||
|
break;
|
||
|
case TT_GETERROR_INVALIDOPERATION:
|
||
|
if (glGetError () != GL_INVALID_OPERATION)
|
||
|
msg = "glGetError () does not return GL_INVALID_OPERATION";
|
||
|
break;
|
||
|
case TT_PARAM1_ZERO:
|
||
|
if (param1)
|
||
|
msg = "The parameter is not zero";
|
||
|
break;
|
||
|
case TT_PARAM1_NONZERO:
|
||
|
if (!param1)
|
||
|
msg = "The parameter is not non-zero";
|
||
|
break;
|
||
|
default:
|
||
|
assert (0);
|
||
|
}
|
||
|
|
||
|
if (msg == NULL)
|
||
|
printf (" OK\n");
|
||
|
else
|
||
|
printf ("*** %s\n", msg);
|
||
|
|
||
|
while (glGetError () != GL_NO_ERROR)
|
||
|
;
|
||
|
}
|
||
|
|
||
|
static void endtest ()
|
||
|
{
|
||
|
endtest1 (0);
|
||
|
}
|
||
|
|
||
|
static GLhandleARB vert = 0;
|
||
|
static GLhandleARB frag = 0;
|
||
|
static GLhandleARB prog = 0;
|
||
|
|
||
|
static GLhandleARB find_invalid_handle ()
|
||
|
{
|
||
|
GLhandleARB handle;
|
||
|
|
||
|
for (handle = 1; handle < 16; handle++)
|
||
|
if (handle != vert && handle != frag && handle != prog)
|
||
|
return handle;
|
||
|
assert (0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static const char *invsynvertsrc =
|
||
|
"void main () {\n"
|
||
|
" gl_Position = gl_ModelViewMatrix ! gl_Vertex;\n" /* unexpected token */
|
||
|
"}\n"
|
||
|
;
|
||
|
|
||
|
static const char *invsemvertsrc =
|
||
|
"void main () {\n"
|
||
|
" gl_Position = gl_ModelviewMatrix * gl_Vertex;\n" /* undeclared identifier */
|
||
|
"}\n"
|
||
|
;
|
||
|
|
||
|
static const char *uniforms =
|
||
|
"uniform vec4 CommonUniform;\n"
|
||
|
;
|
||
|
|
||
|
static const char *validvertsrc =
|
||
|
"uniform vec4 VertexUniform;\n"
|
||
|
"attribute vec4 FirstAttrib;\n"
|
||
|
"attribute vec4 SecondAttrib;\n"
|
||
|
"void main () {\n"
|
||
|
" gl_Position = gl_ModelViewMatrix * gl_Vertex + CommonUniform + VertexUniform\n"
|
||
|
" + FirstAttrib + SecondAttrib;\n"
|
||
|
"}\n"
|
||
|
;
|
||
|
|
||
|
static const char *invsynfragsrc =
|
||
|
"void main () {\n"
|
||
|
" gl_FragColor = gl_Color\n" /* missing ; */
|
||
|
"}\n"
|
||
|
;
|
||
|
|
||
|
static const char *invsemfragsrc =
|
||
|
"void main () {\n"
|
||
|
" gl_FragColor = gl_FrontColor;\n" /* gl_FrontColor only in vertex shader */
|
||
|
"}\n"
|
||
|
;
|
||
|
|
||
|
static const char *validfragsrc =
|
||
|
"uniform vec4 FragmentUniform;\n"
|
||
|
"void main () {\n"
|
||
|
" gl_FragColor = gl_Color + CommonUniform + FragmentUniform;\n"
|
||
|
"}\n"
|
||
|
;
|
||
|
|
||
|
void InitScene (void)
|
||
|
{
|
||
|
GLint params[1];
|
||
|
const char *tab[2];
|
||
|
|
||
|
/*
|
||
|
* GL should silently ignore calls that delete object 0.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_NOERROR, "glDeleteObject(0)");
|
||
|
glDeleteObjectARB (0);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* GL generates an error on invalid object handle.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_INVALIDVALUE, "Pass invalid non-zero object handle");
|
||
|
glDeleteObjectARB (find_invalid_handle ());
|
||
|
endtest ();
|
||
|
glUseProgramObjectARB (find_invalid_handle ());
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Create object. GL should return unique non-zero values.
|
||
|
*/
|
||
|
begintest (TT_PARAM1_NONZERO, "Create object");
|
||
|
vert = glCreateShaderObjectARB (GL_VERTEX_SHADER_ARB);
|
||
|
endtest1 (vert);
|
||
|
frag = glCreateShaderObjectARB (GL_FRAGMENT_SHADER_ARB);
|
||
|
endtest1 (frag);
|
||
|
prog = glCreateProgramObjectARB ();
|
||
|
endtest1 (prog);
|
||
|
endtest1 (vert != frag && frag != prog && prog != vert);
|
||
|
|
||
|
/*
|
||
|
* Link empty program.
|
||
|
*/
|
||
|
begintest (TT_PARAM1_NONZERO, "Link empty program");
|
||
|
glLinkProgramARB (prog);
|
||
|
endtest1 (CheckObjectStatus (prog));
|
||
|
|
||
|
/*
|
||
|
* Use empty program object. Empty program objects are valid.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_NOERROR, "Use empty program object");
|
||
|
glUseProgramObjectARB (prog);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Attach invalid object handles. Program object 0 should not be accepted.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_INVALIDVALUE, "Attach invalid object handle");
|
||
|
glAttachObjectARB (0, find_invalid_handle ());
|
||
|
endtest ();
|
||
|
glAttachObjectARB (0, frag);
|
||
|
endtest ();
|
||
|
glAttachObjectARB (find_invalid_handle (), find_invalid_handle ());
|
||
|
endtest ();
|
||
|
glAttachObjectARB (find_invalid_handle (), frag);
|
||
|
endtest ();
|
||
|
glAttachObjectARB (prog, find_invalid_handle ());
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Attach valid object handles with wrong semantics.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_INVALIDOPERATION, "Attach object badly");
|
||
|
glAttachObjectARB (vert, frag);
|
||
|
endtest ();
|
||
|
glAttachObjectARB (vert, prog);
|
||
|
endtest ();
|
||
|
glAttachObjectARB (prog, prog);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Detach non-attached object.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_INVALIDOPERATION, "Detach non-attached object");
|
||
|
glDetachObjectARB (prog, vert);
|
||
|
endtest ();
|
||
|
glDetachObjectARB (prog, frag);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Attach shader.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_NOERROR, "Attach shader to program object");
|
||
|
glAttachObjectARB (prog, vert);
|
||
|
endtest ();
|
||
|
glAttachObjectARB (prog, frag);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Attach object twice.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_INVALIDOPERATION, "Attach object twice");
|
||
|
glAttachObjectARB (prog, vert);
|
||
|
endtest ();
|
||
|
glAttachObjectARB (prog, frag);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Detach attached object.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_NOERROR, "Detach attached object");
|
||
|
glDetachObjectARB (prog, vert);
|
||
|
endtest ();
|
||
|
glDetachObjectARB (prog, frag);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Attach shader again.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_NOERROR, "Attach shader again");
|
||
|
glAttachObjectARB (prog, vert);
|
||
|
endtest ();
|
||
|
glAttachObjectARB (prog, frag);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Delete attached object.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_NOERROR, "Delete attached object");
|
||
|
glDeleteObjectARB (vert);
|
||
|
endtest ();
|
||
|
glDeleteObjectARB (frag);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Query delete status. It should return TRUE. Object handles are still valid
|
||
|
* as they are referenced by program object container.
|
||
|
*/
|
||
|
begintest (TT_PARAM1_NONZERO, "Query delete status");
|
||
|
glGetObjectParameterivARB (vert, GL_OBJECT_DELETE_STATUS_ARB, params);
|
||
|
endtest1 (params[0]);
|
||
|
glGetObjectParameterivARB (frag, GL_OBJECT_DELETE_STATUS_ARB, params);
|
||
|
endtest1 (params[0]);
|
||
|
|
||
|
/*
|
||
|
* Delete already deleted attached object. The behaviour is undefined, but we
|
||
|
* check for no errors. The object still exists, so the handle value is okay.
|
||
|
* In other words, these calls should be silently ignored by GL.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_NOERROR, "Delete already deleted attached object");
|
||
|
glDeleteObjectARB (vert);
|
||
|
endtest ();
|
||
|
glDeleteObjectARB (frag);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Compile shader source with syntax error.
|
||
|
*/
|
||
|
begintest (TT_PARAM1_ZERO, "Compile shader source with syntax error");
|
||
|
glShaderSourceARB (vert, 1, &invsynvertsrc, NULL);
|
||
|
glCompileShaderARB (vert);
|
||
|
endtest1 (CheckObjectStatus (vert));
|
||
|
glShaderSourceARB (frag, 1, &invsynfragsrc, NULL);
|
||
|
glCompileShaderARB (frag);
|
||
|
endtest1 (CheckObjectStatus (frag));
|
||
|
|
||
|
/*
|
||
|
* Compile shader source with semantic error.
|
||
|
*/
|
||
|
begintest (TT_PARAM1_ZERO, "Compile shader source with semantic error");
|
||
|
glShaderSourceARB (vert, 1, &invsemvertsrc, NULL);
|
||
|
glCompileShaderARB (vert);
|
||
|
endtest1 (CheckObjectStatus (vert));
|
||
|
glShaderSourceARB (frag, 1, &invsemfragsrc, NULL);
|
||
|
glCompileShaderARB (frag);
|
||
|
endtest1 (CheckObjectStatus (frag));
|
||
|
|
||
|
/*
|
||
|
* Link ill-formed vertex-fragment program.
|
||
|
*/
|
||
|
begintest (TT_PARAM1_ZERO, "Link ill-formed vertex-fragment program");
|
||
|
glLinkProgramARB (prog);
|
||
|
endtest1 (CheckObjectStatus (prog));
|
||
|
|
||
|
/*
|
||
|
* Use badly linked program object.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_INVALIDOPERATION, "Use badly linked program object");
|
||
|
glUseProgramObjectARB (prog);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Compile well-formed shader source. Check if multi-string sources can be handled.
|
||
|
*/
|
||
|
begintest (TT_PARAM1_NONZERO, "Compile well-formed shader source");
|
||
|
tab[0] = uniforms;
|
||
|
tab[1] = validvertsrc;
|
||
|
glShaderSourceARB (vert, 2, tab, NULL);
|
||
|
glCompileShaderARB (vert);
|
||
|
endtest1 (CheckObjectStatus (vert));
|
||
|
tab[0] = uniforms;
|
||
|
tab[1] = validfragsrc;
|
||
|
glShaderSourceARB (frag, 2, tab, NULL);
|
||
|
glCompileShaderARB (frag);
|
||
|
endtest1 (CheckObjectStatus (frag));
|
||
|
|
||
|
/*
|
||
|
* Link vertex-fragment program.
|
||
|
*/
|
||
|
begintest (TT_PARAM1_NONZERO, "Link vertex-fragment program");
|
||
|
glLinkProgramARB (prog);
|
||
|
endtest1 (CheckObjectStatus (prog));
|
||
|
|
||
|
/*
|
||
|
* Use valid linked program object.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_NOERROR, "Use linked program object");
|
||
|
glUseProgramObjectARB (prog);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Get current program.
|
||
|
*/
|
||
|
begintest (TT_PARAM1_NONZERO, "Get current program");
|
||
|
endtest1 (glGetHandleARB (GL_PROGRAM_OBJECT_ARB) == prog);
|
||
|
|
||
|
/*
|
||
|
* Use 0 program object.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_NOERROR, "Use 0 program object");
|
||
|
glUseProgramObjectARB (0);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Query uniform location. Uniforms with gl_ prefix cannot be queried.
|
||
|
*/
|
||
|
begintest (TT_PARAM1_NONZERO, "Query uniform location");
|
||
|
endtest1 (glGetUniformLocationARB (prog, "gl_ModelViewMatrix") == -1);
|
||
|
endtest1 (glGetUniformLocationARB (prog, "UniformThatDoesNotExist") == -1);
|
||
|
endtest1 (glGetUniformLocationARB (prog, "") == -1);
|
||
|
endtest1 (glGetUniformLocationARB (prog, "CommonUniform") != -1);
|
||
|
endtest1 (glGetUniformLocationARB (prog, "VertexUniform") != -1);
|
||
|
endtest1 (glGetUniformLocationARB (prog, "FragmentUniform") != -1);
|
||
|
|
||
|
/*
|
||
|
* Query attrib location. Attribs with gl_ prefix cannot be queried.
|
||
|
* When gl_Vertex is used, none of the generic attribs can have index 0.
|
||
|
*/
|
||
|
begintest (TT_PARAM1_NONZERO, "Query attrib location");
|
||
|
endtest1 (glGetAttribLocationARB (prog, "gl_Vertex") == -1);
|
||
|
endtest1 (glGetAttribLocationARB (prog, "AttribThatDoesNotExist") == -1);
|
||
|
endtest1 (glGetAttribLocationARB (prog, "") == -1);
|
||
|
endtest1 (glGetAttribLocationARB (prog, "FirstAttrib") > 0);
|
||
|
endtest1 (glGetAttribLocationARB (prog, "SecondAttrib") > 0);
|
||
|
|
||
|
/*
|
||
|
* Bind attrib locations, link and check if locations are correct.
|
||
|
*/
|
||
|
begintest (TT_PARAM1_NONZERO, "Bind attrib location #1");
|
||
|
glBindAttribLocationARB (prog, 1, "FirstAttrib");
|
||
|
glBindAttribLocationARB (prog, 2, "SecondAttrib");
|
||
|
glLinkProgramARB (prog);
|
||
|
endtest1 (CheckObjectStatus (prog));
|
||
|
endtest1 (glGetAttribLocationARB (prog, "FirstAttrib") == 1);
|
||
|
endtest1 (glGetAttribLocationARB (prog, "SecondAttrib") == 2);
|
||
|
|
||
|
/*
|
||
|
* Bind attrib locations in different order. Link and check if locations are correct.
|
||
|
*/
|
||
|
begintest (TT_PARAM1_NONZERO, "Bind attrib location #2");
|
||
|
glBindAttribLocationARB (prog, 1, "SecondAttrib");
|
||
|
glBindAttribLocationARB (prog, 2, "FirstAttrib");
|
||
|
glLinkProgramARB (prog);
|
||
|
endtest1 (CheckObjectStatus (prog));
|
||
|
endtest1 (glGetAttribLocationARB (prog, "SecondAttrib") == 1);
|
||
|
endtest1 (glGetAttribLocationARB (prog, "FirstAttrib") == 2);
|
||
|
|
||
|
/*
|
||
|
* Detach deleted object.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_NOERROR, "Detach deleted object");
|
||
|
glDetachObjectARB (prog, vert);
|
||
|
endtest ();
|
||
|
glDetachObjectARB (prog, frag);
|
||
|
endtest ();
|
||
|
|
||
|
/*
|
||
|
* Delete deleted detached object.
|
||
|
*/
|
||
|
begintest (TT_GETERROR_INVALIDVALUE, "Delete deleted detached object");
|
||
|
glDeleteObjectARB (vert);
|
||
|
endtest ();
|
||
|
glDeleteObjectARB (frag);
|
||
|
endtest ();
|
||
|
|
||
|
exit (0);
|
||
|
}
|
||
|
|
||
|
void RenderScene (void)
|
||
|
{
|
||
|
/* never reached */
|
||
|
assert (0);
|
||
|
}
|
||
|
|
||
|
int main (int argc, char *argv[])
|
||
|
{
|
||
|
InitFramework (&argc, argv);
|
||
|
return 0;
|
||
|
}
|
||
|
|