1
0
mirror of https://github.com/Yours3lf/rpi-vk-driver.git synced 2024-12-01 13:24:20 +01:00
rpi-vk-driver/driver/wsi.c

552 lines
20 KiB
C
Raw Normal View History

2018-08-26 15:11:43 +02:00
#include "common.h"
#include "modeset.h"
2018-08-26 15:11:43 +02:00
#include "kernel/vc4_packet.h"
2019-09-30 02:13:55 +02:00
#include "declarations.h"
#ifdef __cplusplus
extern "C" {
#endif
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkGetPhysicalDeviceDisplayPropertiesKHR(
VkPhysicalDevice physicalDevice,
uint32_t* pPropertyCount,
VkDisplayPropertiesKHR* pProperties)
{
assert(physicalDevice);
assert(pPropertyCount);
uint32_t numDisplays;
modeset_display displays[16];
modeset_enum_displays(controlFd, &numDisplays, &displays);
if(!pProperties)
{
*pPropertyCount = numDisplays;
return VK_SUCCESS;
}
int arraySize = *pPropertyCount;
int elementsWritten = min(numDisplays, arraySize);
for(int c = 0; c < elementsWritten; ++c)
{
pProperties[c].display = displays[c].connectorID;
char* name = (char*)malloc(32);
memcpy(name, displays[c].name, 32);
pProperties[c].displayName = (const char*)name;
pProperties[c].physicalDimensions.width = displays[c].mmWidth;
pProperties[c].physicalDimensions.height = displays[c].mmHeight;
pProperties[c].physicalResolution.width = displays[c].resWidth;
pProperties[c].physicalResolution.height = displays[c].resHeight;
}
*pPropertyCount = elementsWritten;
if(arraySize < numDisplays)
{
return VK_INCOMPLETE;
}
return VK_SUCCESS;
}
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkGetDisplayModePropertiesKHR(
VkPhysicalDevice physicalDevice,
VkDisplayKHR display,
uint32_t* pPropertyCount,
VkDisplayModePropertiesKHR* pProperties)
{
assert(physicalDevice);
assert(display);
assert(pPropertyCount);
uint32_t numModes;
modeset_display_mode modes[1024];
modeset_enum_modes_for_display(controlFd, display, &numModes, &modes);
if(!pProperties)
{
*pPropertyCount = numModes;
return VK_SUCCESS;
}
int arraySize = *pPropertyCount;
int elementsWritten = min(numModes, arraySize);
for(int c = 0; c < elementsWritten; ++c)
{
_displayMode mode = { modes[c].connectorID, modes[c].modeID };
memcpy(&pProperties[c].displayMode, &mode, sizeof(_displayMode));
pProperties[c].parameters.visibleRegion.width = modes[c].resWidth;
pProperties[c].parameters.visibleRegion.height = modes[c].resHeight;
pProperties[c].parameters.refreshRate = modes[c].refreshRate;
}
*pPropertyCount = elementsWritten;
if(arraySize < numModes)
{
return VK_INCOMPLETE;
}
return VK_SUCCESS;
}
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkCreateDisplayModeKHR(
VkPhysicalDevice physicalDevice,
VkDisplayKHR display,
const VkDisplayModeCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDisplayModeKHR* pMode)
{
assert(physicalDevice);
assert(display);
uint32_t numModes;
modeset_display_mode modes[1024];
modeset_enum_modes_for_display(controlFd, display, &numModes, &modes);
for(uint32_t c = 0; c < numModes; ++c)
{
if(modes[c].refreshRate == pCreateInfo->parameters.refreshRate &&
modes[c].resWidth == pCreateInfo->parameters.visibleRegion.width &&
modes[c].resHeight == pCreateInfo->parameters.visibleRegion.height)
{
_displayMode mode = { modes[c].connectorID, modes[c].modeID };
memcpy(pMode, &mode, sizeof(_displayMode));
}
}
}
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkCreateDisplayPlaneSurfaceKHR(
VkInstance instance,
const VkDisplaySurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface)
{
assert(instance);
assert(pSurface);
_displayMode mode = pCreateInfo->displayMode;
modeset_display_surface* surface = ALLOCATE(sizeof(modeset_display_surface), 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
modeset_create_surface_for_mode(controlFd, mode.connectorID, mode.modeID, surface);
*pSurface = surface;
}
2018-08-26 15:11:43 +02:00
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkDestroySurfaceKHR
* Destroying a VkSurfaceKHR merely severs the connection between Vulkan and the native surface,
* and does not imply destroying the native surface, closing a window, or similar behavior
* (but we'll do so anyways...)
*/
VKAPI_ATTR void VKAPI_CALL rpi_vkDestroySurfaceKHR(
2018-08-26 15:11:43 +02:00
VkInstance instance,
VkSurfaceKHR surface,
const VkAllocationCallbacks* pAllocator)
{
assert(instance);
2019-02-09 17:18:15 +01:00
if(surface)
{
//modeset_destroy(controlFd, (modeset_dev*)surface);
2019-02-09 17:18:15 +01:00
}
FREE(surface);
2018-08-26 15:11:43 +02:00
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkGetPhysicalDeviceSurfaceCapabilitiesKHR
* The capabilities of a swapchain targetting a surface are the intersection of the capabilities of the WSI platform,
* the native window or display, and the physical device. The resulting capabilities can be obtained with the queries listed
* below in this section. Capabilities that correspond to image creation parameters are not independent of each other:
* combinations of parameters that are not supported as reported by vkGetPhysicalDeviceImageFormatProperties are not supported
* by the surface on that physical device, even if the capabilities taken individually are supported as part of some other parameter combinations.
*
* capabilities the specified device supports for a swapchain created for the surface
*/
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
2018-08-26 15:11:43 +02:00
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface,
VkSurfaceCapabilitiesKHR* pSurfaceCapabilities)
{
assert(physicalDevice);
assert(surface);
assert(pSurfaceCapabilities);
pSurfaceCapabilities->minImageCount = 1; //min 1
pSurfaceCapabilities->maxImageCount = 2; //TODO max 2 for double buffering for now...
pSurfaceCapabilities->currentExtent.width = ((modeset_dev*)surface)->width;
pSurfaceCapabilities->currentExtent.height = ((modeset_dev*)surface)->height;
pSurfaceCapabilities->minImageExtent.width = ((modeset_dev*)surface)->width; //TODO
pSurfaceCapabilities->minImageExtent.height = ((modeset_dev*)surface)->height; //TODO
pSurfaceCapabilities->maxImageExtent.width = ((modeset_dev*)surface)->width; //TODO
pSurfaceCapabilities->maxImageExtent.height = ((modeset_dev*)surface)->height; //TODO
pSurfaceCapabilities->maxImageArrayLayers = 1; //TODO maybe more layers for cursor etc.
pSurfaceCapabilities->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; //TODO no rotation for now
pSurfaceCapabilities->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; //TODO get this from dev
pSurfaceCapabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; //TODO no alpha compositing for now
pSurfaceCapabilities->supportedUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; //well we want to draw on the screen right
return VK_SUCCESS;
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkGetPhysicalDeviceSurfaceFormatsKHR
* If pSurfaceFormats is NULL, then the number of format pairs supported for the given surface is returned in pSurfaceFormatCount.
* The number of format pairs supported will be greater than or equal to 1. Otherwise, pSurfaceFormatCount must point to a variable
* set by the user to the number of elements in the pSurfaceFormats array, and on return the variable is overwritten with the number
* of structures actually written to pSurfaceFormats. If the value of pSurfaceFormatCount is less than the number of format pairs supported,
* at most pSurfaceFormatCount structures will be written. If pSurfaceFormatCount is smaller than the number of format pairs supported for the given surface,
* VK_INCOMPLETE will be returned instead of VK_SUCCESS to indicate that not all the available values were returned.
*/
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkGetPhysicalDeviceSurfaceFormatsKHR(
2018-08-26 15:11:43 +02:00
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface,
uint32_t* pSurfaceFormatCount,
VkSurfaceFormatKHR* pSurfaceFormats)
{
assert(physicalDevice);
assert(surface);
assert(pSurfaceFormatCount);
const int numFormats = 1;
if(!pSurfaceFormats)
{
*pSurfaceFormatCount = numFormats;
return VK_SUCCESS;
}
int arraySize = *pSurfaceFormatCount;
int elementsWritten = min(numFormats, arraySize);
for(int c = 0; c < elementsWritten; ++c)
{
pSurfaceFormats[c] = supportedSurfaceFormats[c];
}
*pSurfaceFormatCount = elementsWritten;
if(elementsWritten < numFormats)
{
return VK_INCOMPLETE;
}
return VK_SUCCESS;
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkGetPhysicalDeviceSurfacePresentModesKHR
* If pPresentModes is NULL, then the number of presentation modes supported for the given surface is returned in pPresentModeCount.
* Otherwise, pPresentModeCount must point to a variable set by the user to the number of elements in the pPresentModes array,
* and on return the variable is overwritten with the number of values actually written to pPresentModes.
* If the value of pPresentModeCount is less than the number of presentation modes supported, at most pPresentModeCount values will be written.
* If pPresentModeCount is smaller than the number of presentation modes supported for the given surface, VK_INCOMPLETE will be returned instead of
* VK_SUCCESS to indicate that not all the available values were returned.
*/
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkGetPhysicalDeviceSurfacePresentModesKHR(
2018-08-26 15:11:43 +02:00
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface,
uint32_t* pPresentModeCount,
VkPresentModeKHR* pPresentModes)
{
assert(physicalDevice);
assert(surface);
assert(pPresentModeCount);
const int numModes = 1;
if(!pPresentModes)
{
*pPresentModeCount = numModes;
return VK_SUCCESS;
}
int arraySize = *pPresentModeCount;
int elementsWritten = min(numModes, arraySize);
for(int c = 0; c < elementsWritten; ++c)
{
//TODO
pPresentModes[c] = VK_PRESENT_MODE_FIFO_KHR;
}
*pPresentModeCount = elementsWritten;
if(elementsWritten < numModes)
{
return VK_INCOMPLETE;
}
return VK_SUCCESS;
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkCreateSwapchainKHR
*/
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkCreateSwapchainKHR(
2018-08-26 15:11:43 +02:00
VkDevice device,
const VkSwapchainCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSwapchainKHR* pSwapchain)
{
assert(device);
assert(pCreateInfo);
assert(pSwapchain);
*pSwapchain = ALLOCATE(sizeof(_swapchain), 1, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2018-08-26 15:11:43 +02:00
if(!*pSwapchain)
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
_swapchain* s = *pSwapchain;
//TODO flags, layers, queue sharing, pretransform, composite alpha, present mode..., clipped, oldswapchain
//TODO external sync on surface, oldswapchain
s->images = ALLOCATE(sizeof(_image) * pCreateInfo->minImageCount, 1, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2018-08-26 15:11:43 +02:00
if(!s->images)
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
s->backbufferIdx = 0;
s->numImages = pCreateInfo->minImageCount;
s->surface = pCreateInfo->surface;
for(int c = 0; c < pCreateInfo->minImageCount; ++c)
{
VkImageCreateInfo imageCreateInfo = {};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = pCreateInfo->imageFormat;
imageCreateInfo.mipLevels = 1;
imageCreateInfo.arrayLayers = pCreateInfo->imageArrayLayers;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = pCreateInfo->imageUsage;
imageCreateInfo.sharingMode = pCreateInfo->imageSharingMode;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount;
imageCreateInfo.pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices;
imageCreateInfo.extent.width = pCreateInfo->imageExtent.width;
imageCreateInfo.extent.height = pCreateInfo->imageExtent.height;
imageCreateInfo.extent.depth = 1;
VkImage img;
rpi_vkCreateImage(device, &imageCreateInfo, pAllocator, &img);
s->images[c] = *(_image*)img;
2018-08-26 15:11:43 +02:00
s->images[c].imageSpace = pCreateInfo->imageColorSpace;
s->images[c].preTransformMode = pCreateInfo->preTransform;
s->images[c].compositeAlpha = pCreateInfo->compositeAlpha;
s->images[c].presentMode = pCreateInfo->presentMode;
s->images[c].clipped = pCreateInfo->clipped;
VkMemoryRequirements mr;
2019-09-30 02:13:55 +02:00
rpi_vkGetImageMemoryRequirements(device, &s->images[c], &mr);
2018-12-09 19:21:23 +01:00
s->images[c].alignment = mr.alignment;
VkMemoryAllocateInfo ai;
ai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
ai.allocationSize = mr.size;
for(int d = 0; d < numMemoryTypes; ++d)
{
if(memoryTypes[d].propertyFlags == mr.memoryTypeBits)
{
ai.memoryTypeIndex = d;
break;
}
}
VkDeviceMemory mem;
rpi_vkAllocateMemory(device, &ai, pAllocator, &mem);
2019-09-30 02:13:55 +02:00
rpi_vkBindImageMemory(device, &s->images[c], mem, 0);
int res = modeset_create_fb(controlFd, &s->images[c]); assert(res == 0);
2018-08-26 15:11:43 +02:00
}
//defer to first swapbuffer (or at least later, getting swapchain != presenting immediately)
//int res = modeset_fb_for_dev(controlFd, s->surface, &s->images[s->backbufferIdx]); assert(res == 0);
return VK_SUCCESS;
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkGetSwapchainImagesKHR
* If pSwapchainImages is NULL, then the number of presentable images for swapchain is returned in pSwapchainImageCount.
* Otherwise, pSwapchainImageCount must point to a variable set by the user to the number of elements in the pSwapchainImages array,
* and on return the variable is overwritten with the number of structures actually written to pSwapchainImages.
* If the value of pSwapchainImageCount is less than the number of presentable images for swapchain, at most pSwapchainImageCount structures will be written.
* If pSwapchainImageCount is smaller than the number of presentable images for swapchain, VK_INCOMPLETE will be returned instead of VK_SUCCESS to
* indicate that not all the available values were returned.
*/
2019-09-30 00:52:21 +02:00
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkGetSwapchainImagesKHR(
2018-08-26 15:11:43 +02:00
VkDevice device,
VkSwapchainKHR swapchain,
uint32_t* pSwapchainImageCount,
VkImage* pSwapchainImages)
{
assert(device);
assert(swapchain);
assert(pSwapchainImageCount);
_swapchain* s = swapchain;
if(!pSwapchainImages)
{
*pSwapchainImageCount = s->numImages;
return VK_SUCCESS;
}
int arraySize = *pSwapchainImageCount;
int elementsWritten = min(s->numImages, arraySize);
for(int c = 0; c < elementsWritten; ++c)
{
pSwapchainImages[c] = &s->images[c];
}
*pSwapchainImageCount = elementsWritten;
if(elementsWritten < s->numImages)
{
return VK_INCOMPLETE;
}
return VK_SUCCESS;
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkAcquireNextImageKHR
*/
2019-09-30 00:52:21 +02:00
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkAcquireNextImageKHR(
2018-08-26 15:11:43 +02:00
VkDevice device,
VkSwapchainKHR swapchain,
uint64_t timeout,
VkSemaphore semaphore,
VkFence fence,
uint32_t* pImageIndex)
{
assert(device);
assert(swapchain);
assert(semaphore != VK_NULL_HANDLE || fence != VK_NULL_HANDLE);
sem_t* s = semaphore;
//TODO we need to keep track of currently acquired images?
//TODO wait timeout?
*pImageIndex = ((_swapchain*)swapchain)->backbufferIdx; //return back buffer index
//signal semaphore
int semVal; sem_getvalue(s, &semVal); assert(semVal <= 0); //make sure semaphore is unsignalled
sem_post(s);
//TODO signal fence
return VK_SUCCESS;
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkQueuePresentKHR
* Any writes to memory backing the images referenced by the pImageIndices and pSwapchains members of pPresentInfo,
* that are available before vkQueuePresentKHR is executed, are automatically made visible to the read access performed by the presentation engine.
* This automatic visibility operation for an image happens-after the semaphore signal operation, and happens-before the presentation engine accesses the image.
* Queueing an image for presentation defines a set of queue operations, including waiting on the semaphores and submitting a presentation request to the presentation engine.
* However, the scope of this set of queue operations does not include the actual processing of the image by the presentation engine.
* If vkQueuePresentKHR fails to enqueue the corresponding set of queue operations, it may return VK_ERROR_OUT_OF_HOST_MEMORY or VK_ERROR_OUT_OF_DEVICE_MEMORY.
* If it does, the implementation must ensure that the state and contents of any resources or synchronization primitives referenced is unaffected by the call or its failure.
* If vkQueuePresentKHR fails in such a way that the implementation is unable to make that guarantee, the implementation must return VK_ERROR_DEVICE_LOST.
* However, if the presentation request is rejected by the presentation engine with an error VK_ERROR_OUT_OF_DATE_KHR or VK_ERROR_SURFACE_LOST_KHR,
* the set of queue operations are still considered to be enqueued and thus any semaphore to be waited on gets unsignaled when the corresponding queue operation is complete.
*/
2019-09-30 00:52:21 +02:00
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkQueuePresentKHR(
2018-08-26 15:11:43 +02:00
VkQueue queue,
const VkPresentInfoKHR* pPresentInfo)
{
assert(queue);
assert(pPresentInfo);
//wait for semaphore in present info set by submit ioctl to make sure cls are flushed
for(int c = 0; c < pPresentInfo->waitSemaphoreCount; ++c)
{
sem_wait((sem_t*)pPresentInfo->pWaitSemaphores[c]);
}
for(int c = 0; c < pPresentInfo->swapchainCount; ++c)
{
_swapchain* s = pPresentInfo->pSwapchains[c];
modeset_present_buffer(controlFd, (modeset_dev*)s->surface, &s->images[s->backbufferIdx]);
2018-08-26 15:11:43 +02:00
s->backbufferIdx = (s->backbufferIdx + 1) % s->numImages;
}
return VK_SUCCESS;
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkDestroySwapchainKHR
*/
2019-09-30 00:52:21 +02:00
VKAPI_ATTR void VKAPI_CALL rpi_vkDestroySwapchainKHR(
2018-08-26 15:11:43 +02:00
VkDevice device,
VkSwapchainKHR swapchain,
const VkAllocationCallbacks* pAllocator)
{
assert(device);
//TODO flush all ops
_swapchain* s = swapchain;
2019-02-09 17:18:15 +01:00
if(s)
2018-08-26 15:11:43 +02:00
{
2019-02-09 17:18:15 +01:00
for(int c = 0; c < s->numImages; ++c)
{
2019-09-30 02:13:55 +02:00
rpi_vkFreeMemory(device, s->images[c].boundMem, 0);
2019-02-09 17:18:15 +01:00
modeset_destroy_fb(controlFd, &s->images[c]);
}
FREE(s->images);
2018-08-26 15:11:43 +02:00
}
FREE(s);
2018-08-26 15:11:43 +02:00
}
2019-04-22 15:58:27 +02:00
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkGetPhysicalDeviceSurfaceSupportKHR
* does this queue family support presentation to this surface?
*/
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkGetPhysicalDeviceSurfaceSupportKHR(
2019-04-22 15:58:27 +02:00
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
VkSurfaceKHR surface,
VkBool32* pSupported)
{
assert(pSupported);
assert(surface);
assert(physicalDevice);
assert(queueFamilyIndex < numQueueFamilies);
//TODO if we plan to support headless rendering, there should be 2 families
//one using /dev/dri/card0 which has modesetting
//other using /dev/dri/renderD128 which does not support modesetting, this would say false here
*pSupported = VK_TRUE;
return VK_SUCCESS;
}
#ifdef __cplusplus
}
#endif