Vulkan: Properly invalidate resolve textures

Trace Writer memory caching
This commit is contained in:
DrChat 2017-02-17 18:59:08 -06:00
parent 070e7bf33d
commit c62c4fe741
4 changed files with 86 additions and 36 deletions

View File

@ -47,6 +47,7 @@ bool TraceWriter::Open(const std::wstring& path, uint32_t title_id) {
header.title_id = title_id; header.title_id = title_id;
fwrite(&header, sizeof(header), 1, file_); fwrite(&header, sizeof(header), 1, file_);
cached_memory_reads_.clear();
return true; return true;
} }
@ -58,6 +59,8 @@ void TraceWriter::Flush() {
void TraceWriter::Close() { void TraceWriter::Close() {
if (file_) { if (file_) {
cached_memory_reads_.clear();
fflush(file_); fflush(file_);
fclose(file_); fclose(file_);
file_ = nullptr; file_ = nullptr;
@ -132,6 +135,31 @@ void TraceWriter::WriteMemoryRead(uint32_t base_ptr, size_t length) {
WriteMemoryCommand(TraceCommandType::kMemoryRead, base_ptr, length); WriteMemoryCommand(TraceCommandType::kMemoryRead, base_ptr, length);
} }
void TraceWriter::WriteMemoryReadCached(uint32_t base_ptr, size_t length) {
if (!file_) {
return;
}
// HACK: length is guaranteed to be within 32-bits (guest memory)
uint64_t key = uint64_t(base_ptr) << 32 | uint64_t(length);
if (cached_memory_reads_.find(key) == cached_memory_reads_.end()) {
WriteMemoryCommand(TraceCommandType::kMemoryRead, base_ptr, length);
cached_memory_reads_.insert(key);
}
}
void TraceWriter::WriteMemoryReadCachedNop(uint32_t base_ptr, size_t length) {
if (!file_) {
return;
}
// HACK: length is guaranteed to be within 32-bits (guest memory)
uint64_t key = uint64_t(base_ptr) << 32 | uint64_t(length);
if (cached_memory_reads_.find(key) == cached_memory_reads_.end()) {
cached_memory_reads_.insert(key);
}
}
void TraceWriter::WriteMemoryWrite(uint32_t base_ptr, size_t length) { void TraceWriter::WriteMemoryWrite(uint32_t base_ptr, size_t length) {
if (!file_) { if (!file_) {
return; return;

View File

@ -10,6 +10,7 @@
#ifndef XENIA_GPU_TRACE_WRITER_H_ #ifndef XENIA_GPU_TRACE_WRITER_H_
#define XENIA_GPU_TRACE_WRITER_H_ #define XENIA_GPU_TRACE_WRITER_H_
#include <set>
#include <string> #include <string>
#include "xenia/base/filesystem.h" #include "xenia/base/filesystem.h"
@ -36,6 +37,8 @@ class TraceWriter {
void WritePacketStart(uint32_t base_ptr, uint32_t count); void WritePacketStart(uint32_t base_ptr, uint32_t count);
void WritePacketEnd(); void WritePacketEnd();
void WriteMemoryRead(uint32_t base_ptr, size_t length); void WriteMemoryRead(uint32_t base_ptr, size_t length);
void WriteMemoryReadCached(uint32_t base_ptr, size_t length);
void WriteMemoryReadCachedNop(uint32_t base_ptr, size_t length);
void WriteMemoryWrite(uint32_t base_ptr, size_t length); void WriteMemoryWrite(uint32_t base_ptr, size_t length);
void WriteEvent(EventCommand::Type event_type); void WriteEvent(EventCommand::Type event_type);
@ -43,6 +46,7 @@ class TraceWriter {
void WriteMemoryCommand(TraceCommandType type, uint32_t base_ptr, void WriteMemoryCommand(TraceCommandType type, uint32_t base_ptr,
size_t length); size_t length);
std::set<uint64_t> cached_memory_reads_;
uint8_t* membase_; uint8_t* membase_;
FILE* file_; FILE* file_;

View File

@ -348,9 +348,8 @@ TextureCache::Texture* TextureCache::AllocateTexture(
// Check the device limits for the format before we create it. // Check the device limits for the format before we create it.
VkFormatProperties props; VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(*device_, format, &props); vkGetPhysicalDeviceFormatProperties(*device_, format, &props);
uint32_t required_flags = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | uint32_t required_flags =
VK_FORMAT_FEATURE_BLIT_DST_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT;
VK_FORMAT_FEATURE_BLIT_SRC_BIT;
if ((props.optimalTilingFeatures & required_flags) != required_flags) { if ((props.optimalTilingFeatures & required_flags) != required_flags) {
// Texture needs conversion on upload to a native format. // Texture needs conversion on upload to a native format.
// assert_always(); // assert_always();
@ -484,10 +483,13 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
if (it->second->texture_info == texture_info) { if (it->second->texture_info == texture_info) {
if (it->second->pending_invalidation) { if (it->second->pending_invalidation) {
// This texture has been invalidated! // This texture has been invalidated!
Scavenge(); RemoveInvalidatedTextures();
break; break;
} }
trace_writer_->WriteMemoryReadCached(texture_info.guest_address,
texture_info.input_length);
return it->second; return it->second;
} }
} }
@ -501,6 +503,12 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
texture->texture_info.size_2d.logical_width && texture->texture_info.size_2d.logical_width &&
texture_info.size_2d.logical_height == texture_info.size_2d.logical_height ==
texture->texture_info.size_2d.logical_height) { texture->texture_info.size_2d.logical_height) {
if (texture->pending_invalidation) {
// Texture invalidated! Remove.
RemoveInvalidatedTextures();
break;
}
// Exact match. // Exact match.
// TODO: Lazy match (at an offset) // TODO: Lazy match (at an offset)
// Upgrade this texture to a full texture. // Upgrade this texture to a full texture.
@ -511,6 +519,10 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
memory_->CancelAccessWatch(texture->access_watch_handle); memory_->CancelAccessWatch(texture->access_watch_handle);
} }
// Tell the trace writer to cache this memory but don't read it
trace_writer_->WriteMemoryReadCachedNop(texture_info.guest_address,
texture_info.input_length);
texture->access_watch_handle = memory_->AddPhysicalAccessWatch( texture->access_watch_handle = memory_->AddPhysicalAccessWatch(
texture_info.guest_address, texture_info.input_length, texture_info.guest_address, texture_info.input_length,
cpu::MMIOHandler::kWatchWrite, cpu::MMIOHandler::kWatchWrite,
@ -548,6 +560,9 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
return nullptr; return nullptr;
} }
trace_writer_->WriteMemoryRead(texture_info.guest_address,
texture_info.input_length);
bool uploaded = false; bool uploaded = false;
switch (texture_info.dimension) { switch (texture_info.dimension) {
case Dimension::k1D: { case Dimension::k1D: {
@ -1479,9 +1494,6 @@ bool TextureCache::SetupTextureBinding(VkCommandBuffer command_buffer,
uint16_t swizzle = static_cast<uint16_t>(fetch.swizzle); uint16_t swizzle = static_cast<uint16_t>(fetch.swizzle);
auto view = DemandView(texture, swizzle); auto view = DemandView(texture, swizzle);
trace_writer_->WriteMemoryRead(texture_info.guest_address,
texture_info.input_length);
auto image_info = auto image_info =
&update_set_info->image_infos[update_set_info->image_write_count]; &update_set_info->image_infos[update_set_info->image_write_count];
auto image_write = auto image_write =
@ -1507,35 +1519,7 @@ bool TextureCache::SetupTextureBinding(VkCommandBuffer command_buffer,
return true; return true;
} }
void TextureCache::ClearCache() { void TextureCache::RemoveInvalidatedTextures() {
// TODO(DrChat): Nuke everything.
}
void TextureCache::Scavenge() {
// Close any open descriptor pool batches
if (descriptor_pool_->has_open_batch()) {
descriptor_pool_->EndBatch();
}
// Free unused descriptor sets
// TODO(DrChat): These sets could persist across frames, we just need a smart
// way to detect if they're unused and free them.
texture_bindings_.clear();
descriptor_pool_->Scavenge();
staging_buffer_.Scavenge();
// Kill all pending delete textures.
if (!pending_delete_textures_.empty()) {
for (auto it = pending_delete_textures_.begin();
it != pending_delete_textures_.end();) {
if (!FreeTexture(*it)) {
break;
}
it = pending_delete_textures_.erase(it);
}
}
// Clean up any invalidated textures. // Clean up any invalidated textures.
invalidated_textures_mutex_.lock(); invalidated_textures_mutex_.lock();
std::vector<Texture*>& invalidated_textures = *invalidated_textures_; std::vector<Texture*>& invalidated_textures = *invalidated_textures_;
@ -1574,6 +1558,37 @@ void TextureCache::Scavenge() {
invalidated_resolve_textures_mutex_.unlock(); invalidated_resolve_textures_mutex_.unlock();
} }
void TextureCache::ClearCache() {
// TODO(DrChat): Nuke everything.
}
void TextureCache::Scavenge() {
// Close any open descriptor pool batches
if (descriptor_pool_->has_open_batch()) {
descriptor_pool_->EndBatch();
}
// Free unused descriptor sets
// TODO(DrChat): These sets could persist across frames, we just need a smart
// way to detect if they're unused and free them.
texture_bindings_.clear();
descriptor_pool_->Scavenge();
staging_buffer_.Scavenge();
// Kill all pending delete textures.
RemoveInvalidatedTextures();
if (!pending_delete_textures_.empty()) {
for (auto it = pending_delete_textures_.begin();
it != pending_delete_textures_.end();) {
if (!FreeTexture(*it)) {
break;
}
it = pending_delete_textures_.erase(it);
}
}
}
} // namespace vulkan } // namespace vulkan
} // namespace gpu } // namespace gpu
} // namespace xe } // namespace xe

View File

@ -180,6 +180,9 @@ class TextureCache {
UpdateSetInfo* update_set_info, UpdateSetInfo* update_set_info,
const Shader::TextureBinding& binding); const Shader::TextureBinding& binding);
// Removes invalidated textures from the cache, queues them for delete.
void RemoveInvalidatedTextures();
Memory* memory_ = nullptr; Memory* memory_ = nullptr;
RegisterFile* register_file_ = nullptr; RegisterFile* register_file_ = nullptr;