|
|
|
@ -85,6 +85,11 @@ void TextureCache<P>::RunGarbageCollector() { |
|
|
|
} |
|
|
|
--num_iterations; |
|
|
|
auto& image = slot_images[image_id]; |
|
|
|
if (True(image.flags & ImageFlagBits::IsDecoding)) { |
|
|
|
// This image is still being decoded, deleting it will invalidate the slot |
|
|
|
// used by the async decoder thread. |
|
|
|
return false; |
|
|
|
} |
|
|
|
const bool must_download = |
|
|
|
image.IsSafeDownload() && False(image.flags & ImageFlagBits::BadOverlap); |
|
|
|
if (!high_priority_mode && |
|
|
|
@ -133,6 +138,8 @@ void TextureCache<P>::TickFrame() { |
|
|
|
sentenced_images.Tick(); |
|
|
|
sentenced_framebuffers.Tick(); |
|
|
|
sentenced_image_view.Tick(); |
|
|
|
TickAsyncDecode(); |
|
|
|
|
|
|
|
runtime.TickFrame(); |
|
|
|
critical_gc = 0; |
|
|
|
++frame_tick; |
|
|
|
@ -777,6 +784,10 @@ void TextureCache<P>::RefreshContents(Image& image, ImageId image_id) { |
|
|
|
LOG_WARNING(HW_GPU, "MSAA image uploads are not implemented"); |
|
|
|
return; |
|
|
|
} |
|
|
|
if (True(image.flags & ImageFlagBits::AsynchronousDecode)) { |
|
|
|
QueueAsyncDecode(image, image_id); |
|
|
|
return; |
|
|
|
} |
|
|
|
auto staging = runtime.UploadStagingBuffer(MapSizeBytes(image)); |
|
|
|
UploadImageContents(image, staging); |
|
|
|
runtime.InsertUploadMemoryBarrier(); |
|
|
|
@ -989,6 +1000,65 @@ u64 TextureCache<P>::GetScaledImageSizeBytes(const ImageBase& image) { |
|
|
|
return fitted_size; |
|
|
|
} |
|
|
|
|
|
|
|
template <class P> |
|
|
|
void TextureCache<P>::QueueAsyncDecode(Image& image, ImageId image_id) { |
|
|
|
UNIMPLEMENTED_IF(False(image.flags & ImageFlagBits::Converted)); |
|
|
|
LOG_INFO(HW_GPU, "Queuing async texture decode"); |
|
|
|
|
|
|
|
image.flags |= ImageFlagBits::IsDecoding; |
|
|
|
auto decode = std::make_unique<AsyncDecodeContext>(); |
|
|
|
auto* decode_ptr = decode.get(); |
|
|
|
decode->image_id = image_id; |
|
|
|
async_decodes.push_back(std::move(decode)); |
|
|
|
|
|
|
|
Common::ScratchBuffer<u8> local_unswizzle_data_buffer(image.unswizzled_size_bytes); |
|
|
|
const size_t guest_size_bytes = image.guest_size_bytes; |
|
|
|
swizzle_data_buffer.resize_destructive(guest_size_bytes); |
|
|
|
gpu_memory->ReadBlockUnsafe(image.gpu_addr, swizzle_data_buffer.data(), guest_size_bytes); |
|
|
|
auto copies = UnswizzleImage(*gpu_memory, image.gpu_addr, image.info, swizzle_data_buffer, |
|
|
|
local_unswizzle_data_buffer); |
|
|
|
const size_t out_size = MapSizeBytes(image); |
|
|
|
|
|
|
|
auto func = [out_size, copies, info = image.info, |
|
|
|
input = std::move(local_unswizzle_data_buffer), |
|
|
|
async_decode = decode_ptr]() mutable { |
|
|
|
async_decode->decoded_data.resize_destructive(out_size); |
|
|
|
std::span copies_span{copies.data(), copies.size()}; |
|
|
|
ConvertImage(input, info, async_decode->decoded_data, copies_span); |
|
|
|
|
|
|
|
// TODO: Do we need this lock? |
|
|
|
std::unique_lock lock{async_decode->mutex}; |
|
|
|
async_decode->copies = std::move(copies); |
|
|
|
async_decode->complete = true; |
|
|
|
}; |
|
|
|
texture_decode_worker.QueueWork(std::move(func)); |
|
|
|
} |
|
|
|
|
|
|
|
template <class P> |
|
|
|
void TextureCache<P>::TickAsyncDecode() { |
|
|
|
bool has_uploads{}; |
|
|
|
auto i = async_decodes.begin(); |
|
|
|
while (i != async_decodes.end()) { |
|
|
|
auto* async_decode = i->get(); |
|
|
|
std::unique_lock lock{async_decode->mutex}; |
|
|
|
if (!async_decode->complete) { |
|
|
|
++i; |
|
|
|
continue; |
|
|
|
} |
|
|
|
Image& image = slot_images[async_decode->image_id]; |
|
|
|
auto staging = runtime.UploadStagingBuffer(MapSizeBytes(image)); |
|
|
|
std::memcpy(staging.mapped_span.data(), async_decode->decoded_data.data(), |
|
|
|
async_decode->decoded_data.size()); |
|
|
|
image.UploadMemory(staging, async_decode->copies); |
|
|
|
image.flags &= ~ImageFlagBits::IsDecoding; |
|
|
|
has_uploads = true; |
|
|
|
i = async_decodes.erase(i); |
|
|
|
} |
|
|
|
if (has_uploads) { |
|
|
|
runtime.InsertUploadMemoryBarrier(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
template <class P> |
|
|
|
bool TextureCache<P>::ScaleUp(Image& image) { |
|
|
|
const bool has_copy = image.HasScaled(); |
|
|
|
|