diff --git a/fsl/fsleyes/gl/gl14/gllabel_funcs.py b/fsl/fsleyes/gl/gl14/gllabel_funcs.py
index 2669d48d9515a427fcd9cc0d2d3081225f2b898e..989e51ca134f8bcb92720543f6f225ebc5fd9fec 100644
--- a/fsl/fsleyes/gl/gl14/gllabel_funcs.py
+++ b/fsl/fsleyes/gl/gl14/gllabel_funcs.py
@@ -85,6 +85,8 @@ def updateShaderState(self):
 
     self.shader.unload()
 
+    return True
+
 
 preDraw  = glvolume_funcs.preDraw
 draw     = glvolume_funcs.draw
diff --git a/fsl/fsleyes/gl/gl14/gllinevector_funcs.py b/fsl/fsleyes/gl/gl14/gllinevector_funcs.py
index a47fad3a88601d328b43c3037cdbdcbfa7ba7bf1..a823ff9d1ec732ad5f5d31d94bd0375f6d9f7a4e 100644
--- a/fsl/fsleyes/gl/gl14/gllinevector_funcs.py
+++ b/fsl/fsleyes/gl/gl14/gllinevector_funcs.py
@@ -136,6 +136,8 @@ def updateShaderState(self):
     self.shader.setVertParam('voxelOffsets',  offset)
 
     self.shader.unload()
+
+    return True
     
 
 def preDraw(self):
diff --git a/fsl/fsleyes/gl/gl14/glrgbvector_funcs.py b/fsl/fsleyes/gl/gl14/glrgbvector_funcs.py
index f5d49d469193ecb2b99a8f17a4f25739c14d1134..b671e7ceda179b5262a21dd00498a2b1d1d6257e 100644
--- a/fsl/fsleyes/gl/gl14/glrgbvector_funcs.py
+++ b/fsl/fsleyes/gl/gl14/glrgbvector_funcs.py
@@ -63,6 +63,8 @@ def updateShaderState(self):
     self.shader.setVertParam('imageShape', shape + [0])
     self.shader.unload()
 
+    return True
+
 
 preDraw  = glvolume_funcs.preDraw
 draw     = glvolume_funcs.draw
diff --git a/fsl/fsleyes/gl/gl14/glvector_funcs.py b/fsl/fsleyes/gl/gl14/glvector_funcs.py
index 93f96a58f963683fea6e58d24af2d695194cc647..a2168dddd8d947bc6fc0aa4f6a21e23dde35357c 100644
--- a/fsl/fsleyes/gl/gl14/glvector_funcs.py
+++ b/fsl/fsleyes/gl/gl14/glvector_funcs.py
@@ -114,3 +114,5 @@ def updateFragmentShaderState(self):
         self.shader.setFragParam('cmapXform',   cmapXform)
 
     self.shader.unload()
+
+    return True
diff --git a/fsl/fsleyes/gl/gl21/gllabel_funcs.py b/fsl/fsleyes/gl/gl21/gllabel_funcs.py
index 3467aace556e4244ab490b0e05aef2cafeb06b09..1958fbad7ec5377e7f6c6575ab7e19e4842d3c02 100644
--- a/fsl/fsleyes/gl/gl21/gllabel_funcs.py
+++ b/fsl/fsleyes/gl/gl21/gllabel_funcs.py
@@ -68,16 +68,20 @@ def updateShaderState(self):
 
     shader.load()
 
-    shader.set('outline',        opts.outline)
-    shader.set('numLabels',      opts.lut.max() + 1)
-    shader.set('imageShape',     imageShape)
-    shader.set('voxValXform',    vvx)
-    shader.set('outlineOffsets', outlineOffsets)
-    shader.set('imageTexture',   0)
-    shader.set('lutTexture',     1)
+    changed = False
+
+    changed |= shader.set('outline',        opts.outline)
+    changed |= shader.set('numLabels',      opts.lut.max() + 1)
+    changed |= shader.set('imageShape',     imageShape)
+    changed |= shader.set('voxValXform',    vvx)
+    changed |= shader.set('outlineOffsets', outlineOffsets)
+    changed |= shader.set('imageTexture',   0)
+    changed |= shader.set('lutTexture',     1)
 
     shader.unload()
 
+    return changed
+
 
 preDraw  = glvolume_funcs.preDraw
 draw     = glvolume_funcs.draw
diff --git a/fsl/fsleyes/gl/gl21/gllinevector_funcs.py b/fsl/fsleyes/gl/gl21/gllinevector_funcs.py
index 87416a6189c1e828d340ca00a1146a45e64982c4..a523ef183e0747ec650cee9c9e99b24fb56982a4 100644
--- a/fsl/fsleyes/gl/gl21/gllinevector_funcs.py
+++ b/fsl/fsleyes/gl/gl21/gllinevector_funcs.py
@@ -71,16 +71,15 @@ def updateShaderState(self):
     shader = self.shader
     shader.load()
     
-    glvector_funcs.updateFragmentShaderState(self)
+    changed   = glvector_funcs.updateFragmentShaderState(self)
+    image     = self.vectorImage
+    opts      = self.displayOpts
 
-    image = self.vectorImage
-    opts  = self.displayOpts
-
-    vvxMat     = self.imageTexture.voxValXform
-    directed   = opts.directed
-    imageDims  = image.pixdim[:3]
-    d2vMat     = opts.getTransform('display', 'voxel')
-    v2dMat     = opts.getTransform('voxel',   'display')
+    vvxMat    = self.imageTexture.voxValXform
+    directed  = opts.directed
+    imageDims = image.pixdim[:3]
+    d2vMat    = opts.getTransform('display', 'voxel')
+    v2dMat    = opts.getTransform('voxel',   'display')
 
     # The shader adds these offsets to
     # transformed voxel coordinates, so
@@ -88,16 +87,18 @@ def updateShaderState(self):
     # voxel coordinates
     offset = [0.5, 0.5, 0.5]
 
-    shader.set('vectorTexture',   0)
-    shader.set('displayToVoxMat', d2vMat)
-    shader.set('voxToDisplayMat', v2dMat)
-    shader.set('voxValXform',     vvxMat)
-    shader.set('voxelOffset',     offset)
-    shader.set('imageDims',       imageDims)
-    shader.set('directed',        directed)
+    changed |= shader.set('vectorTexture',   0)
+    changed |= shader.set('displayToVoxMat', d2vMat)
+    changed |= shader.set('voxToDisplayMat', v2dMat)
+    changed |= shader.set('voxValXform',     vvxMat)
+    changed |= shader.set('voxelOffset',     offset)
+    changed |= shader.set('imageDims',       imageDims)
+    changed |= shader.set('directed',        directed)
 
     shader.unload()
 
+    return changed
+
 
 def preDraw(self):
     """Prepares the GL state for drawing. This amounts to loading the
diff --git a/fsl/fsleyes/gl/gl21/glrgbvector_funcs.py b/fsl/fsleyes/gl/gl21/glrgbvector_funcs.py
index 7fc8485c074c53727b862beb9dd09bde0a85161d..097cfbf5b709e9785865e5a56677892659863f7d 100644
--- a/fsl/fsleyes/gl/gl21/glrgbvector_funcs.py
+++ b/fsl/fsleyes/gl/gl21/glrgbvector_funcs.py
@@ -60,9 +60,12 @@ def updateShaderState(self):
     useSpline = opts.interpolation == 'spline'
 
     self.shader.load()
-    glvector_funcs.updateFragmentShaderState(self, useSpline=useSpline)
+    changed = glvector_funcs.updateFragmentShaderState(self,
+                                                       useSpline=useSpline)
     self.shader.unload()
 
+    return changed
+
 
 preDraw  = glvolume_funcs.preDraw
 draw     = glvolume_funcs.draw
diff --git a/fsl/fsleyes/gl/gl21/gltensor_funcs.py b/fsl/fsleyes/gl/gl21/gltensor_funcs.py
index 9e3a8ed4ee2f0923b4eb7c677c1d64253a5366b8..15554b661892b741871df346cb4d9d04d5e76c59 100644
--- a/fsl/fsleyes/gl/gl21/gltensor_funcs.py
+++ b/fsl/fsleyes/gl/gl21/gltensor_funcs.py
@@ -137,7 +137,8 @@ def updateShaderState(self):
     opts   = self.displayOpts
     
     shader.load()
-    glvector_funcs.updateFragmentShaderState(self)
+    
+    changed = glvector_funcs.updateFragmentShaderState(self)
 
     # Texture -> value value offsets/scales
     # used by the vertex and fragment shaders
@@ -163,24 +164,24 @@ def updateShaderState(self):
     lightPos /= np.sqrt(np.sum(lightPos ** 2)) 
  
     # Textures used by the vertex shader
-    shader.set('v1Texture', 8)
-    shader.set('v2Texture', 9)
-    shader.set('v3Texture', 10)
-    shader.set('l1Texture', 11)
-    shader.set('l2Texture', 12)
-    shader.set('l3Texture', 13)
+    changed |= shader.set('v1Texture', 8)
+    changed |= shader.set('v2Texture', 9)
+    changed |= shader.set('v3Texture', 10)
+    changed |= shader.set('l1Texture', 11)
+    changed |= shader.set('l2Texture', 12)
+    changed |= shader.set('l3Texture', 13)
     
-    shader.set('v1ValXform', v1ValXform)
-    shader.set('v2ValXform', v2ValXform)
-    shader.set('v3ValXform', v3ValXform)
-    shader.set('l1ValXform', l1ValXform)
-    shader.set('l2ValXform', l2ValXform)
-    shader.set('l3ValXform', l3ValXform)
-
-    shader.set('imageShape', imageShape)
-    shader.set('eigValNorm', eigValNorm)
-    shader.set('lighting',   opts.lighting)
-    shader.set('lightPos',   lightPos)
+    changed |= shader.set('v1ValXform', v1ValXform)
+    changed |= shader.set('v2ValXform', v2ValXform)
+    changed |= shader.set('v3ValXform', v3ValXform)
+    changed |= shader.set('l1ValXform', l1ValXform)
+    changed |= shader.set('l2ValXform', l2ValXform)
+    changed |= shader.set('l3ValXform', l3ValXform)
+
+    changed |= shader.set('imageShape', imageShape)
+    changed |= shader.set('eigValNorm', eigValNorm)
+    changed |= shader.set('lighting',   opts.lighting)
+    changed |= shader.set('lightPos',   lightPos)
     
     # Vertices of a unit sphere. The vertex
     # shader will transform these vertices
@@ -194,6 +195,8 @@ def updateShaderState(self):
     shader.setIndices(indices)
     shader.unload()
 
+    return changed
+
 
 def preDraw(self):
     """Must be called before :func:`draw`. Loads the shader programs, does
diff --git a/fsl/fsleyes/gl/gl21/glvector_funcs.py b/fsl/fsleyes/gl/gl21/glvector_funcs.py
index 9463cdff74da848b08b5c4b84ace33dbb68857fc..dd5cdf08f4c7dd32d775e7a3b1cabdc62012feee 100644
--- a/fsl/fsleyes/gl/gl21/glvector_funcs.py
+++ b/fsl/fsleyes/gl/gl21/glvector_funcs.py
@@ -44,6 +44,8 @@ def updateFragmentShaderState(self, useSpline=False):
     """Updates the state of the fragment shader - it may be either the
     ``glvolume`` or the ``glvector`` shader.
     """
+
+    changed             = False
     opts                = self.displayOpts
     shader              = self.shader
     useVolumeFragShader = opts.colourImage is not None
@@ -74,34 +76,36 @@ def updateFragmentShaderState(self, useSpline=False):
             voxValXform,
             self.cmapTexture.getCoordinateTransform())
 
-        shader.set('clipTexture',      2)
-        shader.set('imageTexture',     3)
-        shader.set('colourTexture',    7)
-        shader.set('negColourTexture', 7)
-        shader.set('img2CmapXform',    img2CmapXform)
-        shader.set('imageShape',       imageShape)
-        shader.set('imageIsClip',      False)
-        shader.set('useNegCmap',       False)
-        shader.set('useSpline',        useSpline)
-        shader.set('clipLow',          clipLow)
-        shader.set('clipHigh',         clipHigh)
-        shader.set('texZero',          texZero)
-        shader.set('invertClip',       False)
+        changed |= shader.set('clipTexture',      2)
+        changed |= shader.set('imageTexture',     3)
+        changed |= shader.set('colourTexture',    7)
+        changed |= shader.set('negColourTexture', 7)
+        changed |= shader.set('img2CmapXform',    img2CmapXform)
+        changed |= shader.set('imageShape',       imageShape)
+        changed |= shader.set('imageIsClip',      False)
+        changed |= shader.set('useNegCmap',       False)
+        changed |= shader.set('useSpline',        useSpline)
+        changed |= shader.set('clipLow',          clipLow)
+        changed |= shader.set('clipHigh',         clipHigh)
+        changed |= shader.set('texZero',          texZero)
+        changed |= shader.set('invertClip',       False)
     
     else:
 
         voxValXform = self.imageTexture.voxValXform
         cmapXform   = self.xColourTexture.getCoordinateTransform()
 
-        shader.set('vectorTexture',   0)
-        shader.set('modulateTexture', 1)
-        shader.set('clipTexture',     2)
-        shader.set('xColourTexture',  4)
-        shader.set('yColourTexture',  5)
-        shader.set('zColourTexture',  6)
-        shader.set('voxValXform',     voxValXform)
-        shader.set('cmapXform',       cmapXform)
-        shader.set('imageShape',      imageShape)
-        shader.set('clipLow',         clipLow)
-        shader.set('clipHigh',        clipHigh) 
-        shader.set('useSpline',       useSpline)
+        changed |= shader.set('vectorTexture',   0)
+        changed |= shader.set('modulateTexture', 1)
+        changed |= shader.set('clipTexture',     2)
+        changed |= shader.set('xColourTexture',  4)
+        changed |= shader.set('yColourTexture',  5)
+        changed |= shader.set('zColourTexture',  6)
+        changed |= shader.set('voxValXform',     voxValXform)
+        changed |= shader.set('cmapXform',       cmapXform)
+        changed |= shader.set('imageShape',      imageShape)
+        changed |= shader.set('clipLow',         clipLow)
+        changed |= shader.set('clipHigh',        clipHigh) 
+        changed |= shader.set('useSpline',       useSpline)
+
+    return changed
diff --git a/fsl/fsleyes/gl/gllabel.py b/fsl/fsleyes/gl/gllabel.py
index 4af0470796f331fa0e547188bb8ea0a94bcea98b..a91e381fb3ccc1198bd9acc36e85f09666550e86 100644
--- a/fsl/fsleyes/gl/gllabel.py
+++ b/fsl/fsleyes/gl/gllabel.py
@@ -101,8 +101,8 @@ class GLLabel(globject.GLImageObject):
 
         def shaderUpdate(*a):
             if self.ready():
-                fslgl.gllabel_funcs.updateShaderState(self)
-                self.notify()
+                if fslgl.gllabel_funcs.updateShaderState(self):
+                    self.notify()
             
         def shaderCompile(*a):
             fslgl.gllabel_funcs.compileShaders(self)
diff --git a/fsl/fsleyes/gl/gllinevector.py b/fsl/fsleyes/gl/gllinevector.py
index 4507d96c78de5494eb8bdfed9f5b9651b9ed6cda..1549f9bdd5e9eb1313455054f429d2668b074814 100644
--- a/fsl/fsleyes/gl/gllinevector.py
+++ b/fsl/fsleyes/gl/gllinevector.py
@@ -122,7 +122,7 @@ class GLLineVector(glvector.GLVector):
         """Overrides :meth:`.GLVector.updateShaderState`. Calls the OpenGL
         version-specific ``updateShaderState`` function.
         """ 
-        fslgl.gllinevector_funcs.updateShaderState(self)
+        return fslgl.gllinevector_funcs.updateShaderState(self)
  
 
     def preDraw(self):
diff --git a/fsl/fsleyes/gl/glmask.py b/fsl/fsleyes/gl/glmask.py
index b6436d26b27ce335b0907980ed4e4325bdc935a9..bf144ec17b8f76ad14f39cd38114b4e2fc86f9d6 100644
--- a/fsl/fsleyes/gl/glmask.py
+++ b/fsl/fsleyes/gl/glmask.py
@@ -53,8 +53,8 @@ class GLMask(glvolume.GLVolume):
         
         def shaderUpdate(*a):
             if self.ready():
-                fslgl.glvolume_funcs.updateShaderState(self)
-                self.notify() 
+                if fslgl.glvolume_funcs.updateShaderState(self):
+                    self.notify() 
 
         def shaderCompile(*a):
             fslgl.glvolume_funcs.compileShaders(self)
diff --git a/fsl/fsleyes/gl/glrgbvector.py b/fsl/fsleyes/gl/glrgbvector.py
index 8d8968dce5a7563b1e87250cab272e41f9158663..5d290dd506ace290f48abe8b9bebda278f5970ad 100644
--- a/fsl/fsleyes/gl/glrgbvector.py
+++ b/fsl/fsleyes/gl/glrgbvector.py
@@ -147,7 +147,7 @@ class GLRGBVector(glvector.GLVector):
         """Overrides :meth:`.GLVector.compileShaders`. Calls the OpenGL
         version-specific ``updateShaderState`` function.
         """ 
-        fslgl.glrgbvector_funcs.updateShaderState(self)
+        return fslgl.glrgbvector_funcs.updateShaderState(self)
 
 
     def preDraw(self):
diff --git a/fsl/fsleyes/gl/gltensor.py b/fsl/fsleyes/gl/gltensor.py
index 513c51f9ea5c0c2b4dd866b0ef35adc5a0cd5f5a..96f8e7d68bbd91d840a1136ea41e9baf33005279 100644
--- a/fsl/fsleyes/gl/gltensor.py
+++ b/fsl/fsleyes/gl/gltensor.py
@@ -112,7 +112,7 @@ class GLTensor(glvector.GLVector):
         """Overrides :meth:`.GLVector.updateShaderState`. Calls the
         :func:`.gl21.gltensor_funcs.updateShaderState` function.
         """ 
-        fslgl.gltensor_funcs.updateShaderState(self)
+        return fslgl.gltensor_funcs.updateShaderState(self)
 
         
     def preDraw(self):
diff --git a/fsl/fsleyes/gl/glvector.py b/fsl/fsleyes/gl/glvector.py
index 73b6dfc5406e010ba50a3d211db4766c9957d4d7..94dab3d867790c130559a9c17f7ace5e0aed040b 100644
--- a/fsl/fsleyes/gl/glvector.py
+++ b/fsl/fsleyes/gl/glvector.py
@@ -255,8 +255,8 @@ class GLVector(globject.GLImageObject):
             
         def shaderUpdate(*a):
             if self.ready():
-                self.updateShaderState()
-                self.notify() 
+                if self.updateShaderState():
+                    self.notify() 
         
         def modUpdate( *a):
             self.deregisterAuxImage('modulate')
@@ -410,7 +410,8 @@ class GLVector(globject.GLImageObject):
     def updateShaderState(self):
         """This method must be provided by subclasses (the
         :class:`.GLRGBVector` and :class:`.GLLineVector` classes), and must
-        update the state of the vertex/fragment shader programs.
+        update the state of the vertex/fragment shader programs. It must return
+        ``True`` if the shader state was updated, ``False`` otherwise.
         """
         raise NotImplementedError('updateShaderState must be implemented by '
                                   '{} subclasses'.format(type(self).__name__))