• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <keithw@vmware.com>
29  * Author: Jakob Bornecrantz <wallbraker@gmail.com>
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       case __DRI_CTX_PRIORITY_REALTIME:
140          attribs.context_flags |= PIPE_CONTEXT_REALTIME_PRIORITY;
141          break;
142       default:
143          break;
144       }
145    }
146 
147    if ((ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_RELEASE_BEHAVIOR)
148        && (ctx_config->release_behavior == __DRI_CTX_RELEASE_BEHAVIOR_NONE))
149       attribs.flags |= ST_CONTEXT_FLAG_RELEASE_NONE;
150 
151    if (ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_PROTECTED)
152       attribs.context_flags |= PIPE_CONTEXT_PROTECTED;
153 
154    struct dri_context *share_ctx = NULL;
155    if (sharedContextPrivate) {
156       share_ctx = (struct dri_context *)sharedContextPrivate;
157       st_share = share_ctx->st;
158    }
159 
160    ctx = CALLOC_STRUCT(dri_context);
161    if (ctx == NULL) {
162       *error = __DRI_CTX_ERROR_NO_MEMORY;
163       goto fail;
164    }
165 
166    ctx->screen = screen;
167    ctx->loaderPrivate = loaderPrivate;
168 
169    /* KHR_no_error is likely to crash, overflow memory, etc if an application
170     * has errors so don't enable it for setuid processes.
171     */
172    if (debug_get_bool_option("MESA_NO_ERROR", false) ||
173        driQueryOptionb(&screen->dev->option_cache, "mesa_no_error"))
174 #if !defined(_WIN32)
175       if (__normal_user())
176 #endif
177          attribs.flags |= ST_CONTEXT_FLAG_NO_ERROR;
178 
179    attribs.options = screen->options;
180    dri_fill_st_visual(&attribs.visual, screen, visual);
181    ctx->st = st_api_create_context(&screen->base, &attribs, &ctx_err,
182 				   st_share);
183    if (ctx->st == NULL) {
184       switch (ctx_err) {
185       case ST_CONTEXT_SUCCESS:
186 	 *error = __DRI_CTX_ERROR_SUCCESS;
187 	 break;
188       case ST_CONTEXT_ERROR_NO_MEMORY:
189 	 *error = __DRI_CTX_ERROR_NO_MEMORY;
190 	 break;
191       case ST_CONTEXT_ERROR_BAD_VERSION:
192 	 *error = __DRI_CTX_ERROR_BAD_VERSION;
193 	 break;
194       }
195       goto fail;
196    }
197    ctx->st->frontend_context = (void *) ctx;
198 
199    if (ctx->st->cso_context) {
200       ctx->pp = pp_init(ctx->st->pipe, screen->pp_enabled, ctx->st->cso_context,
201                         ctx->st, st_context_invalidate_state);
202       ctx->hud = hud_create(ctx->st->cso_context,
203                             share_ctx ? share_ctx->hud : NULL,
204                             ctx->st, st_context_invalidate_state);
205    }
206 
207    /* order of precedence (least to most):
208     * - driver setting
209     * - app setting
210     * - user setting
211     */
212    bool enable_glthread = driQueryOptionb(&screen->dev->option_cache, "mesa_glthread_driver");
213 
214    /* always disable glthread by default if fewer than 5 "big" CPUs are active */
215    unsigned nr_big_cpus = util_get_cpu_caps()->nr_big_cpus;
216    if (util_get_cpu_caps()->nr_cpus < 4 || (nr_big_cpus && nr_big_cpus < 5))
217       enable_glthread = false;
218 
219    int app_enable_glthread = driQueryOptioni(&screen->dev->option_cache, "mesa_glthread_app_profile");
220    if (app_enable_glthread != -1) {
221       /* if set (not -1), apply the app setting */
222       enable_glthread = app_enable_glthread == 1;
223    }
224    if (getenv("mesa_glthread")) {
225       /* only apply the env var if set */
226       bool user_enable_glthread = debug_get_bool_option("mesa_glthread", false);
227       if (user_enable_glthread != enable_glthread) {
228          /* print warning to mimic old behavior */
229          fprintf(stderr, "ATTENTION: default value of option mesa_glthread overridden by environment.\n");
230       }
231       enable_glthread = user_enable_glthread;
232    }
233    /* Do this last. */
234    if (enable_glthread) {
235       bool safe = true;
236 
237       /* This is only needed by X11/DRI2, which can be unsafe. */
238       if (backgroundCallable &&
239           backgroundCallable->base.version >= 2 &&
240           backgroundCallable->isThreadSafe &&
241           !backgroundCallable->isThreadSafe(loaderPrivate))
242          safe = false;
243 
244       if (safe)
245          _mesa_glthread_init(ctx->st->ctx);
246    }
247 
248    *error = __DRI_CTX_ERROR_SUCCESS;
249    return ctx;
250 
251  fail:
252    if (ctx && ctx->st)
253       st_destroy_context(ctx->st);
254 
255    free(ctx);
256    return NULL;
257 }
258 
259 void
dri_destroy_context(struct dri_context * ctx)260 dri_destroy_context(struct dri_context *ctx)
261 {
262    /* Wait for glthread to finish because we can't use pipe_context from
263     * multiple threads.
264     */
265    _mesa_glthread_finish(ctx->st->ctx);
266 
267    if (ctx->hud) {
268       hud_destroy(ctx->hud, ctx->st->cso_context);
269    }
270 
271    if (ctx->pp)
272       pp_free(ctx->pp);
273 
274    /* No particular reason to wait for command completion before
275     * destroying a context, but we flush the context here
276     * to avoid having to add code elsewhere to cope with flushing a
277     * partially destroyed context.
278     */
279    st_context_flush(ctx->st, 0, NULL, NULL, NULL);
280    st_destroy_context(ctx->st);
281    free(ctx);
282 }
283 
284 /* This is called inside MakeCurrent to unbind the context. */
285 bool
dri_unbind_context(struct dri_context * ctx)286 dri_unbind_context(struct dri_context *ctx)
287 {
288    /* dri_util.c ensures cPriv is not null */
289    struct st_context *st = ctx->st;
290 
291    if (st == st_api_get_current()) {
292       _mesa_glthread_finish(st->ctx);
293 
294       /* Record HUD queries for the duration the context was "current". */
295       if (ctx->hud)
296          hud_record_only(ctx->hud, st->pipe);
297 
298       st_api_make_current(NULL, NULL, NULL);
299    }
300 
301    if (ctx->draw || ctx->read) {
302       assert(ctx->draw);
303 
304       dri_put_drawable(ctx->draw);
305 
306       if (ctx->read != ctx->draw)
307           dri_put_drawable(ctx->read);
308 
309       ctx->draw = NULL;
310       ctx->read = NULL;
311    }
312 
313    return GL_TRUE;
314 }
315 
316 bool
dri_make_current(struct dri_context * ctx,struct dri_drawable * draw,struct dri_drawable * read)317 dri_make_current(struct dri_context *ctx,
318 		 struct dri_drawable *draw,
319 		 struct dri_drawable *read)
320 {
321    /* dri_unbind_context() is always called before this, so drawables are
322     * always NULL here.
323     */
324    assert(!ctx->draw);
325    assert(!ctx->read);
326 
327    if ((draw && !read) || (!draw && read))
328       return GL_FALSE; /* only both non-NULL or both NULL are allowed */
329 
330    /* Wait for glthread to finish because we can't use st_context from
331     * multiple threads.
332     */
333    _mesa_glthread_finish(ctx->st->ctx);
334 
335    /* There are 2 cases that can occur here. Either we bind drawables, or we
336     * bind NULL for configless and surfaceless contexts.
337     */
338    if (!draw && !read)
339       return st_api_make_current(ctx->st, NULL, NULL);
340 
341    /* Bind drawables to the context */
342    ctx->draw = draw;
343    ctx->read = read;
344 
345    dri_get_drawable(draw);
346    draw->texture_stamp = draw->lastStamp - 1;
347 
348    if (draw != read) {
349       dri_get_drawable(read);
350       read->texture_stamp = read->lastStamp - 1;
351    }
352 
353    st_api_make_current(ctx->st, &draw->base, &read->base);
354 
355    /* This is ok to call here. If they are already init, it's a no-op. */
356    if (ctx->pp && draw->textures[ST_ATTACHMENT_BACK_LEFT])
357       pp_init_fbos(ctx->pp, draw->textures[ST_ATTACHMENT_BACK_LEFT]->width0,
358                    draw->textures[ST_ATTACHMENT_BACK_LEFT]->height0);
359 
360    return GL_TRUE;
361 }
362 
363 struct dri_context *
dri_get_current(void)364 dri_get_current(void)
365 {
366    struct st_context *st = st_api_get_current();
367 
368    return (struct dri_context *) st ? st->frontend_context : NULL;
369 }
370 
371 /* vim: set sw=3 ts=8 sts=3 expandtab: */
372