697 lines
28 KiB
C++
697 lines
28 KiB
C++
#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
|