Updated to 5.0-17430 for more optimisations!

This commit is contained in:
sirmangler 2022-09-24 14:55:45 +01:00
commit aaa54ae2a7
124 changed files with 2350 additions and 1635 deletions

View File

@ -980,6 +980,10 @@ else()
set(DOLPHIN_WC_IS_STABLE "0") set(DOLPHIN_WC_IS_STABLE "0")
endif() endif()
# Remove in-tree revision information generated by Visual Studio
# This is because the compiler will check in-tree first and use this, even if it is outdated
file(REMOVE "${PROJECT_SOURCE_DIR}/Source/Core/Common/scmrev.h")
configure_file( configure_file(
"${PROJECT_SOURCE_DIR}/Source/Core/Common/scmrev.h.in" "${PROJECT_SOURCE_DIR}/Source/Core/Common/scmrev.h.in"
"${PROJECT_BINARY_DIR}/Source/Core/Common/scmrev.h" "${PROJECT_BINARY_DIR}/Source/Core/Common/scmrev.h"

View File

@ -9,7 +9,7 @@ if(APPLE)
elseif(MSVC) elseif(MSVC)
target_sources(hidapi PRIVATE windows/hid.c) target_sources(hidapi PRIVATE windows/hid.c)
else() else()
find_package(Libudev) find_package(LIBUDEV)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND LIBUDEV_FOUND) if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND LIBUDEV_FOUND)
target_sources(hidapi PRIVATE linux/hid.c) target_sources(hidapi PRIVATE linux/hid.c)
target_link_libraries(hidapi PRIVATE udev) target_link_libraries(hidapi PRIVATE udev)

View File

@ -154,20 +154,6 @@ Section "Base" SEC01
SetOutPath "$TEMP" SetOutPath "$TEMP"
SetOverwrite on SetOverwrite on
File /r "dxredist"
File /r "vcredist"
SectionEnd
Section "DirectX Runtime" SEC02
DetailPrint "Running DirectX runtime setup..."
ExecWait '"$TEMP\dxredist\DXSETUP.exe" /silent'
DetailPrint "Finished DirectX runtime setup"
SectionEnd
Section "Visual C++ 2015 Redistributable" SEC03
DetailPrint "Running Visual C++ 2015 Redistributable setup..."
ExecWait '"$TEMP\vcredist\vc_redist.x64.exe" /install /quiet /norestart'
DetailPrint "Finished Visual C++ 2015 Redistributable setup"
SectionEnd SectionEnd
Section -AdditionalIcons Section -AdditionalIcons
@ -193,8 +179,6 @@ SectionEnd
; Section descriptions ; Section descriptions
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SEC01} "Installs all files required to run the Dolphin Emulator." !insertmacro MUI_DESCRIPTION_TEXT ${SEC01} "Installs all files required to run the Dolphin Emulator."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC02} "Installs the recommended DirectX runtime libraries that are needed by Dolphin."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC03} "Installs the required Visual C++ 2015 Redistributable that is needed by Dolphin."
!insertmacro MUI_FUNCTION_DESCRIPTION_END !insertmacro MUI_FUNCTION_DESCRIPTION_END
Section Uninstall Section Uninstall

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -16,7 +16,7 @@ Primehack is now supported on MacOS thanks to the efforts of [Brandon Sorensen](
# Original Dolphin Readme file contents: # Original Dolphin Readme file contents:
[Homepage](https://dolphin-emu.org/) | [Project Site](https://github.com/dolphin-emu/dolphin) | [Buildbot](https://dolphin.ci) | [Forums](https://forums.dolphin-emu.org) | [Wiki](https://wiki.dolphin-emu.org) | [Github Wiki](https://github.com/dolphin-emu/dolphin/wiki) | [Issue Tracker](https://bugs.dolphin-emu.org/projects/emulator/issues) | [Coding Style](https://github.com/dolphin-emu/dolphin/blob/master/Contributing.md) | [Transifex Page](https://www.transifex.com/projects/p/dolphin-emu) [Homepage](https://dolphin-emu.org/) | [Project Site](https://github.com/dolphin-emu/dolphin) | [Buildbot](https://dolphin.ci/) | [Forums](https://forums.dolphin-emu.org/) | [Wiki](https://wiki.dolphin-emu.org/) | [GitHub Wiki](https://github.com/dolphin-emu/dolphin/wiki) | [Issue Tracker](https://bugs.dolphin-emu.org/projects/emulator/issues) | [Coding Style](https://github.com/dolphin-emu/dolphin/blob/master/Contributing.md) | [Transifex Page](https://explore.transifex.com/delroth/dolphin-emu/)
Dolphin is an emulator for running GameCube and Wii games on Windows, Dolphin is an emulator for running GameCube and Wii games on Windows,
Linux, macOS, and recent Android devices. It's licensed under the terms Linux, macOS, and recent Android devices. It's licensed under the terms

View File

@ -14,9 +14,10 @@ import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.divider.MaterialDividerItemDecoration;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel; import org.dolphinemu.dolphinemu.features.cheats.model.CheatsViewModel;
import org.dolphinemu.dolphinemu.ui.DividerItemDecoration;
public class CheatListFragment extends Fragment public class CheatListFragment extends Fragment
{ {
@ -38,6 +39,10 @@ public class CheatListFragment extends Fragment
recyclerView.setAdapter(new CheatsAdapter(activity, viewModel)); recyclerView.setAdapter(new CheatsAdapter(activity, viewModel));
recyclerView.setLayoutManager(new LinearLayoutManager(activity)); recyclerView.setLayoutManager(new LinearLayoutManager(activity));
recyclerView.addItemDecoration(new DividerItemDecoration(activity, null));
MaterialDividerItemDecoration divider =
new MaterialDividerItemDecoration(requireActivity(), LinearLayoutManager.VERTICAL);
divider.setLastItemDecorated(false);
recyclerView.addItemDecoration(divider);
} }
} }

View File

@ -14,10 +14,11 @@ import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.divider.MaterialDividerItemDecoration;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.model.Settings; import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.ui.DividerItemDecoration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -136,7 +137,11 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
recyclerView.setAdapter(mAdapter); recyclerView.setAdapter(mAdapter);
recyclerView.setLayoutManager(manager); recyclerView.setLayoutManager(manager);
recyclerView.addItemDecoration(new DividerItemDecoration(requireActivity(), null));
MaterialDividerItemDecoration divider =
new MaterialDividerItemDecoration(requireActivity(), LinearLayoutManager.VERTICAL);
divider.setLastItemDecorated(false);
recyclerView.addItemDecoration(divider);
SettingsActivityView activity = (SettingsActivityView) getActivity(); SettingsActivityView activity = (SettingsActivityView) getActivity();
mPresenter.onViewCreated(menuTag, activity.getSettings()); mPresenter.onViewCreated(menuTag, activity.getSettings());

View File

@ -1,162 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.ui;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
/**
* Implementation from:
* https://gist.github.com/lapastillaroja/858caf1a82791b6c1a36
*/
public final class DividerItemDecoration extends RecyclerView.ItemDecoration
{
private Drawable mDivider;
private boolean mShowFirstDivider = false;
private boolean mShowLastDivider = false;
public DividerItemDecoration(Context context, AttributeSet attrs)
{
final TypedArray a = context
.obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
mDivider = a.getDrawable(0);
a.recycle();
}
public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
boolean showLastDivider)
{
this(context, attrs);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
public DividerItemDecoration(Drawable divider)
{
mDivider = divider;
}
public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
boolean showLastDivider)
{
this(divider);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,
@NonNull RecyclerView parent,
@NonNull RecyclerView.State state)
{
super.getItemOffsets(outRect, view, parent, state);
if (mDivider == null)
{
return;
}
if (parent.getChildAdapterPosition(view) < 1)
{
return;
}
if (getOrientation(parent) == LinearLayoutManager.VERTICAL)
{
outRect.top = mDivider.getIntrinsicHeight();
}
else
{
outRect.left = mDivider.getIntrinsicWidth();
}
}
@Override
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent,
@NonNull RecyclerView.State state)
{
if (mDivider == null)
{
super.onDrawOver(c, parent, state);
return;
}
// Initialization needed to avoid compiler warning
int left = 0, right = 0, top = 0, bottom = 0, size;
int orientation = getOrientation(parent);
int childCount = parent.getChildCount();
if (orientation == LinearLayoutManager.VERTICAL)
{
size = mDivider.getIntrinsicHeight();
left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight();
}
else
{ //horizontal
size = mDivider.getIntrinsicWidth();
top = parent.getPaddingTop();
bottom = parent.getHeight() - parent.getPaddingBottom();
}
for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++)
{
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL)
{
top = child.getTop() - params.topMargin;
bottom = top + size;
}
else
{ //horizontal
left = child.getLeft() - params.leftMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
// show last divider
if (mShowLastDivider && childCount > 0)
{
View child = parent.getChildAt(childCount - 1);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL)
{
top = child.getBottom() + params.bottomMargin;
bottom = top + size;
}
else
{ // horizontal
left = child.getRight() + params.rightMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
private int getOrientation(RecyclerView parent)
{
if (parent.getLayoutManager() instanceof LinearLayoutManager)
{
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getOrientation();
}
else
{
throw new IllegalStateException(
"DividerItemDecoration can only be used with a LinearLayoutManager.");
}
}
}

View File

@ -50,7 +50,7 @@
app:layout_constraintWidth_max="400dp" app:layout_constraintWidth_max="400dp"
app:layout_constraintEnd_toStartOf="@id/divider" app:layout_constraintEnd_toStartOf="@id/divider"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/divider" app:layout_constraintTop_toTopOf="parent"
tools:text="@string/user_data_new_location" /> tools:text="@string/user_data_new_location" />
<TextView <TextView
@ -84,15 +84,14 @@
app:barrierDirection="end" app:barrierDirection="end"
app:constraint_referenced_ids="text_type,text_path,text_android_11" /> app:constraint_referenced_ids="text_type,text_path,text_android_11" />
<View <com.google.android.material.divider.MaterialDivider
android:id="@+id/divider" android:id="@+id/divider"
android:layout_width="1dp" android:layout_width="1dp"
android:layout_height="0dp" android:layout_height="0dp"
android:background="#1F000000"
android:layout_marginStart="24dp" android:layout_marginStart="24dp"
android:layout_marginEnd="24dp" android:layout_marginEnd="24dp"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="@id/text_type"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="@id/text_android_11"
app:layout_constraintStart_toEndOf="@id/barrier_text" app:layout_constraintStart_toEndOf="@id/barrier_text"
app:layout_constraintEnd_toStartOf="@id/barrier_buttons" /> app:layout_constraintEnd_toStartOf="@id/barrier_buttons" />

View File

@ -53,11 +53,10 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/divider" /> app:layout_constraintEnd_toStartOf="@id/divider" />
<View <com.google.android.material.divider.MaterialDivider
android:id="@+id/divider" android:id="@+id/divider"
android:layout_width="1dp" android:layout_width="1dp"
android:layout_height="0dp" android:layout_height="0dp"
android:background="#1F000000"
android:layout_marginStart="24dp" android:layout_marginStart="24dp"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"

View File

@ -51,11 +51,10 @@
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/divider" /> app:layout_constraintBottom_toTopOf="@id/divider" />
<View <com.google.android.material.divider.MaterialDivider
android:id="@+id/divider" android:id="@+id/divider"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="1dp" android:layout_height="wrap_content"
android:background="#1F000000"
android:layout_marginTop="24dp" android:layout_marginTop="24dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View File

@ -52,11 +52,10 @@
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/divider" /> app:layout_constraintBottom_toTopOf="@id/divider" />
<View <com.google.android.material.divider.MaterialDivider
android:id="@+id/divider" android:id="@+id/divider"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="1dp" android:layout_height="wrap_content"
android:background="#1F000000"
android:layout_marginHorizontal="@dimen/spacing_large" android:layout_marginHorizontal="@dimen/spacing_large"
android:layout_marginVertical="@dimen/spacing_small" android:layout_marginVertical="@dimen/spacing_small"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"

View File

@ -44,11 +44,10 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_description" /> app:layout_constraintTop_toBottomOf="@id/text_description" />
<View <com.google.android.material.divider.MaterialDivider
android:id="@+id/divider_1" android:id="@+id/divider_1"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="1dp" android:layout_height="wrap_content"
android:background="#1F000000"
android:layout_marginTop="32dp" android:layout_marginTop="32dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
@ -145,11 +144,10 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBaseline_toBaselineOf="@id/label_revision" /> app:layout_constraintBaseline_toBaselineOf="@id/label_revision" />
<View <com.google.android.material.divider.MaterialDivider
android:id="@+id/divider_2" android:id="@+id/divider_2"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="1dp" android:layout_height="wrap_content"
android:background="#1F000000"
android:layout_marginTop="32dp" android:layout_marginTop="32dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View File

@ -110,11 +110,10 @@
</ScrollView> </ScrollView>
<View <com.google.android.material.divider.MaterialDivider
android:id="@+id/divider" android:id="@+id/divider_2"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="1dp" android:layout_height="wrap_content"
android:background="?attr/colorOnSurfaceVariant"
android:layout_marginTop="24dp" android:layout_marginTop="24dp"
android:layout_marginBottom="16dp" /> android:layout_marginBottom="16dp" />

View File

@ -58,4 +58,8 @@
<item name="tickVisible">false</item> <item name="tickVisible">false</item>
<item name="labelBehavior">gone</item> <item name="labelBehavior">gone</item>
</style> </style>
<style name="DolphinDivider" parent="Widget.Material3.MaterialDivider">
<item name="dividerColor">?attr/colorSurfaceVariant</item>
</style>
</resources> </resources>

View File

@ -54,6 +54,7 @@
<item name="materialAlertDialogTheme">@style/DolphinMaterialDialog</item> <item name="materialAlertDialogTheme">@style/DolphinMaterialDialog</item>
<item name="popupTheme">@style/DolphinPopup</item> <item name="popupTheme">@style/DolphinPopup</item>
<item name="sliderStyle">@style/DolphinSlider</item> <item name="sliderStyle">@style/DolphinSlider</item>
<item name="materialDividerStyle">@style/DolphinDivider</item>
</style> </style>
<!-- Trick for API >= 27 specific changes --> <!-- Trick for API >= 27 specific changes -->

View File

@ -485,13 +485,22 @@ void ARM64XEmitter::EncodeLoadStorePairedInst(u32 op, ARM64Reg Rt, ARM64Reg Rt2,
bool bVec = IsVector(Rt); bool bVec = IsVector(Rt);
if (b128Bit) if (b128Bit)
{
ASSERT_MSG(DYNA_REC, (imm & 0xf) == 0, "128-bit load/store must use aligned offset: {}", imm);
imm >>= 4; imm >>= 4;
}
else if (b64Bit) else if (b64Bit)
{
ASSERT_MSG(DYNA_REC, (imm & 0x7) == 0, "64-bit load/store must use aligned offset: {}", imm);
imm >>= 3; imm >>= 3;
}
else else
{
ASSERT_MSG(DYNA_REC, (imm & 0x3) == 0, "32-bit load/store must use aligned offset: {}", imm);
imm >>= 2; imm >>= 2;
}
ASSERT_MSG(DYNA_REC, !(imm & ~0xF), "offset too large {}", imm); ASSERT_MSG(DYNA_REC, (imm & ~0xF) == 0, "offset too large {}", imm);
u32 opc = 0; u32 opc = 0;
if (b128Bit) if (b128Bit)
@ -524,11 +533,20 @@ void ARM64XEmitter::EncodeLoadStoreIndexedInst(u32 op, ARM64Reg Rt, ARM64Reg Rn,
bool bVec = IsVector(Rt); bool bVec = IsVector(Rt);
if (size == 64) if (size == 64)
{
ASSERT_MSG(DYNA_REC, (imm & 0x7) == 0, "64-bit load/store must use aligned offset: {}", imm);
imm >>= 3; imm >>= 3;
}
else if (size == 32) else if (size == 32)
{
ASSERT_MSG(DYNA_REC, (imm & 0x3) == 0, "32-bit load/store must use aligned offset: {}", imm);
imm >>= 2; imm >>= 2;
}
else if (size == 16) else if (size == 16)
{
ASSERT_MSG(DYNA_REC, (imm & 0x1) == 0, "16-bit load/store must use aligned offset: {}", imm);
imm >>= 1; imm >>= 1;
}
ASSERT_MSG(DYNA_REC, imm >= 0, "(IndexType::Unsigned): offset must be positive {}", imm); ASSERT_MSG(DYNA_REC, imm >= 0, "(IndexType::Unsigned): offset must be positive {}", imm);
ASSERT_MSG(DYNA_REC, !(imm & ~0xFFF), "(IndexType::Unsigned): offset too large {}", imm); ASSERT_MSG(DYNA_REC, !(imm & ~0xFFF), "(IndexType::Unsigned): offset too large {}", imm);
@ -615,10 +633,12 @@ void ARM64XEmitter::EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64R
if (b64Bit) if (b64Bit)
{ {
op |= 0b10; op |= 0b10;
ASSERT_MSG(DYNA_REC, (imm & 0x7) == 0, "64-bit load/store must use aligned offset: {}", imm);
imm >>= 3; imm >>= 3;
} }
else else
{ {
ASSERT_MSG(DYNA_REC, (imm & 0x3) == 0, "32-bit load/store must use aligned offset: {}", imm);
imm >>= 2; imm >>= 2;
} }
@ -2072,19 +2092,29 @@ void ARM64FloatEmitter::EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type,
if (type == IndexType::Unsigned) if (type == IndexType::Unsigned)
{ {
ASSERT_MSG(DYNA_REC, !(imm & ((size - 1) >> 3)),
"(IndexType::Unsigned) immediate offset must be aligned to size! ({}) ({})", imm,
fmt::ptr(m_emit->GetCodePtr()));
ASSERT_MSG(DYNA_REC, imm >= 0, "(IndexType::Unsigned) immediate offset must be positive! ({})", ASSERT_MSG(DYNA_REC, imm >= 0, "(IndexType::Unsigned) immediate offset must be positive! ({})",
imm); imm);
if (size == 16) if (size == 16)
{
ASSERT_MSG(DYNA_REC, (imm & 0x1) == 0, "16-bit load/store must use aligned offset: {}", imm);
imm >>= 1; imm >>= 1;
}
else if (size == 32) else if (size == 32)
{
ASSERT_MSG(DYNA_REC, (imm & 0x3) == 0, "32-bit load/store must use aligned offset: {}", imm);
imm >>= 2; imm >>= 2;
}
else if (size == 64) else if (size == 64)
{
ASSERT_MSG(DYNA_REC, (imm & 0x7) == 0, "64-bit load/store must use aligned offset: {}", imm);
imm >>= 3; imm >>= 3;
}
else if (size == 128) else if (size == 128)
{
ASSERT_MSG(DYNA_REC, (imm & 0xf) == 0, "128-bit load/store must use aligned offset: {}", imm);
imm >>= 4; imm >>= 4;
}
ASSERT_MSG(DYNA_REC, imm <= 0xFFF, "Immediate value is too big: {}", imm);
encoded_imm = (imm & 0xFFF); encoded_imm = (imm & 0xFFF);
} }
else else

View File

@ -24,6 +24,11 @@ union TVec3
{ {
} }
constexpr bool operator==(const TVec3& other) const
{
return x == other.x && y == other.y && z == other.z;
}
constexpr TVec3 Cross(const TVec3& rhs) const constexpr TVec3 Cross(const TVec3& rhs) const
{ {
return {(y * rhs.z) - (rhs.y * z), (z * rhs.x) - (rhs.z * x), (x * rhs.y) - (rhs.x * y)}; return {(y * rhs.z) - (rhs.y * z), (z * rhs.x) - (rhs.z * x), (x * rhs.y) - (rhs.x * y)};
@ -153,6 +158,11 @@ union TVec4
constexpr TVec4(TVec3<T> _vec, T _w) : TVec4{_vec.x, _vec.y, _vec.z, _w} {} constexpr TVec4(TVec3<T> _vec, T _w) : TVec4{_vec.x, _vec.y, _vec.z, _w} {}
constexpr TVec4(T _x, T _y, T _z, T _w) : data{_x, _y, _z, _w} {} constexpr TVec4(T _x, T _y, T _z, T _w) : data{_x, _y, _z, _w} {}
constexpr bool operator==(const TVec4& other) const
{
return x == other.x && y == other.y && z == other.z && w == other.w;
}
constexpr T Dot(const TVec4& other) const constexpr T Dot(const TVec4& other) const
{ {
return x * other.x + y * other.y + z * other.z + w * other.w; return x * other.x + y * other.y + z * other.z + w * other.w;
@ -216,6 +226,8 @@ union TVec2
{ {
} }
constexpr bool operator==(const TVec2& other) const { return x == other.x && y == other.y; }
constexpr T Cross(const TVec2& rhs) const { return (x * rhs.y) - (y * rhs.x); } constexpr T Cross(const TVec2& rhs) const { return (x * rhs.y) - (y * rhs.x); }
constexpr T Dot(const TVec2& rhs) const { return (x * rhs.x) + (y * rhs.y); } constexpr T Dot(const TVec2& rhs) const { return (x * rhs.x) + (y * rhs.y); }
constexpr T LengthSquared() const { return Dot(*this); } constexpr T LengthSquared() const { return Dot(*this); }

View File

@ -29,7 +29,7 @@ using StringTranslator = std::string (*)(const char* text);
void RegisterMsgAlertHandler(MsgAlertHandler handler); void RegisterMsgAlertHandler(MsgAlertHandler handler);
void RegisterStringTranslator(StringTranslator translator); void RegisterStringTranslator(StringTranslator translator);
std::string GetStringT(const char* string); [[nodiscard]] std::string GetStringT(const char* string);
bool MsgAlertFmtImpl(bool yes_no, MsgType style, Common::Log::LogType log_type, const char* file, bool MsgAlertFmtImpl(bool yes_no, MsgType style, Common::Log::LogType log_type, const char* file,
int line, fmt::string_view format, const fmt::format_args& args); int line, fmt::string_view format, const fmt::format_args& args);

View File

@ -91,11 +91,7 @@ bool BootCore(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
return false; return false;
Config::AddLayer(ConfigLoaders::GenerateNetPlayConfigLoader(*netplay_settings)); Config::AddLayer(ConfigLoaders::GenerateNetPlayConfigLoader(*netplay_settings));
StartUp.bCopyWiiSaveNetplay = netplay_settings->m_CopyWiiSave; StartUp.bCopyWiiSaveNetplay = netplay_settings->copy_wii_save;
}
else
{
g_SRAM_netplay_initialized = false;
} }
// Override out-of-region languages/countries to prevent games from crashing or behaving oddly // Override out-of-region languages/countries to prevent games from crashing or behaving oddly

View File

@ -30,99 +30,99 @@ public:
void Load(Config::Layer* layer) override void Load(Config::Layer* layer) override
{ {
layer->Set(Config::MAIN_CPU_THREAD, m_settings.m_CPUthread); layer->Set(Config::MAIN_CPU_THREAD, m_settings.cpu_thread);
layer->Set(Config::MAIN_CPU_CORE, m_settings.m_CPUcore); layer->Set(Config::MAIN_CPU_CORE, m_settings.cpu_core);
layer->Set(Config::MAIN_ENABLE_CHEATS, m_settings.m_EnableCheats); layer->Set(Config::MAIN_ENABLE_CHEATS, m_settings.enable_cheats);
layer->Set(Config::MAIN_GC_LANGUAGE, m_settings.m_SelectedLanguage); layer->Set(Config::MAIN_GC_LANGUAGE, m_settings.selected_language);
layer->Set(Config::MAIN_OVERRIDE_REGION_SETTINGS, m_settings.m_OverrideRegionSettings); layer->Set(Config::MAIN_OVERRIDE_REGION_SETTINGS, m_settings.override_region_settings);
layer->Set(Config::MAIN_DSP_HLE, m_settings.m_DSPHLE); layer->Set(Config::MAIN_DSP_HLE, m_settings.dsp_hle);
layer->Set(Config::MAIN_OVERCLOCK_ENABLE, m_settings.m_OCEnable); layer->Set(Config::MAIN_OVERCLOCK_ENABLE, m_settings.oc_enable);
layer->Set(Config::MAIN_OVERCLOCK, m_settings.m_OCFactor); layer->Set(Config::MAIN_OVERCLOCK, m_settings.oc_factor);
for (ExpansionInterface::Slot slot : ExpansionInterface::SLOTS) for (ExpansionInterface::Slot slot : ExpansionInterface::SLOTS)
layer->Set(Config::GetInfoForEXIDevice(slot), m_settings.m_EXIDevice[slot]); layer->Set(Config::GetInfoForEXIDevice(slot), m_settings.exi_device[slot]);
layer->Set(Config::MAIN_MEMORY_CARD_SIZE, m_settings.m_MemcardSizeOverride); layer->Set(Config::MAIN_MEMORY_CARD_SIZE, m_settings.memcard_size_override);
layer->Set(Config::SESSION_SAVE_DATA_WRITABLE, m_settings.m_WriteToMemcard); layer->Set(Config::SESSION_SAVE_DATA_WRITABLE, m_settings.write_to_memcard);
layer->Set(Config::MAIN_RAM_OVERRIDE_ENABLE, m_settings.m_RAMOverrideEnable); layer->Set(Config::MAIN_RAM_OVERRIDE_ENABLE, m_settings.ram_override_enable);
layer->Set(Config::MAIN_MEM1_SIZE, m_settings.m_Mem1Size); layer->Set(Config::MAIN_MEM1_SIZE, m_settings.mem1_size);
layer->Set(Config::MAIN_MEM2_SIZE, m_settings.m_Mem2Size); layer->Set(Config::MAIN_MEM2_SIZE, m_settings.mem2_size);
layer->Set(Config::MAIN_FALLBACK_REGION, m_settings.m_FallbackRegion); layer->Set(Config::MAIN_FALLBACK_REGION, m_settings.fallback_region);
layer->Set(Config::MAIN_ALLOW_SD_WRITES, m_settings.m_AllowSDWrites); layer->Set(Config::MAIN_ALLOW_SD_WRITES, m_settings.allow_sd_writes);
layer->Set(Config::MAIN_DSP_JIT, m_settings.m_DSPEnableJIT); layer->Set(Config::MAIN_DSP_JIT, m_settings.dsp_enable_jit);
for (size_t i = 0; i < Config::SYSCONF_SETTINGS.size(); ++i) for (size_t i = 0; i < Config::SYSCONF_SETTINGS.size(); ++i)
{ {
std::visit( std::visit(
[&](auto* info) { [&](auto* info) {
layer->Set(*info, static_cast<decltype(info->GetDefaultValue())>( layer->Set(*info, static_cast<decltype(info->GetDefaultValue())>(
m_settings.m_SYSCONFSettings[i])); m_settings.sysconf_settings[i]));
}, },
Config::SYSCONF_SETTINGS[i].config_info); Config::SYSCONF_SETTINGS[i].config_info);
} }
layer->Set(Config::GFX_HACK_EFB_ACCESS_ENABLE, m_settings.m_EFBAccessEnable); layer->Set(Config::GFX_HACK_EFB_ACCESS_ENABLE, m_settings.efb_access_enable);
layer->Set(Config::GFX_HACK_BBOX_ENABLE, m_settings.m_BBoxEnable); layer->Set(Config::GFX_HACK_BBOX_ENABLE, m_settings.bbox_enable);
layer->Set(Config::GFX_HACK_FORCE_PROGRESSIVE, m_settings.m_ForceProgressive); layer->Set(Config::GFX_HACK_FORCE_PROGRESSIVE, m_settings.force_progressive);
layer->Set(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, m_settings.m_EFBToTextureEnable); layer->Set(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, m_settings.efb_to_texture_enable);
layer->Set(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM, m_settings.m_XFBToTextureEnable); layer->Set(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM, m_settings.xfb_to_texture_enable);
layer->Set(Config::GFX_HACK_DISABLE_COPY_TO_VRAM, m_settings.m_DisableCopyToVRAM); layer->Set(Config::GFX_HACK_DISABLE_COPY_TO_VRAM, m_settings.disable_copy_to_vram);
layer->Set(Config::GFX_HACK_IMMEDIATE_XFB, m_settings.m_ImmediateXFBEnable); layer->Set(Config::GFX_HACK_IMMEDIATE_XFB, m_settings.immediate_xfb_enable);
layer->Set(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES, m_settings.m_EFBEmulateFormatChanges); layer->Set(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES, m_settings.efb_emulate_format_changes);
layer->Set(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES, layer->Set(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES,
m_settings.m_SafeTextureCacheColorSamples); m_settings.safe_texture_cache_color_samples);
layer->Set(Config::GFX_PERF_QUERIES_ENABLE, m_settings.m_PerfQueriesEnable); layer->Set(Config::GFX_PERF_QUERIES_ENABLE, m_settings.perf_queries_enable);
layer->Set(Config::MAIN_FLOAT_EXCEPTIONS, m_settings.m_FloatExceptions); layer->Set(Config::MAIN_FLOAT_EXCEPTIONS, m_settings.float_exceptions);
layer->Set(Config::MAIN_DIVIDE_BY_ZERO_EXCEPTIONS, m_settings.m_DivideByZeroExceptions); layer->Set(Config::MAIN_DIVIDE_BY_ZERO_EXCEPTIONS, m_settings.divide_by_zero_exceptions);
layer->Set(Config::MAIN_FPRF, m_settings.m_FPRF); layer->Set(Config::MAIN_FPRF, m_settings.fprf);
layer->Set(Config::MAIN_ACCURATE_NANS, m_settings.m_AccurateNaNs); layer->Set(Config::MAIN_ACCURATE_NANS, m_settings.accurate_nans);
layer->Set(Config::MAIN_DISABLE_ICACHE, m_settings.m_DisableICache); layer->Set(Config::MAIN_DISABLE_ICACHE, m_settings.disable_icache);
layer->Set(Config::MAIN_SYNC_ON_SKIP_IDLE, m_settings.m_SyncOnSkipIdle); layer->Set(Config::MAIN_SYNC_ON_SKIP_IDLE, m_settings.sync_on_skip_idle);
layer->Set(Config::MAIN_SYNC_GPU, m_settings.m_SyncGPU); layer->Set(Config::MAIN_SYNC_GPU, m_settings.sync_gpu);
layer->Set(Config::MAIN_SYNC_GPU_MAX_DISTANCE, m_settings.m_SyncGpuMaxDistance); layer->Set(Config::MAIN_SYNC_GPU_MAX_DISTANCE, m_settings.sync_gpu_max_distance);
layer->Set(Config::MAIN_SYNC_GPU_MIN_DISTANCE, m_settings.m_SyncGpuMinDistance); layer->Set(Config::MAIN_SYNC_GPU_MIN_DISTANCE, m_settings.sync_gpu_min_distance);
layer->Set(Config::MAIN_SYNC_GPU_OVERCLOCK, m_settings.m_SyncGpuOverclock); layer->Set(Config::MAIN_SYNC_GPU_OVERCLOCK, m_settings.sync_gpu_overclock);
layer->Set(Config::MAIN_JIT_FOLLOW_BRANCH, m_settings.m_JITFollowBranch); layer->Set(Config::MAIN_JIT_FOLLOW_BRANCH, m_settings.jit_follow_branch);
layer->Set(Config::MAIN_FAST_DISC_SPEED, m_settings.m_FastDiscSpeed); layer->Set(Config::MAIN_FAST_DISC_SPEED, m_settings.fast_disc_speed);
layer->Set(Config::MAIN_MMU, m_settings.m_MMU); layer->Set(Config::MAIN_MMU, m_settings.mmu);
layer->Set(Config::MAIN_FASTMEM, m_settings.m_Fastmem); layer->Set(Config::MAIN_FASTMEM, m_settings.fastmem);
layer->Set(Config::MAIN_SKIP_IPL, m_settings.m_SkipIPL); layer->Set(Config::MAIN_SKIP_IPL, m_settings.skip_ipl);
layer->Set(Config::SESSION_LOAD_IPL_DUMP, m_settings.m_LoadIPLDump); layer->Set(Config::SESSION_LOAD_IPL_DUMP, m_settings.load_ipl_dump);
layer->Set(Config::GFX_HACK_DEFER_EFB_COPIES, m_settings.m_DeferEFBCopies); layer->Set(Config::GFX_HACK_DEFER_EFB_COPIES, m_settings.defer_efb_copies);
layer->Set(Config::GFX_HACK_EFB_ACCESS_TILE_SIZE, m_settings.m_EFBAccessTileSize); layer->Set(Config::GFX_HACK_EFB_ACCESS_TILE_SIZE, m_settings.efb_access_tile_size);
layer->Set(Config::GFX_HACK_EFB_DEFER_INVALIDATION, m_settings.m_EFBAccessDeferInvalidation); layer->Set(Config::GFX_HACK_EFB_DEFER_INVALIDATION, m_settings.efb_access_defer_invalidation);
layer->Set(Config::SESSION_USE_FMA, m_settings.m_UseFMA); layer->Set(Config::SESSION_USE_FMA, m_settings.use_fma);
layer->Set(Config::MAIN_BLUETOOTH_PASSTHROUGH_ENABLED, false); layer->Set(Config::MAIN_BLUETOOTH_PASSTHROUGH_ENABLED, false);
if (m_settings.m_StrictSettingsSync) if (m_settings.strict_settings_sync)
{ {
layer->Set(Config::GFX_HACK_VERTEX_ROUNDING, m_settings.m_VertexRounding); layer->Set(Config::GFX_HACK_VERTEX_ROUNDING, m_settings.vertex_rounding);
layer->Set(Config::GFX_EFB_SCALE, m_settings.m_InternalResolution); layer->Set(Config::GFX_EFB_SCALE, m_settings.internal_resolution);
layer->Set(Config::GFX_HACK_COPY_EFB_SCALED, m_settings.m_EFBScaledCopy); layer->Set(Config::GFX_HACK_COPY_EFB_SCALED, m_settings.efb_scaled_copy);
layer->Set(Config::GFX_FAST_DEPTH_CALC, m_settings.m_FastDepthCalc); layer->Set(Config::GFX_FAST_DEPTH_CALC, m_settings.fast_depth_calc);
layer->Set(Config::GFX_ENABLE_PIXEL_LIGHTING, m_settings.m_EnablePixelLighting); layer->Set(Config::GFX_ENABLE_PIXEL_LIGHTING, m_settings.enable_pixel_lighting);
layer->Set(Config::GFX_WIDESCREEN_HACK, m_settings.m_WidescreenHack); layer->Set(Config::GFX_WIDESCREEN_HACK, m_settings.widescreen_hack);
layer->Set(Config::GFX_ENHANCE_FORCE_FILTERING, m_settings.m_ForceFiltering); layer->Set(Config::GFX_ENHANCE_FORCE_FILTERING, m_settings.force_filtering);
layer->Set(Config::GFX_ENHANCE_MAX_ANISOTROPY, m_settings.m_MaxAnisotropy); layer->Set(Config::GFX_ENHANCE_MAX_ANISOTROPY, m_settings.max_anisotropy);
layer->Set(Config::GFX_ENHANCE_FORCE_TRUE_COLOR, m_settings.m_ForceTrueColor); layer->Set(Config::GFX_ENHANCE_FORCE_TRUE_COLOR, m_settings.force_true_color);
layer->Set(Config::GFX_ENHANCE_DISABLE_COPY_FILTER, m_settings.m_DisableCopyFilter); layer->Set(Config::GFX_ENHANCE_DISABLE_COPY_FILTER, m_settings.disable_copy_filter);
layer->Set(Config::GFX_DISABLE_FOG, m_settings.m_DisableFog); layer->Set(Config::GFX_DISABLE_FOG, m_settings.disable_fog);
layer->Set(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION, layer->Set(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION,
m_settings.m_ArbitraryMipmapDetection); m_settings.arbitrary_mipmap_detection);
layer->Set(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION_THRESHOLD, layer->Set(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION_THRESHOLD,
m_settings.m_ArbitraryMipmapDetectionThreshold); m_settings.arbitrary_mipmap_detection_threshold);
layer->Set(Config::GFX_ENABLE_GPU_TEXTURE_DECODING, m_settings.m_EnableGPUTextureDecoding); layer->Set(Config::GFX_ENABLE_GPU_TEXTURE_DECODING, m_settings.enable_gpu_texture_decoding);
// Disable AA as it isn't deterministic across GPUs // Disable AA as it isn't deterministic across GPUs
layer->Set(Config::GFX_MSAA, 1); layer->Set(Config::GFX_MSAA, 1);
layer->Set(Config::GFX_SSAA, false); layer->Set(Config::GFX_SSAA, false);
} }
if (m_settings.m_SyncSaveData) if (m_settings.sync_save_data)
{ {
if (!m_settings.m_IsHosting) if (!m_settings.is_hosting)
{ {
const std::string path = File::GetUserPath(D_GCUSER_IDX) + GC_MEMCARD_NETPLAY DIR_SEP; const std::string path = File::GetUserPath(D_GCUSER_IDX) + GC_MEMCARD_NETPLAY DIR_SEP;
layer->Set(Config::MAIN_GCI_FOLDER_A_PATH_OVERRIDE, path + "Card A"); layer->Set(Config::MAIN_GCI_FOLDER_A_PATH_OVERRIDE, path + "Card A");
@ -130,7 +130,7 @@ public:
const auto make_memcard_path = [this](char letter) { const auto make_memcard_path = [this](char letter) {
return fmt::format("{}{}{}.{}.raw", File::GetUserPath(D_GCUSER_IDX), GC_MEMCARD_NETPLAY, return fmt::format("{}{}{}.{}.raw", File::GetUserPath(D_GCUSER_IDX), GC_MEMCARD_NETPLAY,
letter, m_settings.m_SaveDataRegion); letter, m_settings.save_data_region);
}; };
layer->Set(Config::MAIN_MEMCARD_A_PATH, make_memcard_path('A')); layer->Set(Config::MAIN_MEMCARD_A_PATH, make_memcard_path('A'));
layer->Set(Config::MAIN_MEMCARD_B_PATH, make_memcard_path('B')); layer->Set(Config::MAIN_MEMCARD_B_PATH, make_memcard_path('B'));
@ -140,14 +140,14 @@ public:
} }
#ifdef HAS_LIBMGBA #ifdef HAS_LIBMGBA
for (size_t i = 0; i < m_settings.m_GBARomPaths.size(); ++i) for (size_t i = 0; i < m_settings.gba_rom_paths.size(); ++i)
{ {
layer->Set(Config::MAIN_GBA_ROM_PATHS[i], m_settings.m_GBARomPaths[i]); layer->Set(Config::MAIN_GBA_ROM_PATHS[i], m_settings.gba_rom_paths[i]);
} }
#endif #endif
// Check To Override Client's Cheat Codes // Check To Override Client's Cheat Codes
if (m_settings.m_SyncCodes && !m_settings.m_IsHosting) if (m_settings.sync_codes && !m_settings.is_hosting)
{ {
// Raise flag to use host's codes // Raise flag to use host's codes
layer->Set(Config::SESSION_CODE_SYNC_OVERRIDE, true); layer->Set(Config::SESSION_CODE_SYNC_OVERRIDE, true);

View File

@ -511,7 +511,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
AudioCommon::InitSoundStream(); AudioCommon::InitSoundStream();
Common::ScopeGuard audio_guard{&AudioCommon::ShutdownSoundStream}; Common::ScopeGuard audio_guard{&AudioCommon::ShutdownSoundStream};
HW::Init(); HW::Init(NetPlay::IsNetPlayRunning() ? &(boot_session_data.GetNetplaySettings()->sram) : nullptr);
Common::ScopeGuard hw_guard{[] { Common::ScopeGuard hw_guard{[] {
// We must set up this flag before executing HW::Shutdown() // We must set up this flag before executing HW::Shutdown()

View File

@ -55,6 +55,11 @@ public:
OPCODE_CALLBACK(CPState& GetCPState()) { return m_cpmem; } OPCODE_CALLBACK(CPState& GetCPState()) { return m_cpmem; }
OPCODE_CALLBACK(u32 GetVertexSize(u8 vat))
{
return VertexLoaderBase::GetVertexSize(GetCPState().vtx_desc, GetCPState().vtx_attr[vat]);
}
bool m_start_of_primitives = false; bool m_start_of_primitives = false;
bool m_end_of_primitives = false; bool m_end_of_primitives = false;
bool m_efb_copy = false; bool m_efb_copy = false;

View File

@ -45,6 +45,11 @@ public:
OPCODE_CALLBACK(CPState& GetCPState()) { return m_cpmem; } OPCODE_CALLBACK(CPState& GetCPState()) { return m_cpmem; }
OPCODE_CALLBACK(u32 GetVertexSize(u8 vat))
{
return VertexLoaderBase::GetVertexSize(GetCPState().vtx_desc, GetCPState().vtx_attr[vat]);
}
private: private:
void ProcessVertexComponent(CPArray array_index, VertexComponentFormat array_type, void ProcessVertexComponent(CPArray array_index, VertexComponentFormat array_type,
u32 component_offset, u32 vertex_size, u16 num_vertices, u32 component_offset, u32 vertex_size, u16 num_vertices,

View File

@ -8,6 +8,7 @@
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/IOFile.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
@ -20,11 +21,11 @@
#include "Core/HW/Sram.h" #include "Core/HW/Sram.h"
#include "Core/HW/SystemTimers.h" #include "Core/HW/SystemTimers.h"
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/System.h"
#include "DiscIO/Enums.h" #include "DiscIO/Enums.h"
Sram g_SRAM; bool s_using_overridden_sram = false;
bool g_SRAM_netplay_initialized = false;
namespace ExpansionInterface namespace ExpansionInterface
{ {
@ -102,11 +103,18 @@ u8 SlotToEXIDevice(Slot slot)
} }
} }
void Init() void Init(const Sram* override_sram)
{ {
if (!g_SRAM_netplay_initialized) auto& sram = Core::System::GetInstance().GetSRAM();
if (override_sram)
{ {
InitSRAM(); sram = *override_sram;
s_using_overridden_sram = true;
}
else
{
InitSRAM(&sram, SConfig::GetInstance().m_strSRAM);
s_using_overridden_sram = false;
} }
CEXIMemoryCard::Init(); CEXIMemoryCard::Init();
@ -118,9 +126,9 @@ void Init()
size_mbits = Memcard::MBIT_SIZE_MEMORY_CARD_59 << size_override; size_mbits = Memcard::MBIT_SIZE_MEMORY_CARD_59 << size_override;
const bool shift_jis = const bool shift_jis =
Config::ToGameCubeRegion(SConfig::GetInstance().m_region) == DiscIO::Region::NTSC_J; Config::ToGameCubeRegion(SConfig::GetInstance().m_region) == DiscIO::Region::NTSC_J;
const CardFlashId& flash_id = g_SRAM.settings_ex.flash_id[Memcard::SLOT_A]; const CardFlashId& flash_id = sram.settings_ex.flash_id[Memcard::SLOT_A];
const u32 rtc_bias = g_SRAM.settings.rtc_bias; const u32 rtc_bias = sram.settings.rtc_bias;
const u32 sram_language = static_cast<u32>(g_SRAM.settings.language); const u32 sram_language = static_cast<u32>(sram.settings.language);
const u64 format_time = const u64 format_time =
Common::Timer::GetLocalTimeSinceJan1970() - ExpansionInterface::CEXIIPL::GC_EPOCH; Common::Timer::GetLocalTimeSinceJan1970() - ExpansionInterface::CEXIIPL::GC_EPOCH;
@ -151,6 +159,13 @@ void Shutdown()
channel.reset(); channel.reset();
CEXIMemoryCard::Shutdown(); CEXIMemoryCard::Shutdown();
if (!s_using_overridden_sram)
{
File::IOFile file(SConfig::GetInstance().m_strSRAM, "wb");
auto& sram = Core::System::GetInstance().GetSRAM();
file.WriteArray(&sram, 1);
}
} }
void DoState(PointerWrap& p) void DoState(PointerWrap& p)

View File

@ -10,6 +10,7 @@
#include "Core/CoreTiming.h" #include "Core/CoreTiming.h"
class PointerWrap; class PointerWrap;
struct Sram;
namespace CoreTiming namespace CoreTiming
{ {
@ -51,7 +52,7 @@ constexpr bool IsMemcardSlot(Slot slot)
u8 SlotToEXIChannel(Slot slot); u8 SlotToEXIChannel(Slot slot);
u8 SlotToEXIDevice(Slot slot); u8 SlotToEXIDevice(Slot slot);
void Init(); void Init(const Sram* override_sram);
void Shutdown(); void Shutdown();
void DoState(PointerWrap& p); void DoState(PointerWrap& p);
void PauseAndLock(bool doLock, bool unpauseOnUnlock); void PauseAndLock(bool doLock, bool unpauseOnUnlock);

View File

@ -28,6 +28,7 @@
#include "Core/HW/SystemTimers.h" #include "Core/HW/SystemTimers.h"
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/NetPlayProto.h" #include "Core/NetPlayProto.h"
#include "Core/System.h"
#include "DiscIO/Enums.h" #include "DiscIO/Enums.h"
@ -129,28 +130,25 @@ CEXIIPL::CEXIIPL()
LoadFontFile((File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + FONT_WINDOWS_1252), 0x1fcf00); LoadFontFile((File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + FONT_WINDOWS_1252), 0x1fcf00);
} }
auto& sram = Core::System::GetInstance().GetSRAM();
// Clear RTC // Clear RTC
g_SRAM.rtc = 0; sram.rtc = 0;
// We Overwrite language selection here since it's possible on the GC to change the language as // We Overwrite language selection here since it's possible on the GC to change the language as
// you please // you please
g_SRAM.settings.language = Config::Get(Config::MAIN_GC_LANGUAGE); sram.settings.language = Config::Get(Config::MAIN_GC_LANGUAGE);
g_SRAM.settings.rtc_bias = 0; sram.settings.rtc_bias = 0;
FixSRAMChecksums(); FixSRAMChecksums(&sram);
} }
CEXIIPL::~CEXIIPL() CEXIIPL::~CEXIIPL() = default;
{
// SRAM
if (!g_SRAM_netplay_initialized)
{
File::IOFile file(SConfig::GetInstance().m_strSRAM, "wb");
file.WriteArray(&g_SRAM, 1);
}
}
void CEXIIPL::DoState(PointerWrap& p) void CEXIIPL::DoState(PointerWrap& p)
{ {
p.Do(g_SRAM); auto& sram = Core::System::GetInstance().GetSRAM();
p.Do(sram);
p.Do(g_rtc_flags); p.Do(g_rtc_flags);
p.Do(m_command); p.Do(m_command);
p.Do(m_command_bytes_received); p.Do(m_command_bytes_received);
@ -253,7 +251,8 @@ void CEXIIPL::SetCS(int cs)
void CEXIIPL::UpdateRTC() void CEXIIPL::UpdateRTC()
{ {
g_SRAM.rtc = GetEmulatedTime(GC_EPOCH); auto& sram = Core::System::GetInstance().GetSRAM();
sram.rtc = GetEmulatedTime(GC_EPOCH);
} }
bool CEXIIPL::IsPresent() const bool CEXIIPL::IsPresent() const
@ -343,11 +342,12 @@ void CEXIIPL::TransferByte(u8& data)
} }
else if (IN_RANGE(SRAM)) else if (IN_RANGE(SRAM))
{ {
auto& sram = Core::System::GetInstance().GetSRAM();
u32 dev_addr = DEV_ADDR_CURSOR(SRAM); u32 dev_addr = DEV_ADDR_CURSOR(SRAM);
if (m_command.is_write()) if (m_command.is_write())
g_SRAM[dev_addr] = data; sram[dev_addr] = data;
else else
data = g_SRAM[dev_addr]; data = sram[dev_addr];
} }
else if (IN_RANGE(UART)) else if (IN_RANGE(UART))
{ {

View File

@ -34,6 +34,7 @@
#include "Core/HW/Sram.h" #include "Core/HW/Sram.h"
#include "Core/HW/SystemTimers.h" #include "Core/HW/SystemTimers.h"
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/System.h"
#include "DiscIO/Enums.h" #include "DiscIO/Enums.h"
namespace ExpansionInterface namespace ExpansionInterface
@ -141,7 +142,8 @@ CEXIMemoryCard::CEXIMemoryCard(const Slot slot, bool gci_folder,
m_memory_card_size = m_memory_card->GetCardId() * SIZE_TO_Mb; m_memory_card_size = m_memory_card->GetCardId() * SIZE_TO_Mb;
std::array<u8, 20> header{}; std::array<u8, 20> header{};
m_memory_card->Read(0, static_cast<s32>(header.size()), header.data()); m_memory_card->Read(0, static_cast<s32>(header.size()), header.data());
SetCardFlashID(header.data(), m_card_slot); auto& sram = Core::System::GetInstance().GetSRAM();
SetCardFlashID(&sram, header.data(), m_card_slot);
} }
std::pair<std::string /* path */, bool /* migrate */> std::pair<std::string /* path */, bool /* migrate */>

View File

@ -30,6 +30,7 @@
#include "Core/HW/EXI/EXI_DeviceIPL.h" #include "Core/HW/EXI/EXI_DeviceIPL.h"
#include "Core/HW/GCMemcard/GCMemcard.h" #include "Core/HW/GCMemcard/GCMemcard.h"
#include "Core/HW/Sram.h" #include "Core/HW/Sram.h"
#include "Core/System.h"
#define SIZE_TO_Mb (1024 * 8 * 16) #define SIZE_TO_Mb (1024 * 8 * 16)
#define MC_HDR_SIZE 0xA000 #define MC_HDR_SIZE 0xA000
@ -59,10 +60,11 @@ MemoryCard::MemoryCard(const std::string& filename, ExpansionInterface::Slot car
m_memcard_data = std::make_unique<u8[]>(m_memory_card_size); m_memcard_data = std::make_unique<u8[]>(m_memory_card_size);
// Fills in the first 5 blocks (MC_HDR_SIZE bytes) // Fills in the first 5 blocks (MC_HDR_SIZE bytes)
const CardFlashId& flash_id = g_SRAM.settings_ex.flash_id[Memcard::SLOT_A]; auto& sram = Core::System::GetInstance().GetSRAM();
const CardFlashId& flash_id = sram.settings_ex.flash_id[Memcard::SLOT_A];
const bool shift_jis = m_filename.find(".JAP.raw") != std::string::npos; const bool shift_jis = m_filename.find(".JAP.raw") != std::string::npos;
const u32 rtc_bias = g_SRAM.settings.rtc_bias; const u32 rtc_bias = sram.settings.rtc_bias;
const u32 sram_language = static_cast<u32>(g_SRAM.settings.language); const u32 sram_language = static_cast<u32>(sram.settings.language);
const u64 format_time = const u64 format_time =
Common::Timer::GetLocalTimeSinceJan1970() - ExpansionInterface::CEXIIPL::GC_EPOCH; Common::Timer::GetLocalTimeSinceJan1970() - ExpansionInterface::CEXIIPL::GC_EPOCH;
Memcard::GCMemcard::Format(&m_memcard_data[0], flash_id, size_mbits, shift_jis, rtc_bias, Memcard::GCMemcard::Format(&m_memcard_data[0], flash_id, size_mbits, shift_jis, rtc_bias,

View File

@ -31,7 +31,7 @@
namespace HW namespace HW
{ {
void Init() void Init(const Sram* override_sram)
{ {
CoreTiming::Init(); CoreTiming::Init();
SystemTimers::PreInit(); SystemTimers::PreInit();
@ -43,7 +43,7 @@ void Init()
VideoInterface::Init(); VideoInterface::Init();
SerialInterface::Init(); SerialInterface::Init();
ProcessorInterface::Init(); ProcessorInterface::Init();
ExpansionInterface::Init(); // Needs to be initialized before Memory ExpansionInterface::Init(override_sram); // Needs to be initialized before Memory
HSP::Init(); HSP::Init();
Memory::Init(); // Needs to be initialized before AddressSpace Memory::Init(); // Needs to be initialized before AddressSpace
AddressSpace::Init(); AddressSpace::Init();

View File

@ -4,10 +4,11 @@
#pragma once #pragma once
class PointerWrap; class PointerWrap;
struct Sram;
namespace HW namespace HW
{ {
void Init(); void Init(const Sram* override_sram);
void Shutdown(); void Shutdown();
void DoState(PointerWrap& p); void DoState(PointerWrap& p);
} // namespace HW } // namespace HW

View File

@ -9,7 +9,6 @@
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "Common/Swap.h" #include "Common/Swap.h"
#include "Core/ConfigManager.h"
#include "Core/HW/EXI/EXI.h" #include "Core/HW/EXI/EXI.h"
// English // English
@ -58,24 +57,24 @@ const SRAM sram_dump_german = {{
}}; }};
#endif #endif
void InitSRAM() void InitSRAM(Sram* sram, const std::string& filename)
{ {
File::IOFile file(SConfig::GetInstance().m_strSRAM, "rb"); File::IOFile file(filename, "rb");
if (file) if (file)
{ {
if (!file.ReadArray(&g_SRAM, 1)) if (!file.ReadArray(sram, 1))
{ {
ERROR_LOG_FMT(EXPANSIONINTERFACE, "EXI IPL-DEV: Could not read all of SRAM"); ERROR_LOG_FMT(EXPANSIONINTERFACE, "EXI IPL-DEV: Could not read all of SRAM");
g_SRAM = sram_dump; *sram = sram_dump;
} }
} }
else else
{ {
g_SRAM = sram_dump; *sram = sram_dump;
} }
} }
void SetCardFlashID(const u8* buffer, ExpansionInterface::Slot card_slot) void SetCardFlashID(Sram* sram, const u8* buffer, ExpansionInterface::Slot card_slot)
{ {
u8 card_index; u8 card_index;
switch (card_slot) switch (card_slot)
@ -96,25 +95,25 @@ void SetCardFlashID(const u8* buffer, ExpansionInterface::Slot card_slot)
for (int i = 0; i < 12; i++) for (int i = 0; i < 12; i++)
{ {
rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16);
csum += g_SRAM.settings_ex.flash_id[card_index][i] = buffer[i] - ((u8)rand & 0xff); csum += sram->settings_ex.flash_id[card_index][i] = buffer[i] - ((u8)rand & 0xff);
rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16);
rand &= (u64)0x0000000000007fffULL; rand &= (u64)0x0000000000007fffULL;
} }
g_SRAM.settings_ex.flash_id_checksum[card_index] = csum ^ 0xFF; sram->settings_ex.flash_id_checksum[card_index] = csum ^ 0xFF;
} }
void FixSRAMChecksums() void FixSRAMChecksums(Sram* sram)
{ {
// 16bit big-endian additive checksum // 16bit big-endian additive checksum
u16 checksum = 0; u16 checksum = 0;
u16 checksum_inv = 0; u16 checksum_inv = 0;
for (auto p = reinterpret_cast<u16*>(&g_SRAM.settings.rtc_bias); for (auto p = reinterpret_cast<u16*>(&sram->settings.rtc_bias);
p != reinterpret_cast<u16*>(&g_SRAM.settings_ex); p++) p != reinterpret_cast<u16*>(&sram->settings_ex); p++)
{ {
u16 value = Common::FromBigEndian(*p); u16 value = Common::FromBigEndian(*p);
checksum += value; checksum += value;
checksum_inv += ~value; checksum_inv += ~value;
} }
g_SRAM.settings.checksum = checksum; sram->settings.checksum = checksum;
g_SRAM.settings.checksum_inv = checksum_inv; sram->settings.checksum_inv = checksum_inv;
} }

View File

@ -34,6 +34,7 @@ distribution.
#pragma once #pragma once
#include <array> #include <array>
#include <string>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Swap.h" #include "Common/Swap.h"
@ -133,9 +134,6 @@ static_assert(sizeof(Sram) == 0x44);
#pragma pack(pop) #pragma pack(pop)
void InitSRAM(); void InitSRAM(Sram* sram, const std::string& filename);
void SetCardFlashID(const u8* buffer, ExpansionInterface::Slot card_slot); void SetCardFlashID(Sram* sram, const u8* buffer, ExpansionInterface::Slot card_slot);
void FixSRAMChecksums(); void FixSRAMChecksums(Sram* sram);
extern Sram g_SRAM;
extern bool g_SRAM_netplay_initialized;

View File

@ -432,10 +432,6 @@ void NetPlayClient::OnData(sf::Packet& packet)
OnDesyncDetected(packet); OnDesyncDetected(packet);
break; break;
case MessageID::SyncGCSRAM:
OnSyncGCSRAM(packet);
break;
case MessageID::SyncSaveData: case MessageID::SyncSaveData:
OnSyncSaveData(packet); OnSyncSaveData(packet);
break; break;
@ -635,7 +631,7 @@ void NetPlayClient::OnGBAConfig(sf::Packet& packet)
std::tie(old_config.has_rom, old_config.title, old_config.hash)) std::tie(old_config.has_rom, old_config.title, old_config.hash))
{ {
m_dialog->OnMsgChangeGBARom(static_cast<int>(i), config); m_dialog->OnMsgChangeGBARom(static_cast<int>(i), config);
m_net_settings.m_GBARomPaths[i] = m_net_settings.gba_rom_paths[i] =
config.has_rom ? config.has_rom ?
m_dialog->FindGBARomPath(config.hash, config.title, static_cast<int>(i)) : m_dialog->FindGBARomPath(config.hash, config.title, static_cast<int>(i)) :
""; "";
@ -809,92 +805,94 @@ void NetPlayClient::OnStartGame(sf::Packet& packet)
INFO_LOG_FMT(NETPLAY, "Start of game {}", m_selected_game.game_id); INFO_LOG_FMT(NETPLAY, "Start of game {}", m_selected_game.game_id);
packet >> m_current_game; packet >> m_current_game;
packet >> m_net_settings.m_CPUthread; packet >> m_net_settings.cpu_thread;
packet >> m_net_settings.m_CPUcore; packet >> m_net_settings.cpu_core;
packet >> m_net_settings.m_EnableCheats; packet >> m_net_settings.enable_cheats;
packet >> m_net_settings.m_SelectedLanguage; packet >> m_net_settings.selected_language;
packet >> m_net_settings.m_OverrideRegionSettings; packet >> m_net_settings.override_region_settings;
packet >> m_net_settings.m_DSPEnableJIT; packet >> m_net_settings.dsp_enable_jit;
packet >> m_net_settings.m_DSPHLE; packet >> m_net_settings.dsp_hle;
packet >> m_net_settings.m_WriteToMemcard; packet >> m_net_settings.write_to_memcard;
packet >> m_net_settings.m_RAMOverrideEnable; packet >> m_net_settings.ram_override_enable;
packet >> m_net_settings.m_Mem1Size; packet >> m_net_settings.mem1_size;
packet >> m_net_settings.m_Mem2Size; packet >> m_net_settings.mem2_size;
packet >> m_net_settings.m_FallbackRegion; packet >> m_net_settings.fallback_region;
packet >> m_net_settings.m_AllowSDWrites; packet >> m_net_settings.allow_sd_writes;
packet >> m_net_settings.m_CopyWiiSave; packet >> m_net_settings.copy_wii_save;
packet >> m_net_settings.m_OCEnable; packet >> m_net_settings.oc_enable;
packet >> m_net_settings.m_OCFactor; packet >> m_net_settings.oc_factor;
for (auto slot : ExpansionInterface::SLOTS) for (auto slot : ExpansionInterface::SLOTS)
packet >> m_net_settings.m_EXIDevice[slot]; packet >> m_net_settings.exi_device[slot];
packet >> m_net_settings.m_MemcardSizeOverride; packet >> m_net_settings.memcard_size_override;
for (u32& value : m_net_settings.m_SYSCONFSettings) for (u32& value : m_net_settings.sysconf_settings)
packet >> value; packet >> value;
packet >> m_net_settings.m_EFBAccessEnable; packet >> m_net_settings.efb_access_enable;
packet >> m_net_settings.m_BBoxEnable; packet >> m_net_settings.bbox_enable;
packet >> m_net_settings.m_ForceProgressive; packet >> m_net_settings.force_progressive;
packet >> m_net_settings.m_EFBToTextureEnable; packet >> m_net_settings.efb_to_texture_enable;
packet >> m_net_settings.m_XFBToTextureEnable; packet >> m_net_settings.xfb_to_texture_enable;
packet >> m_net_settings.m_DisableCopyToVRAM; packet >> m_net_settings.disable_copy_to_vram;
packet >> m_net_settings.m_ImmediateXFBEnable; packet >> m_net_settings.immediate_xfb_enable;
packet >> m_net_settings.m_EFBEmulateFormatChanges; packet >> m_net_settings.efb_emulate_format_changes;
packet >> m_net_settings.m_SafeTextureCacheColorSamples; packet >> m_net_settings.safe_texture_cache_color_samples;
packet >> m_net_settings.m_PerfQueriesEnable; packet >> m_net_settings.perf_queries_enable;
packet >> m_net_settings.m_FloatExceptions; packet >> m_net_settings.float_exceptions;
packet >> m_net_settings.m_DivideByZeroExceptions; packet >> m_net_settings.divide_by_zero_exceptions;
packet >> m_net_settings.m_FPRF; packet >> m_net_settings.fprf;
packet >> m_net_settings.m_AccurateNaNs; packet >> m_net_settings.accurate_nans;
packet >> m_net_settings.m_DisableICache; packet >> m_net_settings.disable_icache;
packet >> m_net_settings.m_SyncOnSkipIdle; packet >> m_net_settings.sync_on_skip_idle;
packet >> m_net_settings.m_SyncGPU; packet >> m_net_settings.sync_gpu;
packet >> m_net_settings.m_SyncGpuMaxDistance; packet >> m_net_settings.sync_gpu_max_distance;
packet >> m_net_settings.m_SyncGpuMinDistance; packet >> m_net_settings.sync_gpu_min_distance;
packet >> m_net_settings.m_SyncGpuOverclock; packet >> m_net_settings.sync_gpu_overclock;
packet >> m_net_settings.m_JITFollowBranch; packet >> m_net_settings.jit_follow_branch;
packet >> m_net_settings.m_FastDiscSpeed; packet >> m_net_settings.fast_disc_speed;
packet >> m_net_settings.m_MMU; packet >> m_net_settings.mmu;
packet >> m_net_settings.m_Fastmem; packet >> m_net_settings.fastmem;
packet >> m_net_settings.m_SkipIPL; packet >> m_net_settings.skip_ipl;
packet >> m_net_settings.m_LoadIPLDump; packet >> m_net_settings.load_ipl_dump;
packet >> m_net_settings.m_VertexRounding; packet >> m_net_settings.vertex_rounding;
packet >> m_net_settings.m_InternalResolution; packet >> m_net_settings.internal_resolution;
packet >> m_net_settings.m_EFBScaledCopy; packet >> m_net_settings.efb_scaled_copy;
packet >> m_net_settings.m_FastDepthCalc; packet >> m_net_settings.fast_depth_calc;
packet >> m_net_settings.m_EnablePixelLighting; packet >> m_net_settings.enable_pixel_lighting;
packet >> m_net_settings.m_WidescreenHack; packet >> m_net_settings.widescreen_hack;
packet >> m_net_settings.m_ForceFiltering; packet >> m_net_settings.force_filtering;
packet >> m_net_settings.m_MaxAnisotropy; packet >> m_net_settings.max_anisotropy;
packet >> m_net_settings.m_ForceTrueColor; packet >> m_net_settings.force_true_color;
packet >> m_net_settings.m_DisableCopyFilter; packet >> m_net_settings.disable_copy_filter;
packet >> m_net_settings.m_DisableFog; packet >> m_net_settings.disable_fog;
packet >> m_net_settings.m_ArbitraryMipmapDetection; packet >> m_net_settings.arbitrary_mipmap_detection;
packet >> m_net_settings.m_ArbitraryMipmapDetectionThreshold; packet >> m_net_settings.arbitrary_mipmap_detection_threshold;
packet >> m_net_settings.m_EnableGPUTextureDecoding; packet >> m_net_settings.enable_gpu_texture_decoding;
packet >> m_net_settings.m_DeferEFBCopies; packet >> m_net_settings.defer_efb_copies;
packet >> m_net_settings.m_EFBAccessTileSize; packet >> m_net_settings.efb_access_tile_size;
packet >> m_net_settings.m_EFBAccessDeferInvalidation; packet >> m_net_settings.efb_access_defer_invalidation;
packet >> m_net_settings.m_StrictSettingsSync; packet >> m_net_settings.strict_settings_sync;
m_initial_rtc = Common::PacketReadU64(packet); m_initial_rtc = Common::PacketReadU64(packet);
packet >> m_net_settings.m_SyncSaveData; packet >> m_net_settings.sync_save_data;
packet >> m_net_settings.m_SaveDataRegion; packet >> m_net_settings.save_data_region;
packet >> m_net_settings.m_SyncCodes; packet >> m_net_settings.sync_codes;
packet >> m_net_settings.m_SyncAllWiiSaves; packet >> m_net_settings.sync_all_wii_saves;
for (int& extension : m_net_settings.m_WiimoteExtension) for (int& extension : m_net_settings.wiimote_extension)
packet >> extension; packet >> extension;
packet >> m_net_settings.m_GolfMode; packet >> m_net_settings.golf_mode;
packet >> m_net_settings.m_UseFMA; packet >> m_net_settings.use_fma;
packet >> m_net_settings.m_HideRemoteGBAs; packet >> m_net_settings.hide_remote_gbas;
m_net_settings.m_IsHosting = m_local_player->IsHost(); for (size_t i = 0; i < sizeof(m_net_settings.sram); ++i)
m_net_settings.m_HostInputAuthority = m_host_input_authority; packet >> m_net_settings.sram[i];
m_net_settings.is_hosting = m_local_player->IsHost();
} }
m_dialog->OnMsgStartGame(); m_dialog->OnMsgStartGame();
@ -910,6 +908,7 @@ void NetPlayClient::OnStopGame(sf::Packet& packet)
void NetPlayClient::OnPowerButton() void NetPlayClient::OnPowerButton()
{ {
InvokeStop();
m_dialog->OnMsgPowerButton(); m_dialog->OnMsgPowerButton();
} }
@ -960,20 +959,6 @@ void NetPlayClient::OnDesyncDetected(sf::Packet& packet)
m_dialog->OnDesync(frame, player); m_dialog->OnDesync(frame, player);
} }
void NetPlayClient::OnSyncGCSRAM(sf::Packet& packet)
{
const size_t sram_settings_len = sizeof(g_SRAM) - offsetof(Sram, settings);
u8 sram[sram_settings_len];
for (u8& cell : sram)
packet >> cell;
{
std::lock_guard lkg(m_crit.game);
memcpy(&g_SRAM.settings, sram, sram_settings_len);
g_SRAM_netplay_initialized = true;
}
}
void NetPlayClient::OnSyncSaveData(sf::Packet& packet) void NetPlayClient::OnSyncSaveData(sf::Packet& packet)
{ {
SyncSaveDataID sub_id; SyncSaveDataID sub_id;
@ -2048,6 +2033,22 @@ u64 NetPlayClient::GetInitialRTCValue() const
return m_initial_rtc; return m_initial_rtc;
} }
bool NetPlayClient::WaitForWiimoteBuffer(int _number)
{
while (m_wiimote_buffer[_number].Size() == 0)
{
if (!m_is_running.IsSet())
{
return false;
}
// wait for receiving thread to push some data
m_wii_pad_event.Wait();
}
return true;
}
// called from ---CPU--- thread // called from ---CPU--- thread
bool NetPlayClient::WiimoteUpdate(int _number, u8* data, const std::size_t size, u8 reporting_mode) bool NetPlayClient::WiimoteUpdate(int _number, u8* data, const std::size_t size, u8 reporting_mode)
{ {
@ -2073,16 +2074,8 @@ bool NetPlayClient::WiimoteUpdate(int _number, u8* data, const std::size_t size,
} // unlock players } // unlock players
while (m_wiimote_buffer[_number].Size() == 0) if (!WaitForWiimoteBuffer(_number))
{
if (!m_is_running.IsSet())
{
return false; return false;
}
// wait for receiving thread to push some data
m_wii_pad_event.Wait();
}
m_wiimote_buffer[_number].Pop(nw); m_wiimote_buffer[_number].Pop(nw);
@ -2093,16 +2086,8 @@ bool NetPlayClient::WiimoteUpdate(int _number, u8* data, const std::size_t size,
u32 tries = 0; u32 tries = 0;
while (nw.report_id != reporting_mode) while (nw.report_id != reporting_mode)
{ {
while (m_wiimote_buffer[_number].Size() == 0) if (!WaitForWiimoteBuffer(_number))
{
if (!m_is_running.IsSet())
{
return false; return false;
}
// wait for receiving thread to push some data
m_wii_pad_event.Wait();
}
m_wiimote_buffer[_number].Pop(nw); m_wiimote_buffer[_number].Pop(nw);
@ -2244,8 +2229,7 @@ void NetPlayClient::SendPadHostPoll(const PadIndex pad_num)
SendAsync(std::move(packet)); SendAsync(std::move(packet));
} }
// called from ---GUI--- thread and ---NETPLAY--- thread (client side) void NetPlayClient::InvokeStop()
bool NetPlayClient::StopGame()
{ {
m_is_running.Clear(); m_is_running.Clear();
@ -2254,6 +2238,12 @@ bool NetPlayClient::StopGame()
m_wii_pad_event.Set(); m_wii_pad_event.Set();
m_first_pad_status_received_event.Set(); m_first_pad_status_received_event.Set();
m_wait_on_input_event.Set(); m_wait_on_input_event.Set();
}
// called from ---GUI--- thread and ---NETPLAY--- thread (client side)
bool NetPlayClient::StopGame()
{
InvokeStop();
NetPlay_Disable(); NetPlay_Disable();
@ -2269,13 +2259,7 @@ void NetPlayClient::Stop()
if (!m_is_running.IsSet()) if (!m_is_running.IsSet())
return; return;
m_is_running.Clear(); InvokeStop();
// stop waiting for input
m_gc_pad_event.Set();
m_wii_pad_event.Set();
m_first_pad_status_received_event.Set();
m_wait_on_input_event.Set();
// Tell the server to stop if we have a pad mapped in game. // Tell the server to stop if we have a pad mapped in game.
if (LocalPlayerHasControllerMapped()) if (LocalPlayerHasControllerMapped())
@ -2300,7 +2284,7 @@ void NetPlayClient::SendPowerButtonEvent()
void NetPlayClient::RequestGolfControl(const PlayerId pid) void NetPlayClient::RequestGolfControl(const PlayerId pid)
{ {
if (!m_host_input_authority || !m_net_settings.m_GolfMode) if (!m_host_input_authority || !m_net_settings.golf_mode)
return; return;
sf::Packet packet; sf::Packet packet;
@ -2402,7 +2386,7 @@ void NetPlayClient::SendGameStatus()
for (size_t i = 0; i < 4; ++i) for (size_t i = 0; i < 4; ++i)
{ {
if (m_gba_config[i].enabled && m_gba_config[i].has_rom && if (m_gba_config[i].enabled && m_gba_config[i].has_rom &&
m_net_settings.m_GBARomPaths[i].empty()) m_net_settings.gba_rom_paths[i].empty())
{ {
result = SyncIdentifierComparison::DifferentGame; result = SyncIdentifierComparison::DifferentGame;
} }
@ -2592,7 +2576,7 @@ bool IsSyncingAllWiiSaves()
std::lock_guard lk(crit_netplay_client); std::lock_guard lk(crit_netplay_client);
if (netplay_client) if (netplay_client)
return netplay_client->GetNetSettings().m_SyncAllWiiSaves; return netplay_client->GetNetSettings().sync_all_wii_saves;
return false; return false;
} }
@ -2602,14 +2586,14 @@ void SetupWiimotes()
ASSERT(IsNetPlayRunning()); ASSERT(IsNetPlayRunning());
const NetSettings& netplay_settings = netplay_client->GetNetSettings(); const NetSettings& netplay_settings = netplay_client->GetNetSettings();
const PadMappingArray& wiimote_map = netplay_client->GetWiimoteMapping(); const PadMappingArray& wiimote_map = netplay_client->GetWiimoteMapping();
for (size_t i = 0; i < netplay_settings.m_WiimoteExtension.size(); i++) for (size_t i = 0; i < netplay_settings.wiimote_extension.size(); i++)
{ {
if (wiimote_map[i] > 0) if (wiimote_map[i] > 0)
{ {
static_cast<ControllerEmu::Attachments*>( static_cast<ControllerEmu::Attachments*>(
static_cast<WiimoteEmu::Wiimote*>(Wiimote::GetConfig()->GetController(int(i))) static_cast<WiimoteEmu::Wiimote*>(Wiimote::GetConfig()->GetController(int(i)))
->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Attachments)) ->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Attachments))
->SetSelectedAttachment(netplay_settings.m_WiimoteExtension[i]); ->SetSelectedAttachment(netplay_settings.wiimote_extension[i]);
} }
} }
} }
@ -2618,7 +2602,7 @@ std::string GetGBASavePath(int pad_num)
{ {
std::lock_guard lk(crit_netplay_client); std::lock_guard lk(crit_netplay_client);
if (!netplay_client || netplay_client->GetNetSettings().m_IsHosting) if (!netplay_client || netplay_client->GetNetSettings().is_hosting)
{ {
#ifdef HAS_LIBMGBA #ifdef HAS_LIBMGBA
std::string rom_path = Config::Get(Config::MAIN_GBA_ROM_PATHS[pad_num]); std::string rom_path = Config::Get(Config::MAIN_GBA_ROM_PATHS[pad_num]);
@ -2628,7 +2612,7 @@ std::string GetGBASavePath(int pad_num)
#endif #endif
} }
if (!netplay_client->GetNetSettings().m_SyncSaveData) if (!netplay_client->GetNetSettings().sync_save_data)
return {}; return {};
return fmt::format("{}{}{}.sav", File::GetUserPath(D_GBAUSER_IDX), GBA_SAVE_NETPLAY, pad_num + 1); return fmt::format("{}{}{}.sav", File::GetUserPath(D_GBAUSER_IDX), GBA_SAVE_NETPLAY, pad_num + 1);
@ -2664,7 +2648,7 @@ PadDetails GetPadDetails(int pad_num)
} }
res.is_local = netplay_client->IsLocalPlayer(pad_map[pad_num]); res.is_local = netplay_client->IsLocalPlayer(pad_map[pad_num]);
res.local_pad = res.is_local ? local_pad : netplay_client->NumLocalPads() + non_local_pad; res.local_pad = res.is_local ? local_pad : netplay_client->NumLocalPads() + non_local_pad;
res.hide_gba = !res.is_local && netplay_client->GetNetSettings().m_HideRemoteGBAs && res.hide_gba = !res.is_local && netplay_client->GetNetSettings().hide_remote_gbas &&
netplay_client->LocalPlayerHasControllerMapped(); netplay_client->LocalPlayerHasControllerMapped();
return res; return res;
} }

View File

@ -117,6 +117,7 @@ public:
// Called from the GUI thread. // Called from the GUI thread.
bool IsConnected() const { return m_is_connected; } bool IsConnected() const { return m_is_connected; }
bool StartGame(const std::string& path); bool StartGame(const std::string& path);
void InvokeStop();
bool StopGame(); bool StopGame();
void Stop(); void Stop();
bool ChangeGame(const std::string& game); bool ChangeGame(const std::string& game);
@ -252,6 +253,8 @@ private:
void DisplayPlayersPing(); void DisplayPlayersPing();
u32 GetPlayersMaxPing() const; u32 GetPlayersMaxPing() const;
bool WaitForWiimoteBuffer(int _number);
void OnData(sf::Packet& packet); void OnData(sf::Packet& packet);
void OnPlayerJoin(sf::Packet& packet); void OnPlayerJoin(sf::Packet& packet);
void OnPlayerLeave(sf::Packet& packet); void OnPlayerLeave(sf::Packet& packet);
@ -278,7 +281,6 @@ private:
void OnPing(sf::Packet& packet); void OnPing(sf::Packet& packet);
void OnPlayerPingData(sf::Packet& packet); void OnPlayerPingData(sf::Packet& packet);
void OnDesyncDetected(sf::Packet& packet); void OnDesyncDetected(sf::Packet& packet);
void OnSyncGCSRAM(sf::Packet& packet);
void OnSyncSaveData(sf::Packet& packet); void OnSyncSaveData(sf::Packet& packet);
void OnSyncSaveDataNotify(sf::Packet& packet); void OnSyncSaveDataNotify(sf::Packet& packet);
void OnSyncSaveDataRaw(sf::Packet& packet); void OnSyncSaveDataRaw(sf::Packet& packet);

View File

@ -12,6 +12,7 @@
#include "Core/Config/SYSCONFSettings.h" #include "Core/Config/SYSCONFSettings.h"
#include "Core/HW/EXI/EXI.h" #include "Core/HW/EXI/EXI.h"
#include "Core/HW/EXI/EXI_Device.h" #include "Core/HW/EXI/EXI_Device.h"
#include "Core/HW/Sram.h"
namespace DiscIO namespace DiscIO
{ {
@ -30,85 +31,86 @@ namespace NetPlay
{ {
struct NetSettings struct NetSettings
{ {
bool m_CPUthread = false; bool cpu_thread = false;
PowerPC::CPUCore m_CPUcore{}; PowerPC::CPUCore cpu_core{};
bool m_EnableCheats = false; bool enable_cheats = false;
int m_SelectedLanguage = 0; int selected_language = 0;
bool m_OverrideRegionSettings = false; bool override_region_settings = false;
bool m_DSPHLE = false; bool dsp_hle = false;
bool m_DSPEnableJIT = false; bool dsp_enable_jit = false;
bool m_WriteToMemcard = false; bool write_to_memcard = false;
bool m_RAMOverrideEnable = false; bool ram_override_enable = false;
u32 m_Mem1Size = 0; u32 mem1_size = 0;
u32 m_Mem2Size = 0; u32 mem2_size = 0;
DiscIO::Region m_FallbackRegion{}; DiscIO::Region fallback_region{};
bool m_AllowSDWrites = false; bool allow_sd_writes = false;
bool m_CopyWiiSave = false; bool copy_wii_save = false;
bool m_OCEnable = false; bool oc_enable = false;
float m_OCFactor = 0; float oc_factor = 0;
Common::EnumMap<ExpansionInterface::EXIDeviceType, ExpansionInterface::MAX_SLOT> m_EXIDevice{}; Common::EnumMap<ExpansionInterface::EXIDeviceType, ExpansionInterface::MAX_SLOT> exi_device{};
int m_MemcardSizeOverride = -1; int memcard_size_override = -1;
std::array<u32, Config::SYSCONF_SETTINGS.size()> m_SYSCONFSettings{}; std::array<u32, Config::SYSCONF_SETTINGS.size()> sysconf_settings{};
bool m_EFBAccessEnable = false; bool efb_access_enable = false;
bool m_BBoxEnable = false; bool bbox_enable = false;
bool m_ForceProgressive = false; bool force_progressive = false;
bool m_EFBToTextureEnable = false; bool efb_to_texture_enable = false;
bool m_XFBToTextureEnable = false; bool xfb_to_texture_enable = false;
bool m_DisableCopyToVRAM = false; bool disable_copy_to_vram = false;
bool m_ImmediateXFBEnable = false; bool immediate_xfb_enable = false;
bool m_EFBEmulateFormatChanges = false; bool efb_emulate_format_changes = false;
int m_SafeTextureCacheColorSamples = 0; int safe_texture_cache_color_samples = 0;
bool m_PerfQueriesEnable = false; bool perf_queries_enable = false;
bool m_FloatExceptions = false; bool float_exceptions = false;
bool m_DivideByZeroExceptions = false; bool divide_by_zero_exceptions = false;
bool m_FPRF = false; bool fprf = false;
bool m_AccurateNaNs = false; bool accurate_nans = false;
bool m_DisableICache = false; bool disable_icache = false;
bool m_SyncOnSkipIdle = false; bool sync_on_skip_idle = false;
bool m_SyncGPU = false; bool sync_gpu = false;
int m_SyncGpuMaxDistance = 0; int sync_gpu_max_distance = 0;
int m_SyncGpuMinDistance = 0; int sync_gpu_min_distance = 0;
float m_SyncGpuOverclock = 0; float sync_gpu_overclock = 0;
bool m_JITFollowBranch = false; bool jit_follow_branch = false;
bool m_FastDiscSpeed = false; bool fast_disc_speed = false;
bool m_MMU = false; bool mmu = false;
bool m_Fastmem = false; bool fastmem = false;
bool m_SkipIPL = false; bool skip_ipl = false;
bool m_LoadIPLDump = false; bool load_ipl_dump = false;
bool m_VertexRounding = false; bool vertex_rounding = false;
int m_InternalResolution = 0; int internal_resolution = 0;
bool m_EFBScaledCopy = false; bool efb_scaled_copy = false;
bool m_FastDepthCalc = false; bool fast_depth_calc = false;
bool m_EnablePixelLighting = false; bool enable_pixel_lighting = false;
bool m_WidescreenHack = false; bool widescreen_hack = false;
bool m_ForceFiltering = false; bool force_filtering = false;
int m_MaxAnisotropy = 0; int max_anisotropy = 0;
bool m_ForceTrueColor = false; bool force_true_color = false;
bool m_DisableCopyFilter = false; bool disable_copy_filter = false;
bool m_DisableFog = false; bool disable_fog = false;
bool m_ArbitraryMipmapDetection = false; bool arbitrary_mipmap_detection = false;
float m_ArbitraryMipmapDetectionThreshold = 0; float arbitrary_mipmap_detection_threshold = 0;
bool m_EnableGPUTextureDecoding = false; bool enable_gpu_texture_decoding = false;
bool m_DeferEFBCopies = false; bool defer_efb_copies = false;
int m_EFBAccessTileSize = 0; int efb_access_tile_size = 0;
bool m_EFBAccessDeferInvalidation = false; bool efb_access_defer_invalidation = false;
bool m_StrictSettingsSync = false; bool strict_settings_sync = false;
bool m_SyncSaveData = false; bool sync_save_data = false;
bool m_SyncCodes = false; bool sync_codes = false;
std::string m_SaveDataRegion; std::string save_data_region;
bool m_SyncAllWiiSaves = false; bool sync_all_wii_saves = false;
std::array<int, 4> m_WiimoteExtension{}; std::array<int, 4> wiimote_extension{};
bool m_GolfMode = false; bool golf_mode = false;
bool m_UseFMA = false; bool use_fma = false;
bool m_HideRemoteGBAs = false; bool hide_remote_gbas = false;
Sram sram;
// These aren't sent over the network directly // These aren't sent over the network directly
bool m_IsHosting = false; bool is_hosting = false;
bool m_HostInputAuthority = false; std::array<std::string, 4> gba_rom_paths{};
std::array<std::string, 4> m_GBARomPaths{};
}; };
struct NetTraversalConfig struct NetTraversalConfig
@ -181,7 +183,6 @@ enum class MessageID : u8
Pong = 0xE1, Pong = 0xE1,
PlayerPingData = 0xE2, PlayerPingData = 0xE2,
SyncGCSRAM = 0xF0,
SyncSaveData = 0xF1, SyncSaveData = 0xF1,
SyncCodes = 0xF2, SyncCodes = 0xF2,
}; };

View File

@ -862,7 +862,7 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
if (!m_players.count(pid) || !PlayerHasControllerMapped(player.pid)) if (!m_players.count(pid) || !PlayerHasControllerMapped(player.pid))
break; break;
if (m_host_input_authority && m_settings.m_GolfMode && m_pending_golfer == 0 && if (m_host_input_authority && m_settings.golf_mode && m_pending_golfer == 0 &&
m_current_golfer != pid && PlayerHasControllerMapped(pid)) m_current_golfer != pid && PlayerHasControllerMapped(pid))
{ {
m_pending_golfer = pid; m_pending_golfer = pid;
@ -1254,22 +1254,22 @@ bool NetPlayServer::SetupNetSettings()
ConfigLoaders::GenerateLocalGameConfigLoader(game->GetGameID(), game->GetRevision())); ConfigLoaders::GenerateLocalGameConfigLoader(game->GetGameID(), game->GetRevision()));
// Copy all relevant settings // Copy all relevant settings
settings.m_CPUthread = Config::Get(Config::MAIN_CPU_THREAD); settings.cpu_thread = Config::Get(Config::MAIN_CPU_THREAD);
settings.m_CPUcore = Config::Get(Config::MAIN_CPU_CORE); settings.cpu_core = Config::Get(Config::MAIN_CPU_CORE);
settings.m_EnableCheats = Config::Get(Config::MAIN_ENABLE_CHEATS); settings.enable_cheats = Config::Get(Config::MAIN_ENABLE_CHEATS);
settings.m_SelectedLanguage = Config::Get(Config::MAIN_GC_LANGUAGE); settings.selected_language = Config::Get(Config::MAIN_GC_LANGUAGE);
settings.m_OverrideRegionSettings = Config::Get(Config::MAIN_OVERRIDE_REGION_SETTINGS); settings.override_region_settings = Config::Get(Config::MAIN_OVERRIDE_REGION_SETTINGS);
settings.m_DSPHLE = Config::Get(Config::MAIN_DSP_HLE); settings.dsp_hle = Config::Get(Config::MAIN_DSP_HLE);
settings.m_DSPEnableJIT = Config::Get(Config::MAIN_DSP_JIT); settings.dsp_enable_jit = Config::Get(Config::MAIN_DSP_JIT);
settings.m_WriteToMemcard = Config::Get(Config::NETPLAY_WRITE_SAVE_DATA); settings.write_to_memcard = Config::Get(Config::NETPLAY_WRITE_SAVE_DATA);
settings.m_RAMOverrideEnable = Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE); settings.ram_override_enable = Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE);
settings.m_Mem1Size = Config::Get(Config::MAIN_MEM1_SIZE); settings.mem1_size = Config::Get(Config::MAIN_MEM1_SIZE);
settings.m_Mem2Size = Config::Get(Config::MAIN_MEM2_SIZE); settings.mem2_size = Config::Get(Config::MAIN_MEM2_SIZE);
settings.m_FallbackRegion = Config::Get(Config::MAIN_FALLBACK_REGION); settings.fallback_region = Config::Get(Config::MAIN_FALLBACK_REGION);
settings.m_AllowSDWrites = Config::Get(Config::MAIN_ALLOW_SD_WRITES); settings.allow_sd_writes = Config::Get(Config::MAIN_ALLOW_SD_WRITES);
settings.m_CopyWiiSave = Config::Get(Config::NETPLAY_LOAD_WII_SAVE); settings.copy_wii_save = Config::Get(Config::NETPLAY_LOAD_WII_SAVE);
settings.m_OCEnable = Config::Get(Config::MAIN_OVERCLOCK_ENABLE); settings.oc_enable = Config::Get(Config::MAIN_OVERCLOCK_ENABLE);
settings.m_OCFactor = Config::Get(Config::MAIN_OVERCLOCK); settings.oc_factor = Config::Get(Config::MAIN_OVERCLOCK);
for (ExpansionInterface::Slot slot : ExpansionInterface::SLOTS) for (ExpansionInterface::Slot slot : ExpansionInterface::SLOTS)
{ {
@ -1283,75 +1283,75 @@ bool NetPlayServer::SetupNetSettings()
{ {
device = Config::Get(Config::GetInfoForEXIDevice(slot)); device = Config::Get(Config::GetInfoForEXIDevice(slot));
} }
settings.m_EXIDevice[slot] = device; settings.exi_device[slot] = device;
} }
settings.m_MemcardSizeOverride = Config::Get(Config::MAIN_MEMORY_CARD_SIZE); settings.memcard_size_override = Config::Get(Config::MAIN_MEMORY_CARD_SIZE);
for (size_t i = 0; i < Config::SYSCONF_SETTINGS.size(); ++i) for (size_t i = 0; i < Config::SYSCONF_SETTINGS.size(); ++i)
{ {
std::visit( std::visit(
[&](auto* info) { [&](auto* info) {
static_assert(sizeof(info->GetDefaultValue()) <= sizeof(u32)); static_assert(sizeof(info->GetDefaultValue()) <= sizeof(u32));
settings.m_SYSCONFSettings[i] = static_cast<u32>(Config::Get(*info)); settings.sysconf_settings[i] = static_cast<u32>(Config::Get(*info));
}, },
Config::SYSCONF_SETTINGS[i].config_info); Config::SYSCONF_SETTINGS[i].config_info);
} }
settings.m_EFBAccessEnable = Config::Get(Config::GFX_HACK_EFB_ACCESS_ENABLE); settings.efb_access_enable = Config::Get(Config::GFX_HACK_EFB_ACCESS_ENABLE);
settings.m_BBoxEnable = Config::Get(Config::GFX_HACK_BBOX_ENABLE); settings.bbox_enable = Config::Get(Config::GFX_HACK_BBOX_ENABLE);
settings.m_ForceProgressive = Config::Get(Config::GFX_HACK_FORCE_PROGRESSIVE); settings.force_progressive = Config::Get(Config::GFX_HACK_FORCE_PROGRESSIVE);
settings.m_EFBToTextureEnable = Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM); settings.efb_to_texture_enable = Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM);
settings.m_XFBToTextureEnable = Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM); settings.xfb_to_texture_enable = Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM);
settings.m_DisableCopyToVRAM = Config::Get(Config::GFX_HACK_DISABLE_COPY_TO_VRAM); settings.disable_copy_to_vram = Config::Get(Config::GFX_HACK_DISABLE_COPY_TO_VRAM);
settings.m_ImmediateXFBEnable = Config::Get(Config::GFX_HACK_IMMEDIATE_XFB); settings.immediate_xfb_enable = Config::Get(Config::GFX_HACK_IMMEDIATE_XFB);
settings.m_EFBEmulateFormatChanges = Config::Get(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES); settings.efb_emulate_format_changes = Config::Get(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES);
settings.m_SafeTextureCacheColorSamples = settings.safe_texture_cache_color_samples =
Config::Get(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES); Config::Get(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES);
settings.m_PerfQueriesEnable = Config::Get(Config::GFX_PERF_QUERIES_ENABLE); settings.perf_queries_enable = Config::Get(Config::GFX_PERF_QUERIES_ENABLE);
settings.m_FloatExceptions = Config::Get(Config::MAIN_FLOAT_EXCEPTIONS); settings.float_exceptions = Config::Get(Config::MAIN_FLOAT_EXCEPTIONS);
settings.m_DivideByZeroExceptions = Config::Get(Config::MAIN_DIVIDE_BY_ZERO_EXCEPTIONS); settings.divide_by_zero_exceptions = Config::Get(Config::MAIN_DIVIDE_BY_ZERO_EXCEPTIONS);
settings.m_FPRF = Config::Get(Config::MAIN_FPRF); settings.fprf = Config::Get(Config::MAIN_FPRF);
settings.m_AccurateNaNs = Config::Get(Config::MAIN_ACCURATE_NANS); settings.accurate_nans = Config::Get(Config::MAIN_ACCURATE_NANS);
settings.m_DisableICache = Config::Get(Config::MAIN_DISABLE_ICACHE); settings.disable_icache = Config::Get(Config::MAIN_DISABLE_ICACHE);
settings.m_SyncOnSkipIdle = Config::Get(Config::MAIN_SYNC_ON_SKIP_IDLE); settings.sync_on_skip_idle = Config::Get(Config::MAIN_SYNC_ON_SKIP_IDLE);
settings.m_SyncGPU = Config::Get(Config::MAIN_SYNC_GPU); settings.sync_gpu = Config::Get(Config::MAIN_SYNC_GPU);
settings.m_SyncGpuMaxDistance = Config::Get(Config::MAIN_SYNC_GPU_MAX_DISTANCE); settings.sync_gpu_max_distance = Config::Get(Config::MAIN_SYNC_GPU_MAX_DISTANCE);
settings.m_SyncGpuMinDistance = Config::Get(Config::MAIN_SYNC_GPU_MIN_DISTANCE); settings.sync_gpu_min_distance = Config::Get(Config::MAIN_SYNC_GPU_MIN_DISTANCE);
settings.m_SyncGpuOverclock = Config::Get(Config::MAIN_SYNC_GPU_OVERCLOCK); settings.sync_gpu_overclock = Config::Get(Config::MAIN_SYNC_GPU_OVERCLOCK);
settings.m_JITFollowBranch = Config::Get(Config::MAIN_JIT_FOLLOW_BRANCH); settings.jit_follow_branch = Config::Get(Config::MAIN_JIT_FOLLOW_BRANCH);
settings.m_FastDiscSpeed = Config::Get(Config::MAIN_FAST_DISC_SPEED); settings.fast_disc_speed = Config::Get(Config::MAIN_FAST_DISC_SPEED);
settings.m_MMU = Config::Get(Config::MAIN_MMU); settings.mmu = Config::Get(Config::MAIN_MMU);
settings.m_Fastmem = Config::Get(Config::MAIN_FASTMEM); settings.fastmem = Config::Get(Config::MAIN_FASTMEM);
settings.m_SkipIPL = Config::Get(Config::MAIN_SKIP_IPL) || !DoAllPlayersHaveIPLDump(); settings.skip_ipl = Config::Get(Config::MAIN_SKIP_IPL) || !DoAllPlayersHaveIPLDump();
settings.m_LoadIPLDump = Config::Get(Config::SESSION_LOAD_IPL_DUMP) && DoAllPlayersHaveIPLDump(); settings.load_ipl_dump = Config::Get(Config::SESSION_LOAD_IPL_DUMP) && DoAllPlayersHaveIPLDump();
settings.m_VertexRounding = Config::Get(Config::GFX_HACK_VERTEX_ROUNDING); settings.vertex_rounding = Config::Get(Config::GFX_HACK_VERTEX_ROUNDING);
settings.m_InternalResolution = Config::Get(Config::GFX_EFB_SCALE); settings.internal_resolution = Config::Get(Config::GFX_EFB_SCALE);
settings.m_EFBScaledCopy = Config::Get(Config::GFX_HACK_COPY_EFB_SCALED); settings.efb_scaled_copy = Config::Get(Config::GFX_HACK_COPY_EFB_SCALED);
settings.m_FastDepthCalc = Config::Get(Config::GFX_FAST_DEPTH_CALC); settings.fast_depth_calc = Config::Get(Config::GFX_FAST_DEPTH_CALC);
settings.m_EnablePixelLighting = Config::Get(Config::GFX_ENABLE_PIXEL_LIGHTING); settings.enable_pixel_lighting = Config::Get(Config::GFX_ENABLE_PIXEL_LIGHTING);
settings.m_WidescreenHack = Config::Get(Config::GFX_WIDESCREEN_HACK); settings.widescreen_hack = Config::Get(Config::GFX_WIDESCREEN_HACK);
settings.m_ForceFiltering = Config::Get(Config::GFX_ENHANCE_FORCE_FILTERING); settings.force_filtering = Config::Get(Config::GFX_ENHANCE_FORCE_FILTERING);
settings.m_MaxAnisotropy = Config::Get(Config::GFX_ENHANCE_MAX_ANISOTROPY); settings.max_anisotropy = Config::Get(Config::GFX_ENHANCE_MAX_ANISOTROPY);
settings.m_ForceTrueColor = Config::Get(Config::GFX_ENHANCE_FORCE_TRUE_COLOR); settings.force_true_color = Config::Get(Config::GFX_ENHANCE_FORCE_TRUE_COLOR);
settings.m_DisableCopyFilter = Config::Get(Config::GFX_ENHANCE_DISABLE_COPY_FILTER); settings.disable_copy_filter = Config::Get(Config::GFX_ENHANCE_DISABLE_COPY_FILTER);
settings.m_DisableFog = Config::Get(Config::GFX_DISABLE_FOG); settings.disable_fog = Config::Get(Config::GFX_DISABLE_FOG);
settings.m_ArbitraryMipmapDetection = Config::Get(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION); settings.arbitrary_mipmap_detection = Config::Get(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION);
settings.m_ArbitraryMipmapDetectionThreshold = settings.arbitrary_mipmap_detection_threshold =
Config::Get(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION_THRESHOLD); Config::Get(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION_THRESHOLD);
settings.m_EnableGPUTextureDecoding = Config::Get(Config::GFX_ENABLE_GPU_TEXTURE_DECODING); settings.enable_gpu_texture_decoding = Config::Get(Config::GFX_ENABLE_GPU_TEXTURE_DECODING);
settings.m_DeferEFBCopies = Config::Get(Config::GFX_HACK_DEFER_EFB_COPIES); settings.defer_efb_copies = Config::Get(Config::GFX_HACK_DEFER_EFB_COPIES);
settings.m_EFBAccessTileSize = Config::Get(Config::GFX_HACK_EFB_ACCESS_TILE_SIZE); settings.efb_access_tile_size = Config::Get(Config::GFX_HACK_EFB_ACCESS_TILE_SIZE);
settings.m_EFBAccessDeferInvalidation = Config::Get(Config::GFX_HACK_EFB_DEFER_INVALIDATION); settings.efb_access_defer_invalidation = Config::Get(Config::GFX_HACK_EFB_DEFER_INVALIDATION);
settings.m_StrictSettingsSync = Config::Get(Config::NETPLAY_STRICT_SETTINGS_SYNC); settings.strict_settings_sync = Config::Get(Config::NETPLAY_STRICT_SETTINGS_SYNC);
settings.m_SyncSaveData = Config::Get(Config::NETPLAY_SYNC_SAVES); settings.sync_save_data = Config::Get(Config::NETPLAY_SYNC_SAVES);
settings.m_SyncCodes = Config::Get(Config::NETPLAY_SYNC_CODES); settings.sync_codes = Config::Get(Config::NETPLAY_SYNC_CODES);
settings.m_SyncAllWiiSaves = settings.sync_all_wii_saves =
Config::Get(Config::NETPLAY_SYNC_ALL_WII_SAVES) && Config::Get(Config::NETPLAY_SYNC_SAVES); Config::Get(Config::NETPLAY_SYNC_ALL_WII_SAVES) && Config::Get(Config::NETPLAY_SYNC_SAVES);
settings.m_GolfMode = Config::Get(Config::NETPLAY_NETWORK_MODE) == "golf"; settings.golf_mode = Config::Get(Config::NETPLAY_NETWORK_MODE) == "golf";
settings.m_UseFMA = DoAllPlayersHaveHardwareFMA(); settings.use_fma = DoAllPlayersHaveHardwareFMA();
settings.m_HideRemoteGBAs = Config::Get(Config::NETPLAY_HIDE_REMOTE_GBAS); settings.hide_remote_gbas = Config::Get(Config::NETPLAY_HIDE_REMOTE_GBAS);
// Unload GameINI to restore things to normal // Unload GameINI to restore things to normal
Config::RemoveLayer(Config::LayerType::GlobalGame); Config::RemoveLayer(Config::LayerType::GlobalGame);
@ -1382,7 +1382,7 @@ bool NetPlayServer::RequestStartGame()
bool start_now = true; bool start_now = true;
if (m_settings.m_SyncSaveData && m_players.size() > 1) if (m_settings.sync_save_data && m_players.size() > 1)
{ {
start_now = false; start_now = false;
m_start_pending = true; m_start_pending = true;
@ -1395,7 +1395,7 @@ bool NetPlayServer::RequestStartGame()
} }
// Check To Send Codes to Clients // Check To Send Codes to Clients
if (m_settings.m_SyncCodes && m_players.size() > 1) if (m_settings.sync_codes && m_players.size() > 1)
{ {
start_now = false; start_now = false;
m_start_pending = true; m_start_pending = true;
@ -1436,101 +1436,90 @@ bool NetPlayServer::StartGame()
const std::string region = Config::GetDirectoryForRegion( const std::string region = Config::GetDirectoryForRegion(
Config::ToGameCubeRegion(m_dialog->FindGameFile(m_selected_game_identifier)->GetRegion())); Config::ToGameCubeRegion(m_dialog->FindGameFile(m_selected_game_identifier)->GetRegion()));
// sync GC SRAM with clients // load host's GC SRAM
if (!g_SRAM_netplay_initialized)
{
SConfig::GetInstance().m_strSRAM = File::GetUserPath(F_GCSRAM_IDX); SConfig::GetInstance().m_strSRAM = File::GetUserPath(F_GCSRAM_IDX);
InitSRAM(); InitSRAM(&m_settings.sram, SConfig::GetInstance().m_strSRAM);
g_SRAM_netplay_initialized = true;
}
sf::Packet srampac;
srampac << MessageID::SyncGCSRAM;
for (size_t i = 0; i < sizeof(g_SRAM) - offsetof(Sram, settings); ++i)
{
srampac << g_SRAM[offsetof(Sram, settings) + i];
}
SendAsyncToClients(std::move(srampac), 1);
// tell clients to start game // tell clients to start game
sf::Packet spac; sf::Packet spac;
spac << MessageID::StartGame; spac << MessageID::StartGame;
spac << m_current_game; spac << m_current_game;
spac << m_settings.m_CPUthread; spac << m_settings.cpu_thread;
spac << m_settings.m_CPUcore; spac << m_settings.cpu_core;
spac << m_settings.m_EnableCheats; spac << m_settings.enable_cheats;
spac << m_settings.m_SelectedLanguage; spac << m_settings.selected_language;
spac << m_settings.m_OverrideRegionSettings; spac << m_settings.override_region_settings;
spac << m_settings.m_DSPEnableJIT; spac << m_settings.dsp_enable_jit;
spac << m_settings.m_DSPHLE; spac << m_settings.dsp_hle;
spac << m_settings.m_WriteToMemcard; spac << m_settings.write_to_memcard;
spac << m_settings.m_RAMOverrideEnable; spac << m_settings.ram_override_enable;
spac << m_settings.m_Mem1Size; spac << m_settings.mem1_size;
spac << m_settings.m_Mem2Size; spac << m_settings.mem2_size;
spac << m_settings.m_FallbackRegion; spac << m_settings.fallback_region;
spac << m_settings.m_AllowSDWrites; spac << m_settings.allow_sd_writes;
spac << m_settings.m_CopyWiiSave; spac << m_settings.copy_wii_save;
spac << m_settings.m_OCEnable; spac << m_settings.oc_enable;
spac << m_settings.m_OCFactor; spac << m_settings.oc_factor;
for (auto slot : ExpansionInterface::SLOTS) for (auto slot : ExpansionInterface::SLOTS)
spac << static_cast<int>(m_settings.m_EXIDevice[slot]); spac << static_cast<int>(m_settings.exi_device[slot]);
spac << m_settings.m_MemcardSizeOverride; spac << m_settings.memcard_size_override;
for (u32 value : m_settings.m_SYSCONFSettings) for (u32 value : m_settings.sysconf_settings)
spac << value; spac << value;
spac << m_settings.m_EFBAccessEnable; spac << m_settings.efb_access_enable;
spac << m_settings.m_BBoxEnable; spac << m_settings.bbox_enable;
spac << m_settings.m_ForceProgressive; spac << m_settings.force_progressive;
spac << m_settings.m_EFBToTextureEnable; spac << m_settings.efb_to_texture_enable;
spac << m_settings.m_XFBToTextureEnable; spac << m_settings.xfb_to_texture_enable;
spac << m_settings.m_DisableCopyToVRAM; spac << m_settings.disable_copy_to_vram;
spac << m_settings.m_ImmediateXFBEnable; spac << m_settings.immediate_xfb_enable;
spac << m_settings.m_EFBEmulateFormatChanges; spac << m_settings.efb_emulate_format_changes;
spac << m_settings.m_SafeTextureCacheColorSamples; spac << m_settings.safe_texture_cache_color_samples;
spac << m_settings.m_PerfQueriesEnable; spac << m_settings.perf_queries_enable;
spac << m_settings.m_FloatExceptions; spac << m_settings.float_exceptions;
spac << m_settings.m_DivideByZeroExceptions; spac << m_settings.divide_by_zero_exceptions;
spac << m_settings.m_FPRF; spac << m_settings.fprf;
spac << m_settings.m_AccurateNaNs; spac << m_settings.accurate_nans;
spac << m_settings.m_DisableICache; spac << m_settings.disable_icache;
spac << m_settings.m_SyncOnSkipIdle; spac << m_settings.sync_on_skip_idle;
spac << m_settings.m_SyncGPU; spac << m_settings.sync_gpu;
spac << m_settings.m_SyncGpuMaxDistance; spac << m_settings.sync_gpu_max_distance;
spac << m_settings.m_SyncGpuMinDistance; spac << m_settings.sync_gpu_min_distance;
spac << m_settings.m_SyncGpuOverclock; spac << m_settings.sync_gpu_overclock;
spac << m_settings.m_JITFollowBranch; spac << m_settings.jit_follow_branch;
spac << m_settings.m_FastDiscSpeed; spac << m_settings.fast_disc_speed;
spac << m_settings.m_MMU; spac << m_settings.mmu;
spac << m_settings.m_Fastmem; spac << m_settings.fastmem;
spac << m_settings.m_SkipIPL; spac << m_settings.skip_ipl;
spac << m_settings.m_LoadIPLDump; spac << m_settings.load_ipl_dump;
spac << m_settings.m_VertexRounding; spac << m_settings.vertex_rounding;
spac << m_settings.m_InternalResolution; spac << m_settings.internal_resolution;
spac << m_settings.m_EFBScaledCopy; spac << m_settings.efb_scaled_copy;
spac << m_settings.m_FastDepthCalc; spac << m_settings.fast_depth_calc;
spac << m_settings.m_EnablePixelLighting; spac << m_settings.enable_pixel_lighting;
spac << m_settings.m_WidescreenHack; spac << m_settings.widescreen_hack;
spac << m_settings.m_ForceFiltering; spac << m_settings.force_filtering;
spac << m_settings.m_MaxAnisotropy; spac << m_settings.max_anisotropy;
spac << m_settings.m_ForceTrueColor; spac << m_settings.force_true_color;
spac << m_settings.m_DisableCopyFilter; spac << m_settings.disable_copy_filter;
spac << m_settings.m_DisableFog; spac << m_settings.disable_fog;
spac << m_settings.m_ArbitraryMipmapDetection; spac << m_settings.arbitrary_mipmap_detection;
spac << m_settings.m_ArbitraryMipmapDetectionThreshold; spac << m_settings.arbitrary_mipmap_detection_threshold;
spac << m_settings.m_EnableGPUTextureDecoding; spac << m_settings.enable_gpu_texture_decoding;
spac << m_settings.m_DeferEFBCopies; spac << m_settings.defer_efb_copies;
spac << m_settings.m_EFBAccessTileSize; spac << m_settings.efb_access_tile_size;
spac << m_settings.m_EFBAccessDeferInvalidation; spac << m_settings.efb_access_defer_invalidation;
spac << m_settings.m_StrictSettingsSync; spac << m_settings.strict_settings_sync;
spac << initial_rtc; spac << initial_rtc;
spac << m_settings.m_SyncSaveData; spac << m_settings.sync_save_data;
spac << region; spac << region;
spac << m_settings.m_SyncCodes; spac << m_settings.sync_codes;
spac << m_settings.m_SyncAllWiiSaves; spac << m_settings.sync_all_wii_saves;
for (size_t i = 0; i < m_settings.m_WiimoteExtension.size(); i++) for (size_t i = 0; i < m_settings.wiimote_extension.size(); i++)
{ {
const int extension = const int extension =
static_cast<ControllerEmu::Attachments*>( static_cast<ControllerEmu::Attachments*>(
@ -1540,9 +1529,12 @@ bool NetPlayServer::StartGame()
spac << extension; spac << extension;
} }
spac << m_settings.m_GolfMode; spac << m_settings.golf_mode;
spac << m_settings.m_UseFMA; spac << m_settings.use_fma;
spac << m_settings.m_HideRemoteGBAs; spac << m_settings.hide_remote_gbas;
for (size_t i = 0; i < sizeof(m_settings.sram); ++i)
spac << m_settings.sram[i];
SendAsyncToClients(std::move(spac)); SendAsyncToClients(std::move(spac));
@ -1574,7 +1566,7 @@ bool NetPlayServer::SyncSaveData()
for (ExpansionInterface::Slot slot : ExpansionInterface::MEMCARD_SLOTS) for (ExpansionInterface::Slot slot : ExpansionInterface::MEMCARD_SLOTS)
{ {
if (m_settings.m_EXIDevice[slot] == ExpansionInterface::EXIDeviceType::MemoryCard || if (m_settings.exi_device[slot] == ExpansionInterface::EXIDeviceType::MemoryCard ||
Config::Get(Config::GetInfoForEXIDevice(slot)) == Config::Get(Config::GetInfoForEXIDevice(slot)) ==
ExpansionInterface::EXIDeviceType::MemoryCardFolder) ExpansionInterface::EXIDeviceType::MemoryCardFolder)
{ {
@ -1590,7 +1582,7 @@ bool NetPlayServer::SyncSaveData()
} }
bool wii_save = false; bool wii_save = false;
if (m_settings.m_CopyWiiSave && (game->GetPlatform() == DiscIO::Platform::WiiDisc || if (m_settings.copy_wii_save && (game->GetPlatform() == DiscIO::Platform::WiiDisc ||
game->GetPlatform() == DiscIO::Platform::WiiWAD || game->GetPlatform() == DiscIO::Platform::WiiWAD ||
game->GetPlatform() == DiscIO::Platform::ELFOrDOL)) game->GetPlatform() == DiscIO::Platform::ELFOrDOL))
{ {
@ -1635,9 +1627,9 @@ bool NetPlayServer::SyncSaveData()
{ {
const bool is_slot_a = slot == ExpansionInterface::Slot::A; const bool is_slot_a = slot == ExpansionInterface::Slot::A;
if (m_settings.m_EXIDevice[slot] == ExpansionInterface::EXIDeviceType::MemoryCard) if (m_settings.exi_device[slot] == ExpansionInterface::EXIDeviceType::MemoryCard)
{ {
const int size_override = m_settings.m_MemcardSizeOverride; const int size_override = m_settings.memcard_size_override;
const u16 card_size_mbits = const u16 card_size_mbits =
size_override >= 0 && size_override <= 4 ? size_override >= 0 && size_override <= 4 ?
static_cast<u16>(Memcard::MBIT_SIZE_MEMORY_CARD_59 << size_override) : static_cast<u16>(Memcard::MBIT_SIZE_MEMORY_CARD_59 << size_override) :
@ -1703,7 +1695,7 @@ bool NetPlayServer::SyncSaveData()
const auto configured_fs = IOS::HLE::FS::MakeFileSystem(IOS::HLE::FS::Location::Configured); const auto configured_fs = IOS::HLE::FS::MakeFileSystem(IOS::HLE::FS::Location::Configured);
std::vector<std::pair<u64, WiiSave::StoragePointer>> saves; std::vector<std::pair<u64, WiiSave::StoragePointer>> saves;
if (m_settings.m_SyncAllWiiSaves) if (m_settings.sync_all_wii_saves)
{ {
IOS::HLE::Kernel ios; IOS::HLE::Kernel ios;
for (const u64 title : ios.GetES()->GetInstalledTitles()) for (const u64 title : ios.GetES()->GetInstalledTitles())

View File

@ -336,6 +336,7 @@ void JitArm64::mfspr(UGeckoInstruction inst)
ADD(Xresult, XA, Xresult, ArithOption(Xresult, ShiftType::LSR, 3)); ADD(Xresult, XA, Xresult, ArithOption(Xresult, ShiftType::LSR, 3));
STR(IndexType::Unsigned, Xresult, PPC_REG, PPCSTATE_OFF_SPR(SPR_TL)); STR(IndexType::Unsigned, Xresult, PPC_REG, PPCSTATE_OFF_SPR(SPR_TL));
static_assert((PPCSTATE_OFF_SPR(SPR_TL) & 0x7) == 0);
if (CanMergeNextInstructions(1)) if (CanMergeNextInstructions(1))
{ {

View File

@ -162,7 +162,8 @@ struct PowerPCState
// special purpose registers - controls quantizers, DMA, and lots of other misc extensions. // special purpose registers - controls quantizers, DMA, and lots of other misc extensions.
// also for power management, but we don't care about that. // also for power management, but we don't care about that.
u32 spr[1024]{}; // JitArm64 needs 64-bit alignment for SPR_TL.
alignas(8) u32 spr[1024]{};
// Storage for the stack pointer of the BLR optimization. // Storage for the stack pointer of the BLR optimization.
u8* stored_stack_pointer = nullptr; u8* stored_stack_pointer = nullptr;

View File

@ -74,7 +74,7 @@ static std::recursive_mutex g_save_thread_mutex;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // Don't forget to increase this after doing changes on the savestate system
constexpr u32 STATE_VERSION = 148; // Last changed in PR 10768 constexpr u32 STATE_VERSION = 149; // Last changed in PR 10781
// Maps savestate versions to Dolphin versions. // Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list, // Versions after 42 don't need to be added to this list,

View File

@ -10,6 +10,7 @@
#include "Core/HW/AudioInterface.h" #include "Core/HW/AudioInterface.h"
#include "Core/HW/DVD/DVDInterface.h" #include "Core/HW/DVD/DVDInterface.h"
#include "Core/HW/DVD/DVDThread.h" #include "Core/HW/DVD/DVDThread.h"
#include "Core/HW/Sram.h"
namespace Core namespace Core
{ {
@ -22,6 +23,7 @@ struct System::Impl
AudioInterface::AudioInterfaceState m_audio_interface_state; AudioInterface::AudioInterfaceState m_audio_interface_state;
DVDInterface::DVDInterfaceState m_dvd_interface_state; DVDInterface::DVDInterfaceState m_dvd_interface_state;
DVDThread::DVDThreadState m_dvd_thread_state; DVDThread::DVDThreadState m_dvd_thread_state;
Sram m_sram;
}; };
System::System() : m_impl{std::make_unique<Impl>()} System::System() : m_impl{std::make_unique<Impl>()}
@ -80,4 +82,9 @@ DVDThread::DVDThreadState& System::GetDVDThreadState() const
{ {
return m_impl->m_dvd_thread_state; return m_impl->m_dvd_thread_state;
} }
Sram& System::GetSRAM() const
{
return m_impl->m_sram;
}
} // namespace Core } // namespace Core

View File

@ -6,6 +6,7 @@
#include <memory> #include <memory>
class SoundStream; class SoundStream;
struct Sram;
namespace AudioInterface namespace AudioInterface
{ {
@ -56,6 +57,7 @@ public:
AudioInterface::AudioInterfaceState& GetAudioInterfaceState() const; AudioInterface::AudioInterfaceState& GetAudioInterfaceState() const;
DVDInterface::DVDInterfaceState& GetDVDInterfaceState() const; DVDInterface::DVDInterfaceState& GetDVDInterfaceState() const;
DVDThread::DVDThreadState& GetDVDThreadState() const; DVDThread::DVDThreadState& GetDVDThreadState() const;
Sram& GetSRAM() const;
private: private:
System(); System();

View File

@ -1432,6 +1432,7 @@ void VolumeVerifier::Finish()
} }
else else
{ {
m_result.summary_text =
Common::GetStringT("Problems with low severity were found. They will most " Common::GetStringT("Problems with low severity were found. They will most "
"likely not prevent the game from running."); "likely not prevent the game from running.");
} }

View File

@ -13,12 +13,17 @@
#include "DolphinQt/Config/ControllerInterface/ControllerInterfaceWindow.h" #include "DolphinQt/Config/ControllerInterface/ControllerInterfaceWindow.h"
#include "DolphinQt/QtUtils/NonDefaultQPushButton.h" #include "DolphinQt/QtUtils/NonDefaultQPushButton.h"
#include "DolphinQt/QtUtils/SignalBlocking.h"
#include "DolphinQt/Settings.h"
CommonControllersWidget::CommonControllersWidget(QWidget* parent) : QWidget(parent) CommonControllersWidget::CommonControllersWidget(QWidget* parent) : QWidget(parent)
{ {
CreateLayout(); CreateLayout();
LoadSettings(); LoadSettings();
ConnectWidgets(); ConnectWidgets();
connect(&Settings::Instance(), &Settings::ConfigChanged, this,
&CommonControllersWidget::LoadSettings);
} }
void CommonControllersWidget::CreateLayout() void CommonControllersWidget::CreateLayout()
@ -59,7 +64,7 @@ void CommonControllersWidget::OnControllerInterfaceConfigure()
void CommonControllersWidget::LoadSettings() void CommonControllersWidget::LoadSettings()
{ {
m_common_bg_input->setChecked(Config::Get(Config::MAIN_INPUT_BACKGROUND_INPUT)); SignalBlocking(m_common_bg_input)->setChecked(Config::Get(Config::MAIN_INPUT_BACKGROUND_INPUT));
} }
void CommonControllersWidget::SaveSettings() void CommonControllersWidget::SaveSettings()

View File

@ -26,23 +26,26 @@
#include "DolphinQt/Config/Mapping/MappingWindow.h" #include "DolphinQt/Config/Mapping/MappingWindow.h"
#include "DolphinQt/QtUtils/ModalMessageBox.h" #include "DolphinQt/QtUtils/ModalMessageBox.h"
#include "DolphinQt/QtUtils/NonDefaultQPushButton.h" #include "DolphinQt/QtUtils/NonDefaultQPushButton.h"
#include "DolphinQt/QtUtils/SignalBlocking.h"
#include "DolphinQt/Settings.h" #include "DolphinQt/Settings.h"
#include "InputCommon/GCAdapter.h" #include "InputCommon/GCAdapter.h"
static const std::vector<std::pair<SerialInterface::SIDevices, const char*>> s_gc_types = { using SIDeviceName = std::pair<SerialInterface::SIDevices, const char*>;
{SerialInterface::SIDEVICE_NONE, _trans("None")}, static constexpr std::array s_gc_types = {
{SerialInterface::SIDEVICE_GC_CONTROLLER, _trans("Standard Controller")}, SIDeviceName{SerialInterface::SIDEVICE_NONE, _trans("None")},
{SerialInterface::SIDEVICE_GC_METROID, _trans("Metroid Controller")}, SIDeviceName{SerialInterface::SIDEVICE_GC_CONTROLLER, _trans("Standard Controller")},
{SerialInterface::SIDEVICE_WIIU_ADAPTER, _trans("GameCube Adapter for Wii U")}, SIDeviceName{SerialInterface::SIDEVICE_GC_METROID, _trans("Metroid Controller")},
{SerialInterface::SIDEVICE_GC_STEERING, _trans("Steering Wheel")}, SIDeviceName{SerialInterface::SIDEVICE_WIIU_ADAPTER, _trans("GameCube Adapter for Wii U")},
{SerialInterface::SIDEVICE_DANCEMAT, _trans("Dance Mat")}, SIDeviceName{SerialInterface::SIDEVICE_GC_STEERING, _trans("Steering Wheel")},
{SerialInterface::SIDEVICE_GC_TARUKONGA, _trans("DK Bongos")}, SIDeviceName{SerialInterface::SIDEVICE_DANCEMAT, _trans("Dance Mat")},
SIDeviceName{SerialInterface::SIDEVICE_GC_TARUKONGA, _trans("DK Bongos")},
#ifdef HAS_LIBMGBA #ifdef HAS_LIBMGBA
{SerialInterface::SIDEVICE_GC_GBA_EMULATED, _trans("GBA (Integrated)")}, SIDeviceName{SerialInterface::SIDEVICE_GC_GBA_EMULATED, _trans("GBA (Integrated)")},
#endif #endif
{SerialInterface::SIDEVICE_GC_GBA, _trans("GBA (TCP)")}, SIDeviceName{SerialInterface::SIDEVICE_GC_GBA, _trans("GBA (TCP)")},
{SerialInterface::SIDEVICE_GC_KEYBOARD, _trans("Keyboard")}}; SIDeviceName{SerialInterface::SIDEVICE_GC_KEYBOARD, _trans("Keyboard")},
};
static std::optional<int> ToGCMenuIndex(const SerialInterface::SIDevices sidevice) static std::optional<int> ToGCMenuIndex(const SerialInterface::SIDevices sidevice)
{ {
@ -59,16 +62,14 @@ static SerialInterface::SIDevices FromGCMenuIndex(const int menudevice)
return s_gc_types[menudevice].first; return s_gc_types[menudevice].first;
} }
static bool IsConfigurable(SerialInterface::SIDevices sidevice)
{
return sidevice != SerialInterface::SIDEVICE_NONE && sidevice != SerialInterface::SIDEVICE_GC_GBA;
}
GamecubeControllersWidget::GamecubeControllersWidget(QWidget* parent) : QWidget(parent) GamecubeControllersWidget::GamecubeControllersWidget(QWidget* parent) : QWidget(parent)
{ {
CreateLayout(); CreateLayout();
LoadSettings(); LoadSettings();
ConnectWidgets(); ConnectWidgets();
connect(&Settings::Instance(), &Settings::ConfigChanged, this,
&GamecubeControllersWidget::LoadSettings);
} }
void GamecubeControllersWidget::CreateLayout() void GamecubeControllersWidget::CreateLayout()
@ -105,43 +106,27 @@ void GamecubeControllersWidget::CreateLayout()
void GamecubeControllersWidget::ConnectWidgets() void GamecubeControllersWidget::ConnectWidgets()
{ {
for (size_t i = 0; i < m_gc_controller_boxes.size(); i++) for (size_t i = 0; i < m_gc_controller_boxes.size(); ++i)
{ {
connect(m_gc_controller_boxes[i], qOverload<int>(&QComboBox::currentIndexChanged), this, connect(m_gc_controller_boxes[i], qOverload<int>(&QComboBox::currentIndexChanged), this,
&GamecubeControllersWidget::SaveSettings); [this, i] {
connect(m_gc_controller_boxes[i], qOverload<int>(&QComboBox::currentIndexChanged), this, OnGCTypeChanged(i);
&GamecubeControllersWidget::OnGCTypeChanged);
connect(m_gc_buttons[i], &QPushButton::clicked, this,
&GamecubeControllersWidget::OnGCPadConfigure);
}
}
void GamecubeControllersWidget::OnGCTypeChanged(int type)
{
const auto* box = static_cast<QComboBox*>(QObject::sender());
for (size_t i = 0; i < m_gc_groups.size(); i++)
{
if (m_gc_controller_boxes[i] == box)
{
const SerialInterface::SIDevices si_device = FromGCMenuIndex(box->currentIndex());
m_gc_buttons[i]->setEnabled(IsConfigurable(si_device));
return;
}
}
SaveSettings(); SaveSettings();
});
connect(m_gc_buttons[i], &QPushButton::clicked, this, [this, i] { OnGCPadConfigure(i); });
}
} }
void GamecubeControllersWidget::OnGCPadConfigure() void GamecubeControllersWidget::OnGCTypeChanged(size_t index)
{ {
size_t index; const SerialInterface::SIDevices si_device =
for (index = 0; index < m_gc_groups.size(); index++) FromGCMenuIndex(m_gc_controller_boxes[index]->currentIndex());
{ m_gc_buttons[index]->setEnabled(si_device != SerialInterface::SIDEVICE_NONE &&
if (m_gc_buttons[index] == QObject::sender()) si_device != SerialInterface::SIDEVICE_GC_GBA);
break;
} }
void GamecubeControllersWidget::OnGCPadConfigure(size_t index)
{
MappingWindow::Type type; MappingWindow::Type type;
switch (FromGCMenuIndex(m_gc_controller_boxes[index]->currentIndex())) switch (FromGCMenuIndex(m_gc_controller_boxes[index]->currentIndex()))
@ -207,30 +192,32 @@ void GamecubeControllersWidget::LoadSettings()
const std::optional<int> gc_index = ToGCMenuIndex(si_device); const std::optional<int> gc_index = ToGCMenuIndex(si_device);
if (gc_index) if (gc_index)
{ {
m_gc_controller_boxes[i]->setCurrentIndex(*gc_index); SignalBlocking(m_gc_controller_boxes[i])->setCurrentIndex(*gc_index);
m_gc_buttons[i]->setEnabled(IsConfigurable(si_device)); OnGCTypeChanged(i);
} }
} }
} }
void GamecubeControllersWidget::SaveSettings() void GamecubeControllersWidget::SaveSettings()
{ {
for (size_t i = 0; i < m_gc_groups.size(); i++)
{ {
const int index = m_gc_controller_boxes[i]->currentIndex(); Config::ConfigChangeCallbackGuard config_guard;
const SerialInterface::SIDevices si_device = FromGCMenuIndex(index);
for (size_t i = 0; i < m_gc_groups.size(); ++i)
{
const SerialInterface::SIDevices si_device =
FromGCMenuIndex(m_gc_controller_boxes[i]->currentIndex());
Config::SetBaseOrCurrent(Config::GetInfoForSIDevice(static_cast<int>(i)), si_device); Config::SetBaseOrCurrent(Config::GetInfoForSIDevice(static_cast<int>(i)), si_device);
if (Core::IsRunning()) if (Core::IsRunning())
SerialInterface::ChangeDevice(si_device, static_cast<s32>(i)); SerialInterface::ChangeDevice(si_device, static_cast<s32>(i));
m_gc_buttons[i]->setEnabled(IsConfigurable(si_device));
} }
if (GCAdapter::UseAdapter()) if (GCAdapter::UseAdapter())
GCAdapter::StartScanThread(); GCAdapter::StartScanThread();
else else
GCAdapter::StopScanThread(); GCAdapter::StopScanThread();
}
SConfig::GetInstance().SaveSettings(); SConfig::GetInstance().SaveSettings();
} }

View File

@ -23,8 +23,8 @@ private:
void LoadSettings(); void LoadSettings();
void SaveSettings(); void SaveSettings();
void OnGCTypeChanged(int state); void OnGCTypeChanged(size_t index);
void OnGCPadConfigure(); void OnGCPadConfigure(size_t index);
void CreateLayout(); void CreateLayout();
void ConnectWidgets(); void ConnectWidgets();

View File

@ -33,8 +33,9 @@ AdvancedWidget::AdvancedWidget(GraphicsWindow* parent)
AddDescriptions(); AddDescriptions();
connect(parent, &GraphicsWindow::BackendChanged, this, &AdvancedWidget::OnBackendChanged); connect(parent, &GraphicsWindow::BackendChanged, this, &AdvancedWidget::OnBackendChanged);
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
[=](Core::State state) { OnEmulationStateChanged(state != Core::State::Uninitialized); }); OnEmulationStateChanged(state != Core::State::Uninitialized);
});
OnBackendChanged(); OnBackendChanged();
OnEmulationStateChanged(Core::GetState() != Core::State::Uninitialized); OnEmulationStateChanged(Core::GetState() != Core::State::Uninitialized);

View File

@ -41,8 +41,9 @@ GeneralWidget::GeneralWidget(X11Utils::XRRConfiguration* xrr_config, GraphicsWin
emit BackendChanged(QString::fromStdString(Config::Get(Config::MAIN_GFX_BACKEND))); emit BackendChanged(QString::fromStdString(Config::Get(Config::MAIN_GFX_BACKEND)));
connect(parent, &GraphicsWindow::BackendChanged, this, &GeneralWidget::OnBackendChanged); connect(parent, &GraphicsWindow::BackendChanged, this, &GeneralWidget::OnBackendChanged);
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
[=](Core::State state) { OnEmulationStateChanged(state != Core::State::Uninitialized); }); OnEmulationStateChanged(state != Core::State::Uninitialized);
});
OnEmulationStateChanged(Core::GetState() != Core::State::Uninitialized); OnEmulationStateChanged(Core::GetState() != Core::State::Uninitialized);
} }

View File

@ -34,8 +34,9 @@ SoftwareRendererWidget::SoftwareRendererWidget(GraphicsWindow* parent)
emit BackendChanged(QString::fromStdString(Config::Get(Config::MAIN_GFX_BACKEND))); emit BackendChanged(QString::fromStdString(Config::Get(Config::MAIN_GFX_BACKEND)));
connect(parent, &GraphicsWindow::BackendChanged, [this] { LoadSettings(); }); connect(parent, &GraphicsWindow::BackendChanged, [this] { LoadSettings(); });
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
[=](Core::State state) { OnEmulationStateChanged(state != Core::State::Uninitialized); }); OnEmulationStateChanged(state != Core::State::Uninitialized);
});
OnEmulationStateChanged(Core::GetState() != Core::State::Uninitialized); OnEmulationStateChanged(Core::GetState() != Core::State::Uninitialized);
} }

View File

@ -32,6 +32,7 @@
#include "DolphinQt/Config/Mapping/MappingWindow.h" #include "DolphinQt/Config/Mapping/MappingWindow.h"
#include "DolphinQt/QtUtils/ModalMessageBox.h" #include "DolphinQt/QtUtils/ModalMessageBox.h"
#include "DolphinQt/QtUtils/NonDefaultQPushButton.h" #include "DolphinQt/QtUtils/NonDefaultQPushButton.h"
#include "DolphinQt/QtUtils/SignalBlocking.h"
#include "DolphinQt/Settings.h" #include "DolphinQt/Settings.h"
#include "UICommon/UICommon.h" #include "UICommon/UICommon.h"
@ -39,8 +40,13 @@
WiimoteControllersWidget::WiimoteControllersWidget(QWidget* parent) : QWidget(parent) WiimoteControllersWidget::WiimoteControllersWidget(QWidget* parent) : QWidget(parent)
{ {
CreateLayout(); CreateLayout();
LoadSettings();
ConnectWidgets(); ConnectWidgets();
connect(&Settings::Instance(), &Settings::ConfigChanged, this,
[this] { LoadSettings(Core::GetState()); });
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
[this](Core::State state) { LoadSettings(state); });
LoadSettings(Core::GetState());
} }
static int GetRadioButtonIndicatorWidth() static int GetRadioButtonIndicatorWidth()
@ -153,20 +159,20 @@ void WiimoteControllersWidget::CreateLayout()
void WiimoteControllersWidget::ConnectWidgets() void WiimoteControllersWidget::ConnectWidgets()
{ {
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, connect(m_wiimote_passthrough, &QRadioButton::toggled, this, [this] {
&WiimoteControllersWidget::UpdateDisabledWiimoteControls); SaveSettings();
LoadSettings(Core::GetState());
});
connect(m_wiimote_ciface, &QCheckBox::toggled, this, [this] {
SaveSettings();
LoadSettings(Core::GetState());
WiimoteReal::HandleWiimotesInControllerInterfaceSettingChange();
});
connect(m_wiimote_continuous_scanning, &QCheckBox::toggled, this, [this] {
SaveSettings();
LoadSettings(Core::GetState());
});
connect(m_wiimote_passthrough, &QRadioButton::toggled, this,
&WiimoteControllersWidget::OnWiimoteModeChanged);
connect(m_wiimote_ciface, &QCheckBox::toggled, this,
&WiimoteControllersWidget::OnWiimoteModeChanged);
connect(m_wiimote_ciface, &QCheckBox::toggled, this,
&WiimoteReal::HandleWiimotesInControllerInterfaceSettingChange);
connect(m_wiimote_continuous_scanning, &QCheckBox::toggled, this,
&WiimoteControllersWidget::OnWiimoteModeChanged);
connect(m_wiimote_continuous_scanning, &QCheckBox::toggled, this,
&WiimoteControllersWidget::SaveSettings);
connect(m_wiimote_real_balance_board, &QCheckBox::toggled, this, connect(m_wiimote_real_balance_board, &QCheckBox::toggled, this,
&WiimoteControllersWidget::SaveSettings); &WiimoteControllersWidget::SaveSettings);
connect(m_wiimote_speaker_data, &QCheckBox::toggled, this, connect(m_wiimote_speaker_data, &QCheckBox::toggled, this,
@ -180,59 +186,13 @@ void WiimoteControllersWidget::ConnectWidgets()
for (size_t i = 0; i < m_wiimote_groups.size(); i++) for (size_t i = 0; i < m_wiimote_groups.size(); i++)
{ {
connect(m_wiimote_boxes[i], qOverload<int>(&QComboBox::currentIndexChanged), this, connect(m_wiimote_boxes[i], qOverload<int>(&QComboBox::currentIndexChanged), this, [this] {
&WiimoteControllersWidget::SaveSettings);
connect(m_wiimote_boxes[i], qOverload<int>(&QComboBox::currentIndexChanged), this,
&WiimoteControllersWidget::OnWiimoteModeChanged);
connect(m_wiimote_buttons[i], &QPushButton::clicked, this,
&WiimoteControllersWidget::OnWiimoteConfigure);
}
}
void WiimoteControllersWidget::OnWiimoteModeChanged()
{
SaveSettings(); SaveSettings();
LoadSettings(Core::GetState());
// Make sure continuous scanning setting is applied. });
WiimoteReal::Initialize(::Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES); connect(m_wiimote_buttons[i], &QPushButton::clicked, this,
[this, i] { OnWiimoteConfigure(i); });
UpdateDisabledWiimoteControls();
} }
void WiimoteControllersWidget::UpdateDisabledWiimoteControls()
{
const bool running = Core::GetState() != Core::State::Uninitialized;
m_wiimote_emu->setEnabled(!running);
m_wiimote_passthrough->setEnabled(!running);
const bool running_gc = running && !SConfig::GetInstance().bWii;
const bool enable_passthrough = m_wiimote_passthrough->isChecked() && !running_gc;
const bool enable_emu_bt = !m_wiimote_passthrough->isChecked() && !running_gc;
m_wiimote_sync->setEnabled(enable_passthrough);
m_wiimote_reset->setEnabled(enable_passthrough);
for (auto* pt_label : m_wiimote_pt_labels)
pt_label->setEnabled(enable_passthrough);
for (size_t i = 0; i < m_wiimote_groups.size(); i++)
{
m_wiimote_labels[i]->setEnabled(enable_emu_bt);
m_wiimote_boxes[i]->setEnabled(enable_emu_bt);
const bool is_emu_wiimote = m_wiimote_boxes[i]->currentIndex() == 1 || m_wiimote_boxes[i]->currentIndex() == 3;
m_wiimote_buttons[i]->setEnabled(enable_emu_bt && is_emu_wiimote);
}
m_wiimote_real_balance_board->setEnabled(enable_emu_bt);
m_wiimote_speaker_data->setEnabled(enable_emu_bt);
const bool ciface_wiimotes = m_wiimote_ciface->isChecked();
m_wiimote_refresh->setEnabled((enable_emu_bt || ciface_wiimotes) &&
!m_wiimote_continuous_scanning->isChecked());
m_wiimote_continuous_scanning->setEnabled(enable_emu_bt || ciface_wiimotes);
} }
void WiimoteControllersWidget::OnBluetoothPassthroughResetPressed() void WiimoteControllersWidget::OnBluetoothPassthroughResetPressed()
@ -273,15 +233,8 @@ void WiimoteControllersWidget::OnWiimoteRefreshPressed()
WiimoteReal::Refresh(); WiimoteReal::Refresh();
} }
void WiimoteControllersWidget::OnWiimoteConfigure() void WiimoteControllersWidget::OnWiimoteConfigure(size_t index)
{ {
size_t index;
for (index = 0; index < m_wiimote_groups.size(); index++)
{
if (m_wiimote_buttons[index] == QObject::sender())
break;
}
MappingWindow::Type type; MappingWindow::Type type;
switch (m_wiimote_boxes[index]->currentIndex()) switch (m_wiimote_boxes[index]->currentIndex())
{ {
@ -320,28 +273,68 @@ void WiimoteControllersWidget::OnWiimoteConfigure()
window->show(); window->show();
} }
void WiimoteControllersWidget::LoadSettings() void WiimoteControllersWidget::LoadSettings(Core::State state)
{ {
for (size_t i = 0; i < m_wiimote_groups.size(); i++) for (size_t i = 0; i < m_wiimote_groups.size(); i++)
{ {
m_wiimote_boxes[i]->setCurrentIndex(int(Config::Get(Config::GetInfoForWiimoteSource(int(i))))); SignalBlocking(m_wiimote_boxes[i])
->setCurrentIndex(int(Config::Get(Config::GetInfoForWiimoteSource(int(i)))));
} }
m_wiimote_real_balance_board->setChecked(Config::Get(Config::WIIMOTE_BB_SOURCE) == SignalBlocking(m_wiimote_real_balance_board)
WiimoteSource::Real); ->setChecked(Config::Get(Config::WIIMOTE_BB_SOURCE) == WiimoteSource::Real);
m_wiimote_speaker_data->setChecked(Config::Get(Config::MAIN_WIIMOTE_ENABLE_SPEAKER)); SignalBlocking(m_wiimote_speaker_data)
m_wiimote_ciface->setChecked(Config::Get(Config::MAIN_CONNECT_WIIMOTES_FOR_CONTROLLER_INTERFACE)); ->setChecked(Config::Get(Config::MAIN_WIIMOTE_ENABLE_SPEAKER));
m_wiimote_continuous_scanning->setChecked(Config::Get(Config::MAIN_WIIMOTE_CONTINUOUS_SCANNING)); SignalBlocking(m_wiimote_ciface)
->setChecked(Config::Get(Config::MAIN_CONNECT_WIIMOTES_FOR_CONTROLLER_INTERFACE));
SignalBlocking(m_wiimote_continuous_scanning)
->setChecked(Config::Get(Config::MAIN_WIIMOTE_CONTINUOUS_SCANNING));
if (Config::Get(Config::MAIN_BLUETOOTH_PASSTHROUGH_ENABLED)) if (Config::Get(Config::MAIN_BLUETOOTH_PASSTHROUGH_ENABLED))
m_wiimote_passthrough->setChecked(true); SignalBlocking(m_wiimote_passthrough)->setChecked(true);
else else
m_wiimote_emu->setChecked(true); SignalBlocking(m_wiimote_emu)->setChecked(true);
OnWiimoteModeChanged(); // Make sure continuous scanning setting is applied.
WiimoteReal::Initialize(::Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES);
const bool running = state != Core::State::Uninitialized;
m_wiimote_emu->setEnabled(!running);
m_wiimote_passthrough->setEnabled(!running);
const bool running_gc = running && !SConfig::GetInstance().bWii;
const bool enable_passthrough = m_wiimote_passthrough->isChecked() && !running_gc;
const bool enable_emu_bt = !m_wiimote_passthrough->isChecked() && !running_gc;
m_wiimote_sync->setEnabled(enable_passthrough);
m_wiimote_reset->setEnabled(enable_passthrough);
for (auto* pt_label : m_wiimote_pt_labels)
pt_label->setEnabled(enable_passthrough);
for (size_t i = 0; i < m_wiimote_groups.size(); i++)
{
m_wiimote_labels[i]->setEnabled(enable_emu_bt);
m_wiimote_boxes[i]->setEnabled(enable_emu_bt);
const bool is_emu_wiimote = m_wiimote_boxes[i]->currentIndex() == 1;
m_wiimote_buttons[i]->setEnabled(enable_emu_bt && is_emu_wiimote);
}
m_wiimote_real_balance_board->setEnabled(enable_emu_bt);
m_wiimote_speaker_data->setEnabled(enable_emu_bt);
const bool ciface_wiimotes = m_wiimote_ciface->isChecked();
m_wiimote_refresh->setEnabled((enable_emu_bt || ciface_wiimotes) &&
!m_wiimote_continuous_scanning->isChecked());
m_wiimote_continuous_scanning->setEnabled(enable_emu_bt || ciface_wiimotes);
} }
void WiimoteControllersWidget::SaveSettings() void WiimoteControllersWidget::SaveSettings()
{ {
{
Config::ConfigChangeCallbackGuard config_guard;
Config::SetBaseOrCurrent(Config::MAIN_WIIMOTE_ENABLE_SPEAKER, Config::SetBaseOrCurrent(Config::MAIN_WIIMOTE_ENABLE_SPEAKER,
m_wiimote_speaker_data->isChecked()); m_wiimote_speaker_data->isChecked());
Config::SetBaseOrCurrent(Config::MAIN_CONNECT_WIIMOTES_FOR_CONTROLLER_INTERFACE, Config::SetBaseOrCurrent(Config::MAIN_CONNECT_WIIMOTES_FOR_CONTROLLER_INTERFACE,
@ -360,6 +353,7 @@ void WiimoteControllersWidget::SaveSettings()
const int index = m_wiimote_boxes[i]->currentIndex(); const int index = m_wiimote_boxes[i]->currentIndex();
Config::SetBaseOrCurrent(Config::GetInfoForWiimoteSource(int(i)), WiimoteSource(index)); Config::SetBaseOrCurrent(Config::GetInfoForWiimoteSource(int(i)), WiimoteSource(index));
} }
}
SConfig::GetInstance().SaveSettings(); SConfig::GetInstance().SaveSettings();
} }

View File

@ -16,6 +16,11 @@ class QLabel;
class QPushButton; class QPushButton;
class QRadioButton; class QRadioButton;
namespace Core
{
enum class State;
}
class WiimoteControllersWidget final : public QWidget class WiimoteControllersWidget final : public QWidget
{ {
Q_OBJECT Q_OBJECT
@ -23,17 +28,15 @@ public:
explicit WiimoteControllersWidget(QWidget* parent); explicit WiimoteControllersWidget(QWidget* parent);
private: private:
void OnWiimoteModeChanged();
void UpdateDisabledWiimoteControls();
void SaveSettings(); void SaveSettings();
void OnBluetoothPassthroughSyncPressed(); void OnBluetoothPassthroughSyncPressed();
void OnBluetoothPassthroughResetPressed(); void OnBluetoothPassthroughResetPressed();
void OnWiimoteRefreshPressed(); void OnWiimoteRefreshPressed();
void OnWiimoteConfigure(); void OnWiimoteConfigure(size_t index);
void CreateLayout(); void CreateLayout();
void ConnectWidgets(); void ConnectWidgets();
void LoadSettings(); void LoadSettings(Core::State state);
QGroupBox* m_wiimote_box; QGroupBox* m_wiimote_box;
QGridLayout* m_wiimote_layout; QGridLayout* m_wiimote_layout;

View File

@ -17,6 +17,7 @@
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
#include <QLineEdit> #include <QLineEdit>
#include <QMenuBar>
#include <QPushButton> #include <QPushButton>
#include <QRegularExpression> #include <QRegularExpression>
#include <QScrollArea> #include <QScrollArea>
@ -114,7 +115,6 @@ void MemoryWidget::CreateWidgets()
m_data_edit = new QLineEdit; m_data_edit = new QLineEdit;
m_base_check = new QCheckBox(tr("Hex")); m_base_check = new QCheckBox(tr("Hex"));
m_set_value = new QPushButton(tr("Set &Value")); m_set_value = new QPushButton(tr("Set &Value"));
m_from_file = new QPushButton(tr("Set Value From File"));
m_data_preview = new QLabel; m_data_preview = new QLabel;
m_base_check->setLayoutDirection(Qt::RightToLeft); m_base_check->setLayoutDirection(Qt::RightToLeft);
@ -140,20 +140,6 @@ void MemoryWidget::CreateWidgets()
m_input_combo->addItem(tr("Signed 16"), int(Type::Signed16)); m_input_combo->addItem(tr("Signed 16"), int(Type::Signed16));
m_input_combo->addItem(tr("Signed 32"), int(Type::Signed32)); m_input_combo->addItem(tr("Signed 32"), int(Type::Signed32));
// Dump
auto* dump_group = new QGroupBox(tr("Dump"));
auto* dump_layout = new QVBoxLayout;
dump_group->setLayout(dump_layout);
m_dump_mram = new QPushButton(tr("Dump &MRAM"));
m_dump_exram = new QPushButton(tr("Dump &ExRAM"));
m_dump_aram = new QPushButton(tr("Dump &ARAM"));
m_dump_fake_vmem = new QPushButton(tr("Dump &FakeVMEM"));
dump_layout->addWidget(m_dump_mram);
dump_layout->addWidget(m_dump_exram);
dump_layout->addWidget(m_dump_aram);
dump_layout->addWidget(m_dump_fake_vmem);
// Search Options // Search Options
auto* search_group = new QGroupBox(tr("Search")); auto* search_group = new QGroupBox(tr("Search"));
auto* search_layout = new QVBoxLayout; auto* search_layout = new QVBoxLayout;
@ -253,14 +239,31 @@ void MemoryWidget::CreateWidgets()
// Sidebar // Sidebar
auto* sidebar = new QWidget; auto* sidebar = new QWidget;
auto* sidebar_layout = new QVBoxLayout; auto* sidebar_layout = new QVBoxLayout;
// Sidebar top menu
QMenuBar* menubar = new QMenuBar(sidebar);
menubar->setNativeMenuBar(false);
QMenu* menu_actions = new QMenu(tr("&Actions"));
menu_actions->addAction(tr("&Load file to current address"), this,
&MemoryWidget::OnSetValueFromFile);
menu_actions->addSeparator();
menu_actions->addAction(tr("Dump &MRAM"), this, &MemoryWidget::OnDumpMRAM);
menu_actions->addAction(tr("Dump &ExRAM"), this, &MemoryWidget::OnDumpExRAM);
menu_actions->addAction(tr("Dump &ARAM"), this, &MemoryWidget::OnDumpARAM);
menu_actions->addAction(tr("Dump &FakeVMEM"), this, &MemoryWidget::OnDumpFakeVMEM);
menubar->addMenu(menu_actions);
sidebar_layout->setSpacing(1); sidebar_layout->setSpacing(1);
sidebar->setLayout(sidebar_layout); sidebar->setLayout(sidebar_layout);
sidebar_layout->addItem(new QSpacerItem(1, 20));
sidebar_layout->addWidget(m_address_splitter); sidebar_layout->addWidget(m_address_splitter);
sidebar_layout->addLayout(input_layout); sidebar_layout->addLayout(input_layout);
sidebar_layout->addWidget(m_input_combo); sidebar_layout->addWidget(m_input_combo);
sidebar_layout->addItem(new QSpacerItem(1, 10));
sidebar_layout->addWidget(m_data_preview); sidebar_layout->addWidget(m_data_preview);
sidebar_layout->addWidget(m_set_value); sidebar_layout->addWidget(m_set_value);
sidebar_layout->addWidget(m_from_file);
sidebar_layout->addItem(new QSpacerItem(1, 10)); sidebar_layout->addItem(new QSpacerItem(1, 10));
sidebar_layout->addWidget(search_group); sidebar_layout->addWidget(search_group);
sidebar_layout->addItem(new QSpacerItem(1, 10)); sidebar_layout->addItem(new QSpacerItem(1, 10));
@ -269,8 +272,6 @@ void MemoryWidget::CreateWidgets()
sidebar_layout->addWidget(address_space_group); sidebar_layout->addWidget(address_space_group);
sidebar_layout->addItem(new QSpacerItem(1, 10)); sidebar_layout->addItem(new QSpacerItem(1, 10));
sidebar_layout->addWidget(bp_group); sidebar_layout->addWidget(bp_group);
sidebar_layout->addItem(new QSpacerItem(1, 10));
sidebar_layout->addWidget(dump_group);
sidebar_layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding)); sidebar_layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding));
// Splitter // Splitter
@ -302,14 +303,7 @@ void MemoryWidget::ConnectWidgets()
connect(m_input_combo, qOverload<int>(&QComboBox::currentIndexChanged), this, connect(m_input_combo, qOverload<int>(&QComboBox::currentIndexChanged), this,
&MemoryWidget::ValidateAndPreviewInputValue); &MemoryWidget::ValidateAndPreviewInputValue);
connect(m_set_value, &QPushButton::clicked, this, &MemoryWidget::OnSetValue); connect(m_set_value, &QPushButton::clicked, this, &MemoryWidget::OnSetValue);
connect(m_from_file, &QPushButton::clicked, this, &MemoryWidget::OnSetValueFromFile);
connect(m_dump_mram, &QPushButton::clicked, this, &MemoryWidget::OnDumpMRAM);
connect(m_dump_exram, &QPushButton::clicked, this, &MemoryWidget::OnDumpExRAM);
connect(m_dump_aram, &QPushButton::clicked, this, &MemoryWidget::OnDumpARAM);
connect(m_dump_fake_vmem, &QPushButton::clicked, this, &MemoryWidget::OnDumpFakeVMEM);
connect(m_find_next, &QPushButton::clicked, this, &MemoryWidget::OnFindNextValue); connect(m_find_next, &QPushButton::clicked, this, &MemoryWidget::OnFindNextValue);
connect(m_find_previous, &QPushButton::clicked, this, &MemoryWidget::OnFindPreviousValue); connect(m_find_previous, &QPushButton::clicked, this, &MemoryWidget::OnFindPreviousValue);

View File

@ -85,11 +85,6 @@ private:
QComboBox* m_row_length_combo; QComboBox* m_row_length_combo;
QCheckBox* m_dual_check; QCheckBox* m_dual_check;
QPushButton* m_set_value; QPushButton* m_set_value;
QPushButton* m_from_file;
QPushButton* m_dump_mram;
QPushButton* m_dump_exram;
QPushButton* m_dump_aram;
QPushButton* m_dump_fake_vmem;
// Search // Search
QPushButton* m_find_next; QPushButton* m_find_next;

View File

@ -316,6 +316,11 @@ public:
OPCODE_CALLBACK(CPState& GetCPState()) { return m_cpmem; } OPCODE_CALLBACK(CPState& GetCPState()) { return m_cpmem; }
OPCODE_CALLBACK(u32 GetVertexSize(u8 vat))
{
return VertexLoaderBase::GetVertexSize(GetCPState().vtx_desc, GetCPState().vtx_attr[vat]);
}
QString text; QString text;
CPState m_cpmem; CPState m_cpmem;
}; };
@ -731,6 +736,11 @@ public:
OPCODE_CALLBACK(CPState& GetCPState()) { return m_cpmem; } OPCODE_CALLBACK(CPState& GetCPState()) { return m_cpmem; }
OPCODE_CALLBACK(u32 GetVertexSize(u8 vat))
{
return VertexLoaderBase::GetVertexSize(GetCPState().vtx_desc, GetCPState().vtx_attr[vat]);
}
QString text; QString text;
CPState m_cpmem; CPState m_cpmem;
}; };

View File

@ -358,7 +358,7 @@ void MainWindow::ShutdownControllers()
void MainWindow::InitCoreCallbacks() void MainWindow::InitCoreCallbacks()
{ {
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [=](Core::State state) { connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
if (state == Core::State::Uninitialized) if (state == Core::State::Uninitialized)
OnStopComplete(); OnStopComplete();
if (state != Core::State::Uninitialized && NetPlay::IsNetPlayRunning() && m_controllers_window) if (state != Core::State::Uninitialized && NetPlay::IsNetPlayRunning() && m_controllers_window)
@ -375,7 +375,7 @@ void MainWindow::InitCoreCallbacks()
// Handle file open events // Handle file open events
auto* filter = new FileOpenEventFilter(QGuiApplication::instance()); auto* filter = new FileOpenEventFilter(QGuiApplication::instance());
connect(filter, &FileOpenEventFilter::fileOpened, this, [=](const QString& file_name) { connect(filter, &FileOpenEventFilter::fileOpened, this, [this](const QString& file_name) {
StartGame(BootParameters::GenerateFromFile(file_name.toStdString())); StartGame(BootParameters::GenerateFromFile(file_name.toStdString()));
}); });
} }

View File

@ -90,7 +90,7 @@ MenuBar::MenuBar(QWidget* parent) : QMenuBar(parent)
AddPrimeHackMenu(); AddPrimeHackMenu();
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
[=](Core::State state) { OnEmulationStateChanged(state); }); [=, this](Core::State state) { OnEmulationStateChanged(state); });
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this,
[this] { OnEmulationStateChanged(Core::GetState()); }); [this] { OnEmulationStateChanged(Core::GetState()); });
@ -343,7 +343,7 @@ void MenuBar::AddStateLoadMenu(QMenu* emu_menu)
{ {
QAction* action = m_state_load_slots_menu->addAction(QString{}); QAction* action = m_state_load_slots_menu->addAction(QString{});
connect(action, &QAction::triggered, this, [=]() { emit StateLoadSlotAt(i); }); connect(action, &QAction::triggered, this, [=, this]() { emit StateLoadSlotAt(i); });
} }
} }
@ -360,7 +360,7 @@ void MenuBar::AddStateSaveMenu(QMenu* emu_menu)
{ {
QAction* action = m_state_save_slots_menu->addAction(QString{}); QAction* action = m_state_save_slots_menu->addAction(QString{});
connect(action, &QAction::triggered, this, [=]() { emit StateSaveSlotAt(i); }); connect(action, &QAction::triggered, this, [=, this]() { emit StateSaveSlotAt(i); });
} }
} }
@ -377,7 +377,7 @@ void MenuBar::AddStateSlotMenu(QMenu* emu_menu)
if (Settings::Instance().GetStateSlot() == i) if (Settings::Instance().GetStateSlot() == i)
action->setChecked(true); action->setChecked(true);
connect(action, &QAction::triggered, this, [=]() { emit SetStateSlot(i); }); connect(action, &QAction::triggered, this, [=, this]() { emit SetStateSlot(i); });
} }
} }

View File

@ -369,7 +369,7 @@ void NetPlayDialog::ConnectWidgets()
} }
}); });
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [=](Core::State state) { connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
if (isVisible()) if (isVisible())
{ {
GameStatusChanged(state != Core::State::Uninitialized); GameStatusChanged(state != Core::State::Uninitialized);
@ -850,8 +850,7 @@ void NetPlayDialog::OnMsgStartGame()
g_netplay_chat_ui = g_netplay_chat_ui =
std::make_unique<NetPlayChatUI>([this](const std::string& message) { SendMessage(message); }); std::make_unique<NetPlayChatUI>([this](const std::string& message) { SendMessage(message); });
if (m_host_input_authority && if (m_host_input_authority && Settings::Instance().GetNetPlayClient()->GetNetSettings().golf_mode)
Settings::Instance().GetNetPlayClient()->GetNetSettings().m_GolfMode)
{ {
g_netplay_golf_ui = std::make_unique<NetPlayGolfUI>(Settings::Instance().GetNetPlayClient()); g_netplay_golf_ui = std::make_unique<NetPlayGolfUI>(Settings::Instance().GetNetPlayClient());
} }

View File

@ -35,8 +35,9 @@ AudioPane::AudioPane()
ConnectWidgets(); ConnectWidgets();
connect(&Settings::Instance(), &Settings::VolumeChanged, this, &AudioPane::OnVolumeChanged); connect(&Settings::Instance(), &Settings::VolumeChanged, this, &AudioPane::OnVolumeChanged);
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
[=](Core::State state) { OnEmulationStateChanged(state != Core::State::Uninitialized); }); OnEmulationStateChanged(state != Core::State::Uninitialized);
});
OnEmulationStateChanged(Core::GetState() != Core::State::Uninitialized); OnEmulationStateChanged(Core::GetState() != Core::State::Uninitialized);
} }

View File

@ -213,8 +213,9 @@ void InterfacePane::ConnectLayout()
connect(m_checkbox_disable_screensaver, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig); connect(m_checkbox_disable_screensaver, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
connect(m_checkbox_show_debugging_ui, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig); connect(m_checkbox_show_debugging_ui, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
connect(m_checkbox_focused_hotkeys, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig); connect(m_checkbox_focused_hotkeys, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
connect(m_combobox_theme, qOverload<int>(&QComboBox::currentIndexChanged), this, connect(
[=](int index) { Settings::Instance().SetThemeName(m_combobox_theme->itemText(index)); }); m_combobox_theme, qOverload<int>(&QComboBox::currentIndexChanged), this,
[this](int index) { Settings::Instance().SetThemeName(m_combobox_theme->itemText(index)); });
connect(m_combobox_userstyle, qOverload<int>(&QComboBox::currentIndexChanged), this, connect(m_combobox_userstyle, qOverload<int>(&QComboBox::currentIndexChanged), this,
&InterfacePane::OnSaveConfig); &InterfacePane::OnSaveConfig);
connect(m_combobox_language, qOverload<int>(&QComboBox::currentIndexChanged), this, connect(m_combobox_language, qOverload<int>(&QComboBox::currentIndexChanged), this,

View File

@ -196,7 +196,7 @@ QGridLayout* PathPane::MakePathsLayout()
m_dump_edit = new QLineEdit(QString::fromStdString(File::GetUserPath(D_DUMP_IDX))); m_dump_edit = new QLineEdit(QString::fromStdString(File::GetUserPath(D_DUMP_IDX)));
connect(m_dump_edit, &QLineEdit::editingFinished, connect(m_dump_edit, &QLineEdit::editingFinished,
[=] { Config::SetBase(Config::MAIN_DUMP_PATH, m_dump_edit->text().toStdString()); }); [this] { Config::SetBase(Config::MAIN_DUMP_PATH, m_dump_edit->text().toStdString()); });
QPushButton* dump_open = new NonDefaultQPushButton(QStringLiteral("...")); QPushButton* dump_open = new NonDefaultQPushButton(QStringLiteral("..."));
connect(dump_open, &QPushButton::clicked, this, &PathPane::BrowseDump); connect(dump_open, &QPushButton::clicked, this, &PathPane::BrowseDump);
layout->addWidget(new QLabel(tr("Dump Path:")), 2, 0); layout->addWidget(new QLabel(tr("Dump Path:")), 2, 0);
@ -205,7 +205,7 @@ QGridLayout* PathPane::MakePathsLayout()
m_load_edit = new QLineEdit(QString::fromStdString(File::GetUserPath(D_LOAD_IDX))); m_load_edit = new QLineEdit(QString::fromStdString(File::GetUserPath(D_LOAD_IDX)));
connect(m_load_edit, &QLineEdit::editingFinished, connect(m_load_edit, &QLineEdit::editingFinished,
[=] { Config::SetBase(Config::MAIN_LOAD_PATH, m_load_edit->text().toStdString()); }); [this] { Config::SetBase(Config::MAIN_LOAD_PATH, m_load_edit->text().toStdString()); });
QPushButton* load_open = new NonDefaultQPushButton(QStringLiteral("...")); QPushButton* load_open = new NonDefaultQPushButton(QStringLiteral("..."));
connect(load_open, &QPushButton::clicked, this, &PathPane::BrowseLoad); connect(load_open, &QPushButton::clicked, this, &PathPane::BrowseLoad);
layout->addWidget(new QLabel(tr("Load Path:")), 3, 0); layout->addWidget(new QLabel(tr("Load Path:")), 3, 0);
@ -214,7 +214,7 @@ QGridLayout* PathPane::MakePathsLayout()
m_resource_pack_edit = m_resource_pack_edit =
new QLineEdit(QString::fromStdString(File::GetUserPath(D_RESOURCEPACK_IDX))); new QLineEdit(QString::fromStdString(File::GetUserPath(D_RESOURCEPACK_IDX)));
connect(m_resource_pack_edit, &QLineEdit::editingFinished, [=] { connect(m_resource_pack_edit, &QLineEdit::editingFinished, [this] {
Config::SetBase(Config::MAIN_RESOURCEPACK_PATH, m_resource_pack_edit->text().toStdString()); Config::SetBase(Config::MAIN_RESOURCEPACK_PATH, m_resource_pack_edit->text().toStdString());
}); });
QPushButton* resource_pack_open = new NonDefaultQPushButton(QStringLiteral("...")); QPushButton* resource_pack_open = new NonDefaultQPushButton(QStringLiteral("..."));
@ -225,7 +225,7 @@ QGridLayout* PathPane::MakePathsLayout()
m_wfs_edit = new QLineEdit(QString::fromStdString(File::GetUserPath(D_WFSROOT_IDX))); m_wfs_edit = new QLineEdit(QString::fromStdString(File::GetUserPath(D_WFSROOT_IDX)));
connect(m_load_edit, &QLineEdit::editingFinished, connect(m_load_edit, &QLineEdit::editingFinished,
[=] { Config::SetBase(Config::MAIN_WFS_PATH, m_wfs_edit->text().toStdString()); }); [this] { Config::SetBase(Config::MAIN_WFS_PATH, m_wfs_edit->text().toStdString()); });
QPushButton* wfs_open = new NonDefaultQPushButton(QStringLiteral("...")); QPushButton* wfs_open = new NonDefaultQPushButton(QStringLiteral("..."));
connect(wfs_open, &QPushButton::clicked, this, &PathPane::BrowseWFS); connect(wfs_open, &QPushButton::clicked, this, &PathPane::BrowseWFS);
layout->addWidget(new QLabel(tr("WFS Path:")), 5, 0); layout->addWidget(new QLabel(tr("WFS Path:")), 5, 0);

View File

@ -107,8 +107,9 @@ void WiiPane::ConnectLayout()
connect(m_wiimote_motor, &QCheckBox::toggled, this, &WiiPane::OnSaveConfig); connect(m_wiimote_motor, &QCheckBox::toggled, this, &WiiPane::OnSaveConfig);
// Emulation State // Emulation State
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
[=](Core::State state) { OnEmulationStateChanged(state != Core::State::Uninitialized); }); OnEmulationStateChanged(state != Core::State::Uninitialized);
});
} }
void WiiPane::CreateMisc() void WiiPane::CreateMisc()

View File

@ -103,13 +103,15 @@ struct ThreePointCalibration
template <typename T, size_t Bits> template <typename T, size_t Bits>
struct RawValue struct RawValue
{ {
RawValue() = default; constexpr RawValue() = default;
explicit RawValue(const T& value_) : value{value_} {} constexpr explicit RawValue(const T& value_) : value{value_} {}
static constexpr size_t BITS_OF_PRECISION = Bits; static constexpr size_t BITS_OF_PRECISION = Bits;
T value; T value;
constexpr bool operator==(const RawValue& other) const = default;
template <typename OtherT, size_t OtherBits> template <typename OtherT, size_t OtherBits>
auto GetNormalizedValue(const TwoPointCalibration<OtherT, OtherBits>& calibration) const auto GetNormalizedValue(const TwoPointCalibration<OtherT, OtherBits>& calibration) const
{ {
@ -206,9 +208,9 @@ public:
static_assert(std::is_integral<T>(), "T is only sane for int types."); static_assert(std::is_integral<T>(), "T is only sane for int types.");
static_assert(std::is_floating_point<F>(), "F is only sane for float types."); static_assert(std::is_floating_point<F>(), "F is only sane for float types.");
static_assert(std::numeric_limits<long>::min() <= std::numeric_limits<T>::min() && static_assert(std::numeric_limits<long long>::min() <= std::numeric_limits<T>::min() &&
std::numeric_limits<long>::max() >= std::numeric_limits<T>::max(), std::numeric_limits<long long>::max() >= std::numeric_limits<T>::max(),
"long is not a superset of T. use of std::lround is not sane."); "long long is not a superset of T. use of std::llround is not sane.");
// Here we round when converting from float to int. // Here we round when converting from float to int.
// After applying our deadzone, resizing, and reshaping math // After applying our deadzone, resizing, and reshaping math
@ -216,9 +218,9 @@ public:
// Casting would round down but rounding will yield our "zero_value". // Casting would round down but rounding will yield our "zero_value".
if (input_value > 0) if (input_value > 0)
return T(std::lround((pos_1_value - zero_value) * input_value + zero_value)); return T(std::llround((pos_1_value - zero_value) * input_value + zero_value));
else else
return T(std::lround((zero_value - neg_1_value) * input_value + zero_value)); return T(std::llround((zero_value - neg_1_value) * input_value + zero_value));
} }
protected: protected:

View File

@ -4,6 +4,7 @@
#include "UpdaterCommon/UpdaterCommon.h" #include "UpdaterCommon/UpdaterCommon.h"
#include <array> #include <array>
#include <memory>
#include <optional> #include <optional>
#include <OptionParser.h> #include <OptionParser.h>
@ -132,16 +133,17 @@ std::optional<std::string> GzipInflate(const std::string& data)
inflateInit2(&zstrm, 16 + MAX_WBITS); inflateInit2(&zstrm, 16 + MAX_WBITS);
std::string out; std::string out;
char buffer[4096]; const size_t buf_len = 20 * 1024 * 1024;
auto buffer = std::make_unique<char[]>(buf_len);
int ret; int ret;
do do
{ {
zstrm.avail_out = sizeof(buffer); zstrm.avail_out = buf_len;
zstrm.next_out = reinterpret_cast<u8*>(buffer); zstrm.next_out = reinterpret_cast<u8*>(buffer.get());
ret = inflate(&zstrm, 0); ret = inflate(&zstrm, 0);
out.append(buffer, sizeof(buffer) - zstrm.avail_out); out.append(buffer.get(), buf_len - zstrm.avail_out);
} while (ret == Z_OK); } while (ret == Z_OK);
inflateEnd(&zstrm); inflateEnd(&zstrm);

View File

@ -112,6 +112,7 @@ void VideoBackend::FillBackendInfo()
g_Config.backend_info.bSupportsLogicOp = D3D::SupportsLogicOp(g_Config.iAdapter); g_Config.backend_info.bSupportsLogicOp = D3D::SupportsLogicOp(g_Config.iAdapter);
g_Config.backend_info.bSupportsSettingObjectNames = true; g_Config.backend_info.bSupportsSettingObjectNames = true;
g_Config.backend_info.bSupportsPartialMultisampleResolve = true; g_Config.backend_info.bSupportsPartialMultisampleResolve = true;
g_Config.backend_info.bSupportsDynamicVertexLoader = false;
g_Config.backend_info.Adapters = D3DCommon::GetAdapterNames(); g_Config.backend_info.Adapters = D3DCommon::GetAdapterNames();
g_Config.backend_info.AAModes = D3D::GetAAModes(g_Config.iAdapter); g_Config.backend_info.AAModes = D3D::GetAAModes(g_Config.iAdapter);

View File

@ -180,7 +180,8 @@ void Renderer::SetPipeline(const AbstractPipeline* pipeline)
m_state.root_signature = dx_pipeline->GetRootSignature(); m_state.root_signature = dx_pipeline->GetRootSignature();
m_dirty_bits |= DirtyState_RootSignature | DirtyState_PS_CBV | DirtyState_VS_CBV | m_dirty_bits |= DirtyState_RootSignature | DirtyState_PS_CBV | DirtyState_VS_CBV |
DirtyState_GS_CBV | DirtyState_SRV_Descriptor | DirtyState_GS_CBV | DirtyState_SRV_Descriptor |
DirtyState_Sampler_Descriptor | DirtyState_UAV_Descriptor; DirtyState_Sampler_Descriptor | DirtyState_UAV_Descriptor |
DirtyState_VS_SRV_Descriptor;
} }
if (dx_pipeline->UseIntegerRTV() != m_state.using_integer_rtv) if (dx_pipeline->UseIntegerRTV() != m_state.using_integer_rtv)
{ {
@ -362,6 +363,11 @@ void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
if (!ApplyState()) if (!ApplyState())
return; return;
// DX12 is great and doesn't include the base vertex in SV_VertexID
if (static_cast<const DXPipeline*>(m_current_pipeline)->GetUsage() ==
AbstractPipelineUsage::GXUber)
g_dx_context->GetCommandList()->SetGraphicsRoot32BitConstant(
ROOT_PARAMETER_BASE_VERTEX_CONSTANT, base_vertex, 0);
g_dx_context->GetCommandList()->DrawIndexedInstanced(num_indices, 1, base_index, base_vertex, 0); g_dx_context->GetCommandList()->DrawIndexedInstanced(num_indices, 1, base_index, base_vertex, 0);
} }
@ -494,19 +500,23 @@ void Renderer::SetPixelShaderUAV(D3D12_CPU_DESCRIPTOR_HANDLE handle)
m_dirty_bits |= DirtyState_PS_UAV; m_dirty_bits |= DirtyState_PS_UAV;
} }
void Renderer::SetVertexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, u32 stride, u32 size) void Renderer::SetVertexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, D3D12_CPU_DESCRIPTOR_HANDLE srv,
u32 stride, u32 size)
{ {
if (m_state.vertex_buffer.BufferLocation == address && if (m_state.vertex_buffer.BufferLocation != address ||
m_state.vertex_buffer.StrideInBytes == stride && m_state.vertex_buffer.SizeInBytes == size) m_state.vertex_buffer.StrideInBytes != stride || m_state.vertex_buffer.SizeInBytes != size)
{ {
return;
}
m_state.vertex_buffer.BufferLocation = address; m_state.vertex_buffer.BufferLocation = address;
m_state.vertex_buffer.StrideInBytes = stride; m_state.vertex_buffer.StrideInBytes = stride;
m_state.vertex_buffer.SizeInBytes = size; m_state.vertex_buffer.SizeInBytes = size;
m_dirty_bits |= DirtyState_VertexBuffer; m_dirty_bits |= DirtyState_VertexBuffer;
} }
if (m_state.vs_srv.ptr != srv.ptr)
{
m_state.vs_srv = srv;
m_dirty_bits |= DirtyState_VS_SRV;
}
}
void Renderer::SetIndexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, u32 size, DXGI_FORMAT format) void Renderer::SetIndexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, u32 size, DXGI_FORMAT format)
{ {
@ -535,15 +545,17 @@ bool Renderer::ApplyState()
// Clear bits before actually changing state. Some state (e.g. cbuffers) can't be set // Clear bits before actually changing state. Some state (e.g. cbuffers) can't be set
// if utility pipelines are bound. // if utility pipelines are bound.
const u32 dirty_bits = m_dirty_bits; const u32 dirty_bits = m_dirty_bits;
m_dirty_bits &= ~( m_dirty_bits &=
DirtyState_Framebuffer | DirtyState_Pipeline | DirtyState_Viewport | DirtyState_ScissorRect | ~(DirtyState_Framebuffer | DirtyState_Pipeline | DirtyState_Viewport |
DirtyState_PS_UAV | DirtyState_PS_CBV | DirtyState_VS_CBV | DirtyState_GS_CBV | DirtyState_ScissorRect | DirtyState_PS_UAV | DirtyState_PS_CBV | DirtyState_VS_CBV |
DirtyState_SRV_Descriptor | DirtyState_Sampler_Descriptor | DirtyState_UAV_Descriptor | DirtyState_GS_CBV | DirtyState_SRV_Descriptor | DirtyState_Sampler_Descriptor |
DirtyState_VertexBuffer | DirtyState_IndexBuffer | DirtyState_PrimitiveTopology); DirtyState_UAV_Descriptor | DirtyState_VertexBuffer | DirtyState_IndexBuffer |
DirtyState_PrimitiveTopology | DirtyState_VS_SRV_Descriptor);
auto* const cmdlist = g_dx_context->GetCommandList(); auto* const cmdlist = g_dx_context->GetCommandList();
auto* const pipeline = static_cast<const DXPipeline*>(m_current_pipeline);
if (dirty_bits & DirtyState_Pipeline) if (dirty_bits & DirtyState_Pipeline)
cmdlist->SetPipelineState(static_cast<const DXPipeline*>(m_current_pipeline)->GetPipeline()); cmdlist->SetPipelineState(pipeline->GetPipeline());
if (dirty_bits & DirtyState_Framebuffer) if (dirty_bits & DirtyState_Framebuffer)
BindFramebuffer(static_cast<DXFramebuffer*>(m_current_framebuffer)); BindFramebuffer(static_cast<DXFramebuffer*>(m_current_framebuffer));
@ -572,7 +584,7 @@ bool Renderer::ApplyState()
m_state.sampler_descriptor_base); m_state.sampler_descriptor_base);
} }
if (static_cast<const DXPipeline*>(m_current_pipeline)->GetUsage() == AbstractPipelineUsage::GX) if (pipeline->GetUsage() != AbstractPipelineUsage::Utility)
{ {
if (dirty_bits & DirtyState_VS_CBV) if (dirty_bits & DirtyState_VS_CBV)
{ {
@ -589,6 +601,13 @@ bool Renderer::ApplyState()
} }
} }
if (dirty_bits & DirtyState_VS_SRV_Descriptor &&
pipeline->GetUsage() == AbstractPipelineUsage::GXUber)
{
cmdlist->SetGraphicsRootDescriptorTable(ROOT_PARAMETER_VS_SRV,
m_state.vertex_srv_descriptor_base);
}
if (dirty_bits & DirtyState_GS_CBV) if (dirty_bits & DirtyState_GS_CBV)
{ {
cmdlist->SetGraphicsRootConstantBufferView(ROOT_PARAMETER_GS_CBV, cmdlist->SetGraphicsRootConstantBufferView(ROOT_PARAMETER_GS_CBV,
@ -641,7 +660,9 @@ void Renderer::UpdateDescriptorTables()
const bool sampler_update_failed = const bool sampler_update_failed =
(m_dirty_bits & DirtyState_Samplers) && !UpdateSamplerDescriptorTable(); (m_dirty_bits & DirtyState_Samplers) && !UpdateSamplerDescriptorTable();
const bool uav_update_failed = (m_dirty_bits & DirtyState_PS_UAV) && !UpdateUAVDescriptorTable(); const bool uav_update_failed = (m_dirty_bits & DirtyState_PS_UAV) && !UpdateUAVDescriptorTable();
if (texture_update_failed || sampler_update_failed || uav_update_failed) const bool srv_update_failed =
(m_dirty_bits & DirtyState_VS_SRV) && !UpdateVSSRVDescriptorTable();
if (texture_update_failed || sampler_update_failed || uav_update_failed || srv_update_failed)
{ {
WARN_LOG_FMT(VIDEO, "Executing command list while waiting for temporary {}", WARN_LOG_FMT(VIDEO, "Executing command list while waiting for temporary {}",
texture_update_failed ? "descriptors" : "samplers"); texture_update_failed ? "descriptors" : "samplers");
@ -651,6 +672,7 @@ void Renderer::UpdateDescriptorTables()
UpdateSRVDescriptorTable(); UpdateSRVDescriptorTable();
UpdateSamplerDescriptorTable(); UpdateSamplerDescriptorTable();
UpdateUAVDescriptorTable(); UpdateUAVDescriptorTable();
UpdateVSSRVDescriptorTable();
} }
} }
@ -700,6 +722,26 @@ bool Renderer::UpdateUAVDescriptorTable()
return true; return true;
} }
bool Renderer::UpdateVSSRVDescriptorTable()
{
if (!g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader ||
static_cast<const DXPipeline*>(m_current_pipeline)->GetUsage() !=
AbstractPipelineUsage::GXUber)
{
return true;
}
DescriptorHandle handle;
if (!g_dx_context->GetDescriptorAllocator()->Allocate(1, &handle))
return false;
g_dx_context->GetDevice()->CopyDescriptorsSimple(1, handle.cpu_handle, m_state.vs_srv,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
m_state.vertex_srv_descriptor_base = handle.gpu_handle;
m_dirty_bits = (m_dirty_bits & ~DirtyState_VS_SRV) | DirtyState_VS_SRV_Descriptor;
return true;
}
bool Renderer::UpdateComputeUAVDescriptorTable() bool Renderer::UpdateComputeUAVDescriptorTable()
{ {
DescriptorHandle handle; DescriptorHandle handle;

View File

@ -88,7 +88,8 @@ public:
void SetPixelShaderUAV(D3D12_CPU_DESCRIPTOR_HANDLE handle); void SetPixelShaderUAV(D3D12_CPU_DESCRIPTOR_HANDLE handle);
// Graphics vertex/index buffer binding. // Graphics vertex/index buffer binding.
void SetVertexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, u32 stride, u32 size); void SetVertexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, D3D12_CPU_DESCRIPTOR_HANDLE srv,
u32 stride, u32 size);
void SetIndexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, u32 size, DXGI_FORMAT format); void SetIndexBuffer(D3D12_GPU_VIRTUAL_ADDRESS address, u32 size, DXGI_FORMAT format);
// Binds all dirty state // Binds all dirty state
@ -126,6 +127,8 @@ private:
DirtyState_RootSignature = (1 << 17), DirtyState_RootSignature = (1 << 17),
DirtyState_ComputeRootSignature = (1 << 18), DirtyState_ComputeRootSignature = (1 << 18),
DirtyState_DescriptorHeaps = (1 << 19), DirtyState_DescriptorHeaps = (1 << 19),
DirtyState_VS_SRV = (1 << 20),
DirtyState_VS_SRV_Descriptor = (1 << 21),
DirtyState_All = DirtyState_All =
DirtyState_Framebuffer | DirtyState_Pipeline | DirtyState_Textures | DirtyState_Samplers | DirtyState_Framebuffer | DirtyState_Pipeline | DirtyState_Textures | DirtyState_Samplers |
@ -133,7 +136,8 @@ private:
DirtyState_PS_UAV | DirtyState_PS_CBV | DirtyState_VS_CBV | DirtyState_GS_CBV | DirtyState_PS_UAV | DirtyState_PS_CBV | DirtyState_VS_CBV | DirtyState_GS_CBV |
DirtyState_SRV_Descriptor | DirtyState_Sampler_Descriptor | DirtyState_UAV_Descriptor | DirtyState_SRV_Descriptor | DirtyState_Sampler_Descriptor | DirtyState_UAV_Descriptor |
DirtyState_VertexBuffer | DirtyState_IndexBuffer | DirtyState_PrimitiveTopology | DirtyState_VertexBuffer | DirtyState_IndexBuffer | DirtyState_PrimitiveTopology |
DirtyState_RootSignature | DirtyState_ComputeRootSignature | DirtyState_DescriptorHeaps DirtyState_RootSignature | DirtyState_ComputeRootSignature | DirtyState_DescriptorHeaps |
DirtyState_VS_SRV | DirtyState_VS_SRV_Descriptor
}; };
void CheckForSwapChainChanges(); void CheckForSwapChainChanges();
@ -144,6 +148,7 @@ private:
void UpdateDescriptorTables(); void UpdateDescriptorTables();
bool UpdateSRVDescriptorTable(); bool UpdateSRVDescriptorTable();
bool UpdateUAVDescriptorTable(); bool UpdateUAVDescriptorTable();
bool UpdateVSSRVDescriptorTable();
bool UpdateComputeUAVDescriptorTable(); bool UpdateComputeUAVDescriptorTable();
bool UpdateSamplerDescriptorTable(); bool UpdateSamplerDescriptorTable();
@ -157,11 +162,13 @@ private:
DXShader* compute_shader = nullptr; DXShader* compute_shader = nullptr;
std::array<D3D12_GPU_VIRTUAL_ADDRESS, 3> constant_buffers = {}; std::array<D3D12_GPU_VIRTUAL_ADDRESS, 3> constant_buffers = {};
std::array<D3D12_CPU_DESCRIPTOR_HANDLE, MAX_TEXTURES> textures = {}; std::array<D3D12_CPU_DESCRIPTOR_HANDLE, MAX_TEXTURES> textures = {};
D3D12_CPU_DESCRIPTOR_HANDLE vs_srv = {};
D3D12_CPU_DESCRIPTOR_HANDLE ps_uav = {}; D3D12_CPU_DESCRIPTOR_HANDLE ps_uav = {};
SamplerStateSet samplers = {}; SamplerStateSet samplers = {};
const DXTexture* compute_image_texture = nullptr; const DXTexture* compute_image_texture = nullptr;
D3D12_VIEWPORT viewport = {}; D3D12_VIEWPORT viewport = {};
D3D12_RECT scissor = {}; D3D12_RECT scissor = {};
D3D12_GPU_DESCRIPTOR_HANDLE vertex_srv_descriptor_base = {};
D3D12_GPU_DESCRIPTOR_HANDLE srv_descriptor_base = {}; D3D12_GPU_DESCRIPTOR_HANDLE srv_descriptor_base = {};
D3D12_GPU_DESCRIPTOR_HANDLE sampler_descriptor_base = {}; D3D12_GPU_DESCRIPTOR_HANDLE sampler_descriptor_base = {};
D3D12_GPU_DESCRIPTOR_HANDLE uav_descriptor_base = {}; D3D12_GPU_DESCRIPTOR_HANDLE uav_descriptor_base = {};

View File

@ -64,6 +64,18 @@ bool VertexManager::Initialize()
&srv_desc, dh.cpu_handle); &srv_desc, dh.cpu_handle);
} }
if (!g_dx_context->GetDescriptorHeapManager().Allocate(&m_vertex_srv))
{
PanicAlertFmt("Failed to allocate descriptor for vertex srv");
return false;
}
D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {DXGI_FORMAT_R32_UINT, D3D12_SRV_DIMENSION_BUFFER,
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING};
srv_desc.Buffer.NumElements = m_vertex_stream_buffer.GetSize() / sizeof(u32);
g_dx_context->GetDevice()->CreateShaderResourceView(m_vertex_stream_buffer.GetBuffer(), &srv_desc,
m_vertex_srv.cpu_handle);
UploadAllConstants(); UploadAllConstants();
return true; return true;
} }
@ -115,7 +127,8 @@ void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_in
ADDSTAT(g_stats.this_frame.bytes_vertex_streamed, static_cast<int>(vertex_data_size)); ADDSTAT(g_stats.this_frame.bytes_vertex_streamed, static_cast<int>(vertex_data_size));
ADDSTAT(g_stats.this_frame.bytes_index_streamed, static_cast<int>(index_data_size)); ADDSTAT(g_stats.this_frame.bytes_index_streamed, static_cast<int>(index_data_size));
Renderer::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer.GetGPUPointer(), vertex_stride, Renderer::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer.GetGPUPointer(),
m_vertex_srv.cpu_handle, vertex_stride,
m_vertex_stream_buffer.GetSize()); m_vertex_stream_buffer.GetSize());
Renderer::GetInstance()->SetIndexBuffer(m_index_stream_buffer.GetGPUPointer(), Renderer::GetInstance()->SetIndexBuffer(m_index_stream_buffer.GetGPUPointer(),
m_index_stream_buffer.GetSize(), DXGI_FORMAT_R16_UINT); m_index_stream_buffer.GetSize(), DXGI_FORMAT_R16_UINT);

View File

@ -46,6 +46,7 @@ protected:
StreamBuffer m_uniform_stream_buffer; StreamBuffer m_uniform_stream_buffer;
StreamBuffer m_texel_stream_buffer; StreamBuffer m_texel_stream_buffer;
std::array<DescriptorHandle, NUM_TEXEL_BUFFER_FORMATS> m_texel_buffer_views = {}; std::array<DescriptorHandle, NUM_TEXEL_BUFFER_FORMATS> m_texel_buffer_views = {};
DescriptorHandle m_vertex_srv = {};
}; };
} // namespace DX12 } // namespace DX12

View File

@ -261,6 +261,16 @@ bool DXContext::CreateDescriptorHeaps()
return true; return true;
} }
static void SetRootParamConstant(D3D12_ROOT_PARAMETER* rp, u32 shader_reg, u32 num_values,
D3D12_SHADER_VISIBILITY visibility)
{
rp->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
rp->Constants.Num32BitValues = num_values;
rp->Constants.ShaderRegister = shader_reg;
rp->Constants.RegisterSpace = 0;
rp->ShaderVisibility = visibility;
}
static void SetRootParamCBV(D3D12_ROOT_PARAMETER* rp, u32 shader_reg, static void SetRootParamCBV(D3D12_ROOT_PARAMETER* rp, u32 shader_reg,
D3D12_SHADER_VISIBILITY visibility) D3D12_SHADER_VISIBILITY visibility)
{ {
@ -345,6 +355,11 @@ bool DXContext::CreateGXRootSignature()
param_count++; param_count++;
SetRootParamCBV(&params[param_count], 0, D3D12_SHADER_VISIBILITY_GEOMETRY); SetRootParamCBV(&params[param_count], 0, D3D12_SHADER_VISIBILITY_GEOMETRY);
param_count++; param_count++;
SetRootParamTable(&params[param_count], &ranges[param_count], D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 3,
1, D3D12_SHADER_VISIBILITY_VERTEX);
param_count++;
SetRootParamConstant(&params[param_count], 2, 1, D3D12_SHADER_VISIBILITY_VERTEX);
param_count++;
// Since these must be contiguous, pixel lighting goes to bbox if not enabled. // Since these must be contiguous, pixel lighting goes to bbox if not enabled.
if (g_ActiveConfig.bBBoxEnable) if (g_ActiveConfig.bBBoxEnable)

View File

@ -27,6 +27,8 @@ enum ROOT_PARAMETER
ROOT_PARAMETER_VS_CBV, ROOT_PARAMETER_VS_CBV,
ROOT_PARAMETER_VS_CBV2, ROOT_PARAMETER_VS_CBV2,
ROOT_PARAMETER_GS_CBV, ROOT_PARAMETER_GS_CBV,
ROOT_PARAMETER_VS_SRV,
ROOT_PARAMETER_BASE_VERTEX_CONSTANT,
ROOT_PARAMETER_PS_UAV_OR_CBV2, ROOT_PARAMETER_PS_UAV_OR_CBV2,
ROOT_PARAMETER_PS_CBV2, // ROOT_PARAMETER_PS_UAV_OR_CBV2 if bbox is not enabled ROOT_PARAMETER_PS_CBV2, // ROOT_PARAMETER_PS_UAV_OR_CBV2 if bbox is not enabled
NUM_ROOT_PARAMETERS NUM_ROOT_PARAMETERS

View File

@ -165,6 +165,7 @@ std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& con
switch (config.usage) switch (config.usage)
{ {
case AbstractPipelineUsage::GX: case AbstractPipelineUsage::GX:
case AbstractPipelineUsage::GXUber:
desc.pRootSignature = g_dx_context->GetGXRootSignature(); desc.pRootSignature = g_dx_context->GetGXRootSignature();
break; break;
case AbstractPipelineUsage::Utility: case AbstractPipelineUsage::Utility:

View File

@ -87,6 +87,7 @@ void VideoBackend::FillBackendInfo()
g_Config.backend_info.bSupportsLodBiasInSampler = true; g_Config.backend_info.bSupportsLodBiasInSampler = true;
g_Config.backend_info.bSupportsSettingObjectNames = true; g_Config.backend_info.bSupportsSettingObjectNames = true;
g_Config.backend_info.bSupportsPartialMultisampleResolve = true; g_Config.backend_info.bSupportsPartialMultisampleResolve = true;
g_Config.backend_info.bSupportsDynamicVertexLoader = true;
// We can only check texture support once we have a device. // We can only check texture support once we have a device.
if (g_dx_context) if (g_dx_context)

View File

@ -220,7 +220,7 @@ static MTLCullMode Convert(CullMode cull)
switch (cull) switch (cull)
{ {
case CullMode::None: case CullMode::None:
case CullMode::All: // Handled by disabling rasterization case CullMode::All: // Handled by VertexLoaderManager::RunVertices
return MTLCullModeNone; return MTLCullModeNone;
case CullMode::Front: case CullMode::Front:
return MTLCullModeFront; return MTLCullModeFront;
@ -289,7 +289,8 @@ public:
} }
}; };
template <size_t N> template <size_t N>
static void CopyAll(std::array<VertexAttribute, N>& output, const AttributeFormat (&input)[N]) static void CopyAll(std::array<VertexAttribute, N>& output,
const std::array<AttributeFormat, N>& input)
{ {
for (size_t i = 0; i < N; ++i) for (size_t i = 0; i < N; ++i)
output[i] = VertexAttribute(input[i]); output[i] = VertexAttribute(input[i]);
@ -327,13 +328,14 @@ public:
blend.subtractAlpha = cfg.blending_state.subtractAlpha.Value(); blend.subtractAlpha = cfg.blending_state.subtractAlpha.Value();
// clang-format on // clang-format on
} }
// Throw extras in bits we don't otherwise use
if (cfg.rasterization_state.cullmode == CullMode::All) if (cfg.usage != AbstractPipelineUsage::GXUber)
blend.hex |= 1 << 29; {
if (cfg.rasterization_state.primitive == PrimitiveType::Points) if (cfg.rasterization_state.primitive == PrimitiveType::Points)
blend.hex |= 1 << 30; is_points = true;
else if (cfg.rasterization_state.primitive == PrimitiveType::Lines) else if (cfg.rasterization_state.primitive == PrimitiveType::Lines)
blend.hex |= 1 << 31; is_lines = true;
}
} }
PipelineID() { memset(this, 0, sizeof(*this)); } PipelineID() { memset(this, 0, sizeof(*this)); }
PipelineID(const PipelineID& other) { memcpy(this, &other, sizeof(*this)); } PipelineID(const PipelineID& other) { memcpy(this, &other, sizeof(*this)); }
@ -359,7 +361,13 @@ public:
VertexAttribute v_posmtx; VertexAttribute v_posmtx;
const Shader* vertex_shader; const Shader* vertex_shader;
const Shader* fragment_shader; const Shader* fragment_shader;
union
{
BlendingState blend; BlendingState blend;
// Throw extras in bits we don't otherwise use
BitField<30, 1, bool, u32> is_points;
BitField<31, 1, bool, u32> is_lines;
};
FramebufferState framebuffer; FramebufferState framebuffer;
}; };
@ -377,24 +385,17 @@ public:
auto desc = MRCTransfer([MTLRenderPipelineDescriptor new]); auto desc = MRCTransfer([MTLRenderPipelineDescriptor new]);
[desc setVertexFunction:static_cast<const Shader*>(config.vertex_shader)->GetShader()]; [desc setVertexFunction:static_cast<const Shader*>(config.vertex_shader)->GetShader()];
[desc setFragmentFunction:static_cast<const Shader*>(config.pixel_shader)->GetShader()]; [desc setFragmentFunction:static_cast<const Shader*>(config.pixel_shader)->GetShader()];
if (config.usage == AbstractPipelineUsage::GX) if (config.usage == AbstractPipelineUsage::GXUber)
{ [desc setLabel:[NSString stringWithFormat:@"GX Uber Pipeline %d", m_pipeline_counter[0]++]];
if ([[[desc vertexFunction] label] containsString:@"Uber"]) else if (config.usage == AbstractPipelineUsage::GX)
[desc
setLabel:[NSString stringWithFormat:@"GX Uber Pipeline %d", m_pipeline_counter[0]++]];
else
[desc setLabel:[NSString stringWithFormat:@"GX Pipeline %d", m_pipeline_counter[1]++]]; [desc setLabel:[NSString stringWithFormat:@"GX Pipeline %d", m_pipeline_counter[1]++]];
}
else else
{
[desc setLabel:[NSString stringWithFormat:@"Utility Pipeline %d", m_pipeline_counter[2]++]]; [desc setLabel:[NSString stringWithFormat:@"Utility Pipeline %d", m_pipeline_counter[2]++]];
}
if (config.vertex_format) if (config.vertex_format)
[desc setVertexDescriptor:static_cast<const VertexFormat*>(config.vertex_format)->Get()]; [desc setVertexDescriptor:static_cast<const VertexFormat*>(config.vertex_format)->Get()];
RasterizationState rs = config.rasterization_state; RasterizationState rs = config.rasterization_state;
if (config.usage != AbstractPipelineUsage::GXUber)
[desc setInputPrimitiveTopology:GetClass(rs.primitive)]; [desc setInputPrimitiveTopology:GetClass(rs.primitive)];
if (rs.cullmode == CullMode::All)
[desc setRasterizationEnabled:NO];
MTLRenderPipelineColorAttachmentDescriptor* color0 = MTLRenderPipelineColorAttachmentDescriptor* color0 =
[[desc colorAttachments] objectAtIndexedSubscript:0]; [[desc colorAttachments] objectAtIndexedSubscript:0];
BlendingState bs = config.blending_state; BlendingState bs = config.blending_state;

View File

@ -608,7 +608,7 @@ void Metal::StateTracker::PrepareRender()
BeginRenderPass(MTLLoadActionLoad); BeginRenderPass(MTLLoadActionLoad);
id<MTLRenderCommandEncoder> enc = m_current_render_encoder; id<MTLRenderCommandEncoder> enc = m_current_render_encoder;
const Pipeline* pipe = m_state.render_pipeline; const Pipeline* pipe = m_state.render_pipeline;
bool is_gx = pipe->Usage() == AbstractPipelineUsage::GX; bool is_gx = pipe->Usage() != AbstractPipelineUsage::Utility;
NSString* label = is_gx ? LABEL_GX : LABEL_UTIL; NSString* label = is_gx ? LABEL_GX : LABEL_UTIL;
if (m_flags.should_apply_label && m_current.label != label) if (m_flags.should_apply_label && m_current.label != label)
{ {

View File

@ -74,6 +74,7 @@ void Metal::Util::PopulateBackendInfo(VideoConfig* config)
config->backend_info.bSupportsSettingObjectNames = true; config->backend_info.bSupportsSettingObjectNames = true;
// Metal requires multisample resolve to be done on a render pass // Metal requires multisample resolve to be done on a render pass
config->backend_info.bSupportsPartialMultisampleResolve = false; config->backend_info.bSupportsPartialMultisampleResolve = false;
config->backend_info.bSupportsDynamicVertexLoader = true;
} }
void Metal::Util::PopulateBackendInfoAdapters(VideoConfig* config, void Metal::Util::PopulateBackendInfoAdapters(VideoConfig* config,
@ -426,6 +427,7 @@ std::optional<std::string> Metal::Util::TranslateShaderToMSL(ShaderStage stage,
static const spirv_cross::MSLResourceBinding resource_bindings[] = { static const spirv_cross::MSLResourceBinding resource_bindings[] = {
MakeResourceBinding(spv::ExecutionModelVertex, 0, 0, 1, 0, 0), // vs/ubo MakeResourceBinding(spv::ExecutionModelVertex, 0, 0, 1, 0, 0), // vs/ubo
MakeResourceBinding(spv::ExecutionModelVertex, 0, 1, 1, 0, 0), // vs/ubo MakeResourceBinding(spv::ExecutionModelVertex, 0, 1, 1, 0, 0), // vs/ubo
MakeResourceBinding(spv::ExecutionModelVertex, 2, 1, 0, 0, 0), // vs/ssbo
MakeResourceBinding(spv::ExecutionModelFragment, 0, 0, 0, 0, 0), // vs/ubo MakeResourceBinding(spv::ExecutionModelFragment, 0, 0, 0, 0, 0), // vs/ubo
MakeResourceBinding(spv::ExecutionModelFragment, 0, 1, 1, 0, 0), // vs/ubo MakeResourceBinding(spv::ExecutionModelFragment, 0, 1, 1, 0, 0), // vs/ubo
MakeResourceBinding(spv::ExecutionModelFragment, 1, 0, 0, 0, 0), // ps/samp0 MakeResourceBinding(spv::ExecutionModelFragment, 1, 0, 0, 0, 0), // ps/samp0

View File

@ -125,7 +125,7 @@ static void SetAttribute(MTLVertexDescriptor* desc, u32 attribute, const Attribu
template <size_t N> template <size_t N>
static void SetAttributes(MTLVertexDescriptor* desc, u32 attribute, static void SetAttributes(MTLVertexDescriptor* desc, u32 attribute,
const AttributeFormat (&format)[N]) const std::array<AttributeFormat, N>& format)
{ {
for (size_t i = 0; i < N; ++i) for (size_t i = 0; i < N; ++i)
SetAttribute(desc, attribute + i, format[i]); SetAttribute(desc, attribute + i, format[i]);

View File

@ -60,6 +60,7 @@ void VideoBackend::InitBackendInfo()
g_Config.backend_info.bSupportsLodBiasInSampler = false; g_Config.backend_info.bSupportsLodBiasInSampler = false;
g_Config.backend_info.bSupportsSettingObjectNames = false; g_Config.backend_info.bSupportsSettingObjectNames = false;
g_Config.backend_info.bSupportsPartialMultisampleResolve = true; g_Config.backend_info.bSupportsPartialMultisampleResolve = true;
g_Config.backend_info.bSupportsDynamicVertexLoader = false;
// aamodes: We only support 1 sample, so no MSAA // aamodes: We only support 1 sample, so no MSAA
g_Config.backend_info.Adapters.clear(); g_Config.backend_info.Adapters.clear();

View File

@ -94,6 +94,8 @@ void VideoBackend::InitBackendInfo()
g_Config.backend_info.bSupportsPipelineCacheData = false; g_Config.backend_info.bSupportsPipelineCacheData = false;
g_Config.backend_info.bSupportsLodBiasInSampler = true; g_Config.backend_info.bSupportsLodBiasInSampler = true;
g_Config.backend_info.bSupportsPartialMultisampleResolve = true; g_Config.backend_info.bSupportsPartialMultisampleResolve = true;
// Unneccessary since OGL doesn't use pipelines
g_Config.backend_info.bSupportsDynamicVertexLoader = false;
// TODO: There is a bug here, if texel buffers or SSBOs/atomics are not supported the graphics // TODO: There is a bug here, if texel buffers or SSBOs/atomics are not supported the graphics
// options will show the option when it is not supported. The only way around this would be // options will show the option when it is not supported. The only way around this would be

View File

@ -89,6 +89,7 @@ void VideoSoftware::InitBackendInfo()
g_Config.backend_info.bSupportsLodBiasInSampler = false; g_Config.backend_info.bSupportsLodBiasInSampler = false;
g_Config.backend_info.bSupportsSettingObjectNames = false; g_Config.backend_info.bSupportsSettingObjectNames = false;
g_Config.backend_info.bSupportsPartialMultisampleResolve = true; g_Config.backend_info.bSupportsPartialMultisampleResolve = true;
g_Config.backend_info.bSupportsDynamicVertexLoader = false;
// aamodes // aamodes
g_Config.backend_info.AAModes = {1}; g_Config.backend_info.AAModes = {1};

View File

@ -39,6 +39,8 @@ enum DESCRIPTOR_SET_LAYOUT
// - Per-stage UBO (VS/GS/PS, VS constants accessible from PS) [set=0, binding=0-2] // - Per-stage UBO (VS/GS/PS, VS constants accessible from PS) [set=0, binding=0-2]
// - 8 combined image samplers (accessible from PS) [set=1, binding=0-7] // - 8 combined image samplers (accessible from PS) [set=1, binding=0-7]
// - 1 SSBO accessible from PS if supported [set=2, binding=0] // - 1 SSBO accessible from PS if supported [set=2, binding=0]
// - Uber
// - Like standard, plus 1 SSBO accessible from VS if supported [set=2, binding=1]
// - Utility // - Utility
// - 1 combined UBO, accessible from VS/GS/PS [set=0, binding=0] // - 1 combined UBO, accessible from VS/GS/PS [set=0, binding=0]
// - 8 combined image samplers (accessible from PS) [set=1, binding=0-7] // - 8 combined image samplers (accessible from PS) [set=1, binding=0-7]
@ -55,6 +57,7 @@ enum DESCRIPTOR_SET_LAYOUT
enum PIPELINE_LAYOUT enum PIPELINE_LAYOUT
{ {
PIPELINE_LAYOUT_STANDARD, PIPELINE_LAYOUT_STANDARD,
PIPELINE_LAYOUT_UBER,
PIPELINE_LAYOUT_UTILITY, PIPELINE_LAYOUT_UTILITY,
PIPELINE_LAYOUT_COMPUTE, PIPELINE_LAYOUT_COMPUTE,
NUM_PIPELINE_LAYOUTS NUM_PIPELINE_LAYOUTS

View File

@ -123,8 +123,10 @@ bool ObjectCache::CreateDescriptorSetLayouts()
VK_SHADER_STAGE_FRAGMENT_BIT}, VK_SHADER_STAGE_FRAGMENT_BIT},
}}; }};
static const std::array<VkDescriptorSetLayoutBinding, 1> standard_ssbo_bindings{{ // The dynamic veretex loader's vertex buffer must be last here, for similar reasons
static const std::array<VkDescriptorSetLayoutBinding, 2> standard_ssbo_bindings{{
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT},
}}; }};
static const std::array<VkDescriptorSetLayoutBinding, 1> utility_ubo_bindings{{ static const std::array<VkDescriptorSetLayoutBinding, 1> utility_ubo_bindings{{
@ -173,6 +175,10 @@ bool ObjectCache::CreateDescriptorSetLayouts()
if (!g_ActiveConfig.backend_info.bSupportsGeometryShaders) if (!g_ActiveConfig.backend_info.bSupportsGeometryShaders)
create_infos[DESCRIPTOR_SET_LAYOUT_STANDARD_UNIFORM_BUFFERS].bindingCount--; create_infos[DESCRIPTOR_SET_LAYOUT_STANDARD_UNIFORM_BUFFERS].bindingCount--;
// Remove the dynamic vertex loader's buffer if it'll never be needed
if (!g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader)
create_infos[DESCRIPTOR_SET_LAYOUT_STANDARD_SHADER_STORAGE_BUFFERS].bindingCount--;
for (size_t i = 0; i < create_infos.size(); i++) for (size_t i = 0; i < create_infos.size(); i++)
{ {
VkResult res = vkCreateDescriptorSetLayout(g_vulkan_context->GetDevice(), &create_infos[i], VkResult res = vkCreateDescriptorSetLayout(g_vulkan_context->GetDevice(), &create_infos[i],
@ -206,6 +212,11 @@ bool ObjectCache::CreatePipelineLayouts()
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_STANDARD_SAMPLERS], m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_STANDARD_SAMPLERS],
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_STANDARD_SHADER_STORAGE_BUFFERS], m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_STANDARD_SHADER_STORAGE_BUFFERS],
}; };
const std::array<VkDescriptorSetLayout, 3> uber_sets{
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_STANDARD_UNIFORM_BUFFERS],
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_STANDARD_SAMPLERS],
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_STANDARD_SHADER_STORAGE_BUFFERS],
};
const std::array<VkDescriptorSetLayout, 2> utility_sets{ const std::array<VkDescriptorSetLayout, 2> utility_sets{
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_UTILITY_UNIFORM_BUFFER], m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_UTILITY_UNIFORM_BUFFER],
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_UTILITY_SAMPLERS], m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_UTILITY_SAMPLERS],
@ -220,6 +231,10 @@ bool ObjectCache::CreatePipelineLayouts()
{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0,
static_cast<u32>(standard_sets.size()), standard_sets.data(), 0, nullptr}, static_cast<u32>(standard_sets.size()), standard_sets.data(), 0, nullptr},
// Uber
{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0,
static_cast<u32>(uber_sets.size()), uber_sets.data(), 0, nullptr},
// Utility // Utility
{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0,
static_cast<u32>(utility_sets.size()), utility_sets.data(), 0, nullptr}, static_cast<u32>(utility_sets.size()), utility_sets.data(), 0, nullptr},
@ -232,6 +247,10 @@ bool ObjectCache::CreatePipelineLayouts()
// If bounding box is unsupported, don't bother with the SSBO descriptor set. // If bounding box is unsupported, don't bother with the SSBO descriptor set.
if (!g_ActiveConfig.backend_info.bSupportsBBox) if (!g_ActiveConfig.backend_info.bSupportsBBox)
pipeline_layout_info[PIPELINE_LAYOUT_STANDARD].setLayoutCount--; pipeline_layout_info[PIPELINE_LAYOUT_STANDARD].setLayoutCount--;
// If neither SSBO-using feature is supported, skip in ubershaders too
if (!g_ActiveConfig.backend_info.bSupportsBBox &&
!g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader)
pipeline_layout_info[PIPELINE_LAYOUT_UBER].setLayoutCount--;
for (size_t i = 0; i < pipeline_layout_info.size(); i++) for (size_t i = 0; i < pipeline_layout_info.size(); i++)
{ {

View File

@ -77,15 +77,24 @@ bool StateTracker::Initialize()
return true; return true;
} }
void StateTracker::SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset) void StateTracker::SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset, u32 size)
{
if (m_vertex_buffer != buffer || m_vertex_buffer_offset != offset)
{ {
if (m_vertex_buffer == buffer && m_vertex_buffer_offset == offset)
return;
m_vertex_buffer = buffer; m_vertex_buffer = buffer;
m_vertex_buffer_offset = offset; m_vertex_buffer_offset = offset;
m_dirty_flags |= DIRTY_FLAG_VERTEX_BUFFER; m_dirty_flags |= DIRTY_FLAG_VERTEX_BUFFER;
} }
if (m_bindings.gx_uber_vertex_ssbo.buffer != buffer ||
m_bindings.gx_uber_vertex_ssbo.offset != offset ||
m_bindings.gx_uber_vertex_ssbo.range != size)
{
m_bindings.gx_uber_vertex_ssbo.buffer = buffer;
m_bindings.gx_uber_vertex_ssbo.offset = offset;
m_bindings.gx_uber_vertex_ssbo.range = size;
m_dirty_flags |= DIRTY_FLAG_GX_SSBO;
}
}
void StateTracker::SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type) void StateTracker::SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type)
{ {
@ -366,8 +375,13 @@ bool StateTracker::Bind()
// Re-bind parts of the pipeline // Re-bind parts of the pipeline
const VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer(); const VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
if (m_dirty_flags & DIRTY_FLAG_VERTEX_BUFFER) const bool needs_vertex_buffer = !g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader ||
m_pipeline->GetUsage() != AbstractPipelineUsage::GXUber;
if (needs_vertex_buffer && (m_dirty_flags & DIRTY_FLAG_VERTEX_BUFFER))
{
vkCmdBindVertexBuffers(command_buffer, 0, 1, &m_vertex_buffer, &m_vertex_buffer_offset); vkCmdBindVertexBuffers(command_buffer, 0, 1, &m_vertex_buffer, &m_vertex_buffer_offset);
m_dirty_flags &= ~DIRTY_FLAG_VERTEX_BUFFER;
}
if (m_dirty_flags & DIRTY_FLAG_INDEX_BUFFER) if (m_dirty_flags & DIRTY_FLAG_INDEX_BUFFER)
vkCmdBindIndexBuffer(command_buffer, m_index_buffer, m_index_buffer_offset, m_index_type); vkCmdBindIndexBuffer(command_buffer, m_index_buffer, m_index_buffer_offset, m_index_type);
@ -381,8 +395,8 @@ bool StateTracker::Bind()
if (m_dirty_flags & DIRTY_FLAG_SCISSOR) if (m_dirty_flags & DIRTY_FLAG_SCISSOR)
vkCmdSetScissor(command_buffer, 0, 1, &m_scissor); vkCmdSetScissor(command_buffer, 0, 1, &m_scissor);
m_dirty_flags &= ~(DIRTY_FLAG_VERTEX_BUFFER | DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_PIPELINE | m_dirty_flags &=
DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR); ~(DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_PIPELINE | DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR);
return true; return true;
} }
@ -452,7 +466,7 @@ void StateTracker::EndClearRenderPass()
bool StateTracker::UpdateDescriptorSet() bool StateTracker::UpdateDescriptorSet()
{ {
if (m_pipeline->GetUsage() == AbstractPipelineUsage::GX) if (m_pipeline->GetUsage() != AbstractPipelineUsage::Utility)
return UpdateGXDescriptorSet(); return UpdateGXDescriptorSet();
else else
return UpdateUtilityDescriptorSet(); return UpdateUtilityDescriptorSet();
@ -462,7 +476,7 @@ bool StateTracker::UpdateGXDescriptorSet()
{ {
const size_t MAX_DESCRIPTOR_WRITES = NUM_UBO_DESCRIPTOR_SET_BINDINGS + // UBO const size_t MAX_DESCRIPTOR_WRITES = NUM_UBO_DESCRIPTOR_SET_BINDINGS + // UBO
1 + // Samplers 1 + // Samplers
1; // SSBO 2; // SSBO
std::array<VkWriteDescriptorSet, MAX_DESCRIPTOR_WRITES> writes; std::array<VkWriteDescriptorSet, MAX_DESCRIPTOR_WRITES> writes;
u32 num_writes = 0; u32 num_writes = 0;
@ -516,7 +530,12 @@ bool StateTracker::UpdateGXDescriptorSet()
m_dirty_flags = (m_dirty_flags & ~DIRTY_FLAG_GX_SAMPLERS) | DIRTY_FLAG_DESCRIPTOR_SETS; m_dirty_flags = (m_dirty_flags & ~DIRTY_FLAG_GX_SAMPLERS) | DIRTY_FLAG_DESCRIPTOR_SETS;
} }
if (g_ActiveConfig.backend_info.bSupportsBBox && const bool needs_bbox_ssbo = g_ActiveConfig.backend_info.bSupportsBBox;
const bool needs_vertex_ssbo = g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader &&
m_pipeline->GetUsage() == AbstractPipelineUsage::GXUber;
const bool needs_ssbo = needs_bbox_ssbo || needs_vertex_ssbo;
if (needs_ssbo &&
(m_dirty_flags & DIRTY_FLAG_GX_SSBO || m_gx_descriptor_sets[2] == VK_NULL_HANDLE)) (m_dirty_flags & DIRTY_FLAG_GX_SSBO || m_gx_descriptor_sets[2] == VK_NULL_HANDLE))
{ {
m_gx_descriptor_sets[2] = m_gx_descriptor_sets[2] =
@ -528,6 +547,21 @@ bool StateTracker::UpdateGXDescriptorSet()
writes[num_writes++] = { writes[num_writes++] = {
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, m_gx_descriptor_sets[2], 0, 0, 1, VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, m_gx_descriptor_sets[2], 0, 0, 1,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nullptr, &m_bindings.ssbo, nullptr}; VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nullptr, &m_bindings.ssbo, nullptr};
if (g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader)
{
writes[num_writes++] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
nullptr,
m_gx_descriptor_sets[2],
1,
0,
1,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
nullptr,
&m_bindings.gx_uber_vertex_ssbo,
nullptr};
}
m_dirty_flags = (m_dirty_flags & ~DIRTY_FLAG_GX_SSBO) | DIRTY_FLAG_DESCRIPTOR_SETS; m_dirty_flags = (m_dirty_flags & ~DIRTY_FLAG_GX_SSBO) | DIRTY_FLAG_DESCRIPTOR_SETS;
} }
@ -538,9 +572,7 @@ bool StateTracker::UpdateGXDescriptorSet()
{ {
vkCmdBindDescriptorSets(g_command_buffer_mgr->GetCurrentCommandBuffer(), vkCmdBindDescriptorSets(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline->GetVkPipelineLayout(), 0, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline->GetVkPipelineLayout(), 0,
g_ActiveConfig.backend_info.bSupportsBBox ? needs_ssbo ? NUM_GX_DESCRIPTOR_SETS : (NUM_GX_DESCRIPTOR_SETS - 1),
NUM_GX_DESCRIPTOR_SETS :
(NUM_GX_DESCRIPTOR_SETS - 1),
m_gx_descriptor_sets.data(), m_gx_descriptor_sets.data(),
g_ActiveConfig.backend_info.bSupportsGeometryShaders ? g_ActiveConfig.backend_info.bSupportsGeometryShaders ?
NUM_UBO_DESCRIPTOR_SET_BINDINGS : NUM_UBO_DESCRIPTOR_SET_BINDINGS :

View File

@ -32,7 +32,7 @@ public:
VKFramebuffer* GetFramebuffer() const { return m_framebuffer; } VKFramebuffer* GetFramebuffer() const { return m_framebuffer; }
const VKPipeline* GetPipeline() const { return m_pipeline; } const VKPipeline* GetPipeline() const { return m_pipeline; }
void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset); void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset, u32 size);
void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type); void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type);
void SetFramebuffer(VKFramebuffer* framebuffer); void SetFramebuffer(VKFramebuffer* framebuffer);
void SetPipeline(const VKPipeline* pipeline); void SetPipeline(const VKPipeline* pipeline);
@ -145,6 +145,7 @@ private:
std::array<VkDescriptorImageInfo, NUM_PIXEL_SHADER_SAMPLERS> samplers; std::array<VkDescriptorImageInfo, NUM_PIXEL_SHADER_SAMPLERS> samplers;
std::array<VkBufferView, NUM_COMPUTE_TEXEL_BUFFERS> texel_buffers; std::array<VkBufferView, NUM_COMPUTE_TEXEL_BUFFERS> texel_buffers;
VkDescriptorBufferInfo ssbo; VkDescriptorBufferInfo ssbo;
VkDescriptorBufferInfo gx_uber_vertex_ssbo;
VkDescriptorImageInfo image_texture; VkDescriptorImageInfo image_texture;
} m_bindings = {}; } m_bindings = {};
std::array<VkDescriptorSet, NUM_GX_DESCRIPTOR_SETS> m_gx_descriptor_sets = {}; std::array<VkDescriptorSet, NUM_GX_DESCRIPTOR_SETS> m_gx_descriptor_sets = {};

View File

@ -251,6 +251,9 @@ std::unique_ptr<VKPipeline> VKPipeline::Create(const AbstractPipelineConfig& con
case AbstractPipelineUsage::GX: case AbstractPipelineUsage::GX:
pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD); pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD);
break; break;
case AbstractPipelineUsage::GXUber:
pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_UBER);
break;
case AbstractPipelineUsage::Utility: case AbstractPipelineUsage::Utility:
pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_UTILITY); pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_UTILITY);
break; break;

View File

@ -62,7 +62,8 @@ bool VertexManager::Initialize()
return false; return false;
m_vertex_stream_buffer = m_vertex_stream_buffer =
StreamBuffer::Create(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VERTEX_STREAM_BUFFER_SIZE); StreamBuffer::Create(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
VERTEX_STREAM_BUFFER_SIZE);
m_index_stream_buffer = m_index_stream_buffer =
StreamBuffer::Create(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, INDEX_STREAM_BUFFER_SIZE); StreamBuffer::Create(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, INDEX_STREAM_BUFFER_SIZE);
m_uniform_stream_buffer = m_uniform_stream_buffer =
@ -186,7 +187,8 @@ void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_in
ADDSTAT(g_stats.this_frame.bytes_vertex_streamed, static_cast<int>(vertex_data_size)); ADDSTAT(g_stats.this_frame.bytes_vertex_streamed, static_cast<int>(vertex_data_size));
ADDSTAT(g_stats.this_frame.bytes_index_streamed, static_cast<int>(index_data_size)); ADDSTAT(g_stats.this_frame.bytes_index_streamed, static_cast<int>(index_data_size));
StateTracker::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer->GetBuffer(), 0); StateTracker::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer->GetBuffer(), 0,
VERTEX_STREAM_BUFFER_SIZE);
StateTracker::GetInstance()->SetIndexBuffer(m_index_stream_buffer->GetBuffer(), 0, StateTracker::GetInstance()->SetIndexBuffer(m_index_stream_buffer->GetBuffer(), 0,
VK_INDEX_TYPE_UINT16); VK_INDEX_TYPE_UINT16);
} }

View File

@ -295,6 +295,7 @@ void VulkanContext::PopulateBackendInfo(VideoConfig* config)
config->backend_info.bSupportsLodBiasInSampler = false; // Dependent on OS. config->backend_info.bSupportsLodBiasInSampler = false; // Dependent on OS.
config->backend_info.bSupportsSettingObjectNames = false; // Dependent on features. config->backend_info.bSupportsSettingObjectNames = false; // Dependent on features.
config->backend_info.bSupportsPartialMultisampleResolve = true; // Assumed support. config->backend_info.bSupportsPartialMultisampleResolve = true; // Assumed support.
config->backend_info.bSupportsDynamicVertexLoader = true; // Assumed support.
} }
void VulkanContext::PopulateBackendInfoAdapters(VideoConfig* config, const GPUList& gpu_list) void VulkanContext::PopulateBackendInfoAdapters(VideoConfig* config, const GPUList& gpu_list)

View File

@ -20,6 +20,8 @@ class NativeVertexFormat;
// - Per-stage UBO (VS/GS/PS, VS constants accessible from PS) // - Per-stage UBO (VS/GS/PS, VS constants accessible from PS)
// - 8 combined image samplers (accessible from PS) // - 8 combined image samplers (accessible from PS)
// - 1 SSBO, accessible from PS if bounding box is enabled // - 1 SSBO, accessible from PS if bounding box is enabled
// - GX Uber
// - Same as GX, plus one VS SSBO for vertices if dynamic vertex loading is enabled
// - Utility // - Utility
// - Single UBO, accessible from all stages [set=0, binding=1] // - Single UBO, accessible from all stages [set=0, binding=1]
// - 8 combined image samplers (accessible from PS) [set=1, binding=0-7] // - 8 combined image samplers (accessible from PS) [set=1, binding=0-7]
@ -32,6 +34,7 @@ class NativeVertexFormat;
enum class AbstractPipelineUsage enum class AbstractPipelineUsage
{ {
GX, GX,
GXUber,
Utility Utility
}; };

View File

@ -93,6 +93,13 @@ struct VertexShaderConstants
float4 cached_tangent; float4 cached_tangent;
float4 cached_binormal; float4 cached_binormal;
// For UberShader vertex loader
u32 vertex_stride;
std::array<u32, 3> vertex_offset_normals;
u32 vertex_offset_position;
u32 vertex_offset_posmtx;
std::array<u32, 2> vertex_offset_colors;
std::array<u32, 8> vertex_offset_texcoords;
}; };
struct GeometryShaderConstants struct GeometryShaderConstants

View File

@ -58,9 +58,9 @@ struct PortableVertexDeclaration
int stride; int stride;
AttributeFormat position; AttributeFormat position;
AttributeFormat normals[3]; std::array<AttributeFormat, 3> normals;
AttributeFormat colors[2]; std::array<AttributeFormat, 2> colors;
AttributeFormat texcoords[8]; std::array<AttributeFormat, 8> texcoords;
AttributeFormat posmtx; AttributeFormat posmtx;
inline bool operator<(const PortableVertexDeclaration& b) const inline bool operator<(const PortableVertexDeclaration& b) const

View File

@ -122,7 +122,7 @@ public:
// HACK // HACK
DataReader src{const_cast<u8*>(vertex_data), const_cast<u8*>(vertex_data) + size}; DataReader src{const_cast<u8*>(vertex_data), const_cast<u8*>(vertex_data) + size};
const u32 bytes = const u32 bytes =
VertexLoaderManager::RunVertices(vat, primitive, num_vertices, src, is_preprocess); VertexLoaderManager::RunVertices<is_preprocess>(vat, primitive, num_vertices, src);
ASSERT(bytes == size); ASSERT(bytes == size);
@ -228,6 +228,12 @@ public:
return g_main_cp_state; return g_main_cp_state;
} }
OPCODE_CALLBACK(u32 GetVertexSize(u8 vat))
{
VertexLoaderBase* loader = VertexLoaderManager::RefreshLoader<is_preprocess>(vat);
return loader->m_vertex_size;
}
u32 m_cycles = 0; u32 m_cycles = 0;
bool m_in_display_list = false; bool m_in_display_list = false;
}; };

View File

@ -110,6 +110,8 @@ public:
// Get the current CP state. Needed for vertex decoding; will also be mutated for CP commands. // Get the current CP state. Needed for vertex decoding; will also be mutated for CP commands.
virtual CPState& GetCPState() = 0; virtual CPState& GetCPState() = 0;
virtual u32 GetVertexSize(u8 vat) = 0;
#endif #endif
}; };
@ -229,8 +231,7 @@ static DOLPHIN_FORCE_INLINE u32 RunCommand(const u8* data, u32 available, T& cal
(cmdbyte & OpcodeDecoder::GX_PRIMITIVE_MASK) >> OpcodeDecoder::GX_PRIMITIVE_SHIFT); (cmdbyte & OpcodeDecoder::GX_PRIMITIVE_MASK) >> OpcodeDecoder::GX_PRIMITIVE_SHIFT);
const u8 vat = cmdbyte & OpcodeDecoder::GX_VAT_MASK; const u8 vat = cmdbyte & OpcodeDecoder::GX_VAT_MASK;
const u32 vertex_size = VertexLoaderBase::GetVertexSize(callback.GetCPState().vtx_desc, const u32 vertex_size = callback.GetVertexSize(vat);
callback.GetCPState().vtx_attr[vat]);
const u16 num_vertices = Common::swap16(&data[1]); const u16 num_vertices = Common::swap16(&data[1]);
if (available < 3 + num_vertices * vertex_size) if (available < 3 + num_vertices * vertex_size)

View File

@ -588,10 +588,10 @@ AbstractPipelineConfig ShaderCache::GetGXPipelineConfig(
const NativeVertexFormat* vertex_format, const AbstractShader* vertex_shader, const NativeVertexFormat* vertex_format, const AbstractShader* vertex_shader,
const AbstractShader* geometry_shader, const AbstractShader* pixel_shader, const AbstractShader* geometry_shader, const AbstractShader* pixel_shader,
const RasterizationState& rasterization_state, const DepthState& depth_state, const RasterizationState& rasterization_state, const DepthState& depth_state,
const BlendingState& blending_state) const BlendingState& blending_state, AbstractPipelineUsage usage)
{ {
AbstractPipelineConfig config = {}; AbstractPipelineConfig config = {};
config.usage = AbstractPipelineUsage::GX; config.usage = usage;
config.vertex_format = vertex_format; config.vertex_format = vertex_format;
config.vertex_shader = vertex_shader; config.vertex_shader = vertex_shader;
config.geometry_shader = geometry_shader; config.geometry_shader = geometry_shader;
@ -735,7 +735,7 @@ ShaderCache::GetGXPipelineConfig(const GXPipelineUid& config_in)
} }
return GetGXPipelineConfig(config.vertex_format, vs, gs, ps, config.rasterization_state, return GetGXPipelineConfig(config.vertex_format, vs, gs, ps, config.rasterization_state,
config.depth_state, config.blending_state); config.depth_state, config.blending_state, AbstractPipelineUsage::GX);
} }
/// Edits the UID based on driver bugs and other special configurations /// Edits the UID based on driver bugs and other special configurations
@ -743,6 +743,8 @@ static GXUberPipelineUid ApplyDriverBugs(const GXUberPipelineUid& in)
{ {
GXUberPipelineUid out; GXUberPipelineUid out;
memcpy(&out, &in, sizeof(out)); // Copy padding memcpy(&out, &in, sizeof(out)); // Copy padding
if (g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader)
out.vertex_format = nullptr;
if (g_ActiveConfig.backend_info.bSupportsFramebufferFetch) if (g_ActiveConfig.backend_info.bSupportsFramebufferFetch)
{ {
// Always blend in shader // Always blend in shader
@ -798,7 +800,8 @@ ShaderCache::GetGXPipelineConfig(const GXUberPipelineUid& config_in)
} }
return GetGXPipelineConfig(config.vertex_format, vs, gs, ps, config.rasterization_state, return GetGXPipelineConfig(config.vertex_format, vs, gs, ps, config.rasterization_state,
config.depth_state, config.blending_state); config.depth_state, config.blending_state,
AbstractPipelineUsage::GXUber);
} }
const AbstractPipeline* ShaderCache::InsertGXPipeline(const GXPipelineUid& config, const AbstractPipeline* ShaderCache::InsertGXPipeline(const GXPipelineUid& config,
@ -1233,9 +1236,9 @@ void ShaderCache::QueueUberShaderPipelines()
dummy_vertex_decl.stride = sizeof(float) * 4; dummy_vertex_decl.stride = sizeof(float) * 4;
NativeVertexFormat* dummy_vertex_format = NativeVertexFormat* dummy_vertex_format =
VertexLoaderManager::GetUberVertexFormat(dummy_vertex_decl); VertexLoaderManager::GetUberVertexFormat(dummy_vertex_decl);
auto QueueDummyPipeline = [&](const UberShader::VertexShaderUid& vs_uid, auto QueueDummyPipeline =
const GeometryShaderUid& gs_uid, [&](const UberShader::VertexShaderUid& vs_uid, const GeometryShaderUid& gs_uid,
const UberShader::PixelShaderUid& ps_uid) { const UberShader::PixelShaderUid& ps_uid, const BlendingState& blend) {
GXUberPipelineUid config; GXUberPipelineUid config;
config.vertex_format = dummy_vertex_format; config.vertex_format = dummy_vertex_format;
config.vs_uid = vs_uid; config.vs_uid = vs_uid;
@ -1244,7 +1247,7 @@ void ShaderCache::QueueUberShaderPipelines()
config.rasterization_state = RenderState::GetCullBackFaceRasterizationState( config.rasterization_state = RenderState::GetCullBackFaceRasterizationState(
static_cast<PrimitiveType>(gs_uid.GetUidData()->primitive_type)); static_cast<PrimitiveType>(gs_uid.GetUidData()->primitive_type));
config.depth_state = RenderState::GetNoDepthTestingDepthState(); config.depth_state = RenderState::GetNoDepthTestingDepthState();
config.blending_state = RenderState::GetNoBlendingBlendState(); config.blending_state = blend;
if (ps_uid.GetUidData()->uint_output) if (ps_uid.GetUidData()->uint_output)
{ {
// uint_output is only ever enabled when logic ops are enabled. // uint_output is only ever enabled when logic ops are enabled.
@ -1275,7 +1278,45 @@ void ShaderCache::QueueUberShaderPipelines()
{ {
return; return;
} }
QueueDummyPipeline(vuid, guid, cleared_puid); BlendingState blend = RenderState::GetNoBlendingBlendState();
QueueDummyPipeline(vuid, guid, cleared_puid, blend);
if (g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader)
{
// Not all GPUs need all the pipeline state compiled into shaders, so they tend to key
// compiled shaders based on some subset of the pipeline state.
// Some test results:
// (GPUs tested: AMD Radeon Pro 5600M, Nvidia GT 750M, Intel UHD 630,
// Intel Iris Pro 5200, Apple M1)
// MacOS Metal:
// - AMD, Nvidia, Intel GPUs: Shaders are keyed on vertex layout and whether or not
// dual source blend is enabled. That's it.
// - Apple GPUs: Shaders are keyed on vertex layout and all blending settings. We use
// framebuffer fetch here, so the only blending settings used by ubershaders are the
// alphaupdate and colorupdate ones. Also keyed on primitive type, but Metal supports
// setting it to "unknown" and we do for ubershaders (but MoltenVK won't).
// Windows Vulkan:
// - AMD, Nvidia: Definitely keyed on dual source blend, but the others seem more random
// Changing a setting on one shader will require a recompile, but changing the same
// setting on another won't. Compiling a copy with alphaupdate off, colorupdate off,
// and one with DSB on seems to get pretty good coverage though.
// Windows D3D12:
// - AMD: Keyed on dual source blend and vertex layout
// - Nvidia Kepler: No recompiles for changes to vertex layout or blend
blend.alphaupdate = false;
QueueDummyPipeline(vuid, guid, cleared_puid, blend);
blend.alphaupdate = true;
blend.colorupdate = false;
QueueDummyPipeline(vuid, guid, cleared_puid, blend);
blend.colorupdate = true;
if (!cleared_puid.GetUidData()->no_dual_src && !cleared_puid.GetUidData()->uint_output)
{
blend.blendenable = true;
blend.usedualsrc = true;
blend.srcfactor = SrcBlendFactor::SrcAlpha;
blend.dstfactor = DstBlendFactor::InvSrcAlpha;
QueueDummyPipeline(vuid, guid, cleared_puid, blend);
}
}
}); });
}); });
}); });

View File

@ -151,7 +151,7 @@ private:
GetGXPipelineConfig(const NativeVertexFormat* vertex_format, const AbstractShader* vertex_shader, GetGXPipelineConfig(const NativeVertexFormat* vertex_format, const AbstractShader* vertex_shader,
const AbstractShader* geometry_shader, const AbstractShader* pixel_shader, const AbstractShader* geometry_shader, const AbstractShader* pixel_shader,
const RasterizationState& rasterization_state, const DepthState& depth_state, const RasterizationState& rasterization_state, const DepthState& depth_state,
const BlendingState& blending_state); const BlendingState& blending_state, AbstractPipelineUsage usage);
std::optional<AbstractPipelineConfig> GetGXPipelineConfig(const GXPipelineUid& uid); std::optional<AbstractPipelineConfig> GetGXPipelineConfig(const GXPipelineUid& uid);
std::optional<AbstractPipelineConfig> GetGXPipelineConfig(const GXUberPipelineUid& uid); std::optional<AbstractPipelineConfig> GetGXPipelineConfig(const GXUberPipelineUid& uid);
const AbstractPipeline* InsertGXPipeline(const GXPipelineUid& config, const AbstractPipeline* InsertGXPipeline(const GXPipelineUid& config,

View File

@ -43,6 +43,7 @@ ShaderHostConfig ShaderHostConfig::GetCurrent()
bits.manual_texture_sampling_custom_texture_sizes = bits.manual_texture_sampling_custom_texture_sizes =
g_ActiveConfig.ManualTextureSamplingWithHiResTextures(); g_ActiveConfig.ManualTextureSamplingWithHiResTextures();
bits.backend_sampler_lod_bias = g_ActiveConfig.backend_info.bSupportsLodBiasInSampler; bits.backend_sampler_lod_bias = g_ActiveConfig.backend_info.bSupportsLodBiasInSampler;
bits.backend_dynamic_vertex_loader = g_ActiveConfig.backend_info.bSupportsDynamicVertexLoader;
return bits; return bits;
} }

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