1+ /*
2+ ===========================================================================
3+
4+ Daemon BSD Source Code
5+ Copyright (c) 2025 Daemon Developers
6+ All rights reserved.
7+
8+ This file is part of the Daemon BSD Source Code (Daemon Source Code).
9+
10+ Redistribution and use in source and binary forms, with or without
11+ modification, are permitted provided that the following conditions are met:
12+ * Redistributions of source code must retain the above copyright
13+ notice, this list of conditions and the following disclaimer.
14+ * Redistributions in binary form must reproduce the above copyright
15+ notice, this list of conditions and the following disclaimer in the
16+ documentation and/or other materials provided with the distribution.
17+ * Neither the name of the Daemon developers nor the
18+ names of its contributors may be used to endorse or promote products
19+ derived from this software without specific prior written permission.
20+
21+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+ DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
25+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
32+ ===========================================================================
33+ */
34+ // EngineAllocator.cpp
35+
36+ #include " ../Vulkan.h"
37+
38+ #include " ../../Error.h"
39+
40+ #include " ../../Math/Bit.h"
41+
42+ #include " ../GraphicsCoreStore.h"
43+
44+ #include " ../../GraphicsShared/Bindings.h"
45+
46+ #include " EngineAllocator.h"
47+
48+ constexpr VkSampleCountFlags SamplesToEnum ( const uint32 samples ) {
49+ switch ( samples ) {
50+ case 1 :
51+ return VK_SAMPLE_COUNT_1_BIT;
52+ case 2 :
53+ return VK_SAMPLE_COUNT_2_BIT;
54+ case 4 :
55+ return VK_SAMPLE_COUNT_4_BIT;
56+ case 8 :
57+ return VK_SAMPLE_COUNT_8_BIT;
58+ case 16 :
59+ return VK_SAMPLE_COUNT_16_BIT;
60+ case 32 :
61+ return VK_SAMPLE_COUNT_32_BIT;
62+ case 64 :
63+ return VK_SAMPLE_COUNT_64_BIT;
64+ default :
65+ Err ( " Image sample count must be one of: 1, 2, 4, 8, 16, 32, 64" );
66+ return VK_SAMPLE_COUNT_1_BIT;
67+ }
68+ }
69+
70+ MemoryRequirements GetImageRequirements ( const VkImageType type, const VkFormat format, const bool useMipMaps,
71+ const bool storageImage, const uint32 width, const uint32 height, const uint32 depth, const uint32 layers,
72+ const uint32 samples ) {
73+ const uint32 mips = useMipMaps ? log2f ( std::max ( std::max ( width, height ), depth ) ) + 1 : 1 ;
74+
75+ VkImageCreateInfo imageInfo {
76+ .imageType = type,
77+ .format = format,
78+ .extent = { width, height, depth },
79+ .mipLevels = mips,
80+ .arrayLayers = layers,
81+ .samples = ( VkSampleCountFlagBits ) SamplesToEnum ( samples ),
82+ .tiling = VK_IMAGE_TILING_OPTIMAL,
83+ .usage = ( VkFlags ) ( storageImage ? VK_IMAGE_USAGE_STORAGE_BIT : VK_IMAGE_USAGE_SAMPLED_BIT ),
84+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
85+ .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED
86+ };
87+
88+ VkDeviceImageMemoryRequirements reqs {
89+ .pCreateInfo = &imageInfo
90+ };
91+
92+ VkMemoryDedicatedRequirements dedicatedReqs {};
93+
94+ VkMemoryRequirements2 out { .pNext = &dedicatedReqs };
95+
96+ vkGetDeviceImageMemoryRequirements ( device, &reqs, &out );
97+
98+ return {
99+ out.memoryRequirements .size , out.memoryRequirements .alignment , out.memoryRequirements .memoryTypeBits ,
100+ ( bool ) dedicatedReqs.prefersDedicatedAllocation
101+ };
102+ }
103+
104+ MemoryRequirements GetImage2DRequirements ( const VkFormat format, const bool useMipMaps,
105+ const bool storageImage, const uint32 width, const uint32 height ) {
106+ return GetImageRequirements ( VK_IMAGE_TYPE_2D, format, useMipMaps, storageImage, width, height, 0 , 1 , 1 );
107+ }
108+
109+ MemoryRequirements GetImage3DRequirements ( const VkFormat format, const bool useMipMaps,
110+ const bool storageImage, const uint32 width, const uint32 depth, const uint32 height ) {
111+ return GetImageRequirements ( VK_IMAGE_TYPE_2D, format, useMipMaps, storageImage, width, height, depth, 1 , 1 );
112+ }
113+
114+ MemoryRequirements GetBufferRequirements ( const VkBufferUsageFlags type, const uint64 size ) {
115+ VkBufferCreateInfo bufferInfo {
116+ .size = size,
117+ .usage = type,
118+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE
119+ };
120+
121+ VkDeviceBufferMemoryRequirements reqs2 {
122+ .pCreateInfo = &bufferInfo
123+ };
124+
125+ VkMemoryRequirements2 out {};
126+
127+ vkGetDeviceBufferMemoryRequirements ( device, &reqs2, &out );
128+
129+ return {
130+ out.memoryRequirements .size , out.memoryRequirements .alignment , out.memoryRequirements .memoryTypeBits
131+ };
132+ }
133+
134+ static constexpr VkMemoryPropertyFlags memoryTypeGPU =
135+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
136+ static constexpr VkMemoryPropertyFlags memoryTypeBAR =
137+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
138+ static constexpr VkMemoryPropertyFlags memoryTypeGPUToCPU =
139+ VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
140+
141+ static constexpr VkMemoryPropertyFlags memoryTypeUnified =
142+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
143+ | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
144+
145+ MemoryHeap EngineAllocator::MemoryHeapForUsage ( const MemoryHeap::MemoryType type, const MemoryRequirements& reqs ) {
146+ VkPhysicalDeviceMemoryBudgetPropertiesEXT properties {};
147+ VkPhysicalDeviceMemoryProperties2 properties2 {
148+ .pNext = &properties
149+ };
150+
151+ vkGetPhysicalDeviceMemoryProperties2 ( physicalDevice, &properties2 );
152+
153+ VkPhysicalDeviceMemoryProperties& memoryProperties = properties2.memoryProperties ;
154+
155+ uint32 memoryRegion;
156+ uint32 memoryID;
157+
158+ if ( unifiedMemory ) {
159+ memoryRegion = memoryRegionEngine;
160+ memoryID = memoryIDEngine;
161+ } else {
162+ switch ( type ) {
163+ default :
164+ case MemoryHeap::ENGINE:
165+ memoryRegion = memoryRegionEngine;
166+ memoryID = memoryIDEngine;
167+ break ;
168+ case MemoryHeap::CORE_TO_ENGINE:
169+ memoryRegion = memoryRegionBAR;
170+ memoryID = memoryIDCoreToEngine;
171+ break ;
172+ case MemoryHeap::ENGINE_TO_CORE:
173+ memoryRegion = memoryRegionCore;
174+ memoryID = memoryIDEngineToCore;
175+ break ;
176+ }
177+ }
178+
179+ MemoryHeap memoryHeap {
180+ properties.heapBudget [memoryRegion] - properties.heapUsage [memoryRegion],
181+ properties.heapBudget [memoryRegion],
182+ type
183+ };
184+
185+ uint32 supportedTypes = reqs.type ;
186+
187+ while ( supportedTypes ) {
188+ const uint32 id = FindLSB ( supportedTypes );
189+ const VkMemoryType& memoryType = memoryProperties.memoryTypes [id];
190+
191+ if ( !BitSet ( memoryID, id ) ) {
192+ UnSetBit ( &supportedTypes, id );
193+ continue ;
194+ }
195+
196+ if ( type == MemoryHeap::ENGINE && memoryType.propertyFlags & memoryTypeGPU ||
197+ type == MemoryHeap::CORE_TO_ENGINE && memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
198+ || type == MemoryHeap::ENGINE_TO_CORE && memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT ) {
199+ memoryHeap.id = id;
200+
201+ return memoryHeap;
202+ }
203+
204+ UnSetBit ( &supportedTypes, id );
205+ }
206+
207+ Err ( " No suitable MemoryHeap found" );
208+ return memoryHeap;
209+ }
210+
211+ void EngineAllocator::Init () {
212+ memoryPoolCount = 0 ;
213+
214+ VkPhysicalDeviceMemoryBudgetPropertiesEXT properties {};
215+ VkPhysicalDeviceMemoryProperties2 properties2 {
216+ .pNext = &properties
217+ };
218+
219+ vkGetPhysicalDeviceMemoryProperties2 ( physicalDevice, &properties2 );
220+
221+ VkPhysicalDeviceMemoryProperties& memoryProperties = properties2.memoryProperties ;
222+
223+ memoryIDEngine = 0 ;
224+ memoryIDCoreToEngine = 0 ;
225+ memoryIDEngineToCore = 0 ;
226+
227+ if ( memoryProperties.memoryHeapCount == 1 ) {
228+ unifiedMemory = true ;
229+ rebar = false ;
230+
231+ for ( uint32 i = 0 ; i < memoryProperties.memoryTypeCount ; i++ ) {
232+ const VkMemoryType& memoryType = memoryProperties.memoryTypes [i];
233+
234+ if ( memoryType.propertyFlags & memoryTypeUnified ) {
235+ memoryIDEngine = i;
236+ break ;
237+ }
238+ }
239+
240+ if ( memoryIDEngine == UINT_MAX ) {
241+ Err ( " Couldn't find memory type for ENGINE" );
242+ }
243+
244+ memoryTypeEngine = memoryTypeUnified;
245+ memoryTypeCoreToEngine = memoryTypeUnified;
246+ memoryTypeEngineToCore = memoryTypeUnified;
247+
248+ memoryIDCoreToEngine = memoryIDEngine;
249+ memoryIDEngineToCore = memoryIDEngine;
250+ } else {
251+ for ( uint32 i = 0 ; i < memoryProperties.memoryHeapCount ; i++ ) {
252+ const VkMemoryHeap& memoryRegion = memoryProperties.memoryHeaps [i];
253+
254+ for ( uint32 j = 0 ; j < memoryProperties.memoryTypeCount ; j++ ) {
255+ const VkMemoryType& memoryType = memoryProperties.memoryTypes [j];
256+
257+ if ( memoryType.heapIndex != i ) {
258+ continue ;
259+ }
260+
261+ if ( memoryRegion.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT ) {
262+ if ( memoryType.propertyFlags & memoryTypeGPU
263+ && !( memoryType.propertyFlags & ( VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
264+ | VK_MEMORY_PROPERTY_HOST_CACHED_BIT ) ) ) {
265+ if ( memoryRegionEngine == UINT_MAX ) {
266+ memoryRegionEngine = i;
267+ }
268+
269+ SetBit ( &memoryIDEngine, j );
270+ continue ;
271+ }
272+
273+ if ( memoryType.propertyFlags & memoryTypeBAR
274+ && !( memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT ) ) {
275+ if ( memoryRegionBAR == UINT_MAX ) {
276+ memoryRegionBAR = i;
277+ }
278+
279+ SetBit ( &memoryIDCoreToEngine, j );
280+ continue ;
281+ }
282+ } else {
283+ if ( memoryType.propertyFlags & memoryTypeGPUToCPU ) {
284+ if ( memoryRegionCore == UINT_MAX ) {
285+ memoryRegionCore = i;
286+ }
287+
288+ SetBit ( &memoryIDEngineToCore, j );
289+ continue ;
290+ }
291+ }
292+ }
293+ }
294+
295+ if ( memoryRegionCore == UINT_MAX ) {
296+ Err ( " Couldn't find memory type for ENGINE_TO_CORE" );
297+ }
298+
299+ if ( memoryRegionEngine == UINT_MAX ) {
300+ Err ( " Couldn't find memory type for ENGINE" );
301+ }
302+
303+ if ( memoryRegionBAR == UINT_MAX ) {
304+ Err ( " Couldn't find memory type for CORE_TO_ENGINE" );
305+ }
306+
307+ if ( memoryRegionEngine == memoryRegionBAR ) {
308+ rebar = true ;
309+ }
310+
311+ memoryTypeEngine = memoryTypeGPU;
312+ memoryTypeCoreToEngine = memoryTypeBAR;
313+ memoryTypeEngineToCore = memoryTypeGPUToCPU;
314+ }
315+
316+ MemoryRequirements reqs;
317+ reqs = GetImage2DRequirements ( VK_FORMAT_R8G8B8A8_UNORM, true , false , 1024 , 1024 );
318+ memoryHeapImages = MemoryHeapForUsage ( MemoryHeap::ENGINE, reqs );
319+
320+ reqs = GetImage2DRequirements ( VK_FORMAT_R8G8B8A8_UNORM, false , true , 1024 , 1024 );
321+ memoryHeapStorageImages = MemoryHeapForUsage ( MemoryHeap::ENGINE, reqs );
322+
323+ reqs = GetBufferRequirements ( VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 262144 );
324+ memoryHeapStagingBuffer = MemoryHeapForUsage ( MemoryHeap::CORE_TO_ENGINE, reqs );
325+ }
326+
327+ void EngineAllocator::Free () {
328+ for ( MemoryPool* memoryPool = memoryPools; memoryPool < memoryPools + memoryPoolCount; memoryPool++ ) {
329+ vkFreeMemory ( device, ( VkDeviceMemory ) memoryPool->memory , nullptr );
330+ }
331+ }
0 commit comments