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 if (!surface_priv
->video_buffer
) {
200 surface_priv
->context
= context
;
202 surface
->surface_id
= XAllocID(dpy
);
203 surface
->context_id
= context
->context_id
;
204 surface
->surface_type_id
= context
->surface_type_id
;
205 surface
->width
= context
->width
;
206 surface
->height
= context
->height
;
207 surface
->privData
= surface_priv
;
211 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p created.\n", surface
);
217 Status
XvMCRenderSurface(Display
*dpy
, XvMCContext
*context
, unsigned int picture_structure
,
218 XvMCSurface
*target_surface
, XvMCSurface
*past_surface
, XvMCSurface
*future_surface
,
219 unsigned int flags
, unsigned int num_macroblocks
, unsigned int first_macroblock
,
220 XvMCMacroBlockArray
*macroblocks
, XvMCBlockArray
*blocks
223 struct pipe_mpeg12_macroblock mb
[num_macroblocks
];
224 struct pipe_video_codec
*decoder
;
225 struct pipe_mpeg12_picture_desc desc
;
227 XvMCContextPrivate
*context_priv
;
228 XvMCSurfacePrivate
*target_surface_priv
;
229 XvMCSurfacePrivate
*past_surface_priv
;
230 XvMCSurfacePrivate
*future_surface_priv
;
231 XvMCMacroBlock
*xvmc_mb
;
233 XVMC_MSG(XVMC_TRACE
, "[XvMC] Rendering to surface %p, with past %p and future %p\n",
234 target_surface
, past_surface
, future_surface
);
238 if (!context
|| !context
->privData
)
239 return XvMCBadContext
;
240 if (!target_surface
|| !target_surface
->privData
)
241 return XvMCBadSurface
;
243 if (picture_structure
!= XVMC_TOP_FIELD
&&
244 picture_structure
!= XVMC_BOTTOM_FIELD
&&
245 picture_structure
!= XVMC_FRAME_PICTURE
)
247 /* Bkwd pred equivalent to fwd (past && !future) */
248 if (future_surface
&& !past_surface
)
251 assert(context
->context_id
== target_surface
->context_id
);
252 assert(!past_surface
|| context
->context_id
== past_surface
->context_id
);
253 assert(!future_surface
|| context
->context_id
== future_surface
->context_id
);
258 assert(macroblocks
->context_id
== context
->context_id
);
259 assert(blocks
->context_id
== context
->context_id
);
261 assert(flags
== 0 || flags
== XVMC_SECOND_FIELD
);
263 context_priv
= context
->privData
;
264 decoder
= context_priv
->decoder
;
266 target_surface_priv
= target_surface
->privData
;
267 past_surface_priv
= past_surface
? past_surface
->privData
: NULL
;
268 future_surface_priv
= future_surface
? future_surface
->privData
: NULL
;
270 assert(target_surface_priv
->context
== context
);
271 assert(!past_surface
|| past_surface_priv
->context
== context
);
272 assert(!future_surface
|| future_surface_priv
->context
== context
);
274 // call end frame on all referenced frames
276 RecursiveEndFrame(past_surface
->privData
);
279 RecursiveEndFrame(future_surface
->privData
);
281 xvmc_mb
= macroblocks
->macro_blocks
+ first_macroblock
;
283 /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */
284 if (target_surface_priv
->picture_structure
> 0 && (
285 target_surface_priv
->picture_structure
!= picture_structure
||
286 target_surface_priv
->ref
[0] != past_surface
||
287 target_surface_priv
->ref
[1] != future_surface
||
288 (xvmc_mb
->x
== 0 && xvmc_mb
->y
== 0))) {
290 // If they change anyway we must assume that the current frame is ended
291 RecursiveEndFrame(target_surface_priv
);
294 target_surface_priv
->ref
[0] = past_surface
;
295 target_surface_priv
->ref
[1] = future_surface
;
297 if (target_surface_priv
->picture_structure
)
298 GetPictureDescription(target_surface_priv
, &desc
);
300 target_surface_priv
->picture_structure
= picture_structure
;
301 GetPictureDescription(target_surface_priv
, &desc
);
302 decoder
->begin_frame(decoder
, target_surface_priv
->video_buffer
, &desc
.base
);
305 MacroBlocksToPipe(context_priv
, target_surface_priv
, picture_structure
,
306 xvmc_mb
, blocks
, mb
, num_macroblocks
);
308 context_priv
->decoder
->decode_macroblock(context_priv
->decoder
,
309 target_surface_priv
->video_buffer
,
311 &mb
[0].base
, num_macroblocks
);
313 XVMC_MSG(XVMC_TRACE
, "[XvMC] Submitted surface %p for rendering.\n", target_surface
);
319 Status
XvMCFlushSurface(Display
*dpy
, XvMCSurface
*surface
)
324 return XvMCBadSurface
;
326 // don't call flush here, because this is usually
327 // called once for every slice instead of every frame
329 XVMC_MSG(XVMC_TRACE
, "[XvMC] Flushing surface %p\n", surface
);
335 Status
XvMCSyncSurface(Display
*dpy
, XvMCSurface
*surface
)
340 return XvMCBadSurface
;
342 XVMC_MSG(XVMC_TRACE
, "[XvMC] Syncing surface %p\n", surface
);
348 Status
XvMCPutSurface(Display
*dpy
, XvMCSurface
*surface
, Drawable drawable
,
349 short srcx
, short srcy
, unsigned short srcw
, unsigned short srch
,
350 short destx
, short desty
, unsigned short destw
, unsigned short desth
,
353 static int dump_window
= -1;
355 struct pipe_context
*pipe
;
356 struct vl_compositor
*compositor
;
357 struct vl_compositor_state
*cstate
;
359 XvMCSurfacePrivate
*surface_priv
;
360 XvMCContextPrivate
*context_priv
;
361 XvMCSubpicturePrivate
*subpicture_priv
;
362 XvMCContext
*context
;
363 struct u_rect src_rect
= {srcx
, srcx
+ srcw
, srcy
, srcy
+ srch
};
364 struct u_rect dst_rect
= {destx
, destx
+ destw
, desty
, desty
+ desth
};
366 struct pipe_resource
*tex
;
367 struct pipe_surface surf_templ
, *surf
;
368 struct u_rect
*dirty_area
;
370 XVMC_MSG(XVMC_TRACE
, "[XvMC] Displaying surface %p.\n", surface
);
374 if (!surface
|| !surface
->privData
)
375 return XvMCBadSurface
;
377 surface_priv
= surface
->privData
;
378 context
= surface_priv
->context
;
379 context_priv
= context
->privData
;
381 assert(flags
== XVMC_TOP_FIELD
|| flags
== XVMC_BOTTOM_FIELD
|| flags
== XVMC_FRAME_PICTURE
);
382 assert(srcx
+ srcw
- 1 < surface
->width
);
383 assert(srcy
+ srch
- 1 < surface
->height
);
385 subpicture_priv
= surface_priv
->subpicture
? surface_priv
->subpicture
->privData
: NULL
;
386 pipe
= context_priv
->pipe
;
387 compositor
= &context_priv
->compositor
;
388 cstate
= &context_priv
->cstate
;
390 tex
= vl_screen_texture_from_drawable(context_priv
->vscreen
, drawable
);
391 dirty_area
= vl_screen_get_dirty_area(context_priv
->vscreen
);
393 memset(&surf_templ
, 0, sizeof(surf_templ
));
394 surf_templ
.format
= tex
->format
;
395 surf
= pipe
->create_surface(pipe
, tex
, &surf_templ
);
401 * Some apps (mplayer) hit these asserts because they call
402 * this function after the window has been resized by the WM
403 * but before they've handled the corresponding XEvent and
404 * know about the new dimensions. The output should be clipped
405 * until the app updates destw and desth.
408 assert(destx + destw - 1 < drawable_surface->width);
409 assert(desty + desth - 1 < drawable_surface->height);
412 RecursiveEndFrame(surface_priv
);
414 context_priv
->decoder
->flush(context_priv
->decoder
);
416 vl_compositor_clear_layers(cstate
);
417 vl_compositor_set_buffer_layer(cstate
, compositor
, 0, surface_priv
->video_buffer
,
418 &src_rect
, NULL
, VL_COMPOSITOR_WEAVE
);
420 if (subpicture_priv
) {
421 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p has subpicture %p.\n", surface
, surface_priv
->subpicture
);
423 assert(subpicture_priv
->surface
== surface
);
425 if (subpicture_priv
->palette
)
426 vl_compositor_set_palette_layer(cstate
, compositor
, 1, subpicture_priv
->sampler
, subpicture_priv
->palette
,
427 &subpicture_priv
->src_rect
, &subpicture_priv
->dst_rect
, true);
429 vl_compositor_set_rgba_layer(cstate
, compositor
, 1, subpicture_priv
->sampler
,
430 &subpicture_priv
->src_rect
, &subpicture_priv
->dst_rect
, NULL
);
432 surface_priv
->subpicture
= NULL
;
433 subpicture_priv
->surface
= NULL
;
436 // Workaround for r600g, there seems to be a bug in the fence refcounting code
437 pipe
->screen
->fence_reference(pipe
->screen
, &surface_priv
->fence
, NULL
);
439 vl_compositor_set_layer_dst_area(cstate
, 0, &dst_rect
);
440 vl_compositor_set_layer_dst_area(cstate
, 1, &dst_rect
);
441 vl_compositor_render(cstate
, compositor
, surf
, dirty_area
, true);
443 pipe
->flush(pipe
, &surface_priv
->fence
, 0);
445 XVMC_MSG(XVMC_TRACE
, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface
);
447 pipe
->screen
->flush_frontbuffer
449 pipe
->screen
, tex
, 0, 0,
450 vl_screen_get_private(context_priv
->vscreen
)
453 if(dump_window
== -1) {
454 dump_window
= debug_get_num_option("XVMC_DUMP", 0);
458 static unsigned int framenum
= 0;
461 sprintf(cmd
, "xwd -id %d -out xvmc_frame_%08d.xwd", (int)drawable
, ++framenum
);
462 if (system(cmd
) != 0)
463 XVMC_MSG(XVMC_ERR
, "[XvMC] Dumping surface %p failed.\n", surface
);
466 XVMC_MSG(XVMC_TRACE
, "[XvMC] Pushed surface %p to front buffer.\n", surface
);
472 Status
XvMCGetSurfaceStatus(Display
*dpy
, XvMCSurface
*surface
, int *status
)
474 struct pipe_context
*pipe
;
475 XvMCSurfacePrivate
*surface_priv
;
476 XvMCContextPrivate
*context_priv
;
481 return XvMCBadSurface
;
485 surface_priv
= surface
->privData
;
486 context_priv
= surface_priv
->context
->privData
;
487 pipe
= context_priv
->pipe
;
491 if (surface_priv
->fence
)
492 if (!pipe
->screen
->fence_signalled(pipe
->screen
, surface_priv
->fence
))
493 *status
|= XVMC_RENDERING
;
499 Status
XvMCDestroySurface(Display
*dpy
, XvMCSurface
*surface
)
501 XvMCSurfacePrivate
*surface_priv
;
502 XvMCContextPrivate
*context_priv
;
504 XVMC_MSG(XVMC_TRACE
, "[XvMC] Destroying surface %p.\n", surface
);
508 if (!surface
|| !surface
->privData
)
509 return XvMCBadSurface
;
511 surface_priv
= surface
->privData
;
512 context_priv
= surface_priv
->context
->privData
;
514 if (surface_priv
->picture_structure
) {
515 struct pipe_mpeg12_picture_desc desc
;
516 GetPictureDescription(surface_priv
, &desc
);
517 context_priv
->decoder
->end_frame(context_priv
->decoder
, surface_priv
->video_buffer
, &desc
.base
);
519 surface_priv
->video_buffer
->destroy(surface_priv
->video_buffer
);
521 surface
->privData
= NULL
;
523 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p destroyed.\n", surface
);
529 Status
XvMCHideSurface(Display
*dpy
, XvMCSurface
*surface
)
533 if (!surface
|| !surface
->privData
)
534 return XvMCBadSurface
;
536 /* No op, only for overlaid rendering */