1/*
2 * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
3 * All Rights Reserved.
4 * Copyright 2010 George Sapountzis <gsapountzis@gmail.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24/**
25 * \file drisw_util.c
26 *
27 * DRISW utility functions, i.e. dri_util.c stripped from drm-specific bits.
28 */
29
30#include "dri_util.h"
31#include "utils.h"
32
33
34/**
35 * Screen functions
36 */
37
38static void
39setupLoaderExtensions(__DRIscreen *psp,
40		      const __DRIextension **extensions)
41{
42    int i;
43
44    for (i = 0; extensions[i]; i++) {
45	if (strcmp(extensions[i]->name, __DRI_SWRAST_LOADER) == 0)
46	    psp->swrast_loader = (__DRIswrastLoaderExtension *) extensions[i];
47    }
48}
49
50static __DRIscreen *
51driCreateNewScreen(int scrn, const __DRIextension **extensions,
52		   const __DRIconfig ***driver_configs, void *data)
53{
54    static const __DRIextension *emptyExtensionList[] = { NULL };
55    __DRIscreen *psp;
56
57    psp = CALLOC_STRUCT(__DRIscreenRec);
58    if (!psp)
59	return NULL;
60
61    setupLoaderExtensions(psp, extensions);
62
63    psp->loaderPrivate = data;
64
65    psp->extensions = emptyExtensionList;
66    psp->fd = -1;
67    psp->myNum = scrn;
68
69    *driver_configs = driDriverAPI.InitScreen(psp);
70    if (*driver_configs == NULL) {
71	FREE(psp);
72	return NULL;
73    }
74
75    return psp;
76}
77
78static void driDestroyScreen(__DRIscreen *psp)
79{
80    if (psp) {
81	driDriverAPI.DestroyScreen(psp);
82	FREE(psp);
83    }
84}
85
86static const __DRIextension **driGetExtensions(__DRIscreen *psp)
87{
88    return psp->extensions;
89}
90
91
92/**
93 * Context functions
94 */
95
96static __DRIcontext *
97driCreateContextAttribs(__DRIscreen *screen, int api,
98			const __DRIconfig *config,
99			__DRIcontext *shared,
100			unsigned num_attribs,
101			const uint32_t *attribs,
102			unsigned *error,
103			void *data)
104{
105    __DRIcontext *pcp;
106    const struct gl_config *modes = (config != NULL) ? &config->modes : NULL;
107    void * const shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
108    gl_api mesa_api;
109    unsigned major_version = 1;
110    unsigned minor_version = 0;
111    uint32_t flags = 0;
112
113    /* Either num_attribs is zero and attribs is NULL, or num_attribs is not
114     * zero and attribs is not NULL.
115     */
116    assert((num_attribs == 0) == (attribs == NULL));
117
118    switch (api) {
119    case __DRI_API_OPENGL:
120            mesa_api = API_OPENGL;
121            break;
122    case __DRI_API_GLES:
123            mesa_api = API_OPENGLES;
124            break;
125    case __DRI_API_GLES2:
126            mesa_api = API_OPENGLES2;
127            break;
128    case __DRI_API_OPENGL_CORE:
129    default:
130            return NULL;
131    }
132
133    for (unsigned i = 0; i < num_attribs; i++) {
134	switch (attribs[i * 2]) {
135	case __DRI_CTX_ATTRIB_MAJOR_VERSION:
136	    major_version = attribs[i * 2 + 1];
137	    break;
138	case __DRI_CTX_ATTRIB_MINOR_VERSION:
139	    minor_version = attribs[i * 2 + 1];
140	    break;
141	case __DRI_CTX_ATTRIB_FLAGS:
142	    flags = attribs[i * 2 + 1];
143	    break;
144	default:
145	    /* We can't create a context that satisfies the requirements of an
146	     * attribute that we don't understand.  Return failure.
147	     */
148	    return NULL;
149	}
150    }
151
152    /* There are no forward-compatible contexts before OpenGL 3.0.  The
153     * GLX_ARB_create_context spec says:
154     *
155     *     "Forward-compatible contexts are defined only for OpenGL versions
156     *     3.0 and later."
157     *
158     * Moreover, Mesa can't fulfill the requirements of a forward-looking
159     * context.  Return failure if a forward-looking context is requested.
160     *
161     * In Mesa, a debug context is the same as a regular context.
162     */
163    if (major_version >= 3) {
164	if ((flags & ~__DRI_CTX_FLAG_DEBUG) != 0)
165	    return NULL;
166    }
167
168    pcp = CALLOC_STRUCT(__DRIcontextRec);
169    if (!pcp)
170        return NULL;
171
172    pcp->loaderPrivate = data;
173
174    pcp->driScreenPriv = screen;
175    pcp->driDrawablePriv = NULL;
176    pcp->driReadablePriv = NULL;
177
178    if (!driDriverAPI.CreateContext(mesa_api, modes, pcp,
179				    major_version, minor_version,
180				    flags, error, shareCtx)) {
181        FREE(pcp);
182        return NULL;
183    }
184
185    return pcp;
186}
187
188static __DRIcontext *
189driCreateNewContextForAPI(__DRIscreen *psp, int api,
190                          const __DRIconfig *config,
191                          __DRIcontext *shared, void *data)
192{
193    unsigned error;
194
195    return driCreateContextAttribs(psp, api, config, shared, 0, NULL,
196				   &error, data);
197}
198
199static __DRIcontext *
200driCreateNewContext(__DRIscreen *psp, const __DRIconfig *config,
201		    __DRIcontext *shared, void *data)
202{
203    return driCreateNewContextForAPI(psp, __DRI_API_OPENGL,
204				     config, shared, data);
205}
206
207static void
208driDestroyContext(__DRIcontext *pcp)
209{
210    if (pcp) {
211	driDriverAPI.DestroyContext(pcp);
212	FREE(pcp);
213    }
214}
215
216static int
217driCopyContext(__DRIcontext *dst, __DRIcontext *src, unsigned long mask)
218{
219    return GL_FALSE;
220}
221
222static void dri_get_drawable(__DRIdrawable *pdp);
223static void dri_put_drawable(__DRIdrawable *pdp);
224
225static int driBindContext(__DRIcontext *pcp,
226			  __DRIdrawable *pdp,
227			  __DRIdrawable *prp)
228{
229    /* Bind the drawable to the context */
230    if (pcp) {
231	pcp->driDrawablePriv = pdp;
232	pcp->driReadablePriv = prp;
233	if (pdp) {
234	    pdp->driContextPriv = pcp;
235	    dri_get_drawable(pdp);
236	}
237	if (prp && pdp != prp) {
238	    dri_get_drawable(prp);
239	}
240    }
241
242    return driDriverAPI.MakeCurrent(pcp, pdp, prp);
243}
244
245static int driUnbindContext(__DRIcontext *pcp)
246{
247    __DRIdrawable *pdp;
248    __DRIdrawable *prp;
249
250    if (pcp == NULL)
251	return GL_FALSE;
252
253    pdp = pcp->driDrawablePriv;
254    prp = pcp->driReadablePriv;
255
256    /* already unbound */
257    if (!pdp && !prp)
258	return GL_TRUE;
259
260    driDriverAPI.UnbindContext(pcp);
261
262    dri_put_drawable(pdp);
263
264    if (prp != pdp) {
265	dri_put_drawable(prp);
266    }
267
268    pcp->driDrawablePriv = NULL;
269    pcp->driReadablePriv = NULL;
270
271    return GL_TRUE;
272}
273
274
275/**
276 * Drawable functions
277 */
278
279static void dri_get_drawable(__DRIdrawable *pdp)
280{
281    pdp->refcount++;
282}
283
284static void dri_put_drawable(__DRIdrawable *pdp)
285{
286    if (pdp) {
287	pdp->refcount--;
288	if (pdp->refcount)
289	    return;
290
291	driDriverAPI.DestroyBuffer(pdp);
292	FREE(pdp);
293    }
294}
295
296static __DRIdrawable *
297driCreateNewDrawable(__DRIscreen *psp,
298		     const __DRIconfig *config, void *data)
299{
300    __DRIdrawable *pdp;
301
302    pdp = CALLOC_STRUCT(__DRIdrawableRec);
303    if (!pdp)
304	return NULL;
305
306    pdp->loaderPrivate = data;
307
308    pdp->driScreenPriv = psp;
309    pdp->driContextPriv = NULL;
310
311    dri_get_drawable(pdp);
312
313    if (!driDriverAPI.CreateBuffer(psp, pdp, &config->modes, GL_FALSE)) {
314	FREE(pdp);
315	return NULL;
316    }
317
318    pdp->lastStamp = 1; /* const */
319
320    return pdp;
321}
322
323static void
324driDestroyDrawable(__DRIdrawable *pdp)
325{
326    dri_put_drawable(pdp);
327}
328
329static void driSwapBuffers(__DRIdrawable *pdp)
330{
331    driDriverAPI.SwapBuffers(pdp);
332}
333
334const __DRIcoreExtension driCoreExtension = {
335    { __DRI_CORE, __DRI_CORE_VERSION },
336    NULL, /* driCreateNewScreen */
337    driDestroyScreen,
338    driGetExtensions,
339    driGetConfigAttrib,
340    driIndexConfigAttrib,
341    NULL, /* driCreateNewDrawable */
342    driDestroyDrawable,
343    driSwapBuffers,
344    driCreateNewContext,
345    driCopyContext,
346    driDestroyContext,
347    driBindContext,
348    driUnbindContext
349};
350
351const __DRIswrastExtension driSWRastExtension = {
352    { __DRI_SWRAST, __DRI_SWRAST_VERSION },
353    driCreateNewScreen,
354    driCreateNewDrawable,
355    driCreateNewContextForAPI,
356    driCreateContextAttribs
357};
358