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 | |
13 | namespace 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 | }} |