C++程序  |  278行  |  8.19 KB

/*-------------------------------------------------------------------------
 * 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