[PATCH xserver v2] glamor: add support for NV12 in Xv

Alex Deucher alexdeucher at gmail.com
Tue Sep 11 19:41:57 UTC 2018


On Tue, Sep 11, 2018 at 1:30 PM Julien Isorce <julien.isorce at gmail.com> wrote:
>
> Useful when video decoders only output NV12. Currently
> glamor Xv only supports I420 and YV12.
>
> Note that Intel's sna supports I420, YV12, YUY2, UYVY, NV12.
>
> Test: xvinfo | grep NV12
> Test: gst-launch-1.0 videotestsrc ! video/x-raw, format=NV12 ! xvimagesink
>
> v2: Combine the two texture2Ds on u_sampler.
>
> Signed-off-by: Julien Isorce <jisorce at oblong.com>

Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

> ---
>  glamor/glamor_xv.c | 180 +++++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 155 insertions(+), 25 deletions(-)
>
> diff --git a/glamor/glamor_xv.c b/glamor/glamor_xv.c
> index 62fc4ff..6fef6ed 100644
> --- a/glamor/glamor_xv.c
> +++ b/glamor/glamor_xv.c
> @@ -59,8 +59,40 @@ typedef struct tagREF_TRANSFORM {
>  #define RTFContrast(a)   (1.0 + ((a)*1.0)/1000.0)
>  #define RTFHue(a)   (((a)*3.1416)/1000.0)
>
> -static const glamor_facet glamor_facet_xv_planar = {
> -    .name = "xv_planar",
> +static const glamor_facet glamor_facet_xv_planar_2 = {
> +    .name = "xv_planar_2",
> +
> +    .version = 120,
> +
> +    .source_name = "v_texcoord0",
> +    .vs_vars = ("attribute vec2 position;\n"
> +                "attribute vec2 v_texcoord0;\n"
> +                "varying vec2 tcs;\n"),
> +    .vs_exec = (GLAMOR_POS(gl_Position, position)
> +                "        tcs = v_texcoord0;\n"),
> +
> +    .fs_vars = ("uniform sampler2D y_sampler;\n"
> +                "uniform sampler2D u_sampler;\n"
> +                "uniform vec4 offsetyco;\n"
> +                "uniform vec4 ucogamma;\n"
> +                "uniform vec4 vco;\n"
> +                "varying vec2 tcs;\n"),
> +    .fs_exec = (
> +                "        float sample;\n"
> +                "        vec2 sample_uv;\n"
> +                "        vec4 temp1;\n"
> +                "        sample = texture2D(y_sampler, tcs).w;\n"
> +                "        temp1.xyz = offsetyco.www * vec3(sample) + offsetyco.xyz;\n"
> +                "        sample_uv = texture2D(u_sampler, tcs).xy;\n"
> +                "        temp1.xyz = ucogamma.xyz * vec3(sample_uv.x) + temp1.xyz;\n"
> +                "        temp1.xyz = clamp(vco.xyz * vec3(sample_uv.y) + temp1.xyz, 0.0, 1.0);\n"
> +                "        temp1.w = 1.0;\n"
> +                "        gl_FragColor = temp1;\n"
> +                ),
> +};
> +
> +static const glamor_facet glamor_facet_xv_planar_3 = {
> +    .name = "xv_planar_3",
>
>      .version = 120,
>
> @@ -110,26 +142,50 @@ Atom glamorBrightness, glamorContrast, glamorSaturation, glamorHue,
>  XvImageRec glamor_xv_images[] = {
>      XVIMAGE_YV12,
>      XVIMAGE_I420,
> +    XVIMAGE_NV12
>  };
>  int glamor_xv_num_images = ARRAY_SIZE(glamor_xv_images);
>
>  static void
> -glamor_init_xv_shader(ScreenPtr screen)
> +glamor_init_xv_shader(ScreenPtr screen, int id)
>  {
>      glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
>      GLint sampler_loc;
> +    const glamor_facet *glamor_facet_xv_planar = NULL;
> +
> +    switch (id) {
> +    case FOURCC_YV12:
> +    case FOURCC_I420:
> +        glamor_facet_xv_planar = &glamor_facet_xv_planar_3;
> +        break;
> +    case FOURCC_NV12:
> +        glamor_facet_xv_planar = &glamor_facet_xv_planar_2;
> +        break;
> +    default:
> +        break;
> +    }
>
>      glamor_build_program(screen,
>                           &glamor_priv->xv_prog,
> -                         &glamor_facet_xv_planar, NULL, NULL, NULL);
> +                         glamor_facet_xv_planar, NULL, NULL, NULL);
>
>      glUseProgram(glamor_priv->xv_prog.prog);
>      sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "y_sampler");
>      glUniform1i(sampler_loc, 0);
>      sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "u_sampler");
>      glUniform1i(sampler_loc, 1);
> -    sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "v_sampler");
> -    glUniform1i(sampler_loc, 2);
> +
> +    switch (id) {
> +    case FOURCC_YV12:
> +    case FOURCC_I420:
> +        sampler_loc = glGetUniformLocation(glamor_priv->xv_prog.prog, "v_sampler");
> +        glUniform1i(sampler_loc, 2);
> +        break;
> +    case FOURCC_NV12:
> +        break;
> +    default:
> +        break;
> +    }
>
>  }
>
> @@ -227,6 +283,21 @@ glamor_xv_query_image_attributes(int id,
>              offsets[2] = size;
>          size += tmp;
>          break;
> +    case FOURCC_NV12:
> +        *w = ALIGN(*w, 2);
> +        *h = ALIGN(*h, 2);
> +        size = ALIGN(*w, 4);
> +        if (pitches)
> +            pitches[0] = size;
> +        size *= *h;
> +        if (offsets)
> +            offsets[1] = offsets[2] = size;
> +        tmp = ALIGN(*w, 4);
> +        if (pitches)
> +            pitches[1] = pitches[2] = tmp;
> +        tmp *= (*h >> 1);
> +        size += tmp;
> +        break;
>      }
>      return size;
>  }
> @@ -240,7 +311,7 @@ static REF_TRANSFORM trans[2] = {
>  };
>
>  void
> -glamor_xv_render(glamor_port_private *port_priv)
> +glamor_xv_render(glamor_port_private *port_priv, int id)
>  {
>      ScreenPtr screen = port_priv->pPixmap->drawable.pScreen;
>      glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
> @@ -264,7 +335,7 @@ glamor_xv_render(glamor_port_private *port_priv)
>      int dst_box_index;
>
>      if (!glamor_priv->xv_prog.prog)
> -        glamor_init_xv_shader(screen);
> +        glamor_init_xv_shader(screen, id);
>
>      cont = RTFContrast(port_priv->contrast);
>      bright = RTFBrightness(port_priv->brightness);
> @@ -293,6 +364,8 @@ glamor_xv_render(glamor_port_private *port_priv)
>                  glamor_get_pixmap_private(port_priv->src_pix[i]);
>              pixmap_priv_get_scale(src_pixmap_priv[i], &src_xscale[i],
>                                    &src_yscale[i]);
> +        } else {
> +           src_pixmap_priv[i] = NULL;
>          }
>      }
>      glamor_make_current(glamor_priv);
> @@ -319,12 +392,21 @@ glamor_xv_render(glamor_port_private *port_priv)
>      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
>      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
>
> -    glActiveTexture(GL_TEXTURE2);
> -    glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[2]->fbo->tex);
> -    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
> -    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
> -    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
> -    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
> +    switch (id) {
> +    case FOURCC_YV12:
> +    case FOURCC_I420:
> +        glActiveTexture(GL_TEXTURE2);
> +        glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[2]->fbo->tex);
> +        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
> +        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
> +        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
> +        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
> +        break;
> +    case FOURCC_NV12:
> +        break;
> +    default:
> +        break;
> +    }
>
>      glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
>      glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
> @@ -336,7 +418,7 @@ glamor_xv_render(glamor_port_private *port_priv)
>      /* Set up a single primitive covering the area being drawn.  We'll
>       * clip it to port_priv->clip using GL scissors instead of just
>       * emitting a GL_QUAD per box, because this way we hopefully avoid
> -     * diagonal tearing between the two trangles used to rasterize a
> +     * diagonal tearing between the two triangles used to rasterize a
>       * GL_QUAD.
>       */
>      i = 0;
> @@ -417,6 +499,7 @@ glamor_xv_put_image(glamor_port_private *port_priv,
>                      RegionPtr clipBoxes)
>  {
>      ScreenPtr pScreen = pDrawable->pScreen;
> +    glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
>      int srcPitch, srcPitch2;
>      int top, nlines;
>      int s2offset, s3offset, tmp;
> @@ -425,9 +508,16 @@ glamor_xv_put_image(glamor_port_private *port_priv,
>      s2offset = s3offset = srcPitch2 = 0;
>
>      if (!port_priv->src_pix[0] ||
> -        (width != port_priv->src_pix_w || height != port_priv->src_pix_h)) {
> +        (width != port_priv->src_pix_w || height != port_priv->src_pix_h) ||
> +        (port_priv->src_pix[2] && id == FOURCC_NV12) ||
> +        (!port_priv->src_pix[2] && id != FOURCC_NV12)) {
>          int i;
>
> +        if (glamor_priv->xv_prog.prog) {
> +            glDeleteProgram(glamor_priv->xv_prog.prog);
> +            glamor_priv->xv_prog.prog = 0;
> +        }
> +
>          for (i = 0; i < 3; i++)
>              if (port_priv->src_pix[i])
>                  glamor_destroy_pixmap(port_priv->src_pix[i]);
> @@ -435,17 +525,34 @@ glamor_xv_put_image(glamor_port_private *port_priv,
>          port_priv->src_pix[0] =
>              glamor_create_pixmap(pScreen, width, height, 8,
>                                   GLAMOR_CREATE_FBO_NO_FBO);
> -        port_priv->src_pix[1] =
> -            glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
> -                                 GLAMOR_CREATE_FBO_NO_FBO);
> -        port_priv->src_pix[2] =
> -            glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
> -                                 GLAMOR_CREATE_FBO_NO_FBO);
> +
> +        switch (id) {
> +        case FOURCC_YV12:
> +        case FOURCC_I420:
> +            port_priv->src_pix[1] =
> +                glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
> +                                     GLAMOR_CREATE_FBO_NO_FBO);
> +            port_priv->src_pix[2] =
> +                glamor_create_pixmap(pScreen, width >> 1, height >> 1, 8,
> +                                     GLAMOR_CREATE_FBO_NO_FBO);
> +            if (!port_priv->src_pix[2])
> +                return BadAlloc;
> +            break;
> +        case FOURCC_NV12:
> +            port_priv->src_pix[1] =
> +                glamor_create_pixmap(pScreen, width >> 1, height >> 1, 16,
> +                                     GLAMOR_CREATE_FBO_NO_FBO |
> +                                     GLAMOR_CREATE_FORMAT_CBCR);
> +            port_priv->src_pix[2] = NULL;
> +            break;
> +        default:
> +            return BadMatch;
> +        }
> +
>          port_priv->src_pix_w = width;
>          port_priv->src_pix_h = height;
>
> -        if (!port_priv->src_pix[0] || !port_priv->src_pix[1] ||
> -            !port_priv->src_pix[2])
> +        if (!port_priv->src_pix[0] || !port_priv->src_pix[1])
>              return BadAlloc;
>      }
>
> @@ -489,6 +596,29 @@ glamor_xv_put_image(glamor_port_private *port_priv,
>                              0, 0, 0, 0,
>                              buf + s3offset, srcPitch2);
>          break;
> +    case FOURCC_NV12:
> +        srcPitch = ALIGN(width, 4);
> +        s2offset = srcPitch * height;
> +        s2offset += ((top >> 1) * srcPitch);
> +
> +        full_box.x1 = 0;
> +        full_box.y1 = 0;
> +        full_box.x2 = width;
> +        full_box.y2 = nlines;
> +
> +        half_box.x1 = 0;
> +        half_box.y1 = 0;
> +        half_box.x2 = width;
> +        half_box.y2 = (nlines + 1) >> 1;
> +
> +        glamor_upload_boxes(port_priv->src_pix[0], &full_box, 1,
> +                            0, 0, 0, 0,
> +                            buf + (top * srcPitch), srcPitch);
> +
> +        glamor_upload_boxes(port_priv->src_pix[1], &half_box, 1,
> +                            0, 0, 0, 0,
> +                            buf + s2offset, srcPitch);
> +        break;
>      default:
>          return BadMatch;
>      }
> @@ -511,7 +641,7 @@ glamor_xv_put_image(glamor_port_private *port_priv,
>      port_priv->w = width;
>      port_priv->h = height;
>      port_priv->pDraw = pDrawable;
> -    glamor_xv_render(port_priv);
> +    glamor_xv_render(port_priv, id);
>      return Success;
>  }
>
> --
> 2.7.4
>
> _______________________________________________
> xorg-devel at lists.x.org: X.Org development
> Archives: http://lists.x.org/archives/xorg-devel
> Info: https://lists.x.org/mailman/listinfo/xorg-devel


More information about the xorg-devel mailing list