vblank notification: win32
This commit is contained in:
parent
8fbfeab261
commit
be5b6aea30
|
@ -128,7 +128,6 @@ def build_platform_layer(target, release):
|
|||
|
||||
|
||||
def build_platform_layer_lib_win(release):
|
||||
|
||||
embed_text_files("src\\graphics\\glsl_shaders.h", "glsl_", [
|
||||
"src\\graphics\\glsl_shaders\\common.glsl",
|
||||
"src\\graphics\\glsl_shaders\\blit_vertex.glsl",
|
||||
|
@ -157,6 +156,8 @@ def build_platform_layer_lib_win(release):
|
|||
"ole32.lib",
|
||||
"shell32.lib",
|
||||
"shlwapi.lib",
|
||||
"dxgi.lib",
|
||||
"dxguid.lib",
|
||||
"/LIBPATH:ext/angle/lib",
|
||||
"libEGL.dll.lib",
|
||||
"libGLESv2.dll.lib",
|
||||
|
@ -178,7 +179,6 @@ def build_platform_layer_lib_win(release):
|
|||
"/IMPLIB:build/bin/orca.dll.lib",
|
||||
], check=True)
|
||||
|
||||
|
||||
def build_platform_layer_lib_mac(release):
|
||||
sdk_dir = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "app.c"
|
||||
#include "platform/platform_thread.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include <dwmapi.h>
|
||||
|
||||
void oc_init_keys()
|
||||
|
@ -169,6 +170,8 @@ void oc_init()
|
|||
u32 wheelScrollLines = 3;
|
||||
SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheelScrollLines, 0);
|
||||
oc_appData.win32.wheelScrollLines = wheelScrollLines;
|
||||
|
||||
oc_vsync_init();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -583,6 +586,14 @@ LRESULT oc_win32_win_proc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM
|
|||
}
|
||||
break;
|
||||
|
||||
case OC_WM_USER_VBLANK:
|
||||
{
|
||||
oc_event event = { 0 };
|
||||
event.type = OC_EVENT_FRAME;
|
||||
oc_queue_event(&event);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
handled = false;
|
||||
|
|
|
@ -49,6 +49,7 @@ typedef struct oc_win32_app_data
|
|||
enum OC_WM_USER
|
||||
{
|
||||
OC_WM_USER_DISPATCH_PROC = 0x0400, // WM_USER messages are defined from 0x400 to 0x7FFF
|
||||
OC_WM_USER_VBLANK = 0x0401,
|
||||
};
|
||||
|
||||
#endif __WIN32_APP_H_
|
||||
|
|
|
@ -125,6 +125,15 @@ ORCA_API oc_vec2 oc_surface_contents_scaling(oc_surface surface); //DOC: returns
|
|||
ORCA_API void oc_surface_bring_to_front(oc_surface surface); //DOC: puts surface on top of the surface stack
|
||||
ORCA_API void oc_surface_send_to_back(oc_surface surface); //DOC: puts surface at the bottom of the surface stack
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
//SECTION: vsync
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
typedef void (*oc_vsync_callback)(void* data);
|
||||
|
||||
ORCA_API void oc_vsync_init();
|
||||
ORCA_API void oc_vsync_window(oc_window window);
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
//SECTION: graphics canvas structs
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -148,6 +148,7 @@ oc_surface oc_surface_create_for_window(oc_window window, oc_surface_api api)
|
|||
if(surface)
|
||||
{
|
||||
surfaceHandle = oc_surface_handle_alloc(surface);
|
||||
oc_surface_swap_interval(surfaceHandle, 0);
|
||||
oc_surface_select(surfaceHandle);
|
||||
}
|
||||
return (surfaceHandle);
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
/************************************************************/ /**
|
||||
*
|
||||
* @file: win32_vsync.h
|
||||
* @author: Reuben Dunnington
|
||||
* @date: 26/08/2023
|
||||
*
|
||||
*****************************************************************/
|
||||
|
||||
// #define WIN32_LEAN_AND_MEAN
|
||||
// #define WIN32_EXTRA_LEAN
|
||||
// #define NOMINMAX
|
||||
|
||||
// #define D3D11_NO_HELPERS
|
||||
// #define CINTERFACE
|
||||
// #define COBJMACROS
|
||||
|
||||
// #define interface struct
|
||||
|
||||
// #include <windows.h>
|
||||
|
||||
#include "platform/platform_thread.h"
|
||||
#include "app/win32_app.h"
|
||||
|
||||
// This forward declaration is needed to suppress an order of declarations bug in the d3d headers.
|
||||
// d3d11shader.h(454): warning C4115: 'ID3D11ModuleInstance': named type definition in parentheses
|
||||
// struct ID3D11ModuleInstance;
|
||||
|
||||
#define COBJMACROS
|
||||
#define interface struct
|
||||
#include <d3d11_1.h>
|
||||
#include <dxgi1_6.h>
|
||||
#undef interface
|
||||
|
||||
// #include <dxgidebug.h>
|
||||
// #include <d3dcompiler.h>
|
||||
|
||||
typedef struct oc_vsync_data
|
||||
{
|
||||
IDXGIFactory4* factory;
|
||||
IDXGIAdapter1* adapter;
|
||||
} oc_vsync_data;
|
||||
|
||||
oc_vsync_data __oc_vsync_data;
|
||||
|
||||
typedef struct oc_vsync_thread_data
|
||||
{
|
||||
IDXGIAdapter1* adapter;
|
||||
oc_window window;
|
||||
bool quit;
|
||||
} oc_vsync_thread_data;
|
||||
|
||||
static i32 oc_window_vysnc_notification_thread(void* userPointer)
|
||||
{
|
||||
oc_vsync_thread_data* threadData = (oc_vsync_thread_data*)userPointer;
|
||||
|
||||
while(!threadData->quit)
|
||||
{
|
||||
oc_window_data* windowData = oc_window_ptr_from_handle(threadData->window);
|
||||
if(!windowData)
|
||||
{
|
||||
oc_log_error("Failed to get window ptr - assuming window was closed.");
|
||||
break;
|
||||
}
|
||||
|
||||
RECT windowRect = { 0 };
|
||||
if(GetWindowRect(windowData->win32.hWnd, &windowRect) == FALSE)
|
||||
{
|
||||
oc_log_error("Failed to get window rect with error: %d.", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
//NOTE(Reuben): Wait for VBlank on the display device with which the window has the most intersecting area
|
||||
IDXGIOutput* output = NULL;
|
||||
IDXGIOutput* selectedOutput = NULL;
|
||||
uint32_t selected_intersect_area = 0;
|
||||
for(UINT i = 0; DXGI_ERROR_NOT_FOUND != IDXGIAdapter1_EnumOutputs(threadData->adapter, i, &output); ++i)
|
||||
{
|
||||
DXGI_OUTPUT_DESC outputDesc = { 0 };
|
||||
HRESULT hr = IDXGIOutput_GetDesc(output, &outputDesc);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
RECT intersectRect = { 0 };
|
||||
if(IntersectRect(&intersectRect, &windowRect, &outputDesc.DesktopCoordinates))
|
||||
{
|
||||
uint32_t outputIntersectArea = (intersectRect.right - intersectRect.left) * (intersectRect.bottom - intersectRect.top);
|
||||
|
||||
if(selectedOutput == NULL || outputIntersectArea > selected_intersect_area)
|
||||
{
|
||||
selectedOutput = output;
|
||||
selected_intersect_area = outputIntersectArea;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
oc_log_error("Failed to get IDXGIOutput desc with error: %d", hr);
|
||||
}
|
||||
|
||||
if(selectedOutput != output)
|
||||
{
|
||||
IDXGIOutput_Release(output);
|
||||
}
|
||||
}
|
||||
|
||||
if(selectedOutput)
|
||||
{
|
||||
HRESULT hr = IDXGIOutput_WaitForVBlank(selectedOutput);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
// TODO(reuben) - fall back to software timer
|
||||
oc_log_warning("Failed to wait for vblank with error: %d", hr);
|
||||
}
|
||||
|
||||
SendMessage(windowData->win32.hWnd, OC_WM_USER_VBLANK, 0, 0);
|
||||
|
||||
IDXGIOutput_Release(selectedOutput);
|
||||
}
|
||||
else
|
||||
{
|
||||
oc_log_warning("No outputs found. Were all monitors unplugged?");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void oc_vsync_init()
|
||||
{
|
||||
if(__oc_vsync_data.adapter)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IDXGIFactory4* factory = NULL;
|
||||
{
|
||||
UINT flags = 0;
|
||||
flags |= DXGI_CREATE_FACTORY_DEBUG; // TODO make this optional
|
||||
|
||||
HRESULT hr = CreateDXGIFactory2(flags, &IID_IDXGIFactory4, (void**)&factory);
|
||||
if(!SUCCEEDED(hr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
IDXGIAdapter1* adapter = NULL;
|
||||
IDXGIAdapter1* adapterFallback = NULL;
|
||||
IDXGIAdapter1* enumeratedAdapter = NULL;
|
||||
|
||||
for(UINT i = 0; DXGI_ERROR_NOT_FOUND != IDXGIFactory1_EnumAdapters1(factory, i, &enumeratedAdapter); ++i)
|
||||
{
|
||||
DXGI_ADAPTER_DESC1 adapterDesc;
|
||||
IDXGIAdapter1_GetDesc1(enumeratedAdapter, &adapterDesc);
|
||||
if(adapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
|
||||
{
|
||||
adapterFallback = enumeratedAdapter;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
adapter = enumeratedAdapter;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(adapter == NULL)
|
||||
{
|
||||
adapter = adapterFallback;
|
||||
if(adapter)
|
||||
{
|
||||
oc_log_info("Couldn't find a dedicated hardware DXGI adapater, using software fallback.");
|
||||
}
|
||||
}
|
||||
|
||||
if(adapter)
|
||||
{
|
||||
__oc_vsync_data = (oc_vsync_data){
|
||||
.factory = factory,
|
||||
.adapter = adapter,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
oc_log_info("Couldn't find any DXGI adapters. Vsync will be unavailable.");
|
||||
IDXGIFactory_Release(factory);
|
||||
}
|
||||
}
|
||||
|
||||
void oc_vsync_window(oc_window window)
|
||||
{
|
||||
if(__oc_vsync_data.adapter)
|
||||
{
|
||||
oc_vsync_thread_data* data = malloc(sizeof(oc_vsync_thread_data));
|
||||
*data = (oc_vsync_thread_data){
|
||||
.adapter = __oc_vsync_data.adapter,
|
||||
.window = window,
|
||||
.quit = false,
|
||||
};
|
||||
oc_thread_create_with_name(oc_window_vysnc_notification_thread, data, OC_STR8("vblank thread"));
|
||||
}
|
||||
else
|
||||
{
|
||||
oc_log_error("No DXGI adapter available - unable to start vsync notification thread.");
|
||||
}
|
||||
}
|
|
@ -74,6 +74,7 @@
|
|||
|
||||
#if OC_PLATFORM_WINDOWS
|
||||
#include "app/win32_app.c"
|
||||
#include "graphics/win32_vsync.c"
|
||||
#include "graphics/graphics_common.c"
|
||||
#include "graphics/graphics_surface.c"
|
||||
|
||||
|
|
|
@ -676,6 +676,19 @@ i32 orca_runloop(void* user)
|
|||
}
|
||||
break;
|
||||
|
||||
case OC_EVENT_FRAME:
|
||||
{
|
||||
if(exports[OC_EXPORT_FRAME_REFRESH])
|
||||
{
|
||||
M3Result res = m3_Call(exports[OC_EXPORT_FRAME_REFRESH], 0, 0);
|
||||
if(res)
|
||||
{
|
||||
ORCA_WASM3_ABORT(app->runtime.m3Runtime, res, "Runtime error");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -867,6 +880,8 @@ int main(int argc, char** argv)
|
|||
oc_rect windowRect = { .x = 100, .y = 100, .w = 810, .h = 610 };
|
||||
app->window = oc_window_create(windowRect, OC_STR8("orca"), 0);
|
||||
|
||||
oc_vsync_window(app->window);
|
||||
|
||||
app->debugOverlay.show = false;
|
||||
app->debugOverlay.surface = oc_surface_create_for_window(app->window, OC_CANVAS);
|
||||
app->debugOverlay.canvas = oc_canvas_create();
|
||||
|
|
Loading…
Reference in New Issue