1/**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright 2010 LunarG, Inc.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
18 * of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 *
28 **************************************************************************/
29
30
31/**
32 * Surface-related functions.
33 */
34
35
36#include <assert.h>
37#include <stdlib.h>
38#include <string.h>
39#include "egldisplay.h"
40#include "eglcontext.h"
41#include "eglconfig.h"
42#include "eglcurrent.h"
43#include "egllog.h"
44#include "eglsurface.h"
45
46
47static void
48_eglClampSwapInterval(_EGLSurface *surf, EGLint interval)
49{
50   EGLint bound = surf->Config->MaxSwapInterval;
51   if (interval >= bound) {
52      interval = bound;
53   }
54   else {
55      bound = surf->Config->MinSwapInterval;
56      if (interval < bound)
57         interval = bound;
58   }
59   surf->SwapInterval = interval;
60}
61
62
63#ifdef EGL_MESA_screen_surface
64static EGLint
65_eglParseScreenSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
66{
67   EGLint i, err = EGL_SUCCESS;
68
69   if (!attrib_list)
70      return EGL_SUCCESS;
71
72   for (i = 0; attrib_list[i] != EGL_NONE; i++) {
73      EGLint attr = attrib_list[i++];
74      EGLint val = attrib_list[i];
75
76      switch (attr) {
77      case EGL_WIDTH:
78         if (val < 0) {
79            err = EGL_BAD_PARAMETER;
80            break;
81         }
82         surf->Width = val;
83         break;
84      case EGL_HEIGHT:
85         if (val < 0) {
86            err = EGL_BAD_PARAMETER;
87            break;
88         }
89         surf->Height = val;
90         break;
91      default:
92         err = EGL_BAD_ATTRIBUTE;
93         break;
94      }
95
96      if (err != EGL_SUCCESS) {
97         _eglLog(_EGL_WARNING, "bad surface attribute 0x%04x", attr);
98         break;
99      }
100   }
101
102   return err;
103}
104#endif /* EGL_MESA_screen_surface */
105
106
107/**
108 * Parse the list of surface attributes and return the proper error code.
109 */
110static EGLint
111_eglParseSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
112{
113   _EGLDisplay *dpy = surf->Resource.Display;
114   EGLint type = surf->Type;
115   EGLint texture_type = EGL_PBUFFER_BIT;
116   EGLint i, err = EGL_SUCCESS;
117
118   if (!attrib_list)
119      return EGL_SUCCESS;
120
121#ifdef EGL_MESA_screen_surface
122   if (type == EGL_SCREEN_BIT_MESA)
123      return _eglParseScreenSurfaceAttribList(surf, attrib_list);
124#endif
125
126   if (dpy->Extensions.NOK_texture_from_pixmap)
127      texture_type |= EGL_PIXMAP_BIT;
128
129   for (i = 0; attrib_list[i] != EGL_NONE; i++) {
130      EGLint attr = attrib_list[i++];
131      EGLint val = attrib_list[i];
132
133      switch (attr) {
134      /* common attributes */
135      case EGL_VG_COLORSPACE:
136         switch (val) {
137         case EGL_VG_COLORSPACE_sRGB:
138         case EGL_VG_COLORSPACE_LINEAR:
139            break;
140         default:
141            err = EGL_BAD_ATTRIBUTE;
142            break;
143         }
144         if (err != EGL_SUCCESS)
145            break;
146         surf->VGColorspace = val;
147         break;
148      case EGL_VG_ALPHA_FORMAT:
149         switch (val) {
150         case EGL_VG_ALPHA_FORMAT_NONPRE:
151         case EGL_VG_ALPHA_FORMAT_PRE:
152            break;
153         default:
154            err = EGL_BAD_ATTRIBUTE;
155            break;
156         }
157         if (err != EGL_SUCCESS)
158            break;
159         surf->VGAlphaFormat = val;
160         break;
161      /* window surface attributes */
162      case EGL_RENDER_BUFFER:
163         if (type != EGL_WINDOW_BIT) {
164            err = EGL_BAD_ATTRIBUTE;
165            break;
166         }
167         if (val != EGL_BACK_BUFFER && val != EGL_SINGLE_BUFFER) {
168            err = EGL_BAD_ATTRIBUTE;
169            break;
170         }
171         surf->RenderBuffer = val;
172         break;
173      case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
174         if (!dpy->Extensions.NV_post_sub_buffer ||
175             type != EGL_WINDOW_BIT) {
176            err = EGL_BAD_ATTRIBUTE;
177            break;
178         }
179         if (val != EGL_TRUE && val != EGL_FALSE) {
180            err = EGL_BAD_PARAMETER;
181            break;
182         }
183         surf->PostSubBufferSupportedNV = val;
184         break;
185      /* pbuffer surface attributes */
186      case EGL_WIDTH:
187         if (type != EGL_PBUFFER_BIT) {
188            err = EGL_BAD_ATTRIBUTE;
189            break;
190         }
191         if (val < 0) {
192            err = EGL_BAD_PARAMETER;
193            break;
194         }
195         surf->Width = val;
196         break;
197      case EGL_HEIGHT:
198         if (type != EGL_PBUFFER_BIT) {
199            err = EGL_BAD_ATTRIBUTE;
200            break;
201         }
202         if (val < 0) {
203            err = EGL_BAD_PARAMETER;
204            break;
205         }
206         surf->Height = val;
207         break;
208      case EGL_LARGEST_PBUFFER:
209         if (type != EGL_PBUFFER_BIT) {
210            err = EGL_BAD_ATTRIBUTE;
211            break;
212         }
213         surf->LargestPbuffer = !!val;
214         break;
215      /* for eglBindTexImage */
216      case EGL_TEXTURE_FORMAT:
217         if (!(type & texture_type)) {
218            err = EGL_BAD_ATTRIBUTE;
219            break;
220         }
221         switch (val) {
222         case EGL_TEXTURE_RGB:
223         case EGL_TEXTURE_RGBA:
224         case EGL_NO_TEXTURE:
225            break;
226         default:
227            err = EGL_BAD_ATTRIBUTE;
228            break;
229         }
230         if (err != EGL_SUCCESS)
231            break;
232         surf->TextureFormat = val;
233         break;
234      case EGL_TEXTURE_TARGET:
235         if (!(type & texture_type)) {
236            err = EGL_BAD_ATTRIBUTE;
237            break;
238         }
239         switch (val) {
240         case EGL_TEXTURE_2D:
241         case EGL_NO_TEXTURE:
242            break;
243         default:
244            err = EGL_BAD_ATTRIBUTE;
245            break;
246         }
247         if (err != EGL_SUCCESS)
248            break;
249         surf->TextureTarget = val;
250         break;
251      case EGL_MIPMAP_TEXTURE:
252         if (!(type & texture_type)) {
253            err = EGL_BAD_ATTRIBUTE;
254            break;
255         }
256         surf->MipmapTexture = !!val;
257         break;
258      /* no pixmap surface specific attributes */
259      default:
260         err = EGL_BAD_ATTRIBUTE;
261         break;
262      }
263
264      if (err != EGL_SUCCESS) {
265         _eglLog(_EGL_WARNING, "bad surface attribute 0x%04x", attr);
266         break;
267      }
268   }
269
270   return err;
271}
272
273
274/**
275 * Do error check on parameters and initialize the given _EGLSurface object.
276 * \return EGL_TRUE if no errors, EGL_FALSE otherwise.
277 */
278EGLBoolean
279_eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
280                _EGLConfig *conf, const EGLint *attrib_list)
281{
282   const char *func;
283   EGLint renderBuffer = EGL_BACK_BUFFER;
284   EGLint swapBehavior = EGL_BUFFER_PRESERVED;
285   EGLint err;
286
287   switch (type) {
288   case EGL_WINDOW_BIT:
289      func = "eglCreateWindowSurface";
290      swapBehavior = EGL_BUFFER_DESTROYED;
291      break;
292   case EGL_PIXMAP_BIT:
293      func = "eglCreatePixmapSurface";
294      renderBuffer = EGL_SINGLE_BUFFER;
295      break;
296   case EGL_PBUFFER_BIT:
297      func = "eglCreatePBufferSurface";
298      break;
299#ifdef EGL_MESA_screen_surface
300   case EGL_SCREEN_BIT_MESA:
301      func = "eglCreateScreenSurface";
302      renderBuffer = EGL_SINGLE_BUFFER; /* XXX correct? */
303      break;
304#endif
305   default:
306      _eglLog(_EGL_WARNING, "Bad type in _eglInitSurface");
307      return EGL_FALSE;
308   }
309
310   if ((conf->SurfaceType & type) == 0) {
311      /* The config can't be used to create a surface of this type */
312      _eglError(EGL_BAD_CONFIG, func);
313      return EGL_FALSE;
314   }
315
316   _eglInitResource(&surf->Resource, sizeof(*surf), dpy);
317   surf->Type = type;
318   surf->Config = conf;
319
320   surf->Width = 0;
321   surf->Height = 0;
322   surf->TextureFormat = EGL_NO_TEXTURE;
323   surf->TextureTarget = EGL_NO_TEXTURE;
324   surf->MipmapTexture = EGL_FALSE;
325   surf->LargestPbuffer = EGL_FALSE;
326   surf->RenderBuffer = renderBuffer;
327   surf->VGAlphaFormat = EGL_VG_ALPHA_FORMAT_NONPRE;
328   surf->VGColorspace = EGL_VG_COLORSPACE_sRGB;
329
330   surf->MipmapLevel = 0;
331   surf->MultisampleResolve = EGL_MULTISAMPLE_RESOLVE_DEFAULT;
332   surf->SwapBehavior = swapBehavior;
333
334   surf->HorizontalResolution = EGL_UNKNOWN;
335   surf->VerticalResolution = EGL_UNKNOWN;
336   surf->AspectRatio = EGL_UNKNOWN;
337
338   surf->PostSubBufferSupportedNV = EGL_FALSE;
339
340   /* the default swap interval is 1 */
341   _eglClampSwapInterval(surf, 1);
342
343   err = _eglParseSurfaceAttribList(surf, attrib_list);
344   if (err != EGL_SUCCESS)
345      return _eglError(err, func);
346
347   return EGL_TRUE;
348}
349
350
351EGLBoolean
352_eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
353                 EGLint attribute, EGLint *value)
354{
355   switch (attribute) {
356   case EGL_WIDTH:
357      *value = surface->Width;
358      break;
359   case EGL_HEIGHT:
360      *value = surface->Height;
361      break;
362   case EGL_CONFIG_ID:
363      *value = surface->Config->ConfigID;
364      break;
365   case EGL_LARGEST_PBUFFER:
366      *value = surface->LargestPbuffer;
367      break;
368   case EGL_TEXTURE_FORMAT:
369      /* texture attributes: only for pbuffers, no error otherwise */
370      if (surface->Type == EGL_PBUFFER_BIT)
371         *value = surface->TextureFormat;
372      break;
373   case EGL_TEXTURE_TARGET:
374      if (surface->Type == EGL_PBUFFER_BIT)
375         *value = surface->TextureTarget;
376      break;
377   case EGL_MIPMAP_TEXTURE:
378      if (surface->Type == EGL_PBUFFER_BIT)
379         *value = surface->MipmapTexture;
380      break;
381   case EGL_MIPMAP_LEVEL:
382      if (surface->Type == EGL_PBUFFER_BIT)
383         *value = surface->MipmapLevel;
384      break;
385   case EGL_SWAP_BEHAVIOR:
386      *value = surface->SwapBehavior;
387      break;
388   case EGL_RENDER_BUFFER:
389      *value = surface->RenderBuffer;
390      break;
391   case EGL_PIXEL_ASPECT_RATIO:
392      *value = surface->AspectRatio;
393      break;
394   case EGL_HORIZONTAL_RESOLUTION:
395      *value = surface->HorizontalResolution;
396      break;
397   case EGL_VERTICAL_RESOLUTION:
398      *value = surface->VerticalResolution;
399      break;
400   case EGL_MULTISAMPLE_RESOLVE:
401      *value = surface->MultisampleResolve;
402      break;
403   case EGL_VG_ALPHA_FORMAT:
404      *value = surface->VGAlphaFormat;
405      break;
406   case EGL_VG_COLORSPACE:
407      *value = surface->VGColorspace;
408      break;
409   case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
410      *value = surface->PostSubBufferSupportedNV;
411      break;
412   default:
413      _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
414      return EGL_FALSE;
415   }
416
417   return EGL_TRUE;
418}
419
420
421/**
422 * Default fallback routine - drivers might override this.
423 */
424EGLBoolean
425_eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
426                  EGLint attribute, EGLint value)
427{
428   EGLint confval;
429   EGLint err = EGL_SUCCESS;
430
431   switch (attribute) {
432   case EGL_MIPMAP_LEVEL:
433      confval = surface->Config->RenderableType;
434      if (!(confval & (EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT))) {
435         err = EGL_BAD_PARAMETER;
436         break;
437      }
438      surface->MipmapLevel = value;
439      break;
440   case EGL_MULTISAMPLE_RESOLVE:
441      switch (value) {
442      case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
443         break;
444      case EGL_MULTISAMPLE_RESOLVE_BOX:
445         confval = surface->Config->SurfaceType;
446         if (!(confval & EGL_MULTISAMPLE_RESOLVE_BOX_BIT))
447            err = EGL_BAD_MATCH;
448         break;
449      default:
450         err = EGL_BAD_ATTRIBUTE;
451         break;
452      }
453      if (err != EGL_SUCCESS)
454         break;
455      surface->MultisampleResolve = value;
456      break;
457   case EGL_SWAP_BEHAVIOR:
458      switch (value) {
459      case EGL_BUFFER_DESTROYED:
460         break;
461      case EGL_BUFFER_PRESERVED:
462         confval = surface->Config->SurfaceType;
463         if (!(confval & EGL_SWAP_BEHAVIOR_PRESERVED_BIT))
464            err = EGL_BAD_MATCH;
465         break;
466      default:
467         err = EGL_BAD_ATTRIBUTE;
468         break;
469      }
470      if (err != EGL_SUCCESS)
471         break;
472      surface->SwapBehavior = value;
473      break;
474   default:
475      err = EGL_BAD_ATTRIBUTE;
476      break;
477   }
478
479   if (err != EGL_SUCCESS)
480      return _eglError(err, "eglSurfaceAttrib");
481   return EGL_TRUE;
482}
483
484
485EGLBoolean
486_eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
487                 EGLint buffer)
488{
489   EGLint texture_type = EGL_PBUFFER_BIT;
490
491   /* Just do basic error checking and return success/fail.
492    * Drivers must implement the real stuff.
493    */
494
495   if (dpy->Extensions.NOK_texture_from_pixmap)
496      texture_type |= EGL_PIXMAP_BIT;
497
498   if (!(surface->Type & texture_type)) {
499      _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
500      return EGL_FALSE;
501   }
502
503   if (surface->TextureFormat == EGL_NO_TEXTURE) {
504      _eglError(EGL_BAD_MATCH, "eglBindTexImage");
505      return EGL_FALSE;
506   }
507
508   if (surface->TextureTarget == EGL_NO_TEXTURE) {
509      _eglError(EGL_BAD_MATCH, "eglBindTexImage");
510      return EGL_FALSE;
511   }
512
513   if (buffer != EGL_BACK_BUFFER) {
514      _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
515      return EGL_FALSE;
516   }
517
518   surface->BoundToTexture = EGL_TRUE;
519
520   return EGL_TRUE;
521}
522
523
524EGLBoolean
525_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
526                 EGLint interval)
527{
528   _eglClampSwapInterval(surf, interval);
529   return EGL_TRUE;
530}
531