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>
This commit is contained in:
Jiawei Shao 2020-04-30 02:43:08 +00:00 committed by Commit Bot service account
parent c85ef7927f
commit 754c161fd3
5 changed files with 52 additions and 28 deletions

View File

@ -17,6 +17,8 @@
#include "dawn_native/BindGroup.h" #include "dawn_native/BindGroup.h"
#include "dawn_native/BindGroupTracker.h" #include "dawn_native/BindGroupTracker.h"
#include "dawn_native/Buffer.h"
#include "dawn_native/Texture.h"
namespace dawn_native { namespace dawn_native {
@ -34,8 +36,8 @@ namespace dawn_native {
uint32_t dynamicOffsetCount, uint32_t dynamicOffsetCount,
uint32_t* dynamicOffsets) { uint32_t* dynamicOffsets) {
if (this->mBindGroups[index] != bindGroup) { if (this->mBindGroups[index] != bindGroup) {
mBuffers[index] = {}; mBindings[index] = {};
mBuffersNeedingBarrier[index] = {}; mBindingsNeedingBarrier[index] = {};
const BindGroupLayoutBase* layout = bindGroup->GetLayout(); const BindGroupLayoutBase* layout = bindGroup->GetLayout();
@ -58,16 +60,23 @@ namespace dawn_native {
break; break;
case wgpu::BindingType::StorageBuffer: case wgpu::BindingType::StorageBuffer:
mBuffersNeedingBarrier[index].set(bindingIndex); mBindingsNeedingBarrier[index].set(bindingIndex);
mBuffers[index][bindingIndex] = mBindings[index][bindingIndex] = static_cast<ObjectBase*>(
bindGroup->GetBindingAsBufferBinding(bindingIndex).buffer; 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; break;
case wgpu::BindingType::StorageTexture: case wgpu::BindingType::StorageTexture:
case wgpu::BindingType::ReadonlyStorageTexture:
case wgpu::BindingType::WriteonlyStorageTexture:
// Not implemented. // Not implemented.
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
@ -79,10 +88,10 @@ namespace dawn_native {
} }
protected: protected:
std::array<std::bitset<kMaxBindingsPerGroup>, kMaxBindGroups> mBuffersNeedingBarrier = {}; std::array<std::bitset<kMaxBindingsPerGroup>, kMaxBindGroups> mBindingsNeedingBarrier = {};
std::array<std::array<wgpu::BindingType, kMaxBindingsPerGroup>, kMaxBindGroups> std::array<std::array<wgpu::BindingType, kMaxBindingsPerGroup>, kMaxBindGroups>
mBindingTypes = {}; mBindingTypes = {};
std::array<std::array<BufferBase*, kMaxBindingsPerGroup>, kMaxBindGroups> mBuffers = {}; std::array<std::array<ObjectBase*, kMaxBindingsPerGroup>, kMaxBindGroups> mBindings = {};
}; };
} // namespace dawn_native } // namespace dawn_native

View File

@ -148,11 +148,11 @@ namespace dawn_native { namespace d3d12 {
if (mInCompute) { if (mInCompute) {
for (uint32_t index : IterateBitSet(mBindGroupLayoutsMask)) { 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]; wgpu::BindingType bindingType = mBindingTypes[index][binding];
switch (bindingType) { switch (bindingType) {
case wgpu::BindingType::StorageBuffer: case wgpu::BindingType::StorageBuffer:
ToBackend(mBuffers[index][binding]) static_cast<Buffer*>(mBindings[index][binding])
->TrackUsageAndTransitionNow(commandContext, ->TrackUsageAndTransitionNow(commandContext,
wgpu::BufferUsage::Storage); wgpu::BufferUsage::Storage);
break; break;

View File

@ -140,17 +140,24 @@ namespace dawn_native { namespace vulkan {
mDynamicOffsetCounts, mDynamicOffsets); mDynamicOffsetCounts, mDynamicOffsets);
for (uint32_t index : IterateBitSet(mBindGroupLayoutsMask)) { for (uint32_t index : IterateBitSet(mBindGroupLayoutsMask)) {
for (uint32_t bindingIndex : IterateBitSet(mBuffersNeedingBarrier[index])) { for (uint32_t bindingIndex : IterateBitSet(mBindingsNeedingBarrier[index])) {
switch (mBindingTypes[index][bindingIndex]) { switch (mBindingTypes[index][bindingIndex]) {
case wgpu::BindingType::StorageBuffer: case wgpu::BindingType::StorageBuffer:
ToBackend(mBuffers[index][bindingIndex]) static_cast<Buffer*>(mBindings[index][bindingIndex])
->TransitionUsageNow(recordingContext, ->TransitionUsageNow(recordingContext,
wgpu::BufferUsage::Storage); wgpu::BufferUsage::Storage);
break; break;
case wgpu::BindingType::StorageTexture:
case wgpu::BindingType::ReadonlyStorageTexture: case wgpu::BindingType::ReadonlyStorageTexture:
case wgpu::BindingType::WriteonlyStorageTexture: case wgpu::BindingType::WriteonlyStorageTexture:
ToBackend(
static_cast<TextureViewBase*>(mBindings[index][bindingIndex])
->GetTexture())
->TransitionUsageNow(recordingContext,
wgpu::TextureUsage::Storage);
break;
case wgpu::BindingType::StorageTexture:
// Not implemented. // Not implemented.
case wgpu::BindingType::UniformBuffer: case wgpu::BindingType::UniformBuffer:

View File

@ -120,9 +120,11 @@ namespace dawn_native { namespace vulkan {
// combination of GENERAL and TRANSFER_SRC_OPTIMAL. This would be a problem, so we // combination of GENERAL and TRANSFER_SRC_OPTIMAL. This would be a problem, so we
// make CopySrc use GENERAL. // make CopySrc use GENERAL.
case wgpu::TextureUsage::CopySrc: case wgpu::TextureUsage::CopySrc:
// Writable storage textures must use general. If we could know the texture is read // Read-only and write-only storage textures must use general layout because load
// only we could use SHADER_READ_ONLY_OPTIMAL // and store operations on storage images can only be done on the images in
// VK_IMAGE_LAYOUT_GENERAL layout.
case wgpu::TextureUsage::Storage: case wgpu::TextureUsage::Storage:
case kReadonlyStorageTexture:
return VK_IMAGE_LAYOUT_GENERAL; return VK_IMAGE_LAYOUT_GENERAL;
case wgpu::TextureUsage::OutputAttachment: case wgpu::TextureUsage::OutputAttachment:
if (format.HasDepthOrStencil()) { if (format.HasDepthOrStencil()) {
@ -149,11 +151,15 @@ namespace dawn_native { namespace vulkan {
if (usage & (wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst)) { if (usage & (wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst)) {
flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; 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 | flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_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 (usage & wgpu::TextureUsage::OutputAttachment) {
if (format.HasDepthOrStencil()) { if (format.HasDepthOrStencil()) {
flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |

View File

@ -176,6 +176,7 @@ class StorageTextureTests : public DawnTest {
#version 450 #version 450
void main() { void main() {
gl_Position = vec4(0.f, 0.f, 0.f, 1.f); gl_Position = vec4(0.f, 0.f, 0.f, 1.f);
gl_PointSize = 1.0f;
})"; })";
const char* kCommonReadOnlyTestCode_uimage2D = R"( const char* kCommonReadOnlyTestCode_uimage2D = R"(
@ -236,8 +237,8 @@ TEST_P(StorageTextureTests, BindGroupLayoutWithStorageTextureBindingType) {
// Test that read-only storage textures are supported in compute shader. // Test that read-only storage textures are supported in compute shader.
TEST_P(StorageTextureTests, ReadonlyStorageTextureInComputeShader) { TEST_P(StorageTextureTests, ReadonlyStorageTextureInComputeShader) {
// TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12, Vulkan and OpenGL. // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL()); DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
// Prepare the read-only storage texture and fill it with the expected data. // Prepare the read-only storage texture and fill it with the expected data.
// TODO(jiawei.shao@intel.com): test more texture formats. // TODO(jiawei.shao@intel.com): test more texture formats.
@ -291,8 +292,8 @@ TEST_P(StorageTextureTests, ReadonlyStorageTextureInComputeShader) {
// Test that read-only storage textures are supported in vertex shader. // Test that read-only storage textures are supported in vertex shader.
TEST_P(StorageTextureTests, ReadonlyStorageTextureInVertexShader) { TEST_P(StorageTextureTests, ReadonlyStorageTextureInVertexShader) {
// TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12, Vulkan and OpenGL. // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL()); DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
// When we run dawn_end2end_tests with "--use-spvc-parser", extracting the binding type of a // 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. // read-only image will always return shaderc_spvc_binding_type_writeonly_storage_texture.
@ -321,6 +322,7 @@ TEST_P(StorageTextureTests, ReadonlyStorageTextureInVertexShader) {
} else { } else {
o_color = vec4(1.f, 0.f, 0.f, 1.f); o_color = vec4(1.f, 0.f, 0.f, 1.f);
} }
gl_PointSize = 1.0f;
})"; })";
const char* kFragmentShader = R"( const char* kFragmentShader = R"(
#version 450 #version 450
@ -334,8 +336,8 @@ TEST_P(StorageTextureTests, ReadonlyStorageTextureInVertexShader) {
// Test that read-only storage textures are supported in fragment shader. // Test that read-only storage textures are supported in fragment shader.
TEST_P(StorageTextureTests, ReadonlyStorageTextureInFragmentShader) { TEST_P(StorageTextureTests, ReadonlyStorageTextureInFragmentShader) {
// TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12, Vulkan and OpenGL. // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL()); DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
// When we run dawn_end2end_tests with "--use-spvc-parser", extracting the binding type of a // 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. // read-only image will always return shaderc_spvc_binding_type_writeonly_storage_texture.
@ -370,8 +372,8 @@ TEST_P(StorageTextureTests, ReadonlyStorageTextureInFragmentShader) {
// Test that write-only storage textures are supported in compute shader. // Test that write-only storage textures are supported in compute shader.
TEST_P(StorageTextureTests, WriteonlyStorageTextureInComputeShader) { TEST_P(StorageTextureTests, WriteonlyStorageTextureInComputeShader) {
// TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12, Vulkan and OpenGL. // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL()); DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
// Prepare the write-only storage texture. // Prepare the write-only storage texture.
// TODO(jiawei.shao@intel.com): test more texture formats. // TODO(jiawei.shao@intel.com): test more texture formats.
@ -400,8 +402,8 @@ TEST_P(StorageTextureTests, WriteonlyStorageTextureInComputeShader) {
// Test that write-only storage textures are supported in fragment shader. // Test that write-only storage textures are supported in fragment shader.
TEST_P(StorageTextureTests, WriteonlyStorageTextureInFragmentShader) { TEST_P(StorageTextureTests, WriteonlyStorageTextureInFragmentShader) {
// TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12, Vulkan and OpenGL. // TODO(jiawei.shao@intel.com): support read-only storage texture on D3D12 and OpenGL.
DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsOpenGL()); DAWN_SKIP_TEST_IF(IsD3D12() || IsOpenGL());
// Prepare the write-only storage texture. // Prepare the write-only storage texture.
// TODO(jiawei.shao@intel.com): test more texture formats. // TODO(jiawei.shao@intel.com): test more texture formats.