From 70031cf9d4ab020b9cca8d97bede380a5f1d443e Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 31 Oct 2023 14:28:15 -0400 Subject: [PATCH 01/14] Add gfx_api::buffer::current_buffer_size() --- lib/ivis_opengl/gfx_api.h | 2 ++ lib/ivis_opengl/gfx_api_gl.cpp | 5 +++++ lib/ivis_opengl/gfx_api_gl.h | 1 + lib/ivis_opengl/gfx_api_null.cpp | 5 +++++ lib/ivis_opengl/gfx_api_null.h | 1 + lib/ivis_opengl/gfx_api_vk.cpp | 5 +++++ lib/ivis_opengl/gfx_api_vk.h | 1 + 7 files changed, 20 insertions(+) diff --git a/lib/ivis_opengl/gfx_api.h b/lib/ivis_opengl/gfx_api.h index 8f3f2bd1b0b..657ad53069e 100644 --- a/lib/ivis_opengl/gfx_api.h +++ b/lib/ivis_opengl/gfx_api.h @@ -160,6 +160,8 @@ namespace gfx_api // (i.e. Don't re-use a buffer instance for different data in the same frame - use separate buffer instances.) virtual void update(const size_t& start, const size_t& size, const void* data, const update_flag flag = update_flag::none) = 0; + virtual size_t current_buffer_size() = 0; + virtual void bind() = 0; virtual ~buffer() {}; diff --git a/lib/ivis_opengl/gfx_api_gl.cpp b/lib/ivis_opengl/gfx_api_gl.cpp index ea0ea78b17b..111054db911 100644 --- a/lib/ivis_opengl/gfx_api_gl.cpp +++ b/lib/ivis_opengl/gfx_api_gl.cpp @@ -622,6 +622,11 @@ void gl_buffer::update(const size_t & start, const size_t & size, const void * d glBindBuffer(to_gl(usage), 0); } +size_t gl_buffer::current_buffer_size() +{ + return buffer_size; +} + // MARK: gl_pipeline_state_object struct program_data diff --git a/lib/ivis_opengl/gfx_api_gl.h b/lib/ivis_opengl/gfx_api_gl.h index 6e7cbb1b1bc..10102f86c80 100644 --- a/lib/ivis_opengl/gfx_api_gl.h +++ b/lib/ivis_opengl/gfx_api_gl.h @@ -147,6 +147,7 @@ struct gl_buffer final : public gfx_api::buffer void unbind(); virtual void upload(const size_t & size, const void * data) override; virtual void update(const size_t & start, const size_t & size, const void * data, const update_flag flag = update_flag::none) override; + virtual size_t current_buffer_size() override; }; struct gl_pipeline_id final : public gfx_api::pipeline_state_object diff --git a/lib/ivis_opengl/gfx_api_null.cpp b/lib/ivis_opengl/gfx_api_null.cpp index 5bdde547be3..5c81b608243 100644 --- a/lib/ivis_opengl/gfx_api_null.cpp +++ b/lib/ivis_opengl/gfx_api_null.cpp @@ -158,6 +158,11 @@ void null_buffer::update(const size_t & start, const size_t & size, const void * // no-op } +size_t null_buffer::current_buffer_size() +{ + return buffer_size; +} + // MARK: null_pipeline_state_object null_pipeline_state_object::null_pipeline_state_object(const gfx_api::state_description& _desc, const std::vector& _vertex_buffer_desc) diff --git a/lib/ivis_opengl/gfx_api_null.h b/lib/ivis_opengl/gfx_api_null.h index 9101ad5d7f2..8c6f935397b 100644 --- a/lib/ivis_opengl/gfx_api_null.h +++ b/lib/ivis_opengl/gfx_api_null.h @@ -81,6 +81,7 @@ struct null_buffer final : public gfx_api::buffer void bind() override; virtual void upload(const size_t & size, const void * data) override; virtual void update(const size_t & start, const size_t & size, const void * data, const update_flag flag = update_flag::none) override; + virtual size_t current_buffer_size() override; }; struct null_pipeline_state_object final : public gfx_api::pipeline_state_object diff --git a/lib/ivis_opengl/gfx_api_vk.cpp b/lib/ivis_opengl/gfx_api_vk.cpp index e26995cb422..ff4fa709611 100644 --- a/lib/ivis_opengl/gfx_api_vk.cpp +++ b/lib/ivis_opengl/gfx_api_vk.cpp @@ -1907,6 +1907,11 @@ void VkBuf::update(const size_t & start, const size_t & size, const void * data, cmdBuffer->copyBuffer(stagingMemory.buffer, object, copyRegions, root->vkDynLoader); } +size_t VkBuf::current_buffer_size() +{ + return buffer_size; +} + void VkBuf::bind() {} // MARK: VkTexture diff --git a/lib/ivis_opengl/gfx_api_vk.h b/lib/ivis_opengl/gfx_api_vk.h index 07360ca71d5..901ade3b516 100644 --- a/lib/ivis_opengl/gfx_api_vk.h +++ b/lib/ivis_opengl/gfx_api_vk.h @@ -435,6 +435,7 @@ struct VkBuf final : public gfx_api::buffer virtual void upload(const size_t & size, const void * data) override; virtual void update(const size_t & start, const size_t & size, const void * data, const update_flag flag = update_flag::none) override; + virtual size_t current_buffer_size() override; virtual void bind() override; From 24e1a819a20a6481def292ca0083a73fc0fb3bf1 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 31 Oct 2023 14:29:02 -0400 Subject: [PATCH 02/14] [Vulkan] VkBuf::upload: Only update if data is not null --- lib/ivis_opengl/gfx_api_vk.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/ivis_opengl/gfx_api_vk.cpp b/lib/ivis_opengl/gfx_api_vk.cpp index ff4fa709611..5b75dddbde9 100644 --- a/lib/ivis_opengl/gfx_api_vk.cpp +++ b/lib/ivis_opengl/gfx_api_vk.cpp @@ -1876,7 +1876,10 @@ void VkBuf::upload(const size_t & size, const void * data) { ASSERT(size > 0, "Attempt to upload buffer of size 0"); allocateBufferObject(size); - update(0, size, data); + if (data) + { + update(0, size, data); + } } void VkBuf::update(const size_t & start, const size_t & size, const void * data, const update_flag flag) From fb6cbb277bdf74521864875dd61e0e11e17c2773 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 31 Oct 2023 17:58:35 -0400 Subject: [PATCH 03/14] Fix: Initializing depth pass properties when starting with shadows disabled Always call pie_setShadowMode() on init --- lib/ivis_opengl/piedraw.cpp | 4 +++- lib/ivis_opengl/piestate.cpp | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/ivis_opengl/piedraw.cpp b/lib/ivis_opengl/piedraw.cpp index cf2ceb1994b..bc8f2408530 100644 --- a/lib/ivis_opengl/piedraw.cpp +++ b/lib/ivis_opengl/piedraw.cpp @@ -66,6 +66,7 @@ static size_t pieCount = 0; static size_t polyCount = 0; static size_t drawCallsCount = 0; static bool shadows = false; +static bool shadowsHasBeenInit = false; static ShadowMode shadowMode = ShadowMode::Shadow_Mapping; static gfx_api::gfxFloat lighting0[LIGHT_MAX][4]; static gfx_api::gfxFloat lightingDefault[LIGHT_MAX][4]; @@ -161,7 +162,7 @@ uint32_t pie_getShadowMapResolution() bool pie_setShadowMode(ShadowMode mode) { - if (mode == shadowMode) + if (mode == shadowMode && shadowsHasBeenInit) { return true; } @@ -179,6 +180,7 @@ bool pie_setShadowMode(ShadowMode mode) } shadowMode = mode; refreshShadowShaders(); + shadowsHasBeenInit = true; return successfulChangeToInputMode; } diff --git a/lib/ivis_opengl/piestate.cpp b/lib/ivis_opengl/piestate.cpp index 6e6b32991a5..6c1655173f3 100644 --- a/lib/ivis_opengl/piestate.cpp +++ b/lib/ivis_opengl/piestate.cpp @@ -124,6 +124,7 @@ bool pie_LoadShaders(uint32_t shadowFilterSize) // note: actual loading of shaders now occurs in gfx_api // initialize gfx context shadow constants (must happen after context is initialized) + ASSERT(gfx_api::context::isInitialized(), "gfx context isn't initialized?"); auto shadowConstants = gfx_api::context::get().getShadowConstants(); shadowConstants.shadowFilterSize = shadowFilterSize; gfx_api::context::get().setShadowConstants(shadowConstants); @@ -132,6 +133,10 @@ bool pie_LoadShaders(uint32_t shadowFilterSize) { pie_setShadowMode(ShadowMode::Fallback_Stencil_Shadows); } + else + { + pie_setShadowMode(ShadowMode::Shadow_Mapping); + } gfx_api::gfxUByte rect[] { 0, 255, 0, 255, From ddfd3c561bde437dc0246c443f73b910957e6bfb Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 31 Oct 2023 18:33:13 -0400 Subject: [PATCH 04/14] [OpenGL] Fixes to support a single depth pass Just always use a texture array for the depth passes --- lib/ivis_opengl/gfx_api_gl.cpp | 41 +++++++++++++++++++++++----------- lib/ivis_opengl/gfx_api_gl.h | 3 ++- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/lib/ivis_opengl/gfx_api_gl.cpp b/lib/ivis_opengl/gfx_api_gl.cpp index 111054db911..89fbdfcee45 100644 --- a/lib/ivis_opengl/gfx_api_gl.cpp +++ b/lib/ivis_opengl/gfx_api_gl.cpp @@ -2272,16 +2272,16 @@ gfx_api::texture_array* gl_context::create_texture_array(const size_t& mipmap_co gl_gpurendered_texture* gl_context::create_depthmap_texture(const size_t& layer_count, const size_t& width, const size_t& height, const std::string& filename) { GLenum depthInternalFormat = GL_DEPTH_COMPONENT32F; - return create_gpurendered_texture(depthInternalFormat, GL_DEPTH_COMPONENT, GL_FLOAT, width, height, layer_count, filename); + return create_gpurendered_texture_array(depthInternalFormat, GL_DEPTH_COMPONENT, GL_FLOAT, width, height, layer_count, filename); } -gl_gpurendered_texture* gl_context::create_gpurendered_texture(GLenum internalFormat, GLenum format, GLenum type, const size_t& width, const size_t& height, const size_t& layer_count, const std::string& filename) +gl_gpurendered_texture* gl_context::create_gpurendered_texture(GLenum internalFormat, GLenum format, GLenum type, const size_t& width, const size_t& height, const std::string& filename) { ASSERT(width <= static_cast(std::numeric_limits::max()), "width (%zu) exceeds GLsizei max", width); ASSERT(height <= static_cast(std::numeric_limits::max()), "height (%zu) exceeds GLsizei max", height); auto* new_texture = new gl_gpurendered_texture(); new_texture->gles = gles; - new_texture->_isArray = (layer_count > 1); + new_texture->_isArray = false; #if defined(WZ_DEBUG_GFX_API_LEAKS) new_texture->debugName = filename; #endif @@ -2293,22 +2293,39 @@ gl_gpurendered_texture* gl_context::create_gpurendered_texture(GLenum internalFo glObjectLabel(GL_TEXTURE, new_texture->id(), -1, filename.c_str()); } - if (!new_texture->isArray()) - { - glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, static_cast(width), static_cast(height), 0, format, type, nullptr); - } - else + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, static_cast(width), static_cast(height), 0, format, type, nullptr); + + new_texture->unbind(); + return new_texture; +} + +gl_gpurendered_texture* gl_context::create_gpurendered_texture_array(GLenum internalFormat, GLenum format, GLenum type, const size_t& width, const size_t& height, const size_t& layer_count, const std::string& filename) +{ + ASSERT(width <= static_cast(std::numeric_limits::max()), "width (%zu) exceeds GLsizei max", width); + ASSERT(height <= static_cast(std::numeric_limits::max()), "height (%zu) exceeds GLsizei max", height); + auto* new_texture = new gl_gpurendered_texture(); + new_texture->gles = gles; + new_texture->_isArray = true; +#if defined(WZ_DEBUG_GFX_API_LEAKS) + new_texture->debugName = filename; +#endif + new_texture->bind(); + glTexParameteri(new_texture->target(), GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(new_texture->target(), GL_TEXTURE_MAX_LEVEL, 0); + if (!filename.empty() && ((/*GLEW_VERSION_4_3 ||*/ GLAD_GL_KHR_debug) && glObjectLabel)) { - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, internalFormat, static_cast(width), static_cast(height), static_cast(layer_count), 0, format, type, nullptr); + glObjectLabel(GL_TEXTURE, new_texture->id(), -1, filename.c_str()); } + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, internalFormat, static_cast(width), static_cast(height), static_cast(layer_count), 0, format, type, nullptr); + new_texture->unbind(); return new_texture; } gl_gpurendered_texture* gl_context::create_framebuffer_color_texture(GLenum internalFormat, GLenum format, GLenum type, const size_t& width, const size_t& height, const std::string& filename) { - return create_gpurendered_texture(internalFormat, format, type, width, height, 1, filename); + return create_gpurendered_texture(internalFormat, format, type, width, height, filename); } gfx_api::buffer * gl_context::create_buffer_object(const gfx_api::buffer::usage &usage, const buffer_storage_hint& hint /*= buffer_storage_hint::static_draw*/, const std::string& debugName /*= ""*/) @@ -4133,9 +4150,7 @@ size_t gl_context::initDepthPasses(size_t resolution) if ((!gles && !GLAD_GL_VERSION_3_0) || (gles && !GLAD_GL_ES_VERSION_3_0)) { // glFramebufferTextureLayer requires OpenGL 3.0+ / ES 3.0+ - debug(LOG_ERROR, "Cannot create depth texture array - requires OpenGL 3.0+ / OpenGL ES 3.0+"); - // could use a single depth pass (as a 2d texture) - but only bother if we want to keep support // TODO: decide - depthPassCount = 1; + debug(LOG_ERROR, "Cannot create depth texture array - requires OpenGL 3.0+ / OpenGL ES 3.0+ - this will fail"); } } diff --git a/lib/ivis_opengl/gfx_api_gl.h b/lib/ivis_opengl/gfx_api_gl.h index 10102f86c80..0c3caab0ac9 100644 --- a/lib/ivis_opengl/gfx_api_gl.h +++ b/lib/ivis_opengl/gfx_api_gl.h @@ -344,7 +344,8 @@ struct gl_context final : public gfx_api::context void initPixelFormatsSupport(); bool initInstancedFunctions(); size_t initDepthPasses(size_t resolution); - gl_gpurendered_texture* create_gpurendered_texture(GLenum internalFormat, GLenum format, GLenum type, const size_t& width, const size_t& height, const size_t& layer_count, const std::string& filename); + gl_gpurendered_texture* create_gpurendered_texture(GLenum internalFormat, GLenum format, GLenum type, const size_t& width, const size_t& height, const std::string& filename); + gl_gpurendered_texture* create_gpurendered_texture_array(GLenum internalFormat, GLenum format, GLenum type, const size_t& width, const size_t& height, const size_t& layer_count, const std::string& filename); gl_gpurendered_texture* create_depthmap_texture(const size_t& layer_count, const size_t& width, const size_t& height, const std::string& filename); gl_gpurendered_texture* create_framebuffer_color_texture(GLenum internalFormat, GLenum format, GLenum type, const size_t& width, const size_t& height, const std::string& filename); bool createSceneRenderpass(); From baec7f9e80f2a3a0c653855a93d40dadd1e2f56e Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 31 Oct 2023 18:58:54 -0400 Subject: [PATCH 05/14] piedraw.cpp: Support configurable shadow cascades count --- lib/ivis_opengl/piedef.h | 3 +++ lib/ivis_opengl/piedraw.cpp | 31 ++++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/lib/ivis_opengl/piedef.h b/lib/ivis_opengl/piedef.h index 0eb95ffbe25..b88eb04f375 100644 --- a/lib/ivis_opengl/piedef.h +++ b/lib/ivis_opengl/piedef.h @@ -71,6 +71,9 @@ enum class ShadowMode }; bool pie_setShadowMode(ShadowMode mode); ShadowMode pie_getShadowMode(); +bool pie_setShadowCascades(uint32_t newValue); +uint32_t pie_getShadowCascades(); + optional pie_supportsShadowMapping(); bool pie_setShadowMapResolution(uint32_t resolution); uint32_t pie_getShadowMapResolution(); diff --git a/lib/ivis_opengl/piedraw.cpp b/lib/ivis_opengl/piedraw.cpp index bc8f2408530..8238bf42a8c 100644 --- a/lib/ivis_opengl/piedraw.cpp +++ b/lib/ivis_opengl/piedraw.cpp @@ -68,6 +68,7 @@ static size_t drawCallsCount = 0; static bool shadows = false; static bool shadowsHasBeenInit = false; static ShadowMode shadowMode = ShadowMode::Shadow_Mapping; +static uint32_t numShadowCascades = WZ_MAX_SHADOW_CASCADES; static gfx_api::gfxFloat lighting0[LIGHT_MAX][4]; static gfx_api::gfxFloat lightingDefault[LIGHT_MAX][4]; @@ -114,19 +115,23 @@ static void refreshShadowShaders() { auto shadowConstants = gfx_api::context::get().getShadowConstants(); bool bShadowMappingEnabled = isShadowMappingEnabled(); + uint32_t actualNumCascadesAndPasses = (bShadowMappingEnabled) ? numShadowCascades : 0; if (bShadowMappingEnabled) { shadowConstants.shadowMode = 1; // Possible future TODO: Could get this from the config file to allow testing alternative filter methods + shadowConstants.shadowCascadesCount = actualNumCascadesAndPasses; } else { shadowConstants.shadowMode = 0; // Disable shader-drawn / shadow-mapping shadows } - // Preserve existing shadowFilterSize and shadowCascadesCount + + // Preserve existing shadowFilterSize + gfx_api::context::get().setShadowConstants(shadowConstants); // Trigger depth pass buffer free / rebuild if needed - gfx_api::context::get().setDepthPassProperties((bShadowMappingEnabled) ? WZ_MAX_SHADOW_CASCADES : 0, gfx_api::context::get().getDepthPassDimensions(0)); + gfx_api::context::get().setDepthPassProperties(actualNumCascadesAndPasses, gfx_api::context::get().getDepthPassDimensions(0)); } } @@ -152,7 +157,7 @@ bool pie_setShadowMapResolution(uint32_t resolution) { ASSERT_OR_RETURN(false, resolution && !(resolution & (resolution - 1)), "Expecting power-of-2 resolution, received: %" PRIu32, resolution); bool bShadowMappingEnabled = isShadowMappingEnabled(); - return gfx_api::context::get().setDepthPassProperties((bShadowMappingEnabled) ? WZ_MAX_SHADOW_CASCADES : 0, resolution); + return gfx_api::context::get().setDepthPassProperties((bShadowMappingEnabled) ? numShadowCascades : 0, resolution); } uint32_t pie_getShadowMapResolution() @@ -189,6 +194,26 @@ ShadowMode pie_getShadowMode() return shadowMode; } +bool pie_setShadowCascades(uint32_t newValue) +{ + if (newValue == 0 || newValue > WZ_MAX_SHADOW_CASCADES) + { + return false; + } + if (numShadowCascades == newValue) + { + return true; + } + numShadowCascades = newValue; + refreshShadowShaders(); + return true; +} + +uint32_t pie_getShadowCascades() +{ + return numShadowCascades; +} + static Vector3f currentSunPosition(0.f, 0.f, 0.f); void pie_BeginLighting(const Vector3f &light) From efca68c1010305d7d7818304494c66ac439fadbf Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 31 Oct 2023 19:00:51 -0400 Subject: [PATCH 06/14] wzscriptdebug: Add Shadow Cascades option --- src/wzscriptdebug.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/src/wzscriptdebug.cpp b/src/wzscriptdebug.cpp index 4feb6a042b3..c332ef39be1 100644 --- a/src/wzscriptdebug.cpp +++ b/src/wzscriptdebug.cpp @@ -999,7 +999,9 @@ class WzGraphicsPanel : public W_FORM auto shadowFilterDropdownWidget = panel->makeShadowFilterSizeDropdown(4, shadowsLabel); panel->makeShadowMapResolutionDropdown(4, shadowFilterDropdownWidget); - auto shadowModeDropdownWidget = panel->makeShadowModeDropdown(5); + panel->makeShadowCascadesDropdown(5, shadowsLabel); + + auto shadowModeDropdownWidget = panel->makeShadowModeDropdown(6); return panel; } @@ -1241,6 +1243,79 @@ class WzGraphicsPanel : public W_FORM return dropdown; } + std::shared_ptr makeShadowCascadesDropdown(int row, const std::shared_ptr& previousButton = nullptr) + { + int previousButtonRight = (previousButton) ? previousButton->x() + previousButton->width() : 0; + + std::vector> dropDownChoices = { + {WzString::fromUtf8("Medium (2)"), 2}, + {WzString::fromUtf8("Highest (3)"), 3} + }; + + // If current value is not one of the presets in dropDownChoices, add a "Custom" entry + size_t currentSettingIdx = 0; + uint32_t currValue = pie_getShadowCascades(); + auto it = std::find_if(dropDownChoices.begin(), dropDownChoices.end(), [currValue](const std::tuple& item) -> bool { + return std::get<1>(item) == currValue; + }); + if (it != dropDownChoices.end()) + { + currentSettingIdx = it - dropDownChoices.begin(); + } + else + { + dropDownChoices.push_back({WzString::fromUtf8(astringf("(Custom: %u)", currValue)), currValue}); + currentSettingIdx = dropDownChoices.size() - 1; + } + + int yPos = (row * (TAB_BUTTONS_HEIGHT + ACTION_BUTTON_ROW_SPACING)); + + auto contextLabel = std::make_shared(); + contextLabel->setFont(font_regular, WZCOL_FORM_TEXT); + contextLabel->setString("Cascades:"); + contextLabel->setGeometry((previousButtonRight > 0) ? previousButtonRight + ACTION_BUTTON_SPACING : 0, yPos, contextLabel->getMaxLineWidth() + 10, TAB_BUTTONS_HEIGHT); + contextLabel->setCacheNeverExpires(true); + attach(contextLabel); + + auto dropdown = std::make_shared(); + dropdown->setListHeight(TAB_BUTTONS_HEIGHT * std::min(5, dropDownChoices.size())); + attach(dropdown); + for (const auto& option : dropDownChoices) + { + WzString buttonLabel = std::get<0>(option); + auto button = makeDebugButton(buttonLabel.toUtf8().c_str()); + bool supportedCascadeValue = pie_supportsShadowMapping().value_or(false); + if (!supportedCascadeValue) + { + button->setState(WBUT_DISABLE); + } + dropdown->addItem(button); + } + + dropdown->setSelectedIndex(currentSettingIdx); + + dropdown->setCanChange([dropDownChoices](DropdownWidget &widget, size_t newIndex, std::shared_ptr newSelectedWidget) -> bool { + ASSERT_OR_RETURN(false, newIndex < dropDownChoices.size(), "Invalid index"); + auto newCascadesCount = std::get<1>(dropDownChoices.at(newIndex)); + if (!pie_supportsShadowMapping().value_or(false)) + { + return false; + } + if (!pie_setShadowCascades(newCascadesCount)) + { + debug(LOG_ERROR, "Failed to set shadow cascades: %" PRIu32, newCascadesCount); + return false; + } + // Possible Future TODO: could persist to config (if this proves useful beyond debugging and testing) + return true; + }); + + int contextDropdownX0 = contextLabel->x() + contextLabel->width(); + dropdown->setGeometry(contextDropdownX0, yPos, dropdown->idealWidth() + ACTION_BUTTON_SPACING, TAB_BUTTONS_HEIGHT); + + return dropdown; + } + std::shared_ptr makeShadowMapResolutionDropdown(int row, const std::shared_ptr& previousButton = nullptr) { int previousButtonRight = (previousButton) ? previousButton->x() + previousButton->width() : 0; From 5fe6cef7acea8204295b98e9cfda5b8823a3c673 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 31 Oct 2023 20:03:17 -0400 Subject: [PATCH 07/14] [OpenGL] Adjust getSuggestedDefaultDepthBufferResolution() --- lib/ivis_opengl/gfx_api_gl.cpp | 43 ++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/lib/ivis_opengl/gfx_api_gl.cpp b/lib/ivis_opengl/gfx_api_gl.cpp index 89fbdfcee45..e9c25d89dfd 100644 --- a/lib/ivis_opengl/gfx_api_gl.cpp +++ b/lib/ivis_opengl/gfx_api_gl.cpp @@ -3054,8 +3054,9 @@ uint32_t gl_context::getSuggestedDefaultDepthBufferResolution() const // If GL_NVX_gpu_memory_info is available, get the total graphics memory (in kB) GLint total_graphics_mem_kb = 0; glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &total_graphics_mem_kb); + debug(LOG_3D, "GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX: %d", total_graphics_mem_kb); - if ((total_graphics_mem_kb / 1024) >= 4096) // If >= 4GB graphics memory + if ((total_graphics_mem_kb / 1024) >= 8192) // If >= 8 GiB graphics memory { return 4096; } @@ -3071,9 +3072,11 @@ uint32_t gl_context::getSuggestedDefaultDepthBufferResolution() const glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats_kb); if (stats_kb[0] > 0) { + debug(LOG_3D, "GL_TEXTURE_FREE_MEMORY_ATI [0: total pool avail]: %d", stats_kb[0]); + debug(LOG_3D, "GL_TEXTURE_FREE_MEMORY_ATI [1: largest pool avail]: %d", stats_kb[1]); uint32_t currentFreeTextureMemory_mb = static_cast(stats_kb[0] / 1024); - if (currentFreeTextureMemory_mb >= 4096) // If >= 4 GB free texture memory + if (currentFreeTextureMemory_mb >= 8192) // If >= 8 GiB free texture memory { return 4096; } @@ -3085,24 +3088,34 @@ uint32_t gl_context::getSuggestedDefaultDepthBufferResolution() const } // don't currently have a good way of checking video memory on this system - // instead, check system RAM - auto systemRAMinMiB = wzGetCurrentSystemRAM(); - if (systemRAMinMiB >= 16384) // If >= 16 GB of system RAM - { + // check some specific GL_RENDERER values... #if defined(WZ_OS_WIN) - WzString openGL_renderer = (const char*)wzSafeGlGetString(GL_RENDERER); - if (openGL_renderer.startsWith("Intel(R) HD Graphics")) + WzString openGL_renderer = (const char*)wzSafeGlGetString(GL_RENDERER); + if (openGL_renderer.startsWith("Intel(R) HD Graphics")) + { + // always default to 2048 on Intel HD Graphics... + return 2048; + } +#elif defined (__APPLE__) + WzString openGL_vendor = (const char*)wzSafeGlGetString(GL_VENDOR); + WzString openGL_renderer = (const char*)wzSafeGlGetString(GL_RENDERER); + if (openGL_vendor == "Apple" && openGL_renderer.startsWith("Apple")) + { + // For Apple GPUs, check system RAM + auto systemRAMinMiB = wzGetCurrentSystemRAM(); + if (systemRAMinMiB >= 16384) // If >= 16 GB of system (unified) RAM + { + return 4096; + } + else { - // always default to 2048 on Intel HD Graphics... return 2048; } -#endif - return 4096; - } - else - { - return 2048; } +#endif + + // In all other cases, default to 2048 for better performance by default + return 2048; } bool gl_context::_initialize(const gfx_api::backend_Impl_Factory& impl, int32_t antialiasing, swap_interval_mode mode, optional _mipLodBias, uint32_t _depthMapResolution) From 4d992c18ddcf6824b2745e4fb9e7f487cdb58950 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 31 Oct 2023 20:03:41 -0400 Subject: [PATCH 08/14] [Vulkan] Adjust getVKSuggestedDefaultDepthBufferResolution() --- lib/ivis_opengl/gfx_api_vk.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/ivis_opengl/gfx_api_vk.cpp b/lib/ivis_opengl/gfx_api_vk.cpp index 5b75dddbde9..2169389c668 100644 --- a/lib/ivis_opengl/gfx_api_vk.cpp +++ b/lib/ivis_opengl/gfx_api_vk.cpp @@ -4355,21 +4355,37 @@ static optional getVKLargestDeviceLocalMemoryHeapIndex(const vk::Physi return largestDeviceLocalMemoryHeap; } -static uint32_t getVKSuggestedDefaultDepthBufferResolution(const vk::PhysicalDeviceMemoryProperties& memprops) +static uint32_t getVKSuggestedDefaultDepthBufferResolution(const vk::PhysicalDeviceProperties &physicalDeviceProperties, const vk::PhysicalDeviceMemoryProperties& memprops) { optional largestDeviceLocalMemoryHeap = getVKLargestDeviceLocalMemoryHeapIndex(memprops); ASSERT_OR_RETURN(2048, largestDeviceLocalMemoryHeap.has_value(), "Couldn't find the largest device local memory heap?"); auto largestDeviceLocalMemoryHeapSize = memprops.memoryHeaps[largestDeviceLocalMemoryHeap.value()].size; - if ((largestDeviceLocalMemoryHeapSize / 1048576) >= 4096) // If >= 4GB device-local memory + if (physicalDeviceProperties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) { - return 4096; + if ((largestDeviceLocalMemoryHeapSize / 1048576) >= 8192) // If >= 8 GiB device-local memory on a discrete GPU + { + return 4096; + } + else + { + return 2048; + } } - else + else if (physicalDeviceProperties.vendorID == 4203) // Apple GPU { - return 2048; + if ((largestDeviceLocalMemoryHeapSize / 1048576) >= 16384) // If >= 16 GiB device-local memory on an Apple GPU + { + return 4096; + } + else + { + return 2048; + } } + + return 2048; } bool VkRoot::canUseVulkanInstanceAPI(uint32_t minVulkanAPICoreVersion) const @@ -4689,7 +4705,7 @@ bool VkRoot::_initialize(const gfx_api::backend_Impl_Factory& impl, int32_t anti if (depthMapSize == 0) { - depthMapSize = getVKSuggestedDefaultDepthBufferResolution(memprops); + depthMapSize = getVKSuggestedDefaultDepthBufferResolution(physDeviceProps, memprops); } createDepthPasses(depthBufferFormat); // TODO: Handle failures? From 4e6d0fcd9722d64a78ff9dc15928ed9bec13267b Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 31 Oct 2023 20:04:01 -0400 Subject: [PATCH 09/14] [OpenGL] Additional logging --- lib/ivis_opengl/gfx_api_gl.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/ivis_opengl/gfx_api_gl.cpp b/lib/ivis_opengl/gfx_api_gl.cpp index e9c25d89dfd..e03071d0bc7 100644 --- a/lib/ivis_opengl/gfx_api_gl.cpp +++ b/lib/ivis_opengl/gfx_api_gl.cpp @@ -2728,6 +2728,7 @@ uint64_t gl_context::get_estimated_vram_mb() // If GL_NVX_gpu_memory_info is available, get the total graphics memory GLint total_graphics_mem_kb = 0; glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &total_graphics_mem_kb); + debug(LOG_3D, "GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX: %d", total_graphics_mem_kb); if (total_graphics_mem_kb > 0) { @@ -2741,6 +2742,9 @@ uint64_t gl_context::get_estimated_vram_mb() glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats_kb); if (stats_kb[0] > 0) { + debug(LOG_3D, "GL_TEXTURE_FREE_MEMORY_ATI [0: total pool avail]: %d", stats_kb[0]); + debug(LOG_3D, "GL_TEXTURE_FREE_MEMORY_ATI [1: largest pool avail]: %d", stats_kb[1]); + uint64_t currentFreeTextureMemory_mb = static_cast(stats_kb[0] / 1024); return currentFreeTextureMemory_mb; } @@ -3447,6 +3451,12 @@ bool gl_context::initGLContext() debug(LOG_3D, " * (current) Max array texture layers is %d.", (int) glMaxArrayTextureLayers); maxArrayTextureLayers = glMaxArrayTextureLayers; + uint32_t estimatedVRAMinMiB = get_estimated_vram_mb(); + if (estimatedVRAMinMiB > 0) + { + debug(LOG_3D, " * Estimated VRAM is %" PRIu32 " MiB", estimatedVRAMinMiB); + } + // IMPORTANT: Reserve enough slots in enabledVertexAttribIndexes based on glmaxVertexAttribs if (glmaxVertexAttribs == 0) { From ba48a45065ff47035d94b1f4e527eeb5d9c7378a Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 31 Oct 2023 20:16:01 -0400 Subject: [PATCH 10/14] [OpenGL] Use GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX --- lib/ivis_opengl/gfx_api_gl.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/ivis_opengl/gfx_api_gl.cpp b/lib/ivis_opengl/gfx_api_gl.cpp index e03071d0bc7..a4d2b06d988 100644 --- a/lib/ivis_opengl/gfx_api_gl.cpp +++ b/lib/ivis_opengl/gfx_api_gl.cpp @@ -2725,10 +2725,10 @@ uint64_t gl_context::get_estimated_vram_mb() { if (GLAD_GL_NVX_gpu_memory_info) { - // If GL_NVX_gpu_memory_info is available, get the total graphics memory + // If GL_NVX_gpu_memory_info is available, get the total dedicated graphics memory GLint total_graphics_mem_kb = 0; - glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &total_graphics_mem_kb); - debug(LOG_3D, "GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX: %d", total_graphics_mem_kb); + glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &total_graphics_mem_kb); + debug(LOG_3D, "GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX: %d", total_graphics_mem_kb); if (total_graphics_mem_kb > 0) { @@ -3055,10 +3055,10 @@ uint32_t gl_context::getSuggestedDefaultDepthBufferResolution() const // Use a (very simple) heuristic, that may or may not be useful - but basically try to find graphics cards that have lots of memory... if (GLAD_GL_NVX_gpu_memory_info) { - // If GL_NVX_gpu_memory_info is available, get the total graphics memory (in kB) + // If GL_NVX_gpu_memory_info is available, get the total dedicated graphics memory GLint total_graphics_mem_kb = 0; - glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &total_graphics_mem_kb); - debug(LOG_3D, "GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX: %d", total_graphics_mem_kb); + glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &total_graphics_mem_kb); + debug(LOG_3D, "GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX: %d", total_graphics_mem_kb); if ((total_graphics_mem_kb / 1024) >= 8192) // If >= 8 GiB graphics memory { From 054fb6e9927f0d9395c4c0263b5207cd382c91e1 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Tue, 31 Oct 2023 21:20:32 -0400 Subject: [PATCH 11/14] [OpenGL] Adjust getSuggestedDefaultDepthBufferResolution() --- lib/ivis_opengl/gfx_api_gl.cpp | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/lib/ivis_opengl/gfx_api_gl.cpp b/lib/ivis_opengl/gfx_api_gl.cpp index a4d2b06d988..96dcdc5f1ff 100644 --- a/lib/ivis_opengl/gfx_api_gl.cpp +++ b/lib/ivis_opengl/gfx_api_gl.cpp @@ -3069,27 +3069,12 @@ uint32_t gl_context::getSuggestedDefaultDepthBufferResolution() const return 2048; } } - else if (GLAD_GL_ATI_meminfo) - { - // For GL_ATI_meminfo, get the current free texture memory (stats_kb[0]) - GLint stats_kb[4] = {0, 0, 0, 0}; - glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats_kb); - if (stats_kb[0] > 0) - { - debug(LOG_3D, "GL_TEXTURE_FREE_MEMORY_ATI [0: total pool avail]: %d", stats_kb[0]); - debug(LOG_3D, "GL_TEXTURE_FREE_MEMORY_ATI [1: largest pool avail]: %d", stats_kb[1]); - uint32_t currentFreeTextureMemory_mb = static_cast(stats_kb[0] / 1024); - - if (currentFreeTextureMemory_mb >= 8192) // If >= 8 GiB free texture memory - { - return 4096; - } - else - { - return 2048; - } - } - } +// else if (GLAD_GL_ATI_meminfo) +// { +// // For GL_ATI_meminfo, we could get the current free texture memory (w/ GL_TEXTURE_FREE_MEMORY_ATI, checking stats_kb[0]) +// // However we don't really have any way of differentiating between dedicated VRAM and shared system memory (ex. with integrated graphics) +// // So instead, just ignore this +// } // don't currently have a good way of checking video memory on this system // check some specific GL_RENDERER values... From fa4403f210ab06a2bba2c792f74fd25dd7f0c462 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Thu, 2 Nov 2023 14:53:57 -0400 Subject: [PATCH 12/14] gfx_api: Don't abort if Vulkan backend is unavailable - return false to allow proper fallback handling --- lib/ivis_opengl/gfx_api.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ivis_opengl/gfx_api.cpp b/lib/ivis_opengl/gfx_api.cpp index 1fa67a00b1e..22d52bec340 100644 --- a/lib/ivis_opengl/gfx_api.cpp +++ b/lib/ivis_opengl/gfx_api.cpp @@ -56,8 +56,8 @@ bool gfx_api::context::initialize(const gfx_api::backend_Impl_Factory& impl, int #if defined(WZ_VULKAN_ENABLED) current_backend_context = new VkRoot(uses_gfx_debug); #else - debug(LOG_FATAL, "Warzone was not compiled with the Vulkan backend enabled. Aborting."); - abort(); + debug(LOG_FATAL, "Warzone 2100 was not compiled with support for the Vulkan backend."); + return false; #endif break; } From 252f7aa925bcc447ab3629964f9887841920503b Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Thu, 2 Nov 2023 15:02:13 -0400 Subject: [PATCH 13/14] [CMake] Use already-downloaded prebuilt packages if present --- data/CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index d904cc66fce..687c11f5dc7 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -43,6 +43,16 @@ function(WZ_FETCH_PREBUILT_PACKAGE PACKAGE_URL PACKAGE_FILENAME PACKAGE_SHA512 O endif() endif() + # Check if file already exists at output path + if (EXISTS "${OUTPUT_PATH}") + file(SHA512 "${OUTPUT_PATH}" _dl_received_sha512) + if("${_dl_received_sha512}" STREQUAL "${PACKAGE_SHA512}") + message(STATUS "Found: Already downloaded prebuilt package: ${OUTPUT_PATH}, with hash: ${PACKAGE_SHA512}") + set(${STATUS} TRUE PARENT_SCOPE) + return() + endif() + endif() + # Try to download the prebuilt package file(DOWNLOAD "${PACKAGE_URL}" "${OUTPUT_PATH}" INACTIVITY_TIMEOUT 60 SHOW_PROGRESS STATUS _dl_status TLS_VERIFY ON) list(GET _dl_status 0 _dl_status_code) From 574d368e2c756b4a76437c03783c72b6b7b82fbe Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Thu, 2 Nov 2023 15:12:30 -0400 Subject: [PATCH 14/14] [Vulkan] Additional logging --- lib/ivis_opengl/gfx_api_vk.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/ivis_opengl/gfx_api_vk.cpp b/lib/ivis_opengl/gfx_api_vk.cpp index 2169389c668..824ae33a26c 100644 --- a/lib/ivis_opengl/gfx_api_vk.cpp +++ b/lib/ivis_opengl/gfx_api_vk.cpp @@ -351,6 +351,12 @@ bool checkDeviceExtensionSupport(const vk::PhysicalDevice &device, const std::ve requiredExtensions.erase(extension.extensionName); } + debug(LOG_3D, "Found %zu extensions / did not find %zu extensions, in the enumerated list of %zu device extensions", desiredExtensions.size() - requiredExtensions.size(), requiredExtensions.size(), availableExtensions.size()); + for (const auto& extension : requiredExtensions) + { + debug(LOG_3D, "Did not find extension: \"%s\"", extension.c_str()); + } + return requiredExtensions.empty(); } catch (const vk::SystemError& e)