From bcbe2e0c940ce9755b51f6d58f99fba64f30eebf Mon Sep 17 00:00:00 2001 From: Stephen White Date: Tue, 10 Aug 2021 22:04:33 +0000 Subject: [PATCH] Move SPIRV-Cross functions into OpenGL backend. Since the other backends no longer need it, move all of the utility functions specific to SPIRV-Cross into the OpenGL backend. This obviates the need for the DAWN_USE_SPIRV_CROSS define, so remove it. Bug: dawn:1036 Change-Id: I67bb5a85dc128a6f343d09876046cf559395e05f Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/61541 Reviewed-by: Austin Eng Commit-Queue: Stephen White --- src/common/BUILD.gn | 4 - src/dawn_native/BUILD.gn | 9 +- src/dawn_native/ShaderModule.cpp | 272 -------------------- src/dawn_native/ShaderModule.h | 5 - src/dawn_native/d3d12/ShaderModuleD3D12.cpp | 1 - src/dawn_native/opengl/ShaderModuleGL.cpp | 262 ++++++++++++++++++- src/dawn_native/opengl/ShaderModuleGL.h | 3 + src/dawn_native/{ => opengl}/SpirvUtils.cpp | 2 +- src/dawn_native/{ => opengl}/SpirvUtils.h | 10 +- 9 files changed, 270 insertions(+), 298 deletions(-) rename src/dawn_native/{ => opengl}/SpirvUtils.cpp (99%) rename src/dawn_native/{ => opengl}/SpirvUtils.h (89%) diff --git a/src/common/BUILD.gn b/src/common/BUILD.gn index ebb7018dc1..afaa18f2d5 100644 --- a/src/common/BUILD.gn +++ b/src/common/BUILD.gn @@ -85,10 +85,6 @@ config("dawn_internal") { defines += [ "DAWN_USE_X11" ] } - if (dawn_use_spirv_cross) { - defines += [ "DAWN_USE_SPIRV_CROSS" ] - } - if (dawn_enable_error_injection) { defines += [ "DAWN_ENABLE_ERROR_INJECTION" ] } diff --git a/src/dawn_native/BUILD.gn b/src/dawn_native/BUILD.gn index 27731a5f84..d44de365f4 100644 --- a/src/dawn_native/BUILD.gn +++ b/src/dawn_native/BUILD.gn @@ -313,13 +313,6 @@ source_set("dawn_native_sources") { ] } - if (dawn_use_spirv_cross) { - sources += [ - "SpirvUtils.cpp", - "SpirvUtils.h", - ] - } - # Only win32 app needs to link with user32.lib # In UWP, all availiable APIs are defined in WindowsApp.lib if (is_win && !dawn_is_winuwp) { @@ -527,6 +520,8 @@ source_set("dawn_native_sources") { "opengl/SamplerGL.h", "opengl/ShaderModuleGL.cpp", "opengl/ShaderModuleGL.h", + "opengl/SpirvUtils.cpp", + "opengl/SpirvUtils.h", "opengl/SwapChainGL.cpp", "opengl/SwapChainGL.h", "opengl/TextureGL.cpp", diff --git a/src/dawn_native/ShaderModule.cpp b/src/dawn_native/ShaderModule.cpp index 87af445dbb..96ae1ec1e8 100644 --- a/src/dawn_native/ShaderModule.cpp +++ b/src/dawn_native/ShaderModule.cpp @@ -24,16 +24,10 @@ #include "dawn_native/Pipeline.h" #include "dawn_native/PipelineLayout.h" #include "dawn_native/RenderPipeline.h" -#if defined(DAWN_USE_SPIRV_CROSS) -# include "dawn_native/SpirvUtils.h" -#endif #include "dawn_native/TintUtils.h" #include #include -#if defined(DAWN_USE_SPIRV_CROSS) -# include -#endif // Tint include must be after spirv_cross.hpp, because spirv-cross has its own // version of spirv_headers. We also need to undef SPV_REVISION because SPIRV-Cross @@ -679,252 +673,6 @@ namespace dawn_native { return {}; } -#if defined(DAWN_USE_SPIRV_CROSS) - ResultOrError> ExtractSpirvInfo( - const DeviceBase* device, - const spirv_cross::Compiler& compiler, - const std::string& entryPointName, - SingleShaderStage stage) { - std::unique_ptr metadata = std::make_unique(); - metadata->stage = stage; - - const auto& resources = compiler.get_shader_resources(); - - if (resources.push_constant_buffers.size() > 0) { - return DAWN_VALIDATION_ERROR("Push constants aren't supported."); - } - - if (resources.sampled_images.size() > 0) { - return DAWN_VALIDATION_ERROR("Combined images and samplers aren't supported."); - } - - // Fill in bindingInfo with the SPIRV bindings - auto ExtractResourcesBinding = - [](const DeviceBase* device, - const spirv_cross::SmallVector& resources, - const spirv_cross::Compiler& compiler, BindingInfoType bindingType, - EntryPointMetadata::BindingInfoArray* metadataBindings, - bool isStorageBuffer = false) -> MaybeError { - for (const auto& resource : resources) { - if (!compiler.get_decoration_bitset(resource.id).get(spv::DecorationBinding)) { - return DAWN_VALIDATION_ERROR("No Binding decoration set for resource"); - } - - if (!compiler.get_decoration_bitset(resource.id) - .get(spv::DecorationDescriptorSet)) { - return DAWN_VALIDATION_ERROR("No Descriptor Decoration set for resource"); - } - - BindingNumber bindingNumber( - compiler.get_decoration(resource.id, spv::DecorationBinding)); - BindGroupIndex bindGroupIndex( - compiler.get_decoration(resource.id, spv::DecorationDescriptorSet)); - - if (bindGroupIndex >= kMaxBindGroupsTyped) { - return DAWN_VALIDATION_ERROR("Bind group index over limits in the SPIRV"); - } - - const auto& it = (*metadataBindings)[bindGroupIndex].emplace( - bindingNumber, EntryPointMetadata::ShaderBindingInfo{}); - if (!it.second) { - return DAWN_VALIDATION_ERROR("Shader has duplicate bindings"); - } - - EntryPointMetadata::ShaderBindingInfo* info = &it.first->second; - info->id = resource.id; - info->base_type_id = resource.base_type_id; - info->bindingType = bindingType; - - switch (bindingType) { - case BindingInfoType::Texture: { - spirv_cross::SPIRType::ImageType imageType = - compiler.get_type(info->base_type_id).image; - spirv_cross::SPIRType::BaseType textureComponentType = - compiler.get_type(imageType.type).basetype; - - info->texture.viewDimension = - SpirvDimToTextureViewDimension(imageType.dim, imageType.arrayed); - info->texture.multisampled = imageType.ms; - info->texture.compatibleSampleTypes = - SpirvBaseTypeToSampleTypeBit(textureComponentType); - - if (imageType.depth) { - if ((info->texture.compatibleSampleTypes & SampleTypeBit::Float) == - 0) { - return DAWN_VALIDATION_ERROR( - "Depth textures must have a float type"); - } - info->texture.compatibleSampleTypes = SampleTypeBit::Depth; - } - - if (imageType.ms && imageType.arrayed) { - return DAWN_VALIDATION_ERROR( - "Multisampled array textures aren't supported"); - } - break; - } - case BindingInfoType::Buffer: { - // Determine buffer size, with a minimum of 1 element in the runtime - // array - spirv_cross::SPIRType type = compiler.get_type(info->base_type_id); - info->buffer.minBindingSize = - compiler.get_declared_struct_size_runtime_array(type, 1); - - // Differentiate between readonly storage bindings and writable ones - // based on the NonWritable decoration. - // TODO(dawn:527): Could isStorageBuffer be determined by calling - // compiler.get_storage_class(resource.id)? - if (isStorageBuffer) { - spirv_cross::Bitset flags = - compiler.get_buffer_block_flags(resource.id); - if (flags.get(spv::DecorationNonWritable)) { - info->buffer.type = wgpu::BufferBindingType::ReadOnlyStorage; - } else { - info->buffer.type = wgpu::BufferBindingType::Storage; - } - } else { - info->buffer.type = wgpu::BufferBindingType::Uniform; - } - break; - } - case BindingInfoType::StorageTexture: { - spirv_cross::Bitset flags = compiler.get_decoration_bitset(resource.id); - if (flags.get(spv::DecorationNonReadable)) { - info->storageTexture.access = wgpu::StorageTextureAccess::WriteOnly; - } else if (flags.get(spv::DecorationNonWritable)) { - info->storageTexture.access = wgpu::StorageTextureAccess::ReadOnly; - } else { - return DAWN_VALIDATION_ERROR( - "Read-write storage textures are not supported"); - } - - spirv_cross::SPIRType::ImageType imageType = - compiler.get_type(info->base_type_id).image; - wgpu::TextureFormat storageTextureFormat = - SpirvImageFormatToTextureFormat(imageType.format); - if (storageTextureFormat == wgpu::TextureFormat::Undefined) { - return DAWN_VALIDATION_ERROR( - "Invalid image format declaration on storage image"); - } - const Format& format = - device->GetValidInternalFormat(storageTextureFormat); - if (!format.supportsStorageUsage) { - return DAWN_VALIDATION_ERROR( - "The storage texture format is not supported"); - } - if (imageType.ms) { - return DAWN_VALIDATION_ERROR( - "Multisampled storage textures aren't supported"); - } - if (imageType.depth) { - return DAWN_VALIDATION_ERROR( - "Depth storage textures aren't supported"); - } - info->storageTexture.format = storageTextureFormat; - info->storageTexture.viewDimension = - SpirvDimToTextureViewDimension(imageType.dim, imageType.arrayed); - break; - } - case BindingInfoType::Sampler: { - info->sampler.isComparison = false; - break; - } - case BindingInfoType::ExternalTexture: { - return DAWN_VALIDATION_ERROR("External textures are not supported."); - } - } - } - return {}; - }; - - DAWN_TRY(ExtractResourcesBinding(device, resources.uniform_buffers, compiler, - BindingInfoType::Buffer, &metadata->bindings)); - DAWN_TRY(ExtractResourcesBinding(device, resources.separate_images, compiler, - BindingInfoType::Texture, &metadata->bindings)); - DAWN_TRY(ExtractResourcesBinding(device, resources.separate_samplers, compiler, - BindingInfoType::Sampler, &metadata->bindings)); - DAWN_TRY(ExtractResourcesBinding(device, resources.storage_buffers, compiler, - BindingInfoType::Buffer, &metadata->bindings, true)); - // ReadonlyStorageTexture is used as a tag to do general storage texture handling. - DAWN_TRY(ExtractResourcesBinding(device, resources.storage_images, compiler, - BindingInfoType::StorageTexture, &metadata->bindings)); - - // Extract the vertex attributes - if (stage == SingleShaderStage::Vertex) { - for (const auto& attrib : resources.stage_inputs) { - if (!(compiler.get_decoration_bitset(attrib.id).get(spv::DecorationLocation))) { - return DAWN_VALIDATION_ERROR( - "Unable to find Location decoration for Vertex input"); - } - uint32_t unsanitizedLocation = - compiler.get_decoration(attrib.id, spv::DecorationLocation); - - if (unsanitizedLocation >= kMaxVertexAttributes) { - return DAWN_VALIDATION_ERROR("Attribute location over limits in the SPIRV"); - } - VertexAttributeLocation location(static_cast(unsanitizedLocation)); - - spirv_cross::SPIRType::BaseType inputBaseType = - compiler.get_type(attrib.base_type_id).basetype; - metadata->vertexInputBaseTypes[location] = - SpirvBaseTypeToVertexFormatBaseType(inputBaseType); - metadata->usedVertexInputs.set(location); - } - - // Without a location qualifier on vertex outputs, spirv_cross::CompilerMSL gives - // them all the location 0, causing a compile error. - for (const auto& attrib : resources.stage_outputs) { - if (!compiler.get_decoration_bitset(attrib.id).get(spv::DecorationLocation)) { - return DAWN_VALIDATION_ERROR("Need location qualifier on vertex output"); - } - } - } - - if (stage == SingleShaderStage::Fragment) { - // Without a location qualifier on vertex inputs, spirv_cross::CompilerMSL gives - // them all the location 0, causing a compile error. - for (const auto& attrib : resources.stage_inputs) { - if (!compiler.get_decoration_bitset(attrib.id).get(spv::DecorationLocation)) { - return DAWN_VALIDATION_ERROR("Need location qualifier on fragment input"); - } - } - - for (const auto& fragmentOutput : resources.stage_outputs) { - if (!compiler.get_decoration_bitset(fragmentOutput.id) - .get(spv::DecorationLocation)) { - return DAWN_VALIDATION_ERROR( - "Unable to find Location decoration for Fragment output"); - } - uint32_t unsanitizedAttachment = - compiler.get_decoration(fragmentOutput.id, spv::DecorationLocation); - - if (unsanitizedAttachment >= kMaxColorAttachments) { - return DAWN_VALIDATION_ERROR( - "Fragment output index must be less than max number of color " - "attachments"); - } - ColorAttachmentIndex attachment(static_cast(unsanitizedAttachment)); - - spirv_cross::SPIRType::BaseType shaderFragmentOutputBaseType = - compiler.get_type(fragmentOutput.base_type_id).basetype; - metadata->fragmentOutputFormatBaseTypes[attachment] = - SpirvBaseTypeToTextureComponentType(shaderFragmentOutputBaseType); - metadata->fragmentOutputsWritten.set(attachment); - } - } - - if (stage == SingleShaderStage::Compute) { - const spirv_cross::SPIREntryPoint& spirEntryPoint = - compiler.get_entry_point(entryPointName, spv::ExecutionModelGLCompute); - metadata->localWorkgroupSize.x = spirEntryPoint.workgroup_size.x; - metadata->localWorkgroupSize.y = spirEntryPoint.workgroup_size.y; - metadata->localWorkgroupSize.z = spirEntryPoint.workgroup_size.z; - } - - return {std::move(metadata)}; - } -#endif - ResultOrError ReflectShaderUsingTint( DeviceBase*, const tint::Program* program) { @@ -1628,26 +1376,6 @@ namespace dawn_native { return {}; } -#if defined(DAWN_USE_SPIRV_CROSS) - ResultOrError ShaderModuleBase::ReflectShaderUsingSPIRVCross( - DeviceBase* device, - const std::vector& spirv) { - EntryPointMetadataTable result; - spirv_cross::Compiler compiler(spirv); - for (const spirv_cross::EntryPoint& entryPoint : compiler.get_entry_points_and_stages()) { - ASSERT(result.count(entryPoint.name) == 0); - - SingleShaderStage stage = ExecutionModelToShaderStage(entryPoint.execution_model); - compiler.set_entry_point(entryPoint.name, entryPoint.execution_model); - - std::unique_ptr metadata; - DAWN_TRY_ASSIGN(metadata, ExtractSpirvInfo(device, compiler, entryPoint.name, stage)); - result[entryPoint.name] = std::move(metadata); - } - return std::move(result); - } -#endif - size_t PipelineLayoutEntryPointPairHashFunc::operator()( const PipelineLayoutEntryPointPair& pair) const { size_t hash = 0; diff --git a/src/dawn_native/ShaderModule.h b/src/dawn_native/ShaderModule.h index 7d92c42b75..3f17ceb27d 100644 --- a/src/dawn_native/ShaderModule.h +++ b/src/dawn_native/ShaderModule.h @@ -240,11 +240,6 @@ namespace dawn_native { protected: MaybeError InitializeBase(ShaderModuleParseResult* parseResult); -#if defined(DAWN_USE_SPIRV_CROSS) - static ResultOrError ReflectShaderUsingSPIRVCross( - DeviceBase* device, - const std::vector& spirv); -#endif private: ShaderModuleBase(DeviceBase* device, ObjectBase::ErrorTag tag); diff --git a/src/dawn_native/d3d12/ShaderModuleD3D12.cpp b/src/dawn_native/d3d12/ShaderModuleD3D12.cpp index 28228a71be..3a598901e5 100644 --- a/src/dawn_native/d3d12/ShaderModuleD3D12.cpp +++ b/src/dawn_native/d3d12/ShaderModuleD3D12.cpp @@ -17,7 +17,6 @@ #include "common/Assert.h" #include "common/BitSetIterator.h" #include "common/Log.h" -#include "dawn_native/SpirvUtils.h" #include "dawn_native/TintUtils.h" #include "dawn_native/d3d12/BindGroupLayoutD3D12.h" #include "dawn_native/d3d12/D3D12Error.h" diff --git a/src/dawn_native/opengl/ShaderModuleGL.cpp b/src/dawn_native/opengl/ShaderModuleGL.cpp index c56d95027d..a5a3dd0251 100644 --- a/src/dawn_native/opengl/ShaderModuleGL.cpp +++ b/src/dawn_native/opengl/ShaderModuleGL.cpp @@ -17,10 +17,10 @@ #include "common/Assert.h" #include "common/Platform.h" #include "dawn_native/BindGroupLayout.h" -#include "dawn_native/SpirvUtils.h" #include "dawn_native/TintUtils.h" #include "dawn_native/opengl/DeviceGL.h" #include "dawn_native/opengl/PipelineLayoutGL.h" +#include "dawn_native/opengl/SpirvUtils.h" #include @@ -64,6 +64,247 @@ namespace dawn_native { namespace opengl { return o.str(); } + ResultOrError> ExtractSpirvInfo( + const DeviceBase* device, + const spirv_cross::Compiler& compiler, + const std::string& entryPointName, + SingleShaderStage stage) { + std::unique_ptr metadata = std::make_unique(); + metadata->stage = stage; + + const auto& resources = compiler.get_shader_resources(); + + if (resources.push_constant_buffers.size() > 0) { + return DAWN_VALIDATION_ERROR("Push constants aren't supported."); + } + + if (resources.sampled_images.size() > 0) { + return DAWN_VALIDATION_ERROR("Combined images and samplers aren't supported."); + } + + // Fill in bindingInfo with the SPIRV bindings + auto ExtractResourcesBinding = + [](const DeviceBase* device, + const spirv_cross::SmallVector& resources, + const spirv_cross::Compiler& compiler, BindingInfoType bindingType, + EntryPointMetadata::BindingInfoArray* metadataBindings, + bool isStorageBuffer = false) -> MaybeError { + for (const auto& resource : resources) { + if (!compiler.get_decoration_bitset(resource.id).get(spv::DecorationBinding)) { + return DAWN_VALIDATION_ERROR("No Binding decoration set for resource"); + } + + if (!compiler.get_decoration_bitset(resource.id) + .get(spv::DecorationDescriptorSet)) { + return DAWN_VALIDATION_ERROR("No Descriptor Decoration set for resource"); + } + + BindingNumber bindingNumber( + compiler.get_decoration(resource.id, spv::DecorationBinding)); + BindGroupIndex bindGroupIndex( + compiler.get_decoration(resource.id, spv::DecorationDescriptorSet)); + + if (bindGroupIndex >= kMaxBindGroupsTyped) { + return DAWN_VALIDATION_ERROR("Bind group index over limits in the SPIRV"); + } + + const auto& it = (*metadataBindings)[bindGroupIndex].emplace( + bindingNumber, EntryPointMetadata::ShaderBindingInfo{}); + if (!it.second) { + return DAWN_VALIDATION_ERROR("Shader has duplicate bindings"); + } + + EntryPointMetadata::ShaderBindingInfo* info = &it.first->second; + info->id = resource.id; + info->base_type_id = resource.base_type_id; + info->bindingType = bindingType; + + switch (bindingType) { + case BindingInfoType::Texture: { + spirv_cross::SPIRType::ImageType imageType = + compiler.get_type(info->base_type_id).image; + spirv_cross::SPIRType::BaseType textureComponentType = + compiler.get_type(imageType.type).basetype; + + info->texture.viewDimension = + SpirvDimToTextureViewDimension(imageType.dim, imageType.arrayed); + info->texture.multisampled = imageType.ms; + info->texture.compatibleSampleTypes = + SpirvBaseTypeToSampleTypeBit(textureComponentType); + + if (imageType.depth) { + if ((info->texture.compatibleSampleTypes & SampleTypeBit::Float) == 0) { + return DAWN_VALIDATION_ERROR( + "Depth textures must have a float type"); + } + info->texture.compatibleSampleTypes = SampleTypeBit::Depth; + } + + if (imageType.ms && imageType.arrayed) { + return DAWN_VALIDATION_ERROR( + "Multisampled array textures aren't supported"); + } + break; + } + case BindingInfoType::Buffer: { + // Determine buffer size, with a minimum of 1 element in the runtime + // array + spirv_cross::SPIRType type = compiler.get_type(info->base_type_id); + info->buffer.minBindingSize = + compiler.get_declared_struct_size_runtime_array(type, 1); + + // Differentiate between readonly storage bindings and writable ones + // based on the NonWritable decoration. + // TODO(dawn:527): Could isStorageBuffer be determined by calling + // compiler.get_storage_class(resource.id)? + if (isStorageBuffer) { + spirv_cross::Bitset flags = + compiler.get_buffer_block_flags(resource.id); + if (flags.get(spv::DecorationNonWritable)) { + info->buffer.type = wgpu::BufferBindingType::ReadOnlyStorage; + } else { + info->buffer.type = wgpu::BufferBindingType::Storage; + } + } else { + info->buffer.type = wgpu::BufferBindingType::Uniform; + } + break; + } + case BindingInfoType::StorageTexture: { + spirv_cross::Bitset flags = compiler.get_decoration_bitset(resource.id); + if (flags.get(spv::DecorationNonReadable)) { + info->storageTexture.access = wgpu::StorageTextureAccess::WriteOnly; + } else if (flags.get(spv::DecorationNonWritable)) { + info->storageTexture.access = wgpu::StorageTextureAccess::ReadOnly; + } else { + return DAWN_VALIDATION_ERROR( + "Read-write storage textures are not supported"); + } + + spirv_cross::SPIRType::ImageType imageType = + compiler.get_type(info->base_type_id).image; + wgpu::TextureFormat storageTextureFormat = + SpirvImageFormatToTextureFormat(imageType.format); + if (storageTextureFormat == wgpu::TextureFormat::Undefined) { + return DAWN_VALIDATION_ERROR( + "Invalid image format declaration on storage image"); + } + const Format& format = device->GetValidInternalFormat(storageTextureFormat); + if (!format.supportsStorageUsage) { + return DAWN_VALIDATION_ERROR( + "The storage texture format is not supported"); + } + if (imageType.ms) { + return DAWN_VALIDATION_ERROR( + "Multisampled storage textures aren't supported"); + } + if (imageType.depth) { + return DAWN_VALIDATION_ERROR("Depth storage textures aren't supported"); + } + info->storageTexture.format = storageTextureFormat; + info->storageTexture.viewDimension = + SpirvDimToTextureViewDimension(imageType.dim, imageType.arrayed); + break; + } + case BindingInfoType::Sampler: { + info->sampler.isComparison = false; + break; + } + case BindingInfoType::ExternalTexture: { + return DAWN_VALIDATION_ERROR("External textures are not supported."); + } + } + } + return {}; + }; + + DAWN_TRY(ExtractResourcesBinding(device, resources.uniform_buffers, compiler, + BindingInfoType::Buffer, &metadata->bindings)); + DAWN_TRY(ExtractResourcesBinding(device, resources.separate_images, compiler, + BindingInfoType::Texture, &metadata->bindings)); + DAWN_TRY(ExtractResourcesBinding(device, resources.separate_samplers, compiler, + BindingInfoType::Sampler, &metadata->bindings)); + DAWN_TRY(ExtractResourcesBinding(device, resources.storage_buffers, compiler, + BindingInfoType::Buffer, &metadata->bindings, true)); + // ReadonlyStorageTexture is used as a tag to do general storage texture handling. + DAWN_TRY(ExtractResourcesBinding(device, resources.storage_images, compiler, + BindingInfoType::StorageTexture, &metadata->bindings)); + + // Extract the vertex attributes + if (stage == SingleShaderStage::Vertex) { + for (const auto& attrib : resources.stage_inputs) { + if (!(compiler.get_decoration_bitset(attrib.id).get(spv::DecorationLocation))) { + return DAWN_VALIDATION_ERROR( + "Unable to find Location decoration for Vertex input"); + } + uint32_t unsanitizedLocation = + compiler.get_decoration(attrib.id, spv::DecorationLocation); + + if (unsanitizedLocation >= kMaxVertexAttributes) { + return DAWN_VALIDATION_ERROR("Attribute location over limits in the SPIRV"); + } + VertexAttributeLocation location(static_cast(unsanitizedLocation)); + + spirv_cross::SPIRType::BaseType inputBaseType = + compiler.get_type(attrib.base_type_id).basetype; + metadata->vertexInputBaseTypes[location] = + SpirvBaseTypeToVertexFormatBaseType(inputBaseType); + metadata->usedVertexInputs.set(location); + } + + // Without a location qualifier on vertex outputs, spirv_cross::CompilerMSL gives + // them all the location 0, causing a compile error. + for (const auto& attrib : resources.stage_outputs) { + if (!compiler.get_decoration_bitset(attrib.id).get(spv::DecorationLocation)) { + return DAWN_VALIDATION_ERROR("Need location qualifier on vertex output"); + } + } + } + + if (stage == SingleShaderStage::Fragment) { + // Without a location qualifier on vertex inputs, spirv_cross::CompilerMSL gives + // them all the location 0, causing a compile error. + for (const auto& attrib : resources.stage_inputs) { + if (!compiler.get_decoration_bitset(attrib.id).get(spv::DecorationLocation)) { + return DAWN_VALIDATION_ERROR("Need location qualifier on fragment input"); + } + } + + for (const auto& fragmentOutput : resources.stage_outputs) { + if (!compiler.get_decoration_bitset(fragmentOutput.id) + .get(spv::DecorationLocation)) { + return DAWN_VALIDATION_ERROR( + "Unable to find Location decoration for Fragment output"); + } + uint32_t unsanitizedAttachment = + compiler.get_decoration(fragmentOutput.id, spv::DecorationLocation); + + if (unsanitizedAttachment >= kMaxColorAttachments) { + return DAWN_VALIDATION_ERROR( + "Fragment output index must be less than max number of color " + "attachments"); + } + ColorAttachmentIndex attachment(static_cast(unsanitizedAttachment)); + + spirv_cross::SPIRType::BaseType shaderFragmentOutputBaseType = + compiler.get_type(fragmentOutput.base_type_id).basetype; + metadata->fragmentOutputFormatBaseTypes[attachment] = + SpirvBaseTypeToTextureComponentType(shaderFragmentOutputBaseType); + metadata->fragmentOutputsWritten.set(attachment); + } + } + + if (stage == SingleShaderStage::Compute) { + const spirv_cross::SPIREntryPoint& spirEntryPoint = + compiler.get_entry_point(entryPointName, spv::ExecutionModelGLCompute); + metadata->localWorkgroupSize.x = spirEntryPoint.workgroup_size.x; + metadata->localWorkgroupSize.y = spirEntryPoint.workgroup_size.y; + metadata->localWorkgroupSize.z = spirEntryPoint.workgroup_size.z; + } + + return {std::move(metadata)}; + } + // static ResultOrError> ShaderModule::Create(Device* device, const ShaderModuleDescriptor* descriptor, @@ -77,6 +318,25 @@ namespace dawn_native { namespace opengl { : ShaderModuleBase(device, descriptor) { } + // static + ResultOrError ShaderModule::ReflectShaderUsingSPIRVCross( + DeviceBase* device, + const std::vector& spirv) { + EntryPointMetadataTable result; + spirv_cross::Compiler compiler(spirv); + for (const spirv_cross::EntryPoint& entryPoint : compiler.get_entry_points_and_stages()) { + ASSERT(result.count(entryPoint.name) == 0); + + SingleShaderStage stage = ExecutionModelToShaderStage(entryPoint.execution_model); + compiler.set_entry_point(entryPoint.name, entryPoint.execution_model); + + std::unique_ptr metadata; + DAWN_TRY_ASSIGN(metadata, ExtractSpirvInfo(device, compiler, entryPoint.name, stage)); + result[entryPoint.name] = std::move(metadata); + } + return std::move(result); + } + MaybeError ShaderModule::Initialize(ShaderModuleParseResult* parseResult) { ScopedTintICEHandler scopedICEHandler(GetDevice()); diff --git a/src/dawn_native/opengl/ShaderModuleGL.h b/src/dawn_native/opengl/ShaderModuleGL.h index d6d9f74028..78a2f2a272 100644 --- a/src/dawn_native/opengl/ShaderModuleGL.h +++ b/src/dawn_native/opengl/ShaderModuleGL.h @@ -60,6 +60,9 @@ namespace dawn_native { namespace opengl { ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor); ~ShaderModule() override = default; MaybeError Initialize(ShaderModuleParseResult* parseResult); + static ResultOrError ReflectShaderUsingSPIRVCross( + DeviceBase* device, + const std::vector& spirv); EntryPointMetadataTable mGLEntryPoints; }; diff --git a/src/dawn_native/SpirvUtils.cpp b/src/dawn_native/opengl/SpirvUtils.cpp similarity index 99% rename from src/dawn_native/SpirvUtils.cpp rename to src/dawn_native/opengl/SpirvUtils.cpp index 01749de1dd..a274300b31 100644 --- a/src/dawn_native/SpirvUtils.cpp +++ b/src/dawn_native/opengl/SpirvUtils.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "dawn_native/SpirvUtils.h" +#include "dawn_native/opengl/SpirvUtils.h" namespace dawn_native { diff --git a/src/dawn_native/SpirvUtils.h b/src/dawn_native/opengl/SpirvUtils.h similarity index 89% rename from src/dawn_native/SpirvUtils.h rename to src/dawn_native/opengl/SpirvUtils.h index 3719794658..844b0b7009 100644 --- a/src/dawn_native/SpirvUtils.h +++ b/src/dawn_native/opengl/SpirvUtils.h @@ -15,12 +15,8 @@ // This file contains utilities to convert from-to spirv.hpp datatypes without polluting other // headers with spirv.hpp -#ifndef DAWNNATIVE_SPIRV_UTILS_H_ -#define DAWNNATIVE_SPIRV_UTILS_H_ - -#if !defined(DAWN_USE_SPIRV_CROSS) -# error "SpirvCross.h should not be included if dawn_use_spirv_cross is false" -#endif +#ifndef DAWNNATIVE_OPENGL_SPIRV_UTILS_H_ +#define DAWNNATIVE_OPENGL_SPIRV_UTILS_H_ #include "dawn_native/Format.h" #include "dawn_native/PerStage.h" @@ -52,4 +48,4 @@ namespace dawn_native { } // namespace dawn_native -#endif // DAWNNATIVE_SPIRV_UTILS_H_ +#endif // DAWNNATIVE_OPENGL_SPIRV_UTILS_H_