[GPU] Ownership-transfer-based RT cache, 3x3 resolution scaling

The ROV path is also disabled by default because of lower performance
This commit is contained in:
Triang3l
2021-04-26 22:12:09 +03:00
parent 30ea6e3ea3
commit 913e1e949c
362 changed files with 185259 additions and 38291 deletions

View File

@@ -19,6 +19,8 @@
#include <d3dcompiler.h>
#include <dxgi1_4.h>
#include <dxgidebug.h>
// For Microsoft::WRL::ComPtr.
#include <wrl/client.h>
#include "third_party/DirectXShaderCompiler/include/dxc/dxcapi.h"
#include "third_party/DirectXShaderCompiler/projects/dxilconv/include/DxbcConverter.h"

View File

@@ -0,0 +1,54 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/ui/d3d12/d3d12_cpu_descriptor_pool.h"
#include <cstdint>
#include <memory>
#include "xenia/base/logging.h"
namespace xe {
namespace ui {
namespace d3d12 {
D3D12CpuDescriptorPool::Descriptor
D3D12CpuDescriptorPool::AllocateDescriptor() {
if (!freed_indices_.empty()) {
size_t index = freed_indices_.back();
freed_indices_.pop_back();
return Descriptor(shared_from_this(), index);
}
uint32_t heap_size = uint32_t(1) << heap_size_log2_;
if (!heaps_.empty() && last_heap_allocated_ < heap_size) {
return Descriptor(shared_from_this(),
(heaps_.size() - 1) * heap_size + last_heap_allocated_++);
}
D3D12_DESCRIPTOR_HEAP_DESC descriptor_heap_desc;
descriptor_heap_desc.Type = type_;
descriptor_heap_desc.NumDescriptors = heap_size;
descriptor_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
descriptor_heap_desc.NodeMask = 0;
ID3D12DescriptorHeap* descriptor_heap;
if (FAILED(provider_.GetDevice()->CreateDescriptorHeap(
&descriptor_heap_desc, IID_PPV_ARGS(&descriptor_heap)))) {
XELOGE(
"Failed to create a non-shader-visible descriptor heap for {} "
"descriptors",
heap_size);
return Descriptor();
}
heaps_.push_back(descriptor_heap);
last_heap_allocated_ = 1;
return Descriptor(shared_from_this(), (heaps_.size() - 1) * heap_size);
}
} // namespace d3d12
} // namespace ui
} // namespace xe

View File

@@ -0,0 +1,119 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_D3D12_D3D12_CPU_DESCRIPTOR_POOL_H_
#define XENIA_UI_D3D12_D3D12_CPU_DESCRIPTOR_POOL_H_
#include <cstdint>
#include <memory>
#include <utility>
#include <vector>
#include "xenia/base/assert.h"
#include "xenia/ui/d3d12/d3d12_provider.h"
namespace xe {
namespace ui {
namespace d3d12 {
// Single-descriptor pool with reference counting and unique ownership of
// allocations, safe to use in environments where the order of releasing of the
// descriptor heap and of allocated descriptors is undefined.
class D3D12CpuDescriptorPool
: public std::enable_shared_from_this<D3D12CpuDescriptorPool> {
public:
class Descriptor {
public:
Descriptor() = default;
// shared_ptr to ensure correct release order with between render targets
// and descriptor pools.
Descriptor(std::shared_ptr<D3D12CpuDescriptorPool> pool, size_t index)
: pool_(pool), index_(index) {}
// Owns a descriptor in the pool exclusively.
Descriptor(const Descriptor& descriptor) = delete;
Descriptor& operator=(const Descriptor& descriptor) = delete;
Descriptor(Descriptor&& descriptor) {
pool_ = std::move(descriptor.pool_);
index_ = descriptor.index_;
}
Descriptor& operator=(Descriptor&& descriptor) {
if (IsValid() && pool_ == descriptor.pool_ &&
index_ == descriptor.index_) {
// If moving to self, don't free.
return *this;
}
Free();
pool_ = std::move(descriptor.pool_);
index_ = descriptor.index_;
return *this;
}
~Descriptor() { Free(); }
void Free() {
if (!pool_) {
return;
}
pool_->FreeDescriptor(index_);
pool_.reset();
}
bool IsValid() const { return pool_.get() != nullptr; }
operator bool() const { return IsValid(); }
D3D12_CPU_DESCRIPTOR_HANDLE GetHandle() const {
assert_true(IsValid());
return pool_->GetHandle(index_);
}
private:
std::shared_ptr<D3D12CpuDescriptorPool> pool_;
size_t index_ = 0;
};
D3D12CpuDescriptorPool(const ui::d3d12::D3D12Provider& provider,
D3D12_DESCRIPTOR_HEAP_TYPE type,
uint32_t heap_size_log2)
: provider_(provider), type_(type), heap_size_log2_(heap_size_log2) {
assert_true(heap_size_log2 <= 31);
}
D3D12CpuDescriptorPool(const D3D12CpuDescriptorPool& pool) = delete;
D3D12CpuDescriptorPool& operator=(const D3D12CpuDescriptorPool& pool) =
delete;
// No point in moving, created only via make_shared.
D3D12CpuDescriptorPool(D3D12CpuDescriptorPool&& pool) = delete;
D3D12CpuDescriptorPool& operator=(D3D12CpuDescriptorPool&& pool) = delete;
~D3D12CpuDescriptorPool() {
for (ID3D12DescriptorHeap* heap : heaps_) {
heap->Release();
}
}
Descriptor AllocateDescriptor();
private:
void FreeDescriptor(size_t index) { freed_indices_.push_back(index); }
D3D12_CPU_DESCRIPTOR_HANDLE GetHandle(size_t index) const {
D3D12_CPU_DESCRIPTOR_HANDLE heap_start =
heaps_[index >> heap_size_log2_]->GetCPUDescriptorHandleForHeapStart();
uint32_t heap_local_index =
uint32_t(index & ((uint32_t(1) << heap_size_log2_) - 1));
return provider_.OffsetDescriptor(type_, heap_start, heap_local_index);
}
const ui::d3d12::D3D12Provider& provider_;
D3D12_DESCRIPTOR_HEAP_TYPE type_;
uint32_t heap_size_log2_;
std::vector<ID3D12DescriptorHeap*> heaps_;
std::vector<size_t> freed_indices_;
uint32_t last_heap_allocated_ = 0;
};
} // namespace d3d12
} // namespace ui
} // namespace xe
#endif // XENIA_UI_D3D12_D3D12_CPU_DESCRIPTOR_POOL_H_

View File

@@ -21,6 +21,8 @@ DEFINE_bool(d3d12_debug, false, "Enable Direct3D 12 and DXGI debug layer.",
"D3D12");
DEFINE_bool(d3d12_break_on_error, false,
"Break on Direct3D 12 validation errors.", "D3D12");
DEFINE_bool(d3d12_break_on_warning, false,
"Break on Direct3D 12 validation warnings.", "D3D12");
DEFINE_int32(d3d12_adapter, -1,
"Index of the DXGI adapter to use. "
"-1 for any physical adapter, -2 for WARP software rendering.",
@@ -200,14 +202,20 @@ bool D3D12Provider::Initialize() {
}
// Configure the DXGI debug info queue.
if (cvars::d3d12_break_on_error) {
if (cvars::d3d12_break_on_error || cvars::d3d12_break_on_warning) {
IDXGIInfoQueue* dxgi_info_queue;
if (SUCCEEDED(pfn_dxgi_get_debug_interface1_(
0, IID_PPV_ARGS(&dxgi_info_queue)))) {
dxgi_info_queue->SetBreakOnSeverity(
DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE);
dxgi_info_queue->SetBreakOnSeverity(
DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE);
if (cvars::d3d12_break_on_error) {
dxgi_info_queue->SetBreakOnSeverity(
DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE);
dxgi_info_queue->SetBreakOnSeverity(
DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE);
}
if (cvars::d3d12_break_on_warning) {
dxgi_info_queue->SetBreakOnSeverity(
DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING, TRUE);
}
dxgi_info_queue->Release();
}
}
@@ -273,7 +281,7 @@ bool D3D12Provider::Initialize() {
dxgi_factory->Release();
return false;
}
adapter_vendor_id_ = adapter_desc.VendorId;
adapter_vendor_id_ = GpuVendorID(adapter_desc.VendorId);
int adapter_name_mb_size = WideCharToMultiByte(
CP_UTF8, 0, adapter_desc.Description, -1, nullptr, 0, nullptr, nullptr);
if (adapter_name_mb_size != 0) {
@@ -282,7 +290,7 @@ bool D3D12Provider::Initialize() {
if (WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description, -1,
adapter_name_mb, adapter_name_mb_size, nullptr,
nullptr) != 0) {
XELOGD3D("DXGI adapter: {} (vendor {:04X}, device {:04X})",
XELOGD3D("DXGI adapter: {} (vendor 0x{:04X}, device 0x{:04X})",
adapter_name_mb, adapter_desc.VendorId, adapter_desc.DeviceId);
}
}
@@ -307,9 +315,20 @@ bool D3D12Provider::Initialize() {
D3D12_MESSAGE_ID d3d12_info_queue_denied_messages[] = {
// Xbox 360 vertex fetch is explicit in shaders.
D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_EMPTY_LAYOUT,
// Bug in the debug layer (fixed in some version of Windows) - gaps in
// render target bindings must be represented with a fully typed RTV
// descriptor and DXGI_FORMAT_UNKNOWN in the pipeline state, but older
// debug layer versions give a format mismatch error in this case.
D3D12_MESSAGE_ID_RENDER_TARGET_FORMAT_MISMATCH_PIPELINE_STATE,
// Render targets and shader exports don't have to match on the Xbox
// 360.
D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RENDERTARGETVIEW_NOT_SET,
// Arbitrary scissor can be specified by the guest, also it can be
// explicitly used to disable drawing.
D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE,
// Arbitrary clear values can be specified by the guest.
D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,
};
D3D12_INFO_QUEUE_FILTER d3d12_info_queue_filter = {};
d3d12_info_queue_filter.DenyList.NumSeverities =
@@ -325,6 +344,10 @@ bool D3D12Provider::Initialize() {
TRUE);
d3d12_info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
}
if (cvars::d3d12_break_on_warning) {
d3d12_info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING,
TRUE);
}
d3d12_info_queue->Release();
}
@@ -373,14 +396,10 @@ bool D3D12Provider::Initialize() {
direct_queue_ = direct_queue;
// Get descriptor sizes for each type.
descriptor_size_view_ = device->GetDescriptorHandleIncrementSize(
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
descriptor_size_sampler_ = device->GetDescriptorHandleIncrementSize(
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
descriptor_size_rtv_ =
device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
descriptor_size_dsv_ =
device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
for (uint32_t i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++i) {
descriptor_sizes_[i] =
device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE(i));
}
// Check if optional features are supported.
// D3D12_HEAP_FLAG_CREATE_NOT_ZEROED requires Windows 10 2004 (indicated by
@@ -391,13 +410,16 @@ bool D3D12Provider::Initialize() {
&options7, sizeof(options7)))) {
heap_flag_create_not_zeroed_ = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
}
ps_specified_stencil_reference_supported_ = false;
rasterizer_ordered_views_supported_ = false;
resource_binding_tier_ = D3D12_RESOURCE_BINDING_TIER_1;
tiled_resources_tier_ = D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED;
D3D12_FEATURE_DATA_D3D12_OPTIONS options;
if (SUCCEEDED(device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS,
&options, sizeof(options)))) {
rasterizer_ordered_views_supported_ = options.ROVsSupported ? true : false;
ps_specified_stencil_reference_supported_ =
bool(options.PSSpecifiedStencilRefSupported);
rasterizer_ordered_views_supported_ = bool(options.ROVsSupported);
resource_binding_tier_ = options.ResourceBindingTier;
tiled_resources_tier_ = options.TiledResourcesTier;
}
@@ -421,6 +443,7 @@ bool D3D12Provider::Initialize() {
"Direct3D 12 device and OS features:\n"
"* Max GPU virtual address bits per resource: {}\n"
"* Non-zeroed heap creation: {}\n"
"* Pixel-shader-specified stencil reference: {}\n"
"* Programmable sample positions: tier {}\n"
"* Rasterizer-ordered views: {}\n"
"* Resource binding: tier {}\n"
@@ -428,6 +451,7 @@ bool D3D12Provider::Initialize() {
virtual_address_bits_per_resource_,
(heap_flag_create_not_zeroed_ & D3D12_HEAP_FLAG_CREATE_NOT_ZEROED) ? "yes"
: "no",
ps_specified_stencil_reference_supported_ ? "yes" : "no",
uint32_t(programmable_sample_positions_tier_),
rasterizer_ordered_views_supported_ ? "yes" : "no",
uint32_t(resource_binding_tier_), uint32_t(tiled_resources_tier_));

View File

@@ -41,33 +41,50 @@ class D3D12Provider : public GraphicsProvider {
ID3D12Device* GetDevice() const { return device_; }
ID3D12CommandQueue* GetDirectQueue() const { return direct_queue_; }
uint32_t GetViewDescriptorSize() const { return descriptor_size_view_; }
uint32_t GetSamplerDescriptorSize() const { return descriptor_size_sampler_; }
uint32_t GetRTVDescriptorSize() const { return descriptor_size_rtv_; }
uint32_t GetDSVDescriptorSize() const { return descriptor_size_dsv_; }
uint32_t GetDescriptorSize(D3D12_DESCRIPTOR_HEAP_TYPE type) const {
return descriptor_sizes_[type];
}
uint32_t GetViewDescriptorSize() const {
return GetDescriptorSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
uint32_t GetSamplerDescriptorSize() const {
return GetDescriptorSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
}
uint32_t GetRTVDescriptorSize() const {
return GetDescriptorSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
}
uint32_t GetDSVDescriptorSize() const {
return GetDescriptorSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
}
template <typename T>
T OffsetDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE type, T start,
uint32_t index) const {
start.ptr += index * GetDescriptorSize(type);
return start;
}
template <typename T>
T OffsetViewDescriptor(T start, uint32_t index) const {
start.ptr += index * descriptor_size_view_;
start.ptr += index * GetViewDescriptorSize();
return start;
}
template <typename T>
T OffsetSamplerDescriptor(T start, uint32_t index) const {
start.ptr += index * descriptor_size_sampler_;
start.ptr += index * GetSamplerDescriptorSize();
return start;
}
template <typename T>
T OffsetRTVDescriptor(T start, uint32_t index) const {
start.ptr += index * descriptor_size_rtv_;
start.ptr += index * GetRTVDescriptorSize();
return start;
}
template <typename T>
T OffsetDSVDescriptor(T start, uint32_t index) const {
start.ptr += index * descriptor_size_dsv_;
start.ptr += index * GetDSVDescriptorSize();
return start;
}
// Adapter info.
uint32_t GetAdapterVendorID() const { return adapter_vendor_id_; }
GpuVendorID GetAdapterVendorID() const { return adapter_vendor_id_; }
// Device features.
D3D12_HEAP_FLAGS GetHeapFlagCreateNotZeroed() const {
@@ -77,6 +94,9 @@ class D3D12Provider : public GraphicsProvider {
GetProgrammableSamplePositionsTier() const {
return programmable_sample_positions_tier_;
}
bool IsPSSpecifiedStencilReferenceSupported() const {
return ps_specified_stencil_reference_supported_;
}
bool AreRasterizerOrderedViewsSupported() const {
return rasterizer_ordered_views_supported_;
}
@@ -155,15 +175,13 @@ class D3D12Provider : public GraphicsProvider {
ID3D12Device* device_ = nullptr;
ID3D12CommandQueue* direct_queue_ = nullptr;
uint32_t descriptor_size_view_;
uint32_t descriptor_size_sampler_;
uint32_t descriptor_size_rtv_;
uint32_t descriptor_size_dsv_;
uint32_t descriptor_sizes_[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
uint32_t adapter_vendor_id_;
GpuVendorID adapter_vendor_id_;
D3D12_HEAP_FLAGS heap_flag_create_not_zeroed_;
D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER programmable_sample_positions_tier_;
bool ps_specified_stencil_reference_supported_;
bool rasterizer_ordered_views_supported_;
D3D12_RESOURCE_BINDING_TIER resource_binding_tier_;
D3D12_TILED_RESOURCES_TIER tiled_resources_tier_;

View File

@@ -127,6 +127,189 @@ void CreateBufferTypedUAV(ID3D12Device* device,
device->CreateUnorderedAccessView(buffer, nullptr, &desc, handle);
}
void GetFormatCopyInfo(DXGI_FORMAT format, uint32_t plane,
DXGI_FORMAT& copy_format_out, uint32_t& block_width_out,
uint32_t& block_height_out,
uint32_t& bytes_per_block_out) {
DXGI_FORMAT copy_format = format;
uint32_t block_width = 1;
uint32_t block_height = 1;
bool divide_by_block_size = false;
uint32_t bytes_per_block = 1;
switch (format) {
case DXGI_FORMAT_R32G32B32A32_TYPELESS:
case DXGI_FORMAT_R32G32B32A32_FLOAT:
case DXGI_FORMAT_R32G32B32A32_UINT:
case DXGI_FORMAT_R32G32B32A32_SINT:
bytes_per_block = 16;
break;
case DXGI_FORMAT_R32G32B32_TYPELESS:
case DXGI_FORMAT_R32G32B32_FLOAT:
case DXGI_FORMAT_R32G32B32_UINT:
case DXGI_FORMAT_R32G32B32_SINT:
bytes_per_block = 12;
break;
case DXGI_FORMAT_R16G16B16A16_TYPELESS:
case DXGI_FORMAT_R16G16B16A16_FLOAT:
case DXGI_FORMAT_R16G16B16A16_UNORM:
case DXGI_FORMAT_R16G16B16A16_UINT:
case DXGI_FORMAT_R16G16B16A16_SNORM:
case DXGI_FORMAT_R16G16B16A16_SINT:
case DXGI_FORMAT_R32G32_TYPELESS:
case DXGI_FORMAT_R32G32_FLOAT:
case DXGI_FORMAT_R32G32_UINT:
case DXGI_FORMAT_R32G32_SINT:
case DXGI_FORMAT_Y416:
bytes_per_block = 8;
break;
case DXGI_FORMAT_R32G8X24_TYPELESS:
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
case DXGI_FORMAT_R24G8_TYPELESS:
case DXGI_FORMAT_D24_UNORM_S8_UINT:
case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
if (plane) {
copy_format = DXGI_FORMAT_R8_TYPELESS;
bytes_per_block = 1;
} else {
copy_format = DXGI_FORMAT_R32_TYPELESS;
bytes_per_block = 4;
}
break;
case DXGI_FORMAT_R10G10B10A2_TYPELESS:
case DXGI_FORMAT_R10G10B10A2_UNORM:
case DXGI_FORMAT_R10G10B10A2_UINT:
case DXGI_FORMAT_R11G11B10_FLOAT:
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
case DXGI_FORMAT_R8G8B8A8_UINT:
case DXGI_FORMAT_R8G8B8A8_SNORM:
case DXGI_FORMAT_R8G8B8A8_SINT:
case DXGI_FORMAT_R16G16_TYPELESS:
case DXGI_FORMAT_R16G16_FLOAT:
case DXGI_FORMAT_R16G16_UNORM:
case DXGI_FORMAT_R16G16_UINT:
case DXGI_FORMAT_R16G16_SNORM:
case DXGI_FORMAT_R16G16_SINT:
case DXGI_FORMAT_R32_TYPELESS:
case DXGI_FORMAT_D32_FLOAT:
case DXGI_FORMAT_R32_FLOAT:
case DXGI_FORMAT_R32_UINT:
case DXGI_FORMAT_R32_SINT:
case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_B8G8R8X8_UNORM:
case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8X8_TYPELESS:
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
case DXGI_FORMAT_AYUV:
case DXGI_FORMAT_Y410:
bytes_per_block = 4;
break;
case DXGI_FORMAT_R8G8_TYPELESS:
case DXGI_FORMAT_R8G8_UNORM:
case DXGI_FORMAT_R8G8_UINT:
case DXGI_FORMAT_R8G8_SNORM:
case DXGI_FORMAT_R8G8_SINT:
case DXGI_FORMAT_R16_TYPELESS:
case DXGI_FORMAT_R16_FLOAT:
case DXGI_FORMAT_D16_UNORM:
case DXGI_FORMAT_R16_UNORM:
case DXGI_FORMAT_R16_UINT:
case DXGI_FORMAT_R16_SNORM:
case DXGI_FORMAT_R16_SINT:
case DXGI_FORMAT_B5G6R5_UNORM:
case DXGI_FORMAT_B5G5R5A1_UNORM:
case DXGI_FORMAT_A8P8:
case DXGI_FORMAT_B4G4R4A4_UNORM:
bytes_per_block = 2;
break;
case DXGI_FORMAT_R8_TYPELESS:
case DXGI_FORMAT_R8_UNORM:
case DXGI_FORMAT_R8_UINT:
case DXGI_FORMAT_R8_SNORM:
case DXGI_FORMAT_R8_SINT:
case DXGI_FORMAT_A8_UNORM:
case DXGI_FORMAT_AI44:
case DXGI_FORMAT_IA44:
case DXGI_FORMAT_P8:
bytes_per_block = 1;
break;
// R1_UNORM is not supported in Direct3D 12.
case DXGI_FORMAT_R8G8_B8G8_UNORM:
case DXGI_FORMAT_G8R8_G8B8_UNORM:
case DXGI_FORMAT_Y210:
case DXGI_FORMAT_Y216:
// Failed to GetCopyableFootprints for Y210 and Y216 on Intel UHD Graphics
// 630.
block_width = 2;
bytes_per_block = 4;
break;
case DXGI_FORMAT_BC1_TYPELESS:
case DXGI_FORMAT_BC1_UNORM:
case DXGI_FORMAT_BC1_UNORM_SRGB:
case DXGI_FORMAT_BC4_TYPELESS:
case DXGI_FORMAT_BC4_UNORM:
case DXGI_FORMAT_BC4_SNORM:
block_width = 4;
block_height = 4;
bytes_per_block = 8;
break;
case DXGI_FORMAT_BC2_TYPELESS:
case DXGI_FORMAT_BC2_UNORM:
case DXGI_FORMAT_BC2_UNORM_SRGB:
case DXGI_FORMAT_BC3_TYPELESS:
case DXGI_FORMAT_BC3_UNORM:
case DXGI_FORMAT_BC3_UNORM_SRGB:
case DXGI_FORMAT_BC5_TYPELESS:
case DXGI_FORMAT_BC5_UNORM:
case DXGI_FORMAT_BC5_SNORM:
case DXGI_FORMAT_BC6H_TYPELESS:
case DXGI_FORMAT_BC6H_UF16:
case DXGI_FORMAT_BC6H_SF16:
case DXGI_FORMAT_BC7_TYPELESS:
case DXGI_FORMAT_BC7_UNORM:
case DXGI_FORMAT_BC7_UNORM_SRGB:
block_width = 4;
block_height = 4;
bytes_per_block = 16;
break;
// NV12, P010, P016, 420_OPAQUE and NV11 are not handled here because of
// differences that need to be handled externally.
// For future reference, if needed:
// - Width and height of planes 1 and 2 are divided by the block size in the
// footprint itself (unlike in block-compressed textures, where the
// dimensions are merely aligned).
// - Rows are aligned to the placement alignment (512) rather than the pitch
// alignment (256) for some reason (to match the Direct3D 11 layout
// without explicit planes, requiring the plane data to be laid out in
// some specific way defined on MSDN within each row, though Direct3D 12
// possibly doesn't have such requirement, but investigation needed.
// - NV12: R8_TYPELESS plane 0, R8G8_TYPELESS plane 1.
// - P010, P016: R16_TYPELESS plane 0, R16G16_TYPELESS plane 1. Failed to
// GetCopyableFootprints for P016 on Nvidia GeForce GTX 1070.
// - 420_OPAQUE: Single R8_TYPELESS plane.
// - NV11: Failed to GetCopyableFootprints on both Nvidia GeForce GTX 1070
// and Intel UHD Graphics 630.
case DXGI_FORMAT_YUY2:
block_width = 2;
bytes_per_block = 2;
break;
// P208, V208 and V408 are not supported in Direct3D 12.
default:
assert_unhandled_case(format);
}
copy_format_out = copy_format;
block_width_out = block_width;
block_height_out = block_height;
bytes_per_block_out = bytes_per_block;
}
} // namespace util
} // namespace d3d12
} // namespace ui

View File

@@ -19,7 +19,7 @@ namespace ui {
namespace d3d12 {
namespace util {
using DescriptorCPUGPUHandlePair =
using DescriptorCpuGpuHandlePair =
std::pair<D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_GPU_DESCRIPTOR_HANDLE>;
extern const D3D12_HEAP_PROPERTIES kHeapPropertiesDefault;
@@ -93,6 +93,14 @@ void CreateBufferTypedUAV(ID3D12Device* device,
ID3D12Resource* buffer, DXGI_FORMAT format,
uint32_t num_elements, uint64_t first_element = 0);
// For cases where GetCopyableFootprints isn't usable (such as when the size
// needs to be overaligned beyond the maximum texture size), providing data
// needed to compute the copyable footprints manually.
void GetFormatCopyInfo(DXGI_FORMAT format, uint32_t plane,
DXGI_FORMAT& copy_format_out, uint32_t& block_width_out,
uint32_t& block_height_out,
uint32_t& bytes_per_block_out);
} // namespace util
} // namespace d3d12
} // namespace ui

View File

@@ -23,6 +23,17 @@ class Window;
// according to the rules of the backing graphics API.
class GraphicsProvider {
public:
enum class GpuVendorID {
kAMD = 0x1002,
kApple = 0x106B,
kArm = 0x13B5,
kImagination = 0x1010,
kIntel = 0x8086,
kMicrosoft = 0x1414,
kNvidia = 0x10DE,
kQualcomm = 0x5143,
};
virtual ~GraphicsProvider() = default;
// The 'main' window of an application, used to query provider information.