Add PSVita port (#541)

* add psvita to cmake

* no PIE for vita

* add modules to vpk

* use custom pvr apphint

* select correct renderer for sdl renderer

* patch sdl3 shaders, got something on screen!

* use proper cmake patch for sdl

* add missing module

* remove test window which causes a bug in the vita sdl port to show up

* add gxm renderer (not working with display yet)

* avoid sdl renderer for vita, seems broken

* make gxm renderer work with new d3drm

* fix rendering somewhat, some geometry shows up

* support paletted textures directly to avoid copying the texture twice

* fix Draw2DImage

* make 3d work, broken lights

* clean up a bit

* fix normals matrix

* remove some unneeded changes

* forgot env var

* wrong env dest

* run clang format

* correct texture address mode, use tlsf instead of sceClibMspace

* double buffered uniforms seem to work now

* missed a line

* update GXMRenderer_EnumDevice

* hopefully actually fix uniform buffers

* run clang-format

* remove a change thats not needed

* improve fragment shader performance

* add vita to dist folder

* add base for vita config app

* add config self to vpk

* transform touch events to virtual size

* add livearea graphics

* Update cmake file to include livearea assets

* put manual in the right place

* add sample rco

* add messagebox on vita

* triple buffer textures because fences arent a thing on vita and making draw&cpu sync would be too slow

* make config app not crash on launch

* change defaults

* update gxm renderer with interface changes

* split 2d and 3d shaders completely

* update gxm renderer

* fix transition on gxm

* clang format

* move config cmake

* move CONFIG_vita

* always clear before drawing 2d image

* hopefully fix windows build

* clang-format fix broken includes

* order again

* undo moving qt cmake to its own list

* move uic search path

* use ifdefs for all d3drm backends, cpack to generate vpk

* cmake wrong escape

* small cleanups in gxm renderer

* defer texture delete to avoid overwriting the texture during a frame

* clang-format

* more of the layout for config

* remove top buttons

* use SceAppSettings instead of custom ui

* use select for back to info center on vita, to make screenshots possible again

* remove accidentally left in add_subdirectory

* adjust diskpath to be like other ports

* use vita_create_vpk and not cpack

* gxm: msaa support, fix wrong file path

* gxm: add mipmaps (disabled)

* clang-format

* fix open isle.ini with fopen

* add missing strings

* use iniparser_set not dictionary_set

* add default save path to config

* load config app after initializing ini on vita

* fix config build

* change the default disk & cd path, update the paf library

* update paf library headers

* include orders for clang-format

* clean up

* make shader compiler not required

* move asm language

* warn instead of error when shader source is changed when no compiler is found

---------

Co-authored-by: Li <li@silica.codes>
Co-authored-by: Christian Semmler <mail@csemmler.com>
This commit is contained in:
olebeck 2025-11-01 00:23:12 +01:00 committed by GitHub
parent 3f974f7317
commit 47736862a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
103 changed files with 5448 additions and 15 deletions

View File

@ -48,6 +48,7 @@ jobs:
- { name: 'Nintendo 3DS', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: false, n3ds: true, werror: true, clang-tidy: false, container: 'devkitpro/devkitarm:latest', cmake-args: '-DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/3DS.cmake' }
- { name: 'Xbox One', os: 'windows-latest', generator: 'Visual Studio 17 2022', dx5: false, config: false, msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64', cmake-args: '-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0.26100.0', xbox-one: true}
- { name: 'Android', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: false, android: true, werror: true, clang-tidy: false,}
- { name: 'Vita', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: false, vita: true, werror: true, clang-tidy: false, cmake-args: '--toolchain /usr/local/vitasdk/share/vita.toolchain.cmake'}
steps:
- name: Setup vcvars
if: ${{ !!matrix.msvc }}
@ -117,6 +118,18 @@ jobs:
- name: Setup ninja
if: ${{ matrix.msvc }}
uses: ashutoshvarma/setup-ninja@master
- name: Setup vitasdk
if: ${{ matrix.vita }}
run: |
git clone https://github.com/vitasdk/vdpm
cd vdpm
./bootstrap-vitasdk.sh
export VITASDK=/usr/local/vitasdk
export PATH=$VITASDK/bin:$PATH
echo "VITASDK=/usr/local/vitasdk" >> $GITHUB_ENV
echo "$VITASDK/bin" >> $GITHUB_PATH
./install-all.sh
- uses: actions/checkout@v4
@ -177,7 +190,7 @@ jobs:
run: cmake --build build --verbose --config Release
- name: Package (CPack)
if: ${{ !matrix.n3ds && !matrix.android }}
if: ${{ !matrix.n3ds && !matrix.android && !matrix.vita }}
run: |
cd build
success=0
@ -225,6 +238,13 @@ jobs:
mkdir dist
mv *.3dsx dist/
mv *.cia dist/
- name: Package (Vita)
if: ${{ matrix.vita }}
run: |
cd build
mkdir dist
mv *.vpk dist/
- name: Package (Android)
if: ${{ matrix.android }}
@ -246,6 +266,7 @@ jobs:
build/dist/*.3dsx
build/dist/*.cia
build/dist/*.apk
build/dist/*.vpk
flatpak:
name: "Flatpak (${{ matrix.arch }})"

View File

@ -46,18 +46,18 @@ option(ISLE_BUILD_ASSETS "Build assets from the /assets directory" OFF)
option(ISLE_ASAN "Enable Address Sanitizer" OFF)
option(ISLE_UBSAN "Enable Undefined Behavior Sanitizer" OFF)
option(ISLE_WERROR "Treat warnings as errors" OFF)
option(ISLE_DEBUG "Enable imgui debug" ON)
cmake_dependent_option(ISLE_DEBUG "Enable imgui debug" ON "NOT VITA" OFF)
cmake_dependent_option(ISLE_USE_DX5 "Build with internal DirectX 5 SDK" "${NOT_MINGW}" "WIN32;CMAKE_SIZEOF_VOID_P EQUAL 4" OFF)
cmake_dependent_option(ISLE_MINIWIN "Use miniwin" ON "NOT ISLE_USE_DX5" OFF)
cmake_dependent_option(ISLE_EXTENSIONS "Use extensions" ON "NOT ISLE_USE_DX5;NOT WINDOWS_STORE" OFF)
cmake_dependent_option(ISLE_BUILD_CONFIG "Build CONFIG.EXE application" ON "MSVC OR ISLE_MINIWIN;NOT NINTENDO_3DS;NOT WINDOWS_STORE" OFF)
cmake_dependent_option(ISLE_BUILD_CONFIG "Build CONFIG.EXE application" ON "MSVC OR ISLE_MINIWIN;NOT NINTENDO_3DS;NOT WINDOWS_STORE;NOT VITA" OFF)
cmake_dependent_option(ISLE_COMPILE_SHADERS "Compile shaders" ON "SDL_SHADERCROSS_BIN;TARGET Python3::Interpreter" OFF)
option(CMAKE_POSITION_INDEPENDENT_CODE "Build with -fPIC" ON)
cmake_dependent_option(CMAKE_POSITION_INDEPENDENT_CODE "Build with -fPIC" ON "NOT VITA" OFF)
option(ENABLE_CLANG_TIDY "Enable clang-tidy")
option(DOWNLOAD_DEPENDENCIES "Download dependencies" ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" CACHE PATH "Directory where to put executables and dll")
set(ISLE_EMSCRIPTEN_HOST "" CACHE STRING "Host URL for Emscripten streaming (e.g., https://test.com)")
cmake_dependent_option(BUILD_SHARED_LIBS "Build lego1 as a shared library" ON "NOT EMSCRIPTEN" OFF)
cmake_dependent_option(BUILD_SHARED_LIBS "Build lego1 as a shared library" ON "NOT EMSCRIPTEN;NOT VITA" OFF)
message(STATUS "Isle app: ${ISLE_BUILD_APP}")
message(STATUS "Config app: ${ISLE_BUILD_CONFIG}")
@ -90,6 +90,7 @@ if (DOWNLOAD_DEPENDENCIES)
SDL3
GIT_REPOSITORY "https://github.com/libsdl-org/SDL.git"
GIT_TAG "main"
UPDATE_DISCONNECTED TRUE
EXCLUDE_FROM_ALL
)
endif()
@ -100,6 +101,7 @@ if (DOWNLOAD_DEPENDENCIES)
iniparser
GIT_REPOSITORY "https://gitlab.com/iniparser/iniparser.git"
GIT_TAG "main"
UPDATE_DISCONNECTED TRUE
EXCLUDE_FROM_ALL
)
block()
@ -598,6 +600,12 @@ if (ISLE_BUILD_APP)
ISLE/android/config.cpp
)
endif()
if(VITA)
target_sources(isle PRIVATE
ISLE/vita/config.cpp
ISLE/vita/messagebox.cpp
)
endif()
if(Python3_FOUND)
if(NOT DEFINED PYTHON_PIL_AVAILABLE)
execute_process(
@ -639,18 +647,18 @@ if (ISLE_BUILD_CONFIG)
qt_add_executable(isle-config WIN32
LEGO1/mxdirectx/mxdirectxinfo.cpp
LEGO1/mxdirectx/legodxinfo.cpp
CONFIG/config.cpp
CONFIG/AboutDlg.cpp
CONFIG/MainDlg.cpp
CONFIG/detectdx5.cpp
CONFIG/res/config.rc
CONFIG/res/config.qrc
CONFIG/qt/config.cpp
CONFIG/qt/AboutDlg.cpp
CONFIG/qt/MainDlg.cpp
CONFIG/qt/detectdx5.cpp
CONFIG/qt/res/config.rc
CONFIG/qt/res/config.qrc
)
target_link_libraries(isle-config PRIVATE Qt6::Core Qt6::Widgets)
set_property(TARGET isle-config PROPERTY AUTOMOC ON)
set_property(TARGET isle-config PROPERTY AUTORCC ON)
set_property(TARGET isle-config PROPERTY AUTOUIC ON)
set_property(TARGET isle-config PROPERTY AUTOUIC_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/CONFIG/res")
set_property(TARGET isle-config PROPERTY AUTOUIC_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/CONFIG/qt/res")
list(APPEND isle_targets isle-config)
target_compile_definitions(isle-config PRIVATE _AFXDLL MXDIRECTX_FOR_CONFIG)
target_include_directories(isle-config PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/LEGO1")
@ -782,7 +790,7 @@ endif()
if(BUILD_SHARED_LIBS)
list(APPEND install_extra_targets lego1)
endif()
if (NOT (NINTENDO_3DS OR WINDOWS_STORE))
if (NOT (NINTENDO_3DS OR WINDOWS_STORE OR VITA))
install(TARGETS isle ${install_extra_targets}
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
@ -881,6 +889,35 @@ if(WINDOWS_STORE)
PATTERN "*/*.msix"
PATTERN "*/*.msixbundle")
endif()
if(VITA)
include("${VITASDK}/share/vita.cmake" REQUIRED)
add_subdirectory(CONFIG/vita)
set(ISLE_PACKAGE_NAME "vita-isle")
set(VITA_APP_NAME "Lego Island")
set(VITA_TITLEID "LEGO00001")
set(VITA_VERSION "01.00")
vita_create_self(isle.self isle UNSAFE)
set(VPK_FILE_ARGS "")
file(GLOB_RECURSE SCE_SYS_FILES packaging/vita/sce_sys/*)
foreach(FILE ${SCE_SYS_FILES})
file(RELATIVE_PATH REL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/packaging/vita/ ${FILE})
list(APPEND VPK_FILE_ARGS FILE ${FILE} ${REL_FILE})
endforeach()
vita_create_vpk(isle.vpk ${VITA_TITLEID} isle.self
FILE "${CMAKE_CURRENT_BINARY_DIR}/CONFIG/vita/isle-config.self" isle-config.self
FILE "${CMAKE_CURRENT_BINARY_DIR}/CONFIG/vita/config_plugin.rco" config_plugin.rco
VERSION ${VITA_VERSION}
NAME ${VITA_APP_NAME}
${VPK_FILE_ARGS}
)
add_dependencies(isle.vpk-vpk config_plugin.rco_target)
endif()
if(MSVC OR IOS)
set(CPACK_GENERATOR ZIP)
if(IOS)

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 477 B

After

Width:  |  Height:  |  Size: 477 B

View File

Before

Width:  |  Height:  |  Size: 397 B

After

Width:  |  Height:  |  Size: 397 B

View File

Before

Width:  |  Height:  |  Size: 526 B

After

Width:  |  Height:  |  Size: 526 B

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,73 @@
cmake_minimum_required(VERSION 3.25...4.0 FATAL_ERROR)
project(isle-config LANGUAGES CXX C VERSION 0.1)
include("${VITASDK}/share/vita.cmake" REQUIRED)
include(FetchContent)
FetchContent_Declare(
ScePaf_External
URL https://github.com/olebeck/ScePaf/releases/download/v21/ScePaf-1.0.0.zip
URL_HASH SHA256=357b914a5c99ea17afe0edc8787a05cbf2ecce2f1d73bb9be69f371a294b8943
UPDATE_DISCONNECTED TRUE
)
FetchContent_MakeAvailable(ScePaf_External)
FetchContent_Declare(
iniparser_paf
GIT_REPOSITORY "https://gitlab.com/iniparser/iniparser.git"
GIT_TAG "v4.2.6"
UPDATE_DISCONNECTED TRUE
EXCLUDE_FROM_ALL
PATCH_COMMAND patch -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/iniparser_paf.patch
)
block()
set(BUILD_DOCS off)
set(BUILD_SHARED_LIBS off)
FetchContent_MakeAvailable(iniparser_paf)
endblock()
add_executable(isle-config
src/paf_runtime.cpp
src/app.cpp
)
set_target_properties(isle-config PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
target_compile_options(isle-config PRIVATE
-fno-rtti -fno-exceptions -Wl,-q -Wall -fno-builtin -fshort-wchar -Wno-unused-function -Wno-sign-compare -fno-use-cxa-atexit
)
target_link_options(isle-config PRIVATE
-nostartfiles -nostdlib
)
target_link_libraries(isle-config PRIVATE
SceAppMgr_stub
SceLibKernel_stub
SceSysmodule_stub
ScePafToplevel_stub
ScePafResource_stub
ScePafWidget_stub
ScePafCommon_stub
ScePafStdc_stub
SceAppSettings_stub
SceFios2_stub
SceLibc_stub
iniparser_paf-static
)
vita_create_self(isle-config.self isle-config
CONFIG exports.yml
UNSAFE
STRIPPED
REL_OPTIMIZE
)
include(${scepaf_external_SOURCE_DIR}/rco.cmake)
make_rco(cxml/config_plugin.xml config_plugin.rco)

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<resource version="0.1" type="normal" id="config_plugin">
<filetable>
<file src="settings.xml" type="application/xml" id="settings.xml" compress="off" />
</filetable>
<stringtable>
<!--
<locale src_="locale/ja.xml" compress="on" id="ja" />
-->
<locale src="locale/en.xml" compress="on" id="en" />
<!--
<locale src_="locale/en-gb.xml" compress="on" id="en-gb" />
<locale src_="locale/zh-s.xml" compress="on" id="zh-s" />
<locale src_="locale/zh-t.xml" compress="on" id="zh-t" />
<locale src_="locale/da.xml" compress="on" id="da" />
<locale src_="locale/nl.xml" compress="on" id="nl" />
<locale src_="locale/fi.xml" compress="on" id="fi" />
<locale src_="locale/fr.xml" compress="on" id="fr" />
<locale src_="locale/de.xml" compress="on" id="de" />
<locale src_="locale/it.xml" compress="on" id="it" />
<locale src_="locale/ko.xml" compress="on" id="ko" />
<locale src_="locale/no.xml" compress="on" id="no" />
<locale src_="locale/pl.xml" compress="on" id="pl" />
<locale src_="locale/pt.xml" compress="on" id="pt" />
<locale src_="locale/ru.xml" compress="on" id="ru" />
<locale src_="locale/es.xml" compress="on" id="es" />
<locale src_="locale/sv.xml" compress="on" id="sv" />
<locale src_="locale/pt-br.xml" compress="on" id="pt-br" />
<locale src_="locale/tr.xml" compress="on" id="tr" />
-->
</stringtable>
</resource>

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<stringset>
<!-- Main Page -->
<string id="msg_lego_island_config" src="Lego Island Config"/>
<string id="msg_page_game" src="Game" />
<string id="msg_page_graphics" src="Graphics" />
<string id="msg_page_controls" src="Controls" />
<string id="msg_page_extensions" src="Extensions" />
<!-- Game Page -->
<string id="msg_disk_path" src="Disk Path" />
<string id="msg_cd_path" src="CD Path" />
<string id="msg_save_path" src="Save Path" />
<string id="msg_3d_sound" src="3D Sound" />
<string id="msg_music" src="Music" />
<string id="msg_transition_type" src="Transition Type" />
<string id="msg_transition_none" src="none" />
<string id="msg_transition_dissolve" src="dissolve" />
<string id="msg_transition_mosaic" src="mosaic" />
<string id="msg_transition_wipe_down" src="wipe down" />
<string id="msg_transition_windows" src="windows" />
<!-- Graphics -->
<string id="msg_island_texture_quality" src="Island Texture Quality" />
<string id="msg_texture_fast" src="fast" />
<string id="msg_texture_high" src="high" />
<string id="msg_island_model_quality" src="Island Model Quality" />
<string id="msg_quality_low" src="low" />
<string id="msg_quality_medium" src="medium" />
<string id="msg_quality_high" src="high" />
<string id="msg_max_lod" src="Maximum LOD" />
<string id="msg_max_actors" src="Maximum Actors" />
<string id="msg_msaa" src="MSAA" />
<string id="msg_1x" src="1x" />
<string id="msg_2x" src="2x" />
<string id="msg_4x" src="4x" />
<!-- Controls -->
<string id="msg_touch_control_scheme" src="Touch Control Scheme" />
<string id="msg_virtual_gamepad" src="Virtual Gamepad" />
<string id="msg_virtual_arrow_keys" src="Virtual Arrow Keys" />
<string id="msg_virtual_mouse" src="Virtual Mouse" />
<string id="msg_rumble" src="Rumble" />
<!-- Extensions -->
<string id="msg_texture_loader_extension" src="Texture Loader Extension" />
<string id="msg_texture_loader_path" src="Texture Loader Path" />
<!-- footer -->
<string id="msg_save_exit" src="Save &amp; Exit" />
<string id="msg_save_launch" src="Save &amp; Launch" />
<string id="msg_exit" src="Exit" />
</stringset>

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<application_settings version="1.0" bg_color="4.0, 21.0, 105.0, 255.0">
<setting_list id="lego_island_config" title="msg_lego_island_config">
<setting_list id="page_game" title="msg_page_game" style="edit" icon="tex_spanner">
<text_field id="disk_path" title="msg_disk_path" max_length="255" min_length="0" keyboard_type="alphabet" key="disk_path" default_value=""/>
<text_field id="cd_path" title="msg_cd_path" max_length="255" min_length="0" keyboard_type="alphabet" key="cd_path" default_value=""/>
<text_field id="save_path" title="msg_save_path" max_length="255" min_length="0" keyboard_type="alphabet" key="save_path" default_value=""/>
<list id="transition_type" title="msg_transition_type" key="transition_type" default_value="0">
<list_item id="transition_none" title="msg_transition_none" value="0" />
<list_item id="transition_dissolve" title="msg_transition_dissolve" value="2" />
<list_item id="transition_mosaic" title="msg_transition_mosaic" value="3" />
<list_item id="transition_wipe_down" title="msg_transition_wipe_down" value="4" />
<list_item id="transition_windows" title="msg_transition_windows" value="5" />
</list>
<toggle_switch id="music" title="msg_music" key="music" default_value="1"/>
<toggle_switch id="3d_sound" title="msg_3d_sound" key="3d_sound" default_value="1"/>
</setting_list>
<setting_list id="page_graphics" title="msg_page_graphics" style="edit" icon="tex_spanner">
<list id="island_texture_quality" title="msg_island_texture_quality" key="island_texture_quality" default_value="0">
<list_item id="texture_fast" title="msg_texture_fast" value="0" />
<list_item id="texture_high" title="msg_texture_high" value="1" />
</list>
<list id="island_model_quality" title="msg_island_model_quality" key="island_model_quality" default_value="0">
<list_item id="quality_low" title="msg_quality_low" value="0" />
<list_item id="quality_medium" title="msg_quality_medium" value="1" />
<list_item id="quality_high" title="msg_quality_high" value="2" />
</list>
<list id="msaa" title="msg_msaa" key="msaa" default_value="4">
<list_item id="msaa_1" title="msg_1x" value="1" />
<list_item id="msaa_2" title="msg_2x" value="2" />
<list_item id="msaa_4" title="msg_4x" value="4" />
</list>
</setting_list>
<setting_list id="page_controls" title="msg_page_controls" style="edit" icon="tex_spanner">
<list id="touch_control_scheme" title="msg_touch_control_scheme" key="touch_control_scheme" default_value="0">
<list_item id="virtual_gamepad" title="msg_virtual_gamepad" value="0" />
<list_item id="virtual_arrow_keys" title="msg_virtual_arrow_keys" value="1" />
<list_item id="virtual_mouse" title="msg_virtual_mouse" value="2" />
</list>
<toggle_switch id="rumble" title="msg_rumble" key="rumble" default_value="1"/>
</setting_list>
<setting_list id="page_extensions" title="msg_page_extensions" style="edit" icon="tex_spanner">
<toggle_switch id="texture_loader_extension" title="msg_texture_loader_extension" key="texture_loader_extension" default_value="0"/>
<text_field id="texture_loader_path" title="msg_texture_loader_path" max_length="255" min_length="0" keyboard_type="alphabet" key="texture_loader_path" default_value=""/>
</setting_list>
</setting_list>
</application_settings>

8
CONFIG/vita/exports.yml Normal file
View File

@ -0,0 +1,8 @@
isle-config:
attributes: 0
process_image: true
version:
major: 1
minor: 1
main:
start: module_start

View File

@ -0,0 +1,53 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4f7fdba..d388fc8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.18)
project(
- iniparser
+ iniparser_paf
DESCRIPTION "C library for parsing INI-style files"
HOMEPAGE_URL https://gitlab.com/iniparser/iniparser/
LANGUAGES C
@@ -108,6 +108,19 @@ foreach(TARGET_TYPE ${TARGET_TYPES})
-pedantic)
endif(UNIX)
+ if(VITA)
+ target_compile_options(
+ ${TARGET_NAME}
+ PRIVATE -Wl,-q -Wall -fshort-wchar)
+ target_link_libraries(
+ ${TARGET_NAME}
+ PRIVATE SceLibc_stub
+ )
+ target_link_options(
+ ${TARGET_NAME}
+ PUBLIC -nostartfiles -nostdlib)
+ endif()
+
# install targets
install(
TARGETS ${TARGET_NAME}
diff --git a/src/iniparser.c b/src/iniparser.c
index 1086b46..8e0e9c2 100644
--- a/src/iniparser.c
+++ b/src/iniparser.c
@@ -14,6 +14,15 @@
#include <inttypes.h>
#include "iniparser.h"
+#ifdef __vita__
+extern FILE* _Stderr;
+#undef stderr
+#define stderr _Stderr
+extern const char _Ctype[];
+#undef __locale_ctype_ptr
+#define __locale_ctype_ptr() _Ctype
+#endif
+
/*---------------------------- Defines -------------------------------------*/
#define ASCIILINESZ (1024)
#define INI_INVALID_KEY ((char*)-1)

430
CONFIG/vita/src/app.cpp Normal file
View File

@ -0,0 +1,430 @@
#include <app_settings.h>
#include <iniparser.h>
#include <paf.h>
#include <psp2/appmgr.h>
#include <psp2/io/fcntl.h>
#include <psp2/kernel/clib.h>
#include <psp2/kernel/modulemgr.h>
#include <psp2/sysmodule.h>
int sceLibcHeapSize = 10 * 1024 * 1024;
const char* g_iniPath = "ux0:data/isledecomp/isle/isle.ini";
paf::Framework* g_fw;
paf::Plugin* g_configPlugin;
sce::AppSettings* g_appSettings;
sce::AppSettings::Interface* g_appSetIf;
void merge_dicts(dictionary* dst, dictionary* src)
{
for (int i = 0; i < src->n; i++) {
dictionary_set(dst, src->key[i], src->val[i]);
}
}
struct setting_map {
const char* key_ini;
const char* key_app;
const char type;
};
// mapping from ini key to settings.xml key
const setting_map key_map[] = {
// Game
{"isle:diskpath", "disk_path", 's'},
{"isle:cdpath", "cd_path", 's'},
{"isle:savepath", "save_path", 's'},
{"isle:Transition Type", "transition_type", 'i'},
{"isle:Music", "music", 'b'},
{"isle:3DSound", "3d_sound", 'b'},
// Graphics
{"isle:Island Texture", "island_texture_quality", 'i'},
{"isle:Island Quality", "island_model_quality", 'i'},
//{"isle:Max LOD", "max_lod", 'f'},
//{"isle:Max Allowed Extras", "max_extras", 'i' },
{"isle:MSAA", "msaa", 'i'},
// Controls
{"isle:Touch Scheme", "touch_control_scheme", 'i'},
{"isle:Haptic", "rumble", 'b'},
// Extensions
{"extensions:texture loader", "texture_loader_extension", 'b'},
{"texture loader:texture path", "texture_loader_path", 's'}
};
struct Config {
sce::AppSettings* settings;
dictionary* dict;
char buffer[128];
#define GetDictInt(x, name) x = iniparser_getint(this->dict, name, x)
#define GetDictFloat(x, name) x = iniparser_getdouble(this->dict, name, x)
#define GetDictString(x, name) \
{ \
const char* val = iniparser_getstring(this->dict, name, nullptr); \
if (val != nullptr) { \
x = val; \
} \
}
#define GetDictBool(x, name) x = iniparser_getboolean(this->dict, name, x)
#define SetDictBool(NAME, VALUE) \
{ \
const char* v = VALUE ? "true" : "false"; \
sceClibPrintf("SetIniBool(%s, %s)\n", NAME, v); \
iniparser_set(this->dict, NAME, v); \
}
#define SetDictInt(NAME, VALUE) \
{ \
sceClibSnprintf(buffer, sizeof(buffer), "%d", VALUE); \
sceClibPrintf("SetIniInt(%s, %d)\n", NAME, VALUE); \
iniparser_set(this->dict, NAME, buffer); \
}
#define SetDictFloat(NAME, VALUE) \
{ \
sceClibSnprintf(buffer, sizeof(buffer), "%f", VALUE); \
sceClibPrintf("SetIniFloat(%s, %f)\n", NAME, VALUE); \
iniparser_set(this->dict, NAME, buffer); \
}
#define SetDictString(NAME, VALUE) \
{ \
sceClibPrintf("SetString(%s, %s)\n", NAME, VALUE); \
iniparser_set(this->dict, NAME, VALUE); \
}
void Init(sce::AppSettings* settings)
{
this->settings = settings;
dict = dictionary_new(0);
// set defaults
iniparser_set(this->dict, "isle", nullptr);
iniparser_set(dict, "extensions", NULL);
iniparser_set(this->dict, "texture loader", nullptr);
SetDictString("isle:diskpath", "ux0:data/isledecomp/isle/disk");
SetDictString("isle:cdpath", "ux0:data/isledecomp/isle/cd");
SetDictString("isle:savepath", "ux0:data/isledecomp/isle");
SetDictInt("isle:MSAA", 4);
SetDictInt("isle:Display Bit Depth", 32);
SetDictBool("isle:Flip Surfaces", false);
SetDictBool("isle:Full Screen", true);
SetDictBool("isle:Exclusive Full Screen", true);
SetDictBool("isle:Wide View Angle", true);
SetDictInt("isle:Transition Type", 3); // 3: Mosaic
SetDictInt("isle:Touch Scheme", 2);
SetDictBool("isle:3DSound", true);
SetDictBool("isle:Music", true);
SetDictBool("isle:Haptic", true);
SetDictBool("isle:UseJoystick", true);
SetDictInt("isle:JoystickIndex", 0);
SetDictBool("isle:Draw Cursor", true);
SetDictBool("extensions:texture loader", false);
SetDictString("texture loader:texture path", "textures/");
SetDictBool("isle:Back Buffers in Video RAM", true);
SetDictInt("isle:Island Quality", 2);
SetDictInt("isle:Island Texture", 1);
SetDictInt("isle:MSAA", 4);
SetDictFloat("isle:Max LOD", 3.5);
SetDictInt("isle:Max Allowed Extras", 20);
SetDictInt("isle:Aspect Ratio", 0);
SetDictInt("isle:Horizontal Resolution", 640);
SetDictInt("isle:Vertical Resolution", 480);
SetDictFloat("isle:Frame Delta", 10.0f);
}
void LoadIni()
{
dictionary* ini = iniparser_load(g_iniPath);
if (ini) {
merge_dicts(this->dict, ini);
iniparser_freedict(ini);
}
}
bool SaveIni()
{
FILE* fd = fopen(g_iniPath, "w");
if (fd) {
iniparser_dump_ini(this->dict, fd);
}
else {
sceClibPrintf("failed to write isle.ini\n");
}
return true;
}
void ToSettings()
{
const int len = sizeof(key_map) / sizeof(key_map[0]);
for (int i = 0; i < len; i++) {
const setting_map m = key_map[i];
switch (m.type) {
case 'f': // float, AppSettings doesnt have float so just use string
case 's': {
const char* value = iniparser_getstring(this->dict, m.key_ini, "");
this->settings->SetString(m.key_app, value);
sceClibPrintf("ini->settings %s = %s\n", m.key_app, value);
break;
}
case 'i': {
int32_t value = iniparser_getint(this->dict, m.key_ini, 0);
this->settings->SetInt(m.key_app, value);
sceClibPrintf("ini->settings %s = %d\n", m.key_app, value);
break;
}
case 'b': {
bool value = iniparser_getboolean(this->dict, m.key_ini, 0) == 1;
this->settings->SetBool(m.key_app, value);
sceClibPrintf("ini->settings %s = %s\n", m.key_app, value ? "true" : "false");
break;
}
default: {
sceClibPrintf("invalid setting map entry %s %s %c\n", m.key_app, m.key_ini, m.type);
}
}
}
}
void FromSettings()
{
const int len = sizeof(key_map) / sizeof(key_map[0]);
for (int i = 0; i < len; i++) {
const setting_map m = key_map[i];
switch (m.type) {
case 'f': // float, AppSettings doesnt have float so just use string
case 's': {
const char* def = iniparser_getstring(this->dict, m.key_ini, "");
this->settings->GetString(m.key_app, this->buffer, sizeof(this->buffer), def);
iniparser_set(this->dict, m.key_ini, buffer);
sceClibPrintf("settings->ini %s = %s\n", m.key_ini, buffer);
break;
}
case 'i': {
int32_t value = iniparser_getint(this->dict, m.key_ini, 0);
this->settings->GetInt(m.key_app, &value, value);
SetDictInt(m.key_ini, value);
sceClibPrintf("settings->ini %s = %d\n", m.key_ini, value);
break;
}
case 'b': {
bool value = iniparser_getboolean(this->dict, m.key_ini, 0) == 1;
this->settings->GetBool(m.key_app, &value, value);
SetDictBool(m.key_ini, value);
sceClibPrintf("settings->ini %s = %s\n", m.key_ini, value ? "true" : "false");
break;
}
default: {
sceClibPrintf("invalid setting map entry %s %s %c\n", m.key_app, m.key_ini, m.type);
}
}
}
}
};
Config g_config;
paf::Plugin* load_config_plugin(paf::Framework* paf_fw)
{
paf::Plugin::InitParam pluginParam;
pluginParam.name = "config_plugin";
pluginParam.caller_name = "__main__";
pluginParam.resource_file = "app0:/config_plugin.rco";
pluginParam.init_func = NULL;
pluginParam.start_func = NULL;
pluginParam.stop_func = NULL;
pluginParam.exit_func = NULL;
paf::Plugin::LoadSync(pluginParam);
return paf_fw->FindPlugin("config_plugin");
}
int load_app_settings_plugin()
{
paf::Plugin::InitParam pluginParam;
sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_INTERNAL_BXCE);
sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_INTERNAL_INI_FILE_PROCESSOR);
sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_INTERNAL_COMMON_GUI_DIALOG);
pluginParam.name = "app_settings_plugin";
pluginParam.resource_file = "vs0:vsh/common/app_settings_plugin.rco";
pluginParam.caller_name = "__main__";
pluginParam.set_param_func = sce::AppSettings::PluginSetParamCB;
pluginParam.init_func = sce::AppSettings::PluginInitCB;
pluginParam.start_func = sce::AppSettings::PluginStartCB;
pluginParam.stop_func = sce::AppSettings::PluginStopCB;
pluginParam.exit_func = sce::AppSettings::PluginExitCB;
pluginParam.module_file = "vs0:vsh/common/app_settings.suprx";
pluginParam.draw_priority = 0x96;
paf::Plugin::LoadSync(pluginParam);
return 0;
}
int exit_type = 0;
void save_and_exit()
{
g_config.FromSettings();
g_config.SaveIni();
g_fw->RequestShutdown();
exit_type = 1;
}
void save_and_launch()
{
g_config.FromSettings();
g_config.SaveIni();
g_fw->RequestShutdown();
exit_type = 2;
}
void CBOnStartPageTransition(const char* elementId, int32_t type)
{
}
void CBOnPageActivate(const char* elementId, int32_t type)
{
}
void CBOnPageDeactivate(const char* elementId, int32_t type)
{
}
int32_t CBOnCheckVisible(const char* elementId, bool* pIsVisible)
{
*pIsVisible = true;
return SCE_OK;
}
int32_t CBOnPreCreate(const char* elementId, sce::AppSettings::Element* element)
{
return SCE_OK;
}
int32_t CBOnPostCreate(const char* elementId, paf::ui::Widget* widget)
{
return SCE_OK;
}
int32_t CBOnPress(const char* elementId, const char* newValue)
{
if (sce_paf_strcmp(elementId, "save_exit_button") == 0) {
save_and_exit();
return SCE_OK;
}
if (sce_paf_strcmp(elementId, "save_launch_button") == 0) {
save_and_launch();
return SCE_OK;
}
sceClibPrintf("OnPress %s %s\n", elementId, newValue);
return SCE_OK;
}
int32_t CBOnPress2(const char* elementId, const char* newValue)
{
return SCE_OK;
}
void CBOnTerm(int32_t result)
{
if (exit_type == 0) {
sceKernelExitProcess(0);
}
}
const wchar_t* CBOnGetString(const char* elementId)
{
wchar_t* res = g_configPlugin->GetString(elementId);
if (res[0] != 0) {
return res;
}
return L"unknown string";
}
int32_t CBOnGetSurface(paf::graph::Surface** surf, const char* elementId)
{
return SCE_OK;
}
void open_settings()
{
g_config.Init(g_appSettings);
g_config.LoadIni();
g_config.ToSettings();
sce::AppSettings::InterfaceCallbacks ifCb;
ifCb.onStartPageTransitionCb = CBOnStartPageTransition;
ifCb.onPageActivateCb = CBOnPageActivate;
ifCb.onPageDeactivateCb = CBOnPageDeactivate;
ifCb.onCheckVisible = CBOnCheckVisible;
ifCb.onPreCreateCb = CBOnPreCreate;
ifCb.onPostCreateCb = CBOnPostCreate;
ifCb.onPressCb = CBOnPress;
ifCb.onPressCb2 = CBOnPress2;
ifCb.onTermCb = CBOnTerm;
ifCb.onGetStringCb = (sce::AppSettings::InterfaceCallbacks::GetStringCallback) CBOnGetString;
ifCb.onGetSurfaceCb = CBOnGetSurface;
paf::wstring msg_save_exit(g_configPlugin->GetString("msg_save_exit"));
paf::wstring msg_save_launch(g_configPlugin->GetString("msg_save_launch"));
paf::wstring msg_exit(g_configPlugin->GetString("msg_exit"));
paf::Plugin* appSetPlug = paf::Plugin::Find("app_settings_plugin");
g_appSetIf = (sce::AppSettings::Interface*) appSetPlug->GetInterface(1);
g_appSetIf->Show(&ifCb);
g_appSetIf->AddFooterButton("save_exit_button", &msg_save_exit, 1);
g_appSetIf->AddFooterButton("save_launch_button", &msg_save_launch, 2);
g_appSetIf->ShowFooter();
}
int main()
{
paf::Framework::InitParam fwParam;
fwParam.mode = paf::Framework::Mode_Normal;
paf::Framework* paf_fw = new paf::Framework(fwParam);
g_fw = paf_fw;
paf_fw->LoadCommonResourceSync();
load_app_settings_plugin();
paf::Plugin* configPlugin = load_config_plugin(paf_fw);
g_configPlugin = configPlugin;
configPlugin->SetLocale(Locale_EN);
size_t fileSize = 0;
const char* mimeType = nullptr;
auto settingsXmlFile = configPlugin->GetResource()->GetFile("settings.xml", &fileSize, &mimeType);
sce::AppSettings::InitParam settingsParam;
settingsParam.xml_file = settingsXmlFile;
settingsParam.alloc_cb = sce_paf_malloc;
settingsParam.free_cb = sce_paf_free;
settingsParam.realloc_cb = sce_paf_realloc;
settingsParam.safemem_offset = 0;
settingsParam.safemem_size = 0x400;
sce::AppSettings::GetInstance(settingsParam, &g_appSettings);
g_appSettings->Initialize();
open_settings();
paf_fw->Run();
if (exit_type == 2) {
int ret = sceAppMgrLoadExec("app0:/eboot.bin", NULL, NULL);
printf("sceAppMgrLoadExec: %08x\n", ret);
}
return 0;
}

View File

@ -0,0 +1,169 @@
#include <paf.h>
#include <psp2/kernel/clib.h>
#include <psp2/kernel/modulemgr.h>
#include <psp2/kernel/processmgr.h>
#include <psp2/sysmodule.h>
char sceUserMainThreadName[] = "isle_config";
int sceUserMainThreadPriority = 0x10000100;
int sceUserMainThreadCpuAffinityMask = 0x70000;
SceSize sceUserMainThreadStackSize = 0x4000;
void operator delete(void* ptr, unsigned int n)
{
return sce_paf_free(ptr);
}
extern "C"
{
void user_malloc_init()
{
}
void user_malloc_finalize(void)
{
}
void* user_malloc(size_t size)
{
return sce_paf_malloc(size);
}
void user_free(void* ptr)
{
sce_paf_free(ptr);
}
void* user_calloc(size_t nelem, size_t size)
{
return sce_paf_calloc(nelem, size);
}
void* user_realloc(void* ptr, size_t new_size)
{
return sce_paf_realloc(ptr, new_size);
}
void* user_memalign(size_t boundary, size_t size)
{
return sce_paf_memalign(boundary, size);
}
void* user_reallocalign(void* ptr, size_t size, size_t boundary)
{
sceClibPrintf("[PAF2LIBC] reallocalign is not supported\n");
abort();
return NULL;
}
int user_malloc_stats(struct malloc_managed_size* mmsize)
{
sceClibPrintf("malloc_stats\n");
abort();
return 0;
}
int user_malloc_stats_fast(struct malloc_managed_size* mmsize)
{
sceClibPrintf("user_malloc_stats_fast\n");
abort();
return 0;
}
size_t user_malloc_usable_size(void* ptr)
{
return sce_paf_musable_size(ptr);
}
}
void* user_new(std::size_t size)
{
return sce_paf_malloc(size);
}
void* user_new(std::size_t size, const std::nothrow_t& x)
{
return sce_paf_malloc(size);
}
void* user_new_array(std::size_t size)
{
return sce_paf_malloc(size);
}
void* user_new_array(std::size_t size, const std::nothrow_t& x)
{
return sce_paf_malloc(size);
}
void user_delete(void* ptr)
{
sce_paf_free(ptr);
}
void user_delete(void* ptr, const std::nothrow_t& x)
{
sce_paf_free(ptr);
}
void user_delete_array(void* ptr)
{
sce_paf_free(ptr);
}
void user_delete_array(void* ptr, const std::nothrow_t& x)
{
sce_paf_free(ptr);
}
int paf_init()
{
int load_res;
ScePafInit init_param;
SceSysmoduleOpt sysmodule_opt;
init_param.global_heap_size = 0x1000000;
init_param.cdlg_mode = 0;
init_param.global_heap_alignment = 0;
init_param.global_heap_disable_assert_on_alloc_failure = 0;
load_res = 0xDEADBEEF;
sysmodule_opt.flags = 0;
sysmodule_opt.result = &load_res;
int res = sceSysmoduleLoadModuleInternalWithArg(
SCE_SYSMODULE_INTERNAL_PAF,
sizeof(init_param),
&init_param,
&sysmodule_opt
);
if ((res | load_res) != 0) {
sceClibPrintf(
"[PAF PRX Loader] Failed to load the PAF prx. (return value 0x%x, result code 0x%x )\n",
res,
load_res
);
return -1;
}
return 0;
}
int main();
extern "C" int module_start(SceSize args, void* argp)
{
int res = paf_init();
if (res < 0) {
sceKernelExitProcess(res);
return SCE_KERNEL_START_FAILED;
}
res = main();
sceKernelExitProcess(res);
return SCE_KERNEL_START_SUCCESS;
}
extern "C" void _start()
{
module_start(0, nullptr);
}

View File

@ -77,6 +77,14 @@
#include "android/config.h"
#endif
#ifdef __vita__
#include "vita/config.h"
#include "vita/messagebox.h"
#include <psp2/appmgr.h>
#include <psp2/kernel/clib.h>
#endif
DECOMP_SIZE_ASSERT(IsleApp, 0x8c)
// GLOBAL: ISLE 0x410030
@ -316,6 +324,23 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv)
// Create global app instance
g_isle = new IsleApp();
#ifdef __vita__
SceAppUtilInitParam appUtilInitParam = {0};
SceAppUtilBootParam appUtilBootParam = {0};
sceAppUtilInit(&appUtilInitParam, &appUtilBootParam);
SceAppUtilAppEventParam eventParam = {0};
sceAppUtilReceiveAppEvent(&eventParam);
if (eventParam.type == 0x05) {
g_isle->LoadConfig();
char buffer[2048];
sceAppUtilAppEventParseLiveArea(&eventParam, buffer);
if (strstr(buffer, "-config")) {
sceClibPrintf("Loading Config App.\n");
sceAppMgrLoadExec("app0:/isle-config.self", NULL, NULL);
}
}
#endif
switch (g_isle->ParseArguments(argc, argv)) {
case SDL_APP_FAILURE:
Any_ShowSimpleMessageBox(
@ -452,6 +477,19 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
break;
}
#ifdef __vita__
// reject back touch panel
switch (event->type) {
case SDL_EVENT_FINGER_MOTION:
case SDL_EVENT_FINGER_DOWN:
case SDL_EVENT_FINGER_UP:
case SDL_EVENT_FINGER_CANCELED:
if (event->tfinger.touchID == 2) {
return SDL_APP_CONTINUE;
}
}
#endif
switch (event->type) {
case SDL_EVENT_WINDOW_FOCUS_GAINED:
if (!IsleDebug_Enabled()) {
@ -556,7 +594,11 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
}
break;
#ifdef __vita__ // conflicts with screenshot button combination
case SDL_GAMEPAD_BUTTON_BACK:
#else
case SDL_GAMEPAD_BUTTON_START:
#endif
if (InputManager()) {
InputManager()->QueueEvent(c_notificationKeyPress, SDLK_ESCAPE, 0, 0, SDLK_ESCAPE);
}
@ -884,7 +926,7 @@ MxResult IsleApp::SetupWindow()
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, g_targetHeight);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, m_fullScreen);
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, WINDOW_TITLE);
#if defined(MINIWIN) && !defined(__3DS__) && !defined(WINDOWS_STORE)
#if defined(MINIWIN) && !defined(__3DS__) && !defined(WINDOWS_STORE) && !defined(__vita__)
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
@ -1110,6 +1152,9 @@ bool IsleApp::LoadConfig()
Android_SetupDefaultConfigOverrides(dict);
#endif
#ifdef __vita__
VITA_SetupDefaultConfigOverrides(dict);
#endif
iniparser_dump_ini(dict, iniFP);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "New config written at '%s'", iniConfig.GetData());
fclose(iniFP);

13
ISLE/vita/config.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "config.h"
#include <SDL3/SDL_log.h>
#include <iniparser.h>
void VITA_SetupDefaultConfigOverrides(dictionary* p_dictionary)
{
SDL_Log("Overriding default config for VITA");
iniparser_set(p_dictionary, "isle:diskpath", "ux0:data/isledecomp/isle/disk");
iniparser_set(p_dictionary, "isle:cdpath", "ux0:data/isledecomp/isle/cd");
iniparser_set(p_dictionary, "isle:MSAA", "4");
}

8
ISLE/vita/config.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef VITA_CONFIG_H
#define VITA_CONFIG_H
#include "dictionary.h"
void VITA_SetupDefaultConfigOverrides(dictionary* p_dictionary);
#endif // VITA_CONFIG_H

52
ISLE/vita/messagebox.cpp Normal file
View File

@ -0,0 +1,52 @@
#include "messagebox.h"
#include "../../miniwin/src/d3drm/backends/gxm/gxm_context.h"
#include <psp2/common_dialog.h>
#include <psp2/message_dialog.h>
bool Vita_ShowSimpleMessageBox(SDL_MessageBoxFlags flags, const char* title, const char* message, SDL_Window* window)
{
int ret;
SceMsgDialogParam param;
SceMsgDialogUserMessageParam msgParam;
SceMsgDialogButtonsParam buttonParam;
SceMsgDialogResult dialog_result;
SceCommonDialogErrorCode init_result;
bool setup_minimal_gxm = false;
SDL_zero(param);
sceMsgDialogParamInit(&param);
param.mode = SCE_MSG_DIALOG_MODE_USER_MSG;
SDL_zero(msgParam);
char message_data[0x1000];
SDL_snprintf(message_data, sizeof(message_data), "%s\r\n\r\n%s", title, message);
msgParam.msg = (const SceChar8*) message_data;
msgParam.buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_OK;
param.userMsgParam = &msgParam;
if (!gxm) {
gxm = (GXMContext*) SDL_malloc(sizeof(GXMContext));
}
if (ret = gxm->init(SCE_GXM_MULTISAMPLE_NONE); ret < 0) {
return false;
}
init_result = (SceCommonDialogErrorCode) sceMsgDialogInit(&param);
if (init_result >= 0) {
while (sceMsgDialogGetStatus() == SCE_COMMON_DIALOG_STATUS_RUNNING) {
gxm->clear(0, 0, 0, true);
gxm->swap_display();
}
SDL_zero(dialog_result);
sceMsgDialogGetResult(&dialog_result);
sceMsgDialogTerm();
return dialog_result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_OK;
}
else {
return false;
}
return true;
}

8
ISLE/vita/messagebox.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef VITA_MESSAGE_BOX_H
#define VITA_MESSAGE_BOX_H
#include <SDL3/SDL_messagebox.h>
bool Vita_ShowSimpleMessageBox(SDL_MessageBoxFlags flags, const char* title, const char* message, SDL_Window* window);
#endif // VITA_MESSAGE_BOX_H

View File

@ -18,6 +18,7 @@ Please note: this project is primarily dedicated to achieving platform independe
| Xbox One | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) |
| iOS | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) |
| Android | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) |
| Playstation Vita | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) |
We are actively working to support more platforms. If you have experience with a particular platform, we encourage you to contribute to `isle-portable`. You can find a [list of ongoing efforts](https://github.com/isledecomp/isle-portable/wiki/Work%E2%80%90in%E2%80%90progress-ports) in our Wiki.

View File

@ -30,7 +30,7 @@ target_compile_definitions(miniwin PRIVATE
list(APPEND GRAPHICS_BACKENDS USE_SOFTWARE_RENDER)
list(APPEND GRAPHICS_BACKENDS USE_SDL_GPU)
if(NOT WINDOWS_STORE)
if(NOT (VITA OR WINDOWS_STORE))
find_package(OpenGL)
if(OpenGL_FOUND)
message(STATUS "Found OpenGL: enabling OpenGL 1.x renderer")
@ -69,6 +69,25 @@ if(NOT WINDOWS_STORE)
endif()
endif()
if(VITA)
add_subdirectory(src/d3drm/backends/gxm/shaders)
target_sources(miniwin PRIVATE
src/d3drm/backends/gxm/gxm_context.cpp
src/d3drm/backends/gxm/gxm_renderer.cpp
src/d3drm/backends/gxm/gxm_memory.cpp
src/d3drm/backends/gxm/tlsf.c
)
target_link_libraries(miniwin PRIVATE
SceGxm_stub
SceRazorCapture_stub
SceRazorHud_stub
taihen_stub
gxm_shaders
)
list(APPEND GRAPHICS_BACKENDS USE_GXM)
list(REMOVE_ITEM GRAPHICS_BACKENDS USE_SOFTWARE_RENDER USE_SDL_GPU)
endif()
if(NINTENDO_3DS)
if(ISLE_DEBUG)

View File

@ -0,0 +1,680 @@
#include "gxm_context.h"
#include "gxm_memory.h"
#include "shaders/gxm_shaders.h"
#include "tlsf.h"
#include "utils.h"
#include <SDL3/SDL.h>
#include <psp2/common_dialog.h>
#include <psp2/display.h>
#include <psp2/gxm.h>
#include <psp2/kernel/sysmem.h>
static bool gxm_initialized = false;
bool with_razor_capture;
bool with_razor_hud;
#define CDRAM_POOL_SIZE 64 * 1024 * 1024
#define VITA_GXM_COLOR_FORMAT SCE_GXM_COLOR_FORMAT_A8B8G8R8
typedef struct GXMDisplayData {
void* address;
int index;
} GXMDisplayData;
static void display_callback(const void* callback_data)
{
const GXMDisplayData* display_data = (const GXMDisplayData*) callback_data;
SceDisplayFrameBuf framebuf;
SDL_memset(&framebuf, 0x00, sizeof(SceDisplayFrameBuf));
framebuf.size = sizeof(SceDisplayFrameBuf);
framebuf.base = display_data->address;
framebuf.pitch = VITA_GXM_SCREEN_STRIDE;
framebuf.pixelformat = VITA_GXM_PIXEL_FORMAT;
framebuf.width = VITA_GXM_SCREEN_WIDTH;
framebuf.height = VITA_GXM_SCREEN_HEIGHT;
sceDisplaySetFrameBuf(&framebuf, SCE_DISPLAY_SETBUF_NEXTFRAME);
sceDisplayWaitSetFrameBuf();
}
#ifdef GXM_WITH_RAZOR
static int load_suprx(const char* name)
{
sceClibPrintf("loading %s\n", name);
int modid = _sceKernelLoadModule(name, 0, nullptr);
if (modid < 0) {
sceClibPrintf("%s load: 0x%08x\n", name, modid);
return modid;
}
int status;
int ret = sceKernelStartModule(modid, 0, nullptr, 0, nullptr, &status);
if (ret < 0) {
sceClibPrintf("%s start: 0x%08x\n", name, ret);
}
return ret;
}
static void load_razor()
{
with_razor_capture = false;
with_razor_hud = false;
if (load_suprx("app0:librazorcapture_es4.suprx") >= 0) {
with_razor_capture = true;
}
if (with_razor_capture) {
// sceRazorGpuCaptureEnableSalvage("ux0:data/gpu_crash.sgx");
}
if (with_razor_hud) {
sceRazorGpuTraceSetFilename("ux0:data/gpu_trace", 3);
}
}
#endif
int gxm_library_init()
{
if (gxm_initialized) {
return 0;
}
#ifdef GXM_WITH_RAZOR
load_razor();
#endif
SceGxmInitializeParams initializeParams;
SDL_memset(&initializeParams, 0, sizeof(SceGxmInitializeParams));
initializeParams.flags = 0;
initializeParams.displayQueueMaxPendingCount = VITA_GXM_PENDING_SWAPS;
initializeParams.displayQueueCallback = display_callback;
initializeParams.displayQueueCallbackDataSize = sizeof(GXMDisplayData);
initializeParams.parameterBufferSize = SCE_GXM_DEFAULT_PARAMETER_BUFFER_SIZE;
int err = sceGxmInitialize(&initializeParams);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "gxm init failed: %d", err);
return err;
}
gxm_initialized = true;
return 0;
}
GXMContext* gxm;
void GXMContext::init_cdram_allocator()
{
// allocator
this->cdramMem = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
CDRAM_POOL_SIZE,
16,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&this->cdramUID,
"cdram_pool"
);
this->cdramPool = SDL_malloc(tlsf_size());
tlsf_create(this->cdramPool);
tlsf_add_pool(this->cdramPool, this->cdramMem, CDRAM_POOL_SIZE);
}
int GXMContext::init_context()
{
int ret;
const unsigned int patcherBufferSize = 64 * 1024;
const unsigned int patcherVertexUsseSize = 64 * 1024;
const unsigned int patcherFragmentUsseSize = 64 * 1024;
// allocate buffers
this->vdmRingBuffer = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE,
4,
SCE_GXM_MEMORY_ATTRIB_READ,
&this->vdmRingBufferUid,
"vdmRingBuffer"
);
this->vertexRingBuffer = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE,
4,
SCE_GXM_MEMORY_ATTRIB_READ,
&this->vertexRingBufferUid,
"vertexRingBuffer"
);
this->fragmentRingBuffer = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE,
4,
SCE_GXM_MEMORY_ATTRIB_READ,
&this->fragmentRingBufferUid,
"fragmentRingBuffer"
);
this->fragmentUsseRingBuffer = vita_mem_fragment_usse_alloc(
SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE,
&this->fragmentUsseRingBufferUid,
&this->fragmentUsseRingBufferOffset
);
// create context
SceGxmContextParams contextParams;
memset(&contextParams, 0, sizeof(SceGxmContextParams));
contextParams.hostMem = SDL_malloc(SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE);
contextParams.hostMemSize = SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE;
contextParams.vdmRingBufferMem = this->vdmRingBuffer;
contextParams.vdmRingBufferMemSize = SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE;
contextParams.vertexRingBufferMem = this->vertexRingBuffer;
contextParams.vertexRingBufferMemSize = SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE;
contextParams.fragmentRingBufferMem = this->fragmentRingBuffer;
contextParams.fragmentRingBufferMemSize = SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE;
contextParams.fragmentUsseRingBufferMem = this->fragmentUsseRingBuffer;
contextParams.fragmentUsseRingBufferMemSize = SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE;
contextParams.fragmentUsseRingBufferOffset = this->fragmentUsseRingBufferOffset;
ret = SCE_ERR(sceGxmCreateContext, &contextParams, &this->context);
if (ret < 0) {
return ret;
}
this->contextHostMem = contextParams.hostMem;
// shader patcher
this->patcherBuffer = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
patcherBufferSize,
4,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&this->patcherBufferUid,
"patcherBuffer"
);
this->patcherVertexUsse =
vita_mem_vertex_usse_alloc(patcherVertexUsseSize, &this->patcherVertexUsseUid, &this->patcherVertexUsseOffset);
this->patcherFragmentUsse = vita_mem_fragment_usse_alloc(
patcherFragmentUsseSize,
&this->patcherFragmentUsseUid,
&this->patcherFragmentUsseOffset
);
SceGxmShaderPatcherParams patcherParams;
memset(&patcherParams, 0, sizeof(SceGxmShaderPatcherParams));
patcherParams.userData = NULL;
patcherParams.hostAllocCallback = &patcher_host_alloc;
patcherParams.hostFreeCallback = &patcher_host_free;
patcherParams.bufferAllocCallback = NULL;
patcherParams.bufferFreeCallback = NULL;
patcherParams.bufferMem = this->patcherBuffer;
patcherParams.bufferMemSize = patcherBufferSize;
patcherParams.vertexUsseAllocCallback = NULL;
patcherParams.vertexUsseFreeCallback = NULL;
patcherParams.vertexUsseMem = this->patcherVertexUsse;
patcherParams.vertexUsseMemSize = patcherVertexUsseSize;
patcherParams.vertexUsseOffset = this->patcherVertexUsseOffset;
patcherParams.fragmentUsseAllocCallback = NULL;
patcherParams.fragmentUsseFreeCallback = NULL;
patcherParams.fragmentUsseMem = this->patcherFragmentUsse;
patcherParams.fragmentUsseMemSize = patcherFragmentUsseSize;
patcherParams.fragmentUsseOffset = this->patcherFragmentUsseOffset;
ret = SCE_ERR(sceGxmShaderPatcherCreate, &patcherParams, &this->shaderPatcher);
if (ret < 0) {
return ret;
}
return 0;
}
int GXMContext::create_display_buffers(SceGxmMultisampleMode msaaMode)
{
int ret;
const uint32_t alignedWidth = ALIGN(VITA_GXM_SCREEN_WIDTH, SCE_GXM_TILE_SIZEX);
const uint32_t alignedHeight = ALIGN(VITA_GXM_SCREEN_HEIGHT, SCE_GXM_TILE_SIZEY);
uint32_t sampleCount = alignedWidth * alignedHeight;
uint32_t depthStrideInSamples = alignedWidth;
if (msaaMode == SCE_GXM_MULTISAMPLE_4X) {
sampleCount *= 4;
depthStrideInSamples *= 2;
}
else if (msaaMode == SCE_GXM_MULTISAMPLE_2X) {
sampleCount *= 2;
}
// render target
SceGxmRenderTargetParams renderTargetParams;
memset(&renderTargetParams, 0, sizeof(SceGxmRenderTargetParams));
renderTargetParams.flags = 0;
renderTargetParams.width = VITA_GXM_SCREEN_WIDTH;
renderTargetParams.height = VITA_GXM_SCREEN_HEIGHT;
renderTargetParams.scenesPerFrame = 1;
renderTargetParams.multisampleMode = msaaMode;
renderTargetParams.multisampleLocations = 0;
renderTargetParams.driverMemBlock = -1; // Invalid UID
ret = SCE_ERR(sceGxmCreateRenderTarget, &renderTargetParams, &this->renderTarget);
if (ret < 0) {
return ret;
}
this->renderTargetInit = true;
for (int i = 0; i < GXM_DISPLAY_BUFFER_COUNT; i++) {
this->displayBuffers[i] = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT,
SCE_GXM_COLOR_SURFACE_ALIGNMENT,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&this->displayBuffersUid[i],
"displayBuffers"
);
ret = SCE_ERR(
sceGxmColorSurfaceInit,
&this->displayBuffersSurface[i],
SCE_GXM_COLOR_FORMAT_A8B8G8R8,
SCE_GXM_COLOR_SURFACE_LINEAR,
(msaaMode == SCE_GXM_MULTISAMPLE_NONE) ? SCE_GXM_COLOR_SURFACE_SCALE_NONE
: SCE_GXM_COLOR_SURFACE_SCALE_MSAA_DOWNSCALE,
SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT,
VITA_GXM_SCREEN_WIDTH,
VITA_GXM_SCREEN_HEIGHT,
VITA_GXM_SCREEN_STRIDE,
this->displayBuffers[i]
);
if (ret < 0) {
return ret;
}
ret = SCE_ERR(sceGxmSyncObjectCreate, &this->displayBuffersSync[i]);
if (ret < 0) {
return ret;
}
}
// depth & stencil
this->depthBufferData = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
4 * sampleCount,
SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&this->depthBufferUid,
"depthBufferData"
);
this->stencilBufferData = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
1 * sampleCount,
SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&this->stencilBufferUid,
"stencilBufferData"
);
ret = SCE_ERR(
sceGxmDepthStencilSurfaceInit,
&this->depthSurface,
SCE_GXM_DEPTH_STENCIL_FORMAT_DF32_S8,
SCE_GXM_DEPTH_STENCIL_SURFACE_TILED,
depthStrideInSamples,
this->depthBufferData,
this->stencilBufferData
);
if (ret < 0) {
return ret;
}
return 0;
}
void GXMContext::destroy_display_buffers()
{
if (this->renderTargetInit) {
sceGxmFinish(this->context);
sceGxmDestroyRenderTarget(this->renderTarget);
this->renderTargetInit = false;
}
for (int i = 0; i < GXM_DISPLAY_BUFFER_COUNT; i++) {
if (this->displayBuffers[i]) {
vita_mem_free(this->displayBuffersUid[i]);
this->displayBuffers[i] = nullptr;
this->displayBuffersUid[i] = -1;
sceGxmSyncObjectDestroy(this->displayBuffersSync[i]);
}
}
if (this->depthBufferData) {
vita_mem_free(this->depthBufferUid);
this->depthBufferData = nullptr;
this->depthBufferUid = -1;
}
if (this->stencilBufferData) {
vita_mem_free(this->stencilBufferUid);
this->stencilBufferData = nullptr;
this->stencilBufferUid = -1;
}
}
void GXMContext::init_clear_mesh()
{
this->clearVertices = static_cast<GXMVertex2D*>(this->alloc(sizeof(GXMVertex2D) * 4, 4));
this->clearVertices[0] = {.position = {-1.0, 1.0}, .texCoord = {0, 0}};
this->clearVertices[1] = {.position = {1.0, 1.0}, .texCoord = {0, 0}};
this->clearVertices[2] = {.position = {-1.0, -1.0}, .texCoord = {0, 0}};
this->clearVertices[3] = {.position = {1.0, -1.0}, .texCoord = {0, 0}};
this->clearIndices = static_cast<uint16_t*>(this->alloc(sizeof(uint16_t) * 4, 4));
this->clearIndices[0] = 0;
this->clearIndices[1] = 1;
this->clearIndices[2] = 2;
this->clearIndices[3] = 3;
}
int GXMContext::register_base_shaders()
{
int ret;
// register plane, color, image shaders
ret = SCE_ERR(
sceGxmShaderPatcherRegisterProgram,
this->shaderPatcher,
planeVertexProgramGxp,
&this->planeVertexProgramId
);
if (ret < 0) {
return ret;
}
ret = SCE_ERR(
sceGxmShaderPatcherRegisterProgram,
this->shaderPatcher,
colorFragmentProgramGxp,
&this->colorFragmentProgramId
);
if (ret < 0) {
return ret;
}
ret = SCE_ERR(
sceGxmShaderPatcherRegisterProgram,
this->shaderPatcher,
imageFragmentProgramGxp,
&this->imageFragmentProgramId
);
if (ret < 0) {
return ret;
}
this->color_uColor = sceGxmProgramFindParameterByName(colorFragmentProgramGxp, "uColor"); // vec4
return 0;
}
int GXMContext::patch_base_shaders(SceGxmMultisampleMode msaaMode)
{
int ret;
{
GET_SHADER_PARAM(positionAttribute, planeVertexProgramGxp, "aPosition", -1);
GET_SHADER_PARAM(texCoordAttribute, planeVertexProgramGxp, "aTexCoord", -1);
SceGxmVertexAttribute vertexAttributes[2];
SceGxmVertexStream vertexStreams[1];
// position
vertexAttributes[0].streamIndex = 0;
vertexAttributes[0].offset = 0;
vertexAttributes[0].format = SCE_GXM_ATTRIBUTE_FORMAT_F32;
vertexAttributes[0].componentCount = 2;
vertexAttributes[0].regIndex = sceGxmProgramParameterGetResourceIndex(positionAttribute);
// uv
vertexAttributes[1].streamIndex = 0;
vertexAttributes[1].offset = 8;
vertexAttributes[1].format = SCE_GXM_ATTRIBUTE_FORMAT_F32;
vertexAttributes[1].componentCount = 2;
vertexAttributes[1].regIndex = sceGxmProgramParameterGetResourceIndex(texCoordAttribute);
vertexStreams[0].stride = sizeof(GXMVertex2D);
vertexStreams[0].indexSource = SCE_GXM_INDEX_SOURCE_INDEX_16BIT;
ret = SCE_ERR(
sceGxmShaderPatcherCreateVertexProgram,
this->shaderPatcher,
this->planeVertexProgramId,
vertexAttributes,
2,
vertexStreams,
1,
&this->planeVertexProgram
);
if (ret < 0) {
return ret;
}
ret = SCE_ERR(
sceGxmShaderPatcherCreateFragmentProgram,
this->shaderPatcher,
this->colorFragmentProgramId,
SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
msaaMode,
NULL,
planeVertexProgramGxp,
&this->colorFragmentProgram
);
if (ret < 0) {
return ret;
}
ret = SCE_ERR(
sceGxmShaderPatcherCreateFragmentProgram,
this->shaderPatcher,
this->imageFragmentProgramId,
SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
msaaMode,
&blendInfoTransparent,
planeVertexProgramGxp,
&this->imageFragmentProgram
);
if (ret < 0) {
return ret;
}
}
return 0;
}
void GXMContext::destroy_base_shaders()
{
sceGxmShaderPatcherReleaseVertexProgram(this->shaderPatcher, this->planeVertexProgram);
sceGxmShaderPatcherReleaseFragmentProgram(this->shaderPatcher, this->colorFragmentProgram);
sceGxmShaderPatcherReleaseFragmentProgram(this->shaderPatcher, this->imageFragmentProgram);
}
int GXMContext::init(SceGxmMultisampleMode msaaMode)
{
int ret = 0;
ret = gxm_library_init();
if (ret < 0) {
return ret;
}
if (this->cdramPool == nullptr) {
this->init_cdram_allocator();
}
if (this->context == nullptr) {
ret = this->init_context();
if (ret < 0) {
return ret;
}
}
if (this->planeVertexProgramId == 0) {
ret = this->register_base_shaders();
if (ret < 0) {
return ret;
}
}
if (this->clearVertices == nullptr) {
this->init_clear_mesh();
}
// recreate when msaa is different
if (msaaMode != this->displayMsaa && this->renderTargetInit) {
this->destroy_display_buffers();
this->destroy_base_shaders();
}
if (!this->renderTargetInit) {
ret = this->create_display_buffers(msaaMode);
if (ret < 0) {
return ret;
}
ret = this->patch_base_shaders(msaaMode);
if (ret < 0) {
return ret;
}
}
return 0;
}
static int inuse_mem = 0;
void* GXMContext::alloc(size_t size, size_t align)
{
if (this->cdramPool == nullptr) {
this->init_cdram_allocator();
}
DEBUG_ONLY_PRINTF("cdram_alloc(%d, %d) inuse=%d ", size, align, inuse_mem);
void* ptr = tlsf_memalign(this->cdramPool, align, size);
DEBUG_ONLY_PRINTF("ptr=%p\n", ptr);
inuse_mem += tlsf_block_size(ptr);
return ptr;
}
void GXMContext::free(void* ptr)
{
inuse_mem -= tlsf_block_size(ptr);
DEBUG_ONLY_PRINTF("cdram_free(%p)\n", ptr);
tlsf_free(this->cdramPool, ptr);
}
void GXMContext::clear(float r, float g, float b, bool new_scene)
{
new_scene = new_scene && !this->sceneStarted;
if (new_scene) {
sceGxmBeginScene(
this->context,
0,
this->renderTarget,
nullptr,
nullptr,
this->displayBuffersSync[this->backBufferIndex],
&this->displayBuffersSurface[this->backBufferIndex],
&this->depthSurface
);
this->sceneStarted = true;
}
float color[] = {r, g, b, 1};
sceGxmSetVertexProgram(this->context, this->planeVertexProgram);
sceGxmSetFragmentProgram(this->context, this->colorFragmentProgram);
void* vertUniforms;
void* fragUniforms;
sceGxmReserveVertexDefaultUniformBuffer(gxm->context, &vertUniforms);
sceGxmReserveFragmentDefaultUniformBuffer(gxm->context, &fragUniforms);
sceGxmSetVertexStream(gxm->context, 0, this->clearVertices);
sceGxmSetUniformDataF(fragUniforms, this->color_uColor, 0, 4, color);
sceGxmSetFrontDepthFunc(gxm->context, SCE_GXM_DEPTH_FUNC_ALWAYS);
sceGxmDraw(gxm->context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, this->clearIndices, 4);
if (new_scene) {
sceGxmEndScene(this->context, nullptr, nullptr);
this->sceneStarted = false;
}
}
void GXMContext::copy_frontbuffer()
{
SceGxmTexture texture;
sceGxmTextureInitLinearStrided(
&texture,
this->displayBuffers[this->frontBufferIndex],
SCE_GXM_TEXTURE_FORMAT_U8U8U8U8_ABGR,
VITA_GXM_SCREEN_WIDTH,
VITA_GXM_SCREEN_HEIGHT,
VITA_GXM_SCREEN_STRIDE * 4
);
sceGxmSetVertexProgram(this->context, this->planeVertexProgram);
sceGxmSetFragmentProgram(this->context, this->imageFragmentProgram);
void* vertUniforms;
void* fragUniforms;
sceGxmReserveVertexDefaultUniformBuffer(this->context, &vertUniforms);
sceGxmReserveFragmentDefaultUniformBuffer(this->context, &fragUniforms);
sceGxmSetVertexStream(this->context, 0, this->clearVertices);
sceGxmSetFragmentTexture(this->context, 0, &texture);
sceGxmSetFrontDepthFunc(this->context, SCE_GXM_DEPTH_FUNC_ALWAYS);
sceGxmDraw(this->context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, this->clearIndices, 4);
}
void GXMContext::destroy()
{
sceGxmDisplayQueueFinish();
if (gxm->context) {
sceGxmFinish(gxm->context);
}
this->destroy_display_buffers();
this->destroy_base_shaders();
sceGxmShaderPatcherDestroy(this->shaderPatcher);
sceGxmDestroyContext(this->context);
vita_mem_fragment_usse_free(this->fragmentUsseRingBufferUid);
vita_mem_free(this->fragmentRingBufferUid);
vita_mem_free(this->vertexRingBufferUid);
vita_mem_free(this->vdmRingBufferUid);
SDL_free(this->contextHostMem);
}
void GXMContext::swap_display()
{
if (this->sceneStarted) {
sceGxmEndScene(gxm->context, nullptr, nullptr);
this->sceneStarted = false;
}
SceCommonDialogUpdateParam updateParam;
SDL_zero(updateParam);
updateParam.renderTarget.colorFormat = VITA_GXM_COLOR_FORMAT;
updateParam.renderTarget.surfaceType = SCE_GXM_COLOR_SURFACE_LINEAR;
updateParam.renderTarget.width = VITA_GXM_SCREEN_WIDTH;
updateParam.renderTarget.height = VITA_GXM_SCREEN_HEIGHT;
updateParam.renderTarget.strideInPixels = VITA_GXM_SCREEN_STRIDE;
updateParam.renderTarget.colorSurfaceData = this->displayBuffers[this->backBufferIndex];
updateParam.displaySyncObject = this->displayBuffersSync[this->backBufferIndex];
sceCommonDialogUpdate(&updateParam);
sceGxmPadHeartbeat(
&this->displayBuffersSurface[this->backBufferIndex],
this->displayBuffersSync[this->backBufferIndex]
);
// display
GXMDisplayData displayData;
displayData.address = this->displayBuffers[this->backBufferIndex];
displayData.index = this->backBufferIndex;
sceGxmDisplayQueueAddEntry(
this->displayBuffersSync[this->frontBufferIndex],
this->displayBuffersSync[this->backBufferIndex],
&displayData
);
this->frontBufferIndex = this->backBufferIndex;
this->backBufferIndex = (this->backBufferIndex + 1) % GXM_DISPLAY_BUFFER_COUNT;
}

View File

@ -0,0 +1,105 @@
#pragma once
#include <psp2/gxm.h>
#define VITA_GXM_SCREEN_WIDTH 960
#define VITA_GXM_SCREEN_HEIGHT 544
#define VITA_GXM_SCREEN_STRIDE 1024
#define VITA_GXM_PENDING_SWAPS 2
#define VITA_GXM_PIXEL_FORMAT SCE_DISPLAY_PIXELFORMAT_A8B8G8R8
#define GXM_DISPLAY_BUFFER_COUNT 3
typedef struct GXMVertex2D {
float position[2];
float texCoord[2];
} GXMVertex2D;
typedef struct GXMContext {
// context
SceUID vdmRingBufferUid;
SceUID vertexRingBufferUid;
SceUID fragmentRingBufferUid;
SceUID fragmentUsseRingBufferUid;
size_t fragmentUsseRingBufferOffset;
void* vdmRingBuffer;
void* vertexRingBuffer;
void* fragmentRingBuffer;
void* fragmentUsseRingBuffer;
void* contextHostMem;
SceGxmContext* context;
// shader patcher
SceUID patcherBufferUid;
void* patcherBuffer;
SceUID patcherVertexUsseUid;
size_t patcherVertexUsseOffset;
void* patcherVertexUsse;
SceUID patcherFragmentUsseUid;
size_t patcherFragmentUsseOffset;
void* patcherFragmentUsse;
SceGxmShaderPatcher* shaderPatcher;
// clear
SceGxmShaderPatcherId planeVertexProgramId;
SceGxmShaderPatcherId colorFragmentProgramId;
SceGxmShaderPatcherId imageFragmentProgramId;
SceGxmVertexProgram* planeVertexProgram;
SceGxmFragmentProgram* colorFragmentProgram;
SceGxmFragmentProgram* imageFragmentProgram;
const SceGxmProgramParameter* color_uColor;
GXMVertex2D* clearVertices;
uint16_t* clearIndices;
// display
SceGxmRenderTarget* renderTarget;
bool renderTargetInit = false;
void* displayBuffers[GXM_DISPLAY_BUFFER_COUNT];
SceUID displayBuffersUid[GXM_DISPLAY_BUFFER_COUNT];
SceGxmColorSurface displayBuffersSurface[GXM_DISPLAY_BUFFER_COUNT];
SceGxmSyncObject* displayBuffersSync[GXM_DISPLAY_BUFFER_COUNT];
int backBufferIndex = 0;
int frontBufferIndex = 1;
SceGxmMultisampleMode displayMsaa;
// depth buffer
SceUID depthBufferUid;
void* depthBufferData;
SceUID stencilBufferUid;
void* stencilBufferData;
SceGxmDepthStencilSurface depthSurface;
// allocator
SceUID cdramUID;
void* cdramMem;
void* cdramPool;
bool sceneStarted;
void swap_display();
void copy_frontbuffer();
int init(SceGxmMultisampleMode msaaMode);
void init_cdram_allocator();
int init_context();
int create_display_buffers(SceGxmMultisampleMode msaaMode);
void init_clear_mesh();
void destroy_display_buffers();
int register_base_shaders();
int patch_base_shaders(SceGxmMultisampleMode msaaMode);
void destroy_base_shaders();
void destroy();
void clear(float r, float g, float b, bool new_scene);
void* alloc(size_t size, size_t align);
void free(void* ptr);
} GXMContext;
// global so that common dialog can be rendererd without GXMRenderer
extern GXMContext* gxm;
extern bool with_razor_capture;
extern bool with_razor_hud;

View File

@ -0,0 +1,119 @@
#include "gxm_memory.h"
#include "tlsf.h"
#include "utils.h"
#include <SDL3/SDL_stdinc.h>
#include <psp2/gxm.h>
#include <psp2/kernel/clib.h>
#include <psp2/kernel/sysmem.h>
void* patcher_host_alloc(void* user_data, unsigned int size)
{
void* mem = SDL_malloc(size);
(void) user_data;
return mem;
}
void patcher_host_free(void* user_data, void* mem)
{
(void) user_data;
SDL_free(mem);
}
void* vita_mem_alloc(unsigned int type, size_t size, size_t alignment, int attribs, SceUID* uid, const char* name)
{
void* mem;
if (type == SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW) {
size = ALIGN(size, 256 * 1024);
}
else if (type == SCE_KERNEL_MEMBLOCK_TYPE_USER_MAIN_PHYCONT_NC_RW) {
size = ALIGN(size, 1024 * 1024);
}
else {
size = ALIGN(size, 4 * 1024);
}
*uid = sceKernelAllocMemBlock(name, type, size, NULL);
if (*uid < 0) {
SDL_Log("sceKernelAllocMemBlock: 0x%x", *uid);
return NULL;
}
if (sceKernelGetMemBlockBase(*uid, &mem) < 0) {
return NULL;
}
if (sceGxmMapMemory(mem, size, (SceGxmMemoryAttribFlags) attribs) < 0) {
SDL_Log("sceGxmMapMemory 0x%x 0x%x %d failed", mem, size, attribs);
return NULL;
}
return mem;
}
void vita_mem_free(SceUID uid)
{
void* mem = NULL;
if (sceKernelGetMemBlockBase(uid, &mem) < 0) {
return;
}
sceGxmUnmapMemory(mem);
sceKernelFreeMemBlock(uid);
}
void* vita_mem_vertex_usse_alloc(unsigned int size, SceUID* uid, unsigned int* usse_offset)
{
void* mem = NULL;
size = ALIGN(size, 4096);
*uid = sceKernelAllocMemBlock("vertex_usse", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, size, NULL);
if (sceKernelGetMemBlockBase(*uid, &mem) < 0) {
return NULL;
}
if (sceGxmMapVertexUsseMemory(mem, size, usse_offset) < 0) {
return NULL;
}
return mem;
}
void vita_mem_vertex_usse_free(SceUID uid)
{
void* mem = NULL;
if (sceKernelGetMemBlockBase(uid, &mem) < 0) {
return;
}
sceGxmUnmapVertexUsseMemory(mem);
sceKernelFreeMemBlock(uid);
}
void* vita_mem_fragment_usse_alloc(unsigned int size, SceUID* uid, unsigned int* usse_offset)
{
void* mem = NULL;
size = ALIGN(size, 4096);
*uid = sceKernelAllocMemBlock("fragment_usse", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, size, NULL);
if (sceKernelGetMemBlockBase(*uid, &mem) < 0) {
return NULL;
}
if (sceGxmMapFragmentUsseMemory(mem, size, usse_offset) < 0) {
return NULL;
}
return mem;
}
void vita_mem_fragment_usse_free(SceUID uid)
{
void* mem = NULL;
if (sceKernelGetMemBlockBase(uid, &mem) < 0) {
return;
}
sceGxmUnmapFragmentUsseMemory(mem);
sceKernelFreeMemBlock(uid);
}

View File

@ -0,0 +1,15 @@
#pragma once
#include <SDL3/SDL_stdinc.h>
#include <psp2/types.h>
void* patcher_host_alloc(void* user_data, unsigned int size);
void patcher_host_free(void* user_data, void* mem);
void* vita_mem_alloc(unsigned int type, size_t size, size_t alignment, int attribs, SceUID* uid, const char* name);
void vita_mem_free(SceUID uid);
void* vita_mem_vertex_usse_alloc(unsigned int size, SceUID* uid, unsigned int* usse_offset);
void vita_mem_vertex_usse_free(SceUID uid);
void* vita_mem_fragment_usse_alloc(unsigned int size, SceUID* uid, unsigned int* usse_offset);
void vita_mem_fragment_usse_free(SceUID uid);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
#pragma once
#include <psp2/razor_capture.h>
#include <psp2/razor_hud.h>
extern "C"
{
extern int sceRazorGpuCaptureSetTrigger(int frames, const char* path);
extern int sceRazorGpuTraceTrigger();
extern int sceRazorGpuTraceSetFilename(const char* filename, int counter);
extern int sceRazorHudSetDisplayEnabled(bool enable);
}

View File

@ -0,0 +1,2 @@
*.exe
cache/

View File

@ -0,0 +1,106 @@
cmake_minimum_required(VERSION 3.25...4.0 FATAL_ERROR)
enable_language(ASM)
find_program(PSP2CGC NAMES ${CMAKE_CURRENT_SOURCE_DIR}/psp2cgc.exe psp2cgc.exe psp2cgc)
find_program(PSP2SHADERPERF NAMES ${CMAKE_CURRENT_SOURCE_DIR}/psp2shaderperf.exe psp2shaderperf.exe psp2shaderperf)
list(APPEND CGC_COMMON_FLAGS "-Wperf" "-cache" "-cachedir" "${CMAKE_CURRENT_BINARY_DIR}/cache" "-W4" "-Wsuppress=5206,5203")
make_directory("${CMAKE_CURRENT_BINARY_DIR}/cache")
# compile .cg to .gxp if psp2cgc is found
macro(COMPILE_SHADER INPUT_CG OUTPUT_GXP PROFILE)
set(EXTRA_FLAGS "${ARGN}")
set(INPUT_CG_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_CG}")
set(OUTPUT_GXP_PATH "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_GXP}")
set(TRACKED_GXP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${OUTPUT_GXP}")
if(PSP2CGC)
if(EXISTS ${TRACKED_GXP_PATH})
file(COPY ${TRACKED_GXP_PATH} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
endif()
add_custom_command(
OUTPUT "${OUTPUT_GXP_PATH}"
COMMAND "${PSP2CGC}" ${CGC_COMMON_FLAGS} -profile "${PROFILE}" ${EXTRA_FLAGS} "${INPUT_CG_PATH}" -o "${OUTPUT_GXP_PATH}"
COMMAND ${CMAKE_COMMAND} -E copy "${OUTPUT_GXP_PATH}" "${TRACKED_GXP_PATH}"
DEPENDS "${INPUT_CG_PATH}"
COMMENT "Compiling ${INPUT_CG} -> ${OUTPUT_GXP} ${PROFILE}"
)
else()
if(NOT EXISTS "${TRACKED_GXP_PATH}")
message(FATAL_ERROR "missing shader ${TRACKED_GXP_PATH} ${INPUT_CG}, but psp2cgc.exe not found")
endif()
add_custom_command(
OUTPUT "${OUTPUT_GXP_PATH}"
COMMAND /usr/bin/env bash
ARGS "-c"
"if [ \"${INPUT_CG_PATH}\" -nt \"${TRACKED_GXP_PATH}\" ]; then
echo 'warning: ${INPUT_CG} changed but dont have psp2cgc, cant recompile' >&2;
fi"
COMMAND ${CMAKE_COMMAND} -E copy "${TRACKED_GXP_PATH}" "${OUTPUT_GXP_PATH}"
DEPENDS "${INPUT_CG_PATH}" "${TRACKED_GXP_PATH}"
VERBATIM
COMMENT "Copy ${TRACKED_GXP_PATH} -> ${OUTPUT_GXP} ${PROFILE}"
)
endif()
set(TARGET_NAME "compile_${OUTPUT_GXP}")
string(REPLACE "." "_" TARGET_NAME "${TARGET_NAME}")
add_custom_target("${TARGET_NAME}" DEPENDS "${OUTPUT_GXP_PATH}")
add_dependencies(gxm_shaders_compile "${TARGET_NAME}")
endmacro()
# analyze gxp to create a .perf.txt
macro(GENERATE_PERF GXP_FILE)
set(GXP_PATH "${CMAKE_CURRENT_BINARY_DIR}/${GXP_FILE}")
string(REPLACE ".gxp" ".perf.txt" PERF_FILE_NAME "${GXP_FILE}")
set(PERF_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${PERF_FILE_NAME}")
add_custom_command(
OUTPUT "${PERF_FILE_PATH}"
COMMAND "${PSP2SHADERPERF}" -stats -symbols -disasm "${GXP_PATH}" > "${PERF_FILE_PATH}"
DEPENDS "${GXP_PATH}"
COMMENT "Generating performance analysis for ${GXP_FILE}"
)
set(TARGET_NAME "perf_${PERF_FILE_NAME}")
string(REPLACE "." "_" TARGET_NAME "${TARGET_NAME}")
add_custom_target("${TARGET_NAME}" DEPENDS "${PERF_FILE_PATH}")
add_dependencies(gxm_perfs "${TARGET_NAME}" )
endmacro()
add_library(gxm_shaders STATIC gxm_shaders.s)
target_include_directories(gxm_shaders PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
)
add_custom_target(gxm_shaders_compile)
add_dependencies(gxm_shaders gxm_shaders_compile)
COMPILE_SHADER(plane.vert.cg plane.vert.gxp sce_vp_psp2)
COMPILE_SHADER(color.frag.cg color.frag.gxp sce_fp_psp2)
COMPILE_SHADER(image.frag.cg image.frag.gxp sce_fp_psp2)
COMPILE_SHADER(main.vert.cg main.vert.gxp sce_vp_psp2)
COMPILE_SHADER(main.frag.cg main.color.frag.gxp sce_fp_psp2)
COMPILE_SHADER(main.frag.cg main.texture.frag.gxp sce_fp_psp2 -DTEXTURED=1)
# .perf.txt
if(PSP2SHADERPERF)
add_custom_target(gxm_perfs)
add_dependencies(gxm_shaders gxm_perfs)
GENERATE_PERF(plane.vert.gxp)
GENERATE_PERF(color.frag.gxp)
GENERATE_PERF(image.frag.gxp)
GENERATE_PERF(main.vert.gxp)
GENERATE_PERF(main.color.frag.gxp)
GENERATE_PERF(main.texture.frag.gxp)
else()
message(STATUS "psp2shaderperf not found")
endif()

View File

@ -0,0 +1,6 @@
void main(
uniform float4 uColor : COLOR,
out float4 outColor : COLOR
) {
outColor = uColor;
}

Binary file not shown.

View File

@ -0,0 +1,26 @@
Total estimated cost: 1 cycles, parallel mode
Register count: 2 PAs, 0 temps, 4 SAs *
Texture reads: 0 non-dependent, dependent: 0 unconditional, 0 conditional
High level analysis:
No warnings.
* Please refer to the Razor documentation for details regarding the meaning of these numbers. Decreasing the number of registers used will not necessarily increase performance
Instruction statistics:
Number of alu ops: 1
Number of mem ops: 0
Number of tex ops: 0
Number of floating point ops: 0
Number of integer ops: 0
Number of pack ops: 1
Number of mov ops: 0
Number of nop ops: 0
Constants:
[DEFAULT + 0 ] sa0 = (float4) uColor
Primary program:
0: pack.f16.f32 pa0.xyzw, sa0.xyzw

View File

@ -0,0 +1,32 @@
#include <psp2/gxm.h>
#define GXP(sym) \
extern uint8_t _inc_##sym[]; \
static const SceGxmProgram* sym = (const SceGxmProgram*) _inc_##sym;
GXP(mainVertexProgramGxp);
GXP(mainColorFragmentProgramGxp);
GXP(mainTextureFragmentProgramGxp);
GXP(planeVertexProgramGxp);
GXP(imageFragmentProgramGxp);
GXP(colorFragmentProgramGxp);
static const SceGxmBlendInfo blendInfoOpaque = {
.colorMask = SCE_GXM_COLOR_MASK_ALL,
.colorFunc = SCE_GXM_BLEND_FUNC_NONE,
.alphaFunc = SCE_GXM_BLEND_FUNC_NONE,
.colorSrc = SCE_GXM_BLEND_FACTOR_ZERO,
.colorDst = SCE_GXM_BLEND_FACTOR_ZERO,
.alphaSrc = SCE_GXM_BLEND_FACTOR_ZERO,
.alphaDst = SCE_GXM_BLEND_FACTOR_ZERO,
};
static const SceGxmBlendInfo blendInfoTransparent = {
.colorMask = SCE_GXM_COLOR_MASK_ALL,
.colorFunc = SCE_GXM_BLEND_FUNC_ADD,
.alphaFunc = SCE_GXM_BLEND_FUNC_ADD,
.colorSrc = SCE_GXM_BLEND_FACTOR_SRC_ALPHA,
.colorDst = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.alphaSrc = SCE_GXM_BLEND_FACTOR_ONE,
.alphaDst = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
};

View File

@ -0,0 +1,15 @@
.section .rodata, "a", %progbits
.macro embed file, symbol
.global _inc_\symbol
.align 16
_inc_\symbol:
.incbin "\file"
.endm
embed "main.vert.gxp", mainVertexProgramGxp
embed "main.color.frag.gxp", mainColorFragmentProgramGxp
embed "main.texture.frag.gxp", mainTextureFragmentProgramGxp
embed "plane.vert.gxp", planeVertexProgramGxp
embed "image.frag.gxp", imageFragmentProgramGxp
embed "color.frag.gxp", colorFragmentProgramGxp

View File

@ -0,0 +1,10 @@
void main(
float4 vPosition : POSITION,
float2 vTexCoord : TEXCOORD0,
uniform sampler2D uTexture,
out float4 outColor : COLOR
) {
outColor = tex2D(uTexture, vTexCoord);
}

Binary file not shown.

View File

@ -0,0 +1,29 @@
Total estimated cost: 0 cycles, parallel mode
Register count: 2 PAs, 0 temps, 0 SAs *
Texture reads: 1 non-dependent, dependent: 0 unconditional, 0 conditional
High level analysis:
No warnings.
* Please refer to the Razor documentation for details regarding the meaning of these numbers. Decreasing the number of registers used will not necessarily increase performance
Instruction statistics:
Number of alu ops: 0
Number of mem ops: 0
Number of tex ops: 0
Number of floating point ops: 0
Number of integer ops: 0
Number of pack ops: 0
Number of mov ops: 0
Number of nop ops: 0
Samplers:
TEXUNIT0 = uTexture
Iterators:
Primary program:
pa0 = tex2D<half4>(uTexture, TEXCOORD0.xy)

View File

@ -0,0 +1,134 @@
Total estimated cost: 63.5 cycles, parallel mode
Register count: 8 PAs, 16 temps, 38 SAs *
Texture reads: 0 non-dependent, dependent: 0 unconditional, 0 conditional
High level analysis:
No warnings.
* Please refer to the Razor documentation for details regarding the meaning of these numbers. Decreasing the number of registers used will not necessarily increase performance
Instruction statistics:
Number of alu ops: 63
Number of mem ops: 0
Number of tex ops: 0
Number of floating point ops: 43
Number of integer ops: 1
Number of pack ops: 1
Number of mov ops: 15
Number of nop ops: 2
Constants:
[DEFAULT + 0 ] sa0 = (float1) uShininess
[DEFAULT + 2 ] sa2 = (float4) uColor
[BUFFER0 + 0 ] = (float4) uLights[0].color
[BUFFER0 + 4 ] = (float4) uLights[0].vec
[BUFFER0 + 8 ] = (float1) uLights[0].isDirectional
[BUFFER0 + 10 ] = (float4) uLights[1].color
[BUFFER0 + 14 ] = (float4) uLights[1].vec
[BUFFER0 + 18 ] = (float1) uLights[1].isDirectional
[BUFFER0 + 20 ] = (float3) uAmbientLight
[LITERAL + 1 ] sa7 = 0xffffffff (-1.#QNAN0f) (-1.#QNANh, -1.#QNANh)
[LITERAL + 2 ] sa8 = 0x3f800000 (1.000000f) (0.00000h, 1.87500h)
[BUFFER0 ] sa6 = buffer base address
Iterators:
pa0 = (float4) TEXCOORD1
pa4 = (float4) TEXCOORD2
Secondary program:
0 : lda32 sa1, [sa6, 0x9]
1 : lda32.fetch3 sa9, [sa6, 0x4]
2 : mul.f32 sa32.xy, -sa8.yz, sa0.yy
3 : mul.f32 sa34.x, -sa10.y, sa0.y
4 : lda32.fetch4 sa12, [sa6, 0x0]
5 : mov.f32 sa36.xy, {0, 0}
6 : mov.f32 sa30.x, {0}
7 : lda32 sa15, [sa6, 0x13]
8 : lda32.fetch3 sa16, [sa6, 0xe]
9 : mul.f32 sa26.xy, -sa16.xy, sa14.yy
10: mul.f32 sa28.x, -sa18.x, sa14.y
11: lda32.fetch4 sa19, [sa6, 0xa]
12: lda32.fetch3 sa22, [sa6, 0x14]
13: nop
Primary program:
0 : cmp.gt.f32 p0, sa0.x, {0}
1 : mov.f32 i0.xyz, pa0.xyz
2 : add.f32 i1.xyz, sa8.yzw, -i0.xyz
2 : +dot.f32 pa3.x, i0.xyz, i0.xyz
3 : mov.f32 i2.xyz, sa32.xyz
4 : mad.f32 i2.xyz, -sa0.yyy, i1.xyz, i2.xyz
5 : add.f32 i1.xyz, i2.xyz, i1.xyz
5 : +rsq.f32 pa3.x, pa3.x
6 : dot.f32 i2.x, i1.xyz, i1.xyz
7 : rsq.f32 pa3.x, i2.x
7 : +mul.f32 i0.xyz, -i0.xyz, pa2.yyy
8 : mad.f32 i2.xyz, pa2.yyy, i1.xyz, i0.xyz
8 : +mov.f32 r6.xy, i0.xy
9 : mov.f32 r8.x, i0.z
10: dot.f32 i0.x, i2.xyz, i2.xyz
10: +mov.f32 r2.xy, i2.xy
11: mov.f32 r4.x, i2.z
12: rsq.f32 pa3.x, i0.x
12: +mul.f32 i0.xyz, i1.xyz, pa2.yyy
13: dot.f32 i0.x, pa4.xyz, i0.xyz
14: max.f32 r14.x, i0.x, {0}
15: p0 br #19
16: mov.f32 r10.xy, sa36.xy
17: or.u32 r12.x, sa30.x, 0x0
18: br #30
#19: cmov.lezero.f32 r0.x, r14.x, {0}, sa8.x
20: cmov.ltzero.f32 i0.x, r14.x, sa8.x, {0}
21: mad.f32 i0.x, r0.x, {1}, -i0.x
22: mul.f32 i1.xyz, r2.xyz, pa2.yyy
23: dot.f32 i1.x, pa4.xyz, i1.xyz
24: max.f32 i1.x, i1.x, {0}
25: mul.f32 i0.xyz, sa12.xyz, i0.xxx
25: +log.f32 pa3.x, i1.x
26: mul.f32 i1.x, sa0.x, pa2.y
27: exp.f32 i1.x, i1.x
28: mad.f32 r10.xy, i0.xy, i1.xx, {0, 0}
29: mul.f32 r12.x, i0.z, i1.x
#30: nop
31: mov.f32 i0.xyz, sa16.xyz
32: mad.f32 i0.xyz, -pa0.xyz, {1, 1, 1}, i0.xyz
33: mov.f32 i1.xyz, sa26.xyz
34: mad.f32 i1.xyz, -sa14.yyy, i0.xyz, i1.xyz
35: add.f32 i0.xyz, i1.xyz, i0.xyz
35: +mov.f32 i2.xyz, r6.xyz
36: dot.f32 i1.x, i0.xyz, i0.xyz
37: rsq.f32 i1.x, i1.x
38: mad.f32 i2.xyz, i1.xxx, i0.xyz, i2.xyz
39: mul.f32 i0.xyz, i0.xyz, i1.xxx
39: +mov.f32 r0.xy, i2.xy
40: dot.f32 i0.x, pa4.xyz, i0.xyz
41: max.f32 pa2.x, i0.x, {0}
42: dot.f32 i0.x, i2.xyz, i2.xyz
43: mov.f32 r2.x, i2.z
44: rsq.f32 pa0.-y, i0.x
45: !p0 br #57
46: cmov.lezero.f32 pa0.x, pa2.x, {0}, sa8.x
47: cmov.ltzero.f32 i0.x, pa2.x, sa8.x, {0}
48: mad.f32 i0.x, pa0.x, {1}, -i0.x
49: mul.f32 i1.xyz, r0.xyz, pa0.yyy
50: dot.f32 i1.x, pa4.xyz, i1.xyz
51: max.f32 i1.x, i1.x, {0}
52: mul.f32 i0.xyz, sa18.yzw, i0.xxx
52: +log.f32 pa0.x, i1.x
53: mul.f32 i1.x, sa0.x, pa0.x
54: exp.f32 i1.x, i1.x
55: mad.f32 r10.xy, i0.xy, i1.xx, r10.xy
56: mad.f32 r12.x, i0.z, i1.x, r12.x
#57: nop
58: mad.f32 i0.xy, r14.xx, sa12.xy, sa22.xy
59: mad.f32 i0.--z, r14.--x, sa14.--x, sa24.--x
60: mov.f32 i1.xyz, sa18.yzw
61: mad.f32 i0.xyz, pa2.xxx, i1.xyz, i0.xyz
62: mov.f32 i1.xyz, r10.xyz
63: mov.f32 i2.xyzw, sa2.xyzw
64: mad.f32 i0.xyz, i2.xyz, i0.xyz, i1.xyz
65: min.f32 i0.xyz, i0.xyz, {1, 1, 1}
66: max.f32 i2.xyz, i0.xyz, {0, 0, 0}
67: pack.f16.f32 pa0.xyzw, i2.xyzw

View File

@ -0,0 +1,54 @@
struct SceneLight {
float4 color;
float4 vec;
float isDirectional;
};
void main(
float4 vPosition : POSITION,
float2 vTexCoord : TEXCOORD0,
float3 vViewPos : TEXCOORD1,
float3 vNormal : TEXCOORD2,
uniform __nostrip SceneLight uLights[2] : BUFFER[0],
uniform __nostrip float3 uAmbientLight : BUFFER[0],
uniform __nostrip float uShininess,
uniform __nostrip float4 uColor,
uniform __nostrip sampler2D uTexture,
out float4 outColor : COLOR
) {
float3 diffuse = float3(0.0, 0.0, 0.0);
float3 specular = float3(0.0, 0.0, 0.0);
float3 viewVec = normalize(-vViewPos); // Assuming camera at origin
diffuse += uAmbientLight;
for (int i = 0; i < 2; ++i) {
float3 lightColor = uLights[i].color.rgb;
float isDirectional = uLights[i].isDirectional;
float3 lightVec = normalize(lerp(uLights[i].vec.xyz - vViewPos, -uLights[i].vec.xyz, isDirectional));
float3 halfVec = normalize(viewVec + lightVec);
float dotNL = max(dot(vNormal, lightVec), 0.0);
float dotNH = max(dot(vNormal, halfVec), 0.0);
// Diffuse contribution
diffuse += dotNL * lightColor;
// Specular
float spec = pow(dotNH, uShininess);
if(uShininess > 0.0) {
specular += spec * lightColor * sign(dotNL);
}
}
outColor.rgb = clamp(diffuse * uColor.rgb + specular, 0.0, 1.0);
outColor.a = uColor.a;
#if TEXTURED
float4 texel = tex2D(uTexture, vTexCoord);
outColor.rgb *= texel.rgb;
#endif
}

View File

@ -0,0 +1,139 @@
Total estimated cost: 64.5 cycles, parallel mode
Register count: 12 PAs, 16 temps, 38 SAs *
Texture reads: 1 non-dependent, dependent: 0 unconditional, 0 conditional
High level analysis:
No warnings.
* Please refer to the Razor documentation for details regarding the meaning of these numbers. Decreasing the number of registers used will not necessarily increase performance
Instruction statistics:
Number of alu ops: 64
Number of mem ops: 0
Number of tex ops: 0
Number of floating point ops: 44
Number of integer ops: 1
Number of pack ops: 1
Number of mov ops: 15
Number of nop ops: 2
Constants:
[DEFAULT + 0 ] sa0 = (float1) uShininess
[DEFAULT + 2 ] sa2 = (float4) uColor
[BUFFER0 + 0 ] = (float4) uLights[0].color
[BUFFER0 + 4 ] = (float4) uLights[0].vec
[BUFFER0 + 8 ] = (float1) uLights[0].isDirectional
[BUFFER0 + 10 ] = (float4) uLights[1].color
[BUFFER0 + 14 ] = (float4) uLights[1].vec
[BUFFER0 + 18 ] = (float1) uLights[1].isDirectional
[BUFFER0 + 20 ] = (float3) uAmbientLight
[LITERAL + 1 ] sa7 = 0xffffffff (-1.#QNAN0f) (-1.#QNANh, -1.#QNANh)
[LITERAL + 2 ] sa8 = 0x3f800000 (1.000000f) (0.00000h, 1.87500h)
[BUFFER0 ] sa6 = buffer base address
Samplers:
TEXUNIT0 = uTexture
Iterators:
pa0 = (float4) TEXCOORD1
pa8 = (float4) TEXCOORD2
Secondary program:
0 : lda32 sa1, [sa6, 0x9]
1 : lda32.fetch3 sa9, [sa6, 0x4]
2 : mul.f32 sa32.xy, -sa8.yz, sa0.yy
3 : mul.f32 sa34.x, -sa10.y, sa0.y
4 : lda32.fetch4 sa12, [sa6, 0x0]
5 : mov.f32 sa36.xy, {0, 0}
6 : mov.f32 sa30.x, {0}
7 : lda32 sa15, [sa6, 0x13]
8 : lda32.fetch3 sa16, [sa6, 0xe]
9 : mul.f32 sa26.xy, -sa16.xy, sa14.yy
10: mul.f32 sa28.x, -sa18.x, sa14.y
11: lda32.fetch4 sa19, [sa6, 0xa]
12: lda32.fetch3 sa22, [sa6, 0x14]
13: nop
Primary program:
pa4 = tex2D<float4>(uTexture, TEXCOORD0.xy)
0 : cmp.gt.f32 p0, sa0.x, {0}
1 : mov.f32 i0.xyz, pa0.xyz
2 : add.f32 i1.xyz, sa8.yzw, -i0.xyz
2 : +dot.f32 pa3.x, i0.xyz, i0.xyz
3 : mov.f32 i2.xyz, sa32.xyz
4 : mad.f32 i2.xyz, -sa0.yyy, i1.xyz, i2.xyz
5 : add.f32 i1.xyz, i2.xyz, i1.xyz
5 : +rsq.f32 pa3.x, pa3.x
6 : dot.f32 i2.x, i1.xyz, i1.xyz
7 : rsq.f32 pa3.x, i2.x
7 : +mul.f32 i0.xyz, -i0.xyz, pa2.yyy
8 : mad.f32 i2.xyz, pa2.yyy, i1.xyz, i0.xyz
8 : +mov.f32 r6.xy, i0.xy
9 : mov.f32 r8.x, i0.z
10: dot.f32 i0.x, i2.xyz, i2.xyz
10: +mov.f32 r2.xy, i2.xy
11: mov.f32 r4.x, i2.z
12: rsq.f32 pa3.x, i0.x
12: +mul.f32 i0.xyz, i1.xyz, pa2.yyy
13: dot.f32 i0.x, pa8.xyz, i0.xyz
14: max.f32 r14.x, i0.x, {0}
15: p0 br #19
16: mov.f32 r10.xy, sa36.xy
17: or.u32 r12.x, sa30.x, 0x0
18: br #30
#19: cmov.lezero.f32 r0.x, r14.x, {0}, sa8.x
20: cmov.ltzero.f32 i0.x, r14.x, sa8.x, {0}
21: mad.f32 i0.x, r0.x, {1}, -i0.x
22: mul.f32 i1.xyz, r2.xyz, pa2.yyy
23: dot.f32 i1.x, pa8.xyz, i1.xyz
24: max.f32 i1.x, i1.x, {0}
25: mul.f32 i0.xyz, sa12.xyz, i0.xxx
25: +log.f32 pa3.x, i1.x
26: mul.f32 i1.x, sa0.x, pa2.y
27: exp.f32 i1.x, i1.x
28: mad.f32 r10.xy, i0.xy, i1.xx, {0, 0}
29: mul.f32 r12.x, i0.z, i1.x
#30: nop
31: mov.f32 i0.xyz, sa16.xyz
32: mad.f32 i0.xyz, -pa0.xyz, {1, 1, 1}, i0.xyz
33: mov.f32 i1.xyz, sa26.xyz
34: mad.f32 i1.xyz, -sa14.yyy, i0.xyz, i1.xyz
35: add.f32 i0.xyz, i1.xyz, i0.xyz
35: +mov.f32 i2.xyz, r6.xyz
36: dot.f32 i1.x, i0.xyz, i0.xyz
37: rsq.f32 i1.x, i1.x
38: mad.f32 i2.xyz, i1.xxx, i0.xyz, i2.xyz
39: mul.f32 i0.xyz, i0.xyz, i1.xxx
39: +mov.f32 r0.xy, i2.xy
40: dot.f32 i0.x, pa8.xyz, i0.xyz
41: max.f32 pa2.x, i0.x, {0}
42: dot.f32 i0.x, i2.xyz, i2.xyz
43: mov.f32 r2.x, i2.z
44: rsq.f32 pa0.-y, i0.x
45: !p0 br #57
46: cmov.lezero.f32 pa0.x, pa2.x, {0}, sa8.x
47: cmov.ltzero.f32 i0.x, pa2.x, sa8.x, {0}
48: mad.f32 i0.x, pa0.x, {1}, -i0.x
49: mul.f32 i1.xyz, r0.xyz, pa0.yyy
50: dot.f32 i1.x, pa8.xyz, i1.xyz
51: max.f32 i1.x, i1.x, {0}
52: mul.f32 i0.xyz, sa18.yzw, i0.xxx
52: +log.f32 pa0.x, i1.x
53: mul.f32 i1.x, sa0.x, pa0.x
54: exp.f32 i1.x, i1.x
55: mad.f32 r10.xy, i0.xy, i1.xx, r10.xy
56: mad.f32 r12.x, i0.z, i1.x, r12.x
#57: nop
58: mad.f32 i0.xy, r14.xx, sa12.xy, sa22.xy
59: mad.f32 i0.--z, r14.--x, sa14.--x, sa24.--x
60: mov.f32 i1.xyz, sa18.yzw
61: mad.f32 i0.xyz, pa2.xxx, i1.xyz, i0.xyz
62: mov.f32 i1.xyz, r10.xyz
63: mov.f32 i2.xyzw, sa2.xyzw
64: mad.f32 i0.xyz, i2.xyz, i0.xyz, i1.xyz
65: min.f32 i0.xyz, i0.xyz, {1, 1, 1}
66: max.f32 i0.xyz, i0.xyz, {0, 0, 0}
67: mad.f32 i2.xyz, pa4.xyz, i0.xyz, {0, 0, 0}
68: pack.f16.f32 pa0.xyzw, i2.xyzw

View File

@ -0,0 +1,20 @@
void main(
float3 aPosition : POSITION,
float3 aNormal : NORMAL,
float2 aTexCoord : TEXCOORD0,
column_major uniform float4x4 uModelViewMatrix,
column_major uniform float3x3 uNormalMatrix,
column_major uniform float4x4 uProjectionMatrix,
out float4 vPosition : POSITION,
out float2 vTexCoord : TEXCOORD0,
out float3 vViewPos : TEXCOORD1,
out float3 vNormal : TEXCOORD2
) {
float4 viewPos = mul(uModelViewMatrix, float4(aPosition, 1.0));
vPosition = mul(uProjectionMatrix, viewPos);
vViewPos = viewPos.xyz;
vNormal = normalize(mul(uNormalMatrix, aNormal));
vTexCoord = aTexCoord;
}

Binary file not shown.

View File

@ -0,0 +1,87 @@
Total estimated cost: 18 cycles, parallel mode
Register count: 12 PAs, 0 temps, 56 SAs *
Texture reads: 0 non-dependent, dependent: 0 unconditional, 0 conditional
High level analysis:
- One or multiple vertex outputs are misaligned due to a three coefficient TEXCOORD vertex output. This will lead to additional data movement instructions being generated. If only one three coefficient TEXCOORD output is present, assigning it the coordinate with the greatest index will allow the previous coordinates to be aligned.
* Please refer to the Razor documentation for details regarding the meaning of these numbers. Decreasing the number of registers used will not necessarily increase performance
Instruction statistics:
Number of alu ops: 19
Number of mem ops: 0
Number of tex ops: 0
Number of floating point ops: 14
Number of integer ops: 0
Number of pack ops: 0
Number of mov ops: 4
Number of nop ops: 0
Constants:
[DEFAULT + 0 ] sa0 = (float4) uModelViewMatrix[4]
[DEFAULT + 32 ] sa32 = (float3) uNormalMatrix[3]
[DEFAULT + 16 ] sa16 = (float4) uProjectionMatrix[4]
Vertex attributes:
pa0 = (float4) aPosition
pa4 = (float4) aNormal
pa8 = (float4) aTexCoord
Secondary program:
0 : nop
1 : mov.f32 i0.xyzw, sa8.xyzw
2 : mul.f32 i1.xyzw, sa16.xyzw, i0.xxxx
3 : mad.f32 i1.xyzw, sa20.xyzw, i0.yyyy, i1.xyzw
4 : mad.f32 i1.xyzw, sa24.xyzw, i0.zzzz, i1.xyzw
5 : mad.f32 sa52.xy, sa28.xy, i0.ww, i1.xy
6 : mad.f32 sa54.xy, sa30.xy, i0.ww, i1.zw
7 : mov.f32 i1.xyzw, sa12.xyzw
8 : mul.f32 i2.xyzw, sa28.xyzw, i1.wwww
9 : mad.f32 i2.xyzw, sa24.xyzw, i1.zzzz, i2.xyzw
10: mad.f32 i2.xyzw, sa20.xyzw, i1.yyyy, i2.xyzw
11: mad.f32 sa48.xy, sa16.xy, i1.xx, i2.xy
12: mad.f32 sa50.xy, sa18.xy, i1.xx, i2.zw
13: mov.f32 i2.xyzw, sa4.xyzw
14: mul.f32 i1.xyzw, sa16.xyzw, i2.xxxx
15: mad.f32 i1.xyzw, sa20.xyzw, i2.yyyy, i1.xyzw
16: mad.f32 i1.xyzw, sa24.xyzw, i2.zzzz, i1.xyzw
17: mad.f32 sa44.xy, sa28.xy, i2.ww, i1.xy
18: mad.f32 sa46.xy, sa30.xy, i2.ww, i1.zw
19: mov.f32 i1.xyzw, sa0.xyzw
20: mul.f32 i0.xyzw, sa16.xyzw, i1.xxxx
20: +mov.f32 sa4.xy, i1.yy
21: mad.f32 i0.xyzw, sa20.xyzw, i1.yyyy, i0.xyzw
22: mad.f32 i0.xyzw, sa24.xyzw, i1.zzzz, i0.xyzw
23: mad.f32 sa18.xy, sa28.xy, i1.ww, i0.xy
24: mad.f32 sa16.xy, sa30.xy, i1.ww, i0.zw
25: mov.f32 sa4.-y, i2.-y
26: mov.f32 sa6.xy, (sa8.y, sa12.y)
27: mov.f32 sa0.x, i1.x
28: mov.f32 sa0.-y, i2.-x
29: mov.f32 sa8.-y, sa12.-x
30: mov.f32 sa10.-y, sa14.-x
31: mov.f32 sa2.xy, sa8.xy
32: mov.f32 sa8.x, i1.z
33: mov.f32 sa8.-y, i2.-z
Primary program:
0 : mov.f32 o4.xy, pa8.xy
1 : mov.f32 i0.xyz, pa4.xyz
2 : mad.f32 i1.xyz, sa32.xyz, i0.xxx, {0, 0, 0}
3 : mad.f32 i1.xyz, sa36.xyz, i0.yyy, i1.xyz
4 : mad.f32 i0.xyz, sa40.xyz, i0.zzz, i1.xyz
5 : mov.f32 i1.xyz, pa0.xyz
6 : mov.f32 i2.xyzw, sa48.xyzw
7 : mad.f32 i2.xyzw, sa52.xyzw, i1.zzzz, i2.xyzw
8 : mad.f32 i2.xyzw, sa44.xyzw, i1.yyyy, i2.xyzw
9 : mad.f32 o0.xy, sa18.xy, i1.xx, i2.xy
10: mad.f32 o2.xy, sa16.xy, i1.xx, i2.zw
11: dot.f32 o6.x, sa0.xyzw, i1.xyz1
12: dot.f32 o6.-y, sa4.xyzw, i1.xyz1
13: dot.f32 o6.--z, sa8.xyzw, i1.xyz1
14: dot.f32 i1.x, i0.xyz, i0.xyz
15: rsq.f32 i1.x, i1.x
16: mad.f32 o10.xy, i0.yz, i1.xx, {0, 0}
17: mad.f32 o8.-y, i0.-x, i1.-x, {0, 0}

View File

@ -0,0 +1,11 @@
void main(
float2 aPosition : POSITION,
float2 aTexCoord : TEXCOORD0,
out float4 vPosition : POSITION,
out float2 vTexCoord : TEXCOORD0
) : POSITION {
vPosition = float4(aPosition, 1.f, 1.f);
vTexCoord = aTexCoord;
}

Binary file not shown.

View File

@ -0,0 +1,30 @@
Total estimated cost: 3 cycles, parallel mode
Register count: 8 PAs, 0 temps, 0 SAs *
Texture reads: 0 non-dependent, dependent: 0 unconditional, 0 conditional
High level analysis:
No warnings.
* Please refer to the Razor documentation for details regarding the meaning of these numbers. Decreasing the number of registers used will not necessarily increase performance
Instruction statistics:
Number of alu ops: 4
Number of mem ops: 0
Number of tex ops: 0
Number of floating point ops: 2
Number of integer ops: 0
Number of pack ops: 0
Number of mov ops: 1
Number of nop ops: 0
Vertex attributes:
pa0 = (float4) aPosition
pa4 = (float4) aTexCoord
Primary program:
0: mov.f32 o4.xy, pa4.xy
1: mul.f32 o0.xy, pa0.xy, {1, 1}
2: mul.f32 o2.xy, {1, 1}, {1, 1}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,91 @@
#ifndef INCLUDED_tlsf
#define INCLUDED_tlsf
/*
** Two Level Segregated Fit memory allocator, version 3.1.
** Written by Matthew Conte
** http://tlsf.baisoku.org
**
** Based on the original documentation by Miguel Masmano:
** http://www.gii.upv.es/tlsf/main/docs
**
** This implementation was written to the specification
** of the document, therefore no GPL restrictions apply.
**
** Copyright (c) 2006-2016, Matthew Conte
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the copyright holder nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL MATTHEW CONTE BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stddef.h>
#if defined(__cplusplus)
extern "C"
{
#endif
/* tlsf_t: a TLSF structure. Can contain 1 to N pools. */
/* pool_t: a block of memory that TLSF can manage. */
typedef void* tlsf_t;
typedef void* pool_t;
/* Create/destroy a memory pool. */
tlsf_t tlsf_create(void* mem);
tlsf_t tlsf_create_with_pool(void* mem, size_t bytes);
void tlsf_destroy(tlsf_t tlsf);
pool_t tlsf_get_pool(tlsf_t tlsf);
/* Add/remove memory pools. */
pool_t tlsf_add_pool(tlsf_t tlsf, void* mem, size_t bytes);
void tlsf_remove_pool(tlsf_t tlsf, pool_t pool);
/* malloc/memalign/realloc/free replacements. */
void* tlsf_malloc(tlsf_t tlsf, size_t bytes);
void* tlsf_memalign(tlsf_t tlsf, size_t align, size_t bytes);
void* tlsf_realloc(tlsf_t tlsf, void* ptr, size_t size);
void tlsf_free(tlsf_t tlsf, void* ptr);
/* Returns internal block size, not original request size */
size_t tlsf_block_size(void* ptr);
/* Overheads/limits of internal structures. */
size_t tlsf_size(void);
size_t tlsf_align_size(void);
size_t tlsf_block_size_min(void);
size_t tlsf_block_size_max(void);
size_t tlsf_pool_overhead(void);
size_t tlsf_alloc_overhead(void);
/* Debugging. */
typedef void (*tlsf_walker)(void* ptr, size_t size, int used, void* user);
void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user);
/* Returns nonzero if any internal consistency check fails. */
int tlsf_check(tlsf_t tlsf);
int tlsf_check_pool(pool_t pool);
#if defined(__cplusplus)
};
#endif
#endif

View File

@ -0,0 +1,48 @@
#pragma once
#include <SDL3/SDL_log.h>
#include <psp2/gxm.h>
#include <psp2/kernel/clib.h>
#ifdef DEBUG
#define DEBUG_ONLY_PRINTF(...) sceClibPrintf(__VA_ARGS__)
#else
#define DEBUG_ONLY_PRINTF(...)
#endif
#define SCE_ERR(func, ...) \
({ \
DEBUG_ONLY_PRINTF("%s\n", #func); \
int __sce_err_ret_val = func(__VA_ARGS__); \
if (__sce_err_ret_val < 0) { \
sceClibPrintf(#func " error: 0x%x\n", __sce_err_ret_val); \
} \
__sce_err_ret_val; \
})
#define ALIGN(x, a) (((x) + ((a) -1)) & ~((a) -1))
#define ALIGNMENT(n, a) (((a) - ((n) % (a))) % (a))
#define SET_UNIFORM(buffer, param, value) \
do { \
size_t __offset = sceGxmProgramParameterGetResourceIndex(param); \
void* __dst = (uint8_t*) (buffer) + (__offset * sizeof(uint32_t)); \
memcpy(__dst, reinterpret_cast<const void*>(&(value)), sizeof(value)); \
} while (0)
#define GET_SHADER_PARAM(var, gxp, name, ret) \
const SceGxmProgramParameter* var = sceGxmProgramFindParameterByName(gxp, name); \
if (!var) { \
SDL_Log("Failed to find param %s", name); \
return ret; \
}
static void printMatrix4x4(const float mat[4][4])
{
sceClibPrintf("mat4{\n");
for (int i = 0; i < 4; i++) {
sceClibPrintf("%f %f %f %f\n", mat[i][0], mat[i][1], mat[i][2], mat[i][3]);
}
sceClibPrintf("}\n");
}

View File

@ -20,6 +20,9 @@
#ifdef USE_SOFTWARE_RENDER
#include "d3drmrenderer_software.h"
#endif
#ifdef USE_GXM
#include "d3drmrenderer_gxm.h"
#endif
Direct3DRMRenderer* CreateDirect3DRMRenderer(
const IDirect3DMiniwin* d3d,
@ -66,6 +69,11 @@ Direct3DRMRenderer* CreateDirect3DRMRenderer(
if (SDL_memcmp(guid, &DirectX9_GUID, sizeof(GUID)) == 0) {
return DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
}
#endif
#ifdef USE_GXM
if (SDL_memcmp(guid, &GXM_GUID, sizeof(GUID)) == 0) {
return GXMRenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight, d3d->GetMSAASamples());
}
#endif
return nullptr;
}
@ -93,4 +101,7 @@ void Direct3DRMRenderer_EnumDevices(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICE
#ifdef USE_SOFTWARE_RENDER
Direct3DRMSoftware_EnumDevice(cb, ctx);
#endif
#ifdef USE_GXM
GXMRenderer_EnumDevice(cb, ctx);
#endif
}

View File

@ -0,0 +1,181 @@
#pragma once
#include "../d3drm/backends/gxm/gxm_context.h"
#include "d3drmrenderer.h"
#include "d3drmtexture_impl.h"
#include "ddpalette_impl.h"
#include "ddraw_impl.h"
#include <SDL3/SDL.h>
#include <psp2/gxm.h>
#include <psp2/kernel/clib.h>
#include <psp2/types.h>
#include <vector>
DEFINE_GUID(GXM_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x58, 0x4D);
#define GXM_VERTEX_BUFFER_COUNT 2
#define GXM_FRAGMENT_BUFFER_COUNT 3
#define GXM_WITH_RAZOR DEBUG
struct GXMTextureCacheEntry {
IDirect3DRMTexture* texture;
Uint32 version;
SceGxmTexture gxmTexture;
SceGxmNotification* notification; // latest frame it was used in
};
struct GXMMeshCacheEntry {
const MeshGroup* meshGroup;
int version;
bool flat;
void* meshData;
void* vertexBuffer;
void* indexBuffer;
uint16_t indexCount;
};
struct SceneLightGXM {
float color[4];
float vec[4];
float isDirectional;
float _align;
};
struct GXMSceneLightUniform {
SceneLightGXM lights[2];
float ambientLight[3];
};
class GXMRenderer : public Direct3DRMRenderer {
public:
static Direct3DRMRenderer* Create(DWORD width, DWORD height, DWORD msaaSamples);
GXMRenderer(DWORD width, DWORD height, SceGxmMultisampleMode msaaMode);
~GXMRenderer() override;
void PushLights(const SceneLight* lightsArray, size_t count) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
void SetFrustumPlanes(const Plane* frustumPlanes) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUi, float scaleX, float scaleY) override;
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
HRESULT BeginFrame() override;
void EnableTransparency() override;
void SubmitDraw(
DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
) override;
HRESULT FinalizeFrame() override;
void Resize(int width, int height, const ViewportTransform& viewportTransform) override;
void Clear(float r, float g, float b) override;
void Flip() override;
void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override;
void Download(SDL_Surface* target) override;
void SetDither(bool dither) override;
void DeferredDelete(int index);
private:
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
GXMMeshCacheEntry GXMUploadMesh(const MeshGroup& meshGroup);
void StartScene();
const SceGxmTexture* UseTexture(GXMTextureCacheEntry& texture);
inline GXMVertex2D* QuadVerticesBuffer()
{
GXMVertex2D* verts = &this->quadVertices[this->currentVertexBufferIndex][this->quadsUsed * 4];
this->quadsUsed += 1;
if (this->quadsUsed >= 50) {
SDL_Log("QuadVerticesBuffer overflow");
this->quadsUsed = 0; // declare bankruptcy
}
return verts;
}
inline GXMSceneLightUniform* LightsBuffer() { return this->lights[this->currentFragmentBufferIndex]; }
std::vector<GXMTextureCacheEntry> m_textures;
std::vector<GXMMeshCacheEntry> m_meshes;
D3DRMMATRIX4D m_projection;
std::vector<SceneLight> m_lights;
std::vector<SceGxmTexture> m_textures_delete[GXM_FRAGMENT_BUFFER_COUNT];
std::vector<void*> m_buffers_delete[GXM_FRAGMENT_BUFFER_COUNT];
bool transparencyEnabled = false;
// shader
SceGxmShaderPatcherId mainVertexProgramId;
SceGxmShaderPatcherId mainColorFragmentProgramId;
SceGxmShaderPatcherId mainTextureFragmentProgramId;
SceGxmVertexProgram* mainVertexProgram;
SceGxmFragmentProgram* opaqueColorFragmentProgram;
SceGxmFragmentProgram* blendedColorFragmentProgram;
SceGxmFragmentProgram* opaqueTextureFragmentProgram;
SceGxmFragmentProgram* blendedTextureFragmentProgram;
// main shader vertex uniforms
const SceGxmProgramParameter* uModelViewMatrix;
const SceGxmProgramParameter* uNormalMatrix;
const SceGxmProgramParameter* uProjectionMatrix;
// main shader fragment uniforms
const SceGxmProgramParameter* uShininess;
const SceGxmProgramParameter* uColor;
const SceGxmProgramParameter* uLights;
const SceGxmProgramParameter* uAmbientLight;
// uniforms / quad meshes
GXMSceneLightUniform* lights[GXM_FRAGMENT_BUFFER_COUNT];
GXMVertex2D* quadVertices[GXM_VERTEX_BUFFER_COUNT];
uint16_t* quadIndices;
int quadsUsed = 0;
bool cleared = false;
SceGxmNotification vertexNotifications[GXM_VERTEX_BUFFER_COUNT];
SceGxmNotification fragmentNotifications[GXM_FRAGMENT_BUFFER_COUNT];
int currentFragmentBufferIndex = 0;
int currentVertexBufferIndex = 0;
#ifdef GXM_WITH_RAZOR
bool last_dpad_up;
bool last_dpad_down;
bool last_dpad_left;
bool last_dpad_right;
#endif
bool m_initialized = false;
};
int gxm_library_init();
inline static void GXMRenderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx)
{
D3DDEVICEDESC halDesc = {};
halDesc.dcmColorModel = D3DCOLORMODEL::RGB;
halDesc.dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH;
halDesc.dwDeviceZBufferBitDepth = DDBD_16;
halDesc.dwDeviceZBufferBitDepth |= DDBD_32;
halDesc.dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE;
halDesc.dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND;
halDesc.dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR;
D3DDEVICEDESC helDesc = {};
helDesc.dwDeviceRenderBitDepth = DDBD_32;
int ret = gxm_library_init();
if (ret < 0) {
SDL_Log("gxm_library_init failed: %08x", ret);
return;
}
EnumDevice(cb, ctx, "GXM HAL", &halDesc, &helDesc, GXM_GUID);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<livearea style="a1" format-ver="01.00" content-rev="1">
<livearea-background>
<image>bg.png</image>
</livearea-background>
<gate>
<startup-image>gate.png</startup-image>
</gate>
<frame id="frame3">
<liveitem>
<image align="center" valign="top" x="0" y="0" height="0" origin="background">logo.png</image>
</liveitem>
</frame>
<frame id="frame2">
<liveitem>
<target>psla:-config</target>
<image>configure.png</image>
<text align="center" valign="center" x="0" y="-64" origin="background" text-align="center" text-valign="center">
<str color="#ff4500" bold="on" oblique="off" shadow="on" emboss="off">Configure</str>
</text>
</liveitem>
</frame>
</livearea>

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Some files were not shown because too many files have changed in this diff Show More