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; BufferPointers buffers;
Function function; Function function;
DrawCallInfoBuffer drawCallInfos; DrawCallInfoBuffer drawCallInfos;
Pipeline::Pointer pipeline;
size_t count() const { return drawCallInfos.size(); } size_t count() const { return drawCallInfos.size(); }
void process(Batch& batch) { void process(Batch& batch) {
batch.setPipeline(pipeline);
if (function) { if (function) {
function(batch, *this); function(batch, *this);
} }

View file

@ -494,10 +494,22 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat() {
return INSTANCED_SOLID_STREAM_FORMAT; return INSTANCED_SOLID_STREAM_FORMAT;
} }
render::ShapePipelinePointer GeometryCache::_simplePipeline;
GeometryCache::GeometryCache() : GeometryCache::GeometryCache() :
_nextID(0) _nextID(0)
{ {
buildShapes(); 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() { GeometryCache::~GeometryCache() {
@ -1781,7 +1793,23 @@ inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) {
return a.getRaw() == b.getRaw(); 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; static std::once_flag once;
std::call_once(once, [&]() { std::call_once(once, [&]() {
auto VS = gpu::Shader::createVertex(std::string(simple_vert)); 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(*_simpleShader, slotBindings);
gpu::Shader::makeProgram(*_emissiveShader, slotBindings); gpu::Shader::makeProgram(*_emissiveShader, slotBindings);
}); });
// If the pipeline already exists, return it
auto it = _simplePrograms.find(config); auto it = _simplePrograms.find(config);
if (it != _simplePrograms.end()) { if (it != _simplePrograms.end()) {
return it.value(); return it.value();
} }
// If the pipeline did not exist, make it
auto state = std::make_shared<gpu::State>(); auto state = std::make_shared<gpu::State>();
if (config.isCulled()) { if (config.isCulled()) {
state->setCullMode(gpu::State::CULL_BACK); state->setCullMode(gpu::State::CULL_BACK);
@ -1815,33 +1844,15 @@ gpu::PipelinePointer GeometryCache::getPipeline(SimpleProgramKey config) {
state->setDepthBiasSlopeScale(1.0f); state->setDepthBiasSlopeScale(1.0f);
} }
state->setBlendFunction(false, state->setBlendFunction(false,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, 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::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader;
gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state); gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state);
_simplePrograms.insert(config, pipeline); _simplePrograms.insert(config, pipeline);
return 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 toCompactColor(const glm::vec4& color) {
uint32_t compactColor = ((int(color.x * 255.0f) & 0xFF)) | uint32_t compactColor = ((int(color.x * 255.0f) & 0xFF)) |
((int(color.y * 255.0f) & 0xFF) << 8) | ((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; static const size_t INSTANCE_COLOR_BUFFER = 0;
template <typename F> 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); gpu::BufferPointer instanceColorBuffer = batch.getNamedBuffer(name, INSTANCE_COLOR_BUFFER);
auto compactColor = toCompactColor(color); auto compactColor = toCompactColor(color);
instanceColorBuffer->append(compactColor); instanceColorBuffer->append(compactColor);
} }
batch.setupNamedCalls(name, [f](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { batch.setupNamedCalls(name, [f, pipeline](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch); batch.setPipeline(pipeline->get(batch));
f(batch, data); 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__; 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(), DependencyManager::get<GeometryCache>()->renderShapeInstances(batch, GeometryCache::Sphere, data.count(),
data.buffers[INSTANCE_COLOR_BUFFER]); 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__; 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(), DependencyManager::get<GeometryCache>()->renderWireShapeInstances(batch, GeometryCache::Sphere, data.count(),
data.buffers[INSTANCE_COLOR_BUFFER]); 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 // available shape types, both solid and wireframes
//#define DEBUG_SHAPES //#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__; static const std::string INSTANCE_NAME = __FUNCTION__;
#ifdef DEBUG_SHAPES #ifdef DEBUG_SHAPES
static auto startTime = usecTimestampNow(); 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(); auto usecs = usecTimestampNow();
usecs -= startTime; usecs -= startTime;
@ -1924,18 +1935,17 @@ void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4&
} }
}); });
#else #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(), DependencyManager::get<GeometryCache>()->renderCubeInstances(batch, data.count(),
data.buffers[INSTANCE_COLOR_BUFFER]); data.buffers[INSTANCE_COLOR_BUFFER]);
}); });
#endif #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__; 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(), DependencyManager::get<GeometryCache>()->renderWireCubeInstances(batch, data.count(),
data.buffers[INSTANCE_COLOR_BUFFER]); data.buffers[INSTANCE_COLOR_BUFFER]);
}); });
} }

View file

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

View file

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

View file

@ -22,6 +22,11 @@ ShapeKey::Filter::Builder::Builder() {
_mask.set(INVALID); _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) { void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit, const PipelinePointer& pipeline) {
// Iterate over all keys // Iterate over all keys
if (bit < (int)ShapeKey::FlagBit::NUM_FLAGS) { if (bit < (int)ShapeKey::FlagBit::NUM_FLAGS) {

View file

@ -209,6 +209,10 @@ public:
ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter) : ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter) :
pipeline(pipeline), locations(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; gpu::PipelinePointer pipeline;
std::shared_ptr<Locations> locations; std::shared_ptr<Locations> locations;

View file

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