GLES2Dbg: add more state tracking and snapshot of state per GL call

Use TreeView and Reflection to display the states per GL call.
Need to implement more state cloning and tacking.
Prepare to group calls by frame, and clone the context for each frame.

Change-Id: Ib1e5c175da779610204003e352cc1fcf66af969b
Signed-off-by: David Li <davidxli@google.com>
This commit is contained in:
David Li
2011-03-30 15:14:36 -07:00
parent c93109f059
commit 55fee09e0c
10 changed files with 681 additions and 184 deletions

View File

@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <classpath>
<classpathentry kind="lib" path="lib/sdklib.jar"/>
<classpathentry kind="lib" path="lib/liblzf.jar"/>
<classpathentry kind="lib" path="lib/host-libprotobuf-java-2.3.0-lite.jar"/> <classpathentry kind="lib" path="lib/host-libprotobuf-java-2.3.0-lite.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/> <classpathentry kind="src" path="src"/>
<classpathentry kind="lib" path="lib/liblzf.jar"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View File

@@ -10,4 +10,5 @@ Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ClassPath: lib/host-libprotobuf-java-2.3.0-lite.jar, Bundle-ClassPath: lib/host-libprotobuf-java-2.3.0-lite.jar,
lib/liblzf.jar, lib/liblzf.jar,
lib/sdklib.jar,
. .

View File

@@ -6,4 +6,5 @@ bin.includes = plugin.xml,\
icons/,\ icons/,\
contexts.xml,\ contexts.xml,\
lib/host-libprotobuf-java-2.3.0-lite.jar,\ lib/host-libprotobuf-java-2.3.0-lite.jar,\
lib/liblzf.jar lib/liblzf.jar,\
lib/sdklib.jar

View File

@@ -17,81 +17,205 @@
package com.android.glesv2debugger; package com.android.glesv2debugger;
import com.android.glesv2debugger.DebuggerMessage.Message; import com.android.glesv2debugger.DebuggerMessage.Message;
import com.android.glesv2debugger.DebuggerMessage.Message.Function;
import com.android.sdklib.util.SparseArray;
import com.android.sdklib.util.SparseIntArray;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Image;
import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
public class Context { public class Context implements Cloneable {
public final int contextId; public final int contextId;
ArrayList<Context> shares = new ArrayList<Context>(); // includes self public ArrayList<Context> shares = new ArrayList<Context>(); // self too
public GLServerVertex serverVertex = new GLServerVertex(); public GLServerVertex serverVertex = new GLServerVertex();
public GLServerShader serverShader = new GLServerShader(this); public GLServerShader serverShader = new GLServerShader(this);
public byte[] readPixelRef = new byte[0]; public GLServerState serverState = new GLServerState(this);
byte[] readPixelRef = new byte[0];
Message processed = null; // return; processed Message
public Context(int contextId) { public Context(int contextId) {
this.contextId = contextId; this.contextId = contextId;
shares.add(this); shares.add(this);
} }
public Message ProcessMessage(Message msg) { // returns instance TODO: return new instance if changed
switch (msg.getFunction()) { public Context ProcessMessage(Message msg) {
case glBindBuffer: GLServerVertex newVertex = serverVertex.Process(msg);
serverVertex.glBindBuffer(msg); if (newVertex != null) {
break; processed = newVertex.processed;
case glBufferData: assert newVertex == serverVertex;
serverVertex.glBufferData(msg); return this;
break;
case glBufferSubData:
serverVertex.glBufferSubData(msg);
break;
case glDeleteBuffers:
serverVertex.glDeleteBuffers(msg);
break;
case glDrawArrays:
if (msg.hasArg7())
msg = serverVertex.glDrawArrays(msg);
break;
case glDrawElements:
if (msg.hasArg7())
msg = serverVertex.glDrawElements(msg);
break;
case glDisableVertexAttribArray:
serverVertex.glDisableVertexAttribArray(msg);
break;
case glEnableVertexAttribArray:
serverVertex.glEnableVertexAttribArray(msg);
break;
case glGenBuffers:
serverVertex.glGenBuffers(msg);
break;
case glVertexAttribPointer:
serverVertex.glVertexAttribPointer(msg);
break;
case glVertexAttrib1f:
serverVertex.glVertexAttrib1f(msg);
break;
case glVertexAttrib1fv:
serverVertex.glVertexAttrib1fv(msg);
break;
case glVertexAttrib2f:
serverVertex.glVertexAttrib2f(msg);
break;
case glVertexAttrib2fv:
serverVertex.glVertexAttrib2fv(msg);
break;
case glVertexAttrib3f:
serverVertex.glVertexAttrib3f(msg);
break;
case glVertexAttrib3fv:
serverVertex.glVertexAttrib3fv(msg);
break;
case glVertexAttrib4f:
serverVertex.glVertexAttrib4f(msg);
break;
case glVertexAttrib4fv:
serverVertex.glVertexAttrib4fv(msg);
break;
} }
serverShader.ProcessMessage(msg);
return msg; GLServerShader newShader = serverShader.ProcessMessage(msg);
if (newShader != null) {
assert newShader == serverShader;
return this;
}
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;
}
}
class ContextViewProvider extends LabelProvider implements ITreeContentProvider {
Context context;
@Override
public void dispose() {
}
@Override
public String getText(Object obj) {
if (obj == null)
return "null";
if (obj instanceof Entry) {
Entry entry = (Entry) obj;
if (entry != null)
return entry.name + " = " + entry.obj;
}
return obj.toString();
}
@Override
public Image getImage(Object obj) {
return null;
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
context = (Context) newInput;
}
class Entry {
String name;
Object obj;
Entry(String name, Object obj) {
this.name = name;
this.obj = obj;
}
}
@Override
public Object[] getElements(Object inputElement) {
if (inputElement != context)
return null;
return getChildren(new Entry("Context", inputElement));
}
@Override
public Object[] getChildren(Object parentElement) {
if (!(parentElement instanceof Entry))
return null;
Entry entry = (Entry) parentElement;
ArrayList<Object> children = new ArrayList<Object>();
if (entry.obj == context.serverState.enableDisables) {
for (int i = 0; i < context.serverState.enableDisables.size(); i++) {
final int key = context.serverState.enableDisables.keyAt(i);
final int value = context.serverState.enableDisables.valueAt(i);
children.add(GLEnum.valueOf(key).name() + " = " + value);
}
} 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);
final Message msg = context.serverState.lastSetter.valueAt(i);
if (msg == null)
children.add(Function.valueOf(key).name() + " : default");
else
children.add(Function.valueOf(key).name() + " : "
+ MessageFormatter.Format(msg));
}
} else if (entry.obj instanceof SparseArray) {
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)));
} else if (entry.obj instanceof Map) {
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()));
}
} 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));
} else if (entry.obj instanceof Collection) {
Collection collection = (Collection) entry.obj;
for (Object o : collection)
children.add(new Entry(entry.name, o));
} else if (entry.obj.getClass().isArray()) {
Object[] list = (Object[]) entry.obj;
for (Object o : list)
children.add(new Entry(entry.name, o));
} else {
Field[] fields = entry.obj.getClass().getFields();
for (Field f : fields) {
try {
children.add(new Entry(f.getName(), f.get(entry.obj)));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return children.toArray();
}
@Override
public Object getParent(Object element) {
return null;
}
@Override
public boolean hasChildren(Object element) {
if (element == null)
return false;
if (element.getClass().isPrimitive())
return false;
if (element.getClass().equals(String.class))
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;
}
}
return false;
} }
} }

View File

@@ -17,79 +17,130 @@
package com.android.glesv2debugger; package com.android.glesv2debugger;
import com.android.glesv2debugger.DebuggerMessage.Message; import com.android.glesv2debugger.DebuggerMessage.Message;
import com.android.sdklib.util.SparseArray;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
class GLShader { class GLShader implements Cloneable {
final int name; public final int name;
final GLServerShader context; // the context this was created in final GLServerShader context; // the context this was created in
final GLEnum type; public final GLEnum type;
boolean delete; public boolean delete;
ArrayList<GLProgram> programs = new ArrayList<GLProgram>(); public ArrayList<Integer> programs = new ArrayList<Integer>();
String source, originalSource; public String source, originalSource;
GLShader(final int name, final GLServerShader context, final GLEnum type) { GLShader(final int name, final GLServerShader context, final GLEnum type) {
this.name = name; this.name = name;
this.context = context; this.context = context;
this.type = type; this.type = type;
} }
@Override
// deep copy except for context, which is set afterwards
public Object clone() {
try {
GLShader shader = (GLShader) super.clone();
shader.programs = (ArrayList<Integer>) programs.clone();
return shader;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
assert false;
return null;
}
}
} }
class GLProgram { class GLProgram implements Cloneable {
final int name; public final int name;
final GLServerShader context; // the context this was created in final GLServerShader context; // the context this was created in
boolean delete; public boolean delete;
GLShader vert, frag; public int vert, frag;
GLProgram(final int name, final GLServerShader context) { GLProgram(final int name, final GLServerShader context) {
this.name = name; this.name = name;
this.context = context; this.context = context;
} }
@Override
// deep copy except for context, which is set afterwards
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
assert false;
return null;
}
}
} }
public class GLServerShader { public class GLServerShader implements Cloneable {
final Context context; Context context;
HashMap<Integer, GLShader> privateShaders = new HashMap<Integer, GLShader>(); public SparseArray<GLShader> shaders = new SparseArray<GLShader>();
HashMap<Integer, GLProgram> privatePrograms = new HashMap<Integer, GLProgram>(); public SparseArray<GLProgram> programs = new SparseArray<GLProgram>();
GLProgram current = null; public GLProgram current = null;
public boolean uiUpdate = false; boolean uiUpdate = false;
GLServerShader(final Context context) { GLServerShader(Context context) {
this.context = context; this.context = context;
} }
public void ProcessMessage(final Message msg) { @Override
// deep copy except for context, which is set afterwards
public Object clone() {
try {
GLServerShader copy = (GLServerShader) super.clone();
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.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());
if (current != null)
copy.current = (GLProgram) current.clone();
return copy;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
assert false;
return null;
}
}
// returns instance if processed
public GLServerShader ProcessMessage(final Message msg) {
boolean oldUiUpdate = uiUpdate; boolean oldUiUpdate = uiUpdate;
uiUpdate = true; uiUpdate = true;
switch (msg.getFunction()) { switch (msg.getFunction()) {
case glAttachShader: case glAttachShader:
glAttachShader(msg); glAttachShader(msg);
break; return this;
case glCreateProgram: case glCreateProgram:
glCreateProgram(msg); glCreateProgram(msg);
break; return this;
case glCreateShader: case glCreateShader:
glCreateShader(msg); glCreateShader(msg);
break; return this;
case glDeleteProgram: case glDeleteProgram:
glDeleteProgram(msg); glDeleteProgram(msg);
break; return this;
case glDeleteShader: case glDeleteShader:
glDeleteShader(msg); glDeleteShader(msg);
break; return this;
case glDetachShader: case glDetachShader:
glDetachShader(msg); glDetachShader(msg);
break; return this;
case glShaderSource: case glShaderSource:
glShaderSource(msg); glShaderSource(msg);
break; return this;
case glUseProgram: case glUseProgram:
glUseProgram(msg); glUseProgram(msg);
break; return this;
default: default:
uiUpdate = oldUiUpdate; uiUpdate = oldUiUpdate;
break; return null;
} }
} }
@@ -97,7 +148,7 @@ public class GLServerShader {
if (name == 0) if (name == 0)
return null; return null;
for (Context ctx : context.shares) { for (Context ctx : context.shares) {
GLShader shader = ctx.serverShader.privateShaders.get(name); GLShader shader = ctx.serverShader.shaders.get(name);
if (shader != null) if (shader != null)
return shader; return shader;
} }
@@ -109,7 +160,7 @@ public class GLServerShader {
if (name == 0) if (name == 0)
return null; return null;
for (Context ctx : context.shares) { for (Context ctx : context.shares) {
GLProgram program = ctx.serverShader.privatePrograms.get(name); GLProgram program = ctx.serverShader.programs.get(name);
if (program != null) if (program != null)
return program; return program;
} }
@@ -122,20 +173,20 @@ public class GLServerShader {
GLProgram program = GetProgram(msg.getArg0()); GLProgram program = GetProgram(msg.getArg0());
GLShader shader = GetShader(msg.getArg1()); GLShader shader = GetShader(msg.getArg1());
if (GLEnum.GL_VERTEX_SHADER == shader.type) if (GLEnum.GL_VERTEX_SHADER == shader.type)
program.vert = shader; program.vert = shader.name;
else else
program.frag = shader; program.frag = shader.name;
shader.programs.add(program); shader.programs.add(program.name);
} }
// GLuint API_ENTRY(glCreateProgram)(void) // GLuint API_ENTRY(glCreateProgram)(void)
void glCreateProgram(final Message msg) { void glCreateProgram(final Message msg) {
privatePrograms.put(msg.getRet(), new GLProgram(msg.getRet(), this)); programs.put(msg.getRet(), new GLProgram(msg.getRet(), this));
} }
// GLuint API_ENTRY(glCreateShader)(GLenum type) // GLuint API_ENTRY(glCreateShader)(GLenum type)
void glCreateShader(final Message msg) { void glCreateShader(final Message msg) {
privateShaders.put(msg.getRet(), shaders.put(msg.getRet(),
new GLShader(msg.getRet(), this, GLEnum.valueOf(msg.getArg0()))); new GLShader(msg.getRet(), this, GLEnum.valueOf(msg.getArg0())));
} }
@@ -148,9 +199,9 @@ public class GLServerShader {
for (Context ctx : context.shares) for (Context ctx : context.shares)
if (ctx.serverShader.current == program) if (ctx.serverShader.current == program)
return; return;
glDetachShader(program, program.vert); glDetachShader(program, GetShader(program.vert));
glDetachShader(program, program.frag); glDetachShader(program, GetShader(program.frag));
privatePrograms.remove(program.name); programs.remove(program.name);
} }
// void API_ENTRY(glDeleteShader)(GLuint shader) // void API_ENTRY(glDeleteShader)(GLuint shader)
@@ -160,7 +211,7 @@ public class GLServerShader {
GLShader shader = GetShader(msg.getArg0()); GLShader shader = GetShader(msg.getArg0());
shader.delete = true; shader.delete = true;
if (shader.programs.size() == 0) if (shader.programs.size() == 0)
privateShaders.remove(shader.name); shaders.remove(shader.name);
} }
// void API_ENTRY(glDetachShader)(GLuint program, GLuint shader) // void API_ENTRY(glDetachShader)(GLuint program, GLuint shader)
@@ -171,15 +222,15 @@ public class GLServerShader {
void glDetachShader(final GLProgram program, final GLShader shader) { void glDetachShader(final GLProgram program, final GLShader shader) {
if (program == null) if (program == null)
return; return;
if (program.vert == shader) if (program.vert == shader.name)
program.vert = null; program.vert = 0;
else if (program.frag == shader) else if (program.frag == shader.name)
program.frag = null; program.frag = 0;
else else
return; return;
shader.programs.remove(program); shader.programs.remove(program.name);
if (shader.delete && shader.programs.size() == 0) if (shader.delete && shader.programs.size() == 0)
shader.context.privateShaders.remove(shader.name); shaders.remove(shader.name);
} }
// void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const // void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const
@@ -195,12 +246,11 @@ public class GLServerShader {
void glUseProgram(final Message msg) { void glUseProgram(final Message msg) {
GLProgram oldCurrent = current; GLProgram oldCurrent = current;
current = GetProgram(msg.getArg0()); current = GetProgram(msg.getArg0());
if (null != oldCurrent && oldCurrent.delete && oldCurrent != current) if (null != oldCurrent && oldCurrent.delete && oldCurrent != current) {
{
for (Context ctx : context.shares) for (Context ctx : context.shares)
if (ctx.serverShader.current == oldCurrent) if (ctx.serverShader.current == oldCurrent)
return; return;
oldCurrent.context.privatePrograms.remove(oldCurrent.name); oldCurrent.context.programs.remove(oldCurrent.name);
} }
} }
} }

View File

@@ -0,0 +1,237 @@
/*
** 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.glesv2debugger.DebuggerMessage.Message.Function;
import com.android.sdklib.util.SparseArray;
import com.android.sdklib.util.SparseIntArray;
class GLStencilState implements Cloneable {
public int ref, mask;
public GLEnum func;
public GLEnum sf, df, dp; // operation
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
public class GLServerState implements Cloneable {
final Context context;
public GLStencilState front = new GLStencilState(), back = new GLStencilState();
public SparseIntArray enableDisables;
public SparseArray<Message> lastSetter; // keyed by Function.getNumber()
GLServerState(final Context context) {
this.context = context;
enableDisables = new SparseIntArray(9);
enableDisables.put(GLEnum.GL_BLEND.value, 0);
enableDisables.put(GLEnum.GL_DITHER.value, 1);
enableDisables.put(GLEnum.GL_DEPTH_TEST.value, 0);
enableDisables.put(GLEnum.GL_STENCIL_TEST.value, 0);
enableDisables.put(GLEnum.GL_SCISSOR_TEST.value, 0);
enableDisables.put(GLEnum.GL_SAMPLE_COVERAGE.value, 0);
enableDisables.put(GLEnum.GL_SAMPLE_ALPHA_TO_COVERAGE.value, 0);
enableDisables.put(GLEnum.GL_POLYGON_OFFSET_FILL.value, 0);
enableDisables.put(GLEnum.GL_CULL_FACE.value, 0);
lastSetter = new SparseArray<Message>();
lastSetter.put(Function.glBlendColor.getNumber(), null);
// glBlendEquation overwrites glBlendEquationSeparate
lastSetter.put(Function.glBlendEquationSeparate.getNumber(), null);
// glBlendFunc overwrites glBlendFuncSeparate
lastSetter.put(Function.glBlendFuncSeparate.getNumber(), null);
lastSetter.put(Function.glColorMask.getNumber(), null);
lastSetter.put(Function.glDepthMask.getNumber(), null);
lastSetter.put(Function.glDepthFunc.getNumber(), null);
lastSetter.put(Function.glScissor.getNumber(), null);
lastSetter.put(Function.glStencilMaskSeparate.getNumber(), null);
}
// returns instance if processed (returns new instance if changed)
public GLServerState 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 glColorMask:
return Setter(msg);
case glDepthMask:
return Setter(msg);
case glDepthFunc:
return Setter(msg);
case glDisable:
return EnableDisable(false, msg);
case glEnable:
return EnableDisable(true, msg);
case glScissor:
return Setter(msg);
case glStencilFunc: {
Message.Builder builder = msg.toBuilder();
builder.setArg2(msg.getArg1());
builder.setArg1(msg.getArg0());
builder.setArg0(GLEnum.GL_FRONT_AND_BACK.value);
return glStencilFuncSeparate(builder.build());
}
case glStencilFuncSeparate:
return glStencilFuncSeparate(msg);
case glStencilMask:
return Setter(msg);
case glStencilMaskSeparate:
return Setter(msg);
case glStencilOp: {
Message.Builder builder = msg.toBuilder();
builder.setArg3(msg.getArg2());
builder.setArg2(msg.getArg1());
builder.setArg1(msg.getArg0());
builder.setArg0(GLEnum.GL_FRONT_AND_BACK.value);
return glStencilOpSeparate(builder.build());
}
case glStencilOpSeparate:
return glStencilOpSeparate(msg);
default:
return null;
}
}
GLServerState Setter(final Message msg) {
GLServerState newState = (GLServerState) this.clone();
// TODO: compare for change
switch (msg.getFunction()) {
case glBlendFunc:
newState.lastSetter.put(Function.glBlendFuncSeparate.getNumber(), msg);
break;
case glBlendEquation:
newState.lastSetter.put(Function.glBlendEquationSeparate.getNumber(), msg);
break;
case glStencilMask:
newState.lastSetter.put(Function.glStencilMaskSeparate.getNumber(), msg);
break;
default:
newState.lastSetter.put(msg.getFunction().getNumber(), msg);
break;
}
return newState;
}
GLServerState 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;
}
// void StencilFuncSeparate( enum face, enum func, int ref, uint mask )
GLServerState 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;
final GLEnum face = GLEnum.valueOf(msg.getArg0());
if (face == GLEnum.GL_FRONT || face == GLEnum.GL_FRONT_AND_BACK) {
ff = GLEnum.valueOf(msg.getArg1());
fr = msg.getArg2();
fm = msg.getArg3();
}
if (face == GLEnum.GL_BACK || face == GLEnum.GL_FRONT_AND_BACK) {
bf = GLEnum.valueOf(msg.getArg1());
br = msg.getArg2();
bm = msg.getArg3();
}
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;
}
// void StencilOpSeparate( enum face, enum sfail, enum dpfail, enum dppass )
GLServerState 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());
if (face == GLEnum.GL_FRONT || face == GLEnum.GL_FRONT_AND_BACK) {
fsf = GLEnum.valueOf(msg.getArg1());
fdf = GLEnum.valueOf(msg.getArg2());
fdp = GLEnum.valueOf(msg.getArg3());
}
if (face == GLEnum.GL_BACK || face == GLEnum.GL_FRONT_AND_BACK) {
bsf = GLEnum.valueOf(msg.getArg1());
bdf = GLEnum.valueOf(msg.getArg2());
bdp = GLEnum.valueOf(msg.getArg3());
}
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;
}
@Override
public Object 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));
}
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));
}
return newState;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}

View File

@@ -22,27 +22,27 @@ import java.nio.ByteBuffer;
import java.util.HashMap; import java.util.HashMap;
class GLBuffer { class GLBuffer {
GLEnum usage; public GLEnum usage;
GLEnum target; public GLEnum target;
ByteBuffer data; public ByteBuffer data;
} }
class GLAttribPointer { class GLAttribPointer {
int size; // number of values per vertex public int size; // number of values per vertex
GLEnum type; // data type public GLEnum type; // data type
int stride; // bytes public int stride; // bytes
int ptr; // pointer in debugger server or byte offset into buffer public int ptr; // pointer in debugger server or byte offset into buffer
GLBuffer buffer; public GLBuffer buffer;
boolean normalized; public boolean normalized;
boolean enabled; public boolean enabled;
} }
public class GLServerVertex { public class GLServerVertex {
HashMap<Integer, GLBuffer> buffers; public HashMap<Integer, GLBuffer> buffers;
GLBuffer attribBuffer, indexBuffer; // current binding public GLBuffer attribBuffer, indexBuffer; // current binding
GLAttribPointer attribPointers[]; public GLAttribPointer attribPointers[];
float defaultAttribs[][]; public float defaultAttribs[][];
int maxAttrib; int maxAttrib;
public GLServerVertex() { public GLServerVertex() {
@@ -60,6 +60,73 @@ public class GLServerVertex {
} }
} }
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) {
processed = null;
switch (msg.getFunction()) {
case glBindBuffer:
glBindBuffer(msg);
return this;
case glBufferData:
glBufferData(msg);
return this;
case glBufferSubData:
glBufferSubData(msg);
return this;
case glDeleteBuffers:
glDeleteBuffers(msg);
return this;
case glDrawArrays:
if (msg.hasArg7())
processed = glDrawArrays(msg);
return this;
case glDrawElements:
if (msg.hasArg7())
processed = glDrawElements(msg);
return this;
case glDisableVertexAttribArray:
glDisableVertexAttribArray(msg);
return this;
case glEnableVertexAttribArray:
glEnableVertexAttribArray(msg);
return this;
case glGenBuffers:
glGenBuffers(msg);
return this;
case glVertexAttribPointer:
glVertexAttribPointer(msg);
return this;
case glVertexAttrib1f:
glVertexAttrib1f(msg);
return this;
case glVertexAttrib1fv:
glVertexAttrib1fv(msg);
return this;
case glVertexAttrib2f:
glVertexAttrib2f(msg);
return this;
case glVertexAttrib2fv:
glVertexAttrib2fv(msg);
return this;
case glVertexAttrib3f:
glVertexAttrib3f(msg);
return this;
case glVertexAttrib3fv:
glVertexAttrib3fv(msg);
return this;
case glVertexAttrib4f:
glVertexAttrib4f(msg);
return this;
case glVertexAttrib4fv:
glVertexAttrib4fv(msg);
return this;
default:
return null;
}
}
// void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) // void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer)
public void glBindBuffer(Message msg) { public void glBindBuffer(Message msg) {
if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_ARRAY_BUFFER) { if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_ARRAY_BUFFER) {

View File

@@ -33,9 +33,11 @@ public class MessageData {
public float[] data; public float[] data;
public int maxAttrib; // used for formatting data public int maxAttrib; // used for formatting data
public GLEnum dataType; // could be float, int; mainly for formatting use 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 Context context) {
this.msg = msg; this.msg = msg;
this.context = context;
image = null; image = null;
shader = null; shader = null;
data = null; data = null;

View File

@@ -38,6 +38,7 @@ import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer; import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.jface.viewers.ViewerSorter;
@@ -101,8 +102,10 @@ public class SampleView extends ViewPart implements Runnable {
public static final String ID = "glesv2debuggerclient.views.SampleView"; public static final String ID = "glesv2debuggerclient.views.SampleView";
TabFolder tabFolder; TabFolder tabFolder;
TabItem tabItemText, tabItemImage, tabItemBreakpointOption, tabItemShaderEditor; TabItem tabItemText, tabItemImage, tabItemBreakpointOption;
TabItem tabItemShaderEditor, tabContextViewer;
ListViewer viewer; ListViewer viewer;
TreeViewer contextViewer;
BreakpointOption breakpointOption; BreakpointOption breakpointOption;
ShaderEditor shaderEditor; ShaderEditor shaderEditor;
Canvas canvas; Canvas canvas;
@@ -141,6 +144,7 @@ public class SampleView extends ViewPart implements Runnable {
bar.setSelection(bar.getMaximum()); bar.setSelection(bar.getMaximum());
viewer.getList().setSelection( viewer.getList().setSelection(
entries.size() - 1); entries.size() - 1);
// MessageDataSelected(entries.get(entries.size() - 1));
} }
} }
}); });
@@ -228,6 +232,7 @@ public class SampleView extends ViewPart implements Runnable {
viewer.setFilters(new ViewerFilter[] { viewer.setFilters(new ViewerFilter[] {
new Filter() new Filter()
}); });
} }
/** /**
@@ -270,6 +275,14 @@ public class SampleView extends ViewPart implements Runnable {
tabItemShaderEditor.setText("Shader Editor"); tabItemShaderEditor.setText("Shader Editor");
tabItemShaderEditor.setControl(shaderEditor); tabItemShaderEditor.setControl(shaderEditor);
contextViewer = new TreeViewer(tabFolder);
ContextViewProvider contextViewProvider = new ContextViewProvider();
contextViewer.setContentProvider(contextViewProvider);
contextViewer.setLabelProvider(contextViewProvider);
tabContextViewer = new TabItem(tabFolder, SWT.NONE);
tabContextViewer.setText("Context Viewer");
tabContextViewer.setControl(contextViewer.getTree());
final ScrollBar hBar = canvas.getHorizontalBar(); final ScrollBar hBar = canvas.getHorizontalBar();
hBar.addListener(SWT.Selection, new Listener() { hBar.addListener(SWT.Selection, new Listener() {
@Override @Override
@@ -528,6 +541,33 @@ public class SampleView extends ViewPart implements Runnable {
}); });
} }
void MessageDataSelected(final MessageData msgData) {
if (null == msgData)
return;
contextViewer.setInput(msgData.context);
if (null != msgData.image) {
canvas.setBackgroundImage(msgData.image);
tabFolder.setSelection(tabItemImage);
canvas.redraw();
} else if (null != msgData.shader) {
text.setText(msgData.shader);
tabFolder.setSelection(tabItemText);
} else if (null != msgData.data) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < msgData.data.length; i++) {
builder.append(String.format("%.3g", msgData.data[i]));
if (i % (4 * msgData.maxAttrib) == (4 * msgData.maxAttrib - 1))
builder.append('\n');
else if (i % 4 == 3)
builder.append(" -");
if (i < msgData.data.length - 1)
builder.append(' ');
}
text.setText(builder.toString());
tabFolder.setSelection(tabItemText);
}
}
private void hookSelectionChanged() { private void hookSelectionChanged() {
viewer.addSelectionChangedListener(new ISelectionChangedListener() { viewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override @Override
@@ -537,39 +577,8 @@ public class SampleView extends ViewPart implements Runnable {
if (null == selection) if (null == selection)
return; return;
MessageData msgData = (MessageData) selection.getFirstElement(); MessageData msgData = (MessageData) selection.getFirstElement();
if (null == msgData) MessageDataSelected(msgData);
return;
if (null != msgData.image)
{
canvas.setBackgroundImage(msgData.image);
tabFolder.setSelection(tabItemImage);
}
else if (null != msgData.shader)
{
text.setText(msgData.shader);
text.setVisible(true);
canvas.setVisible(false);
text.getParent().layout();
}
else if (null != msgData.data)
{
StringBuilder builder = new StringBuilder();
for (int i = 0; i < msgData.data.length; i++)
{
builder.append(String.format("%.3g", msgData.data[i]));
if (i % (4 * msgData.maxAttrib) == (4 * msgData.maxAttrib - 1))
builder.append('\n');
else if (i % 4 == 3)
builder.append(" -");
if (i < msgData.data.length - 1)
builder.append(' ');
}
text.setText(builder.toString());
tabFolder.setSelection(tabItemText);
}
} }
}); });
} }
@@ -640,8 +649,13 @@ public class SampleView extends ViewPart implements Runnable {
context = new Context(msg.getContextId()); context = new Context(msg.getContextId());
contexts.put(msg.getContextId(), context); contexts.put(msg.getContextId(), context);
} }
msg = context.ProcessMessage(msg); Context newContext = context.ProcessMessage(msg);
shaderEditorUpdate |= context.serverShader.uiUpdate; // 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() final MessageData msgData = new MessageData(this.getViewSite()
.getShell().getDisplay(), msg, context); .getShell().getDisplay(), msg, context);

View File

@@ -107,7 +107,8 @@ public class ShaderEditor extends Composite implements SelectionListener, Extend
progs += context.serverShader.current.name + "(0x"; progs += context.serverShader.current.name + "(0x";
progs += Integer.toHexString(context.contextId) + ") "; progs += Integer.toHexString(context.contextId) + ") ";
} }
for (GLShader shader : context.serverShader.privateShaders.values()) { for (int i = 0; i < context.serverShader.shaders.size(); i++) {
GLShader shader = context.serverShader.shaders.valueAt(i);
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append(String.format("%08X", context.contextId)); builder.append(String.format("%08X", context.contextId));
builder.append(' '); builder.append(' ');
@@ -123,17 +124,17 @@ public class ShaderEditor extends Composite implements SelectionListener, Extend
builder.append(' '); builder.append(' ');
} }
builder.append(": "); builder.append(": ");
for (GLProgram program : shader.programs) { for (int program : shader.programs) {
builder.append(program.name); builder.append(program);
builder.append(" "); builder.append(" ");
} }
list.add(builder.toString()); list.add(builder.toString());
} }
} }
// if (!progs.equals(currentPrograms.getText())) {
currentPrograms.setText(progs);
// } currentPrograms.setText(progs);
toolbar.redraw();
toolbar.pack(true);
toolbar.update(); toolbar.update();
} }
@@ -169,11 +170,10 @@ public class ShaderEditor extends Composite implements SelectionListener, Extend
new Color(Display.getCurrent(), 255, 230, 230)); new Color(Display.getCurrent(), 255, 230, 230));
} }
if (infolog.length() > 0) { if (infolog.length() > 0) {
MessageDialog.openWarning(getShell(), if (!MessageDialog.openConfirm(getShell(),
"Shader Syntax Error, Upload Aborted", infolog); "Shader Syntax Error, Continue?", infolog))
return; return;
} }
} catch (IOException e) { } catch (IOException e) {
sampleView.showError(e); sampleView.showError(e);
} }
@@ -235,8 +235,7 @@ public class ShaderEditor extends Composite implements SelectionListener, Extend
matchingContext = true; matchingContext = true;
break; break;
} }
if (matchingContext) if (matchingContext) {
{
shadersToUpload.remove(i); shadersToUpload.remove(i);
break; break;
} }
@@ -270,7 +269,8 @@ public class ShaderEditor extends Composite implements SelectionListener, Extend
} }
}); });
} else } else
for (GLProgram program : shader.programs) { for (int programName : shader.programs) {
GLProgram program = shader.context.GetProgram(programName);
ExchangeMessage(contextId, queue, "glLinkProgram(%d)", program.name); ExchangeMessage(contextId, queue, "glLinkProgram(%d)", program.name);
rcv = ExchangeMessage(contextId, queue, rcv = ExchangeMessage(contextId, queue,
"glGetProgramiv(%d, GL_LINK_STATUS, [0])", program.name); "glGetProgramiv(%d, GL_LINK_STATUS, [0])", program.name);
@@ -336,7 +336,7 @@ public class ShaderEditor extends Composite implements SelectionListener, Extend
String[] details = list.getSelection()[0].split("\\s+"); String[] details = list.getSelection()[0].split("\\s+");
final int contextId = Integer.parseInt(details[0], 16); final int contextId = Integer.parseInt(details[0], 16);
int name = Integer.parseInt(details[2]); int name = Integer.parseInt(details[2]);
current = sampleView.contexts.get(contextId).serverShader.privateShaders.get(name); current = sampleView.contexts.get(contextId).serverShader.shaders.get(name);
styledText.setText(current.source); styledText.setText(current.source);
} }