1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

Screenshot function

This commit is contained in:
RipleyTom 2019-08-10 18:49:57 +02:00 committed by Megamouse
parent b3f4cd3a95
commit 87bf0386c4
7 changed files with 140 additions and 2 deletions

View File

@ -25,11 +25,20 @@ namespace date_time
return str;
}
template<char separator = 0>
static inline std::string current_time_narrow()
{
char str[80];
tm now = get_time(0);
strftime(str, sizeof(str), "%Y%m%d%H%M%S", &now);
std::string parse_buf;
if constexpr(separator != 0)
parse_buf = std::string("%Y") + separator + "%m" + separator + "%d" + separator + "%H" + separator + "%M" + separator + "%S";
else
parse_buf = "%Y%m%d%H%M%S";
strftime(str, sizeof(str), parse_buf.c_str(), &now);
return str;
}
}

View File

@ -1681,6 +1681,26 @@ void GLGSRender::flip(int buffer, bool emu_flip)
image = m_flip_tex_color->id();
}
if (m_frame->screenshot_toggle == true)
{
m_frame->screenshot_toggle = false;
std::vector<u8> sshot_frame(buffer_height * buffer_width * 4);
gl::pixel_pack_settings pack_settings{};
pack_settings.apply();
if (gl::get_driver_caps().ARB_dsa_supported)
glGetTextureImage(image, 0, GL_BGRA, GL_UNSIGNED_BYTE, buffer_height * buffer_width * 4, sshot_frame.data());
else
glGetTextureImageEXT(image, GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, sshot_frame.data());
if (GLenum err; (err = glGetError()) != GL_NO_ERROR)
LOG_ERROR(GENERAL, "[Screenshot] Failed to capture image: 0x%x", err);
else
m_frame->take_screenshot(std::move(sshot_frame), buffer_width, buffer_height);
}
areai screen_area = coordi({}, { (int)buffer_width, (int)buffer_height });
if (g_cfg.video.full_rgb_range_output && (!avconfig || avconfig->gamma == 1.f))

View File

@ -85,6 +85,9 @@ using draw_context_t = void*;
virtual int client_height() = 0;
virtual display_handle_t handle() const = 0;
std::atomic<bool> screenshot_toggle = false;
virtual void take_screenshot(const std::vector<u8> sshot_data, const u32 sshot_width, const u32 sshot_height) = 0;
};
class GSRender : public rsx::thread

View File

@ -3373,6 +3373,43 @@ void VKGSRender::flip(int buffer, bool emu_flip)
vk::change_image_layout(*m_current_command_buffer, target_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, present_layout, range);
}
if (m_frame->screenshot_toggle == true)
{
m_frame->screenshot_toggle = false;
const size_t sshot_size = buffer_height * buffer_width * 4;
vk::buffer sshot_vkbuf(*m_device, align(sshot_size, 0x100000), m_device->get_memory_mapping().host_visible_coherent, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
VK_BUFFER_USAGE_TRANSFER_DST_BIT, 0);
VkBufferImageCopy copy_info;
copy_info.bufferOffset = 0;
copy_info.bufferRowLength = 0;
copy_info.bufferImageHeight = 0;
copy_info.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy_info.imageSubresource.baseArrayLayer = 0;
copy_info.imageSubresource.layerCount = 1;
copy_info.imageSubresource.mipLevel = 0;
copy_info.imageOffset.x = 0;
copy_info.imageOffset.y = 0;
copy_info.imageOffset.z = 0;
copy_info.imageExtent.width = buffer_width;
copy_info.imageExtent.height = buffer_height;
copy_info.imageExtent.depth = 1;
image_to_flip->push_layout(*m_current_command_buffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
vk::copy_image_to_buffer(*m_current_command_buffer, image_to_flip, &sshot_vkbuf, copy_info);
image_to_flip->pop_layout(*m_current_command_buffer);
flush_command_queue(true);
auto src = sshot_vkbuf.map(0, sshot_size);
std::vector<u8> sshot_frame(sshot_size);
memcpy(sshot_frame.data(), src, sshot_size);
sshot_vkbuf.unmap();
m_frame->take_screenshot(std::move(sshot_frame), buffer_width, buffer_height);
}
const bool has_overlay = (m_overlay_manager && m_overlay_manager->has_visible());
if (g_cfg.video.overlay || has_overlay)
{

View File

@ -78,4 +78,5 @@ target_link_libraries(rpcs3_ui
3rdparty::zlib 3rdparty::pugixml
3rdparty::discord-rpc
3rdparty::hidapi
3rdparty::libusb)
3rdparty::libusb
3rdparty::libpng)

View File

@ -2,6 +2,7 @@
#include "Utilities/Config.h"
#include "Utilities/Timer.h"
#include "Utilities/date_time.h"
#include "Emu/System.h"
#include <QKeyEvent>
@ -13,6 +14,8 @@
#include "rpcs3_version.h"
#include "png.h"
#ifdef _WIN32
#include <windows.h>
#elif defined(__APPLE__)
@ -151,6 +154,7 @@ void gs_frame::keyPressEvent(QKeyEvent *keyEvent)
else if (Emu.IsPaused()) { Emu.Resume(); return; }
}
break;
case Qt::Key_F12: screenshot_toggle = true; break;
}
}
@ -299,6 +303,68 @@ void gs_frame::flip(draw_context_t, bool /*skip_frame*/)
}
}
void gs_frame::take_screenshot(const std::vector<u8> sshot_data, const u32 sshot_width, const u32 sshot_height)
{
std::thread(
[sshot_width, sshot_height](const std::vector<u8> sshot_data) {
std::string screen_path = fs::get_config_dir() + "/screenshots/";
if (!fs::create_dir(screen_path) && fs::g_tls_error != fs::error::exist)
{
LOG_ERROR(GENERAL, "Failed to create screenshot path \"%s\" : %s", screen_path, fs::g_tls_error);
return;
}
std::string filename = screen_path + "screenshot-" + date_time::current_time_narrow<'_'>() + ".png";
fs::file sshot_file(filename, fs::open_mode::create + fs::open_mode::write + fs::open_mode::excl);
if (!sshot_file)
{
LOG_ERROR(GENERAL, "[Screenshot] Failed to save screenshot \"%s\" : %s", filename, fs::g_tls_error);
return;
}
std::vector<u8> sshot_data_alpha(sshot_data.size());
const u32* sshot_ptr = (const u32*)sshot_data.data();
u32* alpha_ptr = (u32*)sshot_data_alpha.data();
for (size_t index = 0; index < sshot_data.size() / sizeof(u32); index++)
{
alpha_ptr[index] = ((sshot_ptr[index] & 0xFF) << 16) | (sshot_ptr[index] & 0xFF00) | ((sshot_ptr[index] & 0xFF0000) >> 16) | 0xFF000000;
}
std::vector<u8> encoded_png;
png_structp write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
png_infop info_ptr = png_create_info_struct(write_ptr);
png_set_IHDR(write_ptr, info_ptr, sshot_width, sshot_height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
std::vector<u8*> rows(sshot_height);
for (size_t y = 0; y < sshot_height; y++)
rows[y] = (u8*)sshot_data_alpha.data() + y * sshot_width * 4;
png_set_rows(write_ptr, info_ptr, &rows[0]);
png_set_write_fn(write_ptr, &encoded_png,
[](png_structp png_ptr, png_bytep data, png_size_t length) {
std::vector<u8>* p = (std::vector<u8>*)png_get_io_ptr(png_ptr);
p->insert(p->end(), data, data + length);
},
nullptr);
png_write_png(write_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr);
png_free_data(write_ptr, info_ptr, PNG_FREE_ALL, -1);
png_destroy_write_struct(&write_ptr, nullptr);
sshot_file.write(encoded_png.data(), encoded_png.size());
LOG_SUCCESS(GENERAL, "[Screenshot] Successfully saved screenshot to %s", filename);
return;
},
std::move(sshot_data))
.detach();
}
void gs_frame::mouseDoubleClickEvent(QMouseEvent* ev)
{
if (m_disable_mouse) return;

View File

@ -54,6 +54,8 @@ public:
void progress_increment(int delta);
void progress_set_limit(int limit);
void take_screenshot(const std::vector<u8> sshot_data, const u32 sshot_width, const u32 sshot_height) override;
protected:
virtual void paintEvent(QPaintEvent *event);
virtual void showEvent(QShowEvent *event) override;