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 "RenderAPI/BsGpuPipelineParamInfo.h" |
4 | #include "RenderAPI/BsGpuParamDesc.h" |
5 | #include "Managers/BsRenderStateManager.h" |
6 | |
7 | namespace bs |
8 | { |
9 | GpuPipelineParamInfoBase::GpuPipelineParamInfoBase(const GPU_PIPELINE_PARAMS_DESC& desc) |
10 | :mNumSets(0), mNumElements(0), mSetInfos(nullptr), mResourceInfos() |
11 | { |
12 | bs_zero_out(mNumElementsPerType); |
13 | |
14 | mParamDescs[GPT_FRAGMENT_PROGRAM] = desc.fragmentParams; |
15 | mParamDescs[GPT_VERTEX_PROGRAM] = desc.vertexParams; |
16 | mParamDescs[GPT_GEOMETRY_PROGRAM] = desc.geometryParams; |
17 | mParamDescs[GPT_HULL_PROGRAM] = desc.hullParams; |
18 | mParamDescs[GPT_DOMAIN_PROGRAM] = desc.domainParams; |
19 | mParamDescs[GPT_COMPUTE_PROGRAM] = desc.computeParams; |
20 | |
21 | auto countElements = [&](auto& entry, ParamType type) |
22 | { |
23 | int typeIdx = (int)type; |
24 | |
25 | if ((entry.set + 1) > mNumSets) |
26 | mNumSets = entry.set + 1; |
27 | |
28 | mNumElementsPerType[typeIdx]++; |
29 | mNumElements++; |
30 | }; |
31 | |
32 | UINT32 numParamDescs = sizeof(mParamDescs) / sizeof(mParamDescs[0]); |
33 | for (UINT32 i = 0; i < numParamDescs; i++) |
34 | { |
35 | const SPtr<GpuParamDesc>& paramDesc = mParamDescs[i]; |
36 | if (paramDesc == nullptr) |
37 | continue; |
38 | |
39 | for (auto& paramBlock : paramDesc->paramBlocks) |
40 | countElements(paramBlock.second, ParamType::ParamBlock); |
41 | |
42 | for (auto& texture : paramDesc->textures) |
43 | countElements(texture.second, ParamType::Texture); |
44 | |
45 | for (auto& texture : paramDesc->loadStoreTextures) |
46 | countElements(texture.second, ParamType::LoadStoreTexture); |
47 | |
48 | for (auto& buffer : paramDesc->buffers) |
49 | countElements(buffer.second, ParamType::Buffer); |
50 | |
51 | for (auto& sampler : paramDesc->samplers) |
52 | countElements(sampler.second, ParamType::SamplerState); |
53 | } |
54 | |
55 | UINT32* numSlotsPerSet = (UINT32*)bs_stack_alloc(mNumSets * sizeof(UINT32)); |
56 | bs_zero_out(numSlotsPerSet, mNumSets); |
57 | |
58 | for (UINT32 i = 0; i < numParamDescs; i++) |
59 | { |
60 | const SPtr<GpuParamDesc>& paramDesc = mParamDescs[i]; |
61 | if (paramDesc == nullptr) |
62 | continue; |
63 | |
64 | for (auto& paramBlock : paramDesc->paramBlocks) |
65 | numSlotsPerSet[paramBlock.second.set] = |
66 | std::max(numSlotsPerSet[paramBlock.second.set], paramBlock.second.slot + 1); |
67 | |
68 | for (auto& texture : paramDesc->textures) |
69 | numSlotsPerSet[texture.second.set] = |
70 | std::max(numSlotsPerSet[texture.second.set], texture.second.slot + 1); |
71 | |
72 | for (auto& texture : paramDesc->loadStoreTextures) |
73 | numSlotsPerSet[texture.second.set] = |
74 | std::max(numSlotsPerSet[texture.second.set], texture.second.slot + 1); |
75 | |
76 | for (auto& buffer : paramDesc->buffers) |
77 | numSlotsPerSet[buffer.second.set] = |
78 | std::max(numSlotsPerSet[buffer.second.set], buffer.second.slot + 1); |
79 | |
80 | for (auto& sampler : paramDesc->samplers) |
81 | numSlotsPerSet[sampler.second.set] = |
82 | std::max(numSlotsPerSet[sampler.second.set], sampler.second.slot + 1); |
83 | } |
84 | |
85 | UINT32 totalNumSlots = 0; |
86 | for (UINT32 i = 0; i < mNumSets; i++) |
87 | totalNumSlots += numSlotsPerSet[i]; |
88 | |
89 | mAlloc.reserve<SetInfo>(mNumSets) |
90 | .reserve<UINT32>(totalNumSlots) |
91 | .reserve<ParamType>(totalNumSlots) |
92 | .reserve<UINT32>(totalNumSlots); |
93 | |
94 | for (UINT32 i = 0; i < (UINT32)ParamType::Count; i++) |
95 | mAlloc.reserve<ResourceInfo>(mNumElementsPerType[i]); |
96 | |
97 | mAlloc.init(); |
98 | |
99 | mSetInfos = mAlloc.alloc<SetInfo>(mNumSets); |
100 | |
101 | if(mSetInfos != nullptr) |
102 | bs_zero_out(mSetInfos, mNumSets); |
103 | |
104 | for (UINT32 i = 0; i < mNumSets; i++) |
105 | mSetInfos[i].numSlots = numSlotsPerSet[i]; |
106 | |
107 | bs_stack_free(numSlotsPerSet); |
108 | |
109 | for(UINT32 i = 0; i < mNumSets; i++) |
110 | { |
111 | mSetInfos[i].slotIndices = mAlloc.alloc<UINT32>(mSetInfos[i].numSlots); |
112 | memset(mSetInfos[i].slotIndices, -1, sizeof(UINT32) * mSetInfos[i].numSlots); |
113 | |
114 | mSetInfos[i].slotTypes = mAlloc.alloc<ParamType>(mSetInfos[i].numSlots); |
115 | |
116 | mSetInfos[i].slotSamplers = mAlloc.alloc<UINT32>(mSetInfos[i].numSlots); |
117 | memset(mSetInfos[i].slotSamplers, -1, sizeof(UINT32) * mSetInfos[i].numSlots); |
118 | } |
119 | |
120 | for (UINT32 i = 0; i < (UINT32)ParamType::Count; i++) |
121 | { |
122 | mResourceInfos[i] = mAlloc.alloc<ResourceInfo>(mNumElementsPerType[i]); |
123 | mNumElementsPerType[i] = 0; |
124 | } |
125 | |
126 | auto populateSetInfo = [&](auto& entry, ParamType type) |
127 | { |
128 | int typeIdx = (int)type; |
129 | |
130 | UINT32 sequentialIdx = mNumElementsPerType[typeIdx]; |
131 | |
132 | SetInfo& setInfo = mSetInfos[entry.set]; |
133 | setInfo.slotIndices[entry.slot] = sequentialIdx; |
134 | setInfo.slotTypes[entry.slot] = type; |
135 | |
136 | mResourceInfos[typeIdx][sequentialIdx].set = entry.set; |
137 | mResourceInfos[typeIdx][sequentialIdx].slot = entry.slot; |
138 | |
139 | mNumElementsPerType[typeIdx]++; |
140 | }; |
141 | |
142 | for (UINT32 i = 0; i < numParamDescs; i++) |
143 | { |
144 | const SPtr<GpuParamDesc>& paramDesc = mParamDescs[i]; |
145 | if (paramDesc == nullptr) |
146 | continue; |
147 | |
148 | for (auto& paramBlock : paramDesc->paramBlocks) |
149 | populateSetInfo(paramBlock.second, ParamType::ParamBlock); |
150 | |
151 | for (auto& texture : paramDesc->textures) |
152 | populateSetInfo(texture.second, ParamType::Texture); |
153 | |
154 | for (auto& texture : paramDesc->loadStoreTextures) |
155 | populateSetInfo(texture.second, ParamType::LoadStoreTexture); |
156 | |
157 | for (auto& buffer : paramDesc->buffers) |
158 | populateSetInfo(buffer.second, ParamType::Buffer); |
159 | |
160 | // Samplers need to be handled specially because certain slots could be texture/buffer + sampler combinations |
161 | { |
162 | int typeIdx = (int)ParamType::SamplerState; |
163 | for (auto& entry : paramDesc->samplers) |
164 | { |
165 | const GpuParamObjectDesc& samplerDesc = entry.second; |
166 | UINT32 sequentialIdx = mNumElementsPerType[typeIdx]; |
167 | |
168 | SetInfo& setInfo = mSetInfos[samplerDesc.set]; |
169 | if (setInfo.slotIndices[samplerDesc.slot] == (UINT32)-1) // Slot is sampler only |
170 | { |
171 | setInfo.slotIndices[samplerDesc.slot] = sequentialIdx; |
172 | setInfo.slotTypes[samplerDesc.slot] = ParamType::SamplerState; |
173 | } |
174 | else // Slot is a combination |
175 | { |
176 | setInfo.slotSamplers[samplerDesc.slot] = sequentialIdx; |
177 | } |
178 | |
179 | mResourceInfos[typeIdx][sequentialIdx].set = samplerDesc.set; |
180 | mResourceInfos[typeIdx][sequentialIdx].slot = samplerDesc.slot; |
181 | |
182 | mNumElementsPerType[typeIdx]++; |
183 | } |
184 | } |
185 | } |
186 | } |
187 | |
188 | UINT32 GpuPipelineParamInfoBase::getSequentialSlot(ParamType type, UINT32 set, UINT32 slot) const |
189 | { |
190 | #if BS_DEBUG_MODE |
191 | if (set >= mNumSets) |
192 | { |
193 | LOGERR("Set index out of range: Valid range: [0, " + |
194 | toString(mNumSets) + "). Requested: " + toString(set) + "." ); |
195 | return -1; |
196 | } |
197 | |
198 | if (slot >= mSetInfos[set].numSlots) |
199 | { |
200 | LOGERR("Slot index out of range: Valid range: [0, " + |
201 | toString(mSetInfos[set].numSlots) + "). Requested: " + toString(slot) + "." ); |
202 | return -1; |
203 | } |
204 | |
205 | ParamType slotType = mSetInfos[set].slotTypes[slot]; |
206 | if(slotType != type) |
207 | { |
208 | // Allow sampler states & textures/buffers to share the same slot, as some APIs combine them |
209 | if(type == ParamType::SamplerState) |
210 | { |
211 | if (mSetInfos[set].slotSamplers[slot] != (UINT32)-1) |
212 | return mSetInfos[set].slotSamplers[slot]; |
213 | } |
214 | |
215 | LOGERR("Requested parameter is not of the valid type. Requested: " + toString((UINT32)type) + ". Actual: " + |
216 | toString((UINT32)mSetInfos[set].slotTypes[slot]) + "." ); |
217 | return -1; |
218 | } |
219 | |
220 | #endif |
221 | |
222 | return mSetInfos[set].slotIndices[slot]; |
223 | } |
224 | |
225 | void GpuPipelineParamInfoBase::getBinding(ParamType type, UINT32 sequentialSlot, UINT32& set, UINT32& slot) const |
226 | { |
227 | #if BS_DEBUG_MODE |
228 | if(sequentialSlot >= mNumElementsPerType[(int)type]) |
229 | { |
230 | LOGERR("Sequential slot index out of range: Valid range: [0, " + toString(mNumElementsPerType[(int)type]) + |
231 | "). Requested: " + toString(sequentialSlot) + "." ); |
232 | |
233 | set = 0; |
234 | slot = 0; |
235 | return; |
236 | } |
237 | #endif |
238 | |
239 | set = mResourceInfos[(int)type][sequentialSlot].set; |
240 | slot = mResourceInfos[(int)type][sequentialSlot].slot; |
241 | } |
242 | |
243 | void GpuPipelineParamInfoBase::getBindings(ParamType type, const String& name, GpuParamBinding (& bindings)[GPT_COUNT]) |
244 | { |
245 | constexpr UINT32 numParamDescs = sizeof(mParamDescs) / sizeof(mParamDescs[0]); |
246 | static_assert( |
247 | numParamDescs == GPT_COUNT, |
248 | "Number of param descriptor structures must match the number of GPU program stages." |
249 | ); |
250 | |
251 | for (UINT32 i = 0; i < numParamDescs; i++) |
252 | getBinding((GpuProgramType)i, type, name, bindings[i]); |
253 | } |
254 | |
255 | void GpuPipelineParamInfoBase::getBinding(GpuProgramType progType, ParamType type, const String& name, |
256 | GpuParamBinding &binding) |
257 | { |
258 | auto findBinding = [](auto& paramMap, const String& name, GpuParamBinding& binding) |
259 | { |
260 | auto iterFind = paramMap.find(name); |
261 | if (iterFind != paramMap.end()) |
262 | { |
263 | binding.set = iterFind->second.set; |
264 | binding.slot = iterFind->second.slot; |
265 | } |
266 | else |
267 | binding.set = binding.slot = (UINT32)-1; |
268 | }; |
269 | |
270 | const SPtr<GpuParamDesc>& paramDesc = mParamDescs[(UINT32)progType]; |
271 | if (paramDesc == nullptr) |
272 | { |
273 | binding.set = binding.slot = (UINT32)-1; |
274 | return; |
275 | } |
276 | |
277 | switch(type) |
278 | { |
279 | case ParamType::ParamBlock: |
280 | findBinding(paramDesc->paramBlocks, name, binding); |
281 | break; |
282 | case ParamType::Texture: |
283 | findBinding(paramDesc->textures, name, binding); |
284 | break; |
285 | case ParamType::LoadStoreTexture: |
286 | findBinding(paramDesc->loadStoreTextures, name, binding); |
287 | break; |
288 | case ParamType::Buffer: |
289 | findBinding(paramDesc->buffers, name, binding); |
290 | break; |
291 | case ParamType::SamplerState: |
292 | findBinding(paramDesc->samplers, name, binding); |
293 | break; |
294 | default: |
295 | break; |
296 | } |
297 | } |
298 | |
299 | GpuPipelineParamInfo::GpuPipelineParamInfo(const GPU_PIPELINE_PARAMS_DESC& desc) |
300 | :GpuPipelineParamInfoBase(desc) |
301 | { } |
302 | |
303 | SPtr<GpuPipelineParamInfo> GpuPipelineParamInfo::create(const GPU_PIPELINE_PARAMS_DESC& desc) |
304 | { |
305 | SPtr<GpuPipelineParamInfo> paramInfo = |
306 | bs_core_ptr<GpuPipelineParamInfo>(new (bs_alloc<GpuPipelineParamInfo>()) GpuPipelineParamInfo(desc)); |
307 | paramInfo->_setThisPtr(paramInfo); |
308 | paramInfo->initialize(); |
309 | |
310 | return paramInfo; |
311 | } |
312 | |
313 | SPtr<ct::GpuPipelineParamInfo> GpuPipelineParamInfo::getCore() const |
314 | { |
315 | return std::static_pointer_cast<ct::GpuPipelineParamInfo>(mCoreSpecific); |
316 | } |
317 | |
318 | SPtr<ct::CoreObject> GpuPipelineParamInfo::createCore() const |
319 | { |
320 | GPU_PIPELINE_PARAMS_DESC desc; |
321 | desc.fragmentParams = mParamDescs[GPT_FRAGMENT_PROGRAM]; |
322 | desc.vertexParams = mParamDescs[GPT_VERTEX_PROGRAM]; |
323 | desc.geometryParams = mParamDescs[GPT_GEOMETRY_PROGRAM]; |
324 | desc.hullParams = mParamDescs[GPT_HULL_PROGRAM]; |
325 | desc.domainParams = mParamDescs[GPT_DOMAIN_PROGRAM]; |
326 | desc.computeParams = mParamDescs[GPT_COMPUTE_PROGRAM]; |
327 | |
328 | return ct::RenderStateManager::instance()._createPipelineParamInfo(desc); |
329 | } |
330 | |
331 | namespace ct |
332 | { |
333 | GpuPipelineParamInfo::GpuPipelineParamInfo(const GPU_PIPELINE_PARAMS_DESC& desc, GpuDeviceFlags deviceMask) |
334 | :GpuPipelineParamInfoBase(desc) |
335 | { } |
336 | |
337 | SPtr<GpuPipelineParamInfo> GpuPipelineParamInfo::create(const GPU_PIPELINE_PARAMS_DESC& desc, |
338 | GpuDeviceFlags deviceMask) |
339 | { |
340 | return RenderStateManager::instance().createPipelineParamInfo(desc, deviceMask); |
341 | } |
342 | } |
343 | } |