testyuv: verify the YUV surface locking path

Also implemented YUV surface locking for Vulkan
This commit is contained in:
Sam Lantinga
2026-09-10 11:07:36 -07:00
parent 3df2b1a2a7
commit 0f5a7cbd2c
3 changed files with 338 additions and 24 deletions

View File

@@ -73,12 +73,13 @@ SDL_SW_YUVTexture *SDL_SW_CreateYUVTexture(SDL_PixelFormat format, SDL_Colorspac
}
// 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] = w * SDL_BYTESPERPIXEL(format);
swdata->pitches[1] = ((w + 1) / 2) * SDL_BYTESPERPIXEL(format);
swdata->pitches[0] = w * bpp;
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;
@@ -86,7 +87,7 @@ SDL_SW_YUVTexture *SDL_SW_CreateYUVTexture(SDL_PixelFormat format, SDL_Colorspac
break;
case SDL_PIXELFORMAT_I444:
case SDL_PIXELFORMAT_I4FL:
swdata->pitches[0] = w * SDL_BYTESPERPIXEL(format);
swdata->pitches[0] = w * bpp;
swdata->pitches[1] = swdata->pitches[0];
swdata->pitches[2] = swdata->pitches[1];
swdata->planes[0] = swdata->pixels;
@@ -127,6 +128,8 @@ bool SDL_SW_QueryYUVTexturePixels(SDL_SW_YUVTexture *swdata, void **pixels,
bool SDL_SW_UpdateYUVTexture(SDL_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:
@@ -134,17 +137,16 @@ bool SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect,
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) + 2 * ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2));
(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 bpp = SDL_BYTESPERPIXEL(swdata->format);
const int UVpitch = ((pitch / bpp + 1) / 2) * bpp;
// Copy the Y plane
src = (Uint8 *)pixels;
dst = swdata->pixels + rect->y * swdata->w + rect->x;
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);
@@ -154,8 +156,8 @@ bool SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect,
// 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;
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);
@@ -165,9 +167,8 @@ bool SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect,
// Copy the next plane
src = (Uint8 *)pixels + rect->h * pitch + ((rect->h + 1) / 2) * UVpitch;
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;
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);
@@ -185,12 +186,11 @@ 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;
dst += rect->y * swdata->pitches[0] + rect->x *bpp;
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);
@@ -403,7 +403,7 @@ bool SDL_SW_LockYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect,
}
break;
default:
return SDL_SetError("Unsupported YUV format");
break;
}
if (rect) {

View File

@@ -37,6 +37,7 @@
#include "../SDL_sysrender.h"
#include "../SDL_d3dmath.h"
#include "../../video/SDL_pixels_c.h"
#include "../../video/SDL_yuv_c.h"
#include "SDL_shaders_vulkan.h"
#define SET_ERROR_CODE(message, rc) \
@@ -267,6 +268,8 @@ typedef struct
// Pipeline layout with immutable sampler descriptor set layout
VkPipelineLayout pipelineLayoutYcbcr;
Uint8 *pixels;
int pitch;
} VULKAN_TextureData;
// Pipeline State Object data
@@ -2872,6 +2875,7 @@ static void VULKAN_DestroyTexture(SDL_Renderer *renderer,
}
}
SDL_free(textureData->pixels);
SDL_free(textureData);
texture->internal = NULL;
}
@@ -3105,6 +3109,28 @@ static bool VULKAN_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
return SDL_SetError("texture is already locked");
}
bool yuv = (textureData->descriptorSetLayoutYcbcr != VK_NULL_HANDLE);
if (yuv) {
// It's more efficient to upload directly...
if (!textureData->pixels) {
size_t size, calculated_pitch;
if (!SDL_CalculateYUVSize(texture->format, texture->w, texture->h, &size, &calculated_pitch)) {
return false;
}
textureData->pitch = (int)calculated_pitch;
textureData->pixels = (Uint8 *)SDL_malloc(size);
if (!textureData->pixels) {
return false;
}
}
textureData->lockedRect = *rect;
*pixels =
(void *)(textureData->pixels + rect->y * textureData->pitch +
rect->x * SDL_BYTESPERPIXEL(texture->format));
*pitch = textureData->pitch;
return true;
}
VkDeviceSize pixelSize = VULKAN_GetBytesPerPixel(textureData->mainImage.format, 0);
VkDeviceSize length = rect->w * pixelSize;
VkDeviceSize stagingBufferSize = length * rect->h;
@@ -3142,6 +3168,15 @@ static void VULKAN_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
return;
}
bool yuv = (textureData->descriptorSetLayoutYcbcr != VK_NULL_HANDLE);
if (yuv) {
const SDL_Rect *rect = &textureData->lockedRect;
const Uint8 *pixels = textureData->pixels + rect->y * textureData->pitch + rect->x * SDL_BYTESPERPIXEL(texture->format);
VULKAN_UpdateTexture(renderer, texture, rect, pixels, textureData->pitch);
return;
}
VULKAN_EnsureCommandBuffer(rendererData);
// Make sure the destination is in the correct resource state

View File

@@ -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;
}
}