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 
47 static void
_eglClampSwapInterval(_EGLSurface * surf,EGLint interval)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
64 static EGLint
_eglParseScreenSurfaceAttribList(_EGLSurface * surf,const EGLint * attrib_list)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  */
110 static EGLint
_eglParseSurfaceAttribList(_EGLSurface * surf,const EGLint * attrib_list)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  */
278 EGLBoolean
_eglInitSurface(_EGLSurface * surf,_EGLDisplay * dpy,EGLint type,_EGLConfig * conf,const EGLint * attrib_list)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 
351 EGLBoolean
_eglQuerySurface(_EGLDriver * drv,_EGLDisplay * dpy,_EGLSurface * surface,EGLint attribute,EGLint * value)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  */
424 EGLBoolean
_eglSurfaceAttrib(_EGLDriver * drv,_EGLDisplay * dpy,_EGLSurface * surface,EGLint attribute,EGLint value)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 
485 EGLBoolean
_eglBindTexImage(_EGLDriver * drv,_EGLDisplay * dpy,_EGLSurface * surface,EGLint buffer)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 
524 EGLBoolean
_eglSwapInterval(_EGLDriver * drv,_EGLDisplay * dpy,_EGLSurface * surf,EGLint interval)525 _eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
526                  EGLint interval)
527 {
528    _eglClampSwapInterval(surf, interval);
529    return EGL_TRUE;
530 }
531