#if ENABLE_MICROPROFILE #define MICROPROFILE_WEBSERVER 0 #define MICROPROFILE_GPU_TIMERS 0 #define MICROPROFILE_ENABLED 1 #define MICROPROFILEUI_ENABLED 1 #define MICROPROFILE_IMPL 1 #define MICROPROFILEUI_IMPL 1 #define MICROPROFILE_PER_THREAD_BUFFER_SIZE (1024 * 1024 * 20) #define MICROPROFILE_CONTEXT_SWITCH_TRACE 0 #include #include #endif extern "C" { #include "core/assert.h" #include "core/math.h" #include "render/microprofile.h" #include "render/render_backend.h" } static const int FONT_WIDTH = 1024; static const int FONT_HEIGHT = 9; #include "render/microprofile_font.inc" static const int MAX_2D_VERTICES = 32768; static const int MAX_2D_SURFACES = 256; struct microprofile { struct render_backend *r; texture_handle_t font_texture; struct ui_surface surfs[MAX_2D_SURFACES]; int num_surfs; struct ui_vertex verts[MAX_2D_VERTICES]; int num_verts; }; static struct microprofile *s_mp; #define Q0(d, member, v) d[0].member = v #define Q1(d, member, v) \ d[1].member = v; \ d[3].member = v #define Q2(d, member, v) d[4].member = v #define Q3(d, member, v) \ d[2].member = v; \ d[5].member = v static struct ui_vertex *mp_alloc_verts(struct microprofile *mp, const struct ui_surface &desc, int count) { #if ENABLE_MICROPROFILE CHECK(mp->num_verts + count <= MAX_2D_VERTICES); uint32_t first_vert = mp->num_verts; mp->num_verts += count; /* try to batch with the last surface if possible */ if (mp->num_surfs) { struct ui_surface &last_surf = mp->surfs[mp->num_surfs - 1]; if (last_surf.prim_type == desc.prim_type && last_surf.texture == desc.texture && last_surf.src_blend == desc.src_blend && last_surf.dst_blend == desc.dst_blend) { last_surf.num_verts += count; return &mp->verts[first_vert]; } } /* else, allocate a new surface */ CHECK(mp->num_surfs < MAX_2D_SURFACES); struct ui_surface &next_surf = mp->surfs[mp->num_surfs]; next_surf.prim_type = desc.prim_type; next_surf.texture = desc.texture; next_surf.src_blend = desc.src_blend; next_surf.dst_blend = desc.dst_blend; next_surf.scissor = false; next_surf.first_vert = first_vert; next_surf.num_verts = count; mp->num_surfs++; return &mp->verts[first_vert]; #endif return NULL; } static void mp_draw_text(struct microprofile *mp, int x, int y, uint32_t color, const char *text) { #if ENABLE_MICROPROFILE float fx = static_cast(x); float fy = static_cast(y); float fy2 = fy + (MICROPROFILE_TEXT_HEIGHT + 1); int text_len = static_cast(strlen(text)); struct ui_vertex *vertex = mp_alloc_verts(mp, {PRIM_TRIANGLES, mp->font_texture, BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA, false, {0.0f, 0.0f, 0.0f, 0.0f}, 0, 0}, 6 * text_len); for (int i = 0; i < text_len; i++) { float fx2 = fx + MICROPROFILE_TEXT_WIDTH; float fu = s_font_offsets[static_cast(text[i])] / static_cast(FONT_WIDTH); float fu2 = fu + MICROPROFILE_TEXT_WIDTH / static_cast(FONT_WIDTH); Q0(vertex, xy[0], fx); Q0(vertex, xy[1], fy); Q0(vertex, color, color); Q0(vertex, uv[0], fu); Q0(vertex, uv[1], 0.0f); Q1(vertex, xy[0], fx2); Q1(vertex, xy[1], fy); Q1(vertex, color, color); Q1(vertex, uv[0], fu2); Q1(vertex, uv[1], 0.0f); Q2(vertex, xy[0], fx2); Q2(vertex, xy[1], fy2); Q2(vertex, color, color); Q2(vertex, uv[0], fu2); Q2(vertex, uv[1], 1.0f); Q3(vertex, xy[0], fx); Q3(vertex, xy[1], fy2); Q3(vertex, color, color); Q3(vertex, uv[0], fu); Q3(vertex, uv[1], 1.0f); fx = fx2 + 1.0f; vertex += 6; } #endif } static void mp_draw_box(struct microprofile *mp, int x0, int y0, int x1, int y1, uint32_t color, enum box_type type) { #if ENABLE_MICROPROFILE struct ui_vertex *vertex = mp_alloc_verts(mp, {PRIM_TRIANGLES, 0, BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA, false, {0.0f, 0.0f, 0.0f, 0.0f}, 0, 0}, 6); if (type == BOX_FLAT) { Q0(vertex, xy[0], (float)x0); Q0(vertex, xy[1], (float)y0); Q0(vertex, color, color); Q1(vertex, xy[0], (float)x1); Q1(vertex, xy[1], (float)y0); Q1(vertex, color, color); Q2(vertex, xy[0], (float)x1); Q2(vertex, xy[1], (float)y1); Q2(vertex, color, color); Q3(vertex, xy[0], (float)x0); Q3(vertex, xy[1], (float)y1); Q3(vertex, color, color); } else { uint32_t a = (color & 0xff000000) >> 24; uint32_t r = (color & 0xff0000) >> 16; uint32_t g = (color & 0xff00) >> 8; uint32_t b = color & 0xff; uint32_t max = MAX(MAX(MAX(r, g), b), 30u); uint32_t min = MIN(MIN(MIN(r, g), b), 180u); uint32_t r0 = 0xff & ((r + max) / 2); uint32_t g0 = 0xff & ((g + max) / 2); uint32_t b0 = 0xff & ((b + max) / 2); uint32_t r1 = 0xff & ((r + min) / 2); uint32_t g1 = 0xff & ((g + min) / 2); uint32_t b1 = 0xff & ((b + min) / 2); uint32_t color0 = (a << 24) | (b0 << 16) | (g0 << 8) | r0; uint32_t color1 = (a << 24) | (b1 << 16) | (g1 << 8) | r1; Q0(vertex, xy[0], (float)x0); Q0(vertex, xy[1], (float)y0); Q0(vertex, color, color0); Q1(vertex, xy[0], (float)x1); Q1(vertex, xy[1], (float)y0); Q1(vertex, color, color0); Q2(vertex, xy[0], (float)x1); Q2(vertex, xy[1], (float)y1); Q2(vertex, color, color1); Q3(vertex, xy[0], (float)x0); Q3(vertex, xy[1], (float)y1); Q3(vertex, color, color1); } #endif } static void mp_draw_line(struct microprofile *mp, float *verts, int num_verts, uint32_t color) { #if ENABLE_MICROPROFILE CHECK(num_verts); struct ui_vertex *vertex = mp_alloc_verts(mp, {PRIM_LINES, 0, BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA, false, {0.0f, 0.0f, 0.0f, 0.0f}, 0, 0}, 2 * (num_verts - 1)); for (int i = 0; i < num_verts - 1; ++i) { vertex[0].xy[0] = verts[i * 2]; vertex[0].xy[1] = verts[i * 2 + 1]; vertex[0].color = color; vertex[1].xy[0] = verts[(i + 1) * 2]; vertex[1].xy[1] = verts[(i + 1) * 2 + 1]; vertex[1].color = color; vertex += 2; } #endif } void mp_render(struct microprofile *mp) { #if ENABLE_MICROPROFILE s_mp = mp; int width = r_viewport_width(mp->r); int height = r_viewport_height(mp->r); /* update draw surfaces */ MicroProfileDraw(width, height); /* render the surfaces */ r_begin_ui_surfaces(mp->r, mp->verts, mp->num_verts, nullptr, 0); for (int i = 0; i < mp->num_surfs; i++) { struct ui_surface *surf = &mp->surfs[i]; r_draw_ui_surface(mp->r, surf); } r_end_ui_surfaces(mp->r); /* reset surfaces */ mp->num_surfs = 0; mp->num_verts = 0; #endif } void mp_mousemove(struct microprofile *mp, int x, int y) { #if ENABLE_MICROPROFILE MicroProfileMousePosition(x, y, 0); #endif } void mp_keydown(struct microprofile *mp, enum keycode key, int16_t value) { #if ENABLE_MICROPROFILE if (key == K_F2) { if (value > 0) { MicroProfileToggleDisplayMode(); } } else if (key == K_MOUSE1) { int down = value > 0; MicroProfileMouseButton(down, 0); } else if (key == K_MOUSE2) { int down = value > 0; MicroProfileMouseButton(0, down); } #endif } void mp_destroy(struct microprofile *mp) { #if ENABLE_MICROPROFILE r_destroy_texture(mp->r, mp->font_texture); free(mp); #endif } struct microprofile *mp_create(struct render_backend *r) { #if ENABLE_MICROPROFILE struct microprofile *mp = reinterpret_cast( calloc(1, sizeof(struct microprofile))); mp->r = r; /* register and enable cpu and gpu groups by default */ uint16_t cpu_group = MicroProfileGetGroup("cpu", MicroProfileTokenTypeCpu); g_MicroProfile.nActiveGroupWanted |= 1ll << cpu_group; uint16_t gpu_group = MicroProfileGetGroup("gpu", MicroProfileTokenTypeCpu); g_MicroProfile.nActiveGroupWanted |= 1ll << gpu_group; /* render time / average time bars by default */ g_MicroProfile.nBars |= MP_DRAW_TIMERS | MP_DRAW_AVERAGE | MP_DRAW_CALL_COUNT; /* aggregate stats every 120 frames by default */ g_MicroProfile.nAggregateFlip = 120; /* register the font texture */ mp->font_texture = r_create_texture(mp->r, PXL_RGBA, FILTER_NEAREST, WRAP_CLAMP_TO_EDGE, WRAP_CLAMP_TO_EDGE, 0, FONT_WIDTH, FONT_HEIGHT, reinterpret_cast(s_font_data)); return mp; #else return NULL; #endif } /* microprofile expects the following three functions to be defined, they're called during MicroProfileDraw */ #if ENABLE_MICROPROFILE void MicroProfileDrawText(int x, int y, uint32_t color, const char *text, uint32_t len) { /* microprofile provides 24-bit rgb values for text color */ color = 0xff000000 | color; /* convert color from argb -> abgr */ color = (color & 0xff000000) | ((color & 0xff) << 16) | (color & 0xff00) | ((color & 0xff0000) >> 16); mp_draw_text(s_mp, x, y, color, text); } void MicroProfileDrawBox(int x0, int y0, int x1, int y1, uint32_t color, MicroProfileBoxType type) { /* convert color from argb -> abgr */ color = (color & 0xff000000) | ((color & 0xff) << 16) | (color & 0xff00) | ((color & 0xff0000) >> 16); mp_draw_box(s_mp, x0, y0, x1, y1, color, (enum box_type)type); } void MicroProfileDrawLine2D(uint32_t num_vertices, float *vertices, uint32_t color) { /* microprofile provides 24-bit rgb values for line color */ color = 0xff000000 | color; /* convert color from argb -> abgr */ color = (color & 0xff000000) | ((color & 0xff) << 16) | (color & 0xff00) | ((color & 0xff0000) >> 16); mp_draw_line(s_mp, vertices, num_vertices, color); } #endif