diff --git a/src/xenia/gpu/d3d12/render_target_cache.cc b/src/xenia/gpu/d3d12/render_target_cache.cc index ac5a12ec4..982a52fad 100644 --- a/src/xenia/gpu/d3d12/render_target_cache.cc +++ b/src/xenia/gpu/d3d12/render_target_cache.cc @@ -1051,7 +1051,7 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory, // resolve to 8bpp or 16bpp textures at very odd locations. return false; } - uint32_t dest_size = texture_util::GetGuestMipStorageSize( + uint32_t dest_size = texture_util::GetGuestMipSliceStorageSize( xe::align(dest_pitch, 32u), xe::align(dest_height, 32u), 1, true, dest_format, nullptr); if (dest_info & (1 << 3)) { diff --git a/src/xenia/gpu/d3d12/texture_cache.cc b/src/xenia/gpu/d3d12/texture_cache.cc index 05999bc7a..af08792b3 100644 --- a/src/xenia/gpu/d3d12/texture_cache.cc +++ b/src/xenia/gpu/d3d12/texture_cache.cc @@ -846,7 +846,7 @@ bool TextureCache::TileResolvedTexture( // Calculate the texture size for memory operations and ensure we can write to // the specified shared memory location. - uint32_t texture_size = texture_util::GetGuestMipStorageSize( + uint32_t texture_size = texture_util::GetGuestMipSliceStorageSize( texture_pitch, texture_height, 1, true, format, nullptr); if (texture_size == 0) { return true; @@ -1187,21 +1187,25 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) { texture->state = state; texture->mip_offsets[0] = 0; uint32_t width_blocks, height_blocks, depth_blocks; + uint32_t array_size = key.dimension != Dimension::k3D ? key.depth : 1; if (key.base_page != 0) { texture_util::GetGuestMipBlocks(key.dimension, key.width, key.height, key.depth, key.format, 0, width_blocks, height_blocks, depth_blocks); - texture->base_slice_size = texture_util::GetGuestMipStorageSize( + uint32_t slice_size = texture_util::GetGuestMipSliceStorageSize( width_blocks, height_blocks, depth_blocks, key.tiled, key.format, - &texture->mip_pitches[0]); + &texture->pitches[0]); + texture->slice_sizes[0] = slice_size; + texture->base_size = slice_size * array_size; texture->base_in_sync = false; } else { - texture->base_slice_size = 0; - texture->mip_pitches[0] = 0; + texture->base_size = 0; + texture->slice_sizes[0] = 0; + texture->pitches[0] = 0; // Never try to upload the base level if there is none. texture->base_in_sync = true; } - texture->mip_slice_size = 0; + texture->mip_size = 0; if (key.mip_page != 0) { uint32_t mip_max_storage_level = key.mip_max_level; if (key.packed_mips) { @@ -1213,32 +1217,31 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) { texture_util::GetGuestMipBlocks(key.dimension, key.width, key.height, key.depth, key.format, i, width_blocks, height_blocks, depth_blocks); - texture->mip_offsets[i] = texture->mip_slice_size; - texture->mip_slice_size += texture_util::GetGuestMipStorageSize( + texture->mip_offsets[i] = texture->mip_size; + uint32_t slice_size = texture_util::GetGuestMipSliceStorageSize( width_blocks, height_blocks, depth_blocks, key.tiled, key.format, - &texture->mip_pitches[i]); + &texture->pitches[i]); + texture->slice_sizes[i] = slice_size; + texture->mip_size += slice_size * array_size; } // The rest are either packed levels or don't exist at all. for (uint32_t i = mip_max_storage_level + 1; i < xe::countof(texture->mip_offsets); ++i) { texture->mip_offsets[i] = texture->mip_offsets[mip_max_storage_level]; - texture->mip_pitches[i] = texture->mip_pitches[mip_max_storage_level]; + texture->slice_sizes[i] = texture->slice_sizes[mip_max_storage_level]; + texture->pitches[i] = texture->pitches[mip_max_storage_level]; } texture->mips_in_sync = false; } else { std::memset(&texture->mip_offsets[1], 0, (xe::countof(texture->mip_offsets) - 1) * sizeof(uint32_t)); - std::memset(&texture->mip_pitches[1], 0, - (xe::countof(texture->mip_pitches) - 1) * sizeof(uint32_t)); + std::memset(&texture->slice_sizes[1], 0, + (xe::countof(texture->slice_sizes) - 1) * sizeof(uint32_t)); + std::memset(&texture->pitches[1], 0, + (xe::countof(texture->pitches) - 1) * sizeof(uint32_t)); // Never try to upload the mipmaps if there are none. texture->mips_in_sync = true; } - texture->base_size = texture->base_slice_size; - texture->mip_size = texture->mip_slice_size; - if (key.dimension != Dimension::k3D) { - texture->base_size *= key.depth; - texture->mip_size *= key.depth; - } texture->base_watch_handle = nullptr; texture->mip_watch_handle = nullptr; textures_.insert(std::make_pair(map_key, texture)); @@ -1363,16 +1366,15 @@ bool TextureCache::LoadTextureData(Texture* texture) { copy_buffer_state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; for (uint32_t j = mip_first; j <= mip_last; ++j) { if (j == 0) { - load_constants.guest_base = - (texture->key.base_page << 12) + i * texture->base_slice_size; + load_constants.guest_base = texture->key.base_page << 12; } else { - load_constants.guest_base = - (texture->key.mip_page << 12) + i * texture->mip_slice_size; + load_constants.guest_base = texture->key.mip_page << 12; } - load_constants.guest_base += texture->mip_offsets[j]; + load_constants.guest_base += + texture->mip_offsets[j] + i * texture->slice_sizes[j]; load_constants.guest_pitch = texture->key.tiled ? LoadConstants::kGuestPitchTiled - : texture->mip_pitches[j]; + : texture->pitches[j]; load_constants.host_base = uint32_t(host_layouts[j].Offset); load_constants.host_pitch = host_layouts[j].Footprint.RowPitch; load_constants.size_texels[0] = std::max(width >> j, 1u); diff --git a/src/xenia/gpu/d3d12/texture_cache.h b/src/xenia/gpu/d3d12/texture_cache.h index 9715ed3af..96a5f162c 100644 --- a/src/xenia/gpu/d3d12/texture_cache.h +++ b/src/xenia/gpu/d3d12/texture_cache.h @@ -292,18 +292,19 @@ class TextureCache { TextureKey key; ID3D12Resource* resource; D3D12_RESOURCE_STATES state; - // Byte size of one array slice of the top guest mip level. - uint32_t base_slice_size; + // Byte size of the top guest mip level. uint32_t base_size; - // Byte size of one array slice of mips between 1 and key.mip_max_level. - uint32_t mip_slice_size; - // Byte size of mips between 1 and key.mip_max_level. + // Byte size of mips between 1 and key.mip_max_level, containing all array + // slices. uint32_t mip_size; - // Byte offsets of each mipmap within one slice. + // Offsets of all the array slices on a mip level relative to mips_address + // (0 for mip 0, it's relative to base_address then, and for mip 1). uint32_t mip_offsets[14]; - // Byte pitches of each mipmap within one slice (for linear layout mainly). - uint32_t mip_pitches[14]; + // Byte sizes of an array slice on each mip level. + uint32_t slice_sizes[14]; + // Row pitches on each mip level (for linear layout mainly). + uint32_t pitches[14]; // Watch handles for the memory ranges (protected by the shared memory watch // mutex). diff --git a/src/xenia/gpu/texture_util.cc b/src/xenia/gpu/texture_util.cc index 6e8ac2f31..33f163fba 100644 --- a/src/xenia/gpu/texture_util.cc +++ b/src/xenia/gpu/texture_util.cc @@ -54,9 +54,11 @@ void GetGuestMipBlocks(Dimension dimension, uint32_t width, uint32_t height, } } -uint32_t GetGuestMipStorageSize(uint32_t width_blocks, uint32_t height_blocks, - uint32_t depth_blocks, bool is_tiled, - TextureFormat format, uint32_t* row_pitch_out) { +uint32_t GetGuestMipSliceStorageSize(uint32_t width_blocks, + uint32_t height_blocks, + uint32_t depth_blocks, bool is_tiled, + TextureFormat format, + uint32_t* row_pitch_out) { const FormatInfo* format_info = FormatInfo::Get(format); uint32_t row_pitch = width_blocks * format_info->block_width * format_info->block_height * format_info->bits_per_pixel / diff --git a/src/xenia/gpu/texture_util.h b/src/xenia/gpu/texture_util.h index d87e93a2b..780e6de18 100644 --- a/src/xenia/gpu/texture_util.h +++ b/src/xenia/gpu/texture_util.h @@ -29,11 +29,14 @@ void GetGuestMipBlocks(Dimension dimension, uint32_t width, uint32_t height, uint32_t& width_blocks_out, uint32_t& height_blocks_out, uint32_t& depth_blocks_out); -// Calculates the number of bytes required to store a single mip level - width, -// height and depth must be obtained via GetGuestMipExtent. -uint32_t GetGuestMipStorageSize(uint32_t width_blocks, uint32_t height_blocks, - uint32_t depth_blocks, bool is_tiled, - TextureFormat format, uint32_t* row_pitch_out); +// Calculates the number of bytes required to store a single array slice within +// a single mip level - width, height and depth must be obtained via +// GetGuestMipBlocks. +uint32_t GetGuestMipSliceStorageSize(uint32_t width_blocks, + uint32_t height_blocks, + uint32_t depth_blocks, bool is_tiled, + TextureFormat format, + uint32_t* row_pitch_out); // Gets the number of the mipmap level where the packed mips are stored. inline uint32_t GetPackedMipLevel(uint32_t width, uint32_t height) {