1 /**************************************************************************
3 * Copyright 2009, VMware, Inc.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
28 * Author: Keith Whitwell <keithw@vmware.com>
29 * Author: Jakob Bornecrantz <wallbraker@gmail.com>
32 /* XXX DRI1 is untested after the switch to st_api.h */
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"
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"
48 dri1_lock(struct dri_context *ctx)
50 drm_context_t hw_context = ctx->cPriv->hHWContext;
53 DRM_CAS(ctx->lock, hw_context, DRM_LOCK_HELD | hw_context, ret);
55 drmGetLock(ctx->sPriv->fd, hw_context, 0);
56 ctx->stLostLock = TRUE;
57 ctx->wsLostLock = TRUE;
63 dri1_unlock(struct dri_context *ctx)
65 ctx->isLocked = FALSE;
66 DRM_UNLOCK(ctx->sPriv->fd, ctx->lock, ctx->cPriv->hHWContext);
70 dri1_update_drawables_locked(struct dri_context *ctx,
71 __DRIdrawable * driDrawPriv,
72 __DRIdrawable * driReadPriv)
74 if (ctx->stLostLock) {
75 ctx->stLostLock = FALSE;
76 if (driDrawPriv == driReadPriv)
77 DRI_VALIDATE_DRAWABLE_INFO(ctx->sPriv, driDrawPriv);
79 DRI_VALIDATE_TWO_DRAWABLES_INFO(ctx->sPriv, driDrawPriv,
85 * This ensures all contexts which bind to a drawable pick up the
86 * drawable change and signal new buffer state.
89 dri1_propagate_drawable_change(struct dri_context *ctx)
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;
97 if (dPriv && draw->texture_stamp != dPriv->lastStamp) {
98 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
100 ctx->st->notify_invalid_framebuffer(ctx->st, draw->stfb);
103 if (rPriv && dPriv != rPriv && read->texture_stamp != rPriv->lastStamp) {
105 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
106 ctx->st->notify_invalid_framebuffer(ctx->st, read->stfb);
110 static INLINE boolean
111 dri1_intersect_src_bbox(struct drm_clip_rect *dst,
114 const struct drm_clip_rect *src,
115 const struct drm_clip_rect *bbox)
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)
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)
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)
148 struct drm_clip_rect clip;
149 struct drm_clip_rect *cur;
152 cur = dPriv->pClipRects;
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,
159 (int)clip.x1 - dPriv->x,
160 (int)clip.y1 - dPriv->y,
161 clip.x2 - clip.x1, clip.y2 - clip.y1);
163 util_surface_copy(pipe, FALSE, dst, clip.x1, clip.y1,
165 (int)clip.x1 - dPriv->x,
166 (int)clip.y1 - dPriv->y,
167 clip.x2 - clip.x1, clip.y2 - clip.y1);
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)
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;
189 bbox.x2 = ptex->width0;
191 bbox.y2 = ptex->height0;
194 visible = dri1_intersect_src_bbox(&bbox, 0, 0, &bbox, sub_box);
198 pipe = dri1_get_pipe_context(screen);
199 psurf = dri1_get_pipe_surface(drawable, ptex);
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);
211 dri1_swap_copy(pipe, front, psurf, dPriv, &bbox);
213 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, fence);
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)
224 boolean save_lost_lock;
227 save_lost_lock = ctx->stLostLock;
228 dri1_update_drawables_locked(ctx, dPriv, dPriv);
230 dri1_present_texture_locked(dPriv, ptex, sub_box, fence);
232 ctx->stLostLock = save_lost_lock;
235 * FIXME: Revisit this: Update drawables on copy_sub_buffer ?
239 dri1_update_drawables_locked(ctx, ctx->dPriv, ctx->rPriv);
242 dri1_propagate_drawable_change(ctx);
246 * Backend functions for st_framebuffer interface and swap_buffers.
250 dri1_flush_frontbuffer(struct dri_drawable *draw,
251 enum st_attachment_type statt)
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;
260 return; /* For now */
262 ptex = draw->textures[statt];
264 dri1_copy_to_front(ctx, ptex, ctx->dPriv, NULL, &dummy_fence);
265 pipe_screen->fence_reference(pipe_screen, &dummy_fence, NULL);
269 * FIXME: Do we need swap throttling here?
274 dri1_swap_buffers(__DRIdrawable * dPriv)
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;
283 assert(__dri1_api_hooks != NULL);
286 return; /* For now */
288 ptex = draw->textures[ST_ATTACHMENT_BACK_LEFT];
290 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
291 fence = dri1_swap_fences_pop_front(draw);
293 (void)pipe_screen->fence_finish(pipe_screen, fence, 0);
294 pipe_screen->fence_reference(pipe_screen, &fence, NULL);
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);
303 dri1_copy_sub_buffer(__DRIdrawable * dPriv, int x, int y, int w, int h)
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;
313 assert(__dri1_api_hooks != NULL);
323 ptex = draw->textures[ST_ATTACHMENT_BACK_LEFT];
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);
332 * Allocate framebuffer attachments.
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.
339 dri1_allocate_textures(struct dri_drawable *drawable,
342 struct dri_screen *screen = dri_screen(drawable->sPriv);
343 struct pipe_texture templ;
344 unsigned width, height;
348 width = drawable->dPriv->w;
349 height = drawable->dPriv->h;
351 resized = (drawable->old_w != width ||
352 drawable->old_h != height);
354 /* remove outdated textures */
356 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
357 pipe_texture_reference(&drawable->textures[i], NULL);
360 memset(&templ, 0, sizeof(templ));
361 templ.target = PIPE_TEXTURE_2D;
362 templ.width0 = width;
363 templ.height0 = height;
365 templ.last_level = 0;
367 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
368 enum pipe_format format;
371 /* the texture already exists or not requested */
372 if (drawable->textures[i] || !(mask & (1 << 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;
385 case ST_ATTACHMENT_DEPTH_STENCIL:
386 format = drawable->stvis.depth_stencil_format;
387 tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL;
390 format = PIPE_FORMAT_NONE;
394 if (format != PIPE_FORMAT_NONE) {
395 templ.format = format;
396 templ.tex_usage = tex_usage;
398 drawable->textures[i] =
399 screen->pipe_screen->texture_create(screen->pipe_screen, &templ);
403 drawable->old_w = width;
404 drawable->old_h = height;
408 * Backend function for init_screen.
411 static const __DRIextension *dri1_screen_extensions[] = {
412 &driReadDrawableExtension,
413 &driCopySubBufferExtension.base,
414 &driSwapControlExtension.base,
415 &driFrameTrackingExtension.base,
416 &driMediaStreamCounterExtension.base,
421 st_dri_lock(struct pipe_context *pipe)
423 dri1_lock((struct dri_context *)pipe->priv);
427 st_dri_unlock(struct pipe_context *pipe)
429 dri1_unlock((struct dri_context *)pipe->priv);
433 st_dri_is_locked(struct pipe_context *pipe)
435 return ((struct dri_context *)pipe->priv)->isLocked;
439 st_dri_lost_lock(struct pipe_context *pipe)
441 return ((struct dri_context *)pipe->priv)->wsLostLock;
445 st_dri_clear_lost_lock(struct pipe_context *pipe)
447 ((struct dri_context *)pipe->priv)->wsLostLock = FALSE;
450 static struct dri1_api_lock_funcs dri1_lf = {
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
459 dri1_copy_version(struct dri1_api_version *dst,
460 const struct __DRIversionRec *src)
462 dst->major = src->major;
463 dst->minor = src->minor;
464 dst->patch_level = src->patch;
467 struct dri1_api *__dri1_api_hooks = NULL;
470 dri1_init_screen(__DRIscreen * sPriv)
472 const __DRIconfig **configs;
473 struct dri_screen *screen;
474 struct dri1_create_screen_arg arg;
476 screen = CALLOC_STRUCT(dri_screen);
480 screen->api = drm_api_create();
481 screen->sPriv = sPriv;
482 screen->fd = sPriv->fd;
483 screen->drmLock = (drmLock *) & sPriv->pSAREA->lock;
485 sPriv->private = (void *)screen;
486 sPriv->extensions = dri1_screen_extensions;
488 arg.base.mode = DRM_CREATE_DRI1;
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);
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
504 configs = dri_init_screen_helper(screen, &arg.base, sPriv->fbBPP);
509 debug_printf("%s: failed to create dri1 screen\n", __FUNCTION__);
513 __dri1_api_hooks = arg.api;
519 dri_destroy_screen_helper(screen);