From 9c965755c67c005764832875f3c704076617ccc8 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Fri, 10 Jul 2015 20:35:57 -0700 Subject: [PATCH] Simplified renderer interface. --- libxenia.vcxproj | 2 + libxenia.vcxproj.filters | 6 + src/xenia/ui/gl/gl4_elemental_renderer.cc | 292 ++++++++++++++++++++ src/xenia/ui/gl/gl4_elemental_renderer.h | 87 ++++++ src/xenia/ui/gl/wgl_elemental_control.cc | 319 +--------------------- third_party/elemental-forms | 2 +- 6 files changed, 390 insertions(+), 318 deletions(-) create mode 100644 src/xenia/ui/gl/gl4_elemental_renderer.cc create mode 100644 src/xenia/ui/gl/gl4_elemental_renderer.h diff --git a/libxenia.vcxproj b/libxenia.vcxproj index 7c620cc22..e591b3cee 100644 --- a/libxenia.vcxproj +++ b/libxenia.vcxproj @@ -169,6 +169,7 @@ + @@ -401,6 +402,7 @@ + diff --git a/libxenia.vcxproj.filters b/libxenia.vcxproj.filters index c71877768..bfb38c16a 100644 --- a/libxenia.vcxproj.filters +++ b/libxenia.vcxproj.filters @@ -736,6 +736,9 @@ src\xenia\ui\gl + + src\xenia\ui\gl + @@ -1386,6 +1389,9 @@ src\xenia\ui\gl + + src\xenia\ui\gl + diff --git a/src/xenia/ui/gl/gl4_elemental_renderer.cc b/src/xenia/ui/gl/gl4_elemental_renderer.cc new file mode 100644 index 000000000..1aa675c3f --- /dev/null +++ b/src/xenia/ui/gl/gl4_elemental_renderer.cc @@ -0,0 +1,292 @@ +/** + ****************************************************************************** + * 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 "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_context.h" +#include "xenia/ui/gl/gl.h" + +namespace xe { +namespace ui { +namespace gl { + +GL4ElementalRenderer::GL4Bitmap::GL4Bitmap(GLContext* context, + GL4ElementalRenderer* renderer) + : context_(context), renderer_(renderer) {} + +GL4ElementalRenderer::GL4Bitmap::~GL4Bitmap() { + GLContextLock 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) { + 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() { + GLContextLock lock(context_); + vertex_buffer_.Shutdown(); + glDeleteVertexArrays(1, &vao_); + glDeleteProgram(program_); +} + +std::unique_ptr GL4ElementalRenderer::Create( + GLContext* 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 = + "\n\ +#version 450 \n\ +#extension GL_ARB_bindless_texture : require \n\ +#extension GL_ARB_explicit_uniform_location : require \n\ +#extension GL_ARB_shading_language_420pack : require \n\ +precision highp float; \n\ +precision highp int; \n\ +layout(std140, column_major) uniform; \n\ +layout(std430, column_major) buffer; \n\ +"; + const std::string vertex_shader_source = header + + "\n\ +layout(location = 0) uniform mat4 projection_matrix; \n\ +layout(location = 0) in vec2 in_pos; \n\ +layout(location = 1) in vec4 in_color; \n\ +layout(location = 2) in vec2 in_uv; \n\ +layout(location = 0) out vec4 vtx_color; \n\ +layout(location = 1) out vec2 vtx_uv; \n\ +void main() { \n\ + gl_Position = projection_matrix * vec4(in_pos.xy, 0.0, 1.0); \n\ + vtx_color = in_color; \n\ + vtx_uv = in_uv; \n\ +} \n\ +"; + const std::string fragment_shader_source = header + + "\n\ +layout(location = 1, bindless_sampler) uniform sampler2D texture_sampler; \n\ +layout(location = 2) uniform float texture_mix; \n\ +layout(location = 0) in vec4 vtx_color; \n\ +layout(location = 1) in vec2 vtx_uv; \n\ +layout(location = 0) out vec4 oC; \n\ +void main() { \n\ + oC = vtx_color; \n\ + if (texture_mix > 0.0) { \n\ + vec4 color = texture(texture_sampler, vtx_uv); \n\ + oC *= color.rgba; \n\ + } \n\ +} \n\ +"; + + GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); + const char* vertex_shader_source_ptr = vertex_shader_source.c_str(); + GLint vertex_shader_source_length = GLint(vertex_shader_source.size()); + glShaderSource(vertex_shader, 1, &vertex_shader_source_ptr, + &vertex_shader_source_length); + glCompileShader(vertex_shader); + + GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + const char* fragment_shader_source_ptr = fragment_shader_source.c_str(); + GLint fragment_shader_source_length = GLint(fragment_shader_source.size()); + glShaderSource(fragment_shader, 1, &fragment_shader_source_ptr, + &fragment_shader_source_length); + glCompileShader(fragment_shader); + + program_ = glCreateProgram(); + glAttachShader(program_, vertex_shader); + glAttachShader(program_, fragment_shader); + glLinkProgram(program_); + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); + + 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, col)); + 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 = float(render_target_w); + float bottom = float(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_); +} + +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) { + auto bitmap = static_cast(batch->bitmap); + if (bitmap != current_bitmap_) { + current_bitmap_ = bitmap; + Flush(); + glProgramUniformHandleui64ARB(program_, 1, + bitmap ? bitmap->gpu_handle_ : 0); + glProgramUniform1f(program_, 2, bitmap ? 1.0f : 0.0f); + } + + if (draw_command_count_ + 1 > kMaxCommands) { + Flush(); + } + size_t total_length = sizeof(Vertex) * batch->vertex_count; + if (!vertex_buffer_.CanAcquire(total_length)) { + Flush(); + } + 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/gl4_elemental_renderer.h b/src/xenia/ui/gl/gl4_elemental_renderer.h new file mode 100644 index 000000000..2d09a6c56 --- /dev/null +++ b/src/xenia/ui/gl/gl4_elemental_renderer.h @@ -0,0 +1,87 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 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_ + +#include +#include + +#include "el/graphics/renderer.h" +#include "xenia/ui/gl/circular_buffer.h" +#include "xenia/ui/gl/gl_context.h" + +namespace xe { +namespace ui { +namespace gl { + +class GL4ElementalRenderer : public el::graphics::Renderer { + public: + GL4ElementalRenderer(GLContext* context); + ~GL4ElementalRenderer() override; + + static std::unique_ptr Create(GLContext* context); + + void BeginPaint(int render_target_w, int render_target_h) override; + void EndPaint() override; + + std::unique_ptr CreateBitmap(int width, int height, + uint32_t* data) override; + + void RenderBatch(Batch* batch) override; + void set_clip_rect(const el::Rect& rect) override; + + private: + class GL4Bitmap : public el::graphics::Bitmap { + public: + GL4Bitmap(GLContext* context, GL4ElementalRenderer* renderer); + ~GL4Bitmap(); + + 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; + int width_ = 0; + int height_ = 0; + GLuint handle_ = 0; + GLuint64 gpu_handle_ = 0; + }; + + static const uint32_t kMaxVertexBatchSize = 6 * 2048; + + bool Initialize(); + void Flush(); + + size_t max_vertex_batch_size() const override { return kMaxVertexBatchSize; } + + GLContext* 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; + Vertex vertices_[kMaxVertexBatchSize]; +}; + +} // namespace gl +} // namespace ui +} // namespace xe + +#endif // XENIA_UI_GL_GL4_ELEMENTAL_RENDERER_H_ diff --git a/src/xenia/ui/gl/wgl_elemental_control.cc b/src/xenia/ui/gl/wgl_elemental_control.cc index b1093a194..0ff7470a8 100644 --- a/src/xenia/ui/gl/wgl_elemental_control.cc +++ b/src/xenia/ui/gl/wgl_elemental_control.cc @@ -11,8 +11,6 @@ #include -#include "el/graphics/batching_renderer.h" -#include "el/graphics/bitmap_fragment.h" #include "el/util/math.h" #include "xenia/base/assert.h" #include "xenia/base/logging.h" @@ -20,65 +18,12 @@ #include "xenia/ui/gl/circular_buffer.h" #include "xenia/ui/gl/gl_context.h" #include "xenia/ui/gl/gl.h" +#include "xenia/ui/gl/gl4_elemental_renderer.h" namespace xe { namespace ui { namespace gl { -class GL4BatchingRenderer : public el::graphics::BatchingRenderer { - public: - GL4BatchingRenderer(GLContext* context); - ~GL4BatchingRenderer() override; - - static std::unique_ptr Create(GLContext* context); - - void BeginPaint(int render_target_w, int render_target_h) override; - void EndPaint() override; - - std::unique_ptr CreateBitmap(int width, int height, - uint32_t* data) override; - - void RenderBatch(Batch* batch) override; - void set_clip_rect(const el::Rect& rect) override; - - private: - class GL4Bitmap : public el::graphics::Bitmap { - public: - GL4Bitmap(GLContext* context, GL4BatchingRenderer* renderer); - ~GL4Bitmap(); - - 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; - GL4BatchingRenderer* renderer_ = nullptr; - int width_ = 0; - int height_ = 0; - GLuint handle_ = 0; - GLuint64 gpu_handle_ = 0; - }; - - bool Initialize(); - void Flush(); - - GLContext* 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; -}; - WGLElementalControl::WGLElementalControl(Loop* loop) : ElementalControl(loop, Flags::kFlagOwnPaint), loop_(loop) {} @@ -133,7 +78,7 @@ bool WGLElementalControl::Create() { } std::unique_ptr WGLElementalControl::CreateRenderer() { - return GL4BatchingRenderer::Create(&context_); + return GL4ElementalRenderer::Create(&context_); } void WGLElementalControl::OnLayout(UIEvent& e) { @@ -190,266 +135,6 @@ void WGLElementalControl::SynchronousRepaint( RDW_INTERNALPAINT | RDW_UPDATENOW | RDW_ALLCHILDREN); } -GL4BatchingRenderer::GL4Bitmap::GL4Bitmap(GLContext* context, - GL4BatchingRenderer* renderer) - : context_(context), renderer_(renderer) {} - -GL4BatchingRenderer::GL4Bitmap::~GL4Bitmap() { - GLContextLock lock(context_); - - // Must flush and unbind before we delete the texture. - renderer_->FlushBitmap(this); - glMakeTextureHandleNonResidentARB(gpu_handle_); - glDeleteTextures(1, &handle_); -} - -bool GL4BatchingRenderer::GL4Bitmap::Init(int width, int height, - uint32_t* data) { - 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 GL4BatchingRenderer::GL4Bitmap::set_data(uint32_t* data) { - renderer_->FlushBitmap(this); - glTextureSubImage2D(handle_, 0, 0, 0, width_, height_, GL_RGBA, - GL_UNSIGNED_BYTE, data); -} - -GL4BatchingRenderer::GL4BatchingRenderer(GLContext* context) - : context_(context), vertex_buffer_(kVertexBatchSize * sizeof(Vertex)) {} - -GL4BatchingRenderer::~GL4BatchingRenderer() { - GLContextLock lock(context_); - vertex_buffer_.Shutdown(); - glDeleteVertexArrays(1, &vao_); - glDeleteProgram(program_); -} - -std::unique_ptr GL4BatchingRenderer::Create( - GLContext* context) { - auto renderer = std::make_unique(context); - if (!renderer->Initialize()) { - XELOGE("Failed to initialize TurboBadger GL4 renderer"); - return nullptr; - } - return renderer; -} - -bool GL4BatchingRenderer::Initialize() { - if (!vertex_buffer_.Initialize()) { - XELOGE("Failed to initialize circular buffer"); - return false; - } - - const std::string header = - "\n\ -#version 450 \n\ -#extension GL_ARB_bindless_texture : require \n\ -#extension GL_ARB_explicit_uniform_location : require \n\ -#extension GL_ARB_shading_language_420pack : require \n\ -precision highp float; \n\ -precision highp int; \n\ -layout(std140, column_major) uniform; \n\ -layout(std430, column_major) buffer; \n\ -"; - const std::string vertex_shader_source = header + - "\n\ -layout(location = 0) uniform mat4 projection_matrix; \n\ -layout(location = 0) in vec2 in_pos; \n\ -layout(location = 1) in vec4 in_color; \n\ -layout(location = 2) in vec2 in_uv; \n\ -layout(location = 0) out vec4 vtx_color; \n\ -layout(location = 1) out vec2 vtx_uv; \n\ -void main() { \n\ - gl_Position = projection_matrix * vec4(in_pos.xy, 0.0, 1.0); \n\ - vtx_color = in_color; \n\ - vtx_uv = in_uv; \n\ -} \n\ -"; - const std::string fragment_shader_source = header + - "\n\ -layout(location = 1, bindless_sampler) uniform sampler2D texture_sampler; \n\ -layout(location = 2) uniform float texture_mix; \n\ -layout(location = 0) in vec4 vtx_color; \n\ -layout(location = 1) in vec2 vtx_uv; \n\ -layout(location = 0) out vec4 oC; \n\ -void main() { \n\ - oC = vtx_color; \n\ - if (texture_mix > 0.0) { \n\ - vec4 color = texture(texture_sampler, vtx_uv); \n\ - oC *= color.rgba; \n\ - } \n\ -} \n\ -"; - - GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); - const char* vertex_shader_source_ptr = vertex_shader_source.c_str(); - GLint vertex_shader_source_length = GLint(vertex_shader_source.size()); - glShaderSource(vertex_shader, 1, &vertex_shader_source_ptr, - &vertex_shader_source_length); - glCompileShader(vertex_shader); - - GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - const char* fragment_shader_source_ptr = fragment_shader_source.c_str(); - GLint fragment_shader_source_length = GLint(fragment_shader_source.size()); - glShaderSource(fragment_shader, 1, &fragment_shader_source_ptr, - &fragment_shader_source_length); - glCompileShader(fragment_shader); - - program_ = glCreateProgram(); - glAttachShader(program_, vertex_shader); - glAttachShader(program_, fragment_shader); - glLinkProgram(program_); - glDeleteShader(vertex_shader); - glDeleteShader(fragment_shader); - - 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, col)); - 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 GL4BatchingRenderer::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 GL4BatchingRenderer::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 GL4BatchingRenderer::BeginPaint(int render_target_w, int render_target_h) { - BatchingRenderer::BeginPaint(render_target_w, render_target_h); - - 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 = float(render_target_w); - float bottom = float(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_); -} - -void GL4BatchingRenderer::EndPaint() { - BatchingRenderer::EndPaint(); - - Flush(); - - glUseProgram(0); - glBindVertexArray(0); -} - -void GL4BatchingRenderer::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 GL4BatchingRenderer::RenderBatch(Batch* batch) { - auto bitmap = static_cast(batch->bitmap); - if (bitmap != current_bitmap_) { - current_bitmap_ = bitmap; - Flush(); - glProgramUniformHandleui64ARB(program_, 1, - bitmap ? bitmap->gpu_handle_ : 0); - glProgramUniform1f(program_, 2, bitmap ? 1.0f : 0.0f); - } - - if (draw_command_count_ + 1 > kMaxCommands) { - Flush(); - } - size_t total_length = sizeof(Vertex) * batch->vertex_count; - if (!vertex_buffer_.CanAcquire(total_length)) { - Flush(); - } - 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->vertex, 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/third_party/elemental-forms b/third_party/elemental-forms index 30adbc89f..a03a30899 160000 --- a/third_party/elemental-forms +++ b/third_party/elemental-forms @@ -1 +1 @@ -Subproject commit 30adbc89f338caa80693dc6ab48a503f0ef3728f +Subproject commit a03a3089954862677e2d30f85824b978a45eba22