st/mesa: add a notify_before_flush callback param to flush
[mesa.git] / src / gallium / state_trackers / dri / dri_context.c
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 "utils.h"
33
34 #include "dri_screen.h"
35 #include "dri_drawable.h"
36 #include "dri_context.h"
37 #include "state_tracker/drm_driver.h"
38
39 #include "pipe/p_context.h"
40 #include "pipe-loader/pipe_loader.h"
41 #include "state_tracker/st_context.h"
42
43 GLboolean
44 dri_create_context(gl_api api, const struct gl_config * visual,
45 __DRIcontext * cPriv,
46 const struct __DriverContextConfig *ctx_config,
47 unsigned *error,
48 void *sharedContextPrivate)
49 {
50 __DRIscreen *sPriv = cPriv->driScreenPriv;
51 struct dri_screen *screen = dri_screen(sPriv);
52 struct st_api *stapi = screen->st_api;
53 struct dri_context *ctx = NULL;
54 struct st_context_iface *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 __DRI_CTX_FLAG_NO_ERROR;
60 unsigned allowed_attribs =
61 __DRIVER_CONTEXT_ATTRIB_PRIORITY |
62 __DRIVER_CONTEXT_ATTRIB_RELEASE_BEHAVIOR;
63 const __DRIbackgroundCallableExtension *backgroundCallable =
64 screen->sPriv->dri2.backgroundCallable;
65 const struct driOptionCache *optionCache = &screen->dev->option_cache;
66
67 if (screen->has_reset_status_query) {
68 allowed_flags |= __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS;
69 allowed_attribs |= __DRIVER_CONTEXT_ATTRIB_RESET_STRATEGY;
70 }
71
72 if (ctx_config->flags & ~allowed_flags) {
73 *error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
74 goto fail;
75 }
76
77 if (ctx_config->attribute_mask & ~allowed_attribs) {
78 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
79 goto fail;
80 }
81
82 memset(&attribs, 0, sizeof(attribs));
83 switch (api) {
84 case API_OPENGLES:
85 attribs.profile = ST_PROFILE_OPENGL_ES1;
86 break;
87 case API_OPENGLES2:
88 attribs.profile = ST_PROFILE_OPENGL_ES2;
89 break;
90 case API_OPENGL_COMPAT:
91 case API_OPENGL_CORE:
92 if (driQueryOptionb(optionCache, "force_compat_profile")) {
93 attribs.profile = ST_PROFILE_DEFAULT;
94 } else {
95 attribs.profile = api == API_OPENGL_COMPAT ? ST_PROFILE_DEFAULT
96 : ST_PROFILE_OPENGL_CORE;
97 }
98
99 attribs.major = ctx_config->major_version;
100 attribs.minor = ctx_config->minor_version;
101
102 if ((ctx_config->flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0)
103 attribs.flags |= ST_CONTEXT_FLAG_FORWARD_COMPATIBLE;
104 break;
105 default:
106 *error = __DRI_CTX_ERROR_BAD_API;
107 goto fail;
108 }
109
110 if ((ctx_config->flags & __DRI_CTX_FLAG_DEBUG) != 0)
111 attribs.flags |= ST_CONTEXT_FLAG_DEBUG;
112
113 if (ctx_config->flags & __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS)
114 attribs.flags |= ST_CONTEXT_FLAG_ROBUST_ACCESS;
115
116 if (ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_RESET_STRATEGY)
117 if (ctx_config->reset_strategy != __DRI_CTX_RESET_NO_NOTIFICATION)
118 attribs.flags |= ST_CONTEXT_FLAG_RESET_NOTIFICATION_ENABLED;
119
120 if (ctx_config->flags & __DRI_CTX_FLAG_NO_ERROR)
121 attribs.flags |= ST_CONTEXT_FLAG_NO_ERROR;
122
123 if (ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_PRIORITY) {
124 switch (ctx_config->priority) {
125 case __DRI_CTX_PRIORITY_LOW:
126 attribs.flags |= ST_CONTEXT_FLAG_LOW_PRIORITY;
127 break;
128 case __DRI_CTX_PRIORITY_HIGH:
129 attribs.flags |= ST_CONTEXT_FLAG_HIGH_PRIORITY;
130 break;
131 default:
132 break;
133 }
134 }
135
136 if ((ctx_config->attribute_mask & __DRIVER_CONTEXT_ATTRIB_RELEASE_BEHAVIOR)
137 && (ctx_config->release_behavior == __DRI_CTX_RELEASE_BEHAVIOR_NONE))
138 attribs.flags |= ST_CONTEXT_FLAG_RELEASE_NONE;
139
140 struct dri_context *share_ctx = NULL;
141 if (sharedContextPrivate) {
142 share_ctx = (struct dri_context *)sharedContextPrivate;
143 st_share = share_ctx->st;
144 }
145
146 ctx = CALLOC_STRUCT(dri_context);
147 if (ctx == NULL) {
148 *error = __DRI_CTX_ERROR_NO_MEMORY;
149 goto fail;
150 }
151
152 cPriv->driverPrivate = ctx;
153 ctx->cPriv = cPriv;
154 ctx->sPriv = sPriv;
155
156 if (driQueryOptionb(&screen->dev->option_cache, "mesa_no_error"))
157 attribs.flags |= ST_CONTEXT_FLAG_NO_ERROR;
158
159 attribs.options = screen->options;
160 dri_fill_st_visual(&attribs.visual, screen, visual);
161 ctx->st = stapi->create_context(stapi, &screen->base, &attribs, &ctx_err,
162 st_share);
163 if (ctx->st == NULL) {
164 switch (ctx_err) {
165 case ST_CONTEXT_SUCCESS:
166 *error = __DRI_CTX_ERROR_SUCCESS;
167 break;
168 case ST_CONTEXT_ERROR_NO_MEMORY:
169 *error = __DRI_CTX_ERROR_NO_MEMORY;
170 break;
171 case ST_CONTEXT_ERROR_BAD_API:
172 *error = __DRI_CTX_ERROR_BAD_API;
173 break;
174 case ST_CONTEXT_ERROR_BAD_VERSION:
175 *error = __DRI_CTX_ERROR_BAD_VERSION;
176 break;
177 case ST_CONTEXT_ERROR_BAD_FLAG:
178 *error = __DRI_CTX_ERROR_BAD_FLAG;
179 break;
180 case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE:
181 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
182 break;
183 case ST_CONTEXT_ERROR_UNKNOWN_FLAG:
184 *error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
185 break;
186 }
187 goto fail;
188 }
189 ctx->st->st_manager_private = (void *) ctx;
190 ctx->stapi = stapi;
191
192 if (ctx->st->cso_context) {
193 ctx->pp = pp_init(ctx->st->pipe, screen->pp_enabled, ctx->st->cso_context);
194 ctx->hud = hud_create(ctx->st->cso_context,
195 share_ctx ? share_ctx->hud : NULL);
196 }
197
198 /* Do this last. */
199 if (ctx->st->start_thread &&
200 driQueryOptionb(&screen->dev->option_cache, "mesa_glthread")) {
201
202 if (backgroundCallable && backgroundCallable->base.version >= 2 &&
203 backgroundCallable->isThreadSafe) {
204
205 if (backgroundCallable->isThreadSafe(cPriv->loaderPrivate))
206 ctx->st->start_thread(ctx->st);
207 else
208 fprintf(stderr, "dri_create_context: glthread isn't thread safe "
209 "- missing call XInitThreads\n");
210 } else {
211 fprintf(stderr, "dri_create_context: requested glthread but driver "
212 "is missing backgroundCallable V2 extension\n");
213 }
214 }
215
216 *error = __DRI_CTX_ERROR_SUCCESS;
217 return GL_TRUE;
218
219 fail:
220 if (ctx && ctx->st)
221 ctx->st->destroy(ctx->st);
222
223 free(ctx);
224 return GL_FALSE;
225 }
226
227 void
228 dri_destroy_context(__DRIcontext * cPriv)
229 {
230 struct dri_context *ctx = dri_context(cPriv);
231
232 if (ctx->hud) {
233 hud_destroy(ctx->hud, ctx->st->cso_context);
234 }
235
236 if (ctx->pp)
237 pp_free(ctx->pp);
238
239 /* No particular reason to wait for command completion before
240 * destroying a context, but we flush the context here
241 * to avoid having to add code elsewhere to cope with flushing a
242 * partially destroyed context.
243 */
244 ctx->st->flush(ctx->st, 0, NULL, NULL, NULL);
245 ctx->st->destroy(ctx->st);
246 free(ctx);
247 }
248
249 /* This is called inside MakeCurrent to unbind the context. */
250 GLboolean
251 dri_unbind_context(__DRIcontext * cPriv)
252 {
253 /* dri_util.c ensures cPriv is not null */
254 struct dri_screen *screen = dri_screen(cPriv->driScreenPriv);
255 struct dri_context *ctx = dri_context(cPriv);
256 struct st_context_iface *st = ctx->st;
257 struct st_api *stapi = screen->st_api;
258
259 if (--ctx->bind_count == 0) {
260 if (st == stapi->get_current(stapi)) {
261 if (st->thread_finish)
262 st->thread_finish(st);
263
264 /* Record HUD queries for the duration the context was "current". */
265 if (ctx->hud)
266 hud_record_only(ctx->hud, st->pipe);
267
268 stapi->make_current(stapi, NULL, NULL, NULL);
269 }
270 }
271
272 return GL_TRUE;
273 }
274
275 GLboolean
276 dri_make_current(__DRIcontext * cPriv,
277 __DRIdrawable * driDrawPriv,
278 __DRIdrawable * driReadPriv)
279 {
280 /* dri_util.c ensures cPriv is not null */
281 struct dri_context *ctx = dri_context(cPriv);
282 struct dri_drawable *draw = dri_drawable(driDrawPriv);
283 struct dri_drawable *read = dri_drawable(driReadPriv);
284
285 ++ctx->bind_count;
286
287 if (!draw && !read)
288 return ctx->stapi->make_current(ctx->stapi, ctx->st, NULL, NULL);
289 else if (!draw || !read)
290 return GL_FALSE;
291
292 if (ctx->dPriv != driDrawPriv) {
293 ctx->dPriv = driDrawPriv;
294 draw->texture_stamp = driDrawPriv->lastStamp - 1;
295 }
296 if (ctx->rPriv != driReadPriv) {
297 ctx->rPriv = driReadPriv;
298 read->texture_stamp = driReadPriv->lastStamp - 1;
299 }
300
301 ctx->stapi->make_current(ctx->stapi, ctx->st, &draw->base, &read->base);
302
303 /* This is ok to call here. If they are already init, it's a no-op. */
304 if (ctx->pp && draw->textures[ST_ATTACHMENT_BACK_LEFT])
305 pp_init_fbos(ctx->pp, draw->textures[ST_ATTACHMENT_BACK_LEFT]->width0,
306 draw->textures[ST_ATTACHMENT_BACK_LEFT]->height0);
307
308 return GL_TRUE;
309 }
310
311 struct dri_context *
312 dri_get_current(__DRIscreen *sPriv)
313 {
314 struct dri_screen *screen = dri_screen(sPriv);
315 struct st_api *stapi = screen->st_api;
316 struct st_context_iface *st;
317
318 st = stapi->get_current(stapi);
319
320 return (struct dri_context *) st ? st->st_manager_private : NULL;
321 }
322
323 /* vim: set sw=3 ts=8 sts=3 expandtab: */