From 79f8fe9f376271d370574c5792fbb12daec0a1a8 Mon Sep 17 00:00:00 2001 From: gibbed Date: Thu, 31 May 2018 21:50:22 -0500 Subject: [PATCH] [GPU] Fixes to problems caused by previous commit (bad handling of memory addressing, watches, etc). --- src/xenia/gpu/texture_extent.cc | 36 ++++---- src/xenia/gpu/texture_info.cc | 56 +++++-------- src/xenia/gpu/vulkan/texture_cache.cc | 114 +++++++++++++++++--------- 3 files changed, 115 insertions(+), 91 deletions(-) diff --git a/src/xenia/gpu/texture_extent.cc b/src/xenia/gpu/texture_extent.cc index aa20dfaf2..aed06f77b 100644 --- a/src/xenia/gpu/texture_extent.cc +++ b/src/xenia/gpu/texture_extent.cc @@ -23,41 +23,41 @@ static TextureExtent CalculateExtent(const FormatInfo* format_info, uint32_t pitch, uint32_t height, uint32_t depth, bool is_tiled, bool is_guest) { - TextureExtent usage; + TextureExtent extent; - usage.pitch = pitch; - usage.height = height; - usage.block_pitch_h = xe::round_up(usage.pitch, format_info->block_width) / - format_info->block_width; - usage.block_height = xe::round_up(usage.height, format_info->block_height) / - format_info->block_height; - usage.block_pitch_v = usage.block_height; - usage.depth = depth; + extent.pitch = pitch; + extent.height = height; + extent.block_pitch_h = xe::round_up(extent.pitch, format_info->block_width) / + format_info->block_width; + extent.block_height = xe::round_up(extent.height, format_info->block_height) / + format_info->block_height; + extent.block_pitch_v = extent.block_height; + extent.depth = depth; if (is_guest) { // Texture dimensions must be a multiple of tile // dimensions (32x32 blocks). - usage.block_pitch_h = xe::round_up(usage.block_pitch_h, 32); - usage.block_pitch_v = xe::round_up(usage.block_pitch_v, 32); + extent.block_pitch_h = xe::round_up(extent.block_pitch_h, 32); + extent.block_pitch_v = xe::round_up(extent.block_pitch_v, 32); - usage.pitch = usage.block_pitch_h * format_info->block_width; - usage.height = usage.block_pitch_v * format_info->block_height; + extent.pitch = extent.block_pitch_h * format_info->block_width; + extent.height = extent.block_pitch_v * format_info->block_height; uint32_t bytes_per_block = format_info->bytes_per_block(); - uint32_t byte_pitch = usage.block_pitch_h * bytes_per_block; + uint32_t byte_pitch = extent.block_pitch_h * bytes_per_block; if (!is_tiled) { // Each row must be a multiple of 256 bytes in linear textures. byte_pitch = xe::round_up(byte_pitch, 256); - usage.block_pitch_h = byte_pitch / bytes_per_block; - usage.pitch = usage.block_pitch_h * format_info->block_width; + extent.block_pitch_h = byte_pitch / bytes_per_block; + extent.pitch = extent.block_pitch_h * format_info->block_width; } // Is depth special? - usage.depth = usage.depth; + extent.depth = extent.depth; } - return usage; + return extent; } TextureExtent TextureExtent::Calculate(const FormatInfo* format_info, diff --git a/src/xenia/gpu/texture_info.cc b/src/xenia/gpu/texture_info.cc index e40415bac..fe971ce58 100644 --- a/src/xenia/gpu/texture_info.cc +++ b/src/xenia/gpu/texture_info.cc @@ -67,15 +67,16 @@ bool TextureInfo::Prepare(const xe_gpu_texture_fetch_t& fetch, info.is_tiled = fetch.tiled; info.has_packed_mips = fetch.packed_mips; - info.SetupMemoryInfo(fetch.base_address << 12, fetch.mip_address << 12); - if (info.format_info()->format == TextureFormat::kUnknown) { XELOGE("Attempting to fetch from unsupported texture format %d", info.format); + info.memory.base_address = fetch.base_address << 12; + info.memory.mip_address = fetch.mip_address << 12; return false; } info.extent = TextureExtent::Calculate(out_info, true); + info.SetupMemoryInfo(fetch.base_address << 12, fetch.mip_address << 12); return true; } @@ -104,14 +105,14 @@ bool TextureInfo::PrepareResolve(uint32_t physical_address, info.is_tiled = true; info.has_packed_mips = false; - info.SetupMemoryInfo(physical_address, 0); - if (info.format_info()->format == TextureFormat::kUnknown) { assert_true("Unsupported texture format"); + info.memory.base_address = physical_address; return false; } info.extent = TextureExtent::Calculate(out_info, true); + info.SetupMemoryInfo(physical_address, 0); return true; } @@ -159,19 +160,8 @@ uint32_t TextureInfo::GetMipLocation(uint32_t mip, uint32_t* offset_x, } uint32_t address_base, address_offset; - - // If the texture is <= 16 pixels w/h, the mips are packed with the base - // texture. Otherwise, they're stored beginning from mip_address. - if (std::min(width, height) < 16) { - address_base = memory.base_address; - address_offset = 0; - } else if (memory.base_address == memory.mip_address) { - address_base = memory.base_address; - address_offset = memory.base_size; - } else { - address_base = memory.mip_address; - address_offset = 0; - } + address_base = memory.mip_address; + address_offset = 0; auto bytes_per_block = format_info()->bytes_per_block(); @@ -299,32 +289,34 @@ uint64_t TextureInfo::hash() const { } void TextureInfo::SetupMemoryInfo(uint32_t base_address, uint32_t mip_address) { + uint32_t bytes_per_block = format_info()->bytes_per_block(); + memory.base_address = base_address; - memory.base_size = 0; + memory.base_size = GetMipExtent(0, true).visible_blocks() * bytes_per_block; memory.mip_address = 0; memory.mip_size = 0; - uint32_t bytes_per_block = format_info()->bytes_per_block(); - if (mip_levels <= 1) { // Sort circuit. Only one mip. - memory.base_size = GetMipExtent(0, true).all_blocks() * bytes_per_block; return; } + if (!mip_address || base_address == mip_address) { + memory.mip_address = base_address; + memory.mip_address += GetMipExtent(0, true).all_blocks() * bytes_per_block; + } else { + memory.mip_address = mip_address; + } + if (!has_packed_mips) { - assert_true(mip_address == 0 || mip_address == base_address); for (uint32_t mip = 0; mip < mip_levels - 1; mip++) { - memory.base_size += - GetMipExtent(mip, true).all_blocks() * bytes_per_block; + memory.mip_size += GetMipExtent(mip, true).all_blocks() * bytes_per_block; } - memory.base_size += + memory.mip_size += GetMipExtent(mip_levels - 1, true).visible_blocks() * bytes_per_block; return; } - uint32_t total_size = 0; - uint32_t width_pow2 = xe::next_pow2(width + 1); uint32_t height_pow2 = xe::next_pow2(height + 1); @@ -338,15 +330,7 @@ void TextureInfo::SetupMemoryInfo(uint32_t base_address, uint32_t mip_address) { // We've reached the point where the mips are packed into a single tile. break; } - total_size += GetMipExtent(mip, true).all_blocks() * bytes_per_block; - } - - if (mip_address != base_address) { - memory.mip_address = mip_address; - memory.mip_size = total_size; - } else { - memory.base_size = GetMipExtent(0, true).all_blocks() * bytes_per_block; - memory.base_size += total_size; + memory.mip_size += GetMipExtent(mip, true).all_blocks() * bytes_per_block; } } diff --git a/src/xenia/gpu/vulkan/texture_cache.cc b/src/xenia/gpu/vulkan/texture_cache.cc index 02ccaac5c..d589894e8 100644 --- a/src/xenia/gpu/vulkan/texture_cache.cc +++ b/src/xenia/gpu/vulkan/texture_cache.cc @@ -316,7 +316,8 @@ void TextureCache::WatchCallback(void* context_ptr, void* data_ptr, uint32_t address) { auto self = reinterpret_cast(context_ptr); auto touched_texture = reinterpret_cast(data_ptr); - if (!touched_texture || !touched_texture->access_watch_handle) { + if (!touched_texture || !touched_texture->access_watch_handle || + touched_texture->pending_invalidation) { return; } @@ -326,9 +327,6 @@ void TextureCache::WatchCallback(void* context_ptr, void* data_ptr, touched_texture->access_watch_handle = 0; touched_texture->pending_invalidation = true; - /*XELOGI("Invalidating texture @ 0x%.8X!", - touched_texture->texture_info.guest_address);*/ - // Add to pending list so Scavenge will clean it up. self->invalidated_textures_mutex_.lock(); self->invalidated_textures_->insert(touched_texture); @@ -385,13 +383,34 @@ TextureCache::Texture* TextureCache::DemandResolveTexture( get_dimension_name(texture_info.dimension))); // Setup an access watch. If this texture is touched, it is destroyed. - texture->access_watch_handle = memory_->AddPhysicalAccessWatch( - texture_info.memory.base_address, texture_info.memory.base_size, - cpu::MMIOHandler::kWatchWrite, &WatchCallback, this, texture); - if (texture_info.memory.mip_address) { + if (!texture_info.memory.mip_address) { texture->access_watch_handle = memory_->AddPhysicalAccessWatch( - texture_info.memory.mip_address, texture_info.memory.mip_size, + texture_info.memory.base_address, texture_info.memory.base_size, cpu::MMIOHandler::kWatchWrite, &WatchCallback, this, texture); + } else { + // TODO(gibbed): This makes the dangerous assumption that the base mip + + // following mips are near each other in memory. + uint32_t watch_address, watch_size; + if (texture_info.memory.base_address < texture_info.memory.mip_address) { + assert_true(texture_info.memory.base_address + + texture_info.memory.base_size <= + texture_info.memory.mip_address); + watch_address = texture_info.memory.base_address; + watch_size = + (texture_info.memory.mip_address + texture_info.memory.mip_size) - + texture_info.memory.base_address; + } else { + assert_true(texture_info.memory.mip_address + + texture_info.memory.mip_size <= + texture_info.memory.base_address); + watch_address = texture_info.memory.mip_address; + watch_size = + (texture_info.memory.base_address + texture_info.memory.base_size) - + texture_info.memory.mip_address; + } + texture->access_watch_handle = memory_->AddPhysicalAccessWatch( + watch_address, watch_size, cpu::MMIOHandler::kWatchWrite, + &WatchCallback, this, texture); } textures_[texture_hash] = texture; @@ -455,18 +474,6 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info, texture_info.memory.mip_size); } - // Okay. Put a writewatch on it to tell us if it's been modified from the - // guest. - // TODO(gibbed): Setup access watch for mipmap data. - texture->access_watch_handle = memory_->AddPhysicalAccessWatch( - texture_info.memory.base_address, texture_info.memory.base_size, - cpu::MMIOHandler::kWatchWrite, &WatchCallback, this, texture); - if (texture_info.memory.mip_address) { - texture->access_watch_handle = memory_->AddPhysicalAccessWatch( - texture_info.memory.mip_address, texture_info.memory.mip_size, - cpu::MMIOHandler::kWatchWrite, &WatchCallback, this, texture); - } - if (!UploadTexture(command_buffer, completion_fence, texture, texture_info)) { FreeTexture(texture); return nullptr; @@ -484,6 +491,39 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info, textures_[texture_hash] = texture; COUNT_profile_set("gpu/texture_cache/textures", textures_.size()); + + // Okay. Put a writewatch on it to tell us if it's been modified from the + // guest. + if (!texture_info.memory.mip_address) { + texture->access_watch_handle = memory_->AddPhysicalAccessWatch( + texture_info.memory.base_address, texture_info.memory.base_size, + cpu::MMIOHandler::kWatchWrite, &WatchCallback, this, texture); + } else { + // TODO(gibbed): This makes the dangerous assumption that the base mip + + // following mips are near each other in memory. + uint32_t watch_address, watch_size; + if (texture_info.memory.base_address < texture_info.memory.mip_address) { + assert_true(texture_info.memory.base_address + + texture_info.memory.base_size <= + texture_info.memory.mip_address); + watch_address = texture_info.memory.base_address; + watch_size = + (texture_info.memory.mip_address + texture_info.memory.mip_size) - + texture_info.memory.base_address; + } else { + assert_true(texture_info.memory.mip_address + + texture_info.memory.mip_size <= + texture_info.memory.base_address); + watch_address = texture_info.memory.mip_address; + watch_size = + (texture_info.memory.base_address + texture_info.memory.base_size) - + texture_info.memory.mip_address; + } + texture->access_watch_handle = memory_->AddPhysicalAccessWatch( + watch_address, watch_size, cpu::MMIOHandler::kWatchWrite, + &WatchCallback, this, texture); + } + return texture; } @@ -926,12 +966,12 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer, size_t unpack_length = ComputeTextureStorage(src); XELOGGPU( - "Uploading texture @ 0x%.8X/0x%.8X (%dx%dx%d, length: 0x%.8X, format: " - "%s, dim: %s, levels: %d, tiled: %s)", + "Uploading texture @ 0x%.8X/0x%.8X (%dx%dx%d, format: " + "%s, dim: %s, levels: %d, tiled: %s, unpack length: 0x%.8X)", src.memory.base_address, src.memory.mip_address, src.width + 1, - src.height + 1, src.depth + 1, unpack_length, src.format_info()->name, + src.height + 1, src.depth + 1, src.format_info()->name, get_dimension_name(src.dimension), src.mip_levels, - src.is_tiled ? "yes" : "no"); + src.is_tiled ? "yes" : "no", unpack_length); if (!unpack_length) { XELOGW("Failed to compute texture storage!"); @@ -1091,35 +1131,35 @@ TextureExtent TextureCache::GetMipExtent(const TextureInfo& src, uint32_t mip) { uint32_t width = src.width + 1; uint32_t height = src.height + 1; uint32_t depth = src.depth + 1; - TextureExtent usage; + TextureExtent extent; if (mip == 0) { - usage = TextureExtent::Calculate(format_info, width, height, depth, width, - false); + extent = TextureExtent::Calculate(format_info, width, height, depth, width, + false); } else { uint32_t mip_width = xe::next_pow2(width) >> mip; uint32_t mip_height = xe::next_pow2(height) >> mip; - usage = TextureExtent::Calculate(format_info, mip_width, mip_height, depth, - mip_width, false); + extent = TextureExtent::Calculate(format_info, mip_width, mip_height, depth, + mip_width, false); } - return usage; + return extent; } uint32_t TextureCache::ComputeMipStorage(const FormatInfo* format_info, uint32_t width, uint32_t height, uint32_t depth, uint32_t mip) { assert_not_null(format_info); - TextureExtent usage; + TextureExtent extent; if (mip == 0) { - usage = TextureExtent::Calculate(format_info, width, height, depth, false, - false); + extent = TextureExtent::Calculate(format_info, width, height, depth, false, + false); } else { uint32_t mip_width = xe::next_pow2(width) >> mip; uint32_t mip_height = xe::next_pow2(height) >> mip; - usage = TextureExtent::Calculate(format_info, mip_width, mip_height, depth, - false, false); + extent = TextureExtent::Calculate(format_info, mip_width, mip_height, depth, + false, false); } uint32_t bytes_per_block = format_info->bytes_per_block(); - return usage.all_blocks() * bytes_per_block; + return extent.all_blocks() * bytes_per_block; } uint32_t TextureCache::ComputeMipStorage(const TextureInfo& src, uint32_t mip) {