Skip to content

Commit

Permalink
Merge pull request #15487 from hrydgard/texture-dump-thread
Browse files Browse the repository at this point in the history
Save textures on background tasks when texture dumping is enabled.
  • Loading branch information
unknownbrackets authored Apr 18, 2022
2 parents 3a09c85 + dffc1a9 commit 5d22057
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 17 deletions.
9 changes: 7 additions & 2 deletions Common/MemoryUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,21 @@ void FreeAlignedMemory(void* ptr);

int GetMemoryProtectPageSize();

// A simple buffer that bypasses the libc memory allocator. As a result the buffer is always page-aligned.
template <typename T>
class SimpleBuf {
public:
SimpleBuf() : buf_(0), size_(0) {
}
SimpleBuf() : buf_(0), size_(0) {}

SimpleBuf(size_t size) : buf_(0) {
resize(size);
}

SimpleBuf(const SimpleBuf &o) : buf_(o.buf_), size_(o.size_) {}

// Move constructor
SimpleBuf(SimpleBuf &&o) noexcept : buf_(o.buf_), size_(o.size_) { o.buf_ = nullptr; o.size_ = 0; }

~SimpleBuf() {
if (buf_ != 0) {
FreeMemoryPages(buf_, size_ * sizeof(T));
Expand Down
69 changes: 55 additions & 14 deletions Core/TextureReplacer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "Common/StringUtils.h"
#include "Common/Thread/ParallelLoop.h"
#include "Common/Thread/Waitable.h"
#include "Common/Thread/ThreadManager.h"
#include "Common/TimeUtil.h"
#include "Core/Config.h"
#include "Core/Host.h"
Expand Down Expand Up @@ -502,6 +503,39 @@ static bool WriteTextureToPNG(png_imagep image, const Path &filename, int conver
}
}

class TextureSaveTask : public Task {
public:
// Could probably just use a vector.
SimpleBuf<u32> data;

int w = 0;
int h = 0;
int pitch = 0; // bytes

Path path;
u32 replacedInfoHash;

TextureSaveTask(SimpleBuf<u32> _data) : data(std::move(_data)) {}

TaskType Type() const override { return TaskType::CPU_COMPUTE; } // Also I/O blocking but dominated by compute
void Run() override {
png_image png;
memset(&png, 0, sizeof(png));
png.version = PNG_IMAGE_VERSION;
png.format = PNG_FORMAT_RGBA;
png.width = w;
png.height = h;
bool success = WriteTextureToPNG(&png, path, 0, data.data(), pitch, nullptr);
png_image_free(&png);
if (png.warning_or_error >= 2) {
ERROR_LOG(COMMON, "Saving screenshot to PNG produced errors.");
} else if (success) {
NOTICE_LOG(G3D, "Saving texture for replacement: %08x / %dx%d", replacedInfoHash, w, h);
}
}
};


void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &replacedInfo, const void *data, int pitch, int level, int w, int h) {
_assert_msg_(enabled_, "Replacement not enabled");
if (!g_Config.bSaveNewTextures) {
Expand Down Expand Up @@ -564,6 +598,10 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl
h = lookupH * replacedInfo.scaleFactor;
}

SimpleBuf<u32> saveBuf;

// TODO: Move the color conversion to the thread as well.
// Actually may be better to re-decode using expand32?
if (replacedInfo.fmt != ReplacedTextureFormat::F_8888) {
saveBuf.resize((pitch * h) / sizeof(u16));
switch (replacedInfo.fmt) {
Expand Down Expand Up @@ -598,24 +636,27 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl
// We doubled our pitch.
pitch *= 2;
}
} else {
// Copy data to a buffer so we can send it to the thread. Might as well compact-away the pitch
// while we're at it.
saveBuf.resize(w * h);
for (int y = 0; y < h; y++) {
memcpy((u8 *)saveBuf.data() + y * w * 4, (const u8 *)data + y * pitch, w * sizeof(u32));
}
pitch = w * 4;
}

png_image png;
memset(&png, 0, sizeof(png));
png.version = PNG_IMAGE_VERSION;
png.format = PNG_FORMAT_RGBA;
png.width = w;
png.height = h;
bool success = WriteTextureToPNG(&png, saveFilename, 0, data, pitch, nullptr);
png_image_free(&png);

if (png.warning_or_error >= 2) {
ERROR_LOG(COMMON, "Saving screenshot to PNG produced errors.");
} else if (success) {
NOTICE_LOG(G3D, "Saving texture for replacement: %08x / %dx%d", replacedInfo.hash, w, h);
}
TextureSaveTask *task = new TextureSaveTask(std::move(saveBuf));
// Should probably do a proper move constructor but this'll work.
task->w = w;
task->h = h;
task->pitch = pitch;
task->path = saveFilename;
task->replacedInfoHash = replacedInfo.hash;
g_threadManager.EnqueueTask(task); // We don't care about waiting for the task. It'll be fine.

// Remember that we've saved this for next time.
// Should be OK that the actual disk write may not be finished yet.
ReplacedTextureLevel saved;
saved.fmt = ReplacedTextureFormat::F_8888;
saved.file = filename;
Expand Down
1 change: 0 additions & 1 deletion Core/TextureReplacer.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ class TextureReplacer {
void PopulateReplacement(ReplacedTexture *result, u64 cachekey, u32 hash, int w, int h);
bool PopulateLevel(ReplacedTextureLevel &level);

SimpleBuf<u32> saveBuf;
bool enabled_ = false;
bool allowVideo_ = false;
bool ignoreAddress_ = false;
Expand Down
1 change: 1 addition & 0 deletions GPU/D3D11/TextureCacheD3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,7 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &
replacedInfo.scaleFactor = scaleFactor;
replacedInfo.fmt = FromD3D11Format(dstFmt);

// NOTE: Reading the decoded texture here may be very slow, if we just wrote it to write-combined memory.
replacer_.NotifyTextureDecoded(replacedInfo, pixelData, decPitch, level, w, h);
}
}
Expand Down
1 change: 1 addition & 0 deletions GPU/Vulkan/TextureCacheVulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
// When hardware texture scaling is enabled, this saves the original.
int w = dataScaled ? mipWidth : mipUnscaledWidth;
int h = dataScaled ? mipHeight : mipUnscaledHeight;
// NOTE: Reading the decoded texture here may be very slow, if we just wrote it to write-combined memory.
replacer_.NotifyTextureDecoded(replacedInfo, data, stride, i, w, h);
}
}
Expand Down

0 comments on commit 5d22057

Please sign in to comment.