mirror of
https://github.com/RGBCube/serenity
synced 2025-05-29 14:05:11 +00:00

According to the spec, pointers to client data need to be dereferenced immediately when adding calls such as `glDrawElements` or `glArrayElement` to a display list. We were trying to support display lists for these calls but since they only invoke _other_ calls that also support display lists, we can simply defer the display list functionality to them. This fixes the rendering of the ClassiCube port by cflip.
280 lines
7.4 KiB
C++
280 lines
7.4 KiB
C++
/*
|
|
* Copyright (c) 2021, Leon Albrecht <leon2002.la@gmail.com>
|
|
* Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/LexicalPath.h>
|
|
#include <AK/String.h>
|
|
#include <LibCore/FileStream.h>
|
|
#include <LibGL/GL/gl.h>
|
|
#include <LibGL/GLContext.h>
|
|
#include <LibGfx/Bitmap.h>
|
|
#include <LibGfx/QOIWriter.h>
|
|
#include <LibTest/TestCase.h>
|
|
|
|
#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<GL::GLContext> create_testing_context(int width, int height)
|
|
{
|
|
auto bitmap = MUST(Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRx8888, { width, height }));
|
|
auto context = MUST(GL::create_context(*bitmap));
|
|
GL::make_context_current(context);
|
|
|
|
// Assume some defaults for our testing contexts
|
|
glFrontFace(GL_CCW);
|
|
glCullFace(GL_BACK);
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
return context;
|
|
}
|
|
|
|
static void expect_bitmap_equals_reference(Gfx::Bitmap const& bitmap, StringView test_name)
|
|
{
|
|
auto reference_filename = String::formatted("{}.qoi", test_name);
|
|
|
|
if constexpr (SAVE_OUTPUT) {
|
|
auto target_path = LexicalPath("/home/anon").append(reference_filename);
|
|
auto qoi_buffer = Gfx::QOIWriter::encode(bitmap);
|
|
auto qoi_output_stream = MUST(Core::OutputFileStream::open(target_path.string()));
|
|
auto number_of_bytes_written = qoi_output_stream.write(qoi_buffer);
|
|
qoi_output_stream.close();
|
|
EXPECT_EQ(number_of_bytes_written, qoi_buffer.size());
|
|
}
|
|
|
|
auto reference_image_path = String::formatted(REFERENCE_IMAGE_DIR "/{}", reference_filename);
|
|
auto reference_bitmap = MUST(Gfx::Bitmap::try_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);
|
|
}
|