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