From dfd49832d5d2058a69486af32373fc90ddc69a3d Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Wed, 24 Sep 2014 19:03:46 -0700 Subject: emulator/opengl/emugen: Ensure correct buffer alignment. The decoders generated by emugen pass addresses that come directly from the stream to EGL/GL functions. Sometimes, these addresses are not properly padded with regards to the type of data being transfered and this can crash some implementations (e.g. OSMesa being compiled with -msse by default, and doesn't build without it). This patch introduces two helper classes in ProtocolUtils.h, named InputBuffer and OutputBuffer, which are used to auto-align buffer pointers, then make the generated decoder code use them. Change-Id: I345c7eecc230f62310ced5378b6344f419647e06 --- .../shared/OpenglCodecCommon/ProtocolUtils.h | 80 ++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h') 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 #include +#include +#include namespace emugl { @@ -102,6 +104,84 @@ inline T Unpack(const void* ptr) { return UnpackerT::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 -- cgit v1.2.3