aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/texture_cache/texture_cache.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/texture_cache/texture_cache.h')
-rw-r--r--src/video_core/texture_cache/texture_cache.h65
1 files changed, 65 insertions, 0 deletions
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 3b783fc6c6..4b93cd135b 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -729,6 +729,10 @@ void TextureCache<P>::WriteMemory(DAddr cpu_addr, size_t size) {
image.flags |= ImageFlagBits::CpuModified | ImageFlagBits::Remapped;
return;
}
+ if (True(image.flags & ImageFlagBits::SparseTiles)) {
+ MarkRangeWritten(image, cpu_addr, size);
+ return;
+ }
if (UploadsByLayer(image)) {
MarkLayersWritten(image, cpu_addr, size);
return;
@@ -1316,6 +1320,10 @@ void TextureCache<P>::RefreshContents(Image& image, ImageId image_id) {
RefreshSparseLayers(image);
return;
}
+ if (True(image.flags & ImageFlagBits::SparseTiles)) {
+ RefreshSparseTiles(image);
+ return;
+ }
if (!image.dirty_layers.empty() && UploadWrittenLayers(image)) {
runtime.InsertUploadMemoryBarrier();
return;
@@ -1401,6 +1409,63 @@ void TextureCache<P>::MarkLayersWritten(Image& image, DAddr cpu_addr, size_t siz
}
template <class P>
+void TextureCache<P>::MarkRangeWritten(Image& image, DAddr cpu_addr, size_t size) {
+ if (True(image.flags & ImageFlagBits::CpuModified) && image.dirty_ranges.empty()) {
+ return; // all of it is dirty already
+ }
+ const DAddr begin = (std::max<DAddr>)(cpu_addr, image.cpu_addr);
+ const DAddr end = (std::min<DAddr>)(cpu_addr + size, image.cpu_addr + image.guest_size_bytes);
+ if (end <= begin) {
+ return;
+ }
+ image.flags |= ImageFlagBits::CpuModified;
+ image.dirty_ranges.emplace_back(begin - image.cpu_addr, end - begin);
+}
+
+template <class P>
+void TextureCache<P>::RefreshSparseTiles(Image& image) {
+ if constexpr (requires { &Image::BindTiles; }) {
+ // The ranges written since the last upload, or, for a new image, all of it that can hold
+ // data (the tiles the game maps there, or the blocks written).
+ std::vector<std::pair<u64, u64>> ranges = std::move(image.dirty_ranges);
+ image.dirty_ranges.clear();
+ if (ranges.empty()) {
+ ranges = Tegra::Nx2SparseDataRanges(image.gpu_addr, image.guest_size_bytes);
+ }
+ const std::vector<LevelRect> rects =
+ SparseTileRects(image.info, ranges, image.SparseTileWidth(), image.SparseTileHeight(),
+ image.SparseTailLevel());
+ if (rects.empty() || !BindSparseTiles(image, rects)) {
+ runtime.TransitionImageLayout(image);
+ return;
+ }
+ const size_t bytes = UnswizzledRectsBytes(image.info, rects);
+ auto staging = runtime.UploadStagingBuffer(bytes);
+ const std::vector<BufferImageCopy> copies =
+ UnswizzleImageRects(*gpu_memory, image.gpu_addr, image.info, rects, staging.mapped_span);
+ image.UploadMemory(staging, copies);
+ runtime.InsertUploadMemoryBarrier();
+ ++images_uploaded;
+ uploaded_bytes += bytes;
+ }
+}
+
+template <class P>
+bool TextureCache<P>::BindSparseTiles(Image& image, std::span<const LevelRect> rects) {
+ if constexpr (requires { &Image::BindTiles; }) {
+ const u64 bound_bytes = ImageMemoryBytes(image);
+ const bool bound = image.BindTiles(rects);
+ // RegisterImage counts what an image has bound by then; later binds are added here.
+ if (True(image.flags & ImageFlagBits::Registered)) {
+ total_used_memory += ImageMemoryBytes(image) - bound_bytes;
+ }
+ return bound;
+ } else {
+ return false;
+ }
+}
+
+template <class P>
bool TextureCache<P>::UploadWrittenLayers(Image& image) {
if constexpr (requires { &Runtime::AccelerateImageUploadLayers; }) {
const u32 num_layers = static_cast<u32>(image.info.resources.layers);