aboutsummaryrefslogtreecommitdiffstats
path: root/emulator
diff options
context:
space:
mode:
Diffstat (limited to 'emulator')
-rw-r--r--emulator/opengl/host/libs/GLESv1_dec/GLDecoder.cpp40
-rw-r--r--emulator/opengl/host/libs/GLESv1_dec/gl.types66
-rw-r--r--emulator/opengl/host/libs/GLESv2_dec/GL2Decoder.cpp16
-rw-r--r--emulator/opengl/host/libs/GLESv2_dec/gl2.types73
-rw-r--r--emulator/opengl/host/libs/libOpenglRender/RenderControl.cpp52
-rw-r--r--emulator/opengl/host/libs/renderControl_dec/renderControl.types22
-rw-r--r--emulator/opengl/host/tools/emugen/ApiGen.cpp363
-rw-r--r--emulator/opengl/host/tools/emugen/TypeFactory.cpp76
-rw-r--r--emulator/opengl/host/tools/emugen/VarType.h76
-rw-r--r--emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h187
-rw-r--r--emulator/opengl/shared/emugl/common/Android.mk1
-rw-r--r--emulator/opengl/shared/emugl/common/unique_integer_map.h225
-rw-r--r--emulator/opengl/shared/emugl/common/unique_integer_map_unittest.cpp103
13 files changed, 969 insertions, 331 deletions
diff --git a/emulator/opengl/host/libs/GLESv1_dec/GLDecoder.cpp b/emulator/opengl/host/libs/GLESv1_dec/GLDecoder.cpp
index 7aa6ede83..725b815a0 100644
--- a/emulator/opengl/host/libs/GLESv1_dec/GLDecoder.cpp
+++ b/emulator/opengl/host/libs/GLESv1_dec/GLDecoder.cpp
@@ -58,26 +58,26 @@ int GLDecoder::initGL(get_proc_func_t getProcFunc, void *getProcFuncData)
this->initDispatchByName(getProcFunc, getProcFuncData);
}
- set_glGetCompressedTextureFormats(s_glGetCompressedTextureFormats);
- set_glVertexPointerOffset(s_glVertexPointerOffset);
- set_glColorPointerOffset(s_glColorPointerOffset);
- set_glNormalPointerOffset(s_glNormalPointerOffset);
- set_glTexCoordPointerOffset(s_glTexCoordPointerOffset);
- set_glPointSizePointerOffset(s_glPointSizePointerOffset);
- set_glWeightPointerOffset(s_glWeightPointerOffset);
- set_glMatrixIndexPointerOffset(s_glMatrixIndexPointerOffset);
-
- set_glVertexPointerData(s_glVertexPointerData);
- set_glColorPointerData(s_glColorPointerData);
- set_glNormalPointerData(s_glNormalPointerData);
- set_glTexCoordPointerData(s_glTexCoordPointerData);
- set_glPointSizePointerData(s_glPointSizePointerData);
- set_glWeightPointerData(s_glWeightPointerData);
- set_glMatrixIndexPointerData(s_glMatrixIndexPointerData);
-
- set_glDrawElementsOffset(s_glDrawElementsOffset);
- set_glDrawElementsData(s_glDrawElementsData);
- set_glFinishRoundTrip(s_glFinishRoundTrip);
+ glGetCompressedTextureFormats = s_glGetCompressedTextureFormats;
+ glVertexPointerOffset = s_glVertexPointerOffset;
+ glColorPointerOffset = s_glColorPointerOffset;
+ glNormalPointerOffset = s_glNormalPointerOffset;
+ glTexCoordPointerOffset = s_glTexCoordPointerOffset;
+ glPointSizePointerOffset = s_glPointSizePointerOffset;
+ glWeightPointerOffset = s_glWeightPointerOffset;
+ glMatrixIndexPointerOffset = s_glMatrixIndexPointerOffset;
+
+ glVertexPointerData = s_glVertexPointerData;
+ glColorPointerData = s_glColorPointerData;
+ glNormalPointerData = s_glNormalPointerData;
+ glTexCoordPointerData = s_glTexCoordPointerData;
+ glPointSizePointerData = s_glPointSizePointerData;
+ glWeightPointerData = s_glWeightPointerData;
+ glMatrixIndexPointerData = s_glMatrixIndexPointerData;
+
+ glDrawElementsOffset = s_glDrawElementsOffset;
+ glDrawElementsData = s_glDrawElementsData;
+ glFinishRoundTrip = s_glFinishRoundTrip;
return 0;
}
diff --git a/emulator/opengl/host/libs/GLESv1_dec/gl.types b/emulator/opengl/host/libs/GLESv1_dec/gl.types
index b269c0129..2bc2a9e03 100644
--- a/emulator/opengl/host/libs/GLESv1_dec/gl.types
+++ b/emulator/opengl/host/libs/GLESv1_dec/gl.types
@@ -1,33 +1,33 @@
-GLbitfield 32 0x%08x false
-GLboolean 8 %d false
-GLclampf 32 %f false
-GLclampx 32 0x%08x false
-GLeglImageOES 32 %p false
-GLenum 32 0x%08x false
-GLfixed 32 0x%08x false
-GLfloat 32 %f false
-GLint 32 %d false
-GLintptr 32 %p false
-GLshort 16 %d false
-GLsizei 32 %d false
-GLsizeiptr 32 %p false
-GLubyte 8 0x%02x false
-GLuint 32 %u false
-GLvoid 0 %x false
-GLchar 8 %d false
-GLenum* 32 0x%08x true
-GLboolean* 32 0x%08x true
-GLclampf* 32 0x%08x true
-GLclampx* 32 0x%08x true
-GLeglImageOES* 32 0x%08x true
-GLfixed* 32 0x%08x true
-GLfloat* 32 0x%08x true
-GLint* 32 0x%08x true
-GLshort* 32 0x%08x true
-GLsizei* 32 0x%08x true
-GLubyte* 32 0x%08x true
-GLuint* 32 0x%08x true
-GLvoid* 32 0x%08x true
-GLchar* 32 0x%08x true
-GLvoid** 32 0x%08x true
-void* 32 0x%08x true
+GLbitfield 32 0x%08x
+GLboolean 8 %d
+GLclampf 32 %f
+GLclampx 32 0x%08x
+GLeglImageOES 32 %p
+GLenum 32 0x%08x
+GLfixed 32 0x%08x
+GLfloat 32 %f
+GLint 32 %d
+GLintptr 32 %p
+GLshort 16 %d
+GLsizei 32 %d
+GLsizeiptr 32 %p
+GLubyte 8 0x%02x
+GLuint 32 %u
+GLvoid 0 %x
+GLchar 8 %d
+GLenum* 32 0x%08x
+GLboolean* 32 0x%08x
+GLclampf* 32 0x%08x
+GLclampx* 32 0x%08x
+GLeglImageOES* 32 0x%08x
+GLfixed* 32 0x%08x
+GLfloat* 32 0x%08x
+GLint* 32 0x%08x
+GLshort* 32 0x%08x
+GLsizei* 32 0x%08x
+GLubyte* 32 0x%08x
+GLuint* 32 0x%08x
+GLvoid* 32 0x%08x
+GLchar* 32 0x%08x
+GLvoid** 32 0x%08x
+void* 32 0x%08x
diff --git a/emulator/opengl/host/libs/GLESv2_dec/GL2Decoder.cpp b/emulator/opengl/host/libs/GLESv2_dec/GL2Decoder.cpp
index 2ef306e2a..712dcc7e6 100644
--- a/emulator/opengl/host/libs/GLESv2_dec/GL2Decoder.cpp
+++ b/emulator/opengl/host/libs/GLESv2_dec/GL2Decoder.cpp
@@ -70,14 +70,14 @@ int GL2Decoder::initGL(get_proc_func_t getProcFunc, void *getProcFuncData)
this->initDispatchByName(getProcFunc, getProcFuncData);
}
- set_glGetCompressedTextureFormats(s_glGetCompressedTextureFormats);
- set_glVertexAttribPointerData(s_glVertexAttribPointerData);
- set_glVertexAttribPointerOffset(s_glVertexAttribPointerOffset);
-
- set_glDrawElementsOffset(s_glDrawElementsOffset);
- set_glDrawElementsData(s_glDrawElementsData);
- set_glShaderString(s_glShaderString);
- set_glFinishRoundTrip(s_glFinishRoundTrip);
+ glGetCompressedTextureFormats = s_glGetCompressedTextureFormats;
+ glVertexAttribPointerData = s_glVertexAttribPointerData;
+ glVertexAttribPointerOffset = s_glVertexAttribPointerOffset;
+
+ glDrawElementsOffset = s_glDrawElementsOffset;
+ glDrawElementsData = s_glDrawElementsData;
+ glShaderString = s_glShaderString;
+ glFinishRoundTrip = s_glFinishRoundTrip;
return 0;
}
diff --git a/emulator/opengl/host/libs/GLESv2_dec/gl2.types b/emulator/opengl/host/libs/GLESv2_dec/gl2.types
index 4cee99ef0..ab4eae31e 100644
--- a/emulator/opengl/host/libs/GLESv2_dec/gl2.types
+++ b/emulator/opengl/host/libs/GLESv2_dec/gl2.types
@@ -1,37 +1,36 @@
-GLbitfield 32 0x%08x false
-GLboolean 8 %d false
-GLclampf 32 %f false
-GLclampx 32 0x%08x false
-GLeglImageOES 32 %p false
-GLenum 32 0x%08x false
-GLfixed 32 0x%08x false
-GLfloat 32 %f false
-GLint 32 %d false
-GLintptr 32 %p false
-GLshort 16 %d false
-GLsizei 32 %d false
-GLsizeiptr 32 %p false
-GLubyte 8 0x%02x false
-GLuint 32 %u false
-GLvoid 0 %x false
-GLchar 8 %d false
-GLenum* 32 0x%08x true
-GLboolean* 32 0x%08x true
-GLclampf* 32 0x%08x true
-GLclampx* 32 0x%08x true
-GLeglImageOES* 32 0x%08x true
-GLfixed* 32 0x%08x true
-GLfloat* 32 0x%08x true
-GLint* 32 0x%08x true
-GLshort* 32 0x%08x true
-GLsizei* 32 0x%08x true
-GLubyte* 32 0x%08x true
-GLuint* 32 0x%08x true
-GLvoid* 32 0x%08x true
-GLchar* 32 0x%08x true
-GLchar** 32 0x%08x true
-GLvoid** 32 0x%08x true
-void* 32 0x%08x true
-GLstr 32 %s true
-GLstr* 32 0x%08x true
-GLvoidptr* 32 0x%08x true \ No newline at end of file
+GLbitfield 32 0x%08x
+GLboolean 8 %d
+GLclampf 32 %f
+GLclampx 32 0x%08x
+GLeglImageOES 32 %p
+GLenum 32 0x%08x
+GLfixed 32 0x%08x
+GLfloat 32 %f
+GLint 32 %d
+GLintptr 32 %p
+GLshort 16 %d
+GLsizei 32 %d
+GLsizeiptr 32 %p
+GLubyte 8 0x%02x
+GLuint 32 %u
+GLvoid 0 %x
+GLchar 8 %d
+GLenum* 32 0x%08x
+GLboolean* 32 0x%08x
+GLclampf* 32 0x%08x
+GLclampx* 32 0x%08x
+GLeglImageOES* 32 0x%08x
+GLfixed* 32 0x%08x
+GLfloat* 32 0x%08x
+GLint* 32 0x%08x
+GLshort* 32 0x%08x
+GLsizei* 32 0x%08x
+GLubyte* 32 0x%08x
+GLuint* 32 0x%08x
+GLvoid* 32 0x%08x
+GLchar* 32 0x%08x
+GLchar** 32 0x%08x
+GLvoid** 32 0x%08x
+void* 32 0x%08x
+GLstr* 32 0x%08x
+GLvoidptr* 32 0x%08x
diff --git a/emulator/opengl/host/libs/libOpenglRender/RenderControl.cpp b/emulator/opengl/host/libs/libOpenglRender/RenderControl.cpp
index 83ba9c586..c7c792aa4 100644
--- a/emulator/opengl/host/libs/libOpenglRender/RenderControl.cpp
+++ b/emulator/opengl/host/libs/libOpenglRender/RenderControl.cpp
@@ -341,30 +341,30 @@ static int rcUpdateColorBuffer(uint32_t colorBuffer,
void initRenderControlContext(renderControl_decoder_context_t *dec)
{
- dec->set_rcGetRendererVersion(rcGetRendererVersion);
- dec->set_rcGetEGLVersion(rcGetEGLVersion);
- dec->set_rcQueryEGLString(rcQueryEGLString);
- dec->set_rcGetGLString(rcGetGLString);
- dec->set_rcGetNumConfigs(rcGetNumConfigs);
- dec->set_rcGetConfigs(rcGetConfigs);
- dec->set_rcChooseConfig(rcChooseConfig);
- dec->set_rcGetFBParam(rcGetFBParam);
- dec->set_rcCreateContext(rcCreateContext);
- dec->set_rcDestroyContext(rcDestroyContext);
- dec->set_rcCreateWindowSurface(rcCreateWindowSurface);
- dec->set_rcDestroyWindowSurface(rcDestroyWindowSurface);
- dec->set_rcCreateColorBuffer(rcCreateColorBuffer);
- dec->set_rcOpenColorBuffer(rcOpenColorBuffer);
- dec->set_rcCloseColorBuffer(rcCloseColorBuffer);
- dec->set_rcSetWindowColorBuffer(rcSetWindowColorBuffer);
- dec->set_rcFlushWindowColorBuffer(rcFlushWindowColorBuffer);
- dec->set_rcMakeCurrent(rcMakeCurrent);
- dec->set_rcFBPost(rcFBPost);
- dec->set_rcFBSetSwapInterval(rcFBSetSwapInterval);
- dec->set_rcBindTexture(rcBindTexture);
- dec->set_rcBindRenderbuffer(rcBindRenderbuffer);
- dec->set_rcColorBufferCacheFlush(rcColorBufferCacheFlush);
- dec->set_rcReadColorBuffer(rcReadColorBuffer);
- dec->set_rcUpdateColorBuffer(rcUpdateColorBuffer);
- dec->set_rcOpenColorBuffer2(rcOpenColorBuffer2);
+ dec->rcGetRendererVersion = rcGetRendererVersion;
+ dec->rcGetEGLVersion = rcGetEGLVersion;
+ dec->rcQueryEGLString = rcQueryEGLString;
+ dec->rcGetGLString = rcGetGLString;
+ dec->rcGetNumConfigs = rcGetNumConfigs;
+ dec->rcGetConfigs = rcGetConfigs;
+ dec->rcChooseConfig = rcChooseConfig;
+ dec->rcGetFBParam = rcGetFBParam;
+ dec->rcCreateContext = rcCreateContext;
+ dec->rcDestroyContext = rcDestroyContext;
+ dec->rcCreateWindowSurface = rcCreateWindowSurface;
+ dec->rcDestroyWindowSurface = rcDestroyWindowSurface;
+ dec->rcCreateColorBuffer = rcCreateColorBuffer;
+ dec->rcOpenColorBuffer = rcOpenColorBuffer;
+ dec->rcCloseColorBuffer = rcCloseColorBuffer;
+ dec->rcSetWindowColorBuffer = rcSetWindowColorBuffer;
+ dec->rcFlushWindowColorBuffer = rcFlushWindowColorBuffer;
+ dec->rcMakeCurrent = rcMakeCurrent;
+ dec->rcFBPost = rcFBPost;
+ dec->rcFBSetSwapInterval = rcFBSetSwapInterval;
+ dec->rcBindTexture = rcBindTexture;
+ dec->rcBindRenderbuffer = rcBindRenderbuffer;
+ dec->rcColorBufferCacheFlush = rcColorBufferCacheFlush;
+ dec->rcReadColorBuffer = rcReadColorBuffer;
+ dec->rcUpdateColorBuffer = rcUpdateColorBuffer;
+ dec->rcOpenColorBuffer2 = rcOpenColorBuffer2;
}
diff --git a/emulator/opengl/host/libs/renderControl_dec/renderControl.types b/emulator/opengl/host/libs/renderControl_dec/renderControl.types
index a7d96abf8..2b3847078 100644
--- a/emulator/opengl/host/libs/renderControl_dec/renderControl.types
+++ b/emulator/opengl/host/libs/renderControl_dec/renderControl.types
@@ -1,11 +1,11 @@
-uint32_t 32 0x%08x false
-EGLint 32 0x%08x false
-GLint 32 0x%08x false
-GLuint 32 0x%08x false
-GLenum 32 0x%08x false
-EGLenum 32 0x%08x false
-uint32_t* 32 0x%08x true
-EGLint* 32 0x%08x true
-GLint* 32 0x%08x true
-GLuint* 32 0x%08x true
-void* 32 0x%08x true
+uint32_t 32 0x%08x
+EGLint 32 0x%08x
+GLint 32 0x%08x
+GLuint 32 0x%08x
+GLenum 32 0x%08x
+EGLenum 32 0x%08x
+uint32_t* 32 0x%08x
+EGLint* 32 0x%08x
+GLint* 32 0x%08x
+GLuint* 32 0x%08x
+void* 32 0x%08x
diff --git a/emulator/opengl/host/tools/emugen/ApiGen.cpp b/emulator/opengl/host/tools/emugen/ApiGen.cpp
index 2e4c8d115..71cd843cd 100644
--- a/emulator/opengl/host/tools/emugen/ApiGen.cpp
+++ b/emulator/opengl/host/tools/emugen/ApiGen.cpp
@@ -30,6 +30,10 @@
*/
#define WITH_LARGE_SUPPORT 1
+// Set to 1 to ensure buffers passed to/from EGL/GL are properly aligned.
+// This prevents crashes with certain backends (e.g. OSMesa).
+#define USE_ALIGNED_BUFFERS 1
+
EntryPoint * ApiGen::findEntryByName(const std::string & name)
{
EntryPoint * entry = NULL;
@@ -152,15 +156,6 @@ int ApiGen::genContext(const std::string & filename, SideType side)
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));
@@ -658,19 +653,17 @@ int ApiGen::genEncoderImpl(const std::string &filename)
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));
+ fprintf(fp,
+ "\t%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());
+ fprintf(fp,
+ "\t%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");
@@ -728,15 +721,13 @@ int ApiGen::genContextImpl(const std::string &filename, SideType side)
// 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(),
+ fprintf(fp, "\t%s = (%s_%s_proc_t) getProc(\"%s\", userData);\n",
e->name().c_str(),
e->name().c_str(),
- sideString(side));
-
+ sideString(side),
+ e->name().c_str());
}
fprintf(fp, "\treturn 0;\n");
fprintf(fp, "}\n\n");
@@ -761,9 +752,28 @@ int ApiGen::genDecoderImpl(const std::string &filename)
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 \"ProtocolUtils.h\"\n\n");
fprintf(fp, "#include <stdio.h>\n\n");
fprintf(fp, "typedef unsigned int tsize_t; // Target \"size_t\", which is 32-bit for now. It may or may not be the same as host's size_t when emugen is compiled.\n\n");
+ // helper macros
+ fprintf(fp,
+ "#ifdef DEBUG_PRINTOUT\n"
+ "# define DEBUG(...) fprintf(stderr, __VA_ARGS__)\n"
+ "#else\n"
+ "# define DEBUG(...) ((void)0)\n"
+ "#endif\n\n");
+
+ fprintf(fp,
+ "#ifdef CHECK_GLERROR\n"
+ "# define SET_LASTCALL(name) sprintf(lastCall, #name)\n"
+ "#else\n"
+ "# define SET_LASTCALL(name) ((void)0)\n"
+ "#endif\n\n");
+
+ // helper templates
+ fprintf(fp, "using namespace emugl;\n\n");
+
// decoder switch;
fprintf(fp, "size_t %s::decode(void *buf, size_t len, IOStream *stream)\n{\n", classname.c_str());
fprintf(fp,
@@ -776,13 +786,22 @@ int ApiGen::genDecoderImpl(const std::string &filename)
\tchar lastCall[256] = {0}; \n\
#endif \n\
\twhile ((len - pos >= 8) && !unknownOpcode) { \n\
-\t\tint opcode = *(int *)ptr; \n\
-\t\tunsigned int packetLen = *(int *)(ptr + 4);\n\
+\t\tuint32_t opcode = *(uint32_t *)ptr; \n\
+\t\tsize_t packetLen = *(uint32_t *)(ptr + 4);\n\
\t\tif (len - pos < packetLen) return pos; \n\
\t\tswitch(opcode) {\n");
for (size_t f = 0; f < n; f++) {
- enum Pass_t { PASS_TmpBuffAlloc = 0, PASS_MemAlloc, PASS_DebugPrint, PASS_FunctionCall, PASS_Epilog, PASS_LAST };
+ enum Pass_t {
+ PASS_FIRST = 0,
+ PASS_VariableDeclarations = PASS_FIRST,
+ PASS_TmpBuffAlloc,
+ PASS_MemAlloc,
+ PASS_DebugPrint,
+ PASS_FunctionCall,
+ PASS_FlushOutput,
+ PASS_Epilog,
+ PASS_LAST };
EntryPoint *e = &at(f);
// construct a printout string;
@@ -794,8 +813,7 @@ int ApiGen::genDecoderImpl(const std::string &filename)
printString += "";
// TODO - add for return value;
- fprintf(fp, "\t\t\tcase OP_%s:\n", e->name().c_str());
- fprintf(fp, "\t\t\t{\n");
+ fprintf(fp, "\t\tcase OP_%s: {\n", e->name().c_str());
bool totalTmpBuffExist = false;
std::string totalTmpBuffOffset = "0";
@@ -807,8 +825,10 @@ int ApiGen::genDecoderImpl(const std::string &filename)
retvalType = e->retval().type()->name();
}
- for (int pass = PASS_TmpBuffAlloc; pass < PASS_LAST; pass++) {
- if (pass == PASS_FunctionCall && !e->retval().isVoid() && !e->retval().isPointer()) {
+ for (int pass = PASS_FIRST; 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());
}
@@ -820,10 +840,14 @@ int ApiGen::genDecoderImpl(const std::string &filename)
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(%%p): %s(%s)\\n\", stream",
- m_basename.c_str(), e->name().c_str(), printString.c_str());
- if (e->vars().size() > 0 && !e->vars()[0].isVoid()) fprintf(fp, ",");
+ fprintf(fp,
+ "\t\t\tDEBUG(\"%s(%%p): %s(%s)\\n\", stream",
+ m_basename.c_str(),
+ e->name().c_str(),
+ printString.c_str());
+ if (e->vars().size() > 0 && !e->vars()[0].isVoid()) {
+ fprintf(fp, ",");
+ }
}
std::string varoffset = "8"; // skip the header
@@ -831,89 +855,208 @@ int ApiGen::genDecoderImpl(const std::string &filename)
// 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->isVoid()) {
+ continue;
+ }
+ const char* var_name = v->name().c_str();
+ const char* var_type_name = v->type()->name().c_str();
+ const unsigned var_type_bytes = v->type()->bytes();
+
+ if ((pass == PASS_FunctionCall) &&
+ (j != 0 || e->customDecoder())) {
+ fprintf(fp, ", ");
+ }
+ if (pass == PASS_DebugPrint && j != 0) {
+ fprintf(fp, ", ");
+ }
+
+ if (!v->isPointer()) {
+ if (pass == PASS_VariableDeclarations) {
+ fprintf(fp,
+ "\t\t\t%s var_%s = Unpack<%s,uint%u_t>(ptr + %s);\n",
+ var_type_name,
+ var_name,
+ var_type_name,
+ var_type_bytes * 8U,
+ varoffset.c_str());
+ }
- if (!v->isPointer()) {
- if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) {
- fprintf(fp, "*(%s *)(ptr + %s)", v->type()->name().c_str(), varoffset.c_str());
+ if (pass == PASS_FunctionCall ||
+ pass == PASS_DebugPrint) {
+ fprintf(fp, "var_%s", var_name);
+ }
+ varoffset += " + " + toString(var_type_bytes);
+ continue;
+ }
+
+ if (pass == PASS_VariableDeclarations) {
+ fprintf(fp,
+ "\t\t\tuint32_t size_%s __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + %s);\n",
+ var_name,
+ varoffset.c_str());
+ }
+
+ if (v->pointerDir() == Var::POINTER_IN ||
+ v->pointerDir() == Var::POINTER_INOUT) {
+ if (pass == PASS_VariableDeclarations) {
+#if USE_ALIGNED_BUFFERS
+ fprintf(fp,
+ "\t\t\tInputBuffer inptr_%s(ptr + %s + 4, size_%s);\n",
+ var_name,
+ varoffset.c_str(),
+ var_name);
+ }
+ if (pass == PASS_FunctionCall) {
+ if (v->nullAllowed()) {
+ fprintf(fp,
+ "size_%s == 0 ? NULL : (%s)(inptr_%s.get())",
+ var_name,
+ var_type_name,
+ var_name);
+ } else {
+ fprintf(fp,
+ "(%s)(inptr_%s.get())",
+ var_type_name,
+ var_name);
}
- 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",
- (unsigned) j, varoffset.c_str());
- fprintf(fp, "unsigned char *tmpPtr%u = (ptr + %s + 4);\n",
- (unsigned) j, varoffset.c_str());
- }
- if (pass == PASS_FunctionCall) {
- if (v->nullAllowed()) {
- fprintf(fp, "*((unsigned int *)(ptr + %s)) == 0 ? NULL : (%s)(ptr + %s + 4)",
- varoffset.c_str(), v->type()->name().c_str(), varoffset.c_str());
- } else {
- fprintf(fp, "(%s)(ptr + %s + 4)",
- v->type()->name().c_str(), varoffset.c_str());
- }
- } else if (pass == PASS_DebugPrint) {
- fprintf(fp, "(%s)(ptr + %s + 4), *(unsigned int *)(ptr + %s)",
- v->type()->name().c_str(), varoffset.c_str(),
- varoffset.c_str());
- }
- varoffset += " + 4 + *(tsize_t *)(ptr +" + varoffset + ")";
- } else { // out pointer;
- if (pass == PASS_TmpBuffAlloc) {
- fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n",
- (unsigned) j, varoffset.c_str());
- if (!totalTmpBuffExist) {
- fprintf(fp, "\t\t\tsize_t totalTmpSize = tmpPtr%uSize;\n", (unsigned)j);
- } else {
- fprintf(fp, "\t\t\ttotalTmpSize += tmpPtr%uSize;\n", (unsigned)j);
- }
- tmpBufOffset[j] = totalTmpBuffOffset;
- char tmpPtrName[16];
- sprintf(tmpPtrName," + tmpPtr%uSize", (unsigned)j);
- totalTmpBuffOffset += std::string(tmpPtrName);
- totalTmpBuffExist = true;
- } else if (pass == PASS_MemAlloc) {
- fprintf(fp, "\t\t\tunsigned char *tmpPtr%u = &tmpBuf[%s];\n",
- (unsigned)j, tmpBufOffset[j].c_str());
- fprintf(fp, "\t\t\tmemset(tmpPtr%u, 0, %s);\n",
- (unsigned)j,
- toString(v->type()->bytes()).c_str());
- } else if (pass == PASS_FunctionCall) {
- if (v->nullAllowed()) {
- fprintf(fp, "tmpPtr%uSize == 0 ? NULL : (%s)(tmpPtr%u)",
- (unsigned) j, v->type()->name().c_str(), (unsigned) j);
- } else {
- fprintf(fp, "(%s)(tmpPtr%u)", v->type()->name().c_str(), (unsigned) j);
- }
- } else if (pass == PASS_DebugPrint) {
- fprintf(fp, "(%s)(tmpPtr%u), *(unsigned int *)(ptr + %s)",
- v->type()->name().c_str(), (unsigned) j,
- varoffset.c_str());
- }
- varoffset += " + 4";
+ } else if (pass == PASS_DebugPrint) {
+ fprintf(fp,
+ "(%s)(inptr_%s.get()), size_%s",
+ var_type_name,
+ var_name,
+ var_name);
+ }
+#else // !USE_ALIGNED_BUFFERS
+ fprintf(fp,
+ "unsigned char *inptr_%s = (ptr + %s + 4);\n",
+ var_name,
+ varoffset.c_str());
+ }
+ if (pass == PASS_FunctionCall) {
+ if (v->nullAllowed()) {
+ fprintf(fp,
+ "size_%s == 0 ? NULL : (%s)(inptr_%s)",
+ var_name,
+ var_type_name,
+ var_name);
+ } else {
+ fprintf(fp,
+ "(%s)(inptr_%s)",
+ var_type_name,
+ var_name);
+ }
+ } else if (pass == PASS_DebugPrint) {
+ fprintf(fp,
+ "(%s)(inptr_%s), size_%s",
+ var_type_name,
+ var_name,
+ var_name);
+ }
+#endif // !USE_ALIGNED_BUFFERS
+ varoffset += " + 4 + size_";
+ varoffset += var_name;
+ } else { // out pointer;
+ if (pass == PASS_TmpBuffAlloc) {
+ if (!totalTmpBuffExist) {
+ fprintf(fp,
+ "\t\t\tsize_t totalTmpSize = size_%s;\n",
+ var_name);
+ } else {
+ fprintf(fp,
+ "\t\t\ttotalTmpSize += size_%s;\n",
+ var_name);
+ }
+ tmpBufOffset[j] = totalTmpBuffOffset;
+ totalTmpBuffOffset += " + size_";
+ totalTmpBuffOffset += var_name;
+ totalTmpBuffExist = true;
+ } else if (pass == PASS_MemAlloc) {
+#if USE_ALIGNED_BUFFERS
+ fprintf(fp,
+ "\t\t\tOutputBuffer outptr_%s(&tmpBuf[%s], size_%s);\n",
+ var_name,
+ tmpBufOffset[j].c_str(),
+ var_name);
+ } else if (pass == PASS_FunctionCall) {
+ if (v->nullAllowed()) {
+ fprintf(fp,
+ "size_%s == 0 ? NULL : (%s)(outptr_%s.get())",
+ var_name,
+ var_type_name,
+ var_name);
+ } else {
+ fprintf(fp,
+ "(%s)(outptr_%s.get())",
+ var_type_name,
+ var_name);
+ }
+ } else if (pass == PASS_DebugPrint) {
+ fprintf(fp,
+ "(%s)(outptr_%s.get()), size_%s",
+ var_type_name,
+ var_name,
+ var_name);
+ }
+ if (pass == PASS_FlushOutput) {
+ fprintf(fp,
+ "\t\t\toutptr_%s.flush();\n",
+ var_name);
+ }
+#else // !USE_ALIGNED_BUFFERS
+ fprintf(fp,
+ "\t\t\tunsigned char *outptr_%s = &tmpBuf[%s];\n",
+ var_name,
+ tmpBufOffset[j].c_str());
+ fprintf(fp,
+ "\t\t\tmemset(outptr_%s, 0, %s);\n",
+ var_name,
+ toString(v->type()->bytes()).c_str());
+ } else if (pass == PASS_FunctionCall) {
+ if (v->nullAllowed()) {
+ fprintf(fp,
+ "size_%s == 0 ? NULL : (%s)(outptr_%s)",
+ var_name,
+ var_type_name,
+ var_name);
+ } else {
+ fprintf(fp,
+ "(%s)(outptr_%s)",
+ var_type_name,
+ var_name);
}
+ } else if (pass == PASS_DebugPrint) {
+ fprintf(fp,
+ "(%s)(outptr_%s), size_%s",
+ var_type_name,
+ var_name,
+ varoffset.c_str());
}
+#endif // !USE_ALIGNED_BUFFERS
+ varoffset += " + 4";
}
}
- if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) fprintf(fp, ");\n");
- if (pass == PASS_DebugPrint) fprintf(fp, "#endif\n");
+ if (pass == PASS_FunctionCall ||
+ pass == PASS_DebugPrint) {
+ fprintf(fp, ");\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());
+ 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());
+ 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");
+ fprintf(fp,
+ "\t\t\tunsigned char *tmpBuf = stream->alloc(totalTmpSize);\n");
}
}
@@ -922,17 +1065,12 @@ int ApiGen::genDecoderImpl(const std::string &filename)
if (totalTmpBuffExist) {
fprintf(fp, "\t\t\tstream->flush();\n");
}
-
- fprintf(fp, "\t\t\tpos += *(int *)(ptr + 4);\n");
- fprintf(fp, "\t\t\tptr += *(int *)(ptr + 4);\n");
}
} // pass;
- fprintf(fp, "\t\t\t}\n");
- fprintf(fp, "#ifdef CHECK_GL_ERROR\n");
- fprintf(fp, "\t\t\tsprintf(lastCall, \"%s\");\n", e->name().c_str());
- fprintf(fp, "#endif\n");
+ fprintf(fp, "\t\t\tSET_LASTCALL(\"%s\");\n", e->name().c_str());
fprintf(fp, "\t\t\tbreak;\n");
+ fprintf(fp, "\t\t}\n");
delete [] tmpBufOffset;
}
@@ -945,6 +1083,11 @@ int ApiGen::genDecoderImpl(const std::string &filename)
fprintf(fp, "\tif (err) fprintf(stderr, \"%s Error: 0x%%X in %%s\\n\", err, lastCall);\n", m_basename.c_str());
fprintf(fp, "#endif\n");
}
+
+ fprintf(fp, "\t\tif (!unknownOpcode) {\n");
+ fprintf(fp, "\t\t\tpos += packetLen;\n");
+ fprintf(fp, "\t\t\tptr += packetLen;\n");
+ fprintf(fp, "\t\t}\n");
fprintf(fp, "\t} // while\n");
fprintf(fp, "\treturn pos;\n");
fprintf(fp, "}\n");
diff --git a/emulator/opengl/host/tools/emugen/TypeFactory.cpp b/emulator/opengl/host/tools/emugen/TypeFactory.cpp
index 88842250a..7f495caac 100644
--- a/emulator/opengl/host/tools/emugen/TypeFactory.cpp
+++ b/emulator/opengl/host/tools/emugen/TypeFactory.cpp
@@ -24,32 +24,14 @@
TypeFactory * TypeFactory::m_instance = NULL;
-static Var0 g_var0;
-static Var8 g_var8;
-static Var16 g_var16;
-static Var32 g_var32;
-
typedef std::map<std::string, VarType> TypeMap;
static TypeMap g_varMap;
static bool g_initialized = false;
static int g_typeId = 0;
-static VarConverter * getVarConverter(int size)
-{
- VarConverter *v = NULL;
-
- switch(size) {
- case 0: v = &g_var0; break;
- case 8: v = &g_var8; break;
- case 16: v = &g_var16; break;
- case 32: v = &g_var32; break;
- }
- return v;
-}
-
#define ADD_TYPE(name, size, printformat,ispointer) \
- g_varMap.insert(std::pair<std::string, VarType>(name, VarType(g_typeId++, name, &g_var##size , printformat , ispointer)));
+ g_varMap.insert(std::pair<std::string, VarType>(name, VarType(g_typeId++, name, (size + 7) >> 3, printformat , ispointer)));
void TypeFactory::initBaseTypes()
{
@@ -103,39 +85,53 @@ int TypeFactory::initFromFile(const std::string &filename)
return -2;
}
+ // The ispointer definition is optional since we can just
+ // look at the type name, and determine it is a pointer if
+ // it ends with '*'.
+ bool isPointer = (name[name.size() - 1U] == '*');
+
pos = last + 1;
std::string pointerDef;
pointerDef = getNextToken(str, pos, &last, WHITESPACE);
- if (pointerDef.size() == 0) {
- fprintf(stderr, "Error: %d : missing ispointer definition\n", lc);
- return -2;
+ if (pointerDef.size() != 0) {
+ // Just a little sanity check.
+ if (std::string("true")==pointerDef) {
+ if (!isPointer) {
+ fprintf(stderr, "Error: %d: invalid isPointer definition: 'true' but name does not end with '*'!\n", lc);
+ return -2;
+ }
+ } else if (std::string("false")==pointerDef) {
+ if (isPointer) {
+ fprintf(stderr, "Error: %d: invalid isPointer definition: 'false' but name does end with '*'!\n", lc);
+ return -2;
+ }
+ } else {
+ fprintf(stderr, "Error: %d : invalid isPointer definition, must be either \"true\" or \"false\"\n", lc);
+ return -2;
+ }
}
- bool isPointer=false;
- if (std::string("true")==pointerDef)
- isPointer = true;
- else if (std::string("false")==pointerDef)
- isPointer = false;
- else
- {
- fprintf(stderr, "Error: %d : invalid isPointer definition, must be either \"true\" or \"false\"\n", lc);
- return -2;
- }
-
- VarConverter *v = getVarConverter(atoi(size.c_str()));
- if (v == NULL) {
- fprintf(stderr, "Error: %d : unknown var width: %d\n", lc, atoi(size.c_str()));
- return -1;
- }
+ size_t bitSize = atoi(size.c_str());
+ size_t byteSize = (bitSize + 7) >> 3;
if (getVarTypeByName(name)->id() != 0) {
fprintf(stderr,
"Warining: %d : type %s is already known, definition in line %d is taken\n",
lc, name.c_str(), lc);
}
- g_varMap.insert(std::pair<std::string, VarType>(name, VarType(g_typeId++, name, v ,printString,isPointer)));
+ g_varMap.insert(std::pair<std::string, VarType>(
+ name, VarType(g_typeId++,
+ name,
+ byteSize,
+ printString,
+ isPointer)));
std::string constName = "const " + name;
- g_varMap.insert(std::pair<std::string, VarType>(constName, VarType(g_typeId++, constName, v ,printString,isPointer))); //add a const type
+ g_varMap.insert(std::pair<std::string, VarType>(
+ constName, VarType(g_typeId++,
+ constName,
+ byteSize,
+ printString,
+ isPointer))); //add a const type
}
g_initialized = true;
return 0;
diff --git a/emulator/opengl/host/tools/emugen/VarType.h b/emulator/opengl/host/tools/emugen/VarType.h
index 41bb64501..b6937a002 100644
--- a/emulator/opengl/host/tools/emugen/VarType.h
+++ b/emulator/opengl/host/tools/emugen/VarType.h
@@ -18,60 +18,44 @@
#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) {}
-};
-
-
+// VarType models the types of values used on the wire protocol by
+// both encoders and decoders. Each type is identified by a unique id,
+// and a name, and provides a size in bytes for the values, a printf-like
+// formatter string, and a flag telling if the value corresponds to a
+// pointer.
class VarType {
public:
VarType() :
- m_id(0), m_name("default_constructed"), m_converter(NULL), m_printFomrat("0x%x"), m_isPointer(false)
- {
- }
-
- VarType(size_t id, const std::string & name, const VarConverter * converter, const std::string & printFormat , const bool isPointer) :
- m_id(id), m_name(name), m_converter(const_cast<VarConverter *>(converter)), m_printFomrat(printFormat), m_isPointer(isPointer)
- {
- }
+ m_id(0),
+ m_name("default_constructed"),
+ m_byteSize(0),
+ m_printFormat("0x%x"),
+ m_isPointer(false) {}
+
+ VarType(size_t id,
+ const std::string& name,
+ size_t byteSize,
+ const std::string& printFormat,
+ bool isPointer) :
+ m_id(id),
+ m_name(name),
+ m_byteSize(byteSize),
+ m_printFormat(printFormat),
+ m_isPointer(isPointer) {}
+
+ ~VarType() {}
- ~VarType()
- {
- }
- const std::string & name() const { return m_name; }
- const std::string & printFormat() const { return m_printFomrat; }
- size_t bytes() const { return m_converter->bytes(); }
- bool isPointer() const { return m_isPointer; }
size_t id() const { return m_id; }
+ const std::string& name() const { return m_name; }
+ size_t bytes() const { return m_byteSize; }
+ const std::string& printFormat() const { return m_printFormat; }
+ bool isPointer() const { return m_isPointer; }
+
private:
size_t m_id;
std::string m_name;
- VarConverter * m_converter;
- std::string m_printFomrat;
+ size_t m_byteSize;
+ std::string m_printFormat;
bool m_isPointer;
};
diff --git a/emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h b/emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h
new file mode 100644
index 000000000..472d7eadf
--- /dev/null
+++ b/emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h
@@ -0,0 +1,187 @@
+#ifndef EMUGL_PROTOCOL_UTILS_H
+#define EMUGL_PROTOCOL_UTILS_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace emugl {
+
+// Helper macro
+#define COMPILE_ASSERT(cond) static char kAssert##__LINE__[1 - 2 * !(cond)] __attribute__((unused)) = { 0 }
+
+// Helper template: is_pointer.
+// is_pointer<T>::value is true iff |T| is a pointer type.
+template <typename T> struct is_pointer {
+ static const bool value = false;
+};
+
+template <typename T> struct is_pointer<T*> {
+ static const bool value = true;
+};
+
+// A helper template to extract values form the wire protocol stream
+// and convert them to appropriate host values.
+//
+// The wire protocol uses 32-bit exclusively when transferring
+// GLintptr or GLsizei values, as well as opaque handles like GLeglImage,
+// from the guest (even when the guest is 64-bit).
+//
+// The corresponding host definitions depend on the host bitness. For
+// example, GLintptr is 64-bit on linux-x86_64. The following is a set
+// of templates that can simplify the conversion of protocol values
+// into host ones.
+//
+// The most important one is:
+//
+// unpack<HOST_TYPE,SIZE_TYPE>(const void* ptr)
+//
+// Which reads bytes from |ptr|, using |SIZE_TYPE| as the underlying
+// sized-integer specifier (e.g. 'uint32_t'), and converting the result
+// into a |HOST_TYPE| value. For example:
+//
+// unpack<EGLImage,uint32_t>(ptr + 12);
+//
+// will read a 4-byte value from |ptr + 12| and convert it into
+// an EGLImage, which is a host void*. The template detects host
+// pointer types to perform proper type casting.
+//
+// TODO(digit): Add custom unpackers to handle generic opaque void* values.
+// and map them to unique 32-bit values.
+
+template <typename T, typename S, bool IS_POINTER>
+struct UnpackerT {};
+
+template <typename T, typename S>
+struct UnpackerT<T,S,false> {
+ static inline T unpack(const void* ptr) {
+ COMPILE_ASSERT(sizeof(T) == sizeof(S));
+ return (T)(*(S*)(ptr));
+ }
+};
+
+template <typename T, typename S>
+struct UnpackerT<T,S,true> {
+ static inline T unpack(const void* ptr) {
+ return (T)(uintptr_t)(*(S*)(ptr));
+ }
+};
+
+template <>
+struct UnpackerT<float,uint32_t,false> {
+ static inline float unpack(const void* ptr) {
+ union {
+ float f;
+ uint32_t u;
+ } v;
+ v.u = *(uint32_t*)(ptr);
+ return v.f;
+ }
+};
+
+template <>
+struct UnpackerT<double,uint64_t,false> {
+ static inline double unpack(const void* ptr) {
+ union {
+ double d;
+ uint32_t u;
+ } v;
+ v.u = *(uint64_t*)(ptr);
+ return v.d;
+ }
+};
+
+template <>
+struct UnpackerT<ssize_t,uint32_t,false> {
+ static inline ssize_t unpack(const void* ptr) {
+ return (ssize_t)*(int32_t*)(ptr);
+ }
+};
+
+template <typename T, typename S>
+inline T Unpack(const void* ptr) {
+ return UnpackerT<T, S, is_pointer<T>::value>::unpack(ptr);
+}
+
+// Helper class used to ensure input buffers passed to EGL/GL functions
+// are properly aligned (preventing crashes with some backends).
+// Usage example:
+//
+// InputBuffer inputBuffer(ptr, size);
+// glDoStuff(inputBuffer.get());
+//
+// inputBuffer.get() will return the original value of |ptr| if it was
+// aligned on an 8-byte boundary. Otherwise, it will return the address
+// of an aligned heap-allocated copy of the original |size| bytes starting
+// from |ptr|. The heap block is released at scope exit.
+class InputBuffer {
+public:
+ InputBuffer(const void* input, size_t size, size_t align = 8) :
+ mBuff(input), mIsCopy(false) {
+ if (((uintptr_t)input & (align - 1U)) != 0) {
+ void* newBuff = malloc(size);
+ memcpy(newBuff, input, size);
+ mBuff = newBuff;
+ mIsCopy = true;
+ }
+ }
+
+ ~InputBuffer() {
+ if (mIsCopy) {
+ free((void*)mBuff);
+ }
+ }
+
+ const void* get() const {
+ return mBuff;
+ }
+
+private:
+ const void* mBuff;
+ bool mIsCopy;
+};
+
+// Helper class used to ensure that output buffers passed to EGL/GL functions
+// are aligned on 8-byte addresses.
+// Usage example:
+//
+// ptr = stream->alloc(size);
+// OutputBuffer outputBuffer(ptr, size);
+// glGetStuff(outputBuffer.get());
+// outputBuffer.flush();
+//
+// outputBuffer.get() returns the original value of |ptr| if it was already
+// aligned on an 8=byte boundary. Otherwise, it returns the size of an heap
+// allocated zeroed buffer of |size| bytes.
+//
+// outputBuffer.flush() copies the content of the heap allocated buffer back
+// to |ptr| explictly, if needed. If a no-op if |ptr| was aligned.
+class OutputBuffer {
+public:
+ OutputBuffer(unsigned char* ptr, size_t size, size_t align = 8) :
+ mOrgBuff(ptr), mBuff(ptr), mSize(size) {
+ if (((uintptr_t)ptr & (align - 1U)) != 0) {
+ void* newBuff = calloc(1, size);
+ mBuff = newBuff;
+ }
+ }
+
+ void* get() const {
+ return mBuff;
+ }
+
+ void flush() {
+ if (mBuff != mOrgBuff) {
+ memcpy(mOrgBuff, mBuff, mSize);
+ }
+ }
+private:
+ unsigned char* mOrgBuff;
+ void* mBuff;
+ size_t mSize;
+};
+
+} // namespace emugl
+
+#endif // EMUGL_PROTOCOL_UTILS_H
diff --git a/emulator/opengl/shared/emugl/common/Android.mk b/emulator/opengl/shared/emugl/common/Android.mk
index 6aaa0d95e..f481c0c89 100644
--- a/emulator/opengl/shared/emugl/common/Android.mk
+++ b/emulator/opengl/shared/emugl/common/Android.mk
@@ -49,6 +49,7 @@ host_commonSources := \
smart_ptr_unittest.cpp \
thread_store_unittest.cpp \
thread_unittest.cpp \
+ unique_integer_map_unittest.cpp \
$(call emugl-begin-host-executable,emugl_common_host_unittests)
LOCAL_SRC_FILES := $(host_commonSources)
diff --git a/emulator/opengl/shared/emugl/common/unique_integer_map.h b/emulator/opengl/shared/emugl/common/unique_integer_map.h
new file mode 100644
index 000000000..720aceb0c
--- /dev/null
+++ b/emulator/opengl/shared/emugl/common/unique_integer_map.h
@@ -0,0 +1,225 @@
+// Copyright (C) 2014 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 EMUGL_COMMON_UNIQUE_INTEGER_MAP_H
+#define EMUGL_COMMON_UNIQUE_INTEGER_MAP_H
+
+#include "emugl/common/pod_vector.h"
+
+#include <stdint.h>
+
+namespace emugl {
+
+// Helper template class that implements a bi-directional mapping between
+// two integer types |A| and |B|. More specifically:
+//
+// - The map allocates values of type |B| when a key of type |A| is entered
+// in the map.
+//
+// - keys and values cannot be 0, which is reserved (i.e. means 'invalid').
+//
+// This is used in EmuGL to map liberal 'void*' values (e.g. EGLimages ones)
+// to unique 32-bit IDs that can be written to / read from the wire protocol.
+template <typename A, typename B>
+class UniqueIntegerMap {
+public:
+ UniqueIntegerMap() : mForwardPairs(), mBackwardPairs() {}
+ ~UniqueIntegerMap() {}
+
+ // Return true iff the map is empty.
+ const bool empty() const { return mForwardPairs.empty(); }
+
+ // Return the number of (key,value) pairs in the map.
+ size_t size() const { return mForwardPairs.size(); }
+
+ // Find the value associated with |key| in the map.
+ // Returns 0 in case of failure, or if |key| is 0.
+ B find(const A key) const;
+
+ // Find the key associated with a given |value| in the map.
+ // Returns 0 if |value| is 0, or in case of failure.
+ A findKeyFor(const B value) const;
+
+ // Add |key| to the map and return an automatically-allocated
+ // unique value for it. Return 0 if |key| is 0.
+ B add(const A key);
+
+ // Delete the entry associated with a given |key|. The
+ // corresponding value may be recycled by future calls to add().
+ void del(const A key);
+
+private:
+ typedef struct {
+ A first;
+ B second;
+ } ForwardPair;
+
+ typedef struct {
+ B first;
+ A second;
+ } BackwardPair;
+
+ size_t findKeyIndexPlusOne(const A key) const;
+ size_t findValueIndexPlusOne(const B value) const;
+
+ B allocValue();
+ void freeValue(B value);
+
+ PodVector<ForwardPair> mForwardPairs;
+ PodVector<BackwardPair> mBackwardPairs;
+
+ B mLastValue;
+ PodVector<B> mFreeValues;
+};
+
+template <typename A, typename B>
+B UniqueIntegerMap<A,B>::find(const A key) const {
+ size_t keyIndex = findKeyIndexPlusOne(key);
+ if (!keyIndex) {
+ return 0;
+ }
+ return mForwardPairs[keyIndex - 1U].second;
+}
+
+template <typename A, typename B>
+A UniqueIntegerMap<A,B>::findKeyFor(const B value) const {
+ size_t valueIndex = findValueIndexPlusOne(value);
+ if (!valueIndex) {
+ return 0;
+ }
+ return mBackwardPairs[valueIndex - 1U].second;
+}
+
+template <typename A, typename B>
+B UniqueIntegerMap<A,B>::add(const A key) {
+ // Binary search to find the proper insertion point for the key.
+ // Also checks that the key isn't already in the set.
+ size_t min = 0;
+ size_t max = mForwardPairs.size();
+ while (min < max) {
+ size_t mid = min + ((max - min) >> 1);
+ A midKey = mForwardPairs[mid].first;
+ if (midKey < key) {
+ min = mid + 1U;
+ } else if (midKey > key) {
+ max = mid;
+ } else {
+ // Already in the set.
+ return 0;
+ }
+ }
+
+ // Generate new unique value
+ B value = allocValue();
+
+ ForwardPair* pair = mForwardPairs.emplace(min);
+ pair->first = key;
+ pair->second = value;
+
+ // Binary search to find proper insertion point for the value.
+ min = 0;
+ max = mBackwardPairs.size();
+ while (min < max) {
+ size_t mid = min + ((max - min) >> 1);
+ B midValue = mBackwardPairs[mid].first;
+ if (midValue < value) {
+ min = mid + 1U;
+ } else {
+ max = mid;
+ }
+ }
+
+ BackwardPair* backPair = mBackwardPairs.emplace(min);
+ backPair->first = value;
+ backPair->second = key;
+
+ return value;
+}
+
+template <typename A, typename B>
+void UniqueIntegerMap<A,B>::del(const A key) {
+ size_t keyIndex = findKeyIndexPlusOne(key);
+ if (!keyIndex) {
+ return;
+ }
+ B value = mForwardPairs[keyIndex - 1U].second;
+ size_t valueIndex = findValueIndexPlusOne(value);
+ mForwardPairs.remove(keyIndex - 1U);
+ mBackwardPairs.remove(valueIndex - 1U);
+ freeValue(value);
+}
+
+template <typename A, typename B>
+size_t UniqueIntegerMap<A,B>::findKeyIndexPlusOne(const A key) const {
+ // Binary search in forward pair array.
+ size_t min = 0;
+ size_t max = mForwardPairs.size();
+ while (min < max) {
+ size_t mid = min + ((max - min) >> 1);
+ A midKey = mForwardPairs[mid].first;
+ if (midKey < key) {
+ min = mid + 1U;
+ } else if (midKey > key) {
+ max = mid;
+ } else {
+ return mid + 1U;
+ }
+ }
+ return 0U;
+}
+
+template <typename A, typename B>
+size_t UniqueIntegerMap<A,B>::findValueIndexPlusOne(const B value) const {
+ // Binary search in revere pair array.
+ size_t min = 0;
+ size_t max = mBackwardPairs.size();
+ while (min < max) {
+ size_t mid = min + ((max - min) >> 1);
+ B midValue = mBackwardPairs[mid].first;
+ if (midValue < value) {
+ min = mid + 1U;
+ } else if (midValue > value) {
+ max = mid;
+ } else {
+ return mid + 1U;
+ }
+ }
+ return 0U;
+}
+
+template <typename A, typename B>
+B UniqueIntegerMap<A,B>::allocValue() {
+ if (!mFreeValues.empty()) {
+ B result = mFreeValues[0];
+ mFreeValues.pop();
+ return result;
+ }
+ return ++mLastValue;
+}
+
+template <typename A, typename B>
+void UniqueIntegerMap<A,B>::freeValue(B value) {
+ if (!value) {
+ return;
+ }
+ if (value == mLastValue) {
+ mLastValue--;
+ return;
+ }
+ mFreeValues.append(value);
+}
+
+} // namespace emugl
+
+#endif // EMUGL_COMMON_INTEGER_MAP_H
diff --git a/emulator/opengl/shared/emugl/common/unique_integer_map_unittest.cpp b/emulator/opengl/shared/emugl/common/unique_integer_map_unittest.cpp
new file mode 100644
index 000000000..8aee01327
--- /dev/null
+++ b/emulator/opengl/shared/emugl/common/unique_integer_map_unittest.cpp
@@ -0,0 +1,103 @@
+// Copyright (C) 2014 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 "emugl/common/unique_integer_map.h"
+
+#include <gtest/gtest.h>
+
+#include <stdio.h>
+
+namespace emugl {
+
+typedef UniqueIntegerMap<uintptr_t,uint32_t> MyMap;
+
+TEST(UniqueIntegerMap, Empty) {
+ MyMap map;
+
+ EXPECT_TRUE(map.empty());
+ EXPECT_EQ(0U, map.size());
+ EXPECT_EQ(0U, map.find(0U));
+ EXPECT_EQ(0U, map.find(1U));
+ EXPECT_EQ(0U, map.find(2U));
+ EXPECT_EQ(0U, map.find(4U));
+}
+
+TEST(UniqueIntegerMap, AddOne) {
+ MyMap map;
+ uintptr_t key1 = 1U;
+ uint32_t val1 = map.add(key1);
+
+ EXPECT_NE(0U, val1);
+ EXPECT_EQ(val1, map.find(key1));
+ EXPECT_EQ(key1, map.findKeyFor(val1));
+
+ EXPECT_FALSE(map.empty());
+ EXPECT_EQ(1U, map.size());
+
+ EXPECT_EQ(0U, map.find(0));
+ EXPECT_EQ(0U, map.findKeyFor(0));
+
+ EXPECT_EQ(0U, map.find(key1 + 1));
+ EXPECT_EQ(0U, map.findKeyFor(val1 + 1));
+}
+
+TEST(UniqueIntegerMap, AddMultiple) {
+ MyMap map;
+ const size_t kCount = 100;
+ const size_t kKeyMultiplier = 3U; // must be >= 2.
+ uint32_t values[kCount];
+
+ for (size_t n = 0; n < kCount; ++n) {
+ uintptr_t key = 1U + n * kKeyMultiplier;
+ values[n] = map.add(key);
+ EXPECT_NE(0U, values[n]) << "key #" << n;
+ }
+
+ EXPECT_EQ(kCount, map.size());
+
+ for (size_t n = 0; n < kCount; ++n) {
+ uintptr_t key = 1U + n * kKeyMultiplier;
+ EXPECT_EQ(values[n], map.find(key)) << "key #" << n;
+ EXPECT_EQ(0U, map.find(key + 1U)) << "key #" << n;
+ }
+
+ for (size_t n = 0; n < kCount; ++n) {
+ uintptr_t key = 1U + n * kKeyMultiplier;
+ EXPECT_EQ(key, map.findKeyFor(values[n]));
+ }
+}
+
+TEST(UniqueIntegerMap, Del) {
+ MyMap map;
+ const size_t kCount = 100;
+ const size_t kKeyMultiplier = 3U; // must be >= 2.
+ uint32_t values[kCount];
+
+ for (size_t n = 0; n < kCount; ++n) {
+ uintptr_t key = 1U + n * kKeyMultiplier;
+ values[n] = map.add(key);
+ }
+
+ for (size_t n = 0; n < kCount; ++n) {
+ uintptr_t key = 1U + n * kKeyMultiplier;
+ map.del(key);
+ EXPECT_EQ(kCount - 1U - n, map.size());
+ EXPECT_EQ(0U, map.find(key));
+ EXPECT_EQ(0U, map.findKeyFor(values[n]));
+ }
+
+ EXPECT_TRUE(map.empty());
+}
+
+} // namespace emugl