This commit is contained in:
aenu
2025-06-03 11:58:40 +08:00
commit 54e970ef90
11229 changed files with 5031933 additions and 0 deletions

24
.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
o/**
.gradle/
.idea/
local.properties
app/build.gradle
aps3e.keystore
aps3e.jks
app/release/
app/.cxx/
app/src/main/java/aenu/aps3e/R.java
app/src/main/cpp/ab/
app/src/main/cpp/ffmpeg_android/
app/src/main/cpp/iconv_out/
app/src/main/cpp/iso_t/
app/src/main/cpp/llvm_out/
app/src/main/cpp/ffmpeg_out/
app/src/main/cpp/glslang_out/
app/src/main/lib/

1
app/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

81
app/build.gradle.bak Normal file
View File

@@ -0,0 +1,81 @@
plugins {
alias(libs.plugins.android.application)
}
android {
namespace 'aenu.aps3e'
compileSdk 35
defaultConfig {
applicationId "aenu.aps3e"
//applicationId "aenu.aps3e.premium"
minSdk 28
targetSdk 34
versionCode 19
versionName "1.19a"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
abiFilters 'arm64-v8a'
cppFlags ''
}
}
sourceSets{
main {
//jniLibs.srcDirs = ['src/main/lib']
}
}
}
signingConfigs {
release {
}
debug {
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug {
minifyEnabled false
signingConfig signingConfigs.debug
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.22.1'
}
}
packaging{
jniLibs.useLegacyPackaging = true
}
}
dependencies {
implementation libs.appcompat
implementation libs.material
implementation libs.activity
implementation libs.constraintlayout
implementation libs.preference
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core
}

23
app/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,23 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keep class **.R$* { *; }
-keep class **.R { *; }

View File

@@ -0,0 +1,26 @@
package aenu.aps3e;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("aenu.aps3e", appContext.getPackageName());
}
}

View File

@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!--安卓高版本创建socket需要-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<application android:label="@string/app_name"
android:name="aenu.aps3e.Application"
android:allowNativeHeapPointerTagging="false"
android:icon="@drawable/app_icon"
android:isGame="true">
<activity android:name="aenu.aps3e.MainActivity"
android:exported="true"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="aenu.proptest.HelloJni"
android:exported="false"
android:label="@string/about">
</activity>
<activity android:name="aenu.aps3e.TextActivity"
android:exported="false">
</activity>
<activity android:name="aenu.aps3e.KeyMapActivity"
android:exported="false"
android:label="@string/key_mappers"/>
<activity android:name="aenu.aps3e.UserDataActivity"
android:theme="@style/Theme.AppCompat"
android:exported="false"/>
<activity android:name="aenu.aps3e.VirtualPadEdit"
android:screenOrientation="sensorLandscape"
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:exported="false"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:launchMode="singleTask"/>
<activity android:name="aenu.aps3e.EmulatorActivity"
android:screenOrientation="sensorLandscape"
android:launchMode="singleTask"
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:exported="false"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:process=":emu"
>
<intent-filter>
<action android:name="aenu.intent.action.APS3E" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name="aenu.aps3e.EmulatorSettings"
android:theme="@style/Theme.AppCompat"
android:exported="false"
android:label="@string/settings"/>
<provider
android:name="aenu.aps3e.DocumentsProvider"
android:authorities="${applicationId}.provider"
android:exported="true"
android:grantUriPermissions="true"
android:permission="android.permission.MANAGE_DOCUMENTS">
<intent-filter>
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
</intent-filter>
</provider>
<provider
android:name="aenu.aps3e.InnerDocumentsProvider"
android:authorities="${applicationId}.inner.provider"
android:exported="true"
android:grantUriPermissions="true"
android:permission="android.permission.MANAGE_DOCUMENTS">
<intent-filter>
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
</intent-filter>
</provider>
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -0,0 +1,245 @@
Core:
PPU Decoder: Recompiler (LLVM)
PPU Threads: 2
PPU Debug: false
PPU Calling History: false
Save LLVM logs: false
Use LLVM CPU: ""
Max LLVM Compile Threads: 4
LLVM Precompilation: true
Thread Scheduler Mode: Operating System
Set DAZ and FTZ: false
SPU Decoder: Recompiler (LLVM)
SPU Reservation Busy Waiting Percentage: 0
SPU GETLLAR Busy Waiting Percentage: 100
Disable SPU GETLLAR Spin Optimization: false
SPU Debug: false
MFC Debug: false
Preferred SPU Threads: 0
SPU delay penalty: 3
SPU loop detection: false
Max SPURS Threads: 6
SPU Block Size: Safe
Accurate SPU DMA: false
Accurate SPU Reservations: true
Accurate Cache Line Stores: false
Accurate RSX reservation access: false
RSX FIFO Accuracy: Fast
SPU Verification: true
SPU Cache: true
SPU Profiler: false
MFC Commands Shuffling Limit: 0
MFC Commands Timeout: 0
MFC Commands Shuffling In Steps: false
Enable TSX: Disabled
XFloat Accuracy: Approximate
Accurate PPU 128-byte Reservation Op Max Length: 0
Stub PPU Traps: 0
Precise SPU Verification: false
PPU LLVM Java Mode Handling: true
Use Accurate DFMA: true
PPU Set Saturation Bit: false
PPU Accurate Non-Java Mode: false
PPU Fixup Vector NaN Values: false
PPU Accurate Vector NaN Values: false
PPU Set FPCC Bits: false
Debug Console Mode: false
Hook static functions: false
Libraries Control: []
HLE lwmutex: false
SPU LLVM Lower Bound: 0
SPU LLVM Upper Bound: 18446744073709551615
TSX Transaction First Limit: 800
TSX Transaction Second Limit: 2000
Clocks scale: 100
SPU Wake-Up Delay: 0
SPU Wake-Up Delay Thread Mask: 63
Max CPU Preempt Count: 0
Allow RSX CPU Preemptions: true
Sleep Timers Accuracy: As Host
Usleep Time Addend: 0
Performance Report Threshold: 500
Enable Performance Report: false
Assume External Debugger: false
VFS:
Enable /host_root/: false
Initialize Directories: true
Limit disk cache size: false
Disk cache maximum size (MB): 5120
Empty /dev_hdd0/tmp/: true
Video:
Renderer: Vulkan
Resolution: 1280x720
Aspect ratio: 16:9
Frame limit: Auto
Second Frame Limit: 0
MSAA: Auto
Shader Mode: Async Shader Recompiler
Shader Precision: High
Write Color Buffers: false
Write Depth Buffer: false
Read Color Buffers: false
Read Depth Buffer: false
Handle RSX Memory Tiling: false
Log shader programs: false
VSync: false
Debug output: false
Debug overlay: false
Renderdoc Compatibility Mode: false
Use GPU texture scaling: false
Stretch To Display Area: false
Force High Precision Z buffer: false
Strict Rendering Mode: false
Disable ZCull Occlusion Queries: false
Disable Video Output: false
Disable Vertex Cache: false
Disable FIFO Reordering: false
Enable Frame Skip: false
Force CPU Blit: false
Disable On-Disk Shader Cache: false
Disable Vulkan Memory Allocator: false
Use full RGB output range: true
Strict Texture Flushing: false
Multithreaded RSX: false
Relaxed ZCULL Sync: false
Force Hardware MSAA Resolve: false
3D Display Mode: Disabled
Debug Program Analyser: false
Accurate ZCULL stats: true
Consecutive Frames To Draw: 1
Consecutive Frames To Skip: 1
Resolution Scale: 100
Anisotropic Filter Override: 0
Texture LOD Bias Addend: 0
Minimum Scalable Dimension: 16
Shader Compiler Threads: 0
Driver Recovery Timeout: 1000000
Driver Wake-Up Delay: 1
Vblank Rate: 60
Vblank NTSC Fixup: false
DECR memory layout: false
Allow Host GPU Labels: false
Disable Asynchronous Memory Manager: false
Output Scaling Mode: Bilinear
Vertex Buffer Upload Mode: Auto
Vulkan:
Adapter: ""
Force FIFO present mode: true
Exclusive Fullscreen Mode: Automatic
Asynchronous Texture Streaming 2: false
FidelityFX CAS Sharpening Intensity: 50
Asynchronous Queue Scheduler: Safe
VRAM allocation limit (MB): 16384
Use Custom Driver: false
Custom Driver Library Path: ""
Custom Driver Force Max Clocks: false
Performance Overlay:
Enabled: false
Enable Framerate Graph: false
Enable Frametime Graph: false
Framerate datapoints: 50
Frametime datapoints: 170
Detail level: Medium
Framerate graph detail level: All
Frametime graph detail level: All
Metrics update interval (ms): 350
Font size (px): 10
Position: Top Left
Font: n023055ms.ttf
Horizontal Margin (px): 50
Vertical Margin (px): 50
Center Horizontally: false
Center Vertically: false
Opacity (%): 70
Body Color (hex): "#FFE138FF"
Body Background (hex): "#002339FF"
Title Color (hex): "#F26C24FF"
Title Background (hex): "#00000000"
Shader Loading Dialog:
Allow custom background: true
Darkening effect strength: 30
Blur effect strength: 0
Audio:
Renderer: Cubeb
Audio Provider: CellAudio
RSXAudio Avport: HDMI 0
Dump to file: false
Convert to 16 bit: false
Audio Format: Stereo
Audio Formats: 0
Audio Channel Layout: Automatic
Audio Device: "@@@default@@@"
Master Volume: 100
Enable Buffering: true
Desired Audio Buffer Duration: 100
Enable Time Stretching: false
Disable Sampling Skip: false
Time Stretching Threshold: 75
Microphone Type: "Null"
Microphone Devices: "@@@@@@@@@@@@"
Music Handler: Qt
Input/Output:
Keyboard: "Null"
Mouse: Basic
Camera: "Null"
Camera type: Unknown
Camera flip: None
Camera ID: Default
Move: "Null"
Buzz emulated controller: "Null"
Turntable emulated controller: "Null"
GHLtar emulated controller: "Null"
Pad handler mode: Single-threaded
Keep pads connected: false
Pad handler sleep (microseconds): 1000
Background input enabled: true
Show move cursor: false
Lock overlay input to player one: false
Emulated Midi devices: ßßß@@@ßßß@@@ßßß@@@
Load SDL GameController Mappings: true
IO Debug overlay: false
System:
License Area: SCEA
Language: English (US)
Keyboard Type: English keyboard (US standard)
Enter button assignment: Enter with cross
System Name: RPCS3-255
PSID high: 0
PSID low: 0
HDD Model Name: ""
HDD Serial Number: ""
Net:
Internet enabled: Disconnected
IP address: 0.0.0.0
Bind address: 0.0.0.0
DNS address: 8.8.8.8
IP swap list: ""
UPNP Enabled: false
PSN status: Disconnected
PSN Country: us
Savestate:
Start Paused: false
Suspend Emulation Savestate Mode: false
Compatible Savestate Mode: false
Inspection Mode Savestates: false
Save Disc Game Data: false
Miscellaneous:
Automatically start games after boot: true
Exit RPCS3 when process finishes: false
Pause emulation on RPCS3 focus loss: false
Start games in fullscreen mode: false
Show trophy popups: true
Show RPCN popups: true
Show shader compilation hint: true
Show PPU compilation hint: true
Show pressure intensity toggle hint: true
Show analog limiter toggle hint: true
Show autosave/autoload hint: false
Use native user interface: true
GDB Server: 127.0.0.1:2345
Silence All Logs: false
Window Title Format: "FPS: %F | %R | %V | %T [%t]"
Pause Emulation During Home Menu: false
Font File Selection: From Firmware
Custom Font File Path: ""
Log: {}

View File

@@ -0,0 +1,55 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html.
# For more examples on how to use CMake, see https://github.com/android/ndk-samples.
# Sets the minimum CMake version required for this project.
cmake_minimum_required(VERSION 3.22.1)
# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
# Since this is the top level CMakeLists.txt, the project name is also accessible
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
# build script scope).
project("aps3e")
add_compile_options(-march=armv8-a)
add_compile_options(-stdlib=libc++)
#add_compile_options(-flto=thin)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_link_options(-Wl,-z,max-page-size=16384)
set(CMAKE_CXX_STANDARD 20)
project(aps3e LANGUAGES C CXX)
add_library(lang_System SHARED lang_System.cpp)
add_subdirectory(rpcs3 EXCLUDE_FROM_ALL)
add_library(emu SHARED)
set_target_properties(emu PROPERTIES OUTPUT_NAME "e")
target_link_options(emu PRIVATE -Wl,--exclude-libs,ALL)
#target_compile_options(emu PRIVATE -flto)
#target_link_options(emu PRIVATE -flto)
target_sources(emu
PRIVATE
rpcs3/rpcs3/Input/raw_mouse_config.cpp
rpcs3/rpcs3/Input/raw_mouse_handler.cpp
rpcs3/rpcs3/Input/product_info.cpp
rpcs3/rpcs3/rpcs3_version.cpp
rpcs3/rpcs3/stb_image.cpp
rpcs3/rpcs3/stdafx.cpp
aps3e.cpp
iso.cpp
vkapi.cpp
vkutil.cpp
cpuinfo.cpp
glsl2spv.cpp
)
target_link_libraries(emu PRIVATE rpcs3_emu)
target_link_libraries(emu PRIVATE 3rdparty::yaml-cpp 3rdparty::hidapi 3rdparty::libusb 3rdparty::wolfssl 3rdparty::libcurl)
target_link_libraries(emu PRIVATE android)

1965
app/src/main/cpp/aps3e.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,408 @@
//
// Created by aenu on 2025/6/2.
// SPDX-License-Identifier: WTFPL
//
static_assert(sizeof(YAML::Node*)==8,"");
static YAML::Node* open_config_file(JNIEnv* env,jobject self,jstring config_path){
jboolean is_copy=false;
const char* path=env->GetStringUTFChars(config_path,&is_copy);
YAML::Node* config_node = new YAML::Node(YAML::LoadFile(path));
env->ReleaseStringUTFChars(config_path,path);
return config_node;
}
static jstring load_config_entry(JNIEnv* env,jobject self,YAML::Node* config_node,jstring tag){
jboolean is_copy=false;
const char* tag_cstr=env->GetStringUTFChars(tag,&is_copy);
std::string tag_str(tag_cstr);
env->ReleaseStringUTFChars(tag,tag_cstr);
size_t pos=tag_str.find('|');
std::string parent=tag_str.substr(0,pos);
std::string child=tag_str.substr(pos+1);
switch(std::count(child.begin(),child.end(),'|')){
case 0: {
YAML::Node node=(*config_node)[parent][child];
if(node.IsDefined())
return env->NewStringUTF(node.as<std::string>().c_str());
}
break;
case 1:{
pos=child.find('|');
std::string child2=child.substr(pos+1);
child=child.substr(0,pos);
YAML::Node node=(*config_node)[parent][child][child2];
if(node.IsDefined())
return env->NewStringUTF(node.as<std::string>().c_str());
}
break;
#if 0
case 2:{
pos=child.find('|');
std::string child2=child.substr(pos+1);
child=child.substr(0,pos);
pos=child2.find('|');
std::string child3=child2.substr(pos+1);
child2=child2.substr(0,pos);
YAML::Node node=(*config_node)[parent][child][child2][child3];
if(node.IsDefined())
return env->NewStringUTF(node.as<std::string>().c_str());
}
break;
#endif
default:
aps3e_log.error("load_config_entry fail %s",tag_str.c_str());
LOGE("load_config_entry fail %s",tag_str.c_str());
break;
}
return NULL;
}
static void save_config_entry(JNIEnv* env,jobject self,YAML::Node* config_node,jstring tag,jstring val){
jboolean is_copy=false;
const char* tag_cstr=env->GetStringUTFChars(tag,&is_copy);
std::string tag_str(tag_cstr);
env->ReleaseStringUTFChars(tag,tag_cstr);
size_t pos=tag_str.find('|');
std::string parent=tag_str.substr(0,pos);
std::string child=tag_str.substr(pos+1);
const char* val_cstr=env->GetStringUTFChars(val,&is_copy);
switch(std::count(child.begin(),child.end(),'|')){
case 0: {
(*config_node)[parent][child] = std::string(val_cstr);
}
break;
case 1:{
pos=child.find('|');
std::string child2=child.substr(pos+1);
child=child.substr(0,pos);
(*config_node)[parent][child][child2]=std::string(val_cstr);
}
break;
#if 0
case 2:{
pos=child.find('|');
std::string child2=child.substr(pos+1);
child=child.substr(0,pos);
pos=child2.find('|');
std::string child3=child2.substr(pos+1);
child2=child2.substr(0,pos);
(*config_node)[parent][child][child2][child3]=std::string(val_cstr);
}
break;
#endif
default:
aps3e_log.error("save_config_entry fail %s",tag_str.c_str());
LOGE("save_config_entry fail %s",tag_str.c_str());
break;
}
env->ReleaseStringUTFChars(val,val_cstr);
}
static void close_config_file(JNIEnv* env,jobject self,YAML::Node* config_node,jstring config_path){
YAML::Emitter out;
out << *config_node;
jboolean is_copy=false;
const char* path=env->GetStringUTFChars(config_path,&is_copy);
std::ofstream fout(path);
fout << out.c_str();
fout.close();
env->ReleaseStringUTFChars(config_path,path);
delete config_node;
}
auto gen_key=[](const std::string& name)->std::string{
std::string k=name;
if(size_t p=k.find("(");p!=std::string::npos){
k=k.substr(0,p);
}
//replace(' ','_');
//replace('/','_')
for(auto& c:k){
if(c==' '){
c='_';
}
else if(c=='/'){
c='_';
}
else if(c=='|'){
c='_';
}
}
//replace("-","");
size_t p=k.find("-");
while(p!=std::string::npos){
k.erase(p,1);
p=k.find("-");
}
//移除尾部的_
while (k.at(k.size()-1)=='_'){
k.erase(k.size()-1,1);
}
std::transform(k.begin(),k.end(),k.begin(),[](char c){
return std::tolower(c);
});
return k;
};
static jstring generate_config_xml(JNIEnv* env,jobject self){
auto gen_one_preference=[&](const std::string parent_name,cfg::_base* node)->std::string{
std::stringstream out;
std::string parent_name_l=gen_key(parent_name);
const std::string& name=node->get_name();
const std::string key=gen_key(name);
switch (node->get_type()) {
case cfg::type::_bool:
out<<"<CheckBoxPreference app:title=\"@string/emulator_settings_"<<parent_name_l<<"_"<<key<<"\" \n";
out<<"app:key=\""<<parent_name<<"|"<<name<<"\" />\n";
break;
case cfg::type::_int:
case cfg::type::uint:
out<<"<SeekBarPreference app:title=\"@string/emulator_settings_"<<parent_name_l<<"_"<<key<<"\" \n";
out<<"app:min=\""<<node->get_min()<<"\"\n";
if(node->get_max()!=-1)
out<<"android:max=\""<<node->get_max()<<"\"\n";
else
out<<"android:max=\"0x7fffffff\"\n";
out<<"app:showSeekBarValue=\"true\"\n";
out<<"app:key=\""<<parent_name<<"|"<<name<<"\" />\n";
break;
case cfg::type::_enum:
out<<"<ListPreference app:title=\"@string/emulator_settings_"<<parent_name_l<<"_"<<key<<"\" \n";
out<<"app:entries=\""<<"@array/"<<parent_name_l<<"_"<<key<<"_entries\"\n";
out<<"app:entryValues=\""<<"@array/"<<parent_name_l<<"_"<<key<<"_values\"\n";
out<<"app:key=\""<<parent_name<<"|"<<name<<"\" />\n";
break;
default:
out<<"<PreferenceScreen app:title=\"@string/emulator_settings_"<<parent_name_l<<"_"<<key<<"\"\n";
out<<"app:key=\""<<parent_name<<"|"<<name<<"\" />\n";
break;
}
return out.str();
};
std::ostringstream out;
out<<R"(
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
)";
for(auto n:g_cfg.get_nodes()){
const std::string& name=n->get_name();
if(name=="Core"||name=="Video"||name=="Audio"||name=="Input/Output"||name=="System"
||name=="Net"||name=="Savestate"||name=="Miscellaneous"){
out<<" <PreferenceScreen app:title=\"@string/emulator_settings_"<<gen_key(name)<<"\" \n";
out<<"app:key=\""<<name<<"\" >\n";
for(auto n2:reinterpret_cast<cfg::node*>(n)->get_nodes()){
//Video下的3个子项
if(n2->get_type()==cfg::type::node){
out<<"<PreferenceScreen app:title=\"@string/emulator_settings_"<<gen_key(name)<<"_"<<gen_key(n2->get_name())<<"\" \n";
out<<"app:key=\""<<name+"|"+n2->get_name()<<"\" >\n";
for(auto n3:reinterpret_cast<cfg::node*>(n2)->get_nodes()) {
out << "\n" << gen_one_preference(name+"|"+n2->get_name(), n3) << "\n";
}
out<<"</PreferenceScreen>\n";
}
else{
out<<"\n"<< gen_one_preference(name,n2)<<"\n";
}
}
out<<"</PreferenceScreen>\n";
}
}
out<<"</PreferenceScreen>\n";
return env->NewStringUTF(out.str().c_str());
}
//public native String generate_strings_xml();
static jstring generate_strings_xml(JNIEnv* env,jobject self){
auto gen_one_string=[&](const std::string parent_name,cfg::_base* node)->std::string{
std::stringstream out;
std::string parent_name_l=gen_key(parent_name);
const std::string& name=node->get_name();
const std::string key=gen_key(name);
out<<"<string name=\"emulator_settings_"<<parent_name_l<<"_"<<key<<"\">"<<name<<"</string>\n";
if(node->get_type()==cfg::type::_enum){
out<<"<string-array name=\""<<parent_name_l<<"_"<<key<<"_entries\">\n";
std::vector<std::string> list=node->to_list();
for(const auto& e:list){
out<<"<item>"<<e<<"</item>\n";
}
out<<"</string-array>\n";
}
return out.str();
};
std::ostringstream out;
for(auto n:g_cfg.get_nodes()){
const std::string& name=n->get_name();
if(name=="Core"||name=="Video"||name=="Audio"||name=="Input/Output"||name=="System"
||name=="Net"||name=="Savestate"||name=="Miscellaneous"){
out<<"<string name=\"emulator_settings_"<<gen_key(name)<<"\">"<<name<<"</string>\n";
for(auto n2:reinterpret_cast<cfg::node*>(n)->get_nodes()){
//Video下的3个子项
if(n2->get_type()==cfg::type::node){
out<<"<string name=\"emulator_settings_"<<gen_key(name+"|"+n2->get_name())<<"\">"<<n2->get_name()<<"</string>\n";
for(auto n3:reinterpret_cast<cfg::node*>(n2)->get_nodes()) {
out << gen_one_string(name+"|"+n2->get_name(), n3);
}
}
else{
out<< gen_one_string(name,n2);
}
}
}
}
//array
for(auto n:g_cfg.get_nodes()){
const std::string& name=n->get_name();
if(name=="Core"||name=="Video"||name=="Audio"||name=="Input/Output"||name=="System"
||name=="Net"||name=="Savestate"||name=="Miscellaneous"){
for(auto n2:reinterpret_cast<cfg::node*>(n)->get_nodes()){
switch (n2->get_type()) {
case cfg::type::_enum: {
out << "<string-array name=\"" << gen_key(name + "|" + n2->get_name())
<< "_values\">\n";
std::vector<std::string> list = n2->to_list();
for (const auto &e: list) {
out << "<item>" << e << "</item>\n";
}
out << "</string-array>\n";
break;
}
//Video下的3个子项
case cfg::type::node:{
for(auto n3:reinterpret_cast<cfg::node*>(n2)->get_nodes()) {
out << "<string-array name=\""<<gen_key(name+"|"+n2->get_name()+"|"+n3->get_name())<<"_values\">\n";
std::vector<std::string> list=n3->to_list();
for(const auto& e:list){
out<<"<item>"<<e<<"</item>\n";
}
out<<"</string-array>\n";
}
break;
}
default:
break;
}
}
}
}
return env->NewStringUTF(out.str().c_str());
}
static jstring generate_java_string_arr(JNIEnv* env,jobject self){
auto gen_one_key_string=[&](const std::string parent_name,cfg::_base* node,cfg::type test_ty)->std::string{
std::string r="";
if(node->get_type()==test_ty){
return r+"\""+parent_name+"|"+node->get_name()+"\",\n";
}
return r;
};
auto gen_one_key_array=[&](const std::string prefix,cfg::type test_ty)->std::string{
std::ostringstream out;
out<<prefix<<"\n";
for(auto n:g_cfg.get_nodes()){
const std::string& name=n->get_name();
if(name=="Core"||name=="Video"||name=="Audio"||name=="Input/Output"||name=="System"
||name=="Net"||name=="Savestate"||name=="Miscellaneous"){
for(auto n2:reinterpret_cast<cfg::node*>(n)->get_nodes()){
//Video下的3个子项
if(n2->get_type()==cfg::type::node){
for(auto n3:reinterpret_cast<cfg::node*>(n2)->get_nodes()) {
out << gen_one_key_string(name+"|"+n2->get_name(), n3,test_ty);
}
}
else{
out<< gen_one_key_string(name,n2,test_ty);
}
}
}
}
out<<"};\n";
return out.str();
};
auto gen_node_key_array=[&]()->std::string{
std::ostringstream out;
out<<"final String[] NODE_KEYS={\n";
for(auto n:g_cfg.get_nodes()){
const std::string& name=n->get_name();
if(name=="Core"||name=="Video"||name=="Audio"||name=="Input/Output"||name=="System"
||name=="Net"||name=="Savestate"||name=="Miscellaneous"){
out<<"\""<<name<<"\",\n";
for(auto n2:reinterpret_cast<cfg::node*>(n)->get_nodes()){
//Video下的3个子项
if(n2->get_type()==cfg::type::node){
out<<"\""<<name+"|"+n2->get_name()<<"\",\n";
}
}
}
}
out<<"};\n";
return out.str();
};
std::ostringstream out;
out<<gen_one_key_array("final String[] BOOL_KEYS={",cfg::type::_bool);
out<<gen_one_key_array("final String[] INT_KEYS={",cfg::type::_int);
out<<gen_one_key_array("final String[] INT_KEYS={",cfg::type::uint);
out<<gen_one_key_array("final String[] STRING_ARR_KEYS={",cfg::type::_enum);
//
out<<gen_node_key_array();
return env->NewStringUTF(out.str().c_str());
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,669 @@
extern void pad_state_notify_state_change(usz index, u32 state);
extern bool is_input_allowed();
extern std::string g_input_config_override;
namespace pad
{
atomic_t<pad_thread*> g_current = nullptr;
shared_mutex g_pad_mutex;
std::string g_title_id;
atomic_t<bool> g_started{false};
atomic_t<bool> g_reset{false};
atomic_t<bool> g_enabled{true};
atomic_t<bool> g_home_menu_requested{false};
}
namespace rsx
{
void set_native_ui_flip();
}
struct pad_setting
{
u32 port_status = 0;
u32 device_capability = 0;
u32 device_type = 0;
bool is_ldd_pad = false;
};
pad_thread::pad_thread(void* curthread, void* curwindow, std::string_view title_id) : m_curthread(curthread), m_curwindow(curwindow)
{
pad::g_title_id = title_id;
pad::g_current = this;
pad::g_started = false;
}
pad_thread::~pad_thread()
{
pad::g_current = nullptr;
}
void pad_thread::Init()
{
std::lock_guard lock(pad::g_pad_mutex);
// Cache old settings if possible
std::array<pad_setting, CELL_PAD_MAX_PORT_NUM> pad_settings;
for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; i++) // max 7 pads
{
if (m_pads[i])
{
pad_settings[i] =
{
m_pads[i]->m_port_status,
m_pads[i]->m_device_capability,
m_pads[i]->m_device_type,
m_pads[i]->ldd
};
}
else
{
pad_settings[i] =
{
CELL_PAD_STATUS_DISCONNECTED,
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_ACTUATOR,
CELL_PAD_DEV_TYPE_STANDARD,
false
};
}
}
num_ldd_pad = 0;
m_info.now_connect = 0;
m_handlers.clear();
g_cfg_input_configs.load();
std::string active_config = g_cfg_input_configs.active_configs.get_value(pad::g_title_id);
if (active_config.empty())
{
active_config = g_cfg_input_configs.active_configs.get_value(g_cfg_input_configs.global_key);
}
input_log.notice("Using input configuration: '%s' (override='%s')", active_config, g_input_config_override);
// Load in order to get the pad handlers
if (!g_cfg_input.load(pad::g_title_id, active_config))
{
input_log.notice("Loaded empty pad config");
}
// Adjust to the different pad handlers
for (usz i = 0; i < g_cfg_input.player.size(); i++)
{
std::shared_ptr<PadHandlerBase> handler;
pad_thread::InitPadConfig(g_cfg_input.player[i]->config, g_cfg_input.player[i]->handler, handler);
}
// Reload with proper defaults
if (!g_cfg_input.load(pad::g_title_id, active_config))
{
input_log.notice("Reloaded empty pad config");
}
input_log.trace("Using pad config:\n%s", g_cfg_input);
std::shared_ptr<AndroidVirtualPadHandler> keyptr;
// Always have a Null Pad Handler
std::shared_ptr<NullPadHandler> nullpad = std::make_shared<NullPadHandler>();
m_handlers.emplace(pad_handler::null, nullpad);
for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; i++) // max 7 pads
{
cfg_player* cfg = g_cfg_input.player[i];
std::shared_ptr<PadHandlerBase> cur_pad_handler;
const pad_handler handler_type = pad_settings[i].is_ldd_pad ? pad_handler::null : cfg->handler.get();
if (m_handlers.contains(handler_type))
{
cur_pad_handler = m_handlers[handler_type];
}
else
{
if (handler_type == pad_handler::keyboard)
{
keyptr = std::make_shared<AndroidVirtualPadHandler>();
//keyptr->moveToThread(static_cast<QThread*>(m_curthread));
//keyptr->SetTargetWindow(static_cast<QWindow*>(m_curwindow));
cur_pad_handler = keyptr;
}
else
{
cur_pad_handler = GetHandler(handler_type);
}
m_handlers.emplace(handler_type, cur_pad_handler);
}
cur_pad_handler->Init();
std::shared_ptr<Pad> pad = std::make_shared<Pad>(handler_type, i, CELL_PAD_STATUS_DISCONNECTED, pad_settings[i].device_capability, pad_settings[i].device_type);
m_pads[i] = pad;
if (pad_settings[i].is_ldd_pad)
{
InitLddPad(i, &pad_settings[i].port_status);
}
else
{
if (!cur_pad_handler->bindPadToDevice(pad))
{
// Failed to bind the device to cur_pad_handler so binds to NullPadHandler
input_log.error("Failed to bind device '%s' to handler %s. Falling back to NullPadHandler.", cfg->device.to_string(), handler_type);
nullpad->bindPadToDevice(pad);
}
input_log.notice("Pad %d: device='%s', handler=%s, VID=0x%x, PID=0x%x, class_type=0x%x, class_profile=0x%x",
i, cfg->device.to_string(), pad->m_pad_handler, pad->m_vendor_id, pad->m_product_id, pad->m_class_type, pad->m_class_profile);
if (pad->m_pad_handler != pad_handler::null)
{
input_log.notice("Pad %d: config=\n%s", i, cfg->to_string());
}
}
pad->is_fake_pad = (g_cfg.io.move == move_handler::fake && i >= (static_cast<u32>(CELL_PAD_MAX_PORT_NUM) - static_cast<u32>(CELL_GEM_MAX_NUM)))
|| (pad->m_class_type >= CELL_PAD_FAKE_TYPE_FIRST && pad->m_class_type < CELL_PAD_FAKE_TYPE_LAST);
connect_usb_controller(i, input::get_product_by_vid_pid(pad->m_vendor_id, pad->m_product_id));
}
// Initialize active mouse and keyboard. Activate pad handler if one exists.
input::set_mouse_and_keyboard(m_handlers.contains(pad_handler::keyboard) ? input::active_mouse_and_keyboard::pad : input::active_mouse_and_keyboard::emulated);
}
void pad_thread::SetRumble(const u32 pad, u8 large_motor, bool small_motor)
{
if (pad >= m_pads.size())
return;
m_pads[pad]->m_vibrateMotors[0].m_value = large_motor;
m_pads[pad]->m_vibrateMotors[1].m_value = small_motor ? 255 : 0;
}
void pad_thread::SetIntercepted(bool intercepted)
{
if (intercepted)
{
m_info.system_info |= CELL_PAD_INFO_INTERCEPTED;
m_info.ignore_input = true;
}
else
{
m_info.system_info &= ~CELL_PAD_INFO_INTERCEPTED;
}
}
void pad_thread::update_pad_states()
{
for (usz i = 0; i < m_pads.size(); i++)
{
const auto& pad = m_pads[i];
const bool connected = pad && !pad->is_fake_pad && !!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED);
if (m_pads_connected[i] == connected)
continue;
pad_state_notify_state_change(i, connected ? CELL_PAD_STATUS_CONNECTED : CELL_PAD_STATUS_DISCONNECTED);
m_pads_connected[i] = connected;
}
}
namespace aps3e_emu{
extern pthread_mutex_t key_event_mutex;
}
void pad_thread::operator()()
{
Init();
const bool is_vsh = Emu.IsVsh();
pad::g_reset = false;
pad::g_started = true;
bool mode_changed = true;
atomic_t<pad_handler_mode> pad_mode{g_cfg.io.pad_mode.get()};
std::vector<std::unique_ptr<named_thread<std::function<void()>>>> threads;
const auto stop_threads = [&threads]()
{
input_log.notice("Stopping pad threads...");
for (auto& thread : threads)
{
if (thread)
{
auto& enumeration_thread = *thread;
enumeration_thread = thread_state::aborting;
enumeration_thread();
}
}
threads.clear();
input_log.notice("Pad threads stopped");
};
const auto start_threads = [this, &threads, &pad_mode]()
{
if (pad_mode == pad_handler_mode::single_threaded)
{
return;
}
input_log.notice("Starting pad threads...");
for (const auto& handler : m_handlers)
{
if (handler.first == pad_handler::null)
{
continue;
}
threads.push_back(std::make_unique<named_thread<std::function<void()>>>(fmt::format("%s Thread", handler.second->m_type), [&handler = handler.second, &pad_mode]()
{
while (thread_ctrl::state() != thread_state::aborting)
{
if (!pad::g_enabled || !is_input_allowed())
{
thread_ctrl::wait_for(30'000);
continue;
}
handler->process();
u64 pad_sleep = g_cfg.io.pad_sleep;
if (Emu.IsPaused())
{
pad_sleep = std::max<u64>(pad_sleep, 30'000);
}
thread_ctrl::wait_for(pad_sleep);
}
}));
}
input_log.notice("Pad threads started");
};
while (thread_ctrl::state() != thread_state::aborting)
{
if (!pad::g_enabled || !is_input_allowed())
{
m_resume_emulation_flag = false;
m_mask_start_press_to_resume = 0;
thread_ctrl::wait_for(30'000);
continue;
}
// Update variables
const bool needs_reset = pad::g_reset && pad::g_reset.exchange(false);
const pad_handler_mode new_pad_mode = g_cfg.io.pad_mode.get();
mode_changed |= new_pad_mode != pad_mode.exchange(new_pad_mode);
// Reset pad handlers if necessary
if (needs_reset || mode_changed)
{
mode_changed = false;
stop_threads();
if (needs_reset)
{
Init();
}
else
{
input_log.success("The pad mode was changed to %s", pad_mode.load());
}
start_threads();
}
u32 connected_devices = 0;
if (pad_mode == pad_handler_mode::single_threaded)
{
pthread_mutex_lock(&aps3e_emu::key_event_mutex);
for (auto& handler : m_handlers)
{
handler.second->process();
connected_devices += handler.second->connected_devices;
}
pthread_mutex_unlock(&aps3e_emu::key_event_mutex);
}
else
{
for (auto& handler : m_handlers)
{
connected_devices += handler.second->connected_devices;
}
}
if (Emu.IsRunning())
{
update_pad_states();
}
m_info.now_connect = connected_devices + num_ldd_pad;
// The ignore_input section is only reached when a dialog was closed and the pads are still intercepted.
// As long as any of the listed buttons is pressed, cellPadGetData will ignore all input (needed for Hotline Miami).
// ignore_input was added because if we keep the pads intercepted, then some games will enter the menu due to unexpected system interception (tested with Ninja Gaiden Sigma).
if (m_info.ignore_input && !(m_info.system_info & CELL_PAD_INFO_INTERCEPTED))
{
bool any_button_pressed = false;
for (usz i = 0; i < m_pads.size() && !any_button_pressed; i++)
{
const auto& pad = m_pads[i];
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
continue;
for (const auto& button : pad->m_buttons)
{
if (button.m_pressed && (
button.m_outKeyCode == CELL_PAD_CTRL_CROSS ||
button.m_outKeyCode == CELL_PAD_CTRL_CIRCLE ||
button.m_outKeyCode == CELL_PAD_CTRL_TRIANGLE ||
button.m_outKeyCode == CELL_PAD_CTRL_SQUARE ||
button.m_outKeyCode == CELL_PAD_CTRL_START ||
button.m_outKeyCode == CELL_PAD_CTRL_SELECT))
{
any_button_pressed = true;
break;
}
}
}
if (!any_button_pressed)
{
m_info.ignore_input = false;
}
}
// Handle home menu if requested
if (!is_vsh && !m_home_menu_open && Emu.IsRunning())
{
bool ps_button_pressed = false;
for (usz i = 0; i < m_pads.size() && !ps_button_pressed; i++)
{
if (i > 0 && g_cfg.io.lock_overlay_input_to_player_one)
break;
const auto& pad = m_pads[i];
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
continue;
// Check if an LDD pad pressed the PS button (bit 0 of the first button)
// NOTE: Rock Band 3 doesn't seem to care about the len. It's always 0.
if (pad->ldd /*&& pad->ldd_data.len >= 1 */&& !!(pad->ldd_data.button[0] & CELL_PAD_CTRL_LDD_PS))
{
ps_button_pressed = true;
break;
}
for (const auto& button : pad->m_buttons)
{
if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1 && button.m_outKeyCode == CELL_PAD_CTRL_PS && button.m_pressed)
{
ps_button_pressed = true;
break;
}
}
}
// Make sure we call this function only once per button press
if ((ps_button_pressed && !m_ps_button_pressed) || pad::g_home_menu_requested.exchange(false))
{
open_home_menu();
}
m_ps_button_pressed = ps_button_pressed;
}
// Handle paused emulation (if triggered by home menu).
if (m_home_menu_open && g_cfg.misc.pause_during_home_menu)
{
// Reset resume control if the home menu is open
m_resume_emulation_flag = false;
m_mask_start_press_to_resume = 0;
m_track_start_press_begin_timestamp = 0;
// Update UI
rsx::set_native_ui_flip();
thread_ctrl::wait_for(33'000);
continue;
}
if (m_resume_emulation_flag)
{
m_resume_emulation_flag = false;
Emu.BlockingCallFromMainThread([]()
{
Emu.Resume();
});
}
u64 pad_sleep = g_cfg.io.pad_sleep;
if (Emu.GetStatus(false) == system_state::paused)
{
pad_sleep = std::max<u64>(pad_sleep, 30'000);
u64 timestamp = get_system_time();
u32 pressed_mask = 0;
for (usz i = 0; i < m_pads.size(); i++)
{
const auto& pad = m_pads[i];
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
continue;
for (const auto& button : pad->m_buttons)
{
if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1 && button.m_outKeyCode == CELL_PAD_CTRL_START && button.m_pressed)
{
pressed_mask |= 1u << i;
break;
}
}
}
m_mask_start_press_to_resume &= pressed_mask;
if (!pressed_mask || timestamp - m_track_start_press_begin_timestamp >= 700'000)
{
m_track_start_press_begin_timestamp = timestamp;
if (std::exchange(m_mask_start_press_to_resume, u32{umax}))
{
m_mask_start_press_to_resume = 0;
m_track_start_press_begin_timestamp = 0;
//sys_log.success("Resuming emulation using the START button in a few seconds...");
auto msg_ref = std::make_shared<atomic_t<u32>>(1);
rsx::overlays::queue_message(localized_string_id::EMULATION_RESUMING, 2'000'000, msg_ref);
m_resume_emulation_flag = true;
for (u32 i = 0; i < 40; i++)
{
if (Emu.GetStatus(false) != system_state::paused)
{
// Abort if emulation has been resumed by other means
m_resume_emulation_flag = false;
msg_ref->release(0);
break;
}
thread_ctrl::wait_for(50'000);
rsx::set_native_ui_flip();
}
}
}
}
else
{
// Reset resume control if caught a state of unpaused emulation
m_mask_start_press_to_resume = 0;
m_track_start_press_begin_timestamp = 0;
}
thread_ctrl::wait_for(pad_sleep);
}
stop_threads();
}
void pad_thread::InitLddPad(u32 handle, const u32* port_status)
{
if (handle >= m_pads.size())
{
return;
}
static const input::product_info product = input::get_product_info(input::product_type::playstation_3_controller);
m_pads[handle]->ldd = true;
m_pads[handle]->Init
(
port_status ? *port_status : CELL_PAD_STATUS_CONNECTED | CELL_PAD_STATUS_ASSIGN_CHANGES | CELL_PAD_STATUS_CUSTOM_CONTROLLER,
CELL_PAD_CAPABILITY_PS3_CONFORMITY,
CELL_PAD_DEV_TYPE_LDD,
CELL_PAD_PCLASS_TYPE_STANDARD,
product.pclass_profile,
product.vendor_id,
product.product_id,
50
);
input_log.notice("Pad %d: LDD, VID=0x%x, PID=0x%x, class_type=0x%x, class_profile=0x%x",
handle, m_pads[handle]->m_vendor_id, m_pads[handle]->m_product_id, m_pads[handle]->m_class_type, m_pads[handle]->m_class_profile);
num_ldd_pad++;
}
s32 pad_thread::AddLddPad()
{
// Look for first null pad
for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; i++)
{
if (g_cfg_input.player[i]->handler == pad_handler::null && !m_pads[i]->ldd)
{
InitLddPad(i, nullptr);
return i;
}
}
return -1;
}
void pad_thread::UnregisterLddPad(u32 handle)
{
ensure(handle < m_pads.size());
m_pads[handle]->ldd = false;
num_ldd_pad--;
}
std::shared_ptr<PadHandlerBase> pad_thread::GetHandler(pad_handler type)
{
switch (type)
{
case pad_handler::null:
return std::make_shared<NullPadHandler>();
case pad_handler::keyboard:
return std::make_shared<AndroidVirtualPadHandler>();
/*case pad_handler::ds3:
return std::make_shared<ds3_pad_handler>();
case pad_handler::ds4:
return std::make_shared<ds4_pad_handler>();
case pad_handler::dualsense:
return std::make_shared<dualsense_pad_handler>();
case pad_handler::skateboard:
return std::make_shared<skateboard_pad_handler>();
#ifdef _WIN32
case pad_handler::xinput:
return std::make_shared<xinput_pad_handler>();
case pad_handler::mm:
return std::make_shared<mm_joystick_handler>();
#endif
#ifdef HAVE_SDL2
case pad_handler::sdl:
return std::make_shared<sdl_pad_handler>();
/*#endif
#ifdef HAVE_LIBEVDEV
case pad_handler::evdev:
return std::make_shared<evdev_joystick_handler>();
#endif*/
}
return nullptr;
}
void pad_thread::InitPadConfig(cfg_pad& cfg, pad_handler type, std::shared_ptr<PadHandlerBase>& handler)
{
if (!handler)
{
handler = GetHandler(type);
}
ensure(!!handler);
handler->init_config(&cfg);
}
extern bool send_open_home_menu_cmds();
extern void send_close_home_menu_cmds();
extern bool close_osk_from_ps_button();
void pad_thread::open_home_menu()
{
// Check if the OSK is open and can be closed
if (!close_osk_from_ps_button())
{
rsx::overlays::queue_message(get_localized_string(localized_string_id::CELL_OSK_DIALOG_BUSY));
return;
}
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{
if (m_home_menu_open.exchange(true))
{
return;
}
if (!send_open_home_menu_cmds())
{
m_home_menu_open = false;
return;
}
input_log.notice("opening home menu...");
const error_code result = manager->create<rsx::overlays::home_menu_dialog>()->show([this](s32 status)
{
input_log.notice("closing home menu with status %d", status);
m_home_menu_open = false;
send_close_home_menu_cmds();
});
(result ? input_log.error : input_log.notice)("opened home menu with result %d", s32{result});
}
}

View File

@@ -0,0 +1,153 @@
//
// Created by aenu on 2025/5/31.
//
#include "cpuinfo.h"
#include <fstream>
#include <sstream>
#include <algorithm>
#include <map>
std::vector<core_info_t> cpu_get_core_info(){
std::ifstream cpuinfo("/proc/cpuinfo");
if (!cpuinfo.is_open()) {
return {};
}
std::vector<core_info_t> cores;
core_info_t core;
std::string line;
while (std::getline(cpuinfo, line)) {
if (line.find("processor") != std::string::npos) {
core.processor = std::stoi(line.substr(line.find(":") + 2));
}
else if (line.find("CPU implementer") != std::string::npos) {
core.implementer = std::stoi(line.substr(line.find(":") + 2), nullptr, 16);
}
else if (line.find("CPU variant") != std::string::npos) {
core.variant = std::stoi(line.substr(line.find(":") + 2), nullptr, 16);
}
else if (line.find("CPU part") != std::string::npos) {
core.part = std::stoi(line.substr(line.find(":") + 2), nullptr, 16);
cores.push_back(core);
}
else if (line.find("Features") != std::string::npos) {
//FIXME 转换其为编译feature
std::string features = line.substr(line.find(":") + 2);
std::istringstream iss(features);
std::string feature;
while (iss >> feature) {
core.features.push_back(feature);
}
}
}
std::sort(cores.begin(), cores.end(), [](const core_info_t& a, const core_info_t& b) {
return a.processor < b.processor;
});
return cores;
}
//map.find
bool operator<(const core_info_t& lhs,const core_info_t& rhs){
if(lhs.implementer!= rhs.implementer) return lhs.implementer < rhs.implementer;
if(lhs.part!= rhs.part) return lhs.part < rhs.part;
return lhs.variant < rhs.variant;
}
std::string cpu_get_simple_info(const std::vector<core_info_t>& core_info_list){
std::map<core_info_t, int> core_counts;
for (const auto& core : core_info_list) {
if(core_counts.find(core) == core_counts.end())
core_counts[core] = 1;
else
core_counts[core]++;
}
std::stringstream ss;
for (auto it=core_counts.rbegin(); it!=core_counts.rend();it++) {
ss<<cpu_get_processor_name(it->first)<<"*"<<it->second<<"+";
}
std::string r = ss.str();
return r.substr(0,r.size()-1);
}
std::set<core_info_t> get_processor_info_set(){
std::vector<core_info_t> core_info_list = cpu_get_core_info();
return std::set<core_info_t>(core_info_list.begin(), core_info_list.end());
}
std::set<std::string> get_processor_name_set(){
std::vector<core_info_t> core_info_list = cpu_get_core_info();
std::set<std::string> processor_name_set;
std::for_each(core_info_list.begin(), core_info_list.end(), [&processor_name_set](const core_info_t& core_info) {
processor_name_set.insert(cpu_get_processor_name(core_info));
});
return processor_name_set;
}
std::string cpu_get_processor_name(const core_info_t& core_info){
static const std::map<std::tuple<int,int>,std::string> processor_map{
//ARM
{{ 0x41, 0xd04}, "cortex-a35" },
{{ 0x41, 0xd03}, "cortex-a53" },
{{ 0x41, 0xd07}, "cortex-a57" },
{{ 0x41, 0xd08}, "cortex-a72" },
{{ 0x41, 0xd09}, "cortex-a73" },
{{ 0x41, 0xd05}, "cortex-a55" },
{{ 0x41, 0xd0a}, "cortex-a75" },
{{ 0x41, 0xd0b}, "cortex-a76" },
{{ 0x41, 0xd0d}, "cortex-a77" },
{{ 0x41, 0xd41}, "cortex-a78" },
{{ 0x41, 0xd44}, "cortex-x1" },
{{ 0x41, 0xd46}, "cortex-a510" },
{{ 0x41, 0xd47}, "cortex-a710" },
{{ 0x41, 0xd48}, "cortex-x2" },
{{ 0x41, 0xd4d}, "cortex-a715" },
{{ 0x41, 0xd4e}, "cortex-x3" },
{{ 0x41, 0xd80}, "cortex-a520" },
{{ 0x41, 0xd81}, "cortex-a720" },
{{ 0x41, 0xd87}, "cortex-a725" },
{{ 0x41, 0xd82}, "cortex-x4" },
{{ 0x41, 0xd85}, "cortex-x925" },
{{ 0x41, 0xd88}, "cortex-a520ae" },
{{ 0x41, 0xd06}, "cortex-a65" },
{{ 0x41, 0xd43}, "cortex-a65ae" },
{{ 0x41, 0xd0e}, "cortex-a76ae" },
{{ 0x41, 0xd0d}, "cortex-a77" },
{{ 0x41, 0xd42}, "cortex-a78ae" },
{{ 0x41, 0xd4b}, "cortex-a78c" },
//高通
{{ 0x51, 0x801}, "cortex-a73" },// Kryo 2xx Silver
{{ 0x51, 0x802}, "cortex-a75" },// Kryo 3xx Gold
{{ 0x51, 0x803}, "cortex-a75" },// Kryo 3xx Silver
{{ 0x51, 0x804}, "cortex-a76" },// Kryo 4xx Gold
{{ 0x51, 0x805}, "cortex-a76" },// Kryo 4xx/5xx Silver
//{{ 0x51, 0xc00}, "falkor" },
//{{ 0x51, 0xc01}, "saphira" },
{{ 0x51, 0x001}, "oryon-1" },
//海思
//{{ 0x48, 0xd01}, "tsv110" },
//三星
{{ 0x53, 0x002}, "exynos-m3" },
{{ 0x53, 0x003}, "exynos-m4" },
};
int implementer=core_info.implementer;
int variant=core_info.variant;
int part=core_info.part;
if (auto core = processor_map.find(std::make_tuple(implementer, part)); core != processor_map.end()) {
return core->second;
}
return "Unknown";
}

View File

@@ -0,0 +1,24 @@
//
// Created by aenu on 2025/5/31.
//
#ifndef APS3E_CPUINFO_H
#define APS3E_CPUINFO_H
#include <string>
#include <vector>
#include <set>
struct core_info_t {
int processor;
int implementer;
int variant;
int part;
std::vector<std::string> features;
};
std::vector<core_info_t> cpu_get_core_info();
std::string cpu_get_simple_info(const std::vector<core_info_t>& core_info_list);
std::set<core_info_t> get_processor_info_set();
std::set<std::string> get_processor_name_set();
std::string cpu_get_processor_name(const core_info_t& core_info);
#endif //APS3E_CPUINFO_H

View File

@@ -0,0 +1,175 @@
// =========================== COMPRESSION ============================
// Some texture has block compression, when uncompressed will have swizzled layout. Since on some backend, no
// option is provided to make the GPU driver not try to translate the layout to linear, we have to do uncompress
// and unswizzled on the CPU.
// This BC decompression code is based on code from AMD GPUOpen's Compressonator
/**
* \brief Decompresses one block of a BC1 texture and stores the resulting pixels at the appropriate offset in 'image'.
*
* \param block_storage pointer to the block to decompress.
* \param image pointer to image where the decompressed pixel data should be stored.
**/
void decompress_block_bc1(const uint8_t *block_storage, uint32_t *image) {
std::uint16_t n0 = static_cast<std::uint16_t>((block_storage[1] << 8) | block_storage[0]);
std::uint16_t n1 = static_cast<std::uint16_t>((block_storage[3] << 8) | block_storage[2]);
block_storage += 4;
std::uint8_t r0 = (n0 & 0xF800) >> 8;
std::uint8_t g0 = (n0 & 0x07E0) >> 3;
std::uint8_t b0 = (n0 & 0x001F) << 3;
std::uint8_t r1 = (n1 & 0xF800) >> 8;
std::uint8_t g1 = (n1 & 0x07E0) >> 3;
std::uint8_t b1 = (n1 & 0x001F) << 3;
r0 |= r0 >> 5;
r1 |= r1 >> 5;
g0 |= g0 >> 6;
g1 |= g1 >> 6;
b0 |= b0 >> 5;
b1 |= b1 >> 5;
std::uint32_t c0 = 0xFF000000 | (b0 << 16) | (g0 << 8) | r0;
std::uint32_t c1 = 0xFF000000 | (b1 << 16) | (g1 << 8) | r1;
if (n0 > n1) {
std::uint8_t r2 = static_cast<uint8_t>((2 * r0 + r1 + 1) / 3);
std::uint8_t r3 = static_cast<uint8_t>((2 * r1 + r0 + 1) / 3);
std::uint8_t g2 = static_cast<uint8_t>((2 * g0 + g1 + 1) / 3);
std::uint8_t g3 = static_cast<uint8_t>((2 * g1 + g0 + 1) / 3);
std::uint8_t b2 = static_cast<uint8_t>((2 * b0 + b1 + 1) / 3);
std::uint8_t b3 = static_cast<uint8_t>((2 * b1 + b0 + 1) / 3);
std::uint32_t c2 = 0xFF000000 | (b2 << 16) | (g2 << 8) | r2;
std::uint32_t c3 = 0xFF000000 | (b3 << 16) | (g3 << 8) | r3;
for (int i = 0; i < 16; ++i) {
int index = (block_storage[i / 4] >> (i % 4 * 2)) & 0x03;
switch (index) {
case 0:
image[i] = c0;
break;
case 1:
image[i] = c1;
break;
case 2:
image[i] = c2;
break;
case 3:
image[i] = c3;
break;
}
}
} else {
// Transparent decode
std::uint8_t r2 = static_cast<uint8_t>((r0 + r1) / 2);
std::uint8_t g2 = static_cast<uint8_t>((g0 + g1) / 2);
std::uint8_t b2 = static_cast<uint8_t>((b0 + b1) / 2);
std::uint32_t c2 = 0xFF000000 | (b2 << 16) | (g2 << 8) | r2;
for (int i = 0; i < 16; ++i) {
int index = (block_storage[i / 4] >> (i % 4 * 2)) & 0x03;
switch (index) {
case 0:
image[i] = c0;
break;
case 1:
image[i] = c1;
break;
case 2:
image[i] = c2;
break;
case 3:
image[i] = 0x00000000;
break;
}
}
}
}
/**
* \brief Decompresses one block of a alpha texture and stores the resulting pixels at the appropriate offset in 'image'.
*
* \param block_storage pointer to the block to decompress.
* \param image pointer to image where the decompressed pixel data should be stored.
* \param offset offset to where data should be written.
* \param stride stride between bytes to where data should be written.
**/
void decompress_block_alpha(const uint8_t *block_storage, uint8_t *image, const uint32_t offset, const uint32_t stride) {
uint8_t alpha[8];
alpha[0] = block_storage[0];
alpha[1] = block_storage[1];
if (alpha[0] > alpha[1]) {
// 8-alpha block: derive the other six alphas.
// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
alpha[2] = static_cast<uint8_t>((6 * alpha[0] + 1 * alpha[1] + 3) / 7); // bit code 010
alpha[3] = static_cast<uint8_t>((5 * alpha[0] + 2 * alpha[1] + 3) / 7); // bit code 011
alpha[4] = static_cast<uint8_t>((4 * alpha[0] + 3 * alpha[1] + 3) / 7); // bit code 100
alpha[5] = static_cast<uint8_t>((3 * alpha[0] + 4 * alpha[1] + 3) / 7); // bit code 101
alpha[6] = static_cast<uint8_t>((2 * alpha[0] + 5 * alpha[1] + 3) / 7); // bit code 110
alpha[7] = static_cast<uint8_t>((1 * alpha[0] + 6 * alpha[1] + 3) / 7); // bit code 111
} else {
// 6-alpha block.
// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
alpha[2] = static_cast<uint8_t>((4 * alpha[0] + 1 * alpha[1] + 2) / 5); // Bit code 010
alpha[3] = static_cast<uint8_t>((3 * alpha[0] + 2 * alpha[1] + 2) / 5); // Bit code 011
alpha[4] = static_cast<uint8_t>((2 * alpha[0] + 3 * alpha[1] + 2) / 5); // Bit code 100
alpha[5] = static_cast<uint8_t>((1 * alpha[0] + 4 * alpha[1] + 2) / 5); // Bit code 101
alpha[6] = 0; // Bit code 110
alpha[7] = 255; // Bit code 111
}
image += offset;
image[stride * 0] = alpha[block_storage[2] & 0x07];
image[stride * 1] = alpha[(block_storage[2] >> 3) & 0x07];
image[stride * 2] = alpha[((block_storage[3] << 2) & 0x04) | ((block_storage[2] >> 6) & 0x03)];
image[stride * 3] = alpha[(block_storage[3] >> 1) & 0x07];
image[stride * 4] = alpha[(block_storage[3] >> 4) & 0x07];
image[stride * 5] = alpha[((block_storage[4] << 1) & 0x06) | ((block_storage[3] >> 7) & 0x01)];
image[stride * 6] = alpha[(block_storage[4] >> 2) & 0x07];
image[stride * 7] = alpha[(block_storage[4] >> 5) & 0x07];
image[stride * 8] = alpha[block_storage[5] & 0x07];
image[stride * 9] = alpha[(block_storage[5] >> 3) & 0x07];
image[stride * 10] = alpha[((block_storage[6] << 2) & 0x04) | ((block_storage[5] >> 6) & 0x03)];
image[stride * 11] = alpha[(block_storage[6] >> 1) & 0x07];
image[stride * 12] = alpha[(block_storage[6] >> 4) & 0x07];
image[stride * 13] = alpha[((block_storage[7] << 1) & 0x06) | ((block_storage[6] >> 7) & 0x01)];
image[stride * 14] = alpha[(block_storage[7] >> 2) & 0x07];
image[stride * 15] = alpha[(block_storage[7] >> 5) & 0x07];
}
/**
* \brief Decompresses one block of a BC2 texture and stores the resulting pixels at the appropriate offset in 'image'.
*
* \param block_storage pointer to the block to decompress.
* \param image pointer to image where the decompressed pixel data should be stored.
**/
void decompress_block_bc2(const uint8_t *block_storage, uint32_t *image) {
decompress_block_bc1(block_storage + 8, image);
for (int i = 0; i < 8; i++) {
image[2 * i] = (((block_storage[i] & 0x0F) | ((block_storage[i] & 0x0F) << 4)) << 24) | (image[2 * i] & 0x00FFFFFF);
image[2 * i + 1] = (((block_storage[i] & 0xF0) | ((block_storage[i] & 0xF0) >> 4)) << 24) | (image[2 * i + 1] & 0x00FFFFFF);
}
}
/**
* \brief Decompresses one block of a BC3 texture and stores the resulting pixels at the appropriate offset in 'image'.
*
* \param block_storage pointer to the block to decompress.
* \param image pointer to image where the decompressed pixel data should be stored.
**/
void decompress_block_bc3(const uint8_t *block_storage, uint32_t *image) {
decompress_block_bc1(block_storage + 8, image);
decompress_block_alpha(block_storage, reinterpret_cast<std::uint8_t *>(image), 3, 4);
}

View File

@@ -0,0 +1,174 @@
//
// Created by aenu on 2025/6/1.
// SPDX-License-Identifier: WTFPL
//
#include "glsl2spv.h"
namespace{
TBuiltInResource resource;
}
void glsl2spv_init(const VkPhysicalDeviceLimits& limits){
resource.maxLights = 32;
resource.maxClipPlanes = 6;
resource.maxTextureUnits = 32;
resource.maxTextureCoords = 32;
resource.maxVertexAttribs = 64;
resource.maxVertexUniformComponents = 4096;
resource.maxVaryingFloats = 64;
resource.maxVertexTextureImageUnits = 32;
resource.maxCombinedTextureImageUnits = 80;
resource.maxTextureImageUnits = 32;
resource.maxFragmentUniformComponents = 4096;
resource.maxDrawBuffers = 32;
resource.maxVertexUniformVectors = 128;
resource.maxVaryingVectors = 8;
resource.maxFragmentUniformVectors = 16;
resource.maxVertexOutputVectors = limits.maxVertexOutputComponents;
resource.maxFragmentInputVectors = limits.maxFragmentInputComponents;
resource.minProgramTexelOffset = limits.minTexelOffset;
resource.maxProgramTexelOffset = limits.maxTexelOffset;
resource.maxClipDistances = limits.maxClipDistances;
resource.maxComputeWorkGroupCountX = limits.maxComputeWorkGroupCount[0];
resource.maxComputeWorkGroupCountY = limits.maxComputeWorkGroupCount[1];
resource.maxComputeWorkGroupCountZ = limits.maxComputeWorkGroupCount[2];
resource.maxComputeWorkGroupSizeX = limits.maxComputeWorkGroupSize[0];
resource.maxComputeWorkGroupSizeY = limits.maxComputeWorkGroupSize[1];
resource.maxComputeWorkGroupSizeZ = limits.maxComputeWorkGroupSize[2];
resource.maxComputeUniformComponents = 1024;
resource.maxComputeTextureImageUnits = 16;
resource.maxComputeImageUniforms = 8;
resource.maxComputeAtomicCounters = 8;
resource.maxComputeAtomicCounterBuffers = 1;
resource.maxVaryingComponents = 60;
resource.maxVertexOutputComponents = limits.maxVertexOutputComponents;
resource.maxGeometryInputComponents = limits.maxGeometryInputComponents;
resource.maxGeometryOutputComponents = limits.maxGeometryOutputComponents;
resource.maxFragmentInputComponents = limits.maxFragmentInputComponents;
resource.maxImageUnits = 8;
resource.maxCombinedImageUnitsAndFragmentOutputs = 8;
resource.maxCombinedShaderOutputResources = 8;
resource.maxImageSamples = 0;
resource.maxVertexImageUniforms = 0;
resource.maxTessControlImageUniforms = 0;
resource.maxTessEvaluationImageUniforms = 0;
resource.maxGeometryImageUniforms = 0;
resource.maxFragmentImageUniforms = 0;
resource.maxCombinedImageUniforms = 0;
resource.maxGeometryTextureImageUnits = 16;
resource.maxGeometryOutputVertices = limits.maxGeometryOutputVertices;
resource.maxGeometryTotalOutputComponents = limits.maxGeometryTotalOutputComponents;
resource.maxGeometryUniformComponents = 1024;
resource.maxGeometryVaryingComponents = 64;
resource.maxTessControlInputComponents = 128;
resource.maxTessControlOutputComponents = 128;
resource.maxTessControlTextureImageUnits = 16;
resource.maxTessControlUniformComponents = 1024;
resource.maxTessControlTotalOutputComponents = 4096;
resource.maxTessEvaluationInputComponents = 128;
resource.maxTessEvaluationOutputComponents = 128;
resource.maxTessEvaluationTextureImageUnits = 16;
resource.maxTessEvaluationUniformComponents = 1024;
resource.maxTessPatchComponents = 120;
resource.maxPatchVertices = 32;
resource.maxTessGenLevel = limits.maxTessellationGenerationLevel;
resource.maxViewports = limits.maxViewports;
resource.maxVertexAtomicCounters = 0;
resource.maxTessControlAtomicCounters = 0;
resource.maxTessEvaluationAtomicCounters = 0;
resource.maxGeometryAtomicCounters = 0;
resource.maxFragmentAtomicCounters = 0;
resource.maxCombinedAtomicCounters = 0;
resource.maxAtomicCounterBindings = 0;
resource.maxVertexAtomicCounterBuffers = 0;
resource.maxTessControlAtomicCounterBuffers = 0;
resource.maxTessEvaluationAtomicCounterBuffers = 0;
resource.maxGeometryAtomicCounterBuffers = 0;
resource.maxFragmentAtomicCounterBuffers = 0;
resource.maxCombinedAtomicCounterBuffers = 0;
resource.maxAtomicCounterBufferSize = 16384;
resource.maxTransformFeedbackBuffers = 4;
resource.maxTransformFeedbackInterleavedComponents = 64;
resource.maxCullDistances = 8;
resource.maxCombinedClipAndCullDistances = 8;
resource.maxSamples = 4;
/*
int maxMeshOutputVerticesNV;
int maxMeshOutputPrimitivesNV;
int maxMeshWorkGroupSizeX_NV;
int maxMeshWorkGroupSizeY_NV;
int maxMeshWorkGroupSizeZ_NV;
int maxTaskWorkGroupSizeX_NV;
int maxTaskWorkGroupSizeY_NV;
int maxTaskWorkGroupSizeZ_NV;
int maxMeshViewCountNV;
int maxMeshOutputVerticesEXT;
int maxMeshOutputPrimitivesEXT;
int maxMeshWorkGroupSizeX_EXT;
int maxMeshWorkGroupSizeY_EXT;
int maxMeshWorkGroupSizeZ_EXT;
int maxTaskWorkGroupSizeX_EXT;
int maxTaskWorkGroupSizeY_EXT;
int maxTaskWorkGroupSizeZ_EXT;
int maxMeshViewCountEXT;
int maxDualSourceDrawBuffersEXT;
*/
resource.limits= {
.nonInductiveForLoops = true,
.whileLoops = true,
.doWhileLoops = true,
.generalUniformIndexing = true,
.generalAttributeMatrixVectorIndexing = true,
.generalVaryingIndexing = true,
.generalSamplerIndexing = true,
.generalVariableIndexing = true,
.generalConstantMatrixVectorIndexing = true,
};
glslang::InitializeProcess();
}
std::optional<std::vector<uint32_t >> glsl2spv_compile(const std::string& source,EShLanguage lang){
glslang::TShader shader(lang);
shader.setEnvInput(glslang::EShSourceGlsl,lang,glslang::EShClientVulkan,450);
shader.setEnvClient(glslang::EShClientVulkan,glslang::EShTargetVulkan_1_0);
shader.setEnvTarget(glslang::EshTargetSpv,glslang::EShTargetSpv_1_0);
const char* shader_source = source.c_str();
shader.setStrings(&shader_source,1);
EShMessages messages = static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules);
if(!shader.parse(&resource,450,false,messages)){
return std::nullopt;
}
glslang::TProgram program;
program.addShader(&shader);
if(!program.link(messages)){
return std::nullopt;
}
std::vector<uint32_t> spv;
glslang::GlslangToSpv(*program.getIntermediate(lang),spv);
return spv;
}
void glsl2spv_finalize(){
glslang::FinalizeProcess();
}

View File

@@ -0,0 +1,21 @@
//
// Created by aenu on 2025/6/1.
// SPDX-License-Identifier: WTFPL
//
#ifndef APS3E_GLSL2SPV_H
#define APS3E_GLSL2SPV_H
#include <optional>
#include <vector>
#include <cstdint>
#include "vkapi.h"
#include "glslang/Public/ShaderLang.h"
#include "glslang/SPIRV/GlslangToSpv.h"
#include "glslang/Include/glslang_c_interface.h"
void glsl2spv_init(const VkPhysicalDeviceLimits& limits);
std::optional<std::vector<uint32_t >> glsl2spv_compile(const std::string& source,EShLanguage lang);
void glsl2spv_finalize();
#endif //APS3E_GLSL2SPV_H

249
app/src/main/cpp/iso.cpp Normal file
View File

@@ -0,0 +1,249 @@
//
// Created by aenu on 2025/5/11.
//
#include "iso.h"
std::unique_ptr<iso_fs> iso_fs::from_fd(int fd) {
std::unique_ptr<iso_fs> _iso_fs=std::make_unique<iso_fs>();
_iso_fs->fd = fd;
return _iso_fs;
}
bool iso_fs::load(){
off_t pos=0x8000;
std::optional<VolumeDescriptor> primary_vd;
std::optional<VolumeDescriptor> supplementary_vd;
for(;;){
lseek(fd, pos, SEEK_SET);
VolumeDescriptor vd;
if(::read(fd, &vd, sizeof(vd))!=sizeof(vd)){
return false;
}
if(memcmp(vd.identifier, "CD001", 5)!=0)
return false;
if(vd.version>2)
return false;
if(vd.type_code==255)
break;
pos+=0x800;
if(vd.type_code==0){
//Boot Record
continue;
}
if(vd.type_code==1){
primary_vd=vd;
continue;
}
if(vd.type_code==2){
supplementary_vd=vd;
continue;
}
}
if(supplementary_vd){
parse<2>(*supplementary_vd);
return true;
}
else if(primary_vd){
parse<1>(*primary_vd);
return true;
}
else
return false;
}
bool iso_fs::exists(const std::string& path){
if(path==":")
return true;
return files.find(path)!=files.end();
}
std::vector<uint8_t> iso_fs::get_data_tiny(const std::string& path){
auto it = files.find(path);
if (it != files.end()) {
const entry_t& entry = it->second;
#if 0
if(entry.blocks.size()!=1){
//FIXME 应该抛出异常,get_data_tiny应该只用于获取轻量级文件
return {};
}
lseek(fd, entry.blocks[0].offset, SEEK_SET);
std::vector<uint8_t> buffer(entry.blocks[0].size);
#else
lseek(fd, entry.offset, SEEK_SET);
std::vector<uint8_t> buffer(entry.size);
#endif
::read(fd, buffer.data(), buffer.size());
return buffer;
}
return {};
}
std::vector<iso_fs::entry_t>& iso_fs::list_dir(const std::string& path){
return tree[path];
}
iso_fs::~iso_fs()
{
close(fd);
}
template<const int VOLUME_TYPE>
void iso_fs::parse(VolumeDescriptor& vd){
read_dir<VOLUME_TYPE>(vd.root_directory_record, ":");//std::nullopt);
}
template<const int VOLUME_TYPE>
void iso_fs::read_dir(RootDirectoryRecord& dir_record, std::optional<std::string> path) {
if(dir_record.extended_attribute_length!=0){
//return;
}
std::vector<uint8_t> buffer(dir_record.data_length.ne());
lseek(fd, dir_record.extent_location.ne()*2048, SEEK_SET);
if(::read(fd, buffer.data(), buffer.size())!=buffer.size())
return;
for(size_t offset=0;;){
if(offset>=buffer.size())
break;
size_t length=buffer[offset];
if(length==0) {
offset&=~2047;
offset+=2048;
continue;
}
RootDirectoryRecord record;
memcpy(&record, buffer.data()+offset, sizeof(record));
if((record.file_identifier_length&1)==1){
offset+=length;
continue;
}
auto read_file_identifier_ascii=[&]()->std::string {
return std::string(reinterpret_cast<char*>(buffer.data() + offset + sizeof(RootDirectoryRecord)), record.file_identifier_length);
};
//2 bytes
auto read_file_identifier_unicode = [&]()->std::string {
std::string result;
char* file_identifier_base_ptr = reinterpret_cast<char*>(buffer.data() + offset + sizeof(RootDirectoryRecord));
for (size_t i = 0; i + 1 < record.file_identifier_length; i += 2) {
uint16_t code_unit = (static_cast<uint8_t>(file_identifier_base_ptr[i+0]) << 8) |
static_cast<uint8_t>(file_identifier_base_ptr[i + 1]);
if (code_unit <= 0x7F) {
result += static_cast<char>(code_unit);
} else if (code_unit <= 0x7FF) {
result += static_cast<char>(0xC0 | ((code_unit >> 6) & 0x1F));
result += static_cast<char>(0x80 | (code_unit & 0x3F));
} else {
result += static_cast<char>(0xE0 | ((code_unit >> 12) & 0x0F));
result += static_cast<char>(0x80 | ((code_unit >> 6) & 0x3F));
result += static_cast<char>(0x80 | (code_unit & 0x3F));
}
}
return result;
};
std::string file_identifier;
if constexpr (VOLUME_TYPE==1){
file_identifier=read_file_identifier_ascii();
}
else if constexpr (VOLUME_TYPE==2){
file_identifier=read_file_identifier_unicode();
}
//LOGE("%s", file_identifier.c_str());
//if(path)
// file_identifier=path.value()+"/"+file_identifier;
if(path.value()==":")
file_identifier = path.value() + file_identifier;
else
file_identifier = path.value() + "/" + file_identifier;
if(!(record.file_flags&0x2))
file_identifier=file_identifier.substr(0,file_identifier.size()-2); //;1
#if 0
if(auto it=files.find(file_identifier);it!=files.end()){
it->second.blocks.push_back({
.offset=record.extent_location.ne()*2048,
.size=record.data_length.ne(),
.entry_offset=it->second.blocks.back().entry_offset+it->second.blocks.back().size,
});
}
else{
files[file_identifier]=entry_t{
.path=file_identifier,
.blocks={{
.offset=record.extent_location.ne()*2048ull,
.size=record.data_length.ne(),
.entry_offset=0,
}},
.is_dir=!!(record.file_flags&0x2)
};
}
//
if(auto it=tree.find(path.value());it==tree.end()){
tree[path.value()]=std::vector<entry_t>();
}
auto& dir_entries = tree[path.value()];
if(auto it = std::find_if(dir_entries.begin(), dir_entries.end(), [&](const entry_t& entry) {
return entry.path == file_identifier;});it != dir_entries.end())
{
*it = files[file_identifier];
}
else {
dir_entries.push_back(files[file_identifier]);
}
#else
if(auto it=files.find(file_identifier);it!=files.end()){
it->second.size+=record.data_length.ne();
}
else{
files[file_identifier]=entry_t{
.path=file_identifier,
.offset=record.extent_location.ne()*2048ull,
.size=record.data_length.ne(),
.is_dir=!!(record.file_flags&0x2)
};
}
if(auto it=tree.find(path.value());it==tree.end()){
tree[path.value()]=std::vector<entry_t>();
}
auto& dir_entries = tree[path.value()];
if(auto it = std::find_if(dir_entries.begin(), dir_entries.end(), [&](const entry_t& entry) {
return entry.path == file_identifier;
});it != dir_entries.end()){
*it = files[file_identifier];
}
else {
dir_entries.push_back(files[file_identifier]);
}
#endif
if(record.file_flags&0x2){
read_dir<VOLUME_TYPE>(record, file_identifier);
}
offset+=length;
}
}

186
app/src/main/cpp/iso.h Normal file
View File

@@ -0,0 +1,186 @@
//
// Created by aenu on 2025/5/17.
//
#ifndef APS3E_ISO_H
#define APS3E_ISO_H
#include <stdint.h>
#include <endian.h>
#include <bit>
#include <fcntl.h>
#include <unistd.h>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
#include <cassert>
#include <numeric>
#include "util/logs.hpp"
LOG_CHANNEL(iso_fs_log);
template<typename T>
struct le_be_t {
T le;
T be;
T ne() {
#if __BYTE_ORDER==__LITTLE_ENDIAN
return le;
#elif __BYTE_ORDER==__BIG_ENDIAN
return be;
#else
#error "unknown byte order"
#endif
}
};
struct path_table_t{
uint32_t path_table;
uint32_t ext_path_table;
};
static_assert(sizeof(path_table_t)==8, "sizeof(path_table_t) != 8");
#pragma pack(push, 1)
struct RootDirectoryRecord {
uint8_t length;
uint8_t extended_attribute_length;
le_be_t<uint32_t> extent_location;
le_be_t<uint32_t> data_length;
uint8_t recording_date[7];
uint8_t file_flags;
uint8_t file_unit_size;
uint8_t interleave_gap_size;
le_be_t<uint16_t> volume_sequence_number;
uint8_t file_identifier_length;
};
static_assert(sizeof(RootDirectoryRecord)==33, "sizeof(RootDirectoryRecord) != 33");
struct VolumeDescriptor {
uint8_t type_code;
char identifier[5];
uint8_t version;
uint8_t unused[1];
char system_identifier[32];
char volume_identifier[32];
uint8_t unused2[8];
le_be_t<uint32_t> volume_space_size;
uint8_t unused3[32];
le_be_t<uint16_t> volume_set_size;
le_be_t<uint16_t> volume_sequence_number;
le_be_t<uint16_t> logical_block_size;
le_be_t<uint32_t> path_table_size;
le_be_t<path_table_t> path_table_data;
RootDirectoryRecord root_directory_record;
uint8_t unused4[1];
char volume_set_identifier[128];
char publisher_identifier[128];
char data_preparer_identifier[128];
char application_identifier[128];
char copyright_file_identifier[37];
char abstract_file_identifier[37];
char bibliographic_file_identifier[37];
char volume_creation_date[17];
char volume_modification_date[17];
char volume_expiration_date[17];
char volume_effective_date[17];
uint8_t file_structure_version;
uint8_t unused5[1];
uint8_t application_data[512];
uint8_t reserved[653];
};
static_assert(sizeof(VolumeDescriptor)==2048, "sizeof(VolumeDescriptor) != 2048");
struct iso_fs{
static std::unique_ptr<iso_fs> from_fd(int fd);
iso_fs()=default;
~iso_fs();
iso_fs(const iso_fs&) = delete;
iso_fs(iso_fs&&) = delete;
bool load();
bool exists(const std::string& path);
std::vector<uint8_t> get_data_tiny(const std::string& path);
#if 0
struct block_t {
uint64_t offset;
uint64_t size;
uint64_t entry_offset;
};
struct entry_t {
std::string path;
std::vector<block_t> blocks;
bool is_dir;
uint64_t size(){return std::accumulate(blocks.begin(),blocks.end(),0ull,[](uint64_t sum,const block_t& b){return sum+b.size;});}
};
#else
struct entry_t {
std::string path;
uint64_t offset;
uint64_t size;
bool is_dir;
};
#endif
entry_t get_entry(const std::string& path){
if(files.find(path)==files.end()) {
iso_fs_log.warning("iso_fs::get_entry(%s) not found",path);
return {};
}else {
iso_fs_log.warning("iso_fs::get_entry(%s) found",path);
return files[path];
}
}
std::vector<entry_t>& list_dir(const std::string& path);
off_t seek(uint64_t offset) const {return lseek(fd, offset, SEEK_SET);}
ssize_t read(uint8_t* buffer, uint64_t size){return ::read(fd, buffer, size);}
#if 0
void save(int fp,const std::string& path){
auto entry=get_entry(path);
uint8_t buffer[1024*1024];
for(auto& block:entry.blocks){
uint64_t offset=block.offset;
uint64_t remaining=block.size;
uint64_t buffer_size=std::min(remaining,sizeof(buffer));
while(remaining>0){
seek(offset);
read(buffer,buffer_size);
write(fp,buffer,buffer_size);
remaining-=buffer_size;
offset+=buffer_size;
buffer_size=std::min(remaining,sizeof(buffer));
}
}
}
#endif
private:
template<const int VOLUME_TYPE>
void parse(VolumeDescriptor& vd);
template<const int VOLUME_TYPE>
void read_dir(RootDirectoryRecord& dir_record,std::optional<std::string> path);
int fd;
std::unordered_map <std::string, entry_t> files;
std::unordered_map <std::string, std::vector<entry_t>> tree;
};
#pragma pack(pop)
#endif //APS3E_ISO_H

View File

@@ -0,0 +1,13 @@
//
// Created by aenu on 2025/4/10.
//
#include <stdlib.h>
#include <jni.h>
extern "C" JNIEXPORT void JNICALL Java_aenu_lang_System_setenv(JNIEnv* env,jclass cls,jstring jname,jstring jvalue,jboolean overwrite){
const char* name = env->GetStringUTFChars(jname,NULL);
const char* value = env->GetStringUTFChars(jvalue,NULL);
setenv(name,value,overwrite);
env->ReleaseStringUTFChars(jname,name);
env->ReleaseStringUTFChars(jvalue,value);
}

585
app/src/main/cpp/pt.cpp Normal file
View File

@@ -0,0 +1,585 @@
#include <iostream>
#include <vector>
#include <string>
#include <jni.h>
#include <iostream>
#include <csignal>
#include <cstring>
#include <thread>
#include <vector>
#include <tuple>
#include <sys/mman.h>
#include <unistd.h>
#include <atomic>
#include "vkapi.h"
#include "vkutil.h"
#include "cpuinfo.h"
#if 0
std::string get_gpu_info() {
VkApplicationInfo appinfo = {};
appinfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appinfo.pNext = nullptr;
appinfo.pApplicationName = "aps3e-test";
appinfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appinfo.pEngineName = "nul";
appinfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appinfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo inst_create_info = {};
inst_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
inst_create_info.pApplicationInfo = &appinfo;
VkInstance inst;
if (_vkCreateInstance(&inst_create_info, nullptr, &inst)!= VK_SUCCESS) {
return "获取gpu信息失败";;
}
// 获取物理设备数量
uint32_t physicalDeviceCount = 0;
_vkEnumeratePhysicalDevices(inst, &physicalDeviceCount, nullptr);
std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
_vkEnumeratePhysicalDevices(inst, &physicalDeviceCount, physicalDevices.data());
if (physicalDeviceCount != 1) {
if (physicalDeviceCount == 0) {
_vkDestroyInstance(inst, nullptr);
return "没有有效的gpu!";
}
std::string result = "多个gpu! [";
for (int i = 0; i < physicalDeviceCount; ++i) {
VkPhysicalDeviceProperties deviceProperties;
_vkGetPhysicalDeviceProperties(physicalDevices[i], &deviceProperties);
result += deviceProperties.deviceName;
if (i != physicalDeviceCount - 1)
result += ", ";
}
_vkDestroyInstance(inst, nullptr);
return result+"]";
}
VkPhysicalDevice physicalDevice = physicalDevices[0];
// 获取物理设备属性以获取设备名称
VkPhysicalDeviceProperties deviceProperties;
_vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
uint32_t deviceExtensionCount = 0;
_vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount, nullptr);
std::vector<VkExtensionProperties> deviceExtensions(deviceExtensionCount);
_vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount, deviceExtensions.data());
std::ostringstream result;
auto gen_vk_version = [](uint32_t v) {
std::ostringstream oss;
oss << (v >> 22) << "." << ((v >> 12) & 0x3ff) << "." << (v & 0xfff);
return oss.str();
};
result << "GPU ["<<deviceProperties.deviceName<<"(Vulkan "<<gen_vk_version(deviceProperties.apiVersion)<<")]:\n\n";
auto pr_u64 = [](uint64_t v) {
std::ostringstream oss;
oss << std::fixed << std::setprecision(2);
const double GB = 1024.0 * 1024.0 * 1024.0;
const double MB = 1024.0 * 1024.0;
const double KB = 1024.0;
if (v >= GB) {
double value = v / GB;
oss << (value == floor(value) ? std::setprecision(0) : std::setprecision(2))
<< value << "GB(" << v << ")";
} else if (v >= MB) {
double value = v / MB;
oss << (value == floor(value) ? std::setprecision(0) : std::setprecision(2))
<< value << "MB(" << v << ")";
} else if (v >= KB) {
double value = v / KB;
oss << (value == floor(value) ? std::setprecision(0) : std::setprecision(2))
<< value << "KB(" << v << ")";
} else {
oss << v ;
}
std::string result = oss.str();
return result;
};
auto pr_u32 = [&](uint32_t v) {
return pr_u64(v);
};
auto pr_f32 = [](float v) {
std::ostringstream oss;
oss << std::fixed << std::setprecision(4)<<v;
return oss.str();
};
// 宏定义
#define w_u32(field) result << " " #field ": " << pr_u32(deviceProperties.limits.field) << "\n"
#define w_u64(field) result << " " #field ": " << pr_u64(deviceProperties.limits.field) << "\n"
#define w_f32(field) result << " " #field ": " << pr_f32(deviceProperties.limits.field) << "\n"
result << "limits:\n";
// 字段映射列表
w_u32(maxImageDimension1D);
w_u32(maxImageDimension2D);
w_u32(maxImageDimension3D);
w_u32(maxImageDimensionCube);
w_u32(maxImageArrayLayers);
w_u32(maxTexelBufferElements);
w_u32(maxUniformBufferRange);
w_u32(maxStorageBufferRange);
w_u32(maxPushConstantsSize);
w_u32(maxMemoryAllocationCount);
w_u32(maxSamplerAllocationCount);
w_u64(bufferImageGranularity);
w_u64(sparseAddressSpaceSize);
w_u32(maxBoundDescriptorSets);
w_u32(maxPerStageDescriptorSamplers);
w_u32(maxPerStageDescriptorUniformBuffers);
w_u32(maxPerStageDescriptorStorageBuffers);
w_u32(maxPerStageDescriptorSampledImages);
w_u32(maxPerStageDescriptorStorageImages);
w_u32(maxPerStageDescriptorInputAttachments);
w_u32(maxPerStageResources);
w_u32(maxDescriptorSetSamplers);
w_u32(maxDescriptorSetUniformBuffers);
w_u32(maxDescriptorSetUniformBuffersDynamic);
w_u32(maxDescriptorSetStorageBuffers);
w_u32(maxDescriptorSetStorageBuffersDynamic);
w_u32(maxDescriptorSetSampledImages);
w_u32(maxDescriptorSetStorageImages);
w_u32(maxDescriptorSetInputAttachments);
w_u32(maxVertexInputAttributes);
w_u32(maxVertexInputBindings);
w_u32(maxVertexInputAttributeOffset);
w_u32(maxVertexInputBindingStride);
w_u32(maxVertexOutputComponents);
w_u32(maxTessellationGenerationLevel);
w_u32(maxTessellationPatchSize);
w_u32(maxTessellationControlPerVertexInputComponents);
w_u32(maxTessellationControlPerVertexOutputComponents);
w_u32(maxTessellationControlPerPatchOutputComponents);
w_u32(maxTessellationControlTotalOutputComponents);
w_u32(maxTessellationEvaluationInputComponents);
w_u32(maxTessellationEvaluationOutputComponents);
w_u32(maxGeometryShaderInvocations);
w_u32(maxGeometryInputComponents);
w_u32(maxGeometryOutputComponents);
w_u32(maxGeometryOutputVertices);
w_u32(maxGeometryTotalOutputComponents);
w_u32(maxFragmentInputComponents);
w_u32(maxFragmentOutputAttachments);
w_u32(maxFragmentDualSrcAttachments);
w_u32(maxFragmentCombinedOutputResources);
w_u32(maxComputeSharedMemorySize);
result << " maxComputeWorkGroupCount: [x="
<< pr_u32(deviceProperties.limits.maxComputeWorkGroupCount[0]) << ", y="
<< pr_u32(deviceProperties.limits.maxComputeWorkGroupCount[1]) << ", z="
<< pr_u32(deviceProperties.limits.maxComputeWorkGroupCount[2]) << "]\n";
w_u32(maxComputeWorkGroupInvocations);
result << " maxComputeWorkGroupSize: [x="
<< pr_u32(deviceProperties.limits.maxComputeWorkGroupSize[0]) << ", y="
<< pr_u32(deviceProperties.limits.maxComputeWorkGroupSize[1]) << ", z="
<< pr_u32(deviceProperties.limits.maxComputeWorkGroupSize[2]) << "]\n";
w_u32(subPixelPrecisionBits);
w_u32(subTexelPrecisionBits);
w_u32(mipmapPrecisionBits);
w_u32(maxDrawIndexedIndexValue);
w_u32(maxDrawIndirectCount);
w_f32(maxSamplerLodBias);
w_f32(maxSamplerAnisotropy);
w_u32(maxViewports);
// 二维数组处理:
result << " maxViewportDimensions: ["
<< pr_u32(deviceProperties.limits.maxViewportDimensions[0]) << " | "
<< pr_u32(deviceProperties.limits.maxViewportDimensions[1]) << "]\n";
result << " viewportBoundsRange: ["
<< pr_f32(deviceProperties.limits.viewportBoundsRange[0]) << " | "
<< pr_f32(deviceProperties.limits.viewportBoundsRange[1]) << "]\n";
w_u32(viewportSubPixelBits);
w_u64(minMemoryMapAlignment);
w_u64(minTexelBufferOffsetAlignment);
w_u64(minUniformBufferOffsetAlignment);
w_u64(minStorageBufferOffsetAlignment);
w_u32(minTexelOffset);
w_u32(maxTexelOffset);
w_u32(minTexelGatherOffset);
w_u32(maxTexelGatherOffset);
w_f32(minInterpolationOffset);
w_f32(maxInterpolationOffset);
w_u32(subPixelInterpolationOffsetBits);
w_u32(maxFramebufferWidth);
w_u32(maxFramebufferHeight);
w_u32(maxFramebufferLayers);
w_u32(framebufferColorSampleCounts);
w_u32(framebufferDepthSampleCounts);
w_u32(framebufferStencilSampleCounts);
w_u32(framebufferNoAttachmentsSampleCounts);
w_u32(maxColorAttachments);
w_u32(sampledImageColorSampleCounts);
w_u32(sampledImageIntegerSampleCounts);
w_u32(sampledImageDepthSampleCounts);
w_u32(sampledImageStencilSampleCounts);
w_u32(storageImageSampleCounts);
w_u32(maxSampleMaskWords);
w_u32(timestampComputeAndGraphics);
w_f32(timestampPeriod);
w_u32(maxClipDistances);
w_u32(maxCullDistances);
w_u32(maxCombinedClipAndCullDistances);
w_u32(discreteQueuePriorities);
// 浮点数组处理:
result << " pointSizeRange: ["
<< pr_f32(deviceProperties.limits.pointSizeRange[0]) << " | "
<< pr_f32(deviceProperties.limits.pointSizeRange[1]) << "]\n";
result << " lineWidthRange: ["
<< pr_f32(deviceProperties.limits.lineWidthRange[0]) << " | "
<< pr_f32(deviceProperties.limits.lineWidthRange[1]) << "]\n";
w_f32(pointSizeGranularity);
w_f32(lineWidthGranularity);
w_u32(strictLines);
w_u32(standardSampleLocations);
w_u64(optimalBufferCopyOffsetAlignment);
w_u64(optimalBufferCopyRowPitchAlignment);
w_u64(nonCoherentAtomSize);
#undef w_f32
#undef w_u32
#undef w_u64
result << "\n";
result << "extensions:\n";
for (const auto& deviceExt : deviceExtensions) {
result << " * " << deviceExt.extensionName<< "\n";
}
vkDestroyInstance(inst, nullptr);
return result.str();
}
#endif
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#if 0
std::string get_cpu_info() {
std::ifstream cpuinfo("/proc/cpuinfo");
if (!cpuinfo.is_open()) {
return "获取cpuinfo失败";
}
struct CoreInfo {
int implementer;
int variant;
int part;
std::vector<std::string> features;
};
std::vector<CoreInfo> cores;
std::map<std::tuple<int,int,int>,int> core_n;
std::string line;
CoreInfo core;
while (std::getline(cpuinfo, line)) {
if (line.find("CPU implementer") != std::string::npos) {
core.implementer = std::stoi(line.substr(line.find(":") + 2), nullptr, 16);
}
else if (line.find("CPU variant") != std::string::npos) {
core.variant = std::stoi(line.substr(line.find(":") + 2), nullptr, 16);
}
else if (line.find("CPU part") != std::string::npos) {
core.part = std::stoi(line.substr(line.find(":") + 2), nullptr, 16);
cores.push_back(core);
if (core_n.find({core.implementer, core.variant, core.part}) == core_n.end()) {
core_n[{core.implementer, core.variant, core.part}] = 1;
}
else {
core_n[{core.implementer, core.variant, core.part}]++;
}
}
else if (line.find("Features") != std::string::npos) {
std::string features = line.substr(line.find(":") + 2);
std::istringstream iss(features);
std::string feature;
while (iss >> feature) {
core.features.push_back(feature);
}
}
}
auto cpu_core_info = [&]() {
static const std::map<std::tuple<int,int>,std::string> core_map{
{{ 0x41, 0xd01}, "Cortex-A32" },
{{ 0x41, 0xd04}, "Cortex-A35" },
{{ 0x41, 0xd03}, "Cortex-A53" },
{{ 0x41, 0xd07}, "Cortex-A57" },
{{ 0x41, 0xd08}, "Cortex-A72" },
{{ 0x41, 0xd09}, "Cortex-A73" },
{{ 0x41, 0xd05}, "Cortex-A55" },
{{ 0x41, 0xd0a}, "Cortex-A75" },
{{ 0x41, 0xd0b}, "Cortex-A76" },
{{ 0x41, 0xd0d}, "Cortex-A77" },
{{ 0x41, 0xd41}, "Cortex-A78" },
{{ 0x41, 0xd44}, "Cortex-X1" },
{{ 0x41, 0xd46}, "Cortex-A510" },
{{ 0x41, 0xd47}, "Cortex-A710" },
{{ 0x41, 0xd48}, "Cortex-X2" },
{{ 0x41, 0xd4d}, "Cortex-A715" },
{{ 0x41, 0xd4e}, "Cortex-X3" },
{{ 0x41, 0xd80}, "Cortex-A520" },
{{ 0x41, 0xd81}, "Cortex-A720" },
{{ 0x41, 0xd87}, "Cortex-A725" },
{{ 0x41, 0xd82}, "Cortex-X4" },
{{ 0x41, 0xd85}, "Cortex-X925" },
{{ 0x51, 0x001}, "X-Elite" },
};
std::ostringstream ss;
for(const auto& [k,v] : core_n){
auto &[implementer, variant, part] = k;
if (auto core = core_map.find(std::make_tuple(implementer, part)); core != core_map.end()) {
ss <<core->second << "*"<< v << "+";
}
else{
ss <<"[" <<implementer<<" | "<<part<< "]*"<< v << "+";
}
}
std::string r=ss.str();
if(r.size()<1) return "获取cpu信息失败"s;
return r.substr(0,r.size()-1);
}();
std::stringstream result;
result << "CPU [" << cpu_core_info << "]:\n";
if (cores.size() > 0) {
//TODO 理论上来讲所有核心的feature应该都是相同的
for (const auto& frature : cores[0].features) {
result << " * " << frature << "\n";
}
}
return result.str();
}
#endif
/*
int main() {
std::cout<< get_supported_extensions() << std::endl;
}*/
std::string get_auther_info(){
return "b站 路人aenu \n" \
"个人主页https://aenu.cc \n";
}
std::pair<std::string,bool> vk_lib_info(){
const std::pair<std::string,bool> dedault_info={"libvulkan.so",false};
const char* cfg_path=getenv("APS3E_CONFIG_YAML_PATH");
if(!cfg_path)
return dedault_info;
if(!std::filesystem::exists(cfg_path))
return dedault_info;
YAML::Node config_node = YAML::LoadFile(cfg_path);
if(!config_node.IsDefined())
return dedault_info;
YAML::Node use_custom_driver=config_node["Video"]["Vulkan"]["Use Custom Driver"];
if(!use_custom_driver.IsDefined())
return dedault_info;
if(!use_custom_driver.as<bool>())
return dedault_info;
YAML::Node custom_lib_path=config_node["Video"]["Vulkan"]["Custom Driver Library Path"];
if(!custom_lib_path.IsDefined())
return dedault_info;
std::string custom_lib_path_str=custom_lib_path.as<std::string>();
if(custom_lib_path_str.empty()||!std::filesystem::exists(custom_lib_path_str))
return dedault_info;
return {custom_lib_path_str,true};
}
std::string test_compute_pipeline_source(){
return R"(
#version 430
layout(local_size_x=32, local_size_y=1, local_size_z=1) in;
layout(set = 0, binding=0, std430) buffer ssbo{ uint data[]; };
#define KERNEL_SIZE 1
// Generic swap routines
#define bswap_u16(bits) (bits & 0xFF) << 8 | (bits & 0xFF00) >> 8 | (bits & 0xFF0000) << 8 | (bits & 0xFF000000) >> 8
#define bswap_u32(bits) (bits & 0xFF) << 24 | (bits & 0xFF00) << 8 | (bits & 0xFF0000) >> 8 | (bits & 0xFF000000) >> 24
#define bswap_u16_u32(bits) (bits & 0xFFFF) << 16 | (bits & 0xFFFF0000) >> 16
// Depth format conversions
#define d24_to_f32(bits) floatBitsToUint(float(bits) / 16777215.f)
#define f32_to_d24(bits) uint(uintBitsToFloat(bits) * 16777215.f)
#define d24f_to_f32(bits) (bits << 7)
#define f32_to_d24f(bits) (bits >> 7)
#define d24x8_to_f32(bits) d24_to_f32(bits >> 8)
#define d24x8_to_d24x8_swapped(bits) (bits & 0xFF00) | (bits & 0xFF0000) >> 16 | (bits & 0xFF) << 16
#define f32_to_d24x8_swapped(bits) d24x8_to_d24x8_swapped(f32_to_d24(bits))
uint linear_invocation_id()
{
uint size_in_x = (gl_NumWorkGroups.x * gl_WorkGroupSize.x);
return (gl_GlobalInvocationID.y * size_in_x) + gl_GlobalInvocationID.x;
}
void main()
{
uint invocation_id = linear_invocation_id();
uint index = invocation_id * KERNEL_SIZE;
uint value;
{
value = data[index];
data[index] = bswap_u32(value);
}
}
)";
}
std::string get_gpu_info(){
std::pair<std::string,bool> lib_info=vk_lib_info();
vk_load(lib_info.first.c_str(),lib_info.second);
struct clean_t{
std::vector<std::function<void()>> funcs;
~clean_t(){
for(auto it=funcs.rbegin();it!=funcs.rend();it++){
(*it)();
}
}
}clean;
clean.funcs.push_back([](){
vk_unload();
});
std::optional<VkInstance> inst=vk_create_instance("aps3e-gpu_info");
if(!inst) {
return "获取gpu信息失败";
}
clean.funcs.push_back([&](){
vk_destroy_instance(*inst);
});
if(int count=vk_get_physical_device_count(*inst);count!=1) {
if(count<1){
return "获取gpu信息失败";
}
if(count>1){
return "多个gpu!";
}
}
if(auto pdev=vk_get_physical_device(*inst);pdev) {
std::string gpu_name=vk_get_physical_device_properties(*pdev).deviceName;
std::string gpu_vk_ver=[](uint32_t v) {
std::ostringstream oss;
oss << (v >> 22) << "." << ((v >> 12) & 0x3ff) << "." << (v & 0xfff);
return oss.str();
}(vk_get_physical_device_properties(*pdev).apiVersion);
std::string gpu_ext=[&]() {
std::ostringstream oss;
for (auto ext : vk_get_physical_device_extension_properties(*pdev)) {
oss <<" * " << ext.extensionName << "\n";
}
return oss.str();
}();
#if 0
VkQueueFamilyProperties queue_family_props=vk_get_queue_family_properties(*pdev,0);
if(auto dev=vk_create_device(*pdev,0,queue_family_props);dev){
clean.funcs.push_back([&](){
vk_destroy_device(*dev);
});
std::vector<VkDescriptorSetLayoutBinding> binds;
binds.push_back(
VkDescriptorSetLayoutBinding{0,VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,1,VK_SHADER_STAGE_COMPUTE_BIT,nullptr});
auto descriptor_set_layout=vk_create_descriptor_set_layout(*dev,binds);
clean.funcs.push_back([&](){
vk_destroy_descriptor_set_layout(*dev,*descriptor_set_layout);
});
auto pipeline_layout=vk_create_pipeline_layout(*dev,*descriptor_set_layout);
clean.funcs.push_back([&](){
vk_destroy_pipeline_layout(*dev,*pipeline_layout);
});
std::optional<std::vector<uint32_t>> spv=vk_compile_glsl_to_spv(*dev,test_compute_pipeline_source(),vk_get_physical_device_limits(*pdev));
auto module=vk_create_shader_module(*dev,*spv);
clean.funcs.push_back([&](){
vk_destroy_shader_module(*dev,*module);
});
auto pipeline=vk_create_compute_pipeline(*dev,*pipeline_layout,*module);
if(pipeline){
gpu_name+=":ok";
clean.funcs.push_back([&](){
vk_destroy_pipeline(*dev,*pipeline);
});
return "GPU [" + gpu_name +"(VK: "+gpu_vk_ver+ ")]:\n" + gpu_ext;
}
}
#endif
return "GPU [" + gpu_name +"(VK: "+gpu_vk_ver+ ")]:\n" + gpu_ext;
}
return "获取gpu信息失败";
}
std::string get_cpu_info() {
std::vector<core_info_t> core_info=cpu_get_core_info();
std::string cpu_name=cpu_get_simple_info(core_info);
std::string cpu_features=[&](){
std::ostringstream oss;
for(const auto& feature : core_info[0].features){
oss <<" * " << feature << "\n";
}
return oss.str();
}();
return "CPU [" + cpu_name + "]:\n" + cpu_features;
}
extern "C"
{
JNIEXPORT jstring JNICALL Java_aenu_proptest_HelloJni_stringFromJNI(JNIEnv* env, jobject thiz)
{
std::string vv;//=get_auther_info();
vv+=get_cpu_info();
vv+="\n"+get_gpu_info();
return env->NewStringUTF(vv.c_str());
}
}

View File

@@ -0,0 +1,37 @@
#!/bin/sh -ex
# Pull all the submodules except llvm
# Note: Tried to use git submodule status, but it takes over 20 seconds
# shellcheck disable=SC2046
git submodule -q update --init --depth 1 $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
# Prefer newer Clang than in base system (see also .ci/install-freebsd.sh)
# libc++ isn't in llvm* packages, so download manually
fetch https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.1/llvm-project-16.0.1.src.tar.xz
tar xf llvm*.tar.xz
export CC=clang16 CXX=clang++16
cmake -B libcxx_build -G Ninja -S llvm*/libcxx \
-DLLVM_CCACHE_BUILD=ON \
-DLIBCXX_INCLUDE_BENCHMARKS=OFF \
-DCMAKE_INSTALL_PREFIX:PATH=libcxx_prefix
cmake --build libcxx_build
cmake --install libcxx_build
export CXXFLAGS="$CXXFLAGS -nostdinc++ -isystem$PWD/libcxx_prefix/include/c++/v1"
export LDFLAGS="$LDFLAGS -nostdlib++ -L$PWD/libcxx_prefix/lib -l:libc++.a -lcxxrt"
CONFIGURE_ARGS="
-DWITH_LLVM=ON
-DUSE_SDL=OFF
-DUSE_PRECOMPILED_HEADERS=OFF
-DUSE_NATIVE_INSTRUCTIONS=OFF
-DUSE_SYSTEM_FFMPEG=ON
-DUSE_SYSTEM_CURL=ON
-DUSE_SYSTEM_LIBPNG=ON
"
# shellcheck disable=SC2086
cmake -B build -G Ninja $CONFIGURE_ARGS
cmake --build build
ccache --show-stats
ccache --zero-stats

View File

@@ -0,0 +1,47 @@
#!/bin/sh -ex
if [ -z "$CIRRUS_CI" ]; then
cd rpcs3 || exit 1
fi
git config --global --add safe.directory '*'
# Pull all the submodules except llvm
# shellcheck disable=SC2046
git submodule -q update --init $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
mkdir build && cd build || exit 1
export CC="${CLANG_BINARY}"
export CXX="${CLANGXX_BINARY}"
cmake .. \
-DCMAKE_INSTALL_PREFIX=/usr \
-DUSE_NATIVE_INSTRUCTIONS=OFF \
-DUSE_PRECOMPILED_HEADERS=OFF \
-DCMAKE_C_FLAGS="$CFLAGS" \
-DCMAKE_CXX_FLAGS="$CFLAGS" \
-DUSE_SYSTEM_CURL=ON \
-DUSE_SDL=ON \
-DUSE_SYSTEM_SDL=ON \
-DUSE_SYSTEM_FFMPEG=OFF \
-DUSE_DISCORD_RPC=ON \
-DOpenGL_GL_PREFERENCE=LEGACY \
-DLLVM_DIR=/opt/llvm/lib/cmake/llvm \
-DSTATIC_LINK_LLVM=ON \
-G Ninja
ninja; build_status=$?;
cd ..
shellcheck .ci/*.sh
# If it compiled succesfully let's deploy.
# Azure and Cirrus publish PRs as artifacts only.
{ [ "$CI_HAS_ARTIFACTS" = "true" ];
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
.ci/deploy-linux.sh "aarch64"
fi

View File

@@ -0,0 +1,66 @@
#!/bin/sh -ex
if [ -z "$CIRRUS_CI" ]; then
cd rpcs3 || exit 1
fi
git config --global --add safe.directory '*'
# Pull all the submodules except llvm
# Note: Tried to use git submodule status, but it takes over 20 seconds
# shellcheck disable=SC2046
git submodule -q update --init $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
mkdir build && cd build || exit 1
if [ "$COMPILER" = "gcc" ]; then
# These are set in the dockerfile
export CC="${GCC_BINARY}"
export CXX="${GXX_BINARY}"
export LINKER=gold
# We need to set the following variables for LTO to link properly
export AR=/usr/bin/gcc-ar-"$GCCVER"
export RANLIB=/usr/bin/gcc-ranlib-"$GCCVER"
export CFLAGS="-fuse-linker-plugin"
else
export CC="${CLANG_BINARY}"
export CXX="${CLANGXX_BINARY}"
export LINKER=lld
export AR=/usr/bin/llvm-ar-"$LLVMVER"
export RANLIB=/usr/bin/llvm-ranlib-"$LLVMVER"
fi
export CFLAGS="$CFLAGS -fuse-ld=${LINKER}"
cmake .. \
-DCMAKE_INSTALL_PREFIX=/usr \
-DUSE_NATIVE_INSTRUCTIONS=OFF \
-DUSE_PRECOMPILED_HEADERS=OFF \
-DCMAKE_C_FLAGS="$CFLAGS" \
-DCMAKE_CXX_FLAGS="$CFLAGS" \
-DCMAKE_AR="$AR" \
-DCMAKE_RANLIB="$RANLIB" \
-DUSE_SYSTEM_CURL=ON \
-DUSE_SDL=ON \
-DUSE_SYSTEM_SDL=ON \
-DUSE_SYSTEM_FFMPEG=OFF \
-DUSE_DISCORD_RPC=ON \
-DOpenGL_GL_PREFERENCE=LEGACY \
-DLLVM_DIR=/opt/llvm/lib/cmake/llvm \
-DSTATIC_LINK_LLVM=ON \
-G Ninja
ninja; build_status=$?;
cd ..
shellcheck .ci/*.sh
# If it compiled succesfully let's deploy.
# Azure and Cirrus publish PRs as artifacts only.
{ [ "$CI_HAS_ARTIFACTS" = "true" ];
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
.ci/deploy-linux.sh "x86_64"
fi

View File

@@ -0,0 +1,153 @@
#!/bin/sh -ex
# shellcheck disable=SC2086
brew_arm64_install_packages() {
for pkg in "$@"; do
echo "Fetching bottle for $pkg (arm64)..."
bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_ventura "$pkg")"
if [ ! -f "$bottle_path" ]; then
if ! "$BREW_ARM64_PATH/bin/brew" fetch --force --verbose --debug --bottle-tag=arm64_ventura "$pkg"; then
echo "Failed to fetch bottle for $pkg"
return 1
fi
bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_ventura "$pkg")"
fi
echo "Installing $pkg (arm64)..."
"$BREW_ARM64_PATH/bin/brew" install --force --force-bottle --ignore-dependencies "$bottle_path" || true
done
}
export HOMEBREW_NO_AUTO_UPDATE=1
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
export HOMEBREW_NO_INSTALL_CLEANUP=1
/usr/local/bin/brew update
sudo rm -rf /usr/local/Cellar/curl /usr/local/opt/curl
/usr/local/bin/brew install -f --overwrite curl
/usr/local/bin/brew uninstall -f --ignore-dependencies ffmpeg
/usr/local/bin/brew install -f --build-from-source ffmpeg@5 || true
/usr/local/bin/brew install -f --overwrite python || true
/usr/local/bin/brew link --overwrite python || true
/usr/local/bin/brew install -f --overwrite nasm ninja p7zip ccache pipenv #create-dmg
/usr/local/bin/brew link -f curl || true
/usr/local/bin/brew install llvm@$LLVM_COMPILER_VER glew cmake sdl2 vulkan-headers coreutils
/usr/local/bin/brew link -f llvm@$LLVM_COMPILER_VER ffmpeg@5 || true
export BREW_ARM64_PATH="/opt/homebrew1"
sudo mkdir -p "$BREW_ARM64_PATH"
sudo chmod 777 "$BREW_ARM64_PATH"
curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C "$BREW_ARM64_PATH"
#"$BREW_ARM64_PATH/bin/brew" update
# libvorbis requires Homebrew-installed curl, but we can't run it on x64, and we also need the aarch64 libs, so we swap the binary
brew_arm64_install_packages curl
mv /opt/homebrew1/opt/curl/bin/curl /opt/homebrew1/opt/curl/bin/curl.bak
ln -s /usr/local/opt/curl/bin/curl /opt/homebrew1/opt/curl/bin/curl
brew_arm64_install_packages 0mq aom aribb24 ca-certificates cjson dav1d ffmpeg@5 fontconfig freetype freetype2 gettext glew gmp gnutls lame libbluray libidn2 libnettle libogg libpng librist libsodium libsoxr libtasn libtasn1 libunistring libvmaf libvorbis libvpx libx11 libxau libxcb libxdmcp llvm@$LLVM_COMPILER_VER mbedtls molten-vk nettle opencore-amr openjpeg openssl opus p11-kit pkg-config pkgconfig pzstd rav1e sdl2 snappy speex srt svt-av1 theora vulkan-headers webp x264 x265 xz z3 zeromq zmq zstd
"$BREW_ARM64_PATH/bin/brew" link -f ffmpeg@5
# moltenvk based on commit for 1.2.11 release
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/6bfc8950c696d1f952425e8af2a6248603dc0df9/Formula/m/molten-vk.rb
/usr/local/bin/brew install -f --overwrite ./molten-vk.rb
export CXX=clang++
export CC=clang
export BREW_PATH;
BREW_PATH="$(brew --prefix)"
export BREW_X64_PATH;
BREW_X64_PATH="$("/usr/local/bin/brew" --prefix)"
export BREW_BIN="/usr/local/bin"
export BREW_SBIN="/usr/local/sbin"
export CMAKE_EXTRA_OPTS='-DLLVM_TARGETS_TO_BUILD=arm64'
export WORKDIR;
WORKDIR="$(pwd)"
# Get Qt
if [ ! -d "/tmp/Qt/$QT_VER" ]; then
mkdir -p "/tmp/Qt"
git clone https://github.com/engnr/qt-downloader.git
cd qt-downloader
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
cd "/tmp/Qt"
"$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats
fi
cd "$WORKDIR"
ditto "/tmp/Qt/$QT_VER" "qt-downloader/$QT_VER"
export Qt6_DIR="$WORKDIR/qt-downloader/$QT_VER/clang_64/lib/cmake/Qt$QT_VER_MAIN"
export SDL2_DIR="$BREW_ARM64_PATH/opt/sdl2/lib/cmake/SDL2"
export PATH="$BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
export LDFLAGS="-L$BREW_ARM64_PATH/lib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libavcodec.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libavformat.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libavutil.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libswscale.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libswresample.dylib $BREW_ARM64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++.1.dylib $BREW_ARM64_PATH/lib/libSDL2.dylib $BREW_ARM64_PATH/lib/libGLEW.dylib $BREW_ARM64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/libunwind.1.dylib -Wl,-rpath,$BREW_ARM64_PATH/lib"
export CPPFLAGS="-I$BREW_ARM64_PATH/include -I$BREW_X64_PATH/include -no-pie -D__MAC_OS_X_VERSION_MIN_REQUIRED=130000"
export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000"
export LIBRARY_PATH="$BREW_ARM64_PATH/lib"
export LD_LIBRARY_PATH="$BREW_ARM64_PATH/lib"
export VULKAN_SDK
VULKAN_SDK="$BREW_ARM64_PATH/opt/molten-vk"
ln -s "$VULKAN_SDK/lib/libMoltenVK.dylib" "$VULKAN_SDK/lib/libvulkan.dylib" || true
export VK_ICD_FILENAMES="$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json"
export LLVM_DIR
LLVM_DIR="$BREW_ARM64_PATH/opt/llvm@$LLVM_COMPILER_VER"
# exclude ffmpeg, LLVM, and sdl from submodule update
# shellcheck disable=SC2046
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/ffmpeg/ && !/llvm/ && !/SDL/ { print $3 }' .gitmodules)
# 3rdparty fixes
sed -i '' "s/extern const double NSAppKitVersionNumber;/const double NSAppKitVersionNumber = 1343;/g" 3rdparty/hidapi/hidapi/mac/hid.c
rm -rf build
mkdir build && cd build || exit 1
export MACOSX_DEPLOYMENT_TARGET=13.0
"$BREW_X64_PATH/bin/cmake" .. \
-DUSE_SDL=ON \
-DUSE_DISCORD_RPC=OFF \
-DUSE_VULKAN=ON \
-DUSE_ALSA=OFF \
-DUSE_PULSE=OFF \
-DUSE_AUDIOUNIT=ON \
-DUSE_SYSTEM_FFMPEG=ON \
-DLLVM_CCACHE_BUILD=OFF \
-DLLVM_BUILD_RUNTIME=OFF \
-DLLVM_BUILD_TOOLS=OFF \
-DLLVM_INCLUDE_DOCS=OFF \
-DLLVM_INCLUDE_EXAMPLES=OFF \
-DLLVM_INCLUDE_TESTS=OFF \
-DLLVM_INCLUDE_TOOLS=OFF \
-DLLVM_INCLUDE_UTILS=OFF \
-DLLVM_USE_PERF=OFF \
-DLLVM_ENABLE_Z3_SOLVER=OFF \
-DUSE_NATIVE_INSTRUCTIONS=OFF \
-DUSE_SYSTEM_MVK=ON \
-DUSE_SYSTEM_FAUDIO=OFF \
-DUSE_SYSTEM_SDL=ON \
$CMAKE_EXTRA_OPTS \
-DLLVM_TARGET_ARCH=arm64 \
-DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_IGNORE_PATH="$BREW_X64_PATH/lib" \
-DCMAKE_IGNORE_PREFIX_PATH=/usr/local/opt \
-DCMAKE_SYSTEM_PROCESSOR=arm64 \
-DCMAKE_TOOLCHAIN_FILE=buildfiles/cmake/TCDarwinARM64.cmake \
-DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000" \
-G Ninja
"$BREW_PATH/bin/ninja"; build_status=$?;
cd ..
{ [ "$CI_HAS_ARTIFACTS" = "true" ];
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
.ci/deploy-mac-arm64.sh
fi

View File

@@ -0,0 +1,117 @@
#!/bin/sh -ex
# shellcheck disable=SC2086
export HOMEBREW_NO_AUTO_UPDATE=1
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
brew unlink certifi
brew install -f --overwrite nasm ninja p7zip ccache pipenv #create-dmg
#/usr/sbin/softwareupdate --install-rosetta --agree-to-license
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
arch -x86_64 /usr/local/bin/brew update
arch -x86_64 /usr/local/bin/brew install -f --overwrite python || arch -x86_64 /usr/local/bin/brew link --overwrite python
arch -x86_64 /usr/local/bin/brew uninstall -f --ignore-dependencies ffmpeg
arch -x86_64 /usr/local/bin/brew install -f --build-from-source ffmpeg@5
arch -x86_64 /usr/local/bin/brew reinstall -f --build-from-source gnutls freetype
arch -x86_64 /usr/local/bin/brew install llvm@$LLVM_COMPILER_VER glew cmake sdl2 vulkan-headers coreutils
arch -x86_64 /usr/local/bin/brew link -f llvm@$LLVM_COMPILER_VER ffmpeg@5
# moltenvk based on commit for 1.2.11 release
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/6bfc8950c696d1f952425e8af2a6248603dc0df9/Formula/m/molten-vk.rb
arch -x86_64 /usr/local/bin/brew install -f --overwrite ./molten-vk.rb
export CXX=clang++
export CC=clang
export BREW_PATH;
BREW_PATH="$(brew --prefix)"
export BREW_X64_PATH;
BREW_X64_PATH="$("/usr/local/bin/brew" --prefix)"
export BREW_BIN="/usr/local/bin"
export BREW_SBIN="/usr/local/sbin"
export CMAKE_EXTRA_OPTS='-DLLVM_TARGETS_TO_BUILD=X86'
export WORKDIR;
WORKDIR="$(pwd)"
# Get Qt
if [ ! -d "/tmp/Qt/$QT_VER" ]; then
mkdir -p "/tmp/Qt"
git clone https://github.com/engnr/qt-downloader.git
cd qt-downloader
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
cd "/tmp/Qt"
"$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats
fi
cd "$WORKDIR"
ditto "/tmp/Qt/$QT_VER" "qt-downloader/$QT_VER"
export Qt6_DIR="$WORKDIR/qt-downloader/$QT_VER/clang_64/lib/cmake/Qt$QT_VER_MAIN"
export SDL2_DIR="$BREW_X64_PATH/opt/sdl2/lib/cmake/SDL2"
export PATH="$BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
export LDFLAGS="-L$BREW_X64_PATH/lib -Wl,-rpath,$BREW_X64_PATH/lib"
export CPPFLAGS="-I$BREW_X64_PATH/include -msse -msse2 -mcx16 -no-pie -D__MAC_OS_X_VERSION_MIN_REQUIRED=130000"
export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000"
export LIBRARY_PATH="$BREW_X64_PATH/lib"
export LD_LIBRARY_PATH="$BREW_X64_PATH/lib"
export VULKAN_SDK
VULKAN_SDK="$BREW_X64_PATH/opt/molten-vk"
ln -s "$VULKAN_SDK/lib/libMoltenVK.dylib" "$VULKAN_SDK/lib/libvulkan.dylib"
export VK_ICD_FILENAMES="$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json"
export LLVM_DIR
LLVM_DIR="BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER"
# exclude ffmpeg, LLVM, and sdl from submodule update
# shellcheck disable=SC2046
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/ffmpeg/ && !/llvm/ && !/SDL/ { print $3 }' .gitmodules)
# 3rdparty fixes
sed -i '' "s/extern const double NSAppKitVersionNumber;/const double NSAppKitVersionNumber = 1343;/g" 3rdparty/hidapi/hidapi/mac/hid.c
mkdir build && cd build || exit 1
export MACOSX_DEPLOYMENT_TARGET=13.0
"$BREW_X64_PATH/bin/cmake" .. \
-DUSE_SDL=ON \
-DUSE_DISCORD_RPC=ON \
-DUSE_VULKAN=ON \
-DUSE_ALSA=OFF \
-DUSE_PULSE=OFF \
-DUSE_AUDIOUNIT=ON \
-DUSE_SYSTEM_FFMPEG=ON \
-DLLVM_CCACHE_BUILD=OFF \
-DLLVM_BUILD_RUNTIME=OFF \
-DLLVM_BUILD_TOOLS=OFF \
-DLLVM_INCLUDE_DOCS=OFF \
-DLLVM_INCLUDE_EXAMPLES=OFF \
-DLLVM_INCLUDE_TESTS=OFF \
-DLLVM_INCLUDE_TOOLS=OFF \
-DLLVM_INCLUDE_UTILS=OFF \
-DLLVM_USE_PERF=OFF \
-DLLVM_ENABLE_Z3_SOLVER=OFF \
-DUSE_NATIVE_INSTRUCTIONS=OFF \
-DUSE_SYSTEM_MVK=ON \
-DUSE_SYSTEM_FAUDIO=OFF \
-DUSE_SYSTEM_SDL=ON \
$CMAKE_EXTRA_OPTS \
-DLLVM_TARGET_ARCH=X86_64 \
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DCMAKE_IGNORE_PATH="$BREW_PATH/lib" \
-DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000" \
-G Ninja
"$BREW_PATH/bin/ninja"; build_status=$?;
cd ..
{ [ "$CI_HAS_ARTIFACTS" = "true" ];
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
.ci/deploy-mac.sh
fi

View File

@@ -0,0 +1,55 @@
#!/bin/sh -ex
cd build || exit 1
CPU_ARCH="${1:-x86_64}"
if [ "$DEPLOY_APPIMAGE" = "true" ]; then
DESTDIR=AppDir ninja install
curl -fsSLo /usr/bin/linuxdeploy "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-$CPU_ARCH.AppImage"
chmod +x /usr/bin/linuxdeploy
curl -fsSLo /usr/bin/linuxdeploy-plugin-qt "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-$CPU_ARCH.AppImage"
chmod +x /usr/bin/linuxdeploy-plugin-qt
curl -fsSLo linuxdeploy-plugin-checkrt.sh https://github.com/darealshinji/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt.sh
chmod +x ./linuxdeploy-plugin-checkrt.sh
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
export EXTRA_QT_PLUGINS="svg;wayland-decoration-client;wayland-graphics-integration-client;wayland-shell-integration;waylandcompositor"
APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt --plugin checkrt
# Remove libwayland-client because it has platform-dependent exports and breaks other OSes
rm -f ./AppDir/usr/lib/libwayland-client.so*
# Remove libvulkan because it causes issues with gamescope
rm -f ./AppDir/usr/lib/libvulkan.so*
# Remove git directory containing local commit history file
rm -rf ./AppDir/usr/share/rpcs3/git
linuxdeploy --appimage-extract
./squashfs-root/plugins/linuxdeploy-plugin-appimage/usr/bin/appimagetool AppDir -g
APPIMAGE_SUFFIX="linux_${CPU_ARCH}"
if [ "$CPU_ARCH" = "x86_64" ]; then
# Preserve back compat. Previous versions never included the full arch.
APPIMAGE_SUFFIX="linux64"
fi
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ../rpcs3/rpcs3_version.cpp)
COMM_COUNT="$(git rev-list --count HEAD)"
COMM_HASH="$(git rev-parse --short=8 HEAD)"
RPCS3_APPIMAGE="rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_${APPIMAGE_SUFFIX}.AppImage"
mv ./RPCS3*.AppImage "$RPCS3_APPIMAGE"
# If we're building using a CI, let's copy over the AppImage artifact
if [ -n "$BUILD_ARTIFACTSTAGINGDIRECTORY" ]; then
cp "$RPCS3_APPIMAGE" "$ARTDIR"
fi
FILESIZE=$(stat -c %s ./rpcs3*.AppImage)
SHA256SUM=$(sha256sum ./rpcs3*.AppImage | awk '{ print $1 }')
echo "${SHA256SUM};${FILESIZE}B" > "$RELEASE_MESSAGE"
fi

View File

@@ -0,0 +1,76 @@
#!/bin/sh -ex
# shellcheck disable=SC2086
cd build || exit 1
# Gather explicit version number and number of commits
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ../rpcs3/rpcs3_version.cpp)
COMM_COUNT=$(git rev-list --count HEAD)
COMM_HASH=$(git rev-parse --short=8 HEAD)
AVVER="${COMM_TAG}-${COMM_COUNT}"
# AVVER is used for GitHub releases, it is the version number.
echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
cd bin
mkdir "rpcs3.app/Contents/lib/" || true
cp "$(realpath /opt/homebrew1/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib)" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib"
cp "$(realpath /opt/homebrew1/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib"
cp "$(realpath /opt/homebrew1/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib"
rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
"rpcs3.app/Contents/Frameworks/QtQml.framework" \
"rpcs3.app/Contents/Frameworks/QtQmlModels.framework" \
"rpcs3.app/Contents/Frameworks/QtQuick.framework" \
"rpcs3.app/Contents/Frameworks/QtVirtualKeyboard.framework" \
"rpcs3.app/Contents/Plugins/platforminputcontexts" \
"rpcs3.app/Contents/Plugins/virtualkeyboard" \
"rpcs3.app/Contents/Resources/git"
../../.ci/optimize-mac.sh rpcs3.app
# Hack
install_name_tool \
-delete_rpath /opt/homebrew1/lib \
-delete_rpath /opt/homebrew/lib \
-delete_rpath /opt/homebrew1/opt/llvm@$LLVM_COMPILER_VER/lib \
-delete_rpath /usr/local/lib RPCS3.app/Contents/MacOS/rpcs3
#-delete_rpath /opt/homebrew1/Cellar/sdl2/2.30.7/lib
# Need to do this rename hack due to case insensitive filesystem
mv rpcs3.app RPCS3_.app
mv RPCS3_.app RPCS3.app
# NOTE: "--deep" is deprecated
codesign --deep -fs - RPCS3.app
echo "[InternetShortcut]" > Quickstart.url
echo "URL=https://rpcs3.net/quickstart" >> Quickstart.url
echo "IconIndex=0" >> Quickstart.url
#DMG_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos_arm64.dmg"
#"$BREW_X64_PATH/bin/create-dmg" --volname RPCS3 \
#--window-size 800 400 \
#--icon-size 100 \
#--icon rpcs3.app 200 190 \
#--add-file Quickstart.url Quickstart.url 400 20 \
#--hide-extension rpcs3.app \
#--hide-extension Quickstart.url \
#--app-drop-link 600 185 \
#--skip-jenkins \
#--format ULMO \
#"$DMG_FILEPATH" \
#RPCS3.app
#FILESIZE=$(stat -f %z "$DMG_FILEPATH")
#SHA256SUM=$(shasum -a 256 "$DMG_FILEPATH" | awk '{ print $1 }')
ARCHIVE_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos_arm64.7z"
"$BREW_X64_PATH/bin/7z" a -mx9 "$ARCHIVE_FILEPATH" RPCS3.app Quickstart.url
FILESIZE=$(stat -f %z "$ARCHIVE_FILEPATH")
SHA256SUM=$(shasum -a 256 "$ARCHIVE_FILEPATH" | awk '{ print $1 }')
cd ..
echo "${SHA256SUM};${FILESIZE}B" > "$RELEASE_MESSAGE"
cd bin

View File

@@ -0,0 +1,74 @@
#!/bin/sh -ex
# shellcheck disable=SC2086
cd build || exit 1
# Gather explicit version number and number of commits
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ../rpcs3/rpcs3_version.cpp)
COMM_COUNT=$(git rev-list --count HEAD)
COMM_HASH=$(git rev-parse --short=8 HEAD)
AVVER="${COMM_TAG}-${COMM_COUNT}"
# AVVER is used for GitHub releases, it is the version number.
echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
cd bin
mkdir "rpcs3.app/Contents/lib/"
cp "/usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
cp "$(realpath /usr/local/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib"
cp "$(realpath /usr/local/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib"
rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
"rpcs3.app/Contents/Frameworks/QtQml.framework" \
"rpcs3.app/Contents/Frameworks/QtQmlModels.framework" \
"rpcs3.app/Contents/Frameworks/QtQuick.framework" \
"rpcs3.app/Contents/Frameworks/QtVirtualKeyboard.framework" \
"rpcs3.app/Contents/Plugins/platforminputcontexts" \
"rpcs3.app/Contents/Plugins/virtualkeyboard" \
"rpcs3.app/Contents/Resources/git"
../../.ci/optimize-mac.sh rpcs3.app
# Need to do this rename hack due to case insensitive filesystem
mv rpcs3.app RPCS3_.app
mv RPCS3_.app RPCS3.app
# Hack
install_name_tool \
-delete_rpath /usr/local/lib \
-delete_rpath /usr/local/opt/llvm@$LLVM_COMPILER_VER/lib RPCS3.app/Contents/MacOS/rpcs3
#-delete_rpath /usr/local/Cellar/sdl2/2.30.3/lib
# NOTE: "--deep" is deprecated
codesign --deep -fs - RPCS3.app
echo "[InternetShortcut]" > Quickstart.url
echo "URL=https://rpcs3.net/quickstart" >> Quickstart.url
echo "IconIndex=0" >> Quickstart.url
#DMG_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos.dmg"
#"$BREW_X64_PATH/bin/create-dmg" --volname RPCS3 \
#--window-size 800 400 \
#--icon-size 100 \
#--icon rpcs3.app 200 190 \
#--add-file Quickstart.url Quickstart.url 400 20 \
#--hide-extension rpcs3.app \
#--hide-extension Quickstart.url \
#--app-drop-link 600 185 \
#--skip-jenkins \
#--format ULMO \
#"$DMG_FILEPATH" \
#RPCS3.app
#FILESIZE=$(stat -f %z "$DMG_FILEPATH")
#SHA256SUM=$(shasum -a 256 "$DMG_FILEPATH" | awk '{ print $1 }')
ARCHIVE_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos.7z"
"$BREW_X64_PATH/bin/7z" a -mx9 "$ARCHIVE_FILEPATH" RPCS3.app Quickstart.url
FILESIZE=$(stat -f %z "$ARCHIVE_FILEPATH")
SHA256SUM=$(shasum -a 256 "$ARCHIVE_FILEPATH" | awk '{ print $1 }')
cd ..
echo "${SHA256SUM};${FILESIZE}B" > "$RELEASE_MESSAGE"
cd bin

View File

@@ -0,0 +1,29 @@
#!/bin/sh -ex
# BUILD_blablabla is Azure specific, so we wrap it for portability
ARTIFACT_DIR="$BUILD_ARTIFACTSTAGINGDIRECTORY"
# Remove unecessary files
rm -f ./bin/rpcs3.exp ./bin/rpcs3.lib ./bin/rpcs3.pdb ./bin/vc_redist.x64.exe
rm -rf ./bin/git
# Prepare compatibility and SDL database for packaging
mkdir ./bin/config
mkdir ./bin/config/input_configs
curl -fsSL 'https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt' 1> ./bin/config/input_configs/gamecontrollerdb.txt
curl -fsSL 'https://rpcs3.net/compatibility?api=v1&export' | iconv -t UTF-8 1> ./bin/GuiConfigs/compat_database.dat
# Download SSL certificate (not needed with CURLSSLOPT_NATIVE_CA)
#curl -fsSL 'https://curl.haxx.se/ca/cacert.pem' 1> ./bin/cacert.pem
# Package artifacts
7z a -m0=LZMA2 -mx9 "$BUILD" ./bin/*
# Generate sha256 hashes
# Write to file for GitHub releases
sha256sum "$BUILD" | awk '{ print $1 }' | tee "$BUILD.sha256"
echo "$(cat "$BUILD.sha256");$(stat -c %s "$BUILD")B" > GitHubReleaseMessage.txt
# Move files to publishing directory
cp -- "$BUILD" "$ARTIFACT_DIR"
cp -- "$BUILD.sha256" "$ARTIFACT_DIR"

View File

@@ -0,0 +1,15 @@
# Variables set by Azure Pipelines
CI_HAS_ARTIFACTS
BUILD_REASON
BUILD_SOURCEVERSION
BUILD_ARTIFACTSTAGINGDIRECTORY
BUILD_REPOSITORY_NAME
BUILD_SOURCEBRANCHNAME
APPDIR
ARTDIR
RELEASE_MESSAGE
# Variables for build matrix
COMPILER
DEPLOY_APPIMAGE
# Private variables
GITHUB_TOKEN

View File

@@ -0,0 +1,13 @@
#!/bin/sh -e
# Export variables for later stages of the Azure pipeline
# Values done in this manner will appear as environment variables
# in later stages.
# From pure-sh-bible
# Setting 'IFS' tells 'read' where to split the string.
while IFS='=' read -r key val; do
# Skip over lines containing comments.
[ "${key##\#*}" ] || continue
echo "##vso[task.setvariable variable=$key]$val"
done < ".ci/ci-vars.env"

View File

@@ -0,0 +1,13 @@
#!/bin/sh -e
# Export variables for later stages of the Cirrus pipeline
# Values done in this manner will appear as environment variables
# in later stages.
# From pure-sh-bible
# Setting 'IFS' tells 'read' where to split the string.
while IFS='=' read -r key val; do
# Skip over lines containing comments.
[ "${key##\#*}" ] || continue
export "$key"="$val"
done < ".ci/ci-vars.env"

View File

@@ -0,0 +1,4 @@
#!/bin/sh -ex
curl -fLo "./llvm.lock" "https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-16.0.1/llvmlibs_mt.7z.sha256"
curl -fLo "./glslang.lock" "https://github.com/RPCS3/glslang/releases/download/custom-build-win/glslanglibs_mt.7z.sha256"

View File

@@ -0,0 +1,42 @@
#!/bin/sh -ex
ARTIFACT_DIR="$BUILD_ARTIFACTSTAGINGDIRECTORY"
generate_post_data()
{
body=$(cat GitHubReleaseMessage.txt)
cat <<EOF
{
"tag_name": "build-${BUILD_SOURCEVERSION}",
"target_commitish": "${UPLOAD_COMMIT_HASH}",
"name": "${AVVER}",
"body": "$body",
"draft": false,
"prerelease": false
}
EOF
}
curl -fsS \
-H "Authorization: token ${RPCS3_TOKEN}" \
-H "Accept: application/vnd.github.v3+json" \
--data "$(generate_post_data)" "https://api.github.com/repos/$UPLOAD_REPO_FULL_NAME/releases" >> release.json
cat release.json
id=$(grep '"id"' release.json | cut -d ':' -f2 | head -n1 | awk '{$1=$1;print}')
id=${id%?}
echo "${id:?}"
upload_file()
{
curl -fsS \
-H "Authorization: token ${RPCS3_TOKEN}" \
-H "Accept: application/vnd.github.v3+json" \
-H "Content-Type: application/octet-stream" \
--data-binary @"$2"/"$3" \
"https://uploads.github.com/repos/$UPLOAD_REPO_FULL_NAME/releases/$1/assets?name=$3"
}
for file in "$ARTIFACT_DIR"/*; do
name=$(basename "$file")
upload_file "$id" "$ARTIFACT_DIR" "$name"
done

View File

@@ -0,0 +1,18 @@
#!/usr/bin/env -S su -m root -ex
# NOTE: this script is run under root permissions
# shellcheck shell=sh disable=SC2096
# RPCS3 often needs recent Qt and Vulkan-Headers
sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
export ASSUME_ALWAYS_YES=true
pkg info # debug
# Prefer newer Clang than in base system (see also .ci/build-freebsd.sh)
pkg install llvm16
# Mandatory dependencies (qt6-base is pulled via qt6-multimedia)
pkg install git ccache cmake ninja qt6-multimedia qt6-svg glew openal-soft ffmpeg
# Optional dependencies (libevdev is pulled by qt6-base)
pkg install pkgconf alsa-lib pulseaudio sdl2 evdev-proto vulkan-headers vulkan-loader

View File

@@ -0,0 +1,21 @@
#!/bin/sh
file_path=$(find "$1/Contents/MacOS" -type f -print0 | head -n 1)
if [ -z "$file_path" ]; then
echo "No executable file found in $1/Contents/MacOS" >&2
exit 1
fi
target_architecture="$(lipo "$file_path" -archs)"
if [ -z "$target_architecture" ]; then
exit 1
fi
# shellcheck disable=SC3045
find "$1" -type f -print0 | while IFS= read -r -d '' file; do
echo Thinning "$file" -> "$target_architecture"
lipo "$file" -thin "$target_architecture" -output "$file" || true
done

View File

@@ -0,0 +1,118 @@
#!/bin/sh -ex
# These are Azure specific, so we wrap them for portability
REPO_NAME="$BUILD_REPOSITORY_NAME"
REPO_BRANCH="$SYSTEM_PULLREQUEST_SOURCEBRANCH"
PR_NUMBER="$SYSTEM_PULLREQUEST_PULLREQUESTID"
# Resource/dependency URLs
# Qt mirrors can be volatile and slow, so we list 2
#QT_HOST="http://mirrors.ocf.berkeley.edu/qt/"
QT_HOST="http://qt.mirror.constant.com/"
QT_URL_VER=$(echo "$QT_VER" | sed "s/\.//g")
QT_VER_MSVC_UP=$(echo "${QT_VER_MSVC}" | tr '[:lower:]' '[:upper:]')
QT_PREFIX="online/qtsdkrepository/windows_x86/desktop/qt${QT_VER_MAIN}_${QT_URL_VER}/qt.qt${QT_VER_MAIN}.${QT_URL_VER}."
QT_PREFIX_2="win64_${QT_VER_MSVC}_64/${QT_VER}-0-${QT_DATE}"
QT_SUFFIX="-Windows-Windows_10_22H2-${QT_VER_MSVC_UP}-Windows-Windows_10_22H2-X86_64.7z"
QT_BASE_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtbase${QT_SUFFIX}"
QT_DECL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtdeclarative${QT_SUFFIX}"
QT_TOOL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qttools${QT_SUFFIX}"
QT_MM_URL="${QT_HOST}${QT_PREFIX}addons.qtmultimedia.${QT_PREFIX_2}qtmultimedia${QT_SUFFIX}"
QT_SVG_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtsvg${QT_SUFFIX}"
LLVMLIBS_URL='https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-16.0.1/llvmlibs_mt.7z'
GLSLANG_URL='https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z'
VULKAN_SDK_URL="https://www.dropbox.com/scl/fi/sjjh0fc4ld281pjbl2xzu/VulkanSDK-1.3.268.0-Installer.exe?rlkey=f6wzc0lvms5vwkt2z3qabfv9d&dl=1"
DEP_URLS=" \
$QT_BASE_URL \
$QT_DECL_URL \
$QT_TOOL_URL \
$QT_MM_URL \
$QT_SVG_URL \
$LLVMLIBS_URL \
$GLSLANG_URL \
$VULKAN_SDK_URL"
# Azure pipelines doesn't make a cache dir if it doesn't exist, so we do it manually
[ -d "$CACHE_DIR" ] || mkdir "$CACHE_DIR"
# Pull all the submodules except llvm, since it is built separately and we just download that build
# Note: Tried to use git submodule status, but it takes over 20 seconds
# shellcheck disable=SC2046
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/FAudio/ && !/llvm/ { print $3 }' .gitmodules)
# Git bash doesn't have rev, so here it is
rev()
{
echo "$1" | awk '{ for(i = length($0); i != 0; --i) { a = a substr($0, i, 1); } } END { print a }'
}
# Usage: download_and_verify url checksum algo file
# Check to see if a file is already cached, and the checksum matches. If not, download it.
# Tries up to 3 times
download_and_verify()
{
url="$1"
correctChecksum="$2"
algo="$3"
fileName="$4"
for _ in 1 2 3; do
[ -e "$CACHE_DIR/$fileName" ] || curl -fLo "$CACHE_DIR/$fileName" "$url"
fileChecksum=$("${algo}sum" "$CACHE_DIR/$fileName" | awk '{ print $1 }')
[ "$fileChecksum" = "$correctChecksum" ] && return 0
rm "$CACHE_DIR/$fileName"
done
return 1;
}
# Some dependencies install here
[ -d "./lib" ] || mkdir "./lib"
for url in $DEP_URLS; do
# Get the filename from the URL and remove query strings (?arg=something).
fileName="$(rev "$(rev "$url" | cut -d'/' -f1)" | cut -d'?' -f1)"
[ -z "$fileName" ] && echo "Unable to parse url: $url" && exit 1
# shellcheck disable=SC1003
case "$url" in
*qt*) checksum=$(curl -fL "${url}.sha1"); algo="sha1"; outDir='C:\Qt\' ;;
*llvm*) checksum=$(curl -fL "${url}.sha256"); algo="sha256"; outDir="./3rdparty/llvm" ;;
*glslang*) checksum=$(curl -fL "${url}.sha256"); algo="sha256"; outDir="./lib/Release-x64" ;;
*Vulkan*)
# Vulkan setup needs to be run in batch environment
# Need to subshell this or else it doesn't wait
download_and_verify "$url" "$VULKAN_SDK_SHA" "sha256" "$fileName"
cp "$CACHE_DIR/$fileName" .
_=$(echo "$fileName --accept-licenses --default-answer --confirm-command install" | cmd)
continue
;;
*) echo "Unknown url resource: $url"; exit 1 ;;
esac
download_and_verify "$url" "$checksum" "$algo" "$fileName"
7z x -y "$CACHE_DIR/$fileName" -aos -o"$outDir"
done
# Gather explicit version number and number of commits
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ./rpcs3/rpcs3_version.cpp)
COMM_COUNT=$(git rev-list --count HEAD)
COMM_HASH=$(git rev-parse --short=8 HEAD)
# Format the above into filenames
if [ -n "$PR_NUMBER" ]; then
AVVER="${COMM_TAG}-${COMM_HASH}"
BUILD="rpcs3-v${AVVER}_win64.7z"
else
AVVER="${COMM_TAG}-${COMM_COUNT}"
BUILD="rpcs3-v${AVVER}-${COMM_HASH}_win64.7z"
fi
# BRANCH is used for experimental build warnings for pr builds, used in main_window.cpp.
# BUILD is the name of the release artifact
# AVVER is used for GitHub releases, it is the version number.
BRANCH="${REPO_NAME}/${REPO_BRANCH}"
echo "BRANCH=$BRANCH" > .ci/ci-vars.env
echo "BUILD=$BUILD" >> .ci/ci-vars.env
echo "AVVER=$AVVER" >> .ci/ci-vars.env

View File

@@ -0,0 +1,151 @@
env:
CIRRUS_CLONE_DEPTH: 0 # Unshallow clone to obtain proper GIT_VERSION
BUILD_REPOSITORY_NAME: $CIRRUS_REPO_FULL_NAME
SYSTEM_PULLREQUEST_SOURCEBRANCH: $CIRRUS_BRANCH
SYSTEM_PULLREQUEST_PULLREQUESTID: $CIRRUS_PR
BUILD_SOURCEVERSION: $CIRRUS_CHANGE_IN_REPO
BUILD_SOURCEBRANCHNAME: $CIRRUS_BRANCH
RPCS3_TOKEN: ENCRYPTED[100ebb8e3552bf2021d0ef55dccda3e58d27be5b6cab0b0b92843ef490195d3c4edaefa087e4a3b425caa6392300b9b1]
QT_VER_MAIN: '6'
QT_VER: '6.7.3'
# windows_task:
# matrix:
# - name: Cirrus Windows
# windows_container:
# image: cirrusci/windowsservercore:visualstudio2019
# cpu: 8
# memory: 16G
# env:
# CIRRUS_SHELL: "bash"
# COMPILER: msvc
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}\artifacts\
# QT_VER_MSVC: 'msvc2019'
# QT_DATE: '202409200836'
# QTDIR: C:\Qt\${QT_VER}\${QT_VER_MSVC}_64
# VULKAN_VER: '1.3.268.0'
# VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
# VULKAN_SDK: C:\VulkanSDK\${VULKAN_VER}
# CACHE_DIR: "./cache"
# UPLOAD_COMMIT_HASH: 7d09e3be30805911226241afbb14f8cdc2eb054e
# UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-win"
# deps_cache:
# folder: "./cache"
# #obj_cache:
# # folder: "./tmp"
# #obj2_cache:
# # folder: "./rpcs3/x64"
# setup_script:
# - './.ci/get_keys-windows.sh'
# - './.ci/setup-windows.sh'
# rpcs3_script:
# - export PATH=${PATH}:"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin"
# - msbuild.exe rpcs3.sln //p:Configuration=Release //m
# deploy_script:
# - mkdir artifacts
# - source './.ci/export-cirrus-vars.sh'
# - './.ci/deploy-windows.sh'
# artifacts:
# name: Artifact
# path: "*.7z*"
# push_script: |
# if [ "$CIRRUS_REPO_OWNER" = "RPCS3" ] && [ -z "$CIRRUS_PR" ] && [ "$CIRRUS_BRANCH" = "master" ]; then
# source './.ci/export-cirrus-vars.sh'
# './.ci/github-upload.sh'
# fi;
# linux_task:
# container:
# image: rpcs3/rpcs3-ci-focal:1.7
# cpu: 4
# memory: 16G
# env:
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}/artifacts
# ARTDIR: ${CIRRUS_WORKING_DIR}/artifacts/
# CCACHE_DIR: "/tmp/ccache_dir"
# CCACHE_MAXSIZE: 300M
# CI_HAS_ARTIFACTS: true
# UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
# UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux"
# DEPLOY_APPIMAGE: true
# APPDIR: "./appdir"
# RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
# ccache_cache:
# folder: "/tmp/ccache_dir"
# matrix:
# - name: Cirrus Linux GCC
# env:
# COMPILER: gcc
# gcc_script:
# - mkdir artifacts
# - ".ci/build-linux.sh"
# - name: Cirrus Linux Clang
# env:
# COMPILER: clang
# clang_script:
# - mkdir artifacts
# - ".ci/build-linux.sh"
# artifacts:
# name: Artifact
# path: "artifacts/*"
# push_script: |
# if [ "$CIRRUS_REPO_OWNER" = "RPCS3" ] && [ -z "$CIRRUS_PR" ] && [ "$CIRRUS_BRANCH" = "master" ] && [ "$COMPILER" = "gcc" ]; then
# COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ./rpcs3/rpcs3_version.cpp)
# COMM_COUNT=$(git rev-list --count HEAD)
# COMM_HASH=$(git rev-parse --short=8 HEAD)
# export AVVER="${COMM_TAG}-${COMM_COUNT}"
# .ci/github-upload.sh
# fi;
freebsd_task:
matrix:
- name: Cirrus FreeBSD
freebsd_instance:
image_family: freebsd-13-3
cpu: 8
memory: 8G
env:
CCACHE_MAXSIZE: 300M # 3x clean build, rounded
CCACHE_DIR: /tmp/ccache_dir
ccache_cache:
folder: /tmp/ccache_dir
install_script: "sh -ex ./.ci/install-freebsd.sh"
script: "./.ci/build-freebsd.sh"
linux_aarch64_task:
env:
BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}/artifacts
ARTDIR: ${CIRRUS_WORKING_DIR}/artifacts/
CCACHE_DIR: "/tmp/ccache_dir"
CCACHE_MAXSIZE: 300M
CI_HAS_ARTIFACTS: true
UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux-arm64"
DEPLOY_APPIMAGE: true
APPDIR: "./appdir"
RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
COMPILER: clang
ccache_cache:
folder: "/tmp/ccache_dir"
matrix:
- name: Cirrus Linux AArch64 Clang
arm_container:
image: 'docker.io/rpcs3/rpcs3-ci-focal-aarch64:1.0'
cpu: 8
memory: 8G
clang_script:
- mkdir artifacts
- "sh -ex ./.ci/build-linux-aarch64.sh"
artifacts:
name: Artifact
path: "artifacts/*"
push_script: |
if [ "$CIRRUS_REPO_OWNER" = "RPCS3" ] && [ -z "$CIRRUS_PR" ] && [ "$CIRRUS_BRANCH" = "master" ]; then
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ./rpcs3/rpcs3_version.cpp)
COMM_COUNT=$(git rev-list --count HEAD)
COMM_HASH=$(git rev-parse --short=8 HEAD)
export AVVER="${COMM_TAG}-${COMM_COUNT}"
.ci/github-upload.sh
fi;

View File

@@ -0,0 +1,32 @@
Standard: c++20
UseTab: AlignWithSpaces
TabWidth: 4
IndentWidth: 4
AccessModifierOffset: -4
PointerAlignment: Left
NamespaceIndentation: All
ColumnLimit: 0
BreakBeforeBraces: Allman
BreakConstructorInitializers: BeforeColon
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: false
AlwaysBreakTemplateDeclarations: Yes
AllowShortIfStatementsOnASingleLine: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Empty
AllowShortLoopsOnASingleLine: false
AllowShortLambdasOnASingleLine: Empty
Cpp11BracedListStyle: true
IndentCaseLabels: false
SortIncludes: false
ReflowComments: true
AlignConsecutiveAssignments: false
AlignTrailingComments: true
AlignAfterOpenBracket: DontAlign
ConstructorInitializerAllOnOneLineOrOnePerLine: false
BinPackArguments: true
BinPackParameters: true
AlwaysBreakAfterReturnType: None
KeepEmptyLinesAtTheStartOfBlocks: true
IndentWrappedFunctionNames: false

View File

@@ -0,0 +1,7 @@
root = true
[*.{h,cpp,hpp}]
charset = utf-8
indent_style = tab
indent_size = 4
trim_trailing_whitespace = true

View File

@@ -0,0 +1,2 @@
handle SIGSEGV nostop noprint
handle SIGPIPE nostop noprint

View File

@@ -0,0 +1,19 @@
# Getting Started
Before getting started using the emulator, read the [Quickstart Guide](https://rpcs3.net/quickstart). After reading it, if you need support, check out [How to ask for Support](https://github.com/RPCS3/rpcs3/wiki/How-to-ask-for-Support).
# Issue Reporting
**The GitHub Issue Tracker is not the place to ask for support or to submit [Game Compatibility](https://rpcs3.net/compatibility) reports.** Requests for support or incorrect reports will be closed. If you are not sure whether the issue you want to report is an actual issue that is not yet known, please use the forums to submit such report.
**Before reporting an issue:**
- Check if your system matches all the minimum requirements listed in the [Quickstart Guide](https://rpcs3.net/quickstart);
- Search older issues/forum threads to see if your issue was already submitted;
- Use understandable English. It doesn't need to be perfect, but clear enough to understand your message;
- While reporting issues, please follow the template for the type of issue you've selected (Regression Report, Bug Report or Feature Request), which is prefilled on the issue's textbox.
Submitting your test results for Commercial Games must be done on our forums. Please read the [Game Compatibility](https://github.com/RPCS3/rpcs3/wiki/Game-Compatibility) wiki page before doing so.
# Contributing
Check the [Coding Style Guidelines](https://github.com/RPCS3/rpcs3/wiki/Coding-Style) and [Developer Information](https://github.com/RPCS3/rpcs3/wiki/Developer-Information). If you have any questions, hit us up on our [Discord Server](https://discord.me/RPCS3) in the **#development** channel.

View File

@@ -0,0 +1 @@
patreon: Nekotekina

View File

@@ -0,0 +1,93 @@
name: Regression report
description: If something used to work before, but now it doesn't
title: "[Regression] Enter a title here"
labels: []
body:
- type: markdown
attributes:
value: |
# Summary
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
- type: textarea
id: quick-summary
attributes:
label: Quick summary
description: Please briefly describe what has stopped working correctly.
validations:
required: true
- type: textarea
id: details
attributes:
label: Details
description: Please describe the regression as accurately as possible. Include screenshots if neccessary.
validations:
required: false
- type: markdown
attributes:
value: |
# Identify the regressed build
Please provide the _exact_ build (or commit) information that introduced the regression you're reporting.
* Please see [How to find the build that caused a regression](https://wiki.rpcs3.net/index.php?title=Help:Using_different_versions_of_RPCS3#How_to_find_the_build_that_caused_a_regression.3F) in our wiki.
* You can find [History of RPCS3 builds](https://rpcs3.net/compatibility?b) here.
Make sure you're running with settings as close to default as possible
* **Do NOT enable any emulator game patches when reporting issues**
* Only change settings that are required for the game to work
- type: input
id: regressed-build
attributes:
label: Build with regression
description: Provide _exact_ build (or commit) information that introduced the regression you're reporting.
placeholder: v0.0.23-13948-31df99f7
validations:
required: true
- type: markdown
attributes:
value: |
# Log files
Obtaining the log file:
* Run the game until you find the regression.
* Completely close RPCS3 and locate the log file.
RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon).
* On Windows it will be in the RPCS3 directory near the executable
* On Linux it will be in ```~/.cache/rpcs3/```
* On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter.
- type: textarea
id: logs
attributes:
label: Attach two log files
description: |
Attach one file for the build with regression and another for a build that works.
Drag & drop the files into this input field, or upload them to another service (f.ex. Dropbox, Mega) and provide a link.
validations:
required: true
- type: markdown
attributes:
value: |
# Other details
If you describe a graphical regression, please provide an RSX capture and/or a RenderDoc capture that demonstrate it.
* To create an RSX capture, use _Create_ _RSX_ _Capture_ under _Utilities_.
* Captures will be stored in RPCS3 folder → captures.
* To create a RenderDoc capture, please refer to [RenderDoc's documentation](https://renderdoc.org/docs/how/how_capture_frame.html).
- type: textarea
id: captures
attributes:
label: Attach capture files for visual issues
description: Compress your capture with 7z, Rar etc. and attach it here, or upload it to the cloud (Dropbox, Mega etc) and add a link to it.
validations:
required: false
- type: textarea
id: system-info
attributes:
label: System configuration
description: Provide information about your system, such as operating system, CPU and GPU model, GPU driver version and other information that describes your system configuration.
validations:
required: false
- type: textarea
id: other-details
attributes:
label: Other details
description: Include anything else you deem to be important.
validations:
required: false

View File

@@ -0,0 +1,78 @@
name: Bug report
description: If something doesn't work correctly in RPCS3
title: "Enter a title here"
labels: []
body:
- type: markdown
attributes:
value: |
# Summary
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
- type: textarea
id: quick-summary
attributes:
label: Quick summary
description: Please briefly describe what is not working correctly.
validations:
required: true
- type: textarea
id: details
attributes:
label: Details
description: |
Please describe the problem as accurately as possible.
Provide a comparison with a real PS3, if possible.
validations:
required: false
- type: markdown
attributes:
value: |
# Log files
Provide a log file that includes the bug you're reporting.
Obtaining the log file:
* Run the game until you find the regression.
* Completely close RPCS3 and locate the log file.
RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon).
* On Windows it will be in the RPCS3 directory near the executable
* On Linux it will be in ```~/.cache/rpcs3/```
* On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter.
- type: textarea
id: logs
attributes:
label: Attach a log file
description: |
Drag & drop the files into this input field, or upload them to another service (f.ex. Dropbox, Mega) and provide a link.
validations:
required: true
- type: markdown
attributes:
value: |
# Other details
If you describe a graphical issue, please provide an RSX capture and/or a RenderDoc capture that demonstrate it.
* To create an RSX capture, use _Create_ _RSX_ _Capture_ under _Utilities_.
* Captures will be stored in RPCS3 folder → captures.
* To create a RenderDoc capture, please refer to [RenderDoc's documentation](https://renderdoc.org/docs/how/how_capture_frame.html).
- type: textarea
id: captures
attributes:
label: Attach capture files for visual issues
description: Compress your capture with 7z, Rar etc. and attach it here, or upload it to the cloud (Dropbox, Mega etc) and add a link to it.
validations:
required: false
- type: textarea
id: system-info
attributes:
label: System configuration
description: Provide information about your system, such as operating system, CPU and GPU model, GPU driver version and other information that describes your system configuration.
validations:
required: false
- type: textarea
id: other-details
attributes:
label: Other details
description: Include anything else you deem to be important.
validations:
required: false

View File

@@ -0,0 +1,36 @@
name: Feature request
description: If RPCS3 lacks a feature you would like to see
title: "[Feature request] Enter a title here"
labels: []
body:
- type: markdown
attributes:
value: |
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
- type: textarea
id: quick-summary
attributes:
label: Quick summary
description: Please briefly describe what feature you would like RPCS3 to have.
validations:
required: true
- type: textarea
id: details
attributes:
label: Details
description: Please describe the feature as accurately as possible.
validations:
required: false
- type: markdown
attributes:
value: |
Please include the following information:
* What part of RPCS3 would be affected by your feature? (Gameplay, Debugging, UI, Patches, Installation, CI etc.)
* Why your feature is important to RPCS3.
* If the feature is implemented in other projects, attach screenshots.
* If this feature is something that a game is trying to use, upload a log file for it.
RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon).
* On Windows it will be in the RPCS3 directory near the executable
* On Linux it will be in ```~/.cache/rpcs3/```
* On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter.

View File

@@ -0,0 +1,14 @@
---
name: Advanced
about: For developers and experienced users only
title: ''
labels: ''
assignees: ''
---
## Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead.
You're using the advanced template. You're expected to know what to write in order to fill in all the required information for proper report.
If you're unsure on what to do, please return back to the issue type selection and choose different category.

View File

@@ -0,0 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: Quickstart guide
url: https://rpcs3.net/quickstart
about: Everything you need to know to install and configure emulator, and add games
- name: Ask for help
url: https://discord.me/RPCS3
about: If you have some questions or need help, please use our Discord server instead of GitHub
- name: Report game compatibility
url: https://forums.rpcs3.net/thread-196671.html
about: Please use RPCS3 forums to submit or update game compatibility status

View File

@@ -0,0 +1,18 @@
## How to test a PR build
Please take into account, that RPCS3 build usually takes some time (about 15 mins), so you can't access a build if a PR was just submitted.
- Open a PR you want to test
- Scroll to the very bottom and locate the **Checks** section
- Click on **Show all checks**
You are supposed to see something like this
![image](https://user-images.githubusercontent.com/10283761/116630952-2cd99e00-a94c-11eb-933e-986d6020ca92.png)
- Click on __Details__ on either **Cirrus Linux GCC** or **Cirrus Windows**
- Click **View more details on Cirrus CI** at the very bottom
![image](https://user-images.githubusercontent.com/10283761/116631111-5e526980-a94c-11eb-95f7-751e6f15e1ea.png)
- Click on the download button for **Artifact** on the **Artifacts** block
![image](https://user-images.githubusercontent.com/10283761/116631322-bee1a680-a94c-11eb-89a3-be365783582e.png)
- Congratulations! You are now downloading an RPCS3 build for that specific PR.
__Please note that PR builds are not supposed to be stable because they contain new changesets.__

View File

@@ -0,0 +1,3 @@
<!-- Please include a summary of the change and which issue is fixed. -->
[How to test this PR](.github/PR-BUILD.md)

View File

@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="7zip\C\7z.h" />
<ClInclude Include="7zip\C\7zAlloc.h" />
<ClInclude Include="7zip\C\7zBuf.h" />
<ClInclude Include="7zip\C\7zCrc.h" />
<ClInclude Include="7zip\C\7zFile.h" />
<ClInclude Include="7zip\C\7zTypes.h" />
<ClInclude Include="7zip\C\7zVersion.h" />
<ClInclude Include="7zip\C\7zWindows.h" />
<ClInclude Include="7zip\C\Aes.h" />
<ClInclude Include="7zip\C\Alloc.h" />
<ClInclude Include="7zip\C\Bcj2.h" />
<ClInclude Include="7zip\C\Blake2.h" />
<ClInclude Include="7zip\C\Bra.h" />
<ClInclude Include="7zip\C\BwtSort.h" />
<ClInclude Include="7zip\C\Compiler.h" />
<ClInclude Include="7zip\C\CpuArch.h" />
<ClInclude Include="7zip\C\Delta.h" />
<ClInclude Include="7zip\C\DllSecur.h" />
<ClInclude Include="7zip\C\HuffEnc.h" />
<ClInclude Include="7zip\C\LzFind.h" />
<ClInclude Include="7zip\C\LzFindMt.h" />
<ClInclude Include="7zip\C\LzHash.h" />
<ClInclude Include="7zip\C\Lzma2Dec.h" />
<ClInclude Include="7zip\C\Lzma2DecMt.h" />
<ClInclude Include="7zip\C\Lzma2Enc.h" />
<ClInclude Include="7zip\C\Lzma86.h" />
<ClInclude Include="7zip\C\LzmaDec.h" />
<ClInclude Include="7zip\C\LzmaEnc.h" />
<ClInclude Include="7zip\C\LzmaLib.h" />
<ClInclude Include="7zip\C\MtCoder.h" />
<ClInclude Include="7zip\C\MtDec.h" />
<ClInclude Include="7zip\C\Ppmd.h" />
<ClInclude Include="7zip\C\Ppmd7.h" />
<ClInclude Include="7zip\C\Ppmd8.h" />
<ClInclude Include="7zip\C\Precomp.h" />
<ClInclude Include="7zip\C\RotateDefs.h" />
<ClInclude Include="7zip\C\Sha1.h" />
<ClInclude Include="7zip\C\Sha256.h" />
<ClInclude Include="7zip\C\Sort.h" />
<ClInclude Include="7zip\C\SwapBytes.h" />
<ClInclude Include="7zip\C\Threads.h" />
<ClInclude Include="7zip\C\Xz.h" />
<ClInclude Include="7zip\C\XzCrc64.h" />
<ClInclude Include="7zip\C\XzEnc.h" />
<ClInclude Include="7zip\C\Xxh64.h" />
<ClInclude Include="7zip\C\ZstdDec.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="7zip\C\7zAlloc.c" />
<ClCompile Include="7zip\C\7zArcIn.c" />
<ClCompile Include="7zip\C\7zBuf.c" />
<ClCompile Include="7zip\C\7zBuf2.c" />
<ClCompile Include="7zip\C\7zCrc.c" />
<ClCompile Include="7zip\C\7zCrcOpt.c" />
<ClCompile Include="7zip\C\7zDec.c" />
<ClCompile Include="7zip\C\7zFile.c" />
<ClCompile Include="7zip\C\7zStream.c" />
<ClCompile Include="7zip\C\Aes.c" />
<ClCompile Include="7zip\C\AesOpt.c" />
<ClCompile Include="7zip\C\Alloc.c" />
<ClCompile Include="7zip\C\Bcj2.c" />
<ClCompile Include="7zip\C\Bcj2Enc.c" />
<ClCompile Include="7zip\C\Blake2s.c" />
<ClCompile Include="7zip\C\Bra.c" />
<ClCompile Include="7zip\C\Bra86.c" />
<ClCompile Include="7zip\C\BraIA64.c" />
<ClCompile Include="7zip\C\BwtSort.c" />
<ClCompile Include="7zip\C\CpuArch.c" />
<ClCompile Include="7zip\C\Delta.c" />
<ClCompile Include="7zip\C\DllSecur.c" />
<ClCompile Include="7zip\C\HuffEnc.c" />
<ClCompile Include="7zip\C\LzFind.c" />
<ClCompile Include="7zip\C\LzFindMt.c" />
<ClCompile Include="7zip\C\LzFindOpt.c" />
<ClCompile Include="7zip\C\Lzma2Dec.c" />
<ClCompile Include="7zip\C\Lzma2DecMt.c" />
<ClCompile Include="7zip\C\Lzma2Enc.c" />
<ClCompile Include="7zip\C\Lzma86Dec.c" />
<ClCompile Include="7zip\C\Lzma86Enc.c" />
<ClCompile Include="7zip\C\LzmaDec.c" />
<ClCompile Include="7zip\C\LzmaEnc.c" />
<ClCompile Include="7zip\C\LzmaLib.c" />
<ClCompile Include="7zip\C\MtCoder.c" />
<ClCompile Include="7zip\C\MtDec.c" />
<ClCompile Include="7zip\C\Ppmd7.c" />
<ClCompile Include="7zip\C\Ppmd7aDec.c" />
<ClCompile Include="7zip\C\Ppmd7Dec.c" />
<ClCompile Include="7zip\C\Ppmd7Enc.c" />
<ClCompile Include="7zip\C\Ppmd8.c" />
<ClCompile Include="7zip\C\Ppmd8Dec.c" />
<ClCompile Include="7zip\C\Ppmd8Enc.c" />
<ClCompile Include="7zip\C\Sha1.c" />
<ClCompile Include="7zip\C\Sha1Opt.c" />
<ClCompile Include="7zip\C\Sha256.c" />
<ClCompile Include="7zip\C\Sha256Opt.c" />
<ClCompile Include="7zip\C\Sort.c" />
<ClCompile Include="7zip\C\SwapBytes.c" />
<ClCompile Include="7zip\C\Threads.c" />
<ClCompile Include="7zip\C\Xz.c" />
<ClCompile Include="7zip\C\XzCrc64.c" />
<ClCompile Include="7zip\C\XzCrc64Opt.c" />
<ClCompile Include="7zip\C\XzDec.c" />
<ClCompile Include="7zip\C\XzEnc.c" />
<ClCompile Include="7zip\C\XzIn.c" />
<ClCompile Include="7zip\C\Xxh64.c" />
<ClCompile Include="7zip\C\ZstdDec.c" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,267 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="7zip\C\7z.h" />
<ClInclude Include="7zip\C\7zAlloc.h" />
<ClInclude Include="7zip\C\7zBuf.h" />
<ClInclude Include="7zip\C\7zCrc.h" />
<ClInclude Include="7zip\C\7zFile.h" />
<ClInclude Include="7zip\C\7zTypes.h" />
<ClInclude Include="7zip\C\7zVersion.h" />
<ClInclude Include="7zip\C\7zWindows.h" />
<ClInclude Include="7zip\C\Aes.h" />
<ClInclude Include="7zip\C\Alloc.h" />
<ClInclude Include="7zip\C\Bcj2.h" />
<ClInclude Include="7zip\C\Blake2.h" />
<ClInclude Include="7zip\C\Bra.h" />
<ClInclude Include="7zip\C\BwtSort.h" />
<ClInclude Include="7zip\C\Compiler.h" />
<ClInclude Include="7zip\C\CpuArch.h" />
<ClInclude Include="7zip\C\Delta.h" />
<ClInclude Include="7zip\C\DllSecur.h" />
<ClInclude Include="7zip\C\HuffEnc.h" />
<ClInclude Include="7zip\C\LzFind.h" />
<ClInclude Include="7zip\C\LzFindMt.h" />
<ClInclude Include="7zip\C\LzHash.h" />
<ClInclude Include="7zip\C\Lzma2Dec.h" />
<ClInclude Include="7zip\C\Lzma2DecMt.h" />
<ClInclude Include="7zip\C\Lzma2Enc.h" />
<ClInclude Include="7zip\C\Lzma86.h" />
<ClInclude Include="7zip\C\LzmaDec.h" />
<ClInclude Include="7zip\C\LzmaEnc.h" />
<ClInclude Include="7zip\C\LzmaLib.h" />
<ClInclude Include="7zip\C\MtCoder.h" />
<ClInclude Include="7zip\C\MtDec.h" />
<ClInclude Include="7zip\C\Ppmd.h" />
<ClInclude Include="7zip\C\Ppmd7.h" />
<ClInclude Include="7zip\C\Ppmd8.h" />
<ClInclude Include="7zip\C\Precomp.h" />
<ClInclude Include="7zip\C\RotateDefs.h" />
<ClInclude Include="7zip\C\Sha1.h" />
<ClInclude Include="7zip\C\Sha256.h" />
<ClInclude Include="7zip\C\Sort.h" />
<ClInclude Include="7zip\C\SwapBytes.h" />
<ClInclude Include="7zip\C\Threads.h" />
<ClInclude Include="7zip\C\Xxh64.h" />
<ClInclude Include="7zip\C\Xz.h" />
<ClInclude Include="7zip\C\XzCrc64.h" />
<ClInclude Include="7zip\C\XzEnc.h" />
<ClInclude Include="7zip\C\ZstdDec.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="7zip\C\7zAlloc.c" />
<ClCompile Include="7zip\C\7zArcIn.c" />
<ClCompile Include="7zip\C\7zBuf.c" />
<ClCompile Include="7zip\C\7zBuf2.c" />
<ClCompile Include="7zip\C\7zCrc.c" />
<ClCompile Include="7zip\C\7zCrcOpt.c" />
<ClCompile Include="7zip\C\7zDec.c" />
<ClCompile Include="7zip\C\7zFile.c" />
<ClCompile Include="7zip\C\7zStream.c" />
<ClCompile Include="7zip\C\Aes.c" />
<ClCompile Include="7zip\C\AesOpt.c" />
<ClCompile Include="7zip\C\Alloc.c" />
<ClCompile Include="7zip\C\Bcj2.c" />
<ClCompile Include="7zip\C\Bcj2Enc.c" />
<ClCompile Include="7zip\C\Blake2s.c" />
<ClCompile Include="7zip\C\Bra.c" />
<ClCompile Include="7zip\C\Bra86.c" />
<ClCompile Include="7zip\C\BraIA64.c" />
<ClCompile Include="7zip\C\BwtSort.c" />
<ClCompile Include="7zip\C\CpuArch.c" />
<ClCompile Include="7zip\C\Delta.c" />
<ClCompile Include="7zip\C\DllSecur.c" />
<ClCompile Include="7zip\C\HuffEnc.c" />
<ClCompile Include="7zip\C\LzFind.c" />
<ClCompile Include="7zip\C\LzFindMt.c" />
<ClCompile Include="7zip\C\LzFindOpt.c" />
<ClCompile Include="7zip\C\Lzma2Dec.c" />
<ClCompile Include="7zip\C\Lzma2DecMt.c" />
<ClCompile Include="7zip\C\Lzma2Enc.c" />
<ClCompile Include="7zip\C\Lzma86Dec.c" />
<ClCompile Include="7zip\C\Lzma86Enc.c" />
<ClCompile Include="7zip\C\LzmaDec.c" />
<ClCompile Include="7zip\C\LzmaEnc.c" />
<ClCompile Include="7zip\C\LzmaLib.c" />
<ClCompile Include="7zip\C\MtCoder.c" />
<ClCompile Include="7zip\C\MtDec.c" />
<ClCompile Include="7zip\C\Ppmd7.c" />
<ClCompile Include="7zip\C\Ppmd7aDec.c" />
<ClCompile Include="7zip\C\Ppmd7Dec.c" />
<ClCompile Include="7zip\C\Ppmd7Enc.c" />
<ClCompile Include="7zip\C\Ppmd8.c" />
<ClCompile Include="7zip\C\Ppmd8Dec.c" />
<ClCompile Include="7zip\C\Ppmd8Enc.c" />
<ClCompile Include="7zip\C\Sha1.c" />
<ClCompile Include="7zip\C\Sha1Opt.c" />
<ClCompile Include="7zip\C\Sha256.c" />
<ClCompile Include="7zip\C\Sha256Opt.c" />
<ClCompile Include="7zip\C\Sort.c" />
<ClCompile Include="7zip\C\SwapBytes.c" />
<ClCompile Include="7zip\C\Threads.c" />
<ClCompile Include="7zip\C\Xxh64.c" />
<ClCompile Include="7zip\C\Xz.c" />
<ClCompile Include="7zip\C\XzCrc64.c" />
<ClCompile Include="7zip\C\XzCrc64Opt.c" />
<ClCompile Include="7zip\C\XzDec.c" />
<ClCompile Include="7zip\C\XzEnc.c" />
<ClCompile Include="7zip\C\XzIn.c" />
<ClCompile Include="7zip\C\ZstdDec.c" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>My7zlib</RootNamespace>
</PropertyGroup>
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup>
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
</PropertyGroup>
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default_macros.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(SolutionDir)lib/$(Configuration)-$(Platform)/</OutDir>
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)/</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,100 @@
CODE32
EXPORT |CrcUpdateT4@16|
AREA |.text|, CODE, ARM
MACRO
CRC32_STEP_1
ldrb r4, [r1], #1
subs r2, r2, #1
eor r4, r4, r0
and r4, r4, #0xFF
ldr r4, [r3, +r4, lsl #2]
eor r0, r4, r0, lsr #8
MEND
MACRO
CRC32_STEP_4 $STREAM_WORD
eor r7, r7, r8
eor r7, r7, r9
eor r0, r0, r7
eor r0, r0, $STREAM_WORD
ldr $STREAM_WORD, [r1], #4
and r7, r0, #0xFF
and r8, r0, #0xFF00
and r9, r0, #0xFF0000
and r0, r0, #0xFF000000
ldr r7, [r6, +r7, lsl #2]
ldr r8, [r5, +r8, lsr #6]
ldr r9, [r4, +r9, lsr #14]
ldr r0, [r3, +r0, lsr #22]
MEND
|CrcUpdateT4@16| PROC
stmdb sp!, {r4-r11, lr}
cmp r2, #0
beq |$fin|
|$v1|
tst r1, #7
beq |$v2|
CRC32_STEP_1
bne |$v1|
|$v2|
cmp r2, #16
blo |$v3|
ldr r10, [r1], #4
ldr r11, [r1], #4
add r4, r3, #0x400
add r5, r3, #0x800
add r6, r3, #0xC00
mov r7, #0
mov r8, #0
mov r9, #0
sub r2, r2, #16
|$loop|
; pld [r1, #0x40]
CRC32_STEP_4 r10
CRC32_STEP_4 r11
subs r2, r2, #8
bhs |$loop|
sub r1, r1, #8
add r2, r2, #16
eor r7, r7, r8
eor r7, r7, r9
eor r0, r0, r7
|$v3|
cmp r2, #0
beq |$fin|
|$v4|
CRC32_STEP_1
bne |$v4|
|$fin|
ldmia sp!, {r4-r11, pc}
|CrcUpdateT4@16| ENDP
END

View File

@@ -0,0 +1,181 @@
// 7zAsm.S -- ASM macros for arm64
// 2021-04-25 : Igor Pavlov : Public domain
#define r0 x0
#define r1 x1
#define r2 x2
#define r3 x3
#define r4 x4
#define r5 x5
#define r6 x6
#define r7 x7
#define r8 x8
#define r9 x9
#define r10 x10
#define r11 x11
#define r12 x12
#define r13 x13
#define r14 x14
#define r15 x15
#define r16 x16
#define r17 x17
#define r18 x18
#define r19 x19
#define r20 x20
#define r21 x21
#define r22 x22
#define r23 x23
#define r24 x24
#define r25 x25
#define r26 x26
#define r27 x27
#define r28 x28
#define r29 x29
#define r30 x30
#define REG_ABI_PARAM_0 r0
#define REG_ABI_PARAM_1 r1
#define REG_ABI_PARAM_2 r2
.macro p2_add reg:req, param:req
add \reg, \reg, \param
.endm
.macro p2_sub reg:req, param:req
sub \reg, \reg, \param
.endm
.macro p2_sub_s reg:req, param:req
subs \reg, \reg, \param
.endm
.macro p2_and reg:req, param:req
and \reg, \reg, \param
.endm
.macro xor reg:req, param:req
eor \reg, \reg, \param
.endm
.macro or reg:req, param:req
orr \reg, \reg, \param
.endm
.macro shl reg:req, param:req
lsl \reg, \reg, \param
.endm
.macro shr reg:req, param:req
lsr \reg, \reg, \param
.endm
.macro sar reg:req, param:req
asr \reg, \reg, \param
.endm
.macro p1_neg reg:req
neg \reg, \reg
.endm
.macro dec reg:req
sub \reg, \reg, 1
.endm
.macro dec_s reg:req
subs \reg, \reg, 1
.endm
.macro inc reg:req
add \reg, \reg, 1
.endm
.macro inc_s reg:req
adds \reg, \reg, 1
.endm
.macro imul reg:req, param:req
mul \reg, \reg, \param
.endm
/*
arm64 and arm use reverted c flag after subs/cmp instructions:
arm64-arm : x86
b.lo / b.cc : jb / jc
b.hs / b.cs : jae / jnc
*/
.macro jmp lab:req
b \lab
.endm
.macro je lab:req
b.eq \lab
.endm
.macro jz lab:req
b.eq \lab
.endm
.macro jnz lab:req
b.ne \lab
.endm
.macro jne lab:req
b.ne \lab
.endm
.macro jb lab:req
b.lo \lab
.endm
.macro jbe lab:req
b.ls \lab
.endm
.macro ja lab:req
b.hi \lab
.endm
.macro jae lab:req
b.hs \lab
.endm
.macro cmove dest:req, srcTrue:req
csel \dest, \srcTrue, \dest, eq
.endm
.macro cmovne dest:req, srcTrue:req
csel \dest, \srcTrue, \dest, ne
.endm
.macro cmovs dest:req, srcTrue:req
csel \dest, \srcTrue, \dest, mi
.endm
.macro cmovns dest:req, srcTrue:req
csel \dest, \srcTrue, \dest, pl
.endm
.macro cmovb dest:req, srcTrue:req
csel \dest, \srcTrue, \dest, lo
.endm
.macro cmovae dest:req, srcTrue:req
csel \dest, \srcTrue, \dest, hs
.endm
.macro MY_ALIGN_16 macro
.p2align 4,, (1 << 4) - 1
.endm
.macro MY_ALIGN_32 macro
.p2align 5,, (1 << 5) - 1
.endm
.macro MY_ALIGN_64 macro
.p2align 6,, (1 << 6) - 1
.endm

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,341 @@
; 7zAsm.asm -- ASM macros
; 2023-12-08 : Igor Pavlov : Public domain
; UASM can require these changes
; OPTION FRAMEPRESERVEFLAGS:ON
; OPTION PROLOGUE:NONE
; OPTION EPILOGUE:NONE
ifdef @wordsize
; @wordsize is defined only in JWASM and ASMC and is not defined in MASM
; @wordsize eq 8 for 64-bit x64
; @wordsize eq 2 for 32-bit x86
if @wordsize eq 8
x64 equ 1
endif
else
ifdef RAX
x64 equ 1
endif
endif
ifdef x64
IS_X64 equ 1
else
IS_X64 equ 0
endif
ifdef ABI_LINUX
IS_LINUX equ 1
else
IS_LINUX equ 0
endif
ifndef x64
; Use ABI_CDECL for x86 (32-bit) only
; if ABI_CDECL is not defined, we use fastcall abi
ifdef ABI_CDECL
IS_CDECL equ 1
else
IS_CDECL equ 0
endif
endif
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
MY_ASM_START macro
ifdef x64
.code
else
.386
.model flat
_TEXT$00 SEGMENT PARA PUBLIC 'CODE'
endif
endm
MY_PROC macro name:req, numParams:req
align 16
proc_numParams = numParams
if (IS_X64 gt 0)
proc_name equ name
elseif (IS_LINUX gt 0)
proc_name equ name
elseif (IS_CDECL gt 0)
proc_name equ @CatStr(_,name)
else
proc_name equ @CatStr(@,name,@, %numParams * 4)
endif
proc_name PROC
endm
MY_ENDP macro
if (IS_X64 gt 0)
ret
elseif (IS_CDECL gt 0)
ret
elseif (proc_numParams LT 3)
ret
else
ret (proc_numParams - 2) * 4
endif
proc_name ENDP
endm
ifdef x64
REG_SIZE equ 8
REG_LOGAR_SIZE equ 3
else
REG_SIZE equ 4
REG_LOGAR_SIZE equ 2
endif
x0 equ EAX
x1 equ ECX
x2 equ EDX
x3 equ EBX
x4 equ ESP
x5 equ EBP
x6 equ ESI
x7 equ EDI
x0_W equ AX
x1_W equ CX
x2_W equ DX
x3_W equ BX
x5_W equ BP
x6_W equ SI
x7_W equ DI
x0_L equ AL
x1_L equ CL
x2_L equ DL
x3_L equ BL
x0_H equ AH
x1_H equ CH
x2_H equ DH
x3_H equ BH
; r0_L equ AL
; r1_L equ CL
; r2_L equ DL
; r3_L equ BL
; r0_H equ AH
; r1_H equ CH
; r2_H equ DH
; r3_H equ BH
ifdef x64
x5_L equ BPL
x6_L equ SIL
x7_L equ DIL
x8_L equ r8b
x9_L equ r9b
x10_L equ r10b
x11_L equ r11b
x12_L equ r12b
x13_L equ r13b
x14_L equ r14b
x15_L equ r15b
r0 equ RAX
r1 equ RCX
r2 equ RDX
r3 equ RBX
r4 equ RSP
r5 equ RBP
r6 equ RSI
r7 equ RDI
x8 equ r8d
x9 equ r9d
x10 equ r10d
x11 equ r11d
x12 equ r12d
x13 equ r13d
x14 equ r14d
x15 equ r15d
else
r0 equ x0
r1 equ x1
r2 equ x2
r3 equ x3
r4 equ x4
r5 equ x5
r6 equ x6
r7 equ x7
endif
x0_R equ r0
x1_R equ r1
x2_R equ r2
x3_R equ r3
x4_R equ r4
x5_R equ r5
x6_R equ r6
x7_R equ r7
x8_R equ r8
x9_R equ r9
x10_R equ r10
x11_R equ r11
x12_R equ r12
x13_R equ r13
x14_R equ r14
x15_R equ r15
ifdef x64
ifdef ABI_LINUX
MY_PUSH_2_REGS macro
push r3
push r5
endm
MY_POP_2_REGS macro
pop r5
pop r3
endm
endif
endif
MY_PUSH_4_REGS macro
push r3
push r5
push r6
push r7
endm
MY_POP_4_REGS macro
pop r7
pop r6
pop r5
pop r3
endm
; for fastcall and for WIN-x64
REG_PARAM_0_x equ x1
REG_PARAM_0 equ r1
REG_PARAM_1_x equ x2
REG_PARAM_1 equ r2
ifndef x64
; for x86-fastcall
REG_ABI_PARAM_0_x equ REG_PARAM_0_x
REG_ABI_PARAM_0 equ REG_PARAM_0
REG_ABI_PARAM_1_x equ REG_PARAM_1_x
REG_ABI_PARAM_1 equ REG_PARAM_1
MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 macro
MY_PUSH_4_REGS
endm
MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 macro
MY_POP_4_REGS
endm
else
; x64
if (IS_LINUX eq 0)
; for WIN-x64:
REG_PARAM_2_x equ x8
REG_PARAM_2 equ r8
REG_PARAM_3 equ r9
REG_ABI_PARAM_0_x equ REG_PARAM_0_x
REG_ABI_PARAM_0 equ REG_PARAM_0
REG_ABI_PARAM_1_x equ REG_PARAM_1_x
REG_ABI_PARAM_1 equ REG_PARAM_1
REG_ABI_PARAM_2_x equ REG_PARAM_2_x
REG_ABI_PARAM_2 equ REG_PARAM_2
REG_ABI_PARAM_3 equ REG_PARAM_3
else
; for LINUX-x64:
REG_LINUX_PARAM_0_x equ x7
REG_LINUX_PARAM_0 equ r7
REG_LINUX_PARAM_1_x equ x6
REG_LINUX_PARAM_1 equ r6
REG_LINUX_PARAM_2 equ r2
REG_LINUX_PARAM_3 equ r1
REG_LINUX_PARAM_4_x equ x8
REG_LINUX_PARAM_4 equ r8
REG_LINUX_PARAM_5 equ r9
REG_ABI_PARAM_0_x equ REG_LINUX_PARAM_0_x
REG_ABI_PARAM_0 equ REG_LINUX_PARAM_0
REG_ABI_PARAM_1_x equ REG_LINUX_PARAM_1_x
REG_ABI_PARAM_1 equ REG_LINUX_PARAM_1
REG_ABI_PARAM_2 equ REG_LINUX_PARAM_2
REG_ABI_PARAM_3 equ REG_LINUX_PARAM_3
REG_ABI_PARAM_4_x equ REG_LINUX_PARAM_4_x
REG_ABI_PARAM_4 equ REG_LINUX_PARAM_4
REG_ABI_PARAM_5 equ REG_LINUX_PARAM_5
MY_ABI_LINUX_TO_WIN_2 macro
mov r2, r6
mov r1, r7
endm
MY_ABI_LINUX_TO_WIN_3 macro
mov r8, r2
mov r2, r6
mov r1, r7
endm
MY_ABI_LINUX_TO_WIN_4 macro
mov r9, r1
mov r8, r2
mov r2, r6
mov r1, r7
endm
endif ; IS_LINUX
MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 macro
if (IS_LINUX gt 0)
MY_PUSH_2_REGS
else
MY_PUSH_4_REGS
endif
endm
MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 macro
if (IS_LINUX gt 0)
MY_POP_2_REGS
else
MY_POP_4_REGS
endif
endm
MY_PUSH_PRESERVED_ABI_REGS macro
MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11
push r12
push r13
push r14
push r15
endm
MY_POP_PRESERVED_ABI_REGS macro
pop r15
pop r14
pop r13
pop r12
MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11
endm
endif ; x64

View File

@@ -0,0 +1,258 @@
; 7zCrcOpt.asm -- CRC32 calculation : optimized version
; 2023-12-08 : Igor Pavlov : Public domain
include 7zAsm.asm
MY_ASM_START
NUM_WORDS equ 3
UNROLL_CNT equ 2
if (NUM_WORDS lt 1) or (NUM_WORDS gt 64)
.err <NUM_WORDS_IS_INCORRECT>
endif
if (UNROLL_CNT lt 1)
.err <UNROLL_CNT_IS_INCORRECT>
endif
rD equ r2
rD_x equ x2
rN equ r7
rT equ r5
ifndef x64
if (IS_CDECL gt 0)
crc_OFFS equ (REG_SIZE * 5)
data_OFFS equ (REG_SIZE + crc_OFFS)
size_OFFS equ (REG_SIZE + data_OFFS)
else
size_OFFS equ (REG_SIZE * 5)
endif
table_OFFS equ (REG_SIZE + size_OFFS)
endif
; rN + rD is same speed as rD, but we reduce one instruction in loop
SRCDAT_1 equ rN + rD * 1 + 1 *
SRCDAT_4 equ rN + rD * 1 + 4 *
CRC macro op:req, dest:req, src:req, t:req
op dest, dword ptr [rT + @CatStr(src, _R) * 4 + 0400h * (t)]
endm
CRC_XOR macro dest:req, src:req, t:req
CRC xor, dest, src, t
endm
CRC_MOV macro dest:req, src:req, t:req
CRC mov, dest, src, t
endm
MOVZXLO macro dest:req, src:req
movzx dest, @CatStr(src, _L)
endm
MOVZXHI macro dest:req, src:req
movzx dest, @CatStr(src, _H)
endm
; movzx x0, x0_L - is slow in some cpus (ivb), if same register for src and dest
; movzx x3, x0_L sometimes is 0 cycles latency (not always)
; movzx x3, x0_L sometimes is 0.5 cycles latency
; movzx x3, x0_H is 2 cycles latency in some cpus
CRC1b macro
movzx x6, byte ptr [rD]
MOVZXLO x3, x0
inc rD
shr x0, 8
xor x6, x3
CRC_XOR x0, x6, 0
dec rN
endm
LOAD_1 macro dest:req, t:req, iter:req, index:req
movzx dest, byte ptr [SRCDAT_1 (4 * (NUM_WORDS - 1 - t + iter * NUM_WORDS) + index)]
endm
LOAD_2 macro dest:req, t:req, iter:req, index:req
movzx dest, word ptr [SRCDAT_1 (4 * (NUM_WORDS - 1 - t + iter * NUM_WORDS) + index)]
endm
CRC_QUAD macro nn, t:req, iter:req
ifdef x64
; paired memory loads give 1-3% speed gain, but it uses more registers
LOAD_2 x3, t, iter, 0
LOAD_2 x9, t, iter, 2
MOVZXLO x6, x3
shr x3, 8
CRC_XOR nn, x6, t * 4 + 3
MOVZXLO x6, x9
shr x9, 8
CRC_XOR nn, x3, t * 4 + 2
CRC_XOR nn, x6, t * 4 + 1
CRC_XOR nn, x9, t * 4 + 0
elseif 0
LOAD_2 x3, t, iter, 0
MOVZXLO x6, x3
shr x3, 8
CRC_XOR nn, x6, t * 4 + 3
CRC_XOR nn, x3, t * 4 + 2
LOAD_2 x3, t, iter, 2
MOVZXLO x6, x3
shr x3, 8
CRC_XOR nn, x6, t * 4 + 1
CRC_XOR nn, x3, t * 4 + 0
elseif 0
LOAD_1 x3, t, iter, 0
LOAD_1 x6, t, iter, 1
CRC_XOR nn, x3, t * 4 + 3
CRC_XOR nn, x6, t * 4 + 2
LOAD_1 x3, t, iter, 2
LOAD_1 x6, t, iter, 3
CRC_XOR nn, x3, t * 4 + 1
CRC_XOR nn, x6, t * 4 + 0
else
; 32-bit load is better if there is only one read port (core2)
; but that code can be slower if there are 2 read ports (snb)
mov x3, dword ptr [SRCDAT_1 (4 * (NUM_WORDS - 1 - t + iter * NUM_WORDS) + 0)]
MOVZXLO x6, x3
CRC_XOR nn, x6, t * 4 + 3
MOVZXHI x6, x3
shr x3, 16
CRC_XOR nn, x6, t * 4 + 2
MOVZXLO x6, x3
shr x3, 8
CRC_XOR nn, x6, t * 4 + 1
CRC_XOR nn, x3, t * 4 + 0
endif
endm
LAST equ (4 * (NUM_WORDS - 1))
CRC_ITER macro qq, nn, iter
mov nn, [SRCDAT_4 (NUM_WORDS * (1 + iter))]
i = 0
rept NUM_WORDS - 1
CRC_QUAD nn, i, iter
i = i + 1
endm
MOVZXLO x6, qq
mov x3, qq
shr x3, 24
CRC_XOR nn, x6, LAST + 3
CRC_XOR nn, x3, LAST + 0
ror qq, 16
MOVZXLO x6, qq
shr qq, 24
CRC_XOR nn, x6, LAST + 1
if ((UNROLL_CNT and 1) eq 1) and (iter eq (UNROLL_CNT - 1))
CRC_MOV qq, qq, LAST + 2
xor qq, nn
else
CRC_XOR nn, qq, LAST + 2
endif
endm
; + 4 for prefetching next 4-bytes after current iteration
NUM_BYTES_LIMIT equ (NUM_WORDS * 4 * UNROLL_CNT + 4)
ALIGN_MASK equ 3
; MY_PROC @CatStr(CrcUpdateT, 12), 4
MY_PROC @CatStr(CrcUpdateT, %(NUM_WORDS * 4)), 4
MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11
ifdef x64
mov x0, REG_ABI_PARAM_0_x ; x0 = x1(win) / x7(linux)
mov rT, REG_ABI_PARAM_3 ; r5 = r9(win) / x1(linux)
mov rN, REG_ABI_PARAM_2 ; r7 = r8(win) / r2(linux)
; mov rD, REG_ABI_PARAM_1 ; r2 = r2(win)
if (IS_LINUX gt 0)
mov rD, REG_ABI_PARAM_1 ; r2 = r6
endif
else
if (IS_CDECL gt 0)
mov x0, [r4 + crc_OFFS]
mov rD, [r4 + data_OFFS]
else
mov x0, REG_ABI_PARAM_0_x
endif
mov rN, [r4 + size_OFFS]
mov rT, [r4 + table_OFFS]
endif
cmp rN, NUM_BYTES_LIMIT + ALIGN_MASK
jb crc_end
@@:
test rD_x, ALIGN_MASK ; test rD, ALIGN_MASK
jz @F
CRC1b
jmp @B
@@:
xor x0, dword ptr [rD]
lea rN, [rD + rN * 1 - (NUM_BYTES_LIMIT - 1)]
sub rD, rN
align 16
@@:
unr_index = 0
while unr_index lt UNROLL_CNT
if (unr_index and 1) eq 0
CRC_ITER x0, x1, unr_index
else
CRC_ITER x1, x0, unr_index
endif
unr_index = unr_index + 1
endm
add rD, NUM_WORDS * 4 * UNROLL_CNT
jnc @B
if 0
; byte verson
add rD, rN
xor x0, dword ptr [rD]
add rN, NUM_BYTES_LIMIT - 1
else
; 4-byte version
add rN, 4 * NUM_WORDS * UNROLL_CNT
sub rD, 4 * NUM_WORDS * UNROLL_CNT
@@:
MOVZXLO x3, x0
MOVZXHI x1, x0
shr x0, 16
MOVZXLO x6, x0
shr x0, 8
CRC_MOV x0, x0, 0
CRC_XOR x0, x3, 3
CRC_XOR x0, x1, 2
CRC_XOR x0, x6, 1
add rD, 4
if (NUM_WORDS * UNROLL_CNT) ne 1
jc @F
xor x0, [SRCDAT_4 0]
jmp @B
@@:
endif
add rD, rN
add rN, 4 - 1
endif
sub rN, rD
crc_end:
test rN, rN
jz func_end
@@:
CRC1b
jnz @B
func_end:
MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11
MY_ENDP
end

View File

@@ -0,0 +1,742 @@
; AesOpt.asm -- AES optimized code for x86 AES hardware instructions
; 2021-12-25 : Igor Pavlov : Public domain
include 7zAsm.asm
ifdef __ASMC__
use_vaes_256 equ 1
else
ifdef ymm0
use_vaes_256 equ 1
endif
endif
ifdef use_vaes_256
ECHO "++ VAES 256"
else
ECHO "-- NO VAES 256"
endif
ifdef x64
ECHO "x86-64"
else
ECHO "x86"
if (IS_CDECL gt 0)
ECHO "ABI : CDECL"
else
ECHO "ABI : no CDECL : FASTCALL"
endif
endif
if (IS_LINUX gt 0)
ECHO "ABI : LINUX"
else
ECHO "ABI : WINDOWS"
endif
MY_ASM_START
ifndef x64
.686
.xmm
endif
; MY_ALIGN EQU ALIGN(64)
MY_ALIGN EQU
SEG_ALIGN EQU MY_ALIGN
MY_SEG_PROC macro name:req, numParams:req
; seg_name equ @CatStr(_TEXT$, name)
; seg_name SEGMENT SEG_ALIGN 'CODE'
MY_PROC name, numParams
endm
MY_SEG_ENDP macro
; seg_name ENDS
endm
NUM_AES_KEYS_MAX equ 15
; the number of push operators in function PROLOG
if (IS_LINUX eq 0) or (IS_X64 eq 0)
num_regs_push equ 2
stack_param_offset equ (REG_SIZE * (1 + num_regs_push))
endif
ifdef x64
num_param equ REG_ABI_PARAM_2
else
if (IS_CDECL gt 0)
; size_t size
; void * data
; UInt32 * aes
; ret-ip <- (r4)
aes_OFFS equ (stack_param_offset)
data_OFFS equ (REG_SIZE + aes_OFFS)
size_OFFS equ (REG_SIZE + data_OFFS)
num_param equ [r4 + size_OFFS]
else
num_param equ [r4 + stack_param_offset]
endif
endif
keys equ REG_PARAM_0 ; r1
rD equ REG_PARAM_1 ; r2
rN equ r0
koffs_x equ x7
koffs_r equ r7
ksize_x equ x6
ksize_r equ r6
keys2 equ r3
state equ xmm0
key equ xmm0
key_ymm equ ymm0
key_ymm_n equ 0
ifdef x64
ways = 11
else
ways = 4
endif
ways_start_reg equ 1
iv equ @CatStr(xmm, %(ways_start_reg + ways))
iv_ymm equ @CatStr(ymm, %(ways_start_reg + ways))
WOP macro op, op2
i = 0
rept ways
op @CatStr(xmm, %(ways_start_reg + i)), op2
i = i + 1
endm
endm
ifndef ABI_LINUX
ifdef x64
; we use 32 bytes of home space in stack in WIN64-x64
NUM_HOME_MM_REGS equ (32 / 16)
; we preserve xmm registers starting from xmm6 in WIN64-x64
MM_START_SAVE_REG equ 6
SAVE_XMM macro num_used_mm_regs:req
num_save_mm_regs = num_used_mm_regs - MM_START_SAVE_REG
if num_save_mm_regs GT 0
num_save_mm_regs2 = num_save_mm_regs - NUM_HOME_MM_REGS
; RSP is (16*x + 8) after entering the function in WIN64-x64
stack_offset = 16 * num_save_mm_regs2 + (stack_param_offset mod 16)
i = 0
rept num_save_mm_regs
if i eq NUM_HOME_MM_REGS
sub r4, stack_offset
endif
if i lt NUM_HOME_MM_REGS
movdqa [r4 + stack_param_offset + i * 16], @CatStr(xmm, %(MM_START_SAVE_REG + i))
else
movdqa [r4 + (i - NUM_HOME_MM_REGS) * 16], @CatStr(xmm, %(MM_START_SAVE_REG + i))
endif
i = i + 1
endm
endif
endm
RESTORE_XMM macro num_used_mm_regs:req
if num_save_mm_regs GT 0
i = 0
if num_save_mm_regs2 GT 0
rept num_save_mm_regs2
movdqa @CatStr(xmm, %(MM_START_SAVE_REG + NUM_HOME_MM_REGS + i)), [r4 + i * 16]
i = i + 1
endm
add r4, stack_offset
endif
num_low_regs = num_save_mm_regs - i
i = 0
rept num_low_regs
movdqa @CatStr(xmm, %(MM_START_SAVE_REG + i)), [r4 + stack_param_offset + i * 16]
i = i + 1
endm
endif
endm
endif ; x64
endif ; ABI_LINUX
MY_PROLOG macro num_used_mm_regs:req
; num_regs_push: must be equal to the number of push operators
; push r3
; push r5
if (IS_LINUX eq 0) or (IS_X64 eq 0)
push r6
push r7
endif
mov rN, num_param ; don't move it; num_param can use stack pointer (r4)
if (IS_X64 eq 0)
if (IS_CDECL gt 0)
mov rD, [r4 + data_OFFS]
mov keys, [r4 + aes_OFFS]
endif
elseif (IS_LINUX gt 0)
MY_ABI_LINUX_TO_WIN_2
endif
ifndef ABI_LINUX
ifdef x64
SAVE_XMM num_used_mm_regs
endif
endif
mov ksize_x, [keys + 16]
shl ksize_x, 5
endm
MY_EPILOG macro
ifndef ABI_LINUX
ifdef x64
RESTORE_XMM num_save_mm_regs
endif
endif
if (IS_LINUX eq 0) or (IS_X64 eq 0)
pop r7
pop r6
endif
; pop r5
; pop r3
MY_ENDP
endm
OP_KEY macro op:req, offs:req
op state, [keys + offs]
endm
WOP_KEY macro op:req, offs:req
movdqa key, [keys + offs]
WOP op, key
endm
; ---------- AES-CBC Decode ----------
XOR_WITH_DATA macro reg, _ppp_
pxor reg, [rD + i * 16]
endm
WRITE_TO_DATA macro reg, _ppp_
movdqa [rD + i * 16], reg
endm
; state0 equ @CatStr(xmm, %(ways_start_reg))
key0 equ @CatStr(xmm, %(ways_start_reg + ways + 1))
key0_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 1))
key_last equ @CatStr(xmm, %(ways_start_reg + ways + 2))
key_last_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 2))
key_last_ymm_n equ (ways_start_reg + ways + 2)
NUM_CBC_REGS equ (ways_start_reg + ways + 3)
MY_SEG_PROC AesCbc_Decode_HW, 3
AesCbc_Decode_HW_start::
MY_PROLOG NUM_CBC_REGS
AesCbc_Decode_HW_start_2::
movdqa iv, [keys]
add keys, 32
movdqa key0, [keys + 1 * ksize_r]
movdqa key_last, [keys]
sub ksize_x, 16
jmp check2
align 16
nextBlocks2:
WOP movdqa, [rD + i * 16]
mov koffs_x, ksize_x
; WOP_KEY pxor, ksize_r + 16
WOP pxor, key0
; align 16
@@:
WOP_KEY aesdec, 1 * koffs_r
sub koffs_r, 16
jnz @B
; WOP_KEY aesdeclast, 0
WOP aesdeclast, key_last
pxor @CatStr(xmm, %(ways_start_reg)), iv
i = 1
rept ways - 1
pxor @CatStr(xmm, %(ways_start_reg + i)), [rD + i * 16 - 16]
i = i + 1
endm
movdqa iv, [rD + ways * 16 - 16]
WOP WRITE_TO_DATA
add rD, ways * 16
AesCbc_Decode_HW_start_3::
check2:
sub rN, ways
jnc nextBlocks2
add rN, ways
sub ksize_x, 16
jmp check
nextBlock:
movdqa state, [rD]
mov koffs_x, ksize_x
; OP_KEY pxor, 1 * ksize_r + 32
pxor state, key0
; movdqa state0, [rD]
; movdqa state, key0
; pxor state, state0
@@:
OP_KEY aesdec, 1 * koffs_r + 16
OP_KEY aesdec, 1 * koffs_r
sub koffs_r, 32
jnz @B
OP_KEY aesdec, 16
; OP_KEY aesdeclast, 0
aesdeclast state, key_last
pxor state, iv
movdqa iv, [rD]
; movdqa iv, state0
movdqa [rD], state
add rD, 16
check:
sub rN, 1
jnc nextBlock
movdqa [keys - 32], iv
MY_EPILOG
; ---------- AVX ----------
AVX__WOP_n macro op
i = 0
rept ways
op (ways_start_reg + i)
i = i + 1
endm
endm
AVX__WOP macro op
i = 0
rept ways
op @CatStr(ymm, %(ways_start_reg + i))
i = i + 1
endm
endm
AVX__WOP_KEY macro op:req, offs:req
vmovdqa key_ymm, ymmword ptr [keys2 + offs]
AVX__WOP_n op
endm
AVX__CBC_START macro reg
; vpxor reg, key_ymm, ymmword ptr [rD + 32 * i]
vpxor reg, key0_ymm, ymmword ptr [rD + 32 * i]
endm
AVX__CBC_END macro reg
if i eq 0
vpxor reg, reg, iv_ymm
else
vpxor reg, reg, ymmword ptr [rD + i * 32 - 16]
endif
endm
AVX__WRITE_TO_DATA macro reg
vmovdqu ymmword ptr [rD + 32 * i], reg
endm
AVX__XOR_WITH_DATA macro reg
vpxor reg, reg, ymmword ptr [rD + 32 * i]
endm
AVX__CTR_START macro reg
vpaddq iv_ymm, iv_ymm, one_ymm
; vpxor reg, iv_ymm, key_ymm
vpxor reg, iv_ymm, key0_ymm
endm
MY_VAES_INSTR_2 macro cmd, dest, a1, a2
db 0c4H
db 2 + 040H + 020h * (1 - (a2) / 8) + 080h * (1 - (dest) / 8)
db 5 + 8 * ((not (a1)) and 15)
db cmd
db 0c0H + 8 * ((dest) and 7) + ((a2) and 7)
endm
MY_VAES_INSTR macro cmd, dest, a
MY_VAES_INSTR_2 cmd, dest, dest, a
endm
MY_vaesenc macro dest, a
MY_VAES_INSTR 0dcH, dest, a
endm
MY_vaesenclast macro dest, a
MY_VAES_INSTR 0ddH, dest, a
endm
MY_vaesdec macro dest, a
MY_VAES_INSTR 0deH, dest, a
endm
MY_vaesdeclast macro dest, a
MY_VAES_INSTR 0dfH, dest, a
endm
AVX__VAES_DEC macro reg
MY_vaesdec reg, key_ymm_n
endm
AVX__VAES_DEC_LAST_key_last macro reg
; MY_vaesdeclast reg, key_ymm_n
MY_vaesdeclast reg, key_last_ymm_n
endm
AVX__VAES_ENC macro reg
MY_vaesenc reg, key_ymm_n
endm
AVX__VAES_ENC_LAST macro reg
MY_vaesenclast reg, key_ymm_n
endm
AVX__vinserti128_TO_HIGH macro dest, src
vinserti128 dest, dest, src, 1
endm
MY_PROC AesCbc_Decode_HW_256, 3
ifdef use_vaes_256
MY_PROLOG NUM_CBC_REGS
cmp rN, ways * 2
jb AesCbc_Decode_HW_start_2
vmovdqa iv, xmmword ptr [keys]
add keys, 32
vbroadcasti128 key0_ymm, xmmword ptr [keys + 1 * ksize_r]
vbroadcasti128 key_last_ymm, xmmword ptr [keys]
sub ksize_x, 16
mov koffs_x, ksize_x
add ksize_x, ksize_x
AVX_STACK_SUB = ((NUM_AES_KEYS_MAX + 1 - 2) * 32)
push keys2
sub r4, AVX_STACK_SUB
; sub r4, 32
; sub r4, ksize_r
; lea keys2, [r4 + 32]
mov keys2, r4
and keys2, -32
broad:
vbroadcasti128 key_ymm, xmmword ptr [keys + 1 * koffs_r]
vmovdqa ymmword ptr [keys2 + koffs_r * 2], key_ymm
sub koffs_r, 16
; jnc broad
jnz broad
sub rN, ways * 2
align 16
avx_cbcdec_nextBlock2:
mov koffs_x, ksize_x
; AVX__WOP_KEY AVX__CBC_START, 1 * koffs_r + 32
AVX__WOP AVX__CBC_START
@@:
AVX__WOP_KEY AVX__VAES_DEC, 1 * koffs_r
sub koffs_r, 32
jnz @B
; AVX__WOP_KEY AVX__VAES_DEC_LAST, 0
AVX__WOP_n AVX__VAES_DEC_LAST_key_last
AVX__vinserti128_TO_HIGH iv_ymm, xmmword ptr [rD]
AVX__WOP AVX__CBC_END
vmovdqa iv, xmmword ptr [rD + ways * 32 - 16]
AVX__WOP AVX__WRITE_TO_DATA
add rD, ways * 32
sub rN, ways * 2
jnc avx_cbcdec_nextBlock2
add rN, ways * 2
shr ksize_x, 1
; lea r4, [r4 + 1 * ksize_r + 32]
add r4, AVX_STACK_SUB
pop keys2
vzeroupper
jmp AesCbc_Decode_HW_start_3
else
jmp AesCbc_Decode_HW_start
endif
MY_ENDP
MY_SEG_ENDP
; ---------- AES-CBC Encode ----------
e0 equ xmm1
CENC_START_KEY equ 2
CENC_NUM_REG_KEYS equ (3 * 2)
; last_key equ @CatStr(xmm, %(CENC_START_KEY + CENC_NUM_REG_KEYS))
MY_SEG_PROC AesCbc_Encode_HW, 3
MY_PROLOG (CENC_START_KEY + CENC_NUM_REG_KEYS + 0)
movdqa state, [keys]
add keys, 32
i = 0
rept CENC_NUM_REG_KEYS
movdqa @CatStr(xmm, %(CENC_START_KEY + i)), [keys + i * 16]
i = i + 1
endm
add keys, ksize_r
neg ksize_r
add ksize_r, (16 * CENC_NUM_REG_KEYS)
; movdqa last_key, [keys]
jmp check_e
align 16
nextBlock_e:
movdqa e0, [rD]
mov koffs_r, ksize_r
pxor e0, @CatStr(xmm, %(CENC_START_KEY))
pxor state, e0
i = 1
rept (CENC_NUM_REG_KEYS - 1)
aesenc state, @CatStr(xmm, %(CENC_START_KEY + i))
i = i + 1
endm
@@:
OP_KEY aesenc, 1 * koffs_r
OP_KEY aesenc, 1 * koffs_r + 16
add koffs_r, 32
jnz @B
OP_KEY aesenclast, 0
; aesenclast state, last_key
movdqa [rD], state
add rD, 16
check_e:
sub rN, 1
jnc nextBlock_e
; movdqa [keys - 32], state
movdqa [keys + 1 * ksize_r - (16 * CENC_NUM_REG_KEYS) - 32], state
MY_EPILOG
MY_SEG_ENDP
; ---------- AES-CTR ----------
ifdef x64
; ways = 11
endif
one equ @CatStr(xmm, %(ways_start_reg + ways + 1))
one_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 1))
key0 equ @CatStr(xmm, %(ways_start_reg + ways + 2))
key0_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 2))
NUM_CTR_REGS equ (ways_start_reg + ways + 3)
INIT_CTR macro reg, _ppp_
paddq iv, one
movdqa reg, iv
endm
MY_SEG_PROC AesCtr_Code_HW, 3
Ctr_start::
MY_PROLOG NUM_CTR_REGS
Ctr_start_2::
movdqa iv, [keys]
add keys, 32
movdqa key0, [keys]
add keys, ksize_r
neg ksize_r
add ksize_r, 16
Ctr_start_3::
mov koffs_x, 1
movd one, koffs_x
jmp check2_c
align 16
nextBlocks2_c:
WOP INIT_CTR, 0
mov koffs_r, ksize_r
; WOP_KEY pxor, 1 * koffs_r -16
WOP pxor, key0
@@:
WOP_KEY aesenc, 1 * koffs_r
add koffs_r, 16
jnz @B
WOP_KEY aesenclast, 0
WOP XOR_WITH_DATA
WOP WRITE_TO_DATA
add rD, ways * 16
check2_c:
sub rN, ways
jnc nextBlocks2_c
add rN, ways
sub keys, 16
add ksize_r, 16
jmp check_c
; align 16
nextBlock_c:
paddq iv, one
; movdqa state, [keys + 1 * koffs_r - 16]
movdqa state, key0
mov koffs_r, ksize_r
pxor state, iv
@@:
OP_KEY aesenc, 1 * koffs_r
OP_KEY aesenc, 1 * koffs_r + 16
add koffs_r, 32
jnz @B
OP_KEY aesenc, 0
OP_KEY aesenclast, 16
pxor state, [rD]
movdqa [rD], state
add rD, 16
check_c:
sub rN, 1
jnc nextBlock_c
; movdqa [keys - 32], iv
movdqa [keys + 1 * ksize_r - 16 - 32], iv
MY_EPILOG
MY_PROC AesCtr_Code_HW_256, 3
ifdef use_vaes_256
MY_PROLOG NUM_CTR_REGS
cmp rN, ways * 2
jb Ctr_start_2
vbroadcasti128 iv_ymm, xmmword ptr [keys]
add keys, 32
vbroadcasti128 key0_ymm, xmmword ptr [keys]
mov koffs_x, 1
vmovd one, koffs_x
vpsubq iv_ymm, iv_ymm, one_ymm
vpaddq one, one, one
AVX__vinserti128_TO_HIGH one_ymm, one
add keys, ksize_r
sub ksize_x, 16
neg ksize_r
mov koffs_r, ksize_r
add ksize_r, ksize_r
AVX_STACK_SUB = ((NUM_AES_KEYS_MAX + 1 - 1) * 32)
push keys2
lea keys2, [r4 - 32]
sub r4, AVX_STACK_SUB
and keys2, -32
vbroadcasti128 key_ymm, xmmword ptr [keys]
vmovdqa ymmword ptr [keys2], key_ymm
@@:
vbroadcasti128 key_ymm, xmmword ptr [keys + 1 * koffs_r]
vmovdqa ymmword ptr [keys2 + koffs_r * 2], key_ymm
add koffs_r, 16
jnz @B
sub rN, ways * 2
align 16
avx_ctr_nextBlock2:
mov koffs_r, ksize_r
AVX__WOP AVX__CTR_START
; AVX__WOP_KEY AVX__CTR_START, 1 * koffs_r - 32
@@:
AVX__WOP_KEY AVX__VAES_ENC, 1 * koffs_r
add koffs_r, 32
jnz @B
AVX__WOP_KEY AVX__VAES_ENC_LAST, 0
AVX__WOP AVX__XOR_WITH_DATA
AVX__WOP AVX__WRITE_TO_DATA
add rD, ways * 32
sub rN, ways * 2
jnc avx_ctr_nextBlock2
add rN, ways * 2
vextracti128 iv, iv_ymm, 1
sar ksize_r, 1
add r4, AVX_STACK_SUB
pop keys2
vzeroupper
jmp Ctr_start_3
else
jmp Ctr_start
endif
MY_ENDP
MY_SEG_ENDP
end

View File

@@ -0,0 +1,540 @@
; LzFindOpt.asm -- ASM version of GetMatchesSpecN_2() function
; 2024-06-18: Igor Pavlov : Public domain
;
ifndef x64
; x64=1
; .err <x64_IS_REQUIRED>
endif
include 7zAsm.asm
MY_ASM_START
ifndef Z7_LZ_FIND_OPT_ASM_USE_SEGMENT
if (IS_LINUX gt 0)
Z7_LZ_FIND_OPT_ASM_USE_SEGMENT equ 1
else
Z7_LZ_FIND_OPT_ASM_USE_SEGMENT equ 1
endif
endif
ifdef Z7_LZ_FIND_OPT_ASM_USE_SEGMENT
_TEXT$LZFINDOPT SEGMENT ALIGN(64) 'CODE'
MY_ALIGN macro num:req
align num
; align 16
endm
else
MY_ALIGN macro num:req
; We expect that ".text" is aligned for 16-bytes.
; So we don't need large alignment inside our function.
align 16
endm
endif
MY_ALIGN_16 macro
MY_ALIGN 16
endm
MY_ALIGN_32 macro
MY_ALIGN 32
endm
MY_ALIGN_64 macro
MY_ALIGN 64
endm
t0_L equ x0_L
t0_x equ x0
t0 equ r0
t1_x equ x3
t1 equ r3
cp_x equ t1_x
cp_r equ t1
m equ x5
m_r equ r5
len_x equ x6
len equ r6
diff_x equ x7
diff equ r7
len0 equ r10
len1_x equ x11
len1 equ r11
maxLen_x equ x12
maxLen equ r12
d equ r13
ptr0 equ r14
ptr1 equ r15
d_lim equ m_r
cycSize equ len_x
hash_lim equ len0
delta1_x equ len1_x
delta1_r equ len1
delta_x equ maxLen_x
delta_r equ maxLen
hash equ ptr0
src equ ptr1
if (IS_LINUX gt 0)
; r1 r2 r8 r9 : win32
; r7 r6 r2 r1 r8 r9 : linux
lenLimit equ r8
lenLimit_x equ x8
; pos_r equ r2
pos equ x2
cur equ r1
son equ r9
else
lenLimit equ REG_ABI_PARAM_2
lenLimit_x equ REG_ABI_PARAM_2_x
pos equ REG_ABI_PARAM_1_x
cur equ REG_ABI_PARAM_0
son equ REG_ABI_PARAM_3
endif
if (IS_LINUX gt 0)
maxLen_OFFS equ (REG_SIZE * (6 + 1))
else
cutValue_OFFS equ (REG_SIZE * (8 + 1 + 4))
d_OFFS equ (REG_SIZE + cutValue_OFFS)
maxLen_OFFS equ (REG_SIZE + d_OFFS)
endif
hash_OFFS equ (REG_SIZE + maxLen_OFFS)
limit_OFFS equ (REG_SIZE + hash_OFFS)
size_OFFS equ (REG_SIZE + limit_OFFS)
cycPos_OFFS equ (REG_SIZE + size_OFFS)
cycSize_OFFS equ (REG_SIZE + cycPos_OFFS)
posRes_OFFS equ (REG_SIZE + cycSize_OFFS)
if (IS_LINUX gt 0)
else
cutValue_PAR equ [r0 + cutValue_OFFS]
d_PAR equ [r0 + d_OFFS]
endif
maxLen_PAR equ [r0 + maxLen_OFFS]
hash_PAR equ [r0 + hash_OFFS]
limit_PAR equ [r0 + limit_OFFS]
size_PAR equ [r0 + size_OFFS]
cycPos_PAR equ [r0 + cycPos_OFFS]
cycSize_PAR equ [r0 + cycSize_OFFS]
posRes_PAR equ [r0 + posRes_OFFS]
cutValue_VAR equ DWORD PTR [r4 + 8 * 0]
cutValueCur_VAR equ DWORD PTR [r4 + 8 * 0 + 4]
cycPos_VAR equ DWORD PTR [r4 + 8 * 1 + 0]
cycSize_VAR equ DWORD PTR [r4 + 8 * 1 + 4]
hash_VAR equ QWORD PTR [r4 + 8 * 2]
limit_VAR equ QWORD PTR [r4 + 8 * 3]
size_VAR equ QWORD PTR [r4 + 8 * 4]
distances equ QWORD PTR [r4 + 8 * 5]
maxLen_VAR equ QWORD PTR [r4 + 8 * 6]
Old_RSP equ QWORD PTR [r4 + 8 * 7]
LOCAL_SIZE equ 8 * 8
COPY_VAR_32 macro dest_var, src_var
mov x3, src_var
mov dest_var, x3
endm
COPY_VAR_64 macro dest_var, src_var
mov r3, src_var
mov dest_var, r3
endm
ifdef Z7_LZ_FIND_OPT_ASM_USE_SEGMENT
; MY_ALIGN_64
else
MY_ALIGN_16
endif
MY_PROC GetMatchesSpecN_2, 13
MY_PUSH_PRESERVED_ABI_REGS
mov r0, RSP
lea r3, [r0 - LOCAL_SIZE]
and r3, -64
mov RSP, r3
mov Old_RSP, r0
if (IS_LINUX gt 0)
mov d, REG_ABI_PARAM_5 ; r13 = r9
mov cutValue_VAR, REG_ABI_PARAM_4_x ; = r8
mov son, REG_ABI_PARAM_3 ; r9 = r1
mov r8, REG_ABI_PARAM_2 ; r8 = r2
mov pos, REG_ABI_PARAM_1_x ; r2 = x6
mov r1, REG_ABI_PARAM_0 ; r1 = r7
else
COPY_VAR_32 cutValue_VAR, cutValue_PAR
mov d, d_PAR
endif
COPY_VAR_64 limit_VAR, limit_PAR
mov hash_lim, size_PAR
mov size_VAR, hash_lim
mov cp_x, cycPos_PAR
mov hash, hash_PAR
mov cycSize, cycSize_PAR
mov cycSize_VAR, cycSize
; we want cur in (rcx). So we change the cur and lenLimit variables
sub lenLimit, cur
neg lenLimit_x
inc lenLimit_x
mov t0_x, maxLen_PAR
sub t0, lenLimit
mov maxLen_VAR, t0
jmp main_loop
MY_ALIGN_64
fill_empty:
; ptr0 = *ptr1 = kEmptyHashValue;
mov QWORD PTR [ptr1], 0
inc pos
inc cp_x
mov DWORD PTR [d - 4], 0
cmp d, limit_VAR
jae fin
cmp hash, hash_lim
je fin
; MY_ALIGN_64
main_loop:
; UInt32 delta = *hash++;
mov diff_x, [hash] ; delta
add hash, 4
; mov cycPos_VAR, cp_x
inc cur
add d, 4
mov m, pos
sub m, diff_x; ; matchPos
; CLzRef *ptr1 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2;
lea ptr1, [son + 8 * cp_r]
; mov cycSize, cycSize_VAR
cmp pos, cycSize
jb directMode ; if (pos < cycSize_VAR)
; CYC MODE
cmp diff_x, cycSize
jae fill_empty ; if (delta >= cycSize_VAR)
xor t0_x, t0_x
mov cycPos_VAR, cp_x
sub cp_x, diff_x
; jae prepare_for_tree_loop
; add cp_x, cycSize
cmovb t0_x, cycSize
add cp_x, t0_x ; cp_x += (cycPos < delta ? cycSize : 0)
jmp prepare_for_tree_loop
directMode:
cmp diff_x, pos
je fill_empty ; if (delta == pos)
jae fin_error ; if (delta >= pos)
mov cycPos_VAR, cp_x
mov cp_x, m
prepare_for_tree_loop:
mov len0, lenLimit
mov hash_VAR, hash
; CLzRef *ptr0 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2 + 1;
lea ptr0, [ptr1 + 4]
; UInt32 *_distances = ++d;
mov distances, d
neg len0
mov len1, len0
mov t0_x, cutValue_VAR
mov maxLen, maxLen_VAR
mov cutValueCur_VAR, t0_x
MY_ALIGN_32
tree_loop:
neg diff
mov len, len0
cmp len1, len0
cmovb len, len1 ; len = (len1 < len0 ? len1 : len0);
add diff, cur
mov t0_x, [son + cp_r * 8] ; prefetch
movzx t0_x, BYTE PTR [diff + 1 * len]
lea cp_r, [son + cp_r * 8]
cmp [cur + 1 * len], t0_L
je matched_1
jb left_0
mov [ptr1], m
mov m, [cp_r + 4]
lea ptr1, [cp_r + 4]
sub diff, cur ; FIX32
jmp next_node
MY_ALIGN_32
left_0:
mov [ptr0], m
mov m, [cp_r]
mov ptr0, cp_r
sub diff, cur ; FIX32
; jmp next_node
; ------------ NEXT NODE ------------
; MY_ALIGN_32
next_node:
mov cycSize, cycSize_VAR
dec cutValueCur_VAR
je finish_tree
add diff_x, pos ; prev_match = pos + diff
cmp m, diff_x
jae fin_error ; if (new_match >= prev_match)
mov diff_x, pos
sub diff_x, m ; delta = pos - new_match
cmp pos, cycSize
jae cyc_mode_2 ; if (pos >= cycSize)
mov cp_x, m
test m, m
jne tree_loop ; if (m != 0)
finish_tree:
; ptr0 = *ptr1 = kEmptyHashValue;
mov DWORD PTR [ptr0], 0
mov DWORD PTR [ptr1], 0
inc pos
; _distances[-1] = (UInt32)(d - _distances);
mov t0, distances
mov t1, d
sub t1, t0
shr t1_x, 2
mov [t0 - 4], t1_x
cmp d, limit_VAR
jae fin ; if (d >= limit)
mov cp_x, cycPos_VAR
mov hash, hash_VAR
mov hash_lim, size_VAR
inc cp_x
cmp hash, hash_lim
jne main_loop ; if (hash != size)
jmp fin
MY_ALIGN_32
cyc_mode_2:
cmp diff_x, cycSize
jae finish_tree ; if (delta >= cycSize)
mov cp_x, cycPos_VAR
xor t0_x, t0_x
sub cp_x, diff_x ; cp_x = cycPos - delta
cmovb t0_x, cycSize
add cp_x, t0_x ; cp_x += (cycPos < delta ? cycSize : 0)
jmp tree_loop
MY_ALIGN_32
matched_1:
inc len
; cmp len_x, lenLimit_x
je short lenLimit_reach
movzx t0_x, BYTE PTR [diff + 1 * len]
cmp [cur + 1 * len], t0_L
jne mismatch
MY_ALIGN_32
match_loop:
; while (++len != lenLimit) (len[diff] != len[0]) ;
inc len
; cmp len_x, lenLimit_x
je short lenLimit_reach
movzx t0_x, BYTE PTR [diff + 1 * len]
cmp BYTE PTR [cur + 1 * len], t0_L
je match_loop
mismatch:
jb left_2
mov [ptr1], m
mov m, [cp_r + 4]
lea ptr1, [cp_r + 4]
mov len1, len
jmp max_update
MY_ALIGN_32
left_2:
mov [ptr0], m
mov m, [cp_r]
mov ptr0, cp_r
mov len0, len
max_update:
sub diff, cur ; restore diff
cmp maxLen, len
jae next_node
mov maxLen, len
add len, lenLimit
mov [d], len_x
mov t0_x, diff_x
not t0_x
mov [d + 4], t0_x
add d, 8
jmp next_node
MY_ALIGN_32
lenLimit_reach:
mov delta_r, cur
sub delta_r, diff
lea delta1_r, [delta_r - 1]
mov t0_x, [cp_r]
mov [ptr1], t0_x
mov t0_x, [cp_r + 4]
mov [ptr0], t0_x
mov [d], lenLimit_x
mov [d + 4], delta1_x
add d, 8
; _distances[-1] = (UInt32)(d - _distances);
mov t0, distances
mov t1, d
sub t1, t0
shr t1_x, 2
mov [t0 - 4], t1_x
mov hash, hash_VAR
mov hash_lim, size_VAR
inc pos
mov cp_x, cycPos_VAR
inc cp_x
mov d_lim, limit_VAR
mov cycSize, cycSize_VAR
; if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit)
; break;
cmp hash, hash_lim
je fin
cmp d, d_lim
jae fin
cmp delta_x, [hash]
jne main_loop
movzx t0_x, BYTE PTR [diff]
cmp [cur], t0_L
jne main_loop
; jmp main_loop ; bypass for debug
mov cycPos_VAR, cp_x
shl len, 3 ; cycSize * 8
sub diff, cur ; restore diff
xor t0_x, t0_x
cmp cp_x, delta_x ; cmp (cycPos_VAR, delta)
lea cp_r, [son + 8 * cp_r] ; dest
lea src, [cp_r + 8 * diff]
cmovb t0, len ; t0 = (cycPos_VAR < delta ? cycSize * 8 : 0)
add src, t0
add len, son ; len = son + cycSize * 8
MY_ALIGN_32
long_loop:
add hash, 4
; *(UInt64 *)(void *)ptr = ((const UInt64 *)(const void *)ptr)[diff];
mov t0, [src]
add src, 8
mov [cp_r], t0
add cp_r, 8
cmp src, len
cmove src, son ; if end of (son) buffer is reached, we wrap to begin
mov DWORD PTR [d], 2
mov [d + 4], lenLimit_x
mov [d + 8], delta1_x
add d, 12
inc cur
cmp hash, hash_lim
je long_footer
cmp delta_x, [hash]
jne long_footer
movzx t0_x, BYTE PTR [diff + 1 * cur]
cmp [cur], t0_L
jne long_footer
cmp d, d_lim
jb long_loop
long_footer:
sub cp_r, son
shr cp_r, 3
add pos, cp_x
sub pos, cycPos_VAR
mov cycSize, cycSize_VAR
cmp d, d_lim
jae fin
cmp hash, hash_lim
jne main_loop
jmp fin
fin_error:
xor d, d
fin:
mov RSP, Old_RSP
mov t0, [r4 + posRes_OFFS]
mov [t0], pos
mov r0, d
MY_POP_PRESERVED_ABI_REGS
MY_ENDP
ifdef Z7_LZ_FIND_OPT_ASM_USE_SEGMENT
_TEXT$LZFINDOPT ENDS
endif
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,263 @@
; Sha1Opt.asm -- SHA-1 optimized code for SHA-1 x86 hardware instructions
; 2024-06-16 : Igor Pavlov : Public domain
include 7zAsm.asm
MY_ASM_START
CONST SEGMENT READONLY
align 16
Reverse_Endian_Mask db 15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0
CONST ENDS
; _TEXT$SHA1OPT SEGMENT 'CODE'
ifndef x64
.686
.xmm
endif
ifdef x64
rNum equ REG_ABI_PARAM_2
if (IS_LINUX eq 0)
LOCAL_SIZE equ (16 * 2)
endif
else
rNum equ r0
LOCAL_SIZE equ (16 * 1)
endif
rState equ REG_ABI_PARAM_0
rData equ REG_ABI_PARAM_1
MY_sha1rnds4 macro a1, a2, imm
db 0fH, 03aH, 0ccH, (0c0H + a1 * 8 + a2), imm
endm
MY_SHA_INSTR macro cmd, a1, a2
db 0fH, 038H, cmd, (0c0H + a1 * 8 + a2)
endm
cmd_sha1nexte equ 0c8H
cmd_sha1msg1 equ 0c9H
cmd_sha1msg2 equ 0caH
MY_sha1nexte macro a1, a2
MY_SHA_INSTR cmd_sha1nexte, a1, a2
endm
MY_sha1msg1 macro a1, a2
MY_SHA_INSTR cmd_sha1msg1, a1, a2
endm
MY_sha1msg2 macro a1, a2
MY_SHA_INSTR cmd_sha1msg2, a1, a2
endm
MY_PROLOG macro
ifdef x64
if (IS_LINUX eq 0)
movdqa [r4 + 8], xmm6
movdqa [r4 + 8 + 16], xmm7
sub r4, LOCAL_SIZE + 8
movdqa [r4 ], xmm8
movdqa [r4 + 16], xmm9
endif
else ; x86
if (IS_CDECL gt 0)
mov rState, [r4 + REG_SIZE * 1]
mov rData, [r4 + REG_SIZE * 2]
mov rNum, [r4 + REG_SIZE * 3]
else ; fastcall
mov rNum, [r4 + REG_SIZE * 1]
endif
push r5
mov r5, r4
and r4, -16
sub r4, LOCAL_SIZE
endif
endm
MY_EPILOG macro
ifdef x64
if (IS_LINUX eq 0)
movdqa xmm8, [r4]
movdqa xmm9, [r4 + 16]
add r4, LOCAL_SIZE + 8
movdqa xmm6, [r4 + 8]
movdqa xmm7, [r4 + 8 + 16]
endif
else ; x86
mov r4, r5
pop r5
endif
MY_ENDP
endm
e0_N equ 0
e1_N equ 1
abcd_N equ 2
e0_save_N equ 3
w_regs equ 4
e0 equ @CatStr(xmm, %e0_N)
e1 equ @CatStr(xmm, %e1_N)
abcd equ @CatStr(xmm, %abcd_N)
e0_save equ @CatStr(xmm, %e0_save_N)
ifdef x64
abcd_save equ xmm8
mask2 equ xmm9
else
abcd_save equ [r4]
mask2 equ e1
endif
LOAD_MASK macro
movdqa mask2, XMMWORD PTR Reverse_Endian_Mask
endm
LOAD_W macro k:req
movdqu @CatStr(xmm, %(w_regs + k)), [rData + (16 * (k))]
pshufb @CatStr(xmm, %(w_regs + k)), mask2
endm
; pre2 can be 2 or 3 (recommended)
pre2 equ 3
pre1 equ (pre2 + 1)
NUM_ROUNDS4 equ 20
RND4 macro k
movdqa @CatStr(xmm, %(e0_N + ((k + 1) mod 2))), abcd
MY_sha1rnds4 abcd_N, (e0_N + (k mod 2)), k / 5
nextM = (w_regs + ((k + 1) mod 4))
if (k EQ NUM_ROUNDS4 - 1)
nextM = e0_save_N
endif
MY_sha1nexte (e0_N + ((k + 1) mod 2)), nextM
if (k GE (4 - pre2)) AND (k LT (NUM_ROUNDS4 - pre2))
pxor @CatStr(xmm, %(w_regs + ((k + pre2) mod 4))), @CatStr(xmm, %(w_regs + ((k + pre2 - 2) mod 4)))
endif
if (k GE (4 - pre1)) AND (k LT (NUM_ROUNDS4 - pre1))
MY_sha1msg1 (w_regs + ((k + pre1) mod 4)), (w_regs + ((k + pre1 - 3) mod 4))
endif
if (k GE (4 - pre2)) AND (k LT (NUM_ROUNDS4 - pre2))
MY_sha1msg2 (w_regs + ((k + pre2) mod 4)), (w_regs + ((k + pre2 - 1) mod 4))
endif
endm
REVERSE_STATE macro
; abcd ; dcba
; e0 ; 000e
pshufd abcd, abcd, 01bH ; abcd
pshufd e0, e0, 01bH ; e000
endm
MY_PROC Sha1_UpdateBlocks_HW, 3
MY_PROLOG
cmp rNum, 0
je end_c
movdqu abcd, [rState] ; dcba
movd e0, dword ptr [rState + 16] ; 000e
REVERSE_STATE
ifdef x64
LOAD_MASK
endif
align 16
nextBlock:
movdqa abcd_save, abcd
movdqa e0_save, e0
ifndef x64
LOAD_MASK
endif
LOAD_W 0
LOAD_W 1
LOAD_W 2
LOAD_W 3
paddd e0, @CatStr(xmm, %(w_regs))
k = 0
rept NUM_ROUNDS4
RND4 k
k = k + 1
endm
paddd abcd, abcd_save
add rData, 64
sub rNum, 1
jnz nextBlock
REVERSE_STATE
movdqu [rState], abcd
movd dword ptr [rState + 16], e0
end_c:
MY_EPILOG
; _TEXT$SHA1OPT ENDS
end

View File

@@ -0,0 +1,275 @@
; Sha256Opt.asm -- SHA-256 optimized code for SHA-256 x86 hardware instructions
; 2024-06-16 : Igor Pavlov : Public domain
include 7zAsm.asm
MY_ASM_START
; .data
; public K
; we can use external SHA256_K_ARRAY defined in Sha256.c
; but we must guarantee that SHA256_K_ARRAY is aligned for 16-bytes
COMMENT @
ifdef x64
K_CONST equ SHA256_K_ARRAY
else
K_CONST equ _SHA256_K_ARRAY
endif
EXTRN K_CONST:xmmword
@
CONST SEGMENT READONLY
align 16
Reverse_Endian_Mask db 3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12
; COMMENT @
align 16
K_CONST \
DD 0428a2f98H, 071374491H, 0b5c0fbcfH, 0e9b5dba5H
DD 03956c25bH, 059f111f1H, 0923f82a4H, 0ab1c5ed5H
DD 0d807aa98H, 012835b01H, 0243185beH, 0550c7dc3H
DD 072be5d74H, 080deb1feH, 09bdc06a7H, 0c19bf174H
DD 0e49b69c1H, 0efbe4786H, 00fc19dc6H, 0240ca1ccH
DD 02de92c6fH, 04a7484aaH, 05cb0a9dcH, 076f988daH
DD 0983e5152H, 0a831c66dH, 0b00327c8H, 0bf597fc7H
DD 0c6e00bf3H, 0d5a79147H, 006ca6351H, 014292967H
DD 027b70a85H, 02e1b2138H, 04d2c6dfcH, 053380d13H
DD 0650a7354H, 0766a0abbH, 081c2c92eH, 092722c85H
DD 0a2bfe8a1H, 0a81a664bH, 0c24b8b70H, 0c76c51a3H
DD 0d192e819H, 0d6990624H, 0f40e3585H, 0106aa070H
DD 019a4c116H, 01e376c08H, 02748774cH, 034b0bcb5H
DD 0391c0cb3H, 04ed8aa4aH, 05b9cca4fH, 0682e6ff3H
DD 0748f82eeH, 078a5636fH, 084c87814H, 08cc70208H
DD 090befffaH, 0a4506cebH, 0bef9a3f7H, 0c67178f2H
; @
CONST ENDS
; _TEXT$SHA256OPT SEGMENT 'CODE'
ifndef x64
.686
.xmm
endif
; jwasm-based assemblers for linux and linker from new versions of binutils
; can generate incorrect code for load [ARRAY + offset] instructions.
; 22.00: we load K_CONST offset to (rTable) register to avoid jwasm+binutils problem
rTable equ r0
; rTable equ K_CONST
ifdef x64
rNum equ REG_ABI_PARAM_2
if (IS_LINUX eq 0)
LOCAL_SIZE equ (16 * 2)
endif
else
rNum equ r3
LOCAL_SIZE equ (16 * 1)
endif
rState equ REG_ABI_PARAM_0
rData equ REG_ABI_PARAM_1
MY_SHA_INSTR macro cmd, a1, a2
db 0fH, 038H, cmd, (0c0H + a1 * 8 + a2)
endm
cmd_sha256rnds2 equ 0cbH
cmd_sha256msg1 equ 0ccH
cmd_sha256msg2 equ 0cdH
MY_sha256rnds2 macro a1, a2
MY_SHA_INSTR cmd_sha256rnds2, a1, a2
endm
MY_sha256msg1 macro a1, a2
MY_SHA_INSTR cmd_sha256msg1, a1, a2
endm
MY_sha256msg2 macro a1, a2
MY_SHA_INSTR cmd_sha256msg2, a1, a2
endm
MY_PROLOG macro
ifdef x64
if (IS_LINUX eq 0)
movdqa [r4 + 8], xmm6
movdqa [r4 + 8 + 16], xmm7
sub r4, LOCAL_SIZE + 8
movdqa [r4 ], xmm8
movdqa [r4 + 16], xmm9
endif
else ; x86
push r3
push r5
mov r5, r4
NUM_PUSH_REGS equ 2
PARAM_OFFSET equ (REG_SIZE * (1 + NUM_PUSH_REGS))
if (IS_CDECL gt 0)
mov rState, [r4 + PARAM_OFFSET]
mov rData, [r4 + PARAM_OFFSET + REG_SIZE * 1]
mov rNum, [r4 + PARAM_OFFSET + REG_SIZE * 2]
else ; fastcall
mov rNum, [r4 + PARAM_OFFSET]
endif
and r4, -16
sub r4, LOCAL_SIZE
endif
endm
MY_EPILOG macro
ifdef x64
if (IS_LINUX eq 0)
movdqa xmm8, [r4]
movdqa xmm9, [r4 + 16]
add r4, LOCAL_SIZE + 8
movdqa xmm6, [r4 + 8]
movdqa xmm7, [r4 + 8 + 16]
endif
else ; x86
mov r4, r5
pop r5
pop r3
endif
MY_ENDP
endm
msg equ xmm0
tmp equ xmm0
state0_N equ 2
state1_N equ 3
w_regs equ 4
state1_save equ xmm1
state0 equ @CatStr(xmm, %state0_N)
state1 equ @CatStr(xmm, %state1_N)
ifdef x64
state0_save equ xmm8
mask2 equ xmm9
else
state0_save equ [r4]
mask2 equ xmm0
endif
LOAD_MASK macro
movdqa mask2, XMMWORD PTR Reverse_Endian_Mask
endm
LOAD_W macro k:req
movdqu @CatStr(xmm, %(w_regs + k)), [rData + (16 * (k))]
pshufb @CatStr(xmm, %(w_regs + k)), mask2
endm
; pre1 <= 4 && pre2 >= 1 && pre1 > pre2 && (pre1 - pre2) <= 1
pre1 equ 3
pre2 equ 2
RND4 macro k
movdqa msg, xmmword ptr [rTable + (k) * 16]
paddd msg, @CatStr(xmm, %(w_regs + ((k + 0) mod 4)))
MY_sha256rnds2 state0_N, state1_N
pshufd msg, msg, 0eH
if (k GE (4 - pre1)) AND (k LT (16 - pre1))
; w4[0] = msg1(w4[-4], w4[-3])
MY_sha256msg1 (w_regs + ((k + pre1) mod 4)), (w_regs + ((k + pre1 - 3) mod 4))
endif
MY_sha256rnds2 state1_N, state0_N
if (k GE (4 - pre2)) AND (k LT (16 - pre2))
movdqa tmp, @CatStr(xmm, %(w_regs + ((k + pre2 - 1) mod 4)))
palignr tmp, @CatStr(xmm, %(w_regs + ((k + pre2 - 2) mod 4))), 4
paddd @CatStr(xmm, %(w_regs + ((k + pre2) mod 4))), tmp
; w4[0] = msg2(w4[0], w4[-1])
MY_sha256msg2 %(w_regs + ((k + pre2) mod 4)), %(w_regs + ((k + pre2 - 1) mod 4))
endif
endm
REVERSE_STATE macro
; state0 ; dcba
; state1 ; hgfe
pshufd tmp, state0, 01bH ; abcd
pshufd state0, state1, 01bH ; efgh
movdqa state1, state0 ; efgh
punpcklqdq state0, tmp ; cdgh
punpckhqdq state1, tmp ; abef
endm
MY_PROC Sha256_UpdateBlocks_HW, 3
MY_PROLOG
lea rTable, [K_CONST]
cmp rNum, 0
je end_c
movdqu state0, [rState] ; dcba
movdqu state1, [rState + 16] ; hgfe
REVERSE_STATE
ifdef x64
LOAD_MASK
endif
align 16
nextBlock:
movdqa state0_save, state0
movdqa state1_save, state1
ifndef x64
LOAD_MASK
endif
LOAD_W 0
LOAD_W 1
LOAD_W 2
LOAD_W 3
k = 0
rept 16
RND4 k
k = k + 1
endm
paddd state0, state0_save
paddd state1, state1_save
add rData, 64
sub rNum, 1
jnz nextBlock
REVERSE_STATE
movdqu [rState], state0
movdqu [rState + 16], state1
end_c:
MY_EPILOG
; _TEXT$SHA256OPT ENDS
end

View File

@@ -0,0 +1,523 @@
; XzCrc64Opt.asm -- CRC64 calculation : optimized version
; 2023-12-08 : Igor Pavlov : Public domain
include 7zAsm.asm
MY_ASM_START
NUM_WORDS equ 3
if (NUM_WORDS lt 1) or (NUM_WORDS gt 64)
.err <num_words_IS_INCORRECT>
endif
NUM_SKIP_BYTES equ ((NUM_WORDS - 2) * 4)
MOVZXLO macro dest:req, src:req
movzx dest, @CatStr(src, _L)
endm
MOVZXHI macro dest:req, src:req
movzx dest, @CatStr(src, _H)
endm
ifdef x64
rD equ r11
rN equ r10
rT equ r9
CRC_OP macro op:req, dest:req, src:req, t:req
op dest, QWORD PTR [rT + @CatStr(src, _R) * 8 + 0800h * (t)]
endm
CRC_XOR macro dest:req, src:req, t:req
CRC_OP xor, dest, src, t
endm
CRC_MOV macro dest:req, src:req, t:req
CRC_OP mov, dest, src, t
endm
CRC1b macro
movzx x6, BYTE PTR [rD]
inc rD
MOVZXLO x3, x0
xor x6, x3
shr r0, 8
CRC_XOR r0, x6, 0
dec rN
endm
; ALIGN_MASK is 3 or 7 bytes alignment:
ALIGN_MASK equ (7 - (NUM_WORDS and 1) * 4)
if NUM_WORDS eq 1
src_rN_offset equ 4
; + 4 for prefetching next 4-bytes after current iteration
NUM_BYTES_LIMIT equ (NUM_WORDS * 4 + 4)
SRCDAT4 equ DWORD PTR [rN + rD * 1]
XOR_NEXT macro
mov x1, [rD]
xor r0, r1
endm
else ; NUM_WORDS > 1
src_rN_offset equ 8
; + 8 for prefetching next 8-bytes after current iteration
NUM_BYTES_LIMIT equ (NUM_WORDS * 4 + 8)
XOR_NEXT macro
xor r0, QWORD PTR [rD] ; 64-bit read, can be unaligned
endm
; 32-bit or 64-bit
LOAD_SRC_MULT4 macro dest:req, word_index:req
mov dest, [rN + rD * 1 + 4 * (word_index) - src_rN_offset];
endm
endif
MY_PROC @CatStr(XzCrc64UpdateT, %(NUM_WORDS * 4)), 4
MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11
mov r0, REG_ABI_PARAM_0 ; r0 <- r1 / r7
mov rD, REG_ABI_PARAM_1 ; r11 <- r2 / r6
mov rN, REG_ABI_PARAM_2 ; r10 <- r8 / r2
if (IS_LINUX gt 0)
mov rT, REG_ABI_PARAM_3 ; r9 <- r9 / r1
endif
cmp rN, NUM_BYTES_LIMIT + ALIGN_MASK
jb crc_end
@@:
test rD, ALIGN_MASK
jz @F
CRC1b
jmp @B
@@:
XOR_NEXT
lea rN, [rD + rN * 1 - (NUM_BYTES_LIMIT - 1)]
sub rD, rN
add rN, src_rN_offset
align 16
@@:
if NUM_WORDS eq 1
mov x1, x0
shr x1, 8
MOVZXLO x3, x1
MOVZXLO x2, x0
shr x1, 8
shr r0, 32
xor x0, SRCDAT4
CRC_XOR r0, x2, 3
CRC_XOR r0, x3, 2
MOVZXLO x2, x1
shr x1, 8
CRC_XOR r0, x2, 1
CRC_XOR r0, x1, 0
else ; NUM_WORDS > 1
if NUM_WORDS ne 2
k = 2
while k lt NUM_WORDS
LOAD_SRC_MULT4 x1, k
crc_op1 textequ <xor>
if k eq 2
if (NUM_WORDS and 1)
LOAD_SRC_MULT4 x7, NUM_WORDS ; aligned 32-bit
LOAD_SRC_MULT4 x6, NUM_WORDS + 1 ; aligned 32-bit
shl r6, 32
else
LOAD_SRC_MULT4 r6, NUM_WORDS ; aligned 64-bit
crc_op1 textequ <mov>
endif
endif
table = 4 * (NUM_WORDS - 1 - k)
MOVZXLO x3, x1
CRC_OP crc_op1, r7, x3, 3 + table
MOVZXHI x3, x1
shr x1, 16
CRC_XOR r6, x3, 2 + table
MOVZXLO x3, x1
shr x1, 8
CRC_XOR r7, x3, 1 + table
CRC_XOR r6, x1, 0 + table
k = k + 1
endm
crc_op2 textequ <xor>
else ; NUM_WORDS == 2
LOAD_SRC_MULT4 r6, NUM_WORDS ; aligned 64-bit
crc_op2 textequ <mov>
endif ; NUM_WORDS == 2
MOVZXHI x3, x0
MOVZXLO x2, x0
mov r1, r0
shr r1, 32
shr x0, 16
CRC_XOR r6, x2, NUM_SKIP_BYTES + 7
CRC_OP crc_op2, r7, x3, NUM_SKIP_BYTES + 6
MOVZXLO x2, x0
MOVZXHI x5, x1
MOVZXLO x3, x1
shr x0, 8
shr x1, 16
CRC_XOR r7, x2, NUM_SKIP_BYTES + 5
CRC_XOR r6, x3, NUM_SKIP_BYTES + 3
CRC_XOR r7, x0, NUM_SKIP_BYTES + 4
CRC_XOR r6, x5, NUM_SKIP_BYTES + 2
MOVZXLO x2, x1
shr x1, 8
CRC_XOR r7, x2, NUM_SKIP_BYTES + 1
CRC_MOV r0, x1, NUM_SKIP_BYTES + 0
xor r0, r6
xor r0, r7
endif ; NUM_WORDS > 1
add rD, NUM_WORDS * 4
jnc @B
sub rN, src_rN_offset
add rD, rN
XOR_NEXT
add rN, NUM_BYTES_LIMIT - 1
sub rN, rD
crc_end:
test rN, rN
jz func_end
@@:
CRC1b
jnz @B
func_end:
MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11
MY_ENDP
else
; ==================================================================
; x86 (32-bit)
rD equ r7
rN equ r1
rT equ r5
xA equ x6
xA_R equ r6
ifdef x64
num_VAR equ r8
else
crc_OFFS equ (REG_SIZE * 5)
if (IS_CDECL gt 0) or (IS_LINUX gt 0)
; cdecl or (GNU fastcall) stack:
; (UInt32 *) table
; size_t size
; void * data
; (UInt64) crc
; ret-ip <-(r4)
data_OFFS equ (8 + crc_OFFS)
size_OFFS equ (REG_SIZE + data_OFFS)
table_OFFS equ (REG_SIZE + size_OFFS)
num_VAR equ [r4 + size_OFFS]
table_VAR equ [r4 + table_OFFS]
else
; Windows fastcall:
; r1 = data, r2 = size
; stack:
; (UInt32 *) table
; (UInt64) crc
; ret-ip <-(r4)
table_OFFS equ (8 + crc_OFFS)
table_VAR equ [r4 + table_OFFS]
num_VAR equ table_VAR
endif
endif ; x64
SRCDAT4 equ DWORD PTR [rN + rD * 1]
CRC_1 macro op:req, dest:req, src:req, t:req, word_index:req
op dest, DWORD PTR [rT + @CatStr(src, _R) * 8 + 0800h * (t) + (word_index) * 4]
endm
CRC macro op0:req, op1:req, dest0:req, dest1:req, src:req, t:req
CRC_1 op0, dest0, src, t, 0
CRC_1 op1, dest1, src, t, 1
endm
CRC_XOR macro dest0:req, dest1:req, src:req, t:req
CRC xor, xor, dest0, dest1, src, t
endm
CRC1b macro
movzx xA, BYTE PTR [rD]
inc rD
MOVZXLO x3, x0
xor xA, x3
shrd x0, x2, 8
shr x2, 8
CRC_XOR x0, x2, xA, 0
dec rN
endm
MY_PROLOG_BASE macro
MY_PUSH_4_REGS
ifdef x64
mov r0, REG_ABI_PARAM_0 ; r0 <- r1 / r7
mov rT, REG_ABI_PARAM_3 ; r5 <- r9 / r1
mov rN, REG_ABI_PARAM_2 ; r1 <- r8 / r2
mov rD, REG_ABI_PARAM_1 ; r7 <- r2 / r6
mov r2, r0
shr r2, 32
mov x0, x0
else
if (IS_CDECL gt 0) or (IS_LINUX gt 0)
proc_numParams = proc_numParams + 2 ; for ABI_LINUX
mov rN, [r4 + size_OFFS]
mov rD, [r4 + data_OFFS]
else
mov rD, REG_ABI_PARAM_0 ; r7 <- r1 : (data)
mov rN, REG_ABI_PARAM_1 ; r1 <- r2 : (size)
endif
mov x0, [r4 + crc_OFFS]
mov x2, [r4 + crc_OFFS + 4]
mov rT, table_VAR
endif
endm
MY_EPILOG_BASE macro crc_end:req, func_end:req
crc_end:
test rN, rN
jz func_end
@@:
CRC1b
jnz @B
func_end:
ifdef x64
shl r2, 32
xor r0, r2
endif
MY_POP_4_REGS
endm
; ALIGN_MASK is 3 or 7 bytes alignment:
ALIGN_MASK equ (7 - (NUM_WORDS and 1) * 4)
if (NUM_WORDS eq 1)
NUM_BYTES_LIMIT_T4 equ (NUM_WORDS * 4 + 4)
MY_PROC @CatStr(XzCrc64UpdateT, %(NUM_WORDS * 4)), 5
MY_PROLOG_BASE
cmp rN, NUM_BYTES_LIMIT_T4 + ALIGN_MASK
jb crc_end_4
@@:
test rD, ALIGN_MASK
jz @F
CRC1b
jmp @B
@@:
xor x0, [rD]
lea rN, [rD + rN * 1 - (NUM_BYTES_LIMIT_T4 - 1)]
sub rD, rN
add rN, 4
MOVZXLO xA, x0
align 16
@@:
mov x3, SRCDAT4
xor x3, x2
shr x0, 8
CRC xor, mov, x3, x2, xA, 3
MOVZXLO xA, x0
shr x0, 8
; MOVZXHI xA, x0
; shr x0, 16
CRC_XOR x3, x2, xA, 2
MOVZXLO xA, x0
shr x0, 8
CRC_XOR x3, x2, xA, 1
CRC_XOR x3, x2, x0, 0
MOVZXLO xA, x3
mov x0, x3
add rD, 4
jnc @B
sub rN, 4
add rD, rN
xor x0, [rD]
add rN, NUM_BYTES_LIMIT_T4 - 1
sub rN, rD
MY_EPILOG_BASE crc_end_4, func_end_4
MY_ENDP
else ; NUM_WORDS > 1
SHR_X macro x, imm
shr x, imm
endm
ITER_1 macro v0, v1, a, off
MOVZXLO xA, a
SHR_X a, 8
CRC_XOR v0, v1, xA, off
endm
ITER_4 macro v0, v1, a, off
if 0 eq 0
ITER_1 v0, v1, a, off + 3
ITER_1 v0, v1, a, off + 2
ITER_1 v0, v1, a, off + 1
CRC_XOR v0, v1, a, off
elseif 0 eq 0
MOVZXLO xA, a
CRC_XOR v0, v1, xA, off + 3
mov xA, a
ror a, 16 ; 32-bit ror
shr xA, 24
CRC_XOR v0, v1, xA, off
MOVZXLO xA, a
SHR_X a, 24
CRC_XOR v0, v1, xA, off + 1
CRC_XOR v0, v1, a, off + 2
else
; MOVZXHI provides smaller code, but MOVZX_HI_BYTE is not fast instruction
MOVZXLO xA, a
CRC_XOR v0, v1, xA, off + 3
MOVZXHI xA, a
SHR_X a, 16
CRC_XOR v0, v1, xA, off + 2
MOVZXLO xA, a
SHR_X a, 8
CRC_XOR v0, v1, xA, off + 1
CRC_XOR v0, v1, a, off
endif
endm
ITER_1_PAIR macro v0, v1, a0, a1, off
ITER_1 v0, v1, a0, off + 4
ITER_1 v0, v1, a1, off
endm
src_rD_offset equ 8
STEP_SIZE equ (NUM_WORDS * 4)
ITER_12_NEXT macro op, index, v0, v1
op v0, DWORD PTR [rD + (index + 1) * STEP_SIZE - src_rD_offset]
op v1, DWORD PTR [rD + (index + 1) * STEP_SIZE + 4 - src_rD_offset]
endm
ITER_12 macro index, a0, a1, v0, v1
if NUM_SKIP_BYTES eq 0
ITER_12_NEXT mov, index, v0, v1
else
k = 0
while k lt NUM_SKIP_BYTES
movzx xA, BYTE PTR [rD + (index) * STEP_SIZE + k + 8 - src_rD_offset]
if k eq 0
CRC mov, mov, v0, v1, xA, NUM_SKIP_BYTES - 1 - k
else
CRC_XOR v0, v1, xA, NUM_SKIP_BYTES - 1 - k
endif
k = k + 1
endm
ITER_12_NEXT xor, index, v0, v1
endif
if 0 eq 0
ITER_4 v0, v1, a0, NUM_SKIP_BYTES + 4
ITER_4 v0, v1, a1, NUM_SKIP_BYTES
else ; interleave version is faster/slower for different processors
ITER_1_PAIR v0, v1, a0, a1, NUM_SKIP_BYTES + 3
ITER_1_PAIR v0, v1, a0, a1, NUM_SKIP_BYTES + 2
ITER_1_PAIR v0, v1, a0, a1, NUM_SKIP_BYTES + 1
CRC_XOR v0, v1, a0, NUM_SKIP_BYTES + 4
CRC_XOR v0, v1, a1, NUM_SKIP_BYTES
endif
endm
; we use (UNROLL_CNT > 1) to reduce read ports pressure (num_VAR reads)
UNROLL_CNT equ (2 * 1)
NUM_BYTES_LIMIT equ (STEP_SIZE * UNROLL_CNT + 8)
MY_PROC @CatStr(XzCrc64UpdateT, %(NUM_WORDS * 4)), 5
MY_PROLOG_BASE
cmp rN, NUM_BYTES_LIMIT + ALIGN_MASK
jb crc_end_12
@@:
test rD, ALIGN_MASK
jz @F
CRC1b
jmp @B
@@:
xor x0, [rD]
xor x2, [rD + 4]
add rD, src_rD_offset
lea rN, [rD + rN * 1 - (NUM_BYTES_LIMIT - 1)]
mov num_VAR, rN
align 16
@@:
i = 0
rept UNROLL_CNT
if (i and 1) eq 0
ITER_12 i, x0, x2, x1, x3
else
ITER_12 i, x1, x3, x0, x2
endif
i = i + 1
endm
if (UNROLL_CNT and 1)
mov x0, x1
mov x2, x3
endif
add rD, STEP_SIZE * UNROLL_CNT
cmp rD, num_VAR
jb @B
mov rN, num_VAR
add rN, NUM_BYTES_LIMIT - 1
sub rN, rD
sub rD, src_rD_offset
xor x0, [rD]
xor x2, [rD + 4]
MY_EPILOG_BASE crc_end_12, func_end_12
MY_ENDP
endif ; (NUM_WORDS > 1)
endif ; ! x64
end

View File

@@ -0,0 +1,204 @@
/* 7z.h -- 7z interface
2023-04-02 : Igor Pavlov : Public domain */
#ifndef ZIP7_INC_7Z_H
#define ZIP7_INC_7Z_H
#include "7zTypes.h"
EXTERN_C_BEGIN
#define k7zStartHeaderSize 0x20
#define k7zSignatureSize 6
extern const Byte k7zSignature[k7zSignatureSize];
typedef struct
{
const Byte *Data;
size_t Size;
} CSzData;
/* CSzCoderInfo & CSzFolder support only default methods */
typedef struct
{
size_t PropsOffset;
UInt32 MethodID;
Byte NumStreams;
Byte PropsSize;
} CSzCoderInfo;
typedef struct
{
UInt32 InIndex;
UInt32 OutIndex;
} CSzBond;
#define SZ_NUM_CODERS_IN_FOLDER_MAX 4
#define SZ_NUM_BONDS_IN_FOLDER_MAX 3
#define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4
typedef struct
{
UInt32 NumCoders;
UInt32 NumBonds;
UInt32 NumPackStreams;
UInt32 UnpackStream;
UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX];
CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX];
CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX];
} CSzFolder;
SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd);
typedef struct
{
UInt32 Low;
UInt32 High;
} CNtfsFileTime;
typedef struct
{
Byte *Defs; /* MSB 0 bit numbering */
UInt32 *Vals;
} CSzBitUi32s;
typedef struct
{
Byte *Defs; /* MSB 0 bit numbering */
// UInt64 *Vals;
CNtfsFileTime *Vals;
} CSzBitUi64s;
#define SzBitArray_Check(p, i) (((p)[(i) >> 3] & (0x80 >> ((i) & 7))) != 0)
#define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0)
typedef struct
{
UInt32 NumPackStreams;
UInt32 NumFolders;
UInt64 *PackPositions; // NumPackStreams + 1
CSzBitUi32s FolderCRCs; // NumFolders
size_t *FoCodersOffsets; // NumFolders + 1
UInt32 *FoStartPackStreamIndex; // NumFolders + 1
UInt32 *FoToCoderUnpackSizes; // NumFolders + 1
Byte *FoToMainUnpackSizeIndex; // NumFolders
UInt64 *CoderUnpackSizes; // for all coders in all folders
Byte *CodersData;
UInt64 RangeLimit;
} CSzAr;
UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex);
SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
ILookInStreamPtr stream, UInt64 startPos,
Byte *outBuffer, size_t outSize,
ISzAllocPtr allocMain);
typedef struct
{
CSzAr db;
UInt64 startPosAfterHeader;
UInt64 dataPos;
UInt32 NumFiles;
UInt64 *UnpackPositions; // NumFiles + 1
// Byte *IsEmptyFiles;
Byte *IsDirs;
CSzBitUi32s CRCs;
CSzBitUi32s Attribs;
// CSzBitUi32s Parents;
CSzBitUi64s MTime;
CSzBitUi64s CTime;
UInt32 *FolderToFile; // NumFolders + 1
UInt32 *FileToFolder; // NumFiles
size_t *FileNameOffsets; /* in 2-byte steps */
Byte *FileNames; /* UTF-16-LE */
} CSzArEx;
#define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i))
#define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i])
void SzArEx_Init(CSzArEx *p);
void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc);
UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder);
int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize);
/*
if dest == NULL, the return value specifies the required size of the buffer,
in 16-bit characters, including the null-terminating character.
if dest != NULL, the return value specifies the number of 16-bit characters that
are written to the dest, including the null-terminating character. */
size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
/*
size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex);
UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
*/
/*
SzArEx_Extract extracts file from archive
*outBuffer must be 0 before first call for each new archive.
Extracting cache:
If you need to decompress more than one file, you can send
these values from previous call:
*blockIndex,
*outBuffer,
*outBufferSize
You can consider "*outBuffer" as cache of solid block. If your archive is solid,
it will increase decompression speed.
If you use external function, you can declare these 3 cache variables
(blockIndex, outBuffer, outBufferSize) as static in that external function.
Free *outBuffer and set *outBuffer to 0, if you want to flush cache.
*/
SRes SzArEx_Extract(
const CSzArEx *db,
ILookInStreamPtr inStream,
UInt32 fileIndex, /* index of file */
UInt32 *blockIndex, /* index of solid block */
Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
size_t *outBufferSize, /* buffer size for output buffer */
size_t *offset, /* offset of stream for required file in *outBuffer */
size_t *outSizeProcessed, /* size of file in *outBuffer */
ISzAllocPtr allocMain,
ISzAllocPtr allocTemp);
/*
SzArEx_Open Errors:
SZ_ERROR_NO_ARCHIVE
SZ_ERROR_ARCHIVE
SZ_ERROR_UNSUPPORTED
SZ_ERROR_MEM
SZ_ERROR_CRC
SZ_ERROR_INPUT_EOF
SZ_ERROR_FAIL
*/
SRes SzArEx_Open(CSzArEx *p, ILookInStreamPtr inStream,
ISzAllocPtr allocMain, ISzAllocPtr allocTemp);
EXTERN_C_END
#endif

View File

@@ -0,0 +1,89 @@
/* 7zAlloc.c -- Allocation functions for 7z processing
2023-03-04 : Igor Pavlov : Public domain */
#include "Precomp.h"
#include <stdlib.h>
#include "7zAlloc.h"
/* #define SZ_ALLOC_DEBUG */
/* use SZ_ALLOC_DEBUG to debug alloc/free operations */
#ifdef SZ_ALLOC_DEBUG
/*
#ifdef _WIN32
#include "7zWindows.h"
#endif
*/
#include <stdio.h>
static int g_allocCount = 0;
static int g_allocCountTemp = 0;
static void Print_Alloc(const char *s, size_t size, int *counter)
{
const unsigned size2 = (unsigned)size;
fprintf(stderr, "\n%s count = %10d : %10u bytes; ", s, *counter, size2);
(*counter)++;
}
static void Print_Free(const char *s, int *counter)
{
(*counter)--;
fprintf(stderr, "\n%s count = %10d", s, *counter);
}
#endif
void *SzAlloc(ISzAllocPtr p, size_t size)
{
UNUSED_VAR(p)
if (size == 0)
return 0;
#ifdef SZ_ALLOC_DEBUG
Print_Alloc("Alloc", size, &g_allocCount);
#endif
return malloc(size);
}
void SzFree(ISzAllocPtr p, void *address)
{
UNUSED_VAR(p)
#ifdef SZ_ALLOC_DEBUG
if (address)
Print_Free("Free ", &g_allocCount);
#endif
free(address);
}
void *SzAllocTemp(ISzAllocPtr p, size_t size)
{
UNUSED_VAR(p)
if (size == 0)
return 0;
#ifdef SZ_ALLOC_DEBUG
Print_Alloc("Alloc_temp", size, &g_allocCountTemp);
/*
#ifdef _WIN32
return HeapAlloc(GetProcessHeap(), 0, size);
#endif
*/
#endif
return malloc(size);
}
void SzFreeTemp(ISzAllocPtr p, void *address)
{
UNUSED_VAR(p)
#ifdef SZ_ALLOC_DEBUG
if (address)
Print_Free("Free_temp ", &g_allocCountTemp);
/*
#ifdef _WIN32
HeapFree(GetProcessHeap(), 0, address);
return;
#endif
*/
#endif
free(address);
}

View File

@@ -0,0 +1,19 @@
/* 7zAlloc.h -- Allocation functions
2023-03-04 : Igor Pavlov : Public domain */
#ifndef ZIP7_INC_7Z_ALLOC_H
#define ZIP7_INC_7Z_ALLOC_H
#include "7zTypes.h"
EXTERN_C_BEGIN
void *SzAlloc(ISzAllocPtr p, size_t size);
void SzFree(ISzAllocPtr p, void *address);
void *SzAllocTemp(ISzAllocPtr p, size_t size);
void SzFreeTemp(ISzAllocPtr p, void *address);
EXTERN_C_END
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,36 @@
/* 7zBuf.c -- Byte Buffer
2017-04-03 : Igor Pavlov : Public domain */
#include "Precomp.h"
#include "7zBuf.h"
void Buf_Init(CBuf *p)
{
p->data = 0;
p->size = 0;
}
int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc)
{
p->size = 0;
if (size == 0)
{
p->data = 0;
return 1;
}
p->data = (Byte *)ISzAlloc_Alloc(alloc, size);
if (p->data)
{
p->size = size;
return 1;
}
return 0;
}
void Buf_Free(CBuf *p, ISzAllocPtr alloc)
{
ISzAlloc_Free(alloc, p->data);
p->data = 0;
p->size = 0;
}

View File

@@ -0,0 +1,35 @@
/* 7zBuf.h -- Byte Buffer
2023-03-04 : Igor Pavlov : Public domain */
#ifndef ZIP7_INC_7Z_BUF_H
#define ZIP7_INC_7Z_BUF_H
#include "7zTypes.h"
EXTERN_C_BEGIN
typedef struct
{
Byte *data;
size_t size;
} CBuf;
void Buf_Init(CBuf *p);
int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc);
void Buf_Free(CBuf *p, ISzAllocPtr alloc);
typedef struct
{
Byte *data;
size_t size;
size_t pos;
} CDynBuf;
void DynBuf_Construct(CDynBuf *p);
void DynBuf_SeekToBeg(CDynBuf *p);
int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc);
void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc);
EXTERN_C_END
#endif

View File

@@ -0,0 +1,52 @@
/* 7zBuf2.c -- Byte Buffer
2017-04-03 : Igor Pavlov : Public domain */
#include "Precomp.h"
#include <string.h>
#include "7zBuf.h"
void DynBuf_Construct(CDynBuf *p)
{
p->data = 0;
p->size = 0;
p->pos = 0;
}
void DynBuf_SeekToBeg(CDynBuf *p)
{
p->pos = 0;
}
int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc)
{
if (size > p->size - p->pos)
{
size_t newSize = p->pos + size;
Byte *data;
newSize += newSize / 4;
data = (Byte *)ISzAlloc_Alloc(alloc, newSize);
if (!data)
return 0;
p->size = newSize;
if (p->pos != 0)
memcpy(data, p->data, p->pos);
ISzAlloc_Free(alloc, p->data);
p->data = data;
}
if (size != 0)
{
memcpy(p->data + p->pos, buf, size);
p->pos += size;
}
return 1;
}
void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc)
{
ISzAlloc_Free(alloc, p->data);
p->data = 0;
p->size = 0;
p->pos = 0;
}

View File

@@ -0,0 +1,420 @@
/* 7zCrc.c -- CRC32 calculation and init
2024-03-01 : Igor Pavlov : Public domain */
#include "Precomp.h"
#include "7zCrc.h"
#include "CpuArch.h"
// for debug:
// #define __ARM_FEATURE_CRC32 1
#ifdef __ARM_FEATURE_CRC32
// #pragma message("__ARM_FEATURE_CRC32")
#define Z7_CRC_HW_FORCE
#endif
// #define Z7_CRC_DEBUG_BE
#ifdef Z7_CRC_DEBUG_BE
#undef MY_CPU_LE
#define MY_CPU_BE
#endif
#ifdef Z7_CRC_HW_FORCE
#define Z7_CRC_NUM_TABLES_USE 1
#else
#ifdef Z7_CRC_NUM_TABLES
#define Z7_CRC_NUM_TABLES_USE Z7_CRC_NUM_TABLES
#else
#define Z7_CRC_NUM_TABLES_USE 12
#endif
#endif
#if Z7_CRC_NUM_TABLES_USE < 1
#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES
#endif
#if defined(MY_CPU_LE) || (Z7_CRC_NUM_TABLES_USE == 1)
#define Z7_CRC_NUM_TABLES_TOTAL Z7_CRC_NUM_TABLES_USE
#else
#define Z7_CRC_NUM_TABLES_TOTAL (Z7_CRC_NUM_TABLES_USE + 1)
#endif
#ifndef Z7_CRC_HW_FORCE
#if Z7_CRC_NUM_TABLES_USE == 1 \
|| (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
#define Z7_CRC_UPDATE_T1_FUNC_NAME CrcUpdateGT1
static UInt32 Z7_FASTCALL Z7_CRC_UPDATE_T1_FUNC_NAME(UInt32 v, const void *data, size_t size)
{
const UInt32 *table = g_CrcTable;
const Byte *p = (const Byte *)data;
const Byte *lim = p + size;
for (; p != lim; p++)
v = CRC_UPDATE_BYTE_2(v, *p);
return v;
}
#endif
#if Z7_CRC_NUM_TABLES_USE != 1
#ifndef MY_CPU_BE
#define FUNC_NAME_LE_2(s) CrcUpdateT ## s
#define FUNC_NAME_LE_1(s) FUNC_NAME_LE_2(s)
#define FUNC_NAME_LE FUNC_NAME_LE_1(Z7_CRC_NUM_TABLES_USE)
UInt32 Z7_FASTCALL FUNC_NAME_LE (UInt32 v, const void *data, size_t size, const UInt32 *table);
#endif
#ifndef MY_CPU_LE
#define FUNC_NAME_BE_2(s) CrcUpdateT1_BeT ## s
#define FUNC_NAME_BE_1(s) FUNC_NAME_BE_2(s)
#define FUNC_NAME_BE FUNC_NAME_BE_1(Z7_CRC_NUM_TABLES_USE)
UInt32 Z7_FASTCALL FUNC_NAME_BE (UInt32 v, const void *data, size_t size, const UInt32 *table);
#endif
#endif
#endif // Z7_CRC_HW_FORCE
/* ---------- hardware CRC ---------- */
#ifdef MY_CPU_LE
#if defined(MY_CPU_ARM_OR_ARM64)
// #pragma message("ARM*")
#if (defined(__clang__) && (__clang_major__ >= 3)) \
|| defined(__GNUC__) && (__GNUC__ >= 6) && defined(MY_CPU_ARM64) \
|| defined(__GNUC__) && (__GNUC__ >= 8)
#if !defined(__ARM_FEATURE_CRC32)
// #pragma message("!defined(__ARM_FEATURE_CRC32)")
Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
#define __ARM_FEATURE_CRC32 1
Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
#define Z7_ARM_FEATURE_CRC32_WAS_SET
#if defined(__clang__)
#if defined(MY_CPU_ARM64)
#define ATTRIB_CRC __attribute__((__target__("crc")))
#else
#define ATTRIB_CRC __attribute__((__target__("armv8-a,crc")))
#endif
#else
#if defined(MY_CPU_ARM64)
#if !defined(Z7_GCC_VERSION) || (Z7_GCC_VERSION >= 60000)
#define ATTRIB_CRC __attribute__((__target__("+crc")))
#endif
#else
#if !defined(Z7_GCC_VERSION) || (__GNUC__ >= 8)
#if defined(__ARM_FP) && __GNUC__ >= 8
// for -mfloat-abi=hard: similar to <arm_acle.h>
#define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc+simd")))
#else
#define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc")))
#endif
#endif
#endif
#endif
#endif
#if defined(__ARM_FEATURE_CRC32)
// #pragma message("<arm_acle.h>")
/*
arm_acle.h (GGC):
before Nov 17, 2017:
#ifdef __ARM_FEATURE_CRC32
Nov 17, 2017: gcc10.0 (gcc 9.2.0) checked"
#if __ARM_ARCH >= 8
#pragma GCC target ("arch=armv8-a+crc")
Aug 22, 2019: GCC 8.4?, 9.2.1, 10.1:
#ifdef __ARM_FEATURE_CRC32
#ifdef __ARM_FP
#pragma GCC target ("arch=armv8-a+crc+simd")
#else
#pragma GCC target ("arch=armv8-a+crc")
#endif
*/
#if defined(__ARM_ARCH) && __ARM_ARCH < 8
#if defined(Z7_GCC_VERSION) && (__GNUC__ == 8) && (Z7_GCC_VERSION < 80400) \
|| defined(Z7_GCC_VERSION) && (__GNUC__ == 9) && (Z7_GCC_VERSION < 90201) \
|| defined(Z7_GCC_VERSION) && (__GNUC__ == 10) && (Z7_GCC_VERSION < 100100)
Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
// #pragma message("#define __ARM_ARCH 8")
#undef __ARM_ARCH
#define __ARM_ARCH 8
Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
#endif
#endif
#define Z7_CRC_HW_USE
#include <arm_acle.h>
#endif
#elif defined(_MSC_VER)
#if defined(MY_CPU_ARM64)
#if (_MSC_VER >= 1910)
#ifdef __clang__
// #define Z7_CRC_HW_USE
// #include <arm_acle.h>
#else
#define Z7_CRC_HW_USE
#include <intrin.h>
#endif
#endif
#endif
#endif
#else // non-ARM*
// #define Z7_CRC_HW_USE // for debug : we can test HW-branch of code
#ifdef Z7_CRC_HW_USE
#include "7zCrcEmu.h"
#endif
#endif // non-ARM*
#if defined(Z7_CRC_HW_USE)
// #pragma message("USE ARM HW CRC")
#ifdef MY_CPU_64BIT
#define CRC_HW_WORD_TYPE UInt64
#define CRC_HW_WORD_FUNC __crc32d
#else
#define CRC_HW_WORD_TYPE UInt32
#define CRC_HW_WORD_FUNC __crc32w
#endif
#define CRC_HW_UNROLL_BYTES (sizeof(CRC_HW_WORD_TYPE) * 4)
#ifdef ATTRIB_CRC
ATTRIB_CRC
#endif
Z7_NO_INLINE
#ifdef Z7_CRC_HW_FORCE
UInt32 Z7_FASTCALL CrcUpdate
#else
static UInt32 Z7_FASTCALL CrcUpdate_HW
#endif
(UInt32 v, const void *data, size_t size)
{
const Byte *p = (const Byte *)data;
for (; size != 0 && ((unsigned)(ptrdiff_t)p & (CRC_HW_UNROLL_BYTES - 1)) != 0; size--)
v = __crc32b(v, *p++);
if (size >= CRC_HW_UNROLL_BYTES)
{
const Byte *lim = p + size;
size &= CRC_HW_UNROLL_BYTES - 1;
lim -= size;
do
{
v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p));
v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p + sizeof(CRC_HW_WORD_TYPE)));
p += 2 * sizeof(CRC_HW_WORD_TYPE);
v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p));
v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p + sizeof(CRC_HW_WORD_TYPE)));
p += 2 * sizeof(CRC_HW_WORD_TYPE);
}
while (p != lim);
}
for (; size != 0; size--)
v = __crc32b(v, *p++);
return v;
}
#ifdef Z7_ARM_FEATURE_CRC32_WAS_SET
Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
#undef __ARM_FEATURE_CRC32
Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
#undef Z7_ARM_FEATURE_CRC32_WAS_SET
#endif
#endif // defined(Z7_CRC_HW_USE)
#endif // MY_CPU_LE
#ifndef Z7_CRC_HW_FORCE
#if defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME)
/*
typedef UInt32 (Z7_FASTCALL *Z7_CRC_UPDATE_WITH_TABLE_FUNC)
(UInt32 v, const void *data, size_t size, const UInt32 *table);
Z7_CRC_UPDATE_WITH_TABLE_FUNC g_CrcUpdate;
*/
static unsigned g_Crc_Algo;
#if (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
static unsigned g_Crc_Be;
#endif
#endif // defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME)
Z7_NO_INLINE
#ifdef Z7_CRC_HW_USE
static UInt32 Z7_FASTCALL CrcUpdate_Base
#else
UInt32 Z7_FASTCALL CrcUpdate
#endif
(UInt32 crc, const void *data, size_t size)
{
#if Z7_CRC_NUM_TABLES_USE == 1
return Z7_CRC_UPDATE_T1_FUNC_NAME(crc, data, size);
#else // Z7_CRC_NUM_TABLES_USE != 1
#ifdef Z7_CRC_UPDATE_T1_FUNC_NAME
if (g_Crc_Algo == 1)
return Z7_CRC_UPDATE_T1_FUNC_NAME(crc, data, size);
#endif
#ifdef MY_CPU_LE
return FUNC_NAME_LE(crc, data, size, g_CrcTable);
#elif defined(MY_CPU_BE)
return FUNC_NAME_BE(crc, data, size, g_CrcTable);
#else
if (g_Crc_Be)
return FUNC_NAME_BE(crc, data, size, g_CrcTable);
else
return FUNC_NAME_LE(crc, data, size, g_CrcTable);
#endif
#endif // Z7_CRC_NUM_TABLES_USE != 1
}
#ifdef Z7_CRC_HW_USE
Z7_NO_INLINE
UInt32 Z7_FASTCALL CrcUpdate(UInt32 crc, const void *data, size_t size)
{
if (g_Crc_Algo == 0)
return CrcUpdate_HW(crc, data, size);
return CrcUpdate_Base(crc, data, size);
}
#endif
#endif // !defined(Z7_CRC_HW_FORCE)
UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size)
{
return CrcUpdate(CRC_INIT_VAL, data, size) ^ CRC_INIT_VAL;
}
MY_ALIGN(64)
UInt32 g_CrcTable[256 * Z7_CRC_NUM_TABLES_TOTAL];
void Z7_FASTCALL CrcGenerateTable(void)
{
UInt32 i;
for (i = 0; i < 256; i++)
{
#if defined(Z7_CRC_HW_FORCE)
g_CrcTable[i] = __crc32b(i, 0);
#else
#define kCrcPoly 0xEDB88320
UInt32 r = i;
unsigned j;
for (j = 0; j < 8; j++)
r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
g_CrcTable[i] = r;
#endif
}
for (i = 256; i < 256 * Z7_CRC_NUM_TABLES_USE; i++)
{
const UInt32 r = g_CrcTable[(size_t)i - 256];
g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
}
#if !defined(Z7_CRC_HW_FORCE) && \
(defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME) || defined(MY_CPU_BE))
#if Z7_CRC_NUM_TABLES_USE <= 1
g_Crc_Algo = 1;
#else // Z7_CRC_NUM_TABLES_USE <= 1
#if defined(MY_CPU_LE)
g_Crc_Algo = Z7_CRC_NUM_TABLES_USE;
#else // !defined(MY_CPU_LE)
{
#ifndef MY_CPU_BE
UInt32 k = 0x01020304;
const Byte *p = (const Byte *)&k;
if (p[0] == 4 && p[1] == 3)
g_Crc_Algo = Z7_CRC_NUM_TABLES_USE;
else if (p[0] != 1 || p[1] != 2)
g_Crc_Algo = 1;
else
#endif // MY_CPU_BE
{
for (i = 256 * Z7_CRC_NUM_TABLES_TOTAL - 1; i >= 256; i--)
{
const UInt32 x = g_CrcTable[(size_t)i - 256];
g_CrcTable[i] = Z7_BSWAP32(x);
}
#if defined(Z7_CRC_UPDATE_T1_FUNC_NAME)
g_Crc_Algo = Z7_CRC_NUM_TABLES_USE;
#endif
#if (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
g_Crc_Be = 1;
#endif
}
}
#endif // !defined(MY_CPU_LE)
#ifdef MY_CPU_LE
#ifdef Z7_CRC_HW_USE
if (CPU_IsSupported_CRC32())
g_Crc_Algo = 0;
#endif // Z7_CRC_HW_USE
#endif // MY_CPU_LE
#endif // Z7_CRC_NUM_TABLES_USE <= 1
#endif // g_Crc_Algo was declared
}
Z7_CRC_UPDATE_FUNC z7_GetFunc_CrcUpdate(unsigned algo)
{
if (algo == 0)
return &CrcUpdate;
#if defined(Z7_CRC_HW_USE)
if (algo == sizeof(CRC_HW_WORD_TYPE) * 8)
{
#ifdef Z7_CRC_HW_FORCE
return &CrcUpdate;
#else
if (g_Crc_Algo == 0)
return &CrcUpdate_HW;
#endif
}
#endif
#ifndef Z7_CRC_HW_FORCE
if (algo == Z7_CRC_NUM_TABLES_USE)
return
#ifdef Z7_CRC_HW_USE
&CrcUpdate_Base;
#else
&CrcUpdate;
#endif
#endif
return NULL;
}
#undef kCrcPoly
#undef Z7_CRC_NUM_TABLES_USE
#undef Z7_CRC_NUM_TABLES_TOTAL
#undef CRC_UPDATE_BYTE_2
#undef FUNC_NAME_LE_2
#undef FUNC_NAME_LE_1
#undef FUNC_NAME_LE
#undef FUNC_NAME_BE_2
#undef FUNC_NAME_BE_1
#undef FUNC_NAME_BE
#undef CRC_HW_UNROLL_BYTES
#undef CRC_HW_WORD_FUNC
#undef CRC_HW_WORD_TYPE

View File

@@ -0,0 +1,28 @@
/* 7zCrc.h -- CRC32 calculation
2024-01-22 : Igor Pavlov : Public domain */
#ifndef ZIP7_INC_7Z_CRC_H
#define ZIP7_INC_7Z_CRC_H
#include "7zTypes.h"
EXTERN_C_BEGIN
extern UInt32 g_CrcTable[];
/* Call CrcGenerateTable one time before other CRC functions */
void Z7_FASTCALL CrcGenerateTable(void);
#define CRC_INIT_VAL 0xFFFFFFFF
#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
UInt32 Z7_FASTCALL CrcUpdate(UInt32 crc, const void *data, size_t size);
UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size);
typedef UInt32 (Z7_FASTCALL *Z7_CRC_UPDATE_FUNC)(UInt32 v, const void *data, size_t size);
Z7_CRC_UPDATE_FUNC z7_GetFunc_CrcUpdate(unsigned algo);
EXTERN_C_END
#endif

View File

@@ -0,0 +1,199 @@
/* 7zCrcOpt.c -- CRC32 calculation (optimized functions)
2023-12-07 : Igor Pavlov : Public domain */
#include "Precomp.h"
#include "CpuArch.h"
#if !defined(Z7_CRC_NUM_TABLES) || Z7_CRC_NUM_TABLES > 1
// for debug only : define Z7_CRC_DEBUG_BE to test big-endian code in little-endian cpu
// #define Z7_CRC_DEBUG_BE
#ifdef Z7_CRC_DEBUG_BE
#undef MY_CPU_LE
#define MY_CPU_BE
#endif
// the value Z7_CRC_NUM_TABLES_USE must be defined to same value as in 7zCrc.c
#ifdef Z7_CRC_NUM_TABLES
#define Z7_CRC_NUM_TABLES_USE Z7_CRC_NUM_TABLES
#else
#define Z7_CRC_NUM_TABLES_USE 12
#endif
#if Z7_CRC_NUM_TABLES_USE % 4 || \
Z7_CRC_NUM_TABLES_USE < 4 * 1 || \
Z7_CRC_NUM_TABLES_USE > 4 * 6
#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES
#endif
#ifndef MY_CPU_BE
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
#define Q(n, d) \
( (table + ((n) * 4 + 3) * 0x100)[(Byte)(d)] \
^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 1 * 8) & 0xFF] \
^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 2 * 8) & 0xFF] \
^ (table + ((n) * 4 + 0) * 0x100)[((d) >> 3 * 8)] )
#define R(a) *((const UInt32 *)(const void *)p + (a))
#define CRC_FUNC_PRE_LE2(step) \
UInt32 Z7_FASTCALL CrcUpdateT ## step (UInt32 v, const void *data, size_t size, const UInt32 *table)
#define CRC_FUNC_PRE_LE(step) \
CRC_FUNC_PRE_LE2(step); \
CRC_FUNC_PRE_LE2(step)
CRC_FUNC_PRE_LE(Z7_CRC_NUM_TABLES_USE)
{
const Byte *p = (const Byte *)data;
const Byte *lim;
for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC_NUM_TABLES_USE & 4))) != 0; size--, p++)
v = CRC_UPDATE_BYTE_2(v, *p);
lim = p + size;
if (size >= Z7_CRC_NUM_TABLES_USE)
{
lim -= Z7_CRC_NUM_TABLES_USE;
do
{
v ^= R(0);
{
#if Z7_CRC_NUM_TABLES_USE == 1 * 4
v = Q(0, v);
#else
#define U2(r, op) \
{ d = R(r); x op Q(Z7_CRC_NUM_TABLES_USE / 4 - 1 - (r), d); }
UInt32 d, x;
U2(1, =)
#if Z7_CRC_NUM_TABLES_USE >= 3 * 4
#define U(r) U2(r, ^=)
U(2)
#if Z7_CRC_NUM_TABLES_USE >= 4 * 4
U(3)
#if Z7_CRC_NUM_TABLES_USE >= 5 * 4
U(4)
#if Z7_CRC_NUM_TABLES_USE >= 6 * 4
U(5)
#if Z7_CRC_NUM_TABLES_USE >= 7 * 4
#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES
#endif
#endif
#endif
#endif
#endif
#undef U
#undef U2
v = x ^ Q(Z7_CRC_NUM_TABLES_USE / 4 - 1, v);
#endif
}
p += Z7_CRC_NUM_TABLES_USE;
}
while (p <= lim);
lim += Z7_CRC_NUM_TABLES_USE;
}
for (; p < lim; p++)
v = CRC_UPDATE_BYTE_2(v, *p);
return v;
}
#undef CRC_UPDATE_BYTE_2
#undef R
#undef Q
#undef CRC_FUNC_PRE_LE
#undef CRC_FUNC_PRE_LE2
#endif
#ifndef MY_CPU_LE
#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[((crc) >> 24) ^ (b)] ^ ((crc) << 8))
#define Q(n, d) \
( (table + ((n) * 4 + 0) * 0x100)[((d)) & 0xFF] \
^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 1 * 8) & 0xFF] \
^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 2 * 8) & 0xFF] \
^ (table + ((n) * 4 + 3) * 0x100)[((d) >> 3 * 8)] )
#ifdef Z7_CRC_DEBUG_BE
#define R(a) GetBe32a((const UInt32 *)(const void *)p + (a))
#else
#define R(a) *((const UInt32 *)(const void *)p + (a))
#endif
#define CRC_FUNC_PRE_BE2(step) \
UInt32 Z7_FASTCALL CrcUpdateT1_BeT ## step (UInt32 v, const void *data, size_t size, const UInt32 *table)
#define CRC_FUNC_PRE_BE(step) \
CRC_FUNC_PRE_BE2(step); \
CRC_FUNC_PRE_BE2(step)
CRC_FUNC_PRE_BE(Z7_CRC_NUM_TABLES_USE)
{
const Byte *p = (const Byte *)data;
const Byte *lim;
table += 0x100;
v = Z7_BSWAP32(v);
for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC_NUM_TABLES_USE & 4))) != 0; size--, p++)
v = CRC_UPDATE_BYTE_2_BE(v, *p);
lim = p + size;
if (size >= Z7_CRC_NUM_TABLES_USE)
{
lim -= Z7_CRC_NUM_TABLES_USE;
do
{
v ^= R(0);
{
#if Z7_CRC_NUM_TABLES_USE == 1 * 4
v = Q(0, v);
#else
#define U2(r, op) \
{ d = R(r); x op Q(Z7_CRC_NUM_TABLES_USE / 4 - 1 - (r), d); }
UInt32 d, x;
U2(1, =)
#if Z7_CRC_NUM_TABLES_USE >= 3 * 4
#define U(r) U2(r, ^=)
U(2)
#if Z7_CRC_NUM_TABLES_USE >= 4 * 4
U(3)
#if Z7_CRC_NUM_TABLES_USE >= 5 * 4
U(4)
#if Z7_CRC_NUM_TABLES_USE >= 6 * 4
U(5)
#if Z7_CRC_NUM_TABLES_USE >= 7 * 4
#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES
#endif
#endif
#endif
#endif
#endif
#undef U
#undef U2
v = x ^ Q(Z7_CRC_NUM_TABLES_USE / 4 - 1, v);
#endif
}
p += Z7_CRC_NUM_TABLES_USE;
}
while (p <= lim);
lim += Z7_CRC_NUM_TABLES_USE;
}
for (; p < lim; p++)
v = CRC_UPDATE_BYTE_2_BE(v, *p);
return Z7_BSWAP32(v);
}
#undef CRC_UPDATE_BYTE_2_BE
#undef R
#undef Q
#undef CRC_FUNC_PRE_BE
#undef CRC_FUNC_PRE_BE2
#endif
#undef Z7_CRC_NUM_TABLES_USE
#endif

View File

@@ -0,0 +1,672 @@
/* 7zDec.c -- Decoding from 7z folder
2024-03-01 : Igor Pavlov : Public domain */
#include "Precomp.h"
#include <string.h>
/* #define Z7_PPMD_SUPPORT */
#include "7z.h"
#include "7zCrc.h"
#include "Bcj2.h"
#include "Bra.h"
#include "CpuArch.h"
#include "Delta.h"
#include "LzmaDec.h"
#include "Lzma2Dec.h"
#ifdef Z7_PPMD_SUPPORT
#include "Ppmd7.h"
#endif
#define k_Copy 0
#ifndef Z7_NO_METHOD_LZMA2
#define k_LZMA2 0x21
#endif
#define k_LZMA 0x30101
#define k_BCJ2 0x303011B
#if !defined(Z7_NO_METHODS_FILTERS)
#define Z7_USE_BRANCH_FILTER
#endif
#if !defined(Z7_NO_METHODS_FILTERS) || \
defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARM64)
#define Z7_USE_FILTER_ARM64
#ifndef Z7_USE_BRANCH_FILTER
#define Z7_USE_BRANCH_FILTER
#endif
#define k_ARM64 0xa
#endif
#if !defined(Z7_NO_METHODS_FILTERS) || \
defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARMT)
#define Z7_USE_FILTER_ARMT
#ifndef Z7_USE_BRANCH_FILTER
#define Z7_USE_BRANCH_FILTER
#endif
#define k_ARMT 0x3030701
#endif
#ifndef Z7_NO_METHODS_FILTERS
#define k_Delta 3
#define k_RISCV 0xb
#define k_BCJ 0x3030103
#define k_PPC 0x3030205
#define k_IA64 0x3030401
#define k_ARM 0x3030501
#define k_SPARC 0x3030805
#endif
#ifdef Z7_PPMD_SUPPORT
#define k_PPMD 0x30401
typedef struct
{
IByteIn vt;
const Byte *cur;
const Byte *end;
const Byte *begin;
UInt64 processed;
BoolInt extra;
SRes res;
ILookInStreamPtr inStream;
} CByteInToLook;
static Byte ReadByte(IByteInPtr pp)
{
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteInToLook)
if (p->cur != p->end)
return *p->cur++;
if (p->res == SZ_OK)
{
size_t size = (size_t)(p->cur - p->begin);
p->processed += size;
p->res = ILookInStream_Skip(p->inStream, size);
size = (1 << 25);
p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size);
p->cur = p->begin;
p->end = p->begin + size;
if (size != 0)
return *p->cur++;
}
p->extra = True;
return 0;
}
static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
{
CPpmd7 ppmd;
CByteInToLook s;
SRes res = SZ_OK;
s.vt.Read = ReadByte;
s.inStream = inStream;
s.begin = s.end = s.cur = NULL;
s.extra = False;
s.res = SZ_OK;
s.processed = 0;
if (propsSize != 5)
return SZ_ERROR_UNSUPPORTED;
{
unsigned order = props[0];
UInt32 memSize = GetUi32(props + 1);
if (order < PPMD7_MIN_ORDER ||
order > PPMD7_MAX_ORDER ||
memSize < PPMD7_MIN_MEM_SIZE ||
memSize > PPMD7_MAX_MEM_SIZE)
return SZ_ERROR_UNSUPPORTED;
Ppmd7_Construct(&ppmd);
if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
return SZ_ERROR_MEM;
Ppmd7_Init(&ppmd, order);
}
{
ppmd.rc.dec.Stream = &s.vt;
if (!Ppmd7z_RangeDec_Init(&ppmd.rc.dec))
res = SZ_ERROR_DATA;
else if (!s.extra)
{
Byte *buf = outBuffer;
const Byte *lim = buf + outSize;
for (; buf != lim; buf++)
{
int sym = Ppmd7z_DecodeSymbol(&ppmd);
if (s.extra || sym < 0)
break;
*buf = (Byte)sym;
}
if (buf != lim)
res = SZ_ERROR_DATA;
else if (!Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec))
{
/* if (Ppmd7z_DecodeSymbol(&ppmd) != PPMD7_SYM_END || !Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) */
res = SZ_ERROR_DATA;
}
}
if (s.extra)
res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
else if (s.processed + (size_t)(s.cur - s.begin) != inSize)
res = SZ_ERROR_DATA;
}
Ppmd7_Free(&ppmd, allocMain);
return res;
}
#endif
static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
{
CLzmaDec state;
SRes res = SZ_OK;
LzmaDec_CONSTRUCT(&state)
RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain))
state.dic = outBuffer;
state.dicBufSize = outSize;
LzmaDec_Init(&state);
for (;;)
{
const void *inBuf = NULL;
size_t lookahead = (1 << 18);
if (lookahead > inSize)
lookahead = (size_t)inSize;
res = ILookInStream_Look(inStream, &inBuf, &lookahead);
if (res != SZ_OK)
break;
{
SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
ELzmaStatus status;
res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
lookahead -= inProcessed;
inSize -= inProcessed;
if (res != SZ_OK)
break;
if (status == LZMA_STATUS_FINISHED_WITH_MARK)
{
if (outSize != state.dicPos || inSize != 0)
res = SZ_ERROR_DATA;
break;
}
if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
break;
if (inProcessed == 0 && dicPos == state.dicPos)
{
res = SZ_ERROR_DATA;
break;
}
res = ILookInStream_Skip(inStream, inProcessed);
if (res != SZ_OK)
break;
}
}
LzmaDec_FreeProbs(&state, allocMain);
return res;
}
#ifndef Z7_NO_METHOD_LZMA2
static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
{
CLzma2Dec state;
SRes res = SZ_OK;
Lzma2Dec_CONSTRUCT(&state)
if (propsSize != 1)
return SZ_ERROR_DATA;
RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain))
state.decoder.dic = outBuffer;
state.decoder.dicBufSize = outSize;
Lzma2Dec_Init(&state);
for (;;)
{
const void *inBuf = NULL;
size_t lookahead = (1 << 18);
if (lookahead > inSize)
lookahead = (size_t)inSize;
res = ILookInStream_Look(inStream, &inBuf, &lookahead);
if (res != SZ_OK)
break;
{
SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
ELzmaStatus status;
res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
lookahead -= inProcessed;
inSize -= inProcessed;
if (res != SZ_OK)
break;
if (status == LZMA_STATUS_FINISHED_WITH_MARK)
{
if (outSize != state.decoder.dicPos || inSize != 0)
res = SZ_ERROR_DATA;
break;
}
if (inProcessed == 0 && dicPos == state.decoder.dicPos)
{
res = SZ_ERROR_DATA;
break;
}
res = ILookInStream_Skip(inStream, inProcessed);
if (res != SZ_OK)
break;
}
}
Lzma2Dec_FreeProbs(&state, allocMain);
return res;
}
#endif
static SRes SzDecodeCopy(UInt64 inSize, ILookInStreamPtr inStream, Byte *outBuffer)
{
while (inSize > 0)
{
const void *inBuf;
size_t curSize = (1 << 18);
if (curSize > inSize)
curSize = (size_t)inSize;
RINOK(ILookInStream_Look(inStream, &inBuf, &curSize))
if (curSize == 0)
return SZ_ERROR_INPUT_EOF;
memcpy(outBuffer, inBuf, curSize);
outBuffer += curSize;
inSize -= curSize;
RINOK(ILookInStream_Skip(inStream, curSize))
}
return SZ_OK;
}
static BoolInt IS_MAIN_METHOD(UInt32 m)
{
switch (m)
{
case k_Copy:
case k_LZMA:
#ifndef Z7_NO_METHOD_LZMA2
case k_LZMA2:
#endif
#ifdef Z7_PPMD_SUPPORT
case k_PPMD:
#endif
return True;
}
return False;
}
static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c)
{
return
c->NumStreams == 1
/* && c->MethodID <= (UInt32)0xFFFFFFFF */
&& IS_MAIN_METHOD((UInt32)c->MethodID);
}
#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)
static SRes CheckSupportedFolder(const CSzFolder *f)
{
if (f->NumCoders < 1 || f->NumCoders > 4)
return SZ_ERROR_UNSUPPORTED;
if (!IS_SUPPORTED_CODER(&f->Coders[0]))
return SZ_ERROR_UNSUPPORTED;
if (f->NumCoders == 1)
{
if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0)
return SZ_ERROR_UNSUPPORTED;
return SZ_OK;
}
#if defined(Z7_USE_BRANCH_FILTER)
if (f->NumCoders == 2)
{
const CSzCoderInfo *c = &f->Coders[1];
if (
/* c->MethodID > (UInt32)0xFFFFFFFF || */
c->NumStreams != 1
|| f->NumPackStreams != 1
|| f->PackStreams[0] != 0
|| f->NumBonds != 1
|| f->Bonds[0].InIndex != 1
|| f->Bonds[0].OutIndex != 0)
return SZ_ERROR_UNSUPPORTED;
switch ((UInt32)c->MethodID)
{
#if !defined(Z7_NO_METHODS_FILTERS)
case k_Delta:
case k_BCJ:
case k_PPC:
case k_IA64:
case k_SPARC:
case k_ARM:
case k_RISCV:
#endif
#ifdef Z7_USE_FILTER_ARM64
case k_ARM64:
#endif
#ifdef Z7_USE_FILTER_ARMT
case k_ARMT:
#endif
break;
default:
return SZ_ERROR_UNSUPPORTED;
}
return SZ_OK;
}
#endif
if (f->NumCoders == 4)
{
if (!IS_SUPPORTED_CODER(&f->Coders[1])
|| !IS_SUPPORTED_CODER(&f->Coders[2])
|| !IS_BCJ2(&f->Coders[3]))
return SZ_ERROR_UNSUPPORTED;
if (f->NumPackStreams != 4
|| f->PackStreams[0] != 2
|| f->PackStreams[1] != 6
|| f->PackStreams[2] != 1
|| f->PackStreams[3] != 0
|| f->NumBonds != 3
|| f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0
|| f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1
|| f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2)
return SZ_ERROR_UNSUPPORTED;
return SZ_OK;
}
return SZ_ERROR_UNSUPPORTED;
}
static SRes SzFolder_Decode2(const CSzFolder *folder,
const Byte *propsData,
const UInt64 *unpackSizes,
const UInt64 *packPositions,
ILookInStreamPtr inStream, UInt64 startPos,
Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain,
Byte *tempBuf[])
{
UInt32 ci;
SizeT tempSizes[3] = { 0, 0, 0};
SizeT tempSize3 = 0;
Byte *tempBuf3 = 0;
RINOK(CheckSupportedFolder(folder))
for (ci = 0; ci < folder->NumCoders; ci++)
{
const CSzCoderInfo *coder = &folder->Coders[ci];
if (IS_MAIN_METHOD((UInt32)coder->MethodID))
{
UInt32 si = 0;
UInt64 offset;
UInt64 inSize;
Byte *outBufCur = outBuffer;
SizeT outSizeCur = outSize;
if (folder->NumCoders == 4)
{
const UInt32 indices[] = { 3, 2, 0 };
const UInt64 unpackSize = unpackSizes[ci];
si = indices[ci];
if (ci < 2)
{
Byte *temp;
outSizeCur = (SizeT)unpackSize;
if (outSizeCur != unpackSize)
return SZ_ERROR_MEM;
temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur);
if (!temp && outSizeCur != 0)
return SZ_ERROR_MEM;
outBufCur = tempBuf[1 - ci] = temp;
tempSizes[1 - ci] = outSizeCur;
}
else if (ci == 2)
{
if (unpackSize > outSize) /* check it */
return SZ_ERROR_PARAM;
tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
tempSize3 = outSizeCur = (SizeT)unpackSize;
}
else
return SZ_ERROR_UNSUPPORTED;
}
offset = packPositions[si];
inSize = packPositions[(size_t)si + 1] - offset;
RINOK(LookInStream_SeekTo(inStream, startPos + offset))
if (coder->MethodID == k_Copy)
{
if (inSize != outSizeCur) /* check it */
return SZ_ERROR_DATA;
RINOK(SzDecodeCopy(inSize, inStream, outBufCur))
}
else if (coder->MethodID == k_LZMA)
{
RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
}
#ifndef Z7_NO_METHOD_LZMA2
else if (coder->MethodID == k_LZMA2)
{
RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
}
#endif
#ifdef Z7_PPMD_SUPPORT
else if (coder->MethodID == k_PPMD)
{
RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
}
#endif
else
return SZ_ERROR_UNSUPPORTED;
}
else if (coder->MethodID == k_BCJ2)
{
const UInt64 offset = packPositions[1];
const UInt64 s3Size = packPositions[2] - offset;
if (ci != 3)
return SZ_ERROR_UNSUPPORTED;
tempSizes[2] = (SizeT)s3Size;
if (tempSizes[2] != s3Size)
return SZ_ERROR_MEM;
tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]);
if (!tempBuf[2] && tempSizes[2] != 0)
return SZ_ERROR_MEM;
RINOK(LookInStream_SeekTo(inStream, startPos + offset))
RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2]))
if ((tempSizes[0] & 3) != 0 ||
(tempSizes[1] & 3) != 0 ||
tempSize3 + tempSizes[0] + tempSizes[1] != outSize)
return SZ_ERROR_DATA;
{
CBcj2Dec p;
p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3;
p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0];
p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1];
p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2];
p.dest = outBuffer;
p.destLim = outBuffer + outSize;
Bcj2Dec_Init(&p);
RINOK(Bcj2Dec_Decode(&p))
{
unsigned i;
for (i = 0; i < 4; i++)
if (p.bufs[i] != p.lims[i])
return SZ_ERROR_DATA;
if (p.dest != p.destLim || !Bcj2Dec_IsMaybeFinished(&p))
return SZ_ERROR_DATA;
}
}
}
#if defined(Z7_USE_BRANCH_FILTER)
else if (ci == 1)
{
#if !defined(Z7_NO_METHODS_FILTERS)
if (coder->MethodID == k_Delta)
{
if (coder->PropsSize != 1)
return SZ_ERROR_UNSUPPORTED;
{
Byte state[DELTA_STATE_SIZE];
Delta_Init(state);
Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize);
}
continue;
}
#endif
#ifdef Z7_USE_FILTER_ARM64
if (coder->MethodID == k_ARM64)
{
UInt32 pc = 0;
if (coder->PropsSize == 4)
{
pc = GetUi32(propsData + coder->PropsOffset);
if (pc & 3)
return SZ_ERROR_UNSUPPORTED;
}
else if (coder->PropsSize != 0)
return SZ_ERROR_UNSUPPORTED;
z7_BranchConv_ARM64_Dec(outBuffer, outSize, pc);
continue;
}
#endif
#if !defined(Z7_NO_METHODS_FILTERS)
if (coder->MethodID == k_RISCV)
{
UInt32 pc = 0;
if (coder->PropsSize == 4)
{
pc = GetUi32(propsData + coder->PropsOffset);
if (pc & 1)
return SZ_ERROR_UNSUPPORTED;
}
else if (coder->PropsSize != 0)
return SZ_ERROR_UNSUPPORTED;
z7_BranchConv_RISCV_Dec(outBuffer, outSize, pc);
continue;
}
#endif
#if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT)
{
if (coder->PropsSize != 0)
return SZ_ERROR_UNSUPPORTED;
#define CASE_BRA_CONV(isa) case k_ ## isa: Z7_BRANCH_CONV_DEC(isa)(outBuffer, outSize, 0); break; // pc = 0;
switch (coder->MethodID)
{
#if !defined(Z7_NO_METHODS_FILTERS)
case k_BCJ:
{
UInt32 state = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL;
z7_BranchConvSt_X86_Dec(outBuffer, outSize, 0, &state); // pc = 0
break;
}
case k_PPC: Z7_BRANCH_CONV_DEC_2(BranchConv_PPC)(outBuffer, outSize, 0); break; // pc = 0;
// CASE_BRA_CONV(PPC)
CASE_BRA_CONV(IA64)
CASE_BRA_CONV(SPARC)
CASE_BRA_CONV(ARM)
#endif
#if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT)
CASE_BRA_CONV(ARMT)
#endif
default:
return SZ_ERROR_UNSUPPORTED;
}
continue;
}
#endif
} // (c == 1)
#endif // Z7_USE_BRANCH_FILTER
else
return SZ_ERROR_UNSUPPORTED;
}
return SZ_OK;
}
SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
ILookInStreamPtr inStream, UInt64 startPos,
Byte *outBuffer, size_t outSize,
ISzAllocPtr allocMain)
{
SRes res;
CSzFolder folder;
CSzData sd;
const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
sd.Data = data;
sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex];
res = SzGetNextFolderItem(&folder, &sd);
if (res != SZ_OK)
return res;
if (sd.Size != 0
|| folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex]
|| outSize != SzAr_GetFolderUnpackSize(p, folderIndex))
return SZ_ERROR_FAIL;
{
unsigned i;
Byte *tempBuf[3] = { 0, 0, 0};
res = SzFolder_Decode2(&folder, data,
&p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]],
p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
inStream, startPos,
outBuffer, (SizeT)outSize, allocMain, tempBuf);
for (i = 0; i < 3; i++)
ISzAlloc_Free(allocMain, tempBuf[i]);
if (res == SZ_OK)
if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex))
if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex])
res = SZ_ERROR_CRC;
return res;
}
}

View File

@@ -0,0 +1,443 @@
/* 7zFile.c -- File IO
2023-04-02 : Igor Pavlov : Public domain */
#include "Precomp.h"
#include "7zFile.h"
#ifndef USE_WINDOWS_FILE
#include <errno.h>
#ifndef USE_FOPEN
#include <stdio.h>
#include <fcntl.h>
#ifdef _WIN32
#include <io.h>
typedef int ssize_t;
typedef int off_t;
#else
#include <unistd.h>
#endif
#endif
#else
/*
ReadFile and WriteFile functions in Windows have BUG:
If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
(Insufficient system resources exist to complete the requested service).
Probably in some version of Windows there are problems with other sizes:
for 32 MB (maybe also for 16 MB).
And message can be "Network connection was lost"
*/
#endif
#define kChunkSizeMax (1 << 22)
void File_Construct(CSzFile *p)
{
#ifdef USE_WINDOWS_FILE
p->handle = INVALID_HANDLE_VALUE;
#elif defined(USE_FOPEN)
p->file = NULL;
#else
p->fd = -1;
#endif
}
#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
static WRes File_Open(CSzFile *p, const char *name, int writeMode)
{
#ifdef USE_WINDOWS_FILE
p->handle = CreateFileA(name,
writeMode ? GENERIC_WRITE : GENERIC_READ,
FILE_SHARE_READ, NULL,
writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
#elif defined(USE_FOPEN)
p->file = fopen(name, writeMode ? "wb+" : "rb");
return (p->file != 0) ? 0 :
#ifdef UNDER_CE
2; /* ENOENT */
#else
errno;
#endif
#else
int flags = (writeMode ? (O_CREAT | O_EXCL | O_WRONLY) : O_RDONLY);
#ifdef O_BINARY
flags |= O_BINARY;
#endif
p->fd = open(name, flags, 0666);
return (p->fd != -1) ? 0 : errno;
#endif
}
WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
WRes OutFile_Open(CSzFile *p, const char *name)
{
#if defined(USE_WINDOWS_FILE) || defined(USE_FOPEN)
return File_Open(p, name, 1);
#else
p->fd = creat(name, 0666);
return (p->fd != -1) ? 0 : errno;
#endif
}
#endif
#ifdef USE_WINDOWS_FILE
static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode)
{
p->handle = CreateFileW(name,
writeMode ? GENERIC_WRITE : GENERIC_READ,
FILE_SHARE_READ, NULL,
writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
}
WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); }
WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); }
#endif
WRes File_Close(CSzFile *p)
{
#ifdef USE_WINDOWS_FILE
if (p->handle != INVALID_HANDLE_VALUE)
{
if (!CloseHandle(p->handle))
return GetLastError();
p->handle = INVALID_HANDLE_VALUE;
}
#elif defined(USE_FOPEN)
if (p->file != NULL)
{
int res = fclose(p->file);
if (res != 0)
{
if (res == EOF)
return errno;
return res;
}
p->file = NULL;
}
#else
if (p->fd != -1)
{
if (close(p->fd) != 0)
return errno;
p->fd = -1;
}
#endif
return 0;
}
WRes File_Read(CSzFile *p, void *data, size_t *size)
{
size_t originalSize = *size;
*size = 0;
if (originalSize == 0)
return 0;
#ifdef USE_WINDOWS_FILE
do
{
const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
DWORD processed = 0;
const BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
data = (void *)((Byte *)data + processed);
originalSize -= processed;
*size += processed;
if (!res)
return GetLastError();
// debug : we can break here for partial reading mode
if (processed == 0)
break;
}
while (originalSize > 0);
#elif defined(USE_FOPEN)
do
{
const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
const size_t processed = fread(data, 1, curSize, p->file);
data = (void *)((Byte *)data + (size_t)processed);
originalSize -= processed;
*size += processed;
if (processed != curSize)
return ferror(p->file);
// debug : we can break here for partial reading mode
if (processed == 0)
break;
}
while (originalSize > 0);
#else
do
{
const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
const ssize_t processed = read(p->fd, data, curSize);
if (processed == -1)
return errno;
if (processed == 0)
break;
data = (void *)((Byte *)data + (size_t)processed);
originalSize -= (size_t)processed;
*size += (size_t)processed;
// debug : we can break here for partial reading mode
// break;
}
while (originalSize > 0);
#endif
return 0;
}
WRes File_Write(CSzFile *p, const void *data, size_t *size)
{
size_t originalSize = *size;
*size = 0;
if (originalSize == 0)
return 0;
#ifdef USE_WINDOWS_FILE
do
{
const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
DWORD processed = 0;
const BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
data = (const void *)((const Byte *)data + processed);
originalSize -= processed;
*size += processed;
if (!res)
return GetLastError();
if (processed == 0)
break;
}
while (originalSize > 0);
#elif defined(USE_FOPEN)
do
{
const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
const size_t processed = fwrite(data, 1, curSize, p->file);
data = (void *)((Byte *)data + (size_t)processed);
originalSize -= processed;
*size += processed;
if (processed != curSize)
return ferror(p->file);
if (processed == 0)
break;
}
while (originalSize > 0);
#else
do
{
const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
const ssize_t processed = write(p->fd, data, curSize);
if (processed == -1)
return errno;
if (processed == 0)
break;
data = (const void *)((const Byte *)data + (size_t)processed);
originalSize -= (size_t)processed;
*size += (size_t)processed;
}
while (originalSize > 0);
#endif
return 0;
}
WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
{
#ifdef USE_WINDOWS_FILE
DWORD moveMethod;
UInt32 low = (UInt32)*pos;
LONG high = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
// (int) to eliminate clang warning
switch ((int)origin)
{
case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break;
case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break;
case SZ_SEEK_END: moveMethod = FILE_END; break;
default: return ERROR_INVALID_PARAMETER;
}
low = SetFilePointer(p->handle, (LONG)low, &high, moveMethod);
if (low == (UInt32)0xFFFFFFFF)
{
WRes res = GetLastError();
if (res != NO_ERROR)
return res;
}
*pos = ((Int64)high << 32) | low;
return 0;
#else
int moveMethod; // = origin;
switch ((int)origin)
{
case SZ_SEEK_SET: moveMethod = SEEK_SET; break;
case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break;
case SZ_SEEK_END: moveMethod = SEEK_END; break;
default: return EINVAL;
}
#if defined(USE_FOPEN)
{
int res = fseek(p->file, (long)*pos, moveMethod);
if (res == -1)
return errno;
*pos = ftell(p->file);
if (*pos == -1)
return errno;
return 0;
}
#else
{
off_t res = lseek(p->fd, (off_t)*pos, moveMethod);
if (res == -1)
return errno;
*pos = res;
return 0;
}
#endif // USE_FOPEN
#endif // USE_WINDOWS_FILE
}
WRes File_GetLength(CSzFile *p, UInt64 *length)
{
#ifdef USE_WINDOWS_FILE
DWORD sizeHigh;
DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
if (sizeLow == 0xFFFFFFFF)
{
DWORD res = GetLastError();
if (res != NO_ERROR)
return res;
}
*length = (((UInt64)sizeHigh) << 32) + sizeLow;
return 0;
#elif defined(USE_FOPEN)
long pos = ftell(p->file);
int res = fseek(p->file, 0, SEEK_END);
*length = ftell(p->file);
fseek(p->file, pos, SEEK_SET);
return res;
#else
off_t pos;
*length = 0;
pos = lseek(p->fd, 0, SEEK_CUR);
if (pos != -1)
{
const off_t len2 = lseek(p->fd, 0, SEEK_END);
const off_t res2 = lseek(p->fd, pos, SEEK_SET);
if (len2 != -1)
{
*length = (UInt64)len2;
if (res2 != -1)
return 0;
}
}
return errno;
#endif
}
/* ---------- FileSeqInStream ---------- */
static SRes FileSeqInStream_Read(ISeqInStreamPtr pp, void *buf, size_t *size)
{
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileSeqInStream)
const WRes wres = File_Read(&p->file, buf, size);
p->wres = wres;
return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
}
void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
{
p->vt.Read = FileSeqInStream_Read;
}
/* ---------- FileInStream ---------- */
static SRes FileInStream_Read(ISeekInStreamPtr pp, void *buf, size_t *size)
{
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream)
const WRes wres = File_Read(&p->file, buf, size);
p->wres = wres;
return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
}
static SRes FileInStream_Seek(ISeekInStreamPtr pp, Int64 *pos, ESzSeek origin)
{
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream)
const WRes wres = File_Seek(&p->file, pos, origin);
p->wres = wres;
return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
}
void FileInStream_CreateVTable(CFileInStream *p)
{
p->vt.Read = FileInStream_Read;
p->vt.Seek = FileInStream_Seek;
}
/* ---------- FileOutStream ---------- */
static size_t FileOutStream_Write(ISeqOutStreamPtr pp, const void *data, size_t size)
{
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileOutStream)
const WRes wres = File_Write(&p->file, data, &size);
p->wres = wres;
return size;
}
void FileOutStream_CreateVTable(CFileOutStream *p)
{
p->vt.Write = FileOutStream_Write;
}

View File

@@ -0,0 +1,92 @@
/* 7zFile.h -- File IO
2023-03-05 : Igor Pavlov : Public domain */
#ifndef ZIP7_INC_FILE_H
#define ZIP7_INC_FILE_H
#ifdef _WIN32
#define USE_WINDOWS_FILE
// #include <windows.h>
#endif
#ifdef USE_WINDOWS_FILE
#include "7zWindows.h"
#else
// note: USE_FOPEN mode is limited to 32-bit file size
// #define USE_FOPEN
// #include <stdio.h>
#endif
#include "7zTypes.h"
EXTERN_C_BEGIN
/* ---------- File ---------- */
typedef struct
{
#ifdef USE_WINDOWS_FILE
HANDLE handle;
#elif defined(USE_FOPEN)
FILE *file;
#else
int fd;
#endif
} CSzFile;
void File_Construct(CSzFile *p);
#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
WRes InFile_Open(CSzFile *p, const char *name);
WRes OutFile_Open(CSzFile *p, const char *name);
#endif
#ifdef USE_WINDOWS_FILE
WRes InFile_OpenW(CSzFile *p, const WCHAR *name);
WRes OutFile_OpenW(CSzFile *p, const WCHAR *name);
#endif
WRes File_Close(CSzFile *p);
/* reads max(*size, remain file's size) bytes */
WRes File_Read(CSzFile *p, void *data, size_t *size);
/* writes *size bytes */
WRes File_Write(CSzFile *p, const void *data, size_t *size);
WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin);
WRes File_GetLength(CSzFile *p, UInt64 *length);
/* ---------- FileInStream ---------- */
typedef struct
{
ISeqInStream vt;
CSzFile file;
WRes wres;
} CFileSeqInStream;
void FileSeqInStream_CreateVTable(CFileSeqInStream *p);
typedef struct
{
ISeekInStream vt;
CSzFile file;
WRes wres;
} CFileInStream;
void FileInStream_CreateVTable(CFileInStream *p);
typedef struct
{
ISeqOutStream vt;
CSzFile file;
WRes wres;
} CFileOutStream;
void FileOutStream_CreateVTable(CFileOutStream *p);
EXTERN_C_END
#endif

View File

@@ -0,0 +1,199 @@
/* 7zStream.c -- 7z Stream functions
2023-04-02 : Igor Pavlov : Public domain */
#include "Precomp.h"
#include <string.h>
#include "7zTypes.h"
SRes SeqInStream_ReadMax(ISeqInStreamPtr stream, void *buf, size_t *processedSize)
{
size_t size = *processedSize;
*processedSize = 0;
while (size != 0)
{
size_t cur = size;
const SRes res = ISeqInStream_Read(stream, buf, &cur);
*processedSize += cur;
buf = (void *)((Byte *)buf + cur);
size -= cur;
if (res != SZ_OK)
return res;
if (cur == 0)
return SZ_OK;
}
return SZ_OK;
}
/*
SRes SeqInStream_Read2(ISeqInStreamPtr stream, void *buf, size_t size, SRes errorType)
{
while (size != 0)
{
size_t processed = size;
RINOK(ISeqInStream_Read(stream, buf, &processed))
if (processed == 0)
return errorType;
buf = (void *)((Byte *)buf + processed);
size -= processed;
}
return SZ_OK;
}
SRes SeqInStream_Read(ISeqInStreamPtr stream, void *buf, size_t size)
{
return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
}
*/
SRes SeqInStream_ReadByte(ISeqInStreamPtr stream, Byte *buf)
{
size_t processed = 1;
RINOK(ISeqInStream_Read(stream, buf, &processed))
return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF;
}
SRes LookInStream_SeekTo(ILookInStreamPtr stream, UInt64 offset)
{
Int64 t = (Int64)offset;
return ILookInStream_Seek(stream, &t, SZ_SEEK_SET);
}
SRes LookInStream_LookRead(ILookInStreamPtr stream, void *buf, size_t *size)
{
const void *lookBuf;
if (*size == 0)
return SZ_OK;
RINOK(ILookInStream_Look(stream, &lookBuf, size))
memcpy(buf, lookBuf, *size);
return ILookInStream_Skip(stream, *size);
}
SRes LookInStream_Read2(ILookInStreamPtr stream, void *buf, size_t size, SRes errorType)
{
while (size != 0)
{
size_t processed = size;
RINOK(ILookInStream_Read(stream, buf, &processed))
if (processed == 0)
return errorType;
buf = (void *)((Byte *)buf + processed);
size -= processed;
}
return SZ_OK;
}
SRes LookInStream_Read(ILookInStreamPtr stream, void *buf, size_t size)
{
return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
}
#define GET_LookToRead2 Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLookToRead2)
static SRes LookToRead2_Look_Lookahead(ILookInStreamPtr pp, const void **buf, size_t *size)
{
SRes res = SZ_OK;
GET_LookToRead2
size_t size2 = p->size - p->pos;
if (size2 == 0 && *size != 0)
{
p->pos = 0;
p->size = 0;
size2 = p->bufSize;
res = ISeekInStream_Read(p->realStream, p->buf, &size2);
p->size = size2;
}
if (*size > size2)
*size = size2;
*buf = p->buf + p->pos;
return res;
}
static SRes LookToRead2_Look_Exact(ILookInStreamPtr pp, const void **buf, size_t *size)
{
SRes res = SZ_OK;
GET_LookToRead2
size_t size2 = p->size - p->pos;
if (size2 == 0 && *size != 0)
{
p->pos = 0;
p->size = 0;
if (*size > p->bufSize)
*size = p->bufSize;
res = ISeekInStream_Read(p->realStream, p->buf, size);
size2 = p->size = *size;
}
if (*size > size2)
*size = size2;
*buf = p->buf + p->pos;
return res;
}
static SRes LookToRead2_Skip(ILookInStreamPtr pp, size_t offset)
{
GET_LookToRead2
p->pos += offset;
return SZ_OK;
}
static SRes LookToRead2_Read(ILookInStreamPtr pp, void *buf, size_t *size)
{
GET_LookToRead2
size_t rem = p->size - p->pos;
if (rem == 0)
return ISeekInStream_Read(p->realStream, buf, size);
if (rem > *size)
rem = *size;
memcpy(buf, p->buf + p->pos, rem);
p->pos += rem;
*size = rem;
return SZ_OK;
}
static SRes LookToRead2_Seek(ILookInStreamPtr pp, Int64 *pos, ESzSeek origin)
{
GET_LookToRead2
p->pos = p->size = 0;
return ISeekInStream_Seek(p->realStream, pos, origin);
}
void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead)
{
p->vt.Look = lookahead ?
LookToRead2_Look_Lookahead :
LookToRead2_Look_Exact;
p->vt.Skip = LookToRead2_Skip;
p->vt.Read = LookToRead2_Read;
p->vt.Seek = LookToRead2_Seek;
}
static SRes SecToLook_Read(ISeqInStreamPtr pp, void *buf, size_t *size)
{
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSecToLook)
return LookInStream_LookRead(p->realStream, buf, size);
}
void SecToLook_CreateVTable(CSecToLook *p)
{
p->vt.Read = SecToLook_Read;
}
static SRes SecToRead_Read(ISeqInStreamPtr pp, void *buf, size_t *size)
{
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSecToRead)
return ILookInStream_Read(p->realStream, buf, size);
}
void SecToRead_CreateVTable(CSecToRead *p)
{
p->vt.Read = SecToRead_Read;
}

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