st/dri: Headers and public symbols clean up.
[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 #include "util/u_memory.h"
33 #include "util/u_rect.h"
34 #include "pipe/p_context.h"
35 #include "state_tracker/st_context.h"
36 #include "state_tracker/st_public.h"
37 #include "state_tracker/dri1_api.h"
38
39 #include "dri_screen.h"
40 #include "dri_context.h"
41 #include "dri_drawable.h"
42 #include "dri1.h"
43
44 static INLINE void
45 dri1_lock(struct dri_context *ctx)
46 {
47 drm_context_t hw_context = ctx->cPriv->hHWContext;
48 char ret = 0;
49
50 DRM_CAS(ctx->lock, hw_context, DRM_LOCK_HELD | hw_context, ret);
51 if (ret) {
52 drmGetLock(ctx->sPriv->fd, hw_context, 0);
53 ctx->stLostLock = TRUE;
54 ctx->wsLostLock = TRUE;
55 }
56 ctx->isLocked = TRUE;
57 }
58
59 static INLINE void
60 dri1_unlock(struct dri_context *ctx)
61 {
62 ctx->isLocked = FALSE;
63 DRM_UNLOCK(ctx->sPriv->fd, ctx->lock, ctx->cPriv->hHWContext);
64 }
65
66 static struct pipe_fence_handle *
67 dri_swap_fences_pop_front(struct dri_drawable *draw)
68 {
69 struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen;
70 struct pipe_fence_handle *fence = NULL;
71
72 if (draw->cur_fences >= draw->desired_fences) {
73 screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]);
74 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL);
75 --draw->cur_fences;
76 draw->tail &= DRI_SWAP_FENCES_MASK;
77 }
78 return fence;
79 }
80
81 static void
82 dri_swap_fences_push_back(struct dri_drawable *draw,
83 struct pipe_fence_handle *fence)
84 {
85 struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen;
86
87 if (!fence)
88 return;
89
90 if (draw->cur_fences < DRI_SWAP_FENCES_MAX) {
91 draw->cur_fences++;
92 screen->fence_reference(screen, &draw->swap_fences[draw->head++],
93 fence);
94 draw->head &= DRI_SWAP_FENCES_MASK;
95 }
96 }
97
98 void
99 dri1_swap_fences_clear(struct dri_drawable *drawable)
100 {
101 struct pipe_screen *screen = dri_screen(drawable->sPriv)->pipe_screen;
102 struct pipe_fence_handle *fence;
103
104 while (drawable->cur_fences) {
105 fence = dri_swap_fences_pop_front(drawable);
106 screen->fence_reference(screen, &fence, NULL);
107 }
108 }
109
110 static void
111 dri1_update_drawables_locked(struct dri_context *ctx,
112 __DRIdrawable * driDrawPriv,
113 __DRIdrawable * driReadPriv)
114 {
115 if (ctx->stLostLock) {
116 ctx->stLostLock = FALSE;
117 if (driDrawPriv == driReadPriv)
118 DRI_VALIDATE_DRAWABLE_INFO(ctx->sPriv, driDrawPriv);
119 else
120 DRI_VALIDATE_TWO_DRAWABLES_INFO(ctx->sPriv, driDrawPriv,
121 driReadPriv);
122 }
123 }
124
125 /**
126 * This ensures all contexts which bind to a drawable pick up the
127 * drawable change and signal new buffer state.
128 * Calling st_resize_framebuffer for each context may seem like overkill,
129 * but no new buffers will actually be allocated if the dimensions don't
130 * change.
131 */
132
133 static void
134 dri1_propagate_drawable_change(struct dri_context *ctx)
135 {
136 __DRIdrawable *dPriv = ctx->dPriv;
137 __DRIdrawable *rPriv = ctx->rPriv;
138 boolean flushed = FALSE;
139
140 if (dPriv && ctx->d_stamp != dPriv->lastStamp) {
141
142 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
143 flushed = TRUE;
144 ctx->d_stamp = dPriv->lastStamp;
145 st_resize_framebuffer(dri_drawable(dPriv)->stfb, dPriv->w, dPriv->h);
146
147 }
148
149 if (rPriv && dPriv != rPriv && ctx->r_stamp != rPriv->lastStamp) {
150
151 if (!flushed)
152 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
153 ctx->r_stamp = rPriv->lastStamp;
154 st_resize_framebuffer(dri_drawable(rPriv)->stfb, rPriv->w, rPriv->h);
155
156 } else if (rPriv && dPriv == rPriv) {
157
158 ctx->r_stamp = ctx->d_stamp;
159
160 }
161 }
162
163 void
164 dri1_update_drawables(struct dri_context *ctx,
165 struct dri_drawable *draw, struct dri_drawable *read)
166 {
167 dri1_lock(ctx);
168 dri1_update_drawables_locked(ctx, draw->dPriv, read->dPriv);
169 dri1_unlock(ctx);
170
171 dri1_propagate_drawable_change(ctx);
172 }
173
174 static INLINE boolean
175 dri1_intersect_src_bbox(struct drm_clip_rect *dst,
176 int dst_x,
177 int dst_y,
178 const struct drm_clip_rect *src,
179 const struct drm_clip_rect *bbox)
180 {
181 int xy1;
182 int xy2;
183
184 xy1 = ((int)src->x1 > (int)bbox->x1 + dst_x) ? src->x1 :
185 (int)bbox->x1 + dst_x;
186 xy2 = ((int)src->x2 < (int)bbox->x2 + dst_x) ? src->x2 :
187 (int)bbox->x2 + dst_x;
188 if (xy1 >= xy2 || xy1 < 0)
189 return FALSE;
190
191 dst->x1 = xy1;
192 dst->x2 = xy2;
193
194 xy1 = ((int)src->y1 > (int)bbox->y1 + dst_y) ? src->y1 :
195 (int)bbox->y1 + dst_y;
196 xy2 = ((int)src->y2 < (int)bbox->y2 + dst_y) ? src->y2 :
197 (int)bbox->y2 + dst_y;
198 if (xy1 >= xy2 || xy1 < 0)
199 return FALSE;
200
201 dst->y1 = xy1;
202 dst->y2 = xy2;
203 return TRUE;
204 }
205
206 static void
207 dri1_swap_copy(struct dri_context *ctx,
208 struct pipe_surface *dst,
209 struct pipe_surface *src,
210 __DRIdrawable * dPriv, const struct drm_clip_rect *bbox)
211 {
212 struct pipe_context *pipe = ctx->pipe;
213 struct drm_clip_rect clip;
214 struct drm_clip_rect *cur;
215 int i;
216
217 cur = dPriv->pClipRects;
218
219 for (i = 0; i < dPriv->numClipRects; ++i) {
220 if (dri1_intersect_src_bbox(&clip, dPriv->x, dPriv->y, cur++, bbox)) {
221 if (pipe->surface_copy) {
222 pipe->surface_copy(pipe, dst, clip.x1, clip.y1,
223 src,
224 (int)clip.x1 - dPriv->x,
225 (int)clip.y1 - dPriv->y,
226 clip.x2 - clip.x1, clip.y2 - clip.y1);
227 } else {
228 util_surface_copy(pipe, FALSE, dst, clip.x1, clip.y1,
229 src,
230 (int)clip.x1 - dPriv->x,
231 (int)clip.y1 - dPriv->y,
232 clip.x2 - clip.x1, clip.y2 - clip.y1);
233 }
234 }
235 }
236 }
237
238 static void
239 dri1_copy_to_front(struct dri_context *ctx,
240 struct pipe_surface *surf,
241 __DRIdrawable * dPriv,
242 const struct drm_clip_rect *sub_box,
243 struct pipe_fence_handle **fence)
244 {
245 struct pipe_context *pipe = ctx->pipe;
246 boolean save_lost_lock;
247 uint cur_w;
248 uint cur_h;
249 struct drm_clip_rect bbox;
250 boolean visible = TRUE;
251
252 *fence = NULL;
253
254 dri1_lock(ctx);
255 save_lost_lock = ctx->stLostLock;
256 dri1_update_drawables_locked(ctx, dPriv, dPriv);
257 st_get_framebuffer_dimensions(dri_drawable(dPriv)->stfb, &cur_w, &cur_h);
258
259 bbox.x1 = 0;
260 bbox.x2 = cur_w;
261 bbox.y1 = 0;
262 bbox.y2 = cur_h;
263
264 if (sub_box)
265 visible = dri1_intersect_src_bbox(&bbox, 0, 0, &bbox, sub_box);
266
267 if (visible && __dri1_api_hooks->present_locked) {
268
269 __dri1_api_hooks->present_locked(pipe,
270 surf,
271 dPriv->pClipRects,
272 dPriv->numClipRects,
273 dPriv->x, dPriv->y, &bbox, fence);
274
275 } else if (visible && __dri1_api_hooks->front_srf_locked) {
276
277 struct pipe_surface *front = __dri1_api_hooks->front_srf_locked(pipe);
278
279 if (front)
280 dri1_swap_copy(ctx, front, surf, dPriv, &bbox);
281
282 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, fence);
283 }
284
285 ctx->stLostLock = save_lost_lock;
286
287 /**
288 * FIXME: Revisit this: Update drawables on copy_sub_buffer ?
289 */
290
291 if (!sub_box)
292 dri1_update_drawables_locked(ctx, ctx->dPriv, ctx->rPriv);
293
294 dri1_unlock(ctx);
295 dri1_propagate_drawable_change(ctx);
296 }
297
298 void
299 dri1_flush_frontbuffer(struct pipe_screen *screen,
300 struct pipe_surface *surf, void *context_private)
301 {
302 struct dri_context *ctx = (struct dri_context *)context_private;
303 struct pipe_fence_handle *dummy_fence;
304
305 dri1_copy_to_front(ctx, surf, ctx->dPriv, NULL, &dummy_fence);
306 screen->fence_reference(screen, &dummy_fence, NULL);
307
308 /**
309 * FIXME: Do we need swap throttling here?
310 */
311 }
312
313 void
314 dri1_swap_buffers(__DRIdrawable * dPriv)
315 {
316 struct dri_context *ctx;
317 struct pipe_surface *back_surf;
318 struct dri_drawable *draw = dri_drawable(dPriv);
319 struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen;
320 struct pipe_fence_handle *fence;
321 struct st_context *st = st_get_current();
322
323 assert(__dri1_api_hooks != NULL);
324
325 if (!st)
326 return; /* For now */
327
328 ctx = (struct dri_context *)st->pipe->priv;
329
330 st_get_framebuffer_surface(draw->stfb, ST_SURFACE_BACK_LEFT, &back_surf);
331 if (back_surf) {
332 st_notify_swapbuffers(draw->stfb);
333 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
334 fence = dri_swap_fences_pop_front(draw);
335 if (fence) {
336 (void)screen->fence_finish(screen, fence, 0);
337 screen->fence_reference(screen, &fence, NULL);
338 }
339 dri1_copy_to_front(ctx, back_surf, dPriv, NULL, &fence);
340 dri_swap_fences_push_back(draw, fence);
341 screen->fence_reference(screen, &fence, NULL);
342 }
343 }
344
345 void
346 dri1_copy_sub_buffer(__DRIdrawable * dPriv, int x, int y, int w, int h)
347 {
348 struct pipe_screen *screen = dri_screen(dPriv->driScreenPriv)->pipe_screen;
349 struct drm_clip_rect sub_bbox;
350 struct dri_context *ctx;
351 struct pipe_surface *back_surf;
352 struct dri_drawable *draw = dri_drawable(dPriv);
353 struct pipe_fence_handle *dummy_fence;
354 struct st_context *st = st_get_current();
355
356 assert(__dri1_api_hooks != NULL);
357
358 if (!st)
359 return;
360
361 ctx = (struct dri_context *)st->pipe->priv;
362
363 sub_bbox.x1 = x;
364 sub_bbox.x2 = x + w;
365 sub_bbox.y1 = y;
366 sub_bbox.y2 = y + h;
367
368 st_get_framebuffer_surface(draw->stfb, ST_SURFACE_BACK_LEFT, &back_surf);
369 if (back_surf) {
370 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
371 dri1_copy_to_front(ctx, back_surf, dPriv, &sub_bbox, &dummy_fence);
372 screen->fence_reference(screen, &dummy_fence, NULL);
373 }
374 }
375
376 static void
377 st_dri_lock(struct pipe_context *pipe)
378 {
379 dri1_lock((struct dri_context *)pipe->priv);
380 }
381
382 static void
383 st_dri_unlock(struct pipe_context *pipe)
384 {
385 dri1_unlock((struct dri_context *)pipe->priv);
386 }
387
388 static boolean
389 st_dri_is_locked(struct pipe_context *pipe)
390 {
391 return ((struct dri_context *)pipe->priv)->isLocked;
392 }
393
394 static boolean
395 st_dri_lost_lock(struct pipe_context *pipe)
396 {
397 return ((struct dri_context *)pipe->priv)->wsLostLock;
398 }
399
400 static void
401 st_dri_clear_lost_lock(struct pipe_context *pipe)
402 {
403 ((struct dri_context *)pipe->priv)->wsLostLock = FALSE;
404 }
405
406 static struct dri1_api_lock_funcs dri1_lf = {
407 .lock = st_dri_lock,
408 .unlock = st_dri_unlock,
409 .is_locked = st_dri_is_locked,
410 .is_lock_lost = st_dri_lost_lock,
411 .clear_lost_lock = st_dri_clear_lost_lock
412 };
413
414 static const __DRIextension *dri1_screen_extensions[] = {
415 &driReadDrawableExtension,
416 &driCopySubBufferExtension.base,
417 &driSwapControlExtension.base,
418 &driFrameTrackingExtension.base,
419 &driMediaStreamCounterExtension.base,
420 NULL
421 };
422
423 struct dri1_api *__dri1_api_hooks = NULL;
424
425 static INLINE void
426 dri1_copy_version(struct dri1_api_version *dst,
427 const struct __DRIversionRec *src)
428 {
429 dst->major = src->major;
430 dst->minor = src->minor;
431 dst->patch_level = src->patch;
432 }
433
434 const __DRIconfig **
435 dri1_init_screen(__DRIscreen * sPriv)
436 {
437 struct dri_screen *screen;
438 const __DRIconfig **configs;
439 struct dri1_create_screen_arg arg;
440
441 screen = CALLOC_STRUCT(dri_screen);
442 if (!screen)
443 return NULL;
444
445 screen->api = drm_api_create();
446 screen->sPriv = sPriv;
447 screen->fd = sPriv->fd;
448 screen->drmLock = (drmLock *) & sPriv->pSAREA->lock;
449
450 sPriv->private = (void *)screen;
451 sPriv->extensions = dri1_screen_extensions;
452
453 arg.base.mode = DRM_CREATE_DRI1;
454 arg.lf = &dri1_lf;
455 arg.ddx_info = sPriv->pDevPriv;
456 arg.ddx_info_size = sPriv->devPrivSize;
457 arg.sarea = sPriv->pSAREA;
458 dri1_copy_version(&arg.ddx_version, &sPriv->ddx_version);
459 dri1_copy_version(&arg.dri_version, &sPriv->dri_version);
460 dri1_copy_version(&arg.drm_version, &sPriv->drm_version);
461 arg.api = NULL;
462
463 screen->pipe_screen = screen->api->create_screen(screen->api, screen->fd, &arg.base);
464
465 if (!screen->pipe_screen || !arg.api) {
466 debug_printf("%s: failed to create dri1 screen\n", __FUNCTION__);
467 goto out_no_screen;
468 }
469
470 __dri1_api_hooks = arg.api;
471
472 screen->pipe_screen->flush_frontbuffer = dri1_flush_frontbuffer;
473 driParseOptionInfo(&screen->optionCache,
474 __driConfigOptions, __driNConfigOptions);
475
476 /**
477 * FIXME: If the driver supports format conversion swapbuffer blits, we might
478 * want to support other color bit depths than the server is currently
479 * using.
480 */
481
482 configs = dri_fill_in_modes(screen, sPriv->fbBPP);
483 if (!configs)
484 goto out_no_configs;
485
486 return configs;
487 out_no_configs:
488 screen->pipe_screen->destroy(screen->pipe_screen);
489 out_no_screen:
490 FREE(screen);
491 return NULL;
492 }