aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Forbes <chrisforbes@google.com>2016-02-26 16:55:34 +1300
committerChris Forbes <chrisforbes@google.com>2016-03-04 08:57:28 +1300
commitc79c18aac92d9405a0ff553c471f92e3413b7e4e (patch)
tree3bb05eafb2a0def854b474d677be5c8ebfc70ef2
parentd5fc1b5d02234c2829a4295f70fc03bd64d37d2a (diff)
downloadusermoji-c79c18aac92d9405a0ff553c471f92e3413b7e4e.tar.xz
layers: validate push constant ranges accessed by shader
Signed-off-by: Chris Forbes <chrisforbes@google.com>
-rw-r--r--layers/draw_state.cpp95
1 files changed, 95 insertions, 0 deletions
diff --git a/layers/draw_state.cpp b/layers/draw_state.cpp
index 9876f1e9..3200cb90 100644
--- a/layers/draw_state.cpp
+++ b/layers/draw_state.cpp
@@ -1291,6 +1291,93 @@ shader_stage_attribs[] = {
{ "fragment shader", false },
};
+static bool validate_push_constant_block_against_pipeline(
+ layer_data* my_data, VkDevice dev,
+ std::vector<VkPushConstantRange> const* pushConstantRanges,
+ shader_module const* src, spirv_inst_iter type,
+ VkShaderStageFlagBits stage) {
+ bool pass = true;
+
+ /* strip off ptrs etc */
+ type = get_struct_type(src, type, false);
+ assert(type != src->end());
+
+ /* validate directly off the offsets. this isn't quite correct for arrays
+ * and matrices, but is a good first step. TODO: arrays, matrices, weird
+ * sizes */
+ for (auto insn : *src) {
+ if (insn.opcode() == spv::OpMemberDecorate &&
+ insn.word(1) == type.word(1)) {
+ unsigned member_index = insn.word(2);
+
+ if (insn.word(3) == spv::DecorationOffset) {
+ unsigned offset = insn.word(4);
+ auto size = 4; /* bytes; TODO: calculate this based on the type */
+
+ bool found_range = false;
+ for (auto const& range : *pushConstantRanges) {
+ if (range.offset <= offset &&
+ range.offset + range.size >= offset + size) {
+ found_range = true;
+
+ if ((range.stageFlags & stage) == 0) {
+ if (log_msg(
+ my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+ /* dev */ 0, __LINE__,
+ SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE,
+ "SC",
+ "Push constant range covering variable starting at "
+ "offset %u not accessible from %s stage",
+ offset,
+ shader_stage_attribs[get_shader_stage_id(stage)].name)) {
+ pass = false;
+ }
+ }
+
+ break;
+ }
+ }
+
+ if (!found_range) {
+ if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+ /* dev */ 0, __LINE__,
+ SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC",
+ "Push constant range covering variable starting at "
+ "offset %u not declared in layout",
+ offset)) {
+ pass = false;
+ }
+ }
+ }
+ }
+ }
+
+ return pass;
+}
+
+static bool validate_push_constant_usage(
+ layer_data* my_data, VkDevice dev,
+ std::vector<VkPushConstantRange> const* pushConstantRanges,
+ shader_module const* src, std::unordered_set<uint32_t> accessible_ids,
+ VkShaderStageFlagBits stage) {
+ bool pass = true;
+
+ for (auto id : accessible_ids) {
+ auto def_insn = src->get_def(id);
+ if (def_insn.opcode() == spv::OpVariable &&
+ def_insn.word(3) == spv::StorageClassPushConstant) {
+ pass = validate_push_constant_block_against_pipeline(
+ my_data, dev, pushConstantRanges, src,
+ src->get_def(def_insn.word(1)), stage) &&
+ pass;
+ }
+ }
+
+ return pass;
+}
+
// For given pipelineLayout verify that the setLayout at slot.first
// has the requested binding at slot.second
static bool
@@ -1624,6 +1711,14 @@ validate_pipeline_shaders(layer_data *my_data, VkDevice dev, PIPELINE_NODE* pPip
}
}
}
+
+ /* validate push constant usage */
+ pass = validate_push_constant_usage(
+ my_data, dev,
+ &my_data->pipelineLayoutMap[pCreateInfo->layout]
+ .pushConstantRanges,
+ module, accessible_ids, pStage->stage) &&
+ pass;
}
}
}