diff --git a/src/tests/cogl/conform/meson.build b/src/tests/cogl/conform/meson.build index e076733a5..39ada1c67 100644 --- a/src/tests/cogl/conform/meson.build +++ b/src/tests/cogl/conform/meson.build @@ -15,6 +15,7 @@ cogl_tests = [ [ 'test-sub-texture', [] ], [ 'test-custom-attributes', [] ], [ 'test-offscreen', [] ], + [ 'test-offscreen-texture-formats', [] ], [ 'test-journal', [] ], [ 'test-primitive', [] ], [ 'test-sparse-pipeline', [] ], diff --git a/src/tests/cogl/conform/test-offscreen-texture-formats.c b/src/tests/cogl/conform/test-offscreen-texture-formats.c new file mode 100644 index 000000000..7b6e61ec7 --- /dev/null +++ b/src/tests/cogl/conform/test-offscreen-texture-formats.c @@ -0,0 +1,237 @@ +/* + * 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); + return (int) (r * (float) (1 << 8)); +} + +static int +rgb8_to_rgb10 (int rgb8) +{ + float r; + + r = rgb8 / (float) (1 << 8); + return (int) (r * (float) (1 << 10)); +} + +static void +test_offscreen_texture_formats_store_rgb10 (void) +{ + const int rgb10_red = 514; + const int rgb10_green = 258; + const int rgb10_blue = 18; + float red; + float green; + float blue; + GError *error = NULL; + CoglPixelFormat formats[] = { + COGL_PIXEL_FORMAT_ABGR_2101010, + COGL_PIXEL_FORMAT_ARGB_2101010, + COGL_PIXEL_FORMAT_XRGB_2101010, + COGL_PIXEL_FORMAT_RGBA_1010102, + COGL_PIXEL_FORMAT_BGRA_1010102, + COGL_PIXEL_FORMAT_XBGR_2101010, + }; + int i; + + /* The extra fraction is there to avoid rounding inconsistencies in OpenGL + * implementations. */ + red = (rgb10_red / (float) (1 << 10)) + 0.00001; + green = (rgb10_green / (float) (1 << 10)) + 0.00001; + blue = (rgb10_blue / (float) (1 << 10)) + 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]; + uint8_t *rgb8_buf; + 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_clear4f (COGL_FRAMEBUFFER (offscreen), + COGL_BUFFER_BIT_COLOR, + red, green, blue, 1.0); + + for (j = 0; j < G_N_ELEMENTS (formats); j++) + { + uint32_t rgb10_readback[4]; + int channels[3]; + int alpha; + + cogl_framebuffer_read_pixels (COGL_FRAMEBUFFER (offscreen), 0, 0, 2, 2, + formats[j], + (uint8_t *) &rgb10_readback); + + switch (formats[j]) + { + case COGL_PIXEL_FORMAT_RGBA_1010102: + case COGL_PIXEL_FORMAT_BGRA_1010102: + channels[0] = get_bits (rgb10_readback[0], 31, 22); + channels[1] = get_bits (rgb10_readback[0], 21, 12); + channels[2] = get_bits (rgb10_readback[0], 11, 2); + alpha = get_bits (rgb10_readback[0], 1, 0); + break; + case COGL_PIXEL_FORMAT_XRGB_2101010: + case COGL_PIXEL_FORMAT_ARGB_2101010: + case COGL_PIXEL_FORMAT_XBGR_2101010: + case COGL_PIXEL_FORMAT_ABGR_2101010: + alpha = get_bits (rgb10_readback[0], 31, 30); + channels[0] = get_bits (rgb10_readback[0], 29, 20); + channels[1] = get_bits (rgb10_readback[0], 19, 10); + channels[2] = get_bits (rgb10_readback[0], 9, 0); + break; + default: + g_assert_not_reached (); + } + + g_assert_cmpint (alpha, ==, 0x3); + + switch (formats[j]) + { + case COGL_PIXEL_FORMAT_RGBA_1010102: + case COGL_PIXEL_FORMAT_XRGB_2101010: + case COGL_PIXEL_FORMAT_ARGB_2101010: + 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: + case COGL_PIXEL_FORMAT_XBGR_2101010: + case COGL_PIXEL_FORMAT_ABGR_2101010: + 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_RGBA_8888, + (uint8_t *) &rgb8_readback); + rgb8_buf = (uint8_t *) &rgb8_readback[0]; + + 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)); + g_assert_cmpint (rgb8_buf[3], ==, 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; + float red; + float green; + float blue; + CoglTexture2D *tex_src; + CoglOffscreen *offscreen_src; + CoglTexture2D *tex_dst; + CoglOffscreen *offscreen_dst; + CoglPipeline *pipeline; + uint32_t rgb10_readback[4]; + GError *error = NULL; + + /* The extra fraction is there to avoid rounding inconsistencies in OpenGL + * implementations. */ + red = (rgb10_red / (float) (1 << 10)) + 0.00001; + green = (rgb10_green / (float) (1 << 10)) + 0.00001; + blue = (rgb10_blue / (float) (1 << 10)) + 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); + + tex_src = cogl_texture_2d_new_with_format (test_ctx, 2, 2, + COGL_PIXEL_FORMAT_RGBA_1010102); + offscreen_src = cogl_offscreen_new_with_texture (COGL_TEXTURE (tex_src)); + cogl_framebuffer_allocate (COGL_FRAMEBUFFER (offscreen_src), &error); + g_assert_no_error (error); + + tex_dst = cogl_texture_2d_new_with_format (test_ctx, 2, 2, + COGL_PIXEL_FORMAT_ABGR_2101010); + 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, 1.0); + + 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, + COGL_PIXEL_FORMAT_ABGR_2101010, + (uint8_t *) &rgb10_readback); + g_assert_cmpint (get_bits (rgb10_readback[0], 31, 30), ==, 0x3); + g_assert_cmpint (get_bits (rgb10_readback[0], 29, 20), ==, rgb10_blue); + g_assert_cmpint (get_bits (rgb10_readback[0], 19, 10), ==, rgb10_green); + g_assert_cmpint (get_bits (rgb10_readback[0], 9, 0), ==, rgb10_red); +} + +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/paint-rgb10", + test_offscreen_texture_formats_paint_rgb10); +)