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