/************************************************************************** * * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com> * Copyright 2010 LunarG, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * **************************************************************************/ /** * Surface-related functions. */ #include <assert.h> #include <stdlib.h> #include <string.h> #include "egldisplay.h" #include "eglcontext.h" #include "eglconfig.h" #include "eglcurrent.h" #include "egllog.h" #include "eglsurface.h" static void _eglClampSwapInterval(_EGLSurface *surf, EGLint interval) { EGLint bound = surf->Config->MaxSwapInterval; if (interval >= bound) { interval = bound; } else { bound = surf->Config->MinSwapInterval; if (interval < bound) interval = bound; } surf->SwapInterval = interval; } #ifdef EGL_MESA_screen_surface static EGLint _eglParseScreenSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list) { EGLint i, err = EGL_SUCCESS; if (!attrib_list) return EGL_SUCCESS; for (i = 0; attrib_list[i] != EGL_NONE; i++) { EGLint attr = attrib_list[i++]; EGLint val = attrib_list[i]; switch (attr) { case EGL_WIDTH: if (val < 0) { err = EGL_BAD_PARAMETER; break; } surf->Width = val; break; case EGL_HEIGHT: if (val < 0) { err = EGL_BAD_PARAMETER; break; } surf->Height = val; break; default: err = EGL_BAD_ATTRIBUTE; break; } if (err != EGL_SUCCESS) { _eglLog(_EGL_WARNING, "bad surface attribute 0x%04x", attr); break; } } return err; } #endif /* EGL_MESA_screen_surface */ /** * Parse the list of surface attributes and return the proper error code. */ static EGLint _eglParseSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list) { _EGLDisplay *dpy = surf->Resource.Display; EGLint type = surf->Type; EGLint texture_type = EGL_PBUFFER_BIT; EGLint i, err = EGL_SUCCESS; if (!attrib_list) return EGL_SUCCESS; #ifdef EGL_MESA_screen_surface if (type == EGL_SCREEN_BIT_MESA) return _eglParseScreenSurfaceAttribList(surf, attrib_list); #endif if (dpy->Extensions.NOK_texture_from_pixmap) texture_type |= EGL_PIXMAP_BIT; for (i = 0; attrib_list[i] != EGL_NONE; i++) { EGLint attr = attrib_list[i++]; EGLint val = attrib_list[i]; switch (attr) { /* common attributes */ case EGL_VG_COLORSPACE: switch (val) { case EGL_VG_COLORSPACE_sRGB: case EGL_VG_COLORSPACE_LINEAR: break; default: err = EGL_BAD_ATTRIBUTE; break; } if (err != EGL_SUCCESS) break; surf->VGColorspace = val; break; case EGL_VG_ALPHA_FORMAT: switch (val) { case EGL_VG_ALPHA_FORMAT_NONPRE: case EGL_VG_ALPHA_FORMAT_PRE: break; default: err = EGL_BAD_ATTRIBUTE; break; } if (err != EGL_SUCCESS) break; surf->VGAlphaFormat = val; break; /* window surface attributes */ case EGL_RENDER_BUFFER: if (type != EGL_WINDOW_BIT) { err = EGL_BAD_ATTRIBUTE; break; } if (val != EGL_BACK_BUFFER && val != EGL_SINGLE_BUFFER) { err = EGL_BAD_ATTRIBUTE; break; } surf->RenderBuffer = val; break; case EGL_POST_SUB_BUFFER_SUPPORTED_NV: if (!dpy->Extensions.NV_post_sub_buffer || type != EGL_WINDOW_BIT) { err = EGL_BAD_ATTRIBUTE; break; } if (val != EGL_TRUE && val != EGL_FALSE) { err = EGL_BAD_PARAMETER; break; } surf->PostSubBufferSupportedNV = val; break; /* pbuffer surface attributes */ case EGL_WIDTH: if (type != EGL_PBUFFER_BIT) { err = EGL_BAD_ATTRIBUTE; break; } if (val < 0) { err = EGL_BAD_PARAMETER; break; } surf->Width = val; break; case EGL_HEIGHT: if (type != EGL_PBUFFER_BIT) { err = EGL_BAD_ATTRIBUTE; break; } if (val < 0) { err = EGL_BAD_PARAMETER; break; } surf->Height = val; break; case EGL_LARGEST_PBUFFER: if (type != EGL_PBUFFER_BIT) { err = EGL_BAD_ATTRIBUTE; break; } surf->LargestPbuffer = !!val; break; /* for eglBindTexImage */ case EGL_TEXTURE_FORMAT: if (!(type & texture_type)) { err = EGL_BAD_ATTRIBUTE; break; } switch (val) { case EGL_TEXTURE_RGB: case EGL_TEXTURE_RGBA: case EGL_NO_TEXTURE: break; default: err = EGL_BAD_ATTRIBUTE; break; } if (err != EGL_SUCCESS) break; surf->TextureFormat = val; break; case EGL_TEXTURE_TARGET: if (!(type & texture_type)) { err = EGL_BAD_ATTRIBUTE; break; } switch (val) { case EGL_TEXTURE_2D: case EGL_NO_TEXTURE: break; default: err = EGL_BAD_ATTRIBUTE; break; } if (err != EGL_SUCCESS) break; surf->TextureTarget = val; break; case EGL_MIPMAP_TEXTURE: if (!(type & texture_type)) { err = EGL_BAD_ATTRIBUTE; break; } surf->MipmapTexture = !!val; break; /* no pixmap surface specific attributes */ default: err = EGL_BAD_ATTRIBUTE; break; } if (err != EGL_SUCCESS) { _eglLog(_EGL_WARNING, "bad surface attribute 0x%04x", attr); break; } } return err; } /** * Do error check on parameters and initialize the given _EGLSurface object. * \return EGL_TRUE if no errors, EGL_FALSE otherwise. */ EGLBoolean _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type, _EGLConfig *conf, const EGLint *attrib_list) { const char *func; EGLint renderBuffer = EGL_BACK_BUFFER; EGLint swapBehavior = EGL_BUFFER_PRESERVED; EGLint err; switch (type) { case EGL_WINDOW_BIT: func = "eglCreateWindowSurface"; swapBehavior = EGL_BUFFER_DESTROYED; break; case EGL_PIXMAP_BIT: func = "eglCreatePixmapSurface"; renderBuffer = EGL_SINGLE_BUFFER; break; case EGL_PBUFFER_BIT: func = "eglCreatePBufferSurface"; break; #ifdef EGL_MESA_screen_surface case EGL_SCREEN_BIT_MESA: func = "eglCreateScreenSurface"; renderBuffer = EGL_SINGLE_BUFFER; /* XXX correct? */ break; #endif default: _eglLog(_EGL_WARNING, "Bad type in _eglInitSurface"); return EGL_FALSE; } if ((conf->SurfaceType & type) == 0) { /* The config can't be used to create a surface of this type */ _eglError(EGL_BAD_CONFIG, func); return EGL_FALSE; } _eglInitResource(&surf->Resource, sizeof(*surf), dpy); surf->Type = type; surf->Config = conf; surf->Width = 0; surf->Height = 0; surf->TextureFormat = EGL_NO_TEXTURE; surf->TextureTarget = EGL_NO_TEXTURE; surf->MipmapTexture = EGL_FALSE; surf->LargestPbuffer = EGL_FALSE; surf->RenderBuffer = renderBuffer; surf->VGAlphaFormat = EGL_VG_ALPHA_FORMAT_NONPRE; surf->VGColorspace = EGL_VG_COLORSPACE_sRGB; surf->MipmapLevel = 0; surf->MultisampleResolve = EGL_MULTISAMPLE_RESOLVE_DEFAULT; surf->SwapBehavior = swapBehavior; surf->HorizontalResolution = EGL_UNKNOWN; surf->VerticalResolution = EGL_UNKNOWN; surf->AspectRatio = EGL_UNKNOWN; surf->PostSubBufferSupportedNV = EGL_FALSE; /* the default swap interval is 1 */ _eglClampSwapInterval(surf, 1); err = _eglParseSurfaceAttribList(surf, attrib_list); if (err != EGL_SUCCESS) return _eglError(err, func); return EGL_TRUE; } EGLBoolean _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface, EGLint attribute, EGLint *value) { switch (attribute) { case EGL_WIDTH: *value = surface->Width; break; case EGL_HEIGHT: *value = surface->Height; break; case EGL_CONFIG_ID: *value = surface->Config->ConfigID; break; case EGL_LARGEST_PBUFFER: *value = surface->LargestPbuffer; break; case EGL_TEXTURE_FORMAT: /* texture attributes: only for pbuffers, no error otherwise */ if (surface->Type == EGL_PBUFFER_BIT) *value = surface->TextureFormat; break; case EGL_TEXTURE_TARGET: if (surface->Type == EGL_PBUFFER_BIT) *value = surface->TextureTarget; break; case EGL_MIPMAP_TEXTURE: if (surface->Type == EGL_PBUFFER_BIT) *value = surface->MipmapTexture; break; case EGL_MIPMAP_LEVEL: if (surface->Type == EGL_PBUFFER_BIT) *value = surface->MipmapLevel; break; case EGL_SWAP_BEHAVIOR: *value = surface->SwapBehavior; break; case EGL_RENDER_BUFFER: *value = surface->RenderBuffer; break; case EGL_PIXEL_ASPECT_RATIO: *value = surface->AspectRatio; break; case EGL_HORIZONTAL_RESOLUTION: *value = surface->HorizontalResolution; break; case EGL_VERTICAL_RESOLUTION: *value = surface->VerticalResolution; break; case EGL_MULTISAMPLE_RESOLVE: *value = surface->MultisampleResolve; break; case EGL_VG_ALPHA_FORMAT: *value = surface->VGAlphaFormat; break; case EGL_VG_COLORSPACE: *value = surface->VGColorspace; break; case EGL_POST_SUB_BUFFER_SUPPORTED_NV: *value = surface->PostSubBufferSupportedNV; break; default: _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface"); return EGL_FALSE; } return EGL_TRUE; } /** * Default fallback routine - drivers might override this. */ EGLBoolean _eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface, EGLint attribute, EGLint value) { EGLint confval; EGLint err = EGL_SUCCESS; switch (attribute) { case EGL_MIPMAP_LEVEL: confval = surface->Config->RenderableType; if (!(confval & (EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT))) { err = EGL_BAD_PARAMETER; break; } surface->MipmapLevel = value; break; case EGL_MULTISAMPLE_RESOLVE: switch (value) { case EGL_MULTISAMPLE_RESOLVE_DEFAULT: break; case EGL_MULTISAMPLE_RESOLVE_BOX: confval = surface->Config->SurfaceType; if (!(confval & EGL_MULTISAMPLE_RESOLVE_BOX_BIT)) err = EGL_BAD_MATCH; break; default: err = EGL_BAD_ATTRIBUTE; break; } if (err != EGL_SUCCESS) break; surface->MultisampleResolve = value; break; case EGL_SWAP_BEHAVIOR: switch (value) { case EGL_BUFFER_DESTROYED: break; case EGL_BUFFER_PRESERVED: confval = surface->Config->SurfaceType; if (!(confval & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)) err = EGL_BAD_MATCH; break; default: err = EGL_BAD_ATTRIBUTE; break; } if (err != EGL_SUCCESS) break; surface->SwapBehavior = value; break; default: err = EGL_BAD_ATTRIBUTE; break; } if (err != EGL_SUCCESS) return _eglError(err, "eglSurfaceAttrib"); return EGL_TRUE; } EGLBoolean _eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface, EGLint buffer) { EGLint texture_type = EGL_PBUFFER_BIT; /* Just do basic error checking and return success/fail. * Drivers must implement the real stuff. */ if (dpy->Extensions.NOK_texture_from_pixmap) texture_type |= EGL_PIXMAP_BIT; if (!(surface->Type & texture_type)) { _eglError(EGL_BAD_SURFACE, "eglBindTexImage"); return EGL_FALSE; } if (surface->TextureFormat == EGL_NO_TEXTURE) { _eglError(EGL_BAD_MATCH, "eglBindTexImage"); return EGL_FALSE; } if (surface->TextureTarget == EGL_NO_TEXTURE) { _eglError(EGL_BAD_MATCH, "eglBindTexImage"); return EGL_FALSE; } if (buffer != EGL_BACK_BUFFER) { _eglError(EGL_BAD_PARAMETER, "eglBindTexImage"); return EGL_FALSE; } surface->BoundToTexture = EGL_TRUE; return EGL_TRUE; } EGLBoolean _eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint interval) { _eglClampSwapInterval(surf, interval); return EGL_TRUE; }