blob: f50257abb7e8eced4d436f18f9db18a659a281b8 [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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161protected:
162 GGLSurface depth;
163};
164
165egl_surface_t::egl_surface_t(EGLDisplay dpy,
166 EGLConfig config,
167 int32_t depthFormat)
168 : magic(MAGIC), dpy(dpy), config(config), ctx(0)
169{
170 depth.version = sizeof(GGLSurface);
171 depth.data = 0;
172 depth.format = depthFormat;
173}
174egl_surface_t::~egl_surface_t()
175{
176 magic = 0;
177 free(depth.data);
178}
179EGLBoolean egl_surface_t::swapBuffers() {
180 return EGL_FALSE;
181}
182EGLint egl_surface_t::getHorizontalResolution() const {
183 return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
184}
185EGLint egl_surface_t::getVerticalResolution() const {
186 return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
187}
188EGLint egl_surface_t::getRefreshRate() const {
189 return (60 * EGL_DISPLAY_SCALING);
190}
191EGLint egl_surface_t::getSwapBehavior() const {
192 return EGL_BUFFER_PRESERVED;
193}
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700194EGLBoolean egl_surface_t::setSwapRectangle(
195 EGLint l, EGLint t, EGLint w, EGLint h)
196{
197 return EGL_FALSE;
198}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199
200// ----------------------------------------------------------------------------
201
Mathias Agopian1473f462009-04-10 14:24:30 -0700202struct egl_window_surface_v2_t : public egl_surface_t
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203{
Mathias Agopian1473f462009-04-10 14:24:30 -0700204 egl_window_surface_v2_t(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 EGLDisplay dpy, EGLConfig config,
206 int32_t depthFormat,
Mathias Agopian1473f462009-04-10 14:24:30 -0700207 android_native_window_t* window);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208
Mathias Agopian1473f462009-04-10 14:24:30 -0700209 ~egl_window_surface_v2_t();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210
Mathias Agopian1473f462009-04-10 14:24:30 -0700211 virtual bool isValid() const { return nativeWindow->common.magic == ANDROID_NATIVE_WINDOW_MAGIC; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 virtual EGLBoolean swapBuffers();
213 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
214 virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700215 virtual void connect();
216 virtual void disconnect();
Mathias Agopian1473f462009-04-10 14:24:30 -0700217 virtual EGLint getWidth() const { return buffer->width; }
218 virtual EGLint getHeight() const { return buffer->height; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 virtual EGLint getHorizontalResolution() const;
220 virtual EGLint getVerticalResolution() const;
221 virtual EGLint getRefreshRate() const;
222 virtual EGLint getSwapBehavior() const;
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700223 virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225private:
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700226 status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
Mathias Agopiandff8e582009-05-04 14:17:04 -0700227 status_t unlock(android_native_buffer_t* buf);
Mathias Agopian1473f462009-04-10 14:24:30 -0700228 android_native_window_t* nativeWindow;
229 android_native_buffer_t* buffer;
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700230 android_native_buffer_t* previousBuffer;
Mathias Agopiandff8e582009-05-04 14:17:04 -0700231 gralloc_module_t const* module;
Mathias Agopian1473f462009-04-10 14:24:30 -0700232 int width;
233 int height;
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700234 void* bits;
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700235 GGLFormat const* pixelFormatTable;
236
237 struct Rect {
238 inline Rect() { };
239 inline Rect(int32_t w, int32_t h)
240 : left(0), top(0), right(w), bottom(h) { }
241 inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
242 : left(l), top(t), right(r), bottom(b) { }
243 Rect& andSelf(const Rect& r) {
244 left = max(left, r.left);
245 top = max(top, r.top);
246 right = min(right, r.right);
247 bottom = min(bottom, r.bottom);
248 return *this;
249 }
250 bool isEmpty() const {
251 return (left>=right || top>=bottom);
252 }
253 void dump(char const* what) {
254 LOGD("%s { %5d, %5d, w=%5d, h=%5d }",
255 what, left, top, right-left, bottom-top);
256 }
257
258 int32_t left;
259 int32_t top;
260 int32_t right;
261 int32_t bottom;
262 };
263
264 struct Region {
265 inline Region() : count(0) { }
266 static Region subtract(const Rect& lhs, const Rect& rhs) {
267 Region reg;
268 Rect* storage = reg.storage;
269 if (!lhs.isEmpty()) {
270 if (lhs.top < rhs.top) { // top rect
271 storage->left = lhs.left;
272 storage->top = lhs.top;
273 storage->right = lhs.right;
274 storage->bottom = max(lhs.top, rhs.top);
275 storage++;
276 }
277 if (lhs.left < rhs.left) { // left-side rect
278 storage->left = lhs.left;
279 storage->top = max(lhs.top, rhs.top);
280 storage->right = max(lhs.left, rhs.left);
281 storage->bottom = min(lhs.bottom, rhs.bottom);
282 storage++;
283 }
284 if (lhs.right > rhs.right) { // right-side rect
285 storage->left = min(lhs.right, rhs.right);
286 storage->top = max(lhs.top, rhs.top);
287 storage->right = lhs.right;
288 storage->bottom = min(lhs.bottom, rhs.bottom);
289 storage++;
290 }
291 if (lhs.bottom > rhs.bottom) { // bottom rect
292 storage->left = lhs.left;
293 storage->top = min(lhs.bottom, rhs.bottom);
294 storage->right = lhs.right;
295 storage->bottom = lhs.bottom;
296 storage++;
297 }
298 reg.count = storage - reg.storage;
299 }
300 return reg;
301 }
302 bool isEmpty() const {
303 return count<=0;
304 }
305 ssize_t getRects(Rect const* * rects) const {
306 *rects = storage;
307 return count;
308 }
309 private:
310 Rect storage[4];
311 ssize_t count;
312 };
313
314 void copyBlt(
315 android_native_buffer_t* dst, void* dst_vaddr,
316 android_native_buffer_t* src, void const* src_vaddr,
317 const Rect* reg, ssize_t count);
318
319 Rect dirtyRegion;
320 Rect oldDirtyRegion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321};
322
Mathias Agopian1473f462009-04-10 14:24:30 -0700323egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 EGLConfig config,
325 int32_t depthFormat,
Mathias Agopian1473f462009-04-10 14:24:30 -0700326 android_native_window_t* window)
Mathias Agopiandff8e582009-05-04 14:17:04 -0700327 : egl_surface_t(dpy, config, depthFormat),
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700328 nativeWindow(window), buffer(0), previousBuffer(0), module(0),
329 bits(NULL)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330{
Mathias Agopiandff8e582009-05-04 14:17:04 -0700331 hw_module_t const* pModule;
332 hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
333 module = reinterpret_cast<gralloc_module_t const*>(pModule);
334
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700335 pixelFormatTable = gglGetPixelFormatTable();
336
337 // keep a reference on the window
Mathias Agopian1473f462009-04-10 14:24:30 -0700338 nativeWindow->common.incRef(&nativeWindow->common);
339
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700340 // dequeue a buffer
Mathias Agopian1473f462009-04-10 14:24:30 -0700341 nativeWindow->dequeueBuffer(nativeWindow, &buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700342
343 // allocate a corresponding depth-buffer
Mathias Agopian1473f462009-04-10 14:24:30 -0700344 width = buffer->width;
345 height = buffer->height;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 if (depthFormat) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700347 depth.width = width;
348 depth.height = height;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 depth.stride = depth.width; // use the width here
350 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
351 if (depth.data == 0) {
352 setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
353 return;
354 }
355 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700356
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700357 // keep a reference on the buffer
Mathias Agopian1473f462009-04-10 14:24:30 -0700358 buffer->common.incRef(&buffer->common);
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700359}
Mathias Agopian1473f462009-04-10 14:24:30 -0700360
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700361egl_window_surface_v2_t::~egl_window_surface_v2_t() {
362 if (buffer) {
363 buffer->common.decRef(&buffer->common);
364 }
365 if (previousBuffer) {
366 previousBuffer->common.decRef(&previousBuffer->common);
367 }
368 nativeWindow->common.decRef(&nativeWindow->common);
369}
370
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700371void egl_window_surface_v2_t::connect()
372{
Mathias Agopiandff8e582009-05-04 14:17:04 -0700373 // Lock the buffer
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700374 nativeWindow->lockBuffer(nativeWindow, buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700375 // pin the buffer down
376 if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
377 GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
378 LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
379 buffer, buffer->width, buffer->height);
380 setError(EGL_BAD_ACCESS, EGL_NO_SURFACE);
381 // FIXME: we should make sure we're not accessing the buffer anymore
382 }
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700383}
384
385void egl_window_surface_v2_t::disconnect()
386{
387 if (buffer) {
388 bits = NULL;
389 unlock(buffer);
390 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391}
392
Mathias Agopiandff8e582009-05-04 14:17:04 -0700393status_t egl_window_surface_v2_t::lock(
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700394 android_native_buffer_t* buf, int usage, void** vaddr)
Mathias Agopiandff8e582009-05-04 14:17:04 -0700395{
Mathias Agopiane633f932009-05-05 00:59:23 -0700396 int err = module->lock(module, buf->handle,
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700397 usage, 0, 0, buf->width, buf->height, vaddr);
Mathias Agopiandff8e582009-05-04 14:17:04 -0700398 return err;
399}
400
401status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
402{
Mathias Agopiane633f932009-05-05 00:59:23 -0700403 int err = module->unlock(module, buf->handle);
Mathias Agopiandff8e582009-05-04 14:17:04 -0700404 return err;
405}
406
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700407void egl_window_surface_v2_t::copyBlt(
408 android_native_buffer_t* dst, void* dst_vaddr,
409 android_native_buffer_t* src, void const* src_vaddr,
410 const Rect* reg, ssize_t count)
411{
412 // FIXME: use copybit if possible
413 // NOTE: dst and src must be the same format
414
415 Rect r;
416 const size_t bpp = pixelFormatTable[src->format].size;
417 const size_t dbpr = dst->stride * bpp;
418 const size_t sbpr = src->stride * bpp;
Mathias Agopiandff8e582009-05-04 14:17:04 -0700419
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700420 uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
421 uint8_t * const dst_bits = (uint8_t *)dst_vaddr;
422
423 for (int i= 0 ; i<count ; i++) {
424 const Rect& r(reg[i]);
425 ssize_t w = r.right - r.left;
426 ssize_t h = r.bottom - r.top;
427 if (w <= 0 || h<=0) continue;
428 size_t size = w * bpp;
429 uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
430 uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
431 if (dbpr==sbpr && size==sbpr) {
432 size *= h;
433 h = 1;
434 }
435 do {
436 memcpy(d, s, size);
437 d += dbpr;
438 s += sbpr;
439 } while (--h > 0);
Mathias Agopian1473f462009-04-10 14:24:30 -0700440 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700441}
442
443EGLBoolean egl_window_surface_v2_t::swapBuffers()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444{
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700445 /*
446 * Handle eglSetSwapRectangleANDROID()
447 * We copyback from the front buffer
448 */
449 if (!dirtyRegion.isEmpty()) {
450 dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
451 if (previousBuffer) {
452 const Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
453 if (!copyBack.isEmpty()) {
454 Rect const* list;
455 ssize_t count = copyBack.getRects(&list);
456 // copy from previousBuffer to buffer
457 void* prevBits;
458 if (lock(previousBuffer,
459 GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR)
460 {
461 copyBlt(buffer, bits, previousBuffer, prevBits, list, count);
462 unlock(previousBuffer);
463 }
464 }
465 }
466 oldDirtyRegion = dirtyRegion;
467 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700468
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700469 if (previousBuffer) {
470 previousBuffer->common.decRef(&previousBuffer->common);
471 previousBuffer = 0;
472 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700473
Mathias Agopiandff8e582009-05-04 14:17:04 -0700474 unlock(buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700475 previousBuffer = buffer;
Mathias Agopian1473f462009-04-10 14:24:30 -0700476 nativeWindow->queueBuffer(nativeWindow, buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700477 buffer = 0;
Mathias Agopian1473f462009-04-10 14:24:30 -0700478
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700479 // dequeue a new buffer
Mathias Agopian1473f462009-04-10 14:24:30 -0700480 nativeWindow->dequeueBuffer(nativeWindow, &buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700481
Mathias Agopian1473f462009-04-10 14:24:30 -0700482 // TODO: lockBuffer should rather be executed when the very first
483 // direct rendering occurs.
484 nativeWindow->lockBuffer(nativeWindow, buffer);
Mathias Agopian1473f462009-04-10 14:24:30 -0700485
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700486 // reallocate the depth-buffer if needed
Mathias Agopian1473f462009-04-10 14:24:30 -0700487 if ((width != buffer->width) || (height != buffer->height)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 // TODO: we probably should reset the swap rect here
489 // if the window size has changed
Mathias Agopian1473f462009-04-10 14:24:30 -0700490 width = buffer->width;
491 height = buffer->height;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 if (depth.data) {
493 free(depth.data);
Mathias Agopian1473f462009-04-10 14:24:30 -0700494 depth.width = width;
495 depth.height = height;
496 depth.stride = buffer->stride;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
498 if (depth.data == 0) {
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700499 setError(EGL_BAD_ALLOC, EGL_FALSE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 return EGL_FALSE;
501 }
502 }
503 }
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700504
505 // keep a reference on the buffer
506 buffer->common.incRef(&buffer->common);
507
508 // finally pin the buffer down
509 if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
510 GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
511 LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
512 buffer, buffer->width, buffer->height);
513 setError(EGL_BAD_ACCESS, EGL_NO_SURFACE);
514 // FIXME: we should make sure we're not accessing the buffer anymore
515 }
516
517 return EGL_TRUE;
518}
519
520EGLBoolean egl_window_surface_v2_t::setSwapRectangle(
521 EGLint l, EGLint t, EGLint w, EGLint h)
522{
523 dirtyRegion = Rect(l, t, l+w, t+h);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 return EGL_TRUE;
525}
526
Mathias Agopian1473f462009-04-10 14:24:30 -0700527#ifdef LIBAGL_USE_GRALLOC_COPYBITS
528
529static bool supportedCopybitsDestinationFormat(int format) {
530 // Hardware supported and no destination alpha
531 switch (format) {
532 case HAL_PIXEL_FORMAT_RGB_565:
533 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
534 case HAL_PIXEL_FORMAT_YCbCr_420_SP:
535 return true;
536 default:
537 return false;
538 }
539}
540#endif
541
542EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543{
544 GGLSurface buffer;
545 buffer.version = sizeof(GGLSurface);
Mathias Agopian1473f462009-04-10 14:24:30 -0700546 buffer.width = this->buffer->width;
547 buffer.height = this->buffer->height;
548 buffer.stride = this->buffer->stride;
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700549 buffer.data = (GGLubyte*)bits;
Mathias Agopian1473f462009-04-10 14:24:30 -0700550 buffer.format = this->buffer->format;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 gl->rasterizer.procs.colorBuffer(gl, &buffer);
552 if (depth.data != gl->rasterizer.state.buffers.depth.data)
553 gl->rasterizer.procs.depthBuffer(gl, &depth);
Mathias Agopian1473f462009-04-10 14:24:30 -0700554#ifdef LIBAGL_USE_GRALLOC_COPYBITS
555 gl->copybits.drawSurfaceFd = -1;
556 if (supportedCopybitsDestinationFormat(buffer.format)) {
Mathias Agopiane633f932009-05-05 00:59:23 -0700557 buffer_handle_t handle = this->buffer->handle;
Mathias Agopian1473f462009-04-10 14:24:30 -0700558 if (handle != NULL) {
559 private_handle_t* hand = private_handle_t::dynamicCast(handle);
560 if (hand != NULL) {
561 if (hand->usesPhysicallyContiguousMemory()) {
562 gl->copybits.drawSurfaceFd = hand->fd;
563 }
564 }
565 }
566 }
567#endif // LIBAGL_USE_GRALLOC_COPYBITS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 return EGL_TRUE;
569}
Mathias Agopian1473f462009-04-10 14:24:30 -0700570EGLBoolean egl_window_surface_v2_t::bindReadSurface(ogles_context_t* gl)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571{
572 GGLSurface buffer;
573 buffer.version = sizeof(GGLSurface);
Mathias Agopian1473f462009-04-10 14:24:30 -0700574 buffer.width = this->buffer->width;
575 buffer.height = this->buffer->height;
576 buffer.stride = this->buffer->stride;
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700577 buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
Mathias Agopian1473f462009-04-10 14:24:30 -0700578 buffer.format = this->buffer->format;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 gl->rasterizer.procs.readBuffer(gl, &buffer);
580 return EGL_TRUE;
581}
Mathias Agopian1473f462009-04-10 14:24:30 -0700582EGLint egl_window_surface_v2_t::getHorizontalResolution() const {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
584}
Mathias Agopian1473f462009-04-10 14:24:30 -0700585EGLint egl_window_surface_v2_t::getVerticalResolution() const {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
587}
Mathias Agopian1473f462009-04-10 14:24:30 -0700588EGLint egl_window_surface_v2_t::getRefreshRate() const {
589 return (60 * EGL_DISPLAY_SCALING); // FIXME
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590}
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700591EGLint egl_window_surface_v2_t::getSwapBehavior() const
592{
593 /*
594 * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
595 * the content of the swapped buffer.
596 *
597 * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
598 *
599 * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
600 * only applies to the area specified by eglSetSwapRectangleANDROID(), that
601 * is, everything outside of this area is preserved.
602 *
603 * This implementation of EGL assumes the later case.
604 *
605 */
606
Mathias Agopian1473f462009-04-10 14:24:30 -0700607 return EGL_BUFFER_DESTROYED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608}
609
610// ----------------------------------------------------------------------------
611
612struct egl_pixmap_surface_t : public egl_surface_t
613{
614 egl_pixmap_surface_t(
615 EGLDisplay dpy, EGLConfig config,
616 int32_t depthFormat,
617 egl_native_pixmap_t const * pixmap);
618
619 virtual ~egl_pixmap_surface_t() { }
620
Mathias Agopian1473f462009-04-10 14:24:30 -0700621 virtual bool isValid() const { return nativePixmap.version == sizeof(egl_native_pixmap_t); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
623 virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
624 virtual EGLint getWidth() const { return nativePixmap.width; }
625 virtual EGLint getHeight() const { return nativePixmap.height; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626private:
627 egl_native_pixmap_t nativePixmap;
628};
629
630egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
631 EGLConfig config,
632 int32_t depthFormat,
633 egl_native_pixmap_t const * pixmap)
634 : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
635{
636 if (depthFormat) {
637 depth.width = pixmap->width;
638 depth.height = pixmap->height;
639 depth.stride = depth.width; // use the width here
640 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
641 if (depth.data == 0) {
642 setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
643 return;
644 }
645 }
646}
647EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl)
648{
649 GGLSurface buffer;
650 buffer.version = sizeof(GGLSurface);
651 buffer.width = nativePixmap.width;
652 buffer.height = nativePixmap.height;
653 buffer.stride = nativePixmap.stride;
654 buffer.data = nativePixmap.data;
655 buffer.format = nativePixmap.format;
Mathias Agopian1473f462009-04-10 14:24:30 -0700656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 gl->rasterizer.procs.colorBuffer(gl, &buffer);
658 if (depth.data != gl->rasterizer.state.buffers.depth.data)
659 gl->rasterizer.procs.depthBuffer(gl, &depth);
660 return EGL_TRUE;
661}
662EGLBoolean egl_pixmap_surface_t::bindReadSurface(ogles_context_t* gl)
663{
664 GGLSurface buffer;
665 buffer.version = sizeof(GGLSurface);
666 buffer.width = nativePixmap.width;
667 buffer.height = nativePixmap.height;
668 buffer.stride = nativePixmap.stride;
669 buffer.data = nativePixmap.data;
670 buffer.format = nativePixmap.format;
671 gl->rasterizer.procs.readBuffer(gl, &buffer);
672 return EGL_TRUE;
673}
674
675// ----------------------------------------------------------------------------
676
677struct egl_pbuffer_surface_t : public egl_surface_t
678{
679 egl_pbuffer_surface_t(
680 EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
681 int32_t w, int32_t h, int32_t f);
682
683 virtual ~egl_pbuffer_surface_t();
684
Mathias Agopian1473f462009-04-10 14:24:30 -0700685 virtual bool isValid() const { return pbuffer.data != 0; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
687 virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
688 virtual EGLint getWidth() const { return pbuffer.width; }
689 virtual EGLint getHeight() const { return pbuffer.height; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690private:
691 GGLSurface pbuffer;
692};
693
694egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
695 EGLConfig config, int32_t depthFormat,
696 int32_t w, int32_t h, int32_t f)
697 : egl_surface_t(dpy, config, depthFormat)
698{
699 size_t size = w*h;
700 switch (f) {
701 case GGL_PIXEL_FORMAT_A_8: size *= 1; break;
702 case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break;
703 case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break;
704 default:
705 LOGE("incompatible pixel format for pbuffer (format=%d)", f);
706 pbuffer.data = 0;
707 break;
708 }
709 pbuffer.version = sizeof(GGLSurface);
710 pbuffer.width = w;
711 pbuffer.height = h;
712 pbuffer.stride = w;
713 pbuffer.data = (GGLubyte*)malloc(size);
714 pbuffer.format = f;
Mathias Agopian1473f462009-04-10 14:24:30 -0700715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800716 if (depthFormat) {
717 depth.width = pbuffer.width;
718 depth.height = pbuffer.height;
719 depth.stride = depth.width; // use the width here
720 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
721 if (depth.data == 0) {
722 setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
723 return;
724 }
725 }
726}
727egl_pbuffer_surface_t::~egl_pbuffer_surface_t() {
728 free(pbuffer.data);
729}
730EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(ogles_context_t* gl)
731{
732 gl->rasterizer.procs.colorBuffer(gl, &pbuffer);
733 if (depth.data != gl->rasterizer.state.buffers.depth.data)
734 gl->rasterizer.procs.depthBuffer(gl, &depth);
735 return EGL_TRUE;
736}
737EGLBoolean egl_pbuffer_surface_t::bindReadSurface(ogles_context_t* gl)
738{
739 gl->rasterizer.procs.readBuffer(gl, &pbuffer);
740 return EGL_TRUE;
741}
742
743// ----------------------------------------------------------------------------
744
745struct config_pair_t {
746 GLint key;
747 GLint value;
748};
749
750struct configs_t {
751 const config_pair_t* array;
752 int size;
753};
754
755struct config_management_t {
756 GLint key;
757 bool (*match)(GLint reqValue, GLint confValue);
758 static bool atLeast(GLint reqValue, GLint confValue) {
759 return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
760 }
761 static bool exact(GLint reqValue, GLint confValue) {
762 return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
763 }
764 static bool mask(GLint reqValue, GLint confValue) {
765 return (confValue & reqValue) == reqValue;
766 }
767};
768
769// ----------------------------------------------------------------------------
770
771#define VERSION_MAJOR 1
772#define VERSION_MINOR 2
773static char const * const gVendorString = "Google Inc.";
774static char const * const gVersionString = "1.2 Android Driver";
775static char const * const gClientApiString = "OpenGL ES";
Mathias Agopian1473f462009-04-10 14:24:30 -0700776static char const * const gExtensionsString =
Mathias Agopian927d37c2009-05-06 23:47:08 -0700777 "EGL_KHR_image_base "
Mathias Agopian1473f462009-04-10 14:24:30 -0700778 // "KHR_image_pixmap "
779 "EGL_ANDROID_image_native_buffer "
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700780 "EGL_ANDROID_swap_rectangle "
Mathias Agopian1473f462009-04-10 14:24:30 -0700781 ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782
783// ----------------------------------------------------------------------------
784
785struct extention_map_t {
786 const char * const name;
787 __eglMustCastToProperFunctionPointerType address;
788};
789
790static const extention_map_t gExtentionMap[] = {
Mathias Agopian1473f462009-04-10 14:24:30 -0700791 { "glDrawTexsOES",
792 (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES },
793 { "glDrawTexiOES",
794 (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES },
795 { "glDrawTexfOES",
796 (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES },
797 { "glDrawTexxOES",
798 (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES },
799 { "glDrawTexsvOES",
800 (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES },
801 { "glDrawTexivOES",
802 (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES },
803 { "glDrawTexfvOES",
804 (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES },
805 { "glDrawTexxvOES",
806 (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
807 { "glQueryMatrixxOES",
808 (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
809 { "glEGLImageTargetTexture2DOES",
810 (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
811 { "glEGLImageTargetRenderbufferStorageOES",
812 (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
813 { "glClipPlanef",
814 (__eglMustCastToProperFunctionPointerType)&glClipPlanef },
815 { "glClipPlanex",
816 (__eglMustCastToProperFunctionPointerType)&glClipPlanex },
817 { "glBindBuffer",
818 (__eglMustCastToProperFunctionPointerType)&glBindBuffer },
819 { "glBufferData",
820 (__eglMustCastToProperFunctionPointerType)&glBufferData },
821 { "glBufferSubData",
822 (__eglMustCastToProperFunctionPointerType)&glBufferSubData },
823 { "glDeleteBuffers",
824 (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
825 { "glGenBuffers",
826 (__eglMustCastToProperFunctionPointerType)&glGenBuffers },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827};
828
Mathias Agopian1473f462009-04-10 14:24:30 -0700829/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 * In the lists below, attributes names MUST be sorted.
831 * Additionally, all configs must be sorted according to
832 * the EGL specification.
833 */
834
835static config_pair_t const config_base_attribute_list[] = {
836 { EGL_STENCIL_SIZE, 0 },
837 { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG },
838 { EGL_LEVEL, 0 },
839 { EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS },
Mathias Agopian1473f462009-04-10 14:24:30 -0700840 { EGL_MAX_PBUFFER_PIXELS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS },
842 { EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS },
843 { EGL_NATIVE_RENDERABLE, EGL_TRUE },
844 { EGL_NATIVE_VISUAL_ID, 0 },
845 { EGL_NATIVE_VISUAL_TYPE, GGL_PIXEL_FORMAT_RGB_565 },
846 { EGL_SAMPLES, 0 },
847 { EGL_SAMPLE_BUFFERS, 0 },
848 { EGL_TRANSPARENT_TYPE, EGL_NONE },
849 { EGL_TRANSPARENT_BLUE_VALUE, 0 },
850 { EGL_TRANSPARENT_GREEN_VALUE, 0 },
851 { EGL_TRANSPARENT_RED_VALUE, 0 },
852 { EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE },
853 { EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE },
854 { EGL_MIN_SWAP_INTERVAL, 1 },
855 { EGL_MAX_SWAP_INTERVAL, 4 },
856};
857
858// These configs can override the base attribute list
859// NOTE: when adding a config here, don't forget to update eglCreate*Surface()
860
861static config_pair_t const config_0_attribute_list[] = {
862 { EGL_BUFFER_SIZE, 16 },
863 { EGL_ALPHA_SIZE, 0 },
864 { EGL_BLUE_SIZE, 5 },
865 { EGL_GREEN_SIZE, 6 },
866 { EGL_RED_SIZE, 5 },
867 { EGL_DEPTH_SIZE, 0 },
868 { EGL_CONFIG_ID, 0 },
869 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
870};
871
872static config_pair_t const config_1_attribute_list[] = {
873 { EGL_BUFFER_SIZE, 16 },
874 { EGL_ALPHA_SIZE, 0 },
875 { EGL_BLUE_SIZE, 5 },
876 { EGL_GREEN_SIZE, 6 },
877 { EGL_RED_SIZE, 5 },
878 { EGL_DEPTH_SIZE, 16 },
879 { EGL_CONFIG_ID, 1 },
880 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
881};
882
883static config_pair_t const config_2_attribute_list[] = {
884 { EGL_BUFFER_SIZE, 32 },
885 { EGL_ALPHA_SIZE, 8 },
886 { EGL_BLUE_SIZE, 8 },
887 { EGL_GREEN_SIZE, 8 },
888 { EGL_RED_SIZE, 8 },
889 { EGL_DEPTH_SIZE, 0 },
890 { EGL_CONFIG_ID, 2 },
891 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
892};
893
894static config_pair_t const config_3_attribute_list[] = {
895 { EGL_BUFFER_SIZE, 32 },
896 { EGL_ALPHA_SIZE, 8 },
897 { EGL_BLUE_SIZE, 8 },
898 { EGL_GREEN_SIZE, 8 },
899 { EGL_RED_SIZE, 8 },
900 { EGL_DEPTH_SIZE, 16 },
901 { EGL_CONFIG_ID, 3 },
902 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
903};
904
905static config_pair_t const config_4_attribute_list[] = {
906 { EGL_BUFFER_SIZE, 8 },
907 { EGL_ALPHA_SIZE, 8 },
908 { EGL_BLUE_SIZE, 0 },
909 { EGL_GREEN_SIZE, 0 },
910 { EGL_RED_SIZE, 0 },
911 { EGL_DEPTH_SIZE, 0 },
912 { EGL_CONFIG_ID, 4 },
913 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
914};
915
916static config_pair_t const config_5_attribute_list[] = {
917 { EGL_BUFFER_SIZE, 8 },
918 { EGL_ALPHA_SIZE, 8 },
919 { EGL_BLUE_SIZE, 0 },
920 { EGL_GREEN_SIZE, 0 },
921 { EGL_RED_SIZE, 0 },
922 { EGL_DEPTH_SIZE, 16 },
923 { EGL_CONFIG_ID, 5 },
924 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
925};
926
927static configs_t const gConfigs[] = {
928 { config_0_attribute_list, NELEM(config_0_attribute_list) },
929 { config_1_attribute_list, NELEM(config_1_attribute_list) },
930 { config_2_attribute_list, NELEM(config_2_attribute_list) },
931 { config_3_attribute_list, NELEM(config_3_attribute_list) },
932 { config_4_attribute_list, NELEM(config_4_attribute_list) },
933 { config_5_attribute_list, NELEM(config_5_attribute_list) },
934};
935
936static config_management_t const gConfigManagement[] = {
937 { EGL_BUFFER_SIZE, config_management_t::atLeast },
938 { EGL_ALPHA_SIZE, config_management_t::atLeast },
939 { EGL_BLUE_SIZE, config_management_t::atLeast },
940 { EGL_GREEN_SIZE, config_management_t::atLeast },
941 { EGL_RED_SIZE, config_management_t::atLeast },
942 { EGL_DEPTH_SIZE, config_management_t::atLeast },
943 { EGL_STENCIL_SIZE, config_management_t::atLeast },
944 { EGL_CONFIG_CAVEAT, config_management_t::exact },
945 { EGL_CONFIG_ID, config_management_t::exact },
946 { EGL_LEVEL, config_management_t::exact },
947 { EGL_MAX_PBUFFER_HEIGHT, config_management_t::exact },
948 { EGL_MAX_PBUFFER_PIXELS, config_management_t::exact },
949 { EGL_MAX_PBUFFER_WIDTH, config_management_t::exact },
950 { EGL_NATIVE_RENDERABLE, config_management_t::exact },
951 { EGL_NATIVE_VISUAL_ID, config_management_t::exact },
952 { EGL_NATIVE_VISUAL_TYPE, config_management_t::exact },
953 { EGL_SAMPLES, config_management_t::exact },
954 { EGL_SAMPLE_BUFFERS, config_management_t::exact },
955 { EGL_SURFACE_TYPE, config_management_t::mask },
956 { EGL_TRANSPARENT_TYPE, config_management_t::exact },
957 { EGL_TRANSPARENT_BLUE_VALUE, config_management_t::exact },
958 { EGL_TRANSPARENT_GREEN_VALUE, config_management_t::exact },
959 { EGL_TRANSPARENT_RED_VALUE, config_management_t::exact },
960 { EGL_BIND_TO_TEXTURE_RGBA, config_management_t::exact },
961 { EGL_BIND_TO_TEXTURE_RGB, config_management_t::exact },
962 { EGL_MIN_SWAP_INTERVAL, config_management_t::exact },
963 { EGL_MAX_SWAP_INTERVAL, config_management_t::exact },
964};
965
966static config_pair_t const config_defaults[] = {
967 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
968};
969
970// ----------------------------------------------------------------------------
971
972template<typename T>
973static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
974{
975 while (first <= last) {
976 int mid = (first + last) / 2;
Mathias Agopian1473f462009-04-10 14:24:30 -0700977 if (key > sortedArray[mid].key) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 first = mid + 1;
Mathias Agopian1473f462009-04-10 14:24:30 -0700979 } else if (key < sortedArray[mid].key) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 last = mid - 1;
981 } else {
982 return mid;
983 }
984 }
985 return -1;
986}
987
988static int isAttributeMatching(int i, EGLint attr, EGLint val)
989{
990 // look for the attribute in all of our configs
Mathias Agopian1473f462009-04-10 14:24:30 -0700991 config_pair_t const* configFound = gConfigs[i].array;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 int index = binarySearch<config_pair_t>(
993 gConfigs[i].array,
994 0, gConfigs[i].size-1,
995 attr);
996 if (index < 0) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700997 configFound = config_base_attribute_list;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 index = binarySearch<config_pair_t>(
999 config_base_attribute_list,
1000 0, NELEM(config_base_attribute_list)-1,
1001 attr);
1002 }
1003 if (index >= 0) {
1004 // attribute found, check if this config could match
1005 int cfgMgtIndex = binarySearch<config_management_t>(
1006 gConfigManagement,
1007 0, NELEM(gConfigManagement)-1,
1008 attr);
1009 if (index >= 0) {
1010 bool match = gConfigManagement[cfgMgtIndex].match(
1011 val, configFound[index].value);
1012 if (match) {
1013 // this config matches
1014 return 1;
1015 }
1016 } else {
1017 // attribute not found. this should NEVER happen.
1018 }
1019 } else {
1020 // error, this attribute doesn't exist
1021 }
1022 return 0;
1023}
1024
1025static int makeCurrent(ogles_context_t* gl)
1026{
1027 ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();
1028 if (gl) {
1029 egl_context_t* c = egl_context_t::context(gl);
1030 if (c->flags & egl_context_t::IS_CURRENT) {
1031 if (current != gl) {
1032 // it is an error to set a context current, if it's already
1033 // current to another thread
1034 return -1;
1035 }
1036 } else {
1037 if (current) {
1038 // mark the current context as not current, and flush
1039 glFlush();
1040 egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
1041 }
1042 }
1043 if (!(c->flags & egl_context_t::IS_CURRENT)) {
1044 // The context is not current, make it current!
1045 setGlThreadSpecific(gl);
1046 c->flags |= egl_context_t::IS_CURRENT;
1047 }
1048 } else {
1049 if (current) {
1050 // mark the current context as not current, and flush
1051 glFlush();
1052 egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
1053 }
1054 // this thread has no context attached to it
1055 setGlThreadSpecific(0);
1056 }
1057 return 0;
1058}
1059
1060static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
1061 EGLint attribute, EGLint *value)
1062{
1063 size_t numConfigs = NELEM(gConfigs);
1064 int index = (int)config;
1065 if (uint32_t(index) >= numConfigs)
1066 return setError(EGL_BAD_CONFIG, EGL_FALSE);
1067
1068 int attrIndex;
1069 attrIndex = binarySearch<config_pair_t>(
1070 gConfigs[index].array,
1071 0, gConfigs[index].size-1,
1072 attribute);
1073 if (attrIndex>=0) {
1074 *value = gConfigs[index].array[attrIndex].value;
1075 return EGL_TRUE;
1076 }
1077
1078 attrIndex = binarySearch<config_pair_t>(
1079 config_base_attribute_list,
1080 0, NELEM(config_base_attribute_list)-1,
1081 attribute);
1082 if (attrIndex>=0) {
1083 *value = config_base_attribute_list[attrIndex].value;
1084 return EGL_TRUE;
1085 }
1086 return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1087}
1088
1089static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
1090 NativeWindowType window, const EGLint *attrib_list)
1091{
1092 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1093 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1094 if (window == 0)
1095 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1096
1097 EGLint surfaceType;
1098 if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
1099 return EGL_FALSE;
1100
1101 if (!(surfaceType & EGL_WINDOW_BIT))
1102 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1103
1104 EGLint configID;
1105 if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
1106 return EGL_FALSE;
1107
1108 int32_t depthFormat;
1109 int32_t pixelFormat;
1110 switch(configID) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001111 case 0:
1112 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 depthFormat = 0;
1114 break;
1115 case 1:
Mathias Agopian1473f462009-04-10 14:24:30 -07001116 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1118 break;
1119 case 2:
Mathias Agopian1473f462009-04-10 14:24:30 -07001120 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121 depthFormat = 0;
1122 break;
1123 case 3:
Mathias Agopian1473f462009-04-10 14:24:30 -07001124 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1126 break;
1127 case 4:
Mathias Agopian1473f462009-04-10 14:24:30 -07001128 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 depthFormat = 0;
1130 break;
1131 case 5:
Mathias Agopian1473f462009-04-10 14:24:30 -07001132 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1134 break;
1135 default:
1136 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1137 }
1138
1139 // FIXME: we don't have access to the pixelFormat here just yet.
1140 // (it's possible that the surface is not fully initialized)
1141 // maybe this should be done after the page-flip
1142 //if (EGLint(info.format) != pixelFormat)
1143 // return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1144
Mathias Agopian1473f462009-04-10 14:24:30 -07001145 egl_surface_t* surface;
1146 surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
1147 static_cast<android_native_window_t*>(window));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148
1149 if (!surface->isValid()) {
1150 // there was a problem in the ctor, the error
1151 // flag has been set.
1152 delete surface;
1153 surface = 0;
1154 }
1155 return surface;
1156}
1157
1158static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
1159 NativePixmapType pixmap, const EGLint *attrib_list)
1160{
1161 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1162 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1163 if (pixmap == 0)
1164 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1165
1166 EGLint surfaceType;
1167 if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
1168 return EGL_FALSE;
1169
1170 if (!(surfaceType & EGL_PIXMAP_BIT))
1171 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1172
1173 EGLint configID;
1174 if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
1175 return EGL_FALSE;
1176
1177 int32_t depthFormat;
1178 int32_t pixelFormat;
1179 switch(configID) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001180 case 0:
1181 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 depthFormat = 0;
1183 break;
1184 case 1:
Mathias Agopian1473f462009-04-10 14:24:30 -07001185 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001186 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1187 break;
1188 case 2:
Mathias Agopian1473f462009-04-10 14:24:30 -07001189 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190 depthFormat = 0;
1191 break;
1192 case 3:
Mathias Agopian1473f462009-04-10 14:24:30 -07001193 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1195 break;
1196 case 4:
Mathias Agopian1473f462009-04-10 14:24:30 -07001197 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 depthFormat = 0;
1199 break;
1200 case 5:
Mathias Agopian1473f462009-04-10 14:24:30 -07001201 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1203 break;
1204 default:
1205 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1206 }
1207
1208 if (pixmap->format != pixelFormat)
1209 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1210
1211 egl_surface_t* surface =
1212 new egl_pixmap_surface_t(dpy, config, depthFormat,
1213 static_cast<egl_native_pixmap_t*>(pixmap));
1214
1215 if (!surface->isValid()) {
1216 // there was a problem in the ctor, the error
1217 // flag has been set.
1218 delete surface;
1219 surface = 0;
1220 }
1221 return surface;
1222}
1223
1224static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
1225 const EGLint *attrib_list)
1226{
1227 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1228 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1229
1230 EGLint surfaceType;
1231 if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
1232 return EGL_FALSE;
Mathias Agopian1473f462009-04-10 14:24:30 -07001233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 if (!(surfaceType & EGL_PBUFFER_BIT))
1235 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237 EGLint configID;
1238 if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
1239 return EGL_FALSE;
1240
1241 int32_t depthFormat;
1242 int32_t pixelFormat;
1243 switch(configID) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001244 case 0:
1245 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 depthFormat = 0;
1247 break;
1248 case 1:
Mathias Agopian1473f462009-04-10 14:24:30 -07001249 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1251 break;
1252 case 2:
Mathias Agopian1473f462009-04-10 14:24:30 -07001253 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 depthFormat = 0;
1255 break;
1256 case 3:
Mathias Agopian1473f462009-04-10 14:24:30 -07001257 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1259 break;
1260 case 4:
Mathias Agopian1473f462009-04-10 14:24:30 -07001261 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 depthFormat = 0;
1263 break;
1264 case 5:
Mathias Agopian1473f462009-04-10 14:24:30 -07001265 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1267 break;
1268 default:
1269 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1270 }
1271
1272 int32_t w = 0;
1273 int32_t h = 0;
1274 while (attrib_list[0]) {
1275 if (attrib_list[0] == EGL_WIDTH) w = attrib_list[1];
1276 if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
1277 attrib_list+=2;
1278 }
1279
1280 egl_surface_t* surface =
1281 new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
1282
1283 if (!surface->isValid()) {
1284 // there was a problem in the ctor, the error
1285 // flag has been set.
1286 delete surface;
1287 surface = 0;
1288 }
1289 return surface;
1290}
1291
1292// ----------------------------------------------------------------------------
1293}; // namespace android
1294// ----------------------------------------------------------------------------
1295
1296using namespace android;
1297
1298// ----------------------------------------------------------------------------
1299// Initialization
1300// ----------------------------------------------------------------------------
1301
1302EGLDisplay eglGetDisplay(NativeDisplayType display)
1303{
1304#ifndef HAVE_ANDROID_OS
1305 // this just needs to be done once
1306 if (gGLKey == -1) {
1307 pthread_mutex_lock(&gInitMutex);
1308 if (gGLKey == -1)
1309 pthread_key_create(&gGLKey, NULL);
1310 pthread_mutex_unlock(&gInitMutex);
1311 }
1312#endif
1313 if (display == EGL_DEFAULT_DISPLAY) {
1314 EGLDisplay dpy = (EGLDisplay)1;
1315 egl_display_t& d = egl_display_t::get_display(dpy);
1316 d.type = display;
1317 return dpy;
Mathias Agopian1473f462009-04-10 14:24:30 -07001318 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 return EGL_NO_DISPLAY;
1320}
1321
1322EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
1323{
1324 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1325 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 EGLBoolean res = EGL_TRUE;
1328 egl_display_t& d = egl_display_t::get_display(dpy);
Mathias Agopian1473f462009-04-10 14:24:30 -07001329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 if (android_atomic_inc(&d.initialized) == 0) {
1331 // initialize stuff here if needed
1332 //pthread_mutex_lock(&gInitMutex);
1333 //pthread_mutex_unlock(&gInitMutex);
1334 }
1335
1336 if (res == EGL_TRUE) {
1337 if (major != NULL) *major = VERSION_MAJOR;
1338 if (minor != NULL) *minor = VERSION_MINOR;
1339 }
1340 return res;
1341}
1342
1343EGLBoolean eglTerminate(EGLDisplay dpy)
1344{
1345 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1346 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1347
1348 EGLBoolean res = EGL_TRUE;
1349 egl_display_t& d = egl_display_t::get_display(dpy);
1350 if (android_atomic_dec(&d.initialized) == 1) {
1351 // TODO: destroy all resources (surfaces, contexts, etc...)
1352 //pthread_mutex_lock(&gInitMutex);
1353 //pthread_mutex_unlock(&gInitMutex);
1354 }
1355 return res;
1356}
1357
1358// ----------------------------------------------------------------------------
1359// configuration
1360// ----------------------------------------------------------------------------
1361
1362EGLBoolean eglGetConfigs( EGLDisplay dpy,
1363 EGLConfig *configs,
1364 EGLint config_size, EGLint *num_config)
1365{
1366 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1367 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1368
1369 GLint numConfigs = NELEM(gConfigs);
1370 if (!configs) {
1371 *num_config = numConfigs;
1372 return EGL_TRUE;
1373 }
1374 GLint i;
1375 for (i=0 ; i<numConfigs && i<config_size ; i++) {
1376 *configs++ = (EGLConfig)i;
1377 }
1378 *num_config = i;
1379 return EGL_TRUE;
1380}
1381
1382EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
1383 EGLConfig *configs, EGLint config_size,
1384 EGLint *num_config)
1385{
1386 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1387 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Jack Palevich1badb712009-03-25 15:12:17 -07001388
1389 if (ggl_unlikely(num_config==0)) {
1390 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1391 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392
Jack Palevich1badb712009-03-25 15:12:17 -07001393 if (ggl_unlikely(attrib_list==0)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 *num_config = 0;
1395 return EGL_TRUE;
1396 }
Mathias Agopian1473f462009-04-10 14:24:30 -07001397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 int numAttributes = 0;
1399 int numConfigs = NELEM(gConfigs);
1400 uint32_t possibleMatch = (1<<numConfigs)-1;
1401 while(possibleMatch && *attrib_list != EGL_NONE) {
1402 numAttributes++;
1403 EGLint attr = *attrib_list++;
1404 EGLint val = *attrib_list++;
1405 for (int i=0 ; i<numConfigs ; i++) {
1406 if (!(possibleMatch & (1<<i)))
1407 continue;
1408 if (isAttributeMatching(i, attr, val) == 0) {
1409 possibleMatch &= ~(1<<i);
1410 }
1411 }
1412 }
1413
1414 // now, handle the attributes which have a useful default value
1415 for (size_t j=0 ; j<NELEM(config_defaults) ; j++) {
1416 // see if this attribute was specified, if not apply its
1417 // default value
1418 if (binarySearch<config_pair_t>(
1419 (config_pair_t const*)attrib_list,
1420 0, numAttributes,
1421 config_defaults[j].key) < 0)
1422 {
1423 for (int i=0 ; i<numConfigs ; i++) {
1424 if (!(possibleMatch & (1<<i)))
1425 continue;
1426 if (isAttributeMatching(i,
1427 config_defaults[j].key,
1428 config_defaults[j].value) == 0)
1429 {
1430 possibleMatch &= ~(1<<i);
1431 }
1432 }
1433 }
1434 }
1435
1436 // return the configurations found
1437 int n=0;
1438 if (possibleMatch) {
Jack Palevich1badb712009-03-25 15:12:17 -07001439 if (configs) {
1440 for (int i=0 ; config_size && i<numConfigs ; i++) {
1441 if (possibleMatch & (1<<i)) {
1442 *configs++ = (EGLConfig)i;
1443 config_size--;
1444 n++;
1445 }
1446 }
1447 } else {
1448 for (int i=0 ; i<numConfigs ; i++) {
1449 if (possibleMatch & (1<<i)) {
1450 n++;
1451 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452 }
1453 }
1454 }
1455 *num_config = n;
1456 return EGL_TRUE;
1457}
1458
1459EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
1460 EGLint attribute, EGLint *value)
1461{
1462 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1463 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1464
1465 return getConfigAttrib(dpy, config, attribute, value);
1466}
1467
1468// ----------------------------------------------------------------------------
1469// surfaces
1470// ----------------------------------------------------------------------------
1471
1472EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
1473 NativeWindowType window,
1474 const EGLint *attrib_list)
1475{
1476 return createWindowSurface(dpy, config, window, attrib_list);
1477}
Mathias Agopian1473f462009-04-10 14:24:30 -07001478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
1480 NativePixmapType pixmap,
1481 const EGLint *attrib_list)
1482{
1483 return createPixmapSurface(dpy, config, pixmap, attrib_list);
1484}
1485
1486EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
1487 const EGLint *attrib_list)
1488{
1489 return createPbufferSurface(dpy, config, attrib_list);
1490}
Mathias Agopian1473f462009-04-10 14:24:30 -07001491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
1493{
1494 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1495 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1496 if (eglSurface != EGL_NO_SURFACE) {
1497 egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
1498 if (surface->magic != egl_surface_t::MAGIC)
1499 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1500 if (surface->dpy != dpy)
1501 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001502 if (surface->ctx) {
1503 // FIXME: this surface is current check what the spec says
1504 surface->disconnect();
1505 surface->ctx = 0;
1506 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 delete surface;
1508 }
1509 return EGL_TRUE;
1510}
1511
1512EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
1513 EGLint attribute, EGLint *value)
1514{
1515 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1516 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1517 egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
1518 if (surface->dpy != dpy)
1519 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1520
1521 EGLBoolean ret = EGL_TRUE;
1522 switch (attribute) {
1523 case EGL_CONFIG_ID:
1524 ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
1525 break;
1526 case EGL_WIDTH:
1527 *value = surface->getWidth();
1528 break;
1529 case EGL_HEIGHT:
1530 *value = surface->getHeight();
1531 break;
1532 case EGL_LARGEST_PBUFFER:
1533 // not modified for a window or pixmap surface
1534 break;
1535 case EGL_TEXTURE_FORMAT:
1536 *value = EGL_NO_TEXTURE;
1537 break;
1538 case EGL_TEXTURE_TARGET:
1539 *value = EGL_NO_TEXTURE;
1540 break;
1541 case EGL_MIPMAP_TEXTURE:
1542 *value = EGL_FALSE;
1543 break;
1544 case EGL_MIPMAP_LEVEL:
1545 *value = 0;
1546 break;
1547 case EGL_RENDER_BUFFER:
1548 // TODO: return the real RENDER_BUFFER here
1549 *value = EGL_BACK_BUFFER;
1550 break;
1551 case EGL_HORIZONTAL_RESOLUTION:
1552 // pixel/mm * EGL_DISPLAY_SCALING
1553 *value = surface->getHorizontalResolution();
1554 break;
1555 case EGL_VERTICAL_RESOLUTION:
1556 // pixel/mm * EGL_DISPLAY_SCALING
1557 *value = surface->getVerticalResolution();
1558 break;
1559 case EGL_PIXEL_ASPECT_RATIO: {
1560 // w/h * EGL_DISPLAY_SCALING
1561 int wr = surface->getHorizontalResolution();
1562 int hr = surface->getVerticalResolution();
1563 *value = (wr * EGL_DISPLAY_SCALING) / hr;
1564 } break;
1565 case EGL_SWAP_BEHAVIOR:
Mathias Agopian1473f462009-04-10 14:24:30 -07001566 *value = surface->getSwapBehavior();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 break;
1568 default:
1569 ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1570 }
1571 return ret;
1572}
1573
1574EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1575 EGLContext share_list, const EGLint *attrib_list)
1576{
1577 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1578 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1579
1580 ogles_context_t* gl = ogles_init(sizeof(egl_context_t));
1581 if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
1582
1583 egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
1584 c->flags = egl_context_t::NEVER_CURRENT;
1585 c->dpy = dpy;
1586 c->config = config;
1587 c->read = 0;
1588 c->draw = 0;
1589 return (EGLContext)gl;
1590}
1591
1592EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1593{
1594 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1595 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1596 egl_context_t* c = egl_context_t::context(ctx);
1597 if (c->flags & egl_context_t::IS_CURRENT)
1598 setGlThreadSpecific(0);
1599 ogles_uninit((ogles_context_t*)ctx);
1600 return EGL_TRUE;
1601}
1602
1603EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
1604 EGLSurface read, EGLContext ctx)
1605{
1606 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1607 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1608 if (draw) {
1609 egl_surface_t* s = (egl_surface_t*)draw;
1610 if (s->dpy != dpy)
1611 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1612 // TODO: check that draw and read are compatible with the context
1613 }
1614
1615 EGLContext current_ctx = EGL_NO_CONTEXT;
Mathias Agopian1473f462009-04-10 14:24:30 -07001616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
1618 return setError(EGL_BAD_MATCH, EGL_FALSE);
1619
1620 if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
1621 return setError(EGL_BAD_MATCH, EGL_FALSE);
1622
1623 if (ctx == EGL_NO_CONTEXT) {
1624 // if we're detaching, we need the current context
1625 current_ctx = (EGLContext)getGlThreadSpecific();
1626 } else {
1627 egl_context_t* c = egl_context_t::context(ctx);
1628 egl_surface_t* d = (egl_surface_t*)draw;
1629 egl_surface_t* r = (egl_surface_t*)read;
1630 if ((d && d->ctx && d->ctx != ctx) ||
1631 (r && r->ctx && r->ctx != ctx)) {
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001632 // one of the surface is bound to a context in another thread
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 return setError(EGL_BAD_ACCESS, EGL_FALSE);
1634 }
1635 }
1636
1637 ogles_context_t* gl = (ogles_context_t*)ctx;
1638 if (makeCurrent(gl) == 0) {
1639 if (ctx) {
1640 egl_context_t* c = egl_context_t::context(ctx);
1641 egl_surface_t* d = (egl_surface_t*)draw;
1642 egl_surface_t* r = (egl_surface_t*)read;
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001643
1644 if (c->draw) {
1645 reinterpret_cast<egl_surface_t*>(c->draw)->disconnect();
1646 }
1647 if (c->read) {
1648 // FIXME: unlock/disconnect the read surface too
1649 }
1650
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 c->draw = draw;
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001652 c->read = read;
1653
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 if (c->flags & egl_context_t::NEVER_CURRENT) {
1655 c->flags &= ~egl_context_t::NEVER_CURRENT;
1656 GLint w = 0;
1657 GLint h = 0;
1658 if (draw) {
1659 w = d->getWidth();
1660 h = d->getHeight();
1661 }
1662 ogles_surfaceport(gl, 0, 0);
1663 ogles_viewport(gl, 0, 0, w, h);
1664 ogles_scissor(gl, 0, 0, w, h);
1665 }
1666 if (d) {
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001667 d->connect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 d->ctx = ctx;
1669 d->bindDrawSurface(gl);
1670 }
1671 if (r) {
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001672 // FIXME: lock/connect the read surface too
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673 r->ctx = ctx;
1674 r->bindReadSurface(gl);
1675 }
1676 } else {
1677 // if surfaces were bound to the context bound to this thread
1678 // mark then as unbound.
1679 if (current_ctx) {
1680 egl_context_t* c = egl_context_t::context(current_ctx);
1681 egl_surface_t* d = (egl_surface_t*)c->draw;
1682 egl_surface_t* r = (egl_surface_t*)c->read;
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001683 if (d) {
1684 d->ctx = EGL_NO_CONTEXT;
1685 d->disconnect();
1686 }
1687 if (r) {
1688 r->ctx = EGL_NO_CONTEXT;
1689 // FIXME: unlock/disconnect the read surface too
1690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 }
1692 }
1693 return EGL_TRUE;
1694 }
1695 return setError(EGL_BAD_ACCESS, EGL_FALSE);
1696}
1697
1698EGLContext eglGetCurrentContext(void)
1699{
1700 // eglGetCurrentContext returns the current EGL rendering context,
1701 // as specified by eglMakeCurrent. If no context is current,
1702 // EGL_NO_CONTEXT is returned.
1703 return (EGLContext)getGlThreadSpecific();
1704}
1705
1706EGLSurface eglGetCurrentSurface(EGLint readdraw)
1707{
1708 // eglGetCurrentSurface returns the read or draw surface attached
1709 // to the current EGL rendering context, as specified by eglMakeCurrent.
1710 // If no context is current, EGL_NO_SURFACE is returned.
1711 EGLContext ctx = (EGLContext)getGlThreadSpecific();
1712 if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
1713 egl_context_t* c = egl_context_t::context(ctx);
1714 if (readdraw == EGL_READ) {
1715 return c->read;
1716 } else if (readdraw == EGL_DRAW) {
1717 return c->draw;
1718 }
1719 return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
1720}
1721
1722EGLDisplay eglGetCurrentDisplay(void)
1723{
1724 // eglGetCurrentDisplay returns the current EGL display connection
1725 // for the current EGL rendering context, as specified by eglMakeCurrent.
1726 // If no context is current, EGL_NO_DISPLAY is returned.
1727 EGLContext ctx = (EGLContext)getGlThreadSpecific();
1728 if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
1729 egl_context_t* c = egl_context_t::context(ctx);
1730 return c->dpy;
1731}
1732
1733EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1734 EGLint attribute, EGLint *value)
1735{
1736 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1737 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1738 egl_context_t* c = egl_context_t::context(ctx);
1739 switch (attribute) {
1740 case EGL_CONFIG_ID:
1741 // Returns the ID of the EGL frame buffer configuration with
1742 // respect to which the context was created
1743 return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
1744 }
1745 return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1746}
1747
1748EGLBoolean eglWaitGL(void)
1749{
1750 return EGL_TRUE;
1751}
1752
1753EGLBoolean eglWaitNative(EGLint engine)
1754{
1755 return EGL_TRUE;
1756}
1757
1758EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1759{
1760 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1761 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 egl_surface_t* d = static_cast<egl_surface_t*>(draw);
1764 if (d->dpy != dpy)
1765 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1766
1767 // post the surface
1768 d->swapBuffers();
1769
1770 // if it's bound to a context, update the buffer
1771 if (d->ctx != EGL_NO_CONTEXT) {
1772 d->bindDrawSurface((ogles_context_t*)d->ctx);
1773 // if this surface is also the read surface of the context
1774 // it is bound to, make sure to update the read buffer as well.
1775 // The EGL spec is a little unclear about this.
1776 egl_context_t* c = egl_context_t::context(d->ctx);
1777 if (c->read == draw) {
1778 d->bindReadSurface((ogles_context_t*)d->ctx);
1779 }
1780 }
1781
1782 return EGL_TRUE;
1783}
1784
1785EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1786 NativePixmapType target)
1787{
1788 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1789 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1790 // TODO: eglCopyBuffers()
1791 return EGL_FALSE;
1792}
1793
1794EGLint eglGetError(void)
1795{
1796 return getError();
1797}
1798
1799const char* eglQueryString(EGLDisplay dpy, EGLint name)
1800{
1801 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1802 return setError(EGL_BAD_DISPLAY, (const char*)0);
1803
1804 switch (name) {
1805 case EGL_VENDOR:
1806 return gVendorString;
1807 case EGL_VERSION:
1808 return gVersionString;
1809 case EGL_EXTENSIONS:
1810 return gExtensionsString;
1811 case EGL_CLIENT_APIS:
1812 return gClientApiString;
1813 }
1814 return setError(EGL_BAD_PARAMETER, (const char *)0);
1815}
1816
1817// ----------------------------------------------------------------------------
1818// EGL 1.1
1819// ----------------------------------------------------------------------------
1820
1821EGLBoolean eglSurfaceAttrib(
1822 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1823{
1824 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1825 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1826 // TODO: eglSurfaceAttrib()
1827 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1828}
1829
1830EGLBoolean eglBindTexImage(
1831 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1832{
1833 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1834 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1835 // TODO: eglBindTexImage()
1836 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1837}
1838
1839EGLBoolean eglReleaseTexImage(
1840 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1841{
1842 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1843 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1844 // TODO: eglReleaseTexImage()
1845 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1846}
1847
1848EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1849{
1850 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1851 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1852 // TODO: eglSwapInterval()
1853 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1854}
1855
1856// ----------------------------------------------------------------------------
1857// EGL 1.2
1858// ----------------------------------------------------------------------------
1859
1860EGLBoolean eglBindAPI(EGLenum api)
1861{
1862 if (api != EGL_OPENGL_ES_API)
1863 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1864 return EGL_TRUE;
1865}
1866
1867EGLenum eglQueryAPI(void)
1868{
1869 return EGL_OPENGL_ES_API;
1870}
1871
1872EGLBoolean eglWaitClient(void)
1873{
1874 glFinish();
1875 return EGL_TRUE;
1876}
1877
1878EGLBoolean eglReleaseThread(void)
1879{
1880 // TODO: eglReleaseThread()
1881 return EGL_TRUE;
1882}
1883
1884EGLSurface eglCreatePbufferFromClientBuffer(
1885 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1886 EGLConfig config, const EGLint *attrib_list)
1887{
1888 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1889 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1890 // TODO: eglCreatePbufferFromClientBuffer()
1891 return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1892}
1893
1894// ----------------------------------------------------------------------------
Mathias Agopian1473f462009-04-10 14:24:30 -07001895// EGL_EGLEXT_VERSION 3
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001896// ----------------------------------------------------------------------------
1897
1898void (*eglGetProcAddress (const char *procname))()
1899{
1900 extention_map_t const * const map = gExtentionMap;
1901 for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
1902 if (!strcmp(procname, map[i].name)) {
1903 return map[i].address;
1904 }
1905 }
1906 return NULL;
1907}
Mathias Agopian1473f462009-04-10 14:24:30 -07001908
1909EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1910 const EGLint *attrib_list)
1911{
1912 EGLBoolean result = EGL_FALSE;
1913 return result;
1914}
1915
1916EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1917{
1918 EGLBoolean result = EGL_FALSE;
1919 return result;
1920}
1921
1922EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1923 EGLClientBuffer buffer, const EGLint *attrib_list)
1924{
1925 if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
1926 return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1927 }
1928 if (ctx != EGL_NO_CONTEXT) {
1929 return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1930 }
1931 if (target != EGL_NATIVE_BUFFER_ANDROID) {
1932 return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1933 }
1934
1935 android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
1936
1937 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
1938 return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1939
1940 if (native_buffer->common.version != sizeof(android_native_buffer_t))
1941 return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
Mathias Agopianaf9a5152009-04-10 20:34:46 -07001942
Mathias Agopian1473f462009-04-10 14:24:30 -07001943 native_buffer->common.incRef(&native_buffer->common);
1944 return (EGLImageKHR)native_buffer;
1945}
1946
1947EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1948{
1949 if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
1950 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1951 }
1952
1953 android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
1954
1955 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
1956 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1957
1958 if (native_buffer->common.version != sizeof(android_native_buffer_t))
1959 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1960
Mathias Agopian1473f462009-04-10 14:24:30 -07001961 native_buffer->common.decRef(&native_buffer->common);
1962
1963 return EGL_TRUE;
1964}
Mathias Agopian2e20bff2009-05-04 19:29:25 -07001965
1966// ----------------------------------------------------------------------------
1967// ANDROID extensions
1968// ----------------------------------------------------------------------------
1969
1970EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1971 EGLint left, EGLint top, EGLint width, EGLint height)
1972{
1973 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1974 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1975
1976 egl_surface_t* d = static_cast<egl_surface_t*>(draw);
1977 if (d->dpy != dpy)
1978 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1979
1980 // post the surface
1981 d->setSwapRectangle(left, top, width, height);
1982
1983 return EGL_TRUE;
1984}