Batch Rendering & IndexBuffers & RendererProgram

This commit is contained in:
Light 2021-06-13 19:35:48 +04:30
parent 2f560239cb
commit a3092c476c
19 changed files with 263 additions and 52 deletions

View file

@ -24,5 +24,4 @@
#define BIT(x) 1 << x
#define LT_ENGINE_ASSERT(x, ...) { if(!(x)) { LT_ENGINE_CRITICAL(__VA_ARGS__); __debugbreak(); } }
#define LT_CLIENT_ASSERT(x, ...) { if(!(x)) { LT_CLIENT_CRITICAL(__VA_ARGS__); __debugbreak(); } }
#define LT_CLIENT_ASSERT(x, ...) { if(!(x)) { LT_CLIENT_CRITICAL(__VA_ARGS__); __debugbreak(); } }

View file

@ -41,7 +41,9 @@ namespace Light {
m_Window->PollEvents();
// Rendering
m_Window->GetGfxContext()->GetRenderer()->Draw();
m_Window->GetGfxContext()->GetRenderer()->BeginScene();
m_LayerStack.OnRender();
m_Window->GetGfxContext()->GetRenderer()->EndScene();
// Buffer updates
m_Window->GetGfxContext()->GetRenderCommand()->SwapBuffers();

View file

@ -27,12 +27,15 @@ namespace Light {
}
}
IndexBuffer* IndexBuffer::Create(unsigned int count, unsigned int* indices)
IndexBuffer* IndexBuffer::Create(unsigned int count, unsigned int* indices, void* sharedContext)
{
switch (GraphicsContext::GetGraphicsAPI())
{
case GraphicsAPI::OpenGL:
return new glIndexBuffer(count, indices);
case GraphicsAPI::DirectX: LT_WIN(
return new dxIndexBuffer(count, indices, sharedContext);
)
default:
LT_ENGINE_ASSERT(false, "IndexBuffer::Create: invalid/unsupported GraphicsAPI {}", GraphicsContext::GetGraphicsAPI());
return nullptr;

View file

@ -9,6 +9,9 @@ namespace Light {
public:
static VertexBuffer* Create(unsigned int stride, unsigned int count, float* vertices, void* sharedContext);
virtual void* Map() = 0;
virtual void UnMap() = 0;
virtual void Bind() = 0;
virtual void UnBind() = 0;
@ -19,7 +22,7 @@ namespace Light {
class IndexBuffer
{
public:
static IndexBuffer* Create(unsigned int count, unsigned int* indices);
static IndexBuffer* Create(unsigned int count, unsigned int* indices, void* sharedContext);
virtual void Bind() = 0;
virtual void UnBind() = 0;

View file

@ -7,24 +7,36 @@
namespace Light {
Renderer* Renderer::m_Context;
Renderer* Renderer::s_Context;
Renderer::Renderer(std::shared_ptr<RenderCommand> renderCommand, void* sharedContext)
: m_RenderCommand(renderCommand), m_SharedContext(sharedContext)
{
m_Context = this;
s_Context = this;
m_Shader = std::unique_ptr<Shader>(Shader::Create("res/vertex.vertex", "res/fragment.fragment", m_SharedContext));
// QUADRENDERER //
unsigned int offset = 0;
unsigned int* indices = new unsigned int[LT_MAX_QUAD * 6];
float vertices[] =
for (int i = 0; i < LT_MAX_QUAD * 6; i += 6)
{
0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f,
};
indices[i + 0] = offset + 0;
indices[i + 1] = offset + 1;
indices[i + 2] = offset + 2;
m_VertexBuffer = std::unique_ptr<VertexBuffer>(VertexBuffer::Create(6 * sizeof(float), (2 + 4) * 3, vertices, m_SharedContext));
m_VertexLayout = std::unique_ptr<VertexLayout>(VertexLayout::Create(m_VertexBuffer.get(), m_Shader.get(), { { "POSITION", VertexElementType::Float2 },{ "COLOR", VertexElementType::Float4 } }, m_SharedContext));
indices[i + 3] = offset + 2;
indices[i + 4] = offset + 3;
indices[i + 5] = offset + 0;
offset += 4;
}
m_QuadRenderer.shader = std::unique_ptr<Shader>(Shader::Create("res/vertex.vertex", "res/fragment.fragment", m_SharedContext));
m_QuadRenderer.vertexBuffer = std::unique_ptr<VertexBuffer>(VertexBuffer::Create(sizeof(QuadRendererProgram::QuadVertexData), LT_MAX_QUAD * 4, nullptr, m_SharedContext));
m_QuadRenderer.vertexLayout = std::unique_ptr<VertexLayout>(VertexLayout::Create(m_QuadRenderer.vertexBuffer.get(), m_QuadRenderer.shader.get(), { { "POSITION", VertexElementType::Float3 },{ "COLOR", VertexElementType::Float4 } }, m_SharedContext));
m_QuadRenderer.indexBuffer = std::unique_ptr<IndexBuffer>(IndexBuffer::Create(LT_MAX_QUAD * 6, indices, m_SharedContext));
delete[] indices;
// QUADRENDERER //
}
Renderer* Renderer::Create(std::shared_ptr<RenderCommand> renderCommand, void* sharedContext)
@ -32,14 +44,63 @@ namespace Light {
return new Renderer(renderCommand, sharedContext);
}
void Renderer::Draw()
void Renderer::DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& tint)
{
m_Shader->Bind();
m_VertexBuffer->Bind();
m_VertexLayout->Bind();
s_Context->DrawQuadImpl(position, size, tint);
}
m_RenderCommand->Draw(3u);
void Renderer::DrawQuadImpl(const glm::vec3& position, const glm::vec2& size, const glm::vec4& tint)
{
// check
if (m_QuadRenderer.mapCurrent + 4 >= m_QuadRenderer.mapEnd)
{
LT_ENGINE_WARN("Render::DrawQuad: max calls per frame exceeded the limit: {}", LT_MAX_QUAD);
EndScene();
m_QuadRenderer.Map();
}
// local
const float xMin = position.x;
const float yMin = position.y;
const float xMax = position.x + size.x;
const float yMax = position.y + size.y;
// TOP LEFT
m_QuadRenderer.mapCurrent->position = { xMin, yMin, position.z };
m_QuadRenderer.mapCurrent->tint = glm::vec4(1.0f, 0.1f, 0.1f, 1.0f);
m_QuadRenderer.mapCurrent++;
// TOP RIGHT
m_QuadRenderer.mapCurrent->position = { xMax, yMin, position.z };
m_QuadRenderer.mapCurrent->tint = glm::vec4(0.1f, 1.0f, 0.1f, 1.0f);
m_QuadRenderer.mapCurrent++;
// BOTTOM RIGHT
m_QuadRenderer.mapCurrent->position = { xMax, yMax, position.z };
m_QuadRenderer.mapCurrent->tint = glm::vec4(0.3f, 0.3f, 0.3f, 1.0f);
m_QuadRenderer.mapCurrent++;
// BOTTOM LEFT
m_QuadRenderer.mapCurrent->position = { xMin, yMax, position.z };
m_QuadRenderer.mapCurrent->tint = glm::vec4(0.1f, 0.1f, 1.0f, 1.0f);
m_QuadRenderer.mapCurrent++;
// advance
m_QuadRenderer.quadCount++;
}
void Renderer::BeginScene()
{
m_QuadRenderer.Map();
}
void Renderer::EndScene()
{
m_QuadRenderer.Bind();
m_RenderCommand->DrawIndexed(m_QuadRenderer.quadCount * 6);
m_QuadRenderer.quadCount = 0;
}
}

View file

@ -6,31 +6,80 @@
#include "Buffers.h"
#include "VertexLayout.h"
#include <glm/glm.hpp>
#include <memory>
#define LT_MAX_QUAD 124
namespace Light {
class RenderCommand;
struct RendererProgram
{
virtual void Map() = 0;
virtual void Bind() = 0;
};
class Renderer
{
private:
static Renderer* m_Context;
struct QuadRendererProgram : RendererProgram
{
// graphics context
std::shared_ptr<Shader> shader;
std::shared_ptr<VertexLayout> vertexLayout;
std::shared_ptr<VertexBuffer> vertexBuffer;
std::shared_ptr<IndexBuffer> indexBuffer;
// buffer data
struct QuadVertexData
{
glm::vec3 position;
glm::vec4 tint;
};
QuadVertexData* mapCurrent = nullptr;
QuadVertexData* mapEnd = nullptr;
unsigned int quadCount = 0u;
// functions
void Map()
{
mapCurrent = (QuadVertexData*)vertexBuffer->Map();
mapEnd = mapCurrent + LT_MAX_QUAD * 4;
}
void Bind()
{
vertexBuffer->UnMap();
shader->Bind();
vertexLayout->Bind();
vertexBuffer->Bind();
indexBuffer->Bind();
}
};
static Renderer* s_Context;
QuadRendererProgram m_QuadRenderer;
std::shared_ptr<RenderCommand> m_RenderCommand;
std::unique_ptr<Shader> m_Shader;
std::unique_ptr<VertexBuffer> m_VertexBuffer;
std::unique_ptr<VertexLayout> m_VertexLayout;
void* m_SharedContext;
public:
static Renderer* Create(std::shared_ptr<RenderCommand> renderCommand, void* sharedContext);
void Draw();
static void DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& tint);
void BeginScene();
void EndScene();
private:
Renderer(std::shared_ptr<RenderCommand> renderCommand, void* sharedContext);
void DrawQuadImpl(const glm::vec3& position, const glm::vec2& size, const glm::vec4& tint);
};
}

View file

@ -33,6 +33,8 @@ namespace Light {
virtual void OnUpdate(float deltaTime) {}
virtual void OnUserInterfaceUpdate() {}
virtual void OnRender() {}
// Mouse events
virtual bool OnMouseMoved(const MouseMovedEvent& event) { return false; }
virtual bool OnButtonPressed(const ButtonPressedEvent& event) { return false; }

View file

@ -35,6 +35,12 @@ namespace Light {
(*it)->OnUserInterfaceUpdate();
}
void LayerStack::OnRender()
{
for (auto it = m_Begin; it != m_End; it++)
(*it)->OnRender();
}
void LayerStack::OnEvent(const Event& event)
{
switch (event.GetEventType())

View file

@ -30,6 +30,8 @@ namespace Light {
void OnUpdate(float deltaTime);
void OnUserInterfaceUpdate();
void OnRender();
void OnEvent(const Event& event);
inline bool IsEmpty() { return m_Layers.empty(); }

View file

@ -17,8 +17,6 @@ namespace Light {
m_DeviceContext = dxContext->deviceContext;
D3D11_BUFFER_DESC desc = { 0 };
D3D11_SUBRESOURCE_DATA sd = { 0 };
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
desc.Usage = D3D11_USAGE_DYNAMIC;
@ -27,15 +25,24 @@ namespace Light {
desc.ByteWidth = count * stride;
desc.StructureByteStride = stride;
sd.pSysMem = vertices;
DXC(m_Device->CreateBuffer(&desc, &sd, &m_Buffer));
DXC(m_Device->CreateBuffer(&desc, nullptr, &m_Buffer));
}
dxVertexBuffer::~dxVertexBuffer()
{
}
void* dxVertexBuffer::Map()
{
m_DeviceContext->Map(m_Buffer.Get(), NULL, D3D11_MAP_WRITE_DISCARD, NULL, &m_Map);
return m_Map.pData;
}
void dxVertexBuffer::UnMap()
{
m_DeviceContext->Unmap(m_Buffer.Get(), NULL);
}
void dxVertexBuffer::Bind()
{
static const unsigned int offset = 0u;
@ -46,4 +53,41 @@ namespace Light {
{
}
dxIndexBuffer::dxIndexBuffer(unsigned int count, unsigned int* indices, void* sharedContext)
{
HRESULT hr;
dxSharedContext* dxContext = static_cast<dxSharedContext*>(sharedContext);
LT_ENGINE_ASSERT(dxContext, "dxShader::dxShader: invalid dxContext");
m_Device = dxContext->device;
m_DeviceContext = dxContext->deviceContext;
D3D11_BUFFER_DESC bufferDesc = { 0 };
D3D11_SUBRESOURCE_DATA sd = { 0 };
bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.ByteWidth = count * sizeof(unsigned int);
bufferDesc.StructureByteStride = sizeof(unsigned int);
sd.pSysMem = indices;
DXC(m_Device->CreateBuffer(&bufferDesc, &sd, &m_Buffer));
}
dxIndexBuffer::~dxIndexBuffer()
{
}
void dxIndexBuffer::Bind()
{
m_DeviceContext->IASetIndexBuffer(m_Buffer.Get(), DXGI_FORMAT_R32_UINT, 0u);
}
void dxIndexBuffer::UnBind()
{
}
}

View file

@ -17,11 +17,31 @@ namespace Light {
Microsoft::WRL::ComPtr<ID3D11Device> m_Device;
Microsoft::WRL::ComPtr<ID3D11DeviceContext> m_DeviceContext;
D3D11_MAPPED_SUBRESOURCE m_Map;
unsigned int m_Stride;
public:
dxVertexBuffer(unsigned int count, unsigned int stride, float* vertices, void* sharedContext);
~dxVertexBuffer();
void* Map() override;
void UnMap() override;
void Bind() override;
void UnBind() override;
};
class dxIndexBuffer : public IndexBuffer
{
private:
Microsoft::WRL::ComPtr<ID3D11Buffer> m_Buffer;
Microsoft::WRL::ComPtr<ID3D11Device> m_Device;
Microsoft::WRL::ComPtr<ID3D11DeviceContext> m_DeviceContext;
public:
dxIndexBuffer(unsigned int count, unsigned int* indices, void* sharedContext);
~dxIndexBuffer();
void Bind() override;
void UnBind() override;
};

View file

@ -8,8 +8,7 @@ namespace Light {
glVertexBuffer::glVertexBuffer(unsigned int count, float* vertices)
{
glCreateBuffers(1, &m_BufferID);
glBindBuffer(GL_ARRAY_BUFFER, m_BufferID);
glBufferData(GL_ARRAY_BUFFER, count * sizeof(float), vertices, GL_STATIC_DRAW);
glNamedBufferData(m_BufferID, count * sizeof(float), vertices, GL_DYNAMIC_DRAW);
}
glVertexBuffer::~glVertexBuffer()
@ -17,6 +16,16 @@ namespace Light {
glDeleteBuffers(1, &m_BufferID);
}
void* glVertexBuffer::Map()
{
return glMapNamedBuffer(m_BufferID, GL_WRITE_ONLY);
}
void glVertexBuffer::UnMap()
{
glUnmapNamedBuffer(m_BufferID);
}
void glVertexBuffer::Bind()
{
glBindBuffer(GL_ARRAY_BUFFER, m_BufferID);
@ -30,9 +39,7 @@ namespace Light {
glIndexBuffer::glIndexBuffer(unsigned int count, unsigned int* indices)
{
glCreateBuffers(1, &m_BufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_BufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(unsigned int), indices, GL_STATIC_DRAW);
glNamedBufferData(m_BufferID, count * sizeof(unsigned int), indices, GL_STATIC_DRAW);
}
glIndexBuffer::~glIndexBuffer()

View file

@ -14,6 +14,9 @@ namespace Light {
glVertexBuffer(unsigned int count, float* vertices);
~glVertexBuffer();
void* Map() override;
void UnMap() override;
void Bind() override;
void UnBind() override;
};

View file

@ -28,7 +28,7 @@ namespace Light {
glfwSetWindowUserPointer(m_Handle, &m_EventCallback);
BindGlfwEvents();
m_GraphicsContext = std::unique_ptr<GraphicsContext>(GraphicsContext::Create(GraphicsAPI::DirectX, m_Handle));
m_GraphicsContext = std::unique_ptr<GraphicsContext>(GraphicsContext::Create(GraphicsAPI::OpenGL, m_Handle));
LT_ENGINE_ASSERT(m_GraphicsContext, "wWindow::wWindow: graphics context creation failed");
}

View file

@ -4,8 +4,8 @@ Size=400,400
Collapsed=0
[Window][Dear ImGui Demo]
Pos=-3,-1
Size=244,247
Pos=1,-3
Size=405,290
Collapsed=0
[Window][Dear ImGui Metrics/Debugger]

View file

@ -1,4 +1,10 @@
float4 main(float4 Color : COLOR) : SV_Target
#version 440 core
in vec4 fragColor;
out vec4 FragmentColor;
void main()
{
return Color;
FragmentColor = fragColor;
}

View file

@ -1,13 +1,12 @@
struct VertexOut
{
float4 Color : COLOR;
float4 Position : SV_Position;
};
#version 440 core
VertexOut main(float2 InPosition : POSITION, float4 InColor : COLOR)
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec4 a_Color;
out vec4 fragColor;
void main()
{
VertexOut vso;
vso.Position = float4(InPosition.x, InPosition.y, 0.0f, 1.0f);
vso.Color = InColor;
return vso;
gl_Position = vec4(a_Position, 1.0);
fragColor = a_Color;
}

View file

@ -1,7 +1,7 @@
#define LIGHT_ENTRY_POINT
#include <LightEngine.h>
#include "SandboxLayer.h"
#include "SandboxLayer.h"
class Sandbox : public Light::Application
{

View file

@ -5,4 +5,9 @@ class SandboxLayer : public Light::Layer
public:
SandboxLayer(const std::string& name): Light::Layer(name) {}
void OnRender() override
{
Light::Renderer::DrawQuad(glm::vec3(-0.5f, -0.5f, 0.0f), glm::vec2(1.f, 1.f), glm::vec4(1.12f, 1.41f, 1.72f, 1.0f));
}
};