1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "src/gpu/vk/GrVkMemoryReclaimer.h"
17
18#include "include/core/SkLog.h"
19
20#define VK_CALL(GPU, X) GR_VK_CALL((GPU)->vkInterface(), X)
21
22SkExecutor& GrVkMemoryReclaimer::getThreadPool()
23{
24    static std::unique_ptr<SkExecutor> executor = ({
25        auto executor = SkExecutor::MakeFIFOThreadPool(1, false);
26        executor->add([]() {
27            int err = pthread_setname_np(pthread_self(), "async-reclaimer");
28            if (err) {
29                SK_LOGE("GrVkMemoryReclaimer::GetThreadPool pthread_setname_np, error = %d", err);
30            }
31        });
32        std::move(executor);
33    });
34    return *executor;
35}
36
37bool GrVkMemoryReclaimer::addMemoryToWaitQueue(const GrVkGpu* gpu, const GrVkAlloc& alloc, const VkBuffer& buffer)
38{
39    if (!fEnabled) {
40        return false;
41    }
42    fWaitQueues.emplace_back(WaitQueueItem{.fGpu = gpu, .fAlloc = alloc, .fType = ItemType::BUFFER, .fBuffer = buffer});
43    if (fWaitQueues.size() > fMemoryCountThreshold) {
44        invokeParallelReclaiming();
45    }
46    return true;
47}
48
49bool GrVkMemoryReclaimer::addMemoryToWaitQueue(const GrVkGpu* gpu, const GrVkAlloc& alloc, const VkImage& image)
50{
51    if (!fEnabled) {
52        return false;
53    }
54    fWaitQueues.emplace_back(WaitQueueItem{.fGpu = gpu, .fAlloc = alloc, .fType = ItemType::IMAGE, .fImage = image});
55    if (fWaitQueues.size() > fMemoryCountThreshold) {
56        invokeParallelReclaiming();
57    }
58    return true;
59}
60
61void GrVkMemoryReclaimer::flushGpuMemoryInWaitQueue()
62{
63    if (!fEnabled) {
64        return;
65    }
66    if (!fWaitQueues.size()) {
67        return;
68    }
69    invokeParallelReclaiming();
70}
71
72void GrVkMemoryReclaimer::invokeParallelReclaiming()
73{
74    getThreadPool().add([freeQueues {std::move(fWaitQueues)}] {
75        for (auto& item : freeQueues) {
76            if (item.fType == ItemType::BUFFER) {
77                GrVkBuffer::DestroyAndFreeBufferMemory(item.fGpu, item.fAlloc, item.fBuffer);
78            } else {
79                GrVkImage::DestroyAndFreeImageMemory(item.fGpu, item.fAlloc, item.fImage);
80            }
81        }
82    });
83}
84
85void GrVkMemoryReclaimer::setGpuMemoryAsyncReclaimerSwitch(bool enabled)
86{
87    fEnabled = enabled;
88}
89