Replaced GLSLang reflection by SPIRV-Reflect, eventually allowing to move GLSLang out.

This commit is contained in:
Juan Linietsky 2019-07-28 13:42:15 -03:00
parent 0586e18449
commit 60c7498cee
7 changed files with 7828 additions and 10 deletions

View File

@ -33,6 +33,7 @@ else:
# Core dependencies # Core dependencies
SConscript("png/SCsub") SConscript("png/SCsub")
SConscript("spirv-reflect/SCsub")
if env['vsproj']: if env['vsproj']:
import os import os

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python
Import('env')
env_spirv_reflect = env.Clone()
thirdparty_dir = "#thirdparty/spirv-reflect/"
thirdparty_sources = [
"spirv_reflect.c"
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_spirv_reflect.add_source_files(env.drivers_sources, thirdparty_sources)
Export('env')

View File

@ -1,10 +1,11 @@
#include "rendering_device_vulkan.h" #include "rendering_device_vulkan.h"
#include "drivers/vulkan/vulkan_context.h"
#include "core/hashfuncs.h" #include "core/hashfuncs.h"
#include "core/os/file_access.h"
#include "core/project_settings.h" #include "core/project_settings.h"
#include "drivers/vulkan/vulkan_context.h"
#include "thirdparty/glslang/SPIRV/GlslangToSpv.h" #include "thirdparty/glslang/SPIRV/GlslangToSpv.h"
#include "thirdparty/glslang/glslang/Include/Types.h" #include "thirdparty/glslang/glslang/Include/Types.h"
#include "thirdparty/spirv-reflect/spirv_reflect.h"
void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) { void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) {
@ -2371,7 +2372,6 @@ PoolVector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3
image_copy_region.extent.depth = mm_depth; image_copy_region.extent.depth = mm_depth;
vkCmdCopyImage(command_buffer, tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region); vkCmdCopyImage(command_buffer, tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region);
print_line("copying mipmap " + itos(i) + " w: " + itos(mm_width) + " h " + itos(mm_height) + " d " + itos(mm_depth));
} }
} }
@ -3568,7 +3568,7 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
glslang::TShader::ForbidIncluder includer; glslang::TShader::ForbidIncluder includer;
//descriptor layouts //descriptor layouts
Vector<Vector<VkDescriptorSetLayoutBinding> > bindings; Vector<Vector<VkDescriptorSetLayoutBinding> > set_bindings;
Vector<Vector<UniformInfo> > uniform_info; Vector<Vector<UniformInfo> > uniform_info;
Shader::PushConstant push_constant; Shader::PushConstant push_constant;
push_constant.push_constant_size = 0; push_constant.push_constant_size = 0;
@ -3652,11 +3652,27 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
return RID(); return RID();
} }
#if 0
//obtain bindings for descriptor layout //obtain bindings for descriptor layout
program.mapIO(); program.mapIO();
program.buildReflection(EShReflectionAllBlockVariables); program.buildReflection(EShReflectionAllBlockVariables);
//program.dumpReflection(); //program.dumpReflection();
for (int j = 0; j < program.getNumUniformBlocks(); j++) {
const glslang::TObjectReflection &reflection = program.getUniformBlock(j);
if (reflection.getType()->getBasicType() == glslang::EbtBlock && reflection.getType()->getQualifier().storage == glslang::EvqUniform && reflection.getType()->getQualifier().layoutPushConstant) {
uint32_t len = reflection.size;
if (push_constant_debug.push_constant_size != 0 && push_constant_debug.push_constant_size != len) {
print_line("eep");
}
push_constant_debug.push_constant_size = len;
push_constant_debug.push_constants_vk_stage |= shader_stage_masks[p_stages[i].shader_stage];
//print_line("Debug stage " + String(shader_stage_names[p_stages[i].shader_stage]) + " push constant size: " + itos(push_constant_debug.push_constant_size));
}
}
for (int j = 0; j < program.getNumUniformVariables(); j++) { for (int j = 0; j < program.getNumUniformVariables(); j++) {
if (!_uniform_add_binding(bindings, uniform_info, program.getUniform(j), p_stages[i].shader_stage, push_constant, r_error)) { if (!_uniform_add_binding(bindings, uniform_info, program.getUniform(j), p_stages[i].shader_stage, push_constant, r_error)) {
return RID(); return RID();
@ -3698,11 +3714,233 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
fragment_outputs = program.getNumPipeOutputs(); fragment_outputs = program.getNumPipeOutputs();
} }
#endif
std::vector<uint32_t> SpirV; std::vector<uint32_t> SpirV;
spv::SpvBuildLogger logger; spv::SpvBuildLogger logger;
glslang::SpvOptions spvOptions; glslang::SpvOptions spvOptions;
glslang::GlslangToSpv(*program.getIntermediate(stages[p_stages[i].shader_stage]), SpirV, &logger, &spvOptions); glslang::GlslangToSpv(*program.getIntermediate(stages[p_stages[i].shader_stage]), SpirV, &logger, &spvOptions);
{
SpvReflectShaderModule module;
SpvReflectResult result = spvReflectCreateShaderModule(SpirV.size() * sizeof(uint32_t), &SpirV[0], &module);
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed parsing shader.");
uint32_t binding_count = 0;
result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, NULL);
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating descriptor bindings.");
uint32_t stage = p_stages[i].shader_stage;
if (binding_count > 0) {
//Parse bindings
Vector<SpvReflectDescriptorBinding *> bindings;
bindings.resize(binding_count);
result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, bindings.ptrw());
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed getting descriptor bindings.");
for (uint32_t j = 0; j < binding_count; j++) {
const SpvReflectDescriptorBinding &binding = *bindings[j];
VkDescriptorSetLayoutBinding layout_binding;
UniformInfo info;
bool need_array_dimensions = false;
bool need_block_size = false;
switch (binding.descriptor_type) {
case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER: {
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
info.type = UNIFORM_TYPE_SAMPLER;
need_array_dimensions = true;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
need_array_dimensions = true;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE: {
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
info.type = UNIFORM_TYPE_TEXTURE;
need_array_dimensions = true;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
info.type = UNIFORM_TYPE_IMAGE;
need_array_dimensions = true;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: {
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
info.type = UNIFORM_TYPE_TEXTURE_BUFFER;
need_array_dimensions = true;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
info.type = UNIFORM_TYPE_IMAGE_BUFFER;
need_array_dimensions = true;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
info.type = UNIFORM_TYPE_UNIFORM_BUFFER;
need_block_size = true;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
info.type = UNIFORM_TYPE_STORAGE_BUFFER;
need_block_size = true;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: {
ERR_PRINT("Dynamic uniform buffer not supported.");
continue;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
ERR_PRINT("Dynamic storage buffer not supported.");
continue;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
info.type = UNIFORM_TYPE_INPUT_ATTACHMENT;
} break;
}
if (need_array_dimensions) {
if (binding.array.dims_count == 0) {
info.length = 1;
} else {
for (uint32_t k = 0; k < binding.array.dims_count; k++) {
if (k == 0) {
info.length = binding.array.dims[0];
} else {
info.length *= binding.array.dims[k];
}
}
}
layout_binding.descriptorCount = info.length;
} else if (need_block_size) {
info.length = binding.block.size;
layout_binding.descriptorCount = 1;
} else {
info.length = 0;
layout_binding.descriptorCount = 1;
}
info.binding = binding.binding;
uint32_t set = binding.set;
//print_line("Stage: " + String(shader_stage_names[stage]) + " set=" + itos(set) + " binding=" + itos(info.binding) + " type=" + shader_uniform_names[info.type] + " length=" + itos(info.length));
ERR_FAIL_COND_V_MSG(set >= MAX_UNIFORM_SETS, RID(),
"On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ").");
ERR_FAIL_COND_V_MSG(set >= limits.maxBoundDescriptorSets, RID(),
"On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").");
if (set < (uint32_t)set_bindings.size()) {
//check if this already exists
bool exists = false;
for (int k = 0; k < set_bindings[set].size(); k++) {
if (set_bindings[set][k].binding == (uint32_t)info.binding) {
//already exists, verify that it's the same type
ERR_FAIL_COND_V_MSG(set_bindings[set][k].descriptorType != layout_binding.descriptorType, RID(),
"On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform type.");
//also, verify that it's the same size
ERR_FAIL_COND_V_MSG(set_bindings[set][k].descriptorCount != layout_binding.descriptorCount || uniform_info[set][k].length != info.length, RID(),
"On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform size.");
//just append stage mask and return
set_bindings.write[set].write[k].stageFlags |= shader_stage_masks[stage];
uniform_info.write[set].write[k].stages |= 1 << stage;
exists = true;
}
}
if (exists) {
continue; //merged
}
}
layout_binding.binding = info.binding;
layout_binding.stageFlags = shader_stage_masks[stage];
layout_binding.pImmutableSamplers = NULL; //no support for this yet
info.stages = 1 << stage;
info.binding = info.binding;
if (set >= (uint32_t)set_bindings.size()) {
set_bindings.resize(set + 1);
uniform_info.resize(set + 1);
}
set_bindings.write[set].push_back(layout_binding);
uniform_info.write[set].push_back(info);
}
}
if (stage == SHADER_STAGE_FRAGMENT) {
uint32_t ov_count = 0;
result = spvReflectEnumerateOutputVariables(&module, &ov_count, NULL);
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating output variables.");
if (ov_count) {
Vector<SpvReflectInterfaceVariable *> output_vars;
output_vars.resize(ov_count);
result = spvReflectEnumerateOutputVariables(&module, &ov_count, output_vars.ptrw());
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining output variables.");
for (uint32_t j = 0; j < ov_count; j++) {
if (output_vars[j]) {
fragment_outputs = MAX(fragment_outputs, output_vars[j]->location + 1);
}
}
}
}
uint32_t pc_count = 0;
result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, NULL);
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating push constants.");
if (pc_count) {
ERR_FAIL_COND_V_MSG(pc_count > 1, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "': Only one push constant is supported, which should be the same across shader stages.");
Vector<SpvReflectBlockVariable *> pconstants;
pconstants.resize(pc_count);
result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, pconstants.ptrw());
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining push constants.");
#if 0
if (pconstants[0] == NULL) {
FileAccess *f = FileAccess::open("res://popo.spv", FileAccess::WRITE);
f->store_buffer((const uint8_t *)&SpirV[0], SpirV.size() * sizeof(uint32_t));
memdelete(f);
}
#endif
ERR_FAIL_COND_V_MSG(push_constant.push_constant_size && push_constant.push_constant_size != pconstants[0]->size, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "': Push constant block must be the same across shader stages.");
push_constant.push_constant_size = pconstants[0]->size;
push_constant.push_constants_vk_stage |= shader_stage_masks[stage];
//print_line("Stage: " + String(shader_stage_names[stage]) + " push constant of size=" + itos(push_constant.push_constant_size));
}
// Destroy the reflection data when no longer required.
spvReflectDestroyShaderModule(&module);
}
spirv_code.push_back(SpirV); spirv_code.push_back(SpirV);
stages_processed |= (1 << p_stages[i].shader_stage); stages_processed |= (1 << p_stages[i].shader_stage);
@ -3758,15 +3996,15 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
if (success) { if (success) {
for (int i = 0; i < bindings.size(); i++) { for (int i = 0; i < set_bindings.size(); i++) {
//empty ones are fine if they were not used according to spec (binding count will be 0) //empty ones are fine if they were not used according to spec (binding count will be 0)
VkDescriptorSetLayoutCreateInfo layout_create_info; VkDescriptorSetLayoutCreateInfo layout_create_info;
layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layout_create_info.pNext = NULL; layout_create_info.pNext = NULL;
layout_create_info.flags = 0; layout_create_info.flags = 0;
layout_create_info.bindingCount = bindings[i].size(); layout_create_info.bindingCount = set_bindings[i].size();
layout_create_info.pBindings = bindings[i].ptr(); layout_create_info.pBindings = set_bindings[i].ptr();
VkDescriptorSetLayout layout; VkDescriptorSetLayout layout;
VkResult res = vkCreateDescriptorSetLayout(device, &layout_create_info, NULL, &layout); VkResult res = vkCreateDescriptorSetLayout(device, &layout_create_info, NULL, &layout);
@ -4108,7 +4346,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
const Uniform &uniform = uniforms[uniform_idx]; const Uniform &uniform = uniforms[uniform_idx];
ERR_FAIL_COND_V_MSG(uniform.type != set_uniform.type, RID(), ERR_FAIL_COND_V_MSG(uniform.type != set_uniform.type, RID(),
"Mismatch uniform type for binding (" + itos(set_uniform.binding) + ")."); "Mismatch uniform type for binding (" + itos(set_uniform.binding) + "). Expected '" + shader_uniform_names[set_uniform.type] + "', supplied: '" + shader_uniform_names[uniform.type] + "'.");
VkWriteDescriptorSet write; //common header VkWriteDescriptorSet write; //common header
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
@ -6048,7 +6286,6 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) {
} }
texture_upload_region_size_px = GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64); texture_upload_region_size_px = GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64);
texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px); texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px);
print_line("update size: " + itos(texture_upload_region_size_px));
frames_drawn = frame_count; //start from frame count, so everything else is immediately old frames_drawn = frame_count; //start from frame count, so everything else is immediately old

View File

@ -410,7 +410,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
r_gen_code.uniform_total_size = offset; r_gen_code.uniform_total_size = offset;
print_line("uniform total: " + itos(r_gen_code.uniform_total_size)); print_line("uniform total: " + itos(r_gen_code.uniform_total_size));
if (r_gen_code.uniform_total_size % 16 != 0) { //UBO sizes must be multiples of 16 if (r_gen_code.uniform_total_size % 16 != 0) { //UBO sizes must be multiples of 16
//r_gen_code.uniform_total_size += 16 - (r_gen_code.uniform_total_size % 16); r_gen_code.uniform_total_size += 16 - (r_gen_code.uniform_total_size % 16);
} }
#else #else
// add up // add up

File diff suppressed because it is too large Load Diff

4442
thirdparty/spirv-reflect/spirv_reflect.c vendored Normal file

File diff suppressed because it is too large Load Diff

2045
thirdparty/spirv-reflect/spirv_reflect.h vendored Normal file

File diff suppressed because it is too large Load Diff