diff options
Diffstat (limited to 'emulator')
| -rw-r--r-- | emulator/opengl/host/libs/GLESv1_dec/GLDecoder.cpp | 40 | ||||
| -rw-r--r-- | emulator/opengl/host/libs/GLESv1_dec/gl.types | 66 | ||||
| -rw-r--r-- | emulator/opengl/host/libs/GLESv2_dec/GL2Decoder.cpp | 16 | ||||
| -rw-r--r-- | emulator/opengl/host/libs/GLESv2_dec/gl2.types | 73 | ||||
| -rw-r--r-- | emulator/opengl/host/libs/libOpenglRender/RenderControl.cpp | 52 | ||||
| -rw-r--r-- | emulator/opengl/host/libs/renderControl_dec/renderControl.types | 22 | ||||
| -rw-r--r-- | emulator/opengl/host/tools/emugen/ApiGen.cpp | 363 | ||||
| -rw-r--r-- | emulator/opengl/host/tools/emugen/TypeFactory.cpp | 76 | ||||
| -rw-r--r-- | emulator/opengl/host/tools/emugen/VarType.h | 76 | ||||
| -rw-r--r-- | emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h | 187 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/Android.mk | 1 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/unique_integer_map.h | 225 | ||||
| -rw-r--r-- | emulator/opengl/shared/emugl/common/unique_integer_map_unittest.cpp | 103 |
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 |
