-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Ben Holmes wrote:
One general comment first... don't fear whitespace.
This:
if(!strncmp(&(testTexts[currentTest][i]),"expected",8))
is much harder on the eyes than:
if (!strncmp(&(testTexts[currentTest][i]), "expected", 8))
Also, our vague coding standard wants the opening curly-brace on the
same line as the if-statement, while-statement, etc.
I also think you should wrap the text handling in a couple accessor
functions. Something like:
char *get_string(char *input, char **value, int *length);
char *get_float(char *input, float *value);
Each of these would eat whitespace before (and after?) the token, and
each would return the position in the text after the token.
> ---
> tests/all.tests | 6 +
> tests/shaders/CMakeLists.txt | 1 +
> tests/shaders/glsl-shader-loader.c | 456
> ++++++++++++++++++++++++++++++++++++
> 3 files changed, 463 insertions(+), 0 deletions(-)
> create mode 100644 tests/shaders/glsl-shader-loader.c
>
> diff --git a/tests/all.tests b/tests/all.tests
> index ade7048..b05dec9 100644
> --- a/tests/all.tests
> +++ b/tests/all.tests
> @@ -184,6 +184,12 @@ add_vpfpgeneric('vp-sge-alias')
> add_vpfpgeneric('vp-two-constants')
> shaders['vpfp-generic'] = vpfpgeneric
>
> +glslshaderloader = Group()
> +def add_glslshaderloader(name):
> + glslshaderloader[name] = PlainExecTest(['glsl-shader-loader', '-auto',
> testBinDir + '../tests/shaders/glsl-tests/' + name + '.ini'])
> +
> +shaders['glsl-shader-loader'] = glslshaderloader
> +
> bugs = Group()
> add_plain_test(bugs, 'crash-cubemap-order')
> add_plain_test(bugs, 'crash-texparameter-before-teximage')
> diff --git a/tests/shaders/CMakeLists.txt b/tests/shaders/CMakeLists.txt
> index 999ba4f..a60bec5 100644
> --- a/tests/shaders/CMakeLists.txt
> +++ b/tests/shaders/CMakeLists.txt
> @@ -73,3 +73,4 @@ add_executable (glsl-preprocessor-comments
> glsl-preprocessor-comments.c)
> add_executable (vp-ignore-input vp-ignore-input.c)
> add_executable (glsl-empty-vs-no-fs glsl-empty-vs-no-fs.c)
> add_executable (glsl-useprogram-displaylist glsl-useprogram-displaylist.c)
> +add_executable (glsl-shader-loader glsl-shader-loader.c)
> diff --git a/tests/shaders/glsl-shader-loader.c
> b/tests/shaders/glsl-shader-loader.c
> new file mode 100644
> index 0000000..fab09cf
> --- /dev/null
> +++ b/tests/shaders/glsl-shader-loader.c
> @@ -0,0 +1,456 @@
> +/*
> + * Copyright © 2009 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of 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
> + * 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.
> + *
> + * Authors:
> + * Ben Holmes <[email protected]>
> + */
> +
> +/*
> + * Draws quads using a program built from shaders/uniforms
> + * loaded from .ini specified like so: ./glsl-shader-driver ./tests/test.ini
> + */
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <GL/glew.h>
> +#if defined(__APPLE__)
> +#include <GLUT/glut.h>
> +#else
> +#include <GL/glut.h>
> +#endif
> +#include "piglit-util.h"
> +
> +int piglit_width = 600, piglit_height = 400;
> +int piglit_window_mode = GLUT_RGB | GLUT_DOUBLE;
> +static GLuint tex;
> +static GLint prog;
> +static GLint vs;
> +static GLint fs;
> +static char filename[256];
> +static char *buffer;
> +static char *vsText;
> +static GLint vsLength = 0;
> +static char *fsText;
> +static GLint fsLength = 0;
> +static char * testTexts[1024];
> +static int *testLengths;
> +static char *reqsText;
> +static int reqsLength = 0;
> +static int numTests = 0;
> +static int width = 2; //width of each quad, must be at least 2
> +static height = 2; //height of each quad, must be at least 2
> +
> +struct expected
> +{
> + GLfloat color[3];
> + float pos[2];
> +};
> +
> +static struct expected probe;
> +
> +void
> +test_parse(int currentTest)
> +{
> + int i,j;
> + float values[4];
> + char name[256];
> + char *cP;
> + GLint uLoc;
> +
Since currentTest is constant through this whole function, I strongly
recommend:
char *text = testTexts[currentTest];
That will make a lot of the code in the function much more readable.
> + for(i=0;i < testLengths[currentTest];++i)
> + {
> + if(!strncmp(&(testTexts[currentTest][i]),"expected",8))
> + {
> + i+=8;
> + cP = strchr(&(testTexts[currentTest][i]),' ');
> + for(j=0;j<3;++j)
> + {
> + sscanf(cP+1,"%f",&(probe.color[j]));
> + cP = strchr(cP+1,' ');
> + }
> + sscanf(cP+1,"%f",&(probe.pos[0]));
> + cP = strchr(cP+1,' ');
> + sscanf(cP+1,"%f",&(probe.pos[1]));
> + }
> + if(!strncmp(&(testTexts[currentTest][i]),"uniform",7))
> + {
> + i+=8;
> + if(!strncmp(&(testTexts[currentTest][i]),"vec4",4))
> + {
> + i+=5;
> + cP = strchr(&(testTexts[currentTest][i]),' ');
> +
This is not a very good way to parse this. This will accept, for
example, 'vec4xfoo '. I think you only want to advance the position by
4 (length of "vec4") and do something like:
while (isspace(testTexts[currentTest][i]))
i++;
name_ptr = & testTexts[currentTest][i];
while (isspace(testTexts[currentTest][i]))
i++;
Alternately, the get_string funtion that I suggested above would take
care of this.
text_position = get_string(text_position, & token,
& token_length);
if ((token_length == 4)
&& (strncmp(token, "vec4", 4) == 0)) {
text_position = get_string(text_position,
& name, & name_len);
for (j = 0; j < 4; j++) {
text_position = get_float(text_position,
& values[j]);
}
...
}
> + strncpy(name,&(testTexts[currentTest][i]),
> + (int)(cP - &(testTexts[currentTest][i])));
> +
> + name[(int)(cP - &(testTexts[currentTest][i]))]
> + = '\0';
> +
> + i+=(int)(cP - &(testTexts[currentTest][i]));
> +
> + for(j=0;j<4;++j)
> + {
> + sscanf(cP+1,"%f",
> + &(values[j]));
> + cP = strchr(cP+1,' ');
> + }
> + uLoc = glGetUniformLocation(prog, name);
> + glUniform4f(uLoc, values[0],values[1],
> + values[2],values[3]);
This should report an error (and fail the test) if the uniform does not
exist. glGetUniformLocation will return -1. Also, use
"glUniform4fv(uLoc, values)" here.
> + }
> + if(!strncmp(&(testTexts[currentTest][i]),"float",5))
> + {
> + i+=6;
> + cP = strchr(&(testTexts[currentTest][i]),' ');
> +
> + strncpy(name,&(testTexts[currentTest][i]),
> + (int)(cP - &(testTexts[currentTest][i])));
> +
> + name[(int)(cP - &(testTexts[currentTest][i]))]
> + = '\0';
> +
> + i+=(int)(cP - &(testTexts[currentTest][i]));
> +
> + sscanf(cP+1,"%f",&(values[0]));
> + uLoc = glGetUniformLocation(prog, name);
> + glUniform1i(uLoc, values[0]);
^ f
Same comments about error reporting as above.
> + }
> + }
> + }
> +}
> +
> +void
> +req_parse()
> +{
> + int i;
> + float reqVersion=2.0, version=0.0;
> + char requirement[256];
> + char *cP;
> +
> + for(i=0;i<reqsLength;++i)
> + {
> + if((int) (&(reqsText[strlen(reqsText)]) - &(reqsText[i]))
> + < 9)
> + break;
> + if(!strncmp(&(reqsText[i]),"extension",9))
> + {
> + i+=10;
> + cP = strchr(&(reqsText[i]),'\n');
> +
> + strncpy(requirement,&(reqsText[i]),
> + (int)(cP - &(reqsText[i])));
> + requirement[(int)(cP - &(reqsText[i]))] = '\0';
> + i+=(int)(cP - &(reqsText[i]));
> +
> + piglit_require_extension(requirement);
> + }
> + if(!strncmp(&(reqsText[i]),"version",7))
> + {
> + i+=8;
> +
> + sscanf(&(reqsText[i]),"%f",&reqVersion);
> +
> + strncpy(requirement,glGetString(GL_VERSION),3);
> + sscanf(requirement,"%f",&version);
The usual way to do this is:
version = strtod(glGetString(GL_VERSION), NULL);
> + if(version<reqVersion)
> + {
> + printf("Requires OpenGL version %f\n",
> + reqVersion);
> + piglit_report_result(PIGLIT_SKIP);
> + }
> + }
Add a case for glsl_version also. Query the supported version with
glGetString(GL_SHADING_LANGUAGE_VERSION).
> + }
> +}
> +
> +void
> +testFile_parse()
> +{
> + FILE* filePointer;
> + int i=0, secLength=0, fileLength=0, state=0, currentTest=0;
> + char c;
> + char word[32];
> + char *cP;
> +
> + filePointer = fopen(filename, "rt");
> + if(!filePointer)
> + piglit_report_result(PIGLIT_FAILURE);
> +
> +
> + while(fgetc(filePointer)!=EOF)
> + fileLength++;
> +
> + if(fileLength <1)
> + piglit_report_result(PIGLIT_FAILURE);
> +
> + fclose(filePointer);
> +
> + filePointer = fopen(filename, "rt");
> + buffer = (char*) malloc(fileLength+1);
> +
> + c = fgetc(filePointer);
> + while(c != EOF)
> + {
> + buffer[i] = c;
> + ++i;
> + c = fgetc(filePointer);
> + }
> +
> + buffer[i] = '\0';
> + fclose(filePointer);
The code above made my eyes bleed.
fp = fopen(filename, "r");
if (fp == NULL)
/* error */ ;
fseek(fp, 0, SEEK_END);
fileLength = ftell(fp);
fseek(fp, 0, SEEK_SET);
buffer = malloc(fileLength + 1);
fread(buffer, fileLength, 1, fp);
fclose(fp);
buffer[fileLength] = '\0';
Or just use piglit_load_text_file.
buffer = pitlit_load_text_file(filename, & fileLength);
> +
> + i=0;
> +
> + while(buffer[i] != '\0')
> + {
> + if(!strncmp(&(buffer[i]),"[test]",6))
> + ++numTests;
> + ++i;
> + }
> +
> + testLengths = (int *)malloc(sizeof(int)*numTests);
> + for(i=0;i<numTests;++i)
> + testLengths[i] = 0;
Use calloc instead.
> +
> + i=0;
> +
Instead of using an index, it seems like just walking a pointer would be
easier.
> + while(buffer[i] != '\0')
> + {
> + if(buffer[i] == '[')
> + {
> + switch(state)
> + {
> + case 1: //state 1 records vertex shader length
> + vsLength = secLength;
> + break;
> + case 2: //state 2 records fragment shader length
> + fsLength = secLength;
> + break;
> + case 3: //state 3 records test info length
> + testLengths[currentTest-1] = secLength;
> + break;
> + case 4: //state 4 records requirements length
> + reqsLength = secLength;
> + break;
> + }
Use an enum for state.
enum file_section {
start = 0,
vertex_section,
fragment_section,
test_section,
requirements_section
};
> + secLength = 0;
> +
> + if(state == 0)
> + cP = strchr(buffer,']');
> + else
> + cP = strchr(cP+1,']');
> +
> + strncpy(word,&(buffer[i+1]),(int)(cP-&(buffer[i+1])));
Why make a copy? It seems like this should be:
if (strncmp("[vertex]\n", buffer[i], 9) == 0) {
vsText = &buffer[i + 9];
state = vertex_section;
i += 9;
} else if (strncmp("[fragment]\n", buffer[i], 11) == 0) {
...
} ...
> + if(!strncmp(word,"vertex",6))
> + {
> + vsText = cP+1;
> + i = cP+1-buffer;
> + state = 1;
> + }
> + if(!strncmp(word,"fragment",8))
> + {
> + fsText = cP+1;
> + i = cP+1-buffer;
> + state = 2;
> + }
> + if(!strncmp(word,"test",4))
> + {
> + testTexts[currentTest] = cP+1;
> + i = cP+1-buffer;
> + state = 3;
> + ++currentTest;
> + }
> + if(!strncmp(word,"requirements",12))
> + {
> + reqsText = cP+1;
> + i = cP+1-buffer;
> + state = 4;
> + }
> +
> + }
> + ++secLength;
> + ++i;
> + }
> + switch(state)
> + {
> + case 1: //state 1 records vertex shader length
> + vsLength = secLength;
> + break;
> + case 2: //state 2 records fragment shader length
> + fsLength = secLength;
> + break;
> + case 3: //state 3 records test info length
> + testLengths[currentTest-1] = secLength;
> + break;
> + case 4: //state 4 records requirements length
> + reqsLength = secLength;
> + break;
> + }
> +
> + if(vsLength < 1 || fsLength < 1)
> + piglit_report_result(PIGLIT_FAILURE);
> + req_parse();
> +}
> +
> +static void
> +compileLinkProg()
> +{
> + GLint stat;
> +
> + vs = glCreateShader(GL_VERTEX_SHADER);
> + fs = glCreateShader(GL_FRAGMENT_SHADER);
> +
> + glShaderSource(vs, 1, (const GLchar **) &vsText, &vsLength);
> + glShaderSource(fs, 1, (const GLchar **) &fsText, &fsLength);
> +
> + glCompileShader(vs);
> + glGetShaderiv(vs, GL_COMPILE_STATUS, &stat);
> + if (!stat) {
> + printf("error compiling vertex shader1!\n");
> + exit(1);
> + }
> +
> + glCompileShader(fs);
> + glGetShaderiv(fs, GL_COMPILE_STATUS, &stat);
> + if (!stat) {
> + printf("error compiling fragment shader1!\n");
> + exit(1);
> + }
> +
> + prog = glCreateProgram();
> + glAttachShader(prog, vs);
> + glAttachShader(prog, fs);
> + glLinkProgram(prog);
> + glUseProgram(prog);
> +}
> +
> +static void
> +loadTex()
> +{
I just added a piglit_checkerboard_texture function that does this.
That function should be used instead of this one.
> + int height = 2;
> + int width = 2;
> + int i, j;
> +
> + GLfloat texData[width][height][4];
> + for (i=0; i < width; ++i) {
> + for (j=0; j < height; ++j) {
> + if ((i+j) & 1) {
> + texData[i][j][0] = 1;
> + texData[i][j][1] = 0;
> + texData[i][j][2] = 1;
> + texData[i][j][3] = 0;
> + }
> + else {
> + texData[i][j][0] = 0;
> + texData[i][j][1] = 1;
> + texData[i][j][2] = 0;
> + texData[i][j][3] = 1;
> + }
> + }
> + }
> +
> + glGenTextures(1, &tex);
> + glActiveTexture(GL_TEXTURE0);
> + glBindTexture(GL_TEXTURE_2D, tex);
> + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
> + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
> + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
> + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
> + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
> + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
> + GL_RGBA, GL_FLOAT, texData);
> +
> +}
> +
> +void
> +piglit_init(int argc, char **argv)
> +{
> + int i;
> + filename[0] = '\0';
> + if (!GLEW_VERSION_2_0) {
> + printf("Requires OpenGL 2.0\n");
> + piglit_report_result(PIGLIT_SKIP);
> + }
Just handle this in req_parse? That would require some (trivial) rework
to that function, but it seems sensible. I suspect we'll eventually
extend this to support assembly shaders, so there may not be a hard GL
2.0 requirement in the future.
> +
> + for(i=1;i<argc;++i)
> + {
> + strncpy(filename, argv[i], strlen(argv[i]));
> + }
Uh... what? strncpy(a, b, strlen(b)) is just strcpy. Seriously.
There's no reason for any of this madness anyway. This code should just be:
if (argc < 2) {
printf("Usage: %s test_file_name\n", argv[0]);
piglit_report_result(PIGLIT_FAILURE);
}
And pass argv[1] as a parameter to testFile_parse.
> +
> + if(strlen(filename) < 5 || strstr(filename,".ini") == NULL)
There's no reason to force the shader files to end in '.ini'. In fact,
I think naming them *.ini is a horrible idea. :) They use the .ini
/format/, but they're not "initialization" files.
> + piglit_report_result(PIGLIT_FAILURE);
> +
> + printf("using test file: %s\n",filename);
argv[1]
> +
> + piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
> +
> + glEnable(GL_TEXTURE_2D);
> +
> + glClearColor(0.6, 0.6, 0.6, 1.0);
> +
> + probe.color[0]=0.0;
> + probe.color[1]=0.0;
> + probe.color[2]=0.0;
> + probe.pos[0]=0.5;
> + probe.pos[1]=0.5;
> +
> + testFile_parse();
> + compileLinkProg();
> + loadTex();
> +}
> +
> +enum piglit_result
> +piglit_display(void)
> +{
> +
> + int i;
> + int x=0, y=0;
> + GLboolean pass = GL_TRUE;
> + glClear(GL_COLOR_BUFFER_BIT);
> +
> + glUseProgram(prog);
> +
> + for(i=0;i<numTests;++i)
> + {
> + glPushMatrix();
> +
> + if(i%(int)(piglit_width/(width+1)) == 0 && i!=0)
> + {
> + y+=height+1;
> + x=0;
> + }
> +
> + test_parse(i);
> + glTranslatef(x,y,0);
> + piglit_draw_rect_tex(0,0,width,height,0,0,1,1);
> + pass = pass && piglit_probe_pixel_rgb((probe.pos[0]*width)+x,
> + (probe.pos[1]*height)+y,
> + probe.color);
> + x+=width+1;
> + glPopMatrix();
> + }
> +
> + glFinish();
Assuming there are no driver bugs, there is no reason to glFinish.
Assuming there are driver bugs, calling glFinish may hide them.
> + glutSwapBuffers();
> +
> + return pass ? PIGLIT_SUCCESS : PIGLIT_FAILURE;
> +}
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAksVhVsACgkQX1gOwKyEAw9VhACeN+fOYc7uXxngjbf0EQO92kvJ
m6AAnAniAeS7xM9tKf1UWpeePEaQIHYj
=KbUI
-----END PGP SIGNATURE-----
------------------------------------------------------------------------------
Join us December 9, 2009 for the Red Hat Virtual Experience,
a free event focused on virtualization and cloud computing.
Attend in-depth sessions from your desk. Your couch. Anywhere.
http://p.sf.net/sfu/redhat-sfdev2dev
_______________________________________________
Mesa3d-dev mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mesa3d-dev