# HG changeset patch # User Sam Lantinga # Date 1150612541 0 # Node ID c4aa1a2f48f174c533baa851f834fa1fe0a6cc34 # Parent 396a35389351cd854fe55c47a7f4c9548736de53 Software YUV texture support in progress... diff -r 396a35389351 -r c4aa1a2f48f1 include/SDL_pixels.h --- a/include/SDL_pixels.h Sat Jun 17 06:45:14 2006 +0000 +++ b/include/SDL_pixels.h Sun Jun 18 06:35:41 2006 +0000 @@ -179,11 +179,16 @@ SDL_DEFINE_PIXELFORMAT(SDL_PixelType_Packed32, SDL_PackedOrder_ARGB, SDL_PackedLayout_2101010, 32, 4), - SDL_PixelFormat_YV12 = SDL_DEFINE_PIXELFOURCC('Y', 'V', '1', '2'), - SDL_PixelFormat_IYUV = SDL_DEFINE_PIXELFOURCC('I', 'Y', 'U', 'V'), - SDL_PixelFormat_YUY2 = SDL_DEFINE_PIXELFOURCC('Y', 'U', 'Y', '2'), - SDL_PixelFormat_UYVY = SDL_DEFINE_PIXELFOURCC('U', 'Y', 'V', 'Y'), - SDL_PixelFormat_YVYU = SDL_DEFINE_PIXELFOURCC('Y', 'V', 'Y', 'U'), + SDL_PixelFormat_YV12 = /* Planar mode: Y + V + U (3 planes) */ + SDL_DEFINE_PIXELFOURCC('Y', 'V', '1', '2'), + SDL_PixelFormat_IYUV = /* Planar mode: Y + U + V (3 planes) */ + SDL_DEFINE_PIXELFOURCC('I', 'Y', 'U', 'V'), + SDL_PixelFormat_YUY2 = /* Packed mode: Y0+U0+Y1+V0 (1 plane) */ + SDL_DEFINE_PIXELFOURCC('Y', 'U', 'Y', '2'), + 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'), }; typedef struct SDL_Color diff -r 396a35389351 -r c4aa1a2f48f1 src/SDL_compat.c --- a/src/SDL_compat.c Sat Jun 17 06:45:14 2006 +0000 +++ b/src/SDL_compat.c Sun Jun 18 06:35:41 2006 +0000 @@ -1176,121 +1176,159 @@ SDL_memset(SDL_cursor->save[0], 0, savelen); } } +#endif + +struct private_yuvhwdata +{ + Uint16 pitches[3]; + Uint8 *planes[3]; + + SDL_TextureID textureID; +}; SDL_Overlay * SDL_CreateYUVOverlay(int w, int h, Uint32 format, SDL_Surface * display) { - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - SDL_Window *window; - const char *yuv_hwaccel; SDL_Overlay *overlay; + Uint32 texture_format; - window = SDL_GetWindowFromSurface(display); - if (window && (window->flags & SDL_WINDOW_OPENGL)) { + if ((display->flags & SDL_OPENGL) == SDL_OPENGL) { SDL_SetError("YUV overlays are not supported in OpenGL mode"); return NULL; } - /* Display directly on video surface, if possible */ - if (SDL_getenv("SDL_VIDEO_YUV_DIRECT")) { - if (window && - ((window->surface->format->BytesPerPixel == 2) || - (window->surface->format->BytesPerPixel == 4))) { - display = window->surface; - } + if (display != SDL_PublicSurface) { + SDL_SetError("YUV display is only supported on the screen surface"); + return NULL; + } + + switch (format) { + case SDL_YV12_OVERLAY: + texture_format = SDL_PixelFormat_YV12; + break; + case SDL_IYUV_OVERLAY: + texture_format = SDL_PixelFormat_IYUV; + break; + case SDL_YUY2_OVERLAY: + texture_format = SDL_PixelFormat_YUY2; + break; + case SDL_UYVY_OVERLAY: + texture_format = SDL_PixelFormat_UYVY; + break; + case SDL_YVYU_OVERLAY: + texture_format = SDL_PixelFormat_YVYU; + break; + default: + SDL_SetError("Unknown YUV format"); + return NULL; + } + + overlay = (SDL_Overlay *) SDL_malloc(sizeof(*overlay)); + if (!overlay) { + SDL_OutOfMemory(); + return NULL; } - overlay = NULL; - yuv_hwaccel = SDL_getenv("SDL_VIDEO_YUV_HWACCEL"); - if (((display->flags & SDL_SCREEN_SURFACE) && _this->CreateYUVOverlay) && - (!yuv_hwaccel || (SDL_atoi(yuv_hwaccel) > 0))) { - overlay = _this->CreateYUVOverlay(_this, w, h, format, display); + SDL_zerop(overlay); + + overlay->hwdata = + (struct private_yuvhwdata *) SDL_malloc(sizeof(*overlay->hwdata)); + if (!overlay->hwdata) { + SDL_free(overlay); + SDL_OutOfMemory(); + return NULL; + } + + overlay->format = format; + overlay->w = w; + overlay->h = h; + if (format == SDL_YV12_OVERLAY || format == SDL_IYUV_OVERLAY) { + overlay->planes = 3; + } else { + overlay->planes = 1; } - /* If hardware YUV overlay failed ... */ - if (overlay == NULL) { - overlay = SDL_CreateYUV_SW(_this, w, h, format, display); + overlay->pitches = overlay->hwdata->pitches; + overlay->pixels = overlay->hwdata->planes; + + switch (format) { + case SDL_YV12_OVERLAY: + case SDL_IYUV_OVERLAY: + overlay->pitches[0] = overlay->w; + overlay->pitches[1] = overlay->w / 2; + overlay->pitches[2] = overlay->w / 2; + break; + case SDL_YUY2_OVERLAY: + case SDL_UYVY_OVERLAY: + case SDL_YVYU_OVERLAY: + overlay->pitches[0] = overlay->h * 2; + break; } + + overlay->hwdata->textureID = + SDL_CreateTexture(texture_format, SDL_TextureAccess_Local, w, h); + if (!overlay->hwdata->textureID) { + SDL_FreeYUVOverlay(overlay); + return NULL; + } + return overlay; } int SDL_LockYUVOverlay(SDL_Overlay * overlay) { - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - return overlay->hwfuncs->Lock(_this, overlay); + void *pixels; + int pitch; + if (SDL_LockTexture(overlay->hwdata->textureID, NULL, 1, &pixels, &pitch) + < 0) { + return -1; + } + switch (overlay->format) { + case SDL_YV12_OVERLAY: + case SDL_IYUV_OVERLAY: + overlay->pixels[0] = (Uint8 *) pixels; + overlay->pixels[1] = + overlay->pixels[0] + overlay->pitches[0] * overlay->h; + overlay->pixels[2] = + overlay->pixels[1] + overlay->pitches[1] * overlay->h; + break; + case SDL_YUY2_OVERLAY: + case SDL_UYVY_OVERLAY: + case SDL_YVYU_OVERLAY: + overlay->pixels[0] = (Uint8 *) pixels; + break; + } + return 0; } void SDL_UnlockYUVOverlay(SDL_Overlay * overlay) { - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - overlay->hwfuncs->Unlock(_this, overlay); + SDL_UnlockTexture(overlay->hwdata->textureID); } int SDL_DisplayYUVOverlay(SDL_Overlay * overlay, SDL_Rect * dstrect) { - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - SDL_Rect src, dst; - int srcx, srcy, srcw, srch; - int dstx, dsty, dstw, dsth; - - /* Clip the rectangle to the screen area */ - srcx = 0; - srcy = 0; - srcw = overlay->w; - srch = overlay->h; - dstx = dstrect->x; - dsty = dstrect->y; - dstw = dstrect->w; - dsth = dstrect->h; - if (dstx < 0) { - srcw += (dstx * overlay->w) / dstrect->w; - dstw += dstx; - srcx -= (dstx * overlay->w) / dstrect->w; - dstx = 0; - } - if ((dstx + dstw) > SDL_VideoSurface->w) { - int extra = (dstx + dstw - SDL_VideoSurface->w); - srcw -= (extra * overlay->w) / dstrect->w; - dstw -= extra; + if (SDL_RenderCopy(overlay->hwdata->textureID, NULL, dstrect, + SDL_TextureBlendMode_None, + SDL_TextureScaleMode_Fast) < 0) { + return -1; } - if (dsty < 0) { - srch += (dsty * overlay->h) / dstrect->h; - dsth += dsty; - srcy -= (dsty * overlay->h) / dstrect->h; - dsty = 0; - } - if ((dsty + dsth) > SDL_VideoSurface->h) { - int extra = (dsty + dsth - SDL_VideoSurface->h); - srch -= (extra * overlay->h) / dstrect->h; - dsth -= extra; - } - if (srcw <= 0 || srch <= 0 || srch <= 0 || dsth <= 0) { - return 0; - } - /* Ugh, I can't wait for SDL_Rect to be int values */ - src.x = srcx; - src.y = srcy; - src.w = srcw; - src.h = srch; - dst.x = dstx; - dst.y = dsty; - dst.w = dstw; - dst.h = dsth; - return overlay->hwfuncs->Display(_this, overlay, &src, &dst); + SDL_RenderPresent(); } void SDL_FreeYUVOverlay(SDL_Overlay * overlay) { - SDL_VideoDevice *_this = SDL_GetVideoDevice(); if (overlay) { - if (overlay->hwfuncs) { - overlay->hwfuncs->FreeHW(_this, overlay); + if (overlay->hwdata) { + if (overlay->hwdata->textureID) { + SDL_DestroyTexture(overlay->hwdata->textureID); + } + SDL_free(overlay->hwdata); } SDL_free(overlay); } } -#endif /* vi: set ts=4 sw=4 expandtab: */ diff -r 396a35389351 -r c4aa1a2f48f1 src/video/SDL_renderer_sw.c --- a/src/video/SDL_renderer_sw.c Sat Jun 17 06:45:14 2006 +0000 +++ b/src/video/SDL_renderer_sw.c Sun Jun 18 06:35:41 2006 +0000 @@ -23,6 +23,7 @@ #include "SDL_video.h" #include "SDL_sysvideo.h" +#include "SDL_yuv_sw_c.h" /* SDL surface based renderer implementation */ @@ -205,29 +206,30 @@ static int SDL_SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { - SDL_Surface *surface; - int bpp; - Uint32 Rmask, Gmask, Bmask, Amask; + if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { + if (texture->access == SDL_TextureAccess_Render) { + SDL_SetError("Rendering to YUV format textures is not supported"); + return -1; + } + texture->driverdata = SDL_SW_CreateYUVTexture(texture); + } else { + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; - if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { - /* FIXME: implement this */ - return -1; + if (!SDL_PixelFormatEnumToMasks + (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { + SDL_SetError("Unknown texture format"); + return -1; + } + + texture->driverdata = + SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask, + Bmask, Amask); } - if (!SDL_PixelFormatEnumToMasks - (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { - SDL_SetError("Unknown texture format"); + if (!texture->driverdata) { return -1; } - - surface = - SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask, - Bmask, Amask); - if (!surface) { - return -1; - } - - texture->driverdata = surface; return 0; } @@ -235,11 +237,16 @@ SDL_SW_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, void **pixels, int *pitch) { - SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { + return SDL_SW_QueryYUVTexturePixels((SDL_SW_YUVTexture *) texture-> + driverdata, pixels, pitch); + } else { + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - *pixels = surface->pixels; - *pitch = surface->pitch; - return 0; + *pixels = surface->pixels; + *pitch = surface->pitch; + return 0; + } } static int @@ -247,43 +254,58 @@ const SDL_Color * colors, int firstcolor, int ncolors) { - SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { + SDL_SetError("YUV textures don't have a palette"); + return -1; + } else { + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - return SDL_SetPaletteColors(surface->format->palette, colors, firstcolor, - ncolors); + return SDL_SetPaletteColors(surface->format->palette, colors, + firstcolor, ncolors); + } } static int SDL_SW_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, SDL_Color * colors, int firstcolor, int ncolors) { - SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { + SDL_SetError("YUV textures don't have a palette"); + return -1; + } else { + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - SDL_memcpy(colors, &surface->format->palette->colors[firstcolor], - ncolors * sizeof(*colors)); - return 0; + SDL_memcpy(colors, &surface->format->palette->colors[firstcolor], + ncolors * sizeof(*colors)); + return 0; + } } static int SDL_SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, const void *pixels, int pitch) { - SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - Uint8 *src, *dst; - int row; - size_t length; + if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { + return SDL_SW_UpdateYUVTexture((SDL_SW_YUVTexture *) texture-> + driverdata, rect, pixels, pitch); + } else { + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + Uint8 *src, *dst; + int row; + size_t length; - src = (Uint8 *) pixels; - dst = - (Uint8 *) surface->pixels + rect->y * surface->pitch + - rect->x * surface->format->BytesPerPixel; - length = rect->w * surface->format->BytesPerPixel; - for (row = 0; row < rect->h; ++row) { - SDL_memcpy(dst, src, length); - src += pitch; - dst += surface->pitch; + src = (Uint8 *) pixels; + dst = + (Uint8 *) surface->pixels + rect->y * surface->pitch + + rect->x * surface->format->BytesPerPixel; + length = rect->w * surface->format->BytesPerPixel; + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += surface->pitch; + } + return 0; } - return 0; } static int @@ -291,18 +313,27 @@ const SDL_Rect * rect, int markDirty, void **pixels, int *pitch) { - SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { + return SDL_SW_LockYUVTexture((SDL_SW_YUVTexture *) texture-> + driverdata, rect, markDirty, pixels, + pitch); + } else { + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - *pixels = - (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch + - rect->x * surface->format->BytesPerPixel); - *pitch = surface->pitch; - return 0; + *pixels = + (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch + + rect->x * surface->format->BytesPerPixel); + *pitch = surface->pitch; + return 0; + } } static void SDL_SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) { + if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { + SDL_SW_UnlockYUVTexture((SDL_SW_YUVTexture *) texture->driverdata); + } } static void @@ -346,22 +377,36 @@ int blendMode, int scaleMode) { SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata; - SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - SDL_Rect real_srcrect = *srcrect; - SDL_Rect real_dstrect = *dstrect; - if (blendMode & (SDL_TextureBlendMode_Mask | SDL_TextureBlendMode_Blend)) { - SDL_SetAlpha(surface, SDL_SRCALPHA, 0); + if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { + SDL_Surface *target = data->target; + void *pixels = + (Uint8 *) target->pixels + dstrect->y * target->pitch + + dstrect->x * target->format->BytesPerPixel; + return SDL_SW_CopyYUVToRGB((SDL_SW_YUVTexture *) texture->driverdata, + srcrect, + renderer->window->display->current_mode. + format, dstrect->w, dstrect->h, pixels, + target->pitch); } else { - SDL_SetAlpha(surface, 0, 0); - } - if (scaleMode != SDL_TextureScaleMode_None && - (srcrect->w != dstrect->w || srcrect->h != dstrect->h)) { - return SDL_SoftStretch(surface, &real_srcrect, data->target, - &real_dstrect); - } else { - return SDL_LowerBlit(surface, &real_srcrect, data->target, - &real_dstrect); + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + SDL_Rect real_srcrect = *srcrect; + SDL_Rect real_dstrect = *dstrect; + + if (blendMode & + (SDL_TextureBlendMode_Mask | SDL_TextureBlendMode_Blend)) { + SDL_SetAlpha(surface, SDL_SRCALPHA, 0); + } else { + SDL_SetAlpha(surface, 0, 0); + } + if (scaleMode != SDL_TextureScaleMode_None && + (srcrect->w != dstrect->w || srcrect->h != dstrect->h)) { + return SDL_SoftStretch(surface, &real_srcrect, data->target, + &real_dstrect); + } else { + return SDL_LowerBlit(surface, &real_srcrect, data->target, + &real_dstrect); + } } } @@ -446,9 +491,13 @@ static void SDL_SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) { - SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { + SDL_SW_DestroyYUVTexture((SDL_SW_YUVTexture *) texture->driverdata); + } else { + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - SDL_FreeSurface(surface); + SDL_FreeSurface(surface); + } } static void diff -r 396a35389351 -r c4aa1a2f48f1 src/video/SDL_video.c --- a/src/video/SDL_video.c Sat Jun 17 06:45:14 2006 +0000 +++ b/src/video/SDL_video.c Sun Jun 18 06:35:41 2006 +0000 @@ -567,7 +567,7 @@ ncolors = 0; } if ((!ncolors && display->palette) || (ncolors && !display->palette) - || (ncolors != display->palette->ncolors)) { + || (ncolors && ncolors != display->palette->ncolors)) { if (display->palette) { SDL_FreePalette(display->palette); display->palette = NULL; @@ -1434,6 +1434,7 @@ { SDL_Texture *texture = SDL_GetTextureFromID(textureID); SDL_Renderer *renderer; + SDL_Rect full_rect; if (!texture) { return -1; @@ -1443,6 +1444,15 @@ if (!renderer->UpdateTexture) { return -1; } + + if (!rect) { + full_rect.x = 0; + full_rect.y = 0; + full_rect.w = texture->w; + full_rect.h = texture->h; + rect = &full_rect; + } + return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch); } @@ -1452,6 +1462,7 @@ { SDL_Texture *texture = SDL_GetTextureFromID(textureID); SDL_Renderer *renderer; + SDL_Rect full_rect; if (!texture) { return -1; @@ -1461,6 +1472,15 @@ if (!renderer->LockTexture) { return -1; } + + if (!rect) { + full_rect.x = 0; + full_rect.y = 0; + full_rect.w = texture->w; + full_rect.h = texture->h; + rect = &full_rect; + } + return renderer->LockTexture(renderer, texture, rect, markDirty, pixels, pitch); } @@ -1520,6 +1540,7 @@ SDL_RenderFill(const SDL_Rect * rect, Uint32 color) { SDL_Renderer *renderer; + SDL_Rect full_rect; if (!_this) { return -1; @@ -1530,6 +1551,14 @@ return -1; } + if (!rect) { + full_rect.x = 0; + full_rect.y = 0; + full_rect.w = renderer->window->w; + full_rect.h = renderer->window->h; + rect = &full_rect; + } + renderer->RenderFill(renderer, rect, color); } @@ -1539,6 +1568,8 @@ { SDL_Texture *texture = SDL_GetTextureFromID(textureID); SDL_Renderer *renderer; + SDL_Rect full_srcrect; + SDL_Rect full_dstrect; if (!texture || texture->renderer != SDL_CurrentDisplay.current_renderer) { return; @@ -1549,6 +1580,21 @@ return -1; } + if (!srcrect) { + full_srcrect.x = 0; + full_srcrect.y = 0; + full_srcrect.w = texture->w; + full_srcrect.h = texture->h; + srcrect = &full_srcrect; + } + if (!dstrect) { + full_dstrect.x = 0; + full_dstrect.y = 0; + full_dstrect.w = renderer->window->w; + full_dstrect.h = renderer->window->h; + dstrect = &full_dstrect; + } + return renderer->RenderCopy(renderer, texture, srcrect, dstrect, blendMode, scaleMode); } @@ -1557,6 +1603,7 @@ SDL_RenderReadPixels(const SDL_Rect * rect, void *pixels, int pitch) { SDL_Renderer *renderer; + SDL_Rect full_rect; if (!_this) { return -1; @@ -1567,6 +1614,14 @@ return -1; } + if (!rect) { + full_rect.x = 0; + full_rect.y = 0; + full_rect.w = renderer->window->w; + full_rect.h = renderer->window->h; + rect = &full_rect; + } + return renderer->RenderReadPixels(renderer, rect, pixels, pitch); } @@ -1574,6 +1629,7 @@ SDL_RenderWritePixels(const SDL_Rect * rect, const void *pixels, int pitch) { SDL_Renderer *renderer; + SDL_Rect full_rect; if (!_this) { return -1; @@ -1584,6 +1640,14 @@ return -1; } + if (!rect) { + full_rect.x = 0; + full_rect.y = 0; + full_rect.w = renderer->window->w; + full_rect.h = renderer->window->h; + rect = &full_rect; + } + return renderer->RenderWritePixels(renderer, rect, pixels, pitch); } diff -r 396a35389351 -r c4aa1a2f48f1 src/video/SDL_yuv_sw.c --- a/src/video/SDL_yuv_sw.c Sat Jun 17 06:45:14 2006 +0000 +++ b/src/video/SDL_yuv_sw.c Sun Jun 18 06:35:41 2006 +0000 @@ -21,8 +21,7 @@ */ #include "SDL_config.h" -#if 0 /* TODO */ -/* This is the software implementation of the YUV video overlay support */ +/* This is the software implementation of the YUV texture support */ /* This code was derived from code carrying the following copyright notices: @@ -87,22 +86,14 @@ #include "SDL_video.h" #include "SDL_cpuinfo.h" #include "SDL_stretch_c.h" -#include "SDL_yuvfuncs.h" #include "SDL_yuv_sw_c.h" -/* The functions used to manipulate software video overlays */ -static struct private_yuvhwfuncs sw_yuvfuncs = { - SDL_LockYUV_SW, - SDL_UnlockYUV_SW, - SDL_DisplayYUV_SW, - SDL_FreeYUV_SW -}; -/* RGB conversion lookup tables */ -struct private_yuvhwdata +struct SDL_SW_YUVTexture { - SDL_Surface *stretch; - SDL_Surface *display; + SDL_Texture *texture; + + Uint32 target_format; Uint8 *pixels; int *colortab; Uint32 *rgb_2_pix; @@ -118,9 +109,12 @@ /* These are just so we don't have to allocate them separately */ Uint16 pitches[3]; Uint8 *planes[3]; + + /* This is a temporary surface in case we have to stretch copy */ + SDL_Surface *stretch; + SDL_Surface *display; }; - /* The colorspace conversion functions */ #if 0 /*defined(__GNUC__) && defined(__i386__) && SDL_ASSEMBLY_ROUTINES */ @@ -918,105 +912,30 @@ return 1 + free_bits_at_bottom(a >> 1); } - -SDL_Overlay * -SDL_CreateYUV_SW(_THIS, int width, int height, Uint32 format, - SDL_Surface * display) +static int +SDL_SW_SetupYUVDisplay(SDL_SW_YUVTexture * swdata, Uint32 target_format) { - SDL_Overlay *overlay; - struct private_yuvhwdata *swdata; - int *Cr_r_tab; - int *Cr_g_tab; - int *Cb_g_tab; - int *Cb_b_tab; Uint32 *r_2_pix_alloc; Uint32 *g_2_pix_alloc; Uint32 *b_2_pix_alloc; int i; - int CR, CB; - Uint32 Rmask, Gmask, Bmask; - - /* Only RGB packed pixel conversion supported */ - if ((display->format->BytesPerPixel != 2) && - (display->format->BytesPerPixel != 3) && - (display->format->BytesPerPixel != 4)) { - SDL_SetError("Can't use YUV data on non 16/24/32 bit surfaces"); - return (NULL); - } + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; - /* Verify that we support the format */ - switch (format) { - case SDL_YV12_OVERLAY: - case SDL_IYUV_OVERLAY: - case SDL_YUY2_OVERLAY: - case SDL_UYVY_OVERLAY: - case SDL_YVYU_OVERLAY: - break; - default: - SDL_SetError("Unsupported YUV format"); - return (NULL); + if (!SDL_PixelFormatEnumToMasks + (target_format, &bpp, &Rmask, &Gmask, &Bmask, &Amask) || bpp < 15) { + SDL_SetError("Unsupported YUV destination format"); + return -1; } - /* Create the overlay structure */ - overlay = (SDL_Overlay *) SDL_malloc(sizeof *overlay); - if (overlay == NULL) { - SDL_OutOfMemory(); - return (NULL); - } - SDL_memset(overlay, 0, (sizeof *overlay)); - - /* Fill in the basic members */ - overlay->format = format; - overlay->w = width; - overlay->h = height; - - /* Set up the YUV surface function structure */ - overlay->hwfuncs = &sw_yuvfuncs; - - /* Create the pixel data and lookup tables */ - swdata = (struct private_yuvhwdata *) SDL_malloc(sizeof *swdata); - overlay->hwdata = swdata; - if (swdata == NULL) { - SDL_OutOfMemory(); - SDL_FreeYUVOverlay(overlay); - return (NULL); - } - swdata->stretch = NULL; - swdata->display = display; - swdata->pixels = (Uint8 *) SDL_malloc(width * height * 2); - swdata->colortab = (int *) SDL_malloc(4 * 256 * sizeof(int)); - Cr_r_tab = &swdata->colortab[0 * 256]; - Cr_g_tab = &swdata->colortab[1 * 256]; - Cb_g_tab = &swdata->colortab[2 * 256]; - Cb_b_tab = &swdata->colortab[3 * 256]; - swdata->rgb_2_pix = (Uint32 *) SDL_malloc(3 * 768 * sizeof(Uint32)); + swdata->target_format = target_format; r_2_pix_alloc = &swdata->rgb_2_pix[0 * 768]; g_2_pix_alloc = &swdata->rgb_2_pix[1 * 768]; b_2_pix_alloc = &swdata->rgb_2_pix[2 * 768]; - if (!swdata->pixels || !swdata->colortab || !swdata->rgb_2_pix) { - SDL_OutOfMemory(); - SDL_FreeYUVOverlay(overlay); - return (NULL); - } - - /* Generate the tables for the display surface */ - for (i = 0; i < 256; i++) { - /* Gamma correction (luminescence table) and chroma correction - would be done here. See the Berkeley mpeg_play sources. - */ - CB = CR = (i - 128); - Cr_r_tab[i] = (int) ((0.419 / 0.299) * CR); - Cr_g_tab[i] = (int) (-(0.299 / 0.419) * CR); - Cb_g_tab[i] = (int) (-(0.114 / 0.331) * CB); - Cb_b_tab[i] = (int) ((0.587 / 0.331) * CB); - } /* * Set up entries 0-255 in rgb-to-pixel value tables. */ - Rmask = display->format->Rmask; - Gmask = display->format->Gmask; - Bmask = display->format->Bmask; for (i = 0; i < 256; ++i) { r_2_pix_alloc[i + 256] = i >> (8 - number_of_bits_set(Rmask)); r_2_pix_alloc[i + 256] <<= free_bits_at_bottom(Rmask); @@ -1033,7 +952,7 @@ * harmless in the normal case as storing a 32-bit value * through a short pointer will lose the top bits anyway. */ - if (display->format->BytesPerPixel == 2) { + if (SDL_BYTESPERPIXEL(target_format) == 2) { for (i = 0; i < 256; ++i) { r_2_pix_alloc[i + 256] |= (r_2_pix_alloc[i + 256]) << 16; g_2_pix_alloc[i + 256] |= (g_2_pix_alloc[i + 256]) << 16; @@ -1055,10 +974,10 @@ } /* You have chosen wisely... */ - switch (format) { - case SDL_YV12_OVERLAY: - case SDL_IYUV_OVERLAY: - if (display->format->BytesPerPixel == 2) { + switch (swdata->texture->format) { + case SDL_PixelFormat_YV12: + case SDL_PixelFormat_IYUV: + if (SDL_BYTESPERPIXEL(target_format) == 2) { #if 0 /*defined(__GNUC__) && defined(__i386__) && SDL_ASSEMBLY_ROUTINES */ /* inline assembly functions */ if (SDL_HasMMX() && (Rmask == 0xF800) && @@ -1074,11 +993,11 @@ #endif swdata->Display2X = Color16DitherYV12Mod2X; } - if (display->format->BytesPerPixel == 3) { + if (SDL_BYTESPERPIXEL(target_format) == 3) { swdata->Display1X = Color24DitherYV12Mod1X; swdata->Display2X = Color24DitherYV12Mod2X; } - if (display->format->BytesPerPixel == 4) { + if (SDL_BYTESPERPIXEL(target_format) == 4) { #if 0 /*defined(__GNUC__) && defined(__i386__) && SDL_ASSEMBLY_ROUTINES */ /* inline assembly functions */ if (SDL_HasMMX() && (Rmask == 0x00FF0000) && @@ -1096,18 +1015,18 @@ swdata->Display2X = Color32DitherYV12Mod2X; } break; - case SDL_YUY2_OVERLAY: - case SDL_UYVY_OVERLAY: - case SDL_YVYU_OVERLAY: - if (display->format->BytesPerPixel == 2) { + case SDL_PixelFormat_YUY2: + case SDL_PixelFormat_UYVY: + case SDL_PixelFormat_YVYU: + if (SDL_BYTESPERPIXEL(target_format) == 2) { swdata->Display1X = Color16DitherYUY2Mod1X; swdata->Display2X = Color16DitherYUY2Mod2X; } - if (display->format->BytesPerPixel == 3) { + if (SDL_BYTESPERPIXEL(target_format) == 3) { swdata->Display1X = Color24DitherYUY2Mod1X; swdata->Display2X = Color24DitherYUY2Mod2X; } - if (display->format->BytesPerPixel == 4) { + if (SDL_BYTESPERPIXEL(target_format) == 4) { swdata->Display1X = Color32DitherYUY2Mod1X; swdata->Display2X = Color32DitherYUY2Mod2X; } @@ -1117,28 +1036,88 @@ break; } + if (swdata->display) { + SDL_FreeSurface(swdata->display); + swdata->display = NULL; + } + return 0; +} + +SDL_SW_YUVTexture * +SDL_SW_CreateYUVTexture(SDL_Texture * texture) +{ + SDL_SW_YUVTexture *swdata; + int *Cr_r_tab; + int *Cr_g_tab; + int *Cb_g_tab; + int *Cb_b_tab; + int i; + int CR, CB; + + swdata = (SDL_SW_YUVTexture *) SDL_malloc(sizeof(*swdata)); + if (!swdata) { + SDL_OutOfMemory(); + return NULL; + } + SDL_zerop(swdata); + + switch (texture->format) { + case SDL_PixelFormat_YV12: + case SDL_PixelFormat_IYUV: + case SDL_PixelFormat_YUY2: + case SDL_PixelFormat_UYVY: + case SDL_PixelFormat_YVYU: + break; + default: + SDL_SetError("Unsupported YUV format"); + return NULL; + } + + swdata->texture = texture; + swdata->target_format = SDL_PixelFormat_Unknown; + swdata->pixels = (Uint8 *) SDL_malloc(texture->w * texture->h * 2); + swdata->colortab = (int *) SDL_malloc(4 * 256 * sizeof(int)); + swdata->rgb_2_pix = (Uint32 *) SDL_malloc(3 * 768 * sizeof(Uint32)); + if (!swdata->pixels || !swdata->colortab || !swdata->rgb_2_pix) { + SDL_OutOfMemory(); + SDL_SW_DestroyYUVTexture(swdata); + return NULL; + } + + /* Generate the tables for the display surface */ + Cr_r_tab = &swdata->colortab[0 * 256]; + Cr_g_tab = &swdata->colortab[1 * 256]; + Cb_g_tab = &swdata->colortab[2 * 256]; + Cb_b_tab = &swdata->colortab[3 * 256]; + for (i = 0; i < 256; i++) { + /* Gamma correction (luminescence table) and chroma correction + would be done here. See the Berkeley mpeg_play sources. + */ + CB = CR = (i - 128); + Cr_r_tab[i] = (int) ((0.419 / 0.299) * CR); + Cr_g_tab[i] = (int) (-(0.299 / 0.419) * CR); + Cb_g_tab[i] = (int) (-(0.114 / 0.331) * CB); + Cb_b_tab[i] = (int) ((0.587 / 0.331) * CB); + } + /* Find the pitch and offset values for the overlay */ - overlay->pitches = swdata->pitches; - overlay->pixels = swdata->planes; - switch (format) { - case SDL_YV12_OVERLAY: - case SDL_IYUV_OVERLAY: - overlay->pitches[0] = overlay->w; - overlay->pitches[1] = overlay->pitches[0] / 2; - overlay->pitches[2] = overlay->pitches[0] / 2; - overlay->pixels[0] = swdata->pixels; - overlay->pixels[1] = overlay->pixels[0] + - overlay->pitches[0] * overlay->h; - overlay->pixels[2] = overlay->pixels[1] + - overlay->pitches[1] * overlay->h / 2; - overlay->planes = 3; + switch (texture->format) { + case SDL_PixelFormat_YV12: + case SDL_PixelFormat_IYUV: + swdata->pitches[0] = texture->w; + swdata->pitches[1] = swdata->pitches[0] / 2; + swdata->pitches[2] = swdata->pitches[0] / 2; + swdata->planes[0] = swdata->pixels; + swdata->planes[1] = + swdata->planes[0] + swdata->pitches[0] * texture->h; + swdata->planes[2] = + swdata->planes[1] + swdata->pitches[1] * texture->h / 2; break; - case SDL_YUY2_OVERLAY: - case SDL_UYVY_OVERLAY: - case SDL_YVYU_OVERLAY: - overlay->pitches[0] = overlay->w * 2; - overlay->pixels[0] = swdata->pixels; - overlay->planes = 1; + case SDL_PixelFormat_YUY2: + case SDL_PixelFormat_UYVY: + case SDL_PixelFormat_YVYU: + swdata->pitches[0] = texture->w * 2; + swdata->planes[0] = swdata->pixels; break; default: /* We should never get here (caught above) */ @@ -1146,146 +1125,210 @@ } /* We're all done.. */ - return (overlay); + return (swdata); } int -SDL_LockYUV_SW(_THIS, SDL_Overlay * overlay) +SDL_SW_QueryYUVTexturePixels(SDL_SW_YUVTexture * swdata, void **pixels, + int *pitch) { - return (0); -} - -void -SDL_UnlockYUV_SW(_THIS, SDL_Overlay * overlay) -{ - return; + *pixels = swdata->planes[0]; + *pitch = swdata->pitches[0]; + return 0; } int -SDL_DisplayYUV_SW(_THIS, SDL_Overlay * overlay, SDL_Rect * src, - SDL_Rect * dst) +SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect, + const void *pixels, int pitch) { - struct private_yuvhwdata *swdata; + SDL_Texture *texture = swdata->texture; + + switch (texture->format) { + case SDL_PixelFormat_YV12: + case SDL_PixelFormat_IYUV: + if (rect + && (rect->x != 0 || rect->y != 0 || rect->w != texture->w + || rect->h != texture->h)) { + SDL_SetError + ("YV12 and IYUV textures only support full surface updates"); + return -1; + } + SDL_memcpy(swdata->pixels, pixels, texture->h * texture->w * 2); + break; + case SDL_PixelFormat_YUY2: + case SDL_PixelFormat_UYVY: + case SDL_PixelFormat_YVYU: + { + Uint8 *src, *dst; + int row; + size_t length; + + src = (Uint8 *) pixels; + dst = + swdata->planes[0] + rect->y * swdata->pitches[0] + + rect->x * 2; + length = rect->w * 2; + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += swdata->pitches[0]; + } + } + break; + } + return 0; +} + +int +SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect, + int markDirty, void **pixels, int *pitch) +{ + SDL_Texture *texture = swdata->texture; + + switch (texture->format) { + case SDL_PixelFormat_YV12: + case SDL_PixelFormat_IYUV: + if (rect + && (rect->x != 0 || rect->y != 0 || rect->w != texture->w + || rect->h != texture->h)) { + SDL_SetError + ("YV12 and IYUV textures only support full surface locks"); + return -1; + } + break; + } + + *pixels = swdata->planes[0] + rect->y * swdata->pitches[0] + rect->x * 2; + *pitch = swdata->pitches[0]; + return 0; +} + +void +SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture * swdata) +{ +} + +int +SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture * swdata, const SDL_Rect * srcrect, + Uint32 target_format, int w, int h, void *pixels, + int pitch) +{ + SDL_Texture *texture = swdata->texture; int stretch; int scale_2x; - SDL_Surface *display; Uint8 *lum, *Cr, *Cb; - Uint8 *dstp; int mod; - swdata = overlay->hwdata; + /* Make sure we're set up to display in the desired format */ + if (target_format != swdata->target_format) { + if (SDL_SW_SetupYUVDisplay(swdata, target_format) < 0) { + return -1; + } + } + stretch = 0; scale_2x = 0; - if (src->x || src->y || src->w < overlay->w || src->h < overlay->h) { + if (srcrect->x || srcrect->y || srcrect->w < texture->w + || srcrect->h < texture->h) { /* The source rectangle has been clipped. Using a scratch surface is easier than adding clipped source support to all the blitters, plus that would slow them down in the general unclipped case. */ stretch = 1; - } else if ((src->w != dst->w) || (src->h != dst->h)) { - if ((dst->w == 2 * src->w) && (dst->h == 2 * src->h)) { + } else if ((srcrect->w != w) || (srcrect->h != h)) { + if ((w == 2 * srcrect->w) && (h == 2 * srcrect->h)) { scale_2x = 1; } else { stretch = 1; } } if (stretch) { + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; + + if (swdata->display) { + swdata->display->w = w; + swdata->display->h = h; + swdata->display->pixels = pixels; + swdata->display->pitch = pitch; + } else { + /* This must have succeeded in SDL_SW_SetupYUVDisplay() earlier */ + SDL_PixelFormatEnumToMasks(target_format, &bpp, &Rmask, &Gmask, + &Bmask, &Amask); + swdata->display = + SDL_CreateRGBSurfaceFrom(pixels, w, h, bpp, pitch, Rmask, + Gmask, Bmask, Amask); + if (!swdata->display) { + return (-1); + } + } if (!swdata->stretch) { - display = swdata->display; - swdata->stretch = SDL_CreateRGBSurface(0, - overlay->w, - overlay->h, - display->format-> - BitsPerPixel, - display->format-> - Rmask, - display->format-> - Gmask, - display->format->Bmask, 0); + /* This must have succeeded in SDL_SW_SetupYUVDisplay() earlier */ + SDL_PixelFormatEnumToMasks(target_format, &bpp, &Rmask, &Gmask, + &Bmask, &Amask); + swdata->stretch = + SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, + Gmask, Bmask, Amask); if (!swdata->stretch) { return (-1); } } - display = swdata->stretch; - } else { - display = swdata->display; + pixels = swdata->stretch->pixels; + pitch = swdata->stretch->pitch; } - switch (overlay->format) { - case SDL_YV12_OVERLAY: - lum = overlay->pixels[0]; - Cr = overlay->pixels[1]; - Cb = overlay->pixels[2]; + switch (texture->format) { + case SDL_PixelFormat_YV12: + lum = swdata->planes[0]; + Cr = swdata->planes[1]; + Cb = swdata->planes[2]; break; - case SDL_IYUV_OVERLAY: - lum = overlay->pixels[0]; - Cr = overlay->pixels[2]; - Cb = overlay->pixels[1]; + case SDL_PixelFormat_IYUV: + lum = swdata->planes[0]; + Cr = swdata->planes[2]; + Cb = swdata->planes[1]; break; - case SDL_YUY2_OVERLAY: - lum = overlay->pixels[0]; + case SDL_PixelFormat_YUY2: + lum = swdata->planes[0]; Cr = lum + 3; Cb = lum + 1; break; - case SDL_UYVY_OVERLAY: - lum = overlay->pixels[0] + 1; + case SDL_PixelFormat_UYVY: + lum = swdata->planes[0] + 1; Cr = lum + 1; Cb = lum - 1; break; - case SDL_YVYU_OVERLAY: - lum = overlay->pixels[0]; + case SDL_PixelFormat_YVYU: + lum = swdata->planes[0]; Cr = lum + 1; Cb = lum + 3; break; default: - SDL_SetError("Unsupported YUV format in blit"); + SDL_SetError("Unsupported YUV format in copy"); return (-1); } - if (SDL_MUSTLOCK(display)) { - if (SDL_LockSurface(display) < 0) { - return (-1); - } - } - if (stretch) { - dstp = (Uint8 *) swdata->stretch->pixels; - } else { - dstp = (Uint8 *) display->pixels - + dst->x * display->format->BytesPerPixel - + dst->y * display->pitch; - } - mod = (display->pitch / display->format->BytesPerPixel); + mod = (pitch / SDL_BYTESPERPIXEL(target_format)); if (scale_2x) { - mod -= (overlay->w * 2); + mod -= (texture->w * 2); swdata->Display2X(swdata->colortab, swdata->rgb_2_pix, - lum, Cr, Cb, dstp, overlay->h, overlay->w, mod); + lum, Cr, Cb, pixels, texture->h, texture->w, mod); } else { - mod -= overlay->w; + mod -= texture->w; swdata->Display1X(swdata->colortab, swdata->rgb_2_pix, - lum, Cr, Cb, dstp, overlay->h, overlay->w, mod); - } - if (SDL_MUSTLOCK(display)) { - SDL_UnlockSurface(display); + lum, Cr, Cb, pixels, texture->h, texture->w, mod); } if (stretch) { - display = swdata->display; - SDL_SoftStretch(swdata->stretch, src, display, dst); + SDL_Rect rect = *srcrect; + SDL_SoftStretch(swdata->stretch, &rect, swdata->display, NULL); } - SDL_UpdateRects(display, 1, dst); - - return (0); + return 0; } void -SDL_FreeYUV_SW(_THIS, SDL_Overlay * overlay) +SDL_SW_DestroyYUVTexture(SDL_SW_YUVTexture * swdata) { - struct private_yuvhwdata *swdata; - - swdata = overlay->hwdata; if (swdata) { - if (swdata->stretch) { - SDL_FreeSurface(swdata->stretch); - } if (swdata->pixels) { SDL_free(swdata->pixels); } @@ -1295,9 +1338,14 @@ if (swdata->rgb_2_pix) { SDL_free(swdata->rgb_2_pix); } + if (swdata->stretch) { + SDL_FreeSurface(swdata->stretch); + } + if (swdata->display) { + SDL_FreeSurface(swdata->display); + } SDL_free(swdata); } } -#endif /* TODO */ /* vi: set ts=4 sw=4 expandtab: */ diff -r 396a35389351 -r c4aa1a2f48f1 src/video/SDL_yuv_sw_c.h --- a/src/video/SDL_yuv_sw_c.h Sat Jun 17 06:45:14 2006 +0000 +++ b/src/video/SDL_yuv_sw_c.h Sun Jun 18 06:35:41 2006 +0000 @@ -24,17 +24,21 @@ #include "SDL_video.h" #include "SDL_sysvideo.h" -/* This is the software implementation of the YUV video overlay support */ +/* This is the software implementation of the YUV texture support */ -extern SDL_Overlay *SDL_CreateYUV_SW(_THIS, int width, int height, - Uint32 format, SDL_Surface * display); - -extern int SDL_LockYUV_SW(_THIS, SDL_Overlay * overlay); +typedef struct SDL_SW_YUVTexture SDL_SW_YUVTexture; -extern void SDL_UnlockYUV_SW(_THIS, SDL_Overlay * overlay); +SDL_SW_YUVTexture *SDL_SW_CreateYUVTexture(SDL_Texture * texture); +int SDL_SW_QueryYUVTexturePixels(SDL_SW_YUVTexture * swdata, void **pixels, + int *pitch); +int SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect, + const void *pixels, int pitch); +int SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect, + int markDirty, void **pixels, int *pitch); +void SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture * swdata); +int SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture * swdata, const SDL_Rect * srcrect, + Uint32 target_format, int w, int h, void *pixels, + int pitch); +void SDL_SW_DestroyYUVTexture(SDL_SW_YUVTexture * swdata); -extern int SDL_DisplayYUV_SW(_THIS, SDL_Overlay * overlay, SDL_Rect * src, - SDL_Rect * dst); - -extern void SDL_FreeYUV_SW(_THIS, SDL_Overlay * overlay); /* vi: set ts=4 sw=4 expandtab: */