1 // Copyright (C) 2021 The Android Open Source Project
2 // Copyright (C) 2021 Google Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 #include "DescriptorSetVirtualization.h"
16 #include "Resources.h"
17
18 namespace goldfish_vk {
19
clearReifiedDescriptorSet(ReifiedDescriptorSet * set)20 void clearReifiedDescriptorSet(ReifiedDescriptorSet* set) {
21 set->pool = VK_NULL_HANDLE;
22 set->setLayout = VK_NULL_HANDLE;
23 set->poolId = -1;
24 set->allocationPending = false;
25 set->allWrites.clear();
26 set->pendingWriteArrayRanges.clear();
27 }
28
initDescriptorWriteTable(const std::vector<VkDescriptorSetLayoutBinding> & layoutBindings,DescriptorWriteTable & table)29 void initDescriptorWriteTable(const std::vector<VkDescriptorSetLayoutBinding>& layoutBindings, DescriptorWriteTable& table) {
30 uint32_t highestBindingNumber = 0;
31
32 for (uint32_t i = 0; i < layoutBindings.size(); ++i) {
33 if (layoutBindings[i].binding > highestBindingNumber) {
34 highestBindingNumber = layoutBindings[i].binding;
35 }
36 }
37
38 std::vector<uint32_t> countsEachBinding(highestBindingNumber + 1, 0);
39
40 for (uint32_t i = 0; i < layoutBindings.size(); ++i) {
41 countsEachBinding[layoutBindings[i].binding] =
42 layoutBindings[i].descriptorCount;
43 }
44
45 table.resize(countsEachBinding.size());
46
47 for (uint32_t i = 0; i < table.size(); ++i) {
48 table[i].resize(countsEachBinding[i]);
49
50 for (uint32_t j = 0; j < countsEachBinding[i]; ++j) {
51 table[i][j].type = DescriptorWriteType::Empty;
52 table[i][j].dstArrayElement = 0;
53 }
54 }
55 }
56
initializeReifiedDescriptorSet(VkDescriptorPool pool,VkDescriptorSetLayout setLayout,ReifiedDescriptorSet * set)57 static void initializeReifiedDescriptorSet(VkDescriptorPool pool, VkDescriptorSetLayout setLayout, ReifiedDescriptorSet* set) {
58
59 set->pendingWriteArrayRanges.clear();
60
61 const auto& layoutInfo = *(as_goldfish_VkDescriptorSetLayout(setLayout)->layoutInfo);
62
63 initDescriptorWriteTable(layoutInfo.bindings, set->allWrites);
64
65 for (size_t i = 0; i < layoutInfo.bindings.size(); ++i) {
66 // Bindings can be sparsely defined
67 const auto& binding = layoutInfo.bindings[i];
68 uint32_t bindingIndex = binding.binding;
69 if (set->bindingIsImmutableSampler.size() <= bindingIndex) {
70 set->bindingIsImmutableSampler.resize(bindingIndex + 1, false);
71 }
72 set->bindingIsImmutableSampler[bindingIndex] =
73 binding.descriptorCount > 0 &&
74 (binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
75 binding.descriptorType ==
76 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
77 binding.pImmutableSamplers;
78 }
79
80 set->pool = pool;
81 set->setLayout = setLayout;
82 set->allocationPending = true;
83 set->bindings = layoutInfo.bindings;
84 }
85
isDescriptorTypeImageInfo(VkDescriptorType descType)86 bool isDescriptorTypeImageInfo(VkDescriptorType descType) {
87 return (descType == VK_DESCRIPTOR_TYPE_SAMPLER) ||
88 (descType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ||
89 (descType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
90 (descType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ||
91 (descType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
92 }
93
isDescriptorTypeBufferInfo(VkDescriptorType descType)94 bool isDescriptorTypeBufferInfo(VkDescriptorType descType) {
95 return (descType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
96 (descType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
97 (descType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||
98 (descType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
99 }
100
isDescriptorTypeBufferView(VkDescriptorType descType)101 bool isDescriptorTypeBufferView(VkDescriptorType descType) {
102 return (descType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ||
103 (descType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER);
104 }
105
isDescriptorTypeInlineUniformBlock(VkDescriptorType descType)106 bool isDescriptorTypeInlineUniformBlock(VkDescriptorType descType) {
107 return descType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT;
108 }
109
isDescriptorTypeAccelerationStructure(VkDescriptorType descType)110 bool isDescriptorTypeAccelerationStructure(VkDescriptorType descType) {
111 return descType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
112 }
113
doEmulatedDescriptorWrite(const VkWriteDescriptorSet * write,ReifiedDescriptorSet * toWrite)114 void doEmulatedDescriptorWrite(const VkWriteDescriptorSet* write, ReifiedDescriptorSet* toWrite) {
115 VkDescriptorType descType = write->descriptorType;
116 uint32_t dstBinding = write->dstBinding;
117 uint32_t dstArrayElement = write->dstArrayElement;
118 uint32_t descriptorCount = write->descriptorCount;
119
120 DescriptorWriteTable& table = toWrite->allWrites;
121
122 uint32_t arrOffset = dstArrayElement;
123
124 if (isDescriptorTypeImageInfo(descType)) {
125 for (uint32_t i = 0; i < descriptorCount; ++i, ++arrOffset) {
126 if (arrOffset >= table[dstBinding].size()) {
127 ++dstBinding;
128 arrOffset = 0;
129 }
130 auto& entry = table[dstBinding][arrOffset];
131 entry.imageInfo = write->pImageInfo[i];
132 entry.type = DescriptorWriteType::ImageInfo;
133 entry.descriptorType = descType;
134 }
135 } else if (isDescriptorTypeBufferInfo(descType)) {
136 for (uint32_t i = 0; i < descriptorCount; ++i, ++arrOffset) {
137 if (arrOffset >= table[dstBinding].size()) {
138 ++dstBinding;
139 arrOffset = 0;
140 }
141 auto& entry = table[dstBinding][arrOffset];
142 entry.bufferInfo = write->pBufferInfo[i];
143 entry.type = DescriptorWriteType::BufferInfo;
144 entry.descriptorType = descType;
145 }
146 } else if (isDescriptorTypeBufferView(descType)) {
147 for (uint32_t i = 0; i < descriptorCount; ++i, ++arrOffset) {
148 if (arrOffset >= table[dstBinding].size()) {
149 ++dstBinding;
150 arrOffset = 0;
151 }
152 auto& entry = table[dstBinding][arrOffset];
153 entry.bufferView = write->pTexelBufferView[i];
154 entry.type = DescriptorWriteType::BufferView;
155 entry.descriptorType = descType;
156 }
157 } else if (isDescriptorTypeInlineUniformBlock(descType)) {
158 // TODO
159 // Look for pNext inline uniform block
160 // Append new DescriptorWrite entry that holds the buffer
161 } else if (isDescriptorTypeAccelerationStructure(descType)) {
162 // TODO
163 // Look for pNext acceleration structure
164 // Append new DescriptorWrite entry that holds it
165 } else {
166 return;
167 }
168 }
169
doEmulatedDescriptorCopy(const VkCopyDescriptorSet * copy,const ReifiedDescriptorSet * src,ReifiedDescriptorSet * dst)170 void doEmulatedDescriptorCopy(const VkCopyDescriptorSet* copy, const ReifiedDescriptorSet* src, ReifiedDescriptorSet* dst) {
171 const DescriptorWriteTable& srcTable = src->allWrites;
172 DescriptorWriteTable& dstTable = dst->allWrites;
173
174 // src/dst may be the same descriptor set, so we need to create a temporary array for that case.
175 // (TODO: Maybe just notice the pointers are the same? can aliasing in any other way happen?)
176
177 std::vector<DescriptorWrite> toCopy;
178 uint32_t currBinding = copy->srcBinding;
179 uint32_t arrOffset = copy->srcArrayElement;
180 for (uint32_t i = 0; i < copy->descriptorCount; ++i, ++arrOffset) {
181 if (arrOffset >= srcTable[currBinding].size()) {
182 ++currBinding;
183 arrOffset = 0;
184 }
185 toCopy.push_back(srcTable[currBinding][arrOffset]);
186 }
187
188 currBinding = copy->dstBinding;
189 arrOffset = copy->dstArrayElement;
190 for (uint32_t i = 0; i < copy->descriptorCount; ++i, ++arrOffset) {
191 if (arrOffset >= dstTable[currBinding].size()) {
192 ++currBinding;
193 arrOffset = 0;
194 }
195 dstTable[currBinding][arrOffset] = toCopy[i];
196 }
197 }
198
doEmulatedDescriptorImageInfoWriteFromTemplate(VkDescriptorType descType,uint32_t binding,uint32_t dstArrayElement,uint32_t count,const VkDescriptorImageInfo * imageInfos,ReifiedDescriptorSet * set)199 void doEmulatedDescriptorImageInfoWriteFromTemplate(
200 VkDescriptorType descType,
201 uint32_t binding,
202 uint32_t dstArrayElement,
203 uint32_t count,
204 const VkDescriptorImageInfo* imageInfos,
205 ReifiedDescriptorSet* set) {
206
207 DescriptorWriteTable& table = set->allWrites;
208
209 uint32_t currBinding = binding;
210 uint32_t arrOffset = dstArrayElement;
211
212 for (uint32_t i = 0; i < count; ++i, ++arrOffset) {
213 if (arrOffset >= table[currBinding].size()) {
214 ++currBinding;
215 arrOffset = 0;
216 }
217 auto& entry = table[currBinding][arrOffset];
218 entry.imageInfo = imageInfos[i];
219 entry.type = DescriptorWriteType::ImageInfo;
220 entry.descriptorType = descType;
221 }
222 }
223
doEmulatedDescriptorBufferInfoWriteFromTemplate(VkDescriptorType descType,uint32_t binding,uint32_t dstArrayElement,uint32_t count,const VkDescriptorBufferInfo * bufferInfos,ReifiedDescriptorSet * set)224 void doEmulatedDescriptorBufferInfoWriteFromTemplate(
225 VkDescriptorType descType,
226 uint32_t binding,
227 uint32_t dstArrayElement,
228 uint32_t count,
229 const VkDescriptorBufferInfo* bufferInfos,
230 ReifiedDescriptorSet* set) {
231
232 DescriptorWriteTable& table = set->allWrites;
233
234 uint32_t currBinding = binding;
235 uint32_t arrOffset = dstArrayElement;
236
237 for (uint32_t i = 0; i < count; ++i, ++arrOffset) {
238 if (arrOffset >= table[currBinding].size()) {
239 ++currBinding;
240 arrOffset = 0;
241 }
242 auto& entry = table[currBinding][dstArrayElement + i];
243 entry.bufferInfo = bufferInfos[i];
244 entry.type = DescriptorWriteType::BufferInfo;
245 entry.descriptorType = descType;
246 }
247 }
248
doEmulatedDescriptorBufferViewWriteFromTemplate(VkDescriptorType descType,uint32_t binding,uint32_t dstArrayElement,uint32_t count,const VkBufferView * bufferViews,ReifiedDescriptorSet * set)249 void doEmulatedDescriptorBufferViewWriteFromTemplate(
250 VkDescriptorType descType,
251 uint32_t binding,
252 uint32_t dstArrayElement,
253 uint32_t count,
254 const VkBufferView* bufferViews,
255 ReifiedDescriptorSet* set) {
256
257 DescriptorWriteTable& table = set->allWrites;
258
259 uint32_t currBinding = binding;
260 uint32_t arrOffset = dstArrayElement;
261
262 for (uint32_t i = 0; i < count; ++i, ++arrOffset) {
263 if (arrOffset >= table[currBinding].size()) {
264 ++currBinding;
265 arrOffset = 0;
266 }
267 auto& entry = table[currBinding][dstArrayElement + i];
268 entry.bufferView = bufferViews[i];
269 entry.type = DescriptorWriteType::BufferView;
270 entry.descriptorType = descType;
271 }
272 }
273
isBindingFeasibleForAlloc(const DescriptorPoolAllocationInfo::DescriptorCountInfo & countInfo,const VkDescriptorSetLayoutBinding & binding)274 static bool isBindingFeasibleForAlloc(
275 const DescriptorPoolAllocationInfo::DescriptorCountInfo& countInfo,
276 const VkDescriptorSetLayoutBinding& binding) {
277
278 if (binding.descriptorCount && (countInfo.type != binding.descriptorType)) {
279 return false;
280 }
281
282 uint32_t availDescriptorCount =
283 countInfo.descriptorCount - countInfo.used;
284
285 if (availDescriptorCount < binding.descriptorCount) {
286 ALOGV("%s: Ran out of descriptors of type 0x%x. "
287 "Wanted %u from layout but "
288 "we only have %u free (total in pool: %u)\n", __func__,
289 binding.descriptorType,
290 binding.descriptorCount,
291 countInfo.descriptorCount - countInfo.used,
292 countInfo.descriptorCount);
293 return false;
294 }
295
296 return true;
297 }
298
isBindingFeasibleForFree(const DescriptorPoolAllocationInfo::DescriptorCountInfo & countInfo,const VkDescriptorSetLayoutBinding & binding)299 static bool isBindingFeasibleForFree(
300 const DescriptorPoolAllocationInfo::DescriptorCountInfo& countInfo,
301 const VkDescriptorSetLayoutBinding& binding) {
302
303 if (countInfo.type != binding.descriptorType) return false;
304 if (countInfo.used < binding.descriptorCount) {
305 ALOGV("%s: Was a descriptor set double freed? "
306 "Ran out of descriptors of type 0x%x. "
307 "Wanted to free %u from layout but "
308 "we only have %u used (total in pool: %u)\n", __func__,
309 binding.descriptorType,
310 binding.descriptorCount,
311 countInfo.used,
312 countInfo.descriptorCount);
313 return false;
314 }
315 return true;
316 }
317
allocBindingFeasible(const VkDescriptorSetLayoutBinding & binding,DescriptorPoolAllocationInfo::DescriptorCountInfo & poolState)318 static void allocBindingFeasible(
319 const VkDescriptorSetLayoutBinding& binding,
320 DescriptorPoolAllocationInfo::DescriptorCountInfo& poolState) {
321 poolState.used += binding.descriptorCount;
322 }
323
freeBindingFeasible(const VkDescriptorSetLayoutBinding & binding,DescriptorPoolAllocationInfo::DescriptorCountInfo & poolState)324 static void freeBindingFeasible(
325 const VkDescriptorSetLayoutBinding& binding,
326 DescriptorPoolAllocationInfo::DescriptorCountInfo& poolState) {
327 poolState.used -= binding.descriptorCount;
328 }
329
validateDescriptorSetAllocation(const VkDescriptorSetAllocateInfo * pAllocateInfo)330 static VkResult validateDescriptorSetAllocation(const VkDescriptorSetAllocateInfo* pAllocateInfo) {
331 VkDescriptorPool pool = pAllocateInfo->descriptorPool;
332 DescriptorPoolAllocationInfo* poolInfo = as_goldfish_VkDescriptorPool(pool)->allocInfo;
333
334 // Check the number of sets available.
335 auto setsAvailable = poolInfo->maxSets - poolInfo->usedSets;
336
337 if (setsAvailable < pAllocateInfo->descriptorSetCount) {
338 ALOGV("%s: Error: VkDescriptorSetAllocateInfo wants %u sets "
339 "but we only have %u available. "
340 "Bailing with VK_ERROR_OUT_OF_POOL_MEMORY.\n", __func__,
341 pAllocateInfo->descriptorSetCount,
342 setsAvailable);
343 return VK_ERROR_OUT_OF_POOL_MEMORY;
344 }
345
346 // Perform simulated allocation and error out with
347 // VK_ERROR_OUT_OF_POOL_MEMORY if it fails.
348 std::vector<DescriptorPoolAllocationInfo::DescriptorCountInfo> descriptorCountCopy =
349 poolInfo->descriptorCountInfo;
350
351 for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; ++i) {
352 if (!pAllocateInfo->pSetLayouts[i]) {
353 ALOGV("%s: Error: Tried to allocate a descriptor set with null set layout.\n", __func__);
354 return VK_ERROR_INITIALIZATION_FAILED;
355 }
356
357 auto setLayoutInfo = as_goldfish_VkDescriptorSetLayout(pAllocateInfo->pSetLayouts[i])->layoutInfo;
358 if (!setLayoutInfo) {
359 return VK_ERROR_INITIALIZATION_FAILED;
360 }
361
362 for (const auto& binding : setLayoutInfo->bindings) {
363 bool success = false;
364 for (auto& pool : descriptorCountCopy) {
365 if (!isBindingFeasibleForAlloc(pool, binding)) continue;
366
367 success = true;
368 allocBindingFeasible(binding, pool);
369 break;
370 }
371
372 if (!success) {
373 return VK_ERROR_OUT_OF_POOL_MEMORY;
374 }
375 }
376 }
377 return VK_SUCCESS;
378 }
379
applyDescriptorSetAllocation(VkDescriptorPool pool,VkDescriptorSetLayout setLayout)380 void applyDescriptorSetAllocation(VkDescriptorPool pool, VkDescriptorSetLayout setLayout) {
381 auto allocInfo = as_goldfish_VkDescriptorPool(pool)->allocInfo;
382 auto setLayoutInfo = as_goldfish_VkDescriptorSetLayout(setLayout)->layoutInfo;
383
384 ++allocInfo->usedSets;
385
386 for (const auto& binding : setLayoutInfo->bindings) {
387 for (auto& countForPool : allocInfo->descriptorCountInfo) {
388 if (!isBindingFeasibleForAlloc(countForPool, binding)) continue;
389 allocBindingFeasible(binding, countForPool);
390 break;
391 }
392 }
393 }
394
removeDescriptorSetAllocation(VkDescriptorPool pool,const std::vector<VkDescriptorSetLayoutBinding> & bindings)395 void removeDescriptorSetAllocation(VkDescriptorPool pool, const std::vector<VkDescriptorSetLayoutBinding>& bindings) {
396 auto allocInfo = as_goldfish_VkDescriptorPool(pool)->allocInfo;
397
398 if (0 == allocInfo->usedSets) {
399 ALOGV("%s: Warning: a descriptor set was double freed.\n", __func__);
400 return;
401 }
402
403 --allocInfo->usedSets;
404
405 for (const auto& binding : bindings) {
406 for (auto& countForPool : allocInfo->descriptorCountInfo) {
407 if (!isBindingFeasibleForFree(countForPool, binding)) continue;
408 freeBindingFeasible(binding, countForPool);
409 break;
410 }
411 }
412 }
413
fillDescriptorSetInfoForPool(VkDescriptorPool pool,VkDescriptorSetLayout setLayout,VkDescriptorSet set)414 void fillDescriptorSetInfoForPool(VkDescriptorPool pool, VkDescriptorSetLayout setLayout, VkDescriptorSet set) {
415 DescriptorPoolAllocationInfo* allocInfo = as_goldfish_VkDescriptorPool(pool)->allocInfo;
416
417 ReifiedDescriptorSet* newReified = new ReifiedDescriptorSet;
418 newReified->poolId = as_goldfish_VkDescriptorSet(set)->underlying;
419 newReified->allocationPending = true;
420
421 as_goldfish_VkDescriptorSet(set)->reified = newReified;
422
423 allocInfo->allocedPoolIds.insert(newReified->poolId);
424 allocInfo->allocedSets.insert(set);
425
426 initializeReifiedDescriptorSet(pool, setLayout, newReified);
427 }
428
validateAndApplyVirtualDescriptorSetAllocation(const VkDescriptorSetAllocateInfo * pAllocateInfo,VkDescriptorSet * pSets)429 VkResult validateAndApplyVirtualDescriptorSetAllocation(const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pSets) {
430 VkResult validateRes = validateDescriptorSetAllocation(pAllocateInfo);
431
432 if (validateRes != VK_SUCCESS) return validateRes;
433
434 for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; ++i) {
435 applyDescriptorSetAllocation(pAllocateInfo->descriptorPool, pAllocateInfo->pSetLayouts[i]);
436 }
437
438 VkDescriptorPool pool = pAllocateInfo->descriptorPool;
439 DescriptorPoolAllocationInfo* allocInfo = as_goldfish_VkDescriptorPool(pool)->allocInfo;
440
441 if (allocInfo->freePoolIds.size() < pAllocateInfo->descriptorSetCount) {
442 ALOGE("%s: FATAL: Somehow out of descriptor pool IDs. Wanted %u IDs but only have %u free IDs remaining. The count for maxSets was %u and used was %u\n", __func__,
443 pAllocateInfo->descriptorSetCount,
444 (uint32_t)allocInfo->freePoolIds.size(),
445 allocInfo->maxSets,
446 allocInfo->usedSets);
447 abort();
448 }
449
450 for (uint32_t i = 0 ; i < pAllocateInfo->descriptorSetCount; ++i) {
451 uint64_t id = allocInfo->freePoolIds.back();
452 allocInfo->freePoolIds.pop_back();
453
454 VkDescriptorSet newSet = new_from_host_VkDescriptorSet((VkDescriptorSet)id);
455 pSets[i] = newSet;
456
457 fillDescriptorSetInfoForPool(pool, pAllocateInfo->pSetLayouts[i], newSet);
458 }
459
460 return VK_SUCCESS;
461 }
462
removeDescriptorSetFromPool(VkDescriptorSet set,bool usePoolIds)463 bool removeDescriptorSetFromPool(VkDescriptorSet set, bool usePoolIds) {
464 ReifiedDescriptorSet* reified = as_goldfish_VkDescriptorSet(set)->reified;
465
466 VkDescriptorPool pool = reified->pool;
467 DescriptorPoolAllocationInfo* allocInfo = as_goldfish_VkDescriptorPool(pool)->allocInfo;
468
469 if (usePoolIds) {
470 // Look for the set's pool Id in the pool. If not found, then this wasn't really allocated, and bail.
471 if (allocInfo->allocedPoolIds.find(reified->poolId) == allocInfo->allocedPoolIds.end()) {
472 return false;
473 }
474 }
475
476 const std::vector<VkDescriptorSetLayoutBinding>& bindings = reified->bindings;
477 removeDescriptorSetAllocation(pool, bindings);
478
479 if (usePoolIds) {
480 allocInfo->freePoolIds.push_back(reified->poolId);
481 allocInfo->allocedPoolIds.erase(reified->poolId);
482 }
483 allocInfo->allocedSets.erase(set);
484
485 return true;
486 }
487
clearDescriptorPool(VkDescriptorPool pool,bool usePoolIds)488 std::vector<VkDescriptorSet> clearDescriptorPool(VkDescriptorPool pool, bool usePoolIds) {
489 std::vector<VkDescriptorSet> toClear;
490 for (auto set : as_goldfish_VkDescriptorPool(pool)->allocInfo->allocedSets) {
491 toClear.push_back(set);
492 }
493
494 for (auto set: toClear) {
495 removeDescriptorSetFromPool(set, usePoolIds);
496 }
497
498 return toClear;
499 }
500
501 } // namespace goldfish_vk
502