|
|
@@ -373,7 +373,266 @@ done:
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-static bool create_textures(SDL_Renderer *renderer, SDL_Surface *original, SDL_PixelFormat yuv_format, SDL_PixelFormat rgb_format, bool planar, bool monochrome, int luminance, SDL_Texture *output[3])
|
|
|
+// Copied from SDL_yuv_sw.c to verify functionality
|
|
|
+
|
|
|
+struct SW_YUVTexture
|
|
|
+{
|
|
|
+ SDL_PixelFormat format;
|
|
|
+ int w, h;
|
|
|
+ Uint8 *pixels;
|
|
|
+ int pitches[3];
|
|
|
+ Uint8 *planes[3];
|
|
|
+};
|
|
|
+
|
|
|
+typedef struct SW_YUVTexture SW_YUVTexture;
|
|
|
+
|
|
|
+static SW_YUVTexture *SW_CreateYUVTexture(SDL_PixelFormat format, int w, int h, void *pixels, int pitch)
|
|
|
+{
|
|
|
+ SW_YUVTexture *swdata;
|
|
|
+
|
|
|
+ switch (format) {
|
|
|
+ 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:
|
|
|
+ case SDL_PIXELFORMAT_YVYU:
|
|
|
+ case SDL_PIXELFORMAT_NV12:
|
|
|
+ case SDL_PIXELFORMAT_NV21:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ SDL_SetError("Unsupported YUV format");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ swdata = (SW_YUVTexture *)SDL_calloc(1, sizeof(*swdata));
|
|
|
+ if (!swdata) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ swdata->format = format;
|
|
|
+ swdata->w = w;
|
|
|
+ swdata->h = h;
|
|
|
+ swdata->pixels = (Uint8 *)pixels;
|
|
|
+
|
|
|
+ // Find the pitch and offset values for the texture
|
|
|
+ const int bpp = SDL_BYTESPERPIXEL(format);
|
|
|
+ switch (format) {
|
|
|
+ case SDL_PIXELFORMAT_YV12:
|
|
|
+ case SDL_PIXELFORMAT_IYUV:
|
|
|
+ case SDL_PIXELFORMAT_I0FL:
|
|
|
+ swdata->pitches[0] = pitch;
|
|
|
+ swdata->pitches[1] = (((swdata->pitches[0] / bpp) + 1) / 2) * bpp;
|
|
|
+ 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);
|
|
|
+ break;
|
|
|
+ case SDL_PIXELFORMAT_I444:
|
|
|
+ case SDL_PIXELFORMAT_I4FL:
|
|
|
+ swdata->pitches[0] = w * bpp;
|
|
|
+ swdata->pitches[1] = swdata->pitches[0];
|
|
|
+ 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;
|
|
|
+ break;
|
|
|
+ case SDL_PIXELFORMAT_YUY2:
|
|
|
+ case SDL_PIXELFORMAT_UYVY:
|
|
|
+ case SDL_PIXELFORMAT_YVYU:
|
|
|
+ swdata->pitches[0] = ((w + 1) / 2) * 4;
|
|
|
+ swdata->planes[0] = swdata->pixels;
|
|
|
+ break;
|
|
|
+ case SDL_PIXELFORMAT_NV12:
|
|
|
+ case SDL_PIXELFORMAT_NV21:
|
|
|
+ swdata->pitches[0] = w;
|
|
|
+ swdata->pitches[1] = 2 * ((swdata->pitches[0] + 1) / 2);
|
|
|
+ swdata->planes[0] = swdata->pixels;
|
|
|
+ swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ SDL_assert(!"We should never get here (caught above)");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // We're all done..
|
|
|
+ return swdata;
|
|
|
+}
|
|
|
+
|
|
|
+static bool SW_UpdateYUVTexture(SW_YUVTexture *swdata, const SDL_Rect *rect, const void *pixels, int pitch)
|
|
|
+{
|
|
|
+ const int bpp = SDL_BYTESPERPIXEL(swdata->format);
|
|
|
+
|
|
|
+ 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,
|
|
|
+ (size_t)(swdata->h * swdata->w * bpp) + 2 * ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2) * bpp);
|
|
|
+ } else {
|
|
|
+ Uint8 *src, *dst;
|
|
|
+ int row;
|
|
|
+ size_t length;
|
|
|
+ const int UVpitch = ((pitch / bpp + 1) / 2) * bpp;
|
|
|
+
|
|
|
+ // Copy the Y plane
|
|
|
+ src = (Uint8 *)pixels;
|
|
|
+ dst = swdata->pixels + rect->y * swdata->w * bpp + rect->x * bpp;
|
|
|
+ length = rect->w * bpp;
|
|
|
+ for (row = 0; row < rect->h; ++row) {
|
|
|
+ SDL_memcpy(dst, src, length);
|
|
|
+ src += pitch;
|
|
|
+ dst += swdata->pitches[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ // Copy the next plane
|
|
|
+ src = (Uint8 *)pixels + rect->h * pitch;
|
|
|
+ dst = swdata->pixels + swdata->h * swdata->pitches[0];
|
|
|
+ dst += (rect->y / 2) * swdata->pitches[1] + (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 += UVpitch;
|
|
|
+ dst += swdata->pitches[1];
|
|
|
+ }
|
|
|
+
|
|
|
+ // Copy the next plane
|
|
|
+ src = (Uint8 *)pixels + rect->h * pitch + ((rect->h + 1) / 2) * UVpitch;
|
|
|
+ dst = swdata->pixels + swdata->h * swdata->pitches[0] + ((rect->h + 1) / 2) * swdata->pitches[1];
|
|
|
+ dst += (rect->y / 2) * swdata->pitches[2] + (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 += UVpitch;
|
|
|
+ dst += swdata->pitches[2];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case SDL_PIXELFORMAT_I444:
|
|
|
+ case SDL_PIXELFORMAT_I4FL:
|
|
|
+ if (rect->x == 0 && rect->y == 0 &&
|
|
|
+ rect->w == swdata->w && rect->h == swdata->h && pitch == swdata->pitches[0]) {
|
|
|
+ SDL_memcpy(swdata->pixels, pixels, (size_t)(swdata->h * pitch * 3));
|
|
|
+ } else {
|
|
|
+ Uint8 *src, *dst;
|
|
|
+ int row;
|
|
|
+ size_t length;
|
|
|
+
|
|
|
+ // Copy the Y plane
|
|
|
+ src = (Uint8 *)pixels;
|
|
|
+ dst = swdata->pixels;
|
|
|
+ dst += rect->y * swdata->pitches[0] + rect->x * bpp;
|
|
|
+ length = rect->w * bpp;
|
|
|
+ for (row = 0; row < rect->h; ++row) {
|
|
|
+ SDL_memcpy(dst, src, length);
|
|
|
+ src += pitch;
|
|
|
+ dst += swdata->pitches[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ // Copy the next plane
|
|
|
+ dst = swdata->pixels + swdata->h * swdata->pitches[0];
|
|
|
+ dst += rect->y * swdata->pitches[1] + rect->x * bpp;
|
|
|
+ for (row = 0; row < rect->h; ++row) {
|
|
|
+ SDL_memcpy(dst, src, length);
|
|
|
+ src += pitch;
|
|
|
+ dst += swdata->pitches[1];
|
|
|
+ }
|
|
|
+
|
|
|
+ // Copy the next plane
|
|
|
+ dst = swdata->pixels + swdata->h * swdata->pitches[0] + swdata->h * swdata->pitches[1];
|
|
|
+ dst += rect->y * swdata->pitches[2] + rect->x * bpp;
|
|
|
+ for (row = 0; row < rect->h; ++row) {
|
|
|
+ SDL_memcpy(dst, src, length);
|
|
|
+ src += pitch;
|
|
|
+ dst += swdata->pitches[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 = 4 * (((size_t)rect->w + 1) / 2);
|
|
|
+ for (row = 0; row < rect->h; ++row) {
|
|
|
+ SDL_memcpy(dst, src, length);
|
|
|
+ src += pitch;
|
|
|
+ dst += swdata->pitches[0];
|
|
|
+ }
|
|
|
+ } break;
|
|
|
+ case SDL_PIXELFORMAT_NV12:
|
|
|
+ case SDL_PIXELFORMAT_NV21:
|
|
|
+ {
|
|
|
+ if (rect->x == 0 && rect->y == 0 && rect->w == swdata->w && rect->h == swdata->h) {
|
|
|
+ SDL_memcpy(swdata->pixels, pixels,
|
|
|
+ (size_t)(swdata->h * swdata->w) + 2 * ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2));
|
|
|
+ } else {
|
|
|
+
|
|
|
+ Uint8 *src, *dst;
|
|
|
+ int row;
|
|
|
+ size_t length;
|
|
|
+
|
|
|
+ // Copy the Y plane
|
|
|
+ src = (Uint8 *)pixels;
|
|
|
+ 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 += pitch;
|
|
|
+ dst += swdata->w;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Copy the next plane
|
|
|
+ src = (Uint8 *)pixels + rect->h * pitch;
|
|
|
+ dst = swdata->pixels + swdata->h * swdata->w;
|
|
|
+ dst += 2 * ((rect->y + 1) / 2) * ((swdata->w + 1) / 2) + 2 * (rect->x / 2);
|
|
|
+ length = 2 * (((size_t)rect->w + 1) / 2);
|
|
|
+ for (row = 0; row < (rect->h + 1) / 2; ++row) {
|
|
|
+ SDL_memcpy(dst, src, length);
|
|
|
+ src += 2 * ((pitch + 1) / 2);
|
|
|
+ dst += 2 * ((swdata->w + 1) / 2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } break;
|
|
|
+ default:
|
|
|
+ return SDL_SetError("Unsupported YUV format");
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static void SW_DestroyYUVTexture(SW_YUVTexture *swdata)
|
|
|
+{
|
|
|
+ if (swdata) {
|
|
|
+ SDL_free(swdata);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static bool update_locked_texture(SDL_PixelFormat format, int w, int h, const void *pixels, int pitch, void *output_pixels, int output_pitch)
|
|
|
+{
|
|
|
+ SW_YUVTexture *swdata = SW_CreateYUVTexture(format, w, h, output_pixels, output_pitch);
|
|
|
+ if (!swdata) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ SDL_Rect rect = { 0, 0, w, h };
|
|
|
+ bool result = SW_UpdateYUVTexture(swdata, &rect, pixels, pitch);
|
|
|
+ SW_DestroyYUVTexture(swdata);
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+static bool create_textures(SDL_Renderer *renderer, SDL_Surface *original, SDL_PixelFormat yuv_format, SDL_PixelFormat rgb_format, bool planar, bool lock, bool monochrome, int luminance, SDL_Texture *output[3])
|
|
|
{
|
|
|
SDL_Colorspace rgb_colorspace = SDL_COLORSPACE_SRGB;
|
|
|
SDL_Colorspace yuv_colorspace;
|
|
|
@@ -556,6 +815,19 @@ static bool create_textures(SDL_Renderer *renderer, SDL_Surface *original, SDL_P
|
|
|
SDL_UpdateNVTexture(output[2], NULL, plane0, Ypitch, plane1, UVpitch);
|
|
|
SDL_free(plane0);
|
|
|
SDL_free(plane1);
|
|
|
+ } else if (lock) {
|
|
|
+ void *dst;
|
|
|
+ int dst_pitch;
|
|
|
+ if (!SDL_LockTexture(output[2], NULL, &dst, &dst_pitch)) {
|
|
|
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't lock YUV texture: %s", SDL_GetError());
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ bool updated = update_locked_texture(yuv_format, original->w, original->h, raw_yuv, pitch, dst, dst_pitch);
|
|
|
+ SDL_UnlockTexture(output[2]);
|
|
|
+ if (!updated) {
|
|
|
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't update YUV texture: %s", SDL_GetError());
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
} else {
|
|
|
SDL_UpdateTexture(output[2], NULL, raw_yuv, pitch);
|
|
|
}
|
|
|
@@ -610,12 +882,12 @@ static bool check_output(SDL_Renderer *renderer, SDL_Surface *original, SDL_Text
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-static bool run_single_format_test(SDL_Renderer *renderer, SDL_Surface *original, SDL_PixelFormat yuv_format, SDL_PixelFormat rgb_format, bool planar)
|
|
|
+static bool run_single_format_test(SDL_Renderer *renderer, SDL_Surface *original, SDL_PixelFormat yuv_format, SDL_PixelFormat rgb_format, bool planar, bool lock)
|
|
|
{
|
|
|
SDL_Texture *output[3];
|
|
|
bool result = true;
|
|
|
|
|
|
- if (!create_textures(renderer, original, yuv_format, rgb_format, planar, false, 100, output)) {
|
|
|
+ if (!create_textures(renderer, original, yuv_format, rgb_format, planar, lock, false, 100, output)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
@@ -668,7 +940,7 @@ static bool run_all_format_test(SDL_Window *window, const char *requested_render
|
|
|
{ YUV_CONVERSION_JPEG, "JPEG" },
|
|
|
{ YUV_CONVERSION_BT601, "BT601" },
|
|
|
{ YUV_CONVERSION_BT709, "BT709" },
|
|
|
- { YUV_CONVERSION_BT2020, "BT2020" }
|
|
|
+ //{ YUV_CONVERSION_BT2020, "BT2020" }
|
|
|
};
|
|
|
bool quit = false;
|
|
|
bool result = true;
|
|
|
@@ -700,10 +972,13 @@ static bool run_all_format_test(SDL_Window *window, const char *requested_render
|
|
|
SDL_PixelFormat rgb_format = rgb_formats[n];
|
|
|
|
|
|
SDL_Log("Testing: %s %s %s %s (planar)", renderer_name, colorspaces[j].name, SDL_GetPixelFormatName(yuv_format), SDL_GetPixelFormatName(rgb_format));
|
|
|
- result &= run_single_format_test(renderer, original, yuv_format, rgb_format, true);
|
|
|
+ result &= run_single_format_test(renderer, original, yuv_format, rgb_format, true, false);
|
|
|
|
|
|
SDL_Log("Testing: %s %s %s %s (packed)", renderer_name, colorspaces[j].name, SDL_GetPixelFormatName(yuv_format), SDL_GetPixelFormatName(rgb_format));
|
|
|
- result &= run_single_format_test(renderer, original, yuv_format, rgb_format, false);
|
|
|
+ result &= run_single_format_test(renderer, original, yuv_format, rgb_format, false, false);
|
|
|
+
|
|
|
+ SDL_Log("Testing: %s %s %s %s (locked)", renderer_name, colorspaces[j].name, SDL_GetPixelFormatName(yuv_format), SDL_GetPixelFormatName(rgb_format));
|
|
|
+ result &= run_single_format_test(renderer, original, yuv_format, rgb_format, false, true);
|
|
|
|
|
|
SDL_Event event;
|
|
|
while (SDL_PollEvent(&event)) {
|
|
|
@@ -720,7 +995,7 @@ static bool run_all_format_test(SDL_Window *window, const char *requested_render
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-static bool run_interactive(SDL_Window *window, const char *renderer_name, SDL_Surface *original, SDL_PixelFormat yuv_format, SDL_PixelFormat rgb_format, bool planar, bool monochrome, int luminance)
|
|
|
+static bool run_interactive(SDL_Window *window, const char *renderer_name, SDL_Surface *original, SDL_PixelFormat yuv_format, SDL_PixelFormat rgb_format, bool planar, bool lock, bool monochrome, int luminance)
|
|
|
{
|
|
|
const char *titles[3] = { "ORIGINAL", "SOFTWARE", "HARDWARE" };
|
|
|
char title[128];
|
|
|
@@ -739,7 +1014,7 @@ static bool run_interactive(SDL_Window *window, const char *renderer_name, SDL_S
|
|
|
renderer_name = SDL_GetRendererName(renderer);
|
|
|
|
|
|
SDL_Texture *output[3];
|
|
|
- if (!create_textures(renderer, original, yuv_format, rgb_format, planar, monochrome, luminance, output)) {
|
|
|
+ if (!create_textures(renderer, original, yuv_format, rgb_format, planar, lock, monochrome, luminance, output)) {
|
|
|
goto done;
|
|
|
}
|
|
|
|
|
|
@@ -865,6 +1140,7 @@ int main(int argc, char **argv)
|
|
|
Uint32 yuv_format = SDL_PIXELFORMAT_YV12;
|
|
|
Uint32 rgb_format = SDL_PIXELFORMAT_RGBX8888;
|
|
|
bool planar = false;
|
|
|
+ bool lock = false;
|
|
|
bool monochrome = false;
|
|
|
int luminance = 100;
|
|
|
int i;
|
|
|
@@ -964,6 +1240,9 @@ int main(int argc, char **argv)
|
|
|
} else if (SDL_strcmp(argv[i], "--planar") == 0) {
|
|
|
planar = true;
|
|
|
consumed = 1;
|
|
|
+ } else if (SDL_strcmp(argv[i], "--lock") == 0) {
|
|
|
+ lock = true;
|
|
|
+ consumed = 1;
|
|
|
} else if (SDL_strcmp(argv[i], "--monochrome") == 0) {
|
|
|
monochrome = true;
|
|
|
consumed = 1;
|
|
|
@@ -989,7 +1268,7 @@ int main(int argc, char **argv)
|
|
|
"[--jpeg|--bt601|--bt709|--auto]",
|
|
|
"[--yv12|--iyuv|--i444|--yuy2|--uyvy|--yvyu|--nv12|--nv21|--p010|--i4fl]",
|
|
|
"[--rgb555|--rgb565|--rgb24|--argb|--abgr|--rgba|--bgra]",
|
|
|
- "[--monochrome] [--luminance N%] [--planar]",
|
|
|
+ "[--monochrome] [--luminance N%] [--planar] [--lock]",
|
|
|
"[--automated] [--colorspace-test] [--renderer NAME]",
|
|
|
"[sample.png]",
|
|
|
NULL,
|
|
|
@@ -1047,7 +1326,7 @@ int main(int argc, char **argv)
|
|
|
result = 5;
|
|
|
}
|
|
|
} else {
|
|
|
- if (!run_interactive(window, renderer_name, original, yuv_format, rgb_format, planar, monochrome, luminance)) {
|
|
|
+ if (!run_interactive(window, renderer_name, original, yuv_format, rgb_format, planar, lock, monochrome, luminance)) {
|
|
|
result = 5;
|
|
|
}
|
|
|
}
|