blob: 28f3a54d83b6844a747ad8050327f77dd20e6be6 [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;
import com.android.glesv2debugger.DebuggerMessage.Message.Function;
import com.android.sdklib.util.SparseIntArray;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Shell;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
public class CodeGen implements IRunnableWithProgress {
private FileWriter codeFile, makeFile, namesHeaderFile, namesSourceFile;
private PrintWriter code, make, namesHeader, namesSource;
private FileOutputStream dataOut;
private SparseIntArray bufferNames,
framebufferNames, programNames, textureNames, shaderNames, renderbufferNames;
/** return true if msg was a texture upload */
private boolean codeGenTextureUpload(final Message msg, final boolean replaceCopy) {
String s = null;
switch (msg.getFunction()) {
case glCompressedTexImage2D:
s = MessageFormatter.format(msg, true).replace("arg7", "texData");
break;
case glCompressedTexSubImage2D:
case glTexImage2D:
case glTexSubImage2D:
s = MessageFormatter.format(msg, true).replace("arg8", "texData");
break;
case glCopyTexImage2D:
if (!replaceCopy) {
code.write(MessageFormatter.format(msg, true));
code.write(";CHKERR;\n");
return true;
}
assert msg.getArg2() == msg.getPixelFormat(); // TODO
s = "//" + MessageFormatter.format(msg, true) + "\n";
s += String.format("glTexImage2D(%s, %d, %s, %d, %d, %d, %s, %s, texData);CHKERR;",
GLEnum.valueOf(msg.getArg0()), msg.getArg1(),
GLEnum.valueOf(msg.getArg2()), msg.getArg5(), msg.getArg6(),
msg.getArg7(), GLEnum.valueOf(msg.getPixelFormat()),
GLEnum.valueOf(msg.getPixelType()));
break;
case glCopyTexSubImage2D:
if (!replaceCopy) {
code.write(MessageFormatter.format(msg, true));
code.write(";CHKERR;\n");
return true;
}
// FIXME: check the texture format & type, and convert
s = "//" + MessageFormatter.format(msg, true) + "\n";
s += String.format(
"glTexSubImage2D(%s, %d, %d, %d, %d, %d, %s, %s, texData);CHKERR;",
GLEnum.valueOf(msg.getArg0()), msg.getArg1(), msg.getArg2(),
msg.getArg3(), msg.getArg6(), msg.getArg7(),
GLEnum.valueOf(msg.getPixelFormat()), GLEnum.valueOf(msg.getPixelType()));
break;
default:
return false;
}
if (msg.hasData()) {
final byte[] data = MessageProcessor.lzfDecompressChunks(msg.getData());
try {
code.write("{\n");
code.format(" void * texData = malloc(%d);CHKERR;\n", data.length);
code.format(" FILE * texFile = fopen(\"/sdcard/frame_data.bin\", \"rb\");CHKERR;\n");
code.format(" assert(texFile);CHKERR;\n");
code.format(" fseek(texFile, %d, SEEK_SET);CHKERR;\n", dataOut.getChannel()
.position());
dataOut.write(data);
code.format(" fread(texData, %d, 1, texFile);CHKERR;\n", data.length);
code.format(" fclose(texFile);CHKERR;\n");
code.format(" " + s + ";\n");
code.format(" free(texData);CHKERR;\n");
code.format("}\n");
} catch (IOException e) {
e.printStackTrace();
assert false;
}
} else
code.write(s.replace("texData", "NULL") + ";\n");
return true;
}
private void codeGenServerState(final GLServerState serverState) {
code.write("// CodeGenServerState\n");
for (int i = 0; i < serverState.enableDisables.size(); i++) {
final GLEnum key = GLEnum.valueOf(serverState.enableDisables.keyAt(i));
if (serverState.enableDisables.valueAt(i) == 0)
code.format("glDisable(%s);CHKERR;\n", key);
else
code.format("glEnable(%s);CHKERR;\n", key);
}
for (int i = 0; i < serverState.lastSetter.size(); i++) {
final Function key = Function.valueOf(serverState.lastSetter.keyAt(i));
final Message msg = serverState.lastSetter.valueAt(i);
if (msg == null) {
code.format("// %s is default\n", key);
continue;
}
final String s = MessageFormatter.format(msg, true);
code.write(s);
code.write(";\n");
}
// TODO: stencil and integers
}
private void codeGenServerShader(final GLServerShader serverShader) {
code.write("// CodeGenServerShader\n");
for (int i = 0; i < serverShader.shaders.size(); i++) {
final int name = serverShader.shaders.keyAt(i);
final GLShader shader = serverShader.shaders.valueAt(i);
final String id = "shader_" + name;
if (shaderNames.indexOfKey(name) < 0) {
namesSource.format("GLuint %s = 0;\n", id);
namesHeader.format("extern GLuint %s;\n", id);
}
code.format("%s = glCreateShader(%s);CHKERR;\n", id, shader.type);
shaderNames.put(name, name);
if (shader.source != null) {
final String src = shader.source.replace("\r", "").replace("\n", "\\n\\\n")
.replace("\"", "\\\"");
code.format("glShaderSource(%s, 1, (const GLchar *[]){\"%s\"}, NULL);CHKERR;\n",
id, src);
code.format("glCompileShader(%s);CHKERR;\n", id);
}
}
for (int i = 0; i < serverShader.programs.size(); i++) {
final int name = serverShader.programs.keyAt(i);
final GLProgram program = serverShader.programs.valueAt(i);
final String id = "program_" + name;
if (programNames.indexOfKey(name) < 0) {
namesSource.format("GLuint %s = 0;\n", id);
namesHeader.format("extern GLuint %s;\n", id);
}
code.format("%s = glCreateProgram();CHKERR;\n", id);
programNames.put(name, name);
code.format("glAttachShader(%s, shader_%d);CHKERR;\n", id,
program.vert);
code.format("glAttachShader(%s, shader_%d);CHKERR;\n", id,
program.frag);
code.format("glLinkProgram(%s);CHKERR;\n", id);
if (serverShader.current == program)
code.format("glUseProgram(%s);CHKERR;\n", id);
}
}
private void codeGenServerTexture(final GLServerTexture serverTexture, final boolean replaceCopy) {
code.write("// CodeGenServerTexture\n");
for (int i = 0; i < serverTexture.textures.size(); i++) {
final int name = serverTexture.textures.keyAt(i);
final GLTexture tex = serverTexture.textures.valueAt(i);
final String id = "texture_" + name;
if (textureNames.indexOfKey(name) < 0) {
namesHeader.format("extern GLuint %s;\n", id);
namesSource.format("GLuint %s = 0;\n", id);
}
code.format("%s = 0;\n", id);
textureNames.put(name, name);
if (name == 0)
continue;
code.format("glGenTextures(1, &%s);CHKERR;\n", id);
String s = String.format("glBindTexture(%s, texture_%d);CHKERR;\n", tex.target,
tex.name);
code.write(s);
for (final Message msg : tex.contentChanges) {
if (codeGenTextureUpload(msg, replaceCopy))
continue;
switch (msg.getFunction()) {
case glGenerateMipmap:
s = MessageFormatter.format(msg, true);
break;
default:
assert false;
}
code.write(s + ";\n");
}
code.format("glTexParameteriv(%s, GL_TEXTURE_WRAP_S, (GLint[]){%s});CHKERR;\n",
tex.target, tex.wrapS);
code.format("glTexParameteriv(%s, GL_TEXTURE_WRAP_T, (GLint[]){%s});CHKERR;\n",
tex.target, tex.wrapT);
code.format("glTexParameteriv(%s, GL_TEXTURE_MIN_FILTER, (GLint[]){%s});CHKERR;\n",
tex.target, tex.min);
code.format("glTexParameteriv(%s, GL_TEXTURE_MAG_FILTER, (GLint[]){%s});CHKERR;\n",
tex.target, tex.mag);
}
for (int i = 0; i < serverTexture.tmu2D.length; i++) {
code.format("glActiveTexture(%s);CHKERR;\n",
GLEnum.valueOf(GLEnum.GL_TEXTURE0.value + i));
code.format("glBindTexture(GL_TEXTURE_2D, texture_%d);CHKERR;\n",
serverTexture.tmu2D[i]);
}
for (int i = 0; i < serverTexture.tmuCube.length; i++) {
code.format("glActiveTexture(%s);CHKERR;\n",
GLEnum.valueOf(GLEnum.GL_TEXTURE0.value + i));
code.format("glBindTexture(GL_TEXTURE_CUBE_MAP, texture_%d);CHKERR;\n",
serverTexture.tmuCube[i]);
}
code.format("glActiveTexture(%s);CHKERR;\n", serverTexture.activeTexture);
if (serverTexture.tex2D == null)
code.format("glBindTexture(GL_TEXTURE_2D, 0);CHKERR;\n");
else
code.format("glBindTexture(GL_TEXTURE_2D, texture_%d);CHKERR;\n",
serverTexture.tex2D.name);
if (serverTexture.texCube == null)
code.format("glBindTexture(GL_TEXTURE_CUBE_MAP, 0);CHKERR;\n");
else
code.format("glBindTexture(GL_TEXTURE_CUBE_MAP, texture_%d);CHKERR;\n",
serverTexture.texCube.name);
}
private void codeGenBufferData(final ByteBuffer buffer, final String call) {
ByteBuffer bfr = buffer;
if (buffer.isReadOnly()) {
bfr = ByteBuffer.allocate(buffer.capacity());
bfr.put(buffer);
}
final byte[] data = bfr.array();
try {
code.write("{\n");
code.format(" void * bufferData = malloc(%d);\n", data.length);
code.format(" FILE * bufferFile = fopen(\"/sdcard/frame_data.bin\", \"rb\");\n");
code.format(" assert(bufferFile);\n");
code.format(" fseek(bufferFile, %d, SEEK_SET);\n", dataOut.getChannel()
.position());
dataOut.write(data);
code.format(" fread(bufferData, %d, 1, bufferFile);\n", data.length);
code.format(" fclose(bufferFile);\n");
code.format(" " + call + ";CHKERR;\n");
code.format(" free(bufferData);\n");
code.format("}\n");
} catch (IOException e) {
e.printStackTrace();
assert false;
}
}
private void codeGenServerVertex(final GLServerVertex v) {
code.write("// CodeGenServerVertex\n");
for (int i = 0; i < v.buffers.size(); i++) {
final int name = v.buffers.keyAt(i);
final String id = "buffer_" + name;
final GLBuffer buffer = v.buffers.valueAt(i);
if (bufferNames.indexOfKey(name) < 0) {
namesHeader.format("extern GLuint %s;\n", id);
namesSource.format("GLuint %s = 0;\n", id);
}
code.format("%s = 0;\n", id);
bufferNames.put(name, name);
if (name == 0)
continue;
code.format("glGenBuffers(1, &%s);CHKERR;\n", id);
if (buffer.target != null) {
code.format("glBindBuffer(%s, %s);CHKERR;\n", buffer.target, id);
if (buffer.data != null) {
String s = String.format("glBufferData(%s, %d, bufferData, %s)", buffer.target,
buffer.data.capacity(), buffer.usage);
codeGenBufferData(buffer.data, s);
}
}
}
// TODO: use MAX_VERTEX_ATTRIBS
for (int i = 0; i < v.defaultAttribs.length; i++)
code.format("glVertexAttrib4f(%d, %f, %f, %f, %f);CHKERR;\n", i,
v.defaultAttribs[i][0],
v.defaultAttribs[i][1], v.defaultAttribs[i][2], v.defaultAttribs[i][3]);
for (int i = 0; i < v.attribPointers.length; i++) {
final GLAttribPointer att = v.attribPointers[i];
if (att.type == null)
continue;
if (att.buffer != null)
code.format("glBindBuffer(GL_ARRAY_BUFFER, buffer_%d);CHKERR;\n", att.buffer.name);
else
code.format("glBindBuffer(GL_ARRAY_BUFFER, 0);CHKERR;\n");
code.format("glVertexAttribPointer(%d, %d, %s, %b, %d, (const GLvoid *)%d);CHKERR;\n",
i, att.size, att.type, att.normalized, att.stride, att.ptr);
}
if (v.attribBuffer != null)
code.format("glBindBuffer(GL_ARRAY_BUFFER, buffer_%d);CHKERR;\n", v.attribBuffer.name);
else
code.write("glBindBuffer(GL_ARRAY_BUFFER, 0);CHKERR;\n");
if (v.indexBuffer != null)
code.format("glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_%d);CHKERR;\n",
v.indexBuffer.name);
else
code.write("glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);CHKERR;\n");
}
private void codeGenGenNames(final Message msg) {
final ByteBuffer names = msg.getData().asReadOnlyByteBuffer();
names.order(SampleView.targetByteOrder);
SparseIntArray namesArray = null;
for (int i = 0; i < msg.getArg0(); i++) {
String id = "";
final int name = names.getInt();
switch (msg.getFunction()) {
case glGenBuffers:
id = "buffer";
namesArray = bufferNames;
break;
case glGenFramebuffers:
id = "framebuffer";
namesArray = framebufferNames;
break;
case glGenRenderbuffers:
id = "renderbuffer";
namesArray = renderbufferNames;
break;
case glGenTextures:
id = "texture";
namesArray = textureNames;
break;
default:
assert false;
}
id += "_" + name;
if (namesArray.indexOfKey(name) < 0) {
namesHeader.format("extern GLuint %s;\n", id);
namesSource.format("GLuint %s = 0;\n", id);
}
code.format("%s = 0;\n", id);
namesArray.put(name, name);
code.format("%s(1, &%s);CHKERR;\n", msg.getFunction(), id);
}
}
private void codeGenDeleteNames(final Message msg) {
final ByteBuffer names = msg.getData().asReadOnlyByteBuffer();
names.order(SampleView.targetByteOrder);
SparseIntArray namesArray = null;
for (int i = 0; i < msg.getArg0(); i++) {
String id = null;
final int name = names.getInt();
switch (msg.getFunction()) {
case glDeleteBuffers:
id = "buffer";
namesArray = bufferNames;
break;
case glDeleteFramebuffers:
id = "framebuffer";
namesArray = framebufferNames;
break;
case glDeleteRenderbuffers:
id = "renderbuffer";
namesArray = renderbufferNames;
break;
case glDeleteTextures:
id = "texture";
namesArray = textureNames;
break;
default:
assert false;
}
id += "_" + name;
code.format("%s = 0;\n", id);
namesArray.put(name, 0);
code.format("%s(1, &%s);CHKERR;\n", msg.getFunction(), id);
}
}
private void codeGenBindNames(final Message msg) {
String id = null;
SparseIntArray namesArray = null;
final int name = msg.getArg1();
switch (msg.getFunction()) {
case glBindBuffer:
id = "buffer";
namesArray = bufferNames;
break;
case glBindFramebuffer:
id = "framebuffer";
namesArray = framebufferNames;
break;
case glBindRenderbuffer:
id = "renderbuffer";
namesArray = renderbufferNames;
break;
case glBindTexture:
id = "texture";
namesArray = textureNames;
break;
default:
assert false;
}
id += "_" + name;
if (namesArray.indexOfKey(name) < 0) {
namesHeader.format("extern GLuint %s;\n", id);
namesSource.format("GLuint %s = 0;\n", id);
} else if (namesArray.get(name) != name)
code.format("%s = %d;\n", id, name); // name was deleted
namesArray.put(name, name);
code.write(MessageFormatter.format(msg, true));
code.write(";CHKERR;\n");
}
private void codeGenDrawArrays(final GLServerVertex v, final MessageData msgData)
throws IOException {
final int maxAttrib = msgData.msg.getArg7();
if (maxAttrib < 1) {
code.write("// no vertex data\n");
return;
}
final byte[] data = msgData.msg.getData().toByteArray();
final GLEnum mode = GLEnum.valueOf(msgData.msg.getArg0());
final int first = msgData.msg.getArg1(), count = msgData.msg.getArg2();
int attribDataStride = 0;
for (int i = 0; i < maxAttrib; i++) {
final GLAttribPointer att = v.attribPointers[i];
if (!att.enabled)
continue;
if (att.buffer != null)
continue;
attribDataStride += att.elemSize;
}
assert attribDataStride * count == data.length;
code.write("{\n");
if (attribDataStride > 0) {
code.format(" FILE * attribFile = fopen(\"/sdcard/frame_data.bin\", \"rb\");CHKERR;\n");
code.format(" assert(attribFile);CHKERR;\n");
code.format(" fseek(attribFile, %d, SEEK_SET);CHKERR;\n", dataOut.getChannel()
.position());
dataOut.write(data);
code.format(" char * const attribData = (char *)malloc(%d);\n", first
* attribDataStride + data.length);
code.format(" assert(attribData);\n");
code.format(" fread(attribData + %d, %d, 1, attribFile);\n",
first * attribDataStride, data.length);
code.format(" fclose(attribFile);\n");
code.format(" glBindBuffer(GL_ARRAY_BUFFER, 0);CHKERR;\n");
int attribDataOffset = 0;
for (int i = 0; i < maxAttrib; i++) {
final GLAttribPointer att = v.attribPointers[i];
if (!att.enabled)
continue;
if (att.buffer != null)
continue;
code.format(
" glVertexAttribPointer(%d, %d, %s, %b, %d, attribData + %d);CHKERR;\n",
i, att.size, att.type, att.normalized,
attribDataStride, attribDataOffset);
attribDataOffset += att.elemSize;
}
if (v.attribBuffer != null)
code.format(" glBindBuffer(GL_ARRAY_BUFFER, %d);CHKERR;\n",
v.attribBuffer.name);
}
code.format(" glDrawArrays(%s, %d, %d);CHKERR;\n", mode, first, count);
if (attribDataStride > 0)
code.format(" free(attribData);CHKERR;\n");
code.write("};\n");
}
private void codeGenDrawElements(final GLServerVertex v, final MessageData msgData)
throws IOException {
final int maxAttrib = msgData.msg.getArg7();
if (maxAttrib < 1) {
code.write("// no vertex data\n");
return;
}
final GLEnum mode = GLEnum.valueOf(msgData.msg.getArg0());
final int count = msgData.msg.getArg1();
final GLEnum type = GLEnum.valueOf(msgData.msg.getArg2());
String typeName = "GLubyte";
if (type == GLEnum.GL_UNSIGNED_SHORT)
typeName = "GLushort";
int attribDataStride = 0;
for (int i = 0; i < maxAttrib; i++) {
final GLAttribPointer att = v.attribPointers[i];
if (!att.enabled)
continue;
if (att.buffer != null)
continue;
attribDataStride += att.elemSize;
}
code.write("{\n");
if (v.indexBuffer == null || attribDataStride > 0) {
// need to load user pointer indices and/or attributes
final byte[] element = new byte[attribDataStride];
final ByteBuffer data = msgData.msg.getData().asReadOnlyByteBuffer();
data.order(SampleView.targetByteOrder);
final ByteBuffer indexData = ByteBuffer.allocate(count * GLServerVertex.typeSize(type));
indexData.order(SampleView.targetByteOrder);
final ByteBuffer attribData = ByteBuffer.allocate(count * attribDataStride);
attribData.order(SampleView.targetByteOrder);
int maxIndex = -1;
ByteBuffer indexSrc = data;
if (v.indexBuffer != null) {
indexSrc = v.indexBuffer.data;
indexSrc.position(msgData.msg.getArg3());
}
indexSrc.order(SampleView.targetByteOrder);
for (int i = 0; i < count; i++) {
int index = -1;
if (type == GLEnum.GL_UNSIGNED_BYTE) {
byte idx = indexSrc.get();
index = idx & 0xff;
indexData.put(idx);
} else if (type == GLEnum.GL_UNSIGNED_SHORT) {
short idx = indexSrc.getShort();
index = idx & 0xffff;
indexData.putShort(idx);
} else
assert false;
data.get(element);
attribData.put(element);
if (index > maxIndex)
maxIndex = index;
}
code.format(" FILE * attribFile = fopen(\"/sdcard/frame_data.bin\", \"rb\");CHKERR;\n");
code.format(" assert(attribFile);CHKERR;\n");
code.format(" fseek(attribFile, 0x%X, SEEK_SET);CHKERR;\n",
dataOut.getChannel().position());
dataOut.write(indexData.array());
code.format(" %s * const indexData = (%s *)malloc(%d);\n", typeName, typeName,
indexData.capacity());
code.format(" assert(indexData);\n");
code.format(" fread(indexData, %d, 1, attribFile);\n", indexData.capacity());
if (attribDataStride > 0) {
code.format(" glBindBuffer(GL_ARRAY_BUFFER, 0);CHKERR;\n");
for (int i = 0; i < maxAttrib; i++) {
final GLAttribPointer att = v.attribPointers[i];
if (!att.enabled)
continue;
if (att.buffer != null)
continue;
code.format(" char * const attrib%d = (char *)malloc(%d);\n",
i, att.elemSize * (maxIndex + 1));
code.format(" assert(attrib%d);\n", i);
code.format(
" glVertexAttribPointer(%d, %d, %s, %b, %d, attrib%d);CHKERR;\n",
i, att.size, att.type, att.normalized, att.elemSize, i);
}
dataOut.write(attribData.array());
code.format(" for (%s i = 0; i < %d; i++) {\n", typeName, count);
for (int i = 0; i < maxAttrib; i++) {
final GLAttribPointer att = v.attribPointers[i];
if (!att.enabled)
continue;
if (att.buffer != null)
continue;
code.format(
" fread(attrib%d + indexData[i] * %d, %d, 1, attribFile);\n",
i, att.elemSize, att.elemSize);
}
code.format(" }\n");
if (v.attribBuffer != null)
code.format(" glBindBuffer(GL_ARRAY_BUFFER, %d);CHKERR;\n",
v.attribBuffer.name);
}
code.format(" fclose(attribFile);\n");
}
if (v.indexBuffer != null)
code.format(" glDrawElements(%s, %d, %s, (const void *)%d);CHKERR;\n",
mode, count, type, msgData.msg.getArg3());
else {
code.format(" glDrawElements(%s, %d, %s, indexData);CHKERR;\n",
mode, count, type);
code.format(" free(indexData);\n");
}
for (int i = 0; i < maxAttrib; i++) {
final GLAttribPointer att = v.attribPointers[i];
if (!att.enabled)
continue;
if (att.buffer != null)
continue;
code.format(" free(attrib%d);\n", i);
}
code.write("};\n");
}
private void codeGenDraw(final GLServerVertex v, final MessageData msgData)
throws IOException {
final int maxAttrib = msgData.msg.getArg7();
if (maxAttrib < 1) {
code.write("// no vertex data\n");
return;
}
final int count = msgData.attribs[0].length / 4;
final GLEnum mode = GLEnum.valueOf(msgData.msg.getArg0());
final ByteBuffer attribData = ByteBuffer.allocate(maxAttrib * count * 16);
attribData.order(SampleView.targetByteOrder);
for (int i = 0; i < count; i++)
for (int j = 0; j < maxAttrib; j++)
for (int k = 0; k < 4; k++)
attribData.putFloat(msgData.attribs[j][i * 4 + k]);
assert attribData.remaining() == 0;
code.write("{\n");
code.format(" FILE * attribFile = fopen(\"/sdcard/frame_data.bin\", \"rb\");CHKERR;\n");
code.format(" assert(attribFile);CHKERR;\n");
code.format(" fseek(attribFile, 0x%X, SEEK_SET);CHKERR;\n",
dataOut.getChannel().position());
dataOut.write(attribData.array());
code.format(" char * const attribData = (char *)malloc(%d);\n", attribData.capacity());
code.format(" assert(attribData);\n");
code.format(" fread(attribData, %d, 1, attribFile);\n", attribData.capacity());
code.format(" fclose(attribFile);\n");
code.format(" glBindBuffer(GL_ARRAY_BUFFER, 0);CHKERR;\n");
for (int i = 0; i < maxAttrib; i++) {
final GLAttribPointer att = v.attribPointers[i];
assert msgData.attribs[i].length == count * 4;
code.format(
" glVertexAttribPointer(%d, %d, GL_FLOAT, GL_FALSE, %d, attribData + %d);CHKERR;\n",
i, att.size, maxAttrib * 16, i * 16);
}
code.format(" glDrawArrays(%s, 0, %d);CHKERR;\n", mode, count);
code.format(" free(attribData);\n");
if (v.attribBuffer != null)
code.format(" glBindBuffer(GL_ARRAY_BUFFER, %d);CHKERR;\n",
v.attribBuffer.name);
code.write("};\n");
}
private void codeGenFunction(final Context ctx, final MessageData msgData)
throws IOException {
final Message msg = msgData.msg;
String call = MessageFormatter.format(msg, true);
switch (msg.getFunction()) {
case glActiveTexture:
case glAttachShader:
case glBindAttribLocation:
break;
case glBindBuffer:
case glBindFramebuffer:
case glBindRenderbuffer:
case glBindTexture:
codeGenBindNames(msg);
return;
case glBlendColor:
case glBlendEquation:
case glBlendEquationSeparate:
case glBlendFunc:
case glBlendFuncSeparate:
break;
case glBufferData:
call = MessageFormatter.format(msg, true).replace("arg2", "bufferData");
codeGenBufferData(msg.getData().asReadOnlyByteBuffer(), call);
return;
case glBufferSubData:
call = MessageFormatter.format(msg, true).replace("arg3", "bufferData");
codeGenBufferData(msg.getData().asReadOnlyByteBuffer(), call);
return;
case glCheckFramebufferStatus:
case glClear:
case glClearColor:
case glClearDepthf:
case glClearStencil:
case glColorMask:
case glCompileShader:
break;
case glCompressedTexImage2D:
case glCompressedTexSubImage2D:
case glCopyTexImage2D:
case glCopyTexSubImage2D:
codeGenTextureUpload(msg, false);
return;
case glCreateProgram:
namesHeader.format("extern GLuint program_%d;\n", msg.getRet());
namesSource.format("GLuint program_%d = 0;\n", msg.getRet());
code.format("program_%d = glCreateProgram();CHKERR;\n", msg.getRet());
return;
case glCreateShader:
namesHeader.format("extern GLuint shader_%d;\n", msg.getRet());
namesSource.format("GLuint shader_%d = 0;\n", msg.getRet());
code.format("shader_%d = %s;\n", msg.getRet(), call);
return;
case glCullFace:
break;
case glDeleteBuffers:
case glDeleteFramebuffers:
case glDeleteProgram:
programNames.put(msg.getArg0(), 0);
break;
case glDeleteRenderbuffers:
codeGenDeleteNames(msg);
return;
case glDeleteShader:
shaderNames.put(msg.getArg0(), 0);
return;
case glDeleteTextures:
codeGenDeleteNames(msg);
return;
case glDepthFunc:
case glDepthMask:
case glDepthRangef:
case glDetachShader:
case glDisable:
case glDisableVertexAttribArray:
break;
case glDrawArrays:
// CodeGenDraw(ctx.serverVertex, msgData);
codeGenDrawArrays(ctx.serverVertex, msgData);
return;
case glDrawElements:
// CodeGenDraw(ctx.serverVertex, msgData);
codeGenDrawElements(ctx.serverVertex, msgData);
return;
case glEnable:
case glEnableVertexAttribArray:
case glFinish:
case glFlush:
case glFramebufferRenderbuffer:
case glFramebufferTexture2D:
case glFrontFace:
break;
case glGenBuffers:
codeGenGenNames(msg);
return;
case glGenerateMipmap:
break;
case glGenFramebuffers:
case glGenRenderbuffers:
case glGenTextures:
codeGenGenNames(msg);
return;
case glGetActiveAttrib:
case glGetActiveUniform:
case glGetAttachedShaders:
break;
case glGetAttribLocation:
call = String.format("assert(%d == %s)", msg.getRet(), call);
break;
case glGetBooleanv:
case glGetBufferParameteriv:
return; // TODO
case glGetError:
code.write("CHKERR;\n");
return;
case glGetFloatv:
case glGetFramebufferAttachmentParameteriv:
case glGetIntegerv:
case glGetProgramiv:
case glGetProgramInfoLog:
case glGetRenderbufferParameteriv:
case glGetShaderiv:
case glGetShaderInfoLog:
case glGetShaderPrecisionFormat:
case glGetShaderSource:
case glGetString:
case glGetTexParameterfv:
case glGetTexParameteriv:
case glGetUniformfv:
case glGetUniformiv:
return;
case glGetUniformLocation:
call = String.format("assert(%d == %s)", msg.getRet(), call);
break;
case glGetVertexAttribfv:
case glGetVertexAttribiv:
case glGetVertexAttribPointerv:
return; // TODO
case glHint:
case glIsBuffer:
case glIsEnabled:
case glIsFramebuffer:
case glIsProgram:
case glIsRenderbuffer:
case glIsShader:
case glIsTexture:
case glLineWidth:
case glLinkProgram:
case glPixelStorei:
case glPolygonOffset:
break;
case glReadPixels:
return; // TODO
case glReleaseShaderCompiler:
case glRenderbufferStorage:
case glSampleCoverage:
case glScissor:
break;
case glShaderBinary:
return; // TODO
case glShaderSource:
call = String.format(
"glShaderSource(shader_%d, 1, (const char * []){\"%s\"}, NULL)",
msg.getArg0(),
msg.getData().toStringUtf8().replace("\r", "").replace("\n", "\\n\\\n")
.replace("\"", "\\\"")
);
break;
case glStencilFunc:
case glStencilFuncSeparate:
case glStencilMask:
case glStencilMaskSeparate:
case glStencilOp:
case glStencilOpSeparate:
break;
case glTexImage2D:
codeGenTextureUpload(msg, false);
return;
case glTexParameterf:
break;
case glTexParameterfv:
return; // TODO
case glTexParameteri:
break;
case glTexParameteriv:
return; // TODO
case glTexSubImage2D:
codeGenTextureUpload(msg, false);
return;
case glUniform1f:
case glUniform1fv:
case glUniform1i:
case glUniform1iv:
case glUniform2f:
case glUniform2fv:
case glUniform2i:
case glUniform2iv:
case glUniform3f:
case glUniform3fv:
case glUniform3i:
case glUniform3iv:
case glUniform4f:
case glUniform4fv:
case glUniform4i:
case glUniform4iv:
case glUniformMatrix2fv:
case glUniformMatrix3fv:
case glUniformMatrix4fv:
case glUseProgram:
case glValidateProgram:
case glVertexAttrib1f:
case glVertexAttrib1fv:
case glVertexAttrib2f:
case glVertexAttrib2fv:
case glVertexAttrib3f:
case glVertexAttrib3fv:
case glVertexAttrib4f:
case glVertexAttrib4fv:
break;
case glVertexAttribPointer:
// if it's user pointer, then CodeGenDrawArrays/Elements will
// replace it with loaded data just before the draw
call = call.replace("arg5", "(const void *)0x" +
Integer.toHexString(msg.getArg5()));
break;
case glViewport:
break;
case eglSwapBuffers:
return;
default:
assert false;
return;
}
if (call.indexOf("glEnable(/*cap*/ GL_TEXTURE_2D)") >= 0)
return;
else if (call.indexOf("glDisable(/*cap*/ GL_TEXTURE_2D)") >= 0)
return;
else if (call.indexOf("glActiveTexture(/*texture*/ GL_TEXTURE_2D)") >= 0)
return;
code.write(call + ";CHKERR;\n");
}
private void codeGenSetup(final Context ctx) {
try {
codeFile = new FileWriter("frame_setup.cpp", false);
code = new PrintWriter(codeFile);
dataOut = new FileOutputStream("frame_data.bin", false);
namesHeaderFile = new FileWriter("frame_names.h", false);
namesHeader = new PrintWriter(namesHeaderFile);
namesSourceFile = new FileWriter("frame_names.cpp", false);
namesSource = new PrintWriter(namesSourceFile);
} catch (IOException e) {
e.printStackTrace();
assert false;
}
bufferNames = new SparseIntArray();
framebufferNames = new SparseIntArray();
programNames = new SparseIntArray();
textureNames = new SparseIntArray();
shaderNames = new SparseIntArray();
renderbufferNames = new SparseIntArray();
namesHeader.write("#include <stdlib.h>\n");
namesHeader.write("#include <stdio.h>\n");
namesHeader.write("#include <assert.h>\n");
namesHeader.write("#include <GLES2/gl2.h>\n");
namesHeader.write("#include <GLES2/gl2ext.h>\n");
namesHeader.write("#define CHKERR assert(GL_NO_ERROR == glGetError());/**/\n");
namesHeader.write("void FrameSetup();\n");
namesHeader.write("extern const unsigned int FrameCount;\n");
namesHeader.write("extern const GLuint program_0;\n");
namesSource.write("/*\n" +
" * Copyright (C) 2011 The Android Open Source Project\n" +
" *\n" +
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n" +
" * you may not use this file except in compliance with the License.\n" +
" * You may obtain a copy of the License at\n" +
" *\n" +
" * http://www.apache.org/licenses/LICENSE-2.0\n" +
" *\n" +
" * Unless required by applicable law or agreed to in writing, software\n" +
" * distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
" * See the License for the specific language governing permissions and\n" +
" * limitations under the License.\n" +
" */\n" +
"\n" +
"#include <stdlib.h>\n" +
"#include <stdio.h>\n" +
"\n" +
"#include <EGL/egl.h>\n" +
"#include <GLES2/gl2.h>\n" +
"#include <GLES2/gl2ext.h>\n" +
"\n" +
"#include <ui/FramebufferNativeWindow.h>\n" +
"#include <ui/EGLUtils.h>\n" +
"\n" +
"#include <private/ui/android_natives_priv.h>\n" +
"\n" +
"#include <surfaceflinger/Surface.h>\n" +
"#include <surfaceflinger/ISurface.h>\n" +
"#include <surfaceflinger/SurfaceComposerClient.h>\n" +
"\n" +
"using namespace android;\n" +
"\n" +
"static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE)\n" +
"{\n" +
" if (returnVal != EGL_TRUE) {\n" +
" fprintf(stderr, \"%s() returned %d\\n\", op, returnVal);\n" +
" }\n" +
"\n" +
" for (EGLint error = eglGetError(); error != EGL_SUCCESS; error\n" +
" = eglGetError()) {\n" +
" fprintf(stderr, \"after %s() eglError %s (0x%x)\\n\", op, EGLUtils::strerror(error),\n" +
" error);\n" +
" }\n" +
"}\n" +
"\n" +
"static EGLDisplay dpy;\n" +
"static EGLSurface surface;\n" +
"\n" +
"#include \"frame_names.h\"\n" +
"const GLuint program_0 = 0;\n" +
"int main(int argc, char** argv)\n" +
"{\n" +
" EGLBoolean returnValue;\n" +
" EGLConfig myConfig = {0};\n" +
"\n" +
" EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };\n" +
" EGLint majorVersion;\n" +
" EGLint minorVersion;\n" +
" EGLContext context;\n" +
" EGLint w, h;\n" +
"\n" +
"\n" +
" checkEglError(\"<init>\");\n" +
" dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);\n" +
" checkEglError(\"eglGetDisplay\");\n" +
" if (dpy == EGL_NO_DISPLAY) {\n" +
" printf(\"eglGetDisplay returned EGL_NO_DISPLAY.\\n\");\n" +
" return 0;\n" +
" }\n" +
"\n" +
" returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);\n" +
" checkEglError(\"eglInitialize\", returnValue);\n" +
" if (returnValue != EGL_TRUE) {\n" +
" printf(\"eglInitialize failed\\n\");\n" +
" return 0;\n" +
" }\n" +
"\n" +
" sp<SurfaceComposerClient> spClient;\n" +
" sp<SurfaceControl> spControl;\n" +
" sp<Surface> spSurface;\n" +
"\n" +
" // create a client to surfaceflinger\n" +
" spClient = new SurfaceComposerClient();\n" +
"\n" +
" spControl = spClient->createSurface(getpid(), 0, 1280, 752, PIXEL_FORMAT_RGBX_8888);\n" +
" spClient->openTransaction();\n" +
" spControl->setLayer(350000);\n" +
" spControl->show();\n" +
" spClient->closeTransaction();\n" +
"\n" +
" spSurface = spControl->getSurface();\n" +
" EGLNativeWindowType window = spSurface.get();\n" +
"\n" +
" printf(\"window=%p\\n\", window);\n" +
" EGLint attrib_list[] = {\n" +
" EGL_SURFACE_TYPE, EGL_WINDOW_BIT,\n" +
" EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,\n" +
" EGL_BUFFER_SIZE, 32,\n" +
" EGL_RED_SIZE, 8,\n" +
" EGL_GREEN_SIZE, 8,\n" +
" EGL_BLUE_SIZE, 8,\n" +
" EGL_NONE\n" +
" };\n" +
"\n" +
" EGLConfig configs[12] = {0};\n" +
" int num_config = -1;\n" +
" eglChooseConfig(dpy, attrib_list, configs, sizeof(configs) / sizeof(*configs), &num_config);\n" +
" printf(\"eglChooseConfig %d \\n\", num_config);\n" +
"\n" +
" surface = eglCreateWindowSurface(dpy, configs[0], window, NULL);\n" +
" checkEglError(\"eglCreateWindowSurface\");\n" +
" if (surface == EGL_NO_SURFACE) {\n" +
" printf(\"gelCreateWindowSurface failed.\\n\");\n" +
" return 0;\n" +
" }\n" +
"\n" +
" context = eglCreateContext(dpy, configs[0], EGL_NO_CONTEXT, context_attribs);\n" +
" checkEglError(\"eglCreateContext\");\n" +
" if (context == EGL_NO_CONTEXT) {\n" +
" printf(\"eglCreateContext failed\\n\");\n" +
" return 0;\n" +
" }\n" +
" printf(\"context=%p \\n\", context);\n" +
"\n" +
" returnValue = eglMakeCurrent(dpy, surface, surface, context);\n" +
" checkEglError(\"eglMakeCurrent\", returnValue);\n" +
" if (returnValue != EGL_TRUE) {\n" +
" return 0;\n" +
" }\n" +
"\n" +
" glClearColor(1,1,1,1);\n" +
" glClear(GL_COLOR_BUFFER_BIT);\n" +
"\n" +
" FrameSetup();\n" +
" while (true)\n" +
" for (unsigned int i = 0; i < FrameCount; i++) {\n" +
" Frames[i]();\n" +
" eglSwapBuffers(dpy, surface);\n" +
" printf(\"press ENTER after Frame%d \\n\", i);\n" +
" getchar();\n" +
" }\n" +
"\n" +
" return 0;\n" +
"}");
code.write("#include \"frame_names.h\"\n");
code.write("void FrameSetup(){\n");
codeGenServerState(ctx.serverState);
codeGenServerShader(ctx.serverShader);
codeGenServerTexture(ctx.serverTexture, true);
codeGenServerVertex(ctx.serverVertex);
code.write("}\n");
try {
codeFile.close();
makeFile = new FileWriter("Android.mk", false);
make = new PrintWriter(makeFile);
make.write("LOCAL_PATH:= $(call my-dir)\n" +
"include $(CLEAR_VARS)\n" +
"LOCAL_SRC_FILES := \\\n");
} catch (IOException e) {
e.printStackTrace();
assert false;
}
}
private void codeGenCleanup() {
make.write(" frame_setup.cpp \\\n");
make.write(" frame_names.cpp \\\n");
make.write("#\n");
make.write(
"LOCAL_SHARED_LIBRARIES := \\\n" +
" libcutils \\\n" +
" libutils \\\n" +
" libEGL \\\n" +
" libGLESv2 \\\n" +
" libui \\\n" +
" libhardware \\\n" +
" libgui\n" +
"\n" +
"LOCAL_MODULE:= gles2dbg\n" +
"\n" +
"LOCAL_MODULE_TAGS := optional\n" +
"\n" +
"LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -O0 -g -DDEBUG -UNDEBUG\n" +
"\n" +
"include $(BUILD_EXECUTABLE)");
try {
dataOut.flush();
dataOut.close();
codeFile.close();
makeFile.close();
namesHeaderFile.close();
namesSourceFile.close();
} catch (IOException e) {
e.printStackTrace();
assert false;
}
dataOut = null;
code = null;
codeFile = null;
make = null;
makeFile = null;
bufferNames = null;
framebufferNames = null;
programNames = null;
textureNames = null;
shaderNames = null;
renderbufferNames = null;
}
private DebugContext dbgCtx;
private int count;
private IProgressMonitor progress;
@Override
public void run(IProgressMonitor monitor) {
progress.beginTask("CodeGenFrames", count + 2);
Context ctx = dbgCtx.getFrame(0).startContext.clone();
codeGenSetup(ctx);
progress.worked(1);
for (int i = 0; i < count; i++) {
try {
codeFile = new FileWriter("frame" + i + ".cpp", false);
code = new PrintWriter(codeFile);
} catch (IOException e1) {
e1.printStackTrace();
assert false;
}
make.format(" frame%d.cpp \\\n", i);
code.write("#include \"frame_names.h\"\n");
code.format("void Frame%d(){\n", i);
final Frame frame = dbgCtx.getFrame(i);
for (int j = 0; j < frame.size(); j++) {
final MessageData msgData = frame.get(j);
code.format("/* frame function %d: %s %s*/\n", j, msgData.msg.getFunction(),
MessageFormatter.format(msgData.msg, false));
ctx.processMessage(msgData.msg);
try {
codeGenFunction(ctx, msgData);
} catch (IOException e) {
e.printStackTrace();
assert false;
}
}
code.write("}\n");
try {
codeFile.close();
} catch (IOException e) {
e.printStackTrace();
assert false;
}
progress.worked(1);
}
for (int i = 0; i < count; i++)
namesHeader.format("void Frame%d();\n", i);
namesHeader.format("extern void (* Frames[%d])();\n", count);
namesSource.format("void (* Frames[%d])() = {\n", count);
for (int i = 0; i < count; i++) {
namesSource.format(" Frame%d,\n", i);
}
namesSource.write("};\n");
namesSource.format("const unsigned int FrameCount = %d;\n", count);
codeGenCleanup();
progress.worked(1);
}
void codeGenFrames(final DebugContext dbgCtx, int count, final Shell shell) {
this.dbgCtx = dbgCtx;
this.count = count;
ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell);
this.progress = dialog.getProgressMonitor();
try {
dialog.run(false, true, this);
} catch (InvocationTargetException e) {
e.printStackTrace();
assert false;
} catch (InterruptedException e) {
e.printStackTrace();
}
this.dbgCtx = null;
this.count = 0;
progress = null;
}
void codeGenFrame(final Frame frame) {
Context ctx = frame.startContext.clone();
codeGenSetup(ctx);
try {
codeFile = new FileWriter("frame0.cpp", false);
code = new PrintWriter(codeFile);
} catch (IOException e1) {
e1.printStackTrace();
assert false;
}
make.format(" frame0.cpp \\\n");
code.write("#include \"frame_names.h\"\n");
code.format("void Frame0(){\n");
for (int i = 0; i < frame.size(); i++) {
final MessageData msgData = frame.get(i);
code.format("/* frame function %d: %s %s*/\n", i, msgData.msg.getFunction(),
MessageFormatter.format(msgData.msg, false));
ctx.processMessage(msgData.msg);
try {
codeGenFunction(ctx, msgData);
} catch (IOException e) {
e.printStackTrace();
assert false;
}
}
code.write("}\n");
namesHeader.write("void Frame0();\n");
namesHeader.write("extern void (* Frames[1])();\n");
namesSource.write("void (* Frames[1])() = {Frame0};\n");
namesSource.write("const unsigned int FrameCount = 1;\n");
codeGenCleanup();
}
}