diff --git a/tools/glesv2debugger/.classpath b/tools/glesv2debugger/.classpath index b9ab6219b..799a9cd32 100755 --- a/tools/glesv2debugger/.classpath +++ b/tools/glesv2debugger/.classpath @@ -1,9 +1,10 @@ + + - diff --git a/tools/glesv2debugger/META-INF/MANIFEST.MF b/tools/glesv2debugger/META-INF/MANIFEST.MF index 8848a93bd..53e5e4538 100644 --- a/tools/glesv2debugger/META-INF/MANIFEST.MF +++ b/tools/glesv2debugger/META-INF/MANIFEST.MF @@ -10,4 +10,5 @@ Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ClassPath: lib/host-libprotobuf-java-2.3.0-lite.jar, lib/liblzf.jar, + lib/sdklib.jar, . diff --git a/tools/glesv2debugger/build.properties b/tools/glesv2debugger/build.properties index 8d519093e..5b94aea25 100644 --- a/tools/glesv2debugger/build.properties +++ b/tools/glesv2debugger/build.properties @@ -3,7 +3,8 @@ output.. = bin/ bin.includes = plugin.xml,\ META-INF/,\ .,\ - icons/,\ - contexts.xml,\ + icons/,\ + contexts.xml,\ lib/host-libprotobuf-java-2.3.0-lite.jar,\ - lib/liblzf.jar + lib/liblzf.jar,\ + lib/sdklib.jar diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/Context.java b/tools/glesv2debugger/src/com/android/glesv2debugger/Context.java index 54ddc9a10..ff096d782 100644 --- a/tools/glesv2debugger/src/com/android/glesv2debugger/Context.java +++ b/tools/glesv2debugger/src/com/android/glesv2debugger/Context.java @@ -17,81 +17,205 @@ 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; +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.Collection; +import java.util.Map; +import java.util.Set; -public class Context { +public class Context implements Cloneable { public final int contextId; - ArrayList shares = new ArrayList(); // includes self + public ArrayList shares = new ArrayList(); // self too public GLServerVertex serverVertex = new GLServerVertex(); 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) { this.contextId = contextId; shares.add(this); } - public Message ProcessMessage(Message msg) { - switch (msg.getFunction()) { - case glBindBuffer: - serverVertex.glBindBuffer(msg); - break; - case glBufferData: - serverVertex.glBufferData(msg); - 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; + // 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; } - 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 children = new ArrayList(); + 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; } } diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerShader.java b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerShader.java index 281db68de..4915921bc 100644 --- a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerShader.java +++ b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerShader.java @@ -17,79 +17,130 @@ package com.android.glesv2debugger; import com.android.glesv2debugger.DebuggerMessage.Message; +import com.android.sdklib.util.SparseArray; import java.util.ArrayList; -import java.util.HashMap; -class GLShader { - final int name; +class GLShader implements Cloneable { + public final int name; final GLServerShader context; // the context this was created in - final GLEnum type; - boolean delete; - ArrayList programs = new ArrayList(); - String source, originalSource; + public final GLEnum type; + public boolean delete; + public ArrayList programs = new ArrayList(); + public String source, originalSource; GLShader(final int name, final GLServerShader context, final GLEnum type) { this.name = name; this.context = context; 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) programs.clone(); + return shader; + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + assert false; + return null; + } + } } -class GLProgram { - final int name; +class GLProgram implements Cloneable { + public final int name; final GLServerShader context; // the context this was created in - boolean delete; - GLShader vert, frag; + public boolean delete; + public int vert, frag; GLProgram(final int name, final GLServerShader context) { this.name = name; 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 { - final Context context; - HashMap privateShaders = new HashMap(); - HashMap privatePrograms = new HashMap(); - GLProgram current = null; - public boolean uiUpdate = false; +public class GLServerShader implements Cloneable { + Context context; + public SparseArray shaders = new SparseArray(); + public SparseArray programs = new SparseArray(); + public GLProgram current = null; + boolean uiUpdate = false; - GLServerShader(final Context context) { + GLServerShader(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(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(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; uiUpdate = true; switch (msg.getFunction()) { case glAttachShader: glAttachShader(msg); - break; + return this; case glCreateProgram: glCreateProgram(msg); - break; + return this; case glCreateShader: glCreateShader(msg); - break; + return this; case glDeleteProgram: glDeleteProgram(msg); - break; + return this; case glDeleteShader: glDeleteShader(msg); - break; + return this; case glDetachShader: glDetachShader(msg); - break; + return this; case glShaderSource: glShaderSource(msg); - break; + return this; case glUseProgram: glUseProgram(msg); - break; + return this; default: uiUpdate = oldUiUpdate; - break; + return null; } } @@ -97,7 +148,7 @@ public class GLServerShader { if (name == 0) return null; for (Context ctx : context.shares) { - GLShader shader = ctx.serverShader.privateShaders.get(name); + GLShader shader = ctx.serverShader.shaders.get(name); if (shader != null) return shader; } @@ -109,7 +160,7 @@ public class GLServerShader { if (name == 0) return null; for (Context ctx : context.shares) { - GLProgram program = ctx.serverShader.privatePrograms.get(name); + GLProgram program = ctx.serverShader.programs.get(name); if (program != null) return program; } @@ -122,20 +173,20 @@ public class GLServerShader { GLProgram program = GetProgram(msg.getArg0()); GLShader shader = GetShader(msg.getArg1()); if (GLEnum.GL_VERTEX_SHADER == shader.type) - program.vert = shader; + program.vert = shader.name; else - program.frag = shader; - shader.programs.add(program); + program.frag = shader.name; + shader.programs.add(program.name); } // GLuint API_ENTRY(glCreateProgram)(void) 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) void glCreateShader(final Message msg) { - privateShaders.put(msg.getRet(), + shaders.put(msg.getRet(), new GLShader(msg.getRet(), this, GLEnum.valueOf(msg.getArg0()))); } @@ -148,9 +199,9 @@ public class GLServerShader { for (Context ctx : context.shares) if (ctx.serverShader.current == program) return; - glDetachShader(program, program.vert); - glDetachShader(program, program.frag); - privatePrograms.remove(program.name); + glDetachShader(program, GetShader(program.vert)); + glDetachShader(program, GetShader(program.frag)); + programs.remove(program.name); } // void API_ENTRY(glDeleteShader)(GLuint shader) @@ -160,7 +211,7 @@ public class GLServerShader { GLShader shader = GetShader(msg.getArg0()); shader.delete = true; if (shader.programs.size() == 0) - privateShaders.remove(shader.name); + shaders.remove(shader.name); } // void API_ENTRY(glDetachShader)(GLuint program, GLuint shader) @@ -171,15 +222,15 @@ public class GLServerShader { void glDetachShader(final GLProgram program, final GLShader shader) { if (program == null) return; - if (program.vert == shader) - program.vert = null; - else if (program.frag == shader) - program.frag = null; + if (program.vert == shader.name) + program.vert = 0; + else if (program.frag == shader.name) + program.frag = 0; else return; - shader.programs.remove(program); + shader.programs.remove(program.name); 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 @@ -195,12 +246,11 @@ public class GLServerShader { void glUseProgram(final Message msg) { GLProgram oldCurrent = current; current = GetProgram(msg.getArg0()); - if (null != oldCurrent && oldCurrent.delete && oldCurrent != current) - { + if (null != oldCurrent && oldCurrent.delete && oldCurrent != current) { for (Context ctx : context.shares) if (ctx.serverShader.current == oldCurrent) return; - oldCurrent.context.privatePrograms.remove(oldCurrent.name); + oldCurrent.context.programs.remove(oldCurrent.name); } } } diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerState.java b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerState.java new file mode 100644 index 000000000..b79ef3775 --- /dev/null +++ b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerState.java @@ -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 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(); + 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(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; + } + } +} diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerVertex.java b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerVertex.java index 0ff03475b..4a23bbb1e 100644 --- a/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerVertex.java +++ b/tools/glesv2debugger/src/com/android/glesv2debugger/GLServerVertex.java @@ -22,27 +22,27 @@ import java.nio.ByteBuffer; import java.util.HashMap; class GLBuffer { - GLEnum usage; - GLEnum target; - ByteBuffer data; + public GLEnum usage; + public GLEnum target; + public ByteBuffer data; } class GLAttribPointer { - int size; // number of values per vertex - GLEnum type; // data type - int stride; // bytes - int ptr; // pointer in debugger server or byte offset into buffer - GLBuffer buffer; - boolean normalized; - boolean enabled; + public int size; // number of values per vertex + public GLEnum type; // data type + public int stride; // bytes + public int ptr; // pointer in debugger server or byte offset into buffer + public GLBuffer buffer; + public boolean normalized; + public boolean enabled; } public class GLServerVertex { - HashMap buffers; - GLBuffer attribBuffer, indexBuffer; // current binding - GLAttribPointer attribPointers[]; - float defaultAttribs[][]; + public HashMap buffers; + public GLBuffer attribBuffer, indexBuffer; // current binding + public GLAttribPointer attribPointers[]; + public float defaultAttribs[][]; int maxAttrib; 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) public void glBindBuffer(Message msg) { if (GLEnum.valueOf(msg.getArg0()) == GLEnum.GL_ARRAY_BUFFER) { @@ -141,32 +208,32 @@ public class GLServerVertex { else if (GLEnum.GL_UNSIGNED_INT == type) if (normalized) return (Integer.reverseBytes(src.getInt()) & 0xffffffffL) / (2e32f - 1); - else + else return Integer.reverseBytes(src.getInt()) & 0xffffffffL; else if (GLEnum.GL_INT == type) if (normalized) return (Integer.reverseBytes(src.getInt()) * 2 + 1) / (2e32f - 1); - else + else return Integer.reverseBytes(src.getInt()); else if (GLEnum.GL_UNSIGNED_SHORT == type) if (normalized) return (Short.reverseBytes(src.getShort()) & 0xffff) / (2e16f - 1); - else + else return Short.reverseBytes(src.getShort()) & 0xffff; else if (GLEnum.GL_SHORT == type) if (normalized) return (Short.reverseBytes(src.getShort()) * 2 + 1) / (2e16f - 1); - else + else return Short.reverseBytes(src.getShort()); else if (GLEnum.GL_UNSIGNED_BYTE == type) if (normalized) return (src.get() & 0xff) / (2e8f - 1); - else + else return src.get() & 0xff; else if (GLEnum.GL_BYTE == type) if (normalized) return (src.get() * 2 + 1) / (2e8f - 1); - else + else return src.get(); else if (GLEnum.GL_FIXED == type) if (normalized) diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/MessageData.java b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageData.java index 9c4143d33..16eee596b 100644 --- a/tools/glesv2debugger/src/com/android/glesv2debugger/MessageData.java +++ b/tools/glesv2debugger/src/com/android/glesv2debugger/MessageData.java @@ -33,9 +33,11 @@ public class MessageData { 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) { this.msg = msg; + this.context = context; image = null; shader = null; data = null; diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/SampleView.java b/tools/glesv2debugger/src/com/android/glesv2debugger/SampleView.java index eb1a6ee60..87d97a4a9 100644 --- a/tools/glesv2debugger/src/com/android/glesv2debugger/SampleView.java +++ b/tools/glesv2debugger/src/com/android/glesv2debugger/SampleView.java @@ -38,6 +38,7 @@ 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.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; 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"; TabFolder tabFolder; - TabItem tabItemText, tabItemImage, tabItemBreakpointOption, tabItemShaderEditor; + TabItem tabItemText, tabItemImage, tabItemBreakpointOption; + TabItem tabItemShaderEditor, tabContextViewer; ListViewer viewer; + TreeViewer contextViewer; BreakpointOption breakpointOption; ShaderEditor shaderEditor; Canvas canvas; @@ -141,6 +144,7 @@ public class SampleView extends ViewPart implements Runnable { bar.setSelection(bar.getMaximum()); viewer.getList().setSelection( entries.size() - 1); + // MessageDataSelected(entries.get(entries.size() - 1)); } } }); @@ -228,6 +232,7 @@ public class SampleView extends ViewPart implements Runnable { viewer.setFilters(new ViewerFilter[] { new Filter() }); + } /** @@ -270,6 +275,14 @@ public class SampleView extends ViewPart implements Runnable { tabItemShaderEditor.setText("Shader Editor"); 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(); hBar.addListener(SWT.Selection, new Listener() { @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() { viewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override @@ -537,39 +577,8 @@ public class SampleView extends ViewPart implements Runnable { if (null == selection) return; MessageData msgData = (MessageData) selection.getFirstElement(); - if (null == 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); - } + MessageDataSelected(msgData); } - }); } @@ -640,8 +649,13 @@ public class SampleView extends ViewPart implements Runnable { context = new Context(msg.getContextId()); contexts.put(msg.getContextId(), context); } - msg = context.ProcessMessage(msg); - shaderEditorUpdate |= context.serverShader.uiUpdate; + 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); diff --git a/tools/glesv2debugger/src/com/android/glesv2debugger/ShaderEditor.java b/tools/glesv2debugger/src/com/android/glesv2debugger/ShaderEditor.java index 49bece304..3aca1c24a 100644 --- a/tools/glesv2debugger/src/com/android/glesv2debugger/ShaderEditor.java +++ b/tools/glesv2debugger/src/com/android/glesv2debugger/ShaderEditor.java @@ -107,7 +107,8 @@ public class ShaderEditor extends Composite implements SelectionListener, Extend progs += context.serverShader.current.name + "(0x"; 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(); builder.append(String.format("%08X", context.contextId)); builder.append(' '); @@ -123,17 +124,17 @@ public class ShaderEditor extends Composite implements SelectionListener, Extend builder.append(' '); } builder.append(": "); - for (GLProgram program : shader.programs) { - builder.append(program.name); + for (int program : shader.programs) { + builder.append(program); builder.append(" "); } list.add(builder.toString()); } } - // if (!progs.equals(currentPrograms.getText())) { - currentPrograms.setText(progs); - // } + currentPrograms.setText(progs); + toolbar.redraw(); + toolbar.pack(true); toolbar.update(); } @@ -169,11 +170,10 @@ public class ShaderEditor extends Composite implements SelectionListener, Extend new Color(Display.getCurrent(), 255, 230, 230)); } if (infolog.length() > 0) { - MessageDialog.openWarning(getShell(), - "Shader Syntax Error, Upload Aborted", infolog); - return; + if (!MessageDialog.openConfirm(getShell(), + "Shader Syntax Error, Continue?", infolog)) + return; } - } catch (IOException e) { sampleView.showError(e); } @@ -235,8 +235,7 @@ public class ShaderEditor extends Composite implements SelectionListener, Extend matchingContext = true; break; } - if (matchingContext) - { + if (matchingContext) { shadersToUpload.remove(i); break; } @@ -270,7 +269,8 @@ public class ShaderEditor extends Composite implements SelectionListener, Extend } }); } else - for (GLProgram program : shader.programs) { + for (int programName : shader.programs) { + GLProgram program = shader.context.GetProgram(programName); ExchangeMessage(contextId, queue, "glLinkProgram(%d)", program.name); rcv = ExchangeMessage(contextId, queue, "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+"); final int contextId = Integer.parseInt(details[0], 16); 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); }