From c024b89171a790e7d22e39737d517097e2407240 Mon Sep 17 00:00:00 2001
From: Joshua Ashton <joshua@froggi.es>
Date: Wed, 1 Jan 2020 20:53:20 +0000
Subject: [PATCH] [dxso] Implement d3d9.forceSamplerTypeSpecConstants

This option makes us always use a spec constant to determine sampler type (instead of just in PS 1.x)
which works around a game bug in Halo CE where it gives cube textures to 2d/volume samplers
---
 src/d3d9/d3d9_device.cpp   |  2 +-
 src/d3d9/d3d9_options.cpp  |  1 +
 src/d3d9/d3d9_options.h    |  4 ++++
 src/dxso/dxso_compiler.cpp | 14 ++++++++------
 src/dxso/dxso_options.cpp  |  2 ++
 src/dxso/dxso_options.h    |  4 ++++
 6 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp
index c2801341c..fb75af28f 100644
--- a/src/d3d9/d3d9_device.cpp
+++ b/src/d3d9/d3d9_device.cpp
@@ -5403,7 +5403,7 @@ namespace dxvk {
       UploadConstants<DxsoProgramTypes::PixelShader>();
 
       if (GetCommonShader(m_state.pixelShader)->GetInfo().majorVersion() >= 2)
-        UpdateSamplerTypes(0u, 0u);
+        UpdateSamplerTypes(m_d3d9Options.forceSamplerTypeSpecConstants ? m_samplerTypeBitfield : 0u, 0u);
       else
         UpdateSamplerTypes(m_samplerTypeBitfield, m_projectionBitfield); // For implicit samplers...
     }
diff --git a/src/d3d9/d3d9_options.cpp b/src/d3d9/d3d9_options.cpp
index 0b7371a12..1f290f760 100644
--- a/src/d3d9/d3d9_options.cpp
+++ b/src/d3d9/d3d9_options.cpp
@@ -61,6 +61,7 @@ namespace dxvk {
     this->memoryTrackTest       = config.getOption<bool>    ("d3d9.memoryTrackTest",       false);
     this->supportVCache         = config.getOption<bool>    ("d3d9.supportVCache",         vendorId == 0x10de);
     this->enableDialogMode      = config.getOption<bool>    ("d3d9.enableDialogMode",      false);
+    this->forceSamplerTypeSpecConstants = config.getOption<bool> ("d3d9.forceSamplerTypeSpecConstants", false);
 
     this->forceAspectRatio      = config.getOption<std::string>("d3d9.forceAspectRatio",   "");
 
diff --git a/src/d3d9/d3d9_options.h b/src/d3d9/d3d9_options.h
index 7e044ddf0..9e33f482f 100644
--- a/src/d3d9/d3d9_options.h
+++ b/src/d3d9/d3d9_options.h
@@ -112,6 +112,10 @@ namespace dxvk {
 
     /// Enable dialog mode (ie. no exclusive fullscreen)
     bool enableDialogMode;
+
+    /// Always use a spec constant to determine sampler type (instead of just in PS 1.x)
+    /// Works around a game bug in Halo CE where it gives cube textures to 2d/volume samplers
+    bool forceSamplerTypeSpecConstants;
   };
 
 }
\ No newline at end of file
diff --git a/src/dxso/dxso_compiler.cpp b/src/dxso/dxso_compiler.cpp
index c1712438e..f430bf351 100644
--- a/src/dxso/dxso_compiler.cpp
+++ b/src/dxso/dxso_compiler.cpp
@@ -438,14 +438,16 @@ namespace dxvk {
     m_ps.functionId = m_module.allocateId();
     m_module.setDebugName(m_ps.functionId, "ps_main");
 
-    if (m_programInfo.majorVersion() < 2) {
+    if (m_programInfo.majorVersion() < 2 || m_moduleInfo.options.forceSamplerTypeSpecConstants) {
       m_ps.samplerTypeSpec = m_module.specConst32(m_module.defIntType(32, 0), 0);
       m_module.decorateSpecId(m_ps.samplerTypeSpec, getSpecId(D3D9SpecConstantId::SamplerType));
       m_module.setDebugName(m_ps.samplerTypeSpec, "s_sampler_types");
 
-      m_ps.projectionSpec = m_module.specConst32(m_module.defIntType(32, 0), 0);
-      m_module.decorateSpecId(m_ps.projectionSpec, getSpecId(D3D9SpecConstantId::ProjectionType));
-      m_module.setDebugName(m_ps.projectionSpec, "s_projections");
+      if (m_programInfo.majorVersion() < 2) {
+        m_ps.projectionSpec = m_module.specConst32(m_module.defIntType(32, 0), 0);
+        m_module.decorateSpecId(m_ps.projectionSpec, getSpecId(D3D9SpecConstantId::ProjectionType));
+        m_module.setDebugName(m_ps.projectionSpec, "s_projections");
+      }
     }
 
     this->setupRenderStateInfo();
@@ -723,7 +725,7 @@ namespace dxvk {
       m_resourceSlots.push_back(resource);
     };
 
-    if (m_programInfo.majorVersion() >= 2) {
+    if (m_programInfo.majorVersion() >= 2 && !m_moduleInfo.options.forceSamplerTypeSpecConstants) {
       DxsoSamplerType samplerType = 
         SamplerTypeFromTextureType(type);
 
@@ -2772,7 +2774,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
         SampleImage(texcoordVar, sampler.color[samplerType], false, samplerType);
     };
 
-    if (m_programInfo.majorVersion() >= 2) {
+    if (m_programInfo.majorVersion() >= 2 && !m_moduleInfo.options.forceSamplerTypeSpecConstants) {
       DxsoSamplerType samplerType =
         SamplerTypeFromTextureType(sampler.type);
 
diff --git a/src/dxso/dxso_options.cpp b/src/dxso/dxso_options.cpp
index ae6fb603d..ef402b0c5 100644
--- a/src/dxso/dxso_options.cpp
+++ b/src/dxso/dxso_options.cpp
@@ -37,6 +37,8 @@ namespace dxvk {
     shaderModel          = options.shaderModel;
 
     invariantPosition    = options.invariantPosition;
+
+    forceSamplerTypeSpecConstants = options.forceSamplerTypeSpecConstants;
   }
 
 }
\ No newline at end of file
diff --git a/src/dxso/dxso_options.h b/src/dxso/dxso_options.h
index def47c420..5a8e5c56a 100644
--- a/src/dxso/dxso_options.h
+++ b/src/dxso/dxso_options.h
@@ -37,6 +37,10 @@ namespace dxvk {
     /// Work around a NV driver quirk
     /// Fixes flickering/z-fighting in some games.
     bool invariantPosition;
+
+    /// Always use a spec constant to determine sampler type (instead of just in PS 1.x)
+    /// Works around a game bug in Halo CE where it gives cube textures to 2d/volume samplers
+    bool forceSamplerTypeSpecConstants;
   };
 
 }
\ No newline at end of file