summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2019-12-08 13:13:18 -0400
committerGravatar FernandoS272019-12-22 12:24:34 -0400
commit51c9e98677395564a4fafeaba718cbd2263541bb (patch)
tree7546b488cf1753f227ba9e409a96ff247bc5ae73 /src
parentMerge pull request #3230 from ReinUsesLisp/vk-emu-shaders (diff)
downloadyuzu-51c9e98677395564a4fafeaba718cbd2263541bb.tar.gz
yuzu-51c9e98677395564a4fafeaba718cbd2263541bb.tar.xz
yuzu-51c9e98677395564a4fafeaba718cbd2263541bb.zip
Texture Cache: Add HLE methods for building 3D textures within the GPU in certain scenarios.
This commit adds a series of HLE methods for handling 3D textures in general. This helps games that generate 3D textures on every frame and may reduce loading times for certain games.
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.h88
-rw-r--r--src/video_core/textures/decoders.h4
4 files changed, 143 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..1c6be25da 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 sizes of a 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..5416eee3b 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -616,6 +616,85 @@ private:
616 } 616 }
617 617
618 /** 618 /**
619 * Takes care of managing 3D textures and its slices. Does some HLE methods when possible.
620 * Fallsback to LLE when it isn't possible.
621 *
622 * @param overlaps The overlapping surfaces registered in the cache.
623 * @param params The parameters on the new surface.
624 * @param gpu_addr The starting address of the new surface.
625 * @param cache_addr The starting address of the new surface on physical memory.
626 * @param preserve_contents Indicates that the new surface should be loaded from memory or
627 * left blank.
628 */
629 std::optional<std::pair<TSurface, TView>> Manage3DSurfaces(std::vector<TSurface>& overlaps,
630 const SurfaceParams& params,
631 const GPUVAddr gpu_addr,
632 const CacheAddr cache_addr,
633 bool preserve_contents) {
634 if (params.target == SurfaceTarget::Texture3D) {
635 bool failed = false;
636 if (params.num_levels > 1) {
637 // We can't handle mipmaps in 3D textures yet, better fallback to LLE approach
638 return std::nullopt;
639 }
640 TSurface new_surface = GetUncachedSurface(gpu_addr, params);
641 bool modified = false;
642 for (auto& surface : overlaps) {
643 const SurfaceParams& src_params = surface->GetSurfaceParams();
644 if (src_params.target != SurfaceTarget::Texture2D) {
645 failed = true;
646 break;
647 }
648 if (src_params.height != params.height) {
649 failed = true;
650 break;
651 }
652 if (src_params.block_depth != params.block_depth ||
653 src_params.block_height != params.block_height) {
654 failed = true;
655 break;
656 }
657 const u32 offset = static_cast<u32>(surface->GetCacheAddr() - cache_addr);
658 const auto [x, y, z] = params.GetBlockOffsetXYZ(offset);
659 modified |= surface->IsModified();
660 const CopyParams copy_params(0, 0, 0, 0, 0, z, 0, 0, params.width, params.height,
661 1);
662 ImageCopy(surface, new_surface, copy_params);
663 }
664 if (failed) {
665 return std::nullopt;
666 }
667 for (const auto& surface : overlaps) {
668 Unregister(surface);
669 }
670 new_surface->MarkAsModified(modified, Tick());
671 Register(new_surface);
672 return {{new_surface, new_surface->GetMainView()}};
673 } else {
674 for (const auto& surface : overlaps) {
675 if (!surface->MatchTarget(params.target)) {
676 if (overlaps.size() == 1 && surface->GetCacheAddr() == cache_addr) {
677 if (Settings::values.use_accurate_gpu_emulation) {
678 return std::nullopt;
679 }
680 Unregister(surface);
681 return InitializeSurface(gpu_addr, params, preserve_contents);
682 }
683 return std::nullopt;
684 }
685 if (surface->GetCacheAddr() != cache_addr) {
686 continue;
687 }
688 const auto struct_result = surface->MatchesStructure(params);
689 if (struct_result == MatchStructureResult::FullMatch) {
690 return {{surface, surface->GetMainView()}};
691 }
692 }
693 return InitializeSurface(gpu_addr, params, preserve_contents);
694 }
695 }
696
697 /**
619 * Gets the starting address and parameters of a candidate surface and tries 698 * 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: 699 * to find a matching surface within the cache. This is done in 3 big steps:
621 * 700 *
@@ -687,6 +766,15 @@ private:
687 } 766 }
688 } 767 }
689 768
769 // Look if it's a 3D texture
770 if (params.block_depth > 0) {
771 std::optional<std::pair<TSurface, TView>> surface =
772 Manage3DSurfaces(overlaps, params, gpu_addr, cache_addr, preserve_contents);
773 if (surface) {
774 return *surface;
775 }
776 }
777
690 // Split cases between 1 overlap or many. 778 // Split cases between 1 overlap or many.
691 if (overlaps.size() == 1) { 779 if (overlaps.size() == 1) {
692 TSurface current_surface = overlaps[0]; 780 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}