diff --git a/pixelgl/interface.go b/pixelgl/interface.go
index c079204ea91fc1cfdacb82322b2673e2f0b23885..3dd71e696ff16e740301b241c3c5d656f437400b 100644
--- a/pixelgl/interface.go
+++ b/pixelgl/interface.go
@@ -27,6 +27,8 @@ package pixelgl
 // Also notice, that the functions are passing a Context around. This context contains the most important state variables.
 // Usually, you just pass it as you received it. If you want to pass a changed context to your child (e.g. your a shader),
 // use ctx.With* methods.
+//
+// If possible and makes sense, Do method should be reentrant.
 type Doer interface {
 	Do(sub func(Context))
 }
diff --git a/pixelgl/shader.go b/pixelgl/shader.go
index 2b24ebd8da022380856c568d5fbe5b28e735a016..3023d8c45b1efd3d518aa42076b03c9e2ac44d39 100644
--- a/pixelgl/shader.go
+++ b/pixelgl/shader.go
@@ -17,6 +17,7 @@ type UniformFormat map[string]Attr
 
 // Shader is an OpenGL shader program.
 type Shader struct {
+	enabled       bool
 	parent        Doer
 	program       uint32
 	vertexFormat  VertexFormat
@@ -383,6 +384,11 @@ func (s *Shader) SetUniformMat43(purpose AttrPurpose, value mgl32.Mat4x3) (ok bo
 // Do stars using a shader, executes sub, and stops using it.
 func (s *Shader) Do(sub func(Context)) {
 	s.parent.Do(func(ctx Context) {
+		if s.enabled {
+			sub(ctx.WithShader(s))
+			return
+		}
+		s.enabled = true
 		DoNoBlock(func() {
 			gl.UseProgram(s.program)
 		})
@@ -390,5 +396,6 @@ func (s *Shader) Do(sub func(Context)) {
 		DoNoBlock(func() {
 			gl.UseProgram(0)
 		})
+		s.enabled = false
 	})
 }
diff --git a/pixelgl/texture.go b/pixelgl/texture.go
index ae6d8a77463c34d51ad208abbb99c097180a3cfe..c79d8cf5398e8a8ecd021f61454c0a74c592fa1f 100644
--- a/pixelgl/texture.go
+++ b/pixelgl/texture.go
@@ -7,8 +7,9 @@ import (
 
 // Texture is an OpenGL texture.
 type Texture struct {
-	parent Doer
-	tex    uint32
+	enabled bool
+	parent  Doer
+	tex     uint32
 }
 
 // NewTexture creates a new texture with the specified width and height.
@@ -63,6 +64,11 @@ func (t *Texture) ID() uint32 {
 // Do bind a texture, executes sub, and unbinds the texture.
 func (t *Texture) Do(sub func(Context)) {
 	t.parent.Do(func(ctx Context) {
+		if t.enabled {
+			sub(ctx)
+			return
+		}
+		t.enabled = true
 		DoNoBlock(func() {
 			gl.BindTexture(gl.TEXTURE_2D, t.tex)
 		})
@@ -70,5 +76,6 @@ func (t *Texture) Do(sub func(Context)) {
 		DoNoBlock(func() {
 			gl.BindTexture(gl.TEXTURE_2D, 0)
 		})
+		t.enabled = false
 	})
 }
diff --git a/pixelgl/vertex.go b/pixelgl/vertex.go
index f112daee242cff7e686418f28334555057020a8f..25012d46a1f57c177f6717c540aa4bb4f15c3648 100644
--- a/pixelgl/vertex.go
+++ b/pixelgl/vertex.go
@@ -69,14 +69,15 @@ const (
 // VertexArray is an OpenGL vertex array object that also holds it's own vertex buffer object.
 // From the user's points of view, VertexArray is an array of vertices that can be drawn.
 type VertexArray struct {
-	parent Doer
-	vao    uint32
-	vbo    uint32
-	format VertexFormat
-	stride int
-	count  int
-	attrs  map[Attr]int
-	mode   VertexDrawMode
+	enabled bool
+	parent  Doer
+	vao     uint32
+	vbo     uint32
+	format  VertexFormat
+	stride  int
+	count   int
+	attrs   map[Attr]int
+	mode    VertexDrawMode
 }
 
 // NewVertexArray creates a new empty vertex array and wraps another Doer around it.
@@ -341,6 +342,11 @@ func (va *VertexArray) SetVertexAttributeVec4(vertex int, purpose AttrPurpose, v
 // Do binds a vertex arrray and it's associated vertex buffer, executes sub, and unbinds the vertex array and it's vertex buffer.
 func (va *VertexArray) Do(sub func(Context)) {
 	va.parent.Do(func(ctx Context) {
+		if va.enabled {
+			sub(ctx)
+			return
+		}
+		va.enabled = true
 		DoNoBlock(func() {
 			gl.BindVertexArray(va.vao)
 			gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
@@ -351,5 +357,6 @@ func (va *VertexArray) Do(sub func(Context)) {
 			gl.BindBuffer(gl.ARRAY_BUFFER, 0)
 			gl.BindVertexArray(0)
 		})
+		va.enabled = false
 	})
 }