blob: 74483cc4654755da02b9c6e0fae71cca8d31e181 [file] [log] [blame]
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001/*
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
Dianne Hackbornba398392011-08-01 16:11:57 -070017package com.android.systemui;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070018
John Spurlockde84f0e2013-06-12 12:41:00 -040019import static android.opengl.GLES20.*;
20import static javax.microedition.khronos.egl.EGL10.*;
21
Romain Guy407ec782011-08-24 17:06:58 -070022import android.app.ActivityManager;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070023import android.app.WallpaperManager;
Romain Guy407ec782011-08-24 17:06:58 -070024import android.content.BroadcastReceiver;
Chet Haasec61d70e2012-10-10 15:41:57 -070025import android.content.ComponentCallbacks2;
Romain Guy407ec782011-08-24 17:06:58 -070026import android.content.Context;
27import android.content.Intent;
28import android.graphics.Bitmap;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070029import android.graphics.Canvas;
Michael Jurka824a4b52013-12-18 17:10:16 +010030import android.graphics.Point;
Dianne Hackborn759a39e2009-08-09 17:20:27 -070031import android.graphics.Rect;
Michael Jurka824a4b52013-12-18 17:10:16 +010032import android.graphics.RectF;
Mathias Agopiane2d034c2009-09-23 21:06:17 -070033import android.graphics.Region.Op;
Romain Guy407ec782011-08-24 17:06:58 -070034import android.opengl.GLUtils;
Romain Guy043a6b12011-09-27 15:37:54 -070035import android.os.SystemProperties;
Romain Guy407ec782011-08-24 17:06:58 -070036import android.renderscript.Matrix4f;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070037import android.service.wallpaper.WallpaperService;
Dianne Hackbornc9dbbe22009-11-11 22:50:37 -080038import android.util.Log;
Michael Jurka824a4b52013-12-18 17:10:16 +010039import android.view.Display;
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -070040import android.view.MotionEvent;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070041import android.view.SurfaceHolder;
Chet Haase2f200812012-10-11 12:49:08 -070042import android.view.WindowManager;
Romain Guy407ec782011-08-24 17:06:58 -070043
Romain Guy407ec782011-08-24 17:06:58 -070044import java.io.IOException;
45import java.nio.ByteBuffer;
46import java.nio.ByteOrder;
47import java.nio.FloatBuffer;
48
John Spurlockde84f0e2013-06-12 12:41:00 -040049import javax.microedition.khronos.egl.EGL10;
50import javax.microedition.khronos.egl.EGLConfig;
51import javax.microedition.khronos.egl.EGLContext;
52import javax.microedition.khronos.egl.EGLDisplay;
53import javax.microedition.khronos.egl.EGLSurface;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070054
55/**
56 * Default built-in wallpaper that simply shows a static image.
57 */
Romain Guy407ec782011-08-24 17:06:58 -070058@SuppressWarnings({"UnusedDeclaration"})
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070059public class ImageWallpaper extends WallpaperService {
Jeff Brownfa2e5042011-01-23 13:14:23 -080060 private static final String TAG = "ImageWallpaper";
Romain Guy407ec782011-08-24 17:06:58 -070061 private static final String GL_LOG_TAG = "ImageWallpaperGL";
Jeff Brownfa2e5042011-01-23 13:14:23 -080062 private static final boolean DEBUG = false;
Romain Guy043a6b12011-09-27 15:37:54 -070063 private static final String PROPERTY_KERNEL_QEMU = "ro.kernel.qemu";
Jeff Brownfa2e5042011-01-23 13:14:23 -080064
Dianne Hackbornba398392011-08-01 16:11:57 -070065 static final boolean FIXED_SIZED_SURFACE = true;
Erik Gilling881fb202011-08-25 10:27:52 -070066 static final boolean USE_OPENGL = true;
Dianne Hackbornba398392011-08-01 16:11:57 -070067
Romain Guyef654bd2009-08-11 19:12:17 -070068 WallpaperManager mWallpaperManager;
Romain Guy407ec782011-08-24 17:06:58 -070069
Chet Haasec61d70e2012-10-10 15:41:57 -070070 DrawableEngine mEngine;
71
Romain Guy407ec782011-08-24 17:06:58 -070072 boolean mIsHwAccelerated;
Dianne Hackborn759a39e2009-08-09 17:20:27 -070073
Romain Guyef654bd2009-08-11 19:12:17 -070074 @Override
75 public void onCreate() {
76 super.onCreate();
77 mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
Romain Guy407ec782011-08-24 17:06:58 -070078
79 //noinspection PointlessBooleanExpression,ConstantConditions
80 if (FIXED_SIZED_SURFACE && USE_OPENGL) {
Romain Guy043a6b12011-09-27 15:37:54 -070081 if (!isEmulator()) {
Jeff Brown98365d72012-08-19 20:30:52 -070082 mIsHwAccelerated = ActivityManager.isHighEndGfx();
Romain Guy043a6b12011-09-27 15:37:54 -070083 }
Romain Guy407ec782011-08-24 17:06:58 -070084 }
Romain Guyef654bd2009-08-11 19:12:17 -070085 }
86
Chet Haasec61d70e2012-10-10 15:41:57 -070087 @Override
88 public void onTrimMemory(int level) {
89 if (mEngine != null) {
90 mEngine.trimMemory(level);
91 }
92 }
93
Romain Guy043a6b12011-09-27 15:37:54 -070094 private static boolean isEmulator() {
95 return "1".equals(SystemProperties.get(PROPERTY_KERNEL_QEMU, "0"));
96 }
97
Craig Mautnerb1ef3692012-11-16 17:31:04 -080098 @Override
Romain Guyef654bd2009-08-11 19:12:17 -070099 public Engine onCreateEngine() {
Chet Haasec61d70e2012-10-10 15:41:57 -0700100 mEngine = new DrawableEngine();
101 return mEngine;
Romain Guyef654bd2009-08-11 19:12:17 -0700102 }
103
104 class DrawableEngine extends Engine {
Romain Guy407ec782011-08-24 17:06:58 -0700105 static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
106 static final int EGL_OPENGL_ES2_BIT = 4;
107
Romain Guy407ec782011-08-24 17:06:58 -0700108 // TODO: Not currently used, keeping around until we know we don't need it
109 @SuppressWarnings({"UnusedDeclaration"})
Dianne Hackborn284ac932009-08-28 10:34:25 -0700110 private WallpaperObserver mReceiver;
Romain Guy407ec782011-08-24 17:06:58 -0700111
112 Bitmap mBackground;
Michael Jurka824a4b52013-12-18 17:10:16 +0100113 int mBackgroundWidth = -1, mBackgroundHeight = -1;
Chet Haase5f0d9762012-10-18 12:01:34 -0700114 int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
Chet Haase2f200812012-10-11 12:49:08 -0700115 int mLastRotation = -1;
Michael Jurka824a4b52013-12-18 17:10:16 +0100116 float mXOffset = 0.5f;
117 float mYOffset = 0.5f;
118 float mScale = 1f;
Romain Guyef654bd2009-08-11 19:12:17 -0700119
Jeff Brownfa2e5042011-01-23 13:14:23 -0800120 boolean mVisible = true;
121 boolean mRedrawNeeded;
122 boolean mOffsetsChanged;
123 int mLastXTranslation;
124 int mLastYTranslation;
125
Romain Guy407ec782011-08-24 17:06:58 -0700126 private EGL10 mEgl;
127 private EGLDisplay mEglDisplay;
128 private EGLConfig mEglConfig;
129 private EGLContext mEglContext;
130 private EGLSurface mEglSurface;
Romain Guy407ec782011-08-24 17:06:58 -0700131
132 private static final String sSimpleVS =
133 "attribute vec4 position;\n" +
134 "attribute vec2 texCoords;\n" +
135 "varying vec2 outTexCoords;\n" +
136 "uniform mat4 projection;\n" +
137 "\nvoid main(void) {\n" +
138 " outTexCoords = texCoords;\n" +
139 " gl_Position = projection * position;\n" +
140 "}\n\n";
141 private static final String sSimpleFS =
142 "precision mediump float;\n\n" +
143 "varying vec2 outTexCoords;\n" +
144 "uniform sampler2D texture;\n" +
145 "\nvoid main(void) {\n" +
146 " gl_FragColor = texture2D(texture, outTexCoords);\n" +
147 "}\n\n";
John Spurlock209bede2013-07-17 12:23:27 -0400148
Romain Guy407ec782011-08-24 17:06:58 -0700149 private static final int FLOAT_SIZE_BYTES = 4;
150 private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
151 private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
152 private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
153
Dianne Hackborn284ac932009-08-28 10:34:25 -0700154 class WallpaperObserver extends BroadcastReceiver {
Craig Mautnerb1ef3692012-11-16 17:31:04 -0800155 @Override
Dianne Hackborn284ac932009-08-28 10:34:25 -0700156 public void onReceive(Context context, Intent intent) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800157 if (DEBUG) {
158 Log.d(TAG, "onReceive");
159 }
160
Craig Mautnerb1ef3692012-11-16 17:31:04 -0800161 mLastSurfaceWidth = mLastSurfaceHeight = -1;
162 mBackground = null;
Michael Jurka824a4b52013-12-18 17:10:16 +0100163 mBackgroundWidth = -1;
164 mBackgroundHeight = -1;
Craig Mautnerb1ef3692012-11-16 17:31:04 -0800165 mRedrawNeeded = true;
166 drawFrame();
Dianne Hackborn284ac932009-08-28 10:34:25 -0700167 }
168 }
169
Jeff Sharkey35be7562012-04-18 19:16:15 -0700170 public DrawableEngine() {
171 super();
172 setFixedSizeAllowed(true);
173 }
174
Chet Haasec61d70e2012-10-10 15:41:57 -0700175 public void trimMemory(int level) {
176 if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW &&
177 mBackground != null && mIsHwAccelerated) {
Chet Haase5f0d9762012-10-18 12:01:34 -0700178 if (DEBUG) {
179 Log.d(TAG, "trimMemory");
180 }
Chet Haasec61d70e2012-10-10 15:41:57 -0700181 mBackground.recycle();
182 mBackground = null;
Michael Jurka824a4b52013-12-18 17:10:16 +0100183 mBackgroundWidth = -1;
184 mBackgroundHeight = -1;
Chet Haasec61d70e2012-10-10 15:41:57 -0700185 mWallpaperManager.forgetLoadedWallpaper();
186 }
187 }
188
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700189 @Override
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700190 public void onCreate(SurfaceHolder surfaceHolder) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800191 if (DEBUG) {
192 Log.d(TAG, "onCreate");
193 }
194
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700195 super.onCreate(surfaceHolder);
John Spurlock209bede2013-07-17 12:23:27 -0400196
Romain Guy407ec782011-08-24 17:06:58 -0700197 // TODO: Don't need this currently because the wallpaper service
Dianne Hackborn9ea31632011-08-05 14:43:50 -0700198 // will restart the image wallpaper whenever the image changes.
199 //IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
200 //mReceiver = new WallpaperObserver();
201 //registerReceiver(mReceiver, filter, null, mHandler);
Jeff Brownfa2e5042011-01-23 13:14:23 -0800202
Dianne Hackbornac1471a2011-02-03 13:46:06 -0800203 updateSurfaceSize(surfaceHolder);
Chet Haasea8e5a2b2011-10-28 13:18:16 -0700204
205 setOffsetNotificationsEnabled(false);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700206 }
207
208 @Override
Dianne Hackborn284ac932009-08-28 10:34:25 -0700209 public void onDestroy() {
210 super.onDestroy();
Dianne Hackborn9ea31632011-08-05 14:43:50 -0700211 if (mReceiver != null) {
212 unregisterReceiver(mReceiver);
213 }
Dianne Hackborn284ac932009-08-28 10:34:25 -0700214 }
215
Dianne Hackbornac1471a2011-02-03 13:46:06 -0800216 void updateSurfaceSize(SurfaceHolder surfaceHolder) {
Michael Jurka824a4b52013-12-18 17:10:16 +0100217 Point p = getDefaultDisplaySize();
218
219 // Load background image dimensions, if we haven't saved them yet
220 if (mBackgroundWidth <= 0 || mBackgroundHeight <= 0) {
221 // Need to load the image to get dimensions
222 mWallpaperManager.forgetLoadedWallpaper();
223 updateWallpaperLocked();
224 if (mBackgroundWidth <= 0 || mBackgroundHeight <= 0) {
225 // Default to the display size if we can't find the dimensions
226 mBackgroundWidth = p.x;
227 mBackgroundHeight = p.y;
228 }
229 }
230
231 // Force the wallpaper to cover the screen in both dimensions
232 int surfaceWidth = Math.max(p.x, mBackgroundWidth);
233 int surfaceHeight = Math.max(p.y, mBackgroundHeight);
234
235 // If the surface dimensions haven't changed, then just return
236 final Rect frame = surfaceHolder.getSurfaceFrame();
237 if (frame != null) {
238 final int dw = frame.width();
239 final int dh = frame.height();
240 if (surfaceWidth == dw && surfaceHeight == dh) {
241 return;
242 }
243 }
244
Dianne Hackbornba398392011-08-01 16:11:57 -0700245 if (FIXED_SIZED_SURFACE) {
246 // Used a fixed size surface, because we are special. We can do
247 // this because we know the current design of window animations doesn't
248 // cause this to break.
Michael Jurka824a4b52013-12-18 17:10:16 +0100249 surfaceHolder.setFixedSize(surfaceWidth, surfaceHeight);
Dianne Hackbornba398392011-08-01 16:11:57 -0700250 } else {
251 surfaceHolder.setSizeFromLayout();
252 }
Dianne Hackbornac1471a2011-02-03 13:46:06 -0800253 }
254
255 @Override
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700256 public void onVisibilityChanged(boolean visible) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800257 if (DEBUG) {
Chet Haase2f200812012-10-11 12:49:08 -0700258 Log.d(TAG, "onVisibilityChanged: mVisible, visible=" + mVisible + ", " + visible);
Jeff Brown30bc34f2011-01-25 12:56:56 -0800259 }
260
Craig Mautnerb1ef3692012-11-16 17:31:04 -0800261 if (mVisible != visible) {
262 if (DEBUG) {
263 Log.d(TAG, "Visibility changed to visible=" + visible);
Jeff Brown30bc34f2011-01-25 12:56:56 -0800264 }
Craig Mautnerb1ef3692012-11-16 17:31:04 -0800265 mVisible = visible;
266 drawFrame();
Jeff Brownfa2e5042011-01-23 13:14:23 -0800267 }
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700268 }
Jeff Brownfa2e5042011-01-23 13:14:23 -0800269
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700270 @Override
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -0700271 public void onTouchEvent(MotionEvent event) {
272 super.onTouchEvent(event);
Dianne Hackborn8df8b2b2009-08-17 15:15:18 -0700273 }
274
275 @Override
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700276 public void onOffsetsChanged(float xOffset, float yOffset,
Marco Nelissenbf6956b2009-11-09 15:21:13 -0800277 float xOffsetStep, float yOffsetStep,
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700278 int xPixels, int yPixels) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800279 if (DEBUG) {
280 Log.d(TAG, "onOffsetsChanged: xOffset=" + xOffset + ", yOffset=" + yOffset
281 + ", xOffsetStep=" + xOffsetStep + ", yOffsetStep=" + yOffsetStep
282 + ", xPixels=" + xPixels + ", yPixels=" + yPixels);
283 }
284
Craig Mautnerb1ef3692012-11-16 17:31:04 -0800285 if (mXOffset != xOffset || mYOffset != yOffset) {
286 if (DEBUG) {
287 Log.d(TAG, "Offsets changed to (" + xOffset + "," + yOffset + ").");
Jeff Brownfa2e5042011-01-23 13:14:23 -0800288 }
Craig Mautnerb1ef3692012-11-16 17:31:04 -0800289 mXOffset = xOffset;
290 mYOffset = yOffset;
291 mOffsetsChanged = true;
Jeff Brownfa2e5042011-01-23 13:14:23 -0800292 }
Craig Mautnerb1ef3692012-11-16 17:31:04 -0800293 drawFrame();
Dianne Hackborn72c82ab2009-08-11 21:13:54 -0700294 }
295
296 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700297 public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Jeff Brown30bc34f2011-01-25 12:56:56 -0800298 if (DEBUG) {
299 Log.d(TAG, "onSurfaceChanged: width=" + width + ", height=" + height);
300 }
301
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700302 super.onSurfaceChanged(holder, format, width, height);
Jeff Brown30bc34f2011-01-25 12:56:56 -0800303
Craig Mautnerb1ef3692012-11-16 17:31:04 -0800304 drawFrame();
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700305 }
306
Craig Mautnerfb729c72012-10-01 09:39:43 -0700307 @Override
Chet Haase2f200812012-10-11 12:49:08 -0700308 public void onSurfaceDestroyed(SurfaceHolder holder) {
309 super.onSurfaceDestroyed(holder);
Chet Haase5f0d9762012-10-18 12:01:34 -0700310 mLastSurfaceWidth = mLastSurfaceHeight = -1;
Chet Haase2f200812012-10-11 12:49:08 -0700311 }
312
313 @Override
314 public void onSurfaceCreated(SurfaceHolder holder) {
315 super.onSurfaceCreated(holder);
Chet Haase5f0d9762012-10-18 12:01:34 -0700316 mLastSurfaceWidth = mLastSurfaceHeight = -1;
Chet Haase2f200812012-10-11 12:49:08 -0700317 }
318
319 @Override
Craig Mautnerfb729c72012-10-01 09:39:43 -0700320 public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
321 if (DEBUG) {
Chet Haase2f200812012-10-11 12:49:08 -0700322 Log.d(TAG, "onSurfaceRedrawNeeded");
Craig Mautnerfb729c72012-10-01 09:39:43 -0700323 }
324 super.onSurfaceRedrawNeeded(holder);
325
Craig Mautnerb1ef3692012-11-16 17:31:04 -0800326 drawFrame();
Craig Mautnerfb729c72012-10-01 09:39:43 -0700327 }
328
Michael Jurka824a4b52013-12-18 17:10:16 +0100329 private Point getDefaultDisplaySize() {
330 Point p = new Point();
331 Context c = ImageWallpaper.this.getApplicationContext();
332 WindowManager wm = (WindowManager)c.getSystemService(Context.WINDOW_SERVICE);
333 Display d = wm.getDefaultDisplay();
334 d.getRealSize(p);
335 return p;
336 }
337
Craig Mautnerb1ef3692012-11-16 17:31:04 -0800338 void drawFrame() {
Michael Jurka824a4b52013-12-18 17:10:16 +0100339 int newRotation = ((WindowManager) getSystemService(WINDOW_SERVICE)).
340 getDefaultDisplay().getRotation();
341
342 // Sometimes a wallpaper is not large enough to cover the screen in one dimension.
343 // Call updateSurfaceSize -- it will only actually do the update if the dimensions
344 // should change
345 if (newRotation != mLastRotation) {
346 // Update surface size (if necessary)
347 updateSurfaceSize(getSurfaceHolder());
348 }
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700349 SurfaceHolder sh = getSurfaceHolder();
Jeff Brown033f63a2011-01-23 22:01:49 -0800350 final Rect frame = sh.getSurfaceFrame();
Jeff Brown033f63a2011-01-23 22:01:49 -0800351 final int dw = frame.width();
352 final int dh = frame.height();
Chet Haase5f0d9762012-10-18 12:01:34 -0700353 boolean surfaceDimensionsChanged = dw != mLastSurfaceWidth || dh != mLastSurfaceHeight;
Chet Haase2f200812012-10-11 12:49:08 -0700354
Chet Haase5f0d9762012-10-18 12:01:34 -0700355 boolean redrawNeeded = surfaceDimensionsChanged || newRotation != mLastRotation;
Chet Haase2f200812012-10-11 12:49:08 -0700356 if (!redrawNeeded && !mOffsetsChanged) {
357 if (DEBUG) {
358 Log.d(TAG, "Suppressed drawFrame since redraw is not needed "
359 + "and offsets have not changed.");
360 }
361 return;
362 }
363 mLastRotation = newRotation;
364
365 // Load bitmap if it is not yet loaded or if it was loaded at a different size
Chet Haase5f0d9762012-10-18 12:01:34 -0700366 if (mBackground == null || surfaceDimensionsChanged) {
Chet Haase2f200812012-10-11 12:49:08 -0700367 if (DEBUG) {
Chet Haase5f0d9762012-10-18 12:01:34 -0700368 Log.d(TAG, "Reloading bitmap: mBackground, bgw, bgh, dw, dh = " +
369 mBackground + ", " +
370 ((mBackground == null) ? 0 : mBackground.getWidth()) + ", " +
371 ((mBackground == null) ? 0 : mBackground.getHeight()) + ", " +
372 dw + ", " + dh);
Chet Haase2f200812012-10-11 12:49:08 -0700373 }
Michael Wrightb9fca992013-10-15 12:49:44 -0700374 mWallpaperManager.forgetLoadedWallpaper();
Chet Haase2f200812012-10-11 12:49:08 -0700375 updateWallpaperLocked();
Chet Haase5f0d9762012-10-18 12:01:34 -0700376 if (mBackground == null) {
377 if (DEBUG) {
378 Log.d(TAG, "Unable to load bitmap");
379 }
380 return;
381 }
382 if (DEBUG) {
383 if (dw != mBackground.getWidth() || dh != mBackground.getHeight()) {
384 Log.d(TAG, "Surface != bitmap dimensions: surface w/h, bitmap w/h: " +
385 dw + ", " + dh + ", " + mBackground.getWidth() + ", " +
386 mBackground.getHeight());
387 }
388 }
Chet Haase2f200812012-10-11 12:49:08 -0700389 }
390
Michael Jurka824a4b52013-12-18 17:10:16 +0100391 // Center the scaled image
392 mScale = Math.max(1f, Math.max(dw / (float) mBackground.getWidth(),
393 dh / (float) mBackground.getHeight()));
394 final int availw = dw - (int) (mBackground.getWidth() * mScale);
395 final int availh = dh - (int) (mBackground.getHeight() * mScale);
396 int xPixels = availw / 2;
397 int yPixels = availh / 2;
398
399 // Adjust the image for xOffset/yOffset values. If window manager is handling offsets,
400 // mXOffset and mYOffset are set to 0.5f by default and therefore xPixels and yPixels
401 // will remain unchanged
402 final int availwUnscaled = dw - mBackground.getWidth();
403 final int availhUnscaled = dh - mBackground.getHeight();
404 if (availwUnscaled < 0) xPixels += (int)(availwUnscaled * (mXOffset - .5f) + .5f);
405 if (availhUnscaled < 0) yPixels += (int)(availhUnscaled * (mYOffset - .5f) + .5f);
Jeff Brown033f63a2011-01-23 22:01:49 -0800406
407 mOffsetsChanged = false;
Chet Haase2f200812012-10-11 12:49:08 -0700408 mRedrawNeeded = false;
Chet Haase5f0d9762012-10-18 12:01:34 -0700409 if (surfaceDimensionsChanged) {
410 mLastSurfaceWidth = dw;
411 mLastSurfaceHeight = dh;
412 }
Chet Haase2f200812012-10-11 12:49:08 -0700413 if (!redrawNeeded && xPixels == mLastXTranslation && yPixels == mLastYTranslation) {
Jeff Brown033f63a2011-01-23 22:01:49 -0800414 if (DEBUG) {
415 Log.d(TAG, "Suppressed drawFrame since the image has not "
416 + "actually moved an integral number of pixels.");
417 }
418 return;
419 }
Michael Jurka824a4b52013-12-18 17:10:16 +0100420 mLastXTranslation = xPixels;
421 mLastYTranslation = yPixels;
Jeff Brown033f63a2011-01-23 22:01:49 -0800422
Craig Mautnerc92f1502012-10-13 15:40:28 -0700423 if (DEBUG) {
Chet Haase2f200812012-10-11 12:49:08 -0700424 Log.d(TAG, "Redrawing wallpaper");
Craig Mautnerc92f1502012-10-13 15:40:28 -0700425 }
Wim Vander Schelden9549c062013-02-07 15:51:51 +0000426
Romain Guy407ec782011-08-24 17:06:58 -0700427 if (mIsHwAccelerated) {
Romain Guyf9296292011-08-25 17:00:39 -0700428 if (!drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels)) {
429 drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
430 }
Romain Guy407ec782011-08-24 17:06:58 -0700431 } else {
432 drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
Chet Haasec61d70e2012-10-10 15:41:57 -0700433 if (FIXED_SIZED_SURFACE) {
434 // If the surface is fixed-size, we should only need to
435 // draw it once and then we'll let the window manager
436 // position it appropriately. As such, we no longer needed
437 // the loaded bitmap. Yay!
438 // hw-accelerated path retains bitmap for faster rotation
439 mBackground = null;
440 mWallpaperManager.forgetLoadedWallpaper();
441 }
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700442 }
Dianne Hackbornba398392011-08-01 16:11:57 -0700443
Dianne Hackborn759a39e2009-08-09 17:20:27 -0700444 }
Romain Guyef654bd2009-08-11 19:12:17 -0700445
Chet Haase5f0d9762012-10-18 12:01:34 -0700446 private void updateWallpaperLocked() {
Jeff Brownfa2e5042011-01-23 13:14:23 -0800447 Throwable exception = null;
448 try {
Chet Haase589a6af2012-10-24 17:37:00 -0700449 mBackground = null;
Michael Jurka824a4b52013-12-18 17:10:16 +0100450 mBackgroundWidth = -1;
451 mBackgroundHeight = -1;
Romain Guy407ec782011-08-24 17:06:58 -0700452 mBackground = mWallpaperManager.getBitmap();
Michael Jurka824a4b52013-12-18 17:10:16 +0100453 mBackgroundWidth = mBackground.getWidth();
454 mBackgroundHeight = mBackground.getHeight();
Jeff Brownfa2e5042011-01-23 13:14:23 -0800455 } catch (RuntimeException e) {
456 exception = e;
457 } catch (OutOfMemoryError e) {
458 exception = e;
459 }
Romain Guy407ec782011-08-24 17:06:58 -0700460
Jeff Brownfa2e5042011-01-23 13:14:23 -0800461 if (exception != null) {
462 mBackground = null;
Michael Jurka824a4b52013-12-18 17:10:16 +0100463 mBackgroundWidth = -1;
464 mBackgroundHeight = -1;
Jeff Brownfa2e5042011-01-23 13:14:23 -0800465 // Note that if we do fail at this, and the default wallpaper can't
466 // be loaded, we will go into a cycle. Don't do a build where the
467 // default wallpaper can't be loaded.
468 Log.w(TAG, "Unable to load wallpaper!", exception);
Dianne Hackbornc9dbbe22009-11-11 22:50:37 -0800469 try {
Jeff Brownfa2e5042011-01-23 13:14:23 -0800470 mWallpaperManager.clear();
471 } catch (IOException ex) {
472 // now we're really screwed.
473 Log.w(TAG, "Unable reset to default wallpaper!", ex);
Dianne Hackbornc9dbbe22009-11-11 22:50:37 -0800474 }
Romain Guyef654bd2009-08-11 19:12:17 -0700475 }
Romain Guy407ec782011-08-24 17:06:58 -0700476 }
477
Michael Jurka824a4b52013-12-18 17:10:16 +0100478 private void drawWallpaperWithCanvas(SurfaceHolder sh, int w, int h, int left, int top) {
Romain Guy407ec782011-08-24 17:06:58 -0700479 Canvas c = sh.lockCanvas();
480 if (c != null) {
481 try {
482 if (DEBUG) {
Michael Jurka824a4b52013-12-18 17:10:16 +0100483 Log.d(TAG, "Redrawing: left=" + left + ", top=" + top);
Romain Guy407ec782011-08-24 17:06:58 -0700484 }
485
Michael Jurka824a4b52013-12-18 17:10:16 +0100486 final float right = left + mBackground.getWidth() * mScale;
487 final float bottom = top + mBackground.getHeight() * mScale;
Romain Guy407ec782011-08-24 17:06:58 -0700488 if (w < 0 || h < 0) {
489 c.save(Canvas.CLIP_SAVE_FLAG);
Michael Jurka824a4b52013-12-18 17:10:16 +0100490 c.clipRect(left, top, right, bottom,
Chet Haase5f0d9762012-10-18 12:01:34 -0700491 Op.DIFFERENCE);
Romain Guy407ec782011-08-24 17:06:58 -0700492 c.drawColor(0xff000000);
493 c.restore();
494 }
495 if (mBackground != null) {
Michael Jurka824a4b52013-12-18 17:10:16 +0100496 RectF dest = new RectF(left, top, right, bottom);
497 // add a filter bitmap?
498 c.drawBitmap(mBackground, null, dest, null);
Romain Guy407ec782011-08-24 17:06:58 -0700499 }
500 } finally {
501 sh.unlockCanvasAndPost(c);
502 }
503 }
504 }
505
Romain Guyf9296292011-08-25 17:00:39 -0700506 private boolean drawWallpaperWithOpenGL(SurfaceHolder sh, int w, int h, int left, int top) {
507 if (!initGL(sh)) return false;
Romain Guy407ec782011-08-24 17:06:58 -0700508
Michael Jurka824a4b52013-12-18 17:10:16 +0100509 final float right = left + mBackground.getWidth() * mScale;
510 final float bottom = top + mBackground.getHeight() * mScale;
Romain Guy407ec782011-08-24 17:06:58 -0700511
512 final Rect frame = sh.getSurfaceFrame();
Romain Guy407ec782011-08-24 17:06:58 -0700513 final Matrix4f ortho = new Matrix4f();
514 ortho.loadOrtho(0.0f, frame.width(), frame.height(), 0.0f, -1.0f, 1.0f);
515
516 final FloatBuffer triangleVertices = createMesh(left, top, right, bottom);
517
518 final int texture = loadTexture(mBackground);
519 final int program = buildProgram(sSimpleVS, sSimpleFS);
Chet Haase2f200812012-10-11 12:49:08 -0700520
Romain Guy407ec782011-08-24 17:06:58 -0700521 final int attribPosition = glGetAttribLocation(program, "position");
522 final int attribTexCoords = glGetAttribLocation(program, "texCoords");
523 final int uniformTexture = glGetUniformLocation(program, "texture");
524 final int uniformProjection = glGetUniformLocation(program, "projection");
525
526 checkGlError();
527
528 glViewport(0, 0, frame.width(), frame.height());
529 glBindTexture(GL_TEXTURE_2D, texture);
530
531 glUseProgram(program);
532 glEnableVertexAttribArray(attribPosition);
533 glEnableVertexAttribArray(attribTexCoords);
534 glUniform1i(uniformTexture, 0);
535 glUniformMatrix4fv(uniformProjection, 1, false, ortho.getArray(), 0);
536
537 checkGlError();
538
Michael Wright6762a442013-10-15 14:43:32 -0700539 if (w > 0 || h > 0) {
Romain Guy407ec782011-08-24 17:06:58 -0700540 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
541 glClear(GL_COLOR_BUFFER_BIT);
542 }
Chet Haase2f200812012-10-11 12:49:08 -0700543
Romain Guy407ec782011-08-24 17:06:58 -0700544 // drawQuad
545 triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
546 glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
547 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
548
549 triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
550 glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
551 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
552
553 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
Chet Haase2f200812012-10-11 12:49:08 -0700554
Romain Guyc8d983f2013-02-20 10:05:36 -0800555 boolean status = mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
Romain Guy407ec782011-08-24 17:06:58 -0700556 checkEglError();
Chet Haase2f200812012-10-11 12:49:08 -0700557
Romain Guy407ec782011-08-24 17:06:58 -0700558 finishGL();
Romain Guyf9296292011-08-25 17:00:39 -0700559
Romain Guyc8d983f2013-02-20 10:05:36 -0800560 return status;
Romain Guy407ec782011-08-24 17:06:58 -0700561 }
562
563 private FloatBuffer createMesh(int left, int top, float right, float bottom) {
564 final float[] verticesData = {
565 // X, Y, Z, U, V
566 left, bottom, 0.0f, 0.0f, 1.0f,
567 right, bottom, 0.0f, 1.0f, 1.0f,
568 left, top, 0.0f, 0.0f, 0.0f,
569 right, top, 0.0f, 1.0f, 0.0f,
570 };
571
572 final int bytes = verticesData.length * FLOAT_SIZE_BYTES;
573 final FloatBuffer triangleVertices = ByteBuffer.allocateDirect(bytes).order(
574 ByteOrder.nativeOrder()).asFloatBuffer();
575 triangleVertices.put(verticesData).position(0);
576 return triangleVertices;
577 }
578
579 private int loadTexture(Bitmap bitmap) {
580 int[] textures = new int[1];
John Spurlock209bede2013-07-17 12:23:27 -0400581
Romain Guy407ec782011-08-24 17:06:58 -0700582 glActiveTexture(GL_TEXTURE0);
583 glGenTextures(1, textures, 0);
584 checkGlError();
John Spurlock209bede2013-07-17 12:23:27 -0400585
Romain Guy407ec782011-08-24 17:06:58 -0700586 int texture = textures[0];
587 glBindTexture(GL_TEXTURE_2D, texture);
588 checkGlError();
John Spurlock209bede2013-07-17 12:23:27 -0400589
Romain Guy407ec782011-08-24 17:06:58 -0700590 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
591 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
John Spurlock209bede2013-07-17 12:23:27 -0400592
Romain Guy407ec782011-08-24 17:06:58 -0700593 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
594 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
John Spurlock209bede2013-07-17 12:23:27 -0400595
Romain Guy407ec782011-08-24 17:06:58 -0700596 GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0);
597 checkGlError();
598
Romain Guy407ec782011-08-24 17:06:58 -0700599 return texture;
600 }
John Spurlock209bede2013-07-17 12:23:27 -0400601
Romain Guy407ec782011-08-24 17:06:58 -0700602 private int buildProgram(String vertex, String fragment) {
603 int vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
604 if (vertexShader == 0) return 0;
John Spurlock209bede2013-07-17 12:23:27 -0400605
Romain Guy407ec782011-08-24 17:06:58 -0700606 int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
607 if (fragmentShader == 0) return 0;
John Spurlock209bede2013-07-17 12:23:27 -0400608
Romain Guy407ec782011-08-24 17:06:58 -0700609 int program = glCreateProgram();
610 glAttachShader(program, vertexShader);
611 checkGlError();
John Spurlock209bede2013-07-17 12:23:27 -0400612
Romain Guy407ec782011-08-24 17:06:58 -0700613 glAttachShader(program, fragmentShader);
614 checkGlError();
John Spurlock209bede2013-07-17 12:23:27 -0400615
Romain Guy407ec782011-08-24 17:06:58 -0700616 glLinkProgram(program);
617 checkGlError();
John Spurlock209bede2013-07-17 12:23:27 -0400618
Romain Guy407ec782011-08-24 17:06:58 -0700619 int[] status = new int[1];
620 glGetProgramiv(program, GL_LINK_STATUS, status, 0);
621 if (status[0] != GL_TRUE) {
622 String error = glGetProgramInfoLog(program);
623 Log.d(GL_LOG_TAG, "Error while linking program:\n" + error);
624 glDeleteShader(vertexShader);
625 glDeleteShader(fragmentShader);
626 glDeleteProgram(program);
627 return 0;
628 }
John Spurlock209bede2013-07-17 12:23:27 -0400629
Romain Guy407ec782011-08-24 17:06:58 -0700630 return program;
631 }
Romain Guy3696779b2013-01-28 14:04:07 -0800632
Romain Guy407ec782011-08-24 17:06:58 -0700633 private int buildShader(String source, int type) {
634 int shader = glCreateShader(type);
John Spurlock209bede2013-07-17 12:23:27 -0400635
Romain Guy407ec782011-08-24 17:06:58 -0700636 glShaderSource(shader, source);
637 checkGlError();
John Spurlock209bede2013-07-17 12:23:27 -0400638
Romain Guy407ec782011-08-24 17:06:58 -0700639 glCompileShader(shader);
640 checkGlError();
John Spurlock209bede2013-07-17 12:23:27 -0400641
Romain Guy407ec782011-08-24 17:06:58 -0700642 int[] status = new int[1];
643 glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0);
644 if (status[0] != GL_TRUE) {
645 String error = glGetShaderInfoLog(shader);
646 Log.d(GL_LOG_TAG, "Error while compiling shader:\n" + error);
647 glDeleteShader(shader);
648 return 0;
649 }
John Spurlock209bede2013-07-17 12:23:27 -0400650
Romain Guy407ec782011-08-24 17:06:58 -0700651 return shader;
652 }
Romain Guy3696779b2013-01-28 14:04:07 -0800653
Romain Guy407ec782011-08-24 17:06:58 -0700654 private void checkEglError() {
655 int error = mEgl.eglGetError();
656 if (error != EGL_SUCCESS) {
657 Log.w(GL_LOG_TAG, "EGL error = " + GLUtils.getEGLErrorString(error));
658 }
659 }
Romain Guy3696779b2013-01-28 14:04:07 -0800660
Romain Guy407ec782011-08-24 17:06:58 -0700661 private void checkGlError() {
662 int error = glGetError();
663 if (error != GL_NO_ERROR) {
664 Log.w(GL_LOG_TAG, "GL error = 0x" + Integer.toHexString(error), new Throwable());
665 }
666 }
Romain Guy3696779b2013-01-28 14:04:07 -0800667
Romain Guy407ec782011-08-24 17:06:58 -0700668 private void finishGL() {
Romain Guyf9296292011-08-25 17:00:39 -0700669 mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
Romain Guy407ec782011-08-24 17:06:58 -0700670 mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
Romain Guyf9296292011-08-25 17:00:39 -0700671 mEgl.eglDestroyContext(mEglDisplay, mEglContext);
Romain Guy3696779b2013-01-28 14:04:07 -0800672 mEgl.eglTerminate(mEglDisplay);
Romain Guy407ec782011-08-24 17:06:58 -0700673 }
Romain Guy3696779b2013-01-28 14:04:07 -0800674
Romain Guyf9296292011-08-25 17:00:39 -0700675 private boolean initGL(SurfaceHolder surfaceHolder) {
Romain Guy407ec782011-08-24 17:06:58 -0700676 mEgl = (EGL10) EGLContext.getEGL();
John Spurlock209bede2013-07-17 12:23:27 -0400677
Romain Guy407ec782011-08-24 17:06:58 -0700678 mEglDisplay = mEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
679 if (mEglDisplay == EGL_NO_DISPLAY) {
680 throw new RuntimeException("eglGetDisplay failed " +
681 GLUtils.getEGLErrorString(mEgl.eglGetError()));
682 }
John Spurlock209bede2013-07-17 12:23:27 -0400683
Romain Guy407ec782011-08-24 17:06:58 -0700684 int[] version = new int[2];
685 if (!mEgl.eglInitialize(mEglDisplay, version)) {
686 throw new RuntimeException("eglInitialize failed " +
687 GLUtils.getEGLErrorString(mEgl.eglGetError()));
688 }
John Spurlock209bede2013-07-17 12:23:27 -0400689
Romain Guy407ec782011-08-24 17:06:58 -0700690 mEglConfig = chooseEglConfig();
691 if (mEglConfig == null) {
692 throw new RuntimeException("eglConfig not initialized");
693 }
John Spurlock209bede2013-07-17 12:23:27 -0400694
Romain Guy407ec782011-08-24 17:06:58 -0700695 mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
Chet Haase187e1e22013-03-13 18:04:00 -0700696 if (mEglContext == EGL_NO_CONTEXT) {
697 throw new RuntimeException("createContext failed " +
698 GLUtils.getEGLErrorString(mEgl.eglGetError()));
Wim Vander Schelden9549c062013-02-07 15:51:51 +0000699 }
Chet Haase187e1e22013-03-13 18:04:00 -0700700
Chet Haase2e417be2013-03-14 09:28:42 -0700701 int attribs[] = {
702 EGL_WIDTH, 1,
703 EGL_HEIGHT, 1,
704 EGL_NONE
705 };
706 EGLSurface tmpSurface = mEgl.eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
707 mEgl.eglMakeCurrent(mEglDisplay, tmpSurface, tmpSurface, mEglContext);
708
709 int[] maxSize = new int[1];
710 Rect frame = surfaceHolder.getSurfaceFrame();
711 glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxSize, 0);
712
713 mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
714 mEgl.eglDestroySurface(mEglDisplay, tmpSurface);
715
716 if(frame.width() > maxSize[0] || frame.height() > maxSize[0]) {
717 mEgl.eglDestroyContext(mEglDisplay, mEglContext);
718 mEgl.eglTerminate(mEglDisplay);
719 Log.e(GL_LOG_TAG, "requested texture size " +
720 frame.width() + "x" + frame.height() + " exceeds the support maximum of " +
721 maxSize[0] + "x" + maxSize[0]);
722 return false;
723 }
724
Romain Guy407ec782011-08-24 17:06:58 -0700725 mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null);
Romain Guy407ec782011-08-24 17:06:58 -0700726 if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
727 int error = mEgl.eglGetError();
Wim Vander Schelden9549c062013-02-07 15:51:51 +0000728 if (error == EGL_BAD_NATIVE_WINDOW || error == EGL_BAD_ALLOC) {
729 Log.e(GL_LOG_TAG, "createWindowSurface returned " +
730 GLUtils.getEGLErrorString(error) + ".");
Romain Guyf9296292011-08-25 17:00:39 -0700731 return false;
Romain Guy407ec782011-08-24 17:06:58 -0700732 }
733 throw new RuntimeException("createWindowSurface failed " +
734 GLUtils.getEGLErrorString(error));
735 }
John Spurlock209bede2013-07-17 12:23:27 -0400736
Romain Guy407ec782011-08-24 17:06:58 -0700737 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
738 throw new RuntimeException("eglMakeCurrent failed " +
739 GLUtils.getEGLErrorString(mEgl.eglGetError()));
740 }
Romain Guyf9296292011-08-25 17:00:39 -0700741
742 return true;
Romain Guy407ec782011-08-24 17:06:58 -0700743 }
John Spurlock209bede2013-07-17 12:23:27 -0400744
745
Romain Guy407ec782011-08-24 17:06:58 -0700746 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
747 int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
John Spurlock209bede2013-07-17 12:23:27 -0400748 return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list);
Romain Guy407ec782011-08-24 17:06:58 -0700749 }
John Spurlock209bede2013-07-17 12:23:27 -0400750
Romain Guy407ec782011-08-24 17:06:58 -0700751 private EGLConfig chooseEglConfig() {
752 int[] configsCount = new int[1];
753 EGLConfig[] configs = new EGLConfig[1];
754 int[] configSpec = getConfig();
755 if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
756 throw new IllegalArgumentException("eglChooseConfig failed " +
757 GLUtils.getEGLErrorString(mEgl.eglGetError()));
758 } else if (configsCount[0] > 0) {
759 return configs[0];
760 }
761 return null;
762 }
763
764 private int[] getConfig() {
765 return new int[] {
766 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
767 EGL_RED_SIZE, 8,
768 EGL_GREEN_SIZE, 8,
769 EGL_BLUE_SIZE, 8,
770 EGL_ALPHA_SIZE, 0,
771 EGL_DEPTH_SIZE, 0,
772 EGL_STENCIL_SIZE, 0,
Romain Guy8efca542012-10-15 18:09:49 -0700773 EGL_CONFIG_CAVEAT, EGL_NONE,
Romain Guy407ec782011-08-24 17:06:58 -0700774 EGL_NONE
775 };
Romain Guyef654bd2009-08-11 19:12:17 -0700776 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700777 }
778}