Browse Source

Make OpenGL pipeline shutdown defensive against missing context

Co-authored-by: djeada <[email protected]>
copilot-swe-agent[bot] 1 month ago
parent
commit
9227d45276

+ 14 - 2
app/core/game_engine.cpp

@@ -298,9 +298,19 @@ GameEngine::~GameEngine() {
 void GameEngine::cleanupOpenGLResources() {
   qInfo() << "Cleaning up OpenGL resources...";
   
+  // Check if we have a valid OpenGL context
+  // If not, skip OpenGL cleanup and just reset the pointers
+  // Qt will handle OpenGL resource cleanup when the context is destroyed
+  QOpenGLContext *context = QOpenGLContext::currentContext();
+  const bool hasValidContext = (context != nullptr);
+  
+  if (!hasValidContext) {
+    qInfo() << "No valid OpenGL context, skipping OpenGL cleanup";
+  }
+  
   // Shutdown renderer and all OpenGL-dependent resources
-  // Must be called while OpenGL context is still valid
-  if (m_renderer) {
+  // Only call shutdown if we have a valid context
+  if (m_renderer && hasValidContext) {
     m_renderer->shutdown();
     qInfo() << "Renderer shut down";
   }
@@ -309,6 +319,8 @@ void GameEngine::cleanupOpenGLResources() {
   m_passes.clear();
   
   // Reset all renderer-dependent unique_ptrs
+  // These will call destructors which may try to access OpenGL
+  // If no valid context, the destructors should be defensive
   m_ground.reset();
   m_terrain.reset();
   m_biome.reset();

+ 29 - 0
render/gl/backend/cylinder_pipeline.cpp

@@ -5,6 +5,7 @@
 #include "../render_constants.h"
 #include "gl/shader_cache.h"
 #include <GL/gl.h>
+#include <QOpenGLContext>
 #include <algorithm>
 #include <cstddef>
 #include <qopenglext.h>
@@ -170,6 +171,20 @@ void CylinderPipeline::initializeCylinderPipeline() {
 }
 
 void CylinderPipeline::shutdownCylinderPipeline() {
+  // Check if we have a valid OpenGL context before cleanup
+  // If not, skip OpenGL calls - resources will be freed by Qt/OS
+  if (QOpenGLContext::currentContext() == nullptr) {
+    // No valid context, just reset state without OpenGL calls
+    m_cylinderVao = 0;
+    m_cylinderVertexBuffer = 0;
+    m_cylinderIndexBuffer = 0;
+    m_cylinderInstanceBuffer = 0;
+    m_cylinderIndexCount = 0;
+    m_cylinderInstanceCapacity = 0;
+    m_cylinderScratch.clear();
+    return;
+  }
+
   initializeOpenGLFunctions();
 
   m_cylinderPersistentBuffer.destroy();
@@ -323,6 +338,20 @@ void CylinderPipeline::initializeFogPipeline() {
 }
 
 void CylinderPipeline::shutdownFogPipeline() {
+  // Check if we have a valid OpenGL context before cleanup
+  // If not, skip OpenGL calls - resources will be freed by Qt/OS
+  if (QOpenGLContext::currentContext() == nullptr) {
+    // No valid context, just reset state without OpenGL calls
+    m_fogVao = 0;
+    m_fogVertexBuffer = 0;
+    m_fogIndexBuffer = 0;
+    m_fogInstanceBuffer = 0;
+    m_fogIndexCount = 0;
+    m_fogInstanceCapacity = 0;
+    m_fogScratch.clear();
+    return;
+  }
+
   initializeOpenGLFunctions();
 
   if (m_fogInstanceBuffer != 0U) {

+ 41 - 0
render/gl/backend/vegetation_pipeline.cpp

@@ -3,6 +3,7 @@
 #include "gl/shader_cache.h"
 #include <GL/gl.h>
 #include <QDebug>
+#include <QOpenGLContext>
 #include <cmath>
 #include <cstddef>
 #include <cstdint>
@@ -186,6 +187,16 @@ void VegetationPipeline::initializeStonePipeline() {
 }
 
 void VegetationPipeline::shutdownStonePipeline() {
+  // Check if we have a valid OpenGL context before cleanup
+  if (QOpenGLContext::currentContext() == nullptr) {
+    m_stoneVao = 0;
+    m_stoneVertexBuffer = 0;
+    m_stoneIndexBuffer = 0;
+    m_stoneVertexCount = 0;
+    m_stoneIndexCount = 0;
+    return;
+  }
+
   initializeOpenGLFunctions();
   if (m_stoneIndexBuffer != 0U) {
     glDeleteBuffers(1, &m_stoneIndexBuffer);
@@ -280,6 +291,16 @@ void VegetationPipeline::initializePlantPipeline() {
 }
 
 void VegetationPipeline::shutdownPlantPipeline() {
+  // Check if we have a valid OpenGL context before cleanup
+  if (QOpenGLContext::currentContext() == nullptr) {
+    m_plantVao = 0;
+    m_plantVertexBuffer = 0;
+    m_plantIndexBuffer = 0;
+    m_plantVertexCount = 0;
+    m_plantIndexCount = 0;
+    return;
+  }
+
   initializeOpenGLFunctions();
   if (m_plantIndexBuffer != 0U) {
     glDeleteBuffers(1, &m_plantIndexBuffer);
@@ -429,6 +450,16 @@ void VegetationPipeline::initializePinePipeline() {
 }
 
 void VegetationPipeline::shutdownPinePipeline() {
+  // Check if we have a valid OpenGL context before cleanup
+  if (QOpenGLContext::currentContext() == nullptr) {
+    m_pineVao = 0;
+    m_pineVertexBuffer = 0;
+    m_pineIndexBuffer = 0;
+    m_pineVertexCount = 0;
+    m_pineIndexCount = 0;
+    return;
+  }
+
   initializeOpenGLFunctions();
   if (m_pineIndexBuffer != 0U) {
     glDeleteBuffers(1, &m_pineIndexBuffer);
@@ -522,6 +553,16 @@ void VegetationPipeline::initializeFireCampPipeline() {
 }
 
 void VegetationPipeline::shutdownFireCampPipeline() {
+  // Check if we have a valid OpenGL context before cleanup
+  if (QOpenGLContext::currentContext() == nullptr) {
+    m_firecampVao = 0;
+    m_firecampVertexBuffer = 0;
+    m_firecampIndexBuffer = 0;
+    m_firecampVertexCount = 0;
+    m_firecampIndexCount = 0;
+    return;
+  }
+
   initializeOpenGLFunctions();
   if (m_firecampIndexBuffer != 0U) {
     glDeleteBuffers(1, &m_firecampIndexBuffer);