GLES2Dbg: organize calls into frames and contexts
Maintain a current state for each context updated by each call.
eglSwapBuffers Begins a new frame; clone current state.
Use clone to compute context for a call within that frame later on,
in the context tree view.
Change-Id: I66658561f610025b203a991b5b9f545a9a2f9cd4
Signed-off-by: David Li <davidxli@google.com>
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/Context.java b/tools/glesv2debugger/src/com/android/glesv2debugger/Context.java
index ff096d7..c228df8 100644
--- a/tools/glesv2debugger/src/com/android/glesv2debugger/Context.java
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/Context.java
@@ -21,23 +21,78 @@
import com.android.sdklib.util.SparseArray;
import com.android.sdklib.util.SparseIntArray;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
+class Frame {
+ final Context startContext;
+ ArrayList<MessageData> calls = new ArrayList<MessageData>();
+
+ Frame(final Context context) {
+ this.startContext = context.clone();
+ }
+}
+
+class DebugContext {
+ final int contextId;
+ Context currentContext;
+ ArrayList<Frame> frames = new ArrayList<Frame>(128);
+ private Frame currentFrame;
+
+ DebugContext(final int contextId) {
+ this.contextId = contextId;
+ currentContext = new Context(contextId);
+ frames.add(new Frame(currentContext));
+ currentFrame = frames.get(0);
+ }
+
+ MessageData ProcessMessage(final Message oriMsg) {
+ currentContext.ProcessMessage(oriMsg);
+ Message msg = oriMsg;
+ if (currentContext.processed != null)
+ msg = currentContext.processed;
+ currentContext.processed = null;
+ MessageData msgData = new MessageData(Display.getCurrent(), msg, oriMsg, currentContext);
+ currentFrame.calls.add(msgData);
+ if (msg.getFunction() != Function.eglSwapBuffers)
+ return msgData;
+ frames.add(currentFrame = new Frame(currentContext));
+ return msgData;
+ }
+
+ Context ComputeContext(final Frame frame, final MessageData call) {
+ Context ctx = frame.startContext.clone();
+ for (int i = 0; i < frame.calls.size(); i++)
+ if (call == frame.calls.get(i))
+ return ctx;
+ else
+ ctx.ProcessMessage(frame.calls.get(i).oriMsg);
+ assert false;
+ return ctx;
+ }
+}
+
+/** aggregate of GL states */
public class Context implements Cloneable {
public final int contextId;
public ArrayList<Context> shares = new ArrayList<Context>(); // self too
public GLServerVertex serverVertex = new GLServerVertex();
public GLServerShader serverShader = new GLServerShader(this);
public GLServerState serverState = new GLServerState(this);
+ public GLServerTexture serverTexture = new GLServerTexture(this);
byte[] readPixelRef = new byte[0];
@@ -48,42 +103,44 @@
shares.add(this);
}
- // returns instance TODO: return new instance if changed
- public Context ProcessMessage(Message msg) {
- GLServerVertex newVertex = serverVertex.Process(msg);
- if (newVertex != null) {
- processed = newVertex.processed;
- assert newVertex == serverVertex;
- return this;
+ @Override
+ public Context clone() {
+ try {
+ Context copy = (Context) super.clone();
+ copy.serverVertex = serverVertex.clone();
+ copy.serverShader = serverShader.clone(copy);
+ copy.serverState = serverState.clone();
+ copy.serverTexture = serverTexture.clone(copy);
+ return copy;
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ assert false;
+ return null;
}
+ }
- GLServerShader newShader = serverShader.ProcessMessage(msg);
- if (newShader != null) {
- assert newShader == serverShader;
- return this;
+ public void ProcessMessage(Message msg) {
+ if (serverVertex.Process(msg)) {
+ processed = serverVertex.processed;
+ return;
}
-
- GLServerState newState = serverState.ProcessMessage(msg);
- if (newState != null) {
- if (newState == serverState)
- return this;
- Context newContext = null;
- try {
- newContext = (Context) clone();
- } catch (CloneNotSupportedException e) {
- assert false;
- }
- newContext.serverState = newState;
- newContext.serverShader.context = newContext;
- return newContext;
- }
-
- return this;
+ if (serverShader.ProcessMessage(msg))
+ return;
+ if (serverState.ProcessMessage(msg))
+ return;
+ if (serverTexture.ProcessMessage(msg))
+ return;
}
}
-class ContextViewProvider extends LabelProvider implements ITreeContentProvider {
+class ContextViewProvider extends LabelProvider implements ITreeContentProvider,
+ ISelectionChangedListener {
Context context;
+ final SampleView sampleView;
+
+ ContextViewProvider(final SampleView sampleView) {
+ this.sampleView = sampleView;
+ }
@Override
public void dispose() {
@@ -95,18 +152,54 @@
return "null";
if (obj instanceof Entry) {
Entry entry = (Entry) obj;
- if (entry != null)
- return entry.name + " = " + entry.obj;
+ String objStr = "null (or default)";
+ if (entry.obj != null) {
+ objStr = entry.obj.toString();
+ if (entry.obj instanceof Message)
+ objStr = MessageFormatter.Format((Message) entry.obj);
+ }
+ return entry.name + " = " + objStr;
}
return obj.toString();
}
@Override
public Image getImage(Object obj) {
+ if (!(obj instanceof Entry))
+ return null;
+ final Entry entry = (Entry) obj;
+ if (!(entry.obj instanceof Message))
+ return null;
+ final Message msg = (Message) entry.obj;
+ for (int i = 0; i <= sampleView.frameNum.getSelection(); i++) {
+ if (i == sampleView.current.frames.size())
+ return null;
+ final Frame frame = sampleView.current.frames.get(i);
+ for (final MessageData msgData : frame.calls)
+ if (msgData.oriMsg == msg)
+ return entry.image = msgData.image;
+ }
return null;
}
@Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ StructuredSelection selection = (StructuredSelection) event
+ .getSelection();
+ if (null == selection)
+ return;
+ final Object obj = selection.getFirstElement();
+ if (!(obj instanceof Entry))
+ return;
+ final Entry entry = (Entry) obj;
+ if (entry.image == null)
+ return;
+ sampleView.tabFolder.setSelection(sampleView.tabItemImage);
+ sampleView.canvas.setBackgroundImage(entry.image);
+ sampleView.canvas.redraw();
+ }
+
+ @Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
context = (Context) newInput;
}
@@ -114,6 +207,7 @@
class Entry {
String name;
Object obj;
+ Image image;
Entry(String name, Object obj) {
this.name = name;
@@ -140,6 +234,16 @@
final int value = context.serverState.enableDisables.valueAt(i);
children.add(GLEnum.valueOf(key).name() + " = " + value);
}
+ } else if (entry.obj == context.serverState.integers) {
+ for (int i = 0; i < context.serverState.integers.size(); i++) {
+ final int key = context.serverState.integers.keyAt(i);
+ final Message val = context.serverState.integers.valueAt(i);
+ if (val != null)
+ children.add(GLEnum.valueOf(key).name() + " : " +
+ MessageFormatter.Format(val));
+ else
+ children.add(GLEnum.valueOf(key).name() + " : default");
+ }
} else if (entry.obj == context.serverState.lastSetter) {
for (int i = 0; i < context.serverState.lastSetter.size(); i++) {
final int key = context.serverState.lastSetter.keyAt(i);
@@ -151,11 +255,11 @@
+ MessageFormatter.Format(msg));
}
} else if (entry.obj instanceof SparseArray) {
- SparseArray sa = (SparseArray) entry.obj;
+ SparseArray<?> sa = (SparseArray<?>) entry.obj;
for (int i = 0; i < sa.size(); i++)
- children.add(new Entry(entry.name + "[" + sa.keyAt(i) + "]", sa.valueAt(i)));
+ children.add(new Entry("[" + sa.keyAt(i) + "]", sa.valueAt(i)));
} else if (entry.obj instanceof Map) {
- Set set = ((Map) entry.obj).entrySet();
+ Set<?> set = ((Map<?, ?>) entry.obj).entrySet();
for (Object o : set) {
Map.Entry e = (Map.Entry) o;
children.add(new Entry(e.getKey().toString(), e.getValue()));
@@ -163,15 +267,14 @@
} else if (entry.obj instanceof SparseIntArray) {
SparseIntArray sa = (SparseIntArray) entry.obj;
for (int i = 0; i < sa.size(); i++)
- children.add(entry.name + "[" + sa.keyAt(i) + "] = " + sa.valueAt(i));
+ children.add("[" + sa.keyAt(i) + "] = " + sa.valueAt(i));
} else if (entry.obj instanceof Collection) {
- Collection collection = (Collection) entry.obj;
+ Collection<?> collection = (Collection<?>) entry.obj;
for (Object o : collection)
- children.add(new Entry(entry.name, o));
+ children.add(new Entry("[?]", o));
} else if (entry.obj.getClass().isArray()) {
- Object[] list = (Object[]) entry.obj;
- for (Object o : list)
- children.add(new Entry(entry.name, o));
+ for (int i = 0; i < Array.getLength(entry.obj); i++)
+ children.add(new Entry("[" + i + "]", Array.get(entry.obj, i)));
} else {
Field[] fields = entry.obj.getClass().getFields();
for (Field f : fields) {
@@ -196,26 +299,46 @@
public boolean hasChildren(Object element) {
if (element == null)
return false;
- if (element.getClass().isPrimitive())
+ if (!(element instanceof Entry))
return false;
- if (element.getClass().equals(String.class))
+ Object obj = ((Entry) element).obj;
+ if (obj == null)
return false;
- if (element instanceof Entry) {
- Entry entry = (Entry) element;
- if (entry.obj != null) {
- if (entry.obj instanceof SparseArray)
- return ((SparseArray) entry.obj).size() > 0;
- else if (entry.obj instanceof SparseIntArray)
- return ((SparseIntArray) entry.obj).size() > 0;
- else if (entry.obj instanceof Collection)
- return ((Collection) entry.obj).size() > 0;
- else if (entry.obj instanceof Map)
- return ((Map) entry.obj).size() > 0;
- else if (entry.obj.getClass().isArray())
- return ((Object[]) entry.obj).length > 0;
- return entry.obj.getClass().getFields().length > 0;
- }
- }
+ if (obj instanceof SparseArray)
+ return ((SparseArray<?>) obj).size() > 0;
+ else if (obj instanceof SparseIntArray)
+ return ((SparseIntArray) obj).size() > 0;
+ else if (obj instanceof Collection)
+ return ((Collection<?>) obj).size() > 0;
+ else if (obj instanceof Map)
+ return ((Map<?, ?>) obj).size() > 0;
+ else if (obj.getClass().isArray())
+ return Array.getLength(obj) > 0;
+ else if (obj instanceof Message)
+ return false;
+ else if (IsPrimitive(obj))
+ return false;
+ else if (obj.getClass().equals(String.class))
+ return false;
+ else if (obj.getClass().equals(Message.class))
+ return false;
+ else if (obj instanceof GLEnum)
+ return false;
+ return obj.getClass().getFields().length > 0;
+ }
+
+ static boolean IsPrimitive(final Object obj) {
+ final Class<? extends Object> c = obj.getClass();
+ if (c.isPrimitive())
+ return true;
+ if (c == Integer.class)
+ return true;
+ if (c == Boolean.class)
+ return true;
+ if (c == Float.class)
+ return true;
+ if (c == Short.class)
+ return true;
return false;
}
}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerShader.java b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerShader.java
index 4915921..cf70993 100644
--- a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerShader.java
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerShader.java
@@ -23,7 +23,7 @@
class GLShader implements Cloneable {
public final int name;
- final GLServerShader context; // the context this was created in
+ GLServerShader context; // the context this was created in
public final GLEnum type;
public boolean delete;
public ArrayList<Integer> programs = new ArrayList<Integer>();
@@ -35,12 +35,12 @@
this.type = type;
}
- @Override
- // deep copy except for context, which is set afterwards
- public Object clone() {
+ /** deep copy */
+ public GLShader clone(final GLServerShader copyContext) {
try {
GLShader shader = (GLShader) super.clone();
shader.programs = (ArrayList<Integer>) programs.clone();
+ shader.context = copyContext;
return shader;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
@@ -52,7 +52,7 @@
class GLProgram implements Cloneable {
public final int name;
- final GLServerShader context; // the context this was created in
+ GLServerShader context; // the context this was created in
public boolean delete;
public int vert, frag;
@@ -61,11 +61,12 @@
this.context = context;
}
- @Override
- // deep copy except for context, which is set afterwards
- public Object clone() {
+ /** deep copy */
+ public GLProgram clone(final GLServerShader copyContext) {
try {
- return super.clone();
+ GLProgram copy = (GLProgram) super.clone();
+ copy.context = copyContext;
+ return copy;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
assert false;
@@ -85,22 +86,22 @@
this.context = context;
}
- @Override
- // deep copy except for context, which is set afterwards
- public Object clone() {
+ /** deep copy */
+ public GLServerShader clone(final Context copyContext) {
try {
GLServerShader copy = (GLServerShader) super.clone();
+ copy.context = copyContext;
copy.shaders = new SparseArray<GLShader>(shaders.size());
for (int i = 0; i < shaders.size(); i++)
- copy.shaders.append(shaders.keyAt(i), (GLShader) shaders.valueAt(i).clone());
+ copy.shaders.append(shaders.keyAt(i), shaders.valueAt(i).clone(copy));
copy.programs = new SparseArray<GLProgram>(programs.size());
for (int i = 0; i < programs.size(); i++)
- copy.programs.append(programs.keyAt(i), (GLProgram) programs.valueAt(i).clone());
+ copy.programs.append(programs.keyAt(i), programs.valueAt(i).clone(copy));
if (current != null)
- copy.current = (GLProgram) current.clone();
+ copy.current = copy.programs.get(current.name);
return copy;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
@@ -109,38 +110,38 @@
}
}
- // returns instance if processed
- public GLServerShader ProcessMessage(final Message msg) {
+ /** returns true if processed */
+ public boolean ProcessMessage(final Message msg) {
boolean oldUiUpdate = uiUpdate;
uiUpdate = true;
switch (msg.getFunction()) {
case glAttachShader:
glAttachShader(msg);
- return this;
+ return true;
case glCreateProgram:
glCreateProgram(msg);
- return this;
+ return true;
case glCreateShader:
glCreateShader(msg);
- return this;
+ return true;
case glDeleteProgram:
glDeleteProgram(msg);
- return this;
+ return true;
case glDeleteShader:
glDeleteShader(msg);
- return this;
+ return true;
case glDetachShader:
glDetachShader(msg);
- return this;
+ return true;
case glShaderSource:
glShaderSource(msg);
- return this;
+ return true;
case glUseProgram:
glUseProgram(msg);
- return this;
+ return true;
default:
uiUpdate = oldUiUpdate;
- return null;
+ return false;
}
}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerState.java b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerState.java
index b79ef37..adab930 100644
--- a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerState.java
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerState.java
@@ -41,7 +41,12 @@
final Context context;
public GLStencilState front = new GLStencilState(), back = new GLStencilState();
public SparseIntArray enableDisables;
- public SparseArray<Message> lastSetter; // keyed by Function.getNumber()
+
+ /** integer states set via a GL function and GLEnum; keyed by GLEnum.value */
+ public SparseArray<Message> integers;
+
+ /** states set only via a GL function; keyed by Function.getNumber() */
+ public SparseArray<Message> lastSetter;
GLServerState(final Context context) {
this.context = context;
@@ -62,36 +67,61 @@
lastSetter.put(Function.glBlendEquationSeparate.getNumber(), null);
// glBlendFunc overwrites glBlendFuncSeparate
lastSetter.put(Function.glBlendFuncSeparate.getNumber(), null);
+ lastSetter.put(Function.glClearColor.getNumber(), null);
+ lastSetter.put(Function.glClearDepthf.getNumber(), null);
+ lastSetter.put(Function.glClearStencil.getNumber(), null);
lastSetter.put(Function.glColorMask.getNumber(), null);
+ lastSetter.put(Function.glCullFace.getNumber(), null);
lastSetter.put(Function.glDepthMask.getNumber(), null);
lastSetter.put(Function.glDepthFunc.getNumber(), null);
+ lastSetter.put(Function.glDepthRangef.getNumber(), null);
+ lastSetter.put(Function.glFrontFace.getNumber(), null);
+ lastSetter.put(Function.glLineWidth.getNumber(), null);
+ lastSetter.put(Function.glPolygonOffset.getNumber(), null);
+ lastSetter.put(Function.glSampleCoverage.getNumber(), null);
lastSetter.put(Function.glScissor.getNumber(), null);
lastSetter.put(Function.glStencilMaskSeparate.getNumber(), null);
+ lastSetter.put(Function.glViewport.getNumber(), null);
+
+ integers = new SparseArray<Message>();
+ integers.put(GLEnum.GL_PACK_ALIGNMENT.value, null);
+ integers.put(GLEnum.GL_UNPACK_ALIGNMENT.value, null);
}
- // returns instance if processed (returns new instance if changed)
- public GLServerState ProcessMessage(final Message msg) {
+ /** returns true if processed */
+ public boolean ProcessMessage(final Message msg) {
switch (msg.getFunction()) {
case glBlendColor:
- return Setter(msg);
case glBlendEquation:
- return Setter(msg);
case glBlendEquationSeparate:
- return Setter(msg);
case glBlendFunc:
- return Setter(msg);
case glBlendFuncSeparate:
- return Setter(msg);
+ case glClearColor:
+ case glClearDepthf:
+ case glClearStencil:
case glColorMask:
- return Setter(msg);
+ case glCullFace:
case glDepthMask:
- return Setter(msg);
case glDepthFunc:
+ case glDepthRangef:
return Setter(msg);
case glDisable:
return EnableDisable(false, msg);
case glEnable:
return EnableDisable(true, msg);
+ case glFrontFace:
+ case glLineWidth:
+ return Setter(msg);
+ case glPixelStorei:
+ if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_PACK_ALIGNMENT)
+ integers.put(msg.getArg0(), msg);
+ else if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_UNPACK_ALIGNMENT)
+ integers.put(msg.getArg0(), msg);
+ else
+ assert false;
+ return true;
+ case glPolygonOffset:
+ case glSampleCoverage:
case glScissor:
return Setter(msg);
case glStencilFunc: {
@@ -104,7 +134,6 @@
case glStencilFuncSeparate:
return glStencilFuncSeparate(msg);
case glStencilMask:
- return Setter(msg);
case glStencilMaskSeparate:
return Setter(msg);
case glStencilOp: {
@@ -117,43 +146,42 @@
}
case glStencilOpSeparate:
return glStencilOpSeparate(msg);
+ case glViewport:
+ return Setter(msg);
default:
- return null;
+ return false;
}
}
- GLServerState Setter(final Message msg) {
- GLServerState newState = (GLServerState) this.clone();
- // TODO: compare for change
+ boolean Setter(final Message msg) {
switch (msg.getFunction()) {
case glBlendFunc:
- newState.lastSetter.put(Function.glBlendFuncSeparate.getNumber(), msg);
+ lastSetter.put(Function.glBlendFuncSeparate.getNumber(), msg);
break;
case glBlendEquation:
- newState.lastSetter.put(Function.glBlendEquationSeparate.getNumber(), msg);
+ lastSetter.put(Function.glBlendEquationSeparate.getNumber(), msg);
break;
case glStencilMask:
- newState.lastSetter.put(Function.glStencilMaskSeparate.getNumber(), msg);
+ lastSetter.put(Function.glStencilMaskSeparate.getNumber(), msg);
break;
default:
- newState.lastSetter.put(msg.getFunction().getNumber(), msg);
+ lastSetter.put(msg.getFunction().getNumber(), msg);
break;
}
- return newState;
+ return true;
}
- GLServerState EnableDisable(boolean enable, final Message msg) {
+ boolean EnableDisable(boolean enable, final Message msg) {
int index = enableDisables.indexOfKey(msg.getArg0());
assert index >= 0;
if ((enableDisables.valueAt(index) != 0) == enable)
- return this;
- GLServerState newState0 = (GLServerState) this.clone();
- newState0.enableDisables.put(msg.getArg0(), enable ? 1 : 0);
- return newState0;
+ return true; // TODO: redundant
+ enableDisables.put(msg.getArg0(), enable ? 1 : 0);
+ return true;
}
// void StencilFuncSeparate( enum face, enum func, int ref, uint mask )
- GLServerState glStencilFuncSeparate(final Message msg) {
+ boolean glStencilFuncSeparate(final Message msg) {
GLEnum ff = front.func, bf = back.func;
int fr = front.ref, br = back.ref;
int fm = front.mask, bm = back.mask;
@@ -170,19 +198,18 @@
}
if (ff == front.func && fr == front.ref && fm == front.mask)
if (bf == back.func && br == back.ref && bm == back.mask)
- return this;
- GLServerState newState = (GLServerState) this.clone();
- newState.front.func = ff;
- newState.front.ref = fr;
- newState.front.mask = fm;
- newState.back.func = bf;
- newState.back.ref = br;
- newState.back.mask = bm;
- return newState;
+ return true; // TODO: redundant
+ front.func = ff;
+ front.ref = fr;
+ front.mask = fm;
+ back.func = bf;
+ back.ref = br;
+ back.mask = bm;
+ return true;
}
// void StencilOpSeparate( enum face, enum sfail, enum dpfail, enum dppass )
- GLServerState glStencilOpSeparate(final Message msg) {
+ boolean glStencilOpSeparate(final Message msg) {
GLEnum fsf = front.sf, fdf = front.df, fdp = front.dp;
GLEnum bsf = back.sf, bdf = back.df, bdp = back.dp;
final GLEnum face = GLEnum.valueOf(msg.getArg0());
@@ -198,39 +225,41 @@
}
if (fsf == front.sf && fdf == front.df && fdp == front.dp)
if (bsf == back.sf && bdf == back.df && bdp == back.dp)
- return this;
- GLServerState newState = (GLServerState) this.clone();
- newState.front.sf = fsf;
- newState.front.df = fdf;
- newState.front.dp = fdp;
- newState.back.sf = bsf;
- newState.back.df = bdf;
- newState.back.dp = bdp;
- return newState;
+ return true; // TODO: redundant
+ front.sf = fsf;
+ front.df = fdf;
+ front.dp = fdp;
+ back.sf = bsf;
+ back.df = bdf;
+ back.dp = bdp;
+ return true;
}
+ /** deep copy */
@Override
- public Object clone() {
+ public GLServerState clone() {
try {
GLServerState newState = (GLServerState) super.clone();
newState.front = (GLStencilState) front.clone();
newState.back = (GLStencilState) back.clone();
newState.enableDisables = new SparseIntArray(enableDisables.size());
- for (int i = 0; i < enableDisables.size(); i++) {
- final int key = enableDisables.keyAt(i);
- newState.enableDisables.append(key, enableDisables.valueAt(i));
- }
+ for (int i = 0; i < enableDisables.size(); i++)
+ newState.enableDisables.append(enableDisables.keyAt(i),
+ enableDisables.valueAt(i));
+
+ newState.integers = new SparseArray<Message>(integers.size());
+ for (int i = 0; i < integers.size(); i++)
+ newState.integers.append(integers.keyAt(i), integers.valueAt(i));
newState.lastSetter = new SparseArray<Message>(lastSetter.size());
- for (int i = 0; i < lastSetter.size(); i++) {
- final int key = lastSetter.keyAt(i);
- newState.lastSetter.append(key, lastSetter.valueAt(i));
- }
+ for (int i = 0; i < lastSetter.size(); i++)
+ newState.lastSetter.append(lastSetter.keyAt(i), lastSetter.valueAt(i));
return newState;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
+ assert false;
return null;
}
}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerTexture.java b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerTexture.java
new file mode 100644
index 0000000..d246e3f
--- /dev/null
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerTexture.java
@@ -0,0 +1,232 @@
+/*
+ ** Copyright 2011, 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 com.android.glesv2debugger;
+
+import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.sdklib.util.SparseArray;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+class GLTexture implements Cloneable {
+ public final int name;
+ public final GLEnum target;
+ public ArrayList<Message> contentChanges = new ArrayList<Message>();
+ public GLEnum wrapS = GLEnum.GL_REPEAT, wrapT = GLEnum.GL_REPEAT;
+ public GLEnum min = GLEnum.GL_NEAREST_MIPMAP_LINEAR;
+ public GLEnum mag = GLEnum.GL_LINEAR;
+ public GLEnum format;
+ public int width, height;
+
+ GLTexture(final int name, final GLEnum target) {
+ this.name = name;
+ this.target = target;
+ }
+
+ @Override
+ public GLTexture clone() {
+ try {
+ GLTexture copy = (GLTexture) super.clone();
+ copy.contentChanges = (ArrayList<Message>) contentChanges.clone();
+ return copy;
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ assert false;
+ return null;
+ }
+ }
+
+ boolean ProcessMessage(final Message msg) {
+ switch (msg.getFunction()) {
+ case glCompressedTexImage2D:
+ case glCopyTexImage2D:
+ case glTexImage2D:
+ if (msg.getArg1() == 0) { // level 0
+ format = GLEnum.valueOf(msg.getArg2());
+ width = msg.getArg3();
+ height = msg.getArg4();
+ }
+ //$FALL-THROUGH$
+ case glCompressedTexSubImage2D:
+ case glCopyTexSubImage2D:
+ case glTexSubImage2D:
+ case glGenerateMipmap:
+ contentChanges.add(msg);
+ break;
+ default:
+ assert false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return target.name() + " " + contentChanges.size() + " content change(s)";
+ }
+}
+
+public class GLServerTexture implements Cloneable {
+ Context context;
+
+ public GLEnum activeTexture = GLEnum.GL_TEXTURE0;
+ public int[] tmu2D = new int[32];
+ public int[] tmuCube = new int[32];
+ public SparseArray<GLTexture> textures = new SparseArray<GLTexture>();
+ public GLTexture tex2D = null, texCube = null;
+
+ GLServerTexture(final Context context) {
+ this.context = context;
+ textures.append(0, null);
+ }
+
+ public GLServerTexture clone(final Context copyContext) {
+ try {
+ GLServerTexture copy = (GLServerTexture) super.clone();
+ copy.context = copyContext;
+
+ copy.tmu2D = tmu2D.clone();
+ copy.tmuCube = tmuCube.clone();
+
+ copy.textures = new SparseArray<GLTexture>(textures.size());
+ for (int i = 0; i < textures.size(); i++)
+ if (textures.valueAt(i) != null)
+ copy.textures.append(textures.keyAt(i), textures.valueAt(i).clone());
+ else
+ copy.textures.append(textures.keyAt(i), null);
+
+ if (tex2D != null)
+ copy.tex2D = copy.textures.get(tex2D.name);
+ if (texCube != null)
+ copy.texCube = copy.textures.get(texCube.name);
+
+ return copy;
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ assert false;
+ return null;
+ }
+ }
+
+ public boolean ProcessMessage(final Message msg) {
+ switch (msg.getFunction()) {
+ case glActiveTexture:
+ activeTexture = GLEnum.valueOf(msg.getArg0());
+ return true;
+ case glBindTexture:
+ return BindTexture(msg.getArg0(), msg.getArg1());
+ case glCompressedTexImage2D:
+ case glCompressedTexSubImage2D:
+ case glCopyTexImage2D:
+ case glCopyTexSubImage2D:
+ case glTexImage2D:
+ case glTexSubImage2D:
+ switch (GLEnum.valueOf(msg.getArg0())) {
+ case GL_TEXTURE_2D:
+ if (tex2D != null)
+ return tex2D.ProcessMessage(msg);
+ return true;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES:
+ if (texCube != null)
+ return texCube.ProcessMessage(msg);
+ return true;
+ default:
+ return true;
+ }
+ case glDeleteTextures: {
+ final ByteBuffer names = msg.getData().asReadOnlyByteBuffer();
+ names.order(SampleView.targetByteOrder);
+ for (int i = 0; i < msg.getArg0(); i++) {
+ final int name = names.getInt();
+ if (tex2D != null && tex2D.name == name)
+ BindTexture(GLEnum.GL_TEXTURE_2D.value, 0);
+ if (texCube != null && texCube.name == name)
+ BindTexture(GLEnum.GL_TEXTURE_CUBE_MAP_OES.value, 0);
+ if (name != 0)
+ textures.remove(name);
+ }
+ return true;
+ }
+ case glGenerateMipmap:
+ if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_TEXTURE_2D && tex2D != null)
+ return tex2D.ProcessMessage(msg);
+ else if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_TEXTURE_CUBE_MAP_OES
+ && texCube != null)
+ return texCube.ProcessMessage(msg);
+ return true;
+ case glTexParameteri:
+ return TexParameter(msg.getArg0(), msg.getArg1(), msg.getArg2());
+ case glTexParameterf:
+ return TexParameter(msg.getArg0(), msg.getArg1(),
+ (int) Float.intBitsToFloat(msg.getArg2()));
+ default:
+ return false;
+ }
+ }
+
+ boolean BindTexture(final int target, final int name) {
+ final int index = activeTexture.value - GLEnum.GL_TEXTURE0.value;
+ if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_2D) {
+ tex2D = textures.get(name);
+ if (name != 0 && tex2D == null)
+ textures.put(name, tex2D = new GLTexture(name,
+ GLEnum.GL_TEXTURE_2D));
+ if (index >= 0 && index < tmu2D.length)
+ tmu2D[index] = name;
+ } else if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_CUBE_MAP_OES) {
+ texCube = textures.get(name);
+ if (name != 0 && texCube == null)
+ textures.put(name, texCube = new GLTexture(name,
+ GLEnum.GL_TEXTURE_CUBE_MAP_OES));
+ if (index >= 0 && index < tmu2D.length)
+ tmu2D[index] = name;
+ } else
+ assert false;
+ return true;
+ }
+
+ boolean TexParameter(final int target, final int pname, final int param) {
+ GLTexture tex = null;
+ if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_2D)
+ tex = tex2D;
+ else if (GLEnum.valueOf(target) == GLEnum.GL_TEXTURE_CUBE_MAP_OES)
+ tex = texCube;
+ if (tex == null)
+ return true;
+ final GLEnum p = GLEnum.valueOf(param);
+ switch (GLEnum.valueOf(pname)) {
+ case GL_TEXTURE_WRAP_S:
+ tex.wrapS = p;
+ return true;
+ case GL_TEXTURE_WRAP_T:
+ tex.wrapT = p;
+ return true;
+ case GL_TEXTURE_MIN_FILTER:
+ tex.min = p;
+ return true;
+ case GL_TEXTURE_MAG_FILTER:
+ tex.mag = p;
+ return true;
+ default:
+ return true;
+ }
+ }
+}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerVertex.java b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerVertex.java
index 4a23bbb..a9b5ab8 100644
--- a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerVertex.java
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerVertex.java
@@ -17,17 +17,40 @@
package com.android.glesv2debugger;
import com.android.glesv2debugger.DebuggerMessage.Message;
+import com.android.sdklib.util.SparseArray;
import java.nio.ByteBuffer;
-import java.util.HashMap;
-class GLBuffer {
+class GLBuffer implements Cloneable {
+ public final int name;
public GLEnum usage;
public GLEnum target;
public ByteBuffer data;
+
+ public GLBuffer(final int name) {
+ this.name = name;
+ }
+
+ /** deep copy */
+ @Override
+ public GLBuffer clone() {
+ try {
+ GLBuffer copy = (GLBuffer) super.clone();
+ if (data != null) {
+ copy.data = ByteBuffer.allocate(data.capacity());
+ data.position(0);
+ copy.data.put(data);
+ }
+ return copy;
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ assert false;
+ return null;
+ }
+ }
}
-class GLAttribPointer {
+class GLAttribPointer implements Cloneable {
public int size; // number of values per vertex
public GLEnum type; // data type
public int stride; // bytes
@@ -35,19 +58,32 @@
public GLBuffer buffer;
public boolean normalized;
public boolean enabled;
+
+ /** deep copy, re-maps buffer into copyBuffers */
+ public GLAttribPointer clone(SparseArray<GLBuffer> copyBuffers) {
+ try {
+ GLAttribPointer copy = (GLAttribPointer) super.clone();
+ if (buffer != null)
+ copy.buffer = copyBuffers.get(buffer.name);
+ return copy;
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ assert false;
+ return null;
+ }
+ }
}
-public class GLServerVertex {
-
- public HashMap<Integer, GLBuffer> buffers;
+public class GLServerVertex implements Cloneable {
+ public SparseArray<GLBuffer> buffers = new SparseArray<GLBuffer>();
public GLBuffer attribBuffer, indexBuffer; // current binding
public GLAttribPointer attribPointers[];
public float defaultAttribs[][];
int maxAttrib;
public GLServerVertex() {
- buffers = new HashMap<Integer, GLBuffer>();
- buffers.put(0, null);
+ buffers.append(0, null);
+ // TODO: get MAX_VERTEX_ATTRIBS from server
attribPointers = new GLAttribPointer[16];
for (int i = 0; i < attribPointers.length; i++)
attribPointers[i] = new GLAttribPointer();
@@ -60,70 +96,102 @@
}
}
+ /** deep copy */
+ @Override
+ public GLServerVertex clone() {
+ try {
+ GLServerVertex copy = (GLServerVertex) super.clone();
+
+ copy.buffers = new SparseArray<GLBuffer>(buffers.size());
+ for (int i = 0; i < buffers.size(); i++)
+ if (buffers.valueAt(i) != null)
+ copy.buffers.append(buffers.keyAt(i), buffers.valueAt(i).clone());
+ else
+ copy.buffers.append(buffers.keyAt(i), null);
+
+ if (attribBuffer != null)
+ copy.attribBuffer = copy.buffers.get(attribBuffer.name);
+ if (indexBuffer != null)
+ copy.indexBuffer = copy.buffers.get(indexBuffer.name);
+
+ copy.attribPointers = new GLAttribPointer[attribPointers.length];
+ for (int i = 0; i < attribPointers.length; i++)
+ copy.attribPointers[i] = attribPointers[i].clone(copy.buffers);
+
+ copy.defaultAttribs = defaultAttribs.clone();
+
+ return copy;
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ assert false;
+ return null;
+ }
+ }
+
Message processed = null; // return; glDrawArrays/Elements with fetched data
- // returns instance if processed TODO: return new instance if changed
- public GLServerVertex Process(final Message msg) {
+ /** returns true if processed */
+ public boolean Process(final Message msg) {
processed = null;
switch (msg.getFunction()) {
case glBindBuffer:
glBindBuffer(msg);
- return this;
+ return true;
case glBufferData:
glBufferData(msg);
- return this;
+ return true;
case glBufferSubData:
glBufferSubData(msg);
- return this;
+ return true;
case glDeleteBuffers:
glDeleteBuffers(msg);
- return this;
+ return true;
case glDrawArrays:
if (msg.hasArg7())
processed = glDrawArrays(msg);
- return this;
+ return true;
case glDrawElements:
if (msg.hasArg7())
processed = glDrawElements(msg);
- return this;
+ return true;
case glDisableVertexAttribArray:
glDisableVertexAttribArray(msg);
- return this;
+ return true;
case glEnableVertexAttribArray:
glEnableVertexAttribArray(msg);
- return this;
+ return true;
case glGenBuffers:
glGenBuffers(msg);
- return this;
+ return true;
case glVertexAttribPointer:
glVertexAttribPointer(msg);
- return this;
+ return true;
case glVertexAttrib1f:
glVertexAttrib1f(msg);
- return this;
+ return true;
case glVertexAttrib1fv:
glVertexAttrib1fv(msg);
- return this;
+ return true;
case glVertexAttrib2f:
glVertexAttrib2f(msg);
- return this;
+ return true;
case glVertexAttrib2fv:
glVertexAttrib2fv(msg);
- return this;
+ return true;
case glVertexAttrib3f:
glVertexAttrib3f(msg);
- return this;
+ return true;
case glVertexAttrib3fv:
glVertexAttrib3fv(msg);
- return this;
+ return true;
case glVertexAttrib4f:
glVertexAttrib4f(msg);
- return this;
+ return true;
case glVertexAttrib4fv:
glVertexAttrib4fv(msg);
- return this;
+ return true;
default:
- return null;
+ return false;
}
}
@@ -181,9 +249,10 @@
public void glDeleteBuffers(Message msg) {
final int n = msg.getArg0();
final ByteBuffer names = msg.getData().asReadOnlyByteBuffer();
+ names.order(SampleView.targetByteOrder);
for (int i = 0; i < n; i++) {
- int name = Integer.reverseBytes(names.getInt());
- GLBuffer buffer = buffers.get(name);
+ final int name = names.getInt();
+ final GLBuffer buffer = buffers.get(name);
for (int j = 0; j < attribPointers.length; j++)
if (attribPointers[j].buffer == buffer) {
attribPointers[j].buffer = null;
@@ -204,27 +273,27 @@
float FetchConvert(final ByteBuffer src, final GLEnum type, final boolean normalized) {
if (GLEnum.GL_FLOAT == type)
- return Float.intBitsToFloat(Integer.reverseBytes(src.getInt()));
+ return Float.intBitsToFloat(src.getInt());
else if (GLEnum.GL_UNSIGNED_INT == type)
if (normalized)
- return (Integer.reverseBytes(src.getInt()) & 0xffffffffL) / (2e32f - 1);
+ return (src.getInt() & 0xffffffffL) / (2e32f - 1);
else
- return Integer.reverseBytes(src.getInt()) & 0xffffffffL;
+ return src.getInt() & 0xffffffffL;
else if (GLEnum.GL_INT == type)
if (normalized)
- return (Integer.reverseBytes(src.getInt()) * 2 + 1) / (2e32f - 1);
+ return (src.getInt() * 2 + 1) / (2e32f - 1);
else
- return Integer.reverseBytes(src.getInt());
+ return src.getInt();
else if (GLEnum.GL_UNSIGNED_SHORT == type)
if (normalized)
- return (Short.reverseBytes(src.getShort()) & 0xffff) / (2e16f - 1);
+ return (src.getShort() & 0xffff) / (2e16f - 1);
else
- return Short.reverseBytes(src.getShort()) & 0xffff;
+ return src.getShort() & 0xffff;
else if (GLEnum.GL_SHORT == type)
if (normalized)
- return (Short.reverseBytes(src.getShort()) * 2 + 1) / (2e16f - 1);
+ return (src.getShort() * 2 + 1) / (2e16f - 1);
else
- return Short.reverseBytes(src.getShort());
+ return src.getShort();
else if (GLEnum.GL_UNSIGNED_BYTE == type)
if (normalized)
return (src.get() & 0xff) / (2e8f - 1);
@@ -237,9 +306,9 @@
return src.get();
else if (GLEnum.GL_FIXED == type)
if (normalized)
- return (Integer.reverseBytes(src.getInt()) * 2 + 1) / (2e32f - 1);
+ return (src.getInt() * 2 + 1) / (2e32f - 1);
else
- return Integer.reverseBytes(src.getInt()) / (2e16f);
+ return src.getInt() / (2e16f);
else
assert false;
return 0;
@@ -276,7 +345,10 @@
final ByteBuffer buffer = ByteBuffer.allocate(4 * 4 * maxAttrib * count);
ByteBuffer arrays = null;
if (msg.hasData()) // server sends user pointer attribs
+ {
arrays = msg.getData().asReadOnlyByteBuffer();
+ arrays.order(SampleView.targetByteOrder);
+ }
for (int i = first; i < first + count; i++)
Fetch(i, arrays, buffer);
assert null == arrays || arrays.remaining() == 0;
@@ -294,16 +366,20 @@
final ByteBuffer buffer = ByteBuffer.allocate(4 * 4 * maxAttrib * count);
ByteBuffer arrays = null, index = null;
if (msg.hasData()) // server sends user pointer attribs
+ {
arrays = msg.getData().asReadOnlyByteBuffer();
+ arrays.order(SampleView.targetByteOrder);
+ }
if (null == indexBuffer)
index = arrays; // server also interleaves user pointer indices
else {
index = indexBuffer.data;
+ index.order(SampleView.targetByteOrder);
index.position(msg.getArg3());
}
if (GLEnum.GL_UNSIGNED_SHORT == type)
for (int i = 0; i < count; i++)
- Fetch(Short.reverseBytes(index.getShort()) & 0xffff, arrays, buffer);
+ Fetch(index.getShort() & 0xffff, arrays, buffer);
else if (GLEnum.GL_UNSIGNED_BYTE == type)
for (int i = 0; i < count; i++)
Fetch(index.get() & 0xff, arrays, buffer);
@@ -324,10 +400,12 @@
public void glGenBuffers(Message msg) {
final int n = msg.getArg0();
final ByteBuffer buffer = msg.getData().asReadOnlyByteBuffer();
+ buffer.order(SampleView.targetByteOrder);
for (int i = 0; i < n; i++) {
- int name = Integer.reverseBytes(buffer.getInt());
- if (!buffers.containsKey(name))
- buffers.put(name, new GLBuffer());
+ final int name = buffer.getInt();
+ final int index = buffers.indexOfKey(name);
+ if (index < 0)
+ buffers.append(name, new GLBuffer(name));
}
}
@@ -347,53 +425,56 @@
// void glVertexAttrib1f(GLuint indx, GLfloat x)
public void glVertexAttrib1f(Message msg) {
- glVertexAttrib4f(msg.getArg0(), Float.intBitsToFloat(Integer.reverseBytes(msg.getArg1())),
+ glVertexAttrib4f(msg.getArg0(), Float.intBitsToFloat(msg.getArg1()),
0, 0, 1);
}
// void glVertexAttrib1fv(GLuint indx, const GLfloat* values)
public void glVertexAttrib1fv(Message msg) {
final ByteBuffer values = msg.getData().asReadOnlyByteBuffer();
+ values.order(SampleView.targetByteOrder);
glVertexAttrib4f(msg.getArg0(),
- Float.intBitsToFloat(Integer.reverseBytes(values.getInt())),
+ Float.intBitsToFloat(values.getInt()),
0, 0, 1);
}
// void glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
public void glVertexAttrib2f(Message msg) {
- glVertexAttrib4f(msg.getArg0(), Float.intBitsToFloat(Integer.reverseBytes(msg.getArg1())),
- Float.intBitsToFloat(Integer.reverseBytes(msg.getArg2())), 0, 1);
+ glVertexAttrib4f(msg.getArg0(), Float.intBitsToFloat(msg.getArg1()),
+ Float.intBitsToFloat(msg.getArg2()), 0, 1);
}
// void glVertexAttrib2fv(GLuint indx, const GLfloat* values)
public void glVertexAttrib2fv(Message msg) {
final ByteBuffer values = msg.getData().asReadOnlyByteBuffer();
+ values.order(SampleView.targetByteOrder);
glVertexAttrib4f(msg.getArg0(),
- Float.intBitsToFloat(Integer.reverseBytes(values.getInt())),
- Float.intBitsToFloat(Integer.reverseBytes(values.getInt())), 0, 1);
+ Float.intBitsToFloat(values.getInt()),
+ Float.intBitsToFloat(values.getInt()), 0, 1);
}
// void glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
public void glVertexAttrib3f(Message msg) {
- glVertexAttrib4f(msg.getArg0(), Float.intBitsToFloat(Integer.reverseBytes(msg.getArg1())),
- Float.intBitsToFloat(Integer.reverseBytes(msg.getArg2())),
- Float.intBitsToFloat(Integer.reverseBytes(msg.getArg3())), 1);
+ glVertexAttrib4f(msg.getArg0(), Float.intBitsToFloat(msg.getArg1()),
+ Float.intBitsToFloat(msg.getArg2()),
+ Float.intBitsToFloat(msg.getArg3()), 1);
}
// void glVertexAttrib3fv(GLuint indx, const GLfloat* values)
public void glVertexAttrib3fv(Message msg) {
final ByteBuffer values = msg.getData().asReadOnlyByteBuffer();
+ values.order(SampleView.targetByteOrder);
glVertexAttrib4f(msg.getArg0(),
- Float.intBitsToFloat(Integer.reverseBytes(values.getInt())),
- Float.intBitsToFloat(Integer.reverseBytes(values.getInt())),
- Float.intBitsToFloat(Integer.reverseBytes(values.getInt())), 1);
+ Float.intBitsToFloat(values.getInt()),
+ Float.intBitsToFloat(values.getInt()),
+ Float.intBitsToFloat(values.getInt()), 1);
}
public void glVertexAttrib4f(Message msg) {
- glVertexAttrib4f(msg.getArg0(), Float.intBitsToFloat(Integer.reverseBytes(msg.getArg1())),
- Float.intBitsToFloat(Integer.reverseBytes(msg.getArg2())),
- Float.intBitsToFloat(Integer.reverseBytes(msg.getArg3())),
- Float.intBitsToFloat(Integer.reverseBytes(msg.getArg4())));
+ glVertexAttrib4f(msg.getArg0(), Float.intBitsToFloat(msg.getArg1()),
+ Float.intBitsToFloat(msg.getArg2()),
+ Float.intBitsToFloat(msg.getArg3()),
+ Float.intBitsToFloat(msg.getArg4()));
}
void glVertexAttrib4f(int indx, float x, float y, float z, float w) {
@@ -406,10 +487,11 @@
// void glVertexAttrib4fv(GLuint indx, const GLfloat* values)
public void glVertexAttrib4fv(Message msg) {
final ByteBuffer values = msg.getData().asReadOnlyByteBuffer();
+ values.order(SampleView.targetByteOrder);
glVertexAttrib4f(msg.getArg0(),
- Float.intBitsToFloat(Integer.reverseBytes(values.getInt())),
- Float.intBitsToFloat(Integer.reverseBytes(values.getInt())),
- Float.intBitsToFloat(Integer.reverseBytes(values.getInt())),
- Float.intBitsToFloat(Integer.reverseBytes(values.getInt())));
+ Float.intBitsToFloat(values.getInt()),
+ Float.intBitsToFloat(values.getInt()),
+ Float.intBitsToFloat(values.getInt()),
+ Float.intBitsToFloat(values.getInt()));
}
}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/MessageData.java b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageData.java
index 16eee59..13965d3 100644
--- a/tools/glesv2debugger/src/com/android/glesv2debugger/MessageData.java
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageData.java
@@ -26,17 +26,20 @@
import org.eclipse.swt.graphics.ImageData;
public class MessageData {
- public final Message msg;
+ public final Message msg, oriMsg;
public Image image; // texture
public String shader; // shader source
public String text;
+ public String[] columns = new String[3];
public float[] data;
public int maxAttrib; // used for formatting data
public GLEnum dataType; // could be float, int; mainly for formatting use
Context context; // the context before this call
- public MessageData(final Device device, final Message msg, final Context context) {
+ public MessageData(final Device device, final Message msg, final Message oriMsg,
+ final Context context) {
this.msg = msg;
+ this.oriMsg = oriMsg;
this.context = context;
image = null;
shader = null;
@@ -46,21 +49,26 @@
ImageData imageData = null;
if (function != Message.Function.ACK)
assert msg.hasTime();
- builder.append(function);
+ builder.append(columns[0] = function.name());
while (builder.length() < 30)
builder.append(' ');
- builder.append(String.format("%.3f", msg.getTime()));
+ columns[1] = String.format("%.3f", msg.getTime());
if (msg.hasClock())
- builder.append(String.format(":%.3f", msg.getClock()));
- builder.append(String.format(" 0x%08X", msg.getContextId()));
+ columns[1] += String.format(":%.3f", msg.getClock());
+ builder.append(columns[1]);
+
builder.append(" ");
+ builder.append(String.format("0x%08X", msg.getContextId()));
+ builder.append(" ");
+ columns[2] = "";
if (msg.getType() == Type.BeforeCall) // incomplete call, client SKIPPED
- builder.append("[BeforeCall(AfterCall missing)] ");
+ columns[2] = "[BeforeCall(AfterCall missing)] ";
else if (msg.getType() == Type.AfterGeneratedCall)
- builder.append("[AfterGeneratedCall] ");
+ columns[2] = "[AfterGeneratedCall] ";
else
assert msg.getType() == Type.AfterCall;
- builder.append(MessageFormatter.Format(msg));
+ columns[2] += MessageFormatter.Format(msg);
+ builder.append(columns[2]);
switch (function) {
case glDrawArrays: // msg was modified by GLServerVertex
case glDrawElements:
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/SampleView.java b/tools/glesv2debugger/src/com/android/glesv2debugger/SampleView.java
index 87d97a4..9c2a28f 100644
--- a/tools/glesv2debugger/src/com/android/glesv2debugger/SampleView.java
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/SampleView.java
@@ -20,6 +20,7 @@
import com.android.glesv2debugger.DebuggerMessage.Message.Function;
import com.android.glesv2debugger.DebuggerMessage.Message.Prop;
import com.android.glesv2debugger.DebuggerMessage.Message.Type;
+import com.android.sdklib.util.SparseArray;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
@@ -28,27 +29,30 @@
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
@@ -56,11 +60,13 @@
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Slider;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IActionBars;
-import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
@@ -70,9 +76,7 @@
import java.io.PrintWriter;
import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
-import java.util.ArrayList;
import java.util.Calendar;
-import java.util.HashMap;
/**
* This sample class demonstrates how to plug-in a new workbench view. The view
@@ -89,13 +93,14 @@
* <p>
*/
-public class SampleView extends ViewPart implements Runnable {
+public class SampleView extends ViewPart implements Runnable, SelectionListener {
public static final ByteOrder targetByteOrder = ByteOrder.LITTLE_ENDIAN;
boolean running = false;
Thread thread;
- MessageQueue messageQueue;
- ViewContentProvider viewContentProvider;
+ MessageQueue messageQueue = new MessageQueue(this);
+ SparseArray<DebugContext> debugContexts = new SparseArray<DebugContext>();
+
/**
* The ID of the view as specified by the extension.
*/
@@ -104,54 +109,33 @@
TabFolder tabFolder;
TabItem tabItemText, tabItemImage, tabItemBreakpointOption;
TabItem tabItemShaderEditor, tabContextViewer;
- ListViewer viewer;
+ ListViewer viewer; // or TableViewer
+ Slider frameNum; // scale max cannot overlap min, so max is array size
TreeViewer contextViewer;
BreakpointOption breakpointOption;
ShaderEditor shaderEditor;
Canvas canvas;
Text text;
Action actionConnect; // connect / disconnect
- Action doubleClickAction;
+
Action actionAutoScroll;
Action actionFilter;
Action actionCapture;
Action actionPort;
+ Action actContext; // for toggling contexts
+ DebugContext current = null;
+
Point origin = new Point(0, 0); // for smooth scrolling canvas
String[] filters = null;
- public HashMap<Integer, Context> contexts = new HashMap<Integer, Context>();
- /*
- * The content provider class is responsible for providing objects to the
- * view. It can wrap existing objects in adapters or simply return objects
- * as-is. These objects may be sensitive to the current input of the view,
- * or ignore it and always show the same content (like Task List, for
- * example).
- */
-
- class ViewContentProvider implements IStructuredContentProvider {
- ArrayList<MessageData> entries = new ArrayList<MessageData>();
-
- public void add(final ArrayList<MessageData> msgs) {
- entries.addAll(msgs);
- viewer.getList().getDisplay().syncExec(new Runnable() {
- @Override
- public void run() {
- viewer.add(msgs.toArray());
- org.eclipse.swt.widgets.ScrollBar bar = viewer
- .getList().getVerticalBar();
- if (null != bar && actionAutoScroll.isChecked()) {
- bar.setSelection(bar.getMaximum());
- viewer.getList().setSelection(
- entries.size() - 1);
- // MessageDataSelected(entries.get(entries.size() - 1));
- }
- }
- });
- }
+ class ViewContentProvider extends LabelProvider implements IStructuredContentProvider,
+ ITableLabelProvider {
+ Frame frame = null;
@Override
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
+ frame = (Frame) newInput;
}
@Override
@@ -160,26 +144,36 @@
@Override
public Object[] getElements(Object parent) {
- return entries.toArray();
+ return frame.calls.toArray();
}
- }
- class ViewLabelProvider extends LabelProvider implements
- ILabelProvider {
@Override
public String getText(Object obj) {
MessageData msgData = (MessageData) obj;
- if (null == msgData)
- return obj.toString();
return msgData.text;
}
@Override
public Image getImage(Object obj) {
MessageData msgData = (MessageData) obj;
- if (null == msgData.image)
- return PlatformUI.getWorkbench().getSharedImages()
- .getImage(ISharedImages.IMG_OBJ_ELEMENT);
+ return msgData.image;
+ }
+
+ @Override
+ public String getColumnText(Object obj, int index) {
+ MessageData msgData = (MessageData) obj;
+ if (index >= msgData.columns.length)
+ return null;
+ return msgData.columns[index];
+ }
+
+ @Override
+ public Image getColumnImage(Object obj, int index) {
+ if (index > -1)
+ return null;
+ MessageData msgData = (MessageData) obj;
+ if (msgData.image == null)
+ return null;
return msgData.image;
}
}
@@ -207,12 +201,7 @@
}
}
- /**
- * The constructor.
- */
public SampleView() {
- messageQueue = new MessageQueue(this);
-
MessageParserEx messageParserEx = new MessageParserEx();
Message.Builder builder = Message.newBuilder();
messageParserEx.Parse(builder, "glUniform4fv(1,2,[0,1,2,3,4,5,6,7])");
@@ -221,18 +210,64 @@
"void glShaderSource(shader=4, count=1, string=\"dksjafhskjahourehghskjg\", length=0x0)");
}
- public void CreateView(Composite parent) {
- viewer = new ListViewer(parent);
+ public void CreateLeftPane(Composite parent) {
+ Composite composite = new Composite(parent, 0);
+
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.numColumns = 1;
+ composite.setLayout(gridLayout);
+
+ frameNum = new Slider(composite, SWT.BORDER | SWT.HORIZONTAL);
+ frameNum.setMinimum(0);
+ frameNum.setMaximum(1);
+ frameNum.setSelection(0);
+ frameNum.addSelectionListener(this);
+
+ GridData gridData = new GridData();
+ gridData.horizontalAlignment = SWT.FILL;
+ gridData.grabExcessHorizontalSpace = true;
+ gridData.verticalAlignment = SWT.FILL;
+ frameNum.setLayoutData(gridData);
+
+ Table table = new Table(composite, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI
+ | SWT.FULL_SELECTION);
+ TableLayout layout = new TableLayout();
+ table.setLayout(layout);
+ table.setLinesVisible(true);
+ table.setHeaderVisible(true);
+ String[] headings = {
+ "Name", "Elapsed (ms)", "Detail"
+ };
+ int[] weights = {
+ 50, 16, 60
+ };
+ int[] widths = {
+ 180, 90, 200
+ };
+ for (int i = 0; i < headings.length; i++) {
+ layout.addColumnData(new ColumnWeightData(weights[i], widths[i],
+ true));
+ TableColumn nameCol = new TableColumn(table, SWT.NONE, i);
+ nameCol.setText(headings[i]);
+ }
+
+ // viewer = new TableViewer(table);
+ viewer = new ListViewer(composite, SWT.DEFAULT);
viewer.getList().setFont(new Font(viewer.getList().getDisplay(), "Courier", 10, SWT.BOLD));
- viewContentProvider = new ViewContentProvider();
- viewer.setContentProvider(viewContentProvider);
- viewer.setLabelProvider(new ViewLabelProvider());
+ ViewContentProvider contentProvider = new ViewContentProvider();
+ viewer.setContentProvider(contentProvider);
+ viewer.setLabelProvider(contentProvider);
// viewer.setSorter(new NameSorter());
- viewer.setInput(getViewSite());
viewer.setFilters(new ViewerFilter[] {
new Filter()
});
+ gridData = new GridData();
+ gridData.horizontalAlignment = SWT.FILL;
+ gridData.grabExcessHorizontalSpace = true;
+ gridData.verticalAlignment = SWT.FILL;
+ gridData.grabExcessVerticalSpace = true;
+ viewer.getControl().setLayoutData(gridData);
}
/**
@@ -241,15 +276,12 @@
*/
@Override
public void createPartControl(Composite parent) {
- CreateView(parent);
+ CreateLeftPane(parent);
// Create the help context id for the viewer's control
PlatformUI.getWorkbench().getHelpSystem()
.setHelp(viewer.getControl(), "GLESv2DebuggerClient.viewer");
- // layoutComposite = new LayoutComposite(parent, 0);
- // layoutComposite.setLayout(new FillLayout());
-
tabFolder = new TabFolder(parent, SWT.BORDER);
text = new Text(tabFolder, SWT.NO_BACKGROUND | SWT.READ_ONLY
@@ -276,7 +308,8 @@
tabItemShaderEditor.setControl(shaderEditor);
contextViewer = new TreeViewer(tabFolder);
- ContextViewProvider contextViewProvider = new ContextViewProvider();
+ ContextViewProvider contextViewProvider = new ContextViewProvider(this);
+ contextViewer.addSelectionChangedListener(contextViewProvider);
contextViewer.setContentProvider(contextViewProvider);
contextViewer.setLabelProvider(contextViewProvider);
tabContextViewer = new TabItem(tabFolder, SWT.NONE);
@@ -363,7 +396,6 @@
makeActions();
hookContextMenu();
- hookDoubleClickAction();
hookSelectionChanged();
contributeToActionBars();
}
@@ -473,6 +505,24 @@
}
});
+ actContext = new Action("Context: 0x", Action.AS_DROP_DOWN_MENU) {
+ @Override
+ public void run()
+ {
+ if (debugContexts.size() < 2)
+ return;
+ final String idStr = this.getText().substring(
+ "Context: 0x".length());
+ if (idStr.length() == 0)
+ return;
+ final int contextId = Integer.parseInt(idStr, 16);
+ int index = debugContexts.indexOfKey(contextId);
+ index = (index + 1) % debugContexts.size();
+ ChangeContext(debugContexts.valueAt(index));
+ }
+ };
+ manager.add(actContext);
+
actionPort = new Action("5039", Action.AS_DROP_DOWN_MENU)
{
@Override
@@ -521,30 +571,16 @@
};
actionConnect.setText("Connect");
actionConnect.setToolTipText("Connect to debuggee");
-
- doubleClickAction = new Action() {
- @Override
- public void run() {
- IStructuredSelection selection = (IStructuredSelection) viewer
- .getSelection();
- MessageData msgData = (MessageData) selection.getFirstElement();
- }
- };
- }
-
- private void hookDoubleClickAction() {
- viewer.addDoubleClickListener(new IDoubleClickListener() {
- @Override
- public void doubleClick(DoubleClickEvent event) {
- doubleClickAction.run();
- }
- });
}
void MessageDataSelected(final MessageData msgData) {
if (null == msgData)
return;
- contextViewer.setInput(msgData.context);
+ if (frameNum.getSelection() == frameNum.getMaximum())
+ return; // scale max cannot overlap min, so max is array size
+ final Frame frame = current.frames.get(frameNum.getSelection());
+ final Context context = current.ComputeContext(frame, msgData);
+ contextViewer.setInput(context);
if (null != msgData.image) {
canvas.setBackgroundImage(msgData.image);
tabFolder.setSelection(tabItemImage);
@@ -615,16 +651,32 @@
} catch (IOException e1) {
showError(e1);
}
- ArrayList<MessageData> msgs = new ArrayList<MessageData>();
- boolean shaderEditorUpdate = false;
+
+ int newMessages = 0;
+
+ boolean shaderEditorUpdate = false, currentUpdate = false;
while (running) {
if (!messageQueue.IsRunning())
break;
- Message msg = messageQueue.RemoveCompleteMessage(0);
- if (msgs.size() > 60 || (msgs.size() > 0 && null == msg)) {
- viewContentProvider.add(msgs);
- msgs.clear();
+ final Message oriMsg = messageQueue.RemoveCompleteMessage(0);
+ if (newMessages > 60 || (newMessages > 0 && null == oriMsg)) {
+ newMessages = 0;
+
+ if (currentUpdate || current == null)
+ getSite().getShell().getDisplay().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (current == null)
+ ChangeContext(debugContexts.valueAt(0));
+ else
+ viewer.refresh(false);
+ frameNum.setMaximum(current.frames.size());
+ if (actionAutoScroll.isChecked())
+ viewer.getList().setSelection(viewer.getList().getItemCount() - 1);
+ }
+ });
+ currentUpdate = false;
if (shaderEditorUpdate)
this.getSite().getShell().getDisplay().syncExec(new Runnable() {
@@ -635,7 +687,7 @@
});
shaderEditorUpdate = false;
}
- if (null == msg) {
+ if (null == oriMsg) {
try {
Thread.sleep(1);
continue;
@@ -644,21 +696,20 @@
}
}
- Context context = contexts.get(msg.getContextId());
- if (null == context) {
- context = new Context(msg.getContextId());
- contexts.put(msg.getContextId(), context);
+ DebugContext debugContext = debugContexts.get(oriMsg.getContextId());
+ if (debugContext == null) {
+ debugContext = new DebugContext(oriMsg.getContextId());
+ debugContexts.put(oriMsg.getContextId(), debugContext);
}
- Context newContext = context.ProcessMessage(msg);
- // TODO: full cloning on change not implemented yet
- if (newContext.processed != null)
- msg = newContext.processed;
- contexts.put(msg.getContextId(), newContext);
- shaderEditorUpdate |= newContext.serverShader.uiUpdate;
- newContext.serverShader.uiUpdate = false;
- final MessageData msgData = new MessageData(this.getViewSite()
- .getShell().getDisplay(), msg, context);
+ final MessageData msgData = debugContext.ProcessMessage(oriMsg);
+ if (current == debugContext) {
+ currentUpdate = true;
+ }
+
+ shaderEditorUpdate |= debugContext.currentContext.serverShader.uiUpdate;
+ debugContext.currentContext.serverShader.uiUpdate = false;
+
if (null != writer) {
writer.write(msgData.text + "\n");
if (msgData.msg.getFunction() == Function.eglSwapBuffers) {
@@ -666,7 +717,7 @@
writer.flush();
}
}
- msgs.add(msgData);
+ newMessages++;
}
if (running)
ConnectDisconnect(); // error occurred, disconnect
@@ -675,4 +726,37 @@
writer.close();
}
}
+
+ /** can be called from non-UI thread */
+ void ChangeContext(final DebugContext newContext) {
+ getSite().getShell().getDisplay().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ current = newContext;
+ frameNum.setMaximum(current.frames.size());
+ frameNum.setSelection(0);
+ viewer.setInput(current.frames.get(frameNum.getSelection()));
+ shaderEditor.Update();
+ actContext.setText("Context: 0x" + Integer.toHexString(current.contextId));
+ getViewSite().getActionBars().getToolBarManager().update(true);
+ }
+ });
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (e.widget != frameNum)
+ assert false;
+ if (current == null)
+ return;
+ if (frameNum.getSelection() == current.frames.size())
+ return; // scale maximum cannot overlap minimum
+ Frame frame = current.frames.get(frameNum.getSelection());
+ viewer.setInput(frame);
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ widgetSelected(e);
+ }
}
diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/ShaderEditor.java b/tools/glesv2debugger/src/com/android/glesv2debugger/ShaderEditor.java
index 3aca1c2..dfb19d2 100644
--- a/tools/glesv2debugger/src/com/android/glesv2debugger/ShaderEditor.java
+++ b/tools/glesv2debugger/src/com/android/glesv2debugger/ShaderEditor.java
@@ -102,7 +102,9 @@
public void Update() {
list.removeAll();
String progs = "Current Programs: ";
- for (Context context : sampleView.contexts.values()) {
+ for (int j = 0; j < sampleView.debugContexts.size(); j++) {
+ final Context context = sampleView.debugContexts.valueAt(j).currentContext;
+
if (context.serverShader.current != null) {
progs += context.serverShader.current.name + "(0x";
progs += Integer.toHexString(context.contextId) + ") ";
@@ -130,6 +132,7 @@
}
list.add(builder.toString());
}
+
}
currentPrograms.setText(progs);
@@ -336,7 +339,8 @@
String[] details = list.getSelection()[0].split("\\s+");
final int contextId = Integer.parseInt(details[0], 16);
int name = Integer.parseInt(details[2]);
- current = sampleView.contexts.get(contextId).serverShader.shaders.get(name);
+ current = sampleView.debugContexts.get(contextId).currentContext.serverShader.shaders
+ .get(name);
styledText.setText(current.source);
}