00cc9309cb
de6e324bdseparate emu thread10d3daf86Roms List improvements95d202f37Let's make the rom list process on a separate thread so the emulator doesnt take ages to load.fc306967fWow the ROM Header was just completely busted. Game list view works nowbad1691eefuck this shit2b59e5f46game list in progressd26417b83remappable inputs in progressac4af8106inpute72abc240update readme430139dc9Qt6 frontend3080d4d45Fix this small bug too08cd13b85Cop0 unused functions do not actually pose a threat (as per manual). They don't do anything, so shall we.61bb4fb44make idle loop detection a little more specific with where the load goesb037de4c3SAZDFsdff12e81e73eneed to figure out why n64-systemtest loops indefinitely at some address that appears to be valid (i think it's me not invalidating the cache properly)204f0e13bidle skipping seems to work!cb8bb634asdkfjlasdf58e5c89c1Fix compilation issue on my machine (no idea)24fb2898eattempting more serious idle skipping214719577Place rsp.Step inside cached interpreter. Gains about 3 more fpsbb97dcc23mmmmm920b77d38wjkhasdfjhkasdf430ccdab4it's a start...4f42a673aCached interpreter plays Mario 64. Start looking into RSP as wellc9a030787idle skipping works!5fbda03cenew idea366637abaIdle skipping... maybe?609fa2fb0Cache instructions implemented but broken lmao. Commented out for nowe140a6d12- Stop using inheritance for CPU, instead use composition. - Introduce KAIZEN_JIT_ENABLED optional define instead of relying on __aarch64__ and the like. - More cache work68e613057prep cache impl811b4d809fix clang formatfda755f7didkd5024ebbfsmall MI refactor in preparation of (eventually) implementing the RDRAM interface properly694b45341Merge commit '206dcdedf195fb320913584180edb12c7731e396' as 'external/SDL'206dcdedfSquashed 'external/SDL/' content from commit 4d17b99d0a4d16e1cb4need to update sdl848b19920Fix compilation errordb61b5299Merge commit 'e94a94559f28e49678fbcf72199a5258137b0fe9' as 'external/imgui'e94a94559Squashed 'external/imgui/' content from commit 02e9b8cac52edb3757need to update imguic1a705e86Emulate weird JALR behaviour4b4c32f4bFix exception for "unusable COP1" in 4 instructions i missed accidentally (again)df5828142Bug putting 0s in the log everywheref8b580048Make isviewer a sink to file8241e9735Fix exception for "unusable COP1" in 4 instructions i missed accidentallyb29715f20small changesd9a620bc1make use of my new small utility library0d1aa938eAdd 'external/ircolib/' from commit 'ce3cd726c8df8388d554abf8bb55d55020eb4450'e64eb40b3Fuck git git-subtree-dir: external/ircolib git-subtree-split:de6e324bde
988 lines
38 KiB
C
988 lines
38 KiB
C
/*
|
|
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely.
|
|
*/
|
|
#include <SDL3/SDL.h>
|
|
#include <SDL3/SDL_main.h>
|
|
#include <SDL3/SDL_test.h>
|
|
#include "testyuv_cvt.h"
|
|
#include "testutils.h"
|
|
|
|
/* 422 (YUY2, etc) and P010 formats are the largest */
|
|
#define MAX_YUV_SURFACE_SIZE(W, H, P) ((H + 1) * ((W + 1) + P) * 4)
|
|
|
|
/* Return true if the YUV format is packed pixels */
|
|
static bool is_packed_yuv_format(Uint32 format)
|
|
{
|
|
return format == SDL_PIXELFORMAT_YUY2 || format == SDL_PIXELFORMAT_UYVY || format == SDL_PIXELFORMAT_YVYU;
|
|
}
|
|
|
|
/* Create a surface with a good pattern for verifying YUV conversion */
|
|
static SDL_Surface *generate_test_pattern(int pattern_size)
|
|
{
|
|
SDL_Surface *pattern = SDL_CreateSurface(pattern_size, pattern_size, SDL_PIXELFORMAT_RGB24);
|
|
|
|
if (pattern) {
|
|
int i, x, y;
|
|
Uint8 *p, c;
|
|
const int thickness = 2; /* Important so 2x2 blocks of color are the same, to avoid Cr/Cb interpolation over pixels */
|
|
|
|
/* R, G, B in alternating horizontal bands */
|
|
for (y = 0; y < pattern->h - (thickness - 1); y += thickness) {
|
|
for (i = 0; i < thickness; ++i) {
|
|
p = (Uint8 *)pattern->pixels + (y + i) * pattern->pitch + ((y / thickness) % 3);
|
|
for (x = 0; x < pattern->w; ++x) {
|
|
*p = 0xFF;
|
|
p += 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Black and white in alternating vertical bands */
|
|
c = 0xFF;
|
|
for (x = 1 * thickness; x < pattern->w; x += 2 * thickness) {
|
|
for (i = 0; i < thickness; ++i) {
|
|
p = (Uint8 *)pattern->pixels + (x + i) * 3;
|
|
for (y = 0; y < pattern->h; ++y) {
|
|
SDL_memset(p, c, 3);
|
|
p += pattern->pitch;
|
|
}
|
|
}
|
|
if (c) {
|
|
c = 0x00;
|
|
} else {
|
|
c = 0xFF;
|
|
}
|
|
}
|
|
}
|
|
return pattern;
|
|
}
|
|
|
|
static bool verify_yuv_data(Uint32 format, SDL_Colorspace colorspace, const Uint8 *yuv, int yuv_pitch, SDL_Surface *surface, int tolerance)
|
|
{
|
|
const int size = (surface->h * surface->pitch);
|
|
Uint8 *rgb;
|
|
bool result = false;
|
|
|
|
rgb = (Uint8 *)SDL_malloc(size);
|
|
if (!rgb) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory");
|
|
return false;
|
|
}
|
|
|
|
if (SDL_ConvertPixelsAndColorspace(surface->w, surface->h, format, colorspace, 0, yuv, yuv_pitch, surface->format, SDL_COLORSPACE_SRGB, 0, rgb, surface->pitch)) {
|
|
int x, y;
|
|
result = true;
|
|
for (y = 0; y < surface->h; ++y) {
|
|
const Uint8 *actual = rgb + y * surface->pitch;
|
|
const Uint8 *expected = (const Uint8 *)surface->pixels + y * surface->pitch;
|
|
for (x = 0; x < surface->w; ++x) {
|
|
int deltaR = (int)actual[0] - expected[0];
|
|
int deltaG = (int)actual[1] - expected[1];
|
|
int deltaB = (int)actual[2] - expected[2];
|
|
int distance = (deltaR * deltaR + deltaG * deltaG + deltaB * deltaB);
|
|
if (distance > tolerance) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Pixel at %d,%d was 0x%.2x,0x%.2x,0x%.2x, expected 0x%.2x,0x%.2x,0x%.2x, distance = %d", x, y, actual[0], actual[1], actual[2], expected[0], expected[1], expected[2], distance);
|
|
result = false;
|
|
}
|
|
actual += 3;
|
|
expected += 3;
|
|
}
|
|
}
|
|
} else {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(format), SDL_GetPixelFormatName(surface->format), SDL_GetError());
|
|
}
|
|
SDL_free(rgb);
|
|
|
|
return result;
|
|
}
|
|
|
|
static bool run_automated_tests(int pattern_size, int extra_pitch)
|
|
{
|
|
const Uint32 formats[] = {
|
|
SDL_PIXELFORMAT_YV12,
|
|
SDL_PIXELFORMAT_IYUV,
|
|
SDL_PIXELFORMAT_NV12,
|
|
SDL_PIXELFORMAT_NV21,
|
|
SDL_PIXELFORMAT_YUY2,
|
|
SDL_PIXELFORMAT_UYVY,
|
|
SDL_PIXELFORMAT_YVYU
|
|
};
|
|
int i, j;
|
|
SDL_Surface *pattern = generate_test_pattern(pattern_size);
|
|
const int yuv_len = MAX_YUV_SURFACE_SIZE(pattern->w, pattern->h, extra_pitch);
|
|
Uint8 *yuv1 = (Uint8 *)SDL_malloc(yuv_len);
|
|
Uint8 *yuv2 = (Uint8 *)SDL_malloc(yuv_len);
|
|
int yuv1_pitch, yuv2_pitch;
|
|
YUV_CONVERSION_MODE mode;
|
|
SDL_Colorspace colorspace;
|
|
const int tight_tolerance = 20;
|
|
const int loose_tolerance = 333;
|
|
bool result = false;
|
|
|
|
if (!pattern || !yuv1 || !yuv2) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate test surfaces");
|
|
goto done;
|
|
}
|
|
|
|
mode = GetYUVConversionModeForResolution(pattern->w, pattern->h);
|
|
colorspace = GetColorspaceForYUVConversionMode(mode);
|
|
|
|
/* Verify conversion from YUV formats */
|
|
for (i = 0; i < SDL_arraysize(formats); ++i) {
|
|
if (!ConvertRGBtoYUV(formats[i], pattern->pixels, pattern->pitch, yuv1, pattern->w, pattern->h, mode, 0, 100)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ConvertRGBtoYUV() doesn't support converting to %s", SDL_GetPixelFormatName(formats[i]));
|
|
goto done;
|
|
}
|
|
yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w);
|
|
if (!verify_yuv_data(formats[i], colorspace, yuv1, yuv1_pitch, pattern, tight_tolerance)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to RGB", SDL_GetPixelFormatName(formats[i]));
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* Verify conversion to YUV formats */
|
|
for (i = 0; i < SDL_arraysize(formats); ++i) {
|
|
yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w) + extra_pitch;
|
|
if (!SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, pattern->format, SDL_COLORSPACE_SRGB, 0, pattern->pixels, pattern->pitch, formats[i], colorspace, 0, yuv1, yuv1_pitch)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(pattern->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError());
|
|
goto done;
|
|
}
|
|
if (!verify_yuv_data(formats[i], colorspace, yuv1, yuv1_pitch, pattern, tight_tolerance)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from RGB to %s", SDL_GetPixelFormatName(formats[i]));
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* Verify conversion between YUV formats */
|
|
for (i = 0; i < SDL_arraysize(formats); ++i) {
|
|
for (j = 0; j < SDL_arraysize(formats); ++j) {
|
|
yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w) + extra_pitch;
|
|
yuv2_pitch = CalculateYUVPitch(formats[j], pattern->w) + extra_pitch;
|
|
if (!SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, pattern->format, SDL_COLORSPACE_SRGB, 0, pattern->pixels, pattern->pitch, formats[i], colorspace, 0, yuv1, yuv1_pitch)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(pattern->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError());
|
|
goto done;
|
|
}
|
|
if (!SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, formats[i], colorspace, 0, yuv1, yuv1_pitch, formats[j], colorspace, 0, yuv2, yuv2_pitch)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]), SDL_GetError());
|
|
goto done;
|
|
}
|
|
if (!verify_yuv_data(formats[j], colorspace, yuv2, yuv2_pitch, pattern, tight_tolerance)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to %s", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]));
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Verify conversion between YUV formats in-place */
|
|
for (i = 0; i < SDL_arraysize(formats); ++i) {
|
|
for (j = 0; j < SDL_arraysize(formats); ++j) {
|
|
if (is_packed_yuv_format(formats[i]) != is_packed_yuv_format(formats[j])) {
|
|
/* Can't change plane vs packed pixel layout in-place */
|
|
continue;
|
|
}
|
|
|
|
yuv1_pitch = CalculateYUVPitch(formats[i], pattern->w) + extra_pitch;
|
|
yuv2_pitch = CalculateYUVPitch(formats[j], pattern->w) + extra_pitch;
|
|
if (!SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, pattern->format, SDL_COLORSPACE_SRGB, 0, pattern->pixels, pattern->pitch, formats[i], colorspace, 0, yuv1, yuv1_pitch)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(pattern->format), SDL_GetPixelFormatName(formats[i]), SDL_GetError());
|
|
goto done;
|
|
}
|
|
if (!SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, formats[i], colorspace, 0, yuv1, yuv1_pitch, formats[j], colorspace, 0, yuv1, yuv2_pitch)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]), SDL_GetError());
|
|
goto done;
|
|
}
|
|
if (!verify_yuv_data(formats[j], colorspace, yuv1, yuv2_pitch, pattern, tight_tolerance)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to %s", SDL_GetPixelFormatName(formats[i]), SDL_GetPixelFormatName(formats[j]));
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Verify round trip through BT.2020 */
|
|
colorspace = SDL_COLORSPACE_BT2020_FULL;
|
|
if (!ConvertRGBtoYUV(SDL_PIXELFORMAT_P010, pattern->pixels, pattern->pitch, yuv1, pattern->w, pattern->h, YUV_CONVERSION_BT2020, 0, 100)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ConvertRGBtoYUV() doesn't support converting to %s", SDL_GetPixelFormatName(SDL_PIXELFORMAT_P010));
|
|
goto done;
|
|
}
|
|
yuv1_pitch = CalculateYUVPitch(SDL_PIXELFORMAT_P010, pattern->w);
|
|
if (!verify_yuv_data(SDL_PIXELFORMAT_P010, colorspace, yuv1, yuv1_pitch, pattern, tight_tolerance)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from %s to RGB", SDL_GetPixelFormatName(SDL_PIXELFORMAT_P010));
|
|
goto done;
|
|
}
|
|
|
|
/* The pitch needs to be Uint16 aligned for P010 pixels */
|
|
yuv1_pitch = CalculateYUVPitch(SDL_PIXELFORMAT_P010, pattern->w) + ((extra_pitch + 1) & ~1);
|
|
if (!SDL_ConvertPixelsAndColorspace(pattern->w, pattern->h, pattern->format, SDL_COLORSPACE_SRGB, 0, pattern->pixels, pattern->pitch, SDL_PIXELFORMAT_P010, colorspace, 0, yuv1, yuv1_pitch)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't convert %s to %s: %s", SDL_GetPixelFormatName(pattern->format), SDL_GetPixelFormatName(SDL_PIXELFORMAT_P010), SDL_GetError());
|
|
goto done;
|
|
}
|
|
/* Going through XRGB2101010 format during P010 conversion is slightly lossy, so use looser tolerance here */
|
|
if (!verify_yuv_data(SDL_PIXELFORMAT_P010, colorspace, yuv1, yuv1_pitch, pattern, loose_tolerance)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed conversion from RGB to %s", SDL_GetPixelFormatName(SDL_PIXELFORMAT_P010));
|
|
goto done;
|
|
}
|
|
|
|
result = true;
|
|
|
|
done:
|
|
SDL_free(yuv1);
|
|
SDL_free(yuv2);
|
|
SDL_DestroySurface(pattern);
|
|
return result;
|
|
}
|
|
|
|
static bool run_colorspace_test(void)
|
|
{
|
|
bool result = false;
|
|
SDL_Window *window;
|
|
SDL_Renderer *renderer;
|
|
struct {
|
|
const char *name;
|
|
SDL_Colorspace colorspace;
|
|
} colorspaces[] = {
|
|
#define COLORSPACE(X) { #X, X }
|
|
COLORSPACE(SDL_COLORSPACE_JPEG),
|
|
#if 0 /* We don't support converting color primaries here */
|
|
COLORSPACE(SDL_COLORSPACE_BT601_LIMITED),
|
|
COLORSPACE(SDL_COLORSPACE_BT601_FULL),
|
|
#endif
|
|
COLORSPACE(SDL_COLORSPACE_BT709_LIMITED),
|
|
COLORSPACE(SDL_COLORSPACE_BT709_FULL)
|
|
#undef COLORSPACE
|
|
};
|
|
SDL_Surface *rgb = NULL;
|
|
SDL_Surface *yuv = NULL;
|
|
SDL_Texture *texture = NULL;
|
|
int allowed_error = 2;
|
|
int i;
|
|
|
|
if (!SDL_CreateWindowAndRenderer("testyuv", 320, 240, 0, &window, &renderer)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window and renderer: %s", SDL_GetError());
|
|
goto done;
|
|
}
|
|
|
|
rgb = SDL_CreateSurface(32, 32, SDL_PIXELFORMAT_XRGB8888);
|
|
if (!rgb) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create RGB surface: %s", SDL_GetError());
|
|
goto done;
|
|
}
|
|
SDL_FillSurfaceRect(rgb, NULL, SDL_MapSurfaceRGB(rgb, 255, 0, 0));
|
|
|
|
for (i = 0; i < SDL_arraysize(colorspaces); ++i) {
|
|
bool next = false;
|
|
Uint8 r, g, b, a;
|
|
|
|
SDL_Log("Checking colorspace %s", colorspaces[i].name);
|
|
|
|
yuv = SDL_ConvertSurfaceAndColorspace(rgb, SDL_PIXELFORMAT_NV12, NULL, colorspaces[i].colorspace, 0);
|
|
if (!yuv) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create YUV surface: %s", SDL_GetError());
|
|
goto done;
|
|
}
|
|
|
|
if (!SDL_ReadSurfacePixel(yuv, 0, 0, &r, &g, &b, &a)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't read YUV surface: %s", SDL_GetError());
|
|
goto done;
|
|
}
|
|
|
|
if (SDL_abs((int)r - 255) > allowed_error ||
|
|
SDL_abs((int)g - 0) > allowed_error ||
|
|
SDL_abs((int)b - 0) > allowed_error) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed color conversion, expected 255,0,0, got %d,%d,%d", r, g, b);
|
|
}
|
|
|
|
texture = SDL_CreateTextureFromSurface(renderer, yuv);
|
|
if (!texture) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create YUV texture: %s", SDL_GetError());
|
|
goto done;
|
|
}
|
|
|
|
SDL_DestroySurface(yuv);
|
|
yuv = NULL;
|
|
|
|
SDL_RenderTexture(renderer, texture, NULL, NULL);
|
|
yuv = SDL_RenderReadPixels(renderer, NULL);
|
|
|
|
if (!SDL_ReadSurfacePixel(yuv, 0, 0, &r, &g, &b, &a)) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't read YUV surface: %s", SDL_GetError());
|
|
goto done;
|
|
}
|
|
|
|
if (SDL_abs((int)r - 255) > allowed_error ||
|
|
SDL_abs((int)g - 0) > allowed_error ||
|
|
SDL_abs((int)b - 0) > allowed_error) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed renderer color conversion, expected 255,0,0, got %d,%d,%d", r, g, b);
|
|
}
|
|
|
|
while (!next) {
|
|
SDL_Event event;
|
|
while (SDL_PollEvent(&event)) {
|
|
switch (event.type) {
|
|
case SDL_EVENT_KEY_DOWN:
|
|
if (event.key.key == SDLK_ESCAPE) {
|
|
result = true;
|
|
goto done;
|
|
}
|
|
if (event.key.key == SDLK_SPACE) {
|
|
next = true;
|
|
}
|
|
break;
|
|
case SDL_EVENT_QUIT:
|
|
result = true;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
SDL_RenderTexture(renderer, texture, NULL, NULL);
|
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
|
SDL_RenderDebugText(renderer, 4, 4, colorspaces[i].name);
|
|
SDL_RenderPresent(renderer);
|
|
SDL_Delay(10);
|
|
}
|
|
|
|
SDL_DestroyTexture(texture);
|
|
texture = NULL;
|
|
}
|
|
|
|
result = true;
|
|
|
|
done:
|
|
SDL_DestroySurface(rgb);
|
|
SDL_DestroySurface(yuv);
|
|
SDL_DestroyTexture(texture);
|
|
SDL_Quit();
|
|
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])
|
|
{
|
|
SDL_Colorspace rgb_colorspace = SDL_COLORSPACE_SRGB;
|
|
SDL_Colorspace yuv_colorspace;
|
|
Uint8 *raw_yuv = NULL;
|
|
int pitch;
|
|
SDL_Surface *converted = NULL;
|
|
bool result = false;
|
|
|
|
YUV_CONVERSION_MODE yuv_mode = GetYUVConversionModeForResolution(original->w, original->h);
|
|
if (yuv_mode == YUV_CONVERSION_BT2020) {
|
|
yuv_format = SDL_PIXELFORMAT_P010;
|
|
rgb_format = SDL_PIXELFORMAT_XBGR2101010;
|
|
rgb_colorspace = SDL_COLORSPACE_HDR10;
|
|
}
|
|
yuv_colorspace = GetColorspaceForYUVConversionMode(yuv_mode);
|
|
|
|
raw_yuv = SDL_calloc(1, MAX_YUV_SURFACE_SIZE(original->w, original->h, 0));
|
|
ConvertRGBtoYUV(yuv_format, original->pixels, original->pitch, raw_yuv, original->w, original->h, yuv_mode, monochrome, luminance);
|
|
pitch = CalculateYUVPitch(yuv_format, original->w);
|
|
|
|
converted = SDL_CreateSurface(original->w, original->h, rgb_format);
|
|
if (!converted) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create converted surface: %s", SDL_GetError());
|
|
goto done;
|
|
}
|
|
SDL_ConvertPixelsAndColorspace(original->w, original->h, yuv_format, yuv_colorspace, 0, raw_yuv, pitch, rgb_format, rgb_colorspace, 0, converted->pixels, converted->pitch);
|
|
|
|
output[0] = SDL_CreateTextureFromSurface(renderer, original);
|
|
output[1] = SDL_CreateTextureFromSurface(renderer, converted);
|
|
SDL_PropertiesID props = SDL_CreateProperties();
|
|
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, yuv_colorspace);
|
|
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, yuv_format);
|
|
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STREAMING);
|
|
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, original->w);
|
|
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, original->h);
|
|
output[2] = SDL_CreateTextureWithProperties(renderer, props);
|
|
SDL_DestroyProperties(props);
|
|
if (!output[0] || !output[1] || !output[2]) {
|
|
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)) {
|
|
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 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);
|
|
Uint8 *plane0 = (Uint8 *)SDL_calloc(1, Yrows * Ypitch);
|
|
Uint8 *plane1 = (Uint8 *)SDL_calloc(1, UVrows * UVpitch);
|
|
Uint8 *plane2 = (Uint8 *)SDL_calloc(1, UVrows * UVpitch);
|
|
int row;
|
|
const Uint8 *src;
|
|
Uint8 *dst;
|
|
|
|
if (!plane0 || !plane1 || !plane0) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create YUV planes: %s", SDL_GetError());
|
|
goto done;
|
|
}
|
|
|
|
src = src_plane0;
|
|
dst = plane0;
|
|
for (row = 0; row < Yrows; ++row) {
|
|
SDL_memcpy(dst, src, src_Ypitch);
|
|
src += src_Ypitch;
|
|
dst += Ypitch;
|
|
}
|
|
|
|
src = src_plane1;
|
|
dst = plane1;
|
|
for (row = 0; row < UVrows; ++row) {
|
|
SDL_memcpy(dst, src, src_UVpitch);
|
|
src += src_UVpitch;
|
|
dst += UVpitch;
|
|
}
|
|
|
|
src = src_plane2;
|
|
dst = plane2;
|
|
for (row = 0; row < UVrows; ++row) {
|
|
SDL_memcpy(dst, src, src_UVpitch);
|
|
src += src_UVpitch;
|
|
dst += UVpitch;
|
|
}
|
|
|
|
if (yuv_format == SDL_PIXELFORMAT_YV12) {
|
|
SDL_UpdateYUVTexture(output[2], NULL, plane0, Ypitch, plane2, UVpitch, plane1, UVpitch);
|
|
} else {
|
|
SDL_UpdateYUVTexture(output[2], NULL, plane0, Ypitch, plane1, UVpitch, plane2, UVpitch);
|
|
}
|
|
SDL_free(plane0);
|
|
SDL_free(plane1);
|
|
SDL_free(plane2);
|
|
} else if (planar && (yuv_format == SDL_PIXELFORMAT_NV12 || yuv_format == SDL_PIXELFORMAT_NV21 || yuv_format == SDL_PIXELFORMAT_P010)) {
|
|
const int Yrows = original->h;
|
|
const int UVrows = ((original->h + 1) / 2);
|
|
const int src_Ypitch = pitch;
|
|
const int src_UVpitch = (yuv_format == SDL_PIXELFORMAT_P010) ? ((pitch + 3) & ~3) : ((pitch + 1) & ~1);
|
|
const Uint8 *src_plane0 = (const Uint8 *)raw_yuv;
|
|
const Uint8 *src_plane1 = src_plane0 + Yrows * src_Ypitch;
|
|
const int Ypitch = pitch + 37;
|
|
const int UVpitch = ((Ypitch + 1) / 2) * 2;
|
|
Uint8 *plane0 = (Uint8 *)SDL_calloc(1, Yrows * Ypitch);
|
|
Uint8 *plane1 = (Uint8 *)SDL_calloc(1, UVrows * UVpitch);
|
|
int row;
|
|
const Uint8 *src;
|
|
Uint8 *dst;
|
|
|
|
if (!plane0 || !plane1) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create YUV planes: %s", SDL_GetError());
|
|
goto done;
|
|
}
|
|
|
|
src = src_plane0;
|
|
dst = plane0;
|
|
for (row = 0; row < Yrows; ++row) {
|
|
SDL_memcpy(dst, src, src_Ypitch);
|
|
src += src_Ypitch;
|
|
dst += Ypitch;
|
|
}
|
|
|
|
src = src_plane1;
|
|
dst = plane1;
|
|
for (row = 0; row < UVrows; ++row) {
|
|
SDL_memcpy(dst, src, src_UVpitch);
|
|
src += src_UVpitch;
|
|
dst += UVpitch;
|
|
}
|
|
|
|
SDL_UpdateNVTexture(output[2], NULL, plane0, Ypitch, plane1, UVpitch);
|
|
SDL_free(plane0);
|
|
SDL_free(plane1);
|
|
} else {
|
|
SDL_UpdateTexture(output[2], NULL, raw_yuv, pitch);
|
|
}
|
|
|
|
result = true;
|
|
|
|
done:
|
|
SDL_DestroySurface(converted);
|
|
SDL_free(raw_yuv);
|
|
return result;
|
|
}
|
|
|
|
static bool has_10bit_texture_format(SDL_Renderer *renderer)
|
|
{
|
|
const SDL_PixelFormat *texture_formats = (const SDL_PixelFormat *)SDL_GetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_TEXTURE_FORMATS_POINTER, NULL);
|
|
if (texture_formats) {
|
|
for (int i = 0; texture_formats[i] != SDL_PIXELFORMAT_UNKNOWN; ++i) {
|
|
if (SDL_ISPIXELFORMAT_10BIT(texture_formats[i])) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool check_output(SDL_Renderer *renderer, SDL_Surface *original, SDL_Texture *texture)
|
|
{
|
|
// Clear to yellow to clearly see unfilled pixels
|
|
SDL_SetRenderDrawColor(renderer, 255, 255, 0, SDL_ALPHA_OPAQUE);
|
|
SDL_RenderClear(renderer);
|
|
|
|
SDL_Rect rect = { 0, 0, texture->w, texture->h };
|
|
SDL_FRect frect = { 0.0f, 0.0f, (float)texture->w, (float)texture->h };
|
|
SDL_RenderTexture(renderer, texture, &frect, &frect);
|
|
SDL_Surface *output = SDL_RenderReadPixels(renderer, &rect);
|
|
if (!output) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't read pixels: %s", SDL_GetError());
|
|
return false;
|
|
}
|
|
SDL_RenderPresent(renderer);
|
|
|
|
// Allow some error for colorspace conversion and differences in color depth
|
|
const int MAX_ALLOWABLE_ERROR = 4096;
|
|
bool result;
|
|
if (SDLTest_CompareSurfaces(output, original, MAX_ALLOWABLE_ERROR) == 0) {
|
|
result = true;
|
|
} else {
|
|
result = false;
|
|
}
|
|
SDL_DestroySurface(output);
|
|
|
|
return result;
|
|
}
|
|
|
|
static bool run_single_format_test(SDL_Renderer *renderer, SDL_Surface *original, SDL_PixelFormat yuv_format, SDL_PixelFormat rgb_format, bool planar)
|
|
{
|
|
SDL_Texture *output[3];
|
|
bool result = true;
|
|
|
|
if (!create_textures(renderer, original, yuv_format, rgb_format, planar, false, 100, output)) {
|
|
return false;
|
|
}
|
|
|
|
if (!check_output(renderer, original, output[0])) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Original texture didn't match source data, failing");
|
|
result = false;
|
|
}
|
|
|
|
if (!check_output(renderer, original, output[1])) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "RGB output didn't match source data, failing");
|
|
result = false;
|
|
}
|
|
|
|
if (!check_output(renderer, original, output[2])) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "YUV output didn't match source data, failing");
|
|
result = false;
|
|
}
|
|
|
|
for (int i = 0; i < SDL_arraysize(output); ++i) {
|
|
SDL_DestroyTexture(output[i]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static bool run_all_format_test(SDL_Window *window, const char *requested_renderer, SDL_Surface *original)
|
|
{
|
|
const SDL_PixelFormat yuv_formats[] = {
|
|
SDL_PIXELFORMAT_YV12,
|
|
SDL_PIXELFORMAT_IYUV,
|
|
SDL_PIXELFORMAT_YUY2,
|
|
SDL_PIXELFORMAT_UYVY,
|
|
SDL_PIXELFORMAT_YVYU,
|
|
SDL_PIXELFORMAT_NV12,
|
|
SDL_PIXELFORMAT_NV21
|
|
};
|
|
const SDL_PixelFormat rgb_formats[] = {
|
|
SDL_PIXELFORMAT_XRGB1555,
|
|
SDL_PIXELFORMAT_RGB565,
|
|
SDL_PIXELFORMAT_RGB24,
|
|
SDL_PIXELFORMAT_ABGR8888,
|
|
SDL_PIXELFORMAT_RGBA8888,
|
|
SDL_PIXELFORMAT_BGRA8888
|
|
};
|
|
const struct
|
|
{
|
|
YUV_CONVERSION_MODE mode;
|
|
const char *name;
|
|
} colorspaces[] = {
|
|
{ YUV_CONVERSION_JPEG, "JPEG" },
|
|
{ YUV_CONVERSION_BT601, "BT601" },
|
|
{ YUV_CONVERSION_BT709, "BT709" },
|
|
{ YUV_CONVERSION_BT2020, "BT2020" }
|
|
};
|
|
bool quit = false;
|
|
bool result = true;
|
|
|
|
for (int i = 0; i < SDL_GetNumRenderDrivers() && !quit; ++i) {
|
|
const char *renderer_name = SDL_GetRenderDriver(i);
|
|
if (requested_renderer && SDL_strcmp(renderer_name, requested_renderer) != 0) {
|
|
continue;
|
|
}
|
|
|
|
SDL_Renderer *renderer = SDL_CreateRenderer(window, renderer_name);
|
|
if (!renderer) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create %s renderer: %s", renderer_name, SDL_GetError());
|
|
result = false;
|
|
continue;
|
|
}
|
|
|
|
for (int j = 0; j < SDL_arraysize(colorspaces) && !quit; ++j) {
|
|
if (colorspaces[j].mode == YUV_CONVERSION_BT2020 &&
|
|
!has_10bit_texture_format(renderer)) {
|
|
SDL_Log("Skipping %s %s, unsupported", renderer_name, colorspaces[j].name);
|
|
continue;
|
|
}
|
|
SetYUVConversionMode(colorspaces[j].mode);
|
|
|
|
for (int m = 0; m < SDL_arraysize(yuv_formats) && !quit; ++m) {
|
|
SDL_PixelFormat yuv_format = yuv_formats[m];
|
|
for (int n = 0; n < SDL_arraysize(rgb_formats) && !quit; ++n) {
|
|
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);
|
|
|
|
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);
|
|
|
|
SDL_Event event;
|
|
while (SDL_PollEvent(&event)) {
|
|
if (event.type == SDL_EVENT_QUIT ||
|
|
(event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_ESCAPE)) {
|
|
quit = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
SDL_DestroyRenderer(renderer);
|
|
}
|
|
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)
|
|
{
|
|
const char *titles[3] = { "ORIGINAL", "SOFTWARE", "HARDWARE" };
|
|
char title[128];
|
|
const char *yuv_mode_name;
|
|
YUV_CONVERSION_MODE yuv_mode;
|
|
const char *yuv_format_name;
|
|
int current = 0;
|
|
bool quit = false;
|
|
bool result = false;
|
|
|
|
SDL_Renderer *renderer = SDL_CreateRenderer(window, renderer_name);
|
|
if (!renderer) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s", SDL_GetError());
|
|
return false;
|
|
}
|
|
|
|
SDL_Texture *output[3];
|
|
if (!create_textures(renderer, original, yuv_format, rgb_format, planar, monochrome, luminance, output)) {
|
|
goto done;
|
|
}
|
|
|
|
yuv_mode = GetYUVConversionModeForResolution(original->w, original->h);
|
|
switch (yuv_mode) {
|
|
case YUV_CONVERSION_JPEG:
|
|
yuv_mode_name = "JPEG";
|
|
break;
|
|
case YUV_CONVERSION_BT601:
|
|
yuv_mode_name = "BT.601";
|
|
break;
|
|
case YUV_CONVERSION_BT709:
|
|
yuv_mode_name = "BT.709";
|
|
break;
|
|
case YUV_CONVERSION_BT2020:
|
|
yuv_mode_name = "BT.2020";
|
|
yuv_format = SDL_PIXELFORMAT_P010;
|
|
break;
|
|
default:
|
|
yuv_mode_name = "UNKNOWN";
|
|
break;
|
|
}
|
|
|
|
yuv_format_name = SDL_GetPixelFormatName(yuv_format);
|
|
if (SDL_strncmp(yuv_format_name, "SDL_PIXELFORMAT_", 16) == 0) {
|
|
yuv_format_name += 16;
|
|
}
|
|
|
|
while (!quit) {
|
|
SDL_Event event;
|
|
while (SDL_PollEvent(&event) > 0) {
|
|
if (event.type == SDL_EVENT_QUIT) {
|
|
quit = true;
|
|
}
|
|
if (event.type == SDL_EVENT_KEY_DOWN) {
|
|
if (event.key.key == SDLK_ESCAPE) {
|
|
quit = true;
|
|
} else if (event.key.key == SDLK_LEFT) {
|
|
--current;
|
|
} else if (event.key.key == SDLK_RIGHT) {
|
|
++current;
|
|
}
|
|
}
|
|
if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
|
|
if (event.button.x < (original->w / 2)) {
|
|
--current;
|
|
} else {
|
|
++current;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Handle wrapping */
|
|
if (current < 0) {
|
|
current += SDL_arraysize(output);
|
|
}
|
|
if (current >= SDL_arraysize(output)) {
|
|
current -= SDL_arraysize(output);
|
|
}
|
|
|
|
SDL_RenderClear(renderer);
|
|
SDL_RenderTexture(renderer, output[current], NULL, NULL);
|
|
SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
|
|
if (current == 0) {
|
|
SDLTest_DrawString(renderer, 4, 4, titles[current]);
|
|
} else {
|
|
if (SDL_snprintf(title, sizeof(title), "%s %s %s", titles[current], yuv_format_name, yuv_mode_name) > 0) {
|
|
SDLTest_DrawString(renderer, 4, 4, title);
|
|
}
|
|
}
|
|
SDL_RenderPresent(renderer);
|
|
SDL_Delay(10);
|
|
}
|
|
|
|
result = true;
|
|
|
|
done:
|
|
for (int i = 0; i < SDL_arraysize(output); ++i) {
|
|
SDL_DestroyTexture(output[i]);
|
|
}
|
|
SDLTest_CleanupTextDrawing();
|
|
SDL_DestroyRenderer(renderer);
|
|
return result;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
struct
|
|
{
|
|
bool enable_intrinsics;
|
|
int pattern_size;
|
|
int extra_pitch;
|
|
} automated_test_params[] = {
|
|
/* Test: single pixel */
|
|
{ false, 1, 0 },
|
|
/* Test: even width and height */
|
|
{ false, 2, 0 },
|
|
{ false, 4, 0 },
|
|
/* Test: odd width and height */
|
|
{ false, 1, 0 },
|
|
{ false, 3, 0 },
|
|
/* Test: even width and height, extra pitch */
|
|
{ false, 2, 3 },
|
|
{ false, 4, 3 },
|
|
/* Test: odd width and height, extra pitch */
|
|
{ false, 1, 3 },
|
|
{ false, 3, 3 },
|
|
/* Test: even width and height with intrinsics */
|
|
{ true, 32, 0 },
|
|
/* Test: odd width and height with intrinsics */
|
|
{ true, 33, 0 },
|
|
{ true, 37, 0 },
|
|
/* Test: even width and height with intrinsics, extra pitch */
|
|
{ true, 32, 3 },
|
|
/* Test: odd width and height with intrinsics, extra pitch */
|
|
{ true, 33, 3 },
|
|
{ true, 37, 3 },
|
|
};
|
|
char *filename = NULL;
|
|
SDL_Surface *original = NULL;
|
|
SDL_Surface *png = NULL;
|
|
SDL_Window *window = NULL;
|
|
const char *renderer_name = NULL;
|
|
Uint32 yuv_format = SDL_PIXELFORMAT_YV12;
|
|
Uint32 rgb_format = SDL_PIXELFORMAT_RGBX8888;
|
|
bool planar = false;
|
|
bool monochrome = false;
|
|
int luminance = 100;
|
|
int i;
|
|
bool should_run_automated_tests = false;
|
|
bool should_run_colorspace_test = false;
|
|
bool should_test_all_formats = false;
|
|
SDLTest_CommonState *state;
|
|
int result = 0;
|
|
|
|
/* Initialize test framework */
|
|
state = SDLTest_CommonCreateState(argv, 0);
|
|
if (!state) {
|
|
return 1;
|
|
}
|
|
|
|
/* Parse command line */
|
|
for (i = 1; i < argc;) {
|
|
int consumed;
|
|
|
|
consumed = SDLTest_CommonArg(state, i);
|
|
if (!consumed) {
|
|
if (SDL_strcmp(argv[i], "--all") == 0) {
|
|
should_test_all_formats = true;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--jpeg") == 0) {
|
|
SetYUVConversionMode(YUV_CONVERSION_JPEG);
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--bt601") == 0) {
|
|
SetYUVConversionMode(YUV_CONVERSION_BT601);
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--bt709") == 0) {
|
|
SetYUVConversionMode(YUV_CONVERSION_BT709);
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--bt2020") == 0) {
|
|
SetYUVConversionMode(YUV_CONVERSION_BT2020);
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--auto") == 0) {
|
|
SetYUVConversionMode(YUV_CONVERSION_AUTOMATIC);
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--yv12") == 0) {
|
|
yuv_format = SDL_PIXELFORMAT_YV12;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--iyuv") == 0) {
|
|
yuv_format = SDL_PIXELFORMAT_IYUV;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--yuy2") == 0) {
|
|
yuv_format = SDL_PIXELFORMAT_YUY2;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--uyvy") == 0) {
|
|
yuv_format = SDL_PIXELFORMAT_UYVY;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--yvyu") == 0) {
|
|
yuv_format = SDL_PIXELFORMAT_YVYU;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--nv12") == 0) {
|
|
yuv_format = SDL_PIXELFORMAT_NV12;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--nv21") == 0) {
|
|
yuv_format = SDL_PIXELFORMAT_NV21;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--rgb555") == 0) {
|
|
rgb_format = SDL_PIXELFORMAT_XRGB1555;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--rgb565") == 0) {
|
|
rgb_format = SDL_PIXELFORMAT_RGB565;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--rgb24") == 0) {
|
|
rgb_format = SDL_PIXELFORMAT_RGB24;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--argb") == 0) {
|
|
rgb_format = SDL_PIXELFORMAT_ARGB8888;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--abgr") == 0) {
|
|
rgb_format = SDL_PIXELFORMAT_ABGR8888;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--rgba") == 0) {
|
|
rgb_format = SDL_PIXELFORMAT_RGBA8888;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--bgra") == 0) {
|
|
rgb_format = SDL_PIXELFORMAT_BGRA8888;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--planar") == 0) {
|
|
planar = true;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--monochrome") == 0) {
|
|
monochrome = true;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--luminance") == 0 && argv[i+1]) {
|
|
luminance = SDL_atoi(argv[i+1]);
|
|
consumed = 2;
|
|
} else if (SDL_strcmp(argv[i], "--automated") == 0) {
|
|
should_run_automated_tests = true;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--colorspace-test") == 0) {
|
|
should_run_colorspace_test = true;
|
|
consumed = 1;
|
|
} else if (SDL_strcmp(argv[i], "--renderer") == 0 && argv[i + 1]) {
|
|
renderer_name = argv[i + 1];
|
|
consumed = 2;
|
|
} else if (!filename) {
|
|
filename = argv[i];
|
|
consumed = 1;
|
|
}
|
|
}
|
|
if (consumed <= 0) {
|
|
static const char *options[] = {
|
|
"[--jpeg|--bt601|--bt709|--bt2020|--auto]",
|
|
"[--yv12|--iyuv|--yuy2|--uyvy|--yvyu|--nv12|--nv21]",
|
|
"[--rgb555|--rgb565|--rgb24|--argb|--abgr|--rgba|--bgra]",
|
|
"[--monochrome] [--luminance N%] [--planar]",
|
|
"[--automated] [--colorspace-test] [--renderer NAME]",
|
|
"[sample.png]",
|
|
NULL,
|
|
};
|
|
SDLTest_CommonLogUsage(state, argv[0], options);
|
|
SDL_Quit();
|
|
SDLTest_CommonDestroyState(state);
|
|
return 1;
|
|
}
|
|
i += consumed;
|
|
}
|
|
|
|
/* Run automated tests */
|
|
if (should_run_automated_tests) {
|
|
for (i = 0; i < (int)SDL_arraysize(automated_test_params); ++i) {
|
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Running automated test, pattern size %d, extra pitch %d, intrinsics %s",
|
|
automated_test_params[i].pattern_size,
|
|
automated_test_params[i].extra_pitch,
|
|
automated_test_params[i].enable_intrinsics ? "enabled" : "disabled");
|
|
if (!run_automated_tests(automated_test_params[i].pattern_size, automated_test_params[i].extra_pitch)) {
|
|
result = 2;
|
|
}
|
|
}
|
|
goto done;
|
|
}
|
|
|
|
if (should_run_colorspace_test) {
|
|
if (!run_colorspace_test()) {
|
|
result = 2;
|
|
}
|
|
goto done;
|
|
}
|
|
|
|
filename = GetResourceFilename(filename, "testyuv.png");
|
|
png = SDL_LoadSurface(filename);
|
|
if (png) {
|
|
original = SDL_ConvertSurface(png, SDL_PIXELFORMAT_RGB24);
|
|
SDL_DestroySurface(png);
|
|
}
|
|
if (!original) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", filename, SDL_GetError());
|
|
result = 3;
|
|
goto done;
|
|
}
|
|
|
|
window = SDL_CreateWindow("YUV test", original->w, original->h, 0);
|
|
if (!window) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s", SDL_GetError());
|
|
result = 4;
|
|
goto done;
|
|
}
|
|
|
|
if (should_test_all_formats) {
|
|
if (!run_all_format_test(window, renderer_name, original)) {
|
|
result = 5;
|
|
}
|
|
} else {
|
|
if (!run_interactive(window, renderer_name, original, yuv_format, rgb_format, planar, monochrome, luminance)) {
|
|
result = 5;
|
|
}
|
|
}
|
|
|
|
done:
|
|
SDL_free(filename);
|
|
SDL_DestroySurface(original);
|
|
SDL_DestroyWindow(window);
|
|
SDL_Quit();
|
|
SDLTest_CommonDestroyState(state);
|
|
return result;
|
|
}
|