diff --git a/tools/emulator/opengl/host/libs/GLESv1_dec/Android.mk b/tools/emulator/opengl/host/libs/GLESv1_dec/Android.mk index c86c29203..f5e244144 100644 --- a/tools/emulator/opengl/host/libs/GLESv1_dec/Android.mk +++ b/tools/emulator/opengl/host/libs/GLESv1_dec/Android.mk @@ -31,7 +31,7 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_LDLIBS := -ldl -GEN := $(intermediates)/gl_dec.cpp $(intermediates)/gl_dec.h +GEN := $(intermediates)/gl_server_context.cpp $(intermediates)/gl_dec.cpp $(intermediates)/gl_dec.h $(GEN) : PRIVATE_PATH := $(LOCAL_PATH) $(GEN) : PRIVATE_CUSTOM_TOOL := $(EMUGEN) -D $(intermediates) -i $(emulatorOpengl)/system/GLESv1_enc gl diff --git a/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp b/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp index dfba6a244..0c94c5967 100644 --- a/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp +++ b/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp @@ -21,7 +21,6 @@ #include #include - EntryPoint * ApiGen::findEntryByName(const std::string & name) { EntryPoint * entry = NULL; @@ -119,12 +118,15 @@ int ApiGen::genContext(const std::string & filename, SideType side) // virtual destructor fprintf(fp, "\t virtual ~%s_%s_context_t() {}\n", m_basename.c_str(), sideString(side)); // accessor - if (side == CLIENT_SIDE) { + 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, "\tvoid setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);\n"); } + // init function + fprintf(fp, "\tint initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);\n"); + fprintf(fp, "};\n"); fprintf(fp, "\n#endif\n"); @@ -132,8 +134,15 @@ int ApiGen::genContext(const std::string & filename, SideType side) return 0; } -int ApiGen::genClientEntryPoints(const std::string & filename) +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()); @@ -143,7 +152,7 @@ int ApiGen::genClientEntryPoints(const std::string & filename) printHeader(fp); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); - fprintf(fp, "#include \"%s_%s_context.h\"\n", m_basename.c_str(), sideString(CLIENT_SIDE)); + fprintf(fp, "#include \"%s_%s_context.h\"\n", m_basename.c_str(), sideString(side)); fprintf(fp, "\n"); fprintf(fp, "extern \"C\" {\n"); @@ -154,11 +163,11 @@ int ApiGen::genClientEntryPoints(const std::string & filename) fprintf(fp, "};\n\n"); fprintf(fp, "static %s_%s_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;\n", - m_basename.c_str(), sideString(CLIENT_SIDE)); + m_basename.c_str(), sideString(side)); fprintf(fp, "void %s_%s_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }\n\n", - m_basename.c_str(), sideString(CLIENT_SIDE)); + m_basename.c_str(), sideString(side)); for (size_t i = 0; i < size(); i++) { @@ -166,18 +175,21 @@ int ApiGen::genClientEntryPoints(const std::string & filename) e->print(fp); fprintf(fp, "{\n"); fprintf(fp, "\t %s_%s_context_t * ctx = getCurrentContext(); \n", - m_basename.c_str(), sideString(CLIENT_SIDE)); + m_basename.c_str(), sideString(side)); bool shouldReturn = !e->retval().isVoid(); - - fprintf(fp, "\t %sctx->%s(ctx", + bool shouldCallWithContext = (side == CLIENT_SIDE); + fprintf(fp, "\t %sctx->%s(%s", shouldReturn ? "return " : "", - e->name().c_str()); + 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", e->vars()[j].name().c_str()); + fprintf(fp, "%s %s", + j != 0 || shouldCallWithContext ? "," : "", + e->vars()[j].name().c_str()); } } fprintf(fp, ");\n"); @@ -467,7 +479,6 @@ int ApiGen::genDecoderHeader(const std::string &filename) 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, "\tint initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);\n"); fprintf(fp, "\n};\n\n"); fprintf(fp, "#endif"); @@ -475,6 +486,39 @@ int ApiGen::genDecoderHeader(const std::string &filename) 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 \n"); + fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(side)); + fprintf(fp, "#include \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(SERVER_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"); @@ -492,22 +536,7 @@ int ApiGen::genDecoderImpl(const std::string &filename) fprintf(fp, "\n\n#include \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 \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(SERVER_SIDE)); - - } - fprintf(fp, "\treturn 0;\n"); - fprintf(fp, "}\n\n"); + fprintf(fp, "#include \n\n"); // decoder switch; fprintf(fp, "size_t %s::decode(void *buf, size_t len, IOStream *stream)\n{\n", classname.c_str()); diff --git a/tools/emulator/opengl/host/tools/emugen/ApiGen.h b/tools/emulator/opengl/host/tools/emugen/ApiGen.h index 3c7fd27b7..18f974b58 100644 --- a/tools/emulator/opengl/host/tools/emugen/ApiGen.h +++ b/tools/emulator/opengl/host/tools/emugen/ApiGen.h @@ -25,7 +25,7 @@ class ApiGen : public std::vector { public: typedef std::vector StringVec; - typedef enum { CLIENT_SIDE, SERVER_SIDE } SideType; + typedef enum { CLIENT_SIDE, SERVER_SIDE, WRAPPER_SIDE } SideType; ApiGen(const std::string & basename) : m_basename(basename), @@ -42,7 +42,21 @@ public: int baseOpcode() { return m_baseOpcode; } void setBaseOpcode(int base) { m_baseOpcode = base; } - const char *sideString(SideType side) { return (side == CLIENT_SIDE) ? "client" : "server"; } + 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; } @@ -55,7 +69,9 @@ public: int genProcTypes(const std::string &filename, SideType side); int genContext(const std::string &filename, SideType side); - int genClientEntryPoints(const std::string &filename); + 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); diff --git a/tools/emulator/opengl/host/tools/emugen/README b/tools/emulator/opengl/host/tools/emugen/README index 18c3edbd7..6fa9ec95a 100644 --- a/tools/emulator/opengl/host/tools/emugen/README +++ b/tools/emulator/opengl/host/tools/emugen/README @@ -1,9 +1,13 @@ 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 @@ -18,7 +22,7 @@ are used interchangeably by the context. Wire Protocol packet structure: - +------------------------------- A general Encoder->Decoder packet is structured as following: struct Packet { unsigned int opcode; @@ -52,7 +56,7 @@ Since ‘foo’ returns value, the caller is expected to read back the return pa Pointer decoding: - +---------------- The wire protocol also allows exchanging of pointer data (arrays). Pointers are defined with directions: @@ -92,7 +96,7 @@ The return packet is; } 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 @@ -101,7 +105,7 @@ 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 @@ -135,17 +139,22 @@ tree. The format of the .attrib file is described below. This files describes the types that are described by the API. A type is defined as follows: - + where: is the name of the type as described in the API 0, 8, 16, 32 sizes are accepted - a string to format the value of the type, as acceted by printf(3) + a string to format the value of the type, as +acceted by printf(3) + true or false string species whether the type should be +treated as a pointer. example: -GLint 32 %d +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: @@ -174,6 +183,9 @@ 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 @@ -181,7 +193,8 @@ functionality. api_enc.cpp - Encoder implementation. -5.1.2.2 Decoder generated files +Decoder generated files +----------------------- In order to generate the decoder files, one should run the ‘emugen’ tool as follows: emugen -i -D basename @@ -197,8 +210,9 @@ api_opcodes.h - Protocol opcodes api_server_proc.h - type definitions for the server side procedures -api_server_context.h - dispatch table the encoder functions +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 @@ -207,8 +221,30 @@ initialize the API server implementation. An example for such initialization is loading a set of functions from a shared library module. -.attrib file format description: +Wrapper generated files +----------------------- +In order to generate a wrapper library files, one should run the +'emugen' tool as follows: +emugen -i -W basename +where: + containes the api specification files (basename.in + basename.attrib) + - 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: diff --git a/tools/emulator/opengl/host/tools/emugen/main.cpp b/tools/emulator/opengl/host/tools/emugen/main.cpp index aefba0a90..bbc9d9058 100644 --- a/tools/emulator/opengl/host/tools/emugen/main.cpp +++ b/tools/emulator/opengl/host/tools/emugen/main.cpp @@ -34,18 +34,23 @@ void usage(const char *filename) fprintf(stderr, "\t-D : 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:h")) != -1) { + while((c = getopt(argc, argv, "TE:D:i:hW:")) != -1) { switch(c) { + case 'W': + wrapperDir = std::string(optarg); + break; case 'T': generateAttributesTemplate = true; break; @@ -76,7 +81,10 @@ int main(int argc, char *argv[]) return BAD_USAGE; } - if (encoderDir.size() == 0 && decoderDir.size() == 0 && generateAttributesTemplate == false) { + if (encoderDir.size() == 0 && + decoderDir.size() == 0 && + generateAttributesTemplate == false && + wrapperDir.size() == 0) { fprintf(stderr, "No output specified - aborting\n"); return BAD_USAGE; } @@ -114,23 +122,31 @@ int main(int argc, char *argv[]) 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.genClientEntryPoints(encoderDir + "/" + baseName + "_entry.cpp"); + 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.genEntryPoints(decoderDir + "/" + baseName + "_entry.cpp", baseName); 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"); - // generate the encoder type; - } + + 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()));