1b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph/*
2b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * Copyright (C) 2017 The Android Open Source Project
3b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph *
4b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * Licensed under the Apache License, Version 2.0 (the "License");
5b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * you may not use this file except in compliance with the License.
6b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * You may obtain a copy of the License at
7b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph *
8b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph *      http://www.apache.org/licenses/LICENSE-2.0
9b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph *
10b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * Unless required by applicable law or agreed to in writing, software
11b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * distributed under the License is distributed on an "AS IS" BASIS,
12b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * See the License for the specific language governing permissions and
14b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * limitations under the License.
15b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph */
16b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
17b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include "GlWrapper.h"
18b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
19b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <stdio.h>
20b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <fcntl.h>
21b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <sys/ioctl.h>
22b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
23b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <ui/DisplayInfo.h>
24b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <ui/GraphicBuffer.h>
25b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <ui/GraphicBufferAllocator.h>
26b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <ui/GraphicBufferMapper.h>
27b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
28b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
29b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphusing namespace android;
30b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
31b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
32b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph// TODO:  Consider dropping direct use of GraphicsBufferAllocator and Mapper?
33b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphusing android::GraphicBuffer;
34b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphusing android::GraphicBufferAllocator;
35b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphusing android::GraphicBufferMapper;
36b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphusing android::sp;
37b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
38b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
39b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphconst char vertexShaderSource[] = ""
40b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "#version 300 es                    \n"
41b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "layout(location = 0) in vec4 pos;  \n"
42b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "layout(location = 1) in vec2 tex;  \n"
43b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "out vec2 uv;                       \n"
44b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "void main()                        \n"
45b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "{                                  \n"
46b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "   gl_Position = pos;              \n"
47b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "   uv = tex;                       \n"
48b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "}                                  \n";
49b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
50b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphconst char pixelShaderSource[] =
51b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "#version 300 es                            \n"
52b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "precision mediump float;                   \n"
53b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "uniform sampler2D tex;                     \n"
54b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "in vec2 uv;                                \n"
55b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "out vec4 color;                            \n"
56b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "void main()                                \n"
57b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "{                                          \n"
58b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "    vec4 texel = texture(tex, uv);         \n"
59b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "    color = texel;                         \n"
60b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        "}                                          \n";
61b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
62b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
63b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphstatic const char *getEGLError(void) {
64b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    switch (eglGetError()) {
65b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_SUCCESS:
66b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_SUCCESS";
67b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_NOT_INITIALIZED:
68b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_NOT_INITIALIZED";
69b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_BAD_ACCESS:
70b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_BAD_ACCESS";
71b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_BAD_ALLOC:
72b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_BAD_ALLOC";
73b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_BAD_ATTRIBUTE:
74b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_BAD_ATTRIBUTE";
75b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_BAD_CONTEXT:
76b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_BAD_CONTEXT";
77b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_BAD_CONFIG:
78b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_BAD_CONFIG";
79b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_BAD_CURRENT_SURFACE:
80b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_BAD_CURRENT_SURFACE";
81b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_BAD_DISPLAY:
82b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_BAD_DISPLAY";
83b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_BAD_SURFACE:
84b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_BAD_SURFACE";
85b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_BAD_MATCH:
86b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_BAD_MATCH";
87b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_BAD_PARAMETER:
88b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_BAD_PARAMETER";
89b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_BAD_NATIVE_PIXMAP:
90b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_BAD_NATIVE_PIXMAP";
91b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_BAD_NATIVE_WINDOW:
92b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_BAD_NATIVE_WINDOW";
93b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        case EGL_CONTEXT_LOST:
94b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "EGL_CONTEXT_LOST";
95b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        default:
96b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return "Unknown error";
97b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
98b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph}
99b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
100b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
101b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph// Given shader source, load and compile it
102b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphstatic GLuint loadShader(GLenum type, const char *shaderSrc) {
103b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Create the shader object
104b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    GLuint shader = glCreateShader (type);
105b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (shader == 0) {
106b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return 0;
107b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
108b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
109b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Load and compile the shader
110b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glShaderSource(shader, 1, &shaderSrc, nullptr);
111b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glCompileShader(shader);
112b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
113b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Verify the compilation worked as expected
114b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    GLint compiled = 0;
115b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
116b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (!compiled) {
117b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("Error compiling shader\n");
118b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
119b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        GLint size = 0;
120b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
121b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        if (size > 0)
122b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        {
123b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            // Get and report the error message
124b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            char *infoLog = (char*)malloc(size);
125b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            glGetShaderInfoLog(shader, size, nullptr, infoLog);
126b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            ALOGE("  msg:\n%s\n", infoLog);
127b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            free(infoLog);
128b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        }
129b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
130b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        glDeleteShader(shader);
131b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return 0;
132b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
133b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
134b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    return shader;
135b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph}
136b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
137b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
138b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph// Create a program object given vertex and pixels shader source
139b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphstatic GLuint buildShaderProgram(const char* vtxSrc, const char* pxlSrc) {
140b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    GLuint program = glCreateProgram();
141b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (program == 0) {
142b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("Failed to allocate program object\n");
143b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return 0;
144b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
145b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
146b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Compile the shaders and bind them to this program
147b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vtxSrc);
148b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (vertexShader == 0) {
149b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("Failed to load vertex shader\n");
150b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        glDeleteProgram(program);
151b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return 0;
152b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
153b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pxlSrc);
154b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (pixelShader == 0) {
155b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("Failed to load pixel shader\n");
156b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        glDeleteProgram(program);
157b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        glDeleteShader(vertexShader);
158b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return 0;
159b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
160b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glAttachShader(program, vertexShader);
161b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glAttachShader(program, pixelShader);
162b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
163b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Link the program
164b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glLinkProgram(program);
165b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    GLint linked = 0;
166b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glGetProgramiv(program, GL_LINK_STATUS, &linked);
167b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (!linked)
168b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    {
169b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("Error linking program.\n");
170b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        GLint size = 0;
171b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &size);
172b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        if (size > 0)
173b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        {
174b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            // Get and report the error message
175b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            char *infoLog = (char*)malloc(size);
176b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            glGetProgramInfoLog(program, size, nullptr, infoLog);
177b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            ALOGE("  msg:  %s\n", infoLog);
178b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            free(infoLog);
179b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        }
180b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
181b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        glDeleteProgram(program);
182b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        glDeleteShader(vertexShader);
183b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        glDeleteShader(pixelShader);
184b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return 0;
185b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
186b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
187b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    return program;
188b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph}
189b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
190b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
191b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph// Main entry point
192b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphbool GlWrapper::initialize() {
193b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    //
194b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    //  Create the native full screen window and get a suitable configuration to match it
195b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    //
196b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    status_t err;
197b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
198f91b3fccfe62a0361f64c89218d3a7a2443f8d0aScott Randolph    mFlinger = new SurfaceComposerClient();
199f91b3fccfe62a0361f64c89218d3a7a2443f8d0aScott Randolph    if (mFlinger == nullptr) {
200f91b3fccfe62a0361f64c89218d3a7a2443f8d0aScott Randolph        ALOGE("SurfaceComposerClient couldn't be allocated");
201f91b3fccfe62a0361f64c89218d3a7a2443f8d0aScott Randolph        return false;
202f91b3fccfe62a0361f64c89218d3a7a2443f8d0aScott Randolph    }
203b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    err = mFlinger->initCheck();
204b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (err != NO_ERROR) {
205b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("SurfaceComposerClient::initCheck error: %#x", err);
206b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return false;
207b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
208b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
209b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Get main display parameters.
210b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    sp <IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay(
211b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            ISurfaceComposer::eDisplayIdMain);
212b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    DisplayInfo mainDpyInfo;
213b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
214b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (err != NO_ERROR) {
215b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("ERROR: unable to get display characteristics");
216b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return false;
217b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
218b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
219b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (mainDpyInfo.orientation != DISPLAY_ORIENTATION_0 &&
220b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        mainDpyInfo.orientation != DISPLAY_ORIENTATION_180) {
221b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        // rotated
222b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        mWidth = mainDpyInfo.h;
223b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        mHeight = mainDpyInfo.w;
224b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    } else {
225b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        mWidth = mainDpyInfo.w;
226b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        mHeight = mainDpyInfo.h;
227b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
228b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
229b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    mFlingerSurfaceControl = mFlinger->createSurface(
230b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            String8("Evs Display"), mWidth, mHeight,
231b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque);
232b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (mFlingerSurfaceControl == nullptr || !mFlingerSurfaceControl->isValid()) {
233b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("Failed to create SurfaceControl");
234b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return false;
235b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
236b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    mFlingerSurface = mFlingerSurfaceControl->getSurface();
237b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
238b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
239b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Set up our OpenGL ES context associated with the default display
240b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
241b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (mDisplay == EGL_NO_DISPLAY) {
242b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("Failed to get egl display");
243b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return false;
244b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
245b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
246b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    EGLint major = 3;
247b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    EGLint minor = 0;
248b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (!eglInitialize(mDisplay, &major, &minor)) {
249b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("Failed to initialize EGL: %s", getEGLError());
250b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return false;
251b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
252b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
253b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
254b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    const EGLint config_attribs[] = {
255b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            // Tag                  Value
256b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            EGL_RED_SIZE,           8,
257b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            EGL_GREEN_SIZE,         8,
258b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            EGL_BLUE_SIZE,          8,
259b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            EGL_DEPTH_SIZE,         0,
260b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            EGL_NONE
261b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    };
262b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
263b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Pick the default configuration without constraints (is this good enough?)
264b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    EGLConfig egl_config = {0};
265b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    EGLint numConfigs = -1;
266b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    eglChooseConfig(mDisplay, config_attribs, &egl_config, 1, &numConfigs);
267b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (numConfigs != 1) {
268b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("Didn't find a suitable format for our display window");
269b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return false;
270b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
271b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
272b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Create the EGL render target surface
273b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    mSurface = eglCreateWindowSurface(mDisplay, egl_config, mFlingerSurface.get(), nullptr);
274b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (mSurface == EGL_NO_SURFACE) {
275b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("gelCreateWindowSurface failed.");
276b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return false;
277b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
278b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
279b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Create the EGL context
280b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // NOTE:  Our shader is (currently at least) written to require version 3, so this
281b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    //        is required.
282b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
283b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    mContext = eglCreateContext(mDisplay, egl_config, EGL_NO_CONTEXT, context_attribs);
284b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (mContext == EGL_NO_CONTEXT) {
285b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("Failed to create OpenGL ES Context: %s", getEGLError());
286b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return false;
287b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
288b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
289b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
290b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Activate our render target for drawing
291b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (!eglMakeCurrent(mDisplay, mSurface, mSurface, mContext)) {
292b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("Failed to make the OpenGL ES Context current: %s", getEGLError());
293b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return false;
294b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
295b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
296b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
297b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Create the shader program for our simple pipeline
298b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    mShaderProgram = buildShaderProgram(vertexShaderSource, pixelShaderSource);
299b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (!mShaderProgram) {
300b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("Failed to build shader program: %s", getEGLError());
301b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return false;
302b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
303b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
304b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Create a GL texture that will eventually wrap our externally created texture surface(s)
305b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glGenTextures(1, &mTextureMap);
306b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (mTextureMap <= 0) {
307b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        ALOGE("Didn't get a texture handle allocated: %s", getEGLError());
308b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        return false;
309b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
310b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
311b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
312b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    return true;
313b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph}
314b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
315b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
316b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphvoid GlWrapper::shutdown() {
317b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
318b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Drop our device textures
319b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (mKHRimage != EGL_NO_IMAGE_KHR) {
320b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        eglDestroyImageKHR(mDisplay, mKHRimage);
321b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        mKHRimage = EGL_NO_IMAGE_KHR;
322b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
323b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
324b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Release all GL resources
325b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
326b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    eglDestroySurface(mDisplay, mSurface);
327b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    eglDestroyContext(mDisplay, mContext);
328b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    eglTerminate(mDisplay);
329b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    mSurface = EGL_NO_SURFACE;
330b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    mContext = EGL_NO_CONTEXT;
331b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    mDisplay = EGL_NO_DISPLAY;
332b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
333b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Let go of our SurfaceComposer resources
334b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    mFlingerSurface.clear();
335b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    mFlingerSurfaceControl.clear();
336b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    mFlinger.clear();
337b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph}
338b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
339b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
340b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphvoid GlWrapper::showWindow() {
341b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (mFlingerSurfaceControl != nullptr) {
342b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        SurfaceComposerClient::openGlobalTransaction();
343b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        mFlingerSurfaceControl->setLayer(0x7FFFFFFF);     // always on top
344b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        mFlingerSurfaceControl->show();
345b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        SurfaceComposerClient::closeGlobalTransaction();
346b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
347b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph}
348b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
349b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
350b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphvoid GlWrapper::hideWindow() {
351b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (mFlingerSurfaceControl != nullptr) {
352b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        SurfaceComposerClient::openGlobalTransaction();
353b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        mFlingerSurfaceControl->hide();
354b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        SurfaceComposerClient::closeGlobalTransaction();
355b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
356b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph}
357b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
358b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
359b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphbool GlWrapper::updateImageTexture(const BufferDesc& buffer) {
360b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
361b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // If we haven't done it yet, create an "image" object to wrap the gralloc buffer
362b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    if (mKHRimage == EGL_NO_IMAGE_KHR) {
363b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        // create a temporary GraphicBuffer to wrap the provided handle
364b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(
365b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                buffer.width,
366b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                buffer.height,
367b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                buffer.format,
368b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                1,      /* layer count */
369b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                buffer.usage,
370b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                buffer.stride,
371b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                const_cast<native_handle_t*>(buffer.memHandle.getNativeHandle()),
372b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                false   /* keep ownership */
373b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        );
374b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        if (pGfxBuffer.get() == nullptr) {
375b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            ALOGE("Failed to allocate GraphicsBuffer to wrap our native handle");
376b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return false;
377b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        }
378b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
379b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
380b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        // Get a GL compatible reference to the graphics buffer we've been given
381b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
382b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
383b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph// TODO:  If we pass in a context, we get "bad context" back
384b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#if 0
385b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        mKHRimage = eglCreateImageKHR(mDisplay, mContext,
386b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                                      EGL_NATIVE_BUFFER_ANDROID, cbuf,
387b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                                      eglImageAttributes);
388b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#else
389b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        mKHRimage = eglCreateImageKHR(mDisplay, EGL_NO_CONTEXT,
390b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                                      EGL_NATIVE_BUFFER_ANDROID, cbuf,
391b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                                      eglImageAttributes);
392b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#endif
393b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        if (mKHRimage == EGL_NO_IMAGE_KHR) {
394b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            ALOGE("error creating EGLImage: %s", getEGLError());
395b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph            return false;
396b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        }
397b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
398b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
399b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        // Update the texture handle we already created to refer to this gralloc buffer
400b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        glActiveTexture(GL_TEXTURE0);
401b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        glBindTexture(GL_TEXTURE_2D, mTextureMap);
402b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(mKHRimage));
403b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
404b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    }
405b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
406b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    return true;
407b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph}
408b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
409b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
410b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphvoid GlWrapper::renderImageToScreen() {
411b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Set the viewport
412b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glViewport(0, 0, mWidth, mHeight);
413b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
414b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Clear the color buffer
415b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glClearColor(0.1f, 0.5f, 0.1f, 1.0f);
416b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glClear(GL_COLOR_BUFFER_BIT);
417b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
418b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Select our screen space simple texture shader
419b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glUseProgram(mShaderProgram);
420b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
421b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Bind the texture and assign it to the shader's sampler
422b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glActiveTexture(GL_TEXTURE0);
423b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glBindTexture(GL_TEXTURE_2D, mTextureMap);
424b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    GLint sampler = glGetUniformLocation(mShaderProgram, "tex");
425b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glUniform1i(sampler, 0);
426b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
427b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // We want our image to show up opaque regardless of alpha values
428b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glDisable(GL_BLEND);
429b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
430b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
431b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Draw a rectangle on the screen
432b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // TODO:  We pulled in from the edges for now for diagnostic purposes...
433b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#if 0
434b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    GLfloat vertsCarPos[] = { -1.0,  1.0, 0.0f,   // left top in window space
435b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                               1.0,  1.0, 0.0f,   // right top
436b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                              -1.0, -1.0, 0.0f,   // left bottom
437b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                               1.0, -1.0, 0.0f    // right bottom
438b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    };
439b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#else
440b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    GLfloat vertsCarPos[] = { -0.8,  0.8, 0.0f,   // left top in window space
441b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                               0.8,  0.8, 0.0f,   // right top
442b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                              -0.8, -0.8, 0.0f,   // left bottom
443b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                               0.8, -0.8, 0.0f    // right bottom
444b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    };
445b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#endif
446b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // NOTE:  We didn't flip the image in the texture, so V=0 is actually the top of the image
447b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    GLfloat vertsCarTex[] = { 0.0f, 0.0f,   // left top
448b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                              1.0f, 0.0f,   // right top
449b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                              0.0f, 1.0f,   // left bottom
450b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph                              1.0f, 1.0f    // right bottom
451b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    };
452b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
453b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
454b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glEnableVertexAttribArray(0);
455b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glEnableVertexAttribArray(1);
456b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
457b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
458b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
459b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
460b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    // Clean up and flip the rendered result to the front so it is visible
461b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glDisableVertexAttribArray(0);
462b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glDisableVertexAttribArray(1);
463b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
464b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    glFinish();
465b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
466b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph    eglSwapBuffers(mDisplay, mSurface);
467b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph}
468b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph
469