Skip to content

Commit

Permalink
we're getting there™
Browse files Browse the repository at this point in the history
  • Loading branch information
TurtleP committed May 1, 2024
1 parent b773a8f commit 0aced70
Show file tree
Hide file tree
Showing 24 changed files with 531 additions and 571 deletions.
1 change: 0 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,6 @@ source/modules/filesystem/wrap_Filesystem.cpp
source/modules/graphics/Graphics.cpp
source/modules/graphics/renderstate.cpp
source/modules/graphics/samplerstate.cpp
source/modules/graphics/StreamBuffer.cpp
source/modules/graphics/Shader.cpp
source/modules/graphics/Quad.cpp
source/modules/graphics/Volatile.cpp
Expand Down
216 changes: 209 additions & 7 deletions include/driver/display/Renderer.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@

#include "common/Singleton.tcc"

#include "modules/graphics/Shader.tcc"
#include "modules/graphics/renderstate.hpp"
#include "modules/graphics/vertex.hpp"

#include "driver/graphics/DrawCommand.hpp"

#include <array>
#include <vector>

#define BUFFER_OFFSET(i) ((char*)NULL + (i))

namespace love
{
Expand All @@ -21,6 +27,39 @@ namespace love
RENDERER_INFO_DEVICE
};

struct BatchedVertexData
{
Vertex* stream;
};

struct BatchedDrawState
{
Vertex* vertices;
size_t verticesSize;

StreamBuffer::MapInfo vertexMap = StreamBuffer::MapInfo();

StreamBuffer* indexBuffer;
StreamBuffer::MapInfo indexMap = StreamBuffer::MapInfo();

PrimitiveType primitiveMode = PRIMITIVE_TRIANGLES;
ShaderBase::StandardShader shader = ShaderBase::STANDARD_DEFAULT;
CommonFormat format = CommonFormat::NONE;

StrongRef<TextureBase> texture;

int vertexCount = 0;
int indexCount = 0;

bool flushing = false;
};

RendererBase() : batchedDrawState {}
{
size_t size = sizeof(uint16_t) * LOVE_UINT16_MAX;
this->batchedDrawState.indexBuffer = new StreamBuffer(BUFFERUSAGE_INDEX, size);
}

size_t getVertexCount() const
{
return this->renderCtx.vertexCount;
Expand All @@ -31,6 +70,171 @@ namespace love
return this->data;
}

BatchedVertexData requestBatchDraw(const DrawCommand& command)
{
BatchedDrawState& state = this->batchedDrawState;

bool shouldFlush = false;
bool shouldResize = false;

// clang-format off
if (command.primitiveMode != state.primitiveMode
|| command.format != state.format
|| ((command.indexMode != TRIANGLEINDEX_NONE) != (state.indexCount > 0))
|| command.texture != state.texture
|| command.shaderType != state.shader)
{
shouldFlush = true;
}
// clang-format on

int totalVertices = state.vertexCount + command.vertexCount;

if (totalVertices > LOVE_UINT16_MAX && command.indexMode != TRIANGLEINDEX_NONE)
shouldFlush = true;

int requestedIndexCount = getIndexCount(command.indexMode, command.vertexCount);
size_t requestedIndexSize = requestedIndexCount * sizeof(uint16_t);

size_t newDataSize = 0;
size_t bufferSizes[2] = { 0, 0 };

{
size_t stride = getFormatStride(command.format);
size_t dataSize = stride * totalVertices;

if (state.vertices != nullptr && dataSize > state.verticesSize)
shouldFlush = true;

if (dataSize > state.verticesSize)
{
bufferSizes[0] = std::max<size_t>(dataSize, state.verticesSize * 1.1f);
shouldResize = true;
}

newDataSize = stride * command.vertexCount;
}

if (command.indexMode != TRIANGLEINDEX_NONE)
{
size_t dataSize = (state.indexCount + requestedIndexCount) * sizeof(uint16_t);

if (state.indexMap.data != nullptr && dataSize > state.indexMap.size)
shouldFlush = true;

if (dataSize > state.indexBuffer->getUsableSize())
{
bufferSizes[1] = std::max<size_t>(dataSize, state.indexBuffer->getSize() * 2);
shouldResize = true;
}
}

if (shouldFlush || shouldResize)
{
flushBatchedDraws();

state.primitiveMode = command.primitiveMode;
state.format = command.format;
state.texture = command.texture;
state.shader = command.shaderType;
}

if (state.vertexCount == 0)
{
if (ShaderBase::isDefaultActive())
ShaderBase::attachDefault(state.shader);
}

if (shouldResize)
{
if (state.verticesSize < bufferSizes[0])
{
linearFree(state.vertices);
state.vertices = (Vertex*)linearAlloc(bufferSizes[0]);
}

if (state.indexBuffer->getSize() < bufferSizes[1])
{
state.indexBuffer->release();
state.indexBuffer = new StreamBuffer(BUFFERUSAGE_INDEX, bufferSizes[1]);
}
}

if (command.indexMode != TRIANGLEINDEX_NONE)
{
if (state.indexMap.data == nullptr)
state.indexMap = state.indexBuffer->map();

uint16_t* indices = (uint16_t*)state.indexMap.data;
fillIndices(command.indexMode, state.vertexCount, command.vertexCount, indices);

state.indexMap.data += requestedIndexSize;
}

BatchedVertexData data {};

if (newDataSize > 0)
{
if (state.vertexMap.data == nullptr)
{
const auto size = command.vertexCount * sizeof(Vertex);
state.vertexMap = StreamBuffer::MapInfo((uint8_t*)state.vertices, size);
}

data.stream = (Vertex*)state.vertexMap.data;
state.vertexMap.data += newDataSize;
}

state.vertexCount += command.vertexCount;
state.indexCount += requestedIndexCount;

return data;
}

virtual void updateUniforms() = 0;

void flushBatchedDraws()
{
BatchedDrawState& state = this->batchedDrawState;

if ((state.vertexCount == 0 && state.indexCount == 0) || state.flushing)
return;

size_t usedSizes[2] = { 0, 0 };

this->updateUniforms();

if (state.format != CommonFormat::NONE)
state.vertexMap = StreamBuffer::MapInfo();

state.flushing = true;

if (state.indexCount > 0)
{
DrawIndexedCommand command {};
command.primitiveType = state.primitiveMode;
command.indexCount = state.indexCount;
command.indexType = INDEX_UINT16;
command.indexBufferOffset = state.indexBuffer->unmap();
command.texture = nullptr;

this->draw(command);
state.indexMap = StreamBuffer::MapInfo();
}

if (usedSizes[1] > 0)
state.indexBuffer->markUsed(usedSizes[1]);

state.vertexCount = 0;
state.indexCount = 0;
state.flushing = false;
}

static void flushBatchedDrawsGlobal()
{
RendererBase<T>::getInstance().flushBatchedDraws();
}

protected:
struct ContextBase
{
Expand All @@ -43,17 +247,15 @@ namespace love

Rect scissor;
Rect viewport;

ShaderBase::StandardShader shader = ShaderBase::STANDARD_DEFAULT;
};

virtual void draw(const DrawIndexedCommand& command) = 0;

bool initialized = false;
bool inFrame = false;

Vertex* data;

struct RenderContext
{
size_t vertexCount;
size_t indexCount;
} renderCtx;
BatchedDrawState batchedDrawState;
};
} // namespace love
122 changes: 122 additions & 0 deletions include/driver/graphics/DrawCommand.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#pragma once

#include "common/Exception.hpp"

#include "modules/graphics/Shader.tcc"
#include "modules/graphics/Texture.tcc"
#include "modules/graphics/vertex.hpp"

#if defined(__3DS__)
#include <3ds.h>

#define _alloc(size) linearAlloc(size)
#define _free(ptr) linearFree(ptr)
#else
#define _alloc(size) malloc(size)
#define _free(ptr) free(ptr)
#endif

namespace love
{
class StreamBuffer final : public Object
{
public:
struct MapInfo
{
uint8_t* data = nullptr;
size_t size = 0;

MapInfo()
{}

MapInfo(uint8_t* data, size_t size) : data(data), size(size)
{}
};

StreamBuffer(BufferUsage usage, size_t size) :
usage(usage),
data(nullptr),
bufferSize(size),
frameGPUReadOffset(0)
{
this->data = (uint8_t*)_alloc(size);

if (this->data == nullptr)
throw love::Exception(E_OUT_OF_MEMORY);

std::memset(this->data, 0, size);
}

virtual ~StreamBuffer()
{
_free(this->data);
}

MapInfo map()
{
return MapInfo(this->data, this->bufferSize);
}

size_t unmap()
{
return (size_t)this->data;
}

size_t getSize() const
{
return this->bufferSize;
}

size_t getUsableSize() const
{
return this->bufferSize - this->frameGPUReadOffset;
}

BufferUsage getMode() const
{
return this->usage;
}

void markUsed(size_t)
{}

ptrdiff_t getHandle() const
{
return 0;
}

private:
BufferUsage usage;

uint8_t* data;
size_t bufferSize;

size_t frameGPUReadOffset;
};

struct DrawCommand
{
PrimitiveType primitiveMode = PRIMITIVE_TRIANGLES;
ShaderBase::StandardShader shaderType = ShaderBase::STANDARD_DEFAULT;
TriangleIndexMode indexMode = TRIANGLEINDEX_NONE;
CommonFormat format = CommonFormat::NONE;

TextureBase* texture = nullptr;
int vertexCount = 0;
};

struct DrawIndexedCommand
{
PrimitiveType primitiveType = PRIMITIVE_TRIANGLES;
int indexCount = 0;
int instanceCount = 1;

IndexDataType indexType = INDEX_UINT16;
size_t lastPosition = 0;

size_t indexBufferOffset = 0;

TextureBase* texture;
CullMode cullMode = CULL_NONE;
};
} // namespace love
Loading

0 comments on commit 0aced70

Please sign in to comment.