aboutsummaryrefslogtreecommitdiffstats
path: root/system/vulkan_enc/VkEncoder.cpp.inl
blob: 5e1c5f3906ca10adad8be43c2df524936117a9f9 (plain)
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

class VkEncoder::Impl {
public:
    Impl(IOStream* stream) : m_stream(stream), m_logEncodes(false) {
        m_stream.incStreamRef();
        const char* emuVkLogEncodesPropName = "qemu.vk.log";
        char encodeProp[PROPERTY_VALUE_MAX];
        if (property_get(emuVkLogEncodesPropName, encodeProp, nullptr) > 0) {
            m_logEncodes = atoi(encodeProp) > 0;
        }
    }

    ~Impl() {
        m_stream.decStreamRef();
    }

    VulkanCountingStream* countingStream() { return &m_countingStream; }
    VulkanStreamGuest* stream() { return &m_stream; }
    Pool* pool() { return &m_pool; }
    ResourceTracker* resources() { return ResourceTracker::get(); }
    Validation* validation() { return &m_validation; }

    void log(const char* text) {
        if (!m_logEncodes) return;
        ALOGD("encoder log: %s", text);
    }

    void flush() {
        lock();
        m_stream.flush();
        unlock();
    }

    // can be recursive
    void lock() {
        if (this == sAcquiredEncoderThreadLocal) {
            ++sAcquiredEncoderThreadLockLevels;
            return; // recursive
        }
        while (mLock.test_and_set(std::memory_order_acquire));
        sAcquiredEncoderThreadLocal = this;
        sAcquiredEncoderThreadLockLevels = 1;
    }

    void unlock() {
        if (this != sAcquiredEncoderThreadLocal) {
            // error, trying to unlock without having locked first
            return;
        }

        --sAcquiredEncoderThreadLockLevels;
        if (0 == sAcquiredEncoderThreadLockLevels) {
            mLock.clear(std::memory_order_release);
            sAcquiredEncoderThreadLocal = nullptr;
        }
    }

    void incRef() {
        __atomic_add_fetch(&m_refCount, 1, __ATOMIC_SEQ_CST);
    }

    bool decRef() {
        if (0 == __atomic_sub_fetch(&m_refCount, 1, __ATOMIC_SEQ_CST)) {
            return true;
        }
        return false;
    }

private:
    VulkanCountingStream m_countingStream;
    VulkanStreamGuest m_stream;
    Pool m_pool { 8, 4096, 64 };

    Validation m_validation;
    bool m_logEncodes;
    std::atomic_flag mLock = ATOMIC_FLAG_INIT;
    static thread_local Impl* sAcquiredEncoderThreadLocal;
    static thread_local uint32_t sAcquiredEncoderThreadLockLevels;
    uint32_t m_refCount = 1;
};

VkEncoder::~VkEncoder() { }

// static
thread_local VkEncoder::Impl* VkEncoder::Impl::sAcquiredEncoderThreadLocal = nullptr;
thread_local uint32_t VkEncoder::Impl::sAcquiredEncoderThreadLockLevels = 0;

struct EncoderAutoLock {
    EncoderAutoLock(VkEncoder* enc) : mEnc(enc) {
        mEnc->lock();
    }
    ~EncoderAutoLock() {
        mEnc->unlock();
    }
    VkEncoder* mEnc;
};

VkEncoder::VkEncoder(IOStream *stream) :
    mImpl(new VkEncoder::Impl(stream)) { }

void VkEncoder::flush() {
    mImpl->flush();
}

void VkEncoder::lock() {
    mImpl->lock();
}

void VkEncoder::unlock() {
    mImpl->unlock();
}

void VkEncoder::incRef() {
    mImpl->incRef();
}

bool VkEncoder::decRef() {
    if (mImpl->decRef()) {
        delete this;
        return true;
    }
    return false;
}