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_codec.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"
40 #include "vl/vl_winsys.h"
42 #include "xvmc_private.h"
45 MacroBlocksToPipe(XvMCContextPrivate
*context
,
46 XvMCSurfacePrivate
*surface
,
47 unsigned int xvmc_picture_structure
,
48 const XvMCMacroBlock
*xvmc_mb
,
49 const XvMCBlockArray
*xvmc_blocks
,
50 struct pipe_mpeg12_macroblock
*mb
,
51 unsigned int num_macroblocks
)
57 assert(num_macroblocks
);
59 for (; num_macroblocks
> 0; --num_macroblocks
) {
60 mb
->base
.codec
= PIPE_VIDEO_FORMAT_MPEG12
;
63 mb
->macroblock_type
= xvmc_mb
->macroblock_type
;
65 switch (xvmc_picture_structure
) {
66 case XVMC_FRAME_PICTURE
:
67 mb
->macroblock_modes
.bits
.frame_motion_type
= xvmc_mb
->motion_type
;
68 mb
->macroblock_modes
.bits
.field_motion_type
= 0;
72 case XVMC_BOTTOM_FIELD
:
73 mb
->macroblock_modes
.bits
.frame_motion_type
= 0;
74 mb
->macroblock_modes
.bits
.field_motion_type
= xvmc_mb
->motion_type
;
81 mb
->macroblock_modes
.bits
.dct_type
= xvmc_mb
->dct_type
;
82 mb
->motion_vertical_field_select
= xvmc_mb
->motion_vertical_field_select
;
84 for (i
= 0; i
< 2; ++i
)
85 for (j
= 0; j
< 2; ++j
)
86 for (k
= 0; k
< 2; ++k
)
87 mb
->PMV
[i
][j
][k
] = xvmc_mb
->PMV
[i
][j
][k
];
89 mb
->coded_block_pattern
= xvmc_mb
->coded_block_pattern
;
90 mb
->blocks
= xvmc_blocks
->blocks
+ xvmc_mb
->index
* BLOCK_SIZE_SAMPLES
;
91 mb
->num_skipped_macroblocks
= 0;
99 GetPictureDescription(XvMCSurfacePrivate
*surface
, struct pipe_mpeg12_picture_desc
*desc
)
101 unsigned i
, num_refs
= 0;
103 assert(surface
&& desc
);
105 memset(desc
, 0, sizeof(*desc
));
106 desc
->base
.profile
= PIPE_VIDEO_PROFILE_MPEG1
;
107 desc
->picture_structure
= surface
->picture_structure
;
108 for (i
= 0; i
< 2; ++i
) {
109 if (surface
->ref
[i
]) {
110 XvMCSurfacePrivate
*ref
= surface
->ref
[i
]->privData
;
113 desc
->ref
[num_refs
++] = ref
->video_buffer
;
119 RecursiveEndFrame(XvMCSurfacePrivate
*surface
)
121 XvMCContextPrivate
*context_priv
;
126 context_priv
= surface
->context
->privData
;
128 for ( i
= 0; i
< 2; ++i
) {
129 if (surface
->ref
[i
]) {
130 XvMCSurface
*ref
= surface
->ref
[i
];
134 surface
->ref
[i
] = NULL
;
135 RecursiveEndFrame(ref
->privData
);
136 surface
->ref
[i
] = ref
;
140 if (surface
->picture_structure
) {
141 struct pipe_mpeg12_picture_desc desc
;
142 GetPictureDescription(surface
, &desc
);
143 surface
->picture_structure
= 0;
145 for (i
= 0; i
< 2; ++i
)
146 surface
->ref
[i
] = NULL
;
148 context_priv
->decoder
->end_frame(context_priv
->decoder
, surface
->video_buffer
, &desc
.base
);
153 Status
XvMCCreateSurface(Display
*dpy
, XvMCContext
*context
, XvMCSurface
*surface
)
155 XvMCContextPrivate
*context_priv
;
156 struct pipe_context
*pipe
;
157 XvMCSurfacePrivate
*surface_priv
;
158 struct pipe_video_buffer tmpl
;
160 XVMC_MSG(XVMC_TRACE
, "[XvMC] Creating surface %p.\n", surface
);
165 return XvMCBadContext
;
167 return XvMCBadSurface
;
169 context_priv
= context
->privData
;
170 pipe
= context_priv
->pipe
;
172 surface_priv
= CALLOC(1, sizeof(XvMCSurfacePrivate
));
176 memset(&tmpl
, 0, sizeof(tmpl
));
177 tmpl
.buffer_format
= pipe
->screen
->get_video_param
180 context_priv
->decoder
->profile
,
181 context_priv
->decoder
->entrypoint
,
182 PIPE_VIDEO_CAP_PREFERED_FORMAT
184 tmpl
.chroma_format
= context_priv
->decoder
->chroma_format
;
185 tmpl
.width
= context_priv
->decoder
->width
;
186 tmpl
.height
= context_priv
->decoder
->height
;
187 tmpl
.interlaced
= pipe
->screen
->get_video_param
190 context_priv
->decoder
->profile
,
191 context_priv
->decoder
->entrypoint
,
192 PIPE_VIDEO_CAP_PREFERS_INTERLACED
195 surface_priv
->video_buffer
= pipe
->create_video_buffer(pipe
, &tmpl
);
196 surface_priv
->context
= context
;
198 surface
->surface_id
= XAllocID(dpy
);
199 surface
->context_id
= context
->context_id
;
200 surface
->surface_type_id
= context
->surface_type_id
;
201 surface
->width
= context
->width
;
202 surface
->height
= context
->height
;
203 surface
->privData
= surface_priv
;
207 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p created.\n", surface
);
213 Status
XvMCRenderSurface(Display
*dpy
, XvMCContext
*context
, unsigned int picture_structure
,
214 XvMCSurface
*target_surface
, XvMCSurface
*past_surface
, XvMCSurface
*future_surface
,
215 unsigned int flags
, unsigned int num_macroblocks
, unsigned int first_macroblock
,
216 XvMCMacroBlockArray
*macroblocks
, XvMCBlockArray
*blocks
219 struct pipe_mpeg12_macroblock mb
[num_macroblocks
];
220 struct pipe_video_codec
*decoder
;
221 struct pipe_mpeg12_picture_desc desc
;
223 XvMCContextPrivate
*context_priv
;
224 XvMCSurfacePrivate
*target_surface_priv
;
225 XvMCSurfacePrivate
*past_surface_priv
;
226 XvMCSurfacePrivate
*future_surface_priv
;
227 XvMCMacroBlock
*xvmc_mb
;
229 XVMC_MSG(XVMC_TRACE
, "[XvMC] Rendering to surface %p, with past %p and future %p\n",
230 target_surface
, past_surface
, future_surface
);
234 if (!context
|| !context
->privData
)
235 return XvMCBadContext
;
236 if (!target_surface
|| !target_surface
->privData
)
237 return XvMCBadSurface
;
239 if (picture_structure
!= XVMC_TOP_FIELD
&&
240 picture_structure
!= XVMC_BOTTOM_FIELD
&&
241 picture_structure
!= XVMC_FRAME_PICTURE
)
243 /* Bkwd pred equivalent to fwd (past && !future) */
244 if (future_surface
&& !past_surface
)
247 assert(context
->context_id
== target_surface
->context_id
);
248 assert(!past_surface
|| context
->context_id
== past_surface
->context_id
);
249 assert(!future_surface
|| context
->context_id
== future_surface
->context_id
);
254 assert(macroblocks
->context_id
== context
->context_id
);
255 assert(blocks
->context_id
== context
->context_id
);
257 assert(flags
== 0 || flags
== XVMC_SECOND_FIELD
);
259 context_priv
= context
->privData
;
260 decoder
= context_priv
->decoder
;
262 target_surface_priv
= target_surface
->privData
;
263 past_surface_priv
= past_surface
? past_surface
->privData
: NULL
;
264 future_surface_priv
= future_surface
? future_surface
->privData
: NULL
;
266 assert(target_surface_priv
->context
== context
);
267 assert(!past_surface
|| past_surface_priv
->context
== context
);
268 assert(!future_surface
|| future_surface_priv
->context
== context
);
270 // call end frame on all referenced frames
272 RecursiveEndFrame(past_surface
->privData
);
275 RecursiveEndFrame(future_surface
->privData
);
277 xvmc_mb
= macroblocks
->macro_blocks
+ first_macroblock
;
279 /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */
280 if (target_surface_priv
->picture_structure
> 0 && (
281 target_surface_priv
->picture_structure
!= picture_structure
||
282 target_surface_priv
->ref
[0] != past_surface
||
283 target_surface_priv
->ref
[1] != future_surface
||
284 (xvmc_mb
->x
== 0 && xvmc_mb
->y
== 0))) {
286 // If they change anyway we must assume that the current frame is ended
287 RecursiveEndFrame(target_surface_priv
);
290 target_surface_priv
->ref
[0] = past_surface
;
291 target_surface_priv
->ref
[1] = future_surface
;
293 if (target_surface_priv
->picture_structure
)
294 GetPictureDescription(target_surface_priv
, &desc
);
296 target_surface_priv
->picture_structure
= picture_structure
;
297 GetPictureDescription(target_surface_priv
, &desc
);
298 decoder
->begin_frame(decoder
, target_surface_priv
->video_buffer
, &desc
.base
);
301 MacroBlocksToPipe(context_priv
, target_surface_priv
, picture_structure
,
302 xvmc_mb
, blocks
, mb
, num_macroblocks
);
304 context_priv
->decoder
->decode_macroblock(context_priv
->decoder
,
305 target_surface_priv
->video_buffer
,
307 &mb
[0].base
, num_macroblocks
);
309 XVMC_MSG(XVMC_TRACE
, "[XvMC] Submitted surface %p for rendering.\n", target_surface
);
315 Status
XvMCFlushSurface(Display
*dpy
, XvMCSurface
*surface
)
320 return XvMCBadSurface
;
322 // don't call flush here, because this is usually
323 // called once for every slice instead of every frame
325 XVMC_MSG(XVMC_TRACE
, "[XvMC] Flushing surface %p\n", surface
);
331 Status
XvMCSyncSurface(Display
*dpy
, XvMCSurface
*surface
)
336 return XvMCBadSurface
;
338 XVMC_MSG(XVMC_TRACE
, "[XvMC] Syncing surface %p\n", surface
);
344 Status
XvMCPutSurface(Display
*dpy
, XvMCSurface
*surface
, Drawable drawable
,
345 short srcx
, short srcy
, unsigned short srcw
, unsigned short srch
,
346 short destx
, short desty
, unsigned short destw
, unsigned short desth
,
349 static int dump_window
= -1;
351 struct pipe_context
*pipe
;
352 struct vl_compositor
*compositor
;
353 struct vl_compositor_state
*cstate
;
355 XvMCSurfacePrivate
*surface_priv
;
356 XvMCContextPrivate
*context_priv
;
357 XvMCSubpicturePrivate
*subpicture_priv
;
358 XvMCContext
*context
;
359 struct u_rect src_rect
= {srcx
, srcx
+ srcw
, srcy
, srcy
+ srch
};
360 struct u_rect dst_rect
= {destx
, destx
+ destw
, desty
, desty
+ desth
};
362 struct pipe_resource
*tex
;
363 struct pipe_surface surf_templ
, *surf
;
364 struct u_rect
*dirty_area
;
366 XVMC_MSG(XVMC_TRACE
, "[XvMC] Displaying surface %p.\n", surface
);
370 if (!surface
|| !surface
->privData
)
371 return XvMCBadSurface
;
373 surface_priv
= surface
->privData
;
374 context
= surface_priv
->context
;
375 context_priv
= context
->privData
;
377 assert(flags
== XVMC_TOP_FIELD
|| flags
== XVMC_BOTTOM_FIELD
|| flags
== XVMC_FRAME_PICTURE
);
378 assert(srcx
+ srcw
- 1 < surface
->width
);
379 assert(srcy
+ srch
- 1 < surface
->height
);
381 subpicture_priv
= surface_priv
->subpicture
? surface_priv
->subpicture
->privData
: NULL
;
382 pipe
= context_priv
->pipe
;
383 compositor
= &context_priv
->compositor
;
384 cstate
= &context_priv
->cstate
;
386 tex
= vl_screen_texture_from_drawable(context_priv
->vscreen
, drawable
);
387 dirty_area
= vl_screen_get_dirty_area(context_priv
->vscreen
);
389 memset(&surf_templ
, 0, sizeof(surf_templ
));
390 surf_templ
.format
= tex
->format
;
391 surf
= pipe
->create_surface(pipe
, tex
, &surf_templ
);
397 * Some apps (mplayer) hit these asserts because they call
398 * this function after the window has been resized by the WM
399 * but before they've handled the corresponding XEvent and
400 * know about the new dimensions. The output should be clipped
401 * until the app updates destw and desth.
404 assert(destx + destw - 1 < drawable_surface->width);
405 assert(desty + desth - 1 < drawable_surface->height);
408 RecursiveEndFrame(surface_priv
);
410 context_priv
->decoder
->flush(context_priv
->decoder
);
412 vl_compositor_clear_layers(cstate
);
413 vl_compositor_set_buffer_layer(cstate
, compositor
, 0, surface_priv
->video_buffer
,
414 &src_rect
, NULL
, VL_COMPOSITOR_WEAVE
);
416 if (subpicture_priv
) {
417 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p has subpicture %p.\n", surface
, surface_priv
->subpicture
);
419 assert(subpicture_priv
->surface
== surface
);
421 if (subpicture_priv
->palette
)
422 vl_compositor_set_palette_layer(cstate
, compositor
, 1, subpicture_priv
->sampler
, subpicture_priv
->palette
,
423 &subpicture_priv
->src_rect
, &subpicture_priv
->dst_rect
, true);
425 vl_compositor_set_rgba_layer(cstate
, compositor
, 1, subpicture_priv
->sampler
,
426 &subpicture_priv
->src_rect
, &subpicture_priv
->dst_rect
, NULL
);
428 surface_priv
->subpicture
= NULL
;
429 subpicture_priv
->surface
= NULL
;
432 // Workaround for r600g, there seems to be a bug in the fence refcounting code
433 pipe
->screen
->fence_reference(pipe
->screen
, &surface_priv
->fence
, NULL
);
435 vl_compositor_set_layer_dst_area(cstate
, 0, &dst_rect
);
436 vl_compositor_set_layer_dst_area(cstate
, 1, &dst_rect
);
437 vl_compositor_render(cstate
, compositor
, surf
, dirty_area
, true);
439 pipe
->flush(pipe
, &surface_priv
->fence
, 0);
441 XVMC_MSG(XVMC_TRACE
, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface
);
443 pipe
->screen
->flush_frontbuffer
445 pipe
->screen
, tex
, 0, 0,
446 vl_screen_get_private(context_priv
->vscreen
)
449 if(dump_window
== -1) {
450 dump_window
= debug_get_num_option("XVMC_DUMP", 0);
454 static unsigned int framenum
= 0;
457 sprintf(cmd
, "xwd -id %d -out xvmc_frame_%08d.xwd", (int)drawable
, ++framenum
);
458 if (system(cmd
) != 0)
459 XVMC_MSG(XVMC_ERR
, "[XvMC] Dumping surface %p failed.\n", surface
);
462 XVMC_MSG(XVMC_TRACE
, "[XvMC] Pushed surface %p to front buffer.\n", surface
);
468 Status
XvMCGetSurfaceStatus(Display
*dpy
, XvMCSurface
*surface
, int *status
)
470 struct pipe_context
*pipe
;
471 XvMCSurfacePrivate
*surface_priv
;
472 XvMCContextPrivate
*context_priv
;
477 return XvMCBadSurface
;
481 surface_priv
= surface
->privData
;
482 context_priv
= surface_priv
->context
->privData
;
483 pipe
= context_priv
->pipe
;
487 if (surface_priv
->fence
)
488 if (!pipe
->screen
->fence_signalled(pipe
->screen
, surface_priv
->fence
))
489 *status
|= XVMC_RENDERING
;
495 Status
XvMCDestroySurface(Display
*dpy
, XvMCSurface
*surface
)
497 XvMCSurfacePrivate
*surface_priv
;
498 XvMCContextPrivate
*context_priv
;
500 XVMC_MSG(XVMC_TRACE
, "[XvMC] Destroying surface %p.\n", surface
);
504 if (!surface
|| !surface
->privData
)
505 return XvMCBadSurface
;
507 surface_priv
= surface
->privData
;
508 context_priv
= surface_priv
->context
->privData
;
510 if (surface_priv
->picture_structure
) {
511 struct pipe_mpeg12_picture_desc desc
;
512 GetPictureDescription(surface_priv
, &desc
);
513 context_priv
->decoder
->end_frame(context_priv
->decoder
, surface_priv
->video_buffer
, &desc
.base
);
515 surface_priv
->video_buffer
->destroy(surface_priv
->video_buffer
);
517 surface
->privData
= NULL
;
519 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p destroyed.\n", surface
);
525 Status
XvMCHideSurface(Display
*dpy
, XvMCSurface
*surface
)
529 if (!surface
|| !surface
->privData
)
530 return XvMCBadSurface
;
532 /* No op, only for overlaid rendering */