dawn-cmake/src/tests/unittests/validation/TextureSubresourceTests.cpp
Yunchao He 23428ea82f Add validation code for texture subresource usage tracking
This patch also add validation tests for texture subresource tracking
for render pass. Resource usage tracking for compute is per each
dispatch() call, I will add it in next patch.

BUG=dawn:157

Change-Id: I6c4b932e317d66521fa428311e727876d0adf4ea
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/17661
Commit-Queue: Yunchao He <yunchao.he@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
2020-05-04 17:10:49 +00:00

168 lines
7.4 KiB
C++

// 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 "utils/WGPUHelpers.h"
#include "tests/unittests/validation/ValidationTest.h"
namespace {
class TextureSubresourceTest : public ValidationTest {
public:
static constexpr uint32_t kSize = 32u;
static constexpr wgpu::TextureFormat kFormat = wgpu::TextureFormat::RGBA8Unorm;
wgpu::Texture CreateTexture(uint32_t mipLevelCount,
uint32_t arrayLayerCount,
wgpu::TextureUsage usage) {
wgpu::TextureDescriptor texDesc;
texDesc.dimension = wgpu::TextureDimension::e2D;
texDesc.size = {kSize, kSize, 1};
texDesc.arrayLayerCount = arrayLayerCount;
texDesc.sampleCount = 1;
texDesc.mipLevelCount = mipLevelCount;
texDesc.usage = usage;
texDesc.format = kFormat;
return device.CreateTexture(&texDesc);
}
wgpu::TextureView CreateTextureView(wgpu::Texture texture,
uint32_t baseMipLevel,
uint32_t baseArrayLayer) {
wgpu::TextureViewDescriptor viewDesc;
viewDesc.format = kFormat;
viewDesc.baseArrayLayer = baseArrayLayer;
viewDesc.arrayLayerCount = 1;
viewDesc.baseMipLevel = baseMipLevel;
viewDesc.mipLevelCount = 1;
viewDesc.dimension = wgpu::TextureViewDimension::e2D;
return texture.CreateView(&viewDesc);
}
void TestRenderPass(const wgpu::TextureView& renderView,
const wgpu::TextureView& samplerView) {
// Create bind group
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Vertex, wgpu::BindingType::SampledTexture}});
utils::ComboRenderPassDescriptor renderPassDesc({renderView});
// It is valid to read from and write into different subresources of the same texture
{
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, samplerView}});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
pass.SetBindGroup(0, bindGroup);
pass.EndPass();
encoder.Finish();
}
// It is valid to has multiple read from a subresource and one single write into another
// subresource
{
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, samplerView}});
wgpu::BindGroupLayout bgl1 = utils::MakeBindGroupLayout(
device,
{{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::ReadonlyStorageTexture,
false, false, wgpu::TextureViewDimension::Undefined,
wgpu::TextureViewDimension::Undefined, wgpu::TextureComponentType::Float,
kFormat}});
wgpu::BindGroup bindGroup1 = utils::MakeBindGroup(device, bgl1, {{0, samplerView}});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
pass.SetBindGroup(0, bindGroup);
pass.SetBindGroup(1, bindGroup1);
pass.EndPass();
encoder.Finish();
}
// It is invalid to read and write into the same subresources
{
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, renderView}});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
pass.SetBindGroup(0, bindGroup);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// It is valid to write into and then read from the same level of a texture in different
// render passes
{
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, samplerView}});
wgpu::BindGroupLayout bgl1 = utils::MakeBindGroupLayout(
device,
{{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::WriteonlyStorageTexture,
false, false, wgpu::TextureViewDimension::Undefined,
wgpu::TextureViewDimension::Undefined, wgpu::TextureComponentType::Float,
kFormat}});
wgpu::BindGroup bindGroup1 = utils::MakeBindGroup(device, bgl1, {{0, samplerView}});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass1 = encoder.BeginRenderPass(&renderPassDesc);
pass1.SetBindGroup(0, bindGroup1);
pass1.EndPass();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
pass.SetBindGroup(0, bindGroup);
pass.EndPass();
encoder.Finish();
}
}
};
// Test different mipmap levels
TEST_F(TextureSubresourceTest, MipmapLevelsTest) {
// Create texture with 2 mipmap levels and 1 layer
wgpu::Texture texture =
CreateTexture(2, 1,
wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment |
wgpu::TextureUsage::Storage);
// Create two views on different mipmap levels.
wgpu::TextureView samplerView = CreateTextureView(texture, 0, 0);
wgpu::TextureView renderView = CreateTextureView(texture, 1, 0);
TestRenderPass(samplerView, renderView);
}
// Test different array layers
TEST_F(TextureSubresourceTest, ArrayLayersTest) {
// Create texture with 1 mipmap level and 2 layers
wgpu::Texture texture =
CreateTexture(1, 2,
wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment |
wgpu::TextureUsage::Storage);
// Create two views on different layers.
wgpu::TextureView samplerView = CreateTextureView(texture, 0, 0);
wgpu::TextureView renderView = CreateTextureView(texture, 0, 1);
TestRenderPass(samplerView, renderView);
}
// TODO (yunchao.he@intel.com):
// * Add tests for compute, in which texture subresource is traced per dispatch.
//
// * Add tests for multiple encoders upon the same resource simultaneously. This situation fits
// some cases like VR, multi-threading, etc.
//
// * Add tests for conflicts between usages in two render bundles used in the same pass.
} // anonymous namespace