presentation.c revision 1d0c357a9733238985cbe029b174173ef927ac70
1/**************************************************************************
2 *
3 * Copyright 2010 Thomas Balling Sørensen.
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 TUNGSTEN GRAPHICS 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#include <stdio.h>
29#include <vdpau/vdpau.h>
30
31#include "util/u_debug.h"
32#include "util/u_memory.h"
33
34#include "vdpau_private.h"
35
36/**
37 * Create a VdpPresentationQueue.
38 */
39VdpStatus
40vlVdpPresentationQueueCreate(VdpDevice device,
41                             VdpPresentationQueueTarget presentation_queue_target,
42                             VdpPresentationQueue *presentation_queue)
43{
44   vlVdpPresentationQueue *pq = NULL;
45   VdpStatus ret;
46
47   if (!presentation_queue)
48      return VDP_STATUS_INVALID_POINTER;
49
50   vlVdpDevice *dev = vlGetDataHTAB(device);
51   if (!dev)
52      return VDP_STATUS_INVALID_HANDLE;
53
54   vlVdpPresentationQueueTarget *pqt = vlGetDataHTAB(presentation_queue_target);
55   if (!pqt)
56      return VDP_STATUS_INVALID_HANDLE;
57
58   if (dev != pqt->device)
59      return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
60
61   pq = CALLOC(1, sizeof(vlVdpPresentationQueue));
62   if (!pq)
63      return VDP_STATUS_RESOURCES;
64
65   pq->device = dev;
66   pq->drawable = pqt->drawable;
67
68   if (!vl_compositor_init_state(&pq->cstate, dev->context)) {
69      ret = VDP_STATUS_ERROR;
70      goto no_compositor;
71   }
72
73   *presentation_queue = vlAddDataHTAB(pq);
74   if (*presentation_queue == 0) {
75      ret = VDP_STATUS_ERROR;
76      goto no_handle;
77   }
78
79   return VDP_STATUS_OK;
80
81no_handle:
82no_compositor:
83   FREE(pq);
84   return ret;
85}
86
87/**
88 * Destroy a VdpPresentationQueue.
89 */
90VdpStatus
91vlVdpPresentationQueueDestroy(VdpPresentationQueue presentation_queue)
92{
93   vlVdpPresentationQueue *pq;
94
95   pq = vlGetDataHTAB(presentation_queue);
96   if (!pq)
97      return VDP_STATUS_INVALID_HANDLE;
98
99   vl_compositor_cleanup_state(&pq->cstate);
100
101   vlRemoveDataHTAB(presentation_queue);
102   FREE(pq);
103
104   return VDP_STATUS_OK;
105}
106
107/**
108 * Configure the background color setting.
109 */
110VdpStatus
111vlVdpPresentationQueueSetBackgroundColor(VdpPresentationQueue presentation_queue,
112                                         VdpColor *const background_color)
113{
114   vlVdpPresentationQueue *pq;
115   union pipe_color_union color;
116
117   if (!background_color)
118      return VDP_STATUS_INVALID_POINTER;
119
120   pq = vlGetDataHTAB(presentation_queue);
121   if (!pq)
122      return VDP_STATUS_INVALID_HANDLE;
123
124   color.f[0] = background_color->red;
125   color.f[1] = background_color->green;
126   color.f[2] = background_color->blue;
127   color.f[3] = background_color->alpha;
128
129   vl_compositor_set_clear_color(&pq->cstate, &color);
130
131   return VDP_STATUS_OK;
132}
133
134/**
135 * Retrieve the current background color setting.
136 */
137VdpStatus
138vlVdpPresentationQueueGetBackgroundColor(VdpPresentationQueue presentation_queue,
139                                         VdpColor *const background_color)
140{
141   vlVdpPresentationQueue *pq;
142   union pipe_color_union color;
143
144   if (!background_color)
145      return VDP_STATUS_INVALID_POINTER;
146
147   pq = vlGetDataHTAB(presentation_queue);
148   if (!pq)
149      return VDP_STATUS_INVALID_HANDLE;
150
151   vl_compositor_get_clear_color(&pq->cstate, &color);
152
153   background_color->red = color.f[0];
154   background_color->green = color.f[1];
155   background_color->blue = color.f[2];
156   background_color->alpha = color.f[3];
157
158   return VDP_STATUS_OK;
159}
160
161/**
162 * Retrieve the presentation queue's "current" time.
163 */
164VdpStatus
165vlVdpPresentationQueueGetTime(VdpPresentationQueue presentation_queue,
166                              VdpTime *current_time)
167{
168   vlVdpPresentationQueue *pq;
169
170   if (!current_time)
171      return VDP_STATUS_INVALID_POINTER;
172
173   pq = vlGetDataHTAB(presentation_queue);
174   if (!pq)
175      return VDP_STATUS_INVALID_HANDLE;
176
177   *current_time = vl_screen_get_timestamp(pq->device->vscreen, pq->drawable);
178
179   return VDP_STATUS_OK;
180}
181
182/**
183 * Enter a surface into the presentation queue.
184 */
185VdpStatus
186vlVdpPresentationQueueDisplay(VdpPresentationQueue presentation_queue,
187                              VdpOutputSurface surface,
188                              uint32_t clip_width,
189                              uint32_t clip_height,
190                              VdpTime  earliest_presentation_time)
191{
192   static int dump_window = -1;
193
194   vlVdpPresentationQueue *pq;
195   vlVdpOutputSurface *surf;
196
197   struct pipe_context *pipe;
198   struct pipe_resource *tex;
199   struct pipe_surface surf_templ, *surf_draw;
200   struct u_rect src_rect, dst_clip, *dirty_area;
201
202   struct vl_compositor *compositor;
203   struct vl_compositor_state *cstate;
204
205   pq = vlGetDataHTAB(presentation_queue);
206   if (!pq)
207      return VDP_STATUS_INVALID_HANDLE;
208
209
210   pipe = pq->device->context;
211   compositor = &pq->device->compositor;
212   cstate = &pq->cstate;
213
214   tex = vl_screen_texture_from_drawable(pq->device->vscreen, pq->drawable);
215   if (!tex)
216      return VDP_STATUS_INVALID_HANDLE;
217
218   dirty_area = vl_screen_get_dirty_area(pq->device->vscreen);
219
220   memset(&surf_templ, 0, sizeof(surf_templ));
221   surf_templ.format = tex->format;
222   surf_templ.usage = PIPE_BIND_RENDER_TARGET;
223   surf_draw = pipe->create_surface(pipe, tex, &surf_templ);
224
225   surf = vlGetDataHTAB(surface);
226   if (!surf)
227      return VDP_STATUS_INVALID_HANDLE;
228
229   surf->timestamp = (vlVdpTime)earliest_presentation_time;
230
231   dst_clip.x0 = 0;
232   dst_clip.y0 = 0;
233   dst_clip.x1 = clip_width ? clip_width : surf_draw->width;
234   dst_clip.y1 = clip_height ? clip_height : surf_draw->height;
235
236   if (pq->device->delayed_rendering.surface == surface &&
237       dst_clip.x1 == surf_draw->width && dst_clip.y1 == surf_draw->height) {
238
239      // TODO: we correctly support the clipping here, but not the pq background color in the clipped area....
240      cstate = pq->device->delayed_rendering.cstate;
241      vl_compositor_set_dst_clip(cstate, &dst_clip);
242      vlVdpResolveDelayedRendering(pq->device, surf_draw, dirty_area);
243
244   } else {
245      vlVdpResolveDelayedRendering(pq->device, NULL, NULL);
246
247      src_rect.x0 = 0;
248      src_rect.y0 = 0;
249      src_rect.x1 = surf_draw->width;
250      src_rect.y1 = surf_draw->height;
251
252      vl_compositor_clear_layers(cstate);
253      vl_compositor_set_rgba_layer(cstate, compositor, 0, surf->sampler_view, &src_rect, NULL, NULL);
254      vl_compositor_set_dst_clip(cstate, &dst_clip);
255      vl_compositor_render(cstate, compositor, surf_draw, dirty_area);
256   }
257
258   vl_screen_set_next_timestamp(pq->device->vscreen, earliest_presentation_time);
259   pipe->screen->flush_frontbuffer
260   (
261      pipe->screen, tex, 0, 0,
262      vl_screen_get_private(pq->device->vscreen)
263   );
264
265   pipe->screen->fence_reference(pipe->screen, &surf->fence, NULL);
266   pipe->flush(pipe, &surf->fence);
267
268   if (dump_window == -1) {
269      dump_window = debug_get_num_option("VDPAU_DUMP", 0);
270   }
271
272   if (dump_window) {
273      static unsigned int framenum = 0;
274      char cmd[256];
275
276      sprintf(cmd, "xwd -id %d -out vdpau_frame_%08d.xwd", (int)pq->drawable, ++framenum);
277      if (system(cmd) != 0)
278         VDPAU_MSG(VDPAU_ERR, "[VDPAU] Dumping surface %d failed.\n", surface);
279   }
280
281   pipe_resource_reference(&tex, NULL);
282   pipe_surface_reference(&surf_draw, NULL);
283
284   return VDP_STATUS_OK;
285}
286
287/**
288 * Wait for a surface to finish being displayed.
289 */
290VdpStatus
291vlVdpPresentationQueueBlockUntilSurfaceIdle(VdpPresentationQueue presentation_queue,
292                                            VdpOutputSurface surface,
293                                            VdpTime *first_presentation_time)
294{
295   vlVdpPresentationQueue *pq;
296   vlVdpOutputSurface *surf;
297   struct pipe_screen *screen;
298
299   if (!first_presentation_time)
300      return VDP_STATUS_INVALID_POINTER;
301
302   pq = vlGetDataHTAB(presentation_queue);
303   if (!pq)
304      return VDP_STATUS_INVALID_HANDLE;
305
306   surf = vlGetDataHTAB(surface);
307   if (!surf)
308      return VDP_STATUS_INVALID_HANDLE;
309
310   if (surf->fence) {
311      screen = pq->device->vscreen->pscreen;
312      screen->fence_finish(screen, surf->fence, 0);
313   }
314
315   return vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
316}
317
318/**
319 * Poll the current queue status of a surface.
320 */
321VdpStatus
322vlVdpPresentationQueueQuerySurfaceStatus(VdpPresentationQueue presentation_queue,
323                                         VdpOutputSurface surface,
324                                         VdpPresentationQueueStatus *status,
325                                         VdpTime *first_presentation_time)
326{
327   vlVdpPresentationQueue *pq;
328   vlVdpOutputSurface *surf;
329   struct pipe_screen *screen;
330
331   if (!(status && first_presentation_time))
332      return VDP_STATUS_INVALID_POINTER;
333
334   pq = vlGetDataHTAB(presentation_queue);
335   if (!pq)
336      return VDP_STATUS_INVALID_HANDLE;
337
338   surf = vlGetDataHTAB(surface);
339   if (!surf)
340      return VDP_STATUS_INVALID_HANDLE;
341
342   *first_presentation_time = 0;
343
344   if (!surf->fence) {
345      *status = VDP_PRESENTATION_QUEUE_STATUS_IDLE;
346   } else {
347      screen = pq->device->vscreen->pscreen;
348      if (screen->fence_signalled(screen, surf->fence)) {
349         screen->fence_reference(screen, &surf->fence, NULL);
350         *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE;
351
352         // We actually need to query the timestamp of the last VSYNC event from the hardware
353         vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
354         *first_presentation_time += 1;
355      } else {
356         *status = VDP_PRESENTATION_QUEUE_STATUS_QUEUED;
357      }
358   }
359
360   return VDP_STATUS_OK;
361}
362