mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-20 22:05:12 +00:00
243 lines
6.1 KiB
C++
243 lines
6.1 KiB
C++
#pragma once
|
|
#include "D3D12Utils.h"
|
|
#include "d3dx12.h"
|
|
|
|
|
|
template<typename T>
|
|
struct init_heap
|
|
{
|
|
static T* init(ID3D12Device *device, size_t heapSize, D3D12_HEAP_TYPE type, D3D12_HEAP_FLAGS flags);
|
|
};
|
|
|
|
template<>
|
|
struct init_heap<ID3D12Heap>
|
|
{
|
|
static ID3D12Heap* init(ID3D12Device *device, size_t heap_size, D3D12_HEAP_TYPE type, D3D12_HEAP_FLAGS flags)
|
|
{
|
|
ID3D12Heap *result;
|
|
D3D12_HEAP_DESC heap_desc = {};
|
|
heap_desc.SizeInBytes = heap_size;
|
|
heap_desc.Properties.Type = type;
|
|
heap_desc.Flags = flags;
|
|
ThrowIfFailed(device->CreateHeap(&heap_desc, IID_PPV_ARGS(&result)));
|
|
return result;
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct init_heap<ID3D12Resource>
|
|
{
|
|
static ID3D12Resource* init(ID3D12Device *device, size_t heap_size, D3D12_HEAP_TYPE type, D3D12_HEAP_FLAGS flags)
|
|
{
|
|
ID3D12Resource *result;
|
|
D3D12_HEAP_PROPERTIES heap_properties = {};
|
|
heap_properties.Type = type;
|
|
ThrowIfFailed(device->CreateCommittedResource(&heap_properties,
|
|
flags,
|
|
&CD3DX12_RESOURCE_DESC::Buffer(heap_size),
|
|
D3D12_RESOURCE_STATE_GENERIC_READ,
|
|
nullptr,
|
|
IID_PPV_ARGS(&result))
|
|
);
|
|
|
|
return result;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Wrapper around a ID3D12Resource or a ID3D12Heap.
|
|
* Acts as a ring buffer : hold a get and put pointers,
|
|
* put pointer is used as storage space offset
|
|
* and get is used as beginning of in use data space.
|
|
* This wrapper checks that put pointer doesn't cross get one.
|
|
*/
|
|
template<typename T, size_t alignment>
|
|
struct data_heap
|
|
{
|
|
T *m_heap;
|
|
size_t m_size;
|
|
size_t m_put_pos; // Start of free space
|
|
size_t m_get_pos; // End of free space
|
|
|
|
void init(ID3D12Device *device, size_t heap_size, D3D12_HEAP_TYPE type, D3D12_HEAP_FLAGS flags)
|
|
{
|
|
m_size = heap_size;
|
|
m_heap = init_heap<T>::init(device, heap_size, type, flags);
|
|
m_put_pos = 0;
|
|
m_get_pos = heap_size - 1;
|
|
}
|
|
|
|
/**
|
|
* Does alloc cross get position ?
|
|
*/
|
|
bool can_alloc(size_t size) const noexcept
|
|
{
|
|
size_t alloc_size = align(size, alignment);
|
|
if (m_put_pos + alloc_size < m_size)
|
|
{
|
|
// range before get
|
|
if (m_put_pos + alloc_size < m_get_pos)
|
|
return true;
|
|
// range after get
|
|
if (m_put_pos > m_get_pos)
|
|
return true;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// ..]....[..get..
|
|
if (m_put_pos < m_get_pos)
|
|
return false;
|
|
// ..get..]...[...
|
|
// Actually all resources extending beyond heap space starts at 0
|
|
if (alloc_size > m_get_pos)
|
|
return false;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
size_t alloc(size_t size) noexcept
|
|
{
|
|
assert(can_alloc(size));
|
|
size_t alloc_size = align(size, alignment);
|
|
if (m_put_pos + alloc_size < m_size)
|
|
{
|
|
size_t old_put_pos = m_put_pos;
|
|
m_put_pos += alloc_size;
|
|
return old_put_pos;
|
|
}
|
|
else
|
|
{
|
|
m_put_pos = alloc_size;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void release() noexcept
|
|
{
|
|
m_heap->Release();
|
|
}
|
|
|
|
/**
|
|
* return current putpos - 1
|
|
*/
|
|
size_t get_current_put_pos_minus_one() const noexcept
|
|
{
|
|
return (m_put_pos - 1 > 0) ? m_put_pos - 1 : m_size - 1;
|
|
}
|
|
};
|
|
|
|
struct texture_entry
|
|
{
|
|
int m_format;
|
|
size_t m_width;
|
|
size_t m_height;
|
|
size_t m_mipmap;
|
|
bool m_is_dirty;
|
|
|
|
texture_entry() : m_format(0), m_width(0), m_height(0), m_is_dirty(true)
|
|
{}
|
|
|
|
texture_entry(int f, size_t w, size_t h, size_t m) : m_format(f), m_width(w), m_height(h), m_is_dirty(false)
|
|
{}
|
|
|
|
bool operator==(const texture_entry &other)
|
|
{
|
|
return (m_format == other.m_format && m_width == other.m_width && m_height == other.m_height);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Manages cache of data (texture/vertex/index)
|
|
*/
|
|
struct data_cache
|
|
{
|
|
private:
|
|
/**
|
|
* Mutex protecting m_dataCache access
|
|
* Memory protection fault catch can be generated by any thread and
|
|
* modifies it.
|
|
*/
|
|
std::mutex m_mut;
|
|
|
|
std::unordered_map<u64, std::pair<texture_entry, ComPtr<ID3D12Resource>> > m_address_to_data; // Storage
|
|
std::list <std::tuple<u64, u32, u32> > m_protected_ranges; // address, start of protected range, size of protected range
|
|
public:
|
|
void store_and_protect_data(u64 key, u32 start, size_t size, int format, size_t w, size_t h, size_t m, ComPtr<ID3D12Resource> data) noexcept;
|
|
|
|
/**
|
|
* Make memory from start to start + size write protected.
|
|
* Associate key to this range so that when a write is detected, data at key is marked dirty.
|
|
*/
|
|
void protect_data(u64 key, u32 start, size_t size) noexcept;
|
|
|
|
/**
|
|
* Remove all data containing addr from cache, unprotect them. Returns false if no data is modified.
|
|
*/
|
|
bool invalidate_address(u32 addr) noexcept;
|
|
|
|
std::pair<texture_entry, ComPtr<ID3D12Resource> > *find_data_if_available(u64 key) noexcept;
|
|
|
|
void unprotect_all() noexcept;
|
|
|
|
/**
|
|
* Remove data stored at key, and returns a ComPtr owning it.
|
|
* The caller is responsible for releasing the ComPtr.
|
|
*/
|
|
ComPtr<ID3D12Resource> remove_from_cache(u64 key) noexcept;
|
|
};
|
|
|
|
/**
|
|
* Stores data that are "ping ponged" between frame.
|
|
* For instance command allocator : maintains 2 command allocators and
|
|
* swap between them when frame is flipped.
|
|
*/
|
|
struct resource_storage
|
|
{
|
|
bool in_use; // False until command list has been populated at least once
|
|
ComPtr<ID3D12Fence> frame_finished_fence;
|
|
UINT64 fence_value;
|
|
HANDLE frame_finished_handle;
|
|
|
|
// Pointer to device, not owned by ResourceStorage
|
|
ID3D12Device *m_device;
|
|
ComPtr<ID3D12CommandAllocator> command_allocator;
|
|
ComPtr<ID3D12GraphicsCommandList> command_list;
|
|
|
|
// Descriptor heap
|
|
ComPtr<ID3D12DescriptorHeap> descriptors_heap;
|
|
size_t descriptors_heap_index;
|
|
|
|
// Sampler heap
|
|
ComPtr<ID3D12DescriptorHeap> sampler_descriptor_heap[2];
|
|
size_t sampler_descriptors_heap_index;
|
|
size_t current_sampler_index;
|
|
|
|
size_t render_targets_descriptors_heap_index;
|
|
ComPtr<ID3D12DescriptorHeap> render_targets_descriptors_heap;
|
|
size_t depth_stencil_descriptor_heap_index;
|
|
ComPtr<ID3D12DescriptorHeap> depth_stencil_descriptor_heap;
|
|
|
|
ComPtr<ID3D12Resource> ram_framebuffer;
|
|
|
|
/// Texture that were invalidated
|
|
std::list<ComPtr<ID3D12Resource> > dirty_textures;
|
|
|
|
/**
|
|
* Start position in heaps of resources used for this frame.
|
|
* This means newer resources shouldn't allocate memory crossing this position
|
|
* until the frame rendering is over.
|
|
*/
|
|
size_t constants_heap_get_pos;
|
|
size_t vertex_index_heap_get_pos;
|
|
size_t texture_upload_heap_get_pos;
|
|
size_t readback_heap_get_pos;
|
|
size_t uav_heap_get_pos;
|
|
|
|
void reset();
|
|
void init(ID3D12Device *device);
|
|
void set_new_command_list();
|
|
void wait_and_clean();
|
|
void release();
|
|
};
|