diff --git a/Juliet/Juliet.vcxproj b/Juliet/Juliet.vcxproj
index a7931b6..f3093a0 100644
--- a/Juliet/Juliet.vcxproj
+++ b/Juliet/Juliet.vcxproj
@@ -129,6 +129,7 @@
+
@@ -163,6 +164,7 @@
+
@@ -200,19 +202,20 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
@@ -277,8 +280,8 @@
-
-
+
+
diff --git a/Juliet/include/Core/Common/CoreUtils.h b/Juliet/include/Core/Common/CoreUtils.h
index 1c5f86e..a2afa97 100644
--- a/Juliet/include/Core/Common/CoreUtils.h
+++ b/Juliet/include/Core/Common/CoreUtils.h
@@ -73,31 +73,4 @@ namespace Juliet
}
extern JULIET_API void Free(ByteBuffer& buffer);
-
- // TODO move to math utils
- template
- constexpr Type Min(Type lhs, Type rhs)
- {
- return rhs < lhs ? rhs : lhs;
- }
-
- template
- constexpr Type Max(Type lhs, Type rhs)
- {
- return lhs < rhs ? rhs : lhs;
- }
-
- template
- constexpr Type Clamp(Type val, Type min, Type max)
- {
- if (val < min)
- {
- return min;
- }
- if (val > max)
- {
- return max;
- }
- return val;
- }
} // namespace Juliet
diff --git a/Juliet/include/Core/Common/String.h b/Juliet/include/Core/Common/String.h
index a2b8a29..7f6c039 100644
--- a/Juliet/include/Core/Common/String.h
+++ b/Juliet/include/Core/Common/String.h
@@ -1,6 +1,6 @@
#pragma once
-#include
+#include
#include
namespace Juliet
diff --git a/Juliet/include/Core/Math/MathUtils.h b/Juliet/include/Core/Math/MathUtils.h
new file mode 100644
index 0000000..426d145
--- /dev/null
+++ b/Juliet/include/Core/Math/MathUtils.h
@@ -0,0 +1,37 @@
+#pragma once
+
+namespace Juliet
+{
+ extern JULIET_API float RoundF(float value);
+
+ inline int32 LRoundF(float value)
+ {
+ return RoundF(value);
+ }
+
+ template
+ constexpr Type Min(Type lhs, Type rhs)
+ {
+ return rhs < lhs ? rhs : lhs;
+ }
+
+ template
+ constexpr Type Max(Type lhs, Type rhs)
+ {
+ return lhs < rhs ? rhs : lhs;
+ }
+
+ template
+ constexpr Type Clamp(Type val, Type min, Type max)
+ {
+ if (val < min)
+ {
+ return min;
+ }
+ if (val > max)
+ {
+ return max;
+ }
+ return val;
+ }
+} // namespace Juliet
diff --git a/Juliet/include/Graphics/Graphics.h b/Juliet/include/Graphics/Graphics.h
index 9d3e12d..1d519cf 100644
--- a/Juliet/include/Graphics/Graphics.h
+++ b/Juliet/include/Graphics/Graphics.h
@@ -115,7 +115,7 @@ namespace Juliet
extern JULIET_API void DestroyShader(NonNullPtr device, NonNullPtr shader);
// Pipelines
- extern JULIET_API GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr device,
- GraphicsPipelineCreateInfo& createInfo);
+ extern JULIET_API GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr device,
+ const GraphicsPipelineCreateInfo& createInfo);
} // namespace Juliet
diff --git a/Juliet/include/Graphics/GraphicsPipeline.h b/Juliet/include/Graphics/GraphicsPipeline.h
index 76d66d4..c192a32 100644
--- a/Juliet/include/Graphics/GraphicsPipeline.h
+++ b/Juliet/include/Graphics/GraphicsPipeline.h
@@ -1,5 +1,6 @@
#pragma once
#include
+#include
namespace Juliet
{
@@ -9,20 +10,23 @@ namespace Juliet
enum class FillMode : uint8
{
Wireframe,
- Solid
+ Solid,
+ Count
};
enum class CullMode : uint8
{
None,
Front,
- Back
+ Back,
+ Count
};
enum class FrontFace : uint8
{
CounterClockwise,
- Clockwise
+ Clockwise,
+ Count
};
enum class PrimitiveType : uint8
@@ -32,6 +36,7 @@ namespace Juliet
LineList,
LineStrip,
PointList,
+ Count
};
struct RasterizerState
@@ -39,21 +44,180 @@ namespace Juliet
FillMode FillMode;
CullMode CullMode;
FrontFace FrontFace;
+
+ float DepthBiasConstantFactor; // How much depth value is added to each fragment
+ float DepthBiasClamp; // Maximum depth bias
+ float DepthBiasSlopeFactor; // Scalar applied to Fragment's slope
+ bool EnableDepthBias; // Bias fragment depth values
+ bool EnableDepthClip; // True to clip, false to clamp
+ };
+
+ enum class VertexInputRate : uint8
+ {
+ Vertex, // Use vertex index
+ Instance, // Use instance index
+ Count
+ };
+
+ struct VertexBufferDescription
+ {
+ uint32 Slot; // Binding Slot
+ uint32 PitchInBytes; // Pitch between two elements
+ VertexInputRate InputRate;
+ uint32 InstanceStepRate; // Only used when input rate == Instance. Number of instances to draw before advancing in the instance buffer by 1
+ };
+
+ enum class VertexElementFormat : uint8
+ {
+ Invalid,
+
+ /* 32-bit Signed Integers */
+ Int,
+ Int2,
+ Int3,
+ Int4,
+
+ /* 32-bit Unsigned Integers */
+ UInt,
+ UInt2,
+ UInt3,
+ UInt4,
+
+ /* 32-bit Floats */
+ Float,
+ Float2,
+ Float3,
+ Float4,
+
+ /* 8-bit Signed Integers */
+ Byte2,
+ Byte4,
+
+ /* 8-bit Unsigned Integers */
+ UByte2,
+ UByte4,
+
+ /* 8-bit Signed Normalized */
+ Byte2_Norm,
+ Byte4_Norm,
+
+ /* 8-bit Unsigned Normalized */
+ UByte2_Norm,
+ UByte4_Norm,
+
+ /* 16-bit Signed Integers */
+ Short2,
+ Short4,
+
+ /* 16-bit Unsigned Integers */
+ UShort2,
+ UShort4,
+
+ /* 16-bit Signed Normalized */
+ Short2_Norm,
+ Short4_Norm,
+
+ /* 16-bit Unsigned Normalized */
+ UShort2_Norm,
+ UShort4_Norm,
+
+ /* 16-bit Floats */
+ Half2,
+ Half4,
+
+ //
+ Count
+ };
+
+ struct VertexAttribute
+ {
+ uint32 Location; // Shader input location index
+ uint32 BufferSlot; // Binding slot of associated vertex buffer
+ VertexElementFormat Format; // Size and type of attribute
+ uint32 Offset; // Offset of this attribute relative to the start of the vertex element
+ };
+
+ struct VertexInputState
+ {
+ const VertexBufferDescription* VertexBufferDescriptions;
+ uint32 NumVertexBufferDescriptions;
+ const VertexAttribute* VertexAttributes;
+ uint32 NumVertexAttributes;
};
struct GraphicsPipelineTargetInfo
{
const ColorTargetDescription* ColorTargetDescriptions;
size_t NumColorTargets;
+ TextureFormat DepthStencilFormat;
+ bool HasDepthStencilTarget;
+ };
+
+ enum class CompareOperation : uint8
+ {
+ Invalid,
+ Never, // The comparison always evaluates false.
+ Less, // The comparison evaluates reference < test.
+ Equal, // The comparison evaluates reference == test.
+ LessOrEqual, // The comparison evaluates reference <= test.
+ Greater, // The comparison evaluates reference > test.
+ NotEqual, // The comparison evaluates reference != test.
+ GreaterOrEqual, // The comparison evalutes reference >= test.
+ Always, // The comparison always evaluates true.
+ Count
+ };
+
+ enum class StencilOperation : uint8
+ {
+ Invalid,
+ Keep, // Keeps the current value.
+ Zero, // Sets the value to 0.
+ Replace, // Sets the value to reference.
+ IncrementAndClamp, // Increments the current value and clamps to the maximum value.
+ DecrementAndClamp, // Decrements the current value and clamps to 0.
+ Invert, // Bitwise-inverts the current value.
+ IncrementAndWrap, // Increments the current value and wraps back to 0.
+ DecrementAndWrap, // Decrements the current value and wraps to the maximum value.
+ Count
+ };
+
+ struct StencilOperationState
+ {
+ StencilOperation FailOperation; // The action performed on samples that fail the stencil test.
+ StencilOperation PassOperation; // The action performed on samples that pass the depth and stencil tests.
+ StencilOperation DepthFailOperation; // The action performed on samples that pass the stencil test and fail the depth test.
+ StencilOperation CompareOperation; // The comparison operator used in the stencil test.
+ };
+
+ struct DepthStencilState
+ {
+ CompareOperation CompareOperation; // The comparison operator used for depth testing.
+ StencilOperationState BackStencilState; // The stencil op state for back-facing triangles.
+ StencilOperationState FrontStencilState; // The stencil op state for front-facing triangles.
+ uint8 CompareMask; // Selects the bits of the stencil values participating in the stencil test.
+ uint8 WriteMask; // Selects the bits of the stencil values updated by the stencil test.
+ bool EnableDepthTest : 1; // true enables the depth test.
+ bool EnableDepthWrite : 1; // true enables depth writes. Depth writes are always disabled when enable_depth_test is false.
+ bool EnableStencilTest : 1; // true enables the stencil test.
+ };
+
+ struct MultisampleState
+ {
+ TextureSampleCount SampleCount;
+ uint32 SampleMask; // Which sample should be updated. If Enabled mask == false -> 0xFFFFFFFF
+ bool EnableMask;
};
struct GraphicsPipelineCreateInfo
{
Shader* VertexShader;
Shader* FragmentShader;
- RasterizerState RasterizerState;
PrimitiveType PrimitiveType;
GraphicsPipelineTargetInfo TargetInfo;
+ RasterizerState RasterizerState;
+ MultisampleState MultisampleState;
+ VertexInputState VertexInputState;
+ DepthStencilState DepthStencilState;
};
// Opaque type
diff --git a/Juliet/include/Graphics/RenderPass.h b/Juliet/include/Graphics/RenderPass.h
index b8de189..5f7b06f 100644
--- a/Juliet/include/Graphics/RenderPass.h
+++ b/Juliet/include/Graphics/RenderPass.h
@@ -41,14 +41,60 @@ namespace Juliet
StoreOperation StoreOperation;
};
+ enum class BlendFactor : uint8
+ {
+ Invalid,
+ Zero,
+ One,
+ Src_Color,
+ One_Minus_Src_Color,
+ Dst_Color,
+ One_Minus_Dst_Color,
+ Src_Alpha,
+ One_Minus_Src_Alpha,
+ Dst_Alpha,
+ One_Minus_Dst_Alpha,
+ Constant_Color,
+ One_MINUS_Constant_Color,
+ Src_Alpha_Saturate, // min(source alpha, 1 - destination alpha)
+ Count
+ };
+
+ enum class BlendOperation : uint8
+ {
+ Invalid,
+ Add, // (source * source_factor) + (destination * destination_factor)
+ Subtract, // (source * source_factor) - (destination * destination_factor)
+ ReverseSubtract, // (destination * destination_factor) - (source * source_factor)
+ Min, // min(source, destination)
+ Max, // max(source, destination)
+ Count
+ };
+
+ enum class ColorComponentFlags : uint8
+ {
+ R = 1u << 0,
+ G = 1u << 1,
+ B = 1u << 2,
+ A = 1u << 3
+ };
+
struct ColorTargetBlendState
{
-
+ BlendFactor SourceColorBlendFactor; // The value to be multiplied by the source RGB value.
+ BlendFactor DestinationColorBlendFactor; // The value to be multiplied by the destination RGB value.
+ BlendOperation ColorBlendOperation; // The blend operation for the RGB components.
+ BlendFactor SourceAlphaBlendFactor; // The value to be multiplied by the source alpha.
+ BlendFactor DestinationAlphaBlendFactor; // The value to be multiplied by the destination alpha.
+ BlendOperation AlphaBlendOperation; // The blend operation for the alpha component.
+ ColorComponentFlags ColorWriteMask; // A bitmask specifying which of the RGBA components are enabled for writing. Writes to all channels if enable_color_write_mask is false.
+ bool EnableBlend : 1; // Whether blending is enabled for the color target.
+ bool EnableColorWriteMask : 1; // Whether the color write mask is enabled.
};
struct ColorTargetDescription
{
- TextureFormat Format;
+ TextureFormat Format;
ColorTargetBlendState BlendState;
};
diff --git a/Juliet/include/Graphics/Texture.h b/Juliet/include/Graphics/Texture.h
index 0eb333e..3ff0206 100644
--- a/Juliet/include/Graphics/Texture.h
+++ b/Juliet/include/Graphics/Texture.h
@@ -124,7 +124,9 @@ namespace Juliet
ASTC_10x8_FLOAT,
ASTC_10x10_FLOAT,
ASTC_12x10_FLOAT,
- ASTC_12x12_FLOAT
+ ASTC_12x12_FLOAT,
+
+ Count
};
enum struct TextureUsageFlag : uint8
diff --git a/Juliet/src/Core/Math/MathRound.cpp b/Juliet/src/Core/Math/MathRound.cpp
new file mode 100644
index 0000000..9baf97d
--- /dev/null
+++ b/Juliet/src/Core/Math/MathRound.cpp
@@ -0,0 +1,63 @@
+#include
+
+#include
+
+namespace Juliet
+{
+ // From MUSL lib https://github.com/rofl0r/musl
+#if FLT_EVAL_METHOD == 0
+#define EPS FLT_EPSILON
+#elif FLT_EVAL_METHOD == 1
+#define EPS DBL_EPSILON
+#elif FLT_EVAL_METHOD == 2
+#define EPS LDBL_EPSILON
+#endif
+
+ namespace
+ {
+ const float_t toint = 1 / EPS;
+ }
+
+ float RoundF(float value)
+ {
+ union
+ {
+ float f;
+ uint32_t i;
+ } u = { value };
+ int e = u.i >> 23 & 0xff;
+ float_t y;
+
+ if (e >= 0x7f + 23)
+ {
+ return value;
+ }
+ if (u.i >> 31)
+ {
+ value = -value;
+ }
+ if (e < 0x7f - 1)
+ {
+ FORCE_EVAL(value + toint);
+ return 0 * u.f;
+ }
+ y = value + toint - toint - value;
+ if (y > 0.5f)
+ {
+ y = y + value - 1;
+ }
+ else if (y <= -0.5f)
+ {
+ y = y + value + 1;
+ }
+ else
+ {
+ y = y + value;
+ }
+ if (u.i >> 31)
+ {
+ y = -y;
+ }
+ return y;
+ }
+} // namespace Juliet
diff --git a/Juliet/src/Core/Math/Math_Private.h b/Juliet/src/Core/Math/Math_Private.h
new file mode 100644
index 0000000..713c746
--- /dev/null
+++ b/Juliet/src/Core/Math/Math_Private.h
@@ -0,0 +1,51 @@
+#pragma once
+
+namespace Juliet
+{
+// From MUSL lib https://github.com/rofl0r/musl
+#ifndef fp_force_evalf
+#define fp_force_evalf fp_force_evalf
+ static inline void fp_force_evalf(float x)
+ {
+ volatile float y;
+ y = x;
+ }
+#endif
+
+#ifndef fp_force_eval
+#define fp_force_eval fp_force_eval
+ static inline void fp_force_eval(double x)
+ {
+ volatile double y;
+ y = x;
+ }
+#endif
+
+#ifndef fp_force_evall
+#define fp_force_evall fp_force_evall
+ static inline void fp_force_evall(long double x)
+ {
+ volatile long double y;
+ y = x;
+ }
+#endif
+
+#define FORCE_EVAL(x) \
+ do \
+ { \
+ if (sizeof(x) == sizeof(float)) \
+ { \
+ fp_force_evalf(x); \
+ } \
+ else if (sizeof(x) == sizeof(double)) \
+ { \
+ fp_force_eval(x); \
+ } \
+ else \
+ { \
+ fp_force_evall(x); \
+ } \
+ } \
+ while (0)
+
+} // namespace Juliet
diff --git a/Juliet/src/Graphics/D3D12/D3D12CommandList.cpp b/Juliet/src/Graphics/D3D12/D3D12CommandList.cpp
index d546db8..9514fe2 100644
--- a/Juliet/src/Graphics/D3D12/D3D12CommandList.cpp
+++ b/Juliet/src/Graphics/D3D12/D3D12CommandList.cpp
@@ -329,7 +329,7 @@ namespace Juliet::D3D12
}
}
- // TODO Destroy anything (buffer, texture, etc...)
+ Internal::DisposePendingResourcces(d3d12Driver);
++d3d12Driver->FrameCounter;
diff --git a/Juliet/src/Graphics/D3D12/D3D12Common.h b/Juliet/src/Graphics/D3D12/D3D12Common.h
index 76afc6d..c6ef10e 100644
--- a/Juliet/src/Graphics/D3D12/D3D12Common.h
+++ b/Juliet/src/Graphics/D3D12/D3D12Common.h
@@ -10,6 +10,7 @@
// SRV = Shader Resource View
// UAV = Unordered Access View
// CBV = Constant Buffer View
+// PSO = Pipeline State Object
// Inspired (copy pasted a lot) by SDL GPU
namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp
index e448bdf..084a1a5 100644
--- a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp
+++ b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp
@@ -620,11 +620,32 @@ namespace Juliet::D3D12
device->Driver = driver;
driver->GraphicsDevice = device;
+ driver->Semantic = WrapString("TEXCOORD");
+
driver->FramesInFlight = 2;
return device;
}
} // namespace
+
+ namespace Internal
+ {
+ void DisposePendingResourcces(NonNullPtr driver)
+ {
+ // TODO Destroy anything (buffer, texture, etc...)
+ for (uint32 idx = driver->GraphicsPipelinesToDisposeCount - 1; idx >= 0ul; --idx)
+ {
+ if (--driver->GraphicsPipelinesToDispose[idx]->ReferenceCount == 0)
+ {
+ ReleaseGraphicsPipeline(driver->GraphicsPipelinesToDispose[idx]);
+
+ driver->GraphicsPipelinesToDispose[idx] =
+ driver->GraphicsPipelinesToDispose[driver->GraphicsPipelinesToDisposeCount - 1];
+ driver->GraphicsPipelinesToDisposeCount -= 1;
+ }
+ }
+ }
+ } // namespace Internal
} // namespace Juliet::D3D12
namespace Juliet
diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.h b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.h
index 776b0d8..c32534f 100644
--- a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.h
+++ b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.h
@@ -2,6 +2,7 @@
#include
#include
+#include
#include
#include
@@ -77,8 +78,14 @@ namespace Juliet::D3D12
uint32 AvailableFenceCount;
uint32 AvailableFenceCapacity;
+ D3D12GraphicsPipeline** GraphicsPipelinesToDispose;
+ uint32 GraphicsPipelinesToDisposeCount;
+ uint32 GraphicsPipelinesToDisposeCapacity;
+
D3D12StagingDescriptorPool* StagingDescriptorPools[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
+ String Semantic;
+
uint8 FramesInFlight;
uint64 FrameCounter = 0; // Number of frame since inception
@@ -87,4 +94,9 @@ namespace Juliet::D3D12
bool IsUMACacheCoherent : 1;
bool GPUUploadHeapSupported : 1;
};
+
+ namespace Internal
+ {
+ void DisposePendingResourcces(NonNullPtr driver);
+ }
} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.cpp b/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.cpp
index 267b3ba..9f7e1b2 100644
--- a/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.cpp
+++ b/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.cpp
@@ -1,14 +1,478 @@
#include
+#include
#include
+#include
#include
-#include
+#include
namespace Juliet::D3D12
{
- GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr driver, GraphicsPipelineCreateInfo& createInfo)
+ namespace
{
- return nullptr;
+ // clang-format off
+ D3D12_INPUT_CLASSIFICATION JulietToD3D12_InputRate[] =
+ {
+ D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, // VERTEX
+ D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA // INSTANCE
+ };
+ // clang-format on
+ static_assert(sizeof(JulietToD3D12_InputRate) / sizeof(JulietToD3D12_InputRate[0]) == ToUnderlying(VertexInputRate::Count));
+
+ // clang-format off
+ D3D12_CULL_MODE JulietToD3D12_CullMode[] =
+ {
+ D3D12_CULL_MODE_NONE,
+ D3D12_CULL_MODE_FRONT,
+ D3D12_CULL_MODE_BACK
+ };
+ // clang-format on
+ static_assert(sizeof(JulietToD3D12_CullMode) / sizeof(JulietToD3D12_CullMode[0]) == ToUnderlying(CullMode::Count));
+
+ // clang-format off
+ D3D12_FILL_MODE JulietToD3D12_FillMode[] =
+ {
+ D3D12_FILL_MODE_SOLID,
+ D3D12_FILL_MODE_WIREFRAME
+ };
+ // clang-format on
+ static_assert(sizeof(JulietToD3D12_FillMode) / sizeof(JulietToD3D12_FillMode[0]) == ToUnderlying(FillMode::Count));
+
+ DXGI_FORMAT JulietToD3D12_VertexFormat[] = {
+ DXGI_FORMAT_UNKNOWN, // Unknown
+ DXGI_FORMAT_R32_SINT, // Int
+ DXGI_FORMAT_R32G32_SINT, // Int2
+ DXGI_FORMAT_R32G32B32_SINT, // Int3
+ DXGI_FORMAT_R32G32B32A32_SINT, // Int4
+ DXGI_FORMAT_R32_UINT, // UInt
+ DXGI_FORMAT_R32G32_UINT, // UInt2
+ DXGI_FORMAT_R32G32B32_UINT, // UInt3
+ DXGI_FORMAT_R32G32B32A32_UINT, // UInt4
+ DXGI_FORMAT_R32_FLOAT, // Float
+ DXGI_FORMAT_R32G32_FLOAT, // Float2
+ DXGI_FORMAT_R32G32B32_FLOAT, // Float3
+ DXGI_FORMAT_R32G32B32A32_FLOAT, // Float4
+ DXGI_FORMAT_R8G8_SINT, // Byte2
+ DXGI_FORMAT_R8G8B8A8_SINT, // Byte4
+ DXGI_FORMAT_R8G8_UINT, // UByte2
+ DXGI_FORMAT_R8G8B8A8_UINT, // UByte4
+ DXGI_FORMAT_R8G8_SNORM, // Byte2_Norm
+ DXGI_FORMAT_R8G8B8A8_SNORM, // Byte4_Norm
+ DXGI_FORMAT_R8G8_UNORM, // UByte2_Norm
+ DXGI_FORMAT_R8G8B8A8_UNORM, // UByte4_Norm
+ DXGI_FORMAT_R16G16_SINT, // Short2
+ DXGI_FORMAT_R16G16B16A16_SINT, // Short4
+ DXGI_FORMAT_R16G16_UINT, // UShort2
+ DXGI_FORMAT_R16G16B16A16_UINT, // UShort4
+ DXGI_FORMAT_R16G16_SNORM, // Short2_Norm
+ DXGI_FORMAT_R16G16B16A16_SNORM, // Short4_Norm
+ DXGI_FORMAT_R16G16_UNORM, // UShort2_Norm
+ DXGI_FORMAT_R16G16B16A16_UNORM, // UShort4_Norm
+ DXGI_FORMAT_R16G16_FLOAT, // Half2
+ DXGI_FORMAT_R16G16B16A16_FLOAT // Half4
+ };
+ static_assert(sizeof(JulietToD3D12_VertexFormat) / sizeof(JulietToD3D12_VertexFormat[0]) ==
+ ToUnderlying(VertexElementFormat::Count));
+
+ // clang-format off
+ D3D12_PRIMITIVE_TOPOLOGY_TYPE JulietToD3D12_PrimitiveTopologyType[] = {
+ D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
+ D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
+ D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
+ D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
+ D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT
+ };
+ // clang-format on
+ static_assert(sizeof(JulietToD3D12_PrimitiveTopologyType) / sizeof(JulietToD3D12_PrimitiveTopologyType[0]) ==
+ ToUnderlying(PrimitiveType::Count));
+
+ // clang-format off
+ D3D12_BLEND JulietToD3D12_BlendFactor[] =
+ {
+ D3D12_BLEND_ZERO,
+ D3D12_BLEND_ZERO,
+ D3D12_BLEND_ONE,
+ D3D12_BLEND_SRC_COLOR,
+ D3D12_BLEND_INV_SRC_COLOR,
+ D3D12_BLEND_DEST_COLOR,
+ D3D12_BLEND_INV_DEST_COLOR,
+ D3D12_BLEND_SRC_ALPHA,
+ D3D12_BLEND_INV_SRC_ALPHA,
+ D3D12_BLEND_DEST_ALPHA,
+ D3D12_BLEND_INV_DEST_ALPHA,
+ D3D12_BLEND_BLEND_FACTOR,
+ D3D12_BLEND_INV_BLEND_FACTOR,
+ D3D12_BLEND_SRC_ALPHA_SAT,
+ };
+ // clang-format on
+ static_assert(sizeof(JulietToD3D12_BlendFactor) / sizeof(JulietToD3D12_BlendFactor[0]) == ToUnderlying(BlendFactor::Count));
+
+ // clang-format off
+ D3D12_BLEND JulietToD3D12_BlendFactorAlpha[] =
+ {
+ D3D12_BLEND_ZERO,
+ D3D12_BLEND_ZERO,
+ D3D12_BLEND_ONE,
+ D3D12_BLEND_SRC_ALPHA,
+ D3D12_BLEND_INV_SRC_ALPHA,
+ D3D12_BLEND_DEST_ALPHA,
+ D3D12_BLEND_INV_DEST_ALPHA,
+ D3D12_BLEND_SRC_ALPHA,
+ D3D12_BLEND_INV_SRC_ALPHA,
+ D3D12_BLEND_DEST_ALPHA,
+ D3D12_BLEND_INV_DEST_ALPHA,
+ D3D12_BLEND_BLEND_FACTOR,
+ D3D12_BLEND_INV_BLEND_FACTOR,
+ D3D12_BLEND_SRC_ALPHA_SAT,
+ };
+ // clang-format on
+ static_assert(sizeof(JulietToD3D12_BlendFactorAlpha) / sizeof(JulietToD3D12_BlendFactorAlpha[0]) ==
+ ToUnderlying(BlendFactor::Count));
+
+ // clang-format off
+ D3D12_BLEND_OP JulietToD3D12_BlendOperation[] =
+ {
+ D3D12_BLEND_OP_ADD,
+ D3D12_BLEND_OP_ADD,
+ D3D12_BLEND_OP_SUBTRACT,
+ D3D12_BLEND_OP_REV_SUBTRACT,
+ D3D12_BLEND_OP_MIN,
+ D3D12_BLEND_OP_MAX
+ };
+ // clang-format on
+ static_assert(sizeof(JulietToD3D12_BlendOperation) / sizeof(JulietToD3D12_BlendOperation[0]) ==
+ ToUnderlying(BlendOperation::Count));
+
+ // clang-format off
+ D3D12_COMPARISON_FUNC JulietToD3D12_CompareOperation[] =
+ {
+ D3D12_COMPARISON_FUNC_NEVER,
+ D3D12_COMPARISON_FUNC_NEVER,
+ D3D12_COMPARISON_FUNC_LESS,
+ D3D12_COMPARISON_FUNC_EQUAL,
+ D3D12_COMPARISON_FUNC_LESS_EQUAL,
+ D3D12_COMPARISON_FUNC_GREATER,
+ D3D12_COMPARISON_FUNC_NOT_EQUAL,
+ D3D12_COMPARISON_FUNC_GREATER_EQUAL,
+ D3D12_COMPARISON_FUNC_ALWAYS
+ };
+ // clang-format on
+ static_assert(sizeof(JulietToD3D12_CompareOperation) / sizeof(JulietToD3D12_CompareOperation[0]) ==
+ ToUnderlying(CompareOperation::Count));
+
+ // clang-format off
+ D3D12_STENCIL_OP JulietToD3D12_StencilOperation[] =
+ {
+ D3D12_STENCIL_OP_KEEP,
+ D3D12_STENCIL_OP_KEEP,
+ D3D12_STENCIL_OP_ZERO,
+ D3D12_STENCIL_OP_REPLACE,
+ D3D12_STENCIL_OP_INCR_SAT,
+ D3D12_STENCIL_OP_DECR_SAT,
+ D3D12_STENCIL_OP_INVERT,
+ D3D12_STENCIL_OP_INCR,
+ D3D12_STENCIL_OP_DECR
+ };
+ // clang-format on
+ static_assert(sizeof(JulietToD3D12_StencilOperation) / sizeof(JulietToD3D12_StencilOperation[0]) ==
+ ToUnderlying(StencilOperation::Count));
+
+ bool ConvertVertexInputState(const VertexInputState& vertexInputState, D3D12_INPUT_ELEMENT_DESC* desc, String semantic)
+ {
+ if (desc == nullptr || vertexInputState.NumVertexAttributes == 0)
+ {
+ return false;
+ }
+
+ for (uint32 idx = 0; idx < vertexInputState.NumVertexAttributes; ++idx)
+ {
+ VertexAttribute attribute = vertexInputState.VertexAttributes[idx];
+
+ desc[idx].SemanticName = CStr(semantic);
+ desc[idx].SemanticIndex = attribute.Location;
+ desc[idx].Format = JulietToD3D12_VertexFormat[ToUnderlying(attribute.Format)];
+ desc[idx].InputSlot = attribute.BufferSlot;
+ desc[idx].AlignedByteOffset = attribute.Offset;
+ desc[idx].InputSlotClass =
+ JulietToD3D12_InputRate[ToUnderlying(vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InputRate)];
+ desc[idx].InstanceDataStepRate =
+ (vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InputRate == VertexInputRate::Instance)
+ ? vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InstanceStepRate
+ : 0;
+ }
+
+ return true;
+ }
+
+ bool ConvertRasterizerState(const RasterizerState& rasterizerState, D3D12_RASTERIZER_DESC& desc)
+ {
+ desc.FillMode = JulietToD3D12_FillMode[ToUnderlying(rasterizerState.FillMode)];
+ desc.CullMode = JulietToD3D12_CullMode[ToUnderlying(rasterizerState.CullMode)];
+
+ switch (rasterizerState.FrontFace)
+ {
+ case FrontFace::CounterClockwise: desc.FrontCounterClockwise = TRUE; break;
+ case FrontFace::Clockwise: desc.FrontCounterClockwise = FALSE; break;
+ default: return false;
+ }
+ static_assert(ToUnderlying(FrontFace::Count) == 2);
+
+ if (rasterizerState.EnableDepthBias)
+ {
+ desc.DepthBias = LRoundF(rasterizerState.DepthBiasConstantFactor);
+ desc.DepthBiasClamp = rasterizerState.DepthBiasClamp;
+ desc.SlopeScaledDepthBias = rasterizerState.DepthBiasSlopeFactor;
+ }
+ else
+ {
+ desc.DepthBias = 0;
+ desc.DepthBiasClamp = 0.0f;
+ desc.SlopeScaledDepthBias = 0.0f;
+ }
+
+ desc.DepthClipEnable = rasterizerState.EnableDepthClip;
+ desc.MultisampleEnable = FALSE;
+ desc.AntialiasedLineEnable = FALSE;
+ desc.ForcedSampleCount = 0;
+ desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
+ return true;
+ }
+
+ bool ConvertBlendState(const GraphicsPipelineCreateInfo& createInfo, D3D12_BLEND_DESC& blendDesc)
+ {
+ ZeroStruct(blendDesc);
+ blendDesc.AlphaToCoverageEnable = FALSE;
+ blendDesc.IndependentBlendEnable = FALSE;
+
+ for (UINT i = 0; i < GPUDriver::kMaxColorTargetInfo; i += 1)
+ {
+ D3D12_RENDER_TARGET_BLEND_DESC rtBlendDesc;
+ rtBlendDesc.BlendEnable = FALSE;
+ rtBlendDesc.LogicOpEnable = FALSE;
+ rtBlendDesc.SrcBlend = D3D12_BLEND_ONE;
+ rtBlendDesc.DestBlend = D3D12_BLEND_ZERO;
+ rtBlendDesc.BlendOp = D3D12_BLEND_OP_ADD;
+ rtBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE;
+ rtBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO;
+ rtBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_ADD;
+ rtBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP;
+ rtBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
+
+ // If target_info has more blend states, you can set IndependentBlendEnable to TRUE and assign different blend states to each render target slot
+ if (i < createInfo.TargetInfo.NumColorTargets)
+ {
+ ColorTargetBlendState blendState = createInfo.TargetInfo.ColorTargetDescriptions[i].BlendState;
+ ColorComponentFlags colorWriteMask =
+ blendState.EnableColorWriteMask ? blendState.ColorWriteMask : static_cast(0xF);
+
+ rtBlendDesc.BlendEnable = blendState.EnableBlend;
+ rtBlendDesc.SrcBlend = JulietToD3D12_BlendFactor[ToUnderlying(blendState.SourceColorBlendFactor)];
+ rtBlendDesc.DestBlend = JulietToD3D12_BlendFactor[ToUnderlying(blendState.DestinationColorBlendFactor)];
+ rtBlendDesc.BlendOp = JulietToD3D12_BlendOperation[ToUnderlying(blendState.ColorBlendOperation)];
+ rtBlendDesc.SrcBlendAlpha = JulietToD3D12_BlendFactorAlpha[ToUnderlying(blendState.SourceAlphaBlendFactor)];
+ rtBlendDesc.DestBlendAlpha =
+ JulietToD3D12_BlendFactorAlpha[ToUnderlying(blendState.DestinationAlphaBlendFactor)];
+ rtBlendDesc.BlendOpAlpha = JulietToD3D12_BlendOperation[ToUnderlying(blendState.AlphaBlendOperation)];
+ rtBlendDesc.RenderTargetWriteMask = ToUnderlying(colorWriteMask);
+
+ if (i > 0)
+ {
+ blendDesc.IndependentBlendEnable = TRUE;
+ }
+ }
+
+ blendDesc.RenderTarget[i] = rtBlendDesc;
+ }
+
+ return true;
+ }
+
+ bool ConvertDepthStencilState(DepthStencilState depthStencilState, D3D12_DEPTH_STENCIL_DESC& desc)
+ {
+ desc.DepthEnable = depthStencilState.EnableDepthTest == true ? TRUE : FALSE;
+ desc.DepthWriteMask = depthStencilState.EnableDepthWrite == true ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
+ desc.DepthFunc = JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.CompareOperation)];
+ desc.StencilEnable = depthStencilState.EnableStencilTest == true ? TRUE : FALSE;
+ desc.StencilReadMask = depthStencilState.CompareMask;
+ desc.StencilWriteMask = depthStencilState.WriteMask;
+
+ desc.FrontFace.StencilFailOp =
+ JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.FailOperation)];
+ desc.FrontFace.StencilDepthFailOp =
+ JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.DepthFailOperation)];
+ desc.FrontFace.StencilPassOp =
+ JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.PassOperation)];
+ desc.FrontFace.StencilFunc =
+ JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.FrontStencilState.CompareOperation)];
+
+ desc.BackFace.StencilFailOp =
+ JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.FailOperation)];
+ desc.BackFace.StencilDepthFailOp =
+ JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.DepthFailOperation)];
+ desc.BackFace.StencilPassOp =
+ JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.PassOperation)];
+ desc.BackFace.StencilFunc =
+ JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.BackStencilState.CompareOperation)];
+
+ return true;
+ }
+
+ D3D12GraphicsRootSignature* CreateGraphicsRootSignature(NonNullPtr renderer, NonNullPtr vertexShader,
+ NonNullPtr fragmentShader)
+ {
+
+ return nullptr;
+ }
+
+ void DestroyGraphicsRootSignature(NonNullPtr rootSignature)
+ {
+ if (!rootSignature)
+ {
+ return;
+ }
+ if (rootSignature->handle)
+ {
+ ID3D12RootSignature_Release(rootSignature->handle);
+ }
+ Free(rootSignature.Get());
+ }
+ } // namespace
+
+ GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr driver, const GraphicsPipelineCreateInfo& createInfo)
+ {
+ auto d3d12Driver = static_cast(driver.Get());
+ auto vertexShader = reinterpret_cast(createInfo.VertexShader);
+ auto fragmentShader = reinterpret_cast(createInfo.FragmentShader);
+
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
+ psoDesc.VS.pShaderBytecode = vertexShader->ByteCode.Data;
+ psoDesc.VS.BytecodeLength = vertexShader->ByteCode.Size;
+ psoDesc.PS.pShaderBytecode = fragmentShader->ByteCode.Data; // PS == Pixel Shader == Fragment Shader
+ psoDesc.PS.BytecodeLength = fragmentShader->ByteCode.Size;
+
+ D3D12_INPUT_ELEMENT_DESC inputElementDescs[D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT];
+ if (createInfo.VertexInputState.NumVertexAttributes > 0)
+ {
+ psoDesc.InputLayout.pInputElementDescs = inputElementDescs;
+ psoDesc.InputLayout.NumElements = createInfo.VertexInputState.NumVertexAttributes;
+ ConvertVertexInputState(createInfo.VertexInputState, inputElementDescs, d3d12Driver->Semantic);
+ }
+
+ psoDesc.PrimitiveTopologyType = JulietToD3D12_PrimitiveTopologyType[ToUnderlying(createInfo.PrimitiveType)];
+
+ if (!ConvertRasterizerState(createInfo.RasterizerState, psoDesc.RasterizerState))
+ {
+ return nullptr;
+ }
+ if (!ConvertBlendState(createInfo, psoDesc.BlendState))
+ {
+ return nullptr;
+ }
+ if (!ConvertDepthStencilState(createInfo.DepthStencilState, psoDesc.DepthStencilState))
+ {
+ return nullptr;
+ }
+
+ auto pipeline = static_cast(Calloc(1, sizeof(D3D12GraphicsPipeline)));
+ if (!pipeline)
+ {
+ return nullptr;
+ }
+
+ uint32 sampleMask = createInfo.MultisampleState.EnableMask ? createInfo.MultisampleState.SampleMask : 0xFFFFFFFF;
+
+ psoDesc.SampleMask = sampleMask;
+ psoDesc.SampleDesc.Count = Internal::JulietToD3D12_SampleCount[ToUnderlying(createInfo.MultisampleState.SampleCount)];
+ psoDesc.SampleDesc.Quality =
+ (createInfo.MultisampleState.SampleCount > TextureSampleCount::One) ? DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN : 0;
+
+ psoDesc.DSVFormat = Internal::ConvertToD3D12DepthFormat(createInfo.TargetInfo.DepthStencilFormat);
+ psoDesc.NumRenderTargets = static_cast(createInfo.TargetInfo.NumColorTargets);
+ for (uint32_t idx = 0; idx < createInfo.TargetInfo.NumColorTargets; ++idx)
+ {
+ psoDesc.RTVFormats[idx] =
+ Internal::ConvertToD3D12TextureFormat(createInfo.TargetInfo.ColorTargetDescriptions[idx].Format);
+ }
+
+ // Assuming some default values or further initialization
+ psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
+ psoDesc.CachedPSO.CachedBlobSizeInBytes = 0;
+ psoDesc.CachedPSO.pCachedBlob = nullptr;
+
+ psoDesc.NodeMask = 0;
+
+ D3D12GraphicsRootSignature* rootSignature = CreateGraphicsRootSignature(d3d12Driver, vertexShader, fragmentShader);
+
+ if (rootSignature == NULL)
+ {
+ Internal::ReleaseGraphicsPipeline(pipeline);
+ return nullptr;
+ }
+ pipeline->RootSignature = rootSignature;
+
+ ID3D12PipelineState* pipelineState;
+ HRESULT res = ID3D12Device_CreateGraphicsPipelineState(d3d12Driver->D3D12Device, &psoDesc, IID_ID3D12PipelineState,
+ reinterpret_cast(&pipelineState));
+ if (FAILED(res))
+ {
+
+ LogError(d3d12Driver, "Could not create graphics pipeline state", res);
+ Internal::ReleaseGraphicsPipeline(pipeline);
+ return nullptr;
+ }
+
+ pipeline->PipelineState = pipelineState;
+
+ for (uint32 i = 0; i < createInfo.VertexInputState.NumVertexBufferDescriptions; i += 1)
+ {
+ pipeline->VertexStrides[createInfo.VertexInputState.VertexBufferDescriptions[i].Slot] =
+ createInfo.VertexInputState.VertexBufferDescriptions[i].PitchInBytes;
+ }
+
+ pipeline->PrimitiveType = createInfo.PrimitiveType;
+
+ pipeline->VertexSamplerCount = vertexShader->NumSamplers;
+ pipeline->VertexStorageTextureCount = vertexShader->NumStorageTextures;
+ pipeline->VertexStorageBufferCount = vertexShader->NumStorageBuffers;
+ pipeline->VertexUniformBufferCount = vertexShader->NumUniformBuffers;
+
+ pipeline->FragmentSamplerCount = fragmentShader->NumSamplers;
+ pipeline->FragmentStorageTextureCount = fragmentShader->NumStorageTextures;
+ pipeline->FragmentStorageBufferCount = fragmentShader->NumStorageBuffers;
+ pipeline->FragmentUniformBufferCount = fragmentShader->NumUniformBuffers;
+
+ pipeline->ReferenceCount = 0;
+
+ return reinterpret_cast(pipeline);
}
+
+ extern void DestroyGraphicsPipeline(NonNullPtr driver, NonNullPtr graphicsPipeline)
+ {
+ auto d3d12Driver = static_cast(driver.Get());
+ auto d3d12GraphicsPipeline = reinterpret_cast(graphicsPipeline.Get());
+
+ if (d3d12Driver->GraphicsPipelinesToDisposeCount + 1 >= d3d12Driver->GraphicsPipelinesToDisposeCapacity)
+ {
+ d3d12Driver->GraphicsPipelinesToDisposeCapacity = d3d12Driver->GraphicsPipelinesToDisposeCapacity * 2;
+ d3d12Driver->GraphicsPipelinesToDispose = static_cast(
+ Realloc(d3d12Driver->GraphicsPipelinesToDispose,
+ sizeof(D3D12GraphicsPipeline*) * d3d12Driver->GraphicsPipelinesToDisposeCapacity));
+ }
+ d3d12Driver->GraphicsPipelinesToDispose[d3d12Driver->GraphicsPipelinesToDisposeCount] = d3d12GraphicsPipeline;
+ d3d12Driver->GraphicsPipelinesToDisposeCount += 1;
+ }
+
+ namespace Internal
+ {
+ void ReleaseGraphicsPipeline(NonNullPtr d3d12GraphicsPipeline)
+ {
+ if (d3d12GraphicsPipeline->PipelineState)
+ {
+ ID3D12PipelineState_Release(d3d12GraphicsPipeline->PipelineState);
+ }
+ DestroyGraphicsRootSignature(d3d12GraphicsPipeline->RootSignature);
+ Free(d3d12GraphicsPipeline.Get());
+ }
+ } // namespace Internal
} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.h b/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.h
index b7efc14..eadcef2 100644
--- a/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.h
+++ b/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.h
@@ -1,6 +1,9 @@
#pragma once
#include
+#include
+#include
+#include
namespace Juliet
{
@@ -11,5 +14,51 @@ namespace Juliet
namespace Juliet::D3D12
{
- extern GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr driver, GraphicsPipelineCreateInfo& createInfo);
-}
+ struct D3D12GraphicsRootSignature
+ {
+ ID3D12RootSignature* handle;
+
+ int32 VertexSamplerRootIndex;
+ int32 VertexSamplerTextureRootIndex;
+ int32 VertexStorageTextureRootIndex;
+ int32 VertexStorageBufferRootIndex;
+
+ int32 VertexUniformBufferRootIndex[GPUDriver::kMaxUniformBuffersPerStage];
+
+ int32 FragmentSamplerRootIndex;
+ int32 FragmentSamplerTextureRootIndex;
+ int32 FragmentStorageTextureRootIndex;
+ int32 FragmentStorageBufferRootIndex;
+
+ int32 FragmentUniformBufferRootIndex[GPUDriver::kMaxUniformBuffersPerStage];
+ };
+
+ struct D3D12GraphicsPipeline
+ {
+ ID3D12PipelineState* PipelineState;
+ D3D12GraphicsRootSignature* RootSignature;
+ PrimitiveType PrimitiveType;
+
+ uint32 VertexStrides[GPUDriver::kMaxVertexBuffers];
+
+ uint32 VertexSamplerCount;
+ uint32 VertexUniformBufferCount;
+ uint32 VertexStorageBufferCount;
+ uint32 VertexStorageTextureCount;
+
+ uint32 FragmentSamplerCount;
+ uint32 FragmentUniformBufferCount;
+ uint32 FragmentStorageBufferCount;
+ uint32 FragmentStorageTextureCount;
+
+ int ReferenceCount;
+ };
+
+ extern GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr driver, const GraphicsPipelineCreateInfo& createInfo);
+ extern void DestroyGraphicsPipeline(NonNullPtr driver, NonNullPtr graphicsPipeline);
+
+ namespace Internal
+ {
+ extern void ReleaseGraphicsPipeline(NonNullPtr d3d12GraphicsPipeline);
+ }
+} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/D3D12Shader.cpp b/Juliet/src/Graphics/D3D12/D3D12Shader.cpp
index d278d3c..0f2f482 100644
--- a/Juliet/src/Graphics/D3D12/D3D12Shader.cpp
+++ b/Juliet/src/Graphics/D3D12/D3D12Shader.cpp
@@ -5,14 +5,6 @@
namespace Juliet::D3D12
{
- namespace
- {
- struct D3D12Shader
- {
- ByteBuffer ByteCode;
- };
- } // namespace
-
Shader* CreateShader(NonNullPtr driver, ByteBuffer shaderByteCode, ShaderCreateInfo& shaderCreateInfo)
{
if (!IsValid(shaderByteCode))
diff --git a/Juliet/src/Graphics/D3D12/D3D12Shader.h b/Juliet/src/Graphics/D3D12/D3D12Shader.h
index 37d7939..839cf84 100644
--- a/Juliet/src/Graphics/D3D12/D3D12Shader.h
+++ b/Juliet/src/Graphics/D3D12/D3D12Shader.h
@@ -6,6 +6,16 @@
namespace Juliet::D3D12
{
+ struct D3D12Shader
+ {
+ ByteBuffer ByteCode;
+
+ uint32 NumSamplers;
+ uint32 NumUniformBuffers;
+ uint32 NumStorageBuffers;
+ uint32 NumStorageTextures;
+ };
+
extern Shader* CreateShader(NonNullPtr driver, ByteBuffer shaderByteCode, ShaderCreateInfo& shaderCreateInfo);
extern void DestroyShader(NonNullPtr driver, NonNullPtr shader);
} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp b/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp
index 86f0159..e10b389 100644
--- a/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp
+++ b/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp
@@ -66,6 +66,8 @@ namespace Juliet::D3D12
result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false);
}
+ Internal::DisposePendingResourcces(d3d12driver);
+
return result;
}
diff --git a/Juliet/src/Graphics/D3D12/D3D12Texture.cpp b/Juliet/src/Graphics/D3D12/D3D12Texture.cpp
index f84bfec..1fcc016 100644
--- a/Juliet/src/Graphics/D3D12/D3D12Texture.cpp
+++ b/Juliet/src/Graphics/D3D12/D3D12Texture.cpp
@@ -116,6 +116,117 @@ namespace Juliet::D3D12
DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT
DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT
};
+ static_assert(sizeof(JulietToD3D12_TextureFormat) / sizeof(JulietToD3D12_TextureFormat[0]) ==
+ ToUnderlying(TextureFormat::Count));
+
+ DXGI_FORMAT JulietToD3D12_DepthFormat[] = {
+ DXGI_FORMAT_UNKNOWN, // INVALID
+ DXGI_FORMAT_UNKNOWN, // A8_UNORM
+ DXGI_FORMAT_UNKNOWN, // R8_UNORM
+ DXGI_FORMAT_UNKNOWN, // R8G8_UNORM
+ DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM
+ DXGI_FORMAT_UNKNOWN, // R16_UNORM
+ DXGI_FORMAT_UNKNOWN, // R16G16_UNORM
+ DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UNORM
+ DXGI_FORMAT_UNKNOWN, // R10G10B10A2_UNORM
+ DXGI_FORMAT_UNKNOWN, // B5G6R5_UNORM
+ DXGI_FORMAT_UNKNOWN, // B5G5R5A1_UNORM
+ DXGI_FORMAT_UNKNOWN, // B4G4R4A4_UNORM
+ DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM
+ DXGI_FORMAT_UNKNOWN, // BC1_UNORM
+ DXGI_FORMAT_UNKNOWN, // BC2_UNORM
+ DXGI_FORMAT_UNKNOWN, // BC3_UNORM
+ DXGI_FORMAT_UNKNOWN, // BC4_UNORM
+ DXGI_FORMAT_UNKNOWN, // BC5_UNORM
+ DXGI_FORMAT_UNKNOWN, // BC7_UNORM
+ DXGI_FORMAT_UNKNOWN, // BC6H_FLOAT
+ DXGI_FORMAT_UNKNOWN, // BC6H_UFLOAT
+ DXGI_FORMAT_UNKNOWN, // R8_SNORM
+ DXGI_FORMAT_UNKNOWN, // R8G8_SNORM
+ DXGI_FORMAT_UNKNOWN, // R8G8B8A8_SNORM
+ DXGI_FORMAT_UNKNOWN, // R16_SNORM
+ DXGI_FORMAT_UNKNOWN, // R16G16_SNORM
+ DXGI_FORMAT_UNKNOWN, // R16G16B16A16_SNORM
+ DXGI_FORMAT_UNKNOWN, // R16_FLOAT
+ DXGI_FORMAT_UNKNOWN, // R16G16_FLOAT
+ DXGI_FORMAT_UNKNOWN, // R16G16B16A16_FLOAT
+ DXGI_FORMAT_UNKNOWN, // R32_FLOAT
+ DXGI_FORMAT_UNKNOWN, // R32G32_FLOAT
+ DXGI_FORMAT_UNKNOWN, // R32G32B32A32_FLOAT
+ DXGI_FORMAT_UNKNOWN, // R11G11B10_UFLOAT
+ DXGI_FORMAT_UNKNOWN, // R8_UINT
+ DXGI_FORMAT_UNKNOWN, // R8G8_UINT
+ DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UINT
+ DXGI_FORMAT_UNKNOWN, // R16_UINT
+ DXGI_FORMAT_UNKNOWN, // R16G16_UINT
+ DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UINT
+ DXGI_FORMAT_UNKNOWN, // R32_UINT
+ DXGI_FORMAT_UNKNOWN, // R32G32_UINT
+ DXGI_FORMAT_UNKNOWN, // R32G32B32A32_UINT
+ DXGI_FORMAT_UNKNOWN, // R8_INT
+ DXGI_FORMAT_UNKNOWN, // R8G8_INT
+ DXGI_FORMAT_UNKNOWN, // R8G8B8A8_INT
+ DXGI_FORMAT_UNKNOWN, // R16_INT
+ DXGI_FORMAT_UNKNOWN, // R16G16_INT
+ DXGI_FORMAT_UNKNOWN, // R16G16B16A16_INT
+ DXGI_FORMAT_UNKNOWN, // R32_INT
+ DXGI_FORMAT_UNKNOWN, // R32G32_INT
+ DXGI_FORMAT_UNKNOWN, // R32G32B32A32_INT
+ DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // BC1_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // BC2_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // BC3_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // BC7_UNORM_SRGB
+ DXGI_FORMAT_D16_UNORM, // D16_UNORM
+ DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM
+ DXGI_FORMAT_D32_FLOAT, // D32_FLOAT
+ DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM_S8_UINT
+ DXGI_FORMAT_D32_FLOAT_S8X24_UINT, // D32_FLOAT_S8_UINT
+ DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM
+ DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB
+ DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT
+ DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT
+ DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT
+ DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT
+ DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT
+ DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT
+ DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT
+ DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT
+ DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT
+ DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT
+ DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT
+ DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT
+ DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT
+ DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT
+ };
+ static_assert(sizeof(JulietToD3D12_DepthFormat) / sizeof(JulietToD3D12_DepthFormat[0]) == ToUnderlying(TextureFormat::Count));
uint32 ComputeSubresourceIndex(uint32 mipLevel, uint32 layer, uint32 numLevels)
{
@@ -236,5 +347,17 @@ namespace Juliet::D3D12
{
return JulietToD3D12_TextureFormat[ToUnderlying(format)];
}
+
+ DXGI_FORMAT ConvertToD3D12DepthFormat(TextureFormat format)
+ {
+ return JulietToD3D12_DepthFormat[ToUnderlying(format)];
+ }
+
+ uint32 JulietToD3D12_SampleCount[] = {
+ 1, // MSAA 1x
+ 2, // MSAA 2x
+ 4, // MSAA 4x
+ 8, // MSAA 8x
+ };
} // namespace Internal
} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/D3D12Texture.h b/Juliet/src/Graphics/D3D12/D3D12Texture.h
index d59d87b..f936163 100644
--- a/Juliet/src/Graphics/D3D12/D3D12Texture.h
+++ b/Juliet/src/Graphics/D3D12/D3D12Texture.h
@@ -88,5 +88,7 @@ namespace Juliet::D3D12
// Utils
extern DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format);
+ extern DXGI_FORMAT ConvertToD3D12DepthFormat(TextureFormat format);
+ extern uint32 JulietToD3D12_SampleCount[];
} // namespace Internal
} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/Graphics.cpp b/Juliet/src/Graphics/Graphics.cpp
index 539a9b3..3b83fdc 100644
--- a/Juliet/src/Graphics/Graphics.cpp
+++ b/Juliet/src/Graphics/Graphics.cpp
@@ -218,8 +218,8 @@ namespace Juliet
device->DestroyShader(device->Driver, shader);
}
- GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr device, GraphicsPipelineCreateInfo& createInfo)
+ GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr device, const GraphicsPipelineCreateInfo& createInfo)
{
- device->CreateGraphicsPipeline(device->Driver, createInfo);
+ return device->CreateGraphicsPipeline(device->Driver, createInfo);
}
} // namespace Juliet
diff --git a/Juliet/src/Graphics/GraphicsDevice.h b/Juliet/src/Graphics/GraphicsDevice.h
index b09c6d6..45aa7cd 100644
--- a/Juliet/src/Graphics/GraphicsDevice.h
+++ b/Juliet/src/Graphics/GraphicsDevice.h
@@ -30,9 +30,11 @@ namespace Juliet
struct GPUDriver
{
- static constexpr uint8 kResourceBufferCount = 2;
- static constexpr uint8 kMaxFramesInFlight = 3;
- static constexpr uint8 kMaxColorTargetInfo = 4;
+ static constexpr uint8 kResourceBufferCount = 2;
+ static constexpr uint8 kMaxFramesInFlight = 3;
+ static constexpr uint8 kMaxColorTargetInfo = 4;
+ static constexpr uint8 kMaxUniformBuffersPerStage = 4;
+ static constexpr uint8 kMaxVertexBuffers = 16;
};
struct GraphicsDevice
@@ -71,7 +73,7 @@ namespace Juliet
void (*DestroyShader)(NonNullPtr driver, NonNullPtr shader);
// Pipeline
- GraphicsPipeline* (*CreateGraphicsPipeline)(NonNullPtr driver, GraphicsPipelineCreateInfo& createInfo);
+ GraphicsPipeline* (*CreateGraphicsPipeline)(NonNullPtr driver, const GraphicsPipelineCreateInfo& createInfo);
const char* Name = "Unknown";
GPUDriver* Driver = nullptr;
diff --git a/JulietApp/main.cpp b/JulietApp/main.cpp
index 0e21167..6dad1c3 100644
--- a/JulietApp/main.cpp
+++ b/JulietApp/main.cpp
@@ -74,18 +74,21 @@ void JulietApplication::Init()
shaderCI.Stage = ShaderStage::Fragment;
Shader* fragmentShader = CreateShader(GraphicsDevice, shaderPath, shaderCI);
- ColorTargetDescription colorTargetDescription = { .Format = GetSwapChainTextureFormat(GraphicsDevice, MainWindow) };
- GraphicsPipelineCreateInfo pipelineCI = {
- .VertexShader = vertexShader,
- .FragmentShader = fragmentShader,
- .PrimitiveType = PrimitiveType::TriangleList,
- .TargetInfo = {
- .ColorTargetDescriptions = &colorTargetDescription,
- .NumColorTargets = 1,
- },
+ ColorTargetDescription colorTargetDescription = {};
+ colorTargetDescription.Format = GetSwapChainTextureFormat(GraphicsDevice, MainWindow);
+
+ GraphicsPipelineCreateInfo pipelineCI = {};
+ pipelineCI.VertexShader = vertexShader;
+ pipelineCI.FragmentShader = fragmentShader;
+ pipelineCI.PrimitiveType = PrimitiveType::TriangleList;
+ pipelineCI.TargetInfo = {
+ .ColorTargetDescriptions = &colorTargetDescription,
+ .NumColorTargets = 1,
};
pipelineCI.RasterizerState.FillMode = FillMode::Solid;
+ GraphicsPipeline* mainPipeline = CreateGraphicsPipeline(GraphicsDevice, pipelineCI);
+
if (vertexShader)
{
DestroyShader(GraphicsDevice, vertexShader);