1/*-------------------------------------------------------------------------
2 * drawElements Quality Program EGL Module
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 Android-specific operations.
22 *//*--------------------------------------------------------------------*/
23
24#include "teglAndroidUtil.hpp"
25
26#include "deStringUtil.hpp"
27#include "tcuTextureUtil.hpp"
28#include "gluTextureUtil.hpp"
29#include "glwEnums.hpp"
30#include "eglwLibrary.hpp"
31#include "eglwEnums.hpp"
32
33namespace deqp
34{
35namespace egl
36{
37namespace Image
38{
39
40using std::string;
41using de::MovePtr;
42using tcu::PixelBufferAccess;
43using tcu::TextureFormat;
44using tcu::Texture2D;
45using eglu::AttribMap;
46using namespace glw;
47using namespace eglw;
48
49#if (DE_OS != DE_OS_ANDROID)
50
51MovePtr<ImageSource> createAndroidNativeImageSource	(GLenum format, deUint32 numLayers, bool isYUV)
52{
53	DE_UNREF(numLayers);
54	return createUnsupportedImageSource("Not Android platform", format, isYUV);
55}
56
57#else // DE_OS == DE_OS_ANDROID
58
59#if defined(__ANDROID_API_O__) && (DE_ANDROID_API >= __ANDROID_API_O__)
60#	define BUILT_WITH_ANDROID_HARDWARE_BUFFER 1
61#endif
62
63#if defined(__ANDROID_API_P__) && (DE_ANDROID_API >= __ANDROID_API_P__)
64#	define BUILT_WITH_ANDROID_P_HARDWARE_BUFFER 1
65#endif
66
67#if !defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER)
68
69MovePtr<ImageSource> createAndroidNativeImageSource	(GLenum format, deUint32 numLayers, bool isYUV)
70{
71	DE_UNREF(numLayers);
72	return createUnsupportedImageSource("AHB API not supported", format, isYUV);
73}
74
75#else // defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER)
76
77namespace
78{
79
80#include <sys/system_properties.h>
81#include <android/hardware_buffer.h>
82#include "deDynamicLibrary.hpp"
83
84const deUint32 AHB_FORMAT_Y8Cb8Cr8_420 = 0x23;
85
86deInt32 androidGetSdkVersion (void)
87{
88	static deInt32 sdkVersion = -1;
89	if (sdkVersion < 0)
90	{
91		char value[128] = {0};
92		__system_property_get("ro.build.version.sdk", value);
93		sdkVersion = static_cast<deInt32>(strtol(value, DE_NULL, 10));
94		printf("SDK Version is %d\n", sdkVersion);
95	}
96	return sdkVersion;
97}
98
99typedef int		(*pfnAHardwareBuffer_allocate)(const AHardwareBuffer_Desc* desc, AHardwareBuffer** outBuffer);
100typedef void	(*pfnAHardwareBuffer_describe)(const AHardwareBuffer* buffer, AHardwareBuffer_Desc* outDesc);
101typedef void	(*pfnAHardwareBuffer_acquire)(AHardwareBuffer* buffer);
102typedef void	(*pfnAHardwareBuffer_release)(AHardwareBuffer* buffer);
103typedef int		(*pfnAHardwareBuffer_isSupported)(const AHardwareBuffer_Desc* desc);
104
105struct AhbFunctions
106{
107	pfnAHardwareBuffer_allocate		allocate;
108	pfnAHardwareBuffer_describe		describe;
109	pfnAHardwareBuffer_acquire		acquire;
110	pfnAHardwareBuffer_release		release;
111	pfnAHardwareBuffer_isSupported	isSupported;
112};
113
114AhbFunctions ahbFunctions;
115
116bool ahbFunctionsLoaded (AhbFunctions* pAhbFunctions, deInt32 sdkVersion)
117{
118	static bool ahbApiLoaded = false;
119	if (ahbApiLoaded ||
120			((pAhbFunctions->allocate != DE_NULL) &&
121			 (pAhbFunctions->describe != DE_NULL) &&
122			 (pAhbFunctions->acquire  != DE_NULL) &&
123			 (pAhbFunctions->release  != DE_NULL) &&
124			 (pAhbFunctions->isSupported != DE_NULL || sdkVersion < 29)))
125	{
126		ahbApiLoaded = true;
127		return true;
128	}
129	return false;
130}
131
132bool loadAhbDynamicApis (deInt32 sdkVersion)
133{
134	if (!ahbFunctionsLoaded(&ahbFunctions, sdkVersion))
135	{
136		static de::DynamicLibrary libnativewindow("libnativewindow.so");
137		ahbFunctions.allocate = reinterpret_cast<pfnAHardwareBuffer_allocate>(libnativewindow.getFunction("AHardwareBuffer_allocate"));
138		ahbFunctions.describe = reinterpret_cast<pfnAHardwareBuffer_describe>(libnativewindow.getFunction("AHardwareBuffer_describe"));
139		ahbFunctions.acquire  = reinterpret_cast<pfnAHardwareBuffer_acquire>(libnativewindow.getFunction("AHardwareBuffer_acquire"));
140		ahbFunctions.release  = reinterpret_cast<pfnAHardwareBuffer_release>(libnativewindow.getFunction("AHardwareBuffer_release"));
141		if (sdkVersion >= 29)
142			ahbFunctions.isSupported = reinterpret_cast<pfnAHardwareBuffer_isSupported>(libnativewindow.getFunction("AHardwareBuffer_isSupported"));
143		else
144			ahbFunctions.isSupported = DE_NULL;
145
146		return ahbFunctionsLoaded(&ahbFunctions, sdkVersion);
147	}
148
149	return true;
150}
151
152deUint32 getPixelFormat (GLenum format)
153{
154	switch (format)
155	{
156		case GL_RGB565:				return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
157		case GL_RGB8:				return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
158		case GL_RGBA8:				return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
159		case GL_DEPTH_COMPONENT16:	return AHARDWAREBUFFER_FORMAT_D16_UNORM;
160		case GL_DEPTH_COMPONENT24:	return AHARDWAREBUFFER_FORMAT_D24_UNORM;
161		case GL_DEPTH24_STENCIL8:	return AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT;
162		case GL_DEPTH_COMPONENT32F:	return AHARDWAREBUFFER_FORMAT_D32_FLOAT;
163		case GL_DEPTH32F_STENCIL8:	return AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT;
164		case GL_RGB10_A2:			return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
165		case GL_RGBA16F:			return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
166		case GL_STENCIL_INDEX8:		return AHARDWAREBUFFER_FORMAT_S8_UINT;
167
168		default:					TCU_THROW(NotSupportedError, "Texture format unsupported by Android");
169	}
170}
171
172class AndroidNativeClientBuffer : public ClientBuffer
173{
174public:
175						AndroidNativeClientBuffer	(const Library& egl, GLenum format, deUint32 numLayers, bool isYUV);
176						~AndroidNativeClientBuffer	(void);
177	EGLClientBuffer		get							(void) const;
178	void				lock						(void** data);
179	void				unlock						(void);
180	AHardwareBuffer_Desc	describe					(void);
181
182private:
183	const Library&			m_egl;
184	AHardwareBuffer*		m_hardwareBuffer;
185};
186
187AndroidNativeClientBuffer::AndroidNativeClientBuffer (const Library& egl, GLenum format, deUint32 numLayers, bool isYUV)
188	: m_egl(egl)
189{
190	deInt32 sdkVersion = androidGetSdkVersion();
191
192#if defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER)
193	// When testing AHB on Android-P and newer the CTS must be compiled against API28 or newer.
194	DE_TEST_ASSERT(sdkVersion >= 28); /*__ANDROID_API_P__ */
195#else
196	// When testing AHB on Android-O and newer the CTS must be compiled against API26 or newer.
197	DE_TEST_ASSERT(sdkVersion >= 26); /* __ANDROID_API_O__ */
198#endif // !defined(BUILT_WITH_ANDROID_P_HARDWARE_BUFFER)
199
200	if (!loadAhbDynamicApis(sdkVersion))
201	{
202		// Couldn't load Android AHB system APIs.
203		DE_TEST_ASSERT(false);
204	}
205
206	AHardwareBuffer_Desc hbufferdesc = {
207		64u,
208		64u,
209		numLayers,
210		isYUV ? AHB_FORMAT_Y8Cb8Cr8_420 : getPixelFormat(format),
211		AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN	|
212		AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY	|
213		AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE	|
214		AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT,
215		0u,		// Stride in pixels, ignored for AHardwareBuffer_allocate()
216		0u,		// Initialize to zero, reserved for future use
217		0u		// Initialize to zero, reserved for future use
218	};
219
220	// If we have AHardwareBuffer_isSupported use that before trying the allocation.
221	if (ahbFunctions.isSupported != DE_NULL)
222	{
223		if (!ahbFunctions.isSupported(&hbufferdesc))
224			TCU_THROW(NotSupportedError, "Texture format unsupported");
225	}
226
227	if (ahbFunctions.allocate(&hbufferdesc, &m_hardwareBuffer) != 0)
228	{
229		// Throw unsupported instead of failing the test as the texture format or the number
230		// of layers might be unsupported.
231		TCU_THROW(NotSupportedError, "AHB allocation failed");
232	}
233}
234
235AndroidNativeClientBuffer::~AndroidNativeClientBuffer (void)
236{
237	ahbFunctions.release(m_hardwareBuffer);
238}
239
240EGLClientBuffer AndroidNativeClientBuffer::get (void) const
241{
242	typedef EGLW_APICALL EGLClientBuffer (EGLW_APIENTRY* eglGetNativeClientBufferANDROIDFunc) (const struct AHardwareBuffer *buffer);
243	return ((eglGetNativeClientBufferANDROIDFunc)m_egl.getProcAddress("eglGetNativeClientBufferANDROID"))(m_hardwareBuffer);
244}
245
246void AndroidNativeClientBuffer::lock (void** data)
247{
248	const int status = AHardwareBuffer_lock(m_hardwareBuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY, -1, DE_NULL, data);
249
250	if (status != 0)
251		TCU_FAIL(("AHardwareBuffer_lock failed with error: " + de::toString(status)).c_str());
252}
253
254void AndroidNativeClientBuffer::unlock (void)
255{
256	const int status = AHardwareBuffer_unlock(m_hardwareBuffer, DE_NULL);
257
258	if (status != 0)
259		TCU_FAIL(("AHardwareBuffer_unlock failed with error: " + de::toString(status)).c_str());
260}
261
262AHardwareBuffer_Desc AndroidNativeClientBuffer::describe (void)
263{
264	AHardwareBuffer_Desc ret;
265	ahbFunctions.describe(m_hardwareBuffer, &ret);
266	return ret;
267}
268
269class AndroidNativeImageSource : public ImageSource
270{
271public:
272							AndroidNativeImageSource	(GLenum format, deUint32 numLayers, bool isYUV) : m_format(format), m_numLayers(numLayers), m_isY8Cb8Cr8_420(isYUV) {}
273							~AndroidNativeImageSource	(void);
274	MovePtr<ClientBuffer>	createBuffer				(const Library& egl, const glw::Functions&, Texture2D*) const;
275	string					getRequiredExtension		(void) const { return "EGL_ANDROID_get_native_client_buffer"; }
276	EGLImageKHR				createImage					(const Library& egl, EGLDisplay dpy, EGLContext ctx, EGLClientBuffer clientBuffer) const;
277	GLenum					getEffectiveFormat			(void) const { return m_format; }
278	bool					isYUVFormatImage			(void) const { return m_isY8Cb8Cr8_420;	}
279protected:
280	GLenum					m_format;
281	deUint32				m_numLayers;
282	bool					m_isY8Cb8Cr8_420;
283};
284
285AndroidNativeImageSource::~AndroidNativeImageSource (void)
286{
287}
288
289MovePtr<ClientBuffer> AndroidNativeImageSource::createBuffer (const Library& egl, const glw::Functions&, Texture2D* ref) const
290{
291	MovePtr<AndroidNativeClientBuffer> buffer (new AndroidNativeClientBuffer(egl, m_format, m_numLayers, m_isY8Cb8Cr8_420));
292
293	if (ref != DE_NULL)
294	{
295		const TextureFormat	texFormat	= glu::mapGLInternalFormat(m_format);
296		void*				bufferData	= DE_NULL;
297
298		*ref = Texture2D(texFormat, 64, 64);
299		ref->m_yuvTextureUsed = m_isY8Cb8Cr8_420;
300		ref->allocLevel(0);
301		tcu::fillWithComponentGradients(ref->getLevel(0),
302										tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
303										tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
304
305		// AHB doesn't allow locking a layered image. In that case the data
306		// will be initialized later using OpenGL API.
307		// YUV format texture will be initialized by glClear.
308
309		if (m_numLayers == 1u && !m_isY8Cb8Cr8_420)
310		{
311			buffer->lock(&bufferData);
312			{
313				AHardwareBuffer_Desc	desc			= buffer->describe();
314				const int				rowPitch		= texFormat.getPixelSize() * desc.stride;
315				const int				slicePitch		= rowPitch * desc.height;
316				PixelBufferAccess		nativeBuffer	(texFormat, desc.width, desc.height, 1, rowPitch, slicePitch, bufferData);
317
318				tcu::copy(nativeBuffer, ref->getLevel(0));
319			}
320			buffer->unlock();
321		}
322	}
323	return MovePtr<ClientBuffer>(buffer);
324}
325
326EGLImageKHR AndroidNativeImageSource::createImage (const Library& egl, EGLDisplay dpy, EGLContext, EGLClientBuffer clientBuffer) const
327{
328	static const EGLint	attribs[]	= { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
329	const EGLImageKHR	image		= egl.createImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attribs);
330
331	EGLU_CHECK_MSG(egl, "eglCreateImageKHR()");
332	return image;
333}
334
335} // anonymous
336
337MovePtr<ImageSource> createAndroidNativeImageSource	(GLenum format, deUint32 numLayers, bool isYUV)
338{
339	try
340	{
341		return MovePtr<ImageSource>(new AndroidNativeImageSource(format, numLayers, isYUV));
342	}
343	catch (const std::runtime_error& exc)
344	{
345		return createUnsupportedImageSource(string("Android native buffers unsupported: ") + exc.what(), format, isYUV);
346	}
347}
348
349#endif // defined(BUILT_WITH_ANDROID_HARDWARE_BUFFER)
350
351#endif // DE_OS == DE_OS_ANDROID
352
353} // Image
354} // egl
355} // deqp
356