refactored to single thread for d3d12 testing

This commit is contained in:
Anton Ljungdahl 2025-05-18 21:23:40 +02:00
parent d26fe05f19
commit d73c450d21
16 changed files with 716 additions and 280 deletions

11
anton_render.raddbgproj Normal file
View File

@ -0,0 +1,11 @@
// raddbg 0.9.17 project file
recent_file: path: "src/render/d3d12/render_d3d12.c"
recent_file: path: "src/os/win32/os_gfx_win32.c"
recent_file: path: "src/main.c"
target:
{
executable: "build/program.exe"
working_directory: build
enabled: 1
}

View File

@ -149,3 +149,43 @@ temp_end(Temp temp)
arena_pop_to(temp.arena, temp.pos);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~ TODO(anton): Testing, to be refactored or removed.
internal void
test_arena(Arena *arena)
{
LOG("Testing arena with filled entries with A prefix.\n");
U64 count = 0;
U64 N1 = 32;
U64 *arr = push_array(arena, U64, N1);
for(U64 i = 0; i < N1; i += 1)
{
arr[i] = i;
count += 1;
}
for(U64 i = 0; i < count; i += 1)
{
U64 value = arr[i];
LOG("arr[%i] = %i \n", i, value);
}
arena_pop(arena, sizeof(U64)*N1);
U64 N2 = 8;
count = 0;
for(U64 i = 0; i < N2; i += 1)
{
arr[i] = 100 + i;
count += 1;
}
LOG("After pop: \n");
for(U64 i = 0; i < count; i += 1)
{
U64 value = arr[i];
LOG("arr[%i] = %i \n", i, value);
}
}

View File

@ -1,7 +1,6 @@
#ifndef BASE_CORE_H
#define BASE_CORE_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
#include <stdint.h>

View File

@ -1,5 +1,11 @@
#include <stdio.h>
#define WINDOW_WIDTH_PX 1280
#define WINDOW_HEIGHT_PX 720
static int g_do_exit = 0;
static void entry_point();
@ -19,45 +25,6 @@ static void entry_point();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
internal void
test_arena(Arena *arena)
{
LOG("Testing arena with filled entries with A prefix.\n");
U64 count = 0;
U64 N1 = 32;
U64 *arr = push_array(arena, U64, N1);
for(U64 i = 0; i < N1; i += 1)
{
arr[i] = i;
count += 1;
}
for(U64 i = 0; i < count; i += 1)
{
U64 value = arr[i];
LOG("arr[%i] = %i \n", i, value);
}
arena_pop(arena, sizeof(U64)*N1);
U64 N2 = 8;
count = 0;
for(U64 i = 0; i < N2; i += 1)
{
arr[i] = 100 + i;
count += 1;
}
LOG("After pop: \n");
for(U64 i = 0; i < count; i += 1)
{
U64 value = arr[i];
LOG("arr[%i] = %i \n", i, value);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~ Main entry
internal void
@ -67,31 +34,34 @@ entry_point()
// Init systems
Arena *arena = arena_alloc();
//test_arena(arena);
r_init();
//test_arena(arena);
r_trigger_debug_message();
//r_log_debug_messages();
// Main program loop
U32 do_exit = 0;
g_do_exit = 0;
for(;;)
{
MSG Message;
while(PeekMessage(&Message, 0, 0, 0, PM_REMOVE))
{
switch(Message.message)
{
case WM_CLOSE:
{
SendMessageW(g_service_window_handle, OS_W32_MSG_DESTROY_WINDOW, Message.wParam, 0);
do_exit = 1;
} break;
}
TranslateMessage(&Message);
DispatchMessageW(&Message);
}
if(do_exit)
//r_log_debug_messages();
if(g_do_exit)
{
break;
}
}
r_cleanup();
arena_release(arena);

View File

@ -2,4 +2,7 @@
//~ os source includes
#include "os/os_core.c"
#include "os/win32/os_core_win32.c"
// If win32
#include "os/win32/os_core_win32.c"
#include "os/win32/os_gfx_win32.c"

View File

@ -8,5 +8,6 @@
// If win32
#include "os/win32/os_core_win32.h"
#include "os/win32/os_gfx_win32.h"
#endif /* OS_INC_H */

View File

@ -1,16 +1,11 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
#pragma comment(lib, "kernel32")
#pragma comment(lib, "user32")
#pragma comment(lib, "gdi32")
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")
#define OS_W32_MSG_CREATE_WINDOW (WM_USER + 0x1337)
#define OS_W32_MSG_DESTROY_WINDOW (WM_USER + 0x1338)
global DWORD MainThreadID;
global HWND g_service_window_handle;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
@ -43,205 +38,6 @@ os_release(void *ptr, U64 size)
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
internal LRESULT CALLBACK
ServiceWndProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam)
{
/* NOTE(casey): This is not really a window handler per se, it's actually just
a remote thread call handler. Windows only really has blocking remote thread
calls if you register a WndProc for them, so that's what we do.
This handles CREATE_DANGEROUS_WINDOW and DESTROY_DANGEROUS_WINDOW, which are
just calls that do CreateWindow and DestroyWindow here on this thread when
some other thread wants that to happen.
*/
LRESULT result = 0;
switch(Message)
{
case OS_W32_MSG_CREATE_WINDOW:
{
OS_W32_WndParam *wndParam = (OS_W32_WndParam *)WParam;
result = (LRESULT)CreateWindowExW(wndParam->dwExStyle,
wndParam->lpClassName,
wndParam->lpWindowName,
wndParam->dwStyle,
wndParam->X,
wndParam->Y,
wndParam->nWidth,
wndParam->nHeight,
wndParam->hWndParent,
wndParam->hMenu,
wndParam->hInstance,
wndParam->lpParam);
} break;
case OS_W32_MSG_DESTROY_WINDOW:
{
DestroyWindow((HWND)WParam);
} break;
default:
{
result = DefWindowProcW(Window, Message, WParam, LParam);
} break;
}
return result;
}
internal LRESULT CALLBACK
DisplayWndProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam)
{
/* NOTE(casey): This is an example of an actual window procedure. It doesn't do anything
but forward things to the main thread, because again, all window messages now occur
on the message thread, and presumably we would rather handle everything there. You
don't _have_ to do that - you could choose to handle some of the messages here.
But if you did, you would have to actually think about whether there are race conditions
with your main thread and all that. So just PostThreadMessageW()'ing everything gets
you out of having to think about it.
*/
LRESULT Result = 0;
switch (Message)
{
// NOTE(casey): Mildly annoying, if you want to specify a window, you have
// to snuggle the params yourself, because Windows doesn't let you forward
// a god damn window message even though the program IS CALLED WINDOWS. It's
// in the name! Let me pass it!
case WM_CLOSE:
{
PostThreadMessageW(MainThreadID, Message, (WPARAM)Window, LParam);
} break;
// NOTE(casey): Anything you want the application to handle, forward to the main thread
// here.
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_DESTROY:
case WM_CHAR:
{
PostThreadMessageW(MainThreadID, Message, WParam, LParam);
} break;
default:
{
Result = DefWindowProcW(Window, Message, WParam, LParam);
} break;
}
return Result;
}
internal DWORD WINAPI
MainThreadEntryPoint(LPVOID Param)
{
/* NOTE(Casey): This is your app code. Basically you just do everything the same,
but instead of calling CreateWindow/DestroyWindow, you use SendMessage to
do it on the other thread, using the CREATE_DANGEROUS_WINDOW and DESTROY_DANGEROUS_WINDOW
user messages. Otherwise, everything proceeds as normal.
*/
HWND ServiceWindow = (HWND)Param;
g_service_window_handle = ServiceWindow;
WNDCLASSEXW WindowClass = {0};
WindowClass.cbSize = sizeof(WindowClass);
WindowClass.lpfnWndProc = &DisplayWndProc;
WindowClass.hInstance = GetModuleHandleW(NULL);
WindowClass.hIcon = LoadIconA(NULL, IDI_APPLICATION);
WindowClass.hCursor = LoadCursorA(NULL, IDC_ARROW);
WindowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
WindowClass.lpszClassName = L"Dangerous Class";
RegisterClassExW(&WindowClass);
OS_W32_WndParam wndParam = {0};
wndParam.dwExStyle = 0;;
wndParam.lpClassName = WindowClass.lpszClassName;
wndParam.lpWindowName = L"Dangerous Window";
wndParam.dwStyle = WS_OVERLAPPEDWINDOW|WS_VISIBLE;
wndParam.X = CW_USEDEFAULT;
wndParam.Y = CW_USEDEFAULT;
wndParam.nWidth = CW_USEDEFAULT;
wndParam.nHeight = CW_USEDEFAULT;
wndParam.hInstance = WindowClass.hInstance;
// Create initial window
HWND ThisWouldBeTheHandleIfYouCared = (HWND)SendMessageW(ServiceWindow,
OS_W32_MSG_CREATE_WINDOW,
(WPARAM)&wndParam,
0);
entry_point();
LOG("Exited main program. Terminating \n");
ExitProcess(0);
}
int
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
/* NOTE(casey): At startup, you create one hidden window used to handle requests
to create or destroy windows. There's nothing special about this window; it
only exists because Windows doesn't have a way to do a remote thread call without
a window handler. You could instead just do this with your own synchronization
primitives if you wanted - this is just the easiest way to do it on Windows
because they've already built it for you.
*/
LOG("Entered WinMain\n");
WNDCLASSEXW WindowClass = {0};
WindowClass.cbSize = sizeof(WindowClass);
WindowClass.lpfnWndProc = &ServiceWndProc;
WindowClass.hInstance = GetModuleHandleW(NULL);
WindowClass.hIcon = LoadIconA(NULL, IDI_APPLICATION);
WindowClass.hCursor = LoadCursorA(NULL, IDC_ARROW);
WindowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
WindowClass.lpszClassName = L"DTCClass";
RegisterClassExW(&WindowClass);
HWND ServiceWindow = CreateWindowExW(0, WindowClass.lpszClassName, L"DTCService", 0,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
0, 0, WindowClass.hInstance, 0);
// NOTE(casey): Once the service window is created, you can start the main thread,
// which is where all your app code would actually happen.
CreateThread(0, 0, MainThreadEntryPoint, ServiceWindow, 0, &MainThreadID);
// NOTE(casey): This thread can just idle for the rest of the run, forwarding
// messages to the main thread that it thinks the main thread wants.
DWORD exitCode;
for(;;)
{
MSG Message;
GetMessageW(&Message, 0, 0, 0);
TranslateMessage(&Message);
if((Message.message == WM_CHAR) ||
(Message.message == WM_KEYDOWN) ||
(Message.message == WM_QUIT) ||
(Message.message == WM_SIZE))
{
PostThreadMessageW(MainThreadID, Message.message, Message.wParam, Message.lParam);
}
else
{
DispatchMessageW(&Message);
}
}
return 0;
}
internal void

View File

@ -6,26 +6,6 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// Temp struct for launching window on separate thread.
// Trying to learn from https://github.com/cmuratori/dtc/blob/main/dtc.cpp
typedef struct OS_W32_WndParam OS_W32_WndParam;
struct OS_W32_WndParam
{
DWORD dwExStyle;
LPCWSTR lpClassName;
LPCWSTR lpWindowName;
DWORD dwStyle;
S32 X;
S32 Y;
S32 nWidth;
S32 nHeight;
HWND hWndParent;
HMENU hMenu;
HINSTANCE hInstance;
LPVOID lpParam;
};
internal void OS_W32_log_debug(const char *fmt_string, ...);
#endif /* OS_CORE_WIN32_H */

362
src/os/win32/os_gfx_win32.c Normal file
View File

@ -0,0 +1,362 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
global HWND g_win32_window_handle;
internal LRESULT CALLBACK
DisplayWndProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam)
{
LRESULT Result = 0;
switch (Message)
{
case WM_QUIT:
case WM_DESTROY:
case WM_CLOSE:
{
g_do_exit = 1;
} break;
// NOTE(casey): Anything you want the application to handle, forward to the main thread
// here.
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_CHAR:
{
} break;
default:
{
Result = DefWindowProcW(Window, Message, WParam, LParam);
} break;
}
return Result;
}
internal DWORD WINAPI
MainThreadEntryPoint()
{
WNDCLASSEXW WindowClass = {0};
WindowClass.cbSize = sizeof(WindowClass);
WindowClass.lpfnWndProc = &DisplayWndProc;
WindowClass.hInstance = GetModuleHandleW(NULL);
WindowClass.hIcon = LoadIconA(NULL, IDI_APPLICATION);
WindowClass.hCursor = LoadCursorA(NULL, IDC_ARROW);
WindowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
WindowClass.lpszClassName = L"TESTING SOME STUFF";
RegisterClassExW(&WindowClass);
OS_W32_WndParam wndParam = {0};
wndParam.dwExStyle = 0;;
wndParam.lpClassName = WindowClass.lpszClassName;
wndParam.lpWindowName = L"TESTING SOME STUFF";
wndParam.dwStyle = WS_OVERLAPPEDWINDOW|WS_VISIBLE;
wndParam.X = CW_USEDEFAULT;
wndParam.Y = CW_USEDEFAULT;
wndParam.nWidth = WINDOW_WIDTH_PX;
wndParam.nHeight = WINDOW_HEIGHT_PX;
wndParam.hInstance = WindowClass.hInstance;
HWND hwnd = CreateWindowExW(wndParam.dwExStyle,
wndParam.lpClassName,
wndParam.lpWindowName,
wndParam.dwStyle,
wndParam.X,
wndParam.Y,
wndParam.nWidth,
wndParam.nHeight,
wndParam.hWndParent,
wndParam.hMenu,
wndParam.hInstance,
wndParam.lpParam);
g_win32_window_handle = hwnd;
entry_point();
LOG("Exited main program. Terminating \n");
ExitProcess(0);
}
int
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
MainThreadEntryPoint();
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~ Below is code for creating a window on a service thread and handling messaging there.
// There are some issues with doing this with D3D12, and since the point is that I want to
// try and use mesh shaders with Vulkan and/or D3D12, I will just have everything running on a main thread
// for now. Eventually I have to fix this properly, but I have to read up a bit
//#define OS_W32_MSG_CREATE_WINDOW (WM_USER + 0x1337)
//#define OS_W32_MSG_DESTROY_WINDOW (WM_USER + 0x1338)
//#define OS_W32_MSG_CREATE_SWAPCHAIN (WM_USER + 0x1339)
//
//global DWORD MainThreadID;
//global HWND g_win32_service_window_handle;
//global HWND g_win32_window_handle;
//
//
//
//internal LRESULT CALLBACK
//ServiceWndProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam)
//{
// /* NOTE(casey): This is not really a window handler per se, it's actually just
// a remote thread call handler. Windows only really has blocking remote thread
// calls if you register a WndProc for them, so that's what we do.
//
// This handles CREATE_DANGEROUS_WINDOW and DESTROY_DANGEROUS_WINDOW, which are
// just calls that do CreateWindow and DestroyWindow here on this thread when
// some other thread wants that to happen.
// */
//
// LRESULT result = 0;
//
// switch(Message)
// {
// case OS_W32_MSG_CREATE_WINDOW:
// {
// OS_W32_WndParam *wndParam = (OS_W32_WndParam *)WParam;
// HWND hwnd = CreateWindowExW(wndParam->dwExStyle,
// wndParam->lpClassName,
// wndParam->lpWindowName,
// wndParam->dwStyle,
// wndParam->X,
// wndParam->Y,
// wndParam->nWidth,
// wndParam->nHeight,
// wndParam->hWndParent,
// wndParam->hMenu,
// wndParam->hInstance,
// wndParam->lpParam);
//
// if(hwnd)
// {
// ShowWindow(hwnd, SW_SHOW);
// UpdateWindow(hwnd);
//
// // Pump messages for this window
// MSG msg;
// while (PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)) {
// TranslateMessage(&msg);
// DispatchMessageW(&msg);
// }
// // Signal that window is ready
// HANDLE windowReadyEvent = (HANDLE)LParam; // Pass event via LParam
// if (windowReadyEvent) {
// SetEvent(windowReadyEvent);
// }
//
// result = (LRESULT)hwnd;
// } else {
// LOG("WIN32 ERROR: failed to create window: %lu \n", GetLastError());
// result = 0;
// }
//
// } break;
//
// case OS_W32_MSG_CREATE_SWAPCHAIN:
// {
// IDXGIFactory4 *factory = (IDXGIFactory4 *)WParam;
// result = r_d3d12_create_swapchain(factory);
// } break;
//
// case OS_W32_MSG_DESTROY_WINDOW:
// {
// DestroyWindow((HWND)WParam);
// } break;
//
// default:
// {
// result = DefWindowProcW(Window, Message, WParam, LParam);
// } break;
// }
//
//
// return result;
//}
//
//internal LRESULT CALLBACK
//DisplayWndProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam)
//{
// /* NOTE(casey): This is an example of an actual window procedure. It doesn't do anything
// but forward things to the main thread, because again, all window messages now occur
// on the message thread, and presumably we would rather handle everything there. You
// don't _have_ to do that - you could choose to handle some of the messages here.
// But if you did, you would have to actually think about whether there are race conditions
// with your main thread and all that. So just PostThreadMessageW()'ing everything gets
// you out of having to think about it.
// */
//
// LRESULT Result = 0;
//
// switch (Message)
// {
// // NOTE(casey): Mildly annoying, if you want to specify a window, you have
// // to snuggle the params yourself, because Windows doesn't let you forward
// // a god damn window message even though the program IS CALLED WINDOWS. It's
// // in the name! Let me pass it!
// case WM_CLOSE:
// {
// PostThreadMessageW(MainThreadID, Message, (WPARAM)Window, LParam);
// } break;
//
// // NOTE(casey): Anything you want the application to handle, forward to the main thread
// // here.
// case WM_MOUSEMOVE:
// case WM_LBUTTONDOWN:
// case WM_LBUTTONUP:
// case WM_DESTROY:
// case WM_CHAR:
// {
// PostThreadMessageW(MainThreadID, Message, WParam, LParam);
// } break;
//
// default:
// {
// Result = DefWindowProcW(Window, Message, WParam, LParam);
// } break;
// }
//
// return Result;
//}
//
//internal DWORD WINAPI
//MainThreadEntryPoint(LPVOID Param)
//{
// /* NOTE(Casey): This is your app code. Basically you just do everything the same,
// but instead of calling CreateWindow/DestroyWindow, you use SendMessage to
// do it on the other thread, using the CREATE_DANGEROUS_WINDOW and DESTROY_DANGEROUS_WINDOW
// user messages. Otherwise, everything proceeds as normal.
// */
// HWND ServiceWindow = (HWND)Param;
// g_win32_service_window_handle = ServiceWindow;
//
// WNDCLASSEXW WindowClass = {0};
// WindowClass.cbSize = sizeof(WindowClass);
// WindowClass.lpfnWndProc = &DisplayWndProc;
// WindowClass.hInstance = GetModuleHandleW(NULL);
// WindowClass.hIcon = LoadIconA(NULL, IDI_APPLICATION);
// WindowClass.hCursor = LoadCursorA(NULL, IDC_ARROW);
// WindowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
// WindowClass.lpszClassName = L"Dangerous Class";
// RegisterClassExW(&WindowClass);
//
// OS_W32_WndParam wndParam = {0};
// wndParam.dwExStyle = 0;;
// wndParam.lpClassName = WindowClass.lpszClassName;
// wndParam.lpWindowName = L"Dangerous Window";
// wndParam.dwStyle = WS_OVERLAPPEDWINDOW|WS_VISIBLE;
// wndParam.X = CW_USEDEFAULT;
// wndParam.Y = CW_USEDEFAULT;
// wndParam.nWidth = WINDOW_WIDTH_PX;
// wndParam.nHeight = WINDOW_HEIGHT_PX;
// wndParam.hInstance = WindowClass.hInstance;
//
// // To ensure that we can set up D3D12 on this thread we wait for synchronisation until the
// // window is created on the service thread.
// HANDLE window_ready_event = CreateEventW(0, FALSE, FALSE, 0);
// if(!window_ready_event)
// {
// LOG("WIN32 ERROR: Failed to create window ready event: %lu \n", GetLastError());
// ExitProcess(1);
// }
//
// g_win32_window_handle = (HWND)SendMessageW(ServiceWindow,
// OS_W32_MSG_CREATE_WINDOW,
// (WPARAM)&wndParam,
// (LPARAM)window_ready_event);
//
// if(!g_win32_window_handle)
// {
// LOG("WIN32 ERROR: Failed to create window on service thread \n");
// CloseHandle(window_ready_event);
// ExitProcess(1);
// }
//
// // Wait for initialisation
// DWORD wait_result = WaitForSingleObject(window_ready_event, 5000);
// CloseHandle(window_ready_event);
// if(wait_result != WAIT_OBJECT_0)
// {
// LOG("WIN32 ERROR: Window creation timeout on service thread: %lu \n", GetLastError());
// SendMessageW(g_win32_service_window_handle,
// OS_W32_MSG_DESTROY_WINDOW,
// (WPARAM)g_win32_window_handle, 0);
// ExitProcess(1);
// }
//
// entry_point();
//
//
// LOG("Exited main program. Terminating \n");
// ExitProcess(0);
//}
//
//int
//WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
//{
//
// /* NOTE(casey): At startup, you create one hidden window used to handle requests
// to create or destroy windows. There's nothing special about this window; it
// only exists because Windows doesn't have a way to do a remote thread call without
// a window handler. You could instead just do this with your own synchronization
// primitives if you wanted - this is just the easiest way to do it on Windows
// because they've already built it for you.
// */
//
// LOG("Entered WinMain\n");
//
// WNDCLASSEXW WindowClass = {0};
// WindowClass.cbSize = sizeof(WindowClass);
// WindowClass.lpfnWndProc = &ServiceWndProc;
// WindowClass.hInstance = GetModuleHandleW(NULL);
// WindowClass.hIcon = LoadIconA(NULL, IDI_APPLICATION);
// WindowClass.hCursor = LoadCursorA(NULL, IDC_ARROW);
// WindowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
// WindowClass.lpszClassName = L"DTCClass";
// RegisterClassExW(&WindowClass);
//
// HWND ServiceWindow = CreateWindowExW(0, WindowClass.lpszClassName, L"DTCService", 0,
// CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
// 0, 0, WindowClass.hInstance, 0);
//
// // NOTE(casey): Once the service window is created, you can start the main thread,
// // which is where all your app code would actually happen.
// CreateThread(0, 0, MainThreadEntryPoint, ServiceWindow, 0, &MainThreadID);
//
// // NOTE(casey): This thread can just idle for the rest of the run, forwarding
// // messages to the main thread that it thinks the main thread wants.
// DWORD exitCode;
// for(;;)
// {
//
// MSG Message;
// GetMessageW(&Message, 0, 0, 0);
// TranslateMessage(&Message);
// if((Message.message == WM_CHAR) ||
// (Message.message == WM_KEYDOWN) ||
// (Message.message == WM_QUIT) ||
// (Message.message == WM_SIZE))
// {
// PostThreadMessageW(MainThreadID, Message.message, Message.wParam, Message.lParam);
// }
// else
// {
// DispatchMessageW(&Message);
// }
//
// }
//
// return 0;
//}
//
//

View File

@ -0,0 +1,27 @@
#ifndef OS_GFX_WIN32_H
#define OS_GFX_WIN32_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
// Temp struct for launching window on separate thread.
// Trying to learn from https://github.com/cmuratori/dtc/blob/main/dtc.cpp
typedef struct OS_W32_WndParam OS_W32_WndParam;
struct OS_W32_WndParam
{
DWORD dwExStyle;
LPCWSTR lpClassName;
LPCWSTR lpWindowName;
DWORD dwStyle;
S32 X;
S32 Y;
S32 nWidth;
S32 nHeight;
HWND hWndParent;
HMENU hMenu;
HINSTANCE hInstance;
LPVOID lpParam;
};
#endif /* OS_GFX_WIN32_H */

View File

@ -0,0 +1,192 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
#pragma comment(lib, "d3d12.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "dxguid.lib")
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
#define D3D12_ERROR(msg, ...) LOG("D3D12 ERROR (anton): "); LOG(msg, __VA_ARGS__); Trap();
#define D3D12_CHECK(hr) if(FAILED((hr))) { Trap(); }
#define D3D12_RELEASE(res) if( (res) && (res)->lpVtbl) { (res)->lpVtbl->Release((res)); (res) = 0; }
global R_D3D12_State *r_d3d12_state = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
// D3D12 initialisiation
internal void
r_init()
{
Arena *arena = arena_alloc();
r_d3d12_state = push_array(arena, R_D3D12_State, 1);
r_d3d12_state->arena = arena;
HRESULT hr;
hr = D3D12GetDebugInterface(&IID_ID3D12Debug, (void**)&r_d3d12_state->debug);
if(SUCCEEDED(hr) && r_d3d12_state->debug )
{
r_d3d12_state->debug->lpVtbl->EnableDebugLayer(r_d3d12_state->debug);
}
else
{
D3D12_ERROR("Failed to create D3D12 Debug interface \n");
}
hr = D3D12CreateDevice(0,
D3D_FEATURE_LEVEL_11_0,
&IID_ID3D12Device,
(void **)&r_d3d12_state->device);
if(FAILED(hr))
{
D3D12_ERROR("Failed to create device \n");
}
}
//internal void
//r_log_debug_messages()
//{
// if(r_d3d12_state->info_queue)
// {
// UINT64 numMessages = r_d3d12_state->info_queue->lpVtbl->GetNumStoredMessages(r_d3d12_state->info_queue);
// for (UINT64 i = 0; i < numMessages; i++) {
// SIZE_T messageLength = 0;
// r_d3d12_state->info_queue->lpVtbl->GetMessage(r_d3d12_state->info_queue, i, NULL, &messageLength);
//
// D3D12_MESSAGE* message = (D3D12_MESSAGE*)malloc(messageLength);
// if (message) {
// r_d3d12_state->info_queue->lpVtbl->GetMessage(r_d3d12_state->info_queue, i, message, &messageLength);
// LOG("DX12 Debug: %s\n", message->pDescription);
// free(message);
// }
// }
// r_d3d12_state->info_queue->lpVtbl->ClearStoredMessages(r_d3d12_state->info_queue);
// }
//}
internal void
r_trigger_debug_message()
{
if(r_d3d12_state->device)
{
D3D12_COMMAND_QUEUE_DESC queue_desc = {0};
queue_desc.Type = -1; // Error value, should be 0,1,2 or 3
ID3D12CommandQueue *queue = 0;
HRESULT hr = r_d3d12_state->device->lpVtbl->CreateCommandQueue(r_d3d12_state->device,
&queue_desc,
&IID_ID3D12CommandQueue,
(void**)&queue);
if(queue) {
queue->lpVtbl->Release(queue);
}
}
}
internal void
r_cleanup()
{
// Report live objects
{
if(r_d3d12_state->device)
{
ID3D12DebugDevice *debug_device = 0;
HRESULT hr = r_d3d12_state->device->lpVtbl->QueryInterface(r_d3d12_state->device,
&IID_ID3D12DebugDevice,
(void **)&debug_device);
if(SUCCEEDED(hr) && debug_device)
{
debug_device->lpVtbl->ReportLiveDeviceObjects(debug_device,
D3D12_RLDO_DETAIL | D3D12_RLDO_IGNORE_INTERNAL);
debug_device->lpVtbl->Release(debug_device);
}
}
}
D3D12_RELEASE(r_d3d12_state->device);
D3D12_RELEASE(r_d3d12_state->debug);
arena_release(r_d3d12_state->arena);
}
//internal LRESULT
//r_d3d12_create_swapchain(IDXGIFactory4 *factory)
//{
// LRESULT result = 0;
// HRESULT hr = 0;
//
// // Log window state
// RECT clientRect;
// GetClientRect(g_win32_window_handle, &clientRect);
// LOG("Swap chain creation - Window state: HWND %p, Visible %d, Client area %ldx%ld\n",
// g_win32_window_handle,
// IsWindowVisible(g_win32_window_handle),
// clientRect.right - clientRect.left,
// clientRect.bottom - clientRect.top);
//
// if (!IsWindowVisible(g_win32_window_handle)) {
// LOG("WARNING: Window not visible, attempting to show\n");
// ShowWindow(g_win32_window_handle, SW_SHOW);
// UpdateWindow(g_win32_window_handle);
// }
//
// if (clientRect.right - clientRect.left == 0 || clientRect.bottom - clientRect.top == 0) {
// LOG("ERROR: Window has zero client area\n");
// result = 0;
// Trap();
// }
//
//
// DXGI_SWAP_CHAIN_DESC1 swapDesc = {0};
// swapDesc.Width = WINDOW_WIDTH_PX;
// swapDesc.Height = WINDOW_HEIGHT_PX;
// swapDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
// swapDesc.SampleDesc.Count = 1;
// swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
// swapDesc.BufferCount = 2;
// swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
// swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
//
// LOG("Creating swap chain on service thread: %dx%d\n", swapDesc.Width, swapDesc.Height);
// IDXGISwapChain1* swapChain = 0;
// hr = factory->lpVtbl->CreateSwapChainForHwnd(
// factory,
// (IUnknown*)r_d3d12_state->device,
// g_win32_window_handle,
// &swapDesc,
// 0, 0,
// &swapChain
// );
// if (FAILED(hr)) {
// LOG("Failed to create swap chain in service thread: HRESULT 0x%X\n", hr);
// r_log_debug_messages();
// result = 0;
// } else {
// hr = swapChain->lpVtbl->QueryInterface(
// swapChain,
// &IID_IDXGISwapChain3,
// (void**)&r_d3d12_state->swapchain
// );
// swapChain->lpVtbl->Release(swapChain);
// if (FAILED(hr)) {
// LOG("Failed to query swap chain: HRESULT 0x%X\n", hr);
// r_log_debug_messages();
// Trap();
// result = 0;
// } else {
// result = 1;
// }
// }
//
// return result;
//}

View File

@ -0,0 +1,30 @@
#ifndef RENDER_D3D12_H
#define RENDER_D3D12_H
#include <d3d12.h>
#include <dxgi1_4.h>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
typedef struct R_D3D12_State R_D3D12_State;
struct R_D3D12_State
{
Arena *arena;
HWND window_handle;
ID3D12Device *device;
ID3D12Debug *debug;
ID3D12InfoQueue *info_queue;
IDXGISwapChain3 *swapchain;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
internal LRESULT r_d3d12_create_swapchain(IDXGIFactory4 *factory);
#endif /* RENDER_D3D12_H */

2
src/render/render_core.c Normal file
View File

@ -0,0 +1,2 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~

15
src/render/render_core.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef RENDER_CORE_H
#define RENDER_CORE_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~
internal void r_init();
internal void r_log_debug_messages();
// TODO(anton): Temp for testing, to be removed
internal void r_trigger_debug_message();
#endif /* RENDER_CORE_H */

View File

@ -1,2 +1,6 @@
//////////////////////////////////////////////////////////////////////////////////////////////
//~
//~
#include "render/render_core.c"
#include "render/d3d12/render_d3d12.c"

View File

@ -4,4 +4,8 @@
//////////////////////////////////////////////////////////////////////////////////////////////
//~
#include "render/render_core.h"
#include "render/d3d12/render_d3d12.h"
#endif /* RENDER_INC_H */