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