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