[Piglit] [PATCH V3 1/4] shader_runner: Add basic SSO support to shader runner

Timothy Arceri timothy.arceri at collabora.com
Sat Dec 5 18:58:31 PST 2015


This sets up the basics for using SSO with shader runner. This will
only support vertex and fragment shaders but is easily extended.

V2: delete pipeline in cleanup code rather than calling gen again,
output error message when SSO fails to link

V3: add new option to [require] to allow separate shader objects to be
enabled for the entire test.

Example use:
[require]
SSO ENABLED

Adding the ENABLED field rather than just using SSO will allow us to use
DISABLED in future should we ever add the ability to automatically run
all tests as SSO.

Example shader:

[require]
GLSL >= 1.50
SSO ENABLED

[vertex shader]

layout(location = 0) in vec4 piglit_vertex;

layout(location = 2) out vec3 a;
layout(location = 3) out vec3 b;

void main()
{
    gl_Position = piglit_vertex;
    a = vec3(0, 0, 1);
    b = vec3(1, 0, 0);
}

[fragment shader]

layout(location = 0) out vec4 out_color;

layout(location = 2) in vec3 b; /* should get vec3(0, 0, 1) */
layout(location = 3) in vec3 a; /* should get vec3(1, 0, 0) */

void main()
{
    out_color = vec4(cross(b, a), 1);
}

[test]
draw rect -1 -1 2 2
probe all rgb 0 1 0

Cc: Kenneth Graunke <kenneth at whitecape.org>
---
 tests/shaders/shader_runner.c | 90 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 86 insertions(+), 4 deletions(-)

diff --git a/tests/shaders/shader_runner.c b/tests/shaders/shader_runner.c
index eeb1aac..a5f456f 100644
--- a/tests/shaders/shader_runner.c
+++ b/tests/shaders/shader_runner.c
@@ -123,10 +123,12 @@ GLint shader_string_size;
 const char *vertex_data_start = NULL;
 const char *vertex_data_end = NULL;
 GLuint prog;
+GLuint pipeline;
 size_t num_vbo_rows = 0;
 bool vbo_present = false;
 bool link_ok = false;
 bool prog_in_use = false;
+bool sso_in_use = false;
 GLchar *prog_err_info = NULL;
 GLuint vao = 0;
 GLuint fbo = 0;
@@ -137,12 +139,14 @@ enum states {
 	requirements,
 	vertex_shader,
 	vertex_shader_passthrough,
+	vertex_sso,
 	vertex_program,
 	tess_ctrl_shader,
 	tess_eval_shader,
 	geometry_shader,
 	geometry_layout,
 	fragment_shader,
+	fragment_sso,
 	fragment_program,
 	compute_shader,
 	vertex_data,
@@ -480,6 +484,55 @@ compile_and_bind_program(GLenum target, const char *start, int len)
 	prog_in_use = true;
 }
 
+void
+create_sso(GLenum target, const char *start, int len)
+{
+	GLuint prog;
+	GLint ok;
+	char *source;
+
+	piglit_require_extension("GL_ARB_separate_shader_objects");
+
+	source = malloc(len + 1);
+	memcpy(source, start, len);
+	source[len] = 0;
+	prog = glCreateShaderProgramv(target, 1,
+					(const GLchar *const *) &source);
+
+	glGetProgramiv(prog, GL_LINK_STATUS, &ok);
+	if (ok) {
+		link_ok = true;
+	} else {
+		GLint size;
+
+		glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
+		prog_err_info = malloc(size);
+
+		glGetProgramInfoLog(prog, size, NULL, prog_err_info);
+
+		fprintf(stderr, "glCreateShaderProgramv(%s) failed: %s\n",
+			target_to_short_name(target),
+			prog_err_info);
+
+		free(prog_err_info);
+		piglit_report_result(PIGLIT_FAIL);
+
+		return;
+	}
+
+	switch (target) {
+	case GL_VERTEX_SHADER:
+		glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT, prog);
+		break;
+	case GL_FRAGMENT_SHADER:
+		glUseProgramStages(pipeline, GL_FRAGMENT_SHADER_BIT, prog);
+		break;
+	}
+
+	sso_in_use = true;
+	prog_in_use = true;
+}
+
 /**
  * Compare two values given a specified comparison operator
  */
@@ -705,13 +758,14 @@ process_requirement(const char *line)
 		return;
 	}
 
-	/* There are four types of requirements that a test can currently
+	/* There are five types of requirements that a test can currently
 	 * have:
 	 *
 	 *    * Require that some GL extension be supported
 	 *    * Require some particular versions of GL
 	 *    * Require some particular versions of GLSL
 	 *    * Require some particular number of uniform components
+	 *    * Require shaders be built as separate shader objects
 	 *
 	 * The tests for GL and GLSL versions can be equal, not equal,
 	 * less, less-or-equal, greater, or greater-or-equal.  Extension tests
@@ -797,6 +851,10 @@ process_requirement(const char *line)
 		}
 
 		piglit_set_rlimit(lim);
+	}  else if (string_match("SSO", line)) {
+		line = eat_whitespace(line + 3);
+		if (string_match("ENABLED", line))
+			sso_in_use = true;
 	}
 }
 
@@ -846,6 +904,13 @@ leave_state(enum states state, const char *line)
 		compile_glsl(GL_VERTEX_SHADER);
 		break;
 
+	case vertex_sso:
+		shader_string_size = line - shader_string;
+		create_sso(GL_VERTEX_SHADER,
+			   shader_string,
+			   line - shader_string);
+		break;
+
 	case vertex_program:
 		compile_and_bind_program(GL_VERTEX_PROGRAM_ARB,
 					 shader_string,
@@ -875,6 +940,12 @@ leave_state(enum states state, const char *line)
 		compile_glsl(GL_FRAGMENT_SHADER);
 		break;
 
+	case fragment_sso:
+		create_sso(GL_FRAGMENT_SHADER,
+			   shader_string,
+			   line - shader_string);
+		break;
+
 	case fragment_program:
 		compile_and_bind_program(GL_FRAGMENT_PROGRAM_ARB,
 					 shader_string,
@@ -1038,7 +1109,7 @@ process_test_script(const char *script_name)
 			if (string_match("[require]", line)) {
 				state = requirements;
 			} else if (string_match("[vertex shader]", line)) {
-				state = vertex_shader;
+				state = sso_in_use ? vertex_sso : vertex_shader;
 				shader_string = NULL;
 			} else if (string_match("[vertex program]", line)) {
 				state = vertex_program;
@@ -1061,7 +1132,7 @@ process_test_script(const char *script_name)
 				state = geometry_layout;
 				shader_string = NULL;
 			} else if (string_match("[fragment shader]", line)) {
-				state = fragment_shader;
+				state = sso_in_use ? fragment_sso : fragment_shader;
 				shader_string = NULL;
 			} else if (string_match("[fragment program]", line)) {
 				state = fragment_program;
@@ -1098,11 +1169,13 @@ process_test_script(const char *script_name)
 				break;
 
 			case vertex_shader:
+			case vertex_sso:
 			case vertex_program:
 			case tess_ctrl_shader:
 			case tess_eval_shader:
 			case geometry_shader:
 			case fragment_shader:
+			case fragment_sso:
 			case fragment_program:
 			case compute_shader:
 				if (shader_string == NULL)
@@ -3094,8 +3167,10 @@ piglit_display(void)
 			glDeleteProgram(prog);
 			glUseProgram(0);
 		} else {
-			glDeleteProgramsARB(1, &prog);
+			if (!sso_in_use)
+				glDeleteProgramsARB(1, &prog);
 		}
+		glDeleteProgramPipelines(1, &pipeline);
 	}
 
 	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
@@ -3138,6 +3213,9 @@ piglit_init(int argc, char **argv)
 		glGetIntegerv(GL_MAX_VARYING_COMPONENTS,
 			      &gl_max_varying_components);
 	glGetIntegerv(GL_MAX_CLIP_PLANES, &gl_max_clip_planes);
+
+	if (piglit_is_extension_supported("GL_ARB_separate_shader_objects"))
+		glGenProgramPipelines(1, &pipeline);
 #else
 	glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS,
 		      &gl_max_fragment_uniform_components);
@@ -3157,6 +3235,10 @@ piglit_init(int argc, char **argv)
 
 	process_test_script(argv[1]);
 	link_and_use_shaders();
+
+	if (sso_in_use)
+		glBindProgramPipeline(pipeline);
+
 	if (link_ok && vertex_data_start != NULL) {
 		program_must_be_in_use();
 		bind_vao_if_supported();
-- 
2.4.3



More information about the Piglit mailing list