Merge branch 'master' of https://github.com/xenia-project/xenia into canary_new
This commit is contained in:
commit
95ca826d95
|
@ -12,7 +12,7 @@ drivers.
|
||||||
* [Visual Studio 2019 or Visual Studio 2017](https://www.visualstudio.com/downloads/)
|
* [Visual Studio 2019 or Visual Studio 2017](https://www.visualstudio.com/downloads/)
|
||||||
* [Python 3.6+](https://www.python.org/downloads/)
|
* [Python 3.6+](https://www.python.org/downloads/)
|
||||||
* Ensure Python is in PATH.
|
* Ensure Python is in PATH.
|
||||||
* Windows 10 SDK
|
* Windows 10 SDK version 10.0.19041.0 (for Visual Studio 2019, this or any newer version)
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/xenia-project/xenia.git
|
git clone https://github.com/xenia-project/xenia.git
|
||||||
|
|
|
@ -202,10 +202,10 @@ solution("xenia")
|
||||||
platforms({"Linux"})
|
platforms({"Linux"})
|
||||||
elseif os.istarget("windows") then
|
elseif os.istarget("windows") then
|
||||||
platforms({"Windows"})
|
platforms({"Windows"})
|
||||||
-- Minimum version to support ID3D12GraphicsCommandList1 (for
|
-- 10.0.15063.0: ID3D12GraphicsCommandList1::SetSamplePositions.
|
||||||
-- SetSamplePositions).
|
-- 10.0.19041.0: D3D12_HEAP_FLAG_CREATE_NOT_ZEROED.
|
||||||
filter("action:vs2017")
|
filter("action:vs2017")
|
||||||
systemversion("10.0.15063.0")
|
systemversion("10.0.19041.0")
|
||||||
filter("action:vs2019")
|
filter("action:vs2019")
|
||||||
systemversion("10.0")
|
systemversion("10.0")
|
||||||
filter({})
|
filter({})
|
||||||
|
|
|
@ -646,14 +646,16 @@ ID3D12Resource* D3D12CommandProcessor::RequestScratchGPUBuffer(
|
||||||
|
|
||||||
size = xe::align(size, kScratchBufferSizeIncrement);
|
size = xe::align(size, kScratchBufferSizeIncrement);
|
||||||
|
|
||||||
auto device = GetD3D12Context().GetD3D12Provider().GetDevice();
|
auto& provider = GetD3D12Context().GetD3D12Provider();
|
||||||
|
auto device = provider.GetDevice();
|
||||||
D3D12_RESOURCE_DESC buffer_desc;
|
D3D12_RESOURCE_DESC buffer_desc;
|
||||||
ui::d3d12::util::FillBufferResourceDesc(
|
ui::d3d12::util::FillBufferResourceDesc(
|
||||||
buffer_desc, size, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
|
buffer_desc, size, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
|
||||||
ID3D12Resource* buffer;
|
ID3D12Resource* buffer;
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&ui::d3d12::util::kHeapPropertiesDefault, D3D12_HEAP_FLAG_NONE,
|
&ui::d3d12::util::kHeapPropertiesDefault,
|
||||||
&buffer_desc, state, nullptr, IID_PPV_ARGS(&buffer)))) {
|
provider.GetHeapFlagCreateNotZeroed(), &buffer_desc, state, nullptr,
|
||||||
|
IID_PPV_ARGS(&buffer)))) {
|
||||||
XELOGE("Failed to create a {} MB scratch GPU buffer", size >> 20);
|
XELOGE("Failed to create a {} MB scratch GPU buffer", size >> 20);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -889,7 +891,7 @@ bool D3D12CommandProcessor::SetupContext() {
|
||||||
|
|
||||||
// Initialize resource binding.
|
// Initialize resource binding.
|
||||||
constant_buffer_pool_ =
|
constant_buffer_pool_ =
|
||||||
std::make_unique<ui::d3d12::UploadBufferPool>(device, 1024 * 1024);
|
std::make_unique<ui::d3d12::UploadBufferPool>(provider, 1024 * 1024);
|
||||||
if (bindless_resources_used_) {
|
if (bindless_resources_used_) {
|
||||||
D3D12_DESCRIPTOR_HEAP_DESC view_bindless_heap_desc;
|
D3D12_DESCRIPTOR_HEAP_DESC view_bindless_heap_desc;
|
||||||
view_bindless_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
view_bindless_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
||||||
|
@ -1181,6 +1183,9 @@ bool D3D12CommandProcessor::SetupContext() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
D3D12_HEAP_FLAGS heap_flag_create_not_zeroed =
|
||||||
|
provider.GetHeapFlagCreateNotZeroed();
|
||||||
|
|
||||||
// Create gamma ramp resources. The PWL gamma ramp is 16-bit, but 6 bits are
|
// Create gamma ramp resources. The PWL gamma ramp is 16-bit, but 6 bits are
|
||||||
// hardwired to zero, so DXGI_FORMAT_R10G10B10A2_UNORM can be used for it too.
|
// hardwired to zero, so DXGI_FORMAT_R10G10B10A2_UNORM can be used for it too.
|
||||||
// https://www.x.org/docs/AMD/old/42590_m76_rrg_1.01o.pdf
|
// https://www.x.org/docs/AMD/old/42590_m76_rrg_1.01o.pdf
|
||||||
|
@ -1202,7 +1207,7 @@ bool D3D12CommandProcessor::SetupContext() {
|
||||||
// The first action will be uploading.
|
// The first action will be uploading.
|
||||||
gamma_ramp_texture_state_ = D3D12_RESOURCE_STATE_COPY_DEST;
|
gamma_ramp_texture_state_ = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&ui::d3d12::util::kHeapPropertiesDefault, D3D12_HEAP_FLAG_NONE,
|
&ui::d3d12::util::kHeapPropertiesDefault, heap_flag_create_not_zeroed,
|
||||||
&gamma_ramp_desc, gamma_ramp_texture_state_, nullptr,
|
&gamma_ramp_desc, gamma_ramp_texture_state_, nullptr,
|
||||||
IID_PPV_ARGS(&gamma_ramp_texture_)))) {
|
IID_PPV_ARGS(&gamma_ramp_texture_)))) {
|
||||||
XELOGE("Failed to create the gamma ramp texture");
|
XELOGE("Failed to create the gamma ramp texture");
|
||||||
|
@ -1218,7 +1223,7 @@ bool D3D12CommandProcessor::SetupContext() {
|
||||||
ui::d3d12::util::FillBufferResourceDesc(
|
ui::d3d12::util::FillBufferResourceDesc(
|
||||||
gamma_ramp_desc, gamma_ramp_upload_size, D3D12_RESOURCE_FLAG_NONE);
|
gamma_ramp_desc, gamma_ramp_upload_size, D3D12_RESOURCE_FLAG_NONE);
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&ui::d3d12::util::kHeapPropertiesUpload, D3D12_HEAP_FLAG_NONE,
|
&ui::d3d12::util::kHeapPropertiesUpload, heap_flag_create_not_zeroed,
|
||||||
&gamma_ramp_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
|
&gamma_ramp_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
|
||||||
IID_PPV_ARGS(&gamma_ramp_upload_)))) {
|
IID_PPV_ARGS(&gamma_ramp_upload_)))) {
|
||||||
XELOGE("Failed to create the gamma ramp upload buffer");
|
XELOGE("Failed to create the gamma ramp upload buffer");
|
||||||
|
@ -1246,7 +1251,7 @@ bool D3D12CommandProcessor::SetupContext() {
|
||||||
swap_texture_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
swap_texture_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
||||||
// Can be sampled at any time, switch to render target when needed, then back.
|
// Can be sampled at any time, switch to render target when needed, then back.
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&ui::d3d12::util::kHeapPropertiesDefault, D3D12_HEAP_FLAG_NONE,
|
&ui::d3d12::util::kHeapPropertiesDefault, heap_flag_create_not_zeroed,
|
||||||
&swap_texture_desc, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
&swap_texture_desc, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
||||||
nullptr, IID_PPV_ARGS(&swap_texture_)))) {
|
nullptr, IID_PPV_ARGS(&swap_texture_)))) {
|
||||||
XELOGE("Failed to create the command processor front buffer");
|
XELOGE("Failed to create the command processor front buffer");
|
||||||
|
@ -4286,15 +4291,16 @@ ID3D12Resource* D3D12CommandProcessor::RequestReadbackBuffer(uint32_t size) {
|
||||||
}
|
}
|
||||||
size = xe::align(size, kReadbackBufferSizeIncrement);
|
size = xe::align(size, kReadbackBufferSizeIncrement);
|
||||||
if (size > readback_buffer_size_) {
|
if (size > readback_buffer_size_) {
|
||||||
auto device = GetD3D12Context().GetD3D12Provider().GetDevice();
|
auto& provider = GetD3D12Context().GetD3D12Provider();
|
||||||
|
auto device = provider.GetDevice();
|
||||||
D3D12_RESOURCE_DESC buffer_desc;
|
D3D12_RESOURCE_DESC buffer_desc;
|
||||||
ui::d3d12::util::FillBufferResourceDesc(buffer_desc, size,
|
ui::d3d12::util::FillBufferResourceDesc(buffer_desc, size,
|
||||||
D3D12_RESOURCE_FLAG_NONE);
|
D3D12_RESOURCE_FLAG_NONE);
|
||||||
ID3D12Resource* buffer;
|
ID3D12Resource* buffer;
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&ui::d3d12::util::kHeapPropertiesReadback, D3D12_HEAP_FLAG_NONE,
|
&ui::d3d12::util::kHeapPropertiesReadback,
|
||||||
&buffer_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
|
provider.GetHeapFlagCreateNotZeroed(), &buffer_desc,
|
||||||
IID_PPV_ARGS(&buffer)))) {
|
D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&buffer)))) {
|
||||||
XELOGE("Failed to create a {} MB readback buffer", size >> 20);
|
XELOGE("Failed to create a {} MB readback buffer", size >> 20);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
#include "xenia/gpu/d3d12/d3d12_graphics_system.h"
|
#include "xenia/gpu/d3d12/d3d12_graphics_system.h"
|
||||||
|
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/math.h"
|
||||||
#include "xenia/gpu/d3d12/d3d12_command_processor.h"
|
#include "xenia/gpu/d3d12/d3d12_command_processor.h"
|
||||||
|
#include "xenia/gpu/draw_util.h"
|
||||||
#include "xenia/ui/d3d12/d3d12_util.h"
|
#include "xenia/ui/d3d12/d3d12_util.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
|
||||||
|
@ -265,22 +267,39 @@ void D3D12GraphicsSystem::Swap(xe::ui::UIEvent* e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t window_width, window_height;
|
||||||
|
display_context_->GetSwapChainSize(window_width, window_height);
|
||||||
|
|
||||||
|
int32_t target_x, target_y;
|
||||||
|
uint32_t target_width, target_height;
|
||||||
|
draw_util::GetPresentArea(swap_state.width, swap_state.height, window_width,
|
||||||
|
window_height, target_x, target_y, target_width,
|
||||||
|
target_height);
|
||||||
|
// For safety.
|
||||||
|
target_x = clamp(target_x, int32_t(D3D12_VIEWPORT_BOUNDS_MIN),
|
||||||
|
int32_t(D3D12_VIEWPORT_BOUNDS_MAX));
|
||||||
|
target_y = clamp(target_y, int32_t(D3D12_VIEWPORT_BOUNDS_MIN),
|
||||||
|
int32_t(D3D12_VIEWPORT_BOUNDS_MAX));
|
||||||
|
target_width = std::min(
|
||||||
|
target_width, uint32_t(int32_t(D3D12_VIEWPORT_BOUNDS_MAX) - target_x));
|
||||||
|
target_height = std::min(
|
||||||
|
target_height, uint32_t(int32_t(D3D12_VIEWPORT_BOUNDS_MAX) - target_y));
|
||||||
|
|
||||||
auto command_list = display_context_->GetSwapCommandList();
|
auto command_list = display_context_->GetSwapCommandList();
|
||||||
uint32_t swap_width, swap_height;
|
// Assuming the window has already been cleared to the needed letterbox color.
|
||||||
display_context_->GetSwapChainSize(swap_width, swap_height);
|
|
||||||
D3D12_VIEWPORT viewport;
|
D3D12_VIEWPORT viewport;
|
||||||
viewport.TopLeftX = 0.0f;
|
viewport.TopLeftX = float(target_x);
|
||||||
viewport.TopLeftY = 0.0f;
|
viewport.TopLeftY = float(target_y);
|
||||||
viewport.Width = float(swap_width);
|
viewport.Width = float(target_width);
|
||||||
viewport.Height = float(swap_height);
|
viewport.Height = float(target_height);
|
||||||
viewport.MinDepth = 0.0f;
|
viewport.MinDepth = 0.0f;
|
||||||
viewport.MaxDepth = 0.0f;
|
viewport.MaxDepth = 0.0f;
|
||||||
command_list->RSSetViewports(1, &viewport);
|
command_list->RSSetViewports(1, &viewport);
|
||||||
D3D12_RECT scissor;
|
D3D12_RECT scissor;
|
||||||
scissor.left = 0;
|
scissor.left = 0;
|
||||||
scissor.top = 0;
|
scissor.top = 0;
|
||||||
scissor.right = swap_width;
|
scissor.right = window_width;
|
||||||
scissor.bottom = swap_height;
|
scissor.bottom = window_height;
|
||||||
command_list->RSSetScissorRects(1, &scissor);
|
command_list->RSSetScissorRects(1, &scissor);
|
||||||
command_list->SetDescriptorHeaps(1, &swap_srv_heap);
|
command_list->SetDescriptorHeaps(1, &swap_srv_heap);
|
||||||
StretchTextureToFrontBuffer(
|
StretchTextureToFrontBuffer(
|
||||||
|
|
|
@ -47,14 +47,16 @@ PrimitiveConverter::PrimitiveConverter(D3D12CommandProcessor& command_processor,
|
||||||
PrimitiveConverter::~PrimitiveConverter() { Shutdown(); }
|
PrimitiveConverter::~PrimitiveConverter() { Shutdown(); }
|
||||||
|
|
||||||
bool PrimitiveConverter::Initialize() {
|
bool PrimitiveConverter::Initialize() {
|
||||||
auto device =
|
auto& provider = command_processor_.GetD3D12Context().GetD3D12Provider();
|
||||||
command_processor_.GetD3D12Context().GetD3D12Provider().GetDevice();
|
auto device = provider.GetDevice();
|
||||||
|
D3D12_HEAP_FLAGS heap_flag_create_not_zeroed =
|
||||||
|
provider.GetHeapFlagCreateNotZeroed();
|
||||||
|
|
||||||
// There can be at most 65535 indices in a Xenos draw call, but they can be up
|
// There can be at most 65535 indices in a Xenos draw call, but they can be up
|
||||||
// to 4 bytes large, and conversion can add more indices (almost triple the
|
// to 4 bytes large, and conversion can add more indices (almost triple the
|
||||||
// count for triangle strips, for instance).
|
// count for triangle strips, for instance).
|
||||||
buffer_pool_ =
|
buffer_pool_ =
|
||||||
std::make_unique<ui::d3d12::UploadBufferPool>(device, 4 * 1024 * 1024);
|
std::make_unique<ui::d3d12::UploadBufferPool>(provider, 4 * 1024 * 1024);
|
||||||
|
|
||||||
// Create the static index buffer for non-indexed drawing.
|
// Create the static index buffer for non-indexed drawing.
|
||||||
D3D12_RESOURCE_DESC static_ib_desc;
|
D3D12_RESOURCE_DESC static_ib_desc;
|
||||||
|
@ -62,7 +64,7 @@ bool PrimitiveConverter::Initialize() {
|
||||||
static_ib_desc, kStaticIBTotalCount * sizeof(uint16_t),
|
static_ib_desc, kStaticIBTotalCount * sizeof(uint16_t),
|
||||||
D3D12_RESOURCE_FLAG_NONE);
|
D3D12_RESOURCE_FLAG_NONE);
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&ui::d3d12::util::kHeapPropertiesUpload, D3D12_HEAP_FLAG_NONE,
|
&ui::d3d12::util::kHeapPropertiesUpload, heap_flag_create_not_zeroed,
|
||||||
&static_ib_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
|
&static_ib_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
|
||||||
IID_PPV_ARGS(&static_ib_upload_)))) {
|
IID_PPV_ARGS(&static_ib_upload_)))) {
|
||||||
XELOGE(
|
XELOGE(
|
||||||
|
@ -108,7 +110,7 @@ bool PrimitiveConverter::Initialize() {
|
||||||
// Not uploaded yet.
|
// Not uploaded yet.
|
||||||
static_ib_upload_submission_ = UINT64_MAX;
|
static_ib_upload_submission_ = UINT64_MAX;
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&ui::d3d12::util::kHeapPropertiesDefault, D3D12_HEAP_FLAG_NONE,
|
&ui::d3d12::util::kHeapPropertiesDefault, heap_flag_create_not_zeroed,
|
||||||
&static_ib_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
|
&static_ib_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
|
||||||
IID_PPV_ARGS(&static_ib_)))) {
|
IID_PPV_ARGS(&static_ib_)))) {
|
||||||
XELOGE("Failed to create the primitive conversion static index buffer");
|
XELOGE("Failed to create the primitive conversion static index buffer");
|
||||||
|
|
|
@ -137,8 +137,6 @@ bool RenderTargetCache::Initialize(const TextureCache& texture_cache) {
|
||||||
uint32_t edram_buffer_size = GetEdramBufferSize();
|
uint32_t edram_buffer_size = GetEdramBufferSize();
|
||||||
|
|
||||||
// Create the buffer for reinterpreting EDRAM contents.
|
// Create the buffer for reinterpreting EDRAM contents.
|
||||||
// No need to clear it in the first frame, memory is zeroed out when allocated
|
|
||||||
// on Windows.
|
|
||||||
D3D12_RESOURCE_DESC edram_buffer_desc;
|
D3D12_RESOURCE_DESC edram_buffer_desc;
|
||||||
ui::d3d12::util::FillBufferResourceDesc(
|
ui::d3d12::util::FillBufferResourceDesc(
|
||||||
edram_buffer_desc, edram_buffer_size,
|
edram_buffer_desc, edram_buffer_size,
|
||||||
|
@ -147,8 +145,15 @@ bool RenderTargetCache::Initialize(const TextureCache& texture_cache) {
|
||||||
edram_buffer_state_ = edram_rov_used_
|
edram_buffer_state_ = edram_rov_used_
|
||||||
? D3D12_RESOURCE_STATE_UNORDERED_ACCESS
|
? D3D12_RESOURCE_STATE_UNORDERED_ACCESS
|
||||||
: D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
: D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||||
|
// Request zeroed (though no guarantee) when not using ROV so the host 32-bit
|
||||||
|
// depth buffer will be initialized to deterministic values (because it's
|
||||||
|
// involved in comparison with converted 24-bit values - whether the 32-bit
|
||||||
|
// value is up to date is determined by whether it's equal to the 24-bit
|
||||||
|
// value in the main EDRAM buffer when converted to 24-bit).
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&ui::d3d12::util::kHeapPropertiesDefault, D3D12_HEAP_FLAG_NONE,
|
&ui::d3d12::util::kHeapPropertiesDefault,
|
||||||
|
edram_rov_used_ ? provider.GetHeapFlagCreateNotZeroed()
|
||||||
|
: D3D12_HEAP_FLAG_NONE,
|
||||||
&edram_buffer_desc, edram_buffer_state_, nullptr,
|
&edram_buffer_desc, edram_buffer_state_, nullptr,
|
||||||
IID_PPV_ARGS(&edram_buffer_)))) {
|
IID_PPV_ARGS(&edram_buffer_)))) {
|
||||||
XELOGE("Failed to create the EDRAM buffer");
|
XELOGE("Failed to create the EDRAM buffer");
|
||||||
|
@ -1451,10 +1456,11 @@ bool RenderTargetCache::InitializeTraceSubmitDownloads() {
|
||||||
ui::d3d12::util::FillBufferResourceDesc(edram_snapshot_download_buffer_desc,
|
ui::d3d12::util::FillBufferResourceDesc(edram_snapshot_download_buffer_desc,
|
||||||
xenos::kEdramSizeBytes,
|
xenos::kEdramSizeBytes,
|
||||||
D3D12_RESOURCE_FLAG_NONE);
|
D3D12_RESOURCE_FLAG_NONE);
|
||||||
auto device =
|
auto& provider = command_processor_.GetD3D12Context().GetD3D12Provider();
|
||||||
command_processor_.GetD3D12Context().GetD3D12Provider().GetDevice();
|
auto device = provider.GetDevice();
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&ui::d3d12::util::kHeapPropertiesReadback, D3D12_HEAP_FLAG_NONE,
|
&ui::d3d12::util::kHeapPropertiesReadback,
|
||||||
|
provider.GetHeapFlagCreateNotZeroed(),
|
||||||
&edram_snapshot_download_buffer_desc,
|
&edram_snapshot_download_buffer_desc,
|
||||||
D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
|
D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
|
||||||
IID_PPV_ARGS(&edram_snapshot_download_buffer_)))) {
|
IID_PPV_ARGS(&edram_snapshot_download_buffer_)))) {
|
||||||
|
@ -1493,10 +1499,9 @@ void RenderTargetCache::RestoreEdramSnapshot(const void* snapshot) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto& provider = command_processor_.GetD3D12Context().GetD3D12Provider();
|
auto& provider = command_processor_.GetD3D12Context().GetD3D12Provider();
|
||||||
auto device = provider.GetDevice();
|
|
||||||
if (!edram_snapshot_restore_pool_) {
|
if (!edram_snapshot_restore_pool_) {
|
||||||
edram_snapshot_restore_pool_ =
|
edram_snapshot_restore_pool_ =
|
||||||
std::make_unique<ui::d3d12::UploadBufferPool>(device,
|
std::make_unique<ui::d3d12::UploadBufferPool>(provider,
|
||||||
xenos::kEdramSizeBytes);
|
xenos::kEdramSizeBytes);
|
||||||
}
|
}
|
||||||
ID3D12Resource* upload_buffer;
|
ID3D12Resource* upload_buffer;
|
||||||
|
@ -1603,14 +1608,15 @@ bool RenderTargetCache::MakeHeapResident(uint32_t heap_index) {
|
||||||
if (heaps_[heap_index] != nullptr) {
|
if (heaps_[heap_index] != nullptr) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
auto device =
|
auto& provider = command_processor_.GetD3D12Context().GetD3D12Provider();
|
||||||
command_processor_.GetD3D12Context().GetD3D12Provider().GetDevice();
|
auto device = provider.GetDevice();
|
||||||
D3D12_HEAP_DESC heap_desc = {};
|
D3D12_HEAP_DESC heap_desc = {};
|
||||||
heap_desc.SizeInBytes = kHeap4MBPages << 22;
|
heap_desc.SizeInBytes = kHeap4MBPages << 22;
|
||||||
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||||
// TODO(Triang3l): If real MSAA is added, alignment must be 4 MB.
|
// TODO(Triang3l): If real MSAA is added, alignment must be 4 MB.
|
||||||
heap_desc.Alignment = 0;
|
heap_desc.Alignment = 0;
|
||||||
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
|
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES |
|
||||||
|
provider.GetHeapFlagCreateNotZeroed();
|
||||||
if (FAILED(
|
if (FAILED(
|
||||||
device->CreateHeap(&heap_desc, IID_PPV_ARGS(&heaps_[heap_index])))) {
|
device->CreateHeap(&heap_desc, IID_PPV_ARGS(&heaps_[heap_index])))) {
|
||||||
XELOGE("Failed to create a {} MB heap for render targets",
|
XELOGE("Failed to create a {} MB heap for render targets",
|
||||||
|
@ -1756,8 +1762,9 @@ RenderTargetCache::RenderTarget* RenderTargetCache::FindOrCreateRenderTarget(
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&ui::d3d12::util::kHeapPropertiesDefault, D3D12_HEAP_FLAG_NONE,
|
&ui::d3d12::util::kHeapPropertiesDefault,
|
||||||
&resource_desc, state, nullptr, IID_PPV_ARGS(&resource)))) {
|
provider.GetHeapFlagCreateNotZeroed(), &resource_desc, state, nullptr,
|
||||||
|
IID_PPV_ARGS(&resource)))) {
|
||||||
XELOGE(
|
XELOGE(
|
||||||
"Failed to create a committed resource for {}x{} {} render target with "
|
"Failed to create a committed resource for {}x{} {} render target with "
|
||||||
"format {}",
|
"format {}",
|
||||||
|
|
|
@ -73,8 +73,9 @@ bool SharedMemory::Initialize() {
|
||||||
"resources yet.");
|
"resources yet.");
|
||||||
}
|
}
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&ui::d3d12::util::kHeapPropertiesDefault, D3D12_HEAP_FLAG_NONE,
|
&ui::d3d12::util::kHeapPropertiesDefault,
|
||||||
&buffer_desc, buffer_state_, nullptr, IID_PPV_ARGS(&buffer_)))) {
|
provider.GetHeapFlagCreateNotZeroed(), &buffer_desc, buffer_state_,
|
||||||
|
nullptr, IID_PPV_ARGS(&buffer_)))) {
|
||||||
XELOGE("Shared memory: Failed to create the 512 MB buffer");
|
XELOGE("Shared memory: Failed to create the 512 MB buffer");
|
||||||
Shutdown();
|
Shutdown();
|
||||||
return false;
|
return false;
|
||||||
|
@ -153,7 +154,7 @@ bool SharedMemory::Initialize() {
|
||||||
system_page_flags_.resize((page_count_ + 63) / 64);
|
system_page_flags_.resize((page_count_ + 63) / 64);
|
||||||
|
|
||||||
upload_buffer_pool_ = std::make_unique<ui::d3d12::UploadBufferPool>(
|
upload_buffer_pool_ = std::make_unique<ui::d3d12::UploadBufferPool>(
|
||||||
device,
|
provider,
|
||||||
xe::align(uint32_t(4 * 1024 * 1024), uint32_t(1) << page_size_log2_));
|
xe::align(uint32_t(4 * 1024 * 1024), uint32_t(1) << page_size_log2_));
|
||||||
|
|
||||||
memory_invalidation_callback_handle_ =
|
memory_invalidation_callback_handle_ =
|
||||||
|
@ -370,7 +371,8 @@ bool SharedMemory::EnsureTilesResident(uint32_t start, uint32_t length) {
|
||||||
D3D12_HEAP_DESC heap_desc = {};
|
D3D12_HEAP_DESC heap_desc = {};
|
||||||
heap_desc.SizeInBytes = kHeapSize;
|
heap_desc.SizeInBytes = kHeapSize;
|
||||||
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||||
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
|
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS |
|
||||||
|
provider.GetHeapFlagCreateNotZeroed();
|
||||||
if (FAILED(device->CreateHeap(&heap_desc, IID_PPV_ARGS(&heaps_[i])))) {
|
if (FAILED(device->CreateHeap(&heap_desc, IID_PPV_ARGS(&heaps_[i])))) {
|
||||||
XELOGE("Shared memory: Failed to create a tile heap");
|
XELOGE("Shared memory: Failed to create a tile heap");
|
||||||
return false;
|
return false;
|
||||||
|
@ -890,11 +892,12 @@ bool SharedMemory::InitializeTraceSubmitDownloads() {
|
||||||
ui::d3d12::util::FillBufferResourceDesc(
|
ui::d3d12::util::FillBufferResourceDesc(
|
||||||
gpu_written_buffer_desc, gpu_written_page_count << page_size_log2_,
|
gpu_written_buffer_desc, gpu_written_page_count << page_size_log2_,
|
||||||
D3D12_RESOURCE_FLAG_NONE);
|
D3D12_RESOURCE_FLAG_NONE);
|
||||||
auto device =
|
auto& provider = command_processor_.GetD3D12Context().GetD3D12Provider();
|
||||||
command_processor_.GetD3D12Context().GetD3D12Provider().GetDevice();
|
auto device = provider.GetDevice();
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&ui::d3d12::util::kHeapPropertiesReadback, D3D12_HEAP_FLAG_NONE,
|
&ui::d3d12::util::kHeapPropertiesReadback,
|
||||||
&gpu_written_buffer_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
|
provider.GetHeapFlagCreateNotZeroed(), &gpu_written_buffer_desc,
|
||||||
|
D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
|
||||||
IID_PPV_ARGS(&trace_gpu_written_buffer_)))) {
|
IID_PPV_ARGS(&trace_gpu_written_buffer_)))) {
|
||||||
XELOGE(
|
XELOGE(
|
||||||
"Shared memory: Failed to create a {} KB GPU-written memory download "
|
"Shared memory: Failed to create a {} KB GPU-written memory download "
|
||||||
|
|
|
@ -1633,7 +1633,8 @@ bool TextureCache::EnsureScaledResolveBufferResident(uint32_t start_unscaled,
|
||||||
D3D12_HEAP_DESC heap_desc = {};
|
D3D12_HEAP_DESC heap_desc = {};
|
||||||
heap_desc.SizeInBytes = kScaledResolveHeapSize;
|
heap_desc.SizeInBytes = kScaledResolveHeapSize;
|
||||||
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||||
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
|
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS |
|
||||||
|
provider.GetHeapFlagCreateNotZeroed();
|
||||||
if (FAILED(device->CreateHeap(&heap_desc,
|
if (FAILED(device->CreateHeap(&heap_desc,
|
||||||
IID_PPV_ARGS(&scaled_resolve_heaps_[i])))) {
|
IID_PPV_ARGS(&scaled_resolve_heaps_[i])))) {
|
||||||
XELOGE("Texture cache: Failed to create a scaled resolve tile heap");
|
XELOGE("Texture cache: Failed to create a scaled resolve tile heap");
|
||||||
|
@ -1953,14 +1954,15 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) {
|
||||||
// Untiling through a buffer instead of using unordered access because copying
|
// Untiling through a buffer instead of using unordered access because copying
|
||||||
// is not done that often.
|
// is not done that often.
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
auto device =
|
auto& provider = command_processor_.GetD3D12Context().GetD3D12Provider();
|
||||||
command_processor_.GetD3D12Context().GetD3D12Provider().GetDevice();
|
auto device = provider.GetDevice();
|
||||||
// Assuming untiling will be the next operation.
|
// Assuming untiling will be the next operation.
|
||||||
D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COPY_DEST;
|
D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
ID3D12Resource* resource;
|
ID3D12Resource* resource;
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&ui::d3d12::util::kHeapPropertiesDefault, D3D12_HEAP_FLAG_NONE, &desc,
|
&ui::d3d12::util::kHeapPropertiesDefault,
|
||||||
state, nullptr, IID_PPV_ARGS(&resource)))) {
|
provider.GetHeapFlagCreateNotZeroed(), &desc, state, nullptr,
|
||||||
|
IID_PPV_ARGS(&resource)))) {
|
||||||
LogTextureKeyAction(key, "Failed to create");
|
LogTextureKeyAction(key, "Failed to create");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "xenia/gpu/draw_util.h"
|
#include "xenia/gpu/draw_util.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
@ -31,6 +32,36 @@ DEFINE_bool(
|
||||||
"for certain games like GTA IV to work).",
|
"for certain games like GTA IV to work).",
|
||||||
"GPU");
|
"GPU");
|
||||||
|
|
||||||
|
DEFINE_bool(
|
||||||
|
present_rescale, true,
|
||||||
|
"Whether to rescale the image, instead of maintaining the original pixel "
|
||||||
|
"size, when presenting to the window. When this is disabled, other "
|
||||||
|
"positioning options are ignored.",
|
||||||
|
"GPU");
|
||||||
|
DEFINE_bool(
|
||||||
|
present_letterbox, true,
|
||||||
|
"Maintain aspect ratio when stretching by displaying bars around the image "
|
||||||
|
"when there's no more overscan area to crop out.",
|
||||||
|
"GPU");
|
||||||
|
// https://github.com/MonoGame/MonoGame/issues/4697#issuecomment-217779403
|
||||||
|
// Using the value from DirectXTK (5% cropped out from each side, thus 90%),
|
||||||
|
// which is not exactly the Xbox One title-safe area, but close, and within the
|
||||||
|
// action-safe area:
|
||||||
|
// https://github.com/microsoft/DirectXTK/blob/1e80a465c6960b457ef9ab6716672c1443a45024/Src/SimpleMath.cpp#L144
|
||||||
|
// XNA TitleSafeArea is 80%, but it's very conservative, designed for CRT, and
|
||||||
|
// is the title-safe area rather than the action-safe area.
|
||||||
|
// 90% is also exactly the fraction of 16:9 height in 16:10.
|
||||||
|
DEFINE_int32(
|
||||||
|
present_safe_area_x, 90,
|
||||||
|
"Percentage of the image width that can be kept when presenting to "
|
||||||
|
"maintain aspect ratio without letterboxing or stretching.",
|
||||||
|
"GPU");
|
||||||
|
DEFINE_int32(
|
||||||
|
present_safe_area_y, 90,
|
||||||
|
"Percentage of the image height that can be kept when presenting to "
|
||||||
|
"maintain aspect ratio without letterboxing or stretching.",
|
||||||
|
"GPU");
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
namespace draw_util {
|
namespace draw_util {
|
||||||
|
@ -589,6 +620,87 @@ ResolveCopyShaderIndex ResolveInfo::GetCopyShader(
|
||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetPresentArea(uint32_t source_width, uint32_t source_height,
|
||||||
|
uint32_t window_width, uint32_t window_height,
|
||||||
|
int32_t& target_x_out, int32_t& target_y_out,
|
||||||
|
uint32_t& target_width_out, uint32_t& target_height_out) {
|
||||||
|
if (!cvars::present_rescale) {
|
||||||
|
target_x_out = (int32_t(window_width) - int32_t(source_width)) / 2;
|
||||||
|
target_y_out = (int32_t(window_height) - int32_t(source_height)) / 2;
|
||||||
|
target_width_out = source_width;
|
||||||
|
target_height_out = source_height;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Prevent division by zero.
|
||||||
|
if (!source_width || !source_height) {
|
||||||
|
target_x_out = 0;
|
||||||
|
target_y_out = 0;
|
||||||
|
target_width_out = 0;
|
||||||
|
target_height_out = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (uint64_t(window_width) * source_height >
|
||||||
|
uint64_t(source_width) * window_height) {
|
||||||
|
// The window is wider that the source - crop along Y, then letterbox or
|
||||||
|
// stretch along X.
|
||||||
|
uint32_t present_safe_area;
|
||||||
|
if (cvars::present_safe_area_y > 0 && cvars::present_safe_area_y < 100) {
|
||||||
|
present_safe_area = uint32_t(cvars::present_safe_area_y);
|
||||||
|
} else {
|
||||||
|
present_safe_area = 100;
|
||||||
|
}
|
||||||
|
uint32_t target_height =
|
||||||
|
uint32_t(uint64_t(window_width) * source_height / source_width);
|
||||||
|
bool letterbox = false;
|
||||||
|
if (target_height * present_safe_area > window_height * 100) {
|
||||||
|
// Don't crop out more than the safe area margin - letterbox or stretch.
|
||||||
|
target_height = window_height * 100 / present_safe_area;
|
||||||
|
letterbox = true;
|
||||||
|
}
|
||||||
|
if (letterbox && cvars::present_letterbox) {
|
||||||
|
uint32_t target_width =
|
||||||
|
uint32_t(uint64_t(source_width) * window_height * 100 /
|
||||||
|
(source_height * present_safe_area));
|
||||||
|
target_x_out = (int32_t(window_width) - int32_t(target_width)) / 2;
|
||||||
|
target_width_out = target_width;
|
||||||
|
} else {
|
||||||
|
target_x_out = 0;
|
||||||
|
target_width_out = window_width;
|
||||||
|
}
|
||||||
|
target_y_out = (int32_t(window_height) - int32_t(target_height)) / 2;
|
||||||
|
target_height_out = target_height;
|
||||||
|
} else {
|
||||||
|
// The window is taller than the source - crop along X, then letterbox or
|
||||||
|
// stretch along Y.
|
||||||
|
uint32_t present_safe_area;
|
||||||
|
if (cvars::present_safe_area_x > 0 && cvars::present_safe_area_x < 100) {
|
||||||
|
present_safe_area = uint32_t(cvars::present_safe_area_x);
|
||||||
|
} else {
|
||||||
|
present_safe_area = 100;
|
||||||
|
}
|
||||||
|
uint32_t target_width =
|
||||||
|
uint32_t(uint64_t(window_height) * source_width / source_height);
|
||||||
|
bool letterbox = false;
|
||||||
|
if (target_width * present_safe_area > window_width * 100) {
|
||||||
|
// Don't crop out more than the safe area margin - letterbox or stretch.
|
||||||
|
target_width = window_width * 100 / present_safe_area;
|
||||||
|
letterbox = true;
|
||||||
|
}
|
||||||
|
if (letterbox && cvars::present_letterbox) {
|
||||||
|
uint32_t target_height =
|
||||||
|
uint32_t(uint64_t(source_height) * window_width * 100 /
|
||||||
|
(source_width * present_safe_area));
|
||||||
|
target_y_out = (int32_t(window_height) - int32_t(target_height)) / 2;
|
||||||
|
target_height_out = target_height;
|
||||||
|
} else {
|
||||||
|
target_y_out = 0;
|
||||||
|
target_height_out = window_height;
|
||||||
|
}
|
||||||
|
target_x_out = (int32_t(window_width) - int32_t(target_width)) / 2;
|
||||||
|
target_width_out = target_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace draw_util
|
} // namespace draw_util
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -272,6 +272,14 @@ bool GetResolveInfo(const RegisterFile& regs, const Memory& memory,
|
||||||
TraceWriter& trace_writer, uint32_t resolution_scale,
|
TraceWriter& trace_writer, uint32_t resolution_scale,
|
||||||
bool edram_16_as_minus_1_to_1, ResolveInfo& info_out);
|
bool edram_16_as_minus_1_to_1, ResolveInfo& info_out);
|
||||||
|
|
||||||
|
// Taking user configuration - stretching or letterboxing, overscan region to
|
||||||
|
// crop to fill while maintaining the aspect ratio - into account, returns the
|
||||||
|
// area where the frame should be presented in the host window.
|
||||||
|
void GetPresentArea(uint32_t source_width, uint32_t source_height,
|
||||||
|
uint32_t window_width, uint32_t window_height,
|
||||||
|
int32_t& target_x_out, int32_t& target_y_out,
|
||||||
|
uint32_t& target_width_out, uint32_t& target_height_out);
|
||||||
|
|
||||||
} // namespace draw_util
|
} // namespace draw_util
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -733,12 +733,6 @@ void DxbcShaderTranslator::ROV_DepthStencilTest() {
|
||||||
DxbcOpAnd(DxbcDest::R(system_temp_rov_params_, 0b0001),
|
DxbcOpAnd(DxbcDest::R(system_temp_rov_params_, 0b0001),
|
||||||
DxbcSrc::R(system_temp_rov_params_, DxbcSrc::kXXXX),
|
DxbcSrc::R(system_temp_rov_params_, DxbcSrc::kXXXX),
|
||||||
DxbcSrc::LU(~uint32_t(1 << i)));
|
DxbcSrc::LU(~uint32_t(1 << i)));
|
||||||
// temp.x? = resulting sample depth after the depth test
|
|
||||||
// temp.y = polygon offset if not writing to oDepth
|
|
||||||
// temp.z = viewport maximum depth if not writing to oDepth
|
|
||||||
// temp.w = old depth/stencil
|
|
||||||
// sample_temp.x = free
|
|
||||||
DxbcOpMov(sample_depth_stencil_dest, sample_temp_x_src);
|
|
||||||
}
|
}
|
||||||
DxbcOpEndIf();
|
DxbcOpEndIf();
|
||||||
// Create packed depth/stencil, with the stencil value unchanged at this
|
// Create packed depth/stencil, with the stencil value unchanged at this
|
||||||
|
@ -977,6 +971,25 @@ void DxbcShaderTranslator::ROV_DepthStencilTest() {
|
||||||
// Close the stencil test check.
|
// Close the stencil test check.
|
||||||
DxbcOpEndIf();
|
DxbcOpEndIf();
|
||||||
|
|
||||||
|
// Check if the depth/stencil has failed not to modify the depth if it has.
|
||||||
|
// sample_temp.x = whether depth/stencil has passed for this sample
|
||||||
|
DxbcOpAnd(sample_temp_x_dest,
|
||||||
|
DxbcSrc::R(system_temp_rov_params_, DxbcSrc::kXXXX),
|
||||||
|
DxbcSrc::LU(1 << i));
|
||||||
|
// If the depth/stencil test has failed, don't change the depth.
|
||||||
|
// sample_temp.x = free
|
||||||
|
DxbcOpIf(false, sample_temp_x_src);
|
||||||
|
{
|
||||||
|
// Copy the new stencil over the old depth.
|
||||||
|
// temp.x? = resulting sample depth/stencil
|
||||||
|
// temp.y = polygon offset if not writing to oDepth
|
||||||
|
// temp.z = viewport maximum depth if not writing to oDepth
|
||||||
|
// temp.w = old depth/stencil
|
||||||
|
DxbcOpBFI(sample_depth_stencil_dest, DxbcSrc::LU(8), DxbcSrc::LU(0),
|
||||||
|
sample_depth_stencil_src, temp_w_src);
|
||||||
|
}
|
||||||
|
// Close the depth/stencil passing check.
|
||||||
|
DxbcOpEndIf();
|
||||||
// Check if the new depth/stencil is different, and thus needs to be
|
// Check if the new depth/stencil is different, and thus needs to be
|
||||||
// written, to temp.w.
|
// written, to temp.w.
|
||||||
// temp.x? = resulting sample depth/stencil
|
// temp.x? = resulting sample depth/stencil
|
||||||
|
|
|
@ -9,9 +9,6 @@
|
||||||
|
|
||||||
#include "xenia/ui/d3d12/d3d12_context.h"
|
#include "xenia/ui/d3d12/d3d12_context.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#include "xenia/base/cvar.h"
|
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/math.h"
|
#include "xenia/base/math.h"
|
||||||
#include "xenia/ui/d3d12/d3d12_immediate_drawer.h"
|
#include "xenia/ui/d3d12/d3d12_immediate_drawer.h"
|
||||||
|
@ -19,9 +16,6 @@
|
||||||
#include "xenia/ui/d3d12/d3d12_util.h"
|
#include "xenia/ui/d3d12/d3d12_util.h"
|
||||||
#include "xenia/ui/window.h"
|
#include "xenia/ui/window.h"
|
||||||
|
|
||||||
DEFINE_bool(d3d12_random_clear_color, false,
|
|
||||||
"Randomize presentation back buffer clear color.", "D3D12");
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
namespace d3d12 {
|
namespace d3d12 {
|
||||||
|
@ -32,110 +26,112 @@ D3D12Context::D3D12Context(D3D12Provider* provider, Window* target_window)
|
||||||
D3D12Context::~D3D12Context() { Shutdown(); }
|
D3D12Context::~D3D12Context() { Shutdown(); }
|
||||||
|
|
||||||
bool D3D12Context::Initialize() {
|
bool D3D12Context::Initialize() {
|
||||||
|
context_lost_ = false;
|
||||||
|
|
||||||
|
if (!target_window_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
auto& provider = GetD3D12Provider();
|
auto& provider = GetD3D12Provider();
|
||||||
auto dxgi_factory = provider.GetDXGIFactory();
|
auto dxgi_factory = provider.GetDXGIFactory();
|
||||||
auto device = provider.GetDevice();
|
auto device = provider.GetDevice();
|
||||||
auto direct_queue = provider.GetDirectQueue();
|
auto direct_queue = provider.GetDirectQueue();
|
||||||
|
|
||||||
context_lost_ = false;
|
swap_fence_current_value_ = 1;
|
||||||
|
swap_fence_completed_value_ = 0;
|
||||||
|
swap_fence_completion_event_ = CreateEvent(nullptr, false, false, nullptr);
|
||||||
|
if (swap_fence_completion_event_ == nullptr) {
|
||||||
|
XELOGE("Failed to create the composition fence completion event");
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Create a fence for transient resources of compositing.
|
||||||
|
if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE,
|
||||||
|
IID_PPV_ARGS(&swap_fence_)))) {
|
||||||
|
XELOGE("Failed to create the composition fence");
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (target_window_) {
|
// Create the swap chain.
|
||||||
swap_fence_current_value_ = 1;
|
swap_chain_width_ = target_window_->scaled_width();
|
||||||
swap_fence_completed_value_ = 0;
|
swap_chain_height_ = target_window_->scaled_height();
|
||||||
swap_fence_completion_event_ = CreateEvent(nullptr, false, false, nullptr);
|
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc;
|
||||||
if (swap_fence_completion_event_ == nullptr) {
|
swap_chain_desc.Width = swap_chain_width_;
|
||||||
XELOGE("Failed to create the composition fence completion event");
|
swap_chain_desc.Height = swap_chain_height_;
|
||||||
Shutdown();
|
swap_chain_desc.Format = kSwapChainFormat;
|
||||||
return false;
|
swap_chain_desc.Stereo = FALSE;
|
||||||
}
|
swap_chain_desc.SampleDesc.Count = 1;
|
||||||
// Create a fence for transient resources of compositing.
|
swap_chain_desc.SampleDesc.Quality = 0;
|
||||||
if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE,
|
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||||
IID_PPV_ARGS(&swap_fence_)))) {
|
swap_chain_desc.BufferCount = kSwapChainBufferCount;
|
||||||
XELOGE("Failed to create the composition fence");
|
swap_chain_desc.Scaling = DXGI_SCALING_STRETCH;
|
||||||
Shutdown();
|
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||||
return false;
|
swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
|
||||||
}
|
swap_chain_desc.Flags = 0;
|
||||||
|
IDXGISwapChain1* swap_chain_1;
|
||||||
// Create the swap chain.
|
if (FAILED(dxgi_factory->CreateSwapChainForHwnd(
|
||||||
swap_chain_width_ = target_window_->scaled_width();
|
provider.GetDirectQueue(),
|
||||||
swap_chain_height_ = target_window_->scaled_height();
|
reinterpret_cast<HWND>(target_window_->native_handle()),
|
||||||
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc;
|
&swap_chain_desc, nullptr, nullptr, &swap_chain_1))) {
|
||||||
swap_chain_desc.Width = swap_chain_width_;
|
XELOGE("Failed to create a DXGI swap chain");
|
||||||
swap_chain_desc.Height = swap_chain_height_;
|
Shutdown();
|
||||||
swap_chain_desc.Format = kSwapChainFormat;
|
return false;
|
||||||
swap_chain_desc.Stereo = FALSE;
|
}
|
||||||
swap_chain_desc.SampleDesc.Count = 1;
|
if (FAILED(swap_chain_1->QueryInterface(IID_PPV_ARGS(&swap_chain_)))) {
|
||||||
swap_chain_desc.SampleDesc.Quality = 0;
|
XELOGE("Failed to get version 3 of the DXGI swap chain interface");
|
||||||
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
|
||||||
swap_chain_desc.BufferCount = kSwapChainBufferCount;
|
|
||||||
swap_chain_desc.Scaling = DXGI_SCALING_STRETCH;
|
|
||||||
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
|
||||||
swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
|
|
||||||
swap_chain_desc.Flags = 0;
|
|
||||||
IDXGISwapChain1* swap_chain_1;
|
|
||||||
if (FAILED(dxgi_factory->CreateSwapChainForHwnd(
|
|
||||||
provider.GetDirectQueue(),
|
|
||||||
static_cast<HWND>(target_window_->native_handle()),
|
|
||||||
&swap_chain_desc, nullptr, nullptr, &swap_chain_1))) {
|
|
||||||
XELOGE("Failed to create a DXGI swap chain");
|
|
||||||
Shutdown();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (FAILED(swap_chain_1->QueryInterface(IID_PPV_ARGS(&swap_chain_)))) {
|
|
||||||
XELOGE("Failed to get version 3 of the DXGI swap chain interface");
|
|
||||||
swap_chain_1->Release();
|
|
||||||
Shutdown();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
swap_chain_1->Release();
|
swap_chain_1->Release();
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
swap_chain_1->Release();
|
||||||
|
|
||||||
// Create a heap for RTV descriptors of swap chain buffers.
|
// Create a heap for RTV descriptors of swap chain buffers.
|
||||||
D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc;
|
D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc;
|
||||||
rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
||||||
rtv_heap_desc.NumDescriptors = kSwapChainBufferCount;
|
rtv_heap_desc.NumDescriptors = kSwapChainBufferCount;
|
||||||
rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||||
rtv_heap_desc.NodeMask = 0;
|
rtv_heap_desc.NodeMask = 0;
|
||||||
if (FAILED(device->CreateDescriptorHeap(
|
if (FAILED(device->CreateDescriptorHeap(
|
||||||
&rtv_heap_desc, IID_PPV_ARGS(&swap_chain_rtv_heap_)))) {
|
&rtv_heap_desc, IID_PPV_ARGS(&swap_chain_rtv_heap_)))) {
|
||||||
XELOGE("Failed to create swap chain RTV descriptor heap");
|
XELOGE("Failed to create swap chain RTV descriptor heap");
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
swap_chain_rtv_heap_start_ =
|
||||||
|
swap_chain_rtv_heap_->GetCPUDescriptorHandleForHeapStart();
|
||||||
|
|
||||||
|
// Get the buffers and create their RTV descriptors.
|
||||||
|
if (!InitializeSwapChainBuffers()) {
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the command list for compositing.
|
||||||
|
for (uint32_t i = 0; i < kSwapCommandAllocatorCount; ++i) {
|
||||||
|
if (FAILED(device->CreateCommandAllocator(
|
||||||
|
D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||||
|
IID_PPV_ARGS(&swap_command_allocators_[i])))) {
|
||||||
|
XELOGE("Failed to create a composition command allocator");
|
||||||
Shutdown();
|
Shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
swap_chain_rtv_heap_start_ =
|
}
|
||||||
swap_chain_rtv_heap_->GetCPUDescriptorHandleForHeapStart();
|
if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||||
|
swap_command_allocators_[0], nullptr,
|
||||||
|
IID_PPV_ARGS(&swap_command_list_)))) {
|
||||||
|
XELOGE("Failed to create the composition graphics command list");
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Initially in open state, wait until BeginSwap.
|
||||||
|
swap_command_list_->Close();
|
||||||
|
|
||||||
// Get the buffers and create their RTV descriptors.
|
// Initialize the immediate mode drawer if not offscreen.
|
||||||
if (!InitializeSwapChainBuffers()) {
|
immediate_drawer_ = std::make_unique<D3D12ImmediateDrawer>(*this);
|
||||||
Shutdown();
|
if (!immediate_drawer_->Initialize()) {
|
||||||
return false;
|
Shutdown();
|
||||||
}
|
return false;
|
||||||
|
|
||||||
// Create the command list for compositing.
|
|
||||||
for (uint32_t i = 0; i < kSwapCommandAllocatorCount; ++i) {
|
|
||||||
if (FAILED(device->CreateCommandAllocator(
|
|
||||||
D3D12_COMMAND_LIST_TYPE_DIRECT,
|
|
||||||
IID_PPV_ARGS(&swap_command_allocators_[i])))) {
|
|
||||||
XELOGE("Failed to create a composition command allocator");
|
|
||||||
Shutdown();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,
|
|
||||||
swap_command_allocators_[0], nullptr,
|
|
||||||
IID_PPV_ARGS(&swap_command_list_)))) {
|
|
||||||
XELOGE("Failed to create the composition graphics command list");
|
|
||||||
Shutdown();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Initially in open state, wait until BeginSwap.
|
|
||||||
swap_command_list_->Close();
|
|
||||||
|
|
||||||
// Initialize the immediate mode drawer if not offscreen.
|
|
||||||
immediate_drawer_ = std::make_unique<D3D12ImmediateDrawer>(*this);
|
|
||||||
if (!immediate_drawer_->Initialize()) {
|
|
||||||
Shutdown();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -223,9 +219,11 @@ ImmediateDrawer* D3D12Context::immediate_drawer() {
|
||||||
return immediate_drawer_.get();
|
return immediate_drawer_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12Context::BeginSwap() {
|
bool D3D12Context::WasLost() { return context_lost_; }
|
||||||
|
|
||||||
|
bool D3D12Context::BeginSwap() {
|
||||||
if (!target_window_ || context_lost_) {
|
if (!target_window_ || context_lost_) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize the swap chain if the window is resized.
|
// Resize the swap chain if the window is resized.
|
||||||
|
@ -252,13 +250,13 @@ void D3D12Context::BeginSwap() {
|
||||||
kSwapChainBufferCount, target_window_width, target_window_height,
|
kSwapChainBufferCount, target_window_width, target_window_height,
|
||||||
kSwapChainFormat, 0))) {
|
kSwapChainFormat, 0))) {
|
||||||
context_lost_ = true;
|
context_lost_ = true;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
swap_chain_width_ = target_window_width;
|
swap_chain_width_ = target_window_width;
|
||||||
swap_chain_height_ = target_window_height;
|
swap_chain_height_ = target_window_height;
|
||||||
if (!InitializeSwapChainBuffers()) {
|
if (!InitializeSwapChainBuffers()) {
|
||||||
context_lost_ = true;
|
context_lost_ = true;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,18 +293,11 @@ void D3D12Context::BeginSwap() {
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE back_buffer_rtv = GetSwapChainBackBufferRTV();
|
D3D12_CPU_DESCRIPTOR_HANDLE back_buffer_rtv = GetSwapChainBackBufferRTV();
|
||||||
swap_command_list_->OMSetRenderTargets(1, &back_buffer_rtv, TRUE, nullptr);
|
swap_command_list_->OMSetRenderTargets(1, &back_buffer_rtv, TRUE, nullptr);
|
||||||
float clear_color[4];
|
float clear_color[4];
|
||||||
if (cvars::d3d12_random_clear_color) {
|
GetClearColor(clear_color);
|
||||||
clear_color[0] = rand() / float(RAND_MAX); // NOLINT(runtime/threadsafe_fn)
|
|
||||||
clear_color[1] = 1.0f;
|
|
||||||
clear_color[2] = 0.0f;
|
|
||||||
} else {
|
|
||||||
clear_color[0] = 238.0f / 255.0f;
|
|
||||||
clear_color[1] = 238.0f / 255.0f;
|
|
||||||
clear_color[2] = 238.0f / 255.0f;
|
|
||||||
}
|
|
||||||
clear_color[3] = 1.0f;
|
|
||||||
swap_command_list_->ClearRenderTargetView(back_buffer_rtv, clear_color, 0,
|
swap_command_list_->ClearRenderTargetView(back_buffer_rtv, clear_color, 0,
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12Context::EndSwap() {
|
void D3D12Context::EndSwap() {
|
||||||
|
|
|
@ -28,9 +28,9 @@ class D3D12Context : public GraphicsContext {
|
||||||
|
|
||||||
ImmediateDrawer* immediate_drawer() override;
|
ImmediateDrawer* immediate_drawer() override;
|
||||||
|
|
||||||
bool WasLost() override { return context_lost_; }
|
bool WasLost() override;
|
||||||
|
|
||||||
void BeginSwap() override;
|
bool BeginSwap() override;
|
||||||
void EndSwap() override;
|
void EndSwap() override;
|
||||||
|
|
||||||
std::unique_ptr<RawImage> Capture() override;
|
std::unique_ptr<RawImage> Capture() override;
|
||||||
|
@ -69,11 +69,10 @@ class D3D12Context : public GraphicsContext {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class D3D12Provider;
|
friend class D3D12Provider;
|
||||||
|
|
||||||
explicit D3D12Context(D3D12Provider* provider, Window* target_window);
|
explicit D3D12Context(D3D12Provider* provider, Window* target_window);
|
||||||
|
bool Initialize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool Initialize();
|
|
||||||
bool InitializeSwapChainBuffers();
|
bool InitializeSwapChainBuffers();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ class D3D12ImmediateTexture : public ImmediateTexture {
|
||||||
ImmediateTextureFilter filter, bool repeat);
|
ImmediateTextureFilter filter, bool repeat);
|
||||||
~D3D12ImmediateTexture() override;
|
~D3D12ImmediateTexture() override;
|
||||||
|
|
||||||
bool Initialize(ID3D12Device* device);
|
bool Initialize(D3D12Provider& provider);
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
ID3D12Resource* GetResource() const { return resource_; }
|
ID3D12Resource* GetResource() const { return resource_; }
|
||||||
|
@ -59,7 +59,7 @@ D3D12ImmediateTexture::D3D12ImmediateTexture(uint32_t width, uint32_t height,
|
||||||
|
|
||||||
D3D12ImmediateTexture::~D3D12ImmediateTexture() { Shutdown(); }
|
D3D12ImmediateTexture::~D3D12ImmediateTexture() { Shutdown(); }
|
||||||
|
|
||||||
bool D3D12ImmediateTexture::Initialize(ID3D12Device* device) {
|
bool D3D12ImmediateTexture::Initialize(D3D12Provider& provider) {
|
||||||
// The first operation will likely be copying the contents.
|
// The first operation will likely be copying the contents.
|
||||||
state_ = D3D12_RESOURCE_STATE_COPY_DEST;
|
state_ = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
|
||||||
|
@ -75,9 +75,9 @@ bool D3D12ImmediateTexture::Initialize(ID3D12Device* device) {
|
||||||
resource_desc.SampleDesc.Quality = 0;
|
resource_desc.SampleDesc.Quality = 0;
|
||||||
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||||
resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(provider.GetDevice()->CreateCommittedResource(
|
||||||
&util::kHeapPropertiesDefault, D3D12_HEAP_FLAG_NONE, &resource_desc,
|
&util::kHeapPropertiesDefault, provider.GetHeapFlagCreateNotZeroed(),
|
||||||
state_, nullptr, IID_PPV_ARGS(&resource_)))) {
|
&resource_desc, state_, nullptr, IID_PPV_ARGS(&resource_)))) {
|
||||||
XELOGE("Failed to create a {}x{} texture for immediate drawing", width,
|
XELOGE("Failed to create a {}x{} texture for immediate drawing", width,
|
||||||
height);
|
height);
|
||||||
return false;
|
return false;
|
||||||
|
@ -288,7 +288,7 @@ bool D3D12ImmediateDrawer::Initialize() {
|
||||||
|
|
||||||
// Create pools for draws.
|
// Create pools for draws.
|
||||||
vertex_buffer_pool_ =
|
vertex_buffer_pool_ =
|
||||||
std::make_unique<UploadBufferPool>(device, 2 * 1024 * 1024);
|
std::make_unique<UploadBufferPool>(provider, 2 * 1024 * 1024);
|
||||||
texture_descriptor_pool_ = std::make_unique<DescriptorHeapPool>(
|
texture_descriptor_pool_ = std::make_unique<DescriptorHeapPool>(
|
||||||
device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2048);
|
device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2048);
|
||||||
texture_descriptor_pool_heap_index_ = DescriptorHeapPool::kHeapIndexInvalid;
|
texture_descriptor_pool_heap_index_ = DescriptorHeapPool::kHeapIndexInvalid;
|
||||||
|
@ -326,7 +326,7 @@ std::unique_ptr<ImmediateTexture> D3D12ImmediateDrawer::CreateTexture(
|
||||||
const uint8_t* data) {
|
const uint8_t* data) {
|
||||||
auto texture =
|
auto texture =
|
||||||
std::make_unique<D3D12ImmediateTexture>(width, height, filter, repeat);
|
std::make_unique<D3D12ImmediateTexture>(width, height, filter, repeat);
|
||||||
texture->Initialize(context_.GetD3D12Provider().GetDevice());
|
texture->Initialize(context_.GetD3D12Provider());
|
||||||
if (data != nullptr) {
|
if (data != nullptr) {
|
||||||
UpdateTexture(texture.get(), data);
|
UpdateTexture(texture.get(), data);
|
||||||
}
|
}
|
||||||
|
@ -343,7 +343,8 @@ void D3D12ImmediateDrawer::UpdateTexture(ImmediateTexture* texture,
|
||||||
}
|
}
|
||||||
uint32_t width = d3d_texture->width, height = d3d_texture->height;
|
uint32_t width = d3d_texture->width, height = d3d_texture->height;
|
||||||
|
|
||||||
auto device = context_.GetD3D12Provider().GetDevice();
|
auto& provider = context_.GetD3D12Provider();
|
||||||
|
auto device = provider.GetDevice();
|
||||||
|
|
||||||
// Create and fill the upload buffer.
|
// Create and fill the upload buffer.
|
||||||
D3D12_RESOURCE_DESC texture_desc = texture_resource->GetDesc();
|
D3D12_RESOURCE_DESC texture_desc = texture_resource->GetDesc();
|
||||||
|
@ -356,8 +357,9 @@ void D3D12ImmediateDrawer::UpdateTexture(ImmediateTexture* texture,
|
||||||
D3D12_RESOURCE_FLAG_NONE);
|
D3D12_RESOURCE_FLAG_NONE);
|
||||||
ID3D12Resource* buffer;
|
ID3D12Resource* buffer;
|
||||||
if (FAILED(device->CreateCommittedResource(
|
if (FAILED(device->CreateCommittedResource(
|
||||||
&util::kHeapPropertiesUpload, D3D12_HEAP_FLAG_NONE, &buffer_desc,
|
&util::kHeapPropertiesUpload, provider.GetHeapFlagCreateNotZeroed(),
|
||||||
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&buffer)))) {
|
&buffer_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
|
||||||
|
IID_PPV_ARGS(&buffer)))) {
|
||||||
XELOGE(
|
XELOGE(
|
||||||
"Failed to create an upload buffer for a {}x{} texture for "
|
"Failed to create an upload buffer for a {}x{} texture for "
|
||||||
"immediate drawing",
|
"immediate drawing",
|
||||||
|
|
|
@ -383,6 +383,14 @@ bool D3D12Provider::Initialize() {
|
||||||
device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
||||||
|
|
||||||
// Check if optional features are supported.
|
// Check if optional features are supported.
|
||||||
|
// D3D12_HEAP_FLAG_CREATE_NOT_ZEROED requires Windows 10 2004 (indicated by
|
||||||
|
// the availability of ID3D12Device8 or D3D12_FEATURE_D3D12_OPTIONS7).
|
||||||
|
heap_flag_create_not_zeroed_ = D3D12_HEAP_FLAG_NONE;
|
||||||
|
D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7;
|
||||||
|
if (SUCCEEDED(device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7,
|
||||||
|
&options7, sizeof(options7)))) {
|
||||||
|
heap_flag_create_not_zeroed_ = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
|
||||||
|
}
|
||||||
rasterizer_ordered_views_supported_ = false;
|
rasterizer_ordered_views_supported_ = false;
|
||||||
resource_binding_tier_ = D3D12_RESOURCE_BINDING_TIER_1;
|
resource_binding_tier_ = D3D12_RESOURCE_BINDING_TIER_1;
|
||||||
tiled_resources_tier_ = D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED;
|
tiled_resources_tier_ = D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED;
|
||||||
|
@ -410,13 +418,16 @@ bool D3D12Provider::Initialize() {
|
||||||
virtual_address_support.MaxGPUVirtualAddressBitsPerResource;
|
virtual_address_support.MaxGPUVirtualAddressBitsPerResource;
|
||||||
}
|
}
|
||||||
XELOGD3D(
|
XELOGD3D(
|
||||||
"Direct3D 12 device features:\n"
|
"Direct3D 12 device and OS features:\n"
|
||||||
"Max GPU virtual address bits per resource: {}\n"
|
"* Max GPU virtual address bits per resource: {}\n"
|
||||||
"Programmable sample positions: tier {}\n"
|
"* Non-zeroed heap creation: {}\n"
|
||||||
"Rasterizer-ordered views: {}\n"
|
"* Programmable sample positions: tier {}\n"
|
||||||
"Resource binding: tier {}\n"
|
"* Rasterizer-ordered views: {}\n"
|
||||||
"Tiled resources: tier {}\n",
|
"* Resource binding: tier {}\n"
|
||||||
|
"* Tiled resources: tier {}\n",
|
||||||
virtual_address_bits_per_resource_,
|
virtual_address_bits_per_resource_,
|
||||||
|
(heap_flag_create_not_zeroed_ & D3D12_HEAP_FLAG_CREATE_NOT_ZEROED) ? "yes"
|
||||||
|
: "no",
|
||||||
uint32_t(programmable_sample_positions_tier_),
|
uint32_t(programmable_sample_positions_tier_),
|
||||||
rasterizer_ordered_views_supported_ ? "yes" : "no",
|
rasterizer_ordered_views_supported_ ? "yes" : "no",
|
||||||
uint32_t(resource_binding_tier_), uint32_t(tiled_resources_tier_));
|
uint32_t(resource_binding_tier_), uint32_t(tiled_resources_tier_));
|
||||||
|
|
|
@ -68,6 +68,9 @@ class D3D12Provider : public GraphicsProvider {
|
||||||
uint32_t GetAdapterVendorID() const { return adapter_vendor_id_; }
|
uint32_t GetAdapterVendorID() const { return adapter_vendor_id_; }
|
||||||
|
|
||||||
// Device features.
|
// Device features.
|
||||||
|
D3D12_HEAP_FLAGS GetHeapFlagCreateNotZeroed() const {
|
||||||
|
return heap_flag_create_not_zeroed_;
|
||||||
|
}
|
||||||
D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER
|
D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER
|
||||||
GetProgrammableSamplePositionsTier() const {
|
GetProgrammableSamplePositionsTier() const {
|
||||||
return programmable_sample_positions_tier_;
|
return programmable_sample_positions_tier_;
|
||||||
|
@ -159,6 +162,7 @@ class D3D12Provider : public GraphicsProvider {
|
||||||
|
|
||||||
uint32_t adapter_vendor_id_;
|
uint32_t adapter_vendor_id_;
|
||||||
|
|
||||||
|
D3D12_HEAP_FLAGS heap_flag_create_not_zeroed_;
|
||||||
D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER programmable_sample_positions_tier_;
|
D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER programmable_sample_positions_tier_;
|
||||||
bool rasterizer_ordered_views_supported_;
|
bool rasterizer_ordered_views_supported_;
|
||||||
D3D12_RESOURCE_BINDING_TIER resource_binding_tier_;
|
D3D12_RESOURCE_BINDING_TIER resource_binding_tier_;
|
||||||
|
|
|
@ -19,8 +19,8 @@ namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
namespace d3d12 {
|
namespace d3d12 {
|
||||||
|
|
||||||
UploadBufferPool::UploadBufferPool(ID3D12Device* device, uint32_t page_size)
|
UploadBufferPool::UploadBufferPool(D3D12Provider& provider, uint32_t page_size)
|
||||||
: device_(device), page_size_(page_size) {}
|
: provider_(provider), page_size_(page_size) {}
|
||||||
|
|
||||||
UploadBufferPool::~UploadBufferPool() { ClearCache(); }
|
UploadBufferPool::~UploadBufferPool() { ClearCache(); }
|
||||||
|
|
||||||
|
@ -101,9 +101,10 @@ uint8_t* UploadBufferPool::Request(uint64_t submission_index, uint32_t size,
|
||||||
util::FillBufferResourceDesc(new_buffer_desc, page_size_,
|
util::FillBufferResourceDesc(new_buffer_desc, page_size_,
|
||||||
D3D12_RESOURCE_FLAG_NONE);
|
D3D12_RESOURCE_FLAG_NONE);
|
||||||
ID3D12Resource* new_buffer;
|
ID3D12Resource* new_buffer;
|
||||||
if (FAILED(device_->CreateCommittedResource(
|
if (FAILED(provider_.GetDevice()->CreateCommittedResource(
|
||||||
&util::kHeapPropertiesUpload, D3D12_HEAP_FLAG_NONE,
|
&util::kHeapPropertiesUpload,
|
||||||
&new_buffer_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
|
provider_.GetHeapFlagCreateNotZeroed(), &new_buffer_desc,
|
||||||
|
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
|
||||||
IID_PPV_ARGS(&new_buffer)))) {
|
IID_PPV_ARGS(&new_buffer)))) {
|
||||||
XELOGE("Failed to create a D3D upload buffer with {} bytes",
|
XELOGE("Failed to create a D3D upload buffer with {} bytes",
|
||||||
page_size_);
|
page_size_);
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "xenia/ui/d3d12/d3d12_api.h"
|
#include "xenia/ui/d3d12/d3d12_provider.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
@ -23,7 +23,7 @@ namespace d3d12 {
|
||||||
|
|
||||||
class UploadBufferPool {
|
class UploadBufferPool {
|
||||||
public:
|
public:
|
||||||
UploadBufferPool(ID3D12Device* device, uint32_t page_size);
|
UploadBufferPool(D3D12Provider& provider, uint32_t page_size);
|
||||||
~UploadBufferPool();
|
~UploadBufferPool();
|
||||||
|
|
||||||
void Reclaim(uint64_t completed_submission_index);
|
void Reclaim(uint64_t completed_submission_index);
|
||||||
|
@ -41,7 +41,7 @@ class UploadBufferPool {
|
||||||
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out);
|
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ID3D12Device* device_;
|
D3D12Provider& provider_;
|
||||||
uint32_t page_size_;
|
uint32_t page_size_;
|
||||||
|
|
||||||
struct Page {
|
struct Page {
|
||||||
|
|
|
@ -9,8 +9,13 @@
|
||||||
|
|
||||||
#include "xenia/ui/graphics_context.h"
|
#include "xenia/ui/graphics_context.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include "xenia/base/cvar.h"
|
||||||
#include "xenia/ui/graphics_provider.h"
|
#include "xenia/ui/graphics_provider.h"
|
||||||
|
|
||||||
|
DEFINE_bool(random_clear_color, false, "Randomize window clear color.", "UI");
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
@ -26,5 +31,18 @@ bool GraphicsContext::MakeCurrent() { return true; }
|
||||||
|
|
||||||
void GraphicsContext::ClearCurrent() {}
|
void GraphicsContext::ClearCurrent() {}
|
||||||
|
|
||||||
|
void GraphicsContext::GetClearColor(float* rgba) {
|
||||||
|
if (cvars::random_clear_color) {
|
||||||
|
rgba[0] = rand() / float(RAND_MAX); // NOLINT(runtime/threadsafe_fn)
|
||||||
|
rgba[1] = 1.0f;
|
||||||
|
rgba[2] = 0.0f;
|
||||||
|
} else {
|
||||||
|
rgba[0] = 0.0f;
|
||||||
|
rgba[1] = 0.0f;
|
||||||
|
rgba[2] = 0.0f;
|
||||||
|
}
|
||||||
|
rgba[3] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -51,7 +51,8 @@ class GraphicsContext {
|
||||||
// This context must be made current in order for this call to work properly.
|
// This context must be made current in order for this call to work properly.
|
||||||
virtual bool WasLost() = 0;
|
virtual bool WasLost() = 0;
|
||||||
|
|
||||||
virtual void BeginSwap() = 0;
|
// Returns true if able to draw now (the target surface is available).
|
||||||
|
virtual bool BeginSwap() = 0;
|
||||||
virtual void EndSwap() = 0;
|
virtual void EndSwap() = 0;
|
||||||
|
|
||||||
virtual std::unique_ptr<RawImage> Capture() = 0;
|
virtual std::unique_ptr<RawImage> Capture() = 0;
|
||||||
|
@ -59,6 +60,8 @@ class GraphicsContext {
|
||||||
protected:
|
protected:
|
||||||
explicit GraphicsContext(GraphicsProvider* provider, Window* target_window);
|
explicit GraphicsContext(GraphicsProvider* provider, Window* target_window);
|
||||||
|
|
||||||
|
static void GetClearColor(float* rgba);
|
||||||
|
|
||||||
GraphicsProvider* provider_ = nullptr;
|
GraphicsProvider* provider_ = nullptr;
|
||||||
Window* target_window_ = nullptr;
|
Window* target_window_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -141,7 +141,7 @@ bool VulkanContext::MakeCurrent() {
|
||||||
|
|
||||||
void VulkanContext::ClearCurrent() {}
|
void VulkanContext::ClearCurrent() {}
|
||||||
|
|
||||||
void VulkanContext::BeginSwap() {
|
bool VulkanContext::BeginSwap() {
|
||||||
SCOPE_profile_cpu_f("gpu");
|
SCOPE_profile_cpu_f("gpu");
|
||||||
auto provider = static_cast<VulkanProvider*>(provider_);
|
auto provider = static_cast<VulkanProvider*>(provider_);
|
||||||
auto device = provider->device();
|
auto device = provider->device();
|
||||||
|
@ -170,6 +170,8 @@ void VulkanContext::BeginSwap() {
|
||||||
// TODO(benvanik): use a fence instead? May not be possible with target image.
|
// TODO(benvanik): use a fence instead? May not be possible with target image.
|
||||||
std::lock_guard<std::mutex> queue_lock(device->primary_queue_mutex());
|
std::lock_guard<std::mutex> queue_lock(device->primary_queue_mutex());
|
||||||
status = vkQueueWaitIdle(device->primary_queue());
|
status = vkQueueWaitIdle(device->primary_queue());
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanContext::EndSwap() {
|
void VulkanContext::EndSwap() {
|
||||||
|
|
|
@ -40,7 +40,7 @@ class VulkanContext : public GraphicsContext {
|
||||||
|
|
||||||
bool WasLost() override { return context_lost_; }
|
bool WasLost() override { return context_lost_; }
|
||||||
|
|
||||||
void BeginSwap() override;
|
bool BeginSwap() override;
|
||||||
void EndSwap() override;
|
void EndSwap() override;
|
||||||
|
|
||||||
std::unique_ptr<RawImage> Capture() override;
|
std::unique_ptr<RawImage> Capture() override;
|
||||||
|
|
|
@ -233,11 +233,15 @@ void Window::OnPaint(UIEvent* e) {
|
||||||
io.DisplaySize = ImVec2(static_cast<float>(scaled_width()),
|
io.DisplaySize = ImVec2(static_cast<float>(scaled_width()),
|
||||||
static_cast<float>(scaled_height()));
|
static_cast<float>(scaled_height()));
|
||||||
|
|
||||||
context_->BeginSwap();
|
bool can_swap = context_->BeginSwap();
|
||||||
if (context_->WasLost()) {
|
if (context_->WasLost()) {
|
||||||
on_context_lost(e);
|
on_context_lost(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!can_swap) {
|
||||||
|
// Surface not available.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
|
|
@ -253,20 +253,6 @@ bool Win32Window::ReleaseMouse() {
|
||||||
|
|
||||||
bool Win32Window::is_fullscreen() const { return fullscreen_; }
|
bool Win32Window::is_fullscreen() const { return fullscreen_; }
|
||||||
|
|
||||||
// https://blogs.msdn.microsoft.com/oldnewthing/20131017-00/?p=2903
|
|
||||||
BOOL UnadjustWindowRect(LPRECT prc, DWORD dwStyle, BOOL fMenu) {
|
|
||||||
RECT rc;
|
|
||||||
SetRectEmpty(&rc);
|
|
||||||
BOOL fRc = AdjustWindowRect(&rc, dwStyle, fMenu);
|
|
||||||
if (fRc) {
|
|
||||||
prc->left -= rc.left;
|
|
||||||
prc->top -= rc.top;
|
|
||||||
prc->right -= rc.right;
|
|
||||||
prc->bottom -= rc.bottom;
|
|
||||||
}
|
|
||||||
return fRc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Win32Window::ToggleFullscreen(bool fullscreen) {
|
void Win32Window::ToggleFullscreen(bool fullscreen) {
|
||||||
if (fullscreen == is_fullscreen()) {
|
if (fullscreen == is_fullscreen()) {
|
||||||
return;
|
return;
|
||||||
|
@ -288,9 +274,6 @@ void Win32Window::ToggleFullscreen(bool fullscreen) {
|
||||||
AdjustWindowRect(&rc, GetWindowLong(hwnd_, GWL_STYLE), false);
|
AdjustWindowRect(&rc, GetWindowLong(hwnd_, GWL_STYLE), false);
|
||||||
MoveWindow(hwnd_, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
|
MoveWindow(hwnd_, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
|
||||||
TRUE);
|
TRUE);
|
||||||
|
|
||||||
width_ = rc.right - rc.left;
|
|
||||||
height_ = rc.bottom - rc.top;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Reinstate borders, resize to 1280x720
|
// Reinstate borders, resize to 1280x720
|
||||||
|
@ -301,15 +284,13 @@ void Win32Window::ToggleFullscreen(bool fullscreen) {
|
||||||
if (main_menu) {
|
if (main_menu) {
|
||||||
::SetMenu(hwnd_, main_menu->handle());
|
::SetMenu(hwnd_, main_menu->handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& rc = windowed_pos_.rcNormalPosition;
|
|
||||||
bool has_menu = main_menu_ ? true : false;
|
|
||||||
UnadjustWindowRect(&rc, GetWindowLong(hwnd_, GWL_STYLE), has_menu);
|
|
||||||
width_ = rc.right - rc.left;
|
|
||||||
height_ = rc.bottom - rc.top;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fullscreen_ = fullscreen;
|
fullscreen_ = fullscreen;
|
||||||
|
|
||||||
|
// width_ and height_ will be updated by the WM_SIZE handler -
|
||||||
|
// windowed_pos_.rcNormalPosition is also not the correct source for them when
|
||||||
|
// switching from fullscreen to maximized.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Win32Window::is_bordered() const {
|
bool Win32Window::is_bordered() const {
|
||||||
|
|
Loading…
Reference in New Issue