Performance optimization.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Has been cancelled
This commit is contained in:
@@ -47,7 +47,7 @@ if (WIN32)
|
||||
)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "-O3 -Wall -Wextra")
|
||||
#set(CMAKE_CXX_FLAGS "-O3 -Wall -Wextra")
|
||||
|
||||
file(COPY "assets" DESTINATION "${PROJECT_BINARY_DIR}")
|
||||
file(GLOB_RECURSE ASSETS "assets/*")
|
||||
|
@@ -72,15 +72,6 @@ vec4 DefaultInstanced() {
|
||||
return gl_ModelViewProjectionMatrix * vec4(world_pos, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec4 FillRectInstanced() {
|
||||
vec2 instance_pos = a_instance_position + vec2(0.0, a_instance_size.y);
|
||||
vec2 scaled = a_vertex_position * a_instance_size;
|
||||
vec2 world_pos = scaled + instance_pos;
|
||||
|
||||
v_color = a_instance_color;
|
||||
return gl_ModelViewProjectionMatrix * vec4(world_pos, 0.0, 1.0);
|
||||
}
|
||||
|
||||
void main() {
|
||||
GL_TEXTURE0_COORD = gl_MultiTexCoord0.xy;
|
||||
GL_TEXTURE1_COORD = gl_MultiTexCoord1.xy;
|
||||
@@ -156,7 +147,7 @@ void main() {
|
||||
*/
|
||||
|
||||
if (JGL_RENDERING_ROUTINE == J2D_FillRect && JGL_INSTANCED_RENDERING)
|
||||
gl_Position = FillRectInstanced();
|
||||
gl_Position = DefaultInstanced();
|
||||
else
|
||||
gl_Position = Default();
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <Color4.hpp>
|
||||
#include <JGL/types/Texture.h>
|
||||
#include <JGL/types/Enums.h>
|
||||
#include <JGL/types/Instance.h>
|
||||
#include <JGL/types/FontCache.h>
|
||||
#include <JGL/types/Font.h>
|
||||
#include <JGL/types/RenderTarget.h>
|
||||
@@ -398,8 +399,7 @@ namespace JGL::J2D {
|
||||
void OutlineEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, float thickness = 1, int subdivisions = 8);
|
||||
void FillEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, int subdivisions = 8);
|
||||
|
||||
void BatchFillRect(const Color4* colors, const Vector2* positions, const Vector2* sizes, const size_t& rect_count);
|
||||
|
||||
void BatchFillRect(const Instance2D* instances, const size_t& instance_count);
|
||||
void BatchFillCircle(const Color4 *colors, const Vector2* positions, float* radii, unsigned int subdivisions, const size_t& circle_count);
|
||||
}
|
||||
|
||||
|
49
include/JGL/types/Instance.h
Normal file
49
include/JGL/types/Instance.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <Colors.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
||||
|
||||
namespace JGL {
|
||||
struct Instance2D;
|
||||
struct Instance3D;
|
||||
}
|
||||
|
||||
/// Information provided to JGL for each instance of an object you're rendering in a batch.
|
||||
/// @note This is non-negotiable. This information is interleaved in *the same buffer* in v-ram for performance reasons - Redacted.
|
||||
struct JGL::Instance2D {
|
||||
public:
|
||||
Color4 color;
|
||||
Vector2 position;
|
||||
Vector2 size;
|
||||
Vector2 scale;
|
||||
float rotation;
|
||||
public:
|
||||
/// @param position The position of the instance in world space.
|
||||
/// @param size The size of the instance.
|
||||
/// @param scale A multiplier to be applied to the size.
|
||||
/// @param rotation The rotation in radians.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4.
|
||||
/// @note If the thing you're drawing is textured you probably want Colors::White
|
||||
Instance2D(const Color4& color, const Vector2& position, const Vector2& size, const Vector2& scale = Vector2::One, float rotation = 0.0f) :
|
||||
color(color), position(position), size(size), scale(scale), rotation(rotation) {};
|
||||
Instance2D() = default;
|
||||
~Instance2D() = default;
|
||||
};
|
||||
|
||||
struct JGL::Instance3D {
|
||||
public:
|
||||
Matrix4x4 instance_matrix;
|
||||
Color4 color;
|
||||
public:
|
||||
/// @param instance_matrix A matrix containing rotation matrix, position, and scale.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4.
|
||||
/// @note If the thing you're drawing is textured you probably want Colors::White
|
||||
Instance3D(const Matrix4x4& instance_matrix, const Color4& color) : instance_matrix(instance_matrix), color(color) {};
|
||||
Instance3D() = default;
|
||||
~Instance3D() = default;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
13
main.cpp
13
main.cpp
@@ -15,9 +15,7 @@ using namespace JGL;
|
||||
using JGL::Font;
|
||||
|
||||
float fps = 0.0f;
|
||||
std::vector<Vector2> rect_pos;
|
||||
std::vector<Vector2> rect_size;
|
||||
std::vector<Color4> rect_colors;
|
||||
std::vector<Instance2D> rect_instances;
|
||||
/// A draggable 2D point that highlights when moused over and when clicked.
|
||||
class Gizmo
|
||||
{
|
||||
@@ -142,11 +140,8 @@ public:
|
||||
shader = new Shader(std::filesystem::path("assets/shader_programs/test_vertex.glsl"), std::filesystem::path("assets/shader_programs/test_fragment.glsl"),
|
||||
{{"a_vertex_position", 0}, {"a_instance_position", 1}, {"a_instance_size", 2}, {"a_instance_color", 3}});
|
||||
|
||||
for (unsigned int i = 0; i < 1000000; i++) {
|
||||
rect_pos.emplace_back(420, 420);
|
||||
rect_size.emplace_back(20, 20);
|
||||
rect_colors.emplace_back(Colors::Red);
|
||||
}
|
||||
for (unsigned int i = 0; i < 100; i++)
|
||||
rect_instances.emplace_back(Colors::Red, Vector2(420, 420), Vector2(20, 20));
|
||||
}
|
||||
|
||||
EulerAngleXYZ textAngle = {0,0,0};
|
||||
@@ -202,7 +197,7 @@ public:
|
||||
|
||||
J2D::Begin(j2d_render_target, shader, true);
|
||||
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
|
||||
J2D::BatchFillRect(rect_colors.data(), rect_pos.data(), rect_size.data(), rect_pos.size());
|
||||
J2D::BatchFillRect(rect_instances.data(), rect_instances.size());
|
||||
J2D::DrawSprite(image, {300, 400}, sprite_radians * 0.10f, {0.5,0.5}, {1, 1}, Colors::White);
|
||||
J2D::DrawMirrorSprite(image, {400, 300}, Direction::Horizontal | Direction::Vertical, sprite_radians, {0.5,0.5}, {1, 1}, Colors::White);
|
||||
J2D::DrawPartialSprite(image, Vector2(225, 300), Vector2(image->GetDimensions()) * 0.25, Vector2(image->GetDimensions()) * 0.75, sprite_radians, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
|
@@ -47,7 +47,8 @@ void JGL::ShapeCache::Init() {
|
||||
cube_normal_data = new VRamList(vertex_normals.data(), vertex_normals.size());
|
||||
|
||||
if (!square_origin_topleft_vertex_data) {
|
||||
std::array<Vector2, 4> square_vertices = { Vector2(0, 0), {1, 0}, {1, -1}, {0, -1} };
|
||||
//std::array<Vector2, 4> square_vertices = { Vector2(0, 0), {1, 0}, {1, -1}, {0, -1} };
|
||||
std::array<Vector2, 4> square_vertices = { Vector2(0, 0), {0, 1}, {1, 1}, {1, 0} };
|
||||
square_origin_topleft_vertex_data = new VRamList(square_vertices.data(), square_vertices.size());
|
||||
}
|
||||
if (!j2d_default_normal_data) {
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include <JGL/JGL.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <JGL/types/Instance.h>
|
||||
#include <J3ML/Algorithm/Bezier.hpp>
|
||||
#include "internals/internals.h"
|
||||
|
||||
@@ -262,14 +263,14 @@ void J2D::OutlineRect(const Color4& color, const Vector2& pos, const Vector2& si
|
||||
}
|
||||
|
||||
void J2D::FillRect(const Color4& color, const Vector2& pos, const Vector2& size) {
|
||||
BatchFillRect(&color, &pos, &size, 1);
|
||||
Instance2D rect(color, pos, size);
|
||||
BatchFillRect(&rect, 1);
|
||||
}
|
||||
|
||||
void J2D::BatchFillRect(const Color4* colors, const Vector2* positions, const Vector2* sizes, const size_t& rect_count) {
|
||||
void J2D::BatchFillRect(const Instance2D* instances, const size_t& instance_count) {
|
||||
if (!state_stack.Size())
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
if (rect_count <= 0)
|
||||
if (instance_count <= 0)
|
||||
return;
|
||||
|
||||
if (current_state.current_shader)
|
||||
@@ -277,14 +278,14 @@ void J2D::BatchFillRect(const Color4* colors, const Vector2* positions, const Ve
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::square_origin_topleft_vertex_data->Handle());
|
||||
|
||||
if (rect_count == 1 || !supports_instanced || !current_state.current_shader) {
|
||||
if (instance_count == 1 || !supports_instanced || !current_state.current_shader) {
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), nullptr);
|
||||
|
||||
for (size_t i = 0; i < rect_count; i++) {
|
||||
for (size_t i = 0; i < instance_count; i++) {
|
||||
glPushMatrix();
|
||||
glColor4ubv(colors[i].ptr());
|
||||
glTranslatef(positions[i].x, positions[i].y + sizes[i].y, 0);
|
||||
glScalef(sizes[i].x, sizes[i].y, 1);
|
||||
glColor4ubv(instances[i].color.ptr());
|
||||
glTranslatef(instances[i].position.x, instances[i].position.y, 0);
|
||||
glScalef(instances[i].size.x, instances[i].size.y, 1);
|
||||
glDrawArrays(GL_QUADS, 0, 4);
|
||||
glPopMatrix();
|
||||
}
|
||||
@@ -294,33 +295,26 @@ void J2D::BatchFillRect(const Color4* colors, const Vector2* positions, const Ve
|
||||
else {
|
||||
current_state.current_shader->SetBool("JGL_INSTANCED_RENDERING", true);
|
||||
|
||||
std::vector<Instance> instances(rect_count);
|
||||
Instance* ptr = instances.data();
|
||||
// Shader does translation to top left corner in this path - Redacted.
|
||||
for (size_t i = 0; i < rect_count; ++i)
|
||||
ptr[i] = { positions[i], sizes[i], colors[i] };
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), nullptr);
|
||||
glVertexAttribDivisorARB(0, 0);
|
||||
|
||||
// * 5 because 4x float & 4x uint8_t = sizeof(float) - Redacted.
|
||||
VRamList instance_buffer((GLfloat*) instances.data(), instances.size() * 5, Stream);
|
||||
VRamList instance_buffer((GLfloat*) instances, instance_count * (sizeof(Instance2D) / sizeof(GLfloat)), Stream);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, instance_buffer.Handle());
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Instance), (GLvoid*) offsetof(Instance, position));
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Instance2D), (GLvoid*) offsetof(Instance2D, position));
|
||||
glVertexAttribDivisorARB(1, 1);
|
||||
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Instance), (GLvoid*) offsetof(Instance, size));
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Instance2D), (GLvoid*) offsetof(Instance2D, size));
|
||||
glVertexAttribDivisorARB(2, 1);
|
||||
|
||||
glEnableVertexAttribArray(3);
|
||||
glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Instance), (GLvoid*) offsetof(Instance, color));
|
||||
glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Instance2D), (GLvoid*) offsetof(Instance2D, color));
|
||||
glVertexAttribDivisorARB(3, 1);
|
||||
|
||||
glDrawArraysInstancedARB(GL_QUADS, 0, 4, rect_count);
|
||||
glDrawArraysInstancedARB(GL_QUADS, 0, 4, instance_count);
|
||||
|
||||
glDisableVertexAttribArray(0);
|
||||
glDisableVertexAttribArray(1);
|
||||
@@ -368,8 +362,6 @@ void J2D::FillGradientRect(const Color4& top_left_color, const Color4& bottom_le
|
||||
|
||||
void J2D::FillRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius, unsigned int subdivisions) {
|
||||
std::array<Color4, 4> colors = { color, color, color, color };
|
||||
std::array<Vector2, 2> rect_positions = { Vector2(pos.x + radius, pos.y), {pos.x, pos.y + radius} };
|
||||
std::array<Vector2, 2> rect_sizes = { Vector2(size.x - 2 * radius, size.y), {size.x, size.y - 2 * radius} };
|
||||
std::array<float, 4> circle_radii = { radius, radius, radius, radius };
|
||||
std::array<Vector2, 4> circle_positions
|
||||
{
|
||||
@@ -380,7 +372,8 @@ void J2D::FillRoundedRect(const Color4& color, const Vector2& pos, const Vector2
|
||||
if (current_state.current_shader)
|
||||
current_state.current_shader->SetInt("JGL_RENDERING_ROUTINE", RENDERING_ROUTINE_ID::J2D_FillRoundedRect);
|
||||
|
||||
J2D::BatchFillRect(colors.data(), rect_positions.data(), rect_sizes.data(), 2);
|
||||
std::array<Instance2D, 2> rect_instances { Instance2D(color,Vector2(pos.x + radius, pos.y), Vector2(size.x - 2 * radius, size.y)), Instance2D(color, Vector2(pos.x, pos.y + radius), Vector2(size.x, size.y - 2 * radius)) };
|
||||
J2D::BatchFillRect(rect_instances.data(), rect_instances.size());
|
||||
J2D::BatchFillCircle(colors.data(), circle_positions.data(), circle_radii.data(), subdivisions, 4);
|
||||
|
||||
if (current_state.current_shader)
|
||||
|
@@ -97,17 +97,6 @@ namespace JGL {
|
||||
inline StateStack state_stack;
|
||||
inline Vector2i window_size;
|
||||
inline bool supports_instanced = true;
|
||||
|
||||
struct Instance {
|
||||
public:
|
||||
Vector2 position;
|
||||
Vector2 size;
|
||||
Color4 color;
|
||||
public:
|
||||
Instance(const Vector2& position, const Vector2& size, const Color4& color) : position(position), size(size), color(color) {}
|
||||
Instance() = default;
|
||||
~Instance() = default;
|
||||
};
|
||||
}
|
||||
|
||||
namespace JGL::J2D {
|
||||
|
@@ -67,7 +67,6 @@ size_t JGL::VRamList::Size() const {
|
||||
|
||||
void JGL::VRamList::SetData(void* data, const long& length) {
|
||||
|
||||
|
||||
bool should_resize = (this->byte_count != length * 4);
|
||||
if (should_resize) {
|
||||
glDeleteBuffers(1, &list_handle);
|
||||
@@ -89,12 +88,8 @@ void JGL::VRamList::SetData(void* data, const long& length) {
|
||||
|
||||
size_t element_size = element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat);
|
||||
|
||||
if (usage_hint != Fixed)
|
||||
glBufferData(GL_ARRAY_BUFFER, length * element_size, nullptr, usage_hint);
|
||||
glBufferSubData(buffer_type, 0, length * element_size, data);
|
||||
|
||||
glBindBuffer(buffer_type, current_buffer);
|
||||
|
||||
}
|
||||
|
||||
void JGL::VRamList::UpdateData(void* data, const long& offset, const long& length) {
|
||||
|
Reference in New Issue
Block a user