Skip to content

Dev/nissekaka directx#33

Merged
nissekaka merged 10 commits into
developfrom
dev/nissekaka-directx
May 12, 2026
Merged

Dev/nissekaka directx#33
nissekaka merged 10 commits into
developfrom
dev/nissekaka-directx

Conversation

@nissekaka
Copy link
Copy Markdown
Collaborator

  • Bug
  • Feature

Description:

Added DirectX 11 and DirectX 12 base. Intention is to create an API that doesn't care what's underneath.

Copy link
Copy Markdown
Owner

@OlleKReutercrona OlleKReutercrona left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vi gör ett försök att flytta d3dx12.h till att vara en submodule istället samt gör DX11 samt DX12 till att vara av en gemensam abstraktionstyp som har samma API. På det sättet kan vi använda byggflaggor för att bestämma vilket API vi vill använda och till och med byta till metal om vi vill bygga för OSX i framtiden ;)

Comment thread Source/Core/Graphics/DX11.cpp Outdated
Comment thread Source/Core/Engine/Engine.h Outdated
Comment thread Source/Core/Engine/Engine.cpp Outdated
Comment thread Source/Core/Graphics/DX11.cpp
Copilot AI review requested due to automatic review settings May 1, 2026 07:32
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a foundational DirectX 11/12 rendering layer under a common IRenderer interface, and wires renderer creation into the engine so the underlying graphics API can be swapped without changing higher-level code.

Changes:

  • Link DirectX 11/12 system libraries in the Core premake project.
  • Add IRenderer plus initial DX11 and DX12 renderer implementations (basic clear + present).
  • Update Engine to own an IRenderer and delegate Render() calls to it.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
Source/Core/premake5.lua Links d3d11/d3d12 to support the new renderer implementations.
Source/Core/Graphics/d3dx12.h Adds the D3DX12 helper header used by the DX12 implementation.
Source/Core/Graphics/IRenderer.h Introduces the renderer abstraction used by Engine.
Source/Core/Graphics/DX12.h Declares the DX12 renderer implementation and its core D3D12 members.
Source/Core/Graphics/DX12.cpp Implements DX12 init/render path (swapchain, RTVs, command list, fence).
Source/Core/Graphics/DX11.h Declares the DX11 renderer implementation.
Source/Core/Graphics/DX11.cpp Implements DX11 init/render path (device+swapchain, RTV, viewport).
Source/Core/Engine/Engine.h Adds GraphicsAPI, mRenderer, and renderer ownership to Engine.
Source/Core/Engine/Engine.cpp Instantiates DX11/DX12 renderer and delegates Engine rendering to it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Source/Core/Graphics/DX12.cpp Outdated
Comment on lines +10 to +18
// Ensure GPU is finished before destroying resources
mFenceValue++;
HRESULT hr = mCommandQueue->Signal(mFence.Get(), mFenceValue);

if (mFence->GetCompletedValue() < mFenceValue) {
hr = mFence->SetEventOnCompletion(mFenceValue, mFenceEvent);
WaitForSingleObject(mFenceEvent, INFINITE);
}
CloseHandle(mFenceEvent);
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DX12 destructor assumes initialization succeeded and unconditionally dereferences mCommandQueue/mFence (and closes mFenceEvent). If Init was never called or threw part-way through, this can null-deref and/or call CloseHandle on an invalid handle. Guard cleanup with mInitialized and/or nullptr checks, and only Signal/SetEvent/CloseHandle when the corresponding objects/handle are valid.

Suggested change
// Ensure GPU is finished before destroying resources
mFenceValue++;
HRESULT hr = mCommandQueue->Signal(mFence.Get(), mFenceValue);
if (mFence->GetCompletedValue() < mFenceValue) {
hr = mFence->SetEventOnCompletion(mFenceValue, mFenceEvent);
WaitForSingleObject(mFenceEvent, INFINITE);
}
CloseHandle(mFenceEvent);
// Only perform GPU synchronization/handle cleanup if initialization completed
// and the corresponding resources were actually created.
if (!mInitialized)
return;
if (mCommandQueue && mFence) {
// Ensure GPU is finished before destroying resources
mFenceValue++;
HRESULT hr = mCommandQueue->Signal(mFence.Get(), mFenceValue);
if (SUCCEEDED(hr) && mFence->GetCompletedValue() < mFenceValue && mFenceEvent) {
hr = mFence->SetEventOnCompletion(mFenceValue, mFenceEvent);
if (SUCCEEDED(hr))
WaitForSingleObject(mFenceEvent, INFINITE);
}
}
if (mFenceEvent)
CloseHandle(mFenceEvent);

Copilot uses AI. Check for mistakes.
Comment on lines +75 to +78
// Reset allocator and command list each frame
HRESULT hr = mCommandAllocator->Reset();
hr = mCommandList->Reset(mCommandAllocator.Get(), nullptr);

Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HRESULTs returned from Reset/Close/Present/Signal/SetEventOnCompletion are assigned to hr but never validated. When these fail (e.g., device removed, invalid state, allocator still in use), the renderer will continue issuing commands with undefined behavior. Check each HRESULT and fail fast (throw/log/return) so errors are surfaced and you don't proceed with an invalid command list or swap chain state.

Copilot uses AI. Check for mistakes.
Comment on lines +146 to +150
void RF::DX12::CreateSwapChain(const HWND hwnd, const uint32_t width, const uint32_t height) {
ComPtr<IDXGIFactory4> factory;
HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
if (FAILED(hr))
throw std::runtime_error("Failed to create DXGI Factory");
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CreateSwapChain creates a new DXGI factory via CreateDXGIFactory1 even though Init already created a factory with debug flags. This duplicates work and (in _DEBUG) can drop DXGI debug factory behavior. Consider passing the factory created in Init into CreateSwapChain or storing it as a member and reusing it.

Copilot uses AI. Check for mistakes.
Comment thread Source/Core/Graphics/DX11.cpp Outdated
Comment on lines +45 to +58
D3D11CreateDeviceAndSwapChain(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
swapCreateFlags,
nullptr,
0,
D3D11_SDK_VERSION,
&scd,
&pSwap,
&pDevice,
nullptr,
&pContext
);
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value from D3D11CreateDeviceAndSwapChain is ignored. If device/swapchain creation fails, subsequent calls will dereference null ComPtrs (pSwap/pDevice/pContext) and crash, while mInitialized is still set to true. Capture the HRESULT and throw/return an error when it fails.

Copilot uses AI. Check for mistakes.
Comment thread Source/Core/Graphics/DX11.cpp Outdated
Comment on lines +63 to +65
Microsoft::WRL::ComPtr<ID3D11Resource> pBackBuffer;
pSwap->GetBuffer(0u, __uuidof(ID3D11Resource), &pBackBuffer);
pDevice->CreateRenderTargetView(pBackBuffer.Get(), nullptr, &pDefaultTarget);
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetBuffer/CreateRenderTargetView results are not checked. If the swap chain buffer retrieval or RTV creation fails, pDefaultTarget may remain null and later ClearRenderTargetView will crash. Please check HRESULTs here and surface an initialization failure instead of continuing.

Copilot uses AI. Check for mistakes.
Comment on lines +27 to +34
switch (mGraphicsAPI) {
case GraphicsAPI::DirectX11:
mRenderer = std::make_unique<RF::DX11>(mWindow->GetHWND(), windowParams.width, windowParams.height);
break;
case GraphicsAPI::DirectX12:
mRenderer = std::make_unique<RF::DX12>(mWindow->GetHWND(), windowParams.width, windowParams.height);
break;
}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Det här borde vara en preprocessor check i och med att vi aldrig kommer byta api i runtime

Suggested change
switch (mGraphicsAPI) {
case GraphicsAPI::DirectX11:
mRenderer = std::make_unique<RF::DX11>(mWindow->GetHWND(), windowParams.width, windowParams.height);
break;
case GraphicsAPI::DirectX12:
mRenderer = std::make_unique<RF::DX12>(mWindow->GetHWND(), windowParams.width, windowParams.height);
break;
}
#ifdef DX11
mRenderer = std::make_unique<RF::DX11>(mWindow->GetHWND(), windowParams.width, windowParams.height);
#elif DX12
mRenderer = std::make_unique<RF::DX12>(mWindow->GetHWND(), windowParams.width, windowParams.height);
#endif

Comment thread Source/Core/Graphics/DX11.cpp
Comment thread Source/Core/Graphics/DX11.cpp
Comment thread Source/Core/Graphics/DX11.cpp Outdated
@nissekaka nissekaka merged commit a059218 into develop May 12, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants