From 4c2257a29de05a397d5d77d1b14cc4d6cc10df96 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Thu, 5 Nov 2015 23:03:02 -0800 Subject: [PATCH] Moving imgui to the new ImmediateDrawer. --- src/xenia/debug/ui/debug_window.cc | 7 +- src/xenia/debug/ui/debug_window.h | 10 +- src/xenia/debug/ui/imgui_renderer.h | 55 ---- src/xenia/gpu/gl4/trace_viewer_main.cc | 272 +----------------- src/xenia/ui/gl/gl_immediate_drawer.cc | 52 ++-- src/xenia/ui/gl/gl_immediate_drawer.h | 5 +- .../imgui_renderer.cc => ui/imgui_drawer.cc} | 264 ++++------------- src/xenia/ui/imgui_drawer.h | 51 ++++ src/xenia/ui/immediate_drawer.h | 25 +- src/xenia/ui/microprofile_drawer.cc | 21 +- 10 files changed, 198 insertions(+), 564 deletions(-) delete mode 100644 src/xenia/debug/ui/imgui_renderer.h rename src/xenia/{debug/ui/imgui_renderer.cc => ui/imgui_drawer.cc} (67%) create mode 100644 src/xenia/ui/imgui_drawer.h diff --git a/src/xenia/debug/ui/debug_window.cc b/src/xenia/debug/ui/debug_window.cc index 62bf5ccda..31873095a 100644 --- a/src/xenia/debug/ui/debug_window.cc +++ b/src/xenia/debug/ui/debug_window.cc @@ -28,11 +28,11 @@ #include "xenia/base/threading.h" #include "xenia/cpu/frontend/ppc_disasm.h" #include "xenia/cpu/stack_walker.h" -#include "xenia/debug/ui/imgui_renderer.h" #include "xenia/gpu/graphics_system.h" #include "xenia/kernel/xmodule.h" #include "xenia/kernel/xthread.h" #include "xenia/ui/gl/gl_context.h" +#include "xenia/ui/imgui_drawer.h" DEFINE_bool(imgui_debug, false, "Show ImGui debugging tools."); @@ -91,7 +91,7 @@ bool DebugWindow::Initialize() { window_->on_closed.AddListener([this](UIEvent* e) { // Kill now while we have a GL context. - imgui_renderer_.reset(); + imgui_drawer_.reset(); }); loop_->on_quit.AddListener([this](UIEvent* e) { window_.reset(); }); @@ -120,8 +120,7 @@ bool DebugWindow::Initialize() { window_->set_context(std::move(context)); // Setup ImGui. - imgui_renderer_ = - std::make_unique(window_.get(), window_->context()); + imgui_drawer_ = std::make_unique(window_.get()); window_->on_key_char.AddListener([](xe::ui::KeyEvent* e) { auto& io = ImGui::GetIO(); if (e->key_code() > 0 && e->key_code() < 0x10000) { diff --git a/src/xenia/debug/ui/debug_window.h b/src/xenia/debug/ui/debug_window.h index 833bfad06..6ebc2f0bc 100644 --- a/src/xenia/debug/ui/debug_window.h +++ b/src/xenia/debug/ui/debug_window.h @@ -21,12 +21,16 @@ #include "xenia/ui/window.h" #include "xenia/xbox.h" +namespace xe { +namespace ui { +class ImGuiDrawer; +} // namespace ui +} // namespace xe + namespace xe { namespace debug { namespace ui { -class ImGuiRenderer; - class DebugWindow : public DebugListener { public: ~DebugWindow(); @@ -91,7 +95,7 @@ class DebugWindow : public DebugListener { Debugger* debugger_ = nullptr; xe::ui::Loop* loop_ = nullptr; std::unique_ptr window_; - std::unique_ptr imgui_renderer_; + std::unique_ptr imgui_drawer_; uint64_t last_draw_tick_count_ = 0; uintptr_t capstone_handle_ = 0; diff --git a/src/xenia/debug/ui/imgui_renderer.h b/src/xenia/debug/ui/imgui_renderer.h deleted file mode 100644 index 2fe153942..000000000 --- a/src/xenia/debug/ui/imgui_renderer.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - ****************************************************************************** - * 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. * - ****************************************************************************** - */ - -#ifndef XENIA_DEBUG_UI_IMGUI_RENDERER_H_ -#define XENIA_DEBUG_UI_IMGUI_RENDERER_H_ - -#include - -#include "third_party/imgui/imgui.h" -#include "xenia/base/clock.h" -#include "xenia/base/logging.h" -#include "xenia/base/math.h" -#include "xenia/ui/gl/circular_buffer.h" -#include "xenia/ui/gl/gl_context.h" -#include "xenia/ui/window.h" - -namespace xe { -namespace debug { -namespace ui { - -class ImGuiRenderer { - public: - ImGuiRenderer(xe::ui::Window* window, xe::ui::GraphicsContext* context); - ~ImGuiRenderer(); - - private: - static ImGuiRenderer* global_renderer_; - - void Initialize(); - void InitializeShaders(); - void InitializeFontTextures(); - void Shutdown(); - - void RenderDrawLists(ImDrawData* data); - - xe::ui::Window* window_ = nullptr; - xe::ui::GraphicsContext* context_ = nullptr; - - GLuint program_ = 0; - GLuint vao_ = 0; - xe::ui::gl::CircularBuffer vertex_buffer_; - xe::ui::gl::CircularBuffer index_buffer_; -}; - -} // namespace ui -} // namespace debug -} // namespace xe - -#endif // XENIA_DEBUG_UI_IMGUI_RENDERER_H_ diff --git a/src/xenia/gpu/gl4/trace_viewer_main.cc b/src/xenia/gpu/gl4/trace_viewer_main.cc index f27103d90..2725af0b5 100644 --- a/src/xenia/gpu/gl4/trace_viewer_main.cc +++ b/src/xenia/gpu/gl4/trace_viewer_main.cc @@ -11,7 +11,6 @@ #include #include "third_party/imgui/imgui.h" - #include "xenia/base/clock.h" #include "xenia/base/logging.h" #include "xenia/base/main.h" @@ -25,6 +24,7 @@ #include "xenia/gpu/xenos.h" #include "xenia/profiling.h" #include "xenia/ui/gl/gl_context.h" +#include "xenia/ui/imgui_drawer.h" #include "xenia/ui/window.h" // HACK: until we have another impl, we just use gl4 directly. @@ -2182,8 +2182,7 @@ void DrawUI(xe::ui::Window* window, TracePlayer& player, Memory* memory) { DrawPacketDisassemblerUI(window, player, memory); } -void ImImpl_Setup(); -void ImImpl_Shutdown(); +std::unique_ptr imgui_drawer_; int trace_viewer_main(const std::vector& args) { // Create the emulator but don't initialize so we can setup the window. @@ -2202,6 +2201,7 @@ int trace_viewer_main(const std::vector& args) { window->on_closed.AddListener([&loop](xe::ui::UIEvent* e) { loop->Quit(); XELOGI("User-initiated death!"); + imgui_drawer_.reset(); exit(1); }); loop->on_quit.AddListener([&window](xe::ui::UIEvent* e) { window.reset(); }); @@ -2236,9 +2236,10 @@ int trace_viewer_main(const std::vector& args) { window->set_title(std::wstring(L"Xenia GPU Trace Viewer: ") + file_name); auto graphics_system = emulator->graphics_system(); - Profiler::set_window(nullptr); - TracePlayer player(loop.get(), emulator->graphics_system()); + imgui_drawer_ = std::make_unique(window.get()); + + TracePlayer player(loop.get(), graphics_system); if (!player.Open(abs_path)) { XELOGE("Could not load trace file"); return 1; @@ -2290,11 +2291,6 @@ int trace_viewer_main(const std::vector& args) { }); window->on_painting.AddListener([&](xe::ui::UIEvent* e) { - static bool imgui_setup = false; - if (!imgui_setup) { - ImImpl_Setup(); - imgui_setup = true; - } auto& io = ImGui::GetIO(); auto current_ticks = Clock::QueryHostTickCount(); static uint64_t last_ticks = 0; @@ -2326,7 +2322,7 @@ int trace_viewer_main(const std::vector& args) { // Wait until we are exited. loop->AwaitQuit(); - ImImpl_Shutdown(); + imgui_drawer_.reset(); emulator.reset(); window.reset(); @@ -2334,260 +2330,6 @@ int trace_viewer_main(const std::vector& args) { return 0; } -// TODO(benvanik): move to another file. - -static int shader_handle, vert_handle, frag_handle; -static int texture_location, proj_mtx_location; -static int position_location, uv_location, colour_location; -static size_t vbo_max_size = 20000; -static unsigned int vbo_handle, vao_handle; -void ImImpl_RenderDrawLists(ImDrawData* data); -void ImImpl_Setup() { - ImGuiIO& io = ImGui::GetIO(); - - const GLchar* vertex_shader = - "#version 330\n" - "uniform mat4 ProjMtx;\n" - "in vec2 Position;\n" - "in vec2 UV;\n" - "in vec4 Color;\n" - "out vec2 Frag_UV;\n" - "out vec4 Frag_Color;\n" - "void main()\n" - "{\n" - " Frag_UV = UV;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" - "}\n"; - - const GLchar* fragment_shader = - "#version 330\n" - "uniform sampler2D Texture;\n" - "in vec2 Frag_UV;\n" - "in vec4 Frag_Color;\n" - "out vec4 Out_Color;\n" - "void main()\n" - "{\n" - " Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n" - "}\n"; - - shader_handle = glCreateProgram(); - vert_handle = glCreateShader(GL_VERTEX_SHADER); - frag_handle = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(vert_handle, 1, &vertex_shader, 0); - glShaderSource(frag_handle, 1, &fragment_shader, 0); - glCompileShader(vert_handle); - glCompileShader(frag_handle); - glAttachShader(shader_handle, vert_handle); - glAttachShader(shader_handle, frag_handle); - glLinkProgram(shader_handle); - - texture_location = glGetUniformLocation(shader_handle, "Texture"); - proj_mtx_location = glGetUniformLocation(shader_handle, "ProjMtx"); - position_location = glGetAttribLocation(shader_handle, "Position"); - uv_location = glGetAttribLocation(shader_handle, "UV"); - colour_location = glGetAttribLocation(shader_handle, "Color"); - - glGenBuffers(1, &vbo_handle); - glBindBuffer(GL_ARRAY_BUFFER, vbo_handle); - glBufferData(GL_ARRAY_BUFFER, vbo_max_size, NULL, GL_DYNAMIC_DRAW); - - glGenVertexArrays(1, &vao_handle); - glBindVertexArray(vao_handle); - glBindBuffer(GL_ARRAY_BUFFER, vbo_handle); - glEnableVertexAttribArray(position_location); - glEnableVertexAttribArray(uv_location); - glEnableVertexAttribArray(colour_location); - - glVertexAttribPointer(position_location, 2, GL_FLOAT, GL_FALSE, - sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, pos)); - glVertexAttribPointer(uv_location, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), - (GLvoid*)offsetof(ImDrawVert, uv)); - glVertexAttribPointer(colour_location, 4, GL_UNSIGNED_BYTE, GL_TRUE, - sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, col)); - glBindVertexArray(0); - glDisableVertexAttribArray(position_location); - glDisableVertexAttribArray(uv_location); - glDisableVertexAttribArray(colour_location); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32( - &pixels, &width, &height); // Load as RGBA 32-bits for OpenGL3 demo - // because it is more likely to be compatible - // with user's existing shader. - - GLuint tex_id; - glCreateTextures(GL_TEXTURE_2D, 1, &tex_id); - glTextureParameteri(tex_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTextureParameteri(tex_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTextureStorage2D(tex_id, 1, GL_RGBA8, width, height); - glTextureSubImage2D(tex_id, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, - pixels); - - // Store our identifier - io.Fonts->TexID = (void*)(intptr_t)tex_id; - - io.DeltaTime = 1.0f / 60.0f; - io.RenderDrawListsFn = ImImpl_RenderDrawLists; - - auto& style = ImGui::GetStyle(); - style.WindowRounding = 0; - - style.Colors[ImGuiCol_Text] = ImVec4(0.89f, 0.90f, 0.90f, 1.00f); - style.Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); - style.Colors[ImGuiCol_ChildWindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - style.Colors[ImGuiCol_Border] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); - style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.60f); - style.Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.22f); - style.Colors[ImGuiCol_TitleBg] = ImVec4(0.00f, 1.00f, 0.00f, 0.78f); - style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.58f, 0.00f, 0.61f); - style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.00f, 0.40f, 0.11f, 0.59f); - style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.00f, 0.68f, 0.00f, 0.68f); - style.Colors[ImGuiCol_ScrollbarGrabHovered] = - ImVec4(0.00f, 1.00f, 0.15f, 0.62f); - style.Colors[ImGuiCol_ScrollbarGrabActive] = - ImVec4(0.00f, 0.91f, 0.09f, 0.40f); - style.Colors[ImGuiCol_ComboBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.99f); - style.Colors[ImGuiCol_CheckMark] = ImVec4(0.74f, 0.90f, 0.72f, 0.50f); - style.Colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); - style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.34f, 0.75f, 0.11f, 1.00f); - style.Colors[ImGuiCol_Button] = ImVec4(0.15f, 0.56f, 0.11f, 0.60f); - style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.19f, 0.72f, 0.09f, 1.00f); - style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.19f, 0.60f, 0.09f, 1.00f); - style.Colors[ImGuiCol_Header] = ImVec4(0.00f, 0.40f, 0.00f, 0.71f); - style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.00f, 0.60f, 0.26f, 0.80f); - style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.00f, 0.75f, 0.00f, 0.80f); - style.Colors[ImGuiCol_Column] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); - style.Colors[ImGuiCol_ColumnHovered] = ImVec4(0.36f, 0.89f, 0.38f, 1.00f); - style.Colors[ImGuiCol_ColumnActive] = ImVec4(0.13f, 0.50f, 0.11f, 1.00f); - style.Colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); - style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.60f); - style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.90f); - style.Colors[ImGuiCol_CloseButton] = ImVec4(0.00f, 0.72f, 0.00f, 0.96f); - style.Colors[ImGuiCol_CloseButtonHovered] = - ImVec4(0.38f, 1.00f, 0.42f, 0.60f); - style.Colors[ImGuiCol_CloseButtonActive] = ImVec4(0.56f, 1.00f, 0.64f, 1.00f); - style.Colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); - style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); - style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); - style.Colors[ImGuiCol_PlotHistogramHovered] = - ImVec4(1.00f, 0.60f, 0.00f, 1.00f); - style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); - style.Colors[ImGuiCol_TooltipBg] = ImVec4(0.05f, 0.05f, 0.10f, 0.90f); - - io.KeyMap[ImGuiKey_Tab] = VK_TAB; - io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; - io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; - io.KeyMap[ImGuiKey_UpArrow] = VK_UP; - io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN; - io.KeyMap[ImGuiKey_Home] = VK_HOME; - io.KeyMap[ImGuiKey_End] = VK_END; - io.KeyMap[ImGuiKey_Delete] = VK_DELETE; - io.KeyMap[ImGuiKey_Backspace] = VK_BACK; - io.KeyMap[ImGuiKey_Enter] = VK_RETURN; - io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE; - io.KeyMap[ImGuiKey_A] = 'A'; - io.KeyMap[ImGuiKey_C] = 'C'; - io.KeyMap[ImGuiKey_V] = 'V'; - io.KeyMap[ImGuiKey_X] = 'X'; - io.KeyMap[ImGuiKey_Y] = 'Y'; - io.KeyMap[ImGuiKey_Z] = 'Z'; -} -void ImImpl_Shutdown() { - ImGuiIO& io = ImGui::GetIO(); - if (vao_handle) glDeleteVertexArrays(1, &vao_handle); - if (vbo_handle) glDeleteBuffers(1, &vbo_handle); - glDetachShader(shader_handle, vert_handle); - glDetachShader(shader_handle, frag_handle); - glDeleteShader(vert_handle); - glDeleteShader(frag_handle); - glDeleteProgram(shader_handle); - auto tex_id = static_cast(intptr_t(io.Fonts->TexID)); - glDeleteTextures(1, &tex_id); - ImGui::Shutdown(); -} -void ImImpl_RenderDrawLists(ImDrawData* data) { - if (data->CmdListsCount == 0) return; - - // Setup render state: alpha-blending enabled, no face culling, no depth - // testing, scissor enabled - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glActiveTexture(GL_TEXTURE0); - - // Setup orthographic projection matrix - const float width = ImGui::GetIO().DisplaySize.x; - const float height = ImGui::GetIO().DisplaySize.y; - const float ortho_projection[4][4] = { - {2.0f / width, 0.0f, 0.0f, 0.0f}, - {0.0f, 2.0f / -height, 0.0f, 0.0f}, - {0.0f, 0.0f, -1.0f, 0.0f}, - {-1.0f, 1.0f, 0.0f, 1.0f}, - }; - glProgramUniform1i(shader_handle, texture_location, 0); - glProgramUniformMatrix4fv(shader_handle, proj_mtx_location, 1, GL_FALSE, - &ortho_projection[0][0]); - - // Grow our buffer according to what we need - glBindBuffer(GL_ARRAY_BUFFER, vbo_handle); - size_t neededBufferSize = data->TotalVtxCount * sizeof(ImDrawVert); - if (neededBufferSize > vbo_max_size) { - vbo_max_size = neededBufferSize + 5000; // Grow buffer - glBufferData(GL_ARRAY_BUFFER, vbo_max_size, NULL, GL_STREAM_DRAW); - } - - glBindVertexArray(vao_handle); - glUseProgram(shader_handle); - - GLuint ib; - glGenBuffers(1, &ib); - - ImTextureID prev_texture_id = 0; - for (int n = 0; n < data->CmdListsCount; n++) { - const ImDrawList* cmd_list = data->CmdLists[n]; - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, - (GLsizeiptr)cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx), - (GLvoid*)&cmd_list->IdxBuffer.front(), GL_STREAM_DRAW); - // Copy and convert all vertices into a single contiguous buffer - unsigned char* buffer_data = - (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - memcpy(buffer_data, &cmd_list->VtxBuffer[0], - cmd_list->VtxBuffer.size() * sizeof(ImDrawVert)); - glUnmapBuffer(GL_ARRAY_BUFFER); - const ImDrawIdx* idx_buffer_offset = 0; - for (auto cmd = cmd_list->CmdBuffer.begin(); - cmd != cmd_list->CmdBuffer.end(); ++cmd) { - if (cmd->TextureId != prev_texture_id) { - glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)cmd->TextureId); - prev_texture_id = cmd->TextureId; - } - glScissor((int)cmd->ClipRect.x, (int)(height - cmd->ClipRect.w), - (int)(cmd->ClipRect.z - cmd->ClipRect.x), - (int)(cmd->ClipRect.w - cmd->ClipRect.y)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->ElemCount, GL_UNSIGNED_SHORT, - idx_buffer_offset); - idx_buffer_offset += cmd->ElemCount; - } - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glDeleteBuffers(1, &ib); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - // Restore modified state - glBindVertexArray(0); - glUseProgram(0); - glDisable(GL_SCISSOR_TEST); - glBindTexture(GL_TEXTURE_2D, 0); -} - } // namespace gpu } // namespace xe diff --git a/src/xenia/ui/gl/gl_immediate_drawer.cc b/src/xenia/ui/gl/gl_immediate_drawer.cc index a84e7d1d9..8d11ebcce 100644 --- a/src/xenia/ui/gl/gl_immediate_drawer.cc +++ b/src/xenia/ui/gl/gl_immediate_drawer.cc @@ -25,8 +25,8 @@ class GLImmediateTexture : public ImmediateTexture { GLImmediateTexture(uint32_t width, uint32_t height, ImmediateTextureFilter filter, bool repeat) : ImmediateTexture(width, height) { - GLuint handle; - glCreateTextures(GL_TEXTURE_2D, 1, &handle); + GLuint gl_handle; + glCreateTextures(GL_TEXTURE_2D, 1, &gl_handle); GLenum gl_filter = GL_NEAREST; switch (filter) { @@ -37,21 +37,22 @@ class GLImmediateTexture : public ImmediateTexture { gl_filter = GL_LINEAR; break; } - glTextureParameteri(handle, GL_TEXTURE_MIN_FILTER, gl_filter); - glTextureParameteri(handle, GL_TEXTURE_MAG_FILTER, gl_filter); + glTextureParameteri(gl_handle, GL_TEXTURE_MIN_FILTER, gl_filter); + glTextureParameteri(gl_handle, GL_TEXTURE_MAG_FILTER, gl_filter); - glTextureParameteri(handle, GL_TEXTURE_WRAP_S, + glTextureParameteri(gl_handle, GL_TEXTURE_WRAP_S, repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); - glTextureParameteri(handle, GL_TEXTURE_WRAP_T, + glTextureParameteri(gl_handle, GL_TEXTURE_WRAP_T, repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); - glTextureStorage2D(handle, 1, GL_RGBA8, width, height); + glTextureStorage2D(gl_handle, 1, GL_RGBA8, width, height); - this->handle = static_cast(handle); + handle = static_cast(gl_handle); } ~GLImmediateTexture() override { - // + GLuint gl_handle = static_cast(handle); + glDeleteTextures(1, &gl_handle); } }; @@ -191,6 +192,7 @@ void GLImmediateDrawer::Begin(int render_target_width, // Prepare drawing resources. glUseProgram(program_); glBindVertexArray(vao_); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_); // Setup orthographic projection matrix and viewport. const float ortho_projection[4][4] = { @@ -203,7 +205,7 @@ void GLImmediateDrawer::Begin(int render_target_width, glViewport(0, 0, render_target_width, render_target_height); } -void GLImmediateDrawer::Draw(const ImmediateDrawBatch& batch) { +void GLImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { glNamedBufferSubData(vertex_buffer_, 0, batch.vertex_count * sizeof(ImmediateVertex), batch.vertices); @@ -212,22 +214,26 @@ void GLImmediateDrawer::Draw(const ImmediateDrawBatch& batch) { batch.indices); } - if (batch.scissor) { + batch_has_index_buffer_ = !!batch.indices; +} + +void GLImmediateDrawer::Draw(const ImmediateDraw& draw) { + if (draw.scissor) { glEnable(GL_SCISSOR_TEST); - glScissor(batch.scissor_rect[0], batch.scissor_rect[1], - batch.scissor_rect[2], batch.scissor_rect[3]); + glScissor(draw.scissor_rect[0], draw.scissor_rect[1], draw.scissor_rect[2], + draw.scissor_rect[3]); } else { glDisable(GL_SCISSOR_TEST); } - if (batch.texture_handle) { - glBindTextureUnit(0, static_cast(batch.texture_handle)); + if (draw.texture_handle) { + glBindTextureUnit(0, static_cast(draw.texture_handle)); } else { glBindTextureUnit(0, 0); } GLenum mode = GL_TRIANGLES; - switch (batch.primitive_type) { + switch (draw.primitive_type) { case ImmediatePrimitiveType::kLines: mode = GL_LINES; break; @@ -236,21 +242,25 @@ void GLImmediateDrawer::Draw(const ImmediateDrawBatch& batch) { break; } - if (batch.indices) { - glDrawElements(mode, batch.index_count, GL_UNSIGNED_SHORT, nullptr); + if (batch_has_index_buffer_) { + glDrawElementsBaseVertex( + mode, draw.count, GL_UNSIGNED_SHORT, + reinterpret_cast(draw.index_offset * sizeof(uint16_t)), + draw.base_vertex); } else { - glDrawArrays(mode, 0, batch.vertex_count); + glDrawArrays(mode, draw.base_vertex, draw.count); } - - glFlush(); } +void GLImmediateDrawer::EndDrawBatch() { glFlush(); } + void GLImmediateDrawer::End() { // Restore modified state. glDisable(GL_SCISSOR_TEST); glBindTextureUnit(0, 0); glUseProgram(0); glBindVertexArray(0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); if (!was_current_) { graphics_context_->ClearCurrent(); diff --git a/src/xenia/ui/gl/gl_immediate_drawer.h b/src/xenia/ui/gl/gl_immediate_drawer.h index ec384c548..e9e02798e 100644 --- a/src/xenia/ui/gl/gl_immediate_drawer.h +++ b/src/xenia/ui/gl/gl_immediate_drawer.h @@ -32,7 +32,9 @@ class GLImmediateDrawer : public ImmediateDrawer { void UpdateTexture(ImmediateTexture* texture, const uint8_t* data) override; void Begin(int render_target_width, int render_target_height) override; - void Draw(const ImmediateDrawBatch& batch) override; + void BeginDrawBatch(const ImmediateDrawBatch& batch) override; + void Draw(const ImmediateDraw& draw) override; + void EndDrawBatch() override; void End() override; private: @@ -44,6 +46,7 @@ class GLImmediateDrawer : public ImmediateDrawer { GLuint index_buffer_ = 0; bool was_current_ = false; + bool batch_has_index_buffer_ = false; }; } // namespace gl diff --git a/src/xenia/debug/ui/imgui_renderer.cc b/src/xenia/ui/imgui_drawer.cc similarity index 67% rename from src/xenia/debug/ui/imgui_renderer.cc rename to src/xenia/ui/imgui_drawer.cc index 350dc4bdf..5feb3fc4f 100644 --- a/src/xenia/debug/ui/imgui_renderer.cc +++ b/src/xenia/ui/imgui_drawer.cc @@ -1,24 +1,19 @@ /** -****************************************************************************** -* 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. * -****************************************************************************** -*/ + ****************************************************************************** + * 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 "xenia/debug/ui/imgui_renderer.h" - -#include +#include "xenia/ui/imgui_drawer.h" +#include "third_party/imgui/imgui.h" #include "xenia/base/assert.h" -#include "xenia/base/logging.h" -#include "xenia/base/math.h" -#include "xenia/ui/gl/circular_buffer.h" -#include "xenia/ui/gl/gl_context.h" +#include "xenia/ui/window.h" namespace xe { -namespace debug { namespace ui { constexpr uint32_t kMaxDrawVertices = 64 * 1024; @@ -29,38 +24,34 @@ constexpr uint32_t kMaxDrawIndices = 64 * 1024; const char kProggyTinyCompressedDataBase85[10950 + 1] = R"(7])#######LJg=:'/###[),##/l:$#Q6>##5[n42>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCm<]vf.r$<$u7k;hb';9C'mm?]XmKVeU2cD4Eo3R/[WB]b(MC;$jPfY.;h^`ItLw6Lh2TlS+f-s$o6Q#X14,MZ[Z##UE31#J&###Q-F%b>-nw'w++GM-]u)Nx0#,M[LH>#Zsvx+6O_^#l(FS7f`C_&E?g'&kcg-6Y,/;M#@2G`Bf%=(`5LF%fv$8#,+[0#veg>$EB&sQSSDgEKnIS7EM9>Z,KO_/78pQWqJE#$nt-4$F&###E`J&#uU'B#*9D6N;@;=-:U>hL&Y5<-%A9;-Y+Z&P^)9##._L&#awnk+ib*.-Z06X1>LcA#'rB#$o4ve6)fbA#kt72LN.72L=CG&#*iXZWt(F,>>#_03:)`(@2L@^x4Sj2B@PN#[xO8QkJNRR()N@#f.Mr#)t-L5FGMm8#&#/2TkLi3n##-/5##MwQ0#EB^1v&ols-)-mTMQ@-##qlQ08*lkA#aNRV7KRYML%4_s[kNa=_0Z%7Nd4[3#S@1g_/v`W#'`Fm#B$(Q#n$oqvc$&Svv$`,TM%,PS=%OeJE%s+]l%A=Fe%']K#&7aW5&O-Nd&q&>^&GZs1'w.bA'c>u>'B-1R'%gJ.(t1tx'_jH4(iNdc(GJ*X(l`uf(^Wqr(-=Jx(=[%5)')Gb)$1vV)57Vk),8n<*BYl/*qs%]*OI5R*Fkgb*H<+q*TQv(+Xak6+?C@H+5SaT+o2VhLKd)k+i$xl+4YW=,sJd,,C*oT,Eb:K,mSPgLsF8e,Z$=rJ[<5J`E:E&#k&bV7uVco]JfaJ2M'8L#xArJ27FJx?Zgt%uov/vZ@?Gj:Kl;,jo%*K;AL7L#7G'3/J(*t.5xO+/0r+N/%ipJ/Bq_k/A>4Y/^iwl/%K:K0[HW=04D'N0wQq_00Kjt0]NJ21?p?d1T:=Y1e*&i1HLr@28x*:29A[L2Mpd%3pFIp2igO+3aXRX3M#PN3uY$d37p2=4c,s54.3SI4v0iw4JqN65G$S*5rh<65ld7E5.IRt5.f-16A/U(6IoFR6Nj7I6Y3i[6>s#s6EF=P90>=W6-Mc##=(V$#MXI%#^3=&#nd0'#(?$(#8pm(#HJa)#X%T*#iUG+##1;,#3b.-#C#$i0B#'2[0#s6aW-AS*wp1W,/$-pZw'%]#AOC+[]O>X`=-9_cHMN8r&MsKH##77N/)8r_G3=^x]O].[]-/(pI$^=Kn<00k-$t`%/LDK5x76,G&#$or>I?v+sQ;koJM>,CS-14,dM,Hv<-cLH?01FQ*NGx0='H9V&#;Rov$8ooX_i7d;)]]>R*sVi.Lt3NM-$@dXM:uSGMDn%>-30[b's6Ct_.39I$3#bo7;FP&#YKh9&#d)KE$tok&L1tY-sTf2LP]K&s9L]u-c4Au9*A>-<'3UN-PZL-NIV+85p0eZ3:.Q8bj1S*(h)Z$lel,MX_CH-.Nck-(veHZwdJe$ej+_frio0cKB$HFtRZ>#DiaWqFq7Q84okA#tiUi'Qumo%<]Xl8As(?@iLT[%tDn8gsDGA#hDu-$+HM3X_?@_8:N+q7v3G&#a7>0H3=t-?ZKm.HK+U58E/.`AcQV,tUd+Z-$fQ-Haotl8Zx2Fn)&UQ8c6E&docd.%&^R]u)x:p.N*wIL8+fsrk+5###>jq:9%/v2;f`?J8fDrG%fmWw9gl'ENgjG:,EC%<-WW5x'6eaR86kf2`5alP&u]::.'a0i);c)3LN3wK#gZb19YvMa,?IggL3xoFMTK_P85.)0xLp7gw]m_oM++.`=JfLm)1#.gGKd4N^@N%M'Np7ZO:k)VTqt%EO`gurjj;-0r%;%I'M,W-(hdnXP4bA,%GLp75c`QUWh<_&.ZoDuWmLCVJ+7:P&#Wj7n$+8sb<:+R.Qx7m<-T`&0%3TK<-h.oN'eSYW-g7D^6mu7Rc;:cIH%5hWHX9uCq'RC/2'GZZ(=:.$ekS>k((WP_=-,8dT%;]DeHjNJ'HOsgj-vUa$UFQO68Ic+k2HwQ'(0Kgn8V=:'_5'r1GX`4;kNbkh&@-HCp[+c+Z68=Z9:BM#Jn$R+0Au6A)K:YXr1d^8ILE65V'#Y_%n8Mc`3r:>H9%PMhj9GVCh3F3wm81EG&#,`**<3AEYLN1pA#>q0p&(^?@'Bl+&>klY'vO%co7juS^d)a#9%=&m9.m`0i)rQNm8*GF]uI9+W-wmw5_L07xLC8qT;`9%90i^Gx'abQp7)>5wLq3n0#/U0V8+B^G3%3,0:3wR]4fJ(d%2N9Z-r_&7rjQS,sM;n9g#>ve^2SK)71JTRxD)o0@1wWA2#E;xov>0f^-QQQYVBeT+?-7kMD5d0B#QZAW0:ZjUK[OZi&61L&#>CCj;r]/RLH'(j>+$P-R9bF69`%f@[p-JZ*.hnp7;-ge$NSi?-qx8;-V]Z##,B?nrCn,)'(Q%a-sI^W&9'i&#SrRfL`Zwe%k.jA,xf:-%$+:t>-v^)'%of?pg=`N_*o'w)3(ip7XqF]uN-Fj9l=K/+sAH^*I=5qBCRt-,T163BO%ov7%,sb&T=XaZ$(#GM0#Qp%a]Cs7HNbxum=g@>wb%?7N:Fk'0PYRhUv-tLWr+P(lLM/:9N*H=KRZT'Pf2;.@2<)#pVl1MwLk0&;tUAuP3w.Le.]T/*Mc##O->>#9NCU.73rI3ZbA;%^xT3BS2L#$uLjf%53Kt-2SJMBFZ.m0cmcPS)aX%(c]Yg<^[G6;$W(8*2&$X->B+kk^$D'8E@P&#I-nT'u5pm8u;Be=AJ8F-T6po)A:&?-CPcd$rDtJjLUsv'7Hx_onecgHu78k:D#]4;tb)$-UHAm8h;2c>8J<@.(W=p&oVoY?&@+w7-)ri'bb=+X:#29.*DW/tNqT&QAl29xj+AuD:*+lnW]D,3l6<-PX9YYw)vX&=WuT8H=AbIs[`Am2xcW-jqbn*cZV%_t/Z&QpvGJ(i2.^==iWDurfn:Ml;-##/-U%)x$+1:lROdt*mpM=i4/)Zdr'H'P[N>-EKHl$hUvf:P'Q3`u*IM&uZA39^0F[pUB+n8hq+?I`L'-)2>Cq71g/6(?(oR&iBRiLr7w;-[HuL3u6e2&V:QjBJ:9iuF8.a##PHT<-.4r1&,qBE#LK,W-fIO4kX@%%#tUB#$57>uHN^KeX'-cD)d.s*#P2+c&#ok:/:3l(RsPD###2d#<-%,.t$5@HgL/mu<+PXhv[Bgb4)GO;eMZQMr?,tXvIIe;t-P2l?G2j1v^)3l$'mEa68K1l@7.`V[GG#)C]Y&f;]?OM>&x]i.L(/5##BO+k9Xp0B#NS9>#+7E<-d]nl$Yw6v9YK*6(sxGug]oko$_'l_-Ai%RMq<&_8o2@2L@@AS)c8(<-c&r]$J9oq7g?(m9LIS;H-)KfF@qVI*^ACO9fKc'&6k/q7RD&Fe&*l2LSQUV$vC#W-lwf&v:'n]%D4xVH4&(^#0jg<-@r'29EQT_6Gx)Q&':nKC>s6.6*;X^ZH.->#>atJC6`hJ>NjO?-^5l-8Tj72LFIRp7,:-.wruM;q0)(YHWp7@i('#'2,##8ZDKM9dvR3kYKd&#V(f+MR?xK#liDE<[/RM3M7-##1na_$+q)'%xheG*DsXbN^BxK#R90%'vrIfL.r&/LT*=(&A's2;O56>>/jsX_Z_+/(NSi.L>jEG']iNUR238^&?MR49neA>.M5N=h#=eq:T?k)/:;SF&#;k-gLXL0e,e6JdDNHj?@ihvi&wNT-;6`E.FAl):%3WK<-:EI+'^([:.+lQS%?_,c<8L[W&T7-##`QHXA=(xn&Yqbf(kge2-g)[OksHT*bm+Do5IM<_jILK4Pv'=u5a*E#Z^FHmn),Dheq.+Sl##04kWoAl[W]rYHI%+d@a-.dm<%#1[,MtRBt)O(35&>-f;-J=.g:(xp/)U]W]+RCwgCbE0#Aes-h%vr_BF0;=K34Yv',/GoEYQQ-U&5&Aw>]ewGt?k,l$1oR8VCkF<%+nTH4Z8f%/M&dQ/(2###S`%/L*cS5JX&V_$iac=(LG:;$ZcRPA.$+bHU7-###c7^O1[qS%)S#qT=lI(#=,o_Q.^r#(w1I<-+PK`&,o'^#GhsWQt6j(,]_##IN]p7i4mFuXih@-t=58.1&>uu$&h2`2H:%'T):wPGJuD%5DJTIUXbA#pvRdM=WcO-uhKj%0ej?Ppruu9k,h%cwfi'B.x`=Tg^d4%45GM@iZQ'YGHP9(MGGGvbG3jZJp7FAeEP&ePL'8k8k91/D?[-7(&(m@?q7kdH)cDfYN)@9TDSe;DG)uQh&#k+'p74N)^ohl=,'';[P9_kisBjgU,&g>Ok2=4'K%cl@Nii)3q-_.1U9,.QL/2&>uuF*^TVA7Bs&;W36AZ(j'muJG4M_CpO4)0kNeFKG2V?'jkgNvkK<&MQU+<[xKVaY>/T@&Jp'HtA$a&5U&R8bs:RWYiYeQu4k(NgxE$%X6V&#X+3O-u_dQ8/_-ldRf1W-2dpGe*E^r7d>S^JisoC%s`^68r*d;))C[p7W?[6OfId2P&;Hr7cpB#$X8-l93rg996Nb4):v0<-Y7`[eEdoW*l/xNN9<&v,%nra*-?078.F8o8aP+Au]ZX2L:1Bn*fuW1;N&&3M5U#x'-KA$ZAf0YS&_;AL;>g6pgV==5A6R.db1Wbs'MC9-)5u:ENe7-##H:O&=$^]712c&gL,%,cM+4(5SmwUF-x-*j0c-G(-9Y`N*$0_k2ece`*#JdQ8Fk=9W'&%kCjYeaHC@nL-$[d;B*<^#DuHQNYF#>Q8L*fW]8cJX/,CWR83+pVooXXk'1HCL:6I%T(`2VY(An&R8?uN]'WLJM'$/*JLXm@8JhS](6l0tv'x06oDXFC'%=7CP8fCKetbqp0%;=0iC/kRkrjK5x'qtD_Or/9x:VWF&#LW`<04=q0E8/c&hItt'a8J0)kY#Q8nnV78o=6UT`-1t%-FuN:xA1J[Oq`p77%72L9$2-'[qp)mH^*[eL]u/o(HF0iu.-vwoW_wn=O:[3NPcDh)Zn)ex[T%LaP-VC%f$36t1CvSw,X>^>Z4q=Z58]evqT5.xP33h839>So>InZb%=w=>F%$Mdm_FjSEEwGJMN3B,-(b@mHM;uFr$r&V@-Vp;m$bF6XJbM0-'-PgQJ=Z.lBE?=x>YBPX9N3?&+0)xm'wQsH$K]MP9cmv9glREr(>=n-k;/6t$r]2@-Ips&d-8oS@pb5r@lwcQ:aum))u=KkrVv[n>Lu,@RvlOE.^Puk;v4[+9.2A2LrPn'&]/?pg&.Rq$9-vc6BUpD*8[?:BmMq*9.HFt_QSl##O->>#b7278#r%34A$;M%+=hlTsVPp'X8N&Zu/To%mDh:.,umo%5VIl90wn5F9;_OFJ?=?JbjcX($^)Rj2vao7W9Udkr[F%8:@(4F@5W5_oHOG%M4Y@G:P+JGUsRA%UeO-;Tr+OOHi8i:F$aC=K@82L(__3:>H-g)S65e;B@:xnT_x0+x,2N:rmL4)VtH#)NF7WAs,Zx'uQpEU78_TX=?1s?cZYlBd'BugDAVB-vlc_fV5gc*s&Y9.;25##F7,W.P'OC&aTZ`*65m_&WRJM'vGl_&==(S*2)7`&27@U1G^4?-:_`=-+()t-c'ChLGF%q.0l:$#:T__&Pi68%0xi_&Zh+/(77j_&JWoF.V735&S)[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&lM4;-xCJcM6X;uM6X;uM(.a..^2TkL%oR(#;u.T%eAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFk-c/>tBc/>`9IL2a)Ph#WL](#O:Jr1Btu+#TH4.#a5C/#vS3rL<1^NMowY.##t6qLw`5oL_R#.#2HwqLUwXrLp/w+#ALx>-1xRu-'*IqL@KCsLB@]qL]cYs-dpao7Om#K)l?1?%;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4TR-&Mglr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4A1OY5EI0;6Ibgr6M$HS7Q<)58UT`l8Ym@M9^/x.:bGXf:f`9G;jxp((F+;?,_br?0wBS@49$5A8QZlAQ#]V-kw:8.o9ro.sQRP/wj320%-ki0)EKJ1-^,,21vcc258DD39P%&4=i[]4A+=>5ECtu5I[TV6Mt587Q6mo7tB'DW-fJcMxUq4S=Gj(N=eC]OkKu=Yc/;ip3#T(j:6s7R`?U+rH#5PSpL7]bIFtIqmW:YYdQqFrhod(WEH1VdDMSrZ>vViBn_t.CTp;JCbMMrdku.Sek+f4ft(XfCsOFlfOuo7[&+T.q6jHPA$HHPB*QHPC0ZHPD6dHPD3Q-P_aQL2context()), + vertices_(kMaxDrawVertices * sizeof(ImmediateVertex)), + indices_(kMaxDrawIndices * sizeof(uint16_t)) { + assert_null(global_drawer_); + global_drawer_ = this; Initialize(); } -ImGuiRenderer::~ImGuiRenderer() { - Shutdown(); +ImGuiDrawer::~ImGuiDrawer() { + ImGui::Shutdown(); - assert_true(global_renderer_ == this); - global_renderer_ = nullptr; + assert_true(global_drawer_ == this); + global_drawer_ = nullptr; } -void ImGuiRenderer::Initialize() { +void ImGuiDrawer::Initialize() { auto& io = ImGui::GetIO(); - vertex_buffer_.Initialize(); - index_buffer_.Initialize(); - InitializeShaders(); - InitializeFontTextures(); + SetupFont(); io.DeltaTime = 1.0f / 60.0f; io.RenderDrawListsFn = [](ImDrawData* data) { - global_renderer_->RenderDrawLists(data); + global_drawer_->RenderDrawLists(data); }; auto& style = ImGui::GetStyle(); @@ -135,77 +126,7 @@ void ImGuiRenderer::Initialize() { io.KeyMap[ImGuiKey_Z] = 'Z'; } -void ImGuiRenderer::InitializeShaders() { - const std::string vertex_shader_source = - R"( -#version 450 -#extension GL_ARB_explicit_uniform_location : require -precision highp float; -layout(location = 0) uniform mat4 projection_matrix; -layout(location = 0) in vec2 in_pos; -layout(location = 1) in vec4 in_color; -layout(location = 2) in vec2 in_uv; -layout(location = 0) out vec4 vtx_color; -layout(location = 1) out vec2 vtx_uv; -void main() { - gl_Position = projection_matrix * vec4(in_pos.xy, 0.0, 1.0); - vtx_color = in_color; - vtx_uv = in_uv; -})"; - - const std::string fragment_shader_source = - R"( -#version 450 -#extension GL_ARB_explicit_uniform_location : require -precision highp float; -layout(location = 1) uniform sampler2D texture_sampler; -layout(location = 2) uniform float texture_mix; -layout(location = 0) in vec4 vtx_color; -layout(location = 1) in vec2 vtx_uv; -layout(location = 0) out vec4 out_color; -void main() { - out_color = vtx_color * texture(texture_sampler, vtx_uv); -})"; - - 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); - - glCreateVertexArrays(1, &vao_); - glEnableVertexArrayAttrib(vao_, 0); - glVertexArrayAttribBinding(vao_, 0, 0); - glVertexArrayAttribFormat(vao_, 0, 2, GL_FLOAT, GL_FALSE, - offsetof(ImDrawVert, pos)); - glEnableVertexArrayAttrib(vao_, 1); - glVertexArrayAttribBinding(vao_, 1, 0); - glVertexArrayAttribFormat(vao_, 1, 4, GL_UNSIGNED_BYTE, GL_TRUE, - offsetof(ImDrawVert, col)); - glEnableVertexArrayAttrib(vao_, 2); - glVertexArrayAttribBinding(vao_, 2, 0); - glVertexArrayAttribFormat(vao_, 2, 2, GL_FLOAT, GL_FALSE, - offsetof(ImDrawVert, uv)); - glVertexArrayVertexBuffer(vao_, 0, vertex_buffer_.handle(), 0, - sizeof(ImDrawVert)); -} - -void ImGuiRenderer::InitializeFontTextures() { +void ImGuiDrawer::SetupFont() { auto& io = ImGui::GetIO(); ImFontConfig font_config; @@ -222,120 +143,55 @@ void ImGuiRenderer::InitializeFontTextures() { int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - GLuint font_texture; - glCreateTextures(GL_TEXTURE_2D, 1, &font_texture); - glTextureParameteri(font_texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTextureParameteri(font_texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTextureStorage2D(font_texture, 1, GL_RGBA8, width, height); - glTextureSubImage2D(font_texture, 0, 0, 0, width, height, GL_RGBA, - GL_UNSIGNED_BYTE, pixels); - io.Fonts->TexID = - reinterpret_cast(static_cast(font_texture)); + font_texture_ = graphics_context_->immediate_drawer()->CreateTexture( + width, height, ImmediateTextureFilter::kLinear, false, + reinterpret_cast(pixels)); + + io.Fonts->TexID = reinterpret_cast(font_texture_->handle); } -void ImGuiRenderer::Shutdown() { - xe::ui::GraphicsContextLock lock(context_); - vertex_buffer_.Shutdown(); - index_buffer_.Shutdown(); - glDeleteVertexArrays(1, &vao_); - glDeleteProgram(program_); +void ImGuiDrawer::RenderDrawLists(ImDrawData* data) { + auto drawer = graphics_context_->immediate_drawer(); - ImGuiIO& io = ImGui::GetIO(); - auto tex_id = - static_cast(reinterpret_cast(io.Fonts->TexID)); - glDeleteTextures(1, &tex_id); - - ImGui::Shutdown(); -} - -void ImGuiRenderer::RenderDrawLists(ImDrawData* data) { - // Setup render state: - // alpha-blending enabled - // no face culling, - // no depth testing - // scissor enabled - glEnablei(GL_BLEND, 0); - glBlendEquationi(0, GL_FUNC_ADD); - glBlendFunci(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - - // Setup orthographic projection matrix. const float width = ImGui::GetIO().DisplaySize.x; const float height = ImGui::GetIO().DisplaySize.y; - const float ortho_projection[4][4] = { - {2.0f / width, 0.0f, 0.0f, 0.0f}, - {0.0f, 2.0f / -height, 0.0f, 0.0f}, - {0.0f, 0.0f, -1.0f, 0.0f}, - {-1.0f, 1.0f, 0.0f, 1.0f}, - }; - glProgramUniformMatrix4fv(program_, 0, 1, GL_FALSE, &ortho_projection[0][0]); + drawer->Begin(static_cast(width), static_cast(height)); - // Prepare drawing resources. - glUseProgram(program_); - glBindVertexArray(vao_); - - // Run through and upload all the vertex and index data. - auto vertex_alloc = - vertex_buffer_.Acquire(data->TotalVtxCount * sizeof(ImDrawVert)); - auto index_alloc = - index_buffer_.Acquire(data->TotalIdxCount * sizeof(ImDrawIdx)); - uintptr_t vertex_offset = 0; - uintptr_t index_offset = 0; - for (int i = 0; i < data->CmdListsCount; ++i) { - auto cmd_list = data->CmdLists[i]; - size_t vertex_bytes = cmd_list->VtxBuffer.size() * sizeof(ImDrawVert); - std::memcpy( - reinterpret_cast(vertex_alloc.host_ptr) + vertex_offset, - cmd_list->VtxBuffer.Data, vertex_bytes); - vertex_offset += vertex_bytes; - size_t index_bytes = cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx); - std::memcpy(reinterpret_cast(index_alloc.host_ptr) + index_offset, - cmd_list->IdxBuffer.Data, index_bytes); - index_offset += index_bytes; - } - vertex_buffer_.Commit(std::move(vertex_alloc)); - vertex_buffer_.Flush(); - index_buffer_.Commit(std::move(index_alloc)); - index_buffer_.Flush(); - - // Second pass to issue draws. - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_.handle()); - ImTextureID prev_texture_id = 0; - const ImDrawIdx* index_buffer_offset = 0; - GLint base_vertex = 0; for (int i = 0; i < data->CmdListsCount; ++i) { const auto cmd_list = data->CmdLists[i]; + + ImmediateDrawBatch batch; + batch.vertices = + reinterpret_cast(cmd_list->VtxBuffer.Data); + batch.vertex_count = cmd_list->VtxBuffer.Size; + batch.indices = cmd_list->IdxBuffer.Data; + batch.index_count = cmd_list->IdxBuffer.Size; + drawer->BeginDrawBatch(batch); + + int index_offset = 0; for (int j = 0; j < cmd_list->CmdBuffer.size(); ++j) { const auto& cmd = cmd_list->CmdBuffer[j]; - if (cmd.TextureId != prev_texture_id) { - glBindTextureUnit( - 0, static_cast(reinterpret_cast(cmd.TextureId))); - prev_texture_id = cmd.TextureId; - } - glScissorIndexed(0, static_cast(cmd.ClipRect.x), - static_cast(height - cmd.ClipRect.w), - static_cast(cmd.ClipRect.z - cmd.ClipRect.x), - static_cast(cmd.ClipRect.w - cmd.ClipRect.y)); - glDrawElementsBaseVertex(GL_TRIANGLES, cmd.ElemCount, GL_UNSIGNED_SHORT, - index_buffer_offset, base_vertex); - index_buffer_offset += cmd.ElemCount; + + ImmediateDraw draw; + draw.primitive_type = ImmediatePrimitiveType::kTriangles; + draw.count = cmd.ElemCount; + draw.index_offset = index_offset; + draw.texture_handle = reinterpret_cast(cmd.TextureId); + draw.scissor = true; + draw.scissor_rect[0] = static_cast(cmd.ClipRect.x); + draw.scissor_rect[1] = static_cast(height - cmd.ClipRect.w); + draw.scissor_rect[2] = static_cast(cmd.ClipRect.z - cmd.ClipRect.x); + draw.scissor_rect[3] = static_cast(cmd.ClipRect.w - cmd.ClipRect.y); + drawer->Draw(draw); + + index_offset += cmd.ElemCount; } - base_vertex += cmd_list->VtxBuffer.Size; + + drawer->EndDrawBatch(); } - // TODO(benvanik): don't finish here. - vertex_buffer_.WaitUntilClean(); - index_buffer_.WaitUntilClean(); - - // Restore modified state. - glBindTextureUnit(0, 0); - glUseProgram(0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); + drawer->End(); } } // namespace ui -} // namespace debug } // namespace xe diff --git a/src/xenia/ui/imgui_drawer.h b/src/xenia/ui/imgui_drawer.h new file mode 100644 index 000000000..8412b72b2 --- /dev/null +++ b/src/xenia/ui/imgui_drawer.h @@ -0,0 +1,51 @@ +/** + ****************************************************************************** + * 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. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_IMGUI_DRAWER_H_ +#define XENIA_UI_IMGUI_DRAWER_H_ + +#include +#include + +#include "xenia/ui/immediate_drawer.h" + +struct ImDrawData; + +namespace xe { +namespace ui { + +class GraphicsContext; +class Window; + +class ImGuiDrawer { + public: + ImGuiDrawer(Window* window); + ~ImGuiDrawer(); + + protected: + void Initialize(); + void SetupFont(); + + void RenderDrawLists(ImDrawData* data); + + static ImGuiDrawer* global_drawer_; + + Window* window_ = nullptr; + GraphicsContext* graphics_context_ = nullptr; + + std::vector vertices_; + std::vector indices_; + + std::unique_ptr font_texture_; +}; + +} // namespace ui +} // namespace xe + +#endif // XENIA_UI_IMGUI_DRAWER_H_ diff --git a/src/xenia/ui/immediate_drawer.h b/src/xenia/ui/immediate_drawer.h index baf4613ee..808b9e88d 100644 --- a/src/xenia/ui/immediate_drawer.h +++ b/src/xenia/ui/immediate_drawer.h @@ -47,6 +47,9 @@ enum class ImmediatePrimitiveType { }; // Simple vertex used by the immediate mode drawer. +// To avoid translations, this matches both imgui and elemental-forms vertices: +// ImDrawVert +// el::graphics::Renderer::Vertex struct ImmediateVertex { float x, y; float u, v; @@ -55,9 +58,6 @@ struct ImmediateVertex { // All parameters required to draw an immediate-mode batch of vertices. struct ImmediateDrawBatch { - // Primitive type the vertices/indices represent. - ImmediatePrimitiveType primitive_type = ImmediatePrimitiveType::kTriangles; - // Vertices to draw. const ImmediateVertex* vertices = nullptr; int vertex_count = 0; @@ -65,6 +65,17 @@ struct ImmediateDrawBatch { // Optional index buffer indices. const uint16_t* indices = nullptr; int index_count = 0; +}; + +struct ImmediateDraw { + // Primitive type the vertices/indices represent. + ImmediatePrimitiveType primitive_type = ImmediatePrimitiveType::kTriangles; + // Total number of elements to draw. + int count = 0; + // Starting offset in the index buffer. + int index_offset = 0; + // Base vertex of elements, if using an index buffer. + int base_vertex = 0; // Texture used when drawing, or nullptr if color only. // This is most commonly the handle of an ImmediateTexture. @@ -91,8 +102,12 @@ class ImmediateDrawer { // Begins drawing in immediate mode using the given projection matrix. virtual void Begin(int render_target_width, int render_target_height) = 0; - // Issues an immediate mode draw batch. - virtual void Draw(const ImmediateDrawBatch& batch) = 0; + // Starts a draw batch. + virtual void BeginDrawBatch(const ImmediateDrawBatch& batch) = 0; + // Draws one set of a batch. + virtual void Draw(const ImmediateDraw& draw) = 0; + // Ends a draw batch. + virtual void EndDrawBatch() = 0; // Ends drawing in immediate mode and flushes contents. virtual void End() = 0; diff --git a/src/xenia/ui/microprofile_drawer.cc b/src/xenia/ui/microprofile_drawer.cc index 64406e058..8534f2f7e 100644 --- a/src/xenia/ui/microprofile_drawer.cc +++ b/src/xenia/ui/microprofile_drawer.cc @@ -158,8 +158,8 @@ void MicroprofileDrawer::SetupFont() { } // Unpack font bitmap into an RGBA texture. - const int UNPACKED_SIZE = kFontTextureWidth * kFontTextureHeight * 4; - uint32_t unpacked[UNPACKED_SIZE]; + const int kUnpackedSize = kFontTextureWidth * kFontTextureHeight * 4; + uint32_t unpacked[kUnpackedSize]; int idx = 0; int end = kFontTextureWidth * kFontTextureHeight / 8; for (int i = 0; i < end; i++) { @@ -175,7 +175,7 @@ void MicroprofileDrawer::SetupFont() { false, reinterpret_cast(unpacked)); } -MicroprofileDrawer::~MicroprofileDrawer() { font_texture_.reset(); } +MicroprofileDrawer::~MicroprofileDrawer() = default; void MicroprofileDrawer::Begin() { graphics_context_->immediate_drawer()->Begin(window_->width(), @@ -202,15 +202,24 @@ ImmediateVertex* MicroprofileDrawer::BeginVertices( void MicroprofileDrawer::EndVertices() {} void MicroprofileDrawer::Flush() { + auto drawer = graphics_context_->immediate_drawer(); if (!vertex_count_) { return; } + ImmediateDrawBatch batch; - batch.primitive_type = current_primitive_type_; batch.vertices = vertices_.data(); batch.vertex_count = vertex_count_; - batch.texture_handle = font_texture_->handle; - graphics_context_->immediate_drawer()->Draw(batch); + drawer->BeginDrawBatch(batch); + + ImmediateDraw draw; + draw.primitive_type = current_primitive_type_; + draw.count = vertex_count_; + draw.texture_handle = font_texture_->handle; + drawer->Draw(draw); + + drawer->EndDrawBatch(); + vertex_count_ = 0; }