[05/24] shader_runner/spirv: Add support for SPIR-V specializations

Submitted by apinheiro on June 20, 2018, 12:40 p.m.

Details

Message ID 20180620124059.25917-6-apinheiro@igalia.com
State New
Headers show
Series "ARB_gl_spirv: support for loading SPIR-V binaries, plus first set of tests" ( rev: 2 ) in Piglit

Not browsing as part of any series.

Commit Message

apinheiro June 20, 2018, 12:40 p.m.
From: Neil Roberts <nroberts@igalia.com>

There can now be extra sections such as the following in the
shader_test file:

[vertex shader specializations]
uint 0 3

These will get passed to glSpecializeShader when compiling the
corresponding shader.
---
 tests/shaders/shader_runner.c | 181 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 180 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/tests/shaders/shader_runner.c b/tests/shaders/shader_runner.c
index abe0df0b0..bffc444d7 100644
--- a/tests/shaders/shader_runner.c
+++ b/tests/shaders/shader_runner.c
@@ -165,6 +165,16 @@  static bool use_get_program_binary = false;
 
 static bool report_subtests = false;
 
+struct specialization_list {
+	size_t buffer_size;
+	size_t n_entries;
+	GLuint *indices;
+	union { GLuint u; GLfloat f; } *values;
+};
+
+static struct specialization_list
+specializations[SHADER_TYPES];
+
 static struct texture_binding {
 	GLuint obj;
 	unsigned width;
@@ -258,19 +268,25 @@  enum states {
 	vertex_shader,
 	vertex_shader_passthrough,
 	vertex_shader_spirv,
+	vertex_shader_specializations,
 	vertex_program,
 	tess_ctrl_shader,
 	tess_ctrl_shader_spirv,
+	tess_ctrl_shader_specializations,
 	tess_eval_shader,
 	tess_eval_shader_spirv,
+	tess_eval_shader_specializations,
 	geometry_shader,
 	geometry_shader_spirv,
+	geometry_shader_specializations,
 	geometry_layout,
 	fragment_shader,
 	fragment_shader_spirv,
+	fragment_shader_specializations,
 	fragment_program,
 	compute_shader,
 	compute_shader_spirv,
+	compute_shader_specializations,
 	vertex_data,
 	test,
 };
@@ -719,7 +735,36 @@  load_and_specialize_spirv(GLenum target,
 	glShaderBinary(1, &shader, GL_SHADER_BINARY_FORMAT_SPIR_V_ARB,
 		       binary, size);
 
-	glSpecializeShaderARB(shader, "main", 0, NULL, NULL);
+	const struct specialization_list *specs;
+
+	switch (target) {
+	case GL_VERTEX_SHADER:
+		specs = specializations + 0;
+		break;
+	case GL_TESS_CONTROL_SHADER:
+		specs = specializations + 1;
+		break;
+	case GL_TESS_EVALUATION_SHADER:
+		specs = specializations + 2;
+		break;
+	case GL_GEOMETRY_SHADER:
+		specs = specializations + 3;
+		break;
+	case GL_FRAGMENT_SHADER:
+		specs = specializations + 4;
+		break;
+	case GL_COMPUTE_SHADER:
+		specs = specializations + 5;
+		break;
+	default:
+		assert(!"Should not get here.");
+	}
+
+	glSpecializeShaderARB(shader,
+			      "main",
+			      specs->n_entries,
+			      specs->indices,
+			      &specs->values[0].u);
 
 	GLint ok;
 	glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
@@ -1256,6 +1301,9 @@  leave_state(enum states state, const char *line, const char *script_name)
 		shader_string_size = line - shader_string;
 		return assemble_spirv(GL_VERTEX_SHADER);
 
+	case vertex_shader_specializations:
+		break;
+
 	case tess_ctrl_shader:
 		if (spirv_replaces_glsl)
 			break;
@@ -1268,6 +1316,9 @@  leave_state(enum states state, const char *line, const char *script_name)
 		shader_string_size = line - shader_string;
 		return assemble_spirv(GL_TESS_CONTROL_SHADER);
 
+	case tess_ctrl_shader_specializations:
+		break;
+
 	case tess_eval_shader:
 		if (spirv_replaces_glsl)
 			break;
@@ -1280,6 +1331,9 @@  leave_state(enum states state, const char *line, const char *script_name)
 		shader_string_size = line - shader_string;
 		return assemble_spirv(GL_TESS_EVALUATION_SHADER);
 
+	case tess_eval_shader_specializations:
+		break;
+
 	case geometry_shader:
 		if (spirv_replaces_glsl)
 			break;
@@ -1292,6 +1346,9 @@  leave_state(enum states state, const char *line, const char *script_name)
 		shader_string_size = line - shader_string;
 		return assemble_spirv(GL_GEOMETRY_SHADER);
 
+	case geometry_shader_specializations:
+		break;
+
 	case geometry_layout:
 		break;
 
@@ -1313,6 +1370,9 @@  leave_state(enum states state, const char *line, const char *script_name)
 		shader_string_size = line - shader_string;
 		return assemble_spirv(GL_FRAGMENT_SHADER);
 
+	case fragment_shader_specializations:
+		break;
+
 	case compute_shader:
 		if (spirv_replaces_glsl)
 			break;
@@ -1325,6 +1385,9 @@  leave_state(enum states state, const char *line, const char *script_name)
 		shader_string_size = line - shader_string;
 		return assemble_spirv(GL_COMPUTE_SHADER);
 
+	case compute_shader_specializations:
+		break;
+
 	case vertex_data:
 		vertex_data_end = line;
 		break;
@@ -1491,6 +1554,93 @@  cleanup:
 	return result;
 }
 
+static enum piglit_result
+process_specialization(enum states state, const char *line)
+{
+	const char *end = strchrnul(line, '\n');
+	const char *next;
+	enum { TYPE_FLOAT, TYPE_UINT } type;
+
+	while (line < end && isspace(*line))
+		line++;
+
+	if (line >= end || *line == '#')
+		return PIGLIT_PASS;
+
+	if (parse_str(line, "uint", &next))
+		type = TYPE_UINT;
+	else if (parse_str(line, "float", &next))
+		type = TYPE_FLOAT;
+	else
+		goto invalid;
+
+	struct specialization_list *list;
+
+	switch (state) {
+	case vertex_shader_specializations:
+		list = specializations + 0;
+		break;
+	case tess_ctrl_shader_specializations:
+		list = specializations + 1;
+		break;
+	case tess_eval_shader_specializations:
+		list = specializations + 2;
+		break;
+	case geometry_shader_specializations:
+		list = specializations + 3;
+		break;
+	case fragment_shader_specializations:
+		list = specializations + 4;
+		break;
+	case compute_shader_specializations:
+		list = specializations + 5;
+		break;
+	default:
+		assert(!"Should not get here.");
+	}
+
+	if (list->n_entries >= list->buffer_size) {
+		if (list->buffer_size == 0)
+			list->buffer_size = 1;
+		else
+			list->buffer_size *= 2;
+		list->indices = realloc(list->indices,
+					(sizeof list->indices[0]) *
+					list->buffer_size);
+		list->values = realloc(list->values,
+				       (sizeof list->values[0]) *
+				       list->buffer_size);
+	}
+
+	if (parse_uints(next, list->indices + list->n_entries, 1, &next) != 1)
+		goto invalid;
+
+	switch (type) {
+	case TYPE_UINT:
+		if (parse_uints(next,
+				&list->values[list->n_entries].u,
+				1,
+				&next) != 1)
+			goto invalid;
+		break;
+	case TYPE_FLOAT:
+		if (parse_floats(next,
+				 &list->values[list->n_entries].f,
+				 1,
+				 &next) != 1)
+			goto invalid;
+		break;
+	}
+
+	list->n_entries++;
+
+	return PIGLIT_PASS;
+
+ invalid:
+	fprintf(stderr, "Invalid specialization line\n");
+	return PIGLIT_FAIL;
+}
+
 static enum piglit_result
 process_test_script(const char *script_name)
 {
@@ -1530,24 +1680,34 @@  process_test_script(const char *script_name)
 			} else if (parse_str(line, "[vertex shader spirv]", NULL)) {
 				state = vertex_shader_spirv;
 				shader_string = NULL;
+			} else if (parse_str(line, "[vertex shader specializations]", NULL)) {
+				state = vertex_shader_specializations;
 			} else if (parse_str(line, "[tessellation control shader]", NULL)) {
 				state = tess_ctrl_shader;
 				shader_string = NULL;
 			} else if (parse_str(line, "[tessellation control shader spirv]", NULL)) {
 				state = tess_ctrl_shader_spirv;
 				shader_string = NULL;
+			} else if (parse_str(line, "[tessellation control shader specializations]", NULL)) {
+				state = tess_ctrl_shader_specializations;
 			} else if (parse_str(line, "[tessellation evaluation shader]", NULL)) {
 				state = tess_eval_shader;
 				shader_string = NULL;
 			} else if (parse_str(line, "[tessellation evaluation shader spirv]", NULL)) {
 				state = tess_eval_shader_spirv;
 				shader_string = NULL;
+			} else if (parse_str(line, "[tessellation evaluation shader specializations]", NULL)) {
+				state = tess_eval_shader_specializations;
 			} else if (parse_str(line, "[geometry shader]", NULL)) {
 				state = geometry_shader;
 				shader_string = NULL;
+			} else if (parse_str(line, "[geometry shader specializations]", NULL)) {
+				state = geometry_shader_specializations;
 			} else if (parse_str(line, "[geometry shader spirv]", NULL)) {
 				state = geometry_shader_spirv;
 				shader_string = NULL;
+			} else if (parse_str(line, "[geometry shader specializations]", NULL)) {
+				state = geometry_shader_specializations;
 			} else if (parse_str(line, "[geometry layout]", NULL)) {
 				state = geometry_layout;
 				shader_string = NULL;
@@ -1557,15 +1717,21 @@  process_test_script(const char *script_name)
 			} else if (parse_str(line, "[fragment program]", NULL)) {
 				state = fragment_program;
 				shader_string = NULL;
+			} else if (parse_str(line, "[fragment shader specializations]", NULL)) {
+				state = fragment_shader_specializations;
 			} else if (parse_str(line, "[fragment shader spirv]", NULL)) {
 				state = fragment_shader_spirv;
 				shader_string = NULL;
+			} else if (parse_str(line, "[fragment shader specializations]", NULL)) {
+				state = fragment_shader_specializations;
 			} else if (parse_str(line, "[compute shader]", NULL)) {
 				state = compute_shader;
 				shader_string = NULL;
 			} else if (parse_str(line, "[compute shader spirv]", NULL)) {
 				state = compute_shader_spirv;
 				shader_string = NULL;
+			} else if (parse_str(line, "[compute shader specializations]", NULL)) {
+				state = compute_shader_specializations;
 			} else if (parse_str(line, "[vertex data]", NULL)) {
 				state = vertex_data;
 				vertex_data_start = NULL;
@@ -1615,6 +1781,19 @@  process_test_script(const char *script_name)
 					shader_string = (char *) line;
 				break;
 
+			case vertex_shader_specializations:
+			case tess_ctrl_shader_specializations:
+			case tess_eval_shader_specializations:
+			case geometry_shader_specializations:
+			case fragment_shader_specializations:
+			case compute_shader_specializations: {
+				enum piglit_result result =
+					process_specialization(state, line);
+				if (result != PIGLIT_PASS)
+					return result;
+				break;
+			}
+
 			case vertex_data:
 				if (vertex_data_start == NULL)
 					vertex_data_start = line;