@@ -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 ) ;
@@ -241,15 +270,20 @@ vgl.shaderProgram = function () {
241270 * Compile and link a shader.
242271 *
243272 * @param {vgl.renderState } renderState
273+ * @returns {boolean } True if the program was compiled and linked successfully, false otherwise.
244274 */
245275 this . compileAndLink = function ( renderState ) {
246276 var i ;
277+ // Rebuild if timestamps are stale or we switched GL contexts.
278+ var contextChanged = hasContextChanged ( renderState ) || ! m_programHandle ;
279+
280+ m_this . _setup ( renderState ) ;
247281
248- if ( m_compileTimestamp . getMTime ( ) >= this . getMTime ( ) ) {
249- return ;
282+ if ( ! contextChanged && m_compileTimestamp . getMTime ( ) >= this . getMTime ( ) ) {
283+ return ! ! m_programHandle ;
250284 }
251285
252- m_this . _setup ( renderState ) ;
286+ clearLocationCaches ( ) ;
253287
254288 // Compile shaders
255289 for ( i = 0 ; i < m_shaders . length ; i += 1 ) {
@@ -263,9 +297,11 @@ vgl.shaderProgram = function () {
263297 if ( ! m_this . link ( renderState ) ) {
264298 console . log ( '[ERROR] Failed to link Program' ) ; // eslint-disable-line no-console
265299 m_this . _cleanup ( renderState ) ;
300+ return false ;
266301 }
267302
268303 m_compileTimestamp . modified ( ) ;
304+ return true ;
269305 } ;
270306
271307 /**
@@ -275,16 +311,24 @@ vgl.shaderProgram = function () {
275311 */
276312 this . bind = function ( renderState ) {
277313 var i = 0 ;
314+ var needBind = renderState . m_contextChanged ||
315+ m_bindTimestamp . getMTime ( ) < m_this . getMTime ( ) ||
316+ m_programContext !== renderState . m_context ;
278317
279- if ( m_bindTimestamp . getMTime ( ) < m_this . getMTime ( ) ) {
318+ if ( needBind ) {
280319
281320 // Compile shaders
282- m_this . compileAndLink ( renderState ) ;
321+ if ( ! m_this . compileAndLink ( renderState ) ) {
322+ return ;
323+ }
283324
284325 m_this . use ( renderState ) ;
285326 m_this . bindUniforms ( renderState ) ;
286327 m_bindTimestamp . modified ( ) ;
287328 } else {
329+ if ( ! m_programHandle ) {
330+ return ;
331+ }
288332 m_this . use ( renderState ) ;
289333 }
290334
0 commit comments