From 8255dd8b9f4140d668e634b46f58f73ba7c45a45 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 12 Feb 2011 00:25:02 -0800 Subject: [PATCH] Initial pass at shader YV12 support - doesn't quite work yet. --- include/SDL_pixels.h | 4 +- src/render/opengl/SDL_render_gl.c | 104 ++++++++++++++++++++++++++++-- test/testoverlay2.c | 16 ++--- 3 files changed, 109 insertions(+), 15 deletions(-) diff --git a/include/SDL_pixels.h b/include/SDL_pixels.h index 0eea505f5..e112894f0 100644 --- a/include/SDL_pixels.h +++ b/include/SDL_pixels.h @@ -124,9 +124,7 @@ enum #define SDL_BITSPERPIXEL(X) (((X) >> 8) & 0xFF) #define SDL_BYTESPERPIXEL(X) \ (SDL_ISPIXELFORMAT_FOURCC(X) ? \ - ((((X) == SDL_PIXELFORMAT_YV12) || \ - ((X) == SDL_PIXELFORMAT_IYUV) || \ - ((X) == SDL_PIXELFORMAT_YUY2) || \ + ((((X) == SDL_PIXELFORMAT_YUY2) || \ ((X) == SDL_PIXELFORMAT_UYVY) || \ ((X) == SDL_PIXELFORMAT_YVYU)) ? 2 : 1) : (((X) >> 0) & 0xFF)) diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index f5c818c8e..3368d8942 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -119,6 +119,11 @@ typedef struct void *pixels; int pitch; SDL_Rect locked_rect; + + /* YV12 texture support */ + SDL_bool yuv; + GLuint utexture; + GLuint vtexture; } GL_TextureData; @@ -292,12 +297,11 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s", data->shaders ? "ENABLED" : "DISABLED"); -#if 0 /* We support YV12 textures using 3 textures and a shader */ 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; } -#endif /* Set up parameters for rendering */ data->blendMode = -1; @@ -372,6 +376,12 @@ convert_format(GL_RenderData *renderdata, Uint32 pixel_format, *format = GL_BGRA; *type = GL_UNSIGNED_INT_8_8_8_8_REV; break; + case SDL_PIXELFORMAT_YV12: + case SDL_PIXELFORMAT_IYUV: + *internalFormat = GL_LUMINANCE; + *format = GL_LUMINANCE; + *type = GL_UNSIGNED_BYTE; + break; default: return SDL_FALSE; } @@ -404,8 +414,15 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) } if (texture->access == SDL_TEXTUREACCESS_STREAMING) { + size_t size; data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format); - data->pixels = SDL_malloc(texture->h * data->pitch); + size = texture->h * data->pitch; + if (texture->format == SDL_PIXELFORMAT_YV12 || + texture->format == SDL_PIXELFORMAT_IYUV) { + /* Need to add size for the U and V planes */ + size += (2 * (texture->h * data->pitch) / 4); + } + data->pixels = SDL_malloc(size); if (!data->pixels) { SDL_OutOfMemory(); SDL_free(data); @@ -478,6 +495,41 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) GL_SetError("glTexImage2D()", result); return -1; } + + if (texture->format == SDL_PIXELFORMAT_YV12 || + texture->format == SDL_PIXELFORMAT_IYUV) { + data->yuv = SDL_TRUE; + + renderdata->glGenTextures(1, &data->utexture); + renderdata->glGenTextures(1, &data->vtexture); + renderdata->glEnable(data->type); + + renderdata->glBindTexture(data->type, data->utexture); + renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + 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, internalFormat, texture_w/2, + texture_h/2, 0, format, type, NULL); + + renderdata->glBindTexture(data->type, data->vtexture); + renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + 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, internalFormat, texture_w/2, + texture_h/2, 0, format, type, NULL); + + renderdata->glDisable(data->type); + } return 0; } @@ -500,6 +552,35 @@ GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w, rect->h, data->format, data->formattype, pixels); + if (data->yuv) { + /* Skip to the top of the next texture */ + const void *top = (const void*)((const Uint8*)pixels + (texture->h-rect->y) * pitch - rect->x); + + /* Skip to the correct offset into the next texture */ + pixels = (const void*)((const Uint8*)top + (rect->y / 2) * pitch + rect->x / 2); + if (texture->format == SDL_PIXELFORMAT_YV12) { + renderdata->glBindTexture(data->type, data->vtexture); + } else { + renderdata->glBindTexture(data->type, data->utexture); + } + renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2, + rect->w/2, rect->h/2, + data->format, data->formattype, pixels); + + /* Skip to the top of the next texture */ + top = (const void*)((const Uint8*)top + (texture->h * pitch)/4); + + /* Skip to the correct offset into the next texture */ + pixels = (const void*)((const Uint8*)top + (rect->y / 2) * pitch + rect->x / 2); + if (texture->format == SDL_PIXELFORMAT_YV12) { + renderdata->glBindTexture(data->type, data->utexture); + } else { + renderdata->glBindTexture(data->type, data->vtexture); + } + renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2, + rect->w/2, rect->h/2, + data->format, data->formattype, pixels); + } renderdata->glDisable(data->type); result = renderdata->glGetError(); if (result != GL_NO_ERROR) { @@ -750,6 +831,13 @@ GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, maxv *= texturedata->texh; 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) { @@ -762,7 +850,11 @@ GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, } GL_SetBlendMode(data, texture->blendMode); - GL_SelectShader(data->shaders, SHADER_RGB); + if (texturedata->yuv) { + GL_SelectShader(data->shaders, SHADER_YV12); + } else { + GL_SelectShader(data->shaders, SHADER_RGB); + } data->glBegin(GL_TRIANGLE_STRIP); data->glTexCoord2f(minu, minv); @@ -848,6 +940,10 @@ GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) if (data->texture) { renderdata->glDeleteTextures(1, &data->texture); } + if (data->yuv) { + renderdata->glDeleteTextures(1, &data->utexture); + renderdata->glDeleteTextures(1, &data->vtexture); + } if (data->pixels) { SDL_free(data->pixels); } diff --git a/test/testoverlay2.c b/test/testoverlay2.c index 2d6f092f3..5069c7ec0 100644 --- a/test/testoverlay2.c +++ b/test/testoverlay2.c @@ -360,7 +360,7 @@ main(int argc, char **argv) int fps = 12; int fpsdelay; int nodelay = 0; - int overlay_format = SDL_YUY2_OVERLAY; + Uint32 pixel_format = SDL_PIXELFORMAT_YV12; int scale = 5; SDL_bool done = SDL_FALSE; @@ -397,15 +397,15 @@ main(int argc, char **argv) } else if (strcmp(argv[1], "-format") == 0) { if (argv[2]) { if (!strcmp(argv[2], "YV12")) - overlay_format = SDL_YV12_OVERLAY; + pixel_format = SDL_PIXELFORMAT_YV12; else if (!strcmp(argv[2], "IYUV")) - overlay_format = SDL_IYUV_OVERLAY; + pixel_format = SDL_PIXELFORMAT_IYUV; else if (!strcmp(argv[2], "YUY2")) - overlay_format = SDL_YUY2_OVERLAY; + pixel_format = SDL_PIXELFORMAT_YUY2; else if (!strcmp(argv[2], "UYVY")) - overlay_format = SDL_UYVY_OVERLAY; + pixel_format = SDL_PIXELFORMAT_UYVY; else if (!strcmp(argv[2], "YVYU")) - overlay_format = SDL_YVYU_OVERLAY; + pixel_format = SDL_PIXELFORMAT_YVYU; else { fprintf(stderr, "The -format option %s is not recognized, see help for info.\n", @@ -490,7 +490,7 @@ main(int argc, char **argv) quit(4); } - MooseTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, MOOSEPIC_W, MOOSEPIC_H); + MooseTexture = SDL_CreateTexture(renderer, pixel_format, SDL_TEXTUREACCESS_STREAMING, MOOSEPIC_W, MOOSEPIC_H); if (!MooseTexture) { fprintf(stderr, "Couldn't set create texture: %s\n", SDL_GetError()); free(RawMooseData); @@ -569,7 +569,7 @@ main(int argc, char **argv) if (!paused) { i = (i + 1) % MOOSEFRAMES_COUNT; - SDL_UpdateTexture(MooseTexture, NULL, MooseFrame[i], MOOSEPIC_W*2); + SDL_UpdateTexture(MooseTexture, NULL, MooseFrame[i], MOOSEPIC_W*SDL_BYTESPERPIXEL(pixel_format)); } SDL_RenderClear(renderer); SDL_RenderCopy(renderer, MooseTexture, NULL, &displayrect);