mirror of
https://github.com/Vita3K/Vita3K-Android.git
synced 2024-11-27 15:30:43 +00:00
host: Move several items from host to emulator:
* init * handle_events * screen_render.cpp and screen_render.h * app.cpp and app.h * config functions * discrete GPU exports * emulator-called SFO functions
This commit is contained in:
parent
a5502792b0
commit
6dcc7633ea
@ -76,14 +76,24 @@ add_subdirectory(gui)
|
|||||||
add_executable(
|
add_executable(
|
||||||
emulator
|
emulator
|
||||||
MACOSX_BUNDLE
|
MACOSX_BUNDLE
|
||||||
|
app.cpp
|
||||||
|
app.h
|
||||||
|
config.cpp
|
||||||
|
config.h
|
||||||
|
init.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
|
performance.cpp
|
||||||
|
screen_render.cpp
|
||||||
|
screen_render.h
|
||||||
|
sfo.cpp
|
||||||
|
sfo.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_link_libraries(emulator PRIVATE ${Boost_LIBRARIES} cpu dialog elfio glbinding-aux glutil gui host shader imgui modules nids util vita-toolchain yaml-cpp)
|
||||||
if(LINUX)
|
if(LINUX)
|
||||||
target_link_libraries(emulator PRIVATE ${Boost_LIBRARIES} cpu dialog elfio glutil gui host shader imgui modules nids vita-toolchain util stdc++fs)
|
target_link_libraries(emulator PRIVATE stdc++fs)
|
||||||
else()
|
|
||||||
target_link_libraries(emulator PRIVATE ${Boost_LIBRARIES} cpu dialog elfio glutil gui host shader imgui modules nids vita-toolchain util)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set_target_properties(emulator PROPERTIES OUTPUT_NAME Vita3K
|
set_target_properties(emulator PROPERTIES OUTPUT_NAME Vita3K
|
||||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||||
|
@ -15,16 +15,19 @@
|
|||||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
#include "app.h"
|
||||||
|
|
||||||
|
#include "sfo.h"
|
||||||
|
|
||||||
#include <gui/functions.h>
|
#include <gui/functions.h>
|
||||||
#include <gui/imgui_impl_sdl_gl3.h>
|
#include <gui/imgui_impl_sdl_gl3.h>
|
||||||
#include <host/app.h>
|
|
||||||
#include <host/functions.h>
|
#include <host/functions.h>
|
||||||
#include <host/sfo.h>
|
|
||||||
#include <host/state.h>
|
#include <host/state.h>
|
||||||
#include <host/version.h>
|
#include <host/version.h>
|
||||||
#include <io/functions.h>
|
#include <io/functions.h>
|
||||||
#include <io/io.h>
|
#include <io/io.h>
|
||||||
#include <io/state.h>
|
#include <io/state.h>
|
||||||
|
#include <kernel/functions.h>
|
||||||
#include <kernel/load_self.h>
|
#include <kernel/load_self.h>
|
||||||
#include <kernel/state.h>
|
#include <kernel/state.h>
|
||||||
#include <kernel/thread/thread_functions.h>
|
#include <kernel/thread/thread_functions.h>
|
||||||
@ -48,6 +51,47 @@ static const char *EBOOT_PATH_ABS = "app0:eboot.bin";
|
|||||||
|
|
||||||
using namespace gl;
|
using namespace gl;
|
||||||
|
|
||||||
|
static void handle_window_event(HostState &state, const SDL_WindowEvent event) {
|
||||||
|
switch (static_cast<SDL_WindowEventID>(event.event)) {
|
||||||
|
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||||
|
update_viewport(state);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle_events(HostState &host) {
|
||||||
|
SDL_Event event;
|
||||||
|
while (SDL_PollEvent(&event)) {
|
||||||
|
ImGui_ImplSdlGL3_ProcessEvent(&event);
|
||||||
|
switch (event.type) {
|
||||||
|
case SDL_QUIT:
|
||||||
|
stop_all_threads(host.kernel);
|
||||||
|
host.gxm.display_queue.abort();
|
||||||
|
host.display.abort.exchange(true);
|
||||||
|
host.display.condvar.notify_all();
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
if (event.key.keysym.sym == SDLK_g) {
|
||||||
|
auto &display = host.display;
|
||||||
|
|
||||||
|
// toggle gui state
|
||||||
|
bool old_imgui_render = display.imgui_render.load();
|
||||||
|
while (!display.imgui_render.compare_exchange_weak(old_imgui_render, !old_imgui_render)) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDL_WINDOWEVENT:
|
||||||
|
handle_window_event(host, event.window);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void error_dialog(const std::string &message, SDL_Window *window) {
|
void error_dialog(const std::string &message, SDL_Window *window) {
|
||||||
if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", message.c_str(), window) < 0) {
|
if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", message.c_str(), window) < 0) {
|
||||||
LOG_ERROR("SDL Error: {}", message);
|
LOG_ERROR("SDL Error: {}", message);
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
struct Config;
|
||||||
struct HostState;
|
struct HostState;
|
||||||
struct SDL_Window;
|
struct SDL_Window;
|
||||||
template <class T>
|
template <class T>
|
||||||
@ -47,6 +48,9 @@ enum class AppRunType {
|
|||||||
Vpk,
|
Vpk,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool init(HostState &state, Config cfg);
|
||||||
|
void update_viewport(HostState &state);
|
||||||
|
bool handle_events(HostState &host);
|
||||||
void error_dialog(const std::string &message, SDL_Window *window = nullptr);
|
void error_dialog(const std::string &message, SDL_Window *window = nullptr);
|
||||||
ExitCode load_app(Ptr<const void> &entry_point, HostState &host, const std::wstring &path, AppRunType run_type);
|
ExitCode load_app(Ptr<const void> &entry_point, HostState &host, const std::wstring &path, AppRunType run_type);
|
||||||
ExitCode run_app(HostState &host, Ptr<const void> &entry_point);
|
ExitCode run_app(HostState &host, Ptr<const void> &entry_point);
|
@ -15,7 +15,7 @@
|
|||||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
#include <host/config.h>
|
#include "config.h"
|
||||||
|
|
||||||
#include <host/version.h>
|
#include <host/version.h>
|
||||||
#include <util/log.h>
|
#include <util/log.h>
|
||||||
@ -111,7 +111,7 @@ bool serialize(Config &cfg) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deserialize(Config &cfg) {
|
static bool deserialize(Config &cfg) {
|
||||||
YAML::Node config_node{};
|
YAML::Node config_node{};
|
||||||
|
|
||||||
try {
|
try {
|
45
src/emulator/config.h
Normal file
45
src/emulator/config.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Vita3K emulator project
|
||||||
|
// Copyright (C) 2018 Vita3K team
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <host/config.h>
|
||||||
|
|
||||||
|
namespace config {
|
||||||
|
|
||||||
|
enum class InitResult {
|
||||||
|
OK,
|
||||||
|
QUIT,
|
||||||
|
INCORRECT_ARGS,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* \brief Save emulator config to a YML file.
|
||||||
|
*
|
||||||
|
* \return True on saving success.
|
||||||
|
*/
|
||||||
|
bool serialize(Config &cfg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initializes config system, parsing command-line args and handling some basic ones:
|
||||||
|
* --help, --version, --log-level
|
||||||
|
* \param cfg Config options are returned via this parameter.
|
||||||
|
* \return True on success, false on error.
|
||||||
|
*/
|
||||||
|
InitResult init(Config &cfg, int argc, char **argv);
|
||||||
|
|
||||||
|
} // namespace config
|
@ -1,18 +1,13 @@
|
|||||||
add_library(
|
add_library(
|
||||||
host
|
host
|
||||||
STATIC
|
STATIC
|
||||||
include/host/app.h
|
|
||||||
include/host/config.h
|
include/host/config.h
|
||||||
include/host/screen_render.h
|
|
||||||
include/host/functions.h
|
include/host/functions.h
|
||||||
include/host/imports.h
|
include/host/imports.h
|
||||||
include/host/sfo.h
|
include/host/sfo.h
|
||||||
include/host/state.h
|
include/host/state.h
|
||||||
include/host/version.h
|
include/host/version.h
|
||||||
include/host/app_util.h
|
include/host/app_util.h
|
||||||
src/app.cpp
|
|
||||||
src/screen_render.cpp
|
|
||||||
src/config.cpp
|
|
||||||
src/host.cpp
|
src/host.cpp
|
||||||
src/sfo.cpp
|
src/sfo.cpp
|
||||||
version.cpp
|
version.cpp
|
||||||
@ -22,4 +17,4 @@ configure_file(src/version.cpp.in version.cpp)
|
|||||||
|
|
||||||
target_include_directories(host PUBLIC include)
|
target_include_directories(host PUBLIC include)
|
||||||
target_link_libraries(host PUBLIC audio cpu ctrl gxm io kernel mem net nids np renderer rtc util gui)
|
target_link_libraries(host PUBLIC audio cpu ctrl gxm io kernel mem net nids np renderer rtc util gui)
|
||||||
target_link_libraries(host PRIVATE ${Boost_LIBRARIES} glbinding-aux glutil microprofile sdl2 yaml-cpp)
|
target_link_libraries(host PRIVATE ${Boost_LIBRARIES} glutil microprofile sdl2)
|
||||||
|
@ -40,36 +40,3 @@ struct Config {
|
|||||||
optional<std::string> pref_path;
|
optional<std::string> pref_path;
|
||||||
bool archive_log = false;
|
bool archive_log = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace config {
|
|
||||||
|
|
||||||
enum class InitResult {
|
|
||||||
OK,
|
|
||||||
QUIT,
|
|
||||||
INCORRECT_ARGS,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* \brief Initializes config system from a YML file.
|
|
||||||
*
|
|
||||||
* \param cfg Config options are returned via this parameter.
|
|
||||||
* \return True on loading success.
|
|
||||||
*/
|
|
||||||
bool deserialize(Config &cfg);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* \brief Save emulator config to a YML file.
|
|
||||||
*
|
|
||||||
* \return True on saving success.
|
|
||||||
*/
|
|
||||||
bool serialize(Config &cfg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Initializes config system, parsing command-line args and handling some basic ones:
|
|
||||||
* --help, --version, --log-level
|
|
||||||
* \param cfg Config options are returned via this parameter.
|
|
||||||
* \return True on success, false on error.
|
|
||||||
*/
|
|
||||||
InitResult init(Config &cfg, int argc, char **argv);
|
|
||||||
|
|
||||||
} // namespace config
|
|
||||||
|
@ -19,10 +19,11 @@
|
|||||||
|
|
||||||
#include <psp2/types.h>
|
#include <psp2/types.h>
|
||||||
|
|
||||||
struct Config;
|
#include <string>
|
||||||
|
|
||||||
struct CPUState;
|
struct CPUState;
|
||||||
struct HostState;
|
struct HostState;
|
||||||
|
struct SfoFile;
|
||||||
|
|
||||||
bool init(HostState &state, Config cfg);
|
|
||||||
bool handle_events(HostState &host);
|
|
||||||
void call_import(HostState &host, CPUState &cpu, uint32_t nid, SceUID thread_id);
|
void call_import(HostState &host, CPUState &cpu, uint32_t nid, SceUID thread_id);
|
||||||
|
bool get_data(std::string &out_data, SfoFile &file, int id);
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility> // pair
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct SfoHeader {
|
struct SfoHeader {
|
||||||
@ -48,7 +48,3 @@ struct SfoFile {
|
|||||||
|
|
||||||
std::vector<SfoEntry> entries;
|
std::vector<SfoEntry> entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool load_sfo(SfoFile &file, const std::vector<uint8_t> &data);
|
|
||||||
bool find_data(std::string &out_data, SfoFile &file, const std::string &key);
|
|
||||||
bool get_data(std::string &out_data, SfoFile &file, int id);
|
|
||||||
|
@ -17,69 +17,16 @@
|
|||||||
|
|
||||||
#include <host/functions.h>
|
#include <host/functions.h>
|
||||||
|
|
||||||
|
#include <cpu/functions.h>
|
||||||
#include <host/imports.h>
|
#include <host/imports.h>
|
||||||
#include <host/state.h>
|
#include <host/state.h>
|
||||||
#include <host/version.h>
|
|
||||||
|
|
||||||
#include <audio/functions.h>
|
|
||||||
#include <cpu/functions.h>
|
|
||||||
#include <glutil/gl.h>
|
|
||||||
#include <io/functions.h>
|
|
||||||
#include <io/io.h>
|
|
||||||
#include <kernel/functions.h>
|
|
||||||
#include <kernel/thread/thread_state.h>
|
|
||||||
#include <nids/functions.h>
|
#include <nids/functions.h>
|
||||||
#include <rtc/rtc.h>
|
|
||||||
#include <util/lock_and_find.h>
|
#include <util/lock_and_find.h>
|
||||||
#include <util/log.h>
|
#include <util/log.h>
|
||||||
|
|
||||||
#include <SDL_events.h>
|
|
||||||
#include <SDL_filesystem.h>
|
|
||||||
#include <SDL_video.h>
|
|
||||||
|
|
||||||
#include <glbinding-aux/types_to_string.h>
|
|
||||||
#include <glbinding/Binding.h>
|
|
||||||
#include <microprofile.h>
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include <gui/imgui_impl_sdl_gl3.h>
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <util/string_utils.h>
|
|
||||||
#else
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
// Use discrete GPU by default
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
// NVIDIA Optimus (Driver: 302+)
|
|
||||||
// See: http://developer.download.nvidia.com/devzone/devcenter/gamegraphics/files/OptimusRenderingPolicies.pdf
|
|
||||||
__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
|
|
||||||
// AMD (Driver: 13.35+)
|
|
||||||
// See: https://gpuopen.com/amdpowerxpressrequesthighperformance/
|
|
||||||
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace glbinding;
|
|
||||||
|
|
||||||
static bool LOG_IMPORT_CALLS = false;
|
static bool LOG_IMPORT_CALLS = false;
|
||||||
static constexpr bool LOG_UNK_NIDS_ALWAYS = false;
|
static constexpr bool LOG_UNK_NIDS_ALWAYS = false;
|
||||||
|
|
||||||
static constexpr auto DEFAULT_RES_WIDTH = 960;
|
|
||||||
static constexpr auto DEFAULT_RES_HEIGHT = 544;
|
|
||||||
|
|
||||||
#define NID(name, nid) extern const ImportFn import_##name;
|
#define NID(name, nid) extern const ImportFn import_##name;
|
||||||
#include <nids/nids.h>
|
#include <nids/nids.h>
|
||||||
#undef NID
|
#undef NID
|
||||||
@ -96,196 +43,6 @@ static ImportFn resolve_import(uint32_t nid) {
|
|||||||
return ImportFn();
|
return ImportFn();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MICROPROFILE_ENABLED
|
|
||||||
static void before_callback(const glbinding::FunctionCall &fn) {
|
|
||||||
const MicroProfileToken token = MicroProfileGetToken("OpenGL", fn.function->name(), MP_CYAN, MicroProfileTokenTypeCpu);
|
|
||||||
MICROPROFILE_ENTER_TOKEN(token);
|
|
||||||
}
|
|
||||||
#endif // MICROPROFILE_ENABLED
|
|
||||||
|
|
||||||
static void after_callback(const glbinding::FunctionCall &fn) {
|
|
||||||
MICROPROFILE_LEAVE();
|
|
||||||
for (GLenum error = glGetError(); error != GL_NO_ERROR; error = glGetError()) {
|
|
||||||
std::stringstream gl_error;
|
|
||||||
gl_error << error;
|
|
||||||
LOG_ERROR("OpenGL: {} set error {}.", fn.function->name(), gl_error.str());
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_viewport(HostState &state) {
|
|
||||||
int w = 0;
|
|
||||||
int h = 0;
|
|
||||||
SDL_GL_GetDrawableSize(state.window.get(), &w, &h);
|
|
||||||
|
|
||||||
state.drawable_size.x = w;
|
|
||||||
state.drawable_size.y = h;
|
|
||||||
|
|
||||||
if (h > 0) {
|
|
||||||
const float window_aspect = static_cast<float>(w) / h;
|
|
||||||
const float vita_aspect = static_cast<float>(DEFAULT_RES_WIDTH) / DEFAULT_RES_HEIGHT;
|
|
||||||
if (window_aspect > vita_aspect) {
|
|
||||||
// Window is wide. Pin top and bottom.
|
|
||||||
state.viewport_size.x = h * vita_aspect;
|
|
||||||
state.viewport_size.y = h;
|
|
||||||
state.viewport_pos.x = (w - state.viewport_size.x) / 2;
|
|
||||||
state.viewport_pos.y = 0;
|
|
||||||
} else {
|
|
||||||
// Window is tall. Pin left and right.
|
|
||||||
state.viewport_size.x = w;
|
|
||||||
state.viewport_size.y = w / vita_aspect;
|
|
||||||
state.viewport_pos.x = 0;
|
|
||||||
state.viewport_pos.y = (h - state.viewport_size.y) / 2;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
state.viewport_pos.x = 0;
|
|
||||||
state.viewport_pos.y = 0;
|
|
||||||
state.viewport_size.x = 0;
|
|
||||||
state.viewport_size.y = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_window_event(HostState &state, const SDL_WindowEvent event) {
|
|
||||||
switch (static_cast<SDL_WindowEventID>(event.event)) {
|
|
||||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
|
||||||
update_viewport(state);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init(HostState &state, Config cfg) {
|
|
||||||
const std::unique_ptr<char, void (&)(void *)> base_path(SDL_GetBasePath(), SDL_free);
|
|
||||||
const std::unique_ptr<char, void (&)(void *)> pref_path(SDL_GetPrefPath(org_name, app_name), SDL_free);
|
|
||||||
|
|
||||||
const ResumeAudioThread resume_thread = [&state](SceUID thread_id) {
|
|
||||||
const ThreadStatePtr thread = lock_and_find(thread_id, state.kernel.threads, state.kernel.mutex);
|
|
||||||
const std::lock_guard<std::mutex> lock(thread->mutex);
|
|
||||||
if (thread->to_do == ThreadToDo::wait) {
|
|
||||||
thread->to_do = ThreadToDo::run;
|
|
||||||
}
|
|
||||||
thread->something_to_do.notify_all();
|
|
||||||
};
|
|
||||||
|
|
||||||
state.cfg = std::move(cfg);
|
|
||||||
state.base_path = base_path.get();
|
|
||||||
|
|
||||||
// If configuration already provides preference path
|
|
||||||
if (!state.cfg.pref_path) {
|
|
||||||
state.pref_path = pref_path.get();
|
|
||||||
state.cfg.pref_path = state.pref_path;
|
|
||||||
} else {
|
|
||||||
state.pref_path = state.cfg.pref_path.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
state.window = WindowPtr(SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, DEFAULT_RES_WIDTH, DEFAULT_RES_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE), SDL_DestroyWindow);
|
|
||||||
if (!state.window || !init(state.mem) || !init(state.audio, resume_thread) || !init(state.io, state.pref_path.c_str(), state.base_path.c_str())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
|
||||||
|
|
||||||
state.glcontext = GLContextPtr(SDL_GL_CreateContext(state.window.get()), SDL_GL_DeleteContext);
|
|
||||||
if (!state.glcontext) {
|
|
||||||
LOG_ERROR("Could not create OpenGL context.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
update_viewport(state);
|
|
||||||
|
|
||||||
// Try adaptive vsync first, falling back to regular vsync.
|
|
||||||
if (SDL_GL_SetSwapInterval(-1) < 0) {
|
|
||||||
SDL_GL_SetSwapInterval(1);
|
|
||||||
}
|
|
||||||
LOG_INFO("Swap interval = {}", SDL_GL_GetSwapInterval());
|
|
||||||
|
|
||||||
const glbinding::GetProcAddress get_proc_address = [](const char *name) {
|
|
||||||
return reinterpret_cast<ProcAddress>(SDL_GL_GetProcAddress(name));
|
|
||||||
};
|
|
||||||
Binding::initialize(get_proc_address, false);
|
|
||||||
Binding::setCallbackMaskExcept(CallbackMask::Before | CallbackMask::After, { "glGetError" });
|
|
||||||
#if MICROPROFILE_ENABLED != 0
|
|
||||||
Binding::setBeforeCallback(before_callback);
|
|
||||||
#endif // MICROPROFILE_ENABLED
|
|
||||||
Binding::setAfterCallback(after_callback);
|
|
||||||
|
|
||||||
state.kernel.base_tick = { rtc_base_ticks() };
|
|
||||||
|
|
||||||
std::string dir_path = state.pref_path + "ux0/app";
|
|
||||||
#ifdef WIN32
|
|
||||||
_WDIR *d = _wopendir((string_utils::utf_to_wide(dir_path)).c_str());
|
|
||||||
_wdirent *dp;
|
|
||||||
#else
|
|
||||||
DIR *d = opendir(dir_path.c_str());
|
|
||||||
dirent *dp;
|
|
||||||
#endif
|
|
||||||
do {
|
|
||||||
std::string d_name_utf8;
|
|
||||||
#ifdef WIN32
|
|
||||||
if ((dp = _wreaddir(d)) != NULL) {
|
|
||||||
d_name_utf8 = string_utils::wide_to_utf(dp->d_name);
|
|
||||||
#else
|
|
||||||
if ((dp = readdir(d)) != NULL) {
|
|
||||||
d_name_utf8 = dp->d_name;
|
|
||||||
#endif
|
|
||||||
if ((strcmp(d_name_utf8.c_str(), ".")) && (strcmp(d_name_utf8.c_str(), ".."))) {
|
|
||||||
vfs::FileBuffer params;
|
|
||||||
state.io.title_id = d_name_utf8;
|
|
||||||
if (vfs::read_app_file(params, state.pref_path, state.io.title_id, "sce_sys/param.sfo")) {
|
|
||||||
SfoFile sfo_handle;
|
|
||||||
load_sfo(sfo_handle, params);
|
|
||||||
find_data(state.game_version, sfo_handle, "APP_VER");
|
|
||||||
find_data(state.game_title, sfo_handle, "TITLE");
|
|
||||||
std::replace(state.game_title.begin(), state.game_title.end(), '\n', ' ');
|
|
||||||
state.gui.game_selector.games.push_back({ state.game_version, state.game_title, state.io.title_id });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (dp);
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
_wclosedir(d);
|
|
||||||
#else
|
|
||||||
closedir(d);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool handle_events(HostState &host) {
|
|
||||||
SDL_Event event;
|
|
||||||
while (SDL_PollEvent(&event)) {
|
|
||||||
ImGui_ImplSdlGL3_ProcessEvent(&event);
|
|
||||||
switch (event.type) {
|
|
||||||
case SDL_QUIT:
|
|
||||||
stop_all_threads(host.kernel);
|
|
||||||
host.gxm.display_queue.abort();
|
|
||||||
host.display.abort.exchange(true);
|
|
||||||
host.display.condvar.notify_all();
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case SDL_KEYDOWN:
|
|
||||||
if (event.key.keysym.sym == SDLK_g) {
|
|
||||||
auto &display = host.display;
|
|
||||||
|
|
||||||
// toggle gui state
|
|
||||||
bool old_imgui_render = display.imgui_render.load();
|
|
||||||
while (!display.imgui_render.compare_exchange_weak(old_imgui_render, !old_imgui_render)) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_WINDOWEVENT:
|
|
||||||
handle_window_event(host, event.window);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Resolves a function imported from a loaded module.
|
* \brief Resolves a function imported from a loaded module.
|
||||||
* \param kernel Kernel state struct
|
* \param kernel Kernel state struct
|
||||||
|
@ -15,67 +15,10 @@
|
|||||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
#include <host/functions.h>
|
||||||
|
|
||||||
#include <host/sfo.h>
|
#include <host/sfo.h>
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
bool load_sfo(SfoFile &sfile, const std::vector<uint8_t> &content) {
|
|
||||||
if (content.empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(static_cast<void *>(&sfile.header), content.data(), sizeof(SfoHeader));
|
|
||||||
|
|
||||||
sfile.entries.resize(sfile.header.tables_entries + 1);
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sfile.header.tables_entries; i++) {
|
|
||||||
memcpy(static_cast<void *>(&sfile.entries[i].entry), content.data() + sizeof(SfoHeader) + i * sizeof(SfoIndexTableEntry), sizeof(SfoIndexTableEntry));
|
|
||||||
}
|
|
||||||
|
|
||||||
sfile.entries[sfile.header.tables_entries].entry.key_offset = sfile.header.data_table_start - sfile.header.key_table_start;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sfile.header.tables_entries; i++) {
|
|
||||||
uint32_t keySize = sfile.entries[i + 1].entry.key_offset - sfile.entries[i].entry.key_offset;
|
|
||||||
|
|
||||||
sfile.entries[i].data.first.resize(keySize);
|
|
||||||
|
|
||||||
memcpy(&sfile.entries[i].data.first[0], &content[sfile.header.key_table_start + sfile.entries[i].entry.key_offset], keySize);
|
|
||||||
|
|
||||||
//Quick hack to remove garbage null terminator caused by reading directly
|
|
||||||
//to buffer
|
|
||||||
sfile.entries[i].data.first = sfile.entries[i].data.first.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sfile.header.tables_entries; i++) {
|
|
||||||
uint32_t dataSize = sfile.entries[i].entry.data_len;
|
|
||||||
|
|
||||||
sfile.entries[i].data.second.resize(dataSize);
|
|
||||||
|
|
||||||
// The last of data is a terminator
|
|
||||||
memcpy(&sfile.entries[i].data.second[0], &content[sfile.header.data_table_start + sfile.entries[i].entry.data_offset], dataSize - 1);
|
|
||||||
|
|
||||||
//Quick hack to remove garbage null terminator caused by reading directly
|
|
||||||
//to buffer
|
|
||||||
sfile.entries[i].data.second = sfile.entries[i].data.second.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool find_data(std::string &out_data, SfoFile &file, const std::string &key) {
|
|
||||||
auto res = std::find_if(file.entries.begin(), file.entries.end(),
|
|
||||||
[key](auto et) { return et.data.first == key; });
|
|
||||||
|
|
||||||
if (res == file.entries.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
out_data = res->data.second;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_data(std::string &out_data, SfoFile &file, int id) {
|
bool get_data(std::string &out_data, SfoFile &file, int id) {
|
||||||
if (file.entries.size() < id) {
|
if (file.entries.size() < id) {
|
||||||
return false;
|
return false;
|
||||||
|
201
src/emulator/init.cpp
Normal file
201
src/emulator/init.cpp
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
// Vita3K emulator project
|
||||||
|
// Copyright (C) 2018 Vita3K team
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
#include "app.h"
|
||||||
|
#include "sfo.h"
|
||||||
|
|
||||||
|
#include <audio/functions.h>
|
||||||
|
#include <glutil/gl.h>
|
||||||
|
#include <host/state.h>
|
||||||
|
#include <host/version.h>
|
||||||
|
#include <io/functions.h>
|
||||||
|
#include <io/io.h> // vfs
|
||||||
|
#include <rtc/rtc.h>
|
||||||
|
#include <util/lock_and_find.h>
|
||||||
|
#include <util/log.h>
|
||||||
|
|
||||||
|
#include <SDL_filesystem.h>
|
||||||
|
#include <SDL_video.h>
|
||||||
|
#include <glbinding-aux/types_to_string.h>
|
||||||
|
#include <glbinding/Binding.h>
|
||||||
|
#include <microprofile.h>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <util/string_utils.h>
|
||||||
|
#else
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace glbinding;
|
||||||
|
|
||||||
|
static constexpr auto DEFAULT_RES_WIDTH = 960;
|
||||||
|
static constexpr auto DEFAULT_RES_HEIGHT = 544;
|
||||||
|
|
||||||
|
#if MICROPROFILE_ENABLED
|
||||||
|
static void before_callback(const glbinding::FunctionCall &fn) {
|
||||||
|
const MicroProfileToken token = MicroProfileGetToken("OpenGL", fn.function->name(), MP_CYAN, MicroProfileTokenTypeCpu);
|
||||||
|
MICROPROFILE_ENTER_TOKEN(token);
|
||||||
|
}
|
||||||
|
#endif // MICROPROFILE_ENABLED
|
||||||
|
|
||||||
|
static void after_callback(const glbinding::FunctionCall &fn) {
|
||||||
|
MICROPROFILE_LEAVE();
|
||||||
|
for (GLenum error = glGetError(); error != GL_NO_ERROR; error = glGetError()) {
|
||||||
|
std::stringstream gl_error;
|
||||||
|
gl_error << error;
|
||||||
|
LOG_ERROR("OpenGL: {} set error {}.", fn.function->name(), gl_error.str());
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_viewport(HostState &state) {
|
||||||
|
int w = 0;
|
||||||
|
int h = 0;
|
||||||
|
SDL_GL_GetDrawableSize(state.window.get(), &w, &h);
|
||||||
|
|
||||||
|
state.drawable_size.x = w;
|
||||||
|
state.drawable_size.y = h;
|
||||||
|
|
||||||
|
if (h > 0) {
|
||||||
|
const float window_aspect = static_cast<float>(w) / h;
|
||||||
|
const float vita_aspect = static_cast<float>(DEFAULT_RES_WIDTH) / DEFAULT_RES_HEIGHT;
|
||||||
|
if (window_aspect > vita_aspect) {
|
||||||
|
// Window is wide. Pin top and bottom.
|
||||||
|
state.viewport_size.x = h * vita_aspect;
|
||||||
|
state.viewport_size.y = h;
|
||||||
|
state.viewport_pos.x = (w - state.viewport_size.x) / 2;
|
||||||
|
state.viewport_pos.y = 0;
|
||||||
|
} else {
|
||||||
|
// Window is tall. Pin left and right.
|
||||||
|
state.viewport_size.x = w;
|
||||||
|
state.viewport_size.y = w / vita_aspect;
|
||||||
|
state.viewport_pos.x = 0;
|
||||||
|
state.viewport_pos.y = (h - state.viewport_size.y) / 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.viewport_pos.x = 0;
|
||||||
|
state.viewport_pos.y = 0;
|
||||||
|
state.viewport_size.x = 0;
|
||||||
|
state.viewport_size.y = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init(HostState &state, Config cfg) {
|
||||||
|
const std::unique_ptr<char, void (&)(void *)> base_path(SDL_GetBasePath(), SDL_free);
|
||||||
|
const std::unique_ptr<char, void (&)(void *)> pref_path(SDL_GetPrefPath(org_name, app_name), SDL_free);
|
||||||
|
|
||||||
|
const ResumeAudioThread resume_thread = [&state](SceUID thread_id) {
|
||||||
|
const ThreadStatePtr thread = lock_and_find(thread_id, state.kernel.threads, state.kernel.mutex);
|
||||||
|
const std::lock_guard<std::mutex> lock(thread->mutex);
|
||||||
|
if (thread->to_do == ThreadToDo::wait) {
|
||||||
|
thread->to_do = ThreadToDo::run;
|
||||||
|
}
|
||||||
|
thread->something_to_do.notify_all();
|
||||||
|
};
|
||||||
|
|
||||||
|
state.cfg = std::move(cfg);
|
||||||
|
state.base_path = base_path.get();
|
||||||
|
|
||||||
|
// If configuration already provides preference path
|
||||||
|
if (!state.cfg.pref_path) {
|
||||||
|
state.pref_path = pref_path.get();
|
||||||
|
state.cfg.pref_path = state.pref_path;
|
||||||
|
} else {
|
||||||
|
state.pref_path = state.cfg.pref_path.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
state.window = WindowPtr(SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, DEFAULT_RES_WIDTH, DEFAULT_RES_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE), SDL_DestroyWindow);
|
||||||
|
if (!state.window || !init(state.mem) || !init(state.audio, resume_thread) || !init(state.io, state.pref_path.c_str(), state.base_path.c_str())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
|
|
||||||
|
state.glcontext = GLContextPtr(SDL_GL_CreateContext(state.window.get()), SDL_GL_DeleteContext);
|
||||||
|
if (!state.glcontext) {
|
||||||
|
LOG_ERROR("Could not create OpenGL context.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_viewport(state);
|
||||||
|
|
||||||
|
// Try adaptive vsync first, falling back to regular vsync.
|
||||||
|
if (SDL_GL_SetSwapInterval(-1) < 0) {
|
||||||
|
SDL_GL_SetSwapInterval(1);
|
||||||
|
}
|
||||||
|
LOG_INFO("Swap interval = {}", SDL_GL_GetSwapInterval());
|
||||||
|
|
||||||
|
const glbinding::GetProcAddress get_proc_address = [](const char *name) {
|
||||||
|
return reinterpret_cast<ProcAddress>(SDL_GL_GetProcAddress(name));
|
||||||
|
};
|
||||||
|
Binding::initialize(get_proc_address, false);
|
||||||
|
Binding::setCallbackMaskExcept(CallbackMask::Before | CallbackMask::After, { "glGetError" });
|
||||||
|
#if MICROPROFILE_ENABLED != 0
|
||||||
|
Binding::setBeforeCallback(before_callback);
|
||||||
|
#endif // MICROPROFILE_ENABLED
|
||||||
|
Binding::setAfterCallback(after_callback);
|
||||||
|
|
||||||
|
state.kernel.base_tick = { rtc_base_ticks() };
|
||||||
|
|
||||||
|
std::string dir_path = state.pref_path + "ux0/app";
|
||||||
|
#ifdef WIN32
|
||||||
|
_WDIR *d = _wopendir((string_utils::utf_to_wide(dir_path)).c_str());
|
||||||
|
_wdirent *dp;
|
||||||
|
#else
|
||||||
|
DIR *d = opendir(dir_path.c_str());
|
||||||
|
dirent *dp;
|
||||||
|
#endif
|
||||||
|
do {
|
||||||
|
std::string d_name_utf8;
|
||||||
|
#ifdef WIN32
|
||||||
|
if ((dp = _wreaddir(d)) != NULL) {
|
||||||
|
d_name_utf8 = string_utils::wide_to_utf(dp->d_name);
|
||||||
|
#else
|
||||||
|
if ((dp = readdir(d)) != NULL) {
|
||||||
|
d_name_utf8 = dp->d_name;
|
||||||
|
#endif
|
||||||
|
if ((strcmp(d_name_utf8.c_str(), ".")) && (strcmp(d_name_utf8.c_str(), ".."))) {
|
||||||
|
vfs::FileBuffer params;
|
||||||
|
state.io.title_id = d_name_utf8;
|
||||||
|
if (vfs::read_app_file(params, state.pref_path, state.io.title_id, "sce_sys/param.sfo")) {
|
||||||
|
SfoFile sfo_handle;
|
||||||
|
load_sfo(sfo_handle, params);
|
||||||
|
find_data(state.game_version, sfo_handle, "APP_VER");
|
||||||
|
find_data(state.game_title, sfo_handle, "TITLE");
|
||||||
|
std::replace(state.game_title.begin(), state.game_title.end(), '\n', ' ');
|
||||||
|
state.gui.game_selector.games.push_back({ state.game_version, state.game_title, state.io.title_id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (dp);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
_wclosedir(d);
|
||||||
|
#else
|
||||||
|
closedir(d);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
@ -15,14 +15,13 @@
|
|||||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
#include "app.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "screen_render.h"
|
||||||
|
|
||||||
#include <gui/functions.h>
|
#include <gui/functions.h>
|
||||||
#include <host/app.h>
|
|
||||||
#include <host/config.h>
|
|
||||||
#include <host/functions.h>
|
|
||||||
#include <host/screen_render.h>
|
|
||||||
#include <host/state.h>
|
#include <host/state.h>
|
||||||
#include <host/version.h>
|
#include <host/version.h>
|
||||||
#include <kernel/thread/thread_functions.h>
|
|
||||||
#include <shader/spirv_recompiler.h>
|
#include <shader/spirv_recompiler.h>
|
||||||
#include <util/log.h>
|
#include <util/log.h>
|
||||||
#include <util/string_utils.h>
|
#include <util/string_utils.h>
|
||||||
@ -30,8 +29,6 @@
|
|||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iterator>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
logging::init();
|
logging::init();
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
|
|
||||||
#include "SceAppMgrUser.h"
|
#include "SceAppMgrUser.h"
|
||||||
|
|
||||||
#include <host/sfo.h>
|
#include <host/functions.h>
|
||||||
|
|
||||||
#include <psp2/appmgr.h>
|
#include <psp2/appmgr.h>
|
||||||
|
|
||||||
EXPORT(int, _sceAppMgrGetAppState, void *appState, uint32_t len, uint32_t version) {
|
EXPORT(int, _sceAppMgrGetAppState, void *appState, uint32_t len, uint32_t version) {
|
||||||
|
30
src/emulator/performance.cpp
Normal file
30
src/emulator/performance.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Vita3K emulator project
|
||||||
|
// Copyright (C) 2018 Vita3K team
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
// http://developer.download.nvidia.com/devzone/devcenter/gamegraphics/files/OptimusRenderingPolicies.pdf
|
||||||
|
__declspec(dllexport) uint32_t NvOptimusEnablement = 1;
|
||||||
|
|
||||||
|
// https://gpuopen.com/amdpowerxpressrequesthighperformance/
|
||||||
|
__declspec(dllexport) uint32_t AmdPowerXpressRequestHighPerformance = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // _WIN32
|
@ -15,7 +15,8 @@
|
|||||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
#include <host/screen_render.h>
|
#include "screen_render.h"
|
||||||
|
|
||||||
#include <host/state.h>
|
#include <host/state.h>
|
||||||
#include <util/log.h>
|
#include <util/log.h>
|
||||||
|
|
78
src/emulator/sfo.cpp
Normal file
78
src/emulator/sfo.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Vita3K emulator project
|
||||||
|
// Copyright (C) 2018 Vita3K team
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
#include "sfo.h"
|
||||||
|
|
||||||
|
#include <host/sfo.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
bool load_sfo(SfoFile &sfile, const std::vector<uint8_t> &content) {
|
||||||
|
if (content.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(static_cast<void *>(&sfile.header), content.data(), sizeof(SfoHeader));
|
||||||
|
|
||||||
|
sfile.entries.resize(sfile.header.tables_entries + 1);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < sfile.header.tables_entries; i++) {
|
||||||
|
memcpy(static_cast<void *>(&sfile.entries[i].entry), content.data() + sizeof(SfoHeader) + i * sizeof(SfoIndexTableEntry), sizeof(SfoIndexTableEntry));
|
||||||
|
}
|
||||||
|
|
||||||
|
sfile.entries[sfile.header.tables_entries].entry.key_offset = sfile.header.data_table_start - sfile.header.key_table_start;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < sfile.header.tables_entries; i++) {
|
||||||
|
uint32_t keySize = sfile.entries[i + 1].entry.key_offset - sfile.entries[i].entry.key_offset;
|
||||||
|
|
||||||
|
sfile.entries[i].data.first.resize(keySize);
|
||||||
|
|
||||||
|
memcpy(&sfile.entries[i].data.first[0], &content[sfile.header.key_table_start + sfile.entries[i].entry.key_offset], keySize);
|
||||||
|
|
||||||
|
//Quick hack to remove garbage null terminator caused by reading directly
|
||||||
|
//to buffer
|
||||||
|
sfile.entries[i].data.first = sfile.entries[i].data.first.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < sfile.header.tables_entries; i++) {
|
||||||
|
uint32_t dataSize = sfile.entries[i].entry.data_len;
|
||||||
|
|
||||||
|
sfile.entries[i].data.second.resize(dataSize);
|
||||||
|
|
||||||
|
// The last of data is a terminator
|
||||||
|
memcpy(&sfile.entries[i].data.second[0], &content[sfile.header.data_table_start + sfile.entries[i].entry.data_offset], dataSize - 1);
|
||||||
|
|
||||||
|
//Quick hack to remove garbage null terminator caused by reading directly
|
||||||
|
//to buffer
|
||||||
|
sfile.entries[i].data.second = sfile.entries[i].data.second.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool find_data(std::string &out_data, SfoFile &file, const std::string &key) {
|
||||||
|
auto res = std::find_if(file.entries.begin(), file.entries.end(),
|
||||||
|
[key](auto et) { return et.data.first == key; });
|
||||||
|
|
||||||
|
if (res == file.entries.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out_data = res->data.second;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
26
src/emulator/sfo.h
Normal file
26
src/emulator/sfo.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Vita3K emulator project
|
||||||
|
// Copyright (C) 2018 Vita3K team
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct SfoFile;
|
||||||
|
|
||||||
|
bool load_sfo(SfoFile &file, const std::vector<uint8_t> &data);
|
||||||
|
bool find_data(std::string &out_data, SfoFile &file, const std::string &key);
|
Loading…
Reference in New Issue
Block a user