Merge branch 'mesa_7_5_branch'
[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_context.h"
37 #include "pipe/p_screen.h"
38 #include "pipe/p_inlines.h"
39 #include "state_tracker/drm_api.h"
40 #include "state_tracker/dri1_api.h"
41 #include "state_tracker/st_public.h"
42 #include "state_tracker/st_context.h"
43 #include "state_tracker/st_cb_fbo.h"
44
45 #include "util/u_memory.h"
46
47 static void
48 dri_copy_to_front(__DRIdrawablePrivate * dPriv,
49 struct pipe_surface *from,
50 int x, int y, unsigned w, unsigned h)
51 {
52 /* TODO send a message to the Xserver to copy to the real front buffer */
53 }
54
55 static struct pipe_surface *
56 dri_surface_from_handle(struct drm_api *api,
57 struct pipe_screen *screen,
58 unsigned handle,
59 enum pipe_format format,
60 unsigned width, unsigned height, unsigned pitch)
61 {
62 struct pipe_surface *surface = NULL;
63 struct pipe_texture *texture = NULL;
64 struct pipe_texture templat;
65 struct pipe_buffer *buf = NULL;
66
67 buf = api->buffer_from_handle(api, screen, "dri2 buffer", handle);
68 if (!buf)
69 return NULL;
70
71 memset(&templat, 0, sizeof(templat));
72 templat.tex_usage |= PIPE_TEXTURE_USAGE_RENDER_TARGET;
73 templat.target = PIPE_TEXTURE_2D;
74 templat.last_level = 0;
75 templat.depth[0] = 1;
76 templat.format = format;
77 templat.width[0] = width;
78 templat.height[0] = height;
79 pf_get_block(templat.format, &templat.block);
80
81 texture = screen->texture_blanket(screen, &templat, &pitch, buf);
82
83 /* we don't need the buffer from this point on */
84 pipe_buffer_reference(&buf, NULL);
85
86 if (!texture)
87 return NULL;
88
89 surface = screen->get_tex_surface(screen, texture, 0, 0, 0,
90 PIPE_BUFFER_USAGE_GPU_READ |
91 PIPE_BUFFER_USAGE_GPU_WRITE);
92
93 /* we don't need the texture from this point on */
94 pipe_texture_reference(&texture, NULL);
95 return surface;
96 }
97
98 /**
99 * This will be called a drawable is known to have been resized.
100 */
101 void
102 dri_get_buffers(__DRIdrawablePrivate * dPriv)
103 {
104
105 struct dri_drawable *drawable = dri_drawable(dPriv);
106 struct pipe_surface *surface = NULL;
107 struct pipe_screen *screen = dri_screen(drawable->sPriv)->pipe_screen;
108 __DRIbuffer *buffers = NULL;
109 __DRIscreen *dri_screen = drawable->sPriv;
110 __DRIdrawable *dri_drawable = drawable->dPriv;
111 struct drm_api *api = ((struct dri_screen*)(dri_screen->private))->api;
112 boolean have_depth = FALSE;
113 int i, count;
114
115 buffers = (*dri_screen->dri2.loader->getBuffers) (dri_drawable,
116 &dri_drawable->w,
117 &dri_drawable->h,
118 drawable->attachments,
119 drawable->
120 num_attachments, &count,
121 dri_drawable->
122 loaderPrivate);
123
124 if (buffers == NULL) {
125 return;
126 }
127
128 /* set one cliprect to cover the whole dri_drawable */
129 dri_drawable->x = 0;
130 dri_drawable->y = 0;
131 dri_drawable->backX = 0;
132 dri_drawable->backY = 0;
133 dri_drawable->numClipRects = 1;
134 dri_drawable->pClipRects[0].x1 = 0;
135 dri_drawable->pClipRects[0].y1 = 0;
136 dri_drawable->pClipRects[0].x2 = dri_drawable->w;
137 dri_drawable->pClipRects[0].y2 = dri_drawable->h;
138 dri_drawable->numBackClipRects = 1;
139 dri_drawable->pBackClipRects[0].x1 = 0;
140 dri_drawable->pBackClipRects[0].y1 = 0;
141 dri_drawable->pBackClipRects[0].x2 = dri_drawable->w;
142 dri_drawable->pBackClipRects[0].y2 = dri_drawable->h;
143
144 if (drawable->old_num == count &&
145 drawable->old_w == dri_drawable->w &&
146 drawable->old_h == dri_drawable->h &&
147 memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * count) == 0) {
148 return;
149 } else {
150 drawable->old_num = count;
151 drawable->old_w = dri_drawable->w;
152 drawable->old_h = dri_drawable->h;
153 memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * count);
154 }
155
156 for (i = 0; i < count; i++) {
157 enum pipe_format format = 0;
158 int index = 0;
159
160 switch (buffers[i].attachment) {
161 case __DRI_BUFFER_FRONT_LEFT:
162 index = ST_SURFACE_FRONT_LEFT;
163 format = drawable->color_format;
164 break;
165 case __DRI_BUFFER_FAKE_FRONT_LEFT:
166 index = ST_SURFACE_FRONT_LEFT;
167 format = drawable->color_format;
168 break;
169 case __DRI_BUFFER_BACK_LEFT:
170 index = ST_SURFACE_BACK_LEFT;
171 format = drawable->color_format;
172 break;
173 case __DRI_BUFFER_DEPTH:
174 index = ST_SURFACE_DEPTH;
175 format = drawable->depth_format;
176 break;
177 case __DRI_BUFFER_STENCIL:
178 index = ST_SURFACE_DEPTH;
179 format = drawable->stencil_format;
180 break;
181 case __DRI_BUFFER_ACCUM:
182 default:
183 assert(0);
184 }
185
186 if (index == ST_SURFACE_DEPTH) {
187 if (have_depth)
188 continue;
189 else
190 have_depth = TRUE;
191 }
192
193 surface = dri_surface_from_handle(api,
194 screen,
195 buffers[i].name,
196 format,
197 dri_drawable->w,
198 dri_drawable->h, buffers[i].pitch);
199
200 st_set_framebuffer_surface(drawable->stfb, index, surface);
201 pipe_surface_reference(&surface, NULL);
202 }
203 /* this needed, or else the state tracker fails to pick the new buffers */
204 st_resize_framebuffer(drawable->stfb, dri_drawable->w, dri_drawable->h);
205 }
206
207 void
208 dri_flush_frontbuffer(struct pipe_screen *screen,
209 struct pipe_surface *surf, void *context_private)
210 {
211 struct dri_context *ctx = (struct dri_context *)context_private;
212
213 dri_copy_to_front(ctx->dPriv, surf, 0, 0, surf->width, surf->height);
214 }
215
216 /**
217 * This is called when we need to set up GL rendering to a new X window.
218 */
219 boolean
220 dri_create_buffer(__DRIscreenPrivate * sPriv,
221 __DRIdrawablePrivate * dPriv,
222 const __GLcontextModes * visual, boolean isPixmap)
223 {
224 struct dri_screen *screen = sPriv->private;
225 struct dri_drawable *drawable = NULL;
226 int i;
227
228 if (isPixmap)
229 goto fail; /* not implemented */
230
231 drawable = CALLOC_STRUCT(dri_drawable);
232 if (drawable == NULL)
233 goto fail;
234
235 drawable->color_format = (visual->redBits == 8) ?
236 PIPE_FORMAT_A8R8G8B8_UNORM : PIPE_FORMAT_R5G6B5_UNORM;
237
238 debug_printf("Red bits is %d\n", visual->redBits);
239
240 switch(visual->depthBits) {
241 default:
242 case 0:
243 debug_printf("Depth buffer 0.\n");
244 drawable->depth_format = PIPE_FORMAT_NONE;
245 break;
246 case 16:
247 debug_printf("Depth buffer 16.\n");
248 drawable->depth_format = PIPE_FORMAT_Z16_UNORM;
249 break;
250 case 24:
251 if (visual->stencilBits == 0) {
252 debug_printf("Depth buffer 24. Stencil 0.\n");
253 drawable->depth_format = (screen->d_depth_bits_last) ?
254 PIPE_FORMAT_X8Z24_UNORM:
255 PIPE_FORMAT_Z24X8_UNORM;
256 } else {
257 debug_printf("Combined depth stencil 24 / 8.\n");
258 drawable->depth_format = (screen->sd_depth_bits_last) ?
259 PIPE_FORMAT_S8Z24_UNORM:
260 PIPE_FORMAT_Z24S8_UNORM;
261 }
262 break;
263 }
264
265 switch(visual->stencilBits) {
266 default:
267 case 0:
268 drawable->stencil_format = PIPE_FORMAT_NONE;
269 break;
270 case 8:
271 drawable->stencil_format = (screen->sd_depth_bits_last) ?
272 PIPE_FORMAT_S8Z24_UNORM:
273 PIPE_FORMAT_Z24S8_UNORM;
274 break;
275 }
276
277 drawable->stfb = st_create_framebuffer(visual,
278 drawable->color_format,
279 drawable->depth_format,
280 drawable->stencil_format,
281 dPriv->w,
282 dPriv->h, (void *)drawable);
283 if (drawable->stfb == NULL)
284 goto fail;
285
286 drawable->sPriv = sPriv;
287 drawable->dPriv = dPriv;
288 dPriv->driverPrivate = (void *)drawable;
289
290 /* setup dri2 buffers information */
291 i = 0;
292 drawable->attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
293 #if 0
294 /* TODO incase of double buffer visual, delay fake creation */
295 drawable->attachments[i++] = __DRI_BUFFER_FAKE_FRONT_LEFT;
296 #endif
297 if (visual->doubleBufferMode)
298 drawable->attachments[i++] = __DRI_BUFFER_BACK_LEFT;
299 if (visual->depthBits)
300 drawable->attachments[i++] = __DRI_BUFFER_DEPTH;
301 if (visual->stencilBits)
302 drawable->attachments[i++] = __DRI_BUFFER_STENCIL;
303 drawable->num_attachments = i;
304
305 drawable->desired_fences = 2;
306
307 return GL_TRUE;
308 fail:
309 FREE(drawable);
310 return GL_FALSE;
311 }
312
313 static struct pipe_fence_handle *
314 dri_swap_fences_pop_front(struct dri_drawable *draw)
315 {
316 struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen;
317 struct pipe_fence_handle *fence = NULL;
318
319 if (draw->cur_fences >= draw->desired_fences) {
320 screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]);
321 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL);
322 --draw->cur_fences;
323 draw->tail &= DRI_SWAP_FENCES_MASK;
324 }
325 return fence;
326 }
327
328 static void
329 dri_swap_fences_push_back(struct dri_drawable *draw,
330 struct pipe_fence_handle *fence)
331 {
332 struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen;
333
334 if (!fence)
335 return;
336
337 if (draw->cur_fences < DRI_SWAP_FENCES_MAX) {
338 draw->cur_fences++;
339 screen->fence_reference(screen, &draw->swap_fences[draw->head++],
340 fence);
341 draw->head &= DRI_SWAP_FENCES_MASK;
342 }
343 }
344
345 void
346 dri_destroy_buffer(__DRIdrawablePrivate * dPriv)
347 {
348 struct dri_drawable *drawable = dri_drawable(dPriv);
349 struct pipe_fence_handle *fence;
350 struct pipe_screen *screen = dri_screen(drawable->sPriv)->pipe_screen;
351
352 st_unreference_framebuffer(drawable->stfb);
353 drawable->desired_fences = 0;
354 while (drawable->cur_fences) {
355 fence = dri_swap_fences_pop_front(drawable);
356 screen->fence_reference(screen, &fence, NULL);
357 }
358
359 FREE(drawable);
360 }
361
362 static void
363 dri1_update_drawables_locked(struct dri_context *ctx,
364 __DRIdrawablePrivate * driDrawPriv,
365 __DRIdrawablePrivate * driReadPriv)
366 {
367 if (ctx->stLostLock) {
368 ctx->stLostLock = FALSE;
369 if (driDrawPriv == driReadPriv)
370 DRI_VALIDATE_DRAWABLE_INFO(ctx->sPriv, driDrawPriv);
371 else
372 DRI_VALIDATE_TWO_DRAWABLES_INFO(ctx->sPriv, driDrawPriv,
373 driReadPriv);
374 }
375 }
376
377 /**
378 * This ensures all contexts which bind to a drawable pick up the
379 * drawable change and signal new buffer state.
380 * Calling st_resize_framebuffer for each context may seem like overkill,
381 * but no new buffers will actually be allocated if the dimensions don't
382 * change.
383 */
384
385 static void
386 dri1_propagate_drawable_change(struct dri_context *ctx)
387 {
388 __DRIdrawablePrivate *dPriv = ctx->dPriv;
389 __DRIdrawablePrivate *rPriv = ctx->rPriv;
390 boolean flushed = FALSE;
391
392 if (dPriv && ctx->d_stamp != dPriv->lastStamp) {
393
394 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
395 flushed = TRUE;
396 ctx->d_stamp = dPriv->lastStamp;
397 st_resize_framebuffer(dri_drawable(dPriv)->stfb, dPriv->w, dPriv->h);
398
399 }
400
401 if (rPriv && dPriv != rPriv && ctx->r_stamp != rPriv->lastStamp) {
402
403 if (!flushed)
404 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
405 ctx->r_stamp = rPriv->lastStamp;
406 st_resize_framebuffer(dri_drawable(rPriv)->stfb, rPriv->w, rPriv->h);
407
408 } else if (rPriv && dPriv == rPriv) {
409
410 ctx->r_stamp = ctx->d_stamp;
411
412 }
413 }
414
415 void
416 dri1_update_drawables(struct dri_context *ctx,
417 struct dri_drawable *draw, struct dri_drawable *read)
418 {
419 dri_lock(ctx);
420 dri1_update_drawables_locked(ctx, draw->dPriv, read->dPriv);
421 dri_unlock(ctx);
422
423 dri1_propagate_drawable_change(ctx);
424 }
425
426 static INLINE boolean
427 dri1_intersect_src_bbox(struct drm_clip_rect *dst,
428 int dst_x,
429 int dst_y,
430 const struct drm_clip_rect *src,
431 const struct drm_clip_rect *bbox)
432 {
433 int xy1;
434 int xy2;
435
436 xy1 = ((int)src->x1 > (int)bbox->x1 + dst_x) ? src->x1 :
437 (int)bbox->x1 + dst_x;
438 xy2 = ((int)src->x2 < (int)bbox->x2 + dst_x) ? src->x2 :
439 (int)bbox->x2 + dst_x;
440 if (xy1 >= xy2 || xy1 < 0)
441 return FALSE;
442
443 dst->x1 = xy1;
444 dst->x2 = xy2;
445
446 xy1 = ((int)src->y1 > (int)bbox->y1 + dst_y) ? src->y1 :
447 (int)bbox->y1 + dst_y;
448 xy2 = ((int)src->y2 < (int)bbox->y2 + dst_y) ? src->y2 :
449 (int)bbox->y2 + dst_y;
450 if (xy1 >= xy2 || xy1 < 0)
451 return FALSE;
452
453 dst->y1 = xy1;
454 dst->y2 = xy2;
455 return TRUE;
456 }
457
458 static void
459 dri1_swap_copy(struct dri_context *ctx,
460 struct pipe_surface *dst,
461 struct pipe_surface *src,
462 __DRIdrawablePrivate * dPriv, const struct drm_clip_rect *bbox)
463 {
464 struct pipe_context *pipe = ctx->pipe;
465 struct drm_clip_rect clip;
466 struct drm_clip_rect *cur;
467 int i;
468
469 cur = dPriv->pClipRects;
470
471 for (i = 0; i < dPriv->numClipRects; ++i) {
472 if (dri1_intersect_src_bbox(&clip, dPriv->x, dPriv->y, cur++, bbox))
473 pipe->surface_copy(pipe, dst, clip.x1, clip.y1,
474 src,
475 (int)clip.x1 - dPriv->x,
476 (int)clip.y1 - dPriv->y,
477 clip.x2 - clip.x1, clip.y2 - clip.y1);
478 }
479 }
480
481 static void
482 dri1_copy_to_front(struct dri_context *ctx,
483 struct pipe_surface *surf,
484 __DRIdrawablePrivate * dPriv,
485 const struct drm_clip_rect *sub_box,
486 struct pipe_fence_handle **fence)
487 {
488 struct pipe_context *pipe = ctx->pipe;
489 boolean save_lost_lock;
490 uint cur_w;
491 uint cur_h;
492 struct drm_clip_rect bbox;
493 boolean visible = TRUE;
494
495 *fence = NULL;
496
497 dri_lock(ctx);
498 save_lost_lock = ctx->stLostLock;
499 dri1_update_drawables_locked(ctx, dPriv, dPriv);
500 st_get_framebuffer_dimensions(dri_drawable(dPriv)->stfb, &cur_w, &cur_h);
501
502 bbox.x1 = 0;
503 bbox.x2 = cur_w;
504 bbox.y1 = 0;
505 bbox.y2 = cur_h;
506
507 if (sub_box)
508 visible = dri1_intersect_src_bbox(&bbox, 0, 0, &bbox, sub_box);
509
510 if (visible && __dri1_api_hooks->present_locked) {
511
512 __dri1_api_hooks->present_locked(pipe,
513 surf,
514 dPriv->pClipRects,
515 dPriv->numClipRects,
516 dPriv->x, dPriv->y, &bbox, fence);
517
518 } else if (visible && __dri1_api_hooks->front_srf_locked) {
519
520 struct pipe_surface *front = __dri1_api_hooks->front_srf_locked(pipe);
521
522 if (front)
523 dri1_swap_copy(ctx, front, surf, dPriv, &bbox);
524
525 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, fence);
526 }
527
528 ctx->stLostLock = save_lost_lock;
529
530 /**
531 * FIXME: Revisit this: Update drawables on copy_sub_buffer ?
532 */
533
534 if (!sub_box)
535 dri1_update_drawables_locked(ctx, ctx->dPriv, ctx->rPriv);
536
537 dri_unlock(ctx);
538 dri1_propagate_drawable_change(ctx);
539 }
540
541 void
542 dri1_flush_frontbuffer(struct pipe_screen *screen,
543 struct pipe_surface *surf, void *context_private)
544 {
545 struct dri_context *ctx = (struct dri_context *)context_private;
546 struct pipe_fence_handle *dummy_fence;
547
548 dri1_copy_to_front(ctx, surf, ctx->dPriv, NULL, &dummy_fence);
549 screen->fence_reference(screen, &dummy_fence, NULL);
550
551 /**
552 * FIXME: Do we need swap throttling here?
553 */
554 }
555
556 void
557 dri_swap_buffers(__DRIdrawablePrivate * dPriv)
558 {
559 struct dri_context *ctx;
560 struct pipe_surface *back_surf;
561 struct dri_drawable *draw = dri_drawable(dPriv);
562 struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen;
563 struct pipe_fence_handle *fence;
564 struct st_context *st = st_get_current();
565
566 assert(__dri1_api_hooks != NULL);
567
568 if (!st)
569 return; /* For now */
570
571 ctx = (struct dri_context *)st->pipe->priv;
572
573 st_get_framebuffer_surface(draw->stfb, ST_SURFACE_BACK_LEFT, &back_surf);
574 if (back_surf) {
575 st_notify_swapbuffers(draw->stfb);
576 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
577 fence = dri_swap_fences_pop_front(draw);
578 if (fence) {
579 (void)screen->fence_finish(screen, fence, 0);
580 screen->fence_reference(screen, &fence, NULL);
581 }
582 dri1_copy_to_front(ctx, back_surf, dPriv, NULL, &fence);
583 dri_swap_fences_push_back(draw, fence);
584 screen->fence_reference(screen, &fence, NULL);
585 }
586 }
587
588 void
589 dri_copy_sub_buffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h)
590 {
591 struct pipe_screen *screen = dri_screen(dPriv->driScreenPriv)->pipe_screen;
592 struct drm_clip_rect sub_bbox;
593 struct dri_context *ctx;
594 struct pipe_surface *back_surf;
595 struct dri_drawable *draw = dri_drawable(dPriv);
596 struct pipe_fence_handle *dummy_fence;
597 struct st_context *st = st_get_current();
598
599 assert(__dri1_api_hooks != NULL);
600
601 if (!st)
602 return;
603
604 ctx = (struct dri_context *)st->pipe->priv;
605
606 sub_bbox.x1 = x;
607 sub_bbox.x2 = x + w;
608 sub_bbox.y1 = y;
609 sub_bbox.y2 = y + h;
610
611 st_get_framebuffer_surface(draw->stfb, ST_SURFACE_BACK_LEFT, &back_surf);
612 if (back_surf) {
613 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
614 dri1_copy_to_front(ctx, back_surf, dPriv, &sub_bbox, &dummy_fence);
615 screen->fence_reference(screen, &dummy_fence, NULL);
616 }
617 }
618
619 /* vim: set sw=3 ts=8 sts=3 expandtab: */