Pass an explicit pipeline to render.*Instance calls

This commit is contained in:
Zach Pomerantz 2016-02-02 17:29:23 -08:00
parent 2af6c08057
commit d14ce8a9fe
8 changed files with 103 additions and 67 deletions

View file

@ -73,10 +73,12 @@ public:
BufferPointers buffers;
Function function;
DrawCallInfoBuffer drawCallInfos;
Pipeline::Pointer pipeline;
size_t count() const { return drawCallInfos.size(); }
void process(Batch& batch) {
batch.setPipeline(pipeline);
if (function) {
function(batch, *this);
}

View file

@ -494,10 +494,22 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat() {
return INSTANCED_SOLID_STREAM_FORMAT;
}
render::ShapePipelinePointer GeometryCache::_simplePipeline;
GeometryCache::GeometryCache() :
_nextID(0)
{
buildShapes();
GeometryCache::_simplePipeline =
std::make_shared<render::ShapePipeline>(getSimplePipeline(), nullptr,
[](const render::ShapePipeline&, gpu::Batch& batch) {
// Set the defaults needed for a simple program
batch.setResourceTexture(render::ShapePipeline::Slot::DIFFUSE_MAP,
DependencyManager::get<TextureCache>()->getWhiteTexture());
batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP,
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
}
);
}
GeometryCache::~GeometryCache() {
@ -1781,7 +1793,23 @@ inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) {
return a.getRaw() == b.getRaw();
}
gpu::PipelinePointer GeometryCache::getPipeline(SimpleProgramKey config) {
void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, bool emissive, bool depthBiased) {
batch.setPipeline(getSimplePipeline(textured, culled, emissive, depthBiased));
// If not textured, set a default diffuse map
if (!textured) {
batch.setResourceTexture(render::ShapePipeline::Slot::DIFFUSE_MAP,
DependencyManager::get<TextureCache>()->getWhiteTexture());
}
// Set a default normal map
batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP,
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
}
gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool culled, bool emissive, bool depthBiased) {
SimpleProgramKey config{textured, culled, emissive, depthBiased};
// Compile the shaders
static std::once_flag once;
std::call_once(once, [&]() {
auto VS = gpu::Shader::createVertex(std::string(simple_vert));
@ -1796,13 +1824,14 @@ gpu::PipelinePointer GeometryCache::getPipeline(SimpleProgramKey config) {
gpu::Shader::makeProgram(*_simpleShader, slotBindings);
gpu::Shader::makeProgram(*_emissiveShader, slotBindings);
});
// If the pipeline already exists, return it
auto it = _simplePrograms.find(config);
if (it != _simplePrograms.end()) {
return it.value();
}
// If the pipeline did not exist, make it
auto state = std::make_shared<gpu::State>();
if (config.isCulled()) {
state->setCullMode(gpu::State::CULL_BACK);
@ -1815,33 +1844,15 @@ gpu::PipelinePointer GeometryCache::getPipeline(SimpleProgramKey config) {
state->setDepthBiasSlopeScale(1.0f);
}
state->setBlendFunction(false,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader;
gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state);
_simplePrograms.insert(config, pipeline);
return pipeline;
}
gpu::PipelinePointer GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled,
bool emissive, bool depthBias) {
SimpleProgramKey config{textured, culled, emissive, depthBias};
gpu::PipelinePointer pipeline = getPipeline(config);
batch.setPipeline(pipeline);
gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader;
if (!config.isTextured()) {
// If it is not textured, bind white texture and keep using textured pipeline
batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
}
batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP,
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
return pipeline;
}
uint32_t toCompactColor(const glm::vec4& color) {
uint32_t compactColor = ((int(color.x * 255.0f) & 0xFF)) |
((int(color.y * 255.0f) & 0xFF) << 8) |
@ -1853,30 +1864,30 @@ uint32_t toCompactColor(const glm::vec4& color) {
static const size_t INSTANCE_COLOR_BUFFER = 0;
template <typename F>
void renderInstances(const std::string& name, gpu::Batch& batch, const glm::vec4& color, F f) {
void renderInstances(const std::string& name, gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline, F f) {
{
gpu::BufferPointer instanceColorBuffer = batch.getNamedBuffer(name, INSTANCE_COLOR_BUFFER);
auto compactColor = toCompactColor(color);
instanceColorBuffer->append(compactColor);
}
batch.setupNamedCalls(name, [f](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
batch.setupNamedCalls(name, [f, pipeline](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
batch.setPipeline(pipeline->get(batch));
f(batch, data);
});
}
void GeometryCache::renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color) {
void GeometryCache::renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
static const std::string INSTANCE_NAME = __FUNCTION__;
renderInstances(INSTANCE_NAME, batch, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
renderInstances(INSTANCE_NAME, batch, color, pipeline, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
DependencyManager::get<GeometryCache>()->renderShapeInstances(batch, GeometryCache::Sphere, data.count(),
data.buffers[INSTANCE_COLOR_BUFFER]);
});
}
void GeometryCache::renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& color) {
void GeometryCache::renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
static const std::string INSTANCE_NAME = __FUNCTION__;
renderInstances(INSTANCE_NAME, batch, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
renderInstances(INSTANCE_NAME, batch, color, pipeline, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
DependencyManager::get<GeometryCache>()->renderWireShapeInstances(batch, GeometryCache::Sphere, data.count(),
data.buffers[INSTANCE_COLOR_BUFFER]);
});
@ -1886,12 +1897,12 @@ void GeometryCache::renderWireSphereInstance(gpu::Batch& batch, const glm::vec4&
// available shape types, both solid and wireframes
//#define DEBUG_SHAPES
void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& color) {
void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
static const std::string INSTANCE_NAME = __FUNCTION__;
#ifdef DEBUG_SHAPES
static auto startTime = usecTimestampNow();
renderInstances(INSTANCE_NAME, batch, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
renderInstances(INSTANCE_NAME, batch, color, pipeline, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
auto usecs = usecTimestampNow();
usecs -= startTime;
@ -1924,18 +1935,17 @@ void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4&
}
});
#else
renderInstances(INSTANCE_NAME, batch, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
renderInstances(INSTANCE_NAME, batch, color, pipeline, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
DependencyManager::get<GeometryCache>()->renderCubeInstances(batch, data.count(),
data.buffers[INSTANCE_COLOR_BUFFER]);
});
#endif
}
void GeometryCache::renderWireCubeInstance(gpu::Batch& batch, const glm::vec4& color) {
void GeometryCache::renderWireCubeInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
static const std::string INSTANCE_NAME = __FUNCTION__;
renderInstances(INSTANCE_NAME, batch, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
renderInstances(INSTANCE_NAME, batch, color, pipeline, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
DependencyManager::get<GeometryCache>()->renderWireCubeInstances(batch, data.count(),
data.buffers[INSTANCE_COLOR_BUFFER]);
});
}

View file

@ -150,31 +150,44 @@ public:
static const int UNKNOWN_ID;
/// Sets up the state necessary to render static untextured geometry with the simple program.
gpu::PipelinePointer bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true,
bool emissive = false, bool depthBias = false);
// Bind the pipeline and get the state to render static geometry
void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true,
bool emissive = false, bool depthBias = false);
// Get the pipeline to render static geometry
gpu::PipelinePointer getSimplePipeline(bool textured = false, bool culled = true,
bool emissive = false, bool depthBias = false);
render::ShapePipelinePointer getShapePipeline() { return GeometryCache::_simplePipeline; }
void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color);
void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec3& color) {
renderSolidSphereInstance(batch, glm::vec4(color, 1.0));
// Static geometry
void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color,
const render::ShapePipelinePointer& pipeline = _simplePipeline);
void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec3& color,
const render::ShapePipelinePointer& pipeline = _simplePipeline) {
renderSolidSphereInstance(batch, glm::vec4(color, 1.0), pipeline);
}
void renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& color);
void renderWireSphereInstance(gpu::Batch& batch, const glm::vec3& color) {
renderWireSphereInstance(batch, glm::vec4(color, 1.0));
void renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& color,
const render::ShapePipelinePointer& pipeline = _simplePipeline);
void renderWireSphereInstance(gpu::Batch& batch, const glm::vec3& color,
const render::ShapePipelinePointer& pipeline = _simplePipeline) {
renderWireSphereInstance(batch, glm::vec4(color, 1.0), pipeline);
}
void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& color);
void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec3& color) {
renderSolidCubeInstance(batch, glm::vec4(color, 1.0));
void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& color,
const render::ShapePipelinePointer& pipeline = _simplePipeline);
void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec3& color,
const render::ShapePipelinePointer& pipeline = _simplePipeline) {
renderSolidCubeInstance(batch, glm::vec4(color, 1.0), pipeline);
}
void renderWireCubeInstance(gpu::Batch& batch, const glm::vec4& color);
void renderWireCubeInstance(gpu::Batch& batch, const glm::vec3& color) {
renderWireCubeInstance(batch, glm::vec4(color, 1.0));
void renderWireCubeInstance(gpu::Batch& batch, const glm::vec4& color,
const render::ShapePipelinePointer& pipeline = _simplePipeline);
void renderWireCubeInstance(gpu::Batch& batch, const glm::vec3& color,
const render::ShapePipelinePointer& pipeline = _simplePipeline) {
renderWireCubeInstance(batch, glm::vec4(color, 1.0), pipeline);
}
// Dynamic geometry
void renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer);
void renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer);
void renderShape(gpu::Batch& batch, Shape shape);
@ -364,11 +377,9 @@ private:
QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
gpu::PipelinePointer getPipeline(SimpleProgramKey config);
gpu::ShaderPointer _simpleShader;
gpu::ShaderPointer _emissiveShader;
static render::ShapePipelinePointer _simplePipeline;
QHash<SimpleProgramKey, gpu::PipelinePointer> _simplePrograms;
};

View file

@ -58,6 +58,15 @@ void initStencilPipeline(gpu::PipelinePointer& pipeline) {
pipeline = gpu::Pipeline::create(program, state);
}
void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) {
// Set a default diffuse map
batch.setResourceTexture(render::ShapePipeline::Slot::DIFFUSE_MAP,
DependencyManager::get<TextureCache>()->getWhiteTexture());
// Set a default normal map
batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP,
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
}
void initOverlay3DPipelines(ShapePlumber& plumber) {
auto vs = gpu::Shader::createVertex(std::string(overlay3D_vert));
auto ps = gpu::Shader::createPixel(std::string(overlay3D_frag));
@ -67,14 +76,7 @@ void initOverlay3DPipelines(ShapePlumber& plumber) {
opaqueState->setDepthTest(false);
opaqueState->setBlendFunction(false);
plumber.addPipeline(ShapeKey::Filter::Builder().withOpaque(), program, opaqueState);
}
void pipelineBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) {
if (pipeline.locations->normalFittingMapUnit > -1) {
batch.setResourceTexture(pipeline.locations->normalFittingMapUnit,
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
}
plumber.addPipeline(ShapeKey::Filter::Builder().withOpaque(), program, opaqueState, &batchSetter);
}
void initDeferredPipelines(render::ShapePlumber& plumber) {
@ -97,7 +99,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber) {
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader);
plumber.addPipeline(key, program, state, &pipelineBatchSetter);
plumber.addPipeline(key, program, state, &batchSetter);
// Add a wireframe version
if (!key.isWireFrame()) {
@ -106,7 +108,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber) {
wireFrameState->setFillMode(gpu::State::FILL_LINE);
plumber.addPipeline(wireFrameKey, program, wireFrameState, &pipelineBatchSetter);
plumber.addPipeline(wireFrameKey, program, wireFrameState, &batchSetter);
}
};

View file

@ -143,6 +143,7 @@ void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, cons
if (args->_pipeline) {
item.render(args);
}
args->_pipeline = nullptr;
} else if (key.hasOwnPipeline()) {
item.render(args);
} else {

View file

@ -22,6 +22,11 @@ ShapeKey::Filter::Builder::Builder() {
_mask.set(INVALID);
}
gpu::PipelinePointer ShapePipeline::get(gpu::Batch& batch) {
batchSetter(*this, batch);
return this->pipeline;
}
void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit, const PipelinePointer& pipeline) {
// Iterate over all keys
if (bit < (int)ShapeKey::FlagBit::NUM_FLAGS) {

View file

@ -209,6 +209,10 @@ public:
ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter) :
pipeline(pipeline), locations(locations), batchSetter(batchSetter) {}
// Normally, a pipeline is accessed thorugh pickPipeline. If it needs to be accessed manually,
// this method preps the pipeline with defaults set by its batchSetter and returns only the gpu::Pipeline.
gpu::PipelinePointer get(gpu::Batch& batch);
gpu::PipelinePointer pipeline;
std::shared_ptr<Locations> locations;

View file

@ -239,6 +239,7 @@ public:
}
}
auto pipeline = geometryCache->getSimplePipeline();
for (auto& transform : transforms) {
batch.setModelTransform(transform);
batch.setupNamedCalls(GRID_INSTANCE, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {