Files
panopainter/src/platform_windows/windows_bootstrap_helpers.cpp

328 lines
9.8 KiB
C++

#include "pch.h"
#include "platform_windows/windows_bootstrap_helpers.h"
#include "app.h"
#include "legacy_gl_runtime_dispatch.h"
#include "legacy_preference_storage.h"
#include "log.h"
#include <shellscalingapi.h>
#include <string>
#if __has_include(<renderdoc_app.h>)
#include <renderdoc_app.h>
#define USE_RENDERDOC
#endif
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);
namespace pp::platform::windows {
void set_async_render_context(HDC hdc, HGLRC hrc);
}
namespace pp::platform::windows {
#ifdef USE_RENDERDOC
RENDERDOC_API_1_4_0* rdoc_api = NULL;
bool win32_renderdoc_init()
{
// At init, on windows
if (HMODULE mod = GetModuleHandleA("renderdoc.dll"))
{
pRENDERDOC_GetAPI RENDERDOC_GetAPI =
(pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI");
return RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void**)&rdoc_api);
}
return false;
}
void win32_renderdoc_frame_start()
{
if (rdoc_api)
rdoc_api->StartFrameCapture(NULL, NULL);
}
void win32_renderdoc_frame_end()
{
if (rdoc_api)
rdoc_api->EndFrameCapture(NULL, NULL);
}
#else
void win32_renderdoc_frame_start() { }
void win32_renderdoc_frame_end() { }
#endif
HRESULT(*GetDpiForMonitor_fn)(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT* dpiX, UINT* dpiY);
HRESULT(*SetProcessDpiAwareness_fn)(PROCESS_DPI_AWARENESS value);
void init_shcore_API()
{
HMODULE dll = LoadLibrary(L"Shcore.dll");
if (!dll)
{
LOG("cannot load Shcore.dll");
return;
}
LOG("loaded Shcore.dll");
GetDpiForMonitor_fn = (decltype(GetDpiForMonitor_fn))GetProcAddress(dll, "GetDpiForMonitor");
SetProcessDpiAwareness_fn = (decltype(SetProcessDpiAwareness_fn))GetProcAddress(dll, "SetProcessDpiAwareness");
}
// Returns the last Win32 error, in string format. Returns an empty string if there is no error.
std::string GetLastErrorAsString()
{
DWORD errorMessageID = ::GetLastError();
if (errorMessageID == 0)
return std::string();
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
std::string message(messageBuffer, size);
LocalFree(messageBuffer);
return message;
}
void ensure_runtime_data_directory()
{
FILE* fp_check = fopen("data\\layout.xml", "rb");
if (!fp_check)
{
LOG("data files not found");
static char path[MAX_PATH];
GetModuleFileNameA(NULL, path, MAX_PATH);
LOG("current dir %s", path);
PathRemoveFileSpecA(path);
SetCurrentDirectoryA(path);
LOG("change dir to %s", path);
return;
}
fclose(fp_check);
LOG("data files ok");
}
MainWindowStartupState initialize_main_window_startup_state()
{
auto startup = MainWindowStartupState {};
const auto hInst = GetModuleHandle(NULL);
const auto className = L"EngineMain";
startup.window_class.hInstance = hInst;
startup.window_class.lpfnWndProc = (WNDPROC)WndProc;
startup.window_class.lpszClassName = className;
startup.window_class.hbrBackground = (HBRUSH)COLOR_WINDOW;
startup.window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClass(&startup.window_class);
auto monitor = MonitorFromWindow(0, MONITOR_DEFAULTTOPRIMARY);
auto x = unsigned{ 96 };
auto y = unsigned{ 96 };
if (GetDpiForMonitor_fn)
GetDpiForMonitor_fn(monitor, MDT_EFFECTIVE_DPI, &x, &y);
App::I->display_density = (float)x / 96.f;
const auto window_preferences = pp::panopainter::read_legacy_window_preferences(SW_NORMAL);
if (window_preferences.has_ui_scale)
App::I->zoom = window_preferences.ui_scale;
else
App::I->zoom = (float)x / 96.f;
startup.show_command = window_preferences.show_command;
startup.client_rect = {
0,
0,
static_cast<LONG>(App::I->width * App::I->zoom),
static_cast<LONG>(App::I->height * App::I->zoom),
};
if (window_preferences.has_window_rect)
{
auto wnd_rect = window_preferences.window_rect;
App::I->width = wnd_rect.z - wnd_rect.x;
App::I->height = wnd_rect.w - wnd_rect.y;
startup.client_rect = { wnd_rect.x, wnd_rect.y, wnd_rect.z, wnd_rect.w };
startup.client_pos = { wnd_rect.x, wnd_rect.y };
}
else
{
AdjustWindowRect(&startup.client_rect, startup.window_style, false);
}
return startup;
}
void create_main_window(const MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, const wchar_t* window_title)
{
const int window_width = startup.client_rect.right - startup.client_rect.left;
const int window_height = startup.client_rect.bottom - startup.client_rect.top;
hWnd = CreateWindow(
startup.window_class.lpszClassName,
window_title,
startup.window_style,
startup.client_pos.x,
startup.client_pos.y,
window_width,
window_height,
0,
0,
hInst,
0);
}
void initialize_pixel_format_descriptor(PIXELFORMATDESCRIPTOR& pixel_format)
{
pixel_format.nSize = sizeof(pixel_format);
pixel_format.nVersion = 1;
pixel_format.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pixel_format.iPixelType = PFD_TYPE_RGBA;
pixel_format.cColorBits = 32;
pixel_format.cDepthBits = 24;
pixel_format.iLayerType = PFD_MAIN_PLANE;
}
bool load_glad_entry_points(HDC device_context)
{
if (!gladLoadGL())
{
LOG("gladLoadGL() failed");
return false;
}
if (!gladLoadWGL(device_context))
{
LOG("gladLoadWGL() failed");
return false;
}
return true;
}
pp::renderer::gl::OpenGlRuntimeInfo log_runtime_info()
{
auto runtime_info = pp::renderer::gl::OpenGlRuntimeInfo {};
const auto runtime_info_result = pp::renderer::gl::query_opengl_runtime_info(
pp::legacy::gl_runtime::runtime_info_dispatch());
if (runtime_info_result.ok())
{
runtime_info = runtime_info_result.value();
LOG("GL version: %s", runtime_info.version);
LOG("GL vendor: %s", runtime_info.vendor);
LOG("GL renderer: %s", runtime_info.renderer);
}
else
{
LOG("OpenGL runtime info query failed: %s", runtime_info_result.status().message);
}
return runtime_info;
}
bool upgrade_to_core_gl_context(const MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, const wchar_t* window_title, OpenGlWindowContext& context)
{
if (!GLAD_WGL_ARB_create_context)
{
LOG("WGL_ARB_create_context not supported");
// If not supported, go fuck yourself we are not gonna support your shitty device
return false;
}
const auto wgl_config = pp::renderer::gl::windows_wgl_core_context_3_3_config();
UINT num_format = 0;
wglMakeCurrent(NULL, NULL);
wglDeleteContext(context.render_context);
DestroyWindow(hWnd);
create_main_window(startup, hWnd, hInst, window_title);
context.device_context = GetDC(hWnd);
int pixel_format = 0;
wglChoosePixelFormatARB(
context.device_context,
wgl_config.pixel_format_attributes.data(),
nullptr,
1,
&pixel_format,
&num_format);
SetPixelFormat(context.device_context, pixel_format, &startup.pixel_format);
context.render_context = wglCreateContextAttribsARB(
context.device_context,
NULL,
wgl_config.context_attributes.data());
wglMakeCurrent(context.device_context, context.render_context);
set_async_render_context(context.device_context, context.render_context);
return true;
}
MainStartupResult initialize_main_window_and_gl(MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, wchar_t* window_title, OpenGlWindowContext& context)
{
create_main_window(startup, hWnd, hInst, L"PanoPainter");
initialize_pixel_format_descriptor(startup.pixel_format);
context.device_context = GetDC(hWnd);
const int pixel_format = ChoosePixelFormat(context.device_context, &startup.pixel_format);
SetPixelFormat(context.device_context, pixel_format, &startup.pixel_format);
context.render_context = wglCreateContext(context.device_context);
wglMakeCurrent(context.device_context, context.render_context);
set_async_render_context(context.device_context, context.render_context);
if (!load_glad_entry_points(context.device_context))
return MainStartupResult::GladLoadFailure;
context.runtime_info = log_runtime_info();
#ifdef USE_RENDERDOC
if (!win32_renderdoc_init())
LOG("Renderdoc not started");
#endif
const auto renderer_name = std::string(context.runtime_info.renderer != nullptr ? context.runtime_info.renderer : "");
swprintf_s(
window_title,
512,
L"PanoPainter %s (%s)",
g_version_number_w,
str2wstr(renderer_name).c_str());
if (!upgrade_to_core_gl_context(startup, hWnd, hInst, window_title, context))
return MainStartupResult::MissingCoreContextSupport;
return MainStartupResult::Ok;
}
BOOL UnadjustWindowRectEx(LPRECT prc, DWORD dwStyle, BOOL fMenu, DWORD dwExStyle)
{
RECT rc;
SetRectEmpty(&rc);
BOOL fRc = AdjustWindowRectEx(&rc, dwStyle, fMenu, dwExStyle);
if (fRc) {
prc->left -= rc.left;
prc->top -= rc.top;
prc->right -= rc.right;
prc->bottom -= rc.bottom;
}
return fRc;
}
void _pre_call_callback(const char* name, void* funcptr, int len_args, ...)
{
assert(App::I->is_render_thread());
}
void _post_call_callback(const char* name, void* funcptr, int len_args, ...)
{
GLenum error_code;
error_code = glad_glGetError();
if (error_code != pp::renderer::gl::no_error_code())
{
LOG("ERROR %d in %s\n", error_code, name);
}
}
}