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 VMWARE 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/macros.h"
38 #include "util/u_inlines.h"
39 #include "util/u_memory.h"
40 #include "util/u_math.h"
41 #include "vl/vl_winsys.h"
43 #include "xvmc_private.h"
46 MacroBlocksToPipe(XvMCContextPrivate
*context
,
47 XvMCSurfacePrivate
*surface
,
48 unsigned int xvmc_picture_structure
,
49 const XvMCMacroBlock
*xvmc_mb
,
50 const XvMCBlockArray
*xvmc_blocks
,
51 struct pipe_mpeg12_macroblock
*mb
,
52 unsigned int num_macroblocks
)
58 assert(num_macroblocks
);
60 for (; num_macroblocks
> 0; --num_macroblocks
) {
61 mb
->base
.codec
= PIPE_VIDEO_FORMAT_MPEG12
;
64 mb
->macroblock_type
= xvmc_mb
->macroblock_type
;
66 switch (xvmc_picture_structure
) {
67 case XVMC_FRAME_PICTURE
:
68 mb
->macroblock_modes
.bits
.frame_motion_type
= xvmc_mb
->motion_type
;
69 mb
->macroblock_modes
.bits
.field_motion_type
= 0;
73 case XVMC_BOTTOM_FIELD
:
74 mb
->macroblock_modes
.bits
.frame_motion_type
= 0;
75 mb
->macroblock_modes
.bits
.field_motion_type
= xvmc_mb
->motion_type
;
82 mb
->macroblock_modes
.bits
.dct_type
= xvmc_mb
->dct_type
;
83 mb
->motion_vertical_field_select
= xvmc_mb
->motion_vertical_field_select
;
85 for (i
= 0; i
< 2; ++i
)
86 for (j
= 0; j
< 2; ++j
)
87 for (k
= 0; k
< 2; ++k
)
88 mb
->PMV
[i
][j
][k
] = xvmc_mb
->PMV
[i
][j
][k
];
90 mb
->coded_block_pattern
= xvmc_mb
->coded_block_pattern
;
91 mb
->blocks
= xvmc_blocks
->blocks
+ xvmc_mb
->index
* BLOCK_SIZE_SAMPLES
;
92 mb
->num_skipped_macroblocks
= 0;
100 GetPictureDescription(XvMCSurfacePrivate
*surface
, struct pipe_mpeg12_picture_desc
*desc
)
102 unsigned i
, num_refs
= 0;
104 assert(surface
&& desc
);
106 memset(desc
, 0, sizeof(*desc
));
107 desc
->base
.profile
= PIPE_VIDEO_PROFILE_MPEG1
;
108 desc
->picture_structure
= surface
->picture_structure
;
109 for (i
= 0; i
< 2; ++i
) {
110 if (surface
->ref
[i
]) {
111 XvMCSurfacePrivate
*ref
= surface
->ref
[i
]->privData
;
114 desc
->ref
[num_refs
++] = ref
->video_buffer
;
120 RecursiveEndFrame(XvMCSurfacePrivate
*surface
)
122 XvMCContextPrivate
*context_priv
;
127 context_priv
= surface
->context
->privData
;
129 for ( i
= 0; i
< 2; ++i
) {
130 if (surface
->ref
[i
]) {
131 XvMCSurface
*ref
= surface
->ref
[i
];
135 surface
->ref
[i
] = NULL
;
136 RecursiveEndFrame(ref
->privData
);
137 surface
->ref
[i
] = ref
;
141 if (surface
->picture_structure
) {
142 struct pipe_mpeg12_picture_desc desc
;
143 GetPictureDescription(surface
, &desc
);
144 surface
->picture_structure
= 0;
146 for (i
= 0; i
< 2; ++i
)
147 surface
->ref
[i
] = NULL
;
149 context_priv
->decoder
->end_frame(context_priv
->decoder
, surface
->video_buffer
, &desc
.base
);
154 Status
XvMCCreateSurface(Display
*dpy
, XvMCContext
*context
, XvMCSurface
*surface
)
156 XvMCContextPrivate
*context_priv
;
157 struct pipe_context
*pipe
;
158 XvMCSurfacePrivate
*surface_priv
;
159 struct pipe_video_buffer tmpl
;
161 XVMC_MSG(XVMC_TRACE
, "[XvMC] Creating surface %p.\n", surface
);
166 return XvMCBadContext
;
168 return XvMCBadSurface
;
170 context_priv
= context
->privData
;
171 pipe
= context_priv
->pipe
;
173 surface_priv
= CALLOC(1, sizeof(XvMCSurfacePrivate
));
177 memset(&tmpl
, 0, sizeof(tmpl
));
178 tmpl
.buffer_format
= pipe
->screen
->get_video_param
181 context_priv
->decoder
->profile
,
182 context_priv
->decoder
->entrypoint
,
183 PIPE_VIDEO_CAP_PREFERED_FORMAT
185 tmpl
.chroma_format
= context_priv
->decoder
->chroma_format
;
186 tmpl
.width
= context_priv
->decoder
->width
;
187 tmpl
.height
= context_priv
->decoder
->height
;
188 tmpl
.interlaced
= pipe
->screen
->get_video_param
191 context_priv
->decoder
->profile
,
192 context_priv
->decoder
->entrypoint
,
193 PIPE_VIDEO_CAP_PREFERS_INTERLACED
196 surface_priv
->video_buffer
= pipe
->create_video_buffer(pipe
, &tmpl
);
197 if (!surface_priv
->video_buffer
) {
201 surface_priv
->context
= context
;
203 surface
->surface_id
= XAllocID(dpy
);
204 surface
->context_id
= context
->context_id
;
205 surface
->surface_type_id
= context
->surface_type_id
;
206 surface
->width
= context
->width
;
207 surface
->height
= context
->height
;
208 surface
->privData
= surface_priv
;
212 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p created.\n", surface
);
218 Status
XvMCRenderSurface(Display
*dpy
, XvMCContext
*context
, unsigned int picture_structure
,
219 XvMCSurface
*target_surface
, XvMCSurface
*past_surface
, XvMCSurface
*future_surface
,
220 unsigned int flags
, unsigned int num_macroblocks
, unsigned int first_macroblock
,
221 XvMCMacroBlockArray
*macroblocks
, XvMCBlockArray
*blocks
224 struct pipe_mpeg12_macroblock mb
[num_macroblocks
];
225 struct pipe_video_codec
*decoder
;
226 struct pipe_mpeg12_picture_desc desc
;
228 XvMCContextPrivate
*context_priv
;
229 XvMCSurfacePrivate
*target_surface_priv
;
230 MAYBE_UNUSED XvMCSurfacePrivate
*past_surface_priv
;
231 MAYBE_UNUSED XvMCSurfacePrivate
*future_surface_priv
;
232 XvMCMacroBlock
*xvmc_mb
;
234 XVMC_MSG(XVMC_TRACE
, "[XvMC] Rendering to surface %p, with past %p and future %p\n",
235 target_surface
, past_surface
, future_surface
);
239 if (!context
|| !context
->privData
)
240 return XvMCBadContext
;
241 if (!target_surface
|| !target_surface
->privData
)
242 return XvMCBadSurface
;
244 if (picture_structure
!= XVMC_TOP_FIELD
&&
245 picture_structure
!= XVMC_BOTTOM_FIELD
&&
246 picture_structure
!= XVMC_FRAME_PICTURE
)
248 /* Bkwd pred equivalent to fwd (past && !future) */
249 if (future_surface
&& !past_surface
)
252 assert(context
->context_id
== target_surface
->context_id
);
253 assert(!past_surface
|| context
->context_id
== past_surface
->context_id
);
254 assert(!future_surface
|| context
->context_id
== future_surface
->context_id
);
259 assert(macroblocks
->context_id
== context
->context_id
);
260 assert(blocks
->context_id
== context
->context_id
);
262 assert(flags
== 0 || flags
== XVMC_SECOND_FIELD
);
264 context_priv
= context
->privData
;
265 decoder
= context_priv
->decoder
;
267 target_surface_priv
= target_surface
->privData
;
268 past_surface_priv
= past_surface
? past_surface
->privData
: NULL
;
269 future_surface_priv
= future_surface
? future_surface
->privData
: NULL
;
271 assert(target_surface_priv
->context
== context
);
272 assert(!past_surface
|| past_surface_priv
->context
== context
);
273 assert(!future_surface
|| future_surface_priv
->context
== context
);
275 // call end frame on all referenced frames
277 RecursiveEndFrame(past_surface
->privData
);
280 RecursiveEndFrame(future_surface
->privData
);
282 xvmc_mb
= macroblocks
->macro_blocks
+ first_macroblock
;
284 /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */
285 if (target_surface_priv
->picture_structure
> 0 && (
286 target_surface_priv
->picture_structure
!= picture_structure
||
287 target_surface_priv
->ref
[0] != past_surface
||
288 target_surface_priv
->ref
[1] != future_surface
||
289 (xvmc_mb
->x
== 0 && xvmc_mb
->y
== 0))) {
291 // If they change anyway we must assume that the current frame is ended
292 RecursiveEndFrame(target_surface_priv
);
295 target_surface_priv
->ref
[0] = past_surface
;
296 target_surface_priv
->ref
[1] = future_surface
;
298 if (target_surface_priv
->picture_structure
)
299 GetPictureDescription(target_surface_priv
, &desc
);
301 target_surface_priv
->picture_structure
= picture_structure
;
302 GetPictureDescription(target_surface_priv
, &desc
);
303 decoder
->begin_frame(decoder
, target_surface_priv
->video_buffer
, &desc
.base
);
306 MacroBlocksToPipe(context_priv
, target_surface_priv
, picture_structure
,
307 xvmc_mb
, blocks
, mb
, num_macroblocks
);
309 context_priv
->decoder
->decode_macroblock(context_priv
->decoder
,
310 target_surface_priv
->video_buffer
,
312 &mb
[0].base
, num_macroblocks
);
314 XVMC_MSG(XVMC_TRACE
, "[XvMC] Submitted surface %p for rendering.\n", target_surface
);
320 Status
XvMCFlushSurface(Display
*dpy
, XvMCSurface
*surface
)
325 return XvMCBadSurface
;
327 // don't call flush here, because this is usually
328 // called once for every slice instead of every frame
330 XVMC_MSG(XVMC_TRACE
, "[XvMC] Flushing surface %p\n", surface
);
336 Status
XvMCSyncSurface(Display
*dpy
, XvMCSurface
*surface
)
341 return XvMCBadSurface
;
343 XVMC_MSG(XVMC_TRACE
, "[XvMC] Syncing surface %p\n", surface
);
349 Status
XvMCPutSurface(Display
*dpy
, XvMCSurface
*surface
, Drawable drawable
,
350 short srcx
, short srcy
, unsigned short srcw
, unsigned short srch
,
351 short destx
, short desty
, unsigned short destw
, unsigned short desth
,
354 static int dump_window
= -1;
356 struct pipe_context
*pipe
;
357 struct vl_compositor
*compositor
;
358 struct vl_compositor_state
*cstate
;
359 struct vl_screen
*vscreen
;
361 XvMCSurfacePrivate
*surface_priv
;
362 XvMCContextPrivate
*context_priv
;
363 XvMCSubpicturePrivate
*subpicture_priv
;
364 XvMCContext
*context
;
365 struct u_rect src_rect
= {srcx
, srcx
+ srcw
, srcy
, srcy
+ srch
};
366 struct u_rect dst_rect
= {destx
, destx
+ destw
, desty
, desty
+ desth
};
368 struct pipe_resource
*tex
;
369 struct pipe_surface surf_templ
, *surf
;
370 struct u_rect
*dirty_area
;
372 XVMC_MSG(XVMC_TRACE
, "[XvMC] Displaying surface %p.\n", surface
);
376 if (!surface
|| !surface
->privData
)
377 return XvMCBadSurface
;
379 surface_priv
= surface
->privData
;
380 context
= surface_priv
->context
;
381 context_priv
= context
->privData
;
383 assert(flags
== XVMC_TOP_FIELD
|| flags
== XVMC_BOTTOM_FIELD
|| flags
== XVMC_FRAME_PICTURE
);
384 assert(srcx
+ srcw
- 1 < surface
->width
);
385 assert(srcy
+ srch
- 1 < surface
->height
);
387 subpicture_priv
= surface_priv
->subpicture
? surface_priv
->subpicture
->privData
: NULL
;
388 pipe
= context_priv
->pipe
;
389 compositor
= &context_priv
->compositor
;
390 cstate
= &context_priv
->cstate
;
391 vscreen
= context_priv
->vscreen
;
393 tex
= vscreen
->texture_from_drawable(vscreen
, (void *)drawable
);
394 dirty_area
= vscreen
->get_dirty_area(vscreen
);
396 memset(&surf_templ
, 0, sizeof(surf_templ
));
397 surf_templ
.format
= tex
->format
;
398 surf
= pipe
->create_surface(pipe
, tex
, &surf_templ
);
404 * Some apps (mplayer) hit these asserts because they call
405 * this function after the window has been resized by the WM
406 * but before they've handled the corresponding XEvent and
407 * know about the new dimensions. The output should be clipped
408 * until the app updates destw and desth.
411 assert(destx + destw - 1 < drawable_surface->width);
412 assert(desty + desth - 1 < drawable_surface->height);
415 RecursiveEndFrame(surface_priv
);
417 context_priv
->decoder
->flush(context_priv
->decoder
);
419 vl_compositor_clear_layers(cstate
);
420 vl_compositor_set_buffer_layer(cstate
, compositor
, 0, surface_priv
->video_buffer
,
421 &src_rect
, NULL
, VL_COMPOSITOR_WEAVE
);
423 if (subpicture_priv
) {
424 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p has subpicture %p.\n", surface
, surface_priv
->subpicture
);
426 assert(subpicture_priv
->surface
== surface
);
428 if (subpicture_priv
->palette
)
429 vl_compositor_set_palette_layer(cstate
, compositor
, 1, subpicture_priv
->sampler
, subpicture_priv
->palette
,
430 &subpicture_priv
->src_rect
, &subpicture_priv
->dst_rect
, true);
432 vl_compositor_set_rgba_layer(cstate
, compositor
, 1, subpicture_priv
->sampler
,
433 &subpicture_priv
->src_rect
, &subpicture_priv
->dst_rect
, NULL
);
435 surface_priv
->subpicture
= NULL
;
436 subpicture_priv
->surface
= NULL
;
439 // Workaround for r600g, there seems to be a bug in the fence refcounting code
440 pipe
->screen
->fence_reference(pipe
->screen
, &surface_priv
->fence
, NULL
);
442 vl_compositor_set_layer_dst_area(cstate
, 0, &dst_rect
);
443 vl_compositor_set_layer_dst_area(cstate
, 1, &dst_rect
);
444 vl_compositor_render(cstate
, compositor
, surf
, dirty_area
, true);
446 pipe
->flush(pipe
, &surface_priv
->fence
, 0);
448 XVMC_MSG(XVMC_TRACE
, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface
);
450 pipe
->screen
->flush_frontbuffer(pipe
->screen
, tex
, 0, 0,
451 vscreen
->get_private(vscreen
), NULL
);
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_finish(pipe
->screen
, NULL
, surface_priv
->fence
, 0))
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 */