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
175
|
/*
* Vulkan buffer class
*
* Encapsulates a Vulkan buffer
*
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
#pragma once
#include "vke.h"
#include "VulkanDevice.hpp"
#include "resource.hpp"
namespace vks
{
struct Buffer : public Resource
{
VkBuffer buffer = VK_NULL_HANDLE;
VkBufferCreateInfo infos = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
VkDescriptorBufferInfo descriptor;
VkDeviceSize size = 0;
VkDeviceSize alignment = 0;
void* mapped = nullptr;
/** @brief Usage flags to be filled by external source at buffer creation (to query at some later point) */
VkBufferUsageFlags usageFlags;
/** @brief Memory propertys flags to be filled by external source at buffer creation (to query at some later point) */
VkMemoryPropertyFlags memoryPropertyFlags;
void create(ptrVkDev _device, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags _memoryPropertyFlags, VkDeviceSize size, void *data = nullptr)
{
device = _device;
infos.size = size;
infos.usage = usageFlags;
infos.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
memoryPropertyFlags = _memoryPropertyFlags;
VK_CHECK_RESULT(vkCreateBuffer(device->dev, &infos, nullptr, &buffer));
vkGetBufferMemoryRequirements(device->dev, buffer, &memReqs);
VkMemoryAllocateInfo memAlloc = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
memAlloc.allocationSize = memReqs.size;
memAlloc.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, _memoryPropertyFlags);
VK_CHECK_RESULT(vkAllocateMemory(device->dev, &memAlloc, nullptr, &deviceMemory));
size = memAlloc.allocationSize;
// If a pointer to the buffer data has been passed, map the buffer and copy over the data
if (data != nullptr)
{
VK_CHECK_RESULT(map());
memcpy(mapped, data, size);
unmap();
}
// Initialize a default descriptor that covers the whole buffer size
setupDescriptor();
// Attach the memory to the buffer object
VK_CHECK_RESULT(bind());
}
VkResult map(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0)
{
return vkMapMemory(device->dev, deviceMemory, offset, size, 0, &mapped);
}
void unmap()
{
if (mapped)
{
vkUnmapMemory(device->dev, deviceMemory);
mapped = nullptr;
}
}
VkResult bind(VkDeviceSize offset = 0)
{
return vkBindBufferMemory(device->dev, buffer, deviceMemory, offset);
}
void setupDescriptor(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0)
{
descriptor.offset = offset;
descriptor.buffer = buffer;
descriptor.range = size;
}
virtual VkWriteDescriptorSet getWriteDescriptorSet(VkDescriptorSet ds, uint32_t binding, VkDescriptorType descriptorType) {
VkWriteDescriptorSet wds = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET};
wds.dstSet = ds;
wds.descriptorType = descriptorType;
wds.dstBinding = binding;
wds.descriptorCount = 1;
wds.pBufferInfo = &descriptor;
return wds;
}
/**
* Copies the specified data to the mapped buffer
*
* @param data Pointer to the data to copy
* @param size Size of the data to copy in machine units
*
*/
void copyTo(void* data, VkDeviceSize size)
{
assert(mapped);
memcpy(mapped, data, size);
}
/**
* Flush a memory range of the buffer to make it visible to the device
*
* @note Only required for non-coherent memory
*
* @param size (Optional) Size of the memory range to flush. Pass VK_WHOLE_SIZE to flush the complete buffer range.
* @param offset (Optional) Byte offset from beginning
*
* @return VkResult of the flush call
*/
VkResult flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0)
{
VkMappedMemoryRange mappedRange = {};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = deviceMemory;
mappedRange.offset = offset;
mappedRange.size = size;
return vkFlushMappedMemoryRanges(device->dev, 1, &mappedRange);
}
/**
* Invalidate a memory range of the buffer to make it visible to the host
*
* @note Only required for non-coherent memory
*
* @param size (Optional) Size of the memory range to invalidate. Pass VK_WHOLE_SIZE to invalidate the complete buffer range.
* @param offset (Optional) Byte offset from beginning
*
* @return VkResult of the invalidate call
*/
VkResult invalidate(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0)
{
VkMappedMemoryRange mappedRange = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE};
mappedRange.memory = deviceMemory;
mappedRange.offset = offset;
mappedRange.size = size;
return vkInvalidateMappedMemoryRanges(device->dev, 1, &mappedRange);
}
/**
* Release all Vulkan resources held by this buffer
*/
void destroy()
{
unmap();
if (deviceMemory)
vkFreeMemory(device->dev, deviceMemory, nullptr);
if (buffer)
vkDestroyBuffer(device->dev, buffer, nullptr);
}
};
}
|