-
-
Save CFSworks/de6c094fdaa472b642290684f3d998d0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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