commit bc4d0fec4f791fb198ff316849aaf3faba24b45a
Author: Gaspard Thevenon <gaspard.thevenon@kitware.com>
Date:   Thu Feb 10 10:19:39 2022 +0100

    Fix shader crash in Multi Volume Rendering without GradientTF
    
    When using OpenGLGPUVolumeRayCastMapper with a MultiVolume,
    not specifying a gradient opacity TF produced an error in
    the composed shader (no argument would be given to functions which expected one),
    and nothing was rendered, although this TF is supposed to be optional.
    
    This commit fixes this by adding tests during the declarations of
    those functions inside the shader, and by changing their signatures as needed.
    Therefore, when no gradient opacity TF is given, no argument is expected
    and none is given.

diff --git a/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx b/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx
index cdcec460ef..dfc65de04b 100644
--- a/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx
+++ b/Rendering/VolumeOpenGL2/vtkOpenGLGPUVolumeRayCastMapper.cxx
@@ -2415,7 +2415,8 @@ void vtkOpenGLGPUVolumeRayCastMapper::ReplaceShaderCompute(
       vtkvolume::ComputeGradientOpacityMulti1DDecl(this->AssembledInputs));
 
     vtkShaderProgram::Substitute(fragmentShader, "//VTK::ComputeColor::Dec",
-      vtkvolume::ComputeColorMultiDeclaration(this->AssembledInputs));
+      vtkvolume::ComputeColorMultiDeclaration(
+        this->AssembledInputs, vol->GetProperty()->HasGradientOpacity()));
 
     vtkShaderProgram::Substitute(fragmentShader, "//VTK::ComputeLighting::Dec",
       vtkvolume::ComputeLightingMultiDeclaration(ren, this, vol, numComps, independentComponents,
@@ -2970,6 +2971,23 @@ bool vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::UpdateInputs(vtkRenderer* ren
     this->ForceTransferInit();
   }
 
+  if (this->MultiVolume)
+  {
+    bool hasGradient = this->Parent->AssembledInputs[0].Volume->GetProperty()->HasGradientOpacity();
+    for (auto& item : this->Parent->AssembledInputs)
+    {
+      if (item.second.Volume->GetProperty()->HasGradientOpacity() != hasGradient)
+      {
+        vtkGenericWarningMacro(
+          "Current implentation of vtkOpenGLGPUVolumeRayCastMapper does not support MultiVolume "
+          "where some volumes have a gradient opacity function and some others don't. "
+          "Rendering of the MultiVolume is disabled.");
+        success = false;
+        break;
+      }
+    }
+  }
+
   return success;
 }
 
@@ -3106,7 +3124,10 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, vtkVolume* vol
   this->Impl->MultiVolume = multiVol && this->GetInputCount() > 1 ? multiVol : nullptr;
 
   this->Impl->ClearRemovedInputs(renWin);
-  this->Impl->UpdateInputs(ren, vol);
+  if (!this->Impl->UpdateInputs(ren, vol))
+  {
+    return;
+  }
   this->Impl->UpdateSamplingDistance(ren);
   this->Impl->UpdateTransfer2DYAxisArray(ren, vol);
   this->Impl->UpdateTransferFunctions(ren);
diff --git a/Rendering/VolumeOpenGL2/vtkVolumeShaderComposer.h b/Rendering/VolumeOpenGL2/vtkVolumeShaderComposer.h
index 766f36ab63..3406bfb431 100644
--- a/Rendering/VolumeOpenGL2/vtkVolumeShaderComposer.h
+++ b/Rendering/VolumeOpenGL2/vtkVolumeShaderComposer.h
@@ -1054,10 +1054,24 @@ std::string ComputeLightingMultiDeclaration(vtkRenderer* vtkNotUsed(ren), vtkVol
   int lightingComplexity)
 {
   vtkVolumeProperty* volProperty = vol->GetProperty();
-  std::string shaderStr = std::string("\
+
+  std::string shaderStr = std::string();
+
+  // if no gradient TF is needed, don't add it into the function signature
+  if (volProperty->HasGradientOpacity())
+  {
+    shaderStr += std::string("\
       \nvec4 computeLighting(vec3 texPos, vec4 color, const in sampler2D gradientTF, const in sampler3D volume, const int volIdx, int component)\
       \n  {\
       \n  vec4 finalColor = vec4(0.0);");
+  }
+  else
+  {
+    shaderStr += std::string("\
+      \nvec4 computeLighting(vec3 texPos, vec4 color, const in sampler3D volume, const int volIdx, int component)\
+      \n  {\
+      \n  vec4 finalColor = vec4(0.0);");
+  }
 
   // Shading for composite blending only
   int const shadeReqd = volProperty->GetShade() &&
@@ -1243,7 +1257,8 @@ std::string ComputeColorDeclaration(vtkRenderer* vtkNotUsed(ren),
 }
 
 //--------------------------------------------------------------------------
-std::string ComputeColorMultiDeclaration(vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs)
+std::string ComputeColorMultiDeclaration(
+  vtkOpenGLGPUVolumeRayCastMapper::VolumeInputMap& inputs, bool useGradientTF)
 {
   std::ostringstream ss;
   int i = 0;
@@ -1274,13 +1289,28 @@ std::string ComputeColorMultiDeclaration(vtkOpenGLGPUVolumeRayCastMapper::Volume
   }
   else
   {
-    ss << "vec4 computeColor(vec3 texPos, vec4 scalar, float opacity, const in sampler2D colorTF, "
-          "const in sampler2D gradientTF, const in sampler3D volume, const int volIdx)\n"
-          "{\n"
-          "  return clamp(computeLighting(texPos, vec4(texture2D(colorTF,\n"
-          "                         vec2(scalar.w, 0.0)).xyz, opacity), gradientTF, volume, "
-          "volIdx, 0), 0.0, 1.0);\n"
-          "}\n";
+    if (useGradientTF)
+    {
+      ss
+        << "vec4 computeColor(vec3 texPos, vec4 scalar, float opacity, const in sampler2D colorTF, "
+           "const in sampler2D gradientTF, const in sampler3D volume, const int volIdx)\n"
+           "{\n"
+           "  return clamp(computeLighting(texPos, vec4(texture2D(colorTF,\n"
+           "                         vec2(scalar.w, 0.0)).xyz, opacity), gradientTF, volume, "
+           "volIdx, 0), 0.0, 1.0);\n"
+           "}\n";
+    }
+    else
+    {
+      ss
+        << "vec4 computeColor(vec3 texPos, vec4 scalar, float opacity, const in sampler2D colorTF, "
+           "const in sampler3D volume, const int volIdx)\n"
+           "{\n"
+           "  return clamp(computeLighting(texPos, vec4(texture2D(colorTF,\n"
+           "                         vec2(scalar.w, 0.0)).xyz, opacity), volume, "
+           "volIdx, 0), 0.0, 1.0);\n"
+           "}\n";
+    }
   }
 
   return ss.str();
@@ -1828,14 +1858,18 @@ std::string ShadingMultipleInputs(
 
         if (property->GetTransferFunctionMode() == vtkVolumeProperty::TF_1D)
         {
+          std::string gradientopacity_param = (property->HasGradientOpacity())
+            ? input.GradientOpacityTablesMap[0] + std::string(", ")
+            : std::string();
+
           toShaderStr << "        g_srcColor.a = computeOpacity(scalar,"
                       << input.OpacityTablesMap[0]
                       << ");\n"
                          "        if (g_srcColor.a > 0.0)\n"
                          "        {\n"
                          "          g_srcColor = computeColor(texPos, scalar, g_srcColor.a, "
-                      << input.RGBTablesMap[0] << ", " << input.GradientOpacityTablesMap[0] << ", "
-                      << "in_volume[" << i << "], " << i << ");\n";
+                      << input.RGBTablesMap[0] << ", " << gradientopacity_param << "in_volume[" << i
+                      << "], " << i << ");\n";
 
           if (property->HasGradientOpacity())
           {
