gallium: implement the backend of threaded GL dispatch
[mesa.git] / src / gallium / state_trackers / dri / dri_drawable.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 "dri_screen.h"
33 #include "dri_context.h"
34 #include "dri_drawable.h"
35
36 #include "pipe/p_screen.h"
37 #include "util/u_format.h"
38 #include "util/u_memory.h"
39 #include "util/u_inlines.h"
40
41 static void
42 swap_fences_unref(struct dri_drawable *draw);
43
44 static boolean
45 dri_st_framebuffer_validate(struct st_context_iface *stctx,
46 struct st_framebuffer_iface *stfbi,
47 const enum st_attachment_type *statts,
48 unsigned count,
49 struct pipe_resource **out)
50 {
51 struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;
52 struct dri_drawable *drawable =
53 (struct dri_drawable *) stfbi->st_manager_private;
54 struct dri_screen *screen = dri_screen(drawable->sPriv);
55 unsigned statt_mask, new_mask;
56 boolean new_stamp;
57 int i;
58 unsigned int lastStamp;
59 struct pipe_resource **textures =
60 drawable->stvis.samples > 1 ? drawable->msaa_textures
61 : drawable->textures;
62
63 statt_mask = 0x0;
64 for (i = 0; i < count; i++)
65 statt_mask |= (1 << statts[i]);
66
67 /* record newly allocated textures */
68 new_mask = (statt_mask & ~drawable->texture_mask);
69
70 /*
71 * dPriv->dri2.stamp is the server stamp. dPriv->lastStamp is the
72 * client stamp. It has the value of the server stamp when last
73 * checked.
74 */
75 do {
76 lastStamp = drawable->dPriv->lastStamp;
77 new_stamp = (drawable->texture_stamp != lastStamp);
78
79 if (new_stamp || new_mask || screen->broken_invalidate) {
80 if (new_stamp && drawable->update_drawable_info)
81 drawable->update_drawable_info(drawable);
82
83 drawable->allocate_textures(ctx, drawable, statts, count);
84
85 /* add existing textures */
86 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
87 if (textures[i])
88 statt_mask |= (1 << i);
89 }
90
91 drawable->texture_stamp = lastStamp;
92 drawable->texture_mask = statt_mask;
93 }
94 } while (lastStamp != drawable->dPriv->lastStamp);
95
96 if (!out)
97 return TRUE;
98
99 /* Set the window-system buffers for the state tracker. */
100 for (i = 0; i < count; i++) {
101 out[i] = NULL;
102 pipe_resource_reference(&out[i], textures[statts[i]]);
103 }
104
105 return TRUE;
106 }
107
108 static boolean
109 dri_st_framebuffer_flush_front(struct st_context_iface *stctx,
110 struct st_framebuffer_iface *stfbi,
111 enum st_attachment_type statt)
112 {
113 struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;
114 struct dri_drawable *drawable =
115 (struct dri_drawable *) stfbi->st_manager_private;
116
117 /* XXX remove this and just set the correct one on the framebuffer */
118 drawable->flush_frontbuffer(ctx, drawable, statt);
119
120 return TRUE;
121 }
122
123 /**
124 * This is called when we need to set up GL rendering to a new X window.
125 */
126 boolean
127 dri_create_buffer(__DRIscreen * sPriv,
128 __DRIdrawable * dPriv,
129 const struct gl_config * visual, boolean isPixmap)
130 {
131 struct dri_screen *screen = sPriv->driverPrivate;
132 struct dri_drawable *drawable = NULL;
133
134 if (isPixmap)
135 goto fail; /* not implemented */
136
137 drawable = CALLOC_STRUCT(dri_drawable);
138 if (drawable == NULL)
139 goto fail;
140
141 dri_fill_st_visual(&drawable->stvis, screen, visual);
142
143 /* setup the st_framebuffer_iface */
144 drawable->base.visual = &drawable->stvis;
145 drawable->base.flush_front = dri_st_framebuffer_flush_front;
146 drawable->base.validate = dri_st_framebuffer_validate;
147 drawable->base.st_manager_private = (void *) drawable;
148
149 drawable->screen = screen;
150 drawable->sPriv = sPriv;
151 drawable->dPriv = dPriv;
152 drawable->desired_fences = screen->default_throttle_frames;
153 if (drawable->desired_fences > DRI_SWAP_FENCES_MAX)
154 drawable->desired_fences = DRI_SWAP_FENCES_MAX;
155
156 dPriv->driverPrivate = (void *)drawable;
157 p_atomic_set(&drawable->base.stamp, 1);
158
159 return GL_TRUE;
160 fail:
161 FREE(drawable);
162 return GL_FALSE;
163 }
164
165 void
166 dri_destroy_buffer(__DRIdrawable * dPriv)
167 {
168 struct dri_drawable *drawable = dri_drawable(dPriv);
169 int i;
170
171 pipe_surface_reference(&drawable->drisw_surface, NULL);
172
173 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
174 pipe_resource_reference(&drawable->textures[i], NULL);
175 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
176 pipe_resource_reference(&drawable->msaa_textures[i], NULL);
177
178 swap_fences_unref(drawable);
179
180 FREE(drawable);
181 }
182
183 /**
184 * Validate the texture at an attachment. Allocate the texture if it does not
185 * exist. Used by the TFP extension.
186 */
187 static void
188 dri_drawable_validate_att(struct dri_context *ctx,
189 struct dri_drawable *drawable,
190 enum st_attachment_type statt)
191 {
192 enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
193 unsigned i, count = 0;
194
195 /* check if buffer already exists */
196 if (drawable->texture_mask & (1 << statt))
197 return;
198
199 /* make sure DRI2 does not destroy existing buffers */
200 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
201 if (drawable->texture_mask & (1 << i)) {
202 statts[count++] = i;
203 }
204 }
205 statts[count++] = statt;
206
207 drawable->texture_stamp = drawable->dPriv->lastStamp - 1;
208
209 drawable->base.validate(ctx->st, &drawable->base, statts, count, NULL);
210 }
211
212 /**
213 * These are used for GLX_EXT_texture_from_pixmap
214 */
215 static void
216 dri_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,
217 GLint format, __DRIdrawable *dPriv)
218 {
219 struct dri_context *ctx = dri_context(pDRICtx);
220 struct st_context_iface *st = ctx->st;
221 struct dri_drawable *drawable = dri_drawable(dPriv);
222 struct pipe_resource *pt;
223
224 if (st->thread_finish)
225 st->thread_finish(st);
226
227 dri_drawable_validate_att(ctx, drawable, ST_ATTACHMENT_FRONT_LEFT);
228
229 /* Use the pipe resource associated with the X drawable */
230 pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
231
232 if (pt) {
233 enum pipe_format internal_format = pt->format;
234
235 if (format == __DRI_TEXTURE_FORMAT_RGB) {
236 /* only need to cover the formats recognized by dri_fill_st_visual */
237 switch (internal_format) {
238 case PIPE_FORMAT_BGRA8888_UNORM:
239 internal_format = PIPE_FORMAT_BGRX8888_UNORM;
240 break;
241 case PIPE_FORMAT_ARGB8888_UNORM:
242 internal_format = PIPE_FORMAT_XRGB8888_UNORM;
243 break;
244 default:
245 break;
246 }
247 }
248
249 drawable->update_tex_buffer(drawable, ctx, pt);
250
251 ctx->st->teximage(ctx->st,
252 (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT,
253 0, internal_format, pt, FALSE);
254 }
255 }
256
257 static void
258 dri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target,
259 __DRIdrawable *dPriv)
260 {
261 dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
262 }
263
264 const __DRItexBufferExtension driTexBufferExtension = {
265 .base = { __DRI_TEX_BUFFER, 2 },
266
267 .setTexBuffer = dri_set_tex_buffer,
268 .setTexBuffer2 = dri_set_tex_buffer2,
269 .releaseTexBuffer = NULL,
270 };
271
272 /**
273 * Get the format and binding of an attachment.
274 */
275 void
276 dri_drawable_get_format(struct dri_drawable *drawable,
277 enum st_attachment_type statt,
278 enum pipe_format *format,
279 unsigned *bind)
280 {
281 switch (statt) {
282 case ST_ATTACHMENT_FRONT_LEFT:
283 case ST_ATTACHMENT_BACK_LEFT:
284 case ST_ATTACHMENT_FRONT_RIGHT:
285 case ST_ATTACHMENT_BACK_RIGHT:
286 /* Other pieces of the driver stack get confused and behave incorrectly
287 * when they get an sRGB drawable. st/mesa receives "drawable->stvis"
288 * though other means and handles it correctly, so we don't really need
289 * to use an sRGB format here.
290 */
291 *format = util_format_linear(drawable->stvis.color_format);
292 *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
293 break;
294 case ST_ATTACHMENT_DEPTH_STENCIL:
295 *format = drawable->stvis.depth_stencil_format;
296 *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
297 break;
298 default:
299 *format = PIPE_FORMAT_NONE;
300 *bind = 0;
301 break;
302 }
303 }
304
305
306 /**
307 * swap_fences_pop_front - pull a fence from the throttle queue
308 *
309 * If the throttle queue is filled to the desired number of fences,
310 * pull fences off the queue until the number is less than the desired
311 * number of fences, and return the last fence pulled.
312 */
313 static struct pipe_fence_handle *
314 swap_fences_pop_front(struct dri_drawable *draw)
315 {
316 struct pipe_screen *screen = draw->screen->base.screen;
317 struct pipe_fence_handle *fence = NULL;
318
319 if (draw->desired_fences == 0)
320 return NULL;
321
322 if (draw->cur_fences >= draw->desired_fences) {
323 screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]);
324 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL);
325 draw->tail &= DRI_SWAP_FENCES_MASK;
326 --draw->cur_fences;
327 }
328 return fence;
329 }
330
331
332 /**
333 * swap_fences_push_back - push a fence onto the throttle queue
334 *
335 * push a fence onto the throttle queue and pull fences of the queue
336 * so that the desired number of fences are on the queue.
337 */
338 static void
339 swap_fences_push_back(struct dri_drawable *draw,
340 struct pipe_fence_handle *fence)
341 {
342 struct pipe_screen *screen = draw->screen->base.screen;
343
344 if (!fence || draw->desired_fences == 0)
345 return;
346
347 while(draw->cur_fences == draw->desired_fences)
348 swap_fences_pop_front(draw);
349
350 draw->cur_fences++;
351 screen->fence_reference(screen, &draw->swap_fences[draw->head++],
352 fence);
353 draw->head &= DRI_SWAP_FENCES_MASK;
354 }
355
356
357 /**
358 * swap_fences_unref - empty the throttle queue
359 *
360 * pulls fences of the throttle queue until it is empty.
361 */
362 static void
363 swap_fences_unref(struct dri_drawable *draw)
364 {
365 struct pipe_screen *screen = draw->screen->base.screen;
366
367 while(draw->cur_fences) {
368 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL);
369 draw->tail &= DRI_SWAP_FENCES_MASK;
370 --draw->cur_fences;
371 }
372 }
373
374 void
375 dri_pipe_blit(struct pipe_context *pipe,
376 struct pipe_resource *dst,
377 struct pipe_resource *src)
378 {
379 struct pipe_blit_info blit;
380
381 if (!dst || !src)
382 return;
383
384 /* From the GL spec, version 4.2, section 4.1.11 (Additional Multisample
385 * Fragment Operations):
386 *
387 * If a framebuffer object is not bound, after all operations have
388 * been completed on the multisample buffer, the sample values for
389 * each color in the multisample buffer are combined to produce a
390 * single color value, and that value is written into the
391 * corresponding color buffers selected by DrawBuffer or
392 * DrawBuffers. An implementation may defer the writing of the color
393 * buffers until a later time, but the state of the framebuffer must
394 * behave as if the color buffers were updated as each fragment was
395 * processed. The method of combination is not specified. If the
396 * framebuffer contains sRGB values, then it is recommended that the
397 * an average of sample values is computed in a linearized space, as
398 * for blending (see section 4.1.7).
399 *
400 * In other words, to do a resolve operation in a linear space, we have
401 * to set sRGB formats if the original resources were sRGB, so don't use
402 * util_format_linear.
403 */
404
405 memset(&blit, 0, sizeof(blit));
406 blit.dst.resource = dst;
407 blit.dst.box.width = dst->width0;
408 blit.dst.box.height = dst->height0;
409 blit.dst.box.depth = 1;
410 blit.dst.format = dst->format;
411 blit.src.resource = src;
412 blit.src.box.width = src->width0;
413 blit.src.box.height = src->height0;
414 blit.src.box.depth = 1;
415 blit.src.format = src->format;
416 blit.mask = PIPE_MASK_RGBA;
417 blit.filter = PIPE_TEX_FILTER_NEAREST;
418
419 pipe->blit(pipe, &blit);
420 }
421
422 static void
423 dri_postprocessing(struct dri_context *ctx,
424 struct dri_drawable *drawable,
425 enum st_attachment_type att)
426 {
427 struct pipe_resource *src = drawable->textures[att];
428 struct pipe_resource *zsbuf = drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL];
429
430 if (ctx->pp && src)
431 pp_run(ctx->pp, src, src, zsbuf);
432 }
433
434 /**
435 * DRI2 flush extension, the flush_with_flags function.
436 *
437 * \param context the context
438 * \param drawable the drawable to flush
439 * \param flags a combination of _DRI2_FLUSH_xxx flags
440 * \param throttle_reason the reason for throttling, 0 = no throttling
441 */
442 void
443 dri_flush(__DRIcontext *cPriv,
444 __DRIdrawable *dPriv,
445 unsigned flags,
446 enum __DRI2throttleReason reason)
447 {
448 struct dri_context *ctx = dri_context(cPriv);
449 struct dri_drawable *drawable = dri_drawable(dPriv);
450 struct st_context_iface *st;
451 unsigned flush_flags;
452 boolean swap_msaa_buffers = FALSE;
453
454 if (!ctx) {
455 assert(0);
456 return;
457 }
458
459 st = ctx->st;
460 if (st->thread_finish)
461 st->thread_finish(st);
462
463 if (drawable) {
464 /* prevent recursion */
465 if (drawable->flushing)
466 return;
467
468 drawable->flushing = TRUE;
469 }
470 else {
471 flags &= ~__DRI2_FLUSH_DRAWABLE;
472 }
473
474 /* Flush the drawable. */
475 if ((flags & __DRI2_FLUSH_DRAWABLE) &&
476 drawable->textures[ST_ATTACHMENT_BACK_LEFT]) {
477 struct pipe_context *pipe = st->pipe;
478
479 if (drawable->stvis.samples > 1 &&
480 reason == __DRI2_THROTTLE_SWAPBUFFER) {
481 /* Resolve the MSAA back buffer. */
482 dri_pipe_blit(st->pipe,
483 drawable->textures[ST_ATTACHMENT_BACK_LEFT],
484 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]);
485
486 if (drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] &&
487 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]) {
488 swap_msaa_buffers = TRUE;
489 }
490
491 /* FRONT_LEFT is resolved in drawable->flush_frontbuffer. */
492 }
493
494 dri_postprocessing(ctx, drawable, ST_ATTACHMENT_BACK_LEFT);
495
496 if (ctx->hud) {
497 hud_draw(ctx->hud, drawable->textures[ST_ATTACHMENT_BACK_LEFT]);
498 }
499
500 pipe->flush_resource(pipe, drawable->textures[ST_ATTACHMENT_BACK_LEFT]);
501
502 if (pipe->invalidate_resource &&
503 (flags & __DRI2_FLUSH_INVALIDATE_ANCILLARY)) {
504 if (drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])
505 pipe->invalidate_resource(pipe, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
506 if (drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL])
507 pipe->invalidate_resource(pipe, drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]);
508 }
509 }
510
511 flush_flags = 0;
512 if (flags & __DRI2_FLUSH_CONTEXT)
513 flush_flags |= ST_FLUSH_FRONT;
514 if (reason == __DRI2_THROTTLE_SWAPBUFFER)
515 flush_flags |= ST_FLUSH_END_OF_FRAME;
516
517 /* Flush the context and throttle if needed. */
518 if (dri_screen(ctx->sPriv)->throttling_enabled &&
519 drawable &&
520 (reason == __DRI2_THROTTLE_SWAPBUFFER ||
521 reason == __DRI2_THROTTLE_FLUSHFRONT)) {
522 /* Throttle.
523 *
524 * This pulls a fence off the throttling queue and waits for it if the
525 * number of fences on the throttling queue has reached the desired
526 * number.
527 *
528 * Then flushes to insert a fence at the current rendering position, and
529 * pushes that fence on the queue. This requires that the st_context_iface
530 * flush method returns a fence even if there are no commands to flush.
531 */
532 struct pipe_screen *screen = drawable->screen->base.screen;
533 struct pipe_fence_handle *fence;
534
535 fence = swap_fences_pop_front(drawable);
536 if (fence) {
537 (void) screen->fence_finish(screen, NULL, fence, PIPE_TIMEOUT_INFINITE);
538 screen->fence_reference(screen, &fence, NULL);
539 }
540
541 st->flush(st, flush_flags, &fence);
542
543 if (fence) {
544 swap_fences_push_back(drawable, fence);
545 screen->fence_reference(screen, &fence, NULL);
546 }
547 }
548 else if (flags & (__DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_CONTEXT)) {
549 st->flush(st, flush_flags, NULL);
550 }
551
552 if (drawable) {
553 drawable->flushing = FALSE;
554 }
555
556 /* Swap the MSAA front and back buffers, so that reading
557 * from the front buffer after SwapBuffers returns what was
558 * in the back buffer.
559 */
560 if (swap_msaa_buffers) {
561 struct pipe_resource *tmp =
562 drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT];
563
564 drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] =
565 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT];
566 drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT] = tmp;
567
568 /* Now that we have swapped the buffers, this tells the state
569 * tracker to revalidate the framebuffer.
570 */
571 p_atomic_inc(&drawable->base.stamp);
572 }
573 }
574
575 /**
576 * dri_throttle - A DRI2ThrottleExtension throttling function.
577 */
578 static void
579 dri_throttle(__DRIcontext *cPriv, __DRIdrawable *dPriv,
580 enum __DRI2throttleReason reason)
581 {
582 dri_flush(cPriv, dPriv, 0, reason);
583 }
584
585
586 const __DRI2throttleExtension dri2ThrottleExtension = {
587 .base = { __DRI2_THROTTLE, 1 },
588
589 .throttle = dri_throttle,
590 };
591
592
593 /* vim: set sw=3 ts=8 sts=3 expandtab: */