1 /**************************************************************************
2 *
3 * Copyright 2009, VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27 /*
28 * Author: Keith Whitwell <[email protected]>
29 * Author: Jakob Bornecrantz <[email protected]>
30 */
31
32 #include "dri_screen.h"
33 #include "dri_drawable.h"
34 #include "dri_context.h"
35 #include "frontend/drm_driver.h"
36
37 #include "pipe/p_context.h"
38 #include "pipe-loader/pipe_loader.h"
39 #include "state_tracker/st_context.h"
40
41 #include "util/u_cpu_detect.h"
42 #include "util/u_memory.h"
43 #include "util/u_debug.h"
44
45 struct dri_context *
dri_create_context(struct dri_screen * screen,gl_api api,const struct gl_config * visual,const struct __DriverContextConfig * ctx_config,unsigned * error,struct dri_context * sharedContextPrivate,void * loaderPrivate)46 dri_create_context(struct dri_screen *screen,
47 gl_api api, const struct gl_config *visual,
48 const struct __DriverContextConfig *ctx_config,
49 unsigned *error,
50 struct dri_context *sharedContextPrivate,
51 void *loaderPrivate)
52 {
53 struct dri_context *ctx = NULL;
54 struct st_context *st_share = NULL;
55 struct st_context_attribs attribs;
56 enum st_context_error ctx_err = 0;
57 unsigned allowed_flags = __DRI_CTX_FLAG_DEBUG |
58 __DRI_CTX_FLAG_FORWARD_COMPATIBLE;
59 unsigned allowed_attribs =
60 __DRIVER_CONTEXT_ATTRIB_PRIORITY |
61 __DRIVER_CONTEXT_ATTRIB_RELEASE_BEHAVIOR |
62 __DRIVER_CONTEXT_ATTRIB_NO_ERROR;
63 const __DRIbackgroundCallableExtension *backgroundCallable =
64 screen->dri2.backgroundCallable;
65 const struct driOptionCache *optionCache = &screen->dev->option_cache;
66
67 /* This is effectively doing error checking for GLX context creation (by both
68 * Mesa and the X server) when the driver doesn't support the robustness ext.
69 * EGL already checks, so it won't send us the flags if the ext isn't
70 * available.
71 */
72 if (screen->has_reset_status_query) {
73 allowed_flags |= __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS;
74 allowed_attribs |= __DRIVER_CONTEXT_ATTRIB_RESET_STRATEGY;
75 }
76
77 if (screen->has_protected_context)
78 allowed_attribs |= __DRIVER_CONTEXT_ATTRIB_PROTECTED;
79
80 if (ctx_config->flags & ~allowed_flags) {
81 *error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
82 goto fail;
83 }
84
85 if (ctx_config->attribute_mask & ~allowed_attribs) {
86 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
87 goto fail;
88 }
89
90 memset(&attribs, 0, sizeof(attribs));
91 switch (api) {
92 case API_OPENGLES:
93 attribs.profile = API_OPENGLES;
94 break;
95 case API_OPENGLES2:
96 attribs.profile = API_OPENGLES2;
97 break;
98 case API_OPENGL_COMPAT:
99 case API_OPENGL_CORE:
100 if (driQueryOptionb(optionCache, "force_compat_profile")) {
101 attribs.profile = API_OPENGL_COMPAT;
102 } else {
103 attribs.profile = api == API_OPENGL_COMPAT ? API_OPENGL_COMPAT
104 : API_OPENGL_CORE;
105 }
106
107 attribs.major = ctx_config->major_version;
108 attribs.minor = ctx_config->minor_version;
109
110 if ((ctx_config->flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0)
111 attribs.flags |= ST_CONTEXT_FLAG_FORWARD_COMPATIBLE;
112 break;
113 default:
114 *error = __DRI_CTX_ERROR_BAD_API;
115 goto fail;
116 }
117
118 if ((ctx_config->flags & __DRI_CTX_FLAG_DEBUG) != 0)
119 attribs.flags |= ST_CONTEXT_FLAG_DEBUG;
120
121 if (ctx_config->flags & __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS)
122 attribs.context_flags |= PIPE_CONTEXT_ROBUST_BUFFER_ACCESS;
123
124 if (ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_RESET_STRATEGY)
125 if (ctx_config->reset_strategy != __DRI_CTX_RESET_NO_NOTIFICATION)
126 attribs.context_flags |= PIPE_CONTEXT_LOSE_CONTEXT_ON_RESET;
127
128 if (ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_NO_ERROR)
129 attribs.flags |= ctx_config->no_error ? ST_CONTEXT_FLAG_NO_ERROR : 0;
130
131 if (ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_PRIORITY) {
132 switch (ctx_config->priority) {
133 case __DRI_CTX_PRIORITY_LOW:
134 attribs.context_flags |= PIPE_CONTEXT_LOW_PRIORITY;
135 break;
136 case __DRI_CTX_PRIORITY_HIGH:
137 attribs.context_flags |= PIPE_CONTEXT_HIGH_PRIORITY;
138 break;
139 default:
140 break;
141 }
142 }
143
144 if ((ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_RELEASE_BEHAVIOR)
145 && (ctx_config->release_behavior == __DRI_CTX_RELEASE_BEHAVIOR_NONE))
146 attribs.flags |= ST_CONTEXT_FLAG_RELEASE_NONE;
147
148 if (ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_PROTECTED)
149 attribs.context_flags |= PIPE_CONTEXT_PROTECTED;
150
151 struct dri_context *share_ctx = NULL;
152 if (sharedContextPrivate) {
153 share_ctx = (struct dri_context *)sharedContextPrivate;
154 st_share = share_ctx->st;
155 }
156
157 ctx = CALLOC_STRUCT(dri_context);
158 if (ctx == NULL) {
159 *error = __DRI_CTX_ERROR_NO_MEMORY;
160 goto fail;
161 }
162
163 ctx->screen = screen;
164 ctx->loaderPrivate = loaderPrivate;
165
166 /* KHR_no_error is likely to crash, overflow memory, etc if an application
167 * has errors so don't enable it for setuid processes.
168 */
169 if (debug_get_bool_option("MESA_NO_ERROR", false) ||
170 driQueryOptionb(&screen->dev->option_cache, "mesa_no_error"))
171 #if !defined(_WIN32)
172 if (__normal_user())
173 #endif
174 attribs.flags |= ST_CONTEXT_FLAG_NO_ERROR;
175
176 attribs.options = screen->options;
177 dri_fill_st_visual(&attribs.visual, screen, visual);
178 ctx->st = st_api_create_context(&screen->base, &attribs, &ctx_err,
179 st_share);
180 if (ctx->st == NULL) {
181 switch (ctx_err) {
182 case ST_CONTEXT_SUCCESS:
183 *error = __DRI_CTX_ERROR_SUCCESS;
184 break;
185 case ST_CONTEXT_ERROR_NO_MEMORY:
186 *error = __DRI_CTX_ERROR_NO_MEMORY;
187 break;
188 case ST_CONTEXT_ERROR_BAD_VERSION:
189 *error = __DRI_CTX_ERROR_BAD_VERSION;
190 break;
191 }
192 goto fail;
193 }
194 ctx->st->frontend_context = (void *) ctx;
195
196 if (ctx->st->cso_context) {
197 ctx->pp = pp_init(ctx->st->pipe, screen->pp_enabled, ctx->st->cso_context,
198 ctx->st, st_context_invalidate_state);
199 ctx->hud = hud_create(ctx->st->cso_context,
200 share_ctx ? share_ctx->hud : NULL,
201 ctx->st, st_context_invalidate_state);
202 }
203
204 /* order of precedence (least to most):
205 * - driver setting
206 * - app setting
207 * - user setting
208 */
209 bool enable_glthread = driQueryOptionb(&screen->dev->option_cache, "mesa_glthread_driver");
210
211 /* always disable glthread by default if fewer than 5 "big" CPUs are active */
212 unsigned nr_big_cpus = util_get_cpu_caps()->nr_big_cpus;
213 if (util_get_cpu_caps()->nr_cpus < 4 || (nr_big_cpus && nr_big_cpus < 5))
214 enable_glthread = false;
215
216 int app_enable_glthread = driQueryOptioni(&screen->dev->option_cache, "mesa_glthread_app_profile");
217 if (app_enable_glthread != -1) {
218 /* if set (not -1), apply the app setting */
219 enable_glthread = app_enable_glthread == 1;
220 }
221 if (getenv("mesa_glthread")) {
222 /* only apply the env var if set */
223 bool user_enable_glthread = debug_get_bool_option("mesa_glthread", false);
224 if (user_enable_glthread != enable_glthread) {
225 /* print warning to mimic old behavior */
226 fprintf(stderr, "ATTENTION: default value of option mesa_glthread overridden by environment.\n");
227 }
228 enable_glthread = user_enable_glthread;
229 }
230 /* Do this last. */
231 if (enable_glthread) {
232 bool safe = true;
233
234 /* This is only needed by X11/DRI2, which can be unsafe. */
235 if (backgroundCallable &&
236 backgroundCallable->base.version >= 2 &&
237 backgroundCallable->isThreadSafe &&
238 !backgroundCallable->isThreadSafe(loaderPrivate))
239 safe = false;
240
241 if (safe)
242 _mesa_glthread_init(ctx->st->ctx);
243 }
244
245 *error = __DRI_CTX_ERROR_SUCCESS;
246 return ctx;
247
248 fail:
249 if (ctx && ctx->st)
250 st_destroy_context(ctx->st);
251
252 free(ctx);
253 return NULL;
254 }
255
256 void
dri_destroy_context(struct dri_context * ctx)257 dri_destroy_context(struct dri_context *ctx)
258 {
259 /* Wait for glthread to finish because we can't use pipe_context from
260 * multiple threads.
261 */
262 _mesa_glthread_finish(ctx->st->ctx);
263
264 if (ctx->hud) {
265 hud_destroy(ctx->hud, ctx->st->cso_context);
266 }
267
268 if (ctx->pp)
269 pp_free(ctx->pp);
270
271 /* No particular reason to wait for command completion before
272 * destroying a context, but we flush the context here
273 * to avoid having to add code elsewhere to cope with flushing a
274 * partially destroyed context.
275 */
276 st_context_flush(ctx->st, 0, NULL, NULL, NULL);
277 st_destroy_context(ctx->st);
278 free(ctx);
279 }
280
281 /* This is called inside MakeCurrent to unbind the context. */
282 bool
dri_unbind_context(struct dri_context * ctx)283 dri_unbind_context(struct dri_context *ctx)
284 {
285 /* dri_util.c ensures cPriv is not null */
286 struct st_context *st = ctx->st;
287
288 if (st == st_api_get_current()) {
289 _mesa_glthread_finish(st->ctx);
290
291 /* Record HUD queries for the duration the context was "current". */
292 if (ctx->hud)
293 hud_record_only(ctx->hud, st->pipe);
294
295 st_api_make_current(NULL, NULL, NULL);
296 }
297
298 if (ctx->draw || ctx->read) {
299 assert(ctx->draw);
300
301 dri_put_drawable(ctx->draw);
302
303 if (ctx->read != ctx->draw)
304 dri_put_drawable(ctx->read);
305
306 ctx->draw = NULL;
307 ctx->read = NULL;
308 }
309
310 return GL_TRUE;
311 }
312
313 bool
dri_make_current(struct dri_context * ctx,struct dri_drawable * draw,struct dri_drawable * read)314 dri_make_current(struct dri_context *ctx,
315 struct dri_drawable *draw,
316 struct dri_drawable *read)
317 {
318 /* dri_unbind_context() is always called before this, so drawables are
319 * always NULL here.
320 */
321 assert(!ctx->draw);
322 assert(!ctx->read);
323
324 if ((draw && !read) || (!draw && read))
325 return GL_FALSE; /* only both non-NULL or both NULL are allowed */
326
327 /* Wait for glthread to finish because we can't use st_context from
328 * multiple threads.
329 */
330 _mesa_glthread_finish(ctx->st->ctx);
331
332 /* There are 2 cases that can occur here. Either we bind drawables, or we
333 * bind NULL for configless and surfaceless contexts.
334 */
335 if (!draw && !read)
336 return st_api_make_current(ctx->st, NULL, NULL);
337
338 /* Bind drawables to the context */
339 ctx->draw = draw;
340 ctx->read = read;
341
342 dri_get_drawable(draw);
343 draw->texture_stamp = draw->lastStamp - 1;
344
345 if (draw != read) {
346 dri_get_drawable(read);
347 read->texture_stamp = read->lastStamp - 1;
348 }
349
350 st_api_make_current(ctx->st, &draw->base, &read->base);
351
352 /* This is ok to call here. If they are already init, it's a no-op. */
353 if (ctx->pp && draw->textures[ST_ATTACHMENT_BACK_LEFT])
354 pp_init_fbos(ctx->pp, draw->textures[ST_ATTACHMENT_BACK_LEFT]->width0,
355 draw->textures[ST_ATTACHMENT_BACK_LEFT]->height0);
356
357 return GL_TRUE;
358 }
359
360 struct dri_context *
dri_get_current(void)361 dri_get_current(void)
362 {
363 struct st_context *st = st_api_get_current();
364
365 return (struct dri_context *) st ? st->frontend_context : NULL;
366 }
367
368 /* vim: set sw=3 ts=8 sts=3 expandtab: */
369