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? */
60static _EGL_DECLARE_MUTEX(_eglNextScreenHandleMutex);
61static EGLScreenMESA _eglNextScreenHandle = 1;
62
63
64/**
65 * Return a new screen handle/ID.
66 * NOTE: we never reuse these!
67 */
68static EGLScreenMESA
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 */
85void
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 */
106EGLScreenMESA
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 *
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
154static EGLBoolean
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
164EGLBoolean
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 */
178EGLBoolean
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 */
192EGLBoolean
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 */
204EGLBoolean
205_eglQueryScreenModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
206                        _EGLMode **m)
207{
208   *m = scrn->CurrentMode;
209   return EGL_TRUE;
210}
211
212
213EGLBoolean
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