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