blob: afa7e91ea0fa3975c9be70822982ef9646019681 [file] [log] [blame]
/*
** 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.Type;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
public class MessageQueue implements Runnable {
boolean running = false;
Thread thread = null;
ArrayList<DebuggerMessage.Message> complete = new ArrayList<DebuggerMessage.Message>();
ArrayList<DebuggerMessage.Message> commands = new ArrayList<DebuggerMessage.Message>();
SampleView sampleView;
HashMap<Integer, GLServerVertex> serversVertex = new HashMap<Integer, GLServerVertex>();
public MessageQueue(SampleView sampleView) {
this.sampleView = sampleView;
}
public void Start() {
if (running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
public void Stop() {
if (!running)
return;
running = false;
}
public boolean IsRunning() {
return running;
}
void SendCommands(final DataOutputStream dos, final int contextId) throws IOException {
synchronized (commands) {
for (int i = 0; i < commands.size(); i++) {
DebuggerMessage.Message command = commands.get(i);
if (command.getContextId() == contextId || contextId == 0) { // FIXME:
// proper
// context
// id
SendMessage(dos, command);
commands.remove(i);
i--;
}
}
}
SendResponse(dos, contextId, DebuggerMessage.Message.Function.SKIP);
}
public void AddCommand(DebuggerMessage.Message command) {
synchronized (commands) {
commands.add(command);
}
}
@Override
public void run() {
Socket socket = new Socket();
DataInputStream dis = null;
DataOutputStream dos = null;
HashMap<Integer, ArrayList<DebuggerMessage.Message>> incoming = new HashMap<Integer, ArrayList<DebuggerMessage.Message>>();
try {
socket.connect(new java.net.InetSocketAddress("127.0.0.1", 5039));
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
} catch (Exception e) {
running = false;
Error(e);
}
// try {
while (running) {
DebuggerMessage.Message msg = null;
if (incoming.size() > 0) { // find queued incoming
for (ArrayList<DebuggerMessage.Message> messages : incoming
.values())
if (messages.size() > 0) {
msg = messages.get(0);
messages.remove(0);
break;
}
}
if (null == msg) { // get incoming from network
try {
msg = ReadMessage(dis);
if (msg.getExpectResponse()) {
if (msg.getType() == Type.BeforeCall)
SendResponse(dos, msg.getContextId(),
DebuggerMessage.Message.Function.CONTINUE);
else if (msg.getType() == Type.AfterCall)
// after GL function call
SendCommands(dos, 0); // FIXME: proper context id
// SendResponse(dos, msg.getContextId(),
// DebuggerMessage.Message.Function.SKIP);
else if (msg.getType() == Type.Response)
assert true;
else
assert false;
}
} catch (IOException e) {
Error(e);
running = false;
break;
}
}
int contextId = msg.getContextId();
if (!incoming.containsKey(contextId))
incoming.put(contextId,
new ArrayList<DebuggerMessage.Message>());
// FIXME: the expected sequence will change for interactive mode
while (msg.getType() == Type.BeforeCall) {
DebuggerMessage.Message next = null;
// get existing message part for this context
ArrayList<DebuggerMessage.Message> messages = incoming
.get(contextId);
if (messages.size() > 0) {
next = messages.get(0);
messages.remove(0);
}
if (null == next) { // read new part for message
try {
next = ReadMessage(dis);
if (next.getExpectResponse()) {
if (next.getType() == Type.BeforeCall)
SendResponse(
dos,
next.getContextId(),
DebuggerMessage.Message.Function.CONTINUE);
else if (next.getType() == Type.AfterCall)
SendCommands(dos, 0); // FIXME: proper context
// id
else if (msg.getType() == Type.Response)
assert true;
else
assert false;
}
} catch (IOException e) {
Error(e);
running = false;
break;
}
if (next.getContextId() != contextId) {
// message part not for this context
if (!incoming.containsKey(next.getContextId()))
incoming.put(
next.getContextId(),
new ArrayList<DebuggerMessage.Message>());
incoming.get(next.getContextId()).add(next);
continue;
}
}
DebuggerMessage.Message.Builder builder = msg.toBuilder();
// builder.mergeFrom(next); seems to merge incorrectly
if (next.hasRet())
builder.setRet(next.getRet());
if (next.hasTime())
builder.setTime(next.getTime());
if (next.hasData())
builder.setData(next.getData());
builder.setType(next.getType());
msg = builder.build();
}
GLServerVertex serverVertex = serversVertex.get(msg.getContextId());
if (null == serverVertex) {
serverVertex = new GLServerVertex();
serversVertex.put(msg.getContextId(), serverVertex);
}
// forward message to synchronize state
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;
}
synchronized (complete) {
complete.add(msg);
}
}
try {
socket.close();
} catch (IOException e) {
Error(e);
running = false;
}
// } catch (Exception e) {
// Error(e);
// running = false;
// }
}
public DebuggerMessage.Message RemoveMessage(int contextId) {
synchronized (complete) {
if (complete.size() == 0)
return null;
if (0 == contextId) // get a message of any
{
DebuggerMessage.Message msg = complete.get(0);
complete.remove(0);
return msg;
}
for (int i = 0; i < complete.size(); i++) {
DebuggerMessage.Message msg = complete.get(i);
if (msg.getContextId() == contextId) {
complete.remove(i);
return msg;
}
}
}
return null;
}
DebuggerMessage.Message ReadMessage(final DataInputStream dis)
throws IOException {
int len = 0;
try {
len = dis.readInt();
} catch (EOFException e) {
Error(new Exception("EOF"));
}
byte[] buffer = new byte[len];
int readLen = 0;
while (readLen < len) {
int read = -1;
try {
read = dis.read(buffer, readLen, len - readLen);
} catch (EOFException e) {
Error(new Exception("EOF"));
}
if (read < 0) {
Error(new Exception("read length = " + read));
return null;
} else
readLen += read;
}
DebuggerMessage.Message msg = DebuggerMessage.Message.parseFrom(buffer);
return msg;
}
void SendMessage(final DataOutputStream dos, final DebuggerMessage.Message message)
throws IOException {
final byte[] data = message.toByteArray();
dos.writeInt(data.length);
dos.write(data);
}
void SendResponse(final DataOutputStream dos, final int contextId,
final DebuggerMessage.Message.Function function) throws IOException {
DebuggerMessage.Message.Builder builder = DebuggerMessage.Message
.newBuilder();
builder.setContextId(contextId);
builder.setFunction(function);
builder.setType(Type.Response);
builder.setExpectResponse(false);
SendMessage(dos, builder.build());
}
void Error(Exception e) {
sampleView.showError(e);
}
}