diff --git a/Juliet/include/Graphics/Graphics.h b/Juliet/include/Graphics/Graphics.h index 1d519cf..7834f96 100644 --- a/Juliet/include/Graphics/Graphics.h +++ b/Juliet/include/Graphics/Graphics.h @@ -117,5 +117,6 @@ namespace Juliet // Pipelines extern JULIET_API GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr device, const GraphicsPipelineCreateInfo& createInfo); + extern JULIET_API void DestroyGraphicsPipeline(NonNullPtr device, NonNullPtr graphicsPipeline); } // namespace Juliet diff --git a/Juliet/include/Graphics/GraphicsConfig.h b/Juliet/include/Graphics/GraphicsConfig.h index d3a2311..8d2e1dd 100644 --- a/Juliet/include/Graphics/GraphicsConfig.h +++ b/Juliet/include/Graphics/GraphicsConfig.h @@ -11,5 +11,6 @@ namespace Juliet struct GraphicsConfig { DriverType PreferredDriver = DriverType::DX12; + bool EnableDebug; }; } // namespace Juliet diff --git a/Juliet/include/Graphics/GraphicsPipeline.h b/Juliet/include/Graphics/GraphicsPipeline.h index c192a32..492a000 100644 --- a/Juliet/include/Graphics/GraphicsPipeline.h +++ b/Juliet/include/Graphics/GraphicsPipeline.h @@ -9,8 +9,8 @@ namespace Juliet enum class FillMode : uint8 { - Wireframe, Solid, + Wireframe, Count }; diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp index 084a1a5..2efd425 100644 --- a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp @@ -8,8 +8,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -18,6 +20,7 @@ #define D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC "D3D12SerializeRootSignature" #define DXGIDEBUG_DLL "dxgidebug.dll" #define DXGI_GET_DEBUG_INTERFACE_FUNC "DXGIGetDebugInterface" +#define D3D12_GET_DEBUG_INTERFACE_FUNC "D3D12GetDebugInterface" // TODO : Use LoadLibrary and not link to the lib. Allows failing earlier if Dx12 is not installed for some reason // + Will load the dll when needed @@ -168,6 +171,116 @@ namespace Juliet::D3D12 } #endif +#ifdef JULIET_DEBUG + void InitializeD3D12DebugLayer(NonNullPtr driver) + { + auto D3D12GetDebugInterfaceFunc = + reinterpret_cast(LoadFunction(driver->D3D12DLL, D3D12_GET_DEBUG_INTERFACE_FUNC)); + if (D3D12GetDebugInterfaceFunc == nullptr) + { + LogWarning(LogCategory::Graphics, "Could not load function: " D3D12_GET_DEBUG_INTERFACE_FUNC); + return; + } + + HRESULT result = D3D12GetDebugInterfaceFunc(IID_ID3D12Debug1, reinterpret_cast(&driver->D3D12Debug)); + if (FAILED(result)) + { + LogWarning(LogCategory::Graphics, "Could not get ID3D12Debug interface"); + return; + } + + ID3D12Debug1_EnableDebugLayer(driver->D3D12Debug); + } + + bool InitializeD3D12DebugInfoQueue(NonNullPtr driver) + { + ID3D12InfoQueue* infoQueue = NULL; + D3D12_MESSAGE_SEVERITY severities[] = { D3D12_MESSAGE_SEVERITY_INFO }; + + HRESULT result = + ID3D12Device_QueryInterface(driver->D3D12Device, IID_ID3D12InfoQueue, reinterpret_cast(&infoQueue)); + if (FAILED(result)) + { + LogError(driver, "Failed to convert ID3D12Device to ID3D12InfoQueue", result); + return false; + } + + D3D12_INFO_QUEUE_FILTER filter = {}; + filter.DenyList.NumSeverities = 1; + filter.DenyList.pSeverityList = severities; + ID3D12InfoQueue_PushStorageFilter(infoQueue, &filter); + ID3D12InfoQueue_SetBreakOnSeverity(infoQueue, D3D12_MESSAGE_SEVERITY_CORRUPTION, true); + ID3D12InfoQueue_Release(infoQueue); + + return true; + } + +#ifdef ID3D12InfoQueue1_SUPPORTED + void WINAPI OnD3D12DebugInfoMsg(D3D12_MESSAGE_CATEGORY category, D3D12_MESSAGE_SEVERITY severity, + D3D12_MESSAGE_ID id, LPCSTR description, void* context) + { + String catStr; + switch (category) + { + case D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED: catStr = WrapString("APPLICATION_DEFINED"); break; + case D3D12_MESSAGE_CATEGORY_MISCELLANEOUS: catStr = WrapString("MISCELLANEOUS"); break; + case D3D12_MESSAGE_CATEGORY_INITIALIZATION: catStr = WrapString("INITIALIZATION"); break; + case D3D12_MESSAGE_CATEGORY_CLEANUP: catStr = WrapString("CLEANUP"); break; + case D3D12_MESSAGE_CATEGORY_COMPILATION: catStr = WrapString("COMPILATION"); break; + case D3D12_MESSAGE_CATEGORY_STATE_CREATION: catStr = WrapString("STATE_CREATION"); break; + case D3D12_MESSAGE_CATEGORY_STATE_SETTING: catStr = WrapString("STATE_SETTING"); break; + case D3D12_MESSAGE_CATEGORY_STATE_GETTING: catStr = WrapString("STATE_GETTING"); break; + case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: catStr = WrapString("RESOURCE_MANIPULATION"); break; + case D3D12_MESSAGE_CATEGORY_EXECUTION: catStr = WrapString("EXECUTION"); break; + case D3D12_MESSAGE_CATEGORY_SHADER: catStr = WrapString("SHADER"); break; + default: catStr = WrapString("UNKNOWN"); break; + } + + String severityStr; + switch (severity) + { + case D3D12_MESSAGE_SEVERITY_CORRUPTION: severityStr = WrapString("CORRUPTION"); break; + case D3D12_MESSAGE_SEVERITY_ERROR: severityStr = WrapString("ERROR"); break; + case D3D12_MESSAGE_SEVERITY_WARNING: severityStr = WrapString("WARNING"); break; + case D3D12_MESSAGE_SEVERITY_INFO: severityStr = WrapString("INFO"); break; + case D3D12_MESSAGE_SEVERITY_MESSAGE: severityStr = WrapString("MESSAGE"); break; + default: severityStr = WrapString("UNKNOWN"); break; + } + + if (severity <= D3D12_MESSAGE_SEVERITY_ERROR) + { + LogWarning(LogCategory::Graphics, "D3D12 ERROR: %s [%s %s #%d]", description, CStr(catStr), CStr(severityStr), id); + } + else + { + LogWarning(LogCategory::Graphics, "D3D12 WARNING: %s [%s %s #%d]", description, CStr(catStr), + CStr(severityStr), id); + } + } + + void InitializeD3D12DebugInfoLogger(NonNullPtr driver) + { + ID3D12InfoQueue* infoQueue = NULL; + HRESULT result = + ID3D12Device5_QueryInterface(driver->D3D12Device, IID_ID3D12InfoQueue, reinterpret_cast(&infoQueue)); + if (FAILED(result)) + { + LogError(driver, "Failed to get ID3D12InfoQueue", result); + return; + } + ID3D12InfoQueue1* infoQueue1 = nullptr; + result = ID3D12Device5_QueryInterface(driver->D3D12Device, IID_ID3D12InfoQueue1, reinterpret_cast(&infoQueue1)); + if (FAILED(result)) + { + return; + } + + ID3D12InfoQueue1_RegisterMessageCallback(infoQueue1, OnD3D12DebugInfoMsg, D3D12_MESSAGE_CALLBACK_FLAG_NONE, NULL, NULL); + ID3D12InfoQueue1_Release(infoQueue); + } +#endif +#endif + void DestroyDriver_Internal(NonNullPtr driver) { // Destroy pools @@ -323,13 +436,12 @@ namespace Juliet::D3D12 Free(device.Get()); } - GraphicsDevice* CreateGraphicsDevice() + GraphicsDevice* CreateGraphicsDevice(bool enableDebug) { auto driver = static_cast(Calloc(1, sizeof(D3D12Driver))); #ifdef IDXGIINFOQUEUE_SUPPORTED - static const bool kDebug = true; - if (kDebug) + if (enableDebug) { InitializeDXGIDebug(driver); } @@ -449,8 +561,12 @@ namespace Juliet::D3D12 return nullptr; } - // TODO : D3D12 Debug Layer here - // InitializeD3D12DebugLayer() +#ifdef JULIET_DEBUG + if (enableDebug) + { + InitializeD3D12DebugLayer(driver); + } +#endif result = D3D12CreateDeviceFuncPtr(reinterpret_cast(driver->DXGIAdapter), kD3DFeatureLevel, IID_ID3D12Device5, reinterpret_cast(&driver->D3D12Device)); @@ -461,8 +577,18 @@ namespace Juliet::D3D12 return nullptr; } - // TODO : D3D12 Debug Info Queue - // InitializeD3D12DebugInfoQueue +#ifdef JULIET_DEBUG + if (enableDebug) + { + if (!InitializeD3D12DebugInfoQueue(driver)) + { + return nullptr; + } +#ifdef ID3D12InfoQueue1_SUPPORTED + InitializeD3D12DebugInfoLogger(driver); +#endif + } +#endif // Check if UMA (unified memory architecture) is available. Used on APU i think ?? D3D12_FEATURE_DATA_ARCHITECTURE architecture; @@ -616,6 +742,7 @@ namespace Juliet::D3D12 device->CreateShader = CreateShader; device->DestroyShader = DestroyShader; device->CreateGraphicsPipeline = CreateGraphicsPipeline; + device->DestroyGraphicsPipeline = DestroyGraphicsPipeline; device->Driver = driver; driver->GraphicsDevice = device; @@ -633,9 +760,9 @@ namespace Juliet::D3D12 void DisposePendingResourcces(NonNullPtr driver) { // TODO Destroy anything (buffer, texture, etc...) - for (uint32 idx = driver->GraphicsPipelinesToDisposeCount - 1; idx >= 0ul; --idx) + for (int32 idx = driver->GraphicsPipelinesToDisposeCount - 1; idx >= 0; --idx) { - if (--driver->GraphicsPipelinesToDispose[idx]->ReferenceCount == 0) + if ((--(driver->GraphicsPipelinesToDispose[idx]->ReferenceCount)) == 0) { ReleaseGraphicsPipeline(driver->GraphicsPipelinesToDispose[idx]); diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.h b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.h index c32534f..96bf435 100644 --- a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.h +++ b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.h @@ -46,6 +46,9 @@ namespace Juliet::D3D12 PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFct; ID3D12CommandQueue* GraphicsQueue; D3D12_COMMAND_QUEUE_DESC QueueDesc[ToUnderlying(QueueType::Copy)]; +#ifdef JULIET_DEBUG + ID3D12Debug1* D3D12Debug; +#endif // Indirect commands signature ID3D12CommandSignature* IndirectDrawCommandSignature; diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.cpp b/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.cpp index 9f7e1b2..54d4034 100644 --- a/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -318,11 +319,269 @@ namespace Juliet::D3D12 return true; } - D3D12GraphicsRootSignature* CreateGraphicsRootSignature(NonNullPtr renderer, NonNullPtr vertexShader, + void DestroyGraphicsRootSignature(NonNullPtr rootSignature); + + constexpr size_t kMaxRootSignatureParameters = 64; + D3D12GraphicsRootSignature* CreateGraphicsRootSignature(NonNullPtr d3d12Driver, + NonNullPtr vertexShader, NonNullPtr fragmentShader) { + // TODO: Investigate bindless resources + D3D12_ROOT_PARAMETER rootParameters[kMaxRootSignatureParameters]; + D3D12_DESCRIPTOR_RANGE descriptorRanges[kMaxRootSignatureParameters]; + ZeroArray(rootParameters); + ZeroArray(descriptorRanges); - return nullptr; + uint32 parameterCount = 0; + uint32 rangeCount = 0; + D3D12_DESCRIPTOR_RANGE descriptorRange = {}; + D3D12_ROOT_PARAMETER rootParameter = {}; + auto d3d12GraphicsRootSignature = + static_cast(Calloc(1, sizeof(D3D12GraphicsRootSignature))); + if (!d3d12GraphicsRootSignature) + { + return nullptr; + } + + d3d12GraphicsRootSignature->VertexSamplerRootIndex = -1; + d3d12GraphicsRootSignature->VertexSamplerTextureRootIndex = -1; + d3d12GraphicsRootSignature->VertexStorageTextureRootIndex = -1; + d3d12GraphicsRootSignature->VertexStorageBufferRootIndex = -1; + + d3d12GraphicsRootSignature->FragmentSamplerRootIndex = -1; + d3d12GraphicsRootSignature->FragmentSamplerTextureRootIndex = -1; + d3d12GraphicsRootSignature->FragmentStorageTextureRootIndex = -1; + d3d12GraphicsRootSignature->FragmentStorageBufferRootIndex = -1; + + for (uint32 i = 0; i < GPUDriver::kMaxUniformBuffersPerStage; ++i) + { + d3d12GraphicsRootSignature->VertexUniformBufferRootIndex[i] = -1; + d3d12GraphicsRootSignature->FragmentUniformBufferRootIndex[i] = -1; + } + + if (vertexShader->NumSamplers > 0) + { + // Vertex Samplers + descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + descriptorRange.NumDescriptors = vertexShader->NumSamplers; + descriptorRange.BaseShaderRegister = 0; + descriptorRange.RegisterSpace = 0; + descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + descriptorRanges[rangeCount] = descriptorRange; + + rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + rootParameter.DescriptorTable.NumDescriptorRanges = 1; + rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; + rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; + rootParameters[parameterCount] = rootParameter; + d3d12GraphicsRootSignature->VertexSamplerRootIndex = parameterCount; + rangeCount += 1; + parameterCount += 1; + + descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + descriptorRange.NumDescriptors = vertexShader->NumSamplers; + descriptorRange.BaseShaderRegister = 0; + descriptorRange.RegisterSpace = 0; + descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + descriptorRanges[rangeCount] = descriptorRange; + + rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + rootParameter.DescriptorTable.NumDescriptorRanges = 1; + rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; + rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; + rootParameters[parameterCount] = rootParameter; + d3d12GraphicsRootSignature->VertexSamplerTextureRootIndex = parameterCount; + rangeCount += 1; + parameterCount += 1; + } + + if (vertexShader->NumStorageTextures) + { + // Vertex storage textures + descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + descriptorRange.NumDescriptors = vertexShader->NumStorageTextures; + descriptorRange.BaseShaderRegister = vertexShader->NumSamplers; + descriptorRange.RegisterSpace = 0; + descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + descriptorRanges[rangeCount] = descriptorRange; + + rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + rootParameter.DescriptorTable.NumDescriptorRanges = 1; + rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; + rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; + rootParameters[parameterCount] = rootParameter; + d3d12GraphicsRootSignature->VertexStorageTextureRootIndex = parameterCount; + rangeCount += 1; + parameterCount += 1; + } + + if (vertexShader->NumStorageBuffers) + { + // Vertex storage buffers + descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + descriptorRange.NumDescriptors = vertexShader->NumStorageBuffers; + descriptorRange.BaseShaderRegister = vertexShader->NumSamplers + vertexShader->NumStorageBuffers; + descriptorRange.RegisterSpace = 0; + descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + descriptorRanges[rangeCount] = descriptorRange; + + rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + rootParameter.DescriptorTable.NumDescriptorRanges = 1; + rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; + rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; + rootParameters[parameterCount] = rootParameter; + d3d12GraphicsRootSignature->VertexStorageBufferRootIndex = parameterCount; + rangeCount += 1; + parameterCount += 1; + } + + // Vertex Uniforms + for (uint32 i = 0; i < vertexShader->NumUniformBuffers; ++i) + { + rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + rootParameter.Descriptor.ShaderRegister = i; + rootParameter.Descriptor.RegisterSpace = 1; + rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; + rootParameters[parameterCount] = rootParameter; + d3d12GraphicsRootSignature->VertexUniformBufferRootIndex[i] = parameterCount; + parameterCount += 1; + } + + if (fragmentShader->NumSamplers) + { + // Fragment Samplers + descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + descriptorRange.NumDescriptors = fragmentShader->NumSamplers; + descriptorRange.BaseShaderRegister = 0; + descriptorRange.RegisterSpace = 2; + descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + descriptorRanges[rangeCount] = descriptorRange; + + rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + rootParameter.DescriptorTable.NumDescriptorRanges = 1; + rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; + rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + rootParameters[parameterCount] = rootParameter; + d3d12GraphicsRootSignature->FragmentSamplerRootIndex = parameterCount; + rangeCount += 1; + parameterCount += 1; + + descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + descriptorRange.NumDescriptors = fragmentShader->NumSamplers; + descriptorRange.BaseShaderRegister = 0; + descriptorRange.RegisterSpace = 2; + descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + descriptorRanges[rangeCount] = descriptorRange; + + rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + rootParameter.DescriptorTable.NumDescriptorRanges = 1; + rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; + rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + rootParameters[parameterCount] = rootParameter; + d3d12GraphicsRootSignature->FragmentSamplerTextureRootIndex = parameterCount; + rangeCount += 1; + parameterCount += 1; + } + + if (fragmentShader->NumStorageTextures) + { + // Fragment Storage Textures + descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + descriptorRange.NumDescriptors = fragmentShader->NumStorageTextures; + descriptorRange.BaseShaderRegister = fragmentShader->NumSamplers; + descriptorRange.RegisterSpace = 2; + descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + descriptorRanges[rangeCount] = descriptorRange; + + rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + rootParameter.DescriptorTable.NumDescriptorRanges = 1; + rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; + rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + rootParameters[parameterCount] = rootParameter; + d3d12GraphicsRootSignature->FragmentStorageTextureRootIndex = parameterCount; + rangeCount += 1; + parameterCount += 1; + } + + if (fragmentShader->NumStorageBuffers) + { + // Fragment Storage Buffers + descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + descriptorRange.NumDescriptors = fragmentShader->NumStorageBuffers; + descriptorRange.BaseShaderRegister = fragmentShader->NumSamplers + fragmentShader->NumStorageTextures; + descriptorRange.RegisterSpace = 2; + descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + descriptorRanges[rangeCount] = descriptorRange; + + rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + rootParameter.DescriptorTable.NumDescriptorRanges = 1; + rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; + rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + rootParameters[parameterCount] = rootParameter; + d3d12GraphicsRootSignature->FragmentStorageBufferRootIndex = parameterCount; + rangeCount += 1; + parameterCount += 1; + } + + // Fragment Uniforms + for (uint32 i = 0; i < fragmentShader->NumUniformBuffers; ++i) + { + rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + rootParameter.Descriptor.ShaderRegister = i; + rootParameter.Descriptor.RegisterSpace = 3; + rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + rootParameters[parameterCount] = rootParameter; + d3d12GraphicsRootSignature->FragmentUniformBufferRootIndex[i] = parameterCount; + parameterCount += 1; + } + + Assert(parameterCount <= kMaxRootSignatureParameters); + Assert(rangeCount <= kMaxRootSignatureParameters); + + // Create the root signature description + D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc; + rootSignatureDesc.NumParameters = parameterCount; + rootSignatureDesc.pParameters = rootParameters; + rootSignatureDesc.NumStaticSamplers = 0; + rootSignatureDesc.pStaticSamplers = nullptr; + rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + // Serialize the root signature + ID3DBlob* serializedRootSignature; + ID3DBlob* errorBlob; + HRESULT res = d3d12Driver->D3D12SerializeRootSignatureFct(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1_0, + &serializedRootSignature, &errorBlob); + if (FAILED(res)) + { + if (errorBlob) + { + auto errorBuffer = ID3D10Blob_GetBufferPointer(errorBlob); + LogError(LogCategory::Graphics, "Failed to serialize RootSignature: %s", errorBuffer); + ID3D10Blob_Release(errorBlob); + } + DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); + return NULL; + } + + // Create the root signature + ID3D12RootSignature* rootSignature; + res = ID3D12Device_CreateRootSignature(d3d12Driver->D3D12Device, 0, ID3D10Blob_GetBufferPointer(serializedRootSignature), + ID3D10Blob_GetBufferSize(serializedRootSignature), + IID_ID3D12RootSignature, reinterpret_cast(&rootSignature)); + if (FAILED(res)) + { + if (errorBlob) + { + LogError(LogCategory::Graphics, "Failed to create RootSignature: %s", + (const char*)ID3D10Blob_GetBufferPointer(errorBlob)); + ID3D10Blob_Release(errorBlob); + } + DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); + return nullptr; + } + + d3d12GraphicsRootSignature->Handle = rootSignature; + return d3d12GraphicsRootSignature; } void DestroyGraphicsRootSignature(NonNullPtr rootSignature) @@ -331,9 +590,9 @@ namespace Juliet::D3D12 { return; } - if (rootSignature->handle) + if (rootSignature->Handle) { - ID3D12RootSignature_Release(rootSignature->handle); + ID3D12RootSignature_Release(rootSignature->Handle); } Free(rootSignature.Get()); } @@ -351,9 +610,9 @@ namespace Juliet::D3D12 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) { + D3D12_INPUT_ELEMENT_DESC inputElementDescs[D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT]; psoDesc.InputLayout.pInputElementDescs = inputElementDescs; psoDesc.InputLayout.NumElements = createInfo.VertexInputState.NumVertexAttributes; ConvertVertexInputState(createInfo.VertexInputState, inputElementDescs, d3d12Driver->Semantic); @@ -403,20 +662,19 @@ namespace Juliet::D3D12 psoDesc.NodeMask = 0; D3D12GraphicsRootSignature* rootSignature = CreateGraphicsRootSignature(d3d12Driver, vertexShader, fragmentShader); - - if (rootSignature == NULL) + if (rootSignature == nullptr) { Internal::ReleaseGraphicsPipeline(pipeline); return nullptr; } pipeline->RootSignature = rootSignature; + psoDesc.pRootSignature = rootSignature->Handle; 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; diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.h b/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.h index eadcef2..4100ed1 100644 --- a/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.h +++ b/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.h @@ -16,7 +16,7 @@ namespace Juliet::D3D12 { struct D3D12GraphicsRootSignature { - ID3D12RootSignature* handle; + ID3D12RootSignature* Handle; int32 VertexSamplerRootIndex; int32 VertexSamplerTextureRootIndex; diff --git a/Juliet/src/Graphics/D3D12/D3D12Includes.h b/Juliet/src/Graphics/D3D12/D3D12Includes.h index 7a86458..b362a84 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Includes.h +++ b/Juliet/src/Graphics/D3D12/D3D12Includes.h @@ -11,27 +11,22 @@ #define COBJMACROS #define CINTERFACE ; -#include -#include -#include -#include #include "d3d12.h" - -#include -// TODO: Should not use this when shipping -// Prebake the shaders and embed .dxil files -// When not shipping, thats ok to compile them -// #include +#include #ifdef _DEBUG #include #endif -#include +//#include #ifdef __IDXGIInfoQueue_INTERFACE_DEFINED__ #define IDXGIINFOQUEUE_SUPPORTED #endif +#ifdef __ID3D12InfoQueue1_INTERFACE_DEFINED__ +#define ID3D12InfoQueue1_SUPPORTED +#endif + #undef min #undef max diff --git a/Juliet/src/Graphics/D3D12/D3D12Shader.cpp b/Juliet/src/Graphics/D3D12/D3D12Shader.cpp index 0f2f482..62db753 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Shader.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12Shader.cpp @@ -13,8 +13,8 @@ namespace Juliet::D3D12 return nullptr; } - size_t allocSize = sizeof(D3D12Shader) + shaderByteCode.Size; - auto shader = static_cast(Malloc(allocSize)); + size_t allocSize = sizeof(D3D12Shader) + shaderByteCode.Size; + auto shader = static_cast(Calloc(1, allocSize)); if (!shader) { LogError(LogCategory::Graphics, "Cannot allocate a new D3D12Shader: Out of memory"); diff --git a/Juliet/src/Graphics/Graphics.cpp b/Juliet/src/Graphics/Graphics.cpp index 3b83fdc..52bc6f2 100644 --- a/Juliet/src/Graphics/Graphics.cpp +++ b/Juliet/src/Graphics/Graphics.cpp @@ -51,7 +51,7 @@ namespace Juliet GraphicsDeviceFactory* chosenFactory = ChooseFactory(config); if (chosenFactory) { - GraphicsDevice* newDevice = chosenFactory->CreateGraphicsDevice(); + GraphicsDevice* newDevice = chosenFactory->CreateGraphicsDevice(config.EnableDebug); newDevice->Name = chosenFactory->Name; return newDevice; } @@ -222,4 +222,10 @@ namespace Juliet { return device->CreateGraphicsPipeline(device->Driver, createInfo); } + + void DestroyGraphicsPipeline(NonNullPtr device, NonNullPtr graphicsPipeline) + { + device->DestroyGraphicsPipeline(device->Driver, graphicsPipeline); + } + } // namespace Juliet diff --git a/Juliet/src/Graphics/GraphicsDevice.h b/Juliet/src/Graphics/GraphicsDevice.h index 45aa7cd..c51fd90 100644 --- a/Juliet/src/Graphics/GraphicsDevice.h +++ b/Juliet/src/Graphics/GraphicsDevice.h @@ -74,6 +74,7 @@ namespace Juliet // Pipeline GraphicsPipeline* (*CreateGraphicsPipeline)(NonNullPtr driver, const GraphicsPipelineCreateInfo& createInfo); + void (*DestroyGraphicsPipeline)(NonNullPtr driver, NonNullPtr pipeline); const char* Name = "Unknown"; GPUDriver* Driver = nullptr; @@ -84,7 +85,7 @@ namespace Juliet const char* Name = "Unknown"; DriverType Type = DriverType::Any; bool (*CheckDriver)(void); - GraphicsDevice* (*CreateGraphicsDevice)(void); + GraphicsDevice* (*CreateGraphicsDevice)(bool enableDebug); }; extern GraphicsDeviceFactory DX12DeviceFactory; diff --git a/JulietApp/main.cpp b/JulietApp/main.cpp index 6dad1c3..fa523a9 100644 --- a/JulietApp/main.cpp +++ b/JulietApp/main.cpp @@ -9,12 +9,12 @@ #include #include #include +#include #include #include #include #include -#include // TODO : Replace with message box from framework + call main and not winmain + subsystem // TODO : Think how to do the draw pipeline. @@ -49,6 +49,9 @@ void JulietApplication::Init() Log(LogLevel::Message, LogCategory::Tool, "%s", CStr(GetBasePath())); GraphicsConfig config; +#if JULIET_DEBUG + config.EnableDebug = true; +#endif GraphicsDevice = CreateGraphicsDevice(config); MainWindow = CreatePlatformWindow("Juliet Editor", 1280, 720); @@ -81,13 +84,18 @@ void JulietApplication::Init() pipelineCI.VertexShader = vertexShader; pipelineCI.FragmentShader = fragmentShader; pipelineCI.PrimitiveType = PrimitiveType::TriangleList; - pipelineCI.TargetInfo = { - .ColorTargetDescriptions = &colorTargetDescription, - .NumColorTargets = 1, - }; - pipelineCI.RasterizerState.FillMode = FillMode::Solid; + pipelineCI.TargetInfo = { .ColorTargetDescriptions = &colorTargetDescription, + .NumColorTargets = 1, + .DepthStencilFormat = {}, + .HasDepthStencilTarget = false }; + pipelineCI.RasterizerState.FillMode = FillMode::Solid; - GraphicsPipeline* mainPipeline = CreateGraphicsPipeline(GraphicsDevice, pipelineCI); + GraphicsPipeline = CreateGraphicsPipeline(GraphicsDevice, pipelineCI); + if (GraphicsPipeline == nullptr) + { + LogError(LogCategory::Game, "Failed to create graphics pipeline!"); + Running = false; + } if (vertexShader) { @@ -97,6 +105,11 @@ void JulietApplication::Init() { DestroyShader(GraphicsDevice, fragmentShader); } + + if (Running == false) + { + return; + } } GameCode.Functions = reinterpret_cast(&Game); @@ -114,8 +127,16 @@ void JulietApplication::Shutdown() { Log(LogLevel::Message, LogCategory::Tool, "Shutting down Juliet Application..."); - Game.Shutdown(); - ShutdownHotReloadCode(GameCode); + if (GameCode.IsValid) + { + Game.Shutdown(); + ShutdownHotReloadCode(GameCode); + } + + if (GraphicsPipeline) + { + DestroyGraphicsPipeline(GraphicsDevice, GraphicsPipeline); + } if (MainWindow && GraphicsDevice) { diff --git a/JulietApp/main.h b/JulietApp/main.h index 6b7728b..1efaba0 100644 --- a/JulietApp/main.h +++ b/JulietApp/main.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace Juliet { @@ -20,9 +21,10 @@ class JulietApplication : public Juliet::IApplication bool IsRunning() override; private: - Juliet::Window* MainWindow = {}; - Juliet::GraphicsDevice* GraphicsDevice = {}; - Juliet::HotReloadCode GameCode = {}; + Juliet::Window* MainWindow = {}; + Juliet::GraphicsDevice* GraphicsDevice = {}; + Juliet::HotReloadCode GameCode = {}; + Juliet::GraphicsPipeline* GraphicsPipeline = {}; bool Running = false; };