diff options
author | Timothy Arceri <[email protected]> | 2016-03-03 15:26:53 +1100 |
---|---|---|
committer | Timothy Arceri <[email protected]> | 2016-03-31 12:52:05 +1100 |
commit | 2fab85aaea59cb2d31d34ea6de94180ca83fe2dd (patch) | |
tree | ce5bee143ecf81de4ef813a80af4709ec4e9aa1c /src | |
parent | 8120e869b1cde7fd1a3679291782f2f50296cb45 (diff) |
glsl: add xfb_stride link time validation
From the ARB_enhanced_layous spec:
"It is a compile-time or link-time error to have any *xfb_offset*
that overflows *xfb_stride*, whether stated on declarations before
or after the *xfb_stride*, or in different compilation units.
...
When no *xfb_stride* is specified for a buffer, the stride of a
buffer will be the smallest needed to hold the variable placed at
the highest offset, including any required padding."
Reviewed-by: Dave Airlie <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/glsl/link_varyings.cpp | 44 | ||||
-rw-r--r-- | src/compiler/glsl/link_varyings.h | 3 |
2 files changed, 39 insertions, 8 deletions
diff --git a/src/compiler/glsl/link_varyings.cpp b/src/compiler/glsl/link_varyings.cpp index d91642dea5c..89bc68e277e 100644 --- a/src/compiler/glsl/link_varyings.cpp +++ b/src/compiler/glsl/link_varyings.cpp @@ -716,7 +716,7 @@ bool tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog, struct gl_transform_feedback_info *info, unsigned buffer, const unsigned max_outputs, - bool has_xfb_qualifiers) const + bool *explicit_stride, bool has_xfb_qualifiers) const { assert(!this->next_buffer_separator); @@ -726,6 +726,13 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog, return true; } + unsigned xfb_offset = 0; + if (has_xfb_qualifiers) { + xfb_offset = this->offset / 4; + } else { + xfb_offset = info->Buffers[buffer].Stride; + } + /* From GL_EXT_transform_feedback: * A program will fail to link if: * @@ -752,17 +759,38 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog, info->Outputs[info->NumOutputs].NumComponents = output_size; info->Outputs[info->NumOutputs].StreamId = stream_id; info->Outputs[info->NumOutputs].OutputBuffer = buffer; - info->Outputs[info->NumOutputs].DstOffset = - info->Buffers[buffer].Stride; + info->Outputs[info->NumOutputs].DstOffset = xfb_offset; ++info->NumOutputs; - info->Buffers[buffer].Stride += output_size; info->Buffers[buffer].Stream = this->stream_id; + xfb_offset += output_size; + num_components -= output_size; location++; location_frac = 0; } - info->Varyings[info->NumVarying].Name = ralloc_strdup(prog, this->orig_name); + if (explicit_stride && explicit_stride[buffer]) { + if (this->is_double() && info->Buffers[buffer].Stride % 2) { + linker_error(prog, "invalid qualifier xfb_stride=%d must be a " + "multiple of 8 as its applied to a type that is or " + "contains a double.", + info->Buffers[buffer].Stride * 4); + return false; + } + + if ((this->offset / 4) / info->Buffers[buffer].Stride != + (xfb_offset - 1) / info->Buffers[buffer].Stride) { + linker_error(prog, "xfb_offset (%d) overflows xfb_stride (%d) for " + "buffer (%d)", xfb_offset * 4, + info->Buffers[buffer].Stride * 4, buffer); + return false; + } + } else { + info->Buffers[buffer].Stride = xfb_offset; + } + + info->Varyings[info->NumVarying].Name = ralloc_strdup(prog, + this->orig_name); info->Varyings[info->NumVarying].Type = this->type; info->Varyings[info->NumVarying].Size = this->size; info->NumVarying++; @@ -916,7 +944,7 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, /* GL_SEPARATE_ATTRIBS */ for (unsigned i = 0; i < num_tfeedback_decls; ++i) { if (!tfeedback_decls[i].store(ctx, prog, &prog->LinkedTransformFeedback, - num_buffers, num_outputs, + num_buffers, num_outputs, NULL, has_xfb_qualifiers)) return false; @@ -929,12 +957,14 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, int buffer_stream_id = -1; unsigned buffer = num_tfeedback_decls ? tfeedback_decls[0].get_buffer() : 0; + bool explicit_stride[MAX_FEEDBACK_BUFFERS] = { false }; /* 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; + explicit_stride[j] = true; prog->LinkedTransformFeedback.Buffers[j].Stride = prog->TransformFeedback.BufferStride[j] / 4; } @@ -973,7 +1003,7 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog, if (!tfeedback_decls[i].store(ctx, prog, &prog->LinkedTransformFeedback, num_buffers, num_outputs, - has_xfb_qualifiers)) + explicit_stride, has_xfb_qualifiers)) return false; } } diff --git a/src/compiler/glsl/link_varyings.h b/src/compiler/glsl/link_varyings.h index 7165ecb9184..7919a8d5cd5 100644 --- a/src/compiler/glsl/link_varyings.h +++ b/src/compiler/glsl/link_varyings.h @@ -98,7 +98,8 @@ public: unsigned get_num_outputs() const; bool store(struct gl_context *ctx, struct gl_shader_program *prog, struct gl_transform_feedback_info *info, unsigned buffer, - const unsigned max_outputs, bool has_xfb_qualifiers) const; + const unsigned max_outputs, bool *explicit_stride, + bool has_xfb_qualifiers) const; const tfeedback_candidate *find_candidate(gl_shader_program *prog, hash_table *tfeedback_candidates); |