1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "BsSamplerOverrides.h"
4#include "BsRenderBeastOptions.h"
5#include "Material/BsMaterial.h"
6#include "RenderAPI/BsGpuParams.h"
7#include "Material/BsGpuParamsSet.h"
8#include "RenderAPI/BsGpuParamDesc.h"
9#include "Material/BsMaterialParams.h"
10#include "RenderAPI/BsSamplerState.h"
11#include "Managers/BsRenderStateManager.h"
12
13namespace bs { namespace ct
14{
15 MaterialSamplerOverrides* SamplerOverrideUtility::generateSamplerOverrides(const SPtr<Shader>& shader,
16 const SPtr<MaterialParams>& params, const SPtr<GpuParamsSet>& paramsSet,
17 const SPtr<RenderBeastOptions>& options)
18 {
19 MaterialSamplerOverrides* output = nullptr;
20
21 if (shader == nullptr)
22 return nullptr;
23
24 bs_frame_mark();
25 {
26 // Generate a list of all sampler state overrides
27 FrameUnorderedMap<String, UINT32> overrideLookup;
28 Vector<SamplerOverride> overrides;
29
30 auto& samplerParams = shader->getSamplerParams();
31 for(auto& samplerParam : samplerParams)
32 {
33 UINT32 paramIdx;
34 auto result = params->getParamIndex(samplerParam.first, MaterialParams::ParamType::Sampler, GPDT_UNKNOWN,
35 0, paramIdx);
36
37 // Parameter shouldn't be in the valid parameter list if it cannot be found
38 assert(result == MaterialParams::GetParamResult::Success);
39 const MaterialParamsBase::ParamData* materialParamData = params->getParamData(paramIdx);
40
41 UINT32 overrideIdx = (UINT32)overrides.size();
42 overrides.push_back(SamplerOverride());
43 SamplerOverride& override = overrides.back();
44
45 SPtr<SamplerState> samplerState;
46 params->getSamplerState(*materialParamData, samplerState);
47
48 if (samplerState == nullptr)
49 samplerState = SamplerState::getDefault();
50
51 override.paramIdx = paramIdx;
52
53 if (checkNeedsOverride(samplerState, options))
54 override.state = generateSamplerOverride(samplerState, options);
55 else
56 override.state = samplerState;
57
58 override.originalStateHash = override.state->getProperties().getHash();
59
60 for (auto& entry : samplerParam.second.gpuVariableNames)
61 overrideLookup[entry] = overrideIdx;
62 }
63
64 UINT32 numPasses = paramsSet->getNumPasses();
65
66 // First pass just determine if we even need to override and count the number of sampler states
67 UINT32* numSetsPerPass = (UINT32*)bs_stack_alloc<UINT32>(numPasses);
68 memset(numSetsPerPass, 0, sizeof(UINT32) * numPasses);
69
70 UINT32 totalNumSets = 0;
71 for (UINT32 i = 0; i < numPasses; i++)
72 {
73 UINT32 maxSamplerSet = 0;
74
75 SPtr<GpuParams> paramsPtr = paramsSet->getGpuParams(i);
76 for (UINT32 j = 0; j < GpuParamsSet::NUM_STAGES; j++)
77 {
78 GpuProgramType progType = (GpuProgramType)j;
79 SPtr<GpuParamDesc> paramDesc = paramsPtr->getParamDesc(progType);
80 if (paramDesc == nullptr)
81 continue;
82
83 for (auto iter = paramDesc->samplers.begin(); iter != paramDesc->samplers.end(); ++iter)
84 {
85 UINT32 set = iter->second.set;
86 maxSamplerSet = std::max(maxSamplerSet, set + 1);
87 }
88 }
89
90 numSetsPerPass[i] = maxSamplerSet;
91 totalNumSets += maxSamplerSet;
92 }
93
94 UINT32 totalNumSamplerStates = 0;
95 UINT32* slotsPerSet = (UINT32*)bs_stack_alloc<UINT32>(totalNumSets);
96 memset(slotsPerSet, 0, sizeof(UINT32) * totalNumSets);
97
98 UINT32* slotsPerSetIter = slotsPerSet;
99 for (UINT32 i = 0; i < numPasses; i++)
100 {
101 SPtr<GpuParams> paramsPtr = paramsSet->getGpuParams(i);
102 for (UINT32 j = 0; j < GpuParamsSet::NUM_STAGES; j++)
103 {
104 GpuProgramType progType = (GpuProgramType)j;
105 SPtr<GpuParamDesc> paramDesc = paramsPtr->getParamDesc(progType);
106 if (paramDesc == nullptr)
107 continue;
108
109 for (auto iter = paramDesc->samplers.begin(); iter != paramDesc->samplers.end(); ++iter)
110 {
111 UINT32 set = iter->second.set;
112 UINT32 slot = iter->second.slot;
113 slotsPerSetIter[set] = std::max(slotsPerSetIter[set], slot + 1);
114 }
115 }
116
117 for(UINT32 j = 0; j < numSetsPerPass[i]; j++)
118 totalNumSamplerStates += slotsPerSetIter[j];
119
120 slotsPerSetIter += numSetsPerPass[i];
121 }
122
123 UINT32 outputSize = sizeof(MaterialSamplerOverrides) +
124 numPasses * sizeof(PassSamplerOverrides) +
125 totalNumSets * sizeof(UINT32*) +
126 totalNumSamplerStates * sizeof(UINT32) +
127 (UINT32)overrides.size() * sizeof(SamplerOverride);
128
129 UINT8* outputData = (UINT8*)bs_alloc(outputSize);
130 output = (MaterialSamplerOverrides*)outputData;
131 outputData += sizeof(MaterialSamplerOverrides);
132
133 output->refCount = 0;
134 output->numPasses = numPasses;
135 output->passes = (PassSamplerOverrides*)outputData;
136 output->isDirty = true;
137 outputData += sizeof(PassSamplerOverrides) * numPasses;
138
139 slotsPerSetIter = slotsPerSet;
140 for (UINT32 i = 0; i < numPasses; i++)
141 {
142 SPtr<GpuParams> paramsPtr = paramsSet->getGpuParams(i);
143
144 PassSamplerOverrides& passOverrides = output->passes[i];
145 passOverrides.numSets = numSetsPerPass[i];
146 passOverrides.stateOverrides = (UINT32**)outputData;
147 outputData += sizeof(UINT32*) * passOverrides.numSets;
148
149 for (UINT32 j = 0; j < passOverrides.numSets; j++)
150 {
151 passOverrides.stateOverrides[j] = (UINT32*)outputData;
152 outputData += sizeof(UINT32) * slotsPerSetIter[j];
153 }
154
155 for (UINT32 j = 0; j < GpuParamsSet::NUM_STAGES; j++)
156 {
157 GpuProgramType progType = (GpuProgramType)j;
158 SPtr<GpuParamDesc> paramDesc = paramsPtr->getParamDesc(progType);
159 if (paramDesc == nullptr)
160 continue;
161
162 UINT32 numStates = 0;
163 for (auto iter = paramDesc->samplers.begin(); iter != paramDesc->samplers.end(); ++iter)
164 {
165 UINT32 set = iter->second.set;
166 UINT32 slot = iter->second.slot;
167 while (slot > numStates)
168 {
169 passOverrides.stateOverrides[set][numStates] = (UINT32)-1;
170 numStates++;
171 }
172
173 numStates = std::max(numStates, slot + 1);
174
175 auto iterFind = overrideLookup.find(iter->first);
176 if (iterFind != overrideLookup.end())
177 passOverrides.stateOverrides[set][slot] = iterFind->second;
178 else
179 passOverrides.stateOverrides[set][slot] = (UINT32)-1;
180 }
181 }
182
183 slotsPerSetIter += passOverrides.numSets;
184 }
185
186 output->numOverrides = (UINT32)overrides.size();
187 output->overrides = (SamplerOverride*)outputData;
188
189 for(UINT32 i = 0; i < output->numOverrides; i++)
190 {
191 new (&output->overrides[i].state) SPtr<SamplerState>();
192 output->overrides[i] = overrides[i];
193 }
194
195 bs_stack_free(slotsPerSet);
196 bs_stack_free(numSetsPerPass);
197 }
198 bs_frame_clear();
199
200 return output;
201 }
202
203 void SamplerOverrideUtility::destroySamplerOverrides(MaterialSamplerOverrides* overrides)
204 {
205 if (overrides != nullptr)
206 {
207 for (UINT32 i = 0; i < overrides->numOverrides; i++)
208 overrides->overrides[i].state.~SPtr<SamplerState>();
209
210 bs_free(overrides);
211 overrides = nullptr;
212 }
213 }
214
215 bool SamplerOverrideUtility::checkNeedsOverride(const SPtr<SamplerState>& samplerState, const SPtr<RenderBeastOptions>& options)
216 {
217 const SamplerProperties& props = samplerState->getProperties();
218
219 switch (options->filtering)
220 {
221 case RenderBeastFiltering::Bilinear:
222 {
223 if (props.getTextureFiltering(FT_MIN) != FO_LINEAR)
224 return true;
225
226 if (props.getTextureFiltering(FT_MAG) != FO_LINEAR)
227 return true;
228
229 if (props.getTextureFiltering(FT_MIP) != FO_POINT)
230 return true;
231 }
232 break;
233 case RenderBeastFiltering::Trilinear:
234 {
235 if (props.getTextureFiltering(FT_MIN) != FO_LINEAR)
236 return true;
237
238 if (props.getTextureFiltering(FT_MAG) != FO_LINEAR)
239 return true;
240
241 if (props.getTextureFiltering(FT_MIP) != FO_LINEAR)
242 return true;
243 }
244 break;
245 case RenderBeastFiltering::Anisotropic:
246 {
247 if (props.getTextureFiltering(FT_MIN) != FO_ANISOTROPIC)
248 return true;
249
250 if (props.getTextureFiltering(FT_MAG) != FO_ANISOTROPIC)
251 return true;
252
253 if (props.getTextureFiltering(FT_MIP) != FO_ANISOTROPIC)
254 return true;
255
256 if (props.getTextureAnisotropy() != options->anisotropyMax)
257 return true;
258 }
259 break;
260 }
261
262 return false;
263 }
264
265 SPtr<SamplerState> SamplerOverrideUtility::generateSamplerOverride(const SPtr<SamplerState>& samplerState, const SPtr<RenderBeastOptions>& options)
266 {
267 const SamplerProperties& props = samplerState->getProperties();
268 SAMPLER_STATE_DESC desc = props.getDesc();
269
270 switch (options->filtering)
271 {
272 case RenderBeastFiltering::Bilinear:
273 desc.minFilter = FO_LINEAR;
274 desc.magFilter = FO_LINEAR;
275 desc.mipFilter = FO_POINT;
276 break;
277 case RenderBeastFiltering::Trilinear:
278 desc.minFilter = FO_LINEAR;
279 desc.magFilter = FO_LINEAR;
280 desc.mipFilter = FO_LINEAR;
281 break;
282 case RenderBeastFiltering::Anisotropic:
283 desc.minFilter = FO_ANISOTROPIC;
284 desc.magFilter = FO_ANISOTROPIC;
285 desc.mipFilter = FO_ANISOTROPIC;
286 break;
287 }
288
289 desc.maxAniso = options->anisotropyMax;
290
291 return RenderStateManager::instance().createSamplerState(desc);
292 }
293}}