Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2015 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkOSWindow_Android.h"
      9 
     10 #include <GLES/gl.h>
     11 
     12 SkOSWindow::SkOSWindow(void* hwnd) {
     13     fWindow.fDisplay = EGL_NO_DISPLAY;
     14     fWindow.fContext = EGL_NO_CONTEXT;
     15     fWindow.fSurface = EGL_NO_SURFACE;
     16     fNativeWindow = (ANativeWindow*)hwnd;
     17     fDestroyRequested = false;
     18 }
     19 
     20 SkOSWindow::~SkOSWindow() {
     21     this->detach();
     22 }
     23 
     24 bool SkOSWindow::attach(SkBackEndTypes attachType,
     25                         int /*msaaSampleCount*/,
     26                         AttachmentInfo* info) {
     27     static const EGLint kEGLContextAttribsForOpenGL[] = {
     28         EGL_NONE
     29     };
     30 
     31     static const EGLint kEGLContextAttribsForOpenGLES[] = {
     32         EGL_CONTEXT_CLIENT_VERSION, 2,
     33         EGL_NONE
     34     };
     35 
     36     static const struct {
     37         const EGLint* fContextAttribs;
     38         EGLenum fAPI;
     39         EGLint  fRenderableTypeBit;
     40     } kAPIs[] = {
     41         {   // OpenGL
     42             kEGLContextAttribsForOpenGL,
     43             EGL_OPENGL_API,
     44             EGL_OPENGL_BIT,
     45         },
     46         {   // OpenGL ES. This seems to work for both ES2 and 3 (when available).
     47             kEGLContextAttribsForOpenGLES,
     48             EGL_OPENGL_ES_API,
     49             EGL_OPENGL_ES2_BIT,
     50         },
     51     };
     52 
     53     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     54     if (EGL_NO_DISPLAY == display) {
     55         return false;
     56     }
     57 
     58     EGLint majorVersion;
     59     EGLint minorVersion;
     60     if (!eglInitialize(display, &majorVersion, &minorVersion)) {
     61         return false;
     62     }
     63 
     64     for (size_t api = 0; api < SK_ARRAY_COUNT(kAPIs); ++api) {
     65         if (!eglBindAPI(kAPIs[api].fAPI)) {
     66             continue;
     67         }
     68 #if 0
     69         SkDebugf("VENDOR: %s\n", eglQueryString(fDisplay, EGL_VENDOR));
     70         SkDebugf("APIS: %s\n", eglQueryString(fDisplay, EGL_CLIENT_APIS));
     71         SkDebugf("VERSION: %s\n", eglQueryString(fDisplay, EGL_VERSION));
     72         SkDebugf("EXTENSIONS %s\n", eglQueryString(fDisplay, EGL_EXTENSIONS));
     73 #endif
     74 
     75         const EGLint configAttribs[] = {
     76             EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
     77             EGL_RENDERABLE_TYPE, kAPIs[api].fRenderableTypeBit,
     78             EGL_RED_SIZE, 8,
     79             EGL_GREEN_SIZE, 8,
     80             EGL_BLUE_SIZE, 8,
     81             EGL_ALPHA_SIZE, 8,
     82             EGL_NONE
     83         };
     84 
     85         EGLint format;
     86         EGLint numConfigs;
     87         EGLConfig config;
     88         EGLSurface surface;
     89         EGLContext context;
     90 
     91         /* Here, the application chooses the configuration it desires. In this
     92          * sample, we have a very simplified selection process, where we pick
     93          * the first EGLConfig that matches our criteria */
     94         if (!eglChooseConfig(display, configAttribs, &config, 1, &numConfigs) ||
     95             numConfigs != 1) {
     96             continue;
     97         }
     98 
     99         /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
    100          * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
    101          * As soon as we picked a EGLConfig, we can safely reconfigure the
    102          * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
    103         if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) {
    104             continue;
    105         }
    106 
    107         ANativeWindow_setBuffersGeometry(fNativeWindow, 0, 0, format);
    108 
    109         surface = eglCreateWindowSurface(display, config, fNativeWindow, nullptr);
    110         if (EGL_NO_SURFACE == surface) {
    111             SkDebugf("eglCreateWindowSurface failed.  EGL Error: 0x%08x\n", eglGetError());
    112             continue;
    113         }
    114         context = eglCreateContext(display, config, nullptr, kAPIs[api].fContextAttribs);
    115         if (EGL_NO_CONTEXT == context) {
    116             SkDebugf("eglCreateContext failed.  EGL Error: 0x%08x\n", eglGetError());
    117             eglDestroySurface(display, surface);
    118             continue;
    119         }
    120 
    121         if (!eglMakeCurrent(display, surface, surface, context)) {
    122             SkDebugf("eglMakeCurrent failed.  EGL Error: 0x%08x\n", eglGetError());
    123             eglDestroyContext(display, context);
    124             eglDestroySurface(display, surface);
    125             continue;
    126         }
    127 
    128         fWindow.fDisplay = display;
    129         fWindow.fContext = context;
    130         fWindow.fSurface = surface;
    131         break;
    132     }
    133 
    134     if (fWindow.fDisplay && fWindow.fContext && fWindow.fSurface) {
    135         EGLint w, h;
    136         eglQuerySurface(fWindow.fDisplay, fWindow.fSurface, EGL_WIDTH, &w);
    137         eglQuerySurface(fWindow.fDisplay, fWindow.fSurface, EGL_HEIGHT, &h);
    138 
    139         glViewport(0, 0, w, h);
    140         glClearColor(0.0, 0, 0, 0.0);
    141         glClearStencil(0);
    142         glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    143 
    144         // We retrieve the fullscreen width and height
    145         this->setSize((SkScalar)w, (SkScalar)h);
    146         return true;
    147     } else {
    148         return false;
    149     }
    150 }
    151 
    152 void SkOSWindow::detach() {
    153     if (fWindow.fDisplay != EGL_NO_DISPLAY) {
    154         eglMakeCurrent(fWindow.fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    155         if (fWindow.fContext != EGL_NO_CONTEXT) {
    156             eglDestroyContext(fWindow.fDisplay, fWindow.fContext);
    157         }
    158         if (fWindow.fSurface != EGL_NO_SURFACE) {
    159             eglDestroySurface(fWindow.fDisplay, fWindow.fSurface);
    160         }
    161         eglTerminate(fWindow.fDisplay);
    162     }
    163     fWindow.fDisplay = EGL_NO_DISPLAY;
    164     fWindow.fContext = EGL_NO_CONTEXT;
    165     fWindow.fSurface = EGL_NO_SURFACE;
    166 }
    167 
    168 void SkOSWindow::present() {
    169     if (fWindow.fDisplay != EGL_NO_DISPLAY && fWindow.fContext != EGL_NO_CONTEXT) {
    170         eglSwapBuffers(fWindow.fDisplay, fWindow.fSurface);
    171     }
    172 }
    173 
    174 void SkOSWindow::closeWindow() {
    175     fDestroyRequested = true;
    176 }
    177 
    178 void SkOSWindow::setVsync(bool vsync) {
    179     if (fWindow.fDisplay != EGL_NO_DISPLAY) {
    180         int swapInterval = vsync ? 1 : 0;
    181         eglSwapInterval(fWindow.fDisplay, swapInterval);
    182     }
    183 }
    184 
    185 void SkOSWindow::onSetTitle(const char title[]) {
    186 }
    187 
    188 void SkOSWindow::onHandleInval(const SkIRect& rect) {
    189 }
    190 
    191 ///////////////////////////////////////////
    192 /////////////// SkEvent impl //////////////
    193 ///////////////////////////////////////////
    194 
    195 void SkEvent::SignalQueueTimer(SkMSec ms) {
    196 }
    197 
    198 void SkEvent::SignalNonEmptyQueue() {
    199 }
    200