From 0e92e9bf3ce51f0908fc146e48998582d8d63647 Mon Sep 17 00:00:00 2001 From: Brandon Jones Date: Thu, 1 Apr 2021 20:46:42 +0000 Subject: [PATCH] Add GPUExternalTexture Types Adds GPUExternalTexture-related types, as well as Device::ImportExternalTexture. Adds a basic unit and end2end test. Bug: dawn:728 Change-Id: Iee9533eb872c493a089cccd500748f1a61457407 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/46060 Reviewed-by: Austin Eng Reviewed-by: Corentin Wallez Commit-Queue: Brandon Jones --- dawn.json | 24 ++++ src/dawn_native/BUILD.gn | 2 + src/dawn_native/CMakeLists.txt | 2 + src/dawn_native/Device.cpp | 20 ++++ src/dawn_native/Device.h | 4 + src/dawn_native/ExternalTexture.cpp | 111 ++++++++++++++++++ src/dawn_native/ExternalTexture.h | 51 ++++++++ src/dawn_native/Format.h | 5 +- src/dawn_native/Subresource.h | 4 + src/tests/BUILD.gn | 2 + src/tests/end2end/ExternalTextureTests.cpp | 69 +++++++++++ .../validation/ExternalTextureTests.cpp | 99 ++++++++++++++++ 12 files changed, 389 insertions(+), 4 deletions(-) create mode 100644 src/dawn_native/ExternalTexture.cpp create mode 100644 src/dawn_native/ExternalTexture.h create mode 100644 src/tests/end2end/ExternalTextureTests.cpp create mode 100644 src/tests/unittests/validation/ExternalTextureTests.cpp diff --git a/dawn.json b/dawn.json index b8abb108fb..ea011fd769 100644 --- a/dawn.json +++ b/dawn.json @@ -766,6 +766,13 @@ "name": "get default queue", "returns": "queue" }, + { + "name": "create external texture", + "returns": "external texture", + "args": [ + {"name": "external texture descriptor", "type": "external texture descriptor", "annotation": "const*"} + ] + }, { "name": "inject error", "args": [ @@ -879,6 +886,23 @@ {"name": "depth", "type": "uint32_t", "default": 1} ] }, + "external texture": { + "category": "object", + "methods": [ + { + "name": "destroy", + "returns": "void" + } + ] + }, + "external texture descriptor": { + "category": "structure", + "extensible": true, + "members": [ + {"name": "plane 0", "type": "texture view"}, + {"name": "format", "type": "texture format"} + ] + }, "fence": { "category": "object", "methods": [ diff --git a/src/dawn_native/BUILD.gn b/src/dawn_native/BUILD.gn index b3bd28ce47..284e61f763 100644 --- a/src/dawn_native/BUILD.gn +++ b/src/dawn_native/BUILD.gn @@ -220,6 +220,8 @@ source_set("dawn_native_sources") { "ErrorScope.h", "Extensions.cpp", "Extensions.h", + "ExternalTexture.cpp", + "ExternalTexture.h", "Fence.cpp", "Fence.h", "Format.cpp", diff --git a/src/dawn_native/CMakeLists.txt b/src/dawn_native/CMakeLists.txt index 915ffd87b0..e6039b397d 100644 --- a/src/dawn_native/CMakeLists.txt +++ b/src/dawn_native/CMakeLists.txt @@ -88,6 +88,8 @@ target_sources(dawn_native PRIVATE "ErrorScope.h" "Extensions.cpp" "Extensions.h" + "ExternalTexture.cpp" + "ExternalTexture.h" "ObjectContentHasher.cpp" "ObjectContentHasher.h" "Fence.cpp" diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp index c146588b73..df30f3d183 100644 --- a/src/dawn_native/Device.cpp +++ b/src/dawn_native/Device.cpp @@ -27,6 +27,7 @@ #include "dawn_native/DynamicUploader.h" #include "dawn_native/ErrorData.h" #include "dawn_native/ErrorScope.h" +#include "dawn_native/ExternalTexture.h" #include "dawn_native/Fence.h" #include "dawn_native/Instance.h" #include "dawn_native/InternalPipelineStore.h" @@ -997,6 +998,16 @@ namespace dawn_native { return APIGetQueue(); } + ExternalTextureBase* DeviceBase::APICreateExternalTexture( + const ExternalTextureDescriptor* descriptor) { + Ref result = nullptr; + if (ConsumedError(CreateExternalTextureInternal(descriptor), &result)) { + return ExternalTextureBase::MakeError(this); + } + + return result.Detach(); + } + void DeviceBase::ApplyExtensions(const DeviceDescriptor* deviceDescriptor) { ASSERT(deviceDescriptor); ASSERT(GetAdapter()->SupportsAllRequestedExtensions(deviceDescriptor->requiredExtensions)); @@ -1116,6 +1127,15 @@ namespace dawn_native { return GetOrCreatePipelineLayout(descriptor); } + ResultOrError> DeviceBase::CreateExternalTextureInternal( + const ExternalTextureDescriptor* descriptor) { + if (IsValidationEnabled()) { + DAWN_TRY(ValidateExternalTextureDescriptor(this, descriptor)); + } + + return ExternalTextureBase::Create(this, descriptor); + } + ResultOrError> DeviceBase::CreateQuerySetInternal( const QuerySetDescriptor* descriptor) { DAWN_TRY(ValidateIsAlive()); diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h index f3a3b37afc..cf64a3837e 100644 --- a/src/dawn_native/Device.h +++ b/src/dawn_native/Device.h @@ -36,6 +36,7 @@ namespace dawn_native { class CreatePipelineAsyncTracker; class DynamicUploader; class ErrorScopeStack; + class ExternalTextureBase; class PersistentCache; class StagingBufferBase; struct InternalPipelineStore; @@ -159,6 +160,7 @@ namespace dawn_native { const RenderBundleEncoderDescriptor* descriptor); RenderPipelineBase* APICreateRenderPipeline(const RenderPipelineDescriptor* descriptor); RenderPipelineBase* APICreateRenderPipeline2(const RenderPipelineDescriptor2* descriptor); + ExternalTextureBase* APICreateExternalTexture(const ExternalTextureDescriptor* descriptor); SamplerBase* APICreateSampler(const SamplerDescriptor* descriptor); ShaderModuleBase* APICreateShaderModule(const ShaderModuleDescriptor* descriptor); SwapChainBase* APICreateSwapChain(Surface* surface, const SwapChainDescriptor* descriptor); @@ -308,6 +310,8 @@ namespace dawn_native { const ComputePipelineDescriptor* descriptor); ResultOrError> CreatePipelineLayoutInternal( const PipelineLayoutDescriptor* descriptor); + ResultOrError> CreateExternalTextureInternal( + const ExternalTextureDescriptor* descriptor); ResultOrError> CreateQuerySetInternal( const QuerySetDescriptor* descriptor); ResultOrError> CreateRenderBundleEncoderInternal( diff --git a/src/dawn_native/ExternalTexture.cpp b/src/dawn_native/ExternalTexture.cpp new file mode 100644 index 0000000000..b65ba467d0 --- /dev/null +++ b/src/dawn_native/ExternalTexture.cpp @@ -0,0 +1,111 @@ +// 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 "dawn_native/ExternalTexture.h" + +#include "dawn_native/Device.h" +#include "dawn_native/Texture.h" + +#include "dawn_native/dawn_platform.h" + +namespace dawn_native { + + MaybeError ValidateExternalTexturePlane(const TextureViewBase* textureView, + wgpu::TextureFormat format) { + if (textureView->GetFormat().format != format) { + return DAWN_VALIDATION_ERROR( + "The external texture descriptor specifies a texture format that is different from " + "at least one of the passed texture views."); + } + + if ((textureView->GetTexture()->GetUsage() & wgpu::TextureUsage::Sampled) != + wgpu::TextureUsage::Sampled) { + return DAWN_VALIDATION_ERROR( + "The external texture descriptor specifies a texture that was not created with " + "TextureUsage::Sampled."); + } + + if (textureView->GetDimension() != wgpu::TextureViewDimension::e2D) { + return DAWN_VALIDATION_ERROR( + "The external texture descriptor contains a texture view with a non-2D dimension."); + } + + if (textureView->GetLevelCount() > 1) { + return DAWN_VALIDATION_ERROR( + "The external texture descriptor contains a texture view with a level count " + "greater than 1."); + } + + return {}; + } + + MaybeError ValidateExternalTextureDescriptor(const DeviceBase* device, + const ExternalTextureDescriptor* descriptor) { + ASSERT(descriptor); + ASSERT(descriptor->plane0); + + const Format* format; + DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->format)); + + switch (descriptor->format) { + case wgpu::TextureFormat::RGBA8Unorm: + case wgpu::TextureFormat::BGRA8Unorm: + case wgpu::TextureFormat::RGBA16Float: + DAWN_TRY(ValidateExternalTexturePlane(descriptor->plane0, descriptor->format)); + break; + default: + return DAWN_VALIDATION_ERROR( + "The external texture descriptor specifies an unsupported format."); + } + + return {}; + } + + // static + ResultOrError> ExternalTextureBase::Create( + DeviceBase* device, + const ExternalTextureDescriptor* descriptor) { + Ref externalTexture = + AcquireRef(new ExternalTextureBase(device, descriptor)); + return std::move(externalTexture); + } + + ExternalTextureBase::ExternalTextureBase(DeviceBase* device, + const ExternalTextureDescriptor* descriptor) + : ObjectBase(device) { + textureViews[0] = descriptor->plane0; + } + + ExternalTextureBase::ExternalTextureBase(DeviceBase* device, ObjectBase::ErrorTag tag) + : ObjectBase(device, tag) { + } + + std::array, kMaxPlanesPerFormat> ExternalTextureBase::GetTextureViews() + const { + return textureViews; + } + + void ExternalTextureBase::APIDestroy() { + if (GetDevice()->ConsumedError(GetDevice()->ValidateObject(this))) { + return; + } + ASSERT(!IsError()); + } + + // static + ExternalTextureBase* ExternalTextureBase::MakeError(DeviceBase* device) { + return new ExternalTextureBase(device, ObjectBase::kError); + } + +} // namespace dawn_native \ No newline at end of file diff --git a/src/dawn_native/ExternalTexture.h b/src/dawn_native/ExternalTexture.h new file mode 100644 index 0000000000..7bc81e2551 --- /dev/null +++ b/src/dawn_native/ExternalTexture.h @@ -0,0 +1,51 @@ +// 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. + +#ifndef DAWNNATIVE_EXTERNALTEXTURE_H_ +#define DAWNNATIVE_EXTERNALTEXTURE_H_ + +#include "dawn_native/Error.h" +#include "dawn_native/ObjectBase.h" +#include "dawn_native/Subresource.h" + +#include + +namespace dawn_native { + + struct ExternalTextureDescriptor; + class TextureViewBase; + + MaybeError ValidateExternalTextureDescriptor(const DeviceBase* device, + const ExternalTextureDescriptor* descriptor); + + class ExternalTextureBase : public ObjectBase { + public: + static ResultOrError> Create( + DeviceBase* device, + const ExternalTextureDescriptor* descriptor); + + std::array, kMaxPlanesPerFormat> GetTextureViews() const; + + static ExternalTextureBase* MakeError(DeviceBase* device); + + void APIDestroy(); + + private: + ExternalTextureBase(DeviceBase* device, const ExternalTextureDescriptor* descriptor); + ExternalTextureBase(DeviceBase* device, ObjectBase::ErrorTag tag); + std::array, kMaxPlanesPerFormat> textureViews; + }; +} // namespace dawn_native + +#endif // DAWNNATIVE_EXTERNALTEXTURE_H_ \ No newline at end of file diff --git a/src/dawn_native/Format.h b/src/dawn_native/Format.h index fefccf345c..01457d1369 100644 --- a/src/dawn_native/Format.h +++ b/src/dawn_native/Format.h @@ -20,6 +20,7 @@ #include "common/ityp_bitset.h" #include "dawn_native/EnumClassBitmasks.h" #include "dawn_native/Error.h" +#include "dawn_native/Subresource.h" #include @@ -75,10 +76,6 @@ namespace dawn_native { // exact number of known format. static constexpr size_t kKnownFormatCount = 55; - // The maximum number of planes per format Dawn knows about. Asserts in BuildFormatTable that - // the per plane index does not exceed the known maximum plane count - static constexpr uint32_t kMaxPlanesPerFormat = 2; - struct Format; using FormatTable = std::array; diff --git a/src/dawn_native/Subresource.h b/src/dawn_native/Subresource.h index ce9b3f3f09..643b7bc022 100644 --- a/src/dawn_native/Subresource.h +++ b/src/dawn_native/Subresource.h @@ -94,6 +94,10 @@ namespace dawn_native { uint8_t GetAspectIndex(Aspect aspect); uint8_t GetAspectCount(Aspect aspects); + // The maximum number of planes per format Dawn knows about. Asserts in BuildFormatTable that + // the per plane index does not exceed the known maximum plane count. + static constexpr uint32_t kMaxPlanesPerFormat = 3; + } // namespace dawn_native namespace wgpu { diff --git a/src/tests/BUILD.gn b/src/tests/BUILD.gn index 850cb8b6ab..bce93a7cd5 100644 --- a/src/tests/BUILD.gn +++ b/src/tests/BUILD.gn @@ -192,6 +192,7 @@ test("dawn_unittests") { "unittests/validation/DrawIndirectValidationTests.cpp", "unittests/validation/DynamicStateCommandValidationTests.cpp", "unittests/validation/ErrorScopeValidationTests.cpp", + "unittests/validation/ExternalTextureTests.cpp", "unittests/validation/FenceValidationTests.cpp", "unittests/validation/GetBindGroupLayoutValidationTests.cpp", "unittests/validation/IndexBufferValidationTests.cpp", @@ -308,6 +309,7 @@ source_set("dawn_end2end_tests_sources") { "end2end/DrawTests.cpp", "end2end/DynamicBufferOffsetTests.cpp", "end2end/EntryPointTests.cpp", + "end2end/ExternalTextureTests.cpp", "end2end/FenceTests.cpp", "end2end/FirstIndexOffsetTests.cpp", "end2end/GpuMemorySynchronizationTests.cpp", diff --git a/src/tests/end2end/ExternalTextureTests.cpp b/src/tests/end2end/ExternalTextureTests.cpp new file mode 100644 index 0000000000..cfb48e4f23 --- /dev/null +++ b/src/tests/end2end/ExternalTextureTests.cpp @@ -0,0 +1,69 @@ +// 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/DawnTest.h" + +namespace { + + wgpu::Texture Create2DTexture(wgpu::Device device, + uint32_t width, + uint32_t height, + wgpu::TextureFormat format, + wgpu::TextureUsage usage) { + wgpu::TextureDescriptor descriptor; + descriptor.dimension = wgpu::TextureDimension::e2D; + descriptor.size.width = width; + descriptor.size.height = height; + descriptor.size.depthOrArrayLayers = 1; + descriptor.sampleCount = 1; + descriptor.format = format; + descriptor.mipLevelCount = 1; + descriptor.usage = usage; + return device.CreateTexture(&descriptor); + } + + class ExternalTextureTests : public DawnTest { + protected: + static constexpr uint32_t kWidth = 4; + static constexpr uint32_t kHeight = 4; + static constexpr wgpu::TextureFormat kFormat = wgpu::TextureFormat::RGBA8Unorm; + static constexpr wgpu::TextureUsage kSampledUsage = wgpu::TextureUsage::Sampled; + }; +} // anonymous namespace + +TEST_P(ExternalTextureTests, CreateExternalTextureSuccess) { + DAWN_SKIP_TEST_IF(UsesWire()); + + wgpu::Texture texture = Create2DTexture(device, kWidth, kHeight, kFormat, kSampledUsage); + + // Create a texture view for the external texture + wgpu::TextureView view = texture.CreateView(); + + // Create an ExternalTextureDescriptor from the texture view + wgpu::ExternalTextureDescriptor externalDesc; + externalDesc.plane0 = view; + externalDesc.format = kFormat; + + // Import the external texture + wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc); + + ASSERT_NE(externalTexture.Get(), nullptr); +} + +DAWN_INSTANTIATE_TEST(ExternalTextureTests, + D3D12Backend(), + MetalBackend(), + OpenGLBackend(), + OpenGLESBackend(), + VulkanBackend()); \ No newline at end of file diff --git a/src/tests/unittests/validation/ExternalTextureTests.cpp b/src/tests/unittests/validation/ExternalTextureTests.cpp new file mode 100644 index 0000000000..70c9590a13 --- /dev/null +++ b/src/tests/unittests/validation/ExternalTextureTests.cpp @@ -0,0 +1,99 @@ +// 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" + +namespace { + class ExternalTextureTest : public ValidationTest { + public: + wgpu::TextureDescriptor CreateDefaultTextureDescriptor() { + wgpu::TextureDescriptor descriptor; + descriptor.size.width = kWidth; + descriptor.size.height = kHeight; + descriptor.size.depth = kDefaultDepth; + descriptor.mipLevelCount = kDefaultMipLevels; + descriptor.sampleCount = kDefaultSampleCount; + descriptor.dimension = wgpu::TextureDimension::e2D; + descriptor.format = kDefaultTextureFormat; + descriptor.usage = wgpu::TextureUsage::Sampled; + return descriptor; + } + + protected: + 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; + }; + + 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)); + } + } + +} // namespace \ No newline at end of file