Merge pull request #68 from DrBeef/master

This commit is contained in:
Amanda Watson 2024-03-14 19:17:39 -05:00 committed by GitHub
commit ef1946abf1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 338 additions and 81 deletions

View file

@ -49,9 +49,8 @@ enum class IntSetting(
if (hMDType == VRUtils.HMDType.QUEST3.value) 1 else 2),
VR_CPU_LEVEL("vr_cpu_level", Settings.SECTION_VR, 3),
VR_IMMERSIVE_MODE("vr_immersive_mode", Settings.SECTION_VR, 0),
VR_IMMERSIVE_POSITIONAL_FACTOR("vr_immersive_positional_factor", Settings.SECTION_VR, 0),
VR_IMMERSIVE_POSITIONAL_GAME_SCALER("vr_immersive_positional_game_scaler", Settings.SECTION_VR, 0),
VR_SI_MODE_REGISTER_OFFSET("vr_si_mode_register_offset", Settings.SECTION_VR, 0);
VR_SI_MODE_REGISTER_OFFSET("vr_si_mode_register_offset", Settings.SECTION_VR, -1);
override var int: Int = defaultValue

View file

@ -15,7 +15,8 @@ enum class StringSetting(
CAMERA_OUTER_LEFT_NAME("camera_outer_left_name", Settings.SECTION_CAMERA, "ndk"),
CAMERA_OUTER_LEFT_CONFIG("camera_outer_left_config", Settings.SECTION_CAMERA, "_back"),
CAMERA_OUTER_RIGHT_NAME("camera_outer_right_name", Settings.SECTION_CAMERA, "ndk"),
CAMERA_OUTER_RIGHT_CONFIG("camera_outer_right_config", Settings.SECTION_CAMERA, "_back");
CAMERA_OUTER_RIGHT_CONFIG("camera_outer_right_config", Settings.SECTION_CAMERA, "_back"),
VR_IMMMERSIVE_EYE_INDICATOR("vr_immersive_eye_indicator", Settings.SECTION_VR, "");
override var string: String = defaultValue

View file

@ -1125,18 +1125,6 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
IntSetting.VR_IMMERSIVE_MODE.defaultValue
)
)
add(
SliderSetting(
IntSetting.VR_IMMERSIVE_POSITIONAL_FACTOR,
R.string.vr_immersive_pos_factor_title,
R.string.vr_immersive_pos_factor_description,
0,
40,
"x",
IntSetting.VR_IMMERSIVE_POSITIONAL_FACTOR.key,
IntSetting.VR_IMMERSIVE_POSITIONAL_FACTOR.defaultValue.toFloat()
)
)
add(
SingleChoiceSetting(
IntSetting.VR_IMMERSIVE_POSITIONAL_GAME_SCALER,
@ -1153,13 +1141,21 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
IntSetting.VR_SI_MODE_REGISTER_OFFSET,
R.string.vr_si_mode_register_offset_title,
R.string.vr_si_mode_register_offset_description,
0,
-1,
92,
"register",
IntSetting.VR_SI_MODE_REGISTER_OFFSET.key,
IntSetting.VR_SI_MODE_REGISTER_OFFSET.defaultValue.toFloat()
)
)
add(
StringInputSetting(
StringSetting.VR_IMMMERSIVE_EYE_INDICATOR,
R.string.vr_immersive_eye_indicator_title,
R.string.vr_immersive_eye_indicator_description,
""
)
)
}
}
}

View file

@ -290,15 +290,22 @@ void Config::ReadValues() {
"VR", "vr_immersive_mode", 0);
Settings::values.vr_immersive_mode = VRSettings::values.vr_immersive_mode;
VRSettings::values.vr_si_mode_register_offset = sdl2_config->GetInteger(
"VR", "vr_si_mode_register_offset", 0);
"VR", "vr_si_mode_register_offset", -1);
Settings::values.vr_si_mode_register_offset = VRSettings::values.vr_si_mode_register_offset;
VRSettings::values.vr_immersive_positional_factor = sdl2_config->GetInteger(
"VR", "vr_immersive_positional_factor", 0);
Settings::values.vr_immersive_positional_factor = VRSettings::values.vr_immersive_positional_factor;
// For immersive modes we use the factor_3d value as a camera movement factor
// which means it affects stereo separation and positional movement
// We have to divide this by 10 or the numbers are too big
VRSettings::values.vr_factor_3d = sdl2_config->GetInteger(
"Renderer", "factor_3d", 100) / 10;
VRSettings::values.vr_immersive_positional_game_scaler = sdl2_config->GetInteger(
"VR", "vr_immersive_positional_game_scaler", 0);
Settings::values.vr_immersive_positional_game_scaler = VRSettings::values.vr_immersive_positional_game_scaler;
VRSettings::values.vr_immersive_eye_indicator = sdl2_config->GetString(
"VR", "vr_immersive_eye_indicator", "");
Settings::values.vr_immersive_eye_indicator = VRSettings::values.vr_immersive_eye_indicator;
if (Settings::values.vr_immersive_mode.GetValue() > 0) {
LOG_INFO(Config, "VR immersive mode enabled");

View file

@ -442,13 +442,20 @@ XrPosef GameSurfaceLayer::GetTopPanelFromHeadPose(uint32_t eye, const XrPosef& h
XrVector3f forward, up, right;
XrMath::Quatf::ToVectors(headPose.orientation, forward, right, up);
panelPosition.z += kSuperImmersiveRadius * (forward.x * 0.4f);
panelPosition.y -= kSuperImmersiveRadius * (forward.z * 0.4f);
panelPosition.x += kSuperImmersiveRadius * (forward.y * 0.4f);
panelPosition.z += kSuperImmersiveRadius * (forward.x * 0.58f);
panelPosition.y -= kSuperImmersiveRadius * (forward.z * 0.58f);
panelPosition.x += kSuperImmersiveRadius * (forward.y * 0.58f);
panelPosition.z += up.x / 12.f;
panelPosition.y -= up.z / 12.f;
panelPosition.x += up.y / 12.f;
panelPosition.z += up.x / 25.f;
panelPosition.y -= up.z / 25.f;
panelPosition.x += up.y / 25.f;
if (mImmersiveMode == 3)
{
panelPosition.z += right.x * (0.065f / 2.f) * (1 - 2.f * eye);
panelPosition.y -= right.z * (0.065f / 2.f) * (1 - 2.f * eye);
panelPosition.x += right.y * (0.065f / 2.f) * (1 - 2.f * eye);
}
return XrPosef{headPose.orientation, panelPosition};
}

View file

@ -75,7 +75,7 @@ std::chrono::time_point<std::chrono::steady_clock> gOnCreateStartTime;
std::unique_ptr<OpenXr> gOpenXr;
MessageQueue gMessageQueue;
const std::vector<float> immersiveScaleFactor = {1.0f, 3.0f, 1.8f};
const std::vector<float> immersiveScaleFactor = {1.0f, 3.0f, 1.4f};
void ForwardButtonStateChangeToCitra(JNIEnv* jni, jobject activityObject,
jmethodID forwardVRInputMethodID, const int androidButtonCode,
@ -433,12 +433,12 @@ private:
-MATH_FLOAT_PI / 8.0f) ||
// If in "super immersive" mode then put controller next to head in order to
// disable the mode temporarily
(VRSettings::values.vr_immersive_mode > 2 && length < 0.2)) {
(VRSettings::values.vr_immersive_mode >= 2 && length < 0.2)) {
XrVector4f identity[4] = {};
XrMath::Matrixf::Identity(identity);
immersiveModeFactor = 1.0f;
Core::System::GetInstance().GPU().Renderer().Rasterizer()->SetVRData(
1, immersiveModeFactor, -1, (float*)identity);
1, immersiveModeFactor, -1, 0.f, (float*)identity);
} else {
XrVector4f transform[4] = {};
XrMath::Quatf::ToRotationMatrix(gOpenXr->headLocation.pose.orientation,
@ -454,20 +454,16 @@ private:
invertedOrientation, gOpenXr->headLocation.pose.position);
const float gamePosScaler =
powf(10.f, VRSettings::values.vr_immersive_positional_game_scaler);
inv_transform[3].x = -position.x *
VRSettings::values.vr_immersive_positional_factor *
gamePosScaler;
inv_transform[3].y = -position.y *
VRSettings::values.vr_immersive_positional_factor *
gamePosScaler;
inv_transform[3].z = -position.z *
VRSettings::values.vr_immersive_positional_factor *
gamePosScaler;
powf(10.f, VRSettings::values.vr_immersive_positional_game_scaler) *
VRSettings::values.vr_factor_3d;
inv_transform[3].x = -position.x * gamePosScaler;
inv_transform[3].y = -position.y * gamePosScaler;
inv_transform[3].z = -position.z * gamePosScaler;
Core::System::GetInstance().GPU().Renderer().Rasterizer()->SetVRData(
VRSettings::values.vr_immersive_mode, immersiveModeFactor, uoffset,
(float*)inv_transform);
-gamePosScaler, (float*)inv_transform);
showLowerPanel = false;
}
}

View file

@ -45,8 +45,9 @@ struct Values {
int32_t vr_immersive_mode = 0;
bool extra_performance_mode_enabled = false;
int32_t vr_si_mode_register_offset = -1;
int32_t vr_immersive_positional_factor = 0;
int32_t vr_factor_3d = 100;
int32_t vr_immersive_positional_game_scaler = 0;
std::string vr_immersive_eye_indicator;
} extern values;
} // namespace VRSettings

View file

@ -453,9 +453,9 @@
<string-array name="vrImmersiveModeNames">
<item>Off</item>
<item>180 Degree Immersive (3DoF)</item>
<item>Super Immersive (6DoF) - Profile 1</item>
<item>Super Immersive (6DoF) - Profile 2</item>
<item>180 Degree Wrap-Around Immersive (3DoF)</item>
<item>"Super Immersive (6DoF) - Profile 1 (Ocarina of Time &#038; Majora's Mask)"</item>
<item>Super Immersive (6DoF) - Profile 2 (All other games)</item>
</string-array>
<integer-array name="vrImmersiveModeValues">

View file

@ -683,10 +683,10 @@
<string name="vr_notice_description2">Some games just won\'t run well. Be sure to check the CitraVR Game Compatibility List to see which games perform best.</string>
<string name="vr_input_binding_subtitle">\nHaving trouble? Press Select + Start to disable Gamepad Gaze Mode, then try again</string>
<string name="immersive_mode">Immersive Mode</string>
<string name="vr_si_mode_register_offset_title">Register Offset</string>
<string name="vr_si_mode_register_offset_description">Sets the register offset used for the view when using Super Immersive Mode Profile 2 - varies by game</string>
<string name="vr_immersive_pos_factor_title">Positional Movement Factor</string>
<string name="vr_immersive_pos_factor_description">Adjusts how much movement left/right/up/down affects the game camera (0 = disabled)</string>
<string name="vr_immersive_pos_game_scaler_title">Positional Movement Factor Multiplier</string>
<string name="vr_immersive_pos_game_scaler_description">Adjusts how much movement left/right/up/down affects the game camera, some games required larger values, so this multiplies the Positional Movement Factor</string>
<string name="vr_si_mode_register_offset_title">Register Offset [Optional]</string>
<string name="vr_si_mode_register_offset_description">[default: -1 = use auto-detect] CAUTION: Sets the register offset used for the view when using Super Immersive Mode Profile 2</string>
<string name="vr_immersive_eye_indicator_title">Eye Indicator Register [Optional]</string>
<string name="vr_immersive_eye_indicator_description">[Leave blank for auto-detect] CAUTION: Sets the register and index offset used for identifying which eye is being drawn e.g 87,2</string>
<string name="vr_immersive_pos_game_scaler_title">Depth Factor Multiplier</string>
<string name="vr_immersive_pos_game_scaler_description">Adjusts how much the depth slider affects the game camera (movement/separation), some games require smaller/larger values, so this multiplier adjusts how much movement the depth setting causes</string>
</resources>

View file

@ -557,9 +557,9 @@ struct Values {
// VR
Setting<u32> vr_immersive_mode{0, "vr_immersive_mode"};
Setting<u32> vr_si_mode_register_offset{-1, "vr_si_mode_register_offset"};
Setting<u32> vr_immersive_positional_factor{0, "vr_immersive_positional_factor"};
Setting<int32_t> vr_si_mode_register_offset{-1, "vr_si_mode_register_offset"};
Setting<u32> vr_immersive_positional_game_scaler{0, "vr_immersive_positional_game_scaler"};
Setting<std::string> vr_immersive_eye_indicator{"", "vr_immersive_eye_indicator"};
};
extern Values values;

View file

@ -85,7 +85,9 @@ Handler::Handler(Core::Timing& timing, u64 override_init_time) : timing(timing)
std::bind(&Handler::UpdateTimeCallback, this, _1, _2));
timing.ScheduleEvent(0, update_time_event, 0, 0);
float slidestate = Settings::values.factor_3d.GetValue() / 100.0f;
float slidestate = Settings::values.vr_immersive_mode.GetValue() < 3 ?
Settings::values.factor_3d.GetValue() / 100.0f :
0.01f;
shared_page.sliderstate_3d = static_cast<float_le>(slidestate);
// TODO(PabloMK7)

View file

@ -217,9 +217,10 @@ void Module::UpdatePadCallback(std::uintptr_t user_data, s64 cycles_late) {
// TODO(xperia64): How the 3D Slider is updated by the HID module needs to be RE'd
// and possibly moved to its own Core::Timing event.
mem->pad.sliderstate_3d = (Settings::values.factor_3d.GetValue() / 100.0f);
system.Kernel().GetSharedPageHandler().Set3DSlider(Settings::values.factor_3d.GetValue() /
100.0f);
mem->pad.sliderstate_3d = Settings::values.vr_immersive_mode.GetValue() < 3 ?
(Settings::values.factor_3d.GetValue() / 100.0f) :
0.01f;
system.Kernel().GetSharedPageHandler().Set3DSlider(mem->pad.sliderstate_3d);
// Reschedule recurrent event
system.CoreTiming().ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);

View file

@ -22,6 +22,8 @@ static Common::Vec3f LightColor(const Pica::LightingRegs::LightColor& color) {
return Common::Vec3u{color.r, color.g, color.b} / 255.0f;
}
constexpr float VR_IPD = 0.065f;
RasterizerAccelerated::HardwareVertex::HardwareVertex(const Pica::OutputVertex& v,
bool flip_quaternion) {
position[0] = v.pos.x.ToFloat32();
@ -859,7 +861,7 @@ void RasterizerAccelerated::SyncClipPlane() {
}
}
void RasterizerAccelerated::SetVRData(const int32_t &vrImmersiveMode, const float& immersiveModeFactor, int uoffset, const float view[16])
void RasterizerAccelerated::SetVRData(const int32_t &vrImmersiveMode, const float& immersiveModeFactor, int uoffset, const float& gamePosScaler, const float inv_view[16])
{
if (vs_uniform_block_data.data.vr_immersive_mode_factor != immersiveModeFactor)
{
@ -869,7 +871,8 @@ void RasterizerAccelerated::SetVRData(const int32_t &vrImmersiveMode, const floa
vr_uoffset = uoffset;
vr_immersive_mode = vrImmersiveMode;
std::memcpy(vr_view, view, sizeof(float) * 16);
vr_game_pos_scaler = gamePosScaler;
std::memcpy(vr_inv_view, inv_view, sizeof(float) * 16);
}
static void MatrixTranspose(float m[16], const float src[16]) {
@ -924,37 +927,275 @@ void RasterizerAccelerated::ApplyVRDataToPicaVSUniforms(Pica::Shader::Generator:
viewMatrixIndex = vr_uoffset;
break;
default:
viewMatrixIndex = -1;
break;
return;
}
const bool findLeftRightEyeIndicator = Settings::values.vr_immersive_eye_indicator.GetValue().empty();
/*
* The following section is a "heuristic" algorithm that guesses (pretty well actually!) both the number of the
* register for the view transformation matrix and also the left/right eye indicator register based on a bunch of
* characteristics I gathered by looking at the register values for a few games. If it gets it wrong, then it is
* still possible to supply your own values using the config options, but the default now should be using this
* "auto-detect" routine.
*/
if (viewMatrixIndex == -1 && mode >= 3)
{
struct regscore
{
regscore() {
neg = pos = 0;
score = bonus = 0.f;
}
int neg;
int pos;
std::set<float> values;
float score;
float bonus;
};
//static array to keep track of the way the data changes in each register location
static regscore regscores[96 * 4];
static regscore regscores2[96];
// use a counter to ignore the first number of
// times through here, as a lot of these will
// just be things like intro videos etc
static int counter = 0;
constexpr int start = 5000;
constexpr int stop = 250000;
constexpr float EPSILON = 0.00001f;
auto between = [=](float l, float v, float r) { return v <= r && v >= l; };
static int identityMatrix[16] = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
if (++counter > start)
{
//Stop collecting after a period of time as we should have a good hit by now
//we don't want to waste precious CPU
if (counter < stop)
{
for (int r = 0; r < 96; ++r)
{
/*
* This block does the scoring for the possible view matrix register
*/
if (r <= 91)
{
//Check that all the values are between -1 and 1
//don't include values that might be positional and values in the final 4x4 row
bool valid = true;
for (int i = 0; i < 3 && valid; ++i) {
for (int j = 0; j < 3 && valid; ++j) {
valid = between(-1.f, f[r + i][j], 1.f);
}
}
//only proceed to score if register could legitimately be a view matrix
if (valid) {
regscores2[r].score += 1;
//bonus point if register appear to be an identity matrix
bool isIdentity = true;
for (int i = 0; i < 3 && isIdentity; ++i) {
for (int j = 0; j < 3 && isIdentity; ++j) {
isIdentity = (int)std::roundf(f[r + i][j]) == identityMatrix[i * 4 + j];
}
}
if (isIdentity) {
regscores2[r].score += 1;
}
//another bonus point if the absolute position values in the matrix are bigger than 1
if (fabsf(f[r].w) > 1.f && fabsf(f[r+1].w) > 1.f && fabsf(f[r+2].w) > 1.f) {
regscores2[r].score += 1;
}
//another bonus point if the last position contains 0, 1, 2, 3 or 0, 0, 0, 1
if ((f[r + 3].x == 0.f && f[r + 3].y == 0.f && f[r + 3].z == 0.f &&
f[r + 3].w == 1.f) ||
(f[r + 3].x == 0.f && f[r + 3].y == 1.f && f[r + 3].z == 2.f &&
f[r + 3].w == 3.f))
{
regscores2[r].score += 1;
}
//Certain values in the register should never be exactly 0
if (f[r].x == 0.f || f[r + 1].y == 0.f || f[r + 2].z == 0.f) {
regscores2[r].score -= 2;
}
// final bonus point if register is a commonly occuring one
if (r == 90 || r == 4 || r == 8) {
regscores2[r].score += 1;
}
} else {
//Not possibly a view matrix, subtract a point as punishment, but don't go below 0
if (regscores2[r].score > 0)
regscores2[r].score -= 1;
}
}
/*
* This block does the scoring for the possible left/right eye indicator register, typical characteristics
* of that register are:
* * Its value has a more or less equal number of negative and positive values over time
* * It is a small number greater than almost 0 and less than 0.1
* * It only has a small amount of variance in its values (rounded to 5dp)
* * Frequently selected registers get a small bonus, as they then become more likely to be the correct ones
*/
for (int i = 0; i <= 3; ++i)
{
float value = fabsf(f[r][i]);
auto &regscore = regscores[r * 4 + i];
if (value < 0.1f && value > EPSILON)
{
if (f[r][i] < 0.f)
{
regscore.neg++;
}
else
{
regscore.pos++;
}
//Store the value rounded, we are looking for the register with the least variance
regscore.values.insert(
floorf(value * 10000) / 10000);
}
// recalc score
if (regscore.neg > 0 &&
regscore.pos > 0 &&
regscore.values.size() > 0)
{
int max = std::max<int>(regscore.neg,
regscore.pos);
int min = std::min<int>(regscore.neg,
regscore.pos);
regscore.score =
((min * 1000.0f) /
(float) (max *
regscore.values.size())) *
((float) (min + max) / (counter - start));
//If this register has only seen 1 or two legit values, then punish it
if (regscore.values.size() < 2)
{
regscore.score /= 10.0f;
}
//Add on any bonuses this register has received
regscore.score += regscore.bonus;
}
}
}
//Now find the highest scoring registers/index
float topscore = 0.f;
float mat_topscore = 0.f;
for (int r = 0; r < 96; ++r)
{
if (regscores2[r].score > mat_topscore) {
vr_heuristic.view_matrixregister = r;
mat_topscore = regscores2[r].score;
}
for (int i = 0; i <= 3; ++i)
{
if (regscores[r * 4 + i].score > topscore)
{
vr_heuristic.eye_indicator_register = r;
vr_heuristic.eye_indicator_reg_index = i;
topscore = regscores[r * 4 + i].score;
}
}
}
if (mat_topscore != 0.f) {
regscores2[vr_heuristic.view_matrixregister].score += 0.05f; // small perk for being selected
}
if (topscore != 0.0f)
{
regscores[vr_heuristic.eye_indicator_register * 4 +
vr_heuristic.eye_indicator_reg_index].bonus += 0.001f; // small perk for being selected
}
}
viewMatrixIndex = vr_heuristic.view_matrixregister;
}
}
if (viewMatrixIndex != -1 && vs_uniforms.uniforms.f.size() > viewMatrixIndex)
{
if (matrixMode == 2)
{
f[viewMatrixIndex][0] = vr_view[0];
f[viewMatrixIndex][1] = vr_view[4];
f[viewMatrixIndex][2] = vr_view[8];
f[viewMatrixIndex + 1][0] = vr_view[1];
f[viewMatrixIndex + 1][1] = vr_view[5];
f[viewMatrixIndex + 1][2] = vr_view[9];
f[viewMatrixIndex + 2][0] = vr_view[2];
f[viewMatrixIndex + 2][1] = vr_view[6];
f[viewMatrixIndex + 2][2] = vr_view[10];
f[viewMatrixIndex][0] = vr_inv_view[0];
f[viewMatrixIndex][1] = vr_inv_view[4];
f[viewMatrixIndex][2] = vr_inv_view[8];
f[viewMatrixIndex + 1][0] = vr_inv_view[1];
f[viewMatrixIndex + 1][1] = vr_inv_view[5];
f[viewMatrixIndex + 1][2] = vr_inv_view[9];
f[viewMatrixIndex + 2][0] = vr_inv_view[2];
f[viewMatrixIndex + 2][1] = vr_inv_view[6];
f[viewMatrixIndex + 2][2] = vr_inv_view[10];
}
else if (matrixMode >= 3)
else if (matrixMode == 3)
{
// First apply the view transformation matrix to the right location
float v[16], v2[16], v3[16];
MatrixTranspose(v, &f[viewMatrixIndex].x);
std::memcpy(v2, vr_view, sizeof(float) * 16);
std::memcpy(v2, vr_inv_view, sizeof(float) * 16);
v2[12] = v2[13] = v2[14] = 0.f;
MatrixMultiply(v3, v2, v);
MatrixTranspose(&f[viewMatrixIndex].x, v3);
// This following part is an improvement on just using the default stereo separation provided by the 3DS
// The problem with the default is it doesn't work correctly when rotating the headset, whereas the following approach
// applies a left/right separation from an (almost) centered camera POV.
// This profile mode will set a depth scale of only 0.1%, and then use a defined vr uniform register
// to identify if the left or right eye is being drawn and apply appropriate stereo separation
//
// The pair of values (e.g "87,2") represents the offset of the Vec4f in the vs pica uniforms and the
// index into that Vec4 of the value that is check for: -ve for left eye and +ve for right eye
float eye_indicator_register = vr_heuristic.eye_indicator_register;
float eye_indicator_reg_index = vr_heuristic.eye_indicator_reg_index;
//If the user _has_ defined this (unlikely!) then use the config setting
if (!findLeftRightEyeIndicator)
{
// Finding these offset/index values manually is easier to do using a desktop build of Citra in a debugger
// however the heuristic search appears to do a very good job of this so it is unlikely people
// will need to find and specify this config, but is still available to set if it fails to work for
// a game and someone identifies the appropriate values
const std::string vr_immersive_eye_indicator = Settings::values.vr_immersive_eye_indicator.GetValue();
eye_indicator_register = atoi(vr_immersive_eye_indicator.substr(0, vr_immersive_eye_indicator.find_first_of(',')).c_str());
eye_indicator_reg_index = atoi(vr_immersive_eye_indicator.substr(vr_immersive_eye_indicator.find_first_of(',')+1).c_str());
}
//If we found/know a viable register/index, then use it for left/right eye logic
if (eye_indicator_register != -1 &&
eye_indicator_reg_index != -1 &&
eye_indicator_register < vs_uniforms.uniforms.f.size() &&
(eye_indicator_register < viewMatrixIndex ||
eye_indicator_register > viewMatrixIndex + 3) &&
f[eye_indicator_register][eye_indicator_reg_index] != 0.0f)
{
const bool isLeftEye = (f[eye_indicator_register][eye_indicator_reg_index] < 0.f);
f[viewMatrixIndex][3] +=
vr_game_pos_scaler * (isLeftEye ? -1 : 1) * (VR_IPD / 2.f);
}
}
f[viewMatrixIndex][3] += vr_view[12];
f[viewMatrixIndex + 1][3] += vr_view[13];
f[viewMatrixIndex + 2][3] += vr_view[14];
f[viewMatrixIndex][3] += vr_inv_view[12];
f[viewMatrixIndex + 1][3] += vr_inv_view[13];
f[viewMatrixIndex + 2][3] += vr_inv_view[14];
}
}
}

View file

@ -4,7 +4,6 @@
#pragma once
#include "common/vector_math.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/shader/generator/pica_fs_config.h"
#include "video_core/shader/generator/shader_uniforms.h"
@ -31,7 +30,7 @@ public:
void SyncEntireState() override;
void SetVRData(const int32_t &vrImmersiveMode, const float& immersiveModeFactor, int uoffset, const float view[16]) override;
void SetVRData(const int32_t &vrImmersiveMode, const float& immersiveModeFactor, int uoffset, const float& gamePosScaler, const float inv_view[16]) override;
protected:
/// Sync fixed-function pipeline state
@ -173,12 +172,19 @@ protected:
std::array<Common::Vec4f, 256> proctex_diff_lut_data{};
//VR Stuff
u32 vr_uoffset = -1;
u32 vr_immersive_mode;
float vr_view[16] = {};
u32 vr_uoffset = 0;
u32 vr_immersive_mode;
float vr_game_pos_scaler = 0.f;
float vr_inv_view[16] = {};
struct HeuristicResult
{
int32_t view_matrixregister = -1;
int32_t eye_indicator_register = -1;
int32_t eye_indicator_reg_index = -1;
} vr_heuristic;
public:
void ApplyVRDataToPicaVSUniforms(Pica::Shader::Generator::VSPicaUniformData &vs_uniforms);
};

View file

@ -84,6 +84,6 @@ public:
virtual void SyncEntireState() {}
/// Set VR position data on the rasterizer
virtual void SetVRData(const int32_t &vrImmersiveMode, const float& immersiveModeFactor, int uoffset, const float view[16]) {}
virtual void SetVRData(const int32_t &vrImmersiveMode, const float& immersiveModeFactor, int uoffset, const float& gamePosScaler, const float inv_view[16]) {}
};
} // namespace VideoCore