diff options
Diffstat (limited to 'bk.c')
| -rw-r--r-- | bk.c | 754 | 
1 files changed, 754 insertions, 0 deletions
@@ -0,0 +1,754 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <SDL2/SDL.h> +#include <SDL2/SDL_vulkan.h> +#include <vulkan/vulkan.h> + +#define ERRFQ(...)				\ +	do {					\ +		fprintf(stderr, __VA_ARGS__);	\ +		exit(1);			\ +	} while(0) + +#define ERRQ(str)				\ +	do {					\ +		fputs((str), stderr);		\ +		fputc('\n', stderr);		\ +		exit(1);			\ +	} while(0) + +uint8_t *read_file(const char *path, size_t size) +{ +	FILE *file = fopen(path, "rb"); +	if (!file) { +		return NULL; +	} +	fseek(file, 0, SEEK_END); +	size_t len = ftell(file); +	rewind(file); +	uint8_t *buf = malloc(len); +	fread(buf, len, 1, file); +	fclose(file); +	*size = len; +	return buf; +} + +/* + * Modifications for Vulkan: + * Row-column flipped + * Negative y + * Expect coordinates on range [0, 1] + */ +void perspective_init(float matrix[4][4], +		const float fov, +		const float aspect, +		const float znear, +		const float zfar) +{ +	memset(matrix, 0, 16*sizeof(float)); +	const float f = 1.0f / tanf(0.5*fov); +	matrix[0][0] = f / aspect; +	matrix[1][1] = -f; +	matrix[2][2] = -znear/(zfar - znear) - 1.0f; +	matrix[3][2] = -zfar*znear/(zfar - znear); +	matrix[2][3] = -1.0f; +} + +void identity_init(float matrix[4][4]) +{ +	memset(matrix, 0, 16*sizeof(float)); +	matrix[0][0] = 1.0f; +	matrix[1][1] = 1.0f; +	matrix[2][2] = 1.0f; +	matrix[3][3] = 1.0f; +} + +struct Uniform { +	float model[4][4]; +	float view[4][4]; +	float proj[4][4]; +}; + +static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( +		VkDebugReportFlagsEXT flags, +		VkDebugReportObjectTypeEXT objType, +		uint64_t obj, +		size_t location, +		int32_t code, +		const char *layerPrefix, +		const char *msg, +		void *userData +		) +{ +	fprintf(stderr, "Validation layer: %s\n", msg); +	return VK_FALSE; +} + +VkResult CreateDebugReportCallbackEXT( +		VkInstance instance, +		const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, +		const VkAllocationCallbacks *pAllocator, +		VkDebugReportCallbackEXT *pCallback +		) +{ +	PFN_vkCreateDebugReportCallbackEXT func = (void*)vkGetInstanceProcAddr(instance, +			"vkCreateDebugReportCallbackEXT"); +	if (func) { +		return func(instance, pCreateInfo, pAllocator, pCallback); +	} else { +		return VK_ERROR_EXTENSION_NOT_PRESENT; +	} +} + +void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, +		const VkAllocationCallbacks *pAllocator) +{ +	PFN_vkDestroyDebugReportCallbackEXT func = (void*)vkGetInstanceProcAddr(instance, +			"vkDestroyDebugReportCallbackEXT"); +	if (func) { +		func(instance, callback, pAllocator); +	} +} + +SDL_Window *win; +VkInstance instance; +VkDebugReportCallbackEXT callback; +VkSurfaceKHR surface; +VkPhysicalDevice physicalDevice; +uint32_t qIndex; +uint32_t nImages; +VkDevice device; +VkSurfaceFormatKHR format; +VkCommandPool cmdPool; +VkCommandBuffer cmdBuffers; +VkSwapchainKHR swapchain; +VkImage *scImages; +VkImageView *scImageViews; +VkImage depthImage; +VkDeviceMemory depthMem; +VkImageView depthView; +VkExtent2D extent; +VkQueue graphicsQueue; +VkQueue presentQueue; + +static void createInstance() +{ +	VkApplicationInfo appInfo = { +		.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, +		.pApplicationName = "VulkanGame", +		.applicationVersion = VK_MAKE_VERSION(1, 0, 0), +		.pEngineName = "VulkanGameEngine", +		.engineVersion = VK_MAKE_VERSION(1, 0, 0), +		.apiVersion = VK_API_VERSION_1_0 +	}; + +	unsigned i, nRequired; +	if (!SDL_Vulkan_GetInstanceExtensions(win, &nRequired, NULL)) { +		ERRFQ("Could not get number of instance extensions\n"); +	} +	static const char *const additional[] = { +		VK_EXT_DEBUG_REPORT_EXTENSION_NAME +	}; +	const unsigned nAdditional = sizeof(additional) / sizeof(additional[0]); +	const uint32_t nExtensions = nRequired + nAdditional; +	const char **extensions = malloc(sizeof(const char*) * nExtensions); +	if (!SDL_Vulkan_GetInstanceExtensions(win, &nRequired, extensions)) { +		/* OS will handle memory freeing */ +		ERRQ(SDL_GetError()); +	} +	for (i = 0; i < nAdditional; ++i) { +		extensions[nRequired + i] = additional[i]; +	} + +	/* Just printing verbosely */ +	for (i = 0; i < nExtensions; ++i) { +		printf("%s\n", extensions[i]); +	} +	printf("\n"); + +#if 1 +	const uint32_t nLayers = 1; +	static const char *const layers[] = { +		"VK_LAYER_LUNARG_standard_validation" +	}; +#endif +	VkInstanceCreateInfo createInfo = { +		.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, +		.pApplicationInfo = &appInfo, +		.enabledExtensionCount = nExtensions, +		.ppEnabledExtensionNames = extensions, +#if 1 +		.enabledLayerCount = nLayers, +		.ppEnabledLayerNames = layers +#endif +	}; +	VkResult result; +	if ((result = vkCreateInstance(&createInfo, NULL, &instance)) != VK_SUCCESS) { +		/* OS will handle memory freeing */ +		ERRFQ("Could not create Vulkan instance: %d\n", result); +	} +	free(extensions); +} + +static void createDebugReporter() +{ +	VkDebugReportCallbackCreateInfoEXT createInfo = { +		.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, +		.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT, +		.pfnCallback = debugCallback +	}; +	if (CreateDebugReportCallbackEXT(instance, &createInfo, NULL, &callback) != VK_SUCCESS) { +		ERRQ("Could not create debug reporter"); +	} +} + +static void selectPhysicalDevice(const char *hint) +{ +	uint32_t nDevices; +	vkEnumeratePhysicalDevices(instance, &nDevices, NULL); +	if (!nDevices) { +		ERRQ("No physical devices found"); +	} +	VkPhysicalDevice *devices = malloc(nDevices * sizeof(*devices)); +	vkEnumeratePhysicalDevices(instance, &nDevices, devices); + +	/* Just printing verbosely */ +	for (uint32_t i = 0; i < nDevices; ++i) { +		VkPhysicalDeviceProperties props; +		vkGetPhysicalDeviceProperties(devices[i], &props); +		printf("%s\n", props.deviceName); +	} + +	/* FIXME: Blindly choosing the first device */ +	physicalDevice = devices[0]; + +	uint32_t nQueueFamilies = 0; +	vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &nQueueFamilies, NULL); +	VkQueueFamilyProperties *qprops = malloc(nQueueFamilies * sizeof(*qprops)); +	vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &nQueueFamilies, qprops); + +	for (qIndex = 0; qIndex < nQueueFamilies; ++qIndex) { +		if (qprops[qIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) { +			break; +		} +	} +	if (qIndex >= nQueueFamilies || nQueueFamilies <= 0) { +		ERRQ("No queue families capable of graphics"); +	} + +	VkBool32 canSurface; +	vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, qIndex, surface, &canSurface); +	if (!canSurface) { +		/* Strange devices may be accommodated for but not for now */ +		ERRQ("Graphics device cannot output a surface"); +	} + +	VkBool32 canSwapchain = 0; +	uint32_t nExtensions; +	vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &nExtensions, NULL); +	VkExtensionProperties *availableExtensions = malloc(nExtensions * sizeof(*availableExtensions)); +	vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &nExtensions, availableExtensions); + +	for (uint32_t i = 0; i < nExtensions; ++i) { +		if (!strcmp(availableExtensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { +			canSwapchain = 1; +			break; +		} +	} +	if (!canSwapchain) { +		ERRQ("Graphics device not swapchain capable"); +	} +	free(availableExtensions); +	free(qprops); +	free(devices); +} + +static void createLogicalDevice() +{ +	VkPhysicalDeviceFeatures features; +	vkGetPhysicalDeviceFeatures(physicalDevice, &features); +	float qPriority = 1.0f; +	VkDeviceQueueCreateInfo qCreateInfo = { +		.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, +		.queueFamilyIndex = qIndex, +		.queueCount = 1, +		.pQueuePriorities = &qPriority +	}; + +	const char *const swapchainName = VK_KHR_SWAPCHAIN_EXTENSION_NAME; +	VkDeviceCreateInfo createInfo = { +		.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, +		.pQueueCreateInfos = &qCreateInfo, +		.queueCreateInfoCount = 1, +		.pEnabledFeatures = &features, +		.enabledExtensionCount = 1, +		.ppEnabledExtensionNames = &swapchainName +	}; + +	if (vkCreateDevice(physicalDevice, &createInfo, NULL, &device)) { +		ERRQ("Could not create logical device"); +	} +} + +static void destroyLogicalDevice() +{ +	vkDestroyDevice(device, NULL); +} + +static void createCommandPool() +{ +	VkCommandPoolCreateInfo createInfo = { +		.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, +		.queueFamilyIndex = qIndex +	}; +	VkResult result; +	if ((result = vkCreateCommandPool(device, &createInfo, NULL, &cmdPool)) != VK_SUCCESS) { +		ERRFQ("Could not create command pool: %d\n", result); +	} +} + +static void destroyCommandPool() +{ +	vkDestroyCommandPool(device, cmdPool, NULL); +} + +static void createCommandBuffers() +{ +	VkCommandBufferAllocateInfo allocInfo = { +		.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, +		.commandPool = cmdPool, +		.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, +		.commandBufferCount = 1 +	}; +	VkResult result; +	if ((result = vkAllocateCommandBuffers(device, &allocInfo, &cmdBuffers)) != VK_SUCCESS) { +		ERRFQ("Could not create command buffers: %d\n", result); +	} +} + +static void destroyCommandBuffers() +{ +	vkFreeCommandBuffers(device, cmdPool, 1, &cmdBuffers); +} + +static void createSwapchain() +{ +	struct { +		VkSurfaceCapabilitiesKHR capabilities; +		VkSurfaceFormatKHR *formats; +		VkPresentModeKHR *presentModes; +	} sc = {0}; + +	vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &sc.capabilities); +	uint32_t nFormats; +	vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &nFormats, NULL); +	if (!nFormats) { +		ERRQ("No surface formats available"); +	} +	sc.formats = malloc(nFormats * sizeof(*sc.formats)); +	vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &nFormats, sc.formats); + +	uint32_t nPresentModes; +	vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &nPresentModes, NULL); +	if (!nPresentModes) { +		ERRQ("No surface present modes available"); +	} +	sc.presentModes = malloc(nPresentModes * sizeof(*sc.presentModes)); +	vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &nPresentModes, sc.presentModes); + +	for (uint32_t i = 0; i < nFormats; ++i) { +		VkSurfaceFormatKHR want = { +			VK_FORMAT_B8G8R8A8_UNORM,	// BGRA +			VK_COLOR_SPACE_SRGB_NONLINEAR_KHR +		}; +		if (sc.formats[i].format == VK_FORMAT_UNDEFINED) { +			format = want; +			fprintf(stderr, "Obtained wanted surface format on first try\n"); +			break; +		} +		if (sc.formats[i].format == want.format && sc.formats[i].colorSpace == want.colorSpace) { +			format = want; +			fprintf(stderr, "Obtained wanted format on try %d/%d\n", i+1, nFormats); +			break; +		} +	} + +	/* FIXME: Just assuming this is available */ +	VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; + +	int width, height; +	SDL_Vulkan_GetDrawableSize(win, &width, &height); +	extent.width = width; +	extent.height = height; + +	nImages = sc.capabilities.minImageCount + 1; +	if (sc.capabilities.maxImageCount > 0 && nImages > sc.capabilities.maxImageCount) { +		/* Clamp to max image count if too many requested */ +		nImages = sc.capabilities.maxImageCount; +	} + +	VkSwapchainCreateInfoKHR createInfo = { +		.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, +		.surface = surface, +		.minImageCount = nImages, +		.imageFormat = format.format, +		.imageExtent = extent, +		.imageArrayLayers = 1, +		.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, +		.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,	// assuming same family +		.preTransform = sc.capabilities.currentTransform, +		.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, +		.presentMode = presentMode, +		.clipped = VK_TRUE, +		.oldSwapchain = VK_NULL_HANDLE +	}; + +	VkResult result; +	if ((result = vkCreateSwapchainKHR(device, &createInfo, NULL, &swapchain)) != VK_SUCCESS) { +		ERRFQ("Could not create swapchain: %d\n", result); +	} +	free(sc.presentModes); +	free(sc.formats); +} + +static void destroySwapchain() +{ +	if (swapchain) { +		vkDestroySwapchainKHR(device, swapchain, NULL); +	} +	swapchain = NULL; +} + +/* Allocates and reallocates memory */ +static void createSwapchainImages() +{ +	vkGetSwapchainImagesKHR(device, swapchain, &nImages, NULL); +	scImages = realloc(scImages, nImages * sizeof(*scImages)); +	vkGetSwapchainImagesKHR(device, swapchain, &nImages, scImages); +	scImageViews = realloc(scImageViews, nImages * sizeof(*scImageViews)); + +	for (uint32_t i = 0; i < nImages; ++i) { +		VkImageViewCreateInfo createInfo = { +			.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, +			.image = scImages[i], +			.viewType = VK_IMAGE_VIEW_TYPE_2D, +			.format = format.format, +			.components.r = VK_COMPONENT_SWIZZLE_IDENTITY, +			.components.g = VK_COMPONENT_SWIZZLE_IDENTITY, +			.components.b = VK_COMPONENT_SWIZZLE_IDENTITY, +			.components.a = VK_COMPONENT_SWIZZLE_IDENTITY, +			.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, +			.subresourceRange.baseMipLevel = 0, +			.subresourceRange.levelCount = 1, +			.subresourceRange.baseArrayLayer = 0, +			.subresourceRange.layerCount = 1 + +		}; +		if (vkCreateImageView(device, &createInfo, NULL, &scImageViews[i]) != VK_SUCCESS) { +			ERRQ("Could not create swapchain image views"); +		} +	} +} + +static void destroySwapchainImages() +{ +	for (uint32_t i = 0; i < nImages; ++i) { +		vkDestroyImageView(device, scImageViews[i], NULL); +	} +	free(scImageViews); +	free(scImages); +	scImageViews = NULL; +	scImages = NULL; +} + +static void createDepthBuffer() +{ +	VkImageCreateInfo createInfo = { +		.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, +		.imageType = VK_IMAGE_TYPE_2D, +		.format = VK_FORMAT_D32_SFLOAT, +		.extent.width = extent.width, +		.extent.height = extent.height, +		.extent.depth = 1, +		.mipLevels = 1, +		.arrayLayers = 1, +		.samples = VK_SAMPLE_COUNT_1_BIT, +		.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, +		.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, +		.sharingMode = VK_SHARING_MODE_EXCLUSIVE, +	}; +	VkResult result; +	if ((result = vkCreateImage(device, &createInfo, NULL, &depthImage)) != VK_SUCCESS) { +		ERRFQ("Could not create depth image: %d\n", result); +	} +	VkPhysicalDeviceMemoryProperties memProps; +	vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps); +	VkMemoryRequirements memReq; +	vkGetImageMemoryRequirements(device, depthImage, &memReq); +	uint32_t typeFilter = memReq.memoryTypeBits; +	uint32_t memType; +	uint32_t props = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; +	for (memType = 0; memType < memProps.memoryTypeCount; ++memType) { +		if (typeFilter & (1<<memType) && (memProps.memoryTypes[memType].propertyFlags & props) == props) { +			break; +		} +	} +	VkMemoryAllocateInfo allocInfo = { +		.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, +		.allocationSize = memReq.size, +		.memoryTypeIndex = memType +	}; +	if ((result = vkAllocateMemory(device, &allocInfo, NULL, &depthMem)) != VK_SUCCESS) { +		ERRFQ("Could not allocate depth buffer memory: %d\n", result); +	} +	if ((result = vkBindImageMemory(device, depthImage, depthMem, 0)) != VK_SUCCESS) { +		ERRFQ("Could not bind depth buffer image memory: %d\n", result); +	} + +	VkImageViewCreateInfo viewInfo = { +		.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, +		.image = depthImage, +		.format = VK_FORMAT_D32_SFLOAT, +		.components.r = VK_COMPONENT_SWIZZLE_R, +		.components.g = VK_COMPONENT_SWIZZLE_G, +		.components.b = VK_COMPONENT_SWIZZLE_B, +		.components.a = VK_COMPONENT_SWIZZLE_A, +		.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, +		.subresourceRange.baseMipLevel = 0, +		.subresourceRange.levelCount = 1, +		.subresourceRange.baseArrayLayer = 0, +		.subresourceRange.layerCount = 1, +		.viewType = VK_IMAGE_VIEW_TYPE_2D, +	}; +	if ((result = vkCreateImageView(device, &viewInfo, NULL, &depthView)) != VK_SUCCESS) { +		ERRFQ("Could not create depth buffer image view: %d\n", result); +	} +} + +static void destroyDepthBuffer() +{ +	vkDestroyImageView(device, depthView, NULL); +	vkFreeMemory(device, depthMem, NULL); +	vkDestroyImage(device, depthImage, NULL); +} + +void initVulkan() +{ +	createInstance(); +	createDebugReporter(); +	if (!SDL_Vulkan_CreateSurface(win, instance, &surface)) { +		ERRQ(SDL_GetError()); +	} +} + +void deinitVulkan() +{ +	vkDestroySurfaceKHR(instance, surface, NULL); +	DestroyDebugReportCallbackEXT(instance, callback, NULL); +	vkDestroyInstance(instance, NULL); +} + +void beginVulkan() +{ +	selectPhysicalDevice(NULL); +	createLogicalDevice(); +	createCommandPool(); +	createCommandBuffers(); +	vkGetDeviceQueue(device, qIndex, 0, &graphicsQueue); +	vkGetDeviceQueue(device, qIndex, 0, &presentQueue); +	createSwapchain(); +	createSwapchainImages(); +	createDepthBuffer(); +} + +void endVulkan() +{ +	destroyDepthBuffer(); +	destroySwapchainImages(); +	destroySwapchain(); +	destroyCommandBuffers(); +	destroyCommandPool(); +	destroyLogicalDevice(); +} + +struct Uniform uniData; +VkBuffer uniBuffer; +VkDeviceMemory uniMem; + +static void createUniformBuffer() +{ +	VkBufferCreateInfo createInfo = { +		.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, +		.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, +		.size = sizeof(struct Uniform), +		.sharingMode = VK_SHARING_MODE_EXCLUSIVE +	}; + +	VkResult result; +	if ((result = vkCreateBuffer(device, &createInfo, NULL, &uniBuffer)) != VK_SUCCESS) { +		ERRFQ("Could not create uniform buffer: %d\n", result); +	} + +	VkPhysicalDeviceMemoryProperties memProps; +	vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps); +	VkMemoryRequirements memReq; +	vkGetBufferMemoryRequirements(device, uniBuffer, &memReq); +	uint32_t typeFilter = memReq.memoryTypeBits; +	uint32_t memType; +	uint32_t props = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; +	for (memType = 0; memType < memProps.memoryTypeCount; ++memType) { +		if (typeFilter & (1<<memType) && (memProps.memoryTypes[memType].propertyFlags & props) == props) { +			break; +		} +	} + +	VkMemoryAllocateInfo allocInfo = { +		.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, +		.allocationSize = memReq.size, +		.memoryTypeIndex = memType +	}; + +	if ((result = vkAllocateMemory(device, &allocInfo, NULL, &uniMem)) != VK_SUCCESS) { +		ERRFQ("Could not allocate uniform buffer memory: %d\n", result); +	} + +	if ((result = vkBindBufferMemory(device, uniBuffer, uniMem, 0)) != VK_SUCCESS) { +		ERRFQ("Could not bind uniform buffer memory: %d\n", result); +	} +} + +static void populateUniformBuffer() +{ +	identity_init(uniData.model); +	identity_init(uniData.view); +	identity_init(uniData.proj); +	VkResult result; +	void *data; +	if ((result = vkMapMemory(device, uniMem, 0, sizeof(uniData), 0, &data)) != VK_SUCCESS) { +		ERRFQ("Could not map uniform buffer memory: %d\n", result); +	} +	memcpy(data, &uniData, sizeof(uniData)); +	vkUnmapMemory(device, uniMem); +} + +VkDescriptorSetLayout descriptorSetLayout; + +static void createDescriptorSetLayout() +{ +	VkDescriptorSetLayoutBinding layoutBinding = { +		.binding = 0, +		.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, +		.descriptorCount = 1, +		.stageFlags = VK_SHADER_STAGE_VERTEX_BIT +	}; +	VkDescriptorSetLayoutCreateInfo createInfo = { +		.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_CREATE_INFO, +		.bindingCount = 1, +		.pBindings = &layoutBinding +	}; +	VkResult result; +	if ((result = vkCreateDescriptorSetLayout(device, &createInfo, NULL, descriptorSetLayout)) != VK_SUCCESS) { +		ERRFQ("Could not create descriptor set layout: %d\n", result); +	} +} + +static void createPipelineLayout() +{ +	VkPipelineLayoutCreateInfo createInfo = { +		.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, +		.pushConstantRangeCount = 0, +		.setLayoutCount = 1,	// number of descriptor sets +		.pSetLayouts = &descriptorSetLayout +	}; +	VkResult result; +	if ((result = vkCreatePipelineLayout(device, &createInfo, NULL, &pipelineLayout)) != VK_SUCCESS) { +		ERRFQ("Could not create pipeline layout: %d\n", result); +	} +} + +VkShaderModule vShaderModule; +VkShaderModule fShaderModule; + +static void createShaderModules() +{ +	size_t vertLen, fragLen; +	uint8_t *vertCode = read_file("vert.spv", &vertLen); +	if (!vertCode) { +		ERRQ("Could not read vert.spv"); +	} +	uint8_t *fragCode = read_file("frag.spv", &fragLen); +	if (!fragCode) { +		ERRQ("Could not read frag.spv"); +	} + +	VkShaderModuleCreateInfo createInfo = { +		.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, +		.codeSize = vertLen, +		.pCode = (void*)vertCode +	}; + +	VkResult result; +	if ((result = vkCreateShaderModule(device, &createInfo, NULL, &vShaderModule)) != VK_SUCCESS) { +		ERRFQ("Could not create vertex shader module: %d\n", result); +	} + +	createInfo.codeSize = fraglen; +	createInfo.pCode = (void*)fragCode; +	if ((result = vkCreateShaderModule(device, &createInfo, NULL, &fShaderModule)) != VK_SUCCESS) { +		ERRFQ("Could not create fragment shader module: %d\n", result); +	} + +	free(vertCode); +	free(fragCode); +} + +static void createGraphicsPipeline + +void setupScene() +{ +	createUniformBuffer(); +	populateUniformBuffer(); +	createDescriptorSetLayout(); +	createPipelineLayout(); +	createShaderModules(); +} + +int main(int argc, char **argv) +{ +	if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { +		ERRQ(SDL_GetError()); +	} +	if (SDL_Vulkan_LoadLibrary(NULL)) { +		ERRQ(SDL_GetError()); +	} +	win = SDL_CreateWindow( +			"Vulkan Window", +			SDL_WINDOWPOS_CENTERED, +			SDL_WINDOWPOS_CENTERED, +			1280, +			720, +			SDL_WINDOW_VULKAN +			); +	if (!win) { +		ERRQ(SDL_GetError()); +	} +	initVulkan(); +	beginVulkan(); + +	SDL_Event e; +	while (1) { +		while (SDL_PollEvent(&e)) { +			if (e.type == SDL_QUIT) { +				goto quit; +			} +		} +	} +quit: +	endVulkan(); +	deinitVulkan(); +	SDL_DestroyWindow(win); +	SDL_Vulkan_UnloadLibrary(); +	SDL_Quit(); +	return 0; +}  | 
