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 <airlied@redhat.com>
This commit is contained in:
@@ -716,7 +716,7 @@ bool
|
|||||||
tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
|
tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
|
||||||
struct gl_transform_feedback_info *info,
|
struct gl_transform_feedback_info *info,
|
||||||
unsigned buffer, const unsigned max_outputs,
|
unsigned buffer, const unsigned max_outputs,
|
||||||
bool has_xfb_qualifiers) const
|
bool *explicit_stride, bool has_xfb_qualifiers) const
|
||||||
{
|
{
|
||||||
assert(!this->next_buffer_separator);
|
assert(!this->next_buffer_separator);
|
||||||
|
|
||||||
@@ -726,6 +726,13 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
|
|||||||
return true;
|
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:
|
/* From GL_EXT_transform_feedback:
|
||||||
* A program will fail to link if:
|
* 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].NumComponents = output_size;
|
||||||
info->Outputs[info->NumOutputs].StreamId = stream_id;
|
info->Outputs[info->NumOutputs].StreamId = stream_id;
|
||||||
info->Outputs[info->NumOutputs].OutputBuffer = buffer;
|
info->Outputs[info->NumOutputs].OutputBuffer = buffer;
|
||||||
info->Outputs[info->NumOutputs].DstOffset =
|
info->Outputs[info->NumOutputs].DstOffset = xfb_offset;
|
||||||
info->Buffers[buffer].Stride;
|
|
||||||
++info->NumOutputs;
|
++info->NumOutputs;
|
||||||
info->Buffers[buffer].Stride += output_size;
|
|
||||||
info->Buffers[buffer].Stream = this->stream_id;
|
info->Buffers[buffer].Stream = this->stream_id;
|
||||||
|
xfb_offset += output_size;
|
||||||
|
|
||||||
num_components -= output_size;
|
num_components -= output_size;
|
||||||
location++;
|
location++;
|
||||||
location_frac = 0;
|
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].Type = this->type;
|
||||||
info->Varyings[info->NumVarying].Size = this->size;
|
info->Varyings[info->NumVarying].Size = this->size;
|
||||||
info->NumVarying++;
|
info->NumVarying++;
|
||||||
@@ -916,7 +944,7 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
|
|||||||
/* GL_SEPARATE_ATTRIBS */
|
/* GL_SEPARATE_ATTRIBS */
|
||||||
for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
|
for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
|
||||||
if (!tfeedback_decls[i].store(ctx, prog, &prog->LinkedTransformFeedback,
|
if (!tfeedback_decls[i].store(ctx, prog, &prog->LinkedTransformFeedback,
|
||||||
num_buffers, num_outputs,
|
num_buffers, num_outputs, NULL,
|
||||||
has_xfb_qualifiers))
|
has_xfb_qualifiers))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -929,12 +957,14 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
|
|||||||
int buffer_stream_id = -1;
|
int buffer_stream_id = -1;
|
||||||
unsigned buffer =
|
unsigned buffer =
|
||||||
num_tfeedback_decls ? tfeedback_decls[0].get_buffer() : 0;
|
num_tfeedback_decls ? tfeedback_decls[0].get_buffer() : 0;
|
||||||
|
bool explicit_stride[MAX_FEEDBACK_BUFFERS] = { false };
|
||||||
|
|
||||||
/* Apply any xfb_stride global qualifiers */
|
/* Apply any xfb_stride global qualifiers */
|
||||||
if (has_xfb_qualifiers) {
|
if (has_xfb_qualifiers) {
|
||||||
for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
|
for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
|
||||||
if (prog->TransformFeedback.BufferStride[j]) {
|
if (prog->TransformFeedback.BufferStride[j]) {
|
||||||
buffers |= 1 << j;
|
buffers |= 1 << j;
|
||||||
|
explicit_stride[j] = true;
|
||||||
prog->LinkedTransformFeedback.Buffers[j].Stride =
|
prog->LinkedTransformFeedback.Buffers[j].Stride =
|
||||||
prog->TransformFeedback.BufferStride[j] / 4;
|
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,
|
if (!tfeedback_decls[i].store(ctx, prog,
|
||||||
&prog->LinkedTransformFeedback,
|
&prog->LinkedTransformFeedback,
|
||||||
num_buffers, num_outputs,
|
num_buffers, num_outputs,
|
||||||
has_xfb_qualifiers))
|
explicit_stride, has_xfb_qualifiers))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -98,7 +98,8 @@ public:
|
|||||||
unsigned get_num_outputs() const;
|
unsigned get_num_outputs() const;
|
||||||
bool store(struct gl_context *ctx, struct gl_shader_program *prog,
|
bool store(struct gl_context *ctx, struct gl_shader_program *prog,
|
||||||
struct gl_transform_feedback_info *info, unsigned buffer,
|
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,
|
const tfeedback_candidate *find_candidate(gl_shader_program *prog,
|
||||||
hash_table *tfeedback_candidates);
|
hash_table *tfeedback_candidates);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user