From 96bd6c7ce568331dd6834adf1e61b0e088272e44 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:33:03 -0500 Subject: [PATCH 1/5] [Vulkan] Handle surface lost in createSwapchain --- lib/ivis_opengl/gfx_api_vk.cpp | 18 ++++++++++++++++-- lib/ivis_opengl/gfx_api_vk.h | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/ivis_opengl/gfx_api_vk.cpp b/lib/ivis_opengl/gfx_api_vk.cpp index 5a97e38018a..7e5ccbc69a4 100644 --- a/lib/ivis_opengl/gfx_api_vk.cpp +++ b/lib/ivis_opengl/gfx_api_vk.cpp @@ -3855,7 +3855,7 @@ bool VkRoot::handleSurfaceLost() } bool result = false; - if (createSwapchain()) + if (createSwapchain(false)) { rebuildPipelinesIfNecessary(); result = true; @@ -4071,7 +4071,7 @@ T clamp(const T& n, const T& lower, const T& upper) { return std::max(lower, std::min(n, upper)); } -bool VkRoot::createSwapchain() +bool VkRoot::createSwapchain(bool allowHandleSurfaceLost) { ASSERT(backend_impl, "Backend implementation is null"); ASSERT(physicalDevice, "Physical device is null"); @@ -4089,6 +4089,20 @@ bool VkRoot::createSwapchain() try { swapChainSupport = querySwapChainSupport(physicalDevice, surface, vkDynLoader); } + catch (const vk::SurfaceLostKHRError &e) + { + if (allowHandleSurfaceLost) + { + debug(LOG_INFO, "Querying swapchain support failed with ErrorSurfaceLostKHR - must recreate surface + swapchain: %s", e.what()); + // recreate surface + swapchain + return handleSurfaceLost(); + } + else + { + debug(LOG_ERROR, "Querying swapchain support failed with error: %s", e.what()); + return false; + } + } catch (const vk::SystemError &e) { debug(LOG_ERROR, "Querying swapchain support failed with error: %s", e.what()); diff --git a/lib/ivis_opengl/gfx_api_vk.h b/lib/ivis_opengl/gfx_api_vk.h index c3ed21485f6..39e9cc606fe 100644 --- a/lib/ivis_opengl/gfx_api_vk.h +++ b/lib/ivis_opengl/gfx_api_vk.h @@ -781,7 +781,7 @@ struct VkRoot final : gfx_api::context bool createLogicalDevice(); bool createAllocator(); void getQueues(); - bool createSwapchain(); + bool createSwapchain(bool allowHandleSurfaceLost = true); void rebuildPipelinesIfNecessary(); void createDefaultRenderpass(vk::Format swapchainFormat, vk::Format depthFormat); From 08af1281451c5c097844e3742af9a4d45638c1c2 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:35:15 -0500 Subject: [PATCH 2/5] [OpenGL] Additional init error checks --- lib/ivis_opengl/gfx_api_gl.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/ivis_opengl/gfx_api_gl.cpp b/lib/ivis_opengl/gfx_api_gl.cpp index 29587f3524c..0f2534bc962 100644 --- a/lib/ivis_opengl/gfx_api_gl.cpp +++ b/lib/ivis_opengl/gfx_api_gl.cpp @@ -3234,12 +3234,18 @@ bool gl_context::_initialize(const gfx_api::backend_Impl_Factory& impl, int32_t int width, height = 0; backend_impl->getDrawableSize(&width, &height); debug(LOG_WZ, "Drawable Size: %d x %d", width, height); + width = std::max(width, 0); + height = std::max(height, 0); + + wzGLClearErrors(); glViewport(0, 0, width, height); + wzGLCheckErrors(); viewportWidth = static_cast(width); viewportHeight = static_cast(height); glCullFace(GL_FRONT); // glEnable(GL_CULL_FACE); + wzGLCheckErrors(); // initialize default (0) textures if (!createDefaultTextures()) @@ -3537,13 +3543,13 @@ bool gl_context::initGLContext() } std::pair glslVersion(0, 0); - sscanf((char const *)glGetString(GL_SHADING_LANGUAGE_VERSION), "%d.%d", &glslVersion.first, &glslVersion.second); + sscanf((char const *)wzSafeGlGetString(GL_SHADING_LANGUAGE_VERSION), "%d.%d", &glslVersion.first, &glslVersion.second); /* Dump information about OpenGL 2.0+ implementation to the console and the dump file */ GLint glMaxTIUs = 0, glMaxTIUAs = 0, glmaxSamples = 0, glmaxSamplesbuf = 0, glmaxVertexAttribs = 0, glMaxArrayTextureLayers = 0; - debug(LOG_3D, " * OpenGL GLSL Version : %s", glGetString(GL_SHADING_LANGUAGE_VERSION)); - ssprintf(opengl.GLSLversion, "OpenGL GLSL Version : %s", glGetString(GL_SHADING_LANGUAGE_VERSION)); + debug(LOG_3D, " * OpenGL GLSL Version : %s", wzSafeGlGetString(GL_SHADING_LANGUAGE_VERSION)); + ssprintf(opengl.GLSLversion, "OpenGL GLSL Version : %s", wzSafeGlGetString(GL_SHADING_LANGUAGE_VERSION)); addDumpInfo(opengl.GLSLversion); glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &glMaxTIUs); @@ -3574,14 +3580,19 @@ bool gl_context::initGLContext() } enabledVertexAttribIndexes.resize(static_cast(glmaxVertexAttribs), false); + wzGLClearErrors(); + if (khr_debug) { if (glDebugMessageCallback && glDebugMessageControl) { glDebugMessageCallback(khr_callback, nullptr); + wzGLCheckErrors(); glEnable(GL_DEBUG_OUTPUT); + wzGLCheckErrors(); // Do not want to output notifications. Some drivers spam them too much. glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE); + wzGLCheckErrors(); debug(LOG_3D, "Enabling KHR_debug message callback"); } else @@ -3600,23 +3611,29 @@ bool gl_context::initGLContext() return false; } glGenVertexArrays(1, &vaoId); + wzGLCheckErrors(); glBindVertexArray(vaoId); + wzGLCheckErrors(); } if (GLAD_GL_ARB_timer_query) { glGenQueries(PERF_COUNT, perfpos); + wzGLCheckErrors(); } if (GLAD_GL_EXT_texture_filter_anisotropic) { maxTextureAnisotropy = 0.f; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxTextureAnisotropy); + wzGLCheckErrors(); } glGenBuffers(1, &scratchbuffer); + wzGLCheckErrors(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + wzGLCheckErrors(); return true; } From 46d9b0339b9e309388e1e1b38a379196c1eed962 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:35:54 -0500 Subject: [PATCH 3/5] [OpenGL] Tweak default logging --- lib/ivis_opengl/gfx_api_gl.cpp | 8 +++++--- lib/sdl/gfx_api_gl_sdl.cpp | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/ivis_opengl/gfx_api_gl.cpp b/lib/ivis_opengl/gfx_api_gl.cpp index 0f2534bc962..03e54d7cf13 100644 --- a/lib/ivis_opengl/gfx_api_gl.cpp +++ b/lib/ivis_opengl/gfx_api_gl.cpp @@ -3416,13 +3416,13 @@ bool gl_context::initGLContext() /* Dump general information about OpenGL implementation to the console and the dump file */ ssprintf(opengl.vendor, "OpenGL Vendor: %s", wzSafeGlGetString(GL_VENDOR)); addDumpInfo(opengl.vendor); - debug(LOG_3D, "%s", opengl.vendor); + debug(LOG_INFO, "%s", opengl.vendor); ssprintf(opengl.renderer, "OpenGL Renderer: %s", wzSafeGlGetString(GL_RENDERER)); addDumpInfo(opengl.renderer); - debug(LOG_3D, "%s", opengl.renderer); + debug(LOG_INFO, "%s", opengl.renderer); ssprintf(opengl.version, "OpenGL Version: %s", wzSafeGlGetString(GL_VERSION)); addDumpInfo(opengl.version); - debug(LOG_3D, "%s", opengl.version); + debug(LOG_INFO, "%s", opengl.version); formattedRendererInfoString = calculateFormattedRendererInfoString(); @@ -3635,6 +3635,8 @@ bool gl_context::initGLContext() glPixelStorei(GL_UNPACK_ALIGNMENT, 1); wzGLCheckErrors(); + debug(LOG_INFO, "Success"); + return true; } diff --git a/lib/sdl/gfx_api_gl_sdl.cpp b/lib/sdl/gfx_api_gl_sdl.cpp index f62d95d1574..5da75777b08 100644 --- a/lib/sdl/gfx_api_gl_sdl.cpp +++ b/lib/sdl/gfx_api_gl_sdl.cpp @@ -182,7 +182,7 @@ bool sdl_OpenGL_Impl::createGLContext() // Although context creation eventually succeeded, log the attempts that failed debug_multiline(LOG_3D, glContextErrors); } - debug(LOG_3D, "Requested %s context", to_string(contextRequest).c_str()); + debug(LOG_INFO, "Requested %s context", to_string(contextRequest).c_str()); int value = 0; if (SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &value) == 0) From 7fcf7c2b8c10ea84d0633730ed7815df8e0f0df1 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:39:59 -0500 Subject: [PATCH 4/5] vk_mem_alloc: Silence Wimplicit-fallthrough --- lib/ivis_opengl/3rdparty/vk_mem_alloc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ivis_opengl/3rdparty/vk_mem_alloc.cpp b/lib/ivis_opengl/3rdparty/vk_mem_alloc.cpp index 1e845de0388..ffbfa154d51 100644 --- a/lib/ivis_opengl/3rdparty/vk_mem_alloc.cpp +++ b/lib/ivis_opengl/3rdparty/vk_mem_alloc.cpp @@ -28,6 +28,7 @@ # pragma clang diagnostic ignored "-Wunused-private-field" # pragma clang diagnostic ignored "-Wcast-align" # pragma clang diagnostic ignored "-Wunused-function" +# pragma clang diagnostic ignored "-Wimplicit-fallthrough" # if defined(__APPLE__) # pragma clang diagnostic ignored "-Wnullability-completeness" // Warning triggered on newer Xcode # endif @@ -47,6 +48,7 @@ # pragma GCC diagnostic ignored "-Wmissing-noreturn" # pragma GCC diagnostic ignored "-Wcast-align" # pragma GCC diagnostic ignored "-Wunused-function" +# pragma GCC diagnostic ignored "-Wimplicit-fallthrough" #elif defined(_MSC_VER) # pragma warning( push ) # pragma warning( disable : 4189 ) // warning C4189: 'identifier' : local variable is initialized but not referenced From bb06ad883f3e0ddf511ab053e47542d1cd7e6af4 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Mon, 27 Nov 2023 18:27:35 -0500 Subject: [PATCH 5/5] [OpenGL] Adjust handling of window size change + scene FBOs Never attempt to create a scene framebuffer with dimensions < 2x2 --- lib/ivis_opengl/gfx_api_gl.cpp | 55 +++++++++++++++++++++++++--------- lib/ivis_opengl/gfx_api_gl.h | 2 ++ 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/lib/ivis_opengl/gfx_api_gl.cpp b/lib/ivis_opengl/gfx_api_gl.cpp index 03e54d7cf13..198e645ded8 100644 --- a/lib/ivis_opengl/gfx_api_gl.cpp +++ b/lib/ivis_opengl/gfx_api_gl.cpp @@ -3247,6 +3247,9 @@ bool gl_context::_initialize(const gfx_api::backend_Impl_Factory& impl, int32_t // glEnable(GL_CULL_FACE); wzGLCheckErrors(); + sceneFramebufferWidth = std::max(viewportWidth, 2); + sceneFramebufferHeight = std::max(viewportHeight, 2); + // initialize default (0) textures if (!createDefaultTextures()) { @@ -4082,14 +4085,34 @@ void gl_context::handleWindowSizeChange(unsigned int oldWidth, unsigned int oldH backend_impl->getDrawableSize(&drawableWidth, &drawableHeight); debug(LOG_WZ, "Logical Size: %d x %d; Drawable Size: %d x %d", screenWidth, screenHeight, drawableWidth, drawableHeight); - glViewport(0, 0, drawableWidth, drawableHeight); - viewportWidth = static_cast(drawableWidth); - viewportHeight = static_cast(drawableHeight); + int width = std::max(drawableWidth, 0); + int height = std::max(drawableHeight, 0); + + glViewport(0, 0, width, height); + viewportWidth = static_cast(width); + viewportHeight = static_cast(height); glCullFace(GL_FRONT); // glEnable(GL_CULL_FACE); - // Re-create scene FBOs using new size - createSceneRenderpass(); + // Re-create scene FBOs using new size (if drawable size is of reasonable dimensions) + if (viewportWidth > 0 && viewportHeight > 0) + { + uint32_t newSceneFramebufferWidth = std::max(viewportWidth, 2); + uint32_t newSceneFramebufferHeight = std::max(viewportHeight, 2); + + if (sceneFramebufferWidth != newSceneFramebufferWidth || sceneFramebufferHeight != newSceneFramebufferHeight) + { + sceneFramebufferWidth = newSceneFramebufferWidth; + sceneFramebufferHeight = newSceneFramebufferHeight; + createSceneRenderpass(); + } + } + else + { + // Some drivers seem to like to occasionally return a drawableSize that has a 0 dimension (ex. when minimized?) + // In this case, don't bother recreating the scene framebuffer (until it changes to something sensible) + debug(LOG_INFO, "Delaying scene framebuffer recreation (current Drawable Size: %d x %d)", drawableWidth, drawableHeight); + } } std::pair gl_context::getDrawableDimensions() @@ -4421,7 +4444,7 @@ bool gl_context::createSceneRenderpass() ASSERT_GL_NOERRORS_OR_RETURN(false); glBindRenderbuffer(GL_RENDERBUFFER, sceneMsaaRBO); ASSERT_GL_NOERRORS_OR_RETURN(false); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, multiSampledBufferInternalFormat, viewportWidth, viewportHeight); // OpenGL 3.0+, OpenGL ES 3.0+ + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, multiSampledBufferInternalFormat, sceneFramebufferWidth, sceneFramebufferHeight); // OpenGL 3.0+, OpenGL ES 3.0+ ASSERT_GL_NOERRORS_OR_RETURN(false); glBindRenderbuffer(GL_RENDERBUFFER, 0); ASSERT_GL_NOERRORS_OR_RETURN(false); @@ -4432,11 +4455,11 @@ bool gl_context::createSceneRenderpass() // - OpenGL ES: color texture format must *MATCH* the format used for the multisampled color render buffer GLenum colorInternalFormat = (samples > 0 && gles) ? multiSampledBufferInternalFormat : GL_RGB8; GLenum colorBaseFormat = (samples > 0 && gles) ? multiSampledBufferBaseFormat : GL_RGB; - auto pNewSceneTexture = create_framebuffer_color_texture(colorInternalFormat, colorBaseFormat, GL_UNSIGNED_BYTE, viewportWidth, viewportHeight, ""); + auto pNewSceneTexture = create_framebuffer_color_texture(colorInternalFormat, colorBaseFormat, GL_UNSIGNED_BYTE, sceneFramebufferWidth, sceneFramebufferHeight, ""); ASSERT_GL_NOERRORS_OR_RETURN(false); if (!pNewSceneTexture) { - debug(LOG_ERROR, "Failed to create scene color texture (%" PRIu32 " x %" PRIu32 ")", viewportWidth, viewportHeight); + debug(LOG_ERROR, "Failed to create scene color texture (%" PRIu32 " x %" PRIu32 ")", sceneFramebufferWidth, sceneFramebufferHeight); return false; } sceneTexture = pNewSceneTexture; @@ -4455,7 +4478,7 @@ bool gl_context::createSceneRenderpass() ASSERT_GL_NOERRORS_OR_RETURN(false); glBindRenderbuffer(GL_RENDERBUFFER, sceneDepthStencilRBO); ASSERT_GL_NOERRORS_OR_RETURN(false); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH24_STENCIL8, viewportWidth, viewportHeight); // OpenGL 3.0+, OpenGL ES 3.0+ + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH24_STENCIL8, sceneFramebufferWidth, sceneFramebufferHeight); // OpenGL 3.0+, OpenGL ES 3.0+ ASSERT_GL_NOERRORS_OR_RETURN(false); glBindRenderbuffer(GL_RENDERBUFFER, 0); ASSERT_GL_NOERRORS_OR_RETURN(false); @@ -4488,7 +4511,7 @@ bool gl_context::createSceneRenderpass() GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { - debug(LOG_ERROR, "Failed to create scene framebuffer[%d] (%" PRIu32 " x %" PRIu32 ", samples: %d) with error: %s", i, viewportWidth, viewportHeight, static_cast(samples), cbframebuffererror(status)); + debug(LOG_ERROR, "Failed to create scene framebuffer[%d] (%" PRIu32 " x %" PRIu32 ", samples: %d) with error: %s", i, sceneFramebufferWidth, sceneFramebufferHeight, static_cast(samples), cbframebuffererror(status)); encounteredError = true; } ASSERT_GL_NOERRORS_OR_RETURN(false); @@ -4513,7 +4536,7 @@ bool gl_context::createSceneRenderpass() status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { - debug(LOG_ERROR, "Failed to create scene resolve framebuffer[%d] (%" PRIu32 " x %" PRIu32 ", samples: %d) with error: %s", i, viewportWidth, viewportHeight, static_cast(samples), cbframebuffererror(status)); + debug(LOG_ERROR, "Failed to create scene resolve framebuffer[%d] (%" PRIu32 " x %" PRIu32 ", samples: %d) with error: %s", i, sceneFramebufferWidth, sceneFramebufferHeight, static_cast(samples), cbframebuffererror(status)); encounteredError = true; } ASSERT_GL_NOERRORS_OR_RETURN(false); @@ -4531,7 +4554,7 @@ bool gl_context::createSceneRenderpass() void gl_context::beginSceneRenderPass() { glBindFramebuffer(GL_FRAMEBUFFER, sceneFBO[sceneFBOIdx]); - glViewport(0, 0, viewportWidth, viewportHeight); + glViewport(0, 0, sceneFramebufferWidth, sceneFramebufferHeight); GLbitfield clearFlags = 0; glDepthMask(GL_TRUE); clearFlags = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; @@ -4584,8 +4607,8 @@ void gl_context::endSceneRenderPass() { glBindFramebuffer(GL_READ_FRAMEBUFFER, sceneFBO[sceneFBOIdx]); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, sceneResolveFBO[sceneFBOIdx]); - glBlitFramebuffer(0,0, viewportWidth, viewportHeight, - 0,0, viewportWidth, viewportHeight, + glBlitFramebuffer(0,0, sceneFramebufferWidth, sceneFramebufferHeight, + 0,0, sceneFramebufferWidth, sceneFramebufferHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); } @@ -4624,6 +4647,10 @@ void gl_context::endSceneRenderPass() // switch back to default framebuffer glBindFramebuffer(GL_FRAMEBUFFER, 0); // Because the scene uses the same viewport, a call to glViewport should not be needed (NOTE: viewport is *not* part of the framebuffer state) + if (sceneFramebufferWidth != viewportWidth || sceneFramebufferHeight != viewportHeight) + { + glViewport(0, 0, viewportWidth, viewportHeight); + } } gfx_api::abstract_texture* gl_context::getSceneTexture() diff --git a/lib/ivis_opengl/gfx_api_gl.h b/lib/ivis_opengl/gfx_api_gl.h index d85d3fb472f..663380c1997 100644 --- a/lib/ivis_opengl/gfx_api_gl.h +++ b/lib/ivis_opengl/gfx_api_gl.h @@ -392,6 +392,8 @@ struct gl_context final : public gfx_api::context size_t depthBufferResolution = 4096; size_t depthPassCount = WZ_MAX_SHADOW_CASCADES; + uint32_t sceneFramebufferWidth = 0; + uint32_t sceneFramebufferHeight = 0; GLenum multiSampledBufferInternalFormat = GL_INVALID_ENUM; GLenum multiSampledBufferBaseFormat = GL_INVALID_ENUM; GLint maxMultiSampleBufferFormatSamples = 0;