Moving elemental to immediate drawer.
This commit is contained in:
parent
440c807936
commit
fdf59fec5f
|
@ -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<uint8_t*>(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<uint8_t*>(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<el::graphics::Bitmap> ElementalDrawer::CreateBitmap(
|
||||||
|
int width, int height, uint32_t* data) {
|
||||||
|
auto bitmap = std::make_unique<ElementalBitmap>(this, width, height, data);
|
||||||
|
return std::unique_ptr<el::graphics::Bitmap>(bitmap.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElementalDrawer::RenderBatch(Batch* batch) {
|
||||||
|
auto immediate_drawer = graphics_context_->immediate_drawer();
|
||||||
|
|
||||||
|
ImmediateDrawBatch draw_batch;
|
||||||
|
|
||||||
|
draw_batch.vertices = reinterpret_cast<ImmediateVertex*>(batch->vertices);
|
||||||
|
draw_batch.vertex_count = static_cast<int>(batch->vertex_count);
|
||||||
|
immediate_drawer->BeginDrawBatch(draw_batch);
|
||||||
|
|
||||||
|
ImmediateDraw draw;
|
||||||
|
draw.primitive_type = ImmediatePrimitiveType::kTriangles;
|
||||||
|
draw.count = static_cast<int>(batch->vertex_count);
|
||||||
|
auto bitmap = static_cast<ElementalBitmap*>(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
|
|
@ -2,31 +2,30 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XENIA_UI_GL_GL4_ELEMENTAL_RENDERER_H_
|
#ifndef XENIA_UI_ELEMENTAL_DRAWER_H_
|
||||||
#define XENIA_UI_GL_GL4_ELEMENTAL_RENDERER_H_
|
#define XENIA_UI_ELEMENTAL_DRAWER_H_
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "el/graphics/renderer.h"
|
#include "el/graphics/renderer.h"
|
||||||
#include "xenia/ui/gl/circular_buffer.h"
|
#include "xenia/ui/immediate_drawer.h"
|
||||||
#include "xenia/ui/gl/gl_context.h"
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
namespace gl {
|
|
||||||
|
|
||||||
class GL4ElementalRenderer : public el::graphics::Renderer {
|
class GraphicsContext;
|
||||||
|
class Window;
|
||||||
|
|
||||||
|
class ElementalDrawer : public el::graphics::Renderer {
|
||||||
public:
|
public:
|
||||||
explicit GL4ElementalRenderer(GLContext* context);
|
ElementalDrawer(Window* window);
|
||||||
~GL4ElementalRenderer() override;
|
~ElementalDrawer();
|
||||||
|
|
||||||
static std::unique_ptr<GL4ElementalRenderer> Create(GLContext* context);
|
|
||||||
|
|
||||||
void BeginPaint(int render_target_w, int render_target_h) override;
|
void BeginPaint(int render_target_w, int render_target_h) override;
|
||||||
void EndPaint() override;
|
void EndPaint() override;
|
||||||
|
@ -37,51 +36,34 @@ class GL4ElementalRenderer : public el::graphics::Renderer {
|
||||||
void RenderBatch(Batch* batch) override;
|
void RenderBatch(Batch* batch) override;
|
||||||
void set_clip_rect(const el::Rect& rect) override;
|
void set_clip_rect(const el::Rect& rect) override;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
class GL4Bitmap : public el::graphics::Bitmap {
|
class ElementalBitmap : public el::graphics::Bitmap {
|
||||||
public:
|
public:
|
||||||
GL4Bitmap(GLContext* context, GL4ElementalRenderer* renderer);
|
ElementalBitmap(ElementalDrawer* drawer, int width, int height,
|
||||||
~GL4Bitmap();
|
uint32_t* data);
|
||||||
|
~ElementalBitmap();
|
||||||
|
|
||||||
bool Init(int width, int height, uint32_t* data);
|
|
||||||
int width() override { return width_; }
|
int width() override { return width_; }
|
||||||
int height() override { return height_; }
|
int height() override { return height_; }
|
||||||
void set_data(uint32_t* data) override;
|
void set_data(uint32_t* data) override;
|
||||||
|
|
||||||
GLContext* context_ = nullptr;
|
ElementalDrawer* drawer_ = nullptr;
|
||||||
GL4ElementalRenderer* renderer_ = nullptr;
|
|
||||||
int width_ = 0;
|
int width_ = 0;
|
||||||
int height_ = 0;
|
int height_ = 0;
|
||||||
GLuint handle_ = 0;
|
std::unique_ptr<ImmediateTexture> texture_;
|
||||||
GLuint64 gpu_handle_ = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t kMaxVertexBatchSize = 6 * 2048;
|
static const uint32_t kMaxVertexBatchSize = 6 * 2048;
|
||||||
|
|
||||||
bool Initialize();
|
|
||||||
void Flush();
|
|
||||||
|
|
||||||
size_t max_vertex_batch_size() const override { return kMaxVertexBatchSize; }
|
size_t max_vertex_batch_size() const override { return kMaxVertexBatchSize; }
|
||||||
|
|
||||||
GLContext* context_ = nullptr;
|
Window* window_ = nullptr;
|
||||||
|
GraphicsContext* graphics_context_ = nullptr;
|
||||||
|
|
||||||
GLuint program_ = 0;
|
el::Rect current_clip_;
|
||||||
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];
|
Vertex vertices_[kMaxVertexBatchSize];
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gl
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
#endif // XENIA_UI_GL_GL4_ELEMENTAL_RENDERER_H_
|
#endif // XENIA_UI_ELEMENTAL_DRAWER_H_
|
|
@ -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 <cstring>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#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> GL4ElementalRenderer::Create(
|
|
||||||
GLContext* context) {
|
|
||||||
GraphicsContextLock lock(context);
|
|
||||||
auto renderer = std::make_unique<GL4ElementalRenderer>(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<el::graphics::Bitmap> GL4ElementalRenderer::CreateBitmap(
|
|
||||||
int width, int height, uint32_t* data) {
|
|
||||||
auto bitmap = std::make_unique<GL4Bitmap>(context_, this);
|
|
||||||
if (!bitmap->Init(width, height, data)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return std::unique_ptr<el::graphics::Bitmap>(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<float>(render_target_w);
|
|
||||||
float bottom = static_cast<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_);
|
|
||||||
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<GL4Bitmap*>(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
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/math.h"
|
#include "xenia/base/math.h"
|
||||||
#include "xenia/profiling.h"
|
#include "xenia/profiling.h"
|
||||||
#include "xenia/ui/gl/gl4_elemental_renderer.h"
|
|
||||||
#include "xenia/ui/gl/gl_immediate_drawer.h"
|
#include "xenia/ui/gl/gl_immediate_drawer.h"
|
||||||
#include "xenia/ui/window.h"
|
#include "xenia/ui/window.h"
|
||||||
|
|
||||||
|
@ -413,10 +412,6 @@ void GLContext::SetupDebugging() {
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<el::graphics::Renderer> GLContext::CreateElementalRenderer() {
|
|
||||||
return GL4ElementalRenderer::Create(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImmediateDrawer* GLContext::immediate_drawer() {
|
ImmediateDrawer* GLContext::immediate_drawer() {
|
||||||
return immediate_drawer_.get();
|
return immediate_drawer_.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@ class GLContext : public GraphicsContext {
|
||||||
HDC dc() const { return dc_; }
|
HDC dc() const { return dc_; }
|
||||||
|
|
||||||
std::unique_ptr<GraphicsContext> CreateShared() override;
|
std::unique_ptr<GraphicsContext> CreateShared() override;
|
||||||
std::unique_ptr<el::graphics::Renderer> CreateElementalRenderer() override;
|
|
||||||
|
|
||||||
ImmediateDrawer* immediate_drawer() override;
|
ImmediateDrawer* immediate_drawer() override;
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/ui/graphics_context.h"
|
#include "xenia/ui/graphics_context.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -119,12 +120,13 @@ void main() {
|
||||||
const std::string fragment_shader_source = header +
|
const std::string fragment_shader_source = header +
|
||||||
R"(
|
R"(
|
||||||
layout(location = 1) uniform sampler2D texture_sampler;
|
layout(location = 1) uniform sampler2D texture_sampler;
|
||||||
|
layout(location = 2) uniform int restrict_texture_samples;
|
||||||
layout(location = 0) in vec2 vtx_uv;
|
layout(location = 0) in vec2 vtx_uv;
|
||||||
layout(location = 1) in vec4 vtx_color;
|
layout(location = 1) in vec4 vtx_color;
|
||||||
layout(location = 0) out vec4 out_color;
|
layout(location = 0) out vec4 out_color;
|
||||||
void main() {
|
void main() {
|
||||||
out_color = vtx_color;
|
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);
|
vec4 tex_color = texture(texture_sampler, vtx_uv);
|
||||||
out_color *= tex_color;
|
out_color *= tex_color;
|
||||||
// TODO(benvanik): microprofiler shadows.
|
// TODO(benvanik): microprofiler shadows.
|
||||||
|
@ -159,9 +161,10 @@ std::unique_ptr<ImmediateTexture> GLImmediateDrawer::CreateTexture(
|
||||||
GraphicsContextLock lock(graphics_context_);
|
GraphicsContextLock lock(graphics_context_);
|
||||||
auto texture =
|
auto texture =
|
||||||
std::make_unique<GLImmediateTexture>(width, height, filter, repeat);
|
std::make_unique<GLImmediateTexture>(width, height, filter, repeat);
|
||||||
|
glTextureStorage2D(static_cast<GLuint>(texture->handle), 1, GL_RGBA8, width,
|
||||||
|
height);
|
||||||
if (data) {
|
if (data) {
|
||||||
glTextureSubImage2D(static_cast<GLuint>(texture->handle), 0, 0, 0, width,
|
UpdateTexture(texture.get(), data);
|
||||||
height, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
|
||||||
}
|
}
|
||||||
return std::unique_ptr<ImmediateTexture>(texture.release());
|
return std::unique_ptr<ImmediateTexture>(texture.release());
|
||||||
}
|
}
|
||||||
|
@ -185,9 +188,8 @@ void GLImmediateDrawer::Begin(int render_target_width,
|
||||||
glEnablei(GL_BLEND, 0);
|
glEnablei(GL_BLEND, 0);
|
||||||
glBlendEquationi(0, GL_FUNC_ADD);
|
glBlendEquationi(0, GL_FUNC_ADD);
|
||||||
glBlendFunci(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunci(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glDisable(GL_CULL_FACE);
|
glDisablei(GL_DEPTH_TEST, 0);
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisablei(GL_SCISSOR_TEST, 0);
|
||||||
glDisable(GL_SCISSOR_TEST);
|
|
||||||
|
|
||||||
// Prepare drawing resources.
|
// Prepare drawing resources.
|
||||||
glUseProgram(program_);
|
glUseProgram(program_);
|
||||||
|
@ -206,10 +208,12 @@ void GLImmediateDrawer::Begin(int render_target_width,
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
|
void GLImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
|
||||||
|
assert_true(batch.vertex_count <= kMaxDrawVertices);
|
||||||
glNamedBufferSubData(vertex_buffer_, 0,
|
glNamedBufferSubData(vertex_buffer_, 0,
|
||||||
batch.vertex_count * sizeof(ImmediateVertex),
|
batch.vertex_count * sizeof(ImmediateVertex),
|
||||||
batch.vertices);
|
batch.vertices);
|
||||||
if (batch.indices) {
|
if (batch.indices) {
|
||||||
|
assert_true(batch.index_count <= kMaxDrawIndices);
|
||||||
glNamedBufferSubData(index_buffer_, 0, batch.index_count * sizeof(uint16_t),
|
glNamedBufferSubData(index_buffer_, 0, batch.index_count * sizeof(uint16_t),
|
||||||
batch.indices);
|
batch.indices);
|
||||||
}
|
}
|
||||||
|
@ -219,11 +223,11 @@ void GLImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
|
||||||
|
|
||||||
void GLImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
void GLImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
||||||
if (draw.scissor) {
|
if (draw.scissor) {
|
||||||
glEnable(GL_SCISSOR_TEST);
|
glEnablei(GL_SCISSOR_TEST, 0);
|
||||||
glScissor(draw.scissor_rect[0], draw.scissor_rect[1], draw.scissor_rect[2],
|
glScissorIndexed(0, draw.scissor_rect[0], draw.scissor_rect[1],
|
||||||
draw.scissor_rect[3]);
|
draw.scissor_rect[2], draw.scissor_rect[3]);
|
||||||
} else {
|
} else {
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisablei(GL_SCISSOR_TEST, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (draw.texture_handle) {
|
if (draw.texture_handle) {
|
||||||
|
@ -231,6 +235,7 @@ void GLImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
||||||
} else {
|
} else {
|
||||||
glBindTextureUnit(0, 0);
|
glBindTextureUnit(0, 0);
|
||||||
}
|
}
|
||||||
|
glProgramUniform1i(program_, 2, draw.restrict_texture_samples ? 1 : 0);
|
||||||
|
|
||||||
GLenum mode = GL_TRIANGLES;
|
GLenum mode = GL_TRIANGLES;
|
||||||
switch (draw.primitive_type) {
|
switch (draw.primitive_type) {
|
||||||
|
@ -256,7 +261,7 @@ void GLImmediateDrawer::EndDrawBatch() { glFlush(); }
|
||||||
|
|
||||||
void GLImmediateDrawer::End() {
|
void GLImmediateDrawer::End() {
|
||||||
// Restore modified state.
|
// Restore modified state.
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisablei(GL_SCISSOR_TEST, 0);
|
||||||
glBindTextureUnit(0, 0);
|
glBindTextureUnit(0, 0);
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "el/graphics/renderer.h"
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
@ -27,7 +25,6 @@ class GraphicsContext {
|
||||||
Window* target_window() const { return target_window_; }
|
Window* target_window() const { return target_window_; }
|
||||||
|
|
||||||
virtual std::unique_ptr<GraphicsContext> CreateShared() = 0;
|
virtual std::unique_ptr<GraphicsContext> CreateShared() = 0;
|
||||||
virtual std::unique_ptr<el::graphics::Renderer> CreateElementalRenderer() = 0;
|
|
||||||
|
|
||||||
virtual ImmediateDrawer* immediate_drawer() = 0;
|
virtual ImmediateDrawer* immediate_drawer() = 0;
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -80,6 +80,8 @@ struct ImmediateDraw {
|
||||||
// Texture used when drawing, or nullptr if color only.
|
// Texture used when drawing, or nullptr if color only.
|
||||||
// This is most commonly the handle of an ImmediateTexture.
|
// This is most commonly the handle of an ImmediateTexture.
|
||||||
uintptr_t texture_handle = 0;
|
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.
|
// True to enable scissoring using the region defined by scissor_rect.
|
||||||
bool scissor = false;
|
bool scissor = false;
|
||||||
|
|
|
@ -216,6 +216,7 @@ void MicroprofileDrawer::Flush() {
|
||||||
draw.primitive_type = current_primitive_type_;
|
draw.primitive_type = current_primitive_type_;
|
||||||
draw.count = vertex_count_;
|
draw.count = vertex_count_;
|
||||||
draw.texture_handle = font_texture_->handle;
|
draw.texture_handle = font_texture_->handle;
|
||||||
|
draw.restrict_texture_samples = true;
|
||||||
drawer->Draw(draw);
|
drawer->Draw(draw);
|
||||||
|
|
||||||
drawer->EndDrawBatch();
|
drawer->EndDrawBatch();
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/clock.h"
|
#include "xenia/base/clock.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/ui/elemental_drawer.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
@ -129,7 +130,7 @@ bool Window::InitializeElemental(Loop* loop, el::graphics::Renderer* renderer) {
|
||||||
bool Window::OnCreate() { return true; }
|
bool Window::OnCreate() { return true; }
|
||||||
|
|
||||||
bool Window::MakeReady() {
|
bool Window::MakeReady() {
|
||||||
renderer_ = context_->CreateElementalRenderer();
|
renderer_ = std::make_unique<ElementalDrawer>(this);
|
||||||
|
|
||||||
// Initialize elemental.
|
// Initialize elemental.
|
||||||
// TODO(benvanik): once? Do we care about multiple controls?
|
// 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_background_skin(TBIDC("background"));
|
||||||
root_element_->set_rect({0, 0, width(), height()});
|
root_element_->set_rect({0, 0, width(), height()});
|
||||||
|
|
||||||
// el::util::ShowDebugInfoSettingsWindow(root_element_.get());
|
el::util::ShowDebugInfoSettingsForm(root_element_.get());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue