blob: 8d79b1ed1fe15a7c8ef3d138dfe396156073d314 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/service/shared_image/d3d_image_utils.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
using dawn::native::ExternalImageDescriptor;
using dawn::native::d3d::ExternalImageDescriptorD3D11Texture;
using dawn::native::d3d::ExternalImageDescriptorDXGISharedHandle;
using dawn::native::d3d::ExternalImageDXGI;
namespace gpu {
namespace {
wgpu::TextureFormat DXGIToWGPUFormat(DXGI_FORMAT dxgi_format) {
switch (dxgi_format) {
case DXGI_FORMAT_R8G8B8A8_UNORM:
return wgpu::TextureFormat::RGBA8Unorm;
case DXGI_FORMAT_B8G8R8A8_UNORM:
return wgpu::TextureFormat::BGRA8Unorm;
case DXGI_FORMAT_R8_UNORM:
return wgpu::TextureFormat::R8Unorm;
case DXGI_FORMAT_R8G8_UNORM:
return wgpu::TextureFormat::RG8Unorm;
case DXGI_FORMAT_R16_UNORM:
return wgpu::TextureFormat::R16Unorm;
case DXGI_FORMAT_R16G16_UNORM:
return wgpu::TextureFormat::RG16Unorm;
case DXGI_FORMAT_R16G16B16A16_FLOAT:
return wgpu::TextureFormat::RGBA16Float;
case DXGI_FORMAT_R10G10B10A2_UNORM:
return wgpu::TextureFormat::RGB10A2Unorm;
case DXGI_FORMAT_NV12:
return wgpu::TextureFormat::R8BG8Biplanar420Unorm;
case DXGI_FORMAT_P010:
return wgpu::TextureFormat::R10X6BG10X6Biplanar420Unorm;
default:
NOTREACHED();
return wgpu::TextureFormat::Undefined;
}
}
wgpu::TextureUsage GetAllowedDawnUsages(
const wgpu::Device& device,
const D3D11_TEXTURE2D_DESC& d3d11_texture_desc,
const wgpu::TextureFormat wgpu_format) {
DCHECK_EQ(wgpu_format, DXGIToWGPUFormat(d3d11_texture_desc.Format));
if (wgpu_format == wgpu::TextureFormat::R8BG8Biplanar420Unorm ||
wgpu_format == wgpu::TextureFormat::R10X6BG10X6Biplanar420Unorm) {
// The bi-planar 420 formats are only supported as a texture binding.
return wgpu::TextureUsage::TextureBinding;
}
wgpu::TextureUsage wgpu_usage =
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
if (d3d11_texture_desc.BindFlags & D3D11_BIND_RENDER_TARGET) {
wgpu_usage |= wgpu::TextureUsage::RenderAttachment;
}
if (d3d11_texture_desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) {
wgpu_usage |= wgpu::TextureUsage::TextureBinding;
}
if (d3d11_texture_desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) {
if (wgpu_format != wgpu::TextureFormat::BGRA8Unorm ||
device.HasFeature(wgpu::FeatureName::BGRA8UnormStorage)) {
wgpu_usage |= wgpu::TextureUsage::StorageBinding;
}
}
return wgpu_usage;
}
} // namespace
bool ClearD3D11TextureToColor(
const Microsoft::WRL::ComPtr<ID3D11Texture2D>& d3d11_texture,
const SkColor4f& color) {
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device;
d3d11_texture->GetDevice(&d3d11_device);
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> render_target;
HRESULT hr = d3d11_device->CreateRenderTargetView(d3d11_texture.Get(),
nullptr, &render_target);
if (FAILED(hr)) {
LOG(ERROR) << "CreateRenderTargetView failed: "
<< logging::SystemErrorCodeToString(hr);
return false;
}
DCHECK(render_target);
Microsoft::WRL::ComPtr<ID3D11DeviceContext> d3d11_device_context;
d3d11_device->GetImmediateContext(&d3d11_device_context);
DCHECK(d3d11_device_context);
d3d11_device_context->ClearRenderTargetView(render_target.Get(), color.vec());
return true;
}
std::unique_ptr<ExternalImageDXGI> CreateDawnExternalImageDXGI(
const wgpu::Device& device,
uint32_t shared_image_usage,
const D3D11_TEXTURE2D_DESC& d3d11_texture_desc,
absl::variant<HANDLE, Microsoft::WRL::ComPtr<ID3D11Texture2D>>
handle_or_texture,
base::span<wgpu::TextureFormat> view_formats) {
const wgpu::TextureFormat wgpu_format =
DXGIToWGPUFormat(d3d11_texture_desc.Format);
if (wgpu_format == wgpu::TextureFormat::Undefined) {
LOG(ERROR) << "Unsupported DXGI_FORMAT found: "
<< d3d11_texture_desc.Format;
return nullptr;
}
// The below usages are not supported for multiplanar formats in Dawn.
// TODO(crbug.com/1451784): Use read/write intent instead of format to get
// correct usages. This needs support in Skia to loosen TextureUsage
// validation. Alternatively, add support in Dawn for multiplanar formats to
// be Renderable.
wgpu::TextureUsage wgpu_allowed_usage =
GetAllowedDawnUsages(device, d3d11_texture_desc, wgpu_format);
if (wgpu_allowed_usage == wgpu::TextureUsage::None) {
LOG(ERROR)
<< "Allowed wgpu::TextureUsage is unknown for wgpu::TextureFormat: "
<< static_cast<int>(wgpu_format);
return nullptr;
}
if (shared_image_usage & SHARED_IMAGE_USAGE_WEBGPU_STORAGE_TEXTURE &&
!(wgpu_allowed_usage & wgpu::TextureUsage::StorageBinding)) {
LOG(ERROR) << "Storage binding is not allowed for wgpu::TextureFormat: "
<< static_cast<int>(wgpu_format);
return nullptr;
}
wgpu::TextureDescriptor wgpu_texture_desc;
wgpu_texture_desc.format = wgpu_format;
wgpu_texture_desc.usage = wgpu_allowed_usage;
wgpu_texture_desc.dimension = wgpu::TextureDimension::e2D;
wgpu_texture_desc.size = {d3d11_texture_desc.Width, d3d11_texture_desc.Height,
1};
wgpu_texture_desc.mipLevelCount = 1;
wgpu_texture_desc.sampleCount = 1;
wgpu_texture_desc.viewFormatCount =
static_cast<uint32_t>(view_formats.size());
wgpu_texture_desc.viewFormats = view_formats.data();
// We need to have internal usages of CopySrc for copies,
// RenderAttachment for clears, and TextureBinding for copyTextureForBrowser
// if texture format allows these usages.
wgpu::DawnTextureInternalUsageDescriptor wgpu_internal_usage_desc;
wgpu_internal_usage_desc.internalUsage = wgpu_allowed_usage;
wgpu_texture_desc.nextInChain = &wgpu_internal_usage_desc;
std::unique_ptr<ExternalImageDXGI> external_image;
if (absl::holds_alternative<HANDLE>(handle_or_texture)) {
ExternalImageDescriptorDXGISharedHandle external_image_desc;
external_image_desc.cTextureDescriptor =
reinterpret_cast<WGPUTextureDescriptor*>(&wgpu_texture_desc);
external_image_desc.sharedHandle = absl::get<HANDLE>(handle_or_texture);
external_image =
ExternalImageDXGI::Create(device.Get(), &external_image_desc);
} else {
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
absl::get<Microsoft::WRL::ComPtr<ID3D11Texture2D>>(handle_or_texture);
ExternalImageDescriptorD3D11Texture external_image_desc;
external_image_desc.cTextureDescriptor =
reinterpret_cast<WGPUTextureDescriptor*>(&wgpu_texture_desc);
external_image_desc.texture = std::move(texture);
external_image =
ExternalImageDXGI::Create(device.Get(), &external_image_desc);
}
if (!external_image) {
LOG(ERROR) << "Failed to create external image";
return nullptr;
}
DCHECK(external_image->IsValid());
return external_image;
}
} // namespace gpu