@@ -20,6 +20,7 @@ vgl.shaderProgram = function () {
2020
2121 var m_this = this ,
2222 m_programHandle = 0 ,
23+ m_programContext = null ,
2324 m_compileTimestamp = timestamp ( ) ,
2425 m_bindTimestamp = timestamp ( ) ,
2526 m_shaders = [ ] ,
@@ -28,6 +29,22 @@ vgl.shaderProgram = function () {
2829 m_uniformNameToLocation = { } ,
2930 m_vertexAttributeNameToLocation = { } ;
3031
32+ function hasContextChanged ( renderState ) {
33+ return m_programContext !== renderState . m_context ||
34+ renderState . m_contextChanged ;
35+ }
36+
37+ function clearLocationCaches ( ) {
38+ m_uniformNameToLocation = { } ;
39+ m_vertexAttributeNameToLocation = { } ;
40+ }
41+
42+ function resetProgramState ( ) {
43+ m_programHandle = 0 ;
44+ m_programContext = null ;
45+ clearLocationCaches ( ) ;
46+ }
47+
3148 /**
3249 * Query uniform location in the program.
3350 *
@@ -184,7 +201,7 @@ vgl.shaderProgram = function () {
184201 * @param {vgl.renderState } renderState
185202 */
186203 this . use = function ( renderState ) {
187- renderState . m_context . useProgram ( m_programHandle ) ;
204+ renderState . m_context . useProgram ( m_programHandle || null ) ;
188205 } ;
189206
190207 /**
@@ -193,8 +210,13 @@ vgl.shaderProgram = function () {
193210 * @param {vgl.renderState } renderState
194211 */
195212 this . _setup = function ( renderState ) {
213+ if ( m_programHandle && hasContextChanged ( renderState ) ) {
214+ // A restored/replaced context invalidates all cached program state.
215+ resetProgramState ( ) ;
216+ }
196217 if ( m_programHandle === 0 ) {
197218 m_programHandle = renderState . m_context . createProgram ( ) ;
219+ m_programContext = renderState . m_context ;
198220 }
199221 } ;
200222
@@ -215,10 +237,11 @@ vgl.shaderProgram = function () {
215237 * @param {vgl.renderState } renderState
216238 */
217239 this . deleteProgram = function ( renderState ) {
218- if ( m_programHandle ) {
240+ if ( m_programHandle && renderState &&
241+ m_programContext === renderState . m_context ) {
219242 renderState . m_context . deleteProgram ( m_programHandle ) ;
220243 }
221- m_programHandle = 0 ;
244+ resetProgramState ( ) ;
222245 } ;
223246
224247 /**
@@ -229,8 +252,14 @@ vgl.shaderProgram = function () {
229252 this . deleteVertexAndFragment = function ( renderState ) {
230253 var i ;
231254 for ( i = 0 ; i < m_shaders . length ; i += 1 ) {
255+ if ( renderState && renderState . m_contextChanged ) {
256+ // After context loss there is nothing to detach/delete in GL.
257+ m_shaders [ i ] . removeContext ( renderState ) ;
258+ continue ;
259+ }
232260 if ( m_shaders [ i ] . shaderHandle ( renderState ) ) {
233- renderState . m_context . detachShader ( m_programHandle , m_shaders [ i ] . shaderHandle ( renderState ) ) ;
261+ renderState . m_context . detachShader (
262+ m_programHandle , m_shaders [ i ] . shaderHandle ( renderState ) ) ;
234263 }
235264 renderState . m_context . deleteShader ( m_shaders [ i ] . shaderHandle ( renderState ) ) ;
236265 m_shaders [ i ] . removeContext ( renderState ) ;
@@ -244,12 +273,16 @@ vgl.shaderProgram = function () {
244273 */
245274 this . compileAndLink = function ( renderState ) {
246275 var i ;
276+ // Rebuild if timestamps are stale or we switched GL contexts.
277+ var contextChanged = hasContextChanged ( renderState ) || ! m_programHandle ;
278+
279+ m_this . _setup ( renderState ) ;
247280
248- if ( m_compileTimestamp . getMTime ( ) >= this . getMTime ( ) ) {
249- return ;
281+ if ( ! contextChanged && m_compileTimestamp . getMTime ( ) >= this . getMTime ( ) ) {
282+ return ! ! m_programHandle ;
250283 }
251284
252- m_this . _setup ( renderState ) ;
285+ clearLocationCaches ( ) ;
253286
254287 // Compile shaders
255288 for ( i = 0 ; i < m_shaders . length ; i += 1 ) {
@@ -263,9 +296,11 @@ vgl.shaderProgram = function () {
263296 if ( ! m_this . link ( renderState ) ) {
264297 console . log ( '[ERROR] Failed to link Program' ) ; // eslint-disable-line no-console
265298 m_this . _cleanup ( renderState ) ;
299+ return false ;
266300 }
267301
268302 m_compileTimestamp . modified ( ) ;
303+ return true ;
269304 } ;
270305
271306 /**
@@ -275,16 +310,24 @@ vgl.shaderProgram = function () {
275310 */
276311 this . bind = function ( renderState ) {
277312 var i = 0 ;
313+ var needBind = renderState . m_contextChanged ||
314+ m_bindTimestamp . getMTime ( ) < m_this . getMTime ( ) ||
315+ m_programContext !== renderState . m_context ;
278316
279- if ( m_bindTimestamp . getMTime ( ) < m_this . getMTime ( ) ) {
317+ if ( needBind ) {
280318
281319 // Compile shaders
282- m_this . compileAndLink ( renderState ) ;
320+ if ( ! m_this . compileAndLink ( renderState ) ) {
321+ return ;
322+ }
283323
284324 m_this . use ( renderState ) ;
285325 m_this . bindUniforms ( renderState ) ;
286326 m_bindTimestamp . modified ( ) ;
287327 } else {
328+ if ( ! m_programHandle ) {
329+ return ;
330+ }
288331 m_this . use ( renderState ) ;
289332 }
290333
0 commit comments