Serenity Operating System
at master 319 lines 8.8 kB view raw
1/* 2 * Copyright (c) 2021, Leon Albrecht <leon2002.la@gmail.com> 3 * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/DeprecatedString.h> 9#include <AK/LexicalPath.h> 10#include <LibCore/File.h> 11#include <LibGL/GL/gl.h> 12#include <LibGL/GLContext.h> 13#include <LibGfx/Bitmap.h> 14#include <LibGfx/QOIWriter.h> 15#include <LibTest/TestCase.h> 16 17#ifdef AK_OS_SERENITY 18# define REFERENCE_IMAGE_DIR "/usr/Tests/LibGL/reference-images" 19#else 20# define REFERENCE_IMAGE_DIR "reference-images" 21#endif 22#define SAVE_OUTPUT false 23 24static NonnullOwnPtr<GL::GLContext> create_testing_context(int width, int height) 25{ 26 auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, { width, height })); 27 auto context = MUST(GL::create_context(*bitmap)); 28 GL::make_context_current(context); 29 return context; 30} 31 32static void expect_bitmap_equals_reference(Gfx::Bitmap const& bitmap, StringView test_name) 33{ 34 auto reference_filename = DeprecatedString::formatted("{}.qoi", test_name); 35 36 if constexpr (SAVE_OUTPUT) { 37 auto target_path = LexicalPath("/home/anon").append(reference_filename); 38 auto qoi_buffer = MUST(Gfx::QOIWriter::encode(bitmap)); 39 auto qoi_output_stream = MUST(Core::File::open(target_path.string(), Core::File::OpenMode::Write)); 40 MUST(qoi_output_stream->write_until_depleted(qoi_buffer)); 41 } 42 43 auto reference_image_path = DeprecatedString::formatted(REFERENCE_IMAGE_DIR "/{}", reference_filename); 44 auto reference_bitmap = MUST(Gfx::Bitmap::load_from_file(reference_image_path)); 45 EXPECT_EQ(reference_bitmap->visually_equals(bitmap), true); 46} 47 48TEST_CASE(0001_simple_triangle) 49{ 50 auto context = create_testing_context(64, 64); 51 52 glBegin(GL_TRIANGLES); 53 glColor3f(1, 1, 1); 54 glVertex2f(0, 1); 55 glVertex2f(-1, -1); 56 glVertex2f(1, -1); 57 glEnd(); 58 59 EXPECT_EQ(glGetError(), 0u); 60 61 context->present(); 62 expect_bitmap_equals_reference(context->frontbuffer(), "0001_simple_triangle"sv); 63} 64 65TEST_CASE(0002_quad_color_interpolation) 66{ 67 auto context = create_testing_context(64, 64); 68 69 glBegin(GL_QUADS); 70 71 glColor3f(1, 0, 0); 72 glVertex2i(-1, -1); 73 glColor3f(0, 1, 0); 74 glVertex2i(1, -1); 75 glColor3f(0, 0, 1); 76 glVertex2i(1, 1); 77 glColor3f(1, 0, 1); 78 glVertex2i(-1, 1); 79 glEnd(); 80 81 EXPECT_EQ(glGetError(), 0u); 82 83 context->present(); 84 expect_bitmap_equals_reference(context->frontbuffer(), "0002_quad_color_interpolation"sv); 85} 86 87TEST_CASE(0003_rect_w_coordinate_regression) 88{ 89 auto context = create_testing_context(64, 64); 90 91 glEnable(GL_DEPTH_TEST); 92 glClear(GL_DEPTH_BUFFER_BIT); 93 94 glColor3f(0, 1, 0); 95 glRectf(-0.5f, -0.5f, 0.5f, 0.5f); 96 97 glBegin(GL_TRIANGLES); 98 glColor3f(1, 0, 0); 99 glVertex2i(-1, -1); 100 glVertex2i(1, -1); 101 glVertex2i(-1, 1); 102 glEnd(); 103 104 EXPECT_EQ(glGetError(), 0u); 105 106 context->present(); 107 expect_bitmap_equals_reference(context->frontbuffer(), "0003_rect_w_coordinate_regression"sv); 108} 109 110TEST_CASE(0004_points) 111{ 112 auto context = create_testing_context(64, 64); 113 114 // Aliased points 115 for (size_t i = 0; i < 3; ++i) { 116 glPointSize(1.f + i); 117 glBegin(GL_POINTS); 118 glVertex2f(-.5f + i * .5f, .5f); 119 glEnd(); 120 } 121 122 // Anti-aliased points 123 glEnable(GL_POINT_SMOOTH); 124 glEnable(GL_BLEND); 125 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 126 127 for (size_t i = 0; i < 3; ++i) { 128 glPointSize(3.f - i); 129 glBegin(GL_POINTS); 130 glVertex2f(-.5f + i * .5f, -.5f); 131 glEnd(); 132 } 133 134 EXPECT_EQ(glGetError(), 0u); 135 136 context->present(); 137 expect_bitmap_equals_reference(context->frontbuffer(), "0004_points"sv); 138} 139 140TEST_CASE(0005_lines_antialiased) 141{ 142 auto context = create_testing_context(64, 64); 143 144 // Draw anti-aliased lines 145 glEnable(GL_LINE_SMOOTH); 146 glEnable(GL_BLEND); 147 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 148 149 glBegin(GL_LINES); 150 for (size_t i = 0; i < 6; ++i) { 151 glVertex2f(-.9f, .25f - i * .1f); 152 glVertex2f(.9f, .9f - i * .36f); 153 } 154 glEnd(); 155 156 EXPECT_EQ(glGetError(), 0u); 157 158 context->present(); 159 expect_bitmap_equals_reference(context->frontbuffer(), "0005_lines"sv); 160} 161 162TEST_CASE(0006_test_rgb565_texture) 163{ 164 auto context = create_testing_context(64, 64); 165 166 GLuint texture_id; 167 glGenTextures(1, &texture_id); 168 glBindTexture(GL_TEXTURE_2D, texture_id); 169 u16 texture_data[] = { 0xF800, 0xC000, 0x8000, 0x07E0, 0x0600, 0x0400, 0x001F, 0x0018, 0x0010 }; 170 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 171 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 3, 3, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texture_data); 172 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 173 174 glEnable(GL_TEXTURE_2D); 175 glBegin(GL_QUADS); 176 glTexCoord2i(0, 0); 177 glVertex2i(-1, 1); 178 glTexCoord2i(0, 1); 179 glVertex2i(-1, -1); 180 glTexCoord2i(1, 1); 181 glVertex2i(1, -1); 182 glTexCoord2i(1, 0); 183 glVertex2i(1, 1); 184 glEnd(); 185 186 EXPECT_EQ(glGetError(), 0u); 187 188 context->present(); 189 expect_bitmap_equals_reference(context->frontbuffer(), "0006_test_rgb565_texture"sv); 190} 191 192TEST_CASE(0007_test_rgba_to_rgb_texture) 193{ 194 auto context = create_testing_context(64, 64); 195 196 GLuint texture_id; 197 glGenTextures(1, &texture_id); 198 glBindTexture(GL_TEXTURE_2D, texture_id); 199 200 // Write RGBA data with A = 0 to an RGB texture 201 u32 texture_data[] = { 0x00FF0000 }; 202 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, texture_data); 203 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 204 205 glEnable(GL_TEXTURE_2D); 206 glBegin(GL_TRIANGLES); 207 glTexCoord2i(0, 0); 208 glVertex2i(-1, 1); 209 glTexCoord2i(0, 1); 210 glVertex2i(-1, -1); 211 glTexCoord2i(1, 1); 212 glVertex2i(1, -1); 213 glEnd(); 214 215 EXPECT_EQ(glGetError(), 0u); 216 217 context->present(); 218 expect_bitmap_equals_reference(context->frontbuffer(), "0007_test_rgba_to_rgb_texture"sv); 219} 220 221TEST_CASE(0008_test_pop_matrix_regression) 222{ 223 auto context = create_testing_context(64, 64); 224 225 // Load identity matrix after popping 226 glMatrixMode(GL_MODELVIEW); 227 glTranslatef(10.f, 10.f, 10.f); 228 glPushMatrix(); 229 glPopMatrix(); 230 glLoadIdentity(); 231 232 glBegin(GL_TRIANGLES); 233 glColor3f(0.f, 1.f, 0.f); 234 glVertex2f(.5f, -.5f); 235 glVertex2f(.0f, .5f); 236 glVertex2f(-.5f, -.5f); 237 glEnd(); 238 239 EXPECT_EQ(glGetError(), 0u); 240 241 context->present(); 242 expect_bitmap_equals_reference(context->frontbuffer(), "0008_test_pop_matrix_regression"sv); 243} 244 245TEST_CASE(0009_test_draw_elements_in_display_list) 246{ 247 auto context = create_testing_context(64, 64); 248 249 glColor3f(0.f, 0.f, 1.f); 250 glEnableClientState(GL_VERTEX_ARRAY); 251 252 auto const list_index = glGenLists(1); 253 glNewList(list_index, GL_COMPILE); 254 float vertices[] = { 0.f, .5f, -.5f, -.5f, .5f, -.5f }; 255 glVertexPointer(2, GL_FLOAT, 0, &vertices); 256 u8 indices[] = { 0, 1, 2 }; 257 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, &indices); 258 glEndList(); 259 260 // Modifying an index here should not have an effect 261 indices[0] = 2; 262 263 glCallList(list_index); 264 265 EXPECT_EQ(glGetError(), 0u); 266 267 context->present(); 268 expect_bitmap_equals_reference(context->frontbuffer(), "0009_test_draw_elements_in_display_list"sv); 269} 270 271TEST_CASE(0010_test_store_data_in_buffer) 272{ 273 auto context = create_testing_context(64, 64); 274 275 glColor3f(1.f, 0.f, 0.f); 276 glEnableClientState(GL_VERTEX_ARRAY); 277 278 float vertices[] = { 0.f, .5f, -.5f, -.5f, .5f, -.5f }; 279 u8 indices[] = { 0, 1, 2 }; 280 281 GLuint buffers[2]; 282 glGenBuffers(2, buffers); 283 284 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); 285 glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), vertices, GL_STATIC_DRAW); 286 287 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); 288 glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3, indices, GL_STATIC_DRAW); 289 290 glVertexPointer(2, GL_FLOAT, 0, 0); 291 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, 0); 292 293 glDeleteBuffers(2, buffers); 294 295 EXPECT_EQ(glGetError(), 0u); 296 297 context->present(); 298 expect_bitmap_equals_reference(context->frontbuffer(), "0010_test_store_data_in_buffer"sv); 299} 300 301TEST_CASE(0011_tex_env_combine_with_constant_color) 302{ 303 auto context = create_testing_context(64, 64); 304 305 glEnable(GL_TEXTURE_2D); 306 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); 307 glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT); 308 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); 309 310 float color[4] = { .3f, .5f, .7f, 1.f }; 311 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); 312 313 glRecti(-1, -1, 1, 1); 314 315 EXPECT_EQ(glGetError(), 0u); 316 317 context->present(); 318 expect_bitmap_equals_reference(context->frontbuffer(), "0011_tex_env_combine_with_constant_color"sv); 319}