diff options
| -rw-r--r-- | emulator/opengl/host/tools/emugen/ApiGen.cpp | 73 | ||||
| -rw-r--r-- | emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h | 80 |
2 files changed, 149 insertions, 4 deletions
diff --git a/emulator/opengl/host/tools/emugen/ApiGen.cpp b/emulator/opengl/host/tools/emugen/ApiGen.cpp index 78c15e49e..bd8fabf28 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; @@ -786,7 +790,7 @@ int ApiGen::genDecoderImpl(const std::string &filename) \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_TmpBuffAlloc = 0, PASS_MemAlloc, PASS_DebugPrint, PASS_FunctionCall, PASS_FlushOutput, PASS_Epilog, PASS_LAST }; EntryPoint *e = &at(f); // construct a printout string; @@ -859,7 +863,7 @@ int ApiGen::genDecoderImpl(const std::string &filename) fprintf(fp, "Unpack<%s,uint%d_t>(ptr + %s)", v->type()->name().c_str(), - v->type()->bytes() * 8, + (unsigned) v->type()->bytes() * 8U, varoffset.c_str()); } varoffset += " + " + toString(v->type()->bytes()); @@ -868,12 +872,39 @@ int ApiGen::genDecoderImpl(const std::string &filename) if (v->pointerDir() == Var::POINTER_IN || v->pointerDir() == Var::POINTER_INOUT) { - if (pass == PASS_MemAlloc && - v->pointerDir() == Var::POINTER_INOUT) { + if (pass == PASS_MemAlloc) { fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(uint32_t *)(ptr + %s);\n", (unsigned) j, varoffset.c_str()); +#if USE_ALIGNED_BUFFERS + fprintf(fp, + "\t\t\tInputBuffer tmpPtr%u(ptr + %s + 4, tmpPtr%uSize);\n", + (unsigned) j, + varoffset.c_str(), + (unsigned) j); + } + if (pass == PASS_FunctionCall) { + if (v->nullAllowed()) { + fprintf(fp, + "tmpPtr%uSize == 0 ? NULL : (%s)(tmpPtr%u.get())", + (unsigned) j, + v->type()->name().c_str(), + (unsigned) j); + } else { + fprintf(fp, + "(%s)(tmpPtr%u.get())", + v->type()->name().c_str(), + (unsigned) j); + } + } else if (pass == PASS_DebugPrint) { + fprintf(fp, + "(%s)(tmpPtr%u.get()), (uint32_t)tmpPtr%uSize", + v->type()->name().c_str(), + (unsigned) j, + (unsigned) j); + } +#else // !USE_ALIGNED_BUFFERS fprintf(fp, "unsigned char *tmpPtr%u = (ptr + %s + 4);\n", (unsigned) j, @@ -899,6 +930,7 @@ int ApiGen::genDecoderImpl(const std::string &filename) varoffset.c_str(), varoffset.c_str()); } +#endif // !USE_ALIGNED_BUFFERS varoffset += " + 4 + *(tsize_t *)(ptr +" + varoffset + ")"; } else { // out pointer; @@ -922,6 +954,38 @@ int ApiGen::genDecoderImpl(const std::string &filename) totalTmpBuffOffset += std::string(tmpPtrName); totalTmpBuffExist = true; } else if (pass == PASS_MemAlloc) { +#if USE_ALIGNED_BUFFERS + fprintf(fp, + "\t\t\tOutputBuffer tmpPtr%u(&tmpBuf[%s], tmpPtr%uSize);\n", + (unsigned) j, + tmpBufOffset[j].c_str(), + (unsigned) j); + } else if (pass == PASS_FunctionCall) { + if (v->nullAllowed()) { + fprintf(fp, + "tmpPtr%uSize == 0 ? NULL : (%s)(tmpPtr%u.get())", + (unsigned) j, + v->type()->name().c_str(), + (unsigned) j); + } else { + fprintf(fp, + "(%s)(tmpPtr%u.get())", + v->type()->name().c_str(), + (unsigned) j); + } + } else if (pass == PASS_DebugPrint) { + fprintf(fp, + "(%s)(tmpPtr%u.get()), (uint32_t)tmpPtr%uSize", + v->type()->name().c_str(), + (unsigned) j, + (unsigned) j); + } + if (pass == PASS_FlushOutput) { + fprintf(fp, + "\t\t\ttmpPtr%u.flush();\n", + (unsigned) j); + } +#else // !USE_ALIGNED_BUFFERS fprintf(fp, "\t\t\tunsigned char *tmpPtr%u = &tmpBuf[%s];\n", (unsigned)j, @@ -950,6 +1014,7 @@ int ApiGen::genDecoderImpl(const std::string &filename) (unsigned) j, varoffset.c_str()); } +#endif // !USE_ALIGNED_BUFFERS varoffset += " + 4"; } } diff --git a/emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h b/emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h index 1198bd19b..472d7eadf 100644 --- a/emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h +++ b/emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h @@ -3,6 +3,8 @@ #include <stddef.h> #include <stdint.h> +#include <stdlib.h> +#include <string.h> namespace emugl { @@ -102,6 +104,84 @@ 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 |
