mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-05-20 18:34:58 +00:00
video_core: Implement guest buffer manager (#373)
* video_core: Introduce buffer cache * video_core: Use multi level page table for caches * renderer_vulkan: Remove unused stream buffer * fix build * oops forgot optimize off
This commit is contained in:
parent
159be2c7f4
commit
381ba8c7a5
55 changed files with 2697 additions and 1039 deletions
107
src/common/object_pool.h
Normal file
107
src/common/object_pool.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace Common {
|
||||
|
||||
template <typename T>
|
||||
requires std::is_destructible_v<T>
|
||||
class ObjectPool {
|
||||
public:
|
||||
explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} {
|
||||
node = &chunks.emplace_back(new_chunk_size);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
requires std::is_constructible_v<T, Args...>
|
||||
[[nodiscard]] T* Create(Args&&... args) {
|
||||
return std::construct_at(Memory(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void ReleaseContents() {
|
||||
if (chunks.empty()) {
|
||||
return;
|
||||
}
|
||||
Chunk& root{chunks.front()};
|
||||
if (root.used_objects == root.num_objects) {
|
||||
// Root chunk has been filled, squash allocations into it
|
||||
const size_t total_objects{root.num_objects + new_chunk_size * (chunks.size() - 1)};
|
||||
chunks.clear();
|
||||
chunks.emplace_back(total_objects);
|
||||
} else {
|
||||
root.Release();
|
||||
chunks.resize(1);
|
||||
}
|
||||
chunks.shrink_to_fit();
|
||||
node = &chunks.front();
|
||||
}
|
||||
|
||||
private:
|
||||
struct NonTrivialDummy {
|
||||
NonTrivialDummy() noexcept {}
|
||||
};
|
||||
|
||||
union Storage {
|
||||
Storage() noexcept {}
|
||||
~Storage() noexcept {}
|
||||
|
||||
NonTrivialDummy dummy{};
|
||||
T object;
|
||||
};
|
||||
|
||||
struct Chunk {
|
||||
explicit Chunk() = default;
|
||||
explicit Chunk(size_t size)
|
||||
: num_objects{size}, storage{std::make_unique<Storage[]>(size)} {}
|
||||
|
||||
Chunk& operator=(Chunk&& rhs) noexcept {
|
||||
Release();
|
||||
used_objects = std::exchange(rhs.used_objects, 0);
|
||||
num_objects = std::exchange(rhs.num_objects, 0);
|
||||
storage = std::move(rhs.storage);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Chunk(Chunk&& rhs) noexcept
|
||||
: used_objects{std::exchange(rhs.used_objects, 0)},
|
||||
num_objects{std::exchange(rhs.num_objects, 0)}, storage{std::move(rhs.storage)} {}
|
||||
|
||||
~Chunk() {
|
||||
Release();
|
||||
}
|
||||
|
||||
void Release() {
|
||||
std::destroy_n(storage.get(), used_objects);
|
||||
used_objects = 0;
|
||||
}
|
||||
|
||||
size_t used_objects{};
|
||||
size_t num_objects{};
|
||||
std::unique_ptr<Storage[]> storage;
|
||||
};
|
||||
|
||||
[[nodiscard]] T* Memory() {
|
||||
Chunk* const chunk{FreeChunk()};
|
||||
return &chunk->storage[chunk->used_objects++].object;
|
||||
}
|
||||
|
||||
[[nodiscard]] Chunk* FreeChunk() {
|
||||
if (node->used_objects != node->num_objects) {
|
||||
return node;
|
||||
}
|
||||
node = &chunks.emplace_back(new_chunk_size);
|
||||
return node;
|
||||
}
|
||||
|
||||
Chunk* node{};
|
||||
std::vector<Chunk> chunks;
|
||||
size_t new_chunk_size{};
|
||||
};
|
||||
|
||||
} // namespace Common
|
61
src/common/unique_function.h
Executable file
61
src/common/unique_function.h
Executable file
|
@ -0,0 +1,61 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace Common {
|
||||
|
||||
/// General purpose function wrapper similar to std::function.
|
||||
/// Unlike std::function, the captured values don't have to be copyable.
|
||||
/// This class can be moved but not copied.
|
||||
template <typename ResultType, typename... Args>
|
||||
class UniqueFunction {
|
||||
class CallableBase {
|
||||
public:
|
||||
virtual ~CallableBase() = default;
|
||||
virtual ResultType operator()(Args&&...) = 0;
|
||||
};
|
||||
|
||||
template <typename Functor>
|
||||
class Callable final : public CallableBase {
|
||||
public:
|
||||
Callable(Functor&& functor_) : functor{std::move(functor_)} {}
|
||||
~Callable() override = default;
|
||||
|
||||
ResultType operator()(Args&&... args) override {
|
||||
return functor(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
Functor functor;
|
||||
};
|
||||
|
||||
public:
|
||||
UniqueFunction() = default;
|
||||
|
||||
template <typename Functor>
|
||||
UniqueFunction(Functor&& functor)
|
||||
: callable{std::make_unique<Callable<Functor>>(std::move(functor))} {}
|
||||
|
||||
UniqueFunction& operator=(UniqueFunction&& rhs) noexcept = default;
|
||||
UniqueFunction(UniqueFunction&& rhs) noexcept = default;
|
||||
|
||||
UniqueFunction& operator=(const UniqueFunction&) = delete;
|
||||
UniqueFunction(const UniqueFunction&) = delete;
|
||||
|
||||
ResultType operator()(Args&&... args) const {
|
||||
return (*callable)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return static_cast<bool>(callable);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<CallableBase> callable;
|
||||
};
|
||||
|
||||
} // namespace Common
|
Loading…
Add table
Add a link
Reference in a new issue