mirror of
https://github.com/lubosz/overte.git
synced 2025-04-14 06:46:19 +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 <PerfStat.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <render/ShapePipeline.h>
|
||||
#include <StencilMaskPass.h>
|
||||
#include <AbstractViewStateInterface.h>
|
||||
#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<gpu::Pipeline> _texturedPipeline;
|
||||
|
||||
static void registerShapePipeline() {
|
||||
if (!CUSTOM_PIPELINE_NUMBER) {
|
||||
ParticlePayloadData::CUSTOM_PIPELINE_NUMBER = render::ShapePipeline::registerCustomShapePipelineFactory(ParticlePayloadData::shapePipelineFactory);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
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<TextureCache>()->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<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,
|
||||
const EntityItemProperties& properties) {
|
||||
auto entity = std::make_shared<RenderableParticleEffectEntityItem>(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>();
|
||||
particlePayloadData->setPipeline(_untexturedPipeline);
|
||||
auto renderPayload = std::make_shared<ParticlePayloadData::Payload>(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<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() {
|
||||
if (!render::Item::isValidID(_renderItemId)) {
|
||||
return;
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -182,7 +182,6 @@ GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& error)
|
|||
filestream.close();
|
||||
}
|
||||
*/
|
||||
delete[] temp;
|
||||
|
||||
glDeleteProgram(glprogram);
|
||||
return 0;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 <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,
|
||||
// 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> bool shapeDefineCustomShapePipeline(const std::shared_ptr<T>& 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<T>(_data); }
|
||||
virtual bool defineCustomShapePipeline(ShapePlumber& plumber, const ShapeKey& key) const override { return shapeDefineCustomShapePipeline<T>(_data, plumber, key); }
|
||||
|
||||
// Meta Type Interface
|
||||
virtual uint32_t fetchMetaSubItems(ItemIDs& subItems) const override { return metaFetchMetaSubItems<T>(_data, subItems); }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -285,6 +285,15 @@ protected:
|
|||
|
||||
BatchSetter _batchSetter;
|
||||
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>;
|
||||
|
||||
|
@ -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<Key, Key::Hash, Key::KeyEqual> _missingKeys;
|
||||
};
|
||||
|
||||
|
||||
using ShapePlumberPointer = std::shared_ptr<ShapePlumber>;
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue