diff options
| author | Chris Forbes <chrisforbes@google.com> | 2016-01-15 14:53:11 +1300 |
|---|---|---|
| committer | Jon Ashburn <jon@lunarg.com> | 2016-01-15 11:13:04 -0700 |
| commit | a5982680a631c1a6b2b5954174a69df75f5c8d8b (patch) | |
| tree | 7ecbac1a7861d0d75ae2869e41f944513b0916b3 | |
| parent | c8f716f269bf4762d407cd3053d9073c1149ef43 (diff) | |
| download | usermoji-a5982680a631c1a6b2b5954174a69df75f5c8d8b.tar.xz | |
layers: Add minimal actual analysis of interface blocks to DrawState
There's definitely still room for improvement here (SPIRV-Tools might have some stuff that will make some of these more complex module walks a little clearer); however, this adds enough support for interface blocks for us to generate all the same kinds of mismatch errors we were previously generating for loose inputs and outputs.
Signed-off-by: Chris Forbes <chrisforbes@google.com>
| -rw-r--r-- | layers/draw_state.cpp | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/layers/draw_state.cpp b/layers/draw_state.cpp index b9d1388d..a9c809bd 100644 --- a/layers/draw_state.cpp +++ b/layers/draw_state.cpp @@ -545,6 +545,91 @@ struct interface_var { /* TODO: collect the name, too? Isn't required to be present. */ }; + +static void +collect_interface_block_members(layer_data *my_data, VkDevice dev, + shader_module const *src, + std::map<uint32_t, interface_var> &out, + std::map<uint32_t, interface_var> &builtins_out, + std::unordered_map<unsigned, unsigned> const &blocks, + bool is_array_of_verts, + uint32_t id, + uint32_t type_id) +{ + /* Walk down the type_id presented, trying to determine whether it's actually an interface block. */ + std::unordered_map<unsigned, unsigned>::const_iterator type_def_it; + while (true) { + + type_def_it = src->type_def_index.find(type_id); + if (type_def_it == src->type_def_index.end()) { + return; /* this is actually broken SPIR-V */ + } + + unsigned int const *code = (unsigned int const *)&src->words[type_def_it->second]; + unsigned opcode = code[0] & 0x0ffffu; + + if (opcode == spv::OpTypePointer) { + type_id = code[3]; + } + else if (opcode == spv::OpTypeArray && is_array_of_verts) { + type_id = code[2]; + is_array_of_verts = false; + } + else if (opcode == spv::OpTypeStruct) { + if (blocks.find(type_id) == blocks.end()) { + /* This isn't an interface block. */ + return; + } + else { + /* We have found the correct type. Walk its members. */ + break; + } + } + else { + /* not an interface block */ + return; + } + } + + /* Walk OpMemberDecorate for type_id. */ + unsigned int const *code = (unsigned int const *)&src->words[0]; + size_t size = src->words.size(); + unsigned word = 5; + while (word < size) { + + unsigned opcode = code[word] & 0x0ffffu; + unsigned oplen = (code[word] & 0xffff0000u) >> 16; + + if (opcode == spv::OpMemberDecorate && code[word+1] == type_id) { + unsigned member_index = code[word+2]; + unsigned member_type_id = code[type_def_it->second + 2 + member_index]; + + if (code[word+3] == spv::DecorationLocation) { + unsigned location = code[word+4]; + unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false); + for (unsigned int offset = 0; offset < num_locations; offset++) { + interface_var v; + v.id = id; + /* TODO: member index in interface_var too? */ + v.type_id = member_type_id; + v.offset = offset; + out[location + offset] = v; + } + } + else if (code[word+3] == spv::DecorationBuiltIn) { + unsigned builtin = code[word+4]; + interface_var v; + v.id = id; + v.type_id = member_type_id; + v.offset = 0; + builtins_out[builtin] = v; + } + } + + word += oplen; + } +} + static void collect_interface_by_location(layer_data *my_data, VkDevice dev, shader_module const *src, spv::StorageClass sinterface, @@ -557,6 +642,7 @@ collect_interface_by_location(layer_data *my_data, VkDevice dev, std::unordered_map<unsigned, unsigned> var_locations; std::unordered_map<unsigned, unsigned> var_builtins; + std::unordered_map<unsigned, unsigned> blocks; unsigned word = 5; while (word < size) { @@ -575,6 +661,10 @@ collect_interface_by_location(layer_data *my_data, VkDevice dev, if (code[word+2] == spv::DecorationBuiltIn) { var_builtins[code[word+1]] = code[word+3]; } + + if (code[word+2] == spv::DecorationBlock) { + blocks[code[word+1]] = 1; + } } /* TODO: handle grouped decorations */ @@ -620,6 +710,11 @@ collect_interface_by_location(layer_data *my_data, VkDevice dev, v.offset = 0; builtins_out[builtin] = v; } + else { + /* An interface block instance */ + collect_interface_block_members(my_data, dev, src, out, builtins_out, + blocks, is_array_of_verts, id, type); + } } word += oplen; |
