KiCad PCB EDA Suite
Loading...
Searching...
No Matches
gl_context_mgr.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2016 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <advanced_config.h>
24#include <trace_helpers.h>
25#include <wx/debug.h>
26#include <wx/log.h>
27
28
30{
31#ifdef __WXMAC__
32 return false;
33#else
35#endif
36}
37
38
39wxGLContext* GL_CONTEXT_MANAGER::CreateCtx( wxGLCanvas* aCanvas, const wxGLContext* aOther )
40{
41 // Sharing fails between contexts with different reset strategies
42 bool loseOnReset = aOther ? IsLoseOnReset( aOther ) : resetRecoveryEnabled();
43 wxGLContext* context = nullptr;
44
45 if( loseOnReset )
46 {
47 wxGLContextAttrs attrs;
48 attrs.PlatformDefaults().LoseOnReset().EndList();
49
50 // wx reports a failed creation with wxLogMessage, which would show a dialog
51 wxLogNull quiet;
52 context = new wxGLContext( aCanvas, aOther, &attrs );
53
54 if( !context->IsOK() )
55 {
56 delete context;
57 context = nullptr;
58
59 if( aOther )
60 return nullptr;
61
62 loseOnReset = false;
63 }
64 }
65
66 if( !context )
67 {
68 context = new wxGLContext( aCanvas, aOther );
69
70 if( !context->IsOK() )
71 {
72 delete context;
73 return nullptr;
74 }
75 }
76
77 wxLogTrace( traceGalContext, wxS( "Created GL context %p on canvas %p, lose on reset %d" ), context,
78 aCanvas, loseOnReset ? 1 : 0 );
79
80 m_glContexts.insert( std::make_pair( context, aCanvas ) );
81
82 if( loseOnReset )
83 m_loseOnResetContexts.insert( context );
84
85 return context;
86}
87
88
89void GL_CONTEXT_MANAGER::DestroyCtx( wxGLContext* aContext )
90{
91 if( m_glContexts.count( aContext ) )
92 {
93 m_glContexts.erase( aContext );
94 m_loseOnResetContexts.erase( aContext );
95 delete aContext;
96 }
97 else
98 {
99 // Do not delete unknown GL contexts
100 wxFAIL;
101 }
102
103 if( m_glCtx == aContext )
104 m_glCtx = nullptr;
105}
106
107
109{
110 m_glCtxMutex.lock();
111
112 for( auto& ctx : m_glContexts )
113 delete ctx.first;
114
115 m_glContexts.clear();
116 m_loseOnResetContexts.clear();
117 m_glCtx = nullptr;
118 m_glCtxMutex.unlock();
119}
120
121
122bool GL_CONTEXT_MANAGER::LockCtx( wxGLContext* aContext, wxGLCanvas* aCanvas )
123{
124 wxCHECK( aContext && m_glContexts.count( aContext ) > 0, false );
125
126 m_glCtxMutex.lock();
127 wxGLCanvas* canvas = aCanvas ? aCanvas : m_glContexts.at( aContext );
128 bool current = false;
129
130#if defined( __WXMSW__ )
131 // Re-binding the current context makes the driver release it first, which hangs NVIDIA after a reset
132 if( wglGetCurrentContext() == aContext->GetGLRC() && wglGetCurrentDC() == canvas->GetHDC() )
133 current = true;
134 else
135#elif defined( __WXGTK__ )
136 // Prevent assertion failure in wxGLContext::SetCurrent during GAL teardown
137 if( canvas->GTKGetDrawingWindow() )
138#endif
139 {
140 current = canvas->SetCurrent( *aContext );
141 }
142
143 if( !current )
144 {
145 wxLogTrace( traceGalContext, wxS( "Could not make GL context %p current on canvas %p" ),
146 aContext, canvas );
147 }
148
149 m_glCtx = aContext;
150
151 return current;
152}
153
154
155void GL_CONTEXT_MANAGER::UnlockCtx( wxGLContext* aContext )
156{
157 wxCHECK( aContext && m_glContexts.count( aContext ) > 0, /* void */ );
158
159 if( m_glCtx == aContext )
160 {
161 m_glCtxMutex.unlock();
162 m_glCtx = nullptr;
163 }
164 else
165 {
166 wxFAIL_MSG( wxString::Format( wxS( "Trying to unlock GL context mutex from "
167 "a wrong context: aContext %p m_glCtx %p" ), aContext, m_glCtx ) );
168 }
169}
170
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void UnlockCtx(wxGLContext *aContext)
Allow other canvases to bind an OpenGL context.
wxGLContext * m_glCtx
Currently bound GL context.
std::mutex m_glCtxMutex
Lock to prevent unexpected GL context switching.
void DestroyCtx(wxGLContext *aContext)
Destroy a managed OpenGL context.
std::set< const wxGLContext * > m_loseOnResetContexts
Contexts created with the lose-on-reset notification strategy.
std::map< wxGLContext *, wxGLCanvas * > m_glContexts
Map of GL contexts & their parent canvases.
bool LockCtx(wxGLContext *aContext, wxGLCanvas *aCanvas)
Set a context as current and prevents other canvases from switching it.
wxGLContext * CreateCtx(wxGLCanvas *aCanvas, const wxGLContext *aOther=nullptr)
Create a managed OpenGL context.
void DeleteAll()
Destroy all managed OpenGL contexts.
bool IsLoseOnReset(const wxGLContext *aContext) const
static bool resetRecoveryEnabled()
bool m_EnableGLResetRecovery
Create OpenGL contexts that report GPU resets so the canvases can rebuild themselves instead of freez...
const wxChar *const traceGalContext
Flag to enable debug output of GAL context binding.
wxLogTrace helper definitions.