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