mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 10:13:15 +02:00
Refining the custom shader pipeline design and registration mechanism
This commit is contained in:
parent
1f2f539507
commit
98cc8c0683
8 changed files with 87 additions and 71 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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); }
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue