diff --git a/src/xenia/gpu/texture_info.cc b/src/xenia/gpu/texture_info.cc index e6a1bd702..cce59b681 100644 --- a/src/xenia/gpu/texture_info.cc +++ b/src/xenia/gpu/texture_info.cc @@ -83,7 +83,8 @@ bool TextureInfo::Prepare(const xe_gpu_texture_fetch_t& fetch, bool TextureInfo::PrepareResolve(uint32_t physical_address, TextureFormat format, Endian endian, uint32_t pitch, uint32_t width, - uint32_t height, TextureInfo* out_info) { + uint32_t height, uint32_t depth, + TextureInfo* out_info) { assert_true(width > 0); assert_true(height > 0); @@ -95,7 +96,7 @@ bool TextureInfo::PrepareResolve(uint32_t physical_address, info.width = width - 1; info.height = height - 1; info.mip_levels = 1; - info.depth = 0; + info.depth = depth - 1; info.pitch = pitch; info.endianness = endian; @@ -156,11 +157,20 @@ uint32_t TextureInfo::GetMipLocation(uint32_t mip, uint32_t* offset_x, return guest_address; } + 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. - uint32_t address_base = - std::min(width, height) < 16 ? guest_address : mip_address; - uint32_t address_offset = 0; + if (std::min(width, height) < 16) { + address_base = guest_address; + address_offset = 0; + } else if (guest_address == mip_address) { + address_base = guest_address; + address_offset = GetMipByteSize(0, is_guest); + } else { + address_base = mip_address; + address_offset = 0; + } if (!has_packed_mips) { for (uint32_t i = 1; i < mip; i++) { @@ -183,7 +193,6 @@ uint32_t TextureInfo::GetMipLocation(uint32_t mip, uint32_t* offset_x, // We've reached the point where the mips are packed into a single tile. break; } - address_offset += GetMipByteSize(i, is_guest); } @@ -196,7 +205,13 @@ uint32_t TextureInfo::GetMipLocation(uint32_t mip, uint32_t* offset_x, uint32_t TextureInfo::GetMipByteSize(uint32_t mip, bool is_guest) const { uint32_t bytes_per_block = format_info()->bytes_per_block(); auto mip_usage = GetMipMemoryUsage(mip, is_guest); - return mip_usage.blocks() * bytes_per_block; + return mip_usage.all_blocks() * bytes_per_block; +} + +uint32_t TextureInfo::GetMipVisibleByteSize(uint32_t mip, bool is_guest) const { + uint32_t bytes_per_block = format_info()->bytes_per_block(); + auto mip_usage = GetMipMemoryUsage(mip, is_guest); + return mip_usage.visible_blocks() * bytes_per_block; } uint32_t TextureInfo::GetByteSize(bool is_guest) const { diff --git a/src/xenia/gpu/texture_info.h b/src/xenia/gpu/texture_info.h index 62874fa7e..c5761db53 100644 --- a/src/xenia/gpu/texture_info.h +++ b/src/xenia/gpu/texture_info.h @@ -291,13 +291,17 @@ struct FormatInfo { struct TextureInfo; struct TextureMemoryUsage { - uint32_t pitch; // texel pitch - uint32_t height; // texel height - uint32_t block_pitch; // # of horizontal pitch blocks - uint32_t block_height; // # of vertical blocks + uint32_t pitch; // texel pitch + uint32_t height; // texel height + uint32_t block_height; // # of vertical blocks + uint32_t block_pitch_h; // # of horizontal pitch blocks + uint32_t block_pitch_v; // # of vertical pitch blocks uint32_t depth; - uint32_t blocks() const { return block_pitch * block_height * depth; } + uint32_t all_blocks() const { return block_pitch_h * block_pitch_v * depth; } + uint32_t visible_blocks() const { + return block_pitch_h * block_height * depth; + } static TextureMemoryUsage Calculate(const FormatInfo* format_info, uint32_t pitch, uint32_t height, @@ -339,7 +343,7 @@ struct TextureInfo { static bool PrepareResolve(uint32_t physical_address, TextureFormat texture_format, Endian endian, uint32_t pitch, uint32_t width, uint32_t height, - TextureInfo* out_info); + uint32_t depth, TextureInfo* out_info); uint32_t GetMaxMipLevels() const; @@ -352,6 +356,7 @@ struct TextureInfo { bool is_guest) const; uint32_t GetMipByteSize(uint32_t mip, bool is_guest) const; + uint32_t GetMipVisibleByteSize(uint32_t mip, bool is_guest) const; uint32_t GetByteSize(bool is_guest) const; diff --git a/src/xenia/gpu/texture_memory_usage.cc b/src/xenia/gpu/texture_memory_usage.cc index d464c4f76..0c80e45d8 100644 --- a/src/xenia/gpu/texture_memory_usage.cc +++ b/src/xenia/gpu/texture_memory_usage.cc @@ -27,29 +27,30 @@ static TextureMemoryUsage CalculateMemoryUsage(const FormatInfo* format_info, usage.pitch = pitch; usage.height = height; - usage.block_pitch = xe::round_up(usage.pitch, format_info->block_width) / - format_info->block_width; + 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; if (is_guest) { // Texture dimensions must be a multiple of tile // dimensions (32x32 blocks). - usage.block_pitch = xe::round_up(usage.block_pitch, 32); - usage.block_height = xe::round_up(usage.block_height, 32); + usage.block_pitch_h = xe::round_up(usage.block_pitch_h, 32); + usage.block_pitch_v = xe::round_up(usage.block_pitch_v, 32); - usage.pitch = usage.block_pitch * format_info->block_width; - usage.height = usage.block_height * format_info->block_height; + usage.pitch = usage.block_pitch_h * format_info->block_width; + usage.height = usage.block_pitch_v * format_info->block_height; uint32_t bytes_per_block = format_info->bytes_per_block(); - uint32_t byte_pitch = usage.block_pitch * bytes_per_block; + uint32_t byte_pitch = usage.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 = byte_pitch / bytes_per_block; - usage.pitch = usage.block_pitch * format_info->block_width; + usage.block_pitch_h = byte_pitch / bytes_per_block; + usage.pitch = usage.block_pitch_h * format_info->block_width; } // Is depth special? diff --git a/src/xenia/gpu/vulkan/texture_cache.cc b/src/xenia/gpu/vulkan/texture_cache.cc index d5a49f6e8..42262f3bd 100644 --- a/src/xenia/gpu/vulkan/texture_cache.cc +++ b/src/xenia/gpu/vulkan/texture_cache.cc @@ -425,6 +425,9 @@ 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); @@ -470,15 +473,17 @@ TextureCache::Texture* TextureCache::DemandResolveTexture( device_->DbgSetObjectName( reinterpret_cast(texture->image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, - xe::format_string( - "RT: 0x%.8X - 0x%.8X (%s, %s)", texture_info.guest_address, - texture_info.guest_address + texture_info.GetByteSize(true), - texture_info.format_info()->name, - get_dimension_name(texture_info.dimension))); + xe::format_string("RT: 0x%.8X - 0x%.8X (%s, %s)", + texture_info.guest_address, + texture_info.guest_address + + texture_info.GetMipVisibleByteSize(0, true), + texture_info.format_info()->name, + get_dimension_name(texture_info.dimension))); // Setup an access watch. If this texture is touched, it is destroyed. + // TODO(gibbed): Setup access watch for mipmap data. texture->access_watch_handle = memory_->AddPhysicalAccessWatch( - texture_info.guest_address, texture_info.GetByteSize(true), + texture_info.guest_address, texture_info.GetMipVisibleByteSize(0, true), cpu::MMIOHandler::kWatchWrite, &WatchCallback, this, texture); textures_[texture_hash] = texture; @@ -536,8 +541,9 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info, // 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.guest_address, texture_info.GetByteSize(true), + texture_info.guest_address, texture_info.GetMipVisibleByteSize(0, true), cpu::MMIOHandler::kWatchWrite, &WatchCallback, this, texture); if (!UploadTexture(command_buffer, completion_fence, texture, texture_info)) { @@ -856,8 +862,8 @@ TextureCache::Texture* TextureCache::LookupAddress(uint32_t guest_address, for (auto it = textures_.begin(); it != textures_.end(); ++it) { const auto& texture_info = it->second->texture_info; if (guest_address >= texture_info.guest_address && - guest_address < - texture_info.guest_address + texture_info.GetByteSize(true) && + guest_address < texture_info.guest_address + + texture_info.GetMipVisibleByteSize(0, true) && texture_info.pitch >= width && texture_info.height >= height && out_offset) { auto offset_bytes = guest_address - texture_info.guest_address; @@ -939,9 +945,9 @@ bool TextureCache::ConvertTexture(uint8_t* dest, VkBufferImageCopy* copy_region, auto dst_usage = GetMipMemoryUsage(src, mip); uint32_t src_pitch = - src_usage.block_pitch * src.format_info()->bytes_per_block(); + src_usage.block_pitch_h * src.format_info()->bytes_per_block(); uint32_t dst_pitch = - dst_usage.block_pitch * GetFormatInfo(src.format)->bytes_per_block(); + dst_usage.block_pitch_h * GetFormatInfo(src.format)->bytes_per_block(); auto copy_block = GetFormatCopyBlock(src.format); @@ -954,8 +960,8 @@ bool TextureCache::ConvertTexture(uint8_t* dest, VkBufferImageCopy* copy_region, copy_block(src.endianness, dest + y * dst_pitch, src_mem + y * src_pitch, dst_pitch); } - src_mem += src_pitch * src_usage.block_height; - dest += dst_pitch * dst_usage.block_height; + src_mem += src_pitch * src_usage.block_pitch_v; + dest += dst_pitch * dst_usage.block_pitch_v; } } else { // Untile image. @@ -965,18 +971,18 @@ bool TextureCache::ConvertTexture(uint8_t* dest, VkBufferImageCopy* copy_region, std::memset(&untile_info, 0, sizeof(untile_info)); untile_info.offset_x = offset_x; untile_info.offset_y = offset_y; - untile_info.width = dst_usage.block_pitch; + untile_info.width = dst_usage.block_pitch_h; untile_info.height = dst_usage.block_height; - untile_info.input_pitch = src_usage.block_pitch; - untile_info.output_pitch = dst_usage.block_pitch; + untile_info.input_pitch = src_usage.block_pitch_h; + untile_info.output_pitch = dst_usage.block_pitch_h; untile_info.input_format_info = src.format_info(); untile_info.output_format_info = GetFormatInfo(src.format); untile_info.copy_callback = [=](auto o, auto i, auto l) { copy_block(src.endianness, o, i, l); }; texture_conversion::Untile(dest, src_mem, &untile_info); - src_mem += src_pitch * src_usage.block_height; - dest += dst_pitch * dst_usage.block_height; + src_mem += src_pitch * src_usage.block_pitch_v; + dest += dst_pitch * dst_usage.block_pitch_v; } } @@ -1195,7 +1201,7 @@ uint32_t TextureCache::ComputeMipStorage(const FormatInfo* format_info, depth, false, false); } uint32_t bytes_per_block = format_info->bytes_per_block(); - return usage.blocks() * bytes_per_block; + return usage.all_blocks() * bytes_per_block; } uint32_t TextureCache::ComputeMipStorage(const TextureInfo& src, uint32_t mip) { diff --git a/src/xenia/gpu/vulkan/vulkan_command_processor.cc b/src/xenia/gpu/vulkan/vulkan_command_processor.cc index 3f4cdf2fa..2eef972bd 100644 --- a/src/xenia/gpu/vulkan/vulkan_command_processor.cc +++ b/src/xenia/gpu/vulkan/vulkan_command_processor.cc @@ -822,6 +822,10 @@ bool VulkanCommandProcessor::PopulateVertexBuffers( assert_true(vertex_bindings.size() <= 32); auto descriptor_set = buffer_cache_->PrepareVertexSet( setup_buffer, current_batch_fence_, vertex_bindings); + if (!descriptor_set) { + XELOGW("Failed to prepare vertex set!"); + return false; + } vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_cache_->pipeline_layout(), 2, 1, @@ -843,6 +847,7 @@ bool VulkanCommandProcessor::PopulateSamplers(VkCommandBuffer command_buffer, pixel_shader ? pixel_shader->texture_bindings() : dummy_bindings); if (!descriptor_set) { // Unable to bind set. + XELOGW("Failed to prepare texture set!"); return false; } @@ -1023,13 +1028,14 @@ bool VulkanCommandProcessor::IssueCopy() { // Demand a resolve texture from the texture cache. TextureInfo texture_info; - TextureInfo::PrepareResolve(copy_dest_base, copy_dest_format, resolve_endian, - copy_dest_pitch, dest_logical_width, - std::max(1u, dest_logical_height), &texture_info); + TextureInfo::PrepareResolve( + copy_dest_base, copy_dest_format, resolve_endian, copy_dest_pitch, + dest_logical_width, std::max(1u, dest_logical_height), 1, &texture_info); auto texture = texture_cache_->DemandResolveTexture(texture_info); if (!texture) { // Out of memory. + XELOGD("Failed to demand resolve texture!"); return false; } @@ -1137,6 +1143,7 @@ bool VulkanCommandProcessor::IssueCopy() { auto view = render_cache_->FindTileView( edram_base, surface_pitch, surface_msaa, is_color_source, src_format); if (!view) { + XELOGGPU("Failed to find tile view!"); break; }