Added optimized YUV texture upload path with SDL_UpdateYUVTexture()
authorSam Lantinga <slouken@libsdl.org>
Sat, 28 Sep 2013 14:06:47 -0700
changeset 7759869583422e5a
parent 7758 54c0acdf9c8e
child 7760 63b519624589
Added optimized YUV texture upload path with SDL_UpdateYUVTexture()
include/SDL_render.h
src/render/SDL_render.c
src/render/SDL_sysrender.h
src/render/SDL_yuv_sw.c
src/render/SDL_yuv_sw_c.h
src/render/opengl/SDL_render_gl.c
     1.1 --- a/include/SDL_render.h	Sat Sep 28 14:06:39 2013 -0700
     1.2 +++ b/include/SDL_render.h	Sat Sep 28 14:06:47 2013 -0700
     1.3 @@ -382,6 +382,31 @@
     1.4                                                const void *pixels, int pitch);
     1.5  
     1.6  /**
     1.7 + *  \brief Update a rectangle within a planar YV12 or IYUV texture with new pixel data.
     1.8 + *
     1.9 + *  \param texture   The texture to update
    1.10 + *  \param rect      A pointer to the rectangle of pixels to update, or NULL to
    1.11 + *                   update the entire texture.
    1.12 + *  \param Yplane    The raw pixel data for the Y plane.
    1.13 + *  \param Ypitch    The number of bytes between rows of pixel data for the Y plane.
    1.14 + *  \param Uplane    The raw pixel data for the U plane.
    1.15 + *  \param Upitch    The number of bytes between rows of pixel data for the U plane.
    1.16 + *  \param Vplane    The raw pixel data for the V plane.
    1.17 + *  \param Vpitch    The number of bytes between rows of pixel data for the V plane.
    1.18 + *
    1.19 + *  \return 0 on success, or -1 if the texture is not valid.
    1.20 + *
    1.21 + *  \note You can use SDL_UpdateTexture() as long as your pixel data is
    1.22 + *        a contiguous block of Y and U/V planes in the proper order, but
    1.23 + *        this function is available if your pixel data is not contiguous.
    1.24 + */
    1.25 +extern DECLSPEC int SDLCALL SDL_UpdateYUVTexture(SDL_Texture * texture,
    1.26 +                                                 const SDL_Rect * rect,
    1.27 +                                                 const Uint8 *Yplane, int Ypitch,
    1.28 +                                                 const Uint8 *Uplane, int Upitch,
    1.29 +                                                 const Uint8 *Vplane, int Vpitch);
    1.30 +
    1.31 +/**
    1.32   *  \brief Lock a portion of the texture for write-only pixel access.
    1.33   *
    1.34   *  \param texture   The texture to lock for access, which was created with
     2.1 --- a/src/render/SDL_render.c	Sat Sep 28 14:06:39 2013 -0700
     2.2 +++ b/src/render/SDL_render.c	Sat Sep 28 14:06:47 2013 -0700
     2.3 @@ -805,6 +805,106 @@
     2.4  }
     2.5  
     2.6  static int
     2.7 +SDL_UpdateTextureYUVPlanar(SDL_Texture * texture, const SDL_Rect * rect,
     2.8 +                           const Uint8 *Yplane, int Ypitch,
     2.9 +                           const Uint8 *Uplane, int Upitch,
    2.10 +                           const Uint8 *Vplane, int Vpitch)
    2.11 +{
    2.12 +    SDL_Texture *native = texture->native;
    2.13 +    SDL_Rect full_rect;
    2.14 +
    2.15 +    if (SDL_SW_UpdateYUVTexturePlanar(texture->yuv, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch) < 0) {
    2.16 +        return -1;
    2.17 +    }
    2.18 +
    2.19 +    full_rect.x = 0;
    2.20 +    full_rect.y = 0;
    2.21 +    full_rect.w = texture->w;
    2.22 +    full_rect.h = texture->h;
    2.23 +    rect = &full_rect;
    2.24 +
    2.25 +    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
    2.26 +        /* We can lock the texture and copy to it */
    2.27 +        void *native_pixels;
    2.28 +        int native_pitch;
    2.29 +
    2.30 +        if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
    2.31 +            return -1;
    2.32 +        }
    2.33 +        SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
    2.34 +                            rect->w, rect->h, native_pixels, native_pitch);
    2.35 +        SDL_UnlockTexture(native);
    2.36 +    } else {
    2.37 +        /* Use a temporary buffer for updating */
    2.38 +        void *temp_pixels;
    2.39 +        int temp_pitch;
    2.40 +
    2.41 +        temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
    2.42 +        temp_pixels = SDL_malloc(rect->h * temp_pitch);
    2.43 +        if (!temp_pixels) {
    2.44 +            return SDL_OutOfMemory();
    2.45 +        }
    2.46 +        SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
    2.47 +                            rect->w, rect->h, temp_pixels, temp_pitch);
    2.48 +        SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
    2.49 +        SDL_free(temp_pixels);
    2.50 +    }
    2.51 +    return 0;
    2.52 +}
    2.53 +
    2.54 +int SDL_UpdateYUVTexture(SDL_Texture * texture, const SDL_Rect * rect,
    2.55 +                         const Uint8 *Yplane, int Ypitch,
    2.56 +                         const Uint8 *Uplane, int Upitch,
    2.57 +                         const Uint8 *Vplane, int Vpitch)
    2.58 +{
    2.59 +    SDL_Renderer *renderer;
    2.60 +    SDL_Rect full_rect;
    2.61 +
    2.62 +    CHECK_TEXTURE_MAGIC(texture, -1);
    2.63 +
    2.64 +    if (!Yplane) {
    2.65 +        return SDL_InvalidParamError("Yplane");
    2.66 +    }
    2.67 +    if (!Ypitch) {
    2.68 +        return SDL_InvalidParamError("Ypitch");
    2.69 +    }
    2.70 +    if (!Uplane) {
    2.71 +        return SDL_InvalidParamError("Uplane");
    2.72 +    }
    2.73 +    if (!Upitch) {
    2.74 +        return SDL_InvalidParamError("Upitch");
    2.75 +    }
    2.76 +    if (!Vplane) {
    2.77 +        return SDL_InvalidParamError("Vplane");
    2.78 +    }
    2.79 +    if (!Vpitch) {
    2.80 +        return SDL_InvalidParamError("Vpitch");
    2.81 +    }
    2.82 +
    2.83 +    if (texture->format != SDL_PIXELFORMAT_YV12 &&
    2.84 +        texture->format != SDL_PIXELFORMAT_IYUV) {
    2.85 +        return SDL_SetError("Texture format must by YV12 or IYUV");
    2.86 +    }
    2.87 +
    2.88 +    if (!rect) {
    2.89 +        full_rect.x = 0;
    2.90 +        full_rect.y = 0;
    2.91 +        full_rect.w = texture->w;
    2.92 +        full_rect.h = texture->h;
    2.93 +        rect = &full_rect;
    2.94 +    }
    2.95 +
    2.96 +    if (texture->yuv) {
    2.97 +        return SDL_UpdateTextureYUVPlanar(texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
    2.98 +    } else {
    2.99 +        SDL_assert(!texture->native);
   2.100 +        renderer = texture->renderer;
   2.101 +        SDL_assert(renderer->UpdateTextureYUV);
   2.102 +        return renderer->UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
   2.103 +    }
   2.104 +}
   2.105 +
   2.106 +static int
   2.107  SDL_LockTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
   2.108                     void **pixels, int *pitch)
   2.109  {
     3.1 --- a/src/render/SDL_sysrender.h	Sat Sep 28 14:06:39 2013 -0700
     3.2 +++ b/src/render/SDL_sysrender.h	Sat Sep 28 14:06:47 2013 -0700
     3.3 @@ -89,6 +89,11 @@
     3.4      int (*UpdateTexture) (SDL_Renderer * renderer, SDL_Texture * texture,
     3.5                            const SDL_Rect * rect, const void *pixels,
     3.6                            int pitch);
     3.7 +    int (*UpdateTextureYUV) (SDL_Renderer * renderer, SDL_Texture * texture,
     3.8 +                            const SDL_Rect * rect,
     3.9 +                            const Uint8 *Yplane, int Ypitch,
    3.10 +                            const Uint8 *Uplane, int Upitch,
    3.11 +                            const Uint8 *Vplane, int Vpitch);
    3.12      int (*LockTexture) (SDL_Renderer * renderer, SDL_Texture * texture,
    3.13                          const SDL_Rect * rect, void **pixels, int *pitch);
    3.14      void (*UnlockTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
     4.1 --- a/src/render/SDL_yuv_sw.c	Sat Sep 28 14:06:39 2013 -0700
     4.2 +++ b/src/render/SDL_yuv_sw.c	Sat Sep 28 14:06:47 2013 -0700
     4.3 @@ -1185,6 +1185,60 @@
     4.4  }
     4.5  
     4.6  int
     4.7 +SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
     4.8 +                              const Uint8 *Yplane, int Ypitch,
     4.9 +                              const Uint8 *Uplane, int Upitch,
    4.10 +                              const Uint8 *Vplane, int Vpitch)
    4.11 +{
    4.12 +    Uint8 *src, *dst;
    4.13 +    int row;
    4.14 +    size_t length;
    4.15 +
    4.16 +    /* Copy the Y plane */
    4.17 +    src = Yplane;
    4.18 +    dst = swdata->pixels + rect->y * swdata->w + rect->x;
    4.19 +    length = rect->w;
    4.20 +    for (row = 0; row < rect->h; ++row) {
    4.21 +        SDL_memcpy(dst, src, length);
    4.22 +        src += Ypitch;
    4.23 +        dst += swdata->w;
    4.24 +    }
    4.25 +
    4.26 +    /* Copy the U plane */
    4.27 +    src = Uplane;
    4.28 +    if (swdata->format == SDL_PIXELFORMAT_IYUV) {
    4.29 +        dst = swdata->pixels + swdata->h * swdata->w;
    4.30 +    } else {
    4.31 +        dst = swdata->pixels + swdata->h * swdata->w +
    4.32 +              (swdata->h * swdata->w) / 4;
    4.33 +    }
    4.34 +    dst += rect->y/2 * swdata->w/2 + rect->x/2;
    4.35 +    length = rect->w / 2;
    4.36 +    for (row = 0; row < rect->h/2; ++row) {
    4.37 +        SDL_memcpy(dst, src, length);
    4.38 +        src += Upitch;
    4.39 +        dst += swdata->w/2;
    4.40 +    }
    4.41 +
    4.42 +    /* Copy the V plane */
    4.43 +    src = Vplane;
    4.44 +    if (swdata->format == SDL_PIXELFORMAT_YV12) {
    4.45 +        dst = swdata->pixels + swdata->h * swdata->w;
    4.46 +    } else {
    4.47 +        dst = swdata->pixels + swdata->h * swdata->w +
    4.48 +              (swdata->h * swdata->w) / 4;
    4.49 +    }
    4.50 +    dst += rect->y/2 * swdata->w/2 + rect->x/2;
    4.51 +    length = rect->w / 2;
    4.52 +    for (row = 0; row < rect->h/2; ++row) {
    4.53 +        SDL_memcpy(dst, src, length);
    4.54 +        src += Vpitch;
    4.55 +        dst += swdata->w/2;
    4.56 +    }
    4.57 +    return 0;
    4.58 +}
    4.59 +
    4.60 +int
    4.61  SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
    4.62                        void **pixels, int *pitch)
    4.63  {
     5.1 --- a/src/render/SDL_yuv_sw_c.h	Sat Sep 28 14:06:39 2013 -0700
     5.2 +++ b/src/render/SDL_yuv_sw_c.h	Sat Sep 28 14:06:47 2013 -0700
     5.3 @@ -57,6 +57,10 @@
     5.4                                   int *pitch);
     5.5  int SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
     5.6                              const void *pixels, int pitch);
     5.7 +int SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
     5.8 +                                  const Uint8 *Yplane, int Ypitch,
     5.9 +                                  const Uint8 *Uplane, int Upitch,
    5.10 +                                  const Uint8 *Vplane, int Vpitch);
    5.11  int SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
    5.12                            void **pixels, int *pitch);
    5.13  void SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture * swdata);
     6.1 --- a/src/render/opengl/SDL_render_gl.c	Sat Sep 28 14:06:39 2013 -0700
     6.2 +++ b/src/render/opengl/SDL_render_gl.c	Sat Sep 28 14:06:47 2013 -0700
     6.3 @@ -52,6 +52,11 @@
     6.4  static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
     6.5                              const SDL_Rect * rect, const void *pixels,
     6.6                              int pitch);
     6.7 +static int GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
     6.8 +                               const SDL_Rect * rect,
     6.9 +                               const Uint8 *Yplane, int Ypitch,
    6.10 +                               const Uint8 *Uplane, int Upitch,
    6.11 +                               const Uint8 *Vplane, int Vpitch);
    6.12  static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    6.13                            const SDL_Rect * rect, void **pixels, int *pitch);
    6.14  static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    6.15 @@ -403,6 +408,7 @@
    6.16      renderer->GetOutputSize = GL_GetOutputSize;
    6.17      renderer->CreateTexture = GL_CreateTexture;
    6.18      renderer->UpdateTexture = GL_UpdateTexture;
    6.19 +    renderer->UpdateTextureYUV = GL_UpdateTextureYUV;
    6.20      renderer->LockTexture = GL_LockTexture;
    6.21      renderer->UnlockTexture = GL_UnlockTexture;
    6.22      renderer->SetRenderTarget = GL_SetRenderTarget;
    6.23 @@ -802,6 +808,41 @@
    6.24  }
    6.25  
    6.26  static int
    6.27 +GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
    6.28 +                    const SDL_Rect * rect,
    6.29 +                    const Uint8 *Yplane, int Ypitch,
    6.30 +                    const Uint8 *Uplane, int Upitch,
    6.31 +                    const Uint8 *Vplane, int Vpitch)
    6.32 +{
    6.33 +    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
    6.34 +    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
    6.35 +
    6.36 +    GL_ActivateRenderer(renderer);
    6.37 +
    6.38 +    renderdata->glEnable(data->type);
    6.39 +    renderdata->glBindTexture(data->type, data->texture);
    6.40 +    renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    6.41 +    renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Ypitch);
    6.42 +    renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
    6.43 +                                rect->h, data->format, data->formattype,
    6.44 +                                Yplane);
    6.45 +
    6.46 +    renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Upitch);
    6.47 +    renderdata->glBindTexture(data->type, data->utexture);
    6.48 +    renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
    6.49 +                                rect->w/2, rect->h/2,
    6.50 +                                data->format, data->formattype, Uplane);
    6.51 +
    6.52 +    renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Vpitch);
    6.53 +    renderdata->glBindTexture(data->type, data->vtexture);
    6.54 +    renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
    6.55 +                                rect->w/2, rect->h/2,
    6.56 +                                data->format, data->formattype, Vplane);
    6.57 +    renderdata->glDisable(data->type);
    6.58 +    return GL_CheckError("glTexSubImage2D()", renderer);
    6.59 +}
    6.60 +
    6.61 +static int
    6.62  GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    6.63                 const SDL_Rect * rect, void **pixels, int *pitch)
    6.64  {