Merge pull request #5539 from jherico/homer

Breaking up transfers and draw calls
This commit is contained in:
samcake 2015-08-11 12:12:48 -07:00
commit 0a8a43f8bd
4 changed files with 159 additions and 53 deletions

View file

@ -11,6 +11,8 @@
#include "GLBackendShared.h" #include "GLBackendShared.h"
#include <mutex> #include <mutex>
#include <queue>
#include <list>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
using namespace gpu; using namespace gpu;
@ -105,10 +107,10 @@ Backend* GLBackend::createBackend() {
GLBackend::GLBackend() : GLBackend::GLBackend() :
_input(), _input(),
_transform(),
_pipeline(), _pipeline(),
_output() _output()
{ {
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uboAlignment);
initInput(); initInput();
initTransform(); initTransform();
} }
@ -120,18 +122,99 @@ GLBackend::~GLBackend() {
killTransform(); killTransform();
} }
void GLBackend::render(Batch& batch) { void GLBackend::renderPassTransfer(Batch& batch) {
const size_t numCommands = batch.getCommands().size();
uint32 numCommands = batch.getCommands().size();
const Batch::Commands::value_type* command = batch.getCommands().data(); const Batch::Commands::value_type* command = batch.getCommands().data();
const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data(); const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data();
for (unsigned int i = 0; i < numCommands; i++) { _transform._cameraTransforms.resize(0);
CommandCall call = _commandCalls[(*command)]; _transform._cameraTransforms.push_back(TransformCamera());
(this->*(call))(batch, *offset); _transform._cameraOffsets.clear();
_transform._cameraOffsets.push_back(TransformStageState::Pair(0, 0));
_transform._objectTransforms.push_back(TransformObject());
_transform._objectOffsets.push_back(TransformStageState::Pair(0, 0));
_transform._objectOffsets.clear();
_transform._objectTransforms.resize(0);
_commandIndex = 0;
preUpdateTransform();
int drawCount = 0;
for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) {
switch (*command) {
case Batch::COMMAND_draw:
case Batch::COMMAND_drawIndexed:
case Batch::COMMAND_drawInstanced:
case Batch::COMMAND_drawIndexedInstanced:
preUpdateTransform();
++drawCount;
break;
case Batch::COMMAND_setModelTransform:
case Batch::COMMAND_setViewportTransform:
case Batch::COMMAND_setViewTransform:
case Batch::COMMAND_setProjectionTransform:
{
CommandCall call = _commandCalls[(*command)];
(this->*(call))(batch, *offset);
}
break;
default:
break;
}
command++; command++;
offset++; offset++;
} }
static QByteArray bufferData;
glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformCameraBuffer);
bufferData.resize(_transform._cameraUboSize * _transform._cameraTransforms.size());
for (size_t i = 0; i < _transform._cameraTransforms.size(); ++i) {
memcpy(bufferData.data() + (_transform._cameraUboSize * i), &_transform._cameraTransforms[i], sizeof(TransformCamera));
}
glBufferData(GL_UNIFORM_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformObjectBuffer);
bufferData.resize(_transform._objectUboSize * _transform._objectTransforms.size());
for (size_t i = 0; i < _transform._objectTransforms.size(); ++i) {
memcpy(bufferData.data() + (_transform._objectUboSize * i), &_transform._objectTransforms[i], sizeof(TransformObject));
}
glBufferData(GL_UNIFORM_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
CHECK_GL_ERROR();
}
void GLBackend::renderPassDraw(Batch& batch) {
const size_t numCommands = batch.getCommands().size();
const Batch::Commands::value_type* command = batch.getCommands().data();
const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data();
for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) {
switch (*command) {
// Ignore these commands on this pass, taken care of in the transfer pass
case Batch::COMMAND_setModelTransform:
case Batch::COMMAND_setViewportTransform:
case Batch::COMMAND_setViewTransform:
case Batch::COMMAND_setProjectionTransform:
break;
default:
{
CommandCall call = _commandCalls[(*command)];
(this->*(call))(batch, *offset);
}
break;
}
command++;
offset++;
}
}
void GLBackend::render(Batch& batch) {
renderPassTransfer(batch);
renderPassDraw(batch);
} }
bool GLBackend::checkGLError(const char* name) { bool GLBackend::checkGLError(const char* name) {

View file

@ -14,6 +14,9 @@
#include <assert.h> #include <assert.h>
#include <functional> #include <functional>
#include <bitset> #include <bitset>
#include <queue>
#include <utility>
#include <list>
#include "GPUConfig.h" #include "GPUConfig.h"
@ -239,6 +242,9 @@ public:
void getStats(Stats& stats) const { stats = _stats; } void getStats(Stats& stats) const { stats = _stats; }
protected: protected:
void renderPassTransfer(Batch& batch);
void renderPassDraw(Batch& batch);
Stats _stats; Stats _stats;
// Draw Stage // Draw Stage
@ -305,34 +311,36 @@ protected:
// Synchronize the state cache of this Backend with the actual real state of the GL Context // Synchronize the state cache of this Backend with the actual real state of the GL Context
void syncTransformStateCache(); void syncTransformStateCache();
void updateTransform(); void updateTransform();
void preUpdateTransform();
void resetTransformStage(); void resetTransformStage();
struct TransformStageState { struct TransformStageState {
TransformObject _transformObject; TransformObject _transformObject;
TransformCamera _transformCamera; TransformCamera _transformCamera;
GLuint _transformObjectBuffer;
GLuint _transformCameraBuffer; std::vector<TransformObject> _objectTransforms;
std::vector<TransformCamera> _cameraTransforms;
size_t _cameraUboSize{ 0 };
size_t _objectUboSize{ 0 };
GLuint _transformObjectBuffer{ 0 };
GLuint _transformCameraBuffer{ 0 };
Transform _model; Transform _model;
Transform _view; Transform _view;
Mat4 _projection; Mat4 _projection;
Vec4i _viewport; Vec4i _viewport{ 0, 0, 1, 1 };
bool _invalidModel; bool _invalidModel{true};
bool _invalidView; bool _invalidView{false};
bool _invalidProj; bool _invalidProj{false};
bool _invalidViewport; bool _invalidViewport{ false };
TransformStageState() : using Pair = std::pair<size_t, size_t>;
_transformObjectBuffer(0), using List = std::list<Pair>;
_transformCameraBuffer(0), List _cameraOffsets;
_model(), List _objectOffsets;
_view(),
_projection(),
_viewport(0,0,1,1),
_invalidModel(true),
_invalidView(true),
_invalidProj(false),
_invalidViewport(false) {}
} _transform; } _transform;
int32_t _uboAlignment{ 0 };
// Uniform Stage // Uniform Stage
void do_setUniformBuffer(Batch& batch, uint32 paramOffset); void do_setUniformBuffer(Batch& batch, uint32 paramOffset);
@ -359,6 +367,7 @@ protected:
{} {}
} _resource; } _resource;
size_t _commandIndex{ 0 };
// Pipeline Stage // Pipeline Stage
void do_setPipeline(Batch& batch, uint32 paramOffset); void do_setPipeline(Batch& batch, uint32 paramOffset);

View file

@ -43,14 +43,14 @@ void GLBackend::do_setViewportTransform(Batch& batch, uint32 paramOffset) {
void GLBackend::initTransform() { void GLBackend::initTransform() {
glGenBuffers(1, &_transform._transformObjectBuffer); glGenBuffers(1, &_transform._transformObjectBuffer);
glGenBuffers(1, &_transform._transformCameraBuffer); glGenBuffers(1, &_transform._transformCameraBuffer);
size_t cameraSize = sizeof(TransformCamera);
glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformObjectBuffer); while (_transform._cameraUboSize < cameraSize) {
glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW); _transform._cameraUboSize += _uboAlignment;
}
glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformCameraBuffer); size_t objectSize = sizeof(TransformObject);
glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW); while (_transform._objectUboSize < objectSize) {
_transform._objectUboSize += _uboAlignment;
glBindBuffer(GL_UNIFORM_BUFFER, 0); }
} }
void GLBackend::killTransform() { void GLBackend::killTransform() {
@ -72,7 +72,7 @@ void GLBackend::syncTransformStateCache() {
_transform._model.setIdentity(); _transform._model.setIdentity();
} }
void GLBackend::updateTransform() { void GLBackend::preUpdateTransform() {
// Check all the dirty flags and update the state accordingly // Check all the dirty flags and update the state accordingly
if (_transform._invalidViewport) { if (_transform._invalidViewport) {
_transform._transformCamera._viewport = glm::vec4(_transform._viewport); _transform._transformCamera._viewport = glm::vec4(_transform._viewport);
@ -98,33 +98,47 @@ void GLBackend::updateTransform() {
viewUntranslated[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f); viewUntranslated[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
_transform._transformCamera._projectionViewUntranslated = _transform._transformCamera._projection * viewUntranslated; _transform._transformCamera._projectionViewUntranslated = _transform._transformCamera._projection * viewUntranslated;
} }
// TODO: WE need a ring buffer to do effcient dynamic updates here
// FOr now let's just do that bind and update sequence
if (_transform._invalidView || _transform._invalidProj || _transform._invalidViewport) { if (_transform._invalidView || _transform._invalidProj || _transform._invalidViewport) {
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, 0); _transform._cameraOffsets.push_back(TransformStageState::Pair(_commandIndex, _transform._cameraUboSize * _transform._cameraTransforms.size()));
glBindBuffer(GL_ARRAY_BUFFER, _transform._transformCameraBuffer); _transform._cameraTransforms.push_back(_transform._transformCamera);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(_transform._transformCamera), (const void*)&_transform._transformCamera);
glBindBuffer(GL_ARRAY_BUFFER, 0);
CHECK_GL_ERROR();
} }
if (_transform._invalidModel) { if (_transform._invalidModel) {
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, 0); _transform._objectOffsets.push_back(TransformStageState::Pair(_commandIndex, _transform._objectUboSize * _transform._objectTransforms.size()));
glBindBuffer(GL_ARRAY_BUFFER, _transform._transformObjectBuffer); _transform._objectTransforms.push_back(_transform._transformObject);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(_transform._transformObject), (const void*) &_transform._transformObject);
glBindBuffer(GL_ARRAY_BUFFER, 0);
CHECK_GL_ERROR();
} }
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._transformObjectBuffer);
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, _transform._transformCameraBuffer);
CHECK_GL_ERROR();
// Flags are clean // Flags are clean
_transform._invalidView = _transform._invalidProj = _transform._invalidModel = _transform._invalidViewport = false; _transform._invalidView = _transform._invalidProj = _transform._invalidModel = _transform._invalidViewport = false;
} }
void GLBackend::updateTransform() {
int offset = -1;
while (!_transform._objectOffsets.empty() && _commandIndex >= _transform._objectOffsets.front().first) {
offset = _transform._objectOffsets.front().second;
_transform._objectOffsets.pop_front();
}
if (offset >= 0) {
glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT,
_transform._transformObjectBuffer,
offset, sizeof(Backend::TransformObject));
}
offset = -1;
while (!_transform._cameraOffsets.empty() && _commandIndex >= _transform._cameraOffsets.front().first) {
offset = _transform._cameraOffsets.front().second;
_transform._cameraOffsets.pop_front();
}
if (offset >= 0) {
glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT,
_transform._transformCameraBuffer,
offset, sizeof(Backend::TransformObject));
}
(void)CHECK_GL_ERROR();
}
void GLBackend::resetTransformStage() { void GLBackend::resetTransformStage() {
} }

View file

@ -25,14 +25,14 @@ struct TransformCamera {
vec4 _viewport; vec4 _viewport;
}; };
uniform transformObjectBuffer { layout(std140) uniform transformObjectBuffer {
TransformObject _object; TransformObject _object;
}; };
TransformObject getTransformObject() { TransformObject getTransformObject() {
return _object; return _object;
} }
uniform transformCameraBuffer { layout(std140) uniform transformCameraBuffer {
TransformCamera _camera; TransformCamera _camera;
}; };
TransformCamera getTransformCamera() { TransformCamera getTransformCamera() {