[GPU] Fixes to problems caused by previous commit (bad handling of memory addressing, watches, etc).
This commit is contained in:
parent
9ac2bf0beb
commit
79f8fe9f37
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue