opengl3 driver now works on windows including multi window
fixed and simplified gl_manager_windows swap buffers now called for all windows fixed missing pixel format setting in additional windows this makes them work in OpenGL contexts changed verbose error printing to write once this error message happens very frequently while opengl3 is not finished removed dead code no longer needed after changes fixed comments that were misinformation window messages during window creation now handled these were previously discarded messages now tunnel the required context changed failure to create opengl3 window on windows to be more fatal marked a problem with pen code conditional compilation of vulkan and opengl3 on windows fixed windows debug builds now show messages on debug console also rendering driver selection box now shows only compiled drivers marked some problematic code thanks to akien-mga for patiently rewriting my style mistakes
This commit is contained in:
parent
943b509952
commit
96c21bc749
13 changed files with 230 additions and 86 deletions
|
@ -210,6 +210,9 @@ RasterizerGLES3::RasterizerGLES3() {
|
|||
#ifdef GLAD_ENABLED
|
||||
if (!gladLoadGL()) {
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
@ -289,6 +292,9 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
|
|||
|
||||
// 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) {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->external.fbo);
|
||||
} else {
|
||||
|
@ -296,6 +302,7 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
|
|||
}
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ Config::Config() {
|
|||
singleton = this;
|
||||
|
||||
{
|
||||
int max_extensions = 0;
|
||||
GLint max_extensions = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &max_extensions);
|
||||
for (int i = 0; i < max_extensions; i++) {
|
||||
const GLubyte *s = glGetStringi(GL_EXTENSIONS, i);
|
||||
|
|
|
@ -2547,7 +2547,7 @@ RS::ShaderNativeSourceCode MaterialStorage::shader_get_native_source_code(RID p_
|
|||
|
||||
/* 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->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;
|
||||
#endif
|
||||
|
||||
String default_renderer = "";
|
||||
String renderer_hints = "";
|
||||
|
||||
packed_data = PackedData::get_singleton();
|
||||
if (!packed_data) {
|
||||
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,
|
||||
// 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.
|
||||
// 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",
|
||||
PropertyInfo(Variant::STRING,
|
||||
"rendering/driver/driver_name",
|
||||
PROPERTY_HINT_ENUM, "vulkan,opengl3"));
|
||||
PROPERTY_HINT_ENUM, renderer_hints));
|
||||
|
||||
// if not set on the command line
|
||||
if (rendering_driver.is_empty()) {
|
||||
|
|
|
@ -269,12 +269,14 @@ def configure_msvc(env, manual_msvc_config):
|
|||
"dwmapi",
|
||||
]
|
||||
|
||||
env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED"])
|
||||
if not env["use_volk"]:
|
||||
LIBS += ["vulkan"]
|
||||
if env["vulkan"]:
|
||||
env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED"])
|
||||
if not env["use_volk"]:
|
||||
LIBS += ["vulkan"]
|
||||
|
||||
env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
|
||||
LIBS += ["opengl32"]
|
||||
if env["opengl3"]:
|
||||
env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
|
||||
LIBS += ["opengl32"]
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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.
|
||||
SetFocus(wd.hWnd); // Set keyboard focus.
|
||||
}
|
||||
|
@ -1794,7 +1797,9 @@ void DisplayServerWindows::make_rendering_thread() {
|
|||
|
||||
void DisplayServerWindows::swap_buffers() {
|
||||
#if defined(GLES3_ENABLED)
|
||||
gl_manager->swap_buffers();
|
||||
if (gl_manager) {
|
||||
gl_manager->swap_buffers();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1946,14 +1951,18 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
|
|||
void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
#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
|
||||
}
|
||||
|
||||
DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
#if defined(VULKAN_ENABLED)
|
||||
return context_vulkan->get_vsync_mode(p_window);
|
||||
if (context_vulkan) {
|
||||
return context_vulkan->get_vsync_mode(p_window);
|
||||
}
|
||||
#endif
|
||||
return DisplayServer::VSYNC_ENABLED;
|
||||
}
|
||||
|
@ -2187,8 +2196,39 @@ LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam)
|
|||
return ::CallNextHookEx(mouse_monitor, code, wParam, lParam);
|
||||
}
|
||||
|
||||
// Our default window procedure to handle processing of window-related system messages/events.
|
||||
// Also known as DefProc or DefWindowProc.
|
||||
// Handle a single window message received while CreateWindowEx is still on the stack and our data
|
||||
// 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
|
||||
LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
if (drop_events) {
|
||||
|
@ -2202,7 +2242,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
|
|||
WindowID window_id = INVALID_WINDOW_ID;
|
||||
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) {
|
||||
if (E.value.hWnd == hWnd) {
|
||||
window_id = E.key;
|
||||
|
@ -2211,10 +2253,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) {
|
||||
window_id = window_id_counter;
|
||||
ERR_FAIL_COND_V(!windows.has(window_id), 0);
|
||||
// don't let code below operate on incompletely initialized window objects or missing window_id
|
||||
return _handle_early_window_message(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
// Process window messages.
|
||||
|
@ -3382,11 +3426,17 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
|
|||
WindowRect.top,
|
||||
WindowRect.right - WindowRect.left,
|
||||
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) {
|
||||
MessageBoxW(nullptr, L"Window Creation Error.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
|
||||
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) {
|
||||
wd.pre_fs_valid = true;
|
||||
|
@ -3406,7 +3456,14 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
|
|||
#ifdef GLES3_ENABLED
|
||||
if (gl_manager) {
|
||||
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
|
||||
|
||||
|
@ -3451,6 +3508,8 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
|
|||
ImmReleaseContext(wd.hWnd, wd.im_himc);
|
||||
|
||||
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.width = p_rect.size.width;
|
||||
wd.height = p_rect.size.height;
|
||||
|
@ -3741,6 +3800,7 @@ DisplayServerWindows::~DisplayServerWindows() {
|
|||
|
||||
#ifdef GLES3_ENABLED
|
||||
// destroy windows .. NYI?
|
||||
// FIXME wglDeleteContext is never called
|
||||
#endif
|
||||
|
||||
if (windows.has(MAIN_WINDOW_ID)) {
|
||||
|
|
|
@ -447,6 +447,8 @@ class DisplayServerWindows : public DisplayServer {
|
|||
static void _dispatch_input_events(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:
|
||||
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
LRESULT MouseProc(int code, WPARAM wParam, LPARAM lParam);
|
||||
|
|
|
@ -54,6 +54,18 @@
|
|||
|
||||
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) {
|
||||
// find display NYI, only 1 supported so far
|
||||
if (_displays.size()) {
|
||||
|
@ -79,7 +91,7 @@ int GLManager_Windows::_find_or_create_display(GLWindow &win) {
|
|||
return new_display_id;
|
||||
}
|
||||
|
||||
Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
|
||||
static Error _configure_pixel_format(HDC hDC) {
|
||||
static PIXELFORMATDESCRIPTOR pfd = {
|
||||
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
|
||||
1,
|
||||
|
@ -101,9 +113,6 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
|
|||
0, 0, 0 // Layer Masks Ignored
|
||||
};
|
||||
|
||||
// alias
|
||||
HDC hDC = win.hDC;
|
||||
|
||||
int pixel_format = ChoosePixelFormat(hDC, &pfd);
|
||||
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
|
||||
}
|
||||
|
||||
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?
|
||||
{
|
||||
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[] = {
|
||||
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;
|
||||
}
|
||||
|
||||
HGLRC new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs);
|
||||
HGLRC new_hRC = wglCreateContextAttribsARB(win.hDC, 0, attribs);
|
||||
if (!new_hRC) {
|
||||
wglDeleteContext(gl_display.hRC);
|
||||
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);
|
||||
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);
|
||||
gl_display.hRC = 0;
|
||||
return ERR_CANT_CREATE; // Return FALSE
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!hdc) {
|
||||
return ERR_CANT_CREATE; // Return FALSE
|
||||
HDC hDC = GetDC(p_hwnd);
|
||||
if (!hDC) {
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
|
||||
// make sure vector is big enough...
|
||||
// we can mirror the external vector, it is simpler
|
||||
// to keep the IDs identical for fast lookup
|
||||
if (p_window_id >= (int)_windows.size()) {
|
||||
_windows.resize(p_window_id + 1);
|
||||
// configure the HDC to use a compatible pixel format
|
||||
Error result = _configure_pixel_format(hDC);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
GLWindow &win = _windows[p_window_id];
|
||||
win.in_use = true;
|
||||
win.window_id = p_window_id;
|
||||
GLWindow win;
|
||||
win.width = p_width;
|
||||
win.height = p_height;
|
||||
win.hwnd = p_hwnd;
|
||||
win.hDC = hdc;
|
||||
win.hDC = hDC;
|
||||
|
||||
win.gldisplay_id = _find_or_create_display(win);
|
||||
|
||||
if (win.gldisplay_id == -1) {
|
||||
// release DC?
|
||||
_windows.remove_at(_windows.size() - 1);
|
||||
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
|
||||
window_make_current(_windows.size() - 1);
|
||||
window_make_current(p_window_id);
|
||||
|
||||
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) {
|
||||
GLWindow &win = get_window(p_window_id);
|
||||
win.in_use = false;
|
||||
|
||||
if (_current_window == &win) {
|
||||
_current_window = nullptr;
|
||||
}
|
||||
_windows.erase(p_window_id);
|
||||
}
|
||||
|
||||
void GLManager_Windows::release_current() {
|
||||
|
@ -229,7 +252,9 @@ void GLManager_Windows::release_current() {
|
|||
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) {
|
||||
|
@ -237,10 +262,8 @@ void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id)
|
|||
return;
|
||||
}
|
||||
|
||||
// crash if our data structures are out of sync, i.e. not found
|
||||
GLWindow &win = _windows[p_window_id];
|
||||
if (!win.in_use) {
|
||||
return;
|
||||
}
|
||||
|
||||
// noop
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
@ -257,34 +282,19 @@ void GLManager_Windows::make_current() {
|
|||
if (!_current_window) {
|
||||
return;
|
||||
}
|
||||
if (!_current_window->in_use) {
|
||||
WARN_PRINT("current window not in use!");
|
||||
return;
|
||||
}
|
||||
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() {
|
||||
// NO NEED TO CALL SWAP BUFFERS for each window...
|
||||
// see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXSwapBuffers.xml
|
||||
|
||||
if (!_current_window) {
|
||||
return;
|
||||
// on other platforms, OpenGL swaps buffers for all windows (on all displays, really?)
|
||||
// Windows swaps buffers on a per-window basis
|
||||
// REVISIT: this could be structurally bad, should we have "dirty" flags then?
|
||||
for (KeyValue<DisplayServer::WindowID, GLWindow> &entry : _windows) {
|
||||
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() {
|
||||
|
|
|
@ -52,10 +52,6 @@ public:
|
|||
private:
|
||||
// any data specific to the window
|
||||
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 height = 0;
|
||||
|
||||
|
@ -71,7 +67,7 @@ private:
|
|||
HGLRC hRC;
|
||||
};
|
||||
|
||||
LocalVector<GLWindow> _windows;
|
||||
Map<DisplayServer::WindowID, GLWindow> _windows;
|
||||
LocalVector<GLDisplay> _displays;
|
||||
|
||||
GLWindow *_current_window = nullptr;
|
||||
|
|
|
@ -129,9 +129,34 @@ void OS_Windows::initialize_debugging() {
|
|||
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() {
|
||||
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
|
||||
RedirectIOToConsole();
|
||||
#endif
|
||||
|
@ -194,6 +219,10 @@ void OS_Windows::finalize_core() {
|
|||
|
||||
memdelete(process_map);
|
||||
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) {
|
||||
|
|
|
@ -57,6 +57,11 @@
|
|||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
// forward error messages to OutputDebugString
|
||||
#define WINDOWS_DEBUG_OUTPUT_ENABLED
|
||||
#endif
|
||||
|
||||
class JoypadWindows;
|
||||
class OS_Windows : public OS {
|
||||
#ifdef STDOUT_FILE
|
||||
|
@ -81,6 +86,10 @@ class OS_Windows : public OS {
|
|||
|
||||
CrashHandler crash_handler;
|
||||
|
||||
#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
|
||||
ErrorHandlerList error_handlers;
|
||||
#endif
|
||||
|
||||
bool force_quit;
|
||||
HWND main_window;
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#if defined(WINDOWS_ENABLED) && defined(VULKAN_ENABLED)
|
||||
|
||||
#include "vulkan_context_win.h"
|
||||
#ifdef USE_VOLK
|
||||
#include <volk.h>
|
||||
|
@ -57,3 +59,5 @@ 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()) {
|
||||
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)) {
|
||||
instance->base_type = RS::INSTANCE_OCCLUDER;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(instance->base_type == RS::INSTANCE_NONE);
|
||||
|
||||
switch (instance->base_type) {
|
||||
case RS::INSTANCE_NONE: {
|
||||
ERR_PRINT_ONCE("unimplemented base type encountered in renderer scene cull");
|
||||
return;
|
||||
}
|
||||
case RS::INSTANCE_LIGHT: {
|
||||
InstanceLightData *light = memnew(InstanceLightData);
|
||||
|
||||
|
|
Loading…
Reference in a new issue