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