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 <enga@chromium.org> Commit-Queue: Stephen White <senorblanco@chromium.org>
This commit is contained in:
parent
5d17ed6541
commit
bcbe2e0c94
|
@ -85,10 +85,6 @@ config("dawn_internal") {
|
||||||
defines += [ "DAWN_USE_X11" ]
|
defines += [ "DAWN_USE_X11" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dawn_use_spirv_cross) {
|
|
||||||
defines += [ "DAWN_USE_SPIRV_CROSS" ]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dawn_enable_error_injection) {
|
if (dawn_enable_error_injection) {
|
||||||
defines += [ "DAWN_ENABLE_ERROR_INJECTION" ]
|
defines += [ "DAWN_ENABLE_ERROR_INJECTION" ]
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
# Only win32 app needs to link with user32.lib
|
||||||
# In UWP, all availiable APIs are defined in WindowsApp.lib
|
# In UWP, all availiable APIs are defined in WindowsApp.lib
|
||||||
if (is_win && !dawn_is_winuwp) {
|
if (is_win && !dawn_is_winuwp) {
|
||||||
|
@ -527,6 +520,8 @@ source_set("dawn_native_sources") {
|
||||||
"opengl/SamplerGL.h",
|
"opengl/SamplerGL.h",
|
||||||
"opengl/ShaderModuleGL.cpp",
|
"opengl/ShaderModuleGL.cpp",
|
||||||
"opengl/ShaderModuleGL.h",
|
"opengl/ShaderModuleGL.h",
|
||||||
|
"opengl/SpirvUtils.cpp",
|
||||||
|
"opengl/SpirvUtils.h",
|
||||||
"opengl/SwapChainGL.cpp",
|
"opengl/SwapChainGL.cpp",
|
||||||
"opengl/SwapChainGL.h",
|
"opengl/SwapChainGL.h",
|
||||||
"opengl/TextureGL.cpp",
|
"opengl/TextureGL.cpp",
|
||||||
|
|
|
@ -24,16 +24,10 @@
|
||||||
#include "dawn_native/Pipeline.h"
|
#include "dawn_native/Pipeline.h"
|
||||||
#include "dawn_native/PipelineLayout.h"
|
#include "dawn_native/PipelineLayout.h"
|
||||||
#include "dawn_native/RenderPipeline.h"
|
#include "dawn_native/RenderPipeline.h"
|
||||||
#if defined(DAWN_USE_SPIRV_CROSS)
|
|
||||||
# include "dawn_native/SpirvUtils.h"
|
|
||||||
#endif
|
|
||||||
#include "dawn_native/TintUtils.h"
|
#include "dawn_native/TintUtils.h"
|
||||||
|
|
||||||
#include <spirv-tools/libspirv.hpp>
|
#include <spirv-tools/libspirv.hpp>
|
||||||
#include <spirv-tools/optimizer.hpp>
|
#include <spirv-tools/optimizer.hpp>
|
||||||
#if defined(DAWN_USE_SPIRV_CROSS)
|
|
||||||
# include <spirv_cross.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Tint include must be after spirv_cross.hpp, because spirv-cross has its own
|
// 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
|
// version of spirv_headers. We also need to undef SPV_REVISION because SPIRV-Cross
|
||||||
|
@ -679,252 +673,6 @@ namespace dawn_native {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DAWN_USE_SPIRV_CROSS)
|
|
||||||
ResultOrError<std::unique_ptr<EntryPointMetadata>> ExtractSpirvInfo(
|
|
||||||
const DeviceBase* device,
|
|
||||||
const spirv_cross::Compiler& compiler,
|
|
||||||
const std::string& entryPointName,
|
|
||||||
SingleShaderStage stage) {
|
|
||||||
std::unique_ptr<EntryPointMetadata> metadata = std::make_unique<EntryPointMetadata>();
|
|
||||||
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<spirv_cross::Resource>& 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<uint8_t>(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<uint8_t>(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<EntryPointMetadataTable> ReflectShaderUsingTint(
|
ResultOrError<EntryPointMetadataTable> ReflectShaderUsingTint(
|
||||||
DeviceBase*,
|
DeviceBase*,
|
||||||
const tint::Program* program) {
|
const tint::Program* program) {
|
||||||
|
@ -1628,26 +1376,6 @@ namespace dawn_native {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DAWN_USE_SPIRV_CROSS)
|
|
||||||
ResultOrError<EntryPointMetadataTable> ShaderModuleBase::ReflectShaderUsingSPIRVCross(
|
|
||||||
DeviceBase* device,
|
|
||||||
const std::vector<uint32_t>& 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<EntryPointMetadata> 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()(
|
size_t PipelineLayoutEntryPointPairHashFunc::operator()(
|
||||||
const PipelineLayoutEntryPointPair& pair) const {
|
const PipelineLayoutEntryPointPair& pair) const {
|
||||||
size_t hash = 0;
|
size_t hash = 0;
|
||||||
|
|
|
@ -240,11 +240,6 @@ namespace dawn_native {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MaybeError InitializeBase(ShaderModuleParseResult* parseResult);
|
MaybeError InitializeBase(ShaderModuleParseResult* parseResult);
|
||||||
#if defined(DAWN_USE_SPIRV_CROSS)
|
|
||||||
static ResultOrError<EntryPointMetadataTable> ReflectShaderUsingSPIRVCross(
|
|
||||||
DeviceBase* device,
|
|
||||||
const std::vector<uint32_t>& spirv);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ShaderModuleBase(DeviceBase* device, ObjectBase::ErrorTag tag);
|
ShaderModuleBase(DeviceBase* device, ObjectBase::ErrorTag tag);
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include "common/Assert.h"
|
#include "common/Assert.h"
|
||||||
#include "common/BitSetIterator.h"
|
#include "common/BitSetIterator.h"
|
||||||
#include "common/Log.h"
|
#include "common/Log.h"
|
||||||
#include "dawn_native/SpirvUtils.h"
|
|
||||||
#include "dawn_native/TintUtils.h"
|
#include "dawn_native/TintUtils.h"
|
||||||
#include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
|
#include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
|
||||||
#include "dawn_native/d3d12/D3D12Error.h"
|
#include "dawn_native/d3d12/D3D12Error.h"
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
#include "common/Assert.h"
|
#include "common/Assert.h"
|
||||||
#include "common/Platform.h"
|
#include "common/Platform.h"
|
||||||
#include "dawn_native/BindGroupLayout.h"
|
#include "dawn_native/BindGroupLayout.h"
|
||||||
#include "dawn_native/SpirvUtils.h"
|
|
||||||
#include "dawn_native/TintUtils.h"
|
#include "dawn_native/TintUtils.h"
|
||||||
#include "dawn_native/opengl/DeviceGL.h"
|
#include "dawn_native/opengl/DeviceGL.h"
|
||||||
#include "dawn_native/opengl/PipelineLayoutGL.h"
|
#include "dawn_native/opengl/PipelineLayoutGL.h"
|
||||||
|
#include "dawn_native/opengl/SpirvUtils.h"
|
||||||
|
|
||||||
#include <spirv_glsl.hpp>
|
#include <spirv_glsl.hpp>
|
||||||
|
|
||||||
|
@ -64,6 +64,247 @@ namespace dawn_native { namespace opengl {
|
||||||
return o.str();
|
return o.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultOrError<std::unique_ptr<EntryPointMetadata>> ExtractSpirvInfo(
|
||||||
|
const DeviceBase* device,
|
||||||
|
const spirv_cross::Compiler& compiler,
|
||||||
|
const std::string& entryPointName,
|
||||||
|
SingleShaderStage stage) {
|
||||||
|
std::unique_ptr<EntryPointMetadata> metadata = std::make_unique<EntryPointMetadata>();
|
||||||
|
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<spirv_cross::Resource>& 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<uint8_t>(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<uint8_t>(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
|
// static
|
||||||
ResultOrError<Ref<ShaderModule>> ShaderModule::Create(Device* device,
|
ResultOrError<Ref<ShaderModule>> ShaderModule::Create(Device* device,
|
||||||
const ShaderModuleDescriptor* descriptor,
|
const ShaderModuleDescriptor* descriptor,
|
||||||
|
@ -77,6 +318,25 @@ namespace dawn_native { namespace opengl {
|
||||||
: ShaderModuleBase(device, descriptor) {
|
: ShaderModuleBase(device, descriptor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
ResultOrError<EntryPointMetadataTable> ShaderModule::ReflectShaderUsingSPIRVCross(
|
||||||
|
DeviceBase* device,
|
||||||
|
const std::vector<uint32_t>& 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<EntryPointMetadata> 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) {
|
MaybeError ShaderModule::Initialize(ShaderModuleParseResult* parseResult) {
|
||||||
ScopedTintICEHandler scopedICEHandler(GetDevice());
|
ScopedTintICEHandler scopedICEHandler(GetDevice());
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,9 @@ namespace dawn_native { namespace opengl {
|
||||||
ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor);
|
ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor);
|
||||||
~ShaderModule() override = default;
|
~ShaderModule() override = default;
|
||||||
MaybeError Initialize(ShaderModuleParseResult* parseResult);
|
MaybeError Initialize(ShaderModuleParseResult* parseResult);
|
||||||
|
static ResultOrError<EntryPointMetadataTable> ReflectShaderUsingSPIRVCross(
|
||||||
|
DeviceBase* device,
|
||||||
|
const std::vector<uint32_t>& spirv);
|
||||||
|
|
||||||
EntryPointMetadataTable mGLEntryPoints;
|
EntryPointMetadataTable mGLEntryPoints;
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "dawn_native/SpirvUtils.h"
|
#include "dawn_native/opengl/SpirvUtils.h"
|
||||||
|
|
||||||
namespace dawn_native {
|
namespace dawn_native {
|
||||||
|
|
|
@ -15,12 +15,8 @@
|
||||||
// This file contains utilities to convert from-to spirv.hpp datatypes without polluting other
|
// This file contains utilities to convert from-to spirv.hpp datatypes without polluting other
|
||||||
// headers with spirv.hpp
|
// headers with spirv.hpp
|
||||||
|
|
||||||
#ifndef DAWNNATIVE_SPIRV_UTILS_H_
|
#ifndef DAWNNATIVE_OPENGL_SPIRV_UTILS_H_
|
||||||
#define DAWNNATIVE_SPIRV_UTILS_H_
|
#define DAWNNATIVE_OPENGL_SPIRV_UTILS_H_
|
||||||
|
|
||||||
#if !defined(DAWN_USE_SPIRV_CROSS)
|
|
||||||
# error "SpirvCross.h should not be included if dawn_use_spirv_cross is false"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "dawn_native/Format.h"
|
#include "dawn_native/Format.h"
|
||||||
#include "dawn_native/PerStage.h"
|
#include "dawn_native/PerStage.h"
|
||||||
|
@ -52,4 +48,4 @@ namespace dawn_native {
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
|
||||||
#endif // DAWNNATIVE_SPIRV_UTILS_H_
|
#endif // DAWNNATIVE_OPENGL_SPIRV_UTILS_H_
|
Loading…
Reference in New Issue