Added NV12 and NV21 texture support for OpenGL and OpenGL ES 2.0 renderers
authorSam Lantinga <slouken@libsdl.org>
Wed, 06 Aug 2014 11:34:54 -0700
changeset 9046c3ec7c3e6c24
parent 9045 c689ac0e8411
child 9047 101109110bf7
Added NV12 and NV21 texture support for OpenGL and OpenGL ES 2.0 renderers
include/SDL_pixels.h
src/render/opengl/SDL_render_gl.c
src/render/opengl/SDL_shaders_gl.c
src/render/opengl/SDL_shaders_gl.h
src/render/opengles2/SDL_render_gles2.c
src/render/opengles2/SDL_shaders_gles2.c
src/render/opengles2/SDL_shaders_gles2.h
src/test/SDL_test_common.c
src/video/SDL_pixels.c
src/video/SDL_surface.c
test/testautomation_pixels.c
test/testoverlay2.c
     1.1 --- a/include/SDL_pixels.h	Wed Aug 06 00:28:02 2014 -0700
     1.2 +++ b/include/SDL_pixels.h	Wed Aug 06 11:34:54 2014 -0700
     1.3 @@ -248,7 +248,11 @@
     1.4      SDL_PIXELFORMAT_UYVY =      /**< Packed mode: U0+Y0+V0+Y1 (1 plane) */
     1.5          SDL_DEFINE_PIXELFOURCC('U', 'Y', 'V', 'Y'),
     1.6      SDL_PIXELFORMAT_YVYU =      /**< Packed mode: Y0+V0+Y1+U0 (1 plane) */
     1.7 -        SDL_DEFINE_PIXELFOURCC('Y', 'V', 'Y', 'U')
     1.8 +        SDL_DEFINE_PIXELFOURCC('Y', 'V', 'Y', 'U'),
     1.9 +    SDL_PIXELFORMAT_NV12 =      /**< Planar mode: Y + U/V interleaved  (2 planes) */
    1.10 +        SDL_DEFINE_PIXELFOURCC('N', 'V', '1', '2'),
    1.11 +    SDL_PIXELFORMAT_NV21 =      /**< Planar mode: Y + V/U interleaved  (2 planes) */
    1.12 +        SDL_DEFINE_PIXELFOURCC('N', 'V', '2', '1')
    1.13  };
    1.14  
    1.15  typedef struct SDL_Color
     2.1 --- a/src/render/opengl/SDL_render_gl.c	Wed Aug 06 00:28:02 2014 -0700
     2.2 +++ b/src/render/opengl/SDL_render_gl.c	Wed Aug 06 11:34:54 2014 -0700
     2.3 @@ -164,8 +164,9 @@
     2.4      int pitch;
     2.5      SDL_Rect locked_rect;
     2.6  
     2.7 -    /* YV12 texture support */
     2.8 +    /* YUV texture support */
     2.9      SDL_bool yuv;
    2.10 +    SDL_bool nv12;
    2.11      GLuint utexture;
    2.12      GLuint vtexture;
    2.13  
    2.14 @@ -531,6 +532,8 @@
    2.15      if (data->shaders && data->num_texture_units >= 3) {
    2.16          renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
    2.17          renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
    2.18 +        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
    2.19 +        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
    2.20      }
    2.21  
    2.22  #ifdef __MACOSX__
    2.23 @@ -611,16 +614,18 @@
    2.24          break;
    2.25      case SDL_PIXELFORMAT_YV12:
    2.26      case SDL_PIXELFORMAT_IYUV:
    2.27 +    case SDL_PIXELFORMAT_NV12:
    2.28 +    case SDL_PIXELFORMAT_NV21:
    2.29          *internalFormat = GL_LUMINANCE;
    2.30          *format = GL_LUMINANCE;
    2.31          *type = GL_UNSIGNED_BYTE;
    2.32          break;
    2.33  #ifdef __MACOSX__
    2.34      case SDL_PIXELFORMAT_UYVY:
    2.35 -		*internalFormat = GL_RGB8;
    2.36 -		*format = GL_YCBCR_422_APPLE;
    2.37 -		*type = GL_UNSIGNED_SHORT_8_8_APPLE;
    2.38 -		break;
    2.39 +        *internalFormat = GL_RGB8;
    2.40 +        *format = GL_YCBCR_422_APPLE;
    2.41 +        *type = GL_UNSIGNED_SHORT_8_8_APPLE;
    2.42 +        break;
    2.43  #endif
    2.44      default:
    2.45          return SDL_FALSE;
    2.46 @@ -672,6 +677,11 @@
    2.47              /* Need to add size for the U and V planes */
    2.48              size += (2 * (texture->h * data->pitch) / 4);
    2.49          }
    2.50 +        if (texture->format == SDL_PIXELFORMAT_NV12 ||
    2.51 +            texture->format == SDL_PIXELFORMAT_NV21) {
    2.52 +            /* Need to add size for the U/V plane */
    2.53 +            size += ((texture->h * data->pitch) / 2);
    2.54 +        }
    2.55          data->pixels = SDL_calloc(1, size);
    2.56          if (!data->pixels) {
    2.57              SDL_free(data);
    2.58 @@ -801,6 +811,27 @@
    2.59          renderdata->glDisable(data->type);
    2.60      }
    2.61  
    2.62 +    if (texture->format == SDL_PIXELFORMAT_NV12 ||
    2.63 +        texture->format == SDL_PIXELFORMAT_NV21) {
    2.64 +        data->nv12 = SDL_TRUE;
    2.65 +
    2.66 +        renderdata->glGenTextures(1, &data->utexture);
    2.67 +        renderdata->glEnable(data->type);
    2.68 +
    2.69 +        renderdata->glBindTexture(data->type, data->utexture);
    2.70 +        renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
    2.71 +                                    scaleMode);
    2.72 +        renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
    2.73 +                                    scaleMode);
    2.74 +        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
    2.75 +                                    GL_CLAMP_TO_EDGE);
    2.76 +        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
    2.77 +                                    GL_CLAMP_TO_EDGE);
    2.78 +        renderdata->glTexImage2D(data->type, 0, GL_LUMINANCE_ALPHA, texture_w/2,
    2.79 +                                 texture_h/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
    2.80 +        renderdata->glDisable(data->type);
    2.81 +    }
    2.82 +
    2.83      return GL_CheckError("", renderer);
    2.84  }
    2.85  
    2.86 @@ -848,6 +879,17 @@
    2.87                                      rect->w/2, rect->h/2,
    2.88                                      data->format, data->formattype, pixels);
    2.89      }
    2.90 +
    2.91 +    if (data->nv12) {
    2.92 +        renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2));
    2.93 +
    2.94 +        /* Skip to the correct offset into the next texture */
    2.95 +        pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
    2.96 +        renderdata->glBindTexture(data->type, data->utexture);
    2.97 +        renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
    2.98 +                                    rect->w/2, rect->h/2,
    2.99 +                                    GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels);
   2.100 +    }
   2.101      renderdata->glDisable(data->type);
   2.102  
   2.103      return GL_CheckError("glTexSubImage2D()", renderer);
   2.104 @@ -1184,15 +1226,10 @@
   2.105  }
   2.106  
   2.107  static int
   2.108 -GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   2.109 -              const SDL_Rect * srcrect, const SDL_FRect * dstrect)
   2.110 +GL_SetupCopy(SDL_Renderer * renderer, SDL_Texture * texture)
   2.111  {
   2.112      GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   2.113      GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
   2.114 -    GLfloat minx, miny, maxx, maxy;
   2.115 -    GLfloat minu, maxu, minv, maxv;
   2.116 -
   2.117 -    GL_ActivateRenderer(renderer);
   2.118  
   2.119      data->glEnable(texturedata->type);
   2.120      if (texturedata->yuv) {
   2.121 @@ -1204,6 +1241,12 @@
   2.122  
   2.123          data->glActiveTextureARB(GL_TEXTURE0_ARB);
   2.124      }
   2.125 +    if (texturedata->nv12) {
   2.126 +        data->glActiveTextureARB(GL_TEXTURE1_ARB);
   2.127 +        data->glBindTexture(texturedata->type, texturedata->utexture);
   2.128 +
   2.129 +        data->glActiveTextureARB(GL_TEXTURE0_ARB);
   2.130 +    }
   2.131      data->glBindTexture(texturedata->type, texturedata->texture);
   2.132  
   2.133      if (texture->modMode) {
   2.134 @@ -1215,10 +1258,33 @@
   2.135      GL_SetBlendMode(data, texture->blendMode);
   2.136  
   2.137      if (texturedata->yuv) {
   2.138 -        GL_SetShader(data, SHADER_YV12);
   2.139 +        GL_SetShader(data, SHADER_YUV);
   2.140 +    } else if (texturedata->nv12) {
   2.141 +        if (texture->format == SDL_PIXELFORMAT_NV12) {
   2.142 +            GL_SetShader(data, SHADER_NV12);
   2.143 +        } else {
   2.144 +            GL_SetShader(data, SHADER_NV21);
   2.145 +        }
   2.146      } else {
   2.147          GL_SetShader(data, SHADER_RGB);
   2.148      }
   2.149 +    return 0;
   2.150 +}
   2.151 +
   2.152 +static int
   2.153 +GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   2.154 +              const SDL_Rect * srcrect, const SDL_FRect * dstrect)
   2.155 +{
   2.156 +    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
   2.157 +    GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
   2.158 +    GLfloat minx, miny, maxx, maxy;
   2.159 +    GLfloat minu, maxu, minv, maxv;
   2.160 +
   2.161 +    GL_ActivateRenderer(renderer);
   2.162 +
   2.163 +    if (GL_SetupCopy(renderer, texture) < 0) {
   2.164 +        return -1;
   2.165 +    }
   2.166  
   2.167      minx = dstrect->x;
   2.168      miny = dstrect->y;
   2.169 @@ -1263,30 +1329,8 @@
   2.170  
   2.171      GL_ActivateRenderer(renderer);
   2.172  
   2.173 -    data->glEnable(texturedata->type);
   2.174 -    if (texturedata->yuv) {
   2.175 -        data->glActiveTextureARB(GL_TEXTURE2_ARB);
   2.176 -        data->glBindTexture(texturedata->type, texturedata->vtexture);
   2.177 -
   2.178 -        data->glActiveTextureARB(GL_TEXTURE1_ARB);
   2.179 -        data->glBindTexture(texturedata->type, texturedata->utexture);
   2.180 -
   2.181 -        data->glActiveTextureARB(GL_TEXTURE0_ARB);
   2.182 -    }
   2.183 -    data->glBindTexture(texturedata->type, texturedata->texture);
   2.184 -
   2.185 -    if (texture->modMode) {
   2.186 -        GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
   2.187 -    } else {
   2.188 -        GL_SetColor(data, 255, 255, 255, 255);
   2.189 -    }
   2.190 -
   2.191 -    GL_SetBlendMode(data, texture->blendMode);
   2.192 -
   2.193 -    if (texturedata->yuv) {
   2.194 -        GL_SetShader(data, SHADER_YV12);
   2.195 -    } else {
   2.196 -        GL_SetShader(data, SHADER_RGB);
   2.197 +    if (GL_SetupCopy(renderer, texture) < 0) {
   2.198 +        return -1;
   2.199      }
   2.200  
   2.201      centerx = center->x;
     3.1 --- a/src/render/opengl/SDL_shaders_gl.c	Wed Aug 06 00:28:02 2014 -0700
     3.2 +++ b/src/render/opengl/SDL_shaders_gl.c	Wed Aug 06 11:34:54 2014 -0700
     3.3 @@ -113,7 +113,7 @@
     3.4  "}"
     3.5      },
     3.6  
     3.7 -    /* SHADER_YV12 */
     3.8 +    /* SHADER_YUV */
     3.9      {
    3.10          /* vertex shader */
    3.11  "varying vec4 v_color;\n"
    3.12 @@ -164,6 +164,106 @@
    3.13  "    gl_FragColor = vec4(rgb, 1.0) * v_color;\n"
    3.14  "}"
    3.15      },
    3.16 +
    3.17 +    /* SHADER_NV12 */
    3.18 +    {
    3.19 +        /* vertex shader */
    3.20 +"varying vec4 v_color;\n"
    3.21 +"varying vec2 v_texCoord;\n"
    3.22 +"\n"
    3.23 +"void main()\n"
    3.24 +"{\n"
    3.25 +"    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
    3.26 +"    v_color = gl_Color;\n"
    3.27 +"    v_texCoord = vec2(gl_MultiTexCoord0);\n"
    3.28 +"}",
    3.29 +        /* fragment shader */
    3.30 +"varying vec4 v_color;\n"
    3.31 +"varying vec2 v_texCoord;\n"
    3.32 +"uniform sampler2D tex0; // Y \n"
    3.33 +"uniform sampler2D tex1; // U/V \n"
    3.34 +"\n"
    3.35 +"// YUV offset \n"
    3.36 +"const vec3 offset = vec3(-0.0627451017, -0.501960814, -0.501960814);\n"
    3.37 +"\n"
    3.38 +"// RGB coefficients \n"
    3.39 +"const vec3 Rcoeff = vec3(1.164,  0.000,  1.596);\n"
    3.40 +"const vec3 Gcoeff = vec3(1.164, -0.391, -0.813);\n"
    3.41 +"const vec3 Bcoeff = vec3(1.164,  2.018,  0.000);\n"
    3.42 +"\n"
    3.43 +"void main()\n"
    3.44 +"{\n"
    3.45 +"    vec2 tcoord;\n"
    3.46 +"    vec3 yuv, rgb;\n"
    3.47 +"\n"
    3.48 +"    // Get the Y value \n"
    3.49 +"    tcoord = v_texCoord;\n"
    3.50 +"    yuv.x = texture2D(tex0, tcoord).r;\n"
    3.51 +"\n"
    3.52 +"    // Get the U and V values \n"
    3.53 +"    tcoord *= 0.5;\n"
    3.54 +"    yuv.yz = texture2D(tex1, tcoord).ra;\n"
    3.55 +"\n"
    3.56 +"    // Do the color transform \n"
    3.57 +"    yuv += offset;\n"
    3.58 +"    rgb.r = dot(yuv, Rcoeff);\n"
    3.59 +"    rgb.g = dot(yuv, Gcoeff);\n"
    3.60 +"    rgb.b = dot(yuv, Bcoeff);\n"
    3.61 +"\n"
    3.62 +"    // That was easy. :) \n"
    3.63 +"    gl_FragColor = vec4(rgb, 1.0) * v_color;\n"
    3.64 +"}"
    3.65 +    },
    3.66 +
    3.67 +    /* SHADER_NV21 */
    3.68 +    {
    3.69 +        /* vertex shader */
    3.70 +"varying vec4 v_color;\n"
    3.71 +"varying vec2 v_texCoord;\n"
    3.72 +"\n"
    3.73 +"void main()\n"
    3.74 +"{\n"
    3.75 +"    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
    3.76 +"    v_color = gl_Color;\n"
    3.77 +"    v_texCoord = vec2(gl_MultiTexCoord0);\n"
    3.78 +"}",
    3.79 +        /* fragment shader */
    3.80 +"varying vec4 v_color;\n"
    3.81 +"varying vec2 v_texCoord;\n"
    3.82 +"uniform sampler2D tex0; // Y \n"
    3.83 +"uniform sampler2D tex1; // U/V \n"
    3.84 +"\n"
    3.85 +"// YUV offset \n"
    3.86 +"const vec3 offset = vec3(-0.0627451017, -0.501960814, -0.501960814);\n"
    3.87 +"\n"
    3.88 +"// RGB coefficients \n"
    3.89 +"const vec3 Rcoeff = vec3(1.164,  0.000,  1.596);\n"
    3.90 +"const vec3 Gcoeff = vec3(1.164, -0.391, -0.813);\n"
    3.91 +"const vec3 Bcoeff = vec3(1.164,  2.018,  0.000);\n"
    3.92 +"\n"
    3.93 +"void main()\n"
    3.94 +"{\n"
    3.95 +"    vec2 tcoord;\n"
    3.96 +"    vec3 yuv, rgb;\n"
    3.97 +"\n"
    3.98 +"    // Get the Y value \n"
    3.99 +"    tcoord = v_texCoord;\n"
   3.100 +"    yuv.x = texture2D(tex0, tcoord).r;\n"
   3.101 +"\n"
   3.102 +"    // Get the U and V values \n"
   3.103 +"    tcoord *= 0.5;\n"
   3.104 +"    yuv.yz = texture2D(tex1, tcoord).ar;\n"
   3.105 +"\n"
   3.106 +"    // Do the color transform \n"
   3.107 +"    yuv += offset;\n"
   3.108 +"    rgb.r = dot(yuv, Rcoeff);\n"
   3.109 +"    rgb.g = dot(yuv, Gcoeff);\n"
   3.110 +"    rgb.b = dot(yuv, Bcoeff);\n"
   3.111 +"\n"
   3.112 +"    // That was easy. :) \n"
   3.113 +"    gl_FragColor = vec4(rgb, 1.0) * v_color;\n"
   3.114 +"}"
   3.115 +    },
   3.116  };
   3.117  
   3.118  static SDL_bool
     4.1 --- a/src/render/opengl/SDL_shaders_gl.h	Wed Aug 06 00:28:02 2014 -0700
     4.2 +++ b/src/render/opengl/SDL_shaders_gl.h	Wed Aug 06 11:34:54 2014 -0700
     4.3 @@ -26,7 +26,9 @@
     4.4      SHADER_NONE,
     4.5      SHADER_SOLID,
     4.6      SHADER_RGB,
     4.7 -    SHADER_YV12,
     4.8 +    SHADER_YUV,
     4.9 +    SHADER_NV12,
    4.10 +    SHADER_NV21,
    4.11      NUM_SHADERS
    4.12  } GL_Shader;
    4.13  
     5.1 --- a/src/render/opengles2/SDL_render_gles2.c	Wed Aug 06 00:28:02 2014 -0700
     5.2 +++ b/src/render/opengles2/SDL_render_gles2.c	Wed Aug 06 11:34:54 2014 -0700
     5.3 @@ -81,8 +81,9 @@
     5.4      GLenum pixel_type;
     5.5      void *pixel_data;
     5.6      int pitch;
     5.7 -    /* YV12 texture support */
     5.8 +    /* YUV texture support */
     5.9      SDL_bool yuv;
    5.10 +    SDL_bool nv12;
    5.11      GLenum texture_v;
    5.12      GLenum texture_u;
    5.13      GLES2_FBOList *fbo;
    5.14 @@ -151,7 +152,9 @@
    5.15      GLES2_IMAGESOURCE_TEXTURE_ARGB,
    5.16      GLES2_IMAGESOURCE_TEXTURE_RGB,
    5.17      GLES2_IMAGESOURCE_TEXTURE_BGR,
    5.18 -    GLES2_IMAGESOURCE_TEXTURE_YUV
    5.19 +    GLES2_IMAGESOURCE_TEXTURE_YUV,
    5.20 +    GLES2_IMAGESOURCE_TEXTURE_NV12,
    5.21 +    GLES2_IMAGESOURCE_TEXTURE_NV21
    5.22  } GLES2_ImageSource;
    5.23  
    5.24  typedef struct GLES2_DriverContext
    5.25 @@ -488,6 +491,8 @@
    5.26          break;
    5.27      case SDL_PIXELFORMAT_IYUV:
    5.28      case SDL_PIXELFORMAT_YV12:
    5.29 +    case SDL_PIXELFORMAT_NV12:
    5.30 +    case SDL_PIXELFORMAT_NV21:
    5.31          format = GL_LUMINANCE;
    5.32          type = GL_UNSIGNED_BYTE;
    5.33          break;
    5.34 @@ -505,6 +510,7 @@
    5.35      data->pixel_format = format;
    5.36      data->pixel_type = type;
    5.37      data->yuv = ((texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12));
    5.38 +    data->nv12 = ((texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21));
    5.39      data->texture_u = 0;
    5.40      data->texture_v = 0;
    5.41      scaleMode = GetScaleQuality();
    5.42 @@ -518,6 +524,10 @@
    5.43              /* Need to add size for the U and V planes */
    5.44              size += (2 * (texture->h * data->pitch) / 4);
    5.45          }
    5.46 +        if (data->nv12) {
    5.47 +            /* Need to add size for the U/V plane */
    5.48 +            size += ((texture->h * data->pitch) / 2);
    5.49 +        }
    5.50          data->pixel_data = SDL_calloc(1, size);
    5.51          if (!data->pixel_data) {
    5.52              SDL_free(data);
    5.53 @@ -557,6 +567,23 @@
    5.54          }
    5.55      }
    5.56  
    5.57 +    if (data->nv12) {
    5.58 +        renderdata->glGenTextures(1, &data->texture_u);
    5.59 +        if (GL_CheckError("glGenTexures()", renderer) < 0) {
    5.60 +            return -1;
    5.61 +        }
    5.62 +        renderdata->glActiveTexture(GL_TEXTURE1);
    5.63 +        renderdata->glBindTexture(data->texture_type, data->texture_u);
    5.64 +        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
    5.65 +        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
    5.66 +        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    5.67 +        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    5.68 +        renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, texture->w / 2, texture->h / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
    5.69 +        if (GL_CheckError("glTexImage2D()", renderer) < 0) {
    5.70 +            return -1;
    5.71 +        }
    5.72 +    }
    5.73 +
    5.74      renderdata->glGenTextures(1, &data->texture);
    5.75      if (GL_CheckError("glGenTexures()", renderer) < 0) {
    5.76          return -1;
    5.77 @@ -673,6 +700,20 @@
    5.78                  pixels, pitch / 2, 1);
    5.79      }
    5.80  
    5.81 +    if (tdata->nv12) {
    5.82 +        /* Skip to the correct offset into the next texture */
    5.83 +        pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
    5.84 +        data->glBindTexture(tdata->texture_type, tdata->texture_u);
    5.85 +        GLES2_TexSubImage2D(data, tdata->texture_type,
    5.86 +                rect->x / 2,
    5.87 +                rect->y / 2,
    5.88 +                rect->w / 2,
    5.89 +                rect->h / 2,
    5.90 +                GL_LUMINANCE_ALPHA,
    5.91 +                GL_UNSIGNED_BYTE,
    5.92 +                pixels, pitch, 2);
    5.93 +    }
    5.94 +
    5.95      return GL_CheckError("glTexSubImage2D()", renderer);
    5.96  }
    5.97  
    5.98 @@ -1093,6 +1134,12 @@
    5.99      case GLES2_IMAGESOURCE_TEXTURE_YUV:
   5.100          ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_SRC;
   5.101          break;
   5.102 +    case GLES2_IMAGESOURCE_TEXTURE_NV12:
   5.103 +        ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_SRC;
   5.104 +        break;
   5.105 +    case GLES2_IMAGESOURCE_TEXTURE_NV21:
   5.106 +        ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_SRC;
   5.107 +        break;
   5.108      default:
   5.109          goto fault;
   5.110      }
   5.111 @@ -1432,20 +1479,15 @@
   5.112  }
   5.113  
   5.114  static int
   5.115 -GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
   5.116 -                 const SDL_FRect *dstrect)
   5.117 +GLES2_SetupCopy(SDL_Renderer *renderer, SDL_Texture *texture)
   5.118  {
   5.119      GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
   5.120      GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
   5.121      GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
   5.122      SDL_BlendMode blendMode;
   5.123 -    GLfloat vertices[8];
   5.124 -    GLfloat texCoords[8];
   5.125      GLES2_ProgramCacheEntry *program;
   5.126      Uint8 r, g, b, a;
   5.127  
   5.128 -    GLES2_ActivateRenderer(renderer);
   5.129 -
   5.130      /* Activate an appropriate shader and set the projection matrix */
   5.131      blendMode = texture->blendMode;
   5.132      if (renderer->target) {
   5.133 @@ -1505,11 +1547,22 @@
   5.134                          break;
   5.135                  }
   5.136                  break;
   5.137 +            case SDL_PIXELFORMAT_IYUV:
   5.138 +            case SDL_PIXELFORMAT_YV12:
   5.139 +                sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV;
   5.140 +                break;
   5.141 +            case SDL_PIXELFORMAT_NV12:
   5.142 +                sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12;
   5.143 +                break;
   5.144 +            case SDL_PIXELFORMAT_NV21:
   5.145 +                sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21;
   5.146 +                break;
   5.147 +            default:
   5.148 +                return SDL_SetError("Unsupported texture format");
   5.149              }
   5.150          }
   5.151          else sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;   /* Texture formats match, use the non color mapping shader (even if the formats are not ABGR) */
   5.152 -    }
   5.153 -    else {
   5.154 +    } else {
   5.155          switch (texture->format)
   5.156          {
   5.157              case SDL_PIXELFORMAT_ARGB8888:
   5.158 @@ -1524,13 +1577,18 @@
   5.159              case SDL_PIXELFORMAT_BGR888:
   5.160                  sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
   5.161                  break;
   5.162 -            // TODO: new shader to change yv planes YV12 format
   5.163              case SDL_PIXELFORMAT_IYUV:
   5.164              case SDL_PIXELFORMAT_YV12:
   5.165                  sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV;
   5.166                  break;
   5.167 +            case SDL_PIXELFORMAT_NV12:
   5.168 +                sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12;
   5.169 +                break;
   5.170 +            case SDL_PIXELFORMAT_NV21:
   5.171 +                sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21;
   5.172 +                break;
   5.173              default:
   5.174 -                return -1;
   5.175 +                return SDL_SetError("Unsupported texture format");
   5.176          }
   5.177      }
   5.178  
   5.179 @@ -1548,6 +1606,12 @@
   5.180  
   5.181          data->glActiveTexture(GL_TEXTURE0);
   5.182      }
   5.183 +    if (tdata->nv12) {
   5.184 +        data->glActiveTexture(GL_TEXTURE1);
   5.185 +        data->glBindTexture(tdata->texture_type, tdata->texture_u);
   5.186 +
   5.187 +        data->glActiveTexture(GL_TEXTURE0);
   5.188 +    }
   5.189      data->glBindTexture(tdata->texture_type, tdata->texture);
   5.190  
   5.191      /* Configure color modulation */
   5.192 @@ -1578,6 +1642,23 @@
   5.193      GLES2_SetBlendMode(data, blendMode);
   5.194  
   5.195      GLES2_SetTexCoords(data, SDL_TRUE);
   5.196 +    return 0;
   5.197 +}
   5.198 +
   5.199 +static int
   5.200 +GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
   5.201 +                 const SDL_FRect *dstrect)
   5.202 +{
   5.203 +    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
   5.204 +    GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
   5.205 +    GLfloat vertices[8];
   5.206 +    GLfloat texCoords[8];
   5.207 +
   5.208 +    GLES2_ActivateRenderer(renderer);
   5.209 +
   5.210 +    if (GLES2_SetupCopy(renderer, texture) < 0) {
   5.211 +        return -1;
   5.212 +    }
   5.213  
   5.214      /* Emit the textured quad */
   5.215      vertices[0] = dstrect->x;
   5.216 @@ -1609,10 +1690,6 @@
   5.217  {
   5.218      GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
   5.219      GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
   5.220 -    GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
   5.221 -    GLES2_ProgramCacheEntry *program;
   5.222 -    Uint8 r, g, b, a;
   5.223 -    SDL_BlendMode blendMode;
   5.224      GLfloat vertices[8];
   5.225      GLfloat texCoords[8];
   5.226      GLfloat translate[8];
   5.227 @@ -1621,6 +1698,10 @@
   5.228  
   5.229      GLES2_ActivateRenderer(renderer);
   5.230  
   5.231 +    if (GLES2_SetupCopy(renderer, texture) < 0) {
   5.232 +        return -1;
   5.233 +    }
   5.234 +
   5.235      data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_CENTER);
   5.236      data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE);
   5.237      fAngle[0] = fAngle[1] = fAngle[2] = fAngle[3] = (GLfloat)(360.0f - angle);
   5.238 @@ -1628,124 +1709,6 @@
   5.239      translate[0] = translate[2] = translate[4] = translate[6] = (center->x + dstrect->x);
   5.240      translate[1] = translate[3] = translate[5] = translate[7] = (center->y + dstrect->y);
   5.241  
   5.242 -    /* Activate an appropriate shader and set the projection matrix */
   5.243 -    blendMode = texture->blendMode;
   5.244 -    if (renderer->target) {
   5.245 -        /* Check if we need to do color mapping between the source and render target textures */
   5.246 -        if (renderer->target->format != texture->format) {
   5.247 -            switch (texture->format)
   5.248 -            {
   5.249 -            case SDL_PIXELFORMAT_ARGB8888:
   5.250 -                switch (renderer->target->format)
   5.251 -                {
   5.252 -                    case SDL_PIXELFORMAT_ABGR8888:
   5.253 -                    case SDL_PIXELFORMAT_BGR888:
   5.254 -                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
   5.255 -                        break;
   5.256 -                    case SDL_PIXELFORMAT_RGB888:
   5.257 -                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
   5.258 -                        break;
   5.259 -                }
   5.260 -                break;
   5.261 -            case SDL_PIXELFORMAT_ABGR8888:
   5.262 -                switch (renderer->target->format)
   5.263 -                {
   5.264 -                    case SDL_PIXELFORMAT_ARGB8888:
   5.265 -                    case SDL_PIXELFORMAT_RGB888:
   5.266 -                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
   5.267 -                        break;
   5.268 -                    case SDL_PIXELFORMAT_BGR888:
   5.269 -                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
   5.270 -                        break;
   5.271 -                }
   5.272 -                break;
   5.273 -            case SDL_PIXELFORMAT_RGB888:
   5.274 -                switch (renderer->target->format)
   5.275 -                {
   5.276 -                    case SDL_PIXELFORMAT_ABGR8888:
   5.277 -                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
   5.278 -                        break;
   5.279 -                    case SDL_PIXELFORMAT_ARGB8888:
   5.280 -                        sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
   5.281 -                        break;
   5.282 -                    case SDL_PIXELFORMAT_BGR888:
   5.283 -                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
   5.284 -                        break;
   5.285 -                }
   5.286 -                break;
   5.287 -            case SDL_PIXELFORMAT_BGR888:
   5.288 -                switch (renderer->target->format)
   5.289 -                {
   5.290 -                    case SDL_PIXELFORMAT_ABGR8888:
   5.291 -                        sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
   5.292 -                        break;
   5.293 -                    case SDL_PIXELFORMAT_ARGB8888:
   5.294 -                        sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
   5.295 -                        break;
   5.296 -                    case SDL_PIXELFORMAT_RGB888:
   5.297 -                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
   5.298 -                        break;
   5.299 -                }
   5.300 -                break;
   5.301 -            }
   5.302 -        }
   5.303 -        else sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;   /* Texture formats match, use the non color mapping shader (even if the formats are not ABGR) */
   5.304 -    }
   5.305 -    else {
   5.306 -        switch (texture->format)
   5.307 -        {
   5.308 -            case SDL_PIXELFORMAT_ARGB8888:
   5.309 -                sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
   5.310 -                break;
   5.311 -            case SDL_PIXELFORMAT_ABGR8888:
   5.312 -                sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
   5.313 -                break;
   5.314 -            case SDL_PIXELFORMAT_RGB888:
   5.315 -                sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
   5.316 -                break;
   5.317 -            case SDL_PIXELFORMAT_BGR888:
   5.318 -                sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
   5.319 -                break;
   5.320 -            default:
   5.321 -                return -1;
   5.322 -        }
   5.323 -    }
   5.324 -    if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0)
   5.325 -        return -1;
   5.326 -
   5.327 -    /* Select the target texture */
   5.328 -    data->glBindTexture(tdata->texture_type, tdata->texture);
   5.329 -
   5.330 -    /* Configure color modulation */
   5.331 -    /* !!! FIXME: grep for glUniform4f(), move that stuff to a subroutine, it's a lot of copy/paste. */
   5.332 -    g = texture->g;
   5.333 -    a = texture->a;
   5.334 -
   5.335 -    if (renderer->target &&
   5.336 -        (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
   5.337 -         renderer->target->format == SDL_PIXELFORMAT_RGB888)) {
   5.338 -        r = texture->b;
   5.339 -        b = texture->r;
   5.340 -    } else {
   5.341 -        r = texture->r;
   5.342 -        b = texture->b;
   5.343 -    }
   5.344 -
   5.345 -    program = data->current_program;
   5.346 -
   5.347 -    if (!CompareColors(program->modulation_r, program->modulation_g, program->modulation_b, program->modulation_a, r, g, b, a)) {
   5.348 -        data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_MODULATION], r * inv255f, g * inv255f, b * inv255f, a * inv255f);
   5.349 -        program->modulation_r = r;
   5.350 -        program->modulation_g = g;
   5.351 -        program->modulation_b = b;
   5.352 -        program->modulation_a = a;
   5.353 -    }
   5.354 -
   5.355 -    /* Configure texture blending */
   5.356 -    GLES2_SetBlendMode(data, blendMode);
   5.357 -
   5.358 -    GLES2_SetTexCoords(data, SDL_TRUE);
   5.359 -
   5.360      /* Emit the textured quad */
   5.361      vertices[0] = dstrect->x;
   5.362      vertices[1] = dstrect->y;
   5.363 @@ -2066,6 +2029,8 @@
   5.364  
   5.365      renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
   5.366      renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
   5.367 +    renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
   5.368 +    renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
   5.369  
   5.370      GLES2_ResetState(renderer);
   5.371  
     6.1 --- a/src/render/opengles2/SDL_shaders_gles2.c	Wed Aug 06 00:28:02 2014 -0700
     6.2 +++ b/src/render/opengles2/SDL_shaders_gles2.c	Wed Aug 06 11:34:54 2014 -0700
     6.3 @@ -150,6 +150,50 @@
     6.4      } \
     6.5  ";
     6.6  
     6.7 +/* NV12 to ABGR conversion */
     6.8 +static const Uint8 GLES2_FragmentSrc_TextureNV12Src_[] = " \
     6.9 +    precision mediump float; \
    6.10 +    uniform sampler2D u_texture; \
    6.11 +    uniform sampler2D u_texture_u; \
    6.12 +    uniform vec4 u_modulation; \
    6.13 +    varying vec2 v_texCoord; \
    6.14 +    \
    6.15 +    void main() \
    6.16 +    { \
    6.17 +        mediump vec3 yuv; \
    6.18 +        lowp vec3 rgb; \
    6.19 +        yuv.x = texture2D(u_texture,   v_texCoord).r; \
    6.20 +        yuv.yz = texture2D(u_texture_u, v_texCoord).ra - 0.5; \
    6.21 +        rgb = mat3( 1,        1,       1, \
    6.22 +                    0,       -0.39465, 2.03211, \
    6.23 +                    1.13983, -0.58060, 0) * yuv; \
    6.24 +        gl_FragColor = vec4(rgb, 1); \
    6.25 +        gl_FragColor *= u_modulation; \
    6.26 +    } \
    6.27 +";
    6.28 +
    6.29 +/* NV21 to ABGR conversion */
    6.30 +static const Uint8 GLES2_FragmentSrc_TextureNV21Src_[] = " \
    6.31 +    precision mediump float; \
    6.32 +    uniform sampler2D u_texture; \
    6.33 +    uniform sampler2D u_texture_u; \
    6.34 +    uniform vec4 u_modulation; \
    6.35 +    varying vec2 v_texCoord; \
    6.36 +    \
    6.37 +    void main() \
    6.38 +    { \
    6.39 +        mediump vec3 yuv; \
    6.40 +        lowp vec3 rgb; \
    6.41 +        yuv.x = texture2D(u_texture,   v_texCoord).r; \
    6.42 +        yuv.yz = texture2D(u_texture_u, v_texCoord).ar - 0.5; \
    6.43 +        rgb = mat3( 1,        1,       1, \
    6.44 +                    0,       -0.39465, 2.03211, \
    6.45 +                    1.13983, -0.58060, 0) * yuv; \
    6.46 +        gl_FragColor = vec4(rgb, 1); \
    6.47 +        gl_FragColor *= u_modulation; \
    6.48 +    } \
    6.49 +";
    6.50 +
    6.51  static const GLES2_ShaderInstance GLES2_VertexSrc_Default = {
    6.52      GL_VERTEX_SHADER,
    6.53      GLES2_SOURCE_SHADER,
    6.54 @@ -199,6 +243,20 @@
    6.55      GLES2_FragmentSrc_TextureYUVSrc_
    6.56  };
    6.57  
    6.58 +static const GLES2_ShaderInstance GLES2_FragmentSrc_TextureNV12Src = {
    6.59 +    GL_FRAGMENT_SHADER,
    6.60 +    GLES2_SOURCE_SHADER,
    6.61 +    sizeof(GLES2_FragmentSrc_TextureNV12Src_),
    6.62 +    GLES2_FragmentSrc_TextureNV12Src_
    6.63 +};
    6.64 +
    6.65 +static const GLES2_ShaderInstance GLES2_FragmentSrc_TextureNV21Src = {
    6.66 +    GL_FRAGMENT_SHADER,
    6.67 +    GLES2_SOURCE_SHADER,
    6.68 +    sizeof(GLES2_FragmentSrc_TextureNV21Src_),
    6.69 +    GLES2_FragmentSrc_TextureNV21Src_
    6.70 +};
    6.71 +
    6.72  
    6.73  /*************************************************************************************************
    6.74   * Vertex/fragment shader binaries (NVIDIA Tegra 1/2)                                            *
    6.75 @@ -731,6 +789,20 @@
    6.76      }
    6.77  };
    6.78  
    6.79 +static GLES2_Shader GLES2_FragmentShader_TextureNV12Src = {
    6.80 +    1,
    6.81 +    {
    6.82 +        &GLES2_FragmentSrc_TextureNV12Src
    6.83 +    }
    6.84 +};
    6.85 +
    6.86 +static GLES2_Shader GLES2_FragmentShader_TextureNV21Src = {
    6.87 +    1,
    6.88 +    {
    6.89 +        &GLES2_FragmentSrc_TextureNV21Src
    6.90 +    }
    6.91 +};
    6.92 +
    6.93  
    6.94  /*************************************************************************************************
    6.95   * Shader selector                                                                               *
    6.96 @@ -820,6 +892,16 @@
    6.97          return &GLES2_FragmentShader_TextureYUVSrc;
    6.98      }
    6.99  
   6.100 +    case GLES2_SHADER_FRAGMENT_TEXTURE_NV12_SRC:
   6.101 +    {
   6.102 +        return &GLES2_FragmentShader_TextureNV12Src;
   6.103 +    }
   6.104 +
   6.105 +    case GLES2_SHADER_FRAGMENT_TEXTURE_NV21_SRC:
   6.106 +    {
   6.107 +        return &GLES2_FragmentShader_TextureNV21Src;
   6.108 +    }
   6.109 +
   6.110      default:
   6.111          return NULL;
   6.112      }
     7.1 --- a/src/render/opengles2/SDL_shaders_gles2.h	Wed Aug 06 00:28:02 2014 -0700
     7.2 +++ b/src/render/opengles2/SDL_shaders_gles2.h	Wed Aug 06 11:34:54 2014 -0700
     7.3 @@ -47,7 +47,9 @@
     7.4      GLES2_SHADER_FRAGMENT_TEXTURE_ARGB_SRC,
     7.5      GLES2_SHADER_FRAGMENT_TEXTURE_BGR_SRC,
     7.6      GLES2_SHADER_FRAGMENT_TEXTURE_RGB_SRC,
     7.7 -    GLES2_SHADER_FRAGMENT_TEXTURE_YUV_SRC
     7.8 +    GLES2_SHADER_FRAGMENT_TEXTURE_YUV_SRC,
     7.9 +    GLES2_SHADER_FRAGMENT_TEXTURE_NV12_SRC,
    7.10 +    GLES2_SHADER_FRAGMENT_TEXTURE_NV21_SRC
    7.11  } GLES2_ShaderType;
    7.12  
    7.13  #define GLES2_SOURCE_SHADER (GLenum)-1
     8.1 --- a/src/test/SDL_test_common.c	Wed Aug 06 00:28:02 2014 -0700
     8.2 +++ b/src/test/SDL_test_common.c	Wed Aug 06 11:34:54 2014 -0700
     8.3 @@ -572,6 +572,12 @@
     8.4      case SDL_PIXELFORMAT_YVYU:
     8.5          fprintf(stderr, "YVYU");
     8.6          break;
     8.7 +    case SDL_PIXELFORMAT_NV12:
     8.8 +        fprintf(stderr, "NV12");
     8.9 +        break;
    8.10 +    case SDL_PIXELFORMAT_NV21:
    8.11 +        fprintf(stderr, "NV21");
    8.12 +        break;
    8.13      default:
    8.14          fprintf(stderr, "0x%8.8x", format);
    8.15          break;
     9.1 --- a/src/video/SDL_pixels.c	Wed Aug 06 00:28:02 2014 -0700
     9.2 +++ b/src/video/SDL_pixels.c	Wed Aug 06 11:34:54 2014 -0700
     9.3 @@ -122,6 +122,8 @@
     9.4      CASE(SDL_PIXELFORMAT_YUY2)
     9.5      CASE(SDL_PIXELFORMAT_UYVY)
     9.6      CASE(SDL_PIXELFORMAT_YVYU)
     9.7 +    CASE(SDL_PIXELFORMAT_NV12)
     9.8 +    CASE(SDL_PIXELFORMAT_NV21)
     9.9  #undef CASE
    9.10      default:
    9.11          return "SDL_PIXELFORMAT_UNKNOWN";
    10.1 --- a/src/video/SDL_surface.c	Wed Aug 06 00:28:02 2014 -0700
    10.2 +++ b/src/video/SDL_surface.c	Wed Aug 06 11:34:54 2014 -0700
    10.3 @@ -1005,7 +1005,7 @@
    10.4      SDL_Rect rect;
    10.5      void *nonconst_src = (void *) src;
    10.6  
    10.7 -    /* Check to make sure we are bliting somewhere, so we don't crash */
    10.8 +    /* Check to make sure we are blitting somewhere, so we don't crash */
    10.9      if (!dst) {
   10.10          return SDL_InvalidParamError("dst");
   10.11      }
   10.12 @@ -1015,17 +1015,21 @@
   10.13  
   10.14      /* Fast path for same format copy */
   10.15      if (src_format == dst_format) {
   10.16 -        int bpp;
   10.17 +        int bpp, i;
   10.18  
   10.19          if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
   10.20              switch (src_format) {
   10.21 -            case SDL_PIXELFORMAT_YV12:
   10.22 -            case SDL_PIXELFORMAT_IYUV:
   10.23              case SDL_PIXELFORMAT_YUY2:
   10.24              case SDL_PIXELFORMAT_UYVY:
   10.25              case SDL_PIXELFORMAT_YVYU:
   10.26                  bpp = 2;
   10.27                  break;
   10.28 +            case SDL_PIXELFORMAT_YV12:
   10.29 +            case SDL_PIXELFORMAT_IYUV:
   10.30 +            case SDL_PIXELFORMAT_NV12:
   10.31 +            case SDL_PIXELFORMAT_NV21:
   10.32 +                bpp = 1;
   10.33 +                break;
   10.34              default:
   10.35                  return SDL_SetError("Unknown FOURCC pixel format");
   10.36              }
   10.37 @@ -1034,11 +1038,32 @@
   10.38          }
   10.39          width *= bpp;
   10.40  
   10.41 -        while (height-- > 0) {
   10.42 +        for (i = height; i--;) {
   10.43              SDL_memcpy(dst, src, width);
   10.44              src = (Uint8*)src + src_pitch;
   10.45              dst = (Uint8*)dst + dst_pitch;
   10.46          }
   10.47 +
   10.48 +        if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV) {
   10.49 +            /* U and V planes are a quarter the size of the Y plane */
   10.50 +            width /= 2;
   10.51 +            height /= 2;
   10.52 +            src_pitch /= 2;
   10.53 +            dst_pitch /= 2;
   10.54 +            for (i = height * 2; i--;) {
   10.55 +                SDL_memcpy(dst, src, width);
   10.56 +                src = (Uint8*)src + src_pitch;
   10.57 +                dst = (Uint8*)dst + dst_pitch;
   10.58 +            }
   10.59 +        } else if (src_format == SDL_PIXELFORMAT_NV12 || src_format == SDL_PIXELFORMAT_NV21) {
   10.60 +            /* U/V plane is half the height of the Y plane */
   10.61 +            height /= 2;
   10.62 +            for (i = height; i--;) {
   10.63 +                SDL_memcpy(dst, src, width);
   10.64 +                src = (Uint8*)src + src_pitch;
   10.65 +                dst = (Uint8*)dst + dst_pitch;
   10.66 +            }
   10.67 +        }
   10.68          return 0;
   10.69      }
   10.70  
    11.1 --- a/test/testautomation_pixels.c	Wed Aug 06 00:28:02 2014 -0700
    11.2 +++ b/test/testautomation_pixels.c	Wed Aug 06 11:34:54 2014 -0700
    11.3 @@ -79,14 +79,16 @@
    11.4    };
    11.5  
    11.6  /* Definition of all Non-RGB formats used to test pixel conversions */
    11.7 -const int _numNonRGBPixelFormats = 5;
    11.8 +const int _numNonRGBPixelFormats = 7;
    11.9  Uint32 _nonRGBPixelFormats[] =
   11.10    {
   11.11      SDL_PIXELFORMAT_YV12,
   11.12      SDL_PIXELFORMAT_IYUV,
   11.13      SDL_PIXELFORMAT_YUY2,
   11.14      SDL_PIXELFORMAT_UYVY,
   11.15 -    SDL_PIXELFORMAT_YVYU
   11.16 +    SDL_PIXELFORMAT_YVYU,
   11.17 +    SDL_PIXELFORMAT_NV12,
   11.18 +    SDL_PIXELFORMAT_NV21
   11.19    };
   11.20  char* _nonRGBPixelFormatsVerbose[] =
   11.21    {
   11.22 @@ -94,7 +96,9 @@
   11.23      "SDL_PIXELFORMAT_IYUV",
   11.24      "SDL_PIXELFORMAT_YUY2",
   11.25      "SDL_PIXELFORMAT_UYVY",
   11.26 -    "SDL_PIXELFORMAT_YVYU"
   11.27 +    "SDL_PIXELFORMAT_YVYU",
   11.28 +    "SDL_PIXELFORMAT_NV12",
   11.29 +    "SDL_PIXELFORMAT_NV21"
   11.30    };
   11.31  
   11.32  /* Definition of some invalid formats for negative tests */
    12.1 --- a/test/testoverlay2.c	Wed Aug 06 00:28:02 2014 -0700
    12.2 +++ b/test/testoverlay2.c	Wed Aug 06 11:34:54 2014 -0700
    12.3 @@ -206,6 +206,29 @@
    12.4      }
    12.5  }
    12.6  
    12.7 +void
    12.8 +ConvertRGBtoNV12(Uint8 *rgb, Uint8 *out, int w, int h,
    12.9 +                 int monochrome, int luminance)
   12.10 +{
   12.11 +    int x, y;
   12.12 +    int yuv[3];
   12.13 +    Uint8 *op[2];
   12.14 +
   12.15 +    op[0] = out;
   12.16 +    op[1] = op[0] + w*h;
   12.17 +    for (y = 0; y < h; ++y) {
   12.18 +        for (x = 0; x < w; ++x) {
   12.19 +            RGBtoYUV(rgb, yuv, monochrome, luminance);
   12.20 +            *(op[0]++) = yuv[0];
   12.21 +            if (x % 2 == 0 && y % 2 == 0) {
   12.22 +                *(op[1]++) = yuv[1];
   12.23 +                *(op[1]++) = yuv[2];
   12.24 +            }
   12.25 +            rgb += 3;
   12.26 +        }
   12.27 +    }
   12.28 +}
   12.29 +
   12.30  static void
   12.31  PrintUsage(char *argv0)
   12.32  {
   12.33 @@ -241,7 +264,11 @@
   12.34      int fps = 12;
   12.35      int fpsdelay;
   12.36      int nodelay = 0;
   12.37 +#ifdef TEST_NV12
   12.38 +    Uint32 pixel_format = SDL_PIXELFORMAT_NV12;
   12.39 +#else
   12.40      Uint32 pixel_format = SDL_PIXELFORMAT_YV12;
   12.41 +#endif
   12.42      int scale = 5;
   12.43      SDL_bool done = SDL_FALSE;
   12.44  
   12.45 @@ -371,7 +398,17 @@
   12.46              rgb[2] = MooseColors[frame[j]].b;
   12.47              rgb += 3;
   12.48          }
   12.49 -        ConvertRGBtoYV12(MooseFrameRGB, MooseFrame[i], MOOSEPIC_W, MOOSEPIC_H, 0, 100);
   12.50 +        switch (pixel_format) {
   12.51 +        case SDL_PIXELFORMAT_YV12:
   12.52 +            ConvertRGBtoYV12(MooseFrameRGB, MooseFrame[i], MOOSEPIC_W, MOOSEPIC_H, 0, 100);
   12.53 +            break;
   12.54 +        case SDL_PIXELFORMAT_NV12:
   12.55 +            ConvertRGBtoNV12(MooseFrameRGB, MooseFrame[i], MOOSEPIC_W, MOOSEPIC_H, 0, 100);
   12.56 +            break;
   12.57 +        default:
   12.58 +            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unsupported pixel format\n");
   12.59 +            break;
   12.60 +        }
   12.61      }
   12.62  
   12.63      free(RawMooseData);