You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The constructor just receives the `device` that will be used to create this buffer, its size, a parameter named `usage` which will state what this buffer should be used for and a bit mask. This last parameter is use to set the requested memory properties that the data associated to this buffer should use. We will review how these two last parameters are used later on. In order to create a Buffer we need to setup a structure named `VkBufferCreateInfo`, which defines the following attributes:
35
+
The constructor just receives the `device` that will be used to create this buffer, its size, a parameter named `usage` which will state what this buffer should be used for and a bit mask. This last parameter is use to set the requested memory properties that the data associated to this buffer should use. We will review how these two last parameters are used later on. The class also defines an attribute named `mappedMemory` which is a handle that will be used when mapping the buffer memory so it can be accessed from our application (if the buffer is created with the appropriate flags to be accessible from the CPU). In order to create a Buffer we need to setup a structure named `VkBufferCreateInfo`, which defines the following attributes:
35
36
36
37
-`sType`: It shall have the `VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO` value.
37
38
-`size`: The number of bytes that the buffer will hold.
@@ -99,7 +100,7 @@ public class VulkanUtils {
99
100
}
100
101
```
101
102
102
-
The `typeBits` attribute is a bit mask which defines the supported memory types of the physical device. A bit set to `1` means that the type of memory (associated to that index) is supported. The `reqMask` attribute is the type of memory that we need (for example if that memory will be accessed only by the GPU or also by the application). This method basically iterates over all the memory types, checking if that memory index (first condition) is supported by the device and if that it meets the requested type (second condition). Now we can go back to the `VulkanBuffer` constructor and invoke the `vkAllocateMemory` to allocate the memory. After that we can get the finally allocated size and get a handle to that chunk of memory.
103
+
The `typeBits` attribute is a bit mask which defines the supported memory types of the physical device. A bit set to `1` means that the type of memory (associated to that index) is supported. The `reqMask` attribute is the type of memory that we need (for example if that memory will be accessed only by the GPU or also by the application). This method basically iterates over all the memory types, checking if that memory index (first condition) is supported by the device and if that it meets the requested type (second condition). Now we can go back to the `VulkanBuffer` constructor and invoke the `vkAllocateMemory` to allocate the memory. After that we can get the finally allocated size and get a handle to that chunk of memory. We also allocate a `PointerBuffer` which will be used in other methods of the class.
103
104
104
105
```java
105
106
publicclassVulkanBuffer {
@@ -109,6 +110,7 @@ public class VulkanBuffer {
109
110
vkCheck(vkAllocateMemory(device.getVkDevice(), memAlloc, null, lp), "Failed to allocate memory");
110
111
allocationSize = memAlloc.allocationSize();
111
112
memory = lp.get(0);
113
+
pb =PointerBuffer.allocateDirect(1);
112
114
...
113
115
}
114
116
...
@@ -139,24 +141,39 @@ public class VulkanBuffer {
139
141
vkFreeMemory(device.getVkDevice(), memory, null);
140
142
}
141
143
142
-
publiclonggetAllocationSize() {
143
-
return allocationSize;
144
-
}
145
-
146
144
publiclonggetBuffer() {
147
145
return buffer;
148
146
}
149
147
150
-
publiclonggetMemory() {
151
-
return memory;
152
-
}
153
-
154
148
publiclonggetRequestedSize() {
155
149
return requestedSize;
156
150
}
151
+
...
157
152
}
158
153
```
159
154
155
+
To complete the class, we define two methods to map and un-map the memory associated to the buffer so it can be accessed from our application (if they have been created with the flag `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, more on this later on). The `map` method just calls the `vkMapMemory` function which returns a handle that can be used to get a buffer to read / write its contents. The `unMap` method just calls the `vkUnmapMemory` to un-map the previously mapped buffer memory:
156
+
```java
157
+
publicclassVulkanBuffer {
158
+
...
159
+
publiclongmap() {
160
+
if (mappedMemory ==NULL) {
161
+
vkCheck(vkMapMemory(device.getVkDevice(), memory, 0, allocationSize, 0, pb), "Failed to map Buffer");
162
+
mappedMemory = pb.get(0);
163
+
}
164
+
return mappedMemory;
165
+
}
166
+
167
+
publicvoidunMap() {
168
+
if (mappedMemory !=NULL) {
169
+
vkUnmapMemory(device.getVkDevice(), memory);
170
+
mappedMemory =NULL;
171
+
}
172
+
}
173
+
}
174
+
175
+
```
176
+
160
177
## Vertex description
161
178
162
179
We have now created the buffers required to hold the data for vertices, the next step is to describe to Vulkan the format of that data. As you can guess, depending on the specific case, the structure of that data may change, we may have just position coordinates, or position with texture coordinates and normals, etc. Some of the vulkan elements that we will define later on, will need a handle to that structure. In order to support this, we will create an abstract class named `VertexInputStateInfo`, which just stores the handle to a `VkPipelineVertexInputStateCreateInfo` structure:
FloatBuffer data =MemoryUtil.memFloatBuffer(mappedMemory, (int) srcBuffer.getRequestedSize());
459
+
data.put(positions);
460
+
srcBuffer.unMap();
450
461
451
462
returnnewTransferBuffers(srcBuffer, dstBuffer);
452
463
}
@@ -461,7 +472,7 @@ The intermediate buffer is created with the `VK_BUFFER_USAGE_TRANSFER_SRC_BIT` f
461
472
462
473
The destination buffer is created with the `VK_BUFFER_USAGE_TRANSFER_DST_BIT` as its usage parameter. With this flag we state that this buffer can used as the destination of a transfer command. We also set the flag `VK_BUFFER_USAGE_VERTEX_BUFFER_BIT` since it will be used for handling vertices data. For the `reqMask` attribute we use the `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT` flag which states that the memory allocated by this buffer will be used by the GPU.
463
474
464
-
Once the buffers have been created we need to populate the source buffer. In order to do that, we need to map that memory in order to get a pointer to it so we can upload the data. This is done by calling the `vkMapMemory` function. Now we have a pointer to the memory of the buffer which we will use to load the positions. After we have finished copying the data to the source buffer we call the `vkUnmapMemory`.
475
+
Once the buffers have been created we need to populate the source buffer. In order to do that, we need to map that memory in order to get a pointer to it so we can upload the data. This is done by calling the `map` method on the buffer instance. Now we have a pointer to the memory of the buffer which we will use to load the positions. After we have finished copying the data to the source buffer we call the `unMap` method over the buffer.
465
476
466
477
The definition of the `createIndicesBuffers` is similar:
We just create a new `VulkanBuffer` instance which size will be calculated assuming a RGBA model with one byte per channel. The buffer will be used to transfer the image data, this is why we use the `VK_BUFFER_USAGE_TRANSFER_SRC_BIT` flag and the `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` (we will be loading the image from our application). We do not want to perform any flush operation while transferring the data so we also use the `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` flag. After the buffer has been created, we just map the memory associated to it ans we just copy the image contents.
385
+
We just create a new `VulkanBuffer` instance which size will be calculated assuming a RGBA model with one byte per channel. The buffer will be used to transfer the image data, this is why we use the `VK_BUFFER_USAGE_TRANSFER_SRC_BIT` flag and the `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` (we will be loading the image from our application). We do not want to perform any flush operation while transferring the data so we also use the `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` flag. After the buffer has been created, we just map the memory associated to it and copy the image contents.
390
386
391
387
The `Texture` class defines a `cleanup` method to free the resources and special method named `cleanupStgBuffer` to free the staging buffer when is no longer needed. It also provides some *getters* to get the path to the file used to load the texture and the image view.
392
388
@@ -1214,7 +1210,7 @@ public class ForwardRenderActivity {
In the `updateMaterial` method, we just map the buffer and dump the material diffuse color to the appropriate offset.
760
753
761
754
Finally, we just need to update a little bit the way we record the commands to bind the additional descriptor sets and to use the dynamic uniform buffers:
@@ -769,7 +762,7 @@ public class ForwardRenderActivity {
0 commit comments