Coverage Report

Created: 2026-02-16 07:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibWeb/WebGL/OpenGLContext.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <AK/OwnPtr.h>
8
#include <LibGfx/Bitmap.h>
9
#include <LibWeb/WebGL/OpenGLContext.h>
10
11
#ifdef HAS_ACCELERATED_GRAPHICS
12
#    include <LibAccelGfx/Canvas.h>
13
#    include <LibAccelGfx/Context.h>
14
#elif defined(AK_OS_SERENITY)
15
#    include <LibGL/GLContext.h>
16
#endif
17
18
namespace Web::WebGL {
19
20
#ifdef HAS_ACCELERATED_GRAPHICS
21
class AccelGfxContext : public OpenGLContext {
22
public:
23
    void activate()
24
    {
25
        m_context->activate();
26
    }
27
28
    virtual void present(Gfx::Bitmap& bitmap) override
29
    {
30
        VERIFY(bitmap.format() == Gfx::BitmapFormat::BGRA8888);
31
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
32
        glReadPixels(0, 0, bitmap.width(), bitmap.height(), GL_BGRA, GL_UNSIGNED_BYTE, bitmap.scanline(0));
33
    }
34
35
    virtual GLenum gl_get_error() override
36
    {
37
        activate();
38
        return glGetError();
39
    }
40
41
    virtual void gl_get_doublev(GLenum pname, GLdouble* params) override
42
    {
43
        activate();
44
        glGetDoublev(pname, params);
45
    }
46
47
    virtual void gl_get_integerv(GLenum pname, GLint* params) override
48
    {
49
        activate();
50
        glGetIntegerv(pname, params);
51
    }
52
53
    virtual void gl_clear(GLbitfield mask) override
54
    {
55
        activate();
56
        glClear(mask);
57
    }
58
59
    virtual void gl_clear_color(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) override
60
    {
61
        activate();
62
        glClearColor(red, green, blue, alpha);
63
    }
64
65
    virtual void gl_clear_depth(GLdouble depth) override
66
    {
67
        activate();
68
        glClearDepth(depth);
69
    }
70
71
    virtual void gl_clear_stencil(GLint s) override
72
    {
73
        activate();
74
        glClearStencil(s);
75
    }
76
77
    virtual void gl_active_texture(GLenum texture) override
78
    {
79
        activate();
80
        glActiveTexture(texture);
81
    }
82
83
    virtual void gl_viewport(GLint x, GLint y, GLsizei width, GLsizei height) override
84
    {
85
        activate();
86
        glViewport(x, y, width, height);
87
    }
88
89
    virtual void gl_line_width(GLfloat width) override
90
    {
91
        activate();
92
        glLineWidth(width);
93
    }
94
95
    virtual void gl_polygon_offset(GLfloat factor, GLfloat units) override
96
    {
97
        activate();
98
        glPolygonOffset(factor, units);
99
    }
100
101
    virtual void gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height) override
102
    {
103
        activate();
104
        glScissor(x, y, width, height);
105
    }
106
107
    virtual void gl_depth_mask(GLboolean mask) override
108
    {
109
        activate();
110
        glDepthMask(mask);
111
    }
112
113
    virtual void gl_depth_func(GLenum func) override
114
    {
115
        activate();
116
        glDepthFunc(func);
117
    }
118
119
    virtual void gl_depth_range(GLdouble z_near, GLdouble z_far) override
120
    {
121
        activate();
122
        glDepthRange(z_near, z_far);
123
    }
124
125
    virtual void gl_cull_face(GLenum mode) override
126
    {
127
        activate();
128
        glCullFace(mode);
129
    }
130
131
    virtual void gl_color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) override
132
    {
133
        activate();
134
        glColorMask(red, green, blue, alpha);
135
    }
136
137
    virtual void gl_front_face(GLenum mode) override
138
    {
139
        activate();
140
        glFrontFace(mode);
141
    }
142
143
    virtual void gl_finish() override
144
    {
145
        activate();
146
        glFinish();
147
    }
148
149
    virtual void gl_flush() override
150
    {
151
        activate();
152
        glFlush();
153
    }
154
155
    virtual void gl_stencil_op_separate(GLenum, GLenum, GLenum, GLenum) override
156
    {
157
        TODO();
158
    }
159
160
    AccelGfxContext(NonnullOwnPtr<AccelGfx::Context> context, NonnullRefPtr<AccelGfx::Canvas> canvas)
161
        : m_context(move(context))
162
        , m_canvas(move(canvas))
163
    {
164
    }
165
166
    ~AccelGfxContext()
167
    {
168
        activate();
169
    }
170
171
private:
172
    NonnullOwnPtr<AccelGfx::Context> m_context;
173
    NonnullRefPtr<AccelGfx::Canvas> m_canvas;
174
};
175
#endif
176
177
#ifdef AK_OS_SERENITY
178
class LibGLContext : public OpenGLContext {
179
public:
180
    virtual void present(Gfx::Bitmap&) override
181
    {
182
        m_context->present();
183
    }
184
185
    virtual GLenum gl_get_error() override
186
    {
187
        return m_context->gl_get_error();
188
    }
189
190
    virtual void gl_get_doublev(GLenum pname, GLdouble* params) override
191
    {
192
        m_context->gl_get_doublev(pname, params);
193
    }
194
195
    virtual void gl_get_integerv(GLenum pname, GLint* params) override
196
    {
197
        m_context->gl_get_integerv(pname, params);
198
    }
199
200
    virtual void gl_clear(GLbitfield mask) override
201
    {
202
        m_context->gl_clear(mask);
203
    }
204
205
    virtual void gl_clear_color(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) override
206
    {
207
        m_context->gl_clear_color(red, green, blue, alpha);
208
    }
209
210
    virtual void gl_clear_depth(GLdouble depth) override
211
    {
212
        m_context->gl_clear_depth(depth);
213
    }
214
215
    virtual void gl_clear_stencil(GLint s) override
216
    {
217
        m_context->gl_clear_stencil(s);
218
    }
219
220
    virtual void gl_active_texture(GLenum texture) override
221
    {
222
        m_context->gl_active_texture(texture);
223
    }
224
225
    virtual void gl_viewport(GLint x, GLint y, GLsizei width, GLsizei height) override
226
    {
227
        m_context->gl_viewport(x, y, width, height);
228
    }
229
230
    virtual void gl_line_width(GLfloat width) override
231
    {
232
        m_context->gl_line_width(width);
233
    }
234
235
    virtual void gl_polygon_offset(GLfloat factor, GLfloat units) override
236
    {
237
        m_context->gl_polygon_offset(factor, units);
238
    }
239
240
    virtual void gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height) override
241
    {
242
        m_context->gl_scissor(x, y, width, height);
243
    }
244
245
    virtual void gl_depth_mask(GLboolean flag) override
246
    {
247
        m_context->gl_depth_mask(flag);
248
    }
249
250
    virtual void gl_depth_func(GLenum func) override
251
    {
252
        m_context->gl_depth_func(func);
253
    }
254
255
    virtual void gl_depth_range(GLdouble z_near, GLdouble z_far) override
256
    {
257
        m_context->gl_depth_range(z_near, z_far);
258
    }
259
260
    virtual void gl_cull_face(GLenum mode) override
261
    {
262
        m_context->gl_cull_face(mode);
263
    }
264
265
    virtual void gl_color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) override
266
    {
267
        m_context->gl_color_mask(red, green, blue, alpha);
268
    }
269
270
    virtual void gl_front_face(GLenum mode) override
271
    {
272
        m_context->gl_front_face(mode);
273
    }
274
275
    virtual void gl_finish() override
276
    {
277
        m_context->gl_finish();
278
    }
279
280
    virtual void gl_flush() override
281
    {
282
        m_context->gl_flush();
283
    }
284
285
    virtual void gl_stencil_op_separate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) override
286
    {
287
        m_context->gl_stencil_op_separate(face, sfail, dpfail, dppass);
288
    }
289
290
    LibGLContext(OwnPtr<GL::GLContext> context)
291
        : m_context(move(context))
292
    {
293
    }
294
295
private:
296
    OwnPtr<GL::GLContext> m_context;
297
};
298
#endif
299
300
#ifdef HAS_ACCELERATED_GRAPHICS
301
static OwnPtr<AccelGfxContext> make_accelgfx_context(Gfx::Bitmap& bitmap)
302
{
303
    auto context = AccelGfx::Context::create();
304
    if (context.is_error()) {
305
        dbgln("Failed to create AccelGfx context: {}", context.error().string_literal());
306
        return {};
307
    }
308
    auto canvas = AccelGfx::Canvas::create(bitmap.size());
309
    canvas->bind();
310
    return make<AccelGfxContext>(context.release_value(), move(canvas));
311
}
312
#endif
313
314
#ifdef AK_OS_SERENITY
315
static OwnPtr<LibGLContext> make_libgl_context(Gfx::Bitmap& bitmap)
316
{
317
    auto context_or_error = GL::create_context(bitmap);
318
    return make<LibGLContext>(move(context_or_error.value()));
319
}
320
#endif
321
322
OwnPtr<OpenGLContext> OpenGLContext::create(Gfx::Bitmap& bitmap)
323
0
{
324
#ifdef HAS_ACCELERATED_GRAPHICS
325
    return make_accelgfx_context(bitmap);
326
#elif defined(AK_OS_SERENITY)
327
    return make_libgl_context(bitmap);
328
#endif
329
330
0
    (void)bitmap;
331
0
    return {};
332
0
}
333
334
void OpenGLContext::clear_buffer_to_default_values()
335
0
{
336
#if defined(HAS_ACCELERATED_GRAPHICS) || defined(AK_OS_SERENITY)
337
    Array<GLdouble, 4> current_clear_color;
338
    gl_get_doublev(GL_COLOR_CLEAR_VALUE, current_clear_color.data());
339
340
    GLdouble current_clear_depth;
341
    gl_get_doublev(GL_DEPTH_CLEAR_VALUE, &current_clear_depth);
342
343
    GLint current_clear_stencil;
344
    gl_get_integerv(GL_STENCIL_CLEAR_VALUE, &current_clear_stencil);
345
346
    // The implicit clear value for the color buffer is (0, 0, 0, 0)
347
    gl_clear_color(0, 0, 0, 0);
348
349
    // The implicit clear value for the depth buffer is 1.0.
350
    gl_clear_depth(1.0);
351
352
    // The implicit clear value for the stencil buffer is 0.
353
    gl_clear_stencil(0);
354
355
    gl_clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
356
357
    // Restore the clear values.
358
    gl_clear_color(current_clear_color[0], current_clear_color[1], current_clear_color[2], current_clear_color[3]);
359
    gl_clear_depth(current_clear_depth);
360
    gl_clear_stencil(current_clear_stencil);
361
#endif
362
0
}
363
364
}