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:
derammo 2022-05-08 19:25:49 -04:00
parent 943b509952
commit 96c21bc749
13 changed files with 230 additions and 86 deletions

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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()) {

View file

@ -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])

View file

@ -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)) {

View file

@ -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);

View file

@ -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() {

View file

@ -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;

View file

@ -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) {

View file

@ -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;

View file

@ -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

View file

@ -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);