Hash :
394fb0d3
Author :
Date :
2022-04-26T17:17:58
Vulkan: Don't take lock for getLastCompletedQueueSerial getLastCompletedQueueSerial() is simply returning a uint64_t serial number. There is no need to take a mutex lock. This CL uses atomic for mLastCompletedQueueSerial and removed the lock as well as removed the virtual function call. This also avoid the annoyance with mutex lock, that if you call getLastCompletedQueueSerial in places that has other lock held, you may end up with deadlock. This CL avoids that trouble all together other than improves performance. Bug: b/230759914 Change-Id: I9dc688d410e4c6bca7fc70ae4f9fe0c3acc2e005 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3607500 Reviewed-by: Amirali Abdolrashidi <abdolrashidi@google.com> Commit-Queue: Charlie Lao <cclao@google.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>
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 125
//
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// serial_utils:
// Utilities for generating unique IDs for resources in ANGLE.
//
#ifndef LIBANGLE_RENDERER_SERIAL_UTILS_H_
#define LIBANGLE_RENDERER_SERIAL_UTILS_H_
#include <atomic>
#include <limits>
#include "common/angleutils.h"
#include "common/debug.h"
namespace rx
{
class ResourceSerial
{
public:
constexpr ResourceSerial() : mValue(kDirty) {}
explicit constexpr ResourceSerial(uintptr_t value) : mValue(value) {}
constexpr bool operator==(ResourceSerial other) const { return mValue == other.mValue; }
constexpr bool operator!=(ResourceSerial other) const { return mValue != other.mValue; }
void dirty() { mValue = kDirty; }
void clear() { mValue = kEmpty; }
constexpr bool valid() const { return mValue != kEmpty && mValue != kDirty; }
constexpr bool empty() const { return mValue == kEmpty; }
private:
constexpr static uintptr_t kDirty = std::numeric_limits<uintptr_t>::max();
constexpr static uintptr_t kEmpty = 0;
uintptr_t mValue;
};
class Serial final
{
public:
constexpr Serial() : mValue(kInvalid) {}
constexpr Serial(const Serial &other) = default;
Serial &operator=(const Serial &other) = default;
static constexpr Serial Infinite() { return Serial(std::numeric_limits<uint64_t>::max()); }
constexpr bool operator==(const Serial &other) const
{
return mValue != kInvalid && mValue == other.mValue;
}
constexpr bool operator==(uint32_t value) const
{
return mValue != kInvalid && mValue == static_cast<uint64_t>(value);
}
constexpr bool operator!=(const Serial &other) const
{
return mValue == kInvalid || mValue != other.mValue;
}
constexpr bool operator>(const Serial &other) const { return mValue > other.mValue; }
constexpr bool operator>=(const Serial &other) const { return mValue >= other.mValue; }
constexpr bool operator<(const Serial &other) const { return mValue < other.mValue; }
constexpr bool operator<=(const Serial &other) const { return mValue <= other.mValue; }
constexpr bool operator<(uint32_t value) const { return mValue < static_cast<uint64_t>(value); }
// Useful for serialization.
constexpr uint64_t getValue() const { return mValue; }
constexpr bool valid() const { return mValue != kInvalid; }
private:
template <typename T>
friend class SerialFactoryBase;
friend class AtomicQueueSerial;
constexpr explicit Serial(uint64_t value) : mValue(value) {}
uint64_t mValue;
static constexpr uint64_t kInvalid = 0;
};
// Defines class to track the queue serial that can be load/store from multiple threads atomically.
class AtomicQueueSerial final
{
public:
constexpr AtomicQueueSerial() : mValue(kInvalid) { ASSERT(mValue.is_lock_free()); }
AtomicQueueSerial &operator=(const Serial &other)
{
mValue.store(other.mValue, std::memory_order_release);
return *this;
}
Serial getSerial() const { return Serial(mValue.load(std::memory_order_consume)); }
private:
std::atomic<uint64_t> mValue;
static constexpr uint64_t kInvalid = 0;
};
// Used as default/initial serial
static constexpr Serial kZeroSerial = Serial();
template <typename SerialBaseType>
class SerialFactoryBase final : angle::NonCopyable
{
public:
SerialFactoryBase() : mSerial(1) {}
Serial generate()
{
uint64_t current = mSerial++;
ASSERT(mSerial > current); // Integer overflow
return Serial(current);
}
private:
SerialBaseType mSerial;
};
using SerialFactory = SerialFactoryBase<uint64_t>;
using AtomicSerialFactory = SerialFactoryBase<std::atomic<uint64_t>>;
} // namespace rx
#endif // LIBANGLE_RENDERER_SERIAL_UTILS_H_