blob: 57ec556e16088893bdb80d3df7c7af008b2d6d56 [file] [log] [blame] [edit]
// Copyright 2021 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 "tests/unittests/validation/ValidationTest.h"
#include "utils/ComboRenderPipelineDescriptor.h"
#include "utils/WGPUHelpers.h"
namespace {
class ExternalTextureTest : public ValidationTest {
public:
wgpu::TextureDescriptor CreateDefaultTextureDescriptor() {
wgpu::TextureDescriptor descriptor;
descriptor.size.width = kWidth;
descriptor.size.height = kHeight;
descriptor.size.depthOrArrayLayers = kDefaultDepth;
descriptor.mipLevelCount = kDefaultMipLevels;
descriptor.sampleCount = kDefaultSampleCount;
descriptor.dimension = wgpu::TextureDimension::e2D;
descriptor.format = kDefaultTextureFormat;
descriptor.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::RenderAttachment;
return descriptor;
}
protected:
void SetUp() override {
ValidationTest::SetUp();
queue = device.GetQueue();
}
wgpu::RenderPipeline CreateBasicRenderPipeline(wgpu::ExternalTexture externalTexture) {
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}});
bindGroup = utils::MakeBindGroup(device, bgl, {{0, externalTexture}});
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
[[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
return vec4<f32>();
})");
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
[[group(0), binding(0)]] var myExternalTexture: texture_external;
[[stage(fragment)]] fn main() {
textureDimensions(myExternalTexture);
})");
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
pipelineDescriptor.vertex.module = vsModule;
pipelineDescriptor.cFragment.module = fsModule;
wgpu::PipelineLayout pipelineLayout = utils::MakeBasicPipelineLayout(device, &bgl);
pipelineDescriptor.layout = pipelineLayout;
return device.CreateRenderPipeline(&pipelineDescriptor);
}
static constexpr uint32_t kWidth = 32;
static constexpr uint32_t kHeight = 32;
static constexpr uint32_t kDefaultDepth = 1;
static constexpr uint32_t kDefaultMipLevels = 1;
static constexpr uint32_t kDefaultSampleCount = 1;
static constexpr wgpu::TextureFormat kDefaultTextureFormat =
wgpu::TextureFormat::RGBA8Unorm;
wgpu::Queue queue;
wgpu::RenderPipeline renderPipeline;
wgpu::BindGroup bindGroup;
};
TEST_F(ExternalTextureTest, CreateExternalTextureValidation) {
wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
wgpu::ExternalTextureDescriptor externalDesc;
externalDesc.format = kDefaultTextureFormat;
// Creating an external texture from a 2D, single-subresource texture should succeed.
{
wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
externalDesc.plane0 = texture.CreateView();
device.CreateExternalTexture(&externalDesc);
}
// Creating an external texture with a mismatched texture view format should fail.
{
textureDescriptor.format = wgpu::TextureFormat::RGBA8Uint;
wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
externalDesc.plane0 = texture.CreateView();
ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
}
// Creating an external texture from a non-2D texture should fail.
{
textureDescriptor.dimension = wgpu::TextureDimension::e3D;
wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
externalDesc.plane0 = internalTexture.CreateView();
ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
}
// Creating an external texture from a texture with mip count > 1 should fail.
{
textureDescriptor.mipLevelCount = 2;
wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
externalDesc.plane0 = internalTexture.CreateView();
ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
}
// Creating an external texture from a texture without TextureUsage::Sampled should fail.
{
textureDescriptor.mipLevelCount = 2;
wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
externalDesc.plane0 = internalTexture.CreateView();
ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
}
// Creating an external texture with an unsupported format should fail.
{
constexpr wgpu::TextureFormat kUnsupportedFormat = wgpu::TextureFormat::R8Uint;
textureDescriptor.format = kUnsupportedFormat;
wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
externalDesc.plane0 = internalTexture.CreateView();
externalDesc.format = kUnsupportedFormat;
ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
}
// Creating an external texture with an error texture view should fail.
{
wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
wgpu::TextureViewDescriptor errorViewDescriptor;
errorViewDescriptor.format = kDefaultTextureFormat;
errorViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
errorViewDescriptor.mipLevelCount = 1;
errorViewDescriptor.arrayLayerCount = 2;
ASSERT_DEVICE_ERROR(wgpu::TextureView errorTextureView =
internalTexture.CreateView(&errorViewDescriptor));
externalDesc.plane0 = errorTextureView;
externalDesc.format = kDefaultTextureFormat;
ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
}
}
// Test that submitting a command encoder that contains a destroyed external texture results in
// an error.
TEST_F(ExternalTextureTest, SubmitDestroyedExternalTexture) {
wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
wgpu::ExternalTextureDescriptor externalDesc;
externalDesc.format = kDefaultTextureFormat;
externalDesc.plane0 = texture.CreateView();
wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
wgpu::RenderPipeline pipeline = CreateBasicRenderPipeline(externalTexture);
// Create another texture to use as a color attachment.
wgpu::TextureDescriptor renderTextureDescriptor = CreateDefaultTextureDescriptor();
wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor);
wgpu::TextureView renderView = renderTexture.CreateView();
utils::ComboRenderPassDescriptor renderPass({renderView}, nullptr);
// Control case should succeed.
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
{
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Draw(1);
pass.EndPass();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
}
// Destroying the external texture should result in an error.
{
externalTexture.Destroy();
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
{
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Draw(1);
pass.EndPass();
}
wgpu::CommandBuffer commands = encoder.Finish();
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
}
// Test that submitting a command encoder that contains a destroyed external texture plane
// results in an error.
TEST_F(ExternalTextureTest, SubmitDestroyedExternalTexturePlane) {
wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
wgpu::ExternalTextureDescriptor externalDesc;
externalDesc.format = kDefaultTextureFormat;
externalDesc.plane0 = texture.CreateView();
wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
wgpu::RenderPipeline pipeline = CreateBasicRenderPipeline(externalTexture);
// Create another texture to use as a color attachment.
wgpu::TextureDescriptor renderTextureDescriptor = CreateDefaultTextureDescriptor();
wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor);
wgpu::TextureView renderView = renderTexture.CreateView();
utils::ComboRenderPassDescriptor renderPass({renderView}, nullptr);
// Control case should succeed.
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
{
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Draw(1);
pass.EndPass();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
}
// Destroying an external texture underlying plane should result in an error.
{
texture.Destroy();
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
{
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Draw(1);
pass.EndPass();
}
wgpu::CommandBuffer commands = encoder.Finish();
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
}
} // namespace