mirror of
https://github.com/Yours3lf/rpi-vk-driver.git
synced 2024-11-28 10:24:15 +01:00
646 lines
22 KiB
C
646 lines
22 KiB
C
#include "common.h"
|
|
#include "modeset.h"
|
|
|
|
#include "kernel/vc4_packet.h"
|
|
|
|
#include "declarations.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
VKAPI_ATTR VkResult VKAPI_CALL RPIFUNC(vkGetPhysicalDeviceDisplayPropertiesKHR)(
|
|
VkPhysicalDevice physicalDevice,
|
|
uint32_t* pPropertyCount,
|
|
VkDisplayPropertiesKHR* pProperties)
|
|
{
|
|
PROFILESTART(RPIFUNC(vkGetPhysicalDeviceDisplayPropertiesKHR));
|
|
|
|
assert(physicalDevice);
|
|
assert(pPropertyCount);
|
|
|
|
uint32_t numDisplays;
|
|
modeset_display displays[16];
|
|
modeset_enum_displays(controlFd, &numDisplays, displays);
|
|
|
|
if(!pProperties)
|
|
{
|
|
*pPropertyCount = numDisplays;
|
|
|
|
PROFILEEND(RPIFUNC(vkGetPhysicalDeviceDisplayPropertiesKHR));
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
uint32_t arraySize = *pPropertyCount;
|
|
uint32_t elementsWritten = min(numDisplays, arraySize);
|
|
|
|
for(uint32_t c = 0; c < elementsWritten; ++c)
|
|
{
|
|
pProperties[c].display = displays[c].connectorID;
|
|
//fprintf(stderr, "display id %i\n", pProperties[c].display );
|
|
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)
|
|
{
|
|
PROFILEEND(RPIFUNC(vkGetPhysicalDeviceDisplayPropertiesKHR));
|
|
return VK_INCOMPLETE;
|
|
}
|
|
|
|
PROFILEEND(RPIFUNC(vkGetPhysicalDeviceDisplayPropertiesKHR));
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VKAPI_ATTR VkResult VKAPI_CALL RPIFUNC(vkGetDisplayModePropertiesKHR)(
|
|
VkPhysicalDevice physicalDevice,
|
|
VkDisplayKHR display,
|
|
uint32_t* pPropertyCount,
|
|
VkDisplayModePropertiesKHR* pProperties)
|
|
{
|
|
PROFILESTART(RPIFUNC(vkGetDisplayModePropertiesKHR));
|
|
|
|
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;
|
|
|
|
PROFILEEND(RPIFUNC(vkGetDisplayModePropertiesKHR));
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
uint32_t arraySize = *pPropertyCount;
|
|
uint32_t elementsWritten = min(numModes, arraySize);
|
|
|
|
for(uint32_t 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)
|
|
{
|
|
PROFILEEND(RPIFUNC(vkGetDisplayModePropertiesKHR));
|
|
return VK_INCOMPLETE;
|
|
}
|
|
|
|
PROFILEEND(RPIFUNC(vkGetDisplayModePropertiesKHR));
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VKAPI_ATTR VkResult VKAPI_CALL RPIFUNC(vkCreateDisplayPlaneSurfaceKHR)(
|
|
VkInstance instance,
|
|
const VkDisplaySurfaceCreateInfoKHR* pCreateInfo,
|
|
const VkAllocationCallbacks* pAllocator,
|
|
VkSurfaceKHR* pSurface)
|
|
{
|
|
PROFILESTART(RPIFUNC(vkCreateDisplayPlaneSurfaceKHR));
|
|
|
|
assert(instance);
|
|
assert(pSurface);
|
|
|
|
_displayMode mode;
|
|
memcpy(&mode, &pCreateInfo->displayMode, sizeof(_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;
|
|
|
|
PROFILEEND(RPIFUNC(vkCreateDisplayPlaneSurfaceKHR));
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* 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 RPIFUNC(vkDestroySurfaceKHR)(
|
|
VkInstance instance,
|
|
VkSurfaceKHR surface,
|
|
const VkAllocationCallbacks* pAllocator)
|
|
{
|
|
PROFILESTART(RPIFUNC(vkDestroySurfaceKHR));
|
|
|
|
assert(instance);
|
|
|
|
if(surface)
|
|
{
|
|
modeset_destroy_surface(controlFd, surface);
|
|
}
|
|
|
|
FREE(surface);
|
|
|
|
PROFILEEND(RPIFUNC(vkDestroySurfaceKHR));
|
|
}
|
|
|
|
/*
|
|
* 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 RPIFUNC(vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(
|
|
VkPhysicalDevice physicalDevice,
|
|
VkSurfaceKHR surface,
|
|
VkSurfaceCapabilitiesKHR* pSurfaceCapabilities)
|
|
{
|
|
PROFILESTART(RPIFUNC(vkGetPhysicalDeviceSurfaceCapabilitiesKHR));
|
|
|
|
assert(physicalDevice);
|
|
assert(surface);
|
|
assert(pSurfaceCapabilities);
|
|
|
|
modeset_display_surface* surf = surface;
|
|
|
|
uint32_t width = surf->connector->modes[surf->modeID].hdisplay;
|
|
uint32_t height = surf->connector->modes[surf->modeID].vdisplay;
|
|
|
|
pSurfaceCapabilities->minImageCount = 1;
|
|
pSurfaceCapabilities->maxImageCount = 2; //TODO max 2 for double buffering for now...
|
|
pSurfaceCapabilities->currentExtent.width = width;
|
|
pSurfaceCapabilities->currentExtent.height = height;
|
|
pSurfaceCapabilities->minImageExtent.width = width;
|
|
pSurfaceCapabilities->minImageExtent.height = height;
|
|
pSurfaceCapabilities->maxImageExtent.width = width;
|
|
pSurfaceCapabilities->maxImageExtent.height = height;
|
|
pSurfaceCapabilities->maxImageArrayLayers = 1;
|
|
pSurfaceCapabilities->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
|
pSurfaceCapabilities->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
|
pSurfaceCapabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
|
pSurfaceCapabilities->supportedUsageFlags =
|
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | //well we want to draw on the screen right
|
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT | //for clears
|
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT; //for screenshots
|
|
|
|
PROFILEEND(RPIFUNC(vkGetPhysicalDeviceSurfaceCapabilitiesKHR));
|
|
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 RPIFUNC(vkGetPhysicalDeviceSurfaceFormatsKHR)(
|
|
VkPhysicalDevice physicalDevice,
|
|
VkSurfaceKHR surface,
|
|
uint32_t* pSurfaceFormatCount,
|
|
VkSurfaceFormatKHR* pSurfaceFormats)
|
|
{
|
|
PROFILESTART(RPIFUNC(vkGetPhysicalDeviceSurfaceFormatsKHR));
|
|
|
|
assert(physicalDevice);
|
|
assert(surface);
|
|
assert(pSurfaceFormatCount);
|
|
|
|
const int numFormats = 1;
|
|
|
|
if(!pSurfaceFormats)
|
|
{
|
|
*pSurfaceFormatCount = numFormats;
|
|
|
|
PROFILEEND(RPIFUNC(vkGetPhysicalDeviceSurfaceFormatsKHR));
|
|
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)
|
|
{
|
|
PROFILEEND(RPIFUNC(vkGetPhysicalDeviceSurfaceFormatsKHR));
|
|
return VK_INCOMPLETE;
|
|
}
|
|
|
|
PROFILEEND(RPIFUNC(vkGetPhysicalDeviceSurfaceFormatsKHR));
|
|
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 RPIFUNC(vkGetPhysicalDeviceSurfacePresentModesKHR)(
|
|
VkPhysicalDevice physicalDevice,
|
|
VkSurfaceKHR surface,
|
|
uint32_t* pPresentModeCount,
|
|
VkPresentModeKHR* pPresentModes)
|
|
{
|
|
PROFILESTART(RPIFUNC(vkGetPhysicalDeviceSurfacePresentModesKHR));
|
|
|
|
assert(physicalDevice);
|
|
assert(surface);
|
|
assert(pPresentModeCount);
|
|
|
|
if(!pPresentModes)
|
|
{
|
|
*pPresentModeCount = numSupportedPresentModes;
|
|
|
|
PROFILEEND(RPIFUNC(vkGetPhysicalDeviceSurfacePresentModesKHR));
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
uint32_t arraySize = *pPresentModeCount;
|
|
uint32_t elementsWritten = min(numSupportedPresentModes, arraySize);
|
|
|
|
for(uint32_t c = 0; c < elementsWritten; ++c)
|
|
{
|
|
pPresentModes[c] = supportedPresentModes[c];
|
|
}
|
|
|
|
*pPresentModeCount = elementsWritten;
|
|
|
|
if(elementsWritten < numSupportedPresentModes)
|
|
{
|
|
PROFILEEND(RPIFUNC(vkGetPhysicalDeviceSurfacePresentModesKHR));
|
|
return VK_INCOMPLETE;
|
|
}
|
|
|
|
PROFILEEND(RPIFUNC(vkGetPhysicalDeviceSurfacePresentModesKHR));
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkCreateSwapchainKHR
|
|
*/
|
|
VKAPI_ATTR VkResult VKAPI_CALL RPIFUNC(vkCreateSwapchainKHR)(
|
|
VkDevice device,
|
|
const VkSwapchainCreateInfoKHR* pCreateInfo,
|
|
const VkAllocationCallbacks* pAllocator,
|
|
VkSwapchainKHR* pSwapchain)
|
|
{
|
|
PROFILESTART(RPIFUNC(vkCreateSwapchainKHR));
|
|
|
|
assert(device);
|
|
assert(pCreateInfo);
|
|
assert(pSwapchain);
|
|
|
|
*pSwapchain = ALLOCATE(sizeof(_swapchain), 1, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
if(!*pSwapchain)
|
|
{
|
|
PROFILEEND(RPIFUNC(vkCreateSwapchainKHR));
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
}
|
|
|
|
_swapchain* s = *pSwapchain;
|
|
|
|
//TODO flags, layers, queue sharing, pretransform, composite alpha..., clipped, oldswapchain
|
|
|
|
s->images = ALLOCATE(sizeof(_image) * pCreateInfo->minImageCount, 1, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
if(!s->images)
|
|
{
|
|
PROFILEEND(RPIFUNC(vkCreateSwapchainKHR));
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
}
|
|
|
|
s->inFlight = ALLOCATE(sizeof(uint32_t) * pCreateInfo->minImageCount, 1, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
if(!s->inFlight)
|
|
{
|
|
PROFILEEND(RPIFUNC(vkCreateSwapchainKHR));
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
}
|
|
|
|
s->backbufferIdx = 0;
|
|
s->numImages = pCreateInfo->minImageCount;
|
|
s->surface = pCreateInfo->surface;
|
|
|
|
for(uint32_t c = 0; c < pCreateInfo->minImageCount; ++c)
|
|
{
|
|
s->inFlight[c] = 0;
|
|
|
|
VkImageCreateInfo imageCreateInfo = {0};
|
|
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;
|
|
RPIFUNC(vkCreateImage)(device, &imageCreateInfo, pAllocator, &img);
|
|
|
|
s->images[c] = *(_image*)img;
|
|
|
|
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;
|
|
RPIFUNC(vkGetImageMemoryRequirements)(device, &s->images[c], &mr);
|
|
|
|
s->images[c].alignment = mr.alignment;
|
|
|
|
VkMemoryAllocateInfo ai;
|
|
ai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
ai.allocationSize = mr.size;
|
|
for(uint32_t d = 0; d < numMemoryTypes; ++d)
|
|
{
|
|
if(memoryTypes[d].propertyFlags == mr.memoryTypeBits)
|
|
{
|
|
ai.memoryTypeIndex = d;
|
|
break;
|
|
}
|
|
}
|
|
|
|
VkDeviceMemory mem;
|
|
RPIFUNC(vkAllocateMemory)(device, &ai, pAllocator, &mem);
|
|
|
|
RPIFUNC(vkBindImageMemory)(device, &s->images[c], mem, 0);
|
|
|
|
modeset_create_fb_for_surface(controlFd, &s->images[c], pCreateInfo->surface); assert(s->images[c].fb);
|
|
}
|
|
|
|
PROFILEEND(RPIFUNC(vkCreateSwapchainKHR));
|
|
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.
|
|
*/
|
|
VKAPI_ATTR VkResult VKAPI_CALL RPIFUNC(vkGetSwapchainImagesKHR)(
|
|
VkDevice device,
|
|
VkSwapchainKHR swapchain,
|
|
uint32_t* pSwapchainImageCount,
|
|
VkImage* pSwapchainImages)
|
|
{
|
|
PROFILESTART(RPIFUNC(vkGetSwapchainImagesKHR));
|
|
|
|
assert(device);
|
|
assert(swapchain);
|
|
assert(pSwapchainImageCount);
|
|
|
|
_swapchain* s = swapchain;
|
|
|
|
if(!pSwapchainImages)
|
|
{
|
|
*pSwapchainImageCount = s->numImages;
|
|
|
|
PROFILEEND(RPIFUNC(vkGetSwapchainImagesKHR));
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
uint32_t arraySize = *pSwapchainImageCount;
|
|
uint32_t elementsWritten = min(s->numImages, arraySize);
|
|
|
|
for(uint32_t c = 0; c < elementsWritten; ++c)
|
|
{
|
|
pSwapchainImages[c] = &s->images[c];
|
|
}
|
|
|
|
*pSwapchainImageCount = elementsWritten;
|
|
|
|
if(elementsWritten < s->numImages)
|
|
{
|
|
PROFILEEND(RPIFUNC(vkGetSwapchainImagesKHR));
|
|
return VK_INCOMPLETE;
|
|
}
|
|
|
|
PROFILEEND(RPIFUNC(vkGetSwapchainImagesKHR));
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkAcquireNextImageKHR
|
|
*/
|
|
VKAPI_ATTR VkResult VKAPI_CALL RPIFUNC(vkAcquireNextImageKHR)(
|
|
VkDevice device,
|
|
VkSwapchainKHR swapchain,
|
|
uint64_t timeout,
|
|
VkSemaphore semaphore,
|
|
VkFence fence,
|
|
uint32_t* pImageIndex)
|
|
{
|
|
PROFILESTART(RPIFUNC(vkAcquireNextImageKHR));
|
|
|
|
assert(device);
|
|
assert(swapchain);
|
|
|
|
assert(semaphore != VK_NULL_HANDLE || fence != VK_NULL_HANDLE);
|
|
|
|
sem_t* sem = semaphore;
|
|
_swapchain* sc = swapchain;
|
|
|
|
//TODO we need to keep track of currently acquired images?
|
|
|
|
//TODO wait timeout?
|
|
|
|
_image* i;
|
|
modeset_display_surface* surf;
|
|
modeset_acquire_image(controlFd, &i, &surf);
|
|
|
|
if(i && surf)
|
|
{
|
|
for(uint32_t c = 0; c < sc->numImages; ++c)
|
|
{
|
|
if(&sc->images[c] == i && sc->surface == surf)
|
|
{
|
|
sc->inFlight[c] = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t candidateIdx = (sc->backbufferIdx + 1) % sc->numImages;
|
|
for(uint32_t c = 0; c < sc->numImages; ++c)
|
|
{
|
|
if(!sc->inFlight[candidateIdx])
|
|
{
|
|
sc->backbufferIdx = candidateIdx;
|
|
break;
|
|
}
|
|
|
|
candidateIdx = (candidateIdx + 1) % sc->numImages;
|
|
}
|
|
|
|
*pImageIndex = sc->backbufferIdx; //return back buffer index
|
|
|
|
//signal semaphore
|
|
int semVal; sem_getvalue(sem, &semVal); assert(semVal <= 0); //make sure semaphore is unsignalled
|
|
sem_post(sem);
|
|
|
|
_fence* f = fence;
|
|
if(f)
|
|
{
|
|
f->signaled = 1;
|
|
}
|
|
|
|
PROFILEEND(RPIFUNC(vkAcquireNextImageKHR));
|
|
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.
|
|
*/
|
|
VKAPI_ATTR VkResult VKAPI_CALL RPIFUNC(vkQueuePresentKHR)(
|
|
VkQueue queue,
|
|
const VkPresentInfoKHR* pPresentInfo)
|
|
{
|
|
PROFILESTART(RPIFUNC(vkQueuePresentKHR));
|
|
|
|
static unsigned frameProfile = 0;
|
|
if(frameProfile)
|
|
{
|
|
PROFILEEND(&frameProfile);
|
|
}
|
|
|
|
assert(queue);
|
|
assert(pPresentInfo);
|
|
|
|
//wait for semaphore in present info set by submit ioctl to make sure cls are flushed
|
|
for(uint32_t c = 0; c < pPresentInfo->waitSemaphoreCount; ++c)
|
|
{
|
|
sem_wait((sem_t*)pPresentInfo->pWaitSemaphores[c]);
|
|
}
|
|
|
|
for(uint32_t c = 0; c < pPresentInfo->swapchainCount; ++c)
|
|
{
|
|
_swapchain* s = pPresentInfo->pSwapchains[c];
|
|
modeset_present(controlFd, &s->images[pPresentInfo->pImageIndices[c]], s->surface, queue->lastEmitSeqno);
|
|
s->inFlight[pPresentInfo->pImageIndices[c]] = 1;
|
|
}
|
|
|
|
PROFILEEND(RPIFUNC(vkQueuePresentKHR));
|
|
|
|
PROFILESTART(&frameProfile);
|
|
frameProfile = 1;
|
|
|
|
endFrame();
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkDestroySwapchainKHR
|
|
*/
|
|
VKAPI_ATTR void VKAPI_CALL RPIFUNC(vkDestroySwapchainKHR)(
|
|
VkDevice device,
|
|
VkSwapchainKHR swapchain,
|
|
const VkAllocationCallbacks* pAllocator)
|
|
{
|
|
PROFILESTART(RPIFUNC(vkDestroySwapchainKHR));
|
|
|
|
assert(device);
|
|
|
|
//TODO flush all ops
|
|
|
|
_swapchain* s = swapchain;
|
|
|
|
if(s)
|
|
{
|
|
for(uint32_t c = 0; c < s->numImages; ++c)
|
|
{
|
|
RPIFUNC(vkFreeMemory)(device, s->images[c].boundMem, 0);
|
|
modeset_destroy_fb(controlFd, &s->images[c]);
|
|
}
|
|
|
|
FREE(s->images);
|
|
}
|
|
|
|
FREE(s);
|
|
|
|
PROFILEEND(RPIFUNC(vkDestroySwapchainKHR));
|
|
|
|
profilePrintResults();
|
|
}
|
|
|
|
/*
|
|
* 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 RPIFUNC(vkGetPhysicalDeviceSurfaceSupportKHR)(
|
|
VkPhysicalDevice physicalDevice,
|
|
uint32_t queueFamilyIndex,
|
|
VkSurfaceKHR surface,
|
|
VkBool32* pSupported)
|
|
{
|
|
PROFILESTART(RPIFUNC(vkGetPhysicalDeviceSurfaceSupportKHR));
|
|
|
|
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;
|
|
|
|
PROFILEEND(RPIFUNC(vkGetPhysicalDeviceSurfaceSupportKHR));
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|