Compare commits

...

1 Commits

Author SHA1 Message Date
Natsirt867
6a4fafae4c fix opengl context checks 2025-12-14 08:13:43 -06:00
25 changed files with 383 additions and 46 deletions

View File

@@ -2822,6 +2822,8 @@ void MapView::paintGL()
OpenGL::context::scoped_setter const _(::gl, context());
makeCurrent();
gl.processCleanup();
gl.clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
{
@@ -2944,27 +2946,34 @@ void MapView::resizeGL (int width, int height)
MapView::~MapView()
{
makeCurrent();
//makeCurrent();
_destroying = true;
_main_window->removeToolBar(_main_window->_app_toolbar);
OpenGL::context::scoped_setter const _ (::gl, context());
delete _texBrush;
delete _viewport_overlay_ui;
//OpenGL::context::scoped_setter const _ (::gl, context());
//::gl.processCleanup();
//delete _texBrush;
//delete _viewport_overlay_ui;
// when the uid fix fail the UI isn't created
if (!_uid_fix_failed)
{
// delete TexturePicker; // explicitly delete this here to avoid opengl context related crash
// delete objectEditor;
// since the ground effect tool preview renderer got added, this causes crashing on exit to menu.
// Now it crashes in application exit.
// delete texturingTool;
// delete TexturePicker; // explicitly delete this here to avoid opengl context related crash
// delete objectEditor;
// since the ground effect tool preview renderer got added, this causes crashing on exit to menu.
// Now it crashes in application exit.
// delete texturingTool;
if (_tools[static_cast<int>(editing_mode::area_trigger)])
{
_tools[static_cast<int>(editing_mode::area_trigger)]->unload();
}
_tools[static_cast<int>(editing_mode::paint)].reset();
_tools[static_cast<int>(editing_mode::object)].reset();
_tools[static_cast<int>(editing_mode::area_trigger)].reset();
}
if (_force_uid_check)
@@ -2978,14 +2987,22 @@ MapView::~MapView()
Noggit::Ui::selected_texture::texture.reset();
_buffers.unload();
makeCurrent();
OpenGL::context::scoped_setter const _(::gl, context());
::gl.processCleanup();
delete _texBrush;
delete _viewport_overlay_ui;
ModelManager::report();
TextureManager::report();
WMOManager::report();
NOGGIT_ACTION_MGR->disconnect();
_buffers.unload();
}
void MapView::tick (float dt)

View File

@@ -322,6 +322,7 @@ private:
QOpenGLContext* _last_opengl_context;
private:
virtual void tabletEvent(QTabletEvent* event) override;
virtual void initializeGL() override;
virtual void paintGL() override;

View File

@@ -42,8 +42,29 @@ void TextureManager::unload_all(Noggit::NoggitRenderContext context)
for (auto& pair : arrays_for_context)
{
gl.deleteTextures(static_cast<GLuint>(pair.second.arrays.size()), pair.second.arrays.data());
std::vector<GLuint> ids_to_delete = std::move(pair.second.arrays);
GLsizei count = static_cast<GLsizei>(ids_to_delete.size());
if (count == 0)
{
continue;
}
if (QOpenGLContext::currentContext())
{
gl.deleteTextures(count, ids_to_delete.data());
}
else
{
gl.scheduleCleanup([count, ids_to_delete = std::move(ids_to_delete)]() mutable
{
gl.deleteTextures(count, ids_to_delete.data());
}
);
}
}
arrays_for_context.clear();
}
TexArrayParams& TextureManager::get_tex_array(int width, int height, int mip_level,

View File

@@ -198,6 +198,8 @@ namespace Noggit
// Save tool-specific settings to disk
virtual void saveSettings();
virtual void unload() {};
protected:
void addHotkey(StringHash name, Hotkey hotkey);

View File

@@ -191,9 +191,24 @@ void LiquidRender::updateLayerData(LiquidTextureManager* tex_manager)
{
auto& layer_params = _render_layers.back();
gl.deleteBuffers(1, &layer_params.chunk_data_buf);
gl.deleteTextures(1, &layer_params.vertex_data_tex);
GLuint buffer_id = layer_params.chunk_data_buf;
GLuint texture_id = layer_params.vertex_data_tex;
if (QOpenGLContext::currentContext())
{
gl.deleteBuffers(1, &buffer_id);
gl.deleteTextures(1, &texture_id);
}
else
{
gl.scheduleCleanup([buffer_id, texture_id]() mutable
{
gl.deleteBuffers(1, &buffer_id);
gl.deleteTextures(1, &texture_id);
}
);
}
_render_layers.pop_back();
}
}
@@ -226,8 +241,24 @@ void LiquidRender::unload()
for (auto& render_layer : _render_layers)
{
gl.deleteBuffers(1, &render_layer.chunk_data_buf);
gl.deleteTextures(1, &render_layer.vertex_data_tex);
GLuint buffer_id = render_layer.chunk_data_buf;
GLuint texture_id = render_layer.vertex_data_tex;
if (QOpenGLContext::currentContext())
{
gl.deleteBuffers(1, &buffer_id);
gl.deleteTextures(1, &texture_id);
}
else
{
gl.scheduleCleanup([buffer_id, texture_id]() mutable
{
gl.deleteBuffers(1, &buffer_id);
gl.deleteTextures(1, &texture_id);
}
);
}
}
_render_layers.clear();

View File

@@ -137,7 +137,19 @@ void LiquidTextureManager::unload()
for (auto& pair : _texture_frames_map)
{
GLuint array = std::get<0>(pair.second);
gl.deleteTextures(1, &array);
if (QOpenGLContext::currentContext())
{
gl.deleteTextures(1, &array);
}
else
{
gl.scheduleCleanup([array]() mutable
{
gl.deleteTextures(1, &array);
}
);
}
}
_texture_frames_map.clear();

View File

@@ -74,7 +74,22 @@ void ModelRender::unload()
_vertex_arrays.unload();
if (_bone_matrices_buf_tex)
gl.deleteTextures(1, &_bone_matrices_buf_tex);
{
GLuint texture_id = _bone_matrices_buf_tex;
if (QOpenGLContext::currentContext())
{
gl.deleteTextures(1, &texture_id);
}
else
{
gl.scheduleCleanup([texture_id]() mutable
{
gl.deleteTextures(1, &texture_id);
}
);
}
}
for (auto& particle : _model->_particles)
{

View File

@@ -50,6 +50,24 @@ void TileRender::unload()
_buffers.unload();
_uploaded = false;
gl.deleteQueries(1, &_tile_occlusion_query);
if (_tile_occlusion_query)
{
GLuint query_id = _tile_occlusion_query;
if (QOpenGLContext::currentContext())
{
gl.deleteQueries(1, &query_id);
}
else
{
gl.scheduleCleanup([query_id]() mutable
{
gl.deleteQueries(1, &query_id);
}
);
}
}
}

View File

@@ -251,7 +251,23 @@ void WMOGroupRender::unload()
_vertex_array.unload();
_buffers.unload();
gl.deleteTextures(1, &_render_batch_tex);
if (_render_batch_tex)
{
GLuint texture_id = _render_batch_tex;
if (QOpenGLContext::currentContext())
{
gl.deleteTextures(1, &texture_id);
}
else
{
gl.scheduleCleanup([texture_id]() mutable
{
gl.deleteTextures(1, &texture_id);
}
);
}
}
_uploaded = false;
_vao_is_setup = false;

View File

@@ -56,6 +56,17 @@ namespace Noggit
{
}
void AreaTriggerTool::unload()
{
_boxRenderer.unload();
_sphereRenderer.unload();
if (_editor) {
delete _editor;
_editor = nullptr;
}
}
char const* AreaTriggerTool::name() const
{
return "Area Trigger";

View File

@@ -52,6 +52,8 @@ namespace Noggit
void saveSettings() override;
void unload() override;
private:
Ui::Tools::AreaTriggerEditor* _editor = nullptr;
Noggit::Rendering::Primitives::WireBox _boxRenderer;

View File

@@ -170,6 +170,16 @@ namespace Noggit
setupTexturePicker(mv);
}
void TexturingTool::unload()
{
if (_texturingTool)
{
_texturingTool->unload();
}
Tool::unload();
}
void TexturingTool::setupTextureBrowser(MapView* mv)
{
// Dock

View File

@@ -23,6 +23,8 @@ namespace Noggit
TexturingTool(MapView* mapView);
~TexturingTool();
void unload() override;
[[nodiscard]]
char const* name() const override;

View File

@@ -742,6 +742,12 @@ namespace Noggit
void GroundEffectsTool::delete_renderer()
{
delete _preview_renderer;
_preview_renderer = nullptr;
}
void GroundEffectsTool::unload()
{
delete_renderer();
}
void GroundEffectsTool::showEvent(QShowEvent* event)

View File

@@ -82,6 +82,7 @@ namespace Noggit
void updateTerrainUniformParams();
// Delete renderer.
~GroundEffectsTool();
void unload();
float radius() const;
ground_effect_brush_mode brush_mode() const;
bool render_mode() const;

View File

@@ -1025,5 +1025,13 @@ namespace Noggit
style()->drawComplexControl(QStyle::CC_Slider, &opt, &p, this);
*/
}
void texturing_tool::unload()
{
if (_ground_effect_tool)
{
_ground_effect_tool->unload();
}
}
}
}

View File

@@ -77,7 +77,8 @@ namespace Noggit
);
~texturing_tool(); // { _ground_effect_tool->deleteLater(); }; // { delete _ground_effect_tool; };
void unload();
float brush_radius() const;
float hardness() const;
bool show_unpaintable_chunks() const;

View File

@@ -701,9 +701,9 @@ void PreviewRenderer::unloadOpenglData()
return;
}
assert(context() != nullptr);
makeCurrent();
OpenGL::context::scoped_setter const _ (::gl, context());
//assert(context() != nullptr);
//makeCurrent();
//OpenGL::context::scoped_setter const _ (::gl, context());
ModelManager::unload_all(_context);
WMOManager::unload_all(_context);

View File

@@ -600,6 +600,8 @@ namespace Noggit::Ui::Windows
case QMessageBox::AcceptRole:
_stack_widget->setCurrentIndex(0);
_stack_widget->removeLast();
Noggit::Ui::Tools::ViewportManager::ViewportManager::unloadAll();
delete _map_view;
_map_view = nullptr;
_minimap->world(nullptr);
@@ -807,8 +809,16 @@ namespace Noggit::Ui::Windows
progress_box->repaint();
qApp->processEvents();
try
{
//if (!clientData->openArchiveForWriting(*archive))
//{
// QMessageBox::warning(this, "Error", "Failed to switch archive to writable mode.");
// progress_box->close();
// return;
//}
auto start = std::chrono::high_resolution_clock::now();
std::array<int, 2> result = clientData->saveLocalFilesToArchive(archive.value(), mpq_compress_files_chk->isChecked(), mpq_compact_chk->isChecked());
@@ -820,9 +830,11 @@ namespace Noggit::Ui::Windows
std::ostringstream oss; // duration in seconds with 1 digit
oss << std::fixed << std::setprecision(1) << duration.count();
// clientData->closeArchiveToReadOnly(*archive);
// if no file was processed, archive was most likely opened and not accessible
// TODO : we can throw an error message in saveLocalFilesToArchive if (!archive->openForWritting()) instead
if (!processed_files)
if (processed_files <= 0)
{
QMessageBox::warning(this, "Error", "Project Folder is not a valid directory or client MPQ is not accessible.\
\nMake sure it isn't opened by Wow or MPQ editor");
@@ -833,6 +845,26 @@ namespace Noggit::Ui::Windows
}
/*
catch (const BlizzardArchive::Exceptions::Archive::ArchiveOpenError& e)
{
QMessageBox::critical(this, "Archive Access Error",
QString("Failed to open/close the archive for writing.\nDetails: %1").arg(e.what()));
}
catch (const BlizzardArchive::Exceptions::Archive::FileWriteFailedError& e)
{
QMessageBox::critical(this, "File Write Error",
QString("A file operation failed during saving.\nDetails: %1").arg(e.what()));
}
catch (const std::exception& e)
{
QMessageBox::critical(this, "Standard Exception",
QString("An unexpected standard error occurred: %1").arg(e.what()));
}*/
catch (...)
{
QMessageBox::critical(nullptr, "Error", "unhandled exception");

View File

@@ -401,7 +401,23 @@ namespace Noggit
if (!_transform_storage_uploaded)
return;
gl.deleteTextures(1, &_m2_instances_transform_buf_tex);
if (_m2_instances_transform_buf_tex)
{
GLuint texture_id = _m2_instances_transform_buf_tex;
if (QOpenGLContext::currentContext())
{
gl.deleteTextures(1, &texture_id);
}
else
{
gl.scheduleCleanup([texture_id]() mutable
{
gl.deleteTextures(1, &texture_id);
}
);
}
}
_buffers.unload();
_transform_storage_uploaded = false;

View File

@@ -53,4 +53,32 @@ namespace OpenGL
{
return _current_context;
}
void context::scheduleCleanup(std::function<void()> task)
{
QMutexLocker lock(&_cleanup_mutex);
_cleanup_queue.append(task);
}
void context::processCleanup()
{
if (QOpenGLContext::currentContext() != _current_context)
{
// must be called after the context is made current
assert(QOpenGLContext::currentContext() == _current_context);
return;
}
QList<std::function<void()>> tasks_to_process;
{
QMutexLocker lock(&_cleanup_mutex);
_cleanup_queue.swap(tasks_to_process);
}
for (const auto& task : tasks_to_process)
{
task();
}
}
}

View File

@@ -3,6 +3,9 @@
#pragma once
#include <opengl/types.hpp>
#include <QtGui/QOpenGLFunctions_4_1_Core>
#include <QMutex>
#include <QList>
#include <functional>
// NOGGIT_FORCEINLINE ---------------------------------------------//
// Macro to use in place of 'inline' to force a function to be inline
@@ -55,6 +58,12 @@ namespace OpenGL
QOpenGLContext* _current_context = nullptr;
QOpenGLFunctions_4_1_Core* _4_1_core_func = nullptr;
QMutex _cleanup_mutex;
QList<std::function<void()>> _cleanup_queue;
void scheduleCleanup(std::function<void()> task);
void processCleanup();
NOGGIT_FORCEINLINE bool has_extension(std::string const& name);
NOGGIT_FORCEINLINE void enable (GLenum);

View File

@@ -101,7 +101,7 @@ namespace OpenGL
private:
bool _buffer_generated = false;
GLuint _buffers[count];
GLuint _buffers[count] = { 0 };
};
template<std::size_t count>
@@ -139,7 +139,7 @@ namespace OpenGL
private:
bool _buffer_generated = false;
GLuint _vertex_arrays[count];
GLuint _vertex_arrays[count] = { 0 };
};
template<std::size_t count>
@@ -160,7 +160,7 @@ namespace OpenGL
private:
bool _texture_generated = false;
GLuint _textures[count];
GLuint _textures[count] = { 0 };
};
template<std::size_t count>

View File

@@ -139,17 +139,38 @@ namespace OpenGL
template<std::size_t count>
void deferred_upload_buffers<count>::unload()
{
gl.deleteBuffers(count, _buffers);
_buffer_generated = false;
for (int i = 0; i < count; ++i)
{
GLuint& buffer_id = _buffers[i];
if (buffer_id == 0)
{
continue;
}
if (QOpenGLContext::currentContext() && ::gl.getCurrentContext() != nullptr)
{
gl.deleteBuffers(1, &buffer_id);
}
else
{
gl.scheduleCleanup([buffer_id]() mutable
{
gl.deleteBuffers(1, &buffer_id);
}
);
}
buffer_id = 0;
}
_buffer_generated = false;
}
template<std::size_t count>
deferred_upload_buffers<count>::~deferred_upload_buffers()
{
if (_buffer_generated)
{
gl.deleteBuffers (count, _buffers);
}
unload();
}
template<std::size_t count>
@@ -186,8 +207,31 @@ namespace OpenGL
template<std::size_t count>
void deferred_upload_vertex_arrays<count>::unload()
{
gl.deleteVertexArray(count, _vertex_arrays);
_buffer_generated = false;
for (int i = 0; i < count; ++i)
{
GLuint& vertex_array_id = _vertex_arrays[i];
if (vertex_array_id == 0)
{
continue;
}
if (QOpenGLContext::currentContext() && ::gl.getCurrentContext() != nullptr)
{
gl.deleteVertexArray(1, &vertex_array_id);
}
else
{
gl.scheduleCleanup([vertex_array_id]() mutable
{
gl.deleteVertexArray(1, &vertex_array_id);
}
);
}
vertex_array_id = 0;
}
_buffer_generated = false;
}
template<std::size_t count>
@@ -195,7 +239,7 @@ namespace OpenGL
{
if (_buffer_generated)
{
gl.deleteVertexArray (count, _vertex_arrays);
unload();
}
}
@@ -222,17 +266,38 @@ namespace OpenGL
template<std::size_t count>
void deferred_upload_textures<count>::unload()
{
gl.deleteTextures(count, _textures);
_texture_generated = false;
for (int i = 0; i < count; ++i)
{
GLuint& texture_id = _textures[i];
if (texture_id == 0)
{
continue;
}
if (QOpenGLContext::currentContext() && ::gl.getCurrentContext() != nullptr)
{
gl.deleteTextures(1, &texture_id);
}
else
{
gl.scheduleCleanup([texture_id]() mutable
{
gl.deleteTextures(1, &texture_id);
}
);
}
texture_id = 0;
}
_texture_generated = false;
}
template<std::size_t count>
deferred_upload_textures<count>::~deferred_upload_textures()
{
if (_texture_generated)
{
gl.deleteTextures(count, _textures);
}
unload();
}
template<std::size_t count>

View File

@@ -121,7 +121,20 @@ namespace OpenGL
{
if (_handle)
{
gl.deleteProgram (*_handle);
if (QOpenGLContext::currentContext() && ::gl.getCurrentContext() != nullptr)
{
gl.deleteProgram(*_handle);
}
/*else
{
GLuint id = *_handle;
gl.scheduleCleanup([id]()
{
gl.deleteProgram(id);
}
);
}*/
}
}