summaryrefslogtreecommitdiff
path: root/src/video_core/texture_cache.cpp
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-04-24 16:35:54 -0300
committerGravatar ReinUsesLisp2019-06-20 21:36:11 -0300
commit1b4503c571d3b961efe74fa7e35d5fa14941ec09 (patch)
treefb732f50d8bd2855f3fa7657c7c6d36c58134d89 /src/video_core/texture_cache.cpp
parenttexture_cache: Move staging buffer into a generic implementation (diff)
downloadyuzu-1b4503c571d3b961efe74fa7e35d5fa14941ec09.tar.gz
yuzu-1b4503c571d3b961efe74fa7e35d5fa14941ec09.tar.xz
yuzu-1b4503c571d3b961efe74fa7e35d5fa14941ec09.zip
texture_cache: Split texture cache into different files
Diffstat (limited to 'src/video_core/texture_cache.cpp')
-rw-r--r--src/video_core/texture_cache.cpp530
1 files changed, 0 insertions, 530 deletions
diff --git a/src/video_core/texture_cache.cpp b/src/video_core/texture_cache.cpp
deleted file mode 100644
index 146e8ed9b..000000000
--- a/src/video_core/texture_cache.cpp
+++ /dev/null
@@ -1,530 +0,0 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/alignment.h"
6#include "common/assert.h"
7#include "common/cityhash.h"
8#include "common/common_types.h"
9#include "core/core.h"
10#include "video_core/morton.h"
11#include "video_core/surface.h"
12#include "video_core/texture_cache.h"
13#include "video_core/textures/convert.h"
14#include "video_core/textures/decoders.h"
15#include "video_core/textures/texture.h"
16
17namespace VideoCommon {
18
19using VideoCore::MortonSwizzleMode;
20
21using VideoCore::Surface::ComponentTypeFromDepthFormat;
22using VideoCore::Surface::ComponentTypeFromRenderTarget;
23using VideoCore::Surface::ComponentTypeFromTexture;
24using VideoCore::Surface::PixelFormatFromDepthFormat;
25using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
26using VideoCore::Surface::PixelFormatFromTextureFormat;
27using VideoCore::Surface::SurfaceTarget;
28using VideoCore::Surface::SurfaceTargetFromTextureType;
29
30using Tegra::Texture::ConvertFromGuestToHost;
31
32namespace {
33
34constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) {
35 return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile);
36}
37
38void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
39 u32 level) {
40 const u32 width{params.GetMipWidth(level)};
41 const u32 height{params.GetMipHeight(level)};
42 const u32 block_height{params.GetMipBlockHeight(level)};
43 const u32 block_depth{params.GetMipBlockDepth(level)};
44
45 std::size_t guest_offset{params.GetGuestMipmapLevelOffset(level)};
46 if (params.IsLayered()) {
47 std::size_t host_offset{0};
48 const std::size_t guest_stride = params.GetGuestLayerSize();
49 const std::size_t host_stride = params.GetHostLayerSize(level);
50 for (u32 layer = 0; layer < params.GetNumLayers(); layer++) {
51 MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
52 1, params.GetTileWidthSpacing(), buffer + host_offset,
53 memory + guest_offset);
54 guest_offset += guest_stride;
55 host_offset += host_stride;
56 }
57 } else {
58 MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
59 params.GetMipDepth(level), params.GetTileWidthSpacing(), buffer,
60 memory + guest_offset);
61 }
62}
63
64} // Anonymous namespace
65
66SurfaceBaseImpl::SurfaceBaseImpl(const SurfaceParams& params) : params{params} {
67 staging_buffer.resize(params.GetHostSizeInBytes());
68}
69
70SurfaceBaseImpl::~SurfaceBaseImpl() = default;
71
72void SurfaceBaseImpl::LoadBuffer() {
73 if (params.IsTiled()) {
74 ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}",
75 params.GetBlockWidth(), static_cast<u32>(params.GetTarget()));
76 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
77 u8* const buffer{GetStagingBufferLevelData(level)};
78 SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params, buffer, level);
79 }
80 } else {
81 ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented");
82 const u32 bpp{GetFormatBpp(params.GetPixelFormat()) / CHAR_BIT};
83 const u32 block_width{params.GetDefaultBlockWidth()};
84 const u32 block_height{params.GetDefaultBlockHeight()};
85 const u32 width{(params.GetWidth() + block_width - 1) / block_width};
86 const u32 height{(params.GetHeight() + block_height - 1) / block_height};
87 const u32 copy_size{width * bpp};
88 if (params.GetPitch() == copy_size) {
89 std::memcpy(staging_buffer.data(), host_ptr, params.GetHostSizeInBytes());
90 } else {
91 const u8* start{host_ptr};
92 u8* write_to{staging_buffer.data()};
93 for (u32 h = height; h > 0; --h) {
94 std::memcpy(write_to, start, copy_size);
95 start += params.GetPitch();
96 write_to += copy_size;
97 }
98 }
99 }
100
101 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
102 ConvertFromGuestToHost(GetStagingBufferLevelData(level), params.GetPixelFormat(),
103 params.GetMipWidth(level), params.GetMipHeight(level),
104 params.GetMipDepth(level), true, true);
105 }
106}
107
108void SurfaceBaseImpl::FlushBuffer() {
109 if (params.IsTiled()) {
110 ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}",
111 params.GetBlockWidth());
112 for (u32 level = 0; level < params.GetNumLevels(); ++level) {
113 u8* const buffer = GetStagingBufferLevelData(level);
114 SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params, buffer, level);
115 }
116 } else {
117 UNIMPLEMENTED();
118 /*
119 ASSERT(params.GetTarget() == SurfaceTarget::Texture2D);
120 ASSERT(params.GetNumLevels() == 1);
121
122 const u32 bpp{params.GetFormatBpp() / 8};
123 const u32 copy_size{params.GetWidth() * bpp};
124 if (params.GetPitch() == copy_size) {
125 std::memcpy(host_ptr, staging_buffer.data(), GetSizeInBytes());
126 } else {
127 u8* start{host_ptr};
128 const u8* read_to{staging_buffer.data()};
129 for (u32 h = params.GetHeight(); h > 0; --h) {
130 std::memcpy(start, read_to, copy_size);
131 start += params.GetPitch();
132 read_to += copy_size;
133 }
134 }
135 */
136 }
137}
138
139SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
140 const Tegra::Texture::FullTextureInfo& config) {
141 SurfaceParams params;
142 params.is_tiled = config.tic.IsTiled();
143 params.srgb_conversion = config.tic.IsSrgbConversionEnabled();
144 params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0,
145 params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0,
146 params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0,
147 params.tile_width_spacing = params.is_tiled ? (1 << config.tic.tile_width_spacing.Value()) : 1;
148 params.pixel_format = PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(),
149 params.srgb_conversion);
150 params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value());
151 params.type = GetFormatType(params.pixel_format);
152 params.target = SurfaceTargetFromTextureType(config.tic.texture_type);
153 params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format));
154 params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format));
155 params.depth = config.tic.Depth();
156 if (params.target == SurfaceTarget::TextureCubemap ||
157 params.target == SurfaceTarget::TextureCubeArray) {
158 params.depth *= 6;
159 }
160 params.pitch = params.is_tiled ? 0 : config.tic.Pitch();
161 params.unaligned_height = config.tic.Height();
162 params.num_levels = config.tic.max_mip_level + 1;
163
164 params.CalculateCachedValues();
165 return params;
166}
167
168SurfaceParams SurfaceParams::CreateForDepthBuffer(
169 Core::System& system, u32 zeta_width, u32 zeta_height, Tegra::DepthFormat format,
170 u32 block_width, u32 block_height, u32 block_depth,
171 Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type) {
172 SurfaceParams params;
173 params.is_tiled = type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
174 params.srgb_conversion = false;
175 params.block_width = 1 << std::min(block_width, 5U);
176 params.block_height = 1 << std::min(block_height, 5U);
177 params.block_depth = 1 << std::min(block_depth, 5U);
178 params.tile_width_spacing = 1;
179 params.pixel_format = PixelFormatFromDepthFormat(format);
180 params.component_type = ComponentTypeFromDepthFormat(format);
181 params.type = GetFormatType(params.pixel_format);
182 params.width = zeta_width;
183 params.height = zeta_height;
184 params.unaligned_height = zeta_height;
185 params.target = SurfaceTarget::Texture2D;
186 params.depth = 1;
187 params.num_levels = 1;
188
189 params.CalculateCachedValues();
190 return params;
191}
192
193SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::size_t index) {
194 const auto& config{system.GPU().Maxwell3D().regs.rt[index]};
195 SurfaceParams params;
196 params.is_tiled =
197 config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
198 params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB ||
199 config.format == Tegra::RenderTargetFormat::RGBA8_SRGB;
200 params.block_width = 1 << config.memory_layout.block_width;
201 params.block_height = 1 << config.memory_layout.block_height;
202 params.block_depth = 1 << config.memory_layout.block_depth;
203 params.tile_width_spacing = 1;
204 params.pixel_format = PixelFormatFromRenderTargetFormat(config.format);
205 params.component_type = ComponentTypeFromRenderTarget(config.format);
206 params.type = GetFormatType(params.pixel_format);
207 if (params.is_tiled) {
208 params.width = config.width;
209 } else {
210 const u32 bpp = GetFormatBpp(params.pixel_format) / CHAR_BIT;
211 params.pitch = config.width;
212 params.width = params.pitch / bpp;
213 }
214 params.height = config.height;
215 params.depth = 1;
216 params.unaligned_height = config.height;
217 params.target = SurfaceTarget::Texture2D;
218 params.num_levels = 1;
219
220 params.CalculateCachedValues();
221 return params;
222}
223
224SurfaceParams SurfaceParams::CreateForFermiCopySurface(
225 const Tegra::Engines::Fermi2D::Regs::Surface& config) {
226 SurfaceParams params{};
227 params.is_tiled = !config.linear;
228 params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB ||
229 config.format == Tegra::RenderTargetFormat::RGBA8_SRGB;
230 params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0,
231 params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0,
232 params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0,
233 params.tile_width_spacing = 1;
234 params.pixel_format = PixelFormatFromRenderTargetFormat(config.format);
235 params.component_type = ComponentTypeFromRenderTarget(config.format);
236 params.type = GetFormatType(params.pixel_format);
237 params.width = config.width;
238 params.height = config.height;
239 params.unaligned_height = config.height;
240 // TODO(Rodrigo): Try to guess the surface target from depth and layer parameters
241 params.target = SurfaceTarget::Texture2D;
242 params.depth = 1;
243 params.num_levels = 1;
244
245 params.CalculateCachedValues();
246 return params;
247}
248
249u32 SurfaceParams::GetMipWidth(u32 level) const {
250 return std::max(1U, width >> level);
251}
252
253u32 SurfaceParams::GetMipHeight(u32 level) const {
254 return std::max(1U, height >> level);
255}
256
257u32 SurfaceParams::GetMipDepth(u32 level) const {
258 return IsLayered() ? depth : std::max(1U, depth >> level);
259}
260
261bool SurfaceParams::IsLayered() const {
262 switch (target) {
263 case SurfaceTarget::Texture1DArray:
264 case SurfaceTarget::Texture2DArray:
265 case SurfaceTarget::TextureCubemap:
266 case SurfaceTarget::TextureCubeArray:
267 return true;
268 default:
269 return false;
270 }
271}
272
273u32 SurfaceParams::GetMipBlockHeight(u32 level) const {
274 // Auto block resizing algorithm from:
275 // https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nv50/nv50_miptree.c
276 if (level == 0) {
277 return this->block_height;
278 }
279
280 const u32 height{GetMipHeight(level)};
281 const u32 default_block_height{GetDefaultBlockHeight()};
282 const u32 blocks_in_y{(height + default_block_height - 1) / default_block_height};
283 u32 block_height = 16;
284 while (block_height > 1 && blocks_in_y <= block_height * 4) {
285 block_height >>= 1;
286 }
287 return block_height;
288}
289
290u32 SurfaceParams::GetMipBlockDepth(u32 level) const {
291 if (level == 0) {
292 return this->block_depth;
293 }
294 if (IsLayered()) {
295 return 1;
296 }
297
298 const u32 depth{GetMipDepth(level)};
299 u32 block_depth = 32;
300 while (block_depth > 1 && depth * 2 <= block_depth) {
301 block_depth >>= 1;
302 }
303
304 if (block_depth == 32 && GetMipBlockHeight(level) >= 4) {
305 return 16;
306 }
307
308 return block_depth;
309}
310
311std::size_t SurfaceParams::GetGuestMipmapLevelOffset(u32 level) const {
312 std::size_t offset = 0;
313 for (u32 i = 0; i < level; i++) {
314 offset += GetInnerMipmapMemorySize(i, false, false);
315 }
316 return offset;
317}
318
319std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const {
320 std::size_t offset = 0;
321 for (u32 i = 0; i < level; i++) {
322 offset += GetInnerMipmapMemorySize(i, true, false) * GetNumLayers();
323 }
324 return offset;
325}
326
327std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const {
328 return GetInnerMipmapMemorySize(level, true, false) * GetNumLayers();
329}
330
331std::size_t SurfaceParams::GetGuestLayerSize() const {
332 return GetLayerSize(false, false);
333}
334
335std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) const {
336 std::size_t size = 0;
337 for (u32 level = 0; level < num_levels; ++level) {
338 size += GetInnerMipmapMemorySize(level, as_host_size, uncompressed);
339 }
340 if (is_tiled && (IsLayered() || target == SurfaceTarget::Texture3D)) {
341 return Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth);
342 }
343 return size;
344}
345
346std::size_t SurfaceParams::GetHostLayerSize(u32 level) const {
347 ASSERT(target != SurfaceTarget::Texture3D);
348 return GetInnerMipmapMemorySize(level, true, false);
349}
350
351u32 SurfaceParams::GetDefaultBlockWidth() const {
352 return VideoCore::Surface::GetDefaultBlockWidth(pixel_format);
353}
354
355u32 SurfaceParams::GetDefaultBlockHeight() const {
356 return VideoCore::Surface::GetDefaultBlockHeight(pixel_format);
357}
358
359u32 SurfaceParams::GetBitsPerPixel() const {
360 return VideoCore::Surface::GetFormatBpp(pixel_format);
361}
362
363u32 SurfaceParams::GetBytesPerPixel() const {
364 return VideoCore::Surface::GetBytesPerPixel(pixel_format);
365}
366
367bool SurfaceParams::IsFamiliar(const SurfaceParams& view_params) const {
368 if (std::tie(is_tiled, tile_width_spacing, pixel_format, component_type, type) !=
369 std::tie(view_params.is_tiled, view_params.tile_width_spacing, view_params.pixel_format,
370 view_params.component_type, view_params.type)) {
371 return false;
372 }
373
374 const SurfaceTarget view_target{view_params.target};
375 if (view_target == target) {
376 return true;
377 }
378
379 switch (target) {
380 case SurfaceTarget::Texture1D:
381 case SurfaceTarget::Texture2D:
382 case SurfaceTarget::Texture3D:
383 return false;
384 case SurfaceTarget::Texture1DArray:
385 return view_target == SurfaceTarget::Texture1D;
386 case SurfaceTarget::Texture2DArray:
387 return view_target == SurfaceTarget::Texture2D;
388 case SurfaceTarget::TextureCubemap:
389 return view_target == SurfaceTarget::Texture2D ||
390 view_target == SurfaceTarget::Texture2DArray;
391 case SurfaceTarget::TextureCubeArray:
392 return view_target == SurfaceTarget::Texture2D ||
393 view_target == SurfaceTarget::Texture2DArray ||
394 view_target == SurfaceTarget::TextureCubemap;
395 default:
396 UNIMPLEMENTED_MSG("Unimplemented texture family={}", static_cast<u32>(target));
397 return false;
398 }
399}
400
401bool SurfaceParams::IsPixelFormatZeta() const {
402 return pixel_format >= VideoCore::Surface::PixelFormat::MaxColorFormat &&
403 pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat;
404}
405
406void SurfaceParams::CalculateCachedValues() {
407 switch (target) {
408 case SurfaceTarget::Texture1D:
409 case SurfaceTarget::Texture2D:
410 case SurfaceTarget::Texture3D:
411 num_layers = 1;
412 break;
413 case SurfaceTarget::Texture1DArray:
414 case SurfaceTarget::Texture2DArray:
415 case SurfaceTarget::TextureCubemap:
416 case SurfaceTarget::TextureCubeArray:
417 num_layers = depth;
418 break;
419 default:
420 UNREACHABLE();
421 }
422
423 guest_size_in_bytes = GetInnerMemorySize(false, false, false);
424
425 if (IsPixelFormatASTC(pixel_format)) {
426 // ASTC is uncompressed in software, in emulated as RGBA8
427 host_size_in_bytes = static_cast<std::size_t>(width) * static_cast<std::size_t>(height) *
428 static_cast<std::size_t>(depth) * 4ULL;
429 } else {
430 host_size_in_bytes = GetInnerMemorySize(true, false, false);
431 }
432}
433
434std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size,
435 bool uncompressed) const {
436 const bool tiled{as_host_size ? false : is_tiled};
437 const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())};
438 const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), GetDefaultBlockHeight())};
439 const u32 depth{target == SurfaceTarget::Texture3D ? GetMipDepth(level) : 1U};
440 return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(), width, height, depth,
441 GetMipBlockHeight(level), GetMipBlockDepth(level));
442}
443
444std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only,
445 bool uncompressed) const {
446 return GetLayerSize(as_host_size, uncompressed) * (layer_only ? 1U : num_layers);
447}
448
449std::map<u64, std::pair<u32, u32>> SurfaceParams::CreateViewOffsetMap() const {
450 std::map<u64, std::pair<u32, u32>> view_offset_map;
451 switch (target) {
452 case SurfaceTarget::Texture1D:
453 case SurfaceTarget::Texture2D:
454 case SurfaceTarget::Texture3D: {
455 // TODO(Rodrigo): Add layer iterations for 3D textures
456 constexpr u32 layer = 0;
457 for (u32 level = 0; level < num_levels; ++level) {
458 const std::size_t offset{GetGuestMipmapLevelOffset(level)};
459 view_offset_map.insert({offset, {layer, level}});
460 }
461 break;
462 }
463 case SurfaceTarget::Texture1DArray:
464 case SurfaceTarget::Texture2DArray:
465 case SurfaceTarget::TextureCubemap:
466 case SurfaceTarget::TextureCubeArray: {
467 const std::size_t layer_size{GetGuestLayerSize()};
468 for (u32 level = 0; level < num_levels; ++level) {
469 const std::size_t level_offset{GetGuestMipmapLevelOffset(level)};
470 for (u32 layer = 0; layer < num_layers; ++layer) {
471 const auto layer_offset{static_cast<std::size_t>(layer_size * layer)};
472 const std::size_t offset{level_offset + layer_offset};
473 view_offset_map.insert({offset, {layer, level}});
474 }
475 }
476 break;
477 }
478 default:
479 UNIMPLEMENTED_MSG("Unimplemented surface target {}", static_cast<u32>(target));
480 }
481 return view_offset_map;
482}
483
484bool SurfaceParams::IsViewValid(const SurfaceParams& view_params, u32 layer, u32 level) const {
485 return IsDimensionValid(view_params, level) && IsDepthValid(view_params, level) &&
486 IsInBounds(view_params, layer, level);
487}
488
489bool SurfaceParams::IsDimensionValid(const SurfaceParams& view_params, u32 level) const {
490 return view_params.width == GetMipWidth(level) && view_params.height == GetMipHeight(level);
491}
492
493bool SurfaceParams::IsDepthValid(const SurfaceParams& view_params, u32 level) const {
494 if (view_params.target != SurfaceTarget::Texture3D) {
495 return true;
496 }
497 return view_params.depth == GetMipDepth(level);
498}
499
500bool SurfaceParams::IsInBounds(const SurfaceParams& view_params, u32 layer, u32 level) const {
501 return layer + view_params.num_layers <= num_layers &&
502 level + view_params.num_levels <= num_levels;
503}
504
505std::size_t HasheableSurfaceParams::Hash() const {
506 return static_cast<std::size_t>(
507 Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this)));
508}
509
510bool HasheableSurfaceParams::operator==(const HasheableSurfaceParams& rhs) const {
511 return std::tie(is_tiled, block_width, block_height, block_depth, tile_width_spacing, width,
512 height, depth, pitch, unaligned_height, num_levels, pixel_format,
513 component_type, type, target) ==
514 std::tie(rhs.is_tiled, rhs.block_width, rhs.block_height, rhs.block_depth,
515 rhs.tile_width_spacing, rhs.width, rhs.height, rhs.depth, rhs.pitch,
516 rhs.unaligned_height, rhs.num_levels, rhs.pixel_format, rhs.component_type,
517 rhs.type, rhs.target);
518}
519
520std::size_t ViewKey::Hash() const {
521 return static_cast<std::size_t>(
522 Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this)));
523}
524
525bool ViewKey::operator==(const ViewKey& rhs) const {
526 return std::tie(base_layer, num_layers, base_level, num_levels) ==
527 std::tie(rhs.base_layer, rhs.num_layers, rhs.base_level, rhs.num_levels);
528}
529
530} // namespace VideoCommon