/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2015 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include #include #include #include #include namespace xe { namespace gpu { namespace gl4 { extern "C" GLEWContext* glewGetContext(); #define MICROPROFILE_MAX_VERTICES (16 << 10) #define MICROPROFILE_NUM_QUERIES (8 << 10) #define MAX_FONT_CHARS 256 #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 const int FONT_TEX_X = 1024; const int FONT_TEX_Y = 9; const uint8_t profiler_font[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x78, 0x38, 0x78, 0x7c, 0x7c, 0x3c, 0x44, 0x38, 0x04, 0x44, 0x40, 0x44, 0x44, 0x38, 0x78, 0x38, 0x78, 0x38, 0x7c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x7c, 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x18, 0x00, 0x40, 0x10, 0x08, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x10, 0x38, 0x7c, 0x08, 0x7c, 0x1c, 0x7c, 0x38, 0x38, 0x10, 0x28, 0x28, 0x10, 0x00, 0x20, 0x10, 0x08, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x20, 0x38, 0x38, 0x70, 0x00, 0x1c, 0x10, 0x00, 0x1c, 0x10, 0x70, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x44, 0x44, 0x44, 0x40, 0x40, 0x40, 0x44, 0x10, 0x04, 0x48, 0x40, 0x6c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x10, 0x44, 0x44, 0x44, 0x44, 0x44, 0x04, 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x24, 0x00, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x30, 0x44, 0x04, 0x18, 0x40, 0x20, 0x04, 0x44, 0x44, 0x10, 0x28, 0x28, 0x3c, 0x44, 0x50, 0x10, 0x10, 0x08, 0x54, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x10, 0x44, 0x44, 0x40, 0x40, 0x04, 0x28, 0x00, 0x30, 0x10, 0x18, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x40, 0x44, 0x40, 0x40, 0x40, 0x44, 0x10, 0x04, 0x50, 0x40, 0x54, 0x64, 0x44, 0x44, 0x44, 0x44, 0x40, 0x10, 0x44, 0x44, 0x44, 0x28, 0x28, 0x08, 0x00, 0x38, 0x78, 0x3c, 0x3c, 0x38, 0x20, 0x38, 0x78, 0x30, 0x18, 0x44, 0x10, 0x6c, 0x78, 0x38, 0x78, 0x3c, 0x5c, 0x3c, 0x3c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x7c, 0x00, 0x4c, 0x10, 0x04, 0x08, 0x28, 0x78, 0x40, 0x08, 0x44, 0x44, 0x10, 0x00, 0x7c, 0x50, 0x08, 0x50, 0x00, 0x20, 0x04, 0x38, 0x10, 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x10, 0x7c, 0x08, 0x08, 0x54, 0x40, 0x20, 0x04, 0x44, 0x00, 0x30, 0x10, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x78, 0x40, 0x44, 0x78, 0x78, 0x40, 0x7c, 0x10, 0x04, 0x60, 0x40, 0x54, 0x54, 0x44, 0x78, 0x44, 0x78, 0x38, 0x10, 0x44, 0x44, 0x54, 0x10, 0x10, 0x10, 0x00, 0x04, 0x44, 0x40, 0x44, 0x44, 0x78, 0x44, 0x44, 0x10, 0x08, 0x48, 0x10, 0x54, 0x44, 0x44, 0x44, 0x44, 0x60, 0x40, 0x10, 0x44, 0x44, 0x44, 0x28, 0x44, 0x08, 0x00, 0x54, 0x10, 0x18, 0x18, 0x48, 0x04, 0x78, 0x10, 0x38, 0x3c, 0x10, 0x00, 0x28, 0x38, 0x10, 0x20, 0x00, 0x20, 0x04, 0x10, 0x7c, 0x00, 0x7c, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x04, 0x10, 0x5c, 0x40, 0x10, 0x04, 0x00, 0x00, 0x60, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x44, 0x40, 0x44, 0x40, 0x40, 0x4c, 0x44, 0x10, 0x04, 0x50, 0x40, 0x44, 0x4c, 0x44, 0x40, 0x54, 0x50, 0x04, 0x10, 0x44, 0x44, 0x54, 0x28, 0x10, 0x20, 0x00, 0x3c, 0x44, 0x40, 0x44, 0x7c, 0x20, 0x44, 0x44, 0x10, 0x08, 0x70, 0x10, 0x54, 0x44, 0x44, 0x44, 0x44, 0x40, 0x38, 0x10, 0x44, 0x44, 0x54, 0x10, 0x44, 0x10, 0x00, 0x64, 0x10, 0x20, 0x04, 0x7c, 0x04, 0x44, 0x20, 0x44, 0x04, 0x10, 0x00, 0x7c, 0x14, 0x20, 0x54, 0x00, 0x20, 0x04, 0x38, 0x10, 0x10, 0x00, 0x00, 0x20, 0x10, 0x10, 0x10, 0x7c, 0x08, 0x10, 0x58, 0x40, 0x08, 0x04, 0x00, 0x00, 0x30, 0x10, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x40, 0x40, 0x44, 0x44, 0x10, 0x44, 0x48, 0x40, 0x44, 0x44, 0x44, 0x40, 0x48, 0x48, 0x44, 0x10, 0x44, 0x28, 0x6c, 0x44, 0x10, 0x40, 0x00, 0x44, 0x44, 0x40, 0x44, 0x40, 0x20, 0x3c, 0x44, 0x10, 0x08, 0x48, 0x10, 0x54, 0x44, 0x44, 0x44, 0x44, 0x40, 0x04, 0x12, 0x4c, 0x28, 0x54, 0x28, 0x3c, 0x20, 0x00, 0x44, 0x10, 0x40, 0x44, 0x08, 0x44, 0x44, 0x20, 0x44, 0x08, 0x00, 0x00, 0x28, 0x78, 0x44, 0x48, 0x00, 0x10, 0x08, 0x54, 0x10, 0x10, 0x00, 0x00, 0x40, 0x00, 0x10, 0x08, 0x00, 0x10, 0x00, 0x40, 0x40, 0x04, 0x04, 0x00, 0x00, 0x30, 0x10, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x78, 0x38, 0x78, 0x7c, 0x40, 0x3c, 0x44, 0x38, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x38, 0x40, 0x34, 0x44, 0x38, 0x10, 0x38, 0x10, 0x44, 0x44, 0x10, 0x7c, 0x00, 0x3c, 0x78, 0x3c, 0x3c, 0x3c, 0x20, 0x04, 0x44, 0x38, 0x48, 0x44, 0x38, 0x44, 0x44, 0x38, 0x78, 0x3c, 0x40, 0x78, 0x0c, 0x34, 0x10, 0x6c, 0x44, 0x04, 0x7c, 0x00, 0x38, 0x38, 0x7c, 0x38, 0x08, 0x38, 0x38, 0x20, 0x38, 0x70, 0x10, 0x00, 0x28, 0x10, 0x00, 0x34, 0x00, 0x08, 0x10, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x00, 0x20, 0x04, 0x00, 0x20, 0x10, 0x3c, 0x70, 0x00, 0x1c, 0x00, 0x7c, 0x1c, 0x10, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; GL4ProfilerDisplay::GL4ProfilerDisplay(WGLControl* control) : control_(control), program_(0), vao_(0), font_texture_(0), font_handle_(0), vertex_buffer_(MICROPROFILE_MAX_VERTICES * sizeof(Vertex) * 10, sizeof(Vertex)), draw_command_count_(0) { if (!SetupFont() || !SetupState() || !SetupShaders()) { // Hrm. assert_always(); } // Pass through mouse events. control->on_mouse_down.AddListener([](poly::ui::MouseEvent& e) { Profiler::OnMouseDown(e.button() == poly::ui::MouseEvent::Button::kLeft, e.button() == poly::ui::MouseEvent::Button::kRight); e.set_handled(true); }); control->on_mouse_up.AddListener([](poly::ui::MouseEvent& e) { Profiler::OnMouseUp(); e.set_handled(true); }); control->on_mouse_move.AddListener([](poly::ui::MouseEvent& e) { Profiler::OnMouseMove(e.x(), e.y()); e.set_handled(true); }); control->on_mouse_wheel.AddListener([](poly::ui::MouseEvent& e) { Profiler::OnMouseWheel(e.x(), e.y(), -e.dy()); e.set_handled(true); }); // Watch for toggle/mode keys and such. control->on_key_down.AddListener([](poly::ui::KeyEvent& e) { Profiler::OnKeyDown(e.key_code()); e.set_handled(true); }); control->on_key_up.AddListener([](poly::ui::KeyEvent& e) { Profiler::OnKeyUp(e.key_code()); e.set_handled(true); }); } bool GL4ProfilerDisplay::SetupFont() { // Setup font lookup table. for (uint32_t i = 0; i < poly::countof(font_description_.char_offsets); ++i) { font_description_.char_offsets[i] = 206; } for (uint32_t i = 'A'; i <= 'Z'; ++i) { font_description_.char_offsets[i] = (i - 'A') * 8 + 1; } for (uint32_t i = 'a'; i <= 'z'; ++i) { font_description_.char_offsets[i] = (i - 'a') * 8 + 217; } for (uint32_t i = '0'; i <= '9'; ++i) { font_description_.char_offsets[i] = (i - '0') * 8 + 433; } for (uint32_t i = '!'; i <= '/'; ++i) { font_description_.char_offsets[i] = (i - '!') * 8 + 513; } for (uint32_t i = ':'; i <= '@'; ++i) { font_description_.char_offsets[i] = (i - ':') * 8 + 625 + 8; } for (uint32_t i = '['; i <= '_'; ++i) { font_description_.char_offsets[i] = (i - '[') * 8 + 681 + 8; } for (uint32_t i = '{'; i <= '~'; ++i) { font_description_.char_offsets[i] = (i - '{') * 8 + 721 + 8; } // Unpack font bitmap into an RGBA texture. const int UNPACKED_SIZE = FONT_TEX_X * FONT_TEX_Y * 4; uint32_t unpacked[UNPACKED_SIZE]; int idx = 0; int end = FONT_TEX_X * FONT_TEX_Y / 8; for (int i = 0; i < end; i++) { uint8_t b = profiler_font[i]; for (int j = 0; j < 8; ++j) { unpacked[idx++] = b & 0x80 ? 0xFFFFFFFFu : 0; b <<= 1; } } glCreateTextures(GL_TEXTURE_2D, 1, &font_texture_); glTextureParameteri(font_texture_, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTextureParameteri(font_texture_, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTextureParameteri(font_texture_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTextureParameteri(font_texture_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTextureStorage2D(font_texture_, 1, GL_RGBA8, FONT_TEX_X, FONT_TEX_Y); glTextureSubImage2D(font_texture_, 0, 0, 0, FONT_TEX_X, FONT_TEX_Y, GL_RGBA, GL_UNSIGNED_BYTE, unpacked); font_handle_ = glGetTextureHandleARB(font_texture_); glMakeTextureHandleResidentARB(font_handle_); return true; } bool GL4ProfilerDisplay::SetupState() { if (!vertex_buffer_.Initialize()) { return false; } return true; } bool GL4ProfilerDisplay::SetupShaders() { const std::string header = "\n\ #version 450 \n\ #extension GL_ARB_bindless_texture : require\n\ #extension GL_ARB_explicit_uniform_location : require\n\ #extension GL_ARB_shading_language_420pack : require\n\ precision highp float; \n\ precision highp int;\n\ layout(std140, column_major) uniform;\n\ layout(std430, column_major) buffer;\n\ struct VertexData {\n\ vec4 color; \n\ vec2 uv; \n\ };\n\ "; const std::string vertex_shader_source = header + "\n\ layout(location = 0) uniform mat4 projection_matrix; \n\ struct VertexFetch { \n\ vec2 pos; \n\ vec4 color; \n\ vec2 uv; \n\ }; \n\ layout(location = 0) in VertexFetch vfetch; \n\ layout(location = 0) out VertexData vtx; \n\ void main() { \n\ gl_Position = projection_matrix * vec4(vfetch.pos.xy, 0.0, 1.0); \n\ vtx.color = vfetch.color; \n\ vtx.uv = vfetch.uv; \n\ } \n\ "; const std::string fragment_shader_source = header + "\n\ layout(location = 1, bindless_sampler) uniform sampler2D font_texture; \n\ layout(location = 2) uniform float font_height; \n\ layout(location = 0) in VertexData vtx; \n\ layout(location = 0) out vec4 oC; \n\ void main() { \n\ if (vtx.uv.x > 1.0) { \n\ oC = vtx.color; \n\ } else { \n\ vec4 color = texture(font_texture, vtx.uv); \n\ oC = color.rgba * vtx.color; \n\ if (color.a < 0.5) { \n\ vec4 c1 = texture(font_texture, vtx.uv + vec2(0.0, font_height)); \n\ oC = vec4(0, 0, 0, c1.a); \n\ } \n\ } \n\ } \n\ "; GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); const char* vertex_shader_source_ptr = vertex_shader_source.c_str(); GLint vertex_shader_source_length = GLint(vertex_shader_source.size()); glShaderSource(vertex_shader, 1, &vertex_shader_source_ptr, &vertex_shader_source_length); glCompileShader(vertex_shader); GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); const char* fragment_shader_source_ptr = fragment_shader_source.c_str(); GLint fragment_shader_source_length = GLint(fragment_shader_source.size()); glShaderSource(fragment_shader, 1, &fragment_shader_source_ptr, &fragment_shader_source_length); glCompileShader(fragment_shader); program_ = glCreateProgram(); glAttachShader(program_, vertex_shader); glAttachShader(program_, fragment_shader); glLinkProgram(program_); glDeleteShader(vertex_shader); glDeleteShader(fragment_shader); glProgramUniformHandleui64ARB(program_, 1, font_handle_); glProgramUniform1f(program_, 2, 1.0f / FONT_TEX_Y); glCreateVertexArrays(1, &vao_); glEnableVertexArrayAttrib(vao_, 0); glVertexArrayAttribBinding(vao_, 0, 0); glVertexArrayAttribFormat(vao_, 0, 2, GL_FLOAT, GL_FALSE, offsetof(Vertex, x)); glEnableVertexArrayAttrib(vao_, 1); glVertexArrayAttribBinding(vao_, 1, 0); glVertexArrayAttribFormat(vao_, 1, 4, GL_UNSIGNED_BYTE, GL_TRUE, offsetof(Vertex, color)); glEnableVertexArrayAttrib(vao_, 2); glVertexArrayAttribBinding(vao_, 2, 0); glVertexArrayAttribFormat(vao_, 2, 2, GL_FLOAT, GL_FALSE, offsetof(Vertex, u)); glVertexArrayVertexBuffer(vao_, 0, vertex_buffer_.handle(), 0, sizeof(Vertex)); return true; } GL4ProfilerDisplay::~GL4ProfilerDisplay() { vertex_buffer_.Shutdown(); glMakeTextureHandleNonResidentARB(font_handle_); glDeleteTextures(1, &font_texture_); glDeleteVertexArrays(1, &vao_); glDeleteProgram(program_); } uint32_t GL4ProfilerDisplay::width() const { return control_->width(); } uint32_t GL4ProfilerDisplay::height() const { return control_->height(); } void GL4ProfilerDisplay::Begin() { glEnablei(GL_BLEND, 0); glBlendFunci(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_DEPTH_TEST); float left = 0.0f; float right = float(width()); float bottom = float(height()); float top = 0.0f; float z_near = -1.0f; float z_far = 1.0f; float projection[16] = {0}; projection[0] = 2.0f / (right - left); projection[5] = 2.0f / (top - bottom); projection[10] = -2.0f / (z_far - z_near); projection[12] = -(right + left) / (right - left); projection[13] = -(top + bottom) / (top - bottom); projection[14] = -(z_far + z_near) / (z_far - z_near); projection[15] = 1.0f; glProgramUniformMatrix4fv(program_, 0, 1, GL_FALSE, projection); glUseProgram(program_); glBindVertexArray(vao_); } void GL4ProfilerDisplay::End() { Flush(); glUseProgram(0); glBindVertexArray(0); } GL4ProfilerDisplay::Vertex* GL4ProfilerDisplay::BeginVertices(size_t count) { if (draw_command_count_ + 1 > kMaxCommands) { Flush(); } current_allocation_ = vertex_buffer_.Acquire(sizeof(Vertex) * count); return reinterpret_cast(current_allocation_.host_ptr); } void GL4ProfilerDisplay::EndVertices(GLenum prim_type) { size_t vertex_count = current_allocation_.length / sizeof(Vertex); if (draw_command_count_ && draw_commands_[draw_command_count_ - 1].prim_type == prim_type) { // Coalesce. auto& prev_command = draw_commands_[draw_command_count_ - 1]; prev_command.vertex_count += vertex_count; } else { auto& command = draw_commands_[draw_command_count_++]; command.prim_type = prim_type; command.vertex_offset = current_allocation_.offset / sizeof(Vertex); command.vertex_count = vertex_count; } vertex_buffer_.Commit(std::move(current_allocation_)); } void GL4ProfilerDisplay::Flush() { if (!draw_command_count_) { return; } for (size_t i = 0; i < draw_command_count_; ++i) { glDrawArrays(draw_commands_[i].prim_type, GLint(draw_commands_[i].vertex_offset), GLsizei(draw_commands_[i].vertex_count)); } draw_command_count_ = 0; vertex_buffer_.WaitUntilClean(); } void GL4ProfilerDisplay::DrawBox(int x0, int y0, int x1, int y1, uint32_t color, BoxType type) { auto v = BeginVertices(6); if (type == BoxType::kFlat) { color = ((color & 0xff) << 16) | ((color >> 16) & 0xff) | (0xff00ff00 & color); Q0(v, x, (float)x0); Q0(v, y, (float)y0); Q0(v, color, color); Q0(v, u, 2.0f); Q0(v, v, 2.0f); Q1(v, x, (float)x1); Q1(v, y, (float)y0); Q1(v, color, color); Q1(v, u, 2.0f); Q1(v, v, 2.0f); Q2(v, x, (float)x1); Q2(v, y, (float)y1); Q2(v, color, color); Q2(v, u, 2.0f); Q2(v, v, 2.0f); Q3(v, x, (float)x0); Q3(v, y, (float)y1); Q3(v, color, color); Q3(v, u, 2.0f); Q3(v, v, 2.0f); } else { uint32_t r = 0xff & (color >> 16); uint32_t g = 0xff & (color >> 8); uint32_t b = 0xff & color; uint32_t nMax = std::max(std::max(std::max(r, g), b), 30u); uint32_t nMin = std::min(std::min(std::min(r, g), b), 180u); uint32_t r0 = 0xff & ((r + nMax) / 2); uint32_t g0 = 0xff & ((g + nMax) / 2); uint32_t b0 = 0xff & ((b + nMax) / 2); uint32_t r1 = 0xff & ((r + nMin) / 2); uint32_t g1 = 0xff & ((g + nMin) / 2); uint32_t b1 = 0xff & ((b + nMin) / 2); uint32_t color0 = (r0 << 0) | (g0 << 8) | (b0 << 16) | (0xff000000 & color); uint32_t color1 = (r1 << 0) | (g1 << 8) | (b1 << 16) | (0xff000000 & color); Q0(v, x, (float)x0); Q0(v, y, (float)y0); Q0(v, color, color0); Q0(v, u, 2.0f); Q0(v, v, 2.0f); Q1(v, x, (float)x1); Q1(v, y, (float)y0); Q1(v, color, color0); Q1(v, u, 3.0f); Q1(v, v, 2.0f); Q2(v, x, (float)x1); Q2(v, y, (float)y1); Q2(v, color, color1); Q2(v, u, 3.0f); Q2(v, v, 3.0f); Q3(v, x, (float)x0); Q3(v, y, (float)y1); Q3(v, color, color1); Q3(v, u, 2.0f); Q3(v, v, 3.0f); } EndVertices(GL_TRIANGLES); } void GL4ProfilerDisplay::DrawLine2D(uint32_t count, float* vertices, uint32_t color) { if (!count || !vertices) { return; } auto v = BeginVertices(2 * (count - 1)); color = 0xff000000 | ((color & 0xff) << 16) | (color & 0xff00ff00) | ((color >> 16) & 0xff); for (uint32_t i = 0; i < count - 1; ++i) { v[0].x = vertices[i * 2]; v[0].y = vertices[i * 2 + 1]; v[0].color = color; v[0].u = 2.0f; v[0].v = 2.0f; v[1].x = vertices[(i + 1) * 2]; v[1].y = vertices[(i + 1) * 2 + 1]; v[1].color = color; v[1].u = 2.0f; v[1].v = 2.0f; v += 2; } EndVertices(GL_LINES); } void GL4ProfilerDisplay::DrawText(int x, int y, uint32_t color, const char* text, size_t text_length) { if (!text_length) { return; } const float fOffsetU = 5.0f / 1024.0f; float fX = (float)x; float fY = (float)y; float fY2 = fY + (MICROPROFILE_TEXT_HEIGHT + 1); auto v = BeginVertices(6 * text_length); const char* pStr = text; color = 0xff000000 | ((color & 0xff) << 16) | (color & 0xff00) | ((color >> 16) & 0xff); for (size_t j = 0; j < text_length; ++j) { int16_t char_offset = font_description_.char_offsets[(int)*pStr++]; float fOffset = char_offset / 1024.0f; Q0(v, x, fX); Q0(v, y, fY); Q0(v, color, color); Q0(v, u, fOffset); Q0(v, v, 0.0f); Q1(v, x, fX + MICROPROFILE_TEXT_WIDTH); Q1(v, y, fY); Q1(v, color, color); Q1(v, u, fOffset + fOffsetU); Q1(v, v, 0.0f); Q2(v, x, fX + MICROPROFILE_TEXT_WIDTH); Q2(v, y, fY2); Q2(v, color, color); Q2(v, u, fOffset + fOffsetU); Q2(v, v, 1.0f); Q3(v, x, fX); Q3(v, y, fY2); Q3(v, color, color); Q3(v, u, fOffset); Q3(v, v, 1.0f); fX += MICROPROFILE_TEXT_WIDTH + 1; v += 6; } EndVertices(GL_TRIANGLES); } } // namespace gl4 } // namespace gpu } // namespace xe