blob: 268e430d95476692337f9c1e532e2489ac9019cb [file] [log] [blame]
// Copyright 2022 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/d3d12/ExternalImageDXGIImpl.h"
#include <utility>
#include <vector>
#include "dawn/common/Log.h"
#include "dawn/native/D3D12Backend.h"
#include "dawn/native/DawnNative.h"
#include "dawn/native/d3d12/D3D11on12Util.h"
#include "dawn/native/d3d12/DeviceD3D12.h"
namespace dawn::native::d3d12 {
ExternalImageDXGIImpl::ExternalImageDXGIImpl(Device* backendDevice,
Microsoft::WRL::ComPtr<ID3D12Resource> d3d12Resource,
const TextureDescriptor* textureDescriptor,
bool useFenceSynchronization)
: mBackendDevice(backendDevice),
mD3D12Resource(std::move(d3d12Resource)),
mUseFenceSynchronization(useFenceSynchronization),
mD3D11on12ResourceCache(std::make_unique<D3D11on12ResourceCache>()),
mUsage(textureDescriptor->usage),
mDimension(textureDescriptor->dimension),
mSize(textureDescriptor->size),
mFormat(textureDescriptor->format),
mMipLevelCount(textureDescriptor->mipLevelCount),
mSampleCount(textureDescriptor->sampleCount) {
ASSERT(mBackendDevice != nullptr);
ASSERT(mD3D12Resource != nullptr);
ASSERT(!textureDescriptor->nextInChain || textureDescriptor->nextInChain->sType ==
wgpu::SType::DawnTextureInternalUsageDescriptor);
if (textureDescriptor->nextInChain) {
mUsageInternal = reinterpret_cast<const wgpu::DawnTextureInternalUsageDescriptor*>(
textureDescriptor->nextInChain)
->internalUsage;
}
}
ExternalImageDXGIImpl::~ExternalImageDXGIImpl() {
Destroy();
}
bool ExternalImageDXGIImpl::IsValid() const {
return IsInList();
}
void ExternalImageDXGIImpl::Destroy() {
if (IsInList()) {
RemoveFromList();
mBackendDevice = nullptr;
mD3D12Resource = nullptr;
mD3D11on12ResourceCache = nullptr;
}
}
WGPUTexture ExternalImageDXGIImpl::BeginAccess(
const ExternalImageDXGIBeginAccessDescriptor* descriptor) {
ASSERT(mBackendDevice != nullptr);
ASSERT(descriptor != nullptr);
// Ensure the texture usage is allowed
if (!IsSubset(descriptor->usage, static_cast<WGPUTextureUsageFlags>(mUsage))) {
dawn::ErrorLog() << "Texture usage is not valid for external image";
return nullptr;
}
TextureDescriptor textureDescriptor = {};
textureDescriptor.usage = static_cast<wgpu::TextureUsage>(descriptor->usage);
textureDescriptor.dimension = mDimension;
textureDescriptor.size = {mSize.width, mSize.height, mSize.depthOrArrayLayers};
textureDescriptor.format = mFormat;
textureDescriptor.mipLevelCount = mMipLevelCount;
textureDescriptor.sampleCount = mSampleCount;
DawnTextureInternalUsageDescriptor internalDesc = {};
if (mUsageInternal != wgpu::TextureUsage::None) {
textureDescriptor.nextInChain = &internalDesc;
internalDesc.internalUsage = mUsageInternal;
internalDesc.sType = wgpu::SType::DawnTextureInternalUsageDescriptor;
}
std::vector<Ref<Fence>> waitFences;
Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource;
if (mUseFenceSynchronization) {
for (const ExternalImageDXGIFenceDescriptor& fenceDescriptor : descriptor->waitFences) {
ASSERT(fenceDescriptor.fenceHandle != nullptr);
// TODO(sunnyps): Use a fence cache instead of re-importing fences on each BeginAccess.
Ref<Fence> fence;
if (mBackendDevice->ConsumedError(
Fence::CreateFromHandle(mBackendDevice->GetD3D12Device(),
fenceDescriptor.fenceHandle,
fenceDescriptor.fenceValue),
&fence)) {
dawn::ErrorLog() << "Unable to create D3D12 fence for external image";
return nullptr;
}
waitFences.push_back(std::move(fence));
}
} else {
d3d11on12Resource = mD3D11on12ResourceCache->GetOrCreateD3D11on12Resource(
mBackendDevice, mD3D12Resource.Get());
if (d3d11on12Resource == nullptr) {
dawn::ErrorLog() << "Unable to create 11on12 resource for external image";
return nullptr;
}
}
Ref<TextureBase> texture = mBackendDevice->CreateD3D12ExternalTexture(
&textureDescriptor, mD3D12Resource, std::move(waitFences), std::move(d3d11on12Resource),
descriptor->isSwapChainTexture, descriptor->isInitialized);
return ToAPI(texture.Detach());
}
void ExternalImageDXGIImpl::EndAccess(WGPUTexture texture,
ExternalImageDXGIFenceDescriptor* signalFence) {
ASSERT(signalFence != nullptr);
Texture* backendTexture = ToBackend(FromAPI(texture));
ASSERT(backendTexture != nullptr);
if (mUseFenceSynchronization) {
ExecutionSerial fenceValue;
if (mBackendDevice->ConsumedError(backendTexture->EndAccess(), &fenceValue)) {
dawn::ErrorLog() << "D3D12 fence end access failed";
return;
}
signalFence->fenceHandle = mBackendDevice->GetFenceHandle();
signalFence->fenceValue = static_cast<uint64_t>(fenceValue);
}
}
} // namespace dawn::native::d3d12