[GPU] Fixes to problems caused by previous commit (bad handling of memory addressing, watches, etc).

This commit is contained in:
gibbed 2018-05-31 21:50:22 -05:00
parent 9ac2bf0beb
commit 79f8fe9f37
3 changed files with 115 additions and 91 deletions

View File

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

View File

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

View File

@ -316,7 +316,8 @@ void TextureCache::WatchCallback(void* context_ptr, void* data_ptr,
uint32_t address) {
auto self = reinterpret_cast<TextureCache*>(context_ptr);
auto touched_texture = reinterpret_cast<Texture*>(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) {