Support lighting using a graphics buffer that is kep open!

This commit is contained in:
Patedam committed 2026-02-23 19:24:57 -05:00
1 parent 4312ecd172
commit 3277624ec2
26 files changed
+320 -124

No files matched your search

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+11
View File
@@ -1,6 +1,14 @@
#ifndef ROOT_CONSTANTS_HLSL
#define ROOT_CONSTANTS_HLSL
struct PointLight
{
float3 Position;
float Radius;
float3 Color;
float Intensity;
};
cbuffer RootConstants : register(b0, space0)
{
row_major float4x4 ViewProjection;
@@ -16,6 +24,9 @@ cbuffer RootConstants : register(b0, space0)
float LightPad;
float3 LightColor;
float AmbientIntensity;
uint LightBufferIndex;
uint ActiveLightCount;
};
+42 -6
View File
@@ -1,10 +1,46 @@
#include "RootConstants.hlsl"
float4 main(float4 Color : TEXCOORD0, float3 WorldNormal : TEXCOORD1) : SV_Target0
struct Input
{
float3 N = normalize(WorldNormal);
float NdotL = saturate(dot(N, -LightDirection));
float3 diffuse = Color.rgb * LightColor * NdotL;
float3 ambient = Color.rgb * AmbientIntensity;
return float4(diffuse + ambient, Color.a);
float4 Color : TEXCOORD0;
float3 WorldNormal : TEXCOORD1;
float3 WorldPosition : TEXCOORD2;
};
float4 main(Input input) : SV_Target0
{
float3 normal = normalize(input.WorldNormal);
// Initial ambient component
float3 result = input.Color.rgb * LightColor * AmbientIntensity;
// Directional light contribution
float ndotl = max(dot(normal, -LightDirection), 0.0);
result += input.Color.rgb * LightColor * ndotl;
// Point lights
if (ActiveLightCount > 0)
{
StructuredBuffer<PointLight> pointLights = ResourceDescriptorHeap[LightBufferIndex];
for (uint i = 0; i < ActiveLightCount; ++i)
{
PointLight light = pointLights[i];
float3 lightDir = light.Position - input.WorldPosition;
float dist = length(lightDir);
if (dist < light.Radius)
{
lightDir = normalize(lightDir);
float attenuation = 1.0 - (dist / light.Radius);
attenuation = max(attenuation, 0.0);
float pndotl = max(dot(normal, lightDir), 0.0);
result += light.Color * input.Color.rgb * pndotl * attenuation * light.Intensity;
}
}
}
return float4(result, input.Color.a);
}
+4 -1
View File
@@ -2,6 +2,7 @@ struct Output
{
float4 Color : TEXCOORD0;
float3 WorldNormal : TEXCOORD1;
float3 WorldPosition : TEXCOORD2;
float4 Position : SV_Position;
};
@@ -20,8 +21,10 @@ Output main(uint vertexIndex : SV_VertexID)
float3 normal = asfloat(buffer.Load3(offset + 12));
float4 col = asfloat(buffer.Load4(offset + 24));
output.Position = mul(ViewProjection, mul(Model, float4(pos, 1.0f)));
float4 worldPos = mul(Model, float4(pos, 1.0f));
output.Position = mul(ViewProjection, worldPos);
output.Color = col;
output.WorldPosition = worldPos.xyz;
float3 worldNormal = mul((float3x3)Model, normal);
output.WorldNormal = worldNormal;
+7 -2
View File
@@ -193,11 +193,16 @@ namespace Juliet
{
Assert(Arena);
if (InternalArena)
{
ArenaClear(Arena);
DataFirst = DataLast = nullptr;
Data = nullptr;
Count = 0;
Capacity = 0;
Reserve(ReserveSize);
}
DataFirst = DataLast = nullptr;
Count = 0;
}
bool IsEmpty() const { return Count == 0; }
+1
View File
@@ -37,6 +37,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
(void)hPrev;
(void)szCmdLine;
(void)sw;
return Juliet::Bootstrap(JulietMain, __argc, __wargv);
}
}
+7
View File
@@ -81,6 +81,13 @@ namespace Juliet
return result;
}
inline void MatrixTranslate(Matrix& m, const Vector3& v)
{
m.m[0][3] += v.x;
m.m[1][3] += v.y;
m.m[2][3] += v.z;
}
[[nodiscard]] inline Matrix MatrixRotation(float x, float y, float z)
{
return MatrixRotationX(x) * MatrixRotationY(y) * MatrixRotationZ(z);
+2
View File
@@ -164,6 +164,8 @@ namespace Juliet
extern JULIET_API GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GraphicsDevice> device, const BufferCreateInfo& createInfo);
extern JULIET_API GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device,
const TransferBufferCreateInfo& createInfo);
extern JULIET_API void* MapGraphicsBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsBuffer> buffer);
extern JULIET_API void UnmapGraphicsBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsBuffer> buffer);
extern JULIET_API void* MapGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsTransferBuffer> buffer);
extern JULIET_API void UnmapGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsTransferBuffer> buffer);
extern JULIET_API void CopyBuffer(NonNullPtr<CommandList> commandList, NonNullPtr<GraphicsBuffer> dst,
+2 -1
View File
@@ -8,7 +8,6 @@ namespace Juliet
IndexBuffer = 1 << 0,
ConstantBuffer = 1 << 1,
StructuredBuffer = 1 << 2,
VertexBuffer = 1 << 3,
};
enum class TransferBufferUsage : uint8
@@ -20,7 +19,9 @@ namespace Juliet
struct BufferCreateInfo
{
size_t Size;
size_t Stride;
BufferUsage Usage;
bool IsDynamic;
};
struct TransferBufferCreateInfo
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <Juliet.h>
#include <Core/Math/Vector.h>
namespace Juliet
{
struct PointLight
{
Vector3 Position;
float Radius;
Vector3 Color;
float Intensity;
};
} // namespace Juliet
+13
View File
@@ -2,6 +2,7 @@
#include <Core/Container/Vector.h>
#include <Core/Math/Matrix.h>
#include <Graphics/Lighting.h>
#include <Graphics/PushConstants.h>
#include <Graphics/VertexData.h>
#include <Juliet.h>
@@ -18,12 +19,14 @@ namespace Juliet
struct Mesh;
using MeshID = index_t;
using LightID = index_t;
constexpr size_t kGeometryPage = Megabytes(64);
constexpr size_t kIndexPage = Megabytes(32);
constexpr size_t kDefaultMeshNumber = 500;
constexpr size_t kDefaultVertexCount = 2'000'000; // Fit less than one geometry page
constexpr size_t kDefaultIndexCount = 16'000'000; // Fit less than one index page
constexpr size_t kDefaultLightCount = 1024;
struct MeshRenderer
{
@@ -31,12 +34,16 @@ namespace Juliet
VectorArena<Mesh, kDefaultMeshNumber, false> Meshes;
VectorArena<Vertex, kDefaultVertexCount, false> Vertices;
VectorArena<Index, kDefaultIndexCount, false> Indices;
VectorArena<PointLight, kDefaultLightCount, false> PointLights;
GraphicsBuffer* VertexBuffer;
GraphicsBuffer* IndexBuffer;
GraphicsTransferBuffer* StreamCopyBuffer;
GraphicsTransferBuffer* LoadCopyBuffer;
GraphicsBuffer* LightsBuffer;
PointLight* MappedLights;
GraphicsDevice* Device;
GraphicsPipeline* Pipeline;
};
@@ -48,6 +55,12 @@ namespace Juliet
JULIET_API void LoadMeshesOnGPU(NonNullPtr<CommandList> cmdList);
JULIET_API void RenderMeshes(NonNullPtr<RenderPass> pass, NonNullPtr<CommandList> cmdList, PushData& pushData);
// Lights
[[nodiscard]] JULIET_API LightID AddPointLight(const PointLight& light);
JULIET_API void SetPointLightPosition(LightID id, const Vector3& position);
JULIET_API void SetPointLightColor(LightID id, const Vector3& color);
JULIET_API void ClearPointLights();
// Utils
[[nodiscard]] JULIET_API MeshID AddCube();
[[nodiscard]] JULIET_API MeshID AddQuad();
+3
View File
@@ -21,5 +21,8 @@ namespace Juliet
float LightPad;
Vector3 LightColor;
float AmbientIntensity;
uint32 LightBufferIndex;
uint32 ActiveLightCount;
};
} // namespace Juliet
+3 -9
View File
@@ -17,7 +17,7 @@ namespace Juliet
{
Byte* OS_Reserve(size_t size)
{
auto result = static_cast<Byte*>(VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE));
auto* result = static_cast<Byte*>(VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE));
return result;
}
@@ -68,8 +68,6 @@ namespace Juliet
{
int OS_Main(EntryPointFunc entryPointFunc, int argc, wchar_t** argv)
{
(void)argc;
(void)argv;
SetUnhandledExceptionFilter(&ExceptionFilter);
// Allow only one instance to be launched.
@@ -87,12 +85,8 @@ namespace Juliet
GUID guid = WSAID_MULTIPLE_RIO;
DWORD rio_byte = 0;
SOCKET Sock = socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
int result = WSAIoctl(Sock, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
(void**)&w32_rio_functions, sizeof(w32_rio_functions), &rio_byte, nullptr, nullptr);
if (result != 0)
{
LogError(LogCategory::Core, "Couldnt get w32 RIO Functions. Error code %d", result);
}
WSAIoctl(Sock, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
reinterpret_cast<void**>(&w32_rio_functions), sizeof(w32_rio_functions), &rio_byte, nullptr, nullptr);
closesocket(Sock);
}
+65 -65
View File
@@ -38,7 +38,6 @@ namespace Juliet::D3D12
case BufferUsage::ConstantBuffer: return "ConstantBuffer";
case BufferUsage::StructuredBuffer: return "StructuredBuffer";
case BufferUsage::IndexBuffer: return "IndexBuffer";
case BufferUsage::VertexBuffer: return "VertexBuffer";
}
return "Unknown";
}
@@ -62,96 +61,63 @@ namespace Juliet::D3D12
Free(buffer);
}
D3D12Buffer* CreateBuffer(NonNullPtr<D3D12Driver> d3d12Driver, size_t size, BufferUsage usage, D3D12BufferType type)
D3D12Buffer* CreateBuffer(NonNullPtr<D3D12Driver> d3d12Driver, size_t size, size_t stride, BufferUsage usage,
D3D12BufferType type, bool isDynamic)
{
auto buffer = static_cast<D3D12Buffer*>(Calloc(1, sizeof(D3D12Buffer)));
auto* buffer = static_cast<D3D12Buffer*>(Calloc(1, sizeof(D3D12Buffer)));
if (!buffer)
{
return nullptr;
}
if (type == D3D12BufferType::Base && usage == BufferUsage::None)
{
Assert(false, "Creating Base buffer with BufferUsage::None is invalid");
DestroyBuffer(buffer);
return nullptr;
}
// Align size for Constant Buffers
if (usage == BufferUsage::ConstantBuffer)
{
size = (size + 255U) & ~255U;
}
D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON;
D3D12_HEAP_PROPERTIES heapProperties = {};
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON;
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;
switch (type)
{
case D3D12BufferType::Base:
{
switch (usage)
{
case BufferUsage::None:
{
Assert(false, "Creating buffer with invalid usage");
DestroyBuffer(buffer);
return nullptr;
}
// Constant buffers or Dynamic buffers generally need to be uploaded every frame
const bool isUpload = isDynamic || (type == D3D12BufferType::TransferUpload) || (usage == BufferUsage::ConstantBuffer);
case BufferUsage::IndexBuffer:
case BufferUsage::StructuredBuffer:
case BufferUsage::VertexBuffer:
{
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heapFlags = D3D12_HEAP_FLAG_NONE;
break;
}
case BufferUsage::ConstantBuffer:
{
if (d3d12Driver->GPUUploadHeapSupported)
{
heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD;
}
else
{
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
heapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
}
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
break;
}
}
break;
}
case D3D12BufferType::TransferDownload:
if (type == D3D12BufferType::TransferDownload)
{
heapProperties.Type = D3D12_HEAP_TYPE_READBACK;
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heapFlags = D3D12_HEAP_FLAG_NONE;
initialState = D3D12_RESOURCE_STATE_COPY_DEST;
break;
}
case D3D12BufferType::TransferUpload:
else if (isUpload)
{
if (d3d12Driver->GPUUploadHeapSupported)
{
heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD;
initialState = D3D12_RESOURCE_STATE_COMMON;
}
else
{
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
heapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
}
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
break;
}
else
{
// Must be a static buffer (Base type)
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
initialState = D3D12_RESOURCE_STATE_COMMON;
}
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
D3D12_RESOURCE_DESC desc = {};
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Alignment = 0;
@@ -167,20 +133,22 @@ namespace Juliet::D3D12
Log(LogLevel::Message, LogCategory::Graphics, "CreateBuffer: Device=%p, Size=%zu, Type=%s Use=%s",
(void*)d3d12Driver->D3D12Device, size, D3D12BufferTypeToString(type), BufferUsageToString(usage));
ID3D12Resource* handle = nullptr;
HRESULT result = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProperties, heapFlags, &desc,
initialState, nullptr, IID_ID3D12Resource,
reinterpret_cast<void**>(&handle));
if (FAILED(result))
{
Log(LogLevel::Error, LogCategory::Graphics, "Could not create buffer! HRESULT=0x%08X", (uint32)result);
Log(LogLevel::Error, LogCategory::Graphics, "Could not create buffer! HRESULT=0x%08X", static_cast<uint32>(result));
Log(LogLevel::Error, LogCategory::Graphics, "Failed Desc: Width=%llu Layout=%d HeapType=%d",
(unsigned long long)desc.Width, (int)desc.Layout, (int)heapProperties.Type);
HRESULT removeReason = d3d12Driver->D3D12Device->GetDeviceRemovedReason();
if (FAILED(removeReason))
{
Log(LogLevel::Error, LogCategory::Graphics, "Device Removed Reason: 0x%08X", (uint32)removeReason);
Log(LogLevel::Error, LogCategory::Graphics, "Device Removed Reason: 0x%08X", static_cast<uint32>(removeReason));
}
DestroyBuffer(buffer);
@@ -205,6 +173,7 @@ namespace Juliet::D3D12
if (usage == BufferUsage::ConstantBuffer)
{
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
cbvDesc.BufferLocation = handle->GetGPUVirtualAddress();
cbvDesc.SizeInBytes = static_cast<uint32>(size);
d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle);
@@ -212,13 +181,25 @@ namespace Juliet::D3D12
else if (usage == BufferUsage::StructuredBuffer)
{
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.Buffer.FirstElement = 0;
if (stride > 0)
{
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
srvDesc.Buffer.NumElements = static_cast<uint32>(size / stride);
srvDesc.Buffer.StructureByteStride = static_cast<uint32>(stride);
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
}
else
{
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
srvDesc.Buffer.NumElements = static_cast<uint32>(size / 4);
srvDesc.Buffer.StructureByteStride = 0;
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
}
d3d12Driver->D3D12Device->CreateShaderResourceView(handle, &srvDesc, cpuHandle);
Log(LogLevel::Message, LogCategory::Graphics, " -> SRV DescriptorIndex=%u", descriptor.Index);
}
@@ -233,10 +214,10 @@ namespace Juliet::D3D12
}
} // namespace
GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GPUDriver> driver, size_t size, BufferUsage usage)
GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GPUDriver> driver, size_t size, size_t stride, BufferUsage usage, bool isDynamic)
{
auto d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
return reinterpret_cast<GraphicsBuffer*>(CreateBuffer(d3d12Driver, size, usage, D3D12BufferType::Base));
return reinterpret_cast<GraphicsBuffer*>(CreateBuffer(d3d12Driver, size, stride, usage, D3D12BufferType::Base, isDynamic));
}
void DestroyGraphicsBuffer(NonNullPtr<GraphicsBuffer> buffer)
@@ -248,8 +229,9 @@ namespace Juliet::D3D12
{
auto d3d12Driver = static_cast<D3D12Driver*>(driver.Get());
return reinterpret_cast<GraphicsTransferBuffer*>(
CreateBuffer(d3d12Driver, size, BufferUsage::None,
usage == TransferBufferUsage::Upload ? D3D12BufferType::TransferUpload : D3D12BufferType::TransferDownload));
CreateBuffer(d3d12Driver, size, 0, BufferUsage::None,
usage == TransferBufferUsage::Upload ? D3D12BufferType::TransferUpload : D3D12BufferType::TransferDownload,
false));
}
void DestroyGraphicsTransferBuffer(NonNullPtr<GraphicsTransferBuffer> buffer)
@@ -276,6 +258,24 @@ namespace Juliet::D3D12
d3d12Buffer->Handle->Unmap(0, nullptr);
}
void* MapBuffer(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<GraphicsBuffer> buffer)
{
auto d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
void* ptr = nullptr;
D3D12_RANGE readRange = { 0, 0 };
if (FAILED(d3d12Buffer->Handle->Map(0, &readRange, &ptr)))
{
return nullptr;
}
return ptr;
}
void UnmapBuffer(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<GraphicsBuffer> buffer)
{
auto d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
d3d12Buffer->Handle->Unmap(0, nullptr);
}
uint32 GetDescriptorIndex(NonNullPtr<GPUDriver> /*driver*/, NonNullPtr<GraphicsBuffer> buffer)
{
auto d3d12Buffer = reinterpret_cast<D3D12Buffer*>(buffer.Get());
+1 -1
View File
@@ -20,7 +20,7 @@ namespace Juliet::D3D12
size_t Size;
};
extern GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GPUDriver> driver, size_t size, BufferUsage usage);
extern GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GPUDriver> driver, size_t size, size_t stride, BufferUsage usage, bool isDynamic);
extern void DestroyGraphicsBuffer(NonNullPtr<GraphicsBuffer> buffer);
extern GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr<GPUDriver> driver, size_t size, TransferBufferUsage usage);
@@ -1034,6 +1034,8 @@ namespace Juliet::D3D12
device->DestroyGraphicsPipeline = DestroyGraphicsPipeline;
device->CreateGraphicsBuffer = CreateGraphicsBuffer;
device->DestroyGraphicsBuffer = DestroyGraphicsBuffer;
device->MapGraphicsBuffer = MapBuffer;
device->UnmapGraphicsBuffer = UnmapBuffer;
device->CreateGraphicsTransferBuffer = CreateGraphicsTransferBuffer;
device->DestroyGraphicsTransferBuffer = DestroyGraphicsTransferBuffer;
device->MapGraphicsTransferBuffer = MapBuffer;
+11 -1
View File
@@ -371,7 +371,7 @@ namespace Juliet
GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr<GraphicsDevice> device, const BufferCreateInfo& createInfo)
{
return device->CreateGraphicsBuffer(device->Driver, createInfo.Size, createInfo.Usage);
return device->CreateGraphicsBuffer(device->Driver, createInfo.Size, createInfo.Stride, createInfo.Usage, createInfo.IsDynamic);
}
GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device, const TransferBufferCreateInfo& createInfo)
@@ -379,6 +379,16 @@ namespace Juliet
return device->CreateGraphicsTransferBuffer(device->Driver, createInfo.Size, createInfo.Usage);
}
void* MapGraphicsBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsBuffer> buffer)
{
return device->MapGraphicsBuffer(device->Driver, buffer);
}
void UnmapGraphicsBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsBuffer> buffer)
{
device->UnmapGraphicsBuffer(device->Driver, buffer);
}
void* MapGraphicsTransferBuffer(NonNullPtr<GraphicsDevice> device, NonNullPtr<GraphicsTransferBuffer> buffer)
{
return device->MapGraphicsTransferBuffer(device->Driver, buffer);
+4 -1
View File
@@ -100,9 +100,12 @@ namespace Juliet
void (*DestroyTexture)(NonNullPtr<GPUDriver> driver, NonNullPtr<Texture> texture);
// Buffers
GraphicsBuffer* (*CreateGraphicsBuffer)(NonNullPtr<GPUDriver> driver, size_t size, BufferUsage usage);
GraphicsBuffer* (*CreateGraphicsBuffer)(NonNullPtr<GPUDriver> driver, size_t size, size_t stride, BufferUsage usage, bool isDynamic);
void (*DestroyGraphicsBuffer)(NonNullPtr<GraphicsBuffer> buffer);
void* (*MapGraphicsBuffer)(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsBuffer> buffer);
void (*UnmapGraphicsBuffer)(NonNullPtr<GPUDriver> driver, NonNullPtr<GraphicsBuffer> buffer);
GraphicsTransferBuffer* (*CreateGraphicsTransferBuffer)(NonNullPtr<GPUDriver> driver, size_t size, TransferBufferUsage usage);
void (*DestroyGraphicsTransferBuffer)(NonNullPtr<GraphicsTransferBuffer> buffer);
+18 -28
View File
@@ -150,8 +150,8 @@ namespace Juliet
TextureCreateInfo texCI = {};
texCI.Type = TextureType::Texture_2D;
texCI.Width = (uint32)width;
texCI.Height = (uint32)height;
texCI.Width = static_cast<uint32>(width);
texCI.Height = static_cast<uint32>(height);
texCI.Format = TextureFormat::R8G8B8A8_UNORM;
texCI.Flags = TextureUsageFlag::Sampler;
@@ -160,10 +160,10 @@ namespace Juliet
texCI.SampleCount = TextureSampleCount::One;
g_ImGuiState.FontTexture = CreateTexture(device, texCI);
io.Fonts->SetTexID((ImTextureID)g_ImGuiState.FontTexture);
io.Fonts->SetTexID(reinterpret_cast<ImTextureID>(g_ImGuiState.FontTexture));
// Upload data
uint32 rowPitch = (uint32)width * 4u;
uint32 rowPitch = static_cast<uint32>(width) * 4u;
uint32 alignedRowPitch = (rowPitch + 255u) & ~255u;
uint32 textureSize = alignedRowPitch * static_cast<uint32>(height);
@@ -177,7 +177,7 @@ namespace Juliet
return false;
}
auto dst = (uint8*)MapGraphicsTransferBuffer(device, tb);
auto* dst = static_cast<uint8*>(MapGraphicsTransferBuffer(device, tb));
for (uint32 y = 0; y < static_cast<uint32>(height); ++y)
{
@@ -315,13 +315,13 @@ namespace Juliet
FrameResources& currentFrame = g_ImGuiState.Frames[g_ImGuiState.FrameIndex];
// Upload Buffers
uint32 totalVtx = (uint32)drawData->TotalVtxCount;
uint32 totalIdx = (uint32)drawData->TotalIdxCount;
uint32 totalVtx = static_cast<uint32>(drawData->TotalVtxCount);
uint32 totalIdx = static_cast<uint32>(drawData->TotalIdxCount);
EnsureBufferSize(currentFrame, totalVtx * sizeof(ImDrawVert), totalIdx * sizeof(ImDrawIdx));
auto vtxDst = (ImDrawVert*)MapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.VertexUpload);
auto idxDst = (ImDrawIdx*)MapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.IndexUpload);
auto* vtxDst = static_cast<ImDrawVert*>(MapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.VertexUpload));
auto* idxDst = static_cast<ImDrawIdx*>(MapGraphicsTransferBuffer(g_ImGuiState.Device, currentFrame.IndexUpload));
for (int n = 0; n < drawData->CmdListsCount; n++)
{
@@ -403,28 +403,18 @@ namespace Juliet
SetScissorRect(renderPass, scissorRect);
// Bind Texture
uint32 textureIndex = GetDescriptorIndex(g_ImGuiState.Device, (Texture*)pcmd->GetTexID());
uint32 textureIndex = GetDescriptorIndex(g_ImGuiState.Device, reinterpret_cast<Texture*>(pcmd->GetTexID()));
// Push Constants
// Layout: ViewProjection(64) + BufferIndex(4) + TextureIndex(4) + VertexOffset(4) + Padding(4) + Scale(8) + Translate(8)
struct
{
float dummyVP[16]; // Occupy VP slot
uint32 bufferIndex;
uint32 textureIndex;
uint32 vertexOffset; // Base vertex for indexed bindless drawing
uint32 padding; // Alignment padding
float scale[2];
float translate[2];
} pushData = {}; // Zero-initialize all fields
PushData pushData = {}; // Zero-initialize all fields
pushData.bufferIndex = GetDescriptorIndex(g_ImGuiState.Device, currentFrame.VertexBuffer);
pushData.textureIndex = textureIndex;
pushData.vertexOffset = pcmd->VtxOffset + globalVtxOffset; // Pass vertex offset for bindless
pushData.scale[0] = scale[0];
pushData.scale[1] = scale[1];
pushData.translate[0] = translate[0];
pushData.translate[1] = translate[1];
pushData.BufferIndex = GetDescriptorIndex(g_ImGuiState.Device, currentFrame.VertexBuffer);
pushData.TextureIndex = textureIndex;
pushData.VertexOffset = pcmd->VtxOffset + globalVtxOffset; // Pass vertex offset for bindless
pushData.Scale[0] = scale[0];
pushData.Scale[1] = scale[1];
pushData.Translate[0] = translate[0];
pushData.Translate[1] = translate[1];
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
+73 -1
View File
@@ -20,6 +20,7 @@ namespace Juliet
g_MeshRenderer.Meshes.Create(arena JULIET_DEBUG_PARAM("Meshes"));
g_MeshRenderer.Vertices.Create(arena JULIET_DEBUG_PARAM("Vertices"));
g_MeshRenderer.Indices.Create(arena JULIET_DEBUG_PARAM("Indices"));
g_MeshRenderer.PointLights.Create(arena JULIET_DEBUG_PARAM("PointLights"));
}
bool InitializeMeshRendererGraphics(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window)
@@ -53,6 +54,8 @@ namespace Juliet
.DepthStencilFormat = TextureFormat::D32_FLOAT,
.HasDepthStencilTarget = true };
pipelineCI.RasterizerState.FillMode = FillMode::Solid;
pipelineCI.RasterizerState.CullMode = CullMode::None;
pipelineCI.RasterizerState.FrontFace = FrontFace::Clockwise;
pipelineCI.DepthStencilState.EnableDepthTest = true;
pipelineCI.DepthStencilState.EnableDepthWrite = true;
pipelineCI.DepthStencilState.CompareOperation = CompareOperation::Less;
@@ -67,13 +70,33 @@ namespace Juliet
// Create the vertex and index buffers
BufferCreateInfo vertexBufferCI = {};
vertexBufferCI.Size = kGeometryPage;
vertexBufferCI.Stride = 0;
vertexBufferCI.Usage = BufferUsage::StructuredBuffer;
g_MeshRenderer.VertexBuffer = CreateGraphicsBuffer(graphicsDevice, vertexBufferCI);
Assert(g_MeshRenderer.VertexBuffer != nullptr);
BufferCreateInfo indexBufferCI = {};
indexBufferCI.Size = kIndexPage;
indexBufferCI.Usage = BufferUsage::IndexBuffer;
g_MeshRenderer.IndexBuffer = CreateGraphicsBuffer(graphicsDevice, indexBufferCI);
Assert(g_MeshRenderer.IndexBuffer != nullptr);
// Lights Buffer
BufferCreateInfo lightsBufferCI = {};
lightsBufferCI.Size = 1024 * sizeof(PointLight); // Max 1024 lights for now
lightsBufferCI.Stride = sizeof(PointLight);
lightsBufferCI.Usage = BufferUsage::StructuredBuffer;
lightsBufferCI.IsDynamic = true;
g_MeshRenderer.LightsBuffer = CreateGraphicsBuffer(graphicsDevice, lightsBufferCI);
Assert(g_MeshRenderer.LightsBuffer != nullptr);
g_MeshRenderer.MappedLights = static_cast<PointLight*>(MapGraphicsBuffer(graphicsDevice, g_MeshRenderer.LightsBuffer));
Assert(g_MeshRenderer.MappedLights != nullptr);
// Sync existing lights that might have been added before graphics initialization
for (index_t i = 0; i < g_MeshRenderer.PointLights.Count; ++i)
{
g_MeshRenderer.MappedLights[i] = g_MeshRenderer.PointLights.Data[i];
}
if (vertexShader)
{
@@ -88,7 +111,6 @@ namespace Juliet
CommandList* loadCmd = AcquireCommandList(device);
LoadMeshesOnGPU(loadCmd);
SubmitCommandLists(loadCmd);
return result;
}
@@ -103,6 +125,12 @@ namespace Juliet
DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.IndexBuffer);
DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer);
if (g_MeshRenderer.LightsBuffer)
{
UnmapGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer);
DestroyGraphicsBuffer(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer);
}
}
void ShutdownMeshRenderer()
@@ -110,6 +138,7 @@ namespace Juliet
g_MeshRenderer.Indices.Destroy();
g_MeshRenderer.Vertices.Destroy();
g_MeshRenderer.Meshes.Destroy();
g_MeshRenderer.PointLights.Destroy();
}
void LoadMeshesOnGPU(NonNullPtr<CommandList> cmdList)
@@ -159,6 +188,8 @@ namespace Juliet
MemCopy(ptrOneByte + indexOfByteOffset, g_MeshRenderer.Indices.Data, totalIndexBytes);
UnmapGraphicsTransferBuffer(g_MeshRenderer.Device, g_MeshRenderer.LoadCopyBuffer);
CopyBuffer(cmdList, g_MeshRenderer.VertexBuffer, g_MeshRenderer.LoadCopyBuffer, totalVertexBytes, 0, 0);
CopyBuffer(cmdList, g_MeshRenderer.IndexBuffer, g_MeshRenderer.LoadCopyBuffer, totalIndexBytes, 0, indexOfByteOffset);
@@ -181,8 +212,11 @@ namespace Juliet
BindGraphicsPipeline(pass, g_MeshRenderer.Pipeline);
uint32 vertexDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer);
uint32 lightDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.LightsBuffer);
pushData.BufferIndex = vertexDescriptorIndex;
pushData.LightBufferIndex = lightDescriptorIndex;
pushData.ActiveLightCount = static_cast<uint32>(g_MeshRenderer.PointLights.Count);
SetIndexBuffer(cmdList, g_MeshRenderer.IndexBuffer, IndexFormat::UInt16, g_MeshRenderer.Indices.Count, 0);
@@ -202,6 +236,43 @@ namespace Juliet
}
}
LightID AddPointLight(const PointLight& light)
{
Assert(g_MeshRenderer.PointLights.Count < kDefaultLightCount);
LightID id = g_MeshRenderer.PointLights.Count;
g_MeshRenderer.PointLights.PushBack(light);
if (g_MeshRenderer.MappedLights)
{
g_MeshRenderer.MappedLights[id] = light;
}
return id;
}
void SetPointLightPosition(LightID id, const Vector3& position)
{
Assert(id < static_cast<LightID>(g_MeshRenderer.PointLights.Count));
g_MeshRenderer.PointLights.Data[id].Position = position;
if (g_MeshRenderer.MappedLights)
{
g_MeshRenderer.MappedLights[id].Position = position;
}
}
void SetPointLightColor(LightID id, const Vector3& color)
{
Assert(id < static_cast<LightID>(g_MeshRenderer.PointLights.Count));
g_MeshRenderer.PointLights.Data[id].Color = color;
if (g_MeshRenderer.MappedLights)
{
g_MeshRenderer.MappedLights[id].Color = color;
}
}
void ClearPointLights()
{
g_MeshRenderer.PointLights.Clear();
}
MeshID AddCube()
{
Mesh result = {};
@@ -300,6 +371,7 @@ namespace Juliet
Assert(id < static_cast<MeshID>(g_MeshRenderer.Meshes.Count));
g_MeshRenderer.Meshes.Data[id].Transform = transform;
}
#if ALLOW_SHADER_HOT_RELOAD
void ReloadMeshRendererShaders()
{
+36 -8
View File
@@ -1,5 +1,12 @@
#include "main.h"
#ifdef global
#undef global
#endif
#include <ios>
#include <iosfwd>
#define global static
#include <Core/Application/ApplicationManager.h>
#include <Core/Common/EnumUtils.h>
#include <Core/Common/String.h>
@@ -44,13 +51,6 @@ static bool ShowMemoryDebugger = false;
using namespace Juliet;
extern "C" {
__declspec(dllexport) extern const unsigned int D3D12SDKVersion = 615;
}
extern "C" {
__declspec(dllexport) extern const char* D3D12SDKPath = ".\\";
}
namespace
{
using GameInit_t = void (*)(GameInitParams*);
@@ -64,6 +64,9 @@ namespace
} Game;
const char* GameFunctionTable[] = { "GameInit", "GameShutdown", "GameUpdate" };
LightID RedLightID = 0;
LightID BlueLightID = 0;
} // namespace
void JulietApplication::Init(NonNullPtr<Arena>)
@@ -75,6 +78,7 @@ void JulietApplication::Init(NonNullPtr<Arena>)
#if JULIET_DEBUG
config.EnableDebug = true;
#endif
GraphicsDevice = CreateGraphicsDevice(config);
MainWindow = CreatePlatformWindow("Juliet Editor", 1280, 720);
@@ -119,6 +123,21 @@ void JulietApplication::Init(NonNullPtr<Arena>)
SetMeshTransform(cube, MatrixTranslation(x, y, 0.0f) * rotation);
}
}
// Start with some default test lights
PointLight redLight = {};
redLight.Position = { 5.0f, 5.0f, 2.0f };
redLight.Radius = 10.0f;
redLight.Color = { 1.0f, 0.2f, 0.2f };
redLight.Intensity = 5.0f;
RedLightID = AddPointLight(redLight);
PointLight blueLight = {};
blueLight.Position = { -5.0f, 0.0f, 2.0f };
blueLight.Radius = 15.0f;
blueLight.Color = { 0.2f, 0.2f, 1.0f };
blueLight.Intensity = 8.0f;
BlueLightID = AddPointLight(blueLight);
}
GameCode.Functions = reinterpret_cast<void**>(&Game);
@@ -232,14 +251,23 @@ void JulietApplication::Update()
}
}
ArenaClear(GameScratchArena);
Vector3 redLightPos{ cosf(CameraTime * 2.0f) * 5.0f, sinf(CameraTime * 2.0f) * 5.0f, 2.0f };
SetPointLightPosition(RedLightID, redLightPos);
Vector3 blueLightPos{ -5.0f, cosf(CameraTime) * 3.0f, 2.0f };
SetPointLightPosition(BlueLightID, blueLightPos);
#ifdef JULIET_ENABLE_IMGUI
// ImGui::ShowDemoWindow();
ImGui::ShowDemoWindow();
#endif
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f }, false);
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, true);
DebugDisplay_DrawLine({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, true);
DebugDisplay_DrawSphere({ 0.0f, 0.0f, 0.0f }, 0.5f, { 1.0f, 1.0f, 0.0f, 1.0f }, true);
DebugDisplay_DrawSphere(blueLightPos, 0.5f, { 0.0f, 0.0f, 1.0f, 1.0f }, true);
DebugDisplay_DrawSphere(redLightPos, 0.5f, { 1.0f, 0.0f, 0.0f, 1.0f }, true);
Game.Update(0.0f);