Merge branch '7.8'
[mesa.git] / src / gallium / state_trackers / dri / dri1.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 /* XXX DRI1 is untested after the switch to st_api.h */
33
34 #include "util/u_memory.h"
35 #include "util/u_rect.h"
36 #include "util/u_inlines.h"
37 #include "pipe/p_context.h"
38 #include "state_tracker/dri1_api.h"
39
40 #include "dri_screen.h"
41 #include "dri_context.h"
42 #include "dri_drawable.h"
43 #include "dri_st_api.h"
44 #include "dri1.h"
45
46 static INLINE void
47 dri1_lock(struct dri_context *ctx)
48 {
49 drm_context_t hw_context = ctx->cPriv->hHWContext;
50 char ret = 0;
51
52 DRM_CAS(ctx->lock, hw_context, DRM_LOCK_HELD | hw_context, ret);
53 if (ret) {
54 drmGetLock(ctx->sPriv->fd, hw_context, 0);
55 ctx->stLostLock = TRUE;
56 ctx->wsLostLock = TRUE;
57 }
58 ctx->isLocked = TRUE;
59 }
60
61 static INLINE void
62 dri1_unlock(struct dri_context *ctx)
63 {
64 ctx->isLocked = FALSE;
65 DRM_UNLOCK(ctx->sPriv->fd, ctx->lock, ctx->cPriv->hHWContext);
66 }
67
68 static struct pipe_fence_handle *
69 dri_swap_fences_pop_front(struct dri_drawable *draw)
70 {
71 struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen;
72 struct pipe_fence_handle *fence = NULL;
73
74 if (draw->cur_fences >= draw->desired_fences) {
75 screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]);
76 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL);
77 --draw->cur_fences;
78 draw->tail &= DRI_SWAP_FENCES_MASK;
79 }
80 return fence;
81 }
82
83 static void
84 dri_swap_fences_push_back(struct dri_drawable *draw,
85 struct pipe_fence_handle *fence)
86 {
87 struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen;
88
89 if (!fence)
90 return;
91
92 if (draw->cur_fences < DRI_SWAP_FENCES_MAX) {
93 draw->cur_fences++;
94 screen->fence_reference(screen, &draw->swap_fences[draw->head++],
95 fence);
96 draw->head &= DRI_SWAP_FENCES_MASK;
97 }
98 }
99
100 void
101 dri1_swap_fences_clear(struct dri_drawable *drawable)
102 {
103 struct pipe_screen *screen = dri_screen(drawable->sPriv)->pipe_screen;
104 struct pipe_fence_handle *fence;
105
106 while (drawable->cur_fences) {
107 fence = dri_swap_fences_pop_front(drawable);
108 screen->fence_reference(screen, &fence, NULL);
109 }
110 }
111
112 static void
113 dri1_update_drawables_locked(struct dri_context *ctx,
114 __DRIdrawable * driDrawPriv,
115 __DRIdrawable * driReadPriv)
116 {
117 if (ctx->stLostLock) {
118 ctx->stLostLock = FALSE;
119 if (driDrawPriv == driReadPriv)
120 DRI_VALIDATE_DRAWABLE_INFO(ctx->sPriv, driDrawPriv);
121 else
122 DRI_VALIDATE_TWO_DRAWABLES_INFO(ctx->sPriv, driDrawPriv,
123 driReadPriv);
124 }
125 }
126
127 /**
128 * This ensures all contexts which bind to a drawable pick up the
129 * drawable change and signal new buffer state.
130 */
131 static void
132 dri1_propagate_drawable_change(struct dri_context *ctx)
133 {
134 __DRIdrawable *dPriv = ctx->dPriv;
135 __DRIdrawable *rPriv = ctx->rPriv;
136 struct dri_drawable *draw = dri_drawable(dPriv);
137 struct dri_drawable *read = dri_drawable(rPriv);
138 boolean flushed = FALSE;
139
140 if (dPriv && draw->texture_stamp != dPriv->lastStamp) {
141 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
142 flushed = TRUE;
143 ctx->st->notify_invalid_framebuffer(ctx->st, draw->stfb);
144 }
145
146 if (rPriv && dPriv != rPriv && read->texture_stamp != rPriv->lastStamp) {
147 if (!flushed)
148 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
149 ctx->st->notify_invalid_framebuffer(ctx->st, read->stfb);
150 }
151 }
152
153 static INLINE boolean
154 dri1_intersect_src_bbox(struct drm_clip_rect *dst,
155 int dst_x,
156 int dst_y,
157 const struct drm_clip_rect *src,
158 const struct drm_clip_rect *bbox)
159 {
160 int xy1;
161 int xy2;
162
163 xy1 = ((int)src->x1 > (int)bbox->x1 + dst_x) ? src->x1 :
164 (int)bbox->x1 + dst_x;
165 xy2 = ((int)src->x2 < (int)bbox->x2 + dst_x) ? src->x2 :
166 (int)bbox->x2 + dst_x;
167 if (xy1 >= xy2 || xy1 < 0)
168 return FALSE;
169
170 dst->x1 = xy1;
171 dst->x2 = xy2;
172
173 xy1 = ((int)src->y1 > (int)bbox->y1 + dst_y) ? src->y1 :
174 (int)bbox->y1 + dst_y;
175 xy2 = ((int)src->y2 < (int)bbox->y2 + dst_y) ? src->y2 :
176 (int)bbox->y2 + dst_y;
177 if (xy1 >= xy2 || xy1 < 0)
178 return FALSE;
179
180 dst->y1 = xy1;
181 dst->y2 = xy2;
182 return TRUE;
183 }
184
185 static void
186 dri1_swap_copy(struct pipe_context *pipe,
187 struct pipe_surface *dst,
188 struct pipe_surface *src,
189 __DRIdrawable * dPriv, const struct drm_clip_rect *bbox)
190 {
191 struct drm_clip_rect clip;
192 struct drm_clip_rect *cur;
193 int i;
194
195 cur = dPriv->pClipRects;
196
197 for (i = 0; i < dPriv->numClipRects; ++i) {
198 if (dri1_intersect_src_bbox(&clip, dPriv->x, dPriv->y, cur++, bbox)) {
199 if (pipe->surface_copy) {
200 pipe->surface_copy(pipe, dst, clip.x1, clip.y1,
201 src,
202 (int)clip.x1 - dPriv->x,
203 (int)clip.y1 - dPriv->y,
204 clip.x2 - clip.x1, clip.y2 - clip.y1);
205 } else {
206 util_surface_copy(pipe, FALSE, dst, clip.x1, clip.y1,
207 src,
208 (int)clip.x1 - dPriv->x,
209 (int)clip.y1 - dPriv->y,
210 clip.x2 - clip.x1, clip.y2 - clip.y1);
211 }
212 }
213 }
214 }
215
216 static struct pipe_surface *
217 dri1_get_pipe_surface(struct dri_drawable *drawable, struct pipe_texture *ptex)
218 {
219 struct pipe_screen *pipe_screen = dri_screen(drawable->sPriv)->pipe_screen;
220 struct pipe_surface *psurf = drawable->dri1_surface;
221
222 if (!psurf || psurf->texture != ptex) {
223 pipe_surface_reference(&drawable->dri1_surface, NULL);
224
225 drawable->dri1_surface = pipe_screen->get_tex_surface(pipe_screen,
226 ptex, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ);
227
228 psurf = drawable->dri1_surface;
229 }
230
231 return psurf;
232 }
233
234 static struct pipe_context *
235 dri1_get_pipe_context(struct dri_drawable *drawable)
236 {
237 struct dri_screen *screen = dri_screen(drawable->sPriv);
238 struct pipe_context *pipe = screen->dri1_pipe;
239
240 if (!pipe) {
241 screen->dri1_pipe =
242 screen->pipe_screen->context_create(screen->pipe_screen, NULL);
243 pipe = screen->dri1_pipe;
244 }
245
246 return pipe;
247 }
248
249 static void
250 dri1_present_texture_locked(__DRIdrawable * dPriv,
251 struct pipe_texture *ptex,
252 const struct drm_clip_rect *sub_box,
253 struct pipe_fence_handle **fence)
254 {
255 struct dri_drawable *drawable = dri_drawable(dPriv);
256 struct pipe_context *pipe;
257 struct pipe_surface *psurf;
258 struct drm_clip_rect bbox;
259 boolean visible = TRUE;
260
261 *fence = NULL;
262
263 bbox.x1 = 0;
264 bbox.x2 = ptex->width0;
265 bbox.y1 = 0;
266 bbox.y2 = ptex->height0;
267
268 if (sub_box)
269 visible = dri1_intersect_src_bbox(&bbox, 0, 0, &bbox, sub_box);
270 if (!visible)
271 return;
272
273 pipe = dri1_get_pipe_context(drawable);
274 psurf = dri1_get_pipe_surface(drawable, ptex);
275 if (!pipe || !psurf)
276 return;
277
278 if (__dri1_api_hooks->present_locked) {
279 __dri1_api_hooks->present_locked(pipe, psurf,
280 dPriv->pClipRects, dPriv->numClipRects,
281 dPriv->x, dPriv->y, &bbox, fence);
282 } else if (__dri1_api_hooks->front_srf_locked) {
283 struct pipe_surface *front = __dri1_api_hooks->front_srf_locked(pipe);
284
285 if (front)
286 dri1_swap_copy(pipe, front, psurf, dPriv, &bbox);
287
288 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, fence);
289 }
290 }
291
292 static void
293 dri1_copy_to_front(struct dri_context *ctx,
294 struct pipe_texture *ptex,
295 __DRIdrawable * dPriv,
296 const struct drm_clip_rect *sub_box,
297 struct pipe_fence_handle **fence)
298 {
299 boolean save_lost_lock;
300
301 dri1_lock(ctx);
302 save_lost_lock = ctx->stLostLock;
303 dri1_update_drawables_locked(ctx, dPriv, dPriv);
304
305 dri1_present_texture_locked(dPriv, ptex, sub_box, fence);
306
307 ctx->stLostLock = save_lost_lock;
308
309 /**
310 * FIXME: Revisit this: Update drawables on copy_sub_buffer ?
311 */
312
313 if (!sub_box)
314 dri1_update_drawables_locked(ctx, ctx->dPriv, ctx->rPriv);
315
316 dri1_unlock(ctx);
317 dri1_propagate_drawable_change(ctx);
318 }
319
320 void
321 dri1_flush_frontbuffer(struct dri_drawable *drawable,
322 struct pipe_texture *ptex)
323 {
324 struct st_api *stapi = dri_get_st_api();
325 struct dri_screen *screen = dri_screen(drawable->sPriv);
326 struct pipe_screen *pipe_screen = screen->pipe_screen;
327 struct dri_context *ctx;
328 struct pipe_fence_handle *dummy_fence;
329 struct st_context_iface *st = stapi->get_current(stapi);
330
331 if (!st)
332 return;
333
334 ctx = (struct dri_context *) st->st_manager_private;
335
336 dri1_copy_to_front(ctx, ptex, ctx->dPriv, NULL, &dummy_fence);
337 pipe_screen->fence_reference(pipe_screen, &dummy_fence, NULL);
338
339 /**
340 * FIXME: Do we need swap throttling here?
341 */
342 }
343
344 void
345 dri1_swap_buffers(__DRIdrawable * dPriv)
346 {
347 struct dri_context *ctx = dri_get_current();
348 struct dri_drawable *draw = dri_drawable(dPriv);
349 struct dri_screen *screen = dri_screen(draw->sPriv);
350 struct pipe_screen *pipe_screen = screen->pipe_screen;
351 struct pipe_fence_handle *fence;
352 struct pipe_texture *ptex;
353
354 assert(__dri1_api_hooks != NULL);
355
356 if (!ctx)
357 return; /* For now */
358
359 ptex = draw->textures[ST_ATTACHMENT_BACK_LEFT];
360 if (ptex) {
361 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
362 fence = dri_swap_fences_pop_front(draw);
363 if (fence) {
364 (void)pipe_screen->fence_finish(pipe_screen, fence, 0);
365 pipe_screen->fence_reference(pipe_screen, &fence, NULL);
366 }
367 dri1_copy_to_front(ctx, ptex, dPriv, NULL, &fence);
368 dri_swap_fences_push_back(draw, fence);
369 pipe_screen->fence_reference(pipe_screen, &fence, NULL);
370 }
371 }
372
373 void
374 dri1_copy_sub_buffer(__DRIdrawable * dPriv, int x, int y, int w, int h)
375 {
376 struct dri_context *ctx = dri_get_current();
377 struct dri_screen *screen = dri_screen(dPriv->driScreenPriv);
378 struct pipe_screen *pipe_screen = screen->pipe_screen;
379 struct drm_clip_rect sub_bbox;
380 struct dri_drawable *draw = dri_drawable(dPriv);
381 struct pipe_fence_handle *dummy_fence;
382 struct pipe_texture *ptex;
383
384 assert(__dri1_api_hooks != NULL);
385
386 if (!ctx)
387 return;
388
389 sub_bbox.x1 = x;
390 sub_bbox.x2 = x + w;
391 sub_bbox.y1 = y;
392 sub_bbox.y2 = y + h;
393
394 ptex = draw->textures[ST_ATTACHMENT_BACK_LEFT];
395 if (ptex) {
396 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
397 dri1_copy_to_front(ctx, ptex, dPriv, &sub_bbox, &dummy_fence);
398 pipe_screen->fence_reference(pipe_screen, &dummy_fence, NULL);
399 }
400 }
401
402 void
403 dri1_allocate_textures(struct dri_drawable *drawable,
404 unsigned width, unsigned height,
405 unsigned mask)
406 {
407 struct dri_screen *screen = dri_screen(drawable->sPriv);
408 struct pipe_texture templ;
409 int i;
410
411 /* remove outdated textures */
412 if (drawable->old_w != width || drawable->old_h != height) {
413 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
414 pipe_texture_reference(&drawable->textures[i], NULL);
415 }
416
417 memset(&templ, 0, sizeof(templ));
418 templ.target = PIPE_TEXTURE_2D;
419 templ.width0 = width;
420 templ.height0 = height;
421 templ.depth0 = 1;
422 templ.last_level = 0;
423
424 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
425 enum pipe_format format;
426 unsigned tex_usage;
427
428 /* the texture already exists or not requested */
429 if (drawable->textures[i] || !(mask & (1 << i))) {
430 /* remember the texture */
431 if (drawable->textures[i])
432 mask |= (1 << i);
433 continue;
434 }
435
436 switch (i) {
437 case ST_ATTACHMENT_FRONT_LEFT:
438 case ST_ATTACHMENT_BACK_LEFT:
439 case ST_ATTACHMENT_FRONT_RIGHT:
440 case ST_ATTACHMENT_BACK_RIGHT:
441 format = drawable->stvis.color_format;
442 tex_usage = PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
443 PIPE_TEXTURE_USAGE_RENDER_TARGET;
444 break;
445 case ST_ATTACHMENT_DEPTH_STENCIL:
446 format = drawable->stvis.depth_stencil_format;
447 tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL;
448 break;
449 default:
450 format = PIPE_FORMAT_NONE;
451 break;
452 }
453
454 if (format != PIPE_FORMAT_NONE) {
455 templ.format = format;
456 templ.tex_usage = tex_usage;
457
458 drawable->textures[i] =
459 screen->pipe_screen->texture_create(screen->pipe_screen, &templ);
460 }
461 }
462
463 drawable->old_w = width;
464 drawable->old_h = height;
465 drawable->texture_mask = mask;
466 }
467
468 static void
469 st_dri_lock(struct pipe_context *pipe)
470 {
471 dri1_lock((struct dri_context *)pipe->priv);
472 }
473
474 static void
475 st_dri_unlock(struct pipe_context *pipe)
476 {
477 dri1_unlock((struct dri_context *)pipe->priv);
478 }
479
480 static boolean
481 st_dri_is_locked(struct pipe_context *pipe)
482 {
483 return ((struct dri_context *)pipe->priv)->isLocked;
484 }
485
486 static boolean
487 st_dri_lost_lock(struct pipe_context *pipe)
488 {
489 return ((struct dri_context *)pipe->priv)->wsLostLock;
490 }
491
492 static void
493 st_dri_clear_lost_lock(struct pipe_context *pipe)
494 {
495 ((struct dri_context *)pipe->priv)->wsLostLock = FALSE;
496 }
497
498 static struct dri1_api_lock_funcs dri1_lf = {
499 .lock = st_dri_lock,
500 .unlock = st_dri_unlock,
501 .is_locked = st_dri_is_locked,
502 .is_lock_lost = st_dri_lost_lock,
503 .clear_lost_lock = st_dri_clear_lost_lock
504 };
505
506 static const __DRIextension *dri1_screen_extensions[] = {
507 &driReadDrawableExtension,
508 &driCopySubBufferExtension.base,
509 &driSwapControlExtension.base,
510 &driFrameTrackingExtension.base,
511 &driMediaStreamCounterExtension.base,
512 NULL
513 };
514
515 struct dri1_api *__dri1_api_hooks = NULL;
516
517 static INLINE void
518 dri1_copy_version(struct dri1_api_version *dst,
519 const struct __DRIversionRec *src)
520 {
521 dst->major = src->major;
522 dst->minor = src->minor;
523 dst->patch_level = src->patch;
524 }
525
526 const __DRIconfig **
527 dri1_init_screen(__DRIscreen * sPriv)
528 {
529 struct dri_screen *screen;
530 const __DRIconfig **configs;
531 struct dri1_create_screen_arg arg;
532
533 screen = CALLOC_STRUCT(dri_screen);
534 if (!screen)
535 return NULL;
536
537 screen->api = drm_api_create();
538 screen->sPriv = sPriv;
539 screen->fd = sPriv->fd;
540 screen->drmLock = (drmLock *) & sPriv->pSAREA->lock;
541
542 sPriv->private = (void *)screen;
543 sPriv->extensions = dri1_screen_extensions;
544
545 arg.base.mode = DRM_CREATE_DRI1;
546 arg.lf = &dri1_lf;
547 arg.ddx_info = sPriv->pDevPriv;
548 arg.ddx_info_size = sPriv->devPrivSize;
549 arg.sarea = sPriv->pSAREA;
550 dri1_copy_version(&arg.ddx_version, &sPriv->ddx_version);
551 dri1_copy_version(&arg.dri_version, &sPriv->dri_version);
552 dri1_copy_version(&arg.drm_version, &sPriv->drm_version);
553 arg.api = NULL;
554
555 screen->pipe_screen = screen->api->create_screen(screen->api, screen->fd, &arg.base);
556
557 if (!screen->pipe_screen || !arg.api) {
558 debug_printf("%s: failed to create dri1 screen\n", __FUNCTION__);
559 goto out_no_screen;
560 }
561
562 __dri1_api_hooks = arg.api;
563
564 driParseOptionInfo(&screen->optionCache,
565 __driConfigOptions, __driNConfigOptions);
566
567 /**
568 * FIXME: If the driver supports format conversion swapbuffer blits, we might
569 * want to support other color bit depths than the server is currently
570 * using.
571 */
572
573 configs = dri_fill_in_modes(screen, sPriv->fbBPP);
574 if (!configs)
575 goto out_no_configs;
576
577 return configs;
578 out_no_configs:
579 screen->pipe_screen->destroy(screen->pipe_screen);
580 out_no_screen:
581 FREE(screen);
582 return NULL;
583 }