Adding template project
This commit is contained in:
696
vendor/rmlui_backend/RmlUi_Renderer_DX12.h
vendored
Normal file
696
vendor/rmlui_backend/RmlUi_Renderer_DX12.h
vendored
Normal file
@@ -0,0 +1,696 @@
|
||||
#pragma once
|
||||
|
||||
#include <RmlUi/Core/RenderInterface.h>
|
||||
|
||||
#ifndef RMLUI_PLATFORM_WIN32
|
||||
#error "DirectX 12 renderer only supported on Windows"
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
#include "RmlUi_Include_Windows.h"
|
||||
#include "RmlUi_Include_DirectX_12.h"
|
||||
// clang-format on
|
||||
|
||||
enum class ProgramId;
|
||||
|
||||
class RenderLayerStack;
|
||||
namespace Gfx {
|
||||
struct ProgramData;
|
||||
struct FramebufferData;
|
||||
} // namespace Gfx
|
||||
|
||||
namespace Backend {
|
||||
struct RmlRenderInitInfo;
|
||||
struct RmlRendererSettings;
|
||||
} // namespace Backend
|
||||
|
||||
class RenderInterface_DX12 : public Rml::RenderInterface {
|
||||
private:
|
||||
static constexpr uint32_t InvalidConstantBuffer_RootParameterIndex = std::numeric_limits<uint32_t>::max();
|
||||
static constexpr uint8_t MaxConstantBuffersPerShader = 3;
|
||||
static constexpr size_t NumPrograms = 23;
|
||||
|
||||
public:
|
||||
struct GraphicsAllocationInfo {
|
||||
int buffer_index = -1;
|
||||
size_t offset = {};
|
||||
size_t size = {};
|
||||
D3D12MA::VirtualAllocation alloc_info = {};
|
||||
};
|
||||
|
||||
class TextureHandleType : Rml::NonCopyMoveable {
|
||||
public:
|
||||
TextureHandleType() = default;
|
||||
~TextureHandleType()
|
||||
{
|
||||
#ifdef RMLUI_DX_DEBUG
|
||||
RMLUI_ASSERTMSG(m_is_destroyed, "The texture was not destroyed");
|
||||
#endif
|
||||
}
|
||||
|
||||
const GraphicsAllocationInfo& Get_Info() const noexcept { return m_info; }
|
||||
void Set_Info(const GraphicsAllocationInfo& info) { m_info = info; }
|
||||
void Set_Resource(void* p_resource) { m_p_resource = p_resource; }
|
||||
void* Get_Resource() const noexcept { return m_p_resource; }
|
||||
|
||||
#ifdef RMLUI_DX_DEBUG
|
||||
/// @brief returns debug resource name. Implementation of this method exists only when DEBUG is enabled for this project
|
||||
/// @return debug resource name when the source string is passed in LoadTexture method
|
||||
const Rml::String& Get_ResourceName() const { return m_debug_resource_name; }
|
||||
|
||||
/// @brief sets m_debug_resource_name field with specified argument as resource_name
|
||||
/// @param resource_name this string is getting from LoadTexture method from source argument
|
||||
void Set_ResourceName(const Rml::String& resource_name) { m_debug_resource_name = resource_name; }
|
||||
#endif
|
||||
|
||||
// this method calls texture manager! don't call it manually because you must ensure that you freed virtual block if it had
|
||||
void Destroy()
|
||||
{
|
||||
#ifdef RMLUI_DX_DEBUG
|
||||
RMLUI_ASSERTMSG(!m_is_destroyed, "The texture has already been destroyed");
|
||||
m_is_destroyed = true;
|
||||
#endif
|
||||
|
||||
if (m_p_resource)
|
||||
{
|
||||
if (m_info.buffer_index != -1)
|
||||
{
|
||||
static_cast<ID3D12Resource*>(m_p_resource)->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
D3D12MA::Allocation* p_committed_resource = static_cast<D3D12MA::Allocation*>(m_p_resource);
|
||||
if (auto* underlying_resource = p_committed_resource->GetResource())
|
||||
underlying_resource->Release();
|
||||
|
||||
p_committed_resource->Release();
|
||||
}
|
||||
|
||||
m_info = GraphicsAllocationInfo();
|
||||
m_p_resource = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const OffsetAllocator::Allocation& Get_Allocation_DescriptorHeap() const noexcept { return m_allocation_descriptor_heap; }
|
||||
void Set_Allocation_DescriptorHeap(const OffsetAllocator::Allocation& allocation) noexcept { m_allocation_descriptor_heap = allocation; }
|
||||
|
||||
private:
|
||||
GraphicsAllocationInfo m_info;
|
||||
OffsetAllocator::Allocation m_allocation_descriptor_heap;
|
||||
void* m_p_resource = nullptr; // placed or committed (CreateResource from D3D12MA)
|
||||
|
||||
#ifdef RMLUI_DX_DEBUG
|
||||
Rml::String m_debug_resource_name;
|
||||
bool m_is_destroyed = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ConstantBufferType {
|
||||
GraphicsAllocationInfo m_alloc_info;
|
||||
void* m_p_gpu_start_memory_for_binding_data = nullptr;
|
||||
};
|
||||
|
||||
class GeometryHandleType : Rml::NonCopyMoveable {
|
||||
public:
|
||||
GeometryHandleType() = default;
|
||||
|
||||
void Set_InfoVertex(const GraphicsAllocationInfo& info) { m_info_vertex = info; }
|
||||
const GraphicsAllocationInfo& Get_InfoVertex() const noexcept { return m_info_vertex; }
|
||||
|
||||
void Set_InfoIndex(const GraphicsAllocationInfo& info) { m_info_index = info; }
|
||||
const GraphicsAllocationInfo& Get_InfoIndex() const noexcept { return m_info_index; }
|
||||
|
||||
void Set_NumVertices(int num) { m_num_vertices = num; }
|
||||
int Get_NumVertices() const { return m_num_vertices; }
|
||||
|
||||
void Set_NumIndices(int num) { m_num_indices = num; }
|
||||
int Get_NumIndices() const { return m_num_indices; }
|
||||
|
||||
void Set_SizeOfOneVertex(size_t size) { m_one_element_vertex_size = size; }
|
||||
size_t Get_SizeOfOneVertex() const { return m_one_element_vertex_size; }
|
||||
|
||||
void Set_SizeOfOneIndex(size_t size) { m_one_element_index_size = size; }
|
||||
size_t Get_SizeOfOneIndex() const { return m_one_element_index_size; }
|
||||
|
||||
const OffsetAllocator::Allocation& Get_Allocation_DescriptorHeap() const noexcept { return m_allocation_descriptor_heap; }
|
||||
void Set_Allocation_DescriptorHeap(const OffsetAllocator::Allocation& allocation) noexcept { m_allocation_descriptor_heap = allocation; }
|
||||
|
||||
int Get_HistoryBackBufferFrameIndex(void) const { return m_history_backbuffer_frame_index; }
|
||||
void Set_HistoryBackBufferFrameIndex(int frame_index) { m_history_backbuffer_frame_index = frame_index; }
|
||||
|
||||
void Set_ConstantBuffer(ConstantBufferType* p_constant_buffer)
|
||||
{
|
||||
RMLUI_ASSERTMSG(p_constant_buffer, "must be valid constant buffer!");
|
||||
m_p_constant_buffer_override = p_constant_buffer;
|
||||
}
|
||||
|
||||
void Reset_ConstantBuffer()
|
||||
{
|
||||
m_p_constant_buffer_override = nullptr;
|
||||
for (uint8_t i = 0; i < MaxConstantBuffersPerShader; ++i)
|
||||
{
|
||||
m_constant_buffer_root_parameter_indices[i] = InvalidConstantBuffer_RootParameterIndex;
|
||||
}
|
||||
}
|
||||
|
||||
ConstantBufferType* Get_ConstantBuffer() const { return m_p_constant_buffer_override; }
|
||||
|
||||
// use this only for shared CBV that will be used among all shaders otherwise we need to provide a new array that will hold a GPU addresses to
|
||||
// different cbv and their indices but for now it is only for ONE CBV that can be used among vertex and pixel shaders
|
||||
void Add_ConstantBufferRootParameterIndices(uint32_t index)
|
||||
{
|
||||
#ifdef RMLUI_DX_DEBUG
|
||||
bool found_empty_slot = false;
|
||||
#endif
|
||||
|
||||
for (unsigned char i = 0; i < MaxConstantBuffersPerShader; ++i)
|
||||
{
|
||||
if (m_constant_buffer_root_parameter_indices[i] == InvalidConstantBuffer_RootParameterIndex)
|
||||
{
|
||||
#ifdef RMLUI_DX_DEBUG
|
||||
found_empty_slot = true;
|
||||
#endif
|
||||
|
||||
m_constant_buffer_root_parameter_indices[i] = index;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RMLUI_DX_DEBUG
|
||||
RMLUI_ASSERTMSG(found_empty_slot,
|
||||
"failed to obtain empty slot in such case you have to set another limits for engine using "
|
||||
"MaxConstantBuffersPerShader field");
|
||||
#endif
|
||||
}
|
||||
|
||||
const uint32_t* Get_ConstantBufferRootParameterIndices(uint8_t& amount_of_indices) const
|
||||
{
|
||||
amount_of_indices = 0;
|
||||
|
||||
// might be slow for big arrays otherwise provide a cache field for this class just like field that will show current size of
|
||||
// m_constant_buffer_root_parameter_indices member in terms of current entries that are filled the array for now just to reduce the
|
||||
// memory footprint for this class and I don't use this cache field as size so we determine in runtime
|
||||
for (uint8_t i = 0; i < MaxConstantBuffersPerShader; ++i)
|
||||
{
|
||||
if (m_constant_buffer_root_parameter_indices[i] != InvalidConstantBuffer_RootParameterIndex)
|
||||
{
|
||||
amount_of_indices = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return m_constant_buffer_root_parameter_indices;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_num_vertices = {};
|
||||
int m_num_indices = {};
|
||||
int m_history_backbuffer_frame_index = -1;
|
||||
ConstantBufferType* m_p_constant_buffer_override = {};
|
||||
size_t m_one_element_vertex_size = {};
|
||||
size_t m_one_element_index_size = {};
|
||||
uint32_t m_constant_buffer_root_parameter_indices[MaxConstantBuffersPerShader] = {
|
||||
InvalidConstantBuffer_RootParameterIndex,
|
||||
InvalidConstantBuffer_RootParameterIndex,
|
||||
InvalidConstantBuffer_RootParameterIndex,
|
||||
};
|
||||
GraphicsAllocationInfo m_info_vertex;
|
||||
GraphicsAllocationInfo m_info_index;
|
||||
OffsetAllocator::Allocation m_allocation_descriptor_heap;
|
||||
};
|
||||
|
||||
class BufferMemoryManager : Rml::NonCopyMoveable {
|
||||
public:
|
||||
BufferMemoryManager();
|
||||
~BufferMemoryManager();
|
||||
|
||||
void Initialize(ID3D12Device* m_p_device, D3D12MA::Allocator* p_allocator,
|
||||
OffsetAllocator::Allocator* p_offset_allocator_for_descriptor_heap_srv_cbv_uav, D3D12_CPU_DESCRIPTOR_HANDLE* p_handle,
|
||||
uint32_t size_descriptor_element, size_t size_for_allocation = RMLUI_RENDER_BACKEND_FIELD_VIDEOMEMORY_FOR_BUFFER_ALLOCATION,
|
||||
size_t size_alignment = RMLUI_RENDER_BACKEND_FIELD_ALIGNMENT_FOR_BUFFER);
|
||||
void Shutdown();
|
||||
|
||||
void Alloc_Vertex(const void* p_data, int num_vertices, size_t size_of_one_element_in_p_data, GeometryHandleType* p_handle);
|
||||
void Alloc_Index(const void* p_data, int num_vertices, size_t size_of_one_element_in_p_data, GeometryHandleType* p_handle);
|
||||
|
||||
GraphicsAllocationInfo Alloc_ConstantBuffer(ConstantBufferType* p_resource, size_t size);
|
||||
|
||||
void Free_ConstantBuffer(ConstantBufferType* p_constantbuffer);
|
||||
void Free_Geometry(GeometryHandleType* p_geometryhandle);
|
||||
|
||||
void* Get_WritableMemoryFromBufferByOffset(const GraphicsAllocationInfo& info);
|
||||
|
||||
D3D12MA::Allocation* Get_BufferByIndex(int buffer_index);
|
||||
|
||||
bool Is_Initialized() const;
|
||||
|
||||
private:
|
||||
void Alloc_Buffer(size_t size
|
||||
#ifdef RMLUI_DX_DEBUG
|
||||
,
|
||||
const std::wstring& debug_name
|
||||
#endif
|
||||
);
|
||||
|
||||
// Searches for block that has enough memory for requested allocation size, otherwise returns nullptr that means no block!
|
||||
D3D12MA::VirtualBlock* Get_AvailableBlock(size_t size_for_allocation, int* p_result_buffer_index);
|
||||
|
||||
D3D12MA::VirtualBlock* Get_NotOutOfMemoryAndAvailableBlock(size_t size_for_allocation, int* p_result_buffer_index);
|
||||
|
||||
int Alloc(GraphicsAllocationInfo& info, size_t size, size_t alignment = 0);
|
||||
|
||||
void TryToFreeAvailableBlock();
|
||||
|
||||
uint32_t m_descriptor_increment_size_srv_cbv_uav;
|
||||
size_t m_size_for_allocation_in_bytes;
|
||||
size_t m_size_alignment_in_bytes;
|
||||
ID3D12Device* m_p_device;
|
||||
D3D12MA::Allocator* m_p_allocator;
|
||||
OffsetAllocator::Allocator* m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE* m_p_start_pointer_of_descriptor_heap_srv_cbv_uav;
|
||||
/// @brief this is for sub allocating purposes using 'Virtual Allocation' from D3D12MA
|
||||
Rml::Vector<D3D12MA::VirtualBlock*> m_virtual_buffers;
|
||||
/// @brief this is physical representation of VRAM and uses from CPU side for binding data
|
||||
Rml::Vector<Rml::Pair<D3D12MA::Allocation*, void*>> m_buffers;
|
||||
};
|
||||
|
||||
/**
|
||||
* The key feature of this manager is texture management and if texture size is less or equal to 1.0 MB it will
|
||||
* allocate heap for placing resources and if resource is less (or equal) to 1 MB then it will be written to that
|
||||
* heap Otherwise will be used heap per texture (committed resource)
|
||||
*/
|
||||
class TextureMemoryManager : Rml::NonCopyMoveable {
|
||||
public:
|
||||
TextureMemoryManager();
|
||||
~TextureMemoryManager();
|
||||
|
||||
void Initialize(D3D12MA::Allocator* p_allocator, OffsetAllocator::Allocator* p_offset_allocator_for_descriptor_heap_srv_cbv_uav,
|
||||
ID3D12Device* p_device, ID3D12GraphicsCommandList* p_copy_command_list, ID3D12GraphicsCommandList* p_backend_command_list,
|
||||
ID3D12CommandAllocator* p_copy_allocator_command, ID3D12DescriptorHeap* p_descriptor_heap_srv,
|
||||
ID3D12DescriptorHeap* p_descriptor_heap_rtv, ID3D12DescriptorHeap* p_descriptor_heap_dsv, ID3D12CommandQueue* p_copy_queue,
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE* p_handle, RenderInterface_DX12* p_renderer,
|
||||
size_t size_for_placed_heap = RMLUI_RENDER_BACKEND_FIELD_VIDEOMEMORY_FOR_TEXTURE_ALLOCATION);
|
||||
void Shutdown();
|
||||
|
||||
ID3D12Resource* Alloc_Texture(D3D12_RESOURCE_DESC& desc, TextureHandleType* p_impl, const Rml::byte* p_data
|
||||
#ifdef RMLUI_DX_DEBUG
|
||||
,
|
||||
const Rml::String& debug_name
|
||||
#endif
|
||||
);
|
||||
|
||||
// if you want to create texture for rendering to it aka render target texture
|
||||
ID3D12Resource* Alloc_Texture(D3D12_RESOURCE_DESC& desc, Gfx::FramebufferData* p_impl, D3D12_RESOURCE_FLAGS flags,
|
||||
D3D12_RESOURCE_STATES initial_state
|
||||
#ifdef RMLUI_DX_DEBUG
|
||||
,
|
||||
const Rml::String& debug_name
|
||||
#endif
|
||||
);
|
||||
|
||||
void Free_Texture(TextureHandleType* type);
|
||||
void Free_Texture(Gfx::FramebufferData* p_texture);
|
||||
void Free_Texture(TextureHandleType* p_allocated_texture_with_class, bool is_rt, D3D12MA::VirtualAllocation& allocation);
|
||||
|
||||
bool Is_Initialized() const;
|
||||
|
||||
private:
|
||||
bool CanAllocate(size_t total_memory_for_allocation, D3D12MA::VirtualBlock* p_block);
|
||||
bool CanBePlacedResource(size_t total_memory_for_allocation);
|
||||
// don't use it for MSAA texture because we don't implement a such feature!
|
||||
bool CanBeSmallResource(size_t base_memory);
|
||||
|
||||
// use index for obtaining heap from m_heaps_placed
|
||||
D3D12MA::VirtualBlock* Get_AvailableBlock(size_t total_memory_for_allocation, int* result_index);
|
||||
|
||||
void Alloc_As_Committed(size_t base_memory, size_t total_memory, D3D12_RESOURCE_DESC& desc, TextureHandleType* p_impl,
|
||||
const Rml::byte* p_data);
|
||||
// we don't upload to GPU because it is render target and needed to be written
|
||||
void Alloc_As_Committed(size_t base_memory, size_t total_memory, D3D12_RESOURCE_DESC& desc, D3D12_RESOURCE_STATES initial_state,
|
||||
TextureHandleType* p_texture, Gfx::FramebufferData* p_impl);
|
||||
void Alloc_As_Placed(size_t base_memory, size_t total_memory, D3D12_RESOURCE_DESC& desc, TextureHandleType* p_impl, const Rml::byte* p_data);
|
||||
|
||||
void Upload(bool is_committed, TextureHandleType* p_texture_handle, const D3D12_RESOURCE_DESC& desc, const Rml::byte* p_data,
|
||||
ID3D12Resource* p_impl);
|
||||
|
||||
size_t BytesPerPixel(DXGI_FORMAT format);
|
||||
size_t BitsPerPixel(DXGI_FORMAT format);
|
||||
|
||||
Rml::Pair<ID3D12Heap*, D3D12MA::VirtualBlock*> Create_HeapPlaced(size_t size_for_creation);
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE Alloc_RenderTargetResourceView(ID3D12Resource* p_resource, D3D12MA::VirtualAllocation* p_allocation);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE Alloc_DepthStencilResourceView(ID3D12Resource* p_resource, D3D12MA::VirtualAllocation* p_allocation);
|
||||
|
||||
size_t m_size_for_placed_heap;
|
||||
/// @brief limit size that we define as acceptable. On 4 Mb it is enough for placing 1 Mb but higher it is bad. 1 Mb occupies 25% from 4 Mb
|
||||
/// and that means that m_size_limit_for_being_placed will be determined as 25% * m_size_for_placed_heap;
|
||||
size_t m_size_limit_for_being_placed;
|
||||
size_t m_size_srv_cbv_uav_descriptor;
|
||||
size_t m_size_rtv_descriptor;
|
||||
size_t m_size_dsv_descriptor;
|
||||
size_t m_fence_value;
|
||||
D3D12MA::Allocator* m_p_allocator;
|
||||
OffsetAllocator::Allocator* m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav;
|
||||
ID3D12Device* m_p_device;
|
||||
ID3D12GraphicsCommandList* m_p_copy_command_list;
|
||||
/// @brief command list from drawing
|
||||
ID3D12GraphicsCommandList* m_p_backend_command_list;
|
||||
ID3D12CommandAllocator* m_p_command_allocator;
|
||||
ID3D12DescriptorHeap* m_p_descriptor_heap_srv;
|
||||
ID3D12CommandQueue* m_p_copy_queue;
|
||||
ID3D12Fence* m_p_fence;
|
||||
HANDLE m_p_fence_event;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE* m_p_handle;
|
||||
RenderInterface_DX12* m_p_renderer;
|
||||
D3D12MA::VirtualBlock* m_p_virtual_block_for_render_target_heap_allocations;
|
||||
D3D12MA::VirtualBlock* m_p_virtual_block_for_depth_stencil_heap_allocations;
|
||||
ID3D12DescriptorHeap* m_p_descriptor_heap_rtv;
|
||||
ID3D12DescriptorHeap* m_p_descriptor_heap_dsv;
|
||||
#if RMLUI_RENDER_BACKEND_FIELD_STAGING_BUFFER_CACHE_ENABLED == 1
|
||||
D3D12MA::Allocation* m_p_upload_buffer;
|
||||
#endif
|
||||
Rml::Vector<D3D12MA::VirtualBlock*> m_blocks;
|
||||
Rml::Vector<ID3D12Heap*> m_heaps_placed;
|
||||
};
|
||||
|
||||
/*
|
||||
Manages render targets, including the layer stack and postprocessing framebuffers.
|
||||
|
||||
Layers can be pushed and popped, creating new framebuffers as needed. Typically, geometry is rendered to the top
|
||||
layer. The layer framebuffers may have MSAA enabled.
|
||||
|
||||
Postprocessing framebuffers are separate from the layers, and are commonly used to apply texture-wide effects
|
||||
such as filters. They are used both as input and output during rendering, and do not use MSAA.
|
||||
*/
|
||||
class RenderLayerStack : Rml::NonCopyMoveable {
|
||||
public:
|
||||
RenderLayerStack();
|
||||
~RenderLayerStack();
|
||||
|
||||
void Initialize(RenderInterface_DX12* p_owner);
|
||||
void Shutdown();
|
||||
// Push a new layer. All references to previously retrieved layers are invalidated.
|
||||
Rml::LayerHandle PushLayer();
|
||||
|
||||
// Pop the top layer. All references to previously retrieved layers are invalidated.
|
||||
void PopLayer();
|
||||
|
||||
const Gfx::FramebufferData& GetLayer(Rml::LayerHandle layer) const;
|
||||
const Gfx::FramebufferData& GetTopLayer() const;
|
||||
const Gfx::FramebufferData& Get_SharedDepthStencil_Layers();
|
||||
// const Gfx::FramebufferData& Get_SharedDepthStencil_Postprocess();
|
||||
Rml::LayerHandle GetTopLayerHandle() const;
|
||||
|
||||
const Gfx::FramebufferData& GetPostprocessPrimary() { return EnsureFramebufferPostprocess(0); }
|
||||
const Gfx::FramebufferData& GetPostprocessSecondary() { return EnsureFramebufferPostprocess(1); }
|
||||
const Gfx::FramebufferData& GetPostprocessTertiary() { return EnsureFramebufferPostprocess(2); }
|
||||
const Gfx::FramebufferData& GetBlendMask() { return EnsureFramebufferPostprocess(3); }
|
||||
|
||||
void SwapPostprocessPrimarySecondary();
|
||||
|
||||
void BeginFrame(int new_width, int new_height);
|
||||
void EndFrame();
|
||||
|
||||
private:
|
||||
void DestroyFramebuffers();
|
||||
const Gfx::FramebufferData& EnsureFramebufferPostprocess(int index);
|
||||
|
||||
void CreateFramebuffer(Gfx::FramebufferData* p_result, int width, int height, int sample_count, bool is_depth_stencil);
|
||||
void DestroyFramebuffer(Gfx::FramebufferData* p_data);
|
||||
|
||||
unsigned char m_msaa_sample_count;
|
||||
int m_width, m_height;
|
||||
// The number of active layers is manually tracked since we re-use the framebuffers stored in the fb_layers stack.
|
||||
int m_layers_size;
|
||||
TextureMemoryManager* m_p_manager_texture;
|
||||
BufferMemoryManager* m_p_manager_buffer;
|
||||
ID3D12Device* m_p_device;
|
||||
Rml::UniquePtr<Gfx::FramebufferData> m_p_depth_stencil_for_layers;
|
||||
Rml::Vector<Gfx::FramebufferData> m_fb_layers;
|
||||
Rml::Vector<Gfx::FramebufferData> m_fb_postprocess;
|
||||
};
|
||||
|
||||
public:
|
||||
RenderInterface_DX12(void* p_window_handle, const Backend::RmlRendererSettings& settings);
|
||||
~RenderInterface_DX12();
|
||||
|
||||
// Returns true if the renderer was successfully constructed.
|
||||
explicit operator bool() const;
|
||||
|
||||
// The viewport should be updated whenever the window size changes.
|
||||
void SetViewport(int viewport_width, int viewport_height);
|
||||
|
||||
// Sets up OpenGL states for taking rendering commands from RmlUi.
|
||||
void BeginFrame();
|
||||
// Draws the result to the backbuffer and restores OpenGL state.
|
||||
void EndFrame();
|
||||
|
||||
// Optional, can be used to clear the active framebuffer.
|
||||
void Clear();
|
||||
|
||||
// -- Inherited from Rml::RenderInterface --
|
||||
|
||||
Rml::CompiledGeometryHandle CompileGeometry(Rml::Span<const Rml::Vertex> vertices, Rml::Span<const int> indices) override;
|
||||
void RenderGeometry(Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation, Rml::TextureHandle texture) override;
|
||||
void ReleaseGeometry(Rml::CompiledGeometryHandle geometry) override;
|
||||
|
||||
void EnableScissorRegion(bool enable) override;
|
||||
void SetScissorRegion(Rml::Rectanglei region) override;
|
||||
|
||||
void EnableClipMask(bool enable) override;
|
||||
void RenderToClipMask(Rml::ClipMaskOperation mask_operation, Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation) override;
|
||||
|
||||
Rml::TextureHandle LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
|
||||
Rml::TextureHandle GenerateTexture(Rml::Span<const Rml::byte> source_data, Rml::Vector2i source_dimensions) override;
|
||||
void ReleaseTexture(Rml::TextureHandle texture_handle) override;
|
||||
|
||||
void SetTransform(const Rml::Matrix4f* transform) override;
|
||||
|
||||
Rml::LayerHandle PushLayer() override;
|
||||
void CompositeLayers(Rml::LayerHandle source, Rml::LayerHandle destination, Rml::BlendMode blend_mode,
|
||||
Rml::Span<const Rml::CompiledFilterHandle> filters) override;
|
||||
void PopLayer() override;
|
||||
|
||||
Rml::TextureHandle SaveLayerAsTexture() override;
|
||||
|
||||
Rml::CompiledFilterHandle SaveLayerAsMaskImage() override;
|
||||
|
||||
Rml::CompiledFilterHandle CompileFilter(const Rml::String& name, const Rml::Dictionary& parameters) override;
|
||||
void ReleaseFilter(Rml::CompiledFilterHandle filter) override;
|
||||
|
||||
Rml::CompiledShaderHandle CompileShader(const Rml::String& name, const Rml::Dictionary& parameters) override;
|
||||
void RenderShader(Rml::CompiledShaderHandle shader_handle, Rml::CompiledGeometryHandle geometry_handle, Rml::Vector2f translation,
|
||||
Rml::TextureHandle texture) override;
|
||||
void ReleaseShader(Rml::CompiledShaderHandle effect_handle) override;
|
||||
|
||||
// Can be passed to RenderGeometry() to enable texture rendering without changing the bound texture.
|
||||
static constexpr Rml::TextureHandle TextureEnableWithoutBinding = Rml::TextureHandle(-1);
|
||||
// Can be passed to RenderGeometry() to leave the bound texture and used program unchanged.
|
||||
static constexpr Rml::TextureHandle TexturePostprocess = Rml::TextureHandle(-2);
|
||||
|
||||
bool IsSwapchainValid() noexcept;
|
||||
void RecreateSwapchain() noexcept;
|
||||
|
||||
ID3D12Fence* Get_Fence();
|
||||
HANDLE Get_FenceEvent();
|
||||
Rml::Array<uint64_t, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT>& Get_FenceValues();
|
||||
uint32_t Get_CurrentFrameIndex();
|
||||
|
||||
ID3D12Device* Get_Device() const;
|
||||
TextureMemoryManager& Get_TextureManager();
|
||||
BufferMemoryManager& Get_BufferManager();
|
||||
|
||||
unsigned char Get_MSAASampleCount() const;
|
||||
|
||||
void Set_UserFramebufferIndex(unsigned char framebuffer_index);
|
||||
void Set_UserRenderTarget(void* rtv_where_we_render_to);
|
||||
void Set_UserDepthStencil(void* dsv_where_we_render_to);
|
||||
|
||||
bool CaptureScreen(int& width, int& height, int& num_components, Rml::UniquePtr<Rml::byte[]>& data);
|
||||
|
||||
private:
|
||||
void Initialize_Device() noexcept;
|
||||
void Initialize_Adapter() noexcept;
|
||||
void Initialize_DebugLayer() noexcept;
|
||||
|
||||
void Initialize_Swapchain(int width, int height) noexcept;
|
||||
void Initialize_SyncPrimitives() noexcept;
|
||||
void Initialize_SyncPrimitives_Screenshot() noexcept;
|
||||
void Initialize_CommandAllocators();
|
||||
|
||||
void Initialize_Allocator() noexcept;
|
||||
|
||||
void Destroy_Swapchain() noexcept;
|
||||
void Destroy_SyncPrimitives() noexcept;
|
||||
void Destroy_CommandAllocators() noexcept;
|
||||
void Destroy_CommandList() noexcept;
|
||||
void Destroy_Allocator() noexcept;
|
||||
void Destroy_SyncPrimitives_Screenshot() noexcept;
|
||||
|
||||
void Flush() noexcept;
|
||||
uint64_t Signal(uint32_t frame_index) noexcept;
|
||||
void WaitForFenceValue(uint32_t frame_index);
|
||||
|
||||
void Create_Resources_DependentOnSize() noexcept;
|
||||
void Destroy_Resources_DependentOnSize() noexcept;
|
||||
|
||||
ID3D12DescriptorHeap* Create_Resource_DescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags,
|
||||
uint32_t descriptor_count) noexcept;
|
||||
|
||||
ID3D12CommandAllocator* Create_CommandAllocator(D3D12_COMMAND_LIST_TYPE type);
|
||||
ID3D12GraphicsCommandList* Create_CommandList(ID3D12CommandAllocator* p_allocator, D3D12_COMMAND_LIST_TYPE type) noexcept;
|
||||
|
||||
ID3D12CommandQueue* Create_CommandQueue(D3D12_COMMAND_LIST_TYPE type) noexcept;
|
||||
|
||||
void Create_Resource_RenderTargetViews();
|
||||
void Destroy_Resource_RenderTagetViews();
|
||||
|
||||
void Destroy_Resource_For_Shaders();
|
||||
|
||||
void Create_Resource_Pipelines();
|
||||
void Create_Resource_Pipeline_Color();
|
||||
void Create_Resource_Pipeline_Texture();
|
||||
void Create_Resource_Pipeline_Gradient();
|
||||
void Create_Resource_Pipeline_Creation();
|
||||
void Create_Resource_Pipeline_Passthrough();
|
||||
void Create_Resource_Pipeline_Passthrough_NoBlend();
|
||||
void Create_Resource_Pipeline_ColorMatrix();
|
||||
void Create_Resource_Pipeline_BlendMask();
|
||||
void Create_Resource_Pipeline_Blur();
|
||||
void Create_Resource_Pipeline_DropShadow();
|
||||
|
||||
void Create_Resource_DepthStencil();
|
||||
void Destroy_Resource_DepthStencil();
|
||||
|
||||
void Destroy_Resource_Pipelines();
|
||||
|
||||
bool CheckTearingSupport() noexcept;
|
||||
|
||||
IDXGIAdapter* Get_Adapter(bool is_use_warp) noexcept;
|
||||
void PrintAdapterDesc(IDXGIAdapter* p_adapter);
|
||||
|
||||
void SetScissor(Rml::Rectanglei region, bool vertically_flip = false);
|
||||
|
||||
void SubmitTransformUniform(ConstantBufferType& constant_buffer, const Rml::Vector2f& translation);
|
||||
|
||||
void UseProgram(ProgramId pipeline_id);
|
||||
|
||||
ConstantBufferType* Get_ConstantBuffer(uint32_t current_back_buffer_index);
|
||||
|
||||
void Free_Geometry(GeometryHandleType* p_handle);
|
||||
void Free_Texture(TextureHandleType* p_handle);
|
||||
|
||||
void Update_PendingForDeletion_Geometry();
|
||||
|
||||
void BlitLayerToPostprocessPrimary(Rml::LayerHandle layer_id);
|
||||
|
||||
void RenderFilters(Rml::Span<const Rml::CompiledFilterHandle> filter_handles);
|
||||
void RenderBlur(float sigma, const Gfx::FramebufferData& source_destination, const Gfx::FramebufferData& temp,
|
||||
const Rml::Rectanglei window_flipped);
|
||||
|
||||
void DrawFullscreenQuad(ConstantBufferType* p_override_constant_buffer = nullptr);
|
||||
void DrawFullscreenQuad(Rml::Vector2f uv_offset, Rml::Vector2f uv_scaling = Rml::Vector2f(1.f),
|
||||
ConstantBufferType* p_override_constant_buffer = nullptr);
|
||||
|
||||
void BindTexture(TextureHandleType* p_texture, UINT root_parameter_index = 0);
|
||||
void BindRenderTarget(const Gfx::FramebufferData& framebuffer, bool depth_included = true);
|
||||
|
||||
void OverrideConstantBufferOfGeometry(Rml::CompiledGeometryHandle geometry, ConstantBufferType* p_override_constant_buffer);
|
||||
|
||||
// 1 means not supported
|
||||
// otherwise return max value of supported multisample count
|
||||
unsigned char GetMSAASupportedSampleCount(unsigned char max_samples);
|
||||
|
||||
void BlitFramebuffer(const Gfx::FramebufferData& source, const Gfx::FramebufferData& dest, int srcX0, int srcY0, int srcX1, int srcY1, int dstX0,
|
||||
int dstY0, int dstX1, int dstY1);
|
||||
|
||||
// debug only
|
||||
void ValidateTextureAllocationNotAsPlaced(const Gfx::FramebufferData& data);
|
||||
|
||||
ID3D12Resource* GetResourceFromFramebufferData(const Gfx::FramebufferData& data);
|
||||
|
||||
bool m_is_use_vsync;
|
||||
bool m_is_use_tearing;
|
||||
bool m_is_scissor_was_set;
|
||||
bool m_is_stencil_enabled;
|
||||
bool m_is_stencil_equal;
|
||||
bool m_is_use_msaa;
|
||||
bool m_is_execute_when_end_frame_issued;
|
||||
bool m_is_command_list_user;
|
||||
unsigned char m_msaa_sample_count;
|
||||
unsigned char m_user_framebuffer_index;
|
||||
// Current viewport's width
|
||||
int m_width;
|
||||
// Current viewport's height
|
||||
int m_height;
|
||||
int m_current_clip_operation;
|
||||
ProgramId m_active_program_id;
|
||||
Rml::Rectanglei m_scissor;
|
||||
uint32_t m_size_descriptor_heap_render_target_view;
|
||||
uint32_t m_size_descriptor_heap_shaders;
|
||||
UINT m_current_back_buffer_index;
|
||||
UINT m_stencil_ref_value;
|
||||
// For debug builds: D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, otherwise 0.
|
||||
UINT m_default_shader_flags;
|
||||
ID3D12Device* m_p_device;
|
||||
ID3D12CommandQueue* m_p_command_queue;
|
||||
ID3D12CommandQueue* m_p_copy_queue;
|
||||
IDXGISwapChain4* m_p_swapchain;
|
||||
ID3D12GraphicsCommandList* m_p_command_graphics_list;
|
||||
ID3D12GraphicsCommandList* m_p_command_graphics_list_screenshot;
|
||||
ID3D12CommandAllocator* m_p_command_allocator_screenshot;
|
||||
ID3D12DescriptorHeap* m_p_descriptor_heap_render_target_view;
|
||||
ID3D12DescriptorHeap* m_p_descriptor_heap_render_target_view_for_texture_manager;
|
||||
ID3D12DescriptorHeap* m_p_descriptor_heap_depth_stencil_view_for_texture_manager;
|
||||
// cbv; srv; uav; all in one
|
||||
ID3D12DescriptorHeap* m_p_descriptor_heap_shaders;
|
||||
ID3D12DescriptorHeap* m_p_descriptor_heap_depthstencil;
|
||||
D3D12MA::Allocation* m_p_depthstencil_resource;
|
||||
ID3D12Fence* m_p_backbuffer_fence;
|
||||
ID3D12Fence* m_p_fence_screenshot;
|
||||
IDXGIAdapter* m_p_adapter;
|
||||
|
||||
ID3D12PipelineState* m_pipelines[NumPrograms];
|
||||
ID3D12RootSignature* m_root_signatures[NumPrograms];
|
||||
|
||||
ID3D12CommandAllocator* m_p_copy_allocator;
|
||||
ID3D12GraphicsCommandList* m_p_copy_command_list;
|
||||
|
||||
D3D12MA::Allocator* m_p_allocator;
|
||||
OffsetAllocator::Allocator* m_p_offset_allocator_for_descriptor_heap_shaders;
|
||||
// where user wants to render rmlui final image
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE* m_p_user_rtv_present;
|
||||
// as well as rtv just dsv
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE* m_p_user_dsv_present;
|
||||
HWND m_p_window_handle;
|
||||
HANDLE m_p_fence_event;
|
||||
HANDLE m_p_fence_event_screenshot;
|
||||
uint64_t m_fence_value;
|
||||
uint64_t m_fence_screenshot_value;
|
||||
Rml::CompiledGeometryHandle m_precompiled_fullscreen_quad_geometry;
|
||||
|
||||
Rml::Array<ID3D12Resource*, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT> m_backbuffers_resources;
|
||||
Rml::Array<ID3D12CommandAllocator*, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT> m_backbuffers_allocators;
|
||||
Rml::Array<uint64_t, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT> m_backbuffers_fence_values;
|
||||
Rml::Array<size_t, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT> m_constant_buffer_count_per_frame;
|
||||
Rml::Array<size_t, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT> m_vertex_and_index_buffer_count_per_frame;
|
||||
// per object (per draw)
|
||||
Rml::Array<Rml::Vector<ConstantBufferType>, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT> m_constantbuffers;
|
||||
Rml::Vector<GeometryHandleType*> m_pending_for_deletion_geometry;
|
||||
|
||||
DXGI_SAMPLE_DESC m_desc_sample;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE m_handle_shaders;
|
||||
BufferMemoryManager m_manager_buffer;
|
||||
TextureMemoryManager m_manager_texture;
|
||||
Rml::Matrix4f m_constant_buffer_data_transform;
|
||||
Rml::Matrix4f m_constant_buffer_data_projection;
|
||||
Rml::Matrix4f m_projection;
|
||||
RenderLayerStack m_manager_render_layer;
|
||||
};
|
||||
|
||||
namespace Backend {
|
||||
struct RmlRendererSettings {
|
||||
bool vsync;
|
||||
unsigned char msaa_sample_count;
|
||||
};
|
||||
} // namespace Backend
|
||||
Reference in New Issue
Block a user