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