Files
Xenia-Canary/src/xenia/ui/graphics_upload_buffer_pool.cc
Triang3l fe3f0f26e4 [UI] Image post-processing and full presentation/window rework
[GPU] Add FXAA post-processing
[UI] Add FidelityFX FSR and CAS post-processing
[UI] Add blue noise dithering from 10bpc to 8bpc
[GPU] Apply the DC PWL gamma ramp closer to the spec, supporting fully white color
[UI] Allow the GPU CP thread to present on the host directly, bypassing the UI thread OS paint event
[UI] Allow variable refresh rate (or tearing)
[UI] Present the newest frame (restart) on DXGI
[UI] Replace GraphicsContext with a far more advanced Presenter with more coherent surface connection and UI overlay state management
[UI] Connect presentation to windows via the Surface class, not native window handles
[Vulkan] Switch to simpler Vulkan setup with no instance/device separation due to interdependencies and to pass fewer objects around
[Vulkan] Lower the minimum required Vulkan version to 1.0
[UI/GPU] Various cleanup, mainly ComPtr usage
[UI] Support per-monitor DPI awareness v2 on Windows
[UI] DPI-scale Dear ImGui
[UI] Replace the remaining non-detachable window delegates with unified window event and input listeners
[UI] Allow listeners to safely destroy or close the window, and to register/unregister listeners without use-after-free and the ABA problem
[UI] Explicit Z ordering of input listeners and UI overlays, top-down for input, bottom-up for drawing
[UI] Add explicit window lifecycle phases
[UI] Replace Window virtual functions with explicit desired state, its application, actual state, its feedback
[UI] GTK: Apply the initial size to the drawing area
[UI] Limit internal UI frame rate to that of the monitor
[UI] Hide the cursor using a timer instead of polling due to no repeated UI thread paints with GPU CP thread presentation, and only within the window
2022-01-29 13:22:03 +03:00

170 lines
5.5 KiB
C++

/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2022 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"
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::ChangeSubmissionTimeline() {
// Reclaim all submitted pages.
if (writable_last_) {
writable_last_->next_ = submitted_first_;
} else {
writable_first_ = submitted_first_;
}
writable_last_ = submitted_last_;
submitted_first_ = nullptr;
submitted_last_ = nullptr;
// Mark all pages as never used yet in the new timeline.
Page* page = writable_first_;
while (page) {
page->last_submission_index_ = 0;
page = page->next_;
}
}
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) {
alignment = std::max(alignment, size_t(1));
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) {
alignment = std::max(alignment, size_t(1));
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