diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 5ea8af4d7a..276ffb279f 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include "EntitiesRendererLogging.h" @@ -29,6 +30,16 @@ class ParticlePayloadData { public: 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 _texturedPipeline; + + static void registerShapePipeline() { + if (!CUSTOM_PIPELINE_NUMBER) { + ParticlePayloadData::CUSTOM_PIPELINE_NUMBER = render::ShapePipeline::registerCustomShapePipelineFactory(ParticlePayloadData::shapePipelineFactory); + } + } + template struct InterpolationData { T start; @@ -70,9 +81,6 @@ public: 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; } void setModelTransform(const Transform& modelTransform) { _modelTransform = modelTransform; } @@ -90,15 +98,16 @@ public: bool getVisibleFlag() const { return _visibleFlag; } void setVisibleFlag(bool visibleFlag) { _visibleFlag = visibleFlag; } - + void render(RenderArgs* args) const { assert(_pipeline); gpu::Batch& batch = *args->_batch; - batch.setPipeline(_pipeline); if (_texture) { batch.setResourceTexture(0, _texture); + } else { + batch.setResourceTexture(0, DependencyManager::get()->getWhiteTexture()); } batch.setModelTransform(_modelTransform); @@ -144,30 +153,47 @@ namespace render { } template <> const ShapeKey shapeGetShapeKey(const ParticlePayloadData::Pointer& payload) { - return ShapeKey::Builder().withCustom(75).build(); - } - - template <> - bool shapeDefineCustomShapePipeline(const ParticlePayloadData::Pointer& payload, ShapePlumber& plumber, const ShapeKey& key) { - return false; + return render::ShapeKey::Builder().withCustom(ParticlePayloadData::CUSTOM_PIPELINE_NUMBER).withTranslucent().build(); } } +uint8_t ParticlePayloadData::CUSTOM_PIPELINE_NUMBER = 0; +std::weak_ptr 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(); + 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(texturedPipeline, nullptr, nullptr, nullptr); +} EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { auto entity = std::make_shared(entityID); entity->setProperties(properties); + + // As we create the first ParticuleSystem entity, let s register its special shapePIpeline factory: + ParticlePayloadData::registerShapePipeline(); + return entity; } RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID) : ParticleEffectEntityItem(entityItemID) { - // lazy creation of particle system pipeline - if (!_untexturedPipeline || !_texturedPipeline) { - createPipelines(); - } } bool RenderableParticleEffectEntityItem::addToScene(const EntityItemPointer& self, @@ -176,7 +202,6 @@ bool RenderableParticleEffectEntityItem::addToScene(const EntityItemPointer& sel _scene = scene; _renderItemId = _scene->allocateID(); auto particlePayloadData = std::make_shared(); - particlePayloadData->setPipeline(_untexturedPipeline); auto renderPayload = std::make_shared(particlePayloadData); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); @@ -285,47 +310,14 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { if (_texture && _texture->isLoaded()) { payload.setTexture(_texture->getGPUTexture()); - payload.setPipeline(_texturedPipeline); } else { payload.setTexture(nullptr); - payload.setPipeline(_untexturedPipeline); } }); _scene->enqueueTransaction(transaction); } -void RenderableParticleEffectEntityItem::createPipelines() { - if (!_untexturedPipeline) { - auto state = std::make_shared(); - 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(); - 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() { if (!render::Item::isValidID(_renderItemId)) { return; diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index 678b582b41..b0d7e1c920 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -34,16 +34,13 @@ protected: virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); } virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); notifyBoundChanged(); } - void notifyBoundChanged(); + void notifyBoundChanged(); - void createPipelines(); - render::ScenePointer _scene; render::ItemID _renderItemId{ render::Item::INVALID_ITEM_ID }; NetworkTexturePointer _texture; - gpu::PipelinePointer _untexturedPipeline; - gpu::PipelinePointer _texturedPipeline; + }; diff --git a/libraries/entities-renderer/src/untextured_particle.slf b/libraries/entities-renderer/src/untextured_particle.slf index 11f25bb693..a8062f0024 100644 --- a/libraries/entities-renderer/src/untextured_particle.slf +++ b/libraries/entities-renderer/src/untextured_particle.slf @@ -9,10 +9,11 @@ // 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; void main(void) { - outFragColor = _color; + outFragColor = varColor; } diff --git a/libraries/gl/src/gl/GLShaders.cpp b/libraries/gl/src/gl/GLShaders.cpp index fd0c6788cb..8ef0198676 100644 --- a/libraries/gl/src/gl/GLShaders.cpp +++ b/libraries/gl/src/gl/GLShaders.cpp @@ -182,7 +182,6 @@ GLuint compileProgram(const std::vector& glshaders, std::string& error) filestream.close(); } */ - delete[] temp; glDeleteProgram(glprogram); return 0; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 550092c90e..f7712f59e7 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -44,13 +44,13 @@ void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, cons auto key = item.getShapeKey() | globalKey; if (key.isValid() && !key.hasOwnPipeline()) { args->_shapePipeline = shapeContext->pickPipeline(args, key); - if (!args->_shapePipeline) { + /* if (!args->_shapePipeline) { if (key.isCustom()) { if (item.defineCustomShapePipeline(*shapeContext, key)) { args->_shapePipeline = shapeContext->pickPipeline(args, key); } } - } + }*/ if (args->_shapePipeline) { args->_shapePipeline->prepareShapeItem(args, key, item); item.render(args); @@ -119,7 +119,7 @@ void render::renderStateSortShapes(const RenderContextPointer& renderContext, auto& bucket = sortedShapes[pipelineKey]; args->_shapePipeline = shapeContext->pickPipeline(args, pipelineKey); if (!args->_shapePipeline) { - if (pipelineKey.isCustom()) { + /* if (pipelineKey.isCustom()) { if (bucket.front().defineCustomShapePipeline(*shapeContext, pipelineKey)) { args->_shapePipeline = shapeContext->pickPipeline(args, pipelineKey); if (!args->_shapePipeline) { @@ -130,7 +130,7 @@ void render::renderStateSortShapes(const RenderContextPointer& renderContext, } else { continue; } - } + }*/ continue; } for (auto& item : bucket) { diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 8ec80a7d7e..007b34395d 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -320,7 +320,6 @@ public: virtual void render(RenderArgs* args) = 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; @@ -370,7 +369,6 @@ public: // Shape Type Interface const ShapeKey getShapeKey() const { return _payload->getShapeKey(); } - bool defineCustomShapePipeline(ShapePlumber& plumber, const ShapeKey& key) const { return _payload->defineCustomShapePipeline(plumber, key); } // Meta Type Interface uint32_t fetchMetaSubItems(ItemIDs& subItems) const { return _payload->fetchMetaSubItems(subItems); } @@ -417,7 +415,6 @@ template void payloadRender(const std::shared_ptr& payloadData, Ren // 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. template const ShapeKey shapeGetShapeKey(const std::shared_ptr& payloadData) { return ShapeKey::Builder::ownPipeline(); } -template bool shapeDefineCustomShapePipeline(const std::shared_ptr& payloadData, ShapePlumber& plumber, const ShapeKey& key) { return false; } // Meta Type Interface // Meta items act as the grouping object for several sub items (typically shapes). @@ -444,7 +441,6 @@ public: // Shape Type interface virtual const ShapeKey getShapeKey() const override { return shapeGetShapeKey(_data); } - virtual bool defineCustomShapePipeline(ShapePlumber& plumber, const ShapeKey& key) const override { return shapeDefineCustomShapePipeline(_data, plumber, key); } // Meta Type Interface virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const override { return metaFetchMetaSubItems(_data, subItems); } diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index ba506699b2..c83c0b44fc 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -17,6 +17,15 @@ 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) { if (_batchSetter) { _batchSetter(*this, batch, args); @@ -35,7 +44,7 @@ ShapeKey::Filter::Builder::Builder() { _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 if (bit < (int)ShapeKey::FlagBit::NUM_FLAGS) { addPipelineHelper(filter, key, bit + 1, pipeline); @@ -110,10 +119,22 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke const auto& pipelineIterator = _pipelineMap.find(key); 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()) { - _missingKeys.insert(key); - qCDebug(renderlogging) << "Couldn't find a pipeline for" << key; + if (key.isCustom()) { + 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); } diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index afc0eac011..3951e41e44 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -285,6 +285,15 @@ protected: BatchSetter _batchSetter; ItemSetter _itemSetter; +public: + using CustomKey = uint8_t; + using CustomFactory = std::function (const ShapePlumber& plumber, const ShapeKey& key)>; + using CustomFactoryMap = std::map; + + static CustomFactoryMap _globalCustomFactoryMap; + + static CustomKey registerCustomShapePipelineFactory(CustomFactory factory); + }; using ShapePipelinePointer = std::shared_ptr; @@ -309,13 +318,14 @@ public: const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const; protected: - void addPipelineHelper(const Filter& filter, Key key, int bit, const PipelinePointer& pipeline); - PipelineMap _pipelineMap; + void addPipelineHelper(const Filter& filter, Key key, int bit, const PipelinePointer& pipeline) const; + mutable PipelineMap _pipelineMap; private: mutable std::unordered_set _missingKeys; }; + using ShapePlumberPointer = std::shared_ptr; }