GLES2Dbg: implemented shader tracking and editing
Next commit is improving the protocol and checking errors after shader upload Change-Id: I6afe3b63a68e00cd395885fd26cd6fcb311cfbec Signed-off-by: David Li <davidxli@google.com>
This commit is contained in:
@@ -21,7 +21,6 @@ import com.android.glesv2debugger.DebuggerMessage.Message.Function;
|
||||
import com.android.glesv2debugger.DebuggerMessage.Message.Prop;
|
||||
import com.android.glesv2debugger.DebuggerMessage.Message.Type;
|
||||
import org.eclipse.jface.dialogs.InputDialog;
|
||||
import org.eclipse.jface.dialogs.MessageDialog;
|
||||
import org.eclipse.jface.window.Window;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.ScrolledComposite;
|
||||
@@ -42,7 +41,6 @@ public class BreakpointOption extends ScrolledComposite implements SelectionList
|
||||
|
||||
SampleView sampleView;
|
||||
HashMap<Function, Button> buttonsBreak = new HashMap<Function, Button>();
|
||||
MessageParserEx messageParserEx = new MessageParserEx();
|
||||
|
||||
BreakpointOption(SampleView sampleView, Composite parent) {
|
||||
super(parent, SWT.NO_BACKGROUND | SWT.V_SCROLL | SWT.H_SCROLL);
|
||||
@@ -72,7 +70,6 @@ public class BreakpointOption extends ScrolledComposite implements SelectionList
|
||||
this.setExpandVertical(true);
|
||||
this.setMinSize(size);
|
||||
this.layout();
|
||||
// this.pack(true);
|
||||
}
|
||||
|
||||
void SetBreakpoint(Function function, boolean enabled) {
|
||||
@@ -140,7 +137,8 @@ public class BreakpointOption extends ScrolledComposite implements SelectionList
|
||||
SetBreakpoint(msg.getFunction(), false);
|
||||
}
|
||||
else
|
||||
messageParserEx.Parse(builder, inputDialog.getValue());
|
||||
MessageParserEx.instance.Parse(builder, inputDialog.getValue());
|
||||
builder.setExpectResponse(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -18,13 +18,21 @@ package com.android.glesv2debugger;
|
||||
|
||||
import com.android.glesv2debugger.DebuggerMessage.Message;
|
||||
|
||||
public class Context {
|
||||
public int contextId;
|
||||
public GLServerVertex serverVertex = new GLServerVertex();
|
||||
public byte [] readPixelRef = new byte [0];
|
||||
import java.util.ArrayList;
|
||||
|
||||
public Message ProcessMessage(Message msg)
|
||||
{
|
||||
public class Context {
|
||||
public final int contextId;
|
||||
ArrayList<Context> shares = new ArrayList<Context>(); // includes self
|
||||
public GLServerVertex serverVertex = new GLServerVertex();
|
||||
public GLServerShader serverShader = new GLServerShader(this);
|
||||
public byte[] readPixelRef = new byte[0];
|
||||
|
||||
public Context(int contextId) {
|
||||
this.contextId = contextId;
|
||||
shares.add(this);
|
||||
}
|
||||
|
||||
public Message ProcessMessage(Message msg) {
|
||||
switch (msg.getFunction()) {
|
||||
case glBindBuffer:
|
||||
serverVertex.glBindBuffer(msg);
|
||||
@@ -83,6 +91,7 @@ public class Context {
|
||||
serverVertex.glVertexAttrib4fv(msg);
|
||||
break;
|
||||
}
|
||||
serverShader.ProcessMessage(msg);
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,7 +446,8 @@ public final class DebuggerMessage {
|
||||
implements com.google.protobuf.Internal.EnumLite {
|
||||
BeforeCall(0, 0),
|
||||
AfterCall(1, 1),
|
||||
Response(2, 2),
|
||||
AfterGeneratedCall(2, 2),
|
||||
Response(3, 3),
|
||||
;
|
||||
|
||||
|
||||
@@ -456,7 +457,8 @@ public final class DebuggerMessage {
|
||||
switch (value) {
|
||||
case 0: return BeforeCall;
|
||||
case 1: return AfterCall;
|
||||
case 2: return Response;
|
||||
case 2: return AfterGeneratedCall;
|
||||
case 3: return Response;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
** 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 java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
class GLShader {
|
||||
final int name;
|
||||
final GLServerShader context; // the context this was created in
|
||||
final GLEnum type;
|
||||
boolean delete;
|
||||
ArrayList<GLProgram> programs = new ArrayList<GLProgram>();
|
||||
String source, originalSource;
|
||||
|
||||
GLShader(final int name, final GLServerShader context, final GLEnum type) {
|
||||
this.name = name;
|
||||
this.context = context;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
class GLProgram {
|
||||
final int name;
|
||||
final GLServerShader context; // the context this was created in
|
||||
boolean delete;
|
||||
GLShader vert, frag;
|
||||
|
||||
GLProgram(final int name, final GLServerShader context) {
|
||||
this.name = name;
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
|
||||
public class GLServerShader {
|
||||
final Context context;
|
||||
HashMap<Integer, GLShader> privateShaders = new HashMap<Integer, GLShader>();
|
||||
HashMap<Integer, GLProgram> privatePrograms = new HashMap<Integer, GLProgram>();
|
||||
GLProgram current = null;
|
||||
public boolean uiUpdate = false;
|
||||
|
||||
GLServerShader(final Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void ProcessMessage(final Message msg) {
|
||||
boolean oldUiUpdate = uiUpdate;
|
||||
uiUpdate = true;
|
||||
switch (msg.getFunction()) {
|
||||
case glAttachShader:
|
||||
glAttachShader(msg);
|
||||
break;
|
||||
case glCreateProgram:
|
||||
glCreateProgram(msg);
|
||||
break;
|
||||
case glCreateShader:
|
||||
glCreateShader(msg);
|
||||
break;
|
||||
case glDeleteProgram:
|
||||
glDeleteProgram(msg);
|
||||
break;
|
||||
case glDeleteShader:
|
||||
glDeleteShader(msg);
|
||||
break;
|
||||
case glDetachShader:
|
||||
glDetachShader(msg);
|
||||
break;
|
||||
case glShaderSource:
|
||||
glShaderSource(msg);
|
||||
break;
|
||||
case glUseProgram:
|
||||
glUseProgram(msg);
|
||||
break;
|
||||
default:
|
||||
uiUpdate = oldUiUpdate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GLShader GetShader(int name) {
|
||||
if (name == 0)
|
||||
return null;
|
||||
for (Context ctx : context.shares) {
|
||||
GLShader shader = ctx.serverShader.privateShaders.get(name);
|
||||
if (shader != null)
|
||||
return shader;
|
||||
}
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
|
||||
GLProgram GetProgram(int name) {
|
||||
if (name == 0)
|
||||
return null;
|
||||
for (Context ctx : context.shares) {
|
||||
GLProgram program = ctx.serverShader.privatePrograms.get(name);
|
||||
if (program != null)
|
||||
return program;
|
||||
}
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
|
||||
// void API_ENTRY(glAttachShader)(GLuint program, GLuint shader)
|
||||
void glAttachShader(final Message msg) {
|
||||
GLProgram program = GetProgram(msg.getArg0());
|
||||
GLShader shader = GetShader(msg.getArg1());
|
||||
if (GLEnum.GL_VERTEX_SHADER == shader.type)
|
||||
program.vert = shader;
|
||||
else
|
||||
program.frag = shader;
|
||||
shader.programs.add(program);
|
||||
}
|
||||
|
||||
// GLuint API_ENTRY(glCreateProgram)(void)
|
||||
void glCreateProgram(final Message msg) {
|
||||
privatePrograms.put(msg.getRet(), new GLProgram(msg.getRet(), this));
|
||||
}
|
||||
|
||||
// GLuint API_ENTRY(glCreateShader)(GLenum type)
|
||||
void glCreateShader(final Message msg) {
|
||||
privateShaders.put(msg.getRet(),
|
||||
new GLShader(msg.getRet(), this, GLEnum.valueOf(msg.getArg0())));
|
||||
}
|
||||
|
||||
// void API_ENTRY(glDeleteProgram)
|
||||
void glDeleteProgram(final Message msg) {
|
||||
if (msg.getArg0() == 0)
|
||||
return;
|
||||
GLProgram program = GetProgram(msg.getArg0());
|
||||
program.delete = true;
|
||||
for (Context ctx : context.shares)
|
||||
if (ctx.serverShader.current == program)
|
||||
return;
|
||||
glDetachShader(program, program.vert);
|
||||
glDetachShader(program, program.frag);
|
||||
privatePrograms.remove(program.name);
|
||||
}
|
||||
|
||||
// void API_ENTRY(glDeleteShader)(GLuint shader)
|
||||
void glDeleteShader(final Message msg) {
|
||||
if (msg.getArg0() == 0)
|
||||
return;
|
||||
GLShader shader = GetShader(msg.getArg0());
|
||||
shader.delete = true;
|
||||
if (shader.programs.size() == 0)
|
||||
privateShaders.remove(shader.name);
|
||||
}
|
||||
|
||||
// void API_ENTRY(glDetachShader)(GLuint program, GLuint shader)
|
||||
void glDetachShader(final Message msg) {
|
||||
glDetachShader(GetProgram(msg.getArg0()), GetShader(msg.getArg1()));
|
||||
}
|
||||
|
||||
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;
|
||||
else
|
||||
return;
|
||||
shader.programs.remove(program);
|
||||
if (shader.delete && shader.programs.size() == 0)
|
||||
shader.context.privateShaders.remove(shader.name);
|
||||
}
|
||||
|
||||
// void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const
|
||||
// GLchar** string, const GLint* length)
|
||||
void glShaderSource(final Message msg) {
|
||||
if (!msg.hasData())
|
||||
return; // TODO: distinguish between generated calls
|
||||
GLShader shader = GetShader(msg.getArg0());
|
||||
shader.source = shader.originalSource = msg.getData().toStringUtf8();
|
||||
}
|
||||
|
||||
// void API_ENTRY(glUseProgram)(GLuint program)
|
||||
void glUseProgram(final Message msg) {
|
||||
GLProgram oldCurrent = current;
|
||||
current = GetProgram(msg.getArg0());
|
||||
if (null != oldCurrent && oldCurrent.delete && oldCurrent != current)
|
||||
{
|
||||
for (Context ctx : context.shares)
|
||||
if (ctx.serverShader.current == oldCurrent)
|
||||
return;
|
||||
oldCurrent.context.privatePrograms.remove(oldCurrent.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package com.android.glesv2debugger;
|
||||
import com.android.glesv2debugger.DebuggerMessage.Message;
|
||||
import com.android.glesv2debugger.DebuggerMessage.Message.DataType;
|
||||
import com.android.glesv2debugger.DebuggerMessage.Message.Function;
|
||||
import com.android.glesv2debugger.DebuggerMessage.Message.Type;
|
||||
|
||||
import org.eclipse.swt.graphics.Device;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
@@ -51,11 +52,16 @@ public class MessageData {
|
||||
builder.append(String.format(":%.3f", msg.getClock()));
|
||||
builder.append(String.format(" 0x%08X", msg.getContextId()));
|
||||
builder.append(" ");
|
||||
if (msg.getType() == Type.BeforeCall) // incomplete call, client SKIPPED
|
||||
builder.append("[BeforeCall(AfterCall missing)] ");
|
||||
else if (msg.getType() == Type.AfterGeneratedCall)
|
||||
builder.append("[AfterGeneratedCall] ");
|
||||
else
|
||||
assert msg.getType() == Type.AfterCall;
|
||||
builder.append(MessageFormatter.Format(msg));
|
||||
switch (function) {
|
||||
case glDrawArrays: // msg was modified by GLServerVertex
|
||||
case glDrawElements:
|
||||
assert msg.hasData();
|
||||
if (!msg.hasArg8() || !msg.hasData())
|
||||
break;
|
||||
dataType = GLEnum.valueOf(msg.getArg8());
|
||||
|
||||
@@ -301,4 +301,5 @@ public class MessageParserEx extends MessageParser {
|
||||
// TODO: GLvoid* ptr
|
||||
}
|
||||
|
||||
public final static MessageParserEx instance = new MessageParserEx();
|
||||
}
|
||||
|
||||
@@ -20,10 +20,6 @@ import com.android.glesv2debugger.DebuggerMessage.Message;
|
||||
import com.android.glesv2debugger.DebuggerMessage.Message.Function;
|
||||
import com.android.glesv2debugger.DebuggerMessage.Message.Type;
|
||||
|
||||
import org.eclipse.jface.dialogs.MessageDialog;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.EOFException;
|
||||
@@ -85,6 +81,12 @@ public class MessageQueue implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
public void AddCommands(ArrayList<Message> cmds) {
|
||||
synchronized (commands) {
|
||||
commands.addAll(cmds);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Socket socket = new Socket();
|
||||
@@ -101,7 +103,6 @@ public class MessageQueue implements Runnable {
|
||||
Error(e);
|
||||
}
|
||||
|
||||
// try {
|
||||
while (running) {
|
||||
Message msg = null;
|
||||
if (incoming.size() > 0) { // find queued incoming
|
||||
@@ -126,8 +127,10 @@ public class MessageQueue implements Runnable {
|
||||
|
||||
int contextId = msg.getContextId();
|
||||
if (!incoming.containsKey(contextId))
|
||||
incoming.put(contextId,
|
||||
new ArrayList<Message>());
|
||||
incoming.put(contextId, new ArrayList<Message>());
|
||||
|
||||
if (msg.getType() == Type.AfterGeneratedCall)
|
||||
continue; // TODO: for now, don't care
|
||||
|
||||
// FIXME: the expected sequence will change for interactive mode
|
||||
while (msg.getType() == Type.BeforeCall) {
|
||||
@@ -149,6 +152,9 @@ public class MessageQueue implements Runnable {
|
||||
break;
|
||||
}
|
||||
|
||||
if (next.getType() == Type.AfterGeneratedCall)
|
||||
continue; // TODO: for now, don't care
|
||||
|
||||
if (next.getContextId() != contextId) {
|
||||
// message part not for this context
|
||||
if (!incoming.containsKey(next.getContextId()))
|
||||
@@ -176,13 +182,14 @@ public class MessageQueue implements Runnable {
|
||||
Error(e);
|
||||
running = false;
|
||||
}
|
||||
// } catch (Exception e) {
|
||||
// Error(e);
|
||||
// running = false;
|
||||
// }
|
||||
}
|
||||
|
||||
public Message RemoveMessage(int contextId) {
|
||||
Message GetMessage(int contextId) {
|
||||
// ReadMessage and filter by contextId
|
||||
return null;
|
||||
}
|
||||
|
||||
public Message RemoveCompleteMessage(int contextId) {
|
||||
synchronized (complete) {
|
||||
if (complete.size() == 0)
|
||||
return null;
|
||||
@@ -244,10 +251,12 @@ public class MessageQueue implements Runnable {
|
||||
builder.setFunction(Function.CONTINUE);
|
||||
else if (msg.getType() == Type.AfterCall)
|
||||
builder.setFunction(Function.SKIP);
|
||||
else if (msg.getType() == Type.AfterGeneratedCall)
|
||||
builder.setFunction(Function.SKIP);
|
||||
else
|
||||
assert false;
|
||||
builder.setType(Type.Response);
|
||||
builder.setExpectResponse(false);
|
||||
builder.setExpectResponse(msg.getExpectResponse());
|
||||
if (msg.getExpectResponse())
|
||||
sampleView.breakpointOption.BreakpointReached(builder, msg);
|
||||
if (SendCommands(dos, 0) || msg.getExpectResponse())
|
||||
|
||||
@@ -103,6 +103,7 @@ public class SampleView extends ViewPart implements Runnable {
|
||||
LayoutComposite layoutComposite;
|
||||
ListViewer viewer;
|
||||
BreakpointOption breakpointOption;
|
||||
ShaderEditor shaderEditor;
|
||||
org.eclipse.swt.widgets.Canvas canvas;
|
||||
Text text;
|
||||
Action actionConnect; // connect / disconnect
|
||||
@@ -239,11 +240,6 @@ public class SampleView extends ViewPart implements Runnable {
|
||||
// Create the help context id for the viewer's control
|
||||
PlatformUI.getWorkbench().getHelpSystem()
|
||||
.setHelp(viewer.getControl(), "GLESv2DebuggerClient.viewer");
|
||||
makeActions();
|
||||
hookContextMenu();
|
||||
hookDoubleClickAction();
|
||||
hookSelectionChanged();
|
||||
contributeToActionBars();
|
||||
|
||||
layoutComposite = new LayoutComposite(parent, 0);
|
||||
layoutComposite.setLayout(new FillLayout());
|
||||
@@ -257,6 +253,7 @@ public class SampleView extends ViewPart implements Runnable {
|
||||
canvas.setVisible(false);
|
||||
|
||||
breakpointOption = new BreakpointOption(this, layoutComposite);
|
||||
shaderEditor = new ShaderEditor(this, layoutComposite);
|
||||
|
||||
final ScrollBar hBar = canvas.getHorizontalBar();
|
||||
hBar.addListener(SWT.Selection, new Listener() {
|
||||
@@ -335,6 +332,12 @@ public class SampleView extends ViewPart implements Runnable {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
makeActions();
|
||||
hookContextMenu();
|
||||
hookDoubleClickAction();
|
||||
hookSelectionChanged();
|
||||
contributeToActionBars();
|
||||
}
|
||||
|
||||
private void hookContextMenu() {
|
||||
@@ -465,7 +468,18 @@ public class SampleView extends ViewPart implements Runnable {
|
||||
{
|
||||
breakpointOption.setVisible(!breakpointOption.isVisible());
|
||||
layoutComposite.layout(true);
|
||||
manager.update(true);
|
||||
}
|
||||
};
|
||||
action.setChecked(true);
|
||||
manager.add(action);
|
||||
|
||||
action = new Action("Shaders", Action.AS_CHECK_BOX)
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
shaderEditor.setVisible(!shaderEditor.isVisible());
|
||||
layoutComposite.layout(true);
|
||||
}
|
||||
};
|
||||
action.setChecked(true);
|
||||
@@ -606,14 +620,24 @@ public class SampleView extends ViewPart implements Runnable {
|
||||
showError(e1);
|
||||
}
|
||||
ArrayList<MessageData> msgs = new ArrayList<MessageData>();
|
||||
boolean shaderEditorUpdate = false;
|
||||
while (running) {
|
||||
if (!messageQueue.IsRunning())
|
||||
break;
|
||||
|
||||
Message msg = messageQueue.RemoveMessage(0);
|
||||
Message msg = messageQueue.RemoveCompleteMessage(0);
|
||||
if (msgs.size() > 60 || (msgs.size() > 0 && null == msg)) {
|
||||
viewContentProvider.add(msgs);
|
||||
msgs.clear();
|
||||
|
||||
if (shaderEditorUpdate)
|
||||
this.getSite().getShell().getDisplay().syncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
shaderEditor.Update();
|
||||
}
|
||||
});
|
||||
shaderEditorUpdate = false;
|
||||
}
|
||||
if (null == msg) {
|
||||
try {
|
||||
@@ -626,10 +650,11 @@ public class SampleView extends ViewPart implements Runnable {
|
||||
|
||||
Context context = contexts.get(msg.getContextId());
|
||||
if (null == context) {
|
||||
context = new Context();
|
||||
context = new Context(msg.getContextId());
|
||||
contexts.put(msg.getContextId(), context);
|
||||
}
|
||||
msg = context.ProcessMessage(msg);
|
||||
shaderEditorUpdate |= context.serverShader.uiUpdate;
|
||||
|
||||
final MessageData msgData = new MessageData(this.getViewSite()
|
||||
.getShell().getDisplay(), msg, context);
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
** 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.Type;
|
||||
|
||||
import org.eclipse.jface.dialogs.MessageDialog;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.ExtendedModifyEvent;
|
||||
import org.eclipse.swt.custom.ExtendedModifyListener;
|
||||
import org.eclipse.swt.custom.StyleRange;
|
||||
import org.eclipse.swt.custom.StyledText;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.events.SelectionListener;
|
||||
import org.eclipse.swt.graphics.Font;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.List;
|
||||
import org.eclipse.swt.widgets.ToolBar;
|
||||
import org.eclipse.swt.widgets.ToolItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ShaderEditor extends Composite implements SelectionListener, ExtendedModifyListener {
|
||||
SampleView sampleView;
|
||||
|
||||
ToolBar toolbar;
|
||||
ToolItem uploadShader, restoreShader;
|
||||
List list;
|
||||
StyledText styledText;
|
||||
|
||||
GLShader current;
|
||||
|
||||
ArrayList<Message> cmds = new ArrayList<Message>();
|
||||
|
||||
ShaderEditor(SampleView sampleView, Composite parent) {
|
||||
super(parent, 0);
|
||||
this.sampleView = sampleView;
|
||||
|
||||
GridLayout gridLayout = new GridLayout();
|
||||
gridLayout.numColumns = 1;
|
||||
this.setLayout(gridLayout);
|
||||
|
||||
toolbar = new ToolBar(this, SWT.BORDER);
|
||||
|
||||
uploadShader = new ToolItem(toolbar, SWT.PUSH);
|
||||
uploadShader.setText("Upload Shader");
|
||||
uploadShader.addSelectionListener(this);
|
||||
|
||||
restoreShader = new ToolItem(toolbar, SWT.PUSH);
|
||||
restoreShader.setText("Original Shader");
|
||||
restoreShader.addSelectionListener(this);
|
||||
|
||||
list = new List(this, SWT.V_SCROLL);
|
||||
list.setFont(new Font(parent.getDisplay(), "Courier", 10, 0));
|
||||
list.addSelectionListener(this);
|
||||
GridData gridData = new GridData();
|
||||
gridData.horizontalAlignment = SWT.FILL;
|
||||
gridData.grabExcessHorizontalSpace = true;
|
||||
gridData.verticalAlignment = SWT.FILL;
|
||||
gridData.grabExcessVerticalSpace = true;
|
||||
list.setLayoutData(gridData);
|
||||
|
||||
styledText = new StyledText(this, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI);
|
||||
gridData = new GridData();
|
||||
gridData.horizontalAlignment = SWT.FILL;
|
||||
gridData.grabExcessHorizontalSpace = true;
|
||||
gridData.verticalAlignment = SWT.FILL;
|
||||
gridData.grabExcessVerticalSpace = true;
|
||||
styledText.setLayoutData(gridData);
|
||||
styledText.addExtendedModifyListener(this);
|
||||
}
|
||||
|
||||
public void Update() {
|
||||
list.removeAll();
|
||||
for (Context context : sampleView.contexts.values()) {
|
||||
for (GLShader shader : context.serverShader.privateShaders.values()) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(String.format("%08X", context.contextId));
|
||||
builder.append(' ');
|
||||
builder.append(shader.type);
|
||||
while (builder.length() < 30)
|
||||
builder.append(" ");
|
||||
builder.append(shader.name);
|
||||
while (builder.length() < 40)
|
||||
builder.append(" ");
|
||||
builder.append(':');
|
||||
for (Context ctx : context.shares) {
|
||||
builder.append(String.format("%08X", ctx.contextId));
|
||||
builder.append(' ');
|
||||
}
|
||||
builder.append(':');
|
||||
for (GLProgram program : shader.programs) {
|
||||
builder.append(program.name);
|
||||
builder.append(" ");
|
||||
}
|
||||
list.add(builder.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UploadShader() {
|
||||
current.source = styledText.getText();
|
||||
|
||||
ArrayList<Message> cmds = new ArrayList<Message>();
|
||||
final int contextId = current.context.context.contextId;
|
||||
|
||||
Message.Builder builder = GetBuilder(contextId);
|
||||
MessageParserEx.instance.Parse(builder,
|
||||
String.format("glShaderSource(%d,1,\"%s\",0)", current.name, current.source));
|
||||
cmds.add(builder.build());
|
||||
|
||||
builder = GetBuilder(contextId);
|
||||
MessageParserEx.instance.Parse(builder,
|
||||
String.format("glCompileShader(%d)", current.name));
|
||||
cmds.add(builder.build());
|
||||
|
||||
for (GLProgram program : current.programs) {
|
||||
builder = GetBuilder(contextId);
|
||||
MessageParserEx.instance.Parse(builder,
|
||||
String.format("glLinkProgram(%d)", program.name));
|
||||
cmds.add(builder.build());
|
||||
}
|
||||
|
||||
sampleView.messageQueue.AddCommands(cmds);
|
||||
}
|
||||
|
||||
Message.Builder GetBuilder(int contextId) {
|
||||
Message.Builder builder = Message.newBuilder();
|
||||
builder.setContextId(contextId);
|
||||
builder.setType(Type.Response);
|
||||
builder.setExpectResponse(false);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
if (e.getSource() == uploadShader && null != current) {
|
||||
UploadShader();
|
||||
return;
|
||||
} else if (e.getSource() == restoreShader && null != current) {
|
||||
current.source = styledText.getText();
|
||||
styledText.setText(current.originalSource);
|
||||
return;
|
||||
}
|
||||
|
||||
if (list.getSelectionCount() < 1)
|
||||
return;
|
||||
if (null != current && !current.source.equals(styledText.getText())) {
|
||||
String[] btns = {
|
||||
"&Upload", "&Save", "&Discard"
|
||||
};
|
||||
MessageDialog dialog = new MessageDialog(this.getShell(), "Shader Edited",
|
||||
null, "Shader source has been edited", MessageDialog.QUESTION, btns, 0);
|
||||
int rc = dialog.open();
|
||||
if (rc == SWT.DEFAULT || rc == 0)
|
||||
UploadShader();
|
||||
else if (rc == 1)
|
||||
current.source = styledText.getText();
|
||||
// else if (rc == 2) do nothing; selection is changing
|
||||
}
|
||||
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);
|
||||
styledText.setText(current.source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void widgetDefaultSelected(SelectionEvent e) {
|
||||
widgetSelected(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyText(ExtendedModifyEvent event) {
|
||||
final String[] keywords = {
|
||||
"gl_Position", "gl_FragColor"
|
||||
};
|
||||
// FIXME: proper scanner for syntax highlighting
|
||||
String text = styledText.getText();
|
||||
int start = event.start;
|
||||
int end = event.start + event.length;
|
||||
start -= 20; // deleting chars from keyword causes rescan
|
||||
end += 20;
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (end > text.length())
|
||||
end = text.length();
|
||||
if (null != styledText.getStyleRangeAtOffset(event.start)) {
|
||||
StyleRange clearStyleRange = new StyleRange();
|
||||
clearStyleRange.start = start;
|
||||
clearStyleRange.length = end - start;
|
||||
clearStyleRange.foreground = event.display.getSystemColor(SWT.COLOR_BLACK);
|
||||
styledText.setStyleRange(clearStyleRange);
|
||||
}
|
||||
|
||||
while (start < end) {
|
||||
for (final String keyword : keywords) {
|
||||
if (!text.substring(start).startsWith(keyword))
|
||||
continue;
|
||||
if (start > 0) {
|
||||
final char before = text.charAt(start - 1);
|
||||
if (Character.isLetterOrDigit(before))
|
||||
continue;
|
||||
else if (before == '_')
|
||||
continue;
|
||||
}
|
||||
if (start + keyword.length() < text.length()) {
|
||||
final char after = text.charAt(start + keyword.length());
|
||||
if (Character.isLetterOrDigit(after))
|
||||
continue;
|
||||
else if (after == '_')
|
||||
continue;
|
||||
}
|
||||
StyleRange style1 = new StyleRange();
|
||||
style1.start = start;
|
||||
style1.length = keyword.length();
|
||||
style1.foreground = event.display.getSystemColor(SWT.COLOR_BLUE);
|
||||
styledText.setStyleRange(style1);
|
||||
}
|
||||
start++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user