Files
gio/internal/vk/vulkan.go
T
Elias Naur 8613d81a94 gpu/headless: accept the lavapipe Vulkan driver
On headless setups such as sr.ht CI machines, lavapipe is the only
available Vulkan driver. This change accepts the lavapipe software
driver for headless contexts, so that CI won't fall back to OpenGL.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-11-10 15:39:37 +01:00

2082 lines
84 KiB
Go

// SPDX-License-Identifier: Unlicense OR MIT
//go:build linux || freebsd
// +build linux freebsd
package vk
/*
#cgo linux freebsd LDFLAGS: -ldl
#cgo freebsd CFLAGS: -I/usr/local/include
#cgo CFLAGS: -Werror -Werror=return-type
#define VK_NO_PROTOTYPES 1
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
#include <vulkan/vulkan.h>
#define __USE_GNU
#include <dlfcn.h>
#include <stdlib.h>
static VkResult vkCreateInstance(PFN_vkCreateInstance f, VkInstanceCreateInfo pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
return f(&pCreateInfo, pAllocator, pInstance);
}
static void vkDestroyInstance(PFN_vkDestroyInstance f, VkInstance instance, const VkAllocationCallbacks *pAllocator) {
f(instance, pAllocator);
}
static VkResult vkEnumeratePhysicalDevices(PFN_vkEnumeratePhysicalDevices f, VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices) {
return f(instance, pPhysicalDeviceCount, pPhysicalDevices);
}
static void vkGetPhysicalDeviceQueueFamilyProperties(PFN_vkGetPhysicalDeviceQueueFamilyProperties f, VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties *pQueueFamilyProperties) {
f(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
}
static void vkGetPhysicalDeviceFormatProperties(PFN_vkGetPhysicalDeviceFormatProperties f, VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties *pFormatProperties) {
f(physicalDevice, format, pFormatProperties);
}
static VkResult vkCreateDevice(PFN_vkCreateDevice f, VkPhysicalDevice physicalDevice, VkDeviceCreateInfo pCreateInfo, VkDeviceQueueCreateInfo qinf, const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
pCreateInfo.pQueueCreateInfos = &qinf;
return f(physicalDevice, &pCreateInfo, pAllocator, pDevice);
}
static void vkDestroyDevice(PFN_vkDestroyDevice f, VkDevice device, const VkAllocationCallbacks *pAllocator) {
f(device, pAllocator);
}
static void vkGetDeviceQueue(PFN_vkGetDeviceQueue f, VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
f(device, queueFamilyIndex, queueIndex, pQueue);
}
static VkResult vkCreateImageView(PFN_vkCreateImageView f, VkDevice device, const VkImageViewCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
return f(device, pCreateInfo, pAllocator, pView);
}
static void vkDestroyImageView(PFN_vkDestroyImageView f, VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
f(device, imageView, pAllocator);
}
static VkResult vkCreateFramebuffer(PFN_vkCreateFramebuffer f, VkDevice device, VkFramebufferCreateInfo pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) {
return f(device, &pCreateInfo, pAllocator, pFramebuffer);
}
static void vkDestroyFramebuffer(PFN_vkDestroyFramebuffer f, VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
f(device, framebuffer, pAllocator);
}
static VkResult vkDeviceWaitIdle(PFN_vkDeviceWaitIdle f, VkDevice device) {
return f(device);
}
static VkResult vkQueueWaitIdle(PFN_vkQueueWaitIdle f, VkQueue queue) {
return f(queue);
}
static VkResult vkCreateSemaphore(PFN_vkCreateSemaphore f, VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
return f(device, pCreateInfo, pAllocator, pSemaphore);
}
static void vkDestroySemaphore(PFN_vkDestroySemaphore f, VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
f(device, semaphore, pAllocator);
}
static VkResult vkCreateRenderPass(PFN_vkCreateRenderPass f, VkDevice device, VkRenderPassCreateInfo pCreateInfo, VkSubpassDescription subpassInf, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
pCreateInfo.pSubpasses = &subpassInf;
return f(device, &pCreateInfo, pAllocator, pRenderPass);
}
static void vkDestroyRenderPass(PFN_vkDestroyRenderPass f, VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
f(device, renderPass, pAllocator);
}
static VkResult vkCreateCommandPool(PFN_vkCreateCommandPool f, VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) {
return f(device, pCreateInfo, pAllocator, pCommandPool);
}
static void vkDestroyCommandPool(PFN_vkDestroyCommandPool f, VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
f(device, commandPool, pAllocator);
}
static VkResult vkAllocateCommandBuffers(PFN_vkAllocateCommandBuffers f, VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo, VkCommandBuffer *pCommandBuffers) {
return f(device, pAllocateInfo, pCommandBuffers);
}
static void vkFreeCommandBuffers(PFN_vkFreeCommandBuffers f, VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) {
f(device, commandPool, commandBufferCount, pCommandBuffers);
}
static VkResult vkBeginCommandBuffer(PFN_vkBeginCommandBuffer f, VkCommandBuffer commandBuffer, VkCommandBufferBeginInfo pBeginInfo) {
return f(commandBuffer, &pBeginInfo);
}
static VkResult vkEndCommandBuffer(PFN_vkEndCommandBuffer f, VkCommandBuffer commandBuffer) {
return f(commandBuffer);
}
static VkResult vkQueueSubmit(PFN_vkQueueSubmit f, VkQueue queue, VkSubmitInfo pSubmits, VkFence fence) {
return f(queue, 1, &pSubmits, fence);
}
static void vkCmdBeginRenderPass(PFN_vkCmdBeginRenderPass f, VkCommandBuffer commandBuffer, VkRenderPassBeginInfo pRenderPassBegin, VkSubpassContents contents) {
f(commandBuffer, &pRenderPassBegin, contents);
}
static void vkCmdEndRenderPass(PFN_vkCmdEndRenderPass f, VkCommandBuffer commandBuffer) {
f(commandBuffer);
}
static void vkCmdCopyBuffer(PFN_vkCmdCopyBuffer f, VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy *pRegions) {
f(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
}
static void vkCmdCopyBufferToImage(PFN_vkCmdCopyBufferToImage f, VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
f(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
}
static void vkCmdPipelineBarrier(PFN_vkCmdPipelineBarrier f, VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
f(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
}
static void vkCmdPushConstants(PFN_vkCmdPushConstants f, VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void *pValues) {
f(commandBuffer, layout, stageFlags, offset, size, pValues);
}
static void vkCmdBindPipeline(PFN_vkCmdBindPipeline f, VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) {
f(commandBuffer, pipelineBindPoint, pipeline);
}
static void vkCmdBindVertexBuffers(PFN_vkCmdBindVertexBuffers f, VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) {
f(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
}
static void vkCmdSetViewport(PFN_vkCmdSetViewport f, VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports) {
f(commandBuffer, firstViewport, viewportCount, pViewports);
}
static void vkCmdBindIndexBuffer(PFN_vkCmdBindIndexBuffer f, VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) {
f(commandBuffer, buffer, offset, indexType);
}
static void vkCmdDraw(PFN_vkCmdDraw f, VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) {
f(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
}
static void vkCmdDrawIndexed(PFN_vkCmdDrawIndexed f, VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
f(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
}
static void vkCmdBindDescriptorSets(PFN_vkCmdBindDescriptorSets f, VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t *pDynamicOffsets) {
f(commandBuffer, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
}
static void vkCmdCopyImageToBuffer(PFN_vkCmdCopyImageToBuffer f, VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
f(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
}
static void vkCmdDispatch(PFN_vkCmdDispatch f, VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
f(commandBuffer, groupCountX, groupCountY, groupCountZ);
}
static VkResult vkCreateImage(PFN_vkCreateImage f, VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
return f(device, pCreateInfo, pAllocator, pImage);
}
static void vkDestroyImage(PFN_vkDestroyImage f, VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
f(device, image, pAllocator);
}
static void vkGetImageMemoryRequirements(PFN_vkGetImageMemoryRequirements f, VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
f(device, image, pMemoryRequirements);
}
static VkResult vkAllocateMemory(PFN_vkAllocateMemory f, VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
return f(device, pAllocateInfo, pAllocator, pMemory);
}
static VkResult vkBindImageMemory(PFN_vkBindImageMemory f, VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset) {
return f(device, image, memory, memoryOffset);
}
static void vkFreeMemory(PFN_vkFreeMemory f, VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator) {
f(device, memory, pAllocator);
}
static void vkGetPhysicalDeviceMemoryProperties(PFN_vkGetPhysicalDeviceMemoryProperties f, VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties) {
f(physicalDevice, pMemoryProperties);
}
static VkResult vkCreateSampler(PFN_vkCreateSampler f,VkDevice device, const VkSamplerCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
return f(device, pCreateInfo, pAllocator, pSampler);
}
static void vkDestroySampler(PFN_vkDestroySampler f, VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
f(device, sampler, pAllocator);
}
static VkResult vkCreateBuffer(PFN_vkCreateBuffer f, VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
return f(device, pCreateInfo, pAllocator, pBuffer);
}
static void vkDestroyBuffer(PFN_vkDestroyBuffer f, VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
f(device, buffer, pAllocator);
}
static void vkGetBufferMemoryRequirements(PFN_vkGetBufferMemoryRequirements f, VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements) {
f(device, buffer, pMemoryRequirements);
}
static VkResult vkBindBufferMemory(PFN_vkBindBufferMemory f, VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset) {
return f(device, buffer, memory, memoryOffset);
}
static VkResult vkCreateShaderModule(PFN_vkCreateShaderModule f, VkDevice device, VkShaderModuleCreateInfo pCreateInfo, const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) {
return f(device, &pCreateInfo, pAllocator, pShaderModule);
}
static void vkDestroyShaderModule(PFN_vkDestroyShaderModule f, VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator) {
f(device, shaderModule, pAllocator);
}
static VkResult vkCreateGraphicsPipelines(PFN_vkCreateGraphicsPipelines f, VkDevice device, VkPipelineCache pipelineCache, VkGraphicsPipelineCreateInfo pCreateInfo, VkPipelineDynamicStateCreateInfo dynInf, VkPipelineColorBlendStateCreateInfo blendInf, VkPipelineVertexInputStateCreateInfo vertexInf, VkPipelineViewportStateCreateInfo viewportInf, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
pCreateInfo.pDynamicState = &dynInf;
pCreateInfo.pViewportState = &viewportInf;
pCreateInfo.pColorBlendState = &blendInf;
pCreateInfo.pVertexInputState = &vertexInf;
return f(device, pipelineCache, 1, &pCreateInfo, pAllocator, pPipelines);
}
static void vkDestroyPipeline(PFN_vkDestroyPipeline f, VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
f(device, pipeline, pAllocator);
}
static VkResult vkCreatePipelineLayout(PFN_vkCreatePipelineLayout f, VkDevice device, VkPipelineLayoutCreateInfo pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
return f(device, &pCreateInfo, pAllocator, pPipelineLayout);
}
static void vkDestroyPipelineLayout(PFN_vkDestroyPipelineLayout f, VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks *pAllocator) {
f(device, pipelineLayout, pAllocator);
}
static VkResult vkCreateDescriptorSetLayout(PFN_vkCreateDescriptorSetLayout f, VkDevice device, VkDescriptorSetLayoutCreateInfo pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout) {
return f(device, &pCreateInfo, pAllocator, pSetLayout);
}
static void vkDestroyDescriptorSetLayout(PFN_vkDestroyDescriptorSetLayout f, VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks *pAllocator) {
f(device, descriptorSetLayout, pAllocator);
}
static VkResult vkMapMemory(PFN_vkMapMemory f, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void **ppData) {
return f(device, memory, offset, size, flags, ppData);
}
static void vkUnmapMemory(PFN_vkUnmapMemory f, VkDevice device, VkDeviceMemory memory) {
f(device, memory);
}
static VkResult vkResetCommandBuffer(PFN_vkResetCommandBuffer f, VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
return f(commandBuffer, flags);
}
static VkResult vkCreateDescriptorPool(PFN_vkCreateDescriptorPool f, VkDevice device, VkDescriptorPoolCreateInfo pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool) {
return f(device, &pCreateInfo, pAllocator, pDescriptorPool);
}
static void vkDestroyDescriptorPool(PFN_vkDestroyDescriptorPool f, VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator) {
f(device, descriptorPool, pAllocator);
}
static VkResult vkAllocateDescriptorSets(PFN_vkAllocateDescriptorSets f, VkDevice device, VkDescriptorSetAllocateInfo pAllocateInfo, VkDescriptorSet *pDescriptorSets) {
return f(device, &pAllocateInfo, pDescriptorSets);
}
static VkResult vkFreeDescriptorSets(PFN_vkFreeDescriptorSets f, VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets) {
return f(device, descriptorPool, descriptorSetCount, pDescriptorSets);
}
static void vkUpdateDescriptorSets(PFN_vkUpdateDescriptorSets f, VkDevice device, VkWriteDescriptorSet pDescriptorWrite, uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) {
f(device, 1, &pDescriptorWrite, descriptorCopyCount, pDescriptorCopies);
}
static VkResult vkResetDescriptorPool(PFN_vkResetDescriptorPool f, VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) {
return f(device, descriptorPool, flags);
}
static void vkCmdCopyImage(PFN_vkCmdCopyImage f, VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions) {
f(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions);
}
static VkResult vkCreateComputePipelines(PFN_vkCreateComputePipelines f, VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) {
return f(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines);
}
static VkResult vkCreateFence(PFN_vkCreateFence f, VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
return f(device, pCreateInfo, pAllocator, pFence);
}
static void vkDestroyFence(PFN_vkDestroyFence f, VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
f(device, fence, pAllocator);
}
static VkResult vkWaitForFences(PFN_vkWaitForFences f, VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout) {
return f(device, fenceCount, pFences, waitAll, timeout);
}
static VkResult vkResetFences(PFN_vkResetFences f, VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
return f(device, fenceCount, pFences);
}
static void vkGetPhysicalDeviceProperties(PFN_vkGetPhysicalDeviceProperties f, VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties) {
f(physicalDevice, pProperties);
}
static VkResult vkGetPhysicalDeviceSurfaceSupportKHR(PFN_vkGetPhysicalDeviceSurfaceSupportKHR f, VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32 *pSupported) {
return f(physicalDevice, queueFamilyIndex, surface, pSupported);
}
static void vkDestroySurfaceKHR(PFN_vkDestroySurfaceKHR f, VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) {
f(instance, surface, pAllocator);
}
static VkResult vkGetPhysicalDeviceSurfaceFormatsKHR(PFN_vkGetPhysicalDeviceSurfaceFormatsKHR f, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pSurfaceFormatCount, VkSurfaceFormatKHR *pSurfaceFormats) {
return f(physicalDevice, surface, pSurfaceFormatCount, pSurfaceFormats);
}
static VkResult vkGetPhysicalDeviceSurfacePresentModesKHR(PFN_vkGetPhysicalDeviceSurfacePresentModesKHR f, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes) {
return f(physicalDevice, surface, pPresentModeCount, pPresentModes);
}
static VkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR f, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) {
return f(physicalDevice, surface, pSurfaceCapabilities);
}
static VkResult vkCreateSwapchainKHR(PFN_vkCreateSwapchainKHR f, VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
return f(device, pCreateInfo, pAllocator, pSwapchain);
}
static void vkDestroySwapchainKHR(PFN_vkDestroySwapchainKHR f, VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
f(device, swapchain, pAllocator);
}
static VkResult vkGetSwapchainImagesKHR(PFN_vkGetSwapchainImagesKHR f, VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) {
return f(device, swapchain, pSwapchainImageCount, pSwapchainImages);
}
// indexAndResult holds both an integer and a result returned by value, to
// avoid Go heap allocation of the integer with Vulkan's return style.
struct intAndResult {
uint32_t uint;
VkResult res;
};
static struct intAndResult vkAcquireNextImageKHR(PFN_vkAcquireNextImageKHR f, VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence) {
struct intAndResult res;
res.res = f(device, swapchain, timeout, semaphore, fence, &res.uint);
return res;
}
static VkResult vkQueuePresentKHR(PFN_vkQueuePresentKHR f, VkQueue queue, const VkPresentInfoKHR pPresentInfo) {
return f(queue, &pPresentInfo);
}
*/
import "C"
import (
"errors"
"fmt"
"image"
"math"
"reflect"
"runtime"
"sync"
"unsafe"
)
type (
AttachmentLoadOp = C.VkAttachmentLoadOp
AccessFlags = C.VkAccessFlags
BlendFactor = C.VkBlendFactor
Buffer = C.VkBuffer
BufferImageCopy = C.VkBufferImageCopy
BufferMemoryBarrier = C.VkBufferMemoryBarrier
BufferUsageFlags = C.VkBufferUsageFlags
CommandPool = C.VkCommandPool
CommandBuffer = C.VkCommandBuffer
DependencyFlags = C.VkDependencyFlags
DescriptorPool = C.VkDescriptorPool
DescriptorPoolSize = C.VkDescriptorPoolSize
DescriptorSet = C.VkDescriptorSet
DescriptorSetLayout = C.VkDescriptorSetLayout
DescriptorType = C.VkDescriptorType
Device = C.VkDevice
DeviceMemory = C.VkDeviceMemory
DeviceSize = C.VkDeviceSize
Fence = C.VkFence
Queue = C.VkQueue
IndexType = C.VkIndexType
Image = C.VkImage
ImageCopy = C.VkImageCopy
ImageLayout = C.VkImageLayout
ImageMemoryBarrier = C.VkImageMemoryBarrier
ImageUsageFlags = C.VkImageUsageFlags
ImageView = C.VkImageView
Instance = C.VkInstance
Filter = C.VkFilter
Format = C.VkFormat
FormatFeatureFlags = C.VkFormatFeatureFlags
Framebuffer = C.VkFramebuffer
MemoryBarrier = C.VkMemoryBarrier
MemoryPropertyFlags = C.VkMemoryPropertyFlags
Pipeline = C.VkPipeline
PipelineBindPoint = C.VkPipelineBindPoint
PipelineLayout = C.VkPipelineLayout
PipelineStageFlags = C.VkPipelineStageFlags
PhysicalDevice = C.VkPhysicalDevice
PrimitiveTopology = C.VkPrimitiveTopology
PushConstantRange = C.VkPushConstantRange
QueueFamilyProperties = C.VkQueueFamilyProperties
QueueFlags = C.VkQueueFlags
RenderPass = C.VkRenderPass
Sampler = C.VkSampler
SamplerMipmapMode = C.VkSamplerMipmapMode
Semaphore = C.VkSemaphore
ShaderModule = C.VkShaderModule
ShaderStageFlags = C.VkShaderStageFlags
SubpassDependency = C.VkSubpassDependency
Viewport = C.VkViewport
WriteDescriptorSet = C.VkWriteDescriptorSet
Surface = C.VkSurfaceKHR
SurfaceCapabilities = C.VkSurfaceCapabilitiesKHR
Swapchain = C.VkSwapchainKHR
)
type VertexInputBindingDescription struct {
Binding int
Stride int
}
type VertexInputAttributeDescription struct {
Location int
Binding int
Format Format
Offset int
}
type DescriptorSetLayoutBinding struct {
Binding int
DescriptorType DescriptorType
StageFlags ShaderStageFlags
}
type Error C.VkResult
const (
FORMAT_R8G8B8A8_UNORM Format = C.VK_FORMAT_R8G8B8A8_UNORM
FORMAT_B8G8R8A8_SRGB Format = C.VK_FORMAT_B8G8R8A8_SRGB
FORMAT_R8G8B8A8_SRGB Format = C.VK_FORMAT_R8G8B8A8_SRGB
FORMAT_R16_SFLOAT Format = C.VK_FORMAT_R16_SFLOAT
FORMAT_R32_SFLOAT Format = C.VK_FORMAT_R32_SFLOAT
FORMAT_R32G32_SFLOAT Format = C.VK_FORMAT_R32G32_SFLOAT
FORMAT_R32G32B32_SFLOAT Format = C.VK_FORMAT_R32G32B32_SFLOAT
FORMAT_R32G32B32A32_SFLOAT Format = C.VK_FORMAT_R32G32B32A32_SFLOAT
FORMAT_FEATURE_COLOR_ATTACHMENT_BIT FormatFeatureFlags = C.VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT
FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT FormatFeatureFlags = C.VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT
FORMAT_FEATURE_SAMPLED_IMAGE_BIT FormatFeatureFlags = C.VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT
IMAGE_USAGE_SAMPLED_BIT ImageUsageFlags = C.VK_IMAGE_USAGE_SAMPLED_BIT
IMAGE_USAGE_COLOR_ATTACHMENT_BIT ImageUsageFlags = C.VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
IMAGE_USAGE_STORAGE_BIT ImageUsageFlags = C.VK_IMAGE_USAGE_STORAGE_BIT
IMAGE_USAGE_TRANSFER_DST_BIT ImageUsageFlags = C.VK_IMAGE_USAGE_TRANSFER_DST_BIT
IMAGE_USAGE_TRANSFER_SRC_BIT ImageUsageFlags = C.VK_IMAGE_USAGE_TRANSFER_SRC_BIT
FILTER_NEAREST Filter = C.VK_FILTER_NEAREST
FILTER_LINEAR Filter = C.VK_FILTER_LINEAR
ATTACHMENT_LOAD_OP_CLEAR AttachmentLoadOp = C.VK_ATTACHMENT_LOAD_OP_CLEAR
ATTACHMENT_LOAD_OP_DONT_CARE AttachmentLoadOp = C.VK_ATTACHMENT_LOAD_OP_DONT_CARE
ATTACHMENT_LOAD_OP_LOAD AttachmentLoadOp = C.VK_ATTACHMENT_LOAD_OP_LOAD
IMAGE_LAYOUT_UNDEFINED ImageLayout = C.VK_IMAGE_LAYOUT_UNDEFINED
IMAGE_LAYOUT_PRESENT_SRC_KHR ImageLayout = C.VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ImageLayout = C.VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ImageLayout = C.VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ImageLayout = C.VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ImageLayout = C.VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
IMAGE_LAYOUT_GENERAL ImageLayout = C.VK_IMAGE_LAYOUT_GENERAL
BUFFER_USAGE_TRANSFER_DST_BIT BufferUsageFlags = C.VK_BUFFER_USAGE_TRANSFER_DST_BIT
BUFFER_USAGE_TRANSFER_SRC_BIT BufferUsageFlags = C.VK_BUFFER_USAGE_TRANSFER_SRC_BIT
BUFFER_USAGE_UNIFORM_BUFFER_BIT BufferUsageFlags = C.VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
BUFFER_USAGE_STORAGE_BUFFER_BIT BufferUsageFlags = C.VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
BUFFER_USAGE_INDEX_BUFFER_BIT BufferUsageFlags = C.VK_BUFFER_USAGE_INDEX_BUFFER_BIT
BUFFER_USAGE_VERTEX_BUFFER_BIT BufferUsageFlags = C.VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
ERROR_OUT_OF_DATE_KHR = Error(C.VK_ERROR_OUT_OF_DATE_KHR)
ERROR_SURFACE_LOST_KHR = Error(C.VK_ERROR_SURFACE_LOST_KHR)
ERROR_DEVICE_LOST = Error(C.VK_ERROR_DEVICE_LOST)
SUBOPTIMAL_KHR = Error(C.VK_SUBOPTIMAL_KHR)
BLEND_FACTOR_ZERO BlendFactor = C.VK_BLEND_FACTOR_ZERO
BLEND_FACTOR_ONE BlendFactor = C.VK_BLEND_FACTOR_ONE
BLEND_FACTOR_ONE_MINUS_SRC_ALPHA BlendFactor = C.VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
BLEND_FACTOR_DST_COLOR BlendFactor = C.VK_BLEND_FACTOR_DST_COLOR
PRIMITIVE_TOPOLOGY_TRIANGLE_LIST PrimitiveTopology = C.VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP PrimitiveTopology = C.VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
SHADER_STAGE_VERTEX_BIT ShaderStageFlags = C.VK_SHADER_STAGE_VERTEX_BIT
SHADER_STAGE_FRAGMENT_BIT ShaderStageFlags = C.VK_SHADER_STAGE_FRAGMENT_BIT
SHADER_STAGE_COMPUTE_BIT ShaderStageFlags = C.VK_SHADER_STAGE_COMPUTE_BIT
DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER DescriptorType = C.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
DESCRIPTOR_TYPE_UNIFORM_BUFFER DescriptorType = C.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
DESCRIPTOR_TYPE_STORAGE_BUFFER DescriptorType = C.VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
DESCRIPTOR_TYPE_STORAGE_IMAGE DescriptorType = C.VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
MEMORY_PROPERTY_DEVICE_LOCAL_BIT MemoryPropertyFlags = C.VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
MEMORY_PROPERTY_HOST_VISIBLE_BIT MemoryPropertyFlags = C.VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
MEMORY_PROPERTY_HOST_COHERENT_BIT MemoryPropertyFlags = C.VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
DEPENDENCY_BY_REGION_BIT DependencyFlags = C.VK_DEPENDENCY_BY_REGION_BIT
PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
PIPELINE_STAGE_TRANSFER_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_TRANSFER_BIT
PIPELINE_STAGE_FRAGMENT_SHADER_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
PIPELINE_STAGE_COMPUTE_SHADER_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
PIPELINE_STAGE_TOP_OF_PIPE_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
PIPELINE_STAGE_HOST_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_HOST_BIT
PIPELINE_STAGE_VERTEX_INPUT_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_VERTEX_INPUT_BIT
PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
ACCESS_MEMORY_READ_BIT AccessFlags = C.VK_ACCESS_MEMORY_READ_BIT
ACCESS_MEMORY_WRITE_BIT AccessFlags = C.VK_ACCESS_MEMORY_WRITE_BIT
ACCESS_TRANSFER_READ_BIT AccessFlags = C.VK_ACCESS_TRANSFER_READ_BIT
ACCESS_TRANSFER_WRITE_BIT AccessFlags = C.VK_ACCESS_TRANSFER_WRITE_BIT
ACCESS_SHADER_READ_BIT AccessFlags = C.VK_ACCESS_SHADER_READ_BIT
ACCESS_SHADER_WRITE_BIT AccessFlags = C.VK_ACCESS_SHADER_WRITE_BIT
ACCESS_COLOR_ATTACHMENT_READ_BIT AccessFlags = C.VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
ACCESS_COLOR_ATTACHMENT_WRITE_BIT AccessFlags = C.VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
ACCESS_HOST_READ_BIT AccessFlags = C.VK_ACCESS_HOST_READ_BIT
ACCESS_HOST_WRITE_BIT AccessFlags = C.VK_ACCESS_HOST_WRITE_BIT
ACCESS_VERTEX_ATTRIBUTE_READ_BIT AccessFlags = C.VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT
ACCESS_INDEX_READ_BIT AccessFlags = C.VK_ACCESS_INDEX_READ_BIT
PIPELINE_BIND_POINT_COMPUTE PipelineBindPoint = C.VK_PIPELINE_BIND_POINT_COMPUTE
PIPELINE_BIND_POINT_GRAPHICS PipelineBindPoint = C.VK_PIPELINE_BIND_POINT_GRAPHICS
INDEX_TYPE_UINT16 IndexType = C.VK_INDEX_TYPE_UINT16
INDEX_TYPE_UINT32 IndexType = C.VK_INDEX_TYPE_UINT32
QUEUE_GRAPHICS_BIT QueueFlags = C.VK_QUEUE_GRAPHICS_BIT
QUEUE_COMPUTE_BIT QueueFlags = C.VK_QUEUE_COMPUTE_BIT
)
var (
once sync.Once
loadErr error
loadFuncs []func(dlopen func(name string) *[0]byte)
)
var funcs struct {
vkCreateInstance C.PFN_vkCreateInstance
vkDestroyInstance C.PFN_vkDestroyInstance
vkEnumeratePhysicalDevices C.PFN_vkEnumeratePhysicalDevices
vkGetPhysicalDeviceQueueFamilyProperties C.PFN_vkGetPhysicalDeviceQueueFamilyProperties
vkGetPhysicalDeviceFormatProperties C.PFN_vkGetPhysicalDeviceFormatProperties
vkCreateDevice C.PFN_vkCreateDevice
vkDestroyDevice C.PFN_vkDestroyDevice
vkGetDeviceQueue C.PFN_vkGetDeviceQueue
vkCreateImageView C.PFN_vkCreateImageView
vkDestroyImageView C.PFN_vkDestroyImageView
vkCreateFramebuffer C.PFN_vkCreateFramebuffer
vkDestroyFramebuffer C.PFN_vkDestroyFramebuffer
vkDeviceWaitIdle C.PFN_vkDeviceWaitIdle
vkQueueWaitIdle C.PFN_vkQueueWaitIdle
vkCreateSemaphore C.PFN_vkCreateSemaphore
vkDestroySemaphore C.PFN_vkDestroySemaphore
vkCreateRenderPass C.PFN_vkCreateRenderPass
vkDestroyRenderPass C.PFN_vkDestroyRenderPass
vkCreateCommandPool C.PFN_vkCreateCommandPool
vkDestroyCommandPool C.PFN_vkDestroyCommandPool
vkAllocateCommandBuffers C.PFN_vkAllocateCommandBuffers
vkFreeCommandBuffers C.PFN_vkFreeCommandBuffers
vkBeginCommandBuffer C.PFN_vkBeginCommandBuffer
vkEndCommandBuffer C.PFN_vkEndCommandBuffer
vkQueueSubmit C.PFN_vkQueueSubmit
vkCmdBeginRenderPass C.PFN_vkCmdBeginRenderPass
vkCmdEndRenderPass C.PFN_vkCmdEndRenderPass
vkCmdCopyBuffer C.PFN_vkCmdCopyBuffer
vkCmdCopyBufferToImage C.PFN_vkCmdCopyBufferToImage
vkCmdPipelineBarrier C.PFN_vkCmdPipelineBarrier
vkCmdPushConstants C.PFN_vkCmdPushConstants
vkCmdBindPipeline C.PFN_vkCmdBindPipeline
vkCmdBindVertexBuffers C.PFN_vkCmdBindVertexBuffers
vkCmdSetViewport C.PFN_vkCmdSetViewport
vkCmdBindIndexBuffer C.PFN_vkCmdBindIndexBuffer
vkCmdDraw C.PFN_vkCmdDraw
vkCmdDrawIndexed C.PFN_vkCmdDrawIndexed
vkCmdBindDescriptorSets C.PFN_vkCmdBindDescriptorSets
vkCmdCopyImageToBuffer C.PFN_vkCmdCopyImageToBuffer
vkCmdDispatch C.PFN_vkCmdDispatch
vkCreateImage C.PFN_vkCreateImage
vkDestroyImage C.PFN_vkDestroyImage
vkGetImageMemoryRequirements C.PFN_vkGetImageMemoryRequirements
vkAllocateMemory C.PFN_vkAllocateMemory
vkBindImageMemory C.PFN_vkBindImageMemory
vkFreeMemory C.PFN_vkFreeMemory
vkGetPhysicalDeviceMemoryProperties C.PFN_vkGetPhysicalDeviceMemoryProperties
vkCreateSampler C.PFN_vkCreateSampler
vkDestroySampler C.PFN_vkDestroySampler
vkCreateBuffer C.PFN_vkCreateBuffer
vkDestroyBuffer C.PFN_vkDestroyBuffer
vkGetBufferMemoryRequirements C.PFN_vkGetBufferMemoryRequirements
vkBindBufferMemory C.PFN_vkBindBufferMemory
vkCreateShaderModule C.PFN_vkCreateShaderModule
vkDestroyShaderModule C.PFN_vkDestroyShaderModule
vkCreateGraphicsPipelines C.PFN_vkCreateGraphicsPipelines
vkDestroyPipeline C.PFN_vkDestroyPipeline
vkCreatePipelineLayout C.PFN_vkCreatePipelineLayout
vkDestroyPipelineLayout C.PFN_vkDestroyPipelineLayout
vkCreateDescriptorSetLayout C.PFN_vkCreateDescriptorSetLayout
vkDestroyDescriptorSetLayout C.PFN_vkDestroyDescriptorSetLayout
vkMapMemory C.PFN_vkMapMemory
vkUnmapMemory C.PFN_vkUnmapMemory
vkResetCommandBuffer C.PFN_vkResetCommandBuffer
vkCreateDescriptorPool C.PFN_vkCreateDescriptorPool
vkDestroyDescriptorPool C.PFN_vkDestroyDescriptorPool
vkAllocateDescriptorSets C.PFN_vkAllocateDescriptorSets
vkFreeDescriptorSets C.PFN_vkFreeDescriptorSets
vkUpdateDescriptorSets C.PFN_vkUpdateDescriptorSets
vkResetDescriptorPool C.PFN_vkResetDescriptorPool
vkCmdCopyImage C.PFN_vkCmdCopyImage
vkCreateComputePipelines C.PFN_vkCreateComputePipelines
vkCreateFence C.PFN_vkCreateFence
vkDestroyFence C.PFN_vkDestroyFence
vkWaitForFences C.PFN_vkWaitForFences
vkResetFences C.PFN_vkResetFences
vkGetPhysicalDeviceProperties C.PFN_vkGetPhysicalDeviceProperties
vkGetPhysicalDeviceSurfaceSupportKHR C.PFN_vkGetPhysicalDeviceSurfaceSupportKHR
vkDestroySurfaceKHR C.PFN_vkDestroySurfaceKHR
vkGetPhysicalDeviceSurfaceFormatsKHR C.PFN_vkGetPhysicalDeviceSurfaceFormatsKHR
vkGetPhysicalDeviceSurfacePresentModesKHR C.PFN_vkGetPhysicalDeviceSurfacePresentModesKHR
vkGetPhysicalDeviceSurfaceCapabilitiesKHR C.PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
vkCreateSwapchainKHR C.PFN_vkCreateSwapchainKHR
vkDestroySwapchainKHR C.PFN_vkDestroySwapchainKHR
vkGetSwapchainImagesKHR C.PFN_vkGetSwapchainImagesKHR
vkAcquireNextImageKHR C.PFN_vkAcquireNextImageKHR
vkQueuePresentKHR C.PFN_vkQueuePresentKHR
}
var (
nilSurface C.VkSurfaceKHR
nilSwapchain C.VkSwapchainKHR
nilSemaphore C.VkSemaphore
nilImageView C.VkImageView
nilRenderPass C.VkRenderPass
nilFramebuffer C.VkFramebuffer
nilCommandPool C.VkCommandPool
nilImage C.VkImage
nilDeviceMemory C.VkDeviceMemory
nilSampler C.VkSampler
nilBuffer C.VkBuffer
nilShaderModule C.VkShaderModule
nilPipeline C.VkPipeline
nilPipelineCache C.VkPipelineCache
nilPipelineLayout C.VkPipelineLayout
nilDescriptorSetLayout C.VkDescriptorSetLayout
nilDescriptorPool C.VkDescriptorPool
nilDescriptorSet C.VkDescriptorSet
nilFence C.VkFence
)
func vkInit() error {
once.Do(func() {
var libName string
switch {
case runtime.GOOS == "android":
libName = "libvulkan.so"
default:
libName = "libvulkan.so.1"
}
lib := dlopen(libName)
if lib == nil {
loadErr = fmt.Errorf("vulkan: %s", C.GoString(C.dlerror()))
return
}
dlopen := func(name string) *[0]byte {
return (*[0]byte)(dlsym(lib, name))
}
must := func(name string) *[0]byte {
ptr := dlopen(name)
if ptr != nil {
return ptr
}
if loadErr == nil {
loadErr = fmt.Errorf("vulkan: function %q not found: %s", name, C.GoString(C.dlerror()))
}
return nil
}
funcs.vkCreateInstance = must("vkCreateInstance")
funcs.vkDestroyInstance = must("vkDestroyInstance")
funcs.vkEnumeratePhysicalDevices = must("vkEnumeratePhysicalDevices")
funcs.vkGetPhysicalDeviceQueueFamilyProperties = must("vkGetPhysicalDeviceQueueFamilyProperties")
funcs.vkGetPhysicalDeviceFormatProperties = must("vkGetPhysicalDeviceFormatProperties")
funcs.vkCreateDevice = must("vkCreateDevice")
funcs.vkDestroyDevice = must("vkDestroyDevice")
funcs.vkGetDeviceQueue = must("vkGetDeviceQueue")
funcs.vkCreateImageView = must("vkCreateImageView")
funcs.vkDestroyImageView = must("vkDestroyImageView")
funcs.vkCreateFramebuffer = must("vkCreateFramebuffer")
funcs.vkDestroyFramebuffer = must("vkDestroyFramebuffer")
funcs.vkDeviceWaitIdle = must("vkDeviceWaitIdle")
funcs.vkQueueWaitIdle = must("vkQueueWaitIdle")
funcs.vkCreateSemaphore = must("vkCreateSemaphore")
funcs.vkDestroySemaphore = must("vkDestroySemaphore")
funcs.vkCreateRenderPass = must("vkCreateRenderPass")
funcs.vkDestroyRenderPass = must("vkDestroyRenderPass")
funcs.vkCreateCommandPool = must("vkCreateCommandPool")
funcs.vkDestroyCommandPool = must("vkDestroyCommandPool")
funcs.vkAllocateCommandBuffers = must("vkAllocateCommandBuffers")
funcs.vkFreeCommandBuffers = must("vkFreeCommandBuffers")
funcs.vkBeginCommandBuffer = must("vkBeginCommandBuffer")
funcs.vkEndCommandBuffer = must("vkEndCommandBuffer")
funcs.vkQueueSubmit = must("vkQueueSubmit")
funcs.vkCmdBeginRenderPass = must("vkCmdBeginRenderPass")
funcs.vkCmdEndRenderPass = must("vkCmdEndRenderPass")
funcs.vkCmdCopyBuffer = must("vkCmdCopyBuffer")
funcs.vkCmdCopyBufferToImage = must("vkCmdCopyBufferToImage")
funcs.vkCmdPipelineBarrier = must("vkCmdPipelineBarrier")
funcs.vkCmdPushConstants = must("vkCmdPushConstants")
funcs.vkCmdBindPipeline = must("vkCmdBindPipeline")
funcs.vkCmdBindVertexBuffers = must("vkCmdBindVertexBuffers")
funcs.vkCmdSetViewport = must("vkCmdSetViewport")
funcs.vkCmdBindIndexBuffer = must("vkCmdBindIndexBuffer")
funcs.vkCmdDraw = must("vkCmdDraw")
funcs.vkCmdDrawIndexed = must("vkCmdDrawIndexed")
funcs.vkCmdBindDescriptorSets = must("vkCmdBindDescriptorSets")
funcs.vkCmdCopyImageToBuffer = must("vkCmdCopyImageToBuffer")
funcs.vkCmdDispatch = must("vkCmdDispatch")
funcs.vkCreateImage = must("vkCreateImage")
funcs.vkDestroyImage = must("vkDestroyImage")
funcs.vkGetImageMemoryRequirements = must("vkGetImageMemoryRequirements")
funcs.vkAllocateMemory = must("vkAllocateMemory")
funcs.vkBindImageMemory = must("vkBindImageMemory")
funcs.vkFreeMemory = must("vkFreeMemory")
funcs.vkGetPhysicalDeviceMemoryProperties = must("vkGetPhysicalDeviceMemoryProperties")
funcs.vkCreateSampler = must("vkCreateSampler")
funcs.vkDestroySampler = must("vkDestroySampler")
funcs.vkCreateBuffer = must("vkCreateBuffer")
funcs.vkDestroyBuffer = must("vkDestroyBuffer")
funcs.vkGetBufferMemoryRequirements = must("vkGetBufferMemoryRequirements")
funcs.vkBindBufferMemory = must("vkBindBufferMemory")
funcs.vkCreateShaderModule = must("vkCreateShaderModule")
funcs.vkDestroyShaderModule = must("vkDestroyShaderModule")
funcs.vkCreateGraphicsPipelines = must("vkCreateGraphicsPipelines")
funcs.vkDestroyPipeline = must("vkDestroyPipeline")
funcs.vkCreatePipelineLayout = must("vkCreatePipelineLayout")
funcs.vkDestroyPipelineLayout = must("vkDestroyPipelineLayout")
funcs.vkCreateDescriptorSetLayout = must("vkCreateDescriptorSetLayout")
funcs.vkDestroyDescriptorSetLayout = must("vkDestroyDescriptorSetLayout")
funcs.vkMapMemory = must("vkMapMemory")
funcs.vkUnmapMemory = must("vkUnmapMemory")
funcs.vkResetCommandBuffer = must("vkResetCommandBuffer")
funcs.vkCreateDescriptorPool = must("vkCreateDescriptorPool")
funcs.vkDestroyDescriptorPool = must("vkDestroyDescriptorPool")
funcs.vkAllocateDescriptorSets = must("vkAllocateDescriptorSets")
funcs.vkFreeDescriptorSets = must("vkFreeDescriptorSets")
funcs.vkUpdateDescriptorSets = must("vkUpdateDescriptorSets")
funcs.vkResetDescriptorPool = must("vkResetDescriptorPool")
funcs.vkCmdCopyImage = must("vkCmdCopyImage")
funcs.vkCreateComputePipelines = must("vkCreateComputePipelines")
funcs.vkCreateFence = must("vkCreateFence")
funcs.vkDestroyFence = must("vkDestroyFence")
funcs.vkWaitForFences = must("vkWaitForFences")
funcs.vkResetFences = must("vkResetFences")
funcs.vkGetPhysicalDeviceProperties = must("vkGetPhysicalDeviceProperties")
funcs.vkGetPhysicalDeviceSurfaceSupportKHR = dlopen("vkGetPhysicalDeviceSurfaceSupportKHR")
funcs.vkDestroySurfaceKHR = dlopen("vkDestroySurfaceKHR")
funcs.vkGetPhysicalDeviceSurfaceFormatsKHR = dlopen("vkGetPhysicalDeviceSurfaceFormatsKHR")
funcs.vkGetPhysicalDeviceSurfacePresentModesKHR = dlopen("vkGetPhysicalDeviceSurfacePresentModesKHR")
funcs.vkGetPhysicalDeviceSurfaceCapabilitiesKHR = dlopen("vkGetPhysicalDeviceSurfaceCapabilitiesKHR")
funcs.vkCreateSwapchainKHR = dlopen("vkCreateSwapchainKHR")
funcs.vkDestroySwapchainKHR = dlopen("vkDestroySwapchainKHR")
funcs.vkGetSwapchainImagesKHR = dlopen("vkGetSwapchainImagesKHR")
funcs.vkAcquireNextImageKHR = dlopen("vkAcquireNextImageKHR")
funcs.vkQueuePresentKHR = dlopen("vkQueuePresentKHR")
for _, f := range loadFuncs {
f(dlopen)
}
})
return loadErr
}
func CreateInstance(exts ...string) (Instance, error) {
if err := vkInit(); err != nil {
return nil, err
}
inf := C.VkInstanceCreateInfo{
sType: C.VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
}
if len(exts) > 0 {
cexts := mallocCStringArr(exts)
defer freeCStringArr(cexts)
inf.enabledExtensionCount = C.uint32_t(len(exts))
inf.ppEnabledExtensionNames = &cexts[0]
}
var inst Instance
if err := vkErr(C.vkCreateInstance(funcs.vkCreateInstance, inf, nil, &inst)); err != nil {
return nil, fmt.Errorf("vulkan: vkCreateInstance: %w", err)
}
return inst, nil
}
func mallocCStringArr(s []string) []*C.char {
carr := make([]*C.char, len(s))
for i, ext := range s {
carr[i] = C.CString(ext)
}
return carr
}
func freeCStringArr(s []*C.char) {
for i := range s {
C.free(unsafe.Pointer(s[i]))
s[i] = nil
}
}
func DestroyInstance(inst Instance) {
C.vkDestroyInstance(funcs.vkDestroyInstance, inst, nil)
}
func GetPhysicalDeviceQueueFamilyProperties(pd PhysicalDevice) []QueueFamilyProperties {
var count C.uint32_t
C.vkGetPhysicalDeviceQueueFamilyProperties(funcs.vkGetPhysicalDeviceQueueFamilyProperties, pd, &count, nil)
if count == 0 {
return nil
}
queues := make([]C.VkQueueFamilyProperties, count)
C.vkGetPhysicalDeviceQueueFamilyProperties(funcs.vkGetPhysicalDeviceQueueFamilyProperties, pd, &count, &queues[0])
return queues
}
func EnumeratePhysicalDevices(inst Instance) ([]PhysicalDevice, error) {
var count C.uint32_t
if err := vkErr(C.vkEnumeratePhysicalDevices(funcs.vkEnumeratePhysicalDevices, inst, &count, nil)); err != nil {
return nil, fmt.Errorf("vulkan: vkEnumeratePhysicalDevices: %w", err)
}
if count == 0 {
return nil, nil
}
devs := make([]C.VkPhysicalDevice, count)
if err := vkErr(C.vkEnumeratePhysicalDevices(funcs.vkEnumeratePhysicalDevices, inst, &count, &devs[0])); err != nil {
return nil, fmt.Errorf("vulkan: vkEnumeratePhysicalDevices: %w", err)
}
return devs, nil
}
func ChoosePhysicalDevice(inst Instance, surf Surface) (PhysicalDevice, int, error) {
devs, err := EnumeratePhysicalDevices(inst)
if err != nil {
return nil, 0, err
}
for _, pd := range devs {
var props C.VkPhysicalDeviceProperties
C.vkGetPhysicalDeviceProperties(funcs.vkGetPhysicalDeviceProperties, pd, &props)
// The lavapipe software implementation doesn't work well rendering to a surface.
// See https://gitlab.freedesktop.org/mesa/mesa/-/issues/5473.
if surf != 0 && props.deviceType == C.VK_PHYSICAL_DEVICE_TYPE_CPU {
continue
}
const caps = C.VK_QUEUE_GRAPHICS_BIT | C.VK_QUEUE_COMPUTE_BIT
queueIdx, ok, err := chooseQueue(pd, surf, caps)
if err != nil {
return nil, 0, err
}
if !ok {
continue
}
if surf != nilSurface {
_, fmtFound, err := chooseFormat(pd, surf)
if err != nil {
return nil, 0, err
}
_, modFound, err := choosePresentMode(pd, surf)
if err != nil {
return nil, 0, err
}
if !fmtFound || !modFound {
continue
}
}
return pd, queueIdx, nil
}
return nil, 0, errors.New("vulkan: no suitable device found")
}
func CreateDeviceAndQueue(pd C.VkPhysicalDevice, queueIdx int, exts ...string) (Device, error) {
priority := C.float(1.0)
qinf := C.VkDeviceQueueCreateInfo{
sType: C.VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
queueCount: 1,
queueFamilyIndex: C.uint32_t(queueIdx),
pQueuePriorities: &priority,
}
inf := C.VkDeviceCreateInfo{
sType: C.VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
queueCreateInfoCount: 1,
enabledExtensionCount: C.uint32_t(len(exts)),
}
if len(exts) > 0 {
cexts := mallocCStringArr(exts)
defer freeCStringArr(cexts)
inf.ppEnabledExtensionNames = &cexts[0]
}
var dev Device
if err := vkErr(C.vkCreateDevice(funcs.vkCreateDevice, pd, inf, qinf, nil, &dev)); err != nil {
return nil, fmt.Errorf("vulkan: vkCreateDevice: %w", err)
}
return dev, nil
}
func GetDeviceQueue(d Device, queueFamily, queueIndex int) Queue {
var queue Queue
C.vkGetDeviceQueue(funcs.vkGetDeviceQueue, d, C.uint32_t(queueFamily), C.uint32_t(queueIndex), &queue)
return queue
}
func GetPhysicalDeviceSurfaceCapabilities(pd PhysicalDevice, surf Surface) (SurfaceCapabilities, error) {
var caps C.VkSurfaceCapabilitiesKHR
err := vkErr(C.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(funcs.vkGetPhysicalDeviceSurfaceCapabilitiesKHR, pd, surf, &caps))
if err != nil {
return SurfaceCapabilities{}, fmt.Errorf("vulkan: vkGetPhysicalDeviceSurfaceCapabilitiesKHR: %w", err)
}
return caps, nil
}
func CreateSwapchain(pd PhysicalDevice, d Device, surf Surface, width, height int, old Swapchain) (Swapchain, []Image, Format, error) {
caps, err := GetPhysicalDeviceSurfaceCapabilities(pd, surf)
if err != nil {
return nilSwapchain, nil, 0, err
}
mode, modeOK, err := choosePresentMode(pd, surf)
if err != nil {
return nilSwapchain, nil, 0, err
}
format, fmtOK, err := chooseFormat(pd, surf)
if err != nil {
return nilSwapchain, nil, 0, err
}
if !modeOK || !fmtOK {
// This shouldn't happen because CreateDeviceAndQueue found at least
// one valid format and present mode.
return nilSwapchain, nil, 0, errors.New("vulkan: no valid format and present mode found")
}
// Find supported alpha composite mode. It doesn't matter which one, because rendering is
// always opaque.
alphaComp := C.VkCompositeAlphaFlagBitsKHR(1)
for caps.supportedCompositeAlpha&C.VkCompositeAlphaFlagsKHR(alphaComp) == 0 {
alphaComp <<= 1
}
trans := C.VkSurfaceTransformFlagBitsKHR(C.VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
if caps.supportedTransforms&C.VkSurfaceTransformFlagsKHR(trans) == 0 {
return nilSwapchain, nil, 0, errors.New("vulkan: VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR not supported")
}
inf := C.VkSwapchainCreateInfoKHR{
sType: C.VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
surface: surf,
minImageCount: caps.minImageCount,
imageFormat: format.format,
imageColorSpace: format.colorSpace,
imageExtent: C.VkExtent2D{width: C.uint32_t(width), height: C.uint32_t(height)},
imageArrayLayers: 1,
imageUsage: C.VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
imageSharingMode: C.VK_SHARING_MODE_EXCLUSIVE,
preTransform: trans,
presentMode: mode,
compositeAlpha: C.VkCompositeAlphaFlagBitsKHR(alphaComp),
clipped: C.VK_TRUE,
oldSwapchain: old,
}
var swchain Swapchain
if err := vkErr(C.vkCreateSwapchainKHR(funcs.vkCreateSwapchainKHR, d, &inf, nil, &swchain)); err != nil {
return nilSwapchain, nil, 0, fmt.Errorf("vulkan: vkCreateSwapchainKHR: %w", err)
}
var count C.uint32_t
if err := vkErr(C.vkGetSwapchainImagesKHR(funcs.vkGetSwapchainImagesKHR, d, swchain, &count, nil)); err != nil {
DestroySwapchain(d, swchain)
return nilSwapchain, nil, 0, fmt.Errorf("vulkan: vkGetSwapchainImagesKHR: %w", err)
}
if count == 0 {
DestroySwapchain(d, swchain)
return nilSwapchain, nil, 0, errors.New("vulkan: vkGetSwapchainImagesKHR returned no images")
}
imgs := make([]Image, count)
if err := vkErr(C.vkGetSwapchainImagesKHR(funcs.vkGetSwapchainImagesKHR, d, swchain, &count, &imgs[0])); err != nil {
DestroySwapchain(d, swchain)
return nilSwapchain, nil, 0, fmt.Errorf("vulkan: vkGetSwapchainImagesKHR: %w", err)
}
return swchain, imgs, format.format, nil
}
func DestroySwapchain(d Device, swchain Swapchain) {
C.vkDestroySwapchainKHR(funcs.vkDestroySwapchainKHR, d, swchain, nil)
}
func AcquireNextImage(d Device, swchain Swapchain, sem Semaphore, fence Fence) (int, error) {
res := C.vkAcquireNextImageKHR(funcs.vkAcquireNextImageKHR, d, swchain, math.MaxUint64, sem, fence)
if err := vkErr(res.res); err != nil {
return 0, fmt.Errorf("vulkan: vkAcquireNextImageKHR: %w", err)
}
return int(res.uint), nil
}
func PresentQueue(q Queue, swchain Swapchain, sem Semaphore, imgIdx int) error {
cidx := C.uint32_t(imgIdx)
inf := C.VkPresentInfoKHR{
sType: C.VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
swapchainCount: 1,
pSwapchains: &swchain,
pImageIndices: &cidx,
}
if sem != nilSemaphore {
inf.waitSemaphoreCount = 1
inf.pWaitSemaphores = &sem
}
if err := vkErr(C.vkQueuePresentKHR(funcs.vkQueuePresentKHR, q, inf)); err != nil {
return fmt.Errorf("vulkan: vkQueuePresentKHR: %w", err)
}
return nil
}
func CreateImageView(d Device, img Image, format Format) (ImageView, error) {
inf := C.VkImageViewCreateInfo{
sType: C.VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
image: img,
viewType: C.VK_IMAGE_VIEW_TYPE_2D,
format: format,
subresourceRange: C.VkImageSubresourceRange{
aspectMask: C.VK_IMAGE_ASPECT_COLOR_BIT,
levelCount: C.VK_REMAINING_MIP_LEVELS,
layerCount: C.VK_REMAINING_ARRAY_LAYERS,
},
}
var view C.VkImageView
if err := vkErr(C.vkCreateImageView(funcs.vkCreateImageView, d, &inf, nil, &view)); err != nil {
return nilImageView, fmt.Errorf("vulkan: vkCreateImageView: %w", err)
}
return view, nil
}
func DestroyImageView(d Device, view ImageView) {
C.vkDestroyImageView(funcs.vkDestroyImageView, d, view, nil)
}
func CreateRenderPass(d Device, format Format, loadOp AttachmentLoadOp, initialLayout, finalLayout ImageLayout, passDeps []SubpassDependency) (RenderPass, error) {
att := C.VkAttachmentDescription{
format: format,
samples: C.VK_SAMPLE_COUNT_1_BIT,
loadOp: loadOp,
storeOp: C.VK_ATTACHMENT_STORE_OP_STORE,
stencilLoadOp: C.VK_ATTACHMENT_LOAD_OP_DONT_CARE,
stencilStoreOp: C.VK_ATTACHMENT_STORE_OP_DONT_CARE,
initialLayout: initialLayout,
finalLayout: finalLayout,
}
ref := C.VkAttachmentReference{
attachment: 0,
layout: C.VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
}
sub := C.VkSubpassDescription{
pipelineBindPoint: C.VK_PIPELINE_BIND_POINT_GRAPHICS,
colorAttachmentCount: 1,
pColorAttachments: &ref,
}
inf := C.VkRenderPassCreateInfo{
sType: C.VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
attachmentCount: 1,
pAttachments: &att,
subpassCount: 1,
}
if n := len(passDeps); n > 0 {
inf.dependencyCount = C.uint32_t(n)
inf.pDependencies = &passDeps[0]
}
var pass RenderPass
if err := vkErr(C.vkCreateRenderPass(funcs.vkCreateRenderPass, d, inf, sub, nil, &pass)); err != nil {
return nilRenderPass, fmt.Errorf("vulkan: vkCreateRenderPass: %w", err)
}
return pass, nil
}
func DestroyRenderPass(d Device, r RenderPass) {
C.vkDestroyRenderPass(funcs.vkDestroyRenderPass, d, r, nil)
}
func CreateFramebuffer(d Device, rp RenderPass, view ImageView, width, height int) (Framebuffer, error) {
inf := C.VkFramebufferCreateInfo{
sType: C.VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
renderPass: rp,
attachmentCount: 1,
pAttachments: &view,
width: C.uint32_t(width),
height: C.uint32_t(height),
layers: 1,
}
var fbo Framebuffer
if err := vkErr(C.vkCreateFramebuffer(funcs.vkCreateFramebuffer, d, inf, nil, &fbo)); err != nil {
return nilFramebuffer, fmt.Errorf("vulkan: vkCreateFramebuffer: %w", err)
}
return fbo, nil
}
func DestroyFramebuffer(d Device, f Framebuffer) {
C.vkDestroyFramebuffer(funcs.vkDestroyFramebuffer, d, f, nil)
}
func DeviceWaitIdle(d Device) error {
if err := vkErr(C.vkDeviceWaitIdle(funcs.vkDeviceWaitIdle, d)); err != nil {
return fmt.Errorf("vulkan: vkDeviceWaitIdle: %w", err)
}
return nil
}
func QueueWaitIdle(q Queue) error {
if err := vkErr(C.vkQueueWaitIdle(funcs.vkQueueWaitIdle, q)); err != nil {
return fmt.Errorf("vulkan: vkQueueWaitIdle: %w", err)
}
return nil
}
func CreateSemaphore(d Device) (Semaphore, error) {
inf := C.VkSemaphoreCreateInfo{
sType: C.VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
}
var sem Semaphore
err := vkErr(C.vkCreateSemaphore(funcs.vkCreateSemaphore, d, &inf, nil, &sem))
if err != nil {
return nilSemaphore, fmt.Errorf("vulkan: vkCreateSemaphore: %w", err)
}
return sem, err
}
func DestroySemaphore(d Device, sem Semaphore) {
C.vkDestroySemaphore(funcs.vkDestroySemaphore, d, sem, nil)
}
func DestroyDevice(dev Device) {
C.vkDestroyDevice(funcs.vkDestroyDevice, dev, nil)
}
func DestroySurface(inst Instance, s Surface) {
C.vkDestroySurfaceKHR(funcs.vkDestroySurfaceKHR, inst, s, nil)
}
func CreateCommandPool(d Device, queueIndex int) (CommandPool, error) {
inf := C.VkCommandPoolCreateInfo{
sType: C.VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
queueFamilyIndex: C.uint32_t(queueIndex),
flags: C.VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | C.VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
}
var pool CommandPool
if err := vkErr(C.vkCreateCommandPool(funcs.vkCreateCommandPool, d, &inf, nil, &pool)); err != nil {
return nilCommandPool, fmt.Errorf("vulkan: vkCreateCommandPool: %w", err)
}
return pool, nil
}
func DestroyCommandPool(d Device, pool CommandPool) {
C.vkDestroyCommandPool(funcs.vkDestroyCommandPool, d, pool, nil)
}
func AllocateCommandBuffer(d Device, pool CommandPool) (CommandBuffer, error) {
inf := C.VkCommandBufferAllocateInfo{
sType: C.VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
commandPool: pool,
level: C.VK_COMMAND_BUFFER_LEVEL_PRIMARY,
commandBufferCount: 1,
}
var buf CommandBuffer
if err := vkErr(C.vkAllocateCommandBuffers(funcs.vkAllocateCommandBuffers, d, &inf, &buf)); err != nil {
return nil, fmt.Errorf("vulkan: vkAllocateCommandBuffers: %w", err)
}
return buf, nil
}
func FreeCommandBuffers(d Device, pool CommandPool, bufs ...CommandBuffer) {
if len(bufs) == 0 {
return
}
C.vkFreeCommandBuffers(funcs.vkFreeCommandBuffers, d, pool, C.uint32_t(len(bufs)), &bufs[0])
}
func BeginCommandBuffer(buf CommandBuffer) error {
inf := C.VkCommandBufferBeginInfo{
sType: C.VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
flags: C.VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
}
if err := vkErr(C.vkBeginCommandBuffer(funcs.vkBeginCommandBuffer, buf, inf)); err != nil {
return fmt.Errorf("vulkan: vkBeginCommandBuffer: %w", err)
}
return nil
}
func EndCommandBuffer(buf CommandBuffer) error {
if err := vkErr(C.vkEndCommandBuffer(funcs.vkEndCommandBuffer, buf)); err != nil {
return fmt.Errorf("vulkan: vkEndCommandBuffer: %w", err)
}
return nil
}
func QueueSubmit(q Queue, buf CommandBuffer, waitSems []Semaphore, waitStages []PipelineStageFlags, sigSems []Semaphore, fence Fence) error {
inf := C.VkSubmitInfo{
sType: C.VK_STRUCTURE_TYPE_SUBMIT_INFO,
commandBufferCount: 1,
pCommandBuffers: &buf,
}
if len(waitSems) > 0 {
if len(waitSems) != len(waitStages) {
panic("len(waitSems) != len(waitStages)")
}
inf.waitSemaphoreCount = C.uint32_t(len(waitSems))
inf.pWaitSemaphores = &waitSems[0]
inf.pWaitDstStageMask = &waitStages[0]
}
if len(sigSems) > 0 {
inf.signalSemaphoreCount = C.uint32_t(len(sigSems))
inf.pSignalSemaphores = &sigSems[0]
}
if err := vkErr(C.vkQueueSubmit(funcs.vkQueueSubmit, q, inf, fence)); err != nil {
return fmt.Errorf("vulkan: vkQueueSubmit: %w", err)
}
return nil
}
func CmdBeginRenderPass(buf CommandBuffer, rp RenderPass, fbo Framebuffer, width, height int, clearCol [4]float32) {
cclearCol := [4]C.float{C.float(clearCol[0]), C.float(clearCol[1]), C.float(clearCol[2]), C.float(clearCol[3])}
inf := C.VkRenderPassBeginInfo{
sType: C.VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
renderPass: rp,
framebuffer: fbo,
renderArea: C.VkRect2D{extent: C.VkExtent2D{width: C.uint32_t(width), height: C.uint32_t(height)}},
clearValueCount: 1,
pClearValues: (*C.VkClearValue)(unsafe.Pointer(&cclearCol)),
}
C.vkCmdBeginRenderPass(funcs.vkCmdBeginRenderPass, buf, inf, C.VK_SUBPASS_CONTENTS_INLINE)
}
func CmdEndRenderPass(buf CommandBuffer) {
C.vkCmdEndRenderPass(funcs.vkCmdEndRenderPass, buf)
}
func CmdCopyBuffer(cmdBuf CommandBuffer, src, dst Buffer, srcOff, dstOff, size int) {
C.vkCmdCopyBuffer(funcs.vkCmdCopyBuffer, cmdBuf, src, dst, 1, &C.VkBufferCopy{
srcOffset: C.VkDeviceSize(srcOff),
dstOffset: C.VkDeviceSize(dstOff),
size: C.VkDeviceSize(size),
})
}
func CmdCopyBufferToImage(cmdBuf CommandBuffer, src Buffer, dst Image, layout ImageLayout, copy BufferImageCopy) {
C.vkCmdCopyBufferToImage(funcs.vkCmdCopyBufferToImage, cmdBuf, src, dst, layout, 1, &copy)
}
func CmdPipelineBarrier(cmdBuf CommandBuffer, srcStage, dstStage PipelineStageFlags, flags DependencyFlags, memBarriers []MemoryBarrier, bufBarriers []BufferMemoryBarrier, imgBarriers []ImageMemoryBarrier) {
var memPtr *MemoryBarrier
if len(memBarriers) > 0 {
memPtr = &memBarriers[0]
}
var bufPtr *BufferMemoryBarrier
if len(bufBarriers) > 0 {
bufPtr = &bufBarriers[0]
}
var imgPtr *ImageMemoryBarrier
if len(imgBarriers) > 0 {
imgPtr = &imgBarriers[0]
}
C.vkCmdPipelineBarrier(funcs.vkCmdPipelineBarrier, cmdBuf, srcStage, dstStage, flags,
C.uint32_t(len(memBarriers)), memPtr,
C.uint32_t(len(bufBarriers)), bufPtr,
C.uint32_t(len(imgBarriers)), imgPtr)
}
func CmdPushConstants(cmdBuf CommandBuffer, layout PipelineLayout, stages ShaderStageFlags, offset int, data []byte) {
if len(data) == 0 {
return
}
C.vkCmdPushConstants(funcs.vkCmdPushConstants, cmdBuf, layout, stages, C.uint32_t(offset), C.uint32_t(len(data)), unsafe.Pointer(&data[0]))
}
func CmdBindPipeline(cmdBuf CommandBuffer, bindPoint PipelineBindPoint, pipe Pipeline) {
C.vkCmdBindPipeline(funcs.vkCmdBindPipeline, cmdBuf, bindPoint, pipe)
}
func CmdBindVertexBuffers(cmdBuf CommandBuffer, first int, buffers []Buffer, sizes []DeviceSize) {
if len(buffers) == 0 {
return
}
C.vkCmdBindVertexBuffers(funcs.vkCmdBindVertexBuffers, cmdBuf, C.uint32_t(first), C.uint32_t(len(buffers)), &buffers[0], &sizes[0])
}
func CmdSetViewport(cmdBuf CommandBuffer, first int, viewports ...Viewport) {
if len(viewports) == 0 {
return
}
C.vkCmdSetViewport(funcs.vkCmdSetViewport, cmdBuf, C.uint32_t(first), C.uint32_t(len(viewports)), &viewports[0])
}
func CmdBindIndexBuffer(cmdBuf CommandBuffer, buffer Buffer, offset int, typ IndexType) {
C.vkCmdBindIndexBuffer(funcs.vkCmdBindIndexBuffer, cmdBuf, buffer, C.VkDeviceSize(offset), typ)
}
func CmdDraw(cmdBuf CommandBuffer, vertCount, instCount, firstVert, firstInst int) {
C.vkCmdDraw(funcs.vkCmdDraw, cmdBuf, C.uint32_t(vertCount), C.uint32_t(instCount), C.uint32_t(firstVert), C.uint32_t(firstInst))
}
func CmdDrawIndexed(cmdBuf CommandBuffer, idxCount, instCount, firstIdx, vertOff, firstInst int) {
C.vkCmdDrawIndexed(funcs.vkCmdDrawIndexed, cmdBuf, C.uint32_t(idxCount), C.uint32_t(instCount), C.uint32_t(firstIdx), C.int32_t(vertOff), C.uint32_t(firstInst))
}
func GetPhysicalDeviceFormatProperties(physDev PhysicalDevice, format Format) FormatFeatureFlags {
var props C.VkFormatProperties
C.vkGetPhysicalDeviceFormatProperties(funcs.vkGetPhysicalDeviceFormatProperties, physDev, format, &props)
return FormatFeatureFlags(props.optimalTilingFeatures)
}
func CmdBindDescriptorSets(cmdBuf CommandBuffer, point PipelineBindPoint, layout PipelineLayout, firstSet int, sets []DescriptorSet) {
C.vkCmdBindDescriptorSets(funcs.vkCmdBindDescriptorSets, cmdBuf, point, layout, C.uint32_t(firstSet), C.uint32_t(len(sets)), &sets[0], 0, nil)
}
func CmdCopyImage(cmdBuf CommandBuffer, src Image, srcLayout ImageLayout, dst Image, dstLayout ImageLayout, regions []ImageCopy) {
if len(regions) == 0 {
return
}
C.vkCmdCopyImage(funcs.vkCmdCopyImage, cmdBuf, src, srcLayout, dst, dstLayout, C.uint32_t(len(regions)), &regions[0])
}
func CmdCopyImageToBuffer(cmdBuf CommandBuffer, src Image, srcLayout ImageLayout, dst Buffer, regions []BufferImageCopy) {
if len(regions) == 0 {
return
}
C.vkCmdCopyImageToBuffer(funcs.vkCmdCopyImageToBuffer, cmdBuf, src, srcLayout, dst, C.uint32_t(len(regions)), &regions[0])
}
func CmdDispatch(cmdBuf CommandBuffer, x, y, z int) {
C.vkCmdDispatch(funcs.vkCmdDispatch, cmdBuf, C.uint32_t(x), C.uint32_t(y), C.uint32_t(z))
}
func CreateImage(pd PhysicalDevice, d Device, format Format, width, height int, usage ImageUsageFlags) (Image, DeviceMemory, error) {
inf := C.VkImageCreateInfo{
sType: C.VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
imageType: C.VK_IMAGE_TYPE_2D,
format: format,
extent: C.VkExtent3D{
width: C.uint32_t(width),
height: C.uint32_t(height),
depth: 1,
},
mipLevels: 1,
arrayLayers: 1,
samples: C.VK_SAMPLE_COUNT_1_BIT,
tiling: C.VK_IMAGE_TILING_OPTIMAL,
usage: usage,
initialLayout: C.VK_IMAGE_LAYOUT_UNDEFINED,
}
var img C.VkImage
if err := vkErr(C.vkCreateImage(funcs.vkCreateImage, d, &inf, nil, &img)); err != nil {
return nilImage, nilDeviceMemory, fmt.Errorf("vulkan: vkCreateImage: %w", err)
}
var memReqs C.VkMemoryRequirements
C.vkGetImageMemoryRequirements(funcs.vkGetImageMemoryRequirements, d, img, &memReqs)
memIdx, found := findMemoryTypeIndex(pd, memReqs.memoryTypeBits, C.VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
if !found {
DestroyImage(d, img)
return nilImage, nilDeviceMemory, errors.New("vulkan: no memory type suitable for images found")
}
memInf := C.VkMemoryAllocateInfo{
sType: C.VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
allocationSize: memReqs.size,
memoryTypeIndex: C.uint32_t(memIdx),
}
var imgMem C.VkDeviceMemory
if err := vkErr(C.vkAllocateMemory(funcs.vkAllocateMemory, d, &memInf, nil, &imgMem)); err != nil {
DestroyImage(d, img)
return nilImage, nilDeviceMemory, fmt.Errorf("vulkan: vkAllocateMemory: %w", err)
}
if err := vkErr(C.vkBindImageMemory(funcs.vkBindImageMemory, d, img, imgMem, 0)); err != nil {
FreeMemory(d, imgMem)
DestroyImage(d, img)
return nilImage, nilDeviceMemory, fmt.Errorf("vulkan: vkBindImageMemory: %w", err)
}
return img, imgMem, nil
}
func DestroyImage(d Device, img Image) {
C.vkDestroyImage(funcs.vkDestroyImage, d, img, nil)
}
func FreeMemory(d Device, mem DeviceMemory) {
C.vkFreeMemory(funcs.vkFreeMemory, d, mem, nil)
}
func CreateSampler(d Device, minFilter, magFilter Filter) (Sampler, error) {
inf := C.VkSamplerCreateInfo{
sType: C.VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
minFilter: minFilter,
magFilter: magFilter,
addressModeU: C.VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
addressModeV: C.VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
}
var s C.VkSampler
if err := vkErr(C.vkCreateSampler(funcs.vkCreateSampler, d, &inf, nil, &s)); err != nil {
return nilSampler, fmt.Errorf("vulkan: vkCreateSampler: %w", err)
}
return s, nil
}
func DestroySampler(d Device, sampler Sampler) {
C.vkDestroySampler(funcs.vkDestroySampler, d, sampler, nil)
}
func CreateBuffer(pd PhysicalDevice, d Device, size int, usage BufferUsageFlags, props MemoryPropertyFlags) (Buffer, DeviceMemory, error) {
inf := C.VkBufferCreateInfo{
sType: C.VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
size: C.VkDeviceSize(size),
usage: usage,
}
var buf C.VkBuffer
if err := vkErr(C.vkCreateBuffer(funcs.vkCreateBuffer, d, &inf, nil, &buf)); err != nil {
return nilBuffer, nilDeviceMemory, fmt.Errorf("vulkan: vkCreateBuffer: %w", err)
}
var memReqs C.VkMemoryRequirements
C.vkGetBufferMemoryRequirements(funcs.vkGetBufferMemoryRequirements, d, buf, &memReqs)
memIdx, found := findMemoryTypeIndex(pd, memReqs.memoryTypeBits, props)
if !found {
DestroyBuffer(d, buf)
return nilBuffer, nilDeviceMemory, errors.New("vulkan: no memory suitable for buffers found")
}
memInf := C.VkMemoryAllocateInfo{
sType: C.VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
allocationSize: memReqs.size,
memoryTypeIndex: C.uint32_t(memIdx),
}
var mem C.VkDeviceMemory
if err := vkErr(C.vkAllocateMemory(funcs.vkAllocateMemory, d, &memInf, nil, &mem)); err != nil {
DestroyBuffer(d, buf)
return nilBuffer, nilDeviceMemory, fmt.Errorf("vulkan: vkAllocateMemory: %w", err)
}
if err := vkErr(C.vkBindBufferMemory(funcs.vkBindBufferMemory, d, buf, mem, 0)); err != nil {
FreeMemory(d, mem)
DestroyBuffer(d, buf)
return nilBuffer, nilDeviceMemory, fmt.Errorf("vulkan: vkBindBufferMemory: %w", err)
}
return buf, mem, nil
}
func DestroyBuffer(d Device, buf Buffer) {
C.vkDestroyBuffer(funcs.vkDestroyBuffer, d, buf, nil)
}
func CreateShaderModule(d Device, spirv string) (ShaderModule, error) {
ptr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&spirv)).Data)
inf := C.VkShaderModuleCreateInfo{
sType: C.VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
codeSize: C.size_t(len(spirv)),
pCode: (*C.uint32_t)(ptr),
}
var mod C.VkShaderModule
if err := vkErr(C.vkCreateShaderModule(funcs.vkCreateShaderModule, d, inf, nil, &mod)); err != nil {
return nilShaderModule, fmt.Errorf("vulkan: vkCreateShaderModule: %w", err)
}
return mod, nil
}
func DestroyShaderModule(d Device, mod ShaderModule) {
C.vkDestroyShaderModule(funcs.vkDestroyShaderModule, d, mod, nil)
}
func CreateGraphicsPipeline(d Device, pass RenderPass, vmod, fmod ShaderModule, blend bool, srcFactor, dstFactor BlendFactor, topology PrimitiveTopology, bindings []VertexInputBindingDescription, attrs []VertexInputAttributeDescription, layout PipelineLayout) (Pipeline, error) {
main := C.CString("main")
defer C.free(unsafe.Pointer(main))
stages := []C.VkPipelineShaderStageCreateInfo{
{
sType: C.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
stage: C.VK_SHADER_STAGE_VERTEX_BIT,
module: vmod,
pName: main,
},
{
sType: C.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
stage: C.VK_SHADER_STAGE_FRAGMENT_BIT,
module: fmod,
pName: main,
},
}
dynStates := []C.VkDynamicState{C.VK_DYNAMIC_STATE_VIEWPORT}
dynInf := C.VkPipelineDynamicStateCreateInfo{
sType: C.VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
dynamicStateCount: C.uint32_t(len(dynStates)),
pDynamicStates: &dynStates[0],
}
const maxDim = 0x7fffffff
scissors := []C.VkRect2D{{extent: C.VkExtent2D{width: maxDim, height: maxDim}}}
viewportInf := C.VkPipelineViewportStateCreateInfo{
sType: C.VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
viewportCount: 1,
scissorCount: C.uint32_t(len(scissors)),
pScissors: &scissors[0],
}
enable := C.VkBool32(0)
if blend {
enable = 1
}
attBlendInf := C.VkPipelineColorBlendAttachmentState{
blendEnable: enable,
srcColorBlendFactor: srcFactor,
srcAlphaBlendFactor: srcFactor,
dstColorBlendFactor: dstFactor,
dstAlphaBlendFactor: dstFactor,
colorBlendOp: C.VK_BLEND_OP_ADD,
alphaBlendOp: C.VK_BLEND_OP_ADD,
colorWriteMask: C.VK_COLOR_COMPONENT_R_BIT | C.VK_COLOR_COMPONENT_G_BIT | C.VK_COLOR_COMPONENT_B_BIT | C.VK_COLOR_COMPONENT_A_BIT,
}
blendInf := C.VkPipelineColorBlendStateCreateInfo{
sType: C.VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
attachmentCount: 1,
pAttachments: &attBlendInf,
}
var vkBinds []C.VkVertexInputBindingDescription
var vkAttrs []C.VkVertexInputAttributeDescription
for _, b := range bindings {
vkBinds = append(vkBinds, C.VkVertexInputBindingDescription{
binding: C.uint32_t(b.Binding),
stride: C.uint32_t(b.Stride),
})
}
for _, a := range attrs {
vkAttrs = append(vkAttrs, C.VkVertexInputAttributeDescription{
location: C.uint32_t(a.Location),
binding: C.uint32_t(a.Binding),
format: a.Format,
offset: C.uint32_t(a.Offset),
})
}
vertexInf := C.VkPipelineVertexInputStateCreateInfo{
sType: C.VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
}
if n := len(vkBinds); n > 0 {
vertexInf.vertexBindingDescriptionCount = C.uint32_t(n)
vertexInf.pVertexBindingDescriptions = &vkBinds[0]
}
if n := len(vkAttrs); n > 0 {
vertexInf.vertexAttributeDescriptionCount = C.uint32_t(n)
vertexInf.pVertexAttributeDescriptions = &vkAttrs[0]
}
inf := C.VkGraphicsPipelineCreateInfo{
sType: C.VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
stageCount: C.uint32_t(len(stages)),
pStages: &stages[0],
renderPass: pass,
layout: layout,
pRasterizationState: &C.VkPipelineRasterizationStateCreateInfo{
sType: C.VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
lineWidth: 1.0,
},
pMultisampleState: &C.VkPipelineMultisampleStateCreateInfo{
sType: C.VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
rasterizationSamples: C.VK_SAMPLE_COUNT_1_BIT,
},
pInputAssemblyState: &C.VkPipelineInputAssemblyStateCreateInfo{
sType: C.VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
topology: topology,
},
}
var pipe C.VkPipeline
if err := vkErr(C.vkCreateGraphicsPipelines(funcs.vkCreateGraphicsPipelines, d, nilPipelineCache, inf, dynInf, blendInf, vertexInf, viewportInf, nil, &pipe)); err != nil {
return nilPipeline, fmt.Errorf("vulkan: vkCreateGraphicsPipelines: %w", err)
}
return pipe, nil
}
func DestroyPipeline(d Device, p Pipeline) {
C.vkDestroyPipeline(funcs.vkDestroyPipeline, d, p, nil)
}
func CreatePipelineLayout(d Device, pushRanges []PushConstantRange, sets []DescriptorSetLayout) (PipelineLayout, error) {
inf := C.VkPipelineLayoutCreateInfo{
sType: C.VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
}
if n := len(sets); n > 0 {
inf.setLayoutCount = C.uint32_t(n)
inf.pSetLayouts = &sets[0]
}
if n := len(pushRanges); n > 0 {
inf.pushConstantRangeCount = C.uint32_t(n)
inf.pPushConstantRanges = &pushRanges[0]
}
var l C.VkPipelineLayout
if err := vkErr(C.vkCreatePipelineLayout(funcs.vkCreatePipelineLayout, d, inf, nil, &l)); err != nil {
return nilPipelineLayout, fmt.Errorf("vulkan: vkCreatePipelineLayout: %w", err)
}
return l, nil
}
func DestroyPipelineLayout(d Device, l PipelineLayout) {
C.vkDestroyPipelineLayout(funcs.vkDestroyPipelineLayout, d, l, nil)
}
func CreateDescriptorSetLayout(d Device, bindings []DescriptorSetLayoutBinding) (DescriptorSetLayout, error) {
var vkbinds []C.VkDescriptorSetLayoutBinding
for _, b := range bindings {
vkbinds = append(vkbinds, C.VkDescriptorSetLayoutBinding{
binding: C.uint32_t(b.Binding),
descriptorType: b.DescriptorType,
descriptorCount: 1,
stageFlags: b.StageFlags,
})
}
inf := C.VkDescriptorSetLayoutCreateInfo{
sType: C.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
}
if n := len(vkbinds); n > 0 {
inf.bindingCount = C.uint32_t(len(vkbinds))
inf.pBindings = &vkbinds[0]
}
var l C.VkDescriptorSetLayout
if err := vkErr(C.vkCreateDescriptorSetLayout(funcs.vkCreateDescriptorSetLayout, d, inf, nil, &l)); err != nil {
return nilDescriptorSetLayout, fmt.Errorf("vulkan: vkCreateDescriptorSetLayout: %w", err)
}
return l, nil
}
func DestroyDescriptorSetLayout(d Device, l DescriptorSetLayout) {
C.vkDestroyDescriptorSetLayout(funcs.vkDestroyDescriptorSetLayout, d, l, nil)
}
func MapMemory(d Device, mem DeviceMemory, offset, size int) ([]byte, error) {
var ptr unsafe.Pointer
if err := vkErr(C.vkMapMemory(funcs.vkMapMemory, d, mem, C.VkDeviceSize(offset), C.VkDeviceSize(size), 0, &ptr)); err != nil {
return nil, fmt.Errorf("vulkan: vkMapMemory: %w", err)
}
return ((*[1 << 30]byte)(ptr))[:size:size], nil
}
func UnmapMemory(d Device, mem DeviceMemory) {
C.vkUnmapMemory(funcs.vkUnmapMemory, d, mem)
}
func ResetCommandBuffer(buf CommandBuffer) error {
if err := vkErr(C.vkResetCommandBuffer(funcs.vkResetCommandBuffer, buf, 0)); err != nil {
return fmt.Errorf("vulkan: vkResetCommandBuffer. %w", err)
}
return nil
}
func CreateDescriptorPool(d Device, maxSets int, sizes []DescriptorPoolSize) (DescriptorPool, error) {
inf := C.VkDescriptorPoolCreateInfo{
sType: C.VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
maxSets: C.uint32_t(maxSets),
poolSizeCount: C.uint32_t(len(sizes)),
pPoolSizes: &sizes[0],
}
var pool C.VkDescriptorPool
if err := vkErr(C.vkCreateDescriptorPool(funcs.vkCreateDescriptorPool, d, inf, nil, &pool)); err != nil {
return nilDescriptorPool, fmt.Errorf("vulkan: vkCreateDescriptorPool: %w", err)
}
return pool, nil
}
func DestroyDescriptorPool(d Device, pool DescriptorPool) {
C.vkDestroyDescriptorPool(funcs.vkDestroyDescriptorPool, d, pool, nil)
}
func ResetDescriptorPool(d Device, pool DescriptorPool) error {
if err := vkErr(C.vkResetDescriptorPool(funcs.vkResetDescriptorPool, d, pool, 0)); err != nil {
return fmt.Errorf("vulkan: vkResetDescriptorPool: %w", err)
}
return nil
}
func UpdateDescriptorSet(d Device, write WriteDescriptorSet) {
C.vkUpdateDescriptorSets(funcs.vkUpdateDescriptorSets, d, write, 0, nil)
}
func AllocateDescriptorSet(d Device, pool DescriptorPool, layout DescriptorSetLayout) (DescriptorSet, error) {
inf := C.VkDescriptorSetAllocateInfo{
sType: C.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
descriptorPool: pool,
descriptorSetCount: 1,
pSetLayouts: &layout,
}
var set C.VkDescriptorSet
if err := vkErr(C.vkAllocateDescriptorSets(funcs.vkAllocateDescriptorSets, d, inf, &set)); err != nil {
return nilDescriptorSet, fmt.Errorf("vulkan: vkAllocateDescriptorSets: %w", err)
}
return set, nil
}
func CreateComputePipeline(d Device, mod ShaderModule, layout PipelineLayout) (Pipeline, error) {
main := C.CString("main")
defer C.free(unsafe.Pointer(main))
inf := C.VkComputePipelineCreateInfo{
sType: C.VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
stage: C.VkPipelineShaderStageCreateInfo{
sType: C.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
stage: C.VK_SHADER_STAGE_COMPUTE_BIT,
module: mod,
pName: main,
},
layout: layout,
}
var pipe C.VkPipeline
if err := vkErr(C.vkCreateComputePipelines(funcs.vkCreateComputePipelines, d, nilPipelineCache, 1, &inf, nil, &pipe)); err != nil {
return nilPipeline, fmt.Errorf("vulkan: vkCreateComputePipelines: %w", err)
}
return pipe, nil
}
func CreateFence(d Device) (Fence, error) {
inf := C.VkFenceCreateInfo{
sType: C.VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
}
var f C.VkFence
if err := vkErr(C.vkCreateFence(funcs.vkCreateFence, d, &inf, nil, &f)); err != nil {
return nilFence, fmt.Errorf("vulkan: vkCreateFence: %w", err)
}
return f, nil
}
func DestroyFence(d Device, f Fence) {
C.vkDestroyFence(funcs.vkDestroyFence, d, f, nil)
}
func WaitForFences(d Device, fences ...Fence) error {
if len(fences) == 0 {
return nil
}
err := vkErr(C.vkWaitForFences(funcs.vkWaitForFences, d, C.uint32_t(len(fences)), &fences[0], C.VK_TRUE, 0xffffffffffffffff))
if err != nil {
return fmt.Errorf("vulkan: vkWaitForFences: %w", err)
}
return nil
}
func ResetFences(d Device, fences ...Fence) error {
if len(fences) == 0 {
return nil
}
err := vkErr(C.vkResetFences(funcs.vkResetFences, d, C.uint32_t(len(fences)), &fences[0]))
if err != nil {
return fmt.Errorf("vulkan: vkResetFences: %w", err)
}
return nil
}
func BuildSubpassDependency(srcStage, dstStage PipelineStageFlags, srcMask, dstMask AccessFlags, flags DependencyFlags) SubpassDependency {
return C.VkSubpassDependency{
srcSubpass: C.VK_SUBPASS_EXTERNAL,
srcStageMask: srcStage,
srcAccessMask: srcMask,
dstSubpass: 0,
dstStageMask: dstStage,
dstAccessMask: dstMask,
dependencyFlags: flags,
}
}
func BuildPushConstantRange(stages ShaderStageFlags, offset, size int) PushConstantRange {
return C.VkPushConstantRange{
stageFlags: stages,
offset: C.uint32_t(offset),
size: C.uint32_t(size),
}
}
func BuildDescriptorPoolSize(typ DescriptorType, count int) DescriptorPoolSize {
return C.VkDescriptorPoolSize{
_type: typ,
descriptorCount: C.uint32_t(count),
}
}
func BuildWriteDescriptorSetImage(set DescriptorSet, binding int, typ DescriptorType, sampler Sampler, view ImageView, layout ImageLayout) WriteDescriptorSet {
return C.VkWriteDescriptorSet{
sType: C.VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
dstSet: set,
dstBinding: C.uint32_t(binding),
descriptorCount: 1,
descriptorType: typ,
pImageInfo: &C.VkDescriptorImageInfo{
sampler: sampler,
imageView: view,
imageLayout: layout,
},
}
}
func BuildWriteDescriptorSetBuffer(set DescriptorSet, binding int, typ DescriptorType, buf Buffer) WriteDescriptorSet {
return C.VkWriteDescriptorSet{
sType: C.VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
dstSet: set,
dstBinding: C.uint32_t(binding),
descriptorCount: 1,
descriptorType: typ,
pBufferInfo: &C.VkDescriptorBufferInfo{
buffer: buf,
_range: C.VK_WHOLE_SIZE,
},
}
}
func (r PushConstantRange) StageFlags() ShaderStageFlags {
return r.stageFlags
}
func (r PushConstantRange) Offset() int {
return int(r.offset)
}
func (r PushConstantRange) Size() int {
return int(r.size)
}
func (p QueueFamilyProperties) Flags() QueueFlags {
return p.queueFlags
}
func (c SurfaceCapabilities) MinExtent() image.Point {
return image.Pt(int(c.minImageExtent.width), int(c.minImageExtent.height))
}
func (c SurfaceCapabilities) MaxExtent() image.Point {
return image.Pt(int(c.maxImageExtent.width), int(c.maxImageExtent.height))
}
func BuildViewport(x, y, width, height float32) Viewport {
return C.VkViewport{
x: C.float(x),
y: C.float(y),
width: C.float(width),
height: C.float(height),
maxDepth: 1.0,
}
}
func BuildImageMemoryBarrier(img Image, srcMask, dstMask AccessFlags, oldLayout, newLayout ImageLayout) ImageMemoryBarrier {
return C.VkImageMemoryBarrier{
sType: C.VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
srcAccessMask: srcMask,
dstAccessMask: dstMask,
oldLayout: oldLayout,
newLayout: newLayout,
image: img,
subresourceRange: C.VkImageSubresourceRange{
aspectMask: C.VK_IMAGE_ASPECT_COLOR_BIT,
levelCount: C.VK_REMAINING_MIP_LEVELS,
layerCount: C.VK_REMAINING_ARRAY_LAYERS,
},
}
}
func BuildBufferMemoryBarrier(buf Buffer, srcMask, dstMask AccessFlags) BufferMemoryBarrier {
return C.VkBufferMemoryBarrier{
sType: C.VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
srcAccessMask: srcMask,
dstAccessMask: dstMask,
buffer: buf,
size: C.VK_WHOLE_SIZE,
}
}
func BuildMemoryBarrier(srcMask, dstMask AccessFlags) MemoryBarrier {
return C.VkMemoryBarrier{
sType: C.VK_STRUCTURE_TYPE_MEMORY_BARRIER,
srcAccessMask: srcMask,
dstAccessMask: dstMask,
}
}
func BuildBufferImageCopy(bufOff, bufStride, x, y, width, height int) BufferImageCopy {
return C.VkBufferImageCopy{
bufferOffset: C.VkDeviceSize(bufOff),
bufferRowLength: C.uint32_t(bufStride),
imageSubresource: C.VkImageSubresourceLayers{
aspectMask: C.VK_IMAGE_ASPECT_COLOR_BIT,
layerCount: 1,
},
imageOffset: C.VkOffset3D{
x: C.int32_t(x), y: C.int32_t(y), z: 0,
},
imageExtent: C.VkExtent3D{
width: C.uint32_t(width), height: C.uint32_t(height), depth: 1,
},
}
}
func BuildImageCopy(srcX, srcY, dstX, dstY, width, height int) ImageCopy {
return C.VkImageCopy{
srcSubresource: C.VkImageSubresourceLayers{
aspectMask: C.VK_IMAGE_ASPECT_COLOR_BIT,
layerCount: 1,
},
srcOffset: C.VkOffset3D{
x: C.int32_t(srcX),
y: C.int32_t(srcY),
},
dstSubresource: C.VkImageSubresourceLayers{
aspectMask: C.VK_IMAGE_ASPECT_COLOR_BIT,
layerCount: 1,
},
dstOffset: C.VkOffset3D{
x: C.int32_t(dstX),
y: C.int32_t(dstY),
},
extent: C.VkExtent3D{
width: C.uint32_t(width),
height: C.uint32_t(height),
depth: 1,
},
}
}
func findMemoryTypeIndex(pd C.VkPhysicalDevice, constraints C.uint32_t, wantProps C.VkMemoryPropertyFlags) (int, bool) {
var memProps C.VkPhysicalDeviceMemoryProperties
C.vkGetPhysicalDeviceMemoryProperties(funcs.vkGetPhysicalDeviceMemoryProperties, pd, &memProps)
for i := 0; i < int(memProps.memoryTypeCount); i++ {
if (constraints & (1 << i)) == 0 {
continue
}
if (memProps.memoryTypes[i].propertyFlags & wantProps) != wantProps {
continue
}
return i, true
}
return 0, false
}
func choosePresentMode(pd C.VkPhysicalDevice, surf Surface) (C.VkPresentModeKHR, bool, error) {
var count C.uint32_t
err := vkErr(C.vkGetPhysicalDeviceSurfacePresentModesKHR(funcs.vkGetPhysicalDeviceSurfacePresentModesKHR, pd, surf, &count, nil))
if err != nil {
return 0, false, fmt.Errorf("vulkan: vkGetPhysicalDeviceSurfacePresentModesKHR: %w", err)
}
if count == 0 {
return 0, false, nil
}
modes := make([]C.VkPresentModeKHR, count)
err = vkErr(C.vkGetPhysicalDeviceSurfacePresentModesKHR(funcs.vkGetPhysicalDeviceSurfacePresentModesKHR, pd, surf, &count, &modes[0]))
if err != nil {
return 0, false, fmt.Errorf("vulkan: kGetPhysicalDeviceSurfacePresentModesKHR: %w", err)
}
for _, m := range modes {
if m == C.VK_PRESENT_MODE_MAILBOX_KHR || m == C.VK_PRESENT_MODE_FIFO_KHR {
return m, true, nil
}
}
return 0, false, nil
}
func chooseFormat(pd C.VkPhysicalDevice, surf Surface) (C.VkSurfaceFormatKHR, bool, error) {
var count C.uint32_t
err := vkErr(C.vkGetPhysicalDeviceSurfaceFormatsKHR(funcs.vkGetPhysicalDeviceSurfaceFormatsKHR, pd, surf, &count, nil))
if err != nil {
return C.VkSurfaceFormatKHR{}, false, fmt.Errorf("vulkan: vkGetPhysicalDeviceSurfaceFormatsKHR: %w", err)
}
if count == 0 {
return C.VkSurfaceFormatKHR{}, false, nil
}
formats := make([]C.VkSurfaceFormatKHR, count)
err = vkErr(C.vkGetPhysicalDeviceSurfaceFormatsKHR(funcs.vkGetPhysicalDeviceSurfaceFormatsKHR, pd, surf, &count, &formats[0]))
if err != nil {
return C.VkSurfaceFormatKHR{}, false, fmt.Errorf("vulkan: vkGetPhysicalDeviceSurfaceFormatsKHR: %w", err)
}
// Query for format with sRGB support.
// TODO: Support devices without sRGB.
for _, f := range formats {
if f.colorSpace != C.VK_COLOR_SPACE_SRGB_NONLINEAR_KHR {
continue
}
switch f.format {
case C.VK_FORMAT_B8G8R8A8_SRGB, C.VK_FORMAT_R8G8B8A8_SRGB:
return f, true, nil
}
}
return C.VkSurfaceFormatKHR{}, false, nil
}
func chooseQueue(pd C.VkPhysicalDevice, surf Surface, flags C.VkQueueFlags) (int, bool, error) {
queues := GetPhysicalDeviceQueueFamilyProperties(pd)
for i, q := range queues {
// Check for presentation and feature support.
if q.queueFlags&flags != flags {
continue
}
if surf != nilSurface {
// Check for presentation support. It is possible that a device has no
// queue with both rendering and presentation support, but not in reality.
// See https://github.com/KhronosGroup/Vulkan-Docs/issues/1234.
var support C.VkBool32
if err := vkErr(C.vkGetPhysicalDeviceSurfaceSupportKHR(funcs.vkGetPhysicalDeviceSurfaceSupportKHR, pd, C.uint32_t(i), surf, &support)); err != nil {
return 0, false, fmt.Errorf("vulkan: vkGetPhysicalDeviceSurfaceSupportKHR: %w", err)
}
if support != C.VK_TRUE {
continue
}
}
return i, true, nil
}
return 0, false, nil
}
func dlsym(handle unsafe.Pointer, s string) unsafe.Pointer {
cs := C.CString(s)
defer C.free(unsafe.Pointer(cs))
return C.dlsym(handle, cs)
}
func dlopen(lib string) unsafe.Pointer {
clib := C.CString(lib)
defer C.free(unsafe.Pointer(clib))
return C.dlopen(clib, C.RTLD_NOW|C.RTLD_LOCAL)
}
func vkErr(res C.VkResult) error {
switch res {
case C.VK_SUCCESS:
return nil
default:
return Error(res)
}
}
func (e Error) Error() string {
return fmt.Sprintf("error %d", e)
}