/* * Copyright (c) 2021, Leon Albrecht * Copyright (c) 2022, Jelle Raaijmakers * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #ifdef AK_OS_SERENITY # define REFERENCE_IMAGE_DIR "/usr/Tests/LibGL/reference-images" #else # define REFERENCE_IMAGE_DIR "reference-images" #endif #define SAVE_OUTPUT false static NonnullOwnPtr create_testing_context(int width, int height) { auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, { width, height })); auto context = MUST(GL::create_context(*bitmap)); GL::make_context_current(context); return context; } static void expect_bitmap_equals_reference(Gfx::Bitmap const& bitmap, StringView test_name) { auto reference_filename = DeprecatedString::formatted("{}.qoi", test_name); if constexpr (SAVE_OUTPUT) { auto target_path = LexicalPath("/home/anon").append(reference_filename); auto qoi_buffer = MUST(Gfx::QOIWriter::encode(bitmap)); auto qoi_output_stream = MUST(Core::File::open(target_path.string(), Core::File::OpenMode::Write)); MUST(qoi_output_stream->write_until_depleted(qoi_buffer)); } auto reference_image_path = DeprecatedString::formatted(REFERENCE_IMAGE_DIR "/{}", reference_filename); auto reference_bitmap = MUST(Gfx::Bitmap::load_from_file(reference_image_path)); EXPECT_EQ(reference_bitmap->visually_equals(bitmap), true); } TEST_CASE(0001_simple_triangle) { auto context = create_testing_context(64, 64); glBegin(GL_TRIANGLES); glColor3f(1, 1, 1); glVertex2f(0, 1); glVertex2f(-1, -1); glVertex2f(1, -1); glEnd(); EXPECT_EQ(glGetError(), 0u); context->present(); expect_bitmap_equals_reference(context->frontbuffer(), "0001_simple_triangle"sv); } TEST_CASE(0002_quad_color_interpolation) { auto context = create_testing_context(64, 64); glBegin(GL_QUADS); glColor3f(1, 0, 0); glVertex2i(-1, -1); glColor3f(0, 1, 0); glVertex2i(1, -1); glColor3f(0, 0, 1); glVertex2i(1, 1); glColor3f(1, 0, 1); glVertex2i(-1, 1); glEnd(); EXPECT_EQ(glGetError(), 0u); context->present(); expect_bitmap_equals_reference(context->frontbuffer(), "0002_quad_color_interpolation"sv); } TEST_CASE(0003_rect_w_coordinate_regression) { auto context = create_testing_context(64, 64); glEnable(GL_DEPTH_TEST); glClear(GL_DEPTH_BUFFER_BIT); glColor3f(0, 1, 0); glRectf(-0.5f, -0.5f, 0.5f, 0.5f); glBegin(GL_TRIANGLES); glColor3f(1, 0, 0); glVertex2i(-1, -1); glVertex2i(1, -1); glVertex2i(-1, 1); glEnd(); EXPECT_EQ(glGetError(), 0u); context->present(); expect_bitmap_equals_reference(context->frontbuffer(), "0003_rect_w_coordinate_regression"sv); } TEST_CASE(0004_points) { auto context = create_testing_context(64, 64); // Aliased points for (size_t i = 0; i < 3; ++i) { glPointSize(1.f + i); glBegin(GL_POINTS); glVertex2f(-.5f + i * .5f, .5f); glEnd(); } // Anti-aliased points glEnable(GL_POINT_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); for (size_t i = 0; i < 3; ++i) { glPointSize(3.f - i); glBegin(GL_POINTS); glVertex2f(-.5f + i * .5f, -.5f); glEnd(); } EXPECT_EQ(glGetError(), 0u); context->present(); expect_bitmap_equals_reference(context->frontbuffer(), "0004_points"sv); } TEST_CASE(0005_lines_antialiased) { auto context = create_testing_context(64, 64); // Draw anti-aliased lines glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBegin(GL_LINES); for (size_t i = 0; i < 6; ++i) { glVertex2f(-.9f, .25f - i * .1f); glVertex2f(.9f, .9f - i * .36f); } glEnd(); EXPECT_EQ(glGetError(), 0u); context->present(); expect_bitmap_equals_reference(context->frontbuffer(), "0005_lines"sv); } TEST_CASE(0006_test_rgb565_texture) { auto context = create_testing_context(64, 64); GLuint texture_id; glGenTextures(1, &texture_id); glBindTexture(GL_TEXTURE_2D, texture_id); u16 texture_data[] = { 0xF800, 0xC000, 0x8000, 0x07E0, 0x0600, 0x0400, 0x001F, 0x0018, 0x0010 }; glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 3, 3, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texture_data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(-1, 1); glTexCoord2i(0, 1); glVertex2i(-1, -1); glTexCoord2i(1, 1); glVertex2i(1, -1); glTexCoord2i(1, 0); glVertex2i(1, 1); glEnd(); EXPECT_EQ(glGetError(), 0u); context->present(); expect_bitmap_equals_reference(context->frontbuffer(), "0006_test_rgb565_texture"sv); } TEST_CASE(0007_test_rgba_to_rgb_texture) { auto context = create_testing_context(64, 64); GLuint texture_id; glGenTextures(1, &texture_id); glBindTexture(GL_TEXTURE_2D, texture_id); // Write RGBA data with A = 0 to an RGB texture u32 texture_data[] = { 0x00FF0000 }; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, texture_data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glEnable(GL_TEXTURE_2D); glBegin(GL_TRIANGLES); glTexCoord2i(0, 0); glVertex2i(-1, 1); glTexCoord2i(0, 1); glVertex2i(-1, -1); glTexCoord2i(1, 1); glVertex2i(1, -1); glEnd(); EXPECT_EQ(glGetError(), 0u); context->present(); expect_bitmap_equals_reference(context->frontbuffer(), "0007_test_rgba_to_rgb_texture"sv); } TEST_CASE(0008_test_pop_matrix_regression) { auto context = create_testing_context(64, 64); // Load identity matrix after popping glMatrixMode(GL_MODELVIEW); glTranslatef(10.f, 10.f, 10.f); glPushMatrix(); glPopMatrix(); glLoadIdentity(); glBegin(GL_TRIANGLES); glColor3f(0.f, 1.f, 0.f); glVertex2f(.5f, -.5f); glVertex2f(.0f, .5f); glVertex2f(-.5f, -.5f); glEnd(); EXPECT_EQ(glGetError(), 0u); context->present(); expect_bitmap_equals_reference(context->frontbuffer(), "0008_test_pop_matrix_regression"sv); } TEST_CASE(0009_test_draw_elements_in_display_list) { auto context = create_testing_context(64, 64); glColor3f(0.f, 0.f, 1.f); glEnableClientState(GL_VERTEX_ARRAY); auto const list_index = glGenLists(1); glNewList(list_index, GL_COMPILE); float vertices[] = { 0.f, .5f, -.5f, -.5f, .5f, -.5f }; glVertexPointer(2, GL_FLOAT, 0, &vertices); u8 indices[] = { 0, 1, 2 }; glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, &indices); glEndList(); // Modifying an index here should not have an effect indices[0] = 2; glCallList(list_index); EXPECT_EQ(glGetError(), 0u); context->present(); expect_bitmap_equals_reference(context->frontbuffer(), "0009_test_draw_elements_in_display_list"sv); } TEST_CASE(0010_test_store_data_in_buffer) { auto context = create_testing_context(64, 64); glColor3f(1.f, 0.f, 0.f); glEnableClientState(GL_VERTEX_ARRAY); float vertices[] = { 0.f, .5f, -.5f, -.5f, .5f, -.5f }; u8 indices[] = { 0, 1, 2 }; GLuint buffers[2]; glGenBuffers(2, buffers); glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), vertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3, indices, GL_STATIC_DRAW); glVertexPointer(2, GL_FLOAT, 0, 0); glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, 0); glDeleteBuffers(2, buffers); EXPECT_EQ(glGetError(), 0u); context->present(); expect_bitmap_equals_reference(context->frontbuffer(), "0010_test_store_data_in_buffer"sv); } TEST_CASE(0011_tex_env_combine_with_constant_color) { auto context = create_testing_context(64, 64); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); float color[4] = { .3f, .5f, .7f, 1.f }; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); glRecti(-1, -1, 1, 1); EXPECT_EQ(glGetError(), 0u); context->present(); expect_bitmap_equals_reference(context->frontbuffer(), "0011_tex_env_combine_with_constant_color"sv); }