s/Tungsten Graphics/VMware/
[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 VMWARE 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 <vdpau/vdpau.h>
30
31 #include "util/u_debug.h"
32 #include "util/u_memory.h"
33
34 #include "vdpau_private.h"
35
36 /**
37 * Create a VdpPresentationQueue.
38 */
39 VdpStatus
40 vlVdpPresentationQueueCreate(VdpDevice device,
41 VdpPresentationQueueTarget presentation_queue_target,
42 VdpPresentationQueue *presentation_queue)
43 {
44 vlVdpPresentationQueue *pq = NULL;
45 VdpStatus ret;
46
47 if (!presentation_queue)
48 return VDP_STATUS_INVALID_POINTER;
49
50 vlVdpDevice *dev = vlGetDataHTAB(device);
51 if (!dev)
52 return VDP_STATUS_INVALID_HANDLE;
53
54 vlVdpPresentationQueueTarget *pqt = vlGetDataHTAB(presentation_queue_target);
55 if (!pqt)
56 return VDP_STATUS_INVALID_HANDLE;
57
58 if (dev != pqt->device)
59 return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
60
61 pq = CALLOC(1, sizeof(vlVdpPresentationQueue));
62 if (!pq)
63 return VDP_STATUS_RESOURCES;
64
65 pq->device = dev;
66 pq->drawable = pqt->drawable;
67
68 pipe_mutex_lock(dev->mutex);
69 if (!vl_compositor_init_state(&pq->cstate, dev->context)) {
70 pipe_mutex_unlock(dev->mutex);
71 ret = VDP_STATUS_ERROR;
72 goto no_compositor;
73 }
74 pipe_mutex_unlock(dev->mutex);
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
84 no_handle:
85 no_compositor:
86 FREE(pq);
87 return ret;
88 }
89
90 /**
91 * Destroy a VdpPresentationQueue.
92 */
93 VdpStatus
94 vlVdpPresentationQueueDestroy(VdpPresentationQueue presentation_queue)
95 {
96 vlVdpPresentationQueue *pq;
97
98 pq = vlGetDataHTAB(presentation_queue);
99 if (!pq)
100 return VDP_STATUS_INVALID_HANDLE;
101
102 pipe_mutex_lock(pq->device->mutex);
103 vl_compositor_cleanup_state(&pq->cstate);
104 pipe_mutex_unlock(pq->device->mutex);
105
106 vlRemoveDataHTAB(presentation_queue);
107 FREE(pq);
108
109 return VDP_STATUS_OK;
110 }
111
112 /**
113 * Configure the background color setting.
114 */
115 VdpStatus
116 vlVdpPresentationQueueSetBackgroundColor(VdpPresentationQueue presentation_queue,
117 VdpColor *const background_color)
118 {
119 vlVdpPresentationQueue *pq;
120 union pipe_color_union color;
121
122 if (!background_color)
123 return VDP_STATUS_INVALID_POINTER;
124
125 pq = vlGetDataHTAB(presentation_queue);
126 if (!pq)
127 return VDP_STATUS_INVALID_HANDLE;
128
129 color.f[0] = background_color->red;
130 color.f[1] = background_color->green;
131 color.f[2] = background_color->blue;
132 color.f[3] = background_color->alpha;
133
134 pipe_mutex_lock(pq->device->mutex);
135 vl_compositor_set_clear_color(&pq->cstate, &color);
136 pipe_mutex_unlock(pq->device->mutex);
137
138 return VDP_STATUS_OK;
139 }
140
141 /**
142 * Retrieve the current background color setting.
143 */
144 VdpStatus
145 vlVdpPresentationQueueGetBackgroundColor(VdpPresentationQueue presentation_queue,
146 VdpColor *const background_color)
147 {
148 vlVdpPresentationQueue *pq;
149 union pipe_color_union color;
150
151 if (!background_color)
152 return VDP_STATUS_INVALID_POINTER;
153
154 pq = vlGetDataHTAB(presentation_queue);
155 if (!pq)
156 return VDP_STATUS_INVALID_HANDLE;
157
158 pipe_mutex_lock(pq->device->mutex);
159 vl_compositor_get_clear_color(&pq->cstate, &color);
160 pipe_mutex_unlock(pq->device->mutex);
161
162 background_color->red = color.f[0];
163 background_color->green = color.f[1];
164 background_color->blue = color.f[2];
165 background_color->alpha = color.f[3];
166
167 return VDP_STATUS_OK;
168 }
169
170 /**
171 * Retrieve the presentation queue's "current" time.
172 */
173 VdpStatus
174 vlVdpPresentationQueueGetTime(VdpPresentationQueue presentation_queue,
175 VdpTime *current_time)
176 {
177 vlVdpPresentationQueue *pq;
178
179 if (!current_time)
180 return VDP_STATUS_INVALID_POINTER;
181
182 pq = vlGetDataHTAB(presentation_queue);
183 if (!pq)
184 return VDP_STATUS_INVALID_HANDLE;
185
186 pipe_mutex_lock(pq->device->mutex);
187 *current_time = vl_screen_get_timestamp(pq->device->vscreen, pq->drawable);
188 pipe_mutex_unlock(pq->device->mutex);
189
190 return VDP_STATUS_OK;
191 }
192
193 /**
194 * Enter a surface into the presentation queue.
195 */
196 VdpStatus
197 vlVdpPresentationQueueDisplay(VdpPresentationQueue presentation_queue,
198 VdpOutputSurface surface,
199 uint32_t clip_width,
200 uint32_t clip_height,
201 VdpTime earliest_presentation_time)
202 {
203 static int dump_window = -1;
204
205 vlVdpPresentationQueue *pq;
206 vlVdpOutputSurface *surf;
207
208 struct pipe_context *pipe;
209 struct pipe_resource *tex;
210 struct pipe_surface surf_templ, *surf_draw;
211 struct u_rect src_rect, dst_clip, *dirty_area;
212
213 struct vl_compositor *compositor;
214 struct vl_compositor_state *cstate;
215
216 pq = vlGetDataHTAB(presentation_queue);
217 if (!pq)
218 return VDP_STATUS_INVALID_HANDLE;
219
220 surf = vlGetDataHTAB(surface);
221 if (!surf)
222 return VDP_STATUS_INVALID_HANDLE;
223
224 pipe = pq->device->context;
225 compositor = &pq->device->compositor;
226 cstate = &pq->cstate;
227
228 pipe_mutex_lock(pq->device->mutex);
229 tex = vl_screen_texture_from_drawable(pq->device->vscreen, pq->drawable);
230 if (!tex) {
231 pipe_mutex_unlock(pq->device->mutex);
232 return VDP_STATUS_INVALID_HANDLE;
233 }
234
235 dirty_area = vl_screen_get_dirty_area(pq->device->vscreen);
236
237 memset(&surf_templ, 0, sizeof(surf_templ));
238 surf_templ.format = tex->format;
239 surf_draw = pipe->create_surface(pipe, tex, &surf_templ);
240
241 dst_clip.x0 = 0;
242 dst_clip.y0 = 0;
243 dst_clip.x1 = clip_width ? clip_width : surf_draw->width;
244 dst_clip.y1 = clip_height ? clip_height : surf_draw->height;
245
246 if (pq->device->delayed_rendering.surface == surface &&
247 dst_clip.x1 == surf_draw->width && dst_clip.y1 == surf_draw->height) {
248
249 // TODO: we correctly support the clipping here, but not the pq background color in the clipped area....
250 cstate = pq->device->delayed_rendering.cstate;
251 vl_compositor_set_dst_clip(cstate, &dst_clip);
252 vlVdpResolveDelayedRendering(pq->device, surf_draw, dirty_area);
253
254 } else {
255 vlVdpResolveDelayedRendering(pq->device, NULL, NULL);
256
257 src_rect.x0 = 0;
258 src_rect.y0 = 0;
259 src_rect.x1 = surf_draw->width;
260 src_rect.y1 = surf_draw->height;
261
262 vl_compositor_clear_layers(cstate);
263 vl_compositor_set_rgba_layer(cstate, compositor, 0, surf->sampler_view, &src_rect, NULL, NULL);
264 vl_compositor_set_dst_clip(cstate, &dst_clip);
265 vl_compositor_render(cstate, compositor, surf_draw, dirty_area, true);
266 }
267
268 vl_screen_set_next_timestamp(pq->device->vscreen, earliest_presentation_time);
269 pipe->screen->flush_frontbuffer
270 (
271 pipe->screen, tex, 0, 0,
272 vl_screen_get_private(pq->device->vscreen), NULL
273 );
274
275 pipe->screen->fence_reference(pipe->screen, &surf->fence, NULL);
276 pipe->flush(pipe, &surf->fence, 0);
277 pq->last_surf = surf;
278
279 if (dump_window == -1) {
280 dump_window = debug_get_num_option("VDPAU_DUMP", 0);
281 }
282
283 if (dump_window) {
284 static unsigned int framenum = 0;
285 char cmd[256];
286
287 if (framenum) {
288 sprintf(cmd, "xwd -id %d -silent -out vdpau_frame_%08d.xwd", (int)pq->drawable, framenum);
289 if (system(cmd) != 0)
290 VDPAU_MSG(VDPAU_ERR, "[VDPAU] Dumping surface %d failed.\n", surface);
291 }
292 framenum++;
293 }
294
295 pipe_resource_reference(&tex, NULL);
296 pipe_surface_reference(&surf_draw, NULL);
297 pipe_mutex_unlock(pq->device->mutex);
298
299 return VDP_STATUS_OK;
300 }
301
302 /**
303 * Wait for a surface to finish being displayed.
304 */
305 VdpStatus
306 vlVdpPresentationQueueBlockUntilSurfaceIdle(VdpPresentationQueue presentation_queue,
307 VdpOutputSurface surface,
308 VdpTime *first_presentation_time)
309 {
310 vlVdpPresentationQueue *pq;
311 vlVdpOutputSurface *surf;
312 struct pipe_screen *screen;
313
314 if (!first_presentation_time)
315 return VDP_STATUS_INVALID_POINTER;
316
317 pq = vlGetDataHTAB(presentation_queue);
318 if (!pq)
319 return VDP_STATUS_INVALID_HANDLE;
320
321 surf = vlGetDataHTAB(surface);
322 if (!surf)
323 return VDP_STATUS_INVALID_HANDLE;
324
325 pipe_mutex_lock(pq->device->mutex);
326 if (surf->fence) {
327 screen = pq->device->vscreen->pscreen;
328 screen->fence_finish(screen, surf->fence, PIPE_TIMEOUT_INFINITE);
329 screen->fence_reference(screen, &surf->fence, NULL);
330 }
331 pipe_mutex_unlock(pq->device->mutex);
332
333 return vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
334 }
335
336 /**
337 * Poll the current queue status of a surface.
338 */
339 VdpStatus
340 vlVdpPresentationQueueQuerySurfaceStatus(VdpPresentationQueue presentation_queue,
341 VdpOutputSurface surface,
342 VdpPresentationQueueStatus *status,
343 VdpTime *first_presentation_time)
344 {
345 vlVdpPresentationQueue *pq;
346 vlVdpOutputSurface *surf;
347 struct pipe_screen *screen;
348
349 if (!(status && first_presentation_time))
350 return VDP_STATUS_INVALID_POINTER;
351
352 pq = vlGetDataHTAB(presentation_queue);
353 if (!pq)
354 return VDP_STATUS_INVALID_HANDLE;
355
356 surf = vlGetDataHTAB(surface);
357 if (!surf)
358 return VDP_STATUS_INVALID_HANDLE;
359
360 *first_presentation_time = 0;
361
362 if (!surf->fence) {
363 if (pq->last_surf == surf)
364 *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE;
365 else
366 *status = VDP_PRESENTATION_QUEUE_STATUS_IDLE;
367 } else {
368 pipe_mutex_lock(pq->device->mutex);
369 screen = pq->device->vscreen->pscreen;
370 if (screen->fence_signalled(screen, surf->fence)) {
371 screen->fence_reference(screen, &surf->fence, NULL);
372 *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE;
373 pipe_mutex_unlock(pq->device->mutex);
374
375 // We actually need to query the timestamp of the last VSYNC event from the hardware
376 vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
377 *first_presentation_time += 1;
378 } else {
379 *status = VDP_PRESENTATION_QUEUE_STATUS_QUEUED;
380 pipe_mutex_unlock(pq->device->mutex);
381 }
382 }
383
384 return VDP_STATUS_OK;
385 }