yuzu/src/video_core/shader_cache.h

162 lines
5.7 KiB
C
Raw Normal View History

2020-12-28 19:15:37 +04:00
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <algorithm>
2021-07-10 01:54:15 +04:00
#include <array>
2020-12-28 19:15:37 +04:00
#include <memory>
#include <mutex>
2021-07-10 01:54:15 +04:00
#include <span>
2020-12-28 19:15:37 +04:00
#include <unordered_map>
#include <utility>
#include <vector>
#include "common/common_types.h"
#include "video_core/rasterizer_interface.h"
2021-07-10 01:54:15 +04:00
#include "video_core/shader_environment.h"
namespace Tegra {
class MemoryManager;
}
2020-12-28 19:15:37 +04:00
namespace VideoCommon {
2021-07-10 01:54:15 +04:00
class GenericEnvironment;
struct ShaderInfo {
u64 unique_hash{};
size_t size_bytes{};
};
2020-12-28 19:15:37 +04:00
class ShaderCache {
static constexpr u64 PAGE_BITS = 14;
static constexpr u64 PAGE_SIZE = u64(1) << PAGE_BITS;
2021-07-10 01:54:15 +04:00
static constexpr size_t NUM_PROGRAMS = 6;
2020-12-28 19:15:37 +04:00
struct Entry {
VAddr addr_start;
VAddr addr_end;
2021-07-10 01:54:15 +04:00
ShaderInfo* data;
2020-12-28 19:15:37 +04:00
bool is_memory_marked = true;
2021-07-10 01:54:15 +04:00
bool Overlaps(VAddr start, VAddr end) const noexcept {
2020-12-28 19:15:37 +04:00
return start < addr_end && addr_start < end;
}
};
public:
/// @brief Removes shaders inside a given region
/// @note Checks for ranges
/// @param addr Start address of the invalidation
/// @param size Number of bytes of the invalidation
2021-07-10 01:54:15 +04:00
void InvalidateRegion(VAddr addr, size_t size);
2020-12-28 19:15:37 +04:00
/// @brief Unmarks a memory region as cached and marks it for removal
/// @param addr Start address of the CPU write operation
/// @param size Number of bytes of the CPU write operation
2021-07-10 01:54:15 +04:00
void OnCPUWrite(VAddr addr, size_t size);
2020-12-28 19:15:37 +04:00
/// @brief Flushes delayed removal operations
2021-07-10 01:54:15 +04:00
void SyncGuestHost();
2020-12-28 19:15:37 +04:00
2021-07-10 01:54:15 +04:00
protected:
struct GraphicsEnvironments {
std::array<GraphicsEnvironment, NUM_PROGRAMS> envs;
std::array<Shader::Environment*, NUM_PROGRAMS> env_ptrs;
2020-12-28 19:15:37 +04:00
2021-07-10 01:54:15 +04:00
std::span<Shader::Environment* const> Span() const noexcept {
return std::span(env_ptrs.begin(), std::ranges::find(env_ptrs, nullptr));
2020-12-28 19:15:37 +04:00
}
2021-07-10 01:54:15 +04:00
};
2020-12-28 19:15:37 +04:00
2021-07-10 01:54:15 +04:00
explicit ShaderCache(VideoCore::RasterizerInterface& rasterizer_,
Tegra::MemoryManager& gpu_memory_, Tegra::Engines::Maxwell3D& maxwell3d_,
Tegra::Engines::KeplerCompute& kepler_compute_);
2020-12-28 19:15:37 +04:00
2021-07-10 01:54:15 +04:00
/// @brief Update the hashes and information of shader stages
/// @param unique_hashes Shader hashes to store into when a stage is enabled
/// @return True no success, false on error
bool RefreshStages(std::array<u64, NUM_PROGRAMS>& unique_hashes);
2020-12-28 19:15:37 +04:00
2021-07-10 01:54:15 +04:00
/// @brief Returns information about the current compute shader
/// @return Pointer to a valid shader, nullptr on error
const ShaderInfo* ComputeShader();
2020-12-28 19:15:37 +04:00
2021-07-10 01:54:15 +04:00
/// @brief Collect the current graphics environments
void GetGraphicsEnvironments(GraphicsEnvironments& result,
const std::array<u64, NUM_PROGRAMS>& unique_hashes);
2020-12-28 19:15:37 +04:00
2021-07-10 01:54:15 +04:00
Tegra::MemoryManager& gpu_memory;
Tegra::Engines::Maxwell3D& maxwell3d;
Tegra::Engines::KeplerCompute& kepler_compute;
2020-12-28 19:15:37 +04:00
2021-07-10 01:54:15 +04:00
std::array<const ShaderInfo*, NUM_PROGRAMS> shader_infos{};
bool last_shaders_valid = false;
2020-12-28 19:15:37 +04:00
private:
2021-07-10 01:54:15 +04:00
/// @brief Tries to obtain a cached shader starting in a given address
/// @note Doesn't check for ranges, the given address has to be the start of the shader
/// @param addr Start address of the shader, this doesn't cache for region
/// @return Pointer to a valid shader, nullptr when nothing is found
ShaderInfo* TryGet(VAddr addr) const;
/// @brief Register in the cache a given entry
/// @param data Shader to store in the cache
/// @param addr Start address of the shader that will be registered
/// @param size Size in bytes of the shader
void Register(std::unique_ptr<ShaderInfo> data, VAddr addr, size_t size);
2020-12-28 19:15:37 +04:00
/// @brief Invalidate pages in a given region
/// @pre invalidation_mutex is locked
2021-07-10 01:54:15 +04:00
void InvalidatePagesInRegion(VAddr addr, size_t size);
2020-12-28 19:15:37 +04:00
/// @brief Remove shaders marked for deletion
/// @pre invalidation_mutex is locked
2021-07-10 01:54:15 +04:00
void RemovePendingShaders();
2020-12-28 19:15:37 +04:00
/// @brief Invalidates entries in a given range for the passed page
/// @param entries Vector of entries in the page, it will be modified on overlaps
/// @param addr Start address of the invalidation
/// @param addr_end Non-inclusive end address of the invalidation
/// @pre invalidation_mutex is locked
2021-07-10 01:54:15 +04:00
void InvalidatePageEntries(std::vector<Entry*>& entries, VAddr addr, VAddr addr_end);
2020-12-28 19:15:37 +04:00
/// @brief Removes all references to an entry in the invalidation cache
/// @param entry Entry to remove from the invalidation cache
/// @pre invalidation_mutex is locked
2021-07-10 01:54:15 +04:00
void RemoveEntryFromInvalidationCache(const Entry* entry);
2020-12-28 19:15:37 +04:00
/// @brief Unmarks an entry from the rasterizer cache
/// @param entry Entry to unmark from memory
2021-07-10 01:54:15 +04:00
void UnmarkMemory(Entry* entry);
2020-12-28 19:15:37 +04:00
/// @brief Removes a vector of shaders from a list
/// @param removed_shaders Shaders to be removed from the storage
/// @pre invalidation_mutex is locked
/// @pre lookup_mutex is locked
2021-07-10 01:54:15 +04:00
void RemoveShadersFromStorage(std::vector<ShaderInfo*> removed_shaders);
2020-12-28 19:15:37 +04:00
/// @brief Creates a new entry in the lookup cache and returns its pointer
/// @pre lookup_mutex is locked
2021-07-10 01:54:15 +04:00
Entry* NewEntry(VAddr addr, VAddr addr_end, ShaderInfo* data);
2020-12-28 19:15:37 +04:00
2021-07-10 01:54:15 +04:00
/// @brief Create a new shader entry and register it
const ShaderInfo* MakeShaderInfo(GenericEnvironment& env, VAddr cpu_addr);
2020-12-28 19:15:37 +04:00
VideoCore::RasterizerInterface& rasterizer;
mutable std::mutex lookup_mutex;
std::mutex invalidation_mutex;
std::unordered_map<u64, std::unique_ptr<Entry>> lookup_cache;
std::unordered_map<u64, std::vector<Entry*>> invalidation_cache;
2021-07-10 01:54:15 +04:00
std::vector<std::unique_ptr<ShaderInfo>> storage;
2020-12-28 19:15:37 +04:00
std::vector<Entry*> marked_for_removal;
};
} // namespace VideoCommon