Skip to content

Commit

Permalink
Added NV12 and NV21 texture support for OpenGL and OpenGL ES 2.0 rend…
Browse files Browse the repository at this point in the history
…erers
  • Loading branch information
slouken committed Aug 6, 2014
1 parent 6299dae commit 6fef39d
Show file tree
Hide file tree
Showing 12 changed files with 456 additions and 183 deletions.
6 changes: 5 additions & 1 deletion include/SDL_pixels.h
Expand Up @@ -248,7 +248,11 @@ enum
SDL_PIXELFORMAT_UYVY = /**< Packed mode: U0+Y0+V0+Y1 (1 plane) */
SDL_DEFINE_PIXELFOURCC('U', 'Y', 'V', 'Y'),
SDL_PIXELFORMAT_YVYU = /**< Packed mode: Y0+V0+Y1+U0 (1 plane) */
SDL_DEFINE_PIXELFOURCC('Y', 'V', 'Y', 'U')
SDL_DEFINE_PIXELFOURCC('Y', 'V', 'Y', 'U'),
SDL_PIXELFORMAT_NV12 = /**< Planar mode: Y + U/V interleaved (2 planes) */
SDL_DEFINE_PIXELFOURCC('N', 'V', '1', '2'),
SDL_PIXELFORMAT_NV21 = /**< Planar mode: Y + V/U interleaved (2 planes) */
SDL_DEFINE_PIXELFOURCC('N', 'V', '2', '1')
};

typedef struct SDL_Color
Expand Down
116 changes: 80 additions & 36 deletions src/render/opengl/SDL_render_gl.c
Expand Up @@ -164,8 +164,9 @@ typedef struct
int pitch;
SDL_Rect locked_rect;

/* YV12 texture support */
/* YUV texture support */
SDL_bool yuv;
SDL_bool nv12;
GLuint utexture;
GLuint vtexture;

Expand Down Expand Up @@ -531,6 +532,8 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags)
if (data->shaders && data->num_texture_units >= 3) {
renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
}

#ifdef __MACOSX__
Expand Down Expand Up @@ -611,16 +614,18 @@ convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
break;
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
*internalFormat = GL_LUMINANCE;
*format = GL_LUMINANCE;
*type = GL_UNSIGNED_BYTE;
break;
#ifdef __MACOSX__
case SDL_PIXELFORMAT_UYVY:
*internalFormat = GL_RGB8;
*format = GL_YCBCR_422_APPLE;
*type = GL_UNSIGNED_SHORT_8_8_APPLE;
break;
*internalFormat = GL_RGB8;
*format = GL_YCBCR_422_APPLE;
*type = GL_UNSIGNED_SHORT_8_8_APPLE;
break;
#endif
default:
return SDL_FALSE;
Expand Down Expand Up @@ -672,6 +677,11 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
/* Need to add size for the U and V planes */
size += (2 * (texture->h * data->pitch) / 4);
}
if (texture->format == SDL_PIXELFORMAT_NV12 ||
texture->format == SDL_PIXELFORMAT_NV21) {
/* Need to add size for the U/V plane */
size += ((texture->h * data->pitch) / 2);
}
data->pixels = SDL_calloc(1, size);
if (!data->pixels) {
SDL_free(data);
Expand Down Expand Up @@ -801,6 +811,27 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
renderdata->glDisable(data->type);
}

if (texture->format == SDL_PIXELFORMAT_NV12 ||
texture->format == SDL_PIXELFORMAT_NV21) {
data->nv12 = SDL_TRUE;

renderdata->glGenTextures(1, &data->utexture);
renderdata->glEnable(data->type);

renderdata->glBindTexture(data->type, data->utexture);
renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
scaleMode);
renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
scaleMode);
renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
renderdata->glTexImage2D(data->type, 0, GL_LUMINANCE_ALPHA, texture_w/2,
texture_h/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
renderdata->glDisable(data->type);
}

return GL_CheckError("", renderer);
}

Expand Down Expand Up @@ -848,6 +879,17 @@ GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
rect->w/2, rect->h/2,
data->format, data->formattype, pixels);
}

if (data->nv12) {
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2));

/* Skip to the correct offset into the next texture */
pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
renderdata->glBindTexture(data->type, data->utexture);
renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
rect->w/2, rect->h/2,
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels);
}
renderdata->glDisable(data->type);

return GL_CheckError("glTexSubImage2D()", renderer);
Expand Down Expand Up @@ -1184,15 +1226,10 @@ GL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
}

static int
GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * srcrect, const SDL_FRect * dstrect)
GL_SetupCopy(SDL_Renderer * renderer, SDL_Texture * texture)
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
GLfloat minx, miny, maxx, maxy;
GLfloat minu, maxu, minv, maxv;

GL_ActivateRenderer(renderer);

data->glEnable(texturedata->type);
if (texturedata->yuv) {
Expand All @@ -1204,6 +1241,12 @@ GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,

data->glActiveTextureARB(GL_TEXTURE0_ARB);
}
if (texturedata->nv12) {
data->glActiveTextureARB(GL_TEXTURE1_ARB);
data->glBindTexture(texturedata->type, texturedata->utexture);

data->glActiveTextureARB(GL_TEXTURE0_ARB);
}
data->glBindTexture(texturedata->type, texturedata->texture);

if (texture->modMode) {
Expand All @@ -1215,10 +1258,33 @@ GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
GL_SetBlendMode(data, texture->blendMode);

if (texturedata->yuv) {
GL_SetShader(data, SHADER_YV12);
GL_SetShader(data, SHADER_YUV);
} else if (texturedata->nv12) {
if (texture->format == SDL_PIXELFORMAT_NV12) {
GL_SetShader(data, SHADER_NV12);
} else {
GL_SetShader(data, SHADER_NV21);
}
} else {
GL_SetShader(data, SHADER_RGB);
}
return 0;
}

static int
GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * srcrect, const SDL_FRect * dstrect)
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
GLfloat minx, miny, maxx, maxy;
GLfloat minu, maxu, minv, maxv;

GL_ActivateRenderer(renderer);

if (GL_SetupCopy(renderer, texture) < 0) {
return -1;
}

minx = dstrect->x;
miny = dstrect->y;
Expand Down Expand Up @@ -1263,30 +1329,8 @@ GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,

GL_ActivateRenderer(renderer);

data->glEnable(texturedata->type);
if (texturedata->yuv) {
data->glActiveTextureARB(GL_TEXTURE2_ARB);
data->glBindTexture(texturedata->type, texturedata->vtexture);

data->glActiveTextureARB(GL_TEXTURE1_ARB);
data->glBindTexture(texturedata->type, texturedata->utexture);

data->glActiveTextureARB(GL_TEXTURE0_ARB);
}
data->glBindTexture(texturedata->type, texturedata->texture);

if (texture->modMode) {
GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
} else {
GL_SetColor(data, 255, 255, 255, 255);
}

GL_SetBlendMode(data, texture->blendMode);

if (texturedata->yuv) {
GL_SetShader(data, SHADER_YV12);
} else {
GL_SetShader(data, SHADER_RGB);
if (GL_SetupCopy(renderer, texture) < 0) {
return -1;
}

centerx = center->x;
Expand Down
102 changes: 101 additions & 1 deletion src/render/opengl/SDL_shaders_gl.c
Expand Up @@ -113,7 +113,7 @@ static const char *shader_source[NUM_SHADERS][2] =
"}"
},

/* SHADER_YV12 */
/* SHADER_YUV */
{
/* vertex shader */
"varying vec4 v_color;\n"
Expand Down Expand Up @@ -162,6 +162,106 @@ static const char *shader_source[NUM_SHADERS][2] =
"\n"
" // That was easy. :) \n"
" gl_FragColor = vec4(rgb, 1.0) * v_color;\n"
"}"
},

/* SHADER_NV12 */
{
/* vertex shader */
"varying vec4 v_color;\n"
"varying vec2 v_texCoord;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
" v_color = gl_Color;\n"
" v_texCoord = vec2(gl_MultiTexCoord0);\n"
"}",
/* fragment shader */
"varying vec4 v_color;\n"
"varying vec2 v_texCoord;\n"
"uniform sampler2D tex0; // Y \n"
"uniform sampler2D tex1; // U/V \n"
"\n"
"// YUV offset \n"
"const vec3 offset = vec3(-0.0627451017, -0.501960814, -0.501960814);\n"
"\n"
"// RGB coefficients \n"
"const vec3 Rcoeff = vec3(1.164, 0.000, 1.596);\n"
"const vec3 Gcoeff = vec3(1.164, -0.391, -0.813);\n"
"const vec3 Bcoeff = vec3(1.164, 2.018, 0.000);\n"
"\n"
"void main()\n"
"{\n"
" vec2 tcoord;\n"
" vec3 yuv, rgb;\n"
"\n"
" // Get the Y value \n"
" tcoord = v_texCoord;\n"
" yuv.x = texture2D(tex0, tcoord).r;\n"
"\n"
" // Get the U and V values \n"
" tcoord *= 0.5;\n"
" yuv.yz = texture2D(tex1, tcoord).ra;\n"
"\n"
" // Do the color transform \n"
" yuv += offset;\n"
" rgb.r = dot(yuv, Rcoeff);\n"
" rgb.g = dot(yuv, Gcoeff);\n"
" rgb.b = dot(yuv, Bcoeff);\n"
"\n"
" // That was easy. :) \n"
" gl_FragColor = vec4(rgb, 1.0) * v_color;\n"
"}"
},

/* SHADER_NV21 */
{
/* vertex shader */
"varying vec4 v_color;\n"
"varying vec2 v_texCoord;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
" v_color = gl_Color;\n"
" v_texCoord = vec2(gl_MultiTexCoord0);\n"
"}",
/* fragment shader */
"varying vec4 v_color;\n"
"varying vec2 v_texCoord;\n"
"uniform sampler2D tex0; // Y \n"
"uniform sampler2D tex1; // U/V \n"
"\n"
"// YUV offset \n"
"const vec3 offset = vec3(-0.0627451017, -0.501960814, -0.501960814);\n"
"\n"
"// RGB coefficients \n"
"const vec3 Rcoeff = vec3(1.164, 0.000, 1.596);\n"
"const vec3 Gcoeff = vec3(1.164, -0.391, -0.813);\n"
"const vec3 Bcoeff = vec3(1.164, 2.018, 0.000);\n"
"\n"
"void main()\n"
"{\n"
" vec2 tcoord;\n"
" vec3 yuv, rgb;\n"
"\n"
" // Get the Y value \n"
" tcoord = v_texCoord;\n"
" yuv.x = texture2D(tex0, tcoord).r;\n"
"\n"
" // Get the U and V values \n"
" tcoord *= 0.5;\n"
" yuv.yz = texture2D(tex1, tcoord).ar;\n"
"\n"
" // Do the color transform \n"
" yuv += offset;\n"
" rgb.r = dot(yuv, Rcoeff);\n"
" rgb.g = dot(yuv, Gcoeff);\n"
" rgb.b = dot(yuv, Bcoeff);\n"
"\n"
" // That was easy. :) \n"
" gl_FragColor = vec4(rgb, 1.0) * v_color;\n"
"}"
},
};
Expand Down
4 changes: 3 additions & 1 deletion src/render/opengl/SDL_shaders_gl.h
Expand Up @@ -26,7 +26,9 @@ typedef enum {
SHADER_NONE,
SHADER_SOLID,
SHADER_RGB,
SHADER_YV12,
SHADER_YUV,
SHADER_NV12,
SHADER_NV21,
NUM_SHADERS
} GL_Shader;

Expand Down

0 comments on commit 6fef39d

Please sign in to comment.