[Vulkan] Add logging to certain error conditions.
[Vulkan] Track both texture block height and texture block vertical pitch. [Vulkan] Only convert the necessary visible height on texture uploads. [Vulkan] Fix write watch on texture data so it properly only covers mip 0 data.
This commit is contained in:
parent
7068d0a5a9
commit
bbebfd49c8
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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<uint64_t>(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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue