Support Storage Textures as Valid Binding Types
This patch adds the basic validation of read-only storage texture, write-only storage texture and read-write storage texture as new binding types with no bind group layout provided in the creation of pipeline state objects. - Read-only storage textures can be used in vertex, fragment and compute shaders. - Write-only storage textures can only be used in compute shaders due to the limitation on Metal. - Read-write storage textures are not allowed now and they are reserved to be supported as an extension in the future. BUG=dawn:267 TEST=dawn_unittests Change-Id: Iffc432f29a855b85d59451cb3c50269e03b84627 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/16661 Commit-Queue: Jiawei Shao <jiawei.shao@intel.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
52d0627d56
commit
421684f943
2
BUILD.gn
2
BUILD.gn
|
@ -171,6 +171,7 @@ source_set("libdawn_native_sources") {
|
||||||
"src/dawn_native/BackendConnection.h",
|
"src/dawn_native/BackendConnection.h",
|
||||||
"src/dawn_native/BindGroup.cpp",
|
"src/dawn_native/BindGroup.cpp",
|
||||||
"src/dawn_native/BindGroup.h",
|
"src/dawn_native/BindGroup.h",
|
||||||
|
"src/dawn_native/BindGroupAndStorageBarrierTracker.h",
|
||||||
"src/dawn_native/BindGroupLayout.cpp",
|
"src/dawn_native/BindGroupLayout.cpp",
|
||||||
"src/dawn_native/BindGroupLayout.h",
|
"src/dawn_native/BindGroupLayout.h",
|
||||||
"src/dawn_native/BindGroupTracker.h",
|
"src/dawn_native/BindGroupTracker.h",
|
||||||
|
@ -863,6 +864,7 @@ test("dawn_unittests") {
|
||||||
"src/tests/unittests/validation/RenderPipelineValidationTests.cpp",
|
"src/tests/unittests/validation/RenderPipelineValidationTests.cpp",
|
||||||
"src/tests/unittests/validation/SamplerValidationTests.cpp",
|
"src/tests/unittests/validation/SamplerValidationTests.cpp",
|
||||||
"src/tests/unittests/validation/ShaderModuleValidationTests.cpp",
|
"src/tests/unittests/validation/ShaderModuleValidationTests.cpp",
|
||||||
|
"src/tests/unittests/validation/StorageTextureValidationTests.cpp",
|
||||||
"src/tests/unittests/validation/TextureValidationTests.cpp",
|
"src/tests/unittests/validation/TextureValidationTests.cpp",
|
||||||
"src/tests/unittests/validation/TextureViewValidationTests.cpp",
|
"src/tests/unittests/validation/TextureViewValidationTests.cpp",
|
||||||
"src/tests/unittests/validation/ToggleValidationTests.cpp",
|
"src/tests/unittests/validation/ToggleValidationTests.cpp",
|
||||||
|
|
|
@ -114,7 +114,9 @@
|
||||||
{"value": 2, "name": "readonly storage buffer"},
|
{"value": 2, "name": "readonly storage buffer"},
|
||||||
{"value": 3, "name": "sampler"},
|
{"value": 3, "name": "sampler"},
|
||||||
{"value": 4, "name": "sampled texture"},
|
{"value": 4, "name": "sampled texture"},
|
||||||
{"value": 5, "name": "storage texture"}
|
{"value": 5, "name": "storage texture"},
|
||||||
|
{"value": 6, "name": "readonly storage texture"},
|
||||||
|
{"value": 7, "name": "writeonly storage texture"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"blend descriptor": {
|
"blend descriptor": {
|
||||||
|
|
|
@ -159,6 +159,12 @@ namespace dawn_native {
|
||||||
case wgpu::BindingType::Sampler:
|
case wgpu::BindingType::Sampler:
|
||||||
DAWN_TRY(ValidateSamplerBinding(device, binding));
|
DAWN_TRY(ValidateSamplerBinding(device, binding));
|
||||||
break;
|
break;
|
||||||
|
// TODO(jiawei.shao@intel.com): support creating bind group with read-only and
|
||||||
|
// write-only storage textures.
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Readonly and writeonly storage textures are not supported.");
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -15,9 +15,8 @@
|
||||||
#ifndef DAWNNATIVE_BINDGROUPANDSTORAGEBARRIERTRACKER_H_
|
#ifndef DAWNNATIVE_BINDGROUPANDSTORAGEBARRIERTRACKER_H_
|
||||||
#define DAWNNATIVE_BINDGROUPANDSTORAGEBARRIERTRACKER_H_
|
#define DAWNNATIVE_BINDGROUPANDSTORAGEBARRIERTRACKER_H_
|
||||||
|
|
||||||
#include "dawn_native/BindGroupTracker.h"
|
|
||||||
|
|
||||||
#include "dawn_native/BindGroup.h"
|
#include "dawn_native/BindGroup.h"
|
||||||
|
#include "dawn_native/BindGroupTracker.h"
|
||||||
|
|
||||||
namespace dawn_native {
|
namespace dawn_native {
|
||||||
|
|
||||||
|
@ -62,6 +61,8 @@ namespace dawn_native {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
// Not implemented.
|
// Not implemented.
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -14,23 +14,46 @@
|
||||||
|
|
||||||
#include "dawn_native/BindGroupLayout.h"
|
#include "dawn_native/BindGroupLayout.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "common/BitSetIterator.h"
|
#include "common/BitSetIterator.h"
|
||||||
#include "common/HashUtils.h"
|
#include "common/HashUtils.h"
|
||||||
#include "dawn_native/Device.h"
|
#include "dawn_native/Device.h"
|
||||||
#include "dawn_native/ValidationUtils_autogen.h"
|
#include "dawn_native/ValidationUtils_autogen.h"
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
namespace dawn_native {
|
namespace dawn_native {
|
||||||
|
|
||||||
MaybeError ValidateBindingTypeWithShaderStageVisibility(
|
MaybeError ValidateBindingTypeWithShaderStageVisibility(
|
||||||
wgpu::BindingType bindingType,
|
wgpu::BindingType bindingType,
|
||||||
wgpu::ShaderStage shaderStageVisibility) {
|
wgpu::ShaderStage shaderStageVisibility) {
|
||||||
if (bindingType == wgpu::BindingType::StorageBuffer &&
|
// TODO(jiawei.shao@intel.com): support read-write storage textures.
|
||||||
(shaderStageVisibility & wgpu::ShaderStage::Vertex) != 0) {
|
switch (bindingType) {
|
||||||
|
case wgpu::BindingType::StorageBuffer: {
|
||||||
|
if ((shaderStageVisibility & wgpu::ShaderStage::Vertex) != 0) {
|
||||||
return DAWN_VALIDATION_ERROR(
|
return DAWN_VALIDATION_ERROR(
|
||||||
"storage buffer binding is not supported in vertex shader");
|
"storage buffer binding is not supported in vertex shader");
|
||||||
}
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture: {
|
||||||
|
if ((shaderStageVisibility &
|
||||||
|
(wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment)) != 0) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"write-only storage texture binding is only supported in compute shader");
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case wgpu::BindingType::StorageTexture: {
|
||||||
|
return DAWN_VALIDATION_ERROR("Read-write storage texture binding is not supported");
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case wgpu::BindingType::UniformBuffer:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageBuffer:
|
||||||
|
case wgpu::BindingType::Sampler:
|
||||||
|
case wgpu::BindingType::SampledTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -78,6 +101,8 @@ namespace dawn_native {
|
||||||
break;
|
break;
|
||||||
case wgpu::BindingType::SampledTexture:
|
case wgpu::BindingType::SampledTexture:
|
||||||
case wgpu::BindingType::Sampler:
|
case wgpu::BindingType::Sampler:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
if (binding.hasDynamicOffset) {
|
if (binding.hasDynamicOffset) {
|
||||||
return DAWN_VALIDATION_ERROR("Samplers and textures cannot be dynamic");
|
return DAWN_VALIDATION_ERROR("Samplers and textures cannot be dynamic");
|
||||||
}
|
}
|
||||||
|
@ -105,7 +130,7 @@ namespace dawn_native {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
} // namespace dawn_native
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
size_t HashBindingInfo(const BindGroupLayoutBase::LayoutBindingInfo& info) {
|
size_t HashBindingInfo(const BindGroupLayoutBase::LayoutBindingInfo& info) {
|
||||||
|
@ -171,6 +196,8 @@ namespace dawn_native {
|
||||||
case wgpu::BindingType::SampledTexture:
|
case wgpu::BindingType::SampledTexture:
|
||||||
case wgpu::BindingType::Sampler:
|
case wgpu::BindingType::Sampler:
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ target_sources(dawn_native PRIVATE
|
||||||
"BackendConnection.h"
|
"BackendConnection.h"
|
||||||
"BindGroup.cpp"
|
"BindGroup.cpp"
|
||||||
"BindGroup.h"
|
"BindGroup.h"
|
||||||
|
"BindGroupAndStorageBarrierTracker.h"
|
||||||
"BindGroupLayout.cpp"
|
"BindGroupLayout.cpp"
|
||||||
"BindGroupLayout.h"
|
"BindGroupLayout.h"
|
||||||
"BindGroupTracker.h"
|
"BindGroupTracker.h"
|
||||||
|
|
|
@ -33,6 +33,31 @@ namespace dawn_native {
|
||||||
lhs.textureComponentType == rhs.textureComponentType;
|
lhs.textureComponentType == rhs.textureComponentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wgpu::ShaderStage GetShaderStageVisibilityWithBindingType(wgpu::BindingType bindingType) {
|
||||||
|
// TODO(jiawei.shao@intel.com): support read-only and read-write storage textures.
|
||||||
|
switch (bindingType) {
|
||||||
|
case wgpu::BindingType::StorageBuffer:
|
||||||
|
return wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute;
|
||||||
|
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
|
return wgpu::ShaderStage::Compute;
|
||||||
|
|
||||||
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
UNREACHABLE();
|
||||||
|
return wgpu::ShaderStage::None;
|
||||||
|
|
||||||
|
case wgpu::BindingType::UniformBuffer:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageBuffer:
|
||||||
|
case wgpu::BindingType::Sampler:
|
||||||
|
case wgpu::BindingType::SampledTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
return wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment |
|
||||||
|
wgpu::ShaderStage::Compute;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
MaybeError ValidatePipelineLayoutDescriptor(DeviceBase* device,
|
MaybeError ValidatePipelineLayoutDescriptor(DeviceBase* device,
|
||||||
|
@ -135,14 +160,9 @@ namespace dawn_native {
|
||||||
|
|
||||||
DAWN_TRY(ValidateBindingTypeWithShaderStageVisibility(
|
DAWN_TRY(ValidateBindingTypeWithShaderStageVisibility(
|
||||||
bindingInfo.type, StageBit(module->GetExecutionModel())));
|
bindingInfo.type, StageBit(module->GetExecutionModel())));
|
||||||
if (bindingInfo.type == wgpu::BindingType::StorageBuffer) {
|
|
||||||
bindingSlot.visibility =
|
bindingSlot.visibility =
|
||||||
wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute;
|
GetShaderStageVisibilityWithBindingType(bindingInfo.type);
|
||||||
} else {
|
|
||||||
bindingSlot.visibility = wgpu::ShaderStage::Vertex |
|
|
||||||
wgpu::ShaderStage::Fragment |
|
|
||||||
wgpu::ShaderStage::Compute;
|
|
||||||
}
|
|
||||||
bindingSlot.type = bindingInfo.type;
|
bindingSlot.type = bindingInfo.type;
|
||||||
bindingSlot.hasDynamicOffset = false;
|
bindingSlot.hasDynamicOffset = false;
|
||||||
bindingSlot.multisampled = bindingInfo.multisampled;
|
bindingSlot.multisampled = bindingInfo.multisampled;
|
||||||
|
|
|
@ -59,6 +59,8 @@ namespace dawn_native {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -406,6 +406,16 @@ namespace dawn_native {
|
||||||
info->type = wgpu::BindingType::StorageBuffer;
|
info->type = wgpu::BindingType::StorageBuffer;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case wgpu::BindingType::StorageTexture: {
|
||||||
|
spirv_cross::Bitset flags = compiler.get_decoration_bitset(resource.id);
|
||||||
|
if (flags.get(spv::DecorationNonReadable)) {
|
||||||
|
info->type = wgpu::BindingType::WriteonlyStorageTexture;
|
||||||
|
} else if (flags.get(spv::DecorationNonWritable)) {
|
||||||
|
info->type = wgpu::BindingType::ReadonlyStorageTexture;
|
||||||
|
} else {
|
||||||
|
info->type = wgpu::BindingType::StorageTexture;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
info->type = bindingType;
|
info->type = bindingType;
|
||||||
}
|
}
|
||||||
|
@ -421,6 +431,8 @@ namespace dawn_native {
|
||||||
wgpu::BindingType::Sampler));
|
wgpu::BindingType::Sampler));
|
||||||
DAWN_TRY(ExtractResourcesBinding(resources.storage_buffers, compiler,
|
DAWN_TRY(ExtractResourcesBinding(resources.storage_buffers, compiler,
|
||||||
wgpu::BindingType::StorageBuffer));
|
wgpu::BindingType::StorageBuffer));
|
||||||
|
DAWN_TRY(ExtractResourcesBinding(resources.storage_images, compiler,
|
||||||
|
wgpu::BindingType::StorageTexture));
|
||||||
|
|
||||||
// Extract the vertex attributes
|
// Extract the vertex attributes
|
||||||
if (mExecutionModel == SingleShaderStage::Vertex) {
|
if (mExecutionModel == SingleShaderStage::Vertex) {
|
||||||
|
|
|
@ -13,15 +13,15 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "dawn_native/d3d12/BindGroupD3D12.h"
|
#include "dawn_native/d3d12/BindGroupD3D12.h"
|
||||||
|
|
||||||
#include "common/BitSetIterator.h"
|
#include "common/BitSetIterator.h"
|
||||||
#include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
|
#include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
|
||||||
#include "dawn_native/d3d12/BufferD3D12.h"
|
#include "dawn_native/d3d12/BufferD3D12.h"
|
||||||
|
#include "dawn_native/d3d12/DeviceD3D12.h"
|
||||||
#include "dawn_native/d3d12/SamplerD3D12.h"
|
#include "dawn_native/d3d12/SamplerD3D12.h"
|
||||||
#include "dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.h"
|
#include "dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.h"
|
||||||
#include "dawn_native/d3d12/TextureD3D12.h"
|
#include "dawn_native/d3d12/TextureD3D12.h"
|
||||||
|
|
||||||
#include "dawn_native/d3d12/DeviceD3D12.h"
|
|
||||||
|
|
||||||
namespace dawn_native { namespace d3d12 {
|
namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
BindGroup::BindGroup(Device* device, const BindGroupDescriptor* descriptor)
|
BindGroup::BindGroup(Device* device, const BindGroupDescriptor* descriptor)
|
||||||
|
@ -161,6 +161,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -107,6 +109,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
case wgpu::BindingType::SampledTexture:
|
case wgpu::BindingType::SampledTexture:
|
||||||
case wgpu::BindingType::Sampler:
|
case wgpu::BindingType::Sampler:
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -129,6 +133,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
// Not implemented.
|
// Not implemented.
|
||||||
|
|
||||||
case wgpu::BindingType::UniformBuffer:
|
case wgpu::BindingType::UniformBuffer:
|
||||||
|
@ -224,6 +226,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
case wgpu::BindingType::SampledTexture:
|
case wgpu::BindingType::SampledTexture:
|
||||||
case wgpu::BindingType::Sampler:
|
case wgpu::BindingType::Sampler:
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
case wgpu::BindingType::SampledTexture:
|
case wgpu::BindingType::SampledTexture:
|
||||||
case wgpu::BindingType::Sampler:
|
case wgpu::BindingType::Sampler:
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -599,6 +599,8 @@ namespace dawn_native { namespace metal {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,8 @@ namespace dawn_native { namespace metal {
|
||||||
textureIndex++;
|
textureIndex++;
|
||||||
break;
|
break;
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,6 +305,8 @@ namespace dawn_native { namespace opengl {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,8 @@ namespace dawn_native { namespace opengl {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,8 @@ namespace dawn_native { namespace opengl {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -149,6 +149,8 @@ namespace dawn_native { namespace vulkan {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case wgpu::BindingType::StorageTexture:
|
case wgpu::BindingType::StorageTexture:
|
||||||
|
case wgpu::BindingType::ReadonlyStorageTexture:
|
||||||
|
case wgpu::BindingType::WriteonlyStorageTexture:
|
||||||
// Not implemented.
|
// Not implemented.
|
||||||
|
|
||||||
case wgpu::BindingType::UniformBuffer:
|
case wgpu::BindingType::UniformBuffer:
|
||||||
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
// Copyright 2020 The Dawn Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "tests/unittests/validation/ValidationTest.h"
|
||||||
|
#include "utils/ComboRenderPipelineDescriptor.h"
|
||||||
|
#include "utils/WGPUHelpers.h"
|
||||||
|
|
||||||
|
class StorageTextureValidationTests : public ValidationTest {
|
||||||
|
protected:
|
||||||
|
wgpu::ShaderModule mDefaultVSModule =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
|
||||||
|
#version 450
|
||||||
|
void main() {
|
||||||
|
gl_Position = vec4(0.f, 0.f, 0.f, 1.f);
|
||||||
|
})");
|
||||||
|
wgpu::ShaderModule mDefaultFSModule =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
|
||||||
|
#version 450
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
void main() {
|
||||||
|
fragColor = vec4(1.f, 0.f, 0.f, 1.f);
|
||||||
|
})");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Validate read-only storage textures can be declared in vertex and fragment
|
||||||
|
// shaders, while writeonly storage textures can't.
|
||||||
|
TEST_F(StorageTextureValidationTests, RenderPipeline) {
|
||||||
|
// Readonly storage texture can be declared in a vertex shader.
|
||||||
|
{
|
||||||
|
wgpu::ShaderModule vsModule =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
|
||||||
|
#version 450
|
||||||
|
layout(set = 0, binding = 0, rgba8) uniform readonly image2D image0;
|
||||||
|
void main() {
|
||||||
|
gl_Position = imageLoad(image0, ivec2(gl_VertexIndex, 0));
|
||||||
|
})");
|
||||||
|
|
||||||
|
utils::ComboRenderPipelineDescriptor descriptor(device);
|
||||||
|
descriptor.layout = nullptr;
|
||||||
|
descriptor.vertexStage.module = vsModule;
|
||||||
|
descriptor.cFragmentStage.module = mDefaultFSModule;
|
||||||
|
device.CreateRenderPipeline(&descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read-only storage textures can be declared in a fragment shader.
|
||||||
|
{
|
||||||
|
wgpu::ShaderModule fsModule =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
|
||||||
|
#version 450
|
||||||
|
layout(set = 0, binding = 0, rgba8) uniform readonly image2D image0;
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
void main() {
|
||||||
|
fragColor = imageLoad(image0, ivec2(gl_FragCoord.xy));
|
||||||
|
})");
|
||||||
|
|
||||||
|
utils::ComboRenderPipelineDescriptor descriptor(device);
|
||||||
|
descriptor.layout = nullptr;
|
||||||
|
descriptor.vertexStage.module = mDefaultVSModule;
|
||||||
|
descriptor.cFragmentStage.module = fsModule;
|
||||||
|
device.CreateRenderPipeline(&descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write-only storage textures cannot be declared in a vertex shader.
|
||||||
|
{
|
||||||
|
wgpu::ShaderModule vsModule =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
|
||||||
|
#version 450
|
||||||
|
layout(set = 0, binding = 0, rgba8) uniform writeonly image2D image0;
|
||||||
|
void main() {
|
||||||
|
imageStore(image0, ivec2(gl_VertexIndex, 0), vec4(1.f, 0.f, 0.f, 1.f));
|
||||||
|
})");
|
||||||
|
|
||||||
|
utils::ComboRenderPipelineDescriptor descriptor(device);
|
||||||
|
descriptor.layout = nullptr;
|
||||||
|
descriptor.vertexStage.module = vsModule;
|
||||||
|
descriptor.cFragmentStage.module = mDefaultFSModule;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write-only storage textures cannot be declared in a fragment shader.
|
||||||
|
{
|
||||||
|
wgpu::ShaderModule fsModule =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
|
||||||
|
#version 450
|
||||||
|
layout(set = 0, binding = 0, rgba8) uniform writeonly image2D image0;
|
||||||
|
void main() {
|
||||||
|
imageStore(image0, ivec2(gl_FragCoord.xy), vec4(1.f, 0.f, 0.f, 1.f));
|
||||||
|
})");
|
||||||
|
|
||||||
|
utils::ComboRenderPipelineDescriptor descriptor(device);
|
||||||
|
descriptor.layout = nullptr;
|
||||||
|
descriptor.vertexStage.module = mDefaultVSModule;
|
||||||
|
descriptor.cFragmentStage.module = fsModule;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate both read-only and write-only storage textures can be declared in
|
||||||
|
// compute shaders.
|
||||||
|
TEST_F(StorageTextureValidationTests, ComputePipeline) {
|
||||||
|
// Read-only storage textures can be declared in a compute shader.
|
||||||
|
{
|
||||||
|
wgpu::ShaderModule csModule =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
|
||||||
|
#version 450
|
||||||
|
layout(set = 0, binding = 0, rgba8) uniform readonly image2D image0;
|
||||||
|
layout(std430, set = 0, binding = 0) buffer Buf { uint buf; };
|
||||||
|
void main() {
|
||||||
|
vec4 pixel = imageLoad(image0, ivec2(gl_LocalInvocationID.xy));
|
||||||
|
buf = uint(pixel.x);
|
||||||
|
})");
|
||||||
|
|
||||||
|
wgpu::ComputePipelineDescriptor descriptor;
|
||||||
|
descriptor.layout = nullptr;
|
||||||
|
descriptor.computeStage.module = csModule;
|
||||||
|
descriptor.computeStage.entryPoint = "main";
|
||||||
|
|
||||||
|
device.CreateComputePipeline(&descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write-only storage textures can be declared in a compute shader.
|
||||||
|
{
|
||||||
|
wgpu::ShaderModule csModule =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
|
||||||
|
#version 450
|
||||||
|
layout(set = 0, binding = 0, rgba8) uniform writeonly image2D image0;
|
||||||
|
void main() {
|
||||||
|
imageStore(image0, ivec2(gl_LocalInvocationID.xy), vec4(0.f, 0.f, 0.f, 0.f));
|
||||||
|
})");
|
||||||
|
|
||||||
|
wgpu::ComputePipelineDescriptor descriptor;
|
||||||
|
descriptor.layout = nullptr;
|
||||||
|
descriptor.computeStage.module = csModule;
|
||||||
|
descriptor.computeStage.entryPoint = "main";
|
||||||
|
|
||||||
|
device.CreateComputePipeline(&descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate read-write storage textures have not been supported yet.
|
||||||
|
TEST_F(StorageTextureValidationTests, ReadWriteStorageTexture) {
|
||||||
|
// Read-write storage textures cannot be declared in a vertex shader by default.
|
||||||
|
{
|
||||||
|
wgpu::ShaderModule vsModule =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
|
||||||
|
#version 450
|
||||||
|
layout(set = 0, binding = 0, rgba8) uniform image2D image0;
|
||||||
|
void main() {
|
||||||
|
vec4 pixel = imageLoad(image0, ivec2(gl_VertexIndex, 0));
|
||||||
|
imageStore(image0, ivec2(gl_VertexIndex, 0), pixel * 2);
|
||||||
|
})");
|
||||||
|
|
||||||
|
utils::ComboRenderPipelineDescriptor descriptor(device);
|
||||||
|
descriptor.layout = nullptr;
|
||||||
|
descriptor.vertexStage.module = vsModule;
|
||||||
|
descriptor.cFragmentStage.module = mDefaultFSModule;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read-write storage textures cannot be declared in a fragment shader by default.
|
||||||
|
{
|
||||||
|
wgpu::ShaderModule fsModule =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
|
||||||
|
#version 450
|
||||||
|
layout(set = 0, binding = 0, rgba8) uniform image2D image0;
|
||||||
|
void main() {
|
||||||
|
vec4 pixel = imageLoad(image0, ivec2(gl_FragCoord.xy));
|
||||||
|
imageStore(image0, ivec2(gl_FragCoord.xy), pixel * 2);
|
||||||
|
})");
|
||||||
|
|
||||||
|
utils::ComboRenderPipelineDescriptor descriptor(device);
|
||||||
|
descriptor.layout = nullptr;
|
||||||
|
descriptor.vertexStage.module = mDefaultVSModule;
|
||||||
|
descriptor.cFragmentStage.module = fsModule;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read-write storage textures cannot be declared in a compute shader by default.
|
||||||
|
{
|
||||||
|
wgpu::ShaderModule csModule =
|
||||||
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
|
||||||
|
#version 450
|
||||||
|
layout(set = 0, binding = 0, rgba8) uniform image2D image0;
|
||||||
|
void main() {
|
||||||
|
vec4 pixel = imageLoad(image0, ivec2(gl_LocalInvocationID.xy));
|
||||||
|
imageStore(image0, ivec2(gl_LocalInvocationID.xy), pixel * 2);
|
||||||
|
})");
|
||||||
|
|
||||||
|
wgpu::ComputePipelineDescriptor descriptor;
|
||||||
|
descriptor.layout = nullptr;
|
||||||
|
descriptor.computeStage.module = csModule;
|
||||||
|
descriptor.computeStage.entryPoint = "main";
|
||||||
|
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateComputePipeline(&descriptor));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue