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