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