Merge branch 'gallium-polygon-stipple'
[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_decoder.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_context *pipe;
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 pipe = context_priv->vctx->pipe;
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 = pipe->create_video_buffer
330 (
331 pipe, PIPE_FORMAT_NV12, context_priv->decoder->chroma_format,
332 context_priv->decoder->width, context_priv->decoder->height
333 );
334
335 surface_priv->context = context;
336
337 surface->surface_id = XAllocID(dpy);
338 surface->context_id = context->context_id;
339 surface->surface_type_id = context->surface_type_id;
340 surface->width = context->width;
341 surface->height = context->height;
342 surface->privData = surface_priv;
343
344 SyncHandle();
345
346 XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p created.\n", surface);
347
348 return Success;
349 }
350
351 PUBLIC
352 Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int picture_structure,
353 XvMCSurface *target_surface, XvMCSurface *past_surface, XvMCSurface *future_surface,
354 unsigned int flags, unsigned int num_macroblocks, unsigned int first_macroblock,
355 XvMCMacroBlockArray *macroblocks, XvMCBlockArray *blocks
356 )
357 {
358 struct pipe_video_decode_buffer *t_buffer;
359
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 t_buffer = target_surface_priv->decode_buffer;
406
407 // enshure that all reference frames are flushed
408 // not really nessasary, but speeds ups rendering
409 if (past_surface)
410 unmap_and_flush_surface(past_surface->privData);
411
412 if (future_surface)
413 unmap_and_flush_surface(future_surface->privData);
414
415 xvmc_mb = macroblocks->macro_blocks + first_macroblock;
416
417 /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */
418 if (target_surface_priv->mapped && (
419 target_surface_priv->ref[0].surface != past_surface ||
420 target_surface_priv->ref[1].surface != future_surface ||
421 (xvmc_mb->x == 0 && xvmc_mb->y == 0))) {
422
423 // If they change anyway we need to clear our surface
424 unmap_and_flush_surface(target_surface_priv);
425 }
426
427 if (!target_surface_priv->mapped) {
428 t_buffer->begin_frame(t_buffer);
429
430 for (i = 0; i < 3; ++i) {
431 target_surface_priv->ycbcr[i].num_blocks_added = 0;
432 target_surface_priv->ycbcr[i].stream = t_buffer->get_ycbcr_stream(t_buffer, i);
433 target_surface_priv->ycbcr[i].buffer = t_buffer->get_ycbcr_buffer(t_buffer, i);
434 }
435
436 for (i = 0; i < 2; ++i) {
437 target_surface_priv->ref[i].surface = i == 0 ? past_surface : future_surface;
438
439 if (target_surface_priv->ref[i].surface)
440 target_surface_priv->ref[i].mv = t_buffer->get_mv_stream(t_buffer, i);
441 else
442 target_surface_priv->ref[i].mv = NULL;
443 }
444
445 target_surface_priv->mapped = 1;
446 }
447
448 MacroBlocksToPipe(target_surface_priv, picture_structure, xvmc_mb, blocks, num_macroblocks);
449
450 XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for rendering.\n", target_surface);
451
452 return Success;
453 }
454
455 PUBLIC
456 Status XvMCFlushSurface(Display *dpy, XvMCSurface *surface)
457 {
458 assert(dpy);
459
460 if (!surface)
461 return XvMCBadSurface;
462
463 // don't call flush here, because this is usually
464 // called once for every slice instead of every frame
465
466 XVMC_MSG(XVMC_TRACE, "[XvMC] Flushing surface %p\n", surface);
467
468 return Success;
469 }
470
471 PUBLIC
472 Status XvMCSyncSurface(Display *dpy, XvMCSurface *surface)
473 {
474 assert(dpy);
475
476 if (!surface)
477 return XvMCBadSurface;
478
479 XVMC_MSG(XVMC_TRACE, "[XvMC] Syncing surface %p\n", surface);
480
481 return Success;
482 }
483
484 PUBLIC
485 Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable,
486 short srcx, short srcy, unsigned short srcw, unsigned short srch,
487 short destx, short desty, unsigned short destw, unsigned short desth,
488 int flags)
489 {
490 static int dump_window = -1;
491
492 struct pipe_context *pipe;
493 struct vl_compositor *compositor;
494
495 XvMCSurfacePrivate *surface_priv;
496 XvMCContextPrivate *context_priv;
497 XvMCSubpicturePrivate *subpicture_priv;
498 XvMCContext *context;
499 struct pipe_video_rect src_rect = {srcx, srcy, srcw, srch};
500 struct pipe_video_rect dst_rect = {destx, desty, destw, desth};
501
502 XVMC_MSG(XVMC_TRACE, "[XvMC] Displaying surface %p.\n", surface);
503
504 assert(dpy);
505
506 if (!surface || !surface->privData)
507 return XvMCBadSurface;
508
509 surface_priv = surface->privData;
510 context = surface_priv->context;
511 context_priv = context->privData;
512
513 assert(flags == XVMC_TOP_FIELD || flags == XVMC_BOTTOM_FIELD || flags == XVMC_FRAME_PICTURE);
514 assert(srcx + srcw - 1 < surface->width);
515 assert(srcy + srch - 1 < surface->height);
516
517 subpicture_priv = surface_priv->subpicture ? surface_priv->subpicture->privData : NULL;
518 pipe = context_priv->vctx->pipe;
519 compositor = &context_priv->compositor;
520
521 if (!context_priv->drawable_surface ||
522 context_priv->dst_rect.x != dst_rect.x || context_priv->dst_rect.y != dst_rect.y ||
523 context_priv->dst_rect.w != dst_rect.w || context_priv->dst_rect.h != dst_rect.h) {
524
525 pipe_surface_reference(&context_priv->drawable_surface, NULL);
526 context_priv->drawable_surface = vl_drawable_surface_get(context_priv->vctx, drawable);
527 context_priv->dst_rect = dst_rect;
528 vl_compositor_reset_dirty_area(compositor);
529 }
530
531 if (!context_priv->drawable_surface)
532 return BadDrawable;
533
534 /*
535 * Some apps (mplayer) hit these asserts because they call
536 * this function after the window has been resized by the WM
537 * but before they've handled the corresponding XEvent and
538 * know about the new dimensions. The output should be clipped
539 * until the app updates destw and desth.
540 */
541 /*
542 assert(destx + destw - 1 < drawable_surface->width);
543 assert(desty + desth - 1 < drawable_surface->height);
544 */
545
546 unmap_and_flush_surface(surface_priv);
547
548 vl_compositor_clear_layers(compositor);
549 vl_compositor_set_buffer_layer(compositor, 0, surface_priv->video_buffer, &src_rect, NULL);
550
551 if (subpicture_priv) {
552 XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p has subpicture %p.\n", surface, surface_priv->subpicture);
553
554 assert(subpicture_priv->surface == surface);
555
556 if (subpicture_priv->palette)
557 vl_compositor_set_palette_layer(compositor, 1, subpicture_priv->sampler, subpicture_priv->palette,
558 &subpicture_priv->src_rect, &subpicture_priv->dst_rect);
559 else
560 vl_compositor_set_rgba_layer(compositor, 1, subpicture_priv->sampler,
561 &subpicture_priv->src_rect, &subpicture_priv->dst_rect);
562
563 surface_priv->subpicture = NULL;
564 subpicture_priv->surface = NULL;
565 }
566
567 // Workaround for r600g, there seems to be a bug in the fence refcounting code
568 pipe->screen->fence_reference(pipe->screen, &surface_priv->fence, NULL);
569
570 vl_compositor_render(compositor, PictureToPipe(flags), context_priv->drawable_surface, &dst_rect, NULL);
571
572 pipe->flush(pipe, &surface_priv->fence);
573
574 XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface);
575
576 pipe->screen->flush_frontbuffer
577 (
578 pipe->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_context *pipe;
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 pipe = context_priv->vctx->pipe;
619
620 *status = 0;
621
622 if (surface_priv->fence)
623 if (!pipe->screen->fence_signalled(pipe->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
643 if (surface_priv->mapped)
644 surface_priv->decode_buffer->end_frame(surface_priv->decode_buffer);
645 surface_priv->decode_buffer->destroy(surface_priv->decode_buffer);
646 surface_priv->video_buffer->destroy(surface_priv->video_buffer);
647 FREE(surface_priv);
648 surface->privData = NULL;
649
650 XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p destroyed.\n", surface);
651
652 return Success;
653 }
654
655 PUBLIC
656 Status XvMCHideSurface(Display *dpy, XvMCSurface *surface)
657 {
658 assert(dpy);
659
660 if (!surface || !surface->privData)
661 return XvMCBadSurface;
662
663 /* No op, only for overlaid rendering */
664
665 return Success;
666 }