summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/settings.cpp1
-rw-r--r--src/common/settings.h18
-rw-r--r--src/video_core/dirty_flags.h1
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp16
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h8
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp81
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h19
-rw-r--r--src/video_core/texture_cache/image_base.h4
-rw-r--r--src/video_core/texture_cache/image_info.h2
-rw-r--r--src/video_core/texture_cache/texture_cache.h113
-rw-r--r--src/video_core/texture_cache/texture_cache_base.h10
11 files changed, 255 insertions, 18 deletions
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 9dd5e3efb..8c6be2c84 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -47,6 +47,7 @@ void LogSettings() {
47 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); 47 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
48 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); 48 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
49 log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue()); 49 log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
50 log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue());
50 log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue()); 51 log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue());
51 log_setting("Renderer_UseSpeedLimit", values.use_speed_limit.GetValue()); 52 log_setting("Renderer_UseSpeedLimit", values.use_speed_limit.GetValue());
52 log_setting("Renderer_SpeedLimit", values.speed_limit.GetValue()); 53 log_setting("Renderer_SpeedLimit", values.speed_limit.GetValue());
diff --git a/src/common/settings.h b/src/common/settings.h
index 9ff4cf85d..08f3da055 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -52,6 +52,22 @@ enum class NvdecEmulation : u32 {
52 GPU = 2, 52 GPU = 2,
53}; 53};
54 54
55enum class ResolutionSetup : u32 {
56 Res1_2X = 0,
57 Res3_4X = 1,
58 Res1X = 2,
59 Res3_2K = 3,
60 Res2X = 4,
61 Res3X = 5,
62};
63
64struct ResolutionScalingInfo {
65 u32 up_scale{2};
66 u32 down_shift{0};
67 f32 up_factor{2.0f};
68 f32 down_factor{0.5f};
69};
70
55/** The BasicSetting class is a simple resource manager. It defines a label and default value 71/** The BasicSetting class is a simple resource manager. It defines a label and default value
56 * alongside the actual value of the setting for simpler and less-error prone use with frontend 72 * alongside the actual value of the setting for simpler and less-error prone use with frontend
57 * configurations. Setting a default value and label is required, though subclasses may deviate from 73 * configurations. Setting a default value and label is required, though subclasses may deviate from
@@ -451,6 +467,8 @@ struct Values {
451 "disable_shader_loop_safety_checks"}; 467 "disable_shader_loop_safety_checks"};
452 Setting<int> vulkan_device{0, "vulkan_device"}; 468 Setting<int> vulkan_device{0, "vulkan_device"};
453 469
470 ResolutionScalingInfo resolution_info{};
471 Setting<ResolutionSetup> resolution_setup{ResolutionSetup::Res1X, "resolution_setup"};
454 Setting<u16> resolution_factor{1, "resolution_factor"}; 472 Setting<u16> resolution_factor{1, "resolution_factor"};
455 // *nix platforms may have issues with the borderless windowed fullscreen mode. 473 // *nix platforms may have issues with the borderless windowed fullscreen mode.
456 // Default to exclusive fullscreen on these platforms for now. 474 // Default to exclusive fullscreen on these platforms for now.
diff --git a/src/video_core/dirty_flags.h b/src/video_core/dirty_flags.h
index f0d545f90..f11ff5d94 100644
--- a/src/video_core/dirty_flags.h
+++ b/src/video_core/dirty_flags.h
@@ -29,6 +29,7 @@ enum : u8 {
29 ColorBuffer6, 29 ColorBuffer6,
30 ColorBuffer7, 30 ColorBuffer7,
31 ZetaBuffer, 31 ZetaBuffer,
32 Rescale,
32 33
33 VertexBuffers, 34 VertexBuffers,
34 VertexBuffer0, 35 VertexBuffer0,
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 8c3ca3d82..1e594838f 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -849,6 +849,22 @@ void Image::CopyImageToBuffer(const VideoCommon::BufferImageCopy& copy, size_t b
849 } 849 }
850} 850}
851 851
852void Image::ScaleUp() {
853 if (True(flags & ImageFlagBits::Rescaled)) {
854 return;
855 }
856 flags |= ImageFlagBits::Rescaled;
857 UNIMPLEMENTED();
858}
859
860void Image::ScaleDown() {
861 if (False(flags & ImageFlagBits::Rescaled)) {
862 return;
863 }
864 flags &= ~ImageFlagBits::Rescaled;
865 UNIMPLEMENTED();
866}
867
852ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, 868ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
853 ImageId image_id_, Image& image) 869 ImageId image_id_, Image& image)
854 : VideoCommon::ImageViewBase{info, image.info, image_id_}, views{runtime.null_image_views} { 870 : VideoCommon::ImageViewBase{info, image.info, image_id_}, views{runtime.null_image_views} {
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 1ca2c90be..58b36494b 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -72,6 +72,8 @@ public:
72 StateTracker& state_tracker); 72 StateTracker& state_tracker);
73 ~TextureCacheRuntime(); 73 ~TextureCacheRuntime();
74 74
75 void Init() {}
76
75 void Finish(); 77 void Finish();
76 78
77 ImageBufferMap UploadStagingBuffer(size_t size); 79 ImageBufferMap UploadStagingBuffer(size_t size);
@@ -110,6 +112,8 @@ public:
110 112
111 bool HasNativeASTC() const noexcept; 113 bool HasNativeASTC() const noexcept;
112 114
115 void TickFrame() {}
116
113private: 117private:
114 struct StagingBuffers { 118 struct StagingBuffers {
115 explicit StagingBuffers(GLenum storage_flags_, GLenum map_flags_); 119 explicit StagingBuffers(GLenum storage_flags_, GLenum map_flags_);
@@ -185,6 +189,10 @@ public:
185 return gl_type; 189 return gl_type;
186 } 190 }
187 191
192 bool ScaleUp();
193
194 bool ScaleDown();
195
188private: 196private:
189 void CopyBufferToImage(const VideoCommon::BufferImageCopy& copy, size_t buffer_offset); 197 void CopyBufferToImage(const VideoCommon::BufferImageCopy& copy, size_t buffer_offset);
190 198
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 06c5fb867..be5b1d84d 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -32,6 +32,7 @@ using Tegra::Engines::Fermi2D;
32using Tegra::Texture::SwizzleSource; 32using Tegra::Texture::SwizzleSource;
33using Tegra::Texture::TextureMipmapFilter; 33using Tegra::Texture::TextureMipmapFilter;
34using VideoCommon::BufferImageCopy; 34using VideoCommon::BufferImageCopy;
35using VideoCommon::ImageFlagBits;
35using VideoCommon::ImageInfo; 36using VideoCommon::ImageInfo;
36using VideoCommon::ImageType; 37using VideoCommon::ImageType;
37using VideoCommon::SubresourceRange; 38using VideoCommon::SubresourceRange;
@@ -123,7 +124,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
123 } 124 }
124} 125}
125 126
126[[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info) { 127[[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info,
128 u32 up, u32 down) {
127 const PixelFormat format = StorageFormat(info.format); 129 const PixelFormat format = StorageFormat(info.format);
128 const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, format); 130 const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, format);
129 VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; 131 VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
@@ -142,9 +144,9 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
142 .imageType = ConvertImageType(info.type), 144 .imageType = ConvertImageType(info.type),
143 .format = format_info.format, 145 .format = format_info.format,
144 .extent{ 146 .extent{
145 .width = info.size.width >> samples_x, 147 .width = ((info.size.width << up) >> down) >> samples_x,
146 .height = info.size.height >> samples_y, 148 .height = ((info.size.height << up) >> down) >> samples_y,
147 .depth = info.size.depth, 149 .depth = (info.size.depth << up) >> down,
148 }, 150 },
149 .mipLevels = static_cast<u32>(info.resources.levels), 151 .mipLevels = static_cast<u32>(info.resources.levels),
150 .arrayLayers = static_cast<u32>(info.resources.layers), 152 .arrayLayers = static_cast<u32>(info.resources.layers),
@@ -158,11 +160,12 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
158 }; 160 };
159} 161}
160 162
161[[nodiscard]] vk::Image MakeImage(const Device& device, const ImageInfo& info) { 163[[nodiscard]] vk::Image MakeImage(const Device& device, const ImageInfo& info, u32 up = 0,
164 u32 down = 0) {
162 if (info.type == ImageType::Buffer) { 165 if (info.type == ImageType::Buffer) {
163 return vk::Image{}; 166 return vk::Image{};
164 } 167 }
165 return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info)); 168 return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info, up, down));
166} 169}
167 170
168[[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) { 171[[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) {
@@ -590,6 +593,11 @@ struct RangedBarrierRange {
590} 593}
591} // Anonymous namespace 594} // Anonymous namespace
592 595
596void TextureCacheRuntime::Init() {
597 resolution = Settings::values.resolution_info;
598 is_rescaling_on = resolution.up_scale != 1 || resolution.down_shift != 0;
599}
600
593void TextureCacheRuntime::Finish() { 601void TextureCacheRuntime::Finish() {
594 scheduler.Finish(); 602 scheduler.Finish();
595} 603}
@@ -840,20 +848,26 @@ u64 TextureCacheRuntime::GetDeviceLocalMemory() const {
840 return device.GetDeviceLocalMemory(); 848 return device.GetDeviceLocalMemory();
841} 849}
842 850
843Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_addr_, 851void TextureCacheRuntime::TickFrame() {
852 prescaled_images.Tick();
853 prescaled_commits.Tick();
854 prescaled_views.Tick();
855}
856
857Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_,
844 VAddr cpu_addr_) 858 VAddr cpu_addr_)
845 : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime.scheduler}, 859 : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler},
846 image(MakeImage(runtime.device, info)), 860 image(MakeImage(runtime_.device, info)),
847 commit(runtime.memory_allocator.Commit(image, MemoryUsage::DeviceLocal)), 861 commit(runtime_.memory_allocator.Commit(image, MemoryUsage::DeviceLocal)),
848 aspect_mask(ImageAspectMask(info.format)) { 862 aspect_mask(ImageAspectMask(info.format)), runtime{&runtime_} {
849 if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { 863 if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) {
850 if (Settings::values.accelerate_astc.GetValue()) { 864 if (Settings::values.accelerate_astc.GetValue()) {
851 flags |= VideoCommon::ImageFlagBits::AcceleratedUpload; 865 flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
852 } else { 866 } else {
853 flags |= VideoCommon::ImageFlagBits::Converted; 867 flags |= VideoCommon::ImageFlagBits::Converted;
854 } 868 }
855 } 869 }
856 if (runtime.device.HasDebuggingToolAttached()) { 870 if (runtime->device.HasDebuggingToolAttached()) {
857 image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); 871 image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
858 } 872 }
859 static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{ 873 static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{
@@ -861,8 +875,8 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_
861 .pNext = nullptr, 875 .pNext = nullptr,
862 .usage = VK_IMAGE_USAGE_STORAGE_BIT, 876 .usage = VK_IMAGE_USAGE_STORAGE_BIT,
863 }; 877 };
864 if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { 878 if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) {
865 const auto& device = runtime.device.GetLogical(); 879 const auto& device = runtime->device.GetLogical();
866 storage_image_views.reserve(info.resources.levels); 880 storage_image_views.reserve(info.resources.levels);
867 for (s32 level = 0; level < info.resources.levels; ++level) { 881 for (s32 level = 0; level < info.resources.levels; ++level) {
868 storage_image_views.push_back(device.CreateImageView(VkImageViewCreateInfo{ 882 storage_image_views.push_back(device.CreateImageView(VkImageViewCreateInfo{
@@ -907,6 +921,10 @@ void Image::UploadMemory(const StagingBufferRef& map, std::span<const BufferImag
907} 921}
908 922
909void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) { 923void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) {
924 const bool is_rescaled = True(flags & ImageFlagBits::Rescaled);
925 if (is_rescaled) {
926 ScaleDown();
927 }
910 std::vector vk_copies = TransformBufferImageCopies(copies, map.offset, aspect_mask); 928 std::vector vk_copies = TransformBufferImageCopies(copies, map.offset, aspect_mask);
911 scheduler->RequestOutsideRenderPassOperationContext(); 929 scheduler->RequestOutsideRenderPassOperationContext();
912 scheduler->Record([buffer = map.buffer, image = *image, aspect_mask = aspect_mask, 930 scheduler->Record([buffer = map.buffer, image = *image, aspect_mask = aspect_mask,
@@ -959,6 +977,39 @@ void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferIm
959 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 977 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
960 0, memory_write_barrier, nullptr, image_write_barrier); 978 0, memory_write_barrier, nullptr, image_write_barrier);
961 }); 979 });
980 if (is_rescaled) {
981 ScaleUp();
982 }
983}
984
985void Image::ScaleUp() {
986 if (True(flags & ImageFlagBits::Rescaled)) {
987 return;
988 }
989 ASSERT(info.type != ImageType::Linear);
990 if (!runtime->is_rescaling_on) {
991 flags |= ImageFlagBits::Rescaled;
992 return;
993 }
994 flags |= ImageFlagBits::Rescaled;
995 scaling_count++;
996 ASSERT(scaling_count < 10);
997 return;
998}
999
1000void Image::ScaleDown() {
1001 if (False(flags & ImageFlagBits::Rescaled)) {
1002 return;
1003 }
1004 ASSERT(info.type != ImageType::Linear);
1005 if (!runtime->is_rescaling_on) {
1006 flags &= ~ImageFlagBits::Rescaled;
1007 return;
1008 }
1009 flags &= ~ImageFlagBits::Rescaled;
1010 scaling_count++;
1011 ASSERT(scaling_count < 10);
1012 return;
962} 1013}
963 1014
964ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, 1015ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index b09c468e4..f7e782c44 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -6,7 +6,9 @@
6 6
7#include <span> 7#include <span>
8 8
9#include "common/settings.h"
9#include "shader_recompiler/shader_info.h" 10#include "shader_recompiler/shader_info.h"
11#include "video_core/delayed_destruction_ring.h"
10#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 12#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
11#include "video_core/texture_cache/image_view_base.h" 13#include "video_core/texture_cache/image_view_base.h"
12#include "video_core/texture_cache/texture_cache_base.h" 14#include "video_core/texture_cache/texture_cache_base.h"
@@ -15,6 +17,7 @@
15 17
16namespace Vulkan { 18namespace Vulkan {
17 19
20using VideoCommon::DelayedDestructionRing;
18using VideoCommon::ImageId; 21using VideoCommon::ImageId;
19using VideoCommon::NUM_RT; 22using VideoCommon::NUM_RT;
20using VideoCommon::Region2D; 23using VideoCommon::Region2D;
@@ -39,6 +42,14 @@ struct TextureCacheRuntime {
39 BlitImageHelper& blit_image_helper; 42 BlitImageHelper& blit_image_helper;
40 ASTCDecoderPass& astc_decoder_pass; 43 ASTCDecoderPass& astc_decoder_pass;
41 RenderPassCache& render_pass_cache; 44 RenderPassCache& render_pass_cache;
45 static constexpr size_t TICKS_TO_DESTROY = 6;
46 DelayedDestructionRing<vk::Image, TICKS_TO_DESTROY> prescaled_images;
47 DelayedDestructionRing<MemoryCommit, TICKS_TO_DESTROY> prescaled_commits;
48 DelayedDestructionRing<vk::ImageView, TICKS_TO_DESTROY> prescaled_views;
49 Settings::ResolutionScalingInfo resolution;
50 bool is_rescaling_on{};
51
52 void Init();
42 53
43 void Finish(); 54 void Finish();
44 55
@@ -74,6 +85,8 @@ struct TextureCacheRuntime {
74 return true; 85 return true;
75 } 86 }
76 87
88 void TickFrame();
89
77 u64 GetDeviceLocalMemory() const; 90 u64 GetDeviceLocalMemory() const;
78}; 91};
79 92
@@ -113,6 +126,10 @@ public:
113 return std::exchange(initialized, true); 126 return std::exchange(initialized, true);
114 } 127 }
115 128
129 void ScaleUp();
130
131 void ScaleDown();
132
116private: 133private:
117 VKScheduler* scheduler; 134 VKScheduler* scheduler;
118 vk::Image image; 135 vk::Image image;
@@ -121,6 +138,8 @@ private:
121 std::vector<vk::ImageView> storage_image_views; 138 std::vector<vk::ImageView> storage_image_views;
122 VkImageAspectFlags aspect_mask = 0; 139 VkImageAspectFlags aspect_mask = 0;
123 bool initialized = false; 140 bool initialized = false;
141 TextureCacheRuntime* runtime;
142 u32 scaling_count{};
124}; 143};
125 144
126class ImageView : public VideoCommon::ImageViewBase { 145class ImageView : public VideoCommon::ImageViewBase {
diff --git a/src/video_core/texture_cache/image_base.h b/src/video_core/texture_cache/image_base.h
index 0c17a791b..1cd30fd37 100644
--- a/src/video_core/texture_cache/image_base.h
+++ b/src/video_core/texture_cache/image_base.h
@@ -33,6 +33,10 @@ enum class ImageFlagBits : u32 {
33 ///< garbage collection priority 33 ///< garbage collection priority
34 Alias = 1 << 11, ///< This image has aliases and has priority on garbage 34 Alias = 1 << 11, ///< This image has aliases and has priority on garbage
35 ///< collection 35 ///< collection
36
37 // Rescaler
38 Rescaled = 1 << 12,
39 RescaleChecked = 1 << 13,
36}; 40};
37DECLARE_ENUM_FLAG_OPERATORS(ImageFlagBits) 41DECLARE_ENUM_FLAG_OPERATORS(ImageFlagBits)
38 42
diff --git a/src/video_core/texture_cache/image_info.h b/src/video_core/texture_cache/image_info.h
index 5049fc36e..16d4cee37 100644
--- a/src/video_core/texture_cache/image_info.h
+++ b/src/video_core/texture_cache/image_info.h
@@ -15,7 +15,7 @@ using Tegra::Texture::TICEntry;
15using VideoCore::Surface::PixelFormat; 15using VideoCore::Surface::PixelFormat;
16 16
17struct ImageInfo { 17struct ImageInfo {
18 explicit ImageInfo() = default; 18 ImageInfo() = default;
19 explicit ImageInfo(const TICEntry& config) noexcept; 19 explicit ImageInfo(const TICEntry& config) noexcept;
20 explicit ImageInfo(const Tegra::Engines::Maxwell3D::Regs& regs, size_t index) noexcept; 20 explicit ImageInfo(const Tegra::Engines::Maxwell3D::Regs& regs, size_t index) noexcept;
21 explicit ImageInfo(const Tegra::Engines::Maxwell3D::Regs& regs) noexcept; 21 explicit ImageInfo(const Tegra::Engines::Maxwell3D::Regs& regs) noexcept;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index f70c1f764..560da4f16 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -35,6 +35,7 @@ TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface&
35 Tegra::MemoryManager& gpu_memory_) 35 Tegra::MemoryManager& gpu_memory_)
36 : runtime{runtime_}, rasterizer{rasterizer_}, maxwell3d{maxwell3d_}, 36 : runtime{runtime_}, rasterizer{rasterizer_}, maxwell3d{maxwell3d_},
37 kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_} { 37 kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_} {
38 runtime.Init();
38 // Configure null sampler 39 // Configure null sampler
39 TSCEntry sampler_descriptor{}; 40 TSCEntry sampler_descriptor{};
40 sampler_descriptor.min_filter.Assign(Tegra::Texture::TextureFilter::Linear); 41 sampler_descriptor.min_filter.Assign(Tegra::Texture::TextureFilter::Linear);
@@ -103,6 +104,7 @@ void TextureCache<P>::TickFrame() {
103 sentenced_images.Tick(); 104 sentenced_images.Tick();
104 sentenced_framebuffers.Tick(); 105 sentenced_framebuffers.Tick();
105 sentenced_image_view.Tick(); 106 sentenced_image_view.Tick();
107 runtime.TickFrame();
106 ++frame_tick; 108 ++frame_tick;
107} 109}
108 110
@@ -208,18 +210,63 @@ void TextureCache<P>::UpdateRenderTargets(bool is_clear) {
208 const bool force = flags[Dirty::RenderTargetControl]; 210 const bool force = flags[Dirty::RenderTargetControl];
209 flags[Dirty::RenderTargetControl] = false; 211 flags[Dirty::RenderTargetControl] = false;
210 212
213 bool can_rescale = true;
214 std::array<ImageId, NUM_RT> tmp_color_images{};
215 ImageId tmp_depth_image{};
216 const auto check_rescale = [&](ImageViewId view_id, ImageId& id_save) {
217 if (view_id) {
218 const auto& view = slot_image_views[view_id];
219 const auto image_id = view.image_id;
220 id_save = image_id;
221 auto& image = slot_images[image_id];
222 can_rescale &= ImageCanRescale(image);
223 } else {
224 id_save = CORRUPT_ID;
225 }
226 };
211 for (size_t index = 0; index < NUM_RT; ++index) { 227 for (size_t index = 0; index < NUM_RT; ++index) {
212 ImageViewId& color_buffer_id = render_targets.color_buffer_ids[index]; 228 ImageViewId& color_buffer_id = render_targets.color_buffer_ids[index];
213 if (flags[Dirty::ColorBuffer0 + index] || force) { 229 if (flags[Dirty::ColorBuffer0 + index] || force) {
214 flags[Dirty::ColorBuffer0 + index] = false; 230 flags[Dirty::ColorBuffer0 + index] = false;
215 BindRenderTarget(&color_buffer_id, FindColorBuffer(index, is_clear)); 231 BindRenderTarget(&color_buffer_id, FindColorBuffer(index, is_clear));
216 } 232 }
217 PrepareImageView(color_buffer_id, true, is_clear && IsFullClear(color_buffer_id)); 233 check_rescale(color_buffer_id, tmp_color_images[index]);
218 } 234 }
219 if (flags[Dirty::ZetaBuffer] || force) { 235 if (flags[Dirty::ZetaBuffer] || force) {
220 flags[Dirty::ZetaBuffer] = false; 236 flags[Dirty::ZetaBuffer] = false;
221 BindRenderTarget(&render_targets.depth_buffer_id, FindDepthBuffer(is_clear)); 237 BindRenderTarget(&render_targets.depth_buffer_id, FindDepthBuffer(is_clear));
222 } 238 }
239 check_rescale(render_targets.depth_buffer_id, tmp_depth_image);
240
241 if (can_rescale) {
242 const auto scale_up = [this](ImageId image_id) {
243 if (image_id != CORRUPT_ID) {
244 Image& image = slot_images[image_id];
245 image.ScaleUp();
246 }
247 };
248 for (size_t index = 0; index < NUM_RT; ++index) {
249 scale_up(tmp_color_images[index]);
250 }
251 scale_up(tmp_depth_image);
252 } else {
253 const auto scale_down = [this](ImageId image_id) {
254 if (image_id != CORRUPT_ID) {
255 Image& image = slot_images[image_id];
256 image.ScaleDown();
257 }
258 };
259 for (size_t index = 0; index < NUM_RT; ++index) {
260 scale_down(tmp_color_images[index]);
261 }
262 scale_down(tmp_depth_image);
263 }
264 // Rescale End
265
266 for (size_t index = 0; index < NUM_RT; ++index) {
267 ImageViewId& color_buffer_id = render_targets.color_buffer_ids[index];
268 PrepareImageView(color_buffer_id, true, is_clear && IsFullClear(color_buffer_id));
269 }
223 const ImageViewId depth_buffer_id = render_targets.depth_buffer_id; 270 const ImageViewId depth_buffer_id = render_targets.depth_buffer_id;
224 271
225 PrepareImageView(depth_buffer_id, true, is_clear && IsFullClear(depth_buffer_id)); 272 PrepareImageView(depth_buffer_id, true, is_clear && IsFullClear(depth_buffer_id));
@@ -624,6 +671,31 @@ ImageId TextureCache<P>::FindImage(const ImageInfo& info, GPUVAddr gpu_addr,
624} 671}
625 672
626template <class P> 673template <class P>
674bool TextureCache<P>::ImageCanRescale(Image& image) {
675 if (True(image.flags & ImageFlagBits::Rescaled) ||
676 True(image.flags & ImageFlagBits::RescaleChecked)) {
677 return true;
678 }
679 const auto& info = image.info;
680 const bool can_this_rescale =
681 (info.type == ImageType::e1D || info.type == ImageType::e2D) && info.block.depth == 0;
682 if (!can_this_rescale) {
683 image.flags &= ~ImageFlagBits::RescaleChecked;
684 return false;
685 }
686 image.flags |= ImageFlagBits::RescaleChecked;
687 for (const auto& alias : image.aliased_images) {
688 Image& other_image = slot_images[alias.id];
689 if (!ImageCanRescale(other_image)) {
690 image.flags &= ~ImageFlagBits::RescaleChecked;
691 return false;
692 }
693 }
694 image.flags &= ~ImageFlagBits::RescaleChecked;
695 return true;
696}
697
698template <class P>
627ImageId TextureCache<P>::InsertImage(const ImageInfo& info, GPUVAddr gpu_addr, 699ImageId TextureCache<P>::InsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
628 RelaxedOptions options) { 700 RelaxedOptions options) {
629 std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr); 701 std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
@@ -660,12 +732,18 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
660 std::vector<ImageId> right_aliased_ids; 732 std::vector<ImageId> right_aliased_ids;
661 std::unordered_set<ImageId> ignore_textures; 733 std::unordered_set<ImageId> ignore_textures;
662 std::vector<ImageId> bad_overlap_ids; 734 std::vector<ImageId> bad_overlap_ids;
735 std::vector<ImageId> all_siblings;
736 const bool this_is_linear = info.type == ImageType::Linear;
663 const auto region_check = [&](ImageId overlap_id, ImageBase& overlap) { 737 const auto region_check = [&](ImageId overlap_id, ImageBase& overlap) {
664 if (True(overlap.flags & ImageFlagBits::Remapped)) { 738 if (True(overlap.flags & ImageFlagBits::Remapped)) {
665 ignore_textures.insert(overlap_id); 739 ignore_textures.insert(overlap_id);
666 return; 740 return;
667 } 741 }
668 if (info.type == ImageType::Linear) { 742 const bool overlap_is_linear = overlap.info.type == ImageType::Linear;
743 if (this_is_linear != overlap_is_linear) {
744 return;
745 }
746 if (this_is_linear && overlap_is_linear) {
669 if (info.pitch == overlap.info.pitch && gpu_addr == overlap.gpu_addr) { 747 if (info.pitch == overlap.info.pitch && gpu_addr == overlap.gpu_addr) {
670 // Alias linear images with the same pitch 748 // Alias linear images with the same pitch
671 left_aliased_ids.push_back(overlap_id); 749 left_aliased_ids.push_back(overlap_id);
@@ -681,6 +759,7 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
681 cpu_addr = solution->cpu_addr; 759 cpu_addr = solution->cpu_addr;
682 new_info.resources = solution->resources; 760 new_info.resources = solution->resources;
683 overlap_ids.push_back(overlap_id); 761 overlap_ids.push_back(overlap_id);
762 all_siblings.push_back(overlap_id);
684 return; 763 return;
685 } 764 }
686 static constexpr auto options = RelaxedOptions::Size | RelaxedOptions::Format; 765 static constexpr auto options = RelaxedOptions::Size | RelaxedOptions::Format;
@@ -688,10 +767,12 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
688 if (IsSubresource(new_info, overlap, gpu_addr, options, broken_views, native_bgr)) { 767 if (IsSubresource(new_info, overlap, gpu_addr, options, broken_views, native_bgr)) {
689 left_aliased_ids.push_back(overlap_id); 768 left_aliased_ids.push_back(overlap_id);
690 overlap.flags |= ImageFlagBits::Alias; 769 overlap.flags |= ImageFlagBits::Alias;
770 all_siblings.push_back(overlap_id);
691 } else if (IsSubresource(overlap.info, new_image_base, overlap.gpu_addr, options, 771 } else if (IsSubresource(overlap.info, new_image_base, overlap.gpu_addr, options,
692 broken_views, native_bgr)) { 772 broken_views, native_bgr)) {
693 right_aliased_ids.push_back(overlap_id); 773 right_aliased_ids.push_back(overlap_id);
694 overlap.flags |= ImageFlagBits::Alias; 774 overlap.flags |= ImageFlagBits::Alias;
775 all_siblings.push_back(overlap_id);
695 } else { 776 } else {
696 bad_overlap_ids.push_back(overlap_id); 777 bad_overlap_ids.push_back(overlap_id);
697 overlap.flags |= ImageFlagBits::BadOverlap; 778 overlap.flags |= ImageFlagBits::BadOverlap;
@@ -709,8 +790,36 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
709 } 790 }
710 }; 791 };
711 ForEachSparseImageInRegion(gpu_addr, size_bytes, region_check_gpu); 792 ForEachSparseImageInRegion(gpu_addr, size_bytes, region_check_gpu);
793
794 bool can_rescale =
795 (info.type == ImageType::e1D || info.type == ImageType::e2D) && info.block.depth == 0;
796 for (const ImageId sibling_id : all_siblings) {
797 if (!can_rescale) {
798 break;
799 }
800 Image& sibling = slot_images[sibling_id];
801 can_rescale &= ImageCanRescale(sibling);
802 }
803
804 if (can_rescale) {
805 for (const ImageId sibling_id : all_siblings) {
806 Image& sibling = slot_images[sibling_id];
807 sibling.ScaleUp();
808 }
809 } else {
810 for (const ImageId sibling_id : all_siblings) {
811 Image& sibling = slot_images[sibling_id];
812 sibling.ScaleDown();
813 }
814 }
815
712 const ImageId new_image_id = slot_images.insert(runtime, new_info, gpu_addr, cpu_addr); 816 const ImageId new_image_id = slot_images.insert(runtime, new_info, gpu_addr, cpu_addr);
713 Image& new_image = slot_images[new_image_id]; 817 Image& new_image = slot_images[new_image_id];
818 if (can_rescale) {
819 new_image.ScaleUp();
820 } else {
821 new_image.ScaleDown();
822 }
714 823
715 if (!gpu_memory.IsContinousRange(new_image.gpu_addr, new_image.guest_size_bytes)) { 824 if (!gpu_memory.IsContinousRange(new_image.gpu_addr, new_image.guest_size_bytes)) {
716 new_image.flags |= ImageFlagBits::Sparse; 825 new_image.flags |= ImageFlagBits::Sparse;
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h
index 2d1893c1c..a4a2c0832 100644
--- a/src/video_core/texture_cache/texture_cache_base.h
+++ b/src/video_core/texture_cache/texture_cache_base.h
@@ -142,6 +142,14 @@ public:
142 const Tegra::Engines::Fermi2D::Surface& src, 142 const Tegra::Engines::Fermi2D::Surface& src,
143 const Tegra::Engines::Fermi2D::Config& copy); 143 const Tegra::Engines::Fermi2D::Config& copy);
144 144
145 /// Invalidate the contents of the color buffer index
146 /// These contents become unspecified, the cache can assume aggressive optimizations.
147 void InvalidateColorBuffer(size_t index);
148
149 /// Invalidate the contents of the depth buffer
150 /// These contents become unspecified, the cache can assume aggressive optimizations.
151 void InvalidateDepthBuffer();
152
145 /// Try to find a cached image view in the given CPU address 153 /// Try to find a cached image view in the given CPU address
146 [[nodiscard]] ImageView* TryFindFramebufferImageView(VAddr cpu_addr); 154 [[nodiscard]] ImageView* TryFindFramebufferImageView(VAddr cpu_addr);
147 155
@@ -318,6 +326,8 @@ private:
318 /// Returns true if the current clear parameters clear the whole image of a given image view 326 /// Returns true if the current clear parameters clear the whole image of a given image view
319 [[nodiscard]] bool IsFullClear(ImageViewId id); 327 [[nodiscard]] bool IsFullClear(ImageViewId id);
320 328
329 bool ImageCanRescale(Image& image);
330
321 Runtime& runtime; 331 Runtime& runtime;
322 VideoCore::RasterizerInterface& rasterizer; 332 VideoCore::RasterizerInterface& rasterizer;
323 Tegra::Engines::Maxwell3D& maxwell3d; 333 Tegra::Engines::Maxwell3D& maxwell3d;