Skip to content

Commit

Permalink
Merge branch 'Vita3K:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
backgamon authored Feb 4, 2024
2 parents 149b0f4 + 17886d8 commit 64709df
Show file tree
Hide file tree
Showing 18 changed files with 193 additions and 55 deletions.
2 changes: 1 addition & 1 deletion external/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ if(NOT OPENSSL_FOUND)
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/external/openssl")
endif()

set(OPENSSL_ROOT_DIR "${CMAKE_BINARY_DIR}/external/openssl/openssl-3/x64")
set(OPENSSL_ROOT_DIR "${CMAKE_BINARY_DIR}/external/openssl/openssl-3.1/x64")
endif()

find_package(OpenSSL REQUIRED)
Expand Down
4 changes: 2 additions & 2 deletions vita3k/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,8 @@ elseif(WIN32)
add_custom_command(
TARGET vita3k
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_BINARY_DIR}/external/openssl/openssl-3/x64/bin/libssl-3-x64.dll" "$<TARGET_FILE_DIR:vita3k>"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_BINARY_DIR}/external/openssl/openssl-3/x64/bin/libcrypto-3-x64.dll" "$<TARGET_FILE_DIR:vita3k>")
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_BINARY_DIR}/external/openssl/openssl-3.1/x64/bin/libssl-3-x64.dll" "$<TARGET_FILE_DIR:vita3k>"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_BINARY_DIR}/external/openssl/openssl-3.1/x64/bin/libcrypto-3-x64.dll" "$<TARGET_FILE_DIR:vita3k>")
endif()
endif()

Expand Down
1 change: 1 addition & 0 deletions vita3k/config/include/config/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ enum PerfomanceOverleyPosition {
code(int, "keyboard-gui-fullscreen", 68, keyboard_gui_fullscreen) \
code(int, "keyboard-gui-toggle-touch", 23, keyboard_gui_toggle_touch) \
code(int, "keyboard-toggle-texture-replacement", 0, keyboard_toggle_texture_replacement) \
code(int, "keyboard-take-screenshot", 0, keyboard_take_screenshot) \
code(std::string, "user-id", std::string{}, user_id) \
code(bool, "user-auto-connect", false, auto_user_login) \
code(std::string, "user-lang", std::string{}, user_lang) \
Expand Down
3 changes: 3 additions & 0 deletions vita3k/gui/src/controls_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ static void remapper_button(GuiState &gui, EmuEnvState &emuenv, int *button, con
ImGui::TableSetColumnIndex(1);
// the association of the key
int key_association = *button;
ImGui::PushID(button_name);
if (ImGui::Button(SDL_key_to_string[key_association])) {
gui.old_captured_key = key_association;
gui.is_capturing_keys = true;
Expand All @@ -117,6 +118,7 @@ static void remapper_button(GuiState &gui, EmuEnvState &emuenv, int *button, con
}
config::serialize_config(emuenv.cfg, emuenv.cfg.config_path);
}
ImGui::PopID();
}

void draw_controls_dialog(GuiState &gui, EmuEnvState &emuenv) {
Expand Down Expand Up @@ -195,6 +197,7 @@ void draw_controls_dialog(GuiState &gui, EmuEnvState &emuenv) {
ImGui::TableSetupColumn("button");
ImGui::TableSetupColumn("mapped_button");
remapper_button(gui, emuenv, &emuenv.cfg.keyboard_toggle_texture_replacement, lang["toggle_texture_replacement"].c_str());
remapper_button(gui, emuenv, &emuenv.cfg.keyboard_take_screenshot, "Take a screenshot");
ImGui::EndTable();
}

Expand Down
31 changes: 31 additions & 0 deletions vita3k/interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
#include <regex>

#include <SDL.h>
#include <fmt/chrono.h>
#include <stb_image_write.h>

#include <gdbstub/functions.h>

Expand Down Expand Up @@ -530,6 +532,33 @@ static void toggle_texture_replacement(EmuEnvState &emuenv) {
emuenv.renderer->get_texture_cache()->set_replacement_state(emuenv.cfg.current_config.import_textures, emuenv.cfg.current_config.export_textures, emuenv.cfg.current_config.export_as_png);
}

static void take_screenshot(EmuEnvState &emuenv) {
if (emuenv.io.title_id.empty()) {
LOG_ERROR("Trying to take a screenshot while not ingame");
}

uint32_t width, height;
std::vector<uint32_t> frame = emuenv.renderer->dump_frame(emuenv.display, width, height);

if (frame.empty() || frame.size() != width * height) {
LOG_ERROR("Failed to take screenshot");
return;
}

// set the alpha to 1
for (int i = 0; i < width * height; i++)
frame[i] |= 0xFF000000;

const fs::path save_folder = emuenv.shared_path / "screenshots";
fs::create_directories(save_folder);

const fs::path save_file = save_folder / fmt::format("{}_{:%Y-%m-%d_%H-%M-%OS}.png", emuenv.io.title_id, fmt::localtime(std::time(nullptr)));
if (stbi_write_png(fs_utils::path_to_utf8(save_file).c_str(), width, height, 4, frame.data(), width * 4) == 1)
LOG_INFO("Successfully saved screenshot to {}", save_file);
else
LOG_INFO("Failed to save screenshot");
}

bool handle_events(EmuEnvState &emuenv, GuiState &gui) {
refresh_controllers(emuenv.ctrl, emuenv);
const auto allow_switch_state = !emuenv.io.title_id.empty() && !gui.vita_area.app_close && !gui.vita_area.home_screen && !gui.vita_area.user_management && !gui.configuration_menu.custom_settings_dialog && !gui.configuration_menu.settings_dialog && !gui.controls_menu.controls_dialog && gui::get_sys_apps_state(gui);
Expand Down Expand Up @@ -681,6 +710,8 @@ bool handle_events(EmuEnvState &emuenv, GuiState &gui) {
switch_full_screen(emuenv);
if (event.key.keysym.scancode == emuenv.cfg.keyboard_toggle_texture_replacement && !gui.is_key_capture_dropped)
toggle_texture_replacement(emuenv);
if (event.key.keysym.scancode == emuenv.cfg.keyboard_take_screenshot && !gui.is_key_capture_dropped)
take_screenshot(emuenv);

if (sce_ctrl_btn != 0)
ui_navigation(sce_ctrl_btn);
Expand Down
2 changes: 1 addition & 1 deletion vita3k/lang/src/lang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ void init_lang(LangState &lang, EmuEnvState &emuenv) {
set_lang_string(lang.settings_dialog.gpu, settings_dialog.child("gpu"));

// Audio
set_lang_string(lang.settings_dialog.emulator, settings_dialog.child("audio"));
set_lang_string(lang.settings_dialog.audio, settings_dialog.child("audio"));

// System
set_lang_string(lang.settings_dialog.system, settings_dialog.child("system"));
Expand Down
2 changes: 2 additions & 0 deletions vita3k/renderer/include/renderer/gl/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ struct GLState : public renderer::State {
void render_frame(const SceFVector2 &viewport_pos, const SceFVector2 &viewport_size, DisplayState &display,
const GxmState &gxm, MemState &mem) override;
void swap_window(SDL_Window *window) override;
std::vector<uint32_t> dump_frame(DisplayState &display, uint32_t &width, uint32_t &height) override;

int get_supported_filters() override;
void set_screen_filter(const std::string_view &filter) override;
int get_max_anisotropic_filtering() override;
Expand Down
21 changes: 17 additions & 4 deletions vita3k/renderer/include/renderer/gl/surface_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
#pragma once

#include <glutil/object_array.h>
#include <renderer/surface_cache.h>
#include <gxm/types.h>
#include <mem/ptr.h>
#include <renderer/gxm_types.h>

#include <array>
#include <memory>
Expand All @@ -28,9 +30,18 @@

struct MemState;

namespace renderer::gl {
namespace renderer {
struct State;

namespace gl {

struct GLRenderTarget;

enum SurfaceTextureRetrievePurpose {
READING,
WRITING,
};

struct GLSurfaceCacheInfo {
enum {
FLAG_DIRTY = 1 << 0,
Expand Down Expand Up @@ -76,7 +87,7 @@ struct GLDepthStencilSurfaceCacheInfo : public GLSurfaceCacheInfo {
std::int32_t height;
};

class GLSurfaceCache : public SurfaceCache {
class GLSurfaceCache {
private:
static constexpr std::uint32_t MAX_CACHE_SIZE_PER_CONTAINER = 20;

Expand Down Expand Up @@ -117,5 +128,7 @@ class GLSurfaceCache : public SurfaceCache {
}

GLuint sourcing_color_surface_for_presentation(Ptr<const void> address, uint32_t width, uint32_t height, const std::uint32_t pitch, float *uvs, const int res_multiplier, SceFVector2 &texture_size);
std::vector<uint32_t> dump_frame(Ptr<const void> address, uint32_t width, uint32_t height, uint32_t pitch, int res_multiplier, bool support_get_texture_sub_image);
};
} // namespace renderer::gl
} // namespace gl
} // namespace renderer
2 changes: 2 additions & 0 deletions vita3k/renderer/include/renderer/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ struct State {
const GxmState &gxm, MemState &mem)
= 0;
virtual void swap_window(SDL_Window *window) = 0;
// perform a screenshot of the (upscaled) frame to be rendered and return it in a vector in its rgba8 format
virtual std::vector<uint32_t> dump_frame(DisplayState &display, uint32_t &width, uint32_t &height) = 0;
// return a mask of the features which can influence the compiled shaders
virtual uint32_t get_features_mask() {
return 0;
Expand Down
38 changes: 0 additions & 38 deletions vita3k/renderer/include/renderer/surface_cache.h

This file was deleted.

2 changes: 2 additions & 0 deletions vita3k/renderer/include/renderer/vulkan/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ struct VKState : public renderer::State {
void render_frame(const SceFVector2 &viewport_pos, const SceFVector2 &viewport_size, DisplayState &display,
const GxmState &gxm, MemState &mem) override;
void swap_window(SDL_Window *window) override;
std::vector<uint32_t> dump_frame(DisplayState &display, uint32_t &width, uint32_t &height) override;

uint32_t get_features_mask() override;
int get_supported_filters() override;
void set_screen_filter(const std::string_view &filter) override;
Expand Down
11 changes: 8 additions & 3 deletions vita3k/renderer/include/renderer/vulkan/surface_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@

#pragma once

#include <renderer/surface_cache.h>

#include <gxm/types.h>
#include <mem/ptr.h>
#include <renderer/gxm_types.h>
#include <util/containers.h>
#include <vkutil/objects.h>

Expand Down Expand Up @@ -145,7 +146,7 @@ struct SurfaceRetrieveResult {
vkutil::Image *base_image;
};

class VKSurfaceCache : public SurfaceCache {
class VKSurfaceCache {
private:
VKState &state;

Expand Down Expand Up @@ -207,6 +208,10 @@ class VKSurfaceCache : public SurfaceCache {
// Viewport should already have its fields width and height filled
vk::ImageView sourcing_color_surface_for_presentation(Ptr<const void> address, uint32_t pitch, Viewport &viewport);

// Dump an rgba8 frame with the given properties to the returned vector
// if this function fails, the vector will be empty
std::vector<uint32_t> dump_frame(Ptr<const void> address, uint32_t width, uint32_t height, uint32_t pitch);

void set_render_target(VKRenderTarget *new_target) {
target = new_target;
}
Expand Down
14 changes: 13 additions & 1 deletion vita3k/renderer/src/gl/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ void lookup_and_get_surface_data(GLState &renderer, MemState &mem, SceGxmColorSu

GLint tex_handle = static_cast<GLint>(renderer.surface_cache.retrieve_color_surface_texture_handle(renderer, static_cast<std::uint16_t>(surface.width),
static_cast<std::uint16_t>(surface.height), static_cast<std::uint16_t>(surface.strideInPixels),
gxm::get_base_format(surface.colorFormat), surface.data, renderer::SurfaceTextureRetrievePurpose::READING, swizzle));
gxm::get_base_format(surface.colorFormat), surface.data, SurfaceTextureRetrievePurpose::READING, swizzle));

if (tex_handle == 0) {
return;
Expand Down Expand Up @@ -716,6 +716,18 @@ void GLState::swap_window(SDL_Window *window) {
SDL_GL_SwapWindow(window);
}

std::vector<uint32_t> GLState::dump_frame(DisplayState &display, uint32_t &width, uint32_t &height) {
DisplayFrameInfo frame;
{
std::lock_guard<std::mutex> guard(display.display_info_mutex);
frame = display.next_rendered_frame;
}

width = frame.image_size.x * res_multiplier;
height = frame.image_size.y * res_multiplier;
return surface_cache.dump_frame(frame.base, width, height, frame.pitch, res_multiplier, features.support_get_texture_sub_image);
}

int GLState::get_supported_filters() {
// actually it's not even bilinear, it's either bilinear or nearest depending on the last use of the texture..
// TODO: add bicubic filter and allow disabling bilinear.
Expand Down
45 changes: 44 additions & 1 deletion vita3k/renderer/src/gl/surface_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ GLuint GLSurfaceCache::retrieve_framebuffer_handle(const State &state, const Mem
std::uint32_t swizzle_set = color->colorFormat & SCE_GXM_COLOR_SWIZZLE_MASK;
color_handle = static_cast<GLuint>(retrieve_color_surface_texture_handle(state, color->width,
color->height, color->strideInPixels, gxm::get_base_format(color->colorFormat), color->data,
renderer::SurfaceTextureRetrievePurpose::WRITING, swizzle_set, stored_height));
SurfaceTextureRetrievePurpose::WRITING, swizzle_set, stored_height));
} else {
color_handle = target->attachments[0];
}
Expand Down Expand Up @@ -758,4 +758,47 @@ GLuint GLSurfaceCache::sourcing_color_surface_for_presentation(Ptr<const void> a
return 0;
}

std::vector<uint32_t> GLSurfaceCache::dump_frame(Ptr<const void> address, uint32_t width, uint32_t height, uint32_t pitch, int res_multiplier, bool support_get_texture_sub_image) {
auto ite = color_surface_textures.lower_bound(address.address());
if (ite == color_surface_textures.end() || ite->second->pixel_stride != pitch) {
return {};
}

const GLColorSurfaceCacheInfo &info = *ite->second;

const uint32_t data_delta = address.address() - ite->first;
const uint32_t pitch_byte = pitch * 4;
if (info.pixel_stride != pitch || data_delta % pitch_byte != 0)
return {};

const uint32_t line_delta = (data_delta / pitch_byte) * res_multiplier;
if (line_delta >= info.height)
return {};

if (!support_get_texture_sub_image && (line_delta != 0 || info.width != width || info.height != height)) {
LOG_ERROR("Dumping this frame is not supported on the OpenGL renderer");
return {};
}

const uint32_t real_height = std::min(height, info.height - line_delta);

std::vector<uint32_t> frame(width * height, 0);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);

// retrieve the texture, it is on the GPU right now
if (support_get_texture_sub_image) {
glGetTextureSubImage(info.gl_texture[0], 0, 0, line_delta, 0, width, real_height, 1, GL_RGBA, GL_UNSIGNED_BYTE, frame.size() * 4, frame.data());
} else {
GLint last_texture = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);

glBindTexture(GL_TEXTURE_2D, info.gl_texture[0]);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame.data());

glBindTexture(GL_TEXTURE_2D, last_texture);
}

return frame;
}

} // namespace renderer::gl
2 changes: 1 addition & 1 deletion vita3k/renderer/src/gl/sync_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ void sync_texture(GLState &state, GLContext &context, MemState &mem, std::size_t

texture_as_surface = state.surface_cache.retrieve_color_surface_texture_handle(
state, width, height, stride_in_pixels, format_target_of_texture, Ptr<void>(data_addr),
renderer::SurfaceTextureRetrievePurpose::READING, swizz_raw);
SurfaceTextureRetrievePurpose::READING, swizz_raw);

swizzle_surface = color::translate_swizzle(static_cast<SceGxmColorFormat>(format_target_of_texture | swizz_raw));
only_nearest = color::is_write_surface_non_linearity_filtering(format_target_of_texture);
Expand Down
4 changes: 2 additions & 2 deletions vita3k/renderer/src/texture/replacement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ void TextureCache::export_texture_impl(SceGxmTextureBaseFormat base_format, uint
uint64_t hash = current_info->hash;
const std::string file_name = fmt::format("{:016X}.png", hash);
fs::path export_name = export_folder / file_name;
stbi_write_png(export_name.generic_string().c_str(), width, height, nb_comp, data, pixels_per_stride * nb_comp);
stbi_write_png(fs_utils::path_to_utf8(export_name).c_str(), width, height, nb_comp, data, pixels_per_stride * nb_comp);

if (log_texture_export)
LOG_DEBUG("Texture {} ({}x{}) exported", file_name, width, height);
Expand Down Expand Up @@ -507,7 +507,7 @@ bool TextureCache::import_configure_texture() {
imported_texture_decoded = imported_texture_raw_data.data() + dds_descriptor->headerSize;
} else {
int nb_channels;
imported_texture_decoded = stbi_load(import_name.generic_string().c_str(), reinterpret_cast<int *>(&width), reinterpret_cast<int *>(&height), &nb_channels, nb_comp);
imported_texture_decoded = stbi_load(fs_utils::path_to_utf8(import_name).c_str(), reinterpret_cast<int *>(&width), reinterpret_cast<int *>(&height), &nb_channels, nb_comp);
if (imported_texture_decoded == nullptr) {
LOG_ERROR("Failed to decode {}", file_name);
return false;
Expand Down
13 changes: 13 additions & 0 deletions vita3k/renderer/src/vulkan/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(
"VUID-VkImageCreateInfo-imageCreateMaxMipLevels-02251", // srgb does not support the storage format
"VUID-vkCmdPipelineBarrier-pDependencies-02285", // shader write -> vertex input read self-dependency, wrong error
"VUID-vkCmdDrawIndexed-None-09003", // reading from color attachment, works on most GPUs with a general layout
"VUID-vkAcquireNextImageKHR-semaphore-01779" // Semaphore misuse, to fix
};

if (message_severity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
Expand Down Expand Up @@ -747,6 +748,18 @@ void VKState::swap_window(SDL_Window *window) {
}
}

std::vector<uint32_t> VKState::dump_frame(DisplayState &display, uint32_t &width, uint32_t &height) {
DisplayFrameInfo frame;
{
std::lock_guard<std::mutex> guard(display.display_info_mutex);
frame = display.next_rendered_frame;
}

width = frame.image_size.x * res_multiplier;
height = frame.image_size.y * res_multiplier;
return surface_cache.dump_frame(frame.base, width, height, frame.pitch);
}

uint32_t VKState::get_features_mask() {
union {
struct {
Expand Down
Loading

0 comments on commit 64709df

Please sign in to comment.