[UI] UploadBufferPool common code
This commit is contained in:
parent
2cebd3cabe
commit
189a38826f
|
@ -438,9 +438,10 @@ uint64_t D3D12CommandProcessor::RequestViewBindfulDescriptors(
|
|||
uint64_t current_heap_index = view_bindful_heap_pool_->Request(
|
||||
frame_current_, previous_heap_index, count_for_partial_update,
|
||||
count_for_full_update, descriptor_index);
|
||||
if (current_heap_index == ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
if (current_heap_index ==
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
// There was an error.
|
||||
return ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid;
|
||||
return ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid;
|
||||
}
|
||||
ID3D12DescriptorHeap* heap = view_bindful_heap_pool_->GetLastRequestHeap();
|
||||
if (view_bindful_heap_current_ != heap) {
|
||||
|
@ -511,9 +512,9 @@ bool D3D12CommandProcessor::RequestOneUseSingleViewDescriptors(
|
|||
D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle_start;
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_start;
|
||||
if (RequestViewBindfulDescriptors(
|
||||
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, count, count,
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid, count, count,
|
||||
cpu_handle_start, gpu_handle_start) ==
|
||||
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
|
@ -609,9 +610,10 @@ uint64_t D3D12CommandProcessor::RequestSamplerBindfulDescriptors(
|
|||
uint64_t current_heap_index = sampler_bindful_heap_pool_->Request(
|
||||
frame_current_, previous_heap_index, count_for_partial_update,
|
||||
count_for_full_update, descriptor_index);
|
||||
if (current_heap_index == ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
if (current_heap_index ==
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
// There was an error.
|
||||
return ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid;
|
||||
return ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid;
|
||||
}
|
||||
ID3D12DescriptorHeap* heap = sampler_bindful_heap_pool_->GetLastRequestHeap();
|
||||
if (sampler_bindful_heap_current_ != heap) {
|
||||
|
@ -890,10 +892,10 @@ bool D3D12CommandProcessor::SetupContext() {
|
|||
cvars::d3d12_edram_rov && provider.AreRasterizerOrderedViewsSupported();
|
||||
|
||||
// Initialize resource binding.
|
||||
constant_buffer_pool_ = std::make_unique<ui::d3d12::UploadBufferPool>(
|
||||
provider, std::max(ui::d3d12::UploadBufferPool::kDefaultPageSize,
|
||||
uint32_t(D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 4 *
|
||||
sizeof(float))));
|
||||
constant_buffer_pool_ = std::make_unique<ui::d3d12::D3D12UploadBufferPool>(
|
||||
provider,
|
||||
std::max(ui::d3d12::D3D12UploadBufferPool::kDefaultPageSize,
|
||||
sizeof(float) * 4 * D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT));
|
||||
if (bindless_resources_used_) {
|
||||
D3D12_DESCRIPTOR_HEAP_DESC view_bindless_heap_desc;
|
||||
view_bindless_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
||||
|
@ -929,10 +931,12 @@ bool D3D12CommandProcessor::SetupContext() {
|
|||
sampler_bindless_heap_current_->GetGPUDescriptorHandleForHeapStart();
|
||||
sampler_bindless_heap_allocated_ = 0;
|
||||
} else {
|
||||
view_bindful_heap_pool_ = std::make_unique<ui::d3d12::DescriptorHeapPool>(
|
||||
device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, kViewBindfulHeapSize);
|
||||
view_bindful_heap_pool_ =
|
||||
std::make_unique<ui::d3d12::D3D12DescriptorHeapPool>(
|
||||
device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
kViewBindfulHeapSize);
|
||||
sampler_bindful_heap_pool_ =
|
||||
std::make_unique<ui::d3d12::DescriptorHeapPool>(
|
||||
std::make_unique<ui::d3d12::D3D12DescriptorHeapPool>(
|
||||
device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, kSamplerHeapSize);
|
||||
}
|
||||
|
||||
|
@ -2508,9 +2512,9 @@ void D3D12CommandProcessor::BeginSubmission(bool is_guest_command) {
|
|||
cbuffer_binding_descriptor_indices_pixel_.up_to_date = false;
|
||||
} else {
|
||||
draw_view_bindful_heap_index_ =
|
||||
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid;
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid;
|
||||
draw_sampler_bindful_heap_index_ =
|
||||
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid;
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid;
|
||||
bindful_textures_written_vertex_ = false;
|
||||
bindful_textures_written_pixel_ = false;
|
||||
bindful_samplers_written_vertex_ = false;
|
||||
|
@ -3575,8 +3579,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
|||
// empty buffer.
|
||||
uint8_t* float_constants = constant_buffer_pool_->Request(
|
||||
frame_current_,
|
||||
uint32_t(std::max(float_constant_count_vertex, uint32_t(1)) * 4 *
|
||||
sizeof(float)),
|
||||
sizeof(float) * 4 * std::max(float_constant_count_vertex, uint32_t(1)),
|
||||
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT, nullptr, nullptr,
|
||||
&cbuffer_binding_float_vertex_.address);
|
||||
if (float_constants == nullptr) {
|
||||
|
@ -3604,8 +3607,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
|||
if (!cbuffer_binding_float_pixel_.up_to_date) {
|
||||
uint8_t* float_constants = constant_buffer_pool_->Request(
|
||||
frame_current_,
|
||||
uint32_t(std::max(float_constant_count_pixel, uint32_t(1)) * 4 *
|
||||
sizeof(float)),
|
||||
sizeof(float) * 4 * std::max(float_constant_count_pixel, uint32_t(1)),
|
||||
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT, nullptr, nullptr,
|
||||
&cbuffer_binding_float_pixel_.address);
|
||||
if (float_constants == nullptr) {
|
||||
|
@ -3893,9 +3895,9 @@ bool D3D12CommandProcessor::UpdateBindings(
|
|||
uint32_t* descriptor_indices =
|
||||
reinterpret_cast<uint32_t*>(constant_buffer_pool_->Request(
|
||||
frame_current_,
|
||||
uint32_t(std::max(texture_count_vertex + sampler_count_vertex,
|
||||
uint32_t(1)) *
|
||||
sizeof(uint32_t)),
|
||||
std::max(texture_count_vertex + sampler_count_vertex,
|
||||
uint32_t(1)) *
|
||||
sizeof(uint32_t),
|
||||
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT, nullptr, nullptr,
|
||||
&cbuffer_binding_descriptor_indices_vertex_.address));
|
||||
if (!descriptor_indices) {
|
||||
|
@ -3929,9 +3931,8 @@ bool D3D12CommandProcessor::UpdateBindings(
|
|||
uint32_t* descriptor_indices =
|
||||
reinterpret_cast<uint32_t*>(constant_buffer_pool_->Request(
|
||||
frame_current_,
|
||||
uint32_t(std::max(texture_count_pixel + sampler_count_pixel,
|
||||
uint32_t(1)) *
|
||||
sizeof(uint32_t)),
|
||||
std::max(texture_count_pixel + sampler_count_pixel, uint32_t(1)) *
|
||||
sizeof(uint32_t),
|
||||
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT, nullptr, nullptr,
|
||||
&cbuffer_binding_descriptor_indices_pixel_.address));
|
||||
if (!descriptor_indices) {
|
||||
|
@ -4007,7 +4008,8 @@ bool D3D12CommandProcessor::UpdateBindings(
|
|||
uint64_t view_heap_index = RequestViewBindfulDescriptors(
|
||||
draw_view_bindful_heap_index_, view_count_partial_update,
|
||||
view_count_full_update, view_cpu_handle, view_gpu_handle);
|
||||
if (view_heap_index == ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
if (view_heap_index ==
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
XELOGE("Failed to allocate view descriptors");
|
||||
return false;
|
||||
}
|
||||
|
@ -4022,14 +4024,14 @@ bool D3D12CommandProcessor::UpdateBindings(
|
|||
D3D12_GPU_DESCRIPTOR_HANDLE sampler_gpu_handle = {};
|
||||
uint32_t descriptor_size_sampler = provider.GetSamplerDescriptorSize();
|
||||
uint64_t sampler_heap_index =
|
||||
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid;
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid;
|
||||
if (sampler_count_vertex != 0 || sampler_count_pixel != 0) {
|
||||
sampler_heap_index = RequestSamplerBindfulDescriptors(
|
||||
draw_sampler_bindful_heap_index_, sampler_count_partial_update,
|
||||
sampler_count_vertex + sampler_count_pixel, sampler_cpu_handle,
|
||||
sampler_gpu_handle);
|
||||
if (sampler_heap_index ==
|
||||
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
XELOGE("Failed to allocate sampler descriptors");
|
||||
return false;
|
||||
}
|
||||
|
@ -4059,7 +4061,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
|||
~(1u << kRootParameter_Bindful_SharedMemoryAndEdram);
|
||||
}
|
||||
if (sampler_heap_index !=
|
||||
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid &&
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid &&
|
||||
draw_sampler_bindful_heap_index_ != sampler_heap_index) {
|
||||
write_samplers_vertex = sampler_count_vertex != 0;
|
||||
write_samplers_pixel = sampler_count_pixel != 0;
|
||||
|
@ -4143,7 +4145,7 @@ bool D3D12CommandProcessor::UpdateBindings(
|
|||
// Wrote new descriptors on the current page.
|
||||
draw_view_bindful_heap_index_ = view_heap_index;
|
||||
if (sampler_heap_index !=
|
||||
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
ui::d3d12::D3D12DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
draw_sampler_bindful_heap_index_ = sampler_heap_index;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,9 @@
|
|||
#include "xenia/gpu/xenos.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/ui/d3d12/d3d12_context.h"
|
||||
#include "xenia/ui/d3d12/d3d12_descriptor_heap_pool.h"
|
||||
#include "xenia/ui/d3d12/d3d12_upload_buffer_pool.h"
|
||||
#include "xenia/ui/d3d12/d3d12_util.h"
|
||||
#include "xenia/ui/d3d12/pools.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
|
@ -93,7 +94,7 @@ class D3D12CommandProcessor : public CommandProcessor {
|
|||
ID3D12RootSignature* GetRootSignature(const D3D12Shader* vertex_shader,
|
||||
const D3D12Shader* pixel_shader);
|
||||
|
||||
ui::d3d12::UploadBufferPool& GetConstantBufferPool() const {
|
||||
ui::d3d12::D3D12UploadBufferPool& GetConstantBufferPool() const {
|
||||
return *constant_buffer_pool_;
|
||||
}
|
||||
|
||||
|
@ -311,8 +312,8 @@ class D3D12CommandProcessor : public CommandProcessor {
|
|||
void ClearCommandAllocatorCache();
|
||||
|
||||
// Request descriptors and automatically rebind the descriptor heap on the
|
||||
// draw command list. Refer to DescriptorHeapPool::Request for partial/full
|
||||
// update explanation. Doesn't work when bindless descriptors are used.
|
||||
// draw command list. Refer to D3D12DescriptorHeapPool::Request for partial /
|
||||
// full update explanation. Doesn't work when bindless descriptors are used.
|
||||
uint64_t RequestViewBindfulDescriptors(
|
||||
uint64_t previous_heap_index, uint32_t count_for_partial_update,
|
||||
uint32_t count_for_full_update,
|
||||
|
@ -387,12 +388,13 @@ class D3D12CommandProcessor : public CommandProcessor {
|
|||
// targets.
|
||||
bool edram_rov_used_ = false;
|
||||
|
||||
std::unique_ptr<ui::d3d12::UploadBufferPool> constant_buffer_pool_ = nullptr;
|
||||
std::unique_ptr<ui::d3d12::D3D12UploadBufferPool> constant_buffer_pool_ =
|
||||
nullptr;
|
||||
|
||||
static constexpr uint32_t kViewBindfulHeapSize = 32768;
|
||||
static_assert(kViewBindfulHeapSize <=
|
||||
D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1);
|
||||
std::unique_ptr<ui::d3d12::DescriptorHeapPool> view_bindful_heap_pool_ =
|
||||
std::unique_ptr<ui::d3d12::D3D12DescriptorHeapPool> view_bindful_heap_pool_ =
|
||||
nullptr;
|
||||
// Currently bound descriptor heap - updated by RequestViewBindfulDescriptors.
|
||||
ID3D12DescriptorHeap* view_bindful_heap_current_;
|
||||
|
@ -423,8 +425,8 @@ class D3D12CommandProcessor : public CommandProcessor {
|
|||
// FIXME(Triang3l): Investigate the issue with the sampler 2047 on Nvidia.
|
||||
static constexpr uint32_t kSamplerHeapSize = 2000;
|
||||
static_assert(kSamplerHeapSize <= D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE);
|
||||
std::unique_ptr<ui::d3d12::DescriptorHeapPool> sampler_bindful_heap_pool_ =
|
||||
nullptr;
|
||||
std::unique_ptr<ui::d3d12::D3D12DescriptorHeapPool>
|
||||
sampler_bindful_heap_pool_ = nullptr;
|
||||
ID3D12DescriptorHeap* sampler_bindful_heap_current_;
|
||||
ID3D12DescriptorHeap* sampler_bindless_heap_current_ = nullptr;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE sampler_bindless_heap_cpu_start_;
|
||||
|
|
|
@ -56,9 +56,9 @@ bool PrimitiveConverter::Initialize() {
|
|||
// count), but they can be up to 4 bytes large, and conversion can add more
|
||||
// indices (almost triple the count for triangle strips or fans, for
|
||||
// instance).
|
||||
buffer_pool_ = std::make_unique<ui::d3d12::UploadBufferPool>(
|
||||
provider, std::max(uint32_t(65535 * 3 * sizeof(uint32_t)),
|
||||
ui::d3d12::UploadBufferPool::kDefaultPageSize));
|
||||
buffer_pool_ = std::make_unique<ui::d3d12::D3D12UploadBufferPool>(
|
||||
provider, std::max(sizeof(uint32_t) * 3 * 65535,
|
||||
ui::d3d12::D3D12UploadBufferPool::kDefaultPageSize));
|
||||
|
||||
// Create the static index buffer for non-indexed drawing.
|
||||
D3D12_RESOURCE_DESC static_ib_desc;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "xenia/gpu/xenos.h"
|
||||
#include "xenia/memory.h"
|
||||
#include "xenia/ui/d3d12/d3d12_context.h"
|
||||
#include "xenia/ui/d3d12/pools.h"
|
||||
#include "xenia/ui/d3d12/d3d12_upload_buffer_pool.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
|
@ -107,7 +107,7 @@ class PrimitiveConverter {
|
|||
Memory& memory_;
|
||||
TraceWriter& trace_writer_;
|
||||
|
||||
std::unique_ptr<ui::d3d12::UploadBufferPool> buffer_pool_ = nullptr;
|
||||
std::unique_ptr<ui::d3d12::D3D12UploadBufferPool> buffer_pool_ = nullptr;
|
||||
|
||||
// Static index buffers for emulating unsupported primitive types when drawing
|
||||
// without an index buffer.
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "xenia/gpu/texture_info.h"
|
||||
#include "xenia/gpu/texture_util.h"
|
||||
#include "xenia/ui/d3d12/d3d12_util.h"
|
||||
#include "xenia/ui/d3d12/pools.h"
|
||||
|
||||
DEFINE_bool(d3d12_16bit_rtv_full_range, true,
|
||||
"Use full -32...32 range for RG16 and RGBA16 render targets "
|
||||
|
@ -1501,11 +1500,11 @@ void RenderTargetCache::RestoreEdramSnapshot(const void* snapshot) {
|
|||
auto& provider = command_processor_.GetD3D12Context().GetD3D12Provider();
|
||||
if (!edram_snapshot_restore_pool_) {
|
||||
edram_snapshot_restore_pool_ =
|
||||
std::make_unique<ui::d3d12::UploadBufferPool>(provider,
|
||||
xenos::kEdramSizeBytes);
|
||||
std::make_unique<ui::d3d12::D3D12UploadBufferPool>(
|
||||
provider, xenos::kEdramSizeBytes);
|
||||
}
|
||||
ID3D12Resource* upload_buffer;
|
||||
uint32_t upload_buffer_offset;
|
||||
size_t upload_buffer_offset;
|
||||
void* upload_buffer_mapping = edram_snapshot_restore_pool_->Request(
|
||||
command_processor_.GetCurrentSubmission(), xenos::kEdramSizeBytes, 1,
|
||||
&upload_buffer, &upload_buffer_offset, nullptr);
|
||||
|
@ -1518,7 +1517,7 @@ void RenderTargetCache::RestoreEdramSnapshot(const void* snapshot) {
|
|||
TransitionEdramBuffer(D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
command_processor_.SubmitBarriers();
|
||||
command_list.D3DCopyBufferRegion(edram_buffer_, 0, upload_buffer,
|
||||
upload_buffer_offset,
|
||||
UINT64(upload_buffer_offset),
|
||||
xenos::kEdramSizeBytes);
|
||||
if (!edram_rov_used_) {
|
||||
// Clear and ignore the old 32-bit float depth - the non-ROV path is
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "xenia/gpu/xenos.h"
|
||||
#include "xenia/memory.h"
|
||||
#include "xenia/ui/d3d12/d3d12_api.h"
|
||||
#include "xenia/ui/d3d12/pools.h"
|
||||
#include "xenia/ui/d3d12/d3d12_upload_buffer_pool.h"
|
||||
|
||||
DECLARE_bool(d3d12_16bit_rtv_full_range);
|
||||
|
||||
|
@ -602,8 +602,8 @@ class RenderTargetCache {
|
|||
|
||||
// For traces only.
|
||||
ID3D12Resource* edram_snapshot_download_buffer_ = nullptr;
|
||||
std::unique_ptr<ui::d3d12::UploadBufferPool> edram_snapshot_restore_pool_ =
|
||||
nullptr;
|
||||
std::unique_ptr<ui::d3d12::D3D12UploadBufferPool>
|
||||
edram_snapshot_restore_pool_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace d3d12
|
||||
|
|
|
@ -153,9 +153,9 @@ bool SharedMemory::Initialize() {
|
|||
system_page_flags_.clear();
|
||||
system_page_flags_.resize((page_count_ + 63) / 64);
|
||||
|
||||
upload_buffer_pool_ = std::make_unique<ui::d3d12::UploadBufferPool>(
|
||||
provider, xe::align(ui::d3d12::UploadBufferPool::kDefaultPageSize,
|
||||
uint32_t(1) << page_size_log2_));
|
||||
upload_buffer_pool_ = std::make_unique<ui::d3d12::D3D12UploadBufferPool>(
|
||||
provider, xe::align(ui::d3d12::D3D12UploadBufferPool::kDefaultPageSize,
|
||||
size_t(1) << page_size_log2_));
|
||||
|
||||
memory_invalidation_callback_handle_ =
|
||||
memory_.RegisterPhysicalMemoryInvalidationCallback(
|
||||
|
@ -439,26 +439,26 @@ bool SharedMemory::RequestRange(uint32_t start, uint32_t length) {
|
|||
upload_range_length << page_size_log2_);
|
||||
while (upload_range_length != 0) {
|
||||
ID3D12Resource* upload_buffer;
|
||||
uint32_t upload_buffer_offset, upload_buffer_size;
|
||||
size_t upload_buffer_offset, upload_buffer_size;
|
||||
uint8_t* upload_buffer_mapping = upload_buffer_pool_->RequestPartial(
|
||||
command_processor_.GetCurrentSubmission(),
|
||||
upload_range_length << page_size_log2_,
|
||||
uint32_t(1) << page_size_log2_, &upload_buffer, &upload_buffer_offset,
|
||||
&upload_buffer_size, nullptr);
|
||||
upload_range_length << page_size_log2_, size_t(1) << page_size_log2_,
|
||||
&upload_buffer, &upload_buffer_offset, &upload_buffer_size, nullptr);
|
||||
if (upload_buffer_mapping == nullptr) {
|
||||
XELOGE("Shared memory: Failed to get an upload buffer");
|
||||
return false;
|
||||
}
|
||||
uint32_t upload_buffer_pages = upload_buffer_size >> page_size_log2_;
|
||||
MakeRangeValid(upload_range_start << page_size_log2_,
|
||||
upload_buffer_pages << page_size_log2_, false);
|
||||
uint32_t(upload_buffer_size), false);
|
||||
std::memcpy(
|
||||
upload_buffer_mapping,
|
||||
memory_.TranslatePhysical(upload_range_start << page_size_log2_),
|
||||
upload_buffer_size);
|
||||
command_list.D3DCopyBufferRegion(
|
||||
buffer_, upload_range_start << page_size_log2_, upload_buffer,
|
||||
upload_buffer_offset, upload_buffer_size);
|
||||
UINT64(upload_buffer_offset), UINT64(upload_buffer_size));
|
||||
uint32_t upload_buffer_pages =
|
||||
uint32_t(upload_buffer_size >> page_size_log2_);
|
||||
upload_range_start += upload_buffer_pages;
|
||||
upload_range_length -= upload_buffer_pages;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "xenia/gpu/trace_writer.h"
|
||||
#include "xenia/memory.h"
|
||||
#include "xenia/ui/d3d12/d3d12_api.h"
|
||||
#include "xenia/ui/d3d12/pools.h"
|
||||
#include "xenia/ui/d3d12/d3d12_upload_buffer_pool.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
|
@ -212,7 +212,8 @@ class SharedMemory {
|
|||
std::vector<UploadRange> upload_ranges_;
|
||||
void GetRangesToUpload(uint32_t request_page_first,
|
||||
uint32_t request_page_last);
|
||||
std::unique_ptr<ui::d3d12::UploadBufferPool> upload_buffer_pool_ = nullptr;
|
||||
std::unique_ptr<ui::d3d12::D3D12UploadBufferPool> upload_buffer_pool_ =
|
||||
nullptr;
|
||||
|
||||
// GPU-written memory downloading for traces.
|
||||
// Start page, length in pages.
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
#include "xenia/gpu/gpu_flags.h"
|
||||
#include "xenia/gpu/texture_info.h"
|
||||
#include "xenia/gpu/texture_util.h"
|
||||
#include "xenia/ui/d3d12/d3d12_upload_buffer_pool.h"
|
||||
#include "xenia/ui/d3d12/d3d12_util.h"
|
||||
#include "xenia/ui/d3d12/pools.h"
|
||||
|
||||
DEFINE_int32(d3d12_resolution_scale, 1,
|
||||
"Scale of rendering width and height (currently only 1 and 2 "
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/ui/d3d12/d3d12_descriptor_heap_pool.h"
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/ui/d3d12/d3d12_util.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace d3d12 {
|
||||
|
||||
D3D12DescriptorHeapPool::D3D12DescriptorHeapPool(
|
||||
ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32_t page_size)
|
||||
: device_(device), type_(type), page_size_(page_size) {}
|
||||
|
||||
D3D12DescriptorHeapPool::~D3D12DescriptorHeapPool() { ClearCache(); }
|
||||
|
||||
void D3D12DescriptorHeapPool::Reclaim(uint64_t completed_submission_index) {
|
||||
while (submitted_first_) {
|
||||
if (submitted_first_->last_submission_index > completed_submission_index) {
|
||||
break;
|
||||
}
|
||||
if (writable_last_) {
|
||||
writable_last_->next = submitted_first_;
|
||||
} else {
|
||||
writable_first_ = submitted_first_;
|
||||
}
|
||||
writable_last_ = submitted_first_;
|
||||
submitted_first_ = submitted_first_->next;
|
||||
writable_last_->next = nullptr;
|
||||
}
|
||||
if (!submitted_first_) {
|
||||
submitted_last_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12DescriptorHeapPool::ClearCache() {
|
||||
// Not checking current_page_used_ != 0 because asking for 0 descriptors
|
||||
// returns a valid heap also - but actually the new heap will be different now
|
||||
// and the old one must be unbound since it doesn't exist anymore.
|
||||
++current_heap_index_;
|
||||
current_page_used_ = 0;
|
||||
while (submitted_first_) {
|
||||
auto next = submitted_first_->next;
|
||||
submitted_first_->heap->Release();
|
||||
delete submitted_first_;
|
||||
submitted_first_ = next;
|
||||
}
|
||||
submitted_last_ = nullptr;
|
||||
while (writable_first_) {
|
||||
auto next = writable_first_->next;
|
||||
writable_first_->heap->Release();
|
||||
delete writable_first_;
|
||||
writable_first_ = next;
|
||||
}
|
||||
writable_last_ = nullptr;
|
||||
}
|
||||
|
||||
uint64_t D3D12DescriptorHeapPool::Request(uint64_t submission_index,
|
||||
uint64_t previous_heap_index,
|
||||
uint32_t count_for_partial_update,
|
||||
uint32_t count_for_full_update,
|
||||
uint32_t& index_out) {
|
||||
assert_true(count_for_partial_update <= count_for_full_update);
|
||||
assert_true(count_for_full_update <= page_size_);
|
||||
if (count_for_partial_update > count_for_full_update ||
|
||||
count_for_full_update > page_size_) {
|
||||
return kHeapIndexInvalid;
|
||||
}
|
||||
assert_true(!current_page_used_ ||
|
||||
submission_index >= writable_first_->last_submission_index);
|
||||
assert_true(!submitted_last_ ||
|
||||
submission_index >= submitted_last_->last_submission_index);
|
||||
// If the last full update happened on the current page, a partial update is
|
||||
// possible.
|
||||
uint32_t count = previous_heap_index == current_heap_index_
|
||||
? count_for_partial_update
|
||||
: count_for_full_update;
|
||||
// Go to the next page if there's not enough free space on the current one,
|
||||
// or because the previous page may be outdated. In this case, a full update
|
||||
// is necessary.
|
||||
if (page_size_ - current_page_used_ < count) {
|
||||
// Close the page that was current.
|
||||
if (submitted_last_) {
|
||||
submitted_last_->next = writable_first_;
|
||||
} else {
|
||||
submitted_first_ = writable_first_;
|
||||
}
|
||||
submitted_last_ = writable_first_;
|
||||
writable_first_ = writable_first_->next;
|
||||
submitted_last_->next = nullptr;
|
||||
if (!writable_first_) {
|
||||
writable_last_ = nullptr;
|
||||
}
|
||||
++current_heap_index_;
|
||||
current_page_used_ = 0;
|
||||
count = count_for_full_update;
|
||||
}
|
||||
// Create the page if needed (may be the first call for the page).
|
||||
if (!writable_first_) {
|
||||
D3D12_DESCRIPTOR_HEAP_DESC new_heap_desc;
|
||||
new_heap_desc.Type = type_;
|
||||
new_heap_desc.NumDescriptors = page_size_;
|
||||
new_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||
new_heap_desc.NodeMask = 0;
|
||||
ID3D12DescriptorHeap* new_heap;
|
||||
if (FAILED(device_->CreateDescriptorHeap(&new_heap_desc,
|
||||
IID_PPV_ARGS(&new_heap)))) {
|
||||
XELOGE("Failed to create a heap for {} shader-visible descriptors",
|
||||
page_size_);
|
||||
return kHeapIndexInvalid;
|
||||
}
|
||||
writable_first_ = new Page;
|
||||
writable_first_->heap = new_heap;
|
||||
writable_first_->cpu_start = new_heap->GetCPUDescriptorHandleForHeapStart();
|
||||
writable_first_->gpu_start = new_heap->GetGPUDescriptorHandleForHeapStart();
|
||||
writable_first_->last_submission_index = submission_index;
|
||||
writable_first_->next = nullptr;
|
||||
writable_last_ = writable_first_;
|
||||
}
|
||||
writable_first_->last_submission_index = submission_index;
|
||||
index_out = current_page_used_;
|
||||
current_page_used_ += count;
|
||||
return current_heap_index_;
|
||||
}
|
||||
|
||||
} // namespace d3d12
|
||||
} // namespace ui
|
||||
} // namespace xe
|
|
@ -2,13 +2,13 @@
|
|||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2018 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_UI_D3D12_POOLS_H_
|
||||
#define XENIA_UI_D3D12_POOLS_H_
|
||||
#ifndef XENIA_UI_D3D12_D3D12_DESCRIPTOR_HEAP_POOL_H_
|
||||
#define XENIA_UI_D3D12_D3D12_DESCRIPTOR_HEAP_POOL_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
@ -21,60 +21,13 @@ namespace d3d12 {
|
|||
// Submission index is the fence value or a value derived from it (if reclaiming
|
||||
// less often than once per fence value, for instance).
|
||||
|
||||
class UploadBufferPool {
|
||||
public:
|
||||
// Taken from the Direct3D 12 MiniEngine sample (LinearAllocator
|
||||
// kCpuAllocatorPageSize). Large enough for most cases.
|
||||
static constexpr uint32_t kDefaultPageSize = 2 * 1024 * 1024;
|
||||
|
||||
UploadBufferPool(D3D12Provider& provider,
|
||||
uint32_t page_size = kDefaultPageSize);
|
||||
~UploadBufferPool();
|
||||
|
||||
void Reclaim(uint64_t completed_submission_index);
|
||||
void ClearCache();
|
||||
|
||||
// Request to write data in a single piece, creating a new page if the current
|
||||
// one doesn't have enough free space.
|
||||
uint8_t* Request(uint64_t submission_index, uint32_t size, uint32_t alignment,
|
||||
ID3D12Resource** buffer_out, uint32_t* offset_out,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out);
|
||||
// Request to write data in multiple parts, filling the buffer entirely.
|
||||
uint8_t* RequestPartial(uint64_t submission_index, uint32_t size,
|
||||
uint32_t alignment, ID3D12Resource** buffer_out,
|
||||
uint32_t* offset_out, uint32_t* size_out,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out);
|
||||
|
||||
private:
|
||||
D3D12Provider& provider_;
|
||||
uint32_t page_size_;
|
||||
|
||||
struct Page {
|
||||
ID3D12Resource* buffer;
|
||||
D3D12_GPU_VIRTUAL_ADDRESS gpu_address;
|
||||
void* mapping;
|
||||
uint64_t last_submission_index;
|
||||
Page* next;
|
||||
};
|
||||
|
||||
// A list of buffers with free space, with the first buffer being the one
|
||||
// currently being filled.
|
||||
Page* writable_first_ = nullptr;
|
||||
Page* writable_last_ = nullptr;
|
||||
// A list of full buffers that can be reclaimed when the GPU doesn't use them
|
||||
// anymore.
|
||||
Page* submitted_first_ = nullptr;
|
||||
Page* submitted_last_ = nullptr;
|
||||
uint32_t current_page_used_ = 0;
|
||||
};
|
||||
|
||||
class DescriptorHeapPool {
|
||||
class D3D12DescriptorHeapPool {
|
||||
public:
|
||||
static constexpr uint64_t kHeapIndexInvalid = UINT64_MAX;
|
||||
|
||||
DescriptorHeapPool(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type,
|
||||
uint32_t page_size);
|
||||
~DescriptorHeapPool();
|
||||
D3D12DescriptorHeapPool(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type,
|
||||
uint32_t page_size);
|
||||
~D3D12DescriptorHeapPool();
|
||||
|
||||
void Reclaim(uint64_t completed_submission_index);
|
||||
void ClearCache();
|
||||
|
@ -153,4 +106,4 @@ class DescriptorHeapPool {
|
|||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_D3D12_POOLS_H_
|
||||
#endif // XENIA_UI_D3D12_D3D12_UPLOAD_BUFFER_POOL_H_
|
|
@ -287,10 +287,11 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|||
device->CreateSampler(&sampler_desc, sampler_handle);
|
||||
|
||||
// Create pools for draws.
|
||||
vertex_buffer_pool_ = std::make_unique<UploadBufferPool>(provider);
|
||||
texture_descriptor_pool_ = std::make_unique<DescriptorHeapPool>(
|
||||
vertex_buffer_pool_ = std::make_unique<D3D12UploadBufferPool>(provider);
|
||||
texture_descriptor_pool_ = std::make_unique<D3D12DescriptorHeapPool>(
|
||||
device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2048);
|
||||
texture_descriptor_pool_heap_index_ = DescriptorHeapPool::kHeapIndexInvalid;
|
||||
texture_descriptor_pool_heap_index_ =
|
||||
D3D12DescriptorHeapPool::kHeapIndexInvalid;
|
||||
|
||||
// Reset the current state.
|
||||
current_command_list_ = nullptr;
|
||||
|
@ -465,7 +466,8 @@ void D3D12ImmediateDrawer::Begin(int render_target_width,
|
|||
|
||||
vertex_buffer_pool_->Reclaim(completed_fence_value);
|
||||
texture_descriptor_pool_->Reclaim(completed_fence_value);
|
||||
texture_descriptor_pool_heap_index_ = DescriptorHeapPool::kHeapIndexInvalid;
|
||||
texture_descriptor_pool_heap_index_ =
|
||||
D3D12DescriptorHeapPool::kHeapIndexInvalid;
|
||||
|
||||
current_render_target_width_ = render_target_width;
|
||||
current_render_target_height_ = render_target_height;
|
||||
|
@ -567,7 +569,7 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
|||
uint64_t texture_heap_index = texture_descriptor_pool_->Request(
|
||||
context_.GetSwapCurrentFenceValue(), texture_descriptor_pool_heap_index_,
|
||||
bind_texture ? 1 : 0, 1, texture_descriptor_index);
|
||||
if (texture_heap_index == DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
if (texture_heap_index == D3D12DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
return;
|
||||
}
|
||||
if (texture_descriptor_pool_heap_index_ != texture_heap_index) {
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
#include <vector>
|
||||
|
||||
#include "xenia/ui/d3d12/d3d12_api.h"
|
||||
#include "xenia/ui/d3d12/pools.h"
|
||||
#include "xenia/ui/d3d12/d3d12_descriptor_heap_pool.h"
|
||||
#include "xenia/ui/d3d12/d3d12_upload_buffer_pool.h"
|
||||
#include "xenia/ui/immediate_drawer.h"
|
||||
|
||||
namespace xe {
|
||||
|
@ -74,8 +75,8 @@ class D3D12ImmediateDrawer : public ImmediateDrawer {
|
|||
D3D12_CPU_DESCRIPTOR_HANDLE sampler_heap_cpu_start_;
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE sampler_heap_gpu_start_;
|
||||
|
||||
std::unique_ptr<UploadBufferPool> vertex_buffer_pool_ = nullptr;
|
||||
std::unique_ptr<DescriptorHeapPool> texture_descriptor_pool_ = nullptr;
|
||||
std::unique_ptr<D3D12UploadBufferPool> vertex_buffer_pool_ = nullptr;
|
||||
std::unique_ptr<D3D12DescriptorHeapPool> texture_descriptor_pool_ = nullptr;
|
||||
uint64_t texture_descriptor_pool_heap_index_;
|
||||
|
||||
struct PendingTextureUpload {
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/ui/d3d12/d3d12_upload_buffer_pool.h"
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/ui/d3d12/d3d12_util.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace d3d12 {
|
||||
|
||||
// Align to D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT not to waste any space if
|
||||
// it's smaller (the size of the heap backing the buffer will be aligned to
|
||||
// D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT anyway).
|
||||
D3D12UploadBufferPool::D3D12UploadBufferPool(D3D12Provider& provider,
|
||||
size_t page_size)
|
||||
: GraphicsUploadBufferPool(xe::align(
|
||||
page_size, size_t(D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT))),
|
||||
provider_(provider) {}
|
||||
|
||||
uint8_t* D3D12UploadBufferPool::Request(
|
||||
uint64_t submission_index, size_t size, size_t alignment,
|
||||
ID3D12Resource** buffer_out, size_t* offset_out,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out) {
|
||||
size_t offset;
|
||||
const D3D12Page* page =
|
||||
static_cast<const D3D12Page*>(GraphicsUploadBufferPool::Request(
|
||||
submission_index, size, alignment, offset));
|
||||
if (!page) {
|
||||
return nullptr;
|
||||
}
|
||||
if (buffer_out) {
|
||||
*buffer_out = page->buffer_;
|
||||
}
|
||||
if (offset_out) {
|
||||
*offset_out = offset;
|
||||
}
|
||||
if (gpu_address_out) {
|
||||
*gpu_address_out = page->gpu_address_ + offset;
|
||||
}
|
||||
return reinterpret_cast<uint8_t*>(page->mapping_) + offset;
|
||||
}
|
||||
|
||||
uint8_t* D3D12UploadBufferPool::RequestPartial(
|
||||
uint64_t submission_index, size_t size, size_t alignment,
|
||||
ID3D12Resource** buffer_out, size_t* offset_out, size_t* size_out,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out) {
|
||||
size_t offset, size_obtained;
|
||||
const D3D12Page* page =
|
||||
static_cast<const D3D12Page*>(GraphicsUploadBufferPool::RequestPartial(
|
||||
submission_index, size, alignment, offset, size_obtained));
|
||||
if (!page) {
|
||||
return nullptr;
|
||||
}
|
||||
if (buffer_out) {
|
||||
*buffer_out = page->buffer_;
|
||||
}
|
||||
if (offset_out) {
|
||||
*offset_out = offset;
|
||||
}
|
||||
if (size_out) {
|
||||
*size_out = size_obtained;
|
||||
}
|
||||
if (gpu_address_out) {
|
||||
*gpu_address_out = page->gpu_address_ + offset;
|
||||
}
|
||||
return reinterpret_cast<uint8_t*>(page->mapping_) + offset;
|
||||
}
|
||||
|
||||
GraphicsUploadBufferPool::Page*
|
||||
D3D12UploadBufferPool::CreatePageImplementation() {
|
||||
D3D12_RESOURCE_DESC buffer_desc;
|
||||
util::FillBufferResourceDesc(buffer_desc, page_size_,
|
||||
D3D12_RESOURCE_FLAG_NONE);
|
||||
ID3D12Resource* buffer;
|
||||
if (FAILED(provider_.GetDevice()->CreateCommittedResource(
|
||||
&util::kHeapPropertiesUpload, provider_.GetHeapFlagCreateNotZeroed(),
|
||||
&buffer_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
|
||||
IID_PPV_ARGS(&buffer)))) {
|
||||
XELOGE("Failed to create a D3D upload buffer with {} bytes", page_size_);
|
||||
return nullptr;
|
||||
}
|
||||
D3D12_RANGE read_range;
|
||||
read_range.Begin = 0;
|
||||
read_range.End = 0;
|
||||
void* mapping;
|
||||
if (FAILED(buffer->Map(0, &read_range, &mapping))) {
|
||||
XELOGE("Failed to map a D3D upload buffer with {} bytes", page_size_);
|
||||
buffer->Release();
|
||||
return nullptr;
|
||||
}
|
||||
D3D12Page* page = new D3D12Page(buffer, mapping);
|
||||
// Owned by the page now.
|
||||
buffer->Release();
|
||||
return page;
|
||||
}
|
||||
|
||||
D3D12UploadBufferPool::D3D12Page::D3D12Page(ID3D12Resource* buffer,
|
||||
void* mapping)
|
||||
: buffer_(buffer), mapping_(mapping) {
|
||||
buffer_->AddRef();
|
||||
gpu_address_ = buffer_->GetGPUVirtualAddress();
|
||||
}
|
||||
|
||||
D3D12UploadBufferPool::D3D12Page::~D3D12Page() {
|
||||
// Unmapping is done implicitly when the buffer is destroyed.
|
||||
buffer_->Release();
|
||||
}
|
||||
|
||||
} // namespace d3d12
|
||||
} // namespace ui
|
||||
} // namespace xe
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_UI_D3D12_D3D12_UPLOAD_BUFFER_POOL_H_
|
||||
#define XENIA_UI_D3D12_D3D12_UPLOAD_BUFFER_POOL_H_
|
||||
|
||||
#include "xenia/ui/d3d12/d3d12_provider.h"
|
||||
#include "xenia/ui/graphics_upload_buffer_pool.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace d3d12 {
|
||||
|
||||
// Submission index is the fence value or a value derived from it (if reclaiming
|
||||
// less often than once per fence value, for instance).
|
||||
|
||||
class D3D12UploadBufferPool : public GraphicsUploadBufferPool {
|
||||
public:
|
||||
D3D12UploadBufferPool(D3D12Provider& provider,
|
||||
size_t page_size = kDefaultPageSize);
|
||||
|
||||
uint8_t* Request(uint64_t submission_index, size_t size, size_t alignment,
|
||||
ID3D12Resource** buffer_out, size_t* offset_out,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out);
|
||||
uint8_t* RequestPartial(uint64_t submission_index, size_t size,
|
||||
size_t alignment, ID3D12Resource** buffer_out,
|
||||
size_t* offset_out, size_t* size_out,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out);
|
||||
|
||||
protected:
|
||||
Page* CreatePageImplementation() override;
|
||||
|
||||
private:
|
||||
struct D3D12Page : public Page {
|
||||
// Creates a reference to the buffer. It must not be unmapped until this
|
||||
// D3D12Page is deleted.
|
||||
D3D12Page(ID3D12Resource* buffer, void* mapping);
|
||||
~D3D12Page() override;
|
||||
ID3D12Resource* buffer_;
|
||||
void* mapping_;
|
||||
D3D12_GPU_VIRTUAL_ADDRESS gpu_address_;
|
||||
};
|
||||
|
||||
D3D12Provider& provider_;
|
||||
};
|
||||
|
||||
} // namespace d3d12
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_D3D12_D3D12_UPLOAD_BUFFER_POOL_H_
|
|
@ -1,302 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2018 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/ui/d3d12/pools.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/ui/d3d12/d3d12_util.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace d3d12 {
|
||||
|
||||
// Align to D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT not to waste any space if
|
||||
// it's smaller (the size of the heap backing the buffer will be aligned to
|
||||
// D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT anyway).
|
||||
UploadBufferPool::UploadBufferPool(D3D12Provider& provider, uint32_t page_size)
|
||||
: provider_(provider),
|
||||
page_size_(xe::align(
|
||||
page_size, uint32_t(D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT))) {}
|
||||
|
||||
UploadBufferPool::~UploadBufferPool() { ClearCache(); }
|
||||
|
||||
void UploadBufferPool::Reclaim(uint64_t completed_submission_index) {
|
||||
while (submitted_first_) {
|
||||
if (submitted_first_->last_submission_index > completed_submission_index) {
|
||||
break;
|
||||
}
|
||||
if (writable_last_) {
|
||||
writable_last_->next = submitted_first_;
|
||||
} else {
|
||||
writable_first_ = submitted_first_;
|
||||
}
|
||||
writable_last_ = submitted_first_;
|
||||
submitted_first_ = submitted_first_->next;
|
||||
writable_last_->next = nullptr;
|
||||
}
|
||||
if (!submitted_first_) {
|
||||
submitted_last_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void UploadBufferPool::ClearCache() {
|
||||
current_page_used_ = 0;
|
||||
// Deleting anyway, so assuming data not needed anymore.
|
||||
D3D12_RANGE written_range;
|
||||
written_range.Begin = 0;
|
||||
written_range.End = 0;
|
||||
while (submitted_first_) {
|
||||
auto next = submitted_first_->next;
|
||||
submitted_first_->buffer->Unmap(0, &written_range);
|
||||
submitted_first_->buffer->Release();
|
||||
delete submitted_first_;
|
||||
submitted_first_ = next;
|
||||
}
|
||||
submitted_last_ = nullptr;
|
||||
while (writable_first_) {
|
||||
auto next = writable_first_->next;
|
||||
writable_first_->buffer->Unmap(0, &written_range);
|
||||
writable_first_->buffer->Release();
|
||||
delete writable_first_;
|
||||
writable_first_ = next;
|
||||
}
|
||||
writable_last_ = nullptr;
|
||||
}
|
||||
|
||||
uint8_t* UploadBufferPool::Request(uint64_t submission_index, uint32_t size,
|
||||
uint32_t alignment,
|
||||
ID3D12Resource** buffer_out,
|
||||
uint32_t* offset_out,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out) {
|
||||
assert_not_zero(alignment);
|
||||
assert_true(xe::is_pow2(alignment));
|
||||
size = xe::align(size, alignment);
|
||||
assert_true(size <= page_size_);
|
||||
if (size > page_size_) {
|
||||
return nullptr;
|
||||
}
|
||||
assert_true(!current_page_used_ ||
|
||||
submission_index >= writable_first_->last_submission_index);
|
||||
assert_true(!submitted_last_ ||
|
||||
submission_index >= submitted_last_->last_submission_index);
|
||||
uint32_t current_page_used_aligned = xe::align(current_page_used_, alignment);
|
||||
if (current_page_used_aligned + size > page_size_ || !writable_first_) {
|
||||
// Start a new page if can't fit all the bytes or don't have an open page.
|
||||
if (writable_first_) {
|
||||
// Close the page that was current.
|
||||
if (submitted_last_) {
|
||||
submitted_last_->next = writable_first_;
|
||||
} else {
|
||||
submitted_first_ = writable_first_;
|
||||
}
|
||||
submitted_last_ = writable_first_;
|
||||
writable_first_ = writable_first_->next;
|
||||
submitted_last_->next = nullptr;
|
||||
if (!writable_first_) {
|
||||
writable_last_ = nullptr;
|
||||
}
|
||||
}
|
||||
if (!writable_first_) {
|
||||
// Create a new page if none available.
|
||||
D3D12_RESOURCE_DESC new_buffer_desc;
|
||||
util::FillBufferResourceDesc(new_buffer_desc, page_size_,
|
||||
D3D12_RESOURCE_FLAG_NONE);
|
||||
ID3D12Resource* new_buffer;
|
||||
if (FAILED(provider_.GetDevice()->CreateCommittedResource(
|
||||
&util::kHeapPropertiesUpload,
|
||||
provider_.GetHeapFlagCreateNotZeroed(), &new_buffer_desc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
|
||||
IID_PPV_ARGS(&new_buffer)))) {
|
||||
XELOGE("Failed to create a D3D upload buffer with {} bytes",
|
||||
page_size_);
|
||||
return nullptr;
|
||||
}
|
||||
D3D12_RANGE read_range;
|
||||
read_range.Begin = 0;
|
||||
read_range.End = 0;
|
||||
void* new_buffer_mapping;
|
||||
if (FAILED(new_buffer->Map(0, &read_range, &new_buffer_mapping))) {
|
||||
XELOGE("Failed to map a D3D upload buffer with {} bytes", page_size_);
|
||||
new_buffer->Release();
|
||||
return nullptr;
|
||||
}
|
||||
writable_first_ = new Page;
|
||||
writable_first_->buffer = new_buffer;
|
||||
writable_first_->gpu_address = new_buffer->GetGPUVirtualAddress();
|
||||
writable_first_->mapping = new_buffer_mapping;
|
||||
writable_first_->last_submission_index = submission_index;
|
||||
writable_first_->next = nullptr;
|
||||
writable_last_ = writable_first_;
|
||||
}
|
||||
current_page_used_ = 0;
|
||||
current_page_used_aligned = 0;
|
||||
}
|
||||
writable_first_->last_submission_index = submission_index;
|
||||
if (buffer_out) {
|
||||
*buffer_out = writable_first_->buffer;
|
||||
}
|
||||
if (offset_out) {
|
||||
*offset_out = current_page_used_aligned;
|
||||
}
|
||||
if (gpu_address_out) {
|
||||
*gpu_address_out = writable_first_->gpu_address + current_page_used_aligned;
|
||||
}
|
||||
uint8_t* mapping = reinterpret_cast<uint8_t*>(writable_first_->mapping) +
|
||||
current_page_used_aligned;
|
||||
current_page_used_ = current_page_used_aligned + size;
|
||||
return mapping;
|
||||
}
|
||||
|
||||
uint8_t* UploadBufferPool::RequestPartial(
|
||||
uint64_t submission_index, uint32_t size, uint32_t alignment,
|
||||
ID3D12Resource** buffer_out, uint32_t* offset_out, uint32_t* size_out,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out) {
|
||||
assert_not_zero(alignment);
|
||||
assert_true(xe::is_pow2(alignment));
|
||||
size = xe::align(size, alignment);
|
||||
size = std::min(size, page_size_);
|
||||
uint32_t current_page_used_aligned = xe::align(current_page_used_, alignment);
|
||||
if (current_page_used_aligned + alignment <= page_size_) {
|
||||
size = std::min(
|
||||
size, (page_size_ - current_page_used_aligned) & ~(alignment - 1));
|
||||
}
|
||||
uint8_t* mapping = Request(submission_index, size, alignment, buffer_out,
|
||||
offset_out, gpu_address_out);
|
||||
if (!mapping) {
|
||||
return nullptr;
|
||||
}
|
||||
if (size_out) {
|
||||
*size_out = size;
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
DescriptorHeapPool::DescriptorHeapPool(ID3D12Device* device,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE type,
|
||||
uint32_t page_size)
|
||||
: device_(device), type_(type), page_size_(page_size) {}
|
||||
|
||||
DescriptorHeapPool::~DescriptorHeapPool() { ClearCache(); }
|
||||
|
||||
void DescriptorHeapPool::Reclaim(uint64_t completed_submission_index) {
|
||||
while (submitted_first_) {
|
||||
if (submitted_first_->last_submission_index > completed_submission_index) {
|
||||
break;
|
||||
}
|
||||
if (writable_last_) {
|
||||
writable_last_->next = submitted_first_;
|
||||
} else {
|
||||
writable_first_ = submitted_first_;
|
||||
}
|
||||
writable_last_ = submitted_first_;
|
||||
submitted_first_ = submitted_first_->next;
|
||||
writable_last_->next = nullptr;
|
||||
}
|
||||
if (!submitted_first_) {
|
||||
submitted_last_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DescriptorHeapPool::ClearCache() {
|
||||
// Not checking current_page_used_ != 0 because asking for 0 descriptors
|
||||
// returns a valid heap also - but actually the new heap will be different now
|
||||
// and the old one must be unbound since it doesn't exist anymore.
|
||||
++current_heap_index_;
|
||||
current_page_used_ = 0;
|
||||
while (submitted_first_) {
|
||||
auto next = submitted_first_->next;
|
||||
submitted_first_->heap->Release();
|
||||
delete submitted_first_;
|
||||
submitted_first_ = next;
|
||||
}
|
||||
submitted_last_ = nullptr;
|
||||
while (writable_first_) {
|
||||
auto next = writable_first_->next;
|
||||
writable_first_->heap->Release();
|
||||
delete writable_first_;
|
||||
writable_first_ = next;
|
||||
}
|
||||
writable_last_ = nullptr;
|
||||
}
|
||||
|
||||
uint64_t DescriptorHeapPool::Request(uint64_t submission_index,
|
||||
uint64_t previous_heap_index,
|
||||
uint32_t count_for_partial_update,
|
||||
uint32_t count_for_full_update,
|
||||
uint32_t& index_out) {
|
||||
assert_true(count_for_partial_update <= count_for_full_update);
|
||||
assert_true(count_for_full_update <= page_size_);
|
||||
if (count_for_partial_update > count_for_full_update ||
|
||||
count_for_full_update > page_size_) {
|
||||
return kHeapIndexInvalid;
|
||||
}
|
||||
assert_true(!current_page_used_ ||
|
||||
submission_index >= writable_first_->last_submission_index);
|
||||
assert_true(!submitted_last_ ||
|
||||
submission_index >= submitted_last_->last_submission_index);
|
||||
// If the last full update happened on the current page, a partial update is
|
||||
// possible.
|
||||
uint32_t count = previous_heap_index == current_heap_index_
|
||||
? count_for_partial_update
|
||||
: count_for_full_update;
|
||||
// Go to the next page if there's not enough free space on the current one,
|
||||
// or because the previous page may be outdated. In this case, a full update
|
||||
// is necessary.
|
||||
if (page_size_ - current_page_used_ < count) {
|
||||
// Close the page that was current.
|
||||
if (submitted_last_) {
|
||||
submitted_last_->next = writable_first_;
|
||||
} else {
|
||||
submitted_first_ = writable_first_;
|
||||
}
|
||||
submitted_last_ = writable_first_;
|
||||
writable_first_ = writable_first_->next;
|
||||
submitted_last_->next = nullptr;
|
||||
if (!writable_first_) {
|
||||
writable_last_ = nullptr;
|
||||
}
|
||||
++current_heap_index_;
|
||||
current_page_used_ = 0;
|
||||
count = count_for_full_update;
|
||||
}
|
||||
// Create the page if needed (may be the first call for the page).
|
||||
if (!writable_first_) {
|
||||
D3D12_DESCRIPTOR_HEAP_DESC new_heap_desc;
|
||||
new_heap_desc.Type = type_;
|
||||
new_heap_desc.NumDescriptors = page_size_;
|
||||
new_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||
new_heap_desc.NodeMask = 0;
|
||||
ID3D12DescriptorHeap* new_heap;
|
||||
if (FAILED(device_->CreateDescriptorHeap(&new_heap_desc,
|
||||
IID_PPV_ARGS(&new_heap)))) {
|
||||
XELOGE("Failed to create a heap for {} shader-visible descriptors",
|
||||
page_size_);
|
||||
return kHeapIndexInvalid;
|
||||
}
|
||||
writable_first_ = new Page;
|
||||
writable_first_->heap = new_heap;
|
||||
writable_first_->cpu_start = new_heap->GetCPUDescriptorHandleForHeapStart();
|
||||
writable_first_->gpu_start = new_heap->GetGPUDescriptorHandleForHeapStart();
|
||||
writable_first_->last_submission_index = submission_index;
|
||||
writable_first_->next = nullptr;
|
||||
writable_last_ = writable_first_;
|
||||
}
|
||||
writable_first_->last_submission_index = submission_index;
|
||||
index_out = current_page_used_;
|
||||
current_page_used_ += count;
|
||||
return current_heap_index_;
|
||||
}
|
||||
|
||||
} // namespace d3d12
|
||||
} // namespace ui
|
||||
} // namespace xe
|
|
@ -0,0 +1,151 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/ui/graphics_upload_buffer_pool.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/ui/graphics_upload_buffer_pool.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
GraphicsUploadBufferPool::~GraphicsUploadBufferPool() { ClearCache(); }
|
||||
|
||||
void GraphicsUploadBufferPool::Reclaim(uint64_t completed_submission_index) {
|
||||
while (submitted_first_) {
|
||||
if (submitted_first_->last_submission_index_ > completed_submission_index) {
|
||||
break;
|
||||
}
|
||||
if (writable_last_) {
|
||||
writable_last_->next_ = submitted_first_;
|
||||
} else {
|
||||
writable_first_ = submitted_first_;
|
||||
}
|
||||
writable_last_ = submitted_first_;
|
||||
submitted_first_ = submitted_first_->next_;
|
||||
writable_last_->next_ = nullptr;
|
||||
}
|
||||
if (!submitted_first_) {
|
||||
submitted_last_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsUploadBufferPool::ClearCache() {
|
||||
// Called from the destructor - must not call virtual functions here.
|
||||
current_page_flushed_ = 0;
|
||||
current_page_used_ = 0;
|
||||
while (submitted_first_) {
|
||||
Page* next_ = submitted_first_->next_;
|
||||
delete submitted_first_;
|
||||
submitted_first_ = next_;
|
||||
}
|
||||
submitted_last_ = nullptr;
|
||||
while (writable_first_) {
|
||||
Page* next_ = writable_first_->next_;
|
||||
delete writable_first_;
|
||||
writable_first_ = next_;
|
||||
}
|
||||
writable_last_ = nullptr;
|
||||
}
|
||||
|
||||
GraphicsUploadBufferPool::Page::~Page() {}
|
||||
|
||||
void GraphicsUploadBufferPool::FlushWrites() {
|
||||
if (current_page_flushed_ >= current_page_used_) {
|
||||
return;
|
||||
}
|
||||
assert_not_null(writable_first_);
|
||||
FlushPageWrites(writable_first_, current_page_flushed_,
|
||||
current_page_used_ - current_page_flushed_);
|
||||
current_page_flushed_ = current_page_used_;
|
||||
}
|
||||
|
||||
GraphicsUploadBufferPool::Page* GraphicsUploadBufferPool::Request(
|
||||
uint64_t submission_index, size_t size, size_t alignment,
|
||||
size_t& offset_out) {
|
||||
assert_not_zero(alignment);
|
||||
assert_true(xe::is_pow2(alignment));
|
||||
size = xe::align(size, alignment);
|
||||
assert_true(size <= page_size_);
|
||||
if (size > page_size_) {
|
||||
return nullptr;
|
||||
}
|
||||
assert_true(!current_page_used_ ||
|
||||
submission_index >= writable_first_->last_submission_index_);
|
||||
assert_true(!submitted_last_ ||
|
||||
submission_index >= submitted_last_->last_submission_index_);
|
||||
size_t current_page_used_aligned = xe::align(current_page_used_, alignment);
|
||||
if (current_page_used_aligned + size > page_size_ || !writable_first_) {
|
||||
// Start a new page if can't fit all the bytes or don't have an open page.
|
||||
if (writable_first_) {
|
||||
// Close the page that was current.
|
||||
FlushWrites();
|
||||
if (submitted_last_) {
|
||||
submitted_last_->next_ = writable_first_;
|
||||
} else {
|
||||
submitted_first_ = writable_first_;
|
||||
}
|
||||
submitted_last_ = writable_first_;
|
||||
writable_first_ = writable_first_->next_;
|
||||
submitted_last_->next_ = nullptr;
|
||||
if (!writable_first_) {
|
||||
writable_last_ = nullptr;
|
||||
}
|
||||
}
|
||||
if (!writable_first_) {
|
||||
// Create a new page if none available.
|
||||
writable_first_ = CreatePageImplementation();
|
||||
if (!writable_first_) {
|
||||
// Failed to create.
|
||||
return nullptr;
|
||||
}
|
||||
writable_first_->last_submission_index_ = submission_index;
|
||||
writable_first_->next_ = nullptr;
|
||||
writable_last_ = writable_first_;
|
||||
// After CreatePageImplementation (more specifically, the first successful
|
||||
// call), page_size_ may grow - but this doesn't matter here.
|
||||
}
|
||||
current_page_used_ = 0;
|
||||
current_page_used_aligned = 0;
|
||||
current_page_flushed_ = 0;
|
||||
}
|
||||
writable_first_->last_submission_index_ = submission_index;
|
||||
offset_out = current_page_used_aligned;
|
||||
current_page_used_ = current_page_used_aligned + size;
|
||||
return writable_first_;
|
||||
}
|
||||
|
||||
GraphicsUploadBufferPool::Page* GraphicsUploadBufferPool::RequestPartial(
|
||||
uint64_t submission_index, size_t size, size_t alignment,
|
||||
size_t& offset_out, size_t& size_out) {
|
||||
assert_not_zero(alignment);
|
||||
assert_true(xe::is_pow2(alignment));
|
||||
size = xe::align(size, alignment);
|
||||
size = std::min(size, page_size_);
|
||||
size_t current_page_used_aligned = xe::align(current_page_used_, alignment);
|
||||
if (current_page_used_aligned + alignment <= page_size_) {
|
||||
size = std::min(
|
||||
size, (page_size_ - current_page_used_aligned) & ~(alignment - 1));
|
||||
}
|
||||
Page* page = Request(submission_index, size, alignment, offset_out);
|
||||
if (!page) {
|
||||
return nullptr;
|
||||
}
|
||||
size_out = size;
|
||||
return page;
|
||||
}
|
||||
|
||||
void GraphicsUploadBufferPool::FlushPageWrites(Page* page, size_t offset,
|
||||
size_t size) {}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace xe
|
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_UI_GRAPHICS_UPLOAD_BUFFER_POOL_H_
|
||||
#define XENIA_UI_GRAPHICS_UPLOAD_BUFFER_POOL_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
// Submission index is the fence value or a value derived from it (if reclaiming
|
||||
// less often than once per fence value, for instance).
|
||||
|
||||
class GraphicsUploadBufferPool {
|
||||
public:
|
||||
// Taken from the Direct3D 12 MiniEngine sample (LinearAllocator
|
||||
// kCpuAllocatorPageSize). Large enough for most cases.
|
||||
static constexpr size_t kDefaultPageSize = 2 * 1024 * 1024;
|
||||
|
||||
virtual ~GraphicsUploadBufferPool();
|
||||
|
||||
void Reclaim(uint64_t completed_submission_index);
|
||||
void ClearCache();
|
||||
|
||||
// Should be called before submitting anything using this pool, unless the
|
||||
// implementation doesn't require explicit flushing.
|
||||
void FlushWrites();
|
||||
|
||||
protected:
|
||||
// Extended by the implementation.
|
||||
struct Page {
|
||||
virtual ~Page();
|
||||
uint64_t last_submission_index_;
|
||||
Page* next_;
|
||||
};
|
||||
|
||||
GraphicsUploadBufferPool(size_t page_size) : page_size_(page_size) {}
|
||||
|
||||
// Request to write data in a single piece, creating a new page if the current
|
||||
// one doesn't have enough free space.
|
||||
Page* Request(uint64_t submission_index, size_t size, size_t alignment,
|
||||
size_t& offset_out);
|
||||
// Request to write data in multiple parts, filling the buffer entirely.
|
||||
Page* RequestPartial(uint64_t submission_index, size_t size, size_t alignment,
|
||||
size_t& offset_out, size_t& size_out);
|
||||
|
||||
virtual Page* CreatePageImplementation() = 0;
|
||||
|
||||
virtual void FlushPageWrites(Page* page, size_t offset, size_t size);
|
||||
|
||||
// May be increased by the implementation on creation or on first allocation
|
||||
// to avoid wasting space if the real allocation turns out to be bigger than
|
||||
// the specified page size.
|
||||
size_t page_size_;
|
||||
|
||||
// A list of buffers with free space, with the first buffer being the one
|
||||
// currently being filled.
|
||||
Page* writable_first_ = nullptr;
|
||||
Page* writable_last_ = nullptr;
|
||||
// A list of full buffers that can be reclaimed when the GPU doesn't use them
|
||||
// anymore.
|
||||
Page* submitted_first_ = nullptr;
|
||||
Page* submitted_last_ = nullptr;
|
||||
|
||||
size_t current_page_used_ = 0;
|
||||
size_t current_page_flushed_ = 0;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_GRAPHICS_UPLOAD_BUFFER_POOL_H_
|
Loading…
Reference in New Issue