diff options
author | David Nusinow <[email protected]> | 2006-09-24 21:11:46 +0000 |
---|---|---|
committer | David Nusinow <[email protected]> | 2006-09-24 21:11:46 +0000 |
commit | eadb76b3f8e0e9b82da762bd29e53895bf9e6351 (patch) | |
tree | b9f68fc763f9ea055287c366e61de84191b200ce /src/egl | |
parent | b3f7313ae4f4cd418522595e90e7d06ef6992f0a (diff) |
Bump to latest mesa in Debian
Diffstat (limited to 'src/egl')
31 files changed, 6814 insertions, 0 deletions
diff --git a/src/egl/Makefile b/src/egl/Makefile new file mode 100644 index 00000000000..931e9d0cb86 --- /dev/null +++ b/src/egl/Makefile @@ -0,0 +1,24 @@ +# src/egl/Makefile + +TOP = ../.. + +SUBDIRS = main drivers/demo drivers/dri + + +default: subdirs + + +subdirs: + @for dir in $(SUBDIRS) ; do \ + if [ -d $$dir ] ; then \ + (cd $$dir ; $(MAKE)) || exit 1 ; \ + fi \ + done + + +clean: + @for dir in $(SUBDIRS) ; do \ + if [ -d $$dir ] ; then \ + (cd $$dir ; $(MAKE) clean) ; \ + fi \ + done diff --git a/src/egl/docs/EGL_MESA_screen_surface b/src/egl/docs/EGL_MESA_screen_surface new file mode 100644 index 00000000000..3a11da7ac9b --- /dev/null +++ b/src/egl/docs/EGL_MESA_screen_surface @@ -0,0 +1,578 @@ +Name + + MESA_screen_surface + +Name Strings + + EGL_MESA_screen_surface + +Contact + + Brian Paul + + To discuss, join the [email protected] list. + +Status + + Preliminary - totally subject to change. + +Version + + 10 (10 August 2005) + +Number + + TBD + +Dependencies + + EGL 1.0 or later. + +Overview + + EGL 1.1 supports three types of drawing surfaces: + * Window surfaces + * Pixmap surfaces + * Pbuffer surfaces + This extension defines a fourth type of drawing surface: + * Screen surface + + A screen surface is a surface for which the (front) color buffer can + be directly displayed (i.e. scanned out) on a monitor (such as a flat + panel or CRT). In particular the color buffer memory will be allocated + at a location in VRAM (and in a suitable format) which can be displayed + by the graphics hardware. + + Note that the width and height of the screen surface need not exactly + match the monitor's current resolution. For example, while the monitor + may be configured to to show 1024x768 pixels, the associated screen + surface may be larger, such as 1200x1000. The "screen origin" attribute + will specify which region of the screen surface which is visible on the + monitor. The screen surface can be scrolled by changing this origin. + + This extension also defines functions for controlling the monitor's + display mode (width, height, refresh rate, etc), and specifing which + screen surface is to be displayed on a monitor. + + The new EGLModeMESA type and related functions are very similar to the + EGLConfig type and related functions. The user may get a list of + supported modes for a screen and specify the mode to be used when + displaying a screen surface. + + +Issues + + 1. Should EGL_INTERLACE be a supported mode attribute? + + Arguments against: + + No, this should be provided by another extension which would + also provide the mechanisms needed to play back interlaced video + material correctly on hardware that supports it. + This extension should prefer non-interlaced modes. [M. Danzer] + + Arguments for: + + An interlaced display can be of use without considering video + material. Being able to query whether a screen is operating in + interlaced mode can be used by applications to control their + drawing. For example: avoid drawing 1-pixel-wide horizontal lines + if screen is interlaced. [B. Paul] + + Resolution: Defer for future extension? + + + 2. Should EGL_REFRESH_RATE be a supported mode attribute? + + Arguments for: + + Yes, it's been shown that applications and/or users need to select + modes by this. [M. Danzer] + + Many examples have been given in which it's desirable to let the + user choose from a variety of refresh rates without having to + restart/reconfigure. [B. Paul] + + Arguments against: + + TBD. + + Resolution: Yes. + + + 3. Exactly how should the list of modes returned by eglChooseConfigMESA + be sorted? + + Current method is described in the text below. Subject to change. + + Alternately, leave the sorting order undefined so that each + implementation can return the modes in order of "most desirable" + to "least desirable" which may depend on the display technology + (CRT vs LCD, etc) or other factors. + + + 4. How should screen blanking be supported? Note that a screen can be + disabled or turned off by calling eglShowSurface(dpy, scrn, + EGL_NO_SURFACE, EGL_NO_MODE_MESA). But what about power-save mode? + + I would defer this to other extensions that depend on this one. + I can imagine people wanting different semantics not just in + relation to the power management API being exposed (DPMS or whatever) + but also relating to what events can trigger EGL_CONTEXT_LOST. Also + I'm not sure whether power management commands are properly operations + on the Display or on a screen surface. [A. Jackson] + + + 5. Should the EGL_PHYSICAL_SIZE_EGL query be kept? The size information + isn't always reliable (consider video projectors) but can still be + used to determine the pixel aspect ratio. + + Arguments for: + + X supports a similar query with DisplayWidthMM(), DisplayHeightMM(). + If this information can be easily queried with EDID, why not + make it available to the user? + + Arguments against: + + Historically, these values aren't always accurate. Also, they're + not always applicable to the display device. + + Other options: + + Perhaps just a pixel aspect ratio should be supported. [M. Danzer] + + Postpone for a future extension, if needed. [A. Jackson] + + + 6. Should detailed mode timing information be exposed by this API? + + Probably not. Instead, offer that information in a layered extension. + + + 7. How should the notion of a screen's "native" mode be expressed? + For example, LCD panels have a native resolution and refresh rate + that looks best but other sub-optimal resolutions may be supported. + + The mode attribute EGL_OPTIMAL_MESA will be set for modes which + best match the screen. [M. Danzer] + + + 8. Should eglQueryModeStringMESA() be included? This function returns + a human-readable string which corresponds to an EGLMode. + + Arguments for: + + A mode name such as "HDTV-720P" might mean more to users than + "1280x720@60Hz" if the later were generated via code. + + Arguments against: + + There's no standard syntax for the strings. May cause more + trouble than it's worth. + + Postpone for future extension. [A. Jackson] + + Latest discussion leaning toward omitting this function. + + + 9. Should we use "Get" or "Query" for functions which return state? + The EGL 1.x specification doesn't seem to be totally consistent + in this regard, but "Query" is used more often. + + Use "Get" for mode-related queries (as for EGLConfigs) but "Query" + for everything else. + + + 10. What should be the default size for screen surfaces? + + For Pbuffer surfaces the default width and height are zero. + We'll do the same for screen surfaces. Since there's no function + to resize surfaces it's useless to have a 0x0 screen, but this isn't + a situation that'll normally be encountered. + + + 11. Should there be a function for resizing a screen surface? + + Suppose one wants to change the screen's size in the EGL application. + Also suppose there's a hardware restriction such that only one screen + surface can exist at a time (either for lack of memory or because of + memory layout restrictions). + + The basic idea is that the currently displayed screen surface must + be deallocated before a new one can be created. Perhaps a resize + function would work better? + + + 12. How should sub-pixel LCD color information be made available? + What about the display's gamma value? + + Perhaps expose as additional read-only mode attributes. + + Perhaps postpone for a layered extension. + + + 13. What happens if the user attempts to delete a screen surface that + is currently being shown? + + Spec currently says that's illegal and that an error (TBD) will be + generated. + + + 14. What if the physical screen size can't be determined? Should + a query of EGL_PHYSICAL_SIZE_MESA return [0,0]? + + TBD. + + + 15. Suppose the device's number of RAMDACs is different from the + number of output ports. For example, a graphics card with + two RAMDACs but three ports (VGA, DVI, TV). + + Address this in a follow-on extension. [Matthias Hopf] + + + 16. How should we deal with on-the-fly device changes? For example, + the monitor being unplugged and replaced by another with different + characteristics? + + A HAL event could be received via DBUS in the application [J. Smirl, + A. Jackson]. + + Should there be an EGL mechanism for detecting this? Maybe an + EGL_SCREEN_LOST error (similar to EGL_CONTEXT_LOST) can be recorded + when there's a screen change. At least then the application can + poll to detect this situation. + + Maybe leave that to a future extension. + + See also the EGL_SCREEN_COUNT_MESA query. + + + 17. What if pixel-accurate panning is not supported (see + eglScreenPositionMESA)? [M. Danzer] + + Is this a common problem? Can we ignore it for now? + + + 18. Should eglShowSurfaceMESA be renamed to eglShowScreenSurfaceMESA? + + Probably. + + + +New Procedures and Functions + + EGLBoolean eglChooseModeMESA(EGLDisplay dpy, EGLScreenMESA screen, + const EGLint *attrib_list, + EGLModeMESA *modes, EGLint modes_size, + EGLint *num_modes) + + EGLBoolean eglGetModesMESA(EGLDisplay dpy, EGLScreenMESA screen, + EGLModeMESA *modes, EGLint modes_size, + EGLint *num_modes) + + EGLBoolean eglGetModeAttribMESA(EGLDisplay dpy, EGLModeMESA mode, + EGLint attrib, EGLint *value) + + + EGLBoolean eglGetScreensMESA(EGLDisplay dpy, EGLScreenMESA *screens, + EGLint screens_size, EGLint *num_screens) + + EGLSurface eglCreateScreenSurfaceMESA(EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list) + + EGLBoolean eglShowSurfaceMESA(EGLDisplay dpy, EGLScreenMESA screen, + EGLSurface surface, EGLModeMESA mode) + + EGLBoolean eglScreenPositionMESA(EGLDisplay dpy, EGLScreenMESA screen, + EGLint x, EGLint y) + + + EGLBoolean eglQueryScreenMESA(EGLDisplay dpy, EGLScreenMESA screen, + EGLint attrib, EGLint *value); + + EGLBoolean eglQueryScreenSurfaceMESA(EGLDisplay dpy, EGLScreenMESA screen, + EGLSurface *surface) + + EGLBoolean eglQueryScreenModeMESA(EGLDisplay dpy, EGLScreenMESA screen, + EGLModeMESA *mode) + + const char *eglQueryModeStringMESA(EGLDisplay dpy, EGLMode mode); + + +New Types + + EGLModeMESA + EGLScreenMESA + +New Tokens + + New error codes: + + EGL_BAD_SCREEN_MESA + EGL_BAD_MODE_MESA + + Screen-related tokens: + + EGL_SCREEN_COUNT_MESA + EGL_SCREEN_POSITION_MESA + EGL_PHYSICAL_SIZE_MESA + EGL_SCREEN_BIT_MESA + EGL_SCREEN_POSITION_GRANULARITY_MESA + + Mode-related tokens: + + EGL_MODE_ID_MESA + EGL_REFRESH_RATE_MESA + EGL_INTERLACED_MESA + EGL_OPTIMAL_MESA + EGL_NO_MODE_MESA + + +Additions to Chapter X of the EGL 1.1 Specification + + [XXX this all has to be rewritten to fit into the EGL specification + and match the conventions of an EGL extension. For now, just list + all the functions with brief descriptions.] + + + EGLBoolean eglChooseModeMESA(EGLDisplay dpy, const EGLScreenMESA screen, + EGLint *attrib_list, EGLModeMESA *modes, + EGLint modes_size, EGLint *num_modes) + + Like eglChooseConfig, returns a list of EGLModes which match the given + attribute list. This does not set the screen's current display mode. + The attribute list is a list of token/value pairs terminated with + EGL_NONE. Supported attributes include: + + Name Description + --------------------- --------------------------------------------- + EGL_WIDTH Mode width (resolution) + EGL_HEIGHT Mode height (resolution) + EGL_REFRESH_RATE_MESA The mode's refresh rate, multiplied by 1000 + EGL_INTERLACED_MESA 1 indicates an interlaced mode, 0 otherwise + EGL_OPTIMAL_MESA Set if the most is especially optimal for the + screen (ex. for particular LCD resolutions) + + Any other token will generate the error EGL_BAD_ATTRIBUTE. + + The list of modes returned by eglChooseModeMESA will be sorted + according to the following criteria. See the discussion of table 3.3 + in the EGL specification for more information. + + Selection Sort Sort + Attribute Default Criteria Order Priority + -------------------- -------------- ----------- ------ -------- + EGL_OPTIMAL_MESA EGL_DONT_CARE Exact 1,0 1 + EGL_INTERLACED_MESA EGL_DONT_CARE Exact 0,1 2 + EGL_REFRESH_RATE EGL_DONT_CARE AtLeast Larger 3 + EGL_WIDTH EGL_DONT_CARE AtLeast Larger 4 + EGL_HEIGHT EGL_DONT_CARE AtLeast Larger 5 + EGL_MODE_ID_MESA EGL_DONT_CARE Exact Smaller 6 + + + EGLBoolean eglGetModesMESA(EGLDisplay dpy, EGLScreenMESA screen, + EGLModeMESA *modes, EGLint modes_size, + EGLint *num_modes) + + Like eglGetConfigs, returns a list of all modes supported by the + given screen. The returned modes will be sorted in the same manner + as for eglChooseModeMESA(). + + + + EGLBoolean eglGetModeAttribMESA(EGLDisplay dpy, EGLModeMESA mode, + EGLint attrib, EGLint *value) + + Used to query mode attributes. The following attributes are supported: + + Name Return value description + --------------------- ---------------------------------------------- + EGL_OPTIMAL_MESA 1 indicates an optimal mode, 0 otherwise + EGL_INTERLACED_MESA 1 indicates an interlaced mode, 0 otherwise + EGL_REFRESH_RATE_MESA The mode's refresh rate, multiplied by 1000 + EGL_WIDTH Mode width (resolution) + EGL_HEIGHT Mode height (resolution) + EGL_MODE_ID_MESA A unique small integer identifier for the mode + + Any other token will generate the error EGL_BAD_ATTRIBUTE. + + + + EGLBoolean eglGetScreensMESA(EGLDisplay dpy, EGLScreenMESA *screens, + EGLint screens_size, EGLint *num_screens) + + This function returns an array of all available screen handles. + <screens_size> is the maximum number of screens to return in the + <screens> array. <num_screens> will return the number of screen handles + placed in the array, even if <screens> is NULL. + + The number of screens and the availability of each may change over + time (hot-plugging). Screen handles will not be reused. When a + screen handle becomes invalid, function calls which reference an + invalid handle will generate EGL_BAD_SCREEN_MESA. + + The first screen handle returned will be considered to be the primary + one. + + + + EGLSurface eglCreateScreenSurfaceMESA(EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list) + + Create a surface that can be displayed on a screen. <attrib_list> is + an array of token/value pairs terminated with EGL_NONE. Valid tokens + include: + + Name Description + ---------------- -------------------------------- + EGL_WIDTH desired surface width in pixels + EGL_HEIGHT desired surface height in pixels + + Any other token will generate the error EGL_BAD_ATTRIBUTE. + The default width and height are zero. + + + + EGLBoolean eglShowSurfaceMESA(EGLDisplay dpy, EGLScreenMESA screen, + EGLSurface surface, EGLModeMESA mode) + + This function causes a screen to show the given surface (or more + precisely, the surface's front color buffer) with the given mode. + + If the surface is in any way incompatible with the mode, the error + EGL_BAD_MATCH will be generated, EGL_FALSE will be returned, and the + previous screen state will remain in effect. This might occur when + the bandwidth of the video-out subsystem is exceeded, or if the mode + specifies a width or height that's greater than the width or height + of the surface. + + To disable a screen, the values EGL_NO_SURFACE and EGL_NO_MODE_MESA + be passed as the <surface> and <mode> parameters. + + The values of EGL_SCREEN_POSITION_MESA are clamped to the new valid + range computed from the screen size and surface size. If the new + surface is EGL_NO_SURFACE, EGL_SCREEN_POSITION_MESA is set to [0, 0]. + + + Attempting to delete a screen surface which is currently being + displayed will result in the error EGL_BAD_ACCESS being generated. + + + + EGLBoolean eglScreenPositionMESA(EGLDisplay dpy, EGLScreenMESA screen, + EGLint x, EGLint y) + + Specifies the origin of the screen's view into the surface, if the + surface is larger than the screen. Valid values for x and y are + [0, surfaceWidth - screenWidth] and [0, surfaceHeight - screenHeight], + respectively. + + The x and y values are also constrained to be integer multiples of the + EGL_SCREEN_POSITION_GRANULARITY_MESA values. + + + + + EGLBoolean eglQueryScreenMESA(EGLDisplay dpy, EGLScreenMESA screen, + EGLint attrib, EGLint *value); + + Used to query screen attributes. <attrib> may be one of the following: + + Name Return value description + ------------------------ --------------------------------------------- + EGL_SCREEN_POSITION_MESA x, y position of the screen's origin with + respect to the surface. If no surface is + attached to the screen, [0, 0] is returned. + EGL_SCREEN_POSITION_GRANULARITY_MESA + Returns the granularity, in pixels, for + which the screen position is constrained. + EGL_PHYSICAL_SIZE_MESA Physical width and height of the screen + in millimeters + + Any other token will generate the error EGL_BAD_ATTRIBUTE. + + + + + EGLBoolean eglQueryScreenSurfaceMESA(EGLDisplay dpy, EGLScreenMESA screen, + EGLSurface *surface) + + Returns the surface currently displayed on the given screen. <surface> + may be EGL_NO_SURFACE if the screen isn't currently showing any surface. + + + + + EGLBoolean eglQueryScreenModeMESA(EGLDisplay dpy, EGLScreenMESA screen, + EGLModeMESA *mode) + + Returns the given screen's current display mode. The mode may be + EGL_NO_MODE_MESA if the screen is currently disabled. + + + + const char *eglQueryModeStringMESA(EGLDisplay dpy, EGLModeMESA mode); + + Returns a human-readable string for the given mode. The string is a + zero-terminated C string which the user should not attempt to free. + There is no standard syntax for mode strings. Applications should + not directly rely on mode strings. + + + +Version History + + 1. 15 March 2005 - BrianP + Initial version + + 2. 16 March 2005 - BrianP + Removed EGL_DEPTH_MESA + Added EGL_PHYSICAL_WIDTH_MESA, EGL_PHYSICAL_HEIGHT_MESA queries + Added EGL_OPTIMAL_MESA for width/height/refresh rate selection + Added possible eglQueryModeStringMESA() function + More details of the new functions explained. + + 3. 18 March 2005 - BrianP + Added screen_number to eglChooseModeMESA(). + Fix off by one mistake in value range for ORIGIN attributes + Added Issues section + + 4. 21 March 2005 - BrianP + Removed eglScreenAttribsMESA(). + Added eglScreenPositionMESA() to set screen origin. + Replaced EGL_SCREEN_X/Y_OFFSET_MESA with EGL_SCREEN_POSITION_MESA. + Replaced EGL_PHYSICAL_WIDTH/HEIGHT_MESA with EGL_PHYSICAL_SIZE_MESA. + Use EGL_OPTIMAL_MESA as a new mode attribute. (Michel Danzer) + Added a few more issues. + + 5. 6 April 2005 - BrianP + More language for eglGetModeStringMESA(). + Added issues 10, 11, 12, 13, 14. + Updated issue 3 discussion about mode sorting. + + 6. 22 April 2005 - BrianP + Fixed "LDC" typo. + Added issues 15, 16. + Changed dependency on EGL 1.1 to EGL 1.0 + s/EGL_NUM_SCREENS_MESA/EGL_SCREEN_COUNT_MESA/ + Added eglQueryDisplayMESA() to New Functions section. + Clarified language for the EGL_SCREEN_COUNT_MESA query. + + 7. 29 April 2005 - BrianP + Added EGLScreenMESA type and eglGetScreensMESA() function. [J. Smirl]. + Replaced EGLint screen_number parameters with EGLScreenMESA screen. + Added issue 17 (pixel-accurate panning) + + 8. 2 May 2005 - BrianP + Removed eglQueryDisplayMESA. + Fixed a few more EGLint -> EGLScreenMESA changes. + + 9. 20 May 2005 - BrianP + Fixed a few typos. + Updated some open issues text. + + 10. 10 August 2005 - BrianP + Added EGL_SCREEN_POSITION_GRANULARITY_MESA. + diff --git a/src/egl/drivers/demo/Makefile b/src/egl/drivers/demo/Makefile new file mode 100644 index 00000000000..fd587b79e27 --- /dev/null +++ b/src/egl/drivers/demo/Makefile @@ -0,0 +1,31 @@ +# src/egl/drivers/demo/Makefile + +TOP = ../../../.. +include $(TOP)/configs/current + + +INCLUDE_DIRS = -I$(TOP)/include -I$(TOP)/src/egl/main + + +SOURCES = demo.c + +OBJECTS = $(SOURCES:.c=.o) + + +.c.o: + $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@ + + + +default: $(LIB_DIR)/demodriver.so + + +$(LIB_DIR)/demodriver.so: $(OBJECTS) + $(TOP)/bin/mklib -o demodriver.so -noprefix \ + -install $(LIB_DIR) $(OBJECTS) + + + +clean: + rm -f *.o + rm -f *.so diff --git a/src/egl/drivers/demo/demo.c b/src/egl/drivers/demo/demo.c new file mode 100644 index 00000000000..45545755c00 --- /dev/null +++ b/src/egl/drivers/demo/demo.c @@ -0,0 +1,316 @@ +/* + * Sample driver: Demo + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include "eglconfig.h" +#include "eglcontext.h" +#include "egldisplay.h" +#include "egldriver.h" +#include "eglglobals.h" +#include "eglmode.h" +#include "eglscreen.h" +#include "eglsurface.h" + + +/** + * Demo driver-specific driver class derived from _EGLDriver + */ +typedef struct demo_driver +{ + _EGLDriver Base; /* base class/object */ + GLuint DemoStuff; +} DemoDriver; + +#define DEMO_DRIVER(D) ((DemoDriver *) (D)) + + +/** + * Demo driver-specific surface class derived from _EGLSurface + */ +typedef struct demo_surface +{ + _EGLSurface Base; /* base class/object */ + GLuint DemoStuff; +} DemoSurface; + + +/** + * Demo driver-specific context class derived from _EGLContext + */ +typedef struct demo_context +{ + _EGLContext Base; /* base class/object */ + GLuint DemoStuff; +} DemoContext; + + + +static EGLBoolean +demoInitialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + _EGLScreen *scrn; + EGLint i; + + /* Create a screen */ + scrn = calloc(1, sizeof(*scrn)); + _eglAddScreen(disp, scrn); + + /* Create the screen's modes - silly example */ + _eglAddNewMode(scrn, 1600, 1200, 72 * 1000, "1600x1200-72"); + _eglAddNewMode(scrn, 1280, 1024, 72 * 1000, "1280x1024-70"); + _eglAddNewMode(scrn, 1280, 1024, 70 * 1000, "1280x1024-70"); + _eglAddNewMode(scrn, 1024, 768, 72 * 1000, "1024x768-72"); + + /* Create the display's visual configs - silly example */ + for (i = 0; i < 4; i++) { + _EGLConfig config; + _eglInitConfig(&config, i + 1); + _eglSetConfigAttrib(&config, EGL_RED_SIZE, 8); + _eglSetConfigAttrib(&config, EGL_GREEN_SIZE, 8); + _eglSetConfigAttrib(&config, EGL_BLUE_SIZE, 8); + _eglSetConfigAttrib(&config, EGL_ALPHA_SIZE, 8); + _eglSetConfigAttrib(&config, EGL_BUFFER_SIZE, 32); + if (i & 1) { + _eglSetConfigAttrib(&config, EGL_DEPTH_SIZE, 32); + } + if (i & 2) { + _eglSetConfigAttrib(&config, EGL_STENCIL_SIZE, 8); + } + _eglSetConfigAttrib(&config, EGL_SURFACE_TYPE, + (EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT)); + _eglAddConfig(disp, &config); + } + + drv->Initialized = EGL_TRUE; + + *major = 1; + *minor = 0; + + return EGL_TRUE; +} + + +static EGLBoolean +demoTerminate(_EGLDriver *drv, EGLDisplay dpy) +{ + /*DemoDriver *demo = DEMO_DRIVER(dpy);*/ + free(drv); + return EGL_TRUE; +} + + +static DemoContext * +LookupDemoContext(EGLContext ctx) +{ + _EGLContext *c = _eglLookupContext(ctx); + return (DemoContext *) c; +} + + +static DemoSurface * +LookupDemoSurface(EGLSurface surf) +{ + _EGLSurface *s = _eglLookupSurface(surf); + return (DemoSurface *) s; +} + + + +static EGLContext +demoCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list) +{ + _EGLConfig *conf; + DemoContext *c; + int i; + + conf = _eglLookupConfig(drv, dpy, config); + if (!conf) { + _eglError(EGL_BAD_CONFIG, "eglCreateContext"); + return EGL_NO_CONTEXT; + } + + for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { + switch (attrib_list[i]) { + /* no attribs defined for now */ + default: + _eglError(EGL_BAD_ATTRIBUTE, "eglCreateContext"); + return EGL_NO_CONTEXT; + } + } + + c = (DemoContext *) calloc(1, sizeof(DemoContext)); + if (!c) + return EGL_NO_CONTEXT; + + _eglInitContext(drv, dpy, &c->Base, config, attrib_list); + c->DemoStuff = 1; + printf("demoCreateContext\n"); + + /* generate handle and insert into hash table */ + _eglSaveContext(&c->Base); + assert(c->Base.Handle); + + return c->Base.Handle; +} + + +static EGLSurface +demoCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list) +{ + int i; + for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { + switch (attrib_list[i]) { + /* no attribs at this time */ + default: + _eglError(EGL_BAD_ATTRIBUTE, "eglCreateWindowSurface"); + return EGL_NO_SURFACE; + } + } + printf("eglCreateWindowSurface()\n"); + /* XXX unfinished */ + + return EGL_NO_SURFACE; +} + + +static EGLSurface +demoCreatePixmapSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list) +{ + _EGLConfig *conf; + EGLint i; + + conf = _eglLookupConfig(drv, dpy, config); + if (!conf) { + _eglError(EGL_BAD_CONFIG, "eglCreatePixmapSurface"); + return EGL_NO_SURFACE; + } + + for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { + switch (attrib_list[i]) { + /* no attribs at this time */ + default: + _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePixmapSurface"); + return EGL_NO_SURFACE; + } + } + + if (conf->Attrib[EGL_SURFACE_TYPE - FIRST_ATTRIB] == 0) { + _eglError(EGL_BAD_MATCH, "eglCreatePixmapSurface"); + return EGL_NO_SURFACE; + } + + printf("eglCreatePixmapSurface()\n"); + return EGL_NO_SURFACE; +} + + +static EGLSurface +demoCreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list) +{ + DemoSurface *surf = (DemoSurface *) calloc(1, sizeof(DemoSurface)); + if (!surf) + return EGL_NO_SURFACE; + + if (!_eglInitSurface(drv, dpy, &surf->Base, EGL_PBUFFER_BIT, + config, attrib_list)) { + free(surf); + return EGL_NO_SURFACE; + } + + /* a real driver would allocate the pbuffer memory here */ + + return surf->Base.Handle; +} + + +static EGLBoolean +demoDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface) +{ + DemoSurface *fs = LookupDemoSurface(surface); + _eglRemoveSurface(&fs->Base); + if (fs->Base.IsBound) { + fs->Base.DeletePending = EGL_TRUE; + } + else { + free(fs); + } + return EGL_TRUE; +} + + +static EGLBoolean +demoDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context) +{ + DemoContext *fc = LookupDemoContext(context); + _eglRemoveContext(&fc->Base); + if (fc->Base.IsBound) { + fc->Base.DeletePending = EGL_TRUE; + } + else { + free(fc); + } + return EGL_TRUE; +} + + +static EGLBoolean +demoMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext context) +{ + /*DemoDriver *demo = DEMO_DRIVER(dpy);*/ + DemoSurface *readSurf = LookupDemoSurface(read); + DemoSurface *drawSurf = LookupDemoSurface(draw); + DemoContext *ctx = LookupDemoContext(context); + EGLBoolean b; + + b = _eglMakeCurrent(drv, dpy, draw, read, context); + if (!b) + return EGL_FALSE; + + /* XXX this is where we'd do the hardware context switch */ + (void) drawSurf; + (void) readSurf; + (void) ctx; + + printf("eglMakeCurrent()\n"); + return EGL_TRUE; +} + + +/** + * The bootstrap function. Return a new DemoDriver object and + * plug in API functions. + */ +_EGLDriver * +_eglMain(_EGLDisplay *dpy) +{ + DemoDriver *demo; + + demo = (DemoDriver *) calloc(1, sizeof(DemoDriver)); + if (!demo) { + return NULL; + } + + /* First fill in the dispatch table with defaults */ + _eglInitDriverFallbacks(&demo->Base); + /* then plug in our Demo-specific functions */ + demo->Base.API.Initialize = demoInitialize; + demo->Base.API.Terminate = demoTerminate; + demo->Base.API.CreateContext = demoCreateContext; + demo->Base.API.MakeCurrent = demoMakeCurrent; + demo->Base.API.CreateWindowSurface = demoCreateWindowSurface; + demo->Base.API.CreatePixmapSurface = demoCreatePixmapSurface; + demo->Base.API.CreatePbufferSurface = demoCreatePbufferSurface; + demo->Base.API.DestroySurface = demoDestroySurface; + demo->Base.API.DestroyContext = demoDestroyContext; + + /* enable supported extensions */ + demo->Base.Extensions.MESA_screen_surface = EGL_TRUE; + demo->Base.Extensions.MESA_copy_context = EGL_TRUE; + + return &demo->Base; +} diff --git a/src/egl/drivers/dri/Makefile b/src/egl/drivers/dri/Makefile new file mode 100644 index 00000000000..6b50959a5ab --- /dev/null +++ b/src/egl/drivers/dri/Makefile @@ -0,0 +1,64 @@ +# src/egl/drivers/dri/Makefile + +TOP = ../../../.. +include $(TOP)/configs/current + + +### Include directories +INCLUDE_DIRS = \ + -I. \ + -I$(DRM_SOURCE_PATH)/shared-core \ + -I$(DRM_SOURCE_PATH)/libdrm \ + -I$(TOP)/include \ + -I$(TOP)/include/GL/internal \ + -I$(TOP)/src/mesa \ + -I$(TOP)/src/mesa/main \ + -I$(TOP)/src/mesa/glapi \ + -I$(TOP)/src/mesa/math \ + -I$(TOP)/src/mesa/transform \ + -I$(TOP)/src/mesa/shader \ + -I$(TOP)/src/mesa/swrast \ + -I$(TOP)/src/mesa/swrast_setup \ + -I$(TOP)/src/egl/main \ + -I$(TOP)/src/mesa/drivers/dri/common + + +HEADERS = egldri.h + +SOURCES = egldri.c \ + $(DRM_SOURCE_PATH)/libdrm/xf86drm.c \ + $(DRM_SOURCE_PATH)/libdrm/xf86drmHash.c \ + $(DRM_SOURCE_PATH)/libdrm/xf86drmRandom.c + +OBJECTS = $(SOURCES:.c=.o) + + +.c.o: + $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@ + + + +default: depend library Makefile + + +# EGLdri Library +library: $(LIB_DIR)/libEGLdri.so + +$(LIB_DIR)/libEGLdri.so: $(OBJECTS) + $(TOP)/bin/mklib -o EGLdri -major 1 -minor 0 \ + -install $(LIB_DIR) -ldl $(OBJECTS) + + +clean: + rm -f *.o + rm -f *.so + +depend: $(SOURCES) $(HEADERS) + @ echo "running $(MKDEP)" + @ touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) \ + $(SOURCES) $(HEADERS) > /dev/null + +include depend +# DO NOT DELETE + diff --git a/src/egl/drivers/dri/egldri.c b/src/egl/drivers/dri/egldri.c new file mode 100644 index 00000000000..cab0be2bd18 --- /dev/null +++ b/src/egl/drivers/dri/egldri.c @@ -0,0 +1,1138 @@ +/** + * Generic EGL driver for DRI. + * + * This file contains all the code needed to interface DRI-based drivers + * with libEGL. + * + * There's a lot of dependencies on fbdev and the /sys/ filesystem. + */ + + +#include <dirent.h> +#include <stdio.h> +#include <string.h> +#include <linux/fb.h> +#include <assert.h> +#include <dlfcn.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/time.h> + +#include "egldriver.h" +#include "egldisplay.h" +#include "eglcontext.h" +#include "eglconfig.h" +#include "eglsurface.h" +#include "eglscreen.h" +#include "eglglobals.h" +#include "egllog.h" +#include "eglmode.h" + +#include "egldri.h" + +const char *sysfs = "/sys/class"; +#define None 0 +static const int empty_attribute_list[1] = { None }; + + +/** + * The bootstrap function. + * Return a new driDriver object and plug in API functions. + * This function, in turn, loads a specific DRI driver (ex: r200_dri.so). + */ +_EGLDriver * +_eglMain(_EGLDisplay *dpy) +{ + int length; + char path[NAME_MAX]; + struct dirent *dirent; +#if 1 + FILE *file; +#endif + DIR *dir; + _EGLDriver *driver = NULL;; + + snprintf(path, sizeof(path), "%s/drm", sysfs); + if (!(dir = opendir(path))) { + _eglLog(_EGL_WARNING, "%s DRM devices not found.", path); + return EGL_FALSE; + } + while ((dirent = readdir(dir))) { + + if (strncmp(&dirent->d_name[0], "card", 4) != 0) + continue; + if (strcmp(&dirent->d_name[4], &dpy->Name[1]) != 0) + continue; + + snprintf(path, sizeof(path), "%s/drm/card%s/dri_library_name", sysfs, &dpy->Name[1]); + _eglLog(_EGL_INFO, "Opening %s", path); +#if 1 + file = fopen(path, "r"); + if (!file) { + _eglLog(_EGL_WARNING, "Failed to open %s", path); + return NULL; + } + fgets(path, sizeof(path), file); + fclose(file); +#else + strcpy(path, "r200\n"); +#endif + if ((length = strlen(path)) > 0) + path[length - 1] = '\0'; /* remove the trailing newline from sysfs */ + strncat(path, "_dri", sizeof(path)); + + driver = _eglOpenDriver(dpy, path); + + break; + } + closedir(dir); + + return driver; +} + + +/** + * Called by eglCreateContext via drv->API.CreateContext(). + */ +static EGLContext +_eglDRICreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + EGLContext share_list, const EGLint *attrib_list) +{ + driDisplay *disp = Lookup_driDisplay(dpy); + driContext *c, *share; + void *sharePriv; + _EGLConfig *conf; + __GLcontextModes visMode; + + c = (driContext *) calloc(1, sizeof(*c)); + if (!c) + return EGL_NO_CONTEXT; + + if (!_eglInitContext(drv, dpy, &c->Base, config, attrib_list)) { + free(c); + return EGL_NO_CONTEXT; + } + + if (share_list != EGL_NO_CONTEXT) { + _EGLContext *shareCtx = _eglLookupContext(share_list); + if (!shareCtx) { + _eglError(EGL_BAD_CONTEXT, "eglCreateContext(share_list)"); + return EGL_FALSE; + } + } + share = Lookup_driContext(share_list); + if (share) + sharePriv = share->driContext.private; + else + sharePriv = NULL; + + conf = _eglLookupConfig(drv, dpy, config); + assert(conf); + _eglConfigToContextModesRec(conf, &visMode); + + c->driContext.private = disp->driScreen.createNewContext(disp, &visMode, + GLX_WINDOW_BIT, sharePriv, &c->driContext); + if (!c->driContext.private) { + free(c); + return EGL_FALSE; + } + + /* generate handle and insert into hash table */ + _eglSaveContext(&c->Base); + + return c->Base.Handle; +} + + +static EGLBoolean +_eglDRIMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext context) +{ + driDisplay *disp = Lookup_driDisplay(dpy); + driContext *ctx = Lookup_driContext(context); + EGLBoolean b; + + b = _eglMakeCurrent(drv, dpy, draw, read, context); + if (!b) + return EGL_FALSE; + + if (ctx) { + ctx->driContext.bindContext(disp, 0, read, draw, &ctx->driContext); + } + else { + /* what's this??? */ + /* _mesa_make_current( NULL, NULL, NULL );*/ + } + return EGL_TRUE; +} + + +static EGLSurface +_eglDRICreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list) +{ + driSurface *surf; + + surf = (driSurface *) calloc(1, sizeof(*surf)); + if (!surf) { + return EGL_NO_SURFACE; + } + + if (!_eglInitSurface(drv, dpy, &surf->Base, EGL_PBUFFER_BIT, + config, attrib_list)) { + free(surf); + return EGL_NO_SURFACE; + } + + /* create software-based pbuffer */ + { +#if 0 + GLcontext *ctx = NULL; /* this _should_ be OK */ +#endif + GLvisual visMode; + _EGLConfig *conf = _eglLookupConfig(drv, dpy, config); + assert(conf); /* bad config should be caught earlier */ + _eglConfigToContextModesRec(conf, &visMode); + +#if 0 + surf->mesa_framebuffer = _mesa_create_framebuffer(&visMode); + _mesa_add_soft_renderbuffers(surf->mesa_framebuffer, + GL_TRUE, /* color bufs */ + visMode.haveDepthBuffer, + visMode.haveStencilBuffer, + visMode.haveAccumBuffer, + GL_FALSE, /* alpha */ + GL_FALSE /* aux */ ); + + /* set pbuffer/framebuffer size */ + _mesa_resize_framebuffer(ctx, surf->mesa_framebuffer, + surf->Base.Width, surf->Base.Height); +#endif + } + + _eglSaveSurface(&surf->Base); + + return surf->Base.Handle; +} + + +static EGLBoolean +_eglDRIDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface) +{ + driDisplay *disp = Lookup_driDisplay(dpy); + driSurface *fs = Lookup_driSurface(surface); + + _eglRemoveSurface(&fs->Base); + + fs->drawable.destroyDrawable(disp, fs->drawable.private); + + if (fs->Base.IsBound) { + fs->Base.DeletePending = EGL_TRUE; + } + else { + free(fs); + } + return EGL_TRUE; +} + + +static EGLBoolean +_eglDRIDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context) +{ + driDisplay *disp = Lookup_driDisplay(dpy); + driContext *fc = Lookup_driContext(context); + + _eglRemoveContext(&fc->Base); + + fc->driContext.destroyContext(disp, 0, fc->driContext.private); + + if (fc->Base.IsBound) { + fc->Base.DeletePending = EGL_TRUE; + } + else { + free(fc); + } + return EGL_TRUE; +} + + +/** + * Create a drawing surface which can be directly displayed on a screen. + */ +static EGLSurface +_eglDRICreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg, + const EGLint *attrib_list) +{ + _EGLConfig *config = _eglLookupConfig(drv, dpy, cfg); + driDisplay *disp = Lookup_driDisplay(dpy); + driSurface *surface; + GLvisual visMode; + + surface = (driSurface *) calloc(1, sizeof(*surface)); + if (!surface) { + return EGL_NO_SURFACE; + } + + /* init base class, do error checking, etc. */ + if (!_eglInitSurface(drv, dpy, &surface->Base, EGL_SCREEN_BIT_MESA, + cfg, attrib_list)) { + free(surface); + return EGL_NO_SURFACE; + } + + _eglSaveSurface(&surface->Base); + + + /* + * XXX this is where we should allocate video memory for the surface! + */ + + + /* convert EGLConfig to GLvisual */ + _eglConfigToContextModesRec(config, &visMode); + + /* Create a new DRI drawable */ + if (!disp->driScreen.createNewDrawable(disp, &visMode, surface->Base.Handle, + &surface->drawable, GLX_WINDOW_BIT, + empty_attribute_list)) { + _eglRemoveSurface(&surface->Base); + free(surface); + return EGL_NO_SURFACE; + } + + return surface->Base.Handle; +} + + +/** + * Set the fbdev colormap to a simple linear ramp. + */ +static void +_eglDRILoadColormap(driScreen *scrn) +{ + char path[ NAME_MAX ]; + char *buffer; + int i, fd; + + /* cmap attribute uses 256 lines of 16 bytes. + * Allocate one extra char for the \0 added by sprintf() + */ + if ( !( buffer = malloc( 256 * 16 + 1 ) ) ) { + _eglLog(_EGL_WARNING, "Out of memory in _eglDRILoadColormap"); + return; + } + + /* cmap attribute uses 256 lines of 16 bytes */ + for ( i = 0; i < 256; i++ ) { + int c = (i << 8) | i; /* expand to 16-bit value */ + sprintf(&buffer[i * 16], "%02x%c%04x%04x%04x\n", i, ' ', c, c, c); + } + + snprintf(path, sizeof(path), "%s/graphics/%s/color_map", sysfs, scrn->fb); + if ( !( fd = open( path, O_RDWR ) ) ) { + _eglLog(_EGL_WARNING, "Unable to open %s to set colormap", path); + return; + } + write( fd, buffer, 256 * 16 ); + close( fd ); + + free( buffer ); +} + + +/** + * Show the given surface on the named screen. + * If surface is EGL_NO_SURFACE, disable the screen's output. + * Called via eglShowSurfaceMESA(). + */ +EGLBoolean +_eglDRIShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, + EGLScreenMESA screen, + EGLSurface surface, EGLModeMESA m) +{ + driDisplay *display = Lookup_driDisplay(dpy); + driScreen *scrn = Lookup_driScreen(dpy, screen); + driSurface *surf = Lookup_driSurface(surface); + _EGLMode *mode = _eglLookupMode(dpy, m); + FILE *file; + char fname[NAME_MAX], buffer[1000]; + int temp; + + _eglLog(_EGL_DEBUG, "Enter _eglDRIShowScreenSurface"); + + /* This will check that surface, screen, and mode are valid. + * Also, it checks that the surface is large enough for the mode, etc. + */ + if (!_eglShowScreenSurfaceMESA(drv, dpy, screen, surface, m)) + return EGL_FALSE; + + assert(surface == EGL_NO_SURFACE || surf); + assert(m == EGL_NO_MODE_MESA || mode); + assert(scrn); + + /* + * Blank/unblank screen depending on if m == EGL_NO_MODE_MESA + */ + snprintf(fname, sizeof(fname), "%s/graphics/%s/blank", sysfs, scrn->fb); + file = fopen(fname, "r+"); + if (!file) { + _eglLog(_EGL_WARNING, "kernel patch?? chown all fb sysfs attrib to allow" + " write - %s\n", fname); + return EGL_FALSE; + } + snprintf(buffer, sizeof(buffer), "%d", + (m == EGL_NO_MODE_MESA ? VESA_POWERDOWN : VESA_VSYNC_SUSPEND)); + fputs(buffer, file); + fclose(file); + + if (m == EGL_NO_MODE_MESA) { + /* all done! */ + return EGL_TRUE; + } + + _eglLog(_EGL_INFO, "Setting display mode to %d x %d, %d bpp", + mode->Width, mode->Height, display->bpp); + + /* + * Set the display mode + */ + snprintf(fname, sizeof(fname), "%s/graphics/%s/mode", sysfs, scrn->fb); + file = fopen(fname, "r+"); + if (!file) { + _eglLog(_EGL_WARNING, "Failed to open %s to set mode", fname); + return EGL_FALSE; + } + /* note: nothing happens without the \n! */ + snprintf(buffer, sizeof(buffer), "%s\n", mode->Name); + fputs(buffer, file); + fclose(file); + _eglLog(_EGL_INFO, "Set mode to %s in %s", mode->Name, fname); + + /* + * Set display bpp + */ + snprintf(fname, sizeof(fname), "%s/graphics/%s/bits_per_pixel", + sysfs, scrn->fb); + file = fopen(fname, "r+"); + if (!file) { + _eglLog(_EGL_WARNING, "Failed to open %s to set bpp", fname); + return EGL_FALSE; + } + display->bpp = GET_CONFIG_ATTRIB(surf->Base.Config, EGL_BUFFER_SIZE); + display->cpp = display->bpp / 8; + snprintf(buffer, sizeof(buffer), "%d", display->bpp); + fputs(buffer, file); + fclose(file); + + /* + * Unblank display + */ + snprintf(fname, sizeof(fname), "%s/graphics/%s/blank", sysfs, scrn->fb); + file = fopen(fname, "r+"); + if (!file) { + _eglLog(_EGL_WARNING, "Failed to open %s", fname); + return EGL_FALSE; + } + snprintf(buffer, sizeof(buffer), "%d", VESA_NO_BLANKING); + fputs(buffer, file); + fclose(file); + + /* + * Set fbdev buffer virtual size to surface's size. + */ + snprintf(fname, sizeof(fname), "%s/graphics/%s/virtual_size", sysfs, scrn->fb); + file = fopen(fname, "r+"); + snprintf(buffer, sizeof(buffer), "%d,%d", surf->Base.Width, surf->Base.Height); + fputs(buffer, file); + rewind(file); + fgets(buffer, sizeof(buffer), file); + sscanf(buffer, "%d,%d", &display->virtualWidth, &display->virtualHeight); + fclose(file); + + /* + * round up pitch as needed + */ + temp = display->virtualWidth; + switch (display->bpp / 8) { + case 1: temp = (display->virtualWidth + 127) & ~127; break; + case 2: temp = (display->virtualWidth + 31) & ~31; break; + case 3: + case 4: temp = (display->virtualWidth + 15) & ~15; break; + default: + _eglLog(_EGL_WARNING, "Bad display->bpp = %d in _eglDRIShowScreenSurface"); + } + display->virtualWidth = temp; + + /* + * sanity check + */ + if (surf->Base.Width < display->virtualWidth || + surf->Base.Height < display->virtualHeight) { + /* this case _should_ have been caught at the top of this function */ + _eglLog(_EGL_WARNING, "too small of surface in _eglDRIShowScreenSurfaceMESA " + "%d x %d < %d x %d", + surf->Base.Width, + surf->Base.Height, + display->virtualWidth, + display->virtualHeight); + /* + return EGL_FALSE; + */ + } + + /* This used to be done in the _eglDRICreateScreens routine. */ + _eglDRILoadColormap(scrn); + + return EGL_TRUE; +} + + +/** + * Called by eglSwapBuffers via the drv->API.SwapBuffers() pointer. + * + * If the backbuffer is on a videocard, this is extraordinarily slow! + */ +static EGLBoolean +_eglDRISwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw) +{ + driSurface *drawable = Lookup_driSurface(draw); + + /* this does error checking */ + if (!_eglSwapBuffers(drv, dpy, draw)) + return EGL_FALSE; + + drawable->drawable.swapBuffers(NULL, drawable->drawable.private); + + return EGL_TRUE; +} + + +EGLBoolean +_eglDRIGetDisplayInfo(driDisplay *dpy) +{ + char path[ NAME_MAX ]; + FILE *file; + int i, rc; + drmSetVersion sv; + drm_magic_t magic; + + snprintf( path, sizeof( path ), "%s/graphics/fb%d/device/device", sysfs, dpy->minor ); + file = fopen( path, "r" ); + if (!file) { + _eglLog(_EGL_WARNING, "Unable to open %s", path); + return EGL_FALSE; + } + fgets( path, sizeof( path ), file ); + sscanf( path, "%x", &dpy->chipset ); + fclose( file ); + + sprintf(path, DRM_DEV_NAME, DRM_DIR_NAME, dpy->minor); + if ( ( dpy->drmFD = open(path, O_RDWR, 0) ) < 0 ) { + _eglLog(_EGL_WARNING, "drmOpen failed."); + return EGL_FALSE; + } + + /* Set the interface version, asking for 1.2 */ + sv.drm_di_major = 1; + sv.drm_di_minor = 2; + sv.drm_dd_major = -1; + if ((rc = drmSetInterfaceVersion(dpy->drmFD, &sv))) + return EGL_FALSE; + + /* self authorize */ + if (drmGetMagic(dpy->drmFD, &magic)) + return EGL_FALSE; + if (drmAuthMagic(dpy->drmFD, magic)) + return EGL_FALSE; + + /* Map framebuffer and SAREA */ + for (i = 0; ; i++) { + drm_handle_t handle, offset; + drmSize size; + drmMapType type; + drmMapFlags flags; + int mtrr; + + if (drmGetMap(dpy->drmFD, i, &offset, &size, &type, &flags, + &handle, &mtrr)) + break; + + if (type == DRM_FRAME_BUFFER) { + rc = drmMap( dpy->drmFD, offset, size, (drmAddressPtr) &dpy->pFB); + if (rc < 0) { + _eglLog(_EGL_WARNING, "drmMap DRM_FAME_BUFFER failed"); + return EGL_FALSE; + } + dpy->fbSize = size; + _eglLog(_EGL_INFO, "Found framebuffer size: %d", dpy->fbSize); + } + else if (type == DRM_SHM) { + rc = drmMap(dpy->drmFD, offset, size, (drmAddressPtr) &dpy->pSAREA); + if (rc < 0 ) { + _eglLog(_EGL_WARNING, "drmMap DRM_SHM failed."); + return EGL_FALSE; + } + dpy->SAREASize = SAREA_MAX; + _eglLog(_EGL_DEBUG, "mapped SAREA 0x%08lx to %p, size %d", + (unsigned long) offset, dpy->pSAREA, dpy->SAREASize ); + } + } + + if (!dpy->pFB) { + _eglLog(_EGL_WARNING, "failed to map framebuffer"); + return EGL_FALSE; + } + + if (!dpy->pSAREA) { + /* if this happens, make sure you're using the most recent DRM modules */ + _eglLog(_EGL_WARNING, "failed to map SAREA"); + return EGL_FALSE; + } + + memset( dpy->pSAREA, 0, dpy->SAREASize ); + + return EGL_TRUE; +} + + + /* Return the DRI per screen structure */ +static __DRIscreen * +__eglFindDRIScreen(__DRInativeDisplay *ndpy, int scrn) +{ + driDisplay *disp = (driDisplay *)ndpy; + return &disp->driScreen; +} + + +static GLboolean +__eglCreateContextWithConfig(__DRInativeDisplay* ndpy, int screen, + int configID, void* context, + drm_context_t * hHWContext) +{ + __DRIscreen *pDRIScreen; + __DRIscreenPrivate *psp; + + pDRIScreen = __eglFindDRIScreen(ndpy, screen); + if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { + return GL_FALSE; + } + psp = (__DRIscreenPrivate *) pDRIScreen->private; + if (psp->fd) { + if (drmCreateContext(psp->fd, hHWContext)) { + _eglLog(_EGL_WARNING, "drmCreateContext failed."); + return GL_FALSE; + } + *(void**)context = (void*) *hHWContext; + } +#if 0 + __DRIscreen *pDRIScreen; + __DRIscreenPrivate *psp; + + pDRIScreen = __glXFindDRIScreen(dpy, screen); + if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { + return GL_FALSE; + } + + psp = (__DRIscreenPrivate *) pDRIScreen->private; + + if (psp->fd) { + if (drmCreateContext(psp->fd, hHWContext)) { + _eglLog(_EGL_WARNING, "drmCreateContext failed."); + return GL_FALSE; + } + *(void**)contextID = (void*) *hHWContext; + } +#endif + return GL_TRUE; +} + + +static GLboolean +__eglDestroyContext( __DRInativeDisplay * ndpy, int screen, __DRIid context ) +{ + __DRIscreen *pDRIScreen; + __DRIscreenPrivate *psp; + + pDRIScreen = __eglFindDRIScreen(ndpy, screen); + if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { + return GL_FALSE; + } + psp = (__DRIscreenPrivate *) pDRIScreen->private; + if (psp->fd) + drmDestroyContext(psp->fd, context); + + return GL_TRUE; +} + + +static GLboolean +__eglCreateDrawable(__DRInativeDisplay * ndpy, int screen, + __DRIid drawable, drm_drawable_t * hHWDrawable) +{ + __DRIscreen *pDRIScreen; + __DRIscreenPrivate *psp; + + pDRIScreen = __eglFindDRIScreen(ndpy, screen); + if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { + return GL_FALSE; + } + psp = (__DRIscreenPrivate *) pDRIScreen->private; + if (psp->fd) { + if (drmCreateDrawable(psp->fd, hHWDrawable)) { + _eglLog(_EGL_WARNING, "drmCreateDrawable failed."); + return GL_FALSE; + } + } + return GL_TRUE; +} + + +static GLboolean +__eglDestroyDrawable( __DRInativeDisplay * ndpy, int screen, __DRIid drawable ) +{ + __DRIscreen *pDRIScreen; + __DRIscreenPrivate *psp; + + pDRIScreen = __eglFindDRIScreen(ndpy, screen); + if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { + return GL_FALSE; + } + psp = (__DRIscreenPrivate *) pDRIScreen->private; + if (psp->fd) + drmDestroyDrawable(psp->fd, drawable); + + return GL_TRUE; +} + +static GLboolean +__eglGetDrawableInfo(__DRInativeDisplay * ndpy, int screen, __DRIid drawable, + unsigned int* index, unsigned int* stamp, + int* X, int* Y, int* W, int* H, + int* numClipRects, drm_clip_rect_t ** pClipRects, + int* backX, int* backY, + int* numBackClipRects, drm_clip_rect_t ** pBackClipRects ) +{ + __DRIscreen *pDRIScreen; + __DRIscreenPrivate *psp; + driSurface *surf = Lookup_driSurface(drawable); + + pDRIScreen = __eglFindDRIScreen(ndpy, screen); + + if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { + return GL_FALSE; + } + psp = (__DRIscreenPrivate *) pDRIScreen->private; + *X = 0; + *Y = 0; + *W = surf->Base.Width; + *H = surf->Base.Height; + + *backX = 0; + *backY = 0; + *numBackClipRects = 0; + *pBackClipRects = NULL; + + *numClipRects = 1; + *pClipRects = malloc(sizeof(**pClipRects)); + **pClipRects = (drm_clip_rect_t){0, 0, surf->Base.Width, surf->Base.Height}; + + psp->pSAREA->drawableTable[0].stamp = 1; + *stamp = 1; +#if 0 + GLXDrawable drawable = (GLXDrawable) draw; + drm_clip_rect_t * cliprect; + Display* display = (Display*)dpy; + __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)CurrentContext->driContext.private; + if (drawable == 0) { + return GL_FALSE; + } + + cliprect = (drm_clip_rect_t*) _mesa_malloc(sizeof(drm_clip_rect_t)); + cliprect->x1 = drawable->x; + cliprect->y1 = drawable->y; + cliprect->x2 = drawable->x + drawable->w; + cliprect->y2 = drawable->y + drawable->h; + + /* the drawable index is by client id */ + *index = display->clientID; + + *stamp = pcp->driScreenPriv->pSAREA->drawableTable[display->clientID].stamp; + *x = drawable->x; + *y = drawable->y; + *width = drawable->w; + *height = drawable->h; + *numClipRects = 1; + *pClipRects = cliprect; + + *backX = drawable->x; + *backY = drawable->y; + *numBackClipRects = 0; + *pBackClipRects = 0; +#endif + return GL_TRUE; +} + + +/** + * Implement \c __DRIinterfaceMethods::getProcAddress. + */ +static __DRIfuncPtr +get_proc_address(const char * proc_name) +{ + return NULL; +} + + +/** + * Destroy a linked list of \c __GLcontextModes structures created by + * \c _gl_context_modes_create. + * + * \param modes Linked list of structures to be destroyed. All structres + * in the list will be freed. + */ +static void +__egl_context_modes_destroy(__GLcontextModes *modes) +{ + while ( modes != NULL ) { + __GLcontextModes * const next = modes->next; + + free( modes ); + modes = next; + } +} + + +/** + * Allocate a linked list of \c __GLcontextModes structures. The fields of + * each structure will be initialized to "reasonable" default values. In + * most cases this is the default value defined by table 3.4 of the GLX + * 1.3 specification. This means that most values are either initialized to + * zero or \c GLX_DONT_CARE (which is -1). As support for additional + * extensions is added, the new values will be initialized to appropriate + * values from the extension specification. + * + * \param count Number of structures to allocate. + * \param minimum_size Minimum size of a structure to allocate. This allows + * for differences in the version of the + * \c __GLcontextModes stucture used in libGL and in a + * DRI-based driver. + * \returns A pointer to the first element in a linked list of \c count + * stuctures on success, or \c NULL on failure. + * + * \warning Use of \c minimum_size does \b not guarantee binary compatibility. + * The fundamental assumption is that if the \c minimum_size + * specified by the driver and the size of the \c __GLcontextModes + * structure in libGL is the same, then the meaning of each byte in + * the structure is the same in both places. \b Be \b careful! + * Basically this means that fields have to be added in libGL and + * then propagated to drivers. Drivers should \b never arbitrarilly + * extend the \c __GLcontextModes data-structure. + */ +static __GLcontextModes * +__egl_context_modes_create(unsigned count, size_t minimum_size) +{ + const size_t size = (minimum_size > sizeof( __GLcontextModes )) + ? minimum_size : sizeof( __GLcontextModes ); + __GLcontextModes * base = NULL; + __GLcontextModes ** next; + unsigned i; + + next = & base; + for ( i = 0 ; i < count ; i++ ) { + *next = (__GLcontextModes *) malloc( size ); + if ( *next == NULL ) { + __egl_context_modes_destroy( base ); + base = NULL; + break; + } + + (void) memset( *next, 0, size ); + (*next)->visualID = GLX_DONT_CARE; + (*next)->visualType = GLX_DONT_CARE; + (*next)->visualRating = GLX_NONE; + (*next)->transparentPixel = GLX_NONE; + (*next)->transparentRed = GLX_DONT_CARE; + (*next)->transparentGreen = GLX_DONT_CARE; + (*next)->transparentBlue = GLX_DONT_CARE; + (*next)->transparentAlpha = GLX_DONT_CARE; + (*next)->transparentIndex = GLX_DONT_CARE; + (*next)->xRenderable = GLX_DONT_CARE; + (*next)->fbconfigID = GLX_DONT_CARE; + (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML; + + next = & ((*next)->next); + } + + return base; +} + + +static GLboolean +__eglWindowExists(__DRInativeDisplay *dpy, __DRIid draw) +{ + return EGL_TRUE; +} + + +/** + * Get the unadjusted system time (UST). Currently, the UST is measured in + * microseconds since Epoc. The actual resolution of the UST may vary from + * system to system, and the units may vary from release to release. + * Drivers should not call this function directly. They should instead use + * \c glXGetProcAddress to obtain a pointer to the function. + * + * \param ust Location to store the 64-bit UST + * \returns Zero on success or a negative errno value on failure. + * + * \sa glXGetProcAddress, PFNGLXGETUSTPROC + * + * \since Internal API version 20030317. + */ +static int +__eglGetUST(int64_t *ust) +{ + struct timeval tv; + + if ( ust == NULL ) { + return -EFAULT; + } + + if ( gettimeofday( & tv, NULL ) == 0 ) { + ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec; + return 0; + } + else { + return -errno; + } +} + +/** + * Determine the refresh rate of the specified drawable and display. + * + * \param dpy Display whose refresh rate is to be determined. + * \param drawable Drawable whose refresh rate is to be determined. + * \param numerator Numerator of the refresh rate. + * \param demoninator Denominator of the refresh rate. + * \return If the refresh rate for the specified display and drawable could + * be calculated, True is returned. Otherwise False is returned. + * + * \note This function is implemented entirely client-side. A lot of other + * functionality is required to export GLX_OML_sync_control, so on + * XFree86 this function can be called for direct-rendering contexts + * when GLX_OML_sync_control appears in the client extension string. + */ +static GLboolean +__eglGetMSCRate(__DRInativeDisplay * dpy, __DRIid drawable, + int32_t * numerator, int32_t * denominator) +{ + return EGL_TRUE; +} + + +/** + * Table of functions exported by the loader to the driver. + */ +static const __DRIinterfaceMethods interface_methods = { + get_proc_address, + + __egl_context_modes_create, + __egl_context_modes_destroy, + + __eglFindDRIScreen, + __eglWindowExists, + + __eglCreateContextWithConfig, + __eglDestroyContext, + + __eglCreateDrawable, + __eglDestroyDrawable, + __eglGetDrawableInfo, + + __eglGetUST, + __eglGetMSCRate, +}; + + +static int +__glXGetInternalVersion(void) +{ + return 20050725; +} + +static const char createNewScreenName[] = "__driCreateNewScreen_20050727"; + + +/** + * Do per-display initialization. + */ +EGLBoolean +_eglDRICreateDisplay(driDisplay *dpy, __DRIframebuffer *framebuffer) +{ + PFNCREATENEWSCREENFUNC createNewScreen; + int api_ver = __glXGetInternalVersion(); + __DRIversion ddx_version; + __DRIversion dri_version; + __DRIversion drm_version; + drmVersionPtr version; + + version = drmGetVersion( dpy->drmFD ); + if ( version ) { + drm_version.major = version->version_major; + drm_version.minor = version->version_minor; + drm_version.patch = version->version_patchlevel; + drmFreeVersion( version ); + } + else { + drm_version.major = -1; + drm_version.minor = -1; + drm_version.patch = -1; + } + + /* + * Get device name (like "tdfx") and the ddx version numbers. + * We'll check the version in each DRI driver's "createScreen" + * function. + */ + ddx_version.major = 4; + ddx_version.minor = 0; + ddx_version.patch = 0; + + /* + * Get the DRI X extension version. + */ + dri_version.major = 4; + dri_version.minor = 0; + dri_version.patch = 0; + + createNewScreen = ( PFNCREATENEWSCREENFUNC ) dlsym( dpy->Base.Driver->LibHandle, createNewScreenName ); + if ( !createNewScreen ) { + _eglLog(_EGL_WARNING, "Couldn't find %s function in the driver.", + createNewScreenName ); + return EGL_FALSE; + } + + dpy->driScreen.private = createNewScreen( dpy, 0, &dpy->driScreen, NULL, + &ddx_version, &dri_version, + &drm_version, framebuffer, + dpy->pSAREA, dpy->drmFD, + api_ver, + & interface_methods, + NULL); + if (!dpy->driScreen.private) + return EGL_FALSE; + + DRM_UNLOCK( dpy->drmFD, dpy->pSAREA, dpy->serverContext ); + + return EGL_TRUE; +} + + +/** + * Create all the EGL screens for the given display. + */ +EGLBoolean +_eglDRICreateScreens(driDisplay *dpy) +{ + const int numScreens = 1; /* XXX fix this someday */ + int i; + + for (i = 0; i < numScreens; i++) { + char path[ NAME_MAX ]; + FILE *file; + driScreen *s; + + /* Create a screen */ + if ( !( s = ( driScreen * ) calloc( 1, sizeof( *s ) ) ) ) + return EGL_FALSE; + + snprintf( s->fb, NAME_MAX, "fb%d", dpy->minor ); + _eglInitScreen( &s->Base ); + + _eglAddScreen( &dpy->Base, &s->Base ); + + /* Create the screen's mode list */ + snprintf( path, sizeof( path ), "%s/graphics/%s/modes", sysfs, s->fb ); + file = fopen( path, "r" ); + while ( fgets( path, sizeof( path ), file ) ) { + unsigned int x, y, r; + char c; + path[ strlen( path ) - 1 ] = '\0'; /* strip off \n from sysfs */ + sscanf( path, "%c:%ux%u-%u", &c, &x, &y, &r ); + _eglAddNewMode( &s->Base, x, y, r * 1000, path ); + } + fclose( file ); + + /* + * NOTE: we used to set the colormap here, but that didn't work reliably. + * Some entries near the start of the table would get corrupted by later + * mode changes. + */ + } + + return EGL_TRUE; +} + + +EGLBoolean +_eglDRIInitialize(_EGLDriver *drv, EGLDisplay dpy, + EGLint *major, EGLint *minor) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + driDisplay *display; + + assert(disp); + + /* Create new driDisplay object to replace the _EGLDisplay that was + * previously created. + */ + display = calloc(1, sizeof(*display)); + display->Base = *disp; + _eglHashInsert(_eglGlobal.Displays, disp->Handle, display); + free(disp); + + *major = 1; + *minor = 0; + + sscanf(&disp->Name[1], "%d", &display->minor); + + drv->Initialized = EGL_TRUE; + return EGL_TRUE; +} + + +static EGLBoolean +_eglDRITerminate(_EGLDriver *drv, EGLDisplay dpy) +{ + driDisplay *display = Lookup_driDisplay(dpy); + _eglCleanupDisplay(&display->Base);/*rename that function*/ + free(display); + free(drv); + return EGL_TRUE; +} + + +/** + * Plug in the DRI-specific functions into the driver's dispatch table. + * Also, enable some EGL extensions. + */ +void +_eglDRIInitDriverFallbacks(_EGLDriver *drv) +{ + _eglInitDriverFallbacks(drv); + + drv->API.Initialize = _eglDRIInitialize; + drv->API.Terminate = _eglDRITerminate; + drv->API.CreateContext = _eglDRICreateContext; + drv->API.MakeCurrent = _eglDRIMakeCurrent; + drv->API.CreatePbufferSurface = _eglDRICreatePbufferSurface; + drv->API.DestroySurface = _eglDRIDestroySurface; + drv->API.DestroyContext = _eglDRIDestroyContext; + drv->API.CreateScreenSurfaceMESA = _eglDRICreateScreenSurfaceMESA; + drv->API.ShowScreenSurfaceMESA = _eglDRIShowScreenSurfaceMESA; + drv->API.SwapBuffers = _eglDRISwapBuffers; + + /* enable supported extensions */ + drv->Extensions.MESA_screen_surface = EGL_TRUE; + drv->Extensions.MESA_copy_context = EGL_TRUE; +} diff --git a/src/egl/drivers/dri/egldri.h b/src/egl/drivers/dri/egldri.h new file mode 100644 index 00000000000..34b12d64fcd --- /dev/null +++ b/src/egl/drivers/dri/egldri.h @@ -0,0 +1,113 @@ +#ifndef EGLDRI_INCLUDED +#define EGLDRI_INCLUDED + +#include "egldisplay.h" +#include "eglscreen.h" +#include "eglsurface.h" +#include "eglcontext.h" +#include "mtypes.h" +#include "dri_util.h" +#include "drm_sarea.h" + +/** + * dri display-specific driver class derived from _EGLDisplay + */ +typedef struct dri_display +{ + _EGLDisplay Base; /* base class/object */ + void *pFB; + int drmFD; /**< \brief DRM device file descriptor */ + int minor; + unsigned long hFrameBuffer; + + int virtualWidth; + int virtualHeight; + int fbSize; + int bpp; + int cpp; + int card_type; + int SAREASize; + drm_sarea_t *pSAREA; + unsigned int serverContext; /**< \brief DRM context only active on server */ + unsigned long FBStart; /**< \brief physical address of the framebuffer */ + void *driverClientMsg; + int driverClientMsgSize; + int chipset; + void *driverPrivate; + drm_magic_t magic; + + __DRIscreen driScreen; + +} driDisplay; + + +/** + * dri driver-specific screen class derived from _EGLScreen + */ +typedef struct dri_screen +{ + _EGLScreen Base; + char fb[NAME_MAX]; /** the screen name, like "fb0" */ +} driScreen; + + +/** + * dri driver-specific surface class derived from _EGLSurface + */ +typedef struct dri_surface +{ + _EGLSurface Base; /* base class/object */ + __DRIdrawable drawable; +} driSurface; + + +/** + * dri driver-specific context class derived from _EGLContext + */ +typedef struct dri_context +{ + _EGLContext Base; /* base class/object */ + __DRIcontext driContext; /**< \brief context dependent methods */ +} driContext; + + + +static inline driDisplay * +Lookup_driDisplay(EGLDisplay dpy) +{ + _EGLDisplay *d = _eglLookupDisplay(dpy); + return (driDisplay *) d; +} + + +static inline driScreen * +Lookup_driScreen(EGLDisplay dpy, EGLScreenMESA screen) +{ + _EGLScreen *s = _eglLookupScreen(dpy, screen); + return (driScreen *) s; +} + + +static inline driContext * +Lookup_driContext(EGLContext ctx) +{ + _EGLContext *c = _eglLookupContext(ctx); + return (driContext *) c; +} + + +static inline driSurface * +Lookup_driSurface(EGLSurface surf) +{ + _EGLSurface *s = _eglLookupSurface(surf); + return (driSurface *) s; +} + +extern void _eglDRIInitDriverFallbacks(_EGLDriver *drv); +extern EGLBoolean _eglDRIShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLSurface surface, EGLModeMESA m); +extern EGLBoolean _eglDRIInitialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor); +extern EGLBoolean _eglDRIGetDisplayInfo(driDisplay *dpy); +extern EGLBoolean _eglDRICreateDisplay(driDisplay *dpy, __DRIframebuffer *framebuffer); +extern EGLBoolean _eglDRICreateScreens(driDisplay *dpy); + +#endif /* EGLDRI_INCLUDED */ diff --git a/src/egl/main/Makefile b/src/egl/main/Makefile new file mode 100644 index 00000000000..45a4fb39b8b --- /dev/null +++ b/src/egl/main/Makefile @@ -0,0 +1,66 @@ +# src/egl/main/Makefile + +TOP = ../../.. +include $(TOP)/configs/current + + +INCLUDE_DIRS = -I$(TOP)/include -I$(TOP)/src/mesa/glapi + +HEADERS = \ + eglconfig.h \ + eglcontext.h \ + egldisplay.h \ + egldriver.h \ + eglglobals.h \ + egllog.h \ + eglhash.h \ + eglmode.h \ + eglscreen.h \ + eglsurface.h + +SOURCES = \ + eglapi.c \ + eglconfig.c \ + eglcontext.c \ + egldisplay.c \ + egldriver.c \ + eglglobals.c \ + egllog.c \ + eglhash.c \ + eglmode.c \ + eglscreen.c \ + eglsurface.c + +OBJECTS = $(SOURCES:.c=.o) + + +.c.o: + $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@ + + + +default: depend library + + +# EGL Library +library: $(LIB_DIR)/libEGL.so + +$(LIB_DIR)/libEGL.so: $(OBJECTS) + $(TOP)/bin/mklib -o EGL -major 1 -minor 0 \ + -install $(LIB_DIR) -ldl $(OBJECTS) + + + +clean: + rm -f *.o *.so* + rm -f core.* + + +depend: $(SOURCES) $(HEADERS) + @ echo "running $(MKDEP)" + @ touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) \ + $(SOURCES) $(HEADERS) > /dev/null + +include depend +# DO NOT DELETE diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c new file mode 100644 index 00000000000..bfa580e6c3f --- /dev/null +++ b/src/egl/main/eglapi.c @@ -0,0 +1,586 @@ +/** + * Public EGL API entrypoints + * + * Generally, we use the EGLDisplay parameter as a key to lookup the + * appropriate device driver handle, then jump though the driver's + * dispatch table to handle the function. + * + * That allows us the option of supporting multiple, simultaneous, + * heterogeneous hardware devices in the future. + * + * The EGLDisplay, EGLConfig, EGLContext and EGLSurface types are + * opaque handles implemented with 32-bit unsigned integers. + * It's up to the driver function or fallback function to look up the + * handle and get an object. + * By using opaque handles, we leave open the possibility of having + * indirect rendering in the future, like GLX. + * + * + * Notes on naming conventions: + * + * eglFooBar - public EGL function + * EGL_FOO_BAR - public EGL token + * EGLDatatype - public EGL datatype + * + * _eglFooBar - private EGL function + * _EGLDatatype - private EGL datatype, typedef'd struct + * _egl_struct - private EGL struct, non-typedef'd + * + */ + + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "eglcontext.h" +#include "egldisplay.h" +#include "egltypedefs.h" +#include "eglglobals.h" +#include "egldriver.h" +#include "eglsurface.h" + + + +/** + * NOTE: displayName is treated as a string in _eglChooseDriver()!!! + * This will probably change! + * See _eglChooseDriver() for details! + */ +EGLDisplay APIENTRY +eglGetDisplay(NativeDisplayType displayName) +{ + _EGLDisplay *dpy; + _eglInitGlobals(); + dpy = _eglNewDisplay(displayName); + if (dpy) + return dpy->Handle; + else + return EGL_NO_DISPLAY; +} + + +EGLBoolean APIENTRY +eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + if (dpy) { + _EGLDriver *drv = _eglChooseDriver(dpy); + if (drv) + return drv->API.Initialize(drv, dpy, major, minor); + } + return EGL_FALSE; +} + + +EGLBoolean APIENTRY +eglTerminate(EGLDisplay dpy) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + if (drv) + return _eglCloseDriver(drv, dpy); + else + return EGL_FALSE; +} + + +const char * APIENTRY +eglQueryString(EGLDisplay dpy, EGLint name) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + if (drv) + return drv->API.QueryString(drv, dpy, name); + else + return NULL; +} + + +EGLBoolean APIENTRY +eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + /* XXX check drv for null in remaining functions */ + return drv->API.GetConfigs(drv, dpy, configs, config_size, num_config); +} + + +EGLBoolean APIENTRY +eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.ChooseConfig(drv, dpy, attrib_list, configs, config_size, num_config); +} + + +EGLBoolean APIENTRY +eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.GetConfigAttrib(drv, dpy, config, attribute, value); +} + + +EGLContext APIENTRY +eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.CreateContext(drv, dpy, config, share_list, attrib_list); +} + + +EGLBoolean APIENTRY +eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.DestroyContext(drv, dpy, ctx); +} + + +EGLBoolean APIENTRY +eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.MakeCurrent(drv, dpy, draw, read, ctx); +} + + +EGLBoolean APIENTRY +eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.QueryContext(drv, dpy, ctx, attribute, value); +} + + +EGLSurface APIENTRY +eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.CreateWindowSurface(drv, dpy, config, window, attrib_list); +} + + +EGLSurface APIENTRY +eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.CreatePixmapSurface(drv, dpy, config, pixmap, attrib_list); +} + + +EGLSurface APIENTRY +eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.CreatePbufferSurface(drv, dpy, config, attrib_list); +} + + +EGLBoolean APIENTRY +eglDestroySurface(EGLDisplay dpy, EGLSurface surface) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.DestroySurface(drv, dpy, surface); +} + + +EGLBoolean APIENTRY +eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.QuerySurface(drv, dpy, surface, attribute, value); +} + + +EGLBoolean APIENTRY +eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.SurfaceAttrib(drv, dpy, surface, attribute, value); +} + + +EGLBoolean APIENTRY +eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.BindTexImage(drv, dpy, surface, buffer); +} + + +EGLBoolean APIENTRY +eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.ReleaseTexImage(drv, dpy, surface, buffer); +} + + +EGLBoolean APIENTRY +eglSwapInterval(EGLDisplay dpy, EGLint interval) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.SwapInterval(drv, dpy, interval); +} + + +EGLBoolean APIENTRY +eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.SwapBuffers(drv, dpy, draw); +} + + +EGLBoolean APIENTRY +eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, NativePixmapType target) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.CopyBuffers(drv, dpy, surface, target); +} + + +EGLBoolean APIENTRY +eglWaitGL(void) +{ + EGLDisplay dpy = eglGetCurrentDisplay(); + if (dpy != EGL_NO_DISPLAY) { + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.WaitGL(drv, dpy); + } + else + return EGL_FALSE; +} + + +EGLBoolean APIENTRY +eglWaitNative(EGLint engine) +{ + EGLDisplay dpy = eglGetCurrentDisplay(); + if (dpy != EGL_NO_DISPLAY) { + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.WaitNative(drv, dpy, engine); + } + else + return EGL_FALSE; +} + + +EGLDisplay APIENTRY +eglGetCurrentDisplay(void) +{ + _EGLDisplay *dpy = _eglGetCurrentDisplay(); + if (dpy) + return dpy->Handle; + else + return EGL_NO_DISPLAY; +} + + +EGLContext APIENTRY +eglGetCurrentContext(void) +{ + _EGLContext *ctx = _eglGetCurrentContext(); + if (ctx) + return ctx->Handle; + else + return EGL_NO_CONTEXT; +} + + +EGLSurface APIENTRY +eglGetCurrentSurface(EGLint readdraw) +{ + _EGLSurface *s = _eglGetCurrentSurface(readdraw); + if (s) + return s->Handle; + else + return EGL_NO_SURFACE; +} + + +EGLint APIENTRY +eglGetError(void) +{ + _EGLThreadInfo *t = _eglGetCurrentThread(); + EGLint e = t->LastError; + t->LastError = EGL_SUCCESS; + return e; +} + + +void (* APIENTRY eglGetProcAddress(const char *procname))() +{ + typedef void (*genericFunc)(); + struct name_function { + const char *name; + _EGLProc function; + }; + static struct name_function egl_functions[] = { + /* alphabetical order */ + { "eglBindTexImage", (_EGLProc) eglBindTexImage }, + { "eglChooseConfig", (_EGLProc) eglChooseConfig }, + { "eglCopyBuffers", (_EGLProc) eglCopyBuffers }, + { "eglCreateContext", (_EGLProc) eglCreateContext }, + { "eglCreatePbufferSurface", (_EGLProc) eglCreatePbufferSurface }, + { "eglCreatePixmapSurface", (_EGLProc) eglCreatePixmapSurface }, + { "eglCreateWindowSurface", (_EGLProc) eglCreateWindowSurface }, + { "eglDestroyContext", (_EGLProc) eglDestroyContext }, + { "eglDestroySurface", (_EGLProc) eglDestroySurface }, + { "eglGetConfigAttrib", (_EGLProc) eglGetConfigAttrib }, + { "eglGetConfigs", (_EGLProc) eglGetConfigs }, + { "eglGetCurrentContext", (_EGLProc) eglGetCurrentContext }, + { "eglGetCurrentDisplay", (_EGLProc) eglGetCurrentDisplay }, + { "eglGetCurrentSurface", (_EGLProc) eglGetCurrentSurface }, + { "eglGetDisplay", (_EGLProc) eglGetDisplay }, + { "eglGetError", (_EGLProc) eglGetError }, + { "eglGetProcAddress", (_EGLProc) eglGetProcAddress }, + { "eglInitialize", (_EGLProc) eglInitialize }, + { "eglMakeCurrent", (_EGLProc) eglMakeCurrent }, + { "eglQueryContext", (_EGLProc) eglQueryContext }, + { "eglQueryString", (_EGLProc) eglQueryString }, + { "eglQuerySurface", (_EGLProc) eglQuerySurface }, + { "eglReleaseTexImage", (_EGLProc) eglReleaseTexImage }, + { "eglSurfaceAttrib", (_EGLProc) eglSurfaceAttrib }, + { "eglSwapBuffers", (_EGLProc) eglSwapBuffers }, + { "eglSwapInterval", (_EGLProc) eglSwapInterval }, + { "eglTerminate", (_EGLProc) eglTerminate }, + { "eglWaitGL", (_EGLProc) eglWaitGL }, + { "eglWaitNative", (_EGLProc) eglWaitNative }, + /* Extensions */ +#ifdef EGL_MESA_screen_surface + { "eglChooseModeMESA", (_EGLProc) eglChooseModeMESA }, + { "eglGetModesMESA", (_EGLProc) eglGetModesMESA }, + { "eglGetModeAttribMESA", (_EGLProc) eglGetModeAttribMESA }, + { "eglCopyContextMESA", (_EGLProc) eglCopyContextMESA }, + { "eglGetScreensMESA", (_EGLProc) eglGetScreensMESA }, + { "eglCreateScreenSurfaceMESA", (_EGLProc) eglCreateScreenSurfaceMESA }, + { "eglShowScreenSurfaceMESA", (_EGLProc) eglShowScreenSurfaceMESA }, + { "eglScreenPositionMESA", (_EGLProc) eglScreenPositionMESA }, + { "eglQueryScreenMESA", (_EGLProc) eglQueryScreenMESA }, + { "eglQueryScreenSurfaceMESA", (_EGLProc) eglQueryScreenSurfaceMESA }, + { "eglQueryScreenModeMESA", (_EGLProc) eglQueryScreenModeMESA }, + { "eglQueryModeStringMESA", (_EGLProc) eglQueryModeStringMESA }, +#endif /* EGL_MESA_screen_surface */ +#ifdef EGL_VERSION_1_2 + { "eglBindAPI", (_EGLProc) eglBindAPI }, + { "eglCreatePbufferFromClientBuffer", (_EGLProc) eglCreatePbufferFromClientBuffer }, + { "eglQueryAPI", (_EGLProc) eglQueryAPI }, + { "eglReleaseThread", (_EGLProc) eglReleaseThread }, + { "eglWaitClient", (_EGLProc) eglWaitClient }, +#endif /* EGL_VERSION_1_2 */ + { NULL, NULL } + }; + EGLint i; + for (i = 0; egl_functions[i].name; i++) { + if (strcmp(egl_functions[i].name, procname) == 0) { + return (genericFunc) egl_functions[i].function; + } + } +#if 0 + /* XXX enable this code someday */ + return (genericFunc) _glapi_get_proc_address(procname); +#else + return NULL; +#endif +} + + +/* + * EGL_MESA_screen extension + */ + +EGLBoolean APIENTRY +eglChooseModeMESA(EGLDisplay dpy, EGLScreenMESA screen, + const EGLint *attrib_list, EGLModeMESA *modes, + EGLint modes_size, EGLint *num_modes) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + if (drv) + return drv->API.ChooseModeMESA(drv, dpy, screen, attrib_list, modes, modes_size, num_modes); + else + return EGL_FALSE; +} + + +EGLBoolean APIENTRY +eglGetModesMESA(EGLDisplay dpy, EGLScreenMESA screen, EGLModeMESA *modes, EGLint mode_size, EGLint *num_mode) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + if (drv) + return drv->API.GetModesMESA(drv, dpy, screen, modes, mode_size, num_mode); + else + return EGL_FALSE; +} + + +EGLBoolean APIENTRY +eglGetModeAttribMESA(EGLDisplay dpy, EGLModeMESA mode, EGLint attribute, EGLint *value) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + if (drv) + return drv->API.GetModeAttribMESA(drv, dpy, mode, attribute, value); + else + return EGL_FALSE; +} + + +EGLBoolean APIENTRY +eglCopyContextMESA(EGLDisplay dpy, EGLContext source, EGLContext dest, EGLint mask) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + if (drv) + return drv->API.CopyContextMESA(drv, dpy, source, dest, mask); + else + return EGL_FALSE; +} + + +EGLBoolean +eglGetScreensMESA(EGLDisplay dpy, EGLScreenMESA *screens, EGLint max_screens, EGLint *num_screens) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + if (drv) + return drv->API.GetScreensMESA(drv, dpy, screens, max_screens, num_screens); + else + return EGL_FALSE; +} + + +EGLSurface +eglCreateScreenSurfaceMESA(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.CreateScreenSurfaceMESA(drv, dpy, config, attrib_list); +} + + +EGLBoolean +eglShowScreenSurfaceMESA(EGLDisplay dpy, EGLint screen, EGLSurface surface, EGLModeMESA mode) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.ShowScreenSurfaceMESA(drv, dpy, screen, surface, mode); +} + + +EGLBoolean +eglScreenPositionMESA(EGLDisplay dpy, EGLScreenMESA screen, EGLint x, EGLint y) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.ScreenPositionMESA(drv, dpy, screen, x, y); +} + + +EGLBoolean +eglQueryScreenMESA( EGLDisplay dpy, EGLScreenMESA screen, EGLint attribute, EGLint *value) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.QueryScreenMESA(drv, dpy, screen, attribute, value); +} + + +EGLBoolean +eglQueryScreenSurfaceMESA(EGLDisplay dpy, EGLScreenMESA screen, EGLSurface *surface) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.QueryScreenSurfaceMESA(drv, dpy, screen, surface); +} + + +EGLBoolean +eglQueryScreenModeMESA(EGLDisplay dpy, EGLScreenMESA screen, EGLModeMESA *mode) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.QueryScreenModeMESA(drv, dpy, screen, mode); +} + + +const char * +eglQueryModeStringMESA(EGLDisplay dpy, EGLModeMESA mode) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.QueryModeStringMESA(drv, dpy, mode); +} + + +/** + ** EGL 1.2 + **/ + +#ifdef EGL_VERSION_1_2 + +EGLBoolean +eglBindAPI(EGLenum api) +{ + _EGLThreadInfo *t = _eglGetCurrentThread(); + + switch (api) { + case EGL_OPENGL_ES_API: + if (_eglGlobal.OpenGLESAPISupported) { + t->CurrentAPI = api; + return EGL_TRUE; + } + _eglError(EGL_BAD_PARAMETER, "eglBindAPI"); + return EGL_FALSE; + case EGL_OPENVG_API: + if (_eglGlobal.OpenVGAPISupported) { + t->CurrentAPI = api; + return EGL_TRUE; + } + _eglError(EGL_BAD_PARAMETER, "eglBindAPI"); + return EGL_FALSE; + default: + return EGL_FALSE; + } + return EGL_TRUE; +} + + +EGLSurface +eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, + EGLClientBuffer buffer, EGLConfig config, + const EGLint *attrib_list) +{ + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.CreatePbufferFromClientBuffer(drv, dpy, buftype, buffer, + config, attrib_list); +} + + +EGLenum +eglQueryAPI(void) +{ + /* returns one of EGL_OPENGL_ES_API or EGL_OPENVG_API */ + _EGLThreadInfo *t = _eglGetCurrentThread(); + return t->CurrentAPI; +} + + +EGLBoolean +eglReleaseThread(void) +{ + _EGLThreadInfo *t = _eglGetCurrentThread(); + EGLDisplay dpy = eglGetCurrentDisplay(); + if (dpy) { + _EGLDriver *drv = _eglLookupDriver(dpy); + /* unbind context */ + (void) drv->API.MakeCurrent(drv, dpy, EGL_NO_SURFACE, + EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + _eglDeleteThreadData(t); + return EGL_TRUE; +} + + +EGLBoolean +eglWaitClient(void) +{ + EGLDisplay dpy = eglGetCurrentDisplay(); + if (dpy != EGL_NO_DISPLAY) { + _EGLDriver *drv = _eglLookupDriver(dpy); + return drv->API.WaitClient(drv, dpy); + } + else + return EGL_FALSE; +} + +#endif /* EGL_VERSION_1_2 */ diff --git a/src/egl/main/eglapi.h b/src/egl/main/eglapi.h new file mode 100644 index 00000000000..555aa5dd9ef --- /dev/null +++ b/src/egl/main/eglapi.h @@ -0,0 +1,119 @@ +#ifndef EGLAPI_INCLUDED +#define EGLAPI_INCLUDED + +/** + * Typedefs for all EGL API entrypoint functions. + */ + + +/* driver funcs */ +typedef EGLBoolean (*Initialize_t)(_EGLDriver *, EGLDisplay dpy, EGLint *major, EGLint *minor); +typedef EGLBoolean (*Terminate_t)(_EGLDriver *, EGLDisplay dpy); + +/* config funcs */ +typedef EGLBoolean (*GetConfigs_t)(_EGLDriver *drv, EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); +typedef EGLBoolean (*ChooseConfig_t)(_EGLDriver *drv, EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); +typedef EGLBoolean (*GetConfigAttrib_t)(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); + +/* context funcs */ +typedef EGLContext (*CreateContext_t)(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list); +typedef EGLBoolean (*DestroyContext_t)(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx); +typedef EGLBoolean (*MakeCurrent_t)(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); +typedef EGLBoolean (*QueryContext_t)(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value); + +/* surface funcs */ +typedef EGLSurface (*CreateWindowSurface_t)(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list); +typedef EGLSurface (*CreatePixmapSurface_t)(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list); +typedef EGLSurface (*CreatePbufferSurface_t)(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); +typedef EGLBoolean (*DestroySurface_t)(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface); +typedef EGLBoolean (*QuerySurface_t)(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); +typedef EGLBoolean (*SurfaceAttrib_t)(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value); +typedef EGLBoolean (*BindTexImage_t)(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, EGLint buffer); +typedef EGLBoolean (*ReleaseTexImage_t)(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, EGLint buffer); +typedef EGLBoolean (*SwapInterval_t)(_EGLDriver *drv, EGLDisplay dpy, EGLint interval); +typedef EGLBoolean (*SwapBuffers_t)(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw); +typedef EGLBoolean (*CopyBuffers_t)(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, NativePixmapType target); + +/* misc funcs */ +typedef const char *(*QueryString_t)(_EGLDriver *drv, EGLDisplay dpy, EGLint name); +typedef EGLBoolean (*WaitGL_t)(_EGLDriver *drv, EGLDisplay dpy); +typedef EGLBoolean (*WaitNative_t)(_EGLDriver *drv, EGLDisplay dpy, EGLint engine); + + +#ifdef EGL_MESA_screen_surface +typedef EGLBoolean (*ChooseModeMESA_t)(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, const EGLint *attrib_list, EGLModeMESA *modes, EGLint modes_size, EGLint *num_modes); +typedef EGLBoolean (*GetModesMESA_t)(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLModeMESA *modes, EGLint mode_size, EGLint *num_mode); +typedef EGLBoolean (*GetModeAttribMESA_t)(_EGLDriver *drv, EGLDisplay dpy, EGLModeMESA mode, EGLint attribute, EGLint *value); +typedef EGLBoolean (*CopyContextMESA_t)(_EGLDriver *drv, EGLDisplay dpy, EGLContext source, EGLContext dest, EGLint mask); +typedef EGLBoolean (*GetScreensMESA_t)(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA *screens, EGLint max_screens, EGLint *num_screens); +typedef EGLSurface (*CreateScreenSurfaceMESA_t)(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); +typedef EGLBoolean (*ShowScreenSurfaceMESA_t)(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLSurface surface, EGLModeMESA mode); +typedef EGLBoolean (*ScreenPositionMESA_t)(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLint x, EGLint y); +typedef EGLBoolean (*QueryScreenMESA_t)(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLint attribute, EGLint *value); +typedef EGLBoolean (*QueryScreenSurfaceMESA_t)(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLSurface *surface); +typedef EGLBoolean (*QueryScreenModeMESA_t)(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLModeMESA *mode); +typedef const char * (*QueryModeStringMESA_t)(_EGLDriver *drv, EGLDisplay dpy, EGLModeMESA mode); +#endif /* EGL_MESA_screen_surface */ + + +#ifdef EGL_VERSION_1_2 +typedef EGLBoolean (*WaitClient_t)(_EGLDriver *drv, EGLDisplay dpy); +typedef EGLSurface (*CreatePbufferFromClientBuffer_t)(_EGLDriver *drv, EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list); +#endif /* EGL_VERSION_1_2 */ + + + +/** + * The API dispatcher jumps through these functions + */ +struct _egl_api +{ + Initialize_t Initialize; + Terminate_t Terminate; + + GetConfigs_t GetConfigs; + ChooseConfig_t ChooseConfig; + GetConfigAttrib_t GetConfigAttrib; + + CreateContext_t CreateContext; + DestroyContext_t DestroyContext; + MakeCurrent_t MakeCurrent; + QueryContext_t QueryContext; + + CreateWindowSurface_t CreateWindowSurface; + CreatePixmapSurface_t CreatePixmapSurface; + CreatePbufferSurface_t CreatePbufferSurface; + DestroySurface_t DestroySurface; + QuerySurface_t QuerySurface; + SurfaceAttrib_t SurfaceAttrib; + BindTexImage_t BindTexImage; + ReleaseTexImage_t ReleaseTexImage; + SwapInterval_t SwapInterval; + SwapBuffers_t SwapBuffers; + CopyBuffers_t CopyBuffers; + + QueryString_t QueryString; + WaitGL_t WaitGL; + WaitNative_t WaitNative; + + /* EGL_MESA_screen extension */ + ChooseModeMESA_t ChooseModeMESA; + GetModesMESA_t GetModesMESA; + GetModeAttribMESA_t GetModeAttribMESA; + CopyContextMESA_t CopyContextMESA; + GetScreensMESA_t GetScreensMESA; + CreateScreenSurfaceMESA_t CreateScreenSurfaceMESA; + ShowScreenSurfaceMESA_t ShowScreenSurfaceMESA; + ScreenPositionMESA_t ScreenPositionMESA; + QueryScreenMESA_t QueryScreenMESA; + QueryScreenSurfaceMESA_t QueryScreenSurfaceMESA; + QueryScreenModeMESA_t QueryScreenModeMESA; + QueryModeStringMESA_t QueryModeStringMESA; + +#ifdef EGL_VERSION_1_2 + WaitClient_t WaitClient; + CreatePbufferFromClientBuffer_t CreatePbufferFromClientBuffer; +#endif +}; + +#endif /* EGLAPI_INCLUDED */ diff --git a/src/egl/main/eglconfig.c b/src/egl/main/eglconfig.c new file mode 100644 index 00000000000..c180e30d7fa --- /dev/null +++ b/src/egl/main/eglconfig.c @@ -0,0 +1,638 @@ +/** + * EGL Configuration (pixel format) functions. + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include "eglconfig.h" +#include "egldisplay.h" +#include "egldriver.h" +#include "eglglobals.h" +#include "egllog.h" + + +#define MIN2(A, B) (((A) < (B)) ? (A) : (B)) + + +/** + * Convert an _EGLConfig to a __GLcontextModes object. + * NOTE: This routine may be incomplete - we're only making sure that + * the fields needed by Mesa (for _mesa_create_context/framebuffer) are + * set correctly. + */ +void +_eglConfigToContextModesRec(const _EGLConfig *config, __GLcontextModes *mode) +{ + memset(mode, 0, sizeof(*mode)); + + mode->rgbMode = GL_TRUE; /* no color index */ + mode->colorIndexMode = GL_FALSE; + mode->doubleBufferMode = GL_TRUE; /* always DB for now */ + mode->stereoMode = GL_FALSE; + + mode->redBits = GET_CONFIG_ATTRIB(config, EGL_RED_SIZE); + mode->greenBits = GET_CONFIG_ATTRIB(config, EGL_GREEN_SIZE); + mode->blueBits = GET_CONFIG_ATTRIB(config, EGL_BLUE_SIZE); + mode->alphaBits = GET_CONFIG_ATTRIB(config, EGL_ALPHA_SIZE); + mode->rgbBits = GET_CONFIG_ATTRIB(config, EGL_BUFFER_SIZE); + + /* no rgba masks - fix? */ + + mode->depthBits = GET_CONFIG_ATTRIB(config, EGL_DEPTH_SIZE); + mode->haveDepthBuffer = mode->depthBits > 0; + + mode->stencilBits = GET_CONFIG_ATTRIB(config, EGL_STENCIL_SIZE); + mode->haveStencilBuffer = mode->stencilBits > 0; + + /* no accum */ + + mode->level = GET_CONFIG_ATTRIB(config, EGL_LEVEL); + mode->samples = GET_CONFIG_ATTRIB(config, EGL_SAMPLES); + mode->sampleBuffers = GET_CONFIG_ATTRIB(config, EGL_SAMPLE_BUFFERS); + + /* surface type - not really needed */ + mode->visualType = GLX_TRUE_COLOR; + mode->renderType = GLX_RGBA_BIT; +} + + +void +_eglSetConfigAttrib(_EGLConfig *config, EGLint attr, EGLint val) +{ + assert(attr >= FIRST_ATTRIB); + assert(attr < FIRST_ATTRIB + MAX_ATTRIBS); + config->Attrib[attr - FIRST_ATTRIB] = val; +} + + +/** + * Init the given _EGLconfig to default values. + * \param id the configuration's ID. + */ +void +_eglInitConfig(_EGLConfig *config, EGLint id) +{ + memset(config, 0, sizeof(*config)); + config->Handle = id; + _eglSetConfigAttrib(config, EGL_CONFIG_ID, id); + _eglSetConfigAttrib(config, EGL_BIND_TO_TEXTURE_RGB, EGL_DONT_CARE); + _eglSetConfigAttrib(config, EGL_BIND_TO_TEXTURE_RGBA, EGL_DONT_CARE); + _eglSetConfigAttrib(config, EGL_CONFIG_CAVEAT, EGL_DONT_CARE); + _eglSetConfigAttrib(config, EGL_NATIVE_RENDERABLE, EGL_DONT_CARE); + _eglSetConfigAttrib(config, EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE); + _eglSetConfigAttrib(config, EGL_MIN_SWAP_INTERVAL, EGL_DONT_CARE); + _eglSetConfigAttrib(config, EGL_MAX_SWAP_INTERVAL, EGL_DONT_CARE); + _eglSetConfigAttrib(config, EGL_SURFACE_TYPE, + EGL_SCREEN_BIT_MESA | EGL_PBUFFER_BIT | + EGL_PIXMAP_BIT | EGL_WINDOW_BIT); + _eglSetConfigAttrib(config, EGL_TRANSPARENT_TYPE, EGL_NONE); + _eglSetConfigAttrib(config, EGL_TRANSPARENT_RED_VALUE, EGL_DONT_CARE); + _eglSetConfigAttrib(config, EGL_TRANSPARENT_GREEN_VALUE, EGL_DONT_CARE); + _eglSetConfigAttrib(config, EGL_TRANSPARENT_BLUE_VALUE, EGL_DONT_CARE); +#ifdef EGL_VERSION_1_2 + _eglSetConfigAttrib(config, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER); + _eglSetConfigAttrib(config, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT); +#endif /* EGL_VERSION_1_2 */ +} + + +/** + * Given an EGLConfig handle, return the corresponding _EGLConfig object. + */ +_EGLConfig * +_eglLookupConfig(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config) +{ + EGLint i; + _EGLDisplay *disp = _eglLookupDisplay(dpy); + for (i = 0; i < disp->NumConfigs; i++) { + if (disp->Configs[i].Handle == config) { + return disp->Configs + i; + } + } + return NULL; +} + + +/** + * Add the given _EGLConfig to the given display. + */ +_EGLConfig * +_eglAddConfig(_EGLDisplay *display, const _EGLConfig *config) +{ + _EGLConfig *newConfigs; + EGLint n; + + n = display->NumConfigs; + + newConfigs = (_EGLConfig *) realloc(display->Configs, + (n + 1) * sizeof(_EGLConfig)); + if (newConfigs) { + display->Configs = newConfigs; + display->Configs[n] = *config; /* copy struct */ + display->Configs[n].Handle = n; + display->NumConfigs++; + return display->Configs + n; + } + else { + return NULL; + } +} + + +/** + * Parse the attrib_list to fill in the fields of the given _eglConfig + * Return EGL_FALSE if any errors, EGL_TRUE otherwise. + */ +EGLBoolean +_eglParseConfigAttribs(_EGLConfig *config, const EGLint *attrib_list) +{ + EGLint i; + + /* set all config attribs to EGL_DONT_CARE */ + for (i = 0; i < MAX_ATTRIBS; i++) { + config->Attrib[i] = EGL_DONT_CARE; + } + + for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { + const EGLint attr = attrib_list[i]; + if (attr >= EGL_BUFFER_SIZE && + attr <= EGL_MAX_SWAP_INTERVAL) { + EGLint k = attr - FIRST_ATTRIB; + assert(k >= 0); + assert(k < MAX_ATTRIBS); + config->Attrib[k] = attrib_list[++i]; + } +#ifdef EGL_VERSION_1_2 + else if (attr == EGL_COLOR_BUFFER_TYPE) { + EGLint bufType = attrib_list[++i]; + if (bufType != EGL_RGB_BUFFER && bufType != EGL_LUMINANCE_BUFFER) { + _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); + return EGL_FALSE; + } + _eglSetConfigAttrib(config, EGL_COLOR_BUFFER_TYPE, bufType); + } + else if (attr == EGL_RENDERABLE_TYPE) { + EGLint renType = attrib_list[++i]; + if (renType & ~(EGL_OPENGL_ES_BIT | EGL_OPENVG_BIT)) { + _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); + return EGL_FALSE; + } + _eglSetConfigAttrib(config, EGL_RENDERABLE_TYPE, renType); + } + else if (attr == EGL_ALPHA_MASK_SIZE || + attr == EGL_LUMINANCE_SIZE) { + EGLint value = attrib_list[++i]; + _eglSetConfigAttrib(config, attr, value); + } +#endif /* EGL_VERSION_1_2 */ + else { + _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); + return EGL_FALSE; + } + } + return EGL_TRUE; +} + + +#define EXACT 1 +#define ATLEAST 2 +#define MASK 3 +#define SMALLER 4 +#define SPECIAL 5 +#define NONE 6 + +struct sort_info { + EGLint Attribute; + EGLint MatchCriteria; + EGLint SortOrder; +}; + +/* This encodes the info from Table 3.5 of the EGL spec, ordered by + * Sort Priority. + * + * XXX To do: EGL 1.2 attribs + */ +static struct sort_info SortInfo[] = { + { EGL_CONFIG_CAVEAT, EXACT, SPECIAL }, + { EGL_RED_SIZE, ATLEAST, SPECIAL }, + { EGL_GREEN_SIZE, ATLEAST, SPECIAL }, + { EGL_BLUE_SIZE, ATLEAST, SPECIAL }, + { EGL_ALPHA_SIZE, ATLEAST, SPECIAL }, + { EGL_BUFFER_SIZE, ATLEAST, SMALLER }, + { EGL_SAMPLE_BUFFERS, ATLEAST, SMALLER }, + { EGL_SAMPLES, ATLEAST, SMALLER }, + { EGL_DEPTH_SIZE, ATLEAST, SMALLER }, + { EGL_STENCIL_SIZE, ATLEAST, SMALLER }, + { EGL_NATIVE_VISUAL_TYPE, EXACT, SPECIAL }, + { EGL_CONFIG_ID, EXACT, SMALLER }, + { EGL_BIND_TO_TEXTURE_RGB, EXACT, NONE }, + { EGL_BIND_TO_TEXTURE_RGBA, EXACT, NONE }, + { EGL_LEVEL, EXACT, NONE }, + { EGL_NATIVE_RENDERABLE, EXACT, NONE }, + { EGL_MAX_SWAP_INTERVAL, EXACT, NONE }, + { EGL_MIN_SWAP_INTERVAL, EXACT, NONE }, + { EGL_SURFACE_TYPE, MASK, NONE }, + { EGL_TRANSPARENT_TYPE, EXACT, NONE }, + { EGL_TRANSPARENT_RED_VALUE, EXACT, NONE }, + { EGL_TRANSPARENT_GREEN_VALUE, EXACT, NONE }, + { EGL_TRANSPARENT_BLUE_VALUE, EXACT, NONE }, + { 0, 0, 0 } +}; + + +/** + * Return EGL_TRUE if the attributes of c meet or exceed the minimums + * specified by min. + */ +static EGLBoolean +_eglConfigQualifies(const _EGLConfig *c, const _EGLConfig *min) +{ + EGLint i; + for (i = 0; SortInfo[i].Attribute != 0; i++) { + const EGLint mv = GET_CONFIG_ATTRIB(min, SortInfo[i].Attribute); + if (mv != EGL_DONT_CARE) { + const EGLint cv = GET_CONFIG_ATTRIB(c, SortInfo[i].Attribute); + if (SortInfo[i].MatchCriteria == EXACT) { + if (cv != mv) { + return EGL_FALSE; + } + } + else if (SortInfo[i].MatchCriteria == ATLEAST) { + if (cv < mv) { + return EGL_FALSE; + } + } + else { + assert(SortInfo[i].MatchCriteria == MASK); + if ((mv & cv) != mv) { + return EGL_FALSE; + } + } + } + } + return EGL_TRUE; +} + + +/** + * Compare configs 'a' and 'b' and return -1 if a belongs before b, + * 1 if a belongs after b, or 0 if they're equal. + * Used by qsort(). + */ +static int +_eglCompareConfigs(const void *a, const void *b) +{ + const _EGLConfig *aConfig = (const _EGLConfig *) a; + const _EGLConfig *bConfig = (const _EGLConfig *) b; + EGLint i; + + for (i = 0; SortInfo[i].Attribute != 0; i++) { + const EGLint aVal = GET_CONFIG_ATTRIB(aConfig, SortInfo[i].Attribute); + const EGLint bVal = GET_CONFIG_ATTRIB(bConfig, SortInfo[i].Attribute); + if (SortInfo[i].SortOrder == SMALLER) { + if (aVal < bVal) + return -1; + else if (aVal > bVal) + return 1; + /* else, continue examining attribute values */ + } + else if (SortInfo[i].SortOrder == SPECIAL) { + if (SortInfo[i].Attribute == EGL_CONFIG_CAVEAT) { + /* values are EGL_NONE, SLOW_CONFIG, or NON_CONFORMANT_CONFIG */ + if (aVal < bVal) + return -1; + else if (aVal > bVal) + return 1; + } + else if (SortInfo[i].Attribute == EGL_RED_SIZE || + SortInfo[i].Attribute == EGL_GREEN_SIZE || + SortInfo[i].Attribute == EGL_BLUE_SIZE || + SortInfo[i].Attribute == EGL_ALPHA_SIZE) { + if (aVal > bVal) + return -1; + else if (aVal < bVal) + return 1; + } + else { + assert(SortInfo[i].Attribute == EGL_NATIVE_VISUAL_TYPE); + if (aVal < bVal) + return -1; + else if (aVal > bVal) + return 1; + } + } + else { + assert(SortInfo[i].SortOrder == NONE); + /* continue examining attribute values */ + } + } + + /* all attributes identical */ + return 0; +} + + +/** + * Typical fallback routine for eglChooseConfig + */ +EGLBoolean +_eglChooseConfig(_EGLDriver *drv, EGLDisplay dpy, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, EGLint *num_configs) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + _EGLConfig **configList, criteria; + EGLint i, count; + + /* parse the attrib_list to initialize criteria */ + if (!_eglParseConfigAttribs(&criteria, attrib_list)) { + return EGL_FALSE; + } + + /* allocate array of config pointers */ + configList = (_EGLConfig **) malloc(config_size * sizeof(_EGLConfig *)); + if (!configList) { + _eglError(EGL_BAD_CONFIG, "eglChooseConfig(out of memory)"); + return EGL_FALSE; + } + + /* make array of pointers to qualifying configs */ + for (i = count = 0; i < disp->NumConfigs && count < config_size; i++) { + if (_eglConfigQualifies(disp->Configs + i, &criteria)) { + configList[count++] = disp->Configs + i; + } + } + + /* sort array of pointers */ + qsort(configList, count, sizeof(_EGLConfig *), _eglCompareConfigs); + + /* copy config handles to output array */ + for (i = 0; i < count; i++) { + configs[i] = configList[i]->Handle; + } + + free(configList); + + *num_configs = count; + + return EGL_TRUE; +} + + +/** + * Fallback for eglGetConfigAttrib. + */ +EGLBoolean +_eglGetConfigAttrib(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value) +{ + const _EGLConfig *conf = _eglLookupConfig(drv, dpy, config); + const EGLint k = attribute - FIRST_ATTRIB; + if (k >= 0 && k < MAX_ATTRIBS) { + *value = conf->Attrib[k]; + return EGL_TRUE; + } + else { + _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); + return EGL_FALSE; + } +} + + +/** + * Fallback for eglGetConfigs. + */ +EGLBoolean +_eglGetConfigs(_EGLDriver *drv, EGLDisplay dpy, EGLConfig *configs, + EGLint config_size, EGLint *num_config) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + + if (!drv->Initialized) { + _eglError(EGL_NOT_INITIALIZED, "eglGetConfigs"); + return EGL_FALSE; + } + + if (configs) { + EGLint i; + *num_config = MIN2(disp->NumConfigs, config_size); + for (i = 0; i < *num_config; i++) { + configs[i] = disp->Configs[i].Handle; + } + } + else { + /* just return total number of supported configs */ + *num_config = disp->NumConfigs; + } + + return EGL_TRUE; +} + + +/** + * Creates a set of \c __GLcontextModes that a driver will expose. + * + * A set of \c __GLcontextModes will be created based on the supplied + * parameters. The number of modes processed will be 2 * + * \c num_depth_stencil_bits * \c num_db_modes. + * + * For the most part, data is just copied from \c depth_bits, \c stencil_bits, + * \c db_modes, and \c visType into each \c __GLcontextModes element. + * However, the meanings of \c fb_format and \c fb_type require further + * explanation. The \c fb_format specifies which color components are in + * each pixel and what the default order is. For example, \c GL_RGB specifies + * that red, green, blue are available and red is in the "most significant" + * position and blue is in the "least significant". The \c fb_type specifies + * the bit sizes of each component and the actual ordering. For example, if + * \c GL_UNSIGNED_SHORT_5_6_5_REV is specified with \c GL_RGB, bits [15:11] + * are the blue value, bits [10:5] are the green value, and bits [4:0] are + * the red value. + * + * One sublte issue is the combination of \c GL_RGB or \c GL_BGR and either + * of the \c GL_UNSIGNED_INT_8_8_8_8 modes. The resulting mask values in the + * \c __GLcontextModes structure is \b identical to the \c GL_RGBA or + * \c GL_BGRA case, except the \c alphaMask is zero. This means that, as + * far as this routine is concerned, \c GL_RGB with \c GL_UNSIGNED_INT_8_8_8_8 + * still uses 32-bits. + * + * If in doubt, look at the tables used in the function. + * + * \param ptr_to_modes Pointer to a pointer to a linked list of + * \c __GLcontextModes. Upon completion, a pointer to + * the next element to be process will be stored here. + * If the function fails and returns \c GL_FALSE, this + * value will be unmodified, but some elements in the + * linked list may be modified. + * \param fb_format Format of the framebuffer. Currently only \c GL_RGB, + * \c GL_RGBA, \c GL_BGR, and \c GL_BGRA are supported. + * \param fb_type Type of the pixels in the framebuffer. Currently only + * \c GL_UNSIGNED_SHORT_5_6_5, + * \c GL_UNSIGNED_SHORT_5_6_5_REV, + * \c GL_UNSIGNED_INT_8_8_8_8, and + * \c GL_UNSIGNED_INT_8_8_8_8_REV are supported. + * \param depth_bits Array of depth buffer sizes to be exposed. + * \param stencil_bits Array of stencil buffer sizes to be exposed. + * \param num_depth_stencil_bits Number of entries in both \c depth_bits and + * \c stencil_bits. + * \param db_modes Array of buffer swap modes. If an element has a + * value of \c GLX_NONE, then it represents a + * single-buffered mode. Other valid values are + * \c GLX_SWAP_EXCHANGE_OML, \c GLX_SWAP_COPY_OML, and + * \c GLX_SWAP_UNDEFINED_OML. See the + * GLX_OML_swap_method extension spec for more details. + * \param num_db_modes Number of entries in \c db_modes. + * \param visType GLX visual type. Usually either \c GLX_TRUE_COLOR or + * \c GLX_DIRECT_COLOR. + * + * \returns + * \c GL_TRUE on success or \c GL_FALSE on failure. Currently the only + * cause of failure is a bad parameter (i.e., unsupported \c fb_format or + * \c fb_type). + * + * \todo + * There is currently no way to support packed RGB modes (i.e., modes with + * exactly 3 bytes per pixel) or floating-point modes. This could probably + * be done by creating some new, private enums with clever names likes + * \c GL_UNSIGNED_3BYTE_8_8_8, \c GL_4FLOAT_32_32_32_32, + * \c GL_4HALF_16_16_16_16, etc. We can cross that bridge when we come to it. + */ +GLboolean +_eglFillInConfigs(_EGLConfig * configs, + GLenum fb_format, GLenum fb_type, + const u_int8_t * depth_bits, const u_int8_t * stencil_bits, + unsigned num_depth_stencil_bits, + const GLenum * db_modes, unsigned num_db_modes, + int visType) +{ + static const u_int8_t bits_table[3][4] = { + /* R G B A */ + { 5, 6, 5, 0 }, /* Any GL_UNSIGNED_SHORT_5_6_5 */ + { 8, 8, 8, 0 }, /* Any RGB with any GL_UNSIGNED_INT_8_8_8_8 */ + { 8, 8, 8, 8 } /* Any RGBA with any GL_UNSIGNED_INT_8_8_8_8 */ + }; + + /* The following arrays are all indexed by the fb_type masked with 0x07. + * Given the four supported fb_type values, this results in valid array + * indices of 3, 4, 5, and 7. + */ + static const u_int32_t masks_table_rgb[8][4] = { + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000F800, 0x000007E0, 0x0000001F, 0x00000000}, /* 5_6_5 */ + {0x0000001F, 0x000007E0, 0x0000F800, 0x00000000}, /* 5_6_5_REV */ + {0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000}, /* 8_8_8_8 */ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000} /* 8_8_8_8_REV */ + }; + + static const u_int32_t masks_table_rgba[8][4] = { + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000F800, 0x000007E0, 0x0000001F, 0x00000000}, /* 5_6_5 */ + {0x0000001F, 0x000007E0, 0x0000F800, 0x00000000}, /* 5_6_5_REV */ + {0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF}, /* 8_8_8_8 */ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000}, /* 8_8_8_8_REV */ + }; + + static const u_int32_t masks_table_bgr[8][4] = { + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000001F, 0x000007E0, 0x0000F800, 0x00000000}, /* 5_6_5 */ + {0x0000F800, 0x000007E0, 0x0000001F, 0x00000000}, /* 5_6_5_REV */ + {0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000}, /* 8_8_8_8 */ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000}, /* 8_8_8_8_REV */ + }; + + static const u_int32_t masks_table_bgra[8][4] = { + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000001F, 0x000007E0, 0x0000F800, 0x00000000}, /* 5_6_5 */ + {0x0000F800, 0x000007E0, 0x0000001F, 0x00000000}, /* 5_6_5_REV */ + {0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF}, /* 8_8_8_8 */ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000}, /* 8_8_8_8_REV */ + }; + + static const u_int8_t bytes_per_pixel[8] = { + 0, 0, 0, 2, 2, 4, 0, 4 + }; + + const u_int8_t * bits; + const u_int32_t * masks; + const int index = fb_type & 0x07; + _EGLConfig *config; + unsigned i; + unsigned j; + unsigned k; + + if ( bytes_per_pixel[index] == 0 ) { + _eglLog(_EGL_INFO, + "[%s:%u] Framebuffer type 0x%04x has 0 bytes per pixel.", + __FUNCTION__, __LINE__, fb_type); + return GL_FALSE; + } + + /* Valid types are GL_UNSIGNED_SHORT_5_6_5 and GL_UNSIGNED_INT_8_8_8_8 and + * the _REV versions. + * + * Valid formats are GL_RGBA, GL_RGB, and GL_BGRA. + */ + switch ( fb_format ) { + case GL_RGB: + bits = (bytes_per_pixel[index] == 2) ? bits_table[0] : bits_table[1]; + masks = masks_table_rgb[index]; + break; + + case GL_RGBA: + bits = (bytes_per_pixel[index] == 2) ? bits_table[0] : bits_table[2]; + masks = masks_table_rgba[index]; + break; + + case GL_BGR: + bits = (bytes_per_pixel[index] == 2) ? bits_table[0] : bits_table[1]; + masks = masks_table_bgr[index]; + break; + + case GL_BGRA: + bits = (bytes_per_pixel[index] == 2) ? bits_table[0] : bits_table[2]; + masks = masks_table_bgra[index]; + break; + + default: + _eglLog(_EGL_WARNING, + "[%s:%u] Framebuffer format 0x%04x is not GL_RGB, GL_RGBA, GL_BGR, or GL_BGRA.", + __FUNCTION__, __LINE__, fb_format); + return GL_FALSE; + } + + config = configs; + for (k = 0; k < num_depth_stencil_bits; k++) { + for (i = 0; i < num_db_modes; i++) { + for (j = 0; j < 2; j++) { + _eglSetConfigAttrib(config, EGL_RED_SIZE, bits[0]); + _eglSetConfigAttrib(config, EGL_GREEN_SIZE, bits[1]); + _eglSetConfigAttrib(config, EGL_BLUE_SIZE, bits[2]); + _eglSetConfigAttrib(config, EGL_ALPHA_SIZE, bits[3]); + _eglSetConfigAttrib(config, EGL_BUFFER_SIZE, + bits[0] + bits[1] + bits[2] + bits[3]); + + _eglSetConfigAttrib(config, EGL_STENCIL_SIZE, stencil_bits[k]); + _eglSetConfigAttrib(config, EGL_DEPTH_SIZE, depth_bits[i]); + + _eglSetConfigAttrib(config, EGL_SURFACE_TYPE, EGL_SCREEN_BIT_MESA | + EGL_PBUFFER_BIT | EGL_PIXMAP_BIT | EGL_WINDOW_BIT); + + config++; + } + } + } + return GL_TRUE; +} diff --git a/src/egl/main/eglconfig.h b/src/egl/main/eglconfig.h new file mode 100644 index 00000000000..1fb976e5b4b --- /dev/null +++ b/src/egl/main/eglconfig.h @@ -0,0 +1,67 @@ +#ifndef EGLCONFIG_INCLUDED +#define EGLCONFIG_INCLUDED + + +#include "egltypedefs.h" +#include "GL/internal/glcore.h" + + +#define MAX_ATTRIBS 100 +#define FIRST_ATTRIB EGL_BUFFER_SIZE + + +struct _egl_config +{ + EGLConfig Handle; /* the public/opaque handle which names this config */ + EGLint Attrib[MAX_ATTRIBS]; +}; + + +#define SET_CONFIG_ATTRIB(CONF, ATTR, VAL) ((CONF)->Attrib[(ATTR) - FIRST_ATTRIB] = VAL) +#define GET_CONFIG_ATTRIB(CONF, ATTR) ((CONF)->Attrib[(ATTR) - FIRST_ATTRIB]) + + +extern void +_eglInitConfig(_EGLConfig *config, EGLint id); + + +extern _EGLConfig * +_eglLookupConfig(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config); + + +extern _EGLConfig * +_eglAddConfig(_EGLDisplay *display, const _EGLConfig *config); + + +extern EGLBoolean +_eglParseConfigAttribs(_EGLConfig *config, const EGLint *attrib_list); + + +extern EGLBoolean +_eglChooseConfig(_EGLDriver *drv, EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); + + +extern EGLBoolean +_eglGetConfigAttrib(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); + + +extern EGLBoolean +_eglGetConfigs(_EGLDriver *drv, EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); + + +extern void +_eglSetConfigAttrib(_EGLConfig *config, EGLint attr, EGLint val); + +extern GLboolean +_eglFillInConfigs( _EGLConfig *configs, + GLenum fb_format, GLenum fb_type, + const u_int8_t * depth_bits, const u_int8_t * stencil_bits, + unsigned num_depth_stencil_bits, + const GLenum * db_modes, unsigned num_db_modes, + int visType ); + +extern void +_eglConfigToContextModesRec(const _EGLConfig *config, __GLcontextModes *mode); + + +#endif /* EGLCONFIG_INCLUDED */ diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c new file mode 100644 index 00000000000..374c006dae7 --- /dev/null +++ b/src/egl/main/eglcontext.c @@ -0,0 +1,276 @@ +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include "eglconfig.h" +#include "eglcontext.h" +#include "egldisplay.h" +#include "egldriver.h" +#include "eglglobals.h" +#include "eglhash.h" +#include "eglsurface.h" + + +/** + * Initialize the given _EGLContext object to defaults. + */ +EGLBoolean +_eglInitContext(_EGLDriver *drv, EGLDisplay dpy, _EGLContext *ctx, + EGLConfig config, const EGLint *attrib_list) +{ + _EGLConfig *conf; + _EGLDisplay *display = _eglLookupDisplay(dpy); + EGLint i; + + conf = _eglLookupConfig(drv, dpy, config); + if (!conf) { + _eglError(EGL_BAD_CONFIG, "eglCreateContext"); + return EGL_FALSE; + } + + for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { + switch (attrib_list[i]) { + /* no attribs defined for now */ + default: + _eglError(EGL_BAD_ATTRIBUTE, "eglCreateContext"); + return EGL_NO_CONTEXT; + } + } + + memset(ctx, 0, sizeof(_EGLContext)); + ctx->Display = display; + ctx->Config = conf; + ctx->DrawSurface = EGL_NO_SURFACE; + ctx->ReadSurface = EGL_NO_SURFACE; + + return EGL_TRUE; +} + + +/* + * Assign an EGLContext handle to the _EGLContext object then put it into + * the hash table. + */ +void +_eglSaveContext(_EGLContext *ctx) +{ + assert(ctx); + ctx->Handle = _eglHashGenKey(_eglGlobal.Contexts); + _eglHashInsert(_eglGlobal.Contexts, ctx->Handle, ctx); +} + + +/** + * Remove the given _EGLContext object from the hash table. + */ +void +_eglRemoveContext(_EGLContext *ctx) +{ + _eglHashRemove(_eglGlobal.Contexts, ctx->Handle); +} + + +/** + * Return the _EGLContext object that corresponds to the given + * EGLContext handle. + */ +_EGLContext * +_eglLookupContext(EGLContext ctx) +{ + _EGLContext *c = (_EGLContext *) _eglHashLookup(_eglGlobal.Contexts, ctx); + return c; +} + + +/** + * Return the currently bound _EGLContext object, or NULL. + */ +_EGLContext * +_eglGetCurrentContext(void) +{ + _EGLThreadInfo *t = _eglGetCurrentThread(); + return t->CurrentContext; +} + + +/** + * Just a placeholder/demo function. Real driver will never use this! + */ +EGLContext +_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + EGLContext share_list, const EGLint *attrib_list) +{ +#if 0 /* example code */ + _EGLContext *context; + + context = (_EGLContext *) calloc(1, sizeof(_EGLContext)); + if (!context) + return EGL_NO_CONTEXT; + + if (!_eglInitContext(drv, dpy, context, config, attrib_list)) { + free(context); + return EGL_NO_CONTEXT; + } + + _eglSaveContext(context); + return context->Handle; +#endif + return EGL_NO_CONTEXT; +} + + +/** + * Default fallback routine - drivers should usually override this. + */ +EGLBoolean +_eglDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx) +{ + _EGLContext *context = _eglLookupContext(ctx); + if (context) { + _eglHashRemove(_eglGlobal.Contexts, ctx); + if (context->IsBound) { + context->DeletePending = EGL_TRUE; + } + else { + free(context); + } + return EGL_TRUE; + } + else { + _eglError(EGL_BAD_CONTEXT, "eglDestroyContext"); + return EGL_TRUE; + } +} + + +EGLBoolean +_eglQueryContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint *value) +{ + _EGLContext *c = _eglLookupContext(ctx); + + (void) drv; + (void) dpy; + + if (!c) { + _eglError(EGL_BAD_CONTEXT, "eglQueryContext"); + return EGL_FALSE; + } + + switch (attribute) { + case EGL_CONFIG_ID: + *value = GET_CONFIG_ATTRIB(c->Config, EGL_CONFIG_ID); + return EGL_TRUE; +#ifdef EGL_VERSION_1_2 + case EGL_CONTEXT_CLIENT_TYPE: + *value = c->ClientAPI; + return EGL_FALSE; +#endif /* EGL_VERSION_1_2 */ + default: + _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext"); + return EGL_FALSE; + } +} + + +/** + * Drivers will typically call this to do the error checking and + * update the various IsBound and DeletePending flags. + * Then, the driver will do its device-dependent Make-Current stuff. + */ +EGLBoolean +_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d, + EGLSurface r, EGLContext context) +{ + _EGLThreadInfo *t = _eglGetCurrentThread(); + _EGLContext *ctx = _eglLookupContext(context); + _EGLSurface *draw = _eglLookupSurface(d); + _EGLSurface *read = _eglLookupSurface(r); + + _EGLContext *oldContext = _eglGetCurrentContext(); + _EGLSurface *oldDrawSurface = _eglGetCurrentSurface(EGL_DRAW); + _EGLSurface *oldReadSurface = _eglGetCurrentSurface(EGL_READ); + + /* error checking */ + if (ctx) { + if (draw == NULL || read == NULL) { + _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); + return EGL_FALSE; + } + if (draw->Config != ctx->Config) { + _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); + return EGL_FALSE; + } + if (read->Config != ctx->Config) { + _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); + return EGL_FALSE; + } + } + + /* + * check if the old context or surfaces need to be deleted + */ + if (oldDrawSurface != NULL) { + oldDrawSurface->IsBound = EGL_FALSE; + if (oldDrawSurface->DeletePending) { + /* make sure we don't try to rebind a deleted surface */ + if (draw == oldDrawSurface || draw == oldReadSurface) { + draw = NULL; + } + /* really delete surface now */ + drv->API.DestroySurface(drv, dpy, oldDrawSurface->Handle); + } + } + if (oldReadSurface != NULL && oldReadSurface != oldDrawSurface) { + oldReadSurface->IsBound = EGL_FALSE; + if (oldReadSurface->DeletePending) { + /* make sure we don't try to rebind a deleted surface */ + if (read == oldDrawSurface || read == oldReadSurface) { + read = NULL; + } + /* really delete surface now */ + drv->API.DestroySurface(drv, dpy, oldReadSurface->Handle); + } + } + if (oldContext != NULL) { + oldContext->IsBound = EGL_FALSE; + if (oldContext->DeletePending) { + /* make sure we don't try to rebind a deleted context */ + if (ctx == oldContext) { + ctx = NULL; + } + /* really delete context now */ + drv->API.DestroyContext(drv, dpy, oldContext->Handle); + } + } + + if (ctx) { + /* check read/draw again, in case we deleted them above */ + if (draw == NULL || read == NULL) { + _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); + return EGL_FALSE; + } + ctx->DrawSurface = draw; + ctx->ReadSurface = read; + ctx->IsBound = EGL_TRUE; + draw->IsBound = EGL_TRUE; + read->IsBound = EGL_TRUE; + } + + t->CurrentContext = ctx; + + return EGL_TRUE; +} + + +/** + * This is defined by the EGL_MESA_copy_context extension. + */ +EGLBoolean +_eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source, + EGLContext dest, EGLint mask) +{ + /* This function will always have to be overridden/implemented in the + * device driver. If the driver is based on Mesa, use _mesa_copy_context(). + */ + return EGL_FALSE; +} diff --git a/src/egl/main/eglcontext.h b/src/egl/main/eglcontext.h new file mode 100644 index 00000000000..82bfde151f3 --- /dev/null +++ b/src/egl/main/eglcontext.h @@ -0,0 +1,71 @@ + +#ifndef EGLCONTEXT_INCLUDED +#define EGLCONTEXT_INCLUDED + + +#include "egltypedefs.h" + + +/** + * "Base" class for device driver contexts. + */ +struct _egl_context +{ + EGLContext Handle; /* The public/opaque handle which names this object */ + + _EGLDisplay *Display; /* who do I belong to? */ + + _EGLConfig *Config; + + _EGLSurface *DrawSurface; + _EGLSurface *ReadSurface; + + EGLBoolean IsBound; + EGLBoolean DeletePending; +#ifdef EGL_VERSION_1_2 + EGLint ClientAPI; /* Either EGL_OPENGL_ES_API or EGL_OPENVG_API */ +#endif /* EGL_VERSION_1_2 */ +}; + + +extern EGLBoolean +_eglInitContext(_EGLDriver *drv, EGLDisplay dpy, _EGLContext *ctx, + EGLConfig config, const EGLint *attrib_list); + + +extern void +_eglSaveContext(_EGLContext *ctx); + + +extern void +_eglRemoveContext(_EGLContext *ctx); + + +extern _EGLContext * +_eglLookupContext(EGLContext ctx); + + +extern _EGLContext * +_eglGetCurrentContext(void); + + +extern EGLContext +_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list); + + +extern EGLBoolean +_eglDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx); + + +extern EGLBoolean +_eglQueryContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value); + + +extern EGLBoolean +_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); + + +extern EGLBoolean +_eglCopyContextMESA(_EGLDriver *drv, EGLDisplay dpy, EGLContext source, EGLContext dest, EGLint mask); + +#endif /* EGLCONTEXT_INCLUDED */ diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c new file mode 100644 index 00000000000..074a85bf26b --- /dev/null +++ b/src/egl/main/egldisplay.c @@ -0,0 +1,71 @@ +#include <stdlib.h> +#include <string.h> +#include "eglcontext.h" +#include "egldisplay.h" +#include "eglglobals.h" +#include "eglhash.h" + + +static char * +my_strdup(const char *s) +{ + int l = strlen(s); + char *s2 = malloc(l + 1); + strcpy(s2, s); + return s2; +} + + +/** + * We're assuming that the NativeDisplayType parameter is actually + * a string. + * Return a new _EGLDisplay object for the given displayName + */ +_EGLDisplay * +_eglNewDisplay(NativeDisplayType displayName) +{ + _EGLDisplay *dpy = (_EGLDisplay *) calloc(1, sizeof(_EGLDisplay)); + if (dpy) { + dpy->Handle = _eglHashGenKey(_eglGlobal.Displays); + _eglHashInsert(_eglGlobal.Displays, dpy->Handle, dpy); + if (displayName) + dpy->Name = my_strdup(displayName); + else + dpy->Name = NULL; + dpy->Driver = NULL; /* this gets set later */ + } + return dpy; +} + + +/** + * Return the _EGLDisplay object that corresponds to the given public/ + * opaque display handle. + */ +_EGLDisplay * +_eglLookupDisplay(EGLDisplay dpy) +{ + _EGLDisplay *d = (_EGLDisplay *) _eglHashLookup(_eglGlobal.Displays, dpy); + return d; +} + + +_EGLDisplay * +_eglGetCurrentDisplay(void) +{ + _EGLContext *ctx = _eglGetCurrentContext(); + if (ctx) + return ctx->Display; + else + return NULL; +} + + +void +_eglCleanupDisplay(_EGLDisplay *disp) +{ + /* XXX incomplete */ + free(disp->Configs); + free(disp->Name); + /* driver deletes _EGLDisplay */ +} diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h new file mode 100644 index 00000000000..1a03fdd4ad9 --- /dev/null +++ b/src/egl/main/egldisplay.h @@ -0,0 +1,44 @@ +#ifndef EGLDISPLAY_INCLUDED +#define EGLDISPLAY_INCLUDED + + +#include "egltypedefs.h" + + +struct _egl_display +{ + EGLDisplay Handle; + + char *Name; + _EGLDriver *Driver; + + EGLint NumScreens; + _EGLScreen **Screens; /* array [NumScreens] */ + + EGLint NumConfigs; + _EGLConfig *Configs; /* array [NumConfigs] */ +}; + + +extern _EGLDisplay * +_eglNewDisplay(NativeDisplayType displayName); + + +extern _EGLDisplay * +_eglLookupDisplay(EGLDisplay dpy); + + +extern _EGLDisplay * +_eglGetCurrentDisplay(void); + + +extern void +_eglCleanupDisplay(_EGLDisplay *disp); + + +extern EGLBoolean +_eglQueryDisplayMESA(_EGLDriver *drv, EGLDisplay dpy, EGLint attrib, EGLint *value); + + + +#endif /* EGLDISPLAY_INCLUDED */ diff --git a/src/egl/main/egldriver.c b/src/egl/main/egldriver.c new file mode 100644 index 00000000000..bda06dd827d --- /dev/null +++ b/src/egl/main/egldriver.c @@ -0,0 +1,272 @@ +#include <assert.h> +#include <dlfcn.h> +#include <stdio.h> +#include <string.h> +#include "eglconfig.h" +#include "eglcontext.h" +#include "egldisplay.h" +#include "egldriver.h" +#include "eglglobals.h" +#include "egllog.h" +#include "eglmode.h" +#include "eglscreen.h" +#include "eglsurface.h" + + +const char *DefaultDriverName = "demodriver"; + + +/** + * Choose and open/init the hardware driver for the given EGLDisplay. + * Previously, the EGLDisplay was created with _eglNewDisplay() where + * we recorded the user's NativeDisplayType parameter. + * + * Now we'll use the NativeDisplayType value. + * + * Currently, the native display value is treated as a string. + * If the first character is ':' we interpret it as a screen or card index + * number (i.e. ":0" or ":1", etc) + * Else if the first character is '!' we interpret it as specific driver name + * (i.e. "!r200" or "!i830". + */ +_EGLDriver * +_eglChooseDriver(EGLDisplay display) +{ + _EGLDisplay *dpy = _eglLookupDisplay(display); + _EGLDriver *drv; + const char *driverName = DefaultDriverName; + const char *name; + + assert(dpy); + + name = dpy->Name; + if (!name) { + /* use default */ + } + else if (name[0] == ':' && (name[1] >= '0' && name[1] <= '9') && !name[2]) { + /* XXX probe hardware here to determine which driver to open */ + driverName = "libEGLdri"; + } + else if (name[0] == '!') { + /* use specified driver name */ + driverName = name + 1; + } + else { + /* Maybe display was returned by XOpenDisplay? */ + _eglLog(_EGL_FATAL, "eglChooseDriver() bad name"); + } + + _eglLog(_EGL_INFO, "eglChooseDriver() choosing %s", driverName); + + drv = _eglOpenDriver(dpy, driverName); + dpy->Driver = drv; + + return drv; +} + + +/** + * Open/load the named driver and call its bootstrap function: _eglMain(). + * \return new _EGLDriver object. + */ +_EGLDriver * +_eglOpenDriver(_EGLDisplay *dpy, const char *driverName) +{ + _EGLDriver *drv; + _EGLMain_t mainFunc; + void *lib; + char driverFilename[1000]; + + /* XXX also prepend a directory path??? */ + sprintf(driverFilename, "%s.so", driverName); + + _eglLog(_EGL_DEBUG, "dlopen(%s)", driverFilename); + lib = dlopen(driverFilename, RTLD_NOW); + if (!lib) { + _eglLog(_EGL_WARNING, "Could not open %s (%s)", + driverFilename, dlerror()); + return NULL; + } + + mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain"); + if (!mainFunc) { + _eglLog(_EGL_WARNING, "_eglMain not found in %s", driverFilename); + dlclose(lib); + return NULL; + } + + drv = mainFunc(dpy); + if (!drv) { + dlclose(lib); + return NULL; + } + /* with a recurvise open you want the inner most handle */ + if (!drv->LibHandle) + drv->LibHandle = lib; + else + dlclose(lib); + + drv->Display = dpy; + return drv; +} + + +EGLBoolean +_eglCloseDriver(_EGLDriver *drv, EGLDisplay dpy) +{ + void *handle = drv->LibHandle; + EGLBoolean b; + + _eglLog(_EGL_INFO, "Closing driver"); + + /* + * XXX check for currently bound context/surfaces and delete them? + */ + + b = drv->API.Terminate(drv, dpy); + dlclose(handle); + return b; +} + + +/** + * Given a display handle, return the _EGLDriver for that display. + */ +_EGLDriver * +_eglLookupDriver(EGLDisplay dpy) +{ + _EGLDisplay *d = _eglLookupDisplay(dpy); + if (d) + return d->Driver; + else + return NULL; +} + + +/** + * Plug all the available fallback routines into the given driver's + * dispatch table. + */ +void +_eglInitDriverFallbacks(_EGLDriver *drv) +{ + /* If a pointer is set to NULL, then the device driver _really_ has + * to implement it. + */ + drv->API.Initialize = NULL; + drv->API.Terminate = NULL; + + drv->API.GetConfigs = _eglGetConfigs; + drv->API.ChooseConfig = _eglChooseConfig; + drv->API.GetConfigAttrib = _eglGetConfigAttrib; + + drv->API.CreateContext = _eglCreateContext; + drv->API.DestroyContext = _eglDestroyContext; + drv->API.MakeCurrent = _eglMakeCurrent; + drv->API.QueryContext = _eglQueryContext; + + drv->API.CreateWindowSurface = _eglCreateWindowSurface; + drv->API.CreatePixmapSurface = _eglCreatePixmapSurface; + drv->API.CreatePbufferSurface = _eglCreatePbufferSurface; + drv->API.DestroySurface = _eglDestroySurface; + drv->API.QuerySurface = _eglQuerySurface; + drv->API.SurfaceAttrib = _eglSurfaceAttrib; + drv->API.BindTexImage = _eglBindTexImage; + drv->API.ReleaseTexImage = _eglReleaseTexImage; + drv->API.SwapInterval = _eglSwapInterval; + drv->API.SwapBuffers = _eglSwapBuffers; + drv->API.CopyBuffers = _eglCopyBuffers; + + drv->API.QueryString = _eglQueryString; + drv->API.WaitGL = _eglWaitGL; + drv->API.WaitNative = _eglWaitNative; + +#ifdef EGL_MESA_screen_surface + drv->API.ChooseModeMESA = _eglChooseModeMESA; + drv->API.GetModesMESA = _eglGetModesMESA; + drv->API.GetModeAttribMESA = _eglGetModeAttribMESA; + drv->API.GetScreensMESA = _eglGetScreensMESA; + drv->API.CreateScreenSurfaceMESA = _eglCreateScreenSurfaceMESA; + drv->API.ShowScreenSurfaceMESA = _eglShowScreenSurfaceMESA; + drv->API.ScreenPositionMESA = _eglScreenPositionMESA; + drv->API.QueryScreenMESA = _eglQueryScreenMESA; + drv->API.QueryScreenSurfaceMESA = _eglQueryScreenSurfaceMESA; + drv->API.QueryScreenModeMESA = _eglQueryScreenModeMESA; + drv->API.QueryModeStringMESA = _eglQueryModeStringMESA; +#endif /* EGL_MESA_screen_surface */ + +#ifdef EGL_VERSION_1_2 + drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer; +#endif /* EGL_VERSION_1_2 */ +} + + +/** + * Examine the individual extension enable/disable flags and recompute + * the driver's Extensions string. + */ +static void +_eglUpdateExtensionsString(_EGLDriver *drv) +{ + drv->Extensions.String[0] = 0; + + if (drv->Extensions.MESA_screen_surface) + strcat(drv->Extensions.String, "EGL_MESA_screen_surface "); + if (drv->Extensions.MESA_copy_context) + strcat(drv->Extensions.String, "EGL_MESA_copy_context "); + assert(strlen(drv->Extensions.String) < MAX_EXTENSIONS_LEN); +} + + + +const char * +_eglQueryString(_EGLDriver *drv, EGLDisplay dpy, EGLint name) +{ + (void) drv; + (void) dpy; + switch (name) { + case EGL_VENDOR: + return "Mesa Project"; + case EGL_VERSION: + return "1.0"; + case EGL_EXTENSIONS: + _eglUpdateExtensionsString(drv); + return drv->Extensions.String; +#ifdef EGL_VERSION_1_2 + case EGL_CLIENT_APIS: + /* XXX need to initialize somewhere */ + return drv->ClientAPIs; +#endif + default: + _eglError(EGL_BAD_PARAMETER, "eglQueryString"); + return NULL; + } +} + + +EGLBoolean +_eglWaitGL(_EGLDriver *drv, EGLDisplay dpy) +{ + /* just a placeholder */ + (void) drv; + (void) dpy; + return EGL_TRUE; +} + + +EGLBoolean +_eglWaitNative(_EGLDriver *drv, EGLDisplay dpy, EGLint engine) +{ + /* just a placeholder */ + (void) drv; + (void) dpy; + switch (engine) { + case EGL_CORE_NATIVE_ENGINE: + break; + default: + _eglError(EGL_BAD_PARAMETER, "eglWaitNative(engine)"); + return EGL_FALSE; + } + + return EGL_TRUE; +} diff --git a/src/egl/main/egldriver.h b/src/egl/main/egldriver.h new file mode 100644 index 00000000000..88526e973d1 --- /dev/null +++ b/src/egl/main/egldriver.h @@ -0,0 +1,81 @@ +#ifndef EGLDRIVER_INCLUDED +#define EGLDRIVER_INCLUDED + + +#include "egltypedefs.h" +#include "eglapi.h" + +/* should probably use a dynamic-length string, but this will do */ +#define MAX_EXTENSIONS_LEN 1000 + + +/** + * Optional EGL extensions info. + */ +struct _egl_extensions +{ + EGLBoolean MESA_screen_surface; + EGLBoolean MESA_copy_context; + + char String[MAX_EXTENSIONS_LEN]; +}; + + +/** + * Base class for device drivers. + */ +struct _egl_driver +{ + EGLBoolean Initialized; /* set by driver after initialized */ + + void *LibHandle; /* dlopen handle */ + + _EGLDisplay *Display; + + int ABIversion; + int APImajor, APIminor; /* returned through eglInitialize */ + const char *ClientAPIs; + + _EGLAPI API; + + _EGLExtensions Extensions; +}; + + +extern _EGLDriver *_eglMain(_EGLDisplay *dpy); + + +extern _EGLDriver * +_eglChooseDriver(EGLDisplay dpy); + + +extern _EGLDriver * +_eglOpenDriver(_EGLDisplay *dpy, const char *driverName); + + +extern EGLBoolean +_eglCloseDriver(_EGLDriver *drv, EGLDisplay dpy); + + +extern _EGLDriver * +_eglLookupDriver(EGLDisplay d); + + +extern void +_eglInitDriverFallbacks(_EGLDriver *drv); + + +extern const char * +_eglQueryString(_EGLDriver *drv, EGLDisplay dpy, EGLint name); + + +extern EGLBoolean +_eglWaitGL(_EGLDriver *drv, EGLDisplay dpy); + + +extern EGLBoolean +_eglWaitNative(_EGLDriver *drv, EGLDisplay dpy, EGLint engine); + + + +#endif /* EGLDRIVER_INCLUDED */ diff --git a/src/egl/main/eglglobals.c b/src/egl/main/eglglobals.c new file mode 100644 index 00000000000..608311d7494 --- /dev/null +++ b/src/egl/main/eglglobals.c @@ -0,0 +1,148 @@ +#include <stdio.h> +#include <stdlib.h> +#include "eglglobals.h" + + +struct _egl_global _eglGlobal = { .Initialized = EGL_FALSE }; + + +/** + * Init the fields in the _eglGlobal struct + * May be safely called more than once. + */ +void +_eglInitGlobals(void) +{ + if (!_eglGlobal.Initialized) { + _eglGlobal.Displays = _eglNewHashTable(); + _eglGlobal.Contexts = _eglNewHashTable(); + _eglGlobal.Surfaces = _eglNewHashTable(); + _eglGlobal.FreeScreenHandle = 1; + _eglGlobal.Initialized = EGL_TRUE; + + _eglGlobal.OpenGLESAPISupported = EGL_TRUE; + _eglGlobal.OpenVGAPISupported = EGL_FALSE; + + /* XXX temporary */ + _eglGlobal.ThreadInfo = _eglNewThreadInfo(); + } +} + + +/** + * Should call this via an atexit handler. + */ +void +_eglDestroyGlobals(void) +{ + /* XXX TODO walk over table entries, deleting each */ + _eglDeleteHashTable(_eglGlobal.Displays); + _eglDeleteHashTable(_eglGlobal.Contexts); + _eglDeleteHashTable(_eglGlobal.Surfaces); +} + + +/** + * Allocate and init a new _EGLThreadInfo object. + */ +_EGLThreadInfo * +_eglNewThreadInfo(void) +{ + _EGLThreadInfo *t = (_EGLThreadInfo *) calloc(1, sizeof(_EGLThreadInfo)); + if (t) { + t->CurrentContext = EGL_NO_CONTEXT; + t->LastError = EGL_SUCCESS; + t->CurrentAPI = EGL_NONE; + } + return t; +} + + +/** + * Delete/free a _EGLThreadInfo object. + */ +void +_eglDeleteThreadData(_EGLThreadInfo *t) +{ + free(t); +} + + + +/** + * Return pointer to calling thread's _EGLThreadInfo object. + * Create a new one if needed. + * Should never return NULL. + */ +_EGLThreadInfo * +_eglGetCurrentThread(void) +{ + _eglInitGlobals(); + + /* XXX temporary */ + return _eglGlobal.ThreadInfo; +} + + +/** + * Record EGL error code. + */ +void +_eglError(EGLint errCode, const char *msg) +{ + _EGLThreadInfo *t = _eglGetCurrentThread(); + const char *s; + + if (t->LastError == EGL_SUCCESS) { + t->LastError = errCode; + + switch (errCode) { + case EGL_BAD_ACCESS: + s = "EGL_BAD_ACCESS"; + break; + case EGL_BAD_ALLOC: + s = "EGL_BAD_ALLOC"; + break; + case EGL_BAD_ATTRIBUTE: + s = "EGL_BAD_ATTRIBUTE"; + break; + case EGL_BAD_CONFIG: + s = "EGL_BAD_CONFIG"; + break; + case EGL_BAD_CONTEXT: + s = "EGL_BAD_CONTEXT"; + break; + case EGL_BAD_CURRENT_SURFACE: + s = "EGL_BAD_CURRENT_SURFACE"; + break; + case EGL_BAD_DISPLAY: + s = "EGL_BAD_DISPLAY"; + break; + case EGL_BAD_MATCH: + s = "EGL_BAD_MATCH"; + break; + case EGL_BAD_NATIVE_PIXMAP: + s = "EGL_BAD_NATIVE_PIXMAP"; + break; + case EGL_BAD_NATIVE_WINDOW: + s = "EGL_BAD_NATIVE_WINDOW"; + break; + case EGL_BAD_PARAMETER: + s = "EGL_BAD_PARAMETER"; + break; + case EGL_BAD_SURFACE: + s = "EGL_BAD_SURFACE"; + break; + case EGL_BAD_SCREEN_MESA: + s = "EGL_BAD_SCREEN_MESA"; + break; + case EGL_BAD_MODE_MESA: + s = "EGL_BAD_MODE_MESA"; + break; + default: + s = "other"; + } + /* XXX temporary */ + fprintf(stderr, "EGL user error 0x%x (%s) in %s\n", errCode, s, msg); + } +} diff --git a/src/egl/main/eglglobals.h b/src/egl/main/eglglobals.h new file mode 100644 index 00000000000..c16baa2d6bd --- /dev/null +++ b/src/egl/main/eglglobals.h @@ -0,0 +1,68 @@ +#ifndef EGLGLOBALS_INCLUDED +#define EGLGLOBALS_INCLUDED + +#include "egltypedefs.h" +#include "eglhash.h" + + +/** + * Per-thread info + */ +struct _egl_thread_info +{ + EGLint LastError; + _EGLContext *CurrentContext; + EGLenum CurrentAPI; +}; + + +/** + * Global library data + */ +struct _egl_global +{ + EGLBoolean Initialized; + + _EGLHashtable *Displays; + _EGLHashtable *Contexts; + _EGLHashtable *Surfaces; + + EGLScreenMESA FreeScreenHandle; + + /* XXX these may be temporary */ + EGLBoolean OpenGLESAPISupported; + EGLBoolean OpenVGAPISupported; + + /* XXX temporary - should be thread-specific data (TSD) */ + _EGLThreadInfo *ThreadInfo; +}; + + +extern struct _egl_global _eglGlobal; + + +extern void +_eglInitGlobals(void); + + +extern void +_eglDestroyGlobals(void); + + +extern _EGLThreadInfo * +_eglNewThreadInfo(void); + + +extern void +_eglDeleteThreadData(_EGLThreadInfo *t); + + +extern _EGLThreadInfo * +_eglGetCurrentThread(void); + + +extern void +_eglError(EGLint errCode, const char *msg); + + +#endif /* EGLGLOBALS_INCLUDED */ diff --git a/src/egl/main/eglhash.c b/src/egl/main/eglhash.c new file mode 100644 index 00000000000..8e3da2e9061 --- /dev/null +++ b/src/egl/main/eglhash.c @@ -0,0 +1,347 @@ +/** + * \file hash.c + * Generic hash table. + * + * This code taken from Mesa and adapted. + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include "eglhash.h" + + +#define TABLE_SIZE 1023 /**< Size of lookup table/array */ + +#define HASH_FUNC(K) ((K) % TABLE_SIZE) + + +/* + * Unfinished mutex stuff + */ + +typedef int _EGLMutex; + +static void +_eglInitMutex(_EGLMutex m) +{ +} + +static void +_eglDestroyMutex(_EGLMutex m) +{ +} + +static void +_eglLockMutex(_EGLMutex m) +{ +} + +static void +_eglUnlockMutex(_EGLMutex m) +{ +} + + + +typedef struct _egl_hashentry _EGLHashentry; + +struct _egl_hashentry +{ + EGLuint Key; /**< the entry's key */ + void *Data; /**< the entry's data */ + _EGLHashentry *Next; /**< pointer to next entry */ +}; + + +struct _egl_hashtable +{ + _EGLHashentry *Table[TABLE_SIZE]; /**< the lookup table */ + EGLuint MaxKey; /**< highest key inserted so far */ + _EGLMutex Mutex; /**< mutual exclusion lock */ +}; + + +/** + * Create a new hash table. + * + * \return pointer to a new, empty hash table. + */ +_EGLHashtable * +_eglNewHashTable(void) +{ + _EGLHashtable *table = (_EGLHashtable *) calloc(1, sizeof(_EGLHashtable)); + if (table) { + _eglInitMutex(table->Mutex); + table->MaxKey = 1; + } + return table; +} + + + +/** + * Delete a hash table. + * Frees each entry on the hash table and then the hash table structure itself. + * Note that the caller should have already traversed the table and deleted + * the objects in the table (i.e. We don't free the entries' data pointer). + * + * \param table the hash table to delete. + */ +void +_eglDeleteHashTable(_EGLHashtable *table) +{ + EGLuint i; + assert(table); + for (i = 0; i < TABLE_SIZE; i++) { + _EGLHashentry *entry = table->Table[i]; + while (entry) { + _EGLHashentry *next = entry->Next; + free(entry); + entry = next; + } + } + _eglDestroyMutex(table->Mutex); + free(table); +} + + + +/** + * Lookup an entry in the hash table. + * + * \param table the hash table. + * \param key the key. + * + * \return pointer to user's data or NULL if key not in table + */ +void * +_eglHashLookup(const _EGLHashtable *table, EGLuint key) +{ + EGLuint pos; + const _EGLHashentry *entry; + + assert(table); + + if (!key) + return NULL; + + pos = HASH_FUNC(key); + entry = table->Table[pos]; + while (entry) { + if (entry->Key == key) { + return entry->Data; + } + entry = entry->Next; + } + return NULL; +} + + + +/** + * Insert a key/pointer pair into the hash table. + * If an entry with this key already exists we'll replace the existing entry. + * + * \param table the hash table. + * \param key the key (not zero). + * \param data pointer to user data. + */ +void +_eglHashInsert(_EGLHashtable *table, EGLuint key, void *data) +{ + /* search for existing entry with this key */ + EGLuint pos; + _EGLHashentry *entry; + + assert(table); + assert(key); + + _eglLockMutex(table->Mutex); + + if (key > table->MaxKey) + table->MaxKey = key; + + pos = HASH_FUNC(key); + entry = table->Table[pos]; + while (entry) { + if (entry->Key == key) { + /* replace entry's data */ + entry->Data = data; + _eglUnlockMutex(table->Mutex); + return; + } + entry = entry->Next; + } + + /* alloc and insert new table entry */ + entry = (_EGLHashentry *) malloc(sizeof(_EGLHashentry)); + entry->Key = key; + entry->Data = data; + entry->Next = table->Table[pos]; + table->Table[pos] = entry; + + _eglUnlockMutex(table->Mutex); +} + + + +/** + * Remove an entry from the hash table. + * + * \param table the hash table. + * \param key key of entry to remove. + * + * While holding the hash table's lock, searches the entry with the matching + * key and unlinks it. + */ +void +_eglHashRemove(_EGLHashtable *table, EGLuint key) +{ + EGLuint pos; + _EGLHashentry *entry, *prev; + + assert(table); + assert(key); + + _eglLockMutex(table->Mutex); + + pos = HASH_FUNC(key); + prev = NULL; + entry = table->Table[pos]; + while (entry) { + if (entry->Key == key) { + /* found it! */ + if (prev) { + prev->Next = entry->Next; + } + else { + table->Table[pos] = entry->Next; + } + free(entry); + _eglUnlockMutex(table->Mutex); + return; + } + prev = entry; + entry = entry->Next; + } + + _eglUnlockMutex(table->Mutex); +} + + + +/** + * Get the key of the "first" entry in the hash table. + * + * This is used in the course of deleting all display lists when + * a context is destroyed. + * + * \param table the hash table + * + * \return key for the "first" entry in the hash table. + * + * While holding the lock, walks through all table positions until finding + * the first entry of the first non-empty one. + */ +EGLuint +_eglHashFirstEntry(_EGLHashtable *table) +{ + EGLuint pos; + assert(table); + _eglLockMutex(table->Mutex); + for (pos = 0; pos < TABLE_SIZE; pos++) { + if (table->Table[pos]) { + _eglUnlockMutex(table->Mutex); + return table->Table[pos]->Key; + } + } + _eglUnlockMutex(table->Mutex); + return 0; +} + + +/** + * Given a hash table key, return the next key. This is used to walk + * over all entries in the table. Note that the keys returned during + * walking won't be in any particular order. + * \return next hash key or 0 if end of table. + */ +EGLuint +_eglHashNextEntry(const _EGLHashtable *table, EGLuint key) +{ + const _EGLHashentry *entry; + EGLuint pos; + + assert(table); + assert(key); + + /* Find the entry with given key */ + pos = HASH_FUNC(key); + entry = table->Table[pos]; + while (entry) { + if (entry->Key == key) { + break; + } + entry = entry->Next; + } + + if (!entry) { + /* the key was not found, we can't find next entry */ + return 0; + } + + if (entry->Next) { + /* return next in linked list */ + return entry->Next->Key; + } + else { + /* look for next non-empty table slot */ + pos++; + while (pos < TABLE_SIZE) { + if (table->Table[pos]) { + return table->Table[pos]->Key; + } + pos++; + } + return 0; + } +} + + +/** + * Dump contents of hash table for debugging. + * + * \param table the hash table. + */ +void +_eglHashPrint(const _EGLHashtable *table) +{ + EGLuint i; + assert(table); + for (i = 0; i < TABLE_SIZE; i++) { + const _EGLHashentry *entry = table->Table[i]; + while (entry) { + printf("%u %p\n", entry->Key, entry->Data); + entry = entry->Next; + } + } +} + + + +/** + * Return a new, unused hash key. + */ +EGLuint +_eglHashGenKey(_EGLHashtable *table) +{ + EGLuint k; + + _eglLockMutex(table->Mutex); + k = table->MaxKey; + table->MaxKey++; + _eglUnlockMutex(table->Mutex); + return k; +} + diff --git a/src/egl/main/eglhash.h b/src/egl/main/eglhash.h new file mode 100644 index 00000000000..1d6db9598ce --- /dev/null +++ b/src/egl/main/eglhash.h @@ -0,0 +1,39 @@ +/** + * \file eglhash.h + * Generic hash table. + */ + + +#ifndef EGLHASH_INCLUDED +#define EGLHASH_INCLUDED + + +/* XXX move this? */ +typedef unsigned int EGLuint; + + +typedef struct _egl_hashtable _EGLHashtable; + + +extern _EGLHashtable *_eglNewHashTable(void); + +extern void _eglDeleteHashTable(_EGLHashtable *table); + +extern void *_eglHashLookup(const _EGLHashtable *table, EGLuint key); + +extern void _eglHashInsert(_EGLHashtable *table, EGLuint key, void *data); + +extern void _eglHashRemove(_EGLHashtable *table, EGLuint key); + +extern EGLuint _eglHashFirstEntry(_EGLHashtable *table); + +extern EGLuint _eglHashNextEntry(const _EGLHashtable *table, EGLuint key); + +extern void _eglHashPrint(const _EGLHashtable *table); + +extern EGLuint _eglHashGenKey(_EGLHashtable *table); + +extern void _egltest_hash_functions(void); + + +#endif /* EGLHASH_INCLUDED */ diff --git a/src/egl/main/egllog.c b/src/egl/main/egllog.c new file mode 100644 index 00000000000..59b1d2684e3 --- /dev/null +++ b/src/egl/main/egllog.c @@ -0,0 +1,57 @@ +/** + * Logging facility for debug/info messages. + */ + + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include "egllog.h" + +#define MAXSTRING 1000 + + +/* XXX init this with an env var or something */ +static EGLint ReportingLevel = _EGL_DEBUG; + + +/** + * Log a message to stderr. + * \param level one of _EGL_FATAL, _EGL_WARNING, _EGL_INFO, _EGL_DEBUG. + */ +void +_eglLog(EGLint level, const char *fmtStr, ...) +{ + va_list args; + char msg[MAXSTRING]; + const char *levelStr; + + if (level <= ReportingLevel) { + switch (level) { + case _EGL_FATAL: + levelStr = "Fatal"; + break; + case _EGL_WARNING: + levelStr = "Warning"; + break; + case _EGL_INFO: + levelStr = "Info"; + break; + case _EGL_DEBUG: + levelStr = "Debug"; + break; + default: + levelStr = ""; + } + + va_start(args, fmtStr); + vsnprintf(msg, MAXSTRING, fmtStr, args); + va_end(args); + + fprintf(stderr, "EGL %s: %s\n", levelStr, msg); + + if (level == _EGL_FATAL) { + exit(1); /* or abort()? */ + } + } +} diff --git a/src/egl/main/egllog.h b/src/egl/main/egllog.h new file mode 100644 index 00000000000..2fa352f155d --- /dev/null +++ b/src/egl/main/egllog.h @@ -0,0 +1,16 @@ +#ifndef EGLLOG_INCLUDED +#define EGLLOG_INCLUDED + +#include "egltypedefs.h" + +#define _EGL_FATAL 0 /* unrecoverable error */ +#define _EGL_WARNING 1 /* recoverable error/problem */ +#define _EGL_INFO 2 /* just useful info */ +#define _EGL_DEBUG 3 /* useful info for debugging */ + + +extern void +_eglLog(EGLint level, const char *fmtStr, ...); + + +#endif /* EGLLOG_INCLUDED */ diff --git a/src/egl/main/eglmode.c b/src/egl/main/eglmode.c new file mode 100644 index 00000000000..786432234bb --- /dev/null +++ b/src/egl/main/eglmode.c @@ -0,0 +1,431 @@ +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "egldisplay.h" +#include "egldriver.h" +#include "eglmode.h" +#include "eglglobals.h" +#include "eglscreen.h" + + +#define MIN2(A, B) (((A) < (B)) ? (A) : (B)) + + +static char * +my_strdup(const char *s) +{ + if (s) { + int l = strlen(s); + char *s2 = malloc(l + 1); + if (s2) + strcpy(s2, s); + return s2; + } + else { + return NULL; + } +} + + +/** + * Given an EGLModeMESA handle, return the corresponding _EGLMode object + * or null if non-existant. + */ +_EGLMode * +_eglLookupMode(EGLDisplay dpy, EGLModeMESA mode) +{ + const _EGLDisplay *disp = _eglLookupDisplay(dpy); + EGLint scrnum; + + /* loop over all screens on the display */ + for (scrnum = 0; scrnum < disp->NumScreens; scrnum++) { + const _EGLScreen *scrn = disp->Screens[scrnum]; + EGLint i; + /* search list of modes for handle */ + for (i = 0; i < scrn->NumModes; i++) { + if (scrn->Modes[i].Handle == mode) { + return scrn->Modes + i; + } + } + } + + return NULL; +} + + +/** + * Add a new mode with the given attributes (width, height, depth, refreshRate) + * to the given screen. + * Assign a new mode ID/handle to the mode as well. + * \return pointer to the new _EGLMode + */ +_EGLMode * +_eglAddNewMode(_EGLScreen *screen, EGLint width, EGLint height, + EGLint refreshRate, const char *name) +{ + EGLint n; + _EGLMode *newModes; + + assert(screen); + assert(width > 0); + assert(height > 0); + assert(refreshRate > 0); + + n = screen->NumModes; + newModes = (_EGLMode *) realloc(screen->Modes, (n+1) * sizeof(_EGLMode)); + if (newModes) { + screen->Modes = newModes; + screen->Modes[n].Handle = n + 1; + screen->Modes[n].Width = width; + screen->Modes[n].Height = height; + screen->Modes[n].RefreshRate = refreshRate; + screen->Modes[n].Optimal = EGL_FALSE; + screen->Modes[n].Interlaced = EGL_FALSE; + screen->Modes[n].Name = my_strdup(name); + screen->NumModes++; + return screen->Modes + n; + } + else { + return NULL; + } +} + + + +/** + * Parse the attrib_list to fill in the fields of the given _eglMode + * Return EGL_FALSE if any errors, EGL_TRUE otherwise. + */ +static EGLBoolean +_eglParseModeAttribs(_EGLMode *mode, const EGLint *attrib_list) +{ + EGLint i; + + /* init all attribs to EGL_DONT_CARE */ + mode->Handle = EGL_DONT_CARE; + mode->Width = EGL_DONT_CARE; + mode->Height = EGL_DONT_CARE; + mode->RefreshRate = EGL_DONT_CARE; + mode->Optimal = EGL_DONT_CARE; + mode->Interlaced = EGL_DONT_CARE; + mode->Name = NULL; + + for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { + switch (attrib_list[i]) { + case EGL_MODE_ID_MESA: + mode->Handle = attrib_list[++i]; + if (mode->Handle <= 0) { + _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(handle)"); + return EGL_FALSE; + } + break; + case EGL_WIDTH: + mode->Width = attrib_list[++i]; + if (mode->Width <= 0) { + _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(width)"); + return EGL_FALSE; + } + break; + case EGL_HEIGHT: + mode->Height = attrib_list[++i]; + if (mode->Height <= 0) { + _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(height)"); + return EGL_FALSE; + } + break; + case EGL_REFRESH_RATE_MESA: + mode->RefreshRate = attrib_list[++i]; + if (mode->RefreshRate <= 0) { + _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(refresh rate)"); + return EGL_FALSE; + } + break; + case EGL_INTERLACED_MESA: + mode->Interlaced = attrib_list[++i]; + if (mode->Interlaced != EGL_TRUE && mode->Interlaced != EGL_FALSE) { + _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(interlaced)"); + return EGL_FALSE; + } + break; + case EGL_OPTIMAL_MESA: + mode->Optimal = attrib_list[++i]; + if (mode->Optimal != EGL_TRUE && mode->Optimal != EGL_FALSE) { + _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(optimal)"); + return EGL_FALSE; + } + break; + default: + _eglError(EGL_BAD_ATTRIBUTE, "eglChooseModeMESA"); + return EGL_FALSE; + } + } + return EGL_TRUE; +} + + +/** + * Determine if the candidate mode's attributes are at least as good + * as the minimal mode's. + * \return EGL_TRUE if qualifies, EGL_FALSE otherwise + */ +static EGLBoolean +_eglModeQualifies(const _EGLMode *c, const _EGLMode *min) +{ + if (min->Handle != EGL_DONT_CARE && c->Handle != min->Handle) + return EGL_FALSE; + if (min->Width != EGL_DONT_CARE && c->Width < min->Width) + return EGL_FALSE; + if (min->Height != EGL_DONT_CARE && c->Height < min->Height) + return EGL_FALSE; + if (min->RefreshRate != EGL_DONT_CARE && c->RefreshRate < min->RefreshRate) + return EGL_FALSE; + if (min->Optimal != EGL_DONT_CARE && c->Optimal != min->Optimal) + return EGL_FALSE; + if (min->Interlaced != EGL_DONT_CARE && c->Interlaced != min->Interlaced) + return EGL_FALSE; + + return EGL_TRUE; +} + + +/** + * Return value of given mode attribute, or -1 if bad attrib. + */ +static EGLint +getModeAttrib(const _EGLMode *m, EGLint attrib) +{ + switch (attrib) { + case EGL_MODE_ID_MESA: + return m->Handle; + case EGL_WIDTH: + return m->Width; + case EGL_HEIGHT: + return m->Height; + case EGL_REFRESH_RATE_MESA: + return m->RefreshRate; + case EGL_OPTIMAL_MESA: + return m->Optimal; + case EGL_INTERLACED_MESA: + return m->Interlaced; + default: + return -1; + } +} + + +#define SMALLER 1 +#define LARGER 2 + +struct sort_info { + EGLint Attrib; + EGLint Order; /* SMALLER or LARGER */ +}; + +/* the order of these entries is the priority */ +static struct sort_info SortInfo[] = { + { EGL_OPTIMAL_MESA, LARGER }, + { EGL_INTERLACED_MESA, SMALLER }, + { EGL_WIDTH, LARGER }, + { EGL_HEIGHT, LARGER }, + { EGL_REFRESH_RATE_MESA, LARGER }, + { EGL_MODE_ID_MESA, SMALLER }, + { 0, 0 } +}; + + +/** + * Compare modes 'a' and 'b' and return -1 if a belongs before b, or 1 if a + * belongs after b, or 0 if they're equal. + * Used by qsort(). + */ +static int +_eglCompareModes(const void *a, const void *b) +{ + const _EGLMode *aMode = *((const _EGLMode **) a); + const _EGLMode *bMode = *((const _EGLMode **) b); + EGLint i; + + for (i = 0; SortInfo[i].Attrib; i++) { + const EGLint aVal = getModeAttrib(aMode, SortInfo[i].Attrib); + const EGLint bVal = getModeAttrib(bMode, SortInfo[i].Attrib); + if (aVal == bVal) { + /* a tie */ + continue; + } + else if (SortInfo[i].Order == SMALLER) { + return (aVal < bVal) ? -1 : 1; + } + else if (SortInfo[i].Order == LARGER) { + return (aVal > bVal) ? -1 : 1; + } + } + + /* all attributes identical */ + return 0; +} + + +/** + * Search for EGLModes which match the given attribute list. + * Called via eglChooseModeMESA API function. + */ +EGLBoolean +_eglChooseModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, + const EGLint *attrib_list, EGLModeMESA *modes, + EGLint modes_size, EGLint *num_modes) +{ + const _EGLScreen *scrn = _eglLookupScreen(dpy, screen); + _EGLMode **modeList, min; + EGLint i, count; + + if (!scrn) { + _eglError(EGL_BAD_SCREEN_MESA, "eglChooseModeMESA"); + return EGL_FALSE; + } + + if (!_eglParseModeAttribs(&min, attrib_list)) { + /* error code will have been recorded */ + return EGL_FALSE; + } + + /* allocate array of mode pointers */ + modeList = (_EGLMode **) malloc(modes_size * sizeof(_EGLMode *)); + if (!modeList) { + _eglError(EGL_BAD_MODE_MESA, "eglChooseModeMESA(out of memory)"); + return EGL_FALSE; + } + + /* make array of pointers to qualifying modes */ + for (i = count = 0; i < scrn->NumModes && count < modes_size; i++) { + if (_eglModeQualifies(scrn->Modes + i, &min)) { + modeList[count++] = scrn->Modes + i; + } + } + + /* sort array of pointers */ + qsort(modeList, count, sizeof(_EGLMode *), _eglCompareModes); + + /* copy mode handles to output array */ + for (i = 0; i < count; i++) { + modes[i] = modeList[i]->Handle; + } + + free(modeList); + + *num_modes = count; + + return EGL_TRUE; +} + + + +/** + * Return all possible modes for the given screen. No sorting of results. + * Called via eglGetModesMESA() API function. + */ +EGLBoolean +_eglGetModesMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, + EGLModeMESA *modes, EGLint modes_size, EGLint *num_modes) +{ + _EGLScreen *scrn = _eglLookupScreen(dpy, screen); + + if (!scrn) { + _eglError(EGL_BAD_SCREEN_MESA, "eglGetModesMESA"); + return EGL_FALSE; + } + + if (modes) { + EGLint i; + *num_modes = MIN2(scrn->NumModes, modes_size); + for (i = 0; i < *num_modes; i++) { + modes[i] = scrn->Modes[i].Handle; + } + } + else { + /* just return total number of supported modes */ + *num_modes = scrn->NumModes; + } + + return EGL_TRUE; +} + + +/** + * Query an attribute of a mode. + */ +EGLBoolean +_eglGetModeAttribMESA(_EGLDriver *drv, EGLDisplay dpy, + EGLModeMESA mode, EGLint attribute, EGLint *value) +{ + _EGLMode *m = _eglLookupMode(dpy, mode); + EGLint v; + + if (!m) { + _eglError(EGL_BAD_MODE_MESA, "eglGetModeAttribMESA"); + return EGL_FALSE; + } + + v = getModeAttrib(m, attribute); + if (v < 0) { + _eglError(EGL_BAD_ATTRIBUTE, "eglGetModeAttribMESA"); + return EGL_FALSE; + } + *value = v; + return EGL_TRUE; +} + + +/** + * Return human-readable string for given mode. + * This is the default function called by eglQueryModeStringMESA(). + */ +const char * +_eglQueryModeStringMESA(_EGLDriver *drv, EGLDisplay dpy, EGLModeMESA mode) +{ + _EGLMode *m = _eglLookupMode(dpy, mode); + if (!m) { + _eglError(EGL_BAD_MODE_MESA, "eglQueryModeStringMESA"); + return NULL; + } + return m->Name; +} + + +#if 0 +static int +_eglRand(int max) +{ + return rand() % max; +} + +void +_eglTestModeModule(void) +{ + EGLint count = 30; + _EGLMode *modes = (_EGLMode *) malloc(count * sizeof(_EGLMode)); + _EGLMode **modeList = (_EGLMode **) malloc(count * sizeof(_EGLMode*)); + EGLint i; + + for (i = 0; i < count; i++) { + modes[i].Handle = _eglRand(20); + modes[i].Width = 512 + 256 * _eglRand(2); + modes[i].Height = 512 + 256 * _eglRand(2); + modes[i].RefreshRate = 50 + 5 * _eglRand(3); + modes[i].Interlaced = _eglRand(2); + modes[i].Optimal = _eglRand(4) == 0; + modeList[i] = modes + i; + } + + /* sort array of pointers */ + qsort(modeList, count, sizeof(_EGLMode *), compareModes); + + for (i = 0; i < count; i++) { + _EGLMode *m = modeList[i]; + printf("%2d: %3d %4d x %4d @ %3d opt %d int %d\n", i, + m->Handle, m->Width, m->Height, m->RefreshRate, + m->Optimal, m->Interlaced); + } +} +#endif diff --git a/src/egl/main/eglmode.h b/src/egl/main/eglmode.h new file mode 100644 index 00000000000..e70da857595 --- /dev/null +++ b/src/egl/main/eglmode.h @@ -0,0 +1,54 @@ +#ifndef EGLMODE_INCLUDED +#define EGLMODE_INCLUDED + +#include "egltypedefs.h" + + +/** + * Data structure which corresponds to an EGLModeMESA. + */ +struct _egl_mode +{ + EGLModeMESA Handle; /* the public/opaque handle which names this mode */ + EGLint Width, Height; /* size in pixels */ + EGLint RefreshRate; /* rate * 1000.0 */ + EGLint Optimal; + EGLint Interlaced; + const char *Name; + + /* Other possible attributes */ + /* interlaced */ + /* external sync */ +}; + + +extern _EGLMode * +_eglLookupMode(EGLDisplay dpy, EGLModeMESA mode); + + +extern _EGLMode * +_eglAddNewMode(_EGLScreen *screen, EGLint width, EGLint height, + EGLint refreshRate, const char *name); + + +extern EGLBoolean +_eglChooseModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, + const EGLint *attrib_list, EGLModeMESA *modes, + EGLint modes_size, EGLint *num_modes); + + +extern EGLBoolean +_eglGetModesMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, + EGLModeMESA *modes, EGLint modes_size, EGLint *num_modes); + + +extern EGLBoolean +_eglGetModeAttribMESA(_EGLDriver *drv, EGLDisplay dpy, EGLModeMESA mode, + EGLint attribute, EGLint *value); + + +extern const char * +_eglQueryModeStringMESA(_EGLDriver *drv, EGLDisplay dpy, EGLModeMESA mode); + + +#endif /* EGLMODE_INCLUDED */ diff --git a/src/egl/main/eglscreen.c b/src/egl/main/eglscreen.c new file mode 100644 index 00000000000..9c9a8377bf2 --- /dev/null +++ b/src/egl/main/eglscreen.c @@ -0,0 +1,328 @@ +/* + * Ideas for screen management extension to EGL. + * + * Each EGLDisplay has one or more screens (CRTs, Flat Panels, etc). + * The screens' handles can be obtained with eglGetScreensMESA(). + * + * A new kind of EGLSurface is possible- one which can be directly scanned + * out on a screen. Such a surface is created with eglCreateScreenSurface(). + * + * To actually display a screen surface on a screen, the eglShowSurface() + * function is called. + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "egldisplay.h" +#include "eglglobals.h" +#include "eglmode.h" +#include "eglconfig.h" +#include "eglsurface.h" +#include "eglscreen.h" + + +/** + * Return a new screen handle/ID. + * NOTE: we never reuse these! + */ +EGLScreenMESA +_eglAllocScreenHandle(void) +{ + EGLScreenMESA s = _eglGlobal.FreeScreenHandle; + _eglGlobal.FreeScreenHandle++; + return s; +} + + +/** + * Initialize an _EGLScreen object to default values. + */ +void +_eglInitScreen(_EGLScreen *screen) +{ + memset(screen, 0, sizeof(_EGLScreen)); + screen->StepX = 1; + screen->StepY = 1; +} + + +/** + * Given a public screen handle, return the internal _EGLScreen object. + */ +_EGLScreen * +_eglLookupScreen(EGLDisplay dpy, EGLScreenMESA screen) +{ + EGLint i; + _EGLDisplay *display = _eglLookupDisplay(dpy); + + if (!display) + return NULL; + + for (i = 0; i < display->NumScreens; i++) { + if (display->Screens[i]->Handle == screen) + return display->Screens[i]; + } + return NULL; +} + + +/** + * Add the given _EGLScreen to the display's list of screens. + */ +void +_eglAddScreen(_EGLDisplay *display, _EGLScreen *screen) +{ + EGLint n; + + assert(display); + assert(screen); + + screen->Handle = _eglAllocScreenHandle(); + n = display->NumScreens; + display->Screens = realloc(display->Screens, (n+1) * sizeof(_EGLScreen *)); + display->Screens[n] = screen; + display->NumScreens++; +} + + + +EGLBoolean +_eglGetScreensMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA *screens, + EGLint max_screens, EGLint *num_screens) +{ + _EGLDisplay *display = _eglLookupDisplay(dpy); + EGLint n; + + if (!display) { + _eglError(EGL_BAD_DISPLAY, "eglGetScreensMESA"); + return EGL_FALSE; + } + + if (display->NumScreens > max_screens) { + n = max_screens; + } + else { + n = display->NumScreens; + } + + if (screens) { + EGLint i; + for (i = 0; i < n; i++) + screens[i] = display->Screens[i]->Handle; + } + if (num_screens) + *num_screens = n; + + return EGL_TRUE; +} + + +/** + * Example function - drivers should do a proper implementation. + */ +EGLSurface +_eglCreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list) +{ +#if 0 /* THIS IS JUST EXAMPLE CODE */ + _EGLSurface *surf; + + surf = (_EGLSurface *) calloc(1, sizeof(_EGLSurface)); + if (!surf) + return EGL_NO_SURFACE; + + if (!_eglInitSurface(drv, dpy, surf, EGL_SCREEN_BIT_MESA, + config, attrib_list)) { + free(surf); + return EGL_NO_SURFACE; + } + + _eglSaveSurface(surf); + + return surf->Handle; +#endif + return EGL_NO_SURFACE; +} + + +/** + * Show the given surface on the named screen. + * If surface is EGL_NO_SURFACE, disable the screen's output. + * + * This is just a placeholder function; drivers will always override + * this with code that _really_ shows the surface. + */ +EGLBoolean +_eglShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, + EGLScreenMESA screen, EGLSurface surface, + EGLModeMESA m) +{ + _EGLScreen *scrn = _eglLookupScreen(dpy, screen); + _EGLMode *mode = _eglLookupMode(dpy, m); + + if (!scrn) { + _eglError(EGL_BAD_SCREEN_MESA, "eglShowSurfaceMESA"); + return EGL_FALSE; + } + if (!mode && (m != EGL_NO_MODE_MESA )) { + _eglError(EGL_BAD_MODE_MESA, "eglShowSurfaceMESA"); + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) { + scrn->CurrentSurface = NULL; + } + else { + _EGLSurface *surf = _eglLookupSurface(surface); + if (!surf || surf->Type != EGL_SCREEN_BIT_MESA) { + _eglError(EGL_BAD_SURFACE, "eglShowSurfaceMESA"); + return EGL_FALSE; + } + if (surf->Width < mode->Width || surf->Height < mode->Height) { + _eglError(EGL_BAD_SURFACE, + "eglShowSurfaceMESA(surface smaller than screen size)"); + return EGL_FALSE; + } + + scrn->CurrentSurface = surf; + scrn->CurrentMode = mode; + } + return EGL_TRUE; +} + + +/** + * Set a screen's current display mode. + * Note: mode = EGL_NO_MODE is valid (turns off the screen) + * + * This is just a placeholder function; drivers will always override + * this with code that _really_ sets the mode. + */ +EGLBoolean +_eglScreenModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, + EGLModeMESA mode) +{ + _EGLScreen *scrn = _eglLookupScreen(dpy, screen); + + if (!scrn) { + _eglError(EGL_BAD_SCREEN_MESA, "eglScreenModeMESA"); + return EGL_FALSE; + } + + scrn->CurrentMode = _eglLookupMode(dpy, mode); + + return EGL_TRUE; +} + + +/** + * Set a screen's surface origin. + */ +EGLBoolean +_eglScreenPositionMESA(_EGLDriver *drv, EGLDisplay dpy, + EGLScreenMESA screen, EGLint x, EGLint y) +{ + _EGLScreen *scrn = _eglLookupScreen(dpy, screen); + if (!scrn) { + _eglError(EGL_BAD_SCREEN_MESA, "eglScreenPositionMESA"); + return EGL_FALSE; + } + + scrn->OriginX = x; + scrn->OriginY = y; + + return EGL_TRUE; +} + + +/** + * Query a screen's current surface. + */ +EGLBoolean +_eglQueryScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, + EGLScreenMESA screen, EGLSurface *surface) +{ + const _EGLScreen *scrn = _eglLookupScreen(dpy, screen); + if (scrn->CurrentSurface) + *surface = scrn->CurrentSurface->Handle; + else + *surface = EGL_NO_SURFACE; + return EGL_TRUE; +} + + +/** + * Query a screen's current mode. + */ +EGLBoolean +_eglQueryScreenModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, + EGLModeMESA *mode) +{ + const _EGLScreen *scrn = _eglLookupScreen(dpy, screen); + if (scrn->CurrentMode) + *mode = scrn->CurrentMode->Handle; + else + *mode = EGL_NO_MODE_MESA; + return EGL_TRUE; +} + + +EGLBoolean +_eglQueryScreenMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, + EGLint attribute, EGLint *value) +{ + const _EGLScreen *scrn = _eglLookupScreen(dpy, screen); + + if (!scrn) { + _eglError(EGL_BAD_SCREEN_MESA, "eglQueryScreenMESA"); + return EGL_FALSE; + } + + switch (attribute) { + case EGL_SCREEN_POSITION_MESA: + value[0] = scrn->OriginX; + value[1] = scrn->OriginY; + break; + case EGL_SCREEN_POSITION_GRANULARITY_MESA: + value[0] = scrn->StepX; + value[1] = scrn->StepY; + break; + default: + _eglError(EGL_BAD_ATTRIBUTE, "eglQueryScreenMESA"); + return EGL_FALSE; + } + + return EGL_TRUE; +} + + +/** + * Delete the modes associated with given screen. + */ +void +_eglDestroyScreenModes(_EGLScreen *scrn) +{ + EGLint i; + for (i = 0; i < scrn->NumModes; i++) { + if (scrn->Modes[i].Name) + free((char *) scrn->Modes[i].Name); /* cast away const */ + } + if (scrn->Modes) + free(scrn->Modes); + scrn->Modes = NULL; + scrn->NumModes = 0; +} + + +/** + * Default fallback routine - drivers should usually override this. + */ +void +_eglDestroyScreen(_EGLScreen *scrn) +{ + _eglDestroyScreenModes(scrn); + free(scrn); +} + diff --git a/src/egl/main/eglscreen.h b/src/egl/main/eglscreen.h new file mode 100644 index 00000000000..833439b4107 --- /dev/null +++ b/src/egl/main/eglscreen.h @@ -0,0 +1,90 @@ +#ifndef EGLSCREEN_INCLUDED +#define EGLSCREEN_INCLUDED + + +/** + * Per-screen information. + * Note that an EGL screen doesn't have a size. A screen may be set to + * one of several display modes (width/height/scanrate). The screen + * then displays a drawing surface. The drawing surface must be at least + * as large as the display mode's resolution. If it's larger, the + * OriginX and OriginY fields control what part of the surface is visible + * on the screen. + */ +struct _egl_screen +{ + EGLScreenMESA Handle; /* The public/opaque handle which names this object */ + + _EGLMode *CurrentMode; + _EGLSurface *CurrentSurface; + + EGLint OriginX, OriginY; /**< Origin of scan-out region w.r.t. surface */ + EGLint StepX, StepY; /**< Screen position/origin granularity */ + + EGLint NumModes; + _EGLMode *Modes; /**< array [NumModes] */ +}; + + +extern EGLScreenMESA +_eglAllocScreenHandle(void); + + +extern void +_eglInitScreen(_EGLScreen *screen); + + +extern _EGLScreen * +_eglLookupScreen(EGLDisplay dpy, EGLScreenMESA screen); + + +extern void +_eglAddScreen(_EGLDisplay *display, _EGLScreen *screen); + + +extern EGLBoolean +_eglGetScreensMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA *screens, EGLint max_screens, EGLint *num_screens); + + +extern EGLSurface +_eglCreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); + + +extern EGLBoolean +_eglShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLSurface surface, EGLModeMESA mode); + + +extern EGLBoolean +_eglScreenModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLModeMESA mode); + + +extern EGLBoolean +_eglScreenPositionMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLint x, EGLint y); + + +extern EGLBoolean +_eglQueryDisplayMESA(_EGLDriver *drv, EGLDisplay dpy, EGLint attribute, EGLint *value); + + +extern EGLBoolean +_eglQueryScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, + EGLScreenMESA screen, EGLSurface *surface); + + +extern EGLBoolean +_eglQueryScreenModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLModeMESA *mode); + + +extern EGLBoolean +_eglQueryScreenMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLint attribute, EGLint *value); + + +extern void +_eglDestroyScreenModes(_EGLScreen *scrn); + + +extern void +_eglDestroyScreen(_EGLScreen *scrn); + + +#endif /* EGLSCREEN_INCLUDED */ diff --git a/src/egl/main/eglsurface.c b/src/egl/main/eglsurface.c new file mode 100644 index 00000000000..874f318e966 --- /dev/null +++ b/src/egl/main/eglsurface.c @@ -0,0 +1,530 @@ +/** + * Surface-related functions. + */ + + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include "eglcontext.h" +#include "eglconfig.h" +#include "eglglobals.h" +#include "eglhash.h" +#include "egllog.h" +#include "eglsurface.h" + + +/** + * Do error check on parameters and initialize the given _EGLSurface object. + * \return EGL_TRUE if no errors, EGL_FALSE otherwise. + */ +EGLBoolean +_eglInitSurface(_EGLDriver *drv, EGLDisplay dpy, + _EGLSurface *surf, EGLint type, EGLConfig config, + const EGLint *attrib_list) +{ + const char *func; + _EGLConfig *conf; + EGLint width = 0, height = 0, largest = 0; + EGLint texFormat = 0, texTarget = 0, mipmapTex = 0; + EGLint renderBuffer = EGL_BACK_BUFFER; +#ifdef EGL_VERSION_1_2 + EGLint colorspace = EGL_COLORSPACE_sRGB; + EGLint alphaFormat = EGL_ALPHA_FORMAT_NONPRE; +#endif + EGLint i; + + switch (type) { + case EGL_WINDOW_BIT: + func = "eglCreateWindowSurface"; + break; + case EGL_PIXMAP_BIT: + func = "eglCreatePixmapSurface"; + renderBuffer = EGL_SINGLE_BUFFER; + break; + case EGL_PBUFFER_BIT: + func = "eglCreatePBufferSurface"; + break; + case EGL_SCREEN_BIT_MESA: + func = "eglCreateScreenSurface"; + renderBuffer = EGL_SINGLE_BUFFER; /* XXX correct? */ + break; + default: + _eglLog(_EGL_WARNING, "Bad type in _eglInitSurface"); + return EGL_FALSE; + } + + conf = _eglLookupConfig(drv, dpy, config); + if (!conf) { + _eglError(EGL_BAD_CONFIG, func); + return EGL_FALSE; + } + + /* + * Parse attribute list. Different kinds of surfaces support different + * attributes. + */ + for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { + switch (attrib_list[i]) { + case EGL_WIDTH: + if (type == EGL_PBUFFER_BIT || type == EGL_SCREEN_BIT_MESA) { + width = attrib_list[++i]; + } + else { + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + break; + case EGL_HEIGHT: + if (type == EGL_PBUFFER_BIT || type == EGL_SCREEN_BIT_MESA) { + height = attrib_list[++i]; + } + else { + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + break; + case EGL_LARGEST_PBUFFER: + if (type == EGL_PBUFFER_BIT) { + largest = attrib_list[++i]; + } + else { + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + break; + case EGL_TEXTURE_FORMAT: + if (type == EGL_PBUFFER_BIT) { + texFormat = attrib_list[++i]; + } + else { + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + break; + case EGL_TEXTURE_TARGET: + if (type == EGL_PBUFFER_BIT) { + texTarget = attrib_list[++i]; + } + else { + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + break; + case EGL_MIPMAP_TEXTURE: + if (type == EGL_PBUFFER_BIT) { + mipmapTex = attrib_list[++i]; + } + else { + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + break; +#ifdef EGL_VERSION_1_2 + case EGL_RENDER_BUFFER: + if (type == EGL_WINDOW_BIT) { + renderBuffer = attrib_list[++i]; + if (renderBuffer != EGL_BACK_BUFFER && + renderBuffer != EGL_SINGLE_BUFFER) { + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + } + else { + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + break; + case EGL_COLORSPACE: + if (type == EGL_WINDOW_BIT || + type == EGL_PBUFFER_BIT || + type == EGL_PIXMAP_BIT) { + colorspace = attrib_list[++i]; + if (colorspace != EGL_COLORSPACE_sRGB && + colorspace != EGL_COLORSPACE_LINEAR) { + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + } + else { + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + break; + case EGL_ALPHA_FORMAT: + if (type == EGL_WINDOW_BIT || + type == EGL_PBUFFER_BIT || + type == EGL_PIXMAP_BIT) { + alphaFormat = attrib_list[++i]; + if (alphaFormat != EGL_ALPHA_FORMAT_NONPRE && + alphaFormat != EGL_ALPHA_FORMAT_PRE) { + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + } + else { + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + break; + +#endif /* EGL_VERSION_1_2 */ + default: + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + } + + if (width <= 0 || height <= 0) { + _eglError(EGL_BAD_ATTRIBUTE, func); + return EGL_FALSE; + } + + memset(surf, 0, sizeof(_EGLSurface)); + surf->Config = conf; + surf->Type = type; + surf->Width = width; + surf->Height = height; + surf->TextureFormat = texFormat; + surf->TextureTarget = texTarget; + surf->MipmapTexture = mipmapTex; + surf->MipmapLevel = 0; + surf->SwapInterval = 0; +#ifdef EGL_VERSION_1_2 + surf->SwapBehavior = EGL_BUFFER_DESTROYED; /* XXX ok? */ + surf->HorizontalResolution = EGL_UNKNOWN; /* set by caller */ + surf->VerticalResolution = EGL_UNKNOWN; /* set by caller */ + surf->AspectRatio = EGL_UNKNOWN; /* set by caller */ + surf->RenderBuffer = renderBuffer; + surf->AlphaFormat = alphaFormat; + surf->Colorspace = colorspace; +#endif + + return EGL_TRUE; +} + + +void +_eglSaveSurface(_EGLSurface *surf) +{ + assert(surf); + assert(!surf->Handle); + surf->Handle = _eglHashGenKey(_eglGlobal.Contexts); + assert(surf->Handle); + _eglHashInsert(_eglGlobal.Surfaces, surf->Handle, surf); +} + + +void +_eglRemoveSurface(_EGLSurface *surf) +{ + _eglHashRemove(_eglGlobal.Surfaces, surf->Handle); +} + + +_EGLSurface * +_eglLookupSurface(EGLSurface surf) +{ + _EGLSurface *c = (_EGLSurface *) _eglHashLookup(_eglGlobal.Surfaces, surf); + return c; +} + + +_EGLSurface * +_eglGetCurrentSurface(EGLint readdraw) +{ + _EGLContext *ctx = _eglGetCurrentContext(); + if (ctx) { + switch (readdraw) { + case EGL_DRAW: + return ctx->DrawSurface; + case EGL_READ: + return ctx->ReadSurface; + default: + return NULL; + } + } + return NULL; +} + + +EGLBoolean +_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw) +{ + /* Basically just do error checking here. Drivers have to do the + * actual buffer swap. + */ + _EGLContext *context = _eglGetCurrentContext(); + _EGLSurface *surface = _eglLookupSurface(draw); + if (context && context->DrawSurface != surface) { + _eglError(EGL_BAD_SURFACE, "eglSwapBuffers"); + return EGL_FALSE; + } + if (surface == NULL) { + _eglError(EGL_BAD_SURFACE, "eglSwapBuffers"); + return EGL_FALSE; + } + return EGL_TRUE; +} + + +EGLBoolean +_eglCopyBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, + NativePixmapType target) +{ + /* copy surface to native pixmap */ + /* All implementation burdon for this is in the device driver */ + return EGL_FALSE; +} + + +EGLBoolean +_eglQuerySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surf, + EGLint attribute, EGLint *value) +{ + _EGLSurface *surface = _eglLookupSurface(surf); + if (surface == NULL) { + _eglError(EGL_BAD_SURFACE, "eglQuerySurface"); + return EGL_FALSE; + } + switch (attribute) { + case EGL_WIDTH: + *value = surface->Width; + return EGL_TRUE; + case EGL_HEIGHT: + *value = surface->Height; + return EGL_TRUE; + case EGL_CONFIG_ID: + *value = GET_CONFIG_ATTRIB(surface->Config, EGL_CONFIG_ID); + return EGL_TRUE; + /*XXX case EGL_LARGEST_PBUFFER:*/ + case EGL_SURFACE_TYPE: + *value = surface->Type; + return EGL_TRUE; +#ifdef EGL_VERSION_1_1 + case EGL_TEXTURE_FORMAT: + /* texture attributes: only for pbuffers, no error otherwise */ + if (surface->Type == EGL_PBUFFER_BIT) + *value = surface->TextureFormat; + return EGL_TRUE; + case EGL_TEXTURE_TARGET: + if (surface->Type == EGL_PBUFFER_BIT) + *value = surface->TextureTarget; + return EGL_TRUE; + case EGL_MIPMAP_TEXTURE: + if (surface->Type == EGL_PBUFFER_BIT) + *value = surface->MipmapTexture; + return EGL_TRUE; + case EGL_MIPMAP_LEVEL: + if (surface->Type == EGL_PBUFFER_BIT) + *value = surface->MipmapLevel; + return EGL_TRUE; +#endif /* EGL_VERSION_1_1 */ +#ifdef EGL_VERSION_1_2 + case EGL_SWAP_BEHAVIOR: + *value = surface->SwapBehavior; + return EGL_TRUE; + case EGL_RENDER_BUFFER: + *value = surface->RenderBuffer; + return EGL_TRUE; + case EGL_PIXEL_ASPECT_RATIO: + *value = surface->AspectRatio; + return EGL_TRUE; + case EGL_HORIZONTAL_RESOLUTION: + *value = surface->HorizontalResolution; + return EGL_TRUE; + case EGL_VERTICAL_RESOLUTION: + *value = surface->VerticalResolution; + return EGL_TRUE; + case EGL_ALPHA_FORMAT: + *value = surface->AlphaFormat; + return EGL_TRUE; + case EGL_COLORSPACE: + *value = surface->Colorspace; + return EGL_TRUE; +#endif /* EGL_VERSION_1_2 */ + default: + _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface"); + return EGL_FALSE; + } +} + + +/** + * Example function - drivers should do a proper implementation. + */ +EGLSurface +_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + NativeWindowType window, const EGLint *attrib_list) +{ +#if 0 /* THIS IS JUST EXAMPLE CODE */ + _EGLSurface *surf; + + surf = (_EGLSurface *) calloc(1, sizeof(_EGLSurface)); + if (!surf) + return EGL_NO_SURFACE; + + if (!_eglInitSurface(drv, dpy, surf, EGL_WINDOW_BIT, config, attrib_list)) { + free(surf); + return EGL_NO_SURFACE; + } + + _eglSaveSurface(surf); + + return surf->Handle; +#endif + return EGL_NO_SURFACE; +} + + +/** + * Example function - drivers should do a proper implementation. + */ +EGLSurface +_eglCreatePixmapSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + NativePixmapType pixmap, const EGLint *attrib_list) +{ +#if 0 /* THIS IS JUST EXAMPLE CODE */ + _EGLSurface *surf; + + surf = (_EGLSurface *) calloc(1, sizeof(_EGLSurface)); + if (!surf) + return EGL_NO_SURFACE; + + if (!_eglInitSurface(drv, dpy, surf, EGL_PIXMAP_BIT, config, attrib_list)) { + free(surf); + return EGL_NO_SURFACE; + } + + _eglSaveSurface(surf); + + return surf->Handle; +#endif + return EGL_NO_SURFACE; +} + + +/** + * Example function - drivers should do a proper implementation. + */ +EGLSurface +_eglCreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list) +{ +#if 0 /* THIS IS JUST EXAMPLE CODE */ + _EGLSurface *surf; + + surf = (_EGLSurface *) calloc(1, sizeof(_EGLSurface)); + if (!surf) + return EGL_NO_SURFACE; + + if (!_eglInitSurface(drv, dpy, surf, EGL_PBUFFER_BIT, config, attrib_list)) { + free(surf); + return EGL_NO_SURFACE; + } + + _eglSaveSurface(surf); + + return surf->Handle; +#endif + return EGL_NO_SURFACE; +} + + +/** + * Default fallback routine - drivers should usually override this. + */ +EGLBoolean +_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface) +{ + _EGLSurface *surf = _eglLookupSurface(surface); + if (surf) { + _eglHashRemove(_eglGlobal.Surfaces, surface); + if (surf->IsBound) { + surf->DeletePending = EGL_TRUE; + } + else { + free(surf); + } + return EGL_TRUE; + } + else { + _eglError(EGL_BAD_SURFACE, "eglDestroySurface"); + return EGL_FALSE; + } +} + + +/** + * Default fallback routine - drivers might override this. + */ +EGLBoolean +_eglSurfaceAttrib(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surf, EGLint attribute, EGLint value) +{ + _EGLSurface *surface = _eglLookupSurface(surf); + + if (surface == NULL) { + _eglError(EGL_BAD_SURFACE, "eglSurfaceAttrib"); + return EGL_FALSE; + } + + switch (attribute) { + case EGL_MIPMAP_LEVEL: + surface->MipmapLevel = value; + break; + default: + _eglError(EGL_BAD_ATTRIBUTE, "eglSurfaceAttrib"); + return EGL_FALSE; + } + return EGL_TRUE; +} + + +EGLBoolean +_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + /* XXX unfinished */ + return EGL_FALSE; +} + + +EGLBoolean +_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + /* XXX unfinished */ + return EGL_FALSE; +} + + +EGLBoolean +_eglSwapInterval(_EGLDriver *drv, EGLDisplay dpy, EGLint interval) +{ + _EGLSurface *surf = _eglGetCurrentSurface(EGL_DRAW); + if (surf == NULL) { + _eglError(EGL_BAD_SURFACE, "eglSwapInterval"); + return EGL_FALSE; + } + surf->SwapInterval = interval; + return EGL_TRUE; +} + + +#ifdef EGL_VERSION_1_2 + +/** + * Example function - drivers should do a proper implementation. + */ +EGLSurface +_eglCreatePbufferFromClientBuffer(_EGLDriver *drv, EGLDisplay dpy, + EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint *attrib_list) +{ + if (buftype != EGL_OPENVG_IMAGE) { + _eglError(EGL_BAD_PARAMETER, "eglCreatePbufferFromClientBuffer"); + return EGL_NO_SURFACE; + } + + return EGL_NO_SURFACE; +} + +#endif /* EGL_VERSION_1_2 */ diff --git a/src/egl/main/eglsurface.h b/src/egl/main/eglsurface.h new file mode 100644 index 00000000000..79abeca0b2a --- /dev/null +++ b/src/egl/main/eglsurface.h @@ -0,0 +1,117 @@ +#ifndef EGLSURFACE_INCLUDED +#define EGLSURFACE_INCLUDED + + +#include "egltypedefs.h" + + +/** + * "Base" class for device driver surfaces. + */ +struct _egl_surface +{ + EGLSurface Handle; /* The public/opaque handle which names this object */ + _EGLConfig *Config; + + /* May need reference counting here */ + EGLBoolean IsBound; + EGLBoolean DeletePending; + + EGLint Type; /* one of EGL_WINDOW_BIT, EGL_PIXMAP_BIT or EGL_PBUFFER_BIT */ + EGLint Width, Height; + EGLint TextureFormat, TextureTarget; + EGLint MipmapTexture, MipmapLevel; + EGLint SwapInterval; + + /* If type == EGL_SCREEN_BIT: */ + EGLint VisibleRefCount; /* number of screens I'm displayed on */ + +#ifdef EGL_VERSION_1_2 + EGLint SwapBehavior; /* one of EGL_BUFFER_PRESERVED/DESTROYED */ + EGLint HorizontalResolution, VerticalResolution; + EGLint AspectRatio; + EGLint RenderBuffer; /* EGL_BACK_BUFFER or EGL_SINGLE_BUFFER */ + EGLint AlphaFormat; /* EGL_ALPHA_FORMAT_NONPRE or EGL_ALPHA_FORMAT_PRE */ + EGLint Colorspace; /* EGL_COLORSPACE_sRGB or EGL_COLORSPACE_LINEAR */ +#endif /* EGL_VERSION_1_2 */ +}; + + +extern EGLBoolean +_eglInitSurface(_EGLDriver *drv, EGLDisplay dpy, + _EGLSurface *surf, EGLint type, EGLConfig config, + const EGLint *attrib_list); + + +extern void +_eglSaveSurface(_EGLSurface *surf); + + +extern void +_eglRemoveSurface(_EGLSurface *surf); + + +extern _EGLSurface * +_eglLookupSurface(EGLSurface surf); + + +extern _EGLSurface * +_eglGetCurrentSurface(EGLint readdraw); + + +extern EGLBoolean +_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw); + + +extern EGLBoolean +_eglCopyBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, NativePixmapType target); + + +extern EGLBoolean +_eglQuerySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); + + +extern EGLSurface +_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list); + + +extern EGLSurface +_eglCreatePixmapSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list); + + +extern EGLSurface +_eglCreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); + + +extern EGLBoolean +_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface); + + +extern EGLBoolean +_eglSurfaceAttrib(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value); + + +extern EGLBoolean +_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, EGLint buffer); + + +extern EGLBoolean +_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, EGLint buffer); + + +extern EGLBoolean +_eglSwapInterval(_EGLDriver *drv, EGLDisplay dpy, EGLint interval); + + +#ifdef EGL_VERSION_1_2 + +extern EGLSurface +_eglCreatePbufferFromClientBuffer(_EGLDriver *drv, EGLDisplay dpy, + EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint *attrib_list); + +#endif /* EGL_VERSION_1_2 */ + + + +#endif /* EGLSURFACE_INCLUDED */ diff --git a/src/egl/main/egltypedefs.h b/src/egl/main/egltypedefs.h new file mode 100644 index 00000000000..fa8cb496f8d --- /dev/null +++ b/src/egl/main/egltypedefs.h @@ -0,0 +1,34 @@ +#ifndef EGLTYPEDEFS_INCLUDED +#define EGLTYPEDEFS_INCLUDED + + +#include <GLES/egl.h> + + +typedef struct _egl_api _EGLAPI; + +typedef struct _egl_config _EGLConfig; + +typedef struct _egl_context _EGLContext; + +typedef struct _egl_display _EGLDisplay; + +typedef struct _egl_driver _EGLDriver; + +typedef struct _egl_extensions _EGLExtensions; + +typedef struct _egl_mode _EGLMode; + +typedef struct _egl_screen _EGLScreen; + +typedef struct _egl_surface _EGLSurface; + +typedef struct _egl_thread_info _EGLThreadInfo; + + +typedef void (*_EGLProc)(); + +typedef _EGLDriver *(*_EGLMain_t)(_EGLDisplay *dpy); + + +#endif /* EGLTYPEDEFS_INCLUDED */ |