TestRender.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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. #include <AK/LexicalPath.h>
  8. #include <AK/String.h>
  9. #include <LibCore/FileStream.h>
  10. #include <LibGL/GL/gl.h>
  11. #include <LibGL/GLContext.h>
  12. #include <LibGfx/Bitmap.h>
  13. #include <LibGfx/QOIWriter.h>
  14. #include <LibTest/TestCase.h>
  15. #ifdef AK_OS_SERENITY
  16. # define REFERENCE_IMAGE_DIR "/usr/Tests/LibGL/reference-images"
  17. #else
  18. # define REFERENCE_IMAGE_DIR "reference-images"
  19. #endif
  20. #define SAVE_OUTPUT false
  21. static NonnullOwnPtr<GL::GLContext> create_testing_context(int width, int height)
  22. {
  23. auto bitmap = MUST(Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRx8888, { width, height }));
  24. auto context = MUST(GL::create_context(*bitmap));
  25. GL::make_context_current(context);
  26. return context;
  27. }
  28. static void expect_bitmap_equals_reference(Gfx::Bitmap const& bitmap, StringView test_name)
  29. {
  30. auto reference_filename = String::formatted("{}.qoi", test_name);
  31. if constexpr (SAVE_OUTPUT) {
  32. auto target_path = LexicalPath("/home/anon").append(reference_filename);
  33. auto qoi_buffer = Gfx::QOIWriter::encode(bitmap);
  34. auto qoi_output_stream = MUST(Core::OutputFileStream::open(target_path.string()));
  35. auto number_of_bytes_written = qoi_output_stream.write(qoi_buffer);
  36. qoi_output_stream.close();
  37. EXPECT_EQ(number_of_bytes_written, qoi_buffer.size());
  38. }
  39. auto reference_image_path = String::formatted(REFERENCE_IMAGE_DIR "/{}", reference_filename);
  40. auto reference_bitmap = MUST(Gfx::Bitmap::try_load_from_file(reference_image_path));
  41. EXPECT_EQ(reference_bitmap->visually_equals(bitmap), true);
  42. }
  43. TEST_CASE(0001_simple_triangle)
  44. {
  45. auto context = create_testing_context(64, 64);
  46. glBegin(GL_TRIANGLES);
  47. glColor3f(1, 1, 1);
  48. glVertex2f(0, 1);
  49. glVertex2f(-1, -1);
  50. glVertex2f(1, -1);
  51. glEnd();
  52. EXPECT_EQ(glGetError(), 0u);
  53. context->present();
  54. expect_bitmap_equals_reference(context->frontbuffer(), "0001_simple_triangle"sv);
  55. }
  56. TEST_CASE(0002_quad_color_interpolation)
  57. {
  58. auto context = create_testing_context(64, 64);
  59. glBegin(GL_QUADS);
  60. glColor3f(1, 0, 0);
  61. glVertex2i(-1, -1);
  62. glColor3f(0, 1, 0);
  63. glVertex2i(1, -1);
  64. glColor3f(0, 0, 1);
  65. glVertex2i(1, 1);
  66. glColor3f(1, 0, 1);
  67. glVertex2i(-1, 1);
  68. glEnd();
  69. EXPECT_EQ(glGetError(), 0u);
  70. context->present();
  71. expect_bitmap_equals_reference(context->frontbuffer(), "0002_quad_color_interpolation"sv);
  72. }
  73. TEST_CASE(0003_rect_w_coordinate_regression)
  74. {
  75. auto context = create_testing_context(64, 64);
  76. glEnable(GL_DEPTH_TEST);
  77. glClear(GL_DEPTH_BUFFER_BIT);
  78. glColor3f(0, 1, 0);
  79. glRectf(-0.5f, -0.5f, 0.5f, 0.5f);
  80. glBegin(GL_TRIANGLES);
  81. glColor3f(1, 0, 0);
  82. glVertex2i(-1, -1);
  83. glVertex2i(1, -1);
  84. glVertex2i(-1, 1);
  85. glEnd();
  86. EXPECT_EQ(glGetError(), 0u);
  87. context->present();
  88. expect_bitmap_equals_reference(context->frontbuffer(), "0003_rect_w_coordinate_regression"sv);
  89. }
  90. TEST_CASE(0004_points)
  91. {
  92. auto context = create_testing_context(64, 64);
  93. // Aliased points
  94. for (size_t i = 0; i < 3; ++i) {
  95. glPointSize(1.f + i);
  96. glBegin(GL_POINTS);
  97. glVertex2f(-.5f + i * .5f, .5f);
  98. glEnd();
  99. }
  100. // Anti-aliased points
  101. glEnable(GL_POINT_SMOOTH);
  102. glEnable(GL_BLEND);
  103. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  104. for (size_t i = 0; i < 3; ++i) {
  105. glPointSize(3.f - i);
  106. glBegin(GL_POINTS);
  107. glVertex2f(-.5f + i * .5f, -.5f);
  108. glEnd();
  109. }
  110. EXPECT_EQ(glGetError(), 0u);
  111. context->present();
  112. expect_bitmap_equals_reference(context->frontbuffer(), "0004_points"sv);
  113. }
  114. TEST_CASE(0005_lines_antialiased)
  115. {
  116. auto context = create_testing_context(64, 64);
  117. // Draw anti-aliased lines
  118. glEnable(GL_LINE_SMOOTH);
  119. glEnable(GL_BLEND);
  120. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  121. glBegin(GL_LINES);
  122. for (size_t i = 0; i < 6; ++i) {
  123. glVertex2f(-.9f, .25f - i * .1f);
  124. glVertex2f(.9f, .9f - i * .36f);
  125. }
  126. glEnd();
  127. EXPECT_EQ(glGetError(), 0u);
  128. context->present();
  129. expect_bitmap_equals_reference(context->frontbuffer(), "0005_lines"sv);
  130. }
  131. TEST_CASE(0006_test_rgb565_texture)
  132. {
  133. auto context = create_testing_context(64, 64);
  134. GLuint texture_id;
  135. glGenTextures(1, &texture_id);
  136. glBindTexture(GL_TEXTURE_2D, texture_id);
  137. u16 texture_data[] = { 0xF800, 0xC000, 0x8000, 0x07E0, 0x0600, 0x0400, 0x001F, 0x0018, 0x0010 };
  138. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  139. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 3, 3, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texture_data);
  140. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  141. glEnable(GL_TEXTURE_2D);
  142. glBegin(GL_QUADS);
  143. glTexCoord2i(0, 0);
  144. glVertex2i(-1, 1);
  145. glTexCoord2i(0, 1);
  146. glVertex2i(-1, -1);
  147. glTexCoord2i(1, 1);
  148. glVertex2i(1, -1);
  149. glTexCoord2i(1, 0);
  150. glVertex2i(1, 1);
  151. glEnd();
  152. EXPECT_EQ(glGetError(), 0u);
  153. context->present();
  154. expect_bitmap_equals_reference(context->frontbuffer(), "0006_test_rgb565_texture"sv);
  155. }
  156. TEST_CASE(0007_test_rgba_to_rgb_texture)
  157. {
  158. auto context = create_testing_context(64, 64);
  159. GLuint texture_id;
  160. glGenTextures(1, &texture_id);
  161. glBindTexture(GL_TEXTURE_2D, texture_id);
  162. // Write RGBA data with A = 0 to an RGB texture
  163. u32 texture_data[] = { 0x00FF0000 };
  164. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, texture_data);
  165. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  166. glEnable(GL_TEXTURE_2D);
  167. glBegin(GL_TRIANGLES);
  168. glTexCoord2i(0, 0);
  169. glVertex2i(-1, 1);
  170. glTexCoord2i(0, 1);
  171. glVertex2i(-1, -1);
  172. glTexCoord2i(1, 1);
  173. glVertex2i(1, -1);
  174. glEnd();
  175. EXPECT_EQ(glGetError(), 0u);
  176. context->present();
  177. expect_bitmap_equals_reference(context->frontbuffer(), "0007_test_rgba_to_rgb_texture"sv);
  178. }
  179. TEST_CASE(0008_test_pop_matrix_regression)
  180. {
  181. auto context = create_testing_context(64, 64);
  182. // Load identity matrix after popping
  183. glMatrixMode(GL_MODELVIEW);
  184. glTranslatef(10.f, 10.f, 10.f);
  185. glPushMatrix();
  186. glPopMatrix();
  187. glLoadIdentity();
  188. glBegin(GL_TRIANGLES);
  189. glColor3f(0.f, 1.f, 0.f);
  190. glVertex2f(.5f, -.5f);
  191. glVertex2f(.0f, .5f);
  192. glVertex2f(-.5f, -.5f);
  193. glEnd();
  194. EXPECT_EQ(glGetError(), 0u);
  195. context->present();
  196. expect_bitmap_equals_reference(context->frontbuffer(), "0008_test_pop_matrix_regression"sv);
  197. }
  198. TEST_CASE(0009_test_draw_elements_in_display_list)
  199. {
  200. auto context = create_testing_context(64, 64);
  201. glColor3f(0.f, 0.f, 1.f);
  202. glEnableClientState(GL_VERTEX_ARRAY);
  203. auto const list_index = glGenLists(1);
  204. glNewList(list_index, GL_COMPILE);
  205. float vertices[] = { 0.f, .5f, -.5f, -.5f, .5f, -.5f };
  206. glVertexPointer(2, GL_FLOAT, 0, &vertices);
  207. u8 indices[] = { 0, 1, 2 };
  208. glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, &indices);
  209. glEndList();
  210. // Modifying an index here should not have an effect
  211. indices[0] = 2;
  212. glCallList(list_index);
  213. EXPECT_EQ(glGetError(), 0u);
  214. context->present();
  215. expect_bitmap_equals_reference(context->frontbuffer(), "0009_test_draw_elements_in_display_list"sv);
  216. }
  217. TEST_CASE(0010_test_store_data_in_buffer)
  218. {
  219. auto context = create_testing_context(64, 64);
  220. glColor3f(1.f, 0.f, 0.f);
  221. glEnableClientState(GL_VERTEX_ARRAY);
  222. float vertices[] = { 0.f, .5f, -.5f, -.5f, .5f, -.5f };
  223. u8 indices[] = { 0, 1, 2 };
  224. GLuint buffers[2];
  225. glGenBuffers(2, buffers);
  226. glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
  227. glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), vertices, GL_STATIC_DRAW);
  228. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
  229. glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3, indices, GL_STATIC_DRAW);
  230. glVertexPointer(2, GL_FLOAT, 0, 0);
  231. glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, 0);
  232. glDeleteBuffers(2, buffers);
  233. EXPECT_EQ(glGetError(), 0u);
  234. context->present();
  235. expect_bitmap_equals_reference(context->frontbuffer(), "0010_test_store_data_in_buffer"sv);
  236. }