/*-------------------------------------------------------------------------
|
* 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<typename Func>
|
void setFuncPtr (Func*& funcPtr, DynamicLibrary& lib, const string& symname)
|
{
|
funcPtr = reinterpret_cast<Func*>(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 <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
|
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 <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
|
DE_UNREF(fptr);
|
DE_UNREF(obj);
|
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_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
|