diff --git a/src/OpenColorIO/GpuShaderUtils.cpp b/src/OpenColorIO/GpuShaderUtils.cpp index 3f8e158e4..07e41059b 100644 --- a/src/OpenColorIO/GpuShaderUtils.cpp +++ b/src/OpenColorIO/GpuShaderUtils.cpp @@ -404,6 +404,17 @@ std::string GpuShaderText::intKeyword() const return "int"; } +std::string GpuShaderText::intCast(const std::string & expr) const +{ + // HLSL/DXC flags the functional cast int(x) under -Wfloat-conversion; a C-style cast suppresses it (GLSL forbids C-style casts). + if (m_lang == GPU_LANGUAGE_HLSL_SM_5_0) + { + return "(int)(" + expr + ")"; + } + + return intKeyword() + "(" + expr + ")"; +} + std::string GpuShaderText::intKeywordConst() const { std::string str; diff --git a/src/OpenColorIO/GpuShaderUtils.h b/src/OpenColorIO/GpuShaderUtils.h index 0b081acba..de9f9c149 100644 --- a/src/OpenColorIO/GpuShaderUtils.h +++ b/src/OpenColorIO/GpuShaderUtils.h @@ -76,6 +76,8 @@ class GpuShaderText std::string intKeyword() const; std::string intKeywordConst() const; std::string intDecl(const std::string& name) const; + // Cast a float expression to int using language-appropriate syntax. + std::string intCast(const std::string& expr) const; std::string colorDecl(const std::string& name) const; diff --git a/src/OpenColorIO/ops/fixedfunction/FixedFunctionOpGPU.cpp b/src/OpenColorIO/ops/fixedfunction/FixedFunctionOpGPU.cpp index 59ab7121c..763bbb955 100644 --- a/src/OpenColorIO/ops/fixedfunction/FixedFunctionOpGPU.cpp +++ b/src/OpenColorIO/ops/fixedfunction/FixedFunctionOpGPU.cpp @@ -40,7 +40,7 @@ void Add_hue_weight_shader(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText // << " hue = mix( hue, hue - 6.28318530717959, step( 3.14159265358979, hue));\n" ss.newLine() << ss.floatDecl("knot_coord") << " = clamp(2. + hue * float(" << inv_width << "), 0., 4.);"; - ss.newLine() << "int j = int(min(knot_coord, 3.));"; + ss.newLine() << "int j = " << ss.intCast("min(knot_coord, 3.)") << ";"; ss.newLine() << ss.floatDecl("t") << " = knot_coord - float(j);"; ss.newLine() << ss.float4Decl("monomials") << " = " << ss.float4Const("t*t*t", "t*t", "t", "1.") << ";"; ss.newLine() << ss.float4Decl("m0") << " = " << ss.float4Const(0.25, 0.00, 0.00, 0.00) << ";"; @@ -867,14 +867,14 @@ std::string _Add_Cusp_table( ss.newLine() << "{"; ss.indent(); - ss.newLine() << ss.intDecl("i") << " = " << ss.intKeyword() << "(h) + " << g.gamut_cusp_table.base_index << ";"; + ss.newLine() << ss.intDecl("i") << " = " << ss.intCast("h") << " + " << g.gamut_cusp_table.base_index << ";"; - ss.newLine() << ss.intDecl("i_lo") << " = " << ss.intKeyword() << "(max(" - << ss.floatKeyword() << "(" << g.gamut_cusp_table.lower_wrap_index << "), " - << ss.floatKeyword() << "(i + " << g.hue_linearity_search_range[0] << ")));"; - ss.newLine() << ss.intDecl("i_hi") << " = " << ss.intKeyword() << "(min(" - << ss.floatKeyword() << "(" << g.gamut_cusp_table.upper_wrap_index << "), " - << ss.floatKeyword() << "(i + " << g.hue_linearity_search_range[1] << ")));"; + ss.newLine() << ss.intDecl("i_lo") << " = " << ss.intCast( + "max(" + ss.floatKeyword() + "(" + std::to_string(g.gamut_cusp_table.lower_wrap_index) + "), " + + ss.floatKeyword() + "(i + " + std::to_string(g.hue_linearity_search_range[0]) + "))") << ";"; + ss.newLine() << ss.intDecl("i_hi") << " = " << ss.intCast( + "min(" + ss.floatKeyword() + "(" + std::to_string(g.gamut_cusp_table.upper_wrap_index) + "), " + + ss.floatKeyword() + "(i + " + std::to_string(g.hue_linearity_search_range[1]) + "))") << ";"; ss.newLine() << "while (i_lo + 1 < i_hi)"; ss.newLine() << "{"; @@ -1583,8 +1583,7 @@ void Add_Gamut_Compress_Fwd_Shader( const std::string reachName = _Add_Reach_table(shaderCreator, resourceIndex, s.reach_m_table); _Add_WrapHueChannel_Shader(shaderCreator, ss); - _Add_SinCos_Shader(shaderCreator, ss); - + // No _Add_SinCos_Shader: gamut-compress stays in JMh space, so cos_hr/sin_hr would be unused. ss.newLine() << ss.floatDecl("reachMaxM") << " = " << reachName << "_sample(" << pxl << ".b);"; _Add_Gamut_Compress_Fwd_Shader(shaderCreator, ss, resourceIndex, s, g); @@ -1626,8 +1625,7 @@ void Add_Gamut_Compress_Inv_Shader( const std::string reachName = _Add_Reach_table(shaderCreator, resourceIndex, s.reach_m_table); _Add_WrapHueChannel_Shader(shaderCreator, ss); - _Add_SinCos_Shader(shaderCreator, ss); - + // No _Add_SinCos_Shader: gamut-compress stays in JMh space, so cos_hr/sin_hr would be unused. ss.newLine() << ss.floatDecl("reachMaxM") << " = " << reachName << "_sample(" << pxl << ".b);"; _Add_Gamut_Compress_Inv_Shader(shaderCreator, ss, resourceIndex, s, g); diff --git a/src/OpenColorIO/ops/gradingrgbcurve/GradingBSplineCurve.cpp b/src/OpenColorIO/ops/gradingrgbcurve/GradingBSplineCurve.cpp index d04611165..a1fb37f1e 100644 --- a/src/OpenColorIO/ops/gradingrgbcurve/GradingBSplineCurve.cpp +++ b/src/OpenColorIO/ops/gradingrgbcurve/GradingBSplineCurve.cpp @@ -1190,6 +1190,8 @@ void GradingBSplineCurveImpl::AddShaderEvalRevHue(GpuShaderText & st, st.newLine() << "float knStart = " << knots << "[knotsOffs];"; st.newLine() << "float knEnd = " << knots << "[knotsOffs + knotsCnt - 1];"; st.newLine() << "float knStartY = " << coefs << "[coefsOffs + coefsSets * 2];"; + // HUE-FX (curve 7): offset start Y bound by its knot, matching CPU evalRevHue. + st.newLine() << "knStartY = (curveIdx == 7) ? knStartY + knStart : knStartY;"; st.newLine() << "float knEndY;"; st.newLine() << "{"; st.newLine() << " float A = " << coefs << "[coefsOffs + coefsSets - 1];"; @@ -1198,7 +1200,6 @@ void GradingBSplineCurveImpl::AddShaderEvalRevHue(GpuShaderText & st, st.newLine() << " float kn = " << knots << "[knotsOffs + knotsCnt - 2];"; st.newLine() << " float t = knEnd - kn;"; st.newLine() << " knEndY = ( A * t + B ) * t + C;"; - // The HUE-FX curve is index 7 and requires special handling. st.newLine() << " knEndY = (curveIdx == 7) ? knEndY + knEnd : knEndY;"; st.newLine() << "}"; diff --git a/src/OpenColorIO/ops/gradingrgbcurve/GradingRGBCurveOpGPU.cpp b/src/OpenColorIO/ops/gradingrgbcurve/GradingRGBCurveOpGPU.cpp index e2ae5d7b8..628ed4686 100644 --- a/src/OpenColorIO/ops/gradingrgbcurve/GradingRGBCurveOpGPU.cpp +++ b/src/OpenColorIO/ops/gradingrgbcurve/GradingRGBCurveOpGPU.cpp @@ -231,17 +231,22 @@ void AddCurveEvalMethodTextToShaderProgram(GpuShaderCreatorRcPtr & shaderCreator } st.newLine() << ""; - if (shaderCreator->getLanguage() == LANGUAGE_OSL_1 || shaderCreator->getLanguage() == GPU_LANGUAGE_MSL_2_0) + const bool inverse = gcData->getDirection() == TRANSFORM_DIR_INVERSE; + const bool noInQualifier = shaderCreator->getLanguage() == LANGUAGE_OSL_1 || + shaderCreator->getLanguage() == GPU_LANGUAGE_MSL_2_0; + const std::string in = noInQualifier ? "" : "in "; + // The inverse eval omits identity_x (returns the input when there is no curve), matching the CPU evalCurveRev signature. + if (inverse) { - st.newLine() << st.floatKeyword() << " " << props.m_eval << "(int curveIdx, float x, float identity_x)"; + st.newLine() << st.floatKeyword() << " " << props.m_eval << "(" << in << "int curveIdx, " << in << "float x)"; } else { - st.newLine() << st.floatKeyword() << " " << props.m_eval << "(in int curveIdx, in float x, in float identity_x)"; + st.newLine() << st.floatKeyword() << " " << props.m_eval << "(" << in << "int curveIdx, " << in << "float x, " << in << "float identity_x)"; } st.newLine() << "{"; st.indent(); - if (gcData->getDirection() == TRANSFORM_DIR_INVERSE) + if (inverse) { GradingBSplineCurveImpl::AddShaderEvalRev(st, props.m_knotsOffsets, props.m_coefsOffsets, props.m_knots, props.m_coefs); @@ -331,13 +336,13 @@ void AddGCInverseShader(GpuShaderCreatorRcPtr & shaderCreator, const std::string pix(shaderCreator->getPixelName()); - // Call the curve evaluation method for each curve. - st.newLine() << pix << ".rgb.r = " << props.m_eval << "(3, " << pix << ".rgb.r, " << pix << ".rgb.r);"; // MASTER - st.newLine() << pix << ".rgb.g = " << props.m_eval << "(3, " << pix << ".rgb.g, " << pix << ".rgb.g);"; // MASTER - st.newLine() << pix << ".rgb.b = " << props.m_eval << "(3, " << pix << ".rgb.b, " << pix << ".rgb.b);"; // MASTER - st.newLine() << pix << ".rgb.r = " << props.m_eval << "(0, " << pix << ".rgb.r, " << pix << ".rgb.r);"; // RED - st.newLine() << pix << ".rgb.g = " << props.m_eval << "(1, " << pix << ".rgb.g, " << pix << ".rgb.g);"; // GREEN - st.newLine() << pix << ".rgb.b = " << props.m_eval << "(2, " << pix << ".rgb.b, " << pix << ".rgb.b);"; // BLUE + // Call the curve evaluation method for each curve (inverse eval takes no identity_x). + st.newLine() << pix << ".rgb.r = " << props.m_eval << "(3, " << pix << ".rgb.r);"; // MASTER + st.newLine() << pix << ".rgb.g = " << props.m_eval << "(3, " << pix << ".rgb.g);"; // MASTER + st.newLine() << pix << ".rgb.b = " << props.m_eval << "(3, " << pix << ".rgb.b);"; // MASTER + st.newLine() << pix << ".rgb.r = " << props.m_eval << "(0, " << pix << ".rgb.r);"; // RED + st.newLine() << pix << ".rgb.g = " << props.m_eval << "(1, " << pix << ".rgb.g);"; // GREEN + st.newLine() << pix << ".rgb.b = " << props.m_eval << "(2, " << pix << ".rgb.b);"; // BLUE if (doLinToLog) { diff --git a/src/libutils/oglapphelpers/dxapp.cpp b/src/libutils/oglapphelpers/dxapp.cpp index 57fd1f1f0..9a13f065e 100644 --- a/src/libutils/oglapphelpers/dxapp.cpp +++ b/src/libutils/oglapphelpers/dxapp.cpp @@ -568,10 +568,17 @@ void DxApp::setShader(GpuShaderDescRcPtr& shaderDesc) sourceBuffer.Size = sourceBlob->GetBufferSize(); sourceBuffer.Encoding = DXC_CP_UTF8; - // Compile pixel shader (ps_6_0). - LPCWSTR psArgs[] = { L"-T", L"ps_6_0", L"-E", L"PSMain" }; + // Compile pixel shader (ps_6_0). Opt-in: surface useful DXC warnings on the generated HLSL when verbose. + std::vector psArgs = { L"-T", L"ps_6_0", L"-E", L"PSMain" }; + if (isShaderVerbose()) + { + psArgs.push_back(L"-Wall"); + psArgs.push_back(L"-Wextra"); + psArgs.push_back(L"-Wconversion"); + } ComPtr psResult; - ThrowIfFailed(m_dxcCompiler->Compile(&sourceBuffer, psArgs, _countof(psArgs), + ThrowIfFailed(m_dxcCompiler->Compile(&sourceBuffer, psArgs.data(), + static_cast(psArgs.size()), nullptr, IID_PPV_ARGS(&psResult))); HRESULT psHr; psResult->GetStatus(&psHr); @@ -586,6 +593,17 @@ void DxApp::setShader(GpuShaderDescRcPtr& shaderDesc) std::cerr << oss.str() << std::endl; throw Exception(oss.str().c_str()); } + // Opt-in: surface DXC warnings (carried on the ERRORS output even on success) when verbose. + if (isShaderVerbose()) + { + ComPtr psWarnings; + psResult->GetOutput(DXC_OUT_ERRORS, IID_PPV_ARGS(&psWarnings), nullptr); + if (psWarnings && psWarnings->GetStringLength()) + { + std::cerr << "[DXC-WARN] pixel shader '" << shaderDesc->getFunctionName() + << "':\n" << psWarnings->GetStringPointer() << std::endl; + } + } ComPtr pixelShaderBlob; ThrowIfFailed(psResult->GetOutput(DXC_OUT_OBJECT, IID_PPV_ARGS(&pixelShaderBlob), nullptr));