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