[D3D12] Fix mipmapped cubemaps and stacked textures

This commit is contained in:
Triang3l 2018-10-29 22:40:29 +03:00
parent e4a7d1dc5e
commit 251f078baf
5 changed files with 49 additions and 41 deletions

View File

@ -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)) {

View File

@ -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);

View File

@ -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).

View File

@ -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 GetGuestMipSliceStorageSize(uint32_t width_blocks,
uint32_t height_blocks,
uint32_t depth_blocks, bool is_tiled,
TextureFormat format, uint32_t* row_pitch_out) {
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 /

View File

@ -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,
// 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);
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) {