forked from suyu/suyu
Merge pull request #6820 from yzct12345/split-cache
texture_cache: Split out template definitions
This commit is contained in:
commit
6a082df427
13 changed files with 420 additions and 427 deletions
|
@ -97,6 +97,7 @@ add_library(video_core STATIC
|
||||||
renderer_opengl/gl_stream_buffer.h
|
renderer_opengl/gl_stream_buffer.h
|
||||||
renderer_opengl/gl_texture_cache.cpp
|
renderer_opengl/gl_texture_cache.cpp
|
||||||
renderer_opengl/gl_texture_cache.h
|
renderer_opengl/gl_texture_cache.h
|
||||||
|
renderer_opengl/gl_texture_cache_base.cpp
|
||||||
renderer_opengl/gl_query_cache.cpp
|
renderer_opengl/gl_query_cache.cpp
|
||||||
renderer_opengl/gl_query_cache.h
|
renderer_opengl/gl_query_cache.h
|
||||||
renderer_opengl/maxwell_to_gl.h
|
renderer_opengl/maxwell_to_gl.h
|
||||||
|
@ -155,6 +156,7 @@ add_library(video_core STATIC
|
||||||
renderer_vulkan/vk_swapchain.h
|
renderer_vulkan/vk_swapchain.h
|
||||||
renderer_vulkan/vk_texture_cache.cpp
|
renderer_vulkan/vk_texture_cache.cpp
|
||||||
renderer_vulkan/vk_texture_cache.h
|
renderer_vulkan/vk_texture_cache.h
|
||||||
|
renderer_vulkan/vk_texture_cache_base.cpp
|
||||||
renderer_vulkan/vk_update_descriptor.cpp
|
renderer_vulkan/vk_update_descriptor.cpp
|
||||||
renderer_vulkan/vk_update_descriptor.h
|
renderer_vulkan/vk_update_descriptor.h
|
||||||
shader_cache.cpp
|
shader_cache.cpp
|
||||||
|
@ -186,6 +188,7 @@ add_library(video_core STATIC
|
||||||
texture_cache/samples_helper.h
|
texture_cache/samples_helper.h
|
||||||
texture_cache/slot_vector.h
|
texture_cache/slot_vector.h
|
||||||
texture_cache/texture_cache.h
|
texture_cache/texture_cache.h
|
||||||
|
texture_cache/texture_cache_base.h
|
||||||
texture_cache/types.h
|
texture_cache/types.h
|
||||||
texture_cache/util.cpp
|
texture_cache/util.cpp
|
||||||
texture_cache/util.h
|
texture_cache/util.h
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||||
#include "video_core/renderer_opengl/gl_state_tracker.h"
|
#include "video_core/renderer_opengl/gl_state_tracker.h"
|
||||||
#include "video_core/shader_notify.h"
|
#include "video_core/shader_notify.h"
|
||||||
#include "video_core/texture_cache/texture_cache.h"
|
#include "video_core/texture_cache/texture_cache_base.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && defined(NDEBUG)
|
#if defined(_MSC_VER) && defined(NDEBUG)
|
||||||
#define LAMBDA_FORCEINLINE [[msvc::forceinline]]
|
#define LAMBDA_FORCEINLINE [[msvc::forceinline]]
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include "video_core/renderer_opengl/maxwell_to_gl.h"
|
#include "video_core/renderer_opengl/maxwell_to_gl.h"
|
||||||
#include "video_core/renderer_opengl/renderer_opengl.h"
|
#include "video_core/renderer_opengl/renderer_opengl.h"
|
||||||
#include "video_core/shader_cache.h"
|
#include "video_core/shader_cache.h"
|
||||||
#include "video_core/texture_cache/texture_cache.h"
|
#include "video_core/texture_cache/texture_cache_base.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,8 @@
|
||||||
#include "video_core/renderer_opengl/maxwell_to_gl.h"
|
#include "video_core/renderer_opengl/maxwell_to_gl.h"
|
||||||
#include "video_core/renderer_opengl/util_shaders.h"
|
#include "video_core/renderer_opengl/util_shaders.h"
|
||||||
#include "video_core/surface.h"
|
#include "video_core/surface.h"
|
||||||
#include "video_core/texture_cache/format_lookup_table.h"
|
#include "video_core/texture_cache/formatter.h"
|
||||||
#include "video_core/texture_cache/samples_helper.h"
|
#include "video_core/texture_cache/samples_helper.h"
|
||||||
#include "video_core/texture_cache/texture_cache.h"
|
|
||||||
#include "video_core/textures/decoders.h"
|
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "shader_recompiler/shader_info.h"
|
#include "shader_recompiler/shader_info.h"
|
||||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||||
#include "video_core/renderer_opengl/util_shaders.h"
|
#include "video_core/renderer_opengl/util_shaders.h"
|
||||||
#include "video_core/texture_cache/texture_cache.h"
|
#include "video_core/texture_cache/texture_cache_base.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
|
|
10
src/video_core/renderer_opengl/gl_texture_cache_base.cpp
Normal file
10
src/video_core/renderer_opengl/gl_texture_cache_base.cpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright 2021 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "video_core/renderer_opengl/gl_texture_cache.h"
|
||||||
|
#include "video_core/texture_cache/texture_cache.h"
|
||||||
|
|
||||||
|
namespace VideoCommon {
|
||||||
|
template class VideoCommon::TextureCache<OpenGL::TextureCacheParams>;
|
||||||
|
}
|
|
@ -32,7 +32,7 @@
|
||||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||||
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
||||||
#include "video_core/shader_cache.h"
|
#include "video_core/shader_cache.h"
|
||||||
#include "video_core/texture_cache/texture_cache.h"
|
#include "video_core/texture_cache/texture_cache_base.h"
|
||||||
#include "video_core/vulkan_common/vulkan_device.h"
|
#include "video_core/vulkan_common/vulkan_device.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||||
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
|
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
|
||||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||||
|
#include "video_core/texture_cache/formatter.h"
|
||||||
|
#include "video_core/texture_cache/samples_helper.h"
|
||||||
#include "video_core/vulkan_common/vulkan_device.h"
|
#include "video_core/vulkan_common/vulkan_device.h"
|
||||||
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
|
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
#include "shader_recompiler/shader_info.h"
|
#include "shader_recompiler/shader_info.h"
|
||||||
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
|
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
|
||||||
#include "video_core/texture_cache/texture_cache.h"
|
#include "video_core/texture_cache/texture_cache_base.h"
|
||||||
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
|
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
|
|
10
src/video_core/renderer_vulkan/vk_texture_cache_base.cpp
Normal file
10
src/video_core/renderer_vulkan/vk_texture_cache_base.cpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright 2021 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||||
|
#include "video_core/texture_cache/texture_cache.h"
|
||||||
|
|
||||||
|
namespace VideoCommon {
|
||||||
|
template class VideoCommon::TextureCache<Vulkan::TextureCacheParams>;
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "video_core/texture_cache/image_view_info.h"
|
#include "video_core/texture_cache/image_view_info.h"
|
||||||
#include "video_core/texture_cache/texture_cache.h"
|
#include "video_core/texture_cache/texture_cache_base.h"
|
||||||
#include "video_core/texture_cache/types.h"
|
#include "video_core/texture_cache/types.h"
|
||||||
#include "video_core/textures/texture.h"
|
#include "video_core/textures/texture.h"
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ namespace VideoCommon {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using Tegra::Texture::TextureType;
|
||||||
|
|
||||||
constexpr u8 RENDER_TARGET_SWIZZLE = std::numeric_limits<u8>::max();
|
constexpr u8 RENDER_TARGET_SWIZZLE = std::numeric_limits<u8>::max();
|
||||||
|
|
||||||
[[nodiscard]] u8 CastSwizzle(SwizzleSource source) {
|
[[nodiscard]] u8 CastSwizzle(SwizzleSource source) {
|
||||||
|
|
|
@ -4,48 +4,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
|
||||||
#include <bit>
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#include <optional>
|
|
||||||
#include <span>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <boost/container/small_vector.hpp>
|
|
||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/literals.h"
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "video_core/compatible_formats.h"
|
|
||||||
#include "video_core/delayed_destruction_ring.h"
|
|
||||||
#include "video_core/dirty_flags.h"
|
#include "video_core/dirty_flags.h"
|
||||||
#include "video_core/engines/fermi_2d.h"
|
|
||||||
#include "video_core/engines/kepler_compute.h"
|
|
||||||
#include "video_core/engines/maxwell_3d.h"
|
|
||||||
#include "video_core/memory_manager.h"
|
|
||||||
#include "video_core/rasterizer_interface.h"
|
|
||||||
#include "video_core/surface.h"
|
|
||||||
#include "video_core/texture_cache/descriptor_table.h"
|
|
||||||
#include "video_core/texture_cache/format_lookup_table.h"
|
|
||||||
#include "video_core/texture_cache/formatter.h"
|
|
||||||
#include "video_core/texture_cache/image_base.h"
|
|
||||||
#include "video_core/texture_cache/image_info.h"
|
|
||||||
#include "video_core/texture_cache/image_view_base.h"
|
|
||||||
#include "video_core/texture_cache/image_view_info.h"
|
|
||||||
#include "video_core/texture_cache/render_targets.h"
|
|
||||||
#include "video_core/texture_cache/samples_helper.h"
|
#include "video_core/texture_cache/samples_helper.h"
|
||||||
#include "video_core/texture_cache/slot_vector.h"
|
#include "video_core/texture_cache/texture_cache_base.h"
|
||||||
#include "video_core/texture_cache/types.h"
|
|
||||||
#include "video_core/texture_cache/util.h"
|
|
||||||
#include "video_core/textures/texture.h"
|
|
||||||
|
|
||||||
namespace VideoCommon {
|
namespace VideoCommon {
|
||||||
|
|
||||||
|
@ -61,352 +24,6 @@ using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
|
||||||
using VideoCore::Surface::SurfaceType;
|
using VideoCore::Surface::SurfaceType;
|
||||||
using namespace Common::Literals;
|
using namespace Common::Literals;
|
||||||
|
|
||||||
template <class P>
|
|
||||||
class TextureCache {
|
|
||||||
/// Address shift for caching images into a hash table
|
|
||||||
static constexpr u64 PAGE_BITS = 20;
|
|
||||||
|
|
||||||
/// Enables debugging features to the texture cache
|
|
||||||
static constexpr bool ENABLE_VALIDATION = P::ENABLE_VALIDATION;
|
|
||||||
/// Implement blits as copies between framebuffers
|
|
||||||
static constexpr bool FRAMEBUFFER_BLITS = P::FRAMEBUFFER_BLITS;
|
|
||||||
/// True when some copies have to be emulated
|
|
||||||
static constexpr bool HAS_EMULATED_COPIES = P::HAS_EMULATED_COPIES;
|
|
||||||
/// True when the API can provide info about the memory of the device.
|
|
||||||
static constexpr bool HAS_DEVICE_MEMORY_INFO = P::HAS_DEVICE_MEMORY_INFO;
|
|
||||||
|
|
||||||
/// Image view ID for null descriptors
|
|
||||||
static constexpr ImageViewId NULL_IMAGE_VIEW_ID{0};
|
|
||||||
/// Sampler ID for bugged sampler ids
|
|
||||||
static constexpr SamplerId NULL_SAMPLER_ID{0};
|
|
||||||
|
|
||||||
static constexpr u64 DEFAULT_EXPECTED_MEMORY = 1_GiB;
|
|
||||||
static constexpr u64 DEFAULT_CRITICAL_MEMORY = 2_GiB;
|
|
||||||
|
|
||||||
using Runtime = typename P::Runtime;
|
|
||||||
using Image = typename P::Image;
|
|
||||||
using ImageAlloc = typename P::ImageAlloc;
|
|
||||||
using ImageView = typename P::ImageView;
|
|
||||||
using Sampler = typename P::Sampler;
|
|
||||||
using Framebuffer = typename P::Framebuffer;
|
|
||||||
|
|
||||||
struct BlitImages {
|
|
||||||
ImageId dst_id;
|
|
||||||
ImageId src_id;
|
|
||||||
PixelFormat dst_format;
|
|
||||||
PixelFormat src_format;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct IdentityHash {
|
|
||||||
[[nodiscard]] size_t operator()(T value) const noexcept {
|
|
||||||
return static_cast<size_t>(value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit TextureCache(Runtime&, VideoCore::RasterizerInterface&, Tegra::Engines::Maxwell3D&,
|
|
||||||
Tegra::Engines::KeplerCompute&, Tegra::MemoryManager&);
|
|
||||||
|
|
||||||
/// Notify the cache that a new frame has been queued
|
|
||||||
void TickFrame();
|
|
||||||
|
|
||||||
/// Return a constant reference to the given image view id
|
|
||||||
[[nodiscard]] const ImageView& GetImageView(ImageViewId id) const noexcept;
|
|
||||||
|
|
||||||
/// Return a reference to the given image view id
|
|
||||||
[[nodiscard]] ImageView& GetImageView(ImageViewId id) noexcept;
|
|
||||||
|
|
||||||
/// Mark an image as modified from the GPU
|
|
||||||
void MarkModification(ImageId id) noexcept;
|
|
||||||
|
|
||||||
/// Fill image_view_ids with the graphics images in indices
|
|
||||||
void FillGraphicsImageViews(std::span<const u32> indices,
|
|
||||||
std::span<ImageViewId> image_view_ids);
|
|
||||||
|
|
||||||
/// Fill image_view_ids with the compute images in indices
|
|
||||||
void FillComputeImageViews(std::span<const u32> indices, std::span<ImageViewId> image_view_ids);
|
|
||||||
|
|
||||||
/// Get the sampler from the graphics descriptor table in the specified index
|
|
||||||
Sampler* GetGraphicsSampler(u32 index);
|
|
||||||
|
|
||||||
/// Get the sampler from the compute descriptor table in the specified index
|
|
||||||
Sampler* GetComputeSampler(u32 index);
|
|
||||||
|
|
||||||
/// Refresh the state for graphics image view and sampler descriptors
|
|
||||||
void SynchronizeGraphicsDescriptors();
|
|
||||||
|
|
||||||
/// Refresh the state for compute image view and sampler descriptors
|
|
||||||
void SynchronizeComputeDescriptors();
|
|
||||||
|
|
||||||
/// Update bound render targets and upload memory if necessary
|
|
||||||
/// @param is_clear True when the render targets are being used for clears
|
|
||||||
void UpdateRenderTargets(bool is_clear);
|
|
||||||
|
|
||||||
/// Find a framebuffer with the currently bound render targets
|
|
||||||
/// UpdateRenderTargets should be called before this
|
|
||||||
Framebuffer* GetFramebuffer();
|
|
||||||
|
|
||||||
/// Mark images in a range as modified from the CPU
|
|
||||||
void WriteMemory(VAddr cpu_addr, size_t size);
|
|
||||||
|
|
||||||
/// Download contents of host images to guest memory in a region
|
|
||||||
void DownloadMemory(VAddr cpu_addr, size_t size);
|
|
||||||
|
|
||||||
/// Remove images in a region
|
|
||||||
void UnmapMemory(VAddr cpu_addr, size_t size);
|
|
||||||
|
|
||||||
/// Remove images in a region
|
|
||||||
void UnmapGPUMemory(GPUVAddr gpu_addr, size_t size);
|
|
||||||
|
|
||||||
/// Blit an image with the given parameters
|
|
||||||
void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
|
|
||||||
const Tegra::Engines::Fermi2D::Surface& src,
|
|
||||||
const Tegra::Engines::Fermi2D::Config& copy);
|
|
||||||
|
|
||||||
/// Invalidate the contents of the color buffer index
|
|
||||||
/// These contents become unspecified, the cache can assume aggressive optimizations.
|
|
||||||
void InvalidateColorBuffer(size_t index);
|
|
||||||
|
|
||||||
/// Invalidate the contents of the depth buffer
|
|
||||||
/// These contents become unspecified, the cache can assume aggressive optimizations.
|
|
||||||
void InvalidateDepthBuffer();
|
|
||||||
|
|
||||||
/// Try to find a cached image view in the given CPU address
|
|
||||||
[[nodiscard]] ImageView* TryFindFramebufferImageView(VAddr cpu_addr);
|
|
||||||
|
|
||||||
/// Return true when there are uncommitted images to be downloaded
|
|
||||||
[[nodiscard]] bool HasUncommittedFlushes() const noexcept;
|
|
||||||
|
|
||||||
/// Return true when the caller should wait for async downloads
|
|
||||||
[[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept;
|
|
||||||
|
|
||||||
/// Commit asynchronous downloads
|
|
||||||
void CommitAsyncFlushes();
|
|
||||||
|
|
||||||
/// Pop asynchronous downloads
|
|
||||||
void PopAsyncFlushes();
|
|
||||||
|
|
||||||
/// Return true when a CPU region is modified from the GPU
|
|
||||||
[[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size);
|
|
||||||
|
|
||||||
std::mutex mutex;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Iterate over all page indices in a range
|
|
||||||
template <typename Func>
|
|
||||||
static void ForEachCPUPage(VAddr addr, size_t size, Func&& func) {
|
|
||||||
static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
|
|
||||||
const u64 page_end = (addr + size - 1) >> PAGE_BITS;
|
|
||||||
for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
|
|
||||||
if constexpr (RETURNS_BOOL) {
|
|
||||||
if (func(page)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
func(page);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Func>
|
|
||||||
static void ForEachGPUPage(GPUVAddr addr, size_t size, Func&& func) {
|
|
||||||
static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
|
|
||||||
const u64 page_end = (addr + size - 1) >> PAGE_BITS;
|
|
||||||
for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
|
|
||||||
if constexpr (RETURNS_BOOL) {
|
|
||||||
if (func(page)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
func(page);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs the Garbage Collector.
|
|
||||||
void RunGarbageCollector();
|
|
||||||
|
|
||||||
/// Fills image_view_ids in the image views in indices
|
|
||||||
void FillImageViews(DescriptorTable<TICEntry>& table,
|
|
||||||
std::span<ImageViewId> cached_image_view_ids, std::span<const u32> indices,
|
|
||||||
std::span<ImageViewId> image_view_ids);
|
|
||||||
|
|
||||||
/// Find or create an image view in the guest descriptor table
|
|
||||||
ImageViewId VisitImageView(DescriptorTable<TICEntry>& table,
|
|
||||||
std::span<ImageViewId> cached_image_view_ids, u32 index);
|
|
||||||
|
|
||||||
/// Find or create a framebuffer with the given render target parameters
|
|
||||||
FramebufferId GetFramebufferId(const RenderTargets& key);
|
|
||||||
|
|
||||||
/// Refresh the contents (pixel data) of an image
|
|
||||||
void RefreshContents(Image& image, ImageId image_id);
|
|
||||||
|
|
||||||
/// Upload data from guest to an image
|
|
||||||
template <typename StagingBuffer>
|
|
||||||
void UploadImageContents(Image& image, StagingBuffer& staging_buffer);
|
|
||||||
|
|
||||||
/// Find or create an image view from a guest descriptor
|
|
||||||
[[nodiscard]] ImageViewId FindImageView(const TICEntry& config);
|
|
||||||
|
|
||||||
/// Create a new image view from a guest descriptor
|
|
||||||
[[nodiscard]] ImageViewId CreateImageView(const TICEntry& config);
|
|
||||||
|
|
||||||
/// Find or create an image from the given parameters
|
|
||||||
[[nodiscard]] ImageId FindOrInsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
|
|
||||||
RelaxedOptions options = RelaxedOptions{});
|
|
||||||
|
|
||||||
/// Find an image from the given parameters
|
|
||||||
[[nodiscard]] ImageId FindImage(const ImageInfo& info, GPUVAddr gpu_addr,
|
|
||||||
RelaxedOptions options);
|
|
||||||
|
|
||||||
/// Create an image from the given parameters
|
|
||||||
[[nodiscard]] ImageId InsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
|
|
||||||
RelaxedOptions options);
|
|
||||||
|
|
||||||
/// Create a new image and join perfectly matching existing images
|
|
||||||
/// Remove joined images from the cache
|
|
||||||
[[nodiscard]] ImageId JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VAddr cpu_addr);
|
|
||||||
|
|
||||||
/// Return a blit image pair from the given guest blit parameters
|
|
||||||
[[nodiscard]] BlitImages GetBlitImages(const Tegra::Engines::Fermi2D::Surface& dst,
|
|
||||||
const Tegra::Engines::Fermi2D::Surface& src);
|
|
||||||
|
|
||||||
/// Find or create a sampler from a guest descriptor sampler
|
|
||||||
[[nodiscard]] SamplerId FindSampler(const TSCEntry& config);
|
|
||||||
|
|
||||||
/// Find or create an image view for the given color buffer index
|
|
||||||
[[nodiscard]] ImageViewId FindColorBuffer(size_t index, bool is_clear);
|
|
||||||
|
|
||||||
/// Find or create an image view for the depth buffer
|
|
||||||
[[nodiscard]] ImageViewId FindDepthBuffer(bool is_clear);
|
|
||||||
|
|
||||||
/// Find or create a view for a render target with the given image parameters
|
|
||||||
[[nodiscard]] ImageViewId FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr,
|
|
||||||
bool is_clear);
|
|
||||||
|
|
||||||
/// Iterates over all the images in a region calling func
|
|
||||||
template <typename Func>
|
|
||||||
void ForEachImageInRegion(VAddr cpu_addr, size_t size, Func&& func);
|
|
||||||
|
|
||||||
template <typename Func>
|
|
||||||
void ForEachImageInRegionGPU(GPUVAddr gpu_addr, size_t size, Func&& func);
|
|
||||||
|
|
||||||
template <typename Func>
|
|
||||||
void ForEachSparseImageInRegion(GPUVAddr gpu_addr, size_t size, Func&& func);
|
|
||||||
|
|
||||||
/// Iterates over all the images in a region calling func
|
|
||||||
template <typename Func>
|
|
||||||
void ForEachSparseSegment(ImageBase& image, Func&& func);
|
|
||||||
|
|
||||||
/// Find or create an image view in the given image with the passed parameters
|
|
||||||
[[nodiscard]] ImageViewId FindOrEmplaceImageView(ImageId image_id, const ImageViewInfo& info);
|
|
||||||
|
|
||||||
/// Register image in the page table
|
|
||||||
void RegisterImage(ImageId image);
|
|
||||||
|
|
||||||
/// Unregister image from the page table
|
|
||||||
void UnregisterImage(ImageId image);
|
|
||||||
|
|
||||||
/// Track CPU reads and writes for image
|
|
||||||
void TrackImage(ImageBase& image, ImageId image_id);
|
|
||||||
|
|
||||||
/// Stop tracking CPU reads and writes for image
|
|
||||||
void UntrackImage(ImageBase& image, ImageId image_id);
|
|
||||||
|
|
||||||
/// Delete image from the cache
|
|
||||||
void DeleteImage(ImageId image);
|
|
||||||
|
|
||||||
/// Remove image views references from the cache
|
|
||||||
void RemoveImageViewReferences(std::span<const ImageViewId> removed_views);
|
|
||||||
|
|
||||||
/// Remove framebuffers using the given image views from the cache
|
|
||||||
void RemoveFramebuffers(std::span<const ImageViewId> removed_views);
|
|
||||||
|
|
||||||
/// Mark an image as modified from the GPU
|
|
||||||
void MarkModification(ImageBase& image) noexcept;
|
|
||||||
|
|
||||||
/// Synchronize image aliases, copying data if needed
|
|
||||||
void SynchronizeAliases(ImageId image_id);
|
|
||||||
|
|
||||||
/// Prepare an image to be used
|
|
||||||
void PrepareImage(ImageId image_id, bool is_modification, bool invalidate);
|
|
||||||
|
|
||||||
/// Prepare an image view to be used
|
|
||||||
void PrepareImageView(ImageViewId image_view_id, bool is_modification, bool invalidate);
|
|
||||||
|
|
||||||
/// Execute copies from one image to the other, even if they are incompatible
|
|
||||||
void CopyImage(ImageId dst_id, ImageId src_id, std::span<const ImageCopy> copies);
|
|
||||||
|
|
||||||
/// Bind an image view as render target, downloading resources preemtively if needed
|
|
||||||
void BindRenderTarget(ImageViewId* old_id, ImageViewId new_id);
|
|
||||||
|
|
||||||
/// Create a render target from a given image and image view parameters
|
|
||||||
[[nodiscard]] std::pair<FramebufferId, ImageViewId> RenderTargetFromImage(
|
|
||||||
ImageId, const ImageViewInfo& view_info);
|
|
||||||
|
|
||||||
/// Returns true if the current clear parameters clear the whole image of a given image view
|
|
||||||
[[nodiscard]] bool IsFullClear(ImageViewId id);
|
|
||||||
|
|
||||||
Runtime& runtime;
|
|
||||||
VideoCore::RasterizerInterface& rasterizer;
|
|
||||||
Tegra::Engines::Maxwell3D& maxwell3d;
|
|
||||||
Tegra::Engines::KeplerCompute& kepler_compute;
|
|
||||||
Tegra::MemoryManager& gpu_memory;
|
|
||||||
|
|
||||||
DescriptorTable<TICEntry> graphics_image_table{gpu_memory};
|
|
||||||
DescriptorTable<TSCEntry> graphics_sampler_table{gpu_memory};
|
|
||||||
std::vector<SamplerId> graphics_sampler_ids;
|
|
||||||
std::vector<ImageViewId> graphics_image_view_ids;
|
|
||||||
|
|
||||||
DescriptorTable<TICEntry> compute_image_table{gpu_memory};
|
|
||||||
DescriptorTable<TSCEntry> compute_sampler_table{gpu_memory};
|
|
||||||
std::vector<SamplerId> compute_sampler_ids;
|
|
||||||
std::vector<ImageViewId> compute_image_view_ids;
|
|
||||||
|
|
||||||
RenderTargets render_targets;
|
|
||||||
|
|
||||||
std::unordered_map<TICEntry, ImageViewId> image_views;
|
|
||||||
std::unordered_map<TSCEntry, SamplerId> samplers;
|
|
||||||
std::unordered_map<RenderTargets, FramebufferId> framebuffers;
|
|
||||||
|
|
||||||
std::unordered_map<u64, std::vector<ImageMapId>, IdentityHash<u64>> page_table;
|
|
||||||
std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> gpu_page_table;
|
|
||||||
std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> sparse_page_table;
|
|
||||||
|
|
||||||
std::unordered_map<ImageId, std::vector<ImageViewId>> sparse_views;
|
|
||||||
|
|
||||||
VAddr virtual_invalid_space{};
|
|
||||||
|
|
||||||
bool has_deleted_images = false;
|
|
||||||
u64 total_used_memory = 0;
|
|
||||||
u64 minimum_memory;
|
|
||||||
u64 expected_memory;
|
|
||||||
u64 critical_memory;
|
|
||||||
|
|
||||||
SlotVector<Image> slot_images;
|
|
||||||
SlotVector<ImageMapView> slot_map_views;
|
|
||||||
SlotVector<ImageView> slot_image_views;
|
|
||||||
SlotVector<ImageAlloc> slot_image_allocs;
|
|
||||||
SlotVector<Sampler> slot_samplers;
|
|
||||||
SlotVector<Framebuffer> slot_framebuffers;
|
|
||||||
|
|
||||||
// TODO: This data structure is not optimal and it should be reworked
|
|
||||||
std::vector<ImageId> uncommitted_downloads;
|
|
||||||
std::queue<std::vector<ImageId>> committed_downloads;
|
|
||||||
|
|
||||||
static constexpr size_t TICKS_TO_DESTROY = 6;
|
|
||||||
DelayedDestructionRing<Image, TICKS_TO_DESTROY> sentenced_images;
|
|
||||||
DelayedDestructionRing<ImageView, TICKS_TO_DESTROY> sentenced_image_view;
|
|
||||||
DelayedDestructionRing<Framebuffer, TICKS_TO_DESTROY> sentenced_framebuffers;
|
|
||||||
|
|
||||||
std::unordered_map<GPUVAddr, ImageAllocId> image_allocs_table;
|
|
||||||
|
|
||||||
u64 modification_tick = 0;
|
|
||||||
u64 frame_tick = 0;
|
|
||||||
typename SlotVector<Image>::Iterator deletion_iterator;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface& rasterizer_,
|
TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface& rasterizer_,
|
||||||
Tegra::Engines::Maxwell3D& maxwell3d_,
|
Tegra::Engines::Maxwell3D& maxwell3d_,
|
||||||
|
@ -820,40 +437,6 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
|
||||||
void TextureCache<P>::InvalidateColorBuffer(size_t index) {
|
|
||||||
ImageViewId& color_buffer_id = render_targets.color_buffer_ids[index];
|
|
||||||
color_buffer_id = FindColorBuffer(index, false);
|
|
||||||
if (!color_buffer_id) {
|
|
||||||
LOG_ERROR(HW_GPU, "Invalidating invalid color buffer in index={}", index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// When invalidating a color buffer, the old contents are no longer relevant
|
|
||||||
ImageView& color_buffer = slot_image_views[color_buffer_id];
|
|
||||||
Image& image = slot_images[color_buffer.image_id];
|
|
||||||
image.flags &= ~ImageFlagBits::CpuModified;
|
|
||||||
image.flags &= ~ImageFlagBits::GpuModified;
|
|
||||||
|
|
||||||
runtime.InvalidateColorBuffer(color_buffer, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class P>
|
|
||||||
void TextureCache<P>::InvalidateDepthBuffer() {
|
|
||||||
ImageViewId& depth_buffer_id = render_targets.depth_buffer_id;
|
|
||||||
depth_buffer_id = FindDepthBuffer(false);
|
|
||||||
if (!depth_buffer_id) {
|
|
||||||
LOG_ERROR(HW_GPU, "Invalidating invalid depth buffer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// When invalidating the depth buffer, the old contents are no longer relevant
|
|
||||||
ImageBase& image = slot_images[slot_image_views[depth_buffer_id].image_id];
|
|
||||||
image.flags &= ~ImageFlagBits::CpuModified;
|
|
||||||
image.flags &= ~ImageFlagBits::GpuModified;
|
|
||||||
|
|
||||||
ImageView& depth_buffer = slot_image_views[depth_buffer_id];
|
|
||||||
runtime.InvalidateDepthBuffer(depth_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView(VAddr cpu_addr) {
|
typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView(VAddr cpu_addr) {
|
||||||
// TODO: Properly implement this
|
// TODO: Properly implement this
|
||||||
|
|
385
src/video_core/texture_cache/texture_cache_base.h
Normal file
385
src/video_core/texture_cache/texture_cache_base.h
Normal file
|
@ -0,0 +1,385 @@
|
||||||
|
// Copyright 2019 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <mutex>
|
||||||
|
#include <span>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/literals.h"
|
||||||
|
#include "video_core/compatible_formats.h"
|
||||||
|
#include "video_core/delayed_destruction_ring.h"
|
||||||
|
#include "video_core/engines/fermi_2d.h"
|
||||||
|
#include "video_core/engines/kepler_compute.h"
|
||||||
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
|
#include "video_core/memory_manager.h"
|
||||||
|
#include "video_core/rasterizer_interface.h"
|
||||||
|
#include "video_core/surface.h"
|
||||||
|
#include "video_core/texture_cache/descriptor_table.h"
|
||||||
|
#include "video_core/texture_cache/image_base.h"
|
||||||
|
#include "video_core/texture_cache/image_info.h"
|
||||||
|
#include "video_core/texture_cache/image_view_info.h"
|
||||||
|
#include "video_core/texture_cache/render_targets.h"
|
||||||
|
#include "video_core/texture_cache/slot_vector.h"
|
||||||
|
#include "video_core/texture_cache/types.h"
|
||||||
|
#include "video_core/texture_cache/util.h"
|
||||||
|
#include "video_core/textures/texture.h"
|
||||||
|
|
||||||
|
namespace VideoCommon {
|
||||||
|
|
||||||
|
using Tegra::Texture::SwizzleSource;
|
||||||
|
using Tegra::Texture::TICEntry;
|
||||||
|
using Tegra::Texture::TSCEntry;
|
||||||
|
using VideoCore::Surface::GetFormatType;
|
||||||
|
using VideoCore::Surface::IsCopyCompatible;
|
||||||
|
using VideoCore::Surface::PixelFormat;
|
||||||
|
using VideoCore::Surface::PixelFormatFromDepthFormat;
|
||||||
|
using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
|
||||||
|
using namespace Common::Literals;
|
||||||
|
|
||||||
|
template <class P>
|
||||||
|
class TextureCache {
|
||||||
|
/// Address shift for caching images into a hash table
|
||||||
|
static constexpr u64 PAGE_BITS = 20;
|
||||||
|
|
||||||
|
/// Enables debugging features to the texture cache
|
||||||
|
static constexpr bool ENABLE_VALIDATION = P::ENABLE_VALIDATION;
|
||||||
|
/// Implement blits as copies between framebuffers
|
||||||
|
static constexpr bool FRAMEBUFFER_BLITS = P::FRAMEBUFFER_BLITS;
|
||||||
|
/// True when some copies have to be emulated
|
||||||
|
static constexpr bool HAS_EMULATED_COPIES = P::HAS_EMULATED_COPIES;
|
||||||
|
/// True when the API can provide info about the memory of the device.
|
||||||
|
static constexpr bool HAS_DEVICE_MEMORY_INFO = P::HAS_DEVICE_MEMORY_INFO;
|
||||||
|
|
||||||
|
/// Image view ID for null descriptors
|
||||||
|
static constexpr ImageViewId NULL_IMAGE_VIEW_ID{0};
|
||||||
|
/// Sampler ID for bugged sampler ids
|
||||||
|
static constexpr SamplerId NULL_SAMPLER_ID{0};
|
||||||
|
|
||||||
|
static constexpr u64 DEFAULT_EXPECTED_MEMORY = 1_GiB;
|
||||||
|
static constexpr u64 DEFAULT_CRITICAL_MEMORY = 2_GiB;
|
||||||
|
|
||||||
|
using Runtime = typename P::Runtime;
|
||||||
|
using Image = typename P::Image;
|
||||||
|
using ImageAlloc = typename P::ImageAlloc;
|
||||||
|
using ImageView = typename P::ImageView;
|
||||||
|
using Sampler = typename P::Sampler;
|
||||||
|
using Framebuffer = typename P::Framebuffer;
|
||||||
|
|
||||||
|
struct BlitImages {
|
||||||
|
ImageId dst_id;
|
||||||
|
ImageId src_id;
|
||||||
|
PixelFormat dst_format;
|
||||||
|
PixelFormat src_format;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct IdentityHash {
|
||||||
|
[[nodiscard]] size_t operator()(T value) const noexcept {
|
||||||
|
return static_cast<size_t>(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TextureCache(Runtime&, VideoCore::RasterizerInterface&, Tegra::Engines::Maxwell3D&,
|
||||||
|
Tegra::Engines::KeplerCompute&, Tegra::MemoryManager&);
|
||||||
|
|
||||||
|
/// Notify the cache that a new frame has been queued
|
||||||
|
void TickFrame();
|
||||||
|
|
||||||
|
/// Return a constant reference to the given image view id
|
||||||
|
[[nodiscard]] const ImageView& GetImageView(ImageViewId id) const noexcept;
|
||||||
|
|
||||||
|
/// Return a reference to the given image view id
|
||||||
|
[[nodiscard]] ImageView& GetImageView(ImageViewId id) noexcept;
|
||||||
|
|
||||||
|
/// Mark an image as modified from the GPU
|
||||||
|
void MarkModification(ImageId id) noexcept;
|
||||||
|
|
||||||
|
/// Fill image_view_ids with the graphics images in indices
|
||||||
|
void FillGraphicsImageViews(std::span<const u32> indices,
|
||||||
|
std::span<ImageViewId> image_view_ids);
|
||||||
|
|
||||||
|
/// Fill image_view_ids with the compute images in indices
|
||||||
|
void FillComputeImageViews(std::span<const u32> indices, std::span<ImageViewId> image_view_ids);
|
||||||
|
|
||||||
|
/// Get the sampler from the graphics descriptor table in the specified index
|
||||||
|
Sampler* GetGraphicsSampler(u32 index);
|
||||||
|
|
||||||
|
/// Get the sampler from the compute descriptor table in the specified index
|
||||||
|
Sampler* GetComputeSampler(u32 index);
|
||||||
|
|
||||||
|
/// Refresh the state for graphics image view and sampler descriptors
|
||||||
|
void SynchronizeGraphicsDescriptors();
|
||||||
|
|
||||||
|
/// Refresh the state for compute image view and sampler descriptors
|
||||||
|
void SynchronizeComputeDescriptors();
|
||||||
|
|
||||||
|
/// Update bound render targets and upload memory if necessary
|
||||||
|
/// @param is_clear True when the render targets are being used for clears
|
||||||
|
void UpdateRenderTargets(bool is_clear);
|
||||||
|
|
||||||
|
/// Find a framebuffer with the currently bound render targets
|
||||||
|
/// UpdateRenderTargets should be called before this
|
||||||
|
Framebuffer* GetFramebuffer();
|
||||||
|
|
||||||
|
/// Mark images in a range as modified from the CPU
|
||||||
|
void WriteMemory(VAddr cpu_addr, size_t size);
|
||||||
|
|
||||||
|
/// Download contents of host images to guest memory in a region
|
||||||
|
void DownloadMemory(VAddr cpu_addr, size_t size);
|
||||||
|
|
||||||
|
/// Remove images in a region
|
||||||
|
void UnmapMemory(VAddr cpu_addr, size_t size);
|
||||||
|
|
||||||
|
/// Remove images in a region
|
||||||
|
void UnmapGPUMemory(GPUVAddr gpu_addr, size_t size);
|
||||||
|
|
||||||
|
/// Blit an image with the given parameters
|
||||||
|
void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
|
||||||
|
const Tegra::Engines::Fermi2D::Surface& src,
|
||||||
|
const Tegra::Engines::Fermi2D::Config& copy);
|
||||||
|
|
||||||
|
/// Try to find a cached image view in the given CPU address
|
||||||
|
[[nodiscard]] ImageView* TryFindFramebufferImageView(VAddr cpu_addr);
|
||||||
|
|
||||||
|
/// Return true when there are uncommitted images to be downloaded
|
||||||
|
[[nodiscard]] bool HasUncommittedFlushes() const noexcept;
|
||||||
|
|
||||||
|
/// Return true when the caller should wait for async downloads
|
||||||
|
[[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept;
|
||||||
|
|
||||||
|
/// Commit asynchronous downloads
|
||||||
|
void CommitAsyncFlushes();
|
||||||
|
|
||||||
|
/// Pop asynchronous downloads
|
||||||
|
void PopAsyncFlushes();
|
||||||
|
|
||||||
|
/// Return true when a CPU region is modified from the GPU
|
||||||
|
[[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size);
|
||||||
|
|
||||||
|
std::mutex mutex;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Iterate over all page indices in a range
|
||||||
|
template <typename Func>
|
||||||
|
static void ForEachCPUPage(VAddr addr, size_t size, Func&& func) {
|
||||||
|
static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
|
||||||
|
const u64 page_end = (addr + size - 1) >> PAGE_BITS;
|
||||||
|
for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
|
||||||
|
if constexpr (RETURNS_BOOL) {
|
||||||
|
if (func(page)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
func(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Func>
|
||||||
|
static void ForEachGPUPage(GPUVAddr addr, size_t size, Func&& func) {
|
||||||
|
static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
|
||||||
|
const u64 page_end = (addr + size - 1) >> PAGE_BITS;
|
||||||
|
for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
|
||||||
|
if constexpr (RETURNS_BOOL) {
|
||||||
|
if (func(page)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
func(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs the Garbage Collector.
|
||||||
|
void RunGarbageCollector();
|
||||||
|
|
||||||
|
/// Fills image_view_ids in the image views in indices
|
||||||
|
void FillImageViews(DescriptorTable<TICEntry>& table,
|
||||||
|
std::span<ImageViewId> cached_image_view_ids, std::span<const u32> indices,
|
||||||
|
std::span<ImageViewId> image_view_ids);
|
||||||
|
|
||||||
|
/// Find or create an image view in the guest descriptor table
|
||||||
|
ImageViewId VisitImageView(DescriptorTable<TICEntry>& table,
|
||||||
|
std::span<ImageViewId> cached_image_view_ids, u32 index);
|
||||||
|
|
||||||
|
/// Find or create a framebuffer with the given render target parameters
|
||||||
|
FramebufferId GetFramebufferId(const RenderTargets& key);
|
||||||
|
|
||||||
|
/// Refresh the contents (pixel data) of an image
|
||||||
|
void RefreshContents(Image& image, ImageId image_id);
|
||||||
|
|
||||||
|
/// Upload data from guest to an image
|
||||||
|
template <typename StagingBuffer>
|
||||||
|
void UploadImageContents(Image& image, StagingBuffer& staging_buffer);
|
||||||
|
|
||||||
|
/// Find or create an image view from a guest descriptor
|
||||||
|
[[nodiscard]] ImageViewId FindImageView(const TICEntry& config);
|
||||||
|
|
||||||
|
/// Create a new image view from a guest descriptor
|
||||||
|
[[nodiscard]] ImageViewId CreateImageView(const TICEntry& config);
|
||||||
|
|
||||||
|
/// Find or create an image from the given parameters
|
||||||
|
[[nodiscard]] ImageId FindOrInsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
|
||||||
|
RelaxedOptions options = RelaxedOptions{});
|
||||||
|
|
||||||
|
/// Find an image from the given parameters
|
||||||
|
[[nodiscard]] ImageId FindImage(const ImageInfo& info, GPUVAddr gpu_addr,
|
||||||
|
RelaxedOptions options);
|
||||||
|
|
||||||
|
/// Create an image from the given parameters
|
||||||
|
[[nodiscard]] ImageId InsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
|
||||||
|
RelaxedOptions options);
|
||||||
|
|
||||||
|
/// Create a new image and join perfectly matching existing images
|
||||||
|
/// Remove joined images from the cache
|
||||||
|
[[nodiscard]] ImageId JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VAddr cpu_addr);
|
||||||
|
|
||||||
|
/// Return a blit image pair from the given guest blit parameters
|
||||||
|
[[nodiscard]] BlitImages GetBlitImages(const Tegra::Engines::Fermi2D::Surface& dst,
|
||||||
|
const Tegra::Engines::Fermi2D::Surface& src);
|
||||||
|
|
||||||
|
/// Find or create a sampler from a guest descriptor sampler
|
||||||
|
[[nodiscard]] SamplerId FindSampler(const TSCEntry& config);
|
||||||
|
|
||||||
|
/// Find or create an image view for the given color buffer index
|
||||||
|
[[nodiscard]] ImageViewId FindColorBuffer(size_t index, bool is_clear);
|
||||||
|
|
||||||
|
/// Find or create an image view for the depth buffer
|
||||||
|
[[nodiscard]] ImageViewId FindDepthBuffer(bool is_clear);
|
||||||
|
|
||||||
|
/// Find or create a view for a render target with the given image parameters
|
||||||
|
[[nodiscard]] ImageViewId FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr,
|
||||||
|
bool is_clear);
|
||||||
|
|
||||||
|
/// Iterates over all the images in a region calling func
|
||||||
|
template <typename Func>
|
||||||
|
void ForEachImageInRegion(VAddr cpu_addr, size_t size, Func&& func);
|
||||||
|
|
||||||
|
template <typename Func>
|
||||||
|
void ForEachImageInRegionGPU(GPUVAddr gpu_addr, size_t size, Func&& func);
|
||||||
|
|
||||||
|
template <typename Func>
|
||||||
|
void ForEachSparseImageInRegion(GPUVAddr gpu_addr, size_t size, Func&& func);
|
||||||
|
|
||||||
|
/// Iterates over all the images in a region calling func
|
||||||
|
template <typename Func>
|
||||||
|
void ForEachSparseSegment(ImageBase& image, Func&& func);
|
||||||
|
|
||||||
|
/// Find or create an image view in the given image with the passed parameters
|
||||||
|
[[nodiscard]] ImageViewId FindOrEmplaceImageView(ImageId image_id, const ImageViewInfo& info);
|
||||||
|
|
||||||
|
/// Register image in the page table
|
||||||
|
void RegisterImage(ImageId image);
|
||||||
|
|
||||||
|
/// Unregister image from the page table
|
||||||
|
void UnregisterImage(ImageId image);
|
||||||
|
|
||||||
|
/// Track CPU reads and writes for image
|
||||||
|
void TrackImage(ImageBase& image, ImageId image_id);
|
||||||
|
|
||||||
|
/// Stop tracking CPU reads and writes for image
|
||||||
|
void UntrackImage(ImageBase& image, ImageId image_id);
|
||||||
|
|
||||||
|
/// Delete image from the cache
|
||||||
|
void DeleteImage(ImageId image);
|
||||||
|
|
||||||
|
/// Remove image views references from the cache
|
||||||
|
void RemoveImageViewReferences(std::span<const ImageViewId> removed_views);
|
||||||
|
|
||||||
|
/// Remove framebuffers using the given image views from the cache
|
||||||
|
void RemoveFramebuffers(std::span<const ImageViewId> removed_views);
|
||||||
|
|
||||||
|
/// Mark an image as modified from the GPU
|
||||||
|
void MarkModification(ImageBase& image) noexcept;
|
||||||
|
|
||||||
|
/// Synchronize image aliases, copying data if needed
|
||||||
|
void SynchronizeAliases(ImageId image_id);
|
||||||
|
|
||||||
|
/// Prepare an image to be used
|
||||||
|
void PrepareImage(ImageId image_id, bool is_modification, bool invalidate);
|
||||||
|
|
||||||
|
/// Prepare an image view to be used
|
||||||
|
void PrepareImageView(ImageViewId image_view_id, bool is_modification, bool invalidate);
|
||||||
|
|
||||||
|
/// Execute copies from one image to the other, even if they are incompatible
|
||||||
|
void CopyImage(ImageId dst_id, ImageId src_id, std::span<const ImageCopy> copies);
|
||||||
|
|
||||||
|
/// Bind an image view as render target, downloading resources preemtively if needed
|
||||||
|
void BindRenderTarget(ImageViewId* old_id, ImageViewId new_id);
|
||||||
|
|
||||||
|
/// Create a render target from a given image and image view parameters
|
||||||
|
[[nodiscard]] std::pair<FramebufferId, ImageViewId> RenderTargetFromImage(
|
||||||
|
ImageId, const ImageViewInfo& view_info);
|
||||||
|
|
||||||
|
/// Returns true if the current clear parameters clear the whole image of a given image view
|
||||||
|
[[nodiscard]] bool IsFullClear(ImageViewId id);
|
||||||
|
|
||||||
|
Runtime& runtime;
|
||||||
|
VideoCore::RasterizerInterface& rasterizer;
|
||||||
|
Tegra::Engines::Maxwell3D& maxwell3d;
|
||||||
|
Tegra::Engines::KeplerCompute& kepler_compute;
|
||||||
|
Tegra::MemoryManager& gpu_memory;
|
||||||
|
|
||||||
|
DescriptorTable<TICEntry> graphics_image_table{gpu_memory};
|
||||||
|
DescriptorTable<TSCEntry> graphics_sampler_table{gpu_memory};
|
||||||
|
std::vector<SamplerId> graphics_sampler_ids;
|
||||||
|
std::vector<ImageViewId> graphics_image_view_ids;
|
||||||
|
|
||||||
|
DescriptorTable<TICEntry> compute_image_table{gpu_memory};
|
||||||
|
DescriptorTable<TSCEntry> compute_sampler_table{gpu_memory};
|
||||||
|
std::vector<SamplerId> compute_sampler_ids;
|
||||||
|
std::vector<ImageViewId> compute_image_view_ids;
|
||||||
|
|
||||||
|
RenderTargets render_targets;
|
||||||
|
|
||||||
|
std::unordered_map<TICEntry, ImageViewId> image_views;
|
||||||
|
std::unordered_map<TSCEntry, SamplerId> samplers;
|
||||||
|
std::unordered_map<RenderTargets, FramebufferId> framebuffers;
|
||||||
|
|
||||||
|
std::unordered_map<u64, std::vector<ImageMapId>, IdentityHash<u64>> page_table;
|
||||||
|
std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> gpu_page_table;
|
||||||
|
std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> sparse_page_table;
|
||||||
|
|
||||||
|
std::unordered_map<ImageId, std::vector<ImageViewId>> sparse_views;
|
||||||
|
|
||||||
|
VAddr virtual_invalid_space{};
|
||||||
|
|
||||||
|
bool has_deleted_images = false;
|
||||||
|
u64 total_used_memory = 0;
|
||||||
|
u64 minimum_memory;
|
||||||
|
u64 expected_memory;
|
||||||
|
u64 critical_memory;
|
||||||
|
|
||||||
|
SlotVector<Image> slot_images;
|
||||||
|
SlotVector<ImageMapView> slot_map_views;
|
||||||
|
SlotVector<ImageView> slot_image_views;
|
||||||
|
SlotVector<ImageAlloc> slot_image_allocs;
|
||||||
|
SlotVector<Sampler> slot_samplers;
|
||||||
|
SlotVector<Framebuffer> slot_framebuffers;
|
||||||
|
|
||||||
|
// TODO: This data structure is not optimal and it should be reworked
|
||||||
|
std::vector<ImageId> uncommitted_downloads;
|
||||||
|
std::queue<std::vector<ImageId>> committed_downloads;
|
||||||
|
|
||||||
|
static constexpr size_t TICKS_TO_DESTROY = 6;
|
||||||
|
DelayedDestructionRing<Image, TICKS_TO_DESTROY> sentenced_images;
|
||||||
|
DelayedDestructionRing<ImageView, TICKS_TO_DESTROY> sentenced_image_view;
|
||||||
|
DelayedDestructionRing<Framebuffer, TICKS_TO_DESTROY> sentenced_framebuffers;
|
||||||
|
|
||||||
|
std::unordered_map<GPUVAddr, ImageAllocId> image_allocs_table;
|
||||||
|
|
||||||
|
u64 modification_tick = 0;
|
||||||
|
u64 frame_tick = 0;
|
||||||
|
typename SlotVector<Image>::Iterator deletion_iterator;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace VideoCommon
|
Loading…
Reference in a new issue