-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathv_memory.c
174 lines (147 loc) · 5.93 KB
/
v_memory.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#include "v_memory.h"
#include "v_video.h"
#include "def.h"
#include <stdio.h>
#include <vulkan/vulkan_core.h>
#include <assert.h>
// HVC = Host Visible and Coherent
#define MEMORY_SIZE_HVC 524288 // 512 KiB
#define BUFFER_SIZE_HVC 262144 // 256 KiB
// DL = Device Local
#define MEMORY_SIZE_DL 33554432 // 32 MiB
#define MAX_BLOCKS 256
static VkDeviceMemory memoryHostVisibleCoherent;
static VkDeviceMemory memoryDeviceLocal;
static VkBuffer bufferHostMapped;
uint8_t* hostBuffer;
static VkPhysicalDeviceMemoryProperties memoryProperties;
static V_block blocks[MAX_BLOCKS];
static int blockCount = 0;
static int bytesAvailable = BUFFER_SIZE_HVC;
static int curBufferOffset = 0;
static void printBufferMemoryReqs(const VkMemoryRequirements* reqs)
{
printf("Size: %ld\tAlignment: %ld\n", reqs->size, reqs->alignment);
}
void v_InitMemory(void)
{
VkResult r;
int hostVisibleCoherentTypeIndex;
int deviceLocalTypeIndex;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
V1_PRINT("Memory Heap Info:\n");
for (int i = 0; i < memoryProperties.memoryHeapCount; i++)
{
V1_PRINT("Heap %d: Size %ld: %s local\n",
i,
memoryProperties.memoryHeaps[i].size,
memoryProperties.memoryHeaps[i].flags
& VK_MEMORY_HEAP_DEVICE_LOCAL_BIT ? "Device" : "Host");
// note there are other possible flags, but seem to only deal with multiple gpus
}
bool foundHvc = false;
bool foundDl = false;
V1_PRINT("Memory Type Info:\n");
for (int i = 0; i < memoryProperties.memoryTypeCount; i++)
{
VkMemoryPropertyFlags flags = memoryProperties.memoryTypes[i].propertyFlags;
V1_PRINT("Type %d: Heap Index: %d Flags: | %s%s%s%s%s%s\n",
i,
memoryProperties.memoryTypes[i].heapIndex,
flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ? "Device Local | " : "",
flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT ? "Host Visible | " : "",
flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ? "Host Coherent | " : "",
flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT ? "Host Cached | " : "",
flags & VK_MEMORY_PROPERTY_PROTECTED_BIT ? "Protected | " : "",
flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT ? "Lazily allocated | " : ""
);
if ((flags & (VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) &&
!foundHvc)
{
hostVisibleCoherentTypeIndex = i;
foundHvc = true;
}
if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) && !foundDl)
{
deviceLocalTypeIndex = i;
foundDl = true;
}
}
assert( foundHvc );
assert( foundDl );
const VkMemoryAllocateInfo allocInfo = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.allocationSize = MEMORY_SIZE_HVC,
.memoryTypeIndex = hostVisibleCoherentTypeIndex
};
r = vkAllocateMemory(device, &allocInfo, NULL, &memoryHostVisibleCoherent);
assert( VK_SUCCESS == r );
VkBufferCreateInfo ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, // queue determined by first use
.size = BUFFER_SIZE_HVC
};
r = vkCreateBuffer(device, &ci, NULL, &bufferHostMapped);
assert( VK_SUCCESS == r );
VkMemoryRequirements reqs;
vkGetBufferMemoryRequirements(device, bufferHostMapped, &reqs);
// we dont need to check the reqs. spec states that
// any buffer created without SPARSITY flags will
// support being bound to host visible | host coherent
r = vkBindBufferMemory(device, bufferHostMapped, memoryHostVisibleCoherent, 0);
assert( VK_SUCCESS == r );
r = vkMapMemory(device, memoryHostVisibleCoherent, 0, BUFFER_SIZE_HVC, 0, (void**)&hostBuffer);
assert( VK_SUCCESS == r );
// --------------------------------------------------------
// allocate device local memory
// --------------------------------------------------------
const VkMemoryAllocateInfo allocInfoDl = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.allocationSize = MEMORY_SIZE_DL,
.memoryTypeIndex = deviceLocalTypeIndex
};
r = vkAllocateMemory(device, &allocInfoDl, NULL, &memoryDeviceLocal);
assert( VK_SUCCESS == r );
}
V_block* v_RequestBlock(const size_t size)
{
assert( size % 4 == 0 ); // only allow for word-sized blocks
assert( size < bytesAvailable);
assert( blockCount < MAX_BLOCKS );
V_block* pBlock = &blocks[blockCount];
pBlock->address = hostBuffer + curBufferOffset;
pBlock->vBuffer = &bufferHostMapped;
pBlock->size = size;
pBlock->vOffset = curBufferOffset;
pBlock->isMapped = true;
bytesAvailable -= size;
curBufferOffset += size;
blockCount++;
// we really do need to be worrying about alignment here.
// anything that is not a multiple of 4 bytes will have issues.
// there is VERY GOOD CHANCE that there are other alignment
// issues to consider.
//
// we should probably divide up the buffer into Chunks, where
// all the blocks in a chunk contain the same kind of element
// (a chunk for vertices, a chunk for indices, a chunk for
// uniform matrices, etc).
return pBlock;
}
void v_BindImageToMemory(const VkImage image)
{
static bool imageBound = false;
assert (!imageBound);
vkBindImageMemory(device, image, memoryDeviceLocal, 0);
imageBound = true;
}
void v_CleanUpMemory()
{
vkUnmapMemory(device, memoryHostVisibleCoherent);
vkDestroyBuffer(device, bufferHostMapped, NULL);
vkFreeMemory(device, memoryHostVisibleCoherent, NULL);
vkFreeMemory(device, memoryDeviceLocal, NULL);
};