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