From d73c450d21469c2d96446b2876186eced2a8b5c7 Mon Sep 17 00:00:00 2001 From: Anton Ljungdahl Date: Sun, 18 May 2025 21:23:40 +0200 Subject: [PATCH] refactored to single thread for d3d12 testing --- anton_render.raddbgproj | 11 + src/base/base_arena.c | 40 ++++ src/base/base_core.h | 1 - src/main.c | 70 ++---- src/os/os_inc.c | 5 +- src/os/os_inc.h | 1 + src/os/win32/os_core_win32.c | 210 +----------------- src/os/win32/os_core_win32.h | 20 -- src/os/win32/os_gfx_win32.c | 362 ++++++++++++++++++++++++++++++++ src/os/win32/os_gfx_win32.h | 27 +++ src/render/d3d12/render_d3d12.c | 192 +++++++++++++++++ src/render/d3d12/render_d3d12.h | 30 +++ src/render/render_core.c | 2 + src/render/render_core.h | 15 ++ src/render/render_inc.c | 6 +- src/render/render_inc.h | 4 + 16 files changed, 716 insertions(+), 280 deletions(-) create mode 100644 anton_render.raddbgproj create mode 100644 src/os/win32/os_gfx_win32.c create mode 100644 src/os/win32/os_gfx_win32.h create mode 100644 src/render/d3d12/render_d3d12.c create mode 100644 src/render/d3d12/render_d3d12.h create mode 100644 src/render/render_core.c create mode 100644 src/render/render_core.h diff --git a/anton_render.raddbgproj b/anton_render.raddbgproj new file mode 100644 index 0000000..da69b92 --- /dev/null +++ b/anton_render.raddbgproj @@ -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 +} diff --git a/src/base/base_arena.c b/src/base/base_arena.c index d129b5b..4e9ccad 100644 --- a/src/base/base_arena.c +++ b/src/base/base_arena.c @@ -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); + } + +} + diff --git a/src/base/base_core.h b/src/base/base_core.h index 54db56e..346ddc9 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -1,7 +1,6 @@ #ifndef BASE_CORE_H #define BASE_CORE_H - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //~ #include diff --git a/src/main.c b/src/main.c index a4cf281..6118f8f 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,11 @@ #include +#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); diff --git a/src/os/os_inc.c b/src/os/os_inc.c index b108492..1a4cce6 100644 --- a/src/os/os_inc.c +++ b/src/os/os_inc.c @@ -2,4 +2,7 @@ //~ os source includes #include "os/os_core.c" -#include "os/win32/os_core_win32.c" \ No newline at end of file + +// If win32 +#include "os/win32/os_core_win32.c" +#include "os/win32/os_gfx_win32.c" \ No newline at end of file diff --git a/src/os/os_inc.h b/src/os/os_inc.h index 83f8897..0951eb3 100644 --- a/src/os/os_inc.h +++ b/src/os/os_inc.h @@ -8,5 +8,6 @@ // If win32 #include "os/win32/os_core_win32.h" +#include "os/win32/os_gfx_win32.h" #endif /* OS_INC_H */ \ No newline at end of file diff --git a/src/os/win32/os_core_win32.c b/src/os/win32/os_core_win32.c index ffb5879..5ddc8f5 100644 --- a/src/os/win32/os_core_win32.c +++ b/src/os/win32/os_core_win32.c @@ -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 diff --git a/src/os/win32/os_core_win32.h b/src/os/win32/os_core_win32.h index ac10cd5..24fc79c 100644 --- a/src/os/win32/os_core_win32.h +++ b/src/os/win32/os_core_win32.h @@ -6,26 +6,6 @@ #define WIN32_LEAN_AND_MEAN #include -// 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 */ \ No newline at end of file diff --git a/src/os/win32/os_gfx_win32.c b/src/os/win32/os_gfx_win32.c new file mode 100644 index 0000000..9ce5f32 --- /dev/null +++ b/src/os/win32/os_gfx_win32.c @@ -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; +//} +// +// \ No newline at end of file diff --git a/src/os/win32/os_gfx_win32.h b/src/os/win32/os_gfx_win32.h new file mode 100644 index 0000000..a633127 --- /dev/null +++ b/src/os/win32/os_gfx_win32.h @@ -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 */ \ No newline at end of file diff --git a/src/render/d3d12/render_d3d12.c b/src/render/d3d12/render_d3d12.c new file mode 100644 index 0000000..5c70bca --- /dev/null +++ b/src/render/d3d12/render_d3d12.c @@ -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; +//} \ No newline at end of file diff --git a/src/render/d3d12/render_d3d12.h b/src/render/d3d12/render_d3d12.h new file mode 100644 index 0000000..bd9748a --- /dev/null +++ b/src/render/d3d12/render_d3d12.h @@ -0,0 +1,30 @@ +#ifndef RENDER_D3D12_H +#define RENDER_D3D12_H + +#include +#include + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//~ + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//~ + +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 */ \ No newline at end of file diff --git a/src/render/render_core.c b/src/render/render_core.c new file mode 100644 index 0000000..1d1efce --- /dev/null +++ b/src/render/render_core.c @@ -0,0 +1,2 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//~ \ No newline at end of file diff --git a/src/render/render_core.h b/src/render/render_core.h new file mode 100644 index 0000000..72470cf --- /dev/null +++ b/src/render/render_core.h @@ -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 */ \ No newline at end of file diff --git a/src/render/render_inc.c b/src/render/render_inc.c index c488e70..ac6176d 100644 --- a/src/render/render_inc.c +++ b/src/render/render_inc.c @@ -1,2 +1,6 @@ ////////////////////////////////////////////////////////////////////////////////////////////// -//~ \ No newline at end of file +//~ + + +#include "render/render_core.c" +#include "render/d3d12/render_d3d12.c" \ No newline at end of file diff --git a/src/render/render_inc.h b/src/render/render_inc.h index 3572125..132ed50 100644 --- a/src/render/render_inc.h +++ b/src/render/render_inc.h @@ -4,4 +4,8 @@ ////////////////////////////////////////////////////////////////////////////////////////////// //~ + +#include "render/render_core.h" +#include "render/d3d12/render_d3d12.h" + #endif /* RENDER_INC_H */ \ No newline at end of file