diff --git a/tests/util/pattern.c b/tests/util/pattern.c index e5f20c50..7c78c81b 100644 --- a/tests/util/pattern.c +++ b/tests/util/pattern.c @@ -23,6 +23,7 @@ * IN THE SOFTWARE. */ +#include #include #include #include @@ -40,6 +41,13 @@ #include "format.h" #include "pattern.h" +struct color_rgba { + uint16_t red; + uint16_t green; + uint16_t blue; + uint16_t alpha; +}; + struct color_rgb24 { unsigned int value:24; } __attribute__((__packed__)); @@ -301,6 +309,16 @@ static void write_pixels_10bpp(unsigned char *mem, mem[4] = ((d >> 2) & 0xff); } +static void update_pixels_10bpp(unsigned char *mem, uint64_t val, uint64_t mask) +{ + int i; + + for (i = 0; i < 5; i++, mask >>= 8, val >>= 8) { + mem[i] &= ~(mask & 0xff); + mem[i] |= (mask & 0xff) & val; + } +} + static void fill_smpte_yuv_planar_10bpp(const struct util_yuv_info *yuv, unsigned char *y_mem, unsigned char *uv_mem, @@ -1849,6 +1867,267 @@ static void fill_gradient(const struct util_format_info *info, void *planes[3], } } +static struct color_rgba get_black_white_value(uint64_t index) +{ + const struct color_rgba colors[] = { + { .red = 0, .green = 0, .blue = 0, .alpha = 255 }, /* black */ + { .red = 255, .green = 255, .blue = 255, .alpha = 255 }, /* white */ + }; + + return colors[index & 0x1]; +} + +static struct color_rgba get_noise_color_value() +{ + struct color_rgba color = { + .red = rand(), + .green = rand(), + .blue = rand(), + .alpha = 255 + }; + + return color; +} + +static struct color_rgba get_rgb_color(uint64_t index, + enum util_fill_pattern pattern) +{ + struct color_rgba color = { + .red = 0, + .green = 0, + .blue = 0, + .alpha = 0 + }; + + switch (pattern) { + case UTIL_PATTERN_NOISE: + color = get_black_white_value(rand()); + + case UTIL_PATTERN_NOISE_COLOR: + color = get_noise_color_value(); + + case UTIL_PATTERN_BLACK_WHITE: + color = get_black_white_value(index); + + default: + break; + } + + return color; +} + +static void insert_value_yuv_packed(const struct util_format_info *info, + void *planes[3], unsigned int stride, + unsigned int x, unsigned int y, + const struct color_rgba* color) +{ + struct color_yuv val = MAKE_YUV_601(color->red, color->green, color->blue); + const struct util_yuv_info *yuv = &info->yuv; + unsigned char *y_mem = (yuv->order & YUV_YC) ? planes[0] : planes[0] + 1; + unsigned char *c_mem = (yuv->order & YUV_CY) ? planes[0] : planes[0] + 1; + unsigned int u = (yuv->order & YUV_YCrCb) ? 2 : 0; + unsigned int v = (yuv->order & YUV_YCbCr) ? 2 : 0; + + if (x & 0x1) + return; + + y_mem += stride * y; + c_mem += stride * y; + + y_mem[2*x] = val.y; + c_mem[2*x+u] = val.u; + y_mem[2*x+2] = val.y; + c_mem[2*x+v] = val.v; +} + +static void insert_value_yuv_planar(const struct util_format_info *info, + void *planes[3], unsigned int stride, + unsigned int x, unsigned int y, + const struct color_rgba* color) +{ + struct color_yuv val = MAKE_YUV_601(color->red, color->green, color->blue); + const struct util_yuv_info *yuv = &info->yuv; + unsigned int cs = yuv->chroma_stride; + unsigned int xsub = yuv->xsub; + unsigned int ysub = yuv->ysub; + unsigned int chroma_offset = (y + 1) / ysub; + unsigned char *y_mem = planes[0] + (y * stride); + unsigned char *u_mem = planes[1]; + unsigned char *v_mem = planes[2]; + + switch (info->format) { + case DRM_FORMAT_NV42: + u_mem = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1; + v_mem = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1; + break; + case DRM_FORMAT_YVU420: + u_mem = planes[2]; + v_mem = planes[1]; + break; + case DRM_FORMAT_YUV420: + default: + break; + } + + u_mem += (chroma_offset * (stride * cs / xsub)); + v_mem += (chroma_offset * (stride * cs / xsub)); + + y_mem[x] = val.y; + u_mem[x/xsub*cs] = val.u; + v_mem[x/xsub*cs] = val.v; +} + +inline bool is_power_of_two(unsigned long val) +{ + return (val != 0) && ((val & (val - 1)) == 0); +} + +static bool check_yuv(const struct util_yuv_info *info) +{ + if (__builtin_expect( + is_power_of_two(info->xsub) && + is_power_of_two(info->ysub) && + is_power_of_two(info->chroma_stride), 1)) { + return true; + } + + return false; +} + +static void insert_value_yuv_planar_10bpp(const struct util_format_info *info, + void *planes[3], unsigned int stride, + unsigned int x, unsigned int y, + const struct color_rgba* color) +{ + struct color_yuv val = MAKE_YUV_601(color->red, color->green, color->blue); + const struct util_yuv_info *yuv = &info->yuv; + unsigned int cs = yuv->chroma_stride; + unsigned int xsub = yuv->xsub; + unsigned int ysub = yuv->ysub; + unsigned int xstep = cs * xsub; + unsigned int ysub_mask = ysub - 1; + unsigned int xsub_mask = xsub - 1; + unsigned int xstep_mask = xstep - 1; + unsigned char *y_mem = planes[0] + (y * stride); + unsigned char *uv_mem = planes[1] + (y * (stride * cs / xsub)); + unsigned int block_start = ((x & 0x3) * 5) / 4; + unsigned int bit_start = (x & 0x3) * 10; + + /* Plus two because val.y is only 8 bits */ + update_pixels_10bpp(&y_mem[block_start], val.y << (bit_start + 2), + 0x3ff << bit_start); + + /* This logic only works when xsub, ysub and chroma stride is power of two. */ + assert(check_yuv(&info->yuv)); + + if (y & ysub_mask) + return; + + if (x & xsub_mask) + return; + + block_start = ((x & ~xstep_mask) * 5) / xstep; + bit_start = x & xstep_mask ? 0 : 20; + + update_pixels_10bpp(&uv_mem[block_start], + ((val.u << 2) | (val.v << 12)) << bit_start, + 0xfffff << bit_start); +} + + +static void insert_value_rgb32(const struct util_format_info *info, + void *planes[3], unsigned int stride, + unsigned int x, unsigned int y, + const struct color_rgba* color) +{ + uint32_t *row = planes[0] + (stride * y); + uint32_t val = MAKE_RGBA10(&info->rgb, color->red, color->green, + color->blue, color->alpha); + + row[x] = val; +} + +static void insert_value_rgb16fp(const struct util_format_info *info, + void *planes[3], unsigned int stride, + unsigned int x, unsigned int y, + const struct color_rgba* color) +{ + uint64_t *row = planes[0] + (stride * y); + uint64_t val = MAKE_RGBA10FP16(&info->rgb, color->red, color->green, + color->blue, color->alpha); + + row[x] = val; +} + +static void fill_simple_patterns(const struct util_format_info *info, + void *planes[3], unsigned int width, + unsigned int height, unsigned int stride, + enum util_fill_pattern pattern) +{ + void (*func_insert_value)(const struct util_format_info *info, + void *planes[3], unsigned int stride, + unsigned int x, unsigned int y, + const struct color_rgba* color); + int x, y; + + switch (info->format) { + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + func_insert_value = &insert_value_yuv_packed; + break; + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + func_insert_value = &insert_value_yuv_planar; + break; + case DRM_FORMAT_NV15: + case DRM_FORMAT_NV20: + case DRM_FORMAT_NV30: + func_insert_value = &insert_value_yuv_planar_10bpp; + break; + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_BGRA1010102: + case DRM_FORMAT_BGRX1010102: + func_insert_value = &insert_value_rgb32; + break; + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_ABGR16161616F: + func_insert_value = &insert_value_rgb16fp; + break; + default: + return; + } + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + struct color_rgba color = get_rgb_color((width * y) + x, pattern); + (*func_insert_value)(info, planes, stride, x, y, &color); + } + } +} + /* * util_fill_pattern - Fill a buffer with a test pattern * @format: Pixel format @@ -1884,6 +2163,12 @@ void util_fill_pattern(uint32_t format, enum util_fill_pattern pattern, case UTIL_PATTERN_GRADIENT: return fill_gradient(info, planes, width, height, stride); + case UTIL_PATTERN_NOISE: + case UTIL_PATTERN_NOISE_COLOR: + case UTIL_PATTERN_BLACK_WHITE: + return fill_simple_patterns(info, planes, width, height, stride, + pattern); + default: printf("Error: unsupported test pattern %u.\n", pattern); break; @@ -1895,6 +2180,9 @@ static const char *pattern_names[] = { [UTIL_PATTERN_SMPTE] = "smpte", [UTIL_PATTERN_PLAIN] = "plain", [UTIL_PATTERN_GRADIENT] = "gradient", + [UTIL_PATTERN_NOISE] = "noise", + [UTIL_PATTERN_NOISE_COLOR] = "noise-color", + [UTIL_PATTERN_BLACK_WHITE] = "black-white", }; enum util_fill_pattern util_pattern_enum(const char *name) diff --git a/tests/util/pattern.h b/tests/util/pattern.h index e500aba3..13fd8dc8 100644 --- a/tests/util/pattern.h +++ b/tests/util/pattern.h @@ -33,6 +33,9 @@ enum util_fill_pattern { UTIL_PATTERN_PLAIN, UTIL_PATTERN_SMPTE, UTIL_PATTERN_GRADIENT, + UTIL_PATTERN_NOISE, + UTIL_PATTERN_NOISE_COLOR, + UTIL_PATTERN_BLACK_WHITE, }; void util_fill_pattern(uint32_t format, enum util_fill_pattern pattern,