From d4a73461982b50c20d069e19009b801b3507b6eb Mon Sep 17 00:00:00 2001
From: WinterSnowfall <WinterSnowfall@users.noreply.github.com>
Date: Thu, 18 May 2023 11:01:57 +0300
Subject: [PATCH] [dxvk] Add configurable HUD opacity

---
 README.md                                |  1 +
 src/dxvk/hud/dxvk_hud.cpp                |  9 +++++++--
 src/dxvk/hud/dxvk_hud.h                  |  1 +
 src/dxvk/hud/dxvk_hud_renderer.cpp       | 12 +++++++++++-
 src/dxvk/hud/dxvk_hud_renderer.h         |  5 ++++-
 src/dxvk/hud/shaders/hud_graph_frag.frag |  3 ++-
 src/dxvk/hud/shaders/hud_graph_vert.vert |  1 +
 7 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/README.md b/README.md
index 6bab9df49..8e3f4a43b 100644
--- a/README.md
+++ b/README.md
@@ -94,6 +94,7 @@ The `DXVK_HUD` environment variable controls a HUD which can display the framera
 - `compiler`: Shows shader compiler activity
 - `samplers`: Shows the current number of sampler pairs used *[D3D9 Only]*
 - `scale=x`: Scales the HUD by a factor of `x` (e.g. `1.5`)
+- `opacity=y`: Adjusts the HUD opacity by a factor of `y` (e.g. `0.5`, `1.0` being fully opaque).
 
 Additionally, `DXVK_HUD=1` has the same effect as `DXVK_HUD=devinfo,fps`, and `DXVK_HUD=full` enables all available HUD elements.
 
diff --git a/src/dxvk/hud/dxvk_hud.cpp b/src/dxvk/hud/dxvk_hud.cpp
index 752e514b4..2fc34655b 100644
--- a/src/dxvk/hud/dxvk_hud.cpp
+++ b/src/dxvk/hud/dxvk_hud.cpp
@@ -9,11 +9,16 @@ namespace dxvk::hud {
   : m_device        (device),
     m_renderer      (device),
     m_hudItems      (device),
-    m_scale         (m_hudItems.getOption<float>("scale", 1.0f)) {
+    m_scale         (m_hudItems.getOption<float>("scale", 1.0f)),
+    m_opacity       (m_hudItems.getOption<float>("opacity", 1.0f)) {
     // Sanitize scaling factor
     if (m_scale < 0.01f)
       m_scale = 1.0f;
 
+    // Sanitize HUD opacity factor
+    if (m_opacity != 1.0f)
+      m_opacity = std::max(std::min(m_opacity, 1.0f), 0.1f);
+
     // Set up constant state
     m_rsState.polygonMode       = VK_POLYGON_MODE_FILL;
     m_rsState.cullMode          = VK_CULL_MODE_BACK_BIT;
@@ -101,7 +106,7 @@ namespace dxvk::hud {
     ctx->setBlendMode(0, m_blendMode);
 
     ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, 0, colorSpace);
-    m_renderer.beginFrame(ctx, surfaceSize, m_scale);
+    m_renderer.beginFrame(ctx, surfaceSize, m_scale, m_opacity);
   }
 
 
diff --git a/src/dxvk/hud/dxvk_hud.h b/src/dxvk/hud/dxvk_hud.h
index 8efc8774b..7599dea8e 100644
--- a/src/dxvk/hud/dxvk_hud.h
+++ b/src/dxvk/hud/dxvk_hud.h
@@ -84,6 +84,7 @@ namespace dxvk::hud {
     HudItemSet            m_hudItems;
 
     float                 m_scale;
+    float                 m_opacity;
 
     void setupRendererState(
       const Rc<DxvkContext>&  ctx,
diff --git a/src/dxvk/hud/dxvk_hud_renderer.cpp b/src/dxvk/hud/dxvk_hud_renderer.cpp
index f7a7bcd13..630706e0f 100644
--- a/src/dxvk/hud/dxvk_hud_renderer.cpp
+++ b/src/dxvk/hud/dxvk_hud_renderer.cpp
@@ -32,12 +32,17 @@ namespace dxvk::hud {
   }
   
   
-  void HudRenderer::beginFrame(const Rc<DxvkContext>& context, VkExtent2D surfaceSize, float scale) {
+  void HudRenderer::beginFrame(
+          const Rc<DxvkContext>& context, 
+          VkExtent2D surfaceSize, 
+          float scale, 
+          float opacity) {
     if (!m_initialized)
       this->initFontTexture(context);
 
     m_mode        = Mode::RenderNone;
     m_scale       = scale;
+    m_opacity     = opacity;
     m_surfaceSize = surfaceSize;
     m_context     = context;
   }
@@ -61,6 +66,10 @@ namespace dxvk::hud {
     VkDeviceSize offset = allocDataBuffer(textCopy.size());
     std::memcpy(m_dataBuffer->mapPtr(offset), textCopy.data(), textCopy.size());
 
+    // Enforce HUD opacity factor on alpha
+    if (m_opacity != 1.0f)
+      color.a *= m_opacity;
+
     // Fill in push constants for the next draw
     HudTextPushConstants pushData;
     pushData.color = color;
@@ -95,6 +104,7 @@ namespace dxvk::hud {
     pushData.size = size;
     pushData.scale.x = m_scale / std::max(float(m_surfaceSize.width),  1.0f);
     pushData.scale.y = m_scale / std::max(float(m_surfaceSize.height), 1.0f);
+    pushData.opacity = m_opacity;
 
     m_context->pushConstants(0, sizeof(pushData), &pushData);
     m_context->draw(4, 1, 0, 0);
diff --git a/src/dxvk/hud/dxvk_hud_renderer.h b/src/dxvk/hud/dxvk_hud_renderer.h
index dcea3197c..bcfb67543 100644
--- a/src/dxvk/hud/dxvk_hud_renderer.h
+++ b/src/dxvk/hud/dxvk_hud_renderer.h
@@ -67,6 +67,7 @@ namespace dxvk::hud {
     HudPos pos;
     HudPos size;
     HudPos scale;
+    float  opacity;
   };
 
   /**
@@ -106,7 +107,8 @@ namespace dxvk::hud {
     void beginFrame(
       const Rc<DxvkContext>&  context,
             VkExtent2D        surfaceSize,
-            float             scale);
+            float             scale,
+            float             opacity);
     
     void drawText(
             float             size,
@@ -143,6 +145,7 @@ namespace dxvk::hud {
     
     Mode                m_mode;
     float               m_scale;
+    float               m_opacity;
     VkExtent2D          m_surfaceSize;
 
     Rc<DxvkDevice>      m_device;
diff --git a/src/dxvk/hud/shaders/hud_graph_frag.frag b/src/dxvk/hud/shaders/hud_graph_frag.frag
index 6b1a22efb..e555d7334 100644
--- a/src/dxvk/hud/shaders/hud_graph_frag.frag
+++ b/src/dxvk/hud/shaders/hud_graph_frag.frag
@@ -24,6 +24,7 @@ uniform push_data_t {
   vec2 pos;
   vec2 size;
   vec2 scale;
+  float opacity;
 };
 
 void main() {
@@ -47,7 +48,7 @@ void main() {
   o_color = mix(
     unpackUnorm4x8(p0.color),
     unpackUnorm4x8(p1.color), fx);
-  o_color *= alpha;
+  o_color *= alpha * opacity;
 
   o_color.rgb = encodeOutput(o_color.rgb);
 }
diff --git a/src/dxvk/hud/shaders/hud_graph_vert.vert b/src/dxvk/hud/shaders/hud_graph_vert.vert
index 884dc3187..44f3e83ca 100644
--- a/src/dxvk/hud/shaders/hud_graph_vert.vert
+++ b/src/dxvk/hud/shaders/hud_graph_vert.vert
@@ -9,6 +9,7 @@ uniform push_data_t {
   vec2 pos;
   vec2 size;
   vec2 scale;
+  float opacity;
 };
 
 void main() {