1 /* 2 * Copyright (C) 2009 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 package com.android.systemui; 18 19 import static android.opengl.GLES20.*; 20 import static javax.microedition.khronos.egl.EGL10.*; 21 22 import android.app.ActivityManager; 23 import android.app.WallpaperManager; 24 import android.content.BroadcastReceiver; 25 import android.content.ComponentCallbacks2; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.graphics.Bitmap; 29 import android.graphics.Canvas; 30 import android.graphics.Rect; 31 import android.graphics.Region.Op; 32 import android.opengl.GLUtils; 33 import android.os.SystemProperties; 34 import android.renderscript.Matrix4f; 35 import android.service.wallpaper.WallpaperService; 36 import android.util.Log; 37 import android.view.MotionEvent; 38 import android.view.SurfaceHolder; 39 import android.view.WindowManager; 40 41 import java.io.IOException; 42 import java.nio.ByteBuffer; 43 import java.nio.ByteOrder; 44 import java.nio.FloatBuffer; 45 46 import javax.microedition.khronos.egl.EGL10; 47 import javax.microedition.khronos.egl.EGLConfig; 48 import javax.microedition.khronos.egl.EGLContext; 49 import javax.microedition.khronos.egl.EGLDisplay; 50 import javax.microedition.khronos.egl.EGLSurface; 51 52 /** 53 * Default built-in wallpaper that simply shows a static image. 54 */ 55 @SuppressWarnings({"UnusedDeclaration"}) 56 public class ImageWallpaper extends WallpaperService { 57 private static final String TAG = "ImageWallpaper"; 58 private static final String GL_LOG_TAG = "ImageWallpaperGL"; 59 private static final boolean DEBUG = false; 60 private static final String PROPERTY_KERNEL_QEMU = "ro.kernel.qemu"; 61 62 static final boolean FIXED_SIZED_SURFACE = true; 63 static final boolean USE_OPENGL = true; 64 65 WallpaperManager mWallpaperManager; 66 67 DrawableEngine mEngine; 68 69 boolean mIsHwAccelerated; 70 71 @Override 72 public void onCreate() { 73 super.onCreate(); 74 mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE); 75 76 //noinspection PointlessBooleanExpression,ConstantConditions 77 if (FIXED_SIZED_SURFACE && USE_OPENGL) { 78 if (!isEmulator()) { 79 mIsHwAccelerated = ActivityManager.isHighEndGfx(); 80 } 81 } 82 } 83 84 @Override 85 public void onTrimMemory(int level) { 86 if (mEngine != null) { 87 mEngine.trimMemory(level); 88 } 89 } 90 91 private static boolean isEmulator() { 92 return "1".equals(SystemProperties.get(PROPERTY_KERNEL_QEMU, "0")); 93 } 94 95 @Override 96 public Engine onCreateEngine() { 97 mEngine = new DrawableEngine(); 98 return mEngine; 99 } 100 101 class DrawableEngine extends Engine { 102 static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 103 static final int EGL_OPENGL_ES2_BIT = 4; 104 105 // TODO: Not currently used, keeping around until we know we don't need it 106 @SuppressWarnings({"UnusedDeclaration"}) 107 private WallpaperObserver mReceiver; 108 109 Bitmap mBackground; 110 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1; 111 int mLastRotation = -1; 112 float mXOffset; 113 float mYOffset; 114 115 boolean mVisible = true; 116 boolean mRedrawNeeded; 117 boolean mOffsetsChanged; 118 int mLastXTranslation; 119 int mLastYTranslation; 120 121 private EGL10 mEgl; 122 private EGLDisplay mEglDisplay; 123 private EGLConfig mEglConfig; 124 private EGLContext mEglContext; 125 private EGLSurface mEglSurface; 126 127 private static final String sSimpleVS = 128 "attribute vec4 position;\n" + 129 "attribute vec2 texCoords;\n" + 130 "varying vec2 outTexCoords;\n" + 131 "uniform mat4 projection;\n" + 132 "\nvoid main(void) {\n" + 133 " outTexCoords = texCoords;\n" + 134 " gl_Position = projection * position;\n" + 135 "}\n\n"; 136 private static final String sSimpleFS = 137 "precision mediump float;\n\n" + 138 "varying vec2 outTexCoords;\n" + 139 "uniform sampler2D texture;\n" + 140 "\nvoid main(void) {\n" + 141 " gl_FragColor = texture2D(texture, outTexCoords);\n" + 142 "}\n\n"; 143 144 private static final int FLOAT_SIZE_BYTES = 4; 145 private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; 146 private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; 147 private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; 148 149 class WallpaperObserver extends BroadcastReceiver { 150 @Override 151 public void onReceive(Context context, Intent intent) { 152 if (DEBUG) { 153 Log.d(TAG, "onReceive"); 154 } 155 156 mLastSurfaceWidth = mLastSurfaceHeight = -1; 157 mBackground = null; 158 mRedrawNeeded = true; 159 drawFrame(); 160 } 161 } 162 163 public DrawableEngine() { 164 super(); 165 setFixedSizeAllowed(true); 166 } 167 168 public void trimMemory(int level) { 169 if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW && 170 mBackground != null && mIsHwAccelerated) { 171 if (DEBUG) { 172 Log.d(TAG, "trimMemory"); 173 } 174 mBackground.recycle(); 175 mBackground = null; 176 mWallpaperManager.forgetLoadedWallpaper(); 177 } 178 } 179 180 @Override 181 public void onCreate(SurfaceHolder surfaceHolder) { 182 if (DEBUG) { 183 Log.d(TAG, "onCreate"); 184 } 185 186 super.onCreate(surfaceHolder); 187 188 // TODO: Don't need this currently because the wallpaper service 189 // will restart the image wallpaper whenever the image changes. 190 //IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); 191 //mReceiver = new WallpaperObserver(); 192 //registerReceiver(mReceiver, filter, null, mHandler); 193 194 updateSurfaceSize(surfaceHolder); 195 196 setOffsetNotificationsEnabled(false); 197 } 198 199 @Override 200 public void onDestroy() { 201 super.onDestroy(); 202 if (mReceiver != null) { 203 unregisterReceiver(mReceiver); 204 } 205 } 206 207 @Override 208 public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) { 209 super.onDesiredSizeChanged(desiredWidth, desiredHeight); 210 SurfaceHolder surfaceHolder = getSurfaceHolder(); 211 if (surfaceHolder != null) { 212 updateSurfaceSize(surfaceHolder); 213 } 214 } 215 216 void updateSurfaceSize(SurfaceHolder surfaceHolder) { 217 if (FIXED_SIZED_SURFACE) { 218 // Used a fixed size surface, because we are special. We can do 219 // this because we know the current design of window animations doesn't 220 // cause this to break. 221 surfaceHolder.setFixedSize(getDesiredMinimumWidth(), getDesiredMinimumHeight()); 222 } else { 223 surfaceHolder.setSizeFromLayout(); 224 } 225 } 226 227 @Override 228 public void onVisibilityChanged(boolean visible) { 229 if (DEBUG) { 230 Log.d(TAG, "onVisibilityChanged: mVisible, visible=" + mVisible + ", " + visible); 231 } 232 233 if (mVisible != visible) { 234 if (DEBUG) { 235 Log.d(TAG, "Visibility changed to visible=" + visible); 236 } 237 mVisible = visible; 238 drawFrame(); 239 } 240 } 241 242 @Override 243 public void onTouchEvent(MotionEvent event) { 244 super.onTouchEvent(event); 245 } 246 247 @Override 248 public void onOffsetsChanged(float xOffset, float yOffset, 249 float xOffsetStep, float yOffsetStep, 250 int xPixels, int yPixels) { 251 if (DEBUG) { 252 Log.d(TAG, "onOffsetsChanged: xOffset=" + xOffset + ", yOffset=" + yOffset 253 + ", xOffsetStep=" + xOffsetStep + ", yOffsetStep=" + yOffsetStep 254 + ", xPixels=" + xPixels + ", yPixels=" + yPixels); 255 } 256 257 if (mXOffset != xOffset || mYOffset != yOffset) { 258 if (DEBUG) { 259 Log.d(TAG, "Offsets changed to (" + xOffset + "," + yOffset + ")."); 260 } 261 mXOffset = xOffset; 262 mYOffset = yOffset; 263 mOffsetsChanged = true; 264 } 265 drawFrame(); 266 } 267 268 @Override 269 public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { 270 if (DEBUG) { 271 Log.d(TAG, "onSurfaceChanged: width=" + width + ", height=" + height); 272 } 273 274 super.onSurfaceChanged(holder, format, width, height); 275 276 drawFrame(); 277 } 278 279 @Override 280 public void onSurfaceDestroyed(SurfaceHolder holder) { 281 super.onSurfaceDestroyed(holder); 282 mLastSurfaceWidth = mLastSurfaceHeight = -1; 283 } 284 285 @Override 286 public void onSurfaceCreated(SurfaceHolder holder) { 287 super.onSurfaceCreated(holder); 288 mLastSurfaceWidth = mLastSurfaceHeight = -1; 289 } 290 291 @Override 292 public void onSurfaceRedrawNeeded(SurfaceHolder holder) { 293 if (DEBUG) { 294 Log.d(TAG, "onSurfaceRedrawNeeded"); 295 } 296 super.onSurfaceRedrawNeeded(holder); 297 298 drawFrame(); 299 } 300 301 void drawFrame() { 302 SurfaceHolder sh = getSurfaceHolder(); 303 final Rect frame = sh.getSurfaceFrame(); 304 final int dw = frame.width(); 305 final int dh = frame.height(); 306 int newRotation = ((WindowManager) getSystemService(WINDOW_SERVICE)). 307 getDefaultDisplay().getRotation(); 308 boolean surfaceDimensionsChanged = dw != mLastSurfaceWidth || dh != mLastSurfaceHeight; 309 310 boolean redrawNeeded = surfaceDimensionsChanged || newRotation != mLastRotation; 311 if (!redrawNeeded && !mOffsetsChanged) { 312 if (DEBUG) { 313 Log.d(TAG, "Suppressed drawFrame since redraw is not needed " 314 + "and offsets have not changed."); 315 } 316 return; 317 } 318 mLastRotation = newRotation; 319 320 // Load bitmap if it is not yet loaded or if it was loaded at a different size 321 if (mBackground == null || surfaceDimensionsChanged) { 322 if (DEBUG) { 323 Log.d(TAG, "Reloading bitmap: mBackground, bgw, bgh, dw, dh = " + 324 mBackground + ", " + 325 ((mBackground == null) ? 0 : mBackground.getWidth()) + ", " + 326 ((mBackground == null) ? 0 : mBackground.getHeight()) + ", " + 327 dw + ", " + dh); 328 } 329 mWallpaperManager.forgetLoadedWallpaper(); 330 updateWallpaperLocked(); 331 if (mBackground == null) { 332 if (DEBUG) { 333 Log.d(TAG, "Unable to load bitmap"); 334 } 335 return; 336 } 337 if (DEBUG) { 338 if (dw != mBackground.getWidth() || dh != mBackground.getHeight()) { 339 Log.d(TAG, "Surface != bitmap dimensions: surface w/h, bitmap w/h: " + 340 dw + ", " + dh + ", " + mBackground.getWidth() + ", " + 341 mBackground.getHeight()); 342 } 343 } 344 } 345 346 final int availw = dw - mBackground.getWidth(); 347 final int availh = dh - mBackground.getHeight(); 348 int xPixels = availw < 0 ? (int)(availw * mXOffset + .5f) : (availw / 2); 349 int yPixels = availh < 0 ? (int)(availh * mYOffset + .5f) : (availh / 2); 350 351 mOffsetsChanged = false; 352 mRedrawNeeded = false; 353 if (surfaceDimensionsChanged) { 354 mLastSurfaceWidth = dw; 355 mLastSurfaceHeight = dh; 356 } 357 mLastXTranslation = xPixels; 358 mLastYTranslation = yPixels; 359 if (!redrawNeeded && xPixels == mLastXTranslation && yPixels == mLastYTranslation) { 360 if (DEBUG) { 361 Log.d(TAG, "Suppressed drawFrame since the image has not " 362 + "actually moved an integral number of pixels."); 363 } 364 return; 365 } 366 367 if (DEBUG) { 368 Log.d(TAG, "Redrawing wallpaper"); 369 } 370 371 if (mIsHwAccelerated) { 372 if (!drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels)) { 373 drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels); 374 } 375 } else { 376 drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels); 377 if (FIXED_SIZED_SURFACE) { 378 // If the surface is fixed-size, we should only need to 379 // draw it once and then we'll let the window manager 380 // position it appropriately. As such, we no longer needed 381 // the loaded bitmap. Yay! 382 // hw-accelerated path retains bitmap for faster rotation 383 mBackground = null; 384 mWallpaperManager.forgetLoadedWallpaper(); 385 } 386 } 387 388 } 389 390 private void updateWallpaperLocked() { 391 Throwable exception = null; 392 try { 393 mBackground = null; 394 mBackground = mWallpaperManager.getBitmap(); 395 } catch (RuntimeException e) { 396 exception = e; 397 } catch (OutOfMemoryError e) { 398 exception = e; 399 } 400 401 if (exception != null) { 402 mBackground = null; 403 // Note that if we do fail at this, and the default wallpaper can't 404 // be loaded, we will go into a cycle. Don't do a build where the 405 // default wallpaper can't be loaded. 406 Log.w(TAG, "Unable to load wallpaper!", exception); 407 try { 408 mWallpaperManager.clear(); 409 } catch (IOException ex) { 410 // now we're really screwed. 411 Log.w(TAG, "Unable reset to default wallpaper!", ex); 412 } 413 } 414 } 415 416 private void drawWallpaperWithCanvas(SurfaceHolder sh, int w, int h, int x, int y) { 417 Canvas c = sh.lockCanvas(); 418 if (c != null) { 419 try { 420 if (DEBUG) { 421 Log.d(TAG, "Redrawing: x=" + x + ", y=" + y); 422 } 423 424 c.translate(x, y); 425 if (w < 0 || h < 0) { 426 c.save(Canvas.CLIP_SAVE_FLAG); 427 c.clipRect(0, 0, mBackground.getWidth(), mBackground.getHeight(), 428 Op.DIFFERENCE); 429 c.drawColor(0xff000000); 430 c.restore(); 431 } 432 if (mBackground != null) { 433 c.drawBitmap(mBackground, 0, 0, null); 434 } 435 } finally { 436 sh.unlockCanvasAndPost(c); 437 } 438 } 439 } 440 441 private boolean drawWallpaperWithOpenGL(SurfaceHolder sh, int w, int h, int left, int top) { 442 if (!initGL(sh)) return false; 443 444 final float right = left + mBackground.getWidth(); 445 final float bottom = top + mBackground.getHeight(); 446 447 final Rect frame = sh.getSurfaceFrame(); 448 final Matrix4f ortho = new Matrix4f(); 449 ortho.loadOrtho(0.0f, frame.width(), frame.height(), 0.0f, -1.0f, 1.0f); 450 451 final FloatBuffer triangleVertices = createMesh(left, top, right, bottom); 452 453 final int texture = loadTexture(mBackground); 454 final int program = buildProgram(sSimpleVS, sSimpleFS); 455 456 final int attribPosition = glGetAttribLocation(program, "position"); 457 final int attribTexCoords = glGetAttribLocation(program, "texCoords"); 458 final int uniformTexture = glGetUniformLocation(program, "texture"); 459 final int uniformProjection = glGetUniformLocation(program, "projection"); 460 461 checkGlError(); 462 463 glViewport(0, 0, frame.width(), frame.height()); 464 glBindTexture(GL_TEXTURE_2D, texture); 465 466 glUseProgram(program); 467 glEnableVertexAttribArray(attribPosition); 468 glEnableVertexAttribArray(attribTexCoords); 469 glUniform1i(uniformTexture, 0); 470 glUniformMatrix4fv(uniformProjection, 1, false, ortho.getArray(), 0); 471 472 checkGlError(); 473 474 if (w < 0 || h < 0) { 475 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 476 glClear(GL_COLOR_BUFFER_BIT); 477 } 478 479 // drawQuad 480 triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); 481 glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false, 482 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); 483 484 triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); 485 glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false, 486 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); 487 488 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 489 490 boolean status = mEgl.eglSwapBuffers(mEglDisplay, mEglSurface); 491 checkEglError(); 492 493 finishGL(); 494 495 return status; 496 } 497 498 private FloatBuffer createMesh(int left, int top, float right, float bottom) { 499 final float[] verticesData = { 500 // X, Y, Z, U, V 501 left, bottom, 0.0f, 0.0f, 1.0f, 502 right, bottom, 0.0f, 1.0f, 1.0f, 503 left, top, 0.0f, 0.0f, 0.0f, 504 right, top, 0.0f, 1.0f, 0.0f, 505 }; 506 507 final int bytes = verticesData.length * FLOAT_SIZE_BYTES; 508 final FloatBuffer triangleVertices = ByteBuffer.allocateDirect(bytes).order( 509 ByteOrder.nativeOrder()).asFloatBuffer(); 510 triangleVertices.put(verticesData).position(0); 511 return triangleVertices; 512 } 513 514 private int loadTexture(Bitmap bitmap) { 515 int[] textures = new int[1]; 516 517 glActiveTexture(GL_TEXTURE0); 518 glGenTextures(1, textures, 0); 519 checkGlError(); 520 521 int texture = textures[0]; 522 glBindTexture(GL_TEXTURE_2D, texture); 523 checkGlError(); 524 525 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 526 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 527 528 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 529 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 530 531 GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0); 532 checkGlError(); 533 534 return texture; 535 } 536 537 private int buildProgram(String vertex, String fragment) { 538 int vertexShader = buildShader(vertex, GL_VERTEX_SHADER); 539 if (vertexShader == 0) return 0; 540 541 int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); 542 if (fragmentShader == 0) return 0; 543 544 int program = glCreateProgram(); 545 glAttachShader(program, vertexShader); 546 checkGlError(); 547 548 glAttachShader(program, fragmentShader); 549 checkGlError(); 550 551 glLinkProgram(program); 552 checkGlError(); 553 554 int[] status = new int[1]; 555 glGetProgramiv(program, GL_LINK_STATUS, status, 0); 556 if (status[0] != GL_TRUE) { 557 String error = glGetProgramInfoLog(program); 558 Log.d(GL_LOG_TAG, "Error while linking program:\n" + error); 559 glDeleteShader(vertexShader); 560 glDeleteShader(fragmentShader); 561 glDeleteProgram(program); 562 return 0; 563 } 564 565 return program; 566 } 567 568 private int buildShader(String source, int type) { 569 int shader = glCreateShader(type); 570 571 glShaderSource(shader, source); 572 checkGlError(); 573 574 glCompileShader(shader); 575 checkGlError(); 576 577 int[] status = new int[1]; 578 glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0); 579 if (status[0] != GL_TRUE) { 580 String error = glGetShaderInfoLog(shader); 581 Log.d(GL_LOG_TAG, "Error while compiling shader:\n" + error); 582 glDeleteShader(shader); 583 return 0; 584 } 585 586 return shader; 587 } 588 589 private void checkEglError() { 590 int error = mEgl.eglGetError(); 591 if (error != EGL_SUCCESS) { 592 Log.w(GL_LOG_TAG, "EGL error = " + GLUtils.getEGLErrorString(error)); 593 } 594 } 595 596 private void checkGlError() { 597 int error = glGetError(); 598 if (error != GL_NO_ERROR) { 599 Log.w(GL_LOG_TAG, "GL error = 0x" + Integer.toHexString(error), new Throwable()); 600 } 601 } 602 603 private void finishGL() { 604 mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 605 mEgl.eglDestroySurface(mEglDisplay, mEglSurface); 606 mEgl.eglDestroyContext(mEglDisplay, mEglContext); 607 mEgl.eglTerminate(mEglDisplay); 608 } 609 610 private boolean initGL(SurfaceHolder surfaceHolder) { 611 mEgl = (EGL10) EGLContext.getEGL(); 612 613 mEglDisplay = mEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY); 614 if (mEglDisplay == EGL_NO_DISPLAY) { 615 throw new RuntimeException("eglGetDisplay failed " + 616 GLUtils.getEGLErrorString(mEgl.eglGetError())); 617 } 618 619 int[] version = new int[2]; 620 if (!mEgl.eglInitialize(mEglDisplay, version)) { 621 throw new RuntimeException("eglInitialize failed " + 622 GLUtils.getEGLErrorString(mEgl.eglGetError())); 623 } 624 625 mEglConfig = chooseEglConfig(); 626 if (mEglConfig == null) { 627 throw new RuntimeException("eglConfig not initialized"); 628 } 629 630 mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); 631 if (mEglContext == EGL_NO_CONTEXT) { 632 throw new RuntimeException("createContext failed " + 633 GLUtils.getEGLErrorString(mEgl.eglGetError())); 634 } 635 636 int attribs[] = { 637 EGL_WIDTH, 1, 638 EGL_HEIGHT, 1, 639 EGL_NONE 640 }; 641 EGLSurface tmpSurface = mEgl.eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs); 642 mEgl.eglMakeCurrent(mEglDisplay, tmpSurface, tmpSurface, mEglContext); 643 644 int[] maxSize = new int[1]; 645 Rect frame = surfaceHolder.getSurfaceFrame(); 646 glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxSize, 0); 647 648 mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 649 mEgl.eglDestroySurface(mEglDisplay, tmpSurface); 650 651 if(frame.width() > maxSize[0] || frame.height() > maxSize[0]) { 652 mEgl.eglDestroyContext(mEglDisplay, mEglContext); 653 mEgl.eglTerminate(mEglDisplay); 654 Log.e(GL_LOG_TAG, "requested texture size " + 655 frame.width() + "x" + frame.height() + " exceeds the support maximum of " + 656 maxSize[0] + "x" + maxSize[0]); 657 return false; 658 } 659 660 mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null); 661 if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) { 662 int error = mEgl.eglGetError(); 663 if (error == EGL_BAD_NATIVE_WINDOW || error == EGL_BAD_ALLOC) { 664 Log.e(GL_LOG_TAG, "createWindowSurface returned " + 665 GLUtils.getEGLErrorString(error) + "."); 666 return false; 667 } 668 throw new RuntimeException("createWindowSurface failed " + 669 GLUtils.getEGLErrorString(error)); 670 } 671 672 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 673 throw new RuntimeException("eglMakeCurrent failed " + 674 GLUtils.getEGLErrorString(mEgl.eglGetError())); 675 } 676 677 return true; 678 } 679 680 681 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { 682 int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 683 return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list); 684 } 685 686 private EGLConfig chooseEglConfig() { 687 int[] configsCount = new int[1]; 688 EGLConfig[] configs = new EGLConfig[1]; 689 int[] configSpec = getConfig(); 690 if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) { 691 throw new IllegalArgumentException("eglChooseConfig failed " + 692 GLUtils.getEGLErrorString(mEgl.eglGetError())); 693 } else if (configsCount[0] > 0) { 694 return configs[0]; 695 } 696 return null; 697 } 698 699 private int[] getConfig() { 700 return new int[] { 701 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 702 EGL_RED_SIZE, 8, 703 EGL_GREEN_SIZE, 8, 704 EGL_BLUE_SIZE, 8, 705 EGL_ALPHA_SIZE, 0, 706 EGL_DEPTH_SIZE, 0, 707 EGL_STENCIL_SIZE, 0, 708 EGL_CONFIG_CAVEAT, EGL_NONE, 709 EGL_NONE 710 }; 711 } 712 } 713 } 714