summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp10
-rw-r--r--src/video_core/texture_cache/surface_base.h18
-rw-r--r--src/video_core/texture_cache/surface_params.cpp4
-rw-r--r--src/video_core/texture_cache/surface_params.h14
-rw-r--r--src/video_core/texture_cache/texture_cache.h26
5 files changed, 53 insertions, 19 deletions
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 9e9734f9e..e6f08a764 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -195,17 +195,17 @@ OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum inte
195 195
196 switch (params.target) { 196 switch (params.target) {
197 case SurfaceTarget::Texture1D: 197 case SurfaceTarget::Texture1D:
198 glTextureStorage1D(texture.handle, params.num_levels, internal_format, params.width); 198 glTextureStorage1D(texture.handle, params.emulated_levels, internal_format, params.width);
199 break; 199 break;
200 case SurfaceTarget::Texture2D: 200 case SurfaceTarget::Texture2D:
201 case SurfaceTarget::TextureCubemap: 201 case SurfaceTarget::TextureCubemap:
202 glTextureStorage2D(texture.handle, params.num_levels, internal_format, params.width, 202 glTextureStorage2D(texture.handle, params.emulated_levels, internal_format, params.width,
203 params.height); 203 params.height);
204 break; 204 break;
205 case SurfaceTarget::Texture3D: 205 case SurfaceTarget::Texture3D:
206 case SurfaceTarget::Texture2DArray: 206 case SurfaceTarget::Texture2DArray:
207 case SurfaceTarget::TextureCubeArray: 207 case SurfaceTarget::TextureCubeArray:
208 glTextureStorage3D(texture.handle, params.num_levels, internal_format, params.width, 208 glTextureStorage3D(texture.handle, params.emulated_levels, internal_format, params.width,
209 params.height, params.depth); 209 params.height, params.depth);
210 break; 210 break;
211 default: 211 default:
@@ -245,7 +245,7 @@ void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) {
245 // TODO(Rodrigo): Optimize alignment 245 // TODO(Rodrigo): Optimize alignment
246 SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); }); 246 SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); });
247 247
248 for (u32 level = 0; level < params.num_levels; ++level) { 248 for (u32 level = 0; level < params.emulated_levels; ++level) {
249 glPixelStorei(GL_PACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level))); 249 glPixelStorei(GL_PACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level)));
250 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); 250 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level)));
251 const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level); 251 const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level);
@@ -264,7 +264,7 @@ void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) {
264void CachedSurface::UploadTexture(std::vector<u8>& staging_buffer) { 264void CachedSurface::UploadTexture(std::vector<u8>& staging_buffer) {
265 MICROPROFILE_SCOPE(OpenGL_Texture_Upload); 265 MICROPROFILE_SCOPE(OpenGL_Texture_Upload);
266 SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); }); 266 SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); });
267 for (u32 level = 0; level < params.num_levels; ++level) { 267 for (u32 level = 0; level < params.emulated_levels; ++level) {
268 UploadTextureMipmap(level, staging_buffer); 268 UploadTextureMipmap(level, staging_buffer);
269 } 269 }
270} 270}
diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h
index 77c2d6758..70b5258c9 100644
--- a/src/video_core/texture_cache/surface_base.h
+++ b/src/video_core/texture_cache/surface_base.h
@@ -32,6 +32,12 @@ enum class MatchStructureResult : u32 {
32 None = 2, 32 None = 2,
33}; 33};
34 34
35enum class MatchTopologyResult : u32 {
36 FullMatch = 0,
37 CompressUnmatch = 1,
38 None = 2,
39};
40
35class StagingCache { 41class StagingCache {
36public: 42public:
37 StagingCache() {} 43 StagingCache() {}
@@ -136,12 +142,20 @@ public:
136 params.target == SurfaceTarget::Texture2D && params.num_levels == 1; 142 params.target == SurfaceTarget::Texture2D && params.num_levels == 1;
137 } 143 }
138 144
139 bool MatchesTopology(const SurfaceParams& rhs) const { 145 MatchTopologyResult MatchesTopology(const SurfaceParams& rhs) const {
140 const u32 src_bpp{params.GetBytesPerPixel()}; 146 const u32 src_bpp{params.GetBytesPerPixel()};
141 const u32 dst_bpp{rhs.GetBytesPerPixel()}; 147 const u32 dst_bpp{rhs.GetBytesPerPixel()};
142 const bool ib1 = params.IsBuffer(); 148 const bool ib1 = params.IsBuffer();
143 const bool ib2 = rhs.IsBuffer(); 149 const bool ib2 = rhs.IsBuffer();
144 return std::tie(src_bpp, params.is_tiled, ib1) == std::tie(dst_bpp, rhs.is_tiled, ib2); 150 if (std::tie(src_bpp, params.is_tiled, ib1) == std::tie(dst_bpp, rhs.is_tiled, ib2)) {
151 const bool cb1 = params.IsCompressed();
152 const bool cb2 = rhs.IsCompressed();
153 if (cb1 == cb2) {
154 return MatchTopologyResult::FullMatch;
155 }
156 return MatchTopologyResult::CompressUnmatch;
157 }
158 return MatchTopologyResult::None;
145 } 159 }
146 160
147 MatchStructureResult MatchesStructure(const SurfaceParams& rhs) const { 161 MatchStructureResult MatchesStructure(const SurfaceParams& rhs) const {
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp
index d9d157d02..77c09264a 100644
--- a/src/video_core/texture_cache/surface_params.cpp
+++ b/src/video_core/texture_cache/surface_params.cpp
@@ -85,6 +85,7 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
85 } 85 }
86 params.pitch = params.is_tiled ? 0 : config.tic.Pitch(); 86 params.pitch = params.is_tiled ? 0 : config.tic.Pitch();
87 params.num_levels = config.tic.max_mip_level + 1; 87 params.num_levels = config.tic.max_mip_level + 1;
88 params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap());
88 params.is_layered = params.IsLayered(); 89 params.is_layered = params.IsLayered();
89 return params; 90 return params;
90} 91}
@@ -109,6 +110,7 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer(
109 params.depth = 1; 110 params.depth = 1;
110 params.pitch = 0; 111 params.pitch = 0;
111 params.num_levels = 1; 112 params.num_levels = 1;
113 params.emulated_levels = 1;
112 params.is_layered = false; 114 params.is_layered = false;
113 return params; 115 return params;
114} 116}
@@ -139,6 +141,7 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz
139 params.depth = 1; 141 params.depth = 1;
140 params.target = SurfaceTarget::Texture2D; 142 params.target = SurfaceTarget::Texture2D;
141 params.num_levels = 1; 143 params.num_levels = 1;
144 params.emulated_levels = 1;
142 params.is_layered = false; 145 params.is_layered = false;
143 return params; 146 return params;
144} 147}
@@ -163,6 +166,7 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface(
163 params.target = SurfaceTarget::Texture2D; 166 params.target = SurfaceTarget::Texture2D;
164 params.depth = 1; 167 params.depth = 1;
165 params.num_levels = 1; 168 params.num_levels = 1;
169 params.emulated_levels = 1;
166 params.is_layered = params.IsLayered(); 170 params.is_layered = params.IsLayered();
167 return params; 171 return params;
168} 172}
diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h
index c3affd621..5fde695b6 100644
--- a/src/video_core/texture_cache/surface_params.h
+++ b/src/video_core/texture_cache/surface_params.h
@@ -160,6 +160,19 @@ public:
160 return std::min(t_src_height, t_dst_height); 160 return std::min(t_src_height, t_dst_height);
161 } 161 }
162 162
163 u32 MaxPossibleMipmap() const {
164 const u32 max_mipmap_w = Common::Log2Ceil32(width) + 1U;
165 const u32 max_mipmap_h = Common::Log2Ceil32(height) + 1U;
166 const u32 max_mipmap = std::max(max_mipmap_w, max_mipmap_h);
167 if (target != VideoCore::Surface::SurfaceTarget::Texture3D)
168 return max_mipmap;
169 return std::max(max_mipmap, Common::Log2Ceil32(depth) + 1U);
170 }
171
172 bool IsCompressed() const {
173 return GetDefaultBlockHeight() > 1 || GetDefaultBlockWidth() > 1;
174 }
175
163 /// Returns the default block width. 176 /// Returns the default block width.
164 u32 GetDefaultBlockWidth() const { 177 u32 GetDefaultBlockWidth() const {
165 return VideoCore::Surface::GetDefaultBlockWidth(pixel_format); 178 return VideoCore::Surface::GetDefaultBlockWidth(pixel_format);
@@ -205,6 +218,7 @@ public:
205 u32 depth; 218 u32 depth;
206 u32 pitch; 219 u32 pitch;
207 u32 num_levels; 220 u32 num_levels;
221 u32 emulated_levels;
208 VideoCore::Surface::PixelFormat pixel_format; 222 VideoCore::Surface::PixelFormat pixel_format;
209 VideoCore::Surface::ComponentType component_type; 223 VideoCore::Surface::ComponentType component_type;
210 VideoCore::Surface::SurfaceType type; 224 VideoCore::Surface::SurfaceType type;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index d2093e581..69ef7a2bd 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -305,7 +305,7 @@ private:
305 * due to topological reasons. 305 * due to topological reasons.
306 **/ 306 **/
307 RecycleStrategy PickStrategy(std::vector<TSurface>& overlaps, const SurfaceParams& params, 307 RecycleStrategy PickStrategy(std::vector<TSurface>& overlaps, const SurfaceParams& params,
308 const GPUVAddr gpu_addr, const bool untopological) { 308 const GPUVAddr gpu_addr, const MatchTopologyResult untopological) {
309 if (Settings::values.use_accurate_gpu_emulation) { 309 if (Settings::values.use_accurate_gpu_emulation) {
310 return RecycleStrategy::Flush; 310 return RecycleStrategy::Flush;
311 } 311 }
@@ -320,8 +320,8 @@ private:
320 } 320 }
321 } 321 }
322 // Untopological decision 322 // Untopological decision
323 if (untopological) { 323 if (untopological == MatchTopologyResult::CompressUnmatch) {
324 return RecycleStrategy::Ignore; 324 return RecycleStrategy::Flush;
325 } 325 }
326 return RecycleStrategy::Ignore; 326 return RecycleStrategy::Ignore;
327 } 327 }
@@ -341,7 +341,7 @@ private:
341 std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps, 341 std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps,
342 const SurfaceParams& params, const GPUVAddr gpu_addr, 342 const SurfaceParams& params, const GPUVAddr gpu_addr,
343 const bool preserve_contents, 343 const bool preserve_contents,
344 const bool untopological) { 344 const MatchTopologyResult untopological) {
345 const bool do_load = Settings::values.use_accurate_gpu_emulation && preserve_contents; 345 const bool do_load = Settings::values.use_accurate_gpu_emulation && preserve_contents;
346 for (auto surface : overlaps) { 346 for (auto surface : overlaps) {
347 Unregister(surface); 347 Unregister(surface);
@@ -502,9 +502,10 @@ private:
502 // matches at certain level we are pretty much done. 502 // matches at certain level we are pretty much done.
503 if (l1_cache.count(cache_addr) > 0) { 503 if (l1_cache.count(cache_addr) > 0) {
504 TSurface current_surface = l1_cache[cache_addr]; 504 TSurface current_surface = l1_cache[cache_addr];
505 if (!current_surface->MatchesTopology(params)) { 505 auto topological_result = current_surface->MatchesTopology(params);
506 if (topological_result != MatchTopologyResult::FullMatch) {
506 std::vector<TSurface> overlaps{current_surface}; 507 std::vector<TSurface> overlaps{current_surface};
507 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, true); 508 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, topological_result);
508 } 509 }
509 MatchStructureResult s_result = current_surface->MatchesStructure(params); 510 MatchStructureResult s_result = current_surface->MatchesStructure(params);
510 if (s_result != MatchStructureResult::None && 511 if (s_result != MatchStructureResult::None &&
@@ -534,8 +535,9 @@ private:
534 // we do a topological test to ensure we can find some relationship. If it fails 535 // we do a topological test to ensure we can find some relationship. If it fails
535 // inmediatly recycle the texture 536 // inmediatly recycle the texture
536 for (auto surface : overlaps) { 537 for (auto surface : overlaps) {
537 if (!surface->MatchesTopology(params)) { 538 auto topological_result = surface->MatchesTopology(params);
538 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, true); 539 if (topological_result != MatchTopologyResult::FullMatch) {
540 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, topological_result);
539 } 541 }
540 } 542 }
541 543
@@ -553,7 +555,7 @@ private:
553 return *view; 555 return *view;
554 } 556 }
555 } 557 }
556 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); 558 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, MatchTopologyResult::FullMatch);
557 } 559 }
558 // Now we check if the candidate is a mipmap/layer of the overlap 560 // Now we check if the candidate is a mipmap/layer of the overlap
559 std::optional<TView> view = 561 std::optional<TView> view =
@@ -576,13 +578,13 @@ private:
576 pair.first->EmplaceView(params, gpu_addr, candidate_size); 578 pair.first->EmplaceView(params, gpu_addr, candidate_size);
577 if (mirage_view) 579 if (mirage_view)
578 return {pair.first, *mirage_view}; 580 return {pair.first, *mirage_view};
579 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); 581 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, MatchTopologyResult::FullMatch);
580 } 582 }
581 return {current_surface, *view}; 583 return {current_surface, *view};
582 } 584 }
583 // The next case is unsafe, so if we r in accurate GPU, just skip it 585 // The next case is unsafe, so if we r in accurate GPU, just skip it
584 if (Settings::values.use_accurate_gpu_emulation) { 586 if (Settings::values.use_accurate_gpu_emulation) {
585 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); 587 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, MatchTopologyResult::FullMatch);
586 } 588 }
587 // This is the case the texture is a part of the parent. 589 // This is the case the texture is a part of the parent.
588 if (current_surface->MatchesSubTexture(params, gpu_addr)) { 590 if (current_surface->MatchesSubTexture(params, gpu_addr)) {
@@ -599,7 +601,7 @@ private:
599 } 601 }
600 } 602 }
601 // We failed all the tests, recycle the overlaps into a new texture. 603 // We failed all the tests, recycle the overlaps into a new texture.
602 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); 604 return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, MatchTopologyResult::FullMatch);
603 } 605 }
604 606
605 std::pair<TSurface, TView> InitializeSurface(GPUVAddr gpu_addr, const SurfaceParams& params, 607 std::pair<TSurface, TView> InitializeSurface(GPUVAddr gpu_addr, const SurfaceParams& params,