Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/Deferred.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ void Deferred::StartDeferred()

ID3D11Buffer* vrBuffer = nullptr;

if (REL::Module::IsVR()) {
if (globals::game::isVR) {
static REL::Relocation<ID3D11Buffer**> VRValues{ REL::Offset(0x3180688) };
vrBuffer = *VRValues.get();
}
Expand Down Expand Up @@ -302,7 +302,7 @@ void Deferred::DeferredPasses()
ID3D11Buffer* buffers[1] = { *globals::game::perFrame };
ID3D11Buffer* vrBuffer = nullptr;

if (REL::Module::IsVR()) {
if (globals::game::isVR) {
static REL::Relocation<ID3D11Buffer**> VRValues{ REL::Offset(0x3180688) };
vrBuffer = *VRValues.get();
}
Expand Down Expand Up @@ -357,7 +357,7 @@ void Deferred::DeferredPasses()
albedo.SRV, // t1 AlbedoTexture
normalRoughness.SRV, // t2 NormalRoughnessTexture
masks.SRV, // t3 MasksTexture
dynamicCubemaps.loaded || REL::Module::IsVR() ? Util::GetCurrentSceneDepthSRV(false) : nullptr, // t4 DepthTexture (24/32-bit; HLSL type baked at compile via TERRAIN_BLENDING)
dynamicCubemaps.loaded || globals::game::isVR ? Util::GetCurrentSceneDepthSRV(false) : nullptr, // t4 DepthTexture (24/32-bit; HLSL type baked at compile via TERRAIN_BLENDING)
dynamicCubemaps.loaded ? reflectance.SRV : nullptr, // t5 ReflectanceTexture
dynamicCubemaps.loaded ? dynamicCubemaps.envTexture->srv.get() : nullptr, // t6 EnvTexture
dynamicCubemaps.loaded ? dynamicCubemaps.envReflectionsTexture->srv.get() : nullptr, // t7 EnvReflectionsTexture
Expand Down Expand Up @@ -663,10 +663,10 @@ ID3D11ComputeShader* Deferred::GetComputeMainComposite()
if (globals::features::ibl.loaded)
defines.push_back({ "IBL", nullptr });

if (REL::Module::IsVR())
if (globals::game::isVR)
defines.push_back({ "FRAMEBUFFER", nullptr });

if (REL::Module::IsVR())
if (globals::game::isVR)
defines.push_back({ "VR_STEREO_OPT", nullptr });

// TERRAIN_BLENDING flips DepthTexture's HLSL type from `Texture2D<unorm float>`
Expand Down Expand Up @@ -696,10 +696,10 @@ ID3D11ComputeShader* Deferred::GetComputeMainCompositeInterior()
if (globals::features::ibl.loaded)
defines.push_back({ "IBL", nullptr });

if (REL::Module::IsVR())
if (globals::game::isVR)
defines.push_back({ "FRAMEBUFFER", nullptr });

if (REL::Module::IsVR())
if (globals::game::isVR)
defines.push_back({ "VR_STEREO_OPT", nullptr });

// TERRAIN_BLENDING flips DepthTexture's HLSL type from `Texture2D<unorm float>`
Expand Down
2 changes: 1 addition & 1 deletion src/Deferred.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class Deferred
stl::write_thunk_call<Main_RenderWorld_Start>(REL::RelocationID(99938, 106583).address() + REL::Relocate(0x8E, 0x84));
stl::write_thunk_call<Main_RenderWorld_BlendedDecals>(REL::RelocationID(99938, 106583).address() + REL::Relocate(0x319, 0x308, 0x321));

if (!REL::Module::IsVR())
if (!globals::game::isVR)
stl::write_thunk_call<Main_RenderFirstPersonView>(REL::RelocationID(35560, 36559).address() + REL::Relocate(0x944, 0x954));

stl::detour_thunk<Renderer_ResetState>(REL::RelocationID(75570, 77371));
Expand Down
2 changes: 1 addition & 1 deletion src/Feature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ const std::vector<Feature*>& Feature::GetFeatureList()
&globals::features::hdrDisplay
};

if (REL::Module::IsVR()) {
if (globals::game::isVR) {
// Helper function to build VR feature list
static auto BuildVRList = []() -> std::vector<Feature*> {
auto v = features;
Expand Down
2 changes: 1 addition & 1 deletion src/FeatureIssues.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,7 @@ namespace FeatureIssues
}

// Skip VR feature when not in VR mode (it's a core feature)
if (featureName == "VR" && !REL::Module::IsVR()) {
if (featureName == "VR" && !globals::game::isVR) {
logger::info("Ignoring VR.ini in non-VR mode");
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Features/GrassCollision.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ void GrassCollision::UpdateCollisionTexture()
ID3D11Buffer* buffers[1] = { *globals::game::perFrame };
ID3D11Buffer* vrBuffer = nullptr;

if (REL::Module::IsVR()) {
if (globals::game::isVR) {
static REL::Relocation<ID3D11Buffer**> VRValues{ REL::Offset(0x3180688) };
vrBuffer = *VRValues.get();
}
Expand Down
8 changes: 4 additions & 4 deletions src/Features/LightLimitFix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ LightLimitFix::PerFrame LightLimitFix::GetCommonBufferData()
void LightLimitFix::SetupResources()
{
auto screenSize = globals::state->screenSize;
if (REL::Module::IsVR())
if (globals::game::isVR)
screenSize.x *= .5;
clusterSize[0] = ((uint)screenSize.x + 63) / 64;
clusterSize[1] = ((uint)screenSize.y + 63) / 64;
Expand All @@ -413,7 +413,7 @@ void LightLimitFix::SetupResources()

{
std::vector<std::pair<const char*, const char*>> clusterDefines;
if (REL::Module::IsVR())
if (globals::game::isVR)
clusterDefines = { { "VR", "" } };
clusterBuildingCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\LightLimitFix\\ClusterBuildingCS.hlsl", clusterDefines, "cs_5_0");
clusterCullingCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\LightLimitFix\\ClusterCullingCS.hlsl", clusterDefines, "cs_5_0");
Expand Down Expand Up @@ -847,7 +847,7 @@ void LightLimitFix::ClearShaderCache()
clusterCullingCS = nullptr;
}
std::vector<std::pair<const char*, const char*>> clusterDefines;
if (REL::Module::IsVR())
if (globals::game::isVR)
clusterDefines = { { "VR", "" } };
clusterBuildingCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\LightLimitFix\\ClusterBuildingCS.hlsl", clusterDefines, "cs_5_0");
clusterCullingCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\LightLimitFix\\ClusterCullingCS.hlsl", clusterDefines, "cs_5_0");
Expand Down Expand Up @@ -1150,7 +1150,7 @@ void LightLimitFix::UpdateStructure()
lightsFar = *globals::game::cameraFar;

auto renderSize = Util::ConvertToDynamic(globals::state->screenSize);
if (REL::Module::IsVR())
if (globals::game::isVR)
renderSize.x *= .5;
clusterSize[0] = ((uint)renderSize.x + 63) / 64;
clusterSize[1] = ((uint)renderSize.y + 63) / 64;
Expand Down
1 change: 1 addition & 0 deletions src/Features/LightLimitFix.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ struct LightLimitFix : OverlayFeature

ConstantBuffer* strictLightDataCB = nullptr;

// Keep raw runtime check for ctor-time default before globals::ReInit().
int eyeCount = !REL::Module::IsVR() ? 1 : 2;

// Debug-only visualization state. Lives on the instance rather than in
Expand Down
36 changes: 18 additions & 18 deletions src/Features/LightLimitFix/ShadowCasterManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ namespace ShadowCasterManager
// Hook #2: VR: renderer in R14, result -> RBP; SE/AE: renderer in RBP, result -> R14.
static void Hook_SelectDepthBuffer2(CONTEXT& ctx)
{
bool isVR = REL::Module::IsVR();
bool isVR = globals::game::isVR;
bool readOnly = isVR ? reinterpret_cast<RE::BSGraphics::Renderer*>(ctx.R14)->GetRuntimeData().readOnlyDepth : reinterpret_cast<RE::BSGraphics::Renderer*>(ctx.Rbp)->GetRuntimeData().readOnlyDepth;

int type = GetDepthTargetType();
Expand Down Expand Up @@ -479,7 +479,7 @@ namespace ShadowCasterManager
// cover the same range as FindFreeIndex; a mismatch means a light
// silently gets idx=0 and corrupts the slot at index 0.

if (REL::Module::IsVR())
if (globals::game::isVR)
ctx.Rdx = static_cast<DWORD64>(idx);
else
ctx.Rsi = static_cast<DWORD64>(idx);
Expand Down Expand Up @@ -1229,7 +1229,7 @@ namespace ShadowCasterManager
static void GameApplyLensFlare(RE::BSLight* light)
{
// SE/AE only -- no VR equivalent (ID 100440)
if (REL::Module::IsVR())
if (globals::game::isVR)
return;
using F = void (*)(RE::BSLight*);
static REL::Relocation<F> func{ REL::RelocationID(100440, 107157) };
Expand Down Expand Up @@ -1257,7 +1257,7 @@ namespace ShadowCasterManager
// VR: (cam, coord, r1, r2, eyeIndex, eps) -- pass 0xffffffff for combined frustum
static REL::Relocation<uintptr_t> addr{ REL::RelocationID(69265, 70632) };
auto ptr = addr.address();
if (REL::Module::IsVR()) {
if (globals::game::isVR) {
using VR = void (*)(RE::NiCamera*, float*, float*, float*, uint32_t, float);
reinterpret_cast<VR>(ptr)(cam, coord, r1, r2, 0xffffffffu, eps);
} else {
Expand All @@ -1269,12 +1269,12 @@ namespace ShadowCasterManager
// Convenience: runtime-aware shadow-light field accessor (SE vs VR RuntimeData differ).
// Usage: ShadowField(light, maskIndex) = 3;
#define ShadowField(light, member) \
(REL::Module::IsVR() ? (light)->GetVRRuntimeData().member : (light)->GetRuntimeData().member)
(globals::game::isVR ? (light)->GetVRRuntimeData().member : (light)->GetRuntimeData().member)

// Returns the culling process for the first shadow descriptor of a light.
static RE::BSCullingProcess* GetLightCullingProcess(RE::BSShadowLight* light)
{
return REL::Module::IsVR() ? light->GetVRRuntimeData().shadowmapDescriptors.front().cullingProcess : light->GetRuntimeData().shadowmapDescriptors.front().cullingProcess;
return globals::game::isVR ? light->GetVRRuntimeData().shadowmapDescriptors.front().cullingProcess : light->GetRuntimeData().shadowmapDescriptors.front().cullingProcess;
}

// =========================================================================
Expand Down Expand Up @@ -1601,7 +1601,7 @@ namespace ShadowCasterManager
if (drawFocus || (!*GetFocusShadowSelected() && light->GetIsFrustumOrDirectionalLight())) {
GameSetupDirectionalLight(light, camera);
GameAccumulate(light);
if (REL::Module::IsVR()) {
if (globals::game::isVR) {
for (auto& desc : light->GetVRRuntimeData().focusShadowmapDescriptors) {
desc.vrRenderTarget[0] = RE::RENDER_TARGET_DEPTHSTENCIL::kNONE;
desc.vrRenderTarget[1] = RE::RENDER_TARGET_DEPTHSTENCIL::kNONE;
Expand Down Expand Up @@ -1647,7 +1647,7 @@ namespace ShadowCasterManager

float vw = (float)*globals::game::viewWidth;
float vh = (float)*globals::game::viewHeight;
if (REL::Module::IsVR()) {
if (globals::game::isVR) {
vw *= GetVRDRSWidthRatio();
vh *= GetVRDRSHeightRatio();
}
Expand Down Expand Up @@ -1683,7 +1683,7 @@ namespace ShadowCasterManager
int32_t idx = s_lights.FindLight(light, s_settings.ShadowLightCount);
if (idx < 0)
idx = 0;
if (REL::Module::IsVR()) {
if (globals::game::isVR) {
for (auto& desc : light->GetVRRuntimeData().shadowmapDescriptors) {
desc.renderTarget = RE::RENDER_TARGET_DEPTHSTENCIL::kNONE;
desc.shadowmapIndex = static_cast<uint32_t>(idx);
Expand Down Expand Up @@ -1754,7 +1754,7 @@ namespace ShadowCasterManager
} guard;

// VR display guard: skip scheduling when the HMD display is not active.
if (REL::Module::IsVR() && !GetVRDrawShadows())
if (globals::game::isVR && !GetVRDrawShadows())
return;

auto* ssn = GetShadowSceneNode();
Expand Down Expand Up @@ -1792,13 +1792,13 @@ namespace ShadowCasterManager
auto* sun = ssn->GetRuntimeData().sunShadowDirLight;
if (sun) {
static REL::Relocation<bool*> vrUpdateFlag{ REL::Offset(0x1ed62f8) };
uint8_t vrFlag = REL::Module::IsVR() ? static_cast<uint8_t>(*vrUpdateFlag) + 1 : 0;
uint8_t vrFlag = globals::game::isVR ? static_cast<uint8_t>(*vrUpdateFlag) + 1 : 0;
sun->Accumulate(*GetAccumLightSlot(), 0, nullptr, vrFlag);

if (sun->lensFlareData && !REL::Module::IsVR())
if (sun->lensFlareData && !globals::game::isVR)
GameApplyLensFlare(sun);

if (REL::Module::IsVR() && !GetVRAccumFirst()) {
if (globals::game::isVR && !GetVRAccumFirst()) {
GameVRPrepareShadowMaps(sun);
GameVRAccumulateShadowMaps(sun);
}
Expand Down Expand Up @@ -2779,7 +2779,7 @@ namespace ShadowCasterManager
// kSHADOWMAPS, so its descriptor.shadowmapIndex is unused.
if (s_lights.Sun && i == 0)
continue;
if (REL::Module::IsVR()) {
if (globals::game::isVR) {
for (auto& desc : e.Light->GetVRRuntimeData().shadowmapDescriptors)
desc.shadowmapIndex = static_cast<uint32_t>(i);
} else {
Expand Down Expand Up @@ -2866,7 +2866,7 @@ namespace ShadowCasterManager
// iterating shadow casters, then restores it. Without this, each hemisphere
// render is doubled for both eyes -> 4-quadrant shadow map texture.
bool savedStereo = false;
if (REL::Module::IsVR()) {
if (globals::game::isVR) {
savedStereo = *globals::game::drawStereo;
*globals::game::drawStereo = false;
}
Expand Down Expand Up @@ -2918,7 +2918,7 @@ namespace ShadowCasterManager

state->EndPerfEvent();

if (REL::Module::IsVR())
if (globals::game::isVR)
*globals::game::drawStereo = savedStereo;
}

Expand All @@ -2931,7 +2931,7 @@ namespace ShadowCasterManager
// r8 gets a stale pointer whose [+0x50] slot is null -> crash at execute 0x0.
static void Hook_RenderShadowLights(CONTEXT& ctx)
{
if (!REL::Module::IsVR())
if (!globals::game::isVR)
ctx.Rax = 0;
RenderScheduledShadowLights();
};
Expand Down Expand Up @@ -2999,7 +2999,7 @@ namespace ShadowCasterManager
uint32_t fpMask = *reinterpret_cast<uint32_t*>(ctx.Rsp + 0x50); // a10

// VR passes an 11th arg: if non-zero, skip accumulation (vanilla early-out).
if (REL::Module::IsVR() && *reinterpret_cast<char*>(ctx.Rsp + 0x58) != 0) {
if (globals::game::isVR && *reinterpret_cast<char*>(ctx.Rsp + 0x58) != 0) {
ctx.Rax = 1; // addedLightCount = sun only
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Features/RemoteControl/DevBenchBridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ namespace
// Don't let a remote caller enable a VR-incompatible feature on a VR runtime:
// it bypasses the SupportsVR() gate and can destabilize the renderer. Reject +
// report (covers both an explicit enable and an implicit flip resolving to true).
if (applied && REL::Module::IsVR() && !target->SupportsVR()) {
if (applied && globals::game::isVR && !target->SupportsVR()) {
if (auto* dvb = DevBenchAPI::GetDevBenchInterface001()) {
const std::string payload = json{ { "shortName", shortName }, { "error", "feature does not support VR; enable rejected" } }.dump();
dvb->EmitEvent("openshaders.feature.changed", payload.c_str());
Expand Down Expand Up @@ -292,7 +292,7 @@ namespace
return json{
{ "plugin", "CommunityShaders" },
{ "frame_count", EnqueuedFrame() },
{ "vr", REL::Module::IsVR() },
{ "vr", globals::game::isVR },
};
}
if (kind == "shadercache") {
Expand Down
10 changes: 5 additions & 5 deletions src/Features/ScreenSpaceGI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -613,10 +613,10 @@ void ScreenSpaceGI::CompileComputeShaders()
{ &upsampleCompute, "upsample.cs.hlsl", {} },
};

if (REL::Module::IsVR())
if (globals::game::isVR)
shaderInfos.push_back({ &stereoSyncCompute, "stereoSync.cs.hlsl", { { "FRAMEBUFFER", "" } } });
for (auto& info : shaderInfos) {
if (REL::Module::IsVR())
if (globals::game::isVR)
info.defines.push_back({ "VR", "" });
if (settings.ResolutionMode == 1)
info.defines.push_back({ "HALF_RES", "" });
Expand Down Expand Up @@ -654,13 +654,13 @@ void ScreenSpaceGI::UpdateSB()

SSGICB data;
{
for (int eyeIndex = 0; eyeIndex < (1 + REL::Module::IsVR()); ++eyeIndex) {
for (int eyeIndex = 0; eyeIndex < (1 + globals::game::isVR); ++eyeIndex) {
auto eye = Util::GetCameraData(eyeIndex);

data.PrevInvViewMat[eyeIndex] = prevInvView[eyeIndex];
data.NDCToViewMul[eyeIndex] = { 2.0f / eye.projMat(0, 0), -2.0f / eye.projMat(1, 1) };
data.NDCToViewAdd[eyeIndex] = { -1.0f / eye.projMat(0, 0), 1.0f / eye.projMat(1, 1) };
if (REL::Module::IsVR())
if (globals::game::isVR)
data.NDCToViewMul[eyeIndex].x *= 2;

prevInvView[eyeIndex] = eye.viewMat.Invert();
Expand Down Expand Up @@ -913,7 +913,7 @@ void ScreenSpaceGI::DrawSSGI()

// VR stereo sync: bilateral blend of SSGI buffers between eyes
// Shi, Billeter, Eisemann 2022, "Stereo-consistent screen-space ambient occlusion"
if (REL::Module::IsVR() && stereoSyncCompute) {
if (globals::game::isVR && stereoSyncCompute) {
TracyD3D11Zone(globals::state->tracyCtx, "SSGI - Stereo Sync");

if (globals::state->frameAnnotations)
Expand Down
3 changes: 2 additions & 1 deletion src/Features/ScreenSpaceGI.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct ScreenSpaceGI : Feature
"Screen Space Global Illumination adds realistic indirect lighting and "
"ambient occlusion to the game. This technique simulates how light "
"bounces off surfaces to illuminate other objects naturally.";
if (REL::Module::IsVR()) {
if (globals::game::isVR) {
desc +=
"\n\nWarning: In VR, this feature may have visual artifacts and "
"can have a significant performance impact due to the nature of "
Expand Down Expand Up @@ -60,6 +60,7 @@ struct ScreenSpaceGI : Feature
struct Settings
{
bool Enabled = true;
// Keep raw runtime check for ctor-time defaults before globals::ReInit().
bool EnableGI = REL::Module::IsVR() ? false : true; // AO only for VR by default
bool EnableExperimentalSpecularGI = false;
bool EnableVanillaSSAO = false;
Expand Down
2 changes: 1 addition & 1 deletion src/Features/ScreenshotFeature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ void ScreenshotFeature::PostPostLoad()
// only dispatches to LoadSettings when the JSON already has a settings
// block, so a fresh install would skip a seed placed there. Left first so
// it's the initial selection (matches vanilla Skyrim VR's left-eye save).
if (REL::Module::IsVR()) {
if (globals::game::isVR) {
subrect.SeedDefaultPresets({
{ .name = "Left Eye", .uv = { 0.0f, 0.0f, 0.5f, 1.0f } },
{ .name = "Right Eye", .uv = { 0.5f, 0.0f, 0.5f, 1.0f } },
Expand Down
2 changes: 1 addition & 1 deletion src/Features/Skylighting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ void Skylighting::PostPostLoad()
stl::write_vfunc<0x2D, BSLightingShaderProperty_GetPrecipitationOcclusionMapRenderPassesImpl>(RE::VTABLE_BSLightingShaderProperty[0]);
stl::write_thunk_call<Main_Precipitation_RenderOcclusion>(REL::RelocationID(35560, 36559).address() + REL::Relocate(0x3A1, 0x3A1, 0x2FA));

if (REL::Module::IsVR())
if (globals::game::isVR)
stl::write_thunk_call<SetViewFrustumVR>(REL::RelocationID(25643, 26185).address() + REL::Relocate(0x5D9, 0x59D, 0x5DC));
else
stl::write_thunk_call<SetViewFrustum>(REL::RelocationID(25643, 26185).address() + REL::Relocate(0x5D9, 0x59D, 0x5DC));
Expand Down
2 changes: 1 addition & 1 deletion src/Features/Upscaling/DX12SwapChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ void DX12SwapChain::CreateSwapChain(IDXGIAdapter* adapter, DXGI_SWAP_CHAIN_DESC
// Runtime format negotiation for swap chain
DXGI_FORMAT attemptedFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
DXGI_FORMAT negotiatedFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
bool isVR = REL::Module::IsVR();
bool isVR = globals::game::isVR;
bool fallbackUsed = false;

// Test R10G10B10A2 support (applies to both VR and non-VR for HDR capability)
Expand Down
2 changes: 1 addition & 1 deletion src/Features/Upscaling/PerfMode/MenuBridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ void PerfMode::MaybeBlitMenuBG(uint32_t boundRTIdx)

void PerfMode::InstallCreateRTThunks()
{
if (!REL::Module::IsVR())
if (!globals::game::isVR)
return;
auto vrBase = REL::RelocationID(100458, 107175).address();
stl::write_thunk_call<CreateRT_MenuBG_Hook>(vrBase + 0x6cc);
Expand Down
2 changes: 1 addition & 1 deletion src/Features/VR.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ struct VR : OverlayFeature
void CompileStereoBlendShaders();
bool IsStereoOptimizationCullingReady() const
{
return REL::Module::IsVR() &&
return globals::game::isVR &&
stereoOpt.CanDispatchStencil() &&
stereoBlendOverwriteCS &&
stereoBlendCopyTex &&
Expand Down
Loading
Loading