Merge remote-tracking branch 'origin/master' into pipe-video
[mesa.git] / src / gallium / state_trackers / xorg / xvmc / surface.c
1 /**************************************************************************
2 *
3 * Copyright 2009 Younes Manton.
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 <assert.h>
29 #include <stdio.h>
30
31 #include <X11/Xlibint.h>
32
33 #include <pipe/p_video_context.h>
34 #include <pipe/p_video_state.h>
35 #include <pipe/p_state.h>
36
37 #include <util/u_inlines.h>
38 #include <util/u_memory.h>
39 #include <util/u_math.h>
40
41 #include <vl_winsys.h>
42
43 #include "xvmc_private.h"
44
45 static const unsigned const_empty_block_mask_420[3][2][2] = {
46 { { 0x20, 0x10 }, { 0x08, 0x04 } },
47 { { 0x02, 0x02 }, { 0x02, 0x02 } },
48 { { 0x01, 0x01 }, { 0x01, 0x01 } }
49 };
50
51 static enum pipe_mpeg12_picture_type PictureToPipe(int xvmc_pic)
52 {
53 switch (xvmc_pic) {
54 case XVMC_TOP_FIELD:
55 return PIPE_MPEG12_PICTURE_TYPE_FIELD_TOP;
56 case XVMC_BOTTOM_FIELD:
57 return PIPE_MPEG12_PICTURE_TYPE_FIELD_BOTTOM;
58 case XVMC_FRAME_PICTURE:
59 return PIPE_MPEG12_PICTURE_TYPE_FRAME;
60 default:
61 assert(0);
62 }
63
64 XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized picture type 0x%08X.\n", xvmc_pic);
65
66 return -1;
67 }
68
69 static inline void
70 MacroBlockTypeToPipeWeights(const XvMCMacroBlock *xvmc_mb, unsigned weights[2])
71 {
72 assert(xvmc_mb);
73
74 switch (xvmc_mb->macroblock_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) {
75 case XVMC_MB_TYPE_MOTION_FORWARD:
76 weights[0] = PIPE_VIDEO_MV_WEIGHT_MAX;
77 weights[1] = PIPE_VIDEO_MV_WEIGHT_MIN;
78 break;
79
80 case (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD):
81 weights[0] = PIPE_VIDEO_MV_WEIGHT_HALF;
82 weights[1] = PIPE_VIDEO_MV_WEIGHT_HALF;
83 break;
84
85 case XVMC_MB_TYPE_MOTION_BACKWARD:
86 weights[0] = PIPE_VIDEO_MV_WEIGHT_MIN;
87 weights[1] = PIPE_VIDEO_MV_WEIGHT_MAX;
88 break;
89
90 default:
91 /* workaround for xines xxmc video out plugin */
92 if (!(xvmc_mb->macroblock_type & ~XVMC_MB_TYPE_PATTERN)) {
93 weights[0] = PIPE_VIDEO_MV_WEIGHT_MAX;
94 weights[1] = PIPE_VIDEO_MV_WEIGHT_MIN;
95 } else {
96 weights[0] = PIPE_VIDEO_MV_WEIGHT_MIN;
97 weights[1] = PIPE_VIDEO_MV_WEIGHT_MIN;
98 }
99 break;
100 }
101 }
102
103 static inline struct pipe_motionvector
104 MotionVectorToPipe(const XvMCMacroBlock *xvmc_mb, unsigned vector,
105 unsigned field_select_mask, unsigned weight)
106 {
107 struct pipe_motionvector mv;
108
109 assert(xvmc_mb);
110
111 switch (xvmc_mb->motion_type) {
112 case XVMC_PREDICTION_FRAME:
113 mv.top.x = xvmc_mb->PMV[0][vector][0];
114 mv.top.y = xvmc_mb->PMV[0][vector][1];
115 mv.top.field_select = PIPE_VIDEO_FRAME;
116 mv.top.weight = weight;
117
118 mv.bottom.x = xvmc_mb->PMV[0][vector][0];
119 mv.bottom.y = xvmc_mb->PMV[0][vector][1];
120 mv.bottom.weight = weight;
121 mv.bottom.field_select = PIPE_VIDEO_FRAME;
122 break;
123
124 case XVMC_PREDICTION_FIELD:
125 mv.top.x = xvmc_mb->PMV[0][vector][0];
126 mv.top.y = xvmc_mb->PMV[0][vector][1];
127 mv.top.field_select = (xvmc_mb->motion_vertical_field_select & field_select_mask) ?
128 PIPE_VIDEO_BOTTOM_FIELD : PIPE_VIDEO_TOP_FIELD;
129 mv.top.weight = weight;
130
131 mv.bottom.x = xvmc_mb->PMV[1][vector][0];
132 mv.bottom.y = xvmc_mb->PMV[1][vector][1];
133 mv.bottom.field_select = (xvmc_mb->motion_vertical_field_select & (field_select_mask << 2)) ?
134 PIPE_VIDEO_BOTTOM_FIELD : PIPE_VIDEO_TOP_FIELD;
135 mv.bottom.weight = weight;
136 break;
137
138 default: // TODO: Support DUALPRIME and 16x8
139 break;
140 }
141
142 return mv;
143 }
144
145 static inline void
146 UploadYcbcrBlocks(XvMCSurfacePrivate *surface,
147 const XvMCMacroBlock *xvmc_mb,
148 const XvMCBlockArray *xvmc_blocks)
149 {
150 enum pipe_mpeg12_dct_intra intra;
151 enum pipe_mpeg12_dct_type coding;
152
153 unsigned tb, x, y, luma_blocks;
154 short *blocks;
155
156 assert(surface);
157 assert(xvmc_mb);
158
159 if (!xvmc_mb->coded_block_pattern)
160 return;
161
162 intra = xvmc_mb->macroblock_type & XVMC_MB_TYPE_INTRA ?
163 PIPE_MPEG12_DCT_INTRA : PIPE_MPEG12_DCT_DELTA;
164
165 coding = xvmc_mb->dct_type == XVMC_DCT_TYPE_FIELD ?
166 PIPE_MPEG12_DCT_TYPE_FIELD : PIPE_MPEG12_DCT_TYPE_FRAME;
167
168 blocks = xvmc_blocks->blocks + xvmc_mb->index * BLOCK_SIZE_SAMPLES;
169
170 for (y = 0, luma_blocks = 0; y < 2; ++y) {
171 for (x = 0; x < 2; ++x, ++tb) {
172 if (xvmc_mb->coded_block_pattern & const_empty_block_mask_420[0][y][x]) {
173
174 struct pipe_ycbcr_block *stream = surface->ycbcr[0].stream;
175 stream->x = xvmc_mb->x * 2 + x;
176 stream->y = xvmc_mb->y * 2 + y;
177 stream->intra = intra;
178 stream->coding = coding;
179
180 surface->ycbcr[0].num_blocks_added++;
181 surface->ycbcr[0].stream++;
182
183 luma_blocks++;
184 }
185 }
186 }
187
188 if (luma_blocks > 0) {
189 memcpy(surface->ycbcr[0].buffer, blocks, BLOCK_SIZE_BYTES * luma_blocks);
190 surface->ycbcr[0].buffer += BLOCK_SIZE_SAMPLES * luma_blocks;
191 blocks += BLOCK_SIZE_SAMPLES * luma_blocks;
192 }
193
194 /* TODO: Implement 422, 444 */
195 //assert(ctx->base.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420);
196
197 for (tb = 1; tb < 3; ++tb) {
198 if (xvmc_mb->coded_block_pattern & const_empty_block_mask_420[tb][0][0]) {
199
200 struct pipe_ycbcr_block *stream = surface->ycbcr[tb].stream;
201 stream->x = xvmc_mb->x;
202 stream->y = xvmc_mb->y;
203 stream->intra = intra;
204 stream->coding = PIPE_MPEG12_DCT_TYPE_FRAME;
205
206 memcpy(surface->ycbcr[tb].buffer, blocks, BLOCK_SIZE_BYTES);
207
208 surface->ycbcr[tb].num_blocks_added++;
209 surface->ycbcr[tb].stream++;
210 surface->ycbcr[tb].buffer += BLOCK_SIZE_SAMPLES;
211 blocks += BLOCK_SIZE_SAMPLES;
212 }
213 }
214
215 }
216
217 static void
218 MacroBlocksToPipe(XvMCSurfacePrivate *surface,
219 unsigned int xvmc_picture_structure,
220 const XvMCMacroBlock *xvmc_mb,
221 const XvMCBlockArray *xvmc_blocks,
222 unsigned int num_macroblocks)
223 {
224 unsigned int i, j;
225
226 assert(xvmc_mb);
227 assert(xvmc_blocks);
228 assert(num_macroblocks);
229
230 for (i = 0; i < num_macroblocks; ++i) {
231 unsigned mv_pos = xvmc_mb->x + surface->mv_stride * xvmc_mb->y;
232 unsigned mv_weights[2];
233
234 if (xvmc_mb->macroblock_type & (XVMC_MB_TYPE_PATTERN | XVMC_MB_TYPE_INTRA))
235 UploadYcbcrBlocks(surface, xvmc_mb, xvmc_blocks);
236
237 MacroBlockTypeToPipeWeights(xvmc_mb, mv_weights);
238
239 for (j = 0; j < 2; ++j) {
240 if (!surface->ref[j].mv) continue;
241
242 surface->ref[j].mv[mv_pos] = MotionVectorToPipe
243 (
244 xvmc_mb, j,
245 j ? XVMC_SELECT_FIRST_BACKWARD : XVMC_SELECT_FIRST_FORWARD,
246 mv_weights[j]
247 );
248 }
249
250 ++xvmc_mb;
251 }
252 }
253
254 static void
255 unmap_and_flush_surface(XvMCSurfacePrivate *surface)
256 {
257 struct pipe_video_buffer *ref_frames[2];
258 XvMCContextPrivate *context_priv;
259 unsigned i, num_ycbcr_blocks[3];
260
261 assert(surface);
262
263 context_priv = surface->context->privData;
264
265 for ( i = 0; i < 2; ++i ) {
266 if (surface->ref[i].surface) {
267 XvMCSurfacePrivate *ref = surface->ref[i].surface->privData;
268
269 assert(ref);
270
271 unmap_and_flush_surface(ref);
272 surface->ref[i].surface = NULL;
273 ref_frames[i] = ref->video_buffer;
274 } else {
275 ref_frames[i] = NULL;
276 }
277 }
278
279 if (surface->mapped) {
280 surface->decode_buffer->end_frame(surface->decode_buffer);
281 for (i = 0; i < 3; ++i)
282 num_ycbcr_blocks[i] = surface->ycbcr[i].num_blocks_added;
283 context_priv->decoder->flush_buffer(surface->decode_buffer,
284 num_ycbcr_blocks,
285 ref_frames,
286 surface->video_buffer);
287 surface->mapped = 0;
288 }
289 }
290
291 PUBLIC
292 Status XvMCCreateSurface(Display *dpy, XvMCContext *context, XvMCSurface *surface)
293 {
294 static const uint8_t dummy_quant[64] = {
295 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
296 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
297 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
298 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
299 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
300 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
301 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
302 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
303 };
304
305 XvMCContextPrivate *context_priv;
306 struct pipe_video_context *vpipe;
307 XvMCSurfacePrivate *surface_priv;
308
309 XVMC_MSG(XVMC_TRACE, "[XvMC] Creating surface %p.\n", surface);
310
311 assert(dpy);
312
313 if (!context)
314 return XvMCBadContext;
315 if (!surface)
316 return XvMCBadSurface;
317
318 context_priv = context->privData;
319 vpipe = context_priv->vctx->vpipe;
320
321 surface_priv = CALLOC(1, sizeof(XvMCSurfacePrivate));
322 if (!surface_priv)
323 return BadAlloc;
324
325 surface_priv->decode_buffer = context_priv->decoder->create_buffer(context_priv->decoder);
326 surface_priv->decode_buffer->set_quant_matrix(surface_priv->decode_buffer, dummy_quant, dummy_quant);
327
328 surface_priv->mv_stride = surface_priv->decode_buffer->get_mv_stream_stride(surface_priv->decode_buffer);
329 surface_priv->video_buffer = vpipe->create_buffer(vpipe, PIPE_FORMAT_NV12,
330 context_priv->decoder->chroma_format,
331 context_priv->decoder->width,
332 context_priv->decoder->height);
333 surface_priv->context = context;
334
335 surface->surface_id = XAllocID(dpy);
336 surface->context_id = context->context_id;
337 surface->surface_type_id = context->surface_type_id;
338 surface->width = context->width;
339 surface->height = context->height;
340 surface->privData = surface_priv;
341
342 SyncHandle();
343
344 XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p created.\n", surface);
345
346 return Success;
347 }
348
349 PUBLIC
350 Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int picture_structure,
351 XvMCSurface *target_surface, XvMCSurface *past_surface, XvMCSurface *future_surface,
352 unsigned int flags, unsigned int num_macroblocks, unsigned int first_macroblock,
353 XvMCMacroBlockArray *macroblocks, XvMCBlockArray *blocks
354 )
355 {
356 struct pipe_video_context *vpipe;
357 struct pipe_video_decode_buffer *t_buffer;
358
359 XvMCContextPrivate *context_priv;
360 XvMCSurfacePrivate *target_surface_priv;
361 XvMCSurfacePrivate *past_surface_priv;
362 XvMCSurfacePrivate *future_surface_priv;
363 XvMCMacroBlock *xvmc_mb;
364
365 unsigned i;
366
367 XVMC_MSG(XVMC_TRACE, "[XvMC] Rendering to surface %p, with past %p and future %p\n",
368 target_surface, past_surface, future_surface);
369
370 assert(dpy);
371
372 if (!context || !context->privData)
373 return XvMCBadContext;
374 if (!target_surface || !target_surface->privData)
375 return XvMCBadSurface;
376
377 if (picture_structure != XVMC_TOP_FIELD &&
378 picture_structure != XVMC_BOTTOM_FIELD &&
379 picture_structure != XVMC_FRAME_PICTURE)
380 return BadValue;
381 /* Bkwd pred equivalent to fwd (past && !future) */
382 if (future_surface && !past_surface)
383 return BadMatch;
384
385 assert(context->context_id == target_surface->context_id);
386 assert(!past_surface || context->context_id == past_surface->context_id);
387 assert(!future_surface || context->context_id == future_surface->context_id);
388
389 assert(macroblocks);
390 assert(blocks);
391
392 assert(macroblocks->context_id == context->context_id);
393 assert(blocks->context_id == context->context_id);
394
395 assert(flags == 0 || flags == XVMC_SECOND_FIELD);
396
397 target_surface_priv = target_surface->privData;
398 past_surface_priv = past_surface ? past_surface->privData : NULL;
399 future_surface_priv = future_surface ? future_surface->privData : NULL;
400
401 assert(target_surface_priv->context == context);
402 assert(!past_surface || past_surface_priv->context == context);
403 assert(!future_surface || future_surface_priv->context == context);
404
405 context_priv = context->privData;
406 vpipe = context_priv->vctx->vpipe;
407
408 t_buffer = target_surface_priv->decode_buffer;
409
410 // enshure that all reference frames are flushed
411 // not really nessasary, but speeds ups rendering
412 if (past_surface)
413 unmap_and_flush_surface(past_surface->privData);
414
415 if (future_surface)
416 unmap_and_flush_surface(future_surface->privData);
417
418 xvmc_mb = macroblocks->macro_blocks + first_macroblock;
419
420 /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */
421 if (target_surface_priv->mapped && (
422 target_surface_priv->ref[0].surface != past_surface ||
423 target_surface_priv->ref[1].surface != future_surface ||
424 (xvmc_mb->x == 0 && xvmc_mb->y == 0))) {
425
426 // If they change anyway we need to clear our surface
427 unmap_and_flush_surface(target_surface_priv);
428 }
429
430 if (!target_surface_priv->mapped) {
431 t_buffer->begin_frame(t_buffer);
432
433 for (i = 0; i < 3; ++i) {
434 target_surface_priv->ycbcr[i].num_blocks_added = 0;
435 target_surface_priv->ycbcr[i].stream = t_buffer->get_ycbcr_stream(t_buffer, i);
436 target_surface_priv->ycbcr[i].buffer = t_buffer->get_ycbcr_buffer(t_buffer, i);
437 }
438
439 for (i = 0; i < 2; ++i) {
440 target_surface_priv->ref[i].surface = i == 0 ? past_surface : future_surface;
441
442 if (target_surface_priv->ref[i].surface)
443 target_surface_priv->ref[i].mv = t_buffer->get_mv_stream(t_buffer, i);
444 else
445 target_surface_priv->ref[i].mv = NULL;
446 }
447
448 target_surface_priv->mapped = 1;
449 }
450
451 MacroBlocksToPipe(target_surface_priv, picture_structure, xvmc_mb, blocks, num_macroblocks);
452
453 XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for rendering.\n", target_surface);
454
455 return Success;
456 }
457
458 PUBLIC
459 Status XvMCFlushSurface(Display *dpy, XvMCSurface *surface)
460 {
461 assert(dpy);
462
463 if (!surface)
464 return XvMCBadSurface;
465
466 // don't call flush here, because this is usually
467 // called once for every slice instead of every frame
468
469 XVMC_MSG(XVMC_TRACE, "[XvMC] Flushing surface %p\n", surface);
470
471 return Success;
472 }
473
474 PUBLIC
475 Status XvMCSyncSurface(Display *dpy, XvMCSurface *surface)
476 {
477 assert(dpy);
478
479 if (!surface)
480 return XvMCBadSurface;
481
482 XVMC_MSG(XVMC_TRACE, "[XvMC] Syncing surface %p\n", surface);
483
484 return Success;
485 }
486
487 PUBLIC
488 Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable,
489 short srcx, short srcy, unsigned short srcw, unsigned short srch,
490 short destx, short desty, unsigned short destw, unsigned short desth,
491 int flags)
492 {
493 static int dump_window = -1;
494
495 struct pipe_video_context *vpipe;
496 struct pipe_video_compositor *compositor;
497
498 XvMCSurfacePrivate *surface_priv;
499 XvMCContextPrivate *context_priv;
500 XvMCSubpicturePrivate *subpicture_priv;
501 XvMCContext *context;
502 struct pipe_video_rect src_rect = {srcx, srcy, srcw, srch};
503 struct pipe_video_rect dst_rect = {destx, desty, destw, desth};
504
505 XVMC_MSG(XVMC_TRACE, "[XvMC] Displaying surface %p.\n", surface);
506
507 assert(dpy);
508
509 if (!surface || !surface->privData)
510 return XvMCBadSurface;
511
512 surface_priv = surface->privData;
513 context = surface_priv->context;
514 context_priv = context->privData;
515
516 assert(flags == XVMC_TOP_FIELD || flags == XVMC_BOTTOM_FIELD || flags == XVMC_FRAME_PICTURE);
517 assert(srcx + srcw - 1 < surface->width);
518 assert(srcy + srch - 1 < surface->height);
519
520 subpicture_priv = surface_priv->subpicture ? surface_priv->subpicture->privData : NULL;
521 vpipe = context_priv->vctx->vpipe;
522 compositor = context_priv->compositor;
523
524 if (!context_priv->drawable_surface ||
525 context_priv->dst_rect.x != dst_rect.x || context_priv->dst_rect.y != dst_rect.y ||
526 context_priv->dst_rect.w != dst_rect.w || context_priv->dst_rect.h != dst_rect.h) {
527
528 context_priv->drawable_surface = vl_drawable_surface_get(context_priv->vctx, drawable);
529 context_priv->dst_rect = dst_rect;
530 compositor->reset_dirty_area(compositor);
531 }
532
533 if (!context_priv->drawable_surface)
534 return BadDrawable;
535
536 /*
537 * Some apps (mplayer) hit these asserts because they call
538 * this function after the window has been resized by the WM
539 * but before they've handled the corresponding XEvent and
540 * know about the new dimensions. The output should be clipped
541 * until the app updates destw and desth.
542 */
543 /*
544 assert(destx + destw - 1 < drawable_surface->width);
545 assert(desty + desth - 1 < drawable_surface->height);
546 */
547
548 unmap_and_flush_surface(surface_priv);
549
550 compositor->clear_layers(compositor);
551 compositor->set_buffer_layer(compositor, 0, surface_priv->video_buffer, &src_rect, NULL);
552
553 if (subpicture_priv) {
554 XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p has subpicture %p.\n", surface, surface_priv->subpicture);
555
556 assert(subpicture_priv->surface == surface);
557
558 if (subpicture_priv->palette)
559 compositor->set_palette_layer(compositor, 1, subpicture_priv->sampler, subpicture_priv->palette,
560 &subpicture_priv->src_rect, &subpicture_priv->dst_rect);
561 else
562 compositor->set_rgba_layer(compositor, 1, subpicture_priv->sampler,
563 &subpicture_priv->src_rect, &subpicture_priv->dst_rect);
564
565 surface_priv->subpicture = NULL;
566 subpicture_priv->surface = NULL;
567 }
568
569 // Workaround for r600g, there seems to be a bug in the fence refcounting code
570 vpipe->screen->fence_reference(vpipe->screen, &surface_priv->fence, NULL);
571
572 compositor->render_picture(compositor, PictureToPipe(flags), context_priv->drawable_surface, &dst_rect, &surface_priv->fence);
573
574 XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface);
575
576 vpipe->screen->flush_frontbuffer
577 (
578 vpipe->screen,
579 context_priv->drawable_surface->texture,
580 0, 0,
581 vl_contextprivate_get(context_priv->vctx, context_priv->drawable_surface)
582 );
583
584 if(dump_window == -1) {
585 dump_window = debug_get_num_option("XVMC_DUMP", 0);
586 }
587
588 if(dump_window) {
589 static unsigned int framenum = 0;
590 char cmd[256];
591
592 sprintf(cmd, "xwd -id %d -out xvmc_frame_%08d.xwd", (int)drawable, ++framenum);
593 if (system(cmd) != 0)
594 XVMC_MSG(XVMC_ERR, "[XvMC] Dumping surface %p failed.\n", surface);
595 }
596
597 XVMC_MSG(XVMC_TRACE, "[XvMC] Pushed surface %p to front buffer.\n", surface);
598
599 return Success;
600 }
601
602 PUBLIC
603 Status XvMCGetSurfaceStatus(Display *dpy, XvMCSurface *surface, int *status)
604 {
605 struct pipe_video_context *vpipe;
606 XvMCSurfacePrivate *surface_priv;
607 XvMCContextPrivate *context_priv;
608
609 assert(dpy);
610
611 if (!surface)
612 return XvMCBadSurface;
613
614 assert(status);
615
616 surface_priv = surface->privData;
617 context_priv = surface_priv->context->privData;
618 vpipe = context_priv->vctx->vpipe;
619
620 *status = 0;
621
622 if (surface_priv->fence)
623 if (!vpipe->screen->fence_signalled(vpipe->screen, surface_priv->fence))
624 *status |= XVMC_RENDERING;
625
626 return Success;
627 }
628
629 PUBLIC
630 Status XvMCDestroySurface(Display *dpy, XvMCSurface *surface)
631 {
632 XvMCSurfacePrivate *surface_priv;
633
634 XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying surface %p.\n", surface);
635
636 assert(dpy);
637
638 if (!surface || !surface->privData)
639 return XvMCBadSurface;
640
641 surface_priv = surface->privData;
642 surface_priv->decode_buffer->destroy(surface_priv->decode_buffer);
643 surface_priv->video_buffer->destroy(surface_priv->video_buffer);
644 FREE(surface_priv);
645 surface->privData = NULL;
646
647 XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p destroyed.\n", surface);
648
649 return Success;
650 }
651
652 PUBLIC
653 Status XvMCHideSurface(Display *dpy, XvMCSurface *surface)
654 {
655 assert(dpy);
656
657 if (!surface || !surface->privData)
658 return XvMCBadSurface;
659
660 /* No op, only for overlaid rendering */
661
662 return Success;
663 }