presentation.c revision f8ac7e034803a1c873bf156c012fede6d2640097
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   struct vl_compositor_state *cstate;
209
210   pq = vlGetDataHTAB(presentation_queue);
211   if (!pq)
212      return VDP_STATUS_INVALID_HANDLE;
213
214
215   pipe = pq->device->context;
216   compositor = &pq->device->compositor;
217   cstate = &pq->cstate;
218
219   tex = vl_screen_texture_from_drawable(pq->device->vscreen, pq->drawable);
220   if (!tex)
221      return VDP_STATUS_INVALID_HANDLE;
222
223   dirty_area = vl_screen_get_dirty_area(pq->device->vscreen);
224
225   memset(&surf_templ, 0, sizeof(surf_templ));
226   surf_templ.format = tex->format;
227   surf_templ.usage = PIPE_BIND_RENDER_TARGET;
228   surf_draw = pipe->create_surface(pipe, tex, &surf_templ);
229
230   surf = vlGetDataHTAB(surface);
231   if (!surf)
232      return VDP_STATUS_INVALID_HANDLE;
233
234   surf->timestamp = (vlVdpTime)earliest_presentation_time;
235
236   dst_clip.x0 = 0;
237   dst_clip.y0 = 0;
238   dst_clip.x1 = clip_width ? clip_width : surf_draw->width;
239   dst_clip.y1 = clip_height ? clip_height : surf_draw->height;
240
241   if (pq->device->delayed_rendering.surface == surface &&
242       dst_clip.x1 == surf_draw->width && dst_clip.y1 == surf_draw->height) {
243
244      // TODO: we correctly support the clipping here, but not the pq background color in the clipped area....
245      cstate = pq->device->delayed_rendering.cstate;
246      vl_compositor_set_dst_clip(cstate, &dst_clip);
247      vlVdpResolveDelayedRendering(pq->device, surf_draw, dirty_area);
248
249   } else {
250      vlVdpResolveDelayedRendering(pq->device, NULL, NULL);
251
252      src_rect.x0 = 0;
253      src_rect.y0 = 0;
254      src_rect.x1 = surf_draw->width;
255      src_rect.y1 = surf_draw->height;
256
257      vl_compositor_clear_layers(cstate);
258      vl_compositor_set_rgba_layer(cstate, compositor, 0, surf->sampler_view, &src_rect, NULL, NULL);
259      vl_compositor_set_dst_clip(cstate, &dst_clip);
260      vl_compositor_render(cstate, compositor, surf_draw, dirty_area);
261   }
262
263   pipe->screen->flush_frontbuffer
264   (
265      pipe->screen, tex, 0, 0,
266      vl_screen_get_private(pq->device->vscreen)
267   );
268
269   pipe->screen->fence_reference(pipe->screen, &surf->fence, NULL);
270   pipe->flush(pipe, &surf->fence);
271
272   if (dump_window == -1) {
273      dump_window = debug_get_num_option("VDPAU_DUMP", 0);
274   }
275
276   if (dump_window) {
277      static unsigned int framenum = 0;
278      char cmd[256];
279
280      sprintf(cmd, "xwd -id %d -out vdpau_frame_%08d.xwd", (int)pq->drawable, ++framenum);
281      if (system(cmd) != 0)
282         VDPAU_MSG(VDPAU_ERR, "[VDPAU] Dumping surface %d failed.\n", surface);
283   }
284
285   pipe_resource_reference(&tex, NULL);
286   pipe_surface_reference(&surf_draw, NULL);
287
288   return VDP_STATUS_OK;
289}
290
291/**
292 * Wait for a surface to finish being displayed.
293 */
294VdpStatus
295vlVdpPresentationQueueBlockUntilSurfaceIdle(VdpPresentationQueue presentation_queue,
296                                            VdpOutputSurface surface,
297                                            VdpTime *first_presentation_time)
298{
299   vlVdpPresentationQueue *pq;
300   vlVdpOutputSurface *surf;
301   struct pipe_screen *screen;
302
303   if (!first_presentation_time)
304      return VDP_STATUS_INVALID_POINTER;
305
306   pq = vlGetDataHTAB(presentation_queue);
307   if (!pq)
308      return VDP_STATUS_INVALID_HANDLE;
309
310   surf = vlGetDataHTAB(surface);
311   if (!surf)
312      return VDP_STATUS_INVALID_HANDLE;
313
314   if (surf->fence) {
315      screen = pq->device->vscreen->pscreen;
316      screen->fence_finish(screen, surf->fence, 0);
317   }
318
319   // We actually need to query the timestamp of the last VSYNC event from the hardware
320   vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
321
322   return VDP_STATUS_OK;
323}
324
325/**
326 * Poll the current queue status of a surface.
327 */
328VdpStatus
329vlVdpPresentationQueueQuerySurfaceStatus(VdpPresentationQueue presentation_queue,
330                                         VdpOutputSurface surface,
331                                         VdpPresentationQueueStatus *status,
332                                         VdpTime *first_presentation_time)
333{
334   vlVdpPresentationQueue *pq;
335   vlVdpOutputSurface *surf;
336   struct pipe_screen *screen;
337
338   if (!(status && first_presentation_time))
339      return VDP_STATUS_INVALID_POINTER;
340
341   pq = vlGetDataHTAB(presentation_queue);
342   if (!pq)
343      return VDP_STATUS_INVALID_HANDLE;
344
345   surf = vlGetDataHTAB(surface);
346   if (!surf)
347      return VDP_STATUS_INVALID_HANDLE;
348
349   *first_presentation_time = 0;
350
351   if (!surf->fence) {
352      *status = VDP_PRESENTATION_QUEUE_STATUS_IDLE;
353   } else {
354      screen = pq->device->vscreen->pscreen;
355      if (screen->fence_signalled(screen, surf->fence)) {
356         screen->fence_reference(screen, &surf->fence, NULL);
357         *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE;
358
359         // We actually need to query the timestamp of the last VSYNC event from the hardware
360         vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
361         *first_presentation_time += 1;
362      } else {
363         *status = VDP_PRESENTATION_QUEUE_STATUS_QUEUED;
364      }
365   }
366
367   return VDP_STATUS_OK;
368}
369