diff --git a/dawn.json b/dawn.json index 5a952150a6..09c1f06c87 100644 --- a/dawn.json +++ b/dawn.json @@ -1441,7 +1441,8 @@ {"value": 1005, "name": "chromium experimental dp4a", "tags": ["dawn"]}, {"value": 1006, "name": "timestamp query inside passes", "tags": ["dawn"]}, {"value": 1007, "name": "implicit device synchronization", "tags": ["dawn", "native"]}, - {"value": 1008, "name": "surface capabilities", "tags": ["dawn", "native"]} + {"value": 1008, "name": "surface capabilities", "tags": ["dawn", "native"]}, + {"value": 1009, "name": "transient attachments", "tags": ["dawn"]} ] }, "filter mode": { @@ -2829,7 +2830,8 @@ {"value": 4, "name": "texture binding"}, {"value": 8, "name": "storage binding"}, {"value": 16, "name": "render attachment"}, - {"value": 32, "name": "present", "tags": ["dawn"]} + {"value": 32, "name": "present", "tags": ["dawn"]}, + {"value": 64, "name": "transient attachment", "tags": ["dawn"]} ] }, "texture view descriptor": { diff --git a/docs/dawn/features/transient_attachments.md b/docs/dawn/features/transient_attachments.md new file mode 100644 index 0000000000..0c67e86e88 --- /dev/null +++ b/docs/dawn/features/transient_attachments.md @@ -0,0 +1,24 @@ +# Transient Attachments + +The `transient-attachments` feature allows creation of attachments that allow +render pass operations to stay in tile memory, avoiding VRAM traffic and +potentially avoiding VRAM allocation for the textures. + +Example Usage: +``` +wgpu::TextureDescriptor desc; +desc.format = wgpu::TextureFormat::RGBA8Unorm; +desc.size = {1, 1, 1}; +desc.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment; + +auto transientTexture = device.CreateTexture(&desc); + +// Can now create views from the texture to serve as transient attachments, e.g. +// as color attachments in a render pipeline. +``` + +Notes: +- Only supported usage is wgpu::TextureUsage::RenderAttachment | +wgpu::TextureUsage::TransientAttachment +- It is not possible to load from or store to TextureViews that are used as +transient attachments diff --git a/src/dawn/native/CommandEncoder.cpp b/src/dawn/native/CommandEncoder.cpp index 3e3363ee48..3efaa66005 100644 --- a/src/dawn/native/CommandEncoder.cpp +++ b/src/dawn/native/CommandEncoder.cpp @@ -238,6 +238,16 @@ MaybeError ValidateRenderPassColorAttachment(DeviceBase* device, DAWN_TRY(ValidateStoreOp(colorAttachment.storeOp)); DAWN_INVALID_IF(colorAttachment.loadOp == wgpu::LoadOp::Undefined, "loadOp must be set."); DAWN_INVALID_IF(colorAttachment.storeOp == wgpu::StoreOp::Undefined, "storeOp must be set."); + if (attachment->GetTexture()->GetUsage() & wgpu::TextureUsage::TransientAttachment) { + DAWN_INVALID_IF(colorAttachment.loadOp != wgpu::LoadOp::Clear, + "The color attachment %s has the load op set to %s while its usage (%s) " + "has the transient attachment bit set.", + attachment, wgpu::LoadOp::Load, attachment->GetTexture()->GetUsage()); + DAWN_INVALID_IF(colorAttachment.storeOp != wgpu::StoreOp::Discard, + "The color attachment %s has the store op set to %s while its usage (%s) " + "has the transient attachment bit set.", + attachment, wgpu::StoreOp::Store, attachment->GetTexture()->GetUsage()); + } const dawn::native::Color& clearValue = colorAttachment.clearValue; if (colorAttachment.loadOp == wgpu::LoadOp::Clear) { diff --git a/src/dawn/native/Features.cpp b/src/dawn/native/Features.cpp index b097e1617b..adaff42017 100644 --- a/src/dawn/native/Features.cpp +++ b/src/dawn/native/Features.cpp @@ -107,6 +107,11 @@ static constexpr FeatureEnumAndInfoList kFeatureNameAndInfoList = {{ "Support querying Surface's capabilities such as supported usage flags. This feature also " "enables swap chain to be created with usage other than RenderAttachment.", "https://bugs.chromium.org/p/dawn/issues/detail?id=1760", FeatureInfo::FeatureState::Stable}}, + {Feature::TransientAttachments, + {"transient-attachments", + "Support transient attachments that allow render pass operations to stay in tile memory, " + "avoiding VRAM traffic and potentially avoiding VRAM allocation for the textures.", + "https://bugs.chromium.org/p/dawn/issues/detail?id=1695", FeatureInfo::FeatureState::Stable}}, }}; Feature FromAPIFeature(wgpu::FeatureName feature) { @@ -153,6 +158,8 @@ Feature FromAPIFeature(wgpu::FeatureName feature) { return Feature::ImplicitDeviceSynchronization; case wgpu::FeatureName::SurfaceCapabilities: return Feature::SurfaceCapabilities; + case wgpu::FeatureName::TransientAttachments: + return Feature::TransientAttachments; } return Feature::InvalidEnum; } @@ -195,6 +202,8 @@ wgpu::FeatureName ToAPIFeature(Feature feature) { return wgpu::FeatureName::ImplicitDeviceSynchronization; case Feature::SurfaceCapabilities: return wgpu::FeatureName::SurfaceCapabilities; + case Feature::TransientAttachments: + return wgpu::FeatureName::TransientAttachments; case Feature::EnumCount: break; diff --git a/src/dawn/native/Features.h b/src/dawn/native/Features.h index 0453090ca0..40ea498bd9 100644 --- a/src/dawn/native/Features.h +++ b/src/dawn/native/Features.h @@ -47,6 +47,7 @@ enum class Feature { DawnNative, ImplicitDeviceSynchronization, SurfaceCapabilities, + TransientAttachments, EnumCount, InvalidEnum = EnumCount, diff --git a/src/dawn/native/Texture.cpp b/src/dawn/native/Texture.cpp index 7ded6870e9..6169e4cf77 100644 --- a/src/dawn/native/Texture.cpp +++ b/src/dawn/native/Texture.cpp @@ -286,7 +286,8 @@ MaybeError ValidateTextureSize(const DeviceBase* device, return {}; } -MaybeError ValidateTextureUsage(const TextureDescriptor* descriptor, +MaybeError ValidateTextureUsage(const DeviceBase* device, + const TextureDescriptor* descriptor, wgpu::TextureUsage usage, const Format* format) { DAWN_TRY(dawn::native::ValidateTextureUsage(usage)); @@ -318,6 +319,21 @@ MaybeError ValidateTextureUsage(const TextureDescriptor* descriptor, "The texture usage (%s) includes %s, which is incompatible with the format (%s).", usage, wgpu::TextureUsage::StorageBinding, format->format); + const auto kTransientAttachment = wgpu::TextureUsage::TransientAttachment; + if (usage & kTransientAttachment) { + DAWN_INVALID_IF( + !device->HasFeature(Feature::TransientAttachments), + "The texture usage (%s) includes %s, which requires the %s feature to be set", usage, + kTransientAttachment, FeatureEnumToAPIFeature(Feature::TransientAttachments)); + + const auto kAllowedTransientUsage = + kTransientAttachment | wgpu::TextureUsage::RenderAttachment; + DAWN_INVALID_IF(usage != kAllowedTransientUsage, + "The texture usage (%s) includes %s, which requires that the texture usage " + "be exactly %s", + usage, kTransientAttachment, kAllowedTransientUsage); + } + // Only allows simple readonly texture usages. constexpr wgpu::TextureUsage kValidMultiPlanarUsages = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc; @@ -356,7 +372,7 @@ MaybeError ValidateTextureDescriptor(const DeviceBase* device, usage |= internalUsageDesc->internalUsage; } - DAWN_TRY(ValidateTextureUsage(descriptor, usage, format)); + DAWN_TRY(ValidateTextureUsage(device, descriptor, usage, format)); DAWN_TRY(ValidateTextureDimension(descriptor->dimension)); DAWN_TRY(ValidateSampleCount(descriptor, usage, format)); diff --git a/src/dawn/native/metal/BackendMTL.mm b/src/dawn/native/metal/BackendMTL.mm index 241460d2ee..c751b6adb5 100644 --- a/src/dawn/native/metal/BackendMTL.mm +++ b/src/dawn/native/metal/BackendMTL.mm @@ -513,6 +513,14 @@ class Adapter : public AdapterBase { EnableFeature(Feature::MultiPlanarFormats); } + if (@available(macOS 11.0, iOS 10.0, *)) { + // Memoryless storage mode for Metal textures is available only + // from the Apple2 family of GPUs on. + if ([*mDevice supportsFamily:MTLGPUFamilyApple2]) { + EnableFeature(Feature::TransientAttachments); + } + } + EnableFeature(Feature::IndirectFirstInstance); EnableFeature(Feature::ShaderF16); EnableFeature(Feature::RG11B10UfloatRenderable); diff --git a/src/dawn/native/metal/TextureMTL.mm b/src/dawn/native/metal/TextureMTL.mm index af1074f493..c57074ac21 100644 --- a/src/dawn/native/metal/TextureMTL.mm +++ b/src/dawn/native/metal/TextureMTL.mm @@ -677,7 +677,16 @@ NSRef Texture::CreateMetalTextureDescriptor() const { mtlDesc.usage |= MTLTextureUsagePixelFormatView; } mtlDesc.mipmapLevelCount = GetNumMipLevels(); + + // Create the texture in private storage mode unless the client has + // specified that this texture is for a transient attachment, in which case + // the texture should be created in memoryless storage mode. mtlDesc.storageMode = MTLStorageModePrivate; + if (@available(macOS 11.0, iOS 10.0, *)) { + if (GetInternalUsage() & wgpu::TextureUsage::TransientAttachment) { + mtlDesc.storageMode = MTLStorageModeMemoryless; + } + } // Choose the correct MTLTextureType and paper over differences in how the array layer count // is specified. @@ -778,6 +787,11 @@ MaybeError Texture::InitializeFromIOSurface(const ExternalImageDescriptor* descr const TextureDescriptor* textureDescriptor, IOSurfaceRef ioSurface, std::vector waitEvents) { + DAWN_INVALID_IF( + GetInternalUsage() & wgpu::TextureUsage::TransientAttachment, + "Usage flags (%s) include %s, which is not compatible with creation from IOSurface.", + GetInternalUsage(), wgpu::TextureUsage::TransientAttachment); + mIOSurface = ioSurface; mWaitEvents = std::move(waitEvents); diff --git a/src/dawn/native/vulkan/TextureVk.cpp b/src/dawn/native/vulkan/TextureVk.cpp index b916a8c1c4..8f8aac5c78 100644 --- a/src/dawn/native/vulkan/TextureVk.cpp +++ b/src/dawn/native/vulkan/TextureVk.cpp @@ -494,6 +494,8 @@ VkImageUsageFlags VulkanImageUsage(wgpu::TextureUsage usage, const Format& forma } else { flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; } + // TODO(1695): Check for TransientAttachment flag being present and + // convert it into the proper Vulkan flag. } // Choosing Vulkan image usages should not know about kReadOnlyRenderAttachment because that's @@ -575,6 +577,13 @@ VkImageLayout VulkanImageLayout(const Texture* texture, wgpu::TextureUsage usage case kPresentTextureUsage: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + case wgpu::TextureUsage::TransientAttachment: + // Will be covered by RenderAttachment above, as specification of + // TransientAttachment requires that RenderAttachment also be + // specified. + UNREACHABLE(); + break; + case wgpu::TextureUsage::None: break; } diff --git a/src/dawn/tests/end2end/IOSurfaceWrappingTests.cpp b/src/dawn/tests/end2end/IOSurfaceWrappingTests.cpp index 0c86cde098..47e8fafed6 100644 --- a/src/dawn/tests/end2end/IOSurfaceWrappingTests.cpp +++ b/src/dawn/tests/end2end/IOSurfaceWrappingTests.cpp @@ -209,6 +209,33 @@ TEST_P(IOSurfaceValidationTests, InvalidFormat) { ASSERT_EQ(texture.Get(), nullptr); } +class IOSurfaceTransientAttachmentValidationTests : public IOSurfaceValidationTests { + void SetUp() override { + IOSurfaceValidationTests::SetUp(); + + // Skip all tests if the transient attachments feature is not supported. + DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures({wgpu::FeatureName::TransientAttachments})); + } + + std::vector GetRequiredFeatures() override { + std::vector requiredFeatures = {}; + if (SupportsFeatures({wgpu::FeatureName::TransientAttachments})) { + requiredFeatures.push_back(wgpu::FeatureName::TransientAttachments); + } + return requiredFeatures; + } +}; + +// Test that an error occurs if the transient attachment is specified. +TEST_P(IOSurfaceTransientAttachmentValidationTests, ErrorWhenSpecified) { + DAWN_TEST_UNSUPPORTED_IF(UsesWire()); + + descriptor.usage |= wgpu::TextureUsage::TransientAttachment; + + ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapIOSurface(&descriptor, defaultIOSurface.get())); + ASSERT_EQ(texture.Get(), nullptr); +} + // Fixture to test using IOSurfaces through different usages. // These tests are skipped if the harness is using the wire. class IOSurfaceUsageTests : public IOSurfaceTestBase { @@ -653,5 +680,6 @@ TEST_P(IOSurfaceMultithreadTests, WrapAndClear_OnMultipleThreads) { } DAWN_INSTANTIATE_TEST(IOSurfaceValidationTests, MetalBackend()); +DAWN_INSTANTIATE_TEST(IOSurfaceTransientAttachmentValidationTests, MetalBackend()); DAWN_INSTANTIATE_TEST(IOSurfaceUsageTests, MetalBackend()); DAWN_INSTANTIATE_TEST(IOSurfaceMultithreadTests, MetalBackend()); diff --git a/src/dawn/tests/end2end/MultisampledRenderingTests.cpp b/src/dawn/tests/end2end/MultisampledRenderingTests.cpp index 11c2303216..50a50f1abb 100644 --- a/src/dawn/tests/end2end/MultisampledRenderingTests.cpp +++ b/src/dawn/tests/end2end/MultisampledRenderingTests.cpp @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include "dawn/common/Assert.h" #include "dawn/tests/DawnTest.h" @@ -109,7 +110,8 @@ class MultisampledRenderingTest : public DawnTest { wgpu::Texture CreateTextureForRenderAttachment(wgpu::TextureFormat format, uint32_t sampleCount, uint32_t mipLevelCount = 1, - uint32_t arrayLayerCount = 1) { + uint32_t arrayLayerCount = 1, + bool transientAttachment = false) { wgpu::TextureDescriptor descriptor; descriptor.dimension = wgpu::TextureDimension::e2D; descriptor.size.width = kWidth << (mipLevelCount - 1); @@ -118,7 +120,12 @@ class MultisampledRenderingTest : public DawnTest { descriptor.sampleCount = sampleCount; descriptor.format = format; descriptor.mipLevelCount = mipLevelCount; - descriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc; + if (transientAttachment) { + descriptor.usage = + wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment; + } else { + descriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc; + } return device.CreateTexture(&descriptor); } @@ -1129,6 +1136,58 @@ TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithAlphaToCoverageAndRast } } +class MultisampledRenderingWithTransientAttachmentTest : public MultisampledRenderingTest { + void SetUp() override { + MultisampledRenderingTest::SetUp(); + + // Skip all tests if the transient attachments feature is not supported. + DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures({wgpu::FeatureName::TransientAttachments})); + } + + std::vector GetRequiredFeatures() override { + std::vector requiredFeatures = {}; + if (SupportsFeatures({wgpu::FeatureName::TransientAttachments})) { + requiredFeatures.push_back(wgpu::FeatureName::TransientAttachments); + } + return requiredFeatures; + } +}; + +// Test using one multisampled color transient attachment with resolve target can render correctly. +TEST_P(MultisampledRenderingWithTransientAttachmentTest, ResolveTransientAttachmentInto2DTexture) { + constexpr bool kTestDepth = false; + wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth); + + auto transientMultisampledColorTexture = + CreateTextureForRenderAttachment(kColorFormat, kSampleCount, + /*mipLevelCount=*/1, + /*arrayLayerCount=*/1, + /*transientAttachment=*/true); + auto transientMultisampledColorView = transientMultisampledColorTexture.CreateView(); + constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f}; + + wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); + + // Draw a green triangle. + { + utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest( + {transientMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, + wgpu::LoadOp::Clear, kTestDepth); + + // Note: It is not possible to store into a transient attachment. + renderPass.cColorAttachments[0].storeOp = wgpu::StoreOp::Discard; + + std::array kUniformData = {kGreen.r, kGreen.g, kGreen.b, kGreen.a}; + constexpr uint32_t kSize = sizeof(kUniformData); + EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize); + } + + wgpu::CommandBuffer commandBuffer = commandEncoder.Finish(); + queue.Submit(1, &commandBuffer); + + VerifyResolveTarget(kGreen, mResolveTexture); +} + DAWN_INSTANTIATE_TEST(MultisampledRenderingTest, D3D12Backend(), D3D12Backend({}, {"use_d3d12_resource_heap_tier2"}), @@ -1142,3 +1201,17 @@ DAWN_INSTANTIATE_TEST(MultisampledRenderingTest, MetalBackend({"always_resolve_into_zero_level_and_layer"}), MetalBackend({"always_resolve_into_zero_level_and_layer", "emulate_store_and_msaa_resolve"})); + +DAWN_INSTANTIATE_TEST(MultisampledRenderingWithTransientAttachmentTest, + D3D12Backend(), + D3D12Backend({}, {"use_d3d12_resource_heap_tier2"}), + D3D12Backend({}, {"use_d3d12_render_pass"}), + MetalBackend(), + OpenGLBackend(), + OpenGLESBackend(), + VulkanBackend(), + VulkanBackend({"always_resolve_into_zero_level_and_layer"}), + MetalBackend({"emulate_store_and_msaa_resolve"}), + MetalBackend({"always_resolve_into_zero_level_and_layer"}), + MetalBackend({"always_resolve_into_zero_level_and_layer", + "emulate_store_and_msaa_resolve"})); diff --git a/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp b/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp index 7887717315..77e0b5917d 100644 --- a/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp +++ b/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp @@ -1892,3 +1892,111 @@ TEST_F(InterStageVariableMatchingValidationTest, DifferentInterpolationAttribute } } } + +class RenderPipelineTransientAttachmentValidationTest : public RenderPipelineValidationTest { + protected: + WGPUDevice CreateTestDevice(dawn::native::Adapter dawnAdapter) override { + wgpu::DeviceDescriptor descriptor; + wgpu::FeatureName requiredFeatures[2] = {wgpu::FeatureName::ShaderF16, + wgpu::FeatureName::TransientAttachments}; + descriptor.requiredFeatures = requiredFeatures; + descriptor.requiredFeaturesCount = 2; + return dawnAdapter.CreateDevice(&descriptor); + } +}; + +// Test case where creation should succeed. +TEST_F(RenderPipelineTransientAttachmentValidationTest, CreationSuccess) { + constexpr wgpu::TextureFormat kColorFormat = wgpu::TextureFormat::RGBA8Unorm; + + wgpu::TextureDescriptor textureDescriptor; + textureDescriptor.usage = + wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment; + textureDescriptor.format = kColorFormat; + textureDescriptor.size.width = 4; + textureDescriptor.size.height = 4; + + wgpu::Texture transientTexture = device.CreateTexture(&textureDescriptor); + utils::ComboRenderPassDescriptor renderPassDescriptor({transientTexture.CreateView()}); + + // Set load and store ops to supported values with transient attachments. + renderPassDescriptor.cColorAttachments[0].storeOp = wgpu::StoreOp::Discard; + renderPassDescriptor.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear; + + wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); + wgpu::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDescriptor); + + utils::ComboRenderPipelineDescriptor pipelineDescriptor; + pipelineDescriptor.vertex.module = vsModule; + pipelineDescriptor.cFragment.module = fsModule; + wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor); + + renderPass.SetPipeline(pipeline); + renderPass.End(); + + encoder.Finish(); +} + +// Creation of a pipeline that stores into a transient attachment should cause +// an error. +TEST_F(RenderPipelineTransientAttachmentValidationTest, StoreCausesError) { + constexpr wgpu::TextureFormat kColorFormat = wgpu::TextureFormat::RGBA8Unorm; + + wgpu::TextureDescriptor textureDescriptor; + textureDescriptor.usage = + wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment; + textureDescriptor.format = kColorFormat; + textureDescriptor.size.width = 4; + textureDescriptor.size.height = 4; + + wgpu::Texture transientTexture = device.CreateTexture(&textureDescriptor); + utils::ComboRenderPassDescriptor renderPassDescriptor({transientTexture.CreateView()}); + + renderPassDescriptor.cColorAttachments[0].storeOp = wgpu::StoreOp::Store; + renderPassDescriptor.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear; + + wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); + wgpu::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDescriptor); + + utils::ComboRenderPipelineDescriptor pipelineDescriptor; + pipelineDescriptor.vertex.module = vsModule; + pipelineDescriptor.cFragment.module = fsModule; + wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor); + + renderPass.SetPipeline(pipeline); + renderPass.End(); + + ASSERT_DEVICE_ERROR(encoder.Finish()); +} + +// Creation of a pipeline that loads from a transient attachment should cause +// an error. +TEST_F(RenderPipelineTransientAttachmentValidationTest, LoadCausesError) { + constexpr wgpu::TextureFormat kColorFormat = wgpu::TextureFormat::RGBA8Unorm; + + wgpu::TextureDescriptor textureDescriptor; + textureDescriptor.usage = + wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment; + textureDescriptor.format = kColorFormat; + textureDescriptor.size.width = 4; + textureDescriptor.size.height = 4; + + wgpu::Texture transientTexture = device.CreateTexture(&textureDescriptor); + utils::ComboRenderPassDescriptor renderPassDescriptor({transientTexture.CreateView()}); + + renderPassDescriptor.cColorAttachments[0].storeOp = wgpu::StoreOp::Discard; + renderPassDescriptor.cColorAttachments[0].loadOp = wgpu::LoadOp::Load; + + wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); + wgpu::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDescriptor); + + utils::ComboRenderPipelineDescriptor pipelineDescriptor; + pipelineDescriptor.vertex.module = vsModule; + pipelineDescriptor.cFragment.module = fsModule; + wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor); + + renderPass.SetPipeline(pipeline); + renderPass.End(); + + ASSERT_DEVICE_ERROR(encoder.Finish()); +} diff --git a/src/dawn/tests/unittests/validation/TextureValidationTests.cpp b/src/dawn/tests/unittests/validation/TextureValidationTests.cpp index bc3f33c140..96364a6607 100644 --- a/src/dawn/tests/unittests/validation/TextureValidationTests.cpp +++ b/src/dawn/tests/unittests/validation/TextureValidationTests.cpp @@ -1025,4 +1025,60 @@ TEST_F(TextureValidationTest, APIValidateTextureDescriptor) { ASSERT_DEVICE_ERROR(device.ValidateTextureDescriptor(&desc)); } +// Tests that specification of the transient attachment on an unsupported device +// causes an error. +TEST_F(TextureValidationTest, TransientAttachmentOnUnsupportedDevice) { + wgpu::TextureDescriptor desc; + desc.format = wgpu::TextureFormat::RGBA8Unorm; + desc.size = {1, 1, 1}; + desc.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment; + + ASSERT_DEVICE_ERROR(device.CreateTexture(&desc)); +} + +class TransientAttachmentValidationTest : public TextureValidationTest { + protected: + WGPUDevice CreateTestDevice(dawn::native::Adapter dawnAdapter) override { + wgpu::DeviceDescriptor descriptor; + wgpu::FeatureName requiredFeatures[1] = {wgpu::FeatureName::TransientAttachments}; + descriptor.requiredFeatures = requiredFeatures; + descriptor.requiredFeaturesCount = 1; + return dawnAdapter.CreateDevice(&descriptor); + } +}; + +// Tests that specification of the transient attachment with supported usage on +// a supported device does not raise a validation error. +TEST_F(TransientAttachmentValidationTest, Success) { + wgpu::TextureDescriptor desc; + desc.format = wgpu::TextureFormat::RGBA8Unorm; + desc.size = {1, 1, 1}; + desc.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment; + + device.CreateTexture(&desc); +} + +// Tests that specification of the transient attachment without specification of +// the render attachment causes an error. +TEST_F(TransientAttachmentValidationTest, NoRenderAttachment) { + wgpu::TextureDescriptor desc; + desc.format = wgpu::TextureFormat::RGBA8Unorm; + desc.size = {1, 1, 1}; + desc.usage = wgpu::TextureUsage::TransientAttachment; + + ASSERT_DEVICE_ERROR(device.CreateTexture(&desc)); +} + +// Tests that specification of the transient attachment with flags beyond just +// render attachment causes an error. +TEST_F(TransientAttachmentValidationTest, FlagsBeyondRenderAttachment) { + wgpu::TextureDescriptor desc; + desc.format = wgpu::TextureFormat::RGBA8Unorm; + desc.size = {1, 1, 1}; + desc.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment | + wgpu::TextureUsage::CopySrc; + + ASSERT_DEVICE_ERROR(device.CreateTexture(&desc)); +} + } // namespace diff --git a/src/dawn/wire/SupportedFeatures.cpp b/src/dawn/wire/SupportedFeatures.cpp index 3bad7c624b..97811fa1ce 100644 --- a/src/dawn/wire/SupportedFeatures.cpp +++ b/src/dawn/wire/SupportedFeatures.cpp @@ -42,6 +42,7 @@ bool IsFeatureSupported(WGPUFeatureName feature) { case WGPUFeatureName_ShaderF16: case WGPUFeatureName_RG11B10UfloatRenderable: case WGPUFeatureName_BGRA8UnormStorage: + case WGPUFeatureName_TransientAttachments: return true; }