Bug Summary

File:root/firefox-clang/gfx/wr/swgl/src/gl.cc
Warning:line 773, column 8
Excessive padding in 'struct Context' (38 padding bytes, where 6 is optimal). Optimal fields order: blendcolor, cleardepth, queries, framebuffers, renderbuffers, shaders, buffers, programs, textures, vertex_arrays, references, last_error, blendfunc_srgb, blendfunc_drgb, blendfunc_sa, blendfunc_da, blend_equation, depthfunc, unpack_row_length, shaded_rows, shaded_pixels, active_texture_unit, current_program, current_vertex_array, pixel_pack_buffer_binding, pixel_unpack_buffer_binding, array_buffer_binding, time_elapsed_query, samples_passed_query, renderbuffer_binding, draw_framebuffer_binding, read_framebuffer_binding, unknown_binding, viewport, scissor, clearcolor, texture_units, blend, blend_key, depthtest, depthmask, scissortest, validate_vertex_array, consider reordering the fields or adding explicit padding members

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name gl.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -fapprox-func -funsafe-math-optimizations -fno-signed-zeros -mreassociate -freciprocal-math -ffp-contract=fast -fno-rounding-math -mrecip=none -complex-range=basic -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/gfx/wr/swgl -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/root/firefox-clang/gfx/wr/swgl -resource-dir /usr/lib/llvm-21/lib/clang/21 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/gfx/wr/swgl/../webrender/res -I src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/x86_64-unknown-linux-gnu/debug/build/swgl-19ea748e17a3c52a/out -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -D MOZILLA_CONFIG_H -U MOZILLA_CONFIG_H -D _GLIBCXX_USE_CXX11_ABI=0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -std=c++17 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-06-27-100320-3286336-1 -x c++ src/gl.cc
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include <stdlib.h>
6#include <stdint.h>
7#include <string.h>
8#include <assert.h>
9#include <stdio.h>
10#include <math.h>
11
12#ifdef __MACH__
13# include <mach/mach.h>
14# include <mach/mach_time.h>
15#else
16# include <time.h>
17#endif
18
19#ifdef NDEBUG
20# define debugf(...)printf(...)
21#else
22# define debugf(...)printf(...) printf(__VA_ARGS__)
23#endif
24
25// #define PRINT_TIMINGS
26
27#ifdef _WIN32
28# define ALWAYS_INLINE__attribute__((always_inline)) inline __forceinline
29# define NO_INLINE__attribute__((noinline)) __declspec(noinline)
30
31// Including Windows.h brings a huge amount of namespace polution so just
32// define a couple of things manually
33typedef int BOOL;
34# define WINAPI __stdcall
35# define DECLSPEC_IMPORT __declspec(dllimport)
36# define WINBASEAPI DECLSPEC_IMPORT
37typedef unsigned long DWORD;
38typedef long LONG;
39typedef __int64 LONGLONG;
40# define DUMMYSTRUCTNAME
41
42typedef union _LARGE_INTEGER {
43 struct {
44 DWORD LowPart;
45 LONG HighPart;
46 } DUMMYSTRUCTNAME;
47 struct {
48 DWORD LowPart;
49 LONG HighPart;
50 } u;
51 LONGLONG QuadPart;
52} LARGE_INTEGER;
53extern "C" {
54WINBASEAPI BOOL WINAPI
55QueryPerformanceCounter(LARGE_INTEGER* lpPerformanceCount);
56
57WINBASEAPI BOOL WINAPI QueryPerformanceFrequency(LARGE_INTEGER* lpFrequency);
58}
59
60#else
61// GCC is slower when dealing with always_inline, especially in debug builds.
62// When using Clang, use always_inline more aggressively.
63# if defined(__clang__1) || defined(NDEBUG)
64# define ALWAYS_INLINE__attribute__((always_inline)) inline __attribute__((always_inline)) inline
65# else
66# define ALWAYS_INLINE__attribute__((always_inline)) inline inline
67# endif
68# define NO_INLINE__attribute__((noinline)) __attribute__((noinline))
69#endif
70
71// Some functions may cause excessive binary bloat if inlined in debug or with
72// GCC builds, so use PREFER_INLINE on these instead of ALWAYS_INLINE.
73#if defined(__clang__1) && defined(NDEBUG)
74# define PREFER_INLINEinline ALWAYS_INLINE__attribute__((always_inline)) inline
75#else
76# define PREFER_INLINEinline inline
77#endif
78
79#define UNREACHABLE__builtin_unreachable() __builtin_unreachable()
80
81#define UNUSED[[maybe_unused]] [[maybe_unused]]
82
83#define FALLTHROUGH[[fallthrough]] [[fallthrough]]
84
85#if defined(MOZILLA_CLIENT1) && defined(MOZ_CLANG_PLUGIN)
86# define IMPLICIT __attribute__((annotate("moz_implicit")))
87#else
88# define IMPLICIT
89#endif
90
91#include "gl_defs.h"
92#include "glsl.h"
93#include "program.h"
94#include "texture.h"
95
96using namespace glsl;
97
98typedef ivec2_scalar IntPoint;
99
100struct IntRect {
101 int x0;
102 int y0;
103 int x1;
104 int y1;
105
106 IntRect() : x0(0), y0(0), x1(0), y1(0) {}
107 IntRect(int x0, int y0, int x1, int y1) : x0(x0), y0(y0), x1(x1), y1(y1) {}
108 IntRect(IntPoint origin, IntPoint size)
109 : x0(origin.x),
110 y0(origin.y),
111 x1(origin.x + size.x),
112 y1(origin.y + size.y) {}
113
114 int width() const { return x1 - x0; }
115 int height() const { return y1 - y0; }
116 bool is_empty() const { return width() <= 0 || height() <= 0; }
117
118 IntPoint origin() const { return IntPoint(x0, y0); }
119
120 bool same_size(const IntRect& o) const {
121 return width() == o.width() && height() == o.height();
122 }
123
124 bool contains(const IntRect& o) const {
125 return o.x0 >= x0 && o.y0 >= y0 && o.x1 <= x1 && o.y1 <= y1;
126 }
127
128 IntRect& intersect(const IntRect& o) {
129 x0 = max(x0, o.x0);
130 y0 = max(y0, o.y0);
131 x1 = min(x1, o.x1);
132 y1 = min(y1, o.y1);
133 return *this;
134 }
135
136 IntRect intersection(const IntRect& o) {
137 IntRect result = *this;
138 result.intersect(o);
139 return result;
140 }
141
142 // Scale from source-space to dest-space, optionally rounding inward
143 IntRect& scale(int srcWidth, int srcHeight, int dstWidth, int dstHeight,
144 bool roundIn = false) {
145 x0 = (x0 * dstWidth + (roundIn ? srcWidth - 1 : 0)) / srcWidth;
146 y0 = (y0 * dstHeight + (roundIn ? srcHeight - 1 : 0)) / srcHeight;
147 x1 = (x1 * dstWidth) / srcWidth;
148 y1 = (y1 * dstHeight) / srcHeight;
149 return *this;
150 }
151
152 // Flip the rect's Y coords around inflection point at Y=offset
153 void invert_y(int offset) {
154 y0 = offset - y0;
155 y1 = offset - y1;
156 swap(y0, y1);
157 }
158
159 IntRect& offset(const IntPoint& o) {
160 x0 += o.x;
161 y0 += o.y;
162 x1 += o.x;
163 y1 += o.y;
164 return *this;
165 }
166
167 IntRect operator+(const IntPoint& o) const {
168 return IntRect(*this).offset(o);
169 }
170 IntRect operator-(const IntPoint& o) const {
171 return IntRect(*this).offset(-o);
172 }
173};
174
175typedef vec2_scalar Point2D;
176typedef vec4_scalar Point3D;
177
178struct IntRange {
179 int start;
180 int end;
181
182 int len() const { return end - start; }
183
184 IntRange intersect(IntRange r) const {
185 return {max(start, r.start), min(end, r.end)};
186 }
187};
188
189struct FloatRange {
190 float start;
191 float end;
192
193 float clip(float x) const { return clamp(x, start, end); }
194
195 FloatRange clip(FloatRange r) const { return {clip(r.start), clip(r.end)}; }
196
197 FloatRange merge(FloatRange r) const {
198 return {min(start, r.start), max(end, r.end)};
199 }
200
201 IntRange round__glsl_round() const {
202 return {int(floor__glsl_floor(start + 0.5f)), int(floor__glsl_floor(end + 0.5f))};
203 }
204
205 IntRange round_out() const { return {int(floor__glsl_floor(start)), int(ceil__glsl_ceil(end))}; }
206};
207
208template <typename P>
209static inline FloatRange x_range(P p0, P p1) {
210 return {min(p0.x, p1.x), max(p0.x, p1.x)};
211}
212
213struct VertexAttrib {
214 size_t size = 0; // in bytes
215 GLenum type = 0;
216 bool normalized = false;
217 GLsizei stride = 0;
218 GLuint offset = 0;
219 bool enabled = false;
220 GLuint divisor = 0;
221 int vertex_array = 0;
222 int vertex_buffer = 0;
223 char* buf = nullptr; // XXX: this can easily dangle
224 size_t buf_size = 0; // this will let us bounds check
225
226 // Mark the buffer as invalid so we don't accidentally use stale data.
227 void disable() {
228 enabled = false;
229 buf = nullptr;
230 buf_size = 0;
231 }
232};
233
234static int bytes_for_internal_format(GLenum internal_format) {
235 switch (internal_format) {
236 case GL_RGBA32F0x8814:
237 return 4 * 4;
238 case GL_RGBA32I0x8D82:
239 case GL_RGBA_INTEGER0x8D99:
240 return 4 * 4;
241 case GL_RGBA80x8058:
242 case GL_BGRA80x93A1:
243 case GL_RGBA0x1908:
244 case GL_BGRA0x80E1:
245 return 4;
246 case GL_R80x8229:
247 case GL_RED0x1903:
248 return 1;
249 case GL_RG80x822B:
250 case GL_RG0x8227:
251 return 2;
252 case GL_DEPTH_COMPONENT0x1902:
253 case GL_DEPTH_COMPONENT160x81A5:
254 case GL_DEPTH_COMPONENT240x81A6:
255 case GL_DEPTH_COMPONENT320x81A7:
256 return 4;
257 case GL_RGB_RAW_422_APPLE0x8A51:
258 return 2;
259 case GL_R160x822A:
260 return 2;
261 case GL_RG160x822C:
262 return 4;
263 default:
264 debugf("internal format: %x\n", internal_format)printf("internal format: %x\n", internal_format);
265 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
266 return 0;
267 }
268}
269
270static inline int aligned_stride(int row_bytes) { return (row_bytes + 3) & ~3; }
271
272static TextureFormat gl_format_to_texture_format(int type) {
273 switch (type) {
274 case GL_RGBA32F0x8814:
275 return TextureFormat::RGBA32F;
276 case GL_RGBA32I0x8D82:
277 return TextureFormat::RGBA32I;
278 case GL_RGBA80x8058:
279 return TextureFormat::RGBA8;
280 case GL_R80x8229:
281 return TextureFormat::R8;
282 case GL_RG80x822B:
283 return TextureFormat::RG8;
284 case GL_R160x822A:
285 return TextureFormat::R16;
286 case GL_RG160x822C:
287 return TextureFormat::RG16;
288 case GL_RGB_RAW_422_APPLE0x8A51:
289 return TextureFormat::YUY2;
290 default:
291 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
292 return TextureFormat::RGBA8;
293 }
294}
295
296struct Query {
297 uint64_t value = 0;
298};
299
300struct Buffer {
301 char* buf = nullptr;
302 size_t size = 0;
303 size_t capacity = 0;
304
305 // Returns true if re-allocation succeeded, false otherwise...
306 bool allocate(size_t new_size) {
307 // If the size remains unchanged, don't allocate anything.
308 if (new_size == size) {
309 return true;
310 }
311 // If the new size is within the existing capacity of the buffer, just
312 // reuse the existing buffer.
313 if (new_size <= capacity) {
314 size = new_size;
315 return true;
316 }
317 // Otherwise we need to reallocate the buffer to hold up to the requested
318 // larger size.
319 char* new_buf = (char*)realloc(buf, new_size);
320 assert(new_buf)(static_cast <bool> (new_buf) ? void (0) : __assert_fail
("new_buf", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
321 if (!new_buf) {
322 // If we fail, null out the buffer rather than leave around the old
323 // allocation state.
324 cleanup();
325 return false;
326 }
327 // The reallocation succeeded, so install the buffer.
328 buf = new_buf;
329 size = new_size;
330 capacity = new_size;
331 return true;
332 }
333
334 void cleanup() {
335 if (buf) {
336 free(buf);
337 buf = nullptr;
338 size = 0;
339 capacity = 0;
340 }
341 }
342
343 ~Buffer() { cleanup(); }
344
345 char* end_ptr() const { return buf ? buf + size : nullptr; }
346
347 void* get_data(void* data) {
348 if (buf) {
349 size_t offset = (size_t)data;
350 if (offset < size) {
351 return buf + offset;
352 }
353 }
354 return nullptr;
355 }
356};
357
358struct Framebuffer {
359 GLuint color_attachment = 0;
360 GLuint depth_attachment = 0;
361};
362
363struct Renderbuffer {
364 GLuint texture = 0;
365
366 void on_erase();
367};
368
369TextureFilter gl_filter_to_texture_filter(int type) {
370 switch (type) {
371 case GL_NEAREST0x2600:
372 return TextureFilter::NEAREST;
373 case GL_NEAREST_MIPMAP_LINEAR0x2702:
374 return TextureFilter::NEAREST;
375 case GL_NEAREST_MIPMAP_NEAREST0x2700:
376 return TextureFilter::NEAREST;
377 case GL_LINEAR0x2601:
378 return TextureFilter::LINEAR;
379 case GL_LINEAR_MIPMAP_LINEAR0x2703:
380 return TextureFilter::LINEAR;
381 case GL_LINEAR_MIPMAP_NEAREST0x2701:
382 return TextureFilter::LINEAR;
383 default:
384 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
385 return TextureFilter::NEAREST;
386 }
387}
388
389struct Texture {
390 GLenum internal_format = 0;
391 int width = 0;
392 int height = 0;
393 char* buf = nullptr;
394 size_t buf_size = 0;
395 uint32_t buf_stride = 0;
396 uint8_t buf_bpp = 0;
397 GLenum min_filter = GL_NEAREST0x2600;
398 GLenum mag_filter = GL_LINEAR0x2601;
399 // The number of active locks on this texture. If this texture has any active
400 // locks, we need to disallow modifying or destroying the texture as it may
401 // be accessed by other threads where modifications could lead to races.
402 int32_t locked = 0;
403 // When used as an attachment of a framebuffer, rendering to the texture
404 // behaves as if it is located at the given offset such that the offset is
405 // subtracted from all transformed vertexes after the viewport is applied.
406 IntPoint offset;
407
408 enum FLAGS {
409 // If the buffer is internally-allocated by SWGL
410 SHOULD_FREE = 1 << 1,
411 // If the buffer has been cleared to initialize it. Currently this is only
412 // utilized by depth buffers which need to know when depth runs have reset
413 // to a valid row state. When unset, the depth runs may contain garbage.
414 CLEARED = 1 << 2,
415 // The texture was deleted while still locked and must stay alive until all
416 // locks are released.
417 ZOMBIE = 1 << 3,
418 };
419 int flags = SHOULD_FREE;
420 bool should_free() const { return bool(flags & SHOULD_FREE); }
421 bool cleared() const { return bool(flags & CLEARED); }
422 bool zombie() const { return bool(flags & ZOMBIE); }
423
424 void set_flag(int flag, bool val) {
425 if (val) {
426 flags |= flag;
427 } else {
428 flags &= ~flag;
429 }
430 }
431 void set_should_free(bool val) {
432 // buf must be null before SHOULD_FREE can be safely toggled. Otherwise, we
433 // might accidentally mistakenly realloc an externally allocated buffer as
434 // if it were an internally allocated one.
435 assert(!buf)(static_cast <bool> (!buf) ? void (0) : __assert_fail (
"!buf", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
436 set_flag(SHOULD_FREE, val);
437 }
438 void set_cleared(bool val) { set_flag(CLEARED, val); }
439 void set_zombie(bool val) { set_flag(ZOMBIE, val); }
440
441 // Delayed-clearing state. When a clear of an FB is requested, we don't
442 // immediately clear each row, as the rows may be subsequently overwritten
443 // by draw calls, allowing us to skip the work of clearing the affected rows
444 // either fully or partially. Instead, we keep a bit vector of rows that need
445 // to be cleared later and save the value they need to be cleared with so
446 // that we can clear these rows individually when they are touched by draws.
447 // This currently only works for 2D textures, but not on texture arrays.
448 int delay_clear = 0;
449 uint32_t clear_val = 0;
450 uint32_t* cleared_rows = nullptr;
451
452 void init_depth_runs(uint32_t z);
453 void fill_depth_runs(uint32_t z, const IntRect& scissor);
454
455 void enable_delayed_clear(uint32_t val) {
456 delay_clear = height;
457 clear_val = val;
458 if (!cleared_rows) {
459 cleared_rows = new uint32_t[(height + 31) / 32];
460 }
461 memset(cleared_rows, 0, ((height + 31) / 32) * sizeof(uint32_t));
462 if (height & 31) {
463 cleared_rows[height / 32] = ~0U << (height & 31);
464 }
465 }
466
467 void disable_delayed_clear() {
468 if (cleared_rows) {
469 delete[] cleared_rows;
470 cleared_rows = nullptr;
471 delay_clear = 0;
472 }
473 }
474
475 int bpp() const { return buf_bpp; }
476 int compute_bpp() const { return bytes_for_internal_format(internal_format); }
477
478 size_t stride() const { return buf_stride; }
479 size_t compute_stride(int bpp, int width) const {
480 return aligned_stride(bpp * width);
481 }
482
483 // Set an external backing buffer of this texture.
484 void set_buffer(void* new_buf, size_t new_stride) {
485 assert(!should_free())(static_cast <bool> (!should_free()) ? void (0) : __assert_fail
("!should_free()", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
486 // Ensure that the supplied stride is at least as big as the row data and
487 // is aligned to the smaller of either the BPP or word-size. We need to at
488 // least be able to sample data from within a row and sample whole pixels
489 // of smaller formats without risking unaligned access.
490 int new_bpp = compute_bpp();
491 assert(new_stride >= size_t(new_bpp * width) &&(static_cast <bool> (new_stride >= size_t(new_bpp * width
) && new_stride % min(new_bpp, sizeof(uint32_t)) == 0
) ? void (0) : __assert_fail ("new_stride >= size_t(new_bpp * width) && new_stride % min(new_bpp, sizeof(uint32_t)) == 0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
492 new_stride % min(new_bpp, sizeof(uint32_t)) == 0)(static_cast <bool> (new_stride >= size_t(new_bpp * width
) && new_stride % min(new_bpp, sizeof(uint32_t)) == 0
) ? void (0) : __assert_fail ("new_stride >= size_t(new_bpp * width) && new_stride % min(new_bpp, sizeof(uint32_t)) == 0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
493
494 buf = (char*)new_buf;
495 buf_size = 0;
496 buf_bpp = new_bpp;
497 buf_stride = new_stride;
498 }
499
500 // Returns true if re-allocation succeeded, false otherwise...
501 bool allocate(bool force = false, int min_width = 0, int min_height = 0) {
502 assert(!locked)(static_cast <bool> (!locked) ? void (0) : __assert_fail
("!locked", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
; // Locked textures shouldn't be reallocated
503 // If we get here, some GL API call that invalidates the texture was used.
504 // Mark the buffer as not-cleared to signal this.
505 set_cleared(false);
506 // Check if there is either no buffer currently or if we forced validation
507 // of the buffer size because some dimension might have changed.
508 if ((!buf || force) && should_free()) {
509 // Compute the buffer's BPP and stride, since they may have changed.
510 int new_bpp = compute_bpp();
511 size_t new_stride = compute_stride(new_bpp, width);
512 // Compute new size based on the maximum potential stride, rather than
513 // the current stride, to hopefully avoid reallocations when size would
514 // otherwise change too much...
515 size_t max_stride = compute_stride(new_bpp, max(width, min_width));
516 size_t size = max_stride * max(height, min_height);
517 if ((!buf && size > 0) || size > buf_size) {
518 // Allocate with a SIMD register-sized tail of padding at the end so we
519 // can safely read or write past the end of the texture with SIMD ops.
520 // Currently only the flat Z-buffer texture needs this padding due to
521 // full-register loads and stores in check_depth and discard_depth. In
522 // case some code in the future accidentally uses a linear filter on a
523 // texture with less than 2 pixels per row, we also add this padding
524 // just to be safe. All other texture types and use-cases should be
525 // safe to omit padding.
526 size_t padding =
527 internal_format == GL_DEPTH_COMPONENT240x81A6 || max(width, min_width) < 2
528 ? sizeof(Float)
529 : 0;
530 char* new_buf = (char*)realloc(buf, size + padding);
531 assert(new_buf)(static_cast <bool> (new_buf) ? void (0) : __assert_fail
("new_buf", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
532 if (!new_buf) {
533 // Allocation failed, so ensure we don't leave stale buffer state.
534 cleanup();
535 return false;
536 }
537 // Successfully reallocated the buffer, so go ahead and set it.
538 buf = new_buf;
539 buf_size = size;
540 }
541 // Set the BPP and stride in case they changed.
542 buf_bpp = new_bpp;
543 buf_stride = new_stride;
544 }
545 // Allocation succeeded or nothing changed...
546 return true;
547 }
548
549 void cleanup() {
550 assert(!locked)(static_cast <bool> (!locked) ? void (0) : __assert_fail
("!locked", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
; // Locked textures shouldn't be destroyed
551 if (buf) {
552 // If we need to toggle SHOULD_FREE state, ensure that buf is nulled out,
553 // regardless of whether we internally allocated it. This will prevent us
554 // from wrongly treating buf as having been internally allocated for when
555 // we go to realloc if it actually was externally allocted.
556 if (should_free()) {
557 free(buf);
558 }
559 buf = nullptr;
560 buf_size = 0;
561 buf_bpp = 0;
562 buf_stride = 0;
563 }
564 disable_delayed_clear();
565 }
566
567 ~Texture() { cleanup(); }
568
569 IntRect bounds() const { return IntRect{0, 0, width, height}; }
570 IntRect offset_bounds() const { return bounds() + offset; }
571
572 // Find the valid sampling bounds relative to the requested region
573 IntRect sample_bounds(const IntRect& req, bool invertY = false) const {
574 IntRect bb = bounds().intersect(req) - req.origin();
575 if (invertY) bb.invert_y(req.height());
576 return bb;
577 }
578
579 // Get a pointer for sampling at the given offset
580 char* sample_ptr(int x, int y) const {
581 return buf + y * stride() + x * bpp();
582 }
583
584 // Get a pointer to the end of the current buffer
585 char* end_ptr() const {
586 return buf + (height - 1) * stride() + width * bpp();
587 }
588
589 // Get a pointer for sampling the requested region and limit to the provided
590 // sampling bounds
591 char* sample_ptr(const IntRect& req, const IntRect& bounds,
592 bool invertY = false) const {
593 // Offset the sample pointer by the clamped bounds
594 int x = req.x0 + bounds.x0;
595 // Invert the Y offset if necessary
596 int y = invertY ? req.y1 - 1 - bounds.y0 : req.y0 + bounds.y0;
597 return sample_ptr(x, y);
598 }
599};
600
601// The last vertex attribute is reserved as a null attribute in case a vertex
602// attribute is used without being set.
603#define MAX_ATTRIBS17 17
604#define NULL_ATTRIB16 16
605struct VertexArray {
606 VertexAttrib attribs[MAX_ATTRIBS17];
607 int max_attrib = -1;
608 // The GL spec defines element array buffer binding to be part of VAO state.
609 GLuint element_array_buffer_binding = 0;
610
611 void validate();
612};
613
614struct Shader {
615 GLenum type = 0;
616 ProgramLoader loader = nullptr;
617};
618
619struct Program {
620 ProgramImpl* impl = nullptr;
621 VertexShaderImpl* vert_impl = nullptr;
622 FragmentShaderImpl* frag_impl = nullptr;
623 bool deleted = false;
624
625 ~Program() { delete impl; }
626};
627
628// clang-format off
629// Fully-expand GL defines while ignoring more than 4 suffixes
630#define CONCAT_KEY(prefix, x, y, z, w, ...)prefixxyzw prefix##x##y##z##w
631// Generate a blend key enum symbol
632#define BLEND_KEY(...)BLEND_...000 CONCAT_KEY(BLEND_, __VA_ARGS__, 0, 0, 0)BLEND___VA_ARGS__000
633#define MASK_BLEND_KEY(...)MASK_BLEND_...000 CONCAT_KEY(MASK_BLEND_, __VA_ARGS__, 0, 0, 0)MASK_BLEND___VA_ARGS__000
634#define AA_BLEND_KEY(...)AA_BLEND_...000 CONCAT_KEY(AA_BLEND_, __VA_ARGS__, 0, 0, 0)AA_BLEND___VA_ARGS__000
635#define AA_MASK_BLEND_KEY(...)AA_MASK_BLEND_...000 CONCAT_KEY(AA_MASK_BLEND_, __VA_ARGS__, 0, 0, 0)AA_MASK_BLEND___VA_ARGS__000
636
637// Utility macro to easily generate similar code for all implemented blend modes
638#define FOR_EACH_BLEND_KEY(macro)macro(1, 0, 0, 0) macro(0x0302, 0x0303, 1, 0x0303) macro(1, 0x0303
, 0, 0) macro(0, 0x0301, 0, 0) macro(0, 0x0301, 0, 1) macro(0
, 0x0303, 0, 0) macro(0, 0x0300, 0, 0) macro(1, 1, 0, 0) macro
(1, 1, 1, 0x0303) macro(0x0305, 1, 0, 1) macro(0x8001, 0x0301
, 0, 0) macro(1, 0x88FA, 0, 0) macro(0x8007, 0, 0, 0) macro(0x8008
, 0, 0, 0) macro(0x9294, 0, 0, 0) macro(0x9295, 0, 0, 0) macro
(0x9296, 0, 0, 0) macro(0x9297, 0, 0, 0) macro(0x9298, 0, 0, 0
) macro(0x9299, 0, 0, 0) macro(0x929A, 0, 0, 0) macro(0x929B,
0, 0, 0) macro(0x929C, 0, 0, 0) macro(0x929E, 0, 0, 0) macro
(0x92A0, 0, 0, 0) macro(0x92AD, 0, 0, 0) macro(0x92AE, 0, 0, 0
) macro(0x92AF, 0, 0, 0) macro(0x92B0, 0, 0, 0) macro(0xB001,
0, 0, 0) macro(0xB002, 0, 0, 0)
\
639 macro(GL_ONE1, GL_ZERO0, 0, 0) \
640 macro(GL_SRC_ALPHA0x0302, GL_ONE_MINUS_SRC_ALPHA0x0303, GL_ONE1, GL_ONE_MINUS_SRC_ALPHA0x0303) \
641 macro(GL_ONE1, GL_ONE_MINUS_SRC_ALPHA0x0303, 0, 0) \
642 macro(GL_ZERO0, GL_ONE_MINUS_SRC_COLOR0x0301, 0, 0) \
643 macro(GL_ZERO0, GL_ONE_MINUS_SRC_COLOR0x0301, GL_ZERO0, GL_ONE1) \
644 macro(GL_ZERO0, GL_ONE_MINUS_SRC_ALPHA0x0303, 0, 0) \
645 macro(GL_ZERO0, GL_SRC_COLOR0x0300, 0, 0) \
646 macro(GL_ONE1, GL_ONE1, 0, 0) \
647 macro(GL_ONE1, GL_ONE1, GL_ONE1, GL_ONE_MINUS_SRC_ALPHA0x0303) \
648 macro(GL_ONE_MINUS_DST_ALPHA0x0305, GL_ONE1, GL_ZERO0, GL_ONE1) \
649 macro(GL_CONSTANT_COLOR0x8001, GL_ONE_MINUS_SRC_COLOR0x0301, 0, 0) \
650 macro(GL_ONE1, GL_ONE_MINUS_SRC1_COLOR0x88FA, 0, 0) \
651 macro(GL_MIN0x8007, 0, 0, 0) \
652 macro(GL_MAX0x8008, 0, 0, 0) \
653 macro(GL_MULTIPLY_KHR0x9294, 0, 0, 0) \
654 macro(GL_SCREEN_KHR0x9295, 0, 0, 0) \
655 macro(GL_OVERLAY_KHR0x9296, 0, 0, 0) \
656 macro(GL_DARKEN_KHR0x9297, 0, 0, 0) \
657 macro(GL_LIGHTEN_KHR0x9298, 0, 0, 0) \
658 macro(GL_COLORDODGE_KHR0x9299, 0, 0, 0) \
659 macro(GL_COLORBURN_KHR0x929A, 0, 0, 0) \
660 macro(GL_HARDLIGHT_KHR0x929B, 0, 0, 0) \
661 macro(GL_SOFTLIGHT_KHR0x929C, 0, 0, 0) \
662 macro(GL_DIFFERENCE_KHR0x929E, 0, 0, 0) \
663 macro(GL_EXCLUSION_KHR0x92A0, 0, 0, 0) \
664 macro(GL_HSL_HUE_KHR0x92AD, 0, 0, 0) \
665 macro(GL_HSL_SATURATION_KHR0x92AE, 0, 0, 0) \
666 macro(GL_HSL_COLOR_KHR0x92AF, 0, 0, 0) \
667 macro(GL_HSL_LUMINOSITY_KHR0x92B0, 0, 0, 0) \
668 macro(SWGL_BLEND_DROP_SHADOW0xB001, 0, 0, 0) \
669 macro(SWGL_BLEND_SUBPIXEL_TEXT0xB002, 0, 0, 0)
670
671#define DEFINE_BLEND_KEY(...)BLEND_...000, BLEND_KEY(__VA_ARGS__)BLEND___VA_ARGS__000,
672#define DEFINE_MASK_BLEND_KEY(...)MASK_BLEND_...000, MASK_BLEND_KEY(__VA_ARGS__)MASK_BLEND___VA_ARGS__000,
673#define DEFINE_AA_BLEND_KEY(...)AA_BLEND_...000, AA_BLEND_KEY(__VA_ARGS__)AA_BLEND___VA_ARGS__000,
674#define DEFINE_AA_MASK_BLEND_KEY(...)AA_MASK_BLEND_...000, AA_MASK_BLEND_KEY(__VA_ARGS__)AA_MASK_BLEND___VA_ARGS__000,
675enum BlendKey : uint8_t {
676 FOR_EACH_BLEND_KEY(DEFINE_BLEND_KEY)BLEND_1000, BLEND_0x03020x030310x0303, BLEND_10x030300, BLEND_00x030100
, BLEND_00x030101, BLEND_00x030300, BLEND_00x030000, BLEND_1100
, BLEND_1110x0303, BLEND_0x0305101, BLEND_0x80010x030100, BLEND_10x88FA00
, BLEND_0x8007000, BLEND_0x8008000, BLEND_0x9294000, BLEND_0x9295000
, BLEND_0x9296000, BLEND_0x9297000, BLEND_0x9298000, BLEND_0x9299000
, BLEND_0x929A000, BLEND_0x929B000, BLEND_0x929C000, BLEND_0x929E000
, BLEND_0x92A0000, BLEND_0x92AD000, BLEND_0x92AE000, BLEND_0x92AF000
, BLEND_0x92B0000, BLEND_0xB001000, BLEND_0xB002000,
677 FOR_EACH_BLEND_KEY(DEFINE_MASK_BLEND_KEY)MASK_BLEND_1000, MASK_BLEND_0x03020x030310x0303, MASK_BLEND_10x030300
, MASK_BLEND_00x030100, MASK_BLEND_00x030101, MASK_BLEND_00x030300
, MASK_BLEND_00x030000, MASK_BLEND_1100, MASK_BLEND_1110x0303
, MASK_BLEND_0x0305101, MASK_BLEND_0x80010x030100, MASK_BLEND_10x88FA00
, MASK_BLEND_0x8007000, MASK_BLEND_0x8008000, MASK_BLEND_0x9294000
, MASK_BLEND_0x9295000, MASK_BLEND_0x9296000, MASK_BLEND_0x9297000
, MASK_BLEND_0x9298000, MASK_BLEND_0x9299000, MASK_BLEND_0x929A000
, MASK_BLEND_0x929B000, MASK_BLEND_0x929C000, MASK_BLEND_0x929E000
, MASK_BLEND_0x92A0000, MASK_BLEND_0x92AD000, MASK_BLEND_0x92AE000
, MASK_BLEND_0x92AF000, MASK_BLEND_0x92B0000, MASK_BLEND_0xB001000
, MASK_BLEND_0xB002000,
678 FOR_EACH_BLEND_KEY(DEFINE_AA_BLEND_KEY)AA_BLEND_1000, AA_BLEND_0x03020x030310x0303, AA_BLEND_10x030300
, AA_BLEND_00x030100, AA_BLEND_00x030101, AA_BLEND_00x030300,
AA_BLEND_00x030000, AA_BLEND_1100, AA_BLEND_1110x0303, AA_BLEND_0x0305101
, AA_BLEND_0x80010x030100, AA_BLEND_10x88FA00, AA_BLEND_0x8007000
, AA_BLEND_0x8008000, AA_BLEND_0x9294000, AA_BLEND_0x9295000,
AA_BLEND_0x9296000, AA_BLEND_0x9297000, AA_BLEND_0x9298000, AA_BLEND_0x9299000
, AA_BLEND_0x929A000, AA_BLEND_0x929B000, AA_BLEND_0x929C000,
AA_BLEND_0x929E000, AA_BLEND_0x92A0000, AA_BLEND_0x92AD000, AA_BLEND_0x92AE000
, AA_BLEND_0x92AF000, AA_BLEND_0x92B0000, AA_BLEND_0xB001000,
AA_BLEND_0xB002000,
679 FOR_EACH_BLEND_KEY(DEFINE_AA_MASK_BLEND_KEY)AA_MASK_BLEND_1000, AA_MASK_BLEND_0x03020x030310x0303, AA_MASK_BLEND_10x030300
, AA_MASK_BLEND_00x030100, AA_MASK_BLEND_00x030101, AA_MASK_BLEND_00x030300
, AA_MASK_BLEND_00x030000, AA_MASK_BLEND_1100, AA_MASK_BLEND_1110x0303
, AA_MASK_BLEND_0x0305101, AA_MASK_BLEND_0x80010x030100, AA_MASK_BLEND_10x88FA00
, AA_MASK_BLEND_0x8007000, AA_MASK_BLEND_0x8008000, AA_MASK_BLEND_0x9294000
, AA_MASK_BLEND_0x9295000, AA_MASK_BLEND_0x9296000, AA_MASK_BLEND_0x9297000
, AA_MASK_BLEND_0x9298000, AA_MASK_BLEND_0x9299000, AA_MASK_BLEND_0x929A000
, AA_MASK_BLEND_0x929B000, AA_MASK_BLEND_0x929C000, AA_MASK_BLEND_0x929E000
, AA_MASK_BLEND_0x92A0000, AA_MASK_BLEND_0x92AD000, AA_MASK_BLEND_0x92AE000
, AA_MASK_BLEND_0x92AF000, AA_MASK_BLEND_0x92B0000, AA_MASK_BLEND_0xB001000
, AA_MASK_BLEND_0xB002000,
680 BLEND_KEY_NONE = BLEND_KEY(GL_ONE, GL_ZERO)BLEND_1000,
681 MASK_BLEND_KEY_NONE = MASK_BLEND_KEY(GL_ONE, GL_ZERO)MASK_BLEND_1000,
682 AA_BLEND_KEY_NONE = AA_BLEND_KEY(GL_ONE, GL_ZERO)AA_BLEND_1000,
683 AA_MASK_BLEND_KEY_NONE = AA_MASK_BLEND_KEY(GL_ONE, GL_ZERO)AA_MASK_BLEND_1000,
684};
685// clang-format on
686
687const size_t MAX_TEXTURE_UNITS = 16;
688
689template <typename T>
690static inline bool unlink(T& binding, T n) {
691 if (binding == n) {
692 binding = 0;
693 return true;
694 }
695 return false;
696}
697
698template <typename O>
699struct ObjectStore {
700 O** objects = nullptr;
701 size_t size = 0;
702 // reserve object 0 as null
703 size_t first_free = 1;
704 O invalid;
705
706 ~ObjectStore() {
707 if (objects) {
708 for (size_t i = 0; i < size; i++) delete objects[i];
709 free(objects);
710 }
711 }
712
713 bool grow(size_t i) {
714 size_t new_size = size ? size : 8;
715 while (new_size <= i) new_size += new_size / 2;
716 O** new_objects = (O**)realloc(objects, new_size * sizeof(O*));
717 assert(new_objects)(static_cast <bool> (new_objects) ? void (0) : __assert_fail
("new_objects", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
718 if (!new_objects) return false;
719 while (size < new_size) new_objects[size++] = nullptr;
720 objects = new_objects;
721 return true;
722 }
723
724 void insert(size_t i, const O& o) {
725 if (i >= size && !grow(i)) return;
726 if (!objects[i]) objects[i] = new O(o);
727 }
728
729 size_t next_free() {
730 size_t i = first_free;
731 while (i < size && objects[i]) i++;
732 first_free = i;
733 return i;
734 }
735
736 size_t insert(const O& o = O()) {
737 size_t i = next_free();
738 insert(i, o);
739 return i;
740 }
741
742 O& operator[](size_t i) {
743 insert(i, O());
744 return i < size ? *objects[i] : invalid;
745 }
746
747 O* find(size_t i) const { return i < size ? objects[i] : nullptr; }
748
749 template <typename T>
750 void on_erase(T*, ...) {}
751 template <typename T>
752 void on_erase(T* o, decltype(&T::on_erase)) {
753 o->on_erase();
754 }
755
756 bool erase(size_t i, bool should_delete = true) {
757 if (i < size && objects[i]) {
758 on_erase(objects[i], nullptr);
759 if (should_delete) {
760 delete objects[i];
761 }
762 objects[i] = nullptr;
763 if (i < first_free) first_free = i;
764 return true;
765 }
766 return false;
767 }
768
769 O** begin() const { return objects; }
770 O** end() const { return &objects[size]; }
771};
772
773struct Context {
Excessive padding in 'struct Context' (38 padding bytes, where 6 is optimal). Optimal fields order: blendcolor, cleardepth, queries, framebuffers, renderbuffers, shaders, buffers, programs, textures, vertex_arrays, references, last_error, blendfunc_srgb, blendfunc_drgb, blendfunc_sa, blendfunc_da, blend_equation, depthfunc, unpack_row_length, shaded_rows, shaded_pixels, active_texture_unit, current_program, current_vertex_array, pixel_pack_buffer_binding, pixel_unpack_buffer_binding, array_buffer_binding, time_elapsed_query, samples_passed_query, renderbuffer_binding, draw_framebuffer_binding, read_framebuffer_binding, unknown_binding, viewport, scissor, clearcolor, texture_units, blend, blend_key, depthtest, depthmask, scissortest, validate_vertex_array, consider reordering the fields or adding explicit padding members
774 int32_t references = 1;
775
776 ObjectStore<Query> queries;
777 ObjectStore<Buffer> buffers;
778 ObjectStore<Texture> textures;
779 ObjectStore<VertexArray> vertex_arrays;
780 ObjectStore<Framebuffer> framebuffers;
781 ObjectStore<Renderbuffer> renderbuffers;
782 ObjectStore<Shader> shaders;
783 ObjectStore<Program> programs;
784
785 GLenum last_error = GL_NO_ERROR0;
786
787 IntRect viewport = {0, 0, 0, 0};
788
789 bool blend = false;
790 GLenum blendfunc_srgb = GL_ONE1;
791 GLenum blendfunc_drgb = GL_ZERO0;
792 GLenum blendfunc_sa = GL_ONE1;
793 GLenum blendfunc_da = GL_ZERO0;
794 GLenum blend_equation = GL_FUNC_ADD0x8006;
795 V8<uint16_t> blendcolor = 0;
796 BlendKey blend_key = BLEND_KEY_NONE;
797
798 bool depthtest = false;
799 bool depthmask = true;
800 GLenum depthfunc = GL_LESS0x0201;
801
802 bool scissortest = false;
803 IntRect scissor = {0, 0, 0, 0};
804
805 GLfloat clearcolor[4] = {0, 0, 0, 0};
806 GLdouble cleardepth = 1;
807
808 int unpack_row_length = 0;
809
810 int shaded_rows = 0;
811 int shaded_pixels = 0;
812
813 struct TextureUnit {
814 GLuint texture_2d_binding = 0;
815 GLuint texture_rectangle_binding = 0;
816
817 void unlink(GLuint n) {
818 ::unlink(texture_2d_binding, n);
819 ::unlink(texture_rectangle_binding, n);
820 }
821 };
822 TextureUnit texture_units[MAX_TEXTURE_UNITS];
823 int active_texture_unit = 0;
824
825 GLuint current_program = 0;
826
827 GLuint current_vertex_array = 0;
828 bool validate_vertex_array = true;
829
830 GLuint pixel_pack_buffer_binding = 0;
831 GLuint pixel_unpack_buffer_binding = 0;
832 GLuint array_buffer_binding = 0;
833 GLuint time_elapsed_query = 0;
834 GLuint samples_passed_query = 0;
835 GLuint renderbuffer_binding = 0;
836 GLuint draw_framebuffer_binding = 0;
837 GLuint read_framebuffer_binding = 0;
838 GLuint unknown_binding = 0;
839
840 GLuint& get_binding(GLenum name) {
841 switch (name) {
842 case GL_PIXEL_PACK_BUFFER0x88EB:
843 return pixel_pack_buffer_binding;
844 case GL_PIXEL_UNPACK_BUFFER0x88EC:
845 return pixel_unpack_buffer_binding;
846 case GL_ARRAY_BUFFER0x8892:
847 return array_buffer_binding;
848 case GL_ELEMENT_ARRAY_BUFFER0x8893:
849 return vertex_arrays[current_vertex_array].element_array_buffer_binding;
850 case GL_TEXTURE_2D0x0DE1:
851 return texture_units[active_texture_unit].texture_2d_binding;
852 case GL_TEXTURE_RECTANGLE0x84F5:
853 return texture_units[active_texture_unit].texture_rectangle_binding;
854 case GL_TIME_ELAPSED0x88BF:
855 return time_elapsed_query;
856 case GL_SAMPLES_PASSED0x8914:
857 return samples_passed_query;
858 case GL_RENDERBUFFER0x8D41:
859 return renderbuffer_binding;
860 case GL_DRAW_FRAMEBUFFER0x8CA9:
861 return draw_framebuffer_binding;
862 case GL_READ_FRAMEBUFFER0x8CA8:
863 return read_framebuffer_binding;
864 default:
865 debugf("unknown binding %x\n", name)printf("unknown binding %x\n", name);
866 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
867 return unknown_binding;
868 }
869 }
870
871 Texture& get_texture(sampler2D, int unit) {
872 return textures[texture_units[unit].texture_2d_binding];
873 }
874
875 Texture& get_texture(isampler2D, int unit) {
876 return textures[texture_units[unit].texture_2d_binding];
877 }
878
879 Texture& get_texture(sampler2DRect, int unit) {
880 return textures[texture_units[unit].texture_rectangle_binding];
881 }
882
883 IntRect apply_scissor(IntRect bb,
884 const IntPoint& origin = IntPoint(0, 0)) const {
885 return scissortest ? bb.intersect(scissor - origin) : bb;
886 }
887
888 IntRect apply_scissor(const Texture& t) const {
889 return apply_scissor(t.bounds(), t.offset);
890 }
891};
892static Context* ctx = nullptr;
893static VertexShaderImpl* vertex_shader = nullptr;
894static FragmentShaderImpl* fragment_shader = nullptr;
895static BlendKey blend_key = BLEND_KEY_NONE;
896
897static void prepare_texture(Texture& t, const IntRect* skip = nullptr);
898
899template <typename S>
900static inline void init_filter(S* s, Texture& t) {
901 // If the width is not at least 2 pixels, then we can't safely sample the end
902 // of the row with a linear filter. In that case, just punt to using nearest
903 // filtering instead.
904 s->filter = t.width >= 2 ? gl_filter_to_texture_filter(t.mag_filter)
905 : TextureFilter::NEAREST;
906}
907
908template <typename S>
909static inline void init_sampler(S* s, Texture& t) {
910 prepare_texture(t);
911 s->width = t.width;
912 s->height = t.height;
913 s->stride = t.stride();
914 int bpp = t.bpp();
915 if (bpp >= 4)
916 s->stride /= 4;
917 else if (bpp == 2)
918 s->stride /= 2;
919 else
920 assert(bpp == 1)(static_cast <bool> (bpp == 1) ? void (0) : __assert_fail
("bpp == 1", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
921 // Use uint32_t* for easier sampling, but need to cast to uint8_t* or
922 // uint16_t* for formats with bpp < 4.
923 s->buf = (uint32_t*)t.buf;
924 s->format = gl_format_to_texture_format(t.internal_format);
925}
926
927template <typename S>
928static inline void null_sampler(S* s) {
929 // For null texture data, just make the sampler provide a 1x1 buffer that is
930 // transparent black. Ensure buffer holds at least a SIMD vector of zero data
931 // for SIMD padding of unaligned loads.
932 static const uint32_t zeroBuf[sizeof(Float) / sizeof(uint32_t)] = {0};
933 s->width = 1;
934 s->height = 1;
935 s->stride = s->width;
936 s->buf = (uint32_t*)zeroBuf;
937 s->format = TextureFormat::RGBA8;
938}
939
940template <typename S>
941static inline void null_filter(S* s) {
942 s->filter = TextureFilter::NEAREST;
943}
944
945template <typename S>
946S* lookup_sampler(S* s, int texture) {
947 Texture& t = ctx->get_texture(s, texture);
948 if (!t.buf) {
949 null_sampler(s);
950 null_filter(s);
951 } else {
952 init_sampler(s, t);
953 init_filter(s, t);
954 }
955 return s;
956}
957
958template <typename S>
959S* lookup_isampler(S* s, int texture) {
960 Texture& t = ctx->get_texture(s, texture);
961 if (!t.buf) {
962 null_sampler(s);
963 } else {
964 init_sampler(s, t);
965 }
966 return s;
967}
968
969int bytes_per_type(GLenum type) {
970 switch (type) {
971 case GL_INT0x1404:
972 return 4;
973 case GL_FLOAT0x1406:
974 return 4;
975 case GL_UNSIGNED_SHORT0x1403:
976 return 2;
977 case GL_UNSIGNED_BYTE0x1401:
978 return 1;
979 default:
980 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
981 return 0;
982 }
983}
984
985template <typename S, typename C>
986static inline S expand_attrib(const char* buf, size_t size, bool normalized) {
987 typedef typename ElementType<S>::ty elem_type;
988 S scalar = {0};
989 const C* src = reinterpret_cast<const C*>(buf);
990 if (normalized) {
991 const float scale = 1.0f / ((1 << (8 * sizeof(C))) - 1);
992 for (size_t i = 0; i < size / sizeof(C); i++) {
993 put_nth_component(scalar, i, elem_type(src[i]) * scale);
994 }
995 } else {
996 for (size_t i = 0; i < size / sizeof(C); i++) {
997 put_nth_component(scalar, i, elem_type(src[i]));
998 }
999 }
1000 return scalar;
1001}
1002
1003template <typename S>
1004static inline S load_attrib_scalar(VertexAttrib& va, const char* src) {
1005 if (sizeof(S) <= va.size) {
1006 return *reinterpret_cast<const S*>(src);
1007 }
1008 if (va.type == GL_UNSIGNED_SHORT0x1403) {
1009 return expand_attrib<S, uint16_t>(src, va.size, va.normalized);
1010 }
1011 if (va.type == GL_UNSIGNED_BYTE0x1401) {
1012 return expand_attrib<S, uint8_t>(src, va.size, va.normalized);
1013 }
1014 assert(sizeof(typename ElementType<S>::ty) == bytes_per_type(va.type))(static_cast <bool> (sizeof(typename ElementType<S>
::ty) == bytes_per_type(va.type)) ? void (0) : __assert_fail (
"sizeof(typename ElementType<S>::ty) == bytes_per_type(va.type)"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1015 S scalar = {0};
1016 memcpy(&scalar, src, va.size);
1017 return scalar;
1018}
1019
1020template <typename T>
1021void load_attrib(T& attrib, VertexAttrib& va, uint32_t start, int instance,
1022 int count) {
1023 typedef decltype(force_scalar(attrib)) scalar_type;
1024 // If no buffer is available, just use a zero default.
1025 if (!va.buf_size) {
1026 attrib = T(scalar_type{0});
1027 } else if (va.divisor != 0) {
1028 char* src = (char*)va.buf + va.stride * instance + va.offset;
1029 assert(src + va.size <= va.buf + va.buf_size)(static_cast <bool> (src + va.size <= va.buf + va.buf_size
) ? void (0) : __assert_fail ("src + va.size <= va.buf + va.buf_size"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1030 attrib = T(load_attrib_scalar<scalar_type>(va, src));
1031 } else {
1032 // Specialized for WR's primitive vertex order/winding.
1033 if (!count) return;
1034 assert(count >= 2 && count <= 4)(static_cast <bool> (count >= 2 && count <=
4) ? void (0) : __assert_fail ("count >= 2 && count <= 4"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1035 char* src = (char*)va.buf + va.stride * start + va.offset;
1036 switch (count) {
1037 case 2: {
1038 // Lines must be indexed at offsets 0, 1.
1039 // Line vertexes fill vertex shader SIMD lanes as 0, 1, 1, 0.
1040 scalar_type lanes[2] = {
1041 load_attrib_scalar<scalar_type>(va, src),
1042 load_attrib_scalar<scalar_type>(va, src + va.stride)};
1043 attrib = (T){lanes[0], lanes[1], lanes[1], lanes[0]};
1044 break;
1045 }
1046 case 3: {
1047 // Triangles must be indexed at offsets 0, 1, 2.
1048 // Triangle vertexes fill vertex shader SIMD lanes as 0, 1, 2, 2.
1049 scalar_type lanes[3] = {
1050 load_attrib_scalar<scalar_type>(va, src),
1051 load_attrib_scalar<scalar_type>(va, src + va.stride),
1052 load_attrib_scalar<scalar_type>(va, src + va.stride * 2)};
1053 attrib = (T){lanes[0], lanes[1], lanes[2], lanes[2]};
1054 break;
1055 }
1056 default:
1057 // Quads must be successive triangles indexed at offsets 0, 1, 2, 2,
1058 // 1, 3. Quad vertexes fill vertex shader SIMD lanes as 0, 1, 3, 2, so
1059 // that the points form a convex path that can be traversed by the
1060 // rasterizer.
1061 attrib = (T){load_attrib_scalar<scalar_type>(va, src),
1062 load_attrib_scalar<scalar_type>(va, src + va.stride),
1063 load_attrib_scalar<scalar_type>(va, src + va.stride * 3),
1064 load_attrib_scalar<scalar_type>(va, src + va.stride * 2)};
1065 break;
1066 }
1067 }
1068}
1069
1070template <typename T>
1071void load_flat_attrib(T& attrib, VertexAttrib& va, uint32_t start, int instance,
1072 int count) {
1073 typedef decltype(force_scalar(attrib)) scalar_type;
1074 // If no buffer is available, just use a zero default.
1075 if (!va.buf_size) {
1076 attrib = T{0};
1077 return;
1078 }
1079 char* src = nullptr;
1080 if (va.divisor != 0) {
1081 src = (char*)va.buf + va.stride * instance + va.offset;
1082 } else {
1083 if (!count) return;
1084 src = (char*)va.buf + va.stride * start + va.offset;
1085 }
1086 assert(src + va.size <= va.buf + va.buf_size)(static_cast <bool> (src + va.size <= va.buf + va.buf_size
) ? void (0) : __assert_fail ("src + va.size <= va.buf + va.buf_size"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1087 attrib = T(load_attrib_scalar<scalar_type>(va, src));
1088}
1089
1090void setup_program(GLuint program) {
1091 if (!program) {
1092 vertex_shader = nullptr;
1093 fragment_shader = nullptr;
1094 return;
1095 }
1096 Program& p = ctx->programs[program];
1097 assert(p.impl)(static_cast <bool> (p.impl) ? void (0) : __assert_fail
("p.impl", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1098 assert(p.vert_impl)(static_cast <bool> (p.vert_impl) ? void (0) : __assert_fail
("p.vert_impl", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1099 assert(p.frag_impl)(static_cast <bool> (p.frag_impl) ? void (0) : __assert_fail
("p.frag_impl", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1100 vertex_shader = p.vert_impl;
1101 fragment_shader = p.frag_impl;
1102}
1103
1104extern ProgramLoader load_shader(const char* name);
1105
1106extern "C" {
1107
1108void UseProgram(GLuint program) {
1109 if (ctx->current_program && program != ctx->current_program) {
1110 auto* p = ctx->programs.find(ctx->current_program);
1111 if (p && p->deleted) {
1112 ctx->programs.erase(ctx->current_program);
1113 }
1114 }
1115 ctx->current_program = program;
1116 setup_program(program);
1117}
1118
1119void SetViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
1120 ctx->viewport = IntRect{x, y, x + width, y + height};
1121}
1122
1123void Enable(GLenum cap) {
1124 switch (cap) {
1125 case GL_BLEND0x0BE2:
1126 ctx->blend = true;
1127 break;
1128 case GL_DEPTH_TEST0x0B71:
1129 ctx->depthtest = true;
1130 break;
1131 case GL_SCISSOR_TEST0x0C11:
1132 ctx->scissortest = true;
1133 break;
1134 }
1135}
1136
1137void Disable(GLenum cap) {
1138 switch (cap) {
1139 case GL_BLEND0x0BE2:
1140 ctx->blend = false;
1141 break;
1142 case GL_DEPTH_TEST0x0B71:
1143 ctx->depthtest = false;
1144 break;
1145 case GL_SCISSOR_TEST0x0C11:
1146 ctx->scissortest = false;
1147 break;
1148 }
1149}
1150
1151// Report the last error generated and clear the error status.
1152GLenum GetError() {
1153 GLenum error = ctx->last_error;
1154 ctx->last_error = GL_NO_ERROR0;
1155 return error;
1156}
1157
1158// Sets the error status to out-of-memory to indicate that a buffer
1159// or texture re-allocation failed.
1160static void out_of_memory() { ctx->last_error = GL_OUT_OF_MEMORY0x0505; }
1161
1162static const char* const extensions[] = {
1163 "GL_ARB_blend_func_extended",
1164 "GL_ARB_clear_texture",
1165 "GL_ARB_copy_image",
1166 "GL_ARB_draw_instanced",
1167 "GL_ARB_explicit_attrib_location",
1168 "GL_ARB_instanced_arrays",
1169 "GL_ARB_invalidate_subdata",
1170 "GL_ARB_texture_storage",
1171 "GL_EXT_timer_query",
1172 "GL_KHR_blend_equation_advanced",
1173 "GL_KHR_blend_equation_advanced_coherent",
1174 "GL_APPLE_rgb_422",
1175};
1176
1177void GetIntegerv(GLenum pname, GLint* params) {
1178 assert(params)(static_cast <bool> (params) ? void (0) : __assert_fail
("params", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1179 switch (pname) {
1180 case GL_MAX_TEXTURE_UNITS0x84E2:
1181 case GL_MAX_TEXTURE_IMAGE_UNITS0x8872:
1182 params[0] = MAX_TEXTURE_UNITS;
1183 break;
1184 case GL_MAX_TEXTURE_SIZE0x0D33:
1185 params[0] = 1 << 15;
1186 break;
1187 case GL_MAX_ARRAY_TEXTURE_LAYERS0x88FF:
1188 params[0] = 0;
1189 break;
1190 case GL_READ_FRAMEBUFFER_BINDING0x8CAA:
1191 params[0] = ctx->read_framebuffer_binding;
1192 break;
1193 case GL_DRAW_FRAMEBUFFER_BINDING0x8CA6:
1194 params[0] = ctx->draw_framebuffer_binding;
1195 break;
1196 case GL_PIXEL_PACK_BUFFER_BINDING0x88ED:
1197 params[0] = ctx->pixel_pack_buffer_binding;
1198 break;
1199 case GL_PIXEL_UNPACK_BUFFER_BINDING0x88EF:
1200 params[0] = ctx->pixel_unpack_buffer_binding;
1201 break;
1202 case GL_NUM_EXTENSIONS0x821D:
1203 params[0] = sizeof(extensions) / sizeof(extensions[0]);
1204 break;
1205 case GL_MAJOR_VERSION0x821B:
1206 params[0] = 3;
1207 break;
1208 case GL_MINOR_VERSION0x821C:
1209 params[0] = 2;
1210 break;
1211 case GL_MIN_PROGRAM_TEXEL_OFFSET0x8904:
1212 params[0] = 0;
1213 break;
1214 case GL_MAX_PROGRAM_TEXEL_OFFSET0x8905:
1215 params[0] = MAX_TEXEL_OFFSET;
1216 break;
1217 default:
1218 debugf("unhandled glGetIntegerv parameter %x\n", pname)printf("unhandled glGetIntegerv parameter %x\n", pname);
1219 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1220 }
1221}
1222
1223void GetBooleanv(GLenum pname, GLboolean* params) {
1224 assert(params)(static_cast <bool> (params) ? void (0) : __assert_fail
("params", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1225 switch (pname) {
1226 case GL_DEPTH_WRITEMASK0x0B72:
1227 params[0] = ctx->depthmask;
1228 break;
1229 default:
1230 debugf("unhandled glGetBooleanv parameter %x\n", pname)printf("unhandled glGetBooleanv parameter %x\n", pname);
1231 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1232 }
1233}
1234
1235const char* GetString(GLenum name) {
1236 switch (name) {
1237 case GL_VENDOR0x1F00:
1238 return "Mozilla Gfx";
1239 case GL_RENDERER0x1F01:
1240 return "Software WebRender";
1241 case GL_VERSION0x1F02:
1242 return "3.2";
1243 case GL_SHADING_LANGUAGE_VERSION0x8B8C:
1244 return "1.50";
1245 default:
1246 debugf("unhandled glGetString parameter %x\n", name)printf("unhandled glGetString parameter %x\n", name);
1247 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1248 return nullptr;
1249 }
1250}
1251
1252const char* GetStringi(GLenum name, GLuint index) {
1253 switch (name) {
1254 case GL_EXTENSIONS0x1F03:
1255 if (index >= sizeof(extensions) / sizeof(extensions[0])) {
1256 return nullptr;
1257 }
1258 return extensions[index];
1259 default:
1260 debugf("unhandled glGetStringi parameter %x\n", name)printf("unhandled glGetStringi parameter %x\n", name);
1261 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1262 return nullptr;
1263 }
1264}
1265
1266GLenum remap_blendfunc(GLenum rgb, GLenum a) {
1267 switch (a) {
1268 case GL_SRC_ALPHA0x0302:
1269 if (rgb == GL_SRC_COLOR0x0300) a = GL_SRC_COLOR0x0300;
1270 break;
1271 case GL_ONE_MINUS_SRC_ALPHA0x0303:
1272 if (rgb == GL_ONE_MINUS_SRC_COLOR0x0301) a = GL_ONE_MINUS_SRC_COLOR0x0301;
1273 break;
1274 case GL_DST_ALPHA0x0304:
1275 if (rgb == GL_DST_COLOR0x0306) a = GL_DST_COLOR0x0306;
1276 break;
1277 case GL_ONE_MINUS_DST_ALPHA0x0305:
1278 if (rgb == GL_ONE_MINUS_DST_COLOR0x0307) a = GL_ONE_MINUS_DST_COLOR0x0307;
1279 break;
1280 case GL_CONSTANT_ALPHA0x8003:
1281 if (rgb == GL_CONSTANT_COLOR0x8001) a = GL_CONSTANT_COLOR0x8001;
1282 break;
1283 case GL_ONE_MINUS_CONSTANT_ALPHA0x8004:
1284 if (rgb == GL_ONE_MINUS_CONSTANT_COLOR0x8002) a = GL_ONE_MINUS_CONSTANT_COLOR0x8002;
1285 break;
1286 case GL_SRC_COLOR0x0300:
1287 if (rgb == GL_SRC_ALPHA0x0302) a = GL_SRC_ALPHA0x0302;
1288 break;
1289 case GL_ONE_MINUS_SRC_COLOR0x0301:
1290 if (rgb == GL_ONE_MINUS_SRC_ALPHA0x0303) a = GL_ONE_MINUS_SRC_ALPHA0x0303;
1291 break;
1292 case GL_DST_COLOR0x0306:
1293 if (rgb == GL_DST_ALPHA0x0304) a = GL_DST_ALPHA0x0304;
1294 break;
1295 case GL_ONE_MINUS_DST_COLOR0x0307:
1296 if (rgb == GL_ONE_MINUS_DST_ALPHA0x0305) a = GL_ONE_MINUS_DST_ALPHA0x0305;
1297 break;
1298 case GL_CONSTANT_COLOR0x8001:
1299 if (rgb == GL_CONSTANT_ALPHA0x8003) a = GL_CONSTANT_ALPHA0x8003;
1300 break;
1301 case GL_ONE_MINUS_CONSTANT_COLOR0x8002:
1302 if (rgb == GL_ONE_MINUS_CONSTANT_ALPHA0x8004) a = GL_ONE_MINUS_CONSTANT_ALPHA0x8004;
1303 break;
1304 case GL_SRC1_ALPHA0x8589:
1305 if (rgb == GL_SRC1_COLOR0x88F9) a = GL_SRC1_COLOR0x88F9;
1306 break;
1307 case GL_ONE_MINUS_SRC1_ALPHA0x88FB:
1308 if (rgb == GL_ONE_MINUS_SRC1_COLOR0x88FA) a = GL_ONE_MINUS_SRC1_COLOR0x88FA;
1309 break;
1310 case GL_SRC1_COLOR0x88F9:
1311 if (rgb == GL_SRC1_ALPHA0x8589) a = GL_SRC1_ALPHA0x8589;
1312 break;
1313 case GL_ONE_MINUS_SRC1_COLOR0x88FA:
1314 if (rgb == GL_ONE_MINUS_SRC1_ALPHA0x88FB) a = GL_ONE_MINUS_SRC1_ALPHA0x88FB;
1315 break;
1316 }
1317 return a;
1318}
1319
1320// Generate a hashed blend key based on blend func and equation state. This
1321// allows all the blend state to be processed down to a blend key that can be
1322// dealt with inside a single switch statement.
1323static void hash_blend_key() {
1324 GLenum srgb = ctx->blendfunc_srgb;
1325 GLenum drgb = ctx->blendfunc_drgb;
1326 GLenum sa = ctx->blendfunc_sa;
1327 GLenum da = ctx->blendfunc_da;
1328 GLenum equation = ctx->blend_equation;
1329#define HASH_BLEND_KEY(x, y, z, w)((x << 4) | (y) | (z << 24) | (w << 20)) ((x << 4) | (y) | (z << 24) | (w << 20))
1330 // Basic non-separate blend funcs used the two argument form
1331 int hash = HASH_BLEND_KEY(srgb, drgb, 0, 0)((srgb << 4) | (drgb) | (0 << 24) | (0 << 20
))
;
1332 // Separate alpha blend funcs use the 4 argument hash
1333 if (srgb != sa || drgb != da) hash |= HASH_BLEND_KEY(0, 0, sa, da)((0 << 4) | (0) | (sa << 24) | (da << 20));
1334 // Any other blend equation than the default func_add ignores the func and
1335 // instead generates a one-argument hash based on the equation
1336 if (equation != GL_FUNC_ADD0x8006) hash = HASH_BLEND_KEY(equation, 0, 0, 0)((equation << 4) | (0) | (0 << 24) | (0 << 20
))
;
1337 switch (hash) {
1338#define MAP_BLEND_KEY(...)case HASH_BLEND_KEY: ctx->blend_key = BLEND_...000; break; \
1339 case HASH_BLEND_KEY(__VA_ARGS__): \
1340 ctx->blend_key = BLEND_KEY(__VA_ARGS__)BLEND___VA_ARGS__000; \
1341 break;
1342 FOR_EACH_BLEND_KEY(MAP_BLEND_KEY)case ((1 << 4) | (0) | (0 << 24) | (0 << 20
)): ctx->blend_key = BLEND_1000; break; case ((0x0302 <<
4) | (0x0303) | (1 << 24) | (0x0303 << 20)): ctx
->blend_key = BLEND_0x03020x030310x0303; break; case ((1 <<
4) | (0x0303) | (0 << 24) | (0 << 20)): ctx->
blend_key = BLEND_10x030300; break; case ((0 << 4) | (0x0301
) | (0 << 24) | (0 << 20)): ctx->blend_key = BLEND_00x030100
; break; case ((0 << 4) | (0x0301) | (0 << 24) | (
1 << 20)): ctx->blend_key = BLEND_00x030101; break; case
((0 << 4) | (0x0303) | (0 << 24) | (0 << 20
)): ctx->blend_key = BLEND_00x030300; break; case ((0 <<
4) | (0x0300) | (0 << 24) | (0 << 20)): ctx->
blend_key = BLEND_00x030000; break; case ((1 << 4) | (1
) | (0 << 24) | (0 << 20)): ctx->blend_key = BLEND_1100
; break; case ((1 << 4) | (1) | (1 << 24) | (0x0303
<< 20)): ctx->blend_key = BLEND_1110x0303; break; case
((0x0305 << 4) | (1) | (0 << 24) | (1 << 20
)): ctx->blend_key = BLEND_0x0305101; break; case ((0x8001
<< 4) | (0x0301) | (0 << 24) | (0 << 20)):
ctx->blend_key = BLEND_0x80010x030100; break; case ((1 <<
4) | (0x88FA) | (0 << 24) | (0 << 20)): ctx->
blend_key = BLEND_10x88FA00; break; case ((0x8007 << 4)
| (0) | (0 << 24) | (0 << 20)): ctx->blend_key
= BLEND_0x8007000; break; case ((0x8008 << 4) | (0) | (
0 << 24) | (0 << 20)): ctx->blend_key = BLEND_0x8008000
; break; case ((0x9294 << 4) | (0) | (0 << 24) | (
0 << 20)): ctx->blend_key = BLEND_0x9294000; break; case
((0x9295 << 4) | (0) | (0 << 24) | (0 << 20
)): ctx->blend_key = BLEND_0x9295000; break; case ((0x9296
<< 4) | (0) | (0 << 24) | (0 << 20)): ctx->
blend_key = BLEND_0x9296000; break; case ((0x9297 << 4)
| (0) | (0 << 24) | (0 << 20)): ctx->blend_key
= BLEND_0x9297000; break; case ((0x9298 << 4) | (0) | (
0 << 24) | (0 << 20)): ctx->blend_key = BLEND_0x9298000
; break; case ((0x9299 << 4) | (0) | (0 << 24) | (
0 << 20)): ctx->blend_key = BLEND_0x9299000; break; case
((0x929A << 4) | (0) | (0 << 24) | (0 << 20
)): ctx->blend_key = BLEND_0x929A000; break; case ((0x929B
<< 4) | (0) | (0 << 24) | (0 << 20)): ctx->
blend_key = BLEND_0x929B000; break; case ((0x929C << 4)
| (0) | (0 << 24) | (0 << 20)): ctx->blend_key
= BLEND_0x929C000; break; case ((0x929E << 4) | (0) | (
0 << 24) | (0 << 20)): ctx->blend_key = BLEND_0x929E000
; break; case ((0x92A0 << 4) | (0) | (0 << 24) | (
0 << 20)): ctx->blend_key = BLEND_0x92A0000; break; case
((0x92AD << 4) | (0) | (0 << 24) | (0 << 20
)): ctx->blend_key = BLEND_0x92AD000; break; case ((0x92AE
<< 4) | (0) | (0 << 24) | (0 << 20)): ctx->
blend_key = BLEND_0x92AE000; break; case ((0x92AF << 4)
| (0) | (0 << 24) | (0 << 20)): ctx->blend_key
= BLEND_0x92AF000; break; case ((0x92B0 << 4) | (0) | (
0 << 24) | (0 << 20)): ctx->blend_key = BLEND_0x92B0000
; break; case ((0xB001 << 4) | (0) | (0 << 24) | (
0 << 20)): ctx->blend_key = BLEND_0xB001000; break; case
((0xB002 << 4) | (0) | (0 << 24) | (0 << 20
)): ctx->blend_key = BLEND_0xB002000; break;
1343 default:
1344 debugf("blendfunc: %x, %x, separate: %x, %x, equation: %x\n", srgb, drgb,printf("blendfunc: %x, %x, separate: %x, %x, equation: %x\n",
srgb, drgb, sa, da, equation)
1345 sa, da, equation)printf("blendfunc: %x, %x, separate: %x, %x, equation: %x\n",
srgb, drgb, sa, da, equation)
;
1346 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1347 break;
1348 }
1349}
1350
1351void BlendFunc(GLenum srgb, GLenum drgb, GLenum sa, GLenum da) {
1352 ctx->blendfunc_srgb = srgb;
1353 ctx->blendfunc_drgb = drgb;
1354 sa = remap_blendfunc(srgb, sa);
1355 da = remap_blendfunc(drgb, da);
1356 ctx->blendfunc_sa = sa;
1357 ctx->blendfunc_da = da;
1358
1359 hash_blend_key();
1360}
1361
1362void BlendColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
1363 I32 c = round_pixel((Float){b, g, r, a});
1364 ctx->blendcolor = CONVERT(c, U16)__builtin_convertvector(c, U16).xyzwxyzw;
1365}
1366
1367void BlendEquation(GLenum mode) {
1368 assert(mode == GL_FUNC_ADD || mode == GL_MIN || mode == GL_MAX ||(static_cast <bool> (mode == 0x8006 || mode == 0x8007 ||
mode == 0x8008 || (mode >= 0x9294 && mode <= 0x92B0
)) ? void (0) : __assert_fail ("mode == GL_FUNC_ADD || mode == GL_MIN || mode == GL_MAX || (mode >= GL_MULTIPLY_KHR && mode <= GL_HSL_LUMINOSITY_KHR)"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
1369 (mode >= GL_MULTIPLY_KHR && mode <= GL_HSL_LUMINOSITY_KHR))(static_cast <bool> (mode == 0x8006 || mode == 0x8007 ||
mode == 0x8008 || (mode >= 0x9294 && mode <= 0x92B0
)) ? void (0) : __assert_fail ("mode == GL_FUNC_ADD || mode == GL_MIN || mode == GL_MAX || (mode >= GL_MULTIPLY_KHR && mode <= GL_HSL_LUMINOSITY_KHR)"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1370 if (mode != ctx->blend_equation) {
1371 ctx->blend_equation = mode;
1372 hash_blend_key();
1373 }
1374}
1375
1376void DepthMask(GLboolean flag) { ctx->depthmask = flag; }
1377
1378void DepthFunc(GLenum func) {
1379 switch (func) {
1380 case GL_LESS0x0201:
1381 case GL_LEQUAL0x0203:
1382 break;
1383 default:
1384 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1385 }
1386 ctx->depthfunc = func;
1387}
1388
1389void SetScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
1390 ctx->scissor = IntRect{x, y, x + width, y + height};
1391}
1392
1393void ClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
1394 ctx->clearcolor[0] = r;
1395 ctx->clearcolor[1] = g;
1396 ctx->clearcolor[2] = b;
1397 ctx->clearcolor[3] = a;
1398}
1399
1400void ClearDepth(GLdouble depth) { ctx->cleardepth = depth; }
1401
1402void ActiveTexture(GLenum texture) {
1403 assert(texture >= GL_TEXTURE0)(static_cast <bool> (texture >= 0x84C0) ? void (0) :
__assert_fail ("texture >= GL_TEXTURE0", __builtin_FILE (
), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
1404 assert(texture < GL_TEXTURE0 + MAX_TEXTURE_UNITS)(static_cast <bool> (texture < 0x84C0 + MAX_TEXTURE_UNITS
) ? void (0) : __assert_fail ("texture < GL_TEXTURE0 + MAX_TEXTURE_UNITS"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1405 ctx->active_texture_unit =
1406 clamp(int(texture - GL_TEXTURE00x84C0), 0, int(MAX_TEXTURE_UNITS - 1));
1407}
1408
1409void GenQueries(GLsizei n, GLuint* result) {
1410 for (int i = 0; i < n; i++) {
1411 Query q;
1412 result[i] = ctx->queries.insert(q);
1413 }
1414}
1415
1416void DeleteQuery(GLuint n) {
1417 if (n && ctx->queries.erase(n)) {
1418 unlink(ctx->time_elapsed_query, n);
1419 unlink(ctx->samples_passed_query, n);
1420 }
1421}
1422
1423void GenBuffers(int n, GLuint* result) {
1424 for (int i = 0; i < n; i++) {
1425 Buffer b;
1426 result[i] = ctx->buffers.insert(b);
1427 }
1428}
1429
1430void DeleteBuffer(GLuint n) {
1431 if (n && ctx->buffers.erase(n)) {
1432 unlink(ctx->pixel_pack_buffer_binding, n);
1433 unlink(ctx->pixel_unpack_buffer_binding, n);
1434 unlink(ctx->array_buffer_binding, n);
1435 }
1436}
1437
1438void GenVertexArrays(int n, GLuint* result) {
1439 for (int i = 0; i < n; i++) {
1440 VertexArray v;
1441 result[i] = ctx->vertex_arrays.insert(v);
1442 }
1443}
1444
1445void DeleteVertexArray(GLuint n) {
1446 if (n && ctx->vertex_arrays.erase(n)) {
1447 unlink(ctx->current_vertex_array, n);
1448 }
1449}
1450
1451GLuint CreateShader(GLenum type) {
1452 Shader s;
1453 s.type = type;
1454 return ctx->shaders.insert(s);
1455}
1456
1457void ShaderSourceByName(GLuint shader, char* name) {
1458 Shader& s = ctx->shaders[shader];
1459 s.loader = load_shader(name);
1460 if (!s.loader) {
1461 debugf("unknown shader %s\n", name)printf("unknown shader %s\n", name);
1462 }
1463}
1464
1465void AttachShader(GLuint program, GLuint shader) {
1466 Program& p = ctx->programs[program];
1467 Shader& s = ctx->shaders[shader];
1468 if (s.type == GL_VERTEX_SHADER0x8B31) {
1469 if (!p.impl && s.loader) p.impl = s.loader();
1470 } else if (s.type == GL_FRAGMENT_SHADER0x8B30) {
1471 if (!p.impl && s.loader) p.impl = s.loader();
1472 } else {
1473 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1474 }
1475}
1476
1477void DeleteShader(GLuint n) {
1478 if (n) ctx->shaders.erase(n);
1479}
1480
1481GLuint CreateProgram() {
1482 Program p;
1483 return ctx->programs.insert(p);
1484}
1485
1486void DeleteProgram(GLuint n) {
1487 if (!n) return;
1488 if (ctx->current_program == n) {
1489 if (auto* p = ctx->programs.find(n)) {
1490 p->deleted = true;
1491 }
1492 } else {
1493 ctx->programs.erase(n);
1494 }
1495}
1496
1497void LinkProgram(GLuint program) {
1498 Program& p = ctx->programs[program];
1499 assert(p.impl)(static_cast <bool> (p.impl) ? void (0) : __assert_fail
("p.impl", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1500 if (!p.impl) {
1501 return;
1502 }
1503 assert(p.impl->interpolants_size() <= sizeof(Interpolants))(static_cast <bool> (p.impl->interpolants_size() <=
sizeof(Interpolants)) ? void (0) : __assert_fail ("p.impl->interpolants_size() <= sizeof(Interpolants)"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1504 if (!p.vert_impl) p.vert_impl = p.impl->get_vertex_shader();
1505 if (!p.frag_impl) p.frag_impl = p.impl->get_fragment_shader();
1506}
1507
1508GLint GetLinkStatus(GLuint program) {
1509 if (auto* p = ctx->programs.find(program)) {
1510 return p->impl ? 1 : 0;
1511 }
1512 return 0;
1513}
1514
1515void BindAttribLocation(GLuint program, GLuint index, char* name) {
1516 Program& p = ctx->programs[program];
1517 assert(p.impl)(static_cast <bool> (p.impl) ? void (0) : __assert_fail
("p.impl", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1518 if (!p.impl) {
1519 return;
1520 }
1521 p.impl->bind_attrib(name, index);
1522}
1523
1524GLint GetAttribLocation(GLuint program, char* name) {
1525 Program& p = ctx->programs[program];
1526 assert(p.impl)(static_cast <bool> (p.impl) ? void (0) : __assert_fail
("p.impl", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1527 if (!p.impl) {
1528 return -1;
1529 }
1530 return p.impl->get_attrib(name);
1531}
1532
1533GLint GetUniformLocation(GLuint program, char* name) {
1534 Program& p = ctx->programs[program];
1535 assert(p.impl)(static_cast <bool> (p.impl) ? void (0) : __assert_fail
("p.impl", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1536 if (!p.impl) {
1537 return -1;
1538 }
1539 GLint loc = p.impl->get_uniform(name);
1540 // debugf("location: %d\n", loc);
1541 return loc;
1542}
1543
1544static uint64_t get_time_value() {
1545#ifdef __MACH__
1546 return mach_absolute_time();
1547#elif defined(_WIN32)
1548 LARGE_INTEGER time;
1549 static bool have_frequency = false;
1550 static LARGE_INTEGER frequency;
1551 if (!have_frequency) {
1552 QueryPerformanceFrequency(&frequency);
1553 have_frequency = true;
1554 }
1555 QueryPerformanceCounter(&time);
1556 return time.QuadPart * 1000000000ULL / frequency.QuadPart;
1557#else
1558 return ({
1559 struct timespec tp;
1560 clock_gettime(CLOCK_MONOTONIC1, &tp);
1561 tp.tv_sec * 1000000000ULL + tp.tv_nsec;
1562 });
1563#endif
1564}
1565
1566void BeginQuery(GLenum target, GLuint id) {
1567 ctx->get_binding(target) = id;
1568 Query& q = ctx->queries[id];
1569 switch (target) {
1570 case GL_SAMPLES_PASSED0x8914:
1571 q.value = 0;
1572 break;
1573 case GL_TIME_ELAPSED0x88BF:
1574 q.value = get_time_value();
1575 break;
1576 default:
1577 debugf("unknown query target %x for query %d\n", target, id)printf("unknown query target %x for query %d\n", target, id);
1578 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1579 }
1580}
1581
1582void EndQuery(GLenum target) {
1583 Query& q = ctx->queries[ctx->get_binding(target)];
1584 switch (target) {
1585 case GL_SAMPLES_PASSED0x8914:
1586 break;
1587 case GL_TIME_ELAPSED0x88BF:
1588 q.value = get_time_value() - q.value;
1589 break;
1590 default:
1591 debugf("unknown query target %x\n", target)printf("unknown query target %x\n", target);
1592 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1593 }
1594 ctx->get_binding(target) = 0;
1595}
1596
1597void GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64* params) {
1598 Query& q = ctx->queries[id];
1599 switch (pname) {
1600 case GL_QUERY_RESULT0x8866:
1601 assert(params)(static_cast <bool> (params) ? void (0) : __assert_fail
("params", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1602 params[0] = q.value;
1603 break;
1604 default:
1605 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1606 }
1607}
1608
1609void BindVertexArray(GLuint vertex_array) {
1610 if (vertex_array != ctx->current_vertex_array) {
1611 ctx->validate_vertex_array = true;
1612 }
1613 ctx->current_vertex_array = vertex_array;
1614}
1615
1616void BindTexture(GLenum target, GLuint texture) {
1617 ctx->get_binding(target) = texture;
1618}
1619
1620void BindBuffer(GLenum target, GLuint buffer) {
1621 ctx->get_binding(target) = buffer;
1622}
1623
1624void BindFramebuffer(GLenum target, GLuint fb) {
1625 if (target == GL_FRAMEBUFFER0x8D40) {
1626 ctx->read_framebuffer_binding = fb;
1627 ctx->draw_framebuffer_binding = fb;
1628 } else {
1629 assert(target == GL_READ_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER)(static_cast <bool> (target == 0x8CA8 || target == 0x8CA9
) ? void (0) : __assert_fail ("target == GL_READ_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1630 ctx->get_binding(target) = fb;
1631 }
1632}
1633
1634void BindRenderbuffer(GLenum target, GLuint rb) {
1635 ctx->get_binding(target) = rb;
1636}
1637
1638void PixelStorei(GLenum name, GLint param) {
1639 if (name == GL_UNPACK_ALIGNMENT0x0CF5) {
1640 assert(param == 1)(static_cast <bool> (param == 1) ? void (0) : __assert_fail
("param == 1", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1641 } else if (name == GL_UNPACK_ROW_LENGTH0x0CF2) {
1642 ctx->unpack_row_length = param;
1643 }
1644}
1645
1646static GLenum remap_internal_format(GLenum format) {
1647 switch (format) {
1648 case GL_DEPTH_COMPONENT0x1902:
1649 return GL_DEPTH_COMPONENT240x81A6;
1650 case GL_RGBA0x1908:
1651 return GL_RGBA80x8058;
1652 case GL_RED0x1903:
1653 return GL_R80x8229;
1654 case GL_RG0x8227:
1655 return GL_RG80x822B;
1656 case GL_RGB_422_APPLE0x8A1F:
1657 return GL_RGB_RAW_422_APPLE0x8A51;
1658 default:
1659 return format;
1660 }
1661}
1662
1663} // extern "C"
1664
1665static bool format_requires_conversion(GLenum external_format,
1666 GLenum internal_format) {
1667 switch (external_format) {
1668 case GL_RGBA0x1908:
1669 return internal_format == GL_RGBA80x8058;
1670 case GL_RED0x1903:
1671 return internal_format != GL_R80x8229 && internal_format != GL_R160x822A;
1672 case GL_RG0x8227:
1673 return internal_format != GL_RG80x822B && internal_format != GL_RG160x822C;
1674 default:
1675 return false;
1676 }
1677}
1678
1679static inline void copy_bgra8_to_rgba8(uint32_t* dest, const uint32_t* src,
1680 int width) {
1681 for (; width >= 4; width -= 4, dest += 4, src += 4) {
1682 U32 p = unaligned_load<U32>(src);
1683 U32 rb = p & 0x00FF00FF;
1684 unaligned_store(dest, (p & 0xFF00FF00) | (rb << 16) | (rb >> 16));
1685 }
1686 for (; width > 0; width--, dest++, src++) {
1687 uint32_t p = *src;
1688 uint32_t rb = p & 0x00FF00FF;
1689 *dest = (p & 0xFF00FF00) | (rb << 16) | (rb >> 16);
1690 }
1691}
1692
1693static inline void copy_red_to_rgba32f(float* dest, const float* src,
1694 int width) {
1695 for (; width > 0; width--, dest += 4, src++) {
1696 dest[0] = *src;
1697 dest[1] = 0.0f;
1698 dest[2] = 0.0f;
1699 dest[3] = 1.0f;
1700 }
1701}
1702
1703static inline void copy_red_to_bgra8(uint8_t* dest, const uint8_t* src,
1704 int width) {
1705 for (; width > 0; width--, dest += 4, src++) {
1706 dest[0] = 0;
1707 dest[1] = 0;
1708 dest[2] = *src;
1709 dest[3] = 255;
1710 }
1711}
1712
1713template <typename T, size_t N = 1>
1714static int clip_ptrs_against_bounds(T*& dst_buf, T* dst_bound0, T* dst_bound1,
1715 const T*& src_buf, const T* src_bound0,
1716 const T* src_bound1, size_t& len) {
1717 if (dst_bound0) {
1718 assert(dst_bound0 <= dst_bound1)(static_cast <bool> (dst_bound0 <= dst_bound1) ? void
(0) : __assert_fail ("dst_bound0 <= dst_bound1", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
1719 if (dst_buf < dst_bound0) {
1720 size_t offset = size_t(dst_bound0 - dst_buf) / N;
1721 if (len <= offset) {
1722 // dst entirely before bounds
1723 len = 0;
1724 return -1;
1725 }
1726 // dst overlaps bound0
1727 src_buf += offset;
1728 dst_buf += offset * N;
1729 len -= offset;
1730 }
1731 if (dst_buf >= dst_bound1) {
1732 // dst entirely after bounds
1733 len = 0;
1734 return 1;
1735 }
1736 size_t remaining = size_t(dst_bound1 - dst_buf) / N;
1737 if (len > remaining) {
1738 // dst overlaps bound1
1739 len = remaining;
1740 }
1741 }
1742 if (src_bound0) {
1743 assert(src_bound0 <= src_bound1)(static_cast <bool> (src_bound0 <= src_bound1) ? void
(0) : __assert_fail ("src_bound0 <= src_bound1", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
1744 if (src_buf < src_bound0) {
1745 size_t offset = size_t(src_bound0 - src_buf);
1746 if (len <= offset) {
1747 // src entirely before bounds
1748 len = 0;
1749 return -1;
1750 }
1751 // src overlaps bound0
1752 src_buf += offset;
1753 dst_buf += offset * N;
1754 len -= offset;
1755 }
1756 if (src_buf >= src_bound1) {
1757 // src entirely after bounds
1758 len = 0;
1759 return 1;
1760 }
1761 size_t remaining = size_t(src_bound1 - src_buf);
1762 if (len > remaining) {
1763 // src overlaps bound1
1764 len = remaining;
1765 }
1766 }
1767 return 0;
1768}
1769
1770static void convert_copy(GLenum external_format, GLenum internal_format,
1771 uint8_t* dst_buf, size_t dst_stride,
1772 uint8_t* dst_bound0, uint8_t* dst_bound1,
1773 const uint8_t* src_buf, size_t src_stride,
1774 const uint8_t* src_bound0, const uint8_t* src_bound1,
1775 size_t width, size_t height) {
1776 switch (external_format) {
1777 case GL_RGBA0x1908:
1778 if (internal_format == GL_RGBA80x8058) {
1779 for (; height; height--) {
1780 size_t len = width;
1781 uint32_t* dst_ptr = (uint32_t*)dst_buf;
1782 const uint32_t* src_ptr = (const uint32_t*)src_buf;
1783 if (clip_ptrs_against_bounds(dst_ptr, (uint32_t*)dst_bound0,
1784 (uint32_t*)dst_bound1, src_ptr,
1785 (const uint32_t*)src_bound0,
1786 (const uint32_t*)src_bound1, len) > 0) {
1787 return;
1788 }
1789 if (len) {
1790 copy_bgra8_to_rgba8(dst_ptr, src_ptr, len);
1791 }
1792 dst_buf += dst_stride;
1793 src_buf += src_stride;
1794 }
1795 return;
1796 }
1797 break;
1798 case GL_RED0x1903:
1799 switch (internal_format) {
1800 case GL_RGBA80x8058:
1801 for (; height; height--) {
1802 size_t len = width;
1803 uint8_t* dst_ptr = dst_buf;
1804 const uint8_t* src_ptr = src_buf;
1805 if (clip_ptrs_against_bounds<uint8_t, 4>(
1806 dst_ptr, dst_bound0, dst_bound1, src_ptr, src_bound0,
1807 src_bound1, len) > 0) {
1808 return;
1809 }
1810 if (len) {
1811 copy_red_to_bgra8(dst_ptr, src_ptr, len);
1812 }
1813 dst_buf += dst_stride;
1814 src_buf += src_stride;
1815 }
1816 return;
1817 case GL_RGBA32F0x8814:
1818 for (; height; height--) {
1819 size_t len = width;
1820 float* dst_ptr = (float*)dst_buf;
1821 const float* src_ptr = (const float*)src_buf;
1822 if (clip_ptrs_against_bounds<float, 4>(
1823 dst_ptr, (float*)dst_bound0, (float*)dst_bound1, src_ptr,
1824 (const float*)src_bound0, (const float*)src_bound1,
1825 len) > 0) {
1826 return;
1827 }
1828 if (len) {
1829 copy_red_to_rgba32f(dst_ptr, src_ptr, len);
1830 }
1831 dst_buf += dst_stride;
1832 src_buf += src_stride;
1833 }
1834 return;
1835 case GL_R80x8229:
1836 break;
1837 default:
1838 debugf("unsupported format conversion from %x to %x\n",printf("unsupported format conversion from %x to %x\n", external_format
, internal_format)
1839 external_format, internal_format)printf("unsupported format conversion from %x to %x\n", external_format
, internal_format)
;
1840 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1841 return;
1842 }
1843 break;
1844 default:
1845 break;
1846 }
1847 size_t row_bytes = width * bytes_for_internal_format(internal_format);
1848 for (; height; height--) {
1849 size_t len = row_bytes;
1850 uint8_t* dst_ptr = dst_buf;
1851 const uint8_t* src_ptr = src_buf;
1852 if (clip_ptrs_against_bounds(dst_ptr, dst_bound0, dst_bound1, src_ptr,
1853 src_bound0, src_bound1, len) > 0) {
1854 return;
1855 }
1856 if (len) {
1857 memcpy(dst_ptr, src_ptr, len);
1858 }
1859 dst_buf += dst_stride;
1860 src_buf += src_stride;
1861 }
1862}
1863
1864static void set_tex_storage(Texture& t, GLenum external_format, GLsizei width,
1865 GLsizei height, void* buf = nullptr,
1866 GLsizei stride = 0, GLsizei min_width = 0,
1867 GLsizei min_height = 0) {
1868 GLenum internal_format = remap_internal_format(external_format);
1869 bool changed = false;
1870 if (t.width != width || t.height != height ||
1871 t.internal_format != internal_format) {
1872 changed = true;
1873 t.internal_format = internal_format;
1874 t.width = width;
1875 t.height = height;
1876 }
1877 // If we are changed from an internally managed buffer to an externally
1878 // supplied one or vice versa, ensure that we clean up old buffer state.
1879 // However, if we have to convert the data from a non-native format, then
1880 // always treat it as internally managed since we will need to copy to an
1881 // internally managed native format buffer.
1882 bool should_free = buf == nullptr || format_requires_conversion(
1883 external_format, internal_format);
1884 if (t.should_free() != should_free) {
1885 changed = true;
1886 t.cleanup();
1887 t.set_should_free(should_free);
1888 }
1889 // If now an external buffer, explicitly set it...
1890 if (!should_free) {
1891 t.set_buffer(buf, stride);
1892 }
1893 t.disable_delayed_clear();
1894 if (!t.allocate(changed, min_width, min_height)) {
1895 out_of_memory();
1896 }
1897 // If we have a buffer that needs format conversion, then do that now.
1898 if (buf && should_free) {
1899 convert_copy(external_format, internal_format, (uint8_t*)t.buf, t.stride(),
1900 (uint8_t*)t.buf, (uint8_t*)t.end_ptr(), (const uint8_t*)buf,
1901 stride, nullptr, nullptr, width, height);
1902 }
1903}
1904
1905extern "C" {
1906
1907void TexStorage2D(GLenum target, GLint levels, GLenum internal_format,
1908 GLsizei width, GLsizei height) {
1909 assert(levels == 1)(static_cast <bool> (levels == 1) ? void (0) : __assert_fail
("levels == 1", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1910 Texture& t = ctx->textures[ctx->get_binding(target)];
1911 set_tex_storage(t, internal_format, width, height);
1912}
1913
1914GLenum internal_format_for_data(GLenum format, GLenum ty) {
1915 if (format == GL_RED0x1903 && ty == GL_UNSIGNED_BYTE0x1401) {
1916 return GL_R80x8229;
1917 } else if ((format == GL_RGBA0x1908 || format == GL_BGRA0x80E1) &&
1918 (ty == GL_UNSIGNED_BYTE0x1401 || ty == GL_UNSIGNED_INT_8_8_8_8_REV0x8367)) {
1919 return GL_RGBA80x8058;
1920 } else if (format == GL_RGBA0x1908 && ty == GL_FLOAT0x1406) {
1921 return GL_RGBA32F0x8814;
1922 } else if (format == GL_RGBA_INTEGER0x8D99 && ty == GL_INT0x1404) {
1923 return GL_RGBA32I0x8D82;
1924 } else if (format == GL_RG0x8227 && ty == GL_UNSIGNED_BYTE0x1401) {
1925 return GL_RG80x822B;
1926 } else if (format == GL_RGB_422_APPLE0x8A1F &&
1927 ty == GL_UNSIGNED_SHORT_8_8_REV_APPLE0x85BB) {
1928 return GL_RGB_RAW_422_APPLE0x8A51;
1929 } else if (format == GL_RED0x1903 && ty == GL_UNSIGNED_SHORT0x1403) {
1930 return GL_R160x822A;
1931 } else if (format == GL_RG0x8227 && ty == GL_UNSIGNED_SHORT0x1403) {
1932 return GL_RG160x822C;
1933 } else {
1934 debugf("unknown internal format for format %x, type %x\n", format, ty)printf("unknown internal format for format %x, type %x\n", format
, ty)
;
1935 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1936 return 0;
1937 }
1938}
1939
1940static Buffer* get_pixel_pack_buffer() {
1941 return ctx->pixel_pack_buffer_binding
1942 ? &ctx->buffers[ctx->pixel_pack_buffer_binding]
1943 : nullptr;
1944}
1945
1946static Buffer* get_pixel_unpack_buffer() {
1947 return ctx->pixel_unpack_buffer_binding
1948 ? &ctx->buffers[ctx->pixel_unpack_buffer_binding]
1949 : nullptr;
1950}
1951
1952void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
1953 GLsizei width, GLsizei height, GLenum format, GLenum ty,
1954 void* data) {
1955 if (level != 0) {
1956 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1957 return;
1958 }
1959 Buffer* pbo = get_pixel_unpack_buffer();
1960 if (pbo) {
1961 data = pbo->get_data(data);
1962 }
1963 if (!data) return;
1964 Texture& t = ctx->textures[ctx->get_binding(target)];
1965 IntRect skip = {xoffset, yoffset, xoffset + width, yoffset + height};
1966 prepare_texture(t, &skip);
1967 assert(xoffset + width <= t.width)(static_cast <bool> (xoffset + width <= t.width) ? void
(0) : __assert_fail ("xoffset + width <= t.width", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
1968 assert(yoffset + height <= t.height)(static_cast <bool> (yoffset + height <= t.height) ?
void (0) : __assert_fail ("yoffset + height <= t.height",
__builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1969 assert(ctx->unpack_row_length == 0 || ctx->unpack_row_length >= width)(static_cast <bool> (ctx->unpack_row_length == 0 || ctx
->unpack_row_length >= width) ? void (0) : __assert_fail
("ctx->unpack_row_length == 0 || ctx->unpack_row_length >= width"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1970 GLsizei row_length =
1971 ctx->unpack_row_length != 0 ? ctx->unpack_row_length : width;
1972 assert(t.internal_format == internal_format_for_data(format, ty))(static_cast <bool> (t.internal_format == internal_format_for_data
(format, ty)) ? void (0) : __assert_fail ("t.internal_format == internal_format_for_data(format, ty)"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1973 int src_bpp = format_requires_conversion(format, t.internal_format)
1974 ? bytes_for_internal_format(format)
1975 : t.bpp();
1976 if (!src_bpp || !t.buf) return;
1977 convert_copy(format, t.internal_format,
1978 (uint8_t*)t.sample_ptr(xoffset, yoffset), t.stride(),
1979 (uint8_t*)t.buf, (uint8_t*)t.end_ptr(), (const uint8_t*)data,
1980 row_length * src_bpp, pbo ? (const uint8_t*)pbo->buf : nullptr,
1981 pbo ? (const uint8_t*)pbo->end_ptr() : nullptr, width, height);
1982}
1983
1984void TexImage2D(GLenum target, GLint level, GLint internal_format,
1985 GLsizei width, GLsizei height, GLint border, GLenum format,
1986 GLenum ty, void* data) {
1987 if (level != 0) {
1988 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
1989 return;
1990 }
1991 assert(border == 0)(static_cast <bool> (border == 0) ? void (0) : __assert_fail
("border == 0", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
1992 TexStorage2D(target, 1, internal_format, width, height);
1993 TexSubImage2D(target, 0, 0, 0, width, height, format, ty, data);
1994}
1995
1996void GenerateMipmap(UNUSED[[maybe_unused]] GLenum target) {
1997 // TODO: support mipmaps
1998}
1999
2000void SetTextureParameter(GLuint texid, GLenum pname, GLint param) {
2001 Texture& t = ctx->textures[texid];
2002 switch (pname) {
2003 case GL_TEXTURE_WRAP_S0x2802:
2004 assert(param == GL_CLAMP_TO_EDGE)(static_cast <bool> (param == 0x812F) ? void (0) : __assert_fail
("param == GL_CLAMP_TO_EDGE", __builtin_FILE (), __builtin_LINE
(), __extension__ __PRETTY_FUNCTION__))
;
2005 break;
2006 case GL_TEXTURE_WRAP_T0x2803:
2007 assert(param == GL_CLAMP_TO_EDGE)(static_cast <bool> (param == 0x812F) ? void (0) : __assert_fail
("param == GL_CLAMP_TO_EDGE", __builtin_FILE (), __builtin_LINE
(), __extension__ __PRETTY_FUNCTION__))
;
2008 break;
2009 case GL_TEXTURE_MIN_FILTER0x2801:
2010 t.min_filter = param;
2011 break;
2012 case GL_TEXTURE_MAG_FILTER0x2800:
2013 t.mag_filter = param;
2014 break;
2015 default:
2016 break;
2017 }
2018}
2019
2020void TexParameteri(GLenum target, GLenum pname, GLint param) {
2021 SetTextureParameter(ctx->get_binding(target), pname, param);
2022}
2023
2024typedef Texture LockedTexture;
2025
2026// Lock the given texture to prevent modification.
2027LockedTexture* LockTexture(GLuint texId) {
2028 Texture& tex = ctx->textures[texId];
2029 if (!tex.buf) {
2030 assert(tex.buf != nullptr)(static_cast <bool> (tex.buf != nullptr) ? void (0) : __assert_fail
("tex.buf != nullptr", __builtin_FILE (), __builtin_LINE (),
__extension__ __PRETTY_FUNCTION__))
;
2031 return nullptr;
2032 }
2033 if (__sync_fetch_and_add(&tex.locked, 1) == 0) {
2034 // If this is the first time locking the texture, flush any delayed clears.
2035 prepare_texture(tex);
2036 }
2037 return (LockedTexture*)&tex;
2038}
2039
2040// Lock the given framebuffer's color attachment to prevent modification.
2041LockedTexture* LockFramebuffer(GLuint fboId) {
2042 Framebuffer& fb = ctx->framebuffers[fboId];
2043 // Only allow locking a framebuffer if it has a valid color attachment.
2044 if (!fb.color_attachment) {
2045 assert(fb.color_attachment != 0)(static_cast <bool> (fb.color_attachment != 0) ? void (
0) : __assert_fail ("fb.color_attachment != 0", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
2046 return nullptr;
2047 }
2048 return LockTexture(fb.color_attachment);
2049}
2050
2051// Reference an already locked resource
2052void LockResource(LockedTexture* resource) {
2053 if (!resource) {
2054 return;
2055 }
2056 __sync_fetch_and_add(&resource->locked, 1);
2057}
2058
2059// Remove a lock on a texture that has been previously locked
2060int32_t UnlockResource(LockedTexture* resource) {
2061 if (!resource) {
2062 return -1;
2063 }
2064 int32_t locked = __sync_fetch_and_add(&resource->locked, -1);
2065 if (locked <= 0) {
2066 // The lock should always be non-zero before unlocking.
2067 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2068 } else if (locked == 1 && resource->zombie()) {
2069 // If the resource is being kept alive by locks and this is the last lock,
2070 // then delete the resource now.
2071 delete resource;
2072 }
2073 return locked - 1;
2074}
2075
2076void GenTextures(int n, GLuint* result) {
2077 for (int i = 0; i < n; i++) {
2078 Texture t;
2079 result[i] = ctx->textures.insert(t);
2080 }
2081}
2082
2083void DeleteTexture(GLuint n) {
2084 if (!n) {
2085 return;
2086 }
2087 LockedTexture* tex = (LockedTexture*)ctx->textures.find(n);
2088 if (!tex) {
2089 return;
2090 }
2091 // Lock the texture so that it can't be deleted by another thread yet.
2092 LockResource(tex);
2093 // Forget the existing binding to the texture but keep it alive in case there
2094 // are any other locks on it.
2095 if (ctx->textures.erase(n, false)) {
2096 for (size_t i = 0; i < MAX_TEXTURE_UNITS; i++) {
2097 ctx->texture_units[i].unlink(n);
2098 }
2099 }
2100 // Mark the texture as a zombie so that it will be freed if there are no other
2101 // existing locks on it.
2102 tex->set_zombie(true);
2103 if (int32_t locked = UnlockResource(tex)) {
2104 debugf("DeleteTexture(%u) with %d locks\n", n, locked)printf("DeleteTexture(%u) with %d locks\n", n, locked);
2105 }
2106}
2107
2108void GenRenderbuffers(int n, GLuint* result) {
2109 for (int i = 0; i < n; i++) {
2110 Renderbuffer r;
2111 result[i] = ctx->renderbuffers.insert(r);
2112 }
2113}
2114
2115void Renderbuffer::on_erase() {
2116 for (auto* fb : ctx->framebuffers) {
2117 if (fb) {
2118 unlink(fb->color_attachment, texture);
2119 unlink(fb->depth_attachment, texture);
2120 }
2121 }
2122 DeleteTexture(texture);
2123}
2124
2125void DeleteRenderbuffer(GLuint n) {
2126 if (n && ctx->renderbuffers.erase(n)) {
2127 unlink(ctx->renderbuffer_binding, n);
2128 }
2129}
2130
2131void GenFramebuffers(int n, GLuint* result) {
2132 for (int i = 0; i < n; i++) {
2133 Framebuffer f;
2134 result[i] = ctx->framebuffers.insert(f);
2135 }
2136}
2137
2138void DeleteFramebuffer(GLuint n) {
2139 if (n && ctx->framebuffers.erase(n)) {
2140 unlink(ctx->read_framebuffer_binding, n);
2141 unlink(ctx->draw_framebuffer_binding, n);
2142 }
2143}
2144
2145void RenderbufferStorage(GLenum target, GLenum internal_format, GLsizei width,
2146 GLsizei height) {
2147 // Just refer a renderbuffer to a texture to simplify things for now...
2148 Renderbuffer& r = ctx->renderbuffers[ctx->get_binding(target)];
2149 if (!r.texture) {
2150 GenTextures(1, &r.texture);
2151 }
2152 switch (internal_format) {
2153 case GL_DEPTH_COMPONENT0x1902:
2154 case GL_DEPTH_COMPONENT160x81A5:
2155 case GL_DEPTH_COMPONENT240x81A6:
2156 case GL_DEPTH_COMPONENT320x81A7:
2157 // Force depth format to 24 bits...
2158 internal_format = GL_DEPTH_COMPONENT240x81A6;
2159 break;
2160 }
2161 set_tex_storage(ctx->textures[r.texture], internal_format, width, height);
2162}
2163
2164void VertexAttribPointer(GLuint index, GLint size, GLenum type, bool normalized,
2165 GLsizei stride, GLuint offset) {
2166 // debugf("cva: %d\n", ctx->current_vertex_array);
2167 VertexArray& v = ctx->vertex_arrays[ctx->current_vertex_array];
2168 if (index >= NULL_ATTRIB16) {
2169 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2170 return;
2171 }
2172 VertexAttrib& va = v.attribs[index];
2173 va.size = size * bytes_per_type(type);
2174 va.type = type;
2175 va.normalized = normalized;
2176 va.stride = stride;
2177 va.offset = offset;
2178 // Buffer &vertex_buf = ctx->buffers[ctx->array_buffer_binding];
2179 va.vertex_buffer = ctx->array_buffer_binding;
2180 va.vertex_array = ctx->current_vertex_array;
2181 ctx->validate_vertex_array = true;
2182}
2183
2184void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride,
2185 GLuint offset) {
2186 // debugf("cva: %d\n", ctx->current_vertex_array);
2187 VertexArray& v = ctx->vertex_arrays[ctx->current_vertex_array];
2188 if (index >= NULL_ATTRIB16) {
2189 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2190 return;
2191 }
2192 VertexAttrib& va = v.attribs[index];
2193 va.size = size * bytes_per_type(type);
2194 va.type = type;
2195 va.normalized = false;
2196 va.stride = stride;
2197 va.offset = offset;
2198 // Buffer &vertex_buf = ctx->buffers[ctx->array_buffer_binding];
2199 va.vertex_buffer = ctx->array_buffer_binding;
2200 va.vertex_array = ctx->current_vertex_array;
2201 ctx->validate_vertex_array = true;
2202}
2203
2204void EnableVertexAttribArray(GLuint index) {
2205 VertexArray& v = ctx->vertex_arrays[ctx->current_vertex_array];
2206 if (index >= NULL_ATTRIB16) {
2207 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2208 return;
2209 }
2210 VertexAttrib& va = v.attribs[index];
2211 if (!va.enabled) {
2212 ctx->validate_vertex_array = true;
2213 }
2214 va.enabled = true;
2215 v.max_attrib = max(v.max_attrib, (int)index);
2216}
2217
2218void DisableVertexAttribArray(GLuint index) {
2219 VertexArray& v = ctx->vertex_arrays[ctx->current_vertex_array];
2220 if (index >= NULL_ATTRIB16) {
2221 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2222 return;
2223 }
2224 VertexAttrib& va = v.attribs[index];
2225 if (va.enabled) {
2226 ctx->validate_vertex_array = true;
2227 }
2228 va.disable();
2229}
2230
2231void VertexAttribDivisor(GLuint index, GLuint divisor) {
2232 VertexArray& v = ctx->vertex_arrays[ctx->current_vertex_array];
2233 // Only support divisor being 0 (per-vertex) or 1 (per-instance).
2234 if (index >= NULL_ATTRIB16 || divisor > 1) {
2235 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2236 return;
2237 }
2238 VertexAttrib& va = v.attribs[index];
2239 va.divisor = divisor;
2240}
2241
2242void BufferData(GLenum target, GLsizeiptr size, void* data,
2243 UNUSED[[maybe_unused]] GLenum usage) {
2244 if (size < 0) {
2245 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2246 return;
2247 }
2248 Buffer& b = ctx->buffers[ctx->get_binding(target)];
2249 if (size != b.size) {
2250 if (!b.allocate(size)) {
2251 out_of_memory();
2252 }
2253 ctx->validate_vertex_array = true;
2254 }
2255 if (data && b.buf && size <= b.size) {
2256 memcpy(b.buf, data, size);
2257 }
2258}
2259
2260void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
2261 void* data) {
2262 if (offset < 0 || size < 0) {
2263 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2264 return;
2265 }
2266 Buffer& b = ctx->buffers[ctx->get_binding(target)];
2267 assert(offset < b.size && size <= b.size - offset)(static_cast <bool> (offset < b.size && size
<= b.size - offset) ? void (0) : __assert_fail ("offset < b.size && size <= b.size - offset"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2268 if (data && b.buf && offset < b.size && size <= b.size - offset) {
2269 memcpy(&b.buf[offset], data, size);
2270 }
2271}
2272
2273void* MapBuffer(GLenum target, UNUSED[[maybe_unused]] GLbitfield access) {
2274 Buffer& b = ctx->buffers[ctx->get_binding(target)];
2275 return b.buf;
2276}
2277
2278void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
2279 UNUSED[[maybe_unused]] GLbitfield access) {
2280 Buffer& b = ctx->buffers[ctx->get_binding(target)];
2281 if (b.buf && offset >= 0 && length > 0 && offset < b.size &&
2282 length <= b.size - offset) {
2283 return b.buf + offset;
2284 }
2285 return nullptr;
2286}
2287
2288GLboolean UnmapBuffer(GLenum target) {
2289 Buffer& b = ctx->buffers[ctx->get_binding(target)];
2290 return b.buf != nullptr;
2291}
2292
2293void Uniform1i(GLint location, GLint V0) {
2294 // debugf("tex: %d\n", (int)ctx->textures.size);
2295 if (vertex_shader) {
2296 vertex_shader->set_uniform_1i(location, V0);
2297 }
2298}
2299void Uniform4fv(GLint location, GLsizei count, const GLfloat* v) {
2300 assert(count == 1)(static_cast <bool> (count == 1) ? void (0) : __assert_fail
("count == 1", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
2301 if (vertex_shader) {
2302 vertex_shader->set_uniform_4fv(location, v);
2303 }
2304}
2305void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,
2306 const GLfloat* value) {
2307 assert(count == 1)(static_cast <bool> (count == 1) ? void (0) : __assert_fail
("count == 1", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
2308 assert(!transpose)(static_cast <bool> (!transpose) ? void (0) : __assert_fail
("!transpose", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
2309 if (vertex_shader) {
2310 vertex_shader->set_uniform_matrix4fv(location, value);
2311 }
2312}
2313
2314void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget,
2315 GLuint texture, GLint level) {
2316 assert(target == GL_READ_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER)(static_cast <bool> (target == 0x8CA8 || target == 0x8CA9
) ? void (0) : __assert_fail ("target == GL_READ_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2317 assert(textarget == GL_TEXTURE_2D || textarget == GL_TEXTURE_RECTANGLE)(static_cast <bool> (textarget == 0x0DE1 || textarget ==
0x84F5) ? void (0) : __assert_fail ("textarget == GL_TEXTURE_2D || textarget == GL_TEXTURE_RECTANGLE"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2318 assert(level == 0)(static_cast <bool> (level == 0) ? void (0) : __assert_fail
("level == 0", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
2319 Framebuffer& fb = ctx->framebuffers[ctx->get_binding(target)];
2320 if (attachment == GL_COLOR_ATTACHMENT00x8CE0) {
2321 fb.color_attachment = texture;
2322 } else if (attachment == GL_DEPTH_ATTACHMENT0x8D00) {
2323 fb.depth_attachment = texture;
2324 } else {
2325 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2326 }
2327}
2328
2329void FramebufferRenderbuffer(GLenum target, GLenum attachment,
2330 GLenum renderbuffertarget, GLuint renderbuffer) {
2331 assert(target == GL_READ_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER)(static_cast <bool> (target == 0x8CA8 || target == 0x8CA9
) ? void (0) : __assert_fail ("target == GL_READ_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2332 assert(renderbuffertarget == GL_RENDERBUFFER)(static_cast <bool> (renderbuffertarget == 0x8D41) ? void
(0) : __assert_fail ("renderbuffertarget == GL_RENDERBUFFER"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2333 Framebuffer& fb = ctx->framebuffers[ctx->get_binding(target)];
2334 Renderbuffer& rb = ctx->renderbuffers[renderbuffer];
2335 if (attachment == GL_COLOR_ATTACHMENT00x8CE0) {
2336 fb.color_attachment = rb.texture;
2337 } else if (attachment == GL_DEPTH_ATTACHMENT0x8D00) {
2338 fb.depth_attachment = rb.texture;
2339 } else {
2340 assert(0)(static_cast <bool> (0) ? void (0) : __assert_fail ("0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2341 }
2342}
2343
2344} // extern "C"
2345
2346static inline Framebuffer* get_framebuffer(GLenum target,
2347 bool fallback = false) {
2348 if (target == GL_FRAMEBUFFER0x8D40) {
2349 target = GL_DRAW_FRAMEBUFFER0x8CA9;
2350 }
2351 Framebuffer* fb = ctx->framebuffers.find(ctx->get_binding(target));
2352 if (fallback && !fb) {
2353 // If the specified framebuffer isn't found and a fallback is requested,
2354 // use the default framebuffer.
2355 fb = &ctx->framebuffers[0];
2356 }
2357 return fb;
2358}
2359
2360template <typename T>
2361static inline void fill_n(T* dst, size_t n, T val) {
2362 for (T* end = &dst[n]; dst < end; dst++) *dst = val;
2363}
2364
2365#if USE_SSE21
2366template <>
2367inline void fill_n<uint32_t>(uint32_t* dst, size_t n, uint32_t val) {
2368 __asm__ __volatile__("rep stosl\n"
2369 : "+D"(dst), "+c"(n)
2370 : "a"(val)
2371 : "memory", "cc");
2372}
2373#endif
2374
2375static inline uint32_t clear_chunk(uint8_t value) {
2376 return uint32_t(value) * 0x01010101U;
2377}
2378
2379static inline uint32_t clear_chunk(uint16_t value) {
2380 return uint32_t(value) | (uint32_t(value) << 16);
2381}
2382
2383static inline uint32_t clear_chunk(uint32_t value) { return value; }
2384
2385template <typename T>
2386static inline void clear_row(T* buf, size_t len, T value, uint32_t chunk) {
2387 const size_t N = sizeof(uint32_t) / sizeof(T);
2388 // fill any leading unaligned values
2389 if (N > 1) {
2390 size_t align = (-(intptr_t)buf & (sizeof(uint32_t) - 1)) / sizeof(T);
2391 if (align <= len) {
2392 fill_n(buf, align, value);
2393 len -= align;
2394 buf += align;
2395 }
2396 }
2397 // fill as many aligned chunks as possible
2398 fill_n((uint32_t*)buf, len / N, chunk);
2399 // fill any remaining values
2400 if (N > 1) {
2401 fill_n(buf + (len & ~(N - 1)), len & (N - 1), value);
2402 }
2403}
2404
2405template <typename T>
2406static void clear_buffer(Texture& t, T value, IntRect bb, int skip_start = 0,
2407 int skip_end = 0) {
2408 if (!t.buf) return;
2409 skip_start = max(skip_start, bb.x0);
2410 skip_end = max(skip_end, skip_start);
2411 assert(sizeof(T) == t.bpp())(static_cast <bool> (sizeof(T) == t.bpp()) ? void (0) :
__assert_fail ("sizeof(T) == t.bpp()", __builtin_FILE (), __builtin_LINE
(), __extension__ __PRETTY_FUNCTION__))
;
2412 size_t stride = t.stride();
2413 // When clearing multiple full-width rows, collapse them into a single large
2414 // "row" to avoid redundant setup from clearing each row individually. Note
2415 // that we can only safely do this if the stride is tightly packed.
2416 if (bb.width() == t.width && bb.height() > 1 && skip_start >= skip_end &&
2417 (t.should_free() || stride == t.width * sizeof(T))) {
2418 bb.x1 += (stride / sizeof(T)) * (bb.height() - 1);
2419 bb.y1 = bb.y0 + 1;
2420 }
2421 T* buf = (T*)t.sample_ptr(bb.x0, bb.y0);
2422 uint32_t chunk = clear_chunk(value);
2423 for (int rows = bb.height(); rows > 0; rows--) {
2424 if (bb.x0 < skip_start) {
2425 clear_row(buf, skip_start - bb.x0, value, chunk);
2426 }
2427 if (skip_end < bb.x1) {
2428 clear_row(buf + (skip_end - bb.x0), bb.x1 - skip_end, value, chunk);
2429 }
2430 buf += stride / sizeof(T);
2431 }
2432}
2433
2434template <typename T>
2435static inline void force_clear_row(Texture& t, int y, int skip_start = 0,
2436 int skip_end = 0) {
2437 assert(t.buf != nullptr)(static_cast <bool> (t.buf != nullptr) ? void (0) : __assert_fail
("t.buf != nullptr", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
2438 assert(sizeof(T) == t.bpp())(static_cast <bool> (sizeof(T) == t.bpp()) ? void (0) :
__assert_fail ("sizeof(T) == t.bpp()", __builtin_FILE (), __builtin_LINE
(), __extension__ __PRETTY_FUNCTION__))
;
2439 assert(skip_start <= skip_end)(static_cast <bool> (skip_start <= skip_end) ? void (
0) : __assert_fail ("skip_start <= skip_end", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
2440 T* buf = (T*)t.sample_ptr(0, y);
2441 uint32_t chunk = clear_chunk((T)t.clear_val);
2442 if (skip_start > 0) {
2443 clear_row<T>(buf, skip_start, t.clear_val, chunk);
2444 }
2445 if (skip_end < t.width) {
2446 clear_row<T>(buf + skip_end, t.width - skip_end, t.clear_val, chunk);
2447 }
2448}
2449
2450template <typename T>
2451static void force_clear(Texture& t, const IntRect* skip = nullptr) {
2452 if (!t.delay_clear || !t.cleared_rows) {
2453 return;
2454 }
2455 int y0 = 0;
2456 int y1 = t.height;
2457 int skip_start = 0;
2458 int skip_end = 0;
2459 if (skip) {
2460 y0 = clamp(skip->y0, 0, t.height);
2461 y1 = clamp(skip->y1, y0, t.height);
2462 skip_start = clamp(skip->x0, 0, t.width);
2463 skip_end = clamp(skip->x1, skip_start, t.width);
2464 if (skip_start <= 0 && skip_end >= t.width && y0 <= 0 && y1 >= t.height) {
2465 t.disable_delayed_clear();
2466 return;
2467 }
2468 }
2469 int num_masks = (y1 + 31) / 32;
2470 uint32_t* rows = t.cleared_rows;
2471 for (int i = y0 / 32; i < num_masks; i++) {
2472 uint32_t mask = rows[i];
2473 if (mask != ~0U) {
2474 rows[i] = ~0U;
2475 int start = i * 32;
2476 while (mask) {
2477 int count = __builtin_ctz(mask);
2478 if (count > 0) {
2479 clear_buffer<T>(t, t.clear_val,
2480 IntRect{0, start, t.width, start + count}, skip_start,
2481 skip_end);
2482 t.delay_clear -= count;
2483 start += count;
2484 mask >>= count;
2485 }
2486 count = __builtin_ctz(mask + 1);
2487 start += count;
2488 mask >>= count;
2489 }
2490 int count = (i + 1) * 32 - start;
2491 if (count > 0) {
2492 clear_buffer<T>(t, t.clear_val,
2493 IntRect{0, start, t.width, start + count}, skip_start,
2494 skip_end);
2495 t.delay_clear -= count;
2496 }
2497 }
2498 }
2499 if (t.delay_clear <= 0) t.disable_delayed_clear();
2500}
2501
2502static void prepare_texture(Texture& t, const IntRect* skip) {
2503 if (t.delay_clear) {
2504 switch (t.internal_format) {
2505 case GL_RGBA80x8058:
2506 force_clear<uint32_t>(t, skip);
2507 break;
2508 case GL_R80x8229:
2509 force_clear<uint8_t>(t, skip);
2510 break;
2511 case GL_RG80x822B:
2512 force_clear<uint16_t>(t, skip);
2513 break;
2514 default:
2515 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2516 break;
2517 }
2518 }
2519}
2520
2521// Setup a clear on a texture. This may either force an immediate clear or
2522// potentially punt to a delayed clear, if applicable.
2523template <typename T>
2524static void request_clear(Texture& t, T value, const IntRect& scissor) {
2525 // If the clear would require a scissor, force clear anything outside
2526 // the scissor, and then immediately clear anything inside the scissor.
2527 if (!scissor.contains(t.offset_bounds())) {
2528 IntRect skip = scissor - t.offset;
2529 force_clear<T>(t, &skip);
2530 clear_buffer<T>(t, value, skip.intersection(t.bounds()));
2531 } else {
2532 // Do delayed clear for 2D texture without scissor.
2533 t.enable_delayed_clear(value);
2534 }
2535}
2536
2537template <typename T>
2538static inline void request_clear(Texture& t, T value) {
2539 // If scissoring is enabled, use the scissor rect. Otherwise, just scissor to
2540 // the entire texture bounds.
2541 request_clear(t, value, ctx->scissortest ? ctx->scissor : t.offset_bounds());
2542}
2543
2544extern "C" {
2545
2546void InitDefaultFramebuffer(int x, int y, int width, int height, int stride,
2547 void* buf) {
2548 Framebuffer& fb = ctx->framebuffers[0];
2549 if (!fb.color_attachment) {
2550 GenTextures(1, &fb.color_attachment);
2551 }
2552 // If the dimensions or buffer properties changed, we need to reallocate
2553 // the underlying storage for the color buffer texture.
2554 Texture& colortex = ctx->textures[fb.color_attachment];
2555 set_tex_storage(colortex, GL_RGBA80x8058, width, height, buf, stride);
2556 colortex.offset = IntPoint(x, y);
2557 if (!fb.depth_attachment) {
2558 GenTextures(1, &fb.depth_attachment);
2559 }
2560 // Ensure dimensions of the depth buffer match the color buffer.
2561 Texture& depthtex = ctx->textures[fb.depth_attachment];
2562 set_tex_storage(depthtex, GL_DEPTH_COMPONENT240x81A6, width, height);
2563 depthtex.offset = IntPoint(x, y);
2564}
2565
2566void* GetColorBuffer(GLuint fbo, GLboolean flush, int32_t* width,
2567 int32_t* height, int32_t* stride) {
2568 Framebuffer* fb = ctx->framebuffers.find(fbo);
2569 if (!fb || !fb->color_attachment) {
2570 return nullptr;
2571 }
2572 Texture& colortex = ctx->textures[fb->color_attachment];
2573 if (flush) {
2574 prepare_texture(colortex);
2575 }
2576 assert(colortex.offset == IntPoint(0, 0))(static_cast <bool> (colortex.offset == IntPoint(0, 0))
? void (0) : __assert_fail ("colortex.offset == IntPoint(0, 0)"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2577 if (width) {
2578 *width = colortex.width;
2579 }
2580 if (height) {
2581 *height = colortex.height;
2582 }
2583 if (stride) {
2584 *stride = colortex.stride();
2585 }
2586 return colortex.buf ? colortex.sample_ptr(0, 0) : nullptr;
2587}
2588
2589void ResolveFramebuffer(GLuint fbo) {
2590 Framebuffer* fb = ctx->framebuffers.find(fbo);
2591 if (!fb || !fb->color_attachment) {
2592 return;
2593 }
2594 Texture& colortex = ctx->textures[fb->color_attachment];
2595 prepare_texture(colortex);
2596}
2597
2598void SetTextureBuffer(GLuint texid, GLenum internal_format, GLsizei width,
2599 GLsizei height, GLsizei stride, void* buf,
2600 GLsizei min_width, GLsizei min_height) {
2601 Texture& t = ctx->textures[texid];
2602 set_tex_storage(t, internal_format, width, height, buf, stride, min_width,
2603 min_height);
2604}
2605
2606GLenum CheckFramebufferStatus(GLenum target) {
2607 Framebuffer* fb = get_framebuffer(target);
2608 if (!fb || !fb->color_attachment) {
2609 return GL_FRAMEBUFFER_UNSUPPORTED0x8CDD;
2610 }
2611 return GL_FRAMEBUFFER_COMPLETE0x8CD5;
2612}
2613
2614void ClearTexSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset,
2615 GLint zoffset, GLsizei width, GLsizei height,
2616 GLsizei depth, GLenum format, GLenum type,
2617 const void* data) {
2618 if (level != 0) {
2619 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2620 return;
2621 }
2622 Texture& t = ctx->textures[texture];
2623 assert(!t.locked)(static_cast <bool> (!t.locked) ? void (0) : __assert_fail
("!t.locked", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
2624 if (width <= 0 || height <= 0 || depth <= 0) {
2625 return;
2626 }
2627 assert(zoffset == 0 && depth == 1)(static_cast <bool> (zoffset == 0 && depth == 1
) ? void (0) : __assert_fail ("zoffset == 0 && depth == 1"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2628 IntRect scissor = {xoffset, yoffset, xoffset + width, yoffset + height};
2629 if (t.internal_format == GL_DEPTH_COMPONENT240x81A6) {
2630 uint32_t value = 0xFFFFFF;
2631 switch (format) {
2632 case GL_DEPTH_COMPONENT0x1902:
2633 switch (type) {
2634 case GL_DOUBLE0x1408:
2635 value = uint32_t(*(const GLdouble*)data * 0xFFFFFF);
2636 break;
2637 case GL_FLOAT0x1406:
2638 value = uint32_t(*(const GLfloat*)data * 0xFFFFFF);
2639 break;
2640 default:
2641 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2642 break;
2643 }
2644 break;
2645 default:
2646 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2647 break;
2648 }
2649 if (t.cleared() && !scissor.contains(t.offset_bounds())) {
2650 // If we need to scissor the clear and the depth buffer was already
2651 // initialized, then just fill runs for that scissor area.
2652 t.fill_depth_runs(value, scissor);
2653 } else {
2654 // Otherwise, the buffer is either uninitialized or the clear would
2655 // encompass the entire buffer. If uninitialized, we can safely fill
2656 // the entire buffer with any value and thus ignore any scissoring.
2657 t.init_depth_runs(value);
2658 }
2659 return;
2660 }
2661
2662 uint32_t color = 0xFF000000;
2663 switch (type) {
2664 case GL_FLOAT0x1406: {
2665 const GLfloat* f = (const GLfloat*)data;
2666 Float v = {0.0f, 0.0f, 0.0f, 1.0f};
2667 switch (format) {
2668 case GL_RGBA0x1908:
2669 v.w = f[3]; // alpha
2670 FALLTHROUGH[[fallthrough]];
2671 case GL_RGB0x1907:
2672 v.z = f[2]; // blue
2673 FALLTHROUGH[[fallthrough]];
2674 case GL_RG0x8227:
2675 v.y = f[1]; // green
2676 FALLTHROUGH[[fallthrough]];
2677 case GL_RED0x1903:
2678 v.x = f[0]; // red
2679 break;
2680 default:
2681 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2682 break;
2683 }
2684 color = bit_cast<uint32_t>(CONVERT(round_pixel(v), U8)__builtin_convertvector(round_pixel(v), U8));
2685 break;
2686 }
2687 case GL_UNSIGNED_BYTE0x1401: {
2688 const GLubyte* b = (const GLubyte*)data;
2689 switch (format) {
2690 case GL_RGBA0x1908:
2691 color = (color & ~0xFF000000) | (uint32_t(b[3]) << 24); // alpha
2692 FALLTHROUGH[[fallthrough]];
2693 case GL_RGB0x1907:
2694 color = (color & ~0x00FF0000) | (uint32_t(b[2]) << 16); // blue
2695 FALLTHROUGH[[fallthrough]];
2696 case GL_RG0x8227:
2697 color = (color & ~0x0000FF00) | (uint32_t(b[1]) << 8); // green
2698 FALLTHROUGH[[fallthrough]];
2699 case GL_RED0x1903:
2700 color = (color & ~0x000000FF) | uint32_t(b[0]); // red
2701 break;
2702 default:
2703 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2704 break;
2705 }
2706 break;
2707 }
2708 default:
2709 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2710 break;
2711 }
2712
2713 switch (t.internal_format) {
2714 case GL_RGBA80x8058:
2715 // Clear color needs to swizzle to BGRA.
2716 request_clear<uint32_t>(t,
2717 (color & 0xFF00FF00) |
2718 ((color << 16) & 0xFF0000) |
2719 ((color >> 16) & 0xFF),
2720 scissor);
2721 break;
2722 case GL_R80x8229:
2723 request_clear<uint8_t>(t, uint8_t(color & 0xFF), scissor);
2724 break;
2725 case GL_RG80x822B:
2726 request_clear<uint16_t>(t, uint16_t(color & 0xFFFF), scissor);
2727 break;
2728 default:
2729 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2730 break;
2731 }
2732}
2733
2734void ClearTexImage(GLuint texture, GLint level, GLenum format, GLenum type,
2735 const void* data) {
2736 Texture& t = ctx->textures[texture];
2737 IntRect scissor = t.offset_bounds();
2738 ClearTexSubImage(texture, level, scissor.x0, scissor.y0, 0, scissor.width(),
2739 scissor.height(), 1, format, type, data);
2740}
2741
2742void Clear(GLbitfield mask) {
2743 Framebuffer& fb = *get_framebuffer(GL_DRAW_FRAMEBUFFER0x8CA9, true);
2744 if ((mask & GL_COLOR_BUFFER_BIT0x00004000) && fb.color_attachment) {
2745 Texture& t = ctx->textures[fb.color_attachment];
2746 IntRect scissor = ctx->scissortest
2747 ? ctx->scissor.intersection(t.offset_bounds())
2748 : t.offset_bounds();
2749 ClearTexSubImage(fb.color_attachment, 0, scissor.x0, scissor.y0, 0,
2750 scissor.width(), scissor.height(), 1, GL_RGBA0x1908, GL_FLOAT0x1406,
2751 ctx->clearcolor);
2752 }
2753 if ((mask & GL_DEPTH_BUFFER_BIT0x00000100) && fb.depth_attachment) {
2754 Texture& t = ctx->textures[fb.depth_attachment];
2755 IntRect scissor = ctx->scissortest
2756 ? ctx->scissor.intersection(t.offset_bounds())
2757 : t.offset_bounds();
2758 ClearTexSubImage(fb.depth_attachment, 0, scissor.x0, scissor.y0, 0,
2759 scissor.width(), scissor.height(), 1, GL_DEPTH_COMPONENT0x1902,
2760 GL_DOUBLE0x1408, &ctx->cleardepth);
2761 }
2762}
2763
2764void ClearColorRect(GLuint fbo, GLint xoffset, GLint yoffset, GLsizei width,
2765 GLsizei height, GLfloat r, GLfloat g, GLfloat b,
2766 GLfloat a) {
2767 GLfloat color[] = {r, g, b, a};
2768 Framebuffer& fb = ctx->framebuffers[fbo];
2769 Texture& t = ctx->textures[fb.color_attachment];
2770 IntRect scissor =
2771 IntRect{xoffset, yoffset, xoffset + width, yoffset + height}.intersection(
2772 t.offset_bounds());
2773 ClearTexSubImage(fb.color_attachment, 0, scissor.x0, scissor.y0, 0,
2774 scissor.width(), scissor.height(), 1, GL_RGBA0x1908, GL_FLOAT0x1406,
2775 color);
2776}
2777
2778void InvalidateFramebuffer(GLenum target, GLsizei num_attachments,
2779 const GLenum* attachments) {
2780 Framebuffer* fb = get_framebuffer(target);
2781 if (!fb || num_attachments <= 0 || !attachments) {
2782 return;
2783 }
2784 for (GLsizei i = 0; i < num_attachments; i++) {
2785 switch (attachments[i]) {
2786 case GL_DEPTH_ATTACHMENT0x8D00: {
2787 Texture& t = ctx->textures[fb->depth_attachment];
2788 t.set_cleared(false);
2789 break;
2790 }
2791 case GL_COLOR_ATTACHMENT00x8CE0: {
2792 Texture& t = ctx->textures[fb->color_attachment];
2793 t.disable_delayed_clear();
2794 break;
2795 }
2796 }
2797 }
2798}
2799
2800void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
2801 GLenum type, void* data) {
2802 Buffer* pbo = get_pixel_pack_buffer();
2803 if (pbo) {
2804 data = pbo->get_data(data);
2805 }
2806 if (!data) return;
2807 Framebuffer* fb = get_framebuffer(GL_READ_FRAMEBUFFER0x8CA8);
2808 if (!fb) return;
2809 assert(format == GL_RED || format == GL_RGBA || format == GL_RGBA_INTEGER ||(static_cast <bool> (format == 0x1903 || format == 0x1908
|| format == 0x8D99 || format == 0x80E1 || format == 0x8227)
? void (0) : __assert_fail ("format == GL_RED || format == GL_RGBA || format == GL_RGBA_INTEGER || format == GL_BGRA || format == GL_RG"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
2810 format == GL_BGRA || format == GL_RG)(static_cast <bool> (format == 0x1903 || format == 0x1908
|| format == 0x8D99 || format == 0x80E1 || format == 0x8227)
? void (0) : __assert_fail ("format == GL_RED || format == GL_RGBA || format == GL_RGBA_INTEGER || format == GL_BGRA || format == GL_RG"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2811 Texture& t = ctx->textures[fb->color_attachment];
2812 if (!t.buf) return;
2813 prepare_texture(t);
2814 // debugf("read pixels %d, %d, %d, %d from fb %d with format %x\n", x, y,
2815 // width, height, ctx->read_framebuffer_binding, t.internal_format);
2816 x -= t.offset.x;
2817 y -= t.offset.y;
2818 assert(x >= 0 && y >= 0)(static_cast <bool> (x >= 0 && y >= 0) ? void
(0) : __assert_fail ("x >= 0 && y >= 0", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
2819 assert(x + width <= t.width)(static_cast <bool> (x + width <= t.width) ? void (0
) : __assert_fail ("x + width <= t.width", __builtin_FILE (
), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
2820 assert(y + height <= t.height)(static_cast <bool> (y + height <= t.height) ? void (
0) : __assert_fail ("y + height <= t.height", __builtin_FILE
(), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
2821 if (internal_format_for_data(format, type) != t.internal_format) {
2822 debugf("mismatched format for read pixels: %x vs %x\n", t.internal_format,printf("mismatched format for read pixels: %x vs %x\n", t.internal_format
, internal_format_for_data(format, type))
2823 internal_format_for_data(format, type))printf("mismatched format for read pixels: %x vs %x\n", t.internal_format
, internal_format_for_data(format, type))
;
2824 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2825 return;
2826 }
2827 // Only support readback conversions that are reversible
2828 assert(!format_requires_conversion(format, t.internal_format) ||(static_cast <bool> (!format_requires_conversion(format
, t.internal_format) || bytes_for_internal_format(format) == t
.bpp()) ? void (0) : __assert_fail ("!format_requires_conversion(format, t.internal_format) || bytes_for_internal_format(format) == t.bpp()"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
2829 bytes_for_internal_format(format) == t.bpp())(static_cast <bool> (!format_requires_conversion(format
, t.internal_format) || bytes_for_internal_format(format) == t
.bpp()) ? void (0) : __assert_fail ("!format_requires_conversion(format, t.internal_format) || bytes_for_internal_format(format) == t.bpp()"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2830 uint8_t* dest = (uint8_t*)data;
2831 size_t destStride = width * t.bpp();
2832 if (y < 0) {
2833 dest += -y * destStride;
2834 height += y;
2835 y = 0;
2836 }
2837 if (y + height > t.height) {
2838 height = t.height - y;
2839 }
2840 if (x < 0) {
2841 dest += -x * t.bpp();
2842 width += x;
2843 x = 0;
2844 }
2845 if (x + width > t.width) {
2846 width = t.width - x;
2847 }
2848 if (width <= 0 || height <= 0) {
2849 return;
2850 }
2851 convert_copy(format, t.internal_format, dest, destStride,
2852 pbo ? (uint8_t*)pbo->buf : nullptr,
2853 pbo ? (uint8_t*)pbo->end_ptr() : nullptr,
2854 (const uint8_t*)t.sample_ptr(x, y), t.stride(),
2855 (const uint8_t*)t.buf, (const uint8_t*)t.end_ptr(), width,
2856 height);
2857}
2858
2859void CopyImageSubData(GLuint srcName, GLenum srcTarget, UNUSED[[maybe_unused]] GLint srcLevel,
2860 GLint srcX, GLint srcY, GLint srcZ, GLuint dstName,
2861 GLenum dstTarget, UNUSED[[maybe_unused]] GLint dstLevel, GLint dstX,
2862 GLint dstY, GLint dstZ, GLsizei srcWidth,
2863 GLsizei srcHeight, GLsizei srcDepth) {
2864 assert(srcLevel == 0 && dstLevel == 0)(static_cast <bool> (srcLevel == 0 && dstLevel ==
0) ? void (0) : __assert_fail ("srcLevel == 0 && dstLevel == 0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2865 assert(srcZ == 0 && srcDepth == 1 && dstZ == 0)(static_cast <bool> (srcZ == 0 && srcDepth == 1
&& dstZ == 0) ? void (0) : __assert_fail ("srcZ == 0 && srcDepth == 1 && dstZ == 0"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2866 if (srcTarget == GL_RENDERBUFFER0x8D41) {
2867 Renderbuffer& rb = ctx->renderbuffers[srcName];
2868 srcName = rb.texture;
2869 }
2870 if (dstTarget == GL_RENDERBUFFER0x8D41) {
2871 Renderbuffer& rb = ctx->renderbuffers[dstName];
2872 dstName = rb.texture;
2873 }
2874 Texture& srctex = ctx->textures[srcName];
2875 if (!srctex.buf) return;
2876 prepare_texture(srctex);
2877 Texture& dsttex = ctx->textures[dstName];
2878 if (!dsttex.buf) return;
2879 assert(!dsttex.locked)(static_cast <bool> (!dsttex.locked) ? void (0) : __assert_fail
("!dsttex.locked", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
2880 IntRect skip = {dstX, dstY, dstX + srcWidth, dstY + srcHeight};
2881 prepare_texture(dsttex, &skip);
2882 assert(srctex.internal_format == dsttex.internal_format)(static_cast <bool> (srctex.internal_format == dsttex.internal_format
) ? void (0) : __assert_fail ("srctex.internal_format == dsttex.internal_format"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2883 assert(srcWidth >= 0)(static_cast <bool> (srcWidth >= 0) ? void (0) : __assert_fail
("srcWidth >= 0", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
2884 assert(srcHeight >= 0)(static_cast <bool> (srcHeight >= 0) ? void (0) : __assert_fail
("srcHeight >= 0", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
2885 assert(srcX + srcWidth <= srctex.width)(static_cast <bool> (srcX + srcWidth <= srctex.width
) ? void (0) : __assert_fail ("srcX + srcWidth <= srctex.width"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2886 assert(srcY + srcHeight <= srctex.height)(static_cast <bool> (srcY + srcHeight <= srctex.height
) ? void (0) : __assert_fail ("srcY + srcHeight <= srctex.height"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2887 assert(dstX + srcWidth <= dsttex.width)(static_cast <bool> (dstX + srcWidth <= dsttex.width
) ? void (0) : __assert_fail ("dstX + srcWidth <= dsttex.width"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2888 assert(dstY + srcHeight <= dsttex.height)(static_cast <bool> (dstY + srcHeight <= dsttex.height
) ? void (0) : __assert_fail ("dstY + srcHeight <= dsttex.height"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2889 int bpp = srctex.bpp();
2890 int src_stride = srctex.stride();
2891 int dest_stride = dsttex.stride();
2892 char* dest = dsttex.sample_ptr(dstX, dstY);
2893 const char* src = srctex.sample_ptr(srcX, srcY);
2894 for (int y = 0; y < srcHeight; y++) {
2895 char* dst_ptr = dest;
2896 const char* src_ptr = src;
2897 size_t len = size_t(srcWidth) * bpp;
2898 if (clip_ptrs_against_bounds(dst_ptr, dsttex.buf, dsttex.end_ptr(), src_ptr,
2899 srctex.buf, srctex.end_ptr(), len) > 0) {
2900 break;
2901 }
2902 if (len) {
2903 memcpy(dst_ptr, src_ptr, len);
2904 }
2905 dest += dest_stride;
2906 src += src_stride;
2907 }
2908}
2909
2910void CopyTexSubImage2D(GLenum target, UNUSED[[maybe_unused]] GLint level, GLint xoffset,
2911 GLint yoffset, GLint x, GLint y, GLsizei width,
2912 GLsizei height) {
2913 assert(level == 0)(static_cast <bool> (level == 0) ? void (0) : __assert_fail
("level == 0", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
2914 Framebuffer* fb = get_framebuffer(GL_READ_FRAMEBUFFER0x8CA8);
2915 if (!fb) return;
2916 CopyImageSubData(fb->color_attachment, GL_TEXTURE_2D0x0DE1, 0, x, y, 0,
2917 ctx->get_binding(target), GL_TEXTURE_2D0x0DE1, 0, xoffset, yoffset,
2918 0, width, height, 1);
2919}
2920
2921} // extern "C"
2922
2923#include "blend.h"
2924#include "composite.h"
2925#include "swgl_ext.h"
2926
2927#pragma GCC diagnostic push
2928#pragma GCC diagnostic ignored "-Wuninitialized"
2929#pragma GCC diagnostic ignored "-Wunused-function"
2930#pragma GCC diagnostic ignored "-Wunused-parameter"
2931#pragma GCC diagnostic ignored "-Wunused-variable"
2932#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
2933#ifdef __clang__1
2934# pragma GCC diagnostic ignored "-Wunused-private-field"
2935#else
2936# pragma GCC diagnostic ignored "-Wunused-but-set-variable"
2937#endif
2938#include "load_shader.h"
2939#pragma GCC diagnostic pop
2940
2941#include "rasterize.h"
2942
2943void VertexArray::validate() {
2944 int last_enabled = -1;
2945 for (int i = 0; i <= max_attrib; i++) {
2946 VertexAttrib& attr = attribs[i];
2947 if (attr.enabled) {
2948 // VertexArray &v = ctx->vertex_arrays[attr.vertex_array];
2949 Buffer& vertex_buf = ctx->buffers[attr.vertex_buffer];
2950 attr.buf = vertex_buf.buf;
2951 attr.buf_size = vertex_buf.size;
2952 // debugf("%d %x %d %d %d %d\n", i, attr.type, attr.size, attr.stride,
2953 // attr.offset, attr.divisor);
2954 last_enabled = i;
2955 }
2956 }
2957 max_attrib = last_enabled;
2958}
2959
2960extern "C" {
2961
2962void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
2963 GLintptr offset, GLsizei instancecount) {
2964 if (offset < 0 || count <= 0 || instancecount <= 0 || !vertex_shader ||
2965 !fragment_shader) {
2966 return;
2967 }
2968
2969 Framebuffer& fb = *get_framebuffer(GL_DRAW_FRAMEBUFFER0x8CA9, true);
2970 if (!fb.color_attachment) {
2971 return;
2972 }
2973 Texture& colortex = ctx->textures[fb.color_attachment];
2974 if (!colortex.buf) {
2975 return;
2976 }
2977 assert(!colortex.locked)(static_cast <bool> (!colortex.locked) ? void (0) : __assert_fail
("!colortex.locked", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
2978 assert(colortex.internal_format == GL_RGBA8 ||(static_cast <bool> (colortex.internal_format == 0x8058
|| colortex.internal_format == 0x8229) ? void (0) : __assert_fail
("colortex.internal_format == GL_RGBA8 || colortex.internal_format == GL_R8"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
2979 colortex.internal_format == GL_R8)(static_cast <bool> (colortex.internal_format == 0x8058
|| colortex.internal_format == 0x8229) ? void (0) : __assert_fail
("colortex.internal_format == GL_RGBA8 || colortex.internal_format == GL_R8"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2980 Texture& depthtex = ctx->textures[ctx->depthtest ? fb.depth_attachment : 0];
2981 if (depthtex.buf) {
2982 assert(depthtex.internal_format == GL_DEPTH_COMPONENT24)(static_cast <bool> (depthtex.internal_format == 0x81A6
) ? void (0) : __assert_fail ("depthtex.internal_format == GL_DEPTH_COMPONENT24"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2983 assert(colortex.width == depthtex.width &&(static_cast <bool> (colortex.width == depthtex.width &&
colortex.height == depthtex.height) ? void (0) : __assert_fail
("colortex.width == depthtex.width && colortex.height == depthtex.height"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
2984 colortex.height == depthtex.height)(static_cast <bool> (colortex.width == depthtex.width &&
colortex.height == depthtex.height) ? void (0) : __assert_fail
("colortex.width == depthtex.width && colortex.height == depthtex.height"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2985 assert(colortex.offset == depthtex.offset)(static_cast <bool> (colortex.offset == depthtex.offset
) ? void (0) : __assert_fail ("colortex.offset == depthtex.offset"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2986 }
2987
2988 // debugf("current_vertex_array %d\n", ctx->current_vertex_array);
2989 // debugf("indices size: %d\n", indices_buf.size);
2990 VertexArray& v = ctx->vertex_arrays[ctx->current_vertex_array];
2991 if (ctx->validate_vertex_array) {
2992 ctx->validate_vertex_array = false;
2993 v.validate();
2994 }
2995
2996#ifdef PRINT_TIMINGS
2997 uint64_t start = get_time_value();
2998#endif
2999
3000 ctx->shaded_rows = 0;
3001 ctx->shaded_pixels = 0;
3002
3003 vertex_shader->init_batch();
3004
3005 switch (type) {
3006 case GL_UNSIGNED_SHORT0x1403:
3007 assert(mode == GL_TRIANGLES)(static_cast <bool> (mode == 0x0004) ? void (0) : __assert_fail
("mode == GL_TRIANGLES", __builtin_FILE (), __builtin_LINE (
), __extension__ __PRETTY_FUNCTION__))
;
3008 draw_elements<uint16_t>(count, instancecount, offset, v, colortex,
3009 depthtex);
3010 break;
3011 case GL_UNSIGNED_INT0x1405:
3012 assert(mode == GL_TRIANGLES)(static_cast <bool> (mode == 0x0004) ? void (0) : __assert_fail
("mode == GL_TRIANGLES", __builtin_FILE (), __builtin_LINE (
), __extension__ __PRETTY_FUNCTION__))
;
3013 draw_elements<uint32_t>(count, instancecount, offset, v, colortex,
3014 depthtex);
3015 break;
3016 case GL_NONE0:
3017 // Non-standard GL extension - if element type is GL_NONE, then we don't
3018 // use any element buffer and behave as if DrawArrays was called instead.
3019 for (GLsizei instance = 0; instance < instancecount; instance++) {
3020 switch (mode) {
3021 case GL_LINES0x0001:
3022 for (GLsizei i = 0; i + 2 <= count; i += 2) {
3023 vertex_shader->load_attribs(v.attribs, offset + i, instance, 2);
3024 draw_quad(2, colortex, depthtex);
3025 }
3026 break;
3027 case GL_TRIANGLES0x0004:
3028 for (GLsizei i = 0; i + 3 <= count; i += 3) {
3029 vertex_shader->load_attribs(v.attribs, offset + i, instance, 3);
3030 draw_quad(3, colortex, depthtex);
3031 }
3032 break;
3033 default:
3034 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
3035 break;
3036 }
3037 }
3038 break;
3039 default:
3040 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
3041 break;
3042 }
3043
3044 if (ctx->samples_passed_query) {
3045 Query& q = ctx->queries[ctx->samples_passed_query];
3046 q.value += ctx->shaded_pixels;
3047 }
3048
3049#ifdef PRINT_TIMINGS
3050 uint64_t end = get_time_value();
3051 printf(
3052 "%7.3fms draw(%s, %d): %d pixels in %d rows (avg %f pixels/row, "
3053 "%fns/pixel)\n",
3054 double(end - start) / (1000. * 1000.),
3055 ctx->programs[ctx->current_program].impl->get_name(), instancecount,
3056 ctx->shaded_pixels, ctx->shaded_rows,
3057 double(ctx->shaded_pixels) / ctx->shaded_rows,
3058 double(end - start) / max(ctx->shaded_pixels, 1));
3059#endif
3060}
3061
3062void Finish() {
3063#ifdef PRINT_TIMINGS
3064 printf("Finish\n");
3065#endif
3066}
3067
3068void MakeCurrent(Context* c) {
3069 if (ctx == c) {
3070 return;
3071 }
3072 ctx = c;
3073 setup_program(ctx ? ctx->current_program : 0);
3074}
3075
3076Context* CreateContext() { return new Context; }
3077
3078void ReferenceContext(Context* c) {
3079 if (!c) {
3080 return;
3081 }
3082 ++c->references;
3083}
3084
3085void DestroyContext(Context* c) {
3086 if (!c) {
3087 return;
3088 }
3089 assert(c->references > 0)(static_cast <bool> (c->references > 0) ? void (0
) : __assert_fail ("c->references > 0", __builtin_FILE (
), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__))
;
3090 --c->references;
3091 if (c->references > 0) {
3092 return;
3093 }
3094 if (ctx == c) {
3095 MakeCurrent(nullptr);
3096 }
3097 delete c;
3098}
3099
3100size_t ReportMemory(Context* ctx, size_t (*size_of_op)(const void*)) {
3101 size_t size = 0;
3102 if (ctx) {
3103 for (auto& t : ctx->textures) {
3104 if (t && t->should_free()) {
3105 size += size_of_op(t->buf);
3106 }
3107 }
3108 }
3109 return size;
3110}
3111} // extern "C"