| // Copyright 2023 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 "dawn/native/d3d12/SharedTextureMemoryD3D12.h" | |
| #include <utility> | |
| #include "dawn/native/ChainUtils.h" | |
| #include "dawn/native/d3d/D3DError.h" | |
| #include "dawn/native/d3d/KeyedMutex.h" | |
| #include "dawn/native/d3d/UtilsD3D.h" | |
| #include "dawn/native/d3d12/DeviceD3D12.h" | |
| #include "dawn/native/d3d12/TextureD3D12.h" | |
| namespace dawn::native::d3d12 { | |
| // static | |
| ResultOrError<Ref<SharedTextureMemory>> SharedTextureMemory::Create( | |
| Device* device, | |
| StringView label, | |
| const SharedTextureMemoryDXGISharedHandleDescriptor* descriptor) { | |
| DAWN_INVALID_IF(descriptor->handle == nullptr, "shared HANDLE is missing."); | |
| ComPtr<ID3D12Resource> d3d12Resource; | |
| Ref<d3d::KeyedMutex> keyedMutex; | |
| DAWN_TRY(device->ImportSharedHandleResource(descriptor->handle, descriptor->useKeyedMutex, | |
| d3d12Resource, keyedMutex)); | |
| D3D12_RESOURCE_DESC desc = d3d12Resource->GetDesc(); | |
| DAWN_INVALID_IF(desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D, | |
| "Resource dimension (%d) was not Texture2D", desc.Dimension); | |
| DAWN_INVALID_IF(desc.DepthOrArraySize != 1, "Resource DepthOrArraySize (%d) was not 1", | |
| desc.DepthOrArraySize); | |
| DAWN_INVALID_IF(desc.MipLevels != 1, "Resource MipLevels (%d) was not 1", desc.MipLevels); | |
| DAWN_INVALID_IF(desc.SampleDesc.Count != 1, "Resource SampleDesc.Count (%d) was not 1", | |
| desc.SampleDesc.Count); | |
| const CombinedLimits& limits = device->GetLimits(); | |
| DAWN_INVALID_IF(desc.Width > limits.v1.maxTextureDimension2D, | |
| "Resource Width (%u) exceeds maxTextureDimension2D (%u).", desc.Width, | |
| limits.v1.maxTextureDimension2D); | |
| DAWN_INVALID_IF(desc.Height > limits.v1.maxTextureDimension2D, | |
| "Resource Height (%u) exceeds maxTextureDimension2D (%u).", desc.Height, | |
| limits.v1.maxTextureDimension2D); | |
| DAWN_INVALID_IF(!(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS), | |
| "Resource did not have D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS flag"); | |
| SharedTextureMemoryProperties properties; | |
| properties.size = {static_cast<uint32_t>(desc.Width), static_cast<uint32_t>(desc.Height), 1}; | |
| DAWN_TRY_ASSIGN(properties.format, d3d::FromUncompressedColorDXGITextureFormat(desc.Format)); | |
| // The usages that the underlying D3D12 texture supports are partially | |
| // dependent on its creation flags. Note that the SharedTextureMemory | |
| // frontend takes care of stripping out any usages that are not supported | |
| // for `format`. | |
| wgpu::TextureUsage storageBindingUsage = | |
| (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) | |
| ? wgpu::TextureUsage::StorageBinding | |
| : wgpu::TextureUsage::None; | |
| wgpu::TextureUsage renderAttachmentUsage = | |
| (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) | |
| ? wgpu::TextureUsage::RenderAttachment | |
| : wgpu::TextureUsage::None; | |
| properties.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst | | |
| wgpu::TextureUsage::TextureBinding | storageBindingUsage | | |
| renderAttachmentUsage; | |
| auto result = AcquireRef(new SharedTextureMemory( | |
| device, label, properties, std::move(d3d12Resource), std::move(keyedMutex))); | |
| result->Initialize(); | |
| return result; | |
| } | |
| SharedTextureMemory::SharedTextureMemory(Device* device, | |
| StringView label, | |
| SharedTextureMemoryProperties properties, | |
| ComPtr<ID3D12Resource> resource, | |
| Ref<d3d::KeyedMutex> keyedMutex) | |
| : d3d::SharedTextureMemory(device, label, properties), | |
| mResource(std::move(resource)), | |
| mKeyedMutex(std::move(keyedMutex)) {} | |
| void SharedTextureMemory::DestroyImpl() { | |
| ToBackend(GetDevice())->ReferenceUntilUnused(std::move(mResource)); | |
| mKeyedMutex = nullptr; | |
| } | |
| ID3D12Resource* SharedTextureMemory::GetD3DResource() const { | |
| return mResource.Get(); | |
| } | |
| d3d::KeyedMutex* SharedTextureMemory::GetKeyedMutex() const { | |
| return mKeyedMutex.Get(); | |
| } | |
| ResultOrError<Ref<TextureBase>> SharedTextureMemory::CreateTextureImpl( | |
| const UnpackedPtr<TextureDescriptor>& descriptor) { | |
| return Texture::CreateFromSharedTextureMemory(this, descriptor); | |
| } | |
| MaybeError SharedTextureMemory::BeginAccessImpl( | |
| TextureBase* texture, | |
| const UnpackedPtr<BeginAccessDescriptor>& descriptor) { | |
| DAWN_TRY(d3d::SharedTextureMemory::BeginAccessImpl(texture, descriptor)); | |
| if (auto* beginState = descriptor.Get<SharedTextureMemoryD3DSwapchainBeginState>()) { | |
| ToBackend(texture)->SetIsSwapchainTexture(beginState->isSwapchain); | |
| } | |
| // Reset state to COMMON. BeginAccess contains a list of fences to wait on after | |
| // which the texture's usage will complete on the GPU. | |
| // All textures created from SharedTextureMemory must have | |
| // flag D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS. All textures with that flag are eligible | |
| // to decay to COMMON. | |
| // https://learn.microsoft.com/en-us/windows/win32/direct3d12/using-resource-barriers-to-synchronize-resource-states-in-direct3d-12#state-decay-to-common | |
| ToBackend(texture)->ResetSubresourceStateAndDecayToCommon(); | |
| return {}; | |
| } | |
| ResultOrError<FenceAndSignalValue> SharedTextureMemory::EndAccessImpl( | |
| TextureBase* texture, | |
| ExecutionSerial lastUsageSerial, | |
| UnpackedPtr<EndAccessState>& state) { | |
| ToBackend(texture)->NotifySwapChainPresentToPIX(); | |
| return d3d::SharedTextureMemory::EndAccessImpl(texture, lastUsageSerial, state); | |
| } | |
| } // namespace dawn::native::d3d12 |