0e086fc18b42ae89517b39e86f8d19253e4a8a3a
[mesa.git] / src / gallium / state_trackers / vdpau / presentation.c
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 */
42 VdpStatus
43 vlVdpPresentationQueueCreate(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
88 no_handle:
89 no_compositor:
90 FREE(pq);
91 return ret;
92 }
93
94 /**
95 * Destroy a VdpPresentationQueue.
96 */
97 VdpStatus
98 vlVdpPresentationQueueDestroy(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 */
119 VdpStatus
120 vlVdpPresentationQueueSetBackgroundColor(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 */
148 VdpStatus
149 vlVdpPresentationQueueGetBackgroundColor(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 */
177 VdpStatus
178 vlVdpPresentationQueueGetTime(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 */
202 VdpStatus
203 vlVdpPresentationQueueDisplay(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 src_rect, dst_clip;
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 src_rect.x = 0;
233 src_rect.y = 0;
234 src_rect.w = drawable_surface->width;
235 src_rect.h = drawable_surface->height;
236
237 dst_clip.x = 0;
238 dst_clip.y = 0;
239 dst_clip.w = clip_width;
240 dst_clip.h = clip_height;
241
242 vl_compositor_clear_layers(&pq->compositor);
243 vl_compositor_set_rgba_layer(&pq->compositor, 0, surf->sampler_view, &src_rect, NULL);
244 vl_compositor_render(&pq->compositor, drawable_surface, NULL, &dst_clip, &pq->dirty_area);
245
246 pipe = pq->device->context->pipe;
247
248 pipe->screen->flush_frontbuffer
249 (
250 pipe->screen,
251 drawable_surface->texture,
252 0, 0,
253 vl_contextprivate_get(pq->device->context, drawable_surface)
254 );
255
256 pipe->screen->fence_reference(pipe->screen, &surf->fence, NULL);
257 pipe->flush(pipe, &surf->fence);
258
259 if (dump_window == -1) {
260 dump_window = debug_get_num_option("VDPAU_DUMP", 0);
261 }
262
263 if (dump_window) {
264 static unsigned int framenum = 0;
265 char cmd[256];
266
267 sprintf(cmd, "xwd -id %d -out vdpau_frame_%08d.xwd", (int)pq->drawable, ++framenum);
268 if (system(cmd) != 0)
269 VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Dumping surface %d failed.\n", surface);
270 }
271
272 pipe_surface_reference(&drawable_surface, NULL);
273
274 return VDP_STATUS_OK;
275 }
276
277 /**
278 * Wait for a surface to finish being displayed.
279 */
280 VdpStatus
281 vlVdpPresentationQueueBlockUntilSurfaceIdle(VdpPresentationQueue presentation_queue,
282 VdpOutputSurface surface,
283 VdpTime *first_presentation_time)
284 {
285 vlVdpPresentationQueue *pq;
286 vlVdpOutputSurface *surf;
287 struct pipe_screen *screen;
288
289 if (!first_presentation_time)
290 return VDP_STATUS_INVALID_POINTER;
291
292 pq = vlGetDataHTAB(presentation_queue);
293 if (!pq)
294 return VDP_STATUS_INVALID_HANDLE;
295
296 surf = vlGetDataHTAB(surface);
297 if (!surf)
298 return VDP_STATUS_INVALID_HANDLE;
299
300 if (surf->fence) {
301 screen = pq->device->context->pipe->screen;
302 screen->fence_finish(screen, surf->fence, 0);
303 }
304
305 // We actually need to query the timestamp of the last VSYNC event from the hardware
306 vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
307
308 return VDP_STATUS_OK;
309 }
310
311 /**
312 * Poll the current queue status of a surface.
313 */
314 VdpStatus
315 vlVdpPresentationQueueQuerySurfaceStatus(VdpPresentationQueue presentation_queue,
316 VdpOutputSurface surface,
317 VdpPresentationQueueStatus *status,
318 VdpTime *first_presentation_time)
319 {
320 vlVdpPresentationQueue *pq;
321 vlVdpOutputSurface *surf;
322 struct pipe_screen *screen;
323
324 if (!(status && first_presentation_time))
325 return VDP_STATUS_INVALID_POINTER;
326
327 pq = vlGetDataHTAB(presentation_queue);
328 if (!pq)
329 return VDP_STATUS_INVALID_HANDLE;
330
331 surf = vlGetDataHTAB(surface);
332 if (!surf)
333 return VDP_STATUS_INVALID_HANDLE;
334
335 *first_presentation_time = 0;
336
337 if (!surf->fence) {
338 *status = VDP_PRESENTATION_QUEUE_STATUS_IDLE;
339 } else {
340 screen = pq->device->context->pipe->screen;
341 if (screen->fence_signalled(screen, surf->fence)) {
342 screen->fence_reference(screen, &surf->fence, NULL);
343 *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE;
344
345 // We actually need to query the timestamp of the last VSYNC event from the hardware
346 vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
347 *first_presentation_time += 1;
348 } else {
349 *status = VDP_PRESENTATION_QUEUE_STATUS_QUEUED;
350 }
351 }
352
353 return VDP_STATUS_OK;
354 }