diff options
author | Timothy Arceri <timothy.arceri@collabora.com> | 2016-03-11 11:57:52 +1100 |
---|---|---|
committer | Timothy Arceri <timothy.arceri@collabora.com> | 2016-03-31 12:52:00 +1100 |
commit | 8120e869b1cde7fd1a3679291782f2f50296cb45 (patch) | |
tree | c1c38935b9a7ab980684bdcd911d475f50516dc0 | |
parent | cf039a309a36ba537b45f3bfe7e5a154c87d51ad (diff) |
glsl: validate global out xfb_stride qualifiers and set stride on empty buffers
Here we use the built-in validation in
ast_layout_expression::process_qualifier_constant() to check for mismatching
global out strides on buffers in a single shader.
From the ARB_enhanced_layouts spec:
"While *xfb_stride* can be declared multiple times for the same buffer,
it is a compile-time or link-time error to have different values
specified for the stride for the same buffer."
For intrastage validation a new helper link_xfb_stride_layout_qualifiers()
is created. We also take this opportunity to make sure stride is at least
a multiple of 4, we will validate doubles at a later stage.
From the ARB_enhanced_layouts spec:
"If the buffer is capturing any double-typed outputs, the stride must
be a multiple of 8, otherwise it must be a multiple of 4, or a
compile-time or link-time error results."
Finally we update store_tfeedback_info() to apply the strides to
LinkedTransformFeedback and update the buffers bitmask to mark any global
buffers with a stride as active. For example a shader with:
layout (xfb_buffer = 0, xfb_offset = 0) out vec4 gs_fs;
layout (xfb_buffer = 1, xfb_stride = 64) out;
Is expected to have a buffer bound to both 0 and 1.
From the ARB_enhanced_layouts spec:
"A binding point requires a bound buffer object if and only if its
associated stride in the program object used for transform feedback
primitive capture is non-zero."
Reviewed-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | src/compiler/glsl/glsl_parser_extras.cpp | 11 | ||||
-rw-r--r-- | src/compiler/glsl/link_varyings.cpp | 11 | ||||
-rw-r--r-- | src/compiler/glsl/linker.cpp | 65 | ||||
-rw-r--r-- | src/mesa/main/mtypes.h | 7 |
4 files changed, 94 insertions, 0 deletions
diff --git a/src/compiler/glsl/glsl_parser_extras.cpp b/src/compiler/glsl/glsl_parser_extras.cpp index b88b622051..0ce89ceb3a 100644 --- a/src/compiler/glsl/glsl_parser_extras.cpp +++ b/src/compiler/glsl/glsl_parser_extras.cpp @@ -1617,6 +1617,17 @@ set_shader_inout_layout(struct gl_shader *shader, assert(!state->fs_early_fragment_tests); } + for (unsigned i = 0; i < MAX_FEEDBACK_BUFFERS; i++) { + if (state->out_qualifier->out_xfb_stride[i]) { + unsigned xfb_stride; + if (state->out_qualifier->out_xfb_stride[i]-> + process_qualifier_constant(state, "xfb_stride", &xfb_stride, + true)) { + shader->TransformFeedback.BufferStride[i] = xfb_stride; + } + } + } + switch (shader->Stage) { case MESA_SHADER_TESS_CTRL: shader->TessCtrl.VerticesOut = 0; diff --git a/src/compiler/glsl/link_varyings.cpp b/src/compiler/glsl/link_varyings.cpp index 5645f783f3..d91642dea5 100644 --- a/src/compiler/glsl/link_varyings.cpp +++ b/src/compiler/glsl/link_varyings.cpp @@ -930,6 +930,17 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, unsigned buffer = num_tfeedback_decls ? tfeedback_decls[0].get_buffer() : 0; + /* Apply any xfb_stride global qualifiers */ + if (has_xfb_qualifiers) { + for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) { + if (prog->TransformFeedback.BufferStride[j]) { + buffers |= 1 << j; + prog->LinkedTransformFeedback.Buffers[j].Stride = + prog->TransformFeedback.BufferStride[j] / 4; + } + } + } + for (unsigned i = 0; i < num_tfeedback_decls; ++i) { if (tfeedback_decls[i].is_next_buffer_separator()) { num_buffers++; diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp index 3ae958cacb..4f191c5002 100644 --- a/src/compiler/glsl/linker.cpp +++ b/src/compiler/glsl/linker.cpp @@ -1584,6 +1584,69 @@ private: hash_table *unnamed_interfaces; }; +/** + * Check for conflicting xfb_stride default qualifiers and store buffer stride + * for later use. + */ +static void +link_xfb_stride_layout_qualifiers(struct gl_context *ctx, + struct gl_shader_program *prog, + struct gl_shader *linked_shader, + struct gl_shader **shader_list, + unsigned num_shaders) +{ + for (unsigned i = 0; i < MAX_FEEDBACK_BUFFERS; i++) { + linked_shader->TransformFeedback.BufferStride[i] = 0; + } + + for (unsigned i = 0; i < num_shaders; i++) { + struct gl_shader *shader = shader_list[i]; + + for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) { + if (shader->TransformFeedback.BufferStride[j]) { + if (linked_shader->TransformFeedback.BufferStride[j] != 0 && + shader->TransformFeedback.BufferStride[j] != 0 && + linked_shader->TransformFeedback.BufferStride[j] != + shader->TransformFeedback.BufferStride[j]) { + linker_error(prog, + "intrastage shaders defined with conflicting " + "xfb_stride for buffer %d (%d and %d)\n", j, + linked_shader->TransformFeedback.BufferStride[j], + shader->TransformFeedback.BufferStride[j]); + return; + } + + if (shader->TransformFeedback.BufferStride[j]) + linked_shader->TransformFeedback.BufferStride[j] = + shader->TransformFeedback.BufferStride[j]; + } + } + } + + for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) { + if (linked_shader->TransformFeedback.BufferStride[j]) { + prog->TransformFeedback.BufferStride[j] = + linked_shader->TransformFeedback.BufferStride[j]; + + /* We will validate doubles at a later stage */ + if (prog->TransformFeedback.BufferStride[j] % 4) { + linker_error(prog, "invalid qualifier xfb_stride=%d must be a " + "multiple of 4 or if its applied to a type that is " + "or contains a double a multiple of 8.", + prog->TransformFeedback.BufferStride[j]); + return; + } + + if (prog->TransformFeedback.BufferStride[j] / 4 > + ctx->Const.MaxTransformFeedbackInterleavedComponents) { + linker_error(prog, + "The MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS " + "limit has been exceeded."); + return; + } + } + } +} /** * Performs the cross-validation of tessellation control shader vertices and @@ -2101,6 +2164,8 @@ link_intrastage_shaders(void *mem_ctx, link_tes_in_layout_qualifiers(prog, linked, shader_list, num_shaders); link_gs_inout_layout_qualifiers(prog, linked, shader_list, num_shaders); link_cs_input_layout_qualifiers(prog, linked, shader_list, num_shaders); + link_xfb_stride_layout_qualifiers(ctx, prog, linked, shader_list, + num_shaders); populate_symbol_table(linked); diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 90c3851e72..1e15b69ab7 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2337,6 +2337,11 @@ struct gl_shader bool origin_upper_left; bool pixel_center_integer; + struct { + /** Global xfb_stride out qualifier if any */ + GLuint BufferStride[MAX_FEEDBACK_BUFFERS]; + } TransformFeedback; + /** * Tessellation Control shader state from layout qualifiers. */ @@ -2674,6 +2679,8 @@ struct gl_shader_program */ struct { GLenum BufferMode; + /** Global xfb_stride out qualifier if any */ + GLuint BufferStride[MAX_FEEDBACK_BUFFERS]; GLuint NumVarying; GLchar **VaryingNames; /**< Array [NumVarying] of char * */ } TransformFeedback; |