mirror of
				https://git.suyu.dev/suyu/suyu.git
				synced 2025-11-04 12:34:39 +08:00 
			
		
		
		
	Merge pull request #4012 from ReinUsesLisp/mipmap-overlaps
texture_cache: Handle overlaps with multiple subresources
This commit is contained in:
		
						commit
						c647999c61
					
				@ -655,45 +655,63 @@ private:
 | 
				
			|||||||
     **/
 | 
					     **/
 | 
				
			||||||
    std::optional<std::pair<TSurface, TView>> TryReconstructSurface(VectorSurface& overlaps,
 | 
					    std::optional<std::pair<TSurface, TView>> TryReconstructSurface(VectorSurface& overlaps,
 | 
				
			||||||
                                                                    const SurfaceParams& params,
 | 
					                                                                    const SurfaceParams& params,
 | 
				
			||||||
                                                                    const GPUVAddr gpu_addr) {
 | 
					                                                                    GPUVAddr gpu_addr) {
 | 
				
			||||||
        if (params.target == SurfaceTarget::Texture3D) {
 | 
					        if (params.target == SurfaceTarget::Texture3D) {
 | 
				
			||||||
            return {};
 | 
					            return std::nullopt;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        bool modified = false;
 | 
					        const auto test_modified = [](TSurface& surface) { return surface->IsModified(); };
 | 
				
			||||||
        TSurface new_surface = GetUncachedSurface(gpu_addr, params);
 | 
					        TSurface new_surface = GetUncachedSurface(gpu_addr, params);
 | 
				
			||||||
        u32 passed_tests = 0;
 | 
					
 | 
				
			||||||
        for (auto& surface : overlaps) {
 | 
					        if (std::none_of(overlaps.begin(), overlaps.end(), test_modified)) {
 | 
				
			||||||
            const SurfaceParams& src_params = surface->GetSurfaceParams();
 | 
					            LoadSurface(new_surface);
 | 
				
			||||||
            if (src_params.is_layered || src_params.num_levels > 1) {
 | 
					 | 
				
			||||||
                // We send this cases to recycle as they are more complex to handle
 | 
					 | 
				
			||||||
                return {};
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            const std::size_t candidate_size = surface->GetSizeInBytes();
 | 
					 | 
				
			||||||
            auto mipmap_layer{new_surface->GetLayerMipmap(surface->GetGpuAddr())};
 | 
					 | 
				
			||||||
            if (!mipmap_layer) {
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            const auto [layer, mipmap] = *mipmap_layer;
 | 
					 | 
				
			||||||
            if (new_surface->GetMipmapSize(mipmap) != candidate_size) {
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            modified |= surface->IsModified();
 | 
					 | 
				
			||||||
            // Now we got all the data set up
 | 
					 | 
				
			||||||
            const u32 width = SurfaceParams::IntersectWidth(src_params, params, 0, mipmap);
 | 
					 | 
				
			||||||
            const u32 height = SurfaceParams::IntersectHeight(src_params, params, 0, mipmap);
 | 
					 | 
				
			||||||
            const CopyParams copy_params(0, 0, 0, 0, 0, layer, 0, mipmap, width, height, 1);
 | 
					 | 
				
			||||||
            passed_tests++;
 | 
					 | 
				
			||||||
            ImageCopy(surface, new_surface, copy_params);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (passed_tests == 0) {
 | 
					 | 
				
			||||||
            return {};
 | 
					 | 
				
			||||||
            // In Accurate GPU all tests should pass, else we recycle
 | 
					 | 
				
			||||||
        } else if (Settings::IsGPULevelExtreme() && passed_tests != overlaps.size()) {
 | 
					 | 
				
			||||||
            return {};
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
            for (const auto& surface : overlaps) {
 | 
					            for (const auto& surface : overlaps) {
 | 
				
			||||||
                Unregister(surface);
 | 
					                Unregister(surface);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            Register(new_surface);
 | 
				
			||||||
 | 
					            return {{new_surface, new_surface->GetMainView()}};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::size_t passed_tests = 0;
 | 
				
			||||||
 | 
					        for (auto& surface : overlaps) {
 | 
				
			||||||
 | 
					            const SurfaceParams& src_params = surface->GetSurfaceParams();
 | 
				
			||||||
 | 
					            const auto mipmap_layer{new_surface->GetLayerMipmap(surface->GetGpuAddr())};
 | 
				
			||||||
 | 
					            if (!mipmap_layer) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const auto [base_layer, base_mipmap] = *mipmap_layer;
 | 
				
			||||||
 | 
					            if (new_surface->GetMipmapSize(base_mipmap) != surface->GetMipmapSize(0)) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ++passed_tests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Copy all mipmaps and layers
 | 
				
			||||||
 | 
					            const u32 block_width = params.GetDefaultBlockWidth();
 | 
				
			||||||
 | 
					            const u32 block_height = params.GetDefaultBlockHeight();
 | 
				
			||||||
 | 
					            for (u32 mipmap = base_mipmap; mipmap < base_mipmap + src_params.num_levels; ++mipmap) {
 | 
				
			||||||
 | 
					                const u32 width = SurfaceParams::IntersectWidth(src_params, params, 0, mipmap);
 | 
				
			||||||
 | 
					                const u32 height = SurfaceParams::IntersectHeight(src_params, params, 0, mipmap);
 | 
				
			||||||
 | 
					                if (width < block_width || height < block_height) {
 | 
				
			||||||
 | 
					                    // Current APIs forbid copying small compressed textures, avoid errors
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                const CopyParams copy_params(0, 0, 0, 0, 0, base_layer, 0, mipmap, width, height,
 | 
				
			||||||
 | 
					                                             src_params.depth);
 | 
				
			||||||
 | 
					                ImageCopy(surface, new_surface, copy_params);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (passed_tests == 0) {
 | 
				
			||||||
 | 
					            return std::nullopt;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (Settings::IsGPULevelExtreme() && passed_tests != overlaps.size()) {
 | 
				
			||||||
 | 
					            // In Accurate GPU all tests should pass, else we recycle
 | 
				
			||||||
 | 
					            return std::nullopt;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const bool modified = std::any_of(overlaps.begin(), overlaps.end(), test_modified);
 | 
				
			||||||
 | 
					        for (const auto& surface : overlaps) {
 | 
				
			||||||
 | 
					            Unregister(surface);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        new_surface->MarkAsModified(modified, Tick());
 | 
					        new_surface->MarkAsModified(modified, Tick());
 | 
				
			||||||
        Register(new_surface);
 | 
					        Register(new_surface);
 | 
				
			||||||
        return {{new_surface, new_surface->GetMainView()}};
 | 
					        return {{new_surface, new_surface->GetMainView()}};
 | 
				
			||||||
@ -871,13 +889,10 @@ private:
 | 
				
			|||||||
            // two things either the candidate surface is a supertexture of the overlap
 | 
					            // two things either the candidate surface is a supertexture of the overlap
 | 
				
			||||||
            // or they don't match in any known way.
 | 
					            // or they don't match in any known way.
 | 
				
			||||||
            if (!current_surface->IsInside(gpu_addr, gpu_addr + candidate_size)) {
 | 
					            if (!current_surface->IsInside(gpu_addr, gpu_addr + candidate_size)) {
 | 
				
			||||||
                if (current_surface->GetGpuAddr() == gpu_addr) {
 | 
					                const std::optional view = TryReconstructSurface(overlaps, params, gpu_addr);
 | 
				
			||||||
                    std::optional<std::pair<TSurface, TView>> view =
 | 
					 | 
				
			||||||
                        TryReconstructSurface(overlaps, params, gpu_addr);
 | 
					 | 
				
			||||||
                if (view) {
 | 
					                if (view) {
 | 
				
			||||||
                    return *view;
 | 
					                    return *view;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return RecycleSurface(overlaps, params, gpu_addr, preserve_contents,
 | 
					                return RecycleSurface(overlaps, params, gpu_addr, preserve_contents,
 | 
				
			||||||
                                      MatchTopologyResult::FullMatch);
 | 
					                                      MatchTopologyResult::FullMatch);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user