Refining the custom shader pipeline design and registration mechanism

This commit is contained in:
Sam Gateau 2017-07-12 14:13:58 +02:00
parent 1f2f539507
commit 98cc8c0683
8 changed files with 87 additions and 71 deletions

View file

@ -13,6 +13,7 @@
#include <DependencyManager.h> #include <DependencyManager.h>
#include <PerfStat.h> #include <PerfStat.h>
#include <GeometryCache.h> #include <GeometryCache.h>
#include <render/ShapePipeline.h>
#include <StencilMaskPass.h> #include <StencilMaskPass.h>
#include <AbstractViewStateInterface.h> #include <AbstractViewStateInterface.h>
#include "EntitiesRendererLogging.h" #include "EntitiesRendererLogging.h"
@ -29,6 +30,16 @@ class ParticlePayloadData {
public: public:
static const size_t VERTEX_PER_PARTICLE = 4; static const size_t VERTEX_PER_PARTICLE = 4;
static uint8_t CUSTOM_PIPELINE_NUMBER;
static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key);
static std::weak_ptr<gpu::Pipeline> _texturedPipeline;
static void registerShapePipeline() {
if (!CUSTOM_PIPELINE_NUMBER) {
ParticlePayloadData::CUSTOM_PIPELINE_NUMBER = render::ShapePipeline::registerCustomShapePipelineFactory(ParticlePayloadData::shapePipelineFactory);
}
}
template<typename T> template<typename T>
struct InterpolationData { struct InterpolationData {
T start; T start;
@ -70,9 +81,6 @@ public:
offsetof(ParticlePrimitive, uv), gpu::Stream::PER_INSTANCE); offsetof(ParticlePrimitive, uv), gpu::Stream::PER_INSTANCE);
} }
void setPipeline(PipelinePointer pipeline) { _pipeline = pipeline; }
const PipelinePointer& getPipeline() const { return _pipeline; }
const Transform& getModelTransform() const { return _modelTransform; } const Transform& getModelTransform() const { return _modelTransform; }
void setModelTransform(const Transform& modelTransform) { _modelTransform = modelTransform; } void setModelTransform(const Transform& modelTransform) { _modelTransform = modelTransform; }
@ -90,15 +98,16 @@ public:
bool getVisibleFlag() const { return _visibleFlag; } bool getVisibleFlag() const { return _visibleFlag; }
void setVisibleFlag(bool visibleFlag) { _visibleFlag = visibleFlag; } void setVisibleFlag(bool visibleFlag) { _visibleFlag = visibleFlag; }
void render(RenderArgs* args) const { void render(RenderArgs* args) const {
assert(_pipeline); assert(_pipeline);
gpu::Batch& batch = *args->_batch; gpu::Batch& batch = *args->_batch;
batch.setPipeline(_pipeline);
if (_texture) { if (_texture) {
batch.setResourceTexture(0, _texture); batch.setResourceTexture(0, _texture);
} else {
batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
} }
batch.setModelTransform(_modelTransform); batch.setModelTransform(_modelTransform);
@ -144,30 +153,47 @@ namespace render {
} }
template <> template <>
const ShapeKey shapeGetShapeKey(const ParticlePayloadData::Pointer& payload) { const ShapeKey shapeGetShapeKey(const ParticlePayloadData::Pointer& payload) {
return ShapeKey::Builder().withCustom(75).build(); return render::ShapeKey::Builder().withCustom(ParticlePayloadData::CUSTOM_PIPELINE_NUMBER).withTranslucent().build();
}
template <>
bool shapeDefineCustomShapePipeline(const ParticlePayloadData::Pointer& payload, ShapePlumber& plumber, const ShapeKey& key) {
return false;
} }
} }
uint8_t ParticlePayloadData::CUSTOM_PIPELINE_NUMBER = 0;
std::weak_ptr<gpu::Pipeline> ParticlePayloadData::_texturedPipeline;
render::ShapePipelinePointer ParticlePayloadData::shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key) {
auto texturedPipeline = _texturedPipeline.lock();
if (!texturedPipeline) {
auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, false, gpu::LESS_EQUAL);
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMask(*state);
auto vertShader = gpu::Shader::createVertex(std::string(textured_particle_vert));
auto fragShader = gpu::Shader::createPixel(std::string(textured_particle_frag));
auto program = gpu::Shader::createProgram(vertShader, fragShader);
_texturedPipeline = texturedPipeline = gpu::Pipeline::create(program, state);
}
return std::make_shared<render::ShapePipeline>(texturedPipeline, nullptr, nullptr, nullptr);
}
EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID,
const EntityItemProperties& properties) { const EntityItemProperties& properties) {
auto entity = std::make_shared<RenderableParticleEffectEntityItem>(entityID); auto entity = std::make_shared<RenderableParticleEffectEntityItem>(entityID);
entity->setProperties(properties); entity->setProperties(properties);
// As we create the first ParticuleSystem entity, let s register its special shapePIpeline factory:
ParticlePayloadData::registerShapePipeline();
return entity; return entity;
} }
RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID) : RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID) :
ParticleEffectEntityItem(entityItemID) { ParticleEffectEntityItem(entityItemID) {
// lazy creation of particle system pipeline
if (!_untexturedPipeline || !_texturedPipeline) {
createPipelines();
}
} }
bool RenderableParticleEffectEntityItem::addToScene(const EntityItemPointer& self, bool RenderableParticleEffectEntityItem::addToScene(const EntityItemPointer& self,
@ -176,7 +202,6 @@ bool RenderableParticleEffectEntityItem::addToScene(const EntityItemPointer& sel
_scene = scene; _scene = scene;
_renderItemId = _scene->allocateID(); _renderItemId = _scene->allocateID();
auto particlePayloadData = std::make_shared<ParticlePayloadData>(); auto particlePayloadData = std::make_shared<ParticlePayloadData>();
particlePayloadData->setPipeline(_untexturedPipeline);
auto renderPayload = std::make_shared<ParticlePayloadData::Payload>(particlePayloadData); auto renderPayload = std::make_shared<ParticlePayloadData::Payload>(particlePayloadData);
render::Item::Status::Getters statusGetters; render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(getThisPointer(), statusGetters); makeEntityItemStatusGetters(getThisPointer(), statusGetters);
@ -285,47 +310,14 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
if (_texture && _texture->isLoaded()) { if (_texture && _texture->isLoaded()) {
payload.setTexture(_texture->getGPUTexture()); payload.setTexture(_texture->getGPUTexture());
payload.setPipeline(_texturedPipeline);
} else { } else {
payload.setTexture(nullptr); payload.setTexture(nullptr);
payload.setPipeline(_untexturedPipeline);
} }
}); });
_scene->enqueueTransaction(transaction); _scene->enqueueTransaction(transaction);
} }
void RenderableParticleEffectEntityItem::createPipelines() {
if (!_untexturedPipeline) {
auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, false, gpu::LESS_EQUAL);
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMask(*state);
auto vertShader = gpu::Shader::createVertex(std::string(untextured_particle_vert));
auto fragShader = gpu::Shader::createPixel(std::string(untextured_particle_frag));
auto program = gpu::Shader::createProgram(vertShader, fragShader);
_untexturedPipeline = gpu::Pipeline::create(program, state);
}
if (!_texturedPipeline) {
auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, false, gpu::LESS_EQUAL);
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMask(*state);
auto vertShader = gpu::Shader::createVertex(std::string(textured_particle_vert));
auto fragShader = gpu::Shader::createPixel(std::string(textured_particle_frag));
auto program = gpu::Shader::createProgram(vertShader, fragShader);
_texturedPipeline = gpu::Pipeline::create(program, state);
}
}
void RenderableParticleEffectEntityItem::notifyBoundChanged() { void RenderableParticleEffectEntityItem::notifyBoundChanged() {
if (!render::Item::isValidID(_renderItemId)) { if (!render::Item::isValidID(_renderItemId)) {
return; return;

View file

@ -34,16 +34,13 @@ protected:
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); } virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); }
virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); notifyBoundChanged(); } virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); notifyBoundChanged(); }
void notifyBoundChanged(); void notifyBoundChanged();
void createPipelines();
render::ScenePointer _scene; render::ScenePointer _scene;
render::ItemID _renderItemId{ render::Item::INVALID_ITEM_ID }; render::ItemID _renderItemId{ render::Item::INVALID_ITEM_ID };
NetworkTexturePointer _texture; NetworkTexturePointer _texture;
gpu::PipelinePointer _untexturedPipeline;
gpu::PipelinePointer _texturedPipeline;
}; };

View file

@ -9,10 +9,11 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
in vec4 _color; in vec4 varColor;
in vec2 varTexcoord;
out vec4 outFragColor; out vec4 outFragColor;
void main(void) { void main(void) {
outFragColor = _color; outFragColor = varColor;
} }

View file

@ -182,7 +182,6 @@ GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& error)
filestream.close(); filestream.close();
} }
*/ */
delete[] temp;
glDeleteProgram(glprogram); glDeleteProgram(glprogram);
return 0; return 0;

View file

@ -44,13 +44,13 @@ void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, cons
auto key = item.getShapeKey() | globalKey; auto key = item.getShapeKey() | globalKey;
if (key.isValid() && !key.hasOwnPipeline()) { if (key.isValid() && !key.hasOwnPipeline()) {
args->_shapePipeline = shapeContext->pickPipeline(args, key); args->_shapePipeline = shapeContext->pickPipeline(args, key);
if (!args->_shapePipeline) { /* if (!args->_shapePipeline) {
if (key.isCustom()) { if (key.isCustom()) {
if (item.defineCustomShapePipeline(*shapeContext, key)) { if (item.defineCustomShapePipeline(*shapeContext, key)) {
args->_shapePipeline = shapeContext->pickPipeline(args, key); args->_shapePipeline = shapeContext->pickPipeline(args, key);
} }
} }
} }*/
if (args->_shapePipeline) { if (args->_shapePipeline) {
args->_shapePipeline->prepareShapeItem(args, key, item); args->_shapePipeline->prepareShapeItem(args, key, item);
item.render(args); item.render(args);
@ -119,7 +119,7 @@ void render::renderStateSortShapes(const RenderContextPointer& renderContext,
auto& bucket = sortedShapes[pipelineKey]; auto& bucket = sortedShapes[pipelineKey];
args->_shapePipeline = shapeContext->pickPipeline(args, pipelineKey); args->_shapePipeline = shapeContext->pickPipeline(args, pipelineKey);
if (!args->_shapePipeline) { if (!args->_shapePipeline) {
if (pipelineKey.isCustom()) { /* if (pipelineKey.isCustom()) {
if (bucket.front().defineCustomShapePipeline(*shapeContext, pipelineKey)) { if (bucket.front().defineCustomShapePipeline(*shapeContext, pipelineKey)) {
args->_shapePipeline = shapeContext->pickPipeline(args, pipelineKey); args->_shapePipeline = shapeContext->pickPipeline(args, pipelineKey);
if (!args->_shapePipeline) { if (!args->_shapePipeline) {
@ -130,7 +130,7 @@ void render::renderStateSortShapes(const RenderContextPointer& renderContext,
} else { } else {
continue; continue;
} }
} }*/
continue; continue;
} }
for (auto& item : bucket) { for (auto& item : bucket) {

View file

@ -320,7 +320,6 @@ public:
virtual void render(RenderArgs* args) = 0; virtual void render(RenderArgs* args) = 0;
virtual const ShapeKey getShapeKey() const = 0; virtual const ShapeKey getShapeKey() const = 0;
virtual bool defineCustomShapePipeline(ShapePlumber& plumber, const ShapeKey& key) const = 0;
virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const = 0; virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const = 0;
@ -370,7 +369,6 @@ public:
// Shape Type Interface // Shape Type Interface
const ShapeKey getShapeKey() const { return _payload->getShapeKey(); } const ShapeKey getShapeKey() const { return _payload->getShapeKey(); }
bool defineCustomShapePipeline(ShapePlumber& plumber, const ShapeKey& key) const { return _payload->defineCustomShapePipeline(plumber, key); }
// Meta Type Interface // Meta Type Interface
uint32_t fetchMetaSubItems(ItemIDs& subItems) const { return _payload->fetchMetaSubItems(subItems); } uint32_t fetchMetaSubItems(ItemIDs& subItems) const { return _payload->fetchMetaSubItems(subItems); }
@ -417,7 +415,6 @@ template <class T> void payloadRender(const std::shared_ptr<T>& payloadData, Ren
// When creating a new shape payload you need to create a specialized version, or the ShapeKey will be ownPipeline, // When creating a new shape payload you need to create a specialized version, or the ShapeKey will be ownPipeline,
// implying that the shape will setup its own pipeline without the use of the ShapeKey. // implying that the shape will setup its own pipeline without the use of the ShapeKey.
template <class T> const ShapeKey shapeGetShapeKey(const std::shared_ptr<T>& payloadData) { return ShapeKey::Builder::ownPipeline(); } template <class T> const ShapeKey shapeGetShapeKey(const std::shared_ptr<T>& payloadData) { return ShapeKey::Builder::ownPipeline(); }
template <class T> bool shapeDefineCustomShapePipeline(const std::shared_ptr<T>& payloadData, ShapePlumber& plumber, const ShapeKey& key) { return false; }
// Meta Type Interface // Meta Type Interface
// Meta items act as the grouping object for several sub items (typically shapes). // Meta items act as the grouping object for several sub items (typically shapes).
@ -444,7 +441,6 @@ public:
// Shape Type interface // Shape Type interface
virtual const ShapeKey getShapeKey() const override { return shapeGetShapeKey<T>(_data); } virtual const ShapeKey getShapeKey() const override { return shapeGetShapeKey<T>(_data); }
virtual bool defineCustomShapePipeline(ShapePlumber& plumber, const ShapeKey& key) const override { return shapeDefineCustomShapePipeline<T>(_data, plumber, key); }
// Meta Type Interface // Meta Type Interface
virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const override { return metaFetchMetaSubItems<T>(_data, subItems); } virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const override { return metaFetchMetaSubItems<T>(_data, subItems); }

View file

@ -17,6 +17,15 @@
using namespace render; using namespace render;
ShapePipeline::CustomFactoryMap ShapePipeline::_globalCustomFactoryMap;
ShapePipeline::CustomKey ShapePipeline::registerCustomShapePipelineFactory(CustomFactory factory) {
ShapePipeline::CustomKey custom = (ShapePipeline::CustomKey) _globalCustomFactoryMap.size() + 1;
_globalCustomFactoryMap[custom] = factory;
return custom;
}
void ShapePipeline::prepare(gpu::Batch& batch, RenderArgs* args) { void ShapePipeline::prepare(gpu::Batch& batch, RenderArgs* args) {
if (_batchSetter) { if (_batchSetter) {
_batchSetter(*this, batch, args); _batchSetter(*this, batch, args);
@ -35,7 +44,7 @@ ShapeKey::Filter::Builder::Builder() {
_mask.set(INVALID); _mask.set(INVALID);
} }
void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit, const PipelinePointer& pipeline) { void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit, const PipelinePointer& pipeline) const {
// Iterate over all keys // Iterate over all keys
if (bit < (int)ShapeKey::FlagBit::NUM_FLAGS) { if (bit < (int)ShapeKey::FlagBit::NUM_FLAGS) {
addPipelineHelper(filter, key, bit + 1, pipeline); addPipelineHelper(filter, key, bit + 1, pipeline);
@ -110,10 +119,22 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke
const auto& pipelineIterator = _pipelineMap.find(key); const auto& pipelineIterator = _pipelineMap.find(key);
if (pipelineIterator == _pipelineMap.end()) { if (pipelineIterator == _pipelineMap.end()) {
// The first time we can't find a pipeline, we should log it // The first time we can't find a pipeline, we should try things to solve that
if (_missingKeys.find(key) == _missingKeys.end()) { if (_missingKeys.find(key) == _missingKeys.end()) {
_missingKeys.insert(key); if (key.isCustom()) {
qCDebug(renderlogging) << "Couldn't find a pipeline for" << key; auto factoryIt = ShapePipeline::_globalCustomFactoryMap.find(key.getCustom());
if ((factoryIt != ShapePipeline::_globalCustomFactoryMap.end()) && (factoryIt)->second) {
// found a factory for the custom key, can now generate a shape pipeline for this case:
addPipelineHelper(Filter(key), key, 0, (factoryIt)->second(*this, key));
return pickPipeline(args, key);
} else {
qCDebug(renderlogging) << "ShapePlumber::Couldn't find a custom pipeline factory for " << key.getCustom() << " key is: " << key;
}
}
_missingKeys.insert(key);
qCDebug(renderlogging) << "ShapePlumber::Couldn't find a pipeline for" << key;
} }
return PipelinePointer(nullptr); return PipelinePointer(nullptr);
} }

View file

@ -285,6 +285,15 @@ protected:
BatchSetter _batchSetter; BatchSetter _batchSetter;
ItemSetter _itemSetter; ItemSetter _itemSetter;
public:
using CustomKey = uint8_t;
using CustomFactory = std::function<std::shared_ptr<ShapePipeline> (const ShapePlumber& plumber, const ShapeKey& key)>;
using CustomFactoryMap = std::map<CustomKey, CustomFactory>;
static CustomFactoryMap _globalCustomFactoryMap;
static CustomKey registerCustomShapePipelineFactory(CustomFactory factory);
}; };
using ShapePipelinePointer = std::shared_ptr<ShapePipeline>; using ShapePipelinePointer = std::shared_ptr<ShapePipeline>;
@ -309,13 +318,14 @@ public:
const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const; const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const;
protected: protected:
void addPipelineHelper(const Filter& filter, Key key, int bit, const PipelinePointer& pipeline); void addPipelineHelper(const Filter& filter, Key key, int bit, const PipelinePointer& pipeline) const;
PipelineMap _pipelineMap; mutable PipelineMap _pipelineMap;
private: private:
mutable std::unordered_set<Key, Key::Hash, Key::KeyEqual> _missingKeys; mutable std::unordered_set<Key, Key::Hash, Key::KeyEqual> _missingKeys;
}; };
using ShapePlumberPointer = std::shared_ptr<ShapePlumber>; using ShapePlumberPointer = std::shared_ptr<ShapePlumber>;
} }