From a9fe4683fbf2bfafbdf49349ced01fa31e273006 Mon Sep 17 00:00:00 2001 From: Patedam Date: Sun, 9 Mar 2025 22:52:08 -0400 Subject: [PATCH] Graphics pipeline iteration Lot of code. Not working yet --- Juliet/Juliet.vcxproj | 31 +- Juliet/include/Core/Common/CoreUtils.h | 27 - Juliet/include/Core/Common/String.h | 2 +- Juliet/include/Core/Math/MathUtils.h | 37 ++ Juliet/include/Graphics/Graphics.h | 4 +- Juliet/include/Graphics/GraphicsPipeline.h | 172 ++++++- Juliet/include/Graphics/RenderPass.h | 50 +- Juliet/include/Graphics/Texture.h | 4 +- Juliet/src/Core/Math/MathRound.cpp | 63 +++ Juliet/src/Core/Math/Math_Private.h | 51 ++ .../src/Graphics/D3D12/D3D12CommandList.cpp | 2 +- Juliet/src/Graphics/D3D12/D3D12Common.h | 1 + .../Graphics/D3D12/D3D12GraphicsDevice.cpp | 21 + .../src/Graphics/D3D12/D3D12GraphicsDevice.h | 12 + .../Graphics/D3D12/D3D12GraphicsPipeline.cpp | 470 +++++++++++++++++- .../Graphics/D3D12/D3D12GraphicsPipeline.h | 53 +- Juliet/src/Graphics/D3D12/D3D12Shader.cpp | 8 - Juliet/src/Graphics/D3D12/D3D12Shader.h | 10 + .../Graphics/D3D12/D3D12Synchronization.cpp | 2 + Juliet/src/Graphics/D3D12/D3D12Texture.cpp | 123 +++++ Juliet/src/Graphics/D3D12/D3D12Texture.h | 2 + Juliet/src/Graphics/Graphics.cpp | 4 +- Juliet/src/Graphics/GraphicsDevice.h | 10 +- JulietApp/main.cpp | 21 +- 24 files changed, 1100 insertions(+), 80 deletions(-) create mode 100644 Juliet/include/Core/Math/MathUtils.h create mode 100644 Juliet/src/Core/Math/MathRound.cpp create mode 100644 Juliet/src/Core/Math/Math_Private.h 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);