Skip to content

Instantly share code, notes, and snippets.

@CFSworks
Created April 1, 2024 08:58
Show Gist options
  • Save CFSworks/de6c094fdaa472b642290684f3d998d0 to your computer and use it in GitHub Desktop.
Save CFSworks/de6c094fdaa472b642290684f3d998d0 to your computer and use it in GitHub Desktop.
#include <vulkan/vulkan.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_LOOPS 64
#define BUFSIZE(i) (0x10000 << ((i)/8))
uint32_t memoryTypeIndex;
int allocate_buffer(size_t bytes, VkDevice device, VkBuffer *buffer,
VkDeviceMemory *memory) {
VkResult result;
VkMemoryAllocateInfo allocateInfo = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.allocationSize = bytes,
.memoryTypeIndex = memoryTypeIndex,
};
result = vkAllocateMemory(device, &allocateInfo, NULL, memory);
if (result != VK_SUCCESS) {
printf("Failed to allocate device memory.\n");
return result;
}
if (buffer != NULL) {
VkBufferCreateInfo bufferCreateInfo = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = bytes,
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
result = vkCreateBuffer(device, &bufferCreateInfo, NULL, buffer);
if (result != VK_SUCCESS) {
printf("Failed to create buffer.\n");
return result;
}
result = vkBindBufferMemory(device, *buffer, *memory, 0);
if (result != VK_SUCCESS) {
printf("Failed to bind buffer to device memory.\n");
return result;
}
}
return VK_SUCCESS;
}
int main() {
VkResult result;
VkInstance instance;
// Initialize the Vulkan instance
VkInstanceCreateInfo createInfo = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
};
result = vkCreateInstance(&createInfo, NULL, &instance);
if (result != VK_SUCCESS) {
printf("Failed to create Vulkan instance.\n");
return -1;
}
// Select a physical device
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(instance, &deviceCount, NULL);
if (deviceCount == 0) {
printf("Failed to find GPUs with Vulkan support.\n");
return -1;
}
VkPhysicalDevice* devices = (VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice) * deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, devices);
physicalDevice = devices[0]; // Just pick the first device
free(devices);
// Determine the memory type to use for all on-device allocations
VkPhysicalDeviceMemoryProperties props;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &props);
int found = 0;
VkMemoryPropertyFlags desiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
| VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
for (int i = 0; i < props.memoryTypeCount; i++) {
if ((props.memoryTypes[i].propertyFlags & desiredFlags) == desiredFlags) {
memoryTypeIndex = i;
found = 1;
}
}
if (!found) {
printf("No suitable memory type?\n");
return -1;
}
// Create a logical device and queues
float queuePriority = 1.0f;
VkDeviceQueueCreateInfo queueCreateInfo = {
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.queueFamilyIndex = 0,
.queueCount = 1,
.pQueuePriorities = &queuePriority,
};
VkDeviceCreateInfo deviceCreateInfo = {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.queueCreateInfoCount = 1,
.pQueueCreateInfos = &queueCreateInfo,
};
VkDevice device;
result = vkCreateDevice(physicalDevice, &deviceCreateInfo, NULL, &device);
if (result != VK_SUCCESS) {
printf("Failed to create logical device.\n");
return -1;
}
VkQueue queue;
vkGetDeviceQueue(device, 0, 0, &queue);
// Create our main test buffer (accessed repeatedly on-GPU)
VkBuffer buffer;
VkDeviceMemory memory;
result = allocate_buffer(0x10000, device, &buffer, &memory);
if (result != VK_SUCCESS) {
printf("Failed to allocate the test buffer.\n");
return -1;
}
// Create a command pool
VkCommandPool commandPool;
VkCommandPoolCreateInfo poolCreateInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
.queueFamilyIndex = 0,
};
result = vkCreateCommandPool(device, &poolCreateInfo, NULL, &commandPool);
if (result != VK_SUCCESS) {
printf("Failed to create command pool.\n");
return -1;
}
// Allocate a command buffer from the pool
VkCommandBuffer commandBuffer;
VkCommandBufferAllocateInfo allocInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.commandPool = commandPool,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = 1,
};
result = vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);
if (result != VK_SUCCESS) {
printf("Failed to allocate command buffer.\n");
return -1;
}
// Start recording the command buffer
VkCommandBufferBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
};
result = vkBeginCommandBuffer(commandBuffer, &beginInfo);
if (result != VK_SUCCESS) {
printf("Failed to begin recording command buffer.\n");
return -1;
}
// A "fill buffer" command makes the GPU write to its view of the buffer
vkCmdFillBuffer(commandBuffer, buffer, 0, 0x10000, 0);
// End recording
result = vkEndCommandBuffer(commandBuffer);
if (result != VK_SUCCESS) {
printf("Failed to record command buffer.\n");
return -1;
}
// Interleave on-GPU memory accesses, VA growth, and host<->GPU accesses
VkDeviceMemory extraMemories[NUM_LOOPS];
void *maps[NUM_LOOPS];
for (int i = 0; i < NUM_LOOPS; i++) {
printf("Submission #%d...\n", i);
VkSubmitInfo submitInfo = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.commandBufferCount = 1,
.pCommandBuffers = &commandBuffer,
};
result = vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);
if (result != VK_SUCCESS) {
printf("Failed to submit command buffer to queue.\n");
return -1;
}
// Wait for the queue to finish
result = vkQueueWaitIdle(queue);
if (result != VK_SUCCESS) {
printf("Failed to wait for the queue to become idle.\n");
return -1;
}
result = allocate_buffer(BUFSIZE(i), device, NULL, &extraMemories[i]);
if (result != VK_SUCCESS) {
printf("Failed to allocate extra buffer.\n");
return -1;
}
result = vkMapMemory(device, extraMemories[i], 0, BUFSIZE(i), 0, &maps[i]);
if (result != VK_SUCCESS) {
printf("Failed to map extra buffer.\n");
return -1;
}
// Generate a flurry of bus activity
for (int k = 0; k < 500; k++)
for (int j = 0; j < i; j++)
memset(maps[j], 0xAA, BUFSIZE(j));
}
// Clean up
for (int i = 0; i < NUM_LOOPS; i++)
vkFreeMemory(device, extraMemories[i], NULL);
vkFreeMemory(device, memory, NULL);
vkDestroyBuffer(device, buffer, NULL);
vkDestroyCommandPool(device, commandPool, NULL);
vkDestroyDevice(device, NULL);
vkDestroyInstance(instance, NULL);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment