Coverage Report

Created: 2025-11-11 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/Components/RTShaderSystem/src/OgreShaderExIntegratedPSSM3.cpp
Line
Count
Source
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
(Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org/
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
#include "OgreShaderPrecompiledHeaders.h"
29
#ifdef RTSHADER_SYSTEM_BUILD_EXT_SHADERS
30
31
0
#define SGX_LIB_INTEGRATEDPSSM                      "SGXLib_IntegratedPSSM"
32
33
namespace Ogre {
34
namespace RTShader {
35
36
/************************************************************************/
37
/*                                                                      */
38
/************************************************************************/
39
String IntegratedPSSM3::Type = "SGX_IntegratedPSSM3";
40
const String SRS_INTEGRATED_PSSM3 = "SGX_IntegratedPSSM3";
41
const String SRS_SHADOW_MAPPING = "SGX_IntegratedPSSM3";
42
43
//-----------------------------------------------------------------------
44
IntegratedPSSM3::IntegratedPSSM3()
45
0
{
46
0
    mPCFxSamples = 2;
47
0
    mUseTextureCompare = false;
48
0
    mUseColourShadows = false;
49
0
    mDebug = false;
50
0
    mIsD3D9 = false;
51
0
    mUseArrayTexture = false;
52
0
    mShadowTextureParamsList.resize(1); // normal single texture depth shadowmapping
53
0
    mMultiLightCount = 1;
54
0
}
55
56
//-----------------------------------------------------------------------
57
int IntegratedPSSM3::getExecutionOrder() const
58
0
{
59
0
    return FFP_LIGHTING - 1;
60
0
}
61
62
//-----------------------------------------------------------------------
63
void IntegratedPSSM3::updateGpuProgramsParams(Renderable* rend, const Pass* pass,
64
                                             const AutoParamDataSource* source,
65
                                             const LightList* pLightList)
66
0
{
67
0
    if (mMultiLightCount > 1)
68
0
        return;
69
70
0
    Vector4 vSplitPoints;
71
72
0
    for(size_t i = 0; i < mShadowTextureParamsList.size() - 1; i++)
73
0
    {
74
0
        vSplitPoints[i] = mShadowTextureParamsList[i].mMaxRange;
75
0
    }
76
0
    vSplitPoints[3] = mShadowTextureParamsList.back().mMaxRange;
77
78
0
    const Matrix4& proj = source->getProjectionMatrix();
79
80
0
    for(int i = 0; i < 4; i++)
81
0
    {
82
0
        auto tmp = proj * Vector4(0, 0, -vSplitPoints[i], 1);
83
0
        vSplitPoints[i] = tmp[2] / tmp[3];
84
0
    }
85
86
87
0
    mPSSplitPoints->setGpuParameter(vSplitPoints);
88
89
0
}
90
91
//-----------------------------------------------------------------------
92
void IntegratedPSSM3::copyFrom(const SubRenderState& rhs)
93
0
{
94
0
    const IntegratedPSSM3& rhsPssm= static_cast<const IntegratedPSSM3&>(rhs);
95
96
0
    mPCFxSamples = rhsPssm.mPCFxSamples;
97
0
    mUseTextureCompare = rhsPssm.mUseTextureCompare;
98
0
    mUseColourShadows = rhsPssm.mUseColourShadows;
99
0
    mDebug = rhsPssm.mDebug;
100
0
    mMultiLightCount = rhsPssm.mMultiLightCount;
101
0
    mUseArrayTexture = rhsPssm.mUseArrayTexture;
102
0
    mShadowTextureParamsList.resize(rhsPssm.mShadowTextureParamsList.size());
103
104
0
    ShadowTextureParamsConstIterator itSrc = rhsPssm.mShadowTextureParamsList.begin();
105
0
    for (auto& p : mShadowTextureParamsList)
106
0
    {
107
0
        p.mMaxRange = itSrc->mMaxRange;
108
0
        ++itSrc;
109
0
    }
110
0
}
111
112
//-----------------------------------------------------------------------
113
bool IntegratedPSSM3::preAddToRenderState(const RenderState* renderState,
114
                                         Pass* srcPass, Pass* dstPass)
115
0
{
116
0
    if (!srcPass->getParent()->getParent()->getReceiveShadows() ||
117
0
        renderState->getLightCount() == 0)
118
0
        return false;
119
120
0
    mIsD3D9 = ShaderGenerator::getSingleton().getTargetLanguage() == "hlsl" &&
121
0
              !GpuProgramManager::getSingleton().isSyntaxSupported("vs_4_0_level_9_1");
122
123
0
    PixelFormat shadowTexFormat = PF_UNKNOWN;
124
0
    const auto& configs = ShaderGenerator::getSingleton().getActiveSceneManager()->getShadowTextureConfigList();
125
0
    if (!configs.empty())
126
0
        shadowTexFormat = configs[0].format; // assume first texture is representative
127
0
    mUseTextureCompare = PixelUtil::isDepth(shadowTexFormat) && !mIsD3D9;
128
0
    mUseColourShadows = PixelUtil::getComponentType(shadowTexFormat) == PCT_BYTE; // use colour shadowmaps for byte textures
129
130
0
    if(mMultiLightCount > 1)
131
0
        mShadowTextureParamsList.resize(mMultiLightCount);
132
133
0
    auto shadowSampler = TextureManager::getSingleton().getSampler(mUseTextureCompare ? "Ogre/DepthShadowSampler"
134
0
                                                                                      : "Ogre/ShadowSampler");
135
0
    for (auto& p : mShadowTextureParamsList)
136
0
    {
137
0
        TextureUnitState* curShadowTexture = dstPass->createTextureUnitState();
138
0
        curShadowTexture->setContentType(TextureUnitState::CONTENT_SHADOW);
139
0
        curShadowTexture->setSampler(shadowSampler);
140
0
        p.mTextureSamplerIndex = dstPass->getNumTextureUnitStates() - 1;
141
0
    }
142
143
0
    return true;
144
0
}
145
146
//-----------------------------------------------------------------------
147
void IntegratedPSSM3::setSplitPoints(const SplitPointList& newSplitPoints)
148
0
{
149
0
    OgreAssert(newSplitPoints.size() <= 5, "at most 5 split points are supported");
150
151
0
    mShadowTextureParamsList.resize(newSplitPoints.size() - 1);
152
153
0
    for (size_t i = 1; i < newSplitPoints.size(); ++i)
154
0
    {
155
0
        mShadowTextureParamsList[i - 1].mMaxRange = newSplitPoints[i];
156
0
    }
157
0
}
158
159
bool IntegratedPSSM3::setParameter(const String& name, const String& value)
160
0
{
161
0
    if(name == "debug")
162
0
    {
163
0
        return StringConverter::parse(value, mDebug);
164
0
    }
165
0
    else if (name == "filter")
166
0
    {
167
0
        if(value == "pcf4")
168
0
            mPCFxSamples = 2;
169
0
        else if(value == "pcf16")
170
0
            mPCFxSamples = 4;
171
0
        else
172
0
            return false;
173
174
0
        return true;
175
0
    }
176
0
    else if (name == "light_count")
177
0
    {
178
0
        mMultiLightCount = StringConverter::parseInt(value);
179
0
        return true;
180
0
    }
181
0
    else if (name == "array_texture")
182
0
    {
183
0
        return StringConverter::parse(value, mUseArrayTexture);
184
0
    }
185
186
0
    return false;
187
0
}
188
189
void IntegratedPSSM3::setParameter(const String& name, const Any& value)
190
0
{
191
0
    if(name == "split_points")
192
0
    {
193
0
        setSplitPoints(any_cast<SplitPointList>(value));
194
0
        return;
195
0
    }
196
0
    else if (name == "debug")
197
0
    {
198
0
        mDebug = any_cast<bool>(value);
199
0
        return;
200
0
    }
201
0
    else if (name == "array_texture")
202
0
    {
203
0
        mUseArrayTexture = any_cast<bool>(value);
204
0
        return;
205
0
    }
206
207
0
    SubRenderState::setParameter(name, value);
208
0
}
209
210
//-----------------------------------------------------------------------
211
bool IntegratedPSSM3::resolveParameters(ProgramSet* programSet)
212
0
{
213
0
    Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM);
214
0
    Program* psProgram = programSet->getCpuProgram(GPT_FRAGMENT_PROGRAM);
215
0
    Function* vsMain = vsProgram->getEntryPointFunction();
216
0
    Function* psMain = psProgram->getEntryPointFunction();
217
218
    // Get input position parameter.
219
0
    mVSInPos = vsMain->getLocalParameter(Parameter::SPC_POSITION_OBJECT_SPACE);
220
0
    if(!mVSInPos)
221
0
        mVSInPos = vsMain->getInputParameter(Parameter::SPC_POSITION_OBJECT_SPACE);
222
223
    // Get output position parameter.
224
0
    mVSOutPos = vsMain->getOutputParameter(Parameter::SPC_POSITION_PROJECTIVE_SPACE);
225
226
0
    if (mIsD3D9)
227
0
    {
228
0
        mVSOutPos = vsMain->resolveOutputParameter(Parameter::SPC_UNKNOWN, GCT_FLOAT4);
229
0
    }
230
231
    // Resolve input depth parameter.
232
0
    mPSInDepth = psMain->resolveInputParameter(mVSOutPos);
233
234
    // Resolve computed local shadow colour parameter.
235
0
    mPSLocalShadowFactor = psMain->resolveLocalParameter(GCT_FLOAT1, "lShadowFactor", mMultiLightCount);
236
237
    // Resolve computed local shadow colour parameter.
238
0
    mPSSplitPoints = psProgram->resolveParameter(GCT_FLOAT4, "pssm_split_points");
239
240
0
    int lightIndex = 0;
241
242
0
    auto stype = GCT_SAMPLER2D;
243
0
    if(mUseTextureCompare)
244
0
    {
245
0
        stype = mUseArrayTexture ? GCT_SAMPLER2DARRAYSHADOW : GCT_SAMPLER2DSHADOW;
246
0
    }
247
0
    else {
248
0
        stype = mUseArrayTexture ? GCT_SAMPLER2DARRAY : GCT_SAMPLER2D;
249
0
    }
250
251
0
    mWorldViewProjMatrices = vsProgram->resolveParameter(GpuProgramParameters::ACT_TEXTURE_WORLDVIEWPROJ_MATRIX_ARRAY,
252
0
                                                         mShadowTextureParamsList.size());
253
0
    for (auto& p : mShadowTextureParamsList)
254
0
    {
255
0
        p.mVSOutLightPosition = vsMain->resolveOutputParameter(Parameter::SPC_POSITION_LIGHT_SPACE0 + lightIndex);
256
0
        p.mPSInLightPosition = psMain->resolveInputParameter(p.mVSOutLightPosition);
257
0
        if(mUseArrayTexture)
258
0
            p.mTextureSamplerIndex = mShadowTextureParamsList[0].mTextureSamplerIndex;
259
0
        p.mTextureSampler = psProgram->resolveParameter(stype, "shadow_map", p.mTextureSamplerIndex);
260
0
        p.mInvTextureSize = psProgram->resolveParameter(GpuProgramParameters::ACT_INVERSE_TEXTURE_SIZE, p.mTextureSamplerIndex);
261
0
        ++lightIndex;
262
0
    }
263
264
0
    if (!(mVSInPos.get()) || !(mVSOutPos.get()))
265
0
    {
266
0
        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Not all parameters could be constructed for the sub-render state.");
267
0
    }
268
269
0
    return true;
270
0
}
271
272
//-----------------------------------------------------------------------
273
bool IntegratedPSSM3::resolveDependencies(ProgramSet* programSet)
274
0
{
275
0
    Program* psProgram = programSet->getCpuProgram(GPT_FRAGMENT_PROGRAM);
276
0
    psProgram->addDependency(SGX_LIB_INTEGRATEDPSSM);
277
278
0
    psProgram->addPreprocessorDefines(StringUtil::format("PSSM_NUM_SPLITS=%zu,PCF_XSAMPLES=%.1f,SHADOWLIGHT_COUNT=%d",
279
0
                                                         mShadowTextureParamsList.size(), mPCFxSamples, mMultiLightCount));
280
281
0
    if(mDebug)
282
0
        psProgram->addPreprocessorDefines("DEBUG_PSSM");
283
284
0
    if(mUseTextureCompare)
285
0
        psProgram->addPreprocessorDefines("PSSM_SAMPLE_CMP");
286
287
0
    if(mUseColourShadows)
288
0
        psProgram->addPreprocessorDefines("PSSM_SAMPLE_COLOUR");
289
290
0
    if(mUseArrayTexture)
291
0
        psProgram->addPreprocessorDefines("PSSM_ARRAY_TEXTURE");
292
293
0
    return true;
294
0
}
295
296
//-----------------------------------------------------------------------
297
bool IntegratedPSSM3::addFunctionInvocations(ProgramSet* programSet)
298
0
{
299
0
    Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM);
300
0
    Function* vsMain = vsProgram->getEntryPointFunction();
301
0
    Program* psProgram = programSet->getCpuProgram(GPT_FRAGMENT_PROGRAM);
302
303
    // Add vertex shader invocations.
304
0
    if (false == addVSInvocation(vsMain, FFP_VS_TEXTURING + 1))
305
0
        return false;
306
307
    // Add pixel shader invocations.
308
0
    if (false == addPSInvocation(psProgram, FFP_PS_COLOUR_BEGIN))
309
0
        return false;
310
311
0
    return true;
312
0
}
313
314
//-----------------------------------------------------------------------
315
bool IntegratedPSSM3::addVSInvocation(Function* vsMain, const int groupOrder)
316
0
{
317
0
    auto stage = vsMain->getStage(groupOrder);
318
319
0
    if(mIsD3D9)
320
0
    {
321
0
        auto vsOutPos = vsMain->resolveOutputParameter(Parameter::SPC_POSITION_PROJECTIVE_SPACE);
322
0
        stage.assign(vsOutPos, mVSOutPos);
323
0
    }
324
325
    // Compute world space position.
326
0
    int idx = 0;
327
0
    for (auto& p : mShadowTextureParamsList)
328
0
    {
329
0
        stage.callBuiltin("mul", {In(mWorldViewProjMatrices), At(idx++), In(mVSInPos), Out(p.mVSOutLightPosition)});
330
0
    }
331
332
0
    return true;
333
0
}
334
335
//-----------------------------------------------------------------------
336
bool IntegratedPSSM3::addPSInvocation(Program* psProgram, const int groupOrder)
337
0
{
338
0
    Function* psMain = psProgram->getEntryPointFunction();
339
0
    auto stage = psMain->getStage(groupOrder);
340
341
0
    if(mShadowTextureParamsList.size() < 2  || mMultiLightCount > 1)
342
0
    {
343
0
        for(uchar i = 0; i < mMultiLightCount; ++i)
344
0
        {
345
0
            ShadowTextureParams& params = mShadowTextureParamsList[i];
346
0
            stage.callFunction("SGX_ShadowPCF4",
347
0
                               {In(params.mTextureSampler), In(params.mPSInLightPosition),
348
0
                                In(params.mInvTextureSize).xy(), Out(mPSLocalShadowFactor), At(i)});
349
0
        }
350
0
    }
351
0
    else
352
0
    {
353
0
        auto fdepth = psMain->resolveLocalParameter(GCT_FLOAT1, "fdepth");
354
0
        if(mIsD3D9)
355
0
            stage.div(In(mPSInDepth).z(), In(mPSInDepth).w(), fdepth);
356
0
        else
357
0
            stage.assign(In(mPSInDepth).z(), fdepth);
358
0
        std::vector<Operand> params = {In(fdepth), In(mPSSplitPoints)};
359
360
0
        for(auto& texp : mShadowTextureParamsList)
361
0
        {
362
0
            params.push_back(In(texp.mPSInLightPosition));
363
0
            params.push_back(In(texp.mTextureSampler));
364
0
            params.push_back(In(texp.mInvTextureSize).xy());
365
0
        }
366
367
0
        params.push_back(Out(mPSLocalShadowFactor));
368
0
        params.push_back(At(0));
369
370
0
        if(mDebug)
371
0
        {
372
0
            auto sceneCol = psProgram->resolveParameter(GpuProgramParameters::ACT_DERIVED_SCENE_COLOUR);
373
0
            params.push_back(InOut(sceneCol));
374
0
        }
375
376
        // Compute shadow factor.
377
0
        stage.callFunction("SGX_ComputeShadowFactor_PSSM3", params);
378
0
    }
379
380
    // shadow factor is applied by lighting stages
381
0
    return true;
382
0
}
383
384
//-----------------------------------------------------------------------
385
SubRenderState* IntegratedPSSM3Factory::createInstance(const ScriptProperty& prop, Pass* pass, SGScriptTranslator* translator)
386
0
{
387
0
    if (prop.name == "integrated_pssm4")
388
0
    {
389
0
        translator->emitError("integrated_pssm4. Use shadow_mapping instead.", ScriptCompiler::CE_DEPRECATEDSYMBOL);
390
391
0
        SubRenderState* subRenderState = createOrRetrieveInstance(translator);
392
393
0
        if (prop.values.size() >= 4)
394
0
        {
395
0
            IntegratedPSSM3::SplitPointList splitPointList(4);
396
0
            for(int i = 0; i < 4; ++i)
397
0
            {
398
0
                if (!StringConverter::parse(prop.values[i], splitPointList[i]))
399
0
                {
400
0
                    translator->emitError();
401
0
                }
402
0
            }
403
0
            subRenderState->setParameter("split_points", splitPointList);
404
0
        }
405
406
0
        auto it = prop.values.begin() + 4;
407
0
        for (; it != prop.values.end(); ++it)
408
0
        {
409
0
            const auto& val = (*it);
410
0
            if(val == "debug")
411
0
            {
412
0
                subRenderState->setParameter("debug", "true");
413
0
            }
414
0
            else if(val == "pcf16")
415
0
            {
416
0
                subRenderState->setParameter("filter", "pcf16");
417
0
            }
418
0
        }
419
420
0
        return subRenderState;
421
0
    }
422
423
0
    if (prop.name == "shadow_mapping")
424
0
    {
425
0
        SubRenderState* subRenderState = createOrRetrieveInstance(translator);
426
427
0
        auto it = prop.values.begin();
428
0
        while(it != prop.values.end())
429
0
        {
430
0
            String paramName = (*it);
431
0
            String paramValue = (*++it);
432
433
0
            if (!subRenderState->setParameter(paramName, paramValue))
434
0
            {
435
0
                translator->emitError(paramName);
436
0
                return subRenderState;
437
0
            }
438
0
            it++;
439
0
        }
440
441
0
        return subRenderState;
442
0
    }
443
444
0
    return NULL;
445
0
}
446
447
//-----------------------------------------------------------------------
448
SubRenderState* IntegratedPSSM3Factory::createInstanceImpl()
449
0
{
450
    return OGRE_NEW IntegratedPSSM3;
451
0
}
452
453
}
454
}
455
456
#endif