Serenity Operating System
1/*
2 * Copyright (c) 2022, Luke Wilde <lukew@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <LibGL/GL/gl.h>
8#include <LibGL/GLContext.h>
9#include <LibTest/TestCase.h>
10
11static NonnullOwnPtr<GL::GLContext> create_testing_context()
12{
13 auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, { 1, 1 }));
14 auto context = MUST(GL::create_context(*bitmap));
15 GL::make_context_current(context);
16 return context;
17}
18
19TEST_CASE(0001_gl_gen_textures_does_not_return_the_same_texture_name_twice_unless_deleted)
20{
21 // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGenTextures.xhtml
22 // "Texture names returned by a call to glGenTextures are not returned by subsequent calls, unless they are first deleted with glDeleteTextures."
23 auto context = create_testing_context();
24
25 GLuint texture1 = 0;
26 GLuint texture2 = 0;
27
28 glGenTextures(1, &texture1);
29
30 // glDeleteTextures previously did not check that the texture name was allocated by glGenTextures before adding it to the free texture name list.
31 // This means that if you delete a texture twice in a row, the name will appear twice in the free texture list, making glGenTextures return the
32 // same texture name twice in a row.
33 glDeleteTextures(1, &texture1);
34 glDeleteTextures(1, &texture1);
35
36 texture1 = 0;
37
38 glGenTextures(1, &texture1);
39 glGenTextures(1, &texture2);
40
41 EXPECT_NE(texture1, texture2);
42}
43
44TEST_CASE(0002_gl_cull_face_does_not_accept_left_and_right)
45{
46 auto context = create_testing_context();
47
48 // glCullFace only accepts GL_FRONT, GL_BACK and GL_FRONT_AND_BACK. We checked if the mode was valid by performing cull_mode < GL_FRONT || cull_mode > GL_FRONT_AND_BACK.
49 // However, this range also contains GL_LEFT and GL_RIGHT, which we would accept when we should return a GL_INVALID_ENUM error.
50 glCullFace(GL_LEFT);
51 EXPECT_EQ(glGetError(), static_cast<GLenum>(GL_INVALID_ENUM));
52
53 glCullFace(GL_RIGHT);
54 EXPECT_EQ(glGetError(), static_cast<GLenum>(GL_INVALID_ENUM));
55}
56
57TEST_CASE(0003_gl_bind_buffer_names_must_be_allocated)
58{
59 auto context = create_testing_context();
60
61 glBindBuffer(GL_ARRAY_BUFFER, 123);
62 EXPECT_EQ(glGetError(), static_cast<GLenum>(GL_INVALID_VALUE));
63}
64
65TEST_CASE(0004_gl_color_clear_value)
66{
67 auto context = create_testing_context();
68
69 Array<GLdouble, 4> clear_color;
70 glGetDoublev(GL_COLOR_CLEAR_VALUE, clear_color.data());
71 EXPECT_EQ(clear_color[0], 0.);
72 EXPECT_EQ(clear_color[1], 0.);
73 EXPECT_EQ(clear_color[2], 0.);
74 EXPECT_EQ(clear_color[3], 0.);
75
76 glClearColor(.1f, .2f, .3f, .4f);
77
78 glGetDoublev(GL_COLOR_CLEAR_VALUE, clear_color.data());
79 EXPECT_APPROXIMATE(clear_color[0], .1);
80 EXPECT_APPROXIMATE(clear_color[1], .2);
81 EXPECT_APPROXIMATE(clear_color[2], .3);
82 EXPECT_APPROXIMATE(clear_color[3], .4);
83}
84
85TEST_CASE(0005_gl_depth_clear_value)
86{
87 auto context = create_testing_context();
88
89 GLdouble clear_depth;
90 glGetDoublev(GL_DEPTH_CLEAR_VALUE, &clear_depth);
91 EXPECT_EQ(clear_depth, 1.);
92
93 glClearDepth(.1f);
94
95 glGetDoublev(GL_DEPTH_CLEAR_VALUE, &clear_depth);
96 EXPECT_APPROXIMATE(clear_depth, .1);
97}
98
99TEST_CASE(0006_gl_stencil_clear_value)
100{
101 auto context = create_testing_context();
102
103 GLint clear_stencil;
104 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &clear_stencil);
105 EXPECT_EQ(clear_stencil, 0);
106
107 glClearStencil(255);
108
109 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &clear_stencil);
110 EXPECT_EQ(clear_stencil, 255);
111}