Merge remote branch 'origin/7.8'
[mesa.git] / src / gallium / state_trackers / dri / drm / 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 "dri1_helper.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 void
69 dri1_update_drawables_locked(struct dri_context *ctx,
70 __DRIdrawable * driDrawPriv,
71 __DRIdrawable * driReadPriv)
72 {
73 if (ctx->stLostLock) {
74 ctx->stLostLock = FALSE;
75 if (driDrawPriv == driReadPriv)
76 DRI_VALIDATE_DRAWABLE_INFO(ctx->sPriv, driDrawPriv);
77 else
78 DRI_VALIDATE_TWO_DRAWABLES_INFO(ctx->sPriv, driDrawPriv,
79 driReadPriv);
80 }
81 }
82
83 /**
84 * This ensures all contexts which bind to a drawable pick up the
85 * drawable change and signal new buffer state.
86 */
87 static void
88 dri1_propagate_drawable_change(struct dri_context *ctx)
89 {
90 __DRIdrawable *dPriv = ctx->dPriv;
91 __DRIdrawable *rPriv = ctx->rPriv;
92 struct dri_drawable *draw;
93 struct dri_drawable *read;
94 boolean flushed = FALSE;
95
96 if (dPriv) {
97 draw = dri_drawable(dPriv);
98 }
99
100 if (rPriv) {
101 read = dri_drawable(rPriv);
102 }
103
104 if (dPriv && draw->texture_stamp != dPriv->lastStamp) {
105 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
106 flushed = TRUE;
107 ctx->st->notify_invalid_framebuffer(ctx->st, draw->stfb);
108 }
109
110 if (rPriv && dPriv != rPriv && read->texture_stamp != rPriv->lastStamp) {
111 if (!flushed)
112 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
113 ctx->st->notify_invalid_framebuffer(ctx->st, read->stfb);
114 }
115 }
116
117 static INLINE boolean
118 dri1_intersect_src_bbox(struct drm_clip_rect *dst,
119 int dst_x,
120 int dst_y,
121 const struct drm_clip_rect *src,
122 const struct drm_clip_rect *bbox)
123 {
124 int xy1;
125 int xy2;
126
127 xy1 = ((int)src->x1 > (int)bbox->x1 + dst_x) ? src->x1 :
128 (int)bbox->x1 + dst_x;
129 xy2 = ((int)src->x2 < (int)bbox->x2 + dst_x) ? src->x2 :
130 (int)bbox->x2 + dst_x;
131 if (xy1 >= xy2 || xy1 < 0)
132 return FALSE;
133
134 dst->x1 = xy1;
135 dst->x2 = xy2;
136
137 xy1 = ((int)src->y1 > (int)bbox->y1 + dst_y) ? src->y1 :
138 (int)bbox->y1 + dst_y;
139 xy2 = ((int)src->y2 < (int)bbox->y2 + dst_y) ? src->y2 :
140 (int)bbox->y2 + dst_y;
141 if (xy1 >= xy2 || xy1 < 0)
142 return FALSE;
143
144 dst->y1 = xy1;
145 dst->y2 = xy2;
146 return TRUE;
147 }
148
149 static void
150 dri1_swap_copy(struct pipe_context *pipe,
151 struct pipe_surface *dst,
152 struct pipe_surface *src,
153 __DRIdrawable * dPriv, const struct drm_clip_rect *bbox)
154 {
155 struct drm_clip_rect clip;
156 struct drm_clip_rect *cur;
157 int i;
158
159 cur = dPriv->pClipRects;
160
161 for (i = 0; i < dPriv->numClipRects; ++i) {
162 if (dri1_intersect_src_bbox(&clip, dPriv->x, dPriv->y, cur++, bbox)) {
163 if (pipe->surface_copy) {
164 pipe->surface_copy(pipe, dst, clip.x1, clip.y1,
165 src,
166 (int)clip.x1 - dPriv->x,
167 (int)clip.y1 - dPriv->y,
168 clip.x2 - clip.x1, clip.y2 - clip.y1);
169 } else {
170 util_surface_copy(pipe, FALSE, dst, clip.x1, clip.y1,
171 src,
172 (int)clip.x1 - dPriv->x,
173 (int)clip.y1 - dPriv->y,
174 clip.x2 - clip.x1, clip.y2 - clip.y1);
175 }
176 }
177 }
178 }
179
180 static void
181 dri1_present_texture_locked(__DRIdrawable * dPriv,
182 struct pipe_resource *ptex,
183 const struct drm_clip_rect *sub_box,
184 struct pipe_fence_handle **fence)
185 {
186 struct dri_drawable *drawable = dri_drawable(dPriv);
187 struct dri_screen *screen = dri_screen(drawable->sPriv);
188 struct pipe_context *pipe;
189 struct pipe_surface *psurf;
190 struct drm_clip_rect bbox;
191 boolean visible = TRUE;
192
193 *fence = NULL;
194
195 bbox.x1 = 0;
196 bbox.x2 = ptex->width0;
197 bbox.y1 = 0;
198 bbox.y2 = ptex->height0;
199
200 if (sub_box)
201 visible = dri1_intersect_src_bbox(&bbox, 0, 0, &bbox, sub_box);
202 if (!visible)
203 return;
204
205 pipe = dri1_get_pipe_context(screen);
206 psurf = dri1_get_pipe_surface(drawable, ptex);
207 if (!pipe || !psurf)
208 return;
209
210 if (__dri1_api_hooks->present_locked) {
211 __dri1_api_hooks->present_locked(pipe, psurf,
212 dPriv->pClipRects, dPriv->numClipRects,
213 dPriv->x, dPriv->y, &bbox, fence);
214 } else if (__dri1_api_hooks->front_srf_locked) {
215 struct pipe_surface *front = __dri1_api_hooks->front_srf_locked(pipe);
216
217 if (front)
218 dri1_swap_copy(pipe, front, psurf, dPriv, &bbox);
219
220 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, fence);
221 }
222 }
223
224 static void
225 dri1_copy_to_front(struct dri_context *ctx,
226 struct pipe_resource *ptex,
227 __DRIdrawable * dPriv,
228 const struct drm_clip_rect *sub_box,
229 struct pipe_fence_handle **fence)
230 {
231 boolean save_lost_lock;
232
233 dri1_lock(ctx);
234 save_lost_lock = ctx->stLostLock;
235 dri1_update_drawables_locked(ctx, dPriv, dPriv);
236
237 dri1_present_texture_locked(dPriv, ptex, sub_box, fence);
238
239 ctx->stLostLock = save_lost_lock;
240
241 /**
242 * FIXME: Revisit this: Update drawables on copy_sub_buffer ?
243 */
244
245 if (!sub_box)
246 dri1_update_drawables_locked(ctx, ctx->dPriv, ctx->rPriv);
247
248 dri1_unlock(ctx);
249 dri1_propagate_drawable_change(ctx);
250 }
251
252 /*
253 * Backend functions for st_framebuffer interface and swap_buffers.
254 */
255
256 void
257 dri1_flush_frontbuffer(struct dri_drawable *draw,
258 enum st_attachment_type statt)
259 {
260 struct dri_context *ctx = dri_get_current();
261 struct dri_screen *screen = dri_screen(draw->sPriv);
262 struct pipe_screen *pipe_screen = screen->pipe_screen;
263 struct pipe_fence_handle *dummy_fence;
264 struct pipe_resource *ptex;
265
266 if (!ctx)
267 return; /* For now */
268
269 ptex = draw->textures[statt];
270 if (ptex) {
271 dri1_copy_to_front(ctx, ptex, ctx->dPriv, NULL, &dummy_fence);
272 pipe_screen->fence_reference(pipe_screen, &dummy_fence, NULL);
273 }
274
275 /**
276 * FIXME: Do we need swap throttling here?
277 */
278 }
279
280 void
281 dri1_swap_buffers(__DRIdrawable * dPriv)
282 {
283 struct dri_context *ctx = dri_get_current();
284 struct dri_drawable *draw = dri_drawable(dPriv);
285 struct dri_screen *screen = dri_screen(draw->sPriv);
286 struct pipe_screen *pipe_screen = screen->pipe_screen;
287 struct pipe_fence_handle *fence;
288 struct pipe_resource *ptex;
289
290 assert(__dri1_api_hooks != NULL);
291
292 if (!ctx)
293 return; /* For now */
294
295 ptex = draw->textures[ST_ATTACHMENT_BACK_LEFT];
296 if (ptex) {
297 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
298 fence = dri1_swap_fences_pop_front(draw);
299 if (fence) {
300 (void)pipe_screen->fence_finish(pipe_screen, fence, 0);
301 pipe_screen->fence_reference(pipe_screen, &fence, NULL);
302 }
303 dri1_copy_to_front(ctx, ptex, dPriv, NULL, &fence);
304 dri1_swap_fences_push_back(draw, fence);
305 pipe_screen->fence_reference(pipe_screen, &fence, NULL);
306 }
307 }
308
309 void
310 dri1_copy_sub_buffer(__DRIdrawable * dPriv, int x, int y, int w, int h)
311 {
312 struct dri_context *ctx = dri_get_current();
313 struct dri_screen *screen = dri_screen(dPriv->driScreenPriv);
314 struct pipe_screen *pipe_screen = screen->pipe_screen;
315 struct drm_clip_rect sub_bbox;
316 struct dri_drawable *draw = dri_drawable(dPriv);
317 struct pipe_fence_handle *dummy_fence;
318 struct pipe_resource *ptex;
319
320 assert(__dri1_api_hooks != NULL);
321
322 if (!ctx)
323 return;
324
325 sub_bbox.x1 = x;
326 sub_bbox.x2 = x + w;
327 sub_bbox.y1 = y;
328 sub_bbox.y2 = y + h;
329
330 ptex = draw->textures[ST_ATTACHMENT_BACK_LEFT];
331 if (ptex) {
332 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
333 dri1_copy_to_front(ctx, ptex, dPriv, &sub_bbox, &dummy_fence);
334 pipe_screen->fence_reference(pipe_screen, &dummy_fence, NULL);
335 }
336 }
337
338 /**
339 * Allocate framebuffer attachments.
340 *
341 * During fixed-size operation, the function keeps allocating new attachments
342 * as they are requested. Unused attachments are not removed, not until the
343 * framebuffer is resized or destroyed.
344 */
345 void
346 dri1_allocate_textures(struct dri_drawable *drawable,
347 unsigned mask)
348 {
349 struct dri_screen *screen = dri_screen(drawable->sPriv);
350 struct pipe_resource templ;
351 unsigned width, height;
352 boolean resized;
353 int i;
354
355 width = drawable->dPriv->w;
356 height = drawable->dPriv->h;
357
358 resized = (drawable->old_w != width ||
359 drawable->old_h != height);
360
361 /* remove outdated textures */
362 if (resized) {
363 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
364 pipe_resource_reference(&drawable->textures[i], NULL);
365 }
366
367 memset(&templ, 0, sizeof(templ));
368 templ.target = PIPE_TEXTURE_2D;
369 templ.width0 = width;
370 templ.height0 = height;
371 templ.depth0 = 1;
372 templ.last_level = 0;
373
374 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
375 enum pipe_format format;
376 unsigned tex_usage;
377
378 /* the texture already exists or not requested */
379 if (drawable->textures[i] || !(mask & (1 << i))) {
380 continue;
381 }
382
383 switch (i) {
384 case ST_ATTACHMENT_FRONT_LEFT:
385 case ST_ATTACHMENT_BACK_LEFT:
386 case ST_ATTACHMENT_FRONT_RIGHT:
387 case ST_ATTACHMENT_BACK_RIGHT:
388 format = drawable->stvis.color_format;
389 tex_usage = PIPE_BIND_DISPLAY_TARGET |
390 PIPE_BIND_RENDER_TARGET;
391 break;
392 case ST_ATTACHMENT_DEPTH_STENCIL:
393 format = drawable->stvis.depth_stencil_format;
394 tex_usage = PIPE_BIND_DEPTH_STENCIL;
395 break;
396 default:
397 format = PIPE_FORMAT_NONE;
398 break;
399 }
400
401 if (format != PIPE_FORMAT_NONE) {
402 templ.format = format;
403 templ.bind = tex_usage;
404
405 drawable->textures[i] =
406 screen->pipe_screen->resource_create(screen->pipe_screen, &templ);
407 }
408 }
409
410 drawable->old_w = width;
411 drawable->old_h = height;
412 }
413
414 /*
415 * Backend function for init_screen.
416 */
417
418 static const __DRIextension *dri1_screen_extensions[] = {
419 &driReadDrawableExtension,
420 &driCopySubBufferExtension.base,
421 &driSwapControlExtension.base,
422 &driFrameTrackingExtension.base,
423 &driMediaStreamCounterExtension.base,
424 NULL
425 };
426
427 static void
428 st_dri_lock(struct pipe_context *pipe)
429 {
430 dri1_lock((struct dri_context *)pipe->priv);
431 }
432
433 static void
434 st_dri_unlock(struct pipe_context *pipe)
435 {
436 dri1_unlock((struct dri_context *)pipe->priv);
437 }
438
439 static boolean
440 st_dri_is_locked(struct pipe_context *pipe)
441 {
442 return ((struct dri_context *)pipe->priv)->isLocked;
443 }
444
445 static boolean
446 st_dri_lost_lock(struct pipe_context *pipe)
447 {
448 return ((struct dri_context *)pipe->priv)->wsLostLock;
449 }
450
451 static void
452 st_dri_clear_lost_lock(struct pipe_context *pipe)
453 {
454 ((struct dri_context *)pipe->priv)->wsLostLock = FALSE;
455 }
456
457 static struct dri1_api_lock_funcs dri1_lf = {
458 .lock = st_dri_lock,
459 .unlock = st_dri_unlock,
460 .is_locked = st_dri_is_locked,
461 .is_lock_lost = st_dri_lost_lock,
462 .clear_lost_lock = st_dri_clear_lost_lock
463 };
464
465 static INLINE void
466 dri1_copy_version(struct dri1_api_version *dst,
467 const struct __DRIversionRec *src)
468 {
469 dst->major = src->major;
470 dst->minor = src->minor;
471 dst->patch_level = src->patch;
472 }
473
474 struct dri1_api *__dri1_api_hooks = NULL;
475
476 const __DRIconfig **
477 dri1_init_screen(__DRIscreen * sPriv)
478 {
479 const __DRIconfig **configs;
480 struct pipe_screen *pscreen;
481 struct dri_screen *screen;
482 struct dri1_create_screen_arg arg;
483
484 screen = CALLOC_STRUCT(dri_screen);
485 if (!screen)
486 return NULL;
487
488 screen->api = drm_api_create();
489 screen->sPriv = sPriv;
490 screen->fd = sPriv->fd;
491 screen->drmLock = (drmLock *) & sPriv->pSAREA->lock;
492
493 sPriv->private = (void *)screen;
494 sPriv->extensions = dri1_screen_extensions;
495
496 arg.base.mode = DRM_CREATE_DRI1;
497 arg.lf = &dri1_lf;
498 arg.ddx_info = sPriv->pDevPriv;
499 arg.ddx_info_size = sPriv->devPrivSize;
500 arg.sarea = sPriv->pSAREA;
501 dri1_copy_version(&arg.ddx_version, &sPriv->ddx_version);
502 dri1_copy_version(&arg.dri_version, &sPriv->dri_version);
503 dri1_copy_version(&arg.drm_version, &sPriv->drm_version);
504 arg.api = NULL;
505
506 /**
507 * FIXME: If the driver supports format conversion swapbuffer blits, we might
508 * want to support other color bit depths than the server is currently
509 * using.
510 */
511
512 pscreen = screen->api->create_screen(screen->api, screen->fd, &arg.base);
513 /* dri_init_screen_helper checks pscreen for us */
514
515 configs = dri_init_screen_helper(screen, pscreen, sPriv->fbBPP);
516 if (!configs)
517 goto fail;
518
519 if (!arg.api) {
520 debug_printf("%s: failed to create dri1 screen\n", __FUNCTION__);
521 goto fail;
522 }
523
524 __dri1_api_hooks = arg.api;
525
526 return configs;
527 fail:
528 if (configs)
529 FREE(configs);
530 dri_destroy_screen_helper(screen);
531 FREE(screen);
532 return NULL;
533 }