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