mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-10-22 09:19:08 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1557422f15 |
Vendored
+283
-293
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+335
-340
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
Vendored
+278
-288
File diff suppressed because it is too large
Load Diff
@@ -696,7 +696,7 @@
|
||||
<string name="control_stick">عصا التحكم</string>
|
||||
<string name="right_stick">العصا اليمنى</string>
|
||||
<string name="c_stick">عصا-C</string>
|
||||
<string name="pressed">مضغوط</string>
|
||||
<string name="pressed">ضغط العصا</string>
|
||||
<string name="range">النطاق</string>
|
||||
<string name="deadzone">المنطقة الميتة</string>
|
||||
<string name="modifier">معدل</string>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
<string name="input_overlay_options">虛擬按鍵設定</string>
|
||||
<string name="input_overlay_options_description">調整虛擬按鍵的位置與顯示設定</string>
|
||||
<string name="edit_overlay_layout">編輯虛擬按鍵</string>
|
||||
<string name="edit_overlay_layout">調整虛擬按鍵</string>
|
||||
<string name="edit_overlay_layout_description">調整虛擬按鍵的位置和大小</string>
|
||||
|
||||
|
||||
@@ -253,8 +253,8 @@
|
||||
<string name="install_firmware_warning">跳過安裝韌體?</string>
|
||||
<string name="emulator_data">設定模擬器資料</string>
|
||||
<string name="emulator_data_description">模擬器需要金鑰才能正常執行,同時建議安裝韌體以啟動 QLaunch 小程式</string>
|
||||
<string name="permissions">授予權限</string>
|
||||
<string name="permissions_description">授予權限以使用模擬器的特定功能</string>
|
||||
<string name="permissions">授予通知權限</string>
|
||||
<string name="permissions_description">授予 Eden 傳送通知的權限以使用模擬器的特定功能</string>
|
||||
<string name="install_firmware_warning_description">許多遊戲需要韌體才能正常運作</string>
|
||||
<string name="install_firmware_warning_help">https://yuzu-mirror.github.io/help/quickstart/#guide-introduction</string>
|
||||
<string name="notifications">通知</string>
|
||||
@@ -268,8 +268,8 @@
|
||||
<string name="device_manufacturer">製造商</string>
|
||||
<string name="device_model">型號</string>
|
||||
<string name="product">型號代碼</string>
|
||||
<string name="android_version">安卓版本</string>
|
||||
<string name="android_security_patch">安卓安全性修補程式等級</string>
|
||||
<string name="android_version">Android 版本</string>
|
||||
<string name="android_security_patch">Android 安全性修補程式等級</string>
|
||||
<string name="build_id">版本號碼</string>
|
||||
<string name="general_information">基本資訊</string>
|
||||
<string name="hardware">硬體</string>
|
||||
@@ -287,7 +287,7 @@
|
||||
<string name="warning_skip">跳過</string>
|
||||
<string name="warning_cancel">取消</string>
|
||||
<string name="install_amiibo_keys">安裝 Amiibo 金鑰</string>
|
||||
<string name="install_amiibo_keys_description">需要先安裝才能在遊戲中使用 Amiibo</string>
|
||||
<string name="install_amiibo_keys_description">安裝 Amiibo 以在日後遊玩時使用</string>
|
||||
<string name="gpu_driver_fetcher">GPU 驅動程式下載器</string>
|
||||
<string name="gpu_driver_manager">GPU 驅動程式管理員</string>
|
||||
<string name="install_gpu_driver_description">安裝替代驅動程式以取得潛在的更佳效能或準確度</string>
|
||||
@@ -417,17 +417,17 @@
|
||||
<string name="custom_driver_not_supported">您的裝置不支援自訂驅動程式</string>
|
||||
<string name="custom_driver_not_supported_description">此裝置不支援注入自訂驅動程式\n請以後再來查看是否已新增支援!</string>
|
||||
<string name="manage_yuzu_data">管理 Eden 資料</string>
|
||||
<string name="manage_yuzu_data_description">安裝韌體、金鑰,導入/導出使用者資料及安裝其它項目!</string>
|
||||
<string name="manage_yuzu_data_description">安裝韌體、金鑰,匯入/匯出使用者資料及安裝其它項目!</string>
|
||||
<string name="game_folders">遊戲資料夾</string>
|
||||
<string name="deep_scan">深度掃描</string>
|
||||
<string name="add_game_folder">新增遊戲資料夾</string>
|
||||
<string name="folder_already_added">這個資料夾已經新增過了!</string>
|
||||
<string name="game_folder_properties">遊戲資料夾設定</string>
|
||||
<plurals name="saves_import_failed">
|
||||
<item quantity="other">%d 個存檔導入失敗</item>
|
||||
<item quantity="other">%d 個存檔匯入失敗</item>
|
||||
</plurals>
|
||||
<plurals name="saves_import_success">
|
||||
<item quantity="other">成功導入 %d 個存檔</item>
|
||||
<item quantity="other">成功匯入 %d 個存檔</item>
|
||||
</plurals>
|
||||
<string name="no_save_data_found">找不到儲存資料</string>
|
||||
<string name="verify_installed_content">驗證已安裝內容的完整性</string>
|
||||
@@ -578,9 +578,9 @@
|
||||
<string name="skip_cpu_inner_invalidation">跳過 CPU 內部失效處理</string>
|
||||
<string name="skip_cpu_inner_invalidation_description">在記憶體更新期間跳過某些 CPU 端快取的失效處理,減少 CPU 使用率並提高其性能。可能會導致某些遊戲出現故障或當機</string>
|
||||
<string name="nce_invalidation_gpu_readback">在 NCE 無效化前進行 GPU 回讀</string>
|
||||
<string name="nce_invalidation_gpu_readback_description">(暫時性功能)修復 \"終結者瑪格諾莉亞:霧中綻放\" 及其它使用虛幻引擎之遊戲中的當機問題,可能會降低效能。此功能正在改善中</string>
|
||||
<string name="nce_invalidation_gpu_readback_description">(暫時性功能)修復《終結者瑪格諾莉亞:霧中綻放》及其它使用虛幻引擎之遊戲中的當機問題,可能會降低效能。此功能正在改善中</string>
|
||||
<string name="fix_bloom_effects">修正光暈特效</string>
|
||||
<string name="fix_bloom_effects_description">在 \"薩爾達傳說:織夢島\" 和 \"薩爾達傳說:智慧的再現\" 中減少光暈模糊的問題並移除 \"橫衝直撞:狂飆樂園重製版\" 中的光暈效果(適用於 Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string>
|
||||
<string name="fix_bloom_effects_description">在《薩爾達傳說:織夢島》和《薩爾達傳說:智慧的再現》中減少光暈模糊的問題並移除《橫衝直撞:狂飆樂園重製版》中的光暈效果(適用於 Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string>
|
||||
<string name="emulate_bgr565">模擬 BGR565</string>
|
||||
<string name="emulate_bgr565_description">修正遊戲中出現的色彩反轉、圖形異常或陰影異常</string>
|
||||
<string name="rescale_hack">啟用舊版重新縮放處理</string>
|
||||
@@ -603,7 +603,7 @@
|
||||
<string name="extensions">擴充功能</string>
|
||||
|
||||
<string name="dyna_state">擴展動態狀態</string>
|
||||
<string name="dyna_state_description">控制擴展動態狀態中可使用的功能數量,較高的數值可根據驅動程式支援的動態狀態減少管線編譯的次數</string>
|
||||
<string name="dyna_state_description">控制 Vulkan 擴展動態狀態中可使用的功能數量,較高的數值可根據驅動程式支援的動態狀態減少管線編譯的次數</string>
|
||||
<string name="disabled">停用</string>
|
||||
<string name="vertex_input_dynamic_state">頂點輸入動態狀態</string>
|
||||
<string name="vertex_input_dynamic_state_description">啟用此功能可提供更彈性的頂點輸入處理方式,並可能減少頂點/緩衝區的管線編譯時間</string>
|
||||
@@ -808,7 +808,7 @@
|
||||
<string name="recommended_driver">推薦驅動程式:</string>
|
||||
<string name="gpu_model">GPU 型號</string>
|
||||
<string name="unsupported_gpu">不支援的 GPU</string>
|
||||
<string name="unsupported_gpu_warning">您的 GPU 不支援驅動程式注入,不建議嘗試設定自訂驅動程式</string>
|
||||
<string name="unsupported_gpu_warning">您的 GPU 不支援驅動程式注入,不建議嘗試安裝自訂驅動程式</string>
|
||||
|
||||
<!-- Preferences Screen -->
|
||||
<string name="preferences_settings">設定</string>
|
||||
@@ -892,7 +892,7 @@
|
||||
<string name="select_content_type">內容類型</string>
|
||||
<string name="updates_and_dlc">更新及 DLC</string>
|
||||
<string name="mods_and_cheats">模組及金手指</string>
|
||||
<string name="addon_notice">重要的˙附加元件通知</string>
|
||||
<string name="addon_notice">注意!</string>
|
||||
<!-- \"cheats/" "romfs/" and \"exefs/ should not be translated -->
|
||||
<string name="addon_notice_description">若要安裝模組及金手指,您必須選擇一個包含 cheats/、romfs/ 或 exefs/ 的目錄。我們無法驗證這些內容是否與您的遊戲相容,所以請謹慎安裝!</string>
|
||||
<string name="invalid_directory">無效的目錄</string>
|
||||
@@ -981,7 +981,7 @@
|
||||
<string name="emulation_pause">暫停模擬</string>
|
||||
<string name="emulation_unpause">繼續模擬</string>
|
||||
<string name="emulation_input_overlay">疊加層/虛擬按鍵設定</string>
|
||||
<string name="load_amiibo">導入 Amiibo</string>
|
||||
<string name="load_amiibo">匯入 Amiibo</string>
|
||||
<string name="touchscreen">觸控螢幕</string>
|
||||
<string name="lock_drawer">鎖定側邊選單</string>
|
||||
<string name="unlock_drawer">解鎖側邊選單</string>
|
||||
@@ -1128,6 +1128,16 @@
|
||||
<string name="freedreno_clear_all">全部清除</string>
|
||||
<string name="freedreno_saved">Freedreno 設定已儲存</string>
|
||||
<string name="freedreno_cleared_all">已清除所有 Freedreno 變數</string>
|
||||
<string name="freedreno_variable_added">變數 %1$s 已新增</string>
|
||||
<string name="freedreno_preset_applied">設定檔 \"%1$s\" 已套用</string>
|
||||
<string name="freedreno_error_empty_name">變數名稱不可空白</string>
|
||||
<string name="freedreno_error_setting_variable">變數設定失敗</string>
|
||||
<string name="freedreno_info_title">關於 Freedreno 設定</string>
|
||||
<string name="freedreno_info_description">透過調整 Freedreno/Turnip GPU 驅動程式的設定來偵錯、分析和最佳化效能,會自動儲存變更。詳情請參閱 https://docs.mesa3d.org/drivers/freedreno.html</string>
|
||||
<string name="freedreno_per_game_title">Freedreno 設定</string>
|
||||
<string name="freedreno_per_game_description">調整此遊戲的 GPU 驅動程式設定</string>
|
||||
<string name="freedreno_per_game_saved">Freedreno 設定已儲存</string>
|
||||
|
||||
<!-- Gamepad Buttons -->
|
||||
<string name="gamepad_d_pad">方向鍵</string>
|
||||
<string name="gamepad_left_stick">左搖桿</string>
|
||||
@@ -1136,14 +1146,17 @@
|
||||
<string name="gamepad_screenshot">螢幕截圖</string>
|
||||
|
||||
<!-- Disk shader cache -->
|
||||
<string name="building_shaders">正在建置著色器</string>
|
||||
<string name="building_shaders">正在編譯著色器</string>
|
||||
|
||||
<!-- App options -->
|
||||
<string name="change_app_theme">變更應用程式主題</string>
|
||||
<string name="theme_default">預設</string>
|
||||
<string name="theme_material_you">質感設計3</string>
|
||||
<string name="app_settings">Eden介面設定</string>
|
||||
<string name="theme_material_you">Material You</string>
|
||||
<string name="app_settings">Eden 介面設定</string>
|
||||
<string name="theme_and_color">主題和顏色</string>
|
||||
<string name="fullscreen_mode">全螢幕模式</string>
|
||||
<string name="fullscreen_mode_description">在使用 Eden 時隱藏 Android 系統的導覽列,在直向時從螢幕底部往上滑以暫時顯示它們;橫向時則從螢幕側邊往內滑動</string>
|
||||
|
||||
<!-- Theme Modes -->
|
||||
<string name="change_theme_mode">變更主題模式</string>
|
||||
<string name="theme_mode_follow_system">跟隨系統</string>
|
||||
@@ -1152,18 +1165,26 @@
|
||||
|
||||
<!-- Black backgrounds theme -->
|
||||
<string name="use_black_backgrounds">黑色背景</string>
|
||||
<string name="use_black_backgrounds_description">使用深色主題時,套用黑色背景。</string>
|
||||
<string name="use_black_backgrounds_description">使用深色主題時套用黑色背景</string>
|
||||
|
||||
<!-- Buttons -->
|
||||
<string name="enable_folder_button">遊戲資料夾</string>
|
||||
<string name="enable_folder_button_description">在 Eden 首頁顯示新增遊戲資料夾的按鈕</string>
|
||||
<string name="enable_qlaunch_button">QLaunch</string>
|
||||
<string name="enable_qlaunch_button_description">在 Eden 首頁顯示 QLaunch 按鈕</string>
|
||||
|
||||
<!-- App Language -->
|
||||
<string name="app_language">語言</string>
|
||||
<string name="app_language_description">選擇Eden顯示的語言</string>
|
||||
<string name="app_language_description">選擇 Eden 顯示的語言</string>
|
||||
<string name="app_language_system">跟隨系統</string>
|
||||
<!-- Static Themes -->
|
||||
<string name="static_theme_color">主題色彩</string>
|
||||
<string name="eden_theme">Eden</string>
|
||||
<string name="violet">紫色</string>
|
||||
<string name="blue">藍色</string>
|
||||
<string name="cyan">青色</string>
|
||||
<string name="red">紅色</string>
|
||||
<string name="green">綠色</string>
|
||||
<string name="yellow">黃色</string>
|
||||
<string name="orange">橘色</string>
|
||||
<string name="pink">粉紅色</string>
|
||||
@@ -1185,14 +1206,28 @@
|
||||
<string name="applets_menu_description">更改小程式前端和設定</string>
|
||||
|
||||
<string name="applet_hle">自訂前端</string>
|
||||
<string name="applet_lle">Switch小程式</string>
|
||||
<string name="applet_lle">Switch 小程式</string>
|
||||
|
||||
<string name="swkbd_applet">軟體鍵盤</string>
|
||||
|
||||
<string name="airplane_mode">飛航模式</string>
|
||||
<string name="airplane_mode_description">將飛航模式傳遞給Switch作業系統</string>
|
||||
<string name="airplane_mode_description">將飛航模式傳遞給 Switch 作業系統</string>
|
||||
|
||||
<string name="enable_overlay">啟用小程式虛擬按鍵</string>
|
||||
<string name="enable_overlay_description">啟用 Horizon OS 內建的小程式虛擬按鍵,長按 Home 鍵 1 秒以顯示虛擬按鍵</string>
|
||||
|
||||
<!-- Profile Management -->
|
||||
<string name="profile_manager">使用者管理</string>
|
||||
<string name="profile_manager_description">更改使用者名稱、圖片及新增或刪除使用者</string>
|
||||
<string name="profile_add_user">新增使用者</string>
|
||||
<string name="profile_new_user">新增使用者</string>
|
||||
<string name="profile_edit_user">編輯使用者資料</string>
|
||||
<string name="profile_edit">編輯</string>
|
||||
<string name="profile_delete">刪除</string>
|
||||
<string name="profile_username">使用者名稱</string>
|
||||
<string name="profile_uuid">使用者 ID (通用唯一辨識碼)</string>
|
||||
<string name="profile_uuid_description">這是此使用者設定檔的唯一識別碼,建立後就無法進行更改</string>
|
||||
<!-- Licenses screen strings -->
|
||||
<string name="licenses">授權</string>
|
||||
<string name="license_fidelityfx_fsr_description">來自 AMD 的升級圖像品質</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
||||
@@ -40,8 +40,6 @@ struct HostTranslateInfo {
|
||||
bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional
|
||||
///< control flow
|
||||
bool single_lane_geometry_subgroups{};
|
||||
bool support_attribute_texture_handle{}; ///< True when the host binds texture handles that
|
||||
///< arrive as vertex attributes
|
||||
|
||||
void ApplyDescriptorLimitPolicy() noexcept {
|
||||
if (min_ssbo_alignment == 0) {
|
||||
|
||||
@@ -268,10 +268,6 @@ static inline u32 ReadCbufCached(Environment& env, u32 index, u32 offset) {
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline bool IsAttributeHandle(const ConstBufferAddr& cbuf) {
|
||||
return cbuf.index == ATTRIBUTE_HANDLE_CBUF_INDEX;
|
||||
}
|
||||
|
||||
static inline u32 GetTextureHandleCached(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
// Must all be uniquely different variables
|
||||
// If has secondary, then it will be cbuf.secondary_{index|offset}, else its 0.
|
||||
@@ -291,23 +287,14 @@ static inline u32 GetTextureHandleCached(Environment& env, const ConstBufferAddr
|
||||
|
||||
// Cached variants of existing helpers
|
||||
static inline TextureType ReadTextureTypeCached(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
if (IsAttributeHandle(cbuf)) {
|
||||
return TextureType::Color2D;
|
||||
}
|
||||
return env.ReadTextureType(GetTextureHandleCached(env, cbuf));
|
||||
}
|
||||
static inline TexturePixelFormat ReadTexturePixelFormatCached(Environment& env,
|
||||
const ConstBufferAddr& cbuf) {
|
||||
if (IsAttributeHandle(cbuf)) {
|
||||
return TexturePixelFormat::A8B8G8R8_UNORM;
|
||||
}
|
||||
return env.ReadTexturePixelFormat(GetTextureHandleCached(env, cbuf));
|
||||
}
|
||||
static inline bool IsTexturePixelFormatIntegerCached(Environment& env,
|
||||
const ConstBufferAddr& cbuf) {
|
||||
if (IsAttributeHandle(cbuf)) {
|
||||
return false;
|
||||
}
|
||||
return env.IsTexturePixelFormatInteger(GetTextureHandleCached(env, cbuf));
|
||||
}
|
||||
|
||||
@@ -479,43 +466,15 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
|
||||
};
|
||||
}
|
||||
|
||||
bool IsAttributeSourcedHandle(const IR::Value& handle) {
|
||||
if (handle.IsImmediate()) {
|
||||
return false;
|
||||
}
|
||||
const IR::Inst* inst{handle.InstRecursive()};
|
||||
if (inst->GetOpcode() == IR::Opcode::BitCastU32F32 && !inst->Arg(0).IsImmediate()) {
|
||||
inst = inst->Arg(0).InstRecursive();
|
||||
}
|
||||
return inst->GetOpcode() == IR::Opcode::GetAttribute ||
|
||||
inst->GetOpcode() == IR::Opcode::GetAttributeU32;
|
||||
}
|
||||
|
||||
TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst, const HostTranslateInfo& host_info) {
|
||||
ConstBufferAddr addr;
|
||||
if (IsBindless(inst)) {
|
||||
const std::optional<ConstBufferAddr> track_addr{TrackCached(inst.Arg(0), env, host_info)};
|
||||
|
||||
if (track_addr) {
|
||||
addr = *track_addr;
|
||||
} else if (host_info.support_attribute_texture_handle &&
|
||||
IsAttributeSourcedHandle(inst.Arg(0))) {
|
||||
// The handle travels with the vertices (sprite batches pick the texture per quad), so
|
||||
// there is no constant buffer to read it from. The host binds the handle of each run
|
||||
// of vertices that share one.
|
||||
addr = ConstBufferAddr{
|
||||
.index = ATTRIBUTE_HANDLE_CBUF_INDEX,
|
||||
.offset = 0,
|
||||
.shift_left = 0,
|
||||
.secondary_index = 0,
|
||||
.secondary_offset = 0,
|
||||
.secondary_shift_left = 0,
|
||||
.dynamic_offset = {},
|
||||
.count = 1,
|
||||
.has_secondary = false,
|
||||
};
|
||||
} else {
|
||||
if (!track_addr) {
|
||||
throw NotImplementedException("Failed to track bindless texture constant buffer");
|
||||
} else {
|
||||
addr = *track_addr;
|
||||
}
|
||||
} else {
|
||||
addr = ConstBufferAddr{
|
||||
|
||||
@@ -38,10 +38,6 @@ enum class TextureType : u32 {
|
||||
};
|
||||
constexpr u32 NUM_TEXTURE_TYPES = 9;
|
||||
|
||||
/// Constant buffer index marking a texture handle that the shader receives as a vertex attribute
|
||||
/// instead of reading it from a constant buffer. The host supplies the handle of each draw run.
|
||||
constexpr u32 ATTRIBUTE_HANDLE_CBUF_INDEX = 0xFFFF;
|
||||
|
||||
enum class TexturePixelFormat {
|
||||
A8B8G8R8_UNORM,
|
||||
A8B8G8R8_SNORM,
|
||||
|
||||
@@ -276,9 +276,6 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
num_textures += Shader::NumDescriptors(info->texture_descriptors);
|
||||
num_image_elements += Shader::NumDescriptors(info->texture_descriptors);
|
||||
num_image_elements += Shader::NumDescriptors(info->image_descriptors);
|
||||
for (const auto& desc : info->texture_descriptors) {
|
||||
uses_attribute_handle |= desc.cbuf_index == Shader::ATTRIBUTE_HANDLE_CBUF_INDEX;
|
||||
}
|
||||
num_descriptor_entries += NumDescriptorEntries(*info);
|
||||
}
|
||||
fragment_has_color0_output = stage_infos[NUM_STAGES - 1].stores_frag_color[0];
|
||||
@@ -378,9 +375,6 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
}
|
||||
const auto& cbufs{maxwell3d->state.shader_stages[stage].const_buffers};
|
||||
const auto read_handle{[&](const auto& desc, u32 index) {
|
||||
if (desc.cbuf_index == Shader::ATTRIBUTE_HANDLE_CBUF_INDEX) {
|
||||
return TexturePair(attribute_handle, via_header_index);
|
||||
}
|
||||
ASSERT(cbufs[desc.cbuf_index].enabled);
|
||||
const u32 index_offset{index << desc.size_shift};
|
||||
const u32 offset{desc.cbuf_offset + index_offset};
|
||||
|
||||
@@ -110,16 +110,6 @@ public:
|
||||
return configure_func(this, is_indexed);
|
||||
}
|
||||
|
||||
/// True when a shader samples a texture whose handle arrives as a vertex attribute.
|
||||
[[nodiscard]] bool UsesAttributeHandle() const noexcept {
|
||||
return uses_attribute_handle;
|
||||
}
|
||||
|
||||
/// Handle bound to those textures by the next Configure.
|
||||
void SetAttributeHandle(u32 handle) noexcept {
|
||||
attribute_handle = handle;
|
||||
}
|
||||
|
||||
[[nodiscard]] GraphicsPipeline* Next(const GraphicsPipelineCacheKey& current_key) noexcept {
|
||||
if (key == current_key) {
|
||||
return this;
|
||||
@@ -178,8 +168,6 @@ private:
|
||||
u32 num_descriptor_entries{};
|
||||
size_t num_image_elements{};
|
||||
u32 num_textures{};
|
||||
u32 attribute_handle{};
|
||||
bool uses_attribute_handle{};
|
||||
bool fragment_has_color0_output{};
|
||||
|
||||
vk::DescriptorSetLayout descriptor_set_layout;
|
||||
|
||||
@@ -491,7 +491,6 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
|
||||
.support_conditional_barrier = device.SupportsConditionalBarriers(),
|
||||
.single_lane_geometry_subgroups = !profile.SupportsSubgroupStage(Shader::Stage::Geometry),
|
||||
.support_attribute_texture_handle = true,
|
||||
};
|
||||
host_info.ApplyDescriptorLimitPolicy();
|
||||
|
||||
|
||||
@@ -248,15 +248,6 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
|
||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
// update engine as channel may be different.
|
||||
pipeline->SetEngine(maxwell3d, gpu_memory);
|
||||
attribute_handle_pipeline = nullptr;
|
||||
attribute_handle_runs.clear();
|
||||
if (split_attribute_handles && pipeline->UsesAttributeHandle()) {
|
||||
CollectAttributeHandleRuns(is_indexed);
|
||||
if (!attribute_handle_runs.empty()) {
|
||||
attribute_handle_pipeline = pipeline;
|
||||
pipeline->SetAttributeHandle(attribute_handle_runs.front().handle);
|
||||
}
|
||||
}
|
||||
if (!pipeline->Configure(is_indexed))
|
||||
return;
|
||||
|
||||
@@ -268,110 +259,22 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
|
||||
draw_func();
|
||||
}
|
||||
|
||||
void RasterizerVulkan::CollectAttributeHandleRuns(bool is_indexed) {
|
||||
using VertexAttribute = Maxwell::VertexAttribute;
|
||||
const auto& regs = maxwell3d->regs;
|
||||
const auto& draw_state = maxwell3d->draw_manager.draw_state;
|
||||
const u32 total = is_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count;
|
||||
if (total == 0) {
|
||||
return;
|
||||
}
|
||||
// The handle is an integer attribute; sprite batches repeat it on every vertex of a quad.
|
||||
const VertexAttribute* source{};
|
||||
for (const auto& attr : regs.vertex_attrib_format) {
|
||||
if (attr.constant || attr.size == VertexAttribute::Size::Invalid) {
|
||||
continue;
|
||||
}
|
||||
if (attr.type == VertexAttribute::Type::UInt || attr.type == VertexAttribute::Type::SInt) {
|
||||
source = &attr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const auto& stream = regs.vertex_streams[source ? source->buffer.Value() : 0];
|
||||
if (!source || !stream.IsEnabled()) {
|
||||
attribute_handle_runs.push_back({0, total, 0});
|
||||
return;
|
||||
}
|
||||
// Only plain triangle lists are split; anything else keeps the handle of its first vertex.
|
||||
const u32 primitive_size =
|
||||
draw_state.topology == Maxwell::PrimitiveTopology::Triangles ? 3 : total;
|
||||
const GPUVAddr base_address = stream.Address() + source->offset;
|
||||
const auto read_handle = [&](u32 position) {
|
||||
u32 vertex;
|
||||
if (is_indexed) {
|
||||
const auto& index_buffer = draw_state.index_buffer;
|
||||
const GPUVAddr address =
|
||||
index_buffer.IndexStart() + size_t{position} * index_buffer.FormatSizeInBytes();
|
||||
u32 index{};
|
||||
gpu_memory->ReadBlockUnsafe(address, &index, index_buffer.FormatSizeInBytes());
|
||||
vertex = static_cast<u32>(draw_state.base_index + index);
|
||||
} else {
|
||||
vertex = draw_state.vertex_buffer.first + position;
|
||||
}
|
||||
return gpu_memory->Read<u32>(base_address + static_cast<GPUVAddr>(vertex) * stream.stride);
|
||||
};
|
||||
for (u32 position = 0; position + primitive_size <= total; position += primitive_size) {
|
||||
const u32 handle = read_handle(position);
|
||||
if (!attribute_handle_runs.empty() && attribute_handle_runs.back().handle == handle) {
|
||||
attribute_handle_runs.back().count += primitive_size;
|
||||
} else {
|
||||
attribute_handle_runs.push_back({position, primitive_size, handle});
|
||||
}
|
||||
}
|
||||
if (attribute_handle_runs.empty()) {
|
||||
attribute_handle_runs.push_back({0, total, read_handle(0)});
|
||||
} else {
|
||||
const u32 covered = attribute_handle_runs.back().first + attribute_handle_runs.back().count;
|
||||
if (covered < total) {
|
||||
attribute_handle_runs.back().count += total - covered;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) {
|
||||
split_attribute_handles = true;
|
||||
SCOPE_EXIT {
|
||||
split_attribute_handles = false;
|
||||
};
|
||||
PrepareDraw(is_indexed, [this, is_indexed, instance_count] {
|
||||
const auto& draw_state = maxwell3d->draw_manager.draw_state;
|
||||
const u32 num_instances{instance_count};
|
||||
const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)};
|
||||
|
||||
const auto record_draw = [this](const DrawParams& params) {
|
||||
scheduler.Record([params](vk::CommandBuffer cmdbuf) {
|
||||
if (params.is_indexed) {
|
||||
cmdbuf.DrawIndexed(params.num_vertices, params.num_instances,
|
||||
params.first_index, params.base_vertex,
|
||||
params.base_instance);
|
||||
} else {
|
||||
cmdbuf.Draw(params.num_vertices, params.num_instances, params.base_vertex,
|
||||
params.base_instance);
|
||||
}
|
||||
});
|
||||
};
|
||||
if (attribute_handle_pipeline && attribute_handle_runs.size() > 1) {
|
||||
// The first run is already configured, each further one binds its own texture.
|
||||
for (size_t i = 0; i < attribute_handle_runs.size(); ++i) {
|
||||
const AttributeHandleRun& run = attribute_handle_runs[i];
|
||||
if (i != 0) {
|
||||
attribute_handle_pipeline->SetAttributeHandle(run.handle);
|
||||
if (!attribute_handle_pipeline->Configure(is_indexed)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
DrawParams run_params = draw_params;
|
||||
run_params.num_vertices = run.count;
|
||||
if (is_indexed) {
|
||||
run_params.first_index += run.first;
|
||||
} else {
|
||||
run_params.base_vertex += run.first;
|
||||
}
|
||||
record_draw(run_params);
|
||||
scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
|
||||
if (draw_params.is_indexed) {
|
||||
cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances,
|
||||
draw_params.first_index, draw_params.base_vertex,
|
||||
draw_params.base_instance);
|
||||
} else {
|
||||
cmdbuf.Draw(draw_params.num_vertices, draw_params.num_instances,
|
||||
draw_params.base_vertex, draw_params.base_instance);
|
||||
}
|
||||
} else {
|
||||
record_draw(draw_params);
|
||||
}
|
||||
});
|
||||
|
||||
// Log draw call
|
||||
if (GPU::Logging::IsActive() &&
|
||||
|
||||
@@ -157,20 +157,6 @@ private:
|
||||
template <typename Func>
|
||||
void PrepareDraw(bool is_indexed, Func&&);
|
||||
|
||||
/// A stretch of a draw whose vertices all carry the same texture handle.
|
||||
struct AttributeHandleRun {
|
||||
u32 first;
|
||||
u32 count;
|
||||
u32 handle;
|
||||
};
|
||||
|
||||
/// Splits the current draw wherever the texture handle carried in the vertex data changes.
|
||||
void CollectAttributeHandleRuns(bool is_indexed);
|
||||
|
||||
std::vector<AttributeHandleRun> attribute_handle_runs;
|
||||
GraphicsPipeline* attribute_handle_pipeline{};
|
||||
bool split_attribute_handles{};
|
||||
|
||||
void FlushWork();
|
||||
|
||||
void UpdateDynamicStates();
|
||||
|
||||
Reference in New Issue
Block a user