Home | History | Annotate | Download | only in jni
      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