[UI] UploadBufferPool common code
This commit is contained in:
137
src/xenia/ui/d3d12/d3d12_descriptor_heap_pool.cc
Normal file
137
src/xenia/ui/d3d12/d3d12_descriptor_heap_pool.cc
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user