From: Chris Forbes Date: Fri, 15 Jan 2016 01:53:11 +0000 (+1300) Subject: layers: Add minimal actual analysis of interface blocks to DrawState X-Git-Tag: upstream/1.1.92~4091 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a5982680a631c1a6b2b5954174a69df75f5c8d8b;p=platform%2Fupstream%2FVulkan-Tools.git 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 --- diff --git a/layers/draw_state.cpp b/layers/draw_state.cpp index b9d1388..a9c809b 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 &out, + std::map &builtins_out, + std::unordered_map 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::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 var_locations; std::unordered_map var_builtins; + std::unordered_map 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;