Home | History | Annotate | Download | only in sampleDriver
      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 
     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
    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
    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
    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 
    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 
    340 void GlWrapper::showWindow() {
    341     if (mFlingerSurfaceControl != nullptr) {
    342         SurfaceComposerClient::openGlobalTransaction();
    343         mFlingerSurfaceControl->setLayer(0x7FFFFFFF);     // always on top
    344         mFlingerSurfaceControl->show();
    345         SurfaceComposerClient::closeGlobalTransaction();
    346     }
    347 }
    348 
    349 
    350 void GlWrapper::hideWindow() {
    351     if (mFlingerSurfaceControl != nullptr) {
    352         SurfaceComposerClient::openGlobalTransaction();
    353         mFlingerSurfaceControl->hide();
    354         SurfaceComposerClient::closeGlobalTransaction();
    355     }
    356 }
    357 
    358 
    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 
    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