| // Copyright 2018 The Dawn & Tint Authors |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // 1. Redistributions of source code must retain the above copyright notice, this |
| // list of conditions and the following disclaimer. |
| // |
| // 2. Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // 3. Neither the name of the copyright holder nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #include <array> |
| #include <vector> |
| |
| #include "dawn/tests/unittests/validation/ValidationTest.h" |
| #include "dawn/utils/WGPUHelpers.h" |
| |
| namespace dawn { |
| namespace { |
| |
| class TextureViewValidationTest : public ValidationTest {}; |
| |
| constexpr uint32_t kWidth = 32u; |
| constexpr uint32_t kHeight = 32u; |
| constexpr uint32_t kDepth = 6u; |
| constexpr uint32_t kDefaultMipLevels = 6u; |
| |
| constexpr wgpu::TextureFormat kDefaultTextureFormat = wgpu::TextureFormat::RGBA8Unorm; |
| |
| wgpu::Texture Create2DArrayTexture(wgpu::Device& device, |
| uint32_t arrayLayerCount, |
| uint32_t width = kWidth, |
| uint32_t height = kHeight, |
| uint32_t mipLevelCount = kDefaultMipLevels, |
| uint32_t sampleCount = 1) { |
| wgpu::TextureDescriptor descriptor; |
| descriptor.dimension = wgpu::TextureDimension::e2D; |
| descriptor.size.width = width; |
| descriptor.size.height = height; |
| descriptor.size.depthOrArrayLayers = arrayLayerCount; |
| descriptor.sampleCount = sampleCount; |
| descriptor.format = kDefaultTextureFormat; |
| descriptor.mipLevelCount = mipLevelCount; |
| descriptor.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment; |
| return device.CreateTexture(&descriptor); |
| } |
| |
| wgpu::Texture Create3DTexture(wgpu::Device& device) { |
| wgpu::TextureDescriptor descriptor; |
| descriptor.dimension = wgpu::TextureDimension::e3D; |
| descriptor.size = {kWidth, kHeight, kDepth}; |
| descriptor.sampleCount = 1; |
| descriptor.format = kDefaultTextureFormat; |
| descriptor.mipLevelCount = kDefaultMipLevels; |
| descriptor.usage = wgpu::TextureUsage::TextureBinding; |
| return device.CreateTexture(&descriptor); |
| } |
| |
| wgpu::Texture Create1DTexture(wgpu::Device& device) { |
| wgpu::TextureDescriptor descriptor; |
| descriptor.dimension = wgpu::TextureDimension::e1D; |
| descriptor.size = {kWidth, 1, 1}; |
| descriptor.format = kDefaultTextureFormat; |
| descriptor.usage = wgpu::TextureUsage::TextureBinding; |
| return device.CreateTexture(&descriptor); |
| } |
| |
| wgpu::Texture CreateDepthStencilTexture(wgpu::Device& device, wgpu::TextureFormat format) { |
| wgpu::TextureDescriptor descriptor = {}; |
| descriptor.size = {kWidth, kHeight, kDepth}; |
| descriptor.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment; |
| descriptor.mipLevelCount = kDefaultMipLevels; |
| descriptor.format = format; |
| return device.CreateTexture(&descriptor); |
| } |
| |
| wgpu::TextureViewDescriptor CreateDefaultViewDescriptor(wgpu::TextureViewDimension dimension) { |
| wgpu::TextureViewDescriptor descriptor; |
| descriptor.format = kDefaultTextureFormat; |
| descriptor.dimension = dimension; |
| descriptor.baseMipLevel = 0; |
| if (dimension != wgpu::TextureViewDimension::e1D) { |
| descriptor.mipLevelCount = kDefaultMipLevels; |
| } |
| descriptor.baseArrayLayer = 0; |
| descriptor.arrayLayerCount = 1; |
| return descriptor; |
| } |
| |
| // Test creating texture view on a 2D non-array texture |
| TEST_F(TextureViewValidationTest, CreateTextureViewOnTexture2D) { |
| wgpu::Texture texture = Create2DArrayTexture(device, 1); |
| |
| wgpu::TextureViewDescriptor base2DTextureViewDescriptor = |
| CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D); |
| |
| // It is an error to create a view with zero 'arrayLayerCount'. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; |
| descriptor.arrayLayerCount = 0; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is an error to create a view with zero 'mipLevelCount'. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; |
| descriptor.mipLevelCount = 0; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is OK to create a 2D texture view on a 2D texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; |
| descriptor.arrayLayerCount = 1; |
| texture.CreateView(&descriptor); |
| } |
| |
| // It is an error to view a layer past the end of the texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; |
| descriptor.arrayLayerCount = 2; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is OK to create a 1-layer 2D array texture view on a 2D texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::e2DArray; |
| descriptor.arrayLayerCount = 1; |
| texture.CreateView(&descriptor); |
| } |
| |
| // It is an error to create a 3D texture view on a 2D texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::e3D; |
| descriptor.arrayLayerCount = 1; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // baseMipLevel == k && mipLevelCount == WGPU_MIP_LEVEL_COUNT_UNDEFINED means to use levels |
| // k..end. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; |
| descriptor.mipLevelCount = WGPU_MIP_LEVEL_COUNT_UNDEFINED; |
| |
| descriptor.baseMipLevel = 0; |
| texture.CreateView(&descriptor); |
| descriptor.baseMipLevel = 1; |
| texture.CreateView(&descriptor); |
| descriptor.baseMipLevel = kDefaultMipLevels - 1; |
| texture.CreateView(&descriptor); |
| descriptor.baseMipLevel = kDefaultMipLevels; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is an error to make the mip level out of range. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; |
| descriptor.baseMipLevel = 0; |
| descriptor.mipLevelCount = kDefaultMipLevels + 1; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| descriptor.baseMipLevel = 1; |
| descriptor.mipLevelCount = kDefaultMipLevels; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| descriptor.baseMipLevel = kDefaultMipLevels - 1; |
| descriptor.mipLevelCount = 2; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| descriptor.baseMipLevel = kDefaultMipLevels; |
| descriptor.mipLevelCount = 1; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| } |
| |
| // Test creating texture view on a 2D array texture |
| TEST_F(TextureViewValidationTest, CreateTextureViewOnTexture2DArray) { |
| constexpr uint32_t kDefaultArrayLayers = 6; |
| |
| wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers); |
| |
| wgpu::TextureViewDescriptor base2DArrayTextureViewDescriptor = |
| CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2DArray); |
| |
| // It is an error to create a view with zero 'arrayLayerCount'. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::e2D; |
| descriptor.arrayLayerCount = 0; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is an error to create a view with zero 'mipLevelCount'. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::e2D; |
| descriptor.mipLevelCount = 0; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is OK to create a 2D texture view on a 2D array texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::e2D; |
| descriptor.arrayLayerCount = 1; |
| texture.CreateView(&descriptor); |
| } |
| |
| // It is OK to create a 2D array texture view on a 2D array texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.arrayLayerCount = kDefaultArrayLayers; |
| texture.CreateView(&descriptor); |
| } |
| |
| // It is an error to create a 3D texture view on a 2D array texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::e3D; |
| descriptor.arrayLayerCount = 1; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is an error to create a 1D texture view on a 2D array texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::e1D; |
| descriptor.arrayLayerCount = 1; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // baseArrayLayer == k && arrayLayerCount == wgpu::kArrayLayerCountUndefined means to use |
| // layers k..end. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.arrayLayerCount = wgpu::kArrayLayerCountUndefined; |
| |
| descriptor.baseArrayLayer = 0; |
| texture.CreateView(&descriptor); |
| descriptor.baseArrayLayer = 1; |
| texture.CreateView(&descriptor); |
| descriptor.baseArrayLayer = kDefaultArrayLayers - 1; |
| texture.CreateView(&descriptor); |
| descriptor.baseArrayLayer = kDefaultArrayLayers; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is an error for the array layer range of the view to exceed that of the texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.baseArrayLayer = 0; |
| descriptor.arrayLayerCount = kDefaultArrayLayers + 1; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| descriptor.baseArrayLayer = 1; |
| descriptor.arrayLayerCount = kDefaultArrayLayers; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| descriptor.baseArrayLayer = kDefaultArrayLayers - 1; |
| descriptor.arrayLayerCount = 2; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| descriptor.baseArrayLayer = kDefaultArrayLayers; |
| descriptor.arrayLayerCount = 1; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| } |
| |
| // Test creating texture view on a 3D texture |
| TEST_F(TextureViewValidationTest, CreateTextureViewOnTexture3D) { |
| wgpu::Texture texture = Create3DTexture(device); |
| |
| wgpu::TextureViewDescriptor base3DTextureViewDescriptor = |
| CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e3D); |
| |
| // It is an error to create a view with zero 'arrayLayerCount'. |
| { |
| wgpu::TextureViewDescriptor descriptor = base3DTextureViewDescriptor; |
| descriptor.arrayLayerCount = 0; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is an error to create a view with zero 'mipLevelCount'. |
| { |
| wgpu::TextureViewDescriptor descriptor = base3DTextureViewDescriptor; |
| descriptor.mipLevelCount = 0; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is OK to create a 3D texture view on a 3D texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = base3DTextureViewDescriptor; |
| texture.CreateView(&descriptor); |
| } |
| |
| // It is an error to create a 1D/2D/2DArray/Cube/CubeArray texture view on a 3D texture. |
| { |
| wgpu::TextureViewDimension invalidDimensions[] = { |
| wgpu::TextureViewDimension::e1D, wgpu::TextureViewDimension::e2D, |
| wgpu::TextureViewDimension::e2DArray, wgpu::TextureViewDimension::Cube, |
| wgpu::TextureViewDimension::CubeArray, |
| }; |
| for (wgpu::TextureViewDimension dimension : invalidDimensions) { |
| wgpu::TextureViewDescriptor descriptor = base3DTextureViewDescriptor; |
| descriptor.dimension = dimension; |
| if (dimension == wgpu::TextureViewDimension::Cube || |
| dimension == wgpu::TextureViewDimension::CubeArray) { |
| descriptor.arrayLayerCount = 6; |
| } |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| } |
| |
| // baseMipLevel == k && mipLevelCount == WGPU_MIP_LEVEL_COUNT_UNDEFINED means to use levels |
| // k..end. |
| { |
| wgpu::TextureViewDescriptor descriptor = base3DTextureViewDescriptor; |
| descriptor.mipLevelCount = WGPU_MIP_LEVEL_COUNT_UNDEFINED; |
| |
| descriptor.baseMipLevel = 0; |
| texture.CreateView(&descriptor); |
| descriptor.baseMipLevel = 1; |
| texture.CreateView(&descriptor); |
| descriptor.baseMipLevel = kDefaultMipLevels - 1; |
| texture.CreateView(&descriptor); |
| descriptor.baseMipLevel = kDefaultMipLevels; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is an error to make the mip level out of range. |
| { |
| wgpu::TextureViewDescriptor descriptor = base3DTextureViewDescriptor; |
| descriptor.baseMipLevel = 0; |
| descriptor.mipLevelCount = kDefaultMipLevels + 1; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| descriptor.baseMipLevel = 1; |
| descriptor.mipLevelCount = kDefaultMipLevels; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| descriptor.baseMipLevel = kDefaultMipLevels - 1; |
| descriptor.mipLevelCount = 2; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| descriptor.baseMipLevel = kDefaultMipLevels; |
| descriptor.mipLevelCount = 1; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // baseArrayLayer == k && arrayLayerCount == wgpu::kArrayLayerCountUndefined means to use |
| // layers k..end. But baseArrayLayer must be 0, and arrayLayerCount must be 1 at most for 3D |
| // texture view. |
| { |
| wgpu::TextureViewDescriptor descriptor = base3DTextureViewDescriptor; |
| descriptor.arrayLayerCount = wgpu::kArrayLayerCountUndefined; |
| descriptor.baseArrayLayer = 0; |
| texture.CreateView(&descriptor); |
| descriptor.baseArrayLayer = 1; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| |
| descriptor.baseArrayLayer = 0; |
| descriptor.arrayLayerCount = 1; |
| texture.CreateView(&descriptor); |
| descriptor.arrayLayerCount = 2; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| descriptor.arrayLayerCount = kDepth; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| } |
| |
| // Test creating texture view on a 1D texture |
| TEST_F(TextureViewValidationTest, CreateTextureViewOnTexture1D) { |
| wgpu::Texture texture = Create1DTexture(device); |
| |
| wgpu::TextureViewDescriptor base1DTextureViewDescriptor = |
| CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e1D); |
| |
| // It is an error to create a view with zero 'arrayLayerCount'. |
| { |
| wgpu::TextureViewDescriptor descriptor = base1DTextureViewDescriptor; |
| descriptor.arrayLayerCount = 0; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is an error to create a view with zero 'mipLevelCount'. |
| { |
| wgpu::TextureViewDescriptor descriptor = base1DTextureViewDescriptor; |
| descriptor.mipLevelCount = 0; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is OK to create a 1D texture view on a 1D texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = base1DTextureViewDescriptor; |
| texture.CreateView(&descriptor); |
| } |
| |
| // It is an error to create a 2D/2DArray/Cube/CubeArray/3D texture view on a 1D texture. |
| { |
| wgpu::TextureViewDimension invalidDimensions[] = { |
| wgpu::TextureViewDimension::e2D, wgpu::TextureViewDimension::e2DArray, |
| wgpu::TextureViewDimension::Cube, wgpu::TextureViewDimension::CubeArray, |
| wgpu::TextureViewDimension::e3D, |
| }; |
| for (wgpu::TextureViewDimension dimension : invalidDimensions) { |
| wgpu::TextureViewDescriptor descriptor = base1DTextureViewDescriptor; |
| descriptor.dimension = dimension; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| } |
| |
| // No tests for setting mip levels / array layer ranges because 1D textures can only have |
| // a single mip and layer. |
| } |
| |
| // Test creating texture view on a multisampled 2D texture |
| TEST_F(TextureViewValidationTest, CreateTextureViewOnMultisampledTexture2D) { |
| wgpu::Texture texture = Create2DArrayTexture(device, /* arrayLayerCount */ 1, kWidth, kHeight, |
| /* mipLevelCount */ 1, /* sampleCount */ 4); |
| |
| // It is OK to create a 2D texture view on a multisampled 2D texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = {}; |
| texture.CreateView(&descriptor); |
| } |
| |
| // It is an error to create a 1-layer 2D array texture view on a multisampled 2D texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = {}; |
| descriptor.dimension = wgpu::TextureViewDimension::e2DArray; |
| descriptor.arrayLayerCount = 1; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is an error to create a 1D texture view on a multisampled 2D texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = {}; |
| descriptor.dimension = wgpu::TextureViewDimension::e1D; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is an error to create a 3D texture view on a multisampled 2D texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = {}; |
| descriptor.dimension = wgpu::TextureViewDimension::e3D; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| } |
| |
| // Using the "none" ("default") values validates the same as explicitly |
| // specifying the values they're supposed to default to. |
| // Variant for a 2D texture with more than 1 array layer. |
| TEST_F(TextureViewValidationTest, TextureViewDescriptorDefaults2DArray) { |
| constexpr uint32_t kDefaultArrayLayers = 8; |
| wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers); |
| |
| { texture.CreateView(); } |
| { |
| wgpu::TextureViewDescriptor descriptor; |
| descriptor.format = wgpu::TextureFormat::Undefined; |
| texture.CreateView(&descriptor); |
| descriptor.format = wgpu::TextureFormat::RGBA8Unorm; |
| texture.CreateView(&descriptor); |
| descriptor.format = wgpu::TextureFormat::R8Unorm; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| { |
| wgpu::TextureViewDescriptor descriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::Undefined; |
| texture.CreateView(&descriptor); |
| descriptor.dimension = wgpu::TextureViewDimension::e2DArray; |
| texture.CreateView(&descriptor); |
| // Setting view dimension to 2D, its arrayLayer will default to 1. And view creation |
| // will success. |
| descriptor.dimension = wgpu::TextureViewDimension::e2D; |
| texture.CreateView(&descriptor); |
| // Setting view dimension to Cube, its arrayLayer will default to 6. |
| descriptor.dimension = wgpu::TextureViewDimension::Cube; |
| texture.CreateView(&descriptor); |
| descriptor.baseArrayLayer = 2; |
| texture.CreateView(&descriptor); |
| descriptor.baseArrayLayer = 3; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| // Setting view dimension to CubeArray, its arrayLayer will default to |
| // size.depthOrArrayLayers (kDefaultArrayLayers) - baseArrayLayer. |
| descriptor.dimension = wgpu::TextureViewDimension::CubeArray; |
| descriptor.baseArrayLayer = 0; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| descriptor.baseArrayLayer = 2; |
| texture.CreateView(&descriptor); |
| descriptor.baseArrayLayer = 3; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| { |
| wgpu::TextureViewDescriptor descriptor; |
| |
| // Setting array layers to > 1 with an explicit dimensionality of 2D will |
| // causes an error. |
| descriptor.arrayLayerCount = kDefaultArrayLayers; |
| descriptor.dimension = wgpu::TextureViewDimension::e2D; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| // Setting view dimension to Undefined will result in a dimension of 2DArray because the |
| // underlying texture has > 1 array layers. |
| descriptor.dimension = wgpu::TextureViewDimension::Undefined; |
| texture.CreateView(&descriptor); |
| descriptor.dimension = wgpu::TextureViewDimension::e2DArray; |
| texture.CreateView(&descriptor); |
| |
| descriptor.mipLevelCount = kDefaultMipLevels; |
| texture.CreateView(&descriptor); |
| } |
| } |
| |
| // Using the "none" ("default") values validates the same as explicitly |
| // specifying the values they're supposed to default to. |
| // Variant for a 2D texture with only 1 array layer. |
| TEST_F(TextureViewValidationTest, TextureViewDescriptorDefaults2DNonArray) { |
| constexpr uint32_t kDefaultArrayLayers = 1; |
| wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers); |
| |
| { texture.CreateView(); } |
| { |
| wgpu::TextureViewDescriptor descriptor; |
| descriptor.format = wgpu::TextureFormat::Undefined; |
| texture.CreateView(&descriptor); |
| descriptor.format = wgpu::TextureFormat::RGBA8Unorm; |
| texture.CreateView(&descriptor); |
| descriptor.format = wgpu::TextureFormat::R8Unorm; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| { |
| wgpu::TextureViewDescriptor descriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::Undefined; |
| texture.CreateView(&descriptor); |
| descriptor.dimension = wgpu::TextureViewDimension::e2D; |
| texture.CreateView(&descriptor); |
| descriptor.dimension = wgpu::TextureViewDimension::e2DArray; |
| texture.CreateView(&descriptor); |
| } |
| { |
| wgpu::TextureViewDescriptor descriptor; |
| descriptor.arrayLayerCount = wgpu::kArrayLayerCountUndefined; |
| texture.CreateView(&descriptor); |
| descriptor.arrayLayerCount = 1; |
| texture.CreateView(&descriptor); |
| descriptor.arrayLayerCount = 2; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| { |
| wgpu::TextureViewDescriptor descriptor; |
| descriptor.mipLevelCount = kDefaultMipLevels; |
| texture.CreateView(&descriptor); |
| descriptor.arrayLayerCount = kDefaultArrayLayers; |
| texture.CreateView(&descriptor); |
| } |
| } |
| |
| // Using the "none" ("default") values validates the same as explicitly |
| // specifying the values they're supposed to default to. |
| // Variant for a 3D texture. |
| TEST_F(TextureViewValidationTest, TextureViewDescriptorDefaults3D) { |
| wgpu::Texture texture = Create3DTexture(device); |
| |
| { texture.CreateView(); } |
| { |
| wgpu::TextureViewDescriptor descriptor; |
| descriptor.format = wgpu::TextureFormat::Undefined; |
| texture.CreateView(&descriptor); |
| descriptor.format = wgpu::TextureFormat::RGBA8Unorm; |
| texture.CreateView(&descriptor); |
| descriptor.format = wgpu::TextureFormat::R8Unorm; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| { |
| wgpu::TextureViewDescriptor descriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::Undefined; |
| texture.CreateView(&descriptor); |
| descriptor.dimension = wgpu::TextureViewDimension::e3D; |
| texture.CreateView(&descriptor); |
| descriptor.dimension = wgpu::TextureViewDimension::e2DArray; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| descriptor.dimension = wgpu::TextureViewDimension::e2D; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| { |
| wgpu::TextureViewDescriptor descriptor; |
| descriptor.arrayLayerCount = wgpu::kArrayLayerCountUndefined; |
| texture.CreateView(&descriptor); |
| descriptor.arrayLayerCount = 1; |
| texture.CreateView(&descriptor); |
| descriptor.arrayLayerCount = 2; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| { |
| wgpu::TextureViewDescriptor descriptor; |
| descriptor.mipLevelCount = kDefaultMipLevels; |
| texture.CreateView(&descriptor); |
| descriptor.arrayLayerCount = kDepth; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| } |
| |
| // Regression test for crbug.com/1314049. Format default depends on the aspect. |
| // Test that computing the default does not crash if the aspect is invalid. |
| TEST_F(TextureViewValidationTest, TextureViewDescriptorDefaultsInvalidAspect) { |
| wgpu::Texture texture = |
| CreateDepthStencilTexture(device, wgpu::TextureFormat::Depth24PlusStencil8); |
| |
| wgpu::TextureViewDescriptor viewDesc = {}; |
| viewDesc.aspect = static_cast<wgpu::TextureAspect>(-1); |
| |
| // Validation should catch the invalid aspect. |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc), |
| testing::HasSubstr("is invalid for WGPUTextureAspect")); |
| } |
| |
| // Test creating cube map texture view |
| TEST_F(TextureViewValidationTest, CreateCubeMapTextureView) { |
| constexpr uint32_t kDefaultArrayLayers = 16; |
| |
| wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers); |
| |
| wgpu::TextureViewDescriptor base2DArrayTextureViewDescriptor = |
| CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2DArray); |
| |
| // It is an error to create a view with zero 'arrayLayerCount'. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::Cube; |
| descriptor.arrayLayerCount = 0; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is an error to create a view with zero 'mipLevelCount'. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::Cube; |
| descriptor.mipLevelCount = 0; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is OK to create a cube map texture view with arrayLayerCount == 6. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::Cube; |
| descriptor.arrayLayerCount = 6; |
| texture.CreateView(&descriptor); |
| } |
| |
| // It is an error to create a cube map texture view with arrayLayerCount != 6. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::Cube; |
| descriptor.arrayLayerCount = 3; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is OK to create a cube map array texture view with arrayLayerCount % 6 == 0. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::CubeArray; |
| descriptor.arrayLayerCount = 12; |
| texture.CreateView(&descriptor); |
| } |
| |
| // It is an error to create a cube map array texture view with arrayLayerCount % 6 != 0. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::CubeArray; |
| descriptor.arrayLayerCount = 11; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is an error to create a cube map texture view with width != height. |
| { |
| wgpu::Texture nonSquareTexture = Create2DArrayTexture(device, 18, 32, 16, 5); |
| |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::Cube; |
| descriptor.arrayLayerCount = 6; |
| ASSERT_DEVICE_ERROR(nonSquareTexture.CreateView(&descriptor)); |
| } |
| |
| // It is an error to create a cube map array texture view with width != height. |
| { |
| wgpu::Texture nonSquareTexture = Create2DArrayTexture(device, 18, 32, 16, 5); |
| |
| wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; |
| descriptor.dimension = wgpu::TextureViewDimension::CubeArray; |
| descriptor.arrayLayerCount = 12; |
| ASSERT_DEVICE_ERROR(nonSquareTexture.CreateView(&descriptor)); |
| } |
| } |
| |
| // Test the format compatibility rules when creating a texture view. |
| TEST_F(TextureViewValidationTest, TextureViewFormatCompatibility) { |
| wgpu::TextureDescriptor textureDesc = {}; |
| textureDesc.size.width = 4; |
| textureDesc.size.height = 4; |
| textureDesc.usage = wgpu::TextureUsage::TextureBinding; |
| |
| wgpu::TextureViewDescriptor viewDesc = {}; |
| |
| // It is an error to create an sRGB texture view from an RGB texture, without viewFormats. |
| { |
| textureDesc.format = wgpu::TextureFormat::RGBA8Unorm; |
| viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| } |
| |
| // It is an error to create an RGB texture view from an sRGB texture, without viewFormats. |
| { |
| textureDesc.format = wgpu::TextureFormat::BGRA8UnormSrgb; |
| viewDesc.format = wgpu::TextureFormat::BGRA8Unorm; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| } |
| |
| // It is an error to create a texture view with a depth-stencil format of an RGBA texture. |
| { |
| textureDesc.format = wgpu::TextureFormat::RGBA8Unorm; |
| viewDesc.format = wgpu::TextureFormat::Depth24PlusStencil8; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| } |
| |
| // It is an error to create a texture view with a depth format of a depth-stencil texture. |
| { |
| textureDesc.format = wgpu::TextureFormat::Depth24PlusStencil8; |
| viewDesc.format = wgpu::TextureFormat::Depth24Plus; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| } |
| |
| // It is invalid to create a texture view with a combined depth-stencil format if only |
| // the depth aspect is selected. |
| { |
| textureDesc.format = wgpu::TextureFormat::Depth24PlusStencil8; |
| viewDesc.format = wgpu::TextureFormat::Depth24PlusStencil8; |
| viewDesc.aspect = wgpu::TextureAspect::DepthOnly; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| } |
| |
| // It is invalid to create a texture view with a combined depth-stencil format if only |
| // the stencil aspect is selected. |
| { |
| textureDesc.format = wgpu::TextureFormat::Depth24PlusStencil8; |
| viewDesc.format = wgpu::TextureFormat::Depth24PlusStencil8; |
| viewDesc.aspect = wgpu::TextureAspect::StencilOnly; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| } |
| |
| // It is valid to create a texture view with a depth format of a depth-stencil texture |
| // if the depth only aspect is selected. |
| { |
| textureDesc.format = wgpu::TextureFormat::Depth24PlusStencil8; |
| viewDesc.format = wgpu::TextureFormat::Depth24Plus; |
| viewDesc.aspect = wgpu::TextureAspect::DepthOnly; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| texture.CreateView(&viewDesc); |
| |
| viewDesc = {}; |
| } |
| |
| // Prep for testing a single view format in viewFormats. |
| wgpu::TextureFormat viewFormat; |
| textureDesc.viewFormats = &viewFormat; |
| textureDesc.viewFormatCount = 1; |
| |
| // An aspect format is not a valid view format of a depth-stencil texture. |
| { |
| textureDesc.format = wgpu::TextureFormat::Depth24PlusStencil8; |
| viewFormat = wgpu::TextureFormat::Depth24Plus; |
| ASSERT_DEVICE_ERROR(device.CreateTexture(&textureDesc)); |
| } |
| |
| // Test that a RGBA texture can be viewed as both RGBA and RGBASrgb, but not BGRA or |
| // BGRASrgb |
| { |
| textureDesc.format = wgpu::TextureFormat::RGBA8Unorm; |
| viewFormat = wgpu::TextureFormat::RGBA8UnormSrgb; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| |
| viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb; |
| texture.CreateView(&viewDesc); |
| |
| viewDesc.format = wgpu::TextureFormat::RGBA8Unorm; |
| texture.CreateView(&viewDesc); |
| |
| viewDesc.format = wgpu::TextureFormat::BGRA8Unorm; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| |
| viewDesc.format = wgpu::TextureFormat::BGRA8UnormSrgb; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| } |
| |
| // Test that a BGRASrgb texture can be viewed as both BGRA and BGRASrgb, but not RGBA or |
| // RGBASrgb |
| { |
| textureDesc.format = wgpu::TextureFormat::BGRA8UnormSrgb; |
| viewFormat = wgpu::TextureFormat::BGRA8Unorm; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| |
| viewDesc.format = wgpu::TextureFormat::BGRA8Unorm; |
| texture.CreateView(&viewDesc); |
| |
| viewDesc.format = wgpu::TextureFormat::BGRA8UnormSrgb; |
| texture.CreateView(&viewDesc); |
| |
| viewDesc.format = wgpu::TextureFormat::RGBA8Unorm; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| |
| viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| } |
| |
| // Test an RGBA format may be viewed as RGBA (same) |
| { |
| textureDesc.format = wgpu::TextureFormat::RGBA8Unorm; |
| viewFormat = wgpu::TextureFormat::RGBA8Unorm; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| |
| viewDesc.format = wgpu::TextureFormat::RGBA8Unorm; |
| texture.CreateView(&viewDesc); |
| |
| viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| } |
| |
| // Test that duplicate, and multiple view formats are allowed. |
| { |
| std::array<wgpu::TextureFormat, 5> viewFormats = { |
| wgpu::TextureFormat::RGBA8UnormSrgb, wgpu::TextureFormat::RGBA8Unorm, |
| wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureFormat::RGBA8UnormSrgb, |
| wgpu::TextureFormat::RGBA8Unorm, |
| }; |
| textureDesc.viewFormats = viewFormats.data(); |
| textureDesc.viewFormatCount = viewFormats.size(); |
| |
| textureDesc.format = wgpu::TextureFormat::RGBA8Unorm; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| |
| viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb; |
| texture.CreateView(&viewDesc); |
| |
| viewDesc.format = wgpu::TextureFormat::RGBA8Unorm; |
| texture.CreateView(&viewDesc); |
| |
| viewDesc.format = wgpu::TextureFormat::BGRA8Unorm; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| |
| viewDesc.format = wgpu::TextureFormat::BGRA8UnormSrgb; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| } |
| } |
| |
| // Test that it's valid to create a texture view from a destroyed texture |
| TEST_F(TextureViewValidationTest, DestroyCreateTextureView) { |
| wgpu::Texture texture = Create2DArrayTexture(device, 1); |
| wgpu::TextureViewDescriptor descriptor = |
| CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D); |
| texture.Destroy(); |
| texture.CreateView(&descriptor); |
| } |
| |
| // Test that the selected TextureAspects must exist in the texture format |
| TEST_F(TextureViewValidationTest, AspectMustExist) { |
| wgpu::TextureDescriptor descriptor = {}; |
| descriptor.size = {1, 1, 1}; |
| descriptor.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment; |
| |
| // Can select: All and DepthOnly from Depth32Float, but not StencilOnly |
| { |
| descriptor.format = wgpu::TextureFormat::Depth32Float; |
| wgpu::Texture texture = device.CreateTexture(&descriptor); |
| |
| wgpu::TextureViewDescriptor viewDescriptor = {}; |
| viewDescriptor.aspect = wgpu::TextureAspect::All; |
| texture.CreateView(&viewDescriptor); |
| |
| viewDescriptor.aspect = wgpu::TextureAspect::DepthOnly; |
| texture.CreateView(&viewDescriptor); |
| |
| viewDescriptor.aspect = wgpu::TextureAspect::StencilOnly; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDescriptor)); |
| } |
| |
| // Can select: All, DepthOnly, and StencilOnly from Depth24PlusStencil8 |
| { |
| descriptor.format = wgpu::TextureFormat::Depth24PlusStencil8; |
| wgpu::Texture texture = device.CreateTexture(&descriptor); |
| |
| wgpu::TextureViewDescriptor viewDescriptor = {}; |
| viewDescriptor.aspect = wgpu::TextureAspect::All; |
| texture.CreateView(&viewDescriptor); |
| |
| viewDescriptor.aspect = wgpu::TextureAspect::DepthOnly; |
| texture.CreateView(&viewDescriptor); |
| |
| viewDescriptor.aspect = wgpu::TextureAspect::StencilOnly; |
| texture.CreateView(&viewDescriptor); |
| } |
| |
| // Can select: All from RGBA8Unorm |
| { |
| descriptor.format = wgpu::TextureFormat::RGBA8Unorm; |
| wgpu::Texture texture = device.CreateTexture(&descriptor); |
| |
| wgpu::TextureViewDescriptor viewDescriptor = {}; |
| viewDescriptor.aspect = wgpu::TextureAspect::All; |
| texture.CreateView(&viewDescriptor); |
| |
| viewDescriptor.aspect = wgpu::TextureAspect::DepthOnly; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDescriptor)); |
| |
| viewDescriptor.aspect = wgpu::TextureAspect::StencilOnly; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDescriptor)); |
| } |
| } |
| |
| // Test that CreateErrorView creates an invalid texture view but doesn't produce an error. |
| TEST_F(TextureViewValidationTest, CreateErrorView) { |
| wgpu::Texture texture = Create2DArrayTexture(device, 1); |
| wgpu::TextureViewDescriptor descriptor = |
| CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D); |
| |
| // Creating the error texture view doesn't produce an error. |
| wgpu::TextureView view = texture.CreateErrorView(&descriptor); |
| |
| // Using the error texture view will throw an error. |
| wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout( |
| device, {{0, wgpu::ShaderStage::Fragment, wgpu::TextureSampleType::Float}}); |
| ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, view}})); |
| } |
| |
| // Tests that texture view usage is validated for the texture view format and is compatible with the |
| // source texture usages |
| TEST_F(TextureViewValidationTest, Usage) { |
| wgpu::TextureFormat viewFormats[] = {wgpu::TextureFormat::RGBA8Unorm, |
| wgpu::TextureFormat::RGBA8UnormSrgb}; |
| |
| wgpu::TextureDescriptor textureDescriptor; |
| textureDescriptor.dimension = wgpu::TextureDimension::e2D; |
| textureDescriptor.size.width = kWidth; |
| textureDescriptor.size.height = kHeight; |
| textureDescriptor.sampleCount = 1; |
| textureDescriptor.format = wgpu::TextureFormat::RGBA8Unorm; |
| textureDescriptor.mipLevelCount = 1; |
| textureDescriptor.usage = wgpu::TextureUsage::TextureBinding | |
| wgpu::TextureUsage::RenderAttachment | |
| wgpu::TextureUsage::StorageBinding; |
| textureDescriptor.viewFormats = viewFormats; |
| textureDescriptor.viewFormatCount = 2; |
| wgpu::Texture texture = device.CreateTexture(&textureDescriptor); |
| |
| wgpu::TextureViewDescriptor base2DTextureViewDescriptor; |
| base2DTextureViewDescriptor.format = kDefaultTextureFormat; |
| base2DTextureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D; |
| base2DTextureViewDescriptor.baseMipLevel = 0; |
| base2DTextureViewDescriptor.mipLevelCount = 1; |
| base2DTextureViewDescriptor.baseArrayLayer = 0; |
| base2DTextureViewDescriptor.arrayLayerCount = 1; |
| |
| // It is an error to request a usage outside of the source texture's usage |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; |
| descriptor.usage |= wgpu::TextureUsage::CopyDst; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // It is an error to create a view with RGBA8UnormSrgb and default usage which includes |
| // StorageBinding |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; |
| descriptor.format = wgpu::TextureFormat::RGBA8UnormSrgb; |
| descriptor.usage = wgpu::TextureUsage::None; |
| |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| |
| // A view can be created for RGBA8UnormSrgb with a compatible subset of usages |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; |
| descriptor.format = wgpu::TextureFormat::RGBA8UnormSrgb; |
| descriptor.usage = |
| wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment; |
| texture.CreateView(&descriptor); |
| } |
| } |
| |
| // Test setting swizzle when creating a texture view requires feature. |
| TEST_F(TextureViewValidationTest, SwizzleRequiresFeature) { |
| wgpu::TextureDescriptor textureDesc = {}; |
| textureDesc.size = {kWidth, kHeight, kDepth}; |
| textureDesc.usage = wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::RenderAttachment; |
| textureDesc.format = kDefaultTextureFormat; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| |
| wgpu::TextureViewDescriptor viewDesc = {}; |
| wgpu::TextureComponentSwizzleDescriptor swizzleDesc = {}; |
| viewDesc.nextInChain = &swizzleDesc; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| } |
| |
| enum class SwizzleChannel { R, G, B, A }; |
| |
| class ComponentSwizzleTextureViewValidationTests : public ValidationTest { |
| protected: |
| std::vector<wgpu::FeatureName> GetRequiredFeatures() override { |
| return {wgpu::FeatureName::TextureComponentSwizzle}; |
| } |
| |
| wgpu::TextureComponentSwizzleDescriptor GetIdenticalButOneSwizzleDesc( |
| SwizzleChannel channel, |
| std::optional<wgpu::ComponentSwizzle> swizzle = std::nullopt) { |
| wgpu::TextureComponentSwizzleDescriptor desc = {}; |
| switch (channel) { |
| case (SwizzleChannel::R): { |
| desc.swizzle.r = swizzle.value_or(wgpu::ComponentSwizzle::Zero); |
| break; |
| } |
| case (SwizzleChannel::G): { |
| desc.swizzle.g = swizzle.value_or(wgpu::ComponentSwizzle::One); |
| break; |
| } |
| case (SwizzleChannel::B): { |
| desc.swizzle.b = swizzle.value_or(wgpu::ComponentSwizzle::R); |
| break; |
| } |
| case (SwizzleChannel::A): { |
| desc.swizzle.a = swizzle.value_or(wgpu::ComponentSwizzle::G); |
| break; |
| } |
| } |
| return desc; |
| } |
| }; |
| |
| // Test setting invalid component swizzle when creating a texture view fails. |
| TEST_F(ComponentSwizzleTextureViewValidationTests, InvalidComponentSwizzle) { |
| wgpu::TextureDescriptor textureDesc = {}; |
| textureDesc.size = {kWidth, kHeight, kDepth}; |
| textureDesc.usage = wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::RenderAttachment; |
| textureDesc.format = kDefaultTextureFormat; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| |
| // Control case: identity swizzle |
| wgpu::TextureViewDescriptor viewDesc = {}; |
| wgpu::TextureComponentSwizzleDescriptor swizzleDesc = {}; |
| viewDesc.nextInChain = &swizzleDesc; |
| texture.CreateView(&viewDesc); |
| |
| // Invalid component swizzle for each channel |
| for (auto changedChannel : |
| {SwizzleChannel::R, SwizzleChannel::G, SwizzleChannel::B, SwizzleChannel::A}) { |
| swizzleDesc = |
| GetIdenticalButOneSwizzleDesc(changedChannel, static_cast<wgpu::ComponentSwizzle>(-1)); |
| ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc)); |
| } |
| } |
| |
| // Test storage binding requires identity swizzle. |
| TEST_F(ComponentSwizzleTextureViewValidationTests, StorageBindingRequiresIdentitySwizzle) { |
| wgpu::TextureDescriptor textureDesc = {}; |
| textureDesc.size = {kWidth, kHeight, 1}; |
| textureDesc.usage = wgpu::TextureUsage::StorageBinding; |
| textureDesc.format = kDefaultTextureFormat; |
| wgpu::Texture texture = device.CreateTexture(&textureDesc); |
| |
| wgpu::TextureViewDescriptor viewDesc = {}; |
| wgpu::TextureComponentSwizzleDescriptor swizzleDesc = {}; |
| viewDesc.nextInChain = &swizzleDesc; |
| |
| wgpu::ComputePipelineDescriptor cpDesc; |
| cpDesc.compute.module = utils::CreateShaderModule(device, R"( |
| @group(0) @binding(0) var texture : texture_storage_2d<rgba8unorm, read>; |
| |
| @compute @workgroup_size(1) fn main() { |
| var res : vec4f = textureLoad(texture, vec2i(0, 0)); |
| })"); |
| wgpu::ComputePipeline cp = device.CreateComputePipeline(&cpDesc); |
| |
| // Control case: identity swizzle |
| utils::MakeBindGroup(device, cp.GetBindGroupLayout(0), {{0, texture.CreateView(&viewDesc)}}); |
| |
| // Non-identical swizzle cases |
| for (auto changedChannel : |
| {SwizzleChannel::R, SwizzleChannel::G, SwizzleChannel::B, SwizzleChannel::A}) { |
| swizzleDesc = GetIdenticalButOneSwizzleDesc(changedChannel); |
| ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, cp.GetBindGroupLayout(0), |
| {{0, texture.CreateView(&viewDesc)}}), |
| testing::HasSubstr("must be identity")); |
| } |
| } |
| |
| // Test color attachment requires identity swizzle. |
| TEST_F(ComponentSwizzleTextureViewValidationTests, ColorAttachmentRequiresIdentitySwizzle) { |
| wgpu::Texture texture = Create2DArrayTexture(device, /*arrayLayerCount=*/1, kWidth, kHeight, |
| /*mipLevelCount=*/1); |
| wgpu::TextureViewDescriptor viewDesc = {}; |
| wgpu::TextureComponentSwizzleDescriptor swizzleDesc = {}; |
| viewDesc.nextInChain = &swizzleDesc; |
| |
| // Control case: identity swizzle |
| { |
| utils::ComboRenderPassDescriptor renderPassDesc({texture.CreateView(&viewDesc)}); |
| wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); |
| wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPassDesc); |
| renderPassEncoder.End(); |
| commandEncoder.Finish(); |
| } |
| |
| // Non-identical swizzle cases |
| for (auto changedChannel : |
| {SwizzleChannel::R, SwizzleChannel::G, SwizzleChannel::B, SwizzleChannel::A}) { |
| swizzleDesc = GetIdenticalButOneSwizzleDesc(changedChannel); |
| utils::ComboRenderPassDescriptor renderPassDesc({texture.CreateView(&viewDesc)}); |
| wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); |
| wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPassDesc); |
| renderPassEncoder.End(); |
| ASSERT_DEVICE_ERROR(commandEncoder.Finish(), |
| testing::HasSubstr("The color attachment swizzle must be identity")); |
| } |
| } |
| |
| // Test resolve target requires identity swizzle. |
| TEST_F(ComponentSwizzleTextureViewValidationTests, ResolveTargetRequiresIdentitySwizzle) { |
| wgpu::Texture texture = Create2DArrayTexture(device, /*arrayLayerCount=*/1, kWidth, kHeight, |
| /*mipLevelCount=*/1, /*sampleCount=*/4); |
| wgpu::TextureView view = texture.CreateView(); |
| |
| wgpu::Texture resolveTargetTexture = |
| Create2DArrayTexture(device, /*arrayLayerCount=*/1, kWidth, kHeight, |
| /*mipLevelCount=*/1); |
| wgpu::TextureViewDescriptor viewDesc = {}; |
| wgpu::TextureComponentSwizzleDescriptor swizzleDesc = {}; |
| viewDesc.nextInChain = &swizzleDesc; |
| |
| // Control case: identity swizzle |
| { |
| utils::ComboRenderPassDescriptor renderPassDesc({view}); |
| renderPassDesc.cColorAttachments[0].resolveTarget = |
| resolveTargetTexture.CreateView(&viewDesc); |
| wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); |
| wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPassDesc); |
| renderPassEncoder.End(); |
| commandEncoder.Finish(); |
| } |
| |
| // Non-identical swizzle cases |
| for (auto changedChannel : |
| {SwizzleChannel::R, SwizzleChannel::G, SwizzleChannel::B, SwizzleChannel::A}) { |
| swizzleDesc = GetIdenticalButOneSwizzleDesc(changedChannel); |
| utils::ComboRenderPassDescriptor renderPassDesc({view}); |
| renderPassDesc.cColorAttachments[0].resolveTarget = |
| resolveTargetTexture.CreateView(&viewDesc); |
| wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); |
| wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPassDesc); |
| renderPassEncoder.End(); |
| ASSERT_DEVICE_ERROR(commandEncoder.Finish(), |
| testing::HasSubstr("The resolve target swizzle must be identity")); |
| } |
| } |
| |
| // Test depth stencil attachment requires identity swizzle. |
| TEST_F(ComponentSwizzleTextureViewValidationTests, DepthStencilAttachmentRequiresIdentitySwizzle) { |
| wgpu::Texture texture = Create2DArrayTexture(device, /*arrayLayerCount=*/1, kWidth, kHeight, |
| /*mipLevelCount=*/1); |
| wgpu::TextureView view = texture.CreateView(); |
| |
| wgpu::TextureDescriptor textureDesc = {}; |
| textureDesc.size = {kWidth, kHeight, 1}; |
| textureDesc.usage = wgpu::TextureUsage::RenderAttachment; |
| textureDesc.format = wgpu::TextureFormat::Depth24PlusStencil8; |
| wgpu::Texture depthStencilTexture = device.CreateTexture(&textureDesc); |
| |
| wgpu::TextureViewDescriptor viewDesc = {}; |
| viewDesc.aspect = wgpu::TextureAspect::All; |
| wgpu::TextureComponentSwizzleDescriptor swizzleDesc = {}; |
| viewDesc.nextInChain = &swizzleDesc; |
| |
| // Control case: identity swizzle |
| { |
| utils::ComboRenderPassDescriptor renderPassDesc({view}, |
| depthStencilTexture.CreateView(&viewDesc)); |
| wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); |
| wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPassDesc); |
| renderPassEncoder.End(); |
| commandEncoder.Finish(); |
| } |
| |
| // Non-identical swizzle cases |
| for (auto changedChannel : |
| {SwizzleChannel::R, SwizzleChannel::G, SwizzleChannel::B, SwizzleChannel::A}) { |
| swizzleDesc = GetIdenticalButOneSwizzleDesc(changedChannel); |
| utils::ComboRenderPassDescriptor renderPassDesc({view}, |
| depthStencilTexture.CreateView(&viewDesc)); |
| wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); |
| wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPassDesc); |
| renderPassEncoder.End(); |
| ASSERT_DEVICE_ERROR( |
| commandEncoder.Finish(), |
| testing::HasSubstr("The depth stencil attachment swizzle must be identity")); |
| } |
| } |
| |
| class D32S8TextureViewValidationTests : public ValidationTest { |
| protected: |
| std::vector<wgpu::FeatureName> GetRequiredFeatures() override { |
| return {wgpu::FeatureName::Depth32FloatStencil8}; |
| } |
| }; |
| |
| // Test that the selected TextureAspects must exist in the Depth32FloatStencil8 texture format |
| TEST_F(D32S8TextureViewValidationTests, AspectMustExist) { |
| wgpu::Texture texture = |
| CreateDepthStencilTexture(device, wgpu::TextureFormat::Depth32FloatStencil8); |
| |
| // Can select: All, DepthOnly, and StencilOnly from Depth32FloatStencil8 |
| { |
| wgpu::TextureViewDescriptor viewDescriptor = {}; |
| viewDescriptor.aspect = wgpu::TextureAspect::All; |
| texture.CreateView(&viewDescriptor); |
| |
| viewDescriptor.aspect = wgpu::TextureAspect::DepthOnly; |
| texture.CreateView(&viewDescriptor); |
| |
| viewDescriptor.aspect = wgpu::TextureAspect::StencilOnly; |
| texture.CreateView(&viewDescriptor); |
| } |
| } |
| |
| // Test the format compatibility rules when creating a texture view. |
| TEST_F(D32S8TextureViewValidationTests, TextureViewFormatCompatibility) { |
| wgpu::Texture texture = |
| CreateDepthStencilTexture(device, wgpu::TextureFormat::Depth32FloatStencil8); |
| |
| wgpu::TextureViewDescriptor base2DTextureViewDescriptor = |
| CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D); |
| |
| // It is an error to create a texture view in color format on a depth-stencil texture. |
| { |
| wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; |
| descriptor.format = wgpu::TextureFormat::RGBA8Unorm; |
| ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); |
| } |
| } |
| |
| class TexelBufferViewValidationTest : public ValidationTest { |
| protected: |
| wgpu::Buffer CreateTexelBuffer(uint64_t size, wgpu::BufferUsage usage) { |
| wgpu::BufferDescriptor desc; |
| desc.size = size; |
| desc.usage = usage; |
| return device.CreateBuffer(&desc); |
| } |
| }; |
| |
| // Valid texel buffer view creation |
| TEST_F(TexelBufferViewValidationTest, CreationSuccess) { |
| constexpr uint64_t kSize = 4 * 4; // 4 texels of RGBA8Uint |
| wgpu::Buffer buffer = |
| CreateTexelBuffer(kSize, wgpu::BufferUsage::TexelBuffer | wgpu::BufferUsage::CopySrc); |
| |
| wgpu::TexelBufferViewDescriptor viewDesc; |
| viewDesc.format = wgpu::TextureFormat::RGBA8Uint; |
| viewDesc.offset = 0; |
| viewDesc.size = kSize; |
| |
| buffer.CreateTexelView(&viewDesc); |
| } |
| |
| // Format must not be undefined |
| TEST_F(TexelBufferViewValidationTest, UndefinedFormat) { |
| wgpu::Buffer buffer = CreateTexelBuffer(256, wgpu::BufferUsage::TexelBuffer); |
| |
| wgpu::TexelBufferViewDescriptor viewDesc; |
| viewDesc.format = wgpu::TextureFormat::Undefined; |
| viewDesc.offset = 0; |
| viewDesc.size = 256; |
| |
| ASSERT_DEVICE_ERROR(buffer.CreateTexelView(&viewDesc)); |
| } |
| |
| // Offset must be aligned to the texel size |
| TEST_F(TexelBufferViewValidationTest, OffsetAlignment) { |
| wgpu::Buffer buffer = CreateTexelBuffer(512, wgpu::BufferUsage::TexelBuffer); |
| |
| wgpu::TexelBufferViewDescriptor viewDesc; |
| viewDesc.format = wgpu::TextureFormat::RGBA8Uint; |
| viewDesc.offset = 2; // Not aligned to 4-byte texel |
| viewDesc.size = 256; |
| |
| ASSERT_DEVICE_ERROR(buffer.CreateTexelView(&viewDesc)); |
| } |
| |
| // Size must be multiple of texel size |
| TEST_F(TexelBufferViewValidationTest, SizeMustBeMultipleOfTexel) { |
| wgpu::Buffer buffer = CreateTexelBuffer(512, wgpu::BufferUsage::TexelBuffer); |
| |
| wgpu::TexelBufferViewDescriptor viewDesc; |
| viewDesc.format = wgpu::TextureFormat::RGBA8Uint; |
| viewDesc.offset = 256; |
| viewDesc.size = 3; // Not multiple of 4-byte texel |
| |
| ASSERT_DEVICE_ERROR(buffer.CreateTexelView(&viewDesc)); |
| } |
| |
| // Range may not exceed buffer size |
| TEST_F(TexelBufferViewValidationTest, RangeExceedsBuffer) { |
| wgpu::Buffer buffer = CreateTexelBuffer(256, wgpu::BufferUsage::TexelBuffer); |
| |
| wgpu::TexelBufferViewDescriptor viewDesc; |
| viewDesc.format = wgpu::TextureFormat::RGBA8Uint; |
| viewDesc.offset = 0; |
| viewDesc.size = 512; // Larger than buffer |
| |
| ASSERT_DEVICE_ERROR(buffer.CreateTexelView(&viewDesc)); |
| } |
| |
| // Depth formats are not allowed |
| TEST_F(TexelBufferViewValidationTest, DepthFormatNotAllowed) { |
| wgpu::Buffer buffer = CreateTexelBuffer(256, wgpu::BufferUsage::TexelBuffer); |
| |
| wgpu::TexelBufferViewDescriptor viewDesc; |
| viewDesc.format = wgpu::TextureFormat::Depth24Plus; |
| viewDesc.offset = 0; |
| viewDesc.size = 256; |
| |
| ASSERT_DEVICE_ERROR(buffer.CreateTexelView(&viewDesc)); |
| } |
| |
| // R32Float is allowed |
| TEST_F(TexelBufferViewValidationTest, R32FloatAllowed) { |
| wgpu::Buffer buffer = CreateTexelBuffer(256, wgpu::BufferUsage::TexelBuffer); |
| |
| wgpu::TexelBufferViewDescriptor viewDesc; |
| viewDesc.format = wgpu::TextureFormat::R32Float; |
| viewDesc.offset = 0; |
| viewDesc.size = 256; |
| |
| buffer.CreateTexelView(&viewDesc); |
| } |
| |
| // RG8Uint is not a supported texel format |
| TEST_F(TexelBufferViewValidationTest, ColorFormatNotAllowed) { |
| wgpu::Buffer buffer = CreateTexelBuffer(256, wgpu::BufferUsage::TexelBuffer); |
| |
| wgpu::TexelBufferViewDescriptor viewDesc; |
| viewDesc.format = wgpu::TextureFormat::RG8Uint; |
| viewDesc.offset = 0; |
| viewDesc.size = 256; |
| |
| ASSERT_DEVICE_ERROR(buffer.CreateTexelView(&viewDesc)); |
| } |
| |
| } // anonymous namespace |
| } // namespace dawn |