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