9996 lines
363 KiB
C++
9996 lines
363 KiB
C++
#include "RmlUi_Renderer_DX12.h"
|
|
#include "RmlUi_Backend.h"
|
|
#include <RmlUi/Core/Core.h>
|
|
#include <RmlUi/Core/DecorationTypes.h>
|
|
#include <RmlUi/Core/FileInterface.h>
|
|
#include <RmlUi/Core/Log.h>
|
|
#include <RmlUi/Core/Mesh.h>
|
|
#include <RmlUi/Core/MeshUtilities.h>
|
|
#include <RmlUi/Core/Platform.h>
|
|
#include <RmlUi/Core/Profiling.h>
|
|
#include <algorithm>
|
|
#include <string.h>
|
|
|
|
#ifndef RMLUI_PLATFORM_WIN32
|
|
#error unable to compile platform specific renderer required Windows OS that support DirectX-12
|
|
#endif
|
|
|
|
#ifdef RMLUI_DEBUG
|
|
#define RMLUI_ATTR_ASSERT_VARIABLE
|
|
#else
|
|
#define RMLUI_ATTR_ASSERT_VARIABLE [[maybe_unused]]
|
|
#endif
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
#include <d3d12sdklayers.h>
|
|
#include <dxgidebug.h>
|
|
#endif
|
|
|
|
/// @brief in bytes see pShaderSourceText_Vertex - > cbuffer ConstantBuffer : register(b0)
|
|
static constexpr uint32_t kAllocationSize_ConstantBuffer_Vertex_Main = 72;
|
|
|
|
/// @brief in bytes see pShaderSourceText_Vertex_Blur - > cbuffer SharedConstantBuffer : register(b0)
|
|
static constexpr uint32_t kAllocationSize_ConstantBuffer_Vertex_Blur = 96;
|
|
|
|
static constexpr uint32_t kAllocationSize_ConstantBuffer_Pixel_Gradient = 416;
|
|
|
|
/// @brief generally saying it is not universal approach but for keeping things not so much complex better to specify max amount of constantbuffer
|
|
/// that's enough to satisfy all shaders otherwise better to use only those which size is required for allocation
|
|
static constexpr uint32_t kAllocationSizeMax_ConstantBuffer =
|
|
std::max({kAllocationSize_ConstantBuffer_Vertex_Main, kAllocationSize_ConstantBuffer_Vertex_Blur, kAllocationSize_ConstantBuffer_Pixel_Gradient});
|
|
|
|
#define MAX_NUM_STOPS 16
|
|
#define BLUR_SIZE 7
|
|
#define BLUR_NUM_WEIGHTS ((BLUR_SIZE + 1) / 2)
|
|
|
|
#define RMLUI_STRINGIFY_IMPL(x) #x
|
|
#define RMLUI_STRINGIFY(x) RMLUI_STRINGIFY_IMPL(x)
|
|
|
|
static constexpr const char pShaderSourceText_Color[] = R"(
|
|
struct VS_INPUT
|
|
{
|
|
float4 pos : SV_Position;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD;
|
|
};
|
|
|
|
float4 main(const VS_INPUT IN) : SV_TARGET
|
|
{
|
|
return IN.color;
|
|
}
|
|
)";
|
|
|
|
// main
|
|
static constexpr const char pShaderSourceText_Vertex[] = R"(
|
|
struct VS_INPUT
|
|
{
|
|
float2 position : POSITION;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD;
|
|
};
|
|
|
|
struct PS_OUTPUT
|
|
{
|
|
float4 position : SV_Position;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD;
|
|
};
|
|
|
|
cbuffer ConstantBuffer : register(b0)
|
|
{
|
|
float4x4 m_transform;
|
|
float2 m_translate;
|
|
};
|
|
|
|
PS_OUTPUT main(const VS_INPUT IN)
|
|
{
|
|
PS_OUTPUT OUT;
|
|
|
|
float2 translatedPos = IN.position + m_translate;
|
|
float4 resPos = mul(m_transform, float4(translatedPos.x, translatedPos.y, 0.0, 1.0));
|
|
|
|
OUT.position = resPos;
|
|
OUT.color = IN.color;
|
|
OUT.uv = IN.uv;
|
|
|
|
return OUT;
|
|
};
|
|
)";
|
|
|
|
static constexpr const char pShaderSourceText_Texture[] = R"(
|
|
struct VS_INPUT
|
|
{
|
|
float4 pos : SV_Position;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD;
|
|
};
|
|
|
|
Texture2D g_InputTexture : register(t0);
|
|
|
|
SamplerState g_SamplerLinear : register(s0);
|
|
|
|
|
|
float4 main(const VS_INPUT IN) : SV_TARGET
|
|
{
|
|
return IN.color * g_InputTexture.Sample(g_SamplerLinear, IN.uv);
|
|
}
|
|
)";
|
|
|
|
static constexpr const char pShaderSourceText_Vertex_PassThrough[] = R"(
|
|
struct VS_INPUT
|
|
{
|
|
float2 position : POSITION;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD;
|
|
};
|
|
|
|
struct PS_OUTPUT
|
|
{
|
|
float4 position : SV_Position;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD;
|
|
};
|
|
|
|
PS_OUTPUT main(const VS_INPUT IN)
|
|
{
|
|
PS_OUTPUT OUT;
|
|
OUT.position = float4(IN.position.x, IN.position.y, 0.0f, 1.0f);
|
|
OUT.color = IN.color;
|
|
// need to flip here since Rml::MeshUtilities::GenerateQuad makes valid data for GL APIs but on DirectX
|
|
// it is not valid UV (otherwise image will be flipped)
|
|
OUT.uv = float2(IN.uv.x, 1.0f - IN.uv.y);
|
|
|
|
return OUT;
|
|
}
|
|
)";
|
|
|
|
static constexpr const char pShaderSourceText_Pixel_Passthrough[] = R"(
|
|
struct PS_INPUT
|
|
{
|
|
float4 pos : SV_Position;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD;
|
|
};
|
|
|
|
Texture2D g_InputTexture : register(t0);
|
|
|
|
SamplerState g_SamplerLinear : register(s0);
|
|
|
|
|
|
float4 main(const PS_INPUT inputArgs) : SV_TARGET
|
|
{
|
|
return g_InputTexture.Sample(g_SamplerLinear, inputArgs.uv);
|
|
}
|
|
)";
|
|
|
|
#define RMLUI_SHADER_HEADER "#define MAX_NUM_STOPS " RMLUI_STRINGIFY(MAX_NUM_STOPS) "\n#line " RMLUI_STRINGIFY(__LINE__) "\n"
|
|
|
|
#define RMLUI_SHADER_BLUR_HEADER \
|
|
RMLUI_SHADER_HEADER "\n#define BLUR_SIZE " RMLUI_STRINGIFY(BLUR_SIZE) "\n#define BLUR_NUM_WEIGHTS " RMLUI_STRINGIFY(BLUR_NUM_WEIGHTS)
|
|
|
|
static constexpr const char pShaderSourceText_Vertex_Blur[] = RMLUI_SHADER_BLUR_HEADER R"(
|
|
struct VS_INPUT
|
|
{
|
|
float2 position : POSITION;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD;
|
|
};
|
|
|
|
struct PS_INPUT
|
|
{
|
|
float4 position : SV_Position;
|
|
float2 uv[BLUR_SIZE] : TEXCOORD;
|
|
};
|
|
|
|
cbuffer SharedConstantBuffer : register(b0)
|
|
{
|
|
float4x4 m_transform;
|
|
float2 m_translate;
|
|
float2 m_texelOffset;
|
|
float4 m_weights;
|
|
float2 m_texCoordMin;
|
|
float2 m_texCoordMax;
|
|
};
|
|
|
|
PS_INPUT main(const VS_INPUT IN)
|
|
{
|
|
PS_INPUT result = (PS_INPUT)0;
|
|
|
|
for (int i = 0; i < BLUR_SIZE; i++) {
|
|
result.uv[i] = IN.uv - float(i - BLUR_NUM_WEIGHTS + 1) * m_texelOffset;
|
|
}
|
|
result.position = float4(IN.position.xy, 1.0, 1.0);
|
|
|
|
return result;
|
|
};
|
|
)";
|
|
|
|
static constexpr const char pShaderSourceText_Pixel_Blur[] = RMLUI_SHADER_BLUR_HEADER R"(
|
|
Texture2D g_InputTexture : register(t0);
|
|
SamplerState g_SamplerLinear : register(s0);
|
|
|
|
cbuffer SharedConstantBuffer : register(b0)
|
|
{
|
|
float4x4 m_transform;
|
|
float2 m_translate;
|
|
float2 m_texelOffset;
|
|
float4 m_weights;
|
|
float2 m_texCoordMin;
|
|
float2 m_texCoordMax;
|
|
};
|
|
|
|
struct PS_INPUT
|
|
{
|
|
float4 position : SV_Position;
|
|
float2 uv[BLUR_SIZE] : TEXCOORD;
|
|
};
|
|
|
|
float4 main(const PS_INPUT IN) : SV_TARGET
|
|
{
|
|
float4 color = float4(0.0, 0.0, 0.0, 0.0);
|
|
for(int i = 0; i < BLUR_SIZE; i++)
|
|
{
|
|
float2 in_region = step(m_texCoordMin, IN.uv[i]) * step(IN.uv[i], m_texCoordMax);
|
|
color += g_InputTexture.Sample(g_SamplerLinear, float2(IN.uv[i].x, 1.0f - IN.uv[i].y)) * in_region.x * in_region.y * m_weights[abs(i - BLUR_NUM_WEIGHTS + 1)];
|
|
}
|
|
return color;
|
|
};
|
|
)";
|
|
|
|
static constexpr const char pShaderSourceText_Pixel_DropShadow[] = R"(
|
|
Texture2D g_InputTexture : register(t0);
|
|
SamplerState g_SamplerLinear : register(s0);
|
|
|
|
cbuffer DropShadowBuffer : register(b0)
|
|
{
|
|
float2 m_texCoordMin;
|
|
float2 m_texCoordMax;
|
|
float4 m_color;
|
|
};
|
|
|
|
struct PS_INPUT
|
|
{
|
|
float4 position : SV_Position;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD;
|
|
};
|
|
|
|
float4 main(const PS_INPUT IN) : SV_TARGET
|
|
{
|
|
float2 in_region = step(m_texCoordMin, IN.uv) * step(IN.uv, m_texCoordMax);
|
|
return g_InputTexture.Sample(g_SamplerLinear, IN.uv).a * in_region.x * in_region.y * m_color;
|
|
};
|
|
)";
|
|
|
|
static constexpr const char pShaderSourceTet_Pixel_ColorMatrix[] = RMLUI_SHADER_HEADER R"(
|
|
|
|
Texture2D g_InputTexture : register(t0);
|
|
SamplerState g_SamplerLinear : register(s0);
|
|
|
|
cbuffer ConstantBuffer : register(b0)
|
|
{
|
|
float4x4 m_color_matrix;
|
|
};
|
|
|
|
struct PS_Input
|
|
{
|
|
float4 position : SV_Position;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD;
|
|
};
|
|
|
|
float4 main(const PS_Input IN) : SV_TARGET
|
|
{
|
|
// The general case uses a 4x5 color matrix for full rgba transformation, plus a constant term with the last column.
|
|
// However, we only consider the case of rgb transformations. Thus, we could in principle use a 3x4 matrix, but we
|
|
// keep the alpha row for simplicity.
|
|
// In the general case we should do the matrix transformation in non-premultiplied space. However, without alpha
|
|
// transformations, we can do it directly in premultiplied space to avoid the extra division and multiplication
|
|
// steps. In this space, the constant term needs to be multiplied by the alpha value, instead of unity.
|
|
float4 texColor = g_InputTexture.Sample(g_SamplerLinear, IN.uv);
|
|
float3 transformedColor = mul(m_color_matrix, texColor).rgb;
|
|
return float4(transformedColor, texColor.a);
|
|
};
|
|
)";
|
|
|
|
static constexpr const char pShaderSourceText_Pixel_BlendMask[] = RMLUI_SHADER_HEADER R"(
|
|
Texture2D g_InputTexture : register(t0);
|
|
|
|
Texture2D g_MaskTexture : register(t1);
|
|
|
|
SamplerState g_SamplerLinear : register(s0);
|
|
|
|
struct PS_INPUT
|
|
{
|
|
float4 position : SV_Position;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD;
|
|
};
|
|
|
|
float4 main(const PS_INPUT IN) : SV_TARGET
|
|
{
|
|
float4 texColor = g_InputTexture.Sample(g_SamplerLinear, IN.uv);
|
|
float maskAlpha = g_MaskTexture.Sample(g_SamplerLinear, IN.uv).a;
|
|
return texColor * maskAlpha;
|
|
};
|
|
)";
|
|
|
|
// We need to round up at compile-time so that we can address each element of the float4's
|
|
#define CEILING(x, y) (((x) + (y) - 1) / (y))
|
|
static const char pShaderSourceText_Pixel_Gradient[] =
|
|
RMLUI_SHADER_HEADER "#define MAX_NUM_STOPS_PACKED (uint)" RMLUI_STRINGIFY(CEILING(MAX_NUM_STOPS, 4)) R"(
|
|
#define LINEAR 0
|
|
#define RADIAL 1
|
|
#define CONIC 2
|
|
#define REPEATING_LINEAR 3
|
|
#define REPEATING_RADIAL 4
|
|
#define REPEATING_CONIC 5
|
|
#define PI 3.14159265
|
|
|
|
cbuffer SharedConstantBuffer : register(b0)
|
|
{
|
|
float4x4 m_transform;
|
|
float2 m_translate;
|
|
|
|
// One to one translation of the OpenGL uniforms results in a LOT of wasted space due to CBuffer alignment rules.
|
|
// Changes from GL3:
|
|
// - Moved m_num_stops below m_func (saved 4 bytes of padding).
|
|
// - Packed m_stop_positions into a float4[MAX_NUM_STOPS / 4] array, as each array element starts a new 16-byte row.
|
|
// The below layout has 0 bytes of padding.
|
|
|
|
int m_func; // one of the above definitions
|
|
int m_num_stops;
|
|
float2 m_p; // linear: starting point, radial: center, conic: center
|
|
float2 m_v; // linear: vector to ending point, radial: 2d curvature (inverse radius), conic: angled unit vector
|
|
float4 m_stop_colors[MAX_NUM_STOPS];
|
|
float4 m_stop_positions[MAX_NUM_STOPS_PACKED]; // normalized, 0 -> starting point, 1 -> ending point
|
|
};
|
|
|
|
// Hide the way the data is packed in the cbuffer through a macro
|
|
// @NOTE: Hardcoded for MAX_NUM_STOPS 16.
|
|
// i >> 2 => i >> sqrt(MAX_NUM_STOPS)
|
|
#define GET_STOP_POS(i) (m_stop_positions[i >> 2][i & 3])
|
|
|
|
struct PS_INPUT
|
|
{
|
|
float4 position : SV_Position;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD;
|
|
};
|
|
|
|
#define glsl_mod(x,y) (((x)-(y)*floor((x)/(y))))
|
|
|
|
float4 lerp_stop_colors(float t) {
|
|
float4 color = m_stop_colors[0];
|
|
|
|
for (int i = 1; i < m_num_stops; i++)
|
|
color = lerp(color, m_stop_colors[i], smoothstep(GET_STOP_POS(i-1), GET_STOP_POS(i), t));
|
|
|
|
return color;
|
|
};
|
|
|
|
float4 main(const PS_INPUT IN) : SV_TARGET
|
|
{
|
|
float t = 0.0;
|
|
|
|
if (m_func == LINEAR || m_func == REPEATING_LINEAR) {
|
|
float dist_square = dot(m_v, m_v);
|
|
float2 V = IN.uv.xy - m_p;
|
|
t = dot(m_v, V) / dist_square;
|
|
}
|
|
else if (m_func == RADIAL || m_func == REPEATING_RADIAL) {
|
|
float2 V = IN.uv.xy - m_p;
|
|
t = length(m_v * V);
|
|
}
|
|
else if (m_func == CONIC || m_func == REPEATING_CONIC) {
|
|
float2x2 R = float2x2(m_v.x, -m_v.y, m_v.y, m_v.x);
|
|
float2 V = mul((IN.uv.xy - m_p), R);
|
|
t = 0.5 + atan2(-V.x, V.y) / (2.0 * PI);
|
|
}
|
|
|
|
if (m_func == REPEATING_LINEAR || m_func == REPEATING_RADIAL || m_func == REPEATING_CONIC) {
|
|
float t0 = GET_STOP_POS(0);
|
|
float t1 = GET_STOP_POS(m_num_stops - 1);
|
|
t = t0 + glsl_mod(t - t0, t1 - t0);
|
|
}
|
|
|
|
return IN.color * lerp_stop_colors(t);
|
|
};
|
|
)";
|
|
|
|
static constexpr const char pShaderSourceText_Pixel_Creation[] = RMLUI_SHADER_HEADER R"(
|
|
struct PS_Input
|
|
{
|
|
float4 position : SV_Position;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD;
|
|
};
|
|
|
|
cbuffer SharedConstantBuffer : register(b0)
|
|
{
|
|
float4x4 m_transform;
|
|
float2 m_translate;
|
|
float2 m_dimensions;
|
|
float m_value;
|
|
};
|
|
|
|
#define glsl_mod(x,y) (((x)-(y)*floor((x)/(y))))
|
|
|
|
float4 main(const PS_Input IN) : SV_TARGET
|
|
{
|
|
float t = m_value;
|
|
float3 c;
|
|
float l;
|
|
for (int i = 0; i < 3; i++) {
|
|
float2 p = IN.uv;
|
|
float2 uv = p;
|
|
p -= .5;
|
|
p.x *= m_dimensions.x / m_dimensions.y;
|
|
float z = t + ((float)i) * .07;
|
|
l = length(p);
|
|
uv += p / l * (sin(z) + 1.) * abs(sin(l * 9. - z - z));
|
|
c[i] = .01 / length(glsl_mod(uv, 1.) - .5);
|
|
}
|
|
return float4(c / l, IN.color.a);
|
|
};
|
|
)";
|
|
|
|
// AlignUp(314, 256) = 512
|
|
template <typename T>
|
|
static T AlignUp(T val, T alignment)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - AlignUp");
|
|
return (val + alignment - (T)1) & ~(alignment - (T)1);
|
|
}
|
|
|
|
static Rml::Colourf ConvertToColorf(Rml::ColourbPremultiplied c0)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - ConvertToColorf");
|
|
Rml::Colourf result;
|
|
for (int i = 0; i < 4; i++)
|
|
result[i] = (1.f / 255.f) * float(c0[i]);
|
|
return result;
|
|
}
|
|
|
|
/// Flip vertical axis of the rectangle, and move its origin to the vertically opposite side of the viewport.
|
|
/// @note Changes coordinate system from RmlUi to OpenGL, or equivalently in reverse.
|
|
/// @note The Rectangle::Top and Rectangle::Bottom members will have reverse meaning in the returned rectangle.
|
|
static Rml::Rectanglei VerticallyFlipped(Rml::Rectanglei rect, int viewport_height)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - VerticallyFlipped");
|
|
RMLUI_ASSERT(rect.Valid());
|
|
Rml::Rectanglei flipped_rect = rect;
|
|
flipped_rect.p0.y = viewport_height - rect.p1.y;
|
|
flipped_rect.p1.y = viewport_height - rect.p0.y;
|
|
return flipped_rect;
|
|
}
|
|
|
|
static void SetBlurWeights(Rml::Vector4f& p_weights, float sigma)
|
|
{
|
|
float weights[BLUR_NUM_WEIGHTS];
|
|
float normalization = 0.0f;
|
|
for (int i = 0; i < BLUR_NUM_WEIGHTS; i++)
|
|
{
|
|
if (Rml::Math::Absolute(sigma) < 0.1f)
|
|
weights[i] = float(i == 0);
|
|
else
|
|
weights[i] = Rml::Math::Exp(-float(i * i) / (2.0f * sigma * sigma)) / (Rml::Math::SquareRoot(2.f * Rml::Math::RMLUI_PI) * sigma);
|
|
|
|
normalization += (i == 0 ? 1.f : 2.0f) * weights[i];
|
|
}
|
|
for (int i = 0; i < BLUR_NUM_WEIGHTS; i++)
|
|
weights[i] /= normalization;
|
|
|
|
p_weights.x = weights[0];
|
|
p_weights.y = weights[1];
|
|
p_weights.z = weights[2];
|
|
p_weights.w = weights[3];
|
|
}
|
|
|
|
static void SetTexCoordLimits(Rml::Vector2f& p_tex_coord_min, Rml::Vector2f& p_tex_coord_max, Rml::Rectanglei rectangle_flipped,
|
|
Rml::Vector2i framebuffer_size)
|
|
{
|
|
// Offset by half-texel values so that texture lookups are clamped to fragment centers, thereby avoiding color
|
|
// bleeding from neighboring texels due to bilinear interpolation.
|
|
const Rml::Vector2f min = (Rml::Vector2f(rectangle_flipped.p0) + Rml::Vector2f(0.5f)) / Rml::Vector2f(framebuffer_size);
|
|
const Rml::Vector2f max = (Rml::Vector2f(rectangle_flipped.p1) - Rml::Vector2f(0.5f)) / Rml::Vector2f(framebuffer_size);
|
|
|
|
p_tex_coord_min.x = min.x;
|
|
p_tex_coord_min.y = min.y;
|
|
p_tex_coord_max.x = max.x;
|
|
p_tex_coord_max.y = max.y;
|
|
}
|
|
|
|
/// Helper function from the d3dx12 header (MIT License - Microsoft). We avoid the full header for lightness.
|
|
/// https://github.com/microsoft/DirectX-Graphics-Samples/blob/71f3c57648b6cecde532f67dccd07265485e2313/TechniqueDemos/D3D12MemoryManagement/src/d3dx12.h#L1761C5-L1762C43)
|
|
inline UINT64 GetRequiredIntermediateSize(_In_ ID3D12Resource* pDestinationResource, _In_range_(0, D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
|
|
_In_range_(0, D3D12_REQ_SUBRESOURCES - FirstSubresource) UINT NumSubresources)
|
|
{
|
|
D3D12_RESOURCE_DESC Desc = pDestinationResource->GetDesc();
|
|
UINT64 RequiredSize = 0;
|
|
|
|
ID3D12Device* pDevice = nullptr;
|
|
pDestinationResource->GetDevice(__uuidof(*pDevice), reinterpret_cast<void**>(&pDevice));
|
|
pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, 0, nullptr, nullptr, nullptr, &RequiredSize);
|
|
pDevice->Release();
|
|
|
|
return RequiredSize;
|
|
}
|
|
|
|
/// Helper function from the d3dx12 header (MIT License, Microsoft). We avoid the full header for lightness.
|
|
/// https://github.com/microsoft/DirectX-Graphics-Samples/blob/71f3c57648b6cecde532f67dccd07265485e2313/TechniqueDemos/D3D12MemoryManagement/src/d3dx12.h#L1740
|
|
inline void MemcpySubresource(const _In_ D3D12_MEMCPY_DEST* pDest, const _In_ D3D12_SUBRESOURCE_DATA* pSrc, SIZE_T RowSizeInBytes, UINT NumRows,
|
|
UINT NumSlices)
|
|
{
|
|
if (!pSrc)
|
|
return;
|
|
|
|
if (!pSrc->pData)
|
|
return;
|
|
|
|
if (!pDest)
|
|
return;
|
|
|
|
for (UINT z = 0; z < NumSlices; ++z)
|
|
{
|
|
BYTE* pDestSlice = reinterpret_cast<BYTE*>(pDest->pData) + pDest->SlicePitch * z;
|
|
const BYTE* pSrcSlice = reinterpret_cast<const BYTE*>(pSrc->pData) + pSrc->SlicePitch * z;
|
|
for (UINT y = 0; y < NumRows; ++y)
|
|
{
|
|
memcpy(pDestSlice + pDest->RowPitch * y, pSrcSlice + pSrc->RowPitch * y, RowSizeInBytes);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Helper function from the d3dx12 header (MIT License, Microsoft). We avoid the full header for lightness.
|
|
/// https://github.com/microsoft/DirectX-Graphics-Samples/blob/71f3c57648b6cecde532f67dccd07265485e2313/TechniqueDemos/D3D12MemoryManagement/src/d3dx12.h#L1780C15-L1780C33
|
|
inline UINT64 UpdateSubresources(_In_ ID3D12GraphicsCommandList* pCmdList, _In_ ID3D12Resource* pDestinationResource,
|
|
_In_ ID3D12Resource* pIntermediate, _In_range_(0, D3D12_REQ_SUBRESOURCES) UINT FirstSubresource,
|
|
_In_range_(0, D3D12_REQ_SUBRESOURCES - FirstSubresource) UINT NumSubresources, UINT64 RequiredSize,
|
|
_In_reads_(NumSubresources) const D3D12_PLACED_SUBRESOURCE_FOOTPRINT* pLayouts, _In_reads_(NumSubresources) const UINT* pNumRows,
|
|
_In_reads_(NumSubresources) const UINT64* pRowSizesInBytes, _In_reads_(NumSubresources) const D3D12_SUBRESOURCE_DATA* pSrcData)
|
|
{
|
|
// Minor validation
|
|
D3D12_RESOURCE_DESC IntermediateDesc = pIntermediate->GetDesc();
|
|
D3D12_RESOURCE_DESC DestinationDesc = pDestinationResource->GetDesc();
|
|
if (IntermediateDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER || IntermediateDesc.Width < RequiredSize + pLayouts[0].Offset ||
|
|
RequiredSize > (SIZE_T)-1 ||
|
|
(DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER && (FirstSubresource != 0 || NumSubresources != 1)))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
BYTE* pData;
|
|
HRESULT hr = pIntermediate->Map(0, NULL, reinterpret_cast<void**>(&pData));
|
|
if (FAILED(hr))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
for (UINT i = 0; i < NumSubresources; ++i)
|
|
{
|
|
if (pRowSizesInBytes[i] > (SIZE_T)-1)
|
|
return 0;
|
|
D3D12_MEMCPY_DEST DestData = {pData + pLayouts[i].Offset, pLayouts[i].Footprint.RowPitch, pLayouts[i].Footprint.RowPitch * pNumRows[i]};
|
|
MemcpySubresource(&DestData, &pSrcData[i], (SIZE_T)pRowSizesInBytes[i], pNumRows[i], pLayouts[i].Footprint.Depth);
|
|
}
|
|
pIntermediate->Unmap(0, NULL);
|
|
|
|
if (DestinationDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
|
|
{
|
|
D3D12_BOX SrcBox;
|
|
SrcBox.left = UINT(pLayouts[0].Offset);
|
|
SrcBox.right = UINT(pLayouts[0].Offset + pLayouts[0].Footprint.Width);
|
|
SrcBox.top = 0;
|
|
SrcBox.front = 0;
|
|
SrcBox.bottom = 1;
|
|
SrcBox.back = 1;
|
|
|
|
pCmdList->CopyBufferRegion(pDestinationResource, 0, pIntermediate, pLayouts[0].Offset, pLayouts[0].Footprint.Width);
|
|
}
|
|
else
|
|
{
|
|
for (UINT i = 0; i < NumSubresources; ++i)
|
|
{
|
|
D3D12_TEXTURE_COPY_LOCATION Dst;
|
|
Dst.pResource = pDestinationResource;
|
|
Dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
Dst.SubresourceIndex = i + FirstSubresource;
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION Src;
|
|
Src.pResource = pIntermediate;
|
|
Src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
|
Src.PlacedFootprint = pLayouts[i];
|
|
|
|
pCmdList->CopyTextureRegion(&Dst, 0, 0, 0, &Src, nullptr);
|
|
}
|
|
}
|
|
|
|
return RequiredSize;
|
|
}
|
|
|
|
/// stack-allocating
|
|
/// Helper function from the d3dx12 header (MIT License, Microsoft). We avoid the full header for lightness.
|
|
/// https://github.com/microsoft/DirectX-Graphics-Samples/blob/71f3c57648b6cecde532f67dccd07265485e2313/TechniqueDemos/D3D12MemoryManagement/src/d3dx12.h#L1876
|
|
template <UINT MaxSubresources>
|
|
inline UINT64 UpdateSubresources(_In_ ID3D12GraphicsCommandList* pCmdList, _In_ ID3D12Resource* pDestinationResource,
|
|
_In_ ID3D12Resource* pIntermediate, UINT64 IntermediateOffset, _In_range_(0, MaxSubresources) UINT FirstSubresource,
|
|
_In_range_(1, MaxSubresources - FirstSubresource) UINT NumSubresources, _In_reads_(NumSubresources) D3D12_SUBRESOURCE_DATA* pSrcData)
|
|
{
|
|
UINT64 RequiredSize = 0;
|
|
D3D12_PLACED_SUBRESOURCE_FOOTPRINT Layouts[MaxSubresources];
|
|
UINT NumRows[MaxSubresources];
|
|
UINT64 RowSizesInBytes[MaxSubresources];
|
|
|
|
D3D12_RESOURCE_DESC Desc = pDestinationResource->GetDesc();
|
|
ID3D12Device* pDevice = nullptr;
|
|
pDestinationResource->GetDevice(__uuidof(*pDevice), reinterpret_cast<void**>(&pDevice));
|
|
pDevice->GetCopyableFootprints(&Desc, FirstSubresource, NumSubresources, IntermediateOffset, Layouts, NumRows, RowSizesInBytes, &RequiredSize);
|
|
pDevice->Release();
|
|
|
|
return UpdateSubresources(pCmdList, pDestinationResource, pIntermediate, FirstSubresource, NumSubresources, RequiredSize, Layouts, NumRows,
|
|
RowSizesInBytes, pSrcData);
|
|
}
|
|
|
|
enum class ShaderGradientFunction { Linear, Radial, Conic, RepeatingLinear, RepeatingRadial, RepeatingConic }; // Must match shader definitions below.
|
|
|
|
enum class FilterType { Invalid = 0, Passthrough, Blur, DropShadow, ColorMatrix, MaskImage };
|
|
struct CompiledFilter {
|
|
FilterType type;
|
|
|
|
// Passthrough
|
|
float blend_factor;
|
|
|
|
// Blur
|
|
float sigma;
|
|
|
|
// Drop shadow
|
|
Rml::Vector2f offset;
|
|
Rml::ColourbPremultiplied color;
|
|
|
|
// ColorMatrix
|
|
Rml::Matrix4f color_matrix;
|
|
};
|
|
|
|
enum class CompiledShaderType { Invalid = 0, Gradient, Creation };
|
|
struct CompiledShader {
|
|
CompiledShaderType type;
|
|
|
|
// Gradient
|
|
ShaderGradientFunction gradient_function;
|
|
Rml::Vector2f p;
|
|
Rml::Vector2f v;
|
|
Rml::Vector<float> stop_positions;
|
|
Rml::Vector<Rml::Colourf> stop_colors;
|
|
|
|
// Shader
|
|
Rml::Vector2f dimensions;
|
|
};
|
|
|
|
// those programs that have postfix as _MSAA it means that it accepts render target with sample count >= 2 (thus it is called MSAA)
|
|
enum class ProgramId : int {
|
|
None,
|
|
Color_Stencil_Always,
|
|
Color_Stencil_Equal,
|
|
Color_Stencil_Set,
|
|
Color_Stencil_SetInverse,
|
|
Color_Stencil_Intersect,
|
|
Color_Stencil_Disabled,
|
|
Texture_Stencil_Always,
|
|
Texture_Stencil_Equal,
|
|
Texture_Stencil_Disabled,
|
|
Gradient,
|
|
Creation,
|
|
// this is for presenting our msaa render target texture for NO MSAA RT
|
|
// if you do not correctly stuff DX12 validation will say about different
|
|
// sample count like it is expected 1 (because no MSAA) but your RT target texture was created with
|
|
// sample count = 2, so it is not a correct way of using it
|
|
Passthrough,
|
|
Passthrough_NoDepthStencil,
|
|
Passthrough_Opacity,
|
|
Passthrough_MSAA,
|
|
Passthrough_MSAA_Equal,
|
|
Passthrough_NoBlend, // for MSAA RT
|
|
Passthrough_NoBlendAndNoMSAA, // for RT that's not MSAA
|
|
ColorMatrix,
|
|
BlendMask,
|
|
Blur,
|
|
DropShadow,
|
|
Count
|
|
};
|
|
|
|
#define MAX_NUM_STOPS 16
|
|
#define BLUR_SIZE 7
|
|
#define BLUR_NUM_WEIGHTS ((BLUR_SIZE + 1) / 2)
|
|
|
|
#define RMLUI_STRINGIFY_IMPL(x) #x
|
|
#define RMLUI_STRINGIFY(x) RMLUI_STRINGIFY_IMPL(x)
|
|
|
|
#pragma comment(lib, "d3dcompiler.lib")
|
|
#pragma comment(lib, "d3d12.lib")
|
|
#pragma comment(lib, "dxgi.lib")
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
#pragma comment(lib, "dxguid.lib")
|
|
#endif
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
// first argument specifies that input string is char if it is needed to use other languages than English then use u8 prefix
|
|
// example: RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "::RenderGeometry");
|
|
// example UTF8: RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, u8"::RenderGeometry");
|
|
#define RMLUI_DX_MARKER_BEGIN(list, name) \
|
|
if (list) \
|
|
list->BeginEvent(1, reinterpret_cast<const char*>(name), static_cast<UINT>(strlen(name) + 1));
|
|
#define RMLUI_DX_MARKER_END(list) \
|
|
if (list) \
|
|
list->EndEvent();
|
|
#else
|
|
#define RMLUI_DX_MARKER_BEGIN(list, name)
|
|
#define RMLUI_DX_MARKER_END(list)
|
|
#endif
|
|
|
|
namespace Gfx {
|
|
struct FramebufferData {
|
|
public:
|
|
FramebufferData() :
|
|
m_is_render_target{true}, m_width{}, m_height{}, m_id{-1}, m_p_texture{}, m_p_texture_depth_stencil{}, m_texture_descriptor_resource_view{},
|
|
m_allocation_descriptor_offset{}
|
|
{}
|
|
|
|
FramebufferData(const FramebufferData&) = delete;
|
|
FramebufferData& operator=(const FramebufferData&) = delete;
|
|
|
|
// overload because we don't need to copy information about how our object was allocated (from storage or on stack, see m_is_allocated_on_stack)
|
|
FramebufferData(FramebufferData&& data) noexcept :
|
|
m_is_render_target{std::exchange(data.m_is_render_target, true)}, m_width{std::exchange(data.m_width, 0)},
|
|
m_height{std::exchange(data.m_height, 0)}, m_id{std::exchange(data.m_id, -1)}, m_p_texture{std::exchange(data.m_p_texture, nullptr)},
|
|
m_p_texture_depth_stencil{std::exchange(data.m_p_texture_depth_stencil, nullptr)},
|
|
m_texture_descriptor_resource_view{std::exchange(data.m_texture_descriptor_resource_view, {})},
|
|
m_allocation_descriptor_offset{std::exchange(data.m_allocation_descriptor_offset, {})}
|
|
{}
|
|
|
|
// overload because we don't need to copy information about how our object was allocated (from storage or on stack, see m_is_allocated_on_stack)
|
|
FramebufferData& operator=(FramebufferData&& data) noexcept
|
|
{
|
|
m_is_render_target = std::exchange(data.m_is_render_target, true);
|
|
m_width = std::exchange(data.m_width, 0);
|
|
m_height = std::exchange(data.m_height, 0);
|
|
m_id = std::exchange(data.m_id, -1);
|
|
m_p_texture = std::exchange(data.m_p_texture, nullptr);
|
|
m_p_texture_depth_stencil = std::exchange(data.m_p_texture_depth_stencil, nullptr);
|
|
m_texture_descriptor_resource_view = std::exchange(data.m_texture_descriptor_resource_view, {});
|
|
m_allocation_descriptor_offset = std::exchange(data.m_allocation_descriptor_offset, {});
|
|
return *this;
|
|
}
|
|
|
|
~FramebufferData()
|
|
{
|
|
m_id = -1;
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (m_is_allocated_on_stack == false)
|
|
RMLUI_ASSERTMSG(m_p_texture == nullptr, "you must manually deallocate texture and set this field as nullptr!");
|
|
#endif
|
|
}
|
|
|
|
int Get_Width() const { return m_width; }
|
|
void Set_Width(int value) { m_width = value; }
|
|
|
|
int Get_Height() const { return m_height; }
|
|
void Set_Height(int value) { m_height = value; }
|
|
|
|
void Set_ID(int layer_current_size_index) { m_id = layer_current_size_index; }
|
|
int Get_ID() const { return m_id; }
|
|
|
|
void Set_Texture(RenderInterface_DX12::TextureHandleType* p_texture) { m_p_texture = p_texture; }
|
|
RenderInterface_DX12::TextureHandleType* Get_Texture() const { return m_p_texture; }
|
|
|
|
// ResourceView means RTV or DSV
|
|
void Set_DescriptorResourceView(const D3D12_CPU_DESCRIPTOR_HANDLE& handle) { m_texture_descriptor_resource_view = handle; }
|
|
const D3D12_CPU_DESCRIPTOR_HANDLE& Get_DescriptorResourceView() const { return m_texture_descriptor_resource_view; }
|
|
|
|
void Set_SharedDepthStencilTexture(FramebufferData* p_data) { m_p_texture_depth_stencil = p_data; }
|
|
FramebufferData* Get_SharedDepthStencilTexture() const { return m_p_texture_depth_stencil; }
|
|
|
|
D3D12MA::VirtualAllocation* Get_VirtualAllocation_Descriptor() { return &m_allocation_descriptor_offset; }
|
|
|
|
bool Is_RenderTarget() const { return m_is_render_target; }
|
|
void Set_RenderTarget(bool value) { m_is_render_target = value; }
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
// in order to prevent false triggering assert in destructor we determine if object was created on stack or not
|
|
// if not we manually set this field to false
|
|
bool m_is_allocated_on_stack = true;
|
|
#endif
|
|
|
|
private:
|
|
bool m_is_render_target;
|
|
int m_width;
|
|
int m_height;
|
|
int m_id;
|
|
RenderInterface_DX12::TextureHandleType* m_p_texture;
|
|
// this is shared texture and original pointer stored and managed at renderlayerstack class
|
|
FramebufferData* m_p_texture_depth_stencil;
|
|
D3D12_CPU_DESCRIPTOR_HANDLE m_texture_descriptor_resource_view;
|
|
// from dsv or rtv heap!!
|
|
D3D12MA::VirtualAllocation m_allocation_descriptor_offset;
|
|
};
|
|
} // namespace Gfx
|
|
|
|
RenderInterface_DX12::RenderInterface_DX12(void* p_window_handle, const Backend::RmlRendererSettings& settings) :
|
|
m_is_use_vsync{settings.vsync}, m_is_use_tearing{}, m_is_scissor_was_set{}, m_is_stencil_enabled{}, m_is_stencil_equal{}, m_is_use_msaa{true},
|
|
m_msaa_sample_count{settings.msaa_sample_count}, m_user_framebuffer_index{}, m_width{}, m_height{}, m_current_clip_operation{-1},
|
|
m_active_program_id{}, m_size_descriptor_heap_render_target_view{}, m_size_descriptor_heap_shaders{}, m_current_back_buffer_index{},
|
|
m_stencil_ref_value{}, m_p_device{}, m_p_command_queue{}, m_p_copy_queue{}, m_p_swapchain{}, m_p_command_graphics_list{},
|
|
m_p_command_graphics_list_screenshot{}, m_p_command_allocator_screenshot{}, m_p_descriptor_heap_render_target_view{},
|
|
m_p_descriptor_heap_render_target_view_for_texture_manager{}, m_p_descriptor_heap_depth_stencil_view_for_texture_manager{},
|
|
m_p_descriptor_heap_shaders{}, m_p_descriptor_heap_depthstencil{}, m_p_depthstencil_resource{}, m_p_backbuffer_fence{}, m_p_fence_screenshot{},
|
|
m_p_adapter{}, m_p_copy_allocator{}, m_p_copy_command_list{}, m_p_allocator{}, m_p_offset_allocator_for_descriptor_heap_shaders{},
|
|
m_p_user_rtv_present{}, m_p_user_dsv_present{}, m_p_window_handle{}, m_p_fence_event{}, m_p_fence_event_screenshot{}, m_fence_value{},
|
|
m_fence_screenshot_value{}, m_precompiled_fullscreen_quad_geometry{}
|
|
{
|
|
static_assert(RenderInterface_DX12::NumPrograms == static_cast<size_t>(ProgramId::Count),
|
|
"Please adjust the NumPrograms constant for consistency with the number of program IDs.");
|
|
|
|
RMLUI_ZoneScopedN("DirectX 12 - Constructor (non user)");
|
|
RMLUI_ASSERTMSG(p_window_handle, "you can't pass an empty window handle! (also it must be castable to HWND)");
|
|
|
|
m_p_window_handle = static_cast<HWND>(p_window_handle);
|
|
|
|
std::memset(m_pipelines, 0, sizeof(m_pipelines));
|
|
std::memset(m_root_signatures, 0, sizeof(m_root_signatures));
|
|
std::memset(m_constant_buffer_count_per_frame.data(), 0, sizeof(m_constant_buffer_count_per_frame));
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_default_shader_flags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
|
|
#else
|
|
m_default_shader_flags = 0;
|
|
#endif
|
|
|
|
RMLUI_ZoneScopedN("DirectX 12 - Initialize");
|
|
|
|
Initialize_DebugLayer();
|
|
Initialize_Adapter();
|
|
Initialize_Device();
|
|
|
|
unsigned char max_msaa_supported_sample_count = GetMSAASupportedSampleCount(64);
|
|
|
|
m_is_use_msaa = m_msaa_sample_count <= max_msaa_supported_sample_count;
|
|
|
|
// requested count is 1 so we force it to false because in case if GPU doesn't support multisampling and returns 1 we get 1 == 1 situation
|
|
// and m_is_use_msaa will be true but it is not right and validation layers will get assertions about this situation like we want to resolve
|
|
// resource that as source with sample count equal to 1 but it expects to be >= 2
|
|
if (m_msaa_sample_count == 1)
|
|
m_is_use_msaa = false;
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::LT_INFO, "[DirectX-12] Max supported MSAA sample count (Quality:0): %d", max_msaa_supported_sample_count);
|
|
Rml::Log::Message(Rml::Log::LT_INFO, "[DirectX-12] Requested MSAA level: %d (compile-time: %d | supported: %d)", m_msaa_sample_count,
|
|
RMLUI_RENDER_BACKEND_FIELD_MSAA_SAMPLE_COUNT, max_msaa_supported_sample_count);
|
|
Rml::Log::Message(Rml::Log::LT_INFO, "[DirectX-12] MSAA: %s", m_is_use_msaa ? "supported and enabled" : "Not supported by hardware and disabled");
|
|
#endif
|
|
|
|
m_p_command_queue = Create_CommandQueue(D3D12_COMMAND_LIST_TYPE_DIRECT);
|
|
m_p_copy_queue = Create_CommandQueue(D3D12_COMMAND_LIST_TYPE_COPY);
|
|
|
|
RMLUI_ASSERTMSG(m_p_command_queue, "must create command queue!");
|
|
RMLUI_ASSERTMSG(m_p_copy_queue, "must create copy queue!");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_p_copy_queue->SetName(TEXT("Copy Queue (for texture manager)"));
|
|
#endif
|
|
|
|
Initialize_Swapchain(0, 0);
|
|
|
|
m_p_descriptor_heap_render_target_view = Create_Resource_DescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
|
|
D3D12_DESCRIPTOR_HEAP_FLAGS::D3D12_DESCRIPTOR_HEAP_FLAG_NONE, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT);
|
|
|
|
m_p_descriptor_heap_render_target_view_for_texture_manager = Create_Resource_DescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
|
|
D3D12_DESCRIPTOR_HEAP_FLAGS::D3D12_DESCRIPTOR_HEAP_FLAG_NONE, RMLUI_RENDER_BACKEND_FIELD_DESCRIPTOR_HEAP_RTV);
|
|
|
|
m_p_descriptor_heap_shaders = Create_Resource_DescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
|
D3D12_DESCRIPTOR_HEAP_FLAGS::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, RMLUI_RENDER_BACKEND_FIELD_DESCRIPTORAMOUNT_FOR_SRV_CBV_UAV);
|
|
|
|
m_p_descriptor_heap_depthstencil =
|
|
Create_Resource_DescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, D3D12_DESCRIPTOR_HEAP_FLAGS::D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
|
|
|
|
m_p_descriptor_heap_depth_stencil_view_for_texture_manager = Create_Resource_DescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
|
|
D3D12_DESCRIPTOR_HEAP_FLAGS::D3D12_DESCRIPTOR_HEAP_FLAG_NONE, RMLUI_RENDER_BACKEND_FIELD_DESCRIPTOR_HEAP_DSV);
|
|
|
|
m_handle_shaders = D3D12_CPU_DESCRIPTOR_HANDLE(m_p_descriptor_heap_shaders->GetCPUDescriptorHandleForHeapStart());
|
|
|
|
m_size_descriptor_heap_render_target_view = m_p_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
|
m_size_descriptor_heap_shaders = m_p_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
|
Create_Resources_DependentOnSize();
|
|
|
|
Initialize_CommandAllocators();
|
|
m_p_command_graphics_list =
|
|
Create_CommandList(m_backbuffers_allocators.at(m_current_back_buffer_index), D3D12_COMMAND_LIST_TYPE::D3D12_COMMAND_LIST_TYPE_DIRECT);
|
|
Initialize_Allocator();
|
|
|
|
m_p_command_allocator_screenshot = Create_CommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT);
|
|
m_p_command_graphics_list_screenshot = Create_CommandList(m_p_command_allocator_screenshot, D3D12_COMMAND_LIST_TYPE_DIRECT);
|
|
|
|
Initialize_SyncPrimitives();
|
|
|
|
Initialize_SyncPrimitives_Screenshot();
|
|
|
|
m_p_copy_allocator = Create_CommandAllocator(D3D12_COMMAND_LIST_TYPE::D3D12_COMMAND_LIST_TYPE_COPY);
|
|
m_p_copy_command_list = Create_CommandList(m_p_copy_allocator, D3D12_COMMAND_LIST_TYPE::D3D12_COMMAND_LIST_TYPE_COPY);
|
|
|
|
m_p_offset_allocator_for_descriptor_heap_shaders =
|
|
new OffsetAllocator::Allocator(RMLUI_RENDER_BACKEND_FIELD_DESCRIPTORAMOUNT_FOR_SRV_CBV_UAV * m_size_descriptor_heap_shaders);
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "amount of srv_cbv_uav: %d size of increment: %d",
|
|
RMLUI_RENDER_BACKEND_FIELD_DESCRIPTORAMOUNT_FOR_SRV_CBV_UAV, m_size_descriptor_heap_shaders);
|
|
#endif
|
|
|
|
m_manager_buffer.Initialize(m_p_device, m_p_allocator, m_p_offset_allocator_for_descriptor_heap_shaders, &m_handle_shaders,
|
|
m_size_descriptor_heap_shaders);
|
|
m_manager_texture.Initialize(m_p_allocator, m_p_offset_allocator_for_descriptor_heap_shaders, m_p_device, m_p_copy_command_list,
|
|
m_p_command_graphics_list, m_p_copy_allocator, m_p_descriptor_heap_shaders, m_p_descriptor_heap_render_target_view_for_texture_manager,
|
|
m_p_descriptor_heap_depth_stencil_view_for_texture_manager, m_p_copy_queue, &m_handle_shaders, this);
|
|
m_manager_render_layer.Initialize(this);
|
|
|
|
Create_Resource_Pipelines();
|
|
|
|
Rml::Mesh mesh;
|
|
Rml::MeshUtilities::GenerateQuad(mesh, Rml::Vector2f(-1.f), Rml::Vector2f(2.f), {});
|
|
|
|
m_precompiled_fullscreen_quad_geometry = RenderInterface_DX12::CompileGeometry(mesh.vertices, mesh.indices);
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "DirectX 12 Initialize type: full");
|
|
#endif
|
|
}
|
|
|
|
RenderInterface_DX12::~RenderInterface_DX12()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Destructor");
|
|
|
|
Flush();
|
|
|
|
m_manager_render_layer.Shutdown();
|
|
|
|
Destroy_Resource_Pipelines();
|
|
|
|
if (m_precompiled_fullscreen_quad_geometry)
|
|
{
|
|
Free_Geometry(reinterpret_cast<GeometryHandleType*>(m_precompiled_fullscreen_quad_geometry));
|
|
m_precompiled_fullscreen_quad_geometry = {};
|
|
}
|
|
|
|
m_manager_buffer.Shutdown();
|
|
m_manager_texture.Shutdown();
|
|
|
|
if (m_p_offset_allocator_for_descriptor_heap_shaders)
|
|
{
|
|
delete m_p_offset_allocator_for_descriptor_heap_shaders;
|
|
m_p_offset_allocator_for_descriptor_heap_shaders = nullptr;
|
|
}
|
|
|
|
if (m_p_command_graphics_list_screenshot)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_command_graphics_list_screenshot->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
if (m_p_command_allocator_screenshot)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_command_allocator_screenshot->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
Destroy_SyncPrimitives_Screenshot();
|
|
|
|
{
|
|
Destroy_Allocator();
|
|
Destroy_SyncPrimitives();
|
|
Destroy_Resource_RenderTagetViews();
|
|
Destroy_Swapchain();
|
|
Destroy_CommandAllocators();
|
|
|
|
if (m_p_command_graphics_list)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_command_graphics_list->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
if (m_p_command_queue)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_command_queue->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
if (m_p_descriptor_heap_render_target_view)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_descriptor_heap_render_target_view->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
if (m_p_descriptor_heap_render_target_view_for_texture_manager)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_descriptor_heap_render_target_view_for_texture_manager->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
if (m_p_descriptor_heap_depth_stencil_view_for_texture_manager)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_descriptor_heap_depth_stencil_view_for_texture_manager->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
if (m_p_descriptor_heap_shaders)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_descriptor_heap_shaders->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
if (m_p_descriptor_heap_depthstencil)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_descriptor_heap_depthstencil->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
if (m_p_copy_command_list)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_copy_command_list->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
if (m_p_copy_allocator)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_copy_allocator->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
if (m_p_copy_queue)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_copy_queue->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
if (m_p_adapter)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_adapter->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
if (m_p_device)
|
|
{
|
|
// if here you got assert on debug that's 100% leak and not just showing some connections that will be later released like other instances
|
|
// might show (but not true due to correct order of deallocations you get the correct report of unhanleded aka not released resources in
|
|
// dx12), so in good scenario every instance must return ref_count == 0
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_device->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
}
|
|
|
|
m_p_command_allocator_screenshot = nullptr;
|
|
m_p_command_graphics_list_screenshot = nullptr;
|
|
m_p_device = nullptr;
|
|
m_p_adapter = nullptr;
|
|
m_p_window_handle = nullptr;
|
|
m_p_swapchain = nullptr;
|
|
m_p_command_graphics_list = nullptr;
|
|
m_p_command_queue = nullptr;
|
|
m_p_descriptor_heap_render_target_view = nullptr;
|
|
m_p_allocator = nullptr;
|
|
m_p_descriptor_heap_shaders = nullptr;
|
|
m_p_descriptor_heap_depthstencil = nullptr;
|
|
m_p_copy_command_list = nullptr;
|
|
m_p_copy_allocator = nullptr;
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
{
|
|
auto dll_dxgidebug = LoadLibraryEx(TEXT("dxgidebug.dll"), nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
|
|
|
if (dll_dxgidebug)
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "loaded dxgidebug.dll for detecting memory leaks on DirectX's side!");
|
|
|
|
typedef HRESULT(WINAPI * LPDXGIGETDEBUGINTERFACE)(REFIID, void**);
|
|
auto callback_DXGIGetDebugInterface =
|
|
reinterpret_cast<LPDXGIGETDEBUGINTERFACE>(reinterpret_cast<void*>(GetProcAddress(dll_dxgidebug, "DXGIGetDebugInterface")));
|
|
|
|
if (callback_DXGIGetDebugInterface)
|
|
{
|
|
IDXGIDebug* p_debug_references{};
|
|
|
|
auto status = callback_DXGIGetDebugInterface(IID_PPV_ARGS(&p_debug_references));
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to DXGIGetDebugInterface");
|
|
|
|
if (SUCCEEDED(status))
|
|
{
|
|
if (p_debug_references)
|
|
{
|
|
p_debug_references->ReportLiveObjects(DXGI_DEBUG_ALL,
|
|
DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_IGNORE_INTERNAL));
|
|
p_debug_references->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG,
|
|
"Failed to initialize IDXGIDebug interface by DXGIGetDebugInterface function from dxgidebug.dll!");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG,
|
|
"your Windows version is too old for loading dxgidebug.dll! (your OS's SDK doesn't provide a such dll)");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Rml::Log::Message(Rml::Log::Type::LT_INFO, "Backend DirectX 12 is destroyed!");
|
|
}
|
|
|
|
RenderInterface_DX12::operator bool() const
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - operator bool()");
|
|
return !!(m_p_device);
|
|
}
|
|
|
|
void RenderInterface_DX12::BeginFrame()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BeginFrame");
|
|
|
|
auto* p_command_allocator = m_backbuffers_allocators.at(m_current_back_buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_command_allocator, "should be allocated and initialized! Probably early calling");
|
|
RMLUI_ASSERTMSG(m_p_command_graphics_list, "must be allocated and initialized! Probably early calling");
|
|
|
|
if (p_command_allocator)
|
|
{
|
|
RMLUI_DX_VERIFY_MSG(p_command_allocator->Reset(), "failed to reset command allocator");
|
|
}
|
|
|
|
if (m_p_command_graphics_list)
|
|
{
|
|
RMLUI_DX_VERIFY_MSG(m_p_command_graphics_list->Reset(p_command_allocator, nullptr), "failed to reset command graphics list");
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "BeginFrame");
|
|
|
|
m_stencil_ref_value = 0;
|
|
m_is_scissor_was_set = false;
|
|
|
|
SetTransform(nullptr);
|
|
|
|
m_manager_render_layer.BeginFrame(m_width, m_height);
|
|
BindRenderTarget(m_manager_render_layer.GetTopLayer());
|
|
|
|
D3D12_VIEWPORT viewport{};
|
|
viewport.Height = static_cast<FLOAT>(m_height);
|
|
viewport.Width = static_cast<FLOAT>(m_width);
|
|
viewport.MaxDepth = 1.0f;
|
|
m_p_command_graphics_list->RSSetViewports(1, &viewport);
|
|
|
|
UseProgram(ProgramId::None);
|
|
m_is_stencil_equal = false;
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::EndFrame()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - EndFrame");
|
|
auto* p_resource_backbuffer = m_backbuffers_resources.at(m_current_back_buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_resource_backbuffer, "should be allocated and initialized! Probably early calling");
|
|
RMLUI_ASSERTMSG(m_p_command_graphics_list, "Must be allocated and initialzied. Probably early calling!");
|
|
RMLUI_ASSERTMSG(m_p_command_queue, "Must be allocated and initialzied. Probably early calling!");
|
|
|
|
if (m_p_command_graphics_list)
|
|
{
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "EndFrame");
|
|
D3D12_RESOURCE_BARRIER backbuffer_barrier_from_rt_to_present;
|
|
|
|
backbuffer_barrier_from_rt_to_present.Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
backbuffer_barrier_from_rt_to_present.Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
backbuffer_barrier_from_rt_to_present.Transition.pResource = p_resource_backbuffer;
|
|
backbuffer_barrier_from_rt_to_present.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
backbuffer_barrier_from_rt_to_present.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
|
backbuffer_barrier_from_rt_to_present.Transition.Subresource = 0;
|
|
|
|
const Gfx::FramebufferData& fb_active = m_manager_render_layer.GetTopLayer();
|
|
const Gfx::FramebufferData& fb_postprocess = m_manager_render_layer.GetPostprocessPrimary();
|
|
|
|
ID3D12Resource* p_msaa_texture{};
|
|
ID3D12Resource* p_postprocess_texture{};
|
|
|
|
TextureHandleType* p_handle_postprocess_texture = fb_postprocess.Get_Texture();
|
|
|
|
if (fb_active.Get_Texture())
|
|
{
|
|
TextureHandleType* p_resource = fb_active.Get_Texture();
|
|
RMLUI_ASSERTMSG(p_resource->Get_Info().buffer_index == -1, "can't be allocated as placed resource no sense!");
|
|
|
|
D3D12MA::Allocation* p_allocation = static_cast<D3D12MA::Allocation*>(p_resource->Get_Resource());
|
|
p_msaa_texture = p_allocation->GetResource();
|
|
}
|
|
|
|
if (fb_postprocess.Get_Texture())
|
|
{
|
|
TextureHandleType* p_resource = fb_postprocess.Get_Texture();
|
|
RMLUI_ASSERTMSG(p_resource->Get_Info().buffer_index == -1, "can't be allocated as place resource no sense!");
|
|
|
|
D3D12MA::Allocation* p_allocation = static_cast<D3D12MA::Allocation*>(p_resource->Get_Resource());
|
|
p_postprocess_texture = p_allocation->GetResource();
|
|
}
|
|
|
|
RMLUI_ASSERTMSG(p_msaa_texture, "can't be, must be a valid texture!");
|
|
RMLUI_ASSERTMSG(p_postprocess_texture, "can't be, must be a valid texture!");
|
|
RMLUI_ASSERTMSG(p_handle_postprocess_texture, "must be valid!");
|
|
|
|
RMLUI_ASSERTMSG(p_msaa_texture->GetDesc().Width == p_postprocess_texture->GetDesc().Width, "must be same otherwise use blitframebuffer!");
|
|
RMLUI_ASSERTMSG(p_msaa_texture->GetDesc().Height == p_postprocess_texture->GetDesc().Height, "must be same otherwise use blitframebuffer!");
|
|
|
|
#if RMLUI_RENDER_BACKEND_FIELD_MSAA_SAMPLE_COUNT > 1
|
|
D3D12_RESOURCE_BARRIER barriers[2]{};
|
|
|
|
barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barriers[0].Transition.Subresource = 0;
|
|
barriers[0].Transition.pResource = p_msaa_texture;
|
|
barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RESOLVE_SOURCE;
|
|
barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
|
|
barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barriers[1].Transition.Subresource = 0;
|
|
barriers[1].Transition.pResource = p_postprocess_texture;
|
|
barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_RESOLVE_DEST;
|
|
barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
|
|
D3D12_RESOURCE_BARRIER barrier_transition_from_msaa_resolve_source_to_rt;
|
|
barrier_transition_from_msaa_resolve_source_to_rt.Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barrier_transition_from_msaa_resolve_source_to_rt.Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barrier_transition_from_msaa_resolve_source_to_rt.Transition.Subresource = 0;
|
|
barrier_transition_from_msaa_resolve_source_to_rt.Transition.pResource = p_msaa_texture;
|
|
barrier_transition_from_msaa_resolve_source_to_rt.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
barrier_transition_from_msaa_resolve_source_to_rt.Transition.StateBefore = D3D12_RESOURCE_STATE_RESOLVE_SOURCE;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(2, barriers);
|
|
|
|
m_p_command_graphics_list->ResolveSubresource(p_postprocess_texture, 0, p_msaa_texture, 0, RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT);
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, &barrier_transition_from_msaa_resolve_source_to_rt);
|
|
|
|
D3D12_RESOURCE_BARRIER offscreen_texture_barrier_for_shader;
|
|
offscreen_texture_barrier_for_shader.Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
offscreen_texture_barrier_for_shader.Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
offscreen_texture_barrier_for_shader.Transition.pResource = p_postprocess_texture;
|
|
offscreen_texture_barrier_for_shader.Transition.Subresource = 0;
|
|
offscreen_texture_barrier_for_shader.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
offscreen_texture_barrier_for_shader.Transition.StateBefore = D3D12_RESOURCE_STATE_RESOLVE_DEST;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, &offscreen_texture_barrier_for_shader);
|
|
#else
|
|
D3D12_RESOURCE_BARRIER barriers[2]{};
|
|
|
|
barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barriers[0].Transition.Subresource = 0;
|
|
barriers[0].Transition.pResource = p_msaa_texture;
|
|
barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
|
barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
|
|
barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barriers[1].Transition.Subresource = 0;
|
|
barriers[1].Transition.pResource = p_postprocess_texture;
|
|
barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
|
|
D3D12_RESOURCE_BARRIER barrier_transition_from_msaa_resolve_source_to_rt;
|
|
barrier_transition_from_msaa_resolve_source_to_rt.Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barrier_transition_from_msaa_resolve_source_to_rt.Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barrier_transition_from_msaa_resolve_source_to_rt.Transition.Subresource = 0;
|
|
barrier_transition_from_msaa_resolve_source_to_rt.Transition.pResource = p_msaa_texture;
|
|
barrier_transition_from_msaa_resolve_source_to_rt.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
barrier_transition_from_msaa_resolve_source_to_rt.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(2, barriers);
|
|
|
|
m_p_command_graphics_list->CopyResource(p_postprocess_texture, p_msaa_texture);
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, &barrier_transition_from_msaa_resolve_source_to_rt);
|
|
|
|
D3D12_RESOURCE_BARRIER offscreen_texture_barrier_for_shader;
|
|
offscreen_texture_barrier_for_shader.Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
offscreen_texture_barrier_for_shader.Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
offscreen_texture_barrier_for_shader.Transition.pResource = p_postprocess_texture;
|
|
offscreen_texture_barrier_for_shader.Transition.Subresource = 0;
|
|
offscreen_texture_barrier_for_shader.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
offscreen_texture_barrier_for_shader.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, &offscreen_texture_barrier_for_shader);
|
|
#endif
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE handle_rtv(m_p_descriptor_heap_render_target_view->GetCPUDescriptorHandleForHeapStart());
|
|
handle_rtv.ptr += m_current_back_buffer_index * (m_size_descriptor_heap_render_target_view);
|
|
D3D12_CPU_DESCRIPTOR_HANDLE handle_dsv(m_p_descriptor_heap_depthstencil->GetCPUDescriptorHandleForHeapStart());
|
|
|
|
m_p_command_graphics_list->OMSetRenderTargets(1, &handle_rtv, FALSE, &handle_dsv);
|
|
|
|
UseProgram(ProgramId::Passthrough);
|
|
|
|
BindTexture(p_handle_postprocess_texture);
|
|
|
|
DrawFullscreenQuad();
|
|
|
|
m_manager_render_layer.EndFrame();
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, &backbuffer_barrier_from_rt_to_present);
|
|
|
|
D3D12_RESOURCE_BARRIER restore_state_of_postprocess_texture_return_to_rt;
|
|
restore_state_of_postprocess_texture_return_to_rt.Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
restore_state_of_postprocess_texture_return_to_rt.Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
restore_state_of_postprocess_texture_return_to_rt.Transition.Subresource = 0;
|
|
restore_state_of_postprocess_texture_return_to_rt.Transition.pResource = p_postprocess_texture;
|
|
restore_state_of_postprocess_texture_return_to_rt.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
restore_state_of_postprocess_texture_return_to_rt.Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
m_p_command_graphics_list->ResourceBarrier(1, &restore_state_of_postprocess_texture_return_to_rt);
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
|
|
RMLUI_DX_VERIFY_MSG(m_p_command_graphics_list->Close(), "failed to Close");
|
|
|
|
ID3D12CommandList* const lists[] = {m_p_command_graphics_list};
|
|
|
|
if (m_p_command_queue)
|
|
{
|
|
m_p_command_queue->ExecuteCommandLists(_countof(lists), lists);
|
|
}
|
|
|
|
UINT sync_interval = m_is_use_vsync ? 1 : 0;
|
|
UINT present_flags = (m_is_use_tearing && !m_is_use_vsync) ? DXGI_PRESENT_ALLOW_TEARING : 0;
|
|
|
|
RMLUI_DX_VERIFY_MSG(m_p_swapchain->Present(sync_interval, present_flags), "failed to Present");
|
|
|
|
auto fence_value = Signal(m_current_back_buffer_index);
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12] current allocated constant buffers per draw (for frame[%d]): %zu",
|
|
m_current_back_buffer_index, m_constant_buffer_count_per_frame[m_current_back_buffer_index]);
|
|
#endif
|
|
|
|
m_constant_buffer_count_per_frame[m_current_back_buffer_index] = 0;
|
|
|
|
m_current_back_buffer_index = (uint32_t)m_p_swapchain->GetCurrentBackBufferIndex();
|
|
|
|
WaitForFenceValue(m_current_back_buffer_index);
|
|
Update_PendingForDeletion_Geometry();
|
|
m_backbuffers_fence_values[m_current_back_buffer_index] = fence_value + 1;
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Clear()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Clear");
|
|
RMLUI_ASSERTMSG(m_p_command_graphics_list, "early calling prob!");
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "Clear");
|
|
|
|
auto* p_backbuffer = m_backbuffers_resources.at(m_current_back_buffer_index);
|
|
|
|
D3D12_RESOURCE_BARRIER barrier;
|
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barrier.Transition.pResource = p_backbuffer;
|
|
barrier.Transition.Subresource = 0;
|
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, &barrier);
|
|
|
|
constexpr FLOAT clear_color[] = {RMLUI_RENDER_BACKEND_FIELD_CLEAR_VALUE_RENDERTARGET_COLOR_VAlUE};
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE rtv(m_p_descriptor_heap_render_target_view->GetCPUDescriptorHandleForHeapStart());
|
|
rtv.ptr += m_current_back_buffer_index * (m_size_descriptor_heap_render_target_view);
|
|
|
|
m_p_command_graphics_list->ClearDepthStencilView(m_p_descriptor_heap_depthstencil->GetCPUDescriptorHandleForHeapStart(),
|
|
D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
|
|
|
|
m_p_command_graphics_list->ClearRenderTargetView(rtv, clear_color, 0, nullptr);
|
|
|
|
auto& p_current_rtv = m_manager_render_layer.GetTopLayer().Get_DescriptorResourceView();
|
|
// auto& p_current_dsv = m_manager_render_layer.GetTopLayer().Get_SharedDepthStencilTexture()->Get_DescriptorResourceView();
|
|
|
|
constexpr FLOAT clear_color_framebuffer[] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
m_p_command_graphics_list->ClearRenderTargetView(p_current_rtv, clear_color_framebuffer, 0, nullptr);
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
void RenderInterface_DX12::SetViewport(int viewport_width, int viewport_height)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - SetViewport");
|
|
if (viewport_width <= 0 || viewport_height <= 0)
|
|
return;
|
|
|
|
if (m_width != viewport_width || m_height != viewport_height)
|
|
{
|
|
Flush();
|
|
|
|
if (m_p_depthstencil_resource)
|
|
{
|
|
Destroy_Resource_DepthStencil();
|
|
}
|
|
|
|
m_width = viewport_width;
|
|
m_height = viewport_height;
|
|
|
|
m_projection = Rml::Matrix4f::ProjectOrtho(0, static_cast<float>(viewport_width), static_cast<float>(viewport_height), 0, -10000, 10000);
|
|
|
|
if (m_p_swapchain)
|
|
{
|
|
Destroy_Resources_DependentOnSize();
|
|
|
|
for (int i = 0; i < RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT; ++i)
|
|
{
|
|
m_backbuffers_fence_values[i] = m_backbuffers_fence_values[m_current_back_buffer_index];
|
|
}
|
|
|
|
DXGI_SWAP_CHAIN_DESC desc;
|
|
RMLUI_DX_VERIFY_MSG(m_p_swapchain->GetDesc(&desc), "failed to GetDesc");
|
|
RMLUI_DX_VERIFY_MSG(m_p_swapchain->ResizeBuffers(static_cast<UINT>(RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT),
|
|
static_cast<UINT>(m_width), static_cast<UINT>(m_height), desc.BufferDesc.Format, desc.Flags),
|
|
"failed to ResizeBuffers");
|
|
|
|
m_current_back_buffer_index = m_p_swapchain->GetCurrentBackBufferIndex();
|
|
|
|
Create_Resources_DependentOnSize();
|
|
Create_Resource_DepthStencil();
|
|
}
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderGeometry(Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation, Rml::TextureHandle texture)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderGeometry");
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "RenderGeometry");
|
|
|
|
GeometryHandleType* p_handle_geometry = reinterpret_cast<GeometryHandleType*>(geometry);
|
|
TextureHandleType* p_handle_texture{};
|
|
|
|
RMLUI_ASSERTMSG(p_handle_geometry, "expected valid pointer!");
|
|
|
|
ConstantBufferType* p_constant_buffer{};
|
|
uint32_t default_index_for_one_cbv_that_will_be_used_in_vertex_shader{};
|
|
const uint32_t* p_constant_buffer_root_parameter_indicies{&default_index_for_one_cbv_that_will_be_used_in_vertex_shader};
|
|
uint8_t amount_of_constant_buffer_root_parameter_indicies{1};
|
|
|
|
if (texture == TexturePostprocess)
|
|
{
|
|
if (p_handle_geometry->Get_ConstantBuffer())
|
|
{
|
|
p_constant_buffer = p_handle_geometry->Get_ConstantBuffer();
|
|
p_constant_buffer_root_parameter_indicies =
|
|
p_handle_geometry->Get_ConstantBufferRootParameterIndices(amount_of_constant_buffer_root_parameter_indicies);
|
|
}
|
|
}
|
|
else if (texture)
|
|
{
|
|
p_handle_texture = reinterpret_cast<TextureHandleType*>(texture);
|
|
RMLUI_ASSERTMSG(p_handle_texture, "expected valid pointer!");
|
|
|
|
if (m_is_stencil_enabled)
|
|
{
|
|
if (m_is_stencil_equal)
|
|
{
|
|
UseProgram(ProgramId::Texture_Stencil_Equal);
|
|
}
|
|
else
|
|
{
|
|
UseProgram(ProgramId::Texture_Stencil_Always);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UseProgram(ProgramId::Texture_Stencil_Disabled);
|
|
}
|
|
|
|
if (p_handle_geometry->Get_ConstantBuffer() == nullptr)
|
|
{
|
|
p_constant_buffer = Get_ConstantBuffer(m_current_back_buffer_index);
|
|
}
|
|
else
|
|
{
|
|
p_constant_buffer = p_handle_geometry->Get_ConstantBuffer();
|
|
p_constant_buffer_root_parameter_indicies =
|
|
p_handle_geometry->Get_ConstantBufferRootParameterIndices(amount_of_constant_buffer_root_parameter_indicies);
|
|
}
|
|
|
|
SubmitTransformUniform(*p_constant_buffer, translation);
|
|
|
|
if (texture != TextureEnableWithoutBinding)
|
|
{
|
|
D3D12_GPU_DESCRIPTOR_HANDLE srv_handle;
|
|
srv_handle.ptr =
|
|
m_p_descriptor_heap_shaders->GetGPUDescriptorHandleForHeapStart().ptr + p_handle_texture->Get_Allocation_DescriptorHeap().offset;
|
|
|
|
m_p_command_graphics_list->SetGraphicsRootDescriptorTable(1, srv_handle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_current_clip_operation == -1)
|
|
{
|
|
if (m_is_stencil_enabled)
|
|
{
|
|
if (m_is_stencil_equal)
|
|
{
|
|
UseProgram(ProgramId::Color_Stencil_Equal);
|
|
}
|
|
else
|
|
{
|
|
UseProgram(ProgramId::Color_Stencil_Always);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UseProgram(ProgramId::Color_Stencil_Disabled);
|
|
}
|
|
}
|
|
else if (m_current_clip_operation == static_cast<int>(Rml::ClipMaskOperation::Intersect))
|
|
{
|
|
if (m_is_stencil_enabled)
|
|
{
|
|
UseProgram(ProgramId::Color_Stencil_Intersect);
|
|
}
|
|
}
|
|
else if (m_current_clip_operation == static_cast<int>(Rml::ClipMaskOperation::Set))
|
|
{
|
|
if (m_is_stencil_enabled)
|
|
{
|
|
UseProgram(ProgramId::Color_Stencil_Set);
|
|
}
|
|
}
|
|
else if (m_current_clip_operation == static_cast<int>(Rml::ClipMaskOperation::SetInverse))
|
|
{
|
|
if (m_is_stencil_enabled)
|
|
{
|
|
UseProgram(ProgramId::Color_Stencil_SetInverse);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RMLUI_ASSERT(!"not reached code point, something is missing or corrupted data"[0]);
|
|
}
|
|
|
|
// SubmitTransformUniform(p_handle_geometry->Get_ConstantBuffer(), translation);
|
|
if (p_handle_geometry->Get_ConstantBuffer() == nullptr)
|
|
{
|
|
p_constant_buffer = Get_ConstantBuffer(m_current_back_buffer_index);
|
|
}
|
|
else
|
|
{
|
|
p_constant_buffer = p_handle_geometry->Get_ConstantBuffer();
|
|
p_constant_buffer_root_parameter_indicies =
|
|
p_handle_geometry->Get_ConstantBufferRootParameterIndices(amount_of_constant_buffer_root_parameter_indicies);
|
|
}
|
|
|
|
SubmitTransformUniform(*p_constant_buffer, translation);
|
|
}
|
|
|
|
if (!m_is_scissor_was_set)
|
|
{
|
|
D3D12_RECT scissor;
|
|
scissor.left = 0;
|
|
scissor.top = 0;
|
|
scissor.right = m_width;
|
|
scissor.bottom = m_height;
|
|
|
|
m_p_command_graphics_list->RSSetScissorRects(1, &scissor);
|
|
}
|
|
|
|
if (p_constant_buffer)
|
|
{
|
|
auto* p_dx_constant_buffer = m_manager_buffer.Get_BufferByIndex(p_constant_buffer->m_alloc_info.buffer_index);
|
|
RMLUI_ASSERTMSG(p_dx_constant_buffer, "must be valid!");
|
|
|
|
if (p_dx_constant_buffer)
|
|
{
|
|
auto* p_dx_resource = p_dx_constant_buffer->GetResource();
|
|
|
|
RMLUI_ASSERTMSG(p_dx_resource, "must be valid!");
|
|
|
|
RMLUI_ASSERTMSG(p_constant_buffer_root_parameter_indicies,
|
|
"you forgot to update the RPI in CompiledGeometry do that only using active_program_id field!");
|
|
|
|
RMLUI_ASSERTMSG(amount_of_constant_buffer_root_parameter_indicies <= MaxConstantBuffersPerShader &&
|
|
amount_of_constant_buffer_root_parameter_indicies,
|
|
"you use too big shaders for UI but honestly you have to change limits and change this field "
|
|
"_kRenderBackend_MaxConstantBuffersPerShader for desired amount otherwise value of amount is invalid aka equals to 0 that doesn't "
|
|
"make any sense if you have valid p_constant_buffer_root_parameter_indicies pointer");
|
|
|
|
if (p_dx_resource)
|
|
{
|
|
D3D12_GPU_VIRTUAL_ADDRESS one_shared_cbv_for_different_shaders_address =
|
|
p_dx_resource->GetGPUVirtualAddress() + p_constant_buffer->m_alloc_info.offset;
|
|
|
|
for (uint8_t i = 0; i < amount_of_constant_buffer_root_parameter_indicies; ++i)
|
|
{
|
|
uint32_t index = p_constant_buffer_root_parameter_indicies[i];
|
|
|
|
m_p_command_graphics_list->SetGraphicsRootConstantBufferView(index, one_shared_cbv_for_different_shaders_address);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto* p_dx_buffer_vertex = m_manager_buffer.Get_BufferByIndex(p_handle_geometry->Get_InfoVertex().buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_dx_buffer_vertex, "must be valid!");
|
|
|
|
m_p_command_graphics_list->IASetPrimitiveTopology(D3D12_PRIMITIVE_TOPOLOGY::D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
|
|
|
if (p_dx_buffer_vertex)
|
|
{
|
|
auto* p_dx_resource = p_dx_buffer_vertex->GetResource();
|
|
|
|
RMLUI_ASSERTMSG(p_dx_resource, "must be valid!");
|
|
|
|
if (p_dx_resource)
|
|
{
|
|
D3D12_VERTEX_BUFFER_VIEW view_vertex_buffer = {};
|
|
|
|
view_vertex_buffer.BufferLocation = p_dx_resource->GetGPUVirtualAddress() + p_handle_geometry->Get_InfoVertex().offset;
|
|
view_vertex_buffer.StrideInBytes = sizeof(Rml::Vertex);
|
|
view_vertex_buffer.SizeInBytes = static_cast<UINT>(p_handle_geometry->Get_InfoVertex().size);
|
|
|
|
m_p_command_graphics_list->IASetVertexBuffers(0, 1, &view_vertex_buffer);
|
|
}
|
|
}
|
|
|
|
auto* p_dx_buffer_index = m_manager_buffer.Get_BufferByIndex(p_handle_geometry->Get_InfoIndex().buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_dx_buffer_index, "must be valid!");
|
|
|
|
if (p_dx_buffer_index)
|
|
{
|
|
auto* p_dx_resource = p_dx_buffer_index->GetResource();
|
|
|
|
RMLUI_ASSERTMSG(p_dx_resource, "must be valid!");
|
|
|
|
if (p_dx_resource)
|
|
{
|
|
D3D12_INDEX_BUFFER_VIEW view_index_buffer = {};
|
|
|
|
view_index_buffer.BufferLocation = p_dx_resource->GetGPUVirtualAddress() + p_handle_geometry->Get_InfoIndex().offset;
|
|
view_index_buffer.Format = DXGI_FORMAT::DXGI_FORMAT_R32_UINT;
|
|
view_index_buffer.SizeInBytes = static_cast<UINT>(p_handle_geometry->Get_InfoIndex().size);
|
|
|
|
m_p_command_graphics_list->IASetIndexBuffer(&view_index_buffer);
|
|
}
|
|
}
|
|
|
|
m_p_command_graphics_list->DrawIndexedInstanced(p_handle_geometry->Get_NumIndices(), 1, 0, 0, 0);
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
Rml::CompiledGeometryHandle RenderInterface_DX12::CompileGeometry(Rml::Span<const Rml::Vertex> vertices, Rml::Span<const int> indices)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - CompileGeometry");
|
|
|
|
GeometryHandleType* p_handle = new GeometryHandleType();
|
|
|
|
if (p_handle)
|
|
{
|
|
m_manager_buffer.Alloc_Vertex(vertices.data(), static_cast<int>(vertices.size()), sizeof(Rml::Vertex), p_handle);
|
|
m_manager_buffer.Alloc_Index(indices.data(), static_cast<int>(indices.size()), sizeof(int), p_handle);
|
|
|
|
p_handle->Set_HistoryBackBufferFrameIndex(m_current_back_buffer_index);
|
|
}
|
|
|
|
return reinterpret_cast<Rml::CompiledGeometryHandle>(p_handle);
|
|
}
|
|
|
|
void RenderInterface_DX12::ReleaseGeometry(Rml::CompiledGeometryHandle geometry)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - ReleaseGeometry");
|
|
GeometryHandleType* p_handle = reinterpret_cast<GeometryHandleType*>(geometry);
|
|
m_pending_for_deletion_geometry.push_back(p_handle);
|
|
}
|
|
|
|
void RenderInterface_DX12::EnableScissorRegion(bool enable)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - EnableScissorRegion");
|
|
|
|
if (!enable)
|
|
{
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "EnableScissorRegion");
|
|
SetScissor(Rml::Rectanglei::MakeInvalid(), false);
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::SetScissorRegion(Rml::Rectanglei region)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - SetScissorRegion");
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "SetScissorRegion");
|
|
|
|
SetScissor(region);
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
void RenderInterface_DX12::EnableClipMask(bool enable)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - EnableClipMask");
|
|
|
|
m_is_stencil_enabled = enable;
|
|
|
|
if (enable)
|
|
{
|
|
RMLUI_ASSERTMSG(m_p_command_graphics_list, "must be valid!");
|
|
if (m_p_command_graphics_list)
|
|
{
|
|
m_p_command_graphics_list->OMSetStencilRef(m_stencil_ref_value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RMLUI_ASSERTMSG(m_p_command_graphics_list, "mmust be valid!");
|
|
if (m_p_command_graphics_list)
|
|
{
|
|
m_p_command_graphics_list->OMSetStencilRef(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderToClipMask(Rml::ClipMaskOperation mask_operation, Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderToClipMask");
|
|
RMLUI_ASSERTMSG(m_is_stencil_enabled, "must be enabled!");
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "RenderToClipMask");
|
|
|
|
const bool clear_stencil = (mask_operation == Rml::ClipMaskOperation::Set || mask_operation == Rml::ClipMaskOperation::SetInverse);
|
|
|
|
if (clear_stencil)
|
|
{
|
|
Rml::LayerHandle layer_handle = m_manager_render_layer.GetTopLayerHandle();
|
|
const Gfx::FramebufferData& framebuffer = m_manager_render_layer.GetLayer(layer_handle);
|
|
|
|
m_p_command_graphics_list->ClearDepthStencilView(framebuffer.Get_SharedDepthStencilTexture()->Get_DescriptorResourceView(),
|
|
D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
|
|
}
|
|
|
|
switch (mask_operation)
|
|
{
|
|
case Rml::ClipMaskOperation::Set:
|
|
{
|
|
m_current_clip_operation = static_cast<int>(Rml::ClipMaskOperation::Set);
|
|
m_stencil_ref_value = 1;
|
|
break;
|
|
}
|
|
case Rml::ClipMaskOperation::SetInverse:
|
|
{
|
|
m_current_clip_operation = static_cast<int>(Rml::ClipMaskOperation::SetInverse);
|
|
m_stencil_ref_value = 0;
|
|
break;
|
|
}
|
|
case Rml::ClipMaskOperation::Intersect:
|
|
{
|
|
m_current_clip_operation = static_cast<int>(Rml::ClipMaskOperation::Intersect);
|
|
m_stencil_ref_value += 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_p_command_graphics_list->OMSetStencilRef(1);
|
|
|
|
RenderGeometry(geometry, translation, {});
|
|
|
|
m_is_stencil_equal = true;
|
|
m_current_clip_operation = -1;
|
|
m_p_command_graphics_list->OMSetStencilRef(m_stencil_ref_value);
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
// Set to byte packing, or the compiler will expand our struct, which means it won't read correctly from file
|
|
#pragma pack(1)
|
|
struct TGAHeader {
|
|
char idLength;
|
|
char colourMapType;
|
|
char dataType;
|
|
short int colourMapOrigin;
|
|
short int colourMapLength;
|
|
char colourMapDepth;
|
|
short int xOrigin;
|
|
short int yOrigin;
|
|
short int width;
|
|
short int height;
|
|
char bitsPerPixel;
|
|
char imageDescriptor;
|
|
};
|
|
// Restore packing
|
|
#pragma pack()
|
|
|
|
static int nGlobalID{};
|
|
Rml::TextureHandle RenderInterface_DX12::LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - LoadTexture");
|
|
|
|
Rml::FileInterface* file_interface = Rml::GetFileInterface();
|
|
Rml::FileHandle file_handle = file_interface->Open(source);
|
|
if (!file_handle)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
file_interface->Seek(file_handle, 0, SEEK_END);
|
|
size_t buffer_size = file_interface->Tell(file_handle);
|
|
file_interface->Seek(file_handle, 0, SEEK_SET);
|
|
|
|
if (buffer_size <= sizeof(TGAHeader))
|
|
{
|
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Texture file size is smaller than TGAHeader, file is not a valid TGA image.");
|
|
file_interface->Close(file_handle);
|
|
return false;
|
|
}
|
|
|
|
using Rml::byte;
|
|
Rml::UniquePtr<byte[]> buffer(new byte[buffer_size]);
|
|
file_interface->Read(buffer.get(), buffer_size, file_handle);
|
|
file_interface->Close(file_handle);
|
|
|
|
TGAHeader header;
|
|
memcpy(&header, buffer.get(), sizeof(TGAHeader));
|
|
|
|
int color_mode = header.bitsPerPixel / 8;
|
|
const size_t image_size = header.width * header.height * 4; // We always make 32bit textures
|
|
|
|
if (header.dataType != 2)
|
|
{
|
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24/32bit uncompressed TGAs are supported.");
|
|
return false;
|
|
}
|
|
|
|
// Ensure we have at least 3 colors
|
|
if (color_mode < 3)
|
|
{
|
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24 and 32bit textures are supported.");
|
|
return false;
|
|
}
|
|
|
|
const byte* image_src = buffer.get() + sizeof(TGAHeader);
|
|
Rml::UniquePtr<byte[]> image_dest_buffer(new byte[image_size]);
|
|
byte* image_dest = image_dest_buffer.get();
|
|
|
|
// Targa is BGR, swap to RGB, flip Y axis, and convert to premultiplied alpha.
|
|
for (long y = 0; y < header.height; y++)
|
|
{
|
|
long read_index = y * header.width * color_mode;
|
|
long write_index = ((header.imageDescriptor & 32) != 0) ? read_index : (header.height - y - 1) * header.width * 4;
|
|
for (long x = 0; x < header.width; x++)
|
|
{
|
|
image_dest[write_index] = image_src[read_index + 2];
|
|
image_dest[write_index + 1] = image_src[read_index + 1];
|
|
image_dest[write_index + 2] = image_src[read_index];
|
|
if (color_mode == 4)
|
|
{
|
|
const byte alpha = image_src[read_index + 3];
|
|
for (size_t j = 0; j < 3; j++)
|
|
image_dest[write_index + j] = byte((image_dest[write_index + j] * alpha) / 255);
|
|
image_dest[write_index + 3] = alpha;
|
|
}
|
|
else
|
|
image_dest[write_index + 3] = 255;
|
|
|
|
write_index += 4;
|
|
read_index += color_mode;
|
|
}
|
|
}
|
|
|
|
texture_dimensions.x = header.width;
|
|
texture_dimensions.y = header.height;
|
|
|
|
return GenerateTexture({image_dest, image_size}, texture_dimensions);
|
|
}
|
|
|
|
Rml::TextureHandle RenderInterface_DX12::GenerateTexture(Rml::Span<const Rml::byte> source_data, Rml::Vector2i source_dimensions)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - GenerateTexture");
|
|
|
|
// RMLUI_ASSERTMSG(source_data.data(), "must be valid source");
|
|
RMLUI_ASSERTMSG(m_p_allocator, "backend requires initialized allocator, but it is not initialized");
|
|
|
|
int width = source_dimensions.x;
|
|
int height = source_dimensions.y;
|
|
|
|
RMLUI_ASSERTMSG(width > 0, "width is less or equal to 0");
|
|
RMLUI_ASSERTMSG(height > 0, "height is less or equal to 0");
|
|
|
|
D3D12_RESOURCE_DESC desc_texture = {};
|
|
desc_texture.MipLevels = 1;
|
|
desc_texture.DepthOrArraySize = 1;
|
|
desc_texture.Format = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc_texture.Width = width;
|
|
desc_texture.Height = height;
|
|
desc_texture.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
desc_texture.SampleDesc.Count = 1;
|
|
desc_texture.SampleDesc.Quality = 0;
|
|
|
|
TextureHandleType* p_resource = new TextureHandleType();
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (p_resource)
|
|
{
|
|
p_resource->Set_ResourceName(std::to_string(nGlobalID));
|
|
++nGlobalID;
|
|
}
|
|
#endif
|
|
|
|
m_manager_texture.Alloc_Texture(desc_texture, p_resource, source_data.data()
|
|
#ifdef RMLUI_DX_DEBUG
|
|
,
|
|
p_resource->Get_ResourceName()
|
|
#endif
|
|
);
|
|
|
|
return reinterpret_cast<Rml::TextureHandle>(p_resource);
|
|
}
|
|
|
|
void RenderInterface_DX12::ReleaseTexture(Rml::TextureHandle texture_handle)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - ReleaseTexture");
|
|
TextureHandleType* p_texture = reinterpret_cast<TextureHandleType*>(texture_handle);
|
|
// m_pending_for_deletion_textures.push_back(p_texture);
|
|
|
|
if (p_texture)
|
|
{
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::LT_DEBUG, "Destroyed texture: [%s]", p_texture->Get_ResourceName().c_str());
|
|
#endif
|
|
|
|
m_manager_texture.Free_Texture(p_texture);
|
|
|
|
delete p_texture;
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::SetTransform(const Rml::Matrix4f* transform)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - SetTransform");
|
|
|
|
m_constant_buffer_data_transform = (transform ? m_projection * (*transform) : m_projection);
|
|
}
|
|
|
|
RenderInterface_DX12::RenderLayerStack::RenderLayerStack() :
|
|
m_msaa_sample_count{1}, m_width{}, m_height{}, m_layers_size{}, m_p_manager_texture{}, m_p_manager_buffer{}, m_p_device{},
|
|
m_p_depth_stencil_for_layers{}
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::Constructor");
|
|
m_fb_postprocess.resize(4);
|
|
|
|
// in order to prevent calling dtor when doing push_back on m_fb_layers
|
|
// we need to reserve memory, like how much we do expect elements in array (vector)
|
|
// otherwise you will get validation assert in dtor of FramebufferData struct and
|
|
// that validation supposed to be for memory leaks or wrong resource handling (like you forgot to delete resource somehow)
|
|
// if you didn't get it check this: https://en.cppreference.com/w/cpp/container/vector/reserve
|
|
|
|
// otherwise if your default implementation requires more layers by default, thus we have a field at compile-time (or at runtime as dynamic
|
|
// extension) RMLUI_RENDER_BACKEND_OVERRIDE_FIELD_RESERVECOUNT_OF_RENDERSTACK_LAYERS
|
|
m_fb_layers.reserve(RMLUI_RENDER_BACKEND_FIELD_RESERVECOUNT_OF_RENDERSTACK_LAYERS);
|
|
m_p_depth_stencil_for_layers = Rml::MakeUnique<Gfx::FramebufferData>();
|
|
m_p_depth_stencil_for_layers->Set_RenderTarget(false);
|
|
}
|
|
|
|
RenderInterface_DX12::RenderLayerStack::~RenderLayerStack()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::Destructor");
|
|
|
|
m_p_device = nullptr;
|
|
m_p_manager_buffer = nullptr;
|
|
m_p_manager_texture = nullptr;
|
|
m_p_depth_stencil_for_layers.reset();
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderLayerStack::Initialize(RenderInterface_DX12* p_owner)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::Initialize");
|
|
RMLUI_ASSERTMSG(p_owner, "you must pass a valid pointer of RenderInterface_DX12 instance");
|
|
if (p_owner)
|
|
{
|
|
RMLUI_ASSERTMSG(p_owner->Get_TextureManager().Is_Initialized(),
|
|
"early call! you must initialize texture memory manager before calling this method!");
|
|
RMLUI_ASSERTMSG(p_owner->Get_BufferManager().Is_Initialized(),
|
|
"early call! you must initialize buffer memory manager before calling this method!");
|
|
RMLUI_ASSERTMSG(p_owner->Get_Device(), "you must initialize DirectX 12 before calling this method! device is nullptr");
|
|
}
|
|
|
|
if (p_owner)
|
|
{
|
|
m_p_device = p_owner->Get_Device();
|
|
m_p_manager_buffer = &p_owner->Get_BufferManager();
|
|
m_p_manager_texture = &p_owner->Get_TextureManager();
|
|
m_msaa_sample_count = p_owner->Get_MSAASampleCount();
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderLayerStack::Shutdown()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::Shutdown");
|
|
DestroyFramebuffers();
|
|
}
|
|
|
|
Rml::LayerHandle RenderInterface_DX12::RenderLayerStack::PushLayer()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::PushLayer");
|
|
|
|
RMLUI_ASSERTMSG(m_layers_size <= static_cast<int>(m_fb_layers.size()), "overflow of layers!");
|
|
RMLUI_ASSERTMSG(m_p_depth_stencil_for_layers, "must be valid!");
|
|
|
|
if (m_layers_size == static_cast<int>(m_fb_layers.size()))
|
|
{
|
|
if (m_p_depth_stencil_for_layers->Get_Texture() == nullptr)
|
|
{
|
|
CreateFramebuffer(m_p_depth_stencil_for_layers.get(), m_width, m_height, m_msaa_sample_count, true);
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (m_p_depth_stencil_for_layers->Get_Texture())
|
|
{
|
|
wchar_t framebuffer_name[64];
|
|
wsprintf(framebuffer_name, L"framebuffer (layer) shared depth-stencil");
|
|
int index_buffer = m_p_depth_stencil_for_layers->Get_Texture()->Get_Info().buffer_index;
|
|
RMLUI_ASSERTMSG(index_buffer == -1, "you can't allocate framebuffer as placed resource no sense!");
|
|
|
|
if (index_buffer == -1)
|
|
{
|
|
RMLUI_ASSERTMSG(m_p_depth_stencil_for_layers->Get_Texture()->Get_Resource(), "failed to allocate framebuffer!");
|
|
D3D12MA::Allocation* p_committed_resource =
|
|
static_cast<D3D12MA::Allocation*>(m_p_depth_stencil_for_layers->Get_Texture()->Get_Resource());
|
|
|
|
if (p_committed_resource)
|
|
{
|
|
RMLUI_ASSERTMSG(p_committed_resource->GetResource(), "failed to allocate for D3D12MA! (GetResource==nullptr)");
|
|
p_committed_resource->GetResource()->SetName(framebuffer_name);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
m_fb_layers.push_back(Gfx::FramebufferData{});
|
|
auto* p_buffer = &m_fb_layers.back();
|
|
CreateFramebuffer(p_buffer, m_width, m_height, m_msaa_sample_count, false);
|
|
p_buffer->Set_ID(static_cast<int>(m_fb_layers.size() - 1));
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
wchar_t framebuffer_name[32];
|
|
wsprintf(framebuffer_name, L"framebuffer (layer): %d", m_layers_size);
|
|
int index_buffer = p_buffer->Get_Texture()->Get_Info().buffer_index;
|
|
RMLUI_ASSERTMSG(index_buffer == -1, "you can't allocate framebuffer as placed resource no sense!");
|
|
|
|
if (index_buffer == -1)
|
|
{
|
|
RMLUI_ASSERTMSG(p_buffer->Get_Texture()->Get_Resource(), "failed to allocate framebuffer!");
|
|
D3D12MA::Allocation* p_committed_resource = static_cast<D3D12MA::Allocation*>(p_buffer->Get_Texture()->Get_Resource());
|
|
|
|
if (p_committed_resource->GetResource())
|
|
{
|
|
RMLUI_ASSERTMSG(p_committed_resource->GetResource(), "failed to allocate for D3D12MA! (GetResource==nullptr)");
|
|
p_committed_resource->GetResource()->SetName(framebuffer_name);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
p_buffer->Set_SharedDepthStencilTexture(m_p_depth_stencil_for_layers.get());
|
|
}
|
|
|
|
++m_layers_size;
|
|
|
|
return GetTopLayerHandle();
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderLayerStack::PopLayer()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::PopLayer");
|
|
|
|
RMLUI_ASSERTMSG(m_layers_size > 0, "calculations are wrong, debug your code please!");
|
|
m_layers_size -= 1;
|
|
}
|
|
|
|
const Gfx::FramebufferData& RenderInterface_DX12::RenderLayerStack::GetLayer(Rml::LayerHandle layer) const
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::GetLayer");
|
|
|
|
RMLUI_ASSERT(static_cast<size_t>(layer) < static_cast<size_t>(m_layers_size) &&
|
|
"overflow or not correct calculation or something is broken, debug the code!");
|
|
return m_fb_layers.at(static_cast<size_t>(layer));
|
|
}
|
|
|
|
const Gfx::FramebufferData& RenderInterface_DX12::RenderLayerStack::GetTopLayer() const
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::GetTopLayer");
|
|
|
|
RMLUI_ASSERTMSG(m_layers_size > 0, "early calling!");
|
|
return m_fb_layers[m_layers_size - 1];
|
|
}
|
|
|
|
const Gfx::FramebufferData& RenderInterface_DX12::RenderLayerStack::Get_SharedDepthStencil_Layers()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::Get_SharedDepthStencil_Layers");
|
|
|
|
RMLUI_ASSERTMSG(m_p_depth_stencil_for_layers, "early calling!");
|
|
return *m_p_depth_stencil_for_layers;
|
|
}
|
|
|
|
Rml::LayerHandle RenderInterface_DX12::RenderLayerStack::GetTopLayerHandle() const
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::GetTopLayerHandle");
|
|
|
|
RMLUI_ASSERTMSG(m_layers_size > 0, "early calling or something is broken!");
|
|
return static_cast<Rml::LayerHandle>(m_layers_size - 1);
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderLayerStack::SwapPostprocessPrimarySecondary()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::SwapPostprocessPrimarySecondary");
|
|
|
|
std::swap(m_fb_postprocess[0], m_fb_postprocess[1]);
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderLayerStack::BeginFrame(int width_new, int height_new)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::BeginFrame");
|
|
|
|
RMLUI_ASSERTMSG(m_layers_size == 0, "something is wrong and you forgot to clear/delete something!");
|
|
|
|
if (m_width != width_new || m_height != height_new)
|
|
{
|
|
m_width = width_new;
|
|
m_height = height_new;
|
|
|
|
DestroyFramebuffers();
|
|
}
|
|
|
|
PushLayer();
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderLayerStack::EndFrame()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::EndFrame");
|
|
|
|
RMLUI_ASSERTMSG(m_layers_size == 1, "order is wrong or something is broken!");
|
|
PopLayer();
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderLayerStack::DestroyFramebuffers()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::DestroyFramebuffers");
|
|
|
|
RMLUI_ASSERTMSG(m_layers_size == 0, "Do not call this during frame rendering, that is, between BeginFrame() and EndFrame().");
|
|
RMLUI_ASSERTMSG(m_p_manager_texture, "you must initialize this manager or it is a early calling or it is a late calling, debug please!");
|
|
|
|
// deleting shared depth stencil
|
|
|
|
if (m_p_manager_texture)
|
|
{
|
|
if (m_p_depth_stencil_for_layers->Get_Texture())
|
|
{
|
|
m_p_manager_texture->Free_Texture(m_p_depth_stencil_for_layers.get());
|
|
}
|
|
}
|
|
|
|
for (auto& fb : m_fb_layers)
|
|
{
|
|
if (fb.Get_Texture())
|
|
{
|
|
DestroyFramebuffer(&fb);
|
|
}
|
|
}
|
|
|
|
m_fb_layers.clear();
|
|
|
|
for (auto& fb : m_fb_postprocess)
|
|
{
|
|
if (fb.Get_Texture())
|
|
{
|
|
DestroyFramebuffer(&fb);
|
|
}
|
|
}
|
|
}
|
|
|
|
const Gfx::FramebufferData& RenderInterface_DX12::RenderLayerStack::EnsureFramebufferPostprocess(int index)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::EnsureFramebufferPostprocess");
|
|
|
|
RMLUI_ASSERTMSG(index < static_cast<int>(m_fb_postprocess.size()), "overflow or wrong calculation, debug the code!");
|
|
|
|
Gfx::FramebufferData& fb = m_fb_postprocess.at(index);
|
|
|
|
if (!fb.Get_Texture())
|
|
{
|
|
CreateFramebuffer(&fb, m_width, m_height, 1, false);
|
|
fb.Set_ID(index);
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
fb.m_is_allocated_on_stack = false;
|
|
if (fb.Get_Texture())
|
|
{
|
|
wchar_t framebuffer_name[32];
|
|
wsprintf(framebuffer_name, L"framebuffer (postprocess): %d", index);
|
|
int buffer_index = fb.Get_Texture()->Get_Info().buffer_index;
|
|
|
|
RMLUI_ASSERTMSG(buffer_index == -1, "you can't allocate framebuffer as placed resource no sense!");
|
|
if (buffer_index == -1)
|
|
{
|
|
RMLUI_ASSERTMSG(fb.Get_Texture()->Get_Resource(), "must be valid resource failed to allocate!");
|
|
D3D12MA::Allocation* p_alloc = static_cast<D3D12MA::Allocation*>(fb.Get_Texture()->Get_Resource());
|
|
|
|
if (p_alloc)
|
|
{
|
|
ID3D12Resource* p_resource = p_alloc->GetResource();
|
|
RMLUI_ASSERTMSG(p_resource, "failed to allocate for D3D12MA");
|
|
|
|
if (p_resource)
|
|
{
|
|
p_resource->SetName(framebuffer_name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return fb;
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderLayerStack::CreateFramebuffer(Gfx::FramebufferData* p_result, int width, int height, int sample_count,
|
|
bool is_depth_stencil)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::CreateFramebuffer");
|
|
|
|
RMLUI_ASSERTMSG(p_result, "you must pass a valid pointer!");
|
|
RMLUI_ASSERTMSG(sample_count > 0, "you must pass a valid value! it must be positive");
|
|
|
|
RMLUI_ASSERTMSG(width > 0, "pass a valid width!");
|
|
RMLUI_ASSERTMSG(height > 0, "pass a valid height");
|
|
RMLUI_ASSERTMSG(m_p_manager_texture, "you must register manager texture befor calling this method (manager texture is nullptr)");
|
|
if (m_p_manager_texture)
|
|
{
|
|
D3D12_RESOURCE_DESC desc_texture = {};
|
|
|
|
DXGI_FORMAT format{};
|
|
|
|
if (is_depth_stencil)
|
|
format = RMLUI_RENDER_BACKEND_FIELD_DEPTHSTENCIL_TEXTURE_FORMAT;
|
|
else
|
|
format = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
|
|
desc_texture.MipLevels = 1;
|
|
desc_texture.DepthOrArraySize = 1;
|
|
desc_texture.Format = format;
|
|
desc_texture.Width = static_cast<UINT64>(width);
|
|
desc_texture.Height = static_cast<UINT64>(height);
|
|
desc_texture.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
desc_texture.SampleDesc.Count = sample_count;
|
|
desc_texture.SampleDesc.Quality = 0;
|
|
|
|
TextureHandleType* p_resource = new TextureHandleType();
|
|
|
|
RMLUI_ASSERTMSG(p_resource, "[OS][ERROR] not enough memory for allocation!");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (p_resource)
|
|
{
|
|
const char* pWhatTypeOfTexture{};
|
|
|
|
constexpr const char* kHardcodedRenderTargetName = "[RT] ";
|
|
constexpr const char* kHardcodedDepthStencilName = "[DS] ";
|
|
|
|
if (is_depth_stencil)
|
|
pWhatTypeOfTexture = kHardcodedDepthStencilName;
|
|
else
|
|
pWhatTypeOfTexture = kHardcodedRenderTargetName;
|
|
|
|
Rml::String msaa_info;
|
|
|
|
if (sample_count > 1)
|
|
msaa_info = " | MSAA[" + std::to_string(sample_count) + "]";
|
|
|
|
p_resource->Set_ResourceName(pWhatTypeOfTexture + std::string("Render2Texture[") + std::to_string(m_layers_size) + "]" + msaa_info);
|
|
}
|
|
#endif
|
|
|
|
p_result->Set_Width(width);
|
|
p_result->Set_Height(height);
|
|
p_result->Set_Texture(p_resource);
|
|
D3D12_RESOURCE_FLAGS flags{};
|
|
|
|
if (is_depth_stencil)
|
|
flags = D3D12_RESOURCE_FLAGS::D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
|
else
|
|
flags = D3D12_RESOURCE_FLAGS::D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
|
|
D3D12_RESOURCE_STATES states{};
|
|
|
|
if (is_depth_stencil)
|
|
states = D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_DEPTH_WRITE;
|
|
else
|
|
states = D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
const char* pWhatTypeOfTextureForAllocationName{};
|
|
|
|
constexpr const char* kHardcodedNameForDepthStencil = "Render2Texture|Depth-Stencil";
|
|
constexpr const char* kHardcodedNameForRenderTarget = "Render2Texture|Render-Target";
|
|
|
|
if (is_depth_stencil)
|
|
pWhatTypeOfTextureForAllocationName = kHardcodedNameForDepthStencil;
|
|
else
|
|
pWhatTypeOfTextureForAllocationName = kHardcodedNameForRenderTarget;
|
|
#endif
|
|
|
|
m_p_manager_texture->Alloc_Texture(desc_texture, p_result, flags, states
|
|
#ifdef RMLUI_DX_DEBUG
|
|
,
|
|
pWhatTypeOfTextureForAllocationName
|
|
#endif
|
|
);
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderLayerStack::DestroyFramebuffer(Gfx::FramebufferData* p_data)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderLayerStack::DestroyFramebuffer");
|
|
|
|
RMLUI_ASSERTMSG(p_data, "you must pass a valid data");
|
|
RMLUI_ASSERTMSG(m_p_manager_texture, "early/late calling?");
|
|
|
|
if (p_data)
|
|
{
|
|
m_p_manager_texture->Free_Texture(p_data);
|
|
p_data->Set_Width(-1);
|
|
p_data->Set_Height(-1);
|
|
}
|
|
}
|
|
|
|
Rml::LayerHandle RenderInterface_DX12::PushLayer()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - PushLayer");
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "PushLayer");
|
|
|
|
const Rml::LayerHandle layer_handle = m_manager_render_layer.PushLayer();
|
|
|
|
const auto& framebuffer = m_manager_render_layer.GetLayer(layer_handle);
|
|
|
|
RMLUI_ASSERTMSG(framebuffer.Get_SharedDepthStencilTexture(), "you have to set shared depth stencil texture for layer!");
|
|
const auto& shared_depthstencil = *framebuffer.Get_SharedDepthStencilTexture();
|
|
|
|
m_p_command_graphics_list->OMSetRenderTargets(1, &framebuffer.Get_DescriptorResourceView(), FALSE,
|
|
&shared_depthstencil.Get_DescriptorResourceView());
|
|
|
|
constexpr FLOAT clear_color[] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
|
|
m_p_command_graphics_list->ClearRenderTargetView(framebuffer.Get_DescriptorResourceView(), clear_color, 0, nullptr);
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
|
|
return layer_handle;
|
|
}
|
|
|
|
void RenderInterface_DX12::BlitLayerToPostprocessPrimary(Rml::LayerHandle layer_id)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BlitLayerToPostprocessPrimary");
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "BlitLayerToPostprocessPrimary");
|
|
|
|
const Gfx::FramebufferData& source_framebuffer = m_manager_render_layer.GetLayer(layer_id);
|
|
const Gfx::FramebufferData& destination_framebuffer = m_manager_render_layer.GetPostprocessPrimary();
|
|
|
|
RMLUI_ASSERTMSG(source_framebuffer.Get_Texture(), "texture must be presented when you call this method!");
|
|
RMLUI_ASSERTMSG(destination_framebuffer.Get_Texture(), "texture must be presented when you call this method!");
|
|
|
|
RMLUI_ASSERT(source_framebuffer.Get_Texture()->Get_Info().buffer_index == -1 &&
|
|
"expected that this texture was allocated as committed since it is 'framebuffer' ");
|
|
RMLUI_ASSERT(destination_framebuffer.Get_Texture()->Get_Info().buffer_index == -1 &&
|
|
"expected that this texture was allocated as committed since it is 'framebuffer' ");
|
|
|
|
RMLUI_ASSERTMSG(source_framebuffer.Get_Texture()->Get_Resource(), "texture must contain allocated and valid resource!");
|
|
RMLUI_ASSERTMSG(destination_framebuffer.Get_Texture()->Get_Resource(), "texture must contain allocated and valid resource!");
|
|
|
|
ID3D12Resource* p_src = static_cast<D3D12MA::Allocation*>(source_framebuffer.Get_Texture()->Get_Resource())->GetResource();
|
|
ID3D12Resource* p_dst = static_cast<D3D12MA::Allocation*>(destination_framebuffer.Get_Texture()->Get_Resource())->GetResource();
|
|
|
|
RMLUI_ASSERTMSG(p_src, "must be valid && allocated");
|
|
RMLUI_ASSERTMSG(p_dst, "must be valid && allocated");
|
|
|
|
RMLUI_ASSERTMSG(m_p_command_graphics_list, "must be initialized before calling this method");
|
|
|
|
if (!m_p_command_graphics_list)
|
|
return;
|
|
|
|
RMLUI_ASSERTMSG(p_src->GetDesc().Width == p_dst->GetDesc().Width, "must be same otherwise use blitframebuffer");
|
|
RMLUI_ASSERTMSG(p_src->GetDesc().Height == p_dst->GetDesc().Height, "must be same otherwise use blitframebuffer");
|
|
|
|
#if RMLUI_RENDER_BACKEND_FIELD_MSAA_SAMPLE_COUNT > 1
|
|
D3D12_RESOURCE_BARRIER barriers[2];
|
|
barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barriers[0].Transition.pResource = p_src;
|
|
barriers[0].Transition.Subresource = 0;
|
|
barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RESOLVE_SOURCE;
|
|
barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
|
|
barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barriers[1].Transition.pResource = p_dst;
|
|
barriers[1].Transition.Subresource = 0;
|
|
barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_RESOLVE_DEST;
|
|
barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(2, barriers);
|
|
|
|
m_p_command_graphics_list->ResolveSubresource(p_dst, 0, p_src, 0, RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT);
|
|
|
|
barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barriers[0].Transition.pResource = p_dst;
|
|
barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RESOLVE_DEST;
|
|
barriers[0].Transition.Subresource = 0;
|
|
|
|
barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barriers[1].Transition.pResource = p_src;
|
|
barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_RESOLVE_SOURCE;
|
|
barriers[1].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(2, barriers);
|
|
#else
|
|
D3D12_RESOURCE_BARRIER barriers[2];
|
|
barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barriers[0].Transition.pResource = p_src;
|
|
barriers[0].Transition.Subresource = 0;
|
|
barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
|
barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
|
|
barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barriers[1].Transition.pResource = p_dst;
|
|
barriers[1].Transition.Subresource = 0;
|
|
barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(2, barriers);
|
|
|
|
m_p_command_graphics_list->CopyResource(p_dst, p_src);
|
|
|
|
barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barriers[0].Transition.pResource = p_dst;
|
|
barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
barriers[0].Transition.Subresource = 0;
|
|
|
|
barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barriers[1].Transition.pResource = p_src;
|
|
barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
|
barriers[1].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(2, barriers);
|
|
#endif
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
static void SigmaToParameters(const float desired_sigma, int& out_pass_level, float& out_sigma)
|
|
{
|
|
constexpr int max_num_passes = 10;
|
|
static_assert(max_num_passes < 31, "");
|
|
constexpr float max_single_pass_sigma = 3.0f;
|
|
out_pass_level = Rml::Math::Clamp(Rml::Math::Log2(int(desired_sigma * (2.f / max_single_pass_sigma))), 0, max_num_passes);
|
|
out_sigma = Rml::Math::Clamp(desired_sigma / float(1 << out_pass_level), 0.0f, max_single_pass_sigma);
|
|
}
|
|
|
|
void RenderInterface_DX12::DrawFullscreenQuad(ConstantBufferType* p_override_constant_buffer)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - DrawFullscreenQuad()");
|
|
RMLUI_ASSERTMSG(m_p_command_graphics_list, "must be valid!");
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "DrawFullscreenQuad");
|
|
|
|
// actually rml doesn't support anything for by passing custom data as additional argument for RenderGeometry method so
|
|
// some kind of variant for resolving a such situation
|
|
OverrideConstantBufferOfGeometry(m_precompiled_fullscreen_quad_geometry, p_override_constant_buffer);
|
|
|
|
RenderGeometry(m_precompiled_fullscreen_quad_geometry, {}, TexturePostprocess);
|
|
|
|
if (p_override_constant_buffer)
|
|
{
|
|
GeometryHandleType* p_geometry = reinterpret_cast<GeometryHandleType*>(m_precompiled_fullscreen_quad_geometry);
|
|
p_geometry->Reset_ConstantBuffer();
|
|
}
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
void RenderInterface_DX12::DrawFullscreenQuad(Rml::Vector2f uv_offset, Rml::Vector2f uv_scaling, ConstantBufferType* p_override_constant_buffer)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - DrawfullscreenQuad(uv_offset,uv_scaling)");
|
|
RMLUI_ASSERTMSG(m_p_command_graphics_list, "must be valid!");
|
|
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "DrawFullscreenQuad(uv_offset,uv_scaling)");
|
|
|
|
Rml::Mesh mesh;
|
|
Rml::MeshUtilities::GenerateQuad(mesh, Rml::Vector2f(-1), Rml::Vector2f(2), {});
|
|
if (uv_offset != Rml::Vector2f() || uv_scaling != Rml::Vector2f(1.f))
|
|
{
|
|
for (Rml::Vertex& vertex : mesh.vertices)
|
|
vertex.tex_coord = (vertex.tex_coord * uv_scaling) + uv_offset;
|
|
}
|
|
Rml::CompiledGeometryHandle geometry = CompileGeometry(mesh.vertices, mesh.indices);
|
|
|
|
OverrideConstantBufferOfGeometry(geometry, p_override_constant_buffer);
|
|
|
|
RenderGeometry(geometry, {}, TexturePostprocess);
|
|
ReleaseGeometry(geometry);
|
|
|
|
if (p_override_constant_buffer)
|
|
{
|
|
GeometryHandleType* p_geometry = reinterpret_cast<GeometryHandleType*>(geometry);
|
|
p_geometry->Reset_ConstantBuffer();
|
|
}
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
void RenderInterface_DX12::BindTexture(TextureHandleType* p_texture, UINT root_parameter_index)
|
|
{
|
|
RMLUI_ASSERTMSG(p_texture, "you have to pass a valid pointer!");
|
|
RMLUI_ASSERTMSG(m_p_command_graphics_list, "early calling must be initialized before calling this method!");
|
|
RMLUI_ASSERTMSG(m_p_descriptor_heap_shaders, "early calling must be initialzed before calling this method!");
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "BindTexture");
|
|
|
|
if (m_p_command_graphics_list)
|
|
{
|
|
if (p_texture)
|
|
{
|
|
if (m_p_descriptor_heap_shaders)
|
|
{
|
|
D3D12_GPU_DESCRIPTOR_HANDLE srv_handle;
|
|
srv_handle.ptr =
|
|
m_p_descriptor_heap_shaders->GetGPUDescriptorHandleForHeapStart().ptr + p_texture->Get_Allocation_DescriptorHeap().offset;
|
|
|
|
m_p_command_graphics_list->SetGraphicsRootDescriptorTable(root_parameter_index, srv_handle);
|
|
}
|
|
}
|
|
}
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
void RenderInterface_DX12::BindRenderTarget(const Gfx::FramebufferData& framebuffer, bool depth_included)
|
|
{
|
|
RMLUI_ASSERTMSG(m_p_command_graphics_list, "early calling must be initialized before calling this method!");
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "BindRenderTarget");
|
|
|
|
if (m_p_command_graphics_list)
|
|
{
|
|
const D3D12_CPU_DESCRIPTOR_HANDLE* p_dsv_handle = nullptr;
|
|
|
|
if (depth_included)
|
|
{
|
|
RMLUI_ASSERTMSG(framebuffer.Get_SharedDepthStencilTexture(), "expects that it was allocated and set to render target textures!");
|
|
p_dsv_handle = &framebuffer.Get_SharedDepthStencilTexture()->Get_DescriptorResourceView();
|
|
}
|
|
|
|
const D3D12_CPU_DESCRIPTOR_HANDLE* p_rtv_handle = &framebuffer.Get_DescriptorResourceView();
|
|
|
|
m_p_command_graphics_list->OMSetRenderTargets(1, p_rtv_handle, FALSE, p_dsv_handle);
|
|
}
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
void RenderInterface_DX12::OverrideConstantBufferOfGeometry(Rml::CompiledGeometryHandle geometry, ConstantBufferType* p_override_constant_buffer)
|
|
{
|
|
if (p_override_constant_buffer)
|
|
{
|
|
GeometryHandleType* p_geometry = reinterpret_cast<GeometryHandleType*>(geometry);
|
|
p_geometry->Set_ConstantBuffer(p_override_constant_buffer);
|
|
|
|
switch (m_active_program_id)
|
|
{
|
|
case ProgramId::Blur:
|
|
{
|
|
// this for vertex shader
|
|
p_geometry->Add_ConstantBufferRootParameterIndices(1);
|
|
|
|
// this for pixel shader
|
|
p_geometry->Add_ConstantBufferRootParameterIndices(2);
|
|
|
|
// so we can't combine and use one root parameters for pixel and vertex shader even if we use same CBV so yeah...
|
|
|
|
break;
|
|
}
|
|
case ProgramId::DropShadow:
|
|
{
|
|
// for pixel shader
|
|
p_geometry->Add_ConstantBufferRootParameterIndices(1);
|
|
|
|
break;
|
|
}
|
|
case ProgramId::ColorMatrix:
|
|
{
|
|
// for pixel shader
|
|
p_geometry->Add_ConstantBufferRootParameterIndices(1);
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
RMLUI_ASSERT(!"FATAL YOU FORGOT TO REGISTER CONSTANT BUFFER OVERRIDE SITUATION!");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned char RenderInterface_DX12::GetMSAASupportedSampleCount(unsigned char max_samples)
|
|
{
|
|
RMLUI_ASSERTMSG(m_p_device, "early calling this must be initialized before calling!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
#ifdef RMLUI_DX_DEBUG
|
|
bool sample_counts[64]{};
|
|
#endif
|
|
|
|
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS desc{};
|
|
desc.SampleCount = static_cast<UINT>(max_samples);
|
|
desc.Format = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
|
|
|
|
unsigned char max_result = 1;
|
|
|
|
while (desc.SampleCount > 1)
|
|
{
|
|
HRESULT result = m_p_device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &desc, sizeof(desc));
|
|
|
|
if (SUCCEEDED(result))
|
|
{
|
|
#ifdef RMLUI_DX_DEBUG
|
|
sample_counts[desc.SampleCount - 1] = true;
|
|
#endif
|
|
|
|
if (desc.SampleCount > max_result)
|
|
{
|
|
RMLUI_ASSERT(desc.SampleCount <= std::numeric_limits<unsigned char>::max() &&
|
|
"report to developers, it is serious but in reality > 32 is not realistic at all");
|
|
max_result = static_cast<unsigned char>(desc.SampleCount);
|
|
}
|
|
|
|
#ifndef RMLUI_DX_DEBUG
|
|
// on debug we accumulate information about all possible (for debug purposes) max sample sample_counts[0] = false always be false due
|
|
// to sample count checking in while loop
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
--desc.SampleCount;
|
|
}
|
|
|
|
return max_result;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void RenderInterface_DX12::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)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BlitFramebuffer");
|
|
RMLUI_ASSERTMSG(m_p_command_graphics_list, "must be initialized renderer before calling this method!");
|
|
|
|
if (!m_p_command_graphics_list)
|
|
return;
|
|
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "BlitFramebuffer");
|
|
|
|
int src_width = srcX1 - srcX0;
|
|
int src_height = srcY1 - srcY0;
|
|
int dest_width = dstX1 - dstX0;
|
|
int dest_height = dstY1 - dstY0;
|
|
|
|
bool is_flipped = src_width < 0 || src_height < 0 || dest_width < 0 || dest_height < 0;
|
|
bool is_stretched = src_width != dest_width || src_height != dest_height;
|
|
bool is_full_copy = src_width == dest_width && src_height == dest_height && srcX0 == 0 && srcY0 == 0 && dstX0 == 0 && dstY0 == 0;
|
|
|
|
if (is_flipped || is_stretched || !is_full_copy)
|
|
{
|
|
// Full draw call. Slow path because no equivalent in DX12
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
TextureHandleType* p_texture_source = source.Get_Texture();
|
|
TextureHandleType* p_texture_destination = dest.Get_Texture();
|
|
|
|
RMLUI_ASSERTMSG(p_texture_source, "must be valid pointer!");
|
|
RMLUI_ASSERTMSG(p_texture_destination, "must be valid pointer!");
|
|
|
|
RMLUI_ASSERT(p_texture_source->Get_Info().buffer_index == -1 &&
|
|
"expected that a such texture was allocated as committed (e.g. not placed resource), so in that case you can't cast to "
|
|
"D3D12MA::Allocation");
|
|
RMLUI_ASSERT(p_texture_destination->Get_Info().buffer_index == -1 &&
|
|
"expected that a such texture was allocated as committed (e.g. not placed resource) so in that case you can't cast to "
|
|
"D3D12MA::Allocation");
|
|
|
|
RMLUI_ASSERTMSG(p_texture_source->Get_Resource(), "must contain a valid resource");
|
|
RMLUI_ASSERTMSG(p_texture_destination->Get_Resource(), "must contain a valid resource");
|
|
|
|
D3D12MA::Allocation* p_allocation_source = static_cast<D3D12MA::Allocation*>(p_texture_source->Get_Resource());
|
|
D3D12MA::Allocation* p_allocation_destination = static_cast<D3D12MA::Allocation*>(p_texture_destination->Get_Resource());
|
|
|
|
RMLUI_ASSERTMSG(p_allocation_source->GetResource(), "allocation must contain a valid pointer to resource! something is broken");
|
|
RMLUI_ASSERTMSG(p_allocation_destination->GetResource(), "allocation must contain a valid pointer to resource! something is broken");
|
|
|
|
ID3D12Resource* p_resource_src = p_allocation_source->GetResource();
|
|
ID3D12Resource* p_resource_dst = p_allocation_destination->GetResource();
|
|
|
|
const D3D12_RESOURCE_DESC& desc_source = p_resource_src->GetDesc();
|
|
const D3D12_RESOURCE_DESC& desc_dest = p_resource_dst->GetDesc();
|
|
|
|
RMLUI_ASSERTMSG(desc_source.SampleDesc.Count <= 1, "expected only NO MSAA texture (source)");
|
|
RMLUI_ASSERTMSG(desc_dest.SampleDesc.Count <= 1, "expected only NO MSAA texture (dest)");
|
|
#endif
|
|
|
|
D3D12_VIEWPORT vp{};
|
|
vp.TopLeftX = 0;
|
|
vp.TopLeftY = 0;
|
|
vp.Width = (float)dest.Get_Width();
|
|
vp.Height = (float)dest.Get_Height();
|
|
vp.MinDepth = 0.0f;
|
|
vp.MaxDepth = 1.0f;
|
|
|
|
m_p_command_graphics_list->RSSetViewports(1, &vp);
|
|
|
|
UseProgram(ProgramId::Passthrough_NoBlendAndNoMSAA);
|
|
|
|
BindRenderTarget(dest, false);
|
|
BindTexture(source.Get_Texture());
|
|
|
|
float uv_x_min = float(srcX0) / float(source.Get_Width()); // Map to 0
|
|
float uv_y_max = float(srcY0) / float(source.Get_Height()); // Map to 0
|
|
float uv_x_max = float(srcX1) / float(source.Get_Width()); // Map to +1
|
|
float uv_y_min = float(srcY1) / float(source.Get_Height()); // Map to +1
|
|
|
|
float pos_x_min = (dstX0 / float(dest.Get_Width())) * 2.0f - 1.0f;
|
|
float pos_y_min = ((dest.Get_Height() - dstY0 - dest_height) / float(dest.Get_Height())) * 2.0f - 1.0f;
|
|
float pos_x_max = ((dstX0 + dest_width) / float(dest.Get_Width())) * 2.0f - 1.0f;
|
|
float pos_y_max = ((dest.Get_Height() - dstY0) / float(dest.Get_Height())) * 2.0f - 1.0f;
|
|
|
|
Rml::Array<Rml::Vertex, 4> vertices;
|
|
constexpr int indices[6]{0, 3, 1, 1, 3, 2};
|
|
|
|
vertices[0].position.x = pos_x_min;
|
|
vertices[0].position.y = pos_y_min;
|
|
vertices[0].tex_coord.x = uv_x_min;
|
|
vertices[0].tex_coord.y = uv_y_min;
|
|
|
|
vertices[1].position.x = pos_x_max;
|
|
vertices[1].position.y = pos_y_min;
|
|
vertices[1].tex_coord.x = uv_x_max;
|
|
vertices[1].tex_coord.y = uv_y_min;
|
|
|
|
vertices[2].position.x = pos_x_max;
|
|
vertices[2].position.y = pos_y_max;
|
|
vertices[2].tex_coord.x = uv_x_max;
|
|
vertices[2].tex_coord.y = uv_y_max;
|
|
|
|
vertices[3].position.x = pos_x_min;
|
|
vertices[3].position.y = pos_y_max;
|
|
vertices[3].tex_coord.x = uv_x_min;
|
|
vertices[3].tex_coord.y = uv_y_max;
|
|
|
|
const Rml::CompiledGeometryHandle geometry =
|
|
CompileGeometry({&vertices[0], sizeof(vertices) / sizeof(vertices[0])}, {&indices[0], sizeof(indices) / sizeof(indices[0])});
|
|
|
|
RenderGeometry(geometry, {}, TexturePostprocess);
|
|
ReleaseGeometry(geometry);
|
|
}
|
|
else
|
|
{
|
|
RMLUI_ASSERT(!"use resolvesubresource manually! don't call this method for handling resolvesubresource!!!");
|
|
}
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
void RenderInterface_DX12::ValidateTextureAllocationNotAsPlaced(const Gfx::FramebufferData& source)
|
|
{
|
|
#ifdef RMLUI_DX_DEBUG
|
|
|
|
TextureHandleType* p_texture_source = source.Get_Texture();
|
|
|
|
RMLUI_ASSERTMSG(p_texture_source, "must be valid pointer!");
|
|
|
|
RMLUI_ASSERT(p_texture_source->Get_Info().buffer_index == -1 &&
|
|
"expected that a such texture was allocated as committed (e.g. not placed resource), so in that case you can't cast to "
|
|
"D3D12MA::Allocation");
|
|
|
|
RMLUI_ASSERTMSG(p_texture_source->Get_Resource(), "must contain a valid resource");
|
|
|
|
D3D12MA::Allocation* p_allocation_source = static_cast<D3D12MA::Allocation*>(p_texture_source->Get_Resource());
|
|
|
|
RMLUI_ASSERTMSG(p_allocation_source->GetResource(), "allocation must contain a valid pointer to resource! something is broken");
|
|
#else
|
|
(void)source;
|
|
#endif
|
|
}
|
|
|
|
ID3D12Resource* RenderInterface_DX12::GetResourceFromFramebufferData(const Gfx::FramebufferData& data)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - GetResourceFromFramebufferData");
|
|
ID3D12Resource* p_result{};
|
|
|
|
TextureHandleType* p_texture_source = data.Get_Texture();
|
|
|
|
if (p_texture_source == nullptr)
|
|
return p_result;
|
|
|
|
if (p_texture_source->Get_Info().buffer_index == -1)
|
|
{
|
|
// committed
|
|
|
|
if (p_texture_source->Get_Resource() == nullptr)
|
|
return p_result;
|
|
|
|
D3D12MA::Allocation* p_allocation_source = static_cast<D3D12MA::Allocation*>(p_texture_source->Get_Resource());
|
|
|
|
if (p_allocation_source == nullptr)
|
|
return p_result;
|
|
|
|
if (p_allocation_source->GetResource() == nullptr)
|
|
return p_result;
|
|
|
|
p_result = p_allocation_source->GetResource();
|
|
}
|
|
else
|
|
{
|
|
// placed
|
|
|
|
if (p_texture_source->Get_Resource() == nullptr)
|
|
return p_result;
|
|
|
|
p_result = static_cast<ID3D12Resource*>(p_texture_source->Get_Resource());
|
|
}
|
|
|
|
return p_result;
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderBlur(float sigma, const Gfx::FramebufferData& source_destination, const Gfx::FramebufferData& temp,
|
|
const Rml::Rectanglei window_flipped)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderBlur");
|
|
RMLUI_ASSERTMSG(&source_destination != &temp, "you can't pass the same object to source_destination and temp arguments!");
|
|
RMLUI_ASSERTMSG(source_destination.Get_Width() == temp.Get_Width(), "must be equal to the same size!");
|
|
RMLUI_ASSERTMSG(source_destination.Get_Height() == temp.Get_Height(), "must be equal to the same size!");
|
|
RMLUI_ASSERTMSG(window_flipped.Valid(), "must be valid!");
|
|
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "RenderBlur");
|
|
|
|
int pass_level = 0;
|
|
SigmaToParameters(sigma, pass_level, sigma);
|
|
|
|
if (sigma == 0)
|
|
return;
|
|
|
|
const Rml::Rectanglei original_scissor = m_scissor;
|
|
Rml::Rectanglei scissor = window_flipped;
|
|
|
|
// probably we expect only textures with sample count = 1 otherwise it is MSAA and we should dynamically determine which pipeline state we should
|
|
// use in UseProgram method
|
|
UseProgram(ProgramId::Passthrough_NoBlendAndNoMSAA);
|
|
SetScissor(scissor, true);
|
|
|
|
D3D12_VIEWPORT vp{};
|
|
|
|
vp.TopLeftX = 0;
|
|
vp.TopLeftY = source_destination.Get_Height() / 2.0f;
|
|
vp.Width = source_destination.Get_Width() / 2.0f;
|
|
vp.Height = source_destination.Get_Height() / 2.0f;
|
|
vp.MinDepth = 0.0f;
|
|
vp.MaxDepth = 1.0f;
|
|
|
|
m_p_command_graphics_list->RSSetViewports(1, &vp);
|
|
|
|
const Rml::Vector2f uv_scaling = {(source_destination.Get_Width() % 2 == 1) ? (1.f - 1.f / float(source_destination.Get_Width())) : 1.f,
|
|
(source_destination.Get_Height() % 2 == 1) ? (1.f - 1.f / float(source_destination.Get_Height())) : 1.f};
|
|
|
|
ID3D12Resource* p_resource{};
|
|
|
|
// be careful! runtime dx changes this thing BUT argument for ResourceBarrier is CONST IDK how they do in their API but def they change that by
|
|
// themselves or somehow corrupt the inner data and it is kinda sad SO what i want to say that you have to initialize all fields that are required
|
|
// for passing to resource barrier method calling!!!
|
|
// if you have a such long situation and you want to pass just using one variable on stack...
|
|
D3D12_RESOURCE_BARRIER bars[1];
|
|
for (int i = 0; i < pass_level; i++)
|
|
{
|
|
scissor.p0 = (scissor.p0 + Rml::Vector2i(1)) / 2;
|
|
scissor.p1 = Rml::Math::Max(scissor.p1 / 2, scissor.p0);
|
|
const bool from_source = (i % 2 == 0);
|
|
|
|
BindRenderTarget(from_source ? temp : source_destination, false);
|
|
|
|
RenderInterface_DX12::TextureHandleType* p_texture = nullptr;
|
|
|
|
if (from_source)
|
|
{
|
|
// we expect only committed allocated resources
|
|
ValidateTextureAllocationNotAsPlaced(source_destination);
|
|
p_resource = GetResourceFromFramebufferData(source_destination);
|
|
RMLUI_ASSERTMSG(p_resource, "failed to obtain resource from source_destination framebuffer!");
|
|
}
|
|
else
|
|
{
|
|
// we expect only committed allocated resources
|
|
ValidateTextureAllocationNotAsPlaced(temp);
|
|
p_resource = GetResourceFromFramebufferData(temp);
|
|
RMLUI_ASSERTMSG(p_resource, "failed to obtain resource from source_destination framebuffer!");
|
|
}
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = p_resource;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
|
|
p_texture = from_source ? source_destination.Get_Texture() : temp.Get_Texture();
|
|
RMLUI_ASSERTMSG(p_texture, "must be valid!");
|
|
|
|
BindTexture(p_texture);
|
|
|
|
SetScissor(scissor, true);
|
|
|
|
DrawFullscreenQuad({}, uv_scaling);
|
|
|
|
if (from_source)
|
|
{
|
|
// we expect only committed allocated resources
|
|
ValidateTextureAllocationNotAsPlaced(source_destination);
|
|
RMLUI_ATTR_ASSERT_VARIABLE ID3D12Resource* p_resource_sd = GetResourceFromFramebufferData(source_destination);
|
|
RMLUI_ASSERTMSG(p_resource_sd, "failed to obtain resource from source_destination framebuffer!");
|
|
}
|
|
else
|
|
{
|
|
// we expect only committed allocated resources
|
|
ValidateTextureAllocationNotAsPlaced(temp);
|
|
RMLUI_ATTR_ASSERT_VARIABLE ID3D12Resource* p_resource_t = GetResourceFromFramebufferData(temp);
|
|
RMLUI_ASSERTMSG(p_resource_t, "failed to obtain resource from temp framebuffer!");
|
|
}
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = p_resource;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
|
|
vp.TopLeftX = 0;
|
|
vp.TopLeftY = 0;
|
|
vp.Width = static_cast<FLOAT>(source_destination.Get_Width());
|
|
vp.Height = static_cast<FLOAT>(source_destination.Get_Height());
|
|
vp.MinDepth = 0.0f;
|
|
vp.MaxDepth = 1.0f;
|
|
|
|
m_p_command_graphics_list->RSSetViewports(1, &vp);
|
|
const bool transfer_to_temp_buffer = (pass_level % 2 == 0);
|
|
|
|
if (transfer_to_temp_buffer)
|
|
{
|
|
BindRenderTarget(temp, false);
|
|
|
|
RenderInterface_DX12::TextureHandleType* p_texture = source_destination.Get_Texture();
|
|
RMLUI_ASSERTMSG(p_texture, "must be valid!");
|
|
|
|
p_resource = GetResourceFromFramebufferData(source_destination);
|
|
RMLUI_ASSERTMSG(p_resource, "failed to obtain resource from framebuffer source_destination");
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.pResource = p_resource;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
|
|
BindTexture(p_texture);
|
|
|
|
DrawFullscreenQuad();
|
|
}
|
|
|
|
UseProgram(ProgramId::Blur);
|
|
|
|
ConstantBufferType* p_cb = Get_ConstantBuffer(m_current_back_buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_cb, "unable to allocate constant buffer for blur!");
|
|
std::uint8_t* p_cb_begin = reinterpret_cast<std::uint8_t*>(p_cb->m_p_gpu_start_memory_for_binding_data);
|
|
|
|
RMLUI_ASSERTMSG(p_cb_begin, "must be valid pointer of buffer where CB was allocated!");
|
|
|
|
std::uint8_t* p_cb_real_begin = p_cb_begin + p_cb->m_alloc_info.offset + sizeof(m_constant_buffer_data_transform) + sizeof(Rml::Vector2f);
|
|
|
|
// sadly but here we can't optimize and upload directly using pointer from GPU
|
|
// keep allocating on stack still fastest way possible to handle a such small data for uploading :)
|
|
struct {
|
|
Rml::Vector2f texel_offset;
|
|
Rml::Vector4f weights;
|
|
Rml::Vector2f texcoord_min;
|
|
Rml::Vector2f texcoord_max;
|
|
} ShaderConstantBufferMapping_Blur;
|
|
|
|
SetBlurWeights(ShaderConstantBufferMapping_Blur.weights, sigma);
|
|
SetTexCoordLimits(ShaderConstantBufferMapping_Blur.texcoord_min, ShaderConstantBufferMapping_Blur.texcoord_max, scissor,
|
|
{source_destination.Get_Width(), source_destination.Get_Height()});
|
|
|
|
ShaderConstantBufferMapping_Blur.texel_offset = Rml::Vector2f(0.f, 1.f) * (1.0f / float(temp.Get_Height()));
|
|
|
|
std::memcpy(p_cb_real_begin, &ShaderConstantBufferMapping_Blur, sizeof(ShaderConstantBufferMapping_Blur));
|
|
|
|
if (transfer_to_temp_buffer)
|
|
{
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = GetResourceFromFramebufferData(source_destination);
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
|
|
BindRenderTarget(source_destination, false);
|
|
|
|
p_resource = GetResourceFromFramebufferData(temp);
|
|
RMLUI_ASSERTMSG(p_resource, "failed to obtain resource from framebuffer temp!");
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = p_resource;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
|
|
BindTexture(temp.Get_Texture());
|
|
DrawFullscreenQuad(p_cb);
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.Subresource = 0;
|
|
bars[0].Transition.pResource = GetResourceFromFramebufferData(temp);
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
|
|
BindRenderTarget(temp, false);
|
|
|
|
p_resource = GetResourceFromFramebufferData(source_destination);
|
|
RMLUI_ASSERTMSG(p_resource, "failed to obtain resource from framebuffer source_destination");
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = p_resource;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
|
|
BindTexture(source_destination.Get_Texture());
|
|
|
|
// Add a 1px transparent border around the blur region by first clearing with a padded scissor. This helps prevent
|
|
// artifacts when upscaling the blur result in the later step. On Intel and AMD, we have observed that during
|
|
// blitting with linear filtering, pixels outside the 'src' region can be blended into the output. On the other
|
|
// hand, it looks like Nvidia clamps the pixels to the source edge, which is what we really want. Regardless, we
|
|
// work around the issue with this extra step.
|
|
SetScissor(scissor.Extend(1), true);
|
|
|
|
Rml::Rectanglei scissor_ext = scissor.Extend(1);
|
|
scissor_ext = VerticallyFlipped(scissor_ext, m_height);
|
|
|
|
// Some render APIs don't like offscreen positions (WebGL in particular), so clamp them to the viewport.
|
|
const int x_min = Rml::Math::Clamp(scissor_ext.Left(), 0, m_width);
|
|
const int y_min = Rml::Math::Clamp(scissor_ext.Top(), 0, m_height);
|
|
const int x_max = Rml::Math::Clamp(scissor_ext.Right(), 0, m_width);
|
|
const int y_max = Rml::Math::Clamp(scissor_ext.Bottom(), 0, m_height);
|
|
|
|
D3D12_RECT rect_scissor{};
|
|
rect_scissor.left = x_min;
|
|
rect_scissor.top = y_min;
|
|
rect_scissor.right = x_max;
|
|
rect_scissor.bottom = y_max;
|
|
|
|
constexpr FLOAT clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
|
|
m_p_command_graphics_list->ClearRenderTargetView(temp.Get_DescriptorResourceView(), clear_color, 1, &rect_scissor);
|
|
SetScissor(scissor, true);
|
|
|
|
ShaderConstantBufferMapping_Blur.texel_offset = Rml::Vector2f(1.0f, 0.0f) * (1.0f / float(source_destination.Get_Width()));
|
|
|
|
p_cb = Get_ConstantBuffer(m_current_back_buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_cb, "unable to allocate constant buffer for blur!");
|
|
p_cb_begin = reinterpret_cast<std::uint8_t*>(p_cb->m_p_gpu_start_memory_for_binding_data);
|
|
|
|
RMLUI_ASSERTMSG(p_cb_begin, "must be valid pointer of buffer where CB was allocated!");
|
|
|
|
p_cb_real_begin = p_cb_begin + p_cb->m_alloc_info.offset + sizeof(m_constant_buffer_data_transform) + sizeof(Rml::Vector2f);
|
|
std::memcpy(p_cb_real_begin, &ShaderConstantBufferMapping_Blur, sizeof(ShaderConstantBufferMapping_Blur));
|
|
DrawFullscreenQuad(p_cb);
|
|
|
|
p_resource = GetResourceFromFramebufferData(temp);
|
|
RMLUI_ASSERTMSG(p_resource, "failed to obtain resource from framebuffer temp");
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = p_resource;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
|
|
p_resource = GetResourceFromFramebufferData(source_destination);
|
|
RMLUI_ASSERTMSG(p_resource, "failed to obtain resource from framebuffer source_destination");
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = p_resource;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
|
|
// Blit the blurred image to the scissor region with upscaling.
|
|
Rml::Rectanglei window_flipped_twice = VerticallyFlipped(window_flipped, m_height);
|
|
SetScissor(window_flipped_twice, false);
|
|
|
|
const Rml::Vector2i src_min = scissor.p0;
|
|
const Rml::Vector2i src_max = scissor.p1;
|
|
const Rml::Vector2i dst_min = window_flipped_twice.p0;
|
|
const Rml::Vector2i dst_max = window_flipped_twice.p1;
|
|
|
|
BlitFramebuffer(temp, source_destination, src_min.x, src_min.y, src_max.x, src_max.y, dst_min.x, dst_max.y, dst_max.x, dst_min.y);
|
|
|
|
// DirectX 12 implementation notice: The following note is not implemented for this renderer, see the OpenGL 3 reference for details.
|
|
// The above upscale blit might be jittery at low resolutions (large pass levels). This is especially noticeable
|
|
// when moving an element with backdrop blur around or when trying to click/hover an element within a blurred
|
|
// region since it may be rendered at an offset. For more stable and accurate rendering we next upscale the blur
|
|
// image by an exact power-of-two. However, this may not fill the edges completely so we need to do the above
|
|
// first. Note that this strategy may sometimes result in visible seams. Alternatively, we could try to enlarge
|
|
// the window to the next power-of-two size and then downsample and blur that.
|
|
|
|
p_resource = GetResourceFromFramebufferData(temp);
|
|
RMLUI_ASSERTMSG(p_resource, "failed to obtain resource from framebuffer temp");
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = p_resource;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
|
|
// restore things
|
|
D3D12_VIEWPORT viewport{};
|
|
viewport.Height = static_cast<FLOAT>(m_height);
|
|
viewport.Width = static_cast<FLOAT>(m_width);
|
|
viewport.MaxDepth = 1.0f;
|
|
m_p_command_graphics_list->RSSetViewports(1, &viewport);
|
|
SetScissor(original_scissor);
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderFilters(Rml::Span<const Rml::CompiledFilterHandle> filter_handles)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderFilters");
|
|
|
|
for (const Rml::CompiledFilterHandle filter_handle : filter_handles)
|
|
{
|
|
const CompiledFilter& filter = *reinterpret_cast<const CompiledFilter*>(filter_handle);
|
|
const FilterType type = filter.type;
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
const auto filter_type_to_string = [](FilterType type) -> const char* {
|
|
switch (type)
|
|
{
|
|
case FilterType::Invalid: return "Invalid";
|
|
case FilterType::Passthrough: return "Passthrough";
|
|
case FilterType::Blur: return "Blur";
|
|
case FilterType::DropShadow: return "DropShadow";
|
|
case FilterType::ColorMatrix: return "ColorMatrix";
|
|
case FilterType::MaskImage: return "MaskImage";
|
|
default: return "UnknownFilterType";
|
|
}
|
|
};
|
|
const auto marker_name = Rml::CreateString("RenderFilter=%s", filter_type_to_string(type));
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, marker_name.c_str());
|
|
#endif
|
|
|
|
switch (type)
|
|
{
|
|
case FilterType::Passthrough:
|
|
{
|
|
const Gfx::FramebufferData& source = m_manager_render_layer.GetPostprocessPrimary();
|
|
const Gfx::FramebufferData& destination = m_manager_render_layer.GetPostprocessSecondary();
|
|
|
|
TextureHandleType* p_texture_source = source.Get_Texture();
|
|
TextureHandleType* p_texture_destination = destination.Get_Texture();
|
|
|
|
RMLUI_ASSERTMSG(p_texture_source, "must be valid pointer!");
|
|
RMLUI_ASSERTMSG(p_texture_destination, "must be valid pointer!");
|
|
|
|
RMLUI_ASSERT(p_texture_source->Get_Info().buffer_index == -1 &&
|
|
"expected that a such texture was allocated as committed (e.g. not placed resource), so in that case you can't cast to "
|
|
"D3D12MA::Allocation");
|
|
RMLUI_ASSERT(p_texture_destination->Get_Info().buffer_index == -1 &&
|
|
"expected that a such texture was allocated as committed (e.g. not placed resource) so in that case you can't cast to "
|
|
"D3D12MA::Allocation");
|
|
|
|
RMLUI_ASSERTMSG(p_texture_source->Get_Resource(), "must contain a valid resource");
|
|
RMLUI_ASSERTMSG(p_texture_destination->Get_Resource(), "must contain a valid resource");
|
|
|
|
D3D12MA::Allocation* p_allocation_source = static_cast<D3D12MA::Allocation*>(p_texture_source->Get_Resource());
|
|
RMLUI_ATTR_ASSERT_VARIABLE D3D12MA::Allocation* p_allocation_destination =
|
|
static_cast<D3D12MA::Allocation*>(p_texture_destination->Get_Resource());
|
|
|
|
RMLUI_ASSERTMSG(p_allocation_source->GetResource(), "allocation must contain a valid pointer to resource! something is broken");
|
|
RMLUI_ASSERTMSG(p_allocation_destination->GetResource(), "allocation must contain a valid pointer to resource! something is broken");
|
|
|
|
ID3D12Resource* p_resource_as_srv = p_allocation_source->GetResource();
|
|
|
|
BindRenderTarget(destination, false);
|
|
|
|
const FLOAT blend_factor[] = {filter.blend_factor, filter.blend_factor, filter.blend_factor, filter.blend_factor};
|
|
m_p_command_graphics_list->OMSetBlendFactor(blend_factor);
|
|
|
|
UseProgram(ProgramId::Passthrough_Opacity);
|
|
|
|
{
|
|
D3D12_RESOURCE_BARRIER bars[1];
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = p_resource_as_srv;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
|
|
BindTexture(p_texture_source);
|
|
DrawFullscreenQuad();
|
|
|
|
{
|
|
D3D12_RESOURCE_BARRIER bars[1];
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = p_resource_as_srv;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
|
|
m_manager_render_layer.SwapPostprocessPrimarySecondary();
|
|
|
|
break;
|
|
}
|
|
case FilterType::Blur:
|
|
{
|
|
const Gfx::FramebufferData& source = m_manager_render_layer.GetPostprocessPrimary();
|
|
const Gfx::FramebufferData& temp = m_manager_render_layer.GetPostprocessSecondary();
|
|
|
|
const Rml::Rectanglei window_flipped = VerticallyFlipped(m_scissor, m_height);
|
|
RenderBlur(filter.sigma, source, temp, window_flipped);
|
|
break;
|
|
}
|
|
case FilterType::DropShadow:
|
|
{
|
|
UseProgram(ProgramId::DropShadow);
|
|
|
|
const Gfx::FramebufferData& primary = m_manager_render_layer.GetPostprocessPrimary();
|
|
const Gfx::FramebufferData& secondary = m_manager_render_layer.GetPostprocessSecondary();
|
|
|
|
BindRenderTarget(secondary, false);
|
|
|
|
ValidateTextureAllocationNotAsPlaced(primary);
|
|
|
|
{
|
|
ID3D12Resource* pPrimaryResource = GetResourceFromFramebufferData(primary);
|
|
RMLUI_ASSERTMSG(pPrimaryResource, "framebuffer primary doesn't contain a valid resource for barrier transition!");
|
|
|
|
D3D12_RESOURCE_BARRIER bars[1];
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = pPrimaryResource;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.Subresource = 0;
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
|
|
BindTexture(primary.Get_Texture());
|
|
|
|
ConstantBufferType* p_cb_dropshadow = Get_ConstantBuffer(m_current_back_buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_cb_dropshadow, "failed to obtain constant buffer for drop shadow");
|
|
|
|
struct CBV_DropShadow {
|
|
Rml::Vector2f uv_min;
|
|
Rml::Vector2f uv_max;
|
|
Rml::Vector4f color;
|
|
};
|
|
|
|
CBV_DropShadow* pUploadingData = nullptr;
|
|
if (p_cb_dropshadow)
|
|
{
|
|
std::uint8_t* p_gpu_begin = reinterpret_cast<std::uint8_t*>(p_cb_dropshadow->m_p_gpu_start_memory_for_binding_data);
|
|
RMLUI_ASSERTMSG(p_gpu_begin, "constant buffer must contain information about its GPU location (pointer for data binding/uploading)");
|
|
|
|
if (p_gpu_begin)
|
|
{
|
|
std::uint8_t* p_gpu_real_begin = p_gpu_begin + p_cb_dropshadow->m_alloc_info.offset;
|
|
RMLUI_ASSERTMSG(p_gpu_real_begin, "failed to apply offset for gpu pointer");
|
|
|
|
if (p_gpu_real_begin)
|
|
{
|
|
pUploadingData = reinterpret_cast<CBV_DropShadow*>(p_gpu_real_begin);
|
|
}
|
|
}
|
|
}
|
|
|
|
RMLUI_ASSERTMSG(pUploadingData, "failed to obtain uploading pointer for constant buffer (FATAL)");
|
|
|
|
const Rml::Colourf& color = ConvertToColorf(filter.color);
|
|
|
|
pUploadingData->color.x = color.red;
|
|
pUploadingData->color.y = color.green;
|
|
pUploadingData->color.z = color.blue;
|
|
pUploadingData->color.w = color.alpha;
|
|
|
|
const Rml::Rectanglei& window_flipped = VerticallyFlipped(m_scissor, m_height);
|
|
SetTexCoordLimits(pUploadingData->uv_min, pUploadingData->uv_max, m_scissor, {primary.Get_Width(), primary.Get_Height()});
|
|
|
|
const Rml::Vector2f& uv_offset = filter.offset / Rml::Vector2f(-(float)m_width, (float)m_height);
|
|
DrawFullscreenQuad(uv_offset, Rml::Vector2f(1.0f), p_cb_dropshadow);
|
|
|
|
if (filter.sigma >= 0.5f)
|
|
{
|
|
const Gfx::FramebufferData& tertiary = m_manager_render_layer.GetPostprocessTertiary();
|
|
RenderBlur(filter.sigma, secondary, tertiary, window_flipped);
|
|
}
|
|
|
|
UseProgram(ProgramId::Passthrough_NoDepthStencil);
|
|
|
|
BindRenderTarget(secondary, false);
|
|
BindTexture(primary.Get_Texture());
|
|
|
|
DrawFullscreenQuad();
|
|
|
|
{
|
|
ID3D12Resource* pPrimaryResource = GetResourceFromFramebufferData(primary);
|
|
RMLUI_ASSERTMSG(pPrimaryResource, "framebuffer primary doesn't contain a valid resource for barrier transition!");
|
|
|
|
D3D12_RESOURCE_BARRIER bars[1];
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = pPrimaryResource;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.Subresource = 0;
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
|
|
m_manager_render_layer.SwapPostprocessPrimarySecondary();
|
|
|
|
break;
|
|
}
|
|
case FilterType::ColorMatrix:
|
|
{
|
|
UseProgram(ProgramId::ColorMatrix);
|
|
|
|
const Gfx::FramebufferData& source = m_manager_render_layer.GetPostprocessPrimary();
|
|
const Gfx::FramebufferData& destination = m_manager_render_layer.GetPostprocessSecondary();
|
|
|
|
BindRenderTarget(destination, false);
|
|
|
|
{
|
|
ID3D12Resource* pSource = GetResourceFromFramebufferData(source);
|
|
RMLUI_ASSERTMSG(pSource, "failed to obtain resource from framebuffer source!");
|
|
|
|
D3D12_RESOURCE_BARRIER bars[1];
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = pSource;
|
|
bars[0].Transition.Subresource = 0;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
|
|
BindTexture(source.Get_Texture());
|
|
|
|
ConstantBufferType* p_cb = Get_ConstantBuffer(m_current_back_buffer_index);
|
|
RMLUI_ASSERTMSG(p_cb, "failed to obtain constant buffer for color matrix");
|
|
|
|
if (p_cb)
|
|
{
|
|
std::uint8_t* p_cb_begin = reinterpret_cast<std::uint8_t*>(p_cb->m_p_gpu_start_memory_for_binding_data);
|
|
RMLUI_ASSERTMSG(p_cb_begin, "constant buffer must provide gpu begin binding pointer for uploading data from CPU");
|
|
|
|
if (p_cb_begin)
|
|
{
|
|
std::uint8_t* p_cb_real_begin = p_cb_begin + p_cb->m_alloc_info.offset;
|
|
RMLUI_ASSERTMSG(p_cb_real_begin,
|
|
"constant buffer must provide gpu begin binding pointer for upload data from CPU (offset applied)");
|
|
|
|
if (p_cb_real_begin)
|
|
{
|
|
constexpr bool is_need_transpose = std::is_same<decltype(filter.color_matrix), Rml::RowMajorMatrix4f>::value;
|
|
|
|
const float* p_data = is_need_transpose ? filter.color_matrix.Transpose().data() : filter.color_matrix.data();
|
|
|
|
std::memcpy(p_cb_real_begin, p_data, sizeof(filter.color_matrix));
|
|
}
|
|
}
|
|
}
|
|
|
|
DrawFullscreenQuad(p_cb);
|
|
|
|
{
|
|
ID3D12Resource* pSource = GetResourceFromFramebufferData(source);
|
|
RMLUI_ASSERTMSG(pSource, "failed to obtain resource from framebuffer source!");
|
|
|
|
D3D12_RESOURCE_BARRIER bars[1];
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = pSource;
|
|
bars[0].Transition.Subresource = 0;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
|
|
m_manager_render_layer.SwapPostprocessPrimarySecondary();
|
|
|
|
break;
|
|
}
|
|
case FilterType::MaskImage:
|
|
{
|
|
UseProgram(ProgramId::BlendMask);
|
|
|
|
const Gfx::FramebufferData& source = m_manager_render_layer.GetPostprocessPrimary();
|
|
const Gfx::FramebufferData& blend_mask = m_manager_render_layer.GetBlendMask();
|
|
const Gfx::FramebufferData& destination = m_manager_render_layer.GetPostprocessSecondary();
|
|
|
|
{
|
|
ID3D12Resource* pBM = GetResourceFromFramebufferData(blend_mask);
|
|
ID3D12Resource* pSrc = GetResourceFromFramebufferData(source);
|
|
|
|
RMLUI_ASSERTMSG(pBM, "failed to obtain resource from framebuffer blend_mask");
|
|
RMLUI_ASSERTMSG(pSrc, "failed to obtain resource from framebuffer destination");
|
|
|
|
D3D12_RESOURCE_BARRIER bars[2];
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = pBM;
|
|
bars[0].Transition.Subresource = 0;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
|
|
bars[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[1].Transition.pResource = pSrc;
|
|
bars[1].Transition.Subresource = 0;
|
|
bars[1].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[1].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(2, bars);
|
|
}
|
|
|
|
BindRenderTarget(destination, false);
|
|
BindTexture(source.Get_Texture(), 0);
|
|
BindTexture(blend_mask.Get_Texture(), 1);
|
|
|
|
DrawFullscreenQuad();
|
|
|
|
{
|
|
ID3D12Resource* pBM = GetResourceFromFramebufferData(blend_mask);
|
|
ID3D12Resource* pSrc = GetResourceFromFramebufferData(source);
|
|
|
|
RMLUI_ASSERTMSG(pBM, "failed to obtain resource from framebuffer blend_mask");
|
|
RMLUI_ASSERTMSG(pSrc, "failed to obtain resource from framebuffer destination");
|
|
|
|
D3D12_RESOURCE_BARRIER bars[2];
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = pBM;
|
|
bars[0].Transition.Subresource = 0;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
|
|
bars[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[1].Transition.pResource = pSrc;
|
|
bars[1].Transition.Subresource = 0;
|
|
bars[1].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[1].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(2, bars);
|
|
}
|
|
|
|
m_manager_render_layer.SwapPostprocessPrimarySecondary();
|
|
|
|
break;
|
|
}
|
|
case FilterType::Invalid:
|
|
{
|
|
Rml::Log::Message(Rml::Log::LT_WARNING, "Invalid (Unhandled) render filter: %d", static_cast<int>(type));
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
Rml::Log::Message(Rml::Log::LT_WARNING, "Unknown render filter: %d", static_cast<int>(type));
|
|
break;
|
|
}
|
|
}
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::CompositeLayers(Rml::LayerHandle source, Rml::LayerHandle destination, Rml::BlendMode blend_mode,
|
|
Rml::Span<const Rml::CompiledFilterHandle> filters)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - CompositeLayers");
|
|
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "CompositeLayers");
|
|
|
|
BlitLayerToPostprocessPrimary(source);
|
|
|
|
RenderFilters(filters);
|
|
|
|
// Consider instead to use a separate command list and wait for command queue.
|
|
Flush();
|
|
|
|
BindRenderTarget(m_manager_render_layer.GetLayer(destination));
|
|
|
|
if (blend_mode == Rml::BlendMode::Replace)
|
|
{
|
|
UseProgram(ProgramId::Passthrough_NoBlend);
|
|
}
|
|
else
|
|
{
|
|
// since we use msaa render target we should use appropriate version of pipeline
|
|
if (m_is_stencil_equal && m_is_stencil_enabled)
|
|
{
|
|
UseProgram(ProgramId::Passthrough_MSAA_Equal);
|
|
}
|
|
else
|
|
{
|
|
UseProgram(ProgramId::Passthrough_MSAA);
|
|
}
|
|
}
|
|
|
|
{
|
|
ID3D12Resource* pResource = GetResourceFromFramebufferData(m_manager_render_layer.GetPostprocessPrimary());
|
|
RMLUI_ASSERTMSG(pResource, "failed to obtain resource from m_manager_render_layer.GetPostprocessPrimary()");
|
|
|
|
D3D12_RESOURCE_BARRIER bars[1];
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = pResource;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
BindTexture(m_manager_render_layer.GetPostprocessPrimary().Get_Texture());
|
|
|
|
DrawFullscreenQuad();
|
|
|
|
{
|
|
ID3D12Resource* pResource = GetResourceFromFramebufferData(m_manager_render_layer.GetPostprocessPrimary());
|
|
RMLUI_ASSERTMSG(pResource, "failed to obtain resource from m_manager_render_layer.GetPostprocessPrimary()");
|
|
|
|
D3D12_RESOURCE_BARRIER bars[1];
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = pResource;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
|
|
// should we set like return blend state as enabled?
|
|
if (blend_mode == Rml::BlendMode::Replace)
|
|
{
|
|
UseProgram(ProgramId::Passthrough);
|
|
}
|
|
|
|
if (destination != m_manager_render_layer.GetTopLayerHandle())
|
|
{
|
|
BindRenderTarget(m_manager_render_layer.GetTopLayer());
|
|
}
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
void RenderInterface_DX12::PopLayer()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - PopLayer");
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "PopLayer");
|
|
m_manager_render_layer.PopLayer();
|
|
BindRenderTarget(m_manager_render_layer.GetTopLayer());
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
Rml::TextureHandle RenderInterface_DX12::SaveLayerAsTexture()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - SaveLayerAsTexture");
|
|
RMLUI_ASSERT(m_scissor.Valid());
|
|
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "SaveLayerAsTexture");
|
|
|
|
const Rml::Rectanglei bounds = m_scissor;
|
|
|
|
Rml::TextureHandle render_texture = GenerateTexture({}, bounds.Size());
|
|
if (!render_texture)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
BlitLayerToPostprocessPrimary(m_manager_render_layer.GetTopLayerHandle());
|
|
EnableScissorRegion(false);
|
|
|
|
const Gfx::FramebufferData& source = m_manager_render_layer.GetPostprocessPrimary();
|
|
const Gfx::FramebufferData& destination = m_manager_render_layer.GetPostprocessSecondary();
|
|
|
|
{
|
|
ID3D12Resource* pResource = GetResourceFromFramebufferData(source);
|
|
RMLUI_ASSERTMSG(pResource, "failed to obtain resource from framebuffer source");
|
|
|
|
D3D12_RESOURCE_BARRIER bars[1];
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = pResource;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
|
|
BlitFramebuffer(source, destination, bounds.Left(), source.Get_Height() - bounds.Bottom(), bounds.Right(), source.Get_Height() - bounds.Top(), 0,
|
|
bounds.Height(), bounds.Width(), 0);
|
|
|
|
{
|
|
ID3D12Resource* pResource = GetResourceFromFramebufferData(source);
|
|
RMLUI_ASSERTMSG(pResource, "failed to obtain resource from framebuffer source");
|
|
|
|
D3D12_RESOURCE_BARRIER bars[1];
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = pResource;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
|
|
D3D12_BOX copy_box{};
|
|
copy_box.left = bounds.Left();
|
|
copy_box.right = bounds.Right();
|
|
copy_box.top = bounds.Top();
|
|
copy_box.bottom = bounds.Bottom();
|
|
copy_box.front = 0;
|
|
copy_box.back = 1;
|
|
|
|
TextureHandleType* p_casted_rt = reinterpret_cast<TextureHandleType*>(render_texture);
|
|
ID3D12Resource* p_resource_render_texture = nullptr;
|
|
|
|
if (p_casted_rt->Get_Info().buffer_index == -1)
|
|
{
|
|
// committed
|
|
|
|
D3D12MA::Allocation* p_allocation_source = static_cast<D3D12MA::Allocation*>(p_casted_rt->Get_Resource());
|
|
RMLUI_ASSERTMSG(p_allocation_source, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_allocation_source->GetResource(), "must be valid!");
|
|
|
|
p_resource_render_texture = p_allocation_source->GetResource();
|
|
}
|
|
else
|
|
{
|
|
// placed
|
|
|
|
RMLUI_ASSERT(p_casted_rt->Get_Resource());
|
|
|
|
p_resource_render_texture = static_cast<ID3D12Resource*>(p_casted_rt->Get_Resource());
|
|
}
|
|
|
|
RMLUI_ASSERTMSG(p_resource_render_texture, "failed to obtain resource from allocated texture!");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (p_resource_render_texture)
|
|
{
|
|
p_resource_render_texture->SetName(L"SaveLayerAsTexture = Texture dest copy");
|
|
}
|
|
#endif
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION dest_copy;
|
|
dest_copy.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
dest_copy.pResource = p_resource_render_texture;
|
|
dest_copy.SubresourceIndex = 0;
|
|
|
|
ID3D12Resource* p_resource_from_destination = GetResourceFromFramebufferData(destination);
|
|
|
|
RMLUI_ASSERTMSG(p_resource_from_destination, "failed to obtain resource from framebuffer destination");
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION src_copy;
|
|
src_copy.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
src_copy.SubresourceIndex = 0;
|
|
src_copy.pResource = p_resource_from_destination;
|
|
|
|
{
|
|
D3D12_RESOURCE_BARRIER bars[2];
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = p_resource_from_destination;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
bars[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[1].Transition.pResource = p_resource_render_texture;
|
|
bars[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
bars[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON;
|
|
bars[1].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(2, bars);
|
|
}
|
|
|
|
m_p_command_graphics_list->CopyTextureRegion(&dest_copy, 0, 0, 0, &src_copy, ©_box);
|
|
|
|
{
|
|
D3D12_RESOURCE_BARRIER bars[2];
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = p_resource_from_destination;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
|
bars[0].Transition.Subresource = 0;
|
|
|
|
bars[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[1].Transition.pResource = p_resource_render_texture;
|
|
bars[1].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
bars[1].Transition.Subresource = 0;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(2, bars);
|
|
}
|
|
|
|
SetScissor(bounds);
|
|
BindRenderTarget(m_manager_render_layer.GetTopLayer());
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
|
|
return render_texture;
|
|
}
|
|
|
|
Rml::CompiledFilterHandle RenderInterface_DX12::SaveLayerAsMaskImage()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - SaveLayerAsMaskImage");
|
|
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "SaveLayerAsMaskImage");
|
|
|
|
BlitLayerToPostprocessPrimary(m_manager_render_layer.GetTopLayerHandle());
|
|
|
|
const Gfx::FramebufferData& source = m_manager_render_layer.GetPostprocessPrimary();
|
|
const Gfx::FramebufferData& destination = m_manager_render_layer.GetBlendMask();
|
|
|
|
{
|
|
D3D12_RESOURCE_BARRIER bars[1];
|
|
|
|
ID3D12Resource* pSource = GetResourceFromFramebufferData(source);
|
|
RMLUI_ASSERTMSG(pSource, "failed to obtain resource from framebuffer source");
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = pSource;
|
|
bars[0].Transition.Subresource = 0;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
|
|
UseProgram(ProgramId::Passthrough_NoBlendAndNoMSAA);
|
|
BindRenderTarget(destination, false);
|
|
BindTexture(source.Get_Texture());
|
|
|
|
DrawFullscreenQuad();
|
|
|
|
{
|
|
D3D12_RESOURCE_BARRIER bars[1];
|
|
|
|
ID3D12Resource* pSource = GetResourceFromFramebufferData(source);
|
|
RMLUI_ASSERTMSG(pSource, "failed to obtain resource from framebuffer source");
|
|
|
|
bars[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
bars[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bars[0].Transition.pResource = pSource;
|
|
bars[0].Transition.Subresource = 0;
|
|
bars[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
|
bars[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
|
|
m_p_command_graphics_list->ResourceBarrier(1, bars);
|
|
}
|
|
|
|
BindRenderTarget(m_manager_render_layer.GetTopLayer());
|
|
|
|
CompiledFilter filter = {};
|
|
filter.type = FilterType::MaskImage;
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
|
|
return reinterpret_cast<Rml::CompiledFilterHandle>(new CompiledFilter(std::move(filter)));
|
|
}
|
|
|
|
Rml::CompiledFilterHandle RenderInterface_DX12::CompileFilter(const Rml::String& name, const Rml::Dictionary& parameters)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - CompileFilter");
|
|
CompiledFilter filter = {};
|
|
|
|
if (name == "opacity")
|
|
{
|
|
filter.type = FilterType::Passthrough;
|
|
filter.blend_factor = Rml::Get(parameters, "value", 1.0f);
|
|
}
|
|
else if (name == "blur")
|
|
{
|
|
filter.type = FilterType::Blur;
|
|
filter.sigma = Rml::Get(parameters, "sigma", 1.0f);
|
|
}
|
|
else if (name == "drop-shadow")
|
|
{
|
|
filter.type = FilterType::DropShadow;
|
|
filter.sigma = Rml::Get(parameters, "sigma", 0.f);
|
|
filter.color = Rml::Get(parameters, "color", Rml::Colourb()).ToPremultiplied();
|
|
filter.offset = Rml::Get(parameters, "offset", Rml::Vector2f(0.f));
|
|
}
|
|
else if (name == "brightness")
|
|
{
|
|
filter.type = FilterType::ColorMatrix;
|
|
const float value = Rml::Get(parameters, "value", 1.0f);
|
|
filter.color_matrix = Rml::Matrix4f::Diag(value, value, value, 1.f);
|
|
}
|
|
else if (name == "contrast")
|
|
{
|
|
filter.type = FilterType::ColorMatrix;
|
|
const float value = Rml::Get(parameters, "value", 1.0f);
|
|
const float grayness = 0.5f - 0.5f * value;
|
|
filter.color_matrix = Rml::Matrix4f::Diag(value, value, value, 1.f);
|
|
filter.color_matrix.SetColumn(3, Rml::Vector4f(grayness, grayness, grayness, 1.f));
|
|
}
|
|
else if (name == "invert")
|
|
{
|
|
filter.type = FilterType::ColorMatrix;
|
|
const float value = Rml::Math::Clamp(Rml::Get(parameters, "value", 1.0f), 0.f, 1.f);
|
|
const float inverted = 1.f - 2.f * value;
|
|
filter.color_matrix = Rml::Matrix4f::Diag(inverted, inverted, inverted, 1.f);
|
|
filter.color_matrix.SetColumn(3, Rml::Vector4f(value, value, value, 1.f));
|
|
}
|
|
else if (name == "grayscale")
|
|
{
|
|
filter.type = FilterType::ColorMatrix;
|
|
const float value = Rml::Get(parameters, "value", 1.0f);
|
|
const float rev_value = 1.f - value;
|
|
const Rml::Vector3f gray = value * Rml::Vector3f(0.2126f, 0.7152f, 0.0722f);
|
|
// clang-format off
|
|
filter.color_matrix = Rml::Matrix4f::FromRows(
|
|
{gray.x + rev_value, gray.y, gray.z, 0.f},
|
|
{gray.x, gray.y + rev_value, gray.z, 0.f},
|
|
{gray.x, gray.y, gray.z + rev_value, 0.f},
|
|
{0.f, 0.f, 0.f, 1.f}
|
|
);
|
|
// clang-format on
|
|
}
|
|
else if (name == "sepia")
|
|
{
|
|
filter.type = FilterType::ColorMatrix;
|
|
const float value = Rml::Get(parameters, "value", 1.0f);
|
|
const float rev_value = 1.f - value;
|
|
const Rml::Vector3f r_mix = value * Rml::Vector3f(0.393f, 0.769f, 0.189f);
|
|
const Rml::Vector3f g_mix = value * Rml::Vector3f(0.349f, 0.686f, 0.168f);
|
|
const Rml::Vector3f b_mix = value * Rml::Vector3f(0.272f, 0.534f, 0.131f);
|
|
// clang-format off
|
|
filter.color_matrix = Rml::Matrix4f::FromRows(
|
|
{r_mix.x + rev_value, r_mix.y, r_mix.z, 0.f},
|
|
{g_mix.x, g_mix.y + rev_value, g_mix.z, 0.f},
|
|
{b_mix.x, b_mix.y, b_mix.z + rev_value, 0.f},
|
|
{0.f, 0.f, 0.f, 1.f}
|
|
);
|
|
// clang-format on
|
|
}
|
|
else if (name == "hue-rotate")
|
|
{
|
|
// Hue-rotation and saturation values based on: https://www.w3.org/TR/filter-effects-1/#attr-valuedef-type-huerotate
|
|
filter.type = FilterType::ColorMatrix;
|
|
const float value = Rml::Get(parameters, "value", 1.0f);
|
|
const float s = Rml::Math::Sin(value);
|
|
const float c = Rml::Math::Cos(value);
|
|
// clang-format off
|
|
filter.color_matrix = Rml::Matrix4f::FromRows(
|
|
{0.213f + 0.787f * c - 0.213f * s, 0.715f - 0.715f * c - 0.715f * s, 0.072f - 0.072f * c + 0.928f * s, 0.f},
|
|
{0.213f - 0.213f * c + 0.143f * s, 0.715f + 0.285f * c + 0.140f * s, 0.072f - 0.072f * c - 0.283f * s, 0.f},
|
|
{0.213f - 0.213f * c - 0.787f * s, 0.715f - 0.715f * c + 0.715f * s, 0.072f + 0.928f * c + 0.072f * s, 0.f},
|
|
{0.f, 0.f, 0.f, 1.f}
|
|
);
|
|
// clang-format on
|
|
}
|
|
else if (name == "saturate")
|
|
{
|
|
filter.type = FilterType::ColorMatrix;
|
|
const float value = Rml::Get(parameters, "value", 1.0f);
|
|
// clang-format off
|
|
filter.color_matrix = Rml::Matrix4f::FromRows(
|
|
{0.213f + 0.787f * value, 0.715f - 0.715f * value, 0.072f - 0.072f * value, 0.f},
|
|
{0.213f - 0.213f * value, 0.715f + 0.285f * value, 0.072f - 0.072f * value, 0.f},
|
|
{0.213f - 0.213f * value, 0.715f - 0.715f * value, 0.072f + 0.928f * value, 0.f},
|
|
{0.f, 0.f, 0.f, 1.f}
|
|
);
|
|
// clang-format on
|
|
}
|
|
|
|
if (filter.type != FilterType::Invalid)
|
|
return reinterpret_cast<Rml::CompiledFilterHandle>(new CompiledFilter(std::move(filter)));
|
|
|
|
Rml::Log::Message(Rml::Log::LT_WARNING, "Unsupported filter type '%s'.", name.c_str());
|
|
return {};
|
|
}
|
|
|
|
void RenderInterface_DX12::ReleaseFilter(Rml::CompiledFilterHandle filter)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - ReleaseFilter");
|
|
delete reinterpret_cast<CompiledFilter*>(filter);
|
|
}
|
|
|
|
Rml::CompiledShaderHandle RenderInterface_DX12::CompileShader(const Rml::String& name, const Rml::Dictionary& parameters)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - CompileShader");
|
|
auto ApplyColorStopList = [](CompiledShader& shader, const Rml::Dictionary& shader_parameters) {
|
|
auto it = shader_parameters.find("color_stop_list");
|
|
RMLUI_ASSERT(it != shader_parameters.end() && it->second.GetType() == Rml::Variant::COLORSTOPLIST);
|
|
const Rml::ColorStopList& color_stop_list = it->second.GetReference<Rml::ColorStopList>();
|
|
const int num_stops = Rml::Math::Min((int)color_stop_list.size(), MAX_NUM_STOPS);
|
|
|
|
shader.stop_positions.resize(num_stops);
|
|
shader.stop_colors.resize(num_stops);
|
|
for (int i = 0; i < num_stops; i++)
|
|
{
|
|
const Rml::ColorStop& stop = color_stop_list[i];
|
|
RMLUI_ASSERT(stop.position.unit == Rml::Unit::NUMBER);
|
|
shader.stop_positions[i] = stop.position.number;
|
|
shader.stop_colors[i] = ConvertToColorf(stop.color);
|
|
}
|
|
};
|
|
|
|
CompiledShader shader = {};
|
|
|
|
if (name == "linear-gradient")
|
|
{
|
|
shader.type = CompiledShaderType::Gradient;
|
|
const bool repeating = Rml::Get(parameters, "repeating", false);
|
|
shader.gradient_function = (repeating ? ShaderGradientFunction::RepeatingLinear : ShaderGradientFunction::Linear);
|
|
shader.p = Rml::Get(parameters, "p0", Rml::Vector2f(0.f));
|
|
shader.v = Rml::Get(parameters, "p1", Rml::Vector2f(0.f)) - shader.p;
|
|
ApplyColorStopList(shader, parameters);
|
|
}
|
|
else if (name == "radial-gradient")
|
|
{
|
|
shader.type = CompiledShaderType::Gradient;
|
|
const bool repeating = Rml::Get(parameters, "repeating", false);
|
|
shader.gradient_function = (repeating ? ShaderGradientFunction::RepeatingRadial : ShaderGradientFunction::Radial);
|
|
shader.p = Rml::Get(parameters, "center", Rml::Vector2f(0.f));
|
|
shader.v = Rml::Vector2f(1.f) / Rml::Get(parameters, "radius", Rml::Vector2f(1.f));
|
|
ApplyColorStopList(shader, parameters);
|
|
}
|
|
else if (name == "conic-gradient")
|
|
{
|
|
shader.type = CompiledShaderType::Gradient;
|
|
const bool repeating = Rml::Get(parameters, "repeating", false);
|
|
shader.gradient_function = (repeating ? ShaderGradientFunction::RepeatingConic : ShaderGradientFunction::Conic);
|
|
shader.p = Rml::Get(parameters, "center", Rml::Vector2f(0.f));
|
|
const float angle = Rml::Get(parameters, "angle", 0.f);
|
|
shader.v = {Rml::Math::Cos(angle), Rml::Math::Sin(angle)};
|
|
ApplyColorStopList(shader, parameters);
|
|
}
|
|
else if (name == "shader")
|
|
{
|
|
const Rml::String value = Rml::Get(parameters, "value", Rml::String());
|
|
if (value == "creation")
|
|
{
|
|
shader.type = CompiledShaderType::Creation;
|
|
shader.dimensions = Rml::Get(parameters, "dimensions", Rml::Vector2f(0.f));
|
|
}
|
|
}
|
|
|
|
if (shader.type != CompiledShaderType::Invalid)
|
|
return reinterpret_cast<Rml::CompiledShaderHandle>(new CompiledShader(std::move(shader)));
|
|
|
|
Rml::Log::Message(Rml::Log::LT_WARNING, "Unsupported shader type '%s'.", name.c_str());
|
|
return {};
|
|
}
|
|
|
|
void RenderInterface_DX12::RenderShader(Rml::CompiledShaderHandle shader_handle, Rml::CompiledGeometryHandle geometry_handle,
|
|
Rml::Vector2f translation, Rml::TextureHandle texture)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RenderShader");
|
|
RMLUI_ASSERT(shader_handle && geometry_handle);
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "RenderShader");
|
|
|
|
// fixing unreferenced parameter
|
|
(void)(texture);
|
|
|
|
const CompiledShader& shader = *reinterpret_cast<CompiledShader*>(shader_handle);
|
|
const CompiledShaderType type = shader.type;
|
|
const GeometryHandleType* geometry = reinterpret_cast<GeometryHandleType*>(geometry_handle);
|
|
|
|
switch (type)
|
|
{
|
|
case CompiledShaderType::Gradient:
|
|
{
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "Gradient");
|
|
|
|
RMLUI_ASSERT(shader.stop_positions.size() == shader.stop_colors.size());
|
|
const int num_stops = (int)shader.stop_positions.size();
|
|
|
|
UseProgram(ProgramId::Gradient);
|
|
ConstantBufferType* p_cb = Get_ConstantBuffer(m_current_back_buffer_index);
|
|
RMLUI_ASSERTMSG(p_cb, "failed to obtain constant buffer for gradient");
|
|
|
|
struct CBV_Gradient {
|
|
Rml::Matrix4f transform;
|
|
Rml::Vector2f translate;
|
|
|
|
int func;
|
|
int num_stops;
|
|
Rml::Vector2f starting_point;
|
|
Rml::Vector2f ending_point;
|
|
Rml::Vector4f stop_colors[MAX_NUM_STOPS];
|
|
float stop_positions[MAX_NUM_STOPS];
|
|
};
|
|
|
|
if (p_cb)
|
|
{
|
|
std::uint8_t* p_cb_begin = reinterpret_cast<std::uint8_t*>(p_cb->m_p_gpu_start_memory_for_binding_data);
|
|
RMLUI_ASSERTMSG(p_cb_begin, "ConstantBuffer must contain valid pointer to begin of gpu binding pointer for uploading data from CPU!");
|
|
|
|
if (p_cb_begin)
|
|
{
|
|
std::uint8_t* p_cb_begin_real = p_cb_begin + p_cb->m_alloc_info.offset;
|
|
RMLUI_ASSERTMSG(p_cb_begin_real, "failed to offset gpu begin pointer for constant buffer!");
|
|
|
|
if (p_cb_begin_real)
|
|
{
|
|
CBV_Gradient* p_casted = reinterpret_cast<CBV_Gradient*>(p_cb_begin_real);
|
|
|
|
p_casted->transform = m_constant_buffer_data_transform;
|
|
p_casted->translate = translation;
|
|
p_casted->func = (int)(shader.gradient_function);
|
|
p_casted->starting_point = shader.p;
|
|
p_casted->ending_point = shader.v;
|
|
p_casted->num_stops = num_stops;
|
|
std::memset(p_casted->stop_positions, 0, sizeof(CBV_Gradient::stop_positions));
|
|
std::memset(p_casted->stop_colors, 0, sizeof(CBV_Gradient::stop_colors));
|
|
|
|
std::memcpy(&p_casted->stop_positions, shader.stop_positions.data(), num_stops * sizeof(float));
|
|
std::memcpy(&p_casted->stop_colors, shader.stop_colors.data(), num_stops * sizeof(Rml::Vector4f));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (p_cb)
|
|
{
|
|
auto* p_dx_constant_buffer = m_manager_buffer.Get_BufferByIndex(p_cb->m_alloc_info.buffer_index);
|
|
RMLUI_ASSERTMSG(p_dx_constant_buffer, "must be valid!");
|
|
|
|
if (p_dx_constant_buffer)
|
|
{
|
|
auto* p_dx_resource = p_dx_constant_buffer->GetResource();
|
|
|
|
RMLUI_ASSERTMSG(p_dx_resource, "must be valid!");
|
|
|
|
if (p_dx_resource)
|
|
{
|
|
D3D12_GPU_VIRTUAL_ADDRESS one_shared_cbv_for_different_shaders_address =
|
|
p_dx_resource->GetGPUVirtualAddress() + p_cb->m_alloc_info.offset;
|
|
|
|
m_p_command_graphics_list->SetGraphicsRootConstantBufferView(0, one_shared_cbv_for_different_shaders_address);
|
|
m_p_command_graphics_list->SetGraphicsRootConstantBufferView(1, one_shared_cbv_for_different_shaders_address);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_p_command_graphics_list->IASetPrimitiveTopology(D3D12_PRIMITIVE_TOPOLOGY::D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
|
auto* p_dx_buffer_vertex = m_manager_buffer.Get_BufferByIndex(geometry->Get_InfoVertex().buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_dx_buffer_vertex, "must be valid!");
|
|
if (p_dx_buffer_vertex)
|
|
{
|
|
auto* p_dx_resource = p_dx_buffer_vertex->GetResource();
|
|
|
|
RMLUI_ASSERTMSG(p_dx_resource, "must be valid!");
|
|
|
|
if (p_dx_resource)
|
|
{
|
|
D3D12_VERTEX_BUFFER_VIEW view_vertex_buffer = {};
|
|
|
|
view_vertex_buffer.BufferLocation = p_dx_resource->GetGPUVirtualAddress() + geometry->Get_InfoVertex().offset;
|
|
view_vertex_buffer.StrideInBytes = sizeof(Rml::Vertex);
|
|
view_vertex_buffer.SizeInBytes = static_cast<UINT>(geometry->Get_InfoVertex().size);
|
|
|
|
m_p_command_graphics_list->IASetVertexBuffers(0, 1, &view_vertex_buffer);
|
|
}
|
|
}
|
|
|
|
auto* p_dx_buffer_index = m_manager_buffer.Get_BufferByIndex(geometry->Get_InfoIndex().buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_dx_buffer_index, "must be valid!");
|
|
|
|
if (p_dx_buffer_index)
|
|
{
|
|
auto* p_dx_resource = p_dx_buffer_index->GetResource();
|
|
|
|
RMLUI_ASSERTMSG(p_dx_resource, "must be valid!");
|
|
|
|
if (p_dx_resource)
|
|
{
|
|
D3D12_INDEX_BUFFER_VIEW view_index_buffer = {};
|
|
|
|
view_index_buffer.BufferLocation = p_dx_resource->GetGPUVirtualAddress() + geometry->Get_InfoIndex().offset;
|
|
view_index_buffer.Format = DXGI_FORMAT::DXGI_FORMAT_R32_UINT;
|
|
view_index_buffer.SizeInBytes = static_cast<UINT>(geometry->Get_InfoIndex().size);
|
|
|
|
m_p_command_graphics_list->IASetIndexBuffer(&view_index_buffer);
|
|
}
|
|
}
|
|
|
|
m_p_command_graphics_list->DrawIndexedInstanced(geometry->Get_NumIndices(), 1, 0, 0, 0);
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
|
|
break;
|
|
}
|
|
case CompiledShaderType::Creation:
|
|
{
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "Creation");
|
|
|
|
UseProgram(ProgramId::Creation);
|
|
ConstantBufferType* p_cb = Get_ConstantBuffer(m_current_back_buffer_index);
|
|
RMLUI_ASSERTMSG(p_cb, "failed to obtain constant buffer for gradient");
|
|
|
|
struct CBV_Creation {
|
|
Rml::Matrix4f transform;
|
|
Rml::Vector2f translation;
|
|
Rml::Vector2f dimensions;
|
|
float time;
|
|
};
|
|
|
|
if (p_cb)
|
|
{
|
|
std::uint8_t* p_cb_begin = reinterpret_cast<std::uint8_t*>(p_cb->m_p_gpu_start_memory_for_binding_data);
|
|
RMLUI_ASSERTMSG(p_cb_begin, "ConstantBuffer must contain valid pointer to begin of gpu binding pointer for uploading data from CPU!");
|
|
|
|
if (p_cb_begin)
|
|
{
|
|
std::uint8_t* p_cb_begin_real = p_cb_begin + p_cb->m_alloc_info.offset;
|
|
RMLUI_ASSERTMSG(p_cb_begin_real, "failed to offset gpu begin pointer for constant buffer!");
|
|
|
|
if (p_cb_begin_real)
|
|
{
|
|
CBV_Creation* p_casted = reinterpret_cast<CBV_Creation*>(p_cb_begin_real);
|
|
|
|
p_casted->transform = m_constant_buffer_data_transform;
|
|
p_casted->translation = translation;
|
|
|
|
const double time = Rml::GetSystemInterface()->GetElapsedTime();
|
|
p_casted->time = (float)time;
|
|
p_casted->dimensions = shader.dimensions;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (p_cb)
|
|
{
|
|
auto* p_dx_constant_buffer = m_manager_buffer.Get_BufferByIndex(p_cb->m_alloc_info.buffer_index);
|
|
RMLUI_ASSERTMSG(p_dx_constant_buffer, "must be valid!");
|
|
|
|
if (p_dx_constant_buffer)
|
|
{
|
|
auto* p_dx_resource = p_dx_constant_buffer->GetResource();
|
|
|
|
RMLUI_ASSERTMSG(p_dx_resource, "must be valid!");
|
|
|
|
if (p_dx_resource)
|
|
{
|
|
D3D12_GPU_VIRTUAL_ADDRESS one_shared_cbv_for_different_shaders_address =
|
|
p_dx_resource->GetGPUVirtualAddress() + p_cb->m_alloc_info.offset;
|
|
|
|
m_p_command_graphics_list->SetGraphicsRootConstantBufferView(0, one_shared_cbv_for_different_shaders_address);
|
|
m_p_command_graphics_list->SetGraphicsRootConstantBufferView(1, one_shared_cbv_for_different_shaders_address);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_p_command_graphics_list->IASetPrimitiveTopology(D3D12_PRIMITIVE_TOPOLOGY::D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
|
auto* p_dx_buffer_vertex = m_manager_buffer.Get_BufferByIndex(geometry->Get_InfoVertex().buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_dx_buffer_vertex, "must be valid!");
|
|
if (p_dx_buffer_vertex)
|
|
{
|
|
auto* p_dx_resource = p_dx_buffer_vertex->GetResource();
|
|
|
|
RMLUI_ASSERTMSG(p_dx_resource, "must be valid!");
|
|
|
|
if (p_dx_resource)
|
|
{
|
|
D3D12_VERTEX_BUFFER_VIEW view_vertex_buffer = {};
|
|
|
|
view_vertex_buffer.BufferLocation = p_dx_resource->GetGPUVirtualAddress() + geometry->Get_InfoVertex().offset;
|
|
view_vertex_buffer.StrideInBytes = sizeof(Rml::Vertex);
|
|
view_vertex_buffer.SizeInBytes = static_cast<UINT>(geometry->Get_InfoVertex().size);
|
|
|
|
m_p_command_graphics_list->IASetVertexBuffers(0, 1, &view_vertex_buffer);
|
|
}
|
|
}
|
|
|
|
auto* p_dx_buffer_index = m_manager_buffer.Get_BufferByIndex(geometry->Get_InfoIndex().buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_dx_buffer_index, "must be valid!");
|
|
|
|
if (p_dx_buffer_index)
|
|
{
|
|
auto* p_dx_resource = p_dx_buffer_index->GetResource();
|
|
|
|
RMLUI_ASSERTMSG(p_dx_resource, "must be valid!");
|
|
|
|
if (p_dx_resource)
|
|
{
|
|
D3D12_INDEX_BUFFER_VIEW view_index_buffer = {};
|
|
|
|
view_index_buffer.BufferLocation = p_dx_resource->GetGPUVirtualAddress() + geometry->Get_InfoIndex().offset;
|
|
view_index_buffer.Format = DXGI_FORMAT::DXGI_FORMAT_R32_UINT;
|
|
view_index_buffer.SizeInBytes = static_cast<UINT>(geometry->Get_InfoIndex().size);
|
|
|
|
m_p_command_graphics_list->IASetIndexBuffer(&view_index_buffer);
|
|
}
|
|
}
|
|
|
|
m_p_command_graphics_list->DrawIndexedInstanced(geometry->Get_NumIndices(), 1, 0, 0, 0);
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
|
|
break;
|
|
}
|
|
case CompiledShaderType::Invalid:
|
|
{
|
|
Rml::Log::Message(Rml::Log::LT_WARNING, "Unhandled render shader %d", (int)type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
}
|
|
|
|
void RenderInterface_DX12::ReleaseShader(Rml::CompiledShaderHandle effect_handle)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - ReleaseShader");
|
|
delete reinterpret_cast<CompiledShader*>(effect_handle);
|
|
}
|
|
|
|
bool RenderInterface_DX12::IsSwapchainValid() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - IsSwapchainValid");
|
|
return (m_p_swapchain != nullptr);
|
|
}
|
|
|
|
void RenderInterface_DX12::RecreateSwapchain() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - RecreateSwapchain");
|
|
SetViewport(m_width, m_height);
|
|
}
|
|
|
|
ID3D12Fence* RenderInterface_DX12::Get_Fence()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Get_Fence");
|
|
return m_p_backbuffer_fence;
|
|
}
|
|
|
|
HANDLE RenderInterface_DX12::Get_FenceEvent()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Get_FenceEvent");
|
|
return m_p_fence_event;
|
|
}
|
|
|
|
Rml::Array<uint64_t, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT>& RenderInterface_DX12::Get_FenceValues()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Get_FenceValues");
|
|
return m_backbuffers_fence_values;
|
|
}
|
|
|
|
uint32_t RenderInterface_DX12::Get_CurrentFrameIndex()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Get_CurrentFrameIndex");
|
|
return m_current_back_buffer_index;
|
|
}
|
|
|
|
ID3D12Device* RenderInterface_DX12::Get_Device() const
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Get_Device");
|
|
return m_p_device;
|
|
}
|
|
|
|
RenderInterface_DX12::TextureMemoryManager& RenderInterface_DX12::Get_TextureManager()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Get_TextureManager");
|
|
return m_manager_texture;
|
|
}
|
|
|
|
RenderInterface_DX12::BufferMemoryManager& RenderInterface_DX12::Get_BufferManager()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Get_BufferManager");
|
|
return m_manager_buffer;
|
|
}
|
|
|
|
unsigned char RenderInterface_DX12::Get_MSAASampleCount() const
|
|
{
|
|
return m_msaa_sample_count;
|
|
}
|
|
|
|
void RenderInterface_DX12::Set_UserFramebufferIndex(unsigned char framebuffer_index)
|
|
{
|
|
m_current_back_buffer_index = static_cast<UINT>(framebuffer_index);
|
|
}
|
|
|
|
void RenderInterface_DX12::Set_UserRenderTarget(void* rtv_where_we_render_to)
|
|
{
|
|
RMLUI_ASSERTMSG(rtv_where_we_render_to, "you can't pass empty rtv for rendering");
|
|
m_p_user_rtv_present = reinterpret_cast<D3D12_CPU_DESCRIPTOR_HANDLE*>(rtv_where_we_render_to);
|
|
}
|
|
|
|
void RenderInterface_DX12::Set_UserDepthStencil(void* dsv_where_we_render_to)
|
|
{
|
|
RMLUI_ASSERTMSG(dsv_where_we_render_to, "you can't pass empty dsv for rendering");
|
|
m_p_user_dsv_present = reinterpret_cast<D3D12_CPU_DESCRIPTOR_HANDLE*>(dsv_where_we_render_to);
|
|
}
|
|
|
|
bool RenderInterface_DX12::CaptureScreen(int& out_width, int& out_height, int& out_num_components, Rml::UniquePtr<Rml::byte[]>& out_data)
|
|
{
|
|
out_width = -1;
|
|
out_height = -1;
|
|
out_num_components = -1;
|
|
out_data = {};
|
|
|
|
if (!m_p_device || !m_p_swapchain || !m_p_command_allocator_screenshot || !m_p_command_graphics_list_screenshot || !m_p_command_queue ||
|
|
!m_p_fence_screenshot || !m_p_fence_event_screenshot)
|
|
{
|
|
RMLUI_ERRORMSG("Early calling");
|
|
return false;
|
|
}
|
|
HRESULT status = m_p_command_allocator_screenshot->Reset();
|
|
RMLUI_DX_VERIFY_MSG(status, "failed ID3D12CommandAllocator::Reset (screenshot)");
|
|
|
|
status = m_p_command_graphics_list_screenshot->Reset(m_p_command_allocator_screenshot, nullptr);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed ID3D12CommandGraphicsList::Reset (screenshot)");
|
|
|
|
ID3D12Resource* p_back_buffer{};
|
|
status = m_p_swapchain->GetBuffer(m_p_swapchain->GetCurrentBackBufferIndex(), IID_PPV_ARGS(&p_back_buffer));
|
|
|
|
if (!SUCCEEDED(status) || !p_back_buffer)
|
|
{
|
|
RMLUI_ERRORMSG("failed to obtain swapchain's backbuffer");
|
|
return false;
|
|
}
|
|
|
|
const D3D12_RESOURCE_DESC& desc = p_back_buffer->GetDesc();
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12] Obtained swapchain's backbuffer: w=%zu h=%d format=%s", desc.Width, desc.Height,
|
|
Rml::DXGIFormatToString(desc.Format));
|
|
#endif
|
|
|
|
UINT64 required_size = 0;
|
|
D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout = {};
|
|
UINT64 source_row_size_bytes = 0;
|
|
UINT num_rows = 0;
|
|
|
|
m_p_device->GetCopyableFootprints(&desc, 0, 1, 0, &layout, &num_rows, &source_row_size_bytes, &required_size);
|
|
|
|
D3D12_HEAP_PROPERTIES heap_props = {};
|
|
|
|
heap_props.Type = D3D12_HEAP_TYPE_READBACK;
|
|
heap_props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
heap_props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
heap_props.CreationNodeMask = 1;
|
|
heap_props.VisibleNodeMask = 1;
|
|
|
|
D3D12_RESOURCE_DESC cpu_readaccess_buffer_desc = {};
|
|
cpu_readaccess_buffer_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
cpu_readaccess_buffer_desc.Alignment = 0;
|
|
cpu_readaccess_buffer_desc.Width = required_size;
|
|
cpu_readaccess_buffer_desc.Height = 1; // since we just want Rml::byte array there's no need in two dimensionality
|
|
cpu_readaccess_buffer_desc.DepthOrArraySize = 1;
|
|
cpu_readaccess_buffer_desc.MipLevels = 1;
|
|
cpu_readaccess_buffer_desc.Format = DXGI_FORMAT_UNKNOWN;
|
|
cpu_readaccess_buffer_desc.SampleDesc.Count = 1;
|
|
cpu_readaccess_buffer_desc.SampleDesc.Quality = 0;
|
|
cpu_readaccess_buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
cpu_readaccess_buffer_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
|
|
ID3D12Resource* p_cpu_readaccess_buffer{};
|
|
status = m_p_device->CreateCommittedResource(&heap_props, D3D12_HEAP_FLAG_NONE, &cpu_readaccess_buffer_desc,
|
|
D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&p_cpu_readaccess_buffer));
|
|
|
|
if (!SUCCEEDED(status) || !p_cpu_readaccess_buffer)
|
|
{
|
|
RMLUI_ERRORMSG("failed to create buffer for CPU reading");
|
|
return false;
|
|
}
|
|
|
|
D3D12_RESOURCE_BARRIER barrier = {};
|
|
|
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barrier.Transition.pResource = p_back_buffer;
|
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
|
|
|
m_p_command_graphics_list_screenshot->ResourceBarrier(1, &barrier);
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION src_loc = {};
|
|
src_loc.pResource = p_back_buffer;
|
|
src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
src_loc.SubresourceIndex = 0;
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION dst_loc = {};
|
|
dst_loc.pResource = p_cpu_readaccess_buffer;
|
|
dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
|
dst_loc.PlacedFootprint = layout;
|
|
|
|
m_p_command_graphics_list_screenshot->CopyTextureRegion(&dst_loc, 0, 0, 0, &src_loc, nullptr);
|
|
|
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
|
m_p_command_graphics_list_screenshot->ResourceBarrier(1, &barrier);
|
|
|
|
status = m_p_command_graphics_list_screenshot->Close();
|
|
RMLUI_DX_VERIFY_MSG(status, "failed ID3D12CommandGraphicsList::Close");
|
|
|
|
ID3D12CommandList* p_lists[] = {m_p_command_graphics_list_screenshot};
|
|
m_p_command_queue->ExecuteCommandLists(1, p_lists);
|
|
|
|
status = m_p_command_queue->Signal(m_p_fence_screenshot, m_fence_screenshot_value);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed ID3D12CommandQueue::Signal (screenshot)");
|
|
|
|
status = m_p_fence_screenshot->SetEventOnCompletion(m_fence_screenshot_value, m_p_fence_event_screenshot);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed ID3D12Fence::SetEventOnCompletion (screenshot)");
|
|
|
|
WaitForSingleObject(m_p_fence_event_screenshot, INFINITE);
|
|
++m_fence_screenshot_value;
|
|
|
|
void* p_mapped_data = nullptr;
|
|
status = p_cpu_readaccess_buffer->Map(0, nullptr, &p_mapped_data);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to Map buffer (screenshot)");
|
|
|
|
bool result = false;
|
|
if (SUCCEEDED(status))
|
|
{
|
|
const size_t source_num_components = 4;
|
|
const size_t target_num_components = 3;
|
|
const size_t width = desc.Width;
|
|
const size_t height = desc.Height;
|
|
|
|
const size_t target_row_size_bytes = target_num_components * width;
|
|
const size_t target_data_size = target_row_size_bytes * height;
|
|
out_data.reset(new Rml::byte[target_data_size]);
|
|
|
|
for (size_t y = 0; y < height; y++)
|
|
{
|
|
byte* source_row_origin = reinterpret_cast<Rml::byte*>(p_mapped_data) + (height - 1 - y) * layout.Footprint.RowPitch;
|
|
byte* target_row_origin = out_data.get() + y * width * target_num_components;
|
|
|
|
for (size_t x = 0; x < width; x++)
|
|
{
|
|
std::memcpy(target_row_origin + x * target_num_components, source_row_origin + x * source_num_components, target_num_components);
|
|
}
|
|
}
|
|
|
|
out_width = static_cast<int>(width);
|
|
out_height = static_cast<int>(height);
|
|
out_num_components = target_num_components;
|
|
result = true;
|
|
}
|
|
|
|
p_cpu_readaccess_buffer->Unmap(0, nullptr);
|
|
p_back_buffer->Release();
|
|
p_cpu_readaccess_buffer->Release();
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (result)
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12]: successfully captured data of swapchain backbuffer");
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
void RenderInterface_DX12::Initialize_Device() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Initialize_Device");
|
|
RMLUI_ASSERTMSG(m_p_adapter, "you must call this when you initialized adapter!");
|
|
|
|
ID3D12Device2* p_device{};
|
|
|
|
RMLUI_DX_VERIFY_MSG(D3D12CreateDevice(m_p_adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&p_device)), "failed to D3D12CreateDevice");
|
|
|
|
m_p_device = p_device;
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
ID3D12InfoQueue* p_queue{};
|
|
if (p_device)
|
|
{
|
|
RMLUI_DX_VERIFY_MSG(p_device->QueryInterface(IID_PPV_ARGS(&p_queue)), "failed to QueryInterface of ID3D12InfoQueue");
|
|
|
|
if (p_queue)
|
|
{
|
|
// if implementation is good breaking will NOT be caused at all, but if something is bad you will get __debugbreak in Debug after
|
|
// ReportLiveObjects calling that means system works not correctly for D3D12 API at all and you must fix these problems what your device
|
|
// reported (it might be annoying because you will not see the result of ReportLiveObjects and you should comment these line of
|
|
// SetBreakOnSeverity in order to see full report from ReportLiveObjects calling)
|
|
p_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, 1);
|
|
p_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, 1);
|
|
|
|
// Currently we get warnings about scissors being set with zero drawable area, i.e. p0.x == p1.x or p0.y ==
|
|
// p1.y. This is how the RmlUi API works right now and is expected. We could add more conditions to avoid
|
|
// drawing in these situations, eeither on the RmlUi-side or in the renderer. But for now we ignore the
|
|
// warning, it shouldn't cause any issues.
|
|
// p_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, 1);
|
|
|
|
// Suppress messages based on their severity level
|
|
D3D12_MESSAGE_SEVERITY p_sevs[] = {D3D12_MESSAGE_SEVERITY_INFO};
|
|
|
|
D3D12_INFO_QUEUE_FILTER info_filter = {};
|
|
info_filter.DenyList.NumSeverities = _countof(p_sevs);
|
|
info_filter.DenyList.pSeverityList = p_sevs;
|
|
|
|
RMLUI_DX_VERIFY_MSG(p_queue->PushStorageFilter(&info_filter), "failed to PushStorageFilter");
|
|
|
|
p_queue->Release();
|
|
}
|
|
|
|
ID3D12DebugDevice* p_sdk_device{};
|
|
auto status = p_device->QueryInterface(IID_PPV_ARGS(&p_sdk_device));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to obtain debug device!");
|
|
|
|
if (p_sdk_device)
|
|
{
|
|
status = p_sdk_device->SetFeatureMask(D3D12_DEBUG_FEATURE_CONSERVATIVE_RESOURCE_STATE_TRACKING);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to enable feature conservative resource state tracking");
|
|
|
|
p_sdk_device->Release();
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void RenderInterface_DX12::Initialize_Adapter() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Initialize_Adapter");
|
|
if (m_p_adapter)
|
|
{
|
|
m_p_adapter->Release();
|
|
}
|
|
|
|
m_p_adapter = Get_Adapter(false);
|
|
}
|
|
|
|
void RenderInterface_DX12::Initialize_DebugLayer() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Initialize_DebugLayer");
|
|
#ifdef RMLUI_DX_DEBUG
|
|
ID3D12Debug* p_debug{};
|
|
|
|
RMLUI_DX_VERIFY_MSG(D3D12GetDebugInterface(IID_PPV_ARGS(&p_debug)), "failed to D3D12GetDebugInterface");
|
|
|
|
if (p_debug)
|
|
{
|
|
p_debug->EnableDebugLayer();
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12] Debug Layer = ENABLED!");
|
|
#endif
|
|
|
|
ID3D12Debug1* p_sdk_layers{};
|
|
|
|
auto status = p_debug->QueryInterface(IID_PPV_ARGS(&p_sdk_layers));
|
|
|
|
RMLUI_DX_VERIFY_MSG(status,
|
|
"failed to enable GPU based validation :( your driver or windows NT sdk doesn't support a such feature report to developers DX12 SDK or "
|
|
"to GPU vendor developers");
|
|
|
|
if (SUCCEEDED(status))
|
|
{
|
|
p_sdk_layers->SetEnableGPUBasedValidation(TRUE);
|
|
p_sdk_layers->SetEnableSynchronizedCommandQueueValidation(TRUE);
|
|
p_sdk_layers->Release();
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12] GPU validation = ENABLED!");
|
|
#endif
|
|
}
|
|
|
|
p_debug->Release();
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
ID3D12CommandQueue* RenderInterface_DX12::Create_CommandQueue(D3D12_COMMAND_LIST_TYPE type) noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_CommandQueue");
|
|
RMLUI_ASSERTMSG(m_p_device, "you must initialize device before calling this method");
|
|
|
|
ID3D12CommandQueue* p_result{};
|
|
if (m_p_device)
|
|
{
|
|
D3D12_COMMAND_QUEUE_DESC desc = {};
|
|
|
|
desc.Type = type;
|
|
desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
|
|
desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
|
desc.NodeMask = 0;
|
|
|
|
RMLUI_DX_VERIFY_MSG(m_p_device->CreateCommandQueue(&desc, IID_PPV_ARGS(&p_result)), "failed to CreateCommandQueue");
|
|
}
|
|
|
|
return p_result;
|
|
}
|
|
|
|
void RenderInterface_DX12::Initialize_Swapchain(int width, int height) noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Initialize_Swapchain");
|
|
RMLUI_ASSERTMSG(width >= 0, "must not be a negative value");
|
|
RMLUI_ASSERTMSG(height >= 0, "must not be a negative value");
|
|
|
|
// in dx12 0 means it will take size of window automatically
|
|
if (width < 0)
|
|
width = 0;
|
|
|
|
if (height < 0)
|
|
height = 0;
|
|
|
|
IDXGISwapChain4* p_swapchain{};
|
|
IDXGIFactory4* p_factory{};
|
|
|
|
uint32_t create_factory_flags{};
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
create_factory_flags = DXGI_CREATE_FACTORY_DEBUG;
|
|
#endif
|
|
|
|
RMLUI_DX_VERIFY_MSG(CreateDXGIFactory2(create_factory_flags, IID_PPV_ARGS(&p_factory)), "failed to CreateDXGIFactory2");
|
|
|
|
m_desc_sample.Count = m_msaa_sample_count;
|
|
m_desc_sample.Quality = 0;
|
|
|
|
DXGI_SWAP_CHAIN_DESC1 desc = {};
|
|
|
|
desc.Width = width;
|
|
desc.Height = height;
|
|
desc.Format = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc.Stereo = 0;
|
|
// since we can't use rt textures with different sample count than Swapchain's so we create framebuffers and presenting them on NO-MSAA
|
|
// Swapchain
|
|
desc.SampleDesc.Count = 1;
|
|
desc.SampleDesc.Quality = 0;
|
|
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
|
desc.BufferCount = RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT;
|
|
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
|
desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
|
|
|
|
uint32_t flags_swapchain{};
|
|
|
|
if (CheckTearingSupport())
|
|
{
|
|
flags_swapchain = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
|
m_is_use_tearing = true;
|
|
}
|
|
|
|
desc.Flags = flags_swapchain;
|
|
|
|
IDXGISwapChain1* p_swapchain1{};
|
|
|
|
RMLUI_DX_VERIFY_MSG(p_factory->CreateSwapChainForHwnd(m_p_command_queue, m_p_window_handle, &desc, nullptr, nullptr, &p_swapchain1),
|
|
"failed to CreateSwapChainForHwnd");
|
|
|
|
RMLUI_DX_VERIFY_MSG(p_factory->MakeWindowAssociation(m_p_window_handle, DXGI_MWA_NO_ALT_ENTER), "failed to MakeWindowAssociation");
|
|
|
|
RMLUI_DX_VERIFY_MSG(p_swapchain1->QueryInterface(IID_PPV_ARGS(&p_swapchain)), "failed to QueryInterface of IDXGISwapChain4");
|
|
|
|
m_p_swapchain = p_swapchain;
|
|
|
|
if (p_swapchain1)
|
|
{
|
|
p_swapchain1->Release();
|
|
}
|
|
|
|
if (p_factory)
|
|
{
|
|
p_factory->Release();
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Initialize_SyncPrimitives() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Initialize_SyncPrimitives");
|
|
RMLUI_ASSERTMSG(m_p_device, "you must initialize device before calling this method!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
for (int i = 0; i < RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT; ++i)
|
|
{
|
|
m_backbuffers_fence_values[i] = 0;
|
|
}
|
|
|
|
m_p_device->CreateFence(0, D3D12_FENCE_FLAGS::D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_p_backbuffer_fence));
|
|
|
|
m_p_fence_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
RMLUI_ASSERTMSG(m_p_fence_event, "failed to CreateEvent (WinAPI)");
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Initialize_SyncPrimitives_Screenshot() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Initialize_SyncPrimitives_Screenshot");
|
|
RMLUI_ASSERTMSG(m_p_device, "you must initialize device before calling this method!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
HRESULT status = m_p_device->CreateFence(0, D3D12_FENCE_FLAGS::D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_p_fence_screenshot));
|
|
RMLUI_DX_VERIFY_MSG(status, "ID3D12Device::CreateFence failed! (screenshot)");
|
|
|
|
m_p_fence_event_screenshot = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
RMLUI_ASSERTMSG(m_p_fence_event_screenshot, "failed to CreateEvent (Screenshot)");
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Initialize_CommandAllocators()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Initialize_CommandAllocators");
|
|
for (int i = 0; i < RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT; ++i)
|
|
{
|
|
m_backbuffers_allocators[i] = Create_CommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT);
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Initialize_Allocator() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Initialize_Allocator");
|
|
|
|
// I guess better to isolate allocations from user side and using own allocators under of rmlui's renderer thus we forced for creating allocator
|
|
{
|
|
RMLUI_ASSERTMSG(!m_p_allocator, "forgot to destroy before initialization!");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid when you call this method!");
|
|
RMLUI_ASSERTMSG(m_p_adapter, "must be valid when you call this method!");
|
|
|
|
D3D12MA::ALLOCATOR_DESC desc = {};
|
|
desc.pDevice = m_p_device;
|
|
desc.pAdapter = m_p_adapter;
|
|
|
|
D3D12MA::Allocator* p_allocator{};
|
|
|
|
RMLUI_DX_VERIFY_MSG(D3D12MA::CreateAllocator(&desc, &p_allocator), "failed to D3D12MA::CreateAllocator!");
|
|
RMLUI_ASSERTMSG(p_allocator, "failed to create allocator!");
|
|
|
|
m_p_allocator = p_allocator;
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Destroy_Swapchain() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Destroy_Swapchain");
|
|
if (m_p_swapchain)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_swapchain->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
m_p_swapchain = nullptr;
|
|
}
|
|
|
|
void RenderInterface_DX12::Destroy_SyncPrimitives() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Destroy_SyncPrimitives");
|
|
if (m_p_backbuffer_fence)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_backbuffer_fence->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
m_p_backbuffer_fence = nullptr;
|
|
}
|
|
|
|
void RenderInterface_DX12::Destroy_CommandAllocators() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Destroy_CommandAllocators");
|
|
for (ID3D12CommandAllocator* p_allocator : m_backbuffers_allocators)
|
|
{
|
|
RMLUI_ASSERTMSG(p_allocator, "early calling or object is damaged!");
|
|
if (p_allocator)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = p_allocator->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Destroy_CommandList() noexcept {}
|
|
|
|
void RenderInterface_DX12::Destroy_Allocator() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Destroy_Allocator");
|
|
if (m_p_allocator)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_allocator->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Destroy_SyncPrimitives_Screenshot() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Destroy_SyncPrimitives_Screenshot");
|
|
|
|
if (m_p_fence_screenshot)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_fence_screenshot->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
|
|
m_p_fence_screenshot = nullptr;
|
|
}
|
|
|
|
if (m_p_fence_event_screenshot)
|
|
{
|
|
CloseHandle(m_p_fence_event_screenshot);
|
|
m_p_fence_event_screenshot = nullptr;
|
|
}
|
|
|
|
m_fence_screenshot_value = 0;
|
|
}
|
|
|
|
void RenderInterface_DX12::Flush() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Flush");
|
|
Signal(m_current_back_buffer_index);
|
|
RMLUI_ASSERTMSG(m_p_backbuffer_fence, "you must initialize ID3D12Fence first!");
|
|
RMLUI_ASSERTMSG(m_p_fence_event, "you must initialize fence event (HANDLE)");
|
|
|
|
if (m_p_backbuffer_fence)
|
|
{
|
|
if (m_p_fence_event)
|
|
{
|
|
RMLUI_DX_VERIFY_MSG(
|
|
m_p_backbuffer_fence->SetEventOnCompletion(m_backbuffers_fence_values.at(m_current_back_buffer_index), m_p_fence_event),
|
|
"failed to SetEventOnCompletion");
|
|
WaitForSingleObjectEx(m_p_fence_event, INFINITE, FALSE);
|
|
}
|
|
}
|
|
|
|
m_backbuffers_fence_values[m_current_back_buffer_index]++;
|
|
}
|
|
|
|
uint64_t RenderInterface_DX12::Signal(uint32_t frame_index) noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Signal");
|
|
RMLUI_ASSERTMSG(m_p_command_queue, "you must initialize it first before calling this method!");
|
|
RMLUI_ASSERTMSG(m_p_backbuffer_fence, "you must initialize it first before calling this method!");
|
|
|
|
if (m_p_command_queue)
|
|
{
|
|
if (m_p_backbuffer_fence)
|
|
{
|
|
auto value = (m_backbuffers_fence_values.at(frame_index));
|
|
|
|
RMLUI_DX_VERIFY_MSG(m_p_command_queue->Signal(m_p_backbuffer_fence, value), "failed to command queue::Signal!");
|
|
|
|
return value;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void RenderInterface_DX12::WaitForFenceValue(uint32_t frame_index)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - WaitForFenceValue");
|
|
RMLUI_ASSERTMSG(m_p_backbuffer_fence, "you must initialize ID3D12Fence first!");
|
|
RMLUI_ASSERTMSG(m_p_fence_event, "you must initialize fence event (HANDLE)");
|
|
|
|
if (m_p_backbuffer_fence)
|
|
{
|
|
if (m_p_fence_event)
|
|
{
|
|
if (m_p_backbuffer_fence->GetCompletedValue() < m_backbuffers_fence_values.at(frame_index))
|
|
{
|
|
RMLUI_DX_VERIFY_MSG(m_p_backbuffer_fence->SetEventOnCompletion(m_backbuffers_fence_values.at(frame_index), m_p_fence_event),
|
|
"failed to SetEventOnCompletion");
|
|
WaitForSingleObjectEx(m_p_fence_event, INFINITE, FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resources_DependentOnSize() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resources_DependentOnSize");
|
|
Create_Resource_RenderTargetViews();
|
|
// Create_Resource_Pipelines();
|
|
}
|
|
|
|
void RenderInterface_DX12::Destroy_Resources_DependentOnSize() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Destroy_Resources_DependentOnSize");
|
|
// Destroy_Resource_Pipelines();
|
|
Destroy_Resource_RenderTagetViews();
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resource_DepthStencil()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_DepthStencil");
|
|
RMLUI_ASSERTMSG(m_p_descriptor_heap_depthstencil, "you must initialize this descriptor heap before calling this method!");
|
|
RMLUI_ASSERTMSG(m_p_device, "you must create device!");
|
|
RMLUI_ASSERTMSG(m_width > 0, "invalid width");
|
|
RMLUI_ASSERTMSG(m_height > 0, "invalid height");
|
|
|
|
D3D12MA::ALLOCATION_DESC desc_alloc = {};
|
|
desc_alloc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
|
|
|
|
D3D12_RESOURCE_DESC desc_texture = {};
|
|
desc_texture.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
desc_texture.Format = RMLUI_RENDER_BACKEND_FIELD_DEPTHSTENCIL_TEXTURE_FORMAT;
|
|
desc_texture.MipLevels = 1;
|
|
desc_texture.Width = m_width;
|
|
desc_texture.Height = m_height;
|
|
desc_texture.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
desc_texture.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
|
desc_texture.SampleDesc.Count = 1;
|
|
desc_texture.SampleDesc.Quality = 0;
|
|
desc_texture.DepthOrArraySize = 1;
|
|
desc_texture.Alignment = 0;
|
|
|
|
D3D12_CLEAR_VALUE depth_optimized_clear_value = {};
|
|
depth_optimized_clear_value.Format = RMLUI_RENDER_BACKEND_FIELD_DEPTHSTENCIL_TEXTURE_FORMAT;
|
|
depth_optimized_clear_value.DepthStencil.Depth = RMLUI_RENDER_BACKEND_FIELD_CLEAR_VALUE_DEPTHSTENCIL_DEPTH_VALUE;
|
|
depth_optimized_clear_value.DepthStencil.Stencil = RMLUI_RENDER_BACKEND_FIELD_CLEAR_VALUE_DEPTHSTENCIL_STENCIL_VALUE;
|
|
|
|
ID3D12Resource* p_temp{};
|
|
auto status = m_p_allocator->CreateResource(&desc_alloc, &desc_texture, D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_DEPTH_WRITE,
|
|
&depth_optimized_clear_value, &m_p_depthstencil_resource, IID_PPV_ARGS(&p_temp));
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to create resource as depth stencil texture!");
|
|
|
|
RMLUI_ASSERTMSG(m_p_depthstencil_resource, "must be created!");
|
|
RMLUI_ASSERTMSG(p_temp, "must be created!");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_p_depthstencil_resource->SetName(L"DepthStencil texture (resource)");
|
|
#endif
|
|
|
|
D3D12_DEPTH_STENCIL_VIEW_DESC desc_view = {};
|
|
desc_view.Format = RMLUI_RENDER_BACKEND_FIELD_DEPTHSTENCIL_TEXTURE_FORMAT;
|
|
desc_view.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
|
|
desc_view.Flags = D3D12_DSV_FLAG_NONE;
|
|
|
|
m_p_device->CreateDepthStencilView(m_p_depthstencil_resource->GetResource(), &desc_view,
|
|
m_p_descriptor_heap_depthstencil->GetCPUDescriptorHandleForHeapStart());
|
|
}
|
|
|
|
void RenderInterface_DX12::Destroy_Resource_DepthStencil()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Destroy_Resource_DepthStencil");
|
|
RMLUI_ASSERTMSG(m_p_depthstencil_resource, "you must create resource for calling this method!");
|
|
RMLUI_ASSERTMSG(m_p_depthstencil_resource->GetResource(), "must be valid!");
|
|
|
|
if (m_p_depthstencil_resource)
|
|
{
|
|
if (m_p_depthstencil_resource->GetResource())
|
|
{
|
|
m_p_depthstencil_resource->GetResource()->Release();
|
|
}
|
|
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto count = m_p_depthstencil_resource->Release();
|
|
RMLUI_ASSERTMSG(count == 0, "leak!");
|
|
|
|
m_p_depthstencil_resource = nullptr;
|
|
}
|
|
}
|
|
|
|
ID3D12DescriptorHeap* RenderInterface_DX12::Create_Resource_DescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags,
|
|
uint32_t descriptor_count) noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_DescriptorHeap");
|
|
RMLUI_ASSERTMSG(m_p_device, "early calling you have to initialize device first");
|
|
|
|
ID3D12DescriptorHeap* p_result{};
|
|
|
|
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
|
|
desc.NumDescriptors = descriptor_count;
|
|
desc.Type = type;
|
|
desc.Flags = flags;
|
|
|
|
RMLUI_DX_VERIFY_MSG(m_p_device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&p_result)), "failed to CreateDescriptorHeap");
|
|
|
|
return p_result;
|
|
}
|
|
|
|
ID3D12CommandAllocator* RenderInterface_DX12::Create_CommandAllocator(D3D12_COMMAND_LIST_TYPE type)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_CommandAllocator");
|
|
ID3D12CommandAllocator* p_result{};
|
|
|
|
RMLUI_ASSERTMSG(m_p_device, "you must initialize device first!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
RMLUI_DX_VERIFY_MSG(m_p_device->CreateCommandAllocator(type, IID_PPV_ARGS(&p_result)), "failed to CreateCommandAllocator");
|
|
|
|
RMLUI_ASSERTMSG(p_result, "can't allocate command allocator!");
|
|
}
|
|
|
|
return p_result;
|
|
}
|
|
|
|
ID3D12GraphicsCommandList* RenderInterface_DX12::Create_CommandList(ID3D12CommandAllocator* p_allocator, D3D12_COMMAND_LIST_TYPE type) noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_CommandList");
|
|
ID3D12GraphicsCommandList* p_result{};
|
|
|
|
RMLUI_ASSERTMSG(m_p_device, "you must initialize device first!");
|
|
RMLUI_ASSERTMSG(p_allocator, "you must pass a valid instance of ID3D12CommandAllocator*");
|
|
|
|
if (m_p_device)
|
|
{
|
|
RMLUI_DX_VERIFY_MSG(m_p_device->CreateCommandList(0, type, p_allocator, nullptr, IID_PPV_ARGS(&p_result)), "failed to CreateCommandList");
|
|
RMLUI_ASSERTMSG(p_result, "can't allocator command list!");
|
|
|
|
if (p_result)
|
|
{
|
|
RMLUI_DX_VERIFY_MSG(p_result->Close(), "failed to Close command list!");
|
|
}
|
|
}
|
|
|
|
return p_result;
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resource_RenderTargetViews()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_RenderTargetViews");
|
|
RMLUI_ASSERTMSG(m_p_device, "early calling you have to initialize device first!");
|
|
RMLUI_ASSERTMSG(m_p_swapchain, "early calling you have to initialize swapchain first!");
|
|
RMLUI_ASSERTMSG(m_p_descriptor_heap_render_target_view, "early calling you have to initialize descriptor heap for render target views first!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
if (m_p_swapchain)
|
|
{
|
|
if (m_p_descriptor_heap_render_target_view)
|
|
{
|
|
auto rtv_size = m_p_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
|
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle(m_p_descriptor_heap_render_target_view->GetCPUDescriptorHandleForHeapStart());
|
|
|
|
for (auto i = 0; i < RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT; ++i)
|
|
{
|
|
ID3D12Resource* p_back_buffer{};
|
|
|
|
RMLUI_DX_VERIFY_MSG(m_p_swapchain->GetBuffer(i, IID_PPV_ARGS(&p_back_buffer)), "failed to GetBuffer from swapchain");
|
|
|
|
m_p_device->CreateRenderTargetView(p_back_buffer, nullptr, rtv_handle);
|
|
|
|
m_backbuffers_resources[i] = p_back_buffer;
|
|
|
|
rtv_handle.ptr += (rtv_size);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Destroy_Resource_RenderTagetViews()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Destroy_Resource_RenderTargetViews");
|
|
for (ID3D12Resource* p_backbuffer : m_backbuffers_resources)
|
|
{
|
|
RMLUI_ASSERTMSG(p_backbuffer, "it is strange must be always valid pointer!");
|
|
|
|
if (p_backbuffer)
|
|
{
|
|
p_backbuffer->Release();
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT; ++i)
|
|
{
|
|
m_backbuffers_resources[i] = nullptr;
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Destroy_Resource_For_Shaders()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Destroy_Resource_For_Shaders");
|
|
for (auto& vec_cb_per_frame : m_constantbuffers)
|
|
{
|
|
for (auto& cb : vec_cb_per_frame)
|
|
{
|
|
m_manager_buffer.Free_ConstantBuffer(&cb);
|
|
}
|
|
}
|
|
|
|
for (unsigned char i = 0; i < RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT; ++i)
|
|
{
|
|
m_constantbuffers[i].clear();
|
|
}
|
|
|
|
Update_PendingForDeletion_Geometry();
|
|
}
|
|
|
|
void RenderInterface_DX12::Free_Geometry(RenderInterface_DX12::GeometryHandleType* p_handle)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Free_Geometry");
|
|
RMLUI_ASSERTMSG(p_handle, "invalid handle");
|
|
|
|
if (p_handle)
|
|
{
|
|
m_manager_buffer.Free_Geometry(p_handle);
|
|
delete p_handle;
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Free_Texture(RenderInterface_DX12::TextureHandleType* p_handle)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Free_Texture");
|
|
RMLUI_ASSERTMSG(p_handle, "must be valid!");
|
|
|
|
if (p_handle)
|
|
{
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12] Destroyed texture: [%s]", p_handle->Get_ResourceName().c_str());
|
|
#endif
|
|
|
|
m_manager_texture.Free_Texture(p_handle);
|
|
delete p_handle;
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Update_PendingForDeletion_Geometry()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Update_PendingForDeletion_Geometry");
|
|
for (auto& p_handle : m_pending_for_deletion_geometry)
|
|
{
|
|
Free_Geometry(p_handle);
|
|
}
|
|
|
|
m_pending_for_deletion_geometry.clear();
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resource_Pipelines()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_Pipelines");
|
|
for (auto& vec_cb : m_constantbuffers)
|
|
{
|
|
vec_cb.resize(RMLUI_RENDER_BACKEND_FIELD_PREALLOCATED_CONSTANTBUFFERS);
|
|
}
|
|
|
|
for (auto& vec_cb : m_constantbuffers)
|
|
{
|
|
for (auto& cb : vec_cb)
|
|
{
|
|
const auto& info = m_manager_buffer.Alloc_ConstantBuffer(&cb, kAllocationSizeMax_ConstantBuffer);
|
|
cb.m_alloc_info = info;
|
|
}
|
|
}
|
|
|
|
m_pending_for_deletion_geometry.reserve(RMLUI_RENDER_BACKEND_FIELD_PREALLOCATED_CONSTANTBUFFERS);
|
|
|
|
Create_Resource_Pipeline_BlendMask();
|
|
Create_Resource_Pipeline_Blur();
|
|
Create_Resource_Pipeline_Color();
|
|
Create_Resource_Pipeline_ColorMatrix();
|
|
Create_Resource_Pipeline_Creation();
|
|
Create_Resource_Pipeline_DropShadow();
|
|
Create_Resource_Pipeline_Gradient();
|
|
Create_Resource_Pipeline_Passthrough();
|
|
Create_Resource_Pipeline_Passthrough_NoBlend();
|
|
Create_Resource_Pipeline_Texture();
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resource_Pipeline_Color()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_Pipeline_Color");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid when we call this method!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
D3D12_ROOT_DESCRIPTOR descriptor_cbv;
|
|
descriptor_cbv.RegisterSpace = 0;
|
|
descriptor_cbv.ShaderRegister = 0;
|
|
|
|
D3D12_ROOT_PARAMETER parameters[1];
|
|
|
|
parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
parameters[0].Descriptor = descriptor_cbv;
|
|
parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
|
|
|
|
D3D12_ROOT_SIGNATURE_DESC desc_rootsignature;
|
|
desc_rootsignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
|
|
desc_rootsignature.NumStaticSamplers = 0;
|
|
desc_rootsignature.pParameters = parameters;
|
|
desc_rootsignature.NumParameters = _countof(parameters);
|
|
desc_rootsignature.pStaticSamplers = nullptr;
|
|
|
|
ID3DBlob* p_signature{};
|
|
ID3DBlob* p_error{};
|
|
auto status = D3D12SerializeRootSignature(&desc_rootsignature, D3D_ROOT_SIGNATURE_VERSION_1, &p_signature, &p_error);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3D12SerializeRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Always)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
// stencil version
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Intersect)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Set)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_SetInverse)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Equal)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Disabled)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to Color_Stencil_Disabled");
|
|
|
|
if (p_signature)
|
|
{
|
|
p_signature->Release();
|
|
p_signature = nullptr;
|
|
}
|
|
|
|
if (p_error)
|
|
{
|
|
p_error->Release();
|
|
p_error = nullptr;
|
|
}
|
|
|
|
ID3DBlob* p_shader_vertex{};
|
|
ID3DBlob* p_shader_pixel{};
|
|
ID3DBlob* p_error_buff{};
|
|
|
|
status = D3DCompile(pShaderSourceText_Vertex, sizeof(pShaderSourceText_Vertex), nullptr, nullptr, nullptr, "main", "vs_5_0",
|
|
m_default_shader_flags, 0, &p_shader_vertex, &p_error_buff);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_ERROR, "failed to compile shader: %s", (char*)p_error_buff->GetBufferPointer());
|
|
}
|
|
#endif
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
status = D3DCompile(pShaderSourceText_Color, sizeof(pShaderSourceText_Color), nullptr, nullptr, nullptr, "main", "ps_5_0",
|
|
m_default_shader_flags, 0, &p_shader_pixel, &p_error_buff);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_ERROR, "failed to compile shader: %s", (char*)(p_error_buff->GetBufferPointer()));
|
|
}
|
|
#endif
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_pixel_shader = {};
|
|
desc_bytecode_pixel_shader.BytecodeLength = p_shader_pixel->GetBufferSize();
|
|
desc_bytecode_pixel_shader.pShaderBytecode = p_shader_pixel->GetBufferPointer();
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_vertex_shader = {};
|
|
desc_bytecode_vertex_shader.BytecodeLength = p_shader_vertex->GetBufferSize();
|
|
desc_bytecode_vertex_shader.pShaderBytecode = p_shader_vertex->GetBufferPointer();
|
|
|
|
D3D12_INPUT_ELEMENT_DESC desc_input_layout_elements[] = {
|
|
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}};
|
|
|
|
D3D12_INPUT_LAYOUT_DESC desc_input_layout = {};
|
|
|
|
desc_input_layout.NumElements = sizeof(desc_input_layout_elements) / sizeof(D3D12_INPUT_ELEMENT_DESC);
|
|
desc_input_layout.pInputElementDescs = desc_input_layout_elements;
|
|
|
|
D3D12_RASTERIZER_DESC desc_rasterizer = {};
|
|
|
|
desc_rasterizer.FillMode = D3D12_FILL_MODE_SOLID;
|
|
desc_rasterizer.CullMode = D3D12_CULL_MODE_NONE;
|
|
desc_rasterizer.FrontCounterClockwise = FALSE;
|
|
desc_rasterizer.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
|
|
desc_rasterizer.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
|
|
desc_rasterizer.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
|
|
desc_rasterizer.DepthClipEnable = FALSE;
|
|
desc_rasterizer.MultisampleEnable = FALSE;
|
|
desc_rasterizer.AntialiasedLineEnable = FALSE;
|
|
desc_rasterizer.ForcedSampleCount = 0;
|
|
desc_rasterizer.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
|
|
D3D12_BLEND_DESC desc_blend_state = {};
|
|
|
|
desc_blend_state.AlphaToCoverageEnable = FALSE;
|
|
desc_blend_state.IndependentBlendEnable = FALSE;
|
|
const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
|
|
TRUE,
|
|
FALSE,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_LOGIC_OP_NOOP,
|
|
D3D12_COLOR_WRITE_ENABLE_ALL,
|
|
};
|
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
desc_blend_state.RenderTarget[i] = defaultRenderTargetBlendDesc;
|
|
|
|
D3D12_DEPTH_STENCIL_DESC desc_depth_stencil = {};
|
|
|
|
desc_depth_stencil.DepthEnable = FALSE;
|
|
desc_depth_stencil.StencilEnable = TRUE;
|
|
desc_depth_stencil.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
|
desc_depth_stencil.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
|
|
desc_depth_stencil.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
desc_depth_stencil.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_pipeline = {};
|
|
|
|
desc_pipeline.InputLayout = desc_input_layout;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Always)];
|
|
desc_pipeline.VS = desc_bytecode_vertex_shader;
|
|
desc_pipeline.PS = desc_bytecode_pixel_shader;
|
|
desc_pipeline.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
desc_pipeline.RTVFormats[0] = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc_pipeline.DSVFormat = RMLUI_RENDER_BACKEND_FIELD_DEPTHSTENCIL_TEXTURE_FORMAT;
|
|
desc_pipeline.SampleDesc = m_desc_sample;
|
|
desc_pipeline.SampleMask = 0xffffffff;
|
|
desc_pipeline.RasterizerState = desc_rasterizer;
|
|
desc_pipeline.BlendState = desc_blend_state;
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
desc_pipeline.NumRenderTargets = 1;
|
|
|
|
status =
|
|
m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Color_Stencil_Always)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (color)");
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_INCR;
|
|
desc_depth_stencil.BackFace = desc_depth_stencil.FrontFace;
|
|
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Intersect)];
|
|
|
|
desc_blend_state.AlphaToCoverageEnable = FALSE;
|
|
desc_blend_state.IndependentBlendEnable = FALSE;
|
|
const D3D12_RENDER_TARGET_BLEND_DESC editedRenderTargetBlend = {
|
|
TRUE,
|
|
FALSE,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_LOGIC_OP_NOOP,
|
|
0,
|
|
};
|
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
desc_blend_state.RenderTarget[i] = editedRenderTargetBlend;
|
|
|
|
desc_pipeline.BlendState = desc_blend_state;
|
|
|
|
status =
|
|
m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Color_Stencil_Intersect)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (color_stencil_intersect)");
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
|
|
desc_depth_stencil.BackFace = desc_depth_stencil.FrontFace;
|
|
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_SetInverse)];
|
|
|
|
status = m_p_device->CreateGraphicsPipelineState(&desc_pipeline,
|
|
IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Color_Stencil_SetInverse)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (color_stencil_setinverse)");
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
|
|
desc_depth_stencil.BackFace = desc_depth_stencil.FrontFace;
|
|
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Set)];
|
|
|
|
status = m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Color_Stencil_Set)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (color_stencil_set)");
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
desc_depth_stencil.BackFace = desc_depth_stencil.FrontFace;
|
|
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Equal)];
|
|
|
|
desc_blend_state.AlphaToCoverageEnable = FALSE;
|
|
desc_blend_state.IndependentBlendEnable = FALSE;
|
|
const D3D12_RENDER_TARGET_BLEND_DESC editedRenderTargetBlend2 = {
|
|
TRUE,
|
|
FALSE,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_LOGIC_OP_NOOP,
|
|
D3D12_COLOR_WRITE_ENABLE_ALL,
|
|
};
|
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
desc_blend_state.RenderTarget[i] = editedRenderTargetBlend2;
|
|
|
|
desc_pipeline.BlendState = desc_blend_state;
|
|
|
|
status =
|
|
m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Color_Stencil_Equal)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Color_Stencil_Equal)");
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
desc_depth_stencil.BackFace = desc_depth_stencil.FrontFace;
|
|
desc_depth_stencil.StencilEnable = FALSE;
|
|
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Disabled)];
|
|
|
|
desc_pipeline.BlendState = desc_blend_state;
|
|
|
|
status =
|
|
m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Color_Stencil_Disabled)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Color_Stencil_Disabled)");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Always)]->SetName(TEXT("rs of Color_Stencil_Always"));
|
|
m_pipelines[static_cast<int>(ProgramId::Color_Stencil_Always)]->SetName(TEXT("pipeline Color_Stencil_Always"));
|
|
|
|
m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Set)]->SetName(TEXT("rs of Color_Stencil_Set"));
|
|
m_pipelines[static_cast<int>(ProgramId::Color_Stencil_Set)]->SetName(TEXT("pipeline Color_Stencil_Set"));
|
|
|
|
m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_SetInverse)]->SetName(TEXT("rs of Color_Stencil_SetInverse"));
|
|
m_pipelines[static_cast<int>(ProgramId::Color_Stencil_SetInverse)]->SetName(TEXT("pipeline Color_Stencil_SetInverse"));
|
|
|
|
m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Intersect)]->SetName(TEXT("rs of Color_Stencil_Intersect"));
|
|
m_pipelines[static_cast<int>(ProgramId::Color_Stencil_Intersect)]->SetName(TEXT("pipeline Color_Stencil_Intersect"));
|
|
|
|
m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Equal)]->SetName(TEXT("rs of Color_Stencil_Equal"));
|
|
m_pipelines[static_cast<int>(ProgramId::Color_Stencil_Equal)]->SetName(TEXT("pipeline Color_Stencil_Equal"));
|
|
|
|
m_root_signatures[static_cast<int>(ProgramId::Color_Stencil_Disabled)]->SetName(TEXT("rs of Color_Stencil_Disabled"));
|
|
m_pipelines[static_cast<int>(ProgramId::Color_Stencil_Disabled)]->SetName(TEXT("pipeline Color_Stencil_Disabled"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resource_Pipeline_Texture()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_Pipeline_Texture");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid when we call this method!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
D3D12_DESCRIPTOR_RANGE ranges[1];
|
|
ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
|
ranges[0].NumDescriptors = 1;
|
|
ranges[0].BaseShaderRegister = 0;
|
|
ranges[0].RegisterSpace = 0;
|
|
ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
|
|
|
D3D12_ROOT_DESCRIPTOR_TABLE table{};
|
|
table.NumDescriptorRanges = sizeof(ranges) / sizeof(decltype(ranges[0]));
|
|
table.pDescriptorRanges = ranges;
|
|
|
|
D3D12_ROOT_DESCRIPTOR descriptor_cbv{};
|
|
descriptor_cbv.RegisterSpace = 0;
|
|
descriptor_cbv.ShaderRegister = 0;
|
|
|
|
D3D12_ROOT_PARAMETER parameters[2];
|
|
parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
|
parameters[1].DescriptorTable = table;
|
|
parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
parameters[0].Descriptor = descriptor_cbv;
|
|
parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
|
|
|
|
D3D12_STATIC_SAMPLER_DESC sampler = {};
|
|
sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
|
sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.MipLODBias = 0;
|
|
sampler.MaxAnisotropy = 0;
|
|
sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
|
sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
|
|
sampler.MinLOD = 0.0f;
|
|
sampler.MaxLOD = D3D12_FLOAT32_MAX;
|
|
sampler.ShaderRegister = 0;
|
|
sampler.RegisterSpace = 0;
|
|
sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_ROOT_SIGNATURE_DESC desc_rootsignature;
|
|
desc_rootsignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
|
|
desc_rootsignature.NumParameters = _countof(parameters);
|
|
desc_rootsignature.pParameters = parameters;
|
|
desc_rootsignature.pStaticSamplers = &sampler;
|
|
desc_rootsignature.NumStaticSamplers = 1;
|
|
|
|
ID3DBlob* p_signature{};
|
|
ID3DBlob* p_error{};
|
|
auto status = D3D12SerializeRootSignature(&desc_rootsignature, D3D_ROOT_SIGNATURE_VERSION_1, &p_signature, &p_error);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to D3D12SerializeRootSignature: %s",
|
|
(char*)p_error->GetBufferPointer());
|
|
}
|
|
#endif
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3D12SerializeRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Texture_Stencil_Always)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Texture_Stencil_Equal)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Texture_Stencil_Disabled)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
if (p_signature)
|
|
{
|
|
p_signature->Release();
|
|
p_signature = nullptr;
|
|
}
|
|
|
|
if (p_error)
|
|
{
|
|
p_error->Release();
|
|
p_error = nullptr;
|
|
}
|
|
|
|
ID3DBlob* p_shader_vertex{};
|
|
ID3DBlob* p_shader_pixel{};
|
|
ID3DBlob* p_error_buff{};
|
|
|
|
const D3D_SHADER_MACRO macros[] = {NULL, NULL, NULL, NULL};
|
|
|
|
status = D3DCompile(pShaderSourceText_Vertex, sizeof(pShaderSourceText_Vertex), nullptr, macros, nullptr, "main", "vs_5_0",
|
|
m_default_shader_flags, 0, &p_shader_vertex, &p_error_buff);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s", (char*)p_error_buff->GetBufferPointer());
|
|
}
|
|
#endif
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
status = D3DCompile(pShaderSourceText_Texture, sizeof(pShaderSourceText_Texture), nullptr, nullptr, nullptr, "main", "ps_5_0",
|
|
m_default_shader_flags, 0, &p_shader_pixel, &p_error_buff);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s",
|
|
(char*)(p_error_buff->GetBufferPointer()));
|
|
}
|
|
#endif
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_pixel_shader = {};
|
|
desc_bytecode_pixel_shader.BytecodeLength = p_shader_pixel->GetBufferSize();
|
|
desc_bytecode_pixel_shader.pShaderBytecode = p_shader_pixel->GetBufferPointer();
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_vertex_shader = {};
|
|
desc_bytecode_vertex_shader.BytecodeLength = p_shader_vertex->GetBufferSize();
|
|
desc_bytecode_vertex_shader.pShaderBytecode = p_shader_vertex->GetBufferPointer();
|
|
|
|
D3D12_INPUT_ELEMENT_DESC desc_input_layout_elements[] = {
|
|
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}};
|
|
|
|
D3D12_INPUT_LAYOUT_DESC desc_input_layout = {};
|
|
|
|
desc_input_layout.NumElements = sizeof(desc_input_layout_elements) / sizeof(D3D12_INPUT_ELEMENT_DESC);
|
|
desc_input_layout.pInputElementDescs = desc_input_layout_elements;
|
|
|
|
D3D12_RASTERIZER_DESC desc_rasterizer = {};
|
|
|
|
desc_rasterizer.AntialiasedLineEnable = FALSE;
|
|
desc_rasterizer.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
desc_rasterizer.CullMode = D3D12_CULL_MODE_NONE;
|
|
desc_rasterizer.DepthBias = 0;
|
|
desc_rasterizer.DepthBiasClamp = 0;
|
|
desc_rasterizer.DepthClipEnable = FALSE;
|
|
desc_rasterizer.ForcedSampleCount = 0;
|
|
desc_rasterizer.FrontCounterClockwise = FALSE;
|
|
desc_rasterizer.MultisampleEnable = FALSE;
|
|
desc_rasterizer.FillMode = D3D12_FILL_MODE::D3D12_FILL_MODE_SOLID;
|
|
desc_rasterizer.SlopeScaledDepthBias = 0;
|
|
|
|
D3D12_BLEND_DESC desc_blend_state = {};
|
|
|
|
desc_blend_state.AlphaToCoverageEnable = FALSE;
|
|
desc_blend_state.IndependentBlendEnable = FALSE;
|
|
const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
|
|
TRUE,
|
|
FALSE,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_LOGIC_OP_NOOP,
|
|
D3D12_COLOR_WRITE_ENABLE_ALL,
|
|
};
|
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
desc_blend_state.RenderTarget[i] = defaultRenderTargetBlendDesc;
|
|
|
|
D3D12_DEPTH_STENCIL_DESC desc_depth_stencil = {};
|
|
|
|
desc_depth_stencil.DepthEnable = FALSE;
|
|
desc_depth_stencil.StencilEnable = TRUE;
|
|
desc_depth_stencil.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
|
desc_depth_stencil.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
|
|
desc_depth_stencil.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
desc_depth_stencil.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_pipeline = {};
|
|
|
|
desc_pipeline.InputLayout = desc_input_layout;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Texture_Stencil_Always)];
|
|
desc_pipeline.VS = desc_bytecode_vertex_shader;
|
|
desc_pipeline.PS = desc_bytecode_pixel_shader;
|
|
desc_pipeline.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
desc_pipeline.RTVFormats[0] = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc_pipeline.DSVFormat = RMLUI_RENDER_BACKEND_FIELD_DEPTHSTENCIL_TEXTURE_FORMAT;
|
|
desc_pipeline.SampleDesc = m_desc_sample;
|
|
desc_pipeline.SampleMask = 0xffffffff;
|
|
desc_pipeline.RasterizerState = desc_rasterizer;
|
|
desc_pipeline.BlendState = desc_blend_state;
|
|
desc_pipeline.NumRenderTargets = 1;
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
|
|
status =
|
|
m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Texture_Stencil_Always)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Texture_Stencil_Always)");
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
desc_depth_stencil.BackFace = desc_depth_stencil.FrontFace;
|
|
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Texture_Stencil_Equal)];
|
|
|
|
status =
|
|
m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Texture_Stencil_Equal)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Texture_Stencil_Equal)");
|
|
|
|
desc_depth_stencil.StencilEnable = FALSE;
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
desc_depth_stencil.BackFace = desc_depth_stencil.FrontFace;
|
|
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Texture_Stencil_Disabled)];
|
|
|
|
status = m_p_device->CreateGraphicsPipelineState(&desc_pipeline,
|
|
IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Texture_Stencil_Disabled)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Texture_Stencil_Disabled)");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_root_signatures[static_cast<int>(ProgramId::Texture_Stencil_Always)]->SetName(TEXT("rs of Texture_Stencil_Always"));
|
|
m_pipelines[static_cast<int>(ProgramId::Texture_Stencil_Always)]->SetName(TEXT("pipeline Texture_Stencil_Always"));
|
|
|
|
m_root_signatures[static_cast<int>(ProgramId::Texture_Stencil_Equal)]->SetName(TEXT("rs of Texture_Stencil_Equal"));
|
|
m_pipelines[static_cast<int>(ProgramId::Texture_Stencil_Equal)]->SetName(TEXT("pipeline Texture_Stencil_Equal"));
|
|
|
|
m_root_signatures[static_cast<int>(ProgramId::Texture_Stencil_Disabled)]->SetName(TEXT("rs of Texture_Stencil_Disabled"));
|
|
m_pipelines[static_cast<int>(ProgramId::Texture_Stencil_Disabled)]->SetName(TEXT("pipeline Texture_Stencil_Disabled"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resource_Pipeline_Gradient()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_Pipeline_Gradient");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid when we call this method!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
D3D12_ROOT_DESCRIPTOR descriptor_cbv{};
|
|
descriptor_cbv.RegisterSpace = 0;
|
|
descriptor_cbv.ShaderRegister = 0;
|
|
D3D12_ROOT_PARAMETER parameters[2];
|
|
|
|
parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
parameters[0].Descriptor = descriptor_cbv;
|
|
parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
|
|
|
|
parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
parameters[1].Descriptor = descriptor_cbv;
|
|
parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_ROOT_SIGNATURE_DESC desc_rootsignature;
|
|
desc_rootsignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
|
|
desc_rootsignature.NumStaticSamplers = 0;
|
|
desc_rootsignature.pParameters = parameters;
|
|
desc_rootsignature.NumParameters = _countof(parameters);
|
|
desc_rootsignature.pStaticSamplers = nullptr;
|
|
|
|
ID3DBlob* p_signature{};
|
|
ID3DBlob* p_error{};
|
|
auto status = D3D12SerializeRootSignature(&desc_rootsignature, D3D_ROOT_SIGNATURE_VERSION_1, &p_signature, &p_error);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3D12SerializeRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Gradient)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
if (p_signature)
|
|
{
|
|
p_signature->Release();
|
|
p_signature = nullptr;
|
|
}
|
|
|
|
if (p_error)
|
|
{
|
|
p_error->Release();
|
|
p_error = nullptr;
|
|
}
|
|
|
|
ID3DBlob* p_shader_vertex{};
|
|
ID3DBlob* p_shader_pixel{};
|
|
ID3DBlob* p_error_buff{};
|
|
|
|
status = D3DCompile(pShaderSourceText_Vertex, sizeof(pShaderSourceText_Vertex), nullptr, nullptr, nullptr, "main", "vs_5_0",
|
|
m_default_shader_flags, 0, &p_shader_vertex, &p_error_buff);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_ERROR, "failed to compile shader: %s", (char*)p_error_buff->GetBufferPointer());
|
|
}
|
|
#endif
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
status = D3DCompile(pShaderSourceText_Pixel_Gradient, sizeof(pShaderSourceText_Pixel_Gradient), nullptr, nullptr, nullptr, "main", "ps_5_0",
|
|
m_default_shader_flags, 0, &p_shader_pixel, &p_error_buff);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_ERROR, "failed to compile shader: %s", (char*)(p_error_buff->GetBufferPointer()));
|
|
}
|
|
#endif
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_pixel_shader = {};
|
|
desc_bytecode_pixel_shader.BytecodeLength = p_shader_pixel->GetBufferSize();
|
|
desc_bytecode_pixel_shader.pShaderBytecode = p_shader_pixel->GetBufferPointer();
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_vertex_shader = {};
|
|
desc_bytecode_vertex_shader.BytecodeLength = p_shader_vertex->GetBufferSize();
|
|
desc_bytecode_vertex_shader.pShaderBytecode = p_shader_vertex->GetBufferPointer();
|
|
|
|
D3D12_INPUT_ELEMENT_DESC desc_input_layout_elements[] = {
|
|
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}};
|
|
|
|
D3D12_INPUT_LAYOUT_DESC desc_input_layout = {};
|
|
|
|
desc_input_layout.NumElements = sizeof(desc_input_layout_elements) / sizeof(D3D12_INPUT_ELEMENT_DESC);
|
|
desc_input_layout.pInputElementDescs = desc_input_layout_elements;
|
|
|
|
D3D12_RASTERIZER_DESC desc_rasterizer = {};
|
|
|
|
desc_rasterizer.FillMode = D3D12_FILL_MODE_SOLID;
|
|
desc_rasterizer.CullMode = D3D12_CULL_MODE_NONE;
|
|
desc_rasterizer.FrontCounterClockwise = FALSE;
|
|
desc_rasterizer.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
|
|
desc_rasterizer.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
|
|
desc_rasterizer.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
|
|
desc_rasterizer.DepthClipEnable = FALSE;
|
|
desc_rasterizer.MultisampleEnable = FALSE;
|
|
desc_rasterizer.AntialiasedLineEnable = FALSE;
|
|
desc_rasterizer.ForcedSampleCount = 0;
|
|
desc_rasterizer.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
|
|
D3D12_BLEND_DESC desc_blend_state = {};
|
|
|
|
desc_blend_state.AlphaToCoverageEnable = FALSE;
|
|
desc_blend_state.IndependentBlendEnable = FALSE;
|
|
const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
|
|
TRUE,
|
|
FALSE,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_LOGIC_OP_NOOP,
|
|
D3D12_COLOR_WRITE_ENABLE_ALL,
|
|
};
|
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
desc_blend_state.RenderTarget[i] = defaultRenderTargetBlendDesc;
|
|
|
|
D3D12_DEPTH_STENCIL_DESC desc_depth_stencil = {};
|
|
|
|
desc_depth_stencil.DepthEnable = FALSE;
|
|
desc_depth_stencil.StencilEnable = TRUE;
|
|
desc_depth_stencil.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
|
desc_depth_stencil.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
|
|
desc_depth_stencil.StencilWriteMask = 0x0;
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
desc_depth_stencil.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_pipeline = {};
|
|
|
|
desc_pipeline.InputLayout = desc_input_layout;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Gradient)];
|
|
desc_pipeline.VS = desc_bytecode_vertex_shader;
|
|
desc_pipeline.PS = desc_bytecode_pixel_shader;
|
|
desc_pipeline.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
desc_pipeline.RTVFormats[0] = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc_pipeline.DSVFormat = RMLUI_RENDER_BACKEND_FIELD_DEPTHSTENCIL_TEXTURE_FORMAT;
|
|
desc_pipeline.SampleDesc = m_desc_sample;
|
|
desc_pipeline.SampleMask = 0xffffffff;
|
|
desc_pipeline.RasterizerState = desc_rasterizer;
|
|
desc_pipeline.BlendState = desc_blend_state;
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
desc_pipeline.NumRenderTargets = 1;
|
|
|
|
status = m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Gradient)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Gradient)");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_root_signatures[static_cast<int>(ProgramId::Gradient)]->SetName(TEXT("rs of Gradient"));
|
|
m_pipelines[static_cast<int>(ProgramId::Gradient)]->SetName(TEXT("pipeline Gradient"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resource_Pipeline_Creation()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_Pipeline_Creation");
|
|
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid when we call this method!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
D3D12_ROOT_DESCRIPTOR descriptor_cbv{};
|
|
descriptor_cbv.RegisterSpace = 0;
|
|
descriptor_cbv.ShaderRegister = 0;
|
|
D3D12_ROOT_PARAMETER parameters[2];
|
|
|
|
parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
parameters[0].Descriptor = descriptor_cbv;
|
|
parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
|
|
|
|
parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
parameters[1].Descriptor = descriptor_cbv;
|
|
parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_ROOT_SIGNATURE_DESC desc_rootsignature;
|
|
desc_rootsignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
|
|
desc_rootsignature.NumStaticSamplers = 0;
|
|
desc_rootsignature.pParameters = parameters;
|
|
desc_rootsignature.NumParameters = _countof(parameters);
|
|
desc_rootsignature.pStaticSamplers = nullptr;
|
|
|
|
ID3DBlob* p_signature{};
|
|
ID3DBlob* p_error{};
|
|
auto status = D3D12SerializeRootSignature(&desc_rootsignature, D3D_ROOT_SIGNATURE_VERSION_1, &p_signature, &p_error);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3D12SerializeRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Creation)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
if (p_signature)
|
|
{
|
|
p_signature->Release();
|
|
p_signature = nullptr;
|
|
}
|
|
|
|
if (p_error)
|
|
{
|
|
p_error->Release();
|
|
p_error = nullptr;
|
|
}
|
|
|
|
ID3DBlob* p_shader_vertex{};
|
|
ID3DBlob* p_shader_pixel{};
|
|
ID3DBlob* p_error_buff{};
|
|
|
|
status = D3DCompile(pShaderSourceText_Vertex, sizeof(pShaderSourceText_Vertex), nullptr, nullptr, nullptr, "main", "vs_5_0",
|
|
m_default_shader_flags, 0, &p_shader_vertex, &p_error_buff);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_ERROR, "failed to compile shader: %s", (char*)p_error_buff->GetBufferPointer());
|
|
}
|
|
#endif
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
status = D3DCompile(pShaderSourceText_Pixel_Creation, sizeof(pShaderSourceText_Pixel_Creation), nullptr, nullptr, nullptr, "main", "ps_5_0",
|
|
m_default_shader_flags, 0, &p_shader_pixel, &p_error_buff);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_ERROR, "failed to compile shader: %s", (char*)(p_error_buff->GetBufferPointer()));
|
|
}
|
|
#endif
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_pixel_shader = {};
|
|
desc_bytecode_pixel_shader.BytecodeLength = p_shader_pixel->GetBufferSize();
|
|
desc_bytecode_pixel_shader.pShaderBytecode = p_shader_pixel->GetBufferPointer();
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_vertex_shader = {};
|
|
desc_bytecode_vertex_shader.BytecodeLength = p_shader_vertex->GetBufferSize();
|
|
desc_bytecode_vertex_shader.pShaderBytecode = p_shader_vertex->GetBufferPointer();
|
|
|
|
D3D12_INPUT_ELEMENT_DESC desc_input_layout_elements[] = {
|
|
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}};
|
|
|
|
D3D12_INPUT_LAYOUT_DESC desc_input_layout = {};
|
|
|
|
desc_input_layout.NumElements = sizeof(desc_input_layout_elements) / sizeof(D3D12_INPUT_ELEMENT_DESC);
|
|
desc_input_layout.pInputElementDescs = desc_input_layout_elements;
|
|
|
|
D3D12_RASTERIZER_DESC desc_rasterizer = {};
|
|
|
|
desc_rasterizer.FillMode = D3D12_FILL_MODE_SOLID;
|
|
desc_rasterizer.CullMode = D3D12_CULL_MODE_NONE;
|
|
desc_rasterizer.FrontCounterClockwise = FALSE;
|
|
desc_rasterizer.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
|
|
desc_rasterizer.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
|
|
desc_rasterizer.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
|
|
desc_rasterizer.DepthClipEnable = FALSE;
|
|
desc_rasterizer.MultisampleEnable = FALSE;
|
|
desc_rasterizer.AntialiasedLineEnable = FALSE;
|
|
desc_rasterizer.ForcedSampleCount = 0;
|
|
desc_rasterizer.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
|
|
D3D12_BLEND_DESC desc_blend_state = {};
|
|
|
|
desc_blend_state.AlphaToCoverageEnable = FALSE;
|
|
desc_blend_state.IndependentBlendEnable = FALSE;
|
|
const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
|
|
TRUE,
|
|
FALSE,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_LOGIC_OP_NOOP,
|
|
D3D12_COLOR_WRITE_ENABLE_ALL,
|
|
};
|
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
desc_blend_state.RenderTarget[i] = defaultRenderTargetBlendDesc;
|
|
|
|
D3D12_DEPTH_STENCIL_DESC desc_depth_stencil = {};
|
|
|
|
desc_depth_stencil.DepthEnable = FALSE;
|
|
desc_depth_stencil.StencilEnable = TRUE;
|
|
desc_depth_stencil.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
|
desc_depth_stencil.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
|
|
desc_depth_stencil.StencilWriteMask = 0x0;
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
desc_depth_stencil.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_pipeline = {};
|
|
|
|
desc_pipeline.InputLayout = desc_input_layout;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Creation)];
|
|
desc_pipeline.VS = desc_bytecode_vertex_shader;
|
|
desc_pipeline.PS = desc_bytecode_pixel_shader;
|
|
desc_pipeline.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
desc_pipeline.RTVFormats[0] = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc_pipeline.DSVFormat = RMLUI_RENDER_BACKEND_FIELD_DEPTHSTENCIL_TEXTURE_FORMAT;
|
|
desc_pipeline.SampleDesc = m_desc_sample;
|
|
desc_pipeline.SampleMask = 0xffffffff;
|
|
desc_pipeline.RasterizerState = desc_rasterizer;
|
|
desc_pipeline.BlendState = desc_blend_state;
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
desc_pipeline.NumRenderTargets = 1;
|
|
|
|
status = m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Creation)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Creation)");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_root_signatures[static_cast<int>(ProgramId::Creation)]->SetName(TEXT("rs of Creation"));
|
|
m_pipelines[static_cast<int>(ProgramId::Creation)]->SetName(TEXT("pipeline Creation"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resource_Pipeline_Passthrough()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_Pipeline_Passthrough");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid when we call this method!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
D3D12_DESCRIPTOR_RANGE ranges[1];
|
|
ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
|
ranges[0].NumDescriptors = 1;
|
|
ranges[0].BaseShaderRegister = 0;
|
|
ranges[0].RegisterSpace = 0;
|
|
ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
|
|
|
D3D12_ROOT_DESCRIPTOR_TABLE table{};
|
|
table.NumDescriptorRanges = sizeof(ranges) / sizeof(decltype(ranges[0]));
|
|
table.pDescriptorRanges = ranges;
|
|
|
|
D3D12_ROOT_PARAMETER parameters[1];
|
|
parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
|
parameters[0].DescriptorTable = table;
|
|
parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_STATIC_SAMPLER_DESC sampler = {};
|
|
sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
|
sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.MipLODBias = 0;
|
|
sampler.MaxAnisotropy = 0;
|
|
sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
|
sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
|
|
sampler.MinLOD = 0.0f;
|
|
sampler.MaxLOD = D3D12_FLOAT32_MAX;
|
|
sampler.ShaderRegister = 0;
|
|
sampler.RegisterSpace = 0;
|
|
sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_ROOT_SIGNATURE_DESC desc_rootsignature;
|
|
desc_rootsignature.NumParameters = _countof(parameters);
|
|
desc_rootsignature.pParameters = parameters;
|
|
desc_rootsignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
|
|
desc_rootsignature.NumStaticSamplers = 1;
|
|
desc_rootsignature.pStaticSamplers = &sampler;
|
|
|
|
ID3DBlob* p_signature{};
|
|
ID3DBlob* p_error{};
|
|
auto status = D3D12SerializeRootSignature(&desc_rootsignature, D3D_ROOT_SIGNATURE_VERSION_1, &p_signature, &p_error);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to D3D12SerializeRootSignature: %s",
|
|
(char*)p_error->GetBufferPointer());
|
|
}
|
|
#endif
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3D12SerializeRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Passthrough)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Passthrough_NoDepthStencil)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Passthrough_Opacity)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Passthrough_MSAA)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Passthrough_MSAA_Equal)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
if (p_signature)
|
|
{
|
|
p_signature->Release();
|
|
p_signature = nullptr;
|
|
}
|
|
|
|
if (p_error)
|
|
{
|
|
p_error->Release();
|
|
p_error = nullptr;
|
|
}
|
|
|
|
ID3DBlob* p_shader_vertex{};
|
|
ID3DBlob* p_shader_pixel{};
|
|
ID3DBlob* p_error_buff{};
|
|
|
|
const D3D_SHADER_MACRO macros[] = {NULL, NULL, NULL, NULL};
|
|
|
|
status = D3DCompile(pShaderSourceText_Vertex_PassThrough, sizeof(pShaderSourceText_Vertex_PassThrough), nullptr, macros, nullptr, "main",
|
|
"vs_5_0", m_default_shader_flags, 0, &p_shader_vertex, &p_error_buff);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s", (char*)p_error_buff->GetBufferPointer());
|
|
}
|
|
#endif
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
status = D3DCompile(pShaderSourceText_Pixel_Passthrough, sizeof(pShaderSourceText_Pixel_Passthrough), nullptr, nullptr, nullptr, "main",
|
|
"ps_5_0", m_default_shader_flags, 0, &p_shader_pixel, &p_error_buff);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s",
|
|
(char*)(p_error_buff->GetBufferPointer()));
|
|
}
|
|
#endif
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_pixel_shader = {};
|
|
desc_bytecode_pixel_shader.BytecodeLength = p_shader_pixel->GetBufferSize();
|
|
desc_bytecode_pixel_shader.pShaderBytecode = p_shader_pixel->GetBufferPointer();
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_vertex_shader = {};
|
|
desc_bytecode_vertex_shader.BytecodeLength = p_shader_vertex->GetBufferSize();
|
|
desc_bytecode_vertex_shader.pShaderBytecode = p_shader_vertex->GetBufferPointer();
|
|
|
|
D3D12_INPUT_ELEMENT_DESC desc_input_layout_elements[] = {
|
|
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}};
|
|
|
|
D3D12_INPUT_LAYOUT_DESC desc_input_layout = {};
|
|
|
|
desc_input_layout.NumElements = sizeof(desc_input_layout_elements) / sizeof(D3D12_INPUT_ELEMENT_DESC);
|
|
desc_input_layout.pInputElementDescs = desc_input_layout_elements;
|
|
|
|
D3D12_RASTERIZER_DESC desc_rasterizer = {};
|
|
|
|
desc_rasterizer.AntialiasedLineEnable = FALSE;
|
|
desc_rasterizer.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
desc_rasterizer.CullMode = D3D12_CULL_MODE_NONE;
|
|
desc_rasterizer.DepthBias = 0;
|
|
desc_rasterizer.DepthBiasClamp = 0;
|
|
desc_rasterizer.DepthClipEnable = FALSE;
|
|
desc_rasterizer.ForcedSampleCount = 0;
|
|
desc_rasterizer.FrontCounterClockwise = FALSE;
|
|
desc_rasterizer.MultisampleEnable = FALSE;
|
|
desc_rasterizer.FillMode = D3D12_FILL_MODE::D3D12_FILL_MODE_SOLID;
|
|
desc_rasterizer.SlopeScaledDepthBias = 0;
|
|
|
|
D3D12_BLEND_DESC desc_blend_state = {};
|
|
desc_blend_state.AlphaToCoverageEnable = FALSE;
|
|
desc_blend_state.IndependentBlendEnable = FALSE;
|
|
const D3D12_RENDER_TARGET_BLEND_DESC default_render_target_blend_desc = {
|
|
TRUE,
|
|
FALSE,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_LOGIC_OP_NOOP,
|
|
D3D12_COLOR_WRITE_ENABLE_ALL,
|
|
};
|
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
desc_blend_state.RenderTarget[i] = default_render_target_blend_desc;
|
|
|
|
D3D12_DEPTH_STENCIL_DESC desc_depth_stencil = {};
|
|
|
|
desc_depth_stencil.DepthEnable = FALSE;
|
|
desc_depth_stencil.StencilEnable = TRUE;
|
|
desc_depth_stencil.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
|
desc_depth_stencil.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
|
|
desc_depth_stencil.StencilWriteMask = 0;
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
desc_depth_stencil.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
desc_depth_stencil.BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_pipeline = {};
|
|
|
|
desc_pipeline.InputLayout = desc_input_layout;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Passthrough)];
|
|
desc_pipeline.VS = desc_bytecode_vertex_shader;
|
|
desc_pipeline.PS = desc_bytecode_pixel_shader;
|
|
desc_pipeline.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
desc_pipeline.RTVFormats[0] = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc_pipeline.DSVFormat = RMLUI_RENDER_BACKEND_FIELD_DEPTHSTENCIL_TEXTURE_FORMAT;
|
|
|
|
// since it is used for presenting MSAA texture on screen, we create swapchain and all RTs as NO-MSAA, keep this in mind
|
|
// otherwise it is wrong to mix target texture with different sample count than swapchain's
|
|
desc_pipeline.SampleDesc.Count = 1;
|
|
desc_pipeline.SampleDesc.Quality = 0;
|
|
|
|
desc_pipeline.SampleMask = 0xffffffff;
|
|
desc_pipeline.RasterizerState = desc_rasterizer;
|
|
desc_pipeline.BlendState = desc_blend_state;
|
|
desc_pipeline.NumRenderTargets = 1;
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
|
|
status = m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Passthrough)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Passthrough)");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_root_signatures[static_cast<int>(ProgramId::Passthrough)]->SetName(TEXT("rs of Passthrough"));
|
|
m_pipelines[static_cast<int>(ProgramId::Passthrough)]->SetName(TEXT("pipeline Passthrough"));
|
|
#endif
|
|
|
|
desc_pipeline.SampleDesc = m_desc_sample;
|
|
desc_pipeline.DepthStencilState.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_pipeline.DepthStencilState.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
|
|
status = m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Passthrough_MSAA)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Passthrough_MSAA)");
|
|
|
|
desc_pipeline.DepthStencilState.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
desc_pipeline.DepthStencilState.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
status =
|
|
m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Passthrough_MSAA_Equal)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Passthrough_MSAA_Equal)");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_root_signatures[static_cast<int>(ProgramId::Passthrough_MSAA)]->SetName(TEXT("rs of Passthrough_MSAA"));
|
|
m_pipelines[static_cast<int>(ProgramId::Passthrough_MSAA)]->SetName(TEXT("pipeline Passthrough_MSAA"));
|
|
|
|
m_root_signatures[static_cast<int>(ProgramId::Passthrough_MSAA_Equal)]->SetName(TEXT("rs of Passthrough_MSAA_Equal"));
|
|
m_pipelines[static_cast<int>(ProgramId::Passthrough_MSAA_Equal)]->SetName(TEXT("pipeline Passthrough_MSAA_Equal"));
|
|
#endif
|
|
|
|
desc_pipeline.SampleDesc.Count = 1;
|
|
desc_pipeline.SampleDesc.Quality = 0;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Passthrough_NoDepthStencil)];
|
|
desc_pipeline.DSVFormat = DXGI_FORMAT::DXGI_FORMAT_UNKNOWN;
|
|
|
|
status = m_p_device->CreateGraphicsPipelineState(&desc_pipeline,
|
|
IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Passthrough_NoDepthStencil)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPieplineState (Passthrough_NoDepthStencil)");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_root_signatures[static_cast<int>(ProgramId::Passthrough_NoDepthStencil)]->SetName(TEXT("rs of Passthrough_NoDepthStencil"));
|
|
m_pipelines[static_cast<int>(ProgramId::Passthrough_NoDepthStencil)]->SetName(TEXT("pipeline Passthrough_NoDepthStencil"));
|
|
#endif
|
|
|
|
D3D12_RENDER_TARGET_BLEND_DESC opacity_blend_desc;
|
|
opacity_blend_desc.BlendEnable = TRUE;
|
|
opacity_blend_desc.LogicOpEnable = FALSE;
|
|
opacity_blend_desc.SrcBlend = D3D12_BLEND_BLEND_FACTOR;
|
|
opacity_blend_desc.DestBlend = D3D12_BLEND_ZERO;
|
|
opacity_blend_desc.BlendOp = D3D12_BLEND_OP_ADD;
|
|
opacity_blend_desc.SrcBlendAlpha = D3D12_BLEND_BLEND_FACTOR;
|
|
opacity_blend_desc.DestBlendAlpha = D3D12_BLEND_ZERO;
|
|
opacity_blend_desc.BlendOpAlpha = D3D12_BLEND_OP_ADD;
|
|
opacity_blend_desc.LogicOp = D3D12_LOGIC_OP_NOOP;
|
|
opacity_blend_desc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
|
|
|
D3D12_BLEND_DESC desc_blend_state_opacity = {};
|
|
desc_blend_state_opacity.AlphaToCoverageEnable = FALSE;
|
|
desc_blend_state_opacity.IndependentBlendEnable = FALSE;
|
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
desc_blend_state_opacity.RenderTarget[i] = opacity_blend_desc;
|
|
|
|
desc_pipeline.BlendState = desc_blend_state_opacity;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Passthrough_Opacity)];
|
|
|
|
status =
|
|
m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Passthrough_Opacity)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Passthrough_Opacity)");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_root_signatures[static_cast<int>(ProgramId::Passthrough_Opacity)]->SetName(TEXT("rs of Passthrough_Opacity"));
|
|
m_pipelines[static_cast<int>(ProgramId::Passthrough_Opacity)]->SetName(TEXT("pipeline Passthrough_Opacity"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resource_Pipeline_Passthrough_NoBlend()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_Pipeline_Passthrough");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid when we call this method!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
D3D12_DESCRIPTOR_RANGE ranges[1];
|
|
ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
|
ranges[0].NumDescriptors = 1;
|
|
ranges[0].BaseShaderRegister = 0;
|
|
ranges[0].RegisterSpace = 0;
|
|
ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
|
|
|
D3D12_ROOT_DESCRIPTOR_TABLE table{};
|
|
table.NumDescriptorRanges = sizeof(ranges) / sizeof(decltype(ranges[0]));
|
|
table.pDescriptorRanges = ranges;
|
|
|
|
D3D12_ROOT_PARAMETER parameters[1];
|
|
parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
|
parameters[0].DescriptorTable = table;
|
|
parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_STATIC_SAMPLER_DESC sampler = {};
|
|
sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
|
sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.MipLODBias = 0;
|
|
sampler.MaxAnisotropy = 0;
|
|
sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
|
sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
|
|
sampler.MinLOD = 0.0f;
|
|
sampler.MaxLOD = D3D12_FLOAT32_MAX;
|
|
sampler.ShaderRegister = 0;
|
|
sampler.RegisterSpace = 0;
|
|
sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_ROOT_SIGNATURE_DESC desc_rootsignature;
|
|
desc_rootsignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
|
|
desc_rootsignature.NumParameters = _countof(parameters);
|
|
desc_rootsignature.pParameters = parameters;
|
|
desc_rootsignature.NumStaticSamplers = 1;
|
|
desc_rootsignature.pStaticSamplers = &sampler;
|
|
|
|
ID3DBlob* p_signature{};
|
|
ID3DBlob* p_error{};
|
|
auto status = D3D12SerializeRootSignature(&desc_rootsignature, D3D_ROOT_SIGNATURE_VERSION_1, &p_signature, &p_error);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to D3D12SerializeRootSignature: %s",
|
|
(char*)p_error->GetBufferPointer());
|
|
}
|
|
#endif
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3D12SerializeRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Passthrough_NoBlend)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Passthrough_NoBlendAndNoMSAA)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
if (p_signature)
|
|
{
|
|
p_signature->Release();
|
|
p_signature = nullptr;
|
|
}
|
|
|
|
if (p_error)
|
|
{
|
|
p_error->Release();
|
|
p_error = nullptr;
|
|
}
|
|
|
|
ID3DBlob* p_shader_vertex{};
|
|
ID3DBlob* p_shader_pixel{};
|
|
ID3DBlob* p_error_buff{};
|
|
|
|
const D3D_SHADER_MACRO macros[] = {NULL, NULL, NULL, NULL};
|
|
|
|
status = D3DCompile(pShaderSourceText_Vertex_PassThrough, sizeof(pShaderSourceText_Vertex_PassThrough), nullptr, macros, nullptr, "main",
|
|
"vs_5_0", m_default_shader_flags, 0, &p_shader_vertex, &p_error_buff);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s", (char*)p_error_buff->GetBufferPointer());
|
|
}
|
|
#endif
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
status = D3DCompile(pShaderSourceText_Pixel_Passthrough, sizeof(pShaderSourceText_Pixel_Passthrough), nullptr, nullptr, nullptr, "main",
|
|
"ps_5_0", m_default_shader_flags, 0, &p_shader_pixel, &p_error_buff);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s",
|
|
(char*)(p_error_buff->GetBufferPointer()));
|
|
}
|
|
#endif
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_pixel_shader = {};
|
|
desc_bytecode_pixel_shader.BytecodeLength = p_shader_pixel->GetBufferSize();
|
|
desc_bytecode_pixel_shader.pShaderBytecode = p_shader_pixel->GetBufferPointer();
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_vertex_shader = {};
|
|
desc_bytecode_vertex_shader.BytecodeLength = p_shader_vertex->GetBufferSize();
|
|
desc_bytecode_vertex_shader.pShaderBytecode = p_shader_vertex->GetBufferPointer();
|
|
|
|
D3D12_INPUT_ELEMENT_DESC desc_input_layout_elements[] = {
|
|
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}};
|
|
|
|
D3D12_INPUT_LAYOUT_DESC desc_input_layout = {};
|
|
|
|
desc_input_layout.NumElements = sizeof(desc_input_layout_elements) / sizeof(D3D12_INPUT_ELEMENT_DESC);
|
|
desc_input_layout.pInputElementDescs = desc_input_layout_elements;
|
|
|
|
D3D12_RASTERIZER_DESC desc_rasterizer = {};
|
|
|
|
desc_rasterizer.AntialiasedLineEnable = FALSE;
|
|
desc_rasterizer.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
desc_rasterizer.CullMode = D3D12_CULL_MODE_NONE;
|
|
desc_rasterizer.DepthBias = 0;
|
|
desc_rasterizer.DepthBiasClamp = 0;
|
|
desc_rasterizer.DepthClipEnable = FALSE;
|
|
desc_rasterizer.ForcedSampleCount = 0;
|
|
desc_rasterizer.FrontCounterClockwise = FALSE;
|
|
desc_rasterizer.MultisampleEnable = FALSE;
|
|
desc_rasterizer.FillMode = D3D12_FILL_MODE::D3D12_FILL_MODE_SOLID;
|
|
desc_rasterizer.SlopeScaledDepthBias = 0;
|
|
|
|
D3D12_BLEND_DESC desc_blend_state = {};
|
|
|
|
desc_blend_state.AlphaToCoverageEnable = FALSE;
|
|
desc_blend_state.IndependentBlendEnable = FALSE;
|
|
const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
|
|
FALSE,
|
|
FALSE,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_LOGIC_OP_NOOP,
|
|
D3D12_COLOR_WRITE_ENABLE_ALL,
|
|
};
|
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
desc_blend_state.RenderTarget[i] = defaultRenderTargetBlendDesc;
|
|
|
|
D3D12_DEPTH_STENCIL_DESC desc_depth_stencil = {};
|
|
|
|
desc_depth_stencil.DepthEnable = FALSE;
|
|
desc_depth_stencil.StencilEnable = TRUE;
|
|
desc_depth_stencil.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
|
desc_depth_stencil.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
|
|
desc_depth_stencil.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
desc_depth_stencil.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_pipeline = {};
|
|
|
|
desc_pipeline.InputLayout = desc_input_layout;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Passthrough_NoBlend)];
|
|
desc_pipeline.VS = desc_bytecode_vertex_shader;
|
|
desc_pipeline.PS = desc_bytecode_pixel_shader;
|
|
desc_pipeline.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
desc_pipeline.RTVFormats[0] = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc_pipeline.DSVFormat = DXGI_FORMAT::DXGI_FORMAT_UNKNOWN;
|
|
desc_pipeline.SampleDesc = m_desc_sample; // depends on layer texture and layer texture depends on msaa level that user specifies
|
|
desc_pipeline.SampleMask = 0xffffffff;
|
|
desc_pipeline.RasterizerState = desc_rasterizer;
|
|
desc_pipeline.BlendState = desc_blend_state;
|
|
desc_pipeline.NumRenderTargets = 1;
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
|
|
status =
|
|
m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Passthrough_NoBlend)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Passthrough_NoBlend)");
|
|
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Passthrough_NoBlendAndNoMSAA)];
|
|
desc_pipeline.SampleDesc.Count = 1;
|
|
desc_pipeline.SampleDesc.Quality = 0;
|
|
|
|
status = m_p_device->CreateGraphicsPipelineState(&desc_pipeline,
|
|
IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Passthrough_NoBlendAndNoMSAA)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Passthrough_NoBlendAndNoMSAA");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_root_signatures[static_cast<int>(ProgramId::Passthrough_NoBlend)]->SetName(TEXT("rs of Passthrough_NoBlend"));
|
|
m_pipelines[static_cast<int>(ProgramId::Passthrough_NoBlend)]->SetName(TEXT("pipeline Passthrough_NoBlend"));
|
|
|
|
m_root_signatures[static_cast<int>(ProgramId::Passthrough_NoBlendAndNoMSAA)]->SetName(TEXT("rs of Passthrough_NoBlendAndNoMSAA"));
|
|
m_pipelines[static_cast<int>(ProgramId::Passthrough_NoBlendAndNoMSAA)]->SetName(TEXT("pipeline Passthrough_NoBlendAndNoMSAA"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resource_Pipeline_ColorMatrix()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_Pipeline_ColorMatrix");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid when we call this method!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
D3D12_DESCRIPTOR_RANGE ranges[1];
|
|
ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
|
ranges[0].NumDescriptors = 1;
|
|
ranges[0].BaseShaderRegister = 0;
|
|
ranges[0].RegisterSpace = 0;
|
|
ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
|
|
|
D3D12_ROOT_DESCRIPTOR_TABLE table{};
|
|
table.NumDescriptorRanges = sizeof(ranges) / sizeof(decltype(ranges[0]));
|
|
table.pDescriptorRanges = ranges;
|
|
|
|
D3D12_ROOT_DESCRIPTOR descriptor_cbv{};
|
|
descriptor_cbv.RegisterSpace = 0;
|
|
descriptor_cbv.ShaderRegister = 0;
|
|
|
|
D3D12_ROOT_PARAMETER parameters[2];
|
|
|
|
parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
|
parameters[0].DescriptorTable = table;
|
|
parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
parameters[1].Descriptor = descriptor_cbv;
|
|
parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_STATIC_SAMPLER_DESC sampler = {};
|
|
sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
|
sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.MipLODBias = 0;
|
|
sampler.MaxAnisotropy = 0;
|
|
sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
|
sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
|
|
sampler.MinLOD = 0.0f;
|
|
sampler.MaxLOD = D3D12_FLOAT32_MAX;
|
|
sampler.ShaderRegister = 0;
|
|
sampler.RegisterSpace = 0;
|
|
sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_ROOT_SIGNATURE_DESC desc_rootsignature;
|
|
desc_rootsignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
|
|
desc_rootsignature.NumParameters = _countof(parameters);
|
|
desc_rootsignature.pParameters = parameters;
|
|
desc_rootsignature.NumStaticSamplers = 1;
|
|
desc_rootsignature.pStaticSamplers = &sampler;
|
|
|
|
ID3DBlob* p_signature{};
|
|
ID3DBlob* p_error{};
|
|
auto status = D3D12SerializeRootSignature(&desc_rootsignature, D3D_ROOT_SIGNATURE_VERSION_1, &p_signature, &p_error);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to D3D12SerializeRootSignature: %s",
|
|
(char*)p_error->GetBufferPointer());
|
|
}
|
|
#endif
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3D12SerializeRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::ColorMatrix)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
if (p_signature)
|
|
{
|
|
p_signature->Release();
|
|
p_signature = nullptr;
|
|
}
|
|
|
|
if (p_error)
|
|
{
|
|
p_error->Release();
|
|
p_error = nullptr;
|
|
}
|
|
|
|
ID3DBlob* p_shader_vertex{};
|
|
ID3DBlob* p_shader_pixel{};
|
|
ID3DBlob* p_error_buff{};
|
|
|
|
const D3D_SHADER_MACRO macros[] = {NULL, NULL, NULL, NULL};
|
|
|
|
status = D3DCompile(pShaderSourceText_Vertex_PassThrough, sizeof(pShaderSourceText_Vertex_PassThrough), nullptr, macros, nullptr, "main",
|
|
"vs_5_0", m_default_shader_flags, 0, &p_shader_vertex, &p_error_buff);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s", (char*)p_error_buff->GetBufferPointer());
|
|
}
|
|
#endif
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
status = D3DCompile(pShaderSourceTet_Pixel_ColorMatrix, sizeof(pShaderSourceTet_Pixel_ColorMatrix), nullptr, nullptr, nullptr, "main",
|
|
"ps_5_0", m_default_shader_flags, 0, &p_shader_pixel, &p_error_buff);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s",
|
|
(char*)(p_error_buff->GetBufferPointer()));
|
|
}
|
|
#endif
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_pixel_shader = {};
|
|
desc_bytecode_pixel_shader.BytecodeLength = p_shader_pixel->GetBufferSize();
|
|
desc_bytecode_pixel_shader.pShaderBytecode = p_shader_pixel->GetBufferPointer();
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_vertex_shader = {};
|
|
desc_bytecode_vertex_shader.BytecodeLength = p_shader_vertex->GetBufferSize();
|
|
desc_bytecode_vertex_shader.pShaderBytecode = p_shader_vertex->GetBufferPointer();
|
|
|
|
D3D12_INPUT_ELEMENT_DESC desc_input_layout_elements[] = {
|
|
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}};
|
|
|
|
D3D12_INPUT_LAYOUT_DESC desc_input_layout = {};
|
|
|
|
desc_input_layout.NumElements = sizeof(desc_input_layout_elements) / sizeof(D3D12_INPUT_ELEMENT_DESC);
|
|
desc_input_layout.pInputElementDescs = desc_input_layout_elements;
|
|
|
|
D3D12_RASTERIZER_DESC desc_rasterizer = {};
|
|
|
|
desc_rasterizer.AntialiasedLineEnable = FALSE;
|
|
desc_rasterizer.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
desc_rasterizer.CullMode = D3D12_CULL_MODE_NONE;
|
|
desc_rasterizer.DepthBias = 0;
|
|
desc_rasterizer.DepthBiasClamp = 0;
|
|
desc_rasterizer.DepthClipEnable = FALSE;
|
|
desc_rasterizer.ForcedSampleCount = 0;
|
|
desc_rasterizer.FrontCounterClockwise = FALSE;
|
|
desc_rasterizer.MultisampleEnable = FALSE;
|
|
desc_rasterizer.FillMode = D3D12_FILL_MODE::D3D12_FILL_MODE_SOLID;
|
|
desc_rasterizer.SlopeScaledDepthBias = 0;
|
|
|
|
D3D12_BLEND_DESC desc_blend_state = {};
|
|
|
|
desc_blend_state.AlphaToCoverageEnable = FALSE;
|
|
desc_blend_state.IndependentBlendEnable = FALSE;
|
|
const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
|
|
FALSE,
|
|
FALSE,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_LOGIC_OP_NOOP,
|
|
D3D12_COLOR_WRITE_ENABLE_ALL,
|
|
};
|
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
desc_blend_state.RenderTarget[i] = defaultRenderTargetBlendDesc;
|
|
|
|
D3D12_DEPTH_STENCIL_DESC desc_depth_stencil = {};
|
|
|
|
desc_depth_stencil.DepthEnable = FALSE;
|
|
desc_depth_stencil.StencilEnable = TRUE;
|
|
desc_depth_stencil.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
|
desc_depth_stencil.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
|
|
desc_depth_stencil.StencilWriteMask = 0;
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
desc_depth_stencil.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
desc_depth_stencil.BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_pipeline = {};
|
|
|
|
desc_pipeline.InputLayout = desc_input_layout;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::ColorMatrix)];
|
|
desc_pipeline.VS = desc_bytecode_vertex_shader;
|
|
desc_pipeline.PS = desc_bytecode_pixel_shader;
|
|
desc_pipeline.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
desc_pipeline.RTVFormats[0] = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc_pipeline.DSVFormat = DXGI_FORMAT::DXGI_FORMAT_UNKNOWN;
|
|
|
|
// desc_pipeline.SampleDesc = m_desc_sample;
|
|
desc_pipeline.SampleDesc.Count = 1;
|
|
desc_pipeline.SampleDesc.Quality = 0;
|
|
|
|
desc_pipeline.SampleMask = 0xffffffff;
|
|
desc_pipeline.RasterizerState = desc_rasterizer;
|
|
desc_pipeline.BlendState = desc_blend_state;
|
|
desc_pipeline.NumRenderTargets = 1;
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
|
|
status = m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::ColorMatrix)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (ColorMatrix)");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_root_signatures[static_cast<int>(ProgramId::ColorMatrix)]->SetName(TEXT("rs of ColorMatrix"));
|
|
m_pipelines[static_cast<int>(ProgramId::ColorMatrix)]->SetName(TEXT("pipeline ColorMatrix"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resource_Pipeline_BlendMask()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_Pipeline_BlendMask");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid when we call this method!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
D3D12_DESCRIPTOR_RANGE ranges[1];
|
|
ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
|
ranges[0].NumDescriptors = 1;
|
|
ranges[0].BaseShaderRegister = 0;
|
|
ranges[0].RegisterSpace = 0;
|
|
ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
|
|
|
D3D12_ROOT_DESCRIPTOR_TABLE table{};
|
|
table.NumDescriptorRanges = sizeof(ranges) / sizeof(decltype(ranges[0]));
|
|
table.pDescriptorRanges = ranges;
|
|
|
|
D3D12_ROOT_PARAMETER parameters[2];
|
|
|
|
parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
|
parameters[0].DescriptorTable = table;
|
|
parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_DESCRIPTOR_RANGE slot2_ranges[1];
|
|
slot2_ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
|
slot2_ranges[0].NumDescriptors = 1;
|
|
slot2_ranges[0].BaseShaderRegister = 1;
|
|
slot2_ranges[0].RegisterSpace = 0;
|
|
slot2_ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
|
|
|
D3D12_ROOT_DESCRIPTOR_TABLE slot2_table{};
|
|
slot2_table.NumDescriptorRanges = sizeof(slot2_ranges) / sizeof(decltype(slot2_ranges[0]));
|
|
slot2_table.pDescriptorRanges = slot2_ranges;
|
|
|
|
parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
|
parameters[1].DescriptorTable = slot2_table;
|
|
parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_STATIC_SAMPLER_DESC sampler = {};
|
|
sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
|
sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.MipLODBias = 0;
|
|
sampler.MaxAnisotropy = 0;
|
|
sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
|
sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
|
|
sampler.MinLOD = 0.0f;
|
|
sampler.MaxLOD = D3D12_FLOAT32_MAX;
|
|
sampler.ShaderRegister = 0;
|
|
sampler.RegisterSpace = 0;
|
|
sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_ROOT_SIGNATURE_DESC desc_rootsignature;
|
|
desc_rootsignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
|
|
desc_rootsignature.NumParameters = _countof(parameters);
|
|
desc_rootsignature.pParameters = parameters;
|
|
desc_rootsignature.NumStaticSamplers = 1;
|
|
desc_rootsignature.pStaticSamplers = &sampler;
|
|
|
|
ID3DBlob* p_signature{};
|
|
ID3DBlob* p_error{};
|
|
auto status = D3D12SerializeRootSignature(&desc_rootsignature, D3D_ROOT_SIGNATURE_VERSION_1, &p_signature, &p_error);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to D3D12SerializeRootSignature: %s",
|
|
(char*)p_error->GetBufferPointer());
|
|
}
|
|
#endif
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3D12SerializeRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::BlendMask)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
if (p_signature)
|
|
{
|
|
p_signature->Release();
|
|
p_signature = nullptr;
|
|
}
|
|
|
|
if (p_error)
|
|
{
|
|
p_error->Release();
|
|
p_error = nullptr;
|
|
}
|
|
|
|
ID3DBlob* p_shader_vertex{};
|
|
ID3DBlob* p_shader_pixel{};
|
|
ID3DBlob* p_error_buff{};
|
|
|
|
const D3D_SHADER_MACRO macros[] = {NULL, NULL, NULL, NULL};
|
|
|
|
status = D3DCompile(pShaderSourceText_Vertex_PassThrough, sizeof(pShaderSourceText_Vertex_PassThrough), nullptr, macros, nullptr, "main",
|
|
"vs_5_0", m_default_shader_flags, 0, &p_shader_vertex, &p_error_buff);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s", (char*)p_error_buff->GetBufferPointer());
|
|
}
|
|
#endif
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
status = D3DCompile(pShaderSourceText_Pixel_BlendMask, sizeof(pShaderSourceText_Pixel_BlendMask), nullptr, nullptr, nullptr, "main", "ps_5_0",
|
|
m_default_shader_flags, 0, &p_shader_pixel, &p_error_buff);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s",
|
|
(char*)(p_error_buff->GetBufferPointer()));
|
|
}
|
|
#endif
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_pixel_shader = {};
|
|
desc_bytecode_pixel_shader.BytecodeLength = p_shader_pixel->GetBufferSize();
|
|
desc_bytecode_pixel_shader.pShaderBytecode = p_shader_pixel->GetBufferPointer();
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_vertex_shader = {};
|
|
desc_bytecode_vertex_shader.BytecodeLength = p_shader_vertex->GetBufferSize();
|
|
desc_bytecode_vertex_shader.pShaderBytecode = p_shader_vertex->GetBufferPointer();
|
|
|
|
D3D12_INPUT_ELEMENT_DESC desc_input_layout_elements[] = {
|
|
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}};
|
|
|
|
D3D12_INPUT_LAYOUT_DESC desc_input_layout = {};
|
|
|
|
desc_input_layout.NumElements = sizeof(desc_input_layout_elements) / sizeof(D3D12_INPUT_ELEMENT_DESC);
|
|
desc_input_layout.pInputElementDescs = desc_input_layout_elements;
|
|
|
|
D3D12_RASTERIZER_DESC desc_rasterizer = {};
|
|
|
|
desc_rasterizer.AntialiasedLineEnable = FALSE;
|
|
desc_rasterizer.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
desc_rasterizer.CullMode = D3D12_CULL_MODE_NONE;
|
|
desc_rasterizer.DepthBias = 0;
|
|
desc_rasterizer.DepthBiasClamp = 0;
|
|
desc_rasterizer.DepthClipEnable = FALSE;
|
|
desc_rasterizer.ForcedSampleCount = 0;
|
|
desc_rasterizer.FrontCounterClockwise = FALSE;
|
|
desc_rasterizer.MultisampleEnable = FALSE;
|
|
desc_rasterizer.FillMode = D3D12_FILL_MODE::D3D12_FILL_MODE_SOLID;
|
|
desc_rasterizer.SlopeScaledDepthBias = 0;
|
|
|
|
D3D12_BLEND_DESC desc_blend_state = {};
|
|
|
|
desc_blend_state.AlphaToCoverageEnable = FALSE;
|
|
desc_blend_state.IndependentBlendEnable = FALSE;
|
|
const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
|
|
FALSE,
|
|
FALSE,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_LOGIC_OP_NOOP,
|
|
D3D12_COLOR_WRITE_ENABLE_ALL,
|
|
};
|
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
desc_blend_state.RenderTarget[i] = defaultRenderTargetBlendDesc;
|
|
|
|
D3D12_DEPTH_STENCIL_DESC desc_depth_stencil = {};
|
|
|
|
desc_depth_stencil.DepthEnable = FALSE;
|
|
desc_depth_stencil.StencilEnable = TRUE;
|
|
desc_depth_stencil.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
|
desc_depth_stencil.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
|
|
desc_depth_stencil.StencilWriteMask = 0;
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
desc_depth_stencil.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
desc_depth_stencil.BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_pipeline = {};
|
|
|
|
desc_pipeline.InputLayout = desc_input_layout;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::BlendMask)];
|
|
desc_pipeline.VS = desc_bytecode_vertex_shader;
|
|
desc_pipeline.PS = desc_bytecode_pixel_shader;
|
|
desc_pipeline.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
desc_pipeline.RTVFormats[0] = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc_pipeline.DSVFormat = DXGI_FORMAT::DXGI_FORMAT_UNKNOWN;
|
|
|
|
// desc_pipeline.SampleDesc = m_desc_sample;
|
|
desc_pipeline.SampleDesc.Count = 1;
|
|
desc_pipeline.SampleDesc.Quality = 0;
|
|
|
|
desc_pipeline.SampleMask = 0xffffffff;
|
|
desc_pipeline.RasterizerState = desc_rasterizer;
|
|
desc_pipeline.BlendState = desc_blend_state;
|
|
desc_pipeline.NumRenderTargets = 1;
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
|
|
status = m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::BlendMask)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (BlendMask)");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_root_signatures[static_cast<int>(ProgramId::BlendMask)]->SetName(TEXT("rs of BlendMask"));
|
|
m_pipelines[static_cast<int>(ProgramId::BlendMask)]->SetName(TEXT("pipeline BlendMask"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resource_Pipeline_Blur()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_Pipeline_Blur");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid when we call this method!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
D3D12_DESCRIPTOR_RANGE ranges[1];
|
|
ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
|
ranges[0].NumDescriptors = 1;
|
|
ranges[0].BaseShaderRegister = 0;
|
|
ranges[0].RegisterSpace = 0;
|
|
ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
|
|
|
D3D12_ROOT_DESCRIPTOR_TABLE table{};
|
|
table.NumDescriptorRanges = sizeof(ranges) / sizeof(decltype(ranges[0]));
|
|
table.pDescriptorRanges = ranges;
|
|
|
|
D3D12_ROOT_DESCRIPTOR descriptor_cbv{};
|
|
descriptor_cbv.RegisterSpace = 0;
|
|
descriptor_cbv.ShaderRegister = 0;
|
|
|
|
D3D12_ROOT_PARAMETER parameters[3];
|
|
|
|
parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
|
parameters[0].DescriptorTable = table;
|
|
parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
parameters[1].Descriptor = descriptor_cbv;
|
|
parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
|
|
|
|
parameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
parameters[2].Descriptor = descriptor_cbv;
|
|
parameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_STATIC_SAMPLER_DESC sampler = {};
|
|
sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
|
sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.MipLODBias = 0;
|
|
sampler.MaxAnisotropy = 0;
|
|
sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
|
sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
|
|
sampler.MinLOD = 0.0f;
|
|
sampler.MaxLOD = D3D12_FLOAT32_MAX;
|
|
sampler.ShaderRegister = 0;
|
|
sampler.RegisterSpace = 0;
|
|
sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_ROOT_SIGNATURE_DESC desc_rootsignature;
|
|
desc_rootsignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
|
|
desc_rootsignature.NumParameters = _countof(parameters);
|
|
desc_rootsignature.pParameters = parameters;
|
|
desc_rootsignature.NumStaticSamplers = 1;
|
|
desc_rootsignature.pStaticSamplers = &sampler;
|
|
|
|
ID3DBlob* p_signature{};
|
|
ID3DBlob* p_error{};
|
|
auto status = D3D12SerializeRootSignature(&desc_rootsignature, D3D_ROOT_SIGNATURE_VERSION_1, &p_signature, &p_error);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to D3D12SerializeRootSignature: %s",
|
|
(char*)p_error->GetBufferPointer());
|
|
}
|
|
#endif
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3D12SerializeRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::Blur)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
if (p_signature)
|
|
{
|
|
p_signature->Release();
|
|
p_signature = nullptr;
|
|
}
|
|
|
|
if (p_error)
|
|
{
|
|
p_error->Release();
|
|
p_error = nullptr;
|
|
}
|
|
|
|
ID3DBlob* p_shader_vertex{};
|
|
ID3DBlob* p_shader_pixel{};
|
|
ID3DBlob* p_error_buff{};
|
|
|
|
const D3D_SHADER_MACRO macros[] = {NULL, NULL, NULL, NULL};
|
|
|
|
status = D3DCompile(pShaderSourceText_Vertex_Blur, sizeof(pShaderSourceText_Vertex_Blur), nullptr, macros, nullptr, "main", "vs_5_0",
|
|
m_default_shader_flags, 0, &p_shader_vertex, &p_error_buff);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s", (char*)p_error_buff->GetBufferPointer());
|
|
}
|
|
#endif
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
status = D3DCompile(pShaderSourceText_Pixel_Blur, sizeof(pShaderSourceText_Pixel_Blur), nullptr, nullptr, nullptr, "main", "ps_5_0",
|
|
m_default_shader_flags, 0, &p_shader_pixel, &p_error_buff);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s",
|
|
(char*)(p_error_buff->GetBufferPointer()));
|
|
}
|
|
#endif
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_pixel_shader = {};
|
|
desc_bytecode_pixel_shader.BytecodeLength = p_shader_pixel->GetBufferSize();
|
|
desc_bytecode_pixel_shader.pShaderBytecode = p_shader_pixel->GetBufferPointer();
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_vertex_shader = {};
|
|
desc_bytecode_vertex_shader.BytecodeLength = p_shader_vertex->GetBufferSize();
|
|
desc_bytecode_vertex_shader.pShaderBytecode = p_shader_vertex->GetBufferPointer();
|
|
|
|
D3D12_INPUT_ELEMENT_DESC desc_input_layout_elements[] = {
|
|
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}};
|
|
|
|
D3D12_INPUT_LAYOUT_DESC desc_input_layout = {};
|
|
|
|
desc_input_layout.NumElements = sizeof(desc_input_layout_elements) / sizeof(D3D12_INPUT_ELEMENT_DESC);
|
|
desc_input_layout.pInputElementDescs = desc_input_layout_elements;
|
|
|
|
D3D12_RASTERIZER_DESC desc_rasterizer = {};
|
|
|
|
desc_rasterizer.AntialiasedLineEnable = FALSE;
|
|
desc_rasterizer.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
desc_rasterizer.CullMode = D3D12_CULL_MODE_NONE;
|
|
desc_rasterizer.DepthBias = 0;
|
|
desc_rasterizer.DepthBiasClamp = 0;
|
|
desc_rasterizer.DepthClipEnable = FALSE;
|
|
desc_rasterizer.ForcedSampleCount = 0;
|
|
desc_rasterizer.FrontCounterClockwise = FALSE;
|
|
desc_rasterizer.MultisampleEnable = FALSE;
|
|
desc_rasterizer.FillMode = D3D12_FILL_MODE::D3D12_FILL_MODE_SOLID;
|
|
desc_rasterizer.SlopeScaledDepthBias = 0;
|
|
|
|
D3D12_BLEND_DESC desc_blend_state = {};
|
|
|
|
desc_blend_state.AlphaToCoverageEnable = FALSE;
|
|
desc_blend_state.IndependentBlendEnable = FALSE;
|
|
const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
|
|
FALSE,
|
|
FALSE,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_LOGIC_OP_NOOP,
|
|
D3D12_COLOR_WRITE_ENABLE_ALL,
|
|
};
|
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
desc_blend_state.RenderTarget[i] = defaultRenderTargetBlendDesc;
|
|
|
|
D3D12_DEPTH_STENCIL_DESC desc_depth_stencil = {};
|
|
|
|
desc_depth_stencil.DepthEnable = FALSE;
|
|
desc_depth_stencil.StencilEnable = TRUE;
|
|
desc_depth_stencil.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
|
desc_depth_stencil.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
|
|
desc_depth_stencil.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
desc_depth_stencil.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_pipeline = {};
|
|
|
|
desc_pipeline.InputLayout = desc_input_layout;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::Blur)];
|
|
desc_pipeline.VS = desc_bytecode_vertex_shader;
|
|
desc_pipeline.PS = desc_bytecode_pixel_shader;
|
|
desc_pipeline.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
desc_pipeline.RTVFormats[0] = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc_pipeline.DSVFormat = DXGI_FORMAT::DXGI_FORMAT_UNKNOWN;
|
|
|
|
// desc_pipeline.SampleDesc = m_desc_sample;
|
|
desc_pipeline.SampleDesc.Count = 1;
|
|
desc_pipeline.SampleDesc.Quality = 0;
|
|
|
|
desc_pipeline.SampleMask = 0xffffffff;
|
|
desc_pipeline.RasterizerState = desc_rasterizer;
|
|
desc_pipeline.BlendState = desc_blend_state;
|
|
desc_pipeline.NumRenderTargets = 1;
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
|
|
status = m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::Blur)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (Blur)");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_root_signatures[static_cast<int>(ProgramId::Blur)]->SetName(TEXT("rs of Blur"));
|
|
m_pipelines[static_cast<int>(ProgramId::Blur)]->SetName(TEXT("pipeline Blur"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Create_Resource_Pipeline_DropShadow()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Create_Resource_Pipeline_DropShadow");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid when we call this method!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
D3D12_DESCRIPTOR_RANGE ranges[1];
|
|
ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
|
ranges[0].NumDescriptors = 1;
|
|
ranges[0].BaseShaderRegister = 0;
|
|
ranges[0].RegisterSpace = 0;
|
|
ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
|
|
|
D3D12_ROOT_DESCRIPTOR_TABLE table{};
|
|
table.NumDescriptorRanges = sizeof(ranges) / sizeof(decltype(ranges[0]));
|
|
table.pDescriptorRanges = ranges;
|
|
|
|
D3D12_ROOT_DESCRIPTOR descriptor_cbv{};
|
|
descriptor_cbv.RegisterSpace = 0;
|
|
descriptor_cbv.ShaderRegister = 0;
|
|
|
|
D3D12_ROOT_PARAMETER parameters[2];
|
|
|
|
parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
|
parameters[0].DescriptorTable = table;
|
|
parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
parameters[1].Descriptor = descriptor_cbv;
|
|
parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_STATIC_SAMPLER_DESC sampler = {};
|
|
sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
|
sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
|
sampler.MipLODBias = 0;
|
|
sampler.MaxAnisotropy = 0;
|
|
sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
|
sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
|
|
sampler.MinLOD = 0.0f;
|
|
sampler.MaxLOD = D3D12_FLOAT32_MAX;
|
|
sampler.ShaderRegister = 0;
|
|
sampler.RegisterSpace = 0;
|
|
sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
|
|
|
D3D12_ROOT_SIGNATURE_DESC desc_rootsignature;
|
|
desc_rootsignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
|
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
|
|
desc_rootsignature.NumParameters = _countof(parameters);
|
|
desc_rootsignature.pParameters = parameters;
|
|
desc_rootsignature.NumStaticSamplers = 1;
|
|
desc_rootsignature.pStaticSamplers = &sampler;
|
|
|
|
ID3DBlob* p_signature{};
|
|
ID3DBlob* p_error{};
|
|
auto status = D3D12SerializeRootSignature(&desc_rootsignature, D3D_ROOT_SIGNATURE_VERSION_1, &p_signature, &p_error);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to D3D12SerializeRootSignature: %s",
|
|
(char*)p_error->GetBufferPointer());
|
|
}
|
|
#endif
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3D12SerializeRootSignature");
|
|
|
|
status = m_p_device->CreateRootSignature(0, p_signature->GetBufferPointer(), p_signature->GetBufferSize(),
|
|
IID_PPV_ARGS(&m_root_signatures[static_cast<int>(ProgramId::DropShadow)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateRootSignature");
|
|
|
|
if (p_signature)
|
|
{
|
|
p_signature->Release();
|
|
p_signature = nullptr;
|
|
}
|
|
|
|
if (p_error)
|
|
{
|
|
p_error->Release();
|
|
p_error = nullptr;
|
|
}
|
|
|
|
ID3DBlob* p_shader_vertex{};
|
|
ID3DBlob* p_shader_pixel{};
|
|
ID3DBlob* p_error_buff{};
|
|
|
|
const D3D_SHADER_MACRO macros[] = {NULL, NULL, NULL, NULL};
|
|
|
|
status = D3DCompile(pShaderSourceText_Vertex_PassThrough, sizeof(pShaderSourceText_Vertex_PassThrough), nullptr, macros, nullptr, "main",
|
|
"vs_5_0", m_default_shader_flags, 0, &p_shader_vertex, &p_error_buff);
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s", (char*)p_error_buff->GetBufferPointer());
|
|
}
|
|
#endif
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
status = D3DCompile(pShaderSourceText_Pixel_DropShadow, sizeof(pShaderSourceText_Pixel_DropShadow), nullptr, nullptr, nullptr, "main",
|
|
"ps_5_0", m_default_shader_flags, 0, &p_shader_pixel, &p_error_buff);
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (FAILED(status))
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12][ERROR] failed to compile shader: %s",
|
|
(char*)(p_error_buff->GetBufferPointer()));
|
|
}
|
|
#endif
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3DCompile");
|
|
|
|
if (p_error_buff)
|
|
{
|
|
p_error_buff->Release();
|
|
p_error_buff = nullptr;
|
|
}
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_pixel_shader = {};
|
|
desc_bytecode_pixel_shader.BytecodeLength = p_shader_pixel->GetBufferSize();
|
|
desc_bytecode_pixel_shader.pShaderBytecode = p_shader_pixel->GetBufferPointer();
|
|
|
|
D3D12_SHADER_BYTECODE desc_bytecode_vertex_shader = {};
|
|
desc_bytecode_vertex_shader.BytecodeLength = p_shader_vertex->GetBufferSize();
|
|
desc_bytecode_vertex_shader.pShaderBytecode = p_shader_vertex->GetBufferPointer();
|
|
|
|
D3D12_INPUT_ELEMENT_DESC desc_input_layout_elements[] = {
|
|
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
|
|
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}};
|
|
|
|
D3D12_INPUT_LAYOUT_DESC desc_input_layout = {};
|
|
|
|
desc_input_layout.NumElements = sizeof(desc_input_layout_elements) / sizeof(D3D12_INPUT_ELEMENT_DESC);
|
|
desc_input_layout.pInputElementDescs = desc_input_layout_elements;
|
|
|
|
D3D12_RASTERIZER_DESC desc_rasterizer = {};
|
|
|
|
desc_rasterizer.AntialiasedLineEnable = FALSE;
|
|
desc_rasterizer.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
desc_rasterizer.CullMode = D3D12_CULL_MODE_NONE;
|
|
desc_rasterizer.DepthBias = 0;
|
|
desc_rasterizer.DepthBiasClamp = 0;
|
|
desc_rasterizer.DepthClipEnable = FALSE;
|
|
desc_rasterizer.ForcedSampleCount = 0;
|
|
desc_rasterizer.FrontCounterClockwise = FALSE;
|
|
desc_rasterizer.MultisampleEnable = FALSE;
|
|
desc_rasterizer.FillMode = D3D12_FILL_MODE::D3D12_FILL_MODE_SOLID;
|
|
desc_rasterizer.SlopeScaledDepthBias = 0;
|
|
|
|
D3D12_BLEND_DESC desc_blend_state = {};
|
|
|
|
desc_blend_state.AlphaToCoverageEnable = FALSE;
|
|
desc_blend_state.IndependentBlendEnable = FALSE;
|
|
const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
|
|
FALSE,
|
|
FALSE,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_BLEND_ONE,
|
|
D3D12_BLEND_INV_SRC_ALPHA,
|
|
D3D12_BLEND_OP_ADD,
|
|
D3D12_LOGIC_OP_NOOP,
|
|
D3D12_COLOR_WRITE_ENABLE_ALL,
|
|
};
|
|
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
|
|
desc_blend_state.RenderTarget[i] = defaultRenderTargetBlendDesc;
|
|
|
|
D3D12_DEPTH_STENCIL_DESC desc_depth_stencil = {};
|
|
|
|
desc_depth_stencil.DepthEnable = FALSE;
|
|
desc_depth_stencil.StencilEnable = TRUE;
|
|
desc_depth_stencil.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
|
desc_depth_stencil.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
desc_depth_stencil.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
|
|
desc_depth_stencil.StencilWriteMask = 0;
|
|
|
|
desc_depth_stencil.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
desc_depth_stencil.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
desc_depth_stencil.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
desc_depth_stencil.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
|
|
desc_depth_stencil.BackFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_pipeline = {};
|
|
|
|
desc_pipeline.InputLayout = desc_input_layout;
|
|
desc_pipeline.pRootSignature = m_root_signatures[static_cast<int>(ProgramId::DropShadow)];
|
|
desc_pipeline.VS = desc_bytecode_vertex_shader;
|
|
desc_pipeline.PS = desc_bytecode_pixel_shader;
|
|
desc_pipeline.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
desc_pipeline.RTVFormats[0] = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc_pipeline.DSVFormat = DXGI_FORMAT::DXGI_FORMAT_UNKNOWN;
|
|
|
|
// desc_pipeline.SampleDesc = m_desc_sample;
|
|
desc_pipeline.SampleDesc.Count = 1;
|
|
desc_pipeline.SampleDesc.Quality = 0;
|
|
|
|
desc_pipeline.SampleMask = 0xffffffff;
|
|
desc_pipeline.RasterizerState = desc_rasterizer;
|
|
desc_pipeline.BlendState = desc_blend_state;
|
|
desc_pipeline.NumRenderTargets = 1;
|
|
desc_pipeline.DepthStencilState = desc_depth_stencil;
|
|
|
|
status = m_p_device->CreateGraphicsPipelineState(&desc_pipeline, IID_PPV_ARGS(&m_pipelines[static_cast<int>(ProgramId::DropShadow)]));
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateGraphicsPipelineState (DropShadow)");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
m_root_signatures[static_cast<int>(ProgramId::DropShadow)]->SetName(TEXT("rs of DropShadow"));
|
|
m_pipelines[static_cast<int>(ProgramId::DropShadow)]->SetName(TEXT("pipeline DropShadow"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::Destroy_Resource_Pipelines()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Destroy_Resource_Pipelines");
|
|
Destroy_Resource_For_Shaders();
|
|
|
|
if (m_p_depthstencil_resource)
|
|
{
|
|
Destroy_Resource_DepthStencil();
|
|
}
|
|
|
|
for (int i = 1; i < static_cast<int>(ProgramId::Count); ++i)
|
|
{
|
|
if (m_pipelines[i])
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_pipelines[i]->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
m_pipelines[i] = nullptr;
|
|
}
|
|
|
|
if (m_root_signatures[i])
|
|
{
|
|
m_root_signatures[i]->Release();
|
|
m_root_signatures[i] = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool RenderInterface_DX12::CheckTearingSupport() noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - CheckTearingSupport");
|
|
int result{};
|
|
|
|
IDXGIFactory4* pFactory4{};
|
|
|
|
if (SUCCEEDED(CreateDXGIFactory1(IID_PPV_ARGS(&pFactory4))))
|
|
{
|
|
IDXGIFactory5* pFactory5{};
|
|
|
|
if (SUCCEEDED(pFactory4->QueryInterface(IID_PPV_ARGS(&pFactory5))))
|
|
{
|
|
if (FAILED(pFactory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &result, sizeof(result))))
|
|
{
|
|
result = 0;
|
|
}
|
|
|
|
if (pFactory5)
|
|
{
|
|
pFactory5->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pFactory4)
|
|
{
|
|
pFactory4->Release();
|
|
}
|
|
|
|
return result == 1;
|
|
}
|
|
|
|
IDXGIAdapter* RenderInterface_DX12::Get_Adapter(bool is_use_warp) noexcept
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Get_Adapter");
|
|
IDXGIFactory4* p_factory{};
|
|
|
|
uint32_t create_flags{};
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
create_flags = DXGI_CREATE_FACTORY_DEBUG;
|
|
#endif
|
|
|
|
RMLUI_DX_VERIFY_MSG(CreateDXGIFactory2(create_flags, IID_PPV_ARGS(&p_factory)), "failed to CreateDXGIFactory2");
|
|
|
|
IDXGIAdapter* p_adapter{};
|
|
IDXGIAdapter1* p_adapter1{};
|
|
IDXGIAdapter4* p_adapter4{};
|
|
|
|
if (is_use_warp)
|
|
{
|
|
if (p_factory)
|
|
{
|
|
RMLUI_DX_VERIFY_MSG(p_factory->EnumWarpAdapter(IID_PPV_ARGS(&p_adapter)), "failed to EnumAdapters");
|
|
RMLUI_ASSERTMSG(p_adapter, "returned invalid COM object from EnumWarpAdapter");
|
|
|
|
if (p_adapter)
|
|
{
|
|
p_adapter->QueryInterface(IID_PPV_ARGS(&p_adapter4));
|
|
RMLUI_ASSERTMSG(p_adapter4, "returned invalid COM object from QueryInterface");
|
|
PrintAdapterDesc(p_adapter);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (p_factory)
|
|
{
|
|
size_t max_dedicated_video_memory{};
|
|
|
|
for (uint32_t i = 0; p_factory->EnumAdapters(i, &p_adapter) != DXGI_ERROR_NOT_FOUND; ++i)
|
|
{
|
|
if (p_adapter)
|
|
{
|
|
DXGI_ADAPTER_DESC1 desc;
|
|
|
|
RMLUI_DX_VERIFY_MSG(p_adapter->QueryInterface(IID_PPV_ARGS(&p_adapter1)), "failed to QueryInterface of IDXGIAdapter1");
|
|
|
|
if (p_adapter1)
|
|
{
|
|
p_adapter1->GetDesc1(&desc);
|
|
|
|
ID3D12Device* p_test_device{};
|
|
|
|
if ((desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) == 0 &&
|
|
SUCCEEDED(D3D12CreateDevice(p_adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&p_test_device))) &&
|
|
desc.DedicatedVideoMemory > max_dedicated_video_memory)
|
|
{
|
|
max_dedicated_video_memory = desc.DedicatedVideoMemory;
|
|
|
|
// found 'device' with bigger memory means we found our discrete video card (not cpu integrated)
|
|
if (p_adapter4)
|
|
{
|
|
p_adapter4->Release();
|
|
p_adapter4 = nullptr;
|
|
}
|
|
|
|
RMLUI_DX_VERIFY_MSG(p_adapter->QueryInterface(IID_PPV_ARGS(&p_adapter4)), "failed to QueryInterface of IDXGIAdapter4");
|
|
|
|
PrintAdapterDesc(p_adapter);
|
|
}
|
|
|
|
if (p_test_device)
|
|
{
|
|
p_test_device->Release();
|
|
}
|
|
}
|
|
|
|
if (p_adapter)
|
|
{
|
|
p_adapter->Release();
|
|
}
|
|
|
|
if (p_adapter1)
|
|
{
|
|
p_adapter1->Release();
|
|
p_adapter1 = nullptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (p_factory)
|
|
{
|
|
p_factory->Release();
|
|
}
|
|
|
|
if (p_adapter)
|
|
{
|
|
p_adapter->Release();
|
|
}
|
|
|
|
if (p_adapter1)
|
|
{
|
|
p_adapter1->Release();
|
|
}
|
|
|
|
return p_adapter4;
|
|
}
|
|
|
|
void RenderInterface_DX12::PrintAdapterDesc(IDXGIAdapter* p_adapter)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - PrintAdapterDesc");
|
|
RMLUI_ASSERTMSG(p_adapter, "you can't pass invalid argument");
|
|
|
|
if (p_adapter)
|
|
{
|
|
DXGI_ADAPTER_DESC desc;
|
|
p_adapter->GetDesc(&desc);
|
|
|
|
char p_converted[_countof(desc.Description)];
|
|
memset(p_converted, 0, sizeof(p_converted));
|
|
|
|
#ifdef UNICODE
|
|
sprintf(p_converted, "%ls", desc.Description);
|
|
#else
|
|
p_converted = desc.Description;
|
|
#endif
|
|
|
|
float vid_mem_in_bytes = static_cast<float>(desc.DedicatedVideoMemory);
|
|
float vid_mem_in_kilobytes = vid_mem_in_bytes / 1024.0f;
|
|
float vid_mem_in_megabytes = vid_mem_in_kilobytes / 1024.0f;
|
|
float vid_mem_in_gigabytes = vid_mem_in_megabytes / 1024.0f;
|
|
|
|
Rml::Log::Message(Rml::Log::LT_INFO, "Monitor[%s]\n VideoMemory[%f Bytes][%f Mbs][%f Gbs]\n", p_converted, vid_mem_in_bytes,
|
|
vid_mem_in_megabytes, vid_mem_in_gigabytes);
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::SetScissor(Rml::Rectanglei region, bool vertically_flip)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - SetScissor");
|
|
|
|
if (region.Valid() != m_scissor.Valid())
|
|
{
|
|
if (!region.Valid())
|
|
{
|
|
m_is_scissor_was_set = false;
|
|
|
|
if (m_p_command_graphics_list)
|
|
{
|
|
D3D12_RECT disable_scissor = {};
|
|
disable_scissor.left = 0;
|
|
disable_scissor.top = 0;
|
|
disable_scissor.right = m_width;
|
|
disable_scissor.bottom = m_height;
|
|
m_p_command_graphics_list->RSSetScissorRects(1, &disable_scissor);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, "SetScissor");
|
|
|
|
if (region.Valid() && vertically_flip)
|
|
{
|
|
region = VerticallyFlipped(region, m_height);
|
|
}
|
|
|
|
if (region.Valid())
|
|
{
|
|
if (m_p_command_graphics_list)
|
|
{
|
|
D3D12_RECT scissor;
|
|
|
|
const int x_min = Rml::Math::Clamp(region.Left(), 0, m_width);
|
|
const int y_min = Rml::Math::Clamp(region.Top(), 0, m_height);
|
|
const int x_max = Rml::Math::Clamp(region.Right(), 0, m_width);
|
|
const int y_max = Rml::Math::Clamp(region.Bottom(), 0, m_height);
|
|
|
|
scissor.left = x_min;
|
|
scissor.right = x_max;
|
|
scissor.bottom = y_max;
|
|
scissor.top = y_min;
|
|
|
|
m_p_command_graphics_list->RSSetScissorRects(1, &scissor);
|
|
m_is_scissor_was_set = true;
|
|
}
|
|
}
|
|
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
|
|
m_scissor = region;
|
|
}
|
|
|
|
void RenderInterface_DX12::SubmitTransformUniform(ConstantBufferType& constant_buffer, const Rml::Vector2f& translation)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - SubmitTransformUniform");
|
|
static_assert((size_t)ProgramId::Count < RMLUI_RENDER_BACKEND_FIELD_MAXNUMPROGRAMS, "Maximum number of pipelines exceeded");
|
|
|
|
std::uint8_t* p_gpu_binding_start = reinterpret_cast<std::uint8_t*>(constant_buffer.m_p_gpu_start_memory_for_binding_data);
|
|
|
|
{
|
|
RMLUI_ASSERTMSG(p_gpu_binding_start,
|
|
"your allocated constant buffer must contain a valid pointer of beginning mapping of its GPU buffer. Otherwise you destroyed it!");
|
|
|
|
if (p_gpu_binding_start)
|
|
{
|
|
std::uint8_t* p_gpu_binding_offset_to_transform = p_gpu_binding_start + constant_buffer.m_alloc_info.offset;
|
|
|
|
std::memcpy(p_gpu_binding_offset_to_transform, m_constant_buffer_data_transform.data(), sizeof(m_constant_buffer_data_transform));
|
|
}
|
|
}
|
|
|
|
if (p_gpu_binding_start)
|
|
{
|
|
std::uint8_t* p_gpu_binding_offset_to_translate =
|
|
p_gpu_binding_start + (constant_buffer.m_alloc_info.offset + sizeof(m_constant_buffer_data_transform));
|
|
|
|
std::memcpy(p_gpu_binding_offset_to_translate, &translation.x, sizeof(translation));
|
|
}
|
|
}
|
|
|
|
constexpr const char* translate_programId(ProgramId id)
|
|
{
|
|
switch (id)
|
|
{
|
|
case ProgramId::None: return "None";
|
|
case ProgramId::Color_Stencil_Always: return "Color_Stencil_Always";
|
|
case ProgramId::Color_Stencil_Equal: return "Color_Stencil_Equal";
|
|
case ProgramId::Color_Stencil_Set: return "Color_Stencil_Set";
|
|
case ProgramId::Color_Stencil_SetInverse: return "Color_Stencil_SetInverse";
|
|
case ProgramId::Color_Stencil_Intersect: return "Color_Stencil_Intersect";
|
|
case ProgramId::Color_Stencil_Disabled: return "Color_Stencil_Disabled";
|
|
case ProgramId::Texture_Stencil_Always: return "Texture_Stencil_Always";
|
|
case ProgramId::Texture_Stencil_Equal: return "Texture_Stencil_Equal";
|
|
case ProgramId::Texture_Stencil_Disabled: return "Texture_Stencil_Disabled";
|
|
case ProgramId::Gradient: return "Gradient";
|
|
case ProgramId::Creation: return "Creation";
|
|
case ProgramId::Passthrough: return "Passthrough";
|
|
case ProgramId::Passthrough_NoDepthStencil: return "Passthrough_NoDepthStencil";
|
|
case ProgramId::Passthrough_Opacity: return "Passthrough_Opacity";
|
|
case ProgramId::Passthrough_MSAA: return "Passthrough_MSAA";
|
|
case ProgramId::Passthrough_MSAA_Equal: return "Passthrough_MSAA_Equal";
|
|
case ProgramId::Passthrough_NoBlend: return "Passthrough_NoBlend";
|
|
case ProgramId::Passthrough_NoBlendAndNoMSAA: return "Passthrough_NoBlendAndNoMSAA";
|
|
case ProgramId::ColorMatrix: return "ColorMatrix";
|
|
case ProgramId::BlendMask: return "BlendMask";
|
|
case ProgramId::Blur: return "Blur";
|
|
case ProgramId::DropShadow: return "DropShadow";
|
|
case ProgramId::Count: return "Count";
|
|
default: return "UNKNOWN_PROGRAMID";
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::UseProgram(ProgramId pipeline_id)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - UseProgram");
|
|
RMLUI_ASSERTMSG(pipeline_id < ProgramId::Count, "overflow, too big value for indexing");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
char msg[64];
|
|
std::sprintf(msg, "UseProgram = %s", translate_programId(pipeline_id));
|
|
#endif
|
|
|
|
RMLUI_DX_MARKER_BEGIN(m_p_command_graphics_list, msg);
|
|
if (pipeline_id != ProgramId::None)
|
|
{
|
|
RMLUI_ASSERTMSG(m_pipelines[static_cast<int>(pipeline_id)], "you forgot to initialize or deleted!");
|
|
RMLUI_ASSERTMSG(m_root_signatures[static_cast<int>(pipeline_id)], "you forgot to initialize or deleted!");
|
|
|
|
m_p_command_graphics_list->SetPipelineState(m_pipelines[static_cast<int>(pipeline_id)]);
|
|
m_p_command_graphics_list->SetGraphicsRootSignature(m_root_signatures[static_cast<int>(pipeline_id)]);
|
|
|
|
ID3D12DescriptorHeap* p_heaps[] = {m_p_descriptor_heap_shaders};
|
|
m_p_command_graphics_list->SetDescriptorHeaps(_countof(p_heaps), p_heaps);
|
|
}
|
|
RMLUI_DX_MARKER_END(m_p_command_graphics_list);
|
|
|
|
m_active_program_id = pipeline_id;
|
|
}
|
|
|
|
RenderInterface_DX12::ConstantBufferType* RenderInterface_DX12::Get_ConstantBuffer(uint32_t current_back_buffer_index)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Get_ConstantBuffer");
|
|
RMLUI_ASSERTMSG(current_back_buffer_index != uint32_t(-1), "invalid index!");
|
|
|
|
auto max_index = RMLUI_RENDER_BACKEND_FIELD_PREALLOCATED_CONSTANTBUFFERS - 1;
|
|
|
|
if (m_constantbuffers[current_back_buffer_index].size() > RMLUI_RENDER_BACKEND_FIELD_PREALLOCATED_CONSTANTBUFFERS)
|
|
max_index = static_cast<int>(m_constantbuffers[current_back_buffer_index].size() - 1);
|
|
|
|
auto current_constant_buffer_index = m_constant_buffer_count_per_frame[current_back_buffer_index];
|
|
if (current_constant_buffer_index > max_index)
|
|
{
|
|
// resizing...
|
|
for (auto& vec : m_constantbuffers)
|
|
{
|
|
vec.emplace_back(std::move(ConstantBufferType()));
|
|
}
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12] allocated new constant buffer instance for frame[%d], current size of storage[%zu]",
|
|
current_back_buffer_index, m_constantbuffers.at(current_back_buffer_index).size());
|
|
#endif
|
|
}
|
|
|
|
auto& vec_cbs = m_constantbuffers.at(current_back_buffer_index);
|
|
|
|
ConstantBufferType* p_result = &vec_cbs[current_constant_buffer_index];
|
|
if (p_result->m_alloc_info.buffer_index == -1)
|
|
{
|
|
p_result->m_alloc_info = m_manager_buffer.Alloc_ConstantBuffer(p_result, kAllocationSizeMax_ConstantBuffer);
|
|
}
|
|
|
|
++m_constant_buffer_count_per_frame[current_back_buffer_index];
|
|
|
|
return p_result;
|
|
}
|
|
|
|
RenderInterface_DX12::BufferMemoryManager::BufferMemoryManager() :
|
|
m_descriptor_increment_size_srv_cbv_uav{}, m_size_for_allocation_in_bytes{}, m_size_alignment_in_bytes{}, m_p_device{}, m_p_allocator{},
|
|
m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav{}, m_p_start_pointer_of_descriptor_heap_srv_cbv_uav{}
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Constructor");
|
|
}
|
|
|
|
RenderInterface_DX12::BufferMemoryManager::~BufferMemoryManager()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Destructor");
|
|
}
|
|
|
|
bool RenderInterface_DX12::BufferMemoryManager::Is_Initialized() const
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferManagerManager::Is_Initialized");
|
|
return static_cast<bool>(m_p_device != nullptr);
|
|
}
|
|
|
|
void RenderInterface_DX12::BufferMemoryManager::Initialize(ID3D12Device* 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_srv_cbv_uav, size_t size_for_allocation, size_t size_alignment)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Initialize");
|
|
RMLUI_ASSERTMSG(p_allocator, "must be valid!");
|
|
RMLUI_ASSERTMSG(size_for_allocation, "must be greater than 0");
|
|
RMLUI_ASSERTMSG(size_alignment, "must be greater than 0");
|
|
RMLUI_ASSERTMSG(p_offset_allocator_for_descriptor_heap_srv_cbv_uav, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_handle, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_device, "must be valid!");
|
|
|
|
m_p_allocator = p_allocator;
|
|
m_size_for_allocation_in_bytes = size_for_allocation;
|
|
m_size_alignment_in_bytes = size_alignment;
|
|
m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav = p_offset_allocator_for_descriptor_heap_srv_cbv_uav;
|
|
m_p_start_pointer_of_descriptor_heap_srv_cbv_uav = p_handle;
|
|
m_descriptor_increment_size_srv_cbv_uav = size_descriptor_srv_cbv_uav;
|
|
m_p_device = p_device;
|
|
|
|
Alloc_Buffer(size_for_allocation
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
,
|
|
std::wstring(L"buffer[") + std::to_wstring(m_buffers.size()) + L"]"
|
|
#endif
|
|
);
|
|
}
|
|
|
|
void RenderInterface_DX12::BufferMemoryManager::Shutdown()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Shutdown");
|
|
for (auto& pair : m_buffers)
|
|
{
|
|
auto* p_allocation = pair.first;
|
|
|
|
if (p_allocation)
|
|
{
|
|
if (p_allocation->GetResource())
|
|
{
|
|
p_allocation->GetResource()->Unmap(0, nullptr);
|
|
p_allocation->GetResource()->Release();
|
|
}
|
|
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = p_allocation->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak!");
|
|
}
|
|
}
|
|
|
|
for (auto* p_block : m_virtual_buffers)
|
|
{
|
|
if (p_block)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = p_block->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak! (virtual block)");
|
|
}
|
|
}
|
|
|
|
if (m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav)
|
|
{
|
|
m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav = nullptr;
|
|
}
|
|
|
|
if (m_p_allocator)
|
|
{
|
|
m_p_allocator = nullptr;
|
|
}
|
|
|
|
m_buffers.clear();
|
|
m_virtual_buffers.clear();
|
|
m_p_device = nullptr;
|
|
}
|
|
|
|
void RenderInterface_DX12::BufferMemoryManager::Alloc_Vertex(const void* p_data, int num_vertices, size_t size_of_one_element_in_p_data,
|
|
GeometryHandleType* p_handle)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Alloc_Vertex");
|
|
RMLUI_ASSERTMSG(p_data, "data for mapping to buffer must valid!");
|
|
RMLUI_ASSERTMSG(num_vertices, "amount of vertices must be greater than zero!");
|
|
RMLUI_ASSERTMSG(size_of_one_element_in_p_data > 0, "size of one element must be greater than 0");
|
|
RMLUI_ASSERTMSG(p_handle, "must be valid!");
|
|
|
|
if (p_handle)
|
|
{
|
|
RMLUI_ASSERT(p_handle->Get_InfoVertex().buffer_index == -1 &&
|
|
"info is already initialized that means you didn't destroy your buffer! Something is wrong!");
|
|
|
|
p_handle->Set_NumVertices(num_vertices);
|
|
p_handle->Set_SizeOfOneVertex(size_of_one_element_in_p_data);
|
|
|
|
GraphicsAllocationInfo info;
|
|
Alloc(info, num_vertices * size_of_one_element_in_p_data);
|
|
|
|
void* p_writable_part = Get_WritableMemoryFromBufferByOffset(info);
|
|
|
|
RMLUI_ASSERTMSG(p_writable_part, "something is wrong!");
|
|
|
|
if (p_writable_part)
|
|
{
|
|
std::memcpy(p_writable_part, p_data, info.size);
|
|
}
|
|
|
|
p_handle->Set_InfoVertex(info);
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
auto* p_block = m_virtual_buffers.at(info.buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_block, "can't be invalid!");
|
|
|
|
D3D12MA::Statistics stats;
|
|
p_block->GetStatistics(&stats);
|
|
|
|
auto available_memory = stats.BlockBytes - stats.AllocationBytes;
|
|
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG,
|
|
"[DirectX-12] allocated vertex buffer with size[%zu] (in bytes) in buffer[%d] available memory for this buffer [%zu] (in bytes)",
|
|
info.size, info.buffer_index, available_memory);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::BufferMemoryManager::Alloc_Index(const void* p_data, int num_vertices, size_t size_of_one_element_in_p_data,
|
|
GeometryHandleType* p_handle)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Alloc_Index");
|
|
RMLUI_ASSERTMSG(p_data, "data for mapping to buffer must valid!");
|
|
RMLUI_ASSERTMSG(num_vertices, "amount of vertices must be greater than zero!");
|
|
RMLUI_ASSERTMSG(size_of_one_element_in_p_data > 0, "size of one element must be greater than 0");
|
|
RMLUI_ASSERTMSG(p_handle, "must be valid!");
|
|
|
|
if (p_handle)
|
|
{
|
|
RMLUI_ASSERT(p_handle->Get_InfoIndex().buffer_index == -1 &&
|
|
"info is already initialized that means you didn't destroy your buffer! Something is wrong!");
|
|
|
|
p_handle->Set_NumIndices(num_vertices);
|
|
p_handle->Set_SizeOfOneIndex(size_of_one_element_in_p_data);
|
|
|
|
GraphicsAllocationInfo info;
|
|
Alloc(info, num_vertices * size_of_one_element_in_p_data);
|
|
|
|
void* p_writable_part = Get_WritableMemoryFromBufferByOffset(info);
|
|
|
|
RMLUI_ASSERTMSG(p_writable_part, "something is wrong!");
|
|
|
|
if (p_writable_part)
|
|
{
|
|
std::memcpy(p_writable_part, p_data, num_vertices * size_of_one_element_in_p_data);
|
|
}
|
|
|
|
p_handle->Set_InfoIndex(info);
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
auto* p_block = m_virtual_buffers.at(info.buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_block, "can't be invalid!");
|
|
|
|
D3D12MA::Statistics stats;
|
|
p_block->GetStatistics(&stats);
|
|
|
|
auto available_memory = stats.BlockBytes - stats.AllocationBytes;
|
|
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG,
|
|
"[DirectX-12] allocated index buffer with size[%zu] (in bytes) in buffer[%d] available memory for this buffer [%zu] (in bytes)",
|
|
info.size, info.buffer_index, available_memory);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
RenderInterface_DX12::GraphicsAllocationInfo RenderInterface_DX12::BufferMemoryManager::Alloc_ConstantBuffer(ConstantBufferType* p_resource,
|
|
size_t size)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Alloc_ConstantBuffer");
|
|
RMLUI_ASSERTMSG(!m_buffers.empty(), "you forgot to allocate buffer on initialize stage of this manager!");
|
|
RMLUI_ASSERTMSG(p_resource, "must be valid!");
|
|
|
|
GraphicsAllocationInfo result;
|
|
auto result_index = Alloc(result, size, 256);
|
|
|
|
if (p_resource)
|
|
{
|
|
if (result_index != -1)
|
|
{
|
|
#ifdef RMLUI_DX_DEBUG
|
|
auto* p_block = m_virtual_buffers.at(result.buffer_index);
|
|
|
|
RMLUI_ASSERTMSG(p_block, "can't be invalid!");
|
|
|
|
D3D12MA::Statistics stats;
|
|
p_block->GetStatistics(&stats);
|
|
|
|
auto available_memory = stats.BlockBytes - stats.AllocationBytes;
|
|
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG,
|
|
"[DirectX-12] allocated constant buffer with size[%zu] (in bytes) in buffer[%d] available memory for this buffer [%zu] (in bytes)",
|
|
result.size, result.buffer_index, available_memory);
|
|
#endif
|
|
|
|
auto* p_dx_allocation = m_buffers.at(result_index).first;
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto* p_dx_resource = p_dx_allocation->GetResource();
|
|
|
|
RMLUI_ASSERTMSG(p_dx_allocation, "something is broken!");
|
|
RMLUI_ASSERTMSG(p_dx_resource, "something is broken!");
|
|
|
|
p_resource->m_p_gpu_start_memory_for_binding_data = m_buffers.at(result_index).second;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void RenderInterface_DX12::BufferMemoryManager::Free_ConstantBuffer(ConstantBufferType* p_constantbuffer)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Free_ConstantBuffer");
|
|
RMLUI_ASSERTMSG(p_constantbuffer, "you must pass a valid object!");
|
|
|
|
if (p_constantbuffer)
|
|
{
|
|
const auto& info = p_constantbuffer->m_alloc_info;
|
|
RMLUI_ASSERTMSG(info.buffer_index != -1, "must be valid data of this info");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12] deallocated constant buffer with size[%zu] in buffer[%d]", info.size,
|
|
info.buffer_index);
|
|
#endif
|
|
|
|
if (m_virtual_buffers.empty() == false)
|
|
{
|
|
if (D3D12MA::VirtualBlock* p_block = m_virtual_buffers.at(info.buffer_index))
|
|
{
|
|
p_block->FreeAllocation(info.alloc_info);
|
|
p_constantbuffer->m_alloc_info = {};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::BufferMemoryManager::Free_Geometry(GeometryHandleType* p_handle)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Free_Geometry");
|
|
RMLUI_ASSERTMSG(p_handle, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_handle->Get_InfoVertex().buffer_index != -1, "not initialized, maybe you passing twice for deallocation?");
|
|
RMLUI_ASSERTMSG(p_handle->Get_InfoIndex().buffer_index != -1, "not initialized, maybe you passing twice for deallocation?");
|
|
|
|
if (p_handle)
|
|
{
|
|
const auto& info_vertex = p_handle->Get_InfoVertex();
|
|
const auto& info_index = p_handle->Get_InfoIndex();
|
|
|
|
if (m_virtual_buffers.empty() == false)
|
|
{
|
|
D3D12MA::VirtualBlock* p_block_vertex = m_virtual_buffers.at(info_vertex.buffer_index);
|
|
D3D12MA::VirtualBlock* p_block_index = m_virtual_buffers.at(info_index.buffer_index);
|
|
|
|
if (p_block_vertex)
|
|
{
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12] deallocated vertex buffer with size[%zu] in buffer[%d] frame[%d]",
|
|
info_vertex.size, info_vertex.buffer_index, p_handle->Get_HistoryBackBufferFrameIndex());
|
|
#endif
|
|
|
|
p_block_vertex->FreeAllocation(info_vertex.alloc_info);
|
|
|
|
GraphicsAllocationInfo invalidate;
|
|
p_handle->Set_InfoVertex(invalidate);
|
|
}
|
|
|
|
if (p_block_index)
|
|
{
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12] deallocated index buffer with size[%zu] in buffer[%d]", info_index.size,
|
|
info_index.buffer_index);
|
|
#endif
|
|
|
|
p_block_index->FreeAllocation(info_index.alloc_info);
|
|
|
|
GraphicsAllocationInfo invalidate;
|
|
p_handle->Set_InfoIndex(invalidate);
|
|
}
|
|
|
|
// Free_ConstantBuffer(&p_handle->Get_ConstantBuffer());
|
|
}
|
|
}
|
|
}
|
|
|
|
void* RenderInterface_DX12::BufferMemoryManager::Get_WritableMemoryFromBufferByOffset(const GraphicsAllocationInfo& info)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Get_WritableMemoryFromBufferByOffset");
|
|
RMLUI_ASSERTMSG(info.buffer_index != -1, "you pass not initialized graphics allocation info!");
|
|
|
|
void* p_result{};
|
|
if (info.buffer_index != -1)
|
|
{
|
|
std::uint8_t* p_begin = reinterpret_cast<std::uint8_t*>(m_buffers.at(info.buffer_index).second);
|
|
|
|
RMLUI_ASSERTMSG(p_begin, "being pointer is not valid! it's terribly wrong thing!!!!");
|
|
|
|
p_result = p_begin + info.offset;
|
|
}
|
|
|
|
return p_result;
|
|
}
|
|
|
|
D3D12MA::Allocation* RenderInterface_DX12::BufferMemoryManager::Get_BufferByIndex(int buffer_index)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - Get_BufferByIndex");
|
|
RMLUI_ASSERTMSG(buffer_index >= 0, "index must be valid!");
|
|
RMLUI_ASSERTMSG(buffer_index < m_buffers.size(), "overflow index!");
|
|
|
|
D3D12MA::Allocation* p_result{};
|
|
|
|
if (buffer_index >= 0)
|
|
{
|
|
if (buffer_index < m_buffers.size())
|
|
{
|
|
p_result = m_buffers.at(buffer_index).first;
|
|
}
|
|
}
|
|
|
|
return p_result;
|
|
}
|
|
|
|
void RenderInterface_DX12::BufferMemoryManager::Alloc_Buffer(size_t size
|
|
#ifdef RMLUI_DX_DEBUG
|
|
,
|
|
const std::wstring& debug_name
|
|
#endif
|
|
)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Alloc_Buffer");
|
|
RMLUI_ASSERTMSG(size, "must be greater than 0");
|
|
|
|
D3D12_RESOURCE_DESC desc_constantbuffer = {};
|
|
desc_constantbuffer.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
desc_constantbuffer.Alignment = 0;
|
|
desc_constantbuffer.Width = size;
|
|
desc_constantbuffer.Height = 1;
|
|
desc_constantbuffer.DepthOrArraySize = 1;
|
|
desc_constantbuffer.MipLevels = 1;
|
|
desc_constantbuffer.Format = DXGI_FORMAT_UNKNOWN;
|
|
desc_constantbuffer.SampleDesc.Count = 1;
|
|
desc_constantbuffer.SampleDesc.Quality = 0;
|
|
desc_constantbuffer.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
desc_constantbuffer.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
|
|
D3D12MA::ALLOCATION_DESC desc_allocation = {};
|
|
desc_allocation.HeapType = D3D12_HEAP_TYPE_UPLOAD;
|
|
|
|
ID3D12Resource* p_resource{};
|
|
D3D12MA::Allocation* p_allocation{};
|
|
|
|
auto result = m_p_allocator->CreateResource(&desc_allocation, &desc_constantbuffer, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, &p_allocation,
|
|
IID_PPV_ARGS(&p_resource));
|
|
|
|
RMLUI_DX_VERIFY_MSG(result, "failed to CreateResource");
|
|
|
|
void* p_begin_writable_data{};
|
|
D3D12_RANGE range;
|
|
range.Begin = 0;
|
|
range.End = 0;
|
|
|
|
result = p_allocation->GetResource()->Map(0, &range, &p_begin_writable_data);
|
|
|
|
RMLUI_DX_VERIFY_MSG(result, "failed to ID3D12Resource::Map");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
p_allocation->SetName(debug_name.c_str());
|
|
#endif
|
|
|
|
m_buffers.push_back({p_allocation, p_begin_writable_data});
|
|
|
|
D3D12MA::VIRTUAL_BLOCK_DESC desc_virtual = {};
|
|
desc_virtual.Size = size;
|
|
|
|
D3D12MA::VirtualBlock* p_block{};
|
|
result = D3D12MA::CreateVirtualBlock(&desc_virtual, &p_block);
|
|
|
|
RMLUI_DX_VERIFY_MSG(result, "failed to D3D12MA::CreateVirtualBlock");
|
|
|
|
m_virtual_buffers.push_back(p_block);
|
|
}
|
|
|
|
D3D12MA::VirtualBlock* RenderInterface_DX12::BufferMemoryManager::Get_AvailableBlock(size_t size_for_allocation, int* result_index)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Get_AvailableBlock");
|
|
RMLUI_ASSERTMSG(result_index, "must be valid part of memory!");
|
|
|
|
D3D12MA::VirtualBlock* p_result{};
|
|
|
|
int index{};
|
|
for (auto* p_block : m_virtual_buffers)
|
|
{
|
|
if (p_block)
|
|
{
|
|
D3D12MA::Statistics stats;
|
|
p_block->GetStatistics(&stats);
|
|
|
|
if ((stats.BlockBytes - stats.AllocationBytes) >= size_for_allocation)
|
|
{
|
|
p_result = p_block;
|
|
*result_index = index;
|
|
break;
|
|
}
|
|
}
|
|
++index;
|
|
}
|
|
|
|
return p_result;
|
|
}
|
|
|
|
D3D12MA::VirtualBlock* RenderInterface_DX12::BufferMemoryManager::Get_NotOutOfMemoryAndAvailableBlock(size_t size_for_allocation, int* result_index)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Get_NotOutOfMemoryAndAvailableBlock");
|
|
RMLUI_ASSERTMSG(result_index, "must be valid part of memory!");
|
|
RMLUI_ASSERTMSG(*result_index != -1,
|
|
"use this method when you found of available block then tried to allocate from it but got out of memory status!");
|
|
|
|
D3D12MA::VirtualBlock* p_result{};
|
|
|
|
// we skip out of memory block since it shows to us as available
|
|
auto from = *result_index + 1;
|
|
|
|
for (int i = from; i < m_virtual_buffers.size(); ++i)
|
|
{
|
|
auto* p_block = m_virtual_buffers.at(i);
|
|
if (p_block)
|
|
{
|
|
D3D12MA::Statistics stats;
|
|
p_block->GetStatistics(&stats);
|
|
|
|
if ((stats.BlockBytes - stats.AllocationBytes) >= size_for_allocation)
|
|
{
|
|
p_result = p_block;
|
|
*result_index = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return p_result;
|
|
}
|
|
|
|
int RenderInterface_DX12::BufferMemoryManager::Alloc(GraphicsAllocationInfo& info, size_t size, size_t alignment)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::Alloc");
|
|
RMLUI_ASSERTMSG(!m_buffers.empty(), "you forgot to allocate buffer on initialize stage of this manager!");
|
|
|
|
// we don't want to use any recursions because it is slow af
|
|
constexpr int kHowManyRequestsWeCanDoForResolvingOutOfMemory = 15;
|
|
int result_index{-1};
|
|
|
|
if (alignment > 0)
|
|
size = AlignUp(size, alignment);
|
|
|
|
auto* p_block = Get_AvailableBlock(size, &result_index);
|
|
|
|
if (p_block)
|
|
{
|
|
D3D12MA::VIRTUAL_ALLOCATION_DESC desc_alloc = {};
|
|
desc_alloc.Size = size;
|
|
|
|
if (alignment % 2 == 0)
|
|
desc_alloc.Alignment = alignment;
|
|
|
|
D3D12MA::VirtualAllocation alloc;
|
|
UINT64 offset{};
|
|
|
|
auto status = p_block->Allocate(&desc_alloc, &alloc, &offset);
|
|
|
|
if (status == E_OUTOFMEMORY)
|
|
{
|
|
for (int i = 0; i < kHowManyRequestsWeCanDoForResolvingOutOfMemory; ++i)
|
|
{
|
|
p_block = Get_NotOutOfMemoryAndAvailableBlock(size, &result_index);
|
|
if (!p_block)
|
|
{
|
|
if (size > m_size_for_allocation_in_bytes)
|
|
{
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12] auto correction size for buffer from [%zu] to [%zu]",
|
|
m_size_for_allocation_in_bytes, size);
|
|
#endif
|
|
|
|
m_size_for_allocation_in_bytes = size;
|
|
}
|
|
|
|
Alloc_Buffer(m_size_for_allocation_in_bytes
|
|
#ifdef RMLUI_DX_DEBUG
|
|
,
|
|
std::wstring(L"buffer[") + std::to_wstring(m_buffers.size()) + L"]"
|
|
#endif
|
|
);
|
|
result_index = static_cast<int>(m_buffers.size() - 1);
|
|
}
|
|
|
|
p_block = m_virtual_buffers.at(result_index);
|
|
|
|
desc_alloc = {};
|
|
desc_alloc.Size = size;
|
|
if (alignment % 2 == 0)
|
|
desc_alloc.Alignment = alignment;
|
|
|
|
auto status_allocation = p_block->Allocate(&desc_alloc, &alloc, &offset);
|
|
if (status_allocation == E_OUTOFMEMORY)
|
|
{
|
|
continue;
|
|
}
|
|
else if (status_allocation == S_OK)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
RMLUI_ERRORMSG("Unknown allocation status");
|
|
}
|
|
}
|
|
|
|
RMLUI_ASSERTMSG(offset == UINT64_MAX,
|
|
"it was last greedy try for allocating, it is really hard case for handling (report and describe your case on github), try to "
|
|
"optimize your 'stuff' (very calmly saying) "
|
|
"by your own, it is only for really rare specials cases where user doesn't want to think but UI must survive no matter what");
|
|
}
|
|
|
|
info.size = size;
|
|
info.alloc_info = alloc;
|
|
info.offset = offset;
|
|
info.buffer_index = result_index;
|
|
}
|
|
else
|
|
{
|
|
if (size > m_size_for_allocation_in_bytes)
|
|
{
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12] auto correction size for buffer from [%zu] to [%zu]",
|
|
m_size_for_allocation_in_bytes, size);
|
|
#endif
|
|
|
|
m_size_for_allocation_in_bytes = size;
|
|
}
|
|
|
|
Alloc_Buffer(m_size_for_allocation_in_bytes
|
|
#ifdef RMLUI_DX_DEBUG
|
|
,
|
|
std::wstring(L"buffer[") + std::to_wstring(m_buffers.size()) + L"]"
|
|
#endif
|
|
);
|
|
|
|
result_index = -1;
|
|
p_block = Get_AvailableBlock(size, &result_index);
|
|
|
|
RMLUI_ASSERTMSG(p_block, "can't be because in previous line of code you added new allocated fresh buffer!");
|
|
|
|
if (p_block)
|
|
{
|
|
D3D12MA::VIRTUAL_ALLOCATION_DESC desc_alloc = {};
|
|
desc_alloc.Size = size;
|
|
|
|
if (alignment % 2 == 0)
|
|
desc_alloc.Alignment = alignment;
|
|
|
|
D3D12MA::VirtualAllocation alloc;
|
|
UINT64 offset{};
|
|
|
|
auto status = p_block->Allocate(&desc_alloc, &alloc, &offset);
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to Allocate");
|
|
|
|
info.size = size;
|
|
info.alloc_info = alloc;
|
|
info.offset = offset;
|
|
info.buffer_index = result_index;
|
|
}
|
|
}
|
|
|
|
TryToFreeAvailableBlock();
|
|
|
|
return result_index;
|
|
}
|
|
|
|
void RenderInterface_DX12::BufferMemoryManager::TryToFreeAvailableBlock()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - BufferMemoryManager::TryToFreeAvailableBlock");
|
|
Rml::Array<std::pair<Rml::Vector<D3D12MA::VirtualBlock*>::const_iterator, Rml::Vector<Rml::Pair<D3D12MA::Allocation*, void*>>::const_iterator>, 1>
|
|
max_for_free;
|
|
|
|
for (size_t i = 0; i < max_for_free.size(); ++i)
|
|
{
|
|
max_for_free[i].first = m_virtual_buffers.end();
|
|
max_for_free[i].second = m_buffers.end();
|
|
}
|
|
|
|
int total_count{};
|
|
int limit_for_break{static_cast<int>(max_for_free.size())};
|
|
int index{};
|
|
|
|
for (auto cur = m_virtual_buffers.begin(); cur != m_virtual_buffers.end(); ++cur)
|
|
{
|
|
if (total_count == limit_for_break)
|
|
break;
|
|
|
|
if (*cur)
|
|
{
|
|
auto* p_block = *cur;
|
|
D3D12MA::Statistics stats;
|
|
p_block->GetStatistics(&stats);
|
|
|
|
if (stats.AllocationCount == 0 && stats.BlockCount == 0)
|
|
{
|
|
auto ref_count = p_block->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
|
|
ref_count = m_buffers.at(index).first->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
|
|
m_buffers.at(index).second = nullptr;
|
|
|
|
max_for_free[total_count].first = cur;
|
|
max_for_free[total_count].second = m_buffers.begin() + index;
|
|
|
|
++total_count;
|
|
}
|
|
}
|
|
++index;
|
|
}
|
|
|
|
for (int i = 0; i < total_count; ++i)
|
|
{
|
|
auto& pair = max_for_free.at(i);
|
|
|
|
m_virtual_buffers.erase(pair.first);
|
|
m_buffers.erase(pair.second);
|
|
}
|
|
}
|
|
|
|
RenderInterface_DX12::TextureMemoryManager::TextureMemoryManager() :
|
|
m_size_for_placed_heap{}, m_size_limit_for_being_placed{}, m_size_srv_cbv_uav_descriptor{}, m_size_rtv_descriptor{}, m_size_dsv_descriptor{},
|
|
m_fence_value{}, m_p_allocator{}, m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav{}, m_p_device{}, m_p_copy_command_list{},
|
|
m_p_backend_command_list{}, m_p_command_allocator{}, m_p_descriptor_heap_srv{}, m_p_copy_queue{}, m_p_fence{}, m_p_fence_event{}, m_p_handle{},
|
|
m_p_renderer{}, m_p_virtual_block_for_render_target_heap_allocations{}, m_p_virtual_block_for_depth_stencil_heap_allocations{},
|
|
m_p_descriptor_heap_rtv{}, m_p_descriptor_heap_dsv(), m_p_upload_buffer()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Constructor");
|
|
}
|
|
|
|
RenderInterface_DX12::TextureMemoryManager::~TextureMemoryManager()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Destructor");
|
|
}
|
|
|
|
bool RenderInterface_DX12::TextureMemoryManager::Is_Initialized() const
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Is_Initialized");
|
|
return static_cast<bool>(m_p_device != nullptr);
|
|
}
|
|
|
|
void RenderInterface_DX12::TextureMemoryManager::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_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_ZoneScopedN("DirectX 12 - TextureMemoryManager::Initialize");
|
|
RMLUI_ASSERTMSG(p_allocator, "you must pass a valid allocator pointer");
|
|
RMLUI_ASSERTMSG(size_for_placed_heap > 0, "there's no point in creating in such small heap");
|
|
RMLUI_ASSERTMSG(size_for_placed_heap != size_t(-1), "invalid value!");
|
|
RMLUI_ASSERTMSG(p_device, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_copy_command_list, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_backend_command_list, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_allocator_command, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_descriptor_heap_srv, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_copy_queue, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_handle, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_renderer, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_offset_allocator_for_descriptor_heap_srv_cbv_uav, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_descriptor_heap_rtv, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_descriptor_heap_dsv, "must be valid!");
|
|
|
|
m_p_device = p_device;
|
|
m_p_allocator = p_allocator;
|
|
m_p_copy_command_list = p_copy_command_list;
|
|
m_p_backend_command_list = p_backend_command_list;
|
|
m_p_command_allocator = p_allocator_command;
|
|
m_size_for_placed_heap = size_for_placed_heap;
|
|
m_p_descriptor_heap_srv = p_descriptor_heap_srv;
|
|
m_p_descriptor_heap_rtv = p_descriptor_heap_rtv;
|
|
m_p_descriptor_heap_dsv = p_descriptor_heap_dsv;
|
|
m_p_copy_queue = p_copy_queue;
|
|
m_p_renderer = p_renderer;
|
|
m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav = p_offset_allocator_for_descriptor_heap_srv_cbv_uav;
|
|
|
|
// if I have 4 MB then 1 MB is optimal as a maximum size for determing that resource can be allocated as placed resource so we just take 25% from
|
|
// size_for_placed_heap value
|
|
m_size_limit_for_being_placed = size_t((double(size_for_placed_heap) / 100.0) * 25.0);
|
|
|
|
if (m_p_device)
|
|
{
|
|
m_size_srv_cbv_uav_descriptor = m_p_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
|
|
|
m_size_rtv_descriptor = m_p_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
|
m_size_dsv_descriptor = m_p_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
|
}
|
|
|
|
m_p_handle = p_handle;
|
|
|
|
RMLUI_ASSERTMSG(m_size_srv_cbv_uav_descriptor > 0, "must be positive");
|
|
RMLUI_ASSERTMSG(m_size_rtv_descriptor > 0, "must be positive");
|
|
|
|
RMLUI_ASSERTMSG(m_size_limit_for_being_placed > 0 && m_size_limit_for_being_placed != size_t(-1), "something is wrong!");
|
|
|
|
if (m_p_device)
|
|
{
|
|
RMLUI_DX_VERIFY_MSG(m_p_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_p_fence)), "failed to create fence for upload queue");
|
|
|
|
m_p_fence_event = CreateEvent(NULL, FALSE, FALSE, TEXT("Event for copy queue fence"));
|
|
}
|
|
|
|
if (m_p_descriptor_heap_rtv)
|
|
{
|
|
D3D12MA::VIRTUAL_BLOCK_DESC desc_block{};
|
|
desc_block.Size = m_size_rtv_descriptor * RMLUI_RENDER_BACKEND_FIELD_DESCRIPTOR_HEAP_RTV;
|
|
|
|
auto status = D3D12MA::CreateVirtualBlock(&desc_block, &m_p_virtual_block_for_render_target_heap_allocations);
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3D12MA::CreateVirtualBlock (for rtv descriptor heap, texture manager)");
|
|
}
|
|
|
|
if (m_p_descriptor_heap_dsv)
|
|
{
|
|
D3D12MA::VIRTUAL_BLOCK_DESC desc_block{};
|
|
desc_block.Size = m_size_dsv_descriptor * RMLUI_RENDER_BACKEND_FIELD_DESCRIPTOR_HEAP_DSV;
|
|
|
|
auto status = D3D12MA::CreateVirtualBlock(&desc_block, &m_p_virtual_block_for_depth_stencil_heap_allocations);
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3D12MA::CreateVirtualBlock (for dsv descriptor heap, texture manager)");
|
|
}
|
|
|
|
#if RMLUI_RENDER_BACKEND_FIELD_STAGING_BUFFER_CACHE_ENABLED == 1
|
|
if (m_p_allocator)
|
|
{
|
|
D3D12MA::Allocation* p_allocation = nullptr;
|
|
|
|
ID3D12Resource* p_upload_buffer{};
|
|
|
|
D3D12_RESOURCE_DESC buffer_desc;
|
|
|
|
buffer_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
buffer_desc.Alignment = 0;
|
|
buffer_desc.Width = RMLUI_RENDER_BACKEND_FIELD_STAGING_BUFFER_SIZE;
|
|
buffer_desc.Height = 1;
|
|
buffer_desc.DepthOrArraySize = 1;
|
|
buffer_desc.MipLevels = 1;
|
|
buffer_desc.Format = DXGI_FORMAT_UNKNOWN;
|
|
buffer_desc.SampleDesc.Count = 1;
|
|
buffer_desc.SampleDesc.Quality = 0;
|
|
buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
buffer_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
|
|
D3D12MA::ALLOCATION_DESC desc_alloc{};
|
|
desc_alloc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
|
|
|
|
auto status = m_p_allocator->CreateResource(&desc_alloc, &buffer_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, &p_allocation,
|
|
IID_PPV_ARGS(&p_upload_buffer));
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateResource (upload buffer for texture)");
|
|
|
|
m_p_upload_buffer = p_allocation;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void RenderInterface_DX12::TextureMemoryManager::Shutdown()
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Shutdown");
|
|
if (m_p_fence)
|
|
{
|
|
m_p_fence->Release();
|
|
m_p_fence = nullptr;
|
|
}
|
|
|
|
if (m_p_fence_event)
|
|
{
|
|
CloseHandle(m_p_fence_event);
|
|
m_p_fence_event = nullptr;
|
|
}
|
|
|
|
size_t index{};
|
|
for (auto* p_heap : m_heaps_placed)
|
|
{
|
|
p_heap->Release();
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_blocks.at(index)->Release();
|
|
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
++index;
|
|
}
|
|
|
|
if (m_p_virtual_block_for_render_target_heap_allocations)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_virtual_block_for_render_target_heap_allocations->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
if (m_p_virtual_block_for_depth_stencil_heap_allocations)
|
|
{
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_virtual_block_for_depth_stencil_heap_allocations->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak");
|
|
}
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12]: TextureMemoryManager -> total blocks in session were allocated = %zu",
|
|
m_blocks.size());
|
|
#endif
|
|
|
|
m_blocks.clear();
|
|
m_heaps_placed.clear();
|
|
|
|
#if RMLUI_RENDER_BACKEND_FIELD_STAGING_BUFFER_CACHE_ENABLED == 1
|
|
if (m_p_upload_buffer)
|
|
{
|
|
if (m_p_upload_buffer->GetResource())
|
|
{
|
|
m_p_upload_buffer->GetResource()->Release();
|
|
}
|
|
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = m_p_upload_buffer->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak!");
|
|
}
|
|
#endif
|
|
|
|
m_p_allocator = nullptr;
|
|
m_p_device = nullptr;
|
|
m_p_copy_command_list = nullptr;
|
|
m_p_backend_command_list = nullptr;
|
|
m_p_command_allocator = nullptr;
|
|
m_p_descriptor_heap_srv = nullptr;
|
|
m_p_copy_queue = nullptr;
|
|
m_p_handle = nullptr;
|
|
m_p_renderer = nullptr;
|
|
m_p_descriptor_heap_rtv = nullptr;
|
|
m_p_virtual_block_for_render_target_heap_allocations = nullptr;
|
|
m_p_virtual_block_for_depth_stencil_heap_allocations = nullptr;
|
|
}
|
|
|
|
ID3D12Resource* RenderInterface_DX12::TextureMemoryManager::Alloc_Texture(D3D12_RESOURCE_DESC& desc, TextureHandleType* p_impl,
|
|
const Rml::byte* p_data
|
|
#ifdef RMLUI_DX_DEBUG
|
|
,
|
|
const Rml::String& debug_name
|
|
#endif
|
|
)
|
|
{
|
|
#ifdef RMLUI_DX_DEBUG
|
|
(void)(debug_name);
|
|
#endif
|
|
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Alloc_Texture");
|
|
RMLUI_ASSERTMSG(desc.Dimension == D3D12_RESOURCE_DIMENSION::D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
|
"this manager doesn't support 1D or 3D textures. (why do we need to support it?)");
|
|
RMLUI_ASSERTMSG(desc.DepthOrArraySize <= 1, "we don't support a such sizes");
|
|
RMLUI_ASSERTMSG(desc.SampleDesc.Count == 1, "this manager not for allocating render targets or depth stencil!");
|
|
RMLUI_ASSERTMSG(desc.Width, "must specify value for width field");
|
|
RMLUI_ASSERTMSG(desc.Height, "must specify value for height field");
|
|
RMLUI_ASSERTMSG(p_impl, "must be valid!");
|
|
|
|
ID3D12Resource* p_result{};
|
|
|
|
// this size stands for real size of texture and how much it will occupy for allocated block, because if it is larger than 1 MB it is better to
|
|
// allocate as committed resource instead of using placed resource technique (by default we allocate block for 4MB because 1.0 MB textures can be
|
|
// occupied 4 times and smaller even more times, but it is not reasonable to use placed resources for >1MB textures)
|
|
auto base_memory_size_for_allocation_in_bytes = desc.Width * desc.Height * BytesPerPixel(desc.Format);
|
|
size_t total_memory_for_allocation = base_memory_size_for_allocation_in_bytes;
|
|
size_t mipmemory = base_memory_size_for_allocation_in_bytes;
|
|
for (int i = 2; i <= desc.MipLevels; ++i)
|
|
{
|
|
if (mipmemory <= 1)
|
|
{
|
|
break;
|
|
}
|
|
|
|
mipmemory /= 4;
|
|
total_memory_for_allocation += mipmemory;
|
|
}
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX-12] allocating texture with base memory[%zu] and total memory with mips levels[%zu]",
|
|
base_memory_size_for_allocation_in_bytes, total_memory_for_allocation);
|
|
#endif
|
|
|
|
// we need to pass full memory with mipmaps otherwise the DirectX API will validate it by its own. we must ensure what we do.
|
|
if (CanBePlacedResource(total_memory_for_allocation))
|
|
{
|
|
Alloc_As_Placed(base_memory_size_for_allocation_in_bytes, total_memory_for_allocation, desc, p_impl, p_data);
|
|
p_result = static_cast<ID3D12Resource*>(p_impl->Get_Resource());
|
|
}
|
|
else
|
|
{
|
|
Alloc_As_Committed(base_memory_size_for_allocation_in_bytes, total_memory_for_allocation, desc, p_impl, p_data);
|
|
p_result = static_cast<D3D12MA::Allocation*>(p_impl->Get_Resource())->GetResource();
|
|
}
|
|
|
|
return p_result;
|
|
}
|
|
|
|
ID3D12Resource* RenderInterface_DX12::TextureMemoryManager::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
|
|
)
|
|
{
|
|
#ifdef RMLUI_DX_DEBUG
|
|
(void)(debug_name);
|
|
#endif
|
|
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Alloc_Texture");
|
|
RMLUI_ASSERTMSG(desc.Dimension == D3D12_RESOURCE_DIMENSION::D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
|
"this manager doesn't support 1D or 3D textures. (why do we need to support it?)");
|
|
RMLUI_ASSERTMSG(desc.DepthOrArraySize <= 1, "we don't support a such sizes");
|
|
RMLUI_ASSERTMSG(desc.Width, "must specify value for width field");
|
|
RMLUI_ASSERTMSG(desc.Height, "must specify value for height field");
|
|
RMLUI_ASSERTMSG(p_impl, "must be valid!");
|
|
RMLUI_ASSERT(p_impl->Get_Texture() &&
|
|
"you must allocate Gfx::FramebufferData's field (texture) before calling this method! So you need to set your allocated pointer to "
|
|
"Set_Texture method, dude...");
|
|
|
|
ID3D12Resource* p_result{};
|
|
|
|
auto base_memory_size_for_allocation_in_bytes = desc.Width * desc.Height * BytesPerPixel(desc.Format);
|
|
size_t total_memory_for_allocation = base_memory_size_for_allocation_in_bytes;
|
|
size_t mipmemory = base_memory_size_for_allocation_in_bytes;
|
|
for (int i = 2; i <= desc.MipLevels; ++i)
|
|
{
|
|
if (mipmemory <= 1)
|
|
{
|
|
break;
|
|
}
|
|
|
|
mipmemory /= 4;
|
|
total_memory_for_allocation += mipmemory;
|
|
}
|
|
|
|
desc.Flags = flags;
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
bool is_rt = flags & D3D12_RESOURCE_FLAGS::D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
bool is_ds = flags & D3D12_RESOURCE_FLAGS::D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
|
|
|
RMLUI_ASSERTMSG(is_rt || is_ds, "must be allow for RT or DS otherwise you will get assert from DX12");
|
|
|
|
const char* type_of_flag_for_texture_debug_name{};
|
|
|
|
constexpr const char* hardcoded_name_render_target = "render target";
|
|
constexpr const char* hardcoded_name_depth_stencil = "depth-stencil";
|
|
constexpr const char* hardcoded_name_unknown = "unknown";
|
|
|
|
if (is_rt)
|
|
{
|
|
type_of_flag_for_texture_debug_name = hardcoded_name_render_target;
|
|
}
|
|
else if (is_ds)
|
|
{
|
|
type_of_flag_for_texture_debug_name = hardcoded_name_depth_stencil;
|
|
}
|
|
else
|
|
{
|
|
type_of_flag_for_texture_debug_name = hardcoded_name_unknown;
|
|
}
|
|
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG,
|
|
"[DirectX-12] allocating render2texture (%s) with base memory[%zu] and total memory with mips levels[%zu]",
|
|
type_of_flag_for_texture_debug_name, base_memory_size_for_allocation_in_bytes, total_memory_for_allocation);
|
|
#endif
|
|
|
|
Alloc_As_Committed(base_memory_size_for_allocation_in_bytes, total_memory_for_allocation, desc, initial_state, p_impl->Get_Texture(), p_impl);
|
|
|
|
p_result = static_cast<D3D12MA::Allocation*>(p_impl->Get_Texture()->Get_Resource())->GetResource();
|
|
|
|
// dx12 sdk was updated and if we don't do that operation we get a validation error see
|
|
// https://asawicki.info/news_1724_initializing_dx12_textures_after_allocation_and_aliasing direct quote: "If the metadata of such compression are
|
|
// uninitialized, it might have consequences more severe than observing random colors. It's actually an undefined behavior."
|
|
if (p_result)
|
|
{
|
|
bool is_render_target = flags & D3D12_RESOURCE_FLAGS::D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
|
|
RMLUI_ASSERTMSG(m_p_backend_command_list, "must be initialized");
|
|
RMLUI_ASSERTMSG(p_impl, "must be valid");
|
|
|
|
if (is_render_target)
|
|
{
|
|
constexpr FLOAT clear_color[] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
m_p_backend_command_list->ClearRenderTargetView(p_impl->Get_DescriptorResourceView(), clear_color, 0, nullptr);
|
|
}
|
|
}
|
|
|
|
return p_result;
|
|
}
|
|
|
|
void RenderInterface_DX12::TextureMemoryManager::Free_Texture(TextureHandleType* p_texture)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Free_Texture(TextureHandleType)");
|
|
RMLUI_ASSERTMSG(p_texture, "must be valid");
|
|
|
|
if (p_texture)
|
|
{
|
|
auto index = p_texture->Get_Info().buffer_index;
|
|
RMLUI_ASSERTMSG(p_texture->Get_Resource(), "must be valid! can't be! data is corrupted! or was already destroyed!");
|
|
|
|
if (index != -1)
|
|
{
|
|
m_blocks.at(index)->FreeAllocation(p_texture->Get_Info().alloc_info);
|
|
}
|
|
|
|
if (m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav)
|
|
{
|
|
m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav->free(p_texture->Get_Allocation_DescriptorHeap());
|
|
}
|
|
|
|
p_texture->Destroy();
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::TextureMemoryManager::Free_Texture(Gfx::FramebufferData* p_impl)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Free_Texture(FramebufferData)");
|
|
RMLUI_ASSERTMSG(p_impl, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_impl->Get_Texture(), "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_virtual_block_for_render_target_heap_allocations, "must be valid! early calling");
|
|
RMLUI_ASSERTMSG(m_p_virtual_block_for_depth_stencil_heap_allocations, "must be valid! early calling");
|
|
|
|
if (p_impl)
|
|
{
|
|
Free_Texture(p_impl->Get_Texture(), p_impl->Is_RenderTarget(), *(p_impl->Get_VirtualAllocation_Descriptor()));
|
|
|
|
delete p_impl->Get_Texture();
|
|
p_impl->Set_Texture(nullptr);
|
|
|
|
p_impl->Set_DescriptorResourceView({});
|
|
p_impl->Set_ID(-1);
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::TextureMemoryManager::Free_Texture(TextureHandleType* p_texture, bool is_rt, D3D12MA::VirtualAllocation& allocation)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Free_Texture(TextureHandleType,bool,D3D12MA::VirtualAllocation)");
|
|
RMLUI_ASSERTMSG(p_texture, "you must pass a valid pointer!");
|
|
|
|
Free_Texture(p_texture);
|
|
|
|
if (is_rt)
|
|
{
|
|
if (m_p_virtual_block_for_render_target_heap_allocations)
|
|
{
|
|
m_p_virtual_block_for_render_target_heap_allocations->FreeAllocation(allocation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_p_virtual_block_for_depth_stencil_heap_allocations)
|
|
{
|
|
m_p_virtual_block_for_depth_stencil_heap_allocations->FreeAllocation(allocation);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool RenderInterface_DX12::TextureMemoryManager::CanAllocate(size_t total_memory_for_allocation, D3D12MA::VirtualBlock* p_block)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::CanAllocate(size_t, D3D12MA::VirtualBlock)");
|
|
RMLUI_ASSERTMSG(total_memory_for_allocation > 0 && total_memory_for_allocation != size_t(-1), "must be a valid number!");
|
|
|
|
RMLUI_ASSERTMSG(p_block, "must be valid virtual block");
|
|
|
|
bool result{};
|
|
|
|
if (p_block)
|
|
{
|
|
D3D12MA::Statistics stats;
|
|
p_block->GetStatistics(&stats);
|
|
|
|
result = (stats.BlockBytes - stats.AllocationBytes) >= total_memory_for_allocation;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool RenderInterface_DX12::TextureMemoryManager::CanBePlacedResource(size_t total_memory_for_allocation)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::CanBePlacedResource");
|
|
RMLUI_ASSERTMSG(total_memory_for_allocation > 0 && total_memory_for_allocation != size_t(-1), "must be a valid number!");
|
|
|
|
bool result{};
|
|
|
|
if (total_memory_for_allocation <= m_size_limit_for_being_placed)
|
|
result = true;
|
|
|
|
return result;
|
|
}
|
|
|
|
bool RenderInterface_DX12::TextureMemoryManager::CanBeSmallResource(size_t base_memory)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::CanBeSmallResource");
|
|
RMLUI_ASSERTMSG(base_memory > 0, "must be greater than zero!");
|
|
RMLUI_ASSERTMSG(base_memory != size_t(-1), "must be a valid number!");
|
|
|
|
bool result{};
|
|
|
|
constexpr size_t _kNonMSAASmallResourceMemoryLimit = 128 * 128 * 4;
|
|
|
|
// if this is not MSAA texture (because for now we didn't implement a such support)
|
|
if (base_memory <= _kNonMSAASmallResourceMemoryLimit)
|
|
result = true;
|
|
|
|
return result;
|
|
}
|
|
|
|
D3D12MA::VirtualBlock* RenderInterface_DX12::TextureMemoryManager::Get_AvailableBlock(size_t total_memory_for_allocation, int* result_index)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Get_AvailableBlock");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid!");
|
|
RMLUI_ASSERTMSG(result_index, "must be valid!");
|
|
RMLUI_ASSERTMSG(total_memory_for_allocation <= m_size_limit_for_being_placed, "you can't pass a such size here!");
|
|
RMLUI_ASSERTMSG(m_size_limit_for_being_placed < m_size_for_placed_heap, "something is wrong and you initialized your manager wrong!!!!");
|
|
|
|
D3D12MA::VirtualBlock* p_result{};
|
|
|
|
if (m_blocks.empty())
|
|
{
|
|
RMLUI_ASSERTMSG(m_heaps_placed.empty(), "if blocks are empty heaps must be too!");
|
|
|
|
auto pair = Create_HeapPlaced(m_size_for_placed_heap);
|
|
|
|
p_result = pair.second;
|
|
*result_index = 0;
|
|
}
|
|
else
|
|
{
|
|
int index{};
|
|
for (auto* p_block : m_blocks)
|
|
{
|
|
if (p_block)
|
|
{
|
|
if (CanAllocate(total_memory_for_allocation, p_block))
|
|
{
|
|
p_result = p_block;
|
|
*result_index = index;
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (index >= m_blocks.size() - 1)
|
|
{
|
|
auto pair = Create_HeapPlaced(m_size_for_placed_heap);
|
|
++index;
|
|
*result_index = index;
|
|
p_result = pair.second;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
++index;
|
|
}
|
|
}
|
|
|
|
return p_result;
|
|
}
|
|
|
|
void RenderInterface_DX12::TextureMemoryManager::Alloc_As_Committed(RMLUI_ATTR_ASSERT_VARIABLE size_t base_memory,
|
|
RMLUI_ATTR_ASSERT_VARIABLE size_t total_memory, D3D12_RESOURCE_DESC& desc, TextureHandleType* p_impl, const Rml::byte* p_data)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Alloc_As_Committed");
|
|
RMLUI_ASSERTMSG(base_memory > 0, "must be greater than zero!");
|
|
RMLUI_ASSERTMSG(total_memory > 0, "must be greater than zero!");
|
|
RMLUI_ASSERTMSG(base_memory != size_t(-1), "must be valid number!");
|
|
RMLUI_ASSERTMSG(total_memory != size_t(-1), "must be valid number!");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_impl, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_command_allocator, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_copy_command_list, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_allocator, "allocator must be valid!");
|
|
|
|
if (m_p_allocator)
|
|
{
|
|
D3D12MA::ALLOCATION_DESC desc_allocation = {};
|
|
desc_allocation.HeapType = D3D12_HEAP_TYPE_DEFAULT;
|
|
|
|
ID3D12Resource* p_resource{};
|
|
D3D12MA::Allocation* p_allocation{};
|
|
auto status =
|
|
m_p_allocator->CreateResource(&desc_allocation, &desc, D3D12_RESOURCE_STATE_COMMON, nullptr, &p_allocation, IID_PPV_ARGS(&p_resource));
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateResource (D3D12MA)");
|
|
|
|
if (p_impl)
|
|
{
|
|
p_impl->Set_Resource(p_allocation);
|
|
}
|
|
|
|
if (m_p_command_allocator)
|
|
{
|
|
auto status_reset = m_p_command_allocator->Reset();
|
|
RMLUI_DX_VERIFY_MSG(status_reset, "failed to Reset (command allocator)");
|
|
}
|
|
|
|
if (m_p_copy_command_list)
|
|
{
|
|
auto status_reset = m_p_copy_command_list->Reset(m_p_command_allocator, nullptr);
|
|
RMLUI_DX_VERIFY_MSG(status_reset, "failed to Reset (command list)");
|
|
}
|
|
|
|
Upload(true, p_impl, desc, p_data, p_resource);
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::TextureMemoryManager::Alloc_As_Committed(RMLUI_ATTR_ASSERT_VARIABLE size_t base_memory,
|
|
RMLUI_ATTR_ASSERT_VARIABLE size_t total_memory, D3D12_RESOURCE_DESC& desc, D3D12_RESOURCE_STATES initial_state, TextureHandleType* p_texture,
|
|
Gfx::FramebufferData* p_impl)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Alloc_As_Committed");
|
|
RMLUI_ASSERTMSG(base_memory > 0, "must be greater than zero!");
|
|
RMLUI_ASSERTMSG(total_memory > 0, "must be greater than zero!");
|
|
RMLUI_ASSERTMSG(base_memory != size_t(-1), "must be valid number!");
|
|
RMLUI_ASSERTMSG(total_memory != size_t(-1), "must be valid number!");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_impl, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_command_allocator, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_copy_command_list, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_allocator, "allocator must be valid!");
|
|
RMLUI_ASSERTMSG(p_texture, "must be valid!");
|
|
|
|
if (m_p_allocator)
|
|
{
|
|
D3D12MA::ALLOCATION_DESC desc_allocation = {};
|
|
desc_allocation.HeapType = D3D12_HEAP_TYPE_DEFAULT;
|
|
|
|
D3D12_CLEAR_VALUE optimized_clear_value = {};
|
|
|
|
if (p_impl->Is_RenderTarget())
|
|
{
|
|
optimized_clear_value.Format = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
|
|
optimized_clear_value.Color[0] = 0.0f;
|
|
optimized_clear_value.Color[1] = 0.0f;
|
|
optimized_clear_value.Color[2] = 0.0f;
|
|
optimized_clear_value.Color[3] = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
optimized_clear_value.Format = RMLUI_RENDER_BACKEND_FIELD_DEPTHSTENCIL_TEXTURE_FORMAT;
|
|
optimized_clear_value.DepthStencil.Depth = RMLUI_RENDER_BACKEND_FIELD_CLEAR_VALUE_DEPTHSTENCIL_DEPTH_VALUE;
|
|
optimized_clear_value.DepthStencil.Stencil = RMLUI_RENDER_BACKEND_FIELD_CLEAR_VALUE_DEPTHSTENCIL_STENCIL_VALUE;
|
|
}
|
|
|
|
ID3D12Resource* p_resource{};
|
|
D3D12MA::Allocation* p_allocation{};
|
|
auto status =
|
|
m_p_allocator->CreateResource(&desc_allocation, &desc, initial_state, &optimized_clear_value, &p_allocation, IID_PPV_ARGS(&p_resource));
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateResource (D3D12MA) (RenderTargetTexture)");
|
|
|
|
if (p_texture)
|
|
{
|
|
p_texture->Set_Resource(p_allocation);
|
|
}
|
|
|
|
D3D12_SHADER_RESOURCE_VIEW_DESC desc_srv{};
|
|
desc_srv.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
|
|
|
bool is_rt = desc.Flags & D3D12_RESOURCE_FLAGS::D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
bool is_ds = desc.Flags & D3D12_RESOURCE_FLAGS::D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
|
|
|
if (is_rt)
|
|
desc_srv.Format = desc.Format;
|
|
else if (is_ds)
|
|
desc_srv.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
|
|
|
|
if (desc.SampleDesc.Count > 1)
|
|
{
|
|
desc_srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
|
|
}
|
|
else
|
|
{
|
|
desc_srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
|
}
|
|
|
|
desc_srv.Texture2D.MipLevels = desc.MipLevels;
|
|
|
|
RMLUI_ASSERTMSG((is_rt || is_ds), "this method for dsv or rtv resources");
|
|
|
|
auto descriptor_allocation =
|
|
m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav->allocate(static_cast<OffsetAllocator::uint32>(m_size_srv_cbv_uav_descriptor));
|
|
|
|
auto offset_pointer = SIZE_T(INT64(m_p_handle->ptr)) + INT64(descriptor_allocation.offset);
|
|
D3D12_CPU_DESCRIPTOR_HANDLE cast_offset_pointer;
|
|
cast_offset_pointer.ptr = offset_pointer;
|
|
|
|
m_p_device->CreateShaderResourceView(p_resource, &desc_srv, cast_offset_pointer);
|
|
p_texture->Set_Allocation_DescriptorHeap(descriptor_allocation);
|
|
|
|
if (is_rt)
|
|
p_impl->Set_DescriptorResourceView(Alloc_RenderTargetResourceView(p_resource, p_impl->Get_VirtualAllocation_Descriptor()));
|
|
else if (is_ds)
|
|
p_impl->Set_DescriptorResourceView(Alloc_DepthStencilResourceView(p_resource, p_impl->Get_VirtualAllocation_Descriptor()));
|
|
}
|
|
}
|
|
|
|
void RenderInterface_DX12::TextureMemoryManager::Alloc_As_Placed(size_t base_memory, RMLUI_ATTR_ASSERT_VARIABLE size_t total_memory,
|
|
D3D12_RESOURCE_DESC& desc, TextureHandleType* p_impl, const Rml::byte* p_data)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Alloc_As_Placed");
|
|
RMLUI_ASSERTMSG(base_memory > 0, "must be greater than zero!");
|
|
RMLUI_ASSERTMSG(total_memory > 0, "must be greater than zero!");
|
|
RMLUI_ASSERTMSG(base_memory != size_t(-1), "must be valid number!");
|
|
RMLUI_ASSERTMSG(total_memory != size_t(-1), "must be valid number!");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_impl, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_command_allocator, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_copy_command_list, "must be valid!");
|
|
|
|
D3D12_RESOURCE_ALLOCATION_INFO info_for_alloc{};
|
|
|
|
if (CanBeSmallResource(base_memory))
|
|
{
|
|
desc.Alignment = D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT;
|
|
info_for_alloc = m_p_device->GetResourceAllocationInfo(0, 1, &desc);
|
|
|
|
RMLUI_ASSERTMSG(info_for_alloc.Alignment == D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT, "wrong calculation! check CanBeSmallResource method!");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (total_memory != info_for_alloc.SizeInBytes)
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG,
|
|
"[DirectX-12]: WARNING! Probably not aligned size of texture for creation w=[%zu] h=[%d] size=[%zu] align_size=[%zu] since gpu "
|
|
"driver wants to have align data "
|
|
"for allocating you should keep resources dimensions to be multiple of two!",
|
|
desc.Width, desc.Height, total_memory, info_for_alloc.SizeInBytes);
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
desc.Alignment = 0;
|
|
info_for_alloc = m_p_device->GetResourceAllocationInfo(0, 1, &desc);
|
|
|
|
RMLUI_ASSERTMSG(info_for_alloc.Alignment != D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT, "wrong calculation! check CanBeSmallResource method!");
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
if (total_memory != info_for_alloc.SizeInBytes)
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG,
|
|
"[DirectX-12]: WARNING! Probably not aligned size of texture for creation w=[%zu] h=[%d] size=[%zu] align_size=[%zu] since gpu "
|
|
"driver wants to have align data "
|
|
"for allocating you should keep resources dimensions to be multiple of two!",
|
|
desc.Width, desc.Height, total_memory, info_for_alloc.SizeInBytes);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int heap_index{-1};
|
|
auto* p_block = Get_AvailableBlock(info_for_alloc.SizeInBytes, &heap_index);
|
|
|
|
RMLUI_ASSERTMSG(heap_index != -1, "something is wrong!");
|
|
RMLUI_ASSERTMSG(p_block, "something is wrong!");
|
|
|
|
auto* p_heap = m_heaps_placed.at(heap_index);
|
|
RMLUI_ASSERTMSG(p_heap, "something is wrong!");
|
|
|
|
D3D12_RESOURCE_BARRIER bar;
|
|
|
|
D3D12MA::VIRTUAL_ALLOCATION_DESC desc_alloc{};
|
|
desc_alloc.Size = info_for_alloc.SizeInBytes;
|
|
desc_alloc.Alignment = info_for_alloc.Alignment;
|
|
D3D12MA::VirtualAllocation alloc_virtual;
|
|
UINT64 offset{};
|
|
|
|
// wh1t3lord: yeah, we can get a situation of fast allocating things that like visual test sample where we can hold left button and just
|
|
// switch across all samples fast but we could defragment our block that formally the unused space is ENOUGH for allocation but for real there's
|
|
// no free block and D3D12MA doesn't provide a good way for resolving accurately using stats or something else, so if we receive from block that
|
|
// was found in Get_AvailableBlock still can return from ->Allocate E_OUTOFMEMORY and it means we need try to find another one until we tried all
|
|
// and if all failed we have to allocate new block sadly
|
|
auto status = p_block->Allocate(&desc_alloc, &alloc_virtual, &offset);
|
|
|
|
// found a block but need to resolve it
|
|
if (status == E_OUTOFMEMORY)
|
|
{
|
|
// let's find another block if it is available
|
|
|
|
D3D12MA::VirtualBlock* p_valid_block_obtained{};
|
|
heap_index = -1;
|
|
p_heap = nullptr;
|
|
for (int i = 0; i < m_blocks.size(); ++i)
|
|
{
|
|
D3D12MA::VirtualBlock* p_candidate_block = m_blocks[i];
|
|
|
|
RMLUI_ASSERTMSG(p_candidate_block, "probably we can't keep nullptr in valid container");
|
|
|
|
if (p_candidate_block != p_block)
|
|
{
|
|
if (CanAllocate(info_for_alloc.SizeInBytes, p_candidate_block))
|
|
{
|
|
status = p_candidate_block->Allocate(&desc_alloc, &alloc_virtual, &offset);
|
|
|
|
if (SUCCEEDED(status))
|
|
{
|
|
p_valid_block_obtained = p_candidate_block;
|
|
p_heap = m_heaps_placed[i];
|
|
heap_index = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!p_valid_block_obtained)
|
|
{
|
|
const auto& new_heap_and_block = Create_HeapPlaced(m_size_for_placed_heap);
|
|
RMLUI_ASSERTMSG(new_heap_and_block.second, "must be valid!");
|
|
RMLUI_ASSERTMSG(new_heap_and_block.first, "must be valid!");
|
|
|
|
if (new_heap_and_block.second)
|
|
{
|
|
status = new_heap_and_block.second->Allocate(&desc_alloc, &alloc_virtual, &offset);
|
|
RMLUI_DX_VERIFY_MSG(SUCCEEDED(status), "can't resolve allocation for resource, report to developers!");
|
|
|
|
p_heap = new_heap_and_block.first;
|
|
|
|
for (int i = 0; i < m_heaps_placed.size(); ++i)
|
|
{
|
|
if (m_heaps_placed[i] == p_heap)
|
|
{
|
|
heap_index = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "can't allocate virtual alloc!");
|
|
|
|
ID3D12Resource* p_resource{};
|
|
status = m_p_device->CreatePlacedResource(p_heap, offset, &desc, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&p_resource));
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreatePlacedResource!");
|
|
RMLUI_ASSERTMSG(p_resource, "must be valid pointer of ID3D12Resource*!");
|
|
|
|
if (p_impl)
|
|
{
|
|
GraphicsAllocationInfo info_graphics;
|
|
info_graphics.size = info_for_alloc.SizeInBytes;
|
|
info_graphics.buffer_index = heap_index;
|
|
info_graphics.offset = offset;
|
|
info_graphics.alloc_info = alloc_virtual;
|
|
|
|
p_impl->Set_Info(info_graphics);
|
|
p_impl->Set_Resource(p_resource);
|
|
}
|
|
|
|
bar.Flags = D3D12_RESOURCE_BARRIER_FLAGS::D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
bar.Type = D3D12_RESOURCE_BARRIER_TYPE::D3D12_RESOURCE_BARRIER_TYPE_ALIASING;
|
|
bar.Aliasing.pResourceBefore = nullptr;
|
|
bar.Aliasing.pResourceAfter = p_resource;
|
|
|
|
if (m_p_command_allocator)
|
|
{
|
|
auto status_reset = m_p_command_allocator->Reset();
|
|
RMLUI_DX_VERIFY_MSG(status_reset, "failed to Reset (command allocator)");
|
|
}
|
|
|
|
if (m_p_copy_command_list)
|
|
{
|
|
auto status_reset = m_p_copy_command_list->Reset(m_p_command_allocator, nullptr);
|
|
RMLUI_DX_VERIFY_MSG(status_reset, "failed to Reset (command list)");
|
|
|
|
m_p_copy_command_list->ResourceBarrier(1, &bar);
|
|
}
|
|
|
|
Upload(false, p_impl, desc, p_data, p_resource);
|
|
}
|
|
|
|
void RenderInterface_DX12::TextureMemoryManager::Upload(bool is_committed, TextureHandleType* p_texture_handle, const D3D12_RESOURCE_DESC& desc,
|
|
const Rml::byte* p_data, ID3D12Resource* p_resource)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Upload");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid!");
|
|
// RMLUI_ASSERTMSG(p_data, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_resource, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_descriptor_heap_srv, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_allocator, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_copy_command_list, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_handle, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_copy_queue, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_renderer, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav, "must be valid!");
|
|
RMLUI_ASSERTMSG(p_texture_handle, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_fence, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_fence_event, "must be valid!");
|
|
|
|
auto upload_size = GetRequiredIntermediateSize(p_resource, 0, 1);
|
|
|
|
D3D12MA::Allocation* p_allocation{};
|
|
|
|
HRESULT status = S_OK;
|
|
|
|
#if RMLUI_RENDER_BACKEND_FIELD_STAGING_BUFFER_CACHE_ENABLED == 1
|
|
RMLUI_ASSERTMSG(m_p_upload_buffer, "must be valid and initialized");
|
|
|
|
p_allocation = m_p_upload_buffer;
|
|
|
|
bool was_allocated_temp = false;
|
|
|
|
RMLUI_ASSERTMSG(m_p_upload_buffer->GetResource(), "must be initialized");
|
|
if (p_allocation->GetResource())
|
|
{
|
|
if (p_allocation->GetResource()->GetDesc().Width < upload_size)
|
|
{
|
|
Rml::Log::Message(Rml::Log::Type::LT_WARNING,
|
|
"! [DirectX 12]: you are trying to upload huge texture = %zu bytes (%zu MB), so if you can't optimize its size for loading then "
|
|
"ignore "
|
|
"this "
|
|
"message, otherwise we "
|
|
"expect you to upload using staging buffer from UploadResourceManager instance",
|
|
upload_size, upload_size / (1024 * 1024));
|
|
|
|
p_allocation = nullptr;
|
|
|
|
ID3D12Resource* p_upload_buffer{};
|
|
|
|
D3D12_RESOURCE_DESC buffer_desc;
|
|
|
|
buffer_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
buffer_desc.Alignment = 0;
|
|
buffer_desc.Width = upload_size;
|
|
buffer_desc.Height = 1;
|
|
buffer_desc.DepthOrArraySize = 1;
|
|
buffer_desc.MipLevels = 1;
|
|
buffer_desc.Format = DXGI_FORMAT_UNKNOWN;
|
|
buffer_desc.SampleDesc.Count = 1;
|
|
buffer_desc.SampleDesc.Quality = 0;
|
|
buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
buffer_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
|
|
D3D12MA::ALLOCATION_DESC desc_alloc{};
|
|
desc_alloc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
|
|
|
|
status = m_p_allocator->CreateResource(&desc_alloc, &buffer_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, &p_allocation,
|
|
IID_PPV_ARGS(&p_upload_buffer));
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateResource (upload buffer for texture)");
|
|
|
|
was_allocated_temp = true;
|
|
}
|
|
}
|
|
|
|
#else
|
|
ID3D12Resource* p_upload_buffer{};
|
|
|
|
D3D12_RESOURCE_DESC buffer_desc;
|
|
|
|
buffer_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
buffer_desc.Alignment = 0;
|
|
buffer_desc.Width = upload_size;
|
|
buffer_desc.Height = 1;
|
|
buffer_desc.DepthOrArraySize = 1;
|
|
buffer_desc.MipLevels = 1;
|
|
buffer_desc.Format = DXGI_FORMAT_UNKNOWN;
|
|
buffer_desc.SampleDesc.Count = 1;
|
|
buffer_desc.SampleDesc.Quality = 0;
|
|
buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
buffer_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
|
|
D3D12MA::ALLOCATION_DESC desc_alloc{};
|
|
desc_alloc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
|
|
|
|
status = m_p_allocator->CreateResource(&desc_alloc, &buffer_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, &p_allocation,
|
|
IID_PPV_ARGS(&p_upload_buffer));
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateResource (upload buffer for texture)");
|
|
#endif
|
|
|
|
D3D12_SUBRESOURCE_DATA desc_data{};
|
|
desc_data.pData = p_data;
|
|
desc_data.RowPitch = desc.Width * BytesPerPixel(desc.Format);
|
|
desc_data.SlicePitch = desc_data.RowPitch * desc.Height;
|
|
|
|
auto allocated_size = UpdateSubresources<1>(m_p_copy_command_list, p_resource, p_allocation->GetResource(), 0, 0, 1, &desc_data);
|
|
|
|
#ifdef RMLUI_DX_DEBUG
|
|
constexpr const char* p_committed = "committed";
|
|
constexpr const char* p_placed = "placed";
|
|
|
|
const char* p_current_resource_type_name{};
|
|
|
|
if (is_committed)
|
|
p_current_resource_type_name = p_committed;
|
|
else
|
|
p_current_resource_type_name = p_placed;
|
|
|
|
Rml::Log::Message(Rml::Log::Type::LT_DEBUG, "[DirectX 12] allocated %s resource to GPU with size: [%zu]", p_current_resource_type_name,
|
|
allocated_size);
|
|
#else
|
|
(void)is_committed;
|
|
(void)allocated_size;
|
|
#endif
|
|
|
|
D3D12_SHADER_RESOURCE_VIEW_DESC desc_srv{};
|
|
desc_srv.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
|
desc_srv.Format = desc.Format;
|
|
desc_srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
|
desc_srv.Texture2D.MipLevels = desc.MipLevels;
|
|
|
|
auto descriptor_allocation =
|
|
m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav->allocate(static_cast<OffsetAllocator::uint32>(m_size_srv_cbv_uav_descriptor));
|
|
|
|
auto offset_pointer = SIZE_T(INT64(m_p_handle->ptr) + INT64(descriptor_allocation.offset));
|
|
D3D12_CPU_DESCRIPTOR_HANDLE cast_offset_pointer;
|
|
cast_offset_pointer.ptr = offset_pointer;
|
|
|
|
m_p_device->CreateShaderResourceView(p_resource, &desc_srv, cast_offset_pointer);
|
|
p_texture_handle->Set_Allocation_DescriptorHeap(descriptor_allocation);
|
|
|
|
status = m_p_copy_command_list->Close();
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to Close (command list for copy)");
|
|
|
|
ID3D12CommandList* p_lists[] = {m_p_copy_command_list};
|
|
|
|
m_p_copy_queue->ExecuteCommandLists(1, p_lists);
|
|
|
|
// wait queue for completion
|
|
if (m_p_device)
|
|
{
|
|
++m_fence_value;
|
|
|
|
RMLUI_DX_VERIFY_MSG(m_p_copy_queue->Signal(m_p_fence, m_fence_value), "failed to signal copy queue's fence");
|
|
|
|
if (m_p_fence->GetCompletedValue() < m_fence_value)
|
|
{
|
|
RMLUI_DX_VERIFY_MSG(m_p_fence->SetEventOnCompletion(m_fence_value, m_p_fence_event), "failed to SetEventOnCompletion");
|
|
|
|
WaitForSingleObjectEx(m_p_fence_event, INFINITE, FALSE);
|
|
}
|
|
}
|
|
|
|
#if RMLUI_RENDER_BACKEND_FIELD_STAGING_BUFFER_CACHE_ENABLED == 1
|
|
if (was_allocated_temp)
|
|
{
|
|
if (p_allocation)
|
|
{
|
|
if (p_allocation->GetResource())
|
|
{
|
|
p_allocation->GetResource()->Release();
|
|
}
|
|
|
|
RMLUI_ATTR_ASSERT_VARIABLE auto ref_count = p_allocation->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak!");
|
|
}
|
|
}
|
|
#else
|
|
if (p_allocation)
|
|
{
|
|
if (p_allocation->GetResource())
|
|
{
|
|
p_allocation->GetResource()->Release();
|
|
}
|
|
|
|
auto ref_count = p_allocation->Release();
|
|
RMLUI_ASSERTMSG(ref_count == 0, "leak!");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
size_t RenderInterface_DX12::TextureMemoryManager::BytesPerPixel(DXGI_FORMAT format)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::BytesPerPixel");
|
|
return BitsPerPixel(format) / static_cast<size_t>(8);
|
|
}
|
|
|
|
size_t RenderInterface_DX12::TextureMemoryManager::BitsPerPixel(DXGI_FORMAT format)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::BitsPerPixel");
|
|
switch (format)
|
|
{
|
|
case DXGI_FORMAT_R32G32B32A32_TYPELESS:
|
|
case DXGI_FORMAT_R32G32B32A32_FLOAT:
|
|
case DXGI_FORMAT_R32G32B32A32_UINT:
|
|
case DXGI_FORMAT_R32G32B32A32_SINT: return 128;
|
|
|
|
case DXGI_FORMAT_R32G32B32_TYPELESS:
|
|
case DXGI_FORMAT_R32G32B32_FLOAT:
|
|
case DXGI_FORMAT_R32G32B32_UINT:
|
|
case DXGI_FORMAT_R32G32B32_SINT: return 96;
|
|
|
|
case DXGI_FORMAT_R16G16B16A16_TYPELESS:
|
|
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
|
case DXGI_FORMAT_R16G16B16A16_UNORM:
|
|
case DXGI_FORMAT_R16G16B16A16_UINT:
|
|
case DXGI_FORMAT_R16G16B16A16_SNORM:
|
|
case DXGI_FORMAT_R16G16B16A16_SINT:
|
|
case DXGI_FORMAT_R32G32_TYPELESS:
|
|
case DXGI_FORMAT_R32G32_FLOAT:
|
|
case DXGI_FORMAT_R32G32_UINT:
|
|
case DXGI_FORMAT_R32G32_SINT:
|
|
case DXGI_FORMAT_R32G8X24_TYPELESS:
|
|
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
|
|
case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
|
|
case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
|
|
case DXGI_FORMAT_Y416:
|
|
case DXGI_FORMAT_Y210:
|
|
case DXGI_FORMAT_Y216: return 64;
|
|
|
|
case DXGI_FORMAT_R10G10B10A2_TYPELESS:
|
|
case DXGI_FORMAT_R10G10B10A2_UNORM:
|
|
case DXGI_FORMAT_R10G10B10A2_UINT:
|
|
case DXGI_FORMAT_R11G11B10_FLOAT:
|
|
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_R8G8B8A8_UINT:
|
|
case DXGI_FORMAT_R8G8B8A8_SNORM:
|
|
case DXGI_FORMAT_R8G8B8A8_SINT:
|
|
case DXGI_FORMAT_R16G16_TYPELESS:
|
|
case DXGI_FORMAT_R16G16_FLOAT:
|
|
case DXGI_FORMAT_R16G16_UNORM:
|
|
case DXGI_FORMAT_R16G16_UINT:
|
|
case DXGI_FORMAT_R16G16_SNORM:
|
|
case DXGI_FORMAT_R16G16_SINT:
|
|
case DXGI_FORMAT_R32_TYPELESS:
|
|
case DXGI_FORMAT_D32_FLOAT:
|
|
case DXGI_FORMAT_R32_FLOAT:
|
|
case DXGI_FORMAT_R32_UINT:
|
|
case DXGI_FORMAT_R32_SINT:
|
|
case DXGI_FORMAT_R24G8_TYPELESS:
|
|
case DXGI_FORMAT_D24_UNORM_S8_UINT:
|
|
case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
|
|
case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
|
|
case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
|
|
case DXGI_FORMAT_R8G8_B8G8_UNORM:
|
|
case DXGI_FORMAT_G8R8_G8B8_UNORM:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
|
case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
|
|
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
|
case DXGI_FORMAT_B8G8R8X8_TYPELESS:
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
|
|
case DXGI_FORMAT_AYUV:
|
|
case DXGI_FORMAT_Y410:
|
|
case DXGI_FORMAT_YUY2: return 32;
|
|
|
|
case DXGI_FORMAT_P010:
|
|
case DXGI_FORMAT_P016: return 24;
|
|
|
|
case DXGI_FORMAT_R8G8_TYPELESS:
|
|
case DXGI_FORMAT_R8G8_UNORM:
|
|
case DXGI_FORMAT_R8G8_UINT:
|
|
case DXGI_FORMAT_R8G8_SNORM:
|
|
case DXGI_FORMAT_R8G8_SINT:
|
|
case DXGI_FORMAT_R16_TYPELESS:
|
|
case DXGI_FORMAT_R16_FLOAT:
|
|
case DXGI_FORMAT_D16_UNORM:
|
|
case DXGI_FORMAT_R16_UNORM:
|
|
case DXGI_FORMAT_R16_UINT:
|
|
case DXGI_FORMAT_R16_SNORM:
|
|
case DXGI_FORMAT_R16_SINT:
|
|
case DXGI_FORMAT_B5G6R5_UNORM:
|
|
case DXGI_FORMAT_B5G5R5A1_UNORM:
|
|
case DXGI_FORMAT_A8P8:
|
|
case DXGI_FORMAT_B4G4R4A4_UNORM: return 16;
|
|
|
|
case DXGI_FORMAT_NV12:
|
|
case DXGI_FORMAT_420_OPAQUE:
|
|
case DXGI_FORMAT_NV11: return 12;
|
|
|
|
case DXGI_FORMAT_R8_TYPELESS:
|
|
case DXGI_FORMAT_R8_UNORM:
|
|
case DXGI_FORMAT_R8_UINT:
|
|
case DXGI_FORMAT_R8_SNORM:
|
|
case DXGI_FORMAT_R8_SINT:
|
|
case DXGI_FORMAT_A8_UNORM:
|
|
case DXGI_FORMAT_AI44:
|
|
case DXGI_FORMAT_IA44:
|
|
case DXGI_FORMAT_P8: return 8;
|
|
|
|
case DXGI_FORMAT_R1_UNORM: return 1;
|
|
|
|
case DXGI_FORMAT_BC1_TYPELESS:
|
|
case DXGI_FORMAT_BC1_UNORM:
|
|
case DXGI_FORMAT_BC1_UNORM_SRGB:
|
|
case DXGI_FORMAT_BC4_TYPELESS:
|
|
case DXGI_FORMAT_BC4_UNORM:
|
|
case DXGI_FORMAT_BC4_SNORM: return 4;
|
|
|
|
case DXGI_FORMAT_BC2_TYPELESS:
|
|
case DXGI_FORMAT_BC2_UNORM:
|
|
case DXGI_FORMAT_BC2_UNORM_SRGB:
|
|
case DXGI_FORMAT_BC3_TYPELESS:
|
|
case DXGI_FORMAT_BC3_UNORM:
|
|
case DXGI_FORMAT_BC3_UNORM_SRGB:
|
|
case DXGI_FORMAT_BC5_TYPELESS:
|
|
case DXGI_FORMAT_BC5_UNORM:
|
|
case DXGI_FORMAT_BC5_SNORM:
|
|
case DXGI_FORMAT_BC6H_TYPELESS:
|
|
case DXGI_FORMAT_BC6H_UF16:
|
|
case DXGI_FORMAT_BC6H_SF16:
|
|
case DXGI_FORMAT_BC7_TYPELESS:
|
|
case DXGI_FORMAT_BC7_UNORM:
|
|
case DXGI_FORMAT_BC7_UNORM_SRGB: return 8;
|
|
|
|
default:
|
|
{
|
|
RMLUI_ASSERT(!"failed to determine texture type that wasn't registered report to developers (https://github.com/mikke89/RmlUi/issues)");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
Rml::Pair<ID3D12Heap*, D3D12MA::VirtualBlock*> RenderInterface_DX12::TextureMemoryManager::Create_HeapPlaced(size_t size_for_creation)
|
|
{
|
|
(void)(size_for_creation);
|
|
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Create_HeapPlaced");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be valid!");
|
|
|
|
D3D12MA::VIRTUAL_BLOCK_DESC desc_block{};
|
|
|
|
desc_block.Size = m_size_for_placed_heap;
|
|
D3D12MA::VirtualBlock* p_block{};
|
|
auto status = D3D12MA::CreateVirtualBlock(&desc_block, &p_block);
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to D3D12MA::CreateVirtualBlock");
|
|
|
|
m_blocks.push_back(p_block);
|
|
|
|
D3D12_HEAP_DESC desc_heap;
|
|
desc_heap.Flags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
|
|
desc_heap.SizeInBytes = m_size_for_placed_heap;
|
|
desc_heap.Alignment = 0;
|
|
desc_heap.Properties.Type = D3D12_HEAP_TYPE::D3D12_HEAP_TYPE_DEFAULT;
|
|
desc_heap.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
desc_heap.Properties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
desc_heap.Properties.CreationNodeMask = 1;
|
|
desc_heap.Properties.VisibleNodeMask = 1;
|
|
|
|
ID3D12Heap* p_heap{};
|
|
status = m_p_device->CreateHeap(&desc_heap, IID_PPV_ARGS(&p_heap));
|
|
|
|
RMLUI_DX_VERIFY_MSG(status, "failed to CreateHeap!");
|
|
|
|
m_heaps_placed.push_back(p_heap);
|
|
|
|
return {p_heap, p_block};
|
|
}
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE RenderInterface_DX12::TextureMemoryManager::Alloc_DepthStencilResourceView(ID3D12Resource* p_resource,
|
|
D3D12MA::VirtualAllocation* p_alloc)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Alloc_DepthStecilResourceView");
|
|
RMLUI_ASSERTMSG(p_resource, "must be allocated!");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be allocated!");
|
|
RMLUI_ASSERTMSG(m_p_virtual_block_for_depth_stencil_heap_allocations, "must be initialized");
|
|
RMLUI_ASSERTMSG(p_alloc, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_descriptor_heap_dsv, "must be valid!");
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE calculated_offset{};
|
|
|
|
if (p_resource)
|
|
{
|
|
if (m_p_virtual_block_for_depth_stencil_heap_allocations)
|
|
{
|
|
if (m_p_device)
|
|
{
|
|
if (m_p_descriptor_heap_dsv)
|
|
{
|
|
D3D12MA::VIRTUAL_ALLOCATION_DESC desc_alloc = {};
|
|
desc_alloc.Size = m_size_dsv_descriptor;
|
|
UINT64 offset{};
|
|
|
|
auto status = m_p_virtual_block_for_depth_stencil_heap_allocations->Allocate(&desc_alloc, p_alloc, &offset);
|
|
|
|
RMLUI_DX_VERIFY_MSG(status,
|
|
"failed to allocate descriptor rtv, it means you need to resize and set higher size than previous, overflow (see "
|
|
"RMLUI_RENDER_BACKEND_FIELD_DESCRIPTOR_HEAP_RTV constant)");
|
|
|
|
D3D12_DEPTH_STENCIL_VIEW_DESC desc_rtv = {};
|
|
desc_rtv.Format = RMLUI_RENDER_BACKEND_FIELD_DEPTHSTENCIL_TEXTURE_FORMAT;
|
|
desc_rtv.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS;
|
|
|
|
calculated_offset.ptr = (m_p_descriptor_heap_dsv->GetCPUDescriptorHandleForHeapStart().ptr + offset);
|
|
|
|
m_p_device->CreateDepthStencilView(p_resource, &desc_rtv, calculated_offset);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return calculated_offset;
|
|
}
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE RenderInterface_DX12::TextureMemoryManager::Alloc_RenderTargetResourceView(ID3D12Resource* p_resource,
|
|
D3D12MA::VirtualAllocation* p_alloc)
|
|
{
|
|
RMLUI_ZoneScopedN("DirectX 12 - TextureMemoryManager::Alloc_RenderTargetResourceView");
|
|
RMLUI_ASSERTMSG(p_resource, "must be allocated!");
|
|
RMLUI_ASSERTMSG(m_p_device, "must be allocated!");
|
|
RMLUI_ASSERTMSG(m_p_virtual_block_for_render_target_heap_allocations, "must be initialized");
|
|
RMLUI_ASSERTMSG(p_alloc, "must be valid!");
|
|
RMLUI_ASSERTMSG(m_p_descriptor_heap_rtv, "must be valid!");
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE calculated_offset{};
|
|
|
|
if (p_resource)
|
|
{
|
|
if (m_p_virtual_block_for_render_target_heap_allocations)
|
|
{
|
|
if (m_p_device)
|
|
{
|
|
if (m_p_descriptor_heap_rtv)
|
|
{
|
|
D3D12MA::VIRTUAL_ALLOCATION_DESC desc_alloc = {};
|
|
desc_alloc.Size = m_size_rtv_descriptor;
|
|
UINT64 offset{};
|
|
|
|
auto status = m_p_virtual_block_for_render_target_heap_allocations->Allocate(&desc_alloc, p_alloc, &offset);
|
|
|
|
RMLUI_DX_VERIFY_MSG(status,
|
|
"failed to allocate descriptor rtv, it means you need to resize and set higher size than previous, overflow (see "
|
|
"RMLUI_RENDER_BACKEND_FIELD_DESCRIPTOR_HEAP_RTV constant)");
|
|
|
|
D3D12_RENDER_TARGET_VIEW_DESC desc_rtv = {};
|
|
desc_rtv.Format = RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT;
|
|
desc_rtv.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
|
|
|
|
calculated_offset.ptr = (m_p_descriptor_heap_rtv->GetCPUDescriptorHandleForHeapStart().ptr + offset);
|
|
|
|
m_p_device->CreateRenderTargetView(p_resource, &desc_rtv, calculated_offset);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return calculated_offset;
|
|
}
|
|
|
|
#if defined _MSC_VER
|
|
#pragma warning(push, 0)
|
|
#pragma warning(push, 4189)
|
|
#elif defined __clang__
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wall"
|
|
#pragma clang diagnostic ignored "-Wextra"
|
|
#pragma clang diagnostic ignored "-Wnullability-extension"
|
|
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
|
|
#pragma clang diagnostic ignored "-Wnullability-completeness"
|
|
#elif defined __GNUC__
|
|
#pragma GCC system_header
|
|
#endif
|
|
|
|
#include "RmlUi_DirectX/D3D12MemAlloc.cpp"
|
|
#include "RmlUi_DirectX/offsetAllocator.cpp"
|
|
|
|
#if defined _MSC_VER
|
|
#pragma warning(pop)
|
|
#elif defined __clang__
|
|
#pragma clang diagnostic pop
|
|
#endif
|