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