mirror of https://github.com/encounter/SDL.git
Added optimized YUV texture upload path with SDL_UpdateYUVTexture()
This commit is contained in:
parent
d0a57ea2b5
commit
57bd514707
|
@ -381,6 +381,31 @@ extern DECLSPEC int SDLCALL SDL_UpdateTexture(SDL_Texture * texture,
|
||||||
const SDL_Rect * rect,
|
const SDL_Rect * rect,
|
||||||
const void *pixels, int pitch);
|
const void *pixels, int pitch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Update a rectangle within a planar YV12 or IYUV texture with new pixel data.
|
||||||
|
*
|
||||||
|
* \param texture The texture to update
|
||||||
|
* \param rect A pointer to the rectangle of pixels to update, or NULL to
|
||||||
|
* update the entire texture.
|
||||||
|
* \param Yplane The raw pixel data for the Y plane.
|
||||||
|
* \param Ypitch The number of bytes between rows of pixel data for the Y plane.
|
||||||
|
* \param Uplane The raw pixel data for the U plane.
|
||||||
|
* \param Upitch The number of bytes between rows of pixel data for the U plane.
|
||||||
|
* \param Vplane The raw pixel data for the V plane.
|
||||||
|
* \param Vpitch The number of bytes between rows of pixel data for the V plane.
|
||||||
|
*
|
||||||
|
* \return 0 on success, or -1 if the texture is not valid.
|
||||||
|
*
|
||||||
|
* \note You can use SDL_UpdateTexture() as long as your pixel data is
|
||||||
|
* a contiguous block of Y and U/V planes in the proper order, but
|
||||||
|
* this function is available if your pixel data is not contiguous.
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_UpdateYUVTexture(SDL_Texture * texture,
|
||||||
|
const SDL_Rect * rect,
|
||||||
|
const Uint8 *Yplane, int Ypitch,
|
||||||
|
const Uint8 *Uplane, int Upitch,
|
||||||
|
const Uint8 *Vplane, int Vpitch);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Lock a portion of the texture for write-only pixel access.
|
* \brief Lock a portion of the texture for write-only pixel access.
|
||||||
*
|
*
|
||||||
|
|
|
@ -804,6 +804,106 @@ SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
SDL_UpdateTextureYUVPlanar(SDL_Texture * texture, const SDL_Rect * rect,
|
||||||
|
const Uint8 *Yplane, int Ypitch,
|
||||||
|
const Uint8 *Uplane, int Upitch,
|
||||||
|
const Uint8 *Vplane, int Vpitch)
|
||||||
|
{
|
||||||
|
SDL_Texture *native = texture->native;
|
||||||
|
SDL_Rect full_rect;
|
||||||
|
|
||||||
|
if (SDL_SW_UpdateYUVTexturePlanar(texture->yuv, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
full_rect.x = 0;
|
||||||
|
full_rect.y = 0;
|
||||||
|
full_rect.w = texture->w;
|
||||||
|
full_rect.h = texture->h;
|
||||||
|
rect = &full_rect;
|
||||||
|
|
||||||
|
if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
|
||||||
|
/* We can lock the texture and copy to it */
|
||||||
|
void *native_pixels;
|
||||||
|
int native_pitch;
|
||||||
|
|
||||||
|
if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
|
||||||
|
rect->w, rect->h, native_pixels, native_pitch);
|
||||||
|
SDL_UnlockTexture(native);
|
||||||
|
} else {
|
||||||
|
/* Use a temporary buffer for updating */
|
||||||
|
void *temp_pixels;
|
||||||
|
int temp_pitch;
|
||||||
|
|
||||||
|
temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3);
|
||||||
|
temp_pixels = SDL_malloc(rect->h * temp_pitch);
|
||||||
|
if (!temp_pixels) {
|
||||||
|
return SDL_OutOfMemory();
|
||||||
|
}
|
||||||
|
SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format,
|
||||||
|
rect->w, rect->h, temp_pixels, temp_pitch);
|
||||||
|
SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch);
|
||||||
|
SDL_free(temp_pixels);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_UpdateYUVTexture(SDL_Texture * texture, const SDL_Rect * rect,
|
||||||
|
const Uint8 *Yplane, int Ypitch,
|
||||||
|
const Uint8 *Uplane, int Upitch,
|
||||||
|
const Uint8 *Vplane, int Vpitch)
|
||||||
|
{
|
||||||
|
SDL_Renderer *renderer;
|
||||||
|
SDL_Rect full_rect;
|
||||||
|
|
||||||
|
CHECK_TEXTURE_MAGIC(texture, -1);
|
||||||
|
|
||||||
|
if (!Yplane) {
|
||||||
|
return SDL_InvalidParamError("Yplane");
|
||||||
|
}
|
||||||
|
if (!Ypitch) {
|
||||||
|
return SDL_InvalidParamError("Ypitch");
|
||||||
|
}
|
||||||
|
if (!Uplane) {
|
||||||
|
return SDL_InvalidParamError("Uplane");
|
||||||
|
}
|
||||||
|
if (!Upitch) {
|
||||||
|
return SDL_InvalidParamError("Upitch");
|
||||||
|
}
|
||||||
|
if (!Vplane) {
|
||||||
|
return SDL_InvalidParamError("Vplane");
|
||||||
|
}
|
||||||
|
if (!Vpitch) {
|
||||||
|
return SDL_InvalidParamError("Vpitch");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture->format != SDL_PIXELFORMAT_YV12 &&
|
||||||
|
texture->format != SDL_PIXELFORMAT_IYUV) {
|
||||||
|
return SDL_SetError("Texture format must by YV12 or IYUV");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rect) {
|
||||||
|
full_rect.x = 0;
|
||||||
|
full_rect.y = 0;
|
||||||
|
full_rect.w = texture->w;
|
||||||
|
full_rect.h = texture->h;
|
||||||
|
rect = &full_rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture->yuv) {
|
||||||
|
return SDL_UpdateTextureYUVPlanar(texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
|
||||||
|
} else {
|
||||||
|
SDL_assert(!texture->native);
|
||||||
|
renderer = texture->renderer;
|
||||||
|
SDL_assert(renderer->UpdateTextureYUV);
|
||||||
|
return renderer->UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
SDL_LockTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
|
SDL_LockTextureYUV(SDL_Texture * texture, const SDL_Rect * rect,
|
||||||
void **pixels, int *pitch)
|
void **pixels, int *pitch)
|
||||||
|
|
|
@ -89,6 +89,11 @@ struct SDL_Renderer
|
||||||
int (*UpdateTexture) (SDL_Renderer * renderer, SDL_Texture * texture,
|
int (*UpdateTexture) (SDL_Renderer * renderer, SDL_Texture * texture,
|
||||||
const SDL_Rect * rect, const void *pixels,
|
const SDL_Rect * rect, const void *pixels,
|
||||||
int pitch);
|
int pitch);
|
||||||
|
int (*UpdateTextureYUV) (SDL_Renderer * renderer, SDL_Texture * texture,
|
||||||
|
const SDL_Rect * rect,
|
||||||
|
const Uint8 *Yplane, int Ypitch,
|
||||||
|
const Uint8 *Uplane, int Upitch,
|
||||||
|
const Uint8 *Vplane, int Vpitch);
|
||||||
int (*LockTexture) (SDL_Renderer * renderer, SDL_Texture * texture,
|
int (*LockTexture) (SDL_Renderer * renderer, SDL_Texture * texture,
|
||||||
const SDL_Rect * rect, void **pixels, int *pitch);
|
const SDL_Rect * rect, void **pixels, int *pitch);
|
||||||
void (*UnlockTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
|
void (*UnlockTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
|
||||||
|
|
|
@ -1184,6 +1184,60 @@ SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
|
||||||
|
const Uint8 *Yplane, int Ypitch,
|
||||||
|
const Uint8 *Uplane, int Upitch,
|
||||||
|
const Uint8 *Vplane, int Vpitch)
|
||||||
|
{
|
||||||
|
Uint8 *src, *dst;
|
||||||
|
int row;
|
||||||
|
size_t length;
|
||||||
|
|
||||||
|
/* Copy the Y plane */
|
||||||
|
src = Yplane;
|
||||||
|
dst = swdata->pixels + rect->y * swdata->w + rect->x;
|
||||||
|
length = rect->w;
|
||||||
|
for (row = 0; row < rect->h; ++row) {
|
||||||
|
SDL_memcpy(dst, src, length);
|
||||||
|
src += Ypitch;
|
||||||
|
dst += swdata->w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the U plane */
|
||||||
|
src = Uplane;
|
||||||
|
if (swdata->format == SDL_PIXELFORMAT_IYUV) {
|
||||||
|
dst = swdata->pixels + swdata->h * swdata->w;
|
||||||
|
} else {
|
||||||
|
dst = swdata->pixels + swdata->h * swdata->w +
|
||||||
|
(swdata->h * swdata->w) / 4;
|
||||||
|
}
|
||||||
|
dst += rect->y/2 * swdata->w/2 + rect->x/2;
|
||||||
|
length = rect->w / 2;
|
||||||
|
for (row = 0; row < rect->h/2; ++row) {
|
||||||
|
SDL_memcpy(dst, src, length);
|
||||||
|
src += Upitch;
|
||||||
|
dst += swdata->w/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the V plane */
|
||||||
|
src = Vplane;
|
||||||
|
if (swdata->format == SDL_PIXELFORMAT_YV12) {
|
||||||
|
dst = swdata->pixels + swdata->h * swdata->w;
|
||||||
|
} else {
|
||||||
|
dst = swdata->pixels + swdata->h * swdata->w +
|
||||||
|
(swdata->h * swdata->w) / 4;
|
||||||
|
}
|
||||||
|
dst += rect->y/2 * swdata->w/2 + rect->x/2;
|
||||||
|
length = rect->w / 2;
|
||||||
|
for (row = 0; row < rect->h/2; ++row) {
|
||||||
|
SDL_memcpy(dst, src, length);
|
||||||
|
src += Vpitch;
|
||||||
|
dst += swdata->w/2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
|
SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
|
||||||
void **pixels, int *pitch)
|
void **pixels, int *pitch)
|
||||||
|
|
|
@ -57,6 +57,10 @@ int SDL_SW_QueryYUVTexturePixels(SDL_SW_YUVTexture * swdata, void **pixels,
|
||||||
int *pitch);
|
int *pitch);
|
||||||
int SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
|
int SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
|
||||||
const void *pixels, int pitch);
|
const void *pixels, int pitch);
|
||||||
|
int SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
|
||||||
|
const Uint8 *Yplane, int Ypitch,
|
||||||
|
const Uint8 *Uplane, int Upitch,
|
||||||
|
const Uint8 *Vplane, int Vpitch);
|
||||||
int SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
|
int SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
|
||||||
void **pixels, int *pitch);
|
void **pixels, int *pitch);
|
||||||
void SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture * swdata);
|
void SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture * swdata);
|
||||||
|
|
|
@ -52,6 +52,11 @@ static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
|
||||||
static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
|
static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||||
const SDL_Rect * rect, const void *pixels,
|
const SDL_Rect * rect, const void *pixels,
|
||||||
int pitch);
|
int pitch);
|
||||||
|
static int GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||||
|
const SDL_Rect * rect,
|
||||||
|
const Uint8 *Yplane, int Ypitch,
|
||||||
|
const Uint8 *Uplane, int Upitch,
|
||||||
|
const Uint8 *Vplane, int Vpitch);
|
||||||
static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
|
static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||||
const SDL_Rect * rect, void **pixels, int *pitch);
|
const SDL_Rect * rect, void **pixels, int *pitch);
|
||||||
static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
|
static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
|
||||||
|
@ -403,6 +408,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags)
|
||||||
renderer->GetOutputSize = GL_GetOutputSize;
|
renderer->GetOutputSize = GL_GetOutputSize;
|
||||||
renderer->CreateTexture = GL_CreateTexture;
|
renderer->CreateTexture = GL_CreateTexture;
|
||||||
renderer->UpdateTexture = GL_UpdateTexture;
|
renderer->UpdateTexture = GL_UpdateTexture;
|
||||||
|
renderer->UpdateTextureYUV = GL_UpdateTextureYUV;
|
||||||
renderer->LockTexture = GL_LockTexture;
|
renderer->LockTexture = GL_LockTexture;
|
||||||
renderer->UnlockTexture = GL_UnlockTexture;
|
renderer->UnlockTexture = GL_UnlockTexture;
|
||||||
renderer->SetRenderTarget = GL_SetRenderTarget;
|
renderer->SetRenderTarget = GL_SetRenderTarget;
|
||||||
|
@ -801,6 +807,41 @@ GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||||
return GL_CheckError("glTexSubImage2D()", renderer);
|
return GL_CheckError("glTexSubImage2D()", renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||||
|
const SDL_Rect * rect,
|
||||||
|
const Uint8 *Yplane, int Ypitch,
|
||||||
|
const Uint8 *Uplane, int Upitch,
|
||||||
|
const Uint8 *Vplane, int Vpitch)
|
||||||
|
{
|
||||||
|
GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
|
||||||
|
GL_TextureData *data = (GL_TextureData *) texture->driverdata;
|
||||||
|
|
||||||
|
GL_ActivateRenderer(renderer);
|
||||||
|
|
||||||
|
renderdata->glEnable(data->type);
|
||||||
|
renderdata->glBindTexture(data->type, data->texture);
|
||||||
|
renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Ypitch);
|
||||||
|
renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
|
||||||
|
rect->h, data->format, data->formattype,
|
||||||
|
Yplane);
|
||||||
|
|
||||||
|
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Upitch);
|
||||||
|
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, Uplane);
|
||||||
|
|
||||||
|
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Vpitch);
|
||||||
|
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, Vplane);
|
||||||
|
renderdata->glDisable(data->type);
|
||||||
|
return GL_CheckError("glTexSubImage2D()", renderer);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
|
GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||||
const SDL_Rect * rect, void **pixels, int *pitch)
|
const SDL_Rect * rect, void **pixels, int *pitch)
|
||||||
|
|
Loading…
Reference in New Issue