Repository: google/filament
File: filament/src/PostProcessManager.h (C/C++)

Code before:
            backend::Viewport scissor,
            backend::DriverApi& driver) const noexcept;

    // Helper for a common case. Don't use in a loop because retrieving the PipelineState
    // from FMaterialInstance is not trivial.
    void commitAndRenderFullScreenQuad(backend::DriverApi& driver,
            FrameGraphResources::RenderPassInfo const& out,
            FMaterialInstance const* mi,
            PostProcessVariant variant = PostProcessVariant::OPAQUE) const noexcept;

    // Sets the necessary spec constants and uniforms common to both colorGrading.mat and
    // colorGradingAsSubpass.mat.
    FMaterialInstance* configureColorGradingMaterial(
            PostProcessMaterial& material, FColorGrading const* colorGrading,
            ColorGradingConfig const& colorGradingConfig, VignetteOptions const& vignetteOptions,
            uint32_t const width, uint32_t const height) noexcept;

    void resetForRender();

private:
    // This class manages a cache of material instances mapped by materials.  This allows us to
    // re-use instances across frames. Note that also it's possible for the same frame to want to
    // use the same instance multiple times (for example for bilateral blurring or upsampling), but
    // we allocate separate instances for that case so that UBOs are not shared across render
    // passes. This allows for bubble-reduction for vulkan (and possibly other backends).
    class MaterialInstanceManager {
    public:
        class Record {
        public:
            Record(FMaterial const* material)
                : mMaterial(material) {}
            ~Record() = default;

            Record(Record const& rhs) noexcept = default;
            Record& operator=(Record const& rhs) noexcept = default;
            Record(Record&& rhs) noexcept = default;
            Record& operator=(Record&& rhs) noexcept = default;

            void terminate(FEngine& engine);
            void reset() { mAvailable = utils::bitset32{ (1 << (mInstances.size() + 1)) - 1 }; }
            FMaterialInstance* getInstance();

        private:
            FMaterial const* mMaterial = nullptr;
            std::vector<FMaterialInstance*> mInstances;
            utils::bitset32 mAvailable = {};

            friend class MaterialInstanceManager;
        };

        ~MaterialInstanceManager() = default;

Review comment (refactor):
Could we move this into its own file? And just keep the helper for PostProcessMaterial into PostProcessManager (so that MaterialInstanceManager doesn't need to depend on PostProcessMateral).
I think this class is 99% generic, we might as well make it 100%.

Code after:
    void renderFullScreenQuad(FrameGraphResources::RenderPassInfo const& out,
            backend::PipelineState const& pipeline,
            backend::DriverApi& driver) const noexcept;

    void renderFullScreenQuadWithScissor(FrameGraphResources::RenderPassInfo const& out,
            backend::PipelineState const& pipeline,
            backend::Viewport scissor,
            backend::DriverApi& driver) const noexcept;

    // Helper for a common case. Don't use in a loop because retrieving the PipelineState
    // from FMaterialInstance is not trivial.
    void commitAndRenderFullScreenQuad(backend::DriverApi& driver,
            FrameGraphResources::RenderPassInfo const& out,
            FMaterialInstance const* mi,
            PostProcessVariant variant = PostProcessVariant::OPAQUE) const noexcept;

    // Sets the necessary spec constants and uniforms common to both colorGrading.mat and
    // colorGradingAsSubpass.mat.
    FMaterialInstance* configureColorGradingMaterial(
            PostProcessMaterial& material, FColorGrading const* colorGrading,
            ColorGradingConfig const& colorGradingConfig, VignetteOptions const& vignetteOptions,
            uint32_t width, uint32_t height) noexcept;

    StructureDescriptorSet& getStructureDescriptorSet() const noexcept { return mStructureDescriptorSet; }

    void resetForRender();

private:

    // Helper to get a MaterialInstance from a FMaterial
    // This currently just call FMaterial::getDefaultInstance().
    FMaterialInstance* getMaterialInstance(FMaterial const* ma) {
        return mMaterialInstanceManager.getMaterialInstance(ma);
    }

    // Helper to get a MaterialInstance from a PostProcessMaterial.
    FMaterialInstance* getMaterialInstance(FEngine& engine, PostProcessMaterial const& material,
            PostProcessVariant variant = PostProcessVariant::OPAQUE) {
        FMaterial const* ma = material.getMaterial(engine, variant);
        return getMaterialInstance(ma);
    }

    backend::RenderPrimitiveHandle mFullScreenQuadRph;
    backend::VertexBufferInfoHandle mFullScreenQuadVbih;
    backend::DescriptorSetLayoutHandle mPerRenderableDslh;

    FEngine& mEngine;

    mutable SsrPassDescriptorSet mSsrPassDescriptorSet;
    mutable PostProcessDescriptorSet mPostProcessDescriptorSet;
    mutable StructureDescriptorSet mStructureDescriptorSet;