texture_cache: Document the most important methods.
This commit is contained in:
		 Fernando Sahmkow
					Fernando Sahmkow
				
			
				
					committed by
					
						 ReinUsesLisp
						ReinUsesLisp
					
				
			
			
				
	
			
			
			 ReinUsesLisp
						ReinUsesLisp
					
				
			
						parent
						
							4530511ee4
						
					
				
				
					commit
					6162cb922e
				
			| @@ -64,6 +64,10 @@ public: | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * `Guard` guarantees that rendertargets don't unregister themselves if the | ||||
|      * collide. Protection is currently only done on 3D slices. | ||||
|      **/ | ||||
|     void Guard(bool new_guard) { | ||||
|         guard_cache = new_guard; | ||||
|     } | ||||
| @@ -293,6 +297,14 @@ private: | ||||
|         BufferCopy = 3, | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * `PickStrategy` takes care of selecting a proper strategy to deal with a texture recycle. | ||||
|      * @param overlaps, the overlapping surfaces registered in the cache. | ||||
|      * @param params, the paremeters on the new surface. | ||||
|      * @param gpu_addr, the starting address of the new surface. | ||||
|      * @param untopological, tells the recycler that the texture has no way to match the overlaps | ||||
|      * due to topological reasons. | ||||
|      **/ | ||||
|     RecycleStrategy PickStrategy(std::vector<TSurface>& overlaps, const SurfaceParams& params, | ||||
|                                  const GPUVAddr gpu_addr, const bool untopological) { | ||||
|         if (Settings::values.use_accurate_gpu_emulation) { | ||||
| @@ -315,6 +327,18 @@ private: | ||||
|         return RecycleStrategy::Ignore; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      *  `RecycleSurface` es a method we use to decide what to do with textures we can't resolve in | ||||
|      *the cache It has 2 implemented strategies: Ignore and Flush. Ignore just unregisters all the | ||||
|      *overlaps and loads the new texture. Flush, flushes all the overlaps into memory and loads the | ||||
|      *new surface from that data. | ||||
|      * @param overlaps, the overlapping surfaces registered in the cache. | ||||
|      * @param params, the paremeters on the new surface. | ||||
|      * @param gpu_addr, the starting address of the new surface. | ||||
|      * @param preserve_contents, tells if the new surface should be loaded from meory or left blank | ||||
|      * @param untopological, tells the recycler that the texture has no way to match the overlaps | ||||
|      * due to topological reasons. | ||||
|      **/ | ||||
|     std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps, | ||||
|                                               const SurfaceParams& params, const GPUVAddr gpu_addr, | ||||
|                                               const bool preserve_contents, | ||||
| @@ -343,6 +367,12 @@ private: | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * `RebuildSurface` this method takes a single surface and recreates into another that | ||||
|      * may differ in format, target or width alingment. | ||||
|      * @param current_surface, the registered surface in the cache which we want to convert. | ||||
|      * @param params, the new surface params which we'll use to recreate the surface. | ||||
|      **/ | ||||
|     std::pair<TSurface, TView> RebuildSurface(TSurface current_surface, | ||||
|                                               const SurfaceParams& params) { | ||||
|         const auto gpu_addr = current_surface->GetGpuAddr(); | ||||
| @@ -357,6 +387,14 @@ private: | ||||
|         return {new_surface, new_surface->GetMainView()}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * `ManageStructuralMatch` this method takes a single surface and checks with the new surface's | ||||
|      * params if it's an exact match, we return the main view of the registered surface. If it's | ||||
|      * formats don't match, we rebuild the surface. We call this last method a `Mirage`. If formats | ||||
|      * match but the targets don't, we create an overview View of the registered surface. | ||||
|      * @param current_surface, the registered surface in the cache which we want to convert. | ||||
|      * @param params, the new surface params which we want to check. | ||||
|      **/ | ||||
|     std::pair<TSurface, TView> ManageStructuralMatch(TSurface current_surface, | ||||
|                                                      const SurfaceParams& params) { | ||||
|         const bool is_mirage = !current_surface->MatchFormat(params.pixel_format); | ||||
| @@ -370,10 +408,18 @@ private: | ||||
|         return {current_surface, current_surface->EmplaceOverview(params)}; | ||||
|     } | ||||
|  | ||||
|     std::optional<std::pair<TSurface, TView>> ReconstructSurface(std::vector<TSurface>& overlaps, | ||||
|                                                                  const SurfaceParams& params, | ||||
|                                                                  const GPUVAddr gpu_addr, | ||||
|                                                                  const u8* host_ptr) { | ||||
|     /** | ||||
|      * `TryReconstructSurface` unlike `RebuildSurface` where we know the registered surface | ||||
|      * matches the candidate in some way, we got no guarantess here. We try to see if the overlaps | ||||
|      * are sublayers/mipmaps of the new surface, if they all match we end up recreating a surface | ||||
|      * for them, else we return nothing. | ||||
|      * @param overlaps, the overlapping surfaces registered in the cache. | ||||
|      * @param params, the paremeters on the new surface. | ||||
|      * @param gpu_addr, the starting address of the new surface. | ||||
|      **/ | ||||
|     std::optional<std::pair<TSurface, TView>> TryReconstructSurface(std::vector<TSurface>& overlaps, | ||||
|                                                                     const SurfaceParams& params, | ||||
|                                                                     const GPUVAddr gpu_addr) { | ||||
|         if (params.target == SurfaceTarget::Texture3D) { | ||||
|             return {}; | ||||
|         } | ||||
| @@ -412,12 +458,30 @@ private: | ||||
|         return {{new_surface, new_surface->GetMainView()}}; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * `GetSurface` gets the starting address and parameters of a candidate surface and tries | ||||
|      * to find a matching surface within the cache. This is done in 3 big steps. The first is to | ||||
|      * check the 1st Level Cache in order to find an exact match, if we fail, we move to step 2. | ||||
|      * Step 2 is checking if there are any overlaps at all, if none, we just load the texture from | ||||
|      * memory else we move to step 3. Step 3 consists on figuring the relationship between the | ||||
|      * candidate texture and the overlaps. We divide the scenarios depending if there's 1 or many | ||||
|      * overlaps. If there's many, we just try to reconstruct a new surface out of them based on the | ||||
|      * candidate's parameters, if we fail, we recycle. When there's only 1 overlap then we have to | ||||
|      * check if the candidate is a view (layer/mipmap) of the overlap or if the registered surface | ||||
|      * is a mipmap/layer of the candidate. In this last case we reconstruct a new surface. | ||||
|      * @param gpu_addr, the starting address of the candidate surface. | ||||
|      * @param params, the paremeters on the candidate surface. | ||||
|      * @param preserve_contents, tells if the new surface should be loaded from meory or left blank. | ||||
|      **/ | ||||
|     std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const SurfaceParams& params, | ||||
|                                           bool preserve_contents) { | ||||
|  | ||||
|         const auto host_ptr{memory_manager->GetPointer(gpu_addr)}; | ||||
|         const auto cache_addr{ToCacheAddr(host_ptr)}; | ||||
|  | ||||
|         // Step 1 | ||||
|         // Check Level 1 Cache for a fast structural match. If candidate surface | ||||
|         // matches at certain level we are pretty much done. | ||||
|         if (l1_cache.count(cache_addr) > 0) { | ||||
|             TSurface current_surface = l1_cache[cache_addr]; | ||||
|             if (!current_surface->MatchesTopology(params)) { | ||||
| @@ -437,31 +501,43 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Step 2 | ||||
|         // Obtain all possible overlaps in the memory region | ||||
|         const std::size_t candidate_size = params.GetGuestSizeInBytes(); | ||||
|         auto overlaps{GetSurfacesInRegion(cache_addr, candidate_size)}; | ||||
|  | ||||
|         // If none are found, we are done. we just load the surface and create it. | ||||
|         if (overlaps.empty()) { | ||||
|             return InitializeSurface(gpu_addr, params, preserve_contents); | ||||
|         } | ||||
|  | ||||
|         // Step 3 | ||||
|         // Now we need to figure the relationship between the texture and its overlaps | ||||
|         // we do a topological test to ensure we can find some relationship. If it fails | ||||
|         // inmediatly recycle the texture | ||||
|         for (auto surface : overlaps) { | ||||
|             if (!surface->MatchesTopology(params)) { | ||||
|                 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, true); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Split cases between 1 overlap or many. | ||||
|         if (overlaps.size() == 1) { | ||||
|             TSurface current_surface = overlaps[0]; | ||||
|             // First check if the surface is within the overlap. If not, it means | ||||
|             // two things either the candidate surface is a supertexture of the overlap | ||||
|             // or they don't match in any known way. | ||||
|             if (!current_surface->IsInside(gpu_addr, gpu_addr + candidate_size)) { | ||||
|                 if (current_surface->GetGpuAddr() == gpu_addr) { | ||||
|                     std::optional<std::pair<TSurface, TView>> view = | ||||
|                         ReconstructSurface(overlaps, params, gpu_addr, host_ptr); | ||||
|                         TryReconstructSurface(overlaps, params, gpu_addr); | ||||
|                     if (view.has_value()) { | ||||
|                         return *view; | ||||
|                     } | ||||
|                 } | ||||
|                 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); | ||||
|             } | ||||
|             // Now we check if the candidate is a mipmap/layer of the overlap | ||||
|             std::optional<TView> view = | ||||
|                 current_surface->EmplaceView(params, gpu_addr, candidate_size); | ||||
|             if (view.has_value()) { | ||||
| @@ -472,15 +548,18 @@ private: | ||||
|                 } | ||||
|                 return {current_surface, *view}; | ||||
|             } | ||||
|             return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); | ||||
|         } else { | ||||
|             // If there are many overlaps, odds are they are subtextures of the candidate | ||||
|             // surface. We try to construct a new surface based on the candidate parameters, | ||||
|             // using the overlaps. If a single overlap fails, this will fail. | ||||
|             std::optional<std::pair<TSurface, TView>> view = | ||||
|                 ReconstructSurface(overlaps, params, gpu_addr, host_ptr); | ||||
|                 TryReconstructSurface(overlaps, params, gpu_addr); | ||||
|             if (view.has_value()) { | ||||
|                 return *view; | ||||
|             } | ||||
|             return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); | ||||
|         } | ||||
|         // We failed all the tests, recycle the overlaps into a new texture. | ||||
|         return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); | ||||
|     } | ||||
|  | ||||
|     std::pair<TSurface, TView> InitializeSurface(GPUVAddr gpu_addr, const SurfaceParams& params, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user