Navigation Menu

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.