Merge pull request #10950 from samcake/hobbes

add custom shape pipeline, use for Polyvox and Particle system entities
This commit is contained in:
Andrew Meadows 2017-07-13 10:16:46 -07:00 committed by GitHub
commit 01bbd8d89d
12 changed files with 214 additions and 171 deletions

View file

@ -13,14 +13,13 @@
#include <DependencyManager.h>
#include <PerfStat.h>
#include <GeometryCache.h>
#include <render/ShapePipeline.h>
#include <StencilMaskPass.h>
#include <AbstractViewStateInterface.h>
#include "EntitiesRendererLogging.h"
#include "RenderableParticleEffectEntityItem.h"
#include "untextured_particle_vert.h"
#include "untextured_particle_frag.h"
#include "textured_particle_vert.h"
#include "textured_particle_frag.h"
@ -29,6 +28,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 void registerShapePipeline() {
if (!CUSTOM_PIPELINE_NUMBER) {
CUSTOM_PIPELINE_NUMBER = render::ShapePipeline::registerCustomShapePipelineFactory(shapePipelineFactory);
}
}
static std::weak_ptr<gpu::Pipeline> _texturedPipeline;
template<typename T>
struct InterpolationData {
T start;
@ -70,9 +79,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 +96,15 @@ 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);
@ -113,7 +119,6 @@ public:
protected:
Transform _modelTransform;
AABox _bound;
PipelinePointer _pipeline;
FormatPointer _vertexFormat { std::make_shared<Format>() };
BufferPointer _particleBuffer { std::make_shared<Buffer>() };
BufferView _uniformBuffer;
@ -142,23 +147,49 @@ namespace render {
payload->render(args);
}
}
template <>
const ShapeKey shapeGetShapeKey(const ParticlePayloadData::Pointer& payload) {
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,
@ -167,7 +198,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);
@ -276,47 +306,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;

View file

@ -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;
};

View file

@ -59,12 +59,8 @@
#include "EntityEditPacketSender.h"
#include "PhysicalEntitySimulation.h"
gpu::PipelinePointer RenderablePolyVoxEntityItem::_pipeline = nullptr;
gpu::PipelinePointer RenderablePolyVoxEntityItem::_wireframePipeline = nullptr;
const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5;
/*
A PolyVoxEntity has several interdependent parts:
@ -116,6 +112,10 @@ EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entit
EntityItemPointer entity{ new RenderablePolyVoxEntityItem(entityID) };
entity->setProperties(properties);
std::static_pointer_cast<RenderablePolyVoxEntityItem>(entity)->initializePolyVox();
// As we create the first Polyvox entity, let's register its special shapePipeline factory:
PolyVoxPayload::registerShapePipeline();
return entity;
}
@ -732,35 +732,6 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
!mesh->getIndexBuffer()._buffer) {
return;
}
if (!_pipeline) {
gpu::ShaderPointer vertexShader = gpu::Shader::createVertex(std::string(polyvox_vert));
gpu::ShaderPointer pixelShader = gpu::Shader::createPixel(std::string(polyvox_frag));
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("xMap"), 0));
slotBindings.insert(gpu::Shader::Binding(std::string("yMap"), 1));
slotBindings.insert(gpu::Shader::Binding(std::string("zMap"), 2));
gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader);
gpu::Shader::makeProgram(*program, slotBindings);
auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, true, gpu::LESS_EQUAL);
PrepareStencil::testMaskDrawShape(*state);
_pipeline = gpu::Pipeline::create(program, state);
auto wireframeState = std::make_shared<gpu::State>();
wireframeState->setCullMode(gpu::State::CULL_BACK);
wireframeState->setDepthTest(true, true, gpu::LESS_EQUAL);
wireframeState->setFillMode(gpu::State::FILL_LINE);
PrepareStencil::testMaskDrawShape(*wireframeState);
_wireframePipeline = gpu::Pipeline::create(program, wireframeState);
}
if (!_vertexFormat) {
auto vf = std::make_shared<gpu::Stream::Format>();
@ -771,11 +742,6 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
gpu::Batch& batch = *args->_batch;
// Pick correct Pipeline
bool wireframe = (render::ShapeKey(args->_globalShapeKey).isWireframe());
auto pipeline = (wireframe ? _wireframePipeline : _pipeline);
batch.setPipeline(pipeline);
Transform transform(voxelToWorldMatrix());
batch.setModelTransform(transform);
batch.setInputFormat(_vertexFormat);
@ -817,7 +783,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
batch.setResourceTexture(2, DependencyManager::get<TextureCache>()->getWhiteTexture());
}
int voxelVolumeSizeLocation = pipeline->getProgram()->getUniforms().findLocation("voxelVolumeSize");
int voxelVolumeSizeLocation = args->_shapePipeline->pipeline->getProgram()->getUniforms().findLocation("voxelVolumeSize");
batch._glUniform3f(voxelVolumeSizeLocation, voxelVolumeSize.x, voxelVolumeSize.y, voxelVolumeSize.z);
batch.drawIndexed(gpu::TRIANGLES, (gpu::uint32)mesh->getNumIndices(), 0);
@ -848,6 +814,48 @@ void RenderablePolyVoxEntityItem::removeFromScene(const EntityItemPointer& self,
render::Item::clearID(_myItem);
}
uint8_t PolyVoxPayload::CUSTOM_PIPELINE_NUMBER = 0;
std::shared_ptr<gpu::Pipeline> PolyVoxPayload::_pipeline;
std::shared_ptr<gpu::Pipeline> PolyVoxPayload::_wireframePipeline;
render::ShapePipelinePointer PolyVoxPayload::shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key) {
if (!_pipeline) {
gpu::ShaderPointer vertexShader = gpu::Shader::createVertex(std::string(polyvox_vert));
gpu::ShaderPointer pixelShader = gpu::Shader::createPixel(std::string(polyvox_frag));
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), PolyVoxPayload::MATERIAL_GPU_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("xMap"), 0));
slotBindings.insert(gpu::Shader::Binding(std::string("yMap"), 1));
slotBindings.insert(gpu::Shader::Binding(std::string("zMap"), 2));
gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader);
gpu::Shader::makeProgram(*program, slotBindings);
auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, true, gpu::LESS_EQUAL);
PrepareStencil::testMaskDrawShape(*state);
_pipeline = gpu::Pipeline::create(program, state);
auto wireframeState = std::make_shared<gpu::State>();
wireframeState->setCullMode(gpu::State::CULL_BACK);
wireframeState->setDepthTest(true, true, gpu::LESS_EQUAL);
wireframeState->setFillMode(gpu::State::FILL_LINE);
PrepareStencil::testMaskDrawShape(*wireframeState);
_wireframePipeline = gpu::Pipeline::create(program, wireframeState);
}
if (key.isWireframe()) {
return std::make_shared<render::ShapePipeline>(_wireframePipeline, nullptr, nullptr, nullptr);
} else {
return std::make_shared<render::ShapePipeline>(_pipeline, nullptr, nullptr, nullptr);
}
}
namespace render {
template <> const ItemKey payloadGetKey(const PolyVoxPayload::Pointer& payload) {
return ItemKey::Builder::opaqueShape();
@ -871,6 +879,10 @@ namespace render {
payload->_owner->getRenderableInterface()->render(args);
}
}
template <> const ShapeKey shapeGetShapeKey(const PolyVoxPayload::Pointer& payload) {
return ShapeKey::Builder().withCustom(PolyVoxPayload::CUSTOM_PIPELINE_NUMBER).build();
}
}
@ -1619,7 +1631,7 @@ void RenderablePolyVoxEntityItem::bonkNeighbors() {
void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) {
EntityItem::locationChanged(tellPhysics);
if (!_pipeline || !render::Item::isValidID(_myItem)) {
if (!render::Item::isValidID(_myItem)) {
return;
}
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();

View file

@ -28,6 +28,19 @@
class PolyVoxPayload {
public:
static uint8_t CUSTOM_PIPELINE_NUMBER;
static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key);
static void registerShapePipeline() {
if (!CUSTOM_PIPELINE_NUMBER) {
CUSTOM_PIPELINE_NUMBER = render::ShapePipeline::registerCustomShapePipelineFactory(shapePipelineFactory);
}
}
static const int MATERIAL_GPU_SLOT = 3;
static std::shared_ptr<gpu::Pipeline> _pipeline;
static std::shared_ptr<gpu::Pipeline> _wireframePipeline;
PolyVoxPayload(EntityItemPointer owner) : _owner(owner), _bounds(AABox()) { }
typedef render::Payload<PolyVoxPayload> Payload;
typedef Payload::DataPointer Pointer;
@ -40,6 +53,7 @@ namespace render {
template <> const ItemKey payloadGetKey(const PolyVoxPayload::Pointer& payload);
template <> const Item::Bound payloadGetBound(const PolyVoxPayload::Pointer& payload);
template <> void payloadRender(const PolyVoxPayload::Pointer& payload, RenderArgs* args);
template <> const ShapeKey shapeGetShapeKey(const PolyVoxPayload::Pointer& payload);
}
@ -168,10 +182,7 @@ private:
NetworkTexturePointer _yTexture;
NetworkTexturePointer _zTexture;
const int MATERIAL_GPU_SLOT = 3;
render::ItemID _myItem{ render::Item::INVALID_ITEM_ID };
static gpu::PipelinePointer _pipeline;
static gpu::PipelinePointer _wireframePipeline;
ShapeInfo _shapeInfo;

View file

@ -1,18 +0,0 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
// fragment shader
//
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
in vec4 _color;
out vec4 outFragColor;
void main(void) {
outFragColor = _color;
}

View file

@ -1,25 +0,0 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// particle vertex shader
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Inputs.slh@>
<@include gpu/Color.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
out vec4 _color;
void main(void) {
// pass along the color
_color = colorToLinearRGBA(inColor);
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
}

View file

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

View file

@ -29,6 +29,7 @@
#include "gpu/StandardShaderLib.h"
#include "model/TextureMap.h"
#include "render/Args.h"
#include "standardTransformPNTC_vert.h"
#include "standardDrawTexture_frag.h"
@ -459,7 +460,8 @@ _nextID(0) {
// Set the defaults needed for a simple program
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
DependencyManager::get<TextureCache>()->getWhiteTexture());
}
},
nullptr
);
GeometryCache::_simpleTransparentPipeline =
std::make_shared<render::ShapePipeline>(getSimplePipeline(false, true, true, false), nullptr,
@ -467,11 +469,12 @@ _nextID(0) {
// Set the defaults needed for a simple program
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
DependencyManager::get<TextureCache>()->getWhiteTexture());
}
},
nullptr
);
GeometryCache::_simpleWirePipeline =
std::make_shared<render::ShapePipeline>(getSimplePipeline(false, false, true, true), nullptr,
[](const render::ShapePipeline&, gpu::Batch& batch, RenderArgs* args) {});
[](const render::ShapePipeline&, gpu::Batch& batch, RenderArgs* args) {}, nullptr);
}
GeometryCache::~GeometryCache() {

View file

@ -45,8 +45,9 @@ void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, cons
if (key.isValid() && !key.hasOwnPipeline()) {
args->_shapePipeline = shapeContext->pickPipeline(args, key);
if (args->_shapePipeline) {
args->_shapePipeline->prepareShapeItem(args, key, item);
item.render(args);
}
}
args->_shapePipeline = nullptr;
} else if (key.hasOwnPipeline()) {
item.render(args);
@ -110,10 +111,11 @@ void render::renderStateSortShapes(const RenderContextPointer& renderContext,
for (auto& pipelineKey : sortedPipelines) {
auto& bucket = sortedShapes[pipelineKey];
args->_shapePipeline = shapeContext->pickPipeline(args, pipelineKey);
if (!args->_shapePipeline) {
if (!args->_shapePipeline) {
continue;
}
for (auto& item : bucket) {
args->_shapePipeline->prepareShapeItem(args, pipelineKey, item);
item.render(args);
}
}

View file

@ -17,18 +17,34 @@
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);
if (_batchSetter) {
_batchSetter(*this, batch, args);
}
}
void ShapePipeline::prepareShapeItem(RenderArgs* args, const ShapeKey& key, const Item& shape) {
if (_itemSetter) {
_itemSetter(*this, args, shape);
}
}
ShapeKey::Filter::Builder::Builder() {
_mask.set(OWN_PIPELINE);
_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);
@ -48,12 +64,12 @@ void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit
}
void ShapePlumber::addPipeline(const Key& key, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
BatchSetter batchSetter) {
addPipeline(Filter{key}, program, state, batchSetter);
BatchSetter batchSetter, ItemSetter itemSetter) {
addPipeline(Filter{key}, program, state, batchSetter, itemSetter);
}
void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
BatchSetter batchSetter) {
BatchSetter batchSetter, ItemSetter itemSetter) {
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), Slot::BUFFER::LIGHTING_MODEL));
slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::BUFFER::SKINNING));
@ -90,7 +106,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
ShapeKey key{filter._flags};
auto gpuPipeline = gpu::Pipeline::create(program, state);
auto shapePipeline = std::make_shared<Pipeline>(gpuPipeline, locations, batchSetter);
auto shapePipeline = std::make_shared<Pipeline>(gpuPipeline, locations, batchSetter, itemSetter);
addPipelineHelper(filter, key, 0, shapePipeline);
}
@ -103,23 +119,34 @@ 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);
}
PipelinePointer shapePipeline(pipelineIterator->second);
auto& batch = args->_batch;
// Setup the one pipeline (to rule them all)
batch->setPipeline(shapePipeline->pipeline);
args->_batch->setPipeline(shapePipeline->pipeline);
// Run the pipeline's BatchSetter on the passed in batch
if (shapePipeline->batchSetter) {
shapePipeline->batchSetter(*shapePipeline, *batch, args);
if (shapePipeline->_batchSetter) {
shapePipeline->_batchSetter(*shapePipeline, *(args->_batch), args);
}
return shapePipeline;

View file

@ -19,6 +19,8 @@
#include "Args.h"
namespace render {
class Item;
class ShapePlumber;
class ShapeKey {
public:
@ -38,7 +40,19 @@ public:
OWN_PIPELINE,
INVALID,
CUSTOM_0,
CUSTOM_1,
CUSTOM_2,
CUSTOM_3,
CUSTOM_4,
CUSTOM_5,
CUSTOM_6,
CUSTOM_7,
NUM_FLAGS, // Not a valid flag
CUSTOM_MASK = (0xFF << CUSTOM_0),
};
using Flags = std::bitset<NUM_FLAGS>;
@ -73,6 +87,8 @@ public:
Builder& withOwnPipeline() { _flags.set(OWN_PIPELINE); return (*this); }
Builder& invalidate() { _flags.set(INVALID); return (*this); }
Builder& withCustom(uint8_t custom) { _flags &= (~CUSTOM_MASK); _flags |= (custom << CUSTOM_0); return (*this); }
static const ShapeKey ownPipeline() { return Builder().withOwnPipeline(); }
static const ShapeKey invalid() { return Builder().invalidate(); }
@ -127,6 +143,9 @@ public:
Builder& withCullFace() { _flags.reset(NO_CULL_FACE); _mask.set(NO_CULL_FACE); return (*this); }
Builder& withoutCullFace() { _flags.set(NO_CULL_FACE); _mask.set(NO_CULL_FACE); return (*this); }
Builder& withCustom(uint8_t custom) { _flags &= (~CUSTOM_MASK); _flags |= (custom << CUSTOM_0); _mask |= (CUSTOM_MASK); return (*this); }
Builder& withoutCustom() { _flags &= (~CUSTOM_MASK); _mask |= (CUSTOM_MASK); return (*this); }
protected:
friend class Filter;
Flags _flags{0};
@ -155,6 +174,9 @@ public:
bool hasOwnPipeline() const { return _flags[OWN_PIPELINE]; }
bool isValid() const { return !_flags[INVALID]; }
uint8_t getCustom() const { return (_flags.to_ulong() & CUSTOM_MASK) >> CUSTOM_0; }
bool isCustom() const { return (_flags.to_ulong() & CUSTOM_MASK); }
// Comparator for use in stl containers
class Hash {
public:
@ -240,22 +262,39 @@ public:
};
using LocationsPointer = std::shared_ptr<Locations>;
using BatchSetter = std::function<void(const ShapePipeline&, gpu::Batch&, RenderArgs* args)>;
using BatchSetter = std::function<void(const ShapePipeline&, gpu::Batch&, render::Args*)>;
ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter) :
pipeline(pipeline), locations(locations), batchSetter(batchSetter) {}
using ItemSetter = std::function<void(const ShapePipeline&, render::Args*, const render::Item&)>;
// Normally, a pipeline is accessed thorugh pickPipeline. If it needs to be set manually,
ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter, ItemSetter itemSetter) :
pipeline(pipeline),
locations(locations),
_batchSetter(batchSetter),
_itemSetter(itemSetter) {}
// Normally, a pipeline is accessed through pickPipeline. If it needs to be set manually,
// after calling setPipeline this method should be called to prepare the pipeline with default buffers.
void prepare(gpu::Batch& batch, RenderArgs* args);
void prepare(gpu::Batch& batch, Args* args);
gpu::PipelinePointer pipeline;
std::shared_ptr<Locations> locations;
void prepareShapeItem(Args* args, const ShapeKey& key, const Item& shape);
protected:
friend class ShapePlumber;
BatchSetter batchSetter;
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>;
@ -270,22 +309,24 @@ public:
using Locations = Pipeline::Locations;
using LocationsPointer = Pipeline::LocationsPointer;
using BatchSetter = Pipeline::BatchSetter;
using ItemSetter = Pipeline::ItemSetter;
void addPipeline(const Key& key, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
BatchSetter batchSetter = nullptr);
BatchSetter batchSetter = nullptr, ItemSetter itemSetter = nullptr);
void addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
BatchSetter batchSetter = nullptr);
BatchSetter batchSetter = nullptr, ItemSetter itemSetter = nullptr);
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>;
}

View file

@ -57,8 +57,6 @@
#include <render-utils/model_lightmap_specular_map_frag.h>
#include <render-utils/model_translucent_frag.h>
#include <entities-renderer/untextured_particle_frag.h>
#include <entities-renderer/untextured_particle_vert.h>
#include <entities-renderer/textured_particle_frag.h>
#include <entities-renderer/textured_particle_vert.h>
@ -172,7 +170,6 @@ void QTestWindow::draw() {
testShaderBuild(skin_model_normal_map_vert, model_translucent_frag);
testShaderBuild(model_shadow_vert, model_shadow_frag);
testShaderBuild(untextured_particle_vert, untextured_particle_frag);
testShaderBuild(textured_particle_vert, textured_particle_frag);
/* FIXME: Bring back the ssao shader tests
testShaderBuild(gaussian_blur_vertical_vert, gaussian_blur_frag);