[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:
gibbed 2018-05-30 19:38:36 -05:00
parent 7068d0a5a9
commit bbebfd49c8
5 changed files with 78 additions and 44 deletions

View File

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

View File

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

View File

@ -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?

View File

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

View File

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