mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-15 17:45:58 +00:00
Implement using spvc in ExtractSpirvInfo
BUG=dawn:291 Change-Id: I6c12c1874afb9b2c60e326f5c80230fba5fa748c Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/15000 Commit-Queue: Ryan Harrison <rharrison@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
e5cb8f2eff
commit
cd170a5c72
@ -66,6 +66,75 @@ namespace dawn_native {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wgpu::TextureViewDimension ToWGPUTextureViewDimension(
|
||||||
|
shaderc_spvc_texture_view_dimension dim) {
|
||||||
|
switch (dim) {
|
||||||
|
case shaderc_spvc_texture_view_dimension_undefined:
|
||||||
|
return wgpu::TextureViewDimension::Undefined;
|
||||||
|
case shaderc_spvc_texture_view_dimension_e1D:
|
||||||
|
return wgpu::TextureViewDimension::e1D;
|
||||||
|
case shaderc_spvc_texture_view_dimension_e2D:
|
||||||
|
return wgpu::TextureViewDimension::e2D;
|
||||||
|
case shaderc_spvc_texture_view_dimension_e2D_array:
|
||||||
|
return wgpu::TextureViewDimension::e2DArray;
|
||||||
|
case shaderc_spvc_texture_view_dimension_cube:
|
||||||
|
return wgpu::TextureViewDimension::Cube;
|
||||||
|
case shaderc_spvc_texture_view_dimension_cube_array:
|
||||||
|
return wgpu::TextureViewDimension::CubeArray;
|
||||||
|
case shaderc_spvc_texture_view_dimension_e3D:
|
||||||
|
return wgpu::TextureViewDimension::e3D;
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
Format::Type ToDawnFormatType(shaderc_spvc_texture_format_type type) {
|
||||||
|
switch (type) {
|
||||||
|
case shaderc_spvc_texture_format_type_float:
|
||||||
|
return Format::Type::Float;
|
||||||
|
case shaderc_spvc_texture_format_type_sint:
|
||||||
|
return Format::Type::Sint;
|
||||||
|
case shaderc_spvc_texture_format_type_uint:
|
||||||
|
return Format::Type::Uint;
|
||||||
|
case shaderc_spvc_texture_format_type_other:
|
||||||
|
return Format::Type::Other;
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::BindingType ToWGPUBindingType(shaderc_spvc_binding_type type) {
|
||||||
|
switch (type) {
|
||||||
|
case shaderc_spvc_binding_type_uniform_buffer:
|
||||||
|
return wgpu::BindingType::UniformBuffer;
|
||||||
|
case shaderc_spvc_binding_type_storage_buffer:
|
||||||
|
return wgpu::BindingType::StorageBuffer;
|
||||||
|
case shaderc_spvc_binding_type_readonly_storage_buffer:
|
||||||
|
return wgpu::BindingType::ReadonlyStorageBuffer;
|
||||||
|
case shaderc_spvc_binding_type_sampler:
|
||||||
|
return wgpu::BindingType::Sampler;
|
||||||
|
case shaderc_spvc_binding_type_sampled_texture:
|
||||||
|
return wgpu::BindingType::SampledTexture;
|
||||||
|
case shaderc_spvc_binding_type_storage_texture:
|
||||||
|
return wgpu::BindingType::StorageTexture;
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(rharrison): Convert this to ResultOrError once ExtractSPIRVInfo turns an error
|
||||||
|
SingleShaderStage ToSingleShaderStage(shaderc_spvc_execution_model execution_model) {
|
||||||
|
switch (execution_model) {
|
||||||
|
case shaderc_spvc_execution_model_vertex:
|
||||||
|
return SingleShaderStage::Vertex;
|
||||||
|
case shaderc_spvc_execution_model_fragment:
|
||||||
|
return SingleShaderStage::Fragment;
|
||||||
|
case shaderc_spvc_execution_model_glcompute:
|
||||||
|
return SingleShaderStage::Compute;
|
||||||
|
default:
|
||||||
|
// This will be converted to an error return when the whole
|
||||||
|
// calling stack is changed to passing errors.
|
||||||
|
UNREACHABLE();
|
||||||
|
return SingleShaderStage::Vertex;
|
||||||
|
}
|
||||||
|
}
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
MaybeError ValidateShaderModuleDescriptor(DeviceBase*,
|
MaybeError ValidateShaderModuleDescriptor(DeviceBase*,
|
||||||
@ -131,8 +200,159 @@ namespace dawn_native {
|
|||||||
|
|
||||||
void ShaderModuleBase::ExtractSpirvInfo(const spirv_cross::Compiler& compiler) {
|
void ShaderModuleBase::ExtractSpirvInfo(const spirv_cross::Compiler& compiler) {
|
||||||
ASSERT(!IsError());
|
ASSERT(!IsError());
|
||||||
|
if (GetDevice()->IsToggleEnabled(Toggle::UseSpvc)) {
|
||||||
|
ExtractSpirvInfoWithSpvc(compiler);
|
||||||
|
} else {
|
||||||
|
ExtractSpirvInfoWithSpirvCross(compiler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DeviceBase* device = GetDevice();
|
void ShaderModuleBase::ExtractSpirvInfoWithSpvc(const spirv_cross::Compiler& compiler) {
|
||||||
|
shaderc_spvc_execution_model execution_model;
|
||||||
|
if (!CheckSpvcSuccess(mSpvcContext.GetExecutionModel(&execution_model),
|
||||||
|
"Unable to get execution model for shader.")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mExecutionModel = ToSingleShaderStage(execution_model);
|
||||||
|
|
||||||
|
size_t push_constant_buffers_count;
|
||||||
|
if (!CheckSpvcSuccess(mSpvcContext.GetPushConstantBufferCount(&push_constant_buffers_count),
|
||||||
|
"Unable to get push constant buffer count for shader.")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(rharrison): This should be handled by spirv-val pass in spvc,
|
||||||
|
// but need to confirm.
|
||||||
|
if (push_constant_buffers_count > 0) {
|
||||||
|
GetDevice()->HandleError(wgpu::ErrorType::Validation,
|
||||||
|
"Push constants aren't supported.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in bindingInfo with the SPIRV bindings
|
||||||
|
auto ExtractResourcesBinding = [this](std::vector<shaderc_spvc_binding_info> bindings) {
|
||||||
|
for (const auto& binding : bindings) {
|
||||||
|
if (binding.binding >= kMaxBindingsPerGroup || binding.set >= kMaxBindGroups) {
|
||||||
|
GetDevice()->HandleError(wgpu::ErrorType::Validation,
|
||||||
|
"Binding over limits in the SPIRV");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BindingInfo* info = &mBindingInfo[binding.set][binding.binding];
|
||||||
|
*info = {};
|
||||||
|
info->used = true;
|
||||||
|
info->id = binding.id;
|
||||||
|
info->base_type_id = binding.base_type_id;
|
||||||
|
if (binding.binding_type == shaderc_spvc_binding_type_sampled_texture) {
|
||||||
|
info->multisampled = binding.multisampled;
|
||||||
|
info->textureDimension = ToWGPUTextureViewDimension(binding.texture_dimension);
|
||||||
|
info->textureComponentType = ToDawnFormatType(binding.texture_component_type);
|
||||||
|
}
|
||||||
|
info->type = ToWGPUBindingType(binding.binding_type);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<shaderc_spvc_binding_info> resource_bindings;
|
||||||
|
if (!CheckSpvcSuccess(mSpvcContext.GetBindingInfo(
|
||||||
|
shaderc_spvc_shader_resource_uniform_buffers,
|
||||||
|
shaderc_spvc_binding_type_uniform_buffer, &resource_bindings),
|
||||||
|
"Unable to get binding info for uniform buffers from shader")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ExtractResourcesBinding(resource_bindings);
|
||||||
|
|
||||||
|
if (!CheckSpvcSuccess(mSpvcContext.GetBindingInfo(
|
||||||
|
shaderc_spvc_shader_resource_separate_images,
|
||||||
|
shaderc_spvc_binding_type_sampled_texture, &resource_bindings),
|
||||||
|
"Unable to get binding info for sampled textures from shader")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ExtractResourcesBinding(resource_bindings);
|
||||||
|
|
||||||
|
if (!CheckSpvcSuccess(
|
||||||
|
mSpvcContext.GetBindingInfo(shaderc_spvc_shader_resource_separate_samplers,
|
||||||
|
shaderc_spvc_binding_type_sampler, &resource_bindings),
|
||||||
|
"Unable to get binding info for samples from shader")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ExtractResourcesBinding(resource_bindings);
|
||||||
|
|
||||||
|
if (!CheckSpvcSuccess(mSpvcContext.GetBindingInfo(
|
||||||
|
shaderc_spvc_shader_resource_storage_buffers,
|
||||||
|
shaderc_spvc_binding_type_storage_buffer, &resource_bindings),
|
||||||
|
"Unable to get binding info for storage buffers from shader")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ExtractResourcesBinding(resource_bindings);
|
||||||
|
|
||||||
|
std::vector<shaderc_spvc_resource_location_info> input_stage_locations;
|
||||||
|
if (!CheckSpvcSuccess(mSpvcContext.GetInputStageLocationInfo(&input_stage_locations),
|
||||||
|
"Unable to get input stage location information from shader")) {
|
||||||
|
input_stage_locations.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& input : input_stage_locations) {
|
||||||
|
if (mExecutionModel == SingleShaderStage::Vertex) {
|
||||||
|
if (input.location >= kMaxVertexAttributes) {
|
||||||
|
GetDevice()->HandleError(wgpu::ErrorType::Validation,
|
||||||
|
"Attribute location over limits in the SPIRV");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mUsedVertexAttributes.set(input.location);
|
||||||
|
} else if (mExecutionModel == SingleShaderStage::Fragment) {
|
||||||
|
// Without a location qualifier on vertex inputs, spirv_cross::CompilerMSL gives
|
||||||
|
// them all the location 0, causing a compile error.
|
||||||
|
if (!input.has_location) {
|
||||||
|
GetDevice()->HandleError(wgpu::ErrorType::Validation,
|
||||||
|
"Need location qualifier on fragment input");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<shaderc_spvc_resource_location_info> output_stage_locations;
|
||||||
|
if (!CheckSpvcSuccess(mSpvcContext.GetOutputStageLocationInfo(&output_stage_locations),
|
||||||
|
"Unable to get output stage location information from shader")) {
|
||||||
|
output_stage_locations.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& output : output_stage_locations) {
|
||||||
|
if (mExecutionModel == SingleShaderStage::Vertex) {
|
||||||
|
// Without a location qualifier on vertex outputs, spirv_cross::CompilerMSL
|
||||||
|
// gives them all the location 0, causing a compile error.
|
||||||
|
if (!output.has_location) {
|
||||||
|
GetDevice()->HandleError(wgpu::ErrorType::Validation,
|
||||||
|
"Need location qualifier on vertex output");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (mExecutionModel == SingleShaderStage::Fragment) {
|
||||||
|
if (output.location >= kMaxColorAttachments) {
|
||||||
|
GetDevice()->HandleError(wgpu::ErrorType::Validation,
|
||||||
|
"Fragment output location over limits in the SPIRV");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mExecutionModel == SingleShaderStage::Fragment) {
|
||||||
|
std::vector<shaderc_spvc_resource_type_info> output_types;
|
||||||
|
if (!CheckSpvcSuccess(mSpvcContext.GetOutputStageTypeInfo(&output_types),
|
||||||
|
"Unable to get output stage type information from shader")) {
|
||||||
|
output_stage_locations.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& output : output_types) {
|
||||||
|
ASSERT(output.type != shaderc_spvc_texture_format_type_other);
|
||||||
|
mFragmentOutputFormatBaseTypes[output.location] = ToDawnFormatType(output.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderModuleBase::ExtractSpirvInfoWithSpirvCross(const spirv_cross::Compiler& compiler) {
|
||||||
// TODO(cwallez@chromium.org): make errors here creation errors
|
// TODO(cwallez@chromium.org): make errors here creation errors
|
||||||
// currently errors here do not prevent the shadermodule from being used
|
// currently errors here do not prevent the shadermodule from being used
|
||||||
const auto& resources = compiler.get_shader_resources();
|
const auto& resources = compiler.get_shader_resources();
|
||||||
@ -157,17 +377,17 @@ namespace dawn_native {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fill in bindingInfo with the SPIRV bindings
|
// Fill in bindingInfo with the SPIRV bindings
|
||||||
auto ExtractResourcesBinding = [this](const spirv_cross::SmallVector<spirv_cross::Resource>&
|
auto ExtractResourcesBinding =
|
||||||
resources,
|
[this](const spirv_cross::SmallVector<spirv_cross::Resource>& resources,
|
||||||
const spirv_cross::Compiler& compiler,
|
const spirv_cross::Compiler& compiler, wgpu::BindingType bindingType) {
|
||||||
wgpu::BindingType bindingType) {
|
|
||||||
for (const auto& resource : resources) {
|
for (const auto& resource : resources) {
|
||||||
ASSERT(compiler.get_decoration_bitset(resource.id).get(spv::DecorationBinding));
|
ASSERT(compiler.get_decoration_bitset(resource.id).get(spv::DecorationBinding));
|
||||||
ASSERT(
|
ASSERT(compiler.get_decoration_bitset(resource.id)
|
||||||
compiler.get_decoration_bitset(resource.id).get(spv::DecorationDescriptorSet));
|
.get(spv::DecorationDescriptorSet));
|
||||||
|
|
||||||
uint32_t binding = compiler.get_decoration(resource.id, spv::DecorationBinding);
|
uint32_t binding = compiler.get_decoration(resource.id, spv::DecorationBinding);
|
||||||
uint32_t set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
|
uint32_t set =
|
||||||
|
compiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
|
||||||
|
|
||||||
if (binding >= kMaxBindingsPerGroup || set >= kMaxBindGroups) {
|
if (binding >= kMaxBindingsPerGroup || set >= kMaxBindGroups) {
|
||||||
GetDevice()->HandleError(wgpu::ErrorType::Validation,
|
GetDevice()->HandleError(wgpu::ErrorType::Validation,
|
||||||
@ -195,9 +415,10 @@ namespace dawn_native {
|
|||||||
info->type = bindingType;
|
info->type = bindingType;
|
||||||
} break;
|
} break;
|
||||||
case wgpu::BindingType::StorageBuffer: {
|
case wgpu::BindingType::StorageBuffer: {
|
||||||
// Differentiate between readonly storage bindings and writable ones based
|
// Differentiate between readonly storage bindings and writable ones
|
||||||
// on the NonWritable decoration
|
// based on the NonWritable decoration
|
||||||
spirv_cross::Bitset flags = compiler.get_buffer_block_flags(resource.id);
|
spirv_cross::Bitset flags =
|
||||||
|
compiler.get_buffer_block_flags(resource.id);
|
||||||
if (flags.get(spv::DecorationNonWritable)) {
|
if (flags.get(spv::DecorationNonWritable)) {
|
||||||
info->type = wgpu::BindingType::ReadonlyStorageBuffer;
|
info->type = wgpu::BindingType::ReadonlyStorageBuffer;
|
||||||
} else {
|
} else {
|
||||||
@ -225,7 +446,7 @@ namespace dawn_native {
|
|||||||
uint32_t location = compiler.get_decoration(attrib.id, spv::DecorationLocation);
|
uint32_t location = compiler.get_decoration(attrib.id, spv::DecorationLocation);
|
||||||
|
|
||||||
if (location >= kMaxVertexAttributes) {
|
if (location >= kMaxVertexAttributes) {
|
||||||
device->HandleError(wgpu::ErrorType::Validation,
|
GetDevice()->HandleError(wgpu::ErrorType::Validation,
|
||||||
"Attribute location over limits in the SPIRV");
|
"Attribute location over limits in the SPIRV");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -233,11 +454,11 @@ namespace dawn_native {
|
|||||||
mUsedVertexAttributes.set(location);
|
mUsedVertexAttributes.set(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Without a location qualifier on vertex outputs, spirv_cross::CompilerMSL gives them
|
// Without a location qualifier on vertex outputs, spirv_cross::CompilerMSL gives
|
||||||
// all the location 0, causing a compile error.
|
// them all the location 0, causing a compile error.
|
||||||
for (const auto& attrib : resources.stage_outputs) {
|
for (const auto& attrib : resources.stage_outputs) {
|
||||||
if (!compiler.get_decoration_bitset(attrib.id).get(spv::DecorationLocation)) {
|
if (!compiler.get_decoration_bitset(attrib.id).get(spv::DecorationLocation)) {
|
||||||
device->HandleError(wgpu::ErrorType::Validation,
|
GetDevice()->HandleError(wgpu::ErrorType::Validation,
|
||||||
"Need location qualifier on vertex output");
|
"Need location qualifier on vertex output");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -245,11 +466,11 @@ namespace dawn_native {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mExecutionModel == SingleShaderStage::Fragment) {
|
if (mExecutionModel == SingleShaderStage::Fragment) {
|
||||||
// Without a location qualifier on vertex inputs, spirv_cross::CompilerMSL gives them
|
// Without a location qualifier on vertex inputs, spirv_cross::CompilerMSL gives
|
||||||
// all the location 0, causing a compile error.
|
// them all the location 0, causing a compile error.
|
||||||
for (const auto& attrib : resources.stage_inputs) {
|
for (const auto& attrib : resources.stage_inputs) {
|
||||||
if (!compiler.get_decoration_bitset(attrib.id).get(spv::DecorationLocation)) {
|
if (!compiler.get_decoration_bitset(attrib.id).get(spv::DecorationLocation)) {
|
||||||
device->HandleError(wgpu::ErrorType::Validation,
|
GetDevice()->HandleError(wgpu::ErrorType::Validation,
|
||||||
"Need location qualifier on fragment input");
|
"Need location qualifier on fragment input");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -261,7 +482,7 @@ namespace dawn_native {
|
|||||||
uint32_t location =
|
uint32_t location =
|
||||||
compiler.get_decoration(fragmentOutput.id, spv::DecorationLocation);
|
compiler.get_decoration(fragmentOutput.id, spv::DecorationLocation);
|
||||||
if (location >= kMaxColorAttachments) {
|
if (location >= kMaxColorAttachments) {
|
||||||
device->HandleError(wgpu::ErrorType::Validation,
|
GetDevice()->HandleError(wgpu::ErrorType::Validation,
|
||||||
"Fragment output location over limits in the SPIRV");
|
"Fragment output location over limits in the SPIRV");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -379,4 +600,12 @@ namespace dawn_native {
|
|||||||
return a->mCode == b->mCode;
|
return a->mCode == b->mCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ShaderModuleBase::CheckSpvcSuccess(shaderc_spvc_status status, const char* error_msg) {
|
||||||
|
if (status != shaderc_spvc_status_success) {
|
||||||
|
GetDevice()->HandleError(wgpu::ErrorType::Validation, error_msg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
@ -89,6 +89,13 @@ namespace dawn_native {
|
|||||||
|
|
||||||
bool IsCompatibleWithBindGroupLayout(size_t group, const BindGroupLayoutBase* layout) const;
|
bool IsCompatibleWithBindGroupLayout(size_t group, const BindGroupLayoutBase* layout) const;
|
||||||
|
|
||||||
|
// Different implementations reflection into the shader depending on
|
||||||
|
// whether using spvc, or directly accessing spirv-cross.
|
||||||
|
void ExtractSpirvInfoWithSpvc(const spirv_cross::Compiler& compiler);
|
||||||
|
void ExtractSpirvInfoWithSpirvCross(const spirv_cross::Compiler& compiler);
|
||||||
|
|
||||||
|
bool CheckSpvcSuccess(shaderc_spvc_status status, const char* error_msg);
|
||||||
|
|
||||||
// TODO(cwallez@chromium.org): The code is only stored for deduplication. We could maybe
|
// TODO(cwallez@chromium.org): The code is only stored for deduplication. We could maybe
|
||||||
// store a cryptographic hash of the code instead?
|
// store a cryptographic hash of the code instead?
|
||||||
std::vector<uint32_t> mCode;
|
std::vector<uint32_t> mCode;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user