36#include <acfutils/shader.h>
39#ifdef _USE_MATH_DEFINES
40#undef _USE_MATH_DEFINES
72} texsz = { .inited = B_FALSE };
81 cache_entry_type_t type;
99static bool_t inited = B_FALSE;
101static bool_t in_zink_mode = B_FALSE;
113 in_zink_mode = (strcmp((
char *)glGetString(GL_VENDOR),
"Mesa")
115 strncmp((
char *)glGetString(GL_RENDERER),
"zink", 4) == 0);
130 static const GLenum disable_caps[] = {
136 GL_SECONDARY_COLOR_ARRAY,
137 GL_TEXTURE_COORD_ARRAY,
142 if (GLEW_VERSION_3_1)
145 for (
int i = 0; disable_caps[i] != 0; i++)
146 glDisableClientState(disable_caps[i]);
162 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &n_attrs);
163 for (
int i = 0; i < MIN(n_attrs, 32); i++)
164 glDisableVertexAttribArray(i);
183 size_t n_idx = num_vtx + num_vtx / 2;
184 GLuint *idx_data =
safe_malloc(n_idx *
sizeof (*idx_data));
185 for (i = 0, n = 0; i < num_vtx; i += 4, n += 6) {
186 idx_data[n + 0] = i + 0;
187 idx_data[n + 1] = i + 1;
188 idx_data[n + 2] = i + 2;
190 idx_data[n + 3] = i + 0;
191 idx_data[n + 4] = i + 2;
192 idx_data[n + 5] = i + 3;
196 glGenBuffers(1, &buf);
198 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
199 glBufferData(GL_ELEMENT_ARRAY_BUFFER, n *
sizeof (*idx_data),
200 idx_data, GL_STATIC_DRAW);
214 for (
size_t i = 0; i < num_pts; i++)
215 p_3d[i] =
VECT3(p[i].x, p[i].y, 0);
230 for (
size_t i = 0; i < num_pts; i++)
231 p_3d[i] =
VECT3(p[i].x, p[i].y, 0);
247 memset(quads, 0,
sizeof (*quads));
250 glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
252 glGenVertexArrays(1, &quads->vao);
253 glBindVertexArray(quads->vao);
258 glGenBuffers(1, &quads->vbo);
263 glBindVertexArray(old_vao);
279 for (
size_t i = 0; i < num_pts; i++) {
280 vtx_data[i].pos[0] = p[i].x;
281 vtx_data[i].pos[1] = p[i].y;
282 vtx_data[i].pos[2] = p[i].z;
284 vtx_data[i].tex0[0] = t[i].x;
285 vtx_data[i].tex0[1] = t[i].y;
288 glBindBuffer(GL_ARRAY_BUFFER, quads->vbo);
289 glBufferData(GL_ARRAY_BUFFER, num_pts *
sizeof (
vtx_t), vtx_data,
291 if (quads->num_vtx != num_pts || quads->ibo == 0) {
293 glDeleteBuffers(1, &quads->ibo);
296 if (quads->num_vtx != num_pts) {
298 quads->num_vtx * sizeof (
vtx_t)));
300 filename, line, num_pts *
sizeof (
vtx_t)));
302 quads->num_vtx = num_pts;
316 glDeleteVertexArrays(1, &quads->vao);
317 if (quads->vbo != 0) {
319 quads->num_vtx * sizeof (
vtx_t)));
320 glDeleteBuffers(1, &quads->vbo);
323 glDeleteBuffers(1, &quads->ibo);
324 memset(quads, 0,
sizeof (*quads));
328glutils_draw_common(GLenum mode, GLuint vao, GLuint vbo, GLuint ibo,
329 bool_t *setup,
size_t num_vtx, GLint prog)
331 GLint pos_loc = -1, tex0_loc = -1;
338 glBindVertexArray(vao);
341 if (vao == 0 || !(*setup)) {
342 glBindBuffer(GL_ARRAY_BUFFER, vbo);
343 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
345 pos_loc = glGetAttribLocation(prog,
"vtx_pos");
346 tex0_loc = glGetAttribLocation(prog,
"vtx_tex0");
356 glDrawElements(mode, num_vtx, GL_UNSIGNED_INT, NULL);
358 glDrawArrays(mode, 0, num_vtx);
361 glBindVertexArray(0);
366 glBindBuffer(GL_ARRAY_BUFFER, 0);
367 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
394 glutils_draw_common(GL_TRIANGLES, quads->vao, quads->vbo, quads->ibo,
395 &quads->setup, quads->num_vtx + quads->num_vtx / 2, prog);
399cache_compar(
const void *a,
const void *b)
403 if (ca->type < cb->type)
405 if (ca->type > cb->type)
407 for (
int i = 0; i < 2; i++) {
408 if (ca->buf_sz[i] < cb->buf_sz[i])
410 if (ca->buf_sz[i] > cb->buf_sz[i])
413 for (
int i = 0; i < 2; i++) {
414 int res = memcmp(ca->buf[i], cb->buf[i], cb->buf_sz[i]);
442 glutils_cache_t *cache =
safe_calloc(1,
sizeof (*cache));
450 cache->cap = cap_bytes;
464 case CACHE_ENTRY_2D_QUADS:
465 case CACHE_ENTRY_3D_QUADS:
468 case CACHE_ENTRY_3D_LINES:
499 free_cache_entry(ce);
512trim_cache(glutils_cache_t *cache,
size_t extra_needed)
516 while (cache->sz + extra_needed > cache->cap) {
522 ASSERT3U(cache->sz, >=, ce->buf_sz[0] + ce->buf_sz[1]);
523 cache->sz -= (ce->buf_sz[0] + ce->buf_sz[1]);
524 free_cache_entry(ce);
532cache_add_entry(glutils_cache_t *cache,
avl_index_t where,
533 cache_entry_type_t type,
const void *buf0,
size_t buf0_sz,
534 const void *buf1,
size_t buf1_sz,
size_t num_pts)
543 ce->buf_sz[0] = buf0_sz;
545 memcpy(ce->buf[0], buf0, buf0_sz);
547 ce->buf_sz[1] = buf1_sz;
549 memcpy(ce->buf[1], buf1, buf1_sz);
553 case CACHE_ENTRY_2D_QUADS:
556 case CACHE_ENTRY_3D_QUADS:
559 case CACHE_ENTRY_3D_LINES:
572glutils_cache_get_common(glutils_cache_t *cache, cache_entry_type_t type,
573 const void *p,
const void *t,
size_t num_pts)
575 size_t p_sz = (type == CACHE_ENTRY_2D_QUADS ?
sizeof (
vect2_t) :
579 .buf = { (
void *)p, (
void *)t },
582 t != NULL ?
sizeof (
vect2_t) * num_pts : 0
587 size_t bytes = srch.buf_sz[0] + srch.buf_sz[1];
593 ce =
avl_find(&cache->tree, &srch, &where);
595 trim_cache(cache, bytes);
596 ce = cache_add_entry(cache, where, type, p, srch.buf_sz[0],
597 t, srch.buf_sz[1], num_pts);
602 if (type <= CACHE_ENTRY_3D_QUADS)
614 const vect2_t *t,
size_t num_pts)
616 return (glutils_cache_get_common(cache, 0, p, t, num_pts));
639 const vect2_t *t,
size_t num_pts)
641 return (glutils_cache_get_common(cache, 1, p, t, num_pts));
655 return (glutils_cache_get_common(cache, 2, p, NULL, num_pts));
667 int line,
const vect3_t *p,
size_t num_pts)
674 memset(lines, 0,
sizeof (*lines));
675 for (
size_t i = 0; i < num_pts; i++) {
676 vtx_data[i].pos[0] = p[i].x;
677 vtx_data[i].pos[1] = p[i].y;
678 vtx_data[i].pos[2] = p[i].z;
682 glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
684 glGenVertexArrays(1, &lines->vao);
685 glBindVertexArray(lines->vao);
691 glGenBuffers(1, &lines->vbo);
693 lines->num_vtx = num_pts;
695 glBindBuffer(GL_ARRAY_BUFFER, lines->vbo);
696 glBufferData(GL_ARRAY_BUFFER, lines->num_vtx * sizeof (
vtx_t),
697 vtx_data, GL_STATIC_DRAW);
701 filename, line, lines->num_vtx * sizeof (
vtx_t));
705 glBindVertexArray(old_vao);
707 glBindBuffer(GL_ARRAY_BUFFER, 0);
729 glutils_draw_common(GL_LINE_STRIP, lines->vao, lines->vbo, 0,
730 &lines->setup, lines->num_vtx, prog);
744 if (lines->vbo != 0) {
747 lines->num_vtx * sizeof (
vtx_t));
749 glDeleteBuffers(1, &lines->vbo);
750 memset(lines, 0,
sizeof (*lines));
767 glGetIntegerv(GL_VIEWPORT, vp);
768 glm_ortho(vp[0], vp[0] + vp[2], vp[1], vp[1] + vp[3], 0, 1, pvm_mat);
769 memcpy(pvm, pvm_mat,
sizeof (GLfloat) * 16);
773texsz_alloc_compar(
const void *a,
const void *b)
777 if (ta->token < tb->token)
779 if (ta->token > tb->token)
786texsz_instance_compar(
const void *a,
const void *b)
790 if (ta->instance < tb->instance)
792 if (ta->instance > tb->instance)
816 texsz.inited = B_TRUE;
843 void *cookie2 = NULL;
846 ASSERT(ta->token != NULL);
847 if (ta->bytes != 0) {
848 for (ti =
avl_first(&ta->instances); ti != NULL;
849 ti =
AVL_NEXT(&ta->instances, ti)) {
850 logMsg(
"%s: %p %ld (at: %s)\n", ta->token,
851 ti->instance, (
long)ti->bytes,
855 "%s leaked %ld bytes", ta->token, (
long)ta->bytes);
868texsz_incr(
const char *token,
const void *instance,
const char *filename,
869 int line, int64_t bytes)
877 ASSERT_MSG(texsz.bytes + bytes >= 0,
"Texture size accounting error "
878 "(incr %ld bytes)", (
long)bytes);
879 texsz.bytes += bytes;
880 ta =
avl_find(&texsz.allocs, &srch, &where);
884 avl_create(&ta->instances, texsz_instance_compar,
889 ASSERT_MSG(ta->bytes + bytes >= 0,
"Texture size accounting zone "
890 "underflow error (incr %ld bytes in zone %s instance %p)",
891 (
long)bytes, ta->token, instance);
894 if (instance != NULL) {
899 ti =
avl_find(&ta->instances, &srch_ti, &where_ti);
901 ASSERT_MSG(bytes >= 0,
"Texture size accounting error "
902 "(incr %ld bytes in zone %s instance %p, but "
903 "instance is empty).", (
long)bytes, ta->token,
906 ti->instance = instance;
909 ASSERT_MSG(ti->bytes + bytes >= 0,
"Texture size accounting "
910 "instance underflow error (incr %ld bytes in zone %s "
911 "instance %p)", (
long)bytes, ta->token, instance);
913 if (filename != NULL && snprintf(ti->allocd_at,
914 sizeof (ti->allocd_at),
"%s:%d", filename, line) >=
915 (
int)sizeof (ti->allocd_at)) {
916 int l = strlen(filename);
917 int off = MAX(l - 26, 0);
918 snprintf(ti->allocd_at, sizeof (ti->allocd_at),
919 "%s:%d", &filename[off], line);
921 if (ti->bytes == 0) {
931texsz_bytes(GLenum format, GLenum type,
unsigned w,
unsigned h)
948 case GL_RGBA_INTEGER:
949 case GL_BGRA_INTEGER:
958 case GL_UNSIGNED_BYTE:
960 case GL_UNSIGNED_SHORT:
964 case GL_UNSIGNED_INT:
974 return (channels * bpc * w * h);
985 const char *filename,
int line, GLenum format, GLenum type,
986 unsigned w,
unsigned h)
989 texsz_incr(token, instance, filename, line,
990 texsz_bytes(format, type, w, h));
1001 GLenum format, GLenum type,
unsigned w,
unsigned h)
1004 texsz_incr(token, instance, NULL, -1, -texsz_bytes(format, type, w, h));
1015 const char *filename,
int line, int64_t bytes)
1018 texsz_incr(token, instance, filename, line, bytes);
1031 texsz_incr(token, instance, NULL, -1, -bytes);
1042 return (texsz.bytes);
1057 ta =
AVL_NEXT(&texsz.allocs, ta)) {
1058 cb(ta->token, ta->bytes, userinfo);
1068 return (texsz.inited);
1079 for (
int i = 0; environ[i] != NULL; i++) {
1080 if (strncmp(environ[i],
"NSIGHT", 6) == 0 ||
1081 strncmp(environ[i],
"NVIDIA_PROCESS", 14) == 0)
1146 vec3 *pts_3d =
safe_calloc(num_pts,
sizeof (*pts_3d));
1152 for (
size_t i = 0; i < num_pts; i++) {
1153 pts_3d[i][0] = pts[i][0];
1154 pts_3d[i][1] = pts[i][1];
1188 data_bytes = 2 * num_pts *
sizeof (*data);
1191 for (
size_t i = 0; i < num_pts; i += 2) {
1193 memcpy(&data[off + 0].seg_here, pts[i],
sizeof (vec3));
1194 memcpy(&data[off + 1].seg_here, pts[i],
sizeof (vec3));
1195 memcpy(&data[off + 2].seg_here, pts[i + 1],
sizeof (vec3));
1196 memcpy(&data[off + 3].seg_here, pts[i + 1],
sizeof (vec3));
1198 for (
size_t j = 0; j < 4; j++) {
1199 memcpy(&data[off + j].seg_start, pts[i],
1201 memcpy(&data[off + j].seg_end, pts[i + 1],
1206 nl->num_pts = num_pts;
1208 glGenVertexArrays(1, &nl->vao);
1210 glBindVertexArray(nl->vao);
1212 glGenBuffers(1, &nl->vbo);
1214 glBindBuffer(GL_ARRAY_BUFFER, nl->vbo);
1215 glBufferData(GL_ARRAY_BUFFER, data_bytes, data, GL_STATIC_DRAW);
1221 nl->loc.semi_width = -1;
1222 nl->loc.seg_here = -1;
1223 nl->loc.seg_start = -1;
1224 nl->loc.seg_end = -1;
1227 glBindVertexArray(0);
1228 glBindBuffer(GL_ARRAY_BUFFER, 0);
1229 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1246 glDeleteVertexArrays(1, &nl->vao);
1248 glDeleteBuffers(1, &nl->vbo);
1250 glDeleteBuffers(1, &nl->ibo);
1257 if (nl->vao != 0 && nl->last_prog == prog)
1270 nl->loc.vp = glGetUniformLocation(prog,
"_nl_vp");
1271 nl->loc.semi_width = glGetUniformLocation(prog,
"_nl_semi_width");
1274 nl->loc.seg_here = glGetAttribLocation(prog,
"_nl_seg_here");
1275 nl->loc.seg_start = glGetAttribLocation(prog,
"_nl_seg_start");
1276 nl->loc.seg_end = glGetAttribLocation(prog,
"_nl_seg_end");
1278 glBindBuffer(GL_ARRAY_BUFFER, nl->vbo);
1279 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, nl->ibo);
1287 nl->last_prog = prog;
1344 glGetIntegerv(GL_VIEWPORT, vp);
1347 glBindVertexArray(nl->vao);
1349 glBindBuffer(GL_ARRAY_BUFFER, nl->vbo);
1350 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, nl->ibo);
1353 nl_setup_vertex_attribs(nl, prog);
1355 if (nl->loc.vp != -1)
1356 glUniform2f(nl->loc.vp, vp[2], vp[3]);
1357 if (nl->loc.semi_width != -1)
1358 glUniform1f(nl->loc.semi_width, width / 2);
1370 glGetIntegerv(GL_FRONT_FACE, (GLint *)&winding);
1372 glDisable(GL_CULL_FACE);
1373 glDrawElements(GL_TRIANGLES, nl->num_pts * 3, GL_UNSIGNED_INT, NULL);
1374 glEnable(GL_CULL_FACE);
1376 glFrontFace(winding);
1380 glBindVertexArray(0);
1386 glBindBuffer(GL_ARRAY_BUFFER, 0);
1387 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1417 GLint *int_fmt, GLint *fmt, GLint *type)
1423 if (png_bit_depth != 8)
1425 switch (png_color_type) {
1426 case PNG_COLOR_TYPE_RGB:
1429 *type = GL_UNSIGNED_BYTE;
1431 case PNG_COLOR_TYPE_RGB_ALPHA:
1434 *type = GL_UNSIGNED_BYTE;
1449 return (in_zink_mode);
#define ASSERT_MSG(x, fmt,...)
#define ASSERT3U(x, op, y)
#define ASSERT3F(x, op, y)
#define VERIFY_MSG(x, fmt,...)
void * avl_destroy_nodes(avl_tree_t *tree, void **cookie)
void * avl_first(const avl_tree_t *tree)
void avl_remove(avl_tree_t *tree, void *node)
void avl_insert(avl_tree_t *tree, void *node, avl_index_t where)
void avl_create(avl_tree_t *tree, int(*compar)(const void *, const void *), size_t size, size_t offset)
#define AVL_NEXT(tree, node)
void avl_destroy(avl_tree_t *tree)
void * avl_find(const avl_tree_t *tree, const void *node, avl_index_t *where)
#define TEXSZ_FREE_BYTES_INSTANCE(__token_id, __instance, __bytes)
void glutils_nl_draw(glutils_nl_t *nl, float width, GLuint prog)
void glutils_texsz_init(void)
static void glutils_disable_vtx_attr_ptr(GLint index)
uint64_t glutils_texsz_get(void)
void glutils_draw_lines(glutils_lines_t *lines, GLint prog)
#define TEXSZ_ALLOC_BYTES_INSTANCE(__token_id, __instance, __filename, __line, __bytes)
glutils_nl_t * glutils_nl_alloc_3D(const vec3 *pts, size_t num_pts)
void glutils_texsz_alloc(const char *token, const void *instance, const char *filename, int line, GLenum format, GLenum type, unsigned w, unsigned h)
bool_t glutils_nsight_debugger_present(void)
void glutils_sys_init(void)
glutils_nl_t * glutils_nl_alloc_2D(const vec2 *pts, size_t num_pts)
void glutils_update_3D_quads_impl(glutils_quads_t *quads, const char *filename, int line, const vect3_t *p, const vect2_t *t, size_t num_pts)
#define glutils_init_2D_quads(__quads, __p, __t, __num_pts)
void glutils_init_3D_quads_impl(glutils_quads_t *quads, const char *filename, int line, const vect3_t *p, const vect2_t *t, size_t num_pts)
bool_t glutils_texsz_inited(void)
#define TEXSZ_MK_TOKEN(name)
void glutils_init_2D_quads_impl(glutils_quads_t *quads, const char *filename, int line, const vect2_t *p, const vect2_t *t, size_t num_pts)
void glutils_destroy_lines(glutils_lines_t *lines)
void glutils_cache_destroy(glutils_cache_t *cache)
#define glutils_init_3D_lines(__lines, __p, __num_pts)
void glutils_init_3D_lines_impl(glutils_lines_t *lines, const char *filename, int line, const vect3_t *p, size_t num_pts)
void glutils_disable_all_vtx_attrs(void)
void glutils_destroy_quads(glutils_quads_t *quads)
glutils_quads_t * glutils_cache_get_2D_quads(glutils_cache_t *cache, const vect2_t *p, const vect2_t *t, size_t num_pts)
static bool_t glutils_quads_inited(const glutils_quads_t *quads)
glutils_lines_t * glutils_cache_get_3D_lines(glutils_cache_t *cache, const vect3_t *p, size_t num_pts)
void(* glutils_texsz_enum_cb_t)(const char *token, int64_t bytes, void *userinfo)
void glutils_update_2D_quads_impl(glutils_quads_t *quads, const char *filename, int line, const vect2_t *p, const vect2_t *t, size_t num_pts)
glutils_quads_t * glutils_cache_get_3D_quads(glutils_cache_t *cache, const vect3_t *p, const vect2_t *t, size_t num_pts)
GLuint glutils_make_quads_IBO(size_t num_vtx)
#define glutils_init_3D_quads(__quads, __p, __t, __num_pts)
static void glutils_enable_vtx_attr_ptr(GLint index, GLint size, GLenum type, GLboolean normalized, size_t stride, size_t offset)
void glutils_draw_quads(glutils_quads_t *quads, GLint prog)
void glutils_disable_all_client_state(void)
bool_t glutils_png2gltexfmt(int png_color_type, int png_bit_depth, GLint *int_fmt, GLint *fmt, GLint *type)
void glutils_texsz_fini(void)
void glutils_texsz_enum(glutils_texsz_enum_cb_t cb, void *userinfo)
void glutils_texsz_alloc_bytes(const char *token, const void *instance, const char *filename, int line, int64_t bytes)
glutils_cache_t * glutils_cache_new(size_t cap_bytes)
void glutils_texsz_free_bytes(const char *token, const void *instance, int64_t bytes)
void glutils_texsz_free(const char *token, const void *instance, GLenum format, GLenum type, unsigned w, unsigned h)
void glutils_vp2pvm(GLfloat pvm[16])
void glutils_nl_free(glutils_nl_t *nl)
bool_t glutils_in_zink_mode(void)
void list_destroy(list_t *)
void list_create(list_t *, size_t, size_t)
void * list_remove_tail(list_t *)
void list_insert_head(list_t *, void *)
void list_remove(list_t *, void *)
void * list_remove_head(list_t *)
static void * safe_calloc(size_t nmemb, size_t size)
static void * safe_malloc(size_t size)
static void mutex_destroy(mutex_t *mtx)
static void mutex_enter(mutex_t *mtx)
static void mutex_exit(mutex_t *mtx)
static void mutex_init(mutex_t *mtx)