From fdf59fec5fb07b229ed1725aa4890623fa77dd48 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sat, 7 Nov 2015 09:52:57 -0800 Subject: [PATCH] Moving elemental to immediate drawer. --- src/xenia/ui/elemental_drawer.cc | 112 +++++++ ...lemental_renderer.h => elemental_drawer.h} | 60 ++-- src/xenia/ui/gl/gl4_elemental_renderer.cc | 297 ------------------ src/xenia/ui/gl/gl_context.cc | 5 - src/xenia/ui/gl/gl_context.h | 1 - src/xenia/ui/gl/gl_immediate_drawer.cc | 27 +- src/xenia/ui/graphics_context.h | 3 - src/xenia/ui/imgui_drawer.cc | 19 +- src/xenia/ui/immediate_drawer.h | 2 + src/xenia/ui/microprofile_drawer.cc | 1 + src/xenia/ui/window.cc | 5 +- 11 files changed, 169 insertions(+), 363 deletions(-) create mode 100644 src/xenia/ui/elemental_drawer.cc rename src/xenia/ui/{gl/gl4_elemental_renderer.h => elemental_drawer.h} (50%) delete mode 100644 src/xenia/ui/gl/gl4_elemental_renderer.cc diff --git a/src/xenia/ui/elemental_drawer.cc b/src/xenia/ui/elemental_drawer.cc new file mode 100644 index 000000000..906be457b --- /dev/null +++ b/src/xenia/ui/elemental_drawer.cc @@ -0,0 +1,112 @@ +/** + ****************************************************************************** + * 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/ui/elemental_drawer.h" + +#include "el/graphics/bitmap_fragment.h" +#include "el/util/math.h" +#include "xenia/base/assert.h" +#include "xenia/base/logging.h" +#include "xenia/profiling.h" +#include "xenia/ui/window.h" + +namespace xe { +namespace ui { + +ElementalDrawer::ElementalBitmap::ElementalBitmap(ElementalDrawer* drawer, + int width, int height, + uint32_t* data) + : drawer_(drawer) { + assert(width == el::util::GetNearestPowerOfTwo(width)); + assert(height == el::util::GetNearestPowerOfTwo(height)); + width_ = width; + height_ = height; + + drawer_->FlushBitmap(this); + + auto immediate_drawer = drawer_->graphics_context_->immediate_drawer(); + texture_ = immediate_drawer->CreateTexture( + width, height, ImmediateTextureFilter::kLinear, true, + reinterpret_cast(data)); +} + +ElementalDrawer::ElementalBitmap::~ElementalBitmap() { + // Must flush and unbind before we delete the texture. + drawer_->FlushBitmap(this); +} + +void ElementalDrawer::ElementalBitmap::set_data(uint32_t* data) { + drawer_->FlushBitmap(this); + + auto immediate_drawer = drawer_->graphics_context_->immediate_drawer(); + immediate_drawer->UpdateTexture(texture_.get(), + reinterpret_cast(data)); +} + +ElementalDrawer::ElementalDrawer(xe::ui::Window* window) + : window_(window), graphics_context_(window->context()) { + static_assert(sizeof(ImmediateVertex) == sizeof(Vertex), + "Vertex types must match"); +} + +ElementalDrawer::~ElementalDrawer() = default; + +void ElementalDrawer::BeginPaint(int render_target_w, int render_target_h) { + Renderer::BeginPaint(render_target_w, render_target_h); + + auto immediate_drawer = graphics_context_->immediate_drawer(); + immediate_drawer->Begin(render_target_w, render_target_h); + + batch_.vertices = vertices_; +} + +void ElementalDrawer::EndPaint() { + Renderer::EndPaint(); + + auto immediate_drawer = graphics_context_->immediate_drawer(); + immediate_drawer->End(); +} + +std::unique_ptr ElementalDrawer::CreateBitmap( + int width, int height, uint32_t* data) { + auto bitmap = std::make_unique(this, width, height, data); + return std::unique_ptr(bitmap.release()); +} + +void ElementalDrawer::RenderBatch(Batch* batch) { + auto immediate_drawer = graphics_context_->immediate_drawer(); + + ImmediateDrawBatch draw_batch; + + draw_batch.vertices = reinterpret_cast(batch->vertices); + draw_batch.vertex_count = static_cast(batch->vertex_count); + immediate_drawer->BeginDrawBatch(draw_batch); + + ImmediateDraw draw; + draw.primitive_type = ImmediatePrimitiveType::kTriangles; + draw.count = static_cast(batch->vertex_count); + auto bitmap = static_cast(batch->bitmap); + draw.texture_handle = bitmap ? bitmap->texture_->handle : 0; + draw.scissor = true; + draw.scissor_rect[0] = current_clip_.x; + draw.scissor_rect[1] = + window_->height() - (current_clip_.y + current_clip_.h); + draw.scissor_rect[2] = current_clip_.w; + draw.scissor_rect[3] = current_clip_.h; + immediate_drawer->Draw(draw); + + immediate_drawer->EndDrawBatch(); +} + +void ElementalDrawer::set_clip_rect(const el::Rect& rect) { + current_clip_ = rect; +} + +} // namespace ui +} // namespace xe diff --git a/src/xenia/ui/gl/gl4_elemental_renderer.h b/src/xenia/ui/elemental_drawer.h similarity index 50% rename from src/xenia/ui/gl/gl4_elemental_renderer.h rename to src/xenia/ui/elemental_drawer.h index 15bfa7882..34f5672a9 100644 --- a/src/xenia/ui/gl/gl4_elemental_renderer.h +++ b/src/xenia/ui/elemental_drawer.h @@ -2,31 +2,30 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2014 Ben Vanik. All rights reserved. * + * Copyright 2015 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ -#ifndef XENIA_UI_GL_GL4_ELEMENTAL_RENDERER_H_ -#define XENIA_UI_GL_GL4_ELEMENTAL_RENDERER_H_ +#ifndef XENIA_UI_ELEMENTAL_DRAWER_H_ +#define XENIA_UI_ELEMENTAL_DRAWER_H_ #include #include #include "el/graphics/renderer.h" -#include "xenia/ui/gl/circular_buffer.h" -#include "xenia/ui/gl/gl_context.h" +#include "xenia/ui/immediate_drawer.h" namespace xe { namespace ui { -namespace gl { -class GL4ElementalRenderer : public el::graphics::Renderer { +class GraphicsContext; +class Window; + +class ElementalDrawer : public el::graphics::Renderer { public: - explicit GL4ElementalRenderer(GLContext* context); - ~GL4ElementalRenderer() override; - - static std::unique_ptr Create(GLContext* context); + ElementalDrawer(Window* window); + ~ElementalDrawer(); void BeginPaint(int render_target_w, int render_target_h) override; void EndPaint() override; @@ -37,51 +36,34 @@ class GL4ElementalRenderer : public el::graphics::Renderer { void RenderBatch(Batch* batch) override; void set_clip_rect(const el::Rect& rect) override; - private: - class GL4Bitmap : public el::graphics::Bitmap { + protected: + class ElementalBitmap : public el::graphics::Bitmap { public: - GL4Bitmap(GLContext* context, GL4ElementalRenderer* renderer); - ~GL4Bitmap(); + ElementalBitmap(ElementalDrawer* drawer, int width, int height, + uint32_t* data); + ~ElementalBitmap(); - bool Init(int width, int height, uint32_t* data); int width() override { return width_; } int height() override { return height_; } void set_data(uint32_t* data) override; - GLContext* context_ = nullptr; - GL4ElementalRenderer* renderer_ = nullptr; + ElementalDrawer* drawer_ = nullptr; int width_ = 0; int height_ = 0; - GLuint handle_ = 0; - GLuint64 gpu_handle_ = 0; + std::unique_ptr texture_; }; static const uint32_t kMaxVertexBatchSize = 6 * 2048; - - bool Initialize(); - void Flush(); - size_t max_vertex_batch_size() const override { return kMaxVertexBatchSize; } - GLContext* context_ = nullptr; + Window* window_ = nullptr; + GraphicsContext* graphics_context_ = nullptr; - GLuint program_ = 0; - GLuint vao_ = 0; - CircularBuffer vertex_buffer_; - - static const size_t kMaxCommands = 512; - struct { - GLenum prim_type; - size_t vertex_offset; - size_t vertex_count; - } draw_commands_[kMaxCommands] = {{0}}; - uint32_t draw_command_count_ = 0; - GL4Bitmap* current_bitmap_ = nullptr; + el::Rect current_clip_; Vertex vertices_[kMaxVertexBatchSize]; }; -} // namespace gl } // namespace ui } // namespace xe -#endif // XENIA_UI_GL_GL4_ELEMENTAL_RENDERER_H_ +#endif // XENIA_UI_ELEMENTAL_DRAWER_H_ diff --git a/src/xenia/ui/gl/gl4_elemental_renderer.cc b/src/xenia/ui/gl/gl4_elemental_renderer.cc deleted file mode 100644 index aa15dbb5f..000000000 --- a/src/xenia/ui/gl/gl4_elemental_renderer.cc +++ /dev/null @@ -1,297 +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. * - ****************************************************************************** - */ - -#include "xenia/ui/gl/gl4_elemental_renderer.h" - -#include -#include -#include - -#include "el/graphics/bitmap_fragment.h" -#include "el/util/math.h" -#include "xenia/base/assert.h" -#include "xenia/base/logging.h" -#include "xenia/profiling.h" -#include "xenia/ui/gl/gl.h" -#include "xenia/ui/gl/gl_context.h" - -namespace xe { -namespace ui { -namespace gl { - -GL4ElementalRenderer::GL4Bitmap::GL4Bitmap(GLContext* context, - GL4ElementalRenderer* renderer) - : context_(context), renderer_(renderer) {} - -GL4ElementalRenderer::GL4Bitmap::~GL4Bitmap() { - GraphicsContextLock lock(context_); - - // Must flush and unbind before we delete the texture. - renderer_->FlushBitmap(this); - glMakeTextureHandleNonResidentARB(gpu_handle_); - glDeleteTextures(1, &handle_); -} - -bool GL4ElementalRenderer::GL4Bitmap::Init(int width, int height, - uint32_t* data) { - GraphicsContextLock lock(context_); - - assert(width == el::util::GetNearestPowerOfTwo(width)); - assert(height == el::util::GetNearestPowerOfTwo(height)); - width_ = width; - height_ = height; - - glCreateTextures(GL_TEXTURE_2D, 1, &handle_); - glTextureParameteri(handle_, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTextureParameteri(handle_, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTextureParameteri(handle_, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTextureParameteri(handle_, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTextureStorage2D(handle_, 1, GL_RGBA8, width_, height_); - - gpu_handle_ = glGetTextureHandleARB(handle_); - glMakeTextureHandleResidentARB(gpu_handle_); - - set_data(data); - - return true; -} - -void GL4ElementalRenderer::GL4Bitmap::set_data(uint32_t* data) { - renderer_->FlushBitmap(this); - glTextureSubImage2D(handle_, 0, 0, 0, width_, height_, GL_RGBA, - GL_UNSIGNED_BYTE, data); -} - -GL4ElementalRenderer::GL4ElementalRenderer(GLContext* context) - : context_(context), - vertex_buffer_(max_vertex_batch_size() * sizeof(Vertex)) {} - -GL4ElementalRenderer::~GL4ElementalRenderer() { - GraphicsContextLock lock(context_); - vertex_buffer_.Shutdown(); - glDeleteVertexArrays(1, &vao_); - glDeleteProgram(program_); -} - -std::unique_ptr GL4ElementalRenderer::Create( - GLContext* context) { - GraphicsContextLock lock(context); - auto renderer = std::make_unique(context); - if (!renderer->Initialize()) { - XELOGE("Failed to initialize TurboBadger GL4 renderer"); - return nullptr; - } - return renderer; -} - -bool GL4ElementalRenderer::Initialize() { - if (!vertex_buffer_.Initialize()) { - XELOGE("Failed to initialize circular buffer"); - return false; - } - - const std::string header = - R"( -#version 450 -#extension GL_ARB_bindless_texture : require -#extension GL_ARB_explicit_uniform_location : require -#extension GL_ARB_shading_language_420pack : require -precision highp float; -precision highp int; -layout(std140, column_major) uniform; -layout(std430, column_major) buffer; -)"; - const std::string vertex_shader_source = header + - R"( -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 = header + - R"( -layout(location = 1, bindless_sampler) 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 oC; -void main() { - oC = vtx_color; - if (texture_mix > 0.0) { - vec4 color = texture(texture_sampler, vtx_uv); - oC *= color.rgba; - } -})"; - - 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(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; -} - -std::unique_ptr GL4ElementalRenderer::CreateBitmap( - int width, int height, uint32_t* data) { - auto bitmap = std::make_unique(context_, this); - if (!bitmap->Init(width, height, data)) { - return nullptr; - } - return std::unique_ptr(bitmap.release()); -} - -void GL4ElementalRenderer::set_clip_rect(const el::Rect& rect) { - Flush(); - glScissor(clip_rect_.x, screen_rect_.h - (clip_rect_.y + clip_rect_.h), - clip_rect_.w, clip_rect_.h); -} - -void GL4ElementalRenderer::BeginPaint(int render_target_w, - int render_target_h) { - Renderer::BeginPaint(render_target_w, render_target_h); - - batch_.vertices = vertices_; - - glEnablei(GL_BLEND, 0); - glBlendFunci(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_DEPTH_TEST); - glDisable(GL_STENCIL_TEST); - glEnable(GL_SCISSOR_TEST); - - glViewport(0, 0, render_target_w, render_target_h); - glScissor(0, 0, render_target_w, render_target_h); - - float left = 0.0f; - float right = static_cast(render_target_w); - float bottom = static_cast(render_target_h); - 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); - - current_bitmap_ = nullptr; - - glUseProgram(program_); - glBindVertexArray(vao_); - glProgramUniform1f(program_, 2, 0.0f); -} - -void GL4ElementalRenderer::EndPaint() { - Renderer::EndPaint(); - - Flush(); - - glUseProgram(0); - glBindVertexArray(0); -} - -void GL4ElementalRenderer::Flush() { - if (!draw_command_count_) { - return; - } - vertex_buffer_.Flush(); - 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; - // TODO(benvanik): don't finish here. - vertex_buffer_.WaitUntilClean(); -} - -void GL4ElementalRenderer::RenderBatch(Batch* batch) { - if (draw_command_count_ + 1 > kMaxCommands) { - Flush(); - } - size_t total_length = sizeof(Vertex) * batch->vertex_count; - if (!vertex_buffer_.CanAcquire(total_length)) { - Flush(); - } - - auto bitmap = static_cast(batch->bitmap); - if (bitmap != current_bitmap_) { - Flush(); - current_bitmap_ = bitmap; - glProgramUniformHandleui64ARB(program_, 1, - bitmap ? bitmap->gpu_handle_ : 0); - glProgramUniform1f(program_, 2, bitmap ? 1.0f : 0.0f); - } - - auto allocation = vertex_buffer_.Acquire(total_length); - - // TODO(benvanik): custom batcher that lets us use the ringbuffer memory - // without a copy. - std::memcpy(allocation.host_ptr, batch->vertices, total_length); - - if (draw_command_count_ && - draw_commands_[draw_command_count_ - 1].prim_type == GL_TRIANGLES) { - // Coalesce. - assert_always("haven't seen this yet"); - auto& prev_command = draw_commands_[draw_command_count_ - 1]; - prev_command.vertex_count += batch->vertex_count; - } else { - auto& command = draw_commands_[draw_command_count_++]; - command.prim_type = GL_TRIANGLES; - command.vertex_offset = allocation.offset / sizeof(Vertex); - command.vertex_count = batch->vertex_count; - } - - vertex_buffer_.Commit(std::move(allocation)); -} - -} // namespace gl -} // namespace ui -} // namespace xe diff --git a/src/xenia/ui/gl/gl_context.cc b/src/xenia/ui/gl/gl_context.cc index 192468e98..ae70cc93b 100644 --- a/src/xenia/ui/gl/gl_context.cc +++ b/src/xenia/ui/gl/gl_context.cc @@ -18,7 +18,6 @@ #include "xenia/base/logging.h" #include "xenia/base/math.h" #include "xenia/profiling.h" -#include "xenia/ui/gl/gl4_elemental_renderer.h" #include "xenia/ui/gl/gl_immediate_drawer.h" #include "xenia/ui/window.h" @@ -413,10 +412,6 @@ void GLContext::SetupDebugging() { this); } -std::unique_ptr GLContext::CreateElementalRenderer() { - return GL4ElementalRenderer::Create(this); -} - ImmediateDrawer* GLContext::immediate_drawer() { return immediate_drawer_.get(); } diff --git a/src/xenia/ui/gl/gl_context.h b/src/xenia/ui/gl/gl_context.h index c33d3315d..a1596053d 100644 --- a/src/xenia/ui/gl/gl_context.h +++ b/src/xenia/ui/gl/gl_context.h @@ -40,7 +40,6 @@ class GLContext : public GraphicsContext { HDC dc() const { return dc_; } std::unique_ptr CreateShared() override; - std::unique_ptr CreateElementalRenderer() override; ImmediateDrawer* immediate_drawer() override; diff --git a/src/xenia/ui/gl/gl_immediate_drawer.cc b/src/xenia/ui/gl/gl_immediate_drawer.cc index 8d11ebcce..d0ba4ae10 100644 --- a/src/xenia/ui/gl/gl_immediate_drawer.cc +++ b/src/xenia/ui/gl/gl_immediate_drawer.cc @@ -11,6 +11,7 @@ #include +#include "xenia/base/assert.h" #include "xenia/ui/graphics_context.h" namespace xe { @@ -119,12 +120,13 @@ void main() { const std::string fragment_shader_source = header + R"( layout(location = 1) uniform sampler2D texture_sampler; +layout(location = 2) uniform int restrict_texture_samples; layout(location = 0) in vec2 vtx_uv; layout(location = 1) in vec4 vtx_color; layout(location = 0) out vec4 out_color; void main() { out_color = vtx_color; - if (vtx_uv.x <= 1.0) { + if (restrict_texture_samples == 0 || vtx_uv.x <= 1.0) { vec4 tex_color = texture(texture_sampler, vtx_uv); out_color *= tex_color; // TODO(benvanik): microprofiler shadows. @@ -159,9 +161,10 @@ std::unique_ptr GLImmediateDrawer::CreateTexture( GraphicsContextLock lock(graphics_context_); auto texture = std::make_unique(width, height, filter, repeat); + glTextureStorage2D(static_cast(texture->handle), 1, GL_RGBA8, width, + height); if (data) { - glTextureSubImage2D(static_cast(texture->handle), 0, 0, 0, width, - height, GL_RGBA, GL_UNSIGNED_BYTE, data); + UpdateTexture(texture.get(), data); } return std::unique_ptr(texture.release()); } @@ -185,9 +188,8 @@ void GLImmediateDrawer::Begin(int render_target_width, 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); - glDisable(GL_SCISSOR_TEST); + glDisablei(GL_DEPTH_TEST, 0); + glDisablei(GL_SCISSOR_TEST, 0); // Prepare drawing resources. glUseProgram(program_); @@ -206,10 +208,12 @@ void GLImmediateDrawer::Begin(int render_target_width, } void GLImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { + assert_true(batch.vertex_count <= kMaxDrawVertices); glNamedBufferSubData(vertex_buffer_, 0, batch.vertex_count * sizeof(ImmediateVertex), batch.vertices); if (batch.indices) { + assert_true(batch.index_count <= kMaxDrawIndices); glNamedBufferSubData(index_buffer_, 0, batch.index_count * sizeof(uint16_t), batch.indices); } @@ -219,11 +223,11 @@ void GLImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { void GLImmediateDrawer::Draw(const ImmediateDraw& draw) { if (draw.scissor) { - glEnable(GL_SCISSOR_TEST); - glScissor(draw.scissor_rect[0], draw.scissor_rect[1], draw.scissor_rect[2], - draw.scissor_rect[3]); + glEnablei(GL_SCISSOR_TEST, 0); + glScissorIndexed(0, draw.scissor_rect[0], draw.scissor_rect[1], + draw.scissor_rect[2], draw.scissor_rect[3]); } else { - glDisable(GL_SCISSOR_TEST); + glDisablei(GL_SCISSOR_TEST, 0); } if (draw.texture_handle) { @@ -231,6 +235,7 @@ void GLImmediateDrawer::Draw(const ImmediateDraw& draw) { } else { glBindTextureUnit(0, 0); } + glProgramUniform1i(program_, 2, draw.restrict_texture_samples ? 1 : 0); GLenum mode = GL_TRIANGLES; switch (draw.primitive_type) { @@ -256,7 +261,7 @@ void GLImmediateDrawer::EndDrawBatch() { glFlush(); } void GLImmediateDrawer::End() { // Restore modified state. - glDisable(GL_SCISSOR_TEST); + glDisablei(GL_SCISSOR_TEST, 0); glBindTextureUnit(0, 0); glUseProgram(0); glBindVertexArray(0); diff --git a/src/xenia/ui/graphics_context.h b/src/xenia/ui/graphics_context.h index a79007f3c..87d89d3cd 100644 --- a/src/xenia/ui/graphics_context.h +++ b/src/xenia/ui/graphics_context.h @@ -12,8 +12,6 @@ #include -#include "el/graphics/renderer.h" - namespace xe { namespace ui { @@ -27,7 +25,6 @@ class GraphicsContext { Window* target_window() const { return target_window_; } virtual std::unique_ptr CreateShared() = 0; - virtual std::unique_ptr CreateElementalRenderer() = 0; virtual ImmediateDrawer* immediate_drawer() = 0; diff --git a/src/xenia/ui/imgui_drawer.cc b/src/xenia/ui/imgui_drawer.cc index 257fa78ed..b03994d9d 100644 --- a/src/xenia/ui/imgui_drawer.cc +++ b/src/xenia/ui/imgui_drawer.cc @@ -21,6 +21,9 @@ namespace ui { 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_aQL2GetTexDataAsRGBA32(&pixels, &width, &height); font_texture_ = graphics_context_->immediate_drawer()->CreateTexture( - width, height, ImmediateTextureFilter::kLinear, false, + width, height, ImmediateTextureFilter::kLinear, true, reinterpret_cast(pixels)); io.Fonts->TexID = reinterpret_cast(font_texture_->handle); @@ -147,8 +150,14 @@ void ImGuiDrawer::SetupFont() { void ImGuiDrawer::RenderDrawLists(ImDrawData* data) { auto drawer = graphics_context_->immediate_drawer(); - const float width = ImGui::GetIO().DisplaySize.x; - const float height = ImGui::GetIO().DisplaySize.y; + // Handle cases of screen coordinates != from framebuffer coordinates (e.g. + // retina displays). + ImGuiIO& io = ImGui::GetIO(); + float fb_height = io.DisplaySize.y * io.DisplayFramebufferScale.y; + data->ScaleClipRects(io.DisplayFramebufferScale); + + const float width = io.DisplaySize.x; + const float height = io.DisplaySize.y; drawer->Begin(static_cast(width), static_cast(height)); for (int i = 0; i < data->CmdListsCount; ++i) { @@ -157,9 +166,9 @@ void ImGuiDrawer::RenderDrawLists(ImDrawData* data) { ImmediateDrawBatch batch; batch.vertices = reinterpret_cast(cmd_list->VtxBuffer.Data); - batch.vertex_count = cmd_list->VtxBuffer.Size; + batch.vertex_count = cmd_list->VtxBuffer.size(); batch.indices = cmd_list->IdxBuffer.Data; - batch.index_count = cmd_list->IdxBuffer.Size; + batch.index_count = cmd_list->IdxBuffer.size(); drawer->BeginDrawBatch(batch); int index_offset = 0; diff --git a/src/xenia/ui/immediate_drawer.h b/src/xenia/ui/immediate_drawer.h index 808b9e88d..3b7f01238 100644 --- a/src/xenia/ui/immediate_drawer.h +++ b/src/xenia/ui/immediate_drawer.h @@ -80,6 +80,8 @@ struct ImmediateDraw { // Texture used when drawing, or nullptr if color only. // This is most commonly the handle of an ImmediateTexture. uintptr_t texture_handle = 0; + // Any samples outside of [0-1] on uv will be ignored. + bool restrict_texture_samples = false; // True to enable scissoring using the region defined by scissor_rect. bool scissor = false; diff --git a/src/xenia/ui/microprofile_drawer.cc b/src/xenia/ui/microprofile_drawer.cc index 8534f2f7e..e4006d0f5 100644 --- a/src/xenia/ui/microprofile_drawer.cc +++ b/src/xenia/ui/microprofile_drawer.cc @@ -216,6 +216,7 @@ void MicroprofileDrawer::Flush() { draw.primitive_type = current_primitive_type_; draw.count = vertex_count_; draw.texture_handle = font_texture_->handle; + draw.restrict_texture_samples = true; drawer->Draw(draw); drawer->EndDrawBatch(); diff --git a/src/xenia/ui/window.cc b/src/xenia/ui/window.cc index ddbb761b2..222d5a8f3 100644 --- a/src/xenia/ui/window.cc +++ b/src/xenia/ui/window.cc @@ -23,6 +23,7 @@ #include "xenia/base/assert.h" #include "xenia/base/clock.h" #include "xenia/base/logging.h" +#include "xenia/ui/elemental_drawer.h" namespace xe { namespace ui { @@ -129,7 +130,7 @@ bool Window::InitializeElemental(Loop* loop, el::graphics::Renderer* renderer) { bool Window::OnCreate() { return true; } bool Window::MakeReady() { - renderer_ = context_->CreateElementalRenderer(); + renderer_ = std::make_unique(this); // Initialize elemental. // TODO(benvanik): once? Do we care about multiple controls? @@ -143,7 +144,7 @@ bool Window::MakeReady() { root_element_->set_background_skin(TBIDC("background")); root_element_->set_rect({0, 0, width(), height()}); - // el::util::ShowDebugInfoSettingsWindow(root_element_.get()); + el::util::ShowDebugInfoSettingsForm(root_element_.get()); return true; }