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