summaryrefslogtreecommitdiffstats
path: root/src/audio_core/common/workbuffer_allocator.h
blob: fb89f97fea9ddea8eefa5443c2ba0c52aa9f60a0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <span>

#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_types.h"

namespace AudioCore {
/**
 * Responsible for allocating up a workbuffer into multiple pieces.
 * Takes in a buffer and size (it does not own them), and allocates up the buffer via Allocate.
 */
class WorkbufferAllocator {
public:
    explicit WorkbufferAllocator(std::span<u8> buffer_, u64 size_)
        : buffer{reinterpret_cast<u64>(buffer_.data())}, size{size_} {}

    /**
     * Allocate the given count of T elements, aligned to alignment.
     *
     * @param count     - The number of elements to allocate.
     * @param alignment - The required starting alignment.
     * @return Non-owning container of allocated elements.
     */
    template <typename T>
    std::span<T> Allocate(u64 count, u64 alignment) {
        u64 out{0};
        u64 byte_size{count * sizeof(T)};

        if (byte_size > 0) {
            auto current{buffer + offset};
            auto aligned_buffer{Common::AlignUp(current, alignment)};
            if (aligned_buffer + byte_size <= buffer + size) {
                out = aligned_buffer;
                offset = byte_size - buffer + aligned_buffer;
            } else {
                LOG_ERROR(
                    Service_Audio,
                    "Allocated buffer was too small to hold new alloc.\nAllocator size={:08X}, "
                    "offset={:08X}.\nAttempting to allocate {:08X} with alignment={:02X}",
                    size, offset, byte_size, alignment);
                count = 0;
            }
        }

        return std::span<T>(reinterpret_cast<T*>(out), count);
    }

    /**
     * Align the current offset to the given alignment.
     *
     * @param alignment - The required starting alignment.
     */
    void Align(u64 alignment) {
        auto current{buffer + offset};
        auto aligned_buffer{Common::AlignUp(current, alignment)};
        offset = 0 - buffer + aligned_buffer;
    }

    /**
     * Get the current buffer offset.
     *
     * @return The current allocating offset.
     */
    u64 GetCurrentOffset() const {
        return offset;
    }

    /**
     * Get the current buffer size.
     *
     * @return The size of the current buffer.
     */
    u64 GetSize() const {
        return size;
    }

    /**
     * Get the remaining size that can be allocated.
     *
     * @return The remaining size left in the buffer.
     */
    u64 GetRemainingSize() const {
        return size - offset;
    }

private:
    /// The buffer into which we are allocating.
    u64 buffer;
    /// Size of the buffer we're allocating to.
    u64 size;
    /// Current offset into the buffer, an error will be thrown if it exceeds size.
    u64 offset{};
};

} // namespace AudioCore