aboutsummaryrefslogtreecommitdiffstats
path: root/emulator/opengl/host/tools
diff options
context:
space:
mode:
authorJesse Hall <jessehall@google.com>2012-04-16 12:49:39 -0700
committerJesse Hall <jessehall@google.com>2012-04-16 15:54:18 -0700
commitce6c3389061fb9fcdefc94fab2044a8e11600b52 (patch)
treefedd1a11cbd21ec14bf00be83b8712054f8c5506 /emulator/opengl/host/tools
parentad0111a77b0f0908cc945dc6e8e8949b75cb8886 (diff)
downloadsdk-ce6c3389061fb9fcdefc94fab2044a8e11600b52.tar.gz
sdk-ce6c3389061fb9fcdefc94fab2044a8e11600b52.tar.bz2
sdk-ce6c3389061fb9fcdefc94fab2044a8e11600b52.zip
Move emulator GLES from development.git to sdk.git
The emulator GLES support has two interfaces: a host shared library interface used by QEMU, and a protocol between the platform and the host. The host library interface is not versioned; QEMU and the GLES renderer must match. The protocol on the other hand must be backwards compatible: a new GLES renderer must support an older platform image. Thus for branching purposes it makes more sense to put the GLES renderer in sdk.git, which is branched along with qemu.git for SDK releases. Platform images will be built against the protocol version in the platform branch of sdk.git. Change-Id: I2c3bce627ecfd0a4b3e688d1839fe10755a21e58
Diffstat (limited to 'emulator/opengl/host/tools')
-rw-r--r--emulator/opengl/host/tools/emugen/Android.mk26
-rw-r--r--emulator/opengl/host/tools/emugen/ApiGen.cpp1081
-rw-r--r--emulator/opengl/host/tools/emugen/ApiGen.h95
-rw-r--r--emulator/opengl/host/tools/emugen/EntryPoint.cpp376
-rw-r--r--emulator/opengl/host/tools/emugen/EntryPoint.h67
-rw-r--r--emulator/opengl/host/tools/emugen/README332
-rw-r--r--emulator/opengl/host/tools/emugen/TypeFactory.cpp156
-rw-r--r--emulator/opengl/host/tools/emugen/TypeFactory.h37
-rw-r--r--emulator/opengl/host/tools/emugen/Var.h110
-rw-r--r--emulator/opengl/host/tools/emugen/VarType.h78
-rw-r--r--emulator/opengl/host/tools/emugen/errors.h24
-rw-r--r--emulator/opengl/host/tools/emugen/main.cpp164
-rw-r--r--emulator/opengl/host/tools/emugen/strUtils.cpp49
-rw-r--r--emulator/opengl/host/tools/emugen/strUtils.h33
14 files changed, 2628 insertions, 0 deletions
diff --git a/emulator/opengl/host/tools/emugen/Android.mk b/emulator/opengl/host/tools/emugen/Android.mk
new file mode 100644
index 000000000..ad9ab06f8
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/Android.mk
@@ -0,0 +1,26 @@
+ifneq ($(HOST_OS),windows)
+
+LOCAL_PATH:=$(call my-dir)
+
+$(call emugl-begin-host-executable,emugen)
+
+ LOCAL_SRC_FILES := \
+ ApiGen.cpp \
+ EntryPoint.cpp \
+ main.cpp \
+ strUtils.cpp \
+ TypeFactory.cpp
+
+$(call emugl-end-module)
+
+# The location of the emugen host tool that is used to generate wire
+# protocol encoders/ decoders. This variable is used by other emugl modules.
+EMUGL_EMUGEN := $(LOCAL_BUILT_MODULE)
+
+else # windows build
+
+# on windows use the build host emugen executable
+# (that will be the linux exeutable when using mingw build)
+EMUGL_EMUGEN := $(BUILD_OUT_EXECUTABLES)/emugen
+
+endif
diff --git a/emulator/opengl/host/tools/emugen/ApiGen.cpp b/emulator/opengl/host/tools/emugen/ApiGen.cpp
new file mode 100644
index 000000000..bf2d2445d
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/ApiGen.cpp
@@ -0,0 +1,1081 @@
+/*
+* Copyright (C) 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.
+*/
+#include "ApiGen.h"
+#include "EntryPoint.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "strUtils.h"
+#include <errno.h>
+#include <sys/types.h>
+
+/* Define this to 1 to enable support for the 'isLarge' variable flag
+ * that instructs the encoder to send large data buffers by a direct
+ * write through the pipe (i.e. without copying it into a temporary
+ * buffer. This has definite performance benefits when using a QEMU Pipe.
+ *
+ * Set to 0 otherwise.
+ */
+#define WITH_LARGE_SUPPORT 1
+
+EntryPoint * ApiGen::findEntryByName(const std::string & name)
+{
+ EntryPoint * entry = NULL;
+
+ size_t n = this->size();
+ for (size_t i = 0; i < n; i++) {
+ if (at(i).name() == name) {
+ entry = &(at(i));
+ break;
+ }
+ }
+ return entry;
+}
+
+void ApiGen::printHeader(FILE *fp) const
+{
+ fprintf(fp, "// Generated Code - DO NOT EDIT !!\n");
+ fprintf(fp, "// generated by 'emugen'\n");
+}
+
+int ApiGen::genProcTypes(const std::string &filename, SideType side)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+ printHeader(fp);
+
+ const char* basename = m_basename.c_str();
+
+ fprintf(fp, "#ifndef __%s_%s_proc_t_h\n", basename, sideString(side));
+ fprintf(fp, "#define __%s_%s_proc_t_h\n", basename, sideString(side));
+ fprintf(fp, "\n\n");
+ fprintf(fp, "\n#include \"%s_types.h\"\n",basename);
+ fprintf(fp, "#ifndef %s_APIENTRY\n",basename);
+ fprintf(fp, "#define %s_APIENTRY \n",basename);
+ fprintf(fp, "#endif\n");
+
+
+ for (size_t i = 0; i < size(); i++) {
+ EntryPoint *e = &at(i);
+
+ fprintf(fp, "typedef ");
+ e->retval().printType(fp);
+ fprintf(fp, " (%s_APIENTRY *%s_%s_proc_t) (", basename, e->name().c_str(), sideString(side));
+ if (side == CLIENT_SIDE) { fprintf(fp, "void * ctx"); }
+ if (e->customDecoder() && side == SERVER_SIDE) { fprintf(fp, "void *ctx"); }
+
+ VarsArray & evars = e->vars();
+ size_t n = evars.size();
+
+ for (size_t j = 0; j < n; j++) {
+ if (!evars[j].isVoid()) {
+ if (j != 0 || side == CLIENT_SIDE || (side == SERVER_SIDE && e->customDecoder())) fprintf(fp, ", ");
+ evars[j].printType(fp);
+ }
+ }
+ fprintf(fp, ");\n");
+ }
+ fprintf(fp, "\n\n#endif\n");
+ return 0;
+}
+
+int ApiGen::genFuncTable(const std::string &filename, SideType side)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+ printHeader(fp);
+
+ fprintf(fp, "#ifndef __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side));
+ fprintf(fp, "#define __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side));
+ fprintf(fp, "\n\n");
+ fprintf(fp, "static struct _%s_funcs_by_name {\n", m_basename.c_str());
+ fprintf(fp,
+ "\tconst char *name;\n" \
+ "\tvoid *proc;\n" \
+ "} %s_funcs_by_name[] = {\n", m_basename.c_str());
+
+
+ for (size_t i = 0; i < size(); i++) {
+ EntryPoint *e = &at(i);
+ if (e->notApi()) continue;
+ fprintf(fp, "\t{\"%s\", (void*)%s},\n", e->name().c_str(), e->name().c_str());
+ }
+ fprintf(fp, "};\n");
+ fprintf(fp, "static int %s_num_funcs = sizeof(%s_funcs_by_name) / sizeof(struct _%s_funcs_by_name);\n",
+ m_basename.c_str(), m_basename.c_str(), m_basename.c_str());
+ fprintf(fp, "\n\n#endif\n");
+ return 0;
+}
+
+
+int ApiGen::genContext(const std::string & filename, SideType side)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+ printHeader(fp);
+
+ fprintf(fp, "#ifndef __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
+ fprintf(fp, "#define __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
+
+ // fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str());
+ fprintf(fp, "\n#include \"%s_%s_proc.h\"\n", m_basename.c_str(), sideString(side));
+
+ StringVec & contextHeaders = side == CLIENT_SIDE ? m_clientContextHeaders : m_serverContextHeaders;
+ for (size_t i = 0; i < contextHeaders.size(); i++) {
+ fprintf(fp, "#include %s\n", contextHeaders[i].c_str());
+ }
+ fprintf(fp, "\n");
+
+ fprintf(fp, "\nstruct %s_%s_context_t {\n\n", m_basename.c_str(), sideString(side));
+ for (size_t i = 0; i < size(); i++) {
+ EntryPoint *e = &at(i);
+ fprintf(fp, "\t%s_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str());
+ }
+ // accessors
+ fprintf(fp, "\t//Accessors \n");
+
+ for (size_t i = 0; i < size(); i++) {
+ EntryPoint *e = &at(i);
+ const char *n = e->name().c_str();
+ const char *s = sideString(side);
+ fprintf(fp, "\tvirtual %s_%s_proc_t set_%s(%s_%s_proc_t f) { %s_%s_proc_t retval = %s; %s = f; return retval;}\n", n, s, n, n, s, n, s, n, n);
+ }
+
+ // virtual destructor
+ fprintf(fp, "\t virtual ~%s_%s_context_t() {}\n", m_basename.c_str(), sideString(side));
+ // accessor
+ if (side == CLIENT_SIDE || side == WRAPPER_SIDE) {
+ fprintf(fp, "\n\ttypedef %s_%s_context_t *CONTEXT_ACCESSOR_TYPE(void);\n",
+ m_basename.c_str(), sideString(side));
+ fprintf(fp, "\tstatic void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);\n");
+ }
+
+ // init function
+ fprintf(fp, "\tint initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);\n");
+
+ //client site set error virtual func
+ if (side == CLIENT_SIDE) {
+ fprintf(fp, "\tvirtual void setError(unsigned int error){};\n");
+ fprintf(fp, "\tvirtual unsigned int getError(){ return 0; };\n");
+ }
+
+ fprintf(fp, "};\n");
+
+ fprintf(fp, "\n#endif\n");
+ fclose(fp);
+ return 0;
+}
+
+int ApiGen::genEntryPoints(const std::string & filename, SideType side)
+{
+
+ if (side != CLIENT_SIDE && side != WRAPPER_SIDE) {
+ fprintf(stderr, "Entry points are only defined for Client and Wrapper components\n");
+ return -999;
+ }
+
+
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return errno;
+ }
+
+ printHeader(fp);
+ fprintf(fp, "#include <stdio.h>\n");
+ fprintf(fp, "#include <stdlib.h>\n");
+ fprintf(fp, "#include \"%s_%s_context.h\"\n", m_basename.c_str(), sideString(side));
+ fprintf(fp, "\n");
+
+ fprintf(fp, "#ifndef GL_TRUE\n");
+ fprintf(fp, "extern \"C\" {\n");
+
+ for (size_t i = 0; i < size(); i++) {
+ fprintf(fp, "\t"); at(i).print(fp, false); fprintf(fp, ";\n");
+ }
+ fprintf(fp, "};\n\n");
+ fprintf(fp, "#endif\n");
+
+ fprintf(fp, "#ifndef GET_CONTEXT\n");
+ fprintf(fp, "static %s_%s_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;\n",
+ m_basename.c_str(), sideString(side));
+
+ fprintf(fp,
+ "void %s_%s_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }\n",
+ m_basename.c_str(), sideString(side));
+ fprintf(fp, "#define GET_CONTEXT %s_%s_context_t * ctx = getCurrentContext() \n",
+ m_basename.c_str(), sideString(side));
+ fprintf(fp, "#endif\n\n");
+
+
+ for (size_t i = 0; i < size(); i++) {
+ EntryPoint *e = &at(i);
+ e->print(fp);
+ fprintf(fp, "{\n");
+ fprintf(fp, "\tGET_CONTEXT; \n");
+
+ bool shouldReturn = !e->retval().isVoid();
+ bool shouldCallWithContext = (side == CLIENT_SIDE);
+ //param check
+ if (shouldCallWithContext) {
+ for (size_t j=0; j<e->vars().size(); j++) {
+ if (e->vars()[j].paramCheckExpression() != "")
+ fprintf(fp, "\t%s\n", e->vars()[j].paramCheckExpression().c_str());
+ }
+ }
+ fprintf(fp, "\t %sctx->%s(%s",
+ shouldReturn ? "return " : "",
+ e->name().c_str(),
+ shouldCallWithContext ? "ctx" : "");
+ size_t nvars = e->vars().size();
+
+ for (size_t j = 0; j < nvars; j++) {
+ if (!e->vars()[j].isVoid()) {
+ fprintf(fp, "%s %s",
+ j != 0 || shouldCallWithContext ? "," : "",
+ e->vars()[j].name().c_str());
+ }
+ }
+ fprintf(fp, ");\n");
+ fprintf(fp, "}\n\n");
+ }
+ fclose(fp);
+ return 0;
+}
+
+
+int ApiGen::genOpcodes(const std::string &filename)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return errno;
+ }
+
+ printHeader(fp);
+ fprintf(fp, "#ifndef __GUARD_%s_opcodes_h_\n", m_basename.c_str());
+ fprintf(fp, "#define __GUARD_%s_opcodes_h_\n\n", m_basename.c_str());
+ for (size_t i = 0; i < size(); i++) {
+ fprintf(fp, "#define OP_%s \t\t\t\t\t%u\n", at(i).name().c_str(), (unsigned int)i + m_baseOpcode);
+ }
+ fprintf(fp, "#define OP_last \t\t\t\t\t%u\n", (unsigned int)size() + m_baseOpcode);
+ fprintf(fp,"\n\n#endif\n");
+ fclose(fp);
+ return 0;
+
+}
+int ApiGen::genAttributesTemplate(const std::string &filename )
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+
+ for (size_t i = 0; i < size(); i++) {
+ if (at(i).hasPointers()) {
+ fprintf(fp, "#");
+ at(i).print(fp);
+ fprintf(fp, "%s\n\n", at(i).name().c_str());
+ }
+ }
+ fclose(fp);
+ return 0;
+}
+
+int ApiGen::genEncoderHeader(const std::string &filename)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+
+ printHeader(fp);
+ std::string classname = m_basename + "_encoder_context_t";
+
+ fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
+ fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
+
+ fprintf(fp, "#include \"IOStream.h\"\n");
+ fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(CLIENT_SIDE));
+
+ for (size_t i = 0; i < m_encoderHeaders.size(); i++) {
+ fprintf(fp, "#include %s\n", m_encoderHeaders[i].c_str());
+ }
+ fprintf(fp, "\n");
+
+ fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
+ classname.c_str(), m_basename.c_str(), sideString(CLIENT_SIDE));
+ fprintf(fp, "\tIOStream *m_stream;\n\n");
+
+ fprintf(fp, "\t%s(IOStream *stream);\n\n", classname.c_str());
+ fprintf(fp, "\n};\n\n");
+
+ fprintf(fp,"extern \"C\" {\n");
+
+ for (size_t i = 0; i < size(); i++) {
+ fprintf(fp, "\t");
+ at(i).print(fp, false, "_enc", /* classname + "::" */"", "void *self");
+ fprintf(fp, ";\n");
+ }
+ fprintf(fp, "};\n");
+ fprintf(fp, "#endif");
+
+ fclose(fp);
+ return 0;
+}
+
+// Format the byte length expression for a given variable into a user-provided buffer
+// If the variable type is not a pointer, this is simply its size as a decimal constant
+// If the variable is a pointer, this will be an expression provided by the .attrib file
+// through the 'len' attribute.
+//
+// Returns 1 if the variable is a pointer, 0 otherwise
+//
+static int getVarEncodingSizeExpression(Var& var, EntryPoint* e, char* buff, size_t bufflen)
+{
+ int ret = 0;
+ if (!var.isPointer()) {
+ snprintf(buff, bufflen, "%u", (unsigned int) var.type()->bytes());
+ } else {
+ ret = 1;
+ const char* lenExpr = var.lenExpression().c_str();
+ const char* varname = var.name().c_str();
+ if (e != NULL && lenExpr[0] == '\0') {
+ fprintf(stderr, "%s: data len is undefined for '%s'\n",
+ e->name().c_str(), varname);
+ }
+ if (var.nullAllowed()) {
+ snprintf(buff, bufflen, "((%s != NULL) ? %s : 0)", varname, lenExpr);
+ } else {
+ snprintf(buff, bufflen, "%s", lenExpr);
+ }
+ }
+ return ret;
+}
+
+static int writeVarEncodingSize(Var& var, FILE* fp)
+{
+ int ret = 0;
+ if (!var.isPointer()) {
+ fprintf(fp, "%u", (unsigned int) var.type()->bytes());
+ } else {
+ ret = 1;
+ fprintf(fp, "__size_%s", var.name().c_str());
+ }
+ return ret;
+}
+
+
+
+static void writeVarEncodingExpression(Var& var, FILE* fp)
+{
+ const char* varname = var.name().c_str();
+
+ if (var.isPointer()) {
+ // encode a pointer header
+ fprintf(fp, "\t*(unsigned int *)(ptr) = __size_%s; ptr += 4;\n", varname);
+
+ Var::PointerDir dir = var.pointerDir();
+ if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
+ if (var.nullAllowed()) {
+ fprintf(fp, "\tif (%s != NULL) ", varname);
+ } else {
+ fprintf(fp, "\t");
+ }
+
+ if (var.packExpression().size() != 0) {
+ fprintf(fp, "%s;", var.packExpression().c_str());
+ } else {
+ fprintf(fp, "memcpy(ptr, %s, __size_%s);",
+ varname, varname);
+ }
+
+ fprintf(fp, "ptr += __size_%s;\n", varname);
+ }
+ } else {
+ // encode a non pointer variable
+ if (!var.isVoid()) {
+ fprintf(fp, "\t*(%s *) (ptr) = %s; ptr += %u;\n",
+ var.type()->name().c_str(), varname,
+ (uint) var.type()->bytes());
+ }
+ }
+}
+
+#if WITH_LARGE_SUPPORT
+static void writeVarLargeEncodingExpression(Var& var, FILE* fp)
+{
+ const char* varname = var.name().c_str();
+
+ fprintf(fp, "\tstream->writeFully(&__size_%s,4);\n", varname);
+ if (var.nullAllowed()) {
+ fprintf(fp, "\tif (%s != NULL) ", varname);
+ } else {
+ fprintf(fp, "\t");
+ }
+ if (var.writeExpression() != "") {
+ fprintf(fp, "%s", var.writeExpression().c_str());
+ } else {
+ fprintf(fp, "stream->writeFully(%s, __size_%s)", varname, varname);
+ }
+ fprintf(fp, ";\n");
+}
+#endif /* WITH_LARGE_SUPPORT */
+
+int ApiGen::genEncoderImpl(const std::string &filename)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+
+ printHeader(fp);
+ fprintf(fp, "\n\n#include <string.h>\n");
+ fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
+ fprintf(fp, "#include \"%s_enc.h\"\n\n\n", m_basename.c_str());
+ fprintf(fp, "#include <stdio.h>\n");
+ std::string classname = m_basename + "_encoder_context_t";
+ size_t n = size();
+
+ // unsupport printout
+ fprintf(fp,
+ "static void enc_unsupported()\n{\n\tALOGE(\"Function is unsupported\\n\");\n}\n\n");
+
+ // entry points;
+ for (size_t i = 0; i < n; i++) {
+ EntryPoint *e = &at(i);
+
+ if (e->unsupported()) continue;
+
+
+ e->print(fp, true, "_enc", /* classname + "::" */"", "void *self");
+ fprintf(fp, "{\n");
+
+// fprintf(fp, "\n\tDBG(\">>>> %s\\n\");\n", e->name().c_str());
+ fprintf(fp, "\n\t%s *ctx = (%s *)self;\n",
+ classname.c_str(),
+ classname.c_str());
+ fprintf(fp, "\tIOStream *stream = ctx->m_stream;\n\n");
+ VarsArray & evars = e->vars();
+ size_t maxvars = evars.size();
+ size_t j;
+
+ char buff[256];
+
+ // Define the __size_XXX variables that contain the size of data
+ // associated with pointers.
+ for (j = 0; j < maxvars; j++) {
+ Var& var = evars[j];
+
+ if (!var.isPointer())
+ continue;
+
+ const char* varname = var.name().c_str();
+ fprintf(fp, "\tconst unsigned int __size_%s = ", varname);
+
+ getVarEncodingSizeExpression(var, e, buff, sizeof(buff));
+ fprintf(fp, "%s;\n", buff);
+ }
+
+#if WITH_LARGE_SUPPORT
+ // We need to take care of 'isLarge' variable in a special way
+ // Anything before an isLarge variable can be packed into a single
+ // buffer, which is then commited. Each isLarge variable is a pointer
+ // to data that can be written to directly through the pipe, which
+ // will be instant when using a QEMU pipe
+
+ size_t nvars = 0;
+ size_t npointers = 0;
+
+ // First, compute the total size, 8 bytes for the opcode + payload size
+ fprintf(fp, "\t unsigned char *ptr;\n");
+ fprintf(fp, "\t const size_t packetSize = 8");
+
+ for (j = 0; j < maxvars; j++) {
+ fprintf(fp, " + ");
+ npointers += writeVarEncodingSize(evars[j], fp);
+ }
+ if (npointers > 0) {
+ fprintf(fp, " + %zu*4", npointers);
+ }
+ fprintf(fp, ";\n");
+
+ // We need to divide the packet into fragments. Each fragment contains
+ // either copied arguments to a temporary buffer, or direct writes for
+ // large variables.
+ //
+ // The first fragment must also contain the opcode+payload_size
+ //
+ nvars = 0;
+ while (nvars < maxvars || maxvars == 0) {
+
+ // Skip over non-large fields
+ for (j = nvars; j < maxvars; j++) {
+ if (evars[j].isLarge())
+ break;
+ }
+
+ // Write a fragment if needed.
+ if (nvars == 0 || j > nvars) {
+ const char* plus = "";
+
+ if (nvars == 0 && j == maxvars) {
+ // Simple shortcut for the common case where we don't have large variables;
+ fprintf(fp, "\tptr = stream->alloc(packetSize);\n");
+
+ } else {
+ // allocate buffer from the stream until the first large variable
+ fprintf(fp, "\tptr = stream->alloc(");
+ plus = "";
+
+ if (nvars == 0) {
+ fprintf(fp,"8"); plus = " + ";
+ }
+ if (j > nvars) {
+ npointers = 0;
+ for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
+ fprintf(fp, "%s", plus); plus = " + ";
+ npointers += writeVarEncodingSize(evars[j], fp);
+ }
+ if (npointers > 0) {
+ fprintf(fp, "%s%zu*4", plus, npointers); plus = " + ";
+ }
+ }
+ fprintf(fp,");\n");
+ }
+
+ // encode packet header if needed.
+ if (nvars == 0) {
+ fprintf(fp, "\t*(unsigned int *)(ptr) = OP_%s; ptr += 4;\n", e->name().c_str());
+ fprintf(fp, "\t*(unsigned int *)(ptr) = (unsigned int) packetSize; ptr += 4;\n");
+ }
+
+ if (maxvars == 0)
+ break;
+
+ // encode non-large fields in this fragment
+ for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
+ writeVarEncodingExpression(evars[j],fp);
+ }
+
+ // Ensure the fragment is commited if it is followed by a large variable
+ if (j < maxvars) {
+ fprintf(fp, "\tstream->flush();\n");
+ }
+ }
+
+ // If we have one or more large variables, write them directly.
+ // As size + data
+ for ( ; j < maxvars && evars[j].isLarge(); j++) {
+ writeVarLargeEncodingExpression(evars[j], fp);
+ }
+
+ nvars = j;
+ }
+
+#else /* !WITH_LARGE_SUPPORT */
+ size_t nvars = evars.size();
+ size_t npointers = 0;
+ fprintf(fp, "\t const size_t packetSize = 8");
+ for (size_t j = 0; j < nvars; j++) {
+ npointers += getVarEncodingSizeExpression(evars[j],e,buff,sizeof(buff));
+ fprintf(fp, " + %s", buff);
+ }
+ fprintf(fp, " + %u * 4;\n", (unsigned int) npointers);
+
+ // allocate buffer from the stream;
+ fprintf(fp, "\t unsigned char *ptr = stream->alloc(packetSize);\n\n");
+
+ // encode into the stream;
+ fprintf(fp, "\t*(unsigned int *)(ptr) = OP_%s; ptr += 4;\n", e->name().c_str());
+ fprintf(fp, "\t*(unsigned int *)(ptr) = (unsigned int) packetSize; ptr += 4;\n\n");
+
+ // out variables
+ for (size_t j = 0; j < nvars; j++) {
+ writeVarEncodingExpression(evars[j], fp);
+ }
+#endif /* !WITH_LARGE_SUPPORT */
+
+ // in variables;
+ for (size_t j = 0; j < nvars; j++) {
+ if (evars[j].isPointer()) {
+ Var::PointerDir dir = evars[j].pointerDir();
+ if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) {
+ const char* varname = evars[j].name().c_str();
+ if (evars[j].nullAllowed()) {
+ fprintf(fp, "\tif (%s != NULL) ",varname);
+ } else {
+ fprintf(fp, "\t");
+ }
+ fprintf(fp, "stream->readback(%s, __size_%s);\n",
+ varname, varname);
+ }
+ }
+ }
+//XXX fprintf(fp, "\n\tDBG(\"<<<< %s\\n\");\n", e->name().c_str());
+ // todo - return value for pointers
+ if (e->retval().isPointer()) {
+ fprintf(stderr, "WARNING: %s : return value of pointer is unsupported\n",
+ e->name().c_str());
+ fprintf(fp, "\t return NULL;\n");
+ } else if (e->retval().type()->name() != "void") {
+ fprintf(fp, "\n\t%s retval;\n", e->retval().type()->name().c_str());
+ fprintf(fp, "\tstream->readback(&retval, %u);\n",(uint) e->retval().type()->bytes());
+ fprintf(fp, "\treturn retval;\n");
+ }
+ fprintf(fp, "}\n\n");
+ }
+
+ // constructor
+ fprintf(fp, "%s::%s(IOStream *stream)\n{\n", classname.c_str(), classname.c_str());
+ fprintf(fp, "\tm_stream = stream;\n\n");
+
+ for (size_t i = 0; i < n; i++) {
+ EntryPoint *e = &at(i);
+ if (e->unsupported()) {
+ fprintf(fp, "\tset_%s((%s_%s_proc_t)(enc_unsupported));\n", e->name().c_str(), e->name().c_str(), sideString(CLIENT_SIDE));
+ } else {
+ fprintf(fp, "\tset_%s(%s_enc);\n", e->name().c_str(), e->name().c_str());
+ }
+ /**
+ if (e->unsupsported()) {
+ fprintf(fp, "\tmemcpy((void *)(&%s), (const void *)(&enc_unsupported), sizeof(%s));\n",
+ e->name().c_str(),
+ e->name().c_str());
+ } else {
+ fprintf(fp, "\t%s = %s_enc;\n", e->name().c_str(), e->name().c_str());
+ }
+ **/
+ }
+ fprintf(fp, "}\n\n");
+
+ fclose(fp);
+ return 0;
+}
+
+
+int ApiGen::genDecoderHeader(const std::string &filename)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+
+ printHeader(fp);
+ std::string classname = m_basename + "_decoder_context_t";
+
+ fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
+ fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
+
+ fprintf(fp, "#include \"IOStream.h\" \n");
+ fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(SERVER_SIDE));
+
+ for (size_t i = 0; i < m_decoderHeaders.size(); i++) {
+ fprintf(fp, "#include %s\n", m_decoderHeaders[i].c_str());
+ }
+ fprintf(fp, "\n");
+
+ fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
+ classname.c_str(), m_basename.c_str(), sideString(SERVER_SIDE));
+ fprintf(fp, "\tsize_t decode(void *buf, size_t bufsize, IOStream *stream);\n");
+ fprintf(fp, "\n};\n\n");
+ fprintf(fp, "#endif\n");
+
+ fclose(fp);
+ return 0;
+}
+
+int ApiGen::genContextImpl(const std::string &filename, SideType side)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+ printHeader(fp);
+
+ std::string classname = m_basename + "_" + sideString(side) + "_context_t";
+ size_t n = size();
+ fprintf(fp, "\n\n#include <string.h>\n");
+ fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(side));
+ fprintf(fp, "#include <stdio.h>\n\n");
+
+ // init function;
+ fprintf(fp, "int %s::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)\n{\n", classname.c_str());
+ fprintf(fp, "\tvoid *ptr;\n\n");
+ for (size_t i = 0; i < n; i++) {
+ EntryPoint *e = &at(i);
+ fprintf(fp, "\tptr = getProc(\"%s\", userData); set_%s((%s_%s_proc_t)ptr);\n",
+ e->name().c_str(),
+ e->name().c_str(),
+ e->name().c_str(),
+ sideString(side));
+
+ }
+ fprintf(fp, "\treturn 0;\n");
+ fprintf(fp, "}\n\n");
+ fclose(fp);
+ return 0;
+}
+
+int ApiGen::genDecoderImpl(const std::string &filename)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+
+ printHeader(fp);
+
+ std::string classname = m_basename + "_decoder_context_t";
+
+ size_t n = size();
+
+ fprintf(fp, "\n\n#include <string.h>\n");
+ fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
+ fprintf(fp, "#include \"%s_dec.h\"\n\n\n", m_basename.c_str());
+ fprintf(fp, "#include <stdio.h>\n\n");
+ fprintf(fp, "typedef unsigned int tsize_t; // Target \"size_t\", which is 32-bit for now. It may or may not be the same as host's size_t when emugen is compiled.\n\n");
+
+ // decoder switch;
+ fprintf(fp, "size_t %s::decode(void *buf, size_t len, IOStream *stream)\n{\n", classname.c_str());
+ fprintf(fp,
+ " \n\
+\tsize_t pos = 0;\n\
+\tif (len < 8) return pos; \n\
+\tunsigned char *ptr = (unsigned char *)buf;\n\
+\tbool unknownOpcode = false; \n\
+#ifdef CHECK_GL_ERROR \n\
+\tchar lastCall[256] = {0}; \n\
+#endif \n\
+\twhile ((len - pos >= 8) && !unknownOpcode) { \n\
+\t\tvoid *params[%u]; \n\
+\t\tint opcode = *(int *)ptr; \n\
+\t\tunsigned int packetLen = *(int *)(ptr + 4);\n\
+\t\tif (len - pos < packetLen) return pos; \n\
+\t\tswitch(opcode) {\n",
+ (uint) m_maxEntryPointsParams);
+
+ for (size_t f = 0; f < n; f++) {
+ enum Pass_t { PASS_TmpBuffAlloc = 0, PASS_MemAlloc, PASS_DebugPrint, PASS_FunctionCall, PASS_Epilog, PASS_LAST };
+ EntryPoint *e = &at(f);
+
+ // construct a printout string;
+ std::string printString = "";
+ for (size_t i = 0; i < e->vars().size(); i++) {
+ Var *v = &e->vars()[i];
+ if (!v->isVoid()) printString += (v->isPointer() ? "%p(%u)" : v->type()->printFormat()) + " ";
+ }
+ printString += "";
+ // TODO - add for return value;
+
+ fprintf(fp, "\t\t\tcase OP_%s:\n", e->name().c_str());
+ fprintf(fp, "\t\t\t{\n");
+
+ bool totalTmpBuffExist = false;
+ std::string totalTmpBuffOffset = "0";
+ std::string *tmpBufOffset = new std::string[e->vars().size()];
+
+ // construct retval type string
+ std::string retvalType;
+ if (!e->retval().isVoid()) {
+ retvalType = e->retval().type()->name();
+ }
+
+ for (int pass = PASS_TmpBuffAlloc; pass < PASS_LAST; pass++) {
+ if (pass == PASS_FunctionCall && !e->retval().isVoid() && !e->retval().isPointer()) {
+ fprintf(fp, "\t\t\t*(%s *)(&tmpBuf[%s]) = ", retvalType.c_str(),
+ totalTmpBuffOffset.c_str());
+ }
+
+
+ if (pass == PASS_FunctionCall) {
+ fprintf(fp, "\t\t\tthis->%s(", e->name().c_str());
+ if (e->customDecoder()) {
+ fprintf(fp, "this"); // add a context to the call
+ }
+ } else if (pass == PASS_DebugPrint) {
+ fprintf(fp, "#ifdef DEBUG_PRINTOUT\n");
+ fprintf(fp, "\t\t\tfprintf(stderr,\"%s: %s(%s)\\n\"", m_basename.c_str(), e->name().c_str(), printString.c_str());
+ if (e->vars().size() > 0 && !e->vars()[0].isVoid()) fprintf(fp, ",");
+ }
+
+ std::string varoffset = "8"; // skip the header
+ VarsArray & evars = e->vars();
+ // allocate memory for out pointers;
+ for (size_t j = 0; j < evars.size(); j++) {
+ Var *v = & evars[j];
+ if (!v->isVoid()) {
+ if ((pass == PASS_FunctionCall) && (j != 0 || e->customDecoder())) fprintf(fp, ", ");
+ if (pass == PASS_DebugPrint && j != 0) fprintf(fp, ", ");
+
+ if (!v->isPointer()) {
+ if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) {
+ fprintf(fp, "*(%s *)(ptr + %s)", v->type()->name().c_str(), varoffset.c_str());
+ }
+ varoffset += " + " + toString(v->type()->bytes());
+ } else {
+ if (v->pointerDir() == Var::POINTER_IN || v->pointerDir() == Var::POINTER_INOUT) {
+ if (pass == PASS_MemAlloc && v->pointerDir() == Var::POINTER_INOUT) {
+ fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n",
+ (uint) j, varoffset.c_str());
+ fprintf(fp, "unsigned char *tmpPtr%u = (ptr + %s + 4);\n",
+ (uint) j, varoffset.c_str());
+ }
+ if (pass == PASS_FunctionCall) {
+ if (v->nullAllowed()) {
+ fprintf(fp, "*((unsigned int *)(ptr + %s)) == 0 ? NULL : (%s)(ptr + %s + 4)",
+ varoffset.c_str(), v->type()->name().c_str(), varoffset.c_str());
+ } else {
+ fprintf(fp, "(%s)(ptr + %s + 4)",
+ v->type()->name().c_str(), varoffset.c_str());
+ }
+ } else if (pass == PASS_DebugPrint) {
+ fprintf(fp, "(%s)(ptr + %s + 4), *(unsigned int *)(ptr + %s)",
+ v->type()->name().c_str(), varoffset.c_str(),
+ varoffset.c_str());
+ }
+ varoffset += " + 4 + *(tsize_t *)(ptr +" + varoffset + ")";
+ } else { // out pointer;
+ if (pass == PASS_TmpBuffAlloc) {
+ fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n",
+ (uint) j, varoffset.c_str());
+ if (!totalTmpBuffExist) {
+ fprintf(fp, "\t\t\tsize_t totalTmpSize = tmpPtr%uSize;\n", (uint)j);
+ } else {
+ fprintf(fp, "\t\t\ttotalTmpSize += tmpPtr%uSize;\n", (uint)j);
+ }
+ tmpBufOffset[j] = totalTmpBuffOffset;
+ char tmpPtrName[16];
+ sprintf(tmpPtrName," + tmpPtr%uSize", (uint)j);
+ totalTmpBuffOffset += std::string(tmpPtrName);
+ totalTmpBuffExist = true;
+ } else if (pass == PASS_MemAlloc) {
+ fprintf(fp, "\t\t\tunsigned char *tmpPtr%u = &tmpBuf[%s];\n",
+ (uint)j, tmpBufOffset[j].c_str());
+ } else if (pass == PASS_FunctionCall) {
+ if (v->nullAllowed()) {
+ fprintf(fp, "tmpPtr%uSize == 0 ? NULL : (%s)(tmpPtr%u)",
+ (uint) j, v->type()->name().c_str(), (uint) j);
+ } else {
+ fprintf(fp, "(%s)(tmpPtr%u)", v->type()->name().c_str(), (uint) j);
+ }
+ } else if (pass == PASS_DebugPrint) {
+ fprintf(fp, "(%s)(tmpPtr%u), *(unsigned int *)(ptr + %s)",
+ v->type()->name().c_str(), (uint) j,
+ varoffset.c_str());
+ }
+ varoffset += " + 4";
+ }
+ }
+ }
+ }
+
+ if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) fprintf(fp, ");\n");
+ if (pass == PASS_DebugPrint) fprintf(fp, "#endif\n");
+
+ if (pass == PASS_TmpBuffAlloc) {
+ if (!e->retval().isVoid() && !e->retval().isPointer()) {
+ if (!totalTmpBuffExist)
+ fprintf(fp, "\t\t\tsize_t totalTmpSize = sizeof(%s);\n", retvalType.c_str());
+ else
+ fprintf(fp, "\t\t\ttotalTmpSize += sizeof(%s);\n", retvalType.c_str());
+
+ totalTmpBuffExist = true;
+ }
+ if (totalTmpBuffExist) {
+ fprintf(fp, "\t\t\tunsigned char *tmpBuf = stream->alloc(totalTmpSize);\n");
+ }
+ }
+
+ if (pass == PASS_Epilog) {
+ // send back out pointers data as well as retval
+ if (totalTmpBuffExist) {
+ fprintf(fp, "\t\t\tstream->flush();\n");
+ }
+
+ fprintf(fp, "\t\t\tpos += *(int *)(ptr + 4);\n");
+ fprintf(fp, "\t\t\tptr += *(int *)(ptr + 4);\n");
+ }
+
+ } // pass;
+ fprintf(fp, "\t\t\t}\n");
+ fprintf(fp, "#ifdef CHECK_GL_ERROR\n");
+ fprintf(fp, "\t\t\tsprintf(lastCall, \"%s\");\n", e->name().c_str());
+ fprintf(fp, "#endif\n");
+ fprintf(fp, "\t\t\tbreak;\n");
+
+ delete [] tmpBufOffset;
+ }
+ fprintf(fp, "\t\t\tdefault:\n");
+ fprintf(fp, "\t\t\t\tunknownOpcode = true;\n");
+ fprintf(fp, "\t\t} //switch\n");
+ if (strstr(m_basename.c_str(), "gl")) {
+ fprintf(fp, "#ifdef CHECK_GL_ERROR\n");
+ fprintf(fp, "\tint err = this->glGetError();\n");
+ fprintf(fp, "\tif (err) fprintf(stderr, \"%s Error: 0x%%X in %%s\\n\", err, lastCall);\n", m_basename.c_str());
+ fprintf(fp, "#endif\n");
+ }
+ fprintf(fp, "\t} // while\n");
+ fprintf(fp, "\treturn pos;\n");
+ fprintf(fp, "}\n");
+
+ fclose(fp);
+ return 0;
+}
+
+int ApiGen::readSpec(const std::string & filename)
+{
+ FILE *specfp = fopen(filename.c_str(), "rt");
+ if (specfp == NULL) {
+ return -1;
+ }
+
+ char line[1000];
+ unsigned int lc = 0;
+ while (fgets(line, sizeof(line), specfp) != NULL) {
+ lc++;
+ EntryPoint ref;
+ if (ref.parse(lc, std::string(line))) {
+ push_back(ref);
+ updateMaxEntryPointsParams(ref.vars().size());
+ }
+ }
+ fclose(specfp);
+ return 0;
+}
+
+int ApiGen::readAttributes(const std::string & attribFilename)
+{
+ enum { ST_NAME, ST_ATT } state;
+
+ FILE *fp = fopen(attribFilename.c_str(), "rt");
+ if (fp == NULL) {
+ perror(attribFilename.c_str());
+ return -1;
+ }
+ char buf[1000];
+
+ state = ST_NAME;
+ EntryPoint *currentEntry = NULL;
+ size_t lc = 0;
+ bool globalAttributes = false;
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ lc++;
+ std::string line(buf);
+ if (line.size() == 0) continue; // could that happen?
+
+ if (line.at(0) == '#') continue; // comment
+
+ size_t first = line.find_first_not_of(" \t\n");
+ if (state == ST_ATT && (first == std::string::npos || first == 0)) state = ST_NAME;
+
+ line = trim(line);
+ if (line.size() == 0 || line.at(0) == '#') continue;
+
+ switch(state) {
+ case ST_NAME:
+ if (line == "GLOBAL") {
+ globalAttributes = true;
+ } else {
+ globalAttributes = false;
+ currentEntry = findEntryByName(line);
+ if (currentEntry == NULL) {
+ fprintf(stderr, "WARNING: %u: attribute of non existant entry point %s\n", (unsigned int)lc, line.c_str());
+ }
+ }
+ state = ST_ATT;
+ break;
+ case ST_ATT:
+ if (globalAttributes) {
+ setGlobalAttribute(line, lc);
+ } else if (currentEntry != NULL) {
+ currentEntry->setAttribute(line, lc);
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+
+int ApiGen::setGlobalAttribute(const std::string & line, size_t lc)
+{
+ size_t pos = 0;
+ size_t last;
+ std::string token = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+
+ if (token == "base_opcode") {
+ std::string str = getNextToken(line, pos, &last, WHITESPACE);
+ if (str.size() == 0) {
+ fprintf(stderr, "line %u: missing value for base_opcode\n", (uint) lc);
+ } else {
+ setBaseOpcode(atoi(str.c_str()));
+ }
+ } else if (token == "encoder_headers") {
+ std::string str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ while (str.size() != 0) {
+ encoderHeaders().push_back(str);
+ str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ }
+ } else if (token == "client_context_headers") {
+ std::string str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ while (str.size() != 0) {
+ clientContextHeaders().push_back(str);
+ str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ }
+ } else if (token == "server_context_headers") {
+ std::string str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ while (str.size() != 0) {
+ serverContextHeaders().push_back(str);
+ str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ }
+ } else if (token == "decoder_headers") {
+ std::string str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ while (str.size() != 0) {
+ decoderHeaders().push_back(str);
+ str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ }
+ }
+ else {
+ fprintf(stderr, "WARNING: %u : unknown global attribute %s\n", (unsigned int)lc, line.c_str());
+ }
+
+ return 0;
+}
+
diff --git a/emulator/opengl/host/tools/emugen/ApiGen.h b/emulator/opengl/host/tools/emugen/ApiGen.h
new file mode 100644
index 000000000..1627ef6fe
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/ApiGen.h
@@ -0,0 +1,95 @@
+/*
+* Copyright (C) 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.
+*/
+#ifndef __API_GEN_H_
+#define __API_GEN_H_
+
+#include <vector>
+#include <string.h>
+#include "EntryPoint.h"
+
+
+class ApiGen : public std::vector<EntryPoint> {
+
+public:
+ typedef std::vector<std::string> StringVec;
+ typedef enum { CLIENT_SIDE, SERVER_SIDE, WRAPPER_SIDE } SideType;
+
+ ApiGen(const std::string & basename) :
+ m_basename(basename),
+ m_maxEntryPointsParams(0),
+ m_baseOpcode(0)
+ { }
+ virtual ~ApiGen() {}
+ int readSpec(const std::string & filename);
+ int readAttributes(const std::string & attribFilename);
+ size_t maxEntryPointsParams() { return m_maxEntryPointsParams; }
+ void updateMaxEntryPointsParams(size_t val) {
+ if (m_maxEntryPointsParams == 0 || val > m_maxEntryPointsParams) m_maxEntryPointsParams = val;
+ }
+ int baseOpcode() { return m_baseOpcode; }
+ void setBaseOpcode(int base) { m_baseOpcode = base; }
+
+ const char *sideString(SideType side) {
+ const char *retval;
+ switch(side) {
+ case CLIENT_SIDE:
+ retval = "client";
+ break;
+ case SERVER_SIDE:
+ retval = "server";
+ break;
+ case WRAPPER_SIDE:
+ retval = "wrapper";
+ break;
+ }
+ return retval;
+ }
+
+ StringVec & clientContextHeaders() { return m_clientContextHeaders; }
+ StringVec & encoderHeaders() { return m_encoderHeaders; }
+ StringVec & serverContextHeaders() { return m_serverContextHeaders; }
+ StringVec & decoderHeaders() { return m_decoderHeaders; }
+
+ EntryPoint * findEntryByName(const std::string & name);
+ int genOpcodes(const std::string &filename);
+ int genAttributesTemplate(const std::string &filename);
+ int genProcTypes(const std::string &filename, SideType side);
+ int genFuncTable(const std::string &filename, SideType side);
+
+ int genContext(const std::string &filename, SideType side);
+ int genContextImpl(const std::string &filename, SideType side);
+
+ int genEntryPoints(const std::string &filename, SideType side);
+
+ int genEncoderHeader(const std::string &filename);
+ int genEncoderImpl(const std::string &filename);
+
+ int genDecoderHeader(const std::string &filename);
+ int genDecoderImpl(const std::string &filename);
+
+protected:
+ virtual void printHeader(FILE *fp) const;
+ std::string m_basename;
+ StringVec m_clientContextHeaders;
+ StringVec m_encoderHeaders;
+ StringVec m_serverContextHeaders;
+ StringVec m_decoderHeaders;
+ size_t m_maxEntryPointsParams; // record the maximum number of parameters in the entry points;
+ int m_baseOpcode;
+ int setGlobalAttribute(const std::string & line, size_t lc);
+};
+
+#endif
diff --git a/emulator/opengl/host/tools/emugen/EntryPoint.cpp b/emulator/opengl/host/tools/emugen/EntryPoint.cpp
new file mode 100644
index 000000000..43b904bee
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/EntryPoint.cpp
@@ -0,0 +1,376 @@
+/*
+* Copyright (C) 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.
+*/
+#include <stdio.h>
+#include "EntryPoint.h"
+#include <string>
+#include "TypeFactory.h"
+#include "strUtils.h"
+#include <sstream>
+
+
+EntryPoint::EntryPoint()
+{
+ reset();
+}
+
+EntryPoint::~EntryPoint()
+{
+}
+
+void EntryPoint::reset()
+{
+ m_unsupported = false;
+ m_customDecoder = false;
+ m_notApi = false;
+ m_vars.empty();
+}
+
+bool parseTypeField(const std::string & f, std::string *vartype, std::string *varname)
+{
+ size_t pos = 0, last;
+ bool done = false;
+
+
+ *vartype = "";
+ if (varname != NULL) *varname = "";
+
+ enum { ST_TYPE, ST_NAME, ST_END } state = ST_TYPE;
+
+ while(!done) {
+
+ std::string str = getNextToken(f, pos, &last, WHITESPACE);
+ if (str.size() == 0) break;
+
+ switch(state) {
+ case ST_TYPE:
+ if (str == "const") {
+ pos = last;
+ *vartype = "const ";
+ } else {
+ // must be a type name;
+ *vartype += str;
+ state = ST_NAME;
+ pos = last;
+ }
+ break;
+ case ST_NAME:
+ if (str.size() == 0) {
+ done = true;
+ } else if (str == "*") {
+ (*vartype) += "*";
+ pos = last;
+ } else if (varname == NULL) {
+ done = true;
+ } else {
+ while (str[0] == '*') {
+ (*vartype) += "*";
+ str[0] = ' ';
+ str = trim(str);
+ }
+ *varname = str;
+ done = true;
+ }
+ break;
+ case ST_END:
+ break;
+ }
+ }
+ return true;
+}
+
+// return true for valid line (need to get into the entry points list)
+bool EntryPoint::parse(unsigned int lc, const std::string & str)
+{
+ size_t pos, last;
+ std::string field;
+
+ reset();
+ std::string linestr = trim(str);
+
+ if (linestr.size() == 0) return false;
+ if (linestr.at(0) == '#') return false;
+
+ // skip PREFIX
+ field = getNextToken(linestr, 0, &last, "(");
+ pos = last + 1;
+ // return type
+ field = getNextToken(linestr, pos, &last, ",)");
+ std::string retTypeName;
+ if (!parseTypeField(field, &retTypeName, NULL)) {
+ fprintf(stderr, "line: %d: Parsing error in field <%s>\n", lc, field.c_str());
+ return false;
+ }
+ pos = last + 1;
+ const VarType *theType = TypeFactory::instance()->getVarTypeByName(retTypeName);
+ if (theType->name() == "UNKNOWN") {
+ fprintf(stderr, "UNKNOWN retval: %s\n", linestr.c_str());
+ }
+
+ m_retval.init(std::string(""), theType, std::string(""), Var::POINTER_OUT, std::string(""), std::string(""));
+
+ // function name
+ m_name = getNextToken(linestr, pos, &last, ",)");
+ pos = last + 1;
+
+ // parameters;
+ int nvars = 0;
+ while (pos < linestr.size() - 1) {
+ field = getNextToken(linestr, pos, &last, ",)");
+ std::string vartype, varname;
+ if (!parseTypeField(field, &vartype, &varname)) {
+ fprintf(stderr, "line: %d: Parsing error in field <%s>\n", lc, field.c_str());
+ return false;
+ }
+ nvars++;
+ const VarType *v = TypeFactory::instance()->getVarTypeByName(vartype);
+ if (v->id() == 0) {
+ fprintf(stderr, "%d: Unknown type: %s\n", lc, vartype.c_str());
+ } else {
+ if (varname == "" &&
+ !(v->name() == "void" && !v->isPointer())) {
+ std::ostringstream oss;
+ oss << "var" << nvars;
+ varname = oss.str();
+ }
+
+ m_vars.push_back(Var(varname, v, std::string(""), Var::POINTER_IN, "", ""));
+ }
+ pos = last + 1;
+ }
+ return true;
+}
+
+void EntryPoint::print(FILE *fp, bool newline,
+ const std::string & name_suffix,
+ const std::string & name_prefix,
+ const std::string & ctx_param ) const
+{
+ fprintf(fp, "%s %s%s%s(",
+ m_retval.type()->name().c_str(),
+ name_prefix.c_str(),
+ m_name.c_str(),
+ name_suffix.c_str());
+
+ if (ctx_param != "") fprintf(fp, "%s ", ctx_param.c_str());
+
+ for (size_t i = 0; i < m_vars.size(); i++) {
+ if (m_vars[i].isVoid()) continue;
+ if (i != 0 || ctx_param != "") fprintf(fp, ", ");
+ fprintf(fp, "%s %s", m_vars[i].type()->name().c_str(),
+ m_vars[i].name().c_str());
+ }
+ fprintf(fp, ")%s", newline? "\n" : "");
+}
+
+Var * EntryPoint::var(const std::string & name)
+{
+ Var *v = NULL;
+ for (size_t i = 0; i < m_vars.size(); i++) {
+ if (m_vars[i].name() == name) {
+ v = &m_vars[i];
+ break;
+ }
+ }
+ return v;
+}
+
+bool EntryPoint::hasPointers()
+{
+ bool pointers = false;
+ if (m_retval.isPointer()) pointers = true;
+ if (!pointers) {
+ for (size_t i = 0; i < m_vars.size(); i++) {
+ if (m_vars[i].isPointer()) {
+ pointers = true;
+ break;
+ }
+ }
+ }
+ return pointers;
+}
+
+int EntryPoint::setAttribute(const std::string &line, size_t lc)
+{
+ size_t pos = 0;
+ size_t last;
+ std::string token = getNextToken(line, 0, &last, WHITESPACE);
+
+ if (token == "len") {
+ pos = last;
+ std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+
+ if (varname.size() == 0) {
+ fprintf(stderr, "ERROR: %u: Missing variable name in 'len' attribute\n", (unsigned int)lc);
+ return -1;
+ }
+ Var * v = var(varname);
+ if (v == NULL) {
+ fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+ (unsigned int)lc, varname.c_str(), name().c_str());
+ return -2;
+ }
+ // set the size expression into var
+ pos = last;
+ v->setLenExpression(line.substr(pos));
+ } else if (token == "param_check") {
+ pos = last;
+ std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+
+ if (varname.size() == 0) {
+ fprintf(stderr, "ERROR: %u: Missing variable name in 'param_check' attribute\n", (unsigned int)lc);
+ return -1;
+ }
+ Var * v = var(varname);
+ if (v == NULL) {
+ fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+ (unsigned int)lc, varname.c_str(), name().c_str());
+ return -2;
+ }
+ // set the size expression into var
+ pos = last;
+ v->setParamCheckExpression(line.substr(pos));
+
+ } else if (token == "dir") {
+ pos = last;
+ std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+ if (varname.size() == 0) {
+ fprintf(stderr, "ERROR: %u: Missing variable name in 'dir' attribute\n", (unsigned int)lc);
+ return -1;
+ }
+ Var * v = var(varname);
+ if (v == NULL) {
+ fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+ (unsigned int)lc, varname.c_str(), name().c_str());
+ return -2;
+ }
+
+ pos = last;
+ std::string pointerDirStr = getNextToken(line, pos, &last, WHITESPACE);
+ if (pointerDirStr.size() == 0) {
+ fprintf(stderr, "ERROR: %u: missing pointer directions\n", (unsigned int)lc);
+ return -3;
+ }
+
+ if (pointerDirStr == "out") {
+ v->setPointerDir(Var::POINTER_OUT);
+ } else if (pointerDirStr == "inout") {
+ v->setPointerDir(Var::POINTER_INOUT);
+ } else if (pointerDirStr == "in") {
+ v->setPointerDir(Var::POINTER_IN);
+ } else {
+ fprintf(stderr, "ERROR: %u: unknow pointer direction %s\n", (unsigned int)lc, pointerDirStr.c_str());
+ }
+ } else if (token == "var_flag") {
+ pos = last;
+ std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+ if (varname.size() == 0) {
+ fprintf(stderr, "ERROR: %u: Missing variable name in 'var_flag' attribute\n", (unsigned int)lc);
+ return -1;
+ }
+ Var * v = var(varname);
+ if (v == NULL) {
+ fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+ (unsigned int)lc, varname.c_str(), name().c_str());
+ return -2;
+ }
+ int count = 0;
+ for (;;) {
+ pos = last;
+ std::string flag = getNextToken(line, pos, &last, WHITESPACE);
+ if (flag.size() == 0) {
+ if (count == 0) {
+ fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
+ return -3;
+ }
+ break;
+ }
+ count++;
+
+ if (flag == "nullAllowed") {
+ if (v->isPointer()) {
+ v->setNullAllowed(true);
+ } else {
+ fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n",
+ (unsigned int) lc, v->name().c_str());
+ }
+ } else if (flag == "isLarge") {
+ if (v->isPointer()) {
+ v->setIsLarge(true);
+ } else {
+ fprintf(stderr, "WARNING: %u: setting isLarge flag for a non-pointer variable %s\n",
+ (unsigned int) lc, v->name().c_str());
+ }
+ } else {
+ fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str());
+ }
+ }
+ } else if (token == "custom_pack") {
+ pos = last;
+ std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+
+ if (varname.size() == 0) {
+ fprintf(stderr, "ERROR: %u: Missing variable name in 'custom_pack' attribute\n", (unsigned int)lc);
+ return -1;
+ }
+ Var * v = var(varname);
+ if (v == NULL) {
+ fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+ (unsigned int)lc, varname.c_str(), name().c_str());
+ return -2;
+ }
+ // set the size expression into var
+ pos = last;
+ v->setPackExpression(line.substr(pos));
+ } else if (token == "custom_write") {
+ pos = last;
+ std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+
+ if (varname.size() == 0) {
+ fprintf(stderr, "ERROR: %u: Missing variable name in 'custom_write' attribute\n", (unsigned int)lc);
+ return -1;
+ }
+ Var * v = var(varname);
+ if (v == NULL) {
+ fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+ (unsigned int)lc, varname.c_str(), name().c_str());
+ return -2;
+ }
+ // set the size expression into var
+ pos = last;
+ v->setWriteExpression(line.substr(pos));
+ } else if (token == "flag") {
+ pos = last;
+ std::string flag = getNextToken(line, pos, &last, WHITESPACE);
+ if (flag.size() == 0) {
+ fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
+ return -4;
+ }
+
+ if (flag == "unsupported") {
+ setUnsupported(true);
+ } else if (flag == "custom_decoder") {
+ setCustomDecoder(true);
+ } else if (flag == "not_api") {
+ setNotApi(true);
+ } else {
+ fprintf(stderr, "WARNING: %u: unknown flag %s\n", (unsigned int)lc, flag.c_str());
+ }
+ } else {
+ fprintf(stderr, "WARNING: %u: unknown attribute %s\n", (unsigned int)lc, token.c_str());
+ }
+
+ return 0;
+}
diff --git a/emulator/opengl/host/tools/emugen/EntryPoint.h b/emulator/opengl/host/tools/emugen/EntryPoint.h
new file mode 100644
index 000000000..77b8a7f34
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/EntryPoint.h
@@ -0,0 +1,67 @@
+/*
+* Copyright (C) 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.
+*/
+#ifndef __EntryPoint__H__
+#define __EntryPoint__H__
+
+#include <string>
+#include <vector>
+#include <stdio.h>
+
+#include "Var.h"
+
+//---------------------------------------------------
+
+typedef std::vector<Var> VarsArray;
+
+class EntryPoint {
+public:
+ EntryPoint();
+ virtual ~EntryPoint();
+ bool parse(unsigned int lc, const std::string & str);
+ void reset(); // reset the class to empty;
+ void print(FILE *fp = stdout, bool newline = true,
+ const std::string & name_suffix = std::string(""),
+ const std::string & name_prefix = std::string(""),
+ const std::string & ctx_param = std::string("")) const;
+ const std::string & name() const { return m_name; }
+ VarsArray & vars() { return m_vars; }
+ Var & retval() { return m_retval; }
+ Var * var(const std::string & name);
+ bool hasPointers();
+ bool unsupported() const { return m_unsupported; }
+ void setUnsupported(bool state) { m_unsupported = state; }
+ bool customDecoder() { return m_customDecoder; }
+ void setCustomDecoder(bool state) { m_customDecoder = state; }
+ bool notApi() const { return m_notApi; }
+ void setNotApi(bool state) { m_notApi = state; }
+ int setAttribute(const std::string &line, size_t lc);
+
+private:
+ enum { PR_RETVAL = 0, PR_NAME, PR_VARS, PR_DONE } prState;
+ std::string m_name;
+ Var m_retval;
+ VarsArray m_vars;
+ bool m_unsupported;
+ bool m_customDecoder;
+ bool m_notApi;
+
+ void err(unsigned int lc, const char *msg) {
+ fprintf(stderr, "line %d: %s\n", lc, msg);
+ }
+};
+
+
+#endif
diff --git a/emulator/opengl/host/tools/emugen/README b/emulator/opengl/host/tools/emugen/README
new file mode 100644
index 000000000..0fe85f941
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/README
@@ -0,0 +1,332 @@
+Introduction:
+-------------
+The emugen tool is a tool to generate a wire protocol implementation
+based on provided API. The tool generates c++ encoder code that takes
+API calls and encodes them into the wire and decoder code that decodes
+the wire stream and calls server matching API.
+The emugen tool includes additional functionality that enables to
+generate an wrapper library. The wrapper library provides entry points
+for the specified API, where each entry routes the call via a dispatch
+table. The dispatch table may be initialized as required by a specific application.
+
+The following paragraphs includes the following:
+ * Wire Protocol Description
+ * Input files description & format
+ * Generated code description.
+
+
+Note: In this document, the caller is referred to as Encoder or Client
+and the callee is referred to as the Decoder or Server. These terms
+are used interchangeably by the context.
+
+
+
+Wire Protocol packet structure:
+-------------------------------
+A general Encoder->Decoder packet is structured as following:
+struct Packet {
+ unsigned int opcode;
+ unsigned int packet_len;
+ … parameter 1
+ … parameter 2
+};
+A general Decoder->Encoder reply is expected to be received in the
+context of the ‘call’ that triggered it, thus it includes the reply
+data only, with no context headers. In precise term terms, a reply
+packet will look like:
+
+struct {
+ ...// reply data
+};
+
+consider the following function call:
+int foo(int p1, short s1)
+will be encoded into :
+{
+ 101, // foo opcode
+ 14, // sizeof(opcode) + sizeof(packet_len) + sizeof(int) + sizeof(short)
+ p1, // 4 bytes
+ s1 // 2 bytes
+}
+
+Since ‘foo’ returns value, the caller is expected to read back the return packet from the server->client stream. The return value in this example is in thus the return packet is:
+{
+ int retval;
+}
+
+
+Pointer decoding:
+----------------
+The wire protocol also allows exchanging of pointer data
+(arrays). Pointers are defined with directions:
+
+ in : Data is sent from the caller to the calle
+ out: Data is sent from the callee to the caller
+ in_out: data is sent from the caller and return in place.
+
+‘in’ and ‘in_out’ encoded with their len:
+{
+ unsinged int pointer_data_len;
+ unsigned char data[pointer_data_len];… // pointer data
+}
+
+‘out’ pointers are encoded by data length only:
+{
+unsigned int pointer_data_len;
+}
+
+‘out’ and ‘in_out’ pointer’s data is returned in the return
+packet. For example, consider the following call:
+
+int foo(int n, int *ptr); // assume that ‘data’ is in_out pointer which contains ‘n’ ints
+
+The caller packet will have the following form:
+{
+ 101, // foo opcode
+ xx, sizeof(opcode) + sizeof(datalen) + sizeof(int) + sizeof(unsigned int) + n * sizeof(int);
+ n, // the n parameter
+ n * sizeof(int), // size of the data in ptr
+ … // n* sizeof(int) bytes
+}
+
+The return packet is;
+{
+ …. // n * sizeof(int) bytes of data return in ptr
+ retval // sizeof(int) - the return value of the function;
+}
+
+Endianess
+---------
+The Wire protocol is designed to impose minimum overhead on the client
+side. Thus, the data endianness that is sent across the wire is
+determined by the ‘client’ side. It is up to the server side to
+determine the client endianess and marshal the packets as required.
+
+
+
+Emugen input files - protocol specification
+-------------------------------------------
+The protocol generated by emugen consists of two input files:
+
+1. basename.in - A sepcification of the protocol RPC procedures. This
+part of the specification is expected to be generated automatically
+from c/c++ header files or similar.
+
+‘basename’ is the basename for the protocol and will be used to prefix
+the files that are generated for this protocol. A line in the .in
+file has the following format:
+
+[prefix](retvalType, FuncName, <param type> [param name],...)
+where
+ retvalType - The function return value type
+ FuncName - function name
+ <param type> mandatory parameter type
+ [param name] - optional parameter name
+Examples:
+GL_ENTRY(void, glVertex1f, float v)
+XXX(int *, foo, int n, float, short)
+XXX(void, glFlush, void)
+
+Note: Empty lines in the file are ignored. A line starts with # is a comment
+
+2. basename.attrib - Attributes information of the API.
+This file includes additional flags, pointers datalen information and
+global attributes of the protocol. For uptodate format of the file,
+please refer to the specification file in the project source
+tree. The format of the .attrib file is described below.
+
+3. basename.types - Types information
+
+This files describes the types that are described by the API. A type
+is defined as follows:
+<type name> <size in bits> <print format string> <is a pointer? true|false>
+where:
+<type name> is the name of the type as described in the API
+<size in bits> 0, 8, 16, 32 sizes are accepted
+<print format string> a string to format the value of the type, as
+acceted by printf(3)
+<is pointer?> true or false string species whether the type should be
+treated as a pointer.
+
+example:
+GLint 32 %d false
+GLint* 32 %p true
+GLptr 32 %p true
+
+Encoder generated code files
+----------------------------
+In order to generate the encoder files, one should run the ‘emugen’
+tool as follows:
+
+emugen -i <input directory> -E <encoder files output directory> <basename>
+where:
+ <input directory> containes the api specification files (basename.in + basename.attrib)
+ <encoder directory> - a directory name to generate the encoder output files
+ basename - The basename for the api.
+
+Assuming the basename is ‘api’, The following files are generated:
+
+api_opcodes.h - defines the protocol opcodes. The first opcode value
+is 0, unless defined otherwise in the .attrib file
+
+api_entry.cpp - defines entry points for the functions that are
+defined by the protocol. this File also includes a function call
+‘setContextAccessor(void *(*f)()). This function should be used to
+provide a callback function that is used by the functions to access
+the encoder context. For example, such callback could fetch the
+context from a Thread Local Storage (TLS) location.
+
+api_client_proc.h - type defintions for the protocol procedures.
+
+api_client_context.h - defines the client side dispatch table data
+structure that stores the encoding functions. This data structure also
+includes ‘accessors’ methods such that library user can override
+default entries for special case handling.
+
+api_client_context.cpp - defines an initialization function for
+dispatch table
+
+api_enc.h - This header file defines the encoder data strcuture. The
+encoder data structure inherits its functionality from the
+‘client_context’ class above and adds encoding and streaming
+functionality.
+
+api_enc.cpp - Encoder implementation.
+
+Decoder generated files
+-----------------------
+In order to generate the decoder files, one should run the ‘emugen’
+tool as follows:
+emugen -i <input directory> -D <decoder files output directory> basename
+where:
+ <input directory> containes the api specification files (basename.in + basename.attrib)
+ <decoder directory> - a directory name to generate the decoder output files
+ basename - The basename for the api.
+
+With resepct to the example above, Emugen will generate the following
+files:
+
+api_opcodes.h - Protocol opcodes
+
+api_server_proc.h - type definitions for the server side procedures
+
+api_server_context.h - dispatch table the decoder functions
+
+api_server_context.cpp - dispatch table initialization function
+api_dec.h - Decoder header file
+
+api_dec.cpp - Decoder implementation. In addtion, this file includes
+an intiailization function that uses a user provided callback to
+initialize the API server implementation. An example for such
+initialization is loading a set of functions from a shared library
+module.
+
+Wrapper generated files
+-----------------------
+In order to generate a wrapper library files, one should run the
+'emugen' tool as follows:
+
+emugen -i <input directory> -W <wrapper files output directory> basename
+where:
+ <input directory> containes the api specification files (basename.in + basename.attrib)
+ <wrapper directory> - a directory name to generate the wrapper output files
+ basename - The basename for the api.
+
+With resepct to the example above, Emugen will generate the following
+files:
+
+api_wrapper_proc.h - type definitions for the wrapper procedures
+
+api_wrapper_context.h - dispatch table the wrapper functions
+
+api_wrapper_context.cpp - dispatch table initialization function
+api_wrapper_entry.cpp - entry points for the API
+
+
+.attrib file format description:
+-------------------------------
+The .attrib file is an input file to emugen and is used to provide
+ additional information that is required for the code generation.
+The file format is as follows:
+
+a line that starts with # is ignored (comment)
+a empty line just whitespace of (" " "\t" "\n") is ignored.
+
+The file is divided into 'sections', each describes a specific API
+function call. A section starts with the name of the function in
+column 0.
+
+A section that starts with the reserved word 'GLOBAL' provides global
+attributes.
+
+below are few sections examples:
+
+GLOBAL
+ encoder_headers string.h kuku.h
+
+glVertex3fv
+ len data (size)
+glTexImage2D
+ len pixels (pixels == NULL? 0 : (format_pixel_size(internalformat) * width * height * type_size(type)))
+
+
+Global section flags description:
+
+base_opcode
+ set the base opcode value for this api
+ format: base_opcode 100
+
+encoder_headers
+ a list of headers that will be included in the encoder header file
+ format: encoder_headers <stdio.h> "kuku.h"
+
+client_context_headers
+ a list of headers that will be included in the client context header file
+ format: client_context_headers <stdio.h> "kuku.h"
+
+decoder_headers
+ a list of headers that will be included in the decoder header file
+ format: decoder_headers <stdio.h> "kuku.h"
+
+server_context_headers
+ a list of headers that will be included in the server context header file
+ format: server_context_headers <stdio.h> "kuku.h"
+
+
+Entry point flags description:
+
+ len
+ desciption : provide an expression to calcualte an expression data len
+ format: len <var name> <c expression that calcluates the data len>
+
+custom_pack
+ description: provide an expression to pack data into the stream.
+ format: custom_pack <var name> <c++ expression that pack data from var into the stream>
+ The stream is represented by a (unsigned char *)ptr. The expression may also refer
+ to other function parameters. In addition, the expression may refer to 'void *self' which
+ is the encoding context as provided by the caller.
+
+ dir
+ description : set a pointer direction (in - for data that goes
+ to the codec, out from data that returns from the codec.
+ format: dir <varname> <[in | out | inout]>
+
+ var_flag
+ description : set variable flags
+ format: var_flag <varname> < nullAllowed | isLarge | ... >
+
+ nullAllowed -> for pointer variables, indicates that NULL is a valid value
+ isLarge -> for pointer variables, indicates that the data should be sent without an intermediate copy
+
+ flag
+ description: set entry point flag;
+ format: flag < unsupported | ... >
+ supported flags are:
+ unsupported - The encoder side implementation is pointed to "unsuppored reporting function".
+ custom_decoder - The decoder is expected to be provided with
+ custom implementation. The call to the
+ deocder function includes a pointer to the
+ context
+ not_api - the function is not native gl api
+
+
diff --git a/emulator/opengl/host/tools/emugen/TypeFactory.cpp b/emulator/opengl/host/tools/emugen/TypeFactory.cpp
new file mode 100644
index 000000000..88842250a
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/TypeFactory.cpp
@@ -0,0 +1,156 @@
+/*
+* Copyright (C) 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.
+*/
+#include "TypeFactory.h"
+#include "VarType.h"
+#include <string>
+#include <map>
+#include <stdio.h>
+#include <stdlib.h>
+#include "strUtils.h"
+
+
+TypeFactory * TypeFactory::m_instance = NULL;
+
+static Var0 g_var0;
+static Var8 g_var8;
+static Var16 g_var16;
+static Var32 g_var32;
+
+typedef std::map<std::string, VarType> TypeMap;
+static TypeMap g_varMap;
+static bool g_initialized = false;
+static int g_typeId = 0;
+
+
+static VarConverter * getVarConverter(int size)
+{
+ VarConverter *v = NULL;
+
+ switch(size) {
+ case 0: v = &g_var0; break;
+ case 8: v = &g_var8; break;
+ case 16: v = &g_var16; break;
+ case 32: v = &g_var32; break;
+ }
+ return v;
+}
+
+#define ADD_TYPE(name, size, printformat,ispointer) \
+ g_varMap.insert(std::pair<std::string, VarType>(name, VarType(g_typeId++, name, &g_var##size , printformat , ispointer)));
+
+void TypeFactory::initBaseTypes()
+{
+ g_initialized = true;
+ ADD_TYPE("UNKNOWN", 0, "0x%x", false);
+ ADD_TYPE("void", 0, "0x%x", false);
+ ADD_TYPE("char", 8, "%c", false);
+ ADD_TYPE("int", 32, "%d", false);
+ ADD_TYPE("float", 32, "%d", false);
+ ADD_TYPE("short", 16, "%d", false);
+}
+
+int TypeFactory::initFromFile(const std::string &filename)
+{
+ if (!g_initialized) {
+ initBaseTypes();
+ }
+
+ FILE *fp = fopen(filename.c_str(), "rt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+ char line[1000];
+ int lc = 0;
+ while(fgets(line, sizeof(line), fp) != NULL) {
+ lc++;
+ std::string str = trim(line);
+ if (str.size() == 0 || str.at(0) == '#') {
+ continue;
+ }
+ size_t pos = 0, last;
+ std::string name;
+ name = getNextToken(str, pos, &last, WHITESPACE);
+ if (name.size() == 0) {
+ fprintf(stderr, "Error: %d : missing type name\n", lc);
+ return -2;
+ }
+ pos = last + 1;
+ std::string size;
+ size = getNextToken(str, pos, &last, WHITESPACE);
+ if (size.size() == 0) {
+ fprintf(stderr, "Error: %d : missing type width\n", lc);
+ return -2;
+ }
+ pos = last + 1;
+ std::string printString;
+ printString = getNextToken(str, pos, &last, WHITESPACE);
+ if (printString.size() == 0) {
+ fprintf(stderr, "Error: %d : missing print-string\n", lc);
+ return -2;
+ }
+
+ pos = last + 1;
+ std::string pointerDef;
+ pointerDef = getNextToken(str, pos, &last, WHITESPACE);
+ if (pointerDef.size() == 0) {
+ fprintf(stderr, "Error: %d : missing ispointer definition\n", lc);
+ return -2;
+ }
+
+ bool isPointer=false;
+ if (std::string("true")==pointerDef)
+ isPointer = true;
+ else if (std::string("false")==pointerDef)
+ isPointer = false;
+ else
+ {
+ fprintf(stderr, "Error: %d : invalid isPointer definition, must be either \"true\" or \"false\"\n", lc);
+ return -2;
+ }
+
+ VarConverter *v = getVarConverter(atoi(size.c_str()));
+ if (v == NULL) {
+ fprintf(stderr, "Error: %d : unknown var width: %d\n", lc, atoi(size.c_str()));
+ return -1;
+ }
+
+ if (getVarTypeByName(name)->id() != 0) {
+ fprintf(stderr,
+ "Warining: %d : type %s is already known, definition in line %d is taken\n",
+ lc, name.c_str(), lc);
+ }
+ g_varMap.insert(std::pair<std::string, VarType>(name, VarType(g_typeId++, name, v ,printString,isPointer)));
+ std::string constName = "const " + name;
+ g_varMap.insert(std::pair<std::string, VarType>(constName, VarType(g_typeId++, constName, v ,printString,isPointer))); //add a const type
+ }
+ g_initialized = true;
+ return 0;
+}
+
+
+const VarType * TypeFactory::getVarTypeByName(const std::string & type)
+{
+ if (!g_initialized) {
+ initBaseTypes();
+ }
+ TypeMap::iterator i = g_varMap.find(type);
+ if (i == g_varMap.end()) {
+ i = g_varMap.find("UNKNOWN");
+ }
+ return &(i->second);
+}
+
diff --git a/emulator/opengl/host/tools/emugen/TypeFactory.h b/emulator/opengl/host/tools/emugen/TypeFactory.h
new file mode 100644
index 000000000..deee2ca49
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/TypeFactory.h
@@ -0,0 +1,37 @@
+/*
+* Copyright (C) 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.
+*/
+#ifndef __TYPE__FACTORY__H__
+#define __TYPE__FACTORY__H__
+
+#include <string>
+#include "VarType.h"
+
+class TypeFactory {
+public:
+ static TypeFactory *instance() {
+ if (m_instance == NULL) {
+ m_instance = new TypeFactory;
+ }
+ return m_instance;
+ }
+ const VarType * getVarTypeByName(const std::string &type);
+ int initFromFile(const std::string &filename);
+private:
+ static TypeFactory *m_instance;
+ void initBaseTypes();
+ TypeFactory() {}
+};
+#endif
diff --git a/emulator/opengl/host/tools/emugen/Var.h b/emulator/opengl/host/tools/emugen/Var.h
new file mode 100644
index 000000000..322c66a92
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/Var.h
@@ -0,0 +1,110 @@
+/*
+* Copyright (C) 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.
+*/
+#ifndef __VAR__H__
+#define __VAR__H__
+
+#include "VarType.h"
+#include <string>
+#include <stdio.h>
+
+class Var {
+public:
+ // pointer data direction - from the client point of view.
+ typedef enum { POINTER_OUT = 0x1, POINTER_IN = 0x2, POINTER_INOUT = 0x3 } PointerDir;
+ Var() :
+ m_name(""),
+ m_type(NULL),
+ m_lenExpression(""),
+ m_pointerDir(POINTER_IN),
+ m_nullAllowed(false),
+ m_isLarge(false),
+ m_packExpression(""),
+ m_writeExpression(""),
+ m_paramCheckExpression("")
+
+ {
+ }
+
+ Var(const std::string & name,
+ const VarType * vartype,
+ const std::string & lenExpression,
+ PointerDir dir,
+ const std::string &packExpression,
+ const std::string &writeExpression) :
+ m_name(name),
+ m_type(const_cast<VarType *>(vartype)),
+ m_lenExpression(lenExpression),
+ m_pointerDir(dir),
+ m_nullAllowed(false),
+ m_isLarge(false),
+ m_packExpression(packExpression),
+ m_writeExpression(writeExpression),
+ m_paramCheckExpression("")
+ {
+ }
+
+ void init(const std::string name, const VarType * vartype,
+ std::string lenExpression,
+ PointerDir dir,
+ std::string packExpression,
+ std::string writeExpression) {
+ m_name = name;
+ m_type = vartype;
+ m_lenExpression = lenExpression;
+ m_packExpression = packExpression;
+ m_writeExpression = writeExpression;
+ m_pointerDir = dir;
+ m_nullAllowed = false;
+ m_isLarge = false;
+
+ }
+
+ const std::string & name() const { return m_name; }
+ const VarType * type() const { return m_type; }
+ bool isPointer() const { return m_type->isPointer(); }
+ bool isVoid() const { return ((m_type->bytes() == 0) && (!m_type->isPointer())); }
+ const std::string & lenExpression() const { return m_lenExpression; }
+ const std::string & packExpression() const { return(m_packExpression); }
+ const std::string & writeExpression() const { return(m_writeExpression); }
+ const std::string & paramCheckExpression() const { return m_paramCheckExpression; }
+ void setLenExpression(const std::string & lenExpression) { m_lenExpression = lenExpression; }
+ void setPackExpression(const std::string & packExpression) { m_packExpression = packExpression; }
+ void setWriteExpression(const std::string & writeExpression) { m_writeExpression = writeExpression; }
+ void setParamCheckExpression(const std::string & paramCheckExpression) { m_paramCheckExpression = paramCheckExpression; }
+ void setPointerDir(PointerDir dir) { m_pointerDir = dir; }
+ PointerDir pointerDir() { return m_pointerDir; }
+ void setNullAllowed(bool state) { m_nullAllowed = state; }
+ void setIsLarge(bool state) { m_isLarge = state; }
+ bool nullAllowed() const { return m_nullAllowed; }
+ bool isLarge() const { return m_isLarge; }
+ void printType(FILE *fp) { fprintf(fp, "%s", m_type->name().c_str()); }
+ void printTypeName(FILE *fp) { printType(fp); fprintf(fp, " %s", m_name.c_str()); }
+
+private:
+ std::string m_name;
+ const VarType * m_type;
+ bool m_pointer; // is this variable a pointer;
+ std::string m_lenExpression; // an expression to calcualte a pointer data size
+ PointerDir m_pointerDir;
+ bool m_nullAllowed;
+ bool m_isLarge;
+ std::string m_packExpression; // an expression to pack data into the stream
+ std::string m_writeExpression; // an expression to write data into the stream
+ std::string m_paramCheckExpression; //an expression to check parameter value
+
+};
+
+#endif
diff --git a/emulator/opengl/host/tools/emugen/VarType.h b/emulator/opengl/host/tools/emugen/VarType.h
new file mode 100644
index 000000000..41bb64501
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/VarType.h
@@ -0,0 +1,78 @@
+/*
+* Copyright (C) 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.
+*/
+#ifndef __VARTYPE__H__
+#define __VARTYPE__H__
+
+#include <string>
+
+class VarConverter {
+public:
+ VarConverter(size_t bytes) : m_bytes(bytes) {}
+ size_t bytes() const { return m_bytes; }
+private:
+ size_t m_bytes;
+};
+
+class Var8 : public VarConverter {
+public:
+ Var8() : VarConverter(1) {}
+};
+
+class Var16 : public VarConverter {
+public:
+ Var16() : VarConverter(2) {}
+};
+
+class Var32 : public VarConverter {
+public:
+ Var32() : VarConverter(4) {}
+};
+
+class Var0 : public VarConverter {
+public:
+ Var0() : VarConverter(0) {}
+};
+
+
+class VarType {
+public:
+ VarType() :
+ m_id(0), m_name("default_constructed"), m_converter(NULL), m_printFomrat("0x%x"), m_isPointer(false)
+ {
+ }
+
+ VarType(size_t id, const std::string & name, const VarConverter * converter, const std::string & printFormat , const bool isPointer) :
+ m_id(id), m_name(name), m_converter(const_cast<VarConverter *>(converter)), m_printFomrat(printFormat), m_isPointer(isPointer)
+ {
+ }
+
+ ~VarType()
+ {
+ }
+ const std::string & name() const { return m_name; }
+ const std::string & printFormat() const { return m_printFomrat; }
+ size_t bytes() const { return m_converter->bytes(); }
+ bool isPointer() const { return m_isPointer; }
+ size_t id() const { return m_id; }
+private:
+ size_t m_id;
+ std::string m_name;
+ VarConverter * m_converter;
+ std::string m_printFomrat;
+ bool m_isPointer;
+};
+
+#endif
diff --git a/emulator/opengl/host/tools/emugen/errors.h b/emulator/opengl/host/tools/emugen/errors.h
new file mode 100644
index 000000000..d09c29291
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/errors.h
@@ -0,0 +1,24 @@
+/*
+* Copyright (C) 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.
+*/
+#ifndef _ERRORS_H_
+#define _ERRORS_H_
+
+#define BAD_USAGE -1
+#define BAD_SPEC_FILE -2
+#define BAD_TYPES_FILE -3
+#define BAD_ATTRIBUTES_FILE -4
+
+#endif
diff --git a/emulator/opengl/host/tools/emugen/main.cpp b/emulator/opengl/host/tools/emugen/main.cpp
new file mode 100644
index 000000000..96377f20a
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/main.cpp
@@ -0,0 +1,164 @@
+/*
+* Copyright (C) 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.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include "errors.h"
+#include "EntryPoint.h"
+#include "strUtils.h"
+#include "ApiGen.h"
+#include "TypeFactory.h"
+
+const std::string SPEC_EXTENSION = std::string(".in");
+const std::string ATTRIB_EXTENSION = std::string(".attrib");
+const std::string TYPES_EXTENTION = std::string(".types");
+
+
+void usage(const char *filename)
+{
+ fprintf(stderr, "Usage: %s [options] <base name>\n", filename);
+ fprintf(stderr, "\t-h: This message\n");
+ fprintf(stderr, "\t-E <dir>: generate encoder into dir\n");
+ fprintf(stderr, "\t-D <dir>: generate decoder into dir\n");
+ fprintf(stderr, "\t-i: input dir, local directory by default\n");
+ fprintf(stderr, "\t-T : generate attribute template into the input directory\n\t\tno other files are generated\n");
+ fprintf(stderr, "\t-W : generate wrapper into dir\n");
+}
+
+int main(int argc, char *argv[])
+{
+ std::string encoderDir = "";
+ std::string decoderDir = "";
+ std::string wrapperDir = "";
+ std::string inDir = ".";
+ bool generateAttributesTemplate = false;
+
+ int c;
+ while((c = getopt(argc, argv, "TE:D:i:hW:")) != -1) {
+ switch(c) {
+ case 'W':
+ wrapperDir = std::string(optarg);
+ break;
+ case 'T':
+ generateAttributesTemplate = true;
+ break;
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ break;
+ case 'E':
+ encoderDir = std::string(optarg);
+ break;
+ case 'D':
+ decoderDir = std::string(optarg);
+ break;
+ case 'i':
+ inDir = std::string(optarg);
+ break;
+ case ':':
+ fprintf(stderr, "Missing argument !!\n");
+ // fall through
+ default:
+ usage(argv[0]);
+ exit(0);
+ }
+ }
+
+ if (optind >= argc) {
+ fprintf(stderr, "Usage: %s [options] <base name> \n", argv[0]);
+ return BAD_USAGE;
+ }
+
+ if (encoderDir.size() == 0 &&
+ decoderDir.size() == 0 &&
+ generateAttributesTemplate == false &&
+ wrapperDir.size() == 0) {
+ fprintf(stderr, "No output specified - aborting\n");
+ return BAD_USAGE;
+ }
+
+ std::string baseName = std::string(argv[optind]);
+ ApiGen apiEntries(baseName);
+
+ // init types;
+ std::string typesFilename = inDir + "/" + baseName + TYPES_EXTENTION;
+
+ if (TypeFactory::instance()->initFromFile(typesFilename) < 0) {
+ fprintf(stderr, "missing or error reading types file: %s...ignored\n", typesFilename.c_str());
+ }
+
+ std::string filename = inDir + "/" + baseName + SPEC_EXTENSION;
+ if (apiEntries.readSpec(filename) < 0) {
+ perror(filename.c_str());
+ return BAD_SPEC_FILE;
+ }
+
+
+ if (generateAttributesTemplate) {
+ apiEntries.genAttributesTemplate(inDir + "/" + baseName + ATTRIB_EXTENSION);
+ exit(0);
+ }
+
+ std::string attribFileName = inDir + "/" + baseName + ATTRIB_EXTENSION;
+ if (apiEntries.readAttributes(attribFileName) < 0) {
+ perror(attribFileName.c_str());
+ fprintf(stderr, "failed to parse attributes\n");
+ exit(1);
+ }
+
+ if (encoderDir.size() != 0) {
+
+ apiEntries.genOpcodes(encoderDir + "/" + baseName + "_opcodes.h");
+ apiEntries.genContext(encoderDir + "/" + baseName + "_client_context.h", ApiGen::CLIENT_SIDE);
+ apiEntries.genContextImpl(encoderDir + "/" + baseName + "_client_context.cpp", ApiGen::CLIENT_SIDE);
+
+ apiEntries.genProcTypes(encoderDir + "/" + baseName + "_client_proc.h", ApiGen::CLIENT_SIDE);
+ apiEntries.genFuncTable(encoderDir + "/" + baseName + "_ftable.h", ApiGen::CLIENT_SIDE);
+
+ apiEntries.genEntryPoints(encoderDir + "/" + baseName + "_entry.cpp", ApiGen::CLIENT_SIDE);
+ apiEntries.genEncoderHeader(encoderDir + "/" + baseName + "_enc.h");
+ apiEntries.genEncoderImpl(encoderDir + "/" + baseName + "_enc.cpp");
+ }
+
+ if (decoderDir.size() != 0) {
+ apiEntries.genOpcodes(decoderDir + "/" + baseName + "_opcodes.h");
+ apiEntries.genProcTypes(decoderDir + "/" + baseName + "_server_proc.h", ApiGen::SERVER_SIDE);
+ apiEntries.genContext(decoderDir + "/" + baseName + "_server_context.h", ApiGen::SERVER_SIDE);
+ apiEntries.genContextImpl(decoderDir + "/" + baseName + "_server_context.cpp", ApiGen::SERVER_SIDE);
+ apiEntries.genDecoderHeader(decoderDir + "/" + baseName + "_dec.h");
+ apiEntries.genDecoderImpl(decoderDir + "/" + baseName + "_dec.cpp");
+ }
+
+ if (wrapperDir.size() != 0) {
+ apiEntries.genProcTypes(wrapperDir + "/" + baseName + "_wrapper_proc.h", ApiGen::WRAPPER_SIDE);
+ apiEntries.genContext(wrapperDir + "/" + baseName + "_wrapper_context.h", ApiGen::WRAPPER_SIDE);
+ apiEntries.genContextImpl(wrapperDir + "/" + baseName + "_wrapper_context.cpp", ApiGen::WRAPPER_SIDE);
+ apiEntries.genEntryPoints(wrapperDir + "/" + baseName + "_wrapper_entry.cpp", ApiGen::WRAPPER_SIDE);
+ }
+
+#ifdef DEBUG_DUMP
+ int withPointers = 0;
+ printf("%d functions found\n", int(apiEntries.size()));
+ for (int i = 0; i < apiEntries.size(); i++) {
+ if (apiEntries[i].hasPointers()) {
+ withPointers++;
+ apiEntries[i].print();
+ }
+ }
+ fprintf(stdout, "%d entries has poitners\n", withPointers);
+#endif
+
+}
+
diff --git a/emulator/opengl/host/tools/emugen/strUtils.cpp b/emulator/opengl/host/tools/emugen/strUtils.cpp
new file mode 100644
index 000000000..357054b5c
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/strUtils.cpp
@@ -0,0 +1,49 @@
+/*
+* Copyright (C) 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.
+*/
+#include "strUtils.h"
+
+using namespace std;
+
+
+std::string getNextToken(const std::string & str, size_t pos, size_t * last, const std::string & delim)
+{
+ if (str.size() == 0 || pos >= str.size()) return "";
+
+ pos = str.find_first_not_of(WHITESPACE, pos);
+ if (pos == std::string::npos) return "";
+
+ *last = str.find_first_of(delim, pos);
+ if (*last == std::string::npos) *last = str.size();
+ std::string retval = str.substr(pos, *last - pos);
+ retval = trim(retval);
+ return retval;
+}
+
+
+std::string trim(const string & str)
+{
+ string result;
+ string::size_type start = str.find_first_not_of(WHITESPACE, 0);
+ string::size_type end = str.find_last_not_of(WHITESPACE);
+ if (start == string::npos || end == string::npos) {
+ result = string("");
+ } else {
+ result = str.substr(start, end - start + 1);
+ }
+ return result;
+}
+
+
diff --git a/emulator/opengl/host/tools/emugen/strUtils.h b/emulator/opengl/host/tools/emugen/strUtils.h
new file mode 100644
index 000000000..3fa0908d3
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/strUtils.h
@@ -0,0 +1,33 @@
+/*
+* Copyright (C) 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.
+*/
+#ifndef STR_UTILS_H_
+#define STR_UTILS_H_
+
+#include <string>
+#include <sstream>
+
+#define WHITESPACE " \t\n"
+
+std::string trim(const std::string & str);
+std::string getNextToken(const std::string & str, size_t pos, size_t * last, const std::string & delim);
+template <class T> std::string inline toString(const T& t) {
+ std::stringstream ss;
+ ss << t;
+ return ss.str();
+
+}
+
+#endif