Merge "Add gles.tweaker for temporarily tweaking things." into studio-1.4-dev
diff --git a/gfxapi/gles/tweaker.go b/gfxapi/gles/tweaker.go
new file mode 100644
index 0000000..727c8c0
--- /dev/null
+++ b/gfxapi/gles/tweaker.go
@@ -0,0 +1,114 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package gles
+
+import "android.googlesource.com/platform/tools/gpu/atom"
+
+// tweaker provides a set of methods for temporarily changing the GLES state.
+type tweaker struct {
+	out  atom.Writer
+	ctx  *Context
+	undo []func()
+}
+
+// revert undoes all the changes made by the tweaker.
+func (t *tweaker) revert() {
+	for i := len(t.undo) - 1; i >= 0; i-- {
+		t.undo[i]()
+	}
+	t.undo = nil
+}
+
+func (t *tweaker) glEnable(v GLenum) {
+	if !t.ctx.Capabilities[v] {
+		t.undo = append(t.undo, func() {
+			t.out.Write(atom.NoID, NewGlDisable(v))
+			t.ctx.Capabilities[v] = false
+		})
+		t.out.Write(atom.NoID, NewGlEnable(v))
+		t.ctx.Capabilities[v] = true
+	}
+}
+
+func (t *tweaker) glDisable(v GLenum) {
+	if t.ctx.Capabilities[v] {
+		t.undo = append(t.undo, func() {
+			t.out.Write(atom.NoID, NewGlEnable(v))
+			t.ctx.Capabilities[v] = true
+		})
+		t.out.Write(atom.NoID, NewGlDisable(v))
+		t.ctx.Capabilities[v] = false
+	}
+}
+
+func (t *tweaker) glDepthMask(v bool) {
+	if o := t.ctx.Rasterizing.DepthMask; o != v {
+		t.undo = append(t.undo, func() {
+			t.out.Write(atom.NoID, NewGlDepthMask(o))
+			t.ctx.Rasterizing.DepthMask = o
+		})
+		t.out.Write(atom.NoID, NewGlDepthMask(v))
+		t.ctx.Rasterizing.DepthMask = v
+	}
+}
+
+func (t *tweaker) glDepthFunc(v GLenum) {
+	if o := t.ctx.Rasterizing.DepthTestFunction; o != v {
+		t.undo = append(t.undo, func() {
+			t.out.Write(atom.NoID, NewGlDepthFunc(o))
+			t.ctx.Rasterizing.DepthTestFunction = o
+		})
+		t.out.Write(atom.NoID, NewGlDepthFunc(v))
+		t.ctx.Rasterizing.DepthTestFunction = v
+	}
+}
+
+func (t *tweaker) glBlendColor(r, g, b, a float32) {
+	n := Color{Red: r, Green: g, Blue: b, Alpha: a}
+	if o := t.ctx.Blending.BlendColor; o != n {
+		t.undo = append(t.undo, func() {
+			t.out.Write(atom.NoID, NewGlBlendColor(o.Red, o.Green, o.Blue, o.Alpha))
+			t.ctx.Blending.BlendColor = o
+		})
+		t.out.Write(atom.NoID, NewGlBlendColor(r, g, b, a))
+		t.ctx.Blending.BlendColor = n
+	}
+}
+
+func (t *tweaker) glBlendFunc(src, dst GLenum) {
+	t.glBlendFuncSeparate(src, dst, src, dst)
+}
+
+func (t *tweaker) glBlendFuncSeparate(srcRGB, dstRGB, srcA, dstA GLenum) {
+	oSrcRGB, oDstRGB, oSrcA, oDstA :=
+		t.ctx.Blending.SrcRgbBlendFactor,
+		t.ctx.Blending.DstRgbBlendFactor,
+		t.ctx.Blending.SrcAlphaBlendFactor,
+		t.ctx.Blending.DstAlphaBlendFactor
+	if oSrcRGB != srcRGB || oDstRGB != dstRGB || oSrcA != srcA || oDstA != dstA {
+		t.undo = append(t.undo, func() {
+			t.out.Write(atom.NoID, NewGlBlendFuncSeparate(oSrcRGB, oDstRGB, oSrcA, oDstA))
+			t.ctx.Blending.SrcRgbBlendFactor,
+				t.ctx.Blending.DstRgbBlendFactor,
+				t.ctx.Blending.SrcAlphaBlendFactor,
+				t.ctx.Blending.DstAlphaBlendFactor = oSrcRGB, oDstRGB, oSrcA, oDstA
+		})
+		t.out.Write(atom.NoID, NewGlBlendFuncSeparate(srcRGB, dstRGB, srcA, dstA))
+		t.ctx.Blending.SrcRgbBlendFactor,
+			t.ctx.Blending.DstRgbBlendFactor,
+			t.ctx.Blending.SrcAlphaBlendFactor,
+			t.ctx.Blending.DstAlphaBlendFactor = srcRGB, dstRGB, srcA, dstA
+	}
+}