blob: bc1cf363672fbf125324f82a14d67f87efc8c03b [file] [log] [blame]
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001/*
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08002**
3** Copyright 2007 The Android Open Source Project
4**
Mathias Agopian076b1cc2009-04-10 14:24:30 -07005** Licensed under the Apache License Version 2.0(the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08008**
Mathias Agopian076b1cc2009-04-10 14:24:30 -07009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080010**
Mathias Agopian076b1cc2009-04-10 14:24:30 -070011** Unless required by applicable law or agreed to in writing software
12** distributed under the License is distributed on an "AS IS" BASIS
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
14** See the License for the specific language governing permissions and
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080015** limitations under the License.
16*/
17
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080018#include <assert.h>
19#include <errno.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <sys/ioctl.h>
26#include <sys/types.h>
27#include <sys/mman.h>
28
29#include <cutils/log.h>
30#include <cutils/atomic.h>
31
32#include <utils/threads.h>
Mathias Agopian5f2165f2012-02-24 18:25:41 -080033#include <ui/ANativeObjectBase.h>
Jamie Gennisd8e812c2012-06-13 16:32:25 -070034#include <ui/Fence.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080035
36#include <EGL/egl.h>
37#include <EGL/eglext.h>
38#include <GLES/gl.h>
39#include <GLES/glext.h>
40
41#include <pixelflinger/format.h>
42#include <pixelflinger/pixelflinger.h>
43
44#include "context.h"
45#include "state.h"
46#include "texture.h"
47#include "matrix.h"
48
49#undef NELEM
50#define NELEM(x) (sizeof(x)/sizeof(*(x)))
51
Mathias Agopian5f2165f2012-02-24 18:25:41 -080052// ----------------------------------------------------------------------------
Mathias Agopian4b9511c2011-11-13 23:52:47 -080053
54EGLBoolean EGLAPI eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
55 EGLint left, EGLint top, EGLint width, EGLint height);
56
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080057// ----------------------------------------------------------------------------
58namespace android {
Mathias Agopian5f2165f2012-02-24 18:25:41 -080059
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080060// ----------------------------------------------------------------------------
61
62const unsigned int NUM_DISPLAYS = 1;
63
64static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
65static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
66static pthread_key_t gEGLErrorKey = -1;
67#ifndef HAVE_ANDROID_OS
68namespace gl {
69pthread_key_t gGLKey = -1;
70}; // namespace gl
71#endif
72
73template<typename T>
74static T setError(GLint error, T returnValue) {
75 if (ggl_unlikely(gEGLErrorKey == -1)) {
76 pthread_mutex_lock(&gErrorKeyMutex);
77 if (gEGLErrorKey == -1)
78 pthread_key_create(&gEGLErrorKey, NULL);
79 pthread_mutex_unlock(&gErrorKeyMutex);
80 }
81 pthread_setspecific(gEGLErrorKey, (void*)error);
82 return returnValue;
83}
84
85static GLint getError() {
86 if (ggl_unlikely(gEGLErrorKey == -1))
87 return EGL_SUCCESS;
88 GLint error = (GLint)pthread_getspecific(gEGLErrorKey);
Jamie Gennis2076f352011-01-30 15:59:36 -080089 if (error == 0) {
90 // The TLS key has been created by another thread, but the value for
91 // this thread has not been initialized.
92 return EGL_SUCCESS;
93 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080094 pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS);
95 return error;
96}
97
98// ----------------------------------------------------------------------------
99
100struct egl_display_t
101{
102 egl_display_t() : type(0), initialized(0) { }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700103
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800104 static egl_display_t& get_display(EGLDisplay dpy);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700105
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800106 static EGLBoolean is_valid(EGLDisplay dpy) {
107 return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
108 }
109
110 NativeDisplayType type;
111 volatile int32_t initialized;
112};
113
114static egl_display_t gDisplays[NUM_DISPLAYS];
115
116egl_display_t& egl_display_t::get_display(EGLDisplay dpy) {
117 return gDisplays[uintptr_t(dpy)-1U];
118}
119
120struct egl_context_t {
121 enum {
122 IS_CURRENT = 0x00010000,
123 NEVER_CURRENT = 0x00020000
124 };
125 uint32_t flags;
126 EGLDisplay dpy;
127 EGLConfig config;
128 EGLSurface read;
129 EGLSurface draw;
130
131 static inline egl_context_t* context(EGLContext ctx) {
132 ogles_context_t* const gl = static_cast<ogles_context_t*>(ctx);
133 return static_cast<egl_context_t*>(gl->rasterizer.base);
134 }
135};
136
137// ----------------------------------------------------------------------------
138
139struct egl_surface_t
140{
141 enum {
142 PAGE_FLIP = 0x00000001,
143 MAGIC = 0x31415265
144 };
145
146 uint32_t magic;
147 EGLDisplay dpy;
148 EGLConfig config;
149 EGLContext ctx;
Jesse Hall78141e32013-03-07 09:56:26 -0800150 bool zombie;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800151
152 egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
153 virtual ~egl_surface_t();
Mathias Agopian0696a572009-08-20 00:12:56 -0700154 bool isValid() const;
155 virtual bool initCheck() const = 0;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700156
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800157 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl) = 0;
158 virtual EGLBoolean bindReadSurface(ogles_context_t* gl) = 0;
Mathias Agopiancf81c842009-07-31 14:47:00 -0700159 virtual EGLBoolean connect() { return EGL_TRUE; }
Mathias Agopiane71212b2009-05-05 00:37:46 -0700160 virtual void disconnect() {}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800161 virtual EGLint getWidth() const = 0;
162 virtual EGLint getHeight() const = 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800163
164 virtual EGLint getHorizontalResolution() const;
165 virtual EGLint getVerticalResolution() const;
166 virtual EGLint getRefreshRate() const;
167 virtual EGLint getSwapBehavior() const;
168 virtual EGLBoolean swapBuffers();
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700169 virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800170protected:
171 GGLSurface depth;
172};
173
174egl_surface_t::egl_surface_t(EGLDisplay dpy,
175 EGLConfig config,
176 int32_t depthFormat)
Jesse Hall78141e32013-03-07 09:56:26 -0800177 : magic(MAGIC), dpy(dpy), config(config), ctx(0), zombie(false)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800178{
179 depth.version = sizeof(GGLSurface);
180 depth.data = 0;
181 depth.format = depthFormat;
182}
183egl_surface_t::~egl_surface_t()
184{
185 magic = 0;
186 free(depth.data);
187}
Mathias Agopian0696a572009-08-20 00:12:56 -0700188bool egl_surface_t::isValid() const {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000189 ALOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this);
Mathias Agopian0696a572009-08-20 00:12:56 -0700190 return magic == MAGIC;
191}
192
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800193EGLBoolean egl_surface_t::swapBuffers() {
194 return EGL_FALSE;
195}
196EGLint egl_surface_t::getHorizontalResolution() const {
197 return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
198}
199EGLint egl_surface_t::getVerticalResolution() const {
200 return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
201}
202EGLint egl_surface_t::getRefreshRate() const {
203 return (60 * EGL_DISPLAY_SCALING);
204}
205EGLint egl_surface_t::getSwapBehavior() const {
206 return EGL_BUFFER_PRESERVED;
207}
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700208EGLBoolean egl_surface_t::setSwapRectangle(
209 EGLint l, EGLint t, EGLint w, EGLint h)
210{
211 return EGL_FALSE;
212}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800213
214// ----------------------------------------------------------------------------
215
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700216struct egl_window_surface_v2_t : public egl_surface_t
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800217{
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700218 egl_window_surface_v2_t(
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800219 EGLDisplay dpy, EGLConfig config,
220 int32_t depthFormat,
Dianne Hackborn4b5e91e2010-06-30 13:56:17 -0700221 ANativeWindow* window);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800222
Mathias Agopian0696a572009-08-20 00:12:56 -0700223 ~egl_window_surface_v2_t();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800224
Mathias Agopian0696a572009-08-20 00:12:56 -0700225 virtual bool initCheck() const { return true; } // TODO: report failure if ctor fails
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800226 virtual EGLBoolean swapBuffers();
227 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
228 virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
Mathias Agopiancf81c842009-07-31 14:47:00 -0700229 virtual EGLBoolean connect();
Mathias Agopiane71212b2009-05-05 00:37:46 -0700230 virtual void disconnect();
Mathias Agopiancb6b9042009-07-30 18:14:56 -0700231 virtual EGLint getWidth() const { return width; }
232 virtual EGLint getHeight() const { return height; }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800233 virtual EGLint getHorizontalResolution() const;
234 virtual EGLint getVerticalResolution() const;
235 virtual EGLint getRefreshRate() const;
236 virtual EGLint getSwapBehavior() const;
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700237 virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
Mathias Agopian8d2e83b2009-06-24 22:37:39 -0700238
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800239private:
Iliyan Malchev697526b2011-05-01 11:33:26 -0700240 status_t lock(ANativeWindowBuffer* buf, int usage, void** vaddr);
241 status_t unlock(ANativeWindowBuffer* buf);
Dianne Hackborn4b5e91e2010-06-30 13:56:17 -0700242 ANativeWindow* nativeWindow;
Iliyan Malchev697526b2011-05-01 11:33:26 -0700243 ANativeWindowBuffer* buffer;
244 ANativeWindowBuffer* previousBuffer;
Mathias Agopian0926f502009-05-04 14:17:04 -0700245 gralloc_module_t const* module;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700246 int width;
247 int height;
Mathias Agopiane71212b2009-05-05 00:37:46 -0700248 void* bits;
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700249 GGLFormat const* pixelFormatTable;
250
251 struct Rect {
252 inline Rect() { };
253 inline Rect(int32_t w, int32_t h)
254 : left(0), top(0), right(w), bottom(h) { }
255 inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
256 : left(l), top(t), right(r), bottom(b) { }
257 Rect& andSelf(const Rect& r) {
258 left = max(left, r.left);
259 top = max(top, r.top);
260 right = min(right, r.right);
261 bottom = min(bottom, r.bottom);
262 return *this;
263 }
264 bool isEmpty() const {
265 return (left>=right || top>=bottom);
266 }
267 void dump(char const* what) {
Steve Block9d453682011-12-20 16:23:08 +0000268 ALOGD("%s { %5d, %5d, w=%5d, h=%5d }",
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700269 what, left, top, right-left, bottom-top);
270 }
271
272 int32_t left;
273 int32_t top;
274 int32_t right;
275 int32_t bottom;
276 };
277
278 struct Region {
279 inline Region() : count(0) { }
Mathias Agopian240c9fe2009-06-25 15:39:25 -0700280 typedef Rect const* const_iterator;
281 const_iterator begin() const { return storage; }
282 const_iterator end() const { return storage+count; }
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700283 static Region subtract(const Rect& lhs, const Rect& rhs) {
284 Region reg;
285 Rect* storage = reg.storage;
286 if (!lhs.isEmpty()) {
287 if (lhs.top < rhs.top) { // top rect
288 storage->left = lhs.left;
289 storage->top = lhs.top;
290 storage->right = lhs.right;
Mathias Agopian240c9fe2009-06-25 15:39:25 -0700291 storage->bottom = rhs.top;
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700292 storage++;
293 }
Mathias Agopian240c9fe2009-06-25 15:39:25 -0700294 const int32_t top = max(lhs.top, rhs.top);
295 const int32_t bot = min(lhs.bottom, rhs.bottom);
296 if (top < bot) {
297 if (lhs.left < rhs.left) { // left-side rect
298 storage->left = lhs.left;
299 storage->top = top;
300 storage->right = rhs.left;
301 storage->bottom = bot;
302 storage++;
303 }
304 if (lhs.right > rhs.right) { // right-side rect
305 storage->left = rhs.right;
306 storage->top = top;
307 storage->right = lhs.right;
308 storage->bottom = bot;
309 storage++;
310 }
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700311 }
312 if (lhs.bottom > rhs.bottom) { // bottom rect
313 storage->left = lhs.left;
Mathias Agopian240c9fe2009-06-25 15:39:25 -0700314 storage->top = rhs.bottom;
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700315 storage->right = lhs.right;
316 storage->bottom = lhs.bottom;
317 storage++;
318 }
319 reg.count = storage - reg.storage;
320 }
321 return reg;
322 }
323 bool isEmpty() const {
324 return count<=0;
325 }
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700326 private:
327 Rect storage[4];
328 ssize_t count;
329 };
330
331 void copyBlt(
Iliyan Malchev697526b2011-05-01 11:33:26 -0700332 ANativeWindowBuffer* dst, void* dst_vaddr,
333 ANativeWindowBuffer* src, void const* src_vaddr,
Mathias Agopian240c9fe2009-06-25 15:39:25 -0700334 const Region& clip);
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700335
336 Rect dirtyRegion;
337 Rect oldDirtyRegion;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800338};
339
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700340egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800341 EGLConfig config,
342 int32_t depthFormat,
Dianne Hackborn4b5e91e2010-06-30 13:56:17 -0700343 ANativeWindow* window)
Mathias Agopian0926f502009-05-04 14:17:04 -0700344 : egl_surface_t(dpy, config, depthFormat),
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700345 nativeWindow(window), buffer(0), previousBuffer(0), module(0),
Mathias Agopian9cdb01d2011-04-28 19:50:21 -0700346 bits(NULL)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800347{
Mathias Agopian69e43b72011-05-11 13:41:09 -0700348 hw_module_t const* pModule;
349 hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
350 module = reinterpret_cast<gralloc_module_t const*>(pModule);
351
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700352 pixelFormatTable = gglGetPixelFormatTable();
353
354 // keep a reference on the window
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700355 nativeWindow->common.incRef(&nativeWindow->common);
Mathias Agopiancb6b9042009-07-30 18:14:56 -0700356 nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
357 nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
Mathias Agopiane71212b2009-05-05 00:37:46 -0700358}
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700359
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700360egl_window_surface_v2_t::~egl_window_surface_v2_t() {
361 if (buffer) {
362 buffer->common.decRef(&buffer->common);
363 }
364 if (previousBuffer) {
365 previousBuffer->common.decRef(&previousBuffer->common);
366 }
367 nativeWindow->common.decRef(&nativeWindow->common);
368}
369
Mathias Agopiancf81c842009-07-31 14:47:00 -0700370EGLBoolean egl_window_surface_v2_t::connect()
Mathias Agopiane71212b2009-05-05 00:37:46 -0700371{
Mathias Agopian52212712009-08-11 22:34:02 -0700372 // we're intending to do software rendering
373 native_window_set_usage(nativeWindow,
374 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
375
Mathias Agopiancb6b9042009-07-30 18:14:56 -0700376 // dequeue a buffer
Jamie Gennisd8e812c2012-06-13 16:32:25 -0700377 int fenceFd = -1;
378 if (nativeWindow->dequeueBuffer(nativeWindow, &buffer,
379 &fenceFd) != NO_ERROR) {
380 return setError(EGL_BAD_ALLOC, EGL_FALSE);
381 }
382
383 // wait for the buffer
384 sp<Fence> fence(new Fence(fenceFd));
385 if (fence->wait(Fence::TIMEOUT_NEVER) != NO_ERROR) {
386 nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);
Mathias Agopiancf81c842009-07-31 14:47:00 -0700387 return setError(EGL_BAD_ALLOC, EGL_FALSE);
388 }
Mathias Agopiancb6b9042009-07-30 18:14:56 -0700389
390 // allocate a corresponding depth-buffer
391 width = buffer->width;
392 height = buffer->height;
393 if (depth.format) {
394 depth.width = width;
395 depth.height = height;
396 depth.stride = depth.width; // use the width here
397 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
398 if (depth.data == 0) {
Mathias Agopiancf81c842009-07-31 14:47:00 -0700399 return setError(EGL_BAD_ALLOC, EGL_FALSE);
Mathias Agopiancb6b9042009-07-30 18:14:56 -0700400 }
401 }
402
403 // keep a reference on the buffer
404 buffer->common.incRef(&buffer->common);
405
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700406 // pin the buffer down
407 if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
408 GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000409 ALOGE("connect() failed to lock buffer %p (%ux%u)",
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700410 buffer, buffer->width, buffer->height);
Mathias Agopiancf81c842009-07-31 14:47:00 -0700411 return setError(EGL_BAD_ACCESS, EGL_FALSE);
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700412 // FIXME: we should make sure we're not accessing the buffer anymore
413 }
Mathias Agopiancf81c842009-07-31 14:47:00 -0700414 return EGL_TRUE;
Mathias Agopiane71212b2009-05-05 00:37:46 -0700415}
416
417void egl_window_surface_v2_t::disconnect()
418{
Mathias Agopian9648c1a2009-06-03 19:00:53 -0700419 if (buffer && bits) {
Mathias Agopiane71212b2009-05-05 00:37:46 -0700420 bits = NULL;
421 unlock(buffer);
422 }
Mathias Agopiancb6b9042009-07-30 18:14:56 -0700423 // enqueue the last frame
Jamie Gennisd8e812c2012-06-13 16:32:25 -0700424 nativeWindow->queueBuffer(nativeWindow, buffer, -1);
Mathias Agopiancb6b9042009-07-30 18:14:56 -0700425 if (buffer) {
426 buffer->common.decRef(&buffer->common);
427 buffer = 0;
428 }
429 if (previousBuffer) {
430 previousBuffer->common.decRef(&previousBuffer->common);
431 previousBuffer = 0;
432 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800433}
434
Mathias Agopian0926f502009-05-04 14:17:04 -0700435status_t egl_window_surface_v2_t::lock(
Iliyan Malchev697526b2011-05-01 11:33:26 -0700436 ANativeWindowBuffer* buf, int usage, void** vaddr)
Mathias Agopian0926f502009-05-04 14:17:04 -0700437{
Mathias Agopianbc492912009-11-03 20:38:08 -0800438 int err;
Mathias Agopian695b66f2010-12-08 17:44:07 -0800439
440 err = module->lock(module, buf->handle,
441 usage, 0, 0, buf->width, buf->height, vaddr);
442
Mathias Agopian0926f502009-05-04 14:17:04 -0700443 return err;
444}
445
Iliyan Malchev697526b2011-05-01 11:33:26 -0700446status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf)
Mathias Agopian0926f502009-05-04 14:17:04 -0700447{
Mathias Agopiancf81c842009-07-31 14:47:00 -0700448 if (!buf) return BAD_VALUE;
Mathias Agopianbc492912009-11-03 20:38:08 -0800449 int err = NO_ERROR;
Mathias Agopian695b66f2010-12-08 17:44:07 -0800450
451 err = module->unlock(module, buf->handle);
452
Mathias Agopian0926f502009-05-04 14:17:04 -0700453 return err;
454}
455
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700456void egl_window_surface_v2_t::copyBlt(
Iliyan Malchev697526b2011-05-01 11:33:26 -0700457 ANativeWindowBuffer* dst, void* dst_vaddr,
458 ANativeWindowBuffer* src, void const* src_vaddr,
Mathias Agopian240c9fe2009-06-25 15:39:25 -0700459 const Region& clip)
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700460{
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700461 // NOTE: dst and src must be the same format
462
Mathias Agopian9cdb01d2011-04-28 19:50:21 -0700463 Region::const_iterator cur = clip.begin();
464 Region::const_iterator end = clip.end();
Mathias Agopian0926f502009-05-04 14:17:04 -0700465
Mathias Agopian9cdb01d2011-04-28 19:50:21 -0700466 const size_t bpp = pixelFormatTable[src->format].size;
467 const size_t dbpr = dst->stride * bpp;
468 const size_t sbpr = src->stride * bpp;
469
470 uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
471 uint8_t * const dst_bits = (uint8_t *)dst_vaddr;
472
473 while (cur != end) {
474 const Rect& r(*cur++);
475 ssize_t w = r.right - r.left;
476 ssize_t h = r.bottom - r.top;
477 if (w <= 0 || h<=0) continue;
478 size_t size = w * bpp;
479 uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
480 uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
481 if (dbpr==sbpr && size==sbpr) {
482 size *= h;
483 h = 1;
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700484 }
Mathias Agopian9cdb01d2011-04-28 19:50:21 -0700485 do {
486 memcpy(d, s, size);
487 d += dbpr;
488 s += sbpr;
489 } while (--h > 0);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700490 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700491}
492
493EGLBoolean egl_window_surface_v2_t::swapBuffers()
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800494{
Mathias Agopiancf81c842009-07-31 14:47:00 -0700495 if (!buffer) {
496 return setError(EGL_BAD_ACCESS, EGL_FALSE);
497 }
498
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700499 /*
500 * Handle eglSetSwapRectangleANDROID()
501 * We copyback from the front buffer
502 */
503 if (!dirtyRegion.isEmpty()) {
504 dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
505 if (previousBuffer) {
Kristian Monsen72c384e2010-10-27 17:59:09 +0100506 // This was const Region copyBack, but that causes an
507 // internal compile error on simulator builds
508 /*const*/ Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700509 if (!copyBack.isEmpty()) {
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700510 void* prevBits;
511 if (lock(previousBuffer,
Mathias Agopian240c9fe2009-06-25 15:39:25 -0700512 GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
513 // copy from previousBuffer to buffer
514 copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700515 unlock(previousBuffer);
516 }
517 }
518 }
519 oldDirtyRegion = dirtyRegion;
520 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700521
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700522 if (previousBuffer) {
523 previousBuffer->common.decRef(&previousBuffer->common);
524 previousBuffer = 0;
525 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700526
Mathias Agopian0926f502009-05-04 14:17:04 -0700527 unlock(buffer);
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700528 previousBuffer = buffer;
Jamie Gennisd8e812c2012-06-13 16:32:25 -0700529 nativeWindow->queueBuffer(nativeWindow, buffer, -1);
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700530 buffer = 0;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700531
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700532 // dequeue a new buffer
Jamie Gennisd8e812c2012-06-13 16:32:25 -0700533 int fenceFd = -1;
534 if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd) == NO_ERROR) {
535 sp<Fence> fence(new Fence(fenceFd));
536 if (fence->wait(Fence::TIMEOUT_NEVER)) {
537 nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);
538 return setError(EGL_BAD_ALLOC, EGL_FALSE);
539 }
Mathias Agopian031213e2010-08-18 16:07:34 -0700540
541 // reallocate the depth-buffer if needed
542 if ((width != buffer->width) || (height != buffer->height)) {
543 // TODO: we probably should reset the swap rect here
544 // if the window size has changed
545 width = buffer->width;
546 height = buffer->height;
547 if (depth.data) {
548 free(depth.data);
549 depth.width = width;
550 depth.height = height;
551 depth.stride = buffer->stride;
552 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
553 if (depth.data == 0) {
554 setError(EGL_BAD_ALLOC, EGL_FALSE);
555 return EGL_FALSE;
556 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800557 }
558 }
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700559
Mathias Agopian031213e2010-08-18 16:07:34 -0700560 // keep a reference on the buffer
561 buffer->common.incRef(&buffer->common);
562
563 // finally pin the buffer down
564 if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
565 GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000566 ALOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
Mathias Agopian031213e2010-08-18 16:07:34 -0700567 buffer, buffer->width, buffer->height);
568 return setError(EGL_BAD_ACCESS, EGL_FALSE);
569 // FIXME: we should make sure we're not accessing the buffer anymore
570 }
571 } else {
572 return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700573 }
574
575 return EGL_TRUE;
576}
577
578EGLBoolean egl_window_surface_v2_t::setSwapRectangle(
579 EGLint l, EGLint t, EGLint w, EGLint h)
580{
581 dirtyRegion = Rect(l, t, l+w, t+h);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800582 return EGL_TRUE;
583}
584
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700585EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800586{
587 GGLSurface buffer;
588 buffer.version = sizeof(GGLSurface);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700589 buffer.width = this->buffer->width;
590 buffer.height = this->buffer->height;
591 buffer.stride = this->buffer->stride;
Mathias Agopiane71212b2009-05-05 00:37:46 -0700592 buffer.data = (GGLubyte*)bits;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700593 buffer.format = this->buffer->format;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800594 gl->rasterizer.procs.colorBuffer(gl, &buffer);
595 if (depth.data != gl->rasterizer.state.buffers.depth.data)
596 gl->rasterizer.procs.depthBuffer(gl, &depth);
Mathias Agopian0a3139a2009-06-10 16:01:54 -0700597
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800598 return EGL_TRUE;
599}
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700600EGLBoolean egl_window_surface_v2_t::bindReadSurface(ogles_context_t* gl)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800601{
602 GGLSurface buffer;
603 buffer.version = sizeof(GGLSurface);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700604 buffer.width = this->buffer->width;
605 buffer.height = this->buffer->height;
606 buffer.stride = this->buffer->stride;
Mathias Agopiane71212b2009-05-05 00:37:46 -0700607 buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700608 buffer.format = this->buffer->format;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800609 gl->rasterizer.procs.readBuffer(gl, &buffer);
610 return EGL_TRUE;
611}
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700612EGLint egl_window_surface_v2_t::getHorizontalResolution() const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800613 return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
614}
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700615EGLint egl_window_surface_v2_t::getVerticalResolution() const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800616 return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
617}
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700618EGLint egl_window_surface_v2_t::getRefreshRate() const {
619 return (60 * EGL_DISPLAY_SCALING); // FIXME
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800620}
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700621EGLint egl_window_surface_v2_t::getSwapBehavior() const
622{
623 /*
624 * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
625 * the content of the swapped buffer.
626 *
627 * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
628 *
629 * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
630 * only applies to the area specified by eglSetSwapRectangleANDROID(), that
631 * is, everything outside of this area is preserved.
632 *
633 * This implementation of EGL assumes the later case.
634 *
635 */
636
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700637 return EGL_BUFFER_DESTROYED;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800638}
639
640// ----------------------------------------------------------------------------
641
642struct egl_pixmap_surface_t : public egl_surface_t
643{
644 egl_pixmap_surface_t(
645 EGLDisplay dpy, EGLConfig config,
646 int32_t depthFormat,
647 egl_native_pixmap_t const * pixmap);
648
649 virtual ~egl_pixmap_surface_t() { }
650
Mathias Agopian0696a572009-08-20 00:12:56 -0700651 virtual bool initCheck() const { return !depth.format || depth.data!=0; }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800652 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
653 virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
654 virtual EGLint getWidth() const { return nativePixmap.width; }
655 virtual EGLint getHeight() const { return nativePixmap.height; }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800656private:
657 egl_native_pixmap_t nativePixmap;
658};
659
660egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
661 EGLConfig config,
662 int32_t depthFormat,
663 egl_native_pixmap_t const * pixmap)
664 : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
665{
666 if (depthFormat) {
667 depth.width = pixmap->width;
668 depth.height = pixmap->height;
669 depth.stride = depth.width; // use the width here
670 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
671 if (depth.data == 0) {
672 setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800673 }
674 }
675}
676EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl)
677{
678 GGLSurface buffer;
679 buffer.version = sizeof(GGLSurface);
680 buffer.width = nativePixmap.width;
681 buffer.height = nativePixmap.height;
682 buffer.stride = nativePixmap.stride;
683 buffer.data = nativePixmap.data;
684 buffer.format = nativePixmap.format;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700685
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800686 gl->rasterizer.procs.colorBuffer(gl, &buffer);
687 if (depth.data != gl->rasterizer.state.buffers.depth.data)
688 gl->rasterizer.procs.depthBuffer(gl, &depth);
689 return EGL_TRUE;
690}
691EGLBoolean egl_pixmap_surface_t::bindReadSurface(ogles_context_t* gl)
692{
693 GGLSurface buffer;
694 buffer.version = sizeof(GGLSurface);
695 buffer.width = nativePixmap.width;
696 buffer.height = nativePixmap.height;
697 buffer.stride = nativePixmap.stride;
698 buffer.data = nativePixmap.data;
699 buffer.format = nativePixmap.format;
700 gl->rasterizer.procs.readBuffer(gl, &buffer);
701 return EGL_TRUE;
702}
703
704// ----------------------------------------------------------------------------
705
706struct egl_pbuffer_surface_t : public egl_surface_t
707{
708 egl_pbuffer_surface_t(
709 EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
710 int32_t w, int32_t h, int32_t f);
711
712 virtual ~egl_pbuffer_surface_t();
713
Mathias Agopian0696a572009-08-20 00:12:56 -0700714 virtual bool initCheck() const { return pbuffer.data != 0; }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800715 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
716 virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
717 virtual EGLint getWidth() const { return pbuffer.width; }
718 virtual EGLint getHeight() const { return pbuffer.height; }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800719private:
720 GGLSurface pbuffer;
721};
722
723egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
724 EGLConfig config, int32_t depthFormat,
725 int32_t w, int32_t h, int32_t f)
726 : egl_surface_t(dpy, config, depthFormat)
727{
728 size_t size = w*h;
729 switch (f) {
730 case GGL_PIXEL_FORMAT_A_8: size *= 1; break;
731 case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break;
732 case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break;
Mathias Agopian8b6b95a2009-11-03 16:17:55 -0800733 case GGL_PIXEL_FORMAT_RGBX_8888: size *= 4; break;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800734 default:
Steve Blocke6f43dd2012-01-06 19:20:56 +0000735 ALOGE("incompatible pixel format for pbuffer (format=%d)", f);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800736 pbuffer.data = 0;
737 break;
738 }
739 pbuffer.version = sizeof(GGLSurface);
740 pbuffer.width = w;
741 pbuffer.height = h;
742 pbuffer.stride = w;
743 pbuffer.data = (GGLubyte*)malloc(size);
744 pbuffer.format = f;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700745
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800746 if (depthFormat) {
747 depth.width = pbuffer.width;
748 depth.height = pbuffer.height;
749 depth.stride = depth.width; // use the width here
750 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
751 if (depth.data == 0) {
752 setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
753 return;
754 }
755 }
756}
757egl_pbuffer_surface_t::~egl_pbuffer_surface_t() {
758 free(pbuffer.data);
759}
760EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(ogles_context_t* gl)
761{
762 gl->rasterizer.procs.colorBuffer(gl, &pbuffer);
763 if (depth.data != gl->rasterizer.state.buffers.depth.data)
764 gl->rasterizer.procs.depthBuffer(gl, &depth);
765 return EGL_TRUE;
766}
767EGLBoolean egl_pbuffer_surface_t::bindReadSurface(ogles_context_t* gl)
768{
769 gl->rasterizer.procs.readBuffer(gl, &pbuffer);
770 return EGL_TRUE;
771}
772
773// ----------------------------------------------------------------------------
774
775struct config_pair_t {
776 GLint key;
777 GLint value;
778};
779
780struct configs_t {
781 const config_pair_t* array;
782 int size;
783};
784
785struct config_management_t {
786 GLint key;
787 bool (*match)(GLint reqValue, GLint confValue);
788 static bool atLeast(GLint reqValue, GLint confValue) {
789 return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
790 }
791 static bool exact(GLint reqValue, GLint confValue) {
792 return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
793 }
794 static bool mask(GLint reqValue, GLint confValue) {
795 return (confValue & reqValue) == reqValue;
796 }
Mathias Agopian63971672010-10-25 15:51:24 -0700797 static bool ignore(GLint reqValue, GLint confValue) {
798 return true;
799 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800800};
801
802// ----------------------------------------------------------------------------
803
804#define VERSION_MAJOR 1
805#define VERSION_MINOR 2
806static char const * const gVendorString = "Google Inc.";
Mathias Agopian141550b2010-10-19 14:47:08 -0700807static char const * const gVersionString = "1.2 Android Driver 1.2.0";
Mathias Agopiancc2b1562012-05-21 14:01:37 -0700808static char const * const gClientApiString = "OpenGL_ES";
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700809static char const * const gExtensionsString =
Jesse Hall83e7c8c2012-05-22 10:42:56 -0700810 "EGL_KHR_fence_sync "
Mathias Agopiane6bf8b32009-05-06 23:47:08 -0700811 "EGL_KHR_image_base "
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700812 // "KHR_image_pixmap "
813 "EGL_ANDROID_image_native_buffer "
Mathias Agopiandf3ca302009-05-04 19:29:25 -0700814 "EGL_ANDROID_swap_rectangle "
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700815 ;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800816
817// ----------------------------------------------------------------------------
818
819struct extention_map_t {
820 const char * const name;
821 __eglMustCastToProperFunctionPointerType address;
822};
823
824static const extention_map_t gExtentionMap[] = {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700825 { "glDrawTexsOES",
826 (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES },
827 { "glDrawTexiOES",
828 (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES },
829 { "glDrawTexfOES",
830 (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES },
831 { "glDrawTexxOES",
832 (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES },
833 { "glDrawTexsvOES",
834 (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES },
835 { "glDrawTexivOES",
836 (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES },
837 { "glDrawTexfvOES",
838 (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES },
839 { "glDrawTexxvOES",
840 (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
841 { "glQueryMatrixxOES",
842 (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
843 { "glEGLImageTargetTexture2DOES",
844 (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
845 { "glEGLImageTargetRenderbufferStorageOES",
846 (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
847 { "glClipPlanef",
848 (__eglMustCastToProperFunctionPointerType)&glClipPlanef },
849 { "glClipPlanex",
850 (__eglMustCastToProperFunctionPointerType)&glClipPlanex },
851 { "glBindBuffer",
852 (__eglMustCastToProperFunctionPointerType)&glBindBuffer },
853 { "glBufferData",
854 (__eglMustCastToProperFunctionPointerType)&glBufferData },
855 { "glBufferSubData",
856 (__eglMustCastToProperFunctionPointerType)&glBufferSubData },
857 { "glDeleteBuffers",
858 (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
859 { "glGenBuffers",
860 (__eglMustCastToProperFunctionPointerType)&glGenBuffers },
Mathias Agopian8d2e83b2009-06-24 22:37:39 -0700861 { "eglCreateImageKHR",
862 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
863 { "eglDestroyImageKHR",
864 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
Jesse Hall83e7c8c2012-05-22 10:42:56 -0700865 { "eglCreateSyncKHR",
866 (__eglMustCastToProperFunctionPointerType)&eglCreateSyncKHR },
867 { "eglDestroySyncKHR",
868 (__eglMustCastToProperFunctionPointerType)&eglDestroySyncKHR },
869 { "eglClientWaitSyncKHR",
870 (__eglMustCastToProperFunctionPointerType)&eglClientWaitSyncKHR },
871 { "eglGetSyncAttribKHR",
872 (__eglMustCastToProperFunctionPointerType)&eglGetSyncAttribKHR },
Mathias Agopian8d2e83b2009-06-24 22:37:39 -0700873 { "eglSetSwapRectangleANDROID",
874 (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800875};
876
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700877/*
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800878 * In the lists below, attributes names MUST be sorted.
879 * Additionally, all configs must be sorted according to
880 * the EGL specification.
881 */
882
883static config_pair_t const config_base_attribute_list[] = {
884 { EGL_STENCIL_SIZE, 0 },
885 { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG },
886 { EGL_LEVEL, 0 },
887 { EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS },
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700888 { EGL_MAX_PBUFFER_PIXELS,
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800889 GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS },
890 { EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS },
891 { EGL_NATIVE_RENDERABLE, EGL_TRUE },
892 { EGL_NATIVE_VISUAL_ID, 0 },
893 { EGL_NATIVE_VISUAL_TYPE, GGL_PIXEL_FORMAT_RGB_565 },
894 { EGL_SAMPLES, 0 },
895 { EGL_SAMPLE_BUFFERS, 0 },
896 { EGL_TRANSPARENT_TYPE, EGL_NONE },
897 { EGL_TRANSPARENT_BLUE_VALUE, 0 },
898 { EGL_TRANSPARENT_GREEN_VALUE, 0 },
899 { EGL_TRANSPARENT_RED_VALUE, 0 },
900 { EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE },
901 { EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE },
902 { EGL_MIN_SWAP_INTERVAL, 1 },
Mathias Agopian56fa2752009-09-27 20:18:16 -0700903 { EGL_MAX_SWAP_INTERVAL, 1 },
Mathias Agopian0985f6a2009-10-19 14:46:27 -0700904 { EGL_LUMINANCE_SIZE, 0 },
905 { EGL_ALPHA_MASK_SIZE, 0 },
906 { EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER },
Mathias Agopian56fa2752009-09-27 20:18:16 -0700907 { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT },
Mathias Agopian0985f6a2009-10-19 14:46:27 -0700908 { EGL_CONFORMANT, 0 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800909};
910
911// These configs can override the base attribute list
912// NOTE: when adding a config here, don't forget to update eglCreate*Surface()
913
Mathias Agopian8b6b95a2009-11-03 16:17:55 -0800914// 565 configs
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800915static config_pair_t const config_0_attribute_list[] = {
916 { EGL_BUFFER_SIZE, 16 },
917 { EGL_ALPHA_SIZE, 0 },
918 { EGL_BLUE_SIZE, 5 },
919 { EGL_GREEN_SIZE, 6 },
920 { EGL_RED_SIZE, 5 },
921 { EGL_DEPTH_SIZE, 0 },
922 { EGL_CONFIG_ID, 0 },
Mathias Agopiand8e5ceb2010-10-20 17:21:43 -0700923 { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800924 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
925};
926
927static config_pair_t const config_1_attribute_list[] = {
928 { EGL_BUFFER_SIZE, 16 },
929 { EGL_ALPHA_SIZE, 0 },
930 { EGL_BLUE_SIZE, 5 },
931 { EGL_GREEN_SIZE, 6 },
932 { EGL_RED_SIZE, 5 },
933 { EGL_DEPTH_SIZE, 16 },
934 { EGL_CONFIG_ID, 1 },
Mathias Agopiand8e5ceb2010-10-20 17:21:43 -0700935 { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800936 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
937};
938
Mathias Agopian8b6b95a2009-11-03 16:17:55 -0800939// RGB 888 configs
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800940static config_pair_t const config_2_attribute_list[] = {
941 { EGL_BUFFER_SIZE, 32 },
Mathias Agopian8b6b95a2009-11-03 16:17:55 -0800942 { EGL_ALPHA_SIZE, 0 },
943 { EGL_BLUE_SIZE, 8 },
944 { EGL_GREEN_SIZE, 8 },
945 { EGL_RED_SIZE, 8 },
946 { EGL_DEPTH_SIZE, 0 },
947 { EGL_CONFIG_ID, 6 },
Mathias Agopiand8e5ceb2010-10-20 17:21:43 -0700948 { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
Mathias Agopian8b6b95a2009-11-03 16:17:55 -0800949 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
950};
951
952static config_pair_t const config_3_attribute_list[] = {
953 { EGL_BUFFER_SIZE, 32 },
954 { EGL_ALPHA_SIZE, 0 },
955 { EGL_BLUE_SIZE, 8 },
956 { EGL_GREEN_SIZE, 8 },
957 { EGL_RED_SIZE, 8 },
958 { EGL_DEPTH_SIZE, 16 },
959 { EGL_CONFIG_ID, 7 },
Mathias Agopiand8e5ceb2010-10-20 17:21:43 -0700960 { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
Mathias Agopian8b6b95a2009-11-03 16:17:55 -0800961 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
962};
963
964// 8888 configs
965static config_pair_t const config_4_attribute_list[] = {
966 { EGL_BUFFER_SIZE, 32 },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800967 { EGL_ALPHA_SIZE, 8 },
968 { EGL_BLUE_SIZE, 8 },
969 { EGL_GREEN_SIZE, 8 },
970 { EGL_RED_SIZE, 8 },
971 { EGL_DEPTH_SIZE, 0 },
972 { EGL_CONFIG_ID, 2 },
Mathias Agopian6af358e2010-10-21 15:58:25 -0700973 { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800974 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
975};
976
Mathias Agopian8b6b95a2009-11-03 16:17:55 -0800977static config_pair_t const config_5_attribute_list[] = {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800978 { EGL_BUFFER_SIZE, 32 },
979 { EGL_ALPHA_SIZE, 8 },
980 { EGL_BLUE_SIZE, 8 },
981 { EGL_GREEN_SIZE, 8 },
982 { EGL_RED_SIZE, 8 },
983 { EGL_DEPTH_SIZE, 16 },
984 { EGL_CONFIG_ID, 3 },
Mathias Agopiand8e5ceb2010-10-20 17:21:43 -0700985 { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800986 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
987};
988
Mathias Agopian8b6b95a2009-11-03 16:17:55 -0800989// A8 configs
990static config_pair_t const config_6_attribute_list[] = {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800991 { EGL_BUFFER_SIZE, 8 },
992 { EGL_ALPHA_SIZE, 8 },
993 { EGL_BLUE_SIZE, 0 },
994 { EGL_GREEN_SIZE, 0 },
995 { EGL_RED_SIZE, 0 },
996 { EGL_DEPTH_SIZE, 0 },
997 { EGL_CONFIG_ID, 4 },
Mathias Agopiand8e5ceb2010-10-20 17:21:43 -0700998 { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800999 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
1000};
1001
Mathias Agopian8b6b95a2009-11-03 16:17:55 -08001002static config_pair_t const config_7_attribute_list[] = {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001003 { EGL_BUFFER_SIZE, 8 },
1004 { EGL_ALPHA_SIZE, 8 },
1005 { EGL_BLUE_SIZE, 0 },
1006 { EGL_GREEN_SIZE, 0 },
1007 { EGL_RED_SIZE, 0 },
1008 { EGL_DEPTH_SIZE, 16 },
1009 { EGL_CONFIG_ID, 5 },
Mathias Agopian6af358e2010-10-21 15:58:25 -07001010 { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001011 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
1012};
1013
1014static configs_t const gConfigs[] = {
1015 { config_0_attribute_list, NELEM(config_0_attribute_list) },
1016 { config_1_attribute_list, NELEM(config_1_attribute_list) },
1017 { config_2_attribute_list, NELEM(config_2_attribute_list) },
1018 { config_3_attribute_list, NELEM(config_3_attribute_list) },
1019 { config_4_attribute_list, NELEM(config_4_attribute_list) },
1020 { config_5_attribute_list, NELEM(config_5_attribute_list) },
Mathias Agopian8b6b95a2009-11-03 16:17:55 -08001021 { config_6_attribute_list, NELEM(config_6_attribute_list) },
1022 { config_7_attribute_list, NELEM(config_7_attribute_list) },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001023};
1024
1025static config_management_t const gConfigManagement[] = {
1026 { EGL_BUFFER_SIZE, config_management_t::atLeast },
1027 { EGL_ALPHA_SIZE, config_management_t::atLeast },
1028 { EGL_BLUE_SIZE, config_management_t::atLeast },
1029 { EGL_GREEN_SIZE, config_management_t::atLeast },
1030 { EGL_RED_SIZE, config_management_t::atLeast },
1031 { EGL_DEPTH_SIZE, config_management_t::atLeast },
1032 { EGL_STENCIL_SIZE, config_management_t::atLeast },
1033 { EGL_CONFIG_CAVEAT, config_management_t::exact },
1034 { EGL_CONFIG_ID, config_management_t::exact },
1035 { EGL_LEVEL, config_management_t::exact },
Mathias Agopian63971672010-10-25 15:51:24 -07001036 { EGL_MAX_PBUFFER_HEIGHT, config_management_t::ignore },
1037 { EGL_MAX_PBUFFER_PIXELS, config_management_t::ignore },
1038 { EGL_MAX_PBUFFER_WIDTH, config_management_t::ignore },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001039 { EGL_NATIVE_RENDERABLE, config_management_t::exact },
Mathias Agopian63971672010-10-25 15:51:24 -07001040 { EGL_NATIVE_VISUAL_ID, config_management_t::ignore },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001041 { EGL_NATIVE_VISUAL_TYPE, config_management_t::exact },
1042 { EGL_SAMPLES, config_management_t::exact },
1043 { EGL_SAMPLE_BUFFERS, config_management_t::exact },
1044 { EGL_SURFACE_TYPE, config_management_t::mask },
1045 { EGL_TRANSPARENT_TYPE, config_management_t::exact },
1046 { EGL_TRANSPARENT_BLUE_VALUE, config_management_t::exact },
1047 { EGL_TRANSPARENT_GREEN_VALUE, config_management_t::exact },
1048 { EGL_TRANSPARENT_RED_VALUE, config_management_t::exact },
1049 { EGL_BIND_TO_TEXTURE_RGBA, config_management_t::exact },
1050 { EGL_BIND_TO_TEXTURE_RGB, config_management_t::exact },
1051 { EGL_MIN_SWAP_INTERVAL, config_management_t::exact },
1052 { EGL_MAX_SWAP_INTERVAL, config_management_t::exact },
Mathias Agopian0985f6a2009-10-19 14:46:27 -07001053 { EGL_LUMINANCE_SIZE, config_management_t::atLeast },
1054 { EGL_ALPHA_MASK_SIZE, config_management_t::atLeast },
1055 { EGL_COLOR_BUFFER_TYPE, config_management_t::exact },
1056 { EGL_RENDERABLE_TYPE, config_management_t::mask },
1057 { EGL_CONFORMANT, config_management_t::mask }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001058};
1059
Mathias Agopian0985f6a2009-10-19 14:46:27 -07001060
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001061static config_pair_t const config_defaults[] = {
Mathias Agopian0985f6a2009-10-19 14:46:27 -07001062 // attributes that are not specified are simply ignored, if a particular
1063 // one needs not be ignored, it must be specified here, eg:
1064 // { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001065};
1066
1067// ----------------------------------------------------------------------------
1068
Mathias Agopian8b6b95a2009-11-03 16:17:55 -08001069static status_t getConfigFormatInfo(EGLint configID,
1070 int32_t& pixelFormat, int32_t& depthFormat)
1071{
1072 switch(configID) {
1073 case 0:
1074 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
1075 depthFormat = 0;
1076 break;
1077 case 1:
1078 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
1079 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1080 break;
1081 case 2:
1082 pixelFormat = GGL_PIXEL_FORMAT_RGBX_8888;
1083 depthFormat = 0;
1084 break;
1085 case 3:
1086 pixelFormat = GGL_PIXEL_FORMAT_RGBX_8888;
1087 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1088 break;
1089 case 4:
1090 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
1091 depthFormat = 0;
1092 break;
1093 case 5:
1094 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
1095 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1096 break;
1097 case 6:
1098 pixelFormat = GGL_PIXEL_FORMAT_A_8;
1099 depthFormat = 0;
1100 break;
1101 case 7:
1102 pixelFormat = GGL_PIXEL_FORMAT_A_8;
1103 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1104 break;
1105 default:
1106 return NAME_NOT_FOUND;
1107 }
1108 return NO_ERROR;
1109}
1110
1111// ----------------------------------------------------------------------------
1112
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001113template<typename T>
1114static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
1115{
1116 while (first <= last) {
1117 int mid = (first + last) / 2;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001118 if (key > sortedArray[mid].key) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001119 first = mid + 1;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001120 } else if (key < sortedArray[mid].key) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001121 last = mid - 1;
1122 } else {
1123 return mid;
1124 }
1125 }
1126 return -1;
1127}
1128
1129static int isAttributeMatching(int i, EGLint attr, EGLint val)
1130{
1131 // look for the attribute in all of our configs
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001132 config_pair_t const* configFound = gConfigs[i].array;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001133 int index = binarySearch<config_pair_t>(
1134 gConfigs[i].array,
1135 0, gConfigs[i].size-1,
1136 attr);
1137 if (index < 0) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001138 configFound = config_base_attribute_list;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001139 index = binarySearch<config_pair_t>(
1140 config_base_attribute_list,
1141 0, NELEM(config_base_attribute_list)-1,
1142 attr);
1143 }
1144 if (index >= 0) {
1145 // attribute found, check if this config could match
1146 int cfgMgtIndex = binarySearch<config_management_t>(
1147 gConfigManagement,
1148 0, NELEM(gConfigManagement)-1,
1149 attr);
Christoffer Gurell97640b92009-10-12 11:57:27 +02001150 if (cfgMgtIndex >= 0) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001151 bool match = gConfigManagement[cfgMgtIndex].match(
1152 val, configFound[index].value);
1153 if (match) {
1154 // this config matches
1155 return 1;
1156 }
1157 } else {
1158 // attribute not found. this should NEVER happen.
1159 }
1160 } else {
1161 // error, this attribute doesn't exist
1162 }
1163 return 0;
1164}
1165
1166static int makeCurrent(ogles_context_t* gl)
1167{
1168 ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();
1169 if (gl) {
1170 egl_context_t* c = egl_context_t::context(gl);
1171 if (c->flags & egl_context_t::IS_CURRENT) {
1172 if (current != gl) {
1173 // it is an error to set a context current, if it's already
1174 // current to another thread
1175 return -1;
1176 }
1177 } else {
1178 if (current) {
1179 // mark the current context as not current, and flush
1180 glFlush();
1181 egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
1182 }
1183 }
1184 if (!(c->flags & egl_context_t::IS_CURRENT)) {
1185 // The context is not current, make it current!
1186 setGlThreadSpecific(gl);
1187 c->flags |= egl_context_t::IS_CURRENT;
1188 }
1189 } else {
1190 if (current) {
1191 // mark the current context as not current, and flush
1192 glFlush();
1193 egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
1194 }
1195 // this thread has no context attached to it
1196 setGlThreadSpecific(0);
1197 }
1198 return 0;
1199}
1200
1201static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
1202 EGLint attribute, EGLint *value)
1203{
1204 size_t numConfigs = NELEM(gConfigs);
1205 int index = (int)config;
1206 if (uint32_t(index) >= numConfigs)
1207 return setError(EGL_BAD_CONFIG, EGL_FALSE);
1208
1209 int attrIndex;
1210 attrIndex = binarySearch<config_pair_t>(
1211 gConfigs[index].array,
1212 0, gConfigs[index].size-1,
1213 attribute);
1214 if (attrIndex>=0) {
1215 *value = gConfigs[index].array[attrIndex].value;
1216 return EGL_TRUE;
1217 }
1218
1219 attrIndex = binarySearch<config_pair_t>(
1220 config_base_attribute_list,
1221 0, NELEM(config_base_attribute_list)-1,
1222 attribute);
1223 if (attrIndex>=0) {
1224 *value = config_base_attribute_list[attrIndex].value;
1225 return EGL_TRUE;
1226 }
1227 return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1228}
1229
1230static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
1231 NativeWindowType window, const EGLint *attrib_list)
1232{
1233 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1234 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1235 if (window == 0)
1236 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1237
1238 EGLint surfaceType;
1239 if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
1240 return EGL_FALSE;
1241
1242 if (!(surfaceType & EGL_WINDOW_BIT))
1243 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1244
Dianne Hackborn4b5e91e2010-06-30 13:56:17 -07001245 if (static_cast<ANativeWindow*>(window)->common.magic !=
Mathias Agopian0696a572009-08-20 00:12:56 -07001246 ANDROID_NATIVE_WINDOW_MAGIC) {
1247 return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
1248 }
1249
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001250 EGLint configID;
1251 if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
1252 return EGL_FALSE;
1253
1254 int32_t depthFormat;
1255 int32_t pixelFormat;
Mathias Agopian8b6b95a2009-11-03 16:17:55 -08001256 if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001257 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1258 }
1259
1260 // FIXME: we don't have access to the pixelFormat here just yet.
1261 // (it's possible that the surface is not fully initialized)
1262 // maybe this should be done after the page-flip
1263 //if (EGLint(info.format) != pixelFormat)
1264 // return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1265
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001266 egl_surface_t* surface;
1267 surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
Dianne Hackborn4b5e91e2010-06-30 13:56:17 -07001268 static_cast<ANativeWindow*>(window));
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001269
Mathias Agopian0696a572009-08-20 00:12:56 -07001270 if (!surface->initCheck()) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001271 // there was a problem in the ctor, the error
1272 // flag has been set.
1273 delete surface;
1274 surface = 0;
1275 }
1276 return surface;
1277}
1278
1279static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
1280 NativePixmapType pixmap, const EGLint *attrib_list)
1281{
1282 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1283 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1284 if (pixmap == 0)
1285 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1286
1287 EGLint surfaceType;
1288 if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
1289 return EGL_FALSE;
1290
1291 if (!(surfaceType & EGL_PIXMAP_BIT))
1292 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1293
Mathias Agopian0696a572009-08-20 00:12:56 -07001294 if (static_cast<egl_native_pixmap_t*>(pixmap)->version !=
1295 sizeof(egl_native_pixmap_t)) {
1296 return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
1297 }
1298
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001299 EGLint configID;
1300 if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
1301 return EGL_FALSE;
1302
1303 int32_t depthFormat;
1304 int32_t pixelFormat;
Mathias Agopian8b6b95a2009-11-03 16:17:55 -08001305 if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001306 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1307 }
1308
1309 if (pixmap->format != pixelFormat)
1310 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1311
1312 egl_surface_t* surface =
1313 new egl_pixmap_surface_t(dpy, config, depthFormat,
1314 static_cast<egl_native_pixmap_t*>(pixmap));
1315
Mathias Agopian0696a572009-08-20 00:12:56 -07001316 if (!surface->initCheck()) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001317 // there was a problem in the ctor, the error
1318 // flag has been set.
1319 delete surface;
1320 surface = 0;
1321 }
1322 return surface;
1323}
1324
1325static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
1326 const EGLint *attrib_list)
1327{
1328 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1329 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1330
1331 EGLint surfaceType;
1332 if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
1333 return EGL_FALSE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001334
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001335 if (!(surfaceType & EGL_PBUFFER_BIT))
1336 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001337
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001338 EGLint configID;
1339 if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
1340 return EGL_FALSE;
1341
1342 int32_t depthFormat;
1343 int32_t pixelFormat;
Mathias Agopian8b6b95a2009-11-03 16:17:55 -08001344 if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001345 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1346 }
1347
1348 int32_t w = 0;
1349 int32_t h = 0;
1350 while (attrib_list[0]) {
1351 if (attrib_list[0] == EGL_WIDTH) w = attrib_list[1];
1352 if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
1353 attrib_list+=2;
1354 }
1355
1356 egl_surface_t* surface =
1357 new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
1358
Mathias Agopian0696a572009-08-20 00:12:56 -07001359 if (!surface->initCheck()) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001360 // there was a problem in the ctor, the error
1361 // flag has been set.
1362 delete surface;
1363 surface = 0;
1364 }
1365 return surface;
1366}
1367
1368// ----------------------------------------------------------------------------
1369}; // namespace android
1370// ----------------------------------------------------------------------------
1371
1372using namespace android;
1373
1374// ----------------------------------------------------------------------------
1375// Initialization
1376// ----------------------------------------------------------------------------
1377
1378EGLDisplay eglGetDisplay(NativeDisplayType display)
1379{
1380#ifndef HAVE_ANDROID_OS
1381 // this just needs to be done once
1382 if (gGLKey == -1) {
1383 pthread_mutex_lock(&gInitMutex);
1384 if (gGLKey == -1)
1385 pthread_key_create(&gGLKey, NULL);
1386 pthread_mutex_unlock(&gInitMutex);
1387 }
1388#endif
1389 if (display == EGL_DEFAULT_DISPLAY) {
1390 EGLDisplay dpy = (EGLDisplay)1;
1391 egl_display_t& d = egl_display_t::get_display(dpy);
1392 d.type = display;
1393 return dpy;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001394 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001395 return EGL_NO_DISPLAY;
1396}
1397
1398EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
1399{
1400 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1401 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001402
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001403 EGLBoolean res = EGL_TRUE;
1404 egl_display_t& d = egl_display_t::get_display(dpy);
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001405
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001406 if (android_atomic_inc(&d.initialized) == 0) {
1407 // initialize stuff here if needed
1408 //pthread_mutex_lock(&gInitMutex);
1409 //pthread_mutex_unlock(&gInitMutex);
1410 }
1411
1412 if (res == EGL_TRUE) {
1413 if (major != NULL) *major = VERSION_MAJOR;
1414 if (minor != NULL) *minor = VERSION_MINOR;
1415 }
1416 return res;
1417}
1418
1419EGLBoolean eglTerminate(EGLDisplay dpy)
1420{
1421 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1422 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1423
1424 EGLBoolean res = EGL_TRUE;
1425 egl_display_t& d = egl_display_t::get_display(dpy);
1426 if (android_atomic_dec(&d.initialized) == 1) {
1427 // TODO: destroy all resources (surfaces, contexts, etc...)
1428 //pthread_mutex_lock(&gInitMutex);
1429 //pthread_mutex_unlock(&gInitMutex);
1430 }
1431 return res;
1432}
1433
1434// ----------------------------------------------------------------------------
1435// configuration
1436// ----------------------------------------------------------------------------
1437
1438EGLBoolean eglGetConfigs( EGLDisplay dpy,
1439 EGLConfig *configs,
1440 EGLint config_size, EGLint *num_config)
1441{
1442 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1443 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1444
1445 GLint numConfigs = NELEM(gConfigs);
1446 if (!configs) {
1447 *num_config = numConfigs;
1448 return EGL_TRUE;
1449 }
1450 GLint i;
1451 for (i=0 ; i<numConfigs && i<config_size ; i++) {
1452 *configs++ = (EGLConfig)i;
1453 }
1454 *num_config = i;
1455 return EGL_TRUE;
1456}
1457
1458EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
1459 EGLConfig *configs, EGLint config_size,
1460 EGLint *num_config)
1461{
1462 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1463 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Jack Palevich749c63d2009-03-25 15:12:17 -07001464
1465 if (ggl_unlikely(num_config==0)) {
1466 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1467 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001468
Jack Palevich749c63d2009-03-25 15:12:17 -07001469 if (ggl_unlikely(attrib_list==0)) {
Mathias Agopian04aed212010-05-17 14:45:43 -07001470 /*
1471 * A NULL attrib_list should be treated as though it was an empty
1472 * one (terminated with EGL_NONE) as defined in
1473 * section 3.4.1 "Querying Configurations" in the EGL specification.
1474 */
1475 static const EGLint dummy = EGL_NONE;
1476 attrib_list = &dummy;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001477 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001478
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001479 int numAttributes = 0;
1480 int numConfigs = NELEM(gConfigs);
1481 uint32_t possibleMatch = (1<<numConfigs)-1;
1482 while(possibleMatch && *attrib_list != EGL_NONE) {
1483 numAttributes++;
1484 EGLint attr = *attrib_list++;
1485 EGLint val = *attrib_list++;
Mathias Agopian0985f6a2009-10-19 14:46:27 -07001486 for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001487 if (!(possibleMatch & (1<<i)))
1488 continue;
1489 if (isAttributeMatching(i, attr, val) == 0) {
1490 possibleMatch &= ~(1<<i);
1491 }
1492 }
1493 }
1494
1495 // now, handle the attributes which have a useful default value
Mathias Agopian0985f6a2009-10-19 14:46:27 -07001496 for (size_t j=0 ; possibleMatch && j<NELEM(config_defaults) ; j++) {
1497 // see if this attribute was specified, if not, apply its
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001498 // default value
1499 if (binarySearch<config_pair_t>(
1500 (config_pair_t const*)attrib_list,
Mathias Agopiandacd7a32009-07-09 17:33:15 -07001501 0, numAttributes-1,
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001502 config_defaults[j].key) < 0)
1503 {
Mathias Agopian0985f6a2009-10-19 14:46:27 -07001504 for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001505 if (!(possibleMatch & (1<<i)))
1506 continue;
1507 if (isAttributeMatching(i,
1508 config_defaults[j].key,
1509 config_defaults[j].value) == 0)
1510 {
1511 possibleMatch &= ~(1<<i);
1512 }
1513 }
1514 }
1515 }
1516
1517 // return the configurations found
1518 int n=0;
1519 if (possibleMatch) {
Jack Palevich749c63d2009-03-25 15:12:17 -07001520 if (configs) {
1521 for (int i=0 ; config_size && i<numConfigs ; i++) {
1522 if (possibleMatch & (1<<i)) {
1523 *configs++ = (EGLConfig)i;
1524 config_size--;
1525 n++;
1526 }
1527 }
1528 } else {
1529 for (int i=0 ; i<numConfigs ; i++) {
1530 if (possibleMatch & (1<<i)) {
1531 n++;
1532 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001533 }
1534 }
1535 }
1536 *num_config = n;
1537 return EGL_TRUE;
1538}
1539
1540EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
1541 EGLint attribute, EGLint *value)
1542{
1543 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1544 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1545
1546 return getConfigAttrib(dpy, config, attribute, value);
1547}
1548
1549// ----------------------------------------------------------------------------
1550// surfaces
1551// ----------------------------------------------------------------------------
1552
1553EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
1554 NativeWindowType window,
1555 const EGLint *attrib_list)
1556{
1557 return createWindowSurface(dpy, config, window, attrib_list);
1558}
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001559
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001560EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
1561 NativePixmapType pixmap,
1562 const EGLint *attrib_list)
1563{
1564 return createPixmapSurface(dpy, config, pixmap, attrib_list);
1565}
1566
1567EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
1568 const EGLint *attrib_list)
1569{
1570 return createPbufferSurface(dpy, config, attrib_list);
1571}
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001572
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001573EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
1574{
1575 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1576 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1577 if (eglSurface != EGL_NO_SURFACE) {
1578 egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
Mathias Agopian0696a572009-08-20 00:12:56 -07001579 if (!surface->isValid())
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001580 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1581 if (surface->dpy != dpy)
1582 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopiane71212b2009-05-05 00:37:46 -07001583 if (surface->ctx) {
Jesse Hall78141e32013-03-07 09:56:26 -08001584 // defer disconnect/delete until no longer current
1585 surface->zombie = true;
1586 } else {
Mathias Agopiane71212b2009-05-05 00:37:46 -07001587 surface->disconnect();
Jesse Hall78141e32013-03-07 09:56:26 -08001588 delete surface;
Mathias Agopiane71212b2009-05-05 00:37:46 -07001589 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001590 }
1591 return EGL_TRUE;
1592}
1593
1594EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
1595 EGLint attribute, EGLint *value)
1596{
1597 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1598 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1599 egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
Mathias Agopian0696a572009-08-20 00:12:56 -07001600 if (!surface->isValid())
1601 return setError(EGL_BAD_SURFACE, EGL_FALSE);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001602 if (surface->dpy != dpy)
1603 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1604
1605 EGLBoolean ret = EGL_TRUE;
1606 switch (attribute) {
1607 case EGL_CONFIG_ID:
1608 ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
1609 break;
1610 case EGL_WIDTH:
1611 *value = surface->getWidth();
1612 break;
1613 case EGL_HEIGHT:
1614 *value = surface->getHeight();
1615 break;
1616 case EGL_LARGEST_PBUFFER:
1617 // not modified for a window or pixmap surface
1618 break;
1619 case EGL_TEXTURE_FORMAT:
1620 *value = EGL_NO_TEXTURE;
1621 break;
1622 case EGL_TEXTURE_TARGET:
1623 *value = EGL_NO_TEXTURE;
1624 break;
1625 case EGL_MIPMAP_TEXTURE:
1626 *value = EGL_FALSE;
1627 break;
1628 case EGL_MIPMAP_LEVEL:
1629 *value = 0;
1630 break;
1631 case EGL_RENDER_BUFFER:
1632 // TODO: return the real RENDER_BUFFER here
1633 *value = EGL_BACK_BUFFER;
1634 break;
1635 case EGL_HORIZONTAL_RESOLUTION:
1636 // pixel/mm * EGL_DISPLAY_SCALING
1637 *value = surface->getHorizontalResolution();
1638 break;
1639 case EGL_VERTICAL_RESOLUTION:
1640 // pixel/mm * EGL_DISPLAY_SCALING
1641 *value = surface->getVerticalResolution();
1642 break;
1643 case EGL_PIXEL_ASPECT_RATIO: {
1644 // w/h * EGL_DISPLAY_SCALING
1645 int wr = surface->getHorizontalResolution();
1646 int hr = surface->getVerticalResolution();
1647 *value = (wr * EGL_DISPLAY_SCALING) / hr;
1648 } break;
1649 case EGL_SWAP_BEHAVIOR:
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001650 *value = surface->getSwapBehavior();
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001651 break;
1652 default:
1653 ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1654 }
1655 return ret;
1656}
1657
1658EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1659 EGLContext share_list, const EGLint *attrib_list)
1660{
1661 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1662 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1663
1664 ogles_context_t* gl = ogles_init(sizeof(egl_context_t));
1665 if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
1666
1667 egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
1668 c->flags = egl_context_t::NEVER_CURRENT;
1669 c->dpy = dpy;
1670 c->config = config;
1671 c->read = 0;
1672 c->draw = 0;
1673 return (EGLContext)gl;
1674}
1675
1676EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1677{
1678 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1679 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1680 egl_context_t* c = egl_context_t::context(ctx);
1681 if (c->flags & egl_context_t::IS_CURRENT)
1682 setGlThreadSpecific(0);
1683 ogles_uninit((ogles_context_t*)ctx);
1684 return EGL_TRUE;
1685}
1686
1687EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
1688 EGLSurface read, EGLContext ctx)
1689{
1690 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1691 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1692 if (draw) {
1693 egl_surface_t* s = (egl_surface_t*)draw;
Mathias Agopian0696a572009-08-20 00:12:56 -07001694 if (!s->isValid())
1695 return setError(EGL_BAD_SURFACE, EGL_FALSE);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001696 if (s->dpy != dpy)
1697 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian0696a572009-08-20 00:12:56 -07001698 // TODO: check that draw is compatible with the context
1699 }
1700 if (read && read!=draw) {
1701 egl_surface_t* s = (egl_surface_t*)read;
1702 if (!s->isValid())
1703 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1704 if (s->dpy != dpy)
1705 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1706 // TODO: check that read is compatible with the context
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001707 }
1708
1709 EGLContext current_ctx = EGL_NO_CONTEXT;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001710
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001711 if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
1712 return setError(EGL_BAD_MATCH, EGL_FALSE);
1713
1714 if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
1715 return setError(EGL_BAD_MATCH, EGL_FALSE);
1716
1717 if (ctx == EGL_NO_CONTEXT) {
1718 // if we're detaching, we need the current context
1719 current_ctx = (EGLContext)getGlThreadSpecific();
1720 } else {
1721 egl_context_t* c = egl_context_t::context(ctx);
1722 egl_surface_t* d = (egl_surface_t*)draw;
1723 egl_surface_t* r = (egl_surface_t*)read;
1724 if ((d && d->ctx && d->ctx != ctx) ||
1725 (r && r->ctx && r->ctx != ctx)) {
Mathias Agopiane71212b2009-05-05 00:37:46 -07001726 // one of the surface is bound to a context in another thread
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001727 return setError(EGL_BAD_ACCESS, EGL_FALSE);
1728 }
1729 }
1730
1731 ogles_context_t* gl = (ogles_context_t*)ctx;
1732 if (makeCurrent(gl) == 0) {
1733 if (ctx) {
1734 egl_context_t* c = egl_context_t::context(ctx);
1735 egl_surface_t* d = (egl_surface_t*)draw;
1736 egl_surface_t* r = (egl_surface_t*)read;
Mathias Agopiane71212b2009-05-05 00:37:46 -07001737
1738 if (c->draw) {
Mathias Agopian0696a572009-08-20 00:12:56 -07001739 egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
1740 s->disconnect();
Jesse Hall78141e32013-03-07 09:56:26 -08001741 s->ctx = EGL_NO_CONTEXT;
1742 if (s->zombie)
1743 delete s;
Mathias Agopiane71212b2009-05-05 00:37:46 -07001744 }
1745 if (c->read) {
1746 // FIXME: unlock/disconnect the read surface too
1747 }
1748
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001749 c->draw = draw;
Mathias Agopiane71212b2009-05-05 00:37:46 -07001750 c->read = read;
1751
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001752 if (c->flags & egl_context_t::NEVER_CURRENT) {
1753 c->flags &= ~egl_context_t::NEVER_CURRENT;
1754 GLint w = 0;
1755 GLint h = 0;
1756 if (draw) {
1757 w = d->getWidth();
1758 h = d->getHeight();
1759 }
1760 ogles_surfaceport(gl, 0, 0);
1761 ogles_viewport(gl, 0, 0, w, h);
1762 ogles_scissor(gl, 0, 0, w, h);
1763 }
1764 if (d) {
Mathias Agopiancf81c842009-07-31 14:47:00 -07001765 if (d->connect() == EGL_FALSE) {
1766 return EGL_FALSE;
1767 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001768 d->ctx = ctx;
1769 d->bindDrawSurface(gl);
1770 }
1771 if (r) {
Mathias Agopiane71212b2009-05-05 00:37:46 -07001772 // FIXME: lock/connect the read surface too
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001773 r->ctx = ctx;
1774 r->bindReadSurface(gl);
1775 }
1776 } else {
1777 // if surfaces were bound to the context bound to this thread
1778 // mark then as unbound.
1779 if (current_ctx) {
1780 egl_context_t* c = egl_context_t::context(current_ctx);
1781 egl_surface_t* d = (egl_surface_t*)c->draw;
1782 egl_surface_t* r = (egl_surface_t*)c->read;
Mathias Agopiane71212b2009-05-05 00:37:46 -07001783 if (d) {
Mathias Agopian9648c1a2009-06-03 19:00:53 -07001784 c->draw = 0;
Mathias Agopiane71212b2009-05-05 00:37:46 -07001785 d->disconnect();
Jesse Hall78141e32013-03-07 09:56:26 -08001786 d->ctx = EGL_NO_CONTEXT;
1787 if (d->zombie)
1788 delete d;
Mathias Agopiane71212b2009-05-05 00:37:46 -07001789 }
1790 if (r) {
Mathias Agopian9648c1a2009-06-03 19:00:53 -07001791 c->read = 0;
Mathias Agopiane71212b2009-05-05 00:37:46 -07001792 r->ctx = EGL_NO_CONTEXT;
1793 // FIXME: unlock/disconnect the read surface too
1794 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001795 }
1796 }
1797 return EGL_TRUE;
1798 }
1799 return setError(EGL_BAD_ACCESS, EGL_FALSE);
1800}
1801
1802EGLContext eglGetCurrentContext(void)
1803{
1804 // eglGetCurrentContext returns the current EGL rendering context,
1805 // as specified by eglMakeCurrent. If no context is current,
1806 // EGL_NO_CONTEXT is returned.
1807 return (EGLContext)getGlThreadSpecific();
1808}
1809
1810EGLSurface eglGetCurrentSurface(EGLint readdraw)
1811{
1812 // eglGetCurrentSurface returns the read or draw surface attached
1813 // to the current EGL rendering context, as specified by eglMakeCurrent.
1814 // If no context is current, EGL_NO_SURFACE is returned.
1815 EGLContext ctx = (EGLContext)getGlThreadSpecific();
1816 if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
1817 egl_context_t* c = egl_context_t::context(ctx);
1818 if (readdraw == EGL_READ) {
1819 return c->read;
1820 } else if (readdraw == EGL_DRAW) {
1821 return c->draw;
1822 }
1823 return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
1824}
1825
1826EGLDisplay eglGetCurrentDisplay(void)
1827{
1828 // eglGetCurrentDisplay returns the current EGL display connection
1829 // for the current EGL rendering context, as specified by eglMakeCurrent.
1830 // If no context is current, EGL_NO_DISPLAY is returned.
1831 EGLContext ctx = (EGLContext)getGlThreadSpecific();
1832 if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
1833 egl_context_t* c = egl_context_t::context(ctx);
1834 return c->dpy;
1835}
1836
1837EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1838 EGLint attribute, EGLint *value)
1839{
1840 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1841 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1842 egl_context_t* c = egl_context_t::context(ctx);
1843 switch (attribute) {
1844 case EGL_CONFIG_ID:
1845 // Returns the ID of the EGL frame buffer configuration with
1846 // respect to which the context was created
1847 return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
1848 }
1849 return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1850}
1851
1852EGLBoolean eglWaitGL(void)
1853{
1854 return EGL_TRUE;
1855}
1856
1857EGLBoolean eglWaitNative(EGLint engine)
1858{
1859 return EGL_TRUE;
1860}
1861
1862EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1863{
1864 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1865 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001866
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001867 egl_surface_t* d = static_cast<egl_surface_t*>(draw);
Mathias Agopian0696a572009-08-20 00:12:56 -07001868 if (!d->isValid())
1869 return setError(EGL_BAD_SURFACE, EGL_FALSE);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001870 if (d->dpy != dpy)
1871 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1872
1873 // post the surface
1874 d->swapBuffers();
1875
1876 // if it's bound to a context, update the buffer
1877 if (d->ctx != EGL_NO_CONTEXT) {
1878 d->bindDrawSurface((ogles_context_t*)d->ctx);
1879 // if this surface is also the read surface of the context
1880 // it is bound to, make sure to update the read buffer as well.
1881 // The EGL spec is a little unclear about this.
1882 egl_context_t* c = egl_context_t::context(d->ctx);
1883 if (c->read == draw) {
1884 d->bindReadSurface((ogles_context_t*)d->ctx);
1885 }
1886 }
1887
1888 return EGL_TRUE;
1889}
1890
1891EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1892 NativePixmapType target)
1893{
1894 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1895 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1896 // TODO: eglCopyBuffers()
1897 return EGL_FALSE;
1898}
1899
1900EGLint eglGetError(void)
1901{
1902 return getError();
1903}
1904
1905const char* eglQueryString(EGLDisplay dpy, EGLint name)
1906{
1907 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1908 return setError(EGL_BAD_DISPLAY, (const char*)0);
1909
1910 switch (name) {
1911 case EGL_VENDOR:
1912 return gVendorString;
1913 case EGL_VERSION:
1914 return gVersionString;
1915 case EGL_EXTENSIONS:
1916 return gExtensionsString;
1917 case EGL_CLIENT_APIS:
1918 return gClientApiString;
1919 }
1920 return setError(EGL_BAD_PARAMETER, (const char *)0);
1921}
1922
1923// ----------------------------------------------------------------------------
1924// EGL 1.1
1925// ----------------------------------------------------------------------------
1926
1927EGLBoolean eglSurfaceAttrib(
1928 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1929{
1930 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1931 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1932 // TODO: eglSurfaceAttrib()
1933 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1934}
1935
1936EGLBoolean eglBindTexImage(
1937 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1938{
1939 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1940 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1941 // TODO: eglBindTexImage()
1942 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1943}
1944
1945EGLBoolean eglReleaseTexImage(
1946 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1947{
1948 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1949 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1950 // TODO: eglReleaseTexImage()
1951 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1952}
1953
1954EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1955{
1956 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1957 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1958 // TODO: eglSwapInterval()
Ari Hirvonen551dc262010-10-01 19:00:54 +03001959 return EGL_TRUE;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001960}
1961
1962// ----------------------------------------------------------------------------
1963// EGL 1.2
1964// ----------------------------------------------------------------------------
1965
1966EGLBoolean eglBindAPI(EGLenum api)
1967{
1968 if (api != EGL_OPENGL_ES_API)
1969 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1970 return EGL_TRUE;
1971}
1972
1973EGLenum eglQueryAPI(void)
1974{
1975 return EGL_OPENGL_ES_API;
1976}
1977
1978EGLBoolean eglWaitClient(void)
1979{
1980 glFinish();
1981 return EGL_TRUE;
1982}
1983
1984EGLBoolean eglReleaseThread(void)
1985{
1986 // TODO: eglReleaseThread()
1987 return EGL_TRUE;
1988}
1989
1990EGLSurface eglCreatePbufferFromClientBuffer(
1991 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1992 EGLConfig config, const EGLint *attrib_list)
1993{
1994 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1995 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1996 // TODO: eglCreatePbufferFromClientBuffer()
1997 return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1998}
1999
2000// ----------------------------------------------------------------------------
Mathias Agopian076b1cc2009-04-10 14:24:30 -07002001// EGL_EGLEXT_VERSION 3
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08002002// ----------------------------------------------------------------------------
2003
2004void (*eglGetProcAddress (const char *procname))()
2005{
2006 extention_map_t const * const map = gExtentionMap;
2007 for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
2008 if (!strcmp(procname, map[i].name)) {
2009 return map[i].address;
2010 }
2011 }
2012 return NULL;
2013}
Mathias Agopian076b1cc2009-04-10 14:24:30 -07002014
2015EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
2016 const EGLint *attrib_list)
2017{
2018 EGLBoolean result = EGL_FALSE;
2019 return result;
2020}
2021
2022EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
2023{
2024 EGLBoolean result = EGL_FALSE;
2025 return result;
2026}
2027
2028EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
2029 EGLClientBuffer buffer, const EGLint *attrib_list)
2030{
2031 if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
2032 return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
2033 }
2034 if (ctx != EGL_NO_CONTEXT) {
2035 return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
2036 }
2037 if (target != EGL_NATIVE_BUFFER_ANDROID) {
2038 return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
2039 }
2040
Iliyan Malchev697526b2011-05-01 11:33:26 -07002041 ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)buffer;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07002042
2043 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
2044 return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
2045
Iliyan Malchev697526b2011-05-01 11:33:26 -07002046 if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
Mathias Agopian076b1cc2009-04-10 14:24:30 -07002047 return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
Mathias Agopian8dccb262010-02-04 17:04:53 -08002048
2049 switch (native_buffer->format) {
2050 case HAL_PIXEL_FORMAT_RGBA_8888:
2051 case HAL_PIXEL_FORMAT_RGBX_8888:
2052 case HAL_PIXEL_FORMAT_RGB_888:
2053 case HAL_PIXEL_FORMAT_RGB_565:
2054 case HAL_PIXEL_FORMAT_BGRA_8888:
2055 case HAL_PIXEL_FORMAT_RGBA_5551:
2056 case HAL_PIXEL_FORMAT_RGBA_4444:
2057 break;
2058 default:
2059 return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
2060 }
2061
Mathias Agopian076b1cc2009-04-10 14:24:30 -07002062 native_buffer->common.incRef(&native_buffer->common);
2063 return (EGLImageKHR)native_buffer;
2064}
2065
2066EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
2067{
2068 if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
2069 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
2070 }
2071
Iliyan Malchev697526b2011-05-01 11:33:26 -07002072 ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)img;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07002073
2074 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
2075 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
2076
Iliyan Malchev697526b2011-05-01 11:33:26 -07002077 if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
Mathias Agopian076b1cc2009-04-10 14:24:30 -07002078 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
2079
Mathias Agopian076b1cc2009-04-10 14:24:30 -07002080 native_buffer->common.decRef(&native_buffer->common);
2081
2082 return EGL_TRUE;
2083}
Mathias Agopiandf3ca302009-05-04 19:29:25 -07002084
2085// ----------------------------------------------------------------------------
Jesse Hall83e7c8c2012-05-22 10:42:56 -07002086// EGL_KHR_fence_sync
2087// ----------------------------------------------------------------------------
2088
2089#define FENCE_SYNC_HANDLE ((EGLSyncKHR)0xFE4CE)
2090
2091EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type,
2092 const EGLint *attrib_list)
2093{
2094 if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
2095 return setError(EGL_BAD_DISPLAY, EGL_NO_SYNC_KHR);
2096 }
2097
2098 if (type != EGL_SYNC_FENCE_KHR ||
2099 (attrib_list != NULL && attrib_list[0] != EGL_NONE)) {
2100 return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
2101 }
2102
2103 if (eglGetCurrentContext() == EGL_NO_CONTEXT) {
2104 return setError(EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
2105 }
2106
2107 // AGL is synchronous; nothing to do here.
2108
2109 return FENCE_SYNC_HANDLE;
2110}
2111
2112EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
2113{
2114 if (sync != FENCE_SYNC_HANDLE) {
2115 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
2116 }
2117
2118 return EGL_TRUE;
2119}
2120
2121EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags,
2122 EGLTimeKHR timeout)
2123{
2124 if (sync != FENCE_SYNC_HANDLE) {
2125 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
2126 }
2127
2128 return EGL_CONDITION_SATISFIED_KHR;
2129}
2130
2131EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync,
2132 EGLint attribute, EGLint *value)
2133{
2134 if (sync != FENCE_SYNC_HANDLE) {
2135 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
2136 }
2137
2138 switch (attribute) {
2139 case EGL_SYNC_TYPE_KHR:
2140 *value = EGL_SYNC_FENCE_KHR;
2141 return EGL_TRUE;
2142 case EGL_SYNC_STATUS_KHR:
2143 *value = EGL_SIGNALED_KHR;
2144 return EGL_TRUE;
2145 case EGL_SYNC_CONDITION_KHR:
2146 *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
2147 return EGL_TRUE;
2148 default:
2149 return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
2150 }
2151}
2152
2153// ----------------------------------------------------------------------------
Mathias Agopiandf3ca302009-05-04 19:29:25 -07002154// ANDROID extensions
2155// ----------------------------------------------------------------------------
2156
2157EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
2158 EGLint left, EGLint top, EGLint width, EGLint height)
2159{
2160 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
2161 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
2162
2163 egl_surface_t* d = static_cast<egl_surface_t*>(draw);
Mathias Agopian0696a572009-08-20 00:12:56 -07002164 if (!d->isValid())
2165 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopiandf3ca302009-05-04 19:29:25 -07002166 if (d->dpy != dpy)
2167 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
2168
2169 // post the surface
2170 d->setSwapRectangle(left, top, width, height);
2171
2172 return EGL_TRUE;
2173}