redream/src/render/microprofile.cc

351 lines
11 KiB
C++

#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 <microprofile.h>
#include <microprofileui.h>
#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<float>(x);
float fy = static_cast<float>(y);
float fy2 = fy + (MICROPROFILE_TEXT_HEIGHT + 1);
int text_len = static_cast<int>(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<int>(text[i])] /
static_cast<float>(FONT_WIDTH);
float fu2 = fu + MICROPROFILE_TEXT_WIDTH / static_cast<float>(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<struct microprofile *>(
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<const uint8_t *>(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