• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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