// 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, 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::TextureSampleType::Float}}); 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 not currently possible to test that it is valid to have multiple reads from a // subresource while there is a single write in another subresource. // 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::StorageTextureAccess::WriteOnly, 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::TextureBinding | wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::StorageBinding); // 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::TextureBinding | wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::StorageBinding); // 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