1 /**************************************************************************
2  *
3  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4  * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5  * Copyright 2010 LunarG, Inc.
6  * All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the
10  * "Software"), to deal in the Software without restriction, including
11  * without limitation the rights to use, copy, modify, merge, publish,
12  * distribute, sub license, and/or sell copies of the Software, and to
13  * permit persons to whom the Software is furnished to do so, subject to
14  * the following conditions:
15  *
16  * The above copyright notice and this permission notice (including the
17  * next paragraph) shall be included in all copies or substantial portions
18  * of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  *
28  **************************************************************************/
29 
30 
31 /*
32  * Ideas for screen management extension to EGL.
33  *
34  * Each EGLDisplay has one or more screens (CRTs, Flat Panels, etc).
35  * The screens' handles can be obtained with eglGetScreensMESA().
36  *
37  * A new kind of EGLSurface is possible- one which can be directly scanned
38  * out on a screen.  Such a surface is created with eglCreateScreenSurface().
39  *
40  * To actually display a screen surface on a screen, the eglShowSurface()
41  * function is called.
42  */
43 
44 #include <assert.h>
45 #include <stdlib.h>
46 #include <string.h>
47 
48 #include "egldisplay.h"
49 #include "eglcurrent.h"
50 #include "eglmode.h"
51 #include "eglsurface.h"
52 #include "eglscreen.h"
53 #include "eglmutex.h"
54 
55 
56 #ifdef EGL_MESA_screen_surface
57 
58 
59 /* ugh, no atomic op? */
60 static _EGL_DECLARE_MUTEX(_eglNextScreenHandleMutex);
61 static EGLScreenMESA _eglNextScreenHandle = 1;
62 
63 
64 /**
65  * Return a new screen handle/ID.
66  * NOTE: we never reuse these!
67  */
68 static EGLScreenMESA
_eglAllocScreenHandle(void)69 _eglAllocScreenHandle(void)
70 {
71    EGLScreenMESA s;
72 
73    _eglLockMutex(&_eglNextScreenHandleMutex);
74    s = _eglNextScreenHandle;
75    _eglNextScreenHandle += _EGL_SCREEN_MAX_MODES;
76    _eglUnlockMutex(&_eglNextScreenHandleMutex);
77 
78    return s;
79 }
80 
81 
82 /**
83  * Initialize an _EGLScreen object to default values.
84  */
85 void
_eglInitScreen(_EGLScreen * screen,_EGLDisplay * dpy,EGLint num_modes)86 _eglInitScreen(_EGLScreen *screen, _EGLDisplay *dpy, EGLint num_modes)
87 {
88    memset(screen, 0, sizeof(_EGLScreen));
89 
90    screen->Display = dpy;
91    screen->NumModes = num_modes;
92    screen->StepX = 1;
93    screen->StepY = 1;
94 
95    if (num_modes > _EGL_SCREEN_MAX_MODES)
96       num_modes = _EGL_SCREEN_MAX_MODES;
97    screen->Modes = (_EGLMode *) calloc(num_modes, sizeof(*screen->Modes));
98    screen->NumModes = (screen->Modes) ? num_modes : 0;
99 }
100 
101 
102 /**
103  * Link a screen to its display and return the handle of the link.
104  * The handle can be passed to client directly.
105  */
106 EGLScreenMESA
_eglLinkScreen(_EGLScreen * screen)107 _eglLinkScreen(_EGLScreen *screen)
108 {
109    _EGLDisplay *display;
110    EGLint i;
111 
112    assert(screen && screen->Display);
113    display = screen->Display;
114 
115    if (!display->Screens) {
116       display->Screens = _eglCreateArray("Screen", 4);
117       if (!display->Screens)
118          return (EGLScreenMESA) 0;
119    }
120 
121    screen->Handle = _eglAllocScreenHandle();
122    for (i = 0; i < screen->NumModes; i++)
123       screen->Modes[i].Handle = screen->Handle + i;
124 
125    _eglAppendArray(display->Screens, (void *) screen);
126 
127    return screen->Handle;
128 }
129 
130 
131 /**
132  * Lookup a handle to find the linked config.
133  * Return NULL if the handle has no corresponding linked config.
134  */
135 _EGLScreen *
_eglLookupScreen(EGLScreenMESA screen,_EGLDisplay * display)136 _eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display)
137 {
138    EGLint i;
139 
140    if (!display || !display->Screens)
141       return NULL;
142 
143    for (i = 0; i < display->Screens->Size; i++) {
144       _EGLScreen *scr = (_EGLScreen *) display->Screens->Elements[i];
145       if (scr->Handle == screen) {
146          assert(scr->Display == display);
147          return scr;
148       }
149    }
150    return NULL;
151 }
152 
153 
154 static EGLBoolean
_eglFlattenScreen(void * elem,void * buffer)155 _eglFlattenScreen(void *elem, void *buffer)
156 {
157    _EGLScreen *scr = (_EGLScreen *) elem;
158    EGLScreenMESA *handle = (EGLScreenMESA *) buffer;
159    *handle = _eglGetScreenHandle(scr);
160    return EGL_TRUE;
161 }
162 
163 
164 EGLBoolean
_eglGetScreensMESA(_EGLDriver * drv,_EGLDisplay * display,EGLScreenMESA * screens,EGLint max_screens,EGLint * num_screens)165 _eglGetScreensMESA(_EGLDriver *drv, _EGLDisplay *display, EGLScreenMESA *screens,
166                    EGLint max_screens, EGLint *num_screens)
167 {
168    *num_screens = _eglFlattenArray(display->Screens, (void *) screens,
169          sizeof(screens[0]), max_screens, _eglFlattenScreen);
170 
171    return EGL_TRUE;
172 }
173 
174 
175 /**
176  * Set a screen's surface origin.
177  */
178 EGLBoolean
_eglScreenPositionMESA(_EGLDriver * drv,_EGLDisplay * dpy,_EGLScreen * scrn,EGLint x,EGLint y)179 _eglScreenPositionMESA(_EGLDriver *drv, _EGLDisplay *dpy,
180                        _EGLScreen *scrn, EGLint x, EGLint y)
181 {
182    scrn->OriginX = x;
183    scrn->OriginY = y;
184 
185    return EGL_TRUE;
186 }
187 
188 
189 /**
190  * Query a screen's current surface.
191  */
192 EGLBoolean
_eglQueryScreenSurfaceMESA(_EGLDriver * drv,_EGLDisplay * dpy,_EGLScreen * scrn,_EGLSurface ** surf)193 _eglQueryScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy,
194                            _EGLScreen *scrn, _EGLSurface **surf)
195 {
196    *surf = scrn->CurrentSurface;
197    return EGL_TRUE;
198 }
199 
200 
201 /**
202  * Query a screen's current mode.
203  */
204 EGLBoolean
_eglQueryScreenModeMESA(_EGLDriver * drv,_EGLDisplay * dpy,_EGLScreen * scrn,_EGLMode ** m)205 _eglQueryScreenModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
206                         _EGLMode **m)
207 {
208    *m = scrn->CurrentMode;
209    return EGL_TRUE;
210 }
211 
212 
213 EGLBoolean
_eglQueryScreenMESA(_EGLDriver * drv,_EGLDisplay * dpy,_EGLScreen * scrn,EGLint attribute,EGLint * value)214 _eglQueryScreenMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
215                     EGLint attribute, EGLint *value)
216 {
217    switch (attribute) {
218    case EGL_SCREEN_POSITION_MESA:
219       value[0] = scrn->OriginX;
220       value[1] = scrn->OriginY;
221       break;
222    case EGL_SCREEN_POSITION_GRANULARITY_MESA:
223       value[0] = scrn->StepX;
224       value[1] = scrn->StepY;
225       break;
226    default:
227       _eglError(EGL_BAD_ATTRIBUTE, "eglQueryScreenMESA");
228       return EGL_FALSE;
229    }
230 
231    return EGL_TRUE;
232 }
233 
234 
235 #endif /* EGL_MESA_screen_surface */
236