1/*
2 * Copyright (C) 2011 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 <gtest/gtest.h>
18
19#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
20
21#include <configstore/Utils.h>
22#include <utils/String8.h>
23
24#include <EGL/egl.h>
25#include <gui/Surface.h>
26#include <gui/IConsumerListener.h>
27#include <gui/IProducerListener.h>
28#include <gui/IGraphicBufferConsumer.h>
29#include <gui/BufferQueue.h>
30
31#define PIXEL_FORMAT_FLOAT "EGL_EXT_pixel_format_float"
32
33bool hasEglPixelFormatFloat() {
34    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
35    const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
36    size_t cropExtLen = strlen(PIXEL_FORMAT_FLOAT);
37    size_t extsLen = strlen(exts);
38    bool equal = !strcmp(PIXEL_FORMAT_FLOAT, exts);
39    bool atStart = !strncmp(PIXEL_FORMAT_FLOAT " ", exts, cropExtLen + 1);
40    bool atEnd = (cropExtLen + 1) < extsLen &&
41            !strcmp(" " PIXEL_FORMAT_FLOAT, exts + extsLen - (cropExtLen + 1));
42    bool inMiddle = strstr(exts, " " PIXEL_FORMAT_FLOAT " ");
43    return equal || atStart || atEnd || inMiddle;
44}
45
46namespace android {
47
48#define EGL_UNSIGNED_TRUE static_cast<EGLBoolean>(EGL_TRUE)
49
50// retrieve wide-color setting from configstore
51using namespace android::hardware::configstore;
52using namespace android::hardware::configstore::V1_0;
53
54static bool hasWideColorDisplay =
55        getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
56
57class EGLTest : public ::testing::Test {
58protected:
59    EGLDisplay mEglDisplay;
60
61protected:
62    EGLTest() :
63            mEglDisplay(EGL_NO_DISPLAY) {
64    }
65
66    virtual void SetUp() {
67        mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
68        ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
69        ASSERT_EQ(EGL_SUCCESS, eglGetError());
70
71        EGLint majorVersion;
72        EGLint minorVersion;
73        EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
74        ASSERT_EQ(EGL_SUCCESS, eglGetError());
75        RecordProperty("EglVersionMajor", majorVersion);
76        RecordProperty("EglVersionMajor", minorVersion);
77    }
78
79    virtual void TearDown() {
80        EGLBoolean success = eglTerminate(mEglDisplay);
81        ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
82        ASSERT_EQ(EGL_SUCCESS, eglGetError());
83    }
84};
85
86TEST_F(EGLTest, DISABLED_EGLConfigEightBitFirst) {
87
88    EGLint numConfigs;
89    EGLConfig config;
90    EGLBoolean success;
91    EGLint attrs[] = {
92            EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
93            EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
94            EGL_NONE
95    };
96
97    success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
98    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
99    ASSERT_EQ(EGL_SUCCESS, eglGetError());
100    ASSERT_GE(numConfigs, 1);
101
102    EGLint components[3];
103
104    success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
105    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
106    ASSERT_EQ(EGL_SUCCESS, eglGetError());
107    success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
108    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
109    ASSERT_EQ(EGL_SUCCESS, eglGetError());
110    success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
111    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
112    ASSERT_EQ(EGL_SUCCESS, eglGetError());
113
114    EXPECT_GE(components[0], 8);
115    EXPECT_GE(components[1], 8);
116    EXPECT_GE(components[2], 8);
117}
118
119TEST_F(EGLTest, EGLTerminateSucceedsWithRemainingObjects) {
120    EGLint numConfigs;
121    EGLConfig config;
122    EGLint attrs[] = {
123        EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
124        EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
125        EGL_RED_SIZE,           8,
126        EGL_GREEN_SIZE,         8,
127        EGL_BLUE_SIZE,          8,
128        EGL_ALPHA_SIZE,         8,
129        EGL_NONE
130    };
131    EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs));
132
133    struct DummyConsumer : public BnConsumerListener {
134        void onFrameAvailable(const BufferItem& /* item */) override {}
135        void onBuffersReleased() override {}
136        void onSidebandStreamChanged() override {}
137    };
138
139    // Create a EGLSurface
140    sp<IGraphicBufferProducer> producer;
141    sp<IGraphicBufferConsumer> consumer;
142    BufferQueue::createBufferQueue(&producer, &consumer);
143    consumer->consumerConnect(new DummyConsumer, false);
144    sp<Surface> mSTC = new Surface(producer);
145    sp<ANativeWindow> mANW = mSTC;
146
147    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config,
148                                mANW.get(), NULL);
149    ASSERT_EQ(EGL_SUCCESS, eglGetError());
150    ASSERT_NE(EGL_NO_SURFACE, eglSurface) ;
151
152    // do not destroy eglSurface
153    // eglTerminate is called in the tear down and should destroy it for us
154}
155
156TEST_F(EGLTest, EGLConfigRGBA8888First) {
157
158    EGLint numConfigs;
159    EGLConfig config;
160    EGLBoolean success;
161    EGLint attrs[] = {
162            EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
163            EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
164            EGL_RED_SIZE,           8,
165            EGL_GREEN_SIZE,         8,
166            EGL_BLUE_SIZE,          8,
167            EGL_ALPHA_SIZE,         8,
168            EGL_NONE
169    };
170
171    success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
172    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
173    ASSERT_EQ(EGL_SUCCESS, eglGetError());
174    ASSERT_GE(numConfigs, 1);
175
176    EGLint components[4];
177
178    success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
179    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
180    ASSERT_EQ(EGL_SUCCESS, eglGetError());
181    success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
182    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
183    ASSERT_EQ(EGL_SUCCESS, eglGetError());
184    success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
185    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
186    ASSERT_EQ(EGL_SUCCESS, eglGetError());
187    success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]);
188    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
189    ASSERT_EQ(EGL_SUCCESS, eglGetError());
190
191    EXPECT_GE(components[0], 8);
192    EXPECT_GE(components[1], 8);
193    EXPECT_GE(components[2], 8);
194    EXPECT_GE(components[3], 8);
195}
196
197TEST_F(EGLTest, EGLConfigFP16) {
198    EGLint numConfigs;
199    EGLConfig config;
200    EGLBoolean success;
201
202    if (!hasWideColorDisplay) {
203        // skip this test if device does not have wide-color display
204        return;
205    }
206
207    ASSERT_TRUE(hasEglPixelFormatFloat());
208
209    EGLint attrs[] = {EGL_SURFACE_TYPE,
210                      EGL_WINDOW_BIT,
211                      EGL_RENDERABLE_TYPE,
212                      EGL_OPENGL_ES2_BIT,
213                      EGL_RED_SIZE,
214                      16,
215                      EGL_GREEN_SIZE,
216                      16,
217                      EGL_BLUE_SIZE,
218                      16,
219                      EGL_ALPHA_SIZE,
220                      16,
221                      EGL_COLOR_COMPONENT_TYPE_EXT,
222                      EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
223                      EGL_NONE};
224    success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
225    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
226    ASSERT_EQ(1, numConfigs);
227
228    EGLint components[4];
229
230    success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
231    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
232    ASSERT_EQ(EGL_SUCCESS, eglGetError());
233    success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
234    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
235    ASSERT_EQ(EGL_SUCCESS, eglGetError());
236    success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
237    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
238    ASSERT_EQ(EGL_SUCCESS, eglGetError());
239    success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]);
240    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
241    ASSERT_EQ(EGL_SUCCESS, eglGetError());
242
243    EXPECT_GE(components[0], 16);
244    EXPECT_GE(components[1], 16);
245    EXPECT_GE(components[2], 16);
246    EXPECT_GE(components[3], 16);
247
248    struct DummyConsumer : public BnConsumerListener {
249        void onFrameAvailable(const BufferItem& /* item */) override {}
250        void onBuffersReleased() override {}
251        void onSidebandStreamChanged() override {}
252    };
253
254    // Create a EGLSurface
255    sp<IGraphicBufferProducer> producer;
256    sp<IGraphicBufferConsumer> consumer;
257    BufferQueue::createBufferQueue(&producer, &consumer);
258    consumer->consumerConnect(new DummyConsumer, false);
259    sp<Surface> mSTC = new Surface(producer);
260    sp<ANativeWindow> mANW = mSTC;
261
262    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), NULL);
263    ASSERT_EQ(EGL_SUCCESS, eglGetError());
264    ASSERT_NE(EGL_NO_SURFACE, eglSurface);
265
266    EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
267}
268}
269