13ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza/*
23ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza * Copyright 2013 The Android Open Source Project
33ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza *
43ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza * Licensed under the Apache License, Version 2.0 (the "License");
53ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza * you may not use this file except in compliance with the License.
63ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza * You may obtain a copy of the License at
73ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza *
83ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza *      http://www.apache.org/licenses/LICENSE-2.0
93ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza *
103ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza * Unless required by applicable law or agreed to in writing, software
113ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza * distributed under the License is distributed on an "AS IS" BASIS,
123ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza * See the License for the specific language governing permissions and
143ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza * limitations under the License.
153ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza */
163ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
173ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza#define LOG_TAG "SRGB_test"
183ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza//#define LOG_NDEBUG 0
193ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
203ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza#include "GLTest.h"
213ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
223ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza#include <gui/CpuConsumer.h>
233ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza#include <gui/Surface.h>
243ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza#include <gui/SurfaceComposerClient.h>
253ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
263ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza#include <EGL/egl.h>
273ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza#include <EGL/eglext.h>
283ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza#include <GLES3/gl3.h>
293ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
303ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza#include <android/native_window.h>
313ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
323ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza#include <gtest/gtest.h>
333ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
343ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stozanamespace android {
353ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
363ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stozaclass SRGBTest : public ::testing::Test {
373ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stozaprotected:
383ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    // Class constants
393ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    enum {
403ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        DISPLAY_WIDTH = 512,
413ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        DISPLAY_HEIGHT = 512,
426a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        PIXEL_SIZE = 4, // bytes or components
433ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        DISPLAY_SIZE = DISPLAY_WIDTH * DISPLAY_HEIGHT * PIXEL_SIZE,
443ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ALPHA_VALUE = 223, // should be in [0, 255]
453ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        TOLERANCE = 1,
463ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    };
473ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    static const char SHOW_DEBUG_STRING[];
483ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
493ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    SRGBTest() :
503ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            mInputSurface(), mCpuConsumer(), mLockedBuffer(),
513ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            mEglDisplay(EGL_NO_DISPLAY), mEglConfig(),
523ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            mEglContext(EGL_NO_CONTEXT), mEglSurface(EGL_NO_SURFACE),
533ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            mComposerClient(), mSurfaceControl(), mOutputSurface() {
543ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    }
553ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
563ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    virtual ~SRGBTest() {
573ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        if (mEglDisplay != EGL_NO_DISPLAY) {
583ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            if (mEglSurface != EGL_NO_SURFACE) {
593ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                eglDestroySurface(mEglDisplay, mEglSurface);
603ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            }
613ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            if (mEglContext != EGL_NO_CONTEXT) {
623ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                eglDestroyContext(mEglDisplay, mEglContext);
633ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            }
643ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
653ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                    EGL_NO_CONTEXT);
663ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            eglTerminate(mEglDisplay);
673ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        }
683ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    }
693ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
703ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    virtual void SetUp() {
715603a2fbbd1aae74c4635e2f600819fb05d112e0Dan Stoza        sp<IGraphicBufferProducer> producer;
725603a2fbbd1aae74c4635e2f600819fb05d112e0Dan Stoza        sp<IGraphicBufferConsumer> consumer;
735603a2fbbd1aae74c4635e2f600819fb05d112e0Dan Stoza        BufferQueue::createBufferQueue(&producer, &consumer);
745603a2fbbd1aae74c4635e2f600819fb05d112e0Dan Stoza        ASSERT_EQ(NO_ERROR, consumer->setDefaultBufferSize(
753ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                DISPLAY_WIDTH, DISPLAY_HEIGHT));
765603a2fbbd1aae74c4635e2f600819fb05d112e0Dan Stoza        mCpuConsumer = new CpuConsumer(consumer, 1);
773ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        String8 name("CpuConsumer_for_SRGBTest");
783ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        mCpuConsumer->setName(name);
795603a2fbbd1aae74c4635e2f600819fb05d112e0Dan Stoza        mInputSurface = new Surface(producer);
803ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
813ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_NO_FATAL_FAILURE(createEGLSurface(mInputSurface.get()));
823ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_NO_FATAL_FAILURE(createDebugSurface());
833ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    }
843ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
853ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    virtual void TearDown() {
863ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_NO_FATAL_FAILURE(copyToDebugSurface());
87b8072d84ba9bf43701fcace61414b3cef5910919Dan Stoza        ASSERT_TRUE(mLockedBuffer.data != NULL);
886a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(NO_ERROR, mCpuConsumer->unlockBuffer(mLockedBuffer));
893ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    }
903ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
913ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    static float linearToSRGB(float l) {
923ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        if (l <= 0.0031308f) {
933ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            return l * 12.92f;
943ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        } else {
953ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            return 1.055f * pow(l, (1 / 2.4f)) - 0.055f;
963ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        }
973ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    }
983ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
996a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    static float srgbToLinear(float s) {
1006a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        if (s <= 0.04045) {
1016a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            return s / 12.92f;
1026a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        } else {
1036a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            return pow(((s + 0.055f) / 1.055f), 2.4f);
1046a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        }
1056a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    }
1066a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
1076a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    static uint8_t srgbToLinear(uint8_t u) {
1086a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        float f = u / 255.0f;
1096a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        return static_cast<uint8_t>(srgbToLinear(f) * 255.0f + 0.5f);
1106a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    }
1116a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
1123ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    void fillTexture(bool writeAsSRGB) {
1133ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        uint8_t* textureData = new uint8_t[DISPLAY_SIZE];
1143ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
1153ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        for (int y = 0; y < DISPLAY_HEIGHT; ++y) {
1163ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            for (int x = 0; x < DISPLAY_WIDTH; ++x) {
1173ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                float realValue = static_cast<float>(x) / (DISPLAY_WIDTH - 1);
1183ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                realValue *= ALPHA_VALUE / 255.0f; // Premultiply by alpha
1193ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                if (writeAsSRGB) {
1203ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                    realValue = linearToSRGB(realValue);
1213ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                }
1223ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
1233ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                int offset = (y * DISPLAY_WIDTH + x) * PIXEL_SIZE;
1243ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                for (int c = 0; c < 3; ++c) {
1253ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                    uint8_t intValue = static_cast<uint8_t>(
1263ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                            realValue * 255.0f + 0.5f);
1273ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                    textureData[offset + c] = intValue;
1283ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                }
1293ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                textureData[offset + 3] = ALPHA_VALUE;
1303ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            }
1313ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        }
1323ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
1333ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        glTexImage2D(GL_TEXTURE_2D, 0, writeAsSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8,
1343ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1353ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                textureData);
1363ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
1373ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
1383ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        delete[] textureData;
1393ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    }
1403ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
1416a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    void initShaders() {
1426a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        static const char vertexSource[] =
1436a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            "attribute vec4 vPosition;\n"
1446a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            "varying vec2 texCoords;\n"
1456a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            "void main() {\n"
1466a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            "  texCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n"
1476a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            "  gl_Position = vPosition;\n"
1486a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            "}\n";
1496a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
1506a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        static const char fragmentSource[] =
1516a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            "precision mediump float;\n"
1526a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            "uniform sampler2D texSampler;\n"
1536a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            "varying vec2 texCoords;\n"
1546a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            "void main() {\n"
1556a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            "  gl_FragColor = texture2D(texSampler, texCoords);\n"
1566a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            "}\n";
1576a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
1586a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        GLuint program;
1596a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        {
1606a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            SCOPED_TRACE("Creating shader program");
1616a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            ASSERT_NO_FATAL_FAILURE(GLTest::createProgram(
1626a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                    vertexSource, fragmentSource, &program));
1636a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        }
1646a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
1656a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        GLint positionHandle = glGetAttribLocation(program, "vPosition");
1666a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
1676a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_NE(-1, positionHandle);
1686a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
1696a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        GLint samplerHandle = glGetUniformLocation(program, "texSampler");
1706a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
1716a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_NE(-1, samplerHandle);
1726a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
1736a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        static const GLfloat vertices[] = {
1746a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            -1.0f, 1.0f,
1756a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            -1.0f, -1.0f,
1766a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            1.0f, -1.0f,
1776a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            1.0f, 1.0f,
1786a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        };
1796a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
1806a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, vertices);
1816a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
1826a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        glEnableVertexAttribArray(positionHandle);
1836a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
1846a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
1856a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        glUseProgram(program);
1866a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
1876a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        glUniform1i(samplerHandle, 0);
1886a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
1896a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
1906a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        GLuint textureHandle;
1916a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        glGenTextures(1, &textureHandle);
1926a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
1936a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        glBindTexture(GL_TEXTURE_2D, textureHandle);
1946a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
1956a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
1966a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1976a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
1986a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1996a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
2006a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2016a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
2026a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2036a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
2046a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    }
2056a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
2066a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    void drawTexture(bool asSRGB, GLint x, GLint y, GLsizei width,
2076a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            GLsizei height) {
2086a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_NO_FATAL_FAILURE(fillTexture(asSRGB));
2096a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        glViewport(x, y, width, height);
2106a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
2116a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
2126a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(GL_NO_ERROR, glGetError());
2136a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    }
2146a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
2156a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    void checkLockedBuffer(PixelFormat format) {
2166a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(mLockedBuffer.format, format);
2176a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(mLockedBuffer.width, DISPLAY_WIDTH);
2186a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(mLockedBuffer.height, DISPLAY_HEIGHT);
2196a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    }
2206a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
2213ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    static bool withinTolerance(int a, int b) {
2223ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        int diff = a - b;
2233ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        return diff >= 0 ? diff <= TOLERANCE : -diff <= TOLERANCE;
2243ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    }
2253ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2263ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    // Primary producer and consumer
2273ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    sp<Surface> mInputSurface;
2283ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    sp<CpuConsumer> mCpuConsumer;
2293ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    CpuConsumer::LockedBuffer mLockedBuffer;
2303ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2313ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    EGLDisplay mEglDisplay;
2323ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    EGLConfig mEglConfig;
2333ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    EGLContext mEglContext;
2343ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    EGLSurface mEglSurface;
2353ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2363ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    // Auxiliary display output
2373ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    sp<SurfaceComposerClient> mComposerClient;
2383ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    sp<SurfaceControl> mSurfaceControl;
2393ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    sp<Surface> mOutputSurface;
2403ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2413ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stozaprivate:
2423ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    void createEGLSurface(Surface* inputSurface) {
2433ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
2443ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_EQ(EGL_SUCCESS, eglGetError());
2453ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
2463ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2473ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        EXPECT_TRUE(eglInitialize(mEglDisplay, NULL, NULL));
2483ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_EQ(EGL_SUCCESS, eglGetError());
2493ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2503ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        static const EGLint configAttribs[] = {
2513ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
2523ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
2533ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            EGL_RED_SIZE, 8,
2543ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            EGL_GREEN_SIZE, 8,
2553ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            EGL_BLUE_SIZE, 8,
2563ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            EGL_ALPHA_SIZE, 8,
2573ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            EGL_NONE };
2583ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2593ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        EGLint numConfigs = 0;
2603ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        EXPECT_TRUE(eglChooseConfig(mEglDisplay, configAttribs, &mEglConfig, 1,
2613ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                &numConfigs));
2623ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_EQ(EGL_SUCCESS, eglGetError());
263b8072d84ba9bf43701fcace61414b3cef5910919Dan Stoza        ASSERT_GT(numConfigs, 0);
2643ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2653ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        static const EGLint contextAttribs[] = {
2663ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            EGL_CONTEXT_CLIENT_VERSION, 3,
2673ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            EGL_NONE } ;
2683ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2693ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT,
2703ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                contextAttribs);
2713ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_EQ(EGL_SUCCESS, eglGetError());
2723ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
2733ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2743ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig,
2753ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                inputSurface, NULL);
2763ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_EQ(EGL_SUCCESS, eglGetError());
2773ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
2783ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2793ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
2803ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                mEglContext));
2813ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_EQ(EGL_SUCCESS, eglGetError());
2823ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    }
2833ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2843ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    void createDebugSurface() {
2853ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        if (getenv(SHOW_DEBUG_STRING) == NULL) return;
2863ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2873ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        mComposerClient = new SurfaceComposerClient;
2883ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
2893ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2903ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        mSurfaceControl = mComposerClient->createSurface(
2913ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                String8("SRGBTest Surface"), DISPLAY_WIDTH, DISPLAY_HEIGHT,
2923ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                PIXEL_FORMAT_RGBA_8888);
2933ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2943ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_TRUE(mSurfaceControl != NULL);
2953ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_TRUE(mSurfaceControl->isValid());
2963ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
2973ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        SurfaceComposerClient::openGlobalTransaction();
2983ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
2993ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
3003ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        SurfaceComposerClient::closeGlobalTransaction();
3013ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
3023ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ANativeWindow_Buffer outBuffer;
3033ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ARect inOutDirtyBounds;
3043ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        mOutputSurface = mSurfaceControl->getSurface();
3053ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        mOutputSurface->lock(&outBuffer, &inOutDirtyBounds);
3066a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        uint8_t* bytePointer = reinterpret_cast<uint8_t*>(outBuffer.bits);
3073ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        for (int y = 0; y < outBuffer.height; ++y) {
3086a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            int rowOffset = y * outBuffer.stride; // pixels
3093ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            for (int x = 0; x < outBuffer.width; ++x) {
3106a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                int colOffset = (rowOffset + x) * PIXEL_SIZE; // bytes
3116a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                for (int c = 0; c < PIXEL_SIZE; ++c) {
3126a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                    int offset = colOffset + c;
3133ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                    bytePointer[offset] = ((c + 1) * 56) - 1;
3143ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                }
3153ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            }
3163ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        }
3173ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        mOutputSurface->unlockAndPost();
3183ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    }
3193ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
3203ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    void copyToDebugSurface() {
3213ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        if (!mOutputSurface.get()) return;
3223ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
3233ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        size_t bufferSize = mLockedBuffer.height * mLockedBuffer.stride *
3243ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza                PIXEL_SIZE;
3253ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
3263ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ANativeWindow_Buffer outBuffer;
3273ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ARect outBufferBounds;
3283ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        mOutputSurface->lock(&outBuffer, &outBufferBounds);
3296a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_EQ(mLockedBuffer.width, outBuffer.width);
3303ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_EQ(mLockedBuffer.height, outBuffer.height);
3313ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        ASSERT_EQ(mLockedBuffer.stride, outBuffer.stride);
3326a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
3336a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        if (mLockedBuffer.format == outBuffer.format) {
3346a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            memcpy(outBuffer.bits, mLockedBuffer.data, bufferSize);
3356a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        } else {
3366a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            ASSERT_EQ(mLockedBuffer.format, PIXEL_FORMAT_sRGB_A_8888);
3376a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            ASSERT_EQ(outBuffer.format, PIXEL_FORMAT_RGBA_8888);
3386a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            uint8_t* outPointer = reinterpret_cast<uint8_t*>(outBuffer.bits);
3396a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            for (int y = 0; y < outBuffer.height; ++y) {
3406a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                int rowOffset = y * outBuffer.stride; // pixels
3416a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                for (int x = 0; x < outBuffer.width; ++x) {
3426a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                    int colOffset = (rowOffset + x) * PIXEL_SIZE; // bytes
3436a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
3446a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                    // RGB are converted
3456a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                    for (int c = 0; c < (PIXEL_SIZE - 1); ++c) {
3466a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                        outPointer[colOffset + c] = srgbToLinear(
3476a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                                mLockedBuffer.data[colOffset + c]);
3486a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                    }
3496a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
3506a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                    // Alpha isn't converted
3516a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                    outPointer[colOffset + 3] =
3526a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                            mLockedBuffer.data[colOffset + 3];
3536a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                }
3546a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            }
3556a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        }
3563ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        mOutputSurface->unlockAndPost();
3573ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
3583ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        int sleepSeconds = atoi(getenv(SHOW_DEBUG_STRING));
3593ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza        sleep(sleepSeconds);
3603ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    }
3613ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza};
3623ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
3633ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stozaconst char SRGBTest::SHOW_DEBUG_STRING[] = "DEBUG_OUTPUT_SECONDS";
3643ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
3653ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan StozaTEST_F(SRGBTest, GLRenderFromSRGBTexture) {
3666a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_NO_FATAL_FAILURE(initShaders());
3673ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
3683ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    // The RGB texture is displayed in the top half
3696a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_NO_FATAL_FAILURE(drawTexture(false, 0, DISPLAY_HEIGHT / 2,
3706a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            DISPLAY_WIDTH, DISPLAY_HEIGHT / 2));
3713ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
3723ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    // The SRGB texture is displayed in the bottom half
3736a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_NO_FATAL_FAILURE(drawTexture(true, 0, 0,
3746a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            DISPLAY_WIDTH, DISPLAY_HEIGHT / 2));
3753ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
3763ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    eglSwapBuffers(mEglDisplay, mEglSurface);
3773ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    ASSERT_EQ(EGL_SUCCESS, eglGetError());
3783ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
3796a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // Lock
3803ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer));
3816a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_NO_FATAL_FAILURE(checkLockedBuffer(PIXEL_FORMAT_RGBA_8888));
3826a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
3836a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // Compare a pixel in the middle of each texture
3843ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    int midSRGBOffset = (DISPLAY_HEIGHT / 4) * mLockedBuffer.stride *
3853ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza            PIXEL_SIZE;
3863ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    int midRGBOffset = midSRGBOffset * 3;
3873ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    midRGBOffset += (DISPLAY_WIDTH / 2) * PIXEL_SIZE;
3883ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    midSRGBOffset += (DISPLAY_WIDTH / 2) * PIXEL_SIZE;
3896a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    for (int c = 0; c < PIXEL_SIZE; ++c) {
3906a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        int expectedValue = mLockedBuffer.data[midRGBOffset + c];
3916a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        int actualValue = mLockedBuffer.data[midSRGBOffset + c];
3926a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_PRED2(withinTolerance, expectedValue, actualValue);
3936a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    }
3946a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
3956a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // mLockedBuffer is unlocked in TearDown so we can copy data from it to
3966a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // the debug surface if necessary
3976a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza}
3986a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
3996a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan StozaTEST_F(SRGBTest, RenderToSRGBSurface) {
4006a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_NO_FATAL_FAILURE(initShaders());
4016a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4026a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // By default, the first buffer we write into will be RGB
4036a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4046a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // Render an RGB texture across the whole surface
4056a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_NO_FATAL_FAILURE(drawTexture(false, 0, 0,
4066a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            DISPLAY_WIDTH, DISPLAY_HEIGHT));
4076a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    eglSwapBuffers(mEglDisplay, mEglSurface);
4086a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_EQ(EGL_SUCCESS, eglGetError());
4096a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4106a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // Lock
4116a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer));
4126a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_NO_FATAL_FAILURE(checkLockedBuffer(PIXEL_FORMAT_RGBA_8888));
4136a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4146a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // Save the values of the middle pixel for later comparison against SRGB
4156a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    uint8_t values[PIXEL_SIZE] = {};
4166a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    int middleOffset = (DISPLAY_HEIGHT / 2) * mLockedBuffer.stride *
4176a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            PIXEL_SIZE;
4186a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    middleOffset += (DISPLAY_WIDTH / 2) * PIXEL_SIZE;
4196a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    for (int c = 0; c < PIXEL_SIZE; ++c) {
4206a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        values[c] = mLockedBuffer.data[middleOffset + c];
4213ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    }
4226a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4236a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // Unlock
4246a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_EQ(NO_ERROR, mCpuConsumer->unlockBuffer(mLockedBuffer));
4256a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4266a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // Switch to SRGB window surface
4276a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza#define EGL_GL_COLORSPACE_KHR      EGL_VG_COLORSPACE
4286a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza#define EGL_GL_COLORSPACE_SRGB_KHR EGL_VG_COLORSPACE_sRGB
4296a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4306a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    static const int srgbAttribs[] = {
4316a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR,
4326a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        EGL_NONE,
4336a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    };
4346a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4356a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
4366a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            mEglContext));
4376a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_EQ(EGL_SUCCESS, eglGetError());
4386a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4396a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    EXPECT_TRUE(eglDestroySurface(mEglDisplay, mEglSurface));
4406a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_EQ(EGL_SUCCESS, eglGetError());
4416a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4426a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig,
4436a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            mInputSurface.get(), srgbAttribs);
4446a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_EQ(EGL_SUCCESS, eglGetError());
4456a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
4466a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4476a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
4486a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            mEglContext));
4496a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_EQ(EGL_SUCCESS, eglGetError());
4506a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4516a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // Render the texture again
4526a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_NO_FATAL_FAILURE(drawTexture(false, 0, 0,
4536a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza            DISPLAY_WIDTH, DISPLAY_HEIGHT));
4546a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    eglSwapBuffers(mEglDisplay, mEglSurface);
4556a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_EQ(EGL_SUCCESS, eglGetError());
4566a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4576a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // Lock
4586a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer));
4596a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4606a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // Make sure we actually got the SRGB buffer on the consumer side
4616a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    ASSERT_NO_FATAL_FAILURE(checkLockedBuffer(PIXEL_FORMAT_sRGB_A_8888));
4626a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4636a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    // Verify that the stored value is the same, accounting for RGB/SRGB
4646a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    for (int c = 0; c < PIXEL_SIZE; ++c) {
4656a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        // The alpha value should be equivalent before linear->SRGB
4666a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        float rgbAsSRGB = (c == 3) ? values[c] / 255.0f :
4676a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza                linearToSRGB(values[c] / 255.0f);
4686a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        int expectedValue = rgbAsSRGB * 255.0f + 0.5f;
4696a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        int actualValue = mLockedBuffer.data[middleOffset + c];
4706a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza        ASSERT_PRED2(withinTolerance, expectedValue, actualValue);
4716a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza    }
4726a5d35dd5cd8710c6c9f100076e62ffbdb0b868bDan Stoza
4733ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    // mLockedBuffer is unlocked in TearDown so we can copy data from it to
4743ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza    // the debug surface if necessary
4753ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza}
4763ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza
4773ed4e0b3655b4019b9ab9939f6df0cb8a102d37fDan Stoza} // namespace android
478