mirror of
https://github.com/godotengine/godot.git
synced 2024-11-10 14:12:51 +00:00
Merge pull request #60894 from derammo/derammo_opengl3_windows
This commit is contained in:
commit
349aa9c884
@ -210,6 +210,9 @@ RasterizerGLES3::RasterizerGLES3() {
|
|||||||
#ifdef GLAD_ENABLED
|
#ifdef GLAD_ENABLED
|
||||||
if (!gladLoadGL()) {
|
if (!gladLoadGL()) {
|
||||||
ERR_PRINT("Error initializing GLAD");
|
ERR_PRINT("Error initializing GLAD");
|
||||||
|
// FIXME this is an early return from a constructor. Any other code using this instance will crash or the finalizer will crash, because none of
|
||||||
|
// the members of this instance are initialized, so this just makes debugging harder. It should either crash here intentionally,
|
||||||
|
// or we need to actually test for this situation before constructing this.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -285,6 +288,9 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
|
|||||||
|
|
||||||
// TODO: do we need a keep 3d linear option?
|
// TODO: do we need a keep 3d linear option?
|
||||||
|
|
||||||
|
// Make sure we are drawing to the right context.
|
||||||
|
DisplayServer::get_singleton()->gl_window_make_current(p_screen);
|
||||||
|
|
||||||
if (rt->external.fbo != 0) {
|
if (rt->external.fbo != 0) {
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->external.fbo);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->external.fbo);
|
||||||
} else {
|
} else {
|
||||||
@ -292,6 +298,7 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
|
|||||||
}
|
}
|
||||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
||||||
|
// Flip content upside down to correct for coordinates.
|
||||||
glBlitFramebuffer(0, 0, rt->size.x, rt->size.y, 0, p_screen_rect.size.y, p_screen_rect.size.x, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
glBlitFramebuffer(0, 0, rt->size.x, rt->size.y, 0, p_screen_rect.size.y, p_screen_rect.size.x, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ Config::Config() {
|
|||||||
singleton = this;
|
singleton = this;
|
||||||
|
|
||||||
{
|
{
|
||||||
int max_extensions = 0;
|
GLint max_extensions = 0;
|
||||||
glGetIntegerv(GL_NUM_EXTENSIONS, &max_extensions);
|
glGetIntegerv(GL_NUM_EXTENSIONS, &max_extensions);
|
||||||
for (int i = 0; i < max_extensions; i++) {
|
for (int i = 0; i < max_extensions; i++) {
|
||||||
const GLubyte *s = glGetStringi(GL_EXTENSIONS, i);
|
const GLubyte *s = glGetStringi(GL_EXTENSIONS, i);
|
||||||
|
@ -2542,7 +2542,7 @@ RS::ShaderNativeSourceCode MaterialStorage::shader_get_native_source_code(RID p_
|
|||||||
|
|
||||||
/* MATERIAL API */
|
/* MATERIAL API */
|
||||||
|
|
||||||
void MaterialStorage::_material_queue_update(Material *material, bool p_uniform, bool p_texture) {
|
void MaterialStorage::_material_queue_update(GLES3::Material *material, bool p_uniform, bool p_texture) {
|
||||||
material->uniform_dirty = material->uniform_dirty || p_uniform;
|
material->uniform_dirty = material->uniform_dirty || p_uniform;
|
||||||
material->texture_dirty = material->texture_dirty || p_texture;
|
material->texture_dirty = material->texture_dirty || p_texture;
|
||||||
|
|
||||||
|
@ -641,6 +641,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||||||
bool found_project = false;
|
bool found_project = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
String default_renderer = "";
|
||||||
|
String renderer_hints = "";
|
||||||
|
|
||||||
packed_data = PackedData::get_singleton();
|
packed_data = PackedData::get_singleton();
|
||||||
if (!packed_data) {
|
if (!packed_data) {
|
||||||
packed_data = memnew(PackedData);
|
packed_data = memnew(PackedData);
|
||||||
@ -1306,14 +1309,33 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||||||
|
|
||||||
// possibly be worth changing the default from vulkan to something lower spec,
|
// possibly be worth changing the default from vulkan to something lower spec,
|
||||||
// for the project manager, depending on how smooth the fallback is.
|
// for the project manager, depending on how smooth the fallback is.
|
||||||
GLOBAL_DEF_RST("rendering/driver/driver_name", "vulkan");
|
|
||||||
|
|
||||||
// this list is hard coded, which makes it more difficult to add new backends.
|
// this list is hard coded, which makes it more difficult to add new backends.
|
||||||
// can potentially be changed to more of a plugin system at a later date.
|
// can potentially be changed to more of a plugin system at a later date.
|
||||||
|
|
||||||
|
// Start with Vulkan, which will be the default if enabled.
|
||||||
|
#ifdef VULKAN_ENABLED
|
||||||
|
renderer_hints = "vulkan";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// And OpenGL3 next, or first if Vulkan is disabled.
|
||||||
|
#ifdef GLES3_ENABLED
|
||||||
|
if (!renderer_hints.is_empty()) {
|
||||||
|
renderer_hints += ",";
|
||||||
|
}
|
||||||
|
renderer_hints += "opengl3";
|
||||||
|
#endif
|
||||||
|
if (renderer_hints.is_empty()) {
|
||||||
|
ERR_PRINT("No rendering driver available.");
|
||||||
|
}
|
||||||
|
|
||||||
|
default_renderer = renderer_hints.get_slice(",", 0);
|
||||||
|
GLOBAL_DEF_RST("rendering/driver/driver_name", default_renderer);
|
||||||
|
|
||||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/driver/driver_name",
|
ProjectSettings::get_singleton()->set_custom_property_info("rendering/driver/driver_name",
|
||||||
PropertyInfo(Variant::STRING,
|
PropertyInfo(Variant::STRING,
|
||||||
"rendering/driver/driver_name",
|
"rendering/driver/driver_name",
|
||||||
PROPERTY_HINT_ENUM, "vulkan,opengl3"));
|
PROPERTY_HINT_ENUM, renderer_hints));
|
||||||
|
|
||||||
// if not set on the command line
|
// if not set on the command line
|
||||||
if (rendering_driver.is_empty()) {
|
if (rendering_driver.is_empty()) {
|
||||||
|
@ -269,12 +269,14 @@ def configure_msvc(env, manual_msvc_config):
|
|||||||
"dwmapi",
|
"dwmapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED"])
|
if env["vulkan"]:
|
||||||
if not env["use_volk"]:
|
env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED"])
|
||||||
LIBS += ["vulkan"]
|
if not env["use_volk"]:
|
||||||
|
LIBS += ["vulkan"]
|
||||||
|
|
||||||
env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
|
if env["opengl3"]:
|
||||||
LIBS += ["opengl32"]
|
env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
|
||||||
|
LIBS += ["opengl32"]
|
||||||
|
|
||||||
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
|
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
|
||||||
|
|
||||||
|
@ -607,8 +607,11 @@ void DisplayServerWindows::show_window(WindowID p_id) {
|
|||||||
_update_window_style(p_id);
|
_update_window_style(p_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShowWindow(wd.hWnd, (wd.no_focus || wd.is_popup) ? SW_SHOWNOACTIVATE : SW_SHOW); // Show the window.
|
if (wd.no_focus || wd.is_popup) {
|
||||||
if (!wd.no_focus && !wd.is_popup) {
|
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
|
||||||
|
ShowWindow(wd.hWnd, SW_SHOWNA);
|
||||||
|
} else {
|
||||||
|
ShowWindow(wd.hWnd, SW_SHOW);
|
||||||
SetForegroundWindow(wd.hWnd); // Slightly higher priority.
|
SetForegroundWindow(wd.hWnd); // Slightly higher priority.
|
||||||
SetFocus(wd.hWnd); // Set keyboard focus.
|
SetFocus(wd.hWnd); // Set keyboard focus.
|
||||||
}
|
}
|
||||||
@ -1798,7 +1801,9 @@ void DisplayServerWindows::make_rendering_thread() {
|
|||||||
|
|
||||||
void DisplayServerWindows::swap_buffers() {
|
void DisplayServerWindows::swap_buffers() {
|
||||||
#if defined(GLES3_ENABLED)
|
#if defined(GLES3_ENABLED)
|
||||||
gl_manager->swap_buffers();
|
if (gl_manager) {
|
||||||
|
gl_manager->swap_buffers();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1952,14 +1957,18 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
|
|||||||
void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
|
void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
|
||||||
_THREAD_SAFE_METHOD_
|
_THREAD_SAFE_METHOD_
|
||||||
#if defined(VULKAN_ENABLED)
|
#if defined(VULKAN_ENABLED)
|
||||||
context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
|
if (context_vulkan) {
|
||||||
|
context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const {
|
DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const {
|
||||||
_THREAD_SAFE_METHOD_
|
_THREAD_SAFE_METHOD_
|
||||||
#if defined(VULKAN_ENABLED)
|
#if defined(VULKAN_ENABLED)
|
||||||
return context_vulkan->get_vsync_mode(p_window);
|
if (context_vulkan) {
|
||||||
|
return context_vulkan->get_vsync_mode(p_window);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return DisplayServer::VSYNC_ENABLED;
|
return DisplayServer::VSYNC_ENABLED;
|
||||||
}
|
}
|
||||||
@ -2193,8 +2202,39 @@ LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam)
|
|||||||
return ::CallNextHookEx(mouse_monitor, code, wParam, lParam);
|
return ::CallNextHookEx(mouse_monitor, code, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our default window procedure to handle processing of window-related system messages/events.
|
// Handle a single window message received while CreateWindowEx is still on the stack and our data
|
||||||
// Also known as DefProc or DefWindowProc.
|
// structures are not fully initialized.
|
||||||
|
LRESULT DisplayServerWindows::_handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||||
|
switch (uMsg) {
|
||||||
|
case WM_GETMINMAXINFO: {
|
||||||
|
// We receive this during CreateWindowEx and we haven't initialized the window
|
||||||
|
// struct, so let Windows figure out the maximized size.
|
||||||
|
// Silently forward to user/default.
|
||||||
|
} break;
|
||||||
|
case WM_NCCREATE: {
|
||||||
|
// We tunnel an unowned pointer to our window context (WindowData) through the
|
||||||
|
// first possible message (WM_NCCREATE) to fix up our window context collection.
|
||||||
|
CREATESTRUCTW *pCreate = (CREATESTRUCTW *)lParam;
|
||||||
|
WindowData *pWindowData = reinterpret_cast<WindowData *>(pCreate->lpCreateParams);
|
||||||
|
|
||||||
|
// Fix this up so we can recognize the remaining messages.
|
||||||
|
pWindowData->hWnd = hWnd;
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
// Additional messages during window creation should happen after we fixed
|
||||||
|
// up the data structures on WM_NCCREATE, but this might change in the future,
|
||||||
|
// so report an error here and then we can implement them.
|
||||||
|
ERR_PRINT_ONCE(vformat("Unexpected window message 0x%x received for window we cannot recognize in our collection; sequence error.", uMsg));
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_proc) {
|
||||||
|
return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The window procedure for our window class "Engine", used to handle processing of window-related system messages/events.
|
||||||
// See: https://docs.microsoft.com/en-us/windows/win32/winmsg/window-procedures
|
// See: https://docs.microsoft.com/en-us/windows/win32/winmsg/window-procedures
|
||||||
LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||||
if (drop_events) {
|
if (drop_events) {
|
||||||
@ -2208,7 +2248,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
|
|||||||
WindowID window_id = INVALID_WINDOW_ID;
|
WindowID window_id = INVALID_WINDOW_ID;
|
||||||
bool window_created = false;
|
bool window_created = false;
|
||||||
|
|
||||||
// Check whether window exists.
|
// Check whether window exists
|
||||||
|
// FIXME this is O(n), where n is the set of currently open windows and subwindows
|
||||||
|
// we should have a secondary map from HWND to WindowID or even WindowData* alias, if we want to eliminate all the map lookups below
|
||||||
for (const KeyValue<WindowID, WindowData> &E : windows) {
|
for (const KeyValue<WindowID, WindowData> &E : windows) {
|
||||||
if (E.value.hWnd == hWnd) {
|
if (E.value.hWnd == hWnd) {
|
||||||
window_id = E.key;
|
window_id = E.key;
|
||||||
@ -2217,10 +2259,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Window doesn't exist or creation in progress, don't handle messages yet.
|
// WARNING: we get called with events before the window is registered in our collection
|
||||||
|
// specifically, even the call to CreateWindowEx already calls here while still on the stack,
|
||||||
|
// so there is no way to store the window handle in our collection before we get here
|
||||||
if (!window_created) {
|
if (!window_created) {
|
||||||
window_id = window_id_counter;
|
// don't let code below operate on incompletely initialized window objects or missing window_id
|
||||||
ERR_FAIL_COND_V(!windows.has(window_id), 0);
|
return _handle_early_window_message(hWnd, uMsg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process window messages.
|
// Process window messages.
|
||||||
@ -3388,11 +3432,17 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
|
|||||||
WindowRect.top,
|
WindowRect.top,
|
||||||
WindowRect.right - WindowRect.left,
|
WindowRect.right - WindowRect.left,
|
||||||
WindowRect.bottom - WindowRect.top,
|
WindowRect.bottom - WindowRect.top,
|
||||||
nullptr, nullptr, hInstance, nullptr);
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
hInstance,
|
||||||
|
// tunnel the WindowData we need to handle creation message
|
||||||
|
// lifetime is ensured because we are still on the stack when this is
|
||||||
|
// processed in the window proc
|
||||||
|
reinterpret_cast<void *>(&wd));
|
||||||
if (!wd.hWnd) {
|
if (!wd.hWnd) {
|
||||||
MessageBoxW(nullptr, L"Window Creation Error.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
|
MessageBoxW(nullptr, L"Window Creation Error.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
|
||||||
windows.erase(id);
|
windows.erase(id);
|
||||||
return INVALID_WINDOW_ID;
|
ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create Windows OS window.");
|
||||||
}
|
}
|
||||||
if (p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
|
if (p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
|
||||||
wd.pre_fs_valid = true;
|
wd.pre_fs_valid = true;
|
||||||
@ -3412,7 +3462,14 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
|
|||||||
#ifdef GLES3_ENABLED
|
#ifdef GLES3_ENABLED
|
||||||
if (gl_manager) {
|
if (gl_manager) {
|
||||||
Error err = gl_manager->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top);
|
Error err = gl_manager->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top);
|
||||||
ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Failed to create an OpenGL window.");
|
|
||||||
|
// shut down OpenGL, to mirror behavior of Vulkan code
|
||||||
|
if (err != OK) {
|
||||||
|
memdelete(gl_manager);
|
||||||
|
gl_manager = nullptr;
|
||||||
|
windows.erase(id);
|
||||||
|
ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create an OpenGL window.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -3457,6 +3514,8 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
|
|||||||
ImmReleaseContext(wd.hWnd, wd.im_himc);
|
ImmReleaseContext(wd.hWnd, wd.im_himc);
|
||||||
|
|
||||||
wd.im_position = Vector2();
|
wd.im_position = Vector2();
|
||||||
|
|
||||||
|
// FIXME this is wrong in cases where the window coordinates were changed due to full screen mode; use WindowRect
|
||||||
wd.last_pos = p_rect.position;
|
wd.last_pos = p_rect.position;
|
||||||
wd.width = p_rect.size.width;
|
wd.width = p_rect.size.width;
|
||||||
wd.height = p_rect.size.height;
|
wd.height = p_rect.size.height;
|
||||||
@ -3747,6 +3806,7 @@ DisplayServerWindows::~DisplayServerWindows() {
|
|||||||
|
|
||||||
#ifdef GLES3_ENABLED
|
#ifdef GLES3_ENABLED
|
||||||
// destroy windows .. NYI?
|
// destroy windows .. NYI?
|
||||||
|
// FIXME wglDeleteContext is never called
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (windows.has(MAIN_WINDOW_ID)) {
|
if (windows.has(MAIN_WINDOW_ID)) {
|
||||||
|
@ -448,6 +448,8 @@ class DisplayServerWindows : public DisplayServer {
|
|||||||
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
|
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
|
||||||
void _dispatch_input_event(const Ref<InputEvent> &p_event);
|
void _dispatch_input_event(const Ref<InputEvent> &p_event);
|
||||||
|
|
||||||
|
LRESULT _handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
LRESULT MouseProc(int code, WPARAM wParam, LPARAM lParam);
|
LRESULT MouseProc(int code, WPARAM wParam, LPARAM lParam);
|
||||||
|
@ -54,6 +54,18 @@
|
|||||||
|
|
||||||
typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
|
typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
|
||||||
|
|
||||||
|
static String format_error_message(DWORD id) {
|
||||||
|
LPWSTR messageBuffer = nullptr;
|
||||||
|
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
|
||||||
|
|
||||||
|
String msg = "Error " + itos(id) + ": " + String::utf16((const char16_t *)messageBuffer, size);
|
||||||
|
|
||||||
|
LocalFree(messageBuffer);
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
int GLManager_Windows::_find_or_create_display(GLWindow &win) {
|
int GLManager_Windows::_find_or_create_display(GLWindow &win) {
|
||||||
// find display NYI, only 1 supported so far
|
// find display NYI, only 1 supported so far
|
||||||
if (_displays.size()) {
|
if (_displays.size()) {
|
||||||
@ -79,7 +91,7 @@ int GLManager_Windows::_find_or_create_display(GLWindow &win) {
|
|||||||
return new_display_id;
|
return new_display_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
|
static Error _configure_pixel_format(HDC hDC) {
|
||||||
static PIXELFORMATDESCRIPTOR pfd = {
|
static PIXELFORMATDESCRIPTOR pfd = {
|
||||||
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
|
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
|
||||||
1,
|
1,
|
||||||
@ -101,9 +113,6 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
|
|||||||
0, 0, 0 // Layer Masks Ignored
|
0, 0, 0 // Layer Masks Ignored
|
||||||
};
|
};
|
||||||
|
|
||||||
// alias
|
|
||||||
HDC hDC = win.hDC;
|
|
||||||
|
|
||||||
int pixel_format = ChoosePixelFormat(hDC, &pfd);
|
int pixel_format = ChoosePixelFormat(hDC, &pfd);
|
||||||
if (!pixel_format) // Did Windows Find A Matching Pixel Format?
|
if (!pixel_format) // Did Windows Find A Matching Pixel Format?
|
||||||
{
|
{
|
||||||
@ -116,13 +125,24 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
|
|||||||
return ERR_CANT_CREATE; // Return FALSE
|
return ERR_CANT_CREATE; // Return FALSE
|
||||||
}
|
}
|
||||||
|
|
||||||
gl_display.hRC = wglCreateContext(hDC);
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
|
||||||
|
Error err = _configure_pixel_format(win.hDC);
|
||||||
|
if (err != OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_display.hRC = wglCreateContext(win.hDC);
|
||||||
if (!gl_display.hRC) // Are We Able To Get A Rendering Context?
|
if (!gl_display.hRC) // Are We Able To Get A Rendering Context?
|
||||||
{
|
{
|
||||||
return ERR_CANT_CREATE; // Return FALSE
|
return ERR_CANT_CREATE; // Return FALSE
|
||||||
}
|
}
|
||||||
|
|
||||||
wglMakeCurrent(hDC, gl_display.hRC);
|
if (!wglMakeCurrent(win.hDC, gl_display.hRC)) {
|
||||||
|
ERR_PRINT("Could not attach OpenGL context to newly created window: " + format_error_message(GetLastError()));
|
||||||
|
}
|
||||||
|
|
||||||
int attribs[] = {
|
int attribs[] = {
|
||||||
WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context
|
WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context
|
||||||
@ -143,57 +163,61 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
|
|||||||
return ERR_CANT_CREATE;
|
return ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
HGLRC new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs);
|
HGLRC new_hRC = wglCreateContextAttribsARB(win.hDC, 0, attribs);
|
||||||
if (!new_hRC) {
|
if (!new_hRC) {
|
||||||
wglDeleteContext(gl_display.hRC);
|
wglDeleteContext(gl_display.hRC);
|
||||||
gl_display.hRC = 0;
|
gl_display.hRC = 0;
|
||||||
return ERR_CANT_CREATE; // Return false
|
return ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
wglMakeCurrent(hDC, nullptr);
|
|
||||||
|
if (!wglMakeCurrent(win.hDC, nullptr)) {
|
||||||
|
ERR_PRINT("Could not detach OpenGL context from newly created window: " + format_error_message(GetLastError()));
|
||||||
|
}
|
||||||
|
|
||||||
wglDeleteContext(gl_display.hRC);
|
wglDeleteContext(gl_display.hRC);
|
||||||
gl_display.hRC = new_hRC;
|
gl_display.hRC = new_hRC;
|
||||||
|
|
||||||
if (!wglMakeCurrent(hDC, gl_display.hRC)) // Try To Activate The Rendering Context
|
if (!wglMakeCurrent(win.hDC, gl_display.hRC)) // Try To Activate The Rendering Context
|
||||||
{
|
{
|
||||||
|
ERR_PRINT("Could not attach OpenGL context to newly created window with replaced OpenGL context: " + format_error_message(GetLastError()));
|
||||||
wglDeleteContext(gl_display.hRC);
|
wglDeleteContext(gl_display.hRC);
|
||||||
gl_display.hRC = 0;
|
gl_display.hRC = 0;
|
||||||
return ERR_CANT_CREATE; // Return FALSE
|
return ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height) {
|
Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height) {
|
||||||
HDC hdc = GetDC(p_hwnd);
|
HDC hDC = GetDC(p_hwnd);
|
||||||
if (!hdc) {
|
if (!hDC) {
|
||||||
return ERR_CANT_CREATE; // Return FALSE
|
return ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure vector is big enough...
|
// configure the HDC to use a compatible pixel format
|
||||||
// we can mirror the external vector, it is simpler
|
Error result = _configure_pixel_format(hDC);
|
||||||
// to keep the IDs identical for fast lookup
|
if (result != OK) {
|
||||||
if (p_window_id >= (int)_windows.size()) {
|
return result;
|
||||||
_windows.resize(p_window_id + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GLWindow &win = _windows[p_window_id];
|
GLWindow win;
|
||||||
win.in_use = true;
|
|
||||||
win.window_id = p_window_id;
|
|
||||||
win.width = p_width;
|
win.width = p_width;
|
||||||
win.height = p_height;
|
win.height = p_height;
|
||||||
win.hwnd = p_hwnd;
|
win.hwnd = p_hwnd;
|
||||||
win.hDC = hdc;
|
win.hDC = hDC;
|
||||||
|
|
||||||
win.gldisplay_id = _find_or_create_display(win);
|
win.gldisplay_id = _find_or_create_display(win);
|
||||||
|
|
||||||
if (win.gldisplay_id == -1) {
|
if (win.gldisplay_id == -1) {
|
||||||
// release DC?
|
|
||||||
_windows.remove_at(_windows.size() - 1);
|
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WARNING: p_window_id is an eternally growing integer since popup windows keep coming and going
|
||||||
|
// and each of them has a higher id than the previous, so it must be used in a map not a vector
|
||||||
|
_windows[p_window_id] = win;
|
||||||
|
|
||||||
// make current
|
// make current
|
||||||
window_make_current(_windows.size() - 1);
|
window_make_current(p_window_id);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -217,11 +241,10 @@ int GLManager_Windows::window_get_height(DisplayServer::WindowID p_window_id) {
|
|||||||
|
|
||||||
void GLManager_Windows::window_destroy(DisplayServer::WindowID p_window_id) {
|
void GLManager_Windows::window_destroy(DisplayServer::WindowID p_window_id) {
|
||||||
GLWindow &win = get_window(p_window_id);
|
GLWindow &win = get_window(p_window_id);
|
||||||
win.in_use = false;
|
|
||||||
|
|
||||||
if (_current_window == &win) {
|
if (_current_window == &win) {
|
||||||
_current_window = nullptr;
|
_current_window = nullptr;
|
||||||
}
|
}
|
||||||
|
_windows.erase(p_window_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLManager_Windows::release_current() {
|
void GLManager_Windows::release_current() {
|
||||||
@ -229,7 +252,9 @@ void GLManager_Windows::release_current() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wglMakeCurrent(_current_window->hDC, nullptr);
|
if (!wglMakeCurrent(_current_window->hDC, nullptr)) {
|
||||||
|
ERR_PRINT("Could not detach OpenGL context from window marked current: " + format_error_message(GetLastError()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id) {
|
void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id) {
|
||||||
@ -237,10 +262,8 @@ void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// crash if our data structures are out of sync, i.e. not found
|
||||||
GLWindow &win = _windows[p_window_id];
|
GLWindow &win = _windows[p_window_id];
|
||||||
if (!win.in_use) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// noop
|
// noop
|
||||||
if (&win == _current_window) {
|
if (&win == _current_window) {
|
||||||
@ -248,7 +271,9 @@ void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const GLDisplay &disp = get_display(win.gldisplay_id);
|
const GLDisplay &disp = get_display(win.gldisplay_id);
|
||||||
wglMakeCurrent(win.hDC, disp.hRC);
|
if (!wglMakeCurrent(win.hDC, disp.hRC)) {
|
||||||
|
ERR_PRINT("Could not switch OpenGL context to other window: " + format_error_message(GetLastError()));
|
||||||
|
}
|
||||||
|
|
||||||
_internal_set_current_window(&win);
|
_internal_set_current_window(&win);
|
||||||
}
|
}
|
||||||
@ -257,34 +282,19 @@ void GLManager_Windows::make_current() {
|
|||||||
if (!_current_window) {
|
if (!_current_window) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!_current_window->in_use) {
|
|
||||||
WARN_PRINT("current window not in use!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const GLDisplay &disp = get_current_display();
|
const GLDisplay &disp = get_current_display();
|
||||||
wglMakeCurrent(_current_window->hDC, disp.hRC);
|
if (!wglMakeCurrent(_current_window->hDC, disp.hRC)) {
|
||||||
|
ERR_PRINT("Could not switch OpenGL context to window marked current: " + format_error_message(GetLastError()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLManager_Windows::swap_buffers() {
|
void GLManager_Windows::swap_buffers() {
|
||||||
// NO NEED TO CALL SWAP BUFFERS for each window...
|
// on other platforms, OpenGL swaps buffers for all windows (on all displays, really?)
|
||||||
// see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXSwapBuffers.xml
|
// Windows swaps buffers on a per-window basis
|
||||||
|
// REVISIT: this could be structurally bad, should we have "dirty" flags then?
|
||||||
if (!_current_window) {
|
for (KeyValue<DisplayServer::WindowID, GLWindow> &entry : _windows) {
|
||||||
return;
|
SwapBuffers(entry.value.hDC);
|
||||||
}
|
}
|
||||||
if (!_current_window->in_use) {
|
|
||||||
WARN_PRINT("current window not in use!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// print_line("\tswap_buffers");
|
|
||||||
|
|
||||||
// only for debugging without drawing anything
|
|
||||||
// glClearColor(Math::randf(), 0, 1, 1);
|
|
||||||
//glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
// const GLDisplay &disp = get_current_display();
|
|
||||||
SwapBuffers(_current_window->hDC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error GLManager_Windows::initialize() {
|
Error GLManager_Windows::initialize() {
|
||||||
|
@ -52,10 +52,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
// any data specific to the window
|
// any data specific to the window
|
||||||
struct GLWindow {
|
struct GLWindow {
|
||||||
bool in_use = false;
|
|
||||||
|
|
||||||
// the external ID .. should match the GL window number .. unused I think
|
|
||||||
DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID;
|
|
||||||
int width = 0;
|
int width = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
|
|
||||||
@ -71,7 +67,7 @@ private:
|
|||||||
HGLRC hRC;
|
HGLRC hRC;
|
||||||
};
|
};
|
||||||
|
|
||||||
LocalVector<GLWindow> _windows;
|
Map<DisplayServer::WindowID, GLWindow> _windows;
|
||||||
LocalVector<GLDisplay> _displays;
|
LocalVector<GLDisplay> _displays;
|
||||||
|
|
||||||
GLWindow *_current_window = nullptr;
|
GLWindow *_current_window = nullptr;
|
||||||
|
@ -129,9 +129,34 @@ void OS_Windows::initialize_debugging() {
|
|||||||
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
|
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
|
||||||
|
static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||||
|
String err_str;
|
||||||
|
if (p_errorexp && p_errorexp[0]) {
|
||||||
|
err_str = String::utf8(p_errorexp);
|
||||||
|
} else {
|
||||||
|
err_str = String::utf8(p_file) + ":" + itos(p_line) + " - " + String::utf8(p_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_editor_notify) {
|
||||||
|
err_str += " (User)\n";
|
||||||
|
} else {
|
||||||
|
err_str += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputDebugStringW((LPCWSTR)err_str.utf16().ptr());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void OS_Windows::initialize() {
|
void OS_Windows::initialize() {
|
||||||
crash_handler.initialize();
|
crash_handler.initialize();
|
||||||
|
|
||||||
|
#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
|
||||||
|
error_handlers.errfunc = _error_handler;
|
||||||
|
error_handlers.userdata = this;
|
||||||
|
add_error_handler(&error_handlers);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef WINDOWS_SUBSYSTEM_CONSOLE
|
#ifndef WINDOWS_SUBSYSTEM_CONSOLE
|
||||||
RedirectIOToConsole();
|
RedirectIOToConsole();
|
||||||
#endif
|
#endif
|
||||||
@ -194,6 +219,10 @@ void OS_Windows::finalize_core() {
|
|||||||
|
|
||||||
memdelete(process_map);
|
memdelete(process_map);
|
||||||
NetSocketPosix::cleanup();
|
NetSocketPosix::cleanup();
|
||||||
|
|
||||||
|
#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
|
||||||
|
remove_error_handler(&error_handlers);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Error OS_Windows::get_entropy(uint8_t *r_buffer, int p_bytes) {
|
Error OS_Windows::get_entropy(uint8_t *r_buffer, int p_bytes) {
|
||||||
|
@ -57,6 +57,11 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <windowsx.h>
|
#include <windowsx.h>
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
// forward error messages to OutputDebugString
|
||||||
|
#define WINDOWS_DEBUG_OUTPUT_ENABLED
|
||||||
|
#endif
|
||||||
|
|
||||||
class JoypadWindows;
|
class JoypadWindows;
|
||||||
class OS_Windows : public OS {
|
class OS_Windows : public OS {
|
||||||
#ifdef STDOUT_FILE
|
#ifdef STDOUT_FILE
|
||||||
@ -81,6 +86,10 @@ class OS_Windows : public OS {
|
|||||||
|
|
||||||
CrashHandler crash_handler;
|
CrashHandler crash_handler;
|
||||||
|
|
||||||
|
#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
|
||||||
|
ErrorHandlerList error_handlers;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool force_quit;
|
bool force_quit;
|
||||||
HWND main_window;
|
HWND main_window;
|
||||||
|
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#if defined(WINDOWS_ENABLED) && defined(VULKAN_ENABLED)
|
||||||
|
|
||||||
#include "vulkan_context_win.h"
|
#include "vulkan_context_win.h"
|
||||||
#ifdef USE_VOLK
|
#ifdef USE_VOLK
|
||||||
#include <volk.h>
|
#include <volk.h>
|
||||||
@ -57,3 +59,5 @@ VulkanContextWindows::VulkanContextWindows() {
|
|||||||
|
|
||||||
VulkanContextWindows::~VulkanContextWindows() {
|
VulkanContextWindows::~VulkanContextWindows() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -609,13 +609,16 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
|
|||||||
if (p_base.is_valid()) {
|
if (p_base.is_valid()) {
|
||||||
instance->base_type = RSG::storage->get_base_type(p_base);
|
instance->base_type = RSG::storage->get_base_type(p_base);
|
||||||
|
|
||||||
|
// fix up a specific malfunctioning case before the switch, so it can be handled
|
||||||
if (instance->base_type == RS::INSTANCE_NONE && RendererSceneOcclusionCull::get_singleton()->is_occluder(p_base)) {
|
if (instance->base_type == RS::INSTANCE_NONE && RendererSceneOcclusionCull::get_singleton()->is_occluder(p_base)) {
|
||||||
instance->base_type = RS::INSTANCE_OCCLUDER;
|
instance->base_type = RS::INSTANCE_OCCLUDER;
|
||||||
}
|
}
|
||||||
|
|
||||||
ERR_FAIL_COND(instance->base_type == RS::INSTANCE_NONE);
|
|
||||||
|
|
||||||
switch (instance->base_type) {
|
switch (instance->base_type) {
|
||||||
|
case RS::INSTANCE_NONE: {
|
||||||
|
ERR_PRINT_ONCE("unimplemented base type encountered in renderer scene cull");
|
||||||
|
return;
|
||||||
|
}
|
||||||
case RS::INSTANCE_LIGHT: {
|
case RS::INSTANCE_LIGHT: {
|
||||||
InstanceLightData *light = memnew(InstanceLightData);
|
InstanceLightData *light = memnew(InstanceLightData);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user