[D3D12] Upload data to shared memory during frame (fixes swaying palms in CoD4)
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/memory.h"
|
||||
#include "xenia/ui/d3d12/d3d12_api.h"
|
||||
@@ -40,15 +41,15 @@ class SharedMemory {
|
||||
void BeginFrame();
|
||||
// Returns true if anything has been written to command_list been done.
|
||||
// The draw command list is needed for the transition.
|
||||
bool EndFrame(ID3D12GraphicsCommandList* command_list_setup,
|
||||
ID3D12GraphicsCommandList* command_list_draw);
|
||||
void EndFrame();
|
||||
|
||||
// Marks the range as used in this frame, queues it for upload if it was
|
||||
// modified. Ensures the backing memory for the address range is present in
|
||||
// the tiled buffer, allocating if needed. If couldn't allocate, false is
|
||||
// returned - it's unsafe to use this portion (on tiled resources tier 1 at
|
||||
// least).
|
||||
bool UseRange(uint32_t start, uint32_t length);
|
||||
// Checks if the range has been updated, uploads new data if needed and
|
||||
// ensures the buffer tiles backing the range are resident. May transition the
|
||||
// tiled buffer to copy destination - call this before UseForReading or
|
||||
// UseForWriting. Returns true if the range has been fully updated and is
|
||||
// usable.
|
||||
bool RequestRange(uint32_t start, uint32_t length,
|
||||
ID3D12GraphicsCommandList* command_list);
|
||||
|
||||
// Makes the buffer usable for vertices, indices and texture untiling.
|
||||
void UseForReading(ID3D12GraphicsCommandList* command_list);
|
||||
@@ -87,32 +88,30 @@ class SharedMemory {
|
||||
// Total physical page count.
|
||||
uint32_t page_count_;
|
||||
|
||||
// Mutex between the exception handler and the command processor, to be locked
|
||||
// when checking or updating validity of pages/ranges.
|
||||
std::mutex validity_mutex_;
|
||||
// Bit vector containing whether physical memory system pages are up to date.
|
||||
std::vector<uint64_t> pages_in_sync_;
|
||||
std::vector<uint64_t> valid_pages_;
|
||||
// Mark the memory range as updated and watch it.
|
||||
void MakeRangeValid(uint32_t valid_page_first, uint32_t valid_page_count);
|
||||
|
||||
// First page and length in pages.
|
||||
typedef std::pair<uint32_t, uint32_t> UploadRange;
|
||||
// Ranges that need to be uploaded, generated by GetRangesToUpload (a
|
||||
// persistently allocated vector).
|
||||
std::vector<UploadRange> upload_ranges_;
|
||||
void GetRangesToUpload(uint32_t request_page_first,
|
||||
uint32_t request_page_count);
|
||||
std::unique_ptr<ui::d3d12::UploadBufferPool> upload_buffer_pool_ = nullptr;
|
||||
|
||||
// Mutex for the watched pages and the triggered watches.
|
||||
std::mutex watch_mutex_;
|
||||
// Whether each physical page is watched by the GPU (after uploading).
|
||||
// Once a watch is triggered, it's not watched anymore.
|
||||
std::vector<uint64_t> watched_pages_;
|
||||
// Whether each page was modified while the current frame is being processed.
|
||||
// This is checked and cleared in the beginning of a GPU frame.
|
||||
// Because this is done with a locked CPU-GPU mutex, it's stored in 2 levels,
|
||||
// so unmodified pages can be skipped quickly, and clearing is also fast.
|
||||
// On L1, each bit corresponds to a single page, on L2, to 64 pages.
|
||||
// Checking if L2 is non-zero before accessing L1 is REQUIRED since L1 is not
|
||||
// cleared!
|
||||
std::vector<uint64_t> watches_triggered_l1_;
|
||||
std::vector<uint64_t> watches_triggered_l2_;
|
||||
// Memory access callback.
|
||||
static bool WatchCallbackThunk(void* context_ptr, uint32_t address);
|
||||
bool WatchCallback(uint32_t address);
|
||||
|
||||
// Pages that need to be uploaded in this frame (that are used but modified).
|
||||
std::vector<uint64_t> upload_pages_;
|
||||
uint32_t NextUploadRange(uint32_t search_start, uint32_t& length) const;
|
||||
std::unique_ptr<ui::d3d12::UploadBufferPool> upload_buffer_pool_ = nullptr;
|
||||
|
||||
void TransitionBuffer(D3D12_RESOURCE_STATES new_state,
|
||||
ID3D12GraphicsCommandList* command_list);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user