1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <EGL/egl.h> 18 #include <EGL/eglext.h> 19 #include <GLES2/gl2.h> 20 #include <GLES2/gl2ext.h> 21 #include <jni.h> 22 #include <stdlib.h> 23 #include <android/hardware_buffer.h> 24 #include <android/log.h> 25 #include <cmath> 26 #include <string> 27 #include <sstream> 28 29 #define LOG_TAG "VrExtensionsJni" 30 #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__) 31 32 using PFNEGLGETNATIVECLIENTBUFFERANDROID = 33 EGLClientBuffer(EGLAPIENTRYP)(const AHardwareBuffer* buffer); 34 35 using PFNGLEGLIMAGETARGETTEXTURE2DOESPROC = void(GL_APIENTRYP)(GLenum target, 36 void* image); 37 38 using PFNGLBUFFERSTORAGEEXTERNALEXTPROC = 39 void(GL_APIENTRYP)(GLenum target, GLintptr offset, GLsizeiptr size, 40 void* clientBuffer, GLbitfield flags); 41 42 using PFNGLMAPBUFFERRANGEPROC = void*(GL_APIENTRYP)(GLenum target, 43 GLintptr offset, 44 GLsizeiptr length, 45 GLbitfield access); 46 47 using PFNGLUNMAPBUFFERPROC = void*(GL_APIENTRYP)(GLenum target); 48 49 PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; 50 PFNEGLGETNATIVECLIENTBUFFERANDROID eglGetNativeClientBufferANDROID; 51 PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; 52 PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glFramebufferTextureMultiviewOVR; 53 PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC 54 glFramebufferTextureMultisampleMultiviewOVR; 55 PFNGLBUFFERSTORAGEEXTERNALEXTPROC glBufferStorageExternalEXT; 56 PFNGLMAPBUFFERRANGEPROC glMapBufferRange; 57 PFNGLUNMAPBUFFERPROC glUnmapBuffer; 58 59 #define NO_ERROR 0 60 #define GL_UNIFORM_BUFFER 0x8A11 61 62 // Declare flags that are added to MapBufferRange via EXT_buffer_storage. 63 // https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_buffer_storage.txt 64 #define GL_MAP_PERSISTENT_BIT_EXT 0x0040 65 #define GL_MAP_COHERENT_BIT_EXT 0x0080 66 67 // Declare tokens added as a part of EGL_EXT_image_gl_colorspace. 68 #define EGL_GL_COLORSPACE_DEFAULT_EXT 0x314D 69 70 #define LOAD_PROC(NAME, TYPE) \ 71 NAME = reinterpret_cast<TYPE>(eglGetProcAddress(# NAME)) 72 73 #define ASSERT(condition, format, args...) \ 74 if (!(condition)) { \ 75 fail(env, format, ## args); \ 76 return; \ 77 } 78 79 #define ASSERT_TRUE(a) \ 80 ASSERT((a), "assert failed on (" #a ") at " __FILE__ ":%d", __LINE__) 81 #define ASSERT_FALSE(a) \ 82 ASSERT(!(a), "assert failed on (!" #a ") at " __FILE__ ":%d", __LINE__) 83 #define ASSERT_EQ(a, b) \ 84 ASSERT((a) == (b), "assert failed on (" #a ") at " __FILE__ ":%d", __LINE__) 85 #define ASSERT_NE(a, b) \ 86 ASSERT((a) != (b), "assert failed on (" #a ") at " __FILE__ ":%d", __LINE__) 87 #define ASSERT_GT(a, b) \ 88 ASSERT((a) > (b), "assert failed on (" #a ") at " __FILE__ ":%d", __LINE__) 89 #define ASSERT_NEAR(a, b, delta) \ 90 ASSERT((a - delta) <= (b) && (b) <= (a + delta), \ 91 "assert failed on (" #a ") at " __FILE__ ":%d", __LINE__) 92 93 void fail(JNIEnv* env, const char* format, ...) { 94 va_list args; 95 va_start(args, format); 96 char* msg; 97 vasprintf(&msg, format, args); 98 va_end(args); 99 jclass exClass; 100 const char* className = "java/lang/AssertionError"; 101 exClass = env->FindClass(className); 102 env->ThrowNew(exClass, msg); 103 free(msg); 104 } 105 106 static void testEglImageArray(JNIEnv* env, AHardwareBuffer_Desc desc, 107 int nsamples) { 108 ASSERT_GT(desc.layers, 1); 109 AHardwareBuffer* hwbuffer = nullptr; 110 int error = AHardwareBuffer_allocate(&desc, &hwbuffer); 111 ASSERT_FALSE(error); 112 // Create EGLClientBuffer from the AHardwareBuffer. 113 EGLClientBuffer native_buffer = eglGetNativeClientBufferANDROID(hwbuffer); 114 ASSERT_TRUE(native_buffer); 115 // Create EGLImage from EGLClientBuffer. 116 EGLint attrs[] = {EGL_NONE}; 117 EGLImageKHR image = 118 eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT, 119 EGL_NATIVE_BUFFER_ANDROID, native_buffer, attrs); 120 ASSERT_TRUE(image); 121 // Create OpenGL texture from the EGLImage. 122 GLuint texid; 123 glGenTextures(1, &texid); 124 glBindTexture(GL_TEXTURE_2D_ARRAY, texid); 125 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D_ARRAY, image); 126 ASSERT_EQ(glGetError(), GL_NO_ERROR); 127 // Create FBO and add multiview attachment. 128 GLuint fboid; 129 glGenFramebuffers(1, &fboid); 130 glBindFramebuffer(GL_FRAMEBUFFER, fboid); 131 const GLint miplevel = 0; 132 const GLint base_view = 0; 133 const GLint num_views = desc.layers; 134 if (nsamples == 1) { 135 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 136 texid, miplevel, base_view, num_views); 137 } else { 138 glFramebufferTextureMultisampleMultiviewOVR( 139 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texid, miplevel, nsamples, 140 base_view, num_views); 141 } 142 ASSERT_EQ(glGetError(), GL_NO_ERROR); 143 ASSERT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), 144 GL_FRAMEBUFFER_COMPLETE); 145 // Release memory. 146 glDeleteTextures(1, &texid); 147 glDeleteFramebuffers(1, &fboid); 148 AHardwareBuffer_release(hwbuffer); 149 } 150 151 extern "C" JNIEXPORT void JNICALL 152 Java_android_vr_cts_VrExtensionBehaviorTest_nativeTestEglImageArray( 153 JNIEnv* env, jclass /* unused */) { 154 // First, load entry points provided by extensions. 155 LOAD_PROC(glEGLImageTargetTexture2DOES, 156 PFNGLEGLIMAGETARGETTEXTURE2DOESPROC); 157 ASSERT_NE(glEGLImageTargetTexture2DOES, nullptr); 158 LOAD_PROC(eglGetNativeClientBufferANDROID, 159 PFNEGLGETNATIVECLIENTBUFFERANDROID); 160 ASSERT_NE(eglGetNativeClientBufferANDROID, nullptr); 161 LOAD_PROC(eglCreateImageKHR, PFNEGLCREATEIMAGEKHRPROC); 162 ASSERT_NE(eglCreateImageKHR, nullptr); 163 LOAD_PROC(glFramebufferTextureMultiviewOVR, 164 PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC); 165 ASSERT_NE(glFramebufferTextureMultiviewOVR, nullptr); 166 LOAD_PROC(glFramebufferTextureMultisampleMultiviewOVR, 167 PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC); 168 ASSERT_NE(glFramebufferTextureMultisampleMultiviewOVR, nullptr); 169 // Try creating a 32x32 AHardwareBuffer and attaching it to a multiview 170 // framebuffer, with various formats and depths. 171 AHardwareBuffer_Desc desc = {}; 172 desc.width = 32; 173 desc.height = 32; 174 desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | 175 AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT; 176 const int layers[] = {2, 4}; 177 const int formats[] = { 178 AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM, 179 AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 180 AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM, 181 AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT, 182 // Do not test AHARDWAREBUFFER_FORMAT_BLOB, it isn't color-renderable. 183 }; 184 const int samples[] = {1, 2, 4}; 185 for (int nsamples : samples) { 186 for (auto nlayers : layers) { 187 for (auto format : formats) { 188 desc.layers = nlayers; 189 desc.format = format; 190 testEglImageArray(env, desc, nsamples); 191 } 192 } 193 } 194 } 195 196 static void testExternalBuffer(JNIEnv* env, uint64_t usage, bool write_hwbuffer, 197 const std::string& test_string) { 198 // Create a blob AHardwareBuffer suitable for holding the string. 199 AHardwareBuffer_Desc desc = {}; 200 desc.width = test_string.size(); 201 desc.height = 1; 202 desc.layers = 1; 203 desc.format = AHARDWAREBUFFER_FORMAT_BLOB; 204 desc.usage = usage; 205 AHardwareBuffer* hwbuffer = nullptr; 206 int error = AHardwareBuffer_allocate(&desc, &hwbuffer); 207 ASSERT_EQ(error, NO_ERROR); 208 // Create EGLClientBuffer from the AHardwareBuffer. 209 EGLClientBuffer native_buffer = eglGetNativeClientBufferANDROID(hwbuffer); 210 ASSERT_TRUE(native_buffer); 211 // Create uniform buffer from EGLClientBuffer. 212 const GLbitfield flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | 213 GL_MAP_COHERENT_BIT_EXT | GL_MAP_PERSISTENT_BIT_EXT; 214 GLuint buf = 0; 215 glGenBuffers(1, &buf); 216 glBindBuffer(GL_UNIFORM_BUFFER, buf); 217 ASSERT_EQ(glGetError(), GL_NO_ERROR); 218 const GLsizeiptr bufsize = desc.width * desc.height; 219 glBufferStorageExternalEXT(GL_UNIFORM_BUFFER, 0, 220 bufsize, native_buffer, flags); 221 ASSERT_EQ(glGetError(), GL_NO_ERROR); 222 // Obtain a writeable pointer using either OpenGL or the Android API, 223 // then copy the test string into it. 224 if (write_hwbuffer) { 225 void* data = nullptr; 226 error = AHardwareBuffer_lock(hwbuffer, 227 AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, 228 NULL, &data); 229 ASSERT_EQ(error, NO_ERROR); 230 ASSERT_TRUE(data); 231 memcpy(data, test_string.c_str(), test_string.size()); 232 error = AHardwareBuffer_unlock(hwbuffer, nullptr); 233 ASSERT_EQ(error, NO_ERROR); 234 } else { 235 void* data = 236 glMapBufferRange(GL_UNIFORM_BUFFER, 0, bufsize, 237 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT_EXT); 238 ASSERT_EQ(glGetError(), GL_NO_ERROR); 239 ASSERT_TRUE(data); 240 memcpy(data, test_string.c_str(), test_string.size()); 241 glUnmapBuffer(GL_UNIFORM_BUFFER); 242 ASSERT_EQ(glGetError(), GL_NO_ERROR); 243 } 244 // Obtain a readable pointer and verify the data. 245 void* data = glMapBufferRange(GL_UNIFORM_BUFFER, 0, bufsize, GL_MAP_READ_BIT); 246 ASSERT_TRUE(data); 247 ASSERT_EQ(strncmp(static_cast<char*>(data), test_string.c_str(), 248 test_string.size()), 0); 249 glUnmapBuffer(GL_UNIFORM_BUFFER); 250 ASSERT_EQ(glGetError(), GL_NO_ERROR); 251 AHardwareBuffer_release(hwbuffer); 252 } 253 254 extern "C" JNIEXPORT void JNICALL 255 Java_android_vr_cts_VrExtensionBehaviorTest_nativeTestExternalBuffer( 256 JNIEnv* env, jclass /* unused */) { 257 // First, check for EXT_external_buffer in the extension string. 258 auto exts = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)); 259 ASSERT_TRUE(exts && strstr(exts, "GL_EXT_external_buffer")); 260 // Next, load entry points provided by extensions. 261 LOAD_PROC(eglGetNativeClientBufferANDROID, PFNEGLGETNATIVECLIENTBUFFERANDROID); 262 ASSERT_NE(eglGetNativeClientBufferANDROID, nullptr); 263 LOAD_PROC(glBufferStorageExternalEXT, PFNGLBUFFERSTORAGEEXTERNALEXTPROC); 264 ASSERT_NE(glBufferStorageExternalEXT, nullptr); 265 LOAD_PROC(glMapBufferRange, PFNGLMAPBUFFERRANGEPROC); 266 ASSERT_NE(glMapBufferRange, nullptr); 267 LOAD_PROC(glUnmapBuffer, PFNGLUNMAPBUFFERPROC); 268 ASSERT_NE(glUnmapBuffer, nullptr); 269 const uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | 270 AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | 271 AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER | 272 AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA; 273 const std::string test_string = "Hello, world."; 274 // First try writing to the buffer using OpenGL, then try writing to it via 275 // the AHardwareBuffer API. 276 testExternalBuffer(env, usage, false, test_string); 277 testExternalBuffer(env, usage, true, test_string); 278 } 279 280 const GLchar* const kSrgbVertexCode = R"( 281 // vertex position in clip space (-1..1) 282 attribute vec4 position; 283 varying mediump vec2 uv; 284 void main() { 285 gl_Position = position; 286 uv = vec2(0.5 * (position.x + 1.0), 0.5); 287 })"; 288 289 const GLchar* const kSrgbFragmentCode = R"( 290 varying mediump vec2 uv; 291 uniform sampler2D tex; 292 void main() { 293 gl_FragColor = texture2D(tex, uv); 294 })"; 295 296 static inline float SrgbChannelToLinear(float cs) { 297 if (cs <= 0.04045) 298 return cs / 12.92f; 299 else 300 return std::pow((cs + 0.055f) / 1.055f, 2.4f); 301 } 302 303 static inline float LinearChannelToSrgb(float cs) { 304 if (cs <= 0.0f) 305 return 0.0f; 306 else if (cs < 0.0031308f) 307 return 12.92f * cs; 308 else if (cs < 1.0f) 309 return 1.055f * std::pow(cs, 0.41666f) - 0.055f; 310 else 311 return 1.0f; 312 } 313 314 static uint32_t SrgbColorToLinear(uint32_t color) { 315 float r = SrgbChannelToLinear((color & 0xff) / 255.0f); 316 float g = SrgbChannelToLinear(((color >> 8) & 0xff) / 255.0f); 317 float b = SrgbChannelToLinear(((color >> 16) & 0xff) / 255.0f); 318 uint32_t r8 = r * 255.0f; 319 uint32_t g8 = g * 255.0f; 320 uint32_t b8 = b * 255.0f; 321 uint32_t a8 = color >> 24; 322 return (a8 << 24) | (b8 << 16) | (g8 << 8) | r8; 323 } 324 325 static uint32_t LinearColorToSrgb(uint32_t color) { 326 float r = LinearChannelToSrgb((color & 0xff) / 255.0f); 327 float g = LinearChannelToSrgb(((color >> 8) & 0xff) / 255.0f); 328 float b = LinearChannelToSrgb(((color >> 16) & 0xff) / 255.0f); 329 uint32_t r8 = r * 255.0f; 330 uint32_t g8 = g * 255.0f; 331 uint32_t b8 = b * 255.0f; 332 uint32_t a8 = color >> 24; 333 return (a8 << 24) | (b8 << 16) | (g8 << 8) | r8; 334 } 335 336 static uint32_t LerpColor(uint32_t color0, uint32_t color1, float t) { 337 float r0 = (color0 & 0xff) / 255.0f; 338 float g0 = ((color0 >> 8) & 0xff) / 255.0f; 339 float b0 = ((color0 >> 16) & 0xff) / 255.0f; 340 float a0 = ((color0 >> 24) & 0xff) / 255.0f; 341 float r1 = (color1 & 0xff) / 255.0f; 342 float g1 = ((color1 >> 8) & 0xff) / 255.0f; 343 float b1 = ((color1 >> 16) & 0xff) / 255.0f; 344 float a1 = ((color1 >> 24) & 0xff) / 255.0f; 345 uint32_t r8 = (r0 * (1.0f - t) + r1 * t) * 255.0f; 346 uint32_t g8 = (g0 * (1.0f - t) + g1 * t) * 255.0f; 347 uint32_t b8 = (b0 * (1.0f - t) + b1 * t) * 255.0f; 348 uint32_t a8 = (a0 * (1.0f - t) + a1 * t) * 255.0f; 349 return (a8 << 24) | (b8 << 16) | (g8 << 8) | r8; 350 } 351 352 // Choose an odd-numbered framebuffer width so that we can 353 // extract the middle pixel of a gradient. 354 constexpr uint32_t kFramebufferWidth = 31; 355 356 // Declare the pixel data for the 2x1 texture. 357 // Color components are ordered like this: AABBGGRR 358 constexpr uint32_t kTextureData[] = { 359 0xff800000, // Half-Blue 360 0xff000080, // Half-Red 361 }; 362 constexpr uint32_t kTextureWidth = sizeof(kTextureData) / sizeof(kTextureData[0]); 363 364 // Declare expected values for the middle pixel for various sampling behaviors. 365 const uint32_t kExpectedMiddlePixel_NoSrgb = LerpColor(kTextureData[0], kTextureData[1], 0.5f); 366 const uint32_t kExpectedMiddlePixel_LinearizeAfterFiltering = 367 SrgbColorToLinear(kExpectedMiddlePixel_NoSrgb); 368 const uint32_t kExpectedMiddlePixel_LinearizeBeforeFiltering = 369 LerpColor(SrgbColorToLinear(kTextureData[0]), SrgbColorToLinear(kTextureData[1]), 0.5f); 370 371 // Declare expected values for the final pixel color for various blending behaviors. 372 constexpr uint32_t kBlendDestColor = 0xff000080; 373 constexpr uint32_t kBlendSourceColor = 0x80800000; 374 const uint32_t kExpectedBlendedPixel_NoSrgb = LerpColor(kBlendSourceColor, kBlendDestColor, 0.5f); 375 const uint32_t kExpectedBlendedPixel_Srgb = 376 LinearColorToSrgb(LerpColor(kBlendSourceColor, SrgbColorToLinear(kBlendDestColor), 0.5f)); 377 378 // Define a set of test flags. Not using an enum to avoid lots of casts. 379 namespace SrgbFlag { 380 constexpr uint32_t kHardwareBuffer = 1 << 0; 381 constexpr uint32_t kSrgbFormat = 1 << 1; 382 constexpr uint32_t kEglColorspaceDefault = 1 << 2; 383 constexpr uint32_t kEglColorspaceLinear = 1 << 3; 384 constexpr uint32_t kEglColorspaceSrgb = 1 << 4; 385 } // namespace SrgbFlag 386 387 static void configureEglColorspace(EGLint attrs[4], uint32_t srgb_flags) { 388 if (srgb_flags & SrgbFlag::kEglColorspaceDefault) { 389 attrs[0] = EGL_GL_COLORSPACE_KHR; 390 attrs[1] = EGL_GL_COLORSPACE_DEFAULT_EXT; 391 } else if (srgb_flags & SrgbFlag::kEglColorspaceLinear) { 392 attrs[0] = EGL_GL_COLORSPACE_KHR; 393 attrs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; 394 } else if (srgb_flags & SrgbFlag::kEglColorspaceSrgb) { 395 attrs[0] = EGL_GL_COLORSPACE_KHR; 396 attrs[1] = EGL_GL_COLORSPACE_SRGB_KHR; 397 } else { 398 attrs[0] = EGL_NONE; 399 attrs[1] = EGL_NONE; 400 } 401 attrs[2] = EGL_NONE; 402 attrs[3] = EGL_NONE; 403 } 404 405 static void printSrgbFlags(std::ostream& out, uint32_t srgb_flags) { 406 if (srgb_flags & SrgbFlag::kHardwareBuffer) { 407 out << " AHardwareBuffer"; 408 } 409 if (srgb_flags & SrgbFlag::kSrgbFormat) { 410 out << " GL_SRGB_ALPHA"; 411 } 412 if (srgb_flags & SrgbFlag::kEglColorspaceDefault) { 413 out << " EGL_GL_COLORSPACE_DEFAULT_KHR"; 414 } 415 if (srgb_flags & SrgbFlag::kEglColorspaceLinear) { 416 out << " EGL_GL_COLORSPACE_LINEAR_KHR"; 417 } 418 if (srgb_flags & SrgbFlag::kEglColorspaceSrgb) { 419 out << " EGL_GL_COLORSPACE_SRGB_KHR"; 420 } 421 } 422 423 // Draws a gradient and extracts the middle pixel. Returns void to allow ASSERT to work. 424 static void testLinearMagnification(JNIEnv* env, uint32_t flags, uint32_t* middle_pixel) { 425 const bool use_hwbuffer = flags & SrgbFlag::kHardwareBuffer; 426 const bool use_srgb_format = flags & SrgbFlag::kSrgbFormat; 427 GLuint srgbtex; 428 glGenTextures(1, &srgbtex); 429 glBindTexture(GL_TEXTURE_2D, srgbtex); 430 if (use_hwbuffer) { 431 // Create a one-dimensional AHardwareBuffer. 432 AHardwareBuffer_Desc desc = {}; 433 desc.width = kTextureWidth; 434 desc.height = 1; 435 desc.layers = 1; 436 desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; 437 desc.usage = 438 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT; 439 AHardwareBuffer* hwbuffer = nullptr; 440 int error = AHardwareBuffer_allocate(&desc, &hwbuffer); 441 ASSERT_EQ(error, NO_ERROR); 442 // Populate the pixels. 443 uint32_t* pixels = nullptr; 444 error = AHardwareBuffer_lock(hwbuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, -1, nullptr, 445 reinterpret_cast<void**>(&pixels)); 446 ASSERT_EQ(error, NO_ERROR); 447 ASSERT_TRUE(pixels); 448 memcpy(pixels, kTextureData, sizeof(kTextureData)); 449 error = AHardwareBuffer_unlock(hwbuffer, nullptr); 450 ASSERT_EQ(error, NO_ERROR); 451 // Create EGLClientBuffer from the AHardwareBuffer. 452 EGLClientBuffer native_buffer = eglGetNativeClientBufferANDROID(hwbuffer); 453 ASSERT_TRUE(native_buffer); 454 // Create EGLImage from EGLClientBuffer. 455 EGLint attrs[4]; 456 configureEglColorspace(attrs, flags); 457 EGLImageKHR image = eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT, 458 EGL_NATIVE_BUFFER_ANDROID, native_buffer, attrs); 459 ASSERT_TRUE(image); 460 // Allocate the OpenGL texture using the EGLImage. 461 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); 462 } else { 463 GLenum internal_format = use_srgb_format ? GL_SRGB8_ALPHA8_EXT : GL_RGBA8_OES; 464 GLenum format = use_srgb_format ? GL_SRGB_ALPHA_EXT : GL_RGBA; 465 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, kTextureWidth, 1, 0, format, 466 GL_UNSIGNED_BYTE, kTextureData); 467 } 468 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 469 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 470 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 471 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 472 ASSERT_EQ(glGetError(), GL_NO_ERROR); 473 // Clear to an interesting constant color to make it easier to spot bugs. 474 glClearColor(1.0, 0.0, 0.5, 0.25); 475 glClear(GL_COLOR_BUFFER_BIT); 476 // Draw the texture. 477 const float kTriangleCoords[] = {-1, -1, -1, 1, 1, -1, 1, 1}; 478 glBindTexture(GL_TEXTURE_2D, srgbtex); 479 const int kPositionSlot = 0; 480 glVertexAttribPointer(kPositionSlot, 2, GL_FLOAT, false, 0, kTriangleCoords); 481 glEnableVertexAttribArray(kPositionSlot); 482 glViewport(0, 0, kFramebufferWidth, 1); 483 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 484 // Read back the framebuffer. 485 glReadPixels(kFramebufferWidth / 2, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, middle_pixel); 486 std::ostringstream flag_string; 487 printSrgbFlags(flag_string, flags); 488 LOGV("Filtered Result: %8.8X Flags =%s", *middle_pixel, flag_string.str().c_str()); 489 ASSERT_EQ(glGetError(), GL_NO_ERROR); 490 } 491 492 // Blends a color into an (optionally) sRGB-encoded framebuffer and extracts the final color. 493 // Returns void to allow ASSERT to work. 494 static void testFramebufferBlending(JNIEnv* env, uint32_t flags, uint32_t* final_color) { 495 const bool use_hwbuffer = flags & SrgbFlag::kHardwareBuffer; 496 const bool use_srgb_format = flags & SrgbFlag::kSrgbFormat; 497 const bool override_egl_colorspace = use_hwbuffer && (flags & SrgbFlag::kEglColorspaceSrgb); 498 GLuint tex; 499 glGenTextures(1, &tex); 500 glBindTexture(GL_TEXTURE_2D, tex); 501 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 502 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 503 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 504 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 505 // Create a 1x1 half-blue, half-opaque texture. 506 const uint32_t kTextureData[] = { 507 kBlendSourceColor, 508 }; 509 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, 510 GL_UNSIGNED_BYTE, kTextureData); 511 // Create 1x1 framebuffer object. 512 GLuint fbo; 513 glGenFramebuffers(1, &fbo); 514 glBindFramebuffer(GL_FRAMEBUFFER, fbo); 515 GLuint fbotex; 516 glGenTextures(1, &fbotex); 517 glBindTexture(GL_TEXTURE_2D, fbotex); 518 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 519 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 520 if (use_hwbuffer) { 521 AHardwareBuffer_Desc desc = {}; 522 desc.width = 1; 523 desc.height = 1; 524 desc.layers = 1; 525 desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; 526 desc.usage = 527 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT; 528 AHardwareBuffer* hwbuffer = nullptr; 529 int error = AHardwareBuffer_allocate(&desc, &hwbuffer); 530 ASSERT_EQ(error, NO_ERROR); 531 // Create EGLClientBuffer from the AHardwareBuffer. 532 EGLClientBuffer native_buffer = eglGetNativeClientBufferANDROID(hwbuffer); 533 ASSERT_TRUE(native_buffer); 534 // Create EGLImage from EGLClientBuffer. 535 EGLint attrs[4]; 536 configureEglColorspace(attrs, flags); 537 EGLImageKHR image = eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT, 538 EGL_NATIVE_BUFFER_ANDROID, native_buffer, attrs); 539 ASSERT_TRUE(image); 540 // Allocate the OpenGL texture using the EGLImage. 541 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); 542 } else { 543 GLenum internal_format = use_srgb_format ? GL_SRGB8_ALPHA8_EXT : GL_RGBA8_OES; 544 GLenum format = use_srgb_format ? GL_SRGB_ALPHA_EXT : GL_RGBA; 545 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, 1, 1, 0, format, 546 GL_UNSIGNED_BYTE, nullptr); 547 } 548 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 549 GL_TEXTURE_2D, fbotex, 0); 550 ASSERT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE); 551 ASSERT_EQ(glGetError(), GL_NO_ERROR); 552 // Clear to half-red. 553 if (use_srgb_format || override_egl_colorspace) { 554 glClearColor(SrgbChannelToLinear(0.5), 0.0, 0.0, 1.0); 555 } else { 556 glClearColor(0.5, 0.0, 0.0, 1.0); 557 } 558 glClear(GL_COLOR_BUFFER_BIT); 559 // Sanity check the cleared color. 560 uint32_t cleared_color = 0; 561 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &cleared_color); 562 LOGV(" Cleared Color: %8.8X", cleared_color); 563 ASSERT_EQ(cleared_color, kBlendDestColor); 564 // Draw the texture. 565 glEnable(GL_BLEND); 566 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 567 const float kTriangleCoords[] = {-1, -1, -1, 1, 1, -1, 1, 1}; 568 glBindTexture(GL_TEXTURE_2D, tex); 569 const int kPositionSlot = 0; 570 glVertexAttribPointer(kPositionSlot, 2, GL_FLOAT, false, 0, kTriangleCoords); 571 glEnableVertexAttribArray(kPositionSlot); 572 glViewport(0, 0, 1, 1); 573 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 574 // Read back the framebuffer. 575 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, final_color); 576 std::ostringstream flag_string; 577 printSrgbFlags(flag_string, flags); 578 LOGV("Blending Result: %8.8X Flags =%s", *final_color, flag_string.str().c_str()); 579 ASSERT_EQ(glGetError(), GL_NO_ERROR); 580 } 581 582 extern "C" JNIEXPORT void JNICALL 583 Java_android_vr_cts_VrExtensionBehaviorTest_nativeTestSrgbBuffer( 584 JNIEnv* env, jclass /* unused */) { 585 // First, check the published extension strings against expectations. 586 const char *egl_exts = 587 eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS); 588 LOGV("EGL Extensions: %s", egl_exts); 589 ASSERT_TRUE(egl_exts); 590 bool egl_colorspace_supported = strstr(egl_exts, "EGL_EXT_image_gl_colorspace"); 591 auto gl_exts = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)); 592 LOGV("OpenGL Extensions: %s", gl_exts); 593 ASSERT_TRUE(gl_exts); 594 // Load ancillary entry points provided by extensions. 595 LOAD_PROC(eglGetNativeClientBufferANDROID, 596 PFNEGLGETNATIVECLIENTBUFFERANDROID); 597 ASSERT_NE(eglGetNativeClientBufferANDROID, nullptr); 598 LOAD_PROC(eglCreateImageKHR, PFNEGLCREATEIMAGEKHRPROC); 599 ASSERT_NE(eglCreateImageKHR, nullptr); 600 LOAD_PROC(glEGLImageTargetTexture2DOES, 601 PFNGLEGLIMAGETARGETTEXTURE2DOESPROC); 602 ASSERT_NE(glEGLImageTargetTexture2DOES, nullptr); 603 // Create a plain old one-dimensional FBO to render to. 604 GLuint fbo; 605 glGenFramebuffers(1, &fbo); 606 glBindFramebuffer(GL_FRAMEBUFFER, fbo); 607 GLuint fbotex; 608 glGenTextures(1, &fbotex); 609 glBindTexture(GL_TEXTURE_2D, fbotex); 610 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 611 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 612 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kFramebufferWidth, 1, 0, GL_RGBA, 613 GL_UNSIGNED_BYTE, nullptr); 614 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 615 GL_TEXTURE_2D, fbotex, 0); 616 ASSERT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE); 617 ASSERT_EQ(glGetError(), GL_NO_ERROR); 618 // Compile and link shaders. 619 int program = glCreateProgram(); 620 int vshader = glCreateShader(GL_VERTEX_SHADER); 621 glShaderSource(vshader, 1, &kSrgbVertexCode, nullptr); 622 glCompileShader(vshader); 623 glAttachShader(program, vshader); 624 int fshader = glCreateShader(GL_FRAGMENT_SHADER); 625 glShaderSource(fshader, 1, &kSrgbFragmentCode, nullptr); 626 glCompileShader(fshader); 627 glAttachShader(program, fshader); 628 glLinkProgram(program); 629 int status; 630 glGetProgramiv(program, GL_LINK_STATUS, &status); 631 ASSERT_EQ(status, GL_TRUE); 632 glUseProgram(program); 633 ASSERT_EQ(glGetError(), GL_NO_ERROR); 634 635 // Filtering test. 636 LOGV("Expected value for NoSrgb = %8.8X", kExpectedMiddlePixel_NoSrgb); 637 LOGV("Expected value for Srgb = %8.8X", kExpectedMiddlePixel_LinearizeBeforeFiltering); 638 uint32_t middle_pixel; 639 // First do a sanity check with plain old pre-linearized textures. 640 testLinearMagnification(env, 0, &middle_pixel); 641 ASSERT_NEAR(middle_pixel, kExpectedMiddlePixel_NoSrgb, 1); 642 testLinearMagnification(env, SrgbFlag::kHardwareBuffer, &middle_pixel); 643 ASSERT_NEAR(middle_pixel, kExpectedMiddlePixel_NoSrgb, 1); 644 // Try a "normally allocated" OpenGL texture with an sRGB source format. 645 testLinearMagnification(env, SrgbFlag::kSrgbFormat, &middle_pixel); 646 ASSERT_NEAR(middle_pixel, kExpectedMiddlePixel_LinearizeBeforeFiltering, 1); 647 // Try EGL_EXT_image_gl_colorspace. 648 if (egl_colorspace_supported) { 649 testLinearMagnification(env, SrgbFlag::kHardwareBuffer | SrgbFlag::kEglColorspaceDefault, &middle_pixel); 650 ASSERT_NEAR(middle_pixel, kExpectedMiddlePixel_NoSrgb, 1); 651 testLinearMagnification(env, SrgbFlag::kHardwareBuffer | SrgbFlag::kEglColorspaceLinear, &middle_pixel); 652 ASSERT_NEAR(middle_pixel, kExpectedMiddlePixel_NoSrgb, 1); 653 testLinearMagnification(env, SrgbFlag::kHardwareBuffer | SrgbFlag::kEglColorspaceSrgb, &middle_pixel); 654 ASSERT_NEAR(middle_pixel, kExpectedMiddlePixel_LinearizeBeforeFiltering, 1); 655 } 656 657 // Blending test. 658 LOGV("Expected value for NoSrgb = %8.8X", kExpectedBlendedPixel_NoSrgb); 659 LOGV("Expected value for Srgb = %8.8X", kExpectedBlendedPixel_Srgb); 660 uint32_t final_color; 661 // First do a sanity check with plain old pre-linearized textures. 662 testFramebufferBlending(env, 0, &final_color); 663 ASSERT_NEAR(final_color, kExpectedBlendedPixel_NoSrgb, 1); 664 testFramebufferBlending(env, SrgbFlag::kHardwareBuffer, &final_color); 665 ASSERT_NEAR(final_color, kExpectedBlendedPixel_NoSrgb, 1); 666 // Try a "normally allocated" OpenGL texture with an sRGB source format. 667 testFramebufferBlending(env, SrgbFlag::kSrgbFormat, &final_color); 668 ASSERT_NEAR(final_color, kExpectedBlendedPixel_Srgb, 1); 669 // Try EGL_EXT_image_gl_colorspace. 670 if (egl_colorspace_supported) { 671 testFramebufferBlending(env, SrgbFlag::kHardwareBuffer | SrgbFlag::kEglColorspaceDefault, &final_color); 672 ASSERT_NEAR(final_color, kExpectedBlendedPixel_NoSrgb, 1); 673 testFramebufferBlending(env, SrgbFlag::kHardwareBuffer | SrgbFlag::kEglColorspaceLinear, &final_color); 674 ASSERT_NEAR(final_color, kExpectedBlendedPixel_NoSrgb, 1); 675 testFramebufferBlending(env, SrgbFlag::kHardwareBuffer | SrgbFlag::kEglColorspaceSrgb, &final_color); 676 ASSERT_NEAR(final_color, kExpectedBlendedPixel_Srgb, 1); 677 } 678 } 679