mirror of
				https://git.suyu.dev/suyu/suyu.git
				synced 2025-10-31 23:06:43 +08:00 
			
		
		
		
	VideoCore: Initial Setup for the Resolution Scaler.
This commit is contained in:
		
							parent
							
								
									720970c4c1
								
							
						
					
					
						commit
						22f4b290b6
					
				| @ -47,6 +47,7 @@ void LogSettings() { | ||||
|     log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); | ||||
|     log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); | ||||
|     log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue()); | ||||
|     log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue()); | ||||
|     log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue()); | ||||
|     log_setting("Renderer_UseSpeedLimit", values.use_speed_limit.GetValue()); | ||||
|     log_setting("Renderer_SpeedLimit", values.speed_limit.GetValue()); | ||||
|  | ||||
| @ -52,6 +52,22 @@ enum class NvdecEmulation : u32 { | ||||
|     GPU = 2, | ||||
| }; | ||||
| 
 | ||||
| enum class ResolutionSetup : u32 { | ||||
|     Res1_2X = 0, | ||||
|     Res3_4X = 1, | ||||
|     Res1X = 2, | ||||
|     Res3_2K = 3, | ||||
|     Res2X = 4, | ||||
|     Res3X = 5, | ||||
| }; | ||||
| 
 | ||||
| struct ResolutionScalingInfo { | ||||
|     u32 up_scale{2}; | ||||
|     u32 down_shift{0}; | ||||
|     f32 up_factor{2.0f}; | ||||
|     f32 down_factor{0.5f}; | ||||
| }; | ||||
| 
 | ||||
| /** The BasicSetting class is a simple resource manager. It defines a label and default value
 | ||||
|  * alongside the actual value of the setting for simpler and less-error prone use with frontend | ||||
|  * configurations. Setting a default value and label is required, though subclasses may deviate from | ||||
| @ -451,6 +467,8 @@ struct Values { | ||||
|                                                          "disable_shader_loop_safety_checks"}; | ||||
|     Setting<int> vulkan_device{0, "vulkan_device"}; | ||||
| 
 | ||||
|     ResolutionScalingInfo resolution_info{}; | ||||
|     Setting<ResolutionSetup> resolution_setup{ResolutionSetup::Res1X, "resolution_setup"}; | ||||
|     Setting<u16> resolution_factor{1, "resolution_factor"}; | ||||
|     // *nix platforms may have issues with the borderless windowed fullscreen mode.
 | ||||
|     // Default to exclusive fullscreen on these platforms for now.
 | ||||
|  | ||||
| @ -29,6 +29,7 @@ enum : u8 { | ||||
|     ColorBuffer6, | ||||
|     ColorBuffer7, | ||||
|     ZetaBuffer, | ||||
|     Rescale, | ||||
| 
 | ||||
|     VertexBuffers, | ||||
|     VertexBuffer0, | ||||
|  | ||||
| @ -849,6 +849,22 @@ void Image::CopyImageToBuffer(const VideoCommon::BufferImageCopy& copy, size_t b | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Image::ScaleUp() { | ||||
|     if (True(flags & ImageFlagBits::Rescaled)) { | ||||
|         return; | ||||
|     } | ||||
|     flags |= ImageFlagBits::Rescaled; | ||||
|     UNIMPLEMENTED(); | ||||
| } | ||||
| 
 | ||||
| void Image::ScaleDown() { | ||||
|     if (False(flags & ImageFlagBits::Rescaled)) { | ||||
|         return; | ||||
|     } | ||||
|     flags &= ~ImageFlagBits::Rescaled; | ||||
|     UNIMPLEMENTED(); | ||||
| } | ||||
| 
 | ||||
| ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, | ||||
|                      ImageId image_id_, Image& image) | ||||
|     : VideoCommon::ImageViewBase{info, image.info, image_id_}, views{runtime.null_image_views} { | ||||
|  | ||||
| @ -72,6 +72,8 @@ public: | ||||
|                                  StateTracker& state_tracker); | ||||
|     ~TextureCacheRuntime(); | ||||
| 
 | ||||
|     void Init() {} | ||||
| 
 | ||||
|     void Finish(); | ||||
| 
 | ||||
|     ImageBufferMap UploadStagingBuffer(size_t size); | ||||
| @ -110,6 +112,8 @@ public: | ||||
| 
 | ||||
|     bool HasNativeASTC() const noexcept; | ||||
| 
 | ||||
|     void TickFrame() {} | ||||
| 
 | ||||
| private: | ||||
|     struct StagingBuffers { | ||||
|         explicit StagingBuffers(GLenum storage_flags_, GLenum map_flags_); | ||||
| @ -185,6 +189,10 @@ public: | ||||
|         return gl_type; | ||||
|     } | ||||
| 
 | ||||
|     bool ScaleUp(); | ||||
| 
 | ||||
|     bool ScaleDown(); | ||||
| 
 | ||||
| private: | ||||
|     void CopyBufferToImage(const VideoCommon::BufferImageCopy& copy, size_t buffer_offset); | ||||
| 
 | ||||
|  | ||||
| @ -32,6 +32,7 @@ using Tegra::Engines::Fermi2D; | ||||
| using Tegra::Texture::SwizzleSource; | ||||
| using Tegra::Texture::TextureMipmapFilter; | ||||
| using VideoCommon::BufferImageCopy; | ||||
| using VideoCommon::ImageFlagBits; | ||||
| using VideoCommon::ImageInfo; | ||||
| using VideoCommon::ImageType; | ||||
| using VideoCommon::SubresourceRange; | ||||
| @ -123,7 +124,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| [[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info) { | ||||
| [[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info, | ||||
|                                                     u32 up, u32 down) { | ||||
|     const PixelFormat format = StorageFormat(info.format); | ||||
|     const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, format); | ||||
|     VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; | ||||
| @ -142,9 +144,9 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | ||||
|         .imageType = ConvertImageType(info.type), | ||||
|         .format = format_info.format, | ||||
|         .extent{ | ||||
|             .width = info.size.width >> samples_x, | ||||
|             .height = info.size.height >> samples_y, | ||||
|             .depth = info.size.depth, | ||||
|             .width = ((info.size.width << up) >> down) >> samples_x, | ||||
|             .height = ((info.size.height << up) >> down) >> samples_y, | ||||
|             .depth = (info.size.depth << up) >> down, | ||||
|         }, | ||||
|         .mipLevels = static_cast<u32>(info.resources.levels), | ||||
|         .arrayLayers = static_cast<u32>(info.resources.layers), | ||||
| @ -158,11 +160,12 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| [[nodiscard]] vk::Image MakeImage(const Device& device, const ImageInfo& info) { | ||||
| [[nodiscard]] vk::Image MakeImage(const Device& device, const ImageInfo& info, u32 up = 0, | ||||
|                                   u32 down = 0) { | ||||
|     if (info.type == ImageType::Buffer) { | ||||
|         return vk::Image{}; | ||||
|     } | ||||
|     return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info)); | ||||
|     return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info, up, down)); | ||||
| } | ||||
| 
 | ||||
| [[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) { | ||||
| @ -590,6 +593,11 @@ struct RangedBarrierRange { | ||||
| } | ||||
| } // Anonymous namespace
 | ||||
| 
 | ||||
| void TextureCacheRuntime::Init() { | ||||
|     resolution = Settings::values.resolution_info; | ||||
|     is_rescaling_on = resolution.up_scale != 1 || resolution.down_shift != 0; | ||||
| } | ||||
| 
 | ||||
| void TextureCacheRuntime::Finish() { | ||||
|     scheduler.Finish(); | ||||
| } | ||||
| @ -840,20 +848,26 @@ u64 TextureCacheRuntime::GetDeviceLocalMemory() const { | ||||
|     return device.GetDeviceLocalMemory(); | ||||
| } | ||||
| 
 | ||||
| Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_addr_, | ||||
| void TextureCacheRuntime::TickFrame() { | ||||
|     prescaled_images.Tick(); | ||||
|     prescaled_commits.Tick(); | ||||
|     prescaled_views.Tick(); | ||||
| } | ||||
| 
 | ||||
| Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_, | ||||
|              VAddr cpu_addr_) | ||||
|     : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime.scheduler}, | ||||
|       image(MakeImage(runtime.device, info)), | ||||
|       commit(runtime.memory_allocator.Commit(image, MemoryUsage::DeviceLocal)), | ||||
|       aspect_mask(ImageAspectMask(info.format)) { | ||||
|     if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { | ||||
|     : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler}, | ||||
|       image(MakeImage(runtime_.device, info)), | ||||
|       commit(runtime_.memory_allocator.Commit(image, MemoryUsage::DeviceLocal)), | ||||
|       aspect_mask(ImageAspectMask(info.format)), runtime{&runtime_} { | ||||
|     if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) { | ||||
|         if (Settings::values.accelerate_astc.GetValue()) { | ||||
|             flags |= VideoCommon::ImageFlagBits::AcceleratedUpload; | ||||
|         } else { | ||||
|             flags |= VideoCommon::ImageFlagBits::Converted; | ||||
|         } | ||||
|     } | ||||
|     if (runtime.device.HasDebuggingToolAttached()) { | ||||
|     if (runtime->device.HasDebuggingToolAttached()) { | ||||
|         image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); | ||||
|     } | ||||
|     static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{ | ||||
| @ -861,8 +875,8 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_ | ||||
|         .pNext = nullptr, | ||||
|         .usage = VK_IMAGE_USAGE_STORAGE_BIT, | ||||
|     }; | ||||
|     if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { | ||||
|         const auto& device = runtime.device.GetLogical(); | ||||
|     if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) { | ||||
|         const auto& device = runtime->device.GetLogical(); | ||||
|         storage_image_views.reserve(info.resources.levels); | ||||
|         for (s32 level = 0; level < info.resources.levels; ++level) { | ||||
|             storage_image_views.push_back(device.CreateImageView(VkImageViewCreateInfo{ | ||||
| @ -907,6 +921,10 @@ void Image::UploadMemory(const StagingBufferRef& map, std::span<const BufferImag | ||||
| } | ||||
| 
 | ||||
| void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) { | ||||
|     const bool is_rescaled = True(flags & ImageFlagBits::Rescaled); | ||||
|     if (is_rescaled) { | ||||
|         ScaleDown(); | ||||
|     } | ||||
|     std::vector vk_copies = TransformBufferImageCopies(copies, map.offset, aspect_mask); | ||||
|     scheduler->RequestOutsideRenderPassOperationContext(); | ||||
|     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 | ||||
|         cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||||
|                                0, memory_write_barrier, nullptr, image_write_barrier); | ||||
|     }); | ||||
|     if (is_rescaled) { | ||||
|         ScaleUp(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Image::ScaleUp() { | ||||
|     if (True(flags & ImageFlagBits::Rescaled)) { | ||||
|         return; | ||||
|     } | ||||
|     ASSERT(info.type != ImageType::Linear); | ||||
|     if (!runtime->is_rescaling_on) { | ||||
|         flags |= ImageFlagBits::Rescaled; | ||||
|         return; | ||||
|     } | ||||
|     flags |= ImageFlagBits::Rescaled; | ||||
|     scaling_count++; | ||||
|     ASSERT(scaling_count < 10); | ||||
|     return; | ||||
| } | ||||
| 
 | ||||
| void Image::ScaleDown() { | ||||
|     if (False(flags & ImageFlagBits::Rescaled)) { | ||||
|         return; | ||||
|     } | ||||
|     ASSERT(info.type != ImageType::Linear); | ||||
|     if (!runtime->is_rescaling_on) { | ||||
|         flags &= ~ImageFlagBits::Rescaled; | ||||
|         return; | ||||
|     } | ||||
|     flags &= ~ImageFlagBits::Rescaled; | ||||
|     scaling_count++; | ||||
|     ASSERT(scaling_count < 10); | ||||
|     return; | ||||
| } | ||||
| 
 | ||||
| ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, | ||||
|  | ||||
| @ -6,7 +6,9 @@ | ||||
| 
 | ||||
| #include <span> | ||||
| 
 | ||||
| #include "common/settings.h" | ||||
| #include "shader_recompiler/shader_info.h" | ||||
| #include "video_core/delayed_destruction_ring.h" | ||||
| #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | ||||
| #include "video_core/texture_cache/image_view_base.h" | ||||
| #include "video_core/texture_cache/texture_cache_base.h" | ||||
| @ -15,6 +17,7 @@ | ||||
| 
 | ||||
| namespace Vulkan { | ||||
| 
 | ||||
| using VideoCommon::DelayedDestructionRing; | ||||
| using VideoCommon::ImageId; | ||||
| using VideoCommon::NUM_RT; | ||||
| using VideoCommon::Region2D; | ||||
| @ -39,6 +42,14 @@ struct TextureCacheRuntime { | ||||
|     BlitImageHelper& blit_image_helper; | ||||
|     ASTCDecoderPass& astc_decoder_pass; | ||||
|     RenderPassCache& render_pass_cache; | ||||
|     static constexpr size_t TICKS_TO_DESTROY = 6; | ||||
|     DelayedDestructionRing<vk::Image, TICKS_TO_DESTROY> prescaled_images; | ||||
|     DelayedDestructionRing<MemoryCommit, TICKS_TO_DESTROY> prescaled_commits; | ||||
|     DelayedDestructionRing<vk::ImageView, TICKS_TO_DESTROY> prescaled_views; | ||||
|     Settings::ResolutionScalingInfo resolution; | ||||
|     bool is_rescaling_on{}; | ||||
| 
 | ||||
|     void Init(); | ||||
| 
 | ||||
|     void Finish(); | ||||
| 
 | ||||
| @ -74,6 +85,8 @@ struct TextureCacheRuntime { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     void TickFrame(); | ||||
| 
 | ||||
|     u64 GetDeviceLocalMemory() const; | ||||
| }; | ||||
| 
 | ||||
| @ -113,6 +126,10 @@ public: | ||||
|         return std::exchange(initialized, true); | ||||
|     } | ||||
| 
 | ||||
|     void ScaleUp(); | ||||
| 
 | ||||
|     void ScaleDown(); | ||||
| 
 | ||||
| private: | ||||
|     VKScheduler* scheduler; | ||||
|     vk::Image image; | ||||
| @ -121,6 +138,8 @@ private: | ||||
|     std::vector<vk::ImageView> storage_image_views; | ||||
|     VkImageAspectFlags aspect_mask = 0; | ||||
|     bool initialized = false; | ||||
|     TextureCacheRuntime* runtime; | ||||
|     u32 scaling_count{}; | ||||
| }; | ||||
| 
 | ||||
| class ImageView : public VideoCommon::ImageViewBase { | ||||
|  | ||||
| @ -33,6 +33,10 @@ enum class ImageFlagBits : u32 { | ||||
|                           ///< garbage collection priority
 | ||||
|     Alias = 1 << 11,      ///< This image has aliases and has priority on garbage
 | ||||
|                           ///< collection
 | ||||
| 
 | ||||
|     // Rescaler
 | ||||
|     Rescaled = 1 << 12, | ||||
|     RescaleChecked = 1 << 13, | ||||
| }; | ||||
| DECLARE_ENUM_FLAG_OPERATORS(ImageFlagBits) | ||||
| 
 | ||||
|  | ||||
| @ -15,7 +15,7 @@ using Tegra::Texture::TICEntry; | ||||
| using VideoCore::Surface::PixelFormat; | ||||
| 
 | ||||
| struct ImageInfo { | ||||
|     explicit ImageInfo() = default; | ||||
|     ImageInfo() = default; | ||||
|     explicit ImageInfo(const TICEntry& config) noexcept; | ||||
|     explicit ImageInfo(const Tegra::Engines::Maxwell3D::Regs& regs, size_t index) noexcept; | ||||
|     explicit ImageInfo(const Tegra::Engines::Maxwell3D::Regs& regs) noexcept; | ||||
|  | ||||
| @ -35,6 +35,7 @@ TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface& | ||||
|                               Tegra::MemoryManager& gpu_memory_) | ||||
|     : runtime{runtime_}, rasterizer{rasterizer_}, maxwell3d{maxwell3d_}, | ||||
|       kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_} { | ||||
|     runtime.Init(); | ||||
|     // Configure null sampler
 | ||||
|     TSCEntry sampler_descriptor{}; | ||||
|     sampler_descriptor.min_filter.Assign(Tegra::Texture::TextureFilter::Linear); | ||||
| @ -103,6 +104,7 @@ void TextureCache<P>::TickFrame() { | ||||
|     sentenced_images.Tick(); | ||||
|     sentenced_framebuffers.Tick(); | ||||
|     sentenced_image_view.Tick(); | ||||
|     runtime.TickFrame(); | ||||
|     ++frame_tick; | ||||
| } | ||||
| 
 | ||||
| @ -208,18 +210,63 @@ void TextureCache<P>::UpdateRenderTargets(bool is_clear) { | ||||
|     const bool force = flags[Dirty::RenderTargetControl]; | ||||
|     flags[Dirty::RenderTargetControl] = false; | ||||
| 
 | ||||
|     bool can_rescale = true; | ||||
|     std::array<ImageId, NUM_RT> tmp_color_images{}; | ||||
|     ImageId tmp_depth_image{}; | ||||
|     const auto check_rescale = [&](ImageViewId view_id, ImageId& id_save) { | ||||
|         if (view_id) { | ||||
|             const auto& view = slot_image_views[view_id]; | ||||
|             const auto image_id = view.image_id; | ||||
|             id_save = image_id; | ||||
|             auto& image = slot_images[image_id]; | ||||
|             can_rescale &= ImageCanRescale(image); | ||||
|         } else { | ||||
|             id_save = CORRUPT_ID; | ||||
|         } | ||||
|     }; | ||||
|     for (size_t index = 0; index < NUM_RT; ++index) { | ||||
|         ImageViewId& color_buffer_id = render_targets.color_buffer_ids[index]; | ||||
|         if (flags[Dirty::ColorBuffer0 + index] || force) { | ||||
|             flags[Dirty::ColorBuffer0 + index] = false; | ||||
|             BindRenderTarget(&color_buffer_id, FindColorBuffer(index, is_clear)); | ||||
|         } | ||||
|         PrepareImageView(color_buffer_id, true, is_clear && IsFullClear(color_buffer_id)); | ||||
|         check_rescale(color_buffer_id, tmp_color_images[index]); | ||||
|     } | ||||
|     if (flags[Dirty::ZetaBuffer] || force) { | ||||
|         flags[Dirty::ZetaBuffer] = false; | ||||
|         BindRenderTarget(&render_targets.depth_buffer_id, FindDepthBuffer(is_clear)); | ||||
|     } | ||||
|     check_rescale(render_targets.depth_buffer_id, tmp_depth_image); | ||||
| 
 | ||||
|     if (can_rescale) { | ||||
|         const auto scale_up = [this](ImageId image_id) { | ||||
|             if (image_id != CORRUPT_ID) { | ||||
|                 Image& image = slot_images[image_id]; | ||||
|                 image.ScaleUp(); | ||||
|             } | ||||
|         }; | ||||
|         for (size_t index = 0; index < NUM_RT; ++index) { | ||||
|             scale_up(tmp_color_images[index]); | ||||
|         } | ||||
|         scale_up(tmp_depth_image); | ||||
|     } else { | ||||
|         const auto scale_down = [this](ImageId image_id) { | ||||
|             if (image_id != CORRUPT_ID) { | ||||
|                 Image& image = slot_images[image_id]; | ||||
|                 image.ScaleDown(); | ||||
|             } | ||||
|         }; | ||||
|         for (size_t index = 0; index < NUM_RT; ++index) { | ||||
|             scale_down(tmp_color_images[index]); | ||||
|         } | ||||
|         scale_down(tmp_depth_image); | ||||
|     } | ||||
|     // Rescale End
 | ||||
| 
 | ||||
|     for (size_t index = 0; index < NUM_RT; ++index) { | ||||
|         ImageViewId& color_buffer_id = render_targets.color_buffer_ids[index]; | ||||
|         PrepareImageView(color_buffer_id, true, is_clear && IsFullClear(color_buffer_id)); | ||||
|     } | ||||
|     const ImageViewId depth_buffer_id = render_targets.depth_buffer_id; | ||||
| 
 | ||||
|     PrepareImageView(depth_buffer_id, true, is_clear && IsFullClear(depth_buffer_id)); | ||||
| @ -623,6 +670,31 @@ ImageId TextureCache<P>::FindImage(const ImageInfo& info, GPUVAddr gpu_addr, | ||||
|     return image_id; | ||||
| } | ||||
| 
 | ||||
| template <class P> | ||||
| bool TextureCache<P>::ImageCanRescale(Image& image) { | ||||
|     if (True(image.flags & ImageFlagBits::Rescaled) || | ||||
|         True(image.flags & ImageFlagBits::RescaleChecked)) { | ||||
|         return true; | ||||
|     } | ||||
|     const auto& info = image.info; | ||||
|     const bool can_this_rescale = | ||||
|         (info.type == ImageType::e1D || info.type == ImageType::e2D) && info.block.depth == 0; | ||||
|     if (!can_this_rescale) { | ||||
|         image.flags &= ~ImageFlagBits::RescaleChecked; | ||||
|         return false; | ||||
|     } | ||||
|     image.flags |= ImageFlagBits::RescaleChecked; | ||||
|     for (const auto& alias : image.aliased_images) { | ||||
|         Image& other_image = slot_images[alias.id]; | ||||
|         if (!ImageCanRescale(other_image)) { | ||||
|             image.flags &= ~ImageFlagBits::RescaleChecked; | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|     image.flags &= ~ImageFlagBits::RescaleChecked; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| template <class P> | ||||
| ImageId TextureCache<P>::InsertImage(const ImageInfo& info, GPUVAddr gpu_addr, | ||||
|                                      RelaxedOptions options) { | ||||
| @ -660,12 +732,18 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA | ||||
|     std::vector<ImageId> right_aliased_ids; | ||||
|     std::unordered_set<ImageId> ignore_textures; | ||||
|     std::vector<ImageId> bad_overlap_ids; | ||||
|     std::vector<ImageId> all_siblings; | ||||
|     const bool this_is_linear = info.type == ImageType::Linear; | ||||
|     const auto region_check = [&](ImageId overlap_id, ImageBase& overlap) { | ||||
|         if (True(overlap.flags & ImageFlagBits::Remapped)) { | ||||
|             ignore_textures.insert(overlap_id); | ||||
|             return; | ||||
|         } | ||||
|         if (info.type == ImageType::Linear) { | ||||
|         const bool overlap_is_linear = overlap.info.type == ImageType::Linear; | ||||
|         if (this_is_linear != overlap_is_linear) { | ||||
|             return; | ||||
|         } | ||||
|         if (this_is_linear && overlap_is_linear) { | ||||
|             if (info.pitch == overlap.info.pitch && gpu_addr == overlap.gpu_addr) { | ||||
|                 // Alias linear images with the same pitch
 | ||||
|                 left_aliased_ids.push_back(overlap_id); | ||||
| @ -681,6 +759,7 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA | ||||
|             cpu_addr = solution->cpu_addr; | ||||
|             new_info.resources = solution->resources; | ||||
|             overlap_ids.push_back(overlap_id); | ||||
|             all_siblings.push_back(overlap_id); | ||||
|             return; | ||||
|         } | ||||
|         static constexpr auto options = RelaxedOptions::Size | RelaxedOptions::Format; | ||||
| @ -688,10 +767,12 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA | ||||
|         if (IsSubresource(new_info, overlap, gpu_addr, options, broken_views, native_bgr)) { | ||||
|             left_aliased_ids.push_back(overlap_id); | ||||
|             overlap.flags |= ImageFlagBits::Alias; | ||||
|             all_siblings.push_back(overlap_id); | ||||
|         } else if (IsSubresource(overlap.info, new_image_base, overlap.gpu_addr, options, | ||||
|                                  broken_views, native_bgr)) { | ||||
|             right_aliased_ids.push_back(overlap_id); | ||||
|             overlap.flags |= ImageFlagBits::Alias; | ||||
|             all_siblings.push_back(overlap_id); | ||||
|         } else { | ||||
|             bad_overlap_ids.push_back(overlap_id); | ||||
|             overlap.flags |= ImageFlagBits::BadOverlap; | ||||
| @ -709,8 +790,36 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA | ||||
|         } | ||||
|     }; | ||||
|     ForEachSparseImageInRegion(gpu_addr, size_bytes, region_check_gpu); | ||||
| 
 | ||||
|     bool can_rescale = | ||||
|         (info.type == ImageType::e1D || info.type == ImageType::e2D) && info.block.depth == 0; | ||||
|     for (const ImageId sibling_id : all_siblings) { | ||||
|         if (!can_rescale) { | ||||
|             break; | ||||
|         } | ||||
|         Image& sibling = slot_images[sibling_id]; | ||||
|         can_rescale &= ImageCanRescale(sibling); | ||||
|     } | ||||
| 
 | ||||
|     if (can_rescale) { | ||||
|         for (const ImageId sibling_id : all_siblings) { | ||||
|             Image& sibling = slot_images[sibling_id]; | ||||
|             sibling.ScaleUp(); | ||||
|         } | ||||
|     } else { | ||||
|         for (const ImageId sibling_id : all_siblings) { | ||||
|             Image& sibling = slot_images[sibling_id]; | ||||
|             sibling.ScaleDown(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     const ImageId new_image_id = slot_images.insert(runtime, new_info, gpu_addr, cpu_addr); | ||||
|     Image& new_image = slot_images[new_image_id]; | ||||
|     if (can_rescale) { | ||||
|         new_image.ScaleUp(); | ||||
|     } else { | ||||
|         new_image.ScaleDown(); | ||||
|     } | ||||
| 
 | ||||
|     if (!gpu_memory.IsContinousRange(new_image.gpu_addr, new_image.guest_size_bytes)) { | ||||
|         new_image.flags |= ImageFlagBits::Sparse; | ||||
|  | ||||
| @ -142,6 +142,14 @@ public: | ||||
|                    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); | ||||
| 
 | ||||
| @ -318,6 +326,8 @@ private: | ||||
|     /// Returns true if the current clear parameters clear the whole image of a given image view
 | ||||
|     [[nodiscard]] bool IsFullClear(ImageViewId id); | ||||
| 
 | ||||
|     bool ImageCanRescale(Image& image); | ||||
| 
 | ||||
|     Runtime& runtime; | ||||
|     VideoCore::RasterizerInterface& rasterizer; | ||||
|     Tegra::Engines::Maxwell3D& maxwell3d; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user