Repository: google/filament
File: filament/backend/src/vulkan/VulkanPipelineCache.cpp (C++)

Code before:
        mCompilerThreadPool.init(
            /*threadCount=*/1,
            []() {
                JobSystem::setThreadName("CompilerThreadPool");
                // This thread should be lower priority than the main thread.
                JobSystem::setThreadPriority(JobSystem::Priority::DISPLAY);
            }, []() {
                // No cleanup required.
            });
    }
}

void VulkanPipelineCache::bindLayout(VkPipelineLayout layout) noexcept {
    mPipelineRequirements.layout = layout;
}

VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::getOrCreatePipeline() noexcept {
    // If a cached object exists, re-use it, otherwise create a new one.
    if (PipelineMap::iterator pipelineIter = mPipelines.find(mPipelineRequirements);
            pipelineIter != mPipelines.end()) {
        auto& pipeline = pipelineIter.value();
        pipeline.lastUsed = mCurrentTime;
        return &pipeline;
    }
    PipelineCacheEntry cacheEntry {
        .handle = createPipeline(mPipelineRequirements),
        .lastUsed = mCurrentTime,
    };
    return &mPipelines.emplace(mPipelineRequirements, cacheEntry).first.value();
}

void VulkanPipelineCache::bindPipeline(VulkanCommandBuffer* commands) {
    VkCommandBuffer const cmdbuffer = commands->buffer();
    PipelineCacheEntry* cacheEntry = getOrCreatePipeline();

    // If an error occurred, allow higher levels to handle it gracefully.
    assert_invariant(cacheEntry != nullptr && "Failed to create/find pipeline");


    static PipelineEqual equal;
    if (!equal(mBoundPipeline, mPipelineRequirements)) {
        mBoundPipeline = mPipelineRequirements;
        vkCmdBindPipeline(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, cacheEntry->handle);
    }
}

VkPipeline VulkanPipelineCache::createPipeline(const PipelineKey& key) noexcept {
    assert_invariant(key.shaders[0] && "Vertex shader is not bound.");
    assert_invariant(key.layout && "No pipeline layout specified");

    VkPipelineShaderStageCreateInfo shaderStages[SHADER_MODULE_COUNT];

Review comment (bug):
`createPipeline` can return nullptr, which in turn could cause a crash.

Code after:
        mCompilerThreadPool.init(
            /*threadCount=*/1,
            []() {
                JobSystem::setThreadName("CompilerThreadPool");
                // This thread should be lower priority than the main thread.
                JobSystem::setThreadPriority(JobSystem::Priority::DISPLAY);
            }, []() {
                // No cleanup required.
            });
    }
}

void VulkanPipelineCache::bindLayout(VkPipelineLayout layout) noexcept {
    mPipelineRequirements.layout = layout;
}

VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::getOrCreatePipeline() noexcept {
    // If a cached object exists, re-use it, otherwise create a new one.
    if (PipelineMap::iterator pipelineIter = mPipelines.find(mPipelineRequirements);
            pipelineIter != mPipelines.end()) {
        auto& pipeline = pipelineIter.value();
        pipeline.lastUsed = mCurrentTime;
        return &pipeline;
    }
    PipelineCacheEntry cacheEntry {
        .handle = createPipeline(mPipelineRequirements),
        .lastUsed = mCurrentTime,
    };
    assert_invariant(cacheEntry.handle != nullptr && "Pipeline handle is nullptr");
    return &mPipelines.emplace(mPipelineRequirements, cacheEntry).first.value();
}

void VulkanPipelineCache::bindPipeline(VulkanCommandBuffer* commands) {
    VkCommandBuffer const cmdbuffer = commands->buffer();
    PipelineCacheEntry* cacheEntry = getOrCreatePipeline();

    // If an error occurred, allow higher levels to handle it gracefully.
    assert_invariant(cacheEntry != nullptr && "Failed to create/find pipeline");


    static PipelineEqual equal;
    if (!equal(mBoundPipeline, mPipelineRequirements)) {
        mBoundPipeline = mPipelineRequirements;
        vkCmdBindPipeline(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, cacheEntry->handle);
    }
}

VkPipeline VulkanPipelineCache::createPipeline(const PipelineKey& key) noexcept {
    assert_invariant(key.shaders[0] && "Vertex shader is not bound.");
    assert_invariant(key.layout && "No pipeline layout specified");