/* * Copyright (C) 2022 Intel Corporation. * Copyright (C) 2022 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include #include "tests/cogl-test-utils.h" static int get_bits (uint32_t in, int end, int begin) { int mask = (1 << (end - begin + 1)) - 1; return (in >> begin) & mask; } static int rgb10_to_rgb8 (int rgb10) { float r; r = rgb10 / (float) ((1 << 10) - 1); return (int) (r * (float) ((1 << 8) - 1)); } static int rgb8_to_rgb10 (int rgb8) { float r; r = rgb8 / (float) ((1 << 8) - 1); return (int) (r * (float) ((1 << 10) - 1)); } static void test_offscreen_texture_formats_store_rgb10 (void) { const int rgb10_red = 514; const int rgb10_green = 258; const int rgb10_blue = 18; const int rgb10_alpha = 2; float red; float green; float blue; float alpha; GError *error = NULL; CoglPixelFormat formats[] = { COGL_PIXEL_FORMAT_XRGB_2101010, COGL_PIXEL_FORMAT_ARGB_2101010_PRE, COGL_PIXEL_FORMAT_XBGR_2101010, COGL_PIXEL_FORMAT_ABGR_2101010_PRE, COGL_PIXEL_FORMAT_RGBA_1010102_PRE, COGL_PIXEL_FORMAT_BGRA_1010102_PRE, }; int i; /* The extra fraction is there to avoid rounding inconsistencies in OpenGL * implementations. */ red = (rgb10_red / (float) ((1 << 10) - 1)) + 0.00001; green = (rgb10_green / (float) ((1 << 10) - 1)) + 0.00001; blue = (rgb10_blue / (float) ((1 << 10) - 1)) + 0.00001; alpha = (rgb10_alpha / (float) ((1 << 2) - 1)) + 0.00001; /* Make sure that that the color value can't be represented using rgb8. */ g_assert_cmpint (rgb8_to_rgb10 (rgb10_to_rgb8 (rgb10_red)), !=, rgb10_red); g_assert_cmpint (rgb8_to_rgb10 (rgb10_to_rgb8 (rgb10_green)), !=, rgb10_green); g_assert_cmpint (rgb8_to_rgb10 (rgb10_to_rgb8 (rgb10_blue)), !=, rgb10_blue); for (i = 0; i < G_N_ELEMENTS (formats); i++) { CoglTexture2D *tex; CoglOffscreen *offscreen; uint32_t rgb8_readback[4]; int j, k; /* Allocate 2x2 to ensure we avoid any fast paths. */ tex = cogl_texture_2d_new_with_format (test_ctx, 2, 2, formats[i]); offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (tex)); cogl_framebuffer_allocate (COGL_FRAMEBUFFER (offscreen), &error); g_assert_no_error (error); cogl_framebuffer_clear4f (COGL_FRAMEBUFFER (offscreen), COGL_BUFFER_BIT_COLOR, red, green, blue, alpha); for (j = 0; j < G_N_ELEMENTS (formats); j++) { uint32_t rgb10_readback[4]; int alpha_out; cogl_framebuffer_read_pixels (COGL_FRAMEBUFFER (offscreen), 0, 0, 2, 2, formats[j], (uint8_t *) &rgb10_readback); for (k = 0; k < 4; k++) { int channels[3]; switch (formats[j]) { case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: channels[0] = get_bits (rgb10_readback[k], 31, 22); channels[1] = get_bits (rgb10_readback[k], 21, 12); channels[2] = get_bits (rgb10_readback[k], 11, 2); alpha_out = get_bits (rgb10_readback[k], 1, 0); break; case COGL_PIXEL_FORMAT_XRGB_2101010: case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: case COGL_PIXEL_FORMAT_XBGR_2101010: case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: alpha_out = get_bits (rgb10_readback[k], 31, 30); channels[0] = get_bits (rgb10_readback[k], 29, 20); channels[1] = get_bits (rgb10_readback[k], 19, 10); channels[2] = get_bits (rgb10_readback[k], 9, 0); break; default: g_assert_not_reached (); } if ((formats[i] & COGL_A_BIT) && (formats[j] & COGL_A_BIT)) g_assert_cmpint (alpha_out, ==, rgb10_alpha); else if (!(formats[i] & COGL_A_BIT) && !(formats[j] & COGL_A_BIT)) g_assert_cmpint (alpha_out, ==, 0x3); switch (formats[j]) { case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: case COGL_PIXEL_FORMAT_XRGB_2101010: case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: g_assert_cmpint (channels[0], ==, rgb10_red); g_assert_cmpint (channels[1], ==, rgb10_green); g_assert_cmpint (channels[2], ==, rgb10_blue); break; case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: case COGL_PIXEL_FORMAT_XBGR_2101010: case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: g_assert_cmpint (channels[0], ==, rgb10_blue); g_assert_cmpint (channels[1], ==, rgb10_green); g_assert_cmpint (channels[2], ==, rgb10_red); break; default: g_assert_not_reached (); } } } cogl_framebuffer_read_pixels (COGL_FRAMEBUFFER (offscreen), 0, 0, 2, 2, COGL_PIXEL_FORMAT_RGBX_8888, (uint8_t *) &rgb8_readback); for (k = 0; k < 4; k++) { uint8_t *rgb8_buf = (uint8_t *) &rgb8_readback[k]; g_assert_cmpint (rgb8_buf[0], ==, rgb10_to_rgb8 (rgb10_red)); g_assert_cmpint (rgb8_buf[1], ==, rgb10_to_rgb8 (rgb10_green)); g_assert_cmpint (rgb8_buf[2], ==, rgb10_to_rgb8 (rgb10_blue)); if (!(formats[i] & COGL_A_BIT)) g_assert_cmpint (rgb8_buf[3], ==, 0xff); } g_object_unref (offscreen); cogl_object_unref (tex); } } static void test_offscreen_texture_formats_store_rgb8 (void) { CoglColor color; const uint8_t red = 0xab; const uint8_t green = 0x1f; const uint8_t blue = 0x50; const uint8_t alpha = 0x34; CoglPixelFormat formats[] = { COGL_PIXEL_FORMAT_RGBX_8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_PIXEL_FORMAT_BGRX_8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_PIXEL_FORMAT_XRGB_8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_PIXEL_FORMAT_XBGR_8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, }; int i; cogl_color_init_from_4ub (&color, red, green, blue, alpha); for (i = 0; i < G_N_ELEMENTS (formats); i++) { CoglTexture2D *tex; CoglOffscreen *offscreen; GError *error = NULL; int j; /* Allocate 2x2 to ensure we avoid any fast paths. */ tex = cogl_texture_2d_new_with_format (test_ctx, 2, 2, formats[i]); offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (tex)); cogl_framebuffer_allocate (COGL_FRAMEBUFFER (offscreen), &error); g_assert_no_error (error); cogl_framebuffer_clear (COGL_FRAMEBUFFER (offscreen), COGL_BUFFER_BIT_COLOR, &color); for (j = 0; j < G_N_ELEMENTS (formats); j++) { uint8_t rgba_readback[4 * 4] = {}; int alpha_out; int k; cogl_framebuffer_read_pixels (COGL_FRAMEBUFFER (offscreen), 0, 0, 2, 2, formats[j], (uint8_t *) &rgba_readback); for (k = 0; k < 4; k++) { switch (formats[j]) { case COGL_PIXEL_FORMAT_RGBX_8888: case COGL_PIXEL_FORMAT_RGBA_8888_PRE: g_assert_cmpint (rgba_readback[k * 4 + 0], ==, red); g_assert_cmpint (rgba_readback[k * 4 + 1], ==, green); g_assert_cmpint (rgba_readback[k * 4 + 2], ==, blue); alpha_out = rgba_readback[k * 4 + 3]; break; case COGL_PIXEL_FORMAT_XRGB_8888: case COGL_PIXEL_FORMAT_ARGB_8888_PRE: alpha_out = rgba_readback[k * 4 + 0]; g_assert_cmpint (rgba_readback[k * 4 + 1], ==, red); g_assert_cmpint (rgba_readback[k * 4 + 2], ==, green); g_assert_cmpint (rgba_readback[k * 4 + 3], ==, blue); break; case COGL_PIXEL_FORMAT_BGRX_8888: case COGL_PIXEL_FORMAT_BGRA_8888_PRE: g_assert_cmpint (rgba_readback[k * 4 + 0], ==, blue); g_assert_cmpint (rgba_readback[k * 4 + 1], ==, green); g_assert_cmpint (rgba_readback[k * 4 + 2], ==, red); alpha_out = rgba_readback[k * 4 + 3]; break; case COGL_PIXEL_FORMAT_XBGR_8888: case COGL_PIXEL_FORMAT_ABGR_8888_PRE: alpha_out = rgba_readback[k * 4 + 0]; g_assert_cmpint (rgba_readback[k * 4 + 1], ==, blue); g_assert_cmpint (rgba_readback[k * 4 + 2], ==, green); g_assert_cmpint (rgba_readback[k * 4 + 3], ==, red); break; default: g_assert_not_reached (); } if ((formats[i] & COGL_A_BIT) && (formats[j] & COGL_A_BIT)) g_assert_cmpint (alpha_out, ==, alpha); else if (!(formats[i] & COGL_A_BIT) && !(formats[j] & COGL_A_BIT)) g_assert_cmpint (alpha_out, ==, 0xff); } } g_object_unref (offscreen); cogl_object_unref (tex); } } static void test_offscreen_texture_formats_paint_rgb10 (void) { const int rgb10_red = 514; const int rgb10_green = 258; const int rgb10_blue = 18; const int rgb10_alpha = 2; float red; float green; float blue; float alpha; CoglPixelFormat formats[] = { COGL_PIXEL_FORMAT_XRGB_2101010, COGL_PIXEL_FORMAT_ARGB_2101010_PRE, COGL_PIXEL_FORMAT_XBGR_2101010, COGL_PIXEL_FORMAT_ABGR_2101010_PRE, COGL_PIXEL_FORMAT_RGBA_1010102_PRE, COGL_PIXEL_FORMAT_BGRA_1010102_PRE, }; int i; /* The extra fraction is there to avoid rounding inconsistencies in OpenGL * implementations. */ red = (rgb10_red / (float) ((1 << 10 ) - 1)) + 0.00001; green = (rgb10_green / (float) ((1 << 10) - 1)) + 0.00001; blue = (rgb10_blue / (float) ((1 << 10) - 1)) + 0.00001; alpha = (rgb10_alpha / (float) ((1 << 2) - 1)) + 0.00001; /* Make sure that that the color value can't be represented using rgb8. */ g_assert_cmpint (rgb8_to_rgb10 (rgb10_to_rgb8 (rgb10_red)), !=, rgb10_red); g_assert_cmpint (rgb8_to_rgb10 (rgb10_to_rgb8 (rgb10_green)), !=, rgb10_green); g_assert_cmpint (rgb8_to_rgb10 (rgb10_to_rgb8 (rgb10_blue)), !=, rgb10_blue); for (i = 0; i < G_N_ELEMENTS (formats); i++) { CoglTexture2D *tex_src; CoglOffscreen *offscreen_src; GError *error = NULL; int j; tex_src = cogl_texture_2d_new_with_format (test_ctx, 2, 2, formats[i]); offscreen_src = cogl_offscreen_new_with_texture (COGL_TEXTURE (tex_src)); cogl_framebuffer_allocate (COGL_FRAMEBUFFER (offscreen_src), &error); g_assert_no_error (error); for (j = 0; j < G_N_ELEMENTS (formats); j++) { CoglTexture2D *tex_dst; CoglOffscreen *offscreen_dst; CoglPipeline *pipeline; uint32_t rgb10_readback[4]; int k; tex_dst = cogl_texture_2d_new_with_format (test_ctx, 2, 2, formats[j]); offscreen_dst = cogl_offscreen_new_with_texture (COGL_TEXTURE (tex_dst)); cogl_framebuffer_allocate (COGL_FRAMEBUFFER (offscreen_dst), &error); g_assert_no_error (error); cogl_framebuffer_clear4f (COGL_FRAMEBUFFER (offscreen_src), COGL_BUFFER_BIT_COLOR, red, green, blue, alpha); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (pipeline, 0, tex_src); cogl_framebuffer_draw_rectangle (COGL_FRAMEBUFFER (offscreen_dst), pipeline, -1.0, -1.0, 1.0, 1.0); cogl_object_unref (pipeline); cogl_framebuffer_read_pixels (COGL_FRAMEBUFFER (offscreen_dst), 0, 0, 2, 2, formats[j], (uint8_t *) &rgb10_readback); for (k = 0; k < 4; k++) { int channels[3]; int alpha_out; switch (formats[j]) { case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: channels[0] = get_bits (rgb10_readback[k], 31, 22); channels[1] = get_bits (rgb10_readback[k], 21, 12); channels[2] = get_bits (rgb10_readback[k], 11, 2); alpha_out = get_bits (rgb10_readback[k], 1, 0); break; case COGL_PIXEL_FORMAT_XRGB_2101010: case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: case COGL_PIXEL_FORMAT_XBGR_2101010: case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: alpha_out = get_bits (rgb10_readback[k], 31, 30); channels[0] = get_bits (rgb10_readback[k], 29, 20); channels[1] = get_bits (rgb10_readback[k], 19, 10); channels[2] = get_bits (rgb10_readback[k], 9, 0); break; default: g_assert_not_reached (); } if ((formats[i] & COGL_A_BIT) && (formats[j] & COGL_A_BIT)) g_assert_cmpint (alpha_out, ==, rgb10_alpha); else if (!(formats[i] & COGL_A_BIT) && !(formats[j] & COGL_A_BIT)) g_assert_cmpint (alpha_out, ==, 0x3); switch (formats[j]) { case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: case COGL_PIXEL_FORMAT_XRGB_2101010: case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: g_assert_cmpint (channels[0], ==, rgb10_red); g_assert_cmpint (channels[1], ==, rgb10_green); g_assert_cmpint (channels[2], ==, rgb10_blue); break; case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: case COGL_PIXEL_FORMAT_XBGR_2101010: case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: g_assert_cmpint (channels[0], ==, rgb10_blue); g_assert_cmpint (channels[1], ==, rgb10_green); g_assert_cmpint (channels[2], ==, rgb10_red); break; default: g_assert_not_reached (); } } g_object_unref (offscreen_dst); cogl_object_unref (tex_dst); } g_object_unref (offscreen_src); cogl_object_unref (tex_src); } } static void test_offscreen_texture_formats_paint_rgb8 (void) { CoglColor color; const uint8_t red = 0xab; const uint8_t green = 0x1f; const uint8_t blue = 0x50; const uint8_t alpha = 0x34; CoglPixelFormat formats[] = { COGL_PIXEL_FORMAT_RGBX_8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_PIXEL_FORMAT_BGRX_8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_PIXEL_FORMAT_XRGB_8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_PIXEL_FORMAT_XBGR_8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, }; int i; cogl_color_init_from_4ub (&color, red, green, blue, alpha); for (i = 0; i < G_N_ELEMENTS (formats); i++) { CoglTexture2D *tex_src; CoglOffscreen *offscreen_src; GError *error = NULL; int j; tex_src = cogl_texture_2d_new_with_format (test_ctx, 2, 2, formats[i]); offscreen_src = cogl_offscreen_new_with_texture (COGL_TEXTURE (tex_src)); cogl_framebuffer_allocate (COGL_FRAMEBUFFER (offscreen_src), &error); g_assert_no_error (error); for (j = 0; j < G_N_ELEMENTS (formats); j++) { CoglTexture2D *tex_dst; CoglOffscreen *offscreen_dst; CoglPipeline *pipeline; uint8_t rgba_readback[4 * 4] = {}; int k; tex_dst = cogl_texture_2d_new_with_format (test_ctx, 2, 2, formats[j]); offscreen_dst = cogl_offscreen_new_with_texture (COGL_TEXTURE (tex_dst)); cogl_framebuffer_allocate (COGL_FRAMEBUFFER (offscreen_dst), &error); g_assert_no_error (error); cogl_framebuffer_clear (COGL_FRAMEBUFFER (offscreen_src), COGL_BUFFER_BIT_COLOR, &color); pipeline = cogl_pipeline_new (test_ctx); cogl_pipeline_set_layer_texture (pipeline, 0, tex_src); cogl_framebuffer_draw_rectangle (COGL_FRAMEBUFFER (offscreen_dst), pipeline, -1.0, -1.0, 1.0, 1.0); cogl_object_unref (pipeline); cogl_framebuffer_read_pixels (COGL_FRAMEBUFFER (offscreen_dst), 0, 0, 2, 2, formats[j], (uint8_t *) &rgba_readback); for (k = 0; k < 4; k++) { int alpha_out; switch (formats[j]) { case COGL_PIXEL_FORMAT_RGBX_8888: case COGL_PIXEL_FORMAT_RGBA_8888_PRE: g_assert_cmpint (rgba_readback[k * 4 + 0], ==, red); g_assert_cmpint (rgba_readback[k * 4 + 1], ==, green); g_assert_cmpint (rgba_readback[k * 4 + 2], ==, blue); alpha_out = rgba_readback[k * 4 + 3]; break; case COGL_PIXEL_FORMAT_XRGB_8888: case COGL_PIXEL_FORMAT_ARGB_8888_PRE: alpha_out = rgba_readback[k * 4 + 0]; g_assert_cmpint (rgba_readback[k * 4 + 1], ==, red); g_assert_cmpint (rgba_readback[k * 4 + 2], ==, green); g_assert_cmpint (rgba_readback[k * 4 + 3], ==, blue); break; case COGL_PIXEL_FORMAT_BGRX_8888: case COGL_PIXEL_FORMAT_BGRA_8888_PRE: g_assert_cmpint (rgba_readback[k * 4 + 0], ==, blue); g_assert_cmpint (rgba_readback[k * 4 + 1], ==, green); g_assert_cmpint (rgba_readback[k * 4 + 2], ==, red); alpha_out = rgba_readback[k * 4 + 3]; break; case COGL_PIXEL_FORMAT_XBGR_8888: case COGL_PIXEL_FORMAT_ABGR_8888_PRE: alpha_out = rgba_readback[k * 4 + 0]; g_assert_cmpint (rgba_readback[k * 4 + 1], ==, blue); g_assert_cmpint (rgba_readback[k * 4 + 2], ==, green); g_assert_cmpint (rgba_readback[k * 4 + 3], ==, red); break; default: g_assert_not_reached (); } if ((formats[i] & COGL_A_BIT) && (formats[j] & COGL_A_BIT)) g_assert_cmpint (alpha_out, ==, alpha); else if (!(formats[i] & COGL_A_BIT) && !(formats[j] & COGL_A_BIT)) g_assert_cmpint (alpha_out, ==, 0xff); } g_object_unref (offscreen_dst); cogl_object_unref (tex_dst); } g_object_unref (offscreen_src); cogl_object_unref (tex_src); } } COGL_TEST_SUITE ( g_test_add_func ("/offscreen/texture-formats/store-rgb10", test_offscreen_texture_formats_store_rgb10); g_test_add_func ("/offscreen/texture-formats/store-8", test_offscreen_texture_formats_store_rgb8); g_test_add_func ("/offscreen/texture-formats/paint-rgb10", test_offscreen_texture_formats_paint_rgb10); g_test_add_func ("/offscreen/texture-formats/paint-rgb8", test_offscreen_texture_formats_paint_rgb8); )