blob: f6ffc53cfba830437c8b3cda1b3a8c5dff3b74af [file] [log] [blame]
Mathias Agopian1473f462009-04-10 14:24:30 -07001/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002**
3** Copyright 2007 The Android Open Source Project
4**
Mathias Agopian1473f462009-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 Project9066cfe2009-03-03 19:31:44 -08008**
Mathias Agopian1473f462009-04-10 14:24:30 -07009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010**
Mathias Agopian1473f462009-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 Project9066cfe2009-03-03 19:31:44 -080015** limitations under the License.
16*/
17
The Android Open Source Project9066cfe2009-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>
33
34#include <EGL/egl.h>
35#include <EGL/eglext.h>
36#include <GLES/gl.h>
37#include <GLES/glext.h>
38
39#include <pixelflinger/format.h>
40#include <pixelflinger/pixelflinger.h>
41
Mathias Agopianb51e18d2009-05-05 18:21:32 -070042#include <private/ui/android_natives_priv.h>
Mathias Agopianac2523b2009-05-05 18:11:11 -070043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044#include "context.h"
45#include "state.h"
46#include "texture.h"
47#include "matrix.h"
48
Mathias Agopian1473f462009-04-10 14:24:30 -070049#ifdef LIBAGL_USE_GRALLOC_COPYBITS
50#include "gralloc_priv.h"
51#endif // LIBAGL_USE_GRALLOC_COPYBITS
52
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053#undef NELEM
54#define NELEM(x) (sizeof(x)/sizeof(*(x)))
55
56// ----------------------------------------------------------------------------
57namespace android {
58// ----------------------------------------------------------------------------
59
60const unsigned int NUM_DISPLAYS = 1;
61
62static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
63static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
64static pthread_key_t gEGLErrorKey = -1;
65#ifndef HAVE_ANDROID_OS
66namespace gl {
67pthread_key_t gGLKey = -1;
68}; // namespace gl
69#endif
70
71template<typename T>
72static T setError(GLint error, T returnValue) {
73 if (ggl_unlikely(gEGLErrorKey == -1)) {
74 pthread_mutex_lock(&gErrorKeyMutex);
75 if (gEGLErrorKey == -1)
76 pthread_key_create(&gEGLErrorKey, NULL);
77 pthread_mutex_unlock(&gErrorKeyMutex);
78 }
79 pthread_setspecific(gEGLErrorKey, (void*)error);
80 return returnValue;
81}
82
83static GLint getError() {
84 if (ggl_unlikely(gEGLErrorKey == -1))
85 return EGL_SUCCESS;
86 GLint error = (GLint)pthread_getspecific(gEGLErrorKey);
87 pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS);
88 return error;
89}
90
91// ----------------------------------------------------------------------------
92
93struct egl_display_t
94{
95 egl_display_t() : type(0), initialized(0) { }
Mathias Agopian1473f462009-04-10 14:24:30 -070096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 static egl_display_t& get_display(EGLDisplay dpy);
Mathias Agopian1473f462009-04-10 14:24:30 -070098
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 static EGLBoolean is_valid(EGLDisplay dpy) {
100 return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
101 }
102
103 NativeDisplayType type;
104 volatile int32_t initialized;
105};
106
107static egl_display_t gDisplays[NUM_DISPLAYS];
108
109egl_display_t& egl_display_t::get_display(EGLDisplay dpy) {
110 return gDisplays[uintptr_t(dpy)-1U];
111}
112
113struct egl_context_t {
114 enum {
115 IS_CURRENT = 0x00010000,
116 NEVER_CURRENT = 0x00020000
117 };
118 uint32_t flags;
119 EGLDisplay dpy;
120 EGLConfig config;
121 EGLSurface read;
122 EGLSurface draw;
123
124 static inline egl_context_t* context(EGLContext ctx) {
125 ogles_context_t* const gl = static_cast<ogles_context_t*>(ctx);
126 return static_cast<egl_context_t*>(gl->rasterizer.base);
127 }
128};
129
130// ----------------------------------------------------------------------------
131
132struct egl_surface_t
133{
134 enum {
135 PAGE_FLIP = 0x00000001,
136 MAGIC = 0x31415265
137 };
138
139 uint32_t magic;
140 EGLDisplay dpy;
141 EGLConfig config;
142 EGLContext ctx;
143
144 egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
145 virtual ~egl_surface_t();
146 virtual bool isValid() const = 0;
Mathias Agopian1473f462009-04-10 14:24:30 -0700147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl) = 0;
149 virtual EGLBoolean bindReadSurface(ogles_context_t* gl) = 0;
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700150 virtual void connect() {}
151 virtual void disconnect() {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 virtual EGLint getWidth() const = 0;
153 virtual EGLint getHeight() const = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154
155 virtual EGLint getHorizontalResolution() const;
156 virtual EGLint getVerticalResolution() const;
157 virtual EGLint getRefreshRate() const;
158 virtual EGLint getSwapBehavior() const;
159 virtual EGLBoolean swapBuffers();
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700160 virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700161 virtual EGLClientBuffer getRenderBuffer() const;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162protected:
163 GGLSurface depth;
164};
165
166egl_surface_t::egl_surface_t(EGLDisplay dpy,
167 EGLConfig config,
168 int32_t depthFormat)
169 : magic(MAGIC), dpy(dpy), config(config), ctx(0)
170{
171 depth.version = sizeof(GGLSurface);
172 depth.data = 0;
173 depth.format = depthFormat;
174}
175egl_surface_t::~egl_surface_t()
176{
177 magic = 0;
178 free(depth.data);
179}
180EGLBoolean egl_surface_t::swapBuffers() {
181 return EGL_FALSE;
182}
183EGLint egl_surface_t::getHorizontalResolution() const {
184 return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
185}
186EGLint egl_surface_t::getVerticalResolution() const {
187 return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
188}
189EGLint egl_surface_t::getRefreshRate() const {
190 return (60 * EGL_DISPLAY_SCALING);
191}
192EGLint egl_surface_t::getSwapBehavior() const {
193 return EGL_BUFFER_PRESERVED;
194}
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700195EGLBoolean egl_surface_t::setSwapRectangle(
196 EGLint l, EGLint t, EGLint w, EGLint h)
197{
198 return EGL_FALSE;
199}
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700200EGLClientBuffer egl_surface_t::getRenderBuffer() const {
201 return 0;
202}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
204// ----------------------------------------------------------------------------
205
Mathias Agopian1473f462009-04-10 14:24:30 -0700206struct egl_window_surface_v2_t : public egl_surface_t
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207{
Mathias Agopian1473f462009-04-10 14:24:30 -0700208 egl_window_surface_v2_t(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 EGLDisplay dpy, EGLConfig config,
210 int32_t depthFormat,
Mathias Agopian1473f462009-04-10 14:24:30 -0700211 android_native_window_t* window);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212
Mathias Agopian1473f462009-04-10 14:24:30 -0700213 ~egl_window_surface_v2_t();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214
Mathias Agopian1473f462009-04-10 14:24:30 -0700215 virtual bool isValid() const { return nativeWindow->common.magic == ANDROID_NATIVE_WINDOW_MAGIC; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 virtual EGLBoolean swapBuffers();
217 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
218 virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700219 virtual void connect();
220 virtual void disconnect();
Mathias Agopian1473f462009-04-10 14:24:30 -0700221 virtual EGLint getWidth() const { return buffer->width; }
222 virtual EGLint getHeight() const { return buffer->height; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 virtual EGLint getHorizontalResolution() const;
224 virtual EGLint getVerticalResolution() const;
225 virtual EGLint getRefreshRate() const;
226 virtual EGLint getSwapBehavior() const;
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700227 virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700228 virtual EGLClientBuffer getRenderBuffer() const;
229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230private:
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700231 status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
Mathias Agopiandff8e582009-05-04 14:17:04 -0700232 status_t unlock(android_native_buffer_t* buf);
Mathias Agopian1473f462009-04-10 14:24:30 -0700233 android_native_window_t* nativeWindow;
234 android_native_buffer_t* buffer;
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700235 android_native_buffer_t* previousBuffer;
Mathias Agopiandff8e582009-05-04 14:17:04 -0700236 gralloc_module_t const* module;
Mathias Agopian1473f462009-04-10 14:24:30 -0700237 int width;
238 int height;
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700239 void* bits;
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700240 GGLFormat const* pixelFormatTable;
241
242 struct Rect {
243 inline Rect() { };
244 inline Rect(int32_t w, int32_t h)
245 : left(0), top(0), right(w), bottom(h) { }
246 inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
247 : left(l), top(t), right(r), bottom(b) { }
248 Rect& andSelf(const Rect& r) {
249 left = max(left, r.left);
250 top = max(top, r.top);
251 right = min(right, r.right);
252 bottom = min(bottom, r.bottom);
253 return *this;
254 }
255 bool isEmpty() const {
256 return (left>=right || top>=bottom);
257 }
258 void dump(char const* what) {
259 LOGD("%s { %5d, %5d, w=%5d, h=%5d }",
260 what, left, top, right-left, bottom-top);
261 }
262
263 int32_t left;
264 int32_t top;
265 int32_t right;
266 int32_t bottom;
267 };
268
269 struct Region {
270 inline Region() : count(0) { }
271 static Region subtract(const Rect& lhs, const Rect& rhs) {
272 Region reg;
273 Rect* storage = reg.storage;
274 if (!lhs.isEmpty()) {
275 if (lhs.top < rhs.top) { // top rect
276 storage->left = lhs.left;
277 storage->top = lhs.top;
278 storage->right = lhs.right;
279 storage->bottom = max(lhs.top, rhs.top);
280 storage++;
281 }
282 if (lhs.left < rhs.left) { // left-side rect
283 storage->left = lhs.left;
284 storage->top = max(lhs.top, rhs.top);
285 storage->right = max(lhs.left, rhs.left);
286 storage->bottom = min(lhs.bottom, rhs.bottom);
287 storage++;
288 }
289 if (lhs.right > rhs.right) { // right-side rect
290 storage->left = min(lhs.right, rhs.right);
291 storage->top = max(lhs.top, rhs.top);
292 storage->right = lhs.right;
293 storage->bottom = min(lhs.bottom, rhs.bottom);
294 storage++;
295 }
296 if (lhs.bottom > rhs.bottom) { // bottom rect
297 storage->left = lhs.left;
298 storage->top = min(lhs.bottom, rhs.bottom);
299 storage->right = lhs.right;
300 storage->bottom = lhs.bottom;
301 storage++;
302 }
303 reg.count = storage - reg.storage;
304 }
305 return reg;
306 }
307 bool isEmpty() const {
308 return count<=0;
309 }
310 ssize_t getRects(Rect const* * rects) const {
311 *rects = storage;
312 return count;
313 }
314 private:
315 Rect storage[4];
316 ssize_t count;
317 };
318
319 void copyBlt(
320 android_native_buffer_t* dst, void* dst_vaddr,
321 android_native_buffer_t* src, void const* src_vaddr,
322 const Rect* reg, ssize_t count);
323
324 Rect dirtyRegion;
325 Rect oldDirtyRegion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326};
327
Mathias Agopian1473f462009-04-10 14:24:30 -0700328egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 EGLConfig config,
330 int32_t depthFormat,
Mathias Agopian1473f462009-04-10 14:24:30 -0700331 android_native_window_t* window)
Mathias Agopiandff8e582009-05-04 14:17:04 -0700332 : egl_surface_t(dpy, config, depthFormat),
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700333 nativeWindow(window), buffer(0), previousBuffer(0), module(0),
334 bits(NULL)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335{
Mathias Agopiandff8e582009-05-04 14:17:04 -0700336 hw_module_t const* pModule;
337 hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
338 module = reinterpret_cast<gralloc_module_t const*>(pModule);
339
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700340 pixelFormatTable = gglGetPixelFormatTable();
341
342 // keep a reference on the window
Mathias Agopian1473f462009-04-10 14:24:30 -0700343 nativeWindow->common.incRef(&nativeWindow->common);
344
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700345 // dequeue a buffer
Mathias Agopian1473f462009-04-10 14:24:30 -0700346 nativeWindow->dequeueBuffer(nativeWindow, &buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700347
348 // allocate a corresponding depth-buffer
Mathias Agopian1473f462009-04-10 14:24:30 -0700349 width = buffer->width;
350 height = buffer->height;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 if (depthFormat) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700352 depth.width = width;
353 depth.height = height;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 depth.stride = depth.width; // use the width here
355 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
356 if (depth.data == 0) {
357 setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
358 return;
359 }
360 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700361
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700362 // keep a reference on the buffer
Mathias Agopian1473f462009-04-10 14:24:30 -0700363 buffer->common.incRef(&buffer->common);
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700364}
Mathias Agopian1473f462009-04-10 14:24:30 -0700365
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700366egl_window_surface_v2_t::~egl_window_surface_v2_t() {
367 if (buffer) {
368 buffer->common.decRef(&buffer->common);
369 }
370 if (previousBuffer) {
371 previousBuffer->common.decRef(&previousBuffer->common);
372 }
373 nativeWindow->common.decRef(&nativeWindow->common);
374}
375
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700376void egl_window_surface_v2_t::connect()
377{
Mathias Agopiandff8e582009-05-04 14:17:04 -0700378 // Lock the buffer
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700379 nativeWindow->lockBuffer(nativeWindow, buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700380 // pin the buffer down
381 if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
382 GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
383 LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
384 buffer, buffer->width, buffer->height);
385 setError(EGL_BAD_ACCESS, EGL_NO_SURFACE);
386 // FIXME: we should make sure we're not accessing the buffer anymore
387 }
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700388}
389
390void egl_window_surface_v2_t::disconnect()
391{
Mathias Agopian36432cc2009-06-03 19:00:53 -0700392 if (buffer && bits) {
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700393 bits = NULL;
394 unlock(buffer);
395 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396}
397
Mathias Agopiandff8e582009-05-04 14:17:04 -0700398status_t egl_window_surface_v2_t::lock(
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700399 android_native_buffer_t* buf, int usage, void** vaddr)
Mathias Agopiandff8e582009-05-04 14:17:04 -0700400{
Mathias Agopiane633f932009-05-05 00:59:23 -0700401 int err = module->lock(module, buf->handle,
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700402 usage, 0, 0, buf->width, buf->height, vaddr);
Mathias Agopiandff8e582009-05-04 14:17:04 -0700403 return err;
404}
405
406status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
407{
Mathias Agopiane633f932009-05-05 00:59:23 -0700408 int err = module->unlock(module, buf->handle);
Mathias Agopiandff8e582009-05-04 14:17:04 -0700409 return err;
410}
411
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700412void egl_window_surface_v2_t::copyBlt(
413 android_native_buffer_t* dst, void* dst_vaddr,
414 android_native_buffer_t* src, void const* src_vaddr,
415 const Rect* reg, ssize_t count)
416{
417 // FIXME: use copybit if possible
418 // NOTE: dst and src must be the same format
419
420 Rect r;
421 const size_t bpp = pixelFormatTable[src->format].size;
422 const size_t dbpr = dst->stride * bpp;
423 const size_t sbpr = src->stride * bpp;
Mathias Agopiandff8e582009-05-04 14:17:04 -0700424
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700425 uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
426 uint8_t * const dst_bits = (uint8_t *)dst_vaddr;
427
428 for (int i= 0 ; i<count ; i++) {
429 const Rect& r(reg[i]);
430 ssize_t w = r.right - r.left;
431 ssize_t h = r.bottom - r.top;
432 if (w <= 0 || h<=0) continue;
433 size_t size = w * bpp;
434 uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
435 uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
436 if (dbpr==sbpr && size==sbpr) {
437 size *= h;
438 h = 1;
439 }
440 do {
441 memcpy(d, s, size);
442 d += dbpr;
443 s += sbpr;
444 } while (--h > 0);
Mathias Agopian1473f462009-04-10 14:24:30 -0700445 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700446}
447
448EGLBoolean egl_window_surface_v2_t::swapBuffers()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449{
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700450 /*
451 * Handle eglSetSwapRectangleANDROID()
452 * We copyback from the front buffer
453 */
454 if (!dirtyRegion.isEmpty()) {
455 dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
456 if (previousBuffer) {
457 const Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
458 if (!copyBack.isEmpty()) {
459 Rect const* list;
460 ssize_t count = copyBack.getRects(&list);
461 // copy from previousBuffer to buffer
462 void* prevBits;
463 if (lock(previousBuffer,
464 GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR)
465 {
466 copyBlt(buffer, bits, previousBuffer, prevBits, list, count);
467 unlock(previousBuffer);
468 }
469 }
470 }
471 oldDirtyRegion = dirtyRegion;
472 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700473
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700474 if (previousBuffer) {
475 previousBuffer->common.decRef(&previousBuffer->common);
476 previousBuffer = 0;
477 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700478
Mathias Agopiandff8e582009-05-04 14:17:04 -0700479 unlock(buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700480 previousBuffer = buffer;
Mathias Agopian1473f462009-04-10 14:24:30 -0700481 nativeWindow->queueBuffer(nativeWindow, buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700482 buffer = 0;
Mathias Agopian1473f462009-04-10 14:24:30 -0700483
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700484 // dequeue a new buffer
Mathias Agopian1473f462009-04-10 14:24:30 -0700485 nativeWindow->dequeueBuffer(nativeWindow, &buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700486
Mathias Agopian1473f462009-04-10 14:24:30 -0700487 // TODO: lockBuffer should rather be executed when the very first
488 // direct rendering occurs.
489 nativeWindow->lockBuffer(nativeWindow, buffer);
Mathias Agopian1473f462009-04-10 14:24:30 -0700490
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700491 // reallocate the depth-buffer if needed
Mathias Agopian1473f462009-04-10 14:24:30 -0700492 if ((width != buffer->width) || (height != buffer->height)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 // TODO: we probably should reset the swap rect here
494 // if the window size has changed
Mathias Agopian1473f462009-04-10 14:24:30 -0700495 width = buffer->width;
496 height = buffer->height;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 if (depth.data) {
498 free(depth.data);
Mathias Agopian1473f462009-04-10 14:24:30 -0700499 depth.width = width;
500 depth.height = height;
501 depth.stride = buffer->stride;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
503 if (depth.data == 0) {
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700504 setError(EGL_BAD_ALLOC, EGL_FALSE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 return EGL_FALSE;
506 }
507 }
508 }
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700509
510 // keep a reference on the buffer
511 buffer->common.incRef(&buffer->common);
512
513 // finally pin the buffer down
514 if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
515 GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
516 LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
517 buffer, buffer->width, buffer->height);
518 setError(EGL_BAD_ACCESS, EGL_NO_SURFACE);
519 // FIXME: we should make sure we're not accessing the buffer anymore
520 }
521
522 return EGL_TRUE;
523}
524
525EGLBoolean egl_window_surface_v2_t::setSwapRectangle(
526 EGLint l, EGLint t, EGLint w, EGLint h)
527{
528 dirtyRegion = Rect(l, t, l+w, t+h);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 return EGL_TRUE;
530}
531
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700532EGLClientBuffer egl_window_surface_v2_t::getRenderBuffer() const
533{
534 return buffer;
535}
536
Mathias Agopian1473f462009-04-10 14:24:30 -0700537#ifdef LIBAGL_USE_GRALLOC_COPYBITS
538
539static bool supportedCopybitsDestinationFormat(int format) {
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700540 // Hardware supported
Mathias Agopian1473f462009-04-10 14:24:30 -0700541 switch (format) {
542 case HAL_PIXEL_FORMAT_RGB_565:
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700543 case HAL_PIXEL_FORMAT_RGBA_8888:
544 case HAL_PIXEL_FORMAT_RGBA_4444:
545 case HAL_PIXEL_FORMAT_RGBA_5551:
546 case HAL_PIXEL_FORMAT_BGRA_8888:
Mathias Agopian1473f462009-04-10 14:24:30 -0700547 return true;
Mathias Agopian1473f462009-04-10 14:24:30 -0700548 }
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700549 return false;
Mathias Agopian1473f462009-04-10 14:24:30 -0700550}
551#endif
552
553EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554{
555 GGLSurface buffer;
556 buffer.version = sizeof(GGLSurface);
Mathias Agopian1473f462009-04-10 14:24:30 -0700557 buffer.width = this->buffer->width;
558 buffer.height = this->buffer->height;
559 buffer.stride = this->buffer->stride;
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700560 buffer.data = (GGLubyte*)bits;
Mathias Agopian1473f462009-04-10 14:24:30 -0700561 buffer.format = this->buffer->format;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 gl->rasterizer.procs.colorBuffer(gl, &buffer);
563 if (depth.data != gl->rasterizer.state.buffers.depth.data)
564 gl->rasterizer.procs.depthBuffer(gl, &depth);
Mathias Agopian350d6512009-06-10 16:01:54 -0700565
Mathias Agopian1473f462009-04-10 14:24:30 -0700566#ifdef LIBAGL_USE_GRALLOC_COPYBITS
Mathias Agopian350d6512009-06-10 16:01:54 -0700567 gl->copybits.drawSurfaceBuffer = 0;
Mathias Agopian1473f462009-04-10 14:24:30 -0700568 if (supportedCopybitsDestinationFormat(buffer.format)) {
Mathias Agopiane633f932009-05-05 00:59:23 -0700569 buffer_handle_t handle = this->buffer->handle;
Mathias Agopian1473f462009-04-10 14:24:30 -0700570 if (handle != NULL) {
571 private_handle_t* hand = private_handle_t::dynamicCast(handle);
Mathias Agopian350d6512009-06-10 16:01:54 -0700572 if (hand != NULL && hand->usesPhysicallyContiguousMemory()) {
573 gl->copybits.drawSurfaceBuffer = handle;
Mathias Agopian1473f462009-04-10 14:24:30 -0700574 }
575 }
576 }
577#endif // LIBAGL_USE_GRALLOC_COPYBITS
Mathias Agopian350d6512009-06-10 16:01:54 -0700578
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 return EGL_TRUE;
580}
Mathias Agopian1473f462009-04-10 14:24:30 -0700581EGLBoolean egl_window_surface_v2_t::bindReadSurface(ogles_context_t* gl)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582{
583 GGLSurface buffer;
584 buffer.version = sizeof(GGLSurface);
Mathias Agopian1473f462009-04-10 14:24:30 -0700585 buffer.width = this->buffer->width;
586 buffer.height = this->buffer->height;
587 buffer.stride = this->buffer->stride;
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700588 buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
Mathias Agopian1473f462009-04-10 14:24:30 -0700589 buffer.format = this->buffer->format;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 gl->rasterizer.procs.readBuffer(gl, &buffer);
591 return EGL_TRUE;
592}
Mathias Agopian1473f462009-04-10 14:24:30 -0700593EGLint egl_window_surface_v2_t::getHorizontalResolution() const {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
595}
Mathias Agopian1473f462009-04-10 14:24:30 -0700596EGLint egl_window_surface_v2_t::getVerticalResolution() const {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
598}
Mathias Agopian1473f462009-04-10 14:24:30 -0700599EGLint egl_window_surface_v2_t::getRefreshRate() const {
600 return (60 * EGL_DISPLAY_SCALING); // FIXME
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601}
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700602EGLint egl_window_surface_v2_t::getSwapBehavior() const
603{
604 /*
605 * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
606 * the content of the swapped buffer.
607 *
608 * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
609 *
610 * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
611 * only applies to the area specified by eglSetSwapRectangleANDROID(), that
612 * is, everything outside of this area is preserved.
613 *
614 * This implementation of EGL assumes the later case.
615 *
616 */
617
Mathias Agopian1473f462009-04-10 14:24:30 -0700618 return EGL_BUFFER_DESTROYED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619}
620
621// ----------------------------------------------------------------------------
622
623struct egl_pixmap_surface_t : public egl_surface_t
624{
625 egl_pixmap_surface_t(
626 EGLDisplay dpy, EGLConfig config,
627 int32_t depthFormat,
628 egl_native_pixmap_t const * pixmap);
629
630 virtual ~egl_pixmap_surface_t() { }
631
Mathias Agopian1473f462009-04-10 14:24:30 -0700632 virtual bool isValid() const { return nativePixmap.version == sizeof(egl_native_pixmap_t); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
634 virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
635 virtual EGLint getWidth() const { return nativePixmap.width; }
636 virtual EGLint getHeight() const { return nativePixmap.height; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637private:
638 egl_native_pixmap_t nativePixmap;
639};
640
641egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
642 EGLConfig config,
643 int32_t depthFormat,
644 egl_native_pixmap_t const * pixmap)
645 : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
646{
647 if (depthFormat) {
648 depth.width = pixmap->width;
649 depth.height = pixmap->height;
650 depth.stride = depth.width; // use the width here
651 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
652 if (depth.data == 0) {
653 setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
654 return;
655 }
656 }
657}
658EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl)
659{
660 GGLSurface buffer;
661 buffer.version = sizeof(GGLSurface);
662 buffer.width = nativePixmap.width;
663 buffer.height = nativePixmap.height;
664 buffer.stride = nativePixmap.stride;
665 buffer.data = nativePixmap.data;
666 buffer.format = nativePixmap.format;
Mathias Agopian1473f462009-04-10 14:24:30 -0700667
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 gl->rasterizer.procs.colorBuffer(gl, &buffer);
669 if (depth.data != gl->rasterizer.state.buffers.depth.data)
670 gl->rasterizer.procs.depthBuffer(gl, &depth);
671 return EGL_TRUE;
672}
673EGLBoolean egl_pixmap_surface_t::bindReadSurface(ogles_context_t* gl)
674{
675 GGLSurface buffer;
676 buffer.version = sizeof(GGLSurface);
677 buffer.width = nativePixmap.width;
678 buffer.height = nativePixmap.height;
679 buffer.stride = nativePixmap.stride;
680 buffer.data = nativePixmap.data;
681 buffer.format = nativePixmap.format;
682 gl->rasterizer.procs.readBuffer(gl, &buffer);
683 return EGL_TRUE;
684}
685
686// ----------------------------------------------------------------------------
687
688struct egl_pbuffer_surface_t : public egl_surface_t
689{
690 egl_pbuffer_surface_t(
691 EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
692 int32_t w, int32_t h, int32_t f);
693
694 virtual ~egl_pbuffer_surface_t();
695
Mathias Agopian1473f462009-04-10 14:24:30 -0700696 virtual bool isValid() const { return pbuffer.data != 0; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
698 virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
699 virtual EGLint getWidth() const { return pbuffer.width; }
700 virtual EGLint getHeight() const { return pbuffer.height; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701private:
702 GGLSurface pbuffer;
703};
704
705egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
706 EGLConfig config, int32_t depthFormat,
707 int32_t w, int32_t h, int32_t f)
708 : egl_surface_t(dpy, config, depthFormat)
709{
710 size_t size = w*h;
711 switch (f) {
712 case GGL_PIXEL_FORMAT_A_8: size *= 1; break;
713 case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break;
714 case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break;
715 default:
716 LOGE("incompatible pixel format for pbuffer (format=%d)", f);
717 pbuffer.data = 0;
718 break;
719 }
720 pbuffer.version = sizeof(GGLSurface);
721 pbuffer.width = w;
722 pbuffer.height = h;
723 pbuffer.stride = w;
724 pbuffer.data = (GGLubyte*)malloc(size);
725 pbuffer.format = f;
Mathias Agopian1473f462009-04-10 14:24:30 -0700726
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 if (depthFormat) {
728 depth.width = pbuffer.width;
729 depth.height = pbuffer.height;
730 depth.stride = depth.width; // use the width here
731 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
732 if (depth.data == 0) {
733 setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
734 return;
735 }
736 }
737}
738egl_pbuffer_surface_t::~egl_pbuffer_surface_t() {
739 free(pbuffer.data);
740}
741EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(ogles_context_t* gl)
742{
743 gl->rasterizer.procs.colorBuffer(gl, &pbuffer);
744 if (depth.data != gl->rasterizer.state.buffers.depth.data)
745 gl->rasterizer.procs.depthBuffer(gl, &depth);
746 return EGL_TRUE;
747}
748EGLBoolean egl_pbuffer_surface_t::bindReadSurface(ogles_context_t* gl)
749{
750 gl->rasterizer.procs.readBuffer(gl, &pbuffer);
751 return EGL_TRUE;
752}
753
754// ----------------------------------------------------------------------------
755
756struct config_pair_t {
757 GLint key;
758 GLint value;
759};
760
761struct configs_t {
762 const config_pair_t* array;
763 int size;
764};
765
766struct config_management_t {
767 GLint key;
768 bool (*match)(GLint reqValue, GLint confValue);
769 static bool atLeast(GLint reqValue, GLint confValue) {
770 return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
771 }
772 static bool exact(GLint reqValue, GLint confValue) {
773 return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
774 }
775 static bool mask(GLint reqValue, GLint confValue) {
776 return (confValue & reqValue) == reqValue;
777 }
778};
779
780// ----------------------------------------------------------------------------
781
782#define VERSION_MAJOR 1
783#define VERSION_MINOR 2
784static char const * const gVendorString = "Google Inc.";
785static char const * const gVersionString = "1.2 Android Driver";
786static char const * const gClientApiString = "OpenGL ES";
Mathias Agopian1473f462009-04-10 14:24:30 -0700787static char const * const gExtensionsString =
Mathias Agopian927d37c2009-05-06 23:47:08 -0700788 "EGL_KHR_image_base "
Mathias Agopian1473f462009-04-10 14:24:30 -0700789 // "KHR_image_pixmap "
790 "EGL_ANDROID_image_native_buffer "
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700791 "EGL_ANDROID_swap_rectangle "
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700792 "EGL_ANDROID_get_render_buffer "
Mathias Agopian1473f462009-04-10 14:24:30 -0700793 ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794
795// ----------------------------------------------------------------------------
796
797struct extention_map_t {
798 const char * const name;
799 __eglMustCastToProperFunctionPointerType address;
800};
801
802static const extention_map_t gExtentionMap[] = {
Mathias Agopian1473f462009-04-10 14:24:30 -0700803 { "glDrawTexsOES",
804 (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES },
805 { "glDrawTexiOES",
806 (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES },
807 { "glDrawTexfOES",
808 (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES },
809 { "glDrawTexxOES",
810 (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES },
811 { "glDrawTexsvOES",
812 (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES },
813 { "glDrawTexivOES",
814 (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES },
815 { "glDrawTexfvOES",
816 (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES },
817 { "glDrawTexxvOES",
818 (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
819 { "glQueryMatrixxOES",
820 (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
821 { "glEGLImageTargetTexture2DOES",
822 (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
823 { "glEGLImageTargetRenderbufferStorageOES",
824 (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
825 { "glClipPlanef",
826 (__eglMustCastToProperFunctionPointerType)&glClipPlanef },
827 { "glClipPlanex",
828 (__eglMustCastToProperFunctionPointerType)&glClipPlanex },
829 { "glBindBuffer",
830 (__eglMustCastToProperFunctionPointerType)&glBindBuffer },
831 { "glBufferData",
832 (__eglMustCastToProperFunctionPointerType)&glBufferData },
833 { "glBufferSubData",
834 (__eglMustCastToProperFunctionPointerType)&glBufferSubData },
835 { "glDeleteBuffers",
836 (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
837 { "glGenBuffers",
838 (__eglMustCastToProperFunctionPointerType)&glGenBuffers },
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700839 { "eglCreateImageKHR",
840 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
841 { "eglDestroyImageKHR",
842 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
843 { "eglSetSwapRectangleANDROID",
844 (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
845 { "eglGetRenderBufferANDROID",
846 (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847};
848
Mathias Agopian1473f462009-04-10 14:24:30 -0700849/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 * In the lists below, attributes names MUST be sorted.
851 * Additionally, all configs must be sorted according to
852 * the EGL specification.
853 */
854
855static config_pair_t const config_base_attribute_list[] = {
856 { EGL_STENCIL_SIZE, 0 },
857 { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG },
858 { EGL_LEVEL, 0 },
859 { EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS },
Mathias Agopian1473f462009-04-10 14:24:30 -0700860 { EGL_MAX_PBUFFER_PIXELS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS },
862 { EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS },
863 { EGL_NATIVE_RENDERABLE, EGL_TRUE },
864 { EGL_NATIVE_VISUAL_ID, 0 },
865 { EGL_NATIVE_VISUAL_TYPE, GGL_PIXEL_FORMAT_RGB_565 },
866 { EGL_SAMPLES, 0 },
867 { EGL_SAMPLE_BUFFERS, 0 },
868 { EGL_TRANSPARENT_TYPE, EGL_NONE },
869 { EGL_TRANSPARENT_BLUE_VALUE, 0 },
870 { EGL_TRANSPARENT_GREEN_VALUE, 0 },
871 { EGL_TRANSPARENT_RED_VALUE, 0 },
872 { EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE },
873 { EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE },
874 { EGL_MIN_SWAP_INTERVAL, 1 },
875 { EGL_MAX_SWAP_INTERVAL, 4 },
876};
877
878// These configs can override the base attribute list
879// NOTE: when adding a config here, don't forget to update eglCreate*Surface()
880
881static config_pair_t const config_0_attribute_list[] = {
882 { EGL_BUFFER_SIZE, 16 },
883 { EGL_ALPHA_SIZE, 0 },
884 { EGL_BLUE_SIZE, 5 },
885 { EGL_GREEN_SIZE, 6 },
886 { EGL_RED_SIZE, 5 },
887 { EGL_DEPTH_SIZE, 0 },
888 { EGL_CONFIG_ID, 0 },
889 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
890};
891
892static config_pair_t const config_1_attribute_list[] = {
893 { EGL_BUFFER_SIZE, 16 },
894 { EGL_ALPHA_SIZE, 0 },
895 { EGL_BLUE_SIZE, 5 },
896 { EGL_GREEN_SIZE, 6 },
897 { EGL_RED_SIZE, 5 },
898 { EGL_DEPTH_SIZE, 16 },
899 { EGL_CONFIG_ID, 1 },
900 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
901};
902
903static config_pair_t const config_2_attribute_list[] = {
904 { EGL_BUFFER_SIZE, 32 },
905 { EGL_ALPHA_SIZE, 8 },
906 { EGL_BLUE_SIZE, 8 },
907 { EGL_GREEN_SIZE, 8 },
908 { EGL_RED_SIZE, 8 },
909 { EGL_DEPTH_SIZE, 0 },
910 { EGL_CONFIG_ID, 2 },
911 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
912};
913
914static config_pair_t const config_3_attribute_list[] = {
915 { EGL_BUFFER_SIZE, 32 },
916 { EGL_ALPHA_SIZE, 8 },
917 { EGL_BLUE_SIZE, 8 },
918 { EGL_GREEN_SIZE, 8 },
919 { EGL_RED_SIZE, 8 },
920 { EGL_DEPTH_SIZE, 16 },
921 { EGL_CONFIG_ID, 3 },
922 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
923};
924
925static config_pair_t const config_4_attribute_list[] = {
926 { EGL_BUFFER_SIZE, 8 },
927 { EGL_ALPHA_SIZE, 8 },
928 { EGL_BLUE_SIZE, 0 },
929 { EGL_GREEN_SIZE, 0 },
930 { EGL_RED_SIZE, 0 },
931 { EGL_DEPTH_SIZE, 0 },
932 { EGL_CONFIG_ID, 4 },
933 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
934};
935
936static config_pair_t const config_5_attribute_list[] = {
937 { EGL_BUFFER_SIZE, 8 },
938 { EGL_ALPHA_SIZE, 8 },
939 { EGL_BLUE_SIZE, 0 },
940 { EGL_GREEN_SIZE, 0 },
941 { EGL_RED_SIZE, 0 },
942 { EGL_DEPTH_SIZE, 16 },
943 { EGL_CONFIG_ID, 5 },
944 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
945};
946
947static configs_t const gConfigs[] = {
948 { config_0_attribute_list, NELEM(config_0_attribute_list) },
949 { config_1_attribute_list, NELEM(config_1_attribute_list) },
950 { config_2_attribute_list, NELEM(config_2_attribute_list) },
951 { config_3_attribute_list, NELEM(config_3_attribute_list) },
952 { config_4_attribute_list, NELEM(config_4_attribute_list) },
953 { config_5_attribute_list, NELEM(config_5_attribute_list) },
954};
955
956static config_management_t const gConfigManagement[] = {
957 { EGL_BUFFER_SIZE, config_management_t::atLeast },
958 { EGL_ALPHA_SIZE, config_management_t::atLeast },
959 { EGL_BLUE_SIZE, config_management_t::atLeast },
960 { EGL_GREEN_SIZE, config_management_t::atLeast },
961 { EGL_RED_SIZE, config_management_t::atLeast },
962 { EGL_DEPTH_SIZE, config_management_t::atLeast },
963 { EGL_STENCIL_SIZE, config_management_t::atLeast },
964 { EGL_CONFIG_CAVEAT, config_management_t::exact },
965 { EGL_CONFIG_ID, config_management_t::exact },
966 { EGL_LEVEL, config_management_t::exact },
967 { EGL_MAX_PBUFFER_HEIGHT, config_management_t::exact },
968 { EGL_MAX_PBUFFER_PIXELS, config_management_t::exact },
969 { EGL_MAX_PBUFFER_WIDTH, config_management_t::exact },
970 { EGL_NATIVE_RENDERABLE, config_management_t::exact },
971 { EGL_NATIVE_VISUAL_ID, config_management_t::exact },
972 { EGL_NATIVE_VISUAL_TYPE, config_management_t::exact },
973 { EGL_SAMPLES, config_management_t::exact },
974 { EGL_SAMPLE_BUFFERS, config_management_t::exact },
975 { EGL_SURFACE_TYPE, config_management_t::mask },
976 { EGL_TRANSPARENT_TYPE, config_management_t::exact },
977 { EGL_TRANSPARENT_BLUE_VALUE, config_management_t::exact },
978 { EGL_TRANSPARENT_GREEN_VALUE, config_management_t::exact },
979 { EGL_TRANSPARENT_RED_VALUE, config_management_t::exact },
980 { EGL_BIND_TO_TEXTURE_RGBA, config_management_t::exact },
981 { EGL_BIND_TO_TEXTURE_RGB, config_management_t::exact },
982 { EGL_MIN_SWAP_INTERVAL, config_management_t::exact },
983 { EGL_MAX_SWAP_INTERVAL, config_management_t::exact },
984};
985
986static config_pair_t const config_defaults[] = {
987 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
988};
989
990// ----------------------------------------------------------------------------
991
992template<typename T>
993static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
994{
995 while (first <= last) {
996 int mid = (first + last) / 2;
Mathias Agopian1473f462009-04-10 14:24:30 -0700997 if (key > sortedArray[mid].key) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 first = mid + 1;
Mathias Agopian1473f462009-04-10 14:24:30 -0700999 } else if (key < sortedArray[mid].key) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 last = mid - 1;
1001 } else {
1002 return mid;
1003 }
1004 }
1005 return -1;
1006}
1007
1008static int isAttributeMatching(int i, EGLint attr, EGLint val)
1009{
1010 // look for the attribute in all of our configs
Mathias Agopian1473f462009-04-10 14:24:30 -07001011 config_pair_t const* configFound = gConfigs[i].array;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 int index = binarySearch<config_pair_t>(
1013 gConfigs[i].array,
1014 0, gConfigs[i].size-1,
1015 attr);
1016 if (index < 0) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001017 configFound = config_base_attribute_list;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 index = binarySearch<config_pair_t>(
1019 config_base_attribute_list,
1020 0, NELEM(config_base_attribute_list)-1,
1021 attr);
1022 }
1023 if (index >= 0) {
1024 // attribute found, check if this config could match
1025 int cfgMgtIndex = binarySearch<config_management_t>(
1026 gConfigManagement,
1027 0, NELEM(gConfigManagement)-1,
1028 attr);
1029 if (index >= 0) {
1030 bool match = gConfigManagement[cfgMgtIndex].match(
1031 val, configFound[index].value);
1032 if (match) {
1033 // this config matches
1034 return 1;
1035 }
1036 } else {
1037 // attribute not found. this should NEVER happen.
1038 }
1039 } else {
1040 // error, this attribute doesn't exist
1041 }
1042 return 0;
1043}
1044
1045static int makeCurrent(ogles_context_t* gl)
1046{
1047 ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();
1048 if (gl) {
1049 egl_context_t* c = egl_context_t::context(gl);
1050 if (c->flags & egl_context_t::IS_CURRENT) {
1051 if (current != gl) {
1052 // it is an error to set a context current, if it's already
1053 // current to another thread
1054 return -1;
1055 }
1056 } else {
1057 if (current) {
1058 // mark the current context as not current, and flush
1059 glFlush();
1060 egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
1061 }
1062 }
1063 if (!(c->flags & egl_context_t::IS_CURRENT)) {
1064 // The context is not current, make it current!
1065 setGlThreadSpecific(gl);
1066 c->flags |= egl_context_t::IS_CURRENT;
1067 }
1068 } else {
1069 if (current) {
1070 // mark the current context as not current, and flush
1071 glFlush();
1072 egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
1073 }
1074 // this thread has no context attached to it
1075 setGlThreadSpecific(0);
1076 }
1077 return 0;
1078}
1079
1080static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
1081 EGLint attribute, EGLint *value)
1082{
1083 size_t numConfigs = NELEM(gConfigs);
1084 int index = (int)config;
1085 if (uint32_t(index) >= numConfigs)
1086 return setError(EGL_BAD_CONFIG, EGL_FALSE);
1087
1088 int attrIndex;
1089 attrIndex = binarySearch<config_pair_t>(
1090 gConfigs[index].array,
1091 0, gConfigs[index].size-1,
1092 attribute);
1093 if (attrIndex>=0) {
1094 *value = gConfigs[index].array[attrIndex].value;
1095 return EGL_TRUE;
1096 }
1097
1098 attrIndex = binarySearch<config_pair_t>(
1099 config_base_attribute_list,
1100 0, NELEM(config_base_attribute_list)-1,
1101 attribute);
1102 if (attrIndex>=0) {
1103 *value = config_base_attribute_list[attrIndex].value;
1104 return EGL_TRUE;
1105 }
1106 return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1107}
1108
1109static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
1110 NativeWindowType window, const EGLint *attrib_list)
1111{
1112 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1113 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1114 if (window == 0)
1115 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1116
1117 EGLint surfaceType;
1118 if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
1119 return EGL_FALSE;
1120
1121 if (!(surfaceType & EGL_WINDOW_BIT))
1122 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1123
1124 EGLint configID;
1125 if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
1126 return EGL_FALSE;
1127
1128 int32_t depthFormat;
1129 int32_t pixelFormat;
1130 switch(configID) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001131 case 0:
1132 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 depthFormat = 0;
1134 break;
1135 case 1:
Mathias Agopian1473f462009-04-10 14:24:30 -07001136 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1138 break;
1139 case 2:
Mathias Agopian1473f462009-04-10 14:24:30 -07001140 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 depthFormat = 0;
1142 break;
1143 case 3:
Mathias Agopian1473f462009-04-10 14:24:30 -07001144 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1146 break;
1147 case 4:
Mathias Agopian1473f462009-04-10 14:24:30 -07001148 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 depthFormat = 0;
1150 break;
1151 case 5:
Mathias Agopian1473f462009-04-10 14:24:30 -07001152 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1154 break;
1155 default:
1156 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1157 }
1158
1159 // FIXME: we don't have access to the pixelFormat here just yet.
1160 // (it's possible that the surface is not fully initialized)
1161 // maybe this should be done after the page-flip
1162 //if (EGLint(info.format) != pixelFormat)
1163 // return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1164
Mathias Agopian1473f462009-04-10 14:24:30 -07001165 egl_surface_t* surface;
1166 surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
1167 static_cast<android_native_window_t*>(window));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001168
1169 if (!surface->isValid()) {
1170 // there was a problem in the ctor, the error
1171 // flag has been set.
1172 delete surface;
1173 surface = 0;
1174 }
1175 return surface;
1176}
1177
1178static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
1179 NativePixmapType pixmap, const EGLint *attrib_list)
1180{
1181 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1182 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1183 if (pixmap == 0)
1184 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1185
1186 EGLint surfaceType;
1187 if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
1188 return EGL_FALSE;
1189
1190 if (!(surfaceType & EGL_PIXMAP_BIT))
1191 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1192
1193 EGLint configID;
1194 if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
1195 return EGL_FALSE;
1196
1197 int32_t depthFormat;
1198 int32_t pixelFormat;
1199 switch(configID) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001200 case 0:
1201 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 depthFormat = 0;
1203 break;
1204 case 1:
Mathias Agopian1473f462009-04-10 14:24:30 -07001205 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1207 break;
1208 case 2:
Mathias Agopian1473f462009-04-10 14:24:30 -07001209 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 depthFormat = 0;
1211 break;
1212 case 3:
Mathias Agopian1473f462009-04-10 14:24:30 -07001213 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001214 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1215 break;
1216 case 4:
Mathias Agopian1473f462009-04-10 14:24:30 -07001217 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 depthFormat = 0;
1219 break;
1220 case 5:
Mathias Agopian1473f462009-04-10 14:24:30 -07001221 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1223 break;
1224 default:
1225 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1226 }
1227
1228 if (pixmap->format != pixelFormat)
1229 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1230
1231 egl_surface_t* surface =
1232 new egl_pixmap_surface_t(dpy, config, depthFormat,
1233 static_cast<egl_native_pixmap_t*>(pixmap));
1234
1235 if (!surface->isValid()) {
1236 // there was a problem in the ctor, the error
1237 // flag has been set.
1238 delete surface;
1239 surface = 0;
1240 }
1241 return surface;
1242}
1243
1244static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
1245 const EGLint *attrib_list)
1246{
1247 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1248 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1249
1250 EGLint surfaceType;
1251 if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
1252 return EGL_FALSE;
Mathias Agopian1473f462009-04-10 14:24:30 -07001253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 if (!(surfaceType & EGL_PBUFFER_BIT))
1255 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001257 EGLint configID;
1258 if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
1259 return EGL_FALSE;
1260
1261 int32_t depthFormat;
1262 int32_t pixelFormat;
1263 switch(configID) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001264 case 0:
1265 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 depthFormat = 0;
1267 break;
1268 case 1:
Mathias Agopian1473f462009-04-10 14:24:30 -07001269 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1271 break;
1272 case 2:
Mathias Agopian1473f462009-04-10 14:24:30 -07001273 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 depthFormat = 0;
1275 break;
1276 case 3:
Mathias Agopian1473f462009-04-10 14:24:30 -07001277 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1279 break;
1280 case 4:
Mathias Agopian1473f462009-04-10 14:24:30 -07001281 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282 depthFormat = 0;
1283 break;
1284 case 5:
Mathias Agopian1473f462009-04-10 14:24:30 -07001285 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1287 break;
1288 default:
1289 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1290 }
1291
1292 int32_t w = 0;
1293 int32_t h = 0;
1294 while (attrib_list[0]) {
1295 if (attrib_list[0] == EGL_WIDTH) w = attrib_list[1];
1296 if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
1297 attrib_list+=2;
1298 }
1299
1300 egl_surface_t* surface =
1301 new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
1302
1303 if (!surface->isValid()) {
1304 // there was a problem in the ctor, the error
1305 // flag has been set.
1306 delete surface;
1307 surface = 0;
1308 }
1309 return surface;
1310}
1311
1312// ----------------------------------------------------------------------------
1313}; // namespace android
1314// ----------------------------------------------------------------------------
1315
1316using namespace android;
1317
1318// ----------------------------------------------------------------------------
1319// Initialization
1320// ----------------------------------------------------------------------------
1321
1322EGLDisplay eglGetDisplay(NativeDisplayType display)
1323{
1324#ifndef HAVE_ANDROID_OS
1325 // this just needs to be done once
1326 if (gGLKey == -1) {
1327 pthread_mutex_lock(&gInitMutex);
1328 if (gGLKey == -1)
1329 pthread_key_create(&gGLKey, NULL);
1330 pthread_mutex_unlock(&gInitMutex);
1331 }
1332#endif
1333 if (display == EGL_DEFAULT_DISPLAY) {
1334 EGLDisplay dpy = (EGLDisplay)1;
1335 egl_display_t& d = egl_display_t::get_display(dpy);
1336 d.type = display;
1337 return dpy;
Mathias Agopian1473f462009-04-10 14:24:30 -07001338 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 return EGL_NO_DISPLAY;
1340}
1341
1342EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
1343{
1344 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1345 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 EGLBoolean res = EGL_TRUE;
1348 egl_display_t& d = egl_display_t::get_display(dpy);
Mathias Agopian1473f462009-04-10 14:24:30 -07001349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 if (android_atomic_inc(&d.initialized) == 0) {
1351 // initialize stuff here if needed
1352 //pthread_mutex_lock(&gInitMutex);
1353 //pthread_mutex_unlock(&gInitMutex);
1354 }
1355
1356 if (res == EGL_TRUE) {
1357 if (major != NULL) *major = VERSION_MAJOR;
1358 if (minor != NULL) *minor = VERSION_MINOR;
1359 }
1360 return res;
1361}
1362
1363EGLBoolean eglTerminate(EGLDisplay dpy)
1364{
1365 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1366 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1367
1368 EGLBoolean res = EGL_TRUE;
1369 egl_display_t& d = egl_display_t::get_display(dpy);
1370 if (android_atomic_dec(&d.initialized) == 1) {
1371 // TODO: destroy all resources (surfaces, contexts, etc...)
1372 //pthread_mutex_lock(&gInitMutex);
1373 //pthread_mutex_unlock(&gInitMutex);
1374 }
1375 return res;
1376}
1377
1378// ----------------------------------------------------------------------------
1379// configuration
1380// ----------------------------------------------------------------------------
1381
1382EGLBoolean eglGetConfigs( EGLDisplay dpy,
1383 EGLConfig *configs,
1384 EGLint config_size, EGLint *num_config)
1385{
1386 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1387 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1388
1389 GLint numConfigs = NELEM(gConfigs);
1390 if (!configs) {
1391 *num_config = numConfigs;
1392 return EGL_TRUE;
1393 }
1394 GLint i;
1395 for (i=0 ; i<numConfigs && i<config_size ; i++) {
1396 *configs++ = (EGLConfig)i;
1397 }
1398 *num_config = i;
1399 return EGL_TRUE;
1400}
1401
1402EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
1403 EGLConfig *configs, EGLint config_size,
1404 EGLint *num_config)
1405{
1406 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1407 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Jack Palevich1badb712009-03-25 15:12:17 -07001408
1409 if (ggl_unlikely(num_config==0)) {
1410 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1411 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412
Jack Palevich1badb712009-03-25 15:12:17 -07001413 if (ggl_unlikely(attrib_list==0)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 *num_config = 0;
1415 return EGL_TRUE;
1416 }
Mathias Agopian1473f462009-04-10 14:24:30 -07001417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 int numAttributes = 0;
1419 int numConfigs = NELEM(gConfigs);
1420 uint32_t possibleMatch = (1<<numConfigs)-1;
1421 while(possibleMatch && *attrib_list != EGL_NONE) {
1422 numAttributes++;
1423 EGLint attr = *attrib_list++;
1424 EGLint val = *attrib_list++;
1425 for (int i=0 ; i<numConfigs ; i++) {
1426 if (!(possibleMatch & (1<<i)))
1427 continue;
1428 if (isAttributeMatching(i, attr, val) == 0) {
1429 possibleMatch &= ~(1<<i);
1430 }
1431 }
1432 }
1433
1434 // now, handle the attributes which have a useful default value
1435 for (size_t j=0 ; j<NELEM(config_defaults) ; j++) {
1436 // see if this attribute was specified, if not apply its
1437 // default value
1438 if (binarySearch<config_pair_t>(
1439 (config_pair_t const*)attrib_list,
1440 0, numAttributes,
1441 config_defaults[j].key) < 0)
1442 {
1443 for (int i=0 ; i<numConfigs ; i++) {
1444 if (!(possibleMatch & (1<<i)))
1445 continue;
1446 if (isAttributeMatching(i,
1447 config_defaults[j].key,
1448 config_defaults[j].value) == 0)
1449 {
1450 possibleMatch &= ~(1<<i);
1451 }
1452 }
1453 }
1454 }
1455
1456 // return the configurations found
1457 int n=0;
1458 if (possibleMatch) {
Jack Palevich1badb712009-03-25 15:12:17 -07001459 if (configs) {
1460 for (int i=0 ; config_size && i<numConfigs ; i++) {
1461 if (possibleMatch & (1<<i)) {
1462 *configs++ = (EGLConfig)i;
1463 config_size--;
1464 n++;
1465 }
1466 }
1467 } else {
1468 for (int i=0 ; i<numConfigs ; i++) {
1469 if (possibleMatch & (1<<i)) {
1470 n++;
1471 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 }
1473 }
1474 }
1475 *num_config = n;
1476 return EGL_TRUE;
1477}
1478
1479EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
1480 EGLint attribute, EGLint *value)
1481{
1482 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1483 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1484
1485 return getConfigAttrib(dpy, config, attribute, value);
1486}
1487
1488// ----------------------------------------------------------------------------
1489// surfaces
1490// ----------------------------------------------------------------------------
1491
1492EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
1493 NativeWindowType window,
1494 const EGLint *attrib_list)
1495{
1496 return createWindowSurface(dpy, config, window, attrib_list);
1497}
Mathias Agopian1473f462009-04-10 14:24:30 -07001498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
1500 NativePixmapType pixmap,
1501 const EGLint *attrib_list)
1502{
1503 return createPixmapSurface(dpy, config, pixmap, attrib_list);
1504}
1505
1506EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
1507 const EGLint *attrib_list)
1508{
1509 return createPbufferSurface(dpy, config, attrib_list);
1510}
Mathias Agopian1473f462009-04-10 14:24:30 -07001511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
1513{
1514 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1515 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1516 if (eglSurface != EGL_NO_SURFACE) {
1517 egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
1518 if (surface->magic != egl_surface_t::MAGIC)
1519 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1520 if (surface->dpy != dpy)
1521 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001522 if (surface->ctx) {
1523 // FIXME: this surface is current check what the spec says
1524 surface->disconnect();
1525 surface->ctx = 0;
1526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 delete surface;
1528 }
1529 return EGL_TRUE;
1530}
1531
1532EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
1533 EGLint attribute, EGLint *value)
1534{
1535 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1536 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1537 egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
1538 if (surface->dpy != dpy)
1539 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1540
1541 EGLBoolean ret = EGL_TRUE;
1542 switch (attribute) {
1543 case EGL_CONFIG_ID:
1544 ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
1545 break;
1546 case EGL_WIDTH:
1547 *value = surface->getWidth();
1548 break;
1549 case EGL_HEIGHT:
1550 *value = surface->getHeight();
1551 break;
1552 case EGL_LARGEST_PBUFFER:
1553 // not modified for a window or pixmap surface
1554 break;
1555 case EGL_TEXTURE_FORMAT:
1556 *value = EGL_NO_TEXTURE;
1557 break;
1558 case EGL_TEXTURE_TARGET:
1559 *value = EGL_NO_TEXTURE;
1560 break;
1561 case EGL_MIPMAP_TEXTURE:
1562 *value = EGL_FALSE;
1563 break;
1564 case EGL_MIPMAP_LEVEL:
1565 *value = 0;
1566 break;
1567 case EGL_RENDER_BUFFER:
1568 // TODO: return the real RENDER_BUFFER here
1569 *value = EGL_BACK_BUFFER;
1570 break;
1571 case EGL_HORIZONTAL_RESOLUTION:
1572 // pixel/mm * EGL_DISPLAY_SCALING
1573 *value = surface->getHorizontalResolution();
1574 break;
1575 case EGL_VERTICAL_RESOLUTION:
1576 // pixel/mm * EGL_DISPLAY_SCALING
1577 *value = surface->getVerticalResolution();
1578 break;
1579 case EGL_PIXEL_ASPECT_RATIO: {
1580 // w/h * EGL_DISPLAY_SCALING
1581 int wr = surface->getHorizontalResolution();
1582 int hr = surface->getVerticalResolution();
1583 *value = (wr * EGL_DISPLAY_SCALING) / hr;
1584 } break;
1585 case EGL_SWAP_BEHAVIOR:
Mathias Agopian1473f462009-04-10 14:24:30 -07001586 *value = surface->getSwapBehavior();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 break;
1588 default:
1589 ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1590 }
1591 return ret;
1592}
1593
1594EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1595 EGLContext share_list, const EGLint *attrib_list)
1596{
1597 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1598 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1599
1600 ogles_context_t* gl = ogles_init(sizeof(egl_context_t));
1601 if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
1602
1603 egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
1604 c->flags = egl_context_t::NEVER_CURRENT;
1605 c->dpy = dpy;
1606 c->config = config;
1607 c->read = 0;
1608 c->draw = 0;
1609 return (EGLContext)gl;
1610}
1611
1612EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1613{
1614 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1615 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1616 egl_context_t* c = egl_context_t::context(ctx);
1617 if (c->flags & egl_context_t::IS_CURRENT)
1618 setGlThreadSpecific(0);
1619 ogles_uninit((ogles_context_t*)ctx);
1620 return EGL_TRUE;
1621}
1622
1623EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
1624 EGLSurface read, EGLContext ctx)
1625{
1626 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1627 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1628 if (draw) {
1629 egl_surface_t* s = (egl_surface_t*)draw;
1630 if (s->dpy != dpy)
1631 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1632 // TODO: check that draw and read are compatible with the context
1633 }
1634
1635 EGLContext current_ctx = EGL_NO_CONTEXT;
Mathias Agopian1473f462009-04-10 14:24:30 -07001636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001637 if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
1638 return setError(EGL_BAD_MATCH, EGL_FALSE);
1639
1640 if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
1641 return setError(EGL_BAD_MATCH, EGL_FALSE);
1642
1643 if (ctx == EGL_NO_CONTEXT) {
1644 // if we're detaching, we need the current context
1645 current_ctx = (EGLContext)getGlThreadSpecific();
1646 } else {
1647 egl_context_t* c = egl_context_t::context(ctx);
1648 egl_surface_t* d = (egl_surface_t*)draw;
1649 egl_surface_t* r = (egl_surface_t*)read;
1650 if ((d && d->ctx && d->ctx != ctx) ||
1651 (r && r->ctx && r->ctx != ctx)) {
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001652 // one of the surface is bound to a context in another thread
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 return setError(EGL_BAD_ACCESS, EGL_FALSE);
1654 }
1655 }
1656
1657 ogles_context_t* gl = (ogles_context_t*)ctx;
1658 if (makeCurrent(gl) == 0) {
1659 if (ctx) {
1660 egl_context_t* c = egl_context_t::context(ctx);
1661 egl_surface_t* d = (egl_surface_t*)draw;
1662 egl_surface_t* r = (egl_surface_t*)read;
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001663
1664 if (c->draw) {
1665 reinterpret_cast<egl_surface_t*>(c->draw)->disconnect();
1666 }
1667 if (c->read) {
1668 // FIXME: unlock/disconnect the read surface too
1669 }
1670
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 c->draw = draw;
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001672 c->read = read;
1673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674 if (c->flags & egl_context_t::NEVER_CURRENT) {
1675 c->flags &= ~egl_context_t::NEVER_CURRENT;
1676 GLint w = 0;
1677 GLint h = 0;
1678 if (draw) {
1679 w = d->getWidth();
1680 h = d->getHeight();
1681 }
1682 ogles_surfaceport(gl, 0, 0);
1683 ogles_viewport(gl, 0, 0, w, h);
1684 ogles_scissor(gl, 0, 0, w, h);
1685 }
1686 if (d) {
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001687 d->connect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 d->ctx = ctx;
1689 d->bindDrawSurface(gl);
1690 }
1691 if (r) {
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001692 // FIXME: lock/connect the read surface too
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 r->ctx = ctx;
1694 r->bindReadSurface(gl);
1695 }
1696 } else {
1697 // if surfaces were bound to the context bound to this thread
1698 // mark then as unbound.
1699 if (current_ctx) {
1700 egl_context_t* c = egl_context_t::context(current_ctx);
1701 egl_surface_t* d = (egl_surface_t*)c->draw;
1702 egl_surface_t* r = (egl_surface_t*)c->read;
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001703 if (d) {
Mathias Agopian36432cc2009-06-03 19:00:53 -07001704 c->draw = 0;
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001705 d->ctx = EGL_NO_CONTEXT;
1706 d->disconnect();
1707 }
1708 if (r) {
Mathias Agopian36432cc2009-06-03 19:00:53 -07001709 c->read = 0;
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001710 r->ctx = EGL_NO_CONTEXT;
1711 // FIXME: unlock/disconnect the read surface too
1712 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 }
1714 }
1715 return EGL_TRUE;
1716 }
1717 return setError(EGL_BAD_ACCESS, EGL_FALSE);
1718}
1719
1720EGLContext eglGetCurrentContext(void)
1721{
1722 // eglGetCurrentContext returns the current EGL rendering context,
1723 // as specified by eglMakeCurrent. If no context is current,
1724 // EGL_NO_CONTEXT is returned.
1725 return (EGLContext)getGlThreadSpecific();
1726}
1727
1728EGLSurface eglGetCurrentSurface(EGLint readdraw)
1729{
1730 // eglGetCurrentSurface returns the read or draw surface attached
1731 // to the current EGL rendering context, as specified by eglMakeCurrent.
1732 // If no context is current, EGL_NO_SURFACE is returned.
1733 EGLContext ctx = (EGLContext)getGlThreadSpecific();
1734 if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
1735 egl_context_t* c = egl_context_t::context(ctx);
1736 if (readdraw == EGL_READ) {
1737 return c->read;
1738 } else if (readdraw == EGL_DRAW) {
1739 return c->draw;
1740 }
1741 return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
1742}
1743
1744EGLDisplay eglGetCurrentDisplay(void)
1745{
1746 // eglGetCurrentDisplay returns the current EGL display connection
1747 // for the current EGL rendering context, as specified by eglMakeCurrent.
1748 // If no context is current, EGL_NO_DISPLAY is returned.
1749 EGLContext ctx = (EGLContext)getGlThreadSpecific();
1750 if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
1751 egl_context_t* c = egl_context_t::context(ctx);
1752 return c->dpy;
1753}
1754
1755EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1756 EGLint attribute, EGLint *value)
1757{
1758 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1759 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1760 egl_context_t* c = egl_context_t::context(ctx);
1761 switch (attribute) {
1762 case EGL_CONFIG_ID:
1763 // Returns the ID of the EGL frame buffer configuration with
1764 // respect to which the context was created
1765 return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
1766 }
1767 return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1768}
1769
1770EGLBoolean eglWaitGL(void)
1771{
1772 return EGL_TRUE;
1773}
1774
1775EGLBoolean eglWaitNative(EGLint engine)
1776{
1777 return EGL_TRUE;
1778}
1779
1780EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1781{
1782 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1783 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001785 egl_surface_t* d = static_cast<egl_surface_t*>(draw);
1786 if (d->dpy != dpy)
1787 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1788
1789 // post the surface
1790 d->swapBuffers();
1791
1792 // if it's bound to a context, update the buffer
1793 if (d->ctx != EGL_NO_CONTEXT) {
1794 d->bindDrawSurface((ogles_context_t*)d->ctx);
1795 // if this surface is also the read surface of the context
1796 // it is bound to, make sure to update the read buffer as well.
1797 // The EGL spec is a little unclear about this.
1798 egl_context_t* c = egl_context_t::context(d->ctx);
1799 if (c->read == draw) {
1800 d->bindReadSurface((ogles_context_t*)d->ctx);
1801 }
1802 }
1803
1804 return EGL_TRUE;
1805}
1806
1807EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1808 NativePixmapType target)
1809{
1810 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1811 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1812 // TODO: eglCopyBuffers()
1813 return EGL_FALSE;
1814}
1815
1816EGLint eglGetError(void)
1817{
1818 return getError();
1819}
1820
1821const char* eglQueryString(EGLDisplay dpy, EGLint name)
1822{
1823 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1824 return setError(EGL_BAD_DISPLAY, (const char*)0);
1825
1826 switch (name) {
1827 case EGL_VENDOR:
1828 return gVendorString;
1829 case EGL_VERSION:
1830 return gVersionString;
1831 case EGL_EXTENSIONS:
1832 return gExtensionsString;
1833 case EGL_CLIENT_APIS:
1834 return gClientApiString;
1835 }
1836 return setError(EGL_BAD_PARAMETER, (const char *)0);
1837}
1838
1839// ----------------------------------------------------------------------------
1840// EGL 1.1
1841// ----------------------------------------------------------------------------
1842
1843EGLBoolean eglSurfaceAttrib(
1844 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1845{
1846 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1847 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1848 // TODO: eglSurfaceAttrib()
1849 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1850}
1851
1852EGLBoolean eglBindTexImage(
1853 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1854{
1855 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1856 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1857 // TODO: eglBindTexImage()
1858 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1859}
1860
1861EGLBoolean eglReleaseTexImage(
1862 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1863{
1864 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1865 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1866 // TODO: eglReleaseTexImage()
1867 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1868}
1869
1870EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1871{
1872 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1873 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1874 // TODO: eglSwapInterval()
1875 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1876}
1877
1878// ----------------------------------------------------------------------------
1879// EGL 1.2
1880// ----------------------------------------------------------------------------
1881
1882EGLBoolean eglBindAPI(EGLenum api)
1883{
1884 if (api != EGL_OPENGL_ES_API)
1885 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1886 return EGL_TRUE;
1887}
1888
1889EGLenum eglQueryAPI(void)
1890{
1891 return EGL_OPENGL_ES_API;
1892}
1893
1894EGLBoolean eglWaitClient(void)
1895{
1896 glFinish();
1897 return EGL_TRUE;
1898}
1899
1900EGLBoolean eglReleaseThread(void)
1901{
1902 // TODO: eglReleaseThread()
1903 return EGL_TRUE;
1904}
1905
1906EGLSurface eglCreatePbufferFromClientBuffer(
1907 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1908 EGLConfig config, const EGLint *attrib_list)
1909{
1910 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1911 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1912 // TODO: eglCreatePbufferFromClientBuffer()
1913 return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1914}
1915
1916// ----------------------------------------------------------------------------
Mathias Agopian1473f462009-04-10 14:24:30 -07001917// EGL_EGLEXT_VERSION 3
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001918// ----------------------------------------------------------------------------
1919
1920void (*eglGetProcAddress (const char *procname))()
1921{
1922 extention_map_t const * const map = gExtentionMap;
1923 for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
1924 if (!strcmp(procname, map[i].name)) {
1925 return map[i].address;
1926 }
1927 }
1928 return NULL;
1929}
Mathias Agopian1473f462009-04-10 14:24:30 -07001930
1931EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1932 const EGLint *attrib_list)
1933{
1934 EGLBoolean result = EGL_FALSE;
1935 return result;
1936}
1937
1938EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1939{
1940 EGLBoolean result = EGL_FALSE;
1941 return result;
1942}
1943
1944EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1945 EGLClientBuffer buffer, const EGLint *attrib_list)
1946{
1947 if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
1948 return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1949 }
1950 if (ctx != EGL_NO_CONTEXT) {
1951 return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1952 }
1953 if (target != EGL_NATIVE_BUFFER_ANDROID) {
1954 return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1955 }
1956
1957 android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
1958
1959 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
1960 return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1961
1962 if (native_buffer->common.version != sizeof(android_native_buffer_t))
1963 return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
Mathias Agopianaf9a5152009-04-10 20:34:46 -07001964
Mathias Agopian1473f462009-04-10 14:24:30 -07001965 native_buffer->common.incRef(&native_buffer->common);
1966 return (EGLImageKHR)native_buffer;
1967}
1968
1969EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1970{
1971 if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
1972 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1973 }
1974
1975 android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
1976
1977 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
1978 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1979
1980 if (native_buffer->common.version != sizeof(android_native_buffer_t))
1981 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1982
Mathias Agopian1473f462009-04-10 14:24:30 -07001983 native_buffer->common.decRef(&native_buffer->common);
1984
1985 return EGL_TRUE;
1986}
Mathias Agopian2e20bff2009-05-04 19:29:25 -07001987
1988// ----------------------------------------------------------------------------
1989// ANDROID extensions
1990// ----------------------------------------------------------------------------
1991
1992EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1993 EGLint left, EGLint top, EGLint width, EGLint height)
1994{
1995 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1996 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1997
1998 egl_surface_t* d = static_cast<egl_surface_t*>(draw);
1999 if (d->dpy != dpy)
2000 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
2001
2002 // post the surface
2003 d->setSwapRectangle(left, top, width, height);
2004
2005 return EGL_TRUE;
2006}
Mathias Agopianc1e3ec52009-06-24 22:37:39 -07002007
2008EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
2009{
2010 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
2011 return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
2012
2013 egl_surface_t* d = static_cast<egl_surface_t*>(draw);
2014 if (d->dpy != dpy)
2015 return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
2016
2017 // post the surface
2018 return d->getRenderBuffer();
2019}