- Depth buffer
- Debug display basics
- Basic vector + matrix maths
Made partially with gemini + antigravity
This commit is contained in:
2026-01-11 22:07:38 -05:00
parent fa1933c169
commit bfd042abbf
28 changed files with 959 additions and 67 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,4 @@
float4 main(float4 Color : TEXCOORD0) : SV_Target0
{
return Color;
}

View File

@@ -0,0 +1,27 @@
struct Output
{
float4 Color : TEXCOORD0;
float4 Position : SV_Position;
};
#include "RootConstants.hlsl"
Output main(uint vertexIndex : SV_VertexID)
{
Output output;
// Retrieve the vertex buffer using SM6.6 bindless syntax
ByteAddressBuffer buffer = ResourceDescriptorHeap[BufferIndex];
// Vertex layout: float3 Position (12 bytes) + float4 Color (16 bytes) = 28 bytes stride
uint stride = 28;
uint offset = vertexIndex * stride;
float3 pos = asfloat(buffer.Load3(offset));
float4 col = asfloat(buffer.Load4(offset + 12));
// Standard row-major transformation
output.Position = mul(ViewProjection, float4(pos, 1.0f));
output.Color = col;
return output;
}

View File

@@ -0,0 +1,11 @@
#ifndef ROOT_CONSTANTS_HLSL
#define ROOT_CONSTANTS_HLSL
cbuffer RootConstants : register(b0, space0)
{
row_major float4x4 ViewProjection;
uint BufferIndex;
uint _Padding[3];
};
#endif // ROOT_CONSTANTS_HLSL

View File

@@ -1,26 +1,17 @@
struct Input
{
uint VertexIndex : SV_VertexID;
};
struct Output struct Output
{ {
float4 Color : TEXCOORD0; float4 Color : TEXCOORD0;
float4 Position : SV_Position; float4 Position : SV_Position;
}; };
// Bindless storage buffer access #include "RootConstants.hlsl"
// We assume DescriptorIndex 0 is our buffer for this example, or passed via push constant
// Since we don't have push constants hooked up in the C++ simplified example yet,
// we will assume the First descriptor in the heap is our buffer (Index 0).
// In a real app, 'bufferIndex' would be passed as a Root Constant.
Output main(Input input) Output main(uint vertexIndex : SV_VertexID)
{ {
Output output; Output output;
// Retrieve the buffer using SM6.6 bindless syntax // Retrieve the buffer using SM6.6 bindless syntax
// heap index 0 is used for simplicity. // We use index 0 as the sample app doesn't pass push constants yet.
uint bufferIndex = 0; uint bufferIndex = 0;
ByteAddressBuffer buffer = ResourceDescriptorHeap[bufferIndex]; ByteAddressBuffer buffer = ResourceDescriptorHeap[bufferIndex];
@@ -28,7 +19,7 @@ Output main(Input input)
// Stride = 2 float (pos) + 4 float (color) = 6 * 4 = 24 bytes ? // Stride = 2 float (pos) + 4 float (color) = 6 * 4 = 24 bytes ?
// Let's assume just position 2D (8 bytes) + Color (16 bytes) // Let's assume just position 2D (8 bytes) + Color (16 bytes)
uint stride = 24; uint stride = 24;
uint offset = input.VertexIndex * stride; uint offset = vertexIndex * stride;
float2 pos = asfloat(buffer.Load2(offset)); float2 pos = asfloat(buffer.Load2(offset));
float4 col = asfloat(buffer.Load4(offset + 8)); float4 col = asfloat(buffer.Load4(offset + 8));

View File

@@ -53,7 +53,9 @@
<CustomBuild Include="include\Core\Logging\LogManager.h" /> <CustomBuild Include="include\Core\Logging\LogManager.h" />
<CustomBuild Include="include\Core\Logging\LogTypes.h" /> <CustomBuild Include="include\Core\Logging\LogTypes.h" />
<CustomBuild Include="include\Core\Math\MathUtils.h" /> <CustomBuild Include="include\Core\Math\MathUtils.h" />
<CustomBuild Include="include\Core\Math\Matrix.h" />
<CustomBuild Include="include\Core\Math\Shape.h" /> <CustomBuild Include="include\Core\Math\Shape.h" />
<CustomBuild Include="include\Core\Math\Vector.h" />
<CustomBuild Include="include\Core\Memory\Allocator.h" /> <CustomBuild Include="include\Core\Memory\Allocator.h" />
<CustomBuild Include="include\Core\Memory\Utils.h" /> <CustomBuild Include="include\Core\Memory\Utils.h" />
<CustomBuild Include="include\Core\Networking\IPAddress.h" /> <CustomBuild Include="include\Core\Networking\IPAddress.h" />
@@ -66,7 +68,9 @@
<CustomBuild Include="include\Core\Thread\Thread.h" /> <CustomBuild Include="include\Core\Thread\Thread.h" />
<CustomBuild Include="include\Engine\Class.h" /> <CustomBuild Include="include\Engine\Class.h" />
<CustomBuild Include="include\Engine\Engine.h" /> <CustomBuild Include="include\Engine\Engine.h" />
<CustomBuild Include="include\Graphics\Camera.h" />
<CustomBuild Include="include\Graphics\Colors.h" /> <CustomBuild Include="include\Graphics\Colors.h" />
<CustomBuild Include="include\Graphics\DebugDisplay.h" />
<CustomBuild Include="include\Graphics\Graphics.h" /> <CustomBuild Include="include\Graphics\Graphics.h" />
<CustomBuild Include="include\Graphics\GraphicsBuffer.h" /> <CustomBuild Include="include\Graphics\GraphicsBuffer.h" />
<CustomBuild Include="include\Graphics\GraphicsConfig.h" /> <CustomBuild Include="include\Graphics\GraphicsConfig.h" />
@@ -166,6 +170,7 @@
<CustomBuild Include="src\Graphics\D3D12\D3D12Texture.h" /> <CustomBuild Include="src\Graphics\D3D12\D3D12Texture.h" />
<CustomBuild Include="src\Graphics\D3D12\D3D12Utils.cpp" /> <CustomBuild Include="src\Graphics\D3D12\D3D12Utils.cpp" />
<CustomBuild Include="src\Graphics\D3D12\D3D12Utils.h" /> <CustomBuild Include="src\Graphics\D3D12\D3D12Utils.h" />
<CustomBuild Include="src\Graphics\DebugDisplayRenderer.cpp" />
<CustomBuild Include="src\Graphics\Graphics.cpp" /> <CustomBuild Include="src\Graphics\Graphics.cpp" />
<CustomBuild Include="src\Graphics\GraphicsDevice.h" /> <CustomBuild Include="src\Graphics\GraphicsDevice.h" />
</ItemGroup> </ItemGroup>

View File

@@ -79,9 +79,15 @@
<CustomBuild Include="include\Core\Math\MathUtils.h"> <CustomBuild Include="include\Core\Math\MathUtils.h">
<Filter>include\Core\Math</Filter> <Filter>include\Core\Math</Filter>
</CustomBuild> </CustomBuild>
<CustomBuild Include="include\Core\Math\Matrix.h">
<Filter>include\Core\Math</Filter>
</CustomBuild>
<CustomBuild Include="include\Core\Math\Shape.h"> <CustomBuild Include="include\Core\Math\Shape.h">
<Filter>include\Core\Math</Filter> <Filter>include\Core\Math</Filter>
</CustomBuild> </CustomBuild>
<CustomBuild Include="include\Core\Math\Vector.h">
<Filter>include\Core\Math</Filter>
</CustomBuild>
<CustomBuild Include="include\Core\Memory\Allocator.h"> <CustomBuild Include="include\Core\Memory\Allocator.h">
<Filter>include\Core\Memory</Filter> <Filter>include\Core\Memory</Filter>
</CustomBuild> </CustomBuild>
@@ -118,9 +124,15 @@
<CustomBuild Include="include\Engine\Engine.h"> <CustomBuild Include="include\Engine\Engine.h">
<Filter>include\Engine</Filter> <Filter>include\Engine</Filter>
</CustomBuild> </CustomBuild>
<CustomBuild Include="include\Graphics\Camera.h">
<Filter>include\Graphics</Filter>
</CustomBuild>
<CustomBuild Include="include\Graphics\Colors.h"> <CustomBuild Include="include\Graphics\Colors.h">
<Filter>include\Graphics</Filter> <Filter>include\Graphics</Filter>
</CustomBuild> </CustomBuild>
<CustomBuild Include="include\Graphics\DebugDisplay.h">
<Filter>include\Graphics</Filter>
</CustomBuild>
<CustomBuild Include="include\Graphics\Graphics.h"> <CustomBuild Include="include\Graphics\Graphics.h">
<Filter>include\Graphics</Filter> <Filter>include\Graphics</Filter>
</CustomBuild> </CustomBuild>
@@ -417,6 +429,9 @@
<CustomBuild Include="src\Graphics\D3D12\D3D12Utils.h"> <CustomBuild Include="src\Graphics\D3D12\D3D12Utils.h">
<Filter>src\Graphics\D3D12</Filter> <Filter>src\Graphics\D3D12</Filter>
</CustomBuild> </CustomBuild>
<CustomBuild Include="src\Graphics\DebugDisplayRenderer.cpp">
<Filter>src\Graphics</Filter>
</CustomBuild>
<CustomBuild Include="src\Graphics\Graphics.cpp"> <CustomBuild Include="src\Graphics\Graphics.cpp">
<Filter>src\Graphics</Filter> <Filter>src\Graphics</Filter>
</CustomBuild> </CustomBuild>

View File

@@ -0,0 +1,86 @@
#pragma once
#include <Core/Math/Vector.h>
#include <math.h>
namespace Juliet
{
struct Matrix
{
float m[4][4];
static Matrix Identity()
{
Matrix result = {};
result.m[0][0] = 1.0f;
result.m[1][1] = 1.0f;
result.m[2][2] = 1.0f;
result.m[3][3] = 1.0f;
return result;
}
Matrix operator*(const Matrix& rhs) const
{
Matrix result = {};
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
for (int k = 0; k < 4; ++k)
{
result.m[i][j] += m[i][k] * rhs.m[k][j];
}
}
}
return result;
}
};
inline Matrix LookAt(const Vector3& eye, const Vector3& target, const Vector3& up)
{
// Left-Handed convention
Vector3 zaxis = Normalize(target - eye); // Forward is +z
Vector3 xaxis = Normalize(Cross(up, zaxis));
Vector3 yaxis = Cross(zaxis, xaxis);
Matrix result = {};
// Row 0
result.m[0][0] = xaxis.x;
result.m[0][1] = xaxis.y;
result.m[0][2] = xaxis.z;
result.m[0][3] = -Dot(xaxis, eye);
// Row 1
result.m[1][0] = yaxis.x;
result.m[1][1] = yaxis.y;
result.m[1][2] = yaxis.z;
result.m[1][3] = -Dot(yaxis, eye);
// Row 2
result.m[2][0] = zaxis.x;
result.m[2][1] = zaxis.y;
result.m[2][2] = zaxis.z;
result.m[2][3] = -Dot(zaxis, eye);
// Row 3
result.m[3][3] = 1.0f;
return result;
}
inline Matrix PerspectiveFov(float fovY, float aspectRatio, float nearZ, float farZ)
{
// Left-Handed Perspective
float yScale = 1.0f / tanf(fovY * 0.5f);
float xScale = yScale / aspectRatio;
Matrix result = {};
result.m[0][0] = xScale;
result.m[1][1] = yScale;
result.m[2][2] = farZ / (farZ - nearZ);
result.m[2][3] = (-nearZ * farZ) / (farZ - nearZ);
result.m[3][2] = 1.0f;
result.m[3][3] = 0.0f;
return result;
}
} // namespace Juliet

View File

@@ -0,0 +1,39 @@
#pragma once
#include <Core/Common/CoreTypes.h>
#include <Juliet.h>
#include <math.h>
namespace Juliet
{
struct Vector3
{
float x, y, z;
Vector3 operator+(const Vector3& rhs) const { return { x + rhs.x, y + rhs.y, z + rhs.z }; }
Vector3 operator-(const Vector3& rhs) const { return { x - rhs.x, y - rhs.y, z - rhs.z }; }
Vector3 operator*(float s) const { return { x * s, y * s, z * s }; }
};
struct Vector4
{
float x, y, z, w;
};
inline Vector3 Normalize(const Vector3& v)
{
float len = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
if (len > 0.0001f)
{
return { v.x / len, v.y / len, v.z / len };
}
return v;
}
inline Vector3 Cross(const Vector3& a, const Vector3& b)
{
return { a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x };
}
inline float Dot(const Vector3& a, const Vector3& b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
} // namespace Juliet

View File

@@ -0,0 +1,33 @@
#pragma once
#include <Core/Math/Matrix.h>
#include <Juliet.h>
namespace Juliet
{
struct Camera
{
Vector3 Position;
Vector3 Target;
Vector3 Up;
float FOV; // In radians
float AspectRatio;
float NearPlane;
float FarPlane;
};
inline Matrix Camera_GetViewMatrix(const Camera& cam)
{
return LookAt(cam.Position, cam.Target, cam.Up);
}
inline Matrix Camera_GetProjectionMatrix(const Camera& cam)
{
return PerspectiveFov(cam.FOV, cam.AspectRatio, cam.NearPlane, cam.FarPlane);
}
inline Matrix Camera_GetViewProjectionMatrix(const Camera& cam)
{
return Camera_GetProjectionMatrix(cam) * Camera_GetViewMatrix(cam);
}
} // namespace Juliet

View File

@@ -0,0 +1,17 @@
#pragma once
#include <Core/Math/Vector.h>
#include <Graphics/Camera.h>
#include <Graphics/Colors.h>
#include <Graphics/Graphics.h>
#include <Juliet.h>
namespace Juliet
{
extern JULIET_API void DebugDisplay_Initialize(GraphicsDevice* device);
extern JULIET_API void DebugDisplay_Shutdown(GraphicsDevice* device);
extern JULIET_API void DebugDisplay_DrawLine(const Vector3& start, const Vector3& end, const FColor& color, bool overlay);
extern JULIET_API void DebugDisplay_DrawSphere(const Vector3& center, float radius, const FColor& color, bool overlay);
extern JULIET_API void DebugDisplay_Prepare(CommandList* cmdList);
extern JULIET_API void DebugDisplay_Flush(CommandList* cmdList, RenderPass* renderPass, const Camera& camera);
} // namespace Juliet

View File

@@ -104,14 +104,20 @@ namespace Juliet
extern JULIET_API bool WaitForSwapchain(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window); extern JULIET_API bool WaitForSwapchain(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window);
extern JULIET_API TextureFormat GetSwapChainTextureFormat(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window); extern JULIET_API TextureFormat GetSwapChainTextureFormat(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window);
// Textures
extern JULIET_API Texture* CreateTexture(NonNullPtr<GraphicsDevice> device, const TextureCreateInfo& createInfo);
extern JULIET_API void DestroyTexture(NonNullPtr<GraphicsDevice> device, NonNullPtr<Texture> texture);
// Command List // Command List
extern JULIET_API CommandList* AcquireCommandList(NonNullPtr<GraphicsDevice> device, QueueType queueType = QueueType::Graphics); extern JULIET_API CommandList* AcquireCommandList(NonNullPtr<GraphicsDevice> device, QueueType queueType = QueueType::Graphics);
extern JULIET_API void SubmitCommandLists(NonNullPtr<CommandList> commandList); extern JULIET_API void SubmitCommandLists(NonNullPtr<CommandList> commandList);
// RenderPass // RenderPass
extern JULIET_API RenderPass* BeginRenderPass(NonNullPtr<CommandList> commandList, ColorTargetInfo& colorTargetInfo); extern JULIET_API RenderPass* BeginRenderPass(NonNullPtr<CommandList> commandList, ColorTargetInfo& colorTargetInfo,
DepthStencilTargetInfo* depthStencilTargetInfo = nullptr);
extern JULIET_API RenderPass* BeginRenderPass(NonNullPtr<CommandList> commandList, extern JULIET_API RenderPass* BeginRenderPass(NonNullPtr<CommandList> commandList,
NonNullPtr<const ColorTargetInfo> colorTargetInfos, uint32 colorTargetInfoCount); NonNullPtr<const ColorTargetInfo> colorTargetInfos, uint32 colorTargetInfoCount,
DepthStencilTargetInfo* depthStencilTargetInfo = nullptr);
extern JULIET_API void EndRenderPass(NonNullPtr<RenderPass> renderPass); extern JULIET_API void EndRenderPass(NonNullPtr<RenderPass> renderPass);
extern JULIET_API void SetGraphicsViewPort(NonNullPtr<RenderPass> renderPass, const GraphicsViewPort& viewPort); extern JULIET_API void SetGraphicsViewPort(NonNullPtr<RenderPass> renderPass, const GraphicsViewPort& viewPort);

View File

@@ -41,6 +41,18 @@ namespace Juliet
StoreOperation StoreOperation; StoreOperation StoreOperation;
}; };
struct DepthStencilTargetInfo
{
Texture* TargetTexture;
uint32 MipLevel;
uint32 LayerIndex;
float ClearDepth;
uint8 ClearStencil;
LoadOperation LoadOperation;
StoreOperation StoreOperation;
};
enum class BlendFactor : uint8 enum class BlendFactor : uint8
{ {
Invalid, Invalid,

View File

@@ -59,6 +59,7 @@ namespace Juliet::D3D12
D3D12TextureSubresource* ColorTargetSubresources[GPUDriver::kMaxColorTargetInfo]; D3D12TextureSubresource* ColorTargetSubresources[GPUDriver::kMaxColorTargetInfo];
D3D12TextureSubresource* ColorResolveSubresources[GPUDriver::kMaxColorTargetInfo]; D3D12TextureSubresource* ColorResolveSubresources[GPUDriver::kMaxColorTargetInfo];
D3D12TextureSubresource* DepthStencilSubresource;
bool NeedVertexBufferBind : 1; bool NeedVertexBufferBind : 1;
bool NeedVertexSamplerBind : 1; bool NeedVertexSamplerBind : 1;

View File

@@ -13,6 +13,7 @@
#include <Graphics/D3D12/D3D12Shader.h> #include <Graphics/D3D12/D3D12Shader.h>
#include <Graphics/D3D12/D3D12SwapChain.h> #include <Graphics/D3D12/D3D12SwapChain.h>
#include <Graphics/D3D12/D3D12Synchronization.h> #include <Graphics/D3D12/D3D12Synchronization.h>
#include <Graphics/D3D12/D3D12Texture.h>
#include <Graphics/D3D12/D3D12Utils.h> #include <Graphics/D3D12/D3D12Utils.h>
#include <Graphics/Graphics.h> #include <Graphics/Graphics.h>
#include <Graphics/GraphicsDevice.h> #include <Graphics/GraphicsDevice.h>
@@ -254,13 +255,7 @@ namespace Juliet::D3D12
.pParameters = parameters, .pParameters = parameters,
.NumStaticSamplers = ArraySize(samplers), .NumStaticSamplers = ArraySize(samplers),
.pStaticSamplers = samplers, .pStaticSamplers = samplers,
.Flags = D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS | .Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED | D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |
D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED, D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED,
}, },
@@ -1010,6 +1005,8 @@ namespace Juliet::D3D12
device->CopyBuffer = CopyBuffer; device->CopyBuffer = CopyBuffer;
device->TransitionBufferToReadable = TransitionBufferToReadable; device->TransitionBufferToReadable = TransitionBufferToReadable;
device->GetDescriptorIndex = GetDescriptorIndex; device->GetDescriptorIndex = GetDescriptorIndex;
device->CreateTexture = CreateTexture;
device->DestroyTexture = DestroyTexture;
#if ALLOW_SHADER_HOT_RELOAD #if ALLOW_SHADER_HOT_RELOAD
device->UpdateGraphicsPipelineShaders = UpdateGraphicsPipelineShaders; device->UpdateGraphicsPipelineShaders = UpdateGraphicsPipelineShaders;

View File

@@ -21,7 +21,8 @@ namespace Juliet::D3D12
ToUnderlying(PrimitiveType::Count)); ToUnderlying(PrimitiveType::Count));
} // namespace } // namespace
void BeginRenderPass(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos, uint32 colorTargetInfoCount) void BeginRenderPass(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos,
uint32 colorTargetInfoCount, const DepthStencilTargetInfo* depthStencilTargetInfo)
{ {
auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get()); auto* d3d12CommandList = reinterpret_cast<D3D12CommandList*>(commandList.Get());
@@ -39,7 +40,38 @@ namespace Juliet::D3D12
frameBufferHeight = Min(height, frameBufferHeight); frameBufferHeight = Min(height, frameBufferHeight);
} }
// TODO : Depth Stencil and DSV // Depth Stencil and DSV
D3D12_CPU_DESCRIPTOR_HANDLE DSV;
bool hasDSV = false;
if (depthStencilTargetInfo && depthStencilTargetInfo->TargetTexture)
{
auto* container = reinterpret_cast<D3D12TextureContainer*>(depthStencilTargetInfo->TargetTexture);
uint32 width = container->Header.CreateInfo.Width;
uint32 height = container->Header.CreateInfo.Height;
frameBufferWidth = Min(width, frameBufferWidth);
frameBufferHeight = Min(height, frameBufferHeight);
D3D12TextureSubresource* subresource = Internal::PrepareTextureSubresourceForWrite(
d3d12CommandList, container, 0, 0, false, D3D12_RESOURCE_STATE_DEPTH_WRITE);
DSV = subresource->DSVHandle.CpuHandle;
hasDSV = true;
d3d12CommandList->DepthStencilSubresource = subresource;
Internal::TrackTexture(d3d12CommandList, subresource->Parent);
if (depthStencilTargetInfo->LoadOperation == LoadOperation::Clear)
{
D3D12_CLEAR_FLAGS clearFlags = D3D12_CLEAR_FLAG_DEPTH;
// TODO: Check if texture has stencil
// if (HasStencil(container->Header.CreateInfo.Format)) clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
ID3D12GraphicsCommandList_ClearDepthStencilView(d3d12CommandList->GraphicsCommandList.CommandList, DSV,
clearFlags, depthStencilTargetInfo->ClearDepth,
depthStencilTargetInfo->ClearStencil, 0, nullptr);
}
}
D3D12_CPU_DESCRIPTOR_HANDLE RTVs[GPUDriver::kMaxColorTargetInfo]; D3D12_CPU_DESCRIPTOR_HANDLE RTVs[GPUDriver::kMaxColorTargetInfo];
for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx) for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx)
@@ -87,10 +119,8 @@ namespace Juliet::D3D12
} }
} }
// TODO DSV
ID3D12GraphicsCommandList_OMSetRenderTargets(d3d12CommandList->GraphicsCommandList.CommandList, ID3D12GraphicsCommandList_OMSetRenderTargets(d3d12CommandList->GraphicsCommandList.CommandList,
colorTargetInfoCount, RTVs, false, nullptr); colorTargetInfoCount, RTVs, false, hasDSV ? &DSV : nullptr);
// Set defaults graphics states // Set defaults graphics states
GraphicsViewPort defaultViewport; GraphicsViewPort defaultViewport;
@@ -159,7 +189,14 @@ namespace Juliet::D3D12
} }
} }
// TODO : Write Depth stencil // Reset Depth Stencil state
if (d3d12CommandList->DepthStencilSubresource)
{
Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList,
d3d12CommandList->DepthStencilSubresource,
D3D12_RESOURCE_STATE_DEPTH_WRITE);
d3d12CommandList->DepthStencilSubresource = nullptr;
}
d3d12CommandList->CurrentGraphicsPipeline = nullptr; d3d12CommandList->CurrentGraphicsPipeline = nullptr;
ID3D12GraphicsCommandList_OMSetRenderTargets(d3d12CommandList->GraphicsCommandList.CommandList, 0, nullptr, false, nullptr); ID3D12GraphicsCommandList_OMSetRenderTargets(d3d12CommandList->GraphicsCommandList.CommandList, 0, nullptr, false, nullptr);

View File

@@ -7,7 +7,7 @@
namespace Juliet::D3D12 namespace Juliet::D3D12
{ {
extern void BeginRenderPass(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos, extern void BeginRenderPass(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos,
uint32 colorTargetInfoCount); uint32 colorTargetInfoCount, const DepthStencilTargetInfo* depthStencilTargetInfo);
extern void EndRenderPass(NonNullPtr<CommandList> commandList); extern void EndRenderPass(NonNullPtr<CommandList> commandList);
extern void BindGraphicsPipeline(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsPipeline> graphicsPipeline); extern void BindGraphicsPipeline(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsPipeline> graphicsPipeline);

View File

@@ -4,6 +4,10 @@
#include <Graphics/D3D12/D3D12CommandList.h> #include <Graphics/D3D12/D3D12CommandList.h>
#include <Graphics/D3D12/D3D12Synchronization.h> #include <Graphics/D3D12/D3D12Synchronization.h>
#include <Graphics/D3D12/D3D12Texture.h> #include <Graphics/D3D12/D3D12Texture.h>
#include <Graphics/D3D12/D3D12GraphicsDevice.h>
#include <Graphics/D3D12/D3D12Utils.h>
#include <Core/Memory/Allocator.h>
#include <algorithm>
namespace Juliet::D3D12 namespace Juliet::D3D12
{ {
@@ -68,11 +72,11 @@ namespace Juliet::D3D12
DXGI_FORMAT_BC2_UNORM_SRGB, // BC2_UNORM_SRGB DXGI_FORMAT_BC2_UNORM_SRGB, // BC2_UNORM_SRGB
DXGI_FORMAT_BC3_UNORM_SRGB, // BC3_UNORM_SRGB DXGI_FORMAT_BC3_UNORM_SRGB, // BC3_UNORM_SRGB
DXGI_FORMAT_BC7_UNORM_SRGB, // BC7_UNORM_SRGB DXGI_FORMAT_BC7_UNORM_SRGB, // BC7_UNORM_SRGB
DXGI_FORMAT_R16_UNORM, // D16_UNORM DXGI_FORMAT_R16_TYPELESS, // D16_UNORM
DXGI_FORMAT_R24_UNORM_X8_TYPELESS, // D24_UNORM DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM
DXGI_FORMAT_R32_FLOAT, // D32_FLOAT DXGI_FORMAT_R32_TYPELESS, // D32_FLOAT
DXGI_FORMAT_R24_UNORM_X8_TYPELESS, // D24_UNORM_S8_UINT DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM_S8_UINT
DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, // D32_FLOAT_S8_UINT DXGI_FORMAT_R32G8X24_TYPELESS, // D32_FLOAT_S8_UINT
DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM
DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM
DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM
@@ -360,4 +364,165 @@ namespace Juliet::D3D12
8, // MSAA 8x 8, // MSAA 8x
}; };
} // namespace Internal } // namespace Internal
Texture* CreateTexture(NonNullPtr<GPUDriver> driver, const TextureCreateInfo& createInfo)
{
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
D3D12_RESOURCE_DESC desc = {};
switch (createInfo.Type)
{
case TextureType::Texture_2D:
case TextureType::Texture_2DArray:
case TextureType::Texture_Cube:
case TextureType::Texture_CubeArray:
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
break;
case TextureType::Texture_3D:
case TextureType::Texture_3DArray:
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;
break;
}
desc.Alignment = 0;
desc.Width = createInfo.Width;
desc.Height = createInfo.Height;
desc.DepthOrArraySize = static_cast<uint16>(createInfo.LayerCount);
desc.MipLevels = static_cast<uint16>(createInfo.MipLevelCount);
desc.Format = Internal::ConvertToD3D12TextureFormat(createInfo.Format);
desc.SampleDesc.Count = Internal::JulietToD3D12_SampleCount[ToUnderlying(createInfo.SampleCount)];
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None)
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None)
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
if ((createInfo.Flags & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None)
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
D3D12_HEAP_PROPERTIES heapProps = {};
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
ID3D12Resource* resource = nullptr;
D3D12_CLEAR_VALUE clearValue = {};
D3D12_CLEAR_VALUE* pClearValue = nullptr;
if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)
{
clearValue.Format = Internal::ConvertToD3D12DepthFormat(createInfo.Format);
clearValue.DepthStencil.Depth = 1.0f;
clearValue.DepthStencil.Stencil = 0;
pClearValue = &clearValue;
}
else if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
{
clearValue.Format = desc.Format;
clearValue.Color[0] = 0.0f;
clearValue.Color[1] = 0.0f;
clearValue.Color[2] = 0.0f;
clearValue.Color[3] = 0.0f;
pClearValue = &clearValue;
}
HRESULT hr = ID3D12Device_CreateCommittedResource(d3d12Driver->D3D12Device, &heapProps, D3D12_HEAP_FLAG_NONE, &desc,
D3D12_RESOURCE_STATE_COMMON, pClearValue, IID_ID3D12Resource,
reinterpret_cast<void**>(&resource));
if (FAILED(hr))
{
LogError(d3d12Driver->D3D12Device, "Failed to create D3D12 committed resource for texture", hr);
return nullptr;
}
auto* textureContainer = static_cast<D3D12TextureContainer*>(Calloc(1, sizeof(D3D12TextureContainer)));
auto* texture = static_cast<D3D12Texture*>(Calloc(1, sizeof(D3D12Texture)));
textureContainer->Header.CreateInfo = createInfo;
textureContainer->ActiveTexture = texture;
textureContainer->Textures = static_cast<D3D12Texture**>(Malloc(sizeof(D3D12Texture*)));
textureContainer->Textures[0] = texture;
textureContainer->Capacity = 1;
textureContainer->Count = 1;
textureContainer->CanBeCycled = true;
texture->Container = textureContainer;
texture->Resource = resource;
texture->ReferenceCount = 1;
uint32 numLayers = std::max<uint32>(1, createInfo.LayerCount);
uint32 numMips = std::max<uint32>(1, createInfo.MipLevelCount);
texture->SubresourceCount = numLayers * numMips;
texture->Subresources = static_cast<D3D12TextureSubresource*>(Calloc(texture->SubresourceCount, sizeof(D3D12TextureSubresource)));
for (uint32 layer = 0; layer < numLayers; ++layer)
{
for (uint32 mip = 0; mip < numMips; ++mip)
{
uint32 index = mip + (layer * numMips);
auto& sub = texture->Subresources[index];
sub.Parent = texture;
sub.Layer = layer;
sub.Level = mip;
sub.Index = index;
sub.Depth = 1; // 3D texture depth handling would go here
if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None)
{
sub.RTVHandles = static_cast<D3D12StagingDescriptor*>(Calloc(1, sizeof(D3D12StagingDescriptor)));
Internal::AssignStagingDescriptor(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, sub.RTVHandles[0]);
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
rtvDesc.Format = desc.Format;
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
rtvDesc.Texture2D.MipSlice = mip;
ID3D12Device_CreateRenderTargetView(d3d12Driver->D3D12Device, resource, &rtvDesc, sub.RTVHandles[0].CpuHandle);
}
if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None)
{
Internal::AssignStagingDescriptor(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, sub.DSVHandle);
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
dsvDesc.Format = Internal::ConvertToD3D12DepthFormat(createInfo.Format);
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
dsvDesc.Texture2D.MipSlice = mip;
ID3D12Device_CreateDepthStencilView(d3d12Driver->D3D12Device, resource, &dsvDesc, sub.DSVHandle.CpuHandle);
}
}
}
return reinterpret_cast<Texture*>(textureContainer);
}
void DestroyTexture(NonNullPtr<GPUDriver> driver, NonNullPtr<Texture> texture)
{
auto* d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
auto* textureContainer = reinterpret_cast<D3D12TextureContainer*>(texture.Get());
for (uint32 i = 0; i < textureContainer->Count; ++i)
{
D3D12Texture* d3d12Texture = textureContainer->Textures[i];
for (uint32 j = 0; j < d3d12Texture->SubresourceCount; ++j)
{
D3D12TextureSubresource& sub = d3d12Texture->Subresources[j];
if (sub.RTVHandles)
{
Internal::ReleaseStagingDescriptor(d3d12Driver, sub.RTVHandles[0]);
Free(sub.RTVHandles);
}
if (sub.DSVHandle.Heap)
{
Internal::ReleaseStagingDescriptor(d3d12Driver, sub.DSVHandle);
}
}
ID3D12Resource_Release(d3d12Texture->Resource);
Free(d3d12Texture->Subresources);
Free(d3d12Texture);
}
Free(textureContainer->Textures);
Free(textureContainer);
}
} // namespace Juliet::D3D12 } // namespace Juliet::D3D12

View File

@@ -91,4 +91,7 @@ namespace Juliet::D3D12
extern DXGI_FORMAT ConvertToD3D12DepthFormat(TextureFormat format); extern DXGI_FORMAT ConvertToD3D12DepthFormat(TextureFormat format);
extern uint32 JulietToD3D12_SampleCount[]; extern uint32 JulietToD3D12_SampleCount[];
} // namespace Internal } // namespace Internal
extern Texture* CreateTexture(NonNullPtr<GPUDriver> driver, const TextureCreateInfo& createInfo);
extern void DestroyTexture(NonNullPtr<GPUDriver> driver, NonNullPtr<Texture> texture);
} // namespace Juliet::D3D12 } // namespace Juliet::D3D12

View File

@@ -0,0 +1,349 @@
#include <Graphics/DebugDisplay.h>
#include <Core/Logging/LogManager.h>
#include <Core/Logging/LogTypes.h>
#include <Core/Memory/Allocator.h>
#include <Graphics/GraphicsPipeline.h>
namespace Juliet
{
namespace
{
constexpr uint32 kMaxDebugVertices = 65536;
struct DebugVertex
{
Vector3 Position;
FColor Color;
};
struct DebugDisplayState
{
GraphicsDevice* Device;
// Pipelines
GraphicsPipeline* DepthTestedPipeline;
GraphicsPipeline* OverlayPipeline;
// Vertex data
DebugVertex* DepthTestedVertices;
uint32 DepthTestedVertexCount;
DebugVertex* OverlayVertices;
uint32 OverlayVertexCount;
// GPU buffers
GraphicsBuffer* DepthTestedBuffer;
GraphicsBuffer* OverlayBuffer;
GraphicsTransferBuffer* DepthTestedTransfer;
GraphicsTransferBuffer* OverlayTransfer;
bool Initialized;
};
DebugDisplayState g_DebugState = {};
void AddLine(DebugVertex* vertices, uint32& count, const Vector3& start, const Vector3& end, const FColor& color)
{
if (count + 2 > kMaxDebugVertices)
{
return;
}
vertices[count++] = { start, color };
vertices[count++] = { end, color };
}
void AddSphereWireframe(DebugVertex* vertices, uint32& count, const Vector3& center, float radius, const FColor& color)
{
constexpr int segments = 16;
constexpr float pi = 3.14159265358979f;
// Draw 3 circles (XY, XZ, YZ planes)
for (int i = 0; i < segments; ++i)
{
float a1 = (float)i / segments * 2.0f * pi;
float a2 = (float)(i + 1) / segments * 2.0f * pi;
// XY circle
Vector3 p1 = { center.x + cosf(a1) * radius, center.y + sinf(a1) * radius, center.z };
Vector3 p2 = { center.x + cosf(a2) * radius, center.y + sinf(a2) * radius, center.z };
AddLine(vertices, count, p1, p2, color);
// XZ circle
p1 = { center.x + cosf(a1) * radius, center.y, center.z + sinf(a1) * radius };
p2 = { center.x + cosf(a2) * radius, center.y, center.z + sinf(a2) * radius };
AddLine(vertices, count, p1, p2, color);
// YZ circle
p1 = { center.x, center.y + cosf(a1) * radius, center.z + sinf(a1) * radius };
p2 = { center.x, center.y + cosf(a2) * radius, center.z + sinf(a2) * radius };
AddLine(vertices, count, p1, p2, color);
}
}
GraphicsPipeline* CreateDebugPipeline(GraphicsDevice* device, TextureFormat colorFormat, bool enableDepthTest)
{
String entryPoint = WrapString("main");
ShaderCreateInfo shaderCI = {};
shaderCI.EntryPoint = entryPoint;
String vertPath = WrapString("../../Assets/compiled/Debug.vert.dxil");
shaderCI.Stage = ShaderStage::Vertex;
Shader* vertexShader = CreateShader(device, vertPath, shaderCI);
String fragPath = WrapString("../../Assets/compiled/Debug.frag.dxil");
shaderCI.Stage = ShaderStage::Fragment;
Shader* fragmentShader = CreateShader(device, fragPath, shaderCI);
if (!vertexShader || !fragmentShader)
{
LogError(LogCategory::Graphics, "Failed to create debug shaders");
if (vertexShader)
{
DestroyShader(device, vertexShader);
}
if (fragmentShader)
{
DestroyShader(device, fragmentShader);
}
return nullptr;
}
ColorTargetDescription colorDesc = {};
colorDesc.Format = colorFormat;
GraphicsPipelineCreateInfo createInfo = {};
createInfo.VertexShader = vertexShader;
createInfo.FragmentShader = fragmentShader;
createInfo.PrimitiveType = PrimitiveType::LineList;
createInfo.RasterizerState.FillMode = FillMode::Solid;
createInfo.RasterizerState.CullMode = CullMode::None;
createInfo.RasterizerState.FrontFace = FrontFace::CounterClockwise;
createInfo.MultisampleState.SampleCount = TextureSampleCount::One;
// No vertex input state - using bindless buffer access via SV_VertexID
createInfo.TargetInfo.ColorTargetDescriptions = &colorDesc;
createInfo.TargetInfo.NumColorTargets = 1;
// Now that we support depth-stencil targets in the backend, we can enable them.
createInfo.TargetInfo.HasDepthStencilTarget = true;
createInfo.TargetInfo.DepthStencilFormat = TextureFormat::D32_FLOAT;
if (enableDepthTest)
{
createInfo.DepthStencilState.EnableDepthTest = true;
createInfo.DepthStencilState.EnableDepthWrite = true;
createInfo.DepthStencilState.CompareOperation = CompareOperation::Less;
}
else
{
// Overlay pipeline: depth test/write off, so it draws on top
createInfo.DepthStencilState.EnableDepthTest = false;
createInfo.DepthStencilState.EnableDepthWrite = false;
createInfo.DepthStencilState.CompareOperation = CompareOperation::Always;
}
GraphicsPipeline* pipeline = CreateGraphicsPipeline(device, createInfo);
DestroyShader(device, vertexShader);
DestroyShader(device, fragmentShader);
return pipeline;
}
} // namespace
void DebugDisplay_Initialize(GraphicsDevice* device)
{
if (g_DebugState.Initialized)
{
return;
}
g_DebugState.Device = device;
// Allocate CPU vertex arrays
g_DebugState.DepthTestedVertices = static_cast<DebugVertex*>(Malloc(kMaxDebugVertices * sizeof(DebugVertex)));
g_DebugState.OverlayVertices = static_cast<DebugVertex*>(Malloc(kMaxDebugVertices * sizeof(DebugVertex)));
g_DebugState.DepthTestedVertexCount = 0;
g_DebugState.OverlayVertexCount = 0;
// Create GPU buffers
BufferCreateInfo bufferCI = {};
bufferCI.Size = kMaxDebugVertices * sizeof(DebugVertex);
bufferCI.Usage = BufferUsage::StructuredBuffer;
g_DebugState.DepthTestedBuffer = CreateGraphicsBuffer(device, bufferCI);
g_DebugState.OverlayBuffer = CreateGraphicsBuffer(device, bufferCI);
TransferBufferCreateInfo transferCI = {};
transferCI.Size = kMaxDebugVertices * sizeof(DebugVertex);
transferCI.Usage = TransferBufferUsage::Upload;
g_DebugState.DepthTestedTransfer = CreateGraphicsTransferBuffer(device, transferCI);
g_DebugState.OverlayTransfer = CreateGraphicsTransferBuffer(device, transferCI);
g_DebugState.Initialized = true;
}
void DebugDisplay_Shutdown(GraphicsDevice* device)
{
if (!g_DebugState.Initialized)
{
return;
}
if (g_DebugState.DepthTestedPipeline)
{
DestroyGraphicsPipeline(device, g_DebugState.DepthTestedPipeline);
}
if (g_DebugState.OverlayPipeline)
{
DestroyGraphicsPipeline(device, g_DebugState.OverlayPipeline);
}
if (g_DebugState.DepthTestedBuffer)
{
DestroyGraphicsBuffer(device, g_DebugState.DepthTestedBuffer);
}
if (g_DebugState.OverlayBuffer)
{
DestroyGraphicsBuffer(device, g_DebugState.OverlayBuffer);
}
if (g_DebugState.DepthTestedTransfer)
{
DestroyGraphicsTransferBuffer(device, g_DebugState.DepthTestedTransfer);
}
if (g_DebugState.OverlayTransfer)
{
DestroyGraphicsTransferBuffer(device, g_DebugState.OverlayTransfer);
}
SafeFree(g_DebugState.DepthTestedVertices);
SafeFree(g_DebugState.OverlayVertices);
g_DebugState = {};
}
void DebugDisplay_DrawLine(const Vector3& start, const Vector3& end, const FColor& color, bool overlay)
{
if (overlay)
{
AddLine(g_DebugState.OverlayVertices, g_DebugState.OverlayVertexCount, start, end, color);
}
else
{
AddLine(g_DebugState.DepthTestedVertices, g_DebugState.DepthTestedVertexCount, start, end, color);
}
}
void DebugDisplay_DrawSphere(const Vector3& center, float radius, const FColor& color, bool overlay)
{
if (overlay)
{
AddSphereWireframe(g_DebugState.OverlayVertices, g_DebugState.OverlayVertexCount, center, radius, color);
}
else
{
AddSphereWireframe(g_DebugState.DepthTestedVertices, g_DebugState.DepthTestedVertexCount, center, radius, color);
}
}
void DebugDisplay_Prepare(CommandList* cmdList)
{
if (!g_DebugState.Initialized)
{
return;
}
// Render depth-tested primitives
if (g_DebugState.DepthTestedVertexCount > 0 && g_DebugState.DepthTestedBuffer)
{
// Upload vertex data
void* ptr = MapGraphicsTransferBuffer(g_DebugState.Device, g_DebugState.DepthTestedTransfer);
if (ptr)
{
MemCopy(ptr, g_DebugState.DepthTestedVertices, g_DebugState.DepthTestedVertexCount * sizeof(DebugVertex));
UnmapGraphicsTransferBuffer(g_DebugState.Device, g_DebugState.DepthTestedTransfer);
CopyBuffer(cmdList, g_DebugState.DepthTestedBuffer, g_DebugState.DepthTestedTransfer,
g_DebugState.DepthTestedVertexCount * sizeof(DebugVertex));
TransitionBufferToReadable(cmdList, g_DebugState.DepthTestedBuffer);
}
}
// Render overlay primitives
if (g_DebugState.OverlayVertexCount > 0 && g_DebugState.OverlayBuffer)
{
// Upload vertex data
void* ptr = MapGraphicsTransferBuffer(g_DebugState.Device, g_DebugState.OverlayTransfer);
if (ptr)
{
MemCopy(ptr, g_DebugState.OverlayVertices, g_DebugState.OverlayVertexCount * sizeof(DebugVertex));
UnmapGraphicsTransferBuffer(g_DebugState.Device, g_DebugState.OverlayTransfer);
CopyBuffer(cmdList, g_DebugState.OverlayBuffer, g_DebugState.OverlayTransfer,
g_DebugState.OverlayVertexCount * sizeof(DebugVertex));
TransitionBufferToReadable(cmdList, g_DebugState.OverlayBuffer);
}
}
}
void DebugDisplay_Flush(CommandList* cmdList, RenderPass* renderPass, const Camera& camera)
{
if (!g_DebugState.Initialized)
{
return;
}
// Lazy-create pipelines (need swapchain format)
if (!g_DebugState.DepthTestedPipeline)
{
// Use B8G8R8A8_UNORM which matches the SDR swapchain
g_DebugState.DepthTestedPipeline = CreateDebugPipeline(g_DebugState.Device, TextureFormat::B8G8R8A8_UNORM, true);
g_DebugState.OverlayPipeline = CreateDebugPipeline(g_DebugState.Device, TextureFormat::B8G8R8A8_UNORM, false);
}
// Render depth-tested primitives
if (g_DebugState.DepthTestedVertexCount > 0 && g_DebugState.DepthTestedPipeline && g_DebugState.DepthTestedBuffer)
{
BindGraphicsPipeline(renderPass, g_DebugState.DepthTestedPipeline);
// Pack VP matrix + buffer index into push constants
struct {
Matrix vp;
uint32 bufferIndex;
uint32 padding[3];
} pushData;
pushData.vp = Camera_GetViewProjectionMatrix(camera);
pushData.bufferIndex = GetDescriptorIndex(g_DebugState.Device, g_DebugState.DepthTestedBuffer);
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData);
DrawPrimitives(renderPass, g_DebugState.DepthTestedVertexCount, 1, 0, 0);
}
// Render overlay primitives
if (g_DebugState.OverlayVertexCount > 0 && g_DebugState.OverlayPipeline && g_DebugState.OverlayBuffer)
{
BindGraphicsPipeline(renderPass, g_DebugState.OverlayPipeline);
// Pack VP matrix + buffer index into push constants
struct {
Matrix vp;
uint32 bufferIndex;
uint32 padding[3];
} pushData;
pushData.vp = Camera_GetViewProjectionMatrix(camera);
pushData.bufferIndex = GetDescriptorIndex(g_DebugState.Device, g_DebugState.OverlayBuffer);
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData);
DrawPrimitives(renderPass, g_DebugState.OverlayVertexCount, 1, 0, 0);
}
// Clear for next frame
g_DebugState.DepthTestedVertexCount = 0;
g_DebugState.OverlayVertexCount = 0;
}
} // namespace Juliet

View File

@@ -159,6 +159,16 @@ namespace Juliet
return device->GetSwapChainTextureFormat(device->Driver, window); return device->GetSwapChainTextureFormat(device->Driver, window);
} }
Texture* CreateTexture(NonNullPtr<GraphicsDevice> device, const TextureCreateInfo& createInfo)
{
return device->CreateTexture(device->Driver, createInfo);
}
void DestroyTexture(NonNullPtr<GraphicsDevice> device, NonNullPtr<Texture> texture)
{
device->DestroyTexture(device->Driver, texture);
}
CommandList* AcquireCommandList(NonNullPtr<GraphicsDevice> device, QueueType queueType /* = QueueType::Graphics */) CommandList* AcquireCommandList(NonNullPtr<GraphicsDevice> device, QueueType queueType /* = QueueType::Graphics */)
{ {
GPUDriver* driver = device->Driver; GPUDriver* driver = device->Driver;
@@ -185,13 +195,14 @@ namespace Juliet
commandListHeader->Device->SubmitCommandLists(commandList); commandListHeader->Device->SubmitCommandLists(commandList);
} }
RenderPass* BeginRenderPass(NonNullPtr<CommandList> commandList, ColorTargetInfo& colorTargetInfo) RenderPass* BeginRenderPass(NonNullPtr<CommandList> commandList, ColorTargetInfo& colorTargetInfo,
DepthStencilTargetInfo* depthStencilTargetInfo)
{ {
return BeginRenderPass(commandList, &colorTargetInfo, 1); return BeginRenderPass(commandList, &colorTargetInfo, 1, depthStencilTargetInfo);
} }
RenderPass* BeginRenderPass(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos, RenderPass* BeginRenderPass(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos,
uint32 colorTargetInfoCount) uint32 colorTargetInfoCount, DepthStencilTargetInfo* depthStencilTargetInfo)
{ {
if (colorTargetInfoCount > GPUDriver::kMaxColorTargetInfo) if (colorTargetInfoCount > GPUDriver::kMaxColorTargetInfo)
{ {
@@ -200,7 +211,7 @@ namespace Juliet
} }
auto* header = reinterpret_cast<CommandListHeader*>(commandList.Get()); auto* header = reinterpret_cast<CommandListHeader*>(commandList.Get());
header->Device->BeginRenderPass(commandList, colorTargetInfos, colorTargetInfoCount); header->Device->BeginRenderPass(commandList, colorTargetInfos, colorTargetInfoCount, depthStencilTargetInfo);
header->RenderPass.IsInProgress = true; header->RenderPass.IsInProgress = true;
return reinterpret_cast<RenderPass*>(&header->RenderPass); return reinterpret_cast<RenderPass*>(&header->RenderPass);

View File

@@ -59,7 +59,7 @@ namespace Juliet
// RenderPass // RenderPass
void (*BeginRenderPass)(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos, void (*BeginRenderPass)(NonNullPtr<CommandList> commandList, NonNullPtr<const ColorTargetInfo> colorTargetInfos,
uint32 colorTargetInfoCount); uint32 colorTargetInfoCount, const DepthStencilTargetInfo* depthStencilTargetInfo);
void (*EndRenderPass)(NonNullPtr<CommandList> commandList); void (*EndRenderPass)(NonNullPtr<CommandList> commandList);
void (*SetViewPort)(NonNullPtr<CommandList> commandList, const GraphicsViewPort& viewPort); void (*SetViewPort)(NonNullPtr<CommandList> commandList, const GraphicsViewPort& viewPort);
@@ -89,6 +89,10 @@ namespace Juliet
bool (*UpdateGraphicsPipelineShaders)(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsPipeline> graphicsPipeline, bool (*UpdateGraphicsPipelineShaders)(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsPipeline> graphicsPipeline,
Shader* optional_vertexShader, Shader* optional_fragmentShader); Shader* optional_vertexShader, Shader* optional_fragmentShader);
// Textures
Texture* (*CreateTexture)(NonNullPtr<GPUDriver> driver, const TextureCreateInfo& createInfo);
void (*DestroyTexture)(NonNullPtr<GPUDriver> driver, NonNullPtr<Texture> texture);
// Buffers // Buffers
GraphicsBuffer* (*CreateGraphicsBuffer)(NonNullPtr<GPUDriver> driver, size_t size, BufferUsage usage); GraphicsBuffer* (*CreateGraphicsBuffer)(NonNullPtr<GPUDriver> driver, size_t size, BufferUsage usage);
void (*DestroyGraphicsBuffer)(NonNullPtr<GraphicsBuffer> buffer); void (*DestroyGraphicsBuffer)(NonNullPtr<GraphicsBuffer> buffer);

View File

@@ -8,6 +8,8 @@
#include <Core/JulietInit.h> #include <Core/JulietInit.h>
#include <Core/Logging/LogManager.h> #include <Core/Logging/LogManager.h>
#include <Core/Logging/LogTypes.h> #include <Core/Logging/LogTypes.h>
#include <Graphics/Camera.h>
#include <Graphics/DebugDisplay.h>
#include <Graphics/Graphics.h> #include <Graphics/Graphics.h>
#include <Graphics/GraphicsConfig.h> #include <Graphics/GraphicsConfig.h>
#include <Graphics/GraphicsPipeline.h> #include <Graphics/GraphicsPipeline.h>
@@ -93,9 +95,12 @@ void JulietApplication::Init()
pipelineCI.PrimitiveType = PrimitiveType::TriangleList; pipelineCI.PrimitiveType = PrimitiveType::TriangleList;
pipelineCI.TargetInfo = { .ColorTargetDescriptions = &colorTargetDescription, pipelineCI.TargetInfo = { .ColorTargetDescriptions = &colorTargetDescription,
.NumColorTargets = 1, .NumColorTargets = 1,
.DepthStencilFormat = {}, .DepthStencilFormat = TextureFormat::D32_FLOAT,
.HasDepthStencilTarget = false }; .HasDepthStencilTarget = true };
pipelineCI.RasterizerState.FillMode = FillMode::Solid; pipelineCI.RasterizerState.FillMode = FillMode::Solid;
pipelineCI.DepthStencilState.EnableDepthTest = true;
pipelineCI.DepthStencilState.EnableDepthWrite = true;
pipelineCI.DepthStencilState.CompareOperation = CompareOperation::Less;
GraphicsPipeline = CreateGraphicsPipeline(GraphicsDevice, pipelineCI); GraphicsPipeline = CreateGraphicsPipeline(GraphicsDevice, pipelineCI);
if (GraphicsPipeline == nullptr) if (GraphicsPipeline == nullptr)
@@ -104,6 +109,23 @@ void JulietApplication::Init()
Running = false; Running = false;
} }
// Create Depth Buffer
TextureCreateInfo depthCI = {};
depthCI.Type = TextureType::Texture_2D;
depthCI.Width = 1280;
depthCI.Height = 720;
depthCI.Format = TextureFormat::D32_FLOAT;
depthCI.Flags = TextureUsageFlag::DepthStencilTarget;
depthCI.LayerCount = 1;
depthCI.MipLevelCount = 1;
depthCI.SampleCount = TextureSampleCount::One;
DepthBuffer = CreateTexture(GraphicsDevice, depthCI);
if (DepthBuffer == nullptr)
{
LogError(LogCategory::Game, "Failed to create depth buffer!");
Running = false;
}
// Create Buffers // Create Buffers
BufferCreateInfo bufferCI = {}; BufferCreateInfo bufferCI = {};
bufferCI.Size = 256; bufferCI.Size = 256;
@@ -138,6 +160,9 @@ void JulietApplication::Init()
{ {
Game.Init(); Game.Init();
} }
// Initialize DebugDisplay
DebugDisplay_Initialize(GraphicsDevice);
} }
} }
@@ -151,6 +176,12 @@ void JulietApplication::Shutdown()
ShutdownHotReloadCode(GameCode); ShutdownHotReloadCode(GameCode);
} }
// Shutdown DebugDisplay before graphics device
if (GraphicsDevice)
{
DebugDisplay_Shutdown(GraphicsDevice);
}
if (GraphicsPipeline) if (GraphicsPipeline)
{ {
DestroyGraphicsPipeline(GraphicsDevice, GraphicsPipeline); DestroyGraphicsPipeline(GraphicsDevice, GraphicsPipeline);
@@ -163,6 +194,10 @@ void JulietApplication::Shutdown()
{ {
DestroyGraphicsTransferBuffer(GraphicsDevice, TransferBuffer); DestroyGraphicsTransferBuffer(GraphicsDevice, TransferBuffer);
} }
if (DepthBuffer)
{
DestroyTexture(GraphicsDevice, DepthBuffer);
}
if (MainWindow && GraphicsDevice) if (MainWindow && GraphicsDevice)
{ {
@@ -275,7 +310,7 @@ void JulietApplication::Update()
{ {
ColorTargetInfo colorTargetInfo = {}; ColorTargetInfo colorTargetInfo = {};
colorTargetInfo.TargetTexture = swapChainTexture; colorTargetInfo.TargetTexture = swapChainTexture;
colorTargetInfo.ClearColor = { .R = .5f, .G = .8f, .B = .0f, .A = 1.f }; colorTargetInfo.ClearColor = { .R = .0f, .G = .0f, .B = .0f, .A = 1.f };
colorTargetInfo.LoadOperation = LoadOperation::Clear; colorTargetInfo.LoadOperation = LoadOperation::Clear;
colorTargetInfo.StoreOperation = StoreOperation::Store; colorTargetInfo.StoreOperation = StoreOperation::Store;
@@ -303,7 +338,22 @@ void JulietApplication::Update()
TransitionBufferToReadable(cmdList, ConstantBuffer); TransitionBufferToReadable(cmdList, ConstantBuffer);
} }
RenderPass* renderPass = BeginRenderPass(cmdList, colorTargetInfo); // Test lines and sphere - GIANT SCALE
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 10.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f }, false); // X-Axis (Red)
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 10.0f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, true); // Y-Axis (Green)
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 10.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, true); // Z-Axis (Blue) - Up
DebugDisplay_DrawSphere({ 0.0f, 0.0f, 0.0f }, 5.0f, { 1.0f, 1.0f, 0.0f, 1.0f }, true); // Yellow sphere
// Prepare debug data (outside render pass)
DebugDisplay_Prepare(cmdList);
DepthStencilTargetInfo depthTargetInfo = {};
depthTargetInfo.TargetTexture = DepthBuffer;
depthTargetInfo.ClearDepth = 1.0f;
depthTargetInfo.LoadOperation = LoadOperation::Clear;
depthTargetInfo.StoreOperation = StoreOperation::Store;
RenderPass* renderPass = BeginRenderPass(cmdList, colorTargetInfo, &depthTargetInfo);
BindGraphicsPipeline(renderPass, GraphicsPipeline); BindGraphicsPipeline(renderPass, GraphicsPipeline);
// Pass descriptor index via Push Constants AFTER finding the pipeline (RootSignature) // Pass descriptor index via Push Constants AFTER finding the pipeline (RootSignature)
@@ -311,6 +361,23 @@ void JulietApplication::Update()
SetPushConstants(cmdList, ShaderStage::Vertex, 0, 1, &descriptorIndex); SetPushConstants(cmdList, ShaderStage::Vertex, 0, 1, &descriptorIndex);
DrawPrimitives(renderPass, 6, 1, 0, 0); DrawPrimitives(renderPass, 6, 1, 0, 0);
// Debug Display - render shapes (inside render pass)
static float orbitTime = 0.0f;
orbitTime += 0.016f; // Rough approximation for 60fps
float radius = 30.0f;
Camera debugCamera = {};
debugCamera.Position = { cosf(orbitTime) * radius, sinf(orbitTime) * radius, 10.0f }; // Rotate in XY plane
debugCamera.Target = { 0.0f, 0.0f, 0.0f };
debugCamera.Up = { 0.0f, 0.0f, 1.0f }; // Z-Up
debugCamera.FOV = 1.047f; // 60 degrees
debugCamera.AspectRatio = 1200.0f / 800.0f;
debugCamera.NearPlane = 0.1f;
debugCamera.FarPlane = 1000.0f;
DebugDisplay_Flush(cmdList, renderPass, debugCamera);
EndRenderPass(renderPass); EndRenderPass(renderPass);
} }

View File

@@ -29,6 +29,7 @@ class JulietApplication : public Juliet::IApplication
Juliet::GraphicsPipeline* GraphicsPipeline = {}; Juliet::GraphicsPipeline* GraphicsPipeline = {};
Juliet::GraphicsBuffer* ConstantBuffer = {}; Juliet::GraphicsBuffer* ConstantBuffer = {};
Juliet::GraphicsTransferBuffer* TransferBuffer = {}; Juliet::GraphicsTransferBuffer* TransferBuffer = {};
Juliet::Texture* DepthBuffer = {};
bool Running = false; bool Running = false;
}; };

View File

@@ -52,7 +52,7 @@ int main(int argc, char* argv[])
IOClose(outStream); IOClose(outStream);
} }
// Pause here to not close the console window immediately on stop while debugging // Pause here to not close the console window immediately on stop while debugging
__asm int 3; // __asm int 3;
}); });
for (int idx = 1; idx < argc; ++idx) for (int idx = 1; idx < argc; ++idx)

View File

@@ -35,29 +35,40 @@ echo Output Dir: !OUTPUT_DIR!
REM Créer le dossier de sortie s'il n'existe pas REM Créer le dossier de sortie s'il n'existe pas
if not exist "%OUTPUT_DIR%" mkdir "%OUTPUT_DIR%" if not exist "%OUTPUT_DIR%" mkdir "%OUTPUT_DIR%"
REM Parcourir tous les fichiers .frag.hlsl et .vert.hlsl dans le dossier source REM Parcourir tous les fichiers .hlsl dans le dossier source
for %%F in ("%SOURCE_DIR%\*.frag.hlsl" "%SOURCE_DIR%\*.vert.hlsl") do ( for %%F in ("%SOURCE_DIR%\*.hlsl") do (
REM Extraire le nom du fichier sans l'extension set "FULL_FILENAME=%%~nF%%~xF"
set "FILENAME=%%~nF"
REM Extraire l'extension du fichier REM Skip RootConstants.hlsl or other include files
set "EXTENSION=%%~xF" if /I NOT "!FULL_FILENAME!"=="RootConstants.hlsl" (
REM Remplacer .frag.hlsl par frag et .vert.hlsl par vert REM Detect stage from filename (.vert.hlsl, .frag.hlsl)
if "%%~xF"==".frag.hlsl" ( set "SHORT_EXTENSION="
set "BASE_NAME=%%~nF"
echo !FULL_FILENAME! | findstr /I "\.frag\.hlsl" >nul
if !ERRORLEVEL! EQU 0 (
set "SHORT_EXTENSION=frag" set "SHORT_EXTENSION=frag"
) else if "%%~xF"==".vert.hlsl" ( set "BASE_NAME=!BASE_NAME:.frag=!"
) else (
echo !FULL_FILENAME! | findstr /I "\.vert\.hlsl" >nul
if !ERRORLEVEL! EQU 0 (
set "SHORT_EXTENSION=vert" set "SHORT_EXTENSION=vert"
set "BASE_NAME=!BASE_NAME:.vert=!"
) )
REM Construire la ligne de commande )
set "COMMAND=%COMPILER_PATH% %SOURCE_DIR%\!FILENAME!!EXTENSION! -o %OUTPUT_DIR%\!FILENAME!!SHORT_EXTENSION!.dxil"
echo !COMMAND! if not "!SHORT_EXTENSION!"=="" (
REM Afficher la ligne de commande pour le débogage set "OUTPUT_FILE=%OUTPUT_DIR%\%%~nF.dxil"
echo Compiling: !FILENAME!!EXTENSION! set "COMMAND=%COMPILER_PATH% %%F -o !OUTPUT_FILE!"
REM Appeler JulietShaderCompiler.exe avec les arguments spécifiés
echo Compiling: %%F to !OUTPUT_FILE!
!COMMAND! !COMMAND!
if !ERRORLEVEL! NEQ 0 ( if errorlevel 1 (
echo ERREUR lors de la compilation de %%F echo ERREUR lors de la compilation de %%F
) )
)
)
) )
echo. echo.