mirror of https://github.com/RPCS3/rpcs3.git
cellScreenshot: initial implementation
This commit is contained in:
parent
2850d0c6bc
commit
0bad56da67
|
@ -121,5 +121,5 @@ struct CellPadFilterIIRSos
|
||||||
struct pad_info
|
struct pad_info
|
||||||
{
|
{
|
||||||
atomic_t<u32> max_connect = 0;
|
atomic_t<u32> max_connect = 0;
|
||||||
std::array<u32, CELL_PAD_MAX_PORT_NUM> port_setting;
|
std::array<u32, CELL_PAD_MAX_PORT_NUM> port_setting{ 0 };
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
|
#include "Emu/IdManager.h"
|
||||||
#include "Emu/Cell/PPUModule.h"
|
#include "Emu/Cell/PPUModule.h"
|
||||||
|
|
||||||
#include "cellScreenshot.h"
|
#include "cellScreenshot.h"
|
||||||
|
@ -8,27 +9,104 @@
|
||||||
|
|
||||||
LOG_CHANNEL(cellScreenshot);
|
LOG_CHANNEL(cellScreenshot);
|
||||||
|
|
||||||
s32 cellScreenShotSetParameter(vm::cptr<CellScreenShotSetParam> param)
|
template<>
|
||||||
|
void fmt_class_string<CellScreenShotError>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
cellScreenshot.todo("cellScreenShotSetParameter(param=*0x%x)", param);
|
format_enum(out, arg, [](auto error)
|
||||||
|
{
|
||||||
|
switch (error)
|
||||||
|
{
|
||||||
|
STR_CASE(CELL_SCREENSHOT_ERROR_INTERNAL);
|
||||||
|
STR_CASE(CELL_SCREENSHOT_ERROR_PARAM);
|
||||||
|
STR_CASE(CELL_SCREENSHOT_ERROR_DECODE);
|
||||||
|
STR_CASE(CELL_SCREENSHOT_ERROR_NOSPACE);
|
||||||
|
STR_CASE(CELL_SCREENSHOT_ERROR_UNSUPPORTED_COLOR_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return unknown;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
error_code cellScreenShotSetParameter(vm::cptr<CellScreenShotSetParam> param)
|
||||||
|
{
|
||||||
|
cellScreenshot.warning("cellScreenShotSetParameter(param=*0x%x)", param);
|
||||||
|
|
||||||
|
if (!param) // TODO: check if param->reserved must be null
|
||||||
|
return CELL_SCREENSHOT_ERROR_PARAM;
|
||||||
|
|
||||||
|
if (param->photo_title && !memchr(param->photo_title.get_ptr(), '\0', CELL_SCREENSHOT_PHOTO_TITLE_MAX_LENGTH))
|
||||||
|
return CELL_SCREENSHOT_ERROR_PARAM;
|
||||||
|
|
||||||
|
if (param->game_title && !memchr(param->game_title.get_ptr(), '\0', CELL_SCREENSHOT_GAME_TITLE_MAX_LENGTH))
|
||||||
|
return CELL_SCREENSHOT_ERROR_PARAM;
|
||||||
|
|
||||||
|
if (param->game_comment && !memchr(param->game_comment.get_ptr(), '\0', CELL_SCREENSHOT_GAME_COMMENT_MAX_SIZE))
|
||||||
|
return CELL_SCREENSHOT_ERROR_PARAM;
|
||||||
|
|
||||||
|
const auto manager = g_fxo->get<screenshot_manager>();
|
||||||
|
|
||||||
|
if (param->photo_title && param->photo_title[0] != '\0')
|
||||||
|
manager->photo_title = std::string(param->photo_title.get_ptr());
|
||||||
|
else
|
||||||
|
manager->photo_title = "";
|
||||||
|
|
||||||
|
if (param->game_title && param->game_title[0] != '\0')
|
||||||
|
manager->game_title = std::string(param->game_title.get_ptr());
|
||||||
|
else
|
||||||
|
manager->game_title = "";
|
||||||
|
|
||||||
|
if (param->game_comment && param->game_comment[0] != '\0')
|
||||||
|
manager->game_comment = std::string(param->game_comment.get_ptr());
|
||||||
|
else
|
||||||
|
manager->game_comment = "";
|
||||||
|
|
||||||
|
cellScreenshot.notice("cellScreenShotSetParameter(photo_title=%s, game_title=%s, game_comment=%s)", manager->photo_title, manager->game_title, manager->game_comment);
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 cellScreenShotSetOverlayImage(vm::cptr<char> srcDir, vm::cptr<char> srcFile, s32 offset_x, s32 offset_y)
|
error_code cellScreenShotSetOverlayImage(vm::cptr<char> srcDir, vm::cptr<char> srcFile, s32 offset_x, s32 offset_y)
|
||||||
{
|
{
|
||||||
cellScreenshot.todo("cellScreenShotSetOverlayImage(srcDir=%s, srcFile=%s, offset_x=%d, offset_y=%d)", srcDir, srcFile, offset_x, offset_y);
|
cellScreenshot.warning("cellScreenShotSetOverlayImage(srcDir=%s, srcFile=%s, offset_x=%d, offset_y=%d)", srcDir, srcFile, offset_x, offset_y);
|
||||||
|
|
||||||
|
if (!srcDir || !srcFile)
|
||||||
|
return CELL_SCREENSHOT_ERROR_PARAM;
|
||||||
|
|
||||||
|
// TODO: check srcDir (size 1024) and srcFile (size 64) for '-' or '_' or '.' or '/' in some manner (range checks?)
|
||||||
|
|
||||||
|
// Make sure that srcDir starts with /dev_hdd0, /dev_bdvd, /app_home or /host_root
|
||||||
|
if (strncmp(srcDir.get_ptr(), "/dev_hdd0", 9) && strncmp(srcDir.get_ptr(), "/dev_bdvd", 9) && strncmp(srcDir.get_ptr(), "/app_home", 9) && strncmp(srcDir.get_ptr(), "/host_root", 10))
|
||||||
|
{
|
||||||
|
return CELL_SCREENSHOT_ERROR_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto manager = g_fxo->get<screenshot_manager>();
|
||||||
|
|
||||||
|
manager->overlay_dir_name = std::string(srcDir.get_ptr());
|
||||||
|
manager->overlay_file_name = std::string(srcFile.get_ptr());
|
||||||
|
manager->overlay_offset_x = offset_x;
|
||||||
|
manager->overlay_offset_y = offset_y;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 cellScreenShotEnable()
|
error_code cellScreenShotEnable()
|
||||||
{
|
{
|
||||||
cellScreenshot.todo("cellScreenShotEnable()");
|
cellScreenshot.warning("cellScreenShotEnable()");
|
||||||
|
|
||||||
|
const auto manager = g_fxo->get<screenshot_manager>();
|
||||||
|
manager->is_enabled = true;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 cellScreenShotDisable()
|
error_code cellScreenShotDisable()
|
||||||
{
|
{
|
||||||
cellScreenshot.todo("cellScreenShotDisable()");
|
cellScreenshot.warning("cellScreenShotDisable()");
|
||||||
|
|
||||||
|
const auto manager = g_fxo->get<screenshot_manager>();
|
||||||
|
manager->is_enabled = false;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Emu/Memory/vm_ptr.h"
|
#include "Emu/Memory/vm_ptr.h"
|
||||||
|
|
||||||
// Return Codes
|
// Return Codes
|
||||||
enum
|
enum CellScreenShotError : u32
|
||||||
{
|
{
|
||||||
CELL_SCREENSHOT_ERROR_INTERNAL = 0x8002d101,
|
CELL_SCREENSHOT_ERROR_INTERNAL = 0x8002d101,
|
||||||
CELL_SCREENSHOT_ERROR_PARAM = 0x8002d102,
|
CELL_SCREENSHOT_ERROR_PARAM = 0x8002d102,
|
||||||
|
@ -12,9 +12,59 @@ enum
|
||||||
CELL_SCREENSHOT_ERROR_UNSUPPORTED_COLOR_FORMAT = 0x8002d105,
|
CELL_SCREENSHOT_ERROR_UNSUPPORTED_COLOR_FORMAT = 0x8002d105,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum CellScreenShotParamSize
|
||||||
|
{
|
||||||
|
CELL_SCREENSHOT_PHOTO_TITLE_MAX_LENGTH = 64,
|
||||||
|
CELL_SCREENSHOT_GAME_TITLE_MAX_LENGTH = 64,
|
||||||
|
CELL_SCREENSHOT_GAME_COMMENT_MAX_SIZE = 1024,
|
||||||
|
};
|
||||||
|
|
||||||
struct CellScreenShotSetParam
|
struct CellScreenShotSetParam
|
||||||
{
|
{
|
||||||
vm::bcptr<char> photo_title;
|
vm::bcptr<char> photo_title;
|
||||||
vm::bcptr<char> game_title;
|
vm::bcptr<char> game_title;
|
||||||
vm::bcptr<char> game_comment;
|
vm::bcptr<char> game_comment;
|
||||||
|
vm::bptr<void> reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct screenshot_manager
|
||||||
|
{
|
||||||
|
atomic_t<bool> is_enabled{ false };
|
||||||
|
|
||||||
|
std::string photo_title;
|
||||||
|
std::string game_title;
|
||||||
|
std::string game_comment;
|
||||||
|
|
||||||
|
atomic_t<s32> overlay_offset_x{ 0 };
|
||||||
|
atomic_t<s32> overlay_offset_y{ 0 };
|
||||||
|
std::string overlay_dir_name;
|
||||||
|
std::string overlay_file_name;
|
||||||
|
|
||||||
|
std::string get_overlay_path() const
|
||||||
|
{
|
||||||
|
return vfs::get(overlay_dir_name + overlay_file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_photo_title() const
|
||||||
|
{
|
||||||
|
std::string photo = photo_title;
|
||||||
|
if (photo.empty())
|
||||||
|
photo = Emu.GetTitle();
|
||||||
|
return photo;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_game_title() const
|
||||||
|
{
|
||||||
|
std::string game = game_title;
|
||||||
|
if (game.empty())
|
||||||
|
game = Emu.GetTitle();
|
||||||
|
return game;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_screenshot_path() const
|
||||||
|
{
|
||||||
|
// TODO: make sure the file can be saved, add suffix and increase counter if file exists
|
||||||
|
// TODO: maybe find a proper home for these
|
||||||
|
return fs::get_config_dir() + "/screenshots/cell/" + get_photo_title() + ".png";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "Utilities/Timer.h"
|
#include "Utilities/Timer.h"
|
||||||
#include "Utilities/date_time.h"
|
#include "Utilities/date_time.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
|
#include "Emu/Cell/Modules/cellScreenshot.h"
|
||||||
|
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
@ -152,7 +153,11 @@ void gs_frame::keyPressEvent(QKeyEvent *keyEvent)
|
||||||
else if (Emu.IsPaused()) { Emu.Resume(); return; }
|
else if (Emu.IsPaused()) { Emu.Resume(); return; }
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Qt::Key_F12: screenshot_toggle = true; break;
|
case Qt::Key_F12:
|
||||||
|
screenshot_toggle = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,7 +318,8 @@ 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)
|
void gs_frame::take_screenshot(const std::vector<u8> sshot_data, const u32 sshot_width, const u32 sshot_height)
|
||||||
{
|
{
|
||||||
std::thread(
|
std::thread(
|
||||||
[sshot_width, sshot_height](const std::vector<u8> sshot_data) {
|
[sshot_width, sshot_height](const std::vector<u8> sshot_data)
|
||||||
|
{
|
||||||
std::string screen_path = fs::get_config_dir() + "/screenshots/";
|
std::string screen_path = fs::get_config_dir() + "/screenshots/";
|
||||||
|
|
||||||
if (!fs::create_dir(screen_path) && fs::g_tls_error != fs::error::exist)
|
if (!fs::create_dir(screen_path) && fs::g_tls_error != fs::error::exist)
|
||||||
|
@ -352,7 +358,8 @@ void gs_frame::take_screenshot(const std::vector<u8> sshot_data, const u32 sshot
|
||||||
|
|
||||||
png_set_rows(write_ptr, info_ptr, &rows[0]);
|
png_set_rows(write_ptr, info_ptr, &rows[0]);
|
||||||
png_set_write_fn(write_ptr, &encoded_png,
|
png_set_write_fn(write_ptr, &encoded_png,
|
||||||
[](png_structp png_ptr, png_bytep data, png_size_t length) {
|
[](png_structp png_ptr, png_bytep data, png_size_t length)
|
||||||
|
{
|
||||||
std::vector<u8>* p = (std::vector<u8>*)png_get_io_ptr(png_ptr);
|
std::vector<u8>* p = (std::vector<u8>*)png_get_io_ptr(png_ptr);
|
||||||
p->insert(p->end(), data, data + length);
|
p->insert(p->end(), data, data + length);
|
||||||
},
|
},
|
||||||
|
@ -366,6 +373,44 @@ void gs_frame::take_screenshot(const std::vector<u8> sshot_data, const u32 sshot
|
||||||
sshot_file.write(encoded_png.data(), encoded_png.size());
|
sshot_file.write(encoded_png.data(), encoded_png.size());
|
||||||
|
|
||||||
LOG_SUCCESS(GENERAL, "[Screenshot] Successfully saved screenshot to %s", filename);
|
LOG_SUCCESS(GENERAL, "[Screenshot] Successfully saved screenshot to %s", filename);
|
||||||
|
|
||||||
|
const auto fxo = g_fxo->get<screenshot_manager>();
|
||||||
|
|
||||||
|
if (fxo->is_enabled)
|
||||||
|
{
|
||||||
|
const std::string cell_sshot_filename = fxo->get_screenshot_path();
|
||||||
|
const std::string cell_sshot_dir = fs::get_parent_dir(cell_sshot_filename);
|
||||||
|
|
||||||
|
LOG_NOTICE(GENERAL, "[Screenshot] Saving cell screenshot to %s", cell_sshot_filename);
|
||||||
|
|
||||||
|
if (!fs::create_path(cell_sshot_dir) && fs::g_tls_error != fs::error::exist)
|
||||||
|
{
|
||||||
|
LOG_ERROR(GENERAL, "Failed to create cell screenshot dir \"%s\" : %s", cell_sshot_dir, fs::g_tls_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::file cell_sshot_file(cell_sshot_filename, fs::open_mode::create + fs::open_mode::write + fs::open_mode::excl);
|
||||||
|
if (!cell_sshot_file)
|
||||||
|
{
|
||||||
|
LOG_ERROR(GENERAL, "[Screenshot] Failed to save cell screenshot \"%s\" : %s", cell_sshot_filename, fs::g_tls_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string cell_sshot_overlay_path = fxo->get_overlay_path();
|
||||||
|
if (fs::is_file(cell_sshot_overlay_path))
|
||||||
|
{
|
||||||
|
LOG_NOTICE(GENERAL, "[Screenshot] Adding overlay to cell screenshot from %s", cell_sshot_overlay_path);
|
||||||
|
// TODO: add overlay to screenshot
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add tEXt chunk with creation time, source, title id
|
||||||
|
// TODO: add tTXt chunk with data procured from cellScreenShotSetParameter (get_photo_title, get_game_title, game_comment)
|
||||||
|
|
||||||
|
cell_sshot_file.write(encoded_png.data(), encoded_png.size());
|
||||||
|
|
||||||
|
LOG_SUCCESS(GENERAL, "[Screenshot] Successfully saved cell screenshot to %s", cell_sshot_filename);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
std::move(sshot_data))
|
std::move(sshot_data))
|
||||||
|
|
Loading…
Reference in New Issue