dri: Add an explanatory comment for an important driver entrypoint.
[mesa.git] / src / mesa / drivers / dri / common / drisw_util.c
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 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file drisw_util.c
27 *
28 * DRISW utility functions, i.e. dri_util.c stripped from drm-specific bits.
29 */
30
31 #include "dri_util.h"
32 #include "utils.h"
33
34
35 /**
36 * Screen functions
37 */
38
39 static void
40 setupLoaderExtensions(__DRIscreen *psp,
41 const __DRIextension **extensions)
42 {
43 int i;
44
45 for (i = 0; extensions[i]; i++) {
46 if (strcmp(extensions[i]->name, __DRI_SWRAST_LOADER) == 0)
47 psp->swrast_loader = (__DRIswrastLoaderExtension *) extensions[i];
48 }
49 }
50
51 static __DRIscreen *
52 driCreateNewScreen(int scrn, const __DRIextension **extensions,
53 const __DRIconfig ***driver_configs, void *data)
54 {
55 static const __DRIextension *emptyExtensionList[] = { NULL };
56 __DRIscreen *psp;
57
58 psp = CALLOC_STRUCT(__DRIscreenRec);
59 if (!psp)
60 return NULL;
61
62 setupLoaderExtensions(psp, extensions);
63
64 psp->loaderPrivate = data;
65
66 psp->extensions = emptyExtensionList;
67 psp->fd = -1;
68 psp->myNum = scrn;
69
70 *driver_configs = driDriverAPI.InitScreen(psp);
71 if (*driver_configs == NULL) {
72 free(psp);
73 return NULL;
74 }
75
76 return psp;
77 }
78
79 static void driDestroyScreen(__DRIscreen *psp)
80 {
81 if (psp) {
82 driDriverAPI.DestroyScreen(psp);
83 free(psp);
84 }
85 }
86
87 static const __DRIextension **driGetExtensions(__DRIscreen *psp)
88 {
89 return psp->extensions;
90 }
91
92
93 /**
94 * Context functions
95 */
96
97 static __DRIcontext *
98 driCreateContextAttribs(__DRIscreen *screen, int api,
99 const __DRIconfig *config,
100 __DRIcontext *shared,
101 unsigned num_attribs,
102 const uint32_t *attribs,
103 unsigned *error,
104 void *data)
105 {
106 __DRIcontext *pcp;
107 const struct gl_config *modes = (config != NULL) ? &config->modes : NULL;
108 void * const shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
109 gl_api mesa_api;
110 unsigned major_version = 1;
111 unsigned minor_version = 0;
112 uint32_t flags = 0;
113
114 /* Either num_attribs is zero and attribs is NULL, or num_attribs is not
115 * zero and attribs is not NULL.
116 */
117 assert((num_attribs == 0) == (attribs == NULL));
118
119 switch (api) {
120 case __DRI_API_OPENGL:
121 mesa_api = API_OPENGL_COMPAT;
122 break;
123 case __DRI_API_GLES:
124 mesa_api = API_OPENGLES;
125 break;
126 case __DRI_API_GLES2:
127 case __DRI_API_GLES3:
128 mesa_api = API_OPENGLES2;
129 break;
130 case __DRI_API_OPENGL_CORE:
131 mesa_api = API_OPENGL_CORE;
132 break;
133 default:
134 *error = __DRI_CTX_ERROR_BAD_API;
135 return NULL;
136 }
137
138 for (unsigned i = 0; i < num_attribs; i++) {
139 switch (attribs[i * 2]) {
140 case __DRI_CTX_ATTRIB_MAJOR_VERSION:
141 major_version = attribs[i * 2 + 1];
142 break;
143 case __DRI_CTX_ATTRIB_MINOR_VERSION:
144 minor_version = attribs[i * 2 + 1];
145 break;
146 case __DRI_CTX_ATTRIB_FLAGS:
147 flags = attribs[i * 2 + 1];
148 break;
149 default:
150 /* We can't create a context that satisfies the requirements of an
151 * attribute that we don't understand. Return failure.
152 */
153 return NULL;
154 }
155 }
156
157 /* Mesa does not support the GL_ARB_compatibilty extension or the
158 * compatibility profile. This means that we treat a API_OPENGL_COMPAT 3.1 as
159 * API_OPENGL_CORE and reject API_OPENGL_COMPAT 3.2+.
160 */
161 if (mesa_api == API_OPENGL_COMPAT && major_version == 3 && minor_version == 1)
162 mesa_api = API_OPENGL_CORE;
163
164 if (mesa_api == API_OPENGL_COMPAT
165 && ((major_version > 3)
166 || (major_version == 3 && minor_version >= 2))) {
167 *error = __DRI_CTX_ERROR_BAD_API;
168 return NULL;
169 }
170 /* There are no forward-compatible contexts before OpenGL 3.0. The
171 * GLX_ARB_create_context spec says:
172 *
173 * "Forward-compatible contexts are defined only for OpenGL versions
174 * 3.0 and later."
175 *
176 * Moreover, Mesa can't fulfill the requirements of a forward-looking
177 * context. Return failure if a forward-looking context is requested.
178 *
179 * In Mesa, a debug context is the same as a regular context.
180 */
181 if (major_version >= 3) {
182 if ((flags & ~__DRI_CTX_FLAG_DEBUG) != 0)
183 return NULL;
184 }
185
186 pcp = CALLOC_STRUCT(__DRIcontextRec);
187 if (!pcp)
188 return NULL;
189
190 pcp->loaderPrivate = data;
191
192 pcp->driScreenPriv = screen;
193 pcp->driDrawablePriv = NULL;
194 pcp->driReadablePriv = NULL;
195
196 if (!driDriverAPI.CreateContext(mesa_api, modes, pcp,
197 major_version, minor_version,
198 flags, error, shareCtx)) {
199 free(pcp);
200 return NULL;
201 }
202
203 return pcp;
204 }
205
206 static __DRIcontext *
207 driCreateNewContextForAPI(__DRIscreen *psp, int api,
208 const __DRIconfig *config,
209 __DRIcontext *shared, void *data)
210 {
211 unsigned error;
212
213 return driCreateContextAttribs(psp, api, config, shared, 0, NULL,
214 &error, data);
215 }
216
217 static __DRIcontext *
218 driCreateNewContext(__DRIscreen *psp, const __DRIconfig *config,
219 __DRIcontext *shared, void *data)
220 {
221 return driCreateNewContextForAPI(psp, __DRI_API_OPENGL,
222 config, shared, data);
223 }
224
225 static void
226 driDestroyContext(__DRIcontext *pcp)
227 {
228 if (pcp) {
229 driDriverAPI.DestroyContext(pcp);
230 free(pcp);
231 }
232 }
233
234 static int
235 driCopyContext(__DRIcontext *dst, __DRIcontext *src, unsigned long mask)
236 {
237 return GL_FALSE;
238 }
239
240 static void dri_get_drawable(__DRIdrawable *pdp);
241 static void dri_put_drawable(__DRIdrawable *pdp);
242
243 static int driBindContext(__DRIcontext *pcp,
244 __DRIdrawable *pdp,
245 __DRIdrawable *prp)
246 {
247 /* Bind the drawable to the context */
248 if (pcp) {
249 pcp->driDrawablePriv = pdp;
250 pcp->driReadablePriv = prp;
251 if (pdp) {
252 pdp->driContextPriv = pcp;
253 dri_get_drawable(pdp);
254 }
255 if (prp && pdp != prp) {
256 dri_get_drawable(prp);
257 }
258 }
259
260 return driDriverAPI.MakeCurrent(pcp, pdp, prp);
261 }
262
263 static int driUnbindContext(__DRIcontext *pcp)
264 {
265 __DRIdrawable *pdp;
266 __DRIdrawable *prp;
267
268 if (pcp == NULL)
269 return GL_FALSE;
270
271 pdp = pcp->driDrawablePriv;
272 prp = pcp->driReadablePriv;
273
274 /* already unbound */
275 if (!pdp && !prp)
276 return GL_TRUE;
277
278 driDriverAPI.UnbindContext(pcp);
279
280 dri_put_drawable(pdp);
281
282 if (prp != pdp) {
283 dri_put_drawable(prp);
284 }
285
286 pcp->driDrawablePriv = NULL;
287 pcp->driReadablePriv = NULL;
288
289 return GL_TRUE;
290 }
291
292
293 /**
294 * Drawable functions
295 */
296
297 static void dri_get_drawable(__DRIdrawable *pdp)
298 {
299 pdp->refcount++;
300 }
301
302 static void dri_put_drawable(__DRIdrawable *pdp)
303 {
304 if (pdp) {
305 pdp->refcount--;
306 if (pdp->refcount)
307 return;
308
309 driDriverAPI.DestroyBuffer(pdp);
310 free(pdp);
311 }
312 }
313
314 static __DRIdrawable *
315 driCreateNewDrawable(__DRIscreen *psp,
316 const __DRIconfig *config, void *data)
317 {
318 __DRIdrawable *pdp;
319
320 pdp = CALLOC_STRUCT(__DRIdrawableRec);
321 if (!pdp)
322 return NULL;
323
324 pdp->loaderPrivate = data;
325
326 pdp->driScreenPriv = psp;
327 pdp->driContextPriv = NULL;
328
329 dri_get_drawable(pdp);
330
331 if (!driDriverAPI.CreateBuffer(psp, pdp, &config->modes, GL_FALSE)) {
332 free(pdp);
333 return NULL;
334 }
335
336 pdp->lastStamp = 1; /* const */
337
338 return pdp;
339 }
340
341 static void
342 driDestroyDrawable(__DRIdrawable *pdp)
343 {
344 dri_put_drawable(pdp);
345 }
346
347 static void driSwapBuffers(__DRIdrawable *pdp)
348 {
349 driDriverAPI.SwapBuffers(pdp);
350 }
351
352 const __DRIcoreExtension driCoreExtension = {
353 { __DRI_CORE, __DRI_CORE_VERSION },
354 NULL, /* driCreateNewScreen */
355 driDestroyScreen,
356 driGetExtensions,
357 driGetConfigAttrib,
358 driIndexConfigAttrib,
359 NULL, /* driCreateNewDrawable */
360 driDestroyDrawable,
361 driSwapBuffers,
362 driCreateNewContext,
363 driCopyContext,
364 driDestroyContext,
365 driBindContext,
366 driUnbindContext
367 };
368
369 const __DRIswrastExtension driSWRastExtension = {
370 { __DRI_SWRAST, __DRI_SWRAST_VERSION },
371 driCreateNewScreen,
372 driCreateNewDrawable,
373 driCreateNewContextForAPI,
374 driCreateContextAttribs
375 };