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