Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding preliminary SpecConstant support #154

Open
wants to merge 47 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
4937236
Adding preliminary `SpecConstant` support
shangjiaxuan Jul 28, 2022
e1dfa44
Add 64 bit type support, cleanup value clutter
shangjiaxuan Jul 28, 2022
4237240
Adding evaluations
shangjiaxuan Jul 29, 2022
79fbd2e
Adding arithmetic operations
shangjiaxuan Jul 29, 2022
65eabd4
Most arithmetic operations for integers are here.
shangjiaxuan Jul 30, 2022
4697ff6
Move some expr to `#define`
shangjiaxuan Jul 30, 2022
cb7b2b9
Most operations done.
shangjiaxuan Jul 31, 2022
4c8a546
Should now work with vector types and workgroupsize builtin
shangjiaxuan Jul 31, 2022
f3a72fc
Compositing and de-compositing vectors implemented
shangjiaxuan Jul 31, 2022
06da6a4
Switch to another branch
shangjiaxuan Aug 1, 2022
94b2175
Added state tracking and ownership of result
shangjiaxuan Aug 1, 2022
ce8551e
Fix wrong type flag
shangjiaxuan Aug 1, 2022
87440b4
Sorting up api...
shangjiaxuan Aug 1, 2022
c000fdd
Naive implemenation
shangjiaxuan Aug 2, 2022
a52e29e
Refactor code
shangjiaxuan Aug 5, 2022
555b282
core code done
shangjiaxuan Aug 6, 2022
2b02ddb
Unify indentation
shangjiaxuan Aug 6, 2022
79cbd28
Fix const qualifier for cpp
shangjiaxuan Aug 6, 2022
bb0c173
Better WorkGroupSize builtin support
shangjiaxuan Aug 6, 2022
46034ae
Remove writing literal words in insert and extract
shangjiaxuan Aug 6, 2022
c5f79c8
Remove patch file
shangjiaxuan Aug 6, 2022
60a2614
Make evaluation support optional
shangjiaxuan Aug 6, 2022
967e211
Add cmake option
shangjiaxuan Aug 6, 2022
b6a67f4
Separate evaluation state from shader info in cpp
shangjiaxuan Aug 6, 2022
bfe3643
Add test shaders
shangjiaxuan Aug 7, 2022
a9025fc
Add tests
shangjiaxuan Aug 7, 2022
4e9c21e
Clean up
shangjiaxuan Aug 8, 2022
477119a
Fix gcc build warnings and errors
shangjiaxuan Aug 8, 2022
83aab12
Found some indentation inconsistency
shangjiaxuan Aug 10, 2022
830f957
Merge upstream changes.
shangjiaxuan Aug 10, 2022
4640fd6
Fix member indentation
shangjiaxuan Aug 12, 2022
8ad9290
Add structure filling
shangjiaxuan Aug 13, 2022
5f73ca4
Add cpp wrapper function
shangjiaxuan Aug 14, 2022
015bc9e
Fix build with vulkan.h and add evaluation duplication
shangjiaxuan Aug 15, 2022
a121be4
update to current upstream
shangjiaxuan Feb 13, 2023
743085d
Remove unnecessary changes and add tests.
shangjiaxuan Feb 13, 2023
4fdf062
Clean up for merge
shangjiaxuan May 19, 2023
cafdf08
Fix conflict
shangjiaxuan May 19, 2023
a6adf7b
Fix broken tests
shangjiaxuan May 19, 2023
64e256b
remove wrong comment
shangjiaxuan May 19, 2023
3ed6c76
Fix memory leak
shangjiaxuan Jul 12, 2023
2194341
Update upstream changes
shangjiaxuan Jul 12, 2023
0f941ac
Fix wrong text output.
shangjiaxuan Jul 12, 2023
f722a55
Fix Linux CI build
shangjiaxuan Jul 12, 2023
189f1dd
Fix cpp binding formatting
shangjiaxuan Jul 12, 2023
973645b
remove blank line between function and comment
shangjiaxuan Jul 12, 2023
ae349ae
Clarify spvReflectGetSpecializationInfo documentation.
shangjiaxuan Jul 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ OPTION(SPIRV_REFLECT_STRIPPER "Build stripper utility" OFF)
OPTION(SPIRV_REFLECT_STATIC_LIB "Build a SPIRV-Reflect static library" OFF)
OPTION(SPIRV_REFLECT_BUILD_TESTS "Build the SPIRV-Reflect test suite" OFF)
OPTION(SPIRV_REFLECT_ENABLE_ASSERTS "Enable asserts for debugging" OFF)
OPTION(SPIRV_REFLECT_ENABLE_EVALUATION "Enable evaluating constants' result id" ON)

set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_CXX_STANDARD 14)
Expand Down Expand Up @@ -35,6 +36,9 @@ if (SPIRV_REFLECT_EXECUTABLE)
if (SPIRV_REFLECT_ENABLE_ASSERTS)
target_compile_definitions(spirv-reflect PRIVATE SPIRV_REFLECT_ENABLE_ASSERTS)
endif()
if(SPIRV_REFLECT_ENABLE_EVALUATION)
target_compile_definitions(spirv-reflect PRIVATE SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION=1)
endif()
set_target_properties(spirv-reflect PROPERTIES CXX_STANDARD 11)
target_include_directories(spirv-reflect PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
if(WIN32)
Expand Down Expand Up @@ -63,6 +67,9 @@ if (SPIRV_REFLECT_EXECUTABLE)
if (SPIRV_REFLECT_ENABLE_ASSERTS)
target_compile_definitions(spirv-reflect-pp PRIVATE SPIRV_REFLECT_ENABLE_ASSERTS)
endif()
if(SPIRV_REFLECT_ENABLE_EVALUATION)
target_compile_definitions(spirv-reflect-pp PRIVATE SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION=1)
endif()
set_target_properties(spirv-reflect-pp PROPERTIES CXX_STANDARD 11)
target_include_directories(spirv-reflect-pp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
if(WIN32)
Expand Down Expand Up @@ -98,6 +105,9 @@ if (SPIRV_REFLECT_BUILD_TESTS)
CXX_STANDARD 11)
target_compile_definitions(test-spirv-reflect PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:_CRT_SECURE_NO_WARNINGS>)
if(SPIRV_REFLECT_ENABLE_EVALUATION)
target_compile_definitions(test-spirv-reflect PRIVATE SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION=1)
endif()
target_link_libraries(test-spirv-reflect gtest_main)
target_include_directories(test-spirv-reflect PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_command(TARGET test-spirv-reflect POST_BUILD
Expand All @@ -108,7 +118,9 @@ endif()
if(SPIRV_REFLECT_STATIC_LIB)
add_library(spirv-reflect-static STATIC ${CMAKE_CURRENT_SOURCE_DIR}/spirv_reflect.h
${CMAKE_CURRENT_SOURCE_DIR}/spirv_reflect.c)

if(SPIRV_REFLECT_ENABLE_EVALUATION)
target_compile_definitions(spirv-reflect-static PRIVATE SPIRV_REFLECT_ENABLE_CONSTANT_EVALUATION=1)
endif()
target_include_directories(spirv-reflect-static
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
install(TARGETS spirv-reflect-static LIBRARY DESTINATION lib)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ SPIRV-Reflect has been tested on Linux and Windows.
- Remap descriptor bindings at runtime, and update the source SPIR-V bytecode
accordingly.
- Log all reflection data as human-readable text.
- Experimental specialization constant parsing and evaluation

## Integration

Expand Down
190 changes: 172 additions & 18 deletions common/output_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth,
const std::string& parent_name,
uint32_t member_count,
const SpvReflectBlockVariable* p_members,
SpvReflectEvaluation* p_evaluator,
std::vector<TextLine>* p_text_lines) {
const char* t = indent;
for (uint32_t member_index = 0; member_index < member_count; ++member_index) {
Expand Down Expand Up @@ -966,7 +967,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth,
flatten_cbuffers ? p_text_lines : &tl.lines;
ParseBlockMembersToTextLines(t, indent_depth + 1, flatten_cbuffers,
current_parent_name, member.member_count,
member.members, p_target_text_line);
member.members, p_evaluator, p_target_text_line);
tl.text_line_flags = TEXT_LINE_TYPE_LINES;
p_text_lines->push_back(tl);

Expand Down Expand Up @@ -996,6 +997,13 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth,
// dim = 0 means it's an unbounded array
//
if (dim > 0) {
if (dim == 0xFFFFFFFF) {
const SpvReflectValue* val;
SpvReflectResult res = spvReflectEvaluateResult(p_evaluator, member.array.spec_constant_op_ids[array_dim_index], &val);
if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) {
dim = val->data.numeric.scalar.value.uint32_bool_value;
}
}
ss_array << "[" << dim << "]";
} else {
ss_array << "[]";
Expand Down Expand Up @@ -1033,7 +1041,14 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth,
for (uint32_t array_dim_index = 0;
array_dim_index < member.array.dims_count; ++array_dim_index) {
uint32_t dim = member.array.dims[array_dim_index];
ss_array << "[" << dim << "]";
if (dim == 0xFFFFFFFF) {
const SpvReflectValue* val;
SpvReflectResult res = spvReflectEvaluateResult(p_evaluator, member.array.spec_constant_op_ids[array_dim_index], &val);
if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) {
dim = val->data.numeric.scalar.value.uint32_bool_value;
}
}
ss_array << "[" << dim << "]";
}
tl.name += ss_array.str();
}
Expand All @@ -1050,6 +1065,7 @@ void ParseBlockMembersToTextLines(const char* indent, int indent_depth,

void ParseBlockVariableToTextLines(const char* indent, bool flatten_cbuffers,
const SpvReflectBlockVariable& block_var,
SpvReflectEvaluation* p_evaluator,
std::vector<TextLine>* p_text_lines) {
// Begin block
TextLine tl = {};
Expand All @@ -1066,7 +1082,7 @@ void ParseBlockVariableToTextLines(const char* indent, bool flatten_cbuffers,
tl = {};
ParseBlockMembersToTextLines(indent, 2, flatten_cbuffers, "",
block_var.member_count, block_var.members,
&tl.lines);
p_evaluator, &tl.lines);
tl.text_line_flags = TEXT_LINE_TYPE_LINES;
p_text_lines->push_back(tl);

Expand Down Expand Up @@ -1286,6 +1302,7 @@ void StreamWriteTextLines(std::ostream& os, const char* indent,

void StreamWritePushConstantsBlock(std::ostream& os,
const SpvReflectBlockVariable& obj,
SpvReflectEvaluation* p_evaluator,
bool flatten_cbuffers, const char* indent) {
const char* t = indent;
os << t << "spirv id : " << obj.spirv_id << "\n";
Expand All @@ -1298,7 +1315,8 @@ void StreamWritePushConstantsBlock(std::ostream& os,
}

std::vector<TextLine> text_lines;
ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj, &text_lines);
ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj, p_evaluator,
&text_lines);
if (!text_lines.empty()) {
os << "\n";
StreamWriteTextLines(os, t, flatten_cbuffers, text_lines);
Expand All @@ -1308,6 +1326,7 @@ void StreamWritePushConstantsBlock(std::ostream& os,

void StreamWriteDescriptorBinding(std::ostream& os,
const SpvReflectDescriptorBinding& obj,
SpvReflectEvaluation* p_evaluator,
bool write_set, bool flatten_cbuffers,
const char* indent) {
const char* t = indent;
Expand Down Expand Up @@ -1359,7 +1378,7 @@ void StreamWriteDescriptorBinding(std::ostream& os,
obj.descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) {
std::vector<TextLine> text_lines;
ParseBlockVariableToTextLines(" ", flatten_cbuffers, obj.block,
&text_lines);
p_evaluator, &text_lines);
if (!text_lines.empty()) {
os << "\n";
StreamWriteTextLines(os, t, flatten_cbuffers, text_lines);
Expand Down Expand Up @@ -1412,21 +1431,128 @@ void StreamWriteInterfaceVariable(std::ostream& os,
}
}

void StreamWriteEntryPoint(std::ostream& os, const SpvReflectEntryPoint& obj,
const char* indent) {
void StreamWriteSpecializationConstant(
std::ostream& os, const SpvReflectSpecializationConstant& obj,
const char* indent) {
const char* t = indent;
os << t << "spirv id : " << obj.spirv_id << "\n";
os << t << "constant id: " << obj.constant_id << "\n";
os << t << "name : " << (obj.name != NULL ? obj.name : "") << '\n';
os << t << "type : ";
int type = 0;
if (!obj.type || obj.type->type_flags == SPV_REFLECT_TYPE_FLAG_BOOL) {
type = 1;
} else if (obj.type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) {
type = 2;
} else if (obj.type->type_flags == SPV_REFLECT_TYPE_FLAG_FLOAT) {
type = 3;
}
switch (type) {
case 1:
os << "boolean\n";
os << t << "default : " << obj.default_value.value.uint32_bool_value;
break;
case 2:
if (obj.type->traits.numeric.scalar.signedness) {
os << "signed ";
} else {
os << "unsigned ";
}
os << obj.type->traits.numeric.scalar.width << " bit integer\n";
os << t << "default : ";
// let's assume only 32 bit and 64 bit types (no 8 and 16 bit types here)
if (obj.type->traits.numeric.scalar.width == 32) {
if (obj.type->traits.numeric.scalar.signedness) {
os << obj.default_value.value.sint32_value;
} else {
os << obj.default_value.value.uint32_bool_value;
}
} else if (obj.type->traits.numeric.scalar.width == 64) {
if (obj.type->traits.numeric.scalar.signedness) {
os << obj.default_value.value.sint64_value;
} else {
os << obj.default_value.value.uint64_value;
}
} else {
os << "default value not native in c/cpp";
}
break;
case 3:
os << obj.type->traits.numeric.scalar.width << " bit floating point\n";
os << t << "default : ";
if (obj.type->traits.numeric.scalar.width == 32) {
os << obj.default_value.value.float32_value;
} else if (obj.type->traits.numeric.scalar.width == 64) {
os << obj.default_value.value.float64_value;
} else {
os << "default value not native in c/cpp";
}
break;
default:
os << "unknown type";
}
}

void StreamWriteEntryPoint(std::ostream& os, SpvReflectEvaluation* p_eval, const SpvReflectEntryPoint& obj, int entry_flag, const char* indent)
{
os << indent << "entry point : " << obj.name;
os << " (stage=" << ToStringShaderStage(obj.shader_stage) << ")";
if (obj.shader_stage == SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT) {
os << "\n";
os << "local size : "
<< "(" << obj.local_size.x << ", " << obj.local_size.y << ", "
<< obj.local_size.z << ")";
if (entry_flag & 2) {
os << "local size hint : ";
}
else {
os << "local size : ";
}
if (entry_flag & 4) {
const SpvReflectValue* val;
SpvReflectResult res = spvReflectEvaluateResult(p_eval, obj.local_size.x, &val);
if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_VECTOR))
&& (val->type->traits.numeric.scalar.width == 32)) {
os << "(" << val->data.numeric.vector.value[0].value.uint32_bool_value << ", "
<< val->data.numeric.vector.value[1].value.uint32_bool_value << ", "
<< val->data.numeric.vector.value[2].value.uint32_bool_value << ")";
}
else {
os << "(failed evaluation of WorkGroupSize Builtin)";
}
}
else if(entry_flag & 1) {
os << "(";
const SpvReflectValue* val;
SpvReflectResult res = spvReflectEvaluateResult(p_eval, obj.local_size.x, &val);
if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) {
os << val->data.numeric.scalar.value.uint32_bool_value;
}
else {
os << "unknown";
}
os << ", ";
res = spvReflectEvaluateResult(p_eval, obj.local_size.y, &val);
if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) {
os << val->data.numeric.scalar.value.uint32_bool_value;
}
else {
os << "unknown";
} os << ", ";
res = spvReflectEvaluateResult(p_eval, obj.local_size.z, &val);
if ((res == SPV_REFLECT_RESULT_SUCCESS) && val->type && (val->type->type_flags == SPV_REFLECT_TYPE_FLAG_INT) && (val->type->traits.numeric.scalar.width == 32)) {
os << val->data.numeric.vector.value[2].value.uint32_bool_value;
}
else {
os << "unknown";
}
os << ")";
}
else{
os << "(" << obj.local_size.x << ", " << obj.local_size.y << ", " << obj.local_size.z << ")";
}
}
}

void StreamWriteShaderModule(std::ostream& os,
const SpvReflectShaderModule& obj,
const char* indent) {
void StreamWriteShaderModule(std::ostream& os, const SpvReflectShaderModule& obj, SpvReflectEvaluation* p_eval,const char* indent)
{
(void)indent;
os << "generator : " << ToStringGenerator(obj.generator) << "\n";
os << "source lang : " << spvReflectSourceLanguage(obj.source_language)
Expand All @@ -1438,7 +1564,8 @@ void StreamWriteShaderModule(std::ostream& os,
// "\n";

for (uint32_t i = 0; i < obj.entry_point_count; ++i) {
StreamWriteEntryPoint(os, obj.entry_points[i], "");
int mode_flag = spvReflectGetEntryModeFlag(&obj, &obj.entry_points[i]);
StreamWriteEntryPoint(os, p_eval, obj.entry_points[i], mode_flag,"");
if (i < (obj.entry_point_count - 1)) {
os << "\n";
}
Expand All @@ -1458,16 +1585,41 @@ void WriteReflection(const spv_reflect::ShaderModule& obj,
const char* tt = " ";
const char* ttt = " ";

StreamWriteShaderModule(os, obj.GetShaderModule(), "");
const SpvReflectShaderModule& ref_module = obj.GetShaderModule();
SpvReflectEvaluation* p_evaluator = spvReflectGetEvaluationInterface(&ref_module);
StreamWriteShaderModule(os, ref_module, p_evaluator, "");

uint32_t count = 0;
std::vector<SpvReflectInterfaceVariable*> variables;
std::vector<SpvReflectDescriptorBinding*> bindings;
std::vector<SpvReflectDescriptorSet*> sets;
std::vector<SpvReflectBlockVariable*> push_constant_bocks;
std::vector<SpvReflectSpecializationConstant*> specialization_constants;

count = 0;
SpvReflectResult result = obj.EnumerateSpecializationConstants(&count, nullptr);
USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
specialization_constants.resize(count);
result = obj.EnumerateSpecializationConstants(&count, specialization_constants.data());
USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
if (count > 0) {
os << "\n";
os << "\n";
os << "\n";
os << t << "Sepecialization constants: " << count << "\n\n";
for (size_t i = 0; i < specialization_constants.size(); ++i) {
auto p_var = specialization_constants[i];
USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
os << tt << i << ":" << "\n";
StreamWriteSpecializationConstant(os, *p_var, ttt);
if (i < (count - 1)) {
os << "\n";
}
}
}

count = 0;
SpvReflectResult result = obj.EnumerateInputVariables(&count, nullptr);
result = obj.EnumerateInputVariables(&count, nullptr);
USE_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
variables.resize(count);
result = obj.EnumerateInputVariables(&count, variables.data());
Expand Down Expand Up @@ -1527,7 +1679,8 @@ void WriteReflection(const spv_reflect::ShaderModule& obj,
auto p_block = push_constant_bocks[i];
os << tt << i << ":"
<< "\n";
StreamWritePushConstantsBlock(os, *p_block, flatten_cbuffers, ttt);
StreamWritePushConstantsBlock(os, *p_block, p_evaluator,
flatten_cbuffers, ttt);
}
}

Expand Down Expand Up @@ -1556,7 +1709,8 @@ void WriteReflection(const spv_reflect::ShaderModule& obj,
os << tt << "Binding"
<< " " << p_binding->set << "." << p_binding->binding << ""
<< "\n";
StreamWriteDescriptorBinding(os, *p_binding, true, flatten_cbuffers, ttt);
StreamWriteDescriptorBinding(os, *p_binding, p_evaluator,
true, flatten_cbuffers, ttt);
if (i < (count - 1)) {
os << "\n\n";
}
Expand Down
2 changes: 1 addition & 1 deletion main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ int main(int argn, char** argv) {
std::vector<char> spv_data(size);
spv_ifstream.read(spv_data.data(), size);

spv_reflect::ShaderModule reflection(spv_data.size(), spv_data.data());
spv_reflect::ShaderModule reflection(spv_data.size(), spv_data.data(), SPV_REFLECT_MODULE_FLAG_EVALUATE_CONSTANT);
if (reflection.GetResult() != SPV_REFLECT_RESULT_SUCCESS) {
std::cerr << "ERROR: could not process '" << input_spv_path
<< "' (is it a valid SPIR-V bytecode?)" << std::endl;
Expand Down
Loading