1 /**************************************************************************
3 * Copyright 2009 Younes Manton.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
31 #include <X11/Xlibint.h>
33 #include <pipe/p_video_decoder.h>
34 #include <pipe/p_video_state.h>
35 #include <pipe/p_state.h>
37 #include <util/u_inlines.h>
38 #include <util/u_memory.h>
39 #include <util/u_math.h>
41 #include <vl_winsys.h>
43 #include "xvmc_private.h"
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 } }
51 static enum pipe_mpeg12_picture_type
PictureToPipe(int xvmc_pic
)
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
;
64 XVMC_MSG(XVMC_ERR
, "[XvMC] Unrecognized picture type 0x%08X.\n", xvmc_pic
);
70 MacroBlockTypeToPipeWeights(const XvMCMacroBlock
*xvmc_mb
, unsigned weights
[2])
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
;
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
;
85 case XVMC_MB_TYPE_MOTION_BACKWARD
:
86 weights
[0] = PIPE_VIDEO_MV_WEIGHT_MIN
;
87 weights
[1] = PIPE_VIDEO_MV_WEIGHT_MAX
;
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
;
96 weights
[0] = PIPE_VIDEO_MV_WEIGHT_MIN
;
97 weights
[1] = PIPE_VIDEO_MV_WEIGHT_MIN
;
103 static inline struct pipe_motionvector
104 MotionVectorToPipe(const XvMCMacroBlock
*xvmc_mb
, unsigned vector
,
105 unsigned field_select_mask
, unsigned weight
)
107 struct pipe_motionvector mv
;
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
;
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
;
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
;
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
;
138 default: // TODO: Support DUALPRIME and 16x8
146 UploadYcbcrBlocks(XvMCSurfacePrivate
*surface
,
147 const XvMCMacroBlock
*xvmc_mb
,
148 const XvMCBlockArray
*xvmc_blocks
)
150 enum pipe_mpeg12_dct_intra intra
;
151 enum pipe_mpeg12_dct_type coding
;
153 unsigned tb
, x
, y
, luma_blocks
;
159 if (!xvmc_mb
->coded_block_pattern
)
162 intra
= xvmc_mb
->macroblock_type
& XVMC_MB_TYPE_INTRA
?
163 PIPE_MPEG12_DCT_INTRA
: PIPE_MPEG12_DCT_DELTA
;
165 coding
= xvmc_mb
->dct_type
== XVMC_DCT_TYPE_FIELD
?
166 PIPE_MPEG12_DCT_TYPE_FIELD
: PIPE_MPEG12_DCT_TYPE_FRAME
;
168 blocks
= xvmc_blocks
->blocks
+ xvmc_mb
->index
* BLOCK_SIZE_SAMPLES
;
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
]) {
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
;
180 surface
->ycbcr
[0].num_blocks_added
++;
181 surface
->ycbcr
[0].stream
++;
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
;
194 /* TODO: Implement 422, 444 */
195 //assert(ctx->base.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420);
197 for (tb
= 1; tb
< 3; ++tb
) {
198 if (xvmc_mb
->coded_block_pattern
& const_empty_block_mask_420
[tb
][0][0]) {
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
;
206 memcpy(surface
->ycbcr
[tb
].buffer
, blocks
, BLOCK_SIZE_BYTES
);
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
;
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
)
228 assert(num_macroblocks
);
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];
234 if (xvmc_mb
->macroblock_type
& (XVMC_MB_TYPE_PATTERN
| XVMC_MB_TYPE_INTRA
))
235 UploadYcbcrBlocks(surface
, xvmc_mb
, xvmc_blocks
);
237 MacroBlockTypeToPipeWeights(xvmc_mb
, mv_weights
);
239 for (j
= 0; j
< 2; ++j
) {
240 if (!surface
->ref
[j
].mv
) continue;
242 surface
->ref
[j
].mv
[mv_pos
] = MotionVectorToPipe
245 j
? XVMC_SELECT_FIRST_BACKWARD
: XVMC_SELECT_FIRST_FORWARD
,
255 unmap_and_flush_surface(XvMCSurfacePrivate
*surface
)
257 struct pipe_video_buffer
*ref_frames
[2];
258 XvMCContextPrivate
*context_priv
;
259 unsigned i
, num_ycbcr_blocks
[3];
263 context_priv
= surface
->context
->privData
;
265 for ( i
= 0; i
< 2; ++i
) {
266 if (surface
->ref
[i
].surface
) {
267 XvMCSurfacePrivate
*ref
= surface
->ref
[i
].surface
->privData
;
271 unmap_and_flush_surface(ref
);
272 surface
->ref
[i
].surface
= NULL
;
273 ref_frames
[i
] = ref
->video_buffer
;
275 ref_frames
[i
] = NULL
;
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
,
286 surface
->video_buffer
);
292 Status
XvMCCreateSurface(Display
*dpy
, XvMCContext
*context
, XvMCSurface
*surface
)
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
305 XvMCContextPrivate
*context_priv
;
306 struct pipe_context
*pipe
;
307 XvMCSurfacePrivate
*surface_priv
;
309 XVMC_MSG(XVMC_TRACE
, "[XvMC] Creating surface %p.\n", surface
);
314 return XvMCBadContext
;
316 return XvMCBadSurface
;
318 context_priv
= context
->privData
;
319 pipe
= context_priv
->vctx
->pipe
;
321 surface_priv
= CALLOC(1, sizeof(XvMCSurfacePrivate
));
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
);
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
331 pipe
, PIPE_FORMAT_NV12
, context_priv
->decoder
->chroma_format
,
332 context_priv
->decoder
->width
, context_priv
->decoder
->height
335 surface_priv
->context
= context
;
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
;
346 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p created.\n", surface
);
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
358 struct pipe_video_decode_buffer
*t_buffer
;
360 XvMCSurfacePrivate
*target_surface_priv
;
361 XvMCSurfacePrivate
*past_surface_priv
;
362 XvMCSurfacePrivate
*future_surface_priv
;
363 XvMCMacroBlock
*xvmc_mb
;
367 XVMC_MSG(XVMC_TRACE
, "[XvMC] Rendering to surface %p, with past %p and future %p\n",
368 target_surface
, past_surface
, future_surface
);
372 if (!context
|| !context
->privData
)
373 return XvMCBadContext
;
374 if (!target_surface
|| !target_surface
->privData
)
375 return XvMCBadSurface
;
377 if (picture_structure
!= XVMC_TOP_FIELD
&&
378 picture_structure
!= XVMC_BOTTOM_FIELD
&&
379 picture_structure
!= XVMC_FRAME_PICTURE
)
381 /* Bkwd pred equivalent to fwd (past && !future) */
382 if (future_surface
&& !past_surface
)
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
);
392 assert(macroblocks
->context_id
== context
->context_id
);
393 assert(blocks
->context_id
== context
->context_id
);
395 assert(flags
== 0 || flags
== XVMC_SECOND_FIELD
);
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
;
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
);
405 t_buffer
= target_surface_priv
->decode_buffer
;
407 // enshure that all reference frames are flushed
408 // not really nessasary, but speeds ups rendering
410 unmap_and_flush_surface(past_surface
->privData
);
413 unmap_and_flush_surface(future_surface
->privData
);
415 xvmc_mb
= macroblocks
->macro_blocks
+ first_macroblock
;
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))) {
423 // If they change anyway we need to clear our surface
424 unmap_and_flush_surface(target_surface_priv
);
427 if (!target_surface_priv
->mapped
) {
428 t_buffer
->begin_frame(t_buffer
);
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
);
436 for (i
= 0; i
< 2; ++i
) {
437 target_surface_priv
->ref
[i
].surface
= i
== 0 ? past_surface
: future_surface
;
439 if (target_surface_priv
->ref
[i
].surface
)
440 target_surface_priv
->ref
[i
].mv
= t_buffer
->get_mv_stream(t_buffer
, i
);
442 target_surface_priv
->ref
[i
].mv
= NULL
;
445 target_surface_priv
->mapped
= 1;
448 MacroBlocksToPipe(target_surface_priv
, picture_structure
, xvmc_mb
, blocks
, num_macroblocks
);
450 XVMC_MSG(XVMC_TRACE
, "[XvMC] Submitted surface %p for rendering.\n", target_surface
);
456 Status
XvMCFlushSurface(Display
*dpy
, XvMCSurface
*surface
)
461 return XvMCBadSurface
;
463 // don't call flush here, because this is usually
464 // called once for every slice instead of every frame
466 XVMC_MSG(XVMC_TRACE
, "[XvMC] Flushing surface %p\n", surface
);
472 Status
XvMCSyncSurface(Display
*dpy
, XvMCSurface
*surface
)
477 return XvMCBadSurface
;
479 XVMC_MSG(XVMC_TRACE
, "[XvMC] Syncing surface %p\n", surface
);
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
,
490 static int dump_window
= -1;
492 struct pipe_context
*pipe
;
493 struct vl_compositor
*compositor
;
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
};
502 XVMC_MSG(XVMC_TRACE
, "[XvMC] Displaying surface %p.\n", surface
);
506 if (!surface
|| !surface
->privData
)
507 return XvMCBadSurface
;
509 surface_priv
= surface
->privData
;
510 context
= surface_priv
->context
;
511 context_priv
= context
->privData
;
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
);
517 subpicture_priv
= surface_priv
->subpicture
? surface_priv
->subpicture
->privData
: NULL
;
518 pipe
= context_priv
->vctx
->pipe
;
519 compositor
= &context_priv
->compositor
;
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
) {
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
);
531 if (!context_priv
->drawable_surface
)
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.
542 assert(destx + destw - 1 < drawable_surface->width);
543 assert(desty + desth - 1 < drawable_surface->height);
546 unmap_and_flush_surface(surface_priv
);
548 vl_compositor_clear_layers(compositor
);
549 vl_compositor_set_buffer_layer(compositor
, 0, surface_priv
->video_buffer
, &src_rect
, NULL
);
551 if (subpicture_priv
) {
552 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p has subpicture %p.\n", surface
, surface_priv
->subpicture
);
554 assert(subpicture_priv
->surface
== surface
);
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
);
560 vl_compositor_set_rgba_layer(compositor
, 1, subpicture_priv
->sampler
,
561 &subpicture_priv
->src_rect
, &subpicture_priv
->dst_rect
);
563 surface_priv
->subpicture
= NULL
;
564 subpicture_priv
->surface
= NULL
;
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
);
570 vl_compositor_render(compositor
, PictureToPipe(flags
), context_priv
->drawable_surface
, &dst_rect
, NULL
);
572 pipe
->flush(pipe
, &surface_priv
->fence
);
574 XVMC_MSG(XVMC_TRACE
, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface
);
576 pipe
->screen
->flush_frontbuffer
579 context_priv
->drawable_surface
->texture
,
581 vl_contextprivate_get(context_priv
->vctx
, context_priv
->drawable_surface
)
584 if(dump_window
== -1) {
585 dump_window
= debug_get_num_option("XVMC_DUMP", 0);
589 static unsigned int framenum
= 0;
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
);
597 XVMC_MSG(XVMC_TRACE
, "[XvMC] Pushed surface %p to front buffer.\n", surface
);
603 Status
XvMCGetSurfaceStatus(Display
*dpy
, XvMCSurface
*surface
, int *status
)
605 struct pipe_context
*pipe
;
606 XvMCSurfacePrivate
*surface_priv
;
607 XvMCContextPrivate
*context_priv
;
612 return XvMCBadSurface
;
616 surface_priv
= surface
->privData
;
617 context_priv
= surface_priv
->context
->privData
;
618 pipe
= context_priv
->vctx
->pipe
;
622 if (surface_priv
->fence
)
623 if (!pipe
->screen
->fence_signalled(pipe
->screen
, surface_priv
->fence
))
624 *status
|= XVMC_RENDERING
;
630 Status
XvMCDestroySurface(Display
*dpy
, XvMCSurface
*surface
)
632 XvMCSurfacePrivate
*surface_priv
;
634 XVMC_MSG(XVMC_TRACE
, "[XvMC] Destroying surface %p.\n", surface
);
638 if (!surface
|| !surface
->privData
)
639 return XvMCBadSurface
;
641 surface_priv
= surface
->privData
;
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
);
648 surface
->privData
= NULL
;
650 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p destroyed.\n", surface
);
656 Status
XvMCHideSurface(Display
*dpy
, XvMCSurface
*surface
)
660 if (!surface
|| !surface
->privData
)
661 return XvMCBadSurface
;
663 /* No op, only for overlaid rendering */