Moving imgui to the new ImmediateDrawer.

This commit is contained in:
Ben Vanik 2015-11-05 23:03:02 -08:00
parent c631b965d7
commit 4c2257a29d
10 changed files with 198 additions and 564 deletions

View File

@ -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<ImGuiRenderer>(window_.get(), window_->context());
imgui_drawer_ = std::make_unique<xe::ui::ImGuiDrawer>(window_.get());
window_->on_key_char.AddListener([](xe::ui::KeyEvent* e) {
auto& io = ImGui::GetIO();
if (e->key_code() > 0 && e->key_code() < 0x10000) {

View File

@ -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<xe::ui::Window> window_;
std::unique_ptr<ImGuiRenderer> imgui_renderer_;
std::unique_ptr<xe::ui::ImGuiDrawer> imgui_drawer_;
uint64_t last_draw_tick_count_ = 0;
uintptr_t capstone_handle_ = 0;

View File

@ -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 <memory>
#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_

View File

@ -11,7 +11,6 @@
#include <cstring>
#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<xe::ui::ImGuiDrawer> imgui_drawer_;
int trace_viewer_main(const std::vector<std::wstring>& 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<std::wstring>& 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<std::wstring>& 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<xe::ui::ImGuiDrawer>(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<std::wstring>& 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<std::wstring>& 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<std::wstring>& 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<GLuint>(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

View File

@ -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<uintptr_t>(handle);
handle = static_cast<uintptr_t>(gl_handle);
}
~GLImmediateTexture() override {
//
GLuint gl_handle = static_cast<GLuint>(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<GLuint>(batch.texture_handle));
if (draw.texture_handle) {
glBindTextureUnit(0, static_cast<GLuint>(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<void*>(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();

View File

@ -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

File diff suppressed because one or more lines are too long

View File

@ -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 <memory>
#include <vector>
#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<ImmediateVertex> vertices_;
std::vector<uint16_t> indices_;
std::unique_ptr<ImmediateTexture> font_texture_;
};
} // namespace ui
} // namespace xe
#endif // XENIA_UI_IMGUI_DRAWER_H_

View File

@ -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;

View File

@ -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<uint8_t*>(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;
}