1/*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Access to Android internals that are not a part of the NDK.
22 *//*--------------------------------------------------------------------*/
23
24#include "tcuAndroidInternals.hpp"
25#include "deMemory.h"
26#include "deStringUtil.hpp"
27
28namespace tcu
29{
30namespace Android
31{
32namespace internal
33{
34
35using std::string;
36using de::DynamicLibrary;
37
38template<typename Func>
39void setFuncPtr (Func*& funcPtr, DynamicLibrary& lib, const string& symname)
40{
41	funcPtr = reinterpret_cast<Func*>(lib.getFunction(symname.c_str()));
42	if (!funcPtr)
43		TCU_THROW(NotSupportedError, ("Unable to look up symbol from shared object: " + symname).c_str());
44}
45
46LibUI::LibUI (void)
47	: m_library	("libui.so")
48{
49	GraphicBufferFunctions& gb = m_functions.graphicBuffer;
50
51	setFuncPtr(gb.constructor,		m_library,	"_ZN7android13GraphicBufferC1Ejjij");
52	setFuncPtr(gb.destructor,		m_library,	"_ZN7android13GraphicBufferD1Ev");
53	setFuncPtr(gb.getNativeBuffer,	m_library,	"_ZNK7android13GraphicBuffer15getNativeBufferEv");
54	setFuncPtr(gb.lock,				m_library,	"_ZN7android13GraphicBuffer4lockEjPPv");
55	setFuncPtr(gb.unlock,			m_library,	"_ZN7android13GraphicBuffer6unlockEv");
56	setFuncPtr(gb.initCheck,		m_library,	"_ZNK7android13GraphicBuffer9initCheckEv");
57}
58
59#define GRAPHICBUFFER_SIZE 1024 // Hopefully enough
60
61typedef void (*GenericFptr)();
62
63//! call constructor with 4 arguments
64template <typename RT, typename T1, typename T2, typename T3, typename T4>
65RT* callConstructor4 (GenericFptr fptr, void* memory, size_t memorySize, T1 param1, T2 param2, T3 param3, T4 param4)
66{
67	DE_UNREF(memorySize);
68
69#if (DE_CPU == DE_CPU_ARM)
70	// C1 constructors return pointer
71	typedef RT* (*ABIFptr)(void*, T1, T2, T3, T4);
72	(void)((ABIFptr)fptr)(memory, param1, param2, param3, param4);
73	return reinterpret_cast<RT*>(memory);
74#elif (DE_CPU == DE_CPU_ARM_64)
75	// C1 constructors return void
76	typedef void (*ABIFptr)(void*, T1, T2, T3, T4);
77	((ABIFptr)fptr)(memory, param1, param2, param3, param4);
78	return reinterpret_cast<RT*>(memory);
79#elif (DE_CPU == DE_CPU_X86)
80	// ctor returns void
81	typedef void (*ABIFptr)(void*, T1, T2, T3, T4);
82	((ABIFptr)fptr)(memory, param1, param2, param3, param4);
83	return reinterpret_cast<RT*>(memory);
84#elif (DE_CPU == DE_CPU_X86_64)
85	// ctor returns void
86	typedef void (*ABIFptr)(void*, T1, T2, T3, T4);
87	((ABIFptr)fptr)(memory, param1, param2, param3, param4);
88	return reinterpret_cast<RT*>(memory);
89#else
90	DE_UNREF(fptr);
91	DE_UNREF(memory);
92	DE_UNREF(param1);
93	DE_UNREF(param2);
94	DE_UNREF(param3);
95	DE_UNREF(param4);
96	TCU_THROW(NotSupportedError, "ABI not supported");
97	return DE_NULL;
98#endif
99}
100
101template <typename T>
102void callDestructor (GenericFptr fptr, T* obj)
103{
104#if (DE_CPU == DE_CPU_ARM)
105	// D1 destructor returns ptr
106	typedef void* (*ABIFptr)(T* obj);
107	(void)((ABIFptr)fptr)(obj);
108#elif (DE_CPU == DE_CPU_ARM_64)
109	// D1 destructor returns void
110	typedef void (*ABIFptr)(T* obj);
111	((ABIFptr)fptr)(obj);
112#elif (DE_CPU == DE_CPU_X86)
113	// dtor returns void
114	typedef void (*ABIFptr)(T* obj);
115	((ABIFptr)fptr)(obj);
116#elif (DE_CPU == DE_CPU_X86_64)
117	// dtor returns void
118	typedef void (*ABIFptr)(T* obj);
119	((ABIFptr)fptr)(obj);
120#else
121	DE_UNREF(fptr);
122	DE_UNREF(obj);
123	TCU_THROW(NotSupportedError, "ABI not supported");
124#endif
125}
126
127template<typename T1, typename T2>
128T1* pointerToOffset (T2* ptr, size_t bytes)
129{
130	return reinterpret_cast<T1*>((deUint8*)ptr + bytes);
131}
132
133static android::android_native_base_t* getAndroidNativeBase (android::GraphicBuffer* gb)
134{
135	// \note: assuming Itanium ABI
136	return pointerToOffset<android::android_native_base_t>(gb, 2 * DE_PTR_SIZE);
137}
138
139//! android_native_base_t::magic for ANativeWindowBuffer
140static deInt32 getExpectedNativeBufferVersion (void)
141{
142#if (DE_PTR_SIZE == 4)
143	return 96;
144#elif (DE_PTR_SIZE == 8)
145	return 168;
146#else
147#	error Invalid DE_PTR_SIZE
148#endif
149}
150
151//! access android_native_base_t::magic
152static deUint32 getNativeBaseMagic (android::android_native_base_t* base)
153{
154	return *pointerToOffset<deUint32>(base, 0);
155}
156
157//! access android_native_base_t::version
158static deUint32 getNativeBaseVersion (android::android_native_base_t* base)
159{
160	return *pointerToOffset<deInt32>(base, 4);
161}
162
163//! access android_native_base_t::incRef
164static NativeBaseFunctions::incRefFunc getNativeBaseIncRefFunc (android::android_native_base_t* base)
165{
166	return *pointerToOffset<NativeBaseFunctions::incRefFunc>(base, 8 + DE_PTR_SIZE*4);
167}
168
169//! access android_native_base_t::decRef
170static NativeBaseFunctions::decRefFunc getNativeBaseDecRefFunc (android::android_native_base_t* base)
171{
172	return *pointerToOffset<NativeBaseFunctions::decRefFunc>(base, 8 + DE_PTR_SIZE*5);
173}
174
175static android::GraphicBuffer* createGraphicBuffer (const GraphicBufferFunctions& functions, NativeBaseFunctions& baseFunctions, deUint32 w, deUint32 h, PixelFormat format, deUint32 usage)
176{
177	// \note: Hopefully uses the same allocator as libui
178	void* const memory = deMalloc(GRAPHICBUFFER_SIZE);
179	if (memory == DE_NULL)
180		TCU_THROW(ResourceError, "Could not alloc for GraphicBuffer");
181	else
182	{
183		try
184		{
185			android::GraphicBuffer* const			gb			= callConstructor4<android::GraphicBuffer, deUint32, deUint32, PixelFormat, deUint32>(functions.constructor,
186																																					  memory,
187																																					  GRAPHICBUFFER_SIZE,
188																																					  w,
189																																					  h,
190																																					  format,
191																																					  usage);
192			android::android_native_base_t* const	base		= getAndroidNativeBase(gb);
193			status_t								ctorStatus	= functions.initCheck(gb);
194
195			if (ctorStatus)
196			{
197				// ctor failed
198				callDestructor<android::GraphicBuffer>(functions.destructor, gb);
199				TCU_THROW(NotSupportedError, ("GraphicBuffer ctor failed, initCheck returned " + de::toString(ctorStatus)).c_str());
200			}
201
202			// check object layout
203			{
204				const deUint32 magic		= getNativeBaseMagic(base);
205				const deUint32 bufferMagic	= 0x5f626672u; // "_bfr"
206
207				if (magic != bufferMagic)
208					TCU_THROW(NotSupportedError, "GraphicBuffer layout unexpected");
209			}
210
211			// check object version
212			{
213				const deInt32 version			= getNativeBaseVersion(base);
214				const deInt32 expectedVersion	= getExpectedNativeBufferVersion();
215
216				if (version != expectedVersion)
217					TCU_THROW(NotSupportedError, "GraphicBuffer version unexpected");
218			}
219
220			// locate refcounting functions
221
222			if (!baseFunctions.incRef || !baseFunctions.decRef)
223			{
224				baseFunctions.incRef = getNativeBaseIncRefFunc(base);
225				baseFunctions.decRef = getNativeBaseDecRefFunc(base);
226			}
227
228			// take the initial reference and return
229			baseFunctions.incRef(base);
230			return gb;
231		}
232		catch (...)
233		{
234			deFree(memory);
235			throw;
236		}
237	}
238}
239
240GraphicBuffer::GraphicBuffer (const LibUI& lib, deUint32 width, deUint32 height, PixelFormat format, deUint32 usage)
241	: m_functions	(lib.getFunctions().graphicBuffer)
242	, m_impl		(DE_NULL)
243{
244	m_baseFunctions.incRef = DE_NULL;
245	m_baseFunctions.decRef = DE_NULL;
246
247	// \note createGraphicBuffer updates m_baseFunctions
248	m_impl = createGraphicBuffer(m_functions, m_baseFunctions, width, height, format, usage);
249}
250
251GraphicBuffer::~GraphicBuffer (void)
252{
253	if (m_impl && m_baseFunctions.decRef)
254	{
255		m_baseFunctions.decRef(getAndroidNativeBase(m_impl));
256		m_impl = DE_NULL;
257	}
258}
259
260status_t GraphicBuffer::lock (deUint32 usage, void** vaddr)
261{
262	return m_functions.lock(m_impl, usage, vaddr);
263}
264
265status_t GraphicBuffer::unlock (void)
266{
267	return m_functions.unlock(m_impl);
268}
269
270ANativeWindowBuffer* GraphicBuffer::getNativeBuffer (void) const
271{
272	return m_functions.getNativeBuffer(m_impl);
273}
274
275} // internal
276} // Android
277} // tcu
278