Merge "Emugen : A tool to generate wire protocol code"
This commit is contained in:
10
tools/emulator/opengl/host/tools/emugen/Android.mk
Normal file
10
tools/emulator/opengl/host/tools/emugen/Android.mk
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
LOCAL_PATH:=$(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_MODULE_TAGS := debug
|
||||||
|
LOCAL_SRC_FILES := ApiGen.cpp EntryPoint.cpp main.cpp strUtils.cpp TypeFactory.cpp
|
||||||
|
LOCAL_MODULE := emugen
|
||||||
|
|
||||||
|
include $(BUILD_HOST_EXECUTABLE)
|
||||||
805
tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
Normal file
805
tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
Normal file
@@ -0,0 +1,805 @@
|
|||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
fprintf(fp, "#ifndef __%s_%s_proc_t_h\n", m_basename.c_str(), sideString(side));
|
||||||
|
fprintf(fp, "#define __%s_%s_proc_t_h\n", m_basename.c_str(), sideString(side));
|
||||||
|
fprintf(fp, "\n\n");
|
||||||
|
fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size(); i++) {
|
||||||
|
EntryPoint *e = &at(i);
|
||||||
|
|
||||||
|
fprintf(fp, "typedef ");
|
||||||
|
e->retval().printType(fp);
|
||||||
|
fprintf(fp, " (* %s_%s_proc_t) (", 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::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) {
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "};\n");
|
||||||
|
|
||||||
|
fprintf(fp, "\n#endif\n");
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ApiGen::genClientEntryPoints(const std::string & filename)
|
||||||
|
{
|
||||||
|
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(CLIENT_SIDE));
|
||||||
|
fprintf(fp, "\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, "static %s_%s_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;\n",
|
||||||
|
m_basename.c_str(), sideString(CLIENT_SIDE));
|
||||||
|
|
||||||
|
fprintf(fp,
|
||||||
|
"void %s_%s_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }\n\n",
|
||||||
|
m_basename.c_str(), sideString(CLIENT_SIDE));
|
||||||
|
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size(); i++) {
|
||||||
|
EntryPoint *e = &at(i);
|
||||||
|
e->print(fp);
|
||||||
|
fprintf(fp, "{\n");
|
||||||
|
fprintf(fp, "\t %s_%s_context_t * ctx = getCurrentContext(); \n",
|
||||||
|
m_basename.c_str(), sideString(CLIENT_SIDE));
|
||||||
|
|
||||||
|
bool shouldReturn = !e->retval().isVoid();
|
||||||
|
|
||||||
|
fprintf(fp, "\t %sctx->%s(ctx",
|
||||||
|
shouldReturn ? "return " : "",
|
||||||
|
e->name().c_str());
|
||||||
|
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, ");\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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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\tfprintf(stderr, \"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\t%s *ctx = (%s *)self;\n\n",
|
||||||
|
classname.c_str(),
|
||||||
|
classname.c_str());
|
||||||
|
|
||||||
|
// size calculation ;
|
||||||
|
fprintf(fp, "\t size_t packetSize = ");
|
||||||
|
|
||||||
|
VarsArray & evars = e->vars();
|
||||||
|
size_t nvars = evars.size();
|
||||||
|
size_t npointers = 0;
|
||||||
|
for (size_t j = 0; j < nvars; j++) {
|
||||||
|
fprintf(fp, "%s ", j == 0 ? "" : " +");
|
||||||
|
if (evars[j].isPointer()) {
|
||||||
|
npointers++;
|
||||||
|
|
||||||
|
if (evars[j].lenExpression() == "") {
|
||||||
|
fprintf(stderr, "%s: data len is undefined for '%s'\n",
|
||||||
|
e->name().c_str(), evars[j].name().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evars[j].nullAllowed()) {
|
||||||
|
fprintf(fp, "(%s != NULL ? %s : 0)",
|
||||||
|
evars[j].name().c_str(),
|
||||||
|
evars[j].lenExpression().c_str());
|
||||||
|
} else {
|
||||||
|
if (evars[j].pointerDir() == Var::POINTER_IN ||
|
||||||
|
evars[j].pointerDir() == Var::POINTER_INOUT) {
|
||||||
|
fprintf(fp, "%s", evars[j].lenExpression().c_str());
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "%u", (unsigned int) evars[j].type()->bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(fp, " %s 8 + %u * 4;\n", nvars != 0 ? "+" : "", (unsigned int) npointers);
|
||||||
|
|
||||||
|
// allocate buffer from the stream;
|
||||||
|
fprintf(fp, "\t unsigned char *ptr = ctx->m_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++) {
|
||||||
|
if (evars[j].isPointer()) {
|
||||||
|
// encode a pointer header
|
||||||
|
if (evars[j].nullAllowed()) {
|
||||||
|
fprintf(fp, "\t*(unsigned int *)(ptr) = (%s != NULL) ? %s : 0; ptr += 4; \n",
|
||||||
|
evars[j].name().c_str(), evars[j].lenExpression().c_str());
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "\t*(unsigned int *)(ptr) = %s; ptr += 4; \n",
|
||||||
|
evars[j].lenExpression().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
Var::PointerDir dir = evars[j].pointerDir();
|
||||||
|
if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
|
||||||
|
if (evars[j].nullAllowed()) {
|
||||||
|
fprintf(fp, "\tif (%s != NULL) ", evars[j].name().c_str());
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "\t");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evars[j].packExpression().size() != 0) {
|
||||||
|
fprintf(fp, "%s;", evars[j].packExpression().c_str());
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "memcpy(ptr, %s, %s);",
|
||||||
|
evars[j].name().c_str(),
|
||||||
|
evars[j].lenExpression().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "ptr += %s;\n", evars[j].lenExpression().c_str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// encode a non pointer variable
|
||||||
|
if (!evars[j].isVoid()) {
|
||||||
|
fprintf(fp, "\t*(%s *) (ptr) = %s; ptr += %u;\n",
|
||||||
|
evars[j].type()->name().c_str(), evars[j].name().c_str(),
|
||||||
|
(uint) evars[j].type()->bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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) {
|
||||||
|
if (evars[j].nullAllowed()) {
|
||||||
|
fprintf(fp, "\tif (%s != NULL) ctx->m_stream->readback(%s, %s);\n",
|
||||||
|
evars[j].name().c_str(),
|
||||||
|
evars[j].name().c_str(),
|
||||||
|
evars[j].lenExpression().c_str());
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "\tctx->m_stream->readback(%s, %s);\n",
|
||||||
|
evars[j].name().c_str(),
|
||||||
|
evars[j].lenExpression().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, "\tctx->m_stream->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, "\tint initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);\n");
|
||||||
|
fprintf(fp, "\n};\n\n");
|
||||||
|
fprintf(fp, "#endif");
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
// 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\
|
||||||
|
\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();
|
||||||
|
if (e->retval().isPointer()) retvalType += "*";
|
||||||
|
}
|
||||||
|
|
||||||
|
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)\\n\"", 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) {
|
||||||
|
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 + *(size_t *)(ptr +" + varoffset + ")";
|
||||||
|
} else { // in 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%u", (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) {
|
||||||
|
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, "\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");
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
78
tools/emulator/opengl/host/tools/emugen/ApiGen.h
Normal file
78
tools/emulator/opengl/host/tools/emugen/ApiGen.h
Normal file
@@ -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 __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 } 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) { return (side == CLIENT_SIDE) ? "client" : "server"; }
|
||||||
|
|
||||||
|
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 genContext(const std::string &filename, SideType side);
|
||||||
|
int genClientEntryPoints(const std::string &filename);
|
||||||
|
|
||||||
|
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
|
||||||
335
tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp
Normal file
335
tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
/*
|
||||||
|
* 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_vars.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseTypeField(const std::string & f, std::string *vartype, bool *pointer_type, std::string *varname)
|
||||||
|
{
|
||||||
|
size_t pos = 0, last;
|
||||||
|
bool done = false;
|
||||||
|
|
||||||
|
|
||||||
|
*vartype = "";
|
||||||
|
if (varname != NULL) *varname = "";
|
||||||
|
*pointer_type = false;
|
||||||
|
|
||||||
|
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;
|
||||||
|
} else {
|
||||||
|
// must be a type name;
|
||||||
|
*vartype = str;
|
||||||
|
// do we have an astriks at the end of the name?
|
||||||
|
if (vartype->at(vartype->size() - 1) == '*') {
|
||||||
|
*pointer_type = true;
|
||||||
|
// remove the astriks
|
||||||
|
(*vartype)[vartype->size() - 1] = ' ';
|
||||||
|
*vartype = trim(*vartype);
|
||||||
|
}
|
||||||
|
state = ST_NAME;
|
||||||
|
pos = last;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ST_NAME:
|
||||||
|
if (str.size() == 0) {
|
||||||
|
done = true;
|
||||||
|
} else if (str == "*") {
|
||||||
|
*pointer_type = true;
|
||||||
|
// remove the leading astriks;
|
||||||
|
pos = last;
|
||||||
|
} else if (varname == NULL) {
|
||||||
|
done = true;
|
||||||
|
} else {
|
||||||
|
if (str[0] == '*') {
|
||||||
|
*pointer_type = true;
|
||||||
|
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;
|
||||||
|
bool pointer_type;
|
||||||
|
if (!parseTypeField(field, &retTypeName, &pointer_type, 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, pointer_type, std::string(""), Var::POINTER_OUT, 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, &pointer_type, &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" && !pointer_type)) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "var" << nvars;
|
||||||
|
varname = oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_vars.push_back(Var(varname, v, pointer_type, 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%s(",
|
||||||
|
m_retval.type()->name().c_str(),
|
||||||
|
m_retval.isPointer() ? "*" : "",
|
||||||
|
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%s", m_vars[i].type()->name().c_str(),
|
||||||
|
m_vars[i].isPointer() ? "*" : "",
|
||||||
|
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 == "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;
|
||||||
|
}
|
||||||
|
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 -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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 == "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 {
|
||||||
|
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;
|
||||||
|
}
|
||||||
64
tools/emulator/opengl/host/tools/emugen/EntryPoint.h
Normal file
64
tools/emulator/opengl/host/tools/emugen/EntryPoint.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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; }
|
||||||
|
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;
|
||||||
|
|
||||||
|
void err(unsigned int lc, const char *msg) {
|
||||||
|
fprintf(stderr, "line %d: %s\n", lc, msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
292
tools/emulator/opengl/host/tools/emugen/README
Normal file
292
tools/emulator/opengl/host/tools/emugen/README
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
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 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 // 4 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>
|
||||||
|
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)
|
||||||
|
|
||||||
|
example:
|
||||||
|
GLint 32 %d
|
||||||
|
|
||||||
|
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_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.
|
||||||
|
|
||||||
|
5.1.2.2 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 encoder functions
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
.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 | ... >
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
135
tools/emulator/opengl/host/tools/emugen/TypeFactory.cpp
Normal file
135
tools/emulator/opengl/host/tools/emugen/TypeFactory.cpp
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* 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) \
|
||||||
|
g_varMap.insert(std::pair<std::string, VarType>(name, VarType(g_typeId++, name, &g_var##size,printformat)));
|
||||||
|
|
||||||
|
void TypeFactory::initBaseTypes()
|
||||||
|
{
|
||||||
|
g_initialized = true;
|
||||||
|
ADD_TYPE("UNKNOWN", 0, "0x%x");
|
||||||
|
ADD_TYPE("void", 0, "0x%x");
|
||||||
|
ADD_TYPE("char", 8, "%c");
|
||||||
|
ADD_TYPE("int", 32, "%d");
|
||||||
|
ADD_TYPE("float", 32, "%d");
|
||||||
|
ADD_TYPE("short", 16, "%d");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
37
tools/emulator/opengl/host/tools/emugen/TypeFactory.h
Normal file
37
tools/emulator/opengl/host/tools/emugen/TypeFactory.h
Normal file
@@ -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
|
||||||
94
tools/emulator/opengl/host/tools/emugen/Var.h
Normal file
94
tools/emulator/opengl/host/tools/emugen/Var.h
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* 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_pointer(false),
|
||||||
|
m_lenExpression(""),
|
||||||
|
m_pointerDir(POINTER_IN),
|
||||||
|
m_nullAllowed(false),
|
||||||
|
m_packExpression("")
|
||||||
|
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Var(const std::string & name,
|
||||||
|
const VarType * vartype,
|
||||||
|
bool isPointer,
|
||||||
|
const std::string & lenExpression,
|
||||||
|
PointerDir dir,
|
||||||
|
const std::string &packExpression) :
|
||||||
|
m_name(name),
|
||||||
|
m_type(const_cast<VarType *>(vartype)),
|
||||||
|
m_pointer(isPointer),
|
||||||
|
m_lenExpression(lenExpression),
|
||||||
|
m_pointerDir(dir),
|
||||||
|
m_nullAllowed(false),
|
||||||
|
m_packExpression(packExpression)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(const std::string name, const VarType * vartype,
|
||||||
|
bool isPointer, std::string lenExpression,
|
||||||
|
PointerDir dir, std::string packExpression) {
|
||||||
|
m_name = name;
|
||||||
|
m_type = vartype;
|
||||||
|
m_pointer = isPointer;
|
||||||
|
m_lenExpression = lenExpression;
|
||||||
|
m_packExpression = packExpression;
|
||||||
|
m_pointerDir = dir;
|
||||||
|
m_nullAllowed = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string & name() const { return m_name; }
|
||||||
|
const VarType * type() const { return m_type; }
|
||||||
|
bool isPointer() const { return m_pointer; }
|
||||||
|
bool isVoid() const { return ((m_type->bytes() == 0) && (m_pointer == false)); }
|
||||||
|
const std::string & lenExpression() const { return m_lenExpression; }
|
||||||
|
const std::string & packExpression() const { return(m_packExpression); }
|
||||||
|
void setLenExpression(const std::string & lenExpression) { m_lenExpression = lenExpression; }
|
||||||
|
void setPackExpression(const std::string & packExpression) { m_packExpression = packExpression; }
|
||||||
|
void setPointerDir(PointerDir dir) { m_pointerDir = dir; }
|
||||||
|
PointerDir pointerDir() { return m_pointerDir; }
|
||||||
|
void setNullAllowed(bool state) { m_nullAllowed = state; }
|
||||||
|
bool nullAllowed() const { return m_nullAllowed; }
|
||||||
|
void printType(FILE *fp) { fprintf(fp, "%s%s", m_type->name().c_str(), m_pointer ? "*" : ""); }
|
||||||
|
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;
|
||||||
|
std::string m_packExpression; // an expression to pack data into the stream
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
76
tools/emulator/opengl/host/tools/emugen/VarType.h
Normal file
76
tools/emulator/opengl/host/tools/emugen/VarType.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* 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")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VarType(size_t id, const std::string & name, const VarConverter * converter, const std::string & printFormat ) :
|
||||||
|
m_id(id), m_name(name), m_converter(const_cast<VarConverter *>(converter)), m_printFomrat(printFormat)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~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(); }
|
||||||
|
size_t id() const { return m_id; }
|
||||||
|
private:
|
||||||
|
size_t m_id;
|
||||||
|
std::string m_name;
|
||||||
|
VarConverter * m_converter;
|
||||||
|
std::string m_printFomrat;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
24
tools/emulator/opengl/host/tools/emugen/errors.h
Normal file
24
tools/emulator/opengl/host/tools/emugen/errors.h
Normal file
@@ -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
|
||||||
147
tools/emulator/opengl/host/tools/emugen/main.cpp
Normal file
147
tools/emulator/opengl/host/tools/emugen/main.cpp
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
std::string encoderDir = "";
|
||||||
|
std::string decoderDir = "";
|
||||||
|
std::string inDir = ".";
|
||||||
|
bool generateAttributesTemplate = false;
|
||||||
|
|
||||||
|
int c;
|
||||||
|
while((c = getopt(argc, argv, "TE:D:i:h")) != -1) {
|
||||||
|
switch(c) {
|
||||||
|
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) {
|
||||||
|
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.genProcTypes(encoderDir + "/" + baseName + "_client_proc.h", ApiGen::CLIENT_SIDE);
|
||||||
|
|
||||||
|
apiEntries.genClientEntryPoints(encoderDir + "/" + baseName + "_entry.cpp");
|
||||||
|
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.genDecoderHeader(decoderDir + "/" + baseName + "_dec.h");
|
||||||
|
apiEntries.genDecoderImpl(decoderDir + "/" + baseName + "_dec.cpp");
|
||||||
|
// generate the encoder type;
|
||||||
|
|
||||||
|
}
|
||||||
|
#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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
49
tools/emulator/opengl/host/tools/emugen/strUtils.cpp
Normal file
49
tools/emulator/opengl/host/tools/emugen/strUtils.cpp
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
33
tools/emulator/opengl/host/tools/emugen/strUtils.h
Normal file
33
tools/emulator/opengl/host/tools/emugen/strUtils.h
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user