blob: cf66be33729fead2f88e57a7b726dae13e83e636 [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
Mathias Agopian68eeb802009-06-25 15:39:25 -070044#include <hardware/copybit.h>
45
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046#include "context.h"
47#include "state.h"
48#include "texture.h"
49#include "matrix.h"
50
51#undef NELEM
52#define NELEM(x) (sizeof(x)/sizeof(*(x)))
53
54// ----------------------------------------------------------------------------
55namespace android {
56// ----------------------------------------------------------------------------
57
58const unsigned int NUM_DISPLAYS = 1;
59
60static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
61static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
62static pthread_key_t gEGLErrorKey = -1;
63#ifndef HAVE_ANDROID_OS
64namespace gl {
65pthread_key_t gGLKey = -1;
66}; // namespace gl
67#endif
68
69template<typename T>
70static T setError(GLint error, T returnValue) {
71 if (ggl_unlikely(gEGLErrorKey == -1)) {
72 pthread_mutex_lock(&gErrorKeyMutex);
73 if (gEGLErrorKey == -1)
74 pthread_key_create(&gEGLErrorKey, NULL);
75 pthread_mutex_unlock(&gErrorKeyMutex);
76 }
77 pthread_setspecific(gEGLErrorKey, (void*)error);
78 return returnValue;
79}
80
81static GLint getError() {
82 if (ggl_unlikely(gEGLErrorKey == -1))
83 return EGL_SUCCESS;
84 GLint error = (GLint)pthread_getspecific(gEGLErrorKey);
85 pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS);
86 return error;
87}
88
89// ----------------------------------------------------------------------------
90
91struct egl_display_t
92{
93 egl_display_t() : type(0), initialized(0) { }
Mathias Agopian1473f462009-04-10 14:24:30 -070094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 static egl_display_t& get_display(EGLDisplay dpy);
Mathias Agopian1473f462009-04-10 14:24:30 -070096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 static EGLBoolean is_valid(EGLDisplay dpy) {
98 return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
99 }
100
101 NativeDisplayType type;
102 volatile int32_t initialized;
103};
104
105static egl_display_t gDisplays[NUM_DISPLAYS];
106
107egl_display_t& egl_display_t::get_display(EGLDisplay dpy) {
108 return gDisplays[uintptr_t(dpy)-1U];
109}
110
111struct egl_context_t {
112 enum {
113 IS_CURRENT = 0x00010000,
114 NEVER_CURRENT = 0x00020000
115 };
116 uint32_t flags;
117 EGLDisplay dpy;
118 EGLConfig config;
119 EGLSurface read;
120 EGLSurface draw;
121
122 static inline egl_context_t* context(EGLContext ctx) {
123 ogles_context_t* const gl = static_cast<ogles_context_t*>(ctx);
124 return static_cast<egl_context_t*>(gl->rasterizer.base);
125 }
126};
127
128// ----------------------------------------------------------------------------
129
130struct egl_surface_t
131{
132 enum {
133 PAGE_FLIP = 0x00000001,
134 MAGIC = 0x31415265
135 };
136
137 uint32_t magic;
138 EGLDisplay dpy;
139 EGLConfig config;
140 EGLContext ctx;
141
142 egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
143 virtual ~egl_surface_t();
144 virtual bool isValid() const = 0;
Mathias Agopian1473f462009-04-10 14:24:30 -0700145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl) = 0;
147 virtual EGLBoolean bindReadSurface(ogles_context_t* gl) = 0;
Mathias Agopianabac0102009-07-31 14:47:00 -0700148 virtual EGLBoolean connect() { return EGL_TRUE; }
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700149 virtual void disconnect() {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 virtual EGLint getWidth() const = 0;
151 virtual EGLint getHeight() const = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152
153 virtual EGLint getHorizontalResolution() const;
154 virtual EGLint getVerticalResolution() const;
155 virtual EGLint getRefreshRate() const;
156 virtual EGLint getSwapBehavior() const;
157 virtual EGLBoolean swapBuffers();
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700158 virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700159 virtual EGLClientBuffer getRenderBuffer() const;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160protected:
161 GGLSurface depth;
162};
163
164egl_surface_t::egl_surface_t(EGLDisplay dpy,
165 EGLConfig config,
166 int32_t depthFormat)
167 : magic(MAGIC), dpy(dpy), config(config), ctx(0)
168{
169 depth.version = sizeof(GGLSurface);
170 depth.data = 0;
171 depth.format = depthFormat;
172}
173egl_surface_t::~egl_surface_t()
174{
175 magic = 0;
176 free(depth.data);
177}
178EGLBoolean egl_surface_t::swapBuffers() {
179 return EGL_FALSE;
180}
181EGLint egl_surface_t::getHorizontalResolution() const {
182 return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
183}
184EGLint egl_surface_t::getVerticalResolution() const {
185 return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
186}
187EGLint egl_surface_t::getRefreshRate() const {
188 return (60 * EGL_DISPLAY_SCALING);
189}
190EGLint egl_surface_t::getSwapBehavior() const {
191 return EGL_BUFFER_PRESERVED;
192}
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700193EGLBoolean egl_surface_t::setSwapRectangle(
194 EGLint l, EGLint t, EGLint w, EGLint h)
195{
196 return EGL_FALSE;
197}
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700198EGLClientBuffer egl_surface_t::getRenderBuffer() const {
199 return 0;
200}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201
202// ----------------------------------------------------------------------------
203
Mathias Agopian1473f462009-04-10 14:24:30 -0700204struct egl_window_surface_v2_t : public egl_surface_t
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205{
Mathias Agopian1473f462009-04-10 14:24:30 -0700206 egl_window_surface_v2_t(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 EGLDisplay dpy, EGLConfig config,
208 int32_t depthFormat,
Mathias Agopian1473f462009-04-10 14:24:30 -0700209 android_native_window_t* window);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210
Mathias Agopian1473f462009-04-10 14:24:30 -0700211 ~egl_window_surface_v2_t();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212
Mathias Agopian1473f462009-04-10 14:24:30 -0700213 virtual bool isValid() const { return nativeWindow->common.magic == ANDROID_NATIVE_WINDOW_MAGIC; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 virtual EGLBoolean swapBuffers();
215 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
216 virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
Mathias Agopianabac0102009-07-31 14:47:00 -0700217 virtual EGLBoolean connect();
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700218 virtual void disconnect();
Mathias Agopian5b5c9142009-07-30 18:14:56 -0700219 virtual EGLint getWidth() const { return width; }
220 virtual EGLint getHeight() const { return height; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 virtual EGLint getHorizontalResolution() const;
222 virtual EGLint getVerticalResolution() const;
223 virtual EGLint getRefreshRate() const;
224 virtual EGLint getSwapBehavior() const;
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700225 virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700226 virtual EGLClientBuffer getRenderBuffer() const;
227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228private:
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700229 status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
Mathias Agopiandff8e582009-05-04 14:17:04 -0700230 status_t unlock(android_native_buffer_t* buf);
Mathias Agopian1473f462009-04-10 14:24:30 -0700231 android_native_window_t* nativeWindow;
232 android_native_buffer_t* buffer;
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700233 android_native_buffer_t* previousBuffer;
Mathias Agopiandff8e582009-05-04 14:17:04 -0700234 gralloc_module_t const* module;
Mathias Agopian68eeb802009-06-25 15:39:25 -0700235 copybit_device_t* blitengine;
Mathias Agopian1473f462009-04-10 14:24:30 -0700236 int width;
237 int height;
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700238 void* bits;
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700239 GGLFormat const* pixelFormatTable;
240
241 struct Rect {
242 inline Rect() { };
243 inline Rect(int32_t w, int32_t h)
244 : left(0), top(0), right(w), bottom(h) { }
245 inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
246 : left(l), top(t), right(r), bottom(b) { }
247 Rect& andSelf(const Rect& r) {
248 left = max(left, r.left);
249 top = max(top, r.top);
250 right = min(right, r.right);
251 bottom = min(bottom, r.bottom);
252 return *this;
253 }
254 bool isEmpty() const {
255 return (left>=right || top>=bottom);
256 }
257 void dump(char const* what) {
258 LOGD("%s { %5d, %5d, w=%5d, h=%5d }",
259 what, left, top, right-left, bottom-top);
260 }
261
262 int32_t left;
263 int32_t top;
264 int32_t right;
265 int32_t bottom;
266 };
267
268 struct Region {
269 inline Region() : count(0) { }
Mathias Agopian68eeb802009-06-25 15:39:25 -0700270 typedef Rect const* const_iterator;
271 const_iterator begin() const { return storage; }
272 const_iterator end() const { return storage+count; }
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700273 static Region subtract(const Rect& lhs, const Rect& rhs) {
274 Region reg;
275 Rect* storage = reg.storage;
276 if (!lhs.isEmpty()) {
277 if (lhs.top < rhs.top) { // top rect
278 storage->left = lhs.left;
279 storage->top = lhs.top;
280 storage->right = lhs.right;
Mathias Agopian68eeb802009-06-25 15:39:25 -0700281 storage->bottom = rhs.top;
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700282 storage++;
283 }
Mathias Agopian68eeb802009-06-25 15:39:25 -0700284 const int32_t top = max(lhs.top, rhs.top);
285 const int32_t bot = min(lhs.bottom, rhs.bottom);
286 if (top < bot) {
287 if (lhs.left < rhs.left) { // left-side rect
288 storage->left = lhs.left;
289 storage->top = top;
290 storage->right = rhs.left;
291 storage->bottom = bot;
292 storage++;
293 }
294 if (lhs.right > rhs.right) { // right-side rect
295 storage->left = rhs.right;
296 storage->top = top;
297 storage->right = lhs.right;
298 storage->bottom = bot;
299 storage++;
300 }
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700301 }
302 if (lhs.bottom > rhs.bottom) { // bottom rect
303 storage->left = lhs.left;
Mathias Agopian68eeb802009-06-25 15:39:25 -0700304 storage->top = rhs.bottom;
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700305 storage->right = lhs.right;
306 storage->bottom = lhs.bottom;
307 storage++;
308 }
309 reg.count = storage - reg.storage;
310 }
311 return reg;
312 }
313 bool isEmpty() const {
314 return count<=0;
315 }
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700316 private:
317 Rect storage[4];
318 ssize_t count;
319 };
320
Mathias Agopian68eeb802009-06-25 15:39:25 -0700321 struct region_iterator : public copybit_region_t {
322 region_iterator(const Region& region)
323 : b(region.begin()), e(region.end()) {
324 this->next = iterate;
325 }
326 private:
327 static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
328 region_iterator const* me = static_cast<region_iterator const*>(self);
329 if (me->b != me->e) {
330 *reinterpret_cast<Rect*>(rect) = *me->b++;
331 return 1;
332 }
333 return 0;
334 }
335 mutable Region::const_iterator b;
336 Region::const_iterator const e;
337 };
338
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700339 void copyBlt(
340 android_native_buffer_t* dst, void* dst_vaddr,
341 android_native_buffer_t* src, void const* src_vaddr,
Mathias Agopian68eeb802009-06-25 15:39:25 -0700342 const Region& clip);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700343
344 Rect dirtyRegion;
345 Rect oldDirtyRegion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346};
347
Mathias Agopian1473f462009-04-10 14:24:30 -0700348egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 EGLConfig config,
350 int32_t depthFormat,
Mathias Agopian1473f462009-04-10 14:24:30 -0700351 android_native_window_t* window)
Mathias Agopiandff8e582009-05-04 14:17:04 -0700352 : egl_surface_t(dpy, config, depthFormat),
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700353 nativeWindow(window), buffer(0), previousBuffer(0), module(0),
Mathias Agopian68eeb802009-06-25 15:39:25 -0700354 blitengine(0), bits(NULL)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355{
Mathias Agopiandff8e582009-05-04 14:17:04 -0700356 hw_module_t const* pModule;
357 hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
358 module = reinterpret_cast<gralloc_module_t const*>(pModule);
359
Mathias Agopian68eeb802009-06-25 15:39:25 -0700360 if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &pModule) == 0) {
361 copybit_open(pModule, &blitengine);
362 }
363
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700364 pixelFormatTable = gglGetPixelFormatTable();
365
366 // keep a reference on the window
Mathias Agopian1473f462009-04-10 14:24:30 -0700367 nativeWindow->common.incRef(&nativeWindow->common);
Mathias Agopian5b5c9142009-07-30 18:14:56 -0700368 nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
369 nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700370}
Mathias Agopian1473f462009-04-10 14:24:30 -0700371
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700372egl_window_surface_v2_t::~egl_window_surface_v2_t() {
373 if (buffer) {
374 buffer->common.decRef(&buffer->common);
375 }
376 if (previousBuffer) {
377 previousBuffer->common.decRef(&previousBuffer->common);
378 }
379 nativeWindow->common.decRef(&nativeWindow->common);
Mathias Agopian68eeb802009-06-25 15:39:25 -0700380 if (blitengine) {
381 copybit_close(blitengine);
382 }
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700383}
384
Mathias Agopianabac0102009-07-31 14:47:00 -0700385EGLBoolean egl_window_surface_v2_t::connect()
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700386{
Mathias Agopian5b5c9142009-07-30 18:14:56 -0700387 // dequeue a buffer
Mathias Agopianabac0102009-07-31 14:47:00 -0700388 if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
389 return setError(EGL_BAD_ALLOC, EGL_FALSE);
390 }
Mathias Agopian5b5c9142009-07-30 18:14:56 -0700391
392 // allocate a corresponding depth-buffer
393 width = buffer->width;
394 height = buffer->height;
395 if (depth.format) {
396 depth.width = width;
397 depth.height = height;
398 depth.stride = depth.width; // use the width here
399 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
400 if (depth.data == 0) {
Mathias Agopianabac0102009-07-31 14:47:00 -0700401 return setError(EGL_BAD_ALLOC, EGL_FALSE);
Mathias Agopian5b5c9142009-07-30 18:14:56 -0700402 }
403 }
404
405 // keep a reference on the buffer
406 buffer->common.incRef(&buffer->common);
407
Mathias Agopiandff8e582009-05-04 14:17:04 -0700408 // Lock the buffer
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700409 nativeWindow->lockBuffer(nativeWindow, buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700410 // pin the buffer down
411 if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
412 GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
Mathias Agopian68eeb802009-06-25 15:39:25 -0700413 LOGE("connect() failed to lock buffer %p (%ux%u)",
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700414 buffer, buffer->width, buffer->height);
Mathias Agopianabac0102009-07-31 14:47:00 -0700415 return setError(EGL_BAD_ACCESS, EGL_FALSE);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700416 // FIXME: we should make sure we're not accessing the buffer anymore
417 }
Mathias Agopianabac0102009-07-31 14:47:00 -0700418 return EGL_TRUE;
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700419}
420
421void egl_window_surface_v2_t::disconnect()
422{
Mathias Agopian36432cc2009-06-03 19:00:53 -0700423 if (buffer && bits) {
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700424 bits = NULL;
425 unlock(buffer);
426 }
Mathias Agopian5b5c9142009-07-30 18:14:56 -0700427 // enqueue the last frame
428 nativeWindow->queueBuffer(nativeWindow, buffer);
429 if (buffer) {
430 buffer->common.decRef(&buffer->common);
431 buffer = 0;
432 }
433 if (previousBuffer) {
434 previousBuffer->common.decRef(&previousBuffer->common);
435 previousBuffer = 0;
436 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437}
438
Mathias Agopiandff8e582009-05-04 14:17:04 -0700439status_t egl_window_surface_v2_t::lock(
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700440 android_native_buffer_t* buf, int usage, void** vaddr)
Mathias Agopiandff8e582009-05-04 14:17:04 -0700441{
Mathias Agopiane633f932009-05-05 00:59:23 -0700442 int err = module->lock(module, buf->handle,
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700443 usage, 0, 0, buf->width, buf->height, vaddr);
Mathias Agopiandff8e582009-05-04 14:17:04 -0700444 return err;
445}
446
447status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
448{
Mathias Agopianabac0102009-07-31 14:47:00 -0700449 if (!buf) return BAD_VALUE;
Mathias Agopiane633f932009-05-05 00:59:23 -0700450 int err = module->unlock(module, buf->handle);
Mathias Agopiandff8e582009-05-04 14:17:04 -0700451 return err;
452}
453
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700454void egl_window_surface_v2_t::copyBlt(
455 android_native_buffer_t* dst, void* dst_vaddr,
456 android_native_buffer_t* src, void const* src_vaddr,
Mathias Agopian68eeb802009-06-25 15:39:25 -0700457 const Region& clip)
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700458{
459 // FIXME: use copybit if possible
460 // NOTE: dst and src must be the same format
461
Mathias Agopian68eeb802009-06-25 15:39:25 -0700462 status_t err = NO_ERROR;
463 copybit_device_t* const copybit = blitengine;
464 if (copybit) {
465 copybit_image_t simg;
466 simg.w = src->width;
467 simg.h = src->height;
468 simg.format = src->format;
469 simg.handle = const_cast<native_handle_t*>(src->handle);
Mathias Agopiandff8e582009-05-04 14:17:04 -0700470
Mathias Agopian68eeb802009-06-25 15:39:25 -0700471 copybit_image_t dimg;
472 dimg.w = dst->width;
473 dimg.h = dst->height;
474 dimg.format = dst->format;
475 dimg.handle = const_cast<native_handle_t*>(dst->handle);
476
477 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
478 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
479 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
480 region_iterator it(clip);
481 err = copybit->blit(copybit, &dimg, &simg, &it);
482 if (err != NO_ERROR) {
483 LOGE("copybit failed (%s)", strerror(err));
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700484 }
Mathias Agopian68eeb802009-06-25 15:39:25 -0700485 }
486
487 if (!copybit || err) {
488 Region::const_iterator cur = clip.begin();
489 Region::const_iterator end = clip.end();
490
491 const size_t bpp = pixelFormatTable[src->format].size;
492 const size_t dbpr = dst->stride * bpp;
493 const size_t sbpr = src->stride * bpp;
494
495 uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
496 uint8_t * const dst_bits = (uint8_t *)dst_vaddr;
497
498 while (cur != end) {
499 const Rect& r(*cur++);
500 ssize_t w = r.right - r.left;
501 ssize_t h = r.bottom - r.top;
502 if (w <= 0 || h<=0) continue;
503 size_t size = w * bpp;
504 uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
505 uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
506 if (dbpr==sbpr && size==sbpr) {
507 size *= h;
508 h = 1;
509 }
510 do {
511 memcpy(d, s, size);
512 d += dbpr;
513 s += sbpr;
514 } while (--h > 0);
515 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700516 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700517}
518
519EGLBoolean egl_window_surface_v2_t::swapBuffers()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520{
Mathias Agopianabac0102009-07-31 14:47:00 -0700521 if (!buffer) {
522 return setError(EGL_BAD_ACCESS, EGL_FALSE);
523 }
524
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700525 /*
526 * Handle eglSetSwapRectangleANDROID()
527 * We copyback from the front buffer
528 */
529 if (!dirtyRegion.isEmpty()) {
530 dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
531 if (previousBuffer) {
532 const Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
533 if (!copyBack.isEmpty()) {
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700534 void* prevBits;
535 if (lock(previousBuffer,
Mathias Agopian68eeb802009-06-25 15:39:25 -0700536 GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
537 // copy from previousBuffer to buffer
538 copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700539 unlock(previousBuffer);
540 }
541 }
542 }
543 oldDirtyRegion = dirtyRegion;
544 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700545
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700546 if (previousBuffer) {
547 previousBuffer->common.decRef(&previousBuffer->common);
548 previousBuffer = 0;
549 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700550
Mathias Agopiandff8e582009-05-04 14:17:04 -0700551 unlock(buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700552 previousBuffer = buffer;
Mathias Agopian1473f462009-04-10 14:24:30 -0700553 nativeWindow->queueBuffer(nativeWindow, buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700554 buffer = 0;
Mathias Agopian1473f462009-04-10 14:24:30 -0700555
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700556 // dequeue a new buffer
Mathias Agopian1473f462009-04-10 14:24:30 -0700557 nativeWindow->dequeueBuffer(nativeWindow, &buffer);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700558
Mathias Agopian1473f462009-04-10 14:24:30 -0700559 // TODO: lockBuffer should rather be executed when the very first
560 // direct rendering occurs.
561 nativeWindow->lockBuffer(nativeWindow, buffer);
Mathias Agopian1473f462009-04-10 14:24:30 -0700562
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700563 // reallocate the depth-buffer if needed
Mathias Agopian1473f462009-04-10 14:24:30 -0700564 if ((width != buffer->width) || (height != buffer->height)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 // TODO: we probably should reset the swap rect here
566 // if the window size has changed
Mathias Agopian1473f462009-04-10 14:24:30 -0700567 width = buffer->width;
568 height = buffer->height;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 if (depth.data) {
570 free(depth.data);
Mathias Agopian1473f462009-04-10 14:24:30 -0700571 depth.width = width;
572 depth.height = height;
573 depth.stride = buffer->stride;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
575 if (depth.data == 0) {
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700576 setError(EGL_BAD_ALLOC, EGL_FALSE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 return EGL_FALSE;
578 }
579 }
580 }
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700581
582 // keep a reference on the buffer
583 buffer->common.incRef(&buffer->common);
584
585 // finally pin the buffer down
586 if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
587 GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
588 LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
589 buffer, buffer->width, buffer->height);
Mathias Agopianabac0102009-07-31 14:47:00 -0700590 return setError(EGL_BAD_ACCESS, EGL_FALSE);
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700591 // FIXME: we should make sure we're not accessing the buffer anymore
592 }
593
594 return EGL_TRUE;
595}
596
597EGLBoolean egl_window_surface_v2_t::setSwapRectangle(
598 EGLint l, EGLint t, EGLint w, EGLint h)
599{
600 dirtyRegion = Rect(l, t, l+w, t+h);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 return EGL_TRUE;
602}
603
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700604EGLClientBuffer egl_window_surface_v2_t::getRenderBuffer() const
605{
606 return buffer;
607}
608
Mathias Agopian1473f462009-04-10 14:24:30 -0700609#ifdef LIBAGL_USE_GRALLOC_COPYBITS
610
611static bool supportedCopybitsDestinationFormat(int format) {
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700612 // Hardware supported
Mathias Agopian1473f462009-04-10 14:24:30 -0700613 switch (format) {
614 case HAL_PIXEL_FORMAT_RGB_565:
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700615 case HAL_PIXEL_FORMAT_RGBA_8888:
616 case HAL_PIXEL_FORMAT_RGBA_4444:
617 case HAL_PIXEL_FORMAT_RGBA_5551:
618 case HAL_PIXEL_FORMAT_BGRA_8888:
Mathias Agopian1473f462009-04-10 14:24:30 -0700619 return true;
Mathias Agopian1473f462009-04-10 14:24:30 -0700620 }
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700621 return false;
Mathias Agopian1473f462009-04-10 14:24:30 -0700622}
623#endif
624
625EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626{
627 GGLSurface buffer;
628 buffer.version = sizeof(GGLSurface);
Mathias Agopian1473f462009-04-10 14:24:30 -0700629 buffer.width = this->buffer->width;
630 buffer.height = this->buffer->height;
631 buffer.stride = this->buffer->stride;
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700632 buffer.data = (GGLubyte*)bits;
Mathias Agopian1473f462009-04-10 14:24:30 -0700633 buffer.format = this->buffer->format;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 gl->rasterizer.procs.colorBuffer(gl, &buffer);
635 if (depth.data != gl->rasterizer.state.buffers.depth.data)
636 gl->rasterizer.procs.depthBuffer(gl, &depth);
Mathias Agopian350d6512009-06-10 16:01:54 -0700637
Mathias Agopian1473f462009-04-10 14:24:30 -0700638#ifdef LIBAGL_USE_GRALLOC_COPYBITS
Mathias Agopian350d6512009-06-10 16:01:54 -0700639 gl->copybits.drawSurfaceBuffer = 0;
Mathias Agopiana2fb72e2009-07-15 18:53:32 -0700640 if (gl->copybits.blitEngine != NULL) {
641 if (supportedCopybitsDestinationFormat(buffer.format)) {
642 buffer_handle_t handle = this->buffer->handle;
643 if (handle != NULL) {
Mathias Agopian350d6512009-06-10 16:01:54 -0700644 gl->copybits.drawSurfaceBuffer = handle;
Mathias Agopian1473f462009-04-10 14:24:30 -0700645 }
646 }
647 }
648#endif // LIBAGL_USE_GRALLOC_COPYBITS
Mathias Agopian350d6512009-06-10 16:01:54 -0700649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 return EGL_TRUE;
651}
Mathias Agopian1473f462009-04-10 14:24:30 -0700652EGLBoolean egl_window_surface_v2_t::bindReadSurface(ogles_context_t* gl)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653{
654 GGLSurface buffer;
655 buffer.version = sizeof(GGLSurface);
Mathias Agopian1473f462009-04-10 14:24:30 -0700656 buffer.width = this->buffer->width;
657 buffer.height = this->buffer->height;
658 buffer.stride = this->buffer->stride;
Mathias Agopian430f2ed2009-05-05 00:37:46 -0700659 buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
Mathias Agopian1473f462009-04-10 14:24:30 -0700660 buffer.format = this->buffer->format;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 gl->rasterizer.procs.readBuffer(gl, &buffer);
662 return EGL_TRUE;
663}
Mathias Agopian1473f462009-04-10 14:24:30 -0700664EGLint egl_window_surface_v2_t::getHorizontalResolution() const {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
666}
Mathias Agopian1473f462009-04-10 14:24:30 -0700667EGLint egl_window_surface_v2_t::getVerticalResolution() const {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
669}
Mathias Agopian1473f462009-04-10 14:24:30 -0700670EGLint egl_window_surface_v2_t::getRefreshRate() const {
671 return (60 * EGL_DISPLAY_SCALING); // FIXME
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672}
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700673EGLint egl_window_surface_v2_t::getSwapBehavior() const
674{
675 /*
676 * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
677 * the content of the swapped buffer.
678 *
679 * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
680 *
681 * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
682 * only applies to the area specified by eglSetSwapRectangleANDROID(), that
683 * is, everything outside of this area is preserved.
684 *
685 * This implementation of EGL assumes the later case.
686 *
687 */
688
Mathias Agopian1473f462009-04-10 14:24:30 -0700689 return EGL_BUFFER_DESTROYED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690}
691
692// ----------------------------------------------------------------------------
693
694struct egl_pixmap_surface_t : public egl_surface_t
695{
696 egl_pixmap_surface_t(
697 EGLDisplay dpy, EGLConfig config,
698 int32_t depthFormat,
699 egl_native_pixmap_t const * pixmap);
700
701 virtual ~egl_pixmap_surface_t() { }
702
Mathias Agopian1473f462009-04-10 14:24:30 -0700703 virtual bool isValid() const { return nativePixmap.version == sizeof(egl_native_pixmap_t); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
705 virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
706 virtual EGLint getWidth() const { return nativePixmap.width; }
707 virtual EGLint getHeight() const { return nativePixmap.height; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708private:
709 egl_native_pixmap_t nativePixmap;
710};
711
712egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
713 EGLConfig config,
714 int32_t depthFormat,
715 egl_native_pixmap_t const * pixmap)
716 : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
717{
718 if (depthFormat) {
719 depth.width = pixmap->width;
720 depth.height = pixmap->height;
721 depth.stride = depth.width; // use the width here
722 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
723 if (depth.data == 0) {
724 setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
725 return;
726 }
727 }
728}
729EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl)
730{
731 GGLSurface buffer;
732 buffer.version = sizeof(GGLSurface);
733 buffer.width = nativePixmap.width;
734 buffer.height = nativePixmap.height;
735 buffer.stride = nativePixmap.stride;
736 buffer.data = nativePixmap.data;
737 buffer.format = nativePixmap.format;
Mathias Agopian1473f462009-04-10 14:24:30 -0700738
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 gl->rasterizer.procs.colorBuffer(gl, &buffer);
740 if (depth.data != gl->rasterizer.state.buffers.depth.data)
741 gl->rasterizer.procs.depthBuffer(gl, &depth);
742 return EGL_TRUE;
743}
744EGLBoolean egl_pixmap_surface_t::bindReadSurface(ogles_context_t* gl)
745{
746 GGLSurface buffer;
747 buffer.version = sizeof(GGLSurface);
748 buffer.width = nativePixmap.width;
749 buffer.height = nativePixmap.height;
750 buffer.stride = nativePixmap.stride;
751 buffer.data = nativePixmap.data;
752 buffer.format = nativePixmap.format;
753 gl->rasterizer.procs.readBuffer(gl, &buffer);
754 return EGL_TRUE;
755}
756
757// ----------------------------------------------------------------------------
758
759struct egl_pbuffer_surface_t : public egl_surface_t
760{
761 egl_pbuffer_surface_t(
762 EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
763 int32_t w, int32_t h, int32_t f);
764
765 virtual ~egl_pbuffer_surface_t();
766
Mathias Agopian1473f462009-04-10 14:24:30 -0700767 virtual bool isValid() const { return pbuffer.data != 0; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
769 virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
770 virtual EGLint getWidth() const { return pbuffer.width; }
771 virtual EGLint getHeight() const { return pbuffer.height; }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772private:
773 GGLSurface pbuffer;
774};
775
776egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
777 EGLConfig config, int32_t depthFormat,
778 int32_t w, int32_t h, int32_t f)
779 : egl_surface_t(dpy, config, depthFormat)
780{
781 size_t size = w*h;
782 switch (f) {
783 case GGL_PIXEL_FORMAT_A_8: size *= 1; break;
784 case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break;
785 case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break;
786 default:
787 LOGE("incompatible pixel format for pbuffer (format=%d)", f);
788 pbuffer.data = 0;
789 break;
790 }
791 pbuffer.version = sizeof(GGLSurface);
792 pbuffer.width = w;
793 pbuffer.height = h;
794 pbuffer.stride = w;
795 pbuffer.data = (GGLubyte*)malloc(size);
796 pbuffer.format = f;
Mathias Agopian1473f462009-04-10 14:24:30 -0700797
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 if (depthFormat) {
799 depth.width = pbuffer.width;
800 depth.height = pbuffer.height;
801 depth.stride = depth.width; // use the width here
802 depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
803 if (depth.data == 0) {
804 setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
805 return;
806 }
807 }
808}
809egl_pbuffer_surface_t::~egl_pbuffer_surface_t() {
810 free(pbuffer.data);
811}
812EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(ogles_context_t* gl)
813{
814 gl->rasterizer.procs.colorBuffer(gl, &pbuffer);
815 if (depth.data != gl->rasterizer.state.buffers.depth.data)
816 gl->rasterizer.procs.depthBuffer(gl, &depth);
817 return EGL_TRUE;
818}
819EGLBoolean egl_pbuffer_surface_t::bindReadSurface(ogles_context_t* gl)
820{
821 gl->rasterizer.procs.readBuffer(gl, &pbuffer);
822 return EGL_TRUE;
823}
824
825// ----------------------------------------------------------------------------
826
827struct config_pair_t {
828 GLint key;
829 GLint value;
830};
831
832struct configs_t {
833 const config_pair_t* array;
834 int size;
835};
836
837struct config_management_t {
838 GLint key;
839 bool (*match)(GLint reqValue, GLint confValue);
840 static bool atLeast(GLint reqValue, GLint confValue) {
841 return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
842 }
843 static bool exact(GLint reqValue, GLint confValue) {
844 return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
845 }
846 static bool mask(GLint reqValue, GLint confValue) {
847 return (confValue & reqValue) == reqValue;
848 }
849};
850
851// ----------------------------------------------------------------------------
852
853#define VERSION_MAJOR 1
854#define VERSION_MINOR 2
855static char const * const gVendorString = "Google Inc.";
856static char const * const gVersionString = "1.2 Android Driver";
857static char const * const gClientApiString = "OpenGL ES";
Mathias Agopian1473f462009-04-10 14:24:30 -0700858static char const * const gExtensionsString =
Mathias Agopian927d37c2009-05-06 23:47:08 -0700859 "EGL_KHR_image_base "
Mathias Agopian1473f462009-04-10 14:24:30 -0700860 // "KHR_image_pixmap "
861 "EGL_ANDROID_image_native_buffer "
Mathias Agopian2e20bff2009-05-04 19:29:25 -0700862 "EGL_ANDROID_swap_rectangle "
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700863 "EGL_ANDROID_get_render_buffer "
Mathias Agopian1473f462009-04-10 14:24:30 -0700864 ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865
866// ----------------------------------------------------------------------------
867
868struct extention_map_t {
869 const char * const name;
870 __eglMustCastToProperFunctionPointerType address;
871};
872
873static const extention_map_t gExtentionMap[] = {
Mathias Agopian1473f462009-04-10 14:24:30 -0700874 { "glDrawTexsOES",
875 (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES },
876 { "glDrawTexiOES",
877 (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES },
878 { "glDrawTexfOES",
879 (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES },
880 { "glDrawTexxOES",
881 (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES },
882 { "glDrawTexsvOES",
883 (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES },
884 { "glDrawTexivOES",
885 (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES },
886 { "glDrawTexfvOES",
887 (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES },
888 { "glDrawTexxvOES",
889 (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
890 { "glQueryMatrixxOES",
891 (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
892 { "glEGLImageTargetTexture2DOES",
893 (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
894 { "glEGLImageTargetRenderbufferStorageOES",
895 (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
896 { "glClipPlanef",
897 (__eglMustCastToProperFunctionPointerType)&glClipPlanef },
898 { "glClipPlanex",
899 (__eglMustCastToProperFunctionPointerType)&glClipPlanex },
900 { "glBindBuffer",
901 (__eglMustCastToProperFunctionPointerType)&glBindBuffer },
902 { "glBufferData",
903 (__eglMustCastToProperFunctionPointerType)&glBufferData },
904 { "glBufferSubData",
905 (__eglMustCastToProperFunctionPointerType)&glBufferSubData },
906 { "glDeleteBuffers",
907 (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
908 { "glGenBuffers",
909 (__eglMustCastToProperFunctionPointerType)&glGenBuffers },
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700910 { "eglCreateImageKHR",
911 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
912 { "eglDestroyImageKHR",
913 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
914 { "eglSetSwapRectangleANDROID",
915 (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
916 { "eglGetRenderBufferANDROID",
917 (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918};
919
Mathias Agopian1473f462009-04-10 14:24:30 -0700920/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 * In the lists below, attributes names MUST be sorted.
922 * Additionally, all configs must be sorted according to
923 * the EGL specification.
924 */
925
926static config_pair_t const config_base_attribute_list[] = {
927 { EGL_STENCIL_SIZE, 0 },
928 { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG },
929 { EGL_LEVEL, 0 },
930 { EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS },
Mathias Agopian1473f462009-04-10 14:24:30 -0700931 { EGL_MAX_PBUFFER_PIXELS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS },
933 { EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS },
934 { EGL_NATIVE_RENDERABLE, EGL_TRUE },
935 { EGL_NATIVE_VISUAL_ID, 0 },
936 { EGL_NATIVE_VISUAL_TYPE, GGL_PIXEL_FORMAT_RGB_565 },
937 { EGL_SAMPLES, 0 },
938 { EGL_SAMPLE_BUFFERS, 0 },
939 { EGL_TRANSPARENT_TYPE, EGL_NONE },
940 { EGL_TRANSPARENT_BLUE_VALUE, 0 },
941 { EGL_TRANSPARENT_GREEN_VALUE, 0 },
942 { EGL_TRANSPARENT_RED_VALUE, 0 },
943 { EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE },
944 { EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE },
945 { EGL_MIN_SWAP_INTERVAL, 1 },
946 { EGL_MAX_SWAP_INTERVAL, 4 },
947};
948
949// These configs can override the base attribute list
950// NOTE: when adding a config here, don't forget to update eglCreate*Surface()
951
952static config_pair_t const config_0_attribute_list[] = {
953 { EGL_BUFFER_SIZE, 16 },
954 { EGL_ALPHA_SIZE, 0 },
955 { EGL_BLUE_SIZE, 5 },
956 { EGL_GREEN_SIZE, 6 },
957 { EGL_RED_SIZE, 5 },
958 { EGL_DEPTH_SIZE, 0 },
959 { EGL_CONFIG_ID, 0 },
960 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
961};
962
963static config_pair_t const config_1_attribute_list[] = {
964 { EGL_BUFFER_SIZE, 16 },
965 { EGL_ALPHA_SIZE, 0 },
966 { EGL_BLUE_SIZE, 5 },
967 { EGL_GREEN_SIZE, 6 },
968 { EGL_RED_SIZE, 5 },
969 { EGL_DEPTH_SIZE, 16 },
970 { EGL_CONFIG_ID, 1 },
971 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
972};
973
974static config_pair_t const config_2_attribute_list[] = {
975 { EGL_BUFFER_SIZE, 32 },
976 { EGL_ALPHA_SIZE, 8 },
977 { EGL_BLUE_SIZE, 8 },
978 { EGL_GREEN_SIZE, 8 },
979 { EGL_RED_SIZE, 8 },
980 { EGL_DEPTH_SIZE, 0 },
981 { EGL_CONFIG_ID, 2 },
982 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
983};
984
985static config_pair_t const config_3_attribute_list[] = {
986 { EGL_BUFFER_SIZE, 32 },
987 { EGL_ALPHA_SIZE, 8 },
988 { EGL_BLUE_SIZE, 8 },
989 { EGL_GREEN_SIZE, 8 },
990 { EGL_RED_SIZE, 8 },
991 { EGL_DEPTH_SIZE, 16 },
992 { EGL_CONFIG_ID, 3 },
993 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
994};
995
996static config_pair_t const config_4_attribute_list[] = {
997 { EGL_BUFFER_SIZE, 8 },
998 { EGL_ALPHA_SIZE, 8 },
999 { EGL_BLUE_SIZE, 0 },
1000 { EGL_GREEN_SIZE, 0 },
1001 { EGL_RED_SIZE, 0 },
1002 { EGL_DEPTH_SIZE, 0 },
1003 { EGL_CONFIG_ID, 4 },
1004 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
1005};
1006
1007static config_pair_t const config_5_attribute_list[] = {
1008 { EGL_BUFFER_SIZE, 8 },
1009 { EGL_ALPHA_SIZE, 8 },
1010 { EGL_BLUE_SIZE, 0 },
1011 { EGL_GREEN_SIZE, 0 },
1012 { EGL_RED_SIZE, 0 },
1013 { EGL_DEPTH_SIZE, 16 },
1014 { EGL_CONFIG_ID, 5 },
1015 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
1016};
1017
1018static configs_t const gConfigs[] = {
1019 { config_0_attribute_list, NELEM(config_0_attribute_list) },
1020 { config_1_attribute_list, NELEM(config_1_attribute_list) },
1021 { config_2_attribute_list, NELEM(config_2_attribute_list) },
1022 { config_3_attribute_list, NELEM(config_3_attribute_list) },
1023 { config_4_attribute_list, NELEM(config_4_attribute_list) },
1024 { config_5_attribute_list, NELEM(config_5_attribute_list) },
1025};
1026
1027static config_management_t const gConfigManagement[] = {
1028 { EGL_BUFFER_SIZE, config_management_t::atLeast },
1029 { EGL_ALPHA_SIZE, config_management_t::atLeast },
1030 { EGL_BLUE_SIZE, config_management_t::atLeast },
1031 { EGL_GREEN_SIZE, config_management_t::atLeast },
1032 { EGL_RED_SIZE, config_management_t::atLeast },
1033 { EGL_DEPTH_SIZE, config_management_t::atLeast },
1034 { EGL_STENCIL_SIZE, config_management_t::atLeast },
1035 { EGL_CONFIG_CAVEAT, config_management_t::exact },
1036 { EGL_CONFIG_ID, config_management_t::exact },
1037 { EGL_LEVEL, config_management_t::exact },
1038 { EGL_MAX_PBUFFER_HEIGHT, config_management_t::exact },
1039 { EGL_MAX_PBUFFER_PIXELS, config_management_t::exact },
1040 { EGL_MAX_PBUFFER_WIDTH, config_management_t::exact },
1041 { EGL_NATIVE_RENDERABLE, config_management_t::exact },
1042 { EGL_NATIVE_VISUAL_ID, config_management_t::exact },
1043 { EGL_NATIVE_VISUAL_TYPE, config_management_t::exact },
1044 { EGL_SAMPLES, config_management_t::exact },
1045 { EGL_SAMPLE_BUFFERS, config_management_t::exact },
1046 { EGL_SURFACE_TYPE, config_management_t::mask },
1047 { EGL_TRANSPARENT_TYPE, config_management_t::exact },
1048 { EGL_TRANSPARENT_BLUE_VALUE, config_management_t::exact },
1049 { EGL_TRANSPARENT_GREEN_VALUE, config_management_t::exact },
1050 { EGL_TRANSPARENT_RED_VALUE, config_management_t::exact },
1051 { EGL_BIND_TO_TEXTURE_RGBA, config_management_t::exact },
1052 { EGL_BIND_TO_TEXTURE_RGB, config_management_t::exact },
1053 { EGL_MIN_SWAP_INTERVAL, config_management_t::exact },
1054 { EGL_MAX_SWAP_INTERVAL, config_management_t::exact },
1055};
1056
1057static config_pair_t const config_defaults[] = {
1058 { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
1059};
1060
1061// ----------------------------------------------------------------------------
1062
1063template<typename T>
1064static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
1065{
1066 while (first <= last) {
1067 int mid = (first + last) / 2;
Mathias Agopian1473f462009-04-10 14:24:30 -07001068 if (key > sortedArray[mid].key) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 first = mid + 1;
Mathias Agopian1473f462009-04-10 14:24:30 -07001070 } else if (key < sortedArray[mid].key) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001071 last = mid - 1;
1072 } else {
1073 return mid;
1074 }
1075 }
1076 return -1;
1077}
1078
1079static int isAttributeMatching(int i, EGLint attr, EGLint val)
1080{
1081 // look for the attribute in all of our configs
Mathias Agopian1473f462009-04-10 14:24:30 -07001082 config_pair_t const* configFound = gConfigs[i].array;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 int index = binarySearch<config_pair_t>(
1084 gConfigs[i].array,
1085 0, gConfigs[i].size-1,
1086 attr);
1087 if (index < 0) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001088 configFound = config_base_attribute_list;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 index = binarySearch<config_pair_t>(
1090 config_base_attribute_list,
1091 0, NELEM(config_base_attribute_list)-1,
1092 attr);
1093 }
1094 if (index >= 0) {
1095 // attribute found, check if this config could match
1096 int cfgMgtIndex = binarySearch<config_management_t>(
1097 gConfigManagement,
1098 0, NELEM(gConfigManagement)-1,
1099 attr);
1100 if (index >= 0) {
1101 bool match = gConfigManagement[cfgMgtIndex].match(
1102 val, configFound[index].value);
1103 if (match) {
1104 // this config matches
1105 return 1;
1106 }
1107 } else {
1108 // attribute not found. this should NEVER happen.
1109 }
1110 } else {
1111 // error, this attribute doesn't exist
1112 }
1113 return 0;
1114}
1115
1116static int makeCurrent(ogles_context_t* gl)
1117{
1118 ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();
1119 if (gl) {
1120 egl_context_t* c = egl_context_t::context(gl);
1121 if (c->flags & egl_context_t::IS_CURRENT) {
1122 if (current != gl) {
1123 // it is an error to set a context current, if it's already
1124 // current to another thread
1125 return -1;
1126 }
1127 } else {
1128 if (current) {
1129 // mark the current context as not current, and flush
1130 glFlush();
1131 egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
1132 }
1133 }
1134 if (!(c->flags & egl_context_t::IS_CURRENT)) {
1135 // The context is not current, make it current!
1136 setGlThreadSpecific(gl);
1137 c->flags |= egl_context_t::IS_CURRENT;
1138 }
1139 } else {
1140 if (current) {
1141 // mark the current context as not current, and flush
1142 glFlush();
1143 egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
1144 }
1145 // this thread has no context attached to it
1146 setGlThreadSpecific(0);
1147 }
1148 return 0;
1149}
1150
1151static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
1152 EGLint attribute, EGLint *value)
1153{
1154 size_t numConfigs = NELEM(gConfigs);
1155 int index = (int)config;
1156 if (uint32_t(index) >= numConfigs)
1157 return setError(EGL_BAD_CONFIG, EGL_FALSE);
1158
1159 int attrIndex;
1160 attrIndex = binarySearch<config_pair_t>(
1161 gConfigs[index].array,
1162 0, gConfigs[index].size-1,
1163 attribute);
1164 if (attrIndex>=0) {
1165 *value = gConfigs[index].array[attrIndex].value;
1166 return EGL_TRUE;
1167 }
1168
1169 attrIndex = binarySearch<config_pair_t>(
1170 config_base_attribute_list,
1171 0, NELEM(config_base_attribute_list)-1,
1172 attribute);
1173 if (attrIndex>=0) {
1174 *value = config_base_attribute_list[attrIndex].value;
1175 return EGL_TRUE;
1176 }
1177 return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1178}
1179
1180static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
1181 NativeWindowType window, const EGLint *attrib_list)
1182{
1183 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1184 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1185 if (window == 0)
1186 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1187
1188 EGLint surfaceType;
1189 if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
1190 return EGL_FALSE;
1191
1192 if (!(surfaceType & EGL_WINDOW_BIT))
1193 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1194
1195 EGLint configID;
1196 if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
1197 return EGL_FALSE;
1198
1199 int32_t depthFormat;
1200 int32_t pixelFormat;
1201 switch(configID) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001202 case 0:
1203 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 depthFormat = 0;
1205 break;
1206 case 1:
Mathias Agopian1473f462009-04-10 14:24:30 -07001207 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1209 break;
1210 case 2:
Mathias Agopian1473f462009-04-10 14:24:30 -07001211 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 depthFormat = 0;
1213 break;
1214 case 3:
Mathias Agopian1473f462009-04-10 14:24:30 -07001215 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1217 break;
1218 case 4:
Mathias Agopian1473f462009-04-10 14:24:30 -07001219 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 depthFormat = 0;
1221 break;
1222 case 5:
Mathias Agopian1473f462009-04-10 14:24:30 -07001223 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1225 break;
1226 default:
1227 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1228 }
1229
1230 // FIXME: we don't have access to the pixelFormat here just yet.
1231 // (it's possible that the surface is not fully initialized)
1232 // maybe this should be done after the page-flip
1233 //if (EGLint(info.format) != pixelFormat)
1234 // return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1235
Mathias Agopian1473f462009-04-10 14:24:30 -07001236 egl_surface_t* surface;
1237 surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
1238 static_cast<android_native_window_t*>(window));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239
1240 if (!surface->isValid()) {
1241 // there was a problem in the ctor, the error
1242 // flag has been set.
1243 delete surface;
1244 surface = 0;
1245 }
1246 return surface;
1247}
1248
1249static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
1250 NativePixmapType pixmap, const EGLint *attrib_list)
1251{
1252 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1253 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1254 if (pixmap == 0)
1255 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1256
1257 EGLint surfaceType;
1258 if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
1259 return EGL_FALSE;
1260
1261 if (!(surfaceType & EGL_PIXMAP_BIT))
1262 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1263
1264 EGLint configID;
1265 if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
1266 return EGL_FALSE;
1267
1268 int32_t depthFormat;
1269 int32_t pixelFormat;
1270 switch(configID) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001271 case 0:
1272 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 depthFormat = 0;
1274 break;
1275 case 1:
Mathias Agopian1473f462009-04-10 14:24:30 -07001276 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1278 break;
1279 case 2:
Mathias Agopian1473f462009-04-10 14:24:30 -07001280 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 depthFormat = 0;
1282 break;
1283 case 3:
Mathias Agopian1473f462009-04-10 14:24:30 -07001284 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1286 break;
1287 case 4:
Mathias Agopian1473f462009-04-10 14:24:30 -07001288 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 depthFormat = 0;
1290 break;
1291 case 5:
Mathias Agopian1473f462009-04-10 14:24:30 -07001292 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1294 break;
1295 default:
1296 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1297 }
1298
1299 if (pixmap->format != pixelFormat)
1300 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1301
1302 egl_surface_t* surface =
1303 new egl_pixmap_surface_t(dpy, config, depthFormat,
1304 static_cast<egl_native_pixmap_t*>(pixmap));
1305
1306 if (!surface->isValid()) {
1307 // there was a problem in the ctor, the error
1308 // flag has been set.
1309 delete surface;
1310 surface = 0;
1311 }
1312 return surface;
1313}
1314
1315static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
1316 const EGLint *attrib_list)
1317{
1318 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1319 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1320
1321 EGLint surfaceType;
1322 if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
1323 return EGL_FALSE;
Mathias Agopian1473f462009-04-10 14:24:30 -07001324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 if (!(surfaceType & EGL_PBUFFER_BIT))
1326 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 EGLint configID;
1329 if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
1330 return EGL_FALSE;
1331
1332 int32_t depthFormat;
1333 int32_t pixelFormat;
1334 switch(configID) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001335 case 0:
1336 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 depthFormat = 0;
1338 break;
1339 case 1:
Mathias Agopian1473f462009-04-10 14:24:30 -07001340 pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1342 break;
1343 case 2:
Mathias Agopian1473f462009-04-10 14:24:30 -07001344 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 depthFormat = 0;
1346 break;
1347 case 3:
Mathias Agopian1473f462009-04-10 14:24:30 -07001348 pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1350 break;
1351 case 4:
Mathias Agopian1473f462009-04-10 14:24:30 -07001352 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 depthFormat = 0;
1354 break;
1355 case 5:
Mathias Agopian1473f462009-04-10 14:24:30 -07001356 pixelFormat = GGL_PIXEL_FORMAT_A_8;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001357 depthFormat = GGL_PIXEL_FORMAT_Z_16;
1358 break;
1359 default:
1360 return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
1361 }
1362
1363 int32_t w = 0;
1364 int32_t h = 0;
1365 while (attrib_list[0]) {
1366 if (attrib_list[0] == EGL_WIDTH) w = attrib_list[1];
1367 if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
1368 attrib_list+=2;
1369 }
1370
1371 egl_surface_t* surface =
1372 new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
1373
1374 if (!surface->isValid()) {
1375 // there was a problem in the ctor, the error
1376 // flag has been set.
1377 delete surface;
1378 surface = 0;
1379 }
1380 return surface;
1381}
1382
1383// ----------------------------------------------------------------------------
1384}; // namespace android
1385// ----------------------------------------------------------------------------
1386
1387using namespace android;
1388
1389// ----------------------------------------------------------------------------
1390// Initialization
1391// ----------------------------------------------------------------------------
1392
1393EGLDisplay eglGetDisplay(NativeDisplayType display)
1394{
1395#ifndef HAVE_ANDROID_OS
1396 // this just needs to be done once
1397 if (gGLKey == -1) {
1398 pthread_mutex_lock(&gInitMutex);
1399 if (gGLKey == -1)
1400 pthread_key_create(&gGLKey, NULL);
1401 pthread_mutex_unlock(&gInitMutex);
1402 }
1403#endif
1404 if (display == EGL_DEFAULT_DISPLAY) {
1405 EGLDisplay dpy = (EGLDisplay)1;
1406 egl_display_t& d = egl_display_t::get_display(dpy);
1407 d.type = display;
1408 return dpy;
Mathias Agopian1473f462009-04-10 14:24:30 -07001409 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001410 return EGL_NO_DISPLAY;
1411}
1412
1413EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
1414{
1415 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1416 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 EGLBoolean res = EGL_TRUE;
1419 egl_display_t& d = egl_display_t::get_display(dpy);
Mathias Agopian1473f462009-04-10 14:24:30 -07001420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 if (android_atomic_inc(&d.initialized) == 0) {
1422 // initialize stuff here if needed
1423 //pthread_mutex_lock(&gInitMutex);
1424 //pthread_mutex_unlock(&gInitMutex);
1425 }
1426
1427 if (res == EGL_TRUE) {
1428 if (major != NULL) *major = VERSION_MAJOR;
1429 if (minor != NULL) *minor = VERSION_MINOR;
1430 }
1431 return res;
1432}
1433
1434EGLBoolean eglTerminate(EGLDisplay dpy)
1435{
1436 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1437 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1438
1439 EGLBoolean res = EGL_TRUE;
1440 egl_display_t& d = egl_display_t::get_display(dpy);
1441 if (android_atomic_dec(&d.initialized) == 1) {
1442 // TODO: destroy all resources (surfaces, contexts, etc...)
1443 //pthread_mutex_lock(&gInitMutex);
1444 //pthread_mutex_unlock(&gInitMutex);
1445 }
1446 return res;
1447}
1448
1449// ----------------------------------------------------------------------------
1450// configuration
1451// ----------------------------------------------------------------------------
1452
1453EGLBoolean eglGetConfigs( EGLDisplay dpy,
1454 EGLConfig *configs,
1455 EGLint config_size, EGLint *num_config)
1456{
1457 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1458 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1459
1460 GLint numConfigs = NELEM(gConfigs);
1461 if (!configs) {
1462 *num_config = numConfigs;
1463 return EGL_TRUE;
1464 }
1465 GLint i;
1466 for (i=0 ; i<numConfigs && i<config_size ; i++) {
1467 *configs++ = (EGLConfig)i;
1468 }
1469 *num_config = i;
1470 return EGL_TRUE;
1471}
1472
1473EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
1474 EGLConfig *configs, EGLint config_size,
1475 EGLint *num_config)
1476{
1477 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1478 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Jack Palevich1badb712009-03-25 15:12:17 -07001479
1480 if (ggl_unlikely(num_config==0)) {
1481 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1482 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483
Jack Palevich1badb712009-03-25 15:12:17 -07001484 if (ggl_unlikely(attrib_list==0)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 *num_config = 0;
1486 return EGL_TRUE;
1487 }
Mathias Agopian1473f462009-04-10 14:24:30 -07001488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 int numAttributes = 0;
1490 int numConfigs = NELEM(gConfigs);
1491 uint32_t possibleMatch = (1<<numConfigs)-1;
1492 while(possibleMatch && *attrib_list != EGL_NONE) {
1493 numAttributes++;
1494 EGLint attr = *attrib_list++;
1495 EGLint val = *attrib_list++;
1496 for (int i=0 ; i<numConfigs ; i++) {
1497 if (!(possibleMatch & (1<<i)))
1498 continue;
1499 if (isAttributeMatching(i, attr, val) == 0) {
1500 possibleMatch &= ~(1<<i);
1501 }
1502 }
1503 }
1504
1505 // now, handle the attributes which have a useful default value
1506 for (size_t j=0 ; j<NELEM(config_defaults) ; j++) {
1507 // see if this attribute was specified, if not apply its
1508 // default value
1509 if (binarySearch<config_pair_t>(
1510 (config_pair_t const*)attrib_list,
Mathias Agopianab1cf3e2009-07-09 17:33:15 -07001511 0, numAttributes-1,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 config_defaults[j].key) < 0)
1513 {
1514 for (int i=0 ; i<numConfigs ; i++) {
1515 if (!(possibleMatch & (1<<i)))
1516 continue;
1517 if (isAttributeMatching(i,
1518 config_defaults[j].key,
1519 config_defaults[j].value) == 0)
1520 {
1521 possibleMatch &= ~(1<<i);
1522 }
1523 }
1524 }
1525 }
1526
1527 // return the configurations found
1528 int n=0;
1529 if (possibleMatch) {
Jack Palevich1badb712009-03-25 15:12:17 -07001530 if (configs) {
1531 for (int i=0 ; config_size && i<numConfigs ; i++) {
1532 if (possibleMatch & (1<<i)) {
1533 *configs++ = (EGLConfig)i;
1534 config_size--;
1535 n++;
1536 }
1537 }
1538 } else {
1539 for (int i=0 ; i<numConfigs ; i++) {
1540 if (possibleMatch & (1<<i)) {
1541 n++;
1542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 }
1544 }
1545 }
1546 *num_config = n;
1547 return EGL_TRUE;
1548}
1549
1550EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
1551 EGLint attribute, EGLint *value)
1552{
1553 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1554 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1555
1556 return getConfigAttrib(dpy, config, attribute, value);
1557}
1558
1559// ----------------------------------------------------------------------------
1560// surfaces
1561// ----------------------------------------------------------------------------
1562
1563EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
1564 NativeWindowType window,
1565 const EGLint *attrib_list)
1566{
1567 return createWindowSurface(dpy, config, window, attrib_list);
1568}
Mathias Agopian1473f462009-04-10 14:24:30 -07001569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
1571 NativePixmapType pixmap,
1572 const EGLint *attrib_list)
1573{
1574 return createPixmapSurface(dpy, config, pixmap, attrib_list);
1575}
1576
1577EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
1578 const EGLint *attrib_list)
1579{
1580 return createPbufferSurface(dpy, config, attrib_list);
1581}
Mathias Agopian1473f462009-04-10 14:24:30 -07001582
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
1584{
1585 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1586 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1587 if (eglSurface != EGL_NO_SURFACE) {
1588 egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
1589 if (surface->magic != egl_surface_t::MAGIC)
1590 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1591 if (surface->dpy != dpy)
1592 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001593 if (surface->ctx) {
1594 // FIXME: this surface is current check what the spec says
1595 surface->disconnect();
1596 surface->ctx = 0;
1597 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598 delete surface;
1599 }
1600 return EGL_TRUE;
1601}
1602
1603EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
1604 EGLint attribute, EGLint *value)
1605{
1606 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1607 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1608 egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
1609 if (surface->dpy != dpy)
1610 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1611
1612 EGLBoolean ret = EGL_TRUE;
1613 switch (attribute) {
1614 case EGL_CONFIG_ID:
1615 ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
1616 break;
1617 case EGL_WIDTH:
1618 *value = surface->getWidth();
1619 break;
1620 case EGL_HEIGHT:
1621 *value = surface->getHeight();
1622 break;
1623 case EGL_LARGEST_PBUFFER:
1624 // not modified for a window or pixmap surface
1625 break;
1626 case EGL_TEXTURE_FORMAT:
1627 *value = EGL_NO_TEXTURE;
1628 break;
1629 case EGL_TEXTURE_TARGET:
1630 *value = EGL_NO_TEXTURE;
1631 break;
1632 case EGL_MIPMAP_TEXTURE:
1633 *value = EGL_FALSE;
1634 break;
1635 case EGL_MIPMAP_LEVEL:
1636 *value = 0;
1637 break;
1638 case EGL_RENDER_BUFFER:
1639 // TODO: return the real RENDER_BUFFER here
1640 *value = EGL_BACK_BUFFER;
1641 break;
1642 case EGL_HORIZONTAL_RESOLUTION:
1643 // pixel/mm * EGL_DISPLAY_SCALING
1644 *value = surface->getHorizontalResolution();
1645 break;
1646 case EGL_VERTICAL_RESOLUTION:
1647 // pixel/mm * EGL_DISPLAY_SCALING
1648 *value = surface->getVerticalResolution();
1649 break;
1650 case EGL_PIXEL_ASPECT_RATIO: {
1651 // w/h * EGL_DISPLAY_SCALING
1652 int wr = surface->getHorizontalResolution();
1653 int hr = surface->getVerticalResolution();
1654 *value = (wr * EGL_DISPLAY_SCALING) / hr;
1655 } break;
1656 case EGL_SWAP_BEHAVIOR:
Mathias Agopian1473f462009-04-10 14:24:30 -07001657 *value = surface->getSwapBehavior();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 break;
1659 default:
1660 ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1661 }
1662 return ret;
1663}
1664
1665EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1666 EGLContext share_list, const EGLint *attrib_list)
1667{
1668 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1669 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1670
1671 ogles_context_t* gl = ogles_init(sizeof(egl_context_t));
1672 if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
1673
1674 egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
1675 c->flags = egl_context_t::NEVER_CURRENT;
1676 c->dpy = dpy;
1677 c->config = config;
1678 c->read = 0;
1679 c->draw = 0;
1680 return (EGLContext)gl;
1681}
1682
1683EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1684{
1685 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1686 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1687 egl_context_t* c = egl_context_t::context(ctx);
1688 if (c->flags & egl_context_t::IS_CURRENT)
1689 setGlThreadSpecific(0);
1690 ogles_uninit((ogles_context_t*)ctx);
1691 return EGL_TRUE;
1692}
1693
1694EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
1695 EGLSurface read, EGLContext ctx)
1696{
1697 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1698 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1699 if (draw) {
1700 egl_surface_t* s = (egl_surface_t*)draw;
1701 if (s->dpy != dpy)
1702 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1703 // TODO: check that draw and read are compatible with the context
1704 }
1705
1706 EGLContext current_ctx = EGL_NO_CONTEXT;
Mathias Agopian1473f462009-04-10 14:24:30 -07001707
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
1709 return setError(EGL_BAD_MATCH, EGL_FALSE);
1710
1711 if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
1712 return setError(EGL_BAD_MATCH, EGL_FALSE);
1713
1714 if (ctx == EGL_NO_CONTEXT) {
1715 // if we're detaching, we need the current context
1716 current_ctx = (EGLContext)getGlThreadSpecific();
1717 } else {
1718 egl_context_t* c = egl_context_t::context(ctx);
1719 egl_surface_t* d = (egl_surface_t*)draw;
1720 egl_surface_t* r = (egl_surface_t*)read;
1721 if ((d && d->ctx && d->ctx != ctx) ||
1722 (r && r->ctx && r->ctx != ctx)) {
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001723 // one of the surface is bound to a context in another thread
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 return setError(EGL_BAD_ACCESS, EGL_FALSE);
1725 }
1726 }
1727
1728 ogles_context_t* gl = (ogles_context_t*)ctx;
1729 if (makeCurrent(gl) == 0) {
1730 if (ctx) {
1731 egl_context_t* c = egl_context_t::context(ctx);
1732 egl_surface_t* d = (egl_surface_t*)draw;
1733 egl_surface_t* r = (egl_surface_t*)read;
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001734
1735 if (c->draw) {
1736 reinterpret_cast<egl_surface_t*>(c->draw)->disconnect();
1737 }
1738 if (c->read) {
1739 // FIXME: unlock/disconnect the read surface too
1740 }
1741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 c->draw = draw;
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001743 c->read = read;
1744
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 if (c->flags & egl_context_t::NEVER_CURRENT) {
1746 c->flags &= ~egl_context_t::NEVER_CURRENT;
1747 GLint w = 0;
1748 GLint h = 0;
1749 if (draw) {
1750 w = d->getWidth();
1751 h = d->getHeight();
1752 }
1753 ogles_surfaceport(gl, 0, 0);
1754 ogles_viewport(gl, 0, 0, w, h);
1755 ogles_scissor(gl, 0, 0, w, h);
1756 }
1757 if (d) {
Mathias Agopianabac0102009-07-31 14:47:00 -07001758 if (d->connect() == EGL_FALSE) {
1759 return EGL_FALSE;
1760 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 d->ctx = ctx;
1762 d->bindDrawSurface(gl);
1763 }
1764 if (r) {
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001765 // FIXME: lock/connect the read surface too
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766 r->ctx = ctx;
1767 r->bindReadSurface(gl);
1768 }
1769 } else {
1770 // if surfaces were bound to the context bound to this thread
1771 // mark then as unbound.
1772 if (current_ctx) {
1773 egl_context_t* c = egl_context_t::context(current_ctx);
1774 egl_surface_t* d = (egl_surface_t*)c->draw;
1775 egl_surface_t* r = (egl_surface_t*)c->read;
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001776 if (d) {
Mathias Agopian36432cc2009-06-03 19:00:53 -07001777 c->draw = 0;
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001778 d->ctx = EGL_NO_CONTEXT;
1779 d->disconnect();
1780 }
1781 if (r) {
Mathias Agopian36432cc2009-06-03 19:00:53 -07001782 c->read = 0;
Mathias Agopian430f2ed2009-05-05 00:37:46 -07001783 r->ctx = EGL_NO_CONTEXT;
1784 // FIXME: unlock/disconnect the read surface too
1785 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 }
1787 }
1788 return EGL_TRUE;
1789 }
1790 return setError(EGL_BAD_ACCESS, EGL_FALSE);
1791}
1792
1793EGLContext eglGetCurrentContext(void)
1794{
1795 // eglGetCurrentContext returns the current EGL rendering context,
1796 // as specified by eglMakeCurrent. If no context is current,
1797 // EGL_NO_CONTEXT is returned.
1798 return (EGLContext)getGlThreadSpecific();
1799}
1800
1801EGLSurface eglGetCurrentSurface(EGLint readdraw)
1802{
1803 // eglGetCurrentSurface returns the read or draw surface attached
1804 // to the current EGL rendering context, as specified by eglMakeCurrent.
1805 // If no context is current, EGL_NO_SURFACE is returned.
1806 EGLContext ctx = (EGLContext)getGlThreadSpecific();
1807 if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
1808 egl_context_t* c = egl_context_t::context(ctx);
1809 if (readdraw == EGL_READ) {
1810 return c->read;
1811 } else if (readdraw == EGL_DRAW) {
1812 return c->draw;
1813 }
1814 return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
1815}
1816
1817EGLDisplay eglGetCurrentDisplay(void)
1818{
1819 // eglGetCurrentDisplay returns the current EGL display connection
1820 // for the current EGL rendering context, as specified by eglMakeCurrent.
1821 // If no context is current, EGL_NO_DISPLAY is returned.
1822 EGLContext ctx = (EGLContext)getGlThreadSpecific();
1823 if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
1824 egl_context_t* c = egl_context_t::context(ctx);
1825 return c->dpy;
1826}
1827
1828EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1829 EGLint attribute, EGLint *value)
1830{
1831 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1832 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1833 egl_context_t* c = egl_context_t::context(ctx);
1834 switch (attribute) {
1835 case EGL_CONFIG_ID:
1836 // Returns the ID of the EGL frame buffer configuration with
1837 // respect to which the context was created
1838 return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
1839 }
1840 return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1841}
1842
1843EGLBoolean eglWaitGL(void)
1844{
1845 return EGL_TRUE;
1846}
1847
1848EGLBoolean eglWaitNative(EGLint engine)
1849{
1850 return EGL_TRUE;
1851}
1852
1853EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1854{
1855 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1856 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001857
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001858 egl_surface_t* d = static_cast<egl_surface_t*>(draw);
1859 if (d->dpy != dpy)
1860 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1861
1862 // post the surface
1863 d->swapBuffers();
1864
1865 // if it's bound to a context, update the buffer
1866 if (d->ctx != EGL_NO_CONTEXT) {
1867 d->bindDrawSurface((ogles_context_t*)d->ctx);
1868 // if this surface is also the read surface of the context
1869 // it is bound to, make sure to update the read buffer as well.
1870 // The EGL spec is a little unclear about this.
1871 egl_context_t* c = egl_context_t::context(d->ctx);
1872 if (c->read == draw) {
1873 d->bindReadSurface((ogles_context_t*)d->ctx);
1874 }
1875 }
1876
1877 return EGL_TRUE;
1878}
1879
1880EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1881 NativePixmapType target)
1882{
1883 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1884 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1885 // TODO: eglCopyBuffers()
1886 return EGL_FALSE;
1887}
1888
1889EGLint eglGetError(void)
1890{
1891 return getError();
1892}
1893
1894const char* eglQueryString(EGLDisplay dpy, EGLint name)
1895{
1896 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1897 return setError(EGL_BAD_DISPLAY, (const char*)0);
1898
1899 switch (name) {
1900 case EGL_VENDOR:
1901 return gVendorString;
1902 case EGL_VERSION:
1903 return gVersionString;
1904 case EGL_EXTENSIONS:
1905 return gExtensionsString;
1906 case EGL_CLIENT_APIS:
1907 return gClientApiString;
1908 }
1909 return setError(EGL_BAD_PARAMETER, (const char *)0);
1910}
1911
1912// ----------------------------------------------------------------------------
1913// EGL 1.1
1914// ----------------------------------------------------------------------------
1915
1916EGLBoolean eglSurfaceAttrib(
1917 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1918{
1919 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1920 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1921 // TODO: eglSurfaceAttrib()
1922 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1923}
1924
1925EGLBoolean eglBindTexImage(
1926 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1927{
1928 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1929 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1930 // TODO: eglBindTexImage()
1931 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1932}
1933
1934EGLBoolean eglReleaseTexImage(
1935 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1936{
1937 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1938 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1939 // TODO: eglReleaseTexImage()
1940 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1941}
1942
1943EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1944{
1945 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1946 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1947 // TODO: eglSwapInterval()
1948 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1949}
1950
1951// ----------------------------------------------------------------------------
1952// EGL 1.2
1953// ----------------------------------------------------------------------------
1954
1955EGLBoolean eglBindAPI(EGLenum api)
1956{
1957 if (api != EGL_OPENGL_ES_API)
1958 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1959 return EGL_TRUE;
1960}
1961
1962EGLenum eglQueryAPI(void)
1963{
1964 return EGL_OPENGL_ES_API;
1965}
1966
1967EGLBoolean eglWaitClient(void)
1968{
1969 glFinish();
1970 return EGL_TRUE;
1971}
1972
1973EGLBoolean eglReleaseThread(void)
1974{
1975 // TODO: eglReleaseThread()
1976 return EGL_TRUE;
1977}
1978
1979EGLSurface eglCreatePbufferFromClientBuffer(
1980 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1981 EGLConfig config, const EGLint *attrib_list)
1982{
1983 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
1984 return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
1985 // TODO: eglCreatePbufferFromClientBuffer()
1986 return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1987}
1988
1989// ----------------------------------------------------------------------------
Mathias Agopian1473f462009-04-10 14:24:30 -07001990// EGL_EGLEXT_VERSION 3
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001991// ----------------------------------------------------------------------------
1992
1993void (*eglGetProcAddress (const char *procname))()
1994{
1995 extention_map_t const * const map = gExtentionMap;
1996 for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
1997 if (!strcmp(procname, map[i].name)) {
1998 return map[i].address;
1999 }
2000 }
2001 return NULL;
2002}
Mathias Agopian1473f462009-04-10 14:24:30 -07002003
2004EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
2005 const EGLint *attrib_list)
2006{
2007 EGLBoolean result = EGL_FALSE;
2008 return result;
2009}
2010
2011EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
2012{
2013 EGLBoolean result = EGL_FALSE;
2014 return result;
2015}
2016
2017EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
2018 EGLClientBuffer buffer, const EGLint *attrib_list)
2019{
2020 if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
2021 return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
2022 }
2023 if (ctx != EGL_NO_CONTEXT) {
2024 return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
2025 }
2026 if (target != EGL_NATIVE_BUFFER_ANDROID) {
2027 return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
2028 }
2029
2030 android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
2031
2032 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
2033 return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
2034
2035 if (native_buffer->common.version != sizeof(android_native_buffer_t))
2036 return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
Mathias Agopianaf9a5152009-04-10 20:34:46 -07002037
Mathias Agopian1473f462009-04-10 14:24:30 -07002038 native_buffer->common.incRef(&native_buffer->common);
2039 return (EGLImageKHR)native_buffer;
2040}
2041
2042EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
2043{
2044 if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
2045 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
2046 }
2047
2048 android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
2049
2050 if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
2051 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
2052
2053 if (native_buffer->common.version != sizeof(android_native_buffer_t))
2054 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
2055
Mathias Agopian1473f462009-04-10 14:24:30 -07002056 native_buffer->common.decRef(&native_buffer->common);
2057
2058 return EGL_TRUE;
2059}
Mathias Agopian2e20bff2009-05-04 19:29:25 -07002060
2061// ----------------------------------------------------------------------------
2062// ANDROID extensions
2063// ----------------------------------------------------------------------------
2064
2065EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
2066 EGLint left, EGLint top, EGLint width, EGLint height)
2067{
2068 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
2069 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
2070
2071 egl_surface_t* d = static_cast<egl_surface_t*>(draw);
2072 if (d->dpy != dpy)
2073 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
2074
2075 // post the surface
2076 d->setSwapRectangle(left, top, width, height);
2077
2078 return EGL_TRUE;
2079}
Mathias Agopianc1e3ec52009-06-24 22:37:39 -07002080
2081EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
2082{
2083 if (egl_display_t::is_valid(dpy) == EGL_FALSE)
2084 return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
2085
2086 egl_surface_t* d = static_cast<egl_surface_t*>(draw);
2087 if (d->dpy != dpy)
2088 return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
2089
2090 // post the surface
2091 return d->getRenderBuffer();
2092}