diff --git a/include/SDL3/SDL_pixels.h b/include/SDL3/SDL_pixels.h index 94bd873c61..8da15e860a 100644 --- a/include/SDL3/SDL_pixels.h +++ b/include/SDL3/SDL_pixels.h @@ -364,6 +364,7 @@ typedef enum SDL_PackedLayout ((format) == SDL_PIXELFORMAT_UYVY) || \ ((format) == SDL_PIXELFORMAT_YVYU) || \ ((format) == SDL_PIXELFORMAT_P010) || \ + ((format) == SDL_PIXELFORMAT_I0FL) || \ ((format) == SDL_PIXELFORMAT_I4FL)) ? 2 : 1) : (((format) >> 0) & 0xFF)) @@ -676,6 +677,8 @@ typedef enum SDL_PixelFormat /* SDL_DEFINE_PIXELFOURCC('I', '4', '4', '4'), */ SDL_PIXELFORMAT_P010 = 0x30313050u, /**< YUV 4:2:0 16-bit planar mode: Y + U/V interleaved (2 planes) */ /* SDL_DEFINE_PIXELFOURCC('P', '0', '1', '0'), */ + SDL_PIXELFORMAT_I0FL = 0x4c463049u, /**< YUV 4:2:0 16-bit planar mode: Y + U + V (3 planes) */ + /* SDL_DEFINE_PIXELFOURCC('I', '0', 'F', 'L'), */ SDL_PIXELFORMAT_I4FL = 0x4c463449u, /**< YUV 4:4:4 16-bit planar mode: Y + U + V (3 planes) */ /* SDL_DEFINE_PIXELFOURCC('I', '4', 'F', 'L'), */ SDL_PIXELFORMAT_EXTERNAL_OES = 0x2053454fu, /**< Android video texture format */ diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index bd0c2eb6fc..b17ec729ef 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -2498,8 +2498,9 @@ bool SDL_UpdateYUVTexture(SDL_Texture *texture, const SDL_Rect *rect, CHECK_PARAM(texture->format != SDL_PIXELFORMAT_YV12 && texture->format != SDL_PIXELFORMAT_IYUV && texture->format != SDL_PIXELFORMAT_I444 && + texture->format != SDL_PIXELFORMAT_I0FL && texture->format != SDL_PIXELFORMAT_I4FL) { - return SDL_SetError("Texture format must be YV12, IYUV, I444, or I4FL"); + return SDL_SetError("Texture format must be YV12, IYUV, I444, I0FL, or I4FL"); } real_rect.x = 0; diff --git a/src/render/SDL_yuv_sw.c b/src/render/SDL_yuv_sw.c index 02fb98afa9..9bb35eedd0 100644 --- a/src/render/SDL_yuv_sw.c +++ b/src/render/SDL_yuv_sw.c @@ -36,6 +36,7 @@ SDL_SW_YUVTexture *SDL_SW_CreateYUVTexture(SDL_PixelFormat format, SDL_Colorspac case SDL_PIXELFORMAT_YV12: case SDL_PIXELFORMAT_IYUV: case SDL_PIXELFORMAT_I444: + case SDL_PIXELFORMAT_I0FL: case SDL_PIXELFORMAT_I4FL: case SDL_PIXELFORMAT_YUY2: case SDL_PIXELFORMAT_UYVY: @@ -75,9 +76,10 @@ SDL_SW_YUVTexture *SDL_SW_CreateYUVTexture(SDL_PixelFormat format, SDL_Colorspac switch (format) { case SDL_PIXELFORMAT_YV12: case SDL_PIXELFORMAT_IYUV: - swdata->pitches[0] = w; - swdata->pitches[1] = (swdata->pitches[0] + 1) / 2; - swdata->pitches[2] = (swdata->pitches[0] + 1) / 2; + case SDL_PIXELFORMAT_I0FL: + swdata->pitches[0] = w * SDL_BYTESPERPIXEL(format); + swdata->pitches[1] = ((w + 1) / 2) * SDL_BYTESPERPIXEL(format); + swdata->pitches[2] = swdata->pitches[1]; swdata->planes[0] = swdata->pixels; swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h; swdata->planes[2] = swdata->planes[1] + swdata->pitches[1] * ((h + 1) / 2); @@ -128,6 +130,7 @@ bool SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect, switch (swdata->format) { case SDL_PIXELFORMAT_YV12: case SDL_PIXELFORMAT_IYUV: + case SDL_PIXELFORMAT_I0FL: if (rect->x == 0 && rect->y == 0 && rect->w == swdata->w && rect->h == swdata->h && pitch == swdata->pitches[0]) { SDL_memcpy(swdata->pixels, pixels, @@ -136,26 +139,27 @@ bool SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect, Uint8 *src, *dst; int row; size_t length; + const int bpp = SDL_BYTESPERPIXEL(swdata->format); // Copy the Y plane src = (Uint8 *)pixels; dst = swdata->pixels + rect->y * swdata->w + rect->x; - length = rect->w; + length = rect->w * bpp; for (row = 0; row < rect->h; ++row) { SDL_memcpy(dst, src, length); src += pitch; - dst += swdata->w; + dst += swdata->pitches[0]; } // Copy the next plane src = (Uint8 *)pixels + rect->h * pitch; dst = swdata->pixels + swdata->h * swdata->w; dst += rect->y / 2 * ((swdata->w + 1) / 2) + rect->x / 2; - length = (rect->w + 1) / 2; + length = ((rect->w + 1) / 2) * bpp; for (row = 0; row < (rect->h + 1) / 2; ++row) { SDL_memcpy(dst, src, length); src += (pitch + 1) / 2; - dst += (swdata->w + 1) / 2; + dst += swdata->pitches[1]; } // Copy the next plane @@ -163,11 +167,11 @@ bool SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect, dst = swdata->pixels + swdata->h * swdata->w + ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2); dst += rect->y / 2 * ((swdata->w + 1) / 2) + rect->x / 2; - length = (rect->w + 1) / 2; + length = ((rect->w + 1) / 2) * bpp; for (row = 0; row < (rect->h + 1) / 2; ++row) { SDL_memcpy(dst, src, length); src += (pitch + 1) / 2; - dst += (swdata->w + 1) / 2; + dst += swdata->pitches[2]; } } break; @@ -285,7 +289,7 @@ bool SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture *swdata, const SDL_Rect *re // Copy the Y plane src = Yplane; dst = swdata->pixels + rect->y * swdata->pitches[0] + rect->x * bpp; - length = rect->w; + length = rect->w * bpp; for (row = 0; row < rect->h; ++row) { SDL_memcpy(dst, src, length); src += Ypitch; @@ -305,18 +309,18 @@ bool SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture *swdata, const SDL_Rect *re dst += swdata->pitches[1]; } } else { - if (swdata->format == SDL_PIXELFORMAT_IYUV) { - dst = swdata->pixels + swdata->h * swdata->w; + if (swdata->format == SDL_PIXELFORMAT_IYUV || + swdata->format == SDL_PIXELFORMAT_I0FL) { + dst = swdata->pixels + swdata->h * swdata->pitches[0]; } else { - dst = swdata->pixels + swdata->h * swdata->w + - ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2); + dst = swdata->pixels + swdata->h * swdata->pitches[0] + ((swdata->h + 1) / 2) * swdata->pitches[1]; } - dst += rect->y / 2 * ((swdata->w + 1) / 2) + rect->x / 2; - length = (rect->w + 1) / 2; + dst += rect->y / 2 * ((swdata->w + 1) / 2) * bpp + (rect->x / 2) * bpp; + length = ((rect->w + 1) / 2) * bpp; for (row = 0; row < (rect->h + 1) / 2; ++row) { SDL_memcpy(dst, src, length); src += Upitch; - dst += (swdata->w + 1) / 2; + dst += swdata->pitches[1]; } } @@ -334,17 +338,16 @@ bool SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture *swdata, const SDL_Rect *re } } else { if (swdata->format == SDL_PIXELFORMAT_YV12) { - dst = swdata->pixels + swdata->h * swdata->w; + dst = swdata->pixels + swdata->h * swdata->pitches[0]; } else { - dst = swdata->pixels + swdata->h * swdata->w + - ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2); + dst = swdata->pixels + swdata->h * swdata->pitches[0] + ((swdata->h + 1) / 2) * swdata->pitches[1]; } - dst += rect->y / 2 * ((swdata->w + 1) / 2) + rect->x / 2; - length = (rect->w + 1) / 2; + dst += rect->y / 2 * ((swdata->w + 1) / 2) * bpp + (rect->x / 2) * bpp; + length = ((rect->w + 1) / 2) * bpp; for (row = 0; row < (rect->h + 1) / 2; ++row) { SDL_memcpy(dst, src, length); src += Vpitch; - dst += (swdata->w + 1) / 2; + dst += swdata->pitches[2]; } } return true; diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index 6a541a36fe..2b6b339286 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -273,6 +273,7 @@ static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 outpu return DXGI_FORMAT_NV12; case SDL_PIXELFORMAT_P010: return DXGI_FORMAT_P010; + case SDL_PIXELFORMAT_I0FL: case SDL_PIXELFORMAT_I4FL: return DXGI_FORMAT_R16_UNORM; default: @@ -1272,7 +1273,8 @@ static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD #ifdef SDL_HAVE_YUV if (texture->format == SDL_PIXELFORMAT_YV12 || - texture->format == SDL_PIXELFORMAT_IYUV) { + texture->format == SDL_PIXELFORMAT_IYUV || + texture->format == SDL_PIXELFORMAT_I0FL) { textureData->yuv = true; textureDesc.Width = (textureDesc.Width + 1) / 2; @@ -1306,14 +1308,14 @@ static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD } SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D11_TEXTURE_V_POINTER, textureData->mainTextureV); - textureData->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8); + const int bits_per_pixel = (texture->format == SDL_PIXELFORMAT_I0FL) ? 16 : 8; + textureData->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel); if (!textureData->YCbCr_matrix) { return SDL_SetError("Unsupported YUV colorspace"); } } if (texture->format == SDL_PIXELFORMAT_I444 || texture->format == SDL_PIXELFORMAT_I4FL) { - textureData->yuv = true; if (!GetTextureProperty(create_props, SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_U_POINTER, &textureData->mainTextureU)) { @@ -1344,7 +1346,7 @@ static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD } SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D11_TEXTURE_V_POINTER, textureData->mainTextureV); - const int bits_per_pixel = (texture->format == SDL_PIXELFORMAT_I444) ? 8 : 16; + const int bits_per_pixel = (texture->format == SDL_PIXELFORMAT_I4FL) ? 16 : 8; textureData->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel); if (!textureData->YCbCr_matrix) { return SDL_SetError("Unsupported YUV colorspace"); @@ -1353,18 +1355,9 @@ static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD if (texture->format == SDL_PIXELFORMAT_NV12 || texture->format == SDL_PIXELFORMAT_NV21 || texture->format == SDL_PIXELFORMAT_P010) { - int bits_per_pixel; - textureData->nv12 = true; - switch (texture->format) { - case SDL_PIXELFORMAT_P010: - bits_per_pixel = 10; - break; - default: - bits_per_pixel = 8; - break; - } + const int bits_per_pixel = (texture->format == SDL_PIXELFORMAT_P010) ? 10 : 8; textureData->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel); if (!textureData->YCbCr_matrix) { return SDL_SetError("Unsupported YUV colorspace"); @@ -1616,7 +1609,7 @@ static bool D3D11_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, } } else { int Ypitch = srcPitch; - int UVpitch = ((Ypitch + 1) / 2); + int UVpitch = ((Ypitch + 1 * SDL_BYTESPERPIXEL(texture->format)) / 2); const Uint8 *plane0 = (const Uint8 *)srcPixels; const Uint8 *plane1 = plane0 + rect->h * Ypitch; const Uint8 *plane2 = plane1 + ((rect->h + 1) / 2) * UVpitch; @@ -2232,6 +2225,7 @@ static void D3D11_SetupShaderConstants(SDL_Renderer *renderer, const SDL_RenderC constants->texture_type = TEXTURETYPE_NV12; constants->input_type = INPUTTYPE_HDR10; break; + case SDL_PIXELFORMAT_I0FL: case SDL_PIXELFORMAT_I4FL: constants->texture_type = TEXTURETYPE_YUV; constants->input_type = INPUTTYPE_HDR10; @@ -3079,6 +3073,7 @@ static bool D3D11_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV12); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV21); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P010); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_I0FL); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_I4FL); return true; diff --git a/src/render/direct3d12/SDL_render_d3d12.c b/src/render/direct3d12/SDL_render_d3d12.c index daff2f13a9..9e529ce5be 100644 --- a/src/render/direct3d12/SDL_render_d3d12.c +++ b/src/render/direct3d12/SDL_render_d3d12.c @@ -335,6 +335,7 @@ static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(SDL_PixelFormat format, Uin return DXGI_FORMAT_NV12; case SDL_PIXELFORMAT_P010: return DXGI_FORMAT_P010; + case SDL_PIXELFORMAT_I0FL: case SDL_PIXELFORMAT_I4FL: return DXGI_FORMAT_R16_UNORM; default: @@ -1691,7 +1692,8 @@ static bool D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD #ifdef SDL_HAVE_YUV if (texture->format == SDL_PIXELFORMAT_YV12 || - texture->format == SDL_PIXELFORMAT_IYUV) { + texture->format == SDL_PIXELFORMAT_IYUV || + texture->format == SDL_PIXELFORMAT_I0FL) { textureData->yuv = true; textureDesc.Width = (textureDesc.Width + 1) / 2; @@ -1735,7 +1737,8 @@ static bool D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD textureData->mainResourceStateV = D3D12_RESOURCE_STATE_COPY_DEST; SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D12_TEXTURE_V_POINTER, textureData->mainTextureV); - textureData->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8); + const int bits_per_pixel = (texture->format == SDL_PIXELFORMAT_I0FL) ? 16 : 8; + textureData->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel); if (!textureData->YCbCr_matrix) { return SDL_SetError("Unsupported YUV colorspace"); } @@ -1783,7 +1786,7 @@ static bool D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD textureData->mainResourceStateV = D3D12_RESOURCE_STATE_COPY_DEST; SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D12_TEXTURE_V_POINTER, textureData->mainTextureV); - const int bits_per_pixel = (texture->format == SDL_PIXELFORMAT_I444) ? 8 : 16; + const int bits_per_pixel = (texture->format == SDL_PIXELFORMAT_I4FL) ? 16 : 8; textureData->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel); if (!textureData->YCbCr_matrix) { return SDL_SetError("Unsupported YUV colorspace"); @@ -1793,18 +1796,9 @@ static bool D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD if (texture->format == SDL_PIXELFORMAT_NV12 || texture->format == SDL_PIXELFORMAT_NV21 || texture->format == SDL_PIXELFORMAT_P010) { - int bits_per_pixel; - textureData->nv12 = true; - switch (texture->format) { - case SDL_PIXELFORMAT_P010: - bits_per_pixel = 10; - break; - default: - bits_per_pixel = 8; - break; - } + const int bits_per_pixel = (texture->format == SDL_PIXELFORMAT_P010) ? 10 : 8; textureData->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel); if (!textureData->YCbCr_matrix) { return SDL_SetError("Unsupported YUV colorspace"); @@ -2084,15 +2078,17 @@ static bool D3D12_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, return false; } } else { + const int bpp = SDL_BYTESPERPIXEL(texture->format); + // Skip to the correct offset into the next texture srcPixels = (const void *)((const Uint8 *)srcPixels + rect->h * srcPitch); - if (!D3D12_UpdateTextureInternal(rendererData, texture->format == SDL_PIXELFORMAT_YV12 ? textureData->mainTextureV : textureData->mainTextureU, 0, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, srcPixels, (srcPitch + 1) / 2, texture->format == SDL_PIXELFORMAT_YV12 ? &textureData->mainResourceStateV : &textureData->mainResourceStateU)) { + if (!D3D12_UpdateTextureInternal(rendererData, texture->format == SDL_PIXELFORMAT_YV12 ? textureData->mainTextureV : textureData->mainTextureU, 0, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, srcPixels, (srcPitch + 1 * bpp) / 2, texture->format == SDL_PIXELFORMAT_YV12 ? &textureData->mainResourceStateV : &textureData->mainResourceStateU)) { return false; } // Skip to the correct offset into the next texture - srcPixels = (const void *)((const Uint8 *)srcPixels + ((rect->h + 1) / 2) * ((srcPitch + 1) / 2)); - if (!D3D12_UpdateTextureInternal(rendererData, texture->format == SDL_PIXELFORMAT_YV12 ? textureData->mainTextureU : textureData->mainTextureV, 0, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, srcPixels, (srcPitch + 1) / 2, texture->format == SDL_PIXELFORMAT_YV12 ? &textureData->mainResourceStateU : &textureData->mainResourceStateV)) { + srcPixels = (const void *)((const Uint8 *)srcPixels + ((rect->h + 1) / 2) * ((srcPitch + 1 * bpp) / 2)); + if (!D3D12_UpdateTextureInternal(rendererData, texture->format == SDL_PIXELFORMAT_YV12 ? textureData->mainTextureU : textureData->mainTextureV, 0, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, srcPixels, (srcPitch + 1 * bpp) / 2, texture->format == SDL_PIXELFORMAT_YV12 ? &textureData->mainResourceStateU : &textureData->mainResourceStateV)) { return false; } } @@ -2692,6 +2688,7 @@ static void D3D12_SetupShaderConstants(SDL_Renderer *renderer, const SDL_RenderC constants->texture_type = TEXTURETYPE_NV12; constants->input_type = INPUTTYPE_HDR10; break; + case SDL_PIXELFORMAT_I0FL: case SDL_PIXELFORMAT_I4FL: constants->texture_type = TEXTURETYPE_YUV; constants->input_type = INPUTTYPE_HDR10; @@ -3685,6 +3682,7 @@ bool D3D12_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_Proper SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV12); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV21); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P010); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_I0FL); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_I4FL); return true; diff --git a/src/render/gpu/SDL_render_gpu.c b/src/render/gpu/SDL_render_gpu.c index db065138f6..d54243478c 100644 --- a/src/render/gpu/SDL_render_gpu.c +++ b/src/render/gpu/SDL_render_gpu.c @@ -294,6 +294,7 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ format = SDL_GPU_TEXTUREFORMAT_R8_UNORM; break; case SDL_PIXELFORMAT_P010: + case SDL_PIXELFORMAT_I0FL: case SDL_PIXELFORMAT_I4FL: format = SDL_GPU_TEXTUREFORMAT_R16_UNORM; break; @@ -324,7 +325,8 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format); size = (size_t)texture->h * data->pitch; if (texture->format == SDL_PIXELFORMAT_YV12 || - texture->format == SDL_PIXELFORMAT_IYUV) { + texture->format == SDL_PIXELFORMAT_IYUV || + texture->format == SDL_PIXELFORMAT_I0FL) { // Need to add size for the U and V planes size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2); } @@ -378,7 +380,8 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ #ifdef SDL_HAVE_YUV if (texture->format == SDL_PIXELFORMAT_YV12 || - texture->format == SDL_PIXELFORMAT_IYUV) { + texture->format == SDL_PIXELFORMAT_IYUV || + texture->format == SDL_PIXELFORMAT_I0FL) { data->yuv = true; tci.width = (tci.width + 1) / 2; @@ -406,7 +409,8 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ } SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_V_POINTER, data->textureV); - data->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8); + const int bits_per_pixel = (texture->format == SDL_PIXELFORMAT_I0FL) ? 16 : 8; + data->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel); if (!data->YCbCr_matrix) { return SDL_SetError("Unsupported YUV colorspace"); } @@ -437,7 +441,7 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ } SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_V_POINTER, data->textureU); - const int bits_per_pixel = (texture->format == SDL_PIXELFORMAT_I444) ? 8 : 16; + const int bits_per_pixel = (texture->format == SDL_PIXELFORMAT_I4FL) ? 16 : 8; data->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel); if (!data->YCbCr_matrix) { return SDL_SetError("Unsupported YUV colorspace"); @@ -446,8 +450,6 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ if (texture->format == SDL_PIXELFORMAT_NV12 || texture->format == SDL_PIXELFORMAT_NV21 || texture->format == SDL_PIXELFORMAT_P010) { - int bits_per_pixel; - data->nv12 = true; data->textureNV = SDL_GetPointerProperty(create_props, SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_UV_POINTER, NULL); @@ -469,14 +471,7 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ } SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_UV_POINTER, data->textureNV); - switch (texture->format) { - case SDL_PIXELFORMAT_P010: - bits_per_pixel = 10; - break; - default: - bits_per_pixel = 8; - break; - } + const int bits_per_pixel = (texture->format == SDL_PIXELFORMAT_P010) ? 10 : 8; data->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel); if (!data->YCbCr_matrix) { return SDL_SetError("Unsupported YUV colorspace"); @@ -590,7 +585,7 @@ static bool GPU_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, cons retval &= GPU_UpdateTextureInternal(renderdata, cpass, data->textureV, bpp, rect->x, rect->y, rect->w, rect->h, Vplane, pitch); } else { int Ypitch = pitch; - int UVpitch = ((Ypitch + 1) / 2); + int UVpitch = ((Ypitch + 1 * SDL_BYTESPERPIXEL(texture->format)) / 2); const Uint8 *Yplane = (const Uint8 *)pixels; const Uint8 *Uplane = Yplane + rect->h * Ypitch; const Uint8 *Vplane = Uplane + ((rect->h + 1) / 2) * UVpitch; @@ -944,6 +939,7 @@ static void CalculateAdvancedShaderConstants(SDL_Renderer *renderer, const SDL_R constants->texture_type = TEXTURETYPE_NV12; constants->input_type = INPUTTYPE_HDR10; break; + case SDL_PIXELFORMAT_I0FL: case SDL_PIXELFORMAT_I4FL: constants->texture_type = TEXTURETYPE_YUV; constants->input_type = INPUTTYPE_HDR10; @@ -1912,6 +1908,7 @@ static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV12); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV21); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P010); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_I0FL); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_I4FL); SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 16384); diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m index 14b9853e3f..39eae3a36d 100644 --- a/src/render/metal/SDL_render_metal.m +++ b/src/render/metal/SDL_render_metal.m @@ -762,6 +762,7 @@ static bool METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD pixfmt = MTLPixelFormatR8Unorm; break; case SDL_PIXELFORMAT_P010: + case SDL_PIXELFORMAT_I0FL: case SDL_PIXELFORMAT_I4FL: pixfmt = MTLPixelFormatR16Unorm; break; @@ -806,7 +807,7 @@ static bool METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_METAL_TEXTURE_POINTER, (__bridge void *)mtltexture); #ifdef SDL_HAVE_YUV - BOOL yuv = (texture->format == SDL_PIXELFORMAT_IYUV || texture->format == SDL_PIXELFORMAT_YV12 || texture->format == SDL_PIXELFORMAT_I444 || texture->format == SDL_PIXELFORMAT_I4FL); + BOOL yuv = (texture->format == SDL_PIXELFORMAT_IYUV || texture->format == SDL_PIXELFORMAT_YV12 || texture->format == SDL_PIXELFORMAT_I444 || texture->format == SDL_PIXELFORMAT_I0FL || texture->format == SDL_PIXELFORMAT_I4FL); BOOL nv12 = (texture->format == SDL_PIXELFORMAT_NV12 || texture->format == SDL_PIXELFORMAT_NV21 || texture->format == SDL_PIXELFORMAT_P010); if (yuv) { @@ -1008,7 +1009,7 @@ static bool METAL_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, UVpitch = pitch; UVrect = *rect; } else { - UVpitch = (pitch + 1) / 2; + UVpitch = (pitch + 1 * SDL_BYTESPERPIXEL(texture->format)) / 2; UVrect.x = rect->x / 2; UVrect.y = rect->y / 2; UVrect.w = (rect->w + 1) / 2; @@ -1517,6 +1518,7 @@ static void SetupShaderConstants(SDL_Renderer *renderer, const SDL_RenderCommand case SDL_PIXELFORMAT_YV12: case SDL_PIXELFORMAT_IYUV: case SDL_PIXELFORMAT_I444: + case SDL_PIXELFORMAT_I0FL: case SDL_PIXELFORMAT_I4FL: constants->texture_type = TEXTURETYPE_YUV; break; @@ -2622,6 +2624,7 @@ static bool METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV12); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV21); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P010); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_I0FL); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_I4FL); #if defined(SDL_PLATFORM_MACOS) || TARGET_OS_MACCATALYST diff --git a/src/render/vulkan/SDL_render_vulkan.c b/src/render/vulkan/SDL_render_vulkan.c index 80086fb271..9f3993a1b3 100644 --- a/src/render/vulkan/SDL_render_vulkan.c +++ b/src/render/vulkan/SDL_render_vulkan.c @@ -433,6 +433,7 @@ static int VULKAN_VkFormatGetNumPlanes(VkFormat vkFormat) switch (vkFormat) { case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: + case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: return 3; case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: @@ -455,6 +456,7 @@ static VkDeviceSize VULKAN_GetBytesPerPixel(VkFormat vkFormat, int plane) case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: return 1; + case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: return 2; case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: @@ -485,6 +487,8 @@ static VkFormat SDLPixelFormatToVkTextureFormat(SDL_PixelFormat format, Uint32 o return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; case SDL_PIXELFORMAT_P010: return VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16; + case SDL_PIXELFORMAT_I0FL: + return VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM; case SDL_PIXELFORMAT_I4FL: return VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM; default: @@ -2665,6 +2669,7 @@ static bool VULKAN_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, S texture->format == SDL_PIXELFORMAT_NV12 || texture->format == SDL_PIXELFORMAT_NV21 || texture->format == SDL_PIXELFORMAT_P010 || + texture->format == SDL_PIXELFORMAT_I0FL || texture->format == SDL_PIXELFORMAT_I4FL) { const uint32_t YUV_SD_THRESHOLD = 576; @@ -3008,7 +3013,7 @@ static bool VULKAN_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, return VULKAN_UpdateTextureYUV(renderer, texture, rect, plane0, srcPitch, plane1, srcPitch, plane2, srcPitch); } else { int Ypitch = srcPitch; - int UVpitch = ((Ypitch + 1) / 2); + int UVpitch = ((Ypitch + 1 * SDL_BYTESPERPIXEL(texture->format)) / 2); const Uint8 *plane0 = (const Uint8 *)srcPixels; const Uint8 *plane1 = plane0 + rect->h * Ypitch; const Uint8 *plane2 = plane1 + ((rect->h + 1) / 2) * UVpitch; @@ -3497,6 +3502,7 @@ static void VULKAN_SetupShaderConstants(SDL_Renderer *renderer, const SDL_Render constants->input_type = INPUTTYPE_SRGB; break; case SDL_PIXELFORMAT_P010: + case SDL_PIXELFORMAT_I0FL: case SDL_PIXELFORMAT_I4FL: constants->input_type = INPUTTYPE_HDR10; break; @@ -4722,6 +4728,7 @@ static bool VULKAN_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SD SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV12); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV21); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P010); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_I0FL); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_I4FL); } #endif diff --git a/src/video/SDL_pixels.c b/src/video/SDL_pixels.c index e9d4250576..6ed5b23b67 100644 --- a/src/video/SDL_pixels.c +++ b/src/video/SDL_pixels.c @@ -216,6 +216,7 @@ const char *SDL_GetPixelFormatName(SDL_PixelFormat format) CASE(SDL_PIXELFORMAT_NV21) CASE(SDL_PIXELFORMAT_P010) CASE(SDL_PIXELFORMAT_I444) + CASE(SDL_PIXELFORMAT_I0FL) CASE(SDL_PIXELFORMAT_I4FL) CASE(SDL_PIXELFORMAT_EXTERNAL_OES) CASE(SDL_PIXELFORMAT_MJPG) @@ -856,7 +857,7 @@ SDL_Colorspace SDL_GetDefaultColorspaceForFormat(SDL_PixelFormat format) if (SDL_ISPIXELFORMAT_FOURCC(format)) { if (format == SDL_PIXELFORMAT_MJPG) { return SDL_COLORSPACE_SRGB; - } else if (format == SDL_PIXELFORMAT_P010 || format == SDL_PIXELFORMAT_I4FL) { + } else if (format == SDL_PIXELFORMAT_P010 || format == SDL_PIXELFORMAT_I0FL || format == SDL_PIXELFORMAT_I4FL) { return SDL_COLORSPACE_HDR10; } else { return SDL_COLORSPACE_YUV_DEFAULT; diff --git a/src/video/SDL_yuv.c b/src/video/SDL_yuv.c index 732351e152..0295e6a349 100644 --- a/src/video/SDL_yuv.c +++ b/src/video/SDL_yuv.c @@ -34,7 +34,12 @@ static bool IsPlanar1x1Format(SDL_PixelFormat format) static bool IsPlanar2x2Format(SDL_PixelFormat format) { - return format == SDL_PIXELFORMAT_YV12 || format == SDL_PIXELFORMAT_IYUV || format == SDL_PIXELFORMAT_NV12 || format == SDL_PIXELFORMAT_NV21 || format == SDL_PIXELFORMAT_P010; + return format == SDL_PIXELFORMAT_YV12 || + format == SDL_PIXELFORMAT_IYUV || + format == SDL_PIXELFORMAT_NV12 || + format == SDL_PIXELFORMAT_NV21 || + format == SDL_PIXELFORMAT_P010 || + format == SDL_PIXELFORMAT_I0FL; } static bool IsPacked4Format(Uint32 format) @@ -65,16 +70,19 @@ bool SDL_CalculateYUVSize(SDL_PixelFormat format, int w, int h, size_t *size, si sz_plane_chroma = sz_plane; } else if (IsPlanar2x2Format(format)) { { - /* sz_plane == w * h; */ + /* sz_plane == w * h * bpp; */ size_t s1; if (!SDL_size_mul_check_overflow(w, h, &s1)) { return SDL_SetError("width * height would overflow"); } - sz_plane = (int) s1; + if (!SDL_size_mul_check_overflow(s1, SDL_BYTESPERPIXEL(format), &s1)) { + return SDL_SetError("width * height * bpp would overflow"); + } + sz_plane = (int)s1; } { - /* sz_plane_chroma == ((w + 1) / 2) * ((h + 1) / 2); */ + /* sz_plane_chroma == ((w + 1) / 2) * ((h + 1) / 2) * bpp; */ size_t s1, s2, s3; if (!SDL_size_add_check_overflow(w, 1, &s1)) { return SDL_SetError("width + 1 would overflow"); @@ -87,7 +95,10 @@ bool SDL_CalculateYUVSize(SDL_PixelFormat format, int w, int h, size_t *size, si if (!SDL_size_mul_check_overflow(s1, s2, &s3)) { return SDL_SetError("width * height would overflow"); } - sz_plane_chroma = (int) s3; + if (!SDL_size_mul_check_overflow(s3, SDL_BYTESPERPIXEL(format), &s3)) { + return SDL_SetError("width * height * bpp would overflow"); + } + sz_plane_chroma = (int)s3; } } else { /* sz_plane_packed == ((w + 1) / 2) * h; */ @@ -105,8 +116,9 @@ bool SDL_CalculateYUVSize(SDL_PixelFormat format, int w, int h, size_t *size, si switch (format) { case SDL_PIXELFORMAT_YV12: /**< Planar mode: Y + V + U (3 planes) */ case SDL_PIXELFORMAT_IYUV: /**< Planar mode: Y + U + V (3 planes) */ - case SDL_PIXELFORMAT_I444: - case SDL_PIXELFORMAT_I4FL: + case SDL_PIXELFORMAT_I444: /**< Planar mode: Y + U + V (3 planes) */ + case SDL_PIXELFORMAT_I0FL: /**< Planar mode: Y + U + V (3 planes) */ + case SDL_PIXELFORMAT_I4FL: /**< Planar mode: Y + U + V (3 planes) */ if (pitch) { *pitch = w * SDL_BYTESPERPIXEL(format); @@ -223,9 +235,10 @@ static bool GetYUVPlanes(int width, int height, SDL_PixelFormat format, const vo switch (format) { case SDL_PIXELFORMAT_YV12: case SDL_PIXELFORMAT_IYUV: + case SDL_PIXELFORMAT_I0FL: pitches[0] = yuv_pitch; - pitches[1] = (pitches[0] + 1) / 2; - pitches[2] = (pitches[0] + 1) / 2; + pitches[1] = (pitches[0] + 1 * SDL_BYTESPERPIXEL(format)) / 2; + pitches[2] = pitches[1]; planes[0] = (const Uint8 *)yuv; planes[1] = planes[0] + pitches[0] * height; planes[2] = planes[1] + pitches[1] * ((height + 1) / 2); @@ -273,6 +286,7 @@ static bool GetYUVPlanes(int width, int height, SDL_PixelFormat format, const vo break; case SDL_PIXELFORMAT_IYUV: case SDL_PIXELFORMAT_I444: + case SDL_PIXELFORMAT_I0FL: case SDL_PIXELFORMAT_I4FL: *y = planes[0]; *y_stride = pitches[0]; @@ -635,6 +649,16 @@ static bool yuv_rgb_std( } } + if (src_format == SDL_PIXELFORMAT_I0FL) { + switch (dst_format) { + case SDL_PIXELFORMAT_RGB48: + yuvi0fl_rgb48_std(width, height, (const uint16_t *)y, (const uint16_t *)u, (const uint16_t *)v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); + return true; + default: + break; + } + } + if (src_format == SDL_PIXELFORMAT_I4FL) { switch (dst_format) { case SDL_PIXELFORMAT_RGB48: @@ -702,7 +726,7 @@ bool SDL_ConvertPixels_YUV_to_RGB(int width, int height, return result; } - if (src_format == SDL_PIXELFORMAT_I4FL && dst_format != SDL_PIXELFORMAT_RGB48) { + if ((src_format == SDL_PIXELFORMAT_I0FL || src_format == SDL_PIXELFORMAT_I4FL) && dst_format != SDL_PIXELFORMAT_RGB48) { bool result; void *tmp; int tmp_pitch = (width * 3 * sizeof(Uint16)); diff --git a/src/video/yuv2rgb/yuv_rgb_std.c b/src/video/yuv2rgb/yuv_rgb_std.c index ea08d7a156..694021b4fd 100644 --- a/src/video/yuv2rgb/yuv_rgb_std.c +++ b/src/video/yuv2rgb/yuv_rgb_std.c @@ -175,6 +175,11 @@ static uint16_t clamp16(int32_t v) #undef YUV_BITS #define YUV_BITS 16 +#define STD_FUNCTION_NAME yuvi0fl_rgb48_std +#define YUV_FORMAT YUV_FORMAT_420 +#define RGB_FORMAT RGB_FORMAT_RGB48 +#include "yuv_rgb_std_func.h" + #define STD_FUNCTION_NAME yuvi4fl_rgb48_std #define YUV_FORMAT YUV_FORMAT_444 #define RGB_FORMAT RGB_FORMAT_RGB48 diff --git a/src/video/yuv2rgb/yuv_rgb_std.h b/src/video/yuv2rgb/yuv_rgb_std.h index 0c01a0f02b..03441b9560 100644 --- a/src/video/yuv2rgb/yuv_rgb_std.h +++ b/src/video/yuv2rgb/yuv_rgb_std.h @@ -159,6 +159,12 @@ void yuvp010_xbgr2101010_std( uint8_t *rgb, uint32_t rgb_stride, YCbCrType yuv_type); +void yuvi0fl_rgb48_std( + uint32_t width, uint32_t height, + const uint16_t *y, const uint16_t *u, const uint16_t *v, uint32_t y_stride, uint32_t uv_stride, + uint8_t *rgb, uint32_t rgb_stride, + YCbCrType yuv_type); + void yuvi4fl_rgb48_std( uint32_t width, uint32_t height, const uint16_t *y, const uint16_t *u, const uint16_t *v, uint32_t y_stride, uint32_t uv_stride, diff --git a/test/testautomation_pixels.c b/test/testautomation_pixels.c index d5d8b9d912..5e0fa0ce5b 100644 --- a/test/testautomation_pixels.c +++ b/test/testautomation_pixels.c @@ -640,6 +640,14 @@ SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I444_ARRAY, !SDL_ISPIXELFORMAT_ARRAY(SDL SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I444_10BIT, !SDL_ISPIXELFORMAT_10BIT(SDL_PIXELFORMAT_I444)); SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I444_FLOAT, !SDL_ISPIXELFORMAT_FLOAT(SDL_PIXELFORMAT_I444)); SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I444_ALPHA, !SDL_ISPIXELFORMAT_ALPHA(SDL_PIXELFORMAT_I444)); +SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I0FL_FORMAT, SDL_PIXELFORMAT_I0FL == SDL_DEFINE_PIXELFOURCC('I', '0', 'F', 'L')); +SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I0FL_FOURCC, SDL_ISPIXELFORMAT_FOURCC(SDL_PIXELFORMAT_I0FL)); +SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I0FL_INDEXED, !SDL_ISPIXELFORMAT_INDEXED(SDL_PIXELFORMAT_I0FL)); +SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I0FL_PACKED, !SDL_ISPIXELFORMAT_PACKED(SDL_PIXELFORMAT_I0FL)); +SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I0FL_ARRAY, !SDL_ISPIXELFORMAT_ARRAY(SDL_PIXELFORMAT_I0FL)); +SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I0FL_10BIT, !SDL_ISPIXELFORMAT_10BIT(SDL_PIXELFORMAT_I0FL)); +SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I0FL_FLOAT, !SDL_ISPIXELFORMAT_FLOAT(SDL_PIXELFORMAT_I0FL)); +SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I0FL_ALPHA, !SDL_ISPIXELFORMAT_ALPHA(SDL_PIXELFORMAT_I0FL)); SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I4FL_FORMAT, SDL_PIXELFORMAT_I4FL == SDL_DEFINE_PIXELFOURCC('I', '4', 'F', 'L')); SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I4FL_FOURCC, SDL_ISPIXELFORMAT_FOURCC(SDL_PIXELFORMAT_I4FL)); SDL_COMPILE_TIME_ASSERT(SDL_PIXELFORMAT_I4FL_INDEXED, !SDL_ISPIXELFORMAT_INDEXED(SDL_PIXELFORMAT_I4FL)); diff --git a/test/testyuv.c b/test/testyuv.c index ba70a52a8a..767b616e40 100644 --- a/test/testyuv.c +++ b/test/testyuv.c @@ -415,16 +415,16 @@ static bool create_textures(SDL_Renderer *renderer, SDL_Surface *original, SDL_P SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create texture: %s", SDL_GetError()); goto done; } - if (planar && (yuv_format == SDL_PIXELFORMAT_YV12 || yuv_format == SDL_PIXELFORMAT_IYUV)) { + if (planar && (yuv_format == SDL_PIXELFORMAT_YV12 || yuv_format == SDL_PIXELFORMAT_IYUV || yuv_format == SDL_PIXELFORMAT_I0FL)) { const int Yrows = original->h; const int UVrows = ((original->h + 1) / 2); const int src_Ypitch = pitch; - const int src_UVpitch = ((pitch + 1) / 2); + const int src_UVpitch = ((pitch + 1 * SDL_BYTESPERPIXEL(yuv_format)) / 2); const Uint8 *src_plane0 = (const Uint8 *)raw_yuv; const Uint8 *src_plane1 = src_plane0 + Yrows * src_Ypitch; const Uint8 *src_plane2 = src_plane1 + UVrows * src_UVpitch; const int Ypitch = pitch + 37; - const int UVpitch = ((Ypitch + 1) / 2); + const int UVpitch = ((Ypitch + 1 * SDL_BYTESPERPIXEL(yuv_format)) / 2); Uint8 *plane0 = (Uint8 *)SDL_calloc(1, Yrows * Ypitch); Uint8 *plane1 = (Uint8 *)SDL_calloc(1, UVrows * UVpitch); Uint8 *plane2 = (Uint8 *)SDL_calloc(1, UVrows * UVpitch); @@ -929,6 +929,11 @@ int main(int argc, char **argv) rgb_format = SDL_PIXELFORMAT_XBGR2101010; SetYUVConversionMode(YUV_CONVERSION_BT2020); consumed = 1; + } else if (SDL_strcmp(argv[i], "--i0fl") == 0) { + yuv_format = SDL_PIXELFORMAT_I0FL; + rgb_format = SDL_PIXELFORMAT_XBGR2101010; + SetYUVConversionMode(YUV_CONVERSION_BT2020); + consumed = 1; } else if (SDL_strcmp(argv[i], "--i4fl") == 0) { yuv_format = SDL_PIXELFORMAT_I4FL; rgb_format = SDL_PIXELFORMAT_XBGR2101010; diff --git a/test/testyuv_cvt.c b/test/testyuv_cvt.c index 3d9d2ba3c1..1062aa100a 100644 --- a/test/testyuv_cvt.c +++ b/test/testyuv_cvt.c @@ -277,112 +277,123 @@ static void ConvertRGBtoPlanar2x2(Uint32 format, Uint8 *src, int pitch, Uint8 *o Uint8 *rgb1, *rgb2; int rgb_row_advance = (pitch - w * 3) + pitch; int UV_advance; + int yuv_bits; + int yuv_bytes_per_pixel = SDL_BYTESPERPIXEL(format); rgb1 = src; rgb2 = src + pitch; Y1 = out; - Y2 = Y1 + w; + Y2 = Y1 + w * yuv_bytes_per_pixel; switch (format) { case SDL_PIXELFORMAT_YV12: + yuv_bits = 8; V = (Y1 + h * w); U = V + ((h + 1) / 2) * ((w + 1) / 2); UV_advance = 1; break; case SDL_PIXELFORMAT_IYUV: + yuv_bits = 8; U = (Y1 + h * w); V = U + ((h + 1) / 2) * ((w + 1) / 2); UV_advance = 1; break; case SDL_PIXELFORMAT_NV12: + yuv_bits = 8; U = (Y1 + h * w); V = U + 1; UV_advance = 2; break; case SDL_PIXELFORMAT_NV21: + yuv_bits = 8; V = (Y1 + h * w); U = V + 1; UV_advance = 2; break; + case SDL_PIXELFORMAT_I0FL: + yuv_bits = 16; + U = (Y1 + h * w * yuv_bytes_per_pixel); + V = U + ((h + 1) / 2) * ((w + 1) / 2) * yuv_bytes_per_pixel; + UV_advance = 1; + break; default: SDL_assert(!"Unsupported planar YUV format"); return; } +#define COPY_VALUE(X, V, ADVANCE) \ + do { \ + if (format == SDL_PIXELFORMAT_I0FL) { \ + *(Uint16 *)X = (Uint16)V; \ + } else { \ + *X = (Uint8)V; \ + } \ + X += ADVANCE * yuv_bytes_per_pixel; \ + } while (0) + for (y = 0; y < (h - 1); y += 2) { for (x = 0; x < (w - 1); x += 2) { - RGBtoYUV(rgb1, 8, yuv[0], 8, mode, monochrome, luminance); + RGBtoYUV(rgb1, 8, yuv[0], yuv_bits, mode, monochrome, luminance); rgb1 += 3; - *Y1++ = (Uint8)yuv[0][0]; + COPY_VALUE(Y1, yuv[0][0], 1); - RGBtoYUV(rgb1, 8, yuv[1], 8, mode, monochrome, luminance); + RGBtoYUV(rgb1, 8, yuv[1], yuv_bits, mode, monochrome, luminance); rgb1 += 3; - *Y1++ = (Uint8)yuv[1][0]; + COPY_VALUE(Y1, yuv[1][0], 1); - RGBtoYUV(rgb2, 8, yuv[2], 8, mode, monochrome, luminance); + RGBtoYUV(rgb2, 8, yuv[2], yuv_bits, mode, monochrome, luminance); rgb2 += 3; - *Y2++ = (Uint8)yuv[2][0]; + COPY_VALUE(Y2, yuv[2][0], 1); - RGBtoYUV(rgb2, 8, yuv[3], 8, mode, monochrome, luminance); + RGBtoYUV(rgb2, 8, yuv[3], yuv_bits, mode, monochrome, luminance); rgb2 += 3; - *Y2++ = (Uint8)yuv[3][0]; + COPY_VALUE(Y2, yuv[3][0], 1); - *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[1][1] + yuv[2][1] + yuv[3][1]) / 4.0f + 0.5f); - U += UV_advance; - - *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[1][2] + yuv[2][2] + yuv[3][2]) / 4.0f + 0.5f); - V += UV_advance; + COPY_VALUE(U, SDL_floorf((yuv[0][1] + yuv[1][1] + yuv[2][1] + yuv[3][1]) / 4.0f + 0.5f), UV_advance); + COPY_VALUE(V, SDL_floorf((yuv[0][2] + yuv[1][2] + yuv[2][2] + yuv[3][2]) / 4.0f + 0.5f), UV_advance); } /* Last column */ if (x == (w - 1)) { - RGBtoYUV(rgb1, 8, yuv[0], 8, mode, monochrome, luminance); + RGBtoYUV(rgb1, 8, yuv[0], yuv_bits, mode, monochrome, luminance); rgb1 += 3; - *Y1++ = (Uint8)yuv[0][0]; + COPY_VALUE(Y1, yuv[0][0], 1); - RGBtoYUV(rgb2, 8, yuv[2], 8, mode, monochrome, luminance); + RGBtoYUV(rgb2, 8, yuv[2], yuv_bits, mode, monochrome, luminance); rgb2 += 3; - *Y2++ = (Uint8)yuv[2][0]; + COPY_VALUE(Y2, yuv[2][0], 1); - *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[2][1]) / 2.0f + 0.5f); - U += UV_advance; - - *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[2][2]) / 2.0f + 0.5f); - V += UV_advance; + COPY_VALUE(U, SDL_floorf((yuv[0][1] + yuv[2][1]) / 2.0f + 0.5f), UV_advance); + COPY_VALUE(V, SDL_floorf((yuv[0][2] + yuv[2][2]) / 2.0f + 0.5f), UV_advance); } - Y1 += w; - Y2 += w; + Y1 += w * yuv_bytes_per_pixel; + Y2 += w * yuv_bytes_per_pixel; rgb1 += rgb_row_advance; rgb2 += rgb_row_advance; } /* Last row */ if (y == (h - 1)) { for (x = 0; x < (w - 1); x += 2) { - RGBtoYUV(rgb1, 8, yuv[0], 8, mode, monochrome, luminance); + RGBtoYUV(rgb1, 8, yuv[0], yuv_bits, mode, monochrome, luminance); rgb1 += 3; - *Y1++ = (Uint8)yuv[0][0]; + COPY_VALUE(Y1, yuv[0][0], 1); - RGBtoYUV(rgb1, 8, yuv[1], 8, mode, monochrome, luminance); + RGBtoYUV(rgb1, 8, yuv[1], yuv_bits, mode, monochrome, luminance); rgb1 += 3; - *Y1++ = (Uint8)yuv[1][0]; + COPY_VALUE(Y1, yuv[1][0], 1); - *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[1][1]) / 2.0f + 0.5f); - U += UV_advance; - - *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[1][2]) / 2.0f + 0.5f); - V += UV_advance; + COPY_VALUE(U, SDL_floorf((yuv[0][1] + yuv[1][1]) / 2.0f + 0.5f), UV_advance); + COPY_VALUE(V, SDL_floorf((yuv[0][2] + yuv[1][2]) / 2.0f + 0.5f), UV_advance); } /* Last column */ if (x == (w - 1)) { RGBtoYUV(rgb1, 8, yuv[0], 8, mode, monochrome, luminance); - *Y1++ = (Uint8)yuv[0][0]; + COPY_VALUE(Y1, yuv[0][0], 1); - *U = (Uint8)yuv[0][1]; - U += UV_advance; - - *V = (Uint8)yuv[0][2]; - V += UV_advance; + COPY_VALUE(U, yuv[0][1], UV_advance); + COPY_VALUE(V, yuv[0][2], UV_advance); } } +#undef COPY_VALUE } static Uint16 Pack10to16(int v) @@ -575,6 +586,7 @@ bool ConvertRGBtoYUV(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, in case SDL_PIXELFORMAT_IYUV: case SDL_PIXELFORMAT_NV12: case SDL_PIXELFORMAT_NV21: + case SDL_PIXELFORMAT_I0FL: ConvertRGBtoPlanar2x2(format, src, pitch, out, w, h, mode, monochrome, luminance); return true; case SDL_PIXELFORMAT_YUY2: @@ -591,6 +603,7 @@ int CalculateYUVPitch(Uint32 format, int width) { switch (format) { case SDL_PIXELFORMAT_P010: + case SDL_PIXELFORMAT_I0FL: case SDL_PIXELFORMAT_I4FL: return width * 2; case SDL_PIXELFORMAT_YV12: