1
0
mirror of https://github.com/Yours3lf/rpi-vk-driver.git synced 2024-11-29 11:24:14 +01:00
rpi-vk-driver/test/texturing/texturing.cpp
2019-09-23 11:13:43 +01:00

1787 lines
63 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <iostream>
#include <vector>
#include <algorithm>
#include <string.h>
#include "driver/CustomAssert.h"
#include <vulkan/vulkan.h>
#include "driver/vkExt.h"
//#define GLFW_INCLUDE_VULKAN
//#define VK_USE_PLATFORM_WIN32_KHR
//#include <GLFW/glfw3.h>
//#define GLFW_EXPOSE_NATIVE_WIN32
//#include <GLFW/glfw3native.h>
//GLFWwindow * window;
//#define WINDOW_WIDTH 640
//#define WINDOW_HEIGHT 480
// Note: support swap chain recreation (not only required for resized windows!)
// Note: window resize may not result in Vulkan telling that the swap chain should be recreated, should be handled explicitly!
void run();
void setupVulkan();
void mainLoop();
void cleanup();
void createInstance();
void createWindowSurface();
void findPhysicalDevice();
void checkSwapChainSupport();
void findQueueFamilies();
void createLogicalDevice();
void createSemaphores();
void createSwapChain();
void createCommandQueues();
void draw();
void CreateRenderPass();
void CreateFramebuffer();
void CreateShaders();
void CreatePipeline();
void CreateDescriptorSet();
void CreateVertexBuffer();
void CreateTexture();
void recordCommandBuffers();
VkSurfaceFormatKHR chooseSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& surfaceCapabilities);
VkPresentModeKHR choosePresentMode(const std::vector<VkPresentModeKHR> presentModes);
VkInstance instance; //
VkSurfaceKHR windowSurface; //
VkPhysicalDevice physicalDevice;
VkDevice device; //
VkSemaphore imageAvailableSemaphore; //
VkSemaphore renderingFinishedSemaphore; //
VkSwapchainKHR swapChain; //
VkCommandPool commandPool; //
std::vector<VkCommandBuffer> presentCommandBuffers; //
std::vector<VkImage> swapChainImages; //
VkRenderPass renderPass; //
std::vector<VkFramebuffer> fbs; //
VkShaderModule blitShaderModule; //
VkShaderModule sampleShaderModule; //
VkPipeline blitPipeline; //
VkPipeline samplePipeline; //
VkQueue graphicsQueue;
VkQueue presentQueue;
VkBuffer fsqVertexBuffer;
VkDeviceMemory fsqVertexBufferMemory;
VkBuffer triangleVertexBuffer;
VkDeviceMemory triangleVertexBufferMemory;
VkPhysicalDeviceMemoryProperties pdmp;
std::vector<VkImageView> views; //?
VkSurfaceFormatKHR swapchainFormat;
VkExtent2D swapChainExtent;
VkDescriptorPool descriptorPool;
VkDescriptorSet blitDescriptorSet;
VkDescriptorSetLayout blitDsl;
VkPipelineLayout blitPipelineLayout;
VkDescriptorSet sampleDescriptorSet;
VkDescriptorSetLayout sampleDsl;
VkPipelineLayout samplePipelineLayout;
VkImage textureImage;
VkDeviceMemory textureMemory;
VkSampler textureSampler;
VkImageView textureView;
VkBuffer texelBuffer;
VkDeviceMemory texelBufferMemory;
VkBufferView texelBufferView;
VkRenderPass offscreenRenderPass;
VkFramebuffer offscreenFramebuffer;
uint32_t graphicsQueueFamily;
uint32_t presentQueueFamily;
char* readPPM(const char* fileName)
{
uint16_t ppm_magic;
((uint8_t*)&ppm_magic)[0] = 'P';
((uint8_t*)&ppm_magic)[1] = '6';
FILE* fd = fopen(fileName, "rb");
fseek (fd , 0 , SEEK_END);
uint32_t fsize = ftell(fd);
rewind(fd);
char* buf = (char*)malloc(fsize);
if(!buf)
{
return 0;
}
fread(buf, 1, fsize, fd);
fclose(fd);
uint16_t magic_number = ((uint16_t*)buf)[0];
if(magic_number != ppm_magic)
{
fprintf(stderr, "PPM magic number not found: %u\n", magic_number);
return 0;
}
char* widthStr = strtok(buf+3, " ");
char* heightStr = strtok(0, "\n");
char* maxValStr = strtok(0, "\n");
int width = atoi(widthStr);
int height = atoi(heightStr);
int maxVal = atoi(maxValStr);
printf("Image size: %i x %i\n", width, height);
printf("Max value: %i\n", maxVal);
char* imageBuf = maxValStr + strlen(maxValStr) + 1;
//convert to BGRA (A=1)
char* retBuf = (char*)malloc(width * height * 4);
for(int y = 0; y < height; ++y)
{
for(int x = 0; x < width; ++x)
{
retBuf[(y*width+x)*4+0] = imageBuf[(y*width+x)*3+2];
retBuf[(y*width+x)*4+1] = imageBuf[(y*width+x)*3+1];
retBuf[(y*width+x)*4+2] = imageBuf[(y*width+x)*3+0];
retBuf[(y*width+x)*4+3] = 0xff;
}
}
free(buf);
return retBuf;
}
void cleanup() {
vkDeviceWaitIdle(device);
// Note: this is done implicitly when the command pool is freed, but nice to know about
vkFreeCommandBuffers(device, commandPool, presentCommandBuffers.size(), presentCommandBuffers.data());
vkDestroyCommandPool(device, commandPool, nullptr);
vkDestroySemaphore(device, imageAvailableSemaphore, nullptr);
vkDestroySemaphore(device, renderingFinishedSemaphore, nullptr);
for(int c = 0; c < views.size(); ++c)
vkDestroyImageView(device, views[c], 0);
for (int c = 0; c < fbs.size(); ++c)
vkDestroyFramebuffer(device, fbs[c], 0);
vkDestroyRenderPass(device, renderPass, 0);
//vkDestroyShaderModule(device, shaderModule, 0);
//vkDestroyPipeline(device, pipeline, 0);
// Note: implicitly destroys images (in fact, we're not allowed to do that explicitly)
vkDestroySwapchainKHR(device, swapChain, nullptr);
vkDestroyDevice(device, nullptr);
vkDestroySurfaceKHR(instance, windowSurface, nullptr);
vkDestroyInstance(instance, nullptr);
}
void run() {
// Note: dynamically loading loader may be a better idea to fail gracefully when Vulkan is not supported
// Create window for Vulkan
//glfwInit();
//glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
//glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
//window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "The 630 line cornflower blue window", nullptr, nullptr);
// Use Vulkan
setupVulkan();
mainLoop();
cleanup();
}
void setupVulkan() {
createInstance();
createWindowSurface();
findPhysicalDevice();
checkSwapChainSupport();
findQueueFamilies();
createLogicalDevice();
createSemaphores();
createSwapChain();
createCommandQueues();
CreateRenderPass();
CreateFramebuffer();
CreateVertexBuffer();
CreateShaders();
CreateTexture();
CreateDescriptorSet();
CreatePipeline();
recordCommandBuffers();
}
void mainLoop() {
//while (!glfwWindowShouldClose(window)) {
for(int c = 0; c < 300; ++c){
draw();
//glfwPollEvents();
}
}
void createInstance() {
VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "VulkanTriangle";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "TriangleEngine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
// Get instance extensions required by GLFW to draw to window
//unsigned int glfwExtensionCount;
//const char** glfwExtensions;
//glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
// Check for extensions
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
if (extensionCount == 0) {
std::cerr << "no extensions supported!" << std::endl;
assert(0);
}
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, availableExtensions.data());
std::cout << "supported extensions:" << std::endl;
for (const auto& extension : availableExtensions) {
std::cout << "\t" << extension.extensionName << std::endl;
}
VkInstanceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
//createInfo.enabledExtensionCount = glfwExtensionCount;
createInfo.enabledExtensionCount = 0;
//createInfo.ppEnabledExtensionNames = glfwExtensions;
createInfo.ppEnabledExtensionNames = 0;
createInfo.enabledLayerCount = 0;
createInfo.ppEnabledLayerNames = 0;
// Initialize Vulkan instance
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
std::cerr << "failed to create instance!" << std::endl;
assert(0);
}
else {
std::cout << "created vulkan instance" << std::endl;
}
}
void createWindowSurface() {
if (vkCreateRpiSurfaceEXT(instance, 0, 0, &windowSurface) != VK_SUCCESS) {
std::cerr << "failed to create window surface!" << std::endl;
assert(0);
}
std::cout << "created window surface" << std::endl;
}
void findPhysicalDevice() {
// Try to find 1 Vulkan supported device
// Note: perhaps refactor to loop through devices and find first one that supports all required features and extensions
uint32_t deviceCount = 1;
VkResult res = vkEnumeratePhysicalDevices(instance, &deviceCount, &physicalDevice);
if (res != VK_SUCCESS && res != VK_INCOMPLETE) {
std::cerr << "enumerating physical devices failed!" << std::endl;
assert(0);
}
if (deviceCount == 0) {
std::cerr << "no physical devices that support vulkan!" << std::endl;
assert(0);
}
std::cout << "physical device with vulkan support found" << std::endl;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &pdmp);
// Check device features
// Note: will apiVersion >= appInfo.apiVersion? Probably yes, but spec is unclear.
VkPhysicalDeviceProperties deviceProperties;
VkPhysicalDeviceFeatures deviceFeatures;
vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);
uint32_t supportedVersion[] = {
VK_VERSION_MAJOR(deviceProperties.apiVersion),
VK_VERSION_MINOR(deviceProperties.apiVersion),
VK_VERSION_PATCH(deviceProperties.apiVersion)
};
std::cout << "physical device supports version " << supportedVersion[0] << "." << supportedVersion[1] << "." << supportedVersion[2] << std::endl;
}
void checkSwapChainSupport() {
uint32_t extensionCount = 0;
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr);
if (extensionCount == 0) {
std::cerr << "physical device doesn't support any extensions" << std::endl;
assert(0);
}
std::vector<VkExtensionProperties> deviceExtensions(extensionCount);
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, deviceExtensions.data());
for (const auto& extension : deviceExtensions) {
if (strcmp(extension.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
std::cout << "physical device supports swap chains" << std::endl;
return;
}
}
std::cerr << "physical device doesn't support swap chains" << std::endl;
assert(0);
}
void findQueueFamilies() {
// Check queue families
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
if (queueFamilyCount == 0) {
std::cout << "physical device has no queue families!" << std::endl;
assert(0);
}
// Find queue family with graphics support
// Note: is a transfer queue necessary to copy vertices to the gpu or can a graphics queue handle that?
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies.data());
std::cout << "physical device has " << queueFamilyCount << " queue families" << std::endl;
bool foundGraphicsQueueFamily = false;
bool foundPresentQueueFamily = false;
for (uint32_t i = 0; i < queueFamilyCount; i++) {
VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, windowSurface, &presentSupport);
if (queueFamilies[i].queueCount > 0 && queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
graphicsQueueFamily = i;
foundGraphicsQueueFamily = true;
if (presentSupport) {
presentQueueFamily = i;
foundPresentQueueFamily = true;
break;
}
}
if (!foundPresentQueueFamily && presentSupport) {
presentQueueFamily = i;
foundPresentQueueFamily = true;
}
}
if (foundGraphicsQueueFamily) {
std::cout << "queue family #" << graphicsQueueFamily << " supports graphics" << std::endl;
if (foundPresentQueueFamily) {
std::cout << "queue family #" << presentQueueFamily << " supports presentation" << std::endl;
}
else {
std::cerr << "could not find a valid queue family with present support" << std::endl;
assert(0);
}
}
else {
std::cerr << "could not find a valid queue family with graphics support" << std::endl;
assert(0);
}
}
void createLogicalDevice() {
// Greate one graphics queue and optionally a separate presentation queue
float queuePriority = 1.0f;
VkDeviceQueueCreateInfo queueCreateInfo[2] = {};
queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo[0].queueFamilyIndex = graphicsQueueFamily;
queueCreateInfo[0].queueCount = 1;
queueCreateInfo[0].pQueuePriorities = &queuePriority;
queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo[0].queueFamilyIndex = presentQueueFamily;
queueCreateInfo[0].queueCount = 1;
queueCreateInfo[0].pQueuePriorities = &queuePriority;
// Create logical device from physical device
// Note: there are separate instance and device extensions!
VkDeviceCreateInfo deviceCreateInfo = {};
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
if (graphicsQueueFamily == presentQueueFamily) {
deviceCreateInfo.queueCreateInfoCount = 1;
}
else {
deviceCreateInfo.queueCreateInfoCount = 2;
}
const char* deviceExtensions = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
deviceCreateInfo.enabledExtensionCount = 1;
deviceCreateInfo.ppEnabledExtensionNames = &deviceExtensions;
if (vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device) != VK_SUCCESS) {
std::cerr << "failed to create logical device" << std::endl;
assert(0);
}
std::cout << "created logical device" << std::endl;
// Get graphics and presentation queues (which may be the same)
vkGetDeviceQueue(device, graphicsQueueFamily, 0, &graphicsQueue);
vkGetDeviceQueue(device, presentQueueFamily, 0, &presentQueue);
std::cout << "acquired graphics and presentation queues" << std::endl;
}
void createSemaphores() {
VkSemaphoreCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
if (vkCreateSemaphore(device, &createInfo, nullptr, &imageAvailableSemaphore) != VK_SUCCESS ||
vkCreateSemaphore(device, &createInfo, nullptr, &renderingFinishedSemaphore) != VK_SUCCESS) {
std::cerr << "failed to create semaphores" << std::endl;
assert(0);
}
else {
std::cout << "created semaphores" << std::endl;
}
}
void createSwapChain() {
// Find surface capabilities
VkSurfaceCapabilitiesKHR surfaceCapabilities;
if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, windowSurface, &surfaceCapabilities) != VK_SUCCESS) {
std::cerr << "failed to acquire presentation surface capabilities" << std::endl;
assert(0);
}
// Find supported surface formats
uint32_t formatCount;
if (vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, windowSurface, &formatCount, nullptr) != VK_SUCCESS || formatCount == 0) {
std::cerr << "failed to get number of supported surface formats" << std::endl;
assert(0);
}
std::vector<VkSurfaceFormatKHR> surfaceFormats(formatCount);
if (vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, windowSurface, &formatCount, surfaceFormats.data()) != VK_SUCCESS) {
std::cerr << "failed to get supported surface formats" << std::endl;
assert(0);
}
// Find supported present modes
uint32_t presentModeCount;
if (vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, windowSurface, &presentModeCount, nullptr) != VK_SUCCESS || presentModeCount == 0) {
std::cerr << "failed to get number of supported presentation modes" << std::endl;
assert(0);
}
std::vector<VkPresentModeKHR> presentModes(presentModeCount);
if (vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, windowSurface, &presentModeCount, presentModes.data()) != VK_SUCCESS) {
std::cerr << "failed to get supported presentation modes" << std::endl;
assert(0);
}
// Determine number of images for swap chain
uint32_t imageCount = surfaceCapabilities.minImageCount + 1;
if (surfaceCapabilities.maxImageCount != 0 && imageCount > surfaceCapabilities.maxImageCount) {
imageCount = surfaceCapabilities.maxImageCount;
}
std::cout << "using " << imageCount << " images for swap chain" << std::endl;
// Select a surface format
swapchainFormat = chooseSurfaceFormat(surfaceFormats);
// Select swap chain size
swapChainExtent = chooseSwapExtent(surfaceCapabilities);
// Check if swap chain supports being the destination of an image transfer
// Note: AMD driver bug, though it would be nice to implement a workaround that doesn't use transfering
//if (!(surfaceCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
// std::cerr << "swap chain image does not support VK_IMAGE_TRANSFER_DST usage" << std::endl;
//assert(0);
//}
// Determine transformation to use (preferring no transform)
VkSurfaceTransformFlagBitsKHR surfaceTransform;
if (surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
surfaceTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
}
else {
surfaceTransform = surfaceCapabilities.currentTransform;
}
// Choose presentation mode (preferring MAILBOX ~= triple buffering)
VkPresentModeKHR presentMode = choosePresentMode(presentModes);
// Finally, create the swap chain
VkSwapchainCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = windowSurface;
createInfo.minImageCount = imageCount;
createInfo.imageFormat = swapchainFormat.format;
createInfo.imageColorSpace = swapchainFormat.colorSpace;
createInfo.imageExtent = swapChainExtent;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr;
createInfo.preTransform = surfaceTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = presentMode;
createInfo.clipped = VK_TRUE;
createInfo.oldSwapchain = VK_NULL_HANDLE;
if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
std::cerr << "failed to create swap chain" << std::endl;
assert(0);
}
else {
std::cout << "created swap chain" << std::endl;
}
// Store the images used by the swap chain
// Note: these are the images that swap chain image indices refer to
// Note: actual number of images may differ from requested number, since it's a lower bound
uint32_t actualImageCount = 0;
if (vkGetSwapchainImagesKHR(device, swapChain, &actualImageCount, nullptr) != VK_SUCCESS || actualImageCount == 0) {
std::cerr << "failed to acquire number of swap chain images" << std::endl;
assert(0);
}
swapChainImages.resize(actualImageCount);
views.resize(actualImageCount);
if (vkGetSwapchainImagesKHR(device, swapChain, &actualImageCount, swapChainImages.data()) != VK_SUCCESS) {
std::cerr << "failed to acquire swap chain images" << std::endl;
assert(0);
}
std::cout << "acquired swap chain images" << std::endl;
}
VkSurfaceFormatKHR chooseSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
// We can either choose any format
if (availableFormats.size() == 1 && availableFormats[0].format == VK_FORMAT_UNDEFINED) {
return { VK_FORMAT_R8G8B8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR };
}
// Or go with the standard format - if available
for (const auto& availableSurfaceFormat : availableFormats) {
if (availableSurfaceFormat.format == VK_FORMAT_R8G8B8A8_UNORM) {
return availableSurfaceFormat;
}
}
// Or fall back to the first available one
return availableFormats[0];
}
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& surfaceCapabilities) {
if (surfaceCapabilities.currentExtent.width == -1) {
VkExtent2D swapChainExtent = {};
#define min(a, b) (a < b ? a : b)
#define max(a, b) (a > b ? a : b)
swapChainExtent.width = min(max(640, surfaceCapabilities.minImageExtent.width), surfaceCapabilities.maxImageExtent.width);
swapChainExtent.height = min(max(480, surfaceCapabilities.minImageExtent.height), surfaceCapabilities.maxImageExtent.height);
return swapChainExtent;
}
else {
return surfaceCapabilities.currentExtent;
}
}
VkPresentModeKHR choosePresentMode(const std::vector<VkPresentModeKHR> presentModes) {
for (const auto& presentMode : presentModes) {
if (presentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
return presentMode;
}
}
// If mailbox is unavailable, fall back to FIFO (guaranteed to be available)
return VK_PRESENT_MODE_FIFO_KHR;
}
void createCommandQueues() {
// Create presentation command pool
// Note: only command buffers for a single queue family can be created from this pool
VkCommandPoolCreateInfo poolCreateInfo = {};
poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolCreateInfo.queueFamilyIndex = presentQueueFamily;
if (vkCreateCommandPool(device, &poolCreateInfo, nullptr, &commandPool) != VK_SUCCESS) {
std::cerr << "failed to create command queue for presentation queue family" << std::endl;
assert(0);
}
else {
std::cout << "created command pool for presentation queue family" << std::endl;
}
// Get number of swap chain images and create vector to hold command queue for each one
presentCommandBuffers.resize(swapChainImages.size());
// Allocate presentation command buffers
// Note: secondary command buffers are only for nesting in primary command buffers
VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = (uint32_t)swapChainImages.size();
if (vkAllocateCommandBuffers(device, &allocInfo, presentCommandBuffers.data()) != VK_SUCCESS) {
std::cerr << "failed to allocate presentation command buffers" << std::endl;
assert(0);
}
else {
std::cout << "allocated presentation command buffers" << std::endl;
}
}
void recordCommandBuffers()
{
// Prepare data for recording command buffers
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
// Note: contains value for each subresource range
VkClearColorValue clearColor = {
{ 0.4f, 0.6f, 0.9f, 1.0f } // R, G, B, A
};
VkClearValue clearValue = {};
clearValue.color = clearColor;
VkImageSubresourceRange subResourceRange = {};
subResourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subResourceRange.baseMipLevel = 0;
subResourceRange.levelCount = 1;
subResourceRange.baseArrayLayer = 0;
subResourceRange.layerCount = 1;
VkRenderPassBeginInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = renderPass;
renderPassInfo.renderArea.offset.x = 0;
renderPassInfo.renderArea.offset.y = 0;
renderPassInfo.renderArea.extent.width = swapChainExtent.width;
renderPassInfo.renderArea.extent.height = swapChainExtent.height;
renderPassInfo.clearValueCount = 1;
renderPassInfo.pClearValues = &clearValue;
VkViewport viewport = { 0 };
viewport.height = (float)swapChainExtent.width;
viewport.width = (float)swapChainExtent.height;
viewport.minDepth = (float)0.0f;
viewport.maxDepth = (float)1.0f;
VkRect2D scissor = { 0 };
scissor.extent.width = swapChainExtent.width;
scissor.extent.height = swapChainExtent.height;
scissor.offset.x = 0;
scissor.offset.y = 0;
// Record the command buffer for every swap chain image
for (uint32_t i = 0; i < swapChainImages.size(); i++) {
// Record command buffer
vkBeginCommandBuffer(presentCommandBuffers[i], &beginInfo);
{ //offscreen rendering
VkClearValue offscreenClearValues =
{
.color = { 1.0f, 0.0f, 1.0f, 1.0f }
};
renderPassInfo.framebuffer = offscreenFramebuffer;
renderPassInfo.renderPass = offscreenRenderPass;
renderPassInfo.clearValueCount = 1;
renderPassInfo.pClearValues = &offscreenClearValues;
vkCmdBeginRenderPass(presentCommandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(presentCommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, blitPipeline);
VkDeviceSize offsets = 0;
vkCmdBindVertexBuffers(presentCommandBuffers[i], 0, 1, &fsqVertexBuffer, &offsets );
vkCmdBindDescriptorSets(presentCommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, blitPipelineLayout, 0, 1, &blitDescriptorSet, 0, 0);
float Wcoeff = 1.0f; //1.0f / Wc = 2.0 - Wcoeff
float viewportScaleX = (float)(swapChainExtent.width) * 0.5f * 16.0f;
float viewportScaleY = -1.0f * (float)(swapChainExtent.height) * 0.5f * 16.0f;
float Zs = 0.5f;
uint32_t vertConstants[4];
vertConstants[0] = *(uint32_t*)&Wcoeff;
vertConstants[1] = *(uint32_t*)&viewportScaleX;
vertConstants[2] = *(uint32_t*)&viewportScaleY;
vertConstants[3] = *(uint32_t*)&Zs;
vkCmdPushConstants(presentCommandBuffers[i], blitPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vertConstants), &vertConstants);
uint32_t size = swapChainExtent.width * swapChainExtent.height * 4 - 4;//swapChainExtent.width * swapChainExtent.height * 4;
uint32_t fragConstants[2];
fragConstants[0] = size;
fragConstants[1] = 0;
vkCmdPushConstants(presentCommandBuffers[i], blitPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(fragConstants), &fragConstants);
vkCmdDraw(presentCommandBuffers[i], 6, 1, 0, 0);
vkCmdEndRenderPass(presentCommandBuffers[i]);
}
{ //render to screen
renderPassInfo.framebuffer = fbs[i];
renderPassInfo.renderPass = renderPass;
renderPassInfo.clearValueCount = 1;
renderPassInfo.pClearValues = &clearValue;
vkCmdBeginRenderPass(presentCommandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(presentCommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, samplePipeline);
VkDeviceSize offsets = 0;
vkCmdBindVertexBuffers(presentCommandBuffers[i], 0, 1, &triangleVertexBuffer, &offsets );
vkCmdBindDescriptorSets(presentCommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, samplePipelineLayout, 0, 1, &sampleDescriptorSet, 0, 0);
float Wcoeff = 1.0f; //1.0f / Wc = 2.0 - Wcoeff
float viewportScaleX = (float)(swapChainExtent.width) * 0.5f * 16.0f;
float viewportScaleY = -1.0f * (float)(swapChainExtent.height) * 0.5f * 16.0f;
float Zs = 0.5f;
uint32_t pushConstants[4];
pushConstants[0] = *(uint32_t*)&Wcoeff;
pushConstants[1] = *(uint32_t*)&viewportScaleX;
pushConstants[2] = *(uint32_t*)&viewportScaleY;
pushConstants[3] = *(uint32_t*)&Zs;
vkCmdPushConstants(presentCommandBuffers[i], samplePipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(pushConstants), &pushConstants);
vkCmdDraw(presentCommandBuffers[i], 3, 1, 0, 0);
vkCmdEndRenderPass(presentCommandBuffers[i]);
}
if (vkEndCommandBuffer(presentCommandBuffers[i]) != VK_SUCCESS) {
std::cerr << "failed to record command buffer" << std::endl;
assert(0);
}
else {
std::cout << "recorded command buffer for image " << i << std::endl;
}
}
}
void draw() {
// Acquire image
uint32_t imageIndex;
VkResult res = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR) {
std::cerr << "failed to acquire image" << std::endl;
assert(0);
}
std::cout << "acquired image" << std::endl;
// Wait for image to be available and draw
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &imageAvailableSemaphore;
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &renderingFinishedSemaphore;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &presentCommandBuffers[imageIndex];
if (vkQueueSubmit(presentQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
std::cerr << "failed to submit draw command buffer" << std::endl;
assert(0);
}
std::cout << "submitted draw command buffer" << std::endl;
// Present drawn image
// Note: semaphore here is not strictly necessary, because commands are processed in submission order within a single queue
VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = &renderingFinishedSemaphore;
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &swapChain;
presentInfo.pImageIndices = &imageIndex;
res = vkQueuePresentKHR(presentQueue, &presentInfo);
if (res != VK_SUCCESS) {
std::cerr << "failed to submit present command buffer" << std::endl;
assert(0);
}
std::cout << "submitted presentation command buffer" << std::endl;
}
void CreateRenderPass()
{
VkAttachmentReference attachRef = {};
attachRef.attachment = 0;
attachRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpassDesc = {};
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDesc.colorAttachmentCount = 1;
subpassDesc.pColorAttachments = &attachRef;
VkAttachmentDescription attachDesc = {};
attachDesc.format = swapchainFormat.format; //Todo
attachDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachDesc.initialLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
attachDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
attachDesc.samples = VK_SAMPLE_COUNT_1_BIT;
VkRenderPassCreateInfo renderPassCreateInfo = {};
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassCreateInfo.attachmentCount = 1;
renderPassCreateInfo.pAttachments = &attachDesc;
renderPassCreateInfo.subpassCount = 1;
renderPassCreateInfo.pSubpasses = &subpassDesc;
VkResult res = vkCreateRenderPass(device, &renderPassCreateInfo, NULL, &renderPass);
printf("Created a render pass\n");
}
void CreateFramebuffer()
{
fbs.resize(swapChainImages.size());
VkResult res;
for (uint32_t i = 0; i < swapChainImages.size(); i++) {
VkImageViewCreateInfo ViewCreateInfo = {};
ViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
ViewCreateInfo.image = swapChainImages[i];
ViewCreateInfo.format = swapchainFormat.format; //Todo
ViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
ViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
ViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
ViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
ViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
ViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
ViewCreateInfo.subresourceRange.baseMipLevel = 0;
ViewCreateInfo.subresourceRange.levelCount = 1;
ViewCreateInfo.subresourceRange.baseArrayLayer = 0;
ViewCreateInfo.subresourceRange.layerCount = 1;
res = vkCreateImageView(device, &ViewCreateInfo, NULL, &views[i]);
VkFramebufferCreateInfo fbCreateInfo = {};
fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fbCreateInfo.renderPass = renderPass;
fbCreateInfo.attachmentCount = 1;
fbCreateInfo.pAttachments = &views[i];
fbCreateInfo.width = swapChainExtent.width;
fbCreateInfo.height = swapChainExtent.height;
fbCreateInfo.layers = 1;
res = vkCreateFramebuffer(device, &fbCreateInfo, NULL, &fbs[i]);
}
printf("Frame buffers created\n");
}
void CreateShaders()
{
//TODO doesn't work for some reason...
char vs_asm_code[] =
///0x40000000 = 2.0
///uni = 1.0
///rb0 = 2 - 1 = 1
"sig_small_imm ; rx0 = fsub.ws.always(b, a, uni, 0x40000000) ; nop = nop(r0, r0) ;\n"
///set up VPM read for subsequent reads
///0x00201a00: 0000 0000 0010 0000 0001 1010 0000 0000
///addr: 0
///size: 32bit
///packed
///horizontal
///stride=1
///vectors to read = 2 (how many components)
"sig_load_imm ; vr_setup = load32.always(0x00201a00) ; nop = load32.always() ;\n"
///uni = viewportXScale
///r0 = vpm * uni
"sig_none ; nop = nop(r0, r0, vpm_read, uni) ; r0 = fmul.always(a, b) ;\n"
///r1 = r0 * rb0 (1)
"sig_none ; nop = nop(r0, r0, nop, rb0) ; r1 = fmul.always(r0, b) ;\n"
///uni = viewportYScale
///ra0.16a = int(r1), r2 = vpm * uni
"sig_none ; rx0.16a = ftoi.always(r1, r1, vpm_read, uni) ; r2 = fmul.always(a, b) ;\n"
///r3 = r2 * rb0
"sig_none ; nop = nop(r0, r0, nop, rb0) ; r3 = fmul.always(r2, b) ;\n"
///ra0.16b = int(r3)
"sig_none ; rx0.16b = ftoi.always(r3, r3) ; nop = nop(r0, r0) ;\n"
///set up VPM write for subsequent writes
///0x00001a00: 0000 0000 0000 0000 0001 1010 0000 0000
///addr: 0
///size: 32bit
///horizontal
///stride = 1
"sig_load_imm ; vw_setup = load32.always.ws(0x00001a00) ; nop = load32.always() ;\n"
///shaded vertex format for PSE
/// Ys and Xs
///vpm = ra0
"sig_none ; vpm = or.always(a, a, ra0, nop) ; nop = nop(r0, r0);\n"
/// Zs
///uni = 0.5
///vpm = uni
"sig_none ; vpm = or.always(a, a, uni, nop) ; nop = nop(r0, r0);\n"
/// 1.0 / Wc
///vpm = rb0 (1)
"sig_none ; vpm = or.always(b, b, nop, rb0) ; nop = nop(r0, r0);\n"
///END
"sig_end ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n"
"sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n"
"sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n"
"\0";
char cs_asm_code[] =
///uni = 1.0
///r3 = 2.0 - uni
"sig_small_imm ; r3 = fsub.always(b, a, uni, 0x40000000) ; nop = nop(r0, r0);\n"
"sig_load_imm ; vr_setup = load32.always(0x00201a00) ; nop = load32.always() ;\n"
///r2 = vpm
"sig_none ; r2 = or.always(a, a, vpm_read, nop) ; nop = nop(r0, r0);\n"
"sig_load_imm ; vw_setup = load32.always.ws(0x00001a00) ; nop = load32.always() ;\n"
///shaded coordinates format for PTB
/// write Xc
///r1 = vpm, vpm = r2
"sig_none ; r1 = or.always(a, a, vpm_read, nop) ; vpm = v8min.always(r2, r2);\n"
/// write Yc
///uni = viewportXscale
///vpm = r1, r2 = r2 * uni
"sig_none ; vpm = or.always(r1, r1, uni, nop) ; r2 = fmul.always(r2, a);\n"
///uni = viewportYscale
///r1 = r1 * uni
"sig_none ; nop = nop(r0, r0, uni, nop) ; r1 = fmul.always(r1, a);\n"
///r0 = r2 * r3
"sig_none ; nop = nop(r0, r0) ; r0 = fmul.always(r2, r3);\n"
///ra0.16a = r0, r1 = r1 * r3
"sig_none ; rx0.16a = ftoi.always(r0, r0) ; r1 = fmul.always(r1, r3) ;\n"
///ra0.16b = r1
"sig_none ; rx0.16b = ftoi.always(r1, r1) ; nop = nop(r0, r0) ;\n"
///write Zc
///vpm = 0
"sig_small_imm ; vpm = or.always(b, b, nop, 0) ; nop = nop(r0, r0) ;\n"
///write Wc
///vpm = 1.0
"sig_small_imm ; vpm = or.always(b, b, nop, 0x3f800000) ; nop = nop(r0, r0) ;\n"
///write Ys and Xs
///vpm = ra0
"sig_none ; vpm = or.always(a, a, ra0, nop) ; nop = nop(r0, r0) ;\n"
///write Zs
///uni = 0.5
///vpm = uni
"sig_none ; vpm = or.always(a, a, uni, nop) ; nop = nop(r0, r0) ;\n"
///write 1/Wc
///vpm = r3
"sig_none ; vpm = or.always(r3, r3) ; nop = nop(r0, r0) ;\n"
///END
"sig_end ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n"
"sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n"
"sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;\n"
"\0";
//clever: use small immedate -1 interpreted as 0xffffffff (white) to set color to white
//"sig_small_imm ; tlb_color_all = or.always(b, b, nop, -1) ; nop = nop(r0, r0) ;"
//8bit access
//abcd
//BGRA
/**
"General-memory lookups are performed by writing to just the s parameter, using the absolute memory
address. In this case no uniform is read. General-memory lookups always return a 32-bit value, and the bottom
two bits of the address are ignored."
/**/
//blit buffer to texture (generic buffer read)
char blit_fs_asm_code[] =
"sig_load_imm ; r2 = load32.always(0x44f00000) ; nop = load32() ;" //width = 1920.0
"sig_none ; r1 = itof.always(b, b, x_pix, y_pix) ; nop = nop(r0, r0) ;" //FragCoord Y
"sig_none ; r0 = itof.always(a, a, x_pix, y_pix) ; r1 = fmul.always(r1, r2) ;" //FragCoord X, r1 = Y * width
"sig_none ; r0 = fadd.always(r0, r1) ; r0 = nop(r0, r0) ;" //r0 = Y * width + X
"sig_small_imm ; r0 = nop(r0, r0, nop, 0x40800000) ; r0 = fmul.always(r0, b) ;" //r0 = (Y * width + X) * 4
"sig_none ; r0 = ftoi.always(r0, r0) ; nop = nop(r0, r0) ;" //convert to integer
///write general mem access address
///first argument must be clamped to [0...bufsize-4]
///eg must do min(max(x,0), uni)
///second argument must be a uniform (containing base address, which is 0)
///writing tmu0_s signals that all coordinates are written
"sig_small_imm ; r0 = max.always(r0, b, nop, 0) ; nop = nop(r0, r0) ;" //clamp general access
"sig_none ; r0 = min.always(r0, b, nop, uni) ; nop = nop(r0, r0) ;" //uni = 1920 * 1080 * 4 - 4
"sig_none ; tmu0_s = add.always(r0, b, nop, uni) ; nop = nop(r0, r0) ;"
///suspend thread (after 2 nops) to wait for TMU request to finish
"sig_thread_switch ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
"sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
"sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
///read TMU0 request result to R4
"sig_load_tmu0 ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
///when thread has been awakened, MOV from R4 to R0
"sig_none ; r0 = fmax.pm.always.8a(r4, r4) ; nop = nop(r0, r0) ;"
"sig_none ; r1 = fmax.pm.always.8b(r4, r4) ; r0.8a = v8min.always(r0, r0) ;"
"sig_none ; r2 = fmax.pm.always.8c(r4, r4) ; r0.8b = v8min.always(r1, r1) ;"
"sig_none ; r3 = fmax.pm.always.8d(r4, r4) ; r0.8c = v8min.always(r2, r2) ;"
"sig_none ; nop = nop.pm(r0, r0) ; r0.8d = v8min.always(r3, r3) ;"
"sig_none ; tlb_color_all = or.always(r0, r0) ; nop = nop(r0, r0) ;"
"sig_end ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
"sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
"sig_unlock_score ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
"\0";
//sample texture
char sample_fs_asm_code[] =
"sig_none ; r0 = itof.always(b, b, x_pix, y_pix) ; nop = nop(r0, r0) ;"
"sig_load_imm ; r2 = load32.always(0x3a72b9d6) ; nop = load32() ;" //1/1080
"sig_none ; r0 = itof.always(a, a, x_pix, y_pix) ; r1 = fmul.always(r2, r0); ;" //r1 contains tex coord y
"sig_load_imm ; r2 = load32.always(0x3a088888) ; nop = load32() ;" //1/1920
///write texture addresses (x, y)
///writing tmu0_s signals that all coordinates are written
"sig_none ; tmu0_t = or.always(r1, r1) ; r0 = fmul.always(r2, r0) ;" //r0 contains tex coord x
"sig_none ; tmu0_s = or.always(r0, r0) ; nop = nop(r0, r0) ;"
///suspend thread (after 2 nops) to wait for TMU request to finish
"sig_thread_switch ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
"sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
"sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
///read TMU0 request result to R4
"sig_load_tmu0 ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
///when thread has been awakened, MOV from R4 to R0
"sig_none ; r0 = fmax.pm.always.8a(r4, r4) ; nop = nop(r0, r0) ;"
"sig_none ; r1 = fmax.pm.always.8b(r4, r4) ; r0.8a = v8min.always(r0, r0) ;"
"sig_none ; r2 = fmax.pm.always.8c(r4, r4) ; r0.8b = v8min.always(r1, r1) ;"
"sig_none ; r3 = fmax.pm.always.8d(r4, r4) ; r0.8c = v8min.always(r2, r2) ;"
"sig_none ; nop = nop.pm(r0, r0) ; r0.8d = v8min.always(r3, r3) ;"
"sig_none ; tlb_color_all = or.always(r0, r0) ; nop = nop(r0, r0) ;"
"sig_end ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
"sig_none ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
"sig_unlock_score ; nop = nop(r0, r0) ; nop = nop(r0, r0) ;"
"\0";
char* blit_asm_strings[] =
{
(char*)cs_asm_code, (char*)vs_asm_code, (char*)blit_fs_asm_code, 0
};
char* sample_asm_strings[] =
{
(char*)cs_asm_code, (char*)vs_asm_code, (char*)sample_fs_asm_code, 0
};
VkRpiAssemblyMappingEXT blit_mappings[] = {
//vertex shader uniforms
{
VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT,
VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type
0, //descriptor set #
0, //descriptor binding #
0, //descriptor array element #
0, //resource offset
VK_SHADER_STAGE_VERTEX_BIT
},
{
VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT,
VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type
0, //descriptor set #
0, //descriptor binding #
0, //descriptor array element #
4, //resource offset
VK_SHADER_STAGE_VERTEX_BIT
},
{
VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT,
VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type
0, //descriptor set #
0, //descriptor binding #
0, //descriptor array element #
8, //resource offset
VK_SHADER_STAGE_VERTEX_BIT
},
{
VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT,
VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type
0, //descriptor set #
0, //descriptor binding #
0, //descriptor array element #
12, //resource offset
VK_SHADER_STAGE_VERTEX_BIT
},
{
VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT,
VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type
0, //descriptor set #
0, //descriptor binding #
0, //descriptor array element #
0, //resource offset
VK_SHADER_STAGE_FRAGMENT_BIT
},
{
VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT,
VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type
0, //descriptor set #
0, //descriptor binding #
0, //descriptor array element #
4, //resource offset
VK_SHADER_STAGE_FRAGMENT_BIT
},
//fragment shader uniforms
{
VK_RPI_ASSEMBLY_MAPPING_TYPE_DESCRIPTOR,
VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, //descriptor type
0, //descriptor set #
0, //descriptor binding #
0, //descriptor array element #
0, //resource offset
VK_SHADER_STAGE_FRAGMENT_BIT
}
};
VkRpiAssemblyMappingEXT sample_mappings[] = {
//vertex shader uniforms
{
VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT,
VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type
0, //descriptor set #
0, //descriptor binding #
0, //descriptor array element #
0, //resource offset
VK_SHADER_STAGE_VERTEX_BIT
},
{
VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT,
VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type
0, //descriptor set #
0, //descriptor binding #
0, //descriptor array element #
4, //resource offset
VK_SHADER_STAGE_VERTEX_BIT
},
{
VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT,
VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type
0, //descriptor set #
0, //descriptor binding #
0, //descriptor array element #
8, //resource offset
VK_SHADER_STAGE_VERTEX_BIT
},
{
VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT,
VK_DESCRIPTOR_TYPE_MAX_ENUM, //descriptor type
0, //descriptor set #
0, //descriptor binding #
0, //descriptor array element #
12, //resource offset
VK_SHADER_STAGE_VERTEX_BIT
},
//fragment shader uniforms
{
VK_RPI_ASSEMBLY_MAPPING_TYPE_DESCRIPTOR,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, //descriptor type
0, //descriptor set #
0, //descriptor binding #
0, //descriptor array element #
0, //resource offset
VK_SHADER_STAGE_FRAGMENT_BIT
}
};
VkRpiShaderModuleAssemblyCreateInfoEXT shaderModuleCreateInfo;
shaderModuleCreateInfo.asmStrings = blit_asm_strings;
shaderModuleCreateInfo.mappings = blit_mappings;
shaderModuleCreateInfo.numMappings = sizeof(blit_mappings) / sizeof(VkRpiAssemblyMappingEXT);
VkResult res = vkCreateShaderModuleFromRpiAssemblyEXT(device, &shaderModuleCreateInfo, 0, &blitShaderModule);
assert(blitShaderModule);
shaderModuleCreateInfo.asmStrings = sample_asm_strings;
shaderModuleCreateInfo.mappings = sample_mappings;
shaderModuleCreateInfo.numMappings = sizeof(sample_mappings) / sizeof(VkRpiAssemblyMappingEXT);
res = vkCreateShaderModuleFromRpiAssemblyEXT(device, &shaderModuleCreateInfo, 0, &sampleShaderModule);
assert(sampleShaderModule);
//exit(-1);
}
#define VERTEX_BUFFER_BIND_ID 0
void CreatePipeline()
{
VkVertexInputBindingDescription vertexInputBindingDescription =
{
0,
sizeof(float) * 2,
VK_VERTEX_INPUT_RATE_VERTEX
};
VkVertexInputAttributeDescription vertexInputAttributeDescription =
{
0,
0,
VK_FORMAT_R32G32_SFLOAT,
0
};
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputInfo.vertexAttributeDescriptionCount = 1;
vertexInputInfo.pVertexAttributeDescriptions = &vertexInputAttributeDescription;
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &vertexInputBindingDescription;
VkPipelineInputAssemblyStateCreateInfo pipelineIACreateInfo = {};
pipelineIACreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
pipelineIACreateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkViewport vp = {};
vp.x = 0.0f;
vp.y = 0.0f;
vp.width = (float)swapChainExtent.width;
vp.height = (float)swapChainExtent.height;
vp.minDepth = 0.0f;
vp.maxDepth = 1.0f;
VkPipelineViewportStateCreateInfo vpCreateInfo = {};
vpCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
vpCreateInfo.viewportCount = 1;
vpCreateInfo.pViewports = &vp;
VkPipelineRasterizationStateCreateInfo rastCreateInfo = {};
rastCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rastCreateInfo.polygonMode = VK_POLYGON_MODE_FILL;
rastCreateInfo.cullMode = VK_CULL_MODE_NONE;
rastCreateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rastCreateInfo.lineWidth = 1.0f;
VkPipelineMultisampleStateCreateInfo pipelineMSCreateInfo = {};
pipelineMSCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
VkPipelineColorBlendAttachmentState blendAttachState = {};
blendAttachState.colorWriteMask = 0xf;
blendAttachState.blendEnable = false;
VkPipelineColorBlendStateCreateInfo blendCreateInfo = {};
blendCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
blendCreateInfo.attachmentCount = 1;
blendCreateInfo.pAttachments = &blendAttachState;
VkPipelineDepthStencilStateCreateInfo depthStencilState = {};
depthStencilState.depthTestEnable = false;
depthStencilState.stencilTestEnable = false;
{ //create blit pipeline
VkPushConstantRange pushConstantRanges[2];
pushConstantRanges[0].offset = 0;
pushConstantRanges[0].size = 4 * 4; //4 * 32bits
pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
pushConstantRanges[1].offset = 0;
pushConstantRanges[1].size = 3 * 4; //3 * 32bits
pushConstantRanges[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkPipelineShaderStageCreateInfo shaderStageCreateInfo[2] = {};
shaderStageCreateInfo[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStageCreateInfo[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
shaderStageCreateInfo[0].module = blitShaderModule;
shaderStageCreateInfo[0].pName = "main";
shaderStageCreateInfo[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStageCreateInfo[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
shaderStageCreateInfo[1].module = blitShaderModule;
shaderStageCreateInfo[1].pName = "main";
VkPipelineLayoutCreateInfo pipelineLayoutCI = {};
pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutCI.setLayoutCount = 1;
pipelineLayoutCI.pSetLayouts = &blitDsl;
pipelineLayoutCI.pushConstantRangeCount = 2;
pipelineLayoutCI.pPushConstantRanges = &pushConstantRanges[0];
vkCreatePipelineLayout(device, &pipelineLayoutCI, 0, &blitPipelineLayout);
VkGraphicsPipelineCreateInfo pipelineInfo = {};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = &shaderStageCreateInfo[0];
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &pipelineIACreateInfo;
pipelineInfo.pViewportState = &vpCreateInfo;
pipelineInfo.pRasterizationState = &rastCreateInfo;
pipelineInfo.pMultisampleState = &pipelineMSCreateInfo;
pipelineInfo.pColorBlendState = &blendCreateInfo;
pipelineInfo.renderPass = offscreenRenderPass;
pipelineInfo.basePipelineIndex = -1;
pipelineInfo.pDepthStencilState = &depthStencilState;
pipelineInfo.layout = blitPipelineLayout;
VkResult res = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL, &blitPipeline);
}
{ //create sample pipeline
VkPushConstantRange pushConstantRanges[2];
pushConstantRanges[0].offset = 0;
pushConstantRanges[0].size = 4 * 4; //4 * 32bits
pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
pushConstantRanges[1].offset = 0;
pushConstantRanges[1].size = 1 * 4; //1 * 32bits
pushConstantRanges[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkPipelineShaderStageCreateInfo shaderStageCreateInfo[2] = {};
shaderStageCreateInfo[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStageCreateInfo[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
shaderStageCreateInfo[0].module = sampleShaderModule;
shaderStageCreateInfo[0].pName = "main";
shaderStageCreateInfo[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStageCreateInfo[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
shaderStageCreateInfo[1].module = sampleShaderModule;
shaderStageCreateInfo[1].pName = "main";
VkPipelineLayoutCreateInfo pipelineLayoutCI = {};
pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutCI.setLayoutCount = 1;
pipelineLayoutCI.pSetLayouts = &sampleDsl;
pipelineLayoutCI.pushConstantRangeCount = 2;
pipelineLayoutCI.pPushConstantRanges = &pushConstantRanges[0];
vkCreatePipelineLayout(device, &pipelineLayoutCI, 0, &samplePipelineLayout);
VkGraphicsPipelineCreateInfo pipelineInfo = {};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = &shaderStageCreateInfo[0];
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &pipelineIACreateInfo;
pipelineInfo.pViewportState = &vpCreateInfo;
pipelineInfo.pRasterizationState = &rastCreateInfo;
pipelineInfo.pMultisampleState = &pipelineMSCreateInfo;
pipelineInfo.pColorBlendState = &blendCreateInfo;
pipelineInfo.renderPass = renderPass;
pipelineInfo.basePipelineIndex = -1;
pipelineInfo.pDepthStencilState = &depthStencilState;
pipelineInfo.layout = samplePipelineLayout;
VkResult res = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL, &samplePipeline);
}
printf("Graphics pipeline created\n");
}
uint32_t getMemoryTypeIndex(VkPhysicalDeviceMemoryProperties deviceMemoryProperties, uint32_t typeBits, VkMemoryPropertyFlags properties)
{
// Iterate over all memory types available for the device used in this example
for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++)
{
if ((typeBits & 1) == 1)
{
if ((deviceMemoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
{
return i;
}
}
typeBits >>= 1;
}
assert(0);
}
void CreateTexture()
{
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
uint32_t width = swapChainExtent.width, height = swapChainExtent.height;
uint32_t mipLevels = 1;
char* texData = readPPM("image.ppm");
{ //create storage texel buffer for generic mem address TMU ops test
VkBufferCreateInfo bufferCreateInfo = {};
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferCreateInfo.size = width * height * 4;
bufferCreateInfo.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vkCreateBuffer(device, &bufferCreateInfo, 0, &texelBuffer);
VkMemoryRequirements mr;
vkGetBufferMemoryRequirements(device, texelBuffer, &mr);
VkMemoryAllocateInfo mai = {};
mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
mai.allocationSize = mr.size;
mai.memoryTypeIndex = getMemoryTypeIndex(pdmp, mr.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
vkAllocateMemory(device, &mai, 0, &texelBufferMemory);
void* data;
vkMapMemory(device, texelBufferMemory, 0, mr.size, 0, &data);
memcpy(data, texData, width * height * 4);
vkUnmapMemory(device, texelBufferMemory);
free(texData);
vkBindBufferMemory(device, texelBuffer, texelBufferMemory, 0);
VkBufferViewCreateInfo bufferViewCreateInfo = {};
bufferViewCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
bufferViewCreateInfo.buffer = texelBuffer;
bufferViewCreateInfo.format = format;
bufferViewCreateInfo.offset = 0;
bufferViewCreateInfo.range = VK_WHOLE_SIZE;
vkCreateBufferView(device, &bufferViewCreateInfo, 0, &texelBufferView);
}
{ //create texture that we'll write to
VkImageCreateInfo imageCreateInfo = {};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = format;
imageCreateInfo.mipLevels = mipLevels;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.extent = { width, height, 1 };
vkCreateImage(device, &imageCreateInfo, 0, &textureImage);
VkMemoryRequirements mr;
vkGetImageMemoryRequirements(device, textureImage, &mr);
VkMemoryAllocateInfo mai = {};
mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
mai.allocationSize = mr.size;
mai.memoryTypeIndex = getMemoryTypeIndex(pdmp, mr.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vkAllocateMemory(device, &mai, 0, &textureMemory);
vkBindImageMemory(device, textureImage, textureMemory, 0);
VkImageViewCreateInfo view = {};
view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view.viewType = VK_IMAGE_VIEW_TYPE_2D;
view.format = format;
view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
view.subresourceRange.baseMipLevel = 0;
view.subresourceRange.baseArrayLayer = 0;
view.subresourceRange.layerCount = 1;
view.subresourceRange.levelCount = 1;
view.image = textureImage;
vkCreateImageView(device, &view, nullptr, &textureView);
VkSamplerCreateInfo sampler = {};
sampler.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
sampler.magFilter = VK_FILTER_NEAREST;
sampler.minFilter = VK_FILTER_NEAREST;
sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler.mipLodBias = 0.0f;
sampler.compareOp = VK_COMPARE_OP_NEVER;
sampler.minLod = 0.0f;
sampler.maxLod = 0.0f;
sampler.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
vkCreateSampler(device, &sampler, 0, &textureSampler);
VkAttachmentDescription attachmentDescription = {};
attachmentDescription.format = format;
attachmentDescription.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachmentDescription.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
attachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
VkSubpassDescription subpassDescription = {};
subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDescription.colorAttachmentCount = 1;
subpassDescription.pColorAttachments = &colorReference;
VkSubpassDependency dependencies[2];
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = 1;
renderPassInfo.pAttachments = &attachmentDescription;
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpassDescription;
renderPassInfo.dependencyCount = 2;
renderPassInfo.pDependencies = dependencies;
vkCreateRenderPass(device, &renderPassInfo, 0, &offscreenRenderPass);
VkImageView attachments = textureView;
VkFramebufferCreateInfo framebufferCreateInfo = {};
framebufferCreateInfo.renderPass = offscreenRenderPass;
framebufferCreateInfo.attachmentCount = 1;
framebufferCreateInfo.pAttachments = &attachments;
framebufferCreateInfo.width = width;
framebufferCreateInfo.height = height;
framebufferCreateInfo.layers = 1;
vkCreateFramebuffer(device, &framebufferCreateInfo, 0, &offscreenFramebuffer);
}
}
void CreateDescriptorSet()
{
{ //create blit dsl
VkDescriptorSetLayoutBinding setLayoutBinding = {};
setLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
setLayoutBinding.binding = 0;
setLayoutBinding.descriptorCount = 1;
setLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo descriptorLayoutCI = {};
descriptorLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorLayoutCI.bindingCount = 1;
descriptorLayoutCI.pBindings = &setLayoutBinding;
vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, 0, &blitDsl);
}
{ //create sample dsl
VkDescriptorSetLayoutBinding setLayoutBinding = {};
setLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
setLayoutBinding.binding = 0;
setLayoutBinding.descriptorCount = 1;
setLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo descriptorLayoutCI = {};
descriptorLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorLayoutCI.bindingCount = 1;
descriptorLayoutCI.pBindings = &setLayoutBinding;
vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, 0, &sampleDsl);
}
VkDescriptorPoolSize descriptorPoolSizes[2]{};
descriptorPoolSizes[0] = {};
descriptorPoolSizes[0].descriptorCount = 1;
descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
descriptorPoolSizes[1] = {};
descriptorPoolSizes[1].descriptorCount = 1;
descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
VkDescriptorPoolCreateInfo descriptorPoolCI = {};
descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptorPoolCI.poolSizeCount = 2;
descriptorPoolCI.pPoolSizes = descriptorPoolSizes;
descriptorPoolCI.maxSets = 2;
vkCreateDescriptorPool(device, &descriptorPoolCI, 0, &descriptorPool);
{ //create blit descriptor set
VkDescriptorSetAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = descriptorPool;
allocInfo.descriptorSetCount = 1;
allocInfo.pSetLayouts = &blitDsl;
vkAllocateDescriptorSets(device, &allocInfo, &blitDescriptorSet);
VkWriteDescriptorSet writeDescriptorSet = {};
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet.dstSet = blitDescriptorSet;
writeDescriptorSet.dstBinding = 0;
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
writeDescriptorSet.pTexelBufferView = &texelBufferView;
writeDescriptorSet.descriptorCount = 1;
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, 0);
}
{ //create sample descriptor set
VkDescriptorSetAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = descriptorPool;
allocInfo.descriptorSetCount = 1;
allocInfo.pSetLayouts = &sampleDsl;
vkAllocateDescriptorSets(device, &allocInfo, &sampleDescriptorSet);
VkDescriptorImageInfo imageInfo;
imageInfo.imageView = textureView;
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.sampler = textureSampler;
VkWriteDescriptorSet writeDescriptorSet = {};
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet.dstSet = sampleDescriptorSet;
writeDescriptorSet.dstBinding = 0;
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSet.pImageInfo = &imageInfo;
writeDescriptorSet.descriptorCount = 1;
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, 0);
}
}
void CreateVertexBuffer()
{
unsigned vboSize = sizeof(float) * 2 * 3 * 2; //2 * 3 x vec2
VkMemoryRequirements mr;
{ //create fsq vertex buffer
unsigned vboSize = sizeof(float) * 2 * 3 * 2; //2 * 3 x vec2
VkBufferCreateInfo ci = {};
ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
ci.size = vboSize;
ci.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
VkResult res = vkCreateBuffer(device, &ci, 0, &fsqVertexBuffer);
vkGetBufferMemoryRequirements(device, fsqVertexBuffer, &mr);
VkMemoryAllocateInfo mai = {};
mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
mai.allocationSize = mr.size;
mai.memoryTypeIndex = getMemoryTypeIndex(pdmp, mr.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
res = vkAllocateMemory(device, &mai, 0, &fsqVertexBufferMemory);
float vertices[] =
{
-1, -1,
1, -1,
1, 1,
1, 1,
-1, 1,
-1, -1
};
void* data;
res = vkMapMemory(device, fsqVertexBufferMemory, 0, mr.size, 0, &data);
memcpy(data, vertices, vboSize);
vkUnmapMemory(device, fsqVertexBufferMemory);
res = vkBindBufferMemory(device, fsqVertexBuffer, fsqVertexBufferMemory, 0);
}
{ //create triangle vertex buffer
unsigned vboSize = sizeof(float) * 1 * 3 * 2; //1 * 3 x vec2
VkBufferCreateInfo ci = {};
ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
ci.size = vboSize;
ci.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
VkResult res = vkCreateBuffer(device, &ci, 0, &triangleVertexBuffer);
vkGetBufferMemoryRequirements(device, triangleVertexBuffer, &mr);
VkMemoryAllocateInfo mai = {};
mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
mai.allocationSize = mr.size;
mai.memoryTypeIndex = getMemoryTypeIndex(pdmp, mr.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
res = vkAllocateMemory(device, &mai, 0, &triangleVertexBufferMemory);
float vertices[] =
{
-1, -1,
1, -1,
0, 1
};
void* data;
res = vkMapMemory(device, triangleVertexBufferMemory, 0, mr.size, 0, &data);
memcpy(data, vertices, vboSize);
vkUnmapMemory(device, triangleVertexBufferMemory);
res = vkBindBufferMemory(device, triangleVertexBuffer, triangleVertexBufferMemory, 0);
}
printf("Vertex buffer created\n");
}
int main() {
// Note: dynamically loading loader may be a better idea to fail gracefully when Vulkan is not supported
// Create window for Vulkan
//glfwInit();
//glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
//glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
//window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "The 630 line cornflower blue window", nullptr, nullptr);
// Use Vulkan
setupVulkan();
mainLoop();
cleanup();
return 0;
}