*//*--------------------------------------------------------------------*/
#include "tcuAndroidInternals.hpp"
+#include "deMemory.h"
+#include "deStringUtil.hpp"
namespace tcu
{
setFuncPtr(gb.getNativeBuffer, m_library, "_ZNK7android13GraphicBuffer15getNativeBufferEv");
setFuncPtr(gb.lock, m_library, "_ZN7android13GraphicBuffer4lockEjPPv");
setFuncPtr(gb.unlock, m_library, "_ZN7android13GraphicBuffer6unlockEv");
+ setFuncPtr(gb.initCheck, m_library, "_ZNK7android13GraphicBuffer9initCheckEv");
}
#define GRAPHICBUFFER_SIZE 1024 // Hopefully enough
+typedef void (*GenericFptr)();
+
+//! call constructor with 4 arguments
+template <typename RT, typename T1, typename T2, typename T3, typename T4>
+RT* callConstructor4 (GenericFptr fptr, void* memory, size_t memorySize, T1 param1, T2 param2, T3 param3, T4 param4)
+{
+ DE_UNREF(memorySize);
+
+#if (DE_CPU == DE_CPU_ARM)
+ // C1 constructors return pointer
+ typedef RT* (*ABIFptr)(void*, T1, T2, T3, T4);
+ (void)((ABIFptr)fptr)(memory, param1, param2, param3, param4);
+ return reinterpret_cast<RT*>(memory);
+#elif (DE_CPU == DE_CPU_ARM_64)
+ // C1 constructors return void
+ typedef void (*ABIFptr)(void*, T1, T2, T3, T4);
+ ((ABIFptr)fptr)(memory, param1, param2, param3, param4);
+ return reinterpret_cast<RT*>(memory);
+#elif (DE_CPU == DE_CPU_X86)
+ // ctor returns void
+ typedef void (*ABIFptr)(void*, T1, T2, T3, T4);
+ ((ABIFptr)fptr)(memory, param1, param2, param3, param4);
+ return reinterpret_cast<RT*>(memory);
+#elif (DE_CPU == DE_CPU_X86_64)
+ // ctor returns void
+ typedef void (*ABIFptr)(void*, T1, T2, T3, T4);
+ ((ABIFptr)fptr)(memory, param1, param2, param3, param4);
+ return reinterpret_cast<RT*>(memory);
+#else
+ TCU_THROW(NotSupportedError, "ABI not supported");
+ return DE_NULL;
+#endif
+}
+
+template <typename T>
+void callDestructor (GenericFptr fptr, T* obj)
+{
+#if (DE_CPU == DE_CPU_ARM)
+ // D1 destructor returns ptr
+ typedef void* (*ABIFptr)(T* obj);
+ (void)((ABIFptr)fptr)(obj);
+#elif (DE_CPU == DE_CPU_ARM_64)
+ // D1 destructor returns void
+ typedef void (*ABIFptr)(T* obj);
+ ((ABIFptr)fptr)(obj);
+#elif (DE_CPU == DE_CPU_X86)
+ // dtor returns void
+ typedef void (*ABIFptr)(T* obj);
+ ((ABIFptr)fptr)(obj);
+#elif (DE_CPU == DE_CPU_X86_64)
+ // dtor returns void
+ typedef void (*ABIFptr)(T* obj);
+ ((ABIFptr)fptr)(obj);
+#else
+ TCU_THROW(NotSupportedError, "ABI not supported");
+#endif
+}
+
+template<typename T1, typename T2>
+T1* pointerToOffset (T2* ptr, size_t bytes)
+{
+ return reinterpret_cast<T1*>((deUint8*)ptr + bytes);
+}
+
+static android::android_native_base_t* getAndroidNativeBase (android::GraphicBuffer* gb)
+{
+ // \note: assuming Itanium ABI
+ return pointerToOffset<android::android_native_base_t>(gb, 2 * DE_PTR_SIZE);
+}
+
+//! android_native_base_t::magic for ANativeWindowBuffer
+static deInt32 getExpectedNativeBufferVersion (void)
+{
+#if (DE_PTR_SIZE == 4)
+ return 96;
+#elif (DE_PTR_SIZE == 8)
+ return 168;
+#else
+# error Invalid DE_PTR_SIZE
+#endif
+}
+
+//! access android_native_base_t::magic
+static deUint32 getNativeBaseMagic (android::android_native_base_t* base)
+{
+ return *pointerToOffset<deUint32>(base, 0);
+}
+
+//! access android_native_base_t::version
+static deUint32 getNativeBaseVersion (android::android_native_base_t* base)
+{
+ return *pointerToOffset<deInt32>(base, 4);
+}
+
+//! access android_native_base_t::incRef
+static NativeBaseFunctions::incRefFunc getNativeBaseIncRefFunc (android::android_native_base_t* base)
+{
+ return *pointerToOffset<NativeBaseFunctions::incRefFunc>(base, 8 + DE_PTR_SIZE*4);
+}
+
+//! access android_native_base_t::decRef
+static NativeBaseFunctions::decRefFunc getNativeBaseDecRefFunc (android::android_native_base_t* base)
+{
+ return *pointerToOffset<NativeBaseFunctions::decRefFunc>(base, 8 + DE_PTR_SIZE*5);
+}
+
+static android::GraphicBuffer* createGraphicBuffer (const GraphicBufferFunctions& functions, NativeBaseFunctions& baseFunctions, deUint32 w, deUint32 h, PixelFormat format, deUint32 usage)
+{
+ // \note: Hopefully uses the same allocator as libui
+ void* const memory = deMalloc(GRAPHICBUFFER_SIZE);
+ if (memory == DE_NULL)
+ TCU_THROW(ResourceError, "Could not alloc for GraphicBuffer");
+ else
+ {
+ try
+ {
+ android::GraphicBuffer* const gb = callConstructor4<android::GraphicBuffer, deUint32, deUint32, PixelFormat, deUint32>(functions.constructor,
+ memory,
+ GRAPHICBUFFER_SIZE,
+ w,
+ h,
+ format,
+ usage);
+ android::android_native_base_t* const base = getAndroidNativeBase(gb);
+ status_t ctorStatus = functions.initCheck(gb);
+
+ if (ctorStatus)
+ {
+ // ctor failed
+ callDestructor<android::GraphicBuffer>(functions.destructor, gb);
+ TCU_THROW(NotSupportedError, ("GraphicBuffer ctor failed, initCheck returned " + de::toString(ctorStatus)).c_str());
+ }
+
+ // check object layout
+ {
+ const deUint32 magic = getNativeBaseMagic(base);
+ const deUint32 bufferMagic = 0x5f626672u; // "_bfr"
+
+ if (magic != bufferMagic)
+ TCU_THROW(NotSupportedError, "GraphicBuffer layout unexpected");
+ }
+
+ // check object version
+ {
+ const deInt32 version = getNativeBaseVersion(base);
+ const deInt32 expectedVersion = getExpectedNativeBufferVersion();
+
+ if (version != expectedVersion)
+ TCU_THROW(NotSupportedError, "GraphicBuffer version unexpected");
+ }
+
+ // locate refcounting functions
+
+ if (!baseFunctions.incRef || !baseFunctions.decRef)
+ {
+ baseFunctions.incRef = getNativeBaseIncRefFunc(base);
+ baseFunctions.decRef = getNativeBaseDecRefFunc(base);
+ }
+
+ // take the initial reference and return
+ baseFunctions.incRef(base);
+ return gb;
+ }
+ catch (...)
+ {
+ deFree(memory);
+ throw;
+ }
+ }
+}
+
GraphicBuffer::GraphicBuffer (const LibUI& lib, deUint32 width, deUint32 height, PixelFormat format, deUint32 usage)
: m_functions (lib.getFunctions().graphicBuffer)
- , m_memory (GRAPHICBUFFER_SIZE) // vector<char> (new char[]) is max-aligned
- , m_impl (m_functions.constructor(&m_memory.front(), width, height, format, usage))
+ , m_impl (DE_NULL)
{
+ m_baseFunctions.incRef = DE_NULL;
+ m_baseFunctions.decRef = DE_NULL;
+
+ // \note createGraphicBuffer updates m_baseFunctions
+ m_impl = createGraphicBuffer(m_functions, m_baseFunctions, width, height, format, usage);
}
GraphicBuffer::~GraphicBuffer (void)
{
- m_functions.destructor(m_impl);
+ if (m_impl && m_baseFunctions.decRef)
+ {
+ m_baseFunctions.decRef(getAndroidNativeBase(m_impl));
+ m_impl = DE_NULL;
+ }
}
status_t GraphicBuffer::lock (deUint32 usage, void** vaddr)