• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "vl/vl_winsys.h"
41 
42 #include "xvmc_private.h"
43 
44 static void
MacroBlocksToPipe(XvMCContextPrivate * context,XvMCSurfacePrivate * surface,unsigned int xvmc_picture_structure,const XvMCMacroBlock * xvmc_mb,const XvMCBlockArray * xvmc_blocks,struct pipe_mpeg12_macroblock * mb,unsigned int num_macroblocks)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)
52 {
53    unsigned int i, j, k;
54 
55    assert(xvmc_mb);
56    assert(xvmc_blocks);
57    assert(num_macroblocks);
58 
59    for (; num_macroblocks > 0; --num_macroblocks) {
60       mb->base.codec = PIPE_VIDEO_CODEC_MPEG12;
61       mb->x = xvmc_mb->x;
62       mb->y = xvmc_mb->y;
63       mb->macroblock_type = xvmc_mb->macroblock_type;
64 
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;
69          break;
70 
71       case XVMC_TOP_FIELD:
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;
75          break;
76 
77       default:
78          assert(0);
79       }
80 
81       mb->macroblock_modes.bits.dct_type = xvmc_mb->dct_type;
82       mb->motion_vertical_field_select = xvmc_mb->motion_vertical_field_select;
83 
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];
88 
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;
92 
93       ++xvmc_mb;
94       ++mb;
95    }
96 }
97 
98 static void
GetPictureDescription(XvMCSurfacePrivate * surface,struct pipe_mpeg12_picture_desc * desc)99 GetPictureDescription(XvMCSurfacePrivate *surface, struct pipe_mpeg12_picture_desc *desc)
100 {
101    unsigned i, num_refs = 0;
102 
103    assert(surface && desc);
104 
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;
111 
112          if (ref)
113             desc->ref[num_refs++] = ref->video_buffer;
114       }
115    }
116 }
117 
118 static void
RecursiveEndFrame(XvMCSurfacePrivate * surface)119 RecursiveEndFrame(XvMCSurfacePrivate *surface)
120 {
121    XvMCContextPrivate *context_priv;
122    unsigned i;
123 
124    assert(surface);
125 
126    context_priv = surface->context->privData;
127 
128    for ( i = 0; i < 2; ++i ) {
129       if (surface->ref[i]) {
130          XvMCSurface *ref = surface->ref[i];
131 
132          assert(ref);
133 
134          surface->ref[i] = NULL;
135          RecursiveEndFrame(ref->privData);
136          surface->ref[i] = ref;
137       }
138    }
139 
140    if (surface->picture_structure) {
141       struct pipe_mpeg12_picture_desc desc;
142       GetPictureDescription(surface, &desc);
143       surface->picture_structure = 0;
144 
145       for (i = 0; i < 2; ++i)
146          surface->ref[i] = NULL;
147 
148       context_priv->decoder->end_frame(context_priv->decoder, surface->video_buffer, &desc.base);
149    }
150 }
151 
152 PUBLIC
XvMCCreateSurface(Display * dpy,XvMCContext * context,XvMCSurface * surface)153 Status XvMCCreateSurface(Display *dpy, XvMCContext *context, XvMCSurface *surface)
154 {
155    XvMCContextPrivate *context_priv;
156    struct pipe_context *pipe;
157    XvMCSurfacePrivate *surface_priv;
158    struct pipe_video_buffer tmpl;
159 
160    XVMC_MSG(XVMC_TRACE, "[XvMC] Creating surface %p.\n", surface);
161 
162    assert(dpy);
163 
164    if (!context)
165       return XvMCBadContext;
166    if (!surface)
167       return XvMCBadSurface;
168 
169    context_priv = context->privData;
170    pipe = context_priv->pipe;
171 
172    surface_priv = CALLOC(1, sizeof(XvMCSurfacePrivate));
173    if (!surface_priv)
174       return BadAlloc;
175 
176    memset(&tmpl, 0, sizeof(tmpl));
177    tmpl.buffer_format = pipe->screen->get_video_param
178    (
179       pipe->screen,
180       PIPE_VIDEO_PROFILE_MPEG2_MAIN,
181       PIPE_VIDEO_CAP_PREFERED_FORMAT
182    );
183    tmpl.chroma_format = context_priv->decoder->chroma_format;
184    tmpl.width = context_priv->decoder->width;
185    tmpl.height = context_priv->decoder->height;
186    tmpl.interlaced = pipe->screen->get_video_param
187    (
188       pipe->screen,
189       PIPE_VIDEO_PROFILE_MPEG2_MAIN,
190       PIPE_VIDEO_CAP_PREFERS_INTERLACED
191    );
192 
193    surface_priv->video_buffer = pipe->create_video_buffer(pipe, &tmpl);
194    surface_priv->context = context;
195 
196    surface->surface_id = XAllocID(dpy);
197    surface->context_id = context->context_id;
198    surface->surface_type_id = context->surface_type_id;
199    surface->width = context->width;
200    surface->height = context->height;
201    surface->privData = surface_priv;
202 
203    SyncHandle();
204 
205    XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p created.\n", surface);
206 
207    return Success;
208 }
209 
210 PUBLIC
XvMCRenderSurface(Display * dpy,XvMCContext * context,unsigned int picture_structure,XvMCSurface * target_surface,XvMCSurface * past_surface,XvMCSurface * future_surface,unsigned int flags,unsigned int num_macroblocks,unsigned int first_macroblock,XvMCMacroBlockArray * macroblocks,XvMCBlockArray * blocks)211 Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int picture_structure,
212                          XvMCSurface *target_surface, XvMCSurface *past_surface, XvMCSurface *future_surface,
213                          unsigned int flags, unsigned int num_macroblocks, unsigned int first_macroblock,
214                          XvMCMacroBlockArray *macroblocks, XvMCBlockArray *blocks
215 )
216 {
217    struct pipe_mpeg12_macroblock mb[num_macroblocks];
218    struct pipe_video_decoder *decoder;
219    struct pipe_mpeg12_picture_desc desc;
220 
221    XvMCContextPrivate *context_priv;
222    XvMCSurfacePrivate *target_surface_priv;
223    XvMCSurfacePrivate *past_surface_priv;
224    XvMCSurfacePrivate *future_surface_priv;
225    XvMCMacroBlock *xvmc_mb;
226 
227    XVMC_MSG(XVMC_TRACE, "[XvMC] Rendering to surface %p, with past %p and future %p\n",
228             target_surface, past_surface, future_surface);
229 
230    assert(dpy);
231 
232    if (!context || !context->privData)
233       return XvMCBadContext;
234    if (!target_surface || !target_surface->privData)
235       return XvMCBadSurface;
236 
237    if (picture_structure != XVMC_TOP_FIELD &&
238        picture_structure != XVMC_BOTTOM_FIELD &&
239        picture_structure != XVMC_FRAME_PICTURE)
240       return BadValue;
241    /* Bkwd pred equivalent to fwd (past && !future) */
242    if (future_surface && !past_surface)
243       return BadMatch;
244 
245    assert(context->context_id == target_surface->context_id);
246    assert(!past_surface || context->context_id == past_surface->context_id);
247    assert(!future_surface || context->context_id == future_surface->context_id);
248 
249    assert(macroblocks);
250    assert(blocks);
251 
252    assert(macroblocks->context_id == context->context_id);
253    assert(blocks->context_id == context->context_id);
254 
255    assert(flags == 0 || flags == XVMC_SECOND_FIELD);
256 
257    context_priv = context->privData;
258    decoder = context_priv->decoder;
259 
260    target_surface_priv = target_surface->privData;
261    past_surface_priv = past_surface ? past_surface->privData : NULL;
262    future_surface_priv = future_surface ? future_surface->privData : NULL;
263 
264    assert(target_surface_priv->context == context);
265    assert(!past_surface || past_surface_priv->context == context);
266    assert(!future_surface || future_surface_priv->context == context);
267 
268    // call end frame on all referenced frames
269    if (past_surface)
270       RecursiveEndFrame(past_surface->privData);
271 
272    if (future_surface)
273       RecursiveEndFrame(future_surface->privData);
274 
275    xvmc_mb = macroblocks->macro_blocks + first_macroblock;
276 
277    /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */
278    if (target_surface_priv->picture_structure > 0 && (
279        target_surface_priv->picture_structure != picture_structure ||
280        target_surface_priv->ref[0] != past_surface ||
281        target_surface_priv->ref[1] != future_surface ||
282        (xvmc_mb->x == 0 && xvmc_mb->y == 0))) {
283 
284       // If they change anyway we must assume that the current frame is ended
285       RecursiveEndFrame(target_surface_priv);
286    }
287 
288    target_surface_priv->ref[0] = past_surface;
289    target_surface_priv->ref[1] = future_surface;
290 
291    if (target_surface_priv->picture_structure)
292       GetPictureDescription(target_surface_priv, &desc);
293    else {
294       target_surface_priv->picture_structure = picture_structure;
295       GetPictureDescription(target_surface_priv, &desc);
296       decoder->begin_frame(decoder, target_surface_priv->video_buffer, &desc.base);
297    }
298 
299    MacroBlocksToPipe(context_priv, target_surface_priv, picture_structure,
300                      xvmc_mb, blocks, mb, num_macroblocks);
301 
302    context_priv->decoder->decode_macroblock(context_priv->decoder,
303                                             target_surface_priv->video_buffer,
304                                             &desc.base,
305                                             &mb[0].base, num_macroblocks);
306 
307    XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for rendering.\n", target_surface);
308 
309    return Success;
310 }
311 
312 PUBLIC
XvMCFlushSurface(Display * dpy,XvMCSurface * surface)313 Status XvMCFlushSurface(Display *dpy, XvMCSurface *surface)
314 {
315    assert(dpy);
316 
317    if (!surface)
318       return XvMCBadSurface;
319 
320    // don't call flush here, because this is usually
321    // called once for every slice instead of every frame
322 
323    XVMC_MSG(XVMC_TRACE, "[XvMC] Flushing surface %p\n", surface);
324 
325    return Success;
326 }
327 
328 PUBLIC
XvMCSyncSurface(Display * dpy,XvMCSurface * surface)329 Status XvMCSyncSurface(Display *dpy, XvMCSurface *surface)
330 {
331    assert(dpy);
332 
333    if (!surface)
334       return XvMCBadSurface;
335 
336    XVMC_MSG(XVMC_TRACE, "[XvMC] Syncing surface %p\n", surface);
337 
338    return Success;
339 }
340 
341 PUBLIC
XvMCPutSurface(Display * dpy,XvMCSurface * surface,Drawable drawable,short srcx,short srcy,unsigned short srcw,unsigned short srch,short destx,short desty,unsigned short destw,unsigned short desth,int flags)342 Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable,
343                       short srcx, short srcy, unsigned short srcw, unsigned short srch,
344                       short destx, short desty, unsigned short destw, unsigned short desth,
345                       int flags)
346 {
347    static int dump_window = -1;
348 
349    struct pipe_context *pipe;
350    struct vl_compositor *compositor;
351    struct vl_compositor_state *cstate;
352 
353    XvMCSurfacePrivate *surface_priv;
354    XvMCContextPrivate *context_priv;
355    XvMCSubpicturePrivate *subpicture_priv;
356    XvMCContext *context;
357    struct u_rect src_rect = {srcx, srcx + srcw, srcy, srcy + srch};
358    struct u_rect dst_rect = {destx, destx + destw, desty, desty + desth};
359 
360    struct pipe_resource *tex;
361    struct pipe_surface surf_templ, *surf;
362    struct u_rect *dirty_area;
363 
364    XVMC_MSG(XVMC_TRACE, "[XvMC] Displaying surface %p.\n", surface);
365 
366    assert(dpy);
367 
368    if (!surface || !surface->privData)
369       return XvMCBadSurface;
370 
371    surface_priv = surface->privData;
372    context = surface_priv->context;
373    context_priv = context->privData;
374 
375    assert(flags == XVMC_TOP_FIELD || flags == XVMC_BOTTOM_FIELD || flags == XVMC_FRAME_PICTURE);
376    assert(srcx + srcw - 1 < surface->width);
377    assert(srcy + srch - 1 < surface->height);
378 
379    subpicture_priv = surface_priv->subpicture ? surface_priv->subpicture->privData : NULL;
380    pipe = context_priv->pipe;
381    compositor = &context_priv->compositor;
382    cstate = &context_priv->cstate;
383 
384    tex = vl_screen_texture_from_drawable(context_priv->vscreen, drawable);
385    dirty_area = vl_screen_get_dirty_area(context_priv->vscreen);
386 
387    memset(&surf_templ, 0, sizeof(surf_templ));
388    surf_templ.format = tex->format;
389    surf_templ.usage = PIPE_BIND_RENDER_TARGET;
390    surf = pipe->create_surface(pipe, tex, &surf_templ);
391 
392    if (!surf)
393       return BadDrawable;
394 
395    /*
396     * Some apps (mplayer) hit these asserts because they call
397     * this function after the window has been resized by the WM
398     * but before they've handled the corresponding XEvent and
399     * know about the new dimensions. The output should be clipped
400     * until the app updates destw and desth.
401     */
402    /*
403    assert(destx + destw - 1 < drawable_surface->width);
404    assert(desty + desth - 1 < drawable_surface->height);
405     */
406 
407    RecursiveEndFrame(surface_priv);
408 
409    context_priv->decoder->flush(context_priv->decoder);
410 
411    vl_compositor_clear_layers(cstate);
412    vl_compositor_set_buffer_layer(cstate, compositor, 0, surface_priv->video_buffer,
413                                   &src_rect, NULL, VL_COMPOSITOR_WEAVE);
414 
415    if (subpicture_priv) {
416       XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p has subpicture %p.\n", surface, surface_priv->subpicture);
417 
418       assert(subpicture_priv->surface == surface);
419 
420       if (subpicture_priv->palette)
421          vl_compositor_set_palette_layer(cstate, compositor, 1, subpicture_priv->sampler, subpicture_priv->palette,
422                                          &subpicture_priv->src_rect, &subpicture_priv->dst_rect, true);
423       else
424          vl_compositor_set_rgba_layer(cstate, compositor, 1, subpicture_priv->sampler,
425                                       &subpicture_priv->src_rect, &subpicture_priv->dst_rect, NULL);
426 
427       surface_priv->subpicture = NULL;
428       subpicture_priv->surface = NULL;
429    }
430 
431    // Workaround for r600g, there seems to be a bug in the fence refcounting code
432    pipe->screen->fence_reference(pipe->screen, &surface_priv->fence, NULL);
433 
434    vl_compositor_set_layer_dst_area(cstate, 0, &dst_rect);
435    vl_compositor_set_layer_dst_area(cstate, 1, &dst_rect);
436    vl_compositor_render(cstate, compositor, surf, dirty_area);
437 
438    pipe->flush(pipe, &surface_priv->fence);
439 
440    XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface);
441 
442    pipe->screen->flush_frontbuffer
443    (
444       pipe->screen, tex, 0, 0,
445       vl_screen_get_private(context_priv->vscreen)
446    );
447 
448    if(dump_window == -1) {
449       dump_window = debug_get_num_option("XVMC_DUMP", 0);
450    }
451 
452    if(dump_window) {
453       static unsigned int framenum = 0;
454       char cmd[256];
455 
456       sprintf(cmd, "xwd -id %d -out xvmc_frame_%08d.xwd", (int)drawable, ++framenum);
457       if (system(cmd) != 0)
458          XVMC_MSG(XVMC_ERR, "[XvMC] Dumping surface %p failed.\n", surface);
459    }
460 
461    XVMC_MSG(XVMC_TRACE, "[XvMC] Pushed surface %p to front buffer.\n", surface);
462 
463    return Success;
464 }
465 
466 PUBLIC
XvMCGetSurfaceStatus(Display * dpy,XvMCSurface * surface,int * status)467 Status XvMCGetSurfaceStatus(Display *dpy, XvMCSurface *surface, int *status)
468 {
469    struct pipe_context *pipe;
470    XvMCSurfacePrivate *surface_priv;
471    XvMCContextPrivate *context_priv;
472 
473    assert(dpy);
474 
475    if (!surface)
476       return XvMCBadSurface;
477 
478    assert(status);
479 
480    surface_priv = surface->privData;
481    context_priv = surface_priv->context->privData;
482    pipe = context_priv->pipe;
483 
484    *status = 0;
485 
486    if (surface_priv->fence)
487       if (!pipe->screen->fence_signalled(pipe->screen, surface_priv->fence))
488          *status |= XVMC_RENDERING;
489 
490    return Success;
491 }
492 
493 PUBLIC
XvMCDestroySurface(Display * dpy,XvMCSurface * surface)494 Status XvMCDestroySurface(Display *dpy, XvMCSurface *surface)
495 {
496    XvMCSurfacePrivate *surface_priv;
497    XvMCContextPrivate *context_priv;
498 
499    XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying surface %p.\n", surface);
500 
501    assert(dpy);
502 
503    if (!surface || !surface->privData)
504       return XvMCBadSurface;
505 
506    surface_priv = surface->privData;
507    context_priv = surface_priv->context->privData;
508 
509    if (surface_priv->picture_structure) {
510       struct pipe_mpeg12_picture_desc desc;
511       GetPictureDescription(surface_priv, &desc);
512       context_priv->decoder->end_frame(context_priv->decoder, surface_priv->video_buffer, &desc.base);
513    }
514    surface_priv->video_buffer->destroy(surface_priv->video_buffer);
515    FREE(surface_priv);
516    surface->privData = NULL;
517 
518    XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p destroyed.\n", surface);
519 
520    return Success;
521 }
522 
523 PUBLIC
XvMCHideSurface(Display * dpy,XvMCSurface * surface)524 Status XvMCHideSurface(Display *dpy, XvMCSurface *surface)
525 {
526    assert(dpy);
527 
528    if (!surface || !surface->privData)
529       return XvMCBadSurface;
530 
531    /* No op, only for overlaid rendering */
532 
533    return Success;
534 }
535