diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index a2ee57759f..6b8816d50a 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -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); } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index aa82232524..7e34fff2cd 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -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(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()->getWhiteTexture()); + batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP, + DependencyManager::get()->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()->getWhiteTexture()); + } + // Set a default normal map + batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP, + DependencyManager::get()->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(); 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()->getWhiteTexture()); - } - - batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP, - DependencyManager::get()->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 -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()->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()->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()->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()->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()->renderWireCubeInstances(batch, data.count(), data.buffers[INSTANCE_COLOR_BUFFER]); }); } - diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 81b8dfb325..5de08ea717 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -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 > _networkGeometry; - - gpu::PipelinePointer getPipeline(SimpleProgramKey config); - gpu::ShaderPointer _simpleShader; gpu::ShaderPointer _emissiveShader; + static render::ShapePipelinePointer _simplePipeline; QHash _simplePrograms; }; diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index d2e880aea3..2dfe5d8828 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -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()->getWhiteTexture()); + // Set a default normal map + batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP, + DependencyManager::get()->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()->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); } }; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 455a420355..bb31792c4b 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -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 { diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index c83f16c456..d6f3c86540 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -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) { diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 1a6837efa3..6ea9ea1c72 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -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; diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index b1ca3d0448..87ce2d7622 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -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) {