/*------------------------------------------------------------------------- * drawElements Quality Program Tester Core * ---------------------------------------- * * Copyright 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. * *//*! * \file * \brief Access to Android internals that are not a part of the NDK. *//*--------------------------------------------------------------------*/ #include "tcuAndroidInternals.hpp" #include "deMemory.h" #include "deStringUtil.hpp" namespace tcu { namespace Android { namespace internal { using std::string; using de::DynamicLibrary; template void setFuncPtr (Func*& funcPtr, DynamicLibrary& lib, const string& symname) { funcPtr = reinterpret_cast(lib.getFunction(symname.c_str())); if (!funcPtr) TCU_THROW(NotSupportedError, ("Unable to look up symbol from shared object: " + symname).c_str()); } LibUI::LibUI (void) : m_library ("libui.so") { GraphicBufferFunctions& gb = m_functions.graphicBuffer; setFuncPtr(gb.constructor, m_library, "_ZN7android13GraphicBufferC1Ejjij"); setFuncPtr(gb.destructor, m_library, "_ZN7android13GraphicBufferD1Ev"); 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 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(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(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(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(memory); #else DE_UNREF(fptr); DE_UNREF(memory); DE_UNREF(param1); DE_UNREF(param2); DE_UNREF(param3); DE_UNREF(param4); TCU_THROW(NotSupportedError, "ABI not supported"); return DE_NULL; #endif } template 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 DE_UNREF(fptr); DE_UNREF(obj); TCU_THROW(NotSupportedError, "ABI not supported"); #endif } template T1* pointerToOffset (T2* ptr, size_t bytes) { return reinterpret_cast((deUint8*)ptr + bytes); } static android::android_native_base_t* getAndroidNativeBase (android::GraphicBuffer* gb) { // \note: assuming Itanium ABI return pointerToOffset(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(base, 0); } //! access android_native_base_t::version static deUint32 getNativeBaseVersion (android::android_native_base_t* base) { return *pointerToOffset(base, 4); } //! access android_native_base_t::incRef static NativeBaseFunctions::incRefFunc getNativeBaseIncRefFunc (android::android_native_base_t* base) { return *pointerToOffset(base, 8 + DE_PTR_SIZE*4); } //! access android_native_base_t::decRef static NativeBaseFunctions::decRefFunc getNativeBaseDecRefFunc (android::android_native_base_t* base) { return *pointerToOffset(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(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(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_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) { if (m_impl && m_baseFunctions.decRef) { m_baseFunctions.decRef(getAndroidNativeBase(m_impl)); m_impl = DE_NULL; } } status_t GraphicBuffer::lock (deUint32 usage, void** vaddr) { return m_functions.lock(m_impl, usage, vaddr); } status_t GraphicBuffer::unlock (void) { return m_functions.unlock(m_impl); } ANativeWindowBuffer* GraphicBuffer::getNativeBuffer (void) const { return m_functions.getNativeBuffer(m_impl); } } // internal } // Android } // tcu