summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/texture_cache/surface_params.cpp38
-rw-r--r--src/video_core/texture_cache/surface_params.h14
-rw-r--r--src/video_core/texture_cache/texture_cache.h89
-rw-r--r--src/video_core/textures/decoders.h4
4 files changed, 144 insertions, 1 deletions
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp
index a4f1edd9a..38b3a4ba8 100644
--- a/src/video_core/texture_cache/surface_params.cpp
+++ b/src/video_core/texture_cache/surface_params.cpp
@@ -392,4 +392,42 @@ std::string SurfaceParams::TargetName() const {
392 } 392 }
393} 393}
394 394
395u32 SurfaceParams::GetBlockSize() const {
396 const u32 x = 64U << block_width;
397 const u32 y = 8U << block_height;
398 const u32 z = 1U << block_depth;
399 return x * y * z;
400}
401
402std::pair<u32, u32> SurfaceParams::GetBlockXY() const {
403 const u32 x_pixels = 64U / GetBytesPerPixel();
404 const u32 x = x_pixels << block_width;
405 const u32 y = 8U << block_height;
406 return {x, y};
407}
408
409std::tuple<u32, u32, u32> SurfaceParams::GetBlockOffsetXYZ(u32 offset) const {
410 const auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); };
411 const u32 block_size = GetBlockSize();
412 const u32 block_index = offset / block_size;
413 const u32 gob_offset = offset % block_size;
414 const u32 gob_index = gob_offset / static_cast<u32>(Tegra::Texture::GetGOBSize());
415 const u32 x_gob_pixels = 64U / GetBytesPerPixel();
416 const u32 x_block_pixels = x_gob_pixels << block_width;
417 const u32 y_block_pixels = 8U << block_height;
418 const u32 z_block_pixels = 1U << block_depth;
419 const u32 x_blocks = div_ceil(width, x_block_pixels);
420 const u32 y_blocks = div_ceil(height, y_block_pixels);
421 const u32 z_blocks = div_ceil(depth, z_block_pixels);
422 const u32 base_x = block_index % x_blocks;
423 const u32 base_y = (block_index / x_blocks) % y_blocks;
424 const u32 base_z = (block_index / (x_blocks * y_blocks)) % z_blocks;
425 u32 x = base_x * x_block_pixels;
426 u32 y = base_y * y_block_pixels;
427 u32 z = base_z * z_block_pixels;
428 z += gob_index >> block_height;
429 y += (gob_index * 8U) % y_block_pixels;
430 return {x, y, z};
431}
432
395} // namespace VideoCommon 433} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h
index 129817ad3..992b5c022 100644
--- a/src/video_core/texture_cache/surface_params.h
+++ b/src/video_core/texture_cache/surface_params.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <utility>
8
7#include "common/alignment.h" 9#include "common/alignment.h"
8#include "common/bit_util.h" 10#include "common/bit_util.h"
9#include "common/cityhash.h" 11#include "common/cityhash.h"
@@ -136,6 +138,15 @@ public:
136 138
137 std::size_t GetConvertedMipmapSize(u32 level) const; 139 std::size_t GetConvertedMipmapSize(u32 level) const;
138 140
141 /// Get this texture Tegra Block size in guest memory layout
142 u32 GetBlockSize() const;
143
144 /// Get X, Y coordinates max sizes of a single block.
145 std::pair<u32, u32> GetBlockXY() const;
146
147 /// Get the offset in x, y, z coordinates from a memory offset
148 std::tuple<u32, u32, u32> GetBlockOffsetXYZ(u32 offset) const;
149
139 /// Returns the size of a layer in bytes in guest memory. 150 /// Returns the size of a layer in bytes in guest memory.
140 std::size_t GetGuestLayerSize() const { 151 std::size_t GetGuestLayerSize() const {
141 return GetLayerSize(false, false); 152 return GetLayerSize(false, false);
@@ -269,7 +280,8 @@ private:
269 280
270 /// Returns the size of all mipmap levels and aligns as needed. 281 /// Returns the size of all mipmap levels and aligns as needed.
271 std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const { 282 std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const {
272 return GetLayerSize(as_host_size, uncompressed) * (layer_only ? 1U : depth); 283 return GetLayerSize(as_host_size, uncompressed) *
284 (layer_only ? 1U : (is_layered ? depth : 1U));
273 } 285 }
274 286
275 /// Returns the size of a layer 287 /// Returns the size of a layer
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 02d2e9136..f4c015635 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -616,6 +616,86 @@ private:
616 } 616 }
617 617
618 /** 618 /**
619 * Takes care of managing 3D textures and its slices. Does HLE methods for reconstructing the 3D
620 * textures within the GPU if possible. Falls back to LLE when it isn't possible to use any of
621 * the HLE methods.
622 *
623 * @param overlaps The overlapping surfaces registered in the cache.
624 * @param params The parameters on the new surface.
625 * @param gpu_addr The starting address of the new surface.
626 * @param cache_addr The starting address of the new surface on physical memory.
627 * @param preserve_contents Indicates that the new surface should be loaded from memory or
628 * left blank.
629 */
630 std::optional<std::pair<TSurface, TView>> Manage3DSurfaces(std::vector<TSurface>& overlaps,
631 const SurfaceParams& params,
632 const GPUVAddr gpu_addr,
633 const CacheAddr cache_addr,
634 bool preserve_contents) {
635 if (params.target == SurfaceTarget::Texture3D) {
636 bool failed = false;
637 if (params.num_levels > 1) {
638 // We can't handle mipmaps in 3D textures yet, better fallback to LLE approach
639 return std::nullopt;
640 }
641 TSurface new_surface = GetUncachedSurface(gpu_addr, params);
642 bool modified = false;
643 for (auto& surface : overlaps) {
644 const SurfaceParams& src_params = surface->GetSurfaceParams();
645 if (src_params.target != SurfaceTarget::Texture2D) {
646 failed = true;
647 break;
648 }
649 if (src_params.height != params.height) {
650 failed = true;
651 break;
652 }
653 if (src_params.block_depth != params.block_depth ||
654 src_params.block_height != params.block_height) {
655 failed = true;
656 break;
657 }
658 const u32 offset = static_cast<u32>(surface->GetCacheAddr() - cache_addr);
659 const auto [x, y, z] = params.GetBlockOffsetXYZ(offset);
660 modified |= surface->IsModified();
661 const CopyParams copy_params(0, 0, 0, 0, 0, z, 0, 0, params.width, params.height,
662 1);
663 ImageCopy(surface, new_surface, copy_params);
664 }
665 if (failed) {
666 return std::nullopt;
667 }
668 for (const auto& surface : overlaps) {
669 Unregister(surface);
670 }
671 new_surface->MarkAsModified(modified, Tick());
672 Register(new_surface);
673 auto view = new_surface->GetMainView();
674 return {{std::move(new_surface), view}};
675 } else {
676 for (const auto& surface : overlaps) {
677 if (!surface->MatchTarget(params.target)) {
678 if (overlaps.size() == 1 && surface->GetCacheAddr() == cache_addr) {
679 if (Settings::values.use_accurate_gpu_emulation) {
680 return std::nullopt;
681 }
682 Unregister(surface);
683 return InitializeSurface(gpu_addr, params, preserve_contents);
684 }
685 return std::nullopt;
686 }
687 if (surface->GetCacheAddr() != cache_addr) {
688 continue;
689 }
690 if (surface->MatchesStructure(params) == MatchStructureResult::FullMatch) {
691 return {{surface, surface->GetMainView()}};
692 }
693 }
694 return InitializeSurface(gpu_addr, params, preserve_contents);
695 }
696 }
697
698 /**
619 * Gets the starting address and parameters of a candidate surface and tries 699 * Gets the starting address and parameters of a candidate surface and tries
620 * to find a matching surface within the cache. This is done in 3 big steps: 700 * to find a matching surface within the cache. This is done in 3 big steps:
621 * 701 *
@@ -687,6 +767,15 @@ private:
687 } 767 }
688 } 768 }
689 769
770 // Check if it's a 3D texture
771 if (params.block_depth > 0) {
772 auto surface =
773 Manage3DSurfaces(overlaps, params, gpu_addr, cache_addr, preserve_contents);
774 if (surface) {
775 return *surface;
776 }
777 }
778
690 // Split cases between 1 overlap or many. 779 // Split cases between 1 overlap or many.
691 if (overlaps.size() == 1) { 780 if (overlaps.size() == 1) {
692 TSurface current_surface = overlaps[0]; 781 TSurface current_surface = overlaps[0];
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index f1e3952bc..e5eac3f3b 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -12,6 +12,10 @@ namespace Tegra::Texture {
12 12
13// GOBSize constant. Calculated by 64 bytes in x multiplied by 8 y coords, represents 13// GOBSize constant. Calculated by 64 bytes in x multiplied by 8 y coords, represents
14// an small rect of (64/bytes_per_pixel)X8. 14// an small rect of (64/bytes_per_pixel)X8.
15inline std::size_t GetGOBSize() {
16 return 512;
17}
18
15inline std::size_t GetGOBSizeShift() { 19inline std::size_t GetGOBSizeShift() {
16 return 9; 20 return 9;
17} 21}