Validate SetPushConstants is done inside subpass and compute passes

This commit is contained in:
Corentin Wallez 2017-07-20 11:01:37 -04:00 committed by Corentin Wallez
parent be985c1aab
commit c8377da79b
7 changed files with 29 additions and 8 deletions

View File

@ -380,7 +380,7 @@
"TODO Vulkan has an additional stage mask" "TODO Vulkan has an additional stage mask"
], ],
"args": [ "args": [
{"name": "stage", "type": "shader stage bit"}, {"name": "stages", "type": "shader stage bit"},
{"name": "offset", "type": "uint32_t"}, {"name": "offset", "type": "uint32_t"},
{"name": "count", "type": "uint32_t"}, {"name": "count", "type": "uint32_t"},
{"name": "data", "type": "uint32_t", "annotation": "const*", "length": "count"} {"name": "data", "type": "uint32_t", "annotation": "const*", "length": "count"}

View File

@ -552,8 +552,9 @@ namespace backend {
{ {
SetPushConstantsCmd* cmd = iterator.NextCommand<SetPushConstantsCmd>(); SetPushConstantsCmd* cmd = iterator.NextCommand<SetPushConstantsCmd>();
iterator.NextData<uint32_t>(cmd->count); iterator.NextData<uint32_t>(cmd->count);
if (cmd->count + cmd->offset > kMaxPushConstants) { // Validation of count and offset has already been done when the command was recorded
HandleError("Setting pushconstants past the limit"); // because it impacts the size of an allocation in the CommandAllocator.
if (!state->ValidateSetPushConstants(cmd->stages)) {
return false; return false;
} }
} }
@ -755,7 +756,8 @@ namespace backend {
cmd->pipeline = pipeline; cmd->pipeline = pipeline;
} }
void CommandBufferBuilder::SetPushConstants(nxt::ShaderStageBit stage, uint32_t offset, uint32_t count, const void* data) { void CommandBufferBuilder::SetPushConstants(nxt::ShaderStageBit stages, uint32_t offset, uint32_t count, const void* data) {
// TODO(cwallez@chromium.org): check for overflows
if (offset + count > kMaxPushConstants) { if (offset + count > kMaxPushConstants) {
HandleError("Setting too many push constants"); HandleError("Setting too many push constants");
return; return;
@ -763,7 +765,7 @@ namespace backend {
SetPushConstantsCmd* cmd = allocator.Allocate<SetPushConstantsCmd>(Command::SetPushConstants); SetPushConstantsCmd* cmd = allocator.Allocate<SetPushConstantsCmd>(Command::SetPushConstants);
new(cmd) SetPushConstantsCmd; new(cmd) SetPushConstantsCmd;
cmd->stage = stage; cmd->stages = stages;
cmd->offset = offset; cmd->offset = offset;
cmd->count = count; cmd->count = count;

View File

@ -77,7 +77,7 @@ namespace backend {
void EndComputePass(); void EndComputePass();
void EndRenderPass(); void EndRenderPass();
void EndRenderSubpass(); void EndRenderSubpass();
void SetPushConstants(nxt::ShaderStageBit stage, uint32_t offset, uint32_t count, const void* data); void SetPushConstants(nxt::ShaderStageBit stages, uint32_t offset, uint32_t count, const void* data);
void SetComputePipeline(ComputePipelineBase* pipeline); void SetComputePipeline(ComputePipelineBase* pipeline);
void SetRenderPipeline(RenderPipelineBase* pipeline); void SetRenderPipeline(RenderPipelineBase* pipeline);
void SetStencilReference(uint32_t reference); void SetStencilReference(uint32_t reference);

View File

@ -127,6 +127,24 @@ namespace backend {
return true; return true;
} }
bool CommandBufferStateTracker::ValidateSetPushConstants(nxt::ShaderStageBit stages) {
if (aspects[VALIDATION_ASPECT_COMPUTE_PASS]) {
if (stages & ~nxt::ShaderStageBit::Compute) {
builder->HandleError("SetPushConstants stage must be compute or 0 in compute passes");
return false;
}
} else if (aspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
if (stages & ~(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) {
builder->HandleError("SetPushConstants stage must be a subset if (vertex|fragment) in subpasses");
return false;
}
} else {
builder->HandleError("PushConstants must be set in either compute passes or subpasses");
return false;
}
return true;
}
bool CommandBufferStateTracker::BeginComputePass() { bool CommandBufferStateTracker::BeginComputePass() {
if (currentRenderPass != nullptr) { if (currentRenderPass != nullptr) {
builder->HandleError("Cannot begin a compute pass while a render pass is active"); builder->HandleError("Cannot begin a compute pass while a render pass is active");

View File

@ -37,6 +37,7 @@ namespace backend {
bool ValidateCanDrawArrays(); bool ValidateCanDrawArrays();
bool ValidateCanDrawElements(); bool ValidateCanDrawElements();
bool ValidateEndCommandBuffer() const; bool ValidateEndCommandBuffer() const;
bool ValidateSetPushConstants(nxt::ShaderStageBit stages);
// State-modifying methods // State-modifying methods
bool BeginComputePass(); bool BeginComputePass();

View File

@ -130,7 +130,7 @@ namespace backend {
}; };
struct SetPushConstantsCmd { struct SetPushConstantsCmd {
nxt::ShaderStageBit stage; nxt::ShaderStageBit stages;
uint32_t offset; uint32_t offset;
uint32_t count; uint32_t count;
}; };

View File

@ -314,7 +314,7 @@ namespace opengl {
int32_t* valuesInt = reinterpret_cast<int32_t*>(valuesUInt); int32_t* valuesInt = reinterpret_cast<int32_t*>(valuesUInt);
float* valuesFloat = reinterpret_cast<float*>(valuesUInt); float* valuesFloat = reinterpret_cast<float*>(valuesUInt);
for (auto stage : IterateStages(cmd->stage)) { for (auto stage : IterateStages(cmd->stages)) {
const auto& pushConstants = lastPipeline->GetPushConstants(stage); const auto& pushConstants = lastPipeline->GetPushConstants(stage);
const auto& glPushConstants = lastGLPipeline->GetGLPushConstants(stage); const auto& glPushConstants = lastGLPipeline->GetGLPushConstants(stage);
for (size_t i = 0; i < cmd->count; i++) { for (size_t i = 0; i < cmd->count; i++) {