Add basic supports of storage textures on Vulkan
This patch adds the basic supports of read-only and write-only storage
textures on Vulkan.
The subresource tracking and barriers on the subresources used as
read-only and write-only storage textures are not included in this
patch.
BUG=dawn:267
TEST=dawn_end2end_tests
Change-Id: I6831b96202a97182763ecd28bc41ab03df904a7c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/20560
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/BindGroupAndStorageBarrierTracker.h b/src/dawn_native/BindGroupAndStorageBarrierTracker.h
index 94a2be8..8227d84 100644
--- a/src/dawn_native/BindGroupAndStorageBarrierTracker.h
+++ b/src/dawn_native/BindGroupAndStorageBarrierTracker.h
@@ -17,6 +17,8 @@
#include "dawn_native/BindGroup.h"
#include "dawn_native/BindGroupTracker.h"
+#include "dawn_native/Buffer.h"
+#include "dawn_native/Texture.h"
namespace dawn_native {
@@ -34,8 +36,8 @@
uint32_t dynamicOffsetCount,
uint32_t* dynamicOffsets) {
if (this->mBindGroups[index] != bindGroup) {
- mBuffers[index] = {};
- mBuffersNeedingBarrier[index] = {};
+ mBindings[index] = {};
+ mBindingsNeedingBarrier[index] = {};
const BindGroupLayoutBase* layout = bindGroup->GetLayout();
@@ -58,16 +60,23 @@
break;
case wgpu::BindingType::StorageBuffer:
- mBuffersNeedingBarrier[index].set(bindingIndex);
- mBuffers[index][bindingIndex] =
- bindGroup->GetBindingAsBufferBinding(bindingIndex).buffer;
+ mBindingsNeedingBarrier[index].set(bindingIndex);
+ mBindings[index][bindingIndex] = static_cast<ObjectBase*>(
+ bindGroup->GetBindingAsBufferBinding(bindingIndex).buffer);
+ break;
+
+ // Read-only and write-only storage textures must use general layout
+ // because load and store operations on storage images can only be done on
+ // the images in VK_IMAGE_LAYOUT_GENERAL layout.
+ case wgpu::BindingType::ReadonlyStorageTexture:
+ case wgpu::BindingType::WriteonlyStorageTexture:
+ mBindingsNeedingBarrier[index].set(bindingIndex);
+ mBindings[index][bindingIndex] = static_cast<ObjectBase*>(
+ bindGroup->GetBindingAsTextureView(bindingIndex));
break;
case wgpu::BindingType::StorageTexture:
- case wgpu::BindingType::ReadonlyStorageTexture:
- case wgpu::BindingType::WriteonlyStorageTexture:
// Not implemented.
-
default:
UNREACHABLE();
break;
@@ -79,10 +88,10 @@
}
protected:
- std::array<std::bitset<kMaxBindingsPerGroup>, kMaxBindGroups> mBuffersNeedingBarrier = {};
+ std::array<std::bitset<kMaxBindingsPerGroup>, kMaxBindGroups> mBindingsNeedingBarrier = {};
std::array<std::array<wgpu::BindingType, kMaxBindingsPerGroup>, kMaxBindGroups>
mBindingTypes = {};
- std::array<std::array<BufferBase*, kMaxBindingsPerGroup>, kMaxBindGroups> mBuffers = {};
+ std::array<std::array<ObjectBase*, kMaxBindingsPerGroup>, kMaxBindGroups> mBindings = {};
};
} // namespace dawn_native
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index cea9516..9a5b663 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -148,11 +148,11 @@
if (mInCompute) {
for (uint32_t index : IterateBitSet(mBindGroupLayoutsMask)) {
- for (uint32_t binding : IterateBitSet(mBuffersNeedingBarrier[index])) {
+ for (uint32_t binding : IterateBitSet(mBindingsNeedingBarrier[index])) {
wgpu::BindingType bindingType = mBindingTypes[index][binding];
switch (bindingType) {
case wgpu::BindingType::StorageBuffer:
- ToBackend(mBuffers[index][binding])
+ static_cast<Buffer*>(mBindings[index][binding])
->TrackUsageAndTransitionNow(commandContext,
wgpu::BufferUsage::Storage);
break;
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index 5ab1b8f..53f2602 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -140,17 +140,24 @@
mDynamicOffsetCounts, mDynamicOffsets);
for (uint32_t index : IterateBitSet(mBindGroupLayoutsMask)) {
- for (uint32_t bindingIndex : IterateBitSet(mBuffersNeedingBarrier[index])) {
+ for (uint32_t bindingIndex : IterateBitSet(mBindingsNeedingBarrier[index])) {
switch (mBindingTypes[index][bindingIndex]) {
case wgpu::BindingType::StorageBuffer:
- ToBackend(mBuffers[index][bindingIndex])
+ static_cast<Buffer*>(mBindings[index][bindingIndex])
->TransitionUsageNow(recordingContext,
wgpu::BufferUsage::Storage);
break;
- case wgpu::BindingType::StorageTexture:
case wgpu::BindingType::ReadonlyStorageTexture:
case wgpu::BindingType::WriteonlyStorageTexture:
+ ToBackend(
+ static_cast<TextureViewBase*>(mBindings[index][bindingIndex])
+ ->GetTexture())
+ ->TransitionUsageNow(recordingContext,
+ wgpu::TextureUsage::Storage);
+ break;
+
+ case wgpu::BindingType::StorageTexture:
// Not implemented.
case wgpu::BindingType::UniformBuffer:
diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp
index 35ade8b..681e0cf 100644
--- a/src/dawn_native/vulkan/TextureVk.cpp
+++ b/src/dawn_native/vulkan/TextureVk.cpp
@@ -120,9 +120,11 @@
// combination of GENERAL and TRANSFER_SRC_OPTIMAL. This would be a problem, so we
// make CopySrc use GENERAL.
case wgpu::TextureUsage::CopySrc:
- // Writable storage textures must use general. If we could know the texture is read
- // only we could use SHADER_READ_ONLY_OPTIMAL
+ // Read-only and write-only storage textures must use general layout because load
+ // and store operations on storage images can only be done on the images in
+ // VK_IMAGE_LAYOUT_GENERAL layout.
case wgpu::TextureUsage::Storage:
+ case kReadonlyStorageTexture:
return VK_IMAGE_LAYOUT_GENERAL;
case wgpu::TextureUsage::OutputAttachment:
if (format.HasDepthOrStencil()) {
@@ -149,11 +151,15 @@
if (usage & (wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst)) {
flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
}
- if (usage & (wgpu::TextureUsage::Sampled | wgpu::TextureUsage::Storage)) {
+ if (usage & (wgpu::TextureUsage::Sampled | kReadonlyStorageTexture)) {
flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
+ if (usage & wgpu::TextureUsage::Storage) {
+ flags |=
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ }
if (usage & wgpu::TextureUsage::OutputAttachment) {
if (format.HasDepthOrStencil()) {
flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
diff --git a/src/tests/end2end/StorageTextureTests.cpp b/src/tests/end2end/StorageTextureTests.cpp
index da9d983..9e6764c 100644
--- a/src/tests/end2end/StorageTextureTests.cpp
+++ b/src/tests/end2end/StorageTextureTests.cpp
@@ -176,6 +176,7 @@
#version 450
void main() {
gl_Position = vec4(0.f, 0.f, 0.f, 1.f);
+ gl_PointSize = 1.0f;
})";
const char* kCommonReadOnlyTestCode_uimage2D = R"(
@@ -236,8 +237,8 @@
// Test that read-only storage textures are supported in compute shader.
TEST_P(StorageTextureTests, ReadonlyStorageTextureInComputeShader) {
- // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12, Vulkan and OpenGL.
- DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL());
+ // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
+ DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
// Prepare the read-only storage texture and fill it with the expected data.
// TODO(jiawei.shao@intel.com): test more texture formats.
@@ -291,8 +292,8 @@
// Test that read-only storage textures are supported in vertex shader.
TEST_P(StorageTextureTests, ReadonlyStorageTextureInVertexShader) {
- // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12, Vulkan and OpenGL.
- DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL());
+ // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
+ DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
// When we run dawn_end2end_tests with "--use-spvc-parser", extracting the binding type of a
// read-only image will always return shaderc_spvc_binding_type_writeonly_storage_texture.
@@ -321,6 +322,7 @@
} else {
o_color = vec4(1.f, 0.f, 0.f, 1.f);
}
+ gl_PointSize = 1.0f;
})";
const char* kFragmentShader = R"(
#version 450
@@ -334,8 +336,8 @@
// Test that read-only storage textures are supported in fragment shader.
TEST_P(StorageTextureTests, ReadonlyStorageTextureInFragmentShader) {
- // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12, Vulkan and OpenGL.
- DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL());
+ // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
+ DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
// When we run dawn_end2end_tests with "--use-spvc-parser", extracting the binding type of a
// read-only image will always return shaderc_spvc_binding_type_writeonly_storage_texture.
@@ -370,8 +372,8 @@
// Test that write-only storage textures are supported in compute shader.
TEST_P(StorageTextureTests, WriteonlyStorageTextureInComputeShader) {
- // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12, Vulkan and OpenGL.
- DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL());
+ // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
+ DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
// Prepare the write-only storage texture.
// TODO(jiawei.shao@intel.com): test more texture formats.
@@ -400,8 +402,8 @@
// Test that write-only storage textures are supported in fragment shader.
TEST_P(StorageTextureTests, WriteonlyStorageTextureInFragmentShader) {
- // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12, Vulkan and OpenGL.
- DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL());
+ // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
+ DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
// Prepare the write-only storage texture.
// TODO(jiawei.shao@intel.com): test more texture formats.