Skip to content

Commit

Permalink
ui: load savestate thumbnails asynchronously. limit thumbnail size
Browse files Browse the repository at this point in the history
GetLastFrame can take max width or height.
Limit width of savestate screenshot to 640.
Load savestate thumbnail in async task.
  • Loading branch information
flyinghead committed May 14, 2024
1 parent b5f49d6 commit 35acb7e
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 48 deletions.
2 changes: 2 additions & 0 deletions core/hw/pvr/Renderer_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ struct Renderer
virtual bool RenderLastFrame() { return false; }
// Get the last rendered frame pixel data in RGB format
// The returned image is rotated and scaled (upward orientation and square pixels)
// If both width and height are zero, the internal render resolution will be used.
// Otherwise either width or height will be used as the maximum width or height respectively.
virtual bool GetLastFrame(std::vector<u8>& data, int& width, int& height) { return false; }

virtual bool Present() { return true; }
Expand Down
25 changes: 17 additions & 8 deletions core/rend/dx11/dx11_renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1350,16 +1350,25 @@ bool DX11Renderer::GetLastFrame(std::vector<u8>& data, int& width, int& height)
if (!frameRenderedOnce)
return false;

width = this->width;
height = this->height;
if (config::Rotate90)
std::swap(width, height);
// We need square pixels for PNG
int w = aspectRatio * height;
if (width > w)
if (width != 0) {
height = width / aspectRatio;
}
else if (height != 0) {
width = aspectRatio * height;
}
else
width = w;
{
width = this->width;
height = this->height;
if (config::Rotate90)
std::swap(width, height);
// We need square pixels for PNG
int w = aspectRatio * height;
if (width > w)
height = width / aspectRatio;
else
width = w;
}

ComPtr<ID3D11Texture2D> dstTex;
ComPtr<ID3D11RenderTargetView> dstRenderTarget;
Expand Down
25 changes: 17 additions & 8 deletions core/rend/dx9/d3d_renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1427,16 +1427,25 @@ bool D3DRenderer::GetLastFrame(std::vector<u8>& data, int& width, int& height)
if (!frameRenderedOnce || !theDXContext.isReady())
return false;

width = this->width;
height = this->height;
if (config::Rotate90)
std::swap(width, height);
// We need square pixels for PNG
int w = aspectRatio * height;
if (width > w)
if (width != 0) {
height = width / aspectRatio;
}
else if (height != 0) {
width = aspectRatio * height;
}
else
width = w;
{
width = this->width;
height = this->height;
if (config::Rotate90)
std::swap(width, height);
// We need square pixels for PNG
int w = aspectRatio * height;
if (width > w)
height = width / aspectRatio;
else
width = w;
}

backbuffer.reset();
device->GetRenderTarget(0, &backbuffer.get());
Expand Down
25 changes: 17 additions & 8 deletions core/rend/gles/gldraw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -822,16 +822,25 @@ bool OpenGLRenderer::GetLastFrame(std::vector<u8>& data, int& width, int& height
GlFramebuffer *framebuffer = gl.ofbo2.ready ? gl.ofbo2.framebuffer.get() : gl.ofbo.framebuffer.get();
if (framebuffer == nullptr)
return false;
width = framebuffer->getWidth();
height = framebuffer->getHeight();
if (config::Rotate90)
std::swap(width, height);
// We need square pixels for PNG
int w = gl.ofbo.aspectRatio * height;
if (width > w)
if (width != 0) {
height = width / gl.ofbo.aspectRatio;
}
else if (height != 0) {
width = gl.ofbo.aspectRatio * height;
}
else
width = w;
{
width = framebuffer->getWidth();
height = framebuffer->getHeight();
if (config::Rotate90)
std::swap(width, height);
// We need square pixels for PNG
int w = gl.ofbo.aspectRatio * height;
if (width > w)
height = width / gl.ofbo.aspectRatio;
else
width = w;
}

GlFramebuffer dstFramebuffer(width, height, false, false);

Expand Down
25 changes: 17 additions & 8 deletions core/rend/vulkan/vulkan_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1238,16 +1238,25 @@ bool VulkanContext::GetLastFrame(std::vector<u8>& data, int& width, int& height)
if (!lastFrameView)
return false;

width = lastFrameExtent.width;
height = lastFrameExtent.height;
if (config::Rotate90)
std::swap(width, height);
// We need square pixels for PNG
int w = lastFrameAR * height;
if (width > w)
if (width != 0) {
height = width / lastFrameAR;
}
else if (height != 0) {
width = lastFrameAR * height;
}
else
width = w;
{
width = lastFrameExtent.width;
height = lastFrameExtent.height;
if (config::Rotate90)
std::swap(width, height);
// We need square pixels for PNG
int w = lastFrameAR * height;
if (width > w)
height = width / lastFrameAR;
else
width = w;
}
// color attachment
FramebufferAttachment attachment(physicalDevice, *device);
attachment.Init(width, height, vk::Format::eR8G8B8A8Unorm, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc, "screenshot");
Expand Down
7 changes: 4 additions & 3 deletions core/ui/gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -591,11 +591,11 @@ static void appendVectorData(void *context, void *data, int size)
v.insert(v.end(), bytes, bytes + size);
}

static void getScreenshot(std::vector<u8>& data)
static void getScreenshot(std::vector<u8>& data, int width = 0)
{
data.clear();
std::vector<u8> rawData;
int width, height;
int height = 0;
if (renderer == nullptr || !renderer->GetLastFrame(rawData, width, height))
return;
stbi_flip_vertically_on_write(0);
Expand All @@ -621,8 +621,9 @@ static std::string timeToString(time_t time)

static void savestate()
{
// TODO save state async: png compression, savestate file compression/write
std::vector<u8> pngData;
getScreenshot(pngData);
getScreenshot(pngData, 640);
dc_savestate(config::SavestateSlot, pngData.empty() ? nullptr : &pngData[0], pngData.size());
ImguiStateTexture savestatePic;
savestatePic.invalidate();
Expand Down
39 changes: 26 additions & 13 deletions core/ui/gui_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,8 @@ ImTextureID ImguiFileTexture::getId()
return id;
}

std::future<ImguiStateTexture::LoadedPic> ImguiStateTexture::asyncLoad;

bool ImguiStateTexture::exists()
{
std::string path = hostfs::getSavestatePath(config::SavestateSlot, false);
Expand All @@ -810,28 +812,39 @@ ImTextureID ImguiStateTexture::getId()
{
std::string path = hostfs::getSavestatePath(config::SavestateSlot, false);
ImTextureID texid = imguiDriver->getTexture(path);
if (texid == ImTextureID())
if (texid != ImTextureID())
return texid;
if (asyncLoad.valid())
{
// load savestate info
std::vector<u8> pngData;
dc_getStateScreenshot(config::SavestateSlot, pngData);
if (pngData.empty())
if (asyncLoad.wait_for(std::chrono::seconds::zero()) == std::future_status::timeout)
return {};

int width, height, channels;
stbi_set_flip_vertically_on_load(0);
u8 *imgData = stbi_load_from_memory(&pngData[0], pngData.size(), &width, &height, &channels, STBI_rgb_alpha);
if (imgData != nullptr)
LoadedPic loadedPic = asyncLoad.get();
if (loadedPic.data != nullptr)
{
try {
texid = imguiDriver->updateTextureAndAspectRatio(path, imgData, width, height, nearestSampling);
texid = imguiDriver->updateTextureAndAspectRatio(path, loadedPic.data, loadedPic.width, loadedPic.height, nearestSampling);
} catch (...) {
// vulkan can throw during resizing
}
free(imgData);
free(loadedPic.data);
}
return texid;
}
return texid;
asyncLoad = std::async(std::launch::async, []() {
LoadedPic loadedPic{};
// load savestate info
std::vector<u8> pngData;
dc_getStateScreenshot(config::SavestateSlot, pngData);
if (pngData.empty())
return loadedPic;

int channels;
stbi_set_flip_vertically_on_load(0);
loadedPic.data = stbi_load_from_memory(&pngData[0], pngData.size(), &loadedPic.width, &loadedPic.height, &channels, STBI_rgb_alpha);

return loadedPic;
});
return {};
}

void ImguiStateTexture::invalidate()
Expand Down
9 changes: 9 additions & 0 deletions core/ui/gui_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,15 @@ class ImguiStateTexture : public ImguiTexture

bool exists();
void invalidate();

private:
struct LoadedPic
{
u8 *data;
int width;
int height;
};
static std::future<LoadedPic> asyncLoad;
};

class ImguiVmuTexture : public ImguiTexture
Expand Down

0 comments on commit 35acb7e

Please sign in to comment.