1
0
mirror of https://github.com/Yours3lf/rpi-vk-driver.git synced 2024-12-04 16:24:15 +01:00
rpi-vk-driver/driver/instance.c

493 lines
16 KiB
C
Raw Normal View History

2018-08-26 15:11:43 +02:00
#include "common.h"
2019-09-30 00:52:21 +02:00
#include <vulkan/vk_icd.h>
#include "declarations.h"
2019-09-30 21:38:35 +02:00
#define RETFUNC(f) if(!strcmp(pName, #f)) return &rpi_##f
2019-09-30 00:52:21 +02:00
static uint32_t loaderVersion = -1;
VKAPI_ATTR VkResult VKAPI_CALL vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion)
{
assert(pSupportedVersion);
loaderVersion = *pSupportedVersion;
2019-09-30 21:38:35 +02:00
*pSupportedVersion = 4; //we support v4
return VK_SUCCESS;
2019-09-30 00:52:21 +02:00
}
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetInstanceProcAddr(VkInstance instance, const char* pName)
{
if(loaderVersion == -1)
{
//dealing with legacy ICD loader, as vk_icdNegotiateLoaderICDInterfaceVersion has not been called
loaderVersion = 1;
}
2019-09-30 21:38:35 +02:00
void* ptr = rpi_vkGetInstanceProcAddr(instance, pName);
return ptr;
2019-09-30 00:52:21 +02:00
}
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetPhysicalDeviceProcAddr(VkInstance instance,
const char* pName)
{
2019-09-30 22:30:37 +02:00
void* ptr = 0;
2019-09-30 02:13:55 +02:00
// if(!strcmp(pName, "vkCreateShaderModuleFromRpiAssemblyEXT"))
// ptr = &rpi_vkCreateShaderModuleFromRpiAssemblyEXT;
2019-09-30 22:30:37 +02:00
return ptr;
2019-09-30 00:52:21 +02:00
}
2018-08-26 15:11:43 +02:00
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkEnumerateInstanceExtensionProperties
* When pLayerName parameter is NULL, only extensions provided by the Vulkan implementation or by implicitly enabled layers are returned. When pLayerName is the name of a layer,
* the instance extensions provided by that layer are returned.
* If pProperties is NULL, then the number of extensions properties available is returned in pPropertyCount. Otherwise, pPropertyCount must point to a variable set by the user
* to the number of elements in the pProperties array, and on return the variable is overwritten with the number of structures actually written to pProperties.
* If pPropertyCount is less than the number of extension properties available, at most pPropertyCount structures will be written. If pPropertyCount is smaller than the number of extensions available,
* VK_INCOMPLETE will be returned instead of VK_SUCCESS, to indicate that not all the available properties were returned.
* Because the list of available layers may change externally between calls to vkEnumerateInstanceExtensionProperties,
* two calls may retrieve different results if a pLayerName is available in one call but not in another. The extensions supported by a layer may also change between two calls,
* e.g. if the layer implementation is replaced by a different version between those calls.
*/
2019-09-30 00:52:21 +02:00
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkEnumerateInstanceExtensionProperties(
2018-08-26 15:11:43 +02:00
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties)
{
assert(pPropertyCount);
2019-09-08 00:30:52 +02:00
//TODO layers
2018-08-26 15:11:43 +02:00
if(!pProperties)
{
*pPropertyCount = numInstanceExtensions;
return VK_SUCCESS;
2018-08-26 15:11:43 +02:00
}
int arraySize = *pPropertyCount;
int elementsWritten = min(numInstanceExtensions, arraySize);
for(int c = 0; c < elementsWritten; ++c)
{
pProperties[c] = instanceExtensions[c];
}
*pPropertyCount = elementsWritten;
if(arraySize < numInstanceExtensions)
{
return VK_INCOMPLETE;
}
else
{
return VK_SUCCESS;
}
2018-08-26 15:11:43 +02:00
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkCreateInstance
* There is no global state in Vulkan and all per-application state is stored in a VkInstance object. Creating a VkInstance object initializes the Vulkan library
* vkCreateInstance verifies that the requested layers exist. If not, vkCreateInstance will return VK_ERROR_LAYER_NOT_PRESENT. Next vkCreateInstance verifies that
* the requested extensions are supported (e.g. in the implementation or in any enabled instance layer) and if any requested extension is not supported,
* vkCreateInstance must return VK_ERROR_EXTENSION_NOT_PRESENT. After verifying and enabling the instance layers and extensions the VkInstance object is
* created and returned to the application.
*/
2019-09-30 00:52:21 +02:00
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkCreateInstance(
2018-08-26 15:11:43 +02:00
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance)
{
assert(pInstance);
assert(pCreateInfo);
*pInstance = ALLOCATE(sizeof(_instance), 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2018-08-26 15:11:43 +02:00
if(!*pInstance)
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
2019-09-30 00:52:21 +02:00
set_loader_magic_value(&(*pInstance)->loaderData);
2018-08-26 15:11:43 +02:00
(*pInstance)->numEnabledExtensions = 0;
2019-09-08 00:30:52 +02:00
//TODO handle layers
2018-08-26 15:11:43 +02:00
if(pCreateInfo->enabledExtensionCount)
{
assert(pCreateInfo->ppEnabledExtensionNames);
}
for(int c = 0; c < pCreateInfo->enabledExtensionCount; ++c)
{
int findres = findInstanceExtension(pCreateInfo->ppEnabledExtensionNames[c]);
if(findres > -1)
{
(*pInstance)->enabledExtensions[(*pInstance)->numEnabledExtensions] = findres;
(*pInstance)->numEnabledExtensions++;
}
else
{
2019-02-10 00:53:32 +01:00
FREE(*pInstance);
*pInstance = 0;
2018-08-26 15:11:43 +02:00
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
}
//TODO ignored for now
//pCreateInfo->pApplicationInfo
2020-04-10 15:02:44 +02:00
{ //Simple check to make sure we only support RPi 0, 1, 2, 3
FILE* f = fopen("/proc/cpuinfo", "r");
if(!f)
{
return VK_ERROR_INITIALIZATION_FAILED;
}
char* str = malloc(4096);
int n = fread(str, 1, 4096, f);
2020-04-10 15:04:25 +02:00
fclose(f);
2020-04-10 15:02:44 +02:00
str[n] = '\0';
2020-04-10 15:04:25 +02:00
char* hw = strstr(str, "Hardware");
hw = strstr(hw, "BCM");
2020-04-10 15:02:44 +02:00
2020-04-10 15:04:25 +02:00
hw[7] = '\0';
2020-04-10 15:02:44 +02:00
2020-04-10 15:04:25 +02:00
if(strcmp(hw, "BCM2835") &&
strcmp(hw, "BCM2836") &&
strcmp(hw, "BCM2837"))
2020-04-10 15:02:44 +02:00
{
return VK_ERROR_INITIALIZATION_FAILED;
}
2020-04-10 15:04:25 +02:00
free(str);
2020-04-10 15:02:44 +02:00
}
2019-09-08 00:30:52 +02:00
//we assume we are on the RPi and the GPU exists...
int gpuExists = access( "/dev/dri/card0", F_OK ) != -1; assert(gpuExists);
2018-08-26 15:11:43 +02:00
(*pInstance)->dev.path = "/dev/dri/card0";
(*pInstance)->dev.instance = *pInstance;
2018-08-26 15:11:43 +02:00
2019-09-30 00:52:21 +02:00
set_loader_magic_value(&(*pInstance)->dev.loaderData);
int ret = openIoctl(); assert(ret != -1);
assert(vc4_get_chip_info(controlFd,
&(*pInstance)->technologyVersion,
&(*pInstance)->IDstrUINT,
&(*pInstance)->vpmMemorySize,
&(*pInstance)->hdrSupported,
&(*pInstance)->numSemaphores,
&(*pInstance)->numTMUperSlice,
&(*pInstance)->numQPUperSlice,
&(*pInstance)->numSlices,
&(*pInstance)->v3dRevision,
&(*pInstance)-> tileBufferDoubleBufferModeSupported,
&(*pInstance)->tileBufferSize,
&(*pInstance)->vriMemorySize));
(*pInstance)->hasTiling = vc4_test_tiling(controlFd);
(*pInstance)->hasControlFlow = vc4_has_feature(controlFd, DRM_VC4_PARAM_SUPPORTS_BRANCHES);
(*pInstance)->hasEtc1 = vc4_has_feature(controlFd, DRM_VC4_PARAM_SUPPORTS_ETC1);
(*pInstance)->hasThreadedFs = vc4_has_feature(controlFd, DRM_VC4_PARAM_SUPPORTS_THREADED_FS);
(*pInstance)->hasMadvise = vc4_has_feature(controlFd, DRM_VC4_PARAM_SUPPORTS_MADVISE);
(*pInstance)->hasPerfmon = vc4_has_feature(controlFd, DRM_VC4_PARAM_SUPPORTS_PERFMON);
(*pInstance)->hasFixedRCLorder = vc4_has_feature(controlFd, DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER);
char IDstring[] = { 0, 0, 0, 0 };
memcpy(IDstring, &(*pInstance)->IDstrUINT, 3);
printf("------------------------------------------\n");
printf("------------------------------------------\n");
printf("V3D chip info: \n");
printf("IDstring %s\n", IDstring);
printf("technologyVersion: %u\n", (*pInstance)->technologyVersion);
printf("v3dRevision %u\n", (*pInstance)->v3dRevision);
printf("vpmMemorySize %u\n", (*pInstance)->vpmMemorySize);
printf("numSemaphores %u\n", (*pInstance)->numSemaphores);
printf("numTMUperSlice %u\n", (*pInstance)->numTMUperSlice);
printf("numQPUperSlice %u\n", (*pInstance)->numQPUperSlice);
printf("numSlices %u\n", (*pInstance)->numSlices);
printf("tileBufferSize %s\n", (*pInstance)->tileBufferSize > 0 ?
(*pInstance)->tileBufferSize > 1 ? "full" : "half" : "quarter");
printf("vriMemorySize %s\n", (*pInstance)->vriMemorySize ? "full" : "half");
printf("hdrSupported %u\n", (*pInstance)->hdrSupported);
printf("tileBufferDoubleBufferModeSupported %u\n", (*pInstance)-> tileBufferDoubleBufferModeSupported);
printf("hasTiling %u\n", (*pInstance)->hasTiling);
printf("hasControlFlow %u\n", (*pInstance)->hasControlFlow);
printf("hasEtc1 %u\n", (*pInstance)->hasEtc1);
printf("hasThreadedFs %u\n", (*pInstance)->hasThreadedFs);
printf("hasMadvise %u\n", (*pInstance)->hasMadvise);
printf("hasPerfmon %u\n", (*pInstance)->hasPerfmon);
printf("hasFixedRCLorder %u\n", (*pInstance)->hasFixedRCLorder);
printf("------------------------------------------\n");
printf("------------------------------------------\n");
2018-08-26 15:11:43 +02:00
assert((*pInstance)->hasTiling);
assert((*pInstance)->hasControlFlow);
assert((*pInstance)->hasEtc1);
assert((*pInstance)->hasThreadedFs);
assert((*pInstance)->hasPerfmon);
2018-08-26 15:11:43 +02:00
return VK_SUCCESS;
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkDestroyInstance
*
*/
2019-09-30 00:52:21 +02:00
VKAPI_ATTR void VKAPI_CALL rpi_vkDestroyInstance(
2018-08-26 15:11:43 +02:00
VkInstance instance,
const VkAllocationCallbacks* pAllocator)
{
2019-02-10 00:53:32 +01:00
if(instance)
{
closeIoctl();
2018-10-16 20:34:17 +02:00
2019-02-10 00:53:32 +01:00
FREE(instance);
}
2018-10-16 20:34:17 +02:00
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkEnumerateInstanceVersion
*/
2019-09-30 00:52:21 +02:00
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkEnumerateInstanceVersion(
2018-10-16 20:34:17 +02:00
uint32_t* pApiVersion)
{
assert(pApiVersion);
*pApiVersion = VK_DRIVER_VERSION; //
2018-10-16 20:34:17 +02:00
return VK_SUCCESS;
2018-08-26 15:11:43 +02:00
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkGetInstanceProcAddr
*/
2019-09-30 00:52:21 +02:00
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL rpi_vkGetInstanceProcAddr(
VkInstance instance,
const char* pName)
{
//TODO take instance into consideration
//eg only return extension functions that are enabled?
if(!instance && !(
!strcmp(pName, "vkEnumerateInstanceVersion") ||
!strcmp(pName, "vkEnumerateInstanceExtensionProperties") ||
!strcmp(pName, "vkEnumerateInstanceLayerProperties") ||
!strcmp(pName, "vkCreateInstance")
))
{
return 0;
}
RETFUNC(vkCreateInstance);
RETFUNC(vkEnumerateInstanceVersion);
RETFUNC(vkDestroyInstance);
RETFUNC(vkEnumeratePhysicalDevices);
RETFUNC(vkGetPhysicalDeviceFeatures);
RETFUNC(vkGetPhysicalDeviceFormatProperties);
RETFUNC(vkGetPhysicalDeviceImageFormatProperties);
RETFUNC(vkGetPhysicalDeviceProperties);
RETFUNC(vkGetPhysicalDeviceQueueFamilyProperties);
RETFUNC(vkGetPhysicalDeviceMemoryProperties);
RETFUNC(vkGetInstanceProcAddr);
RETFUNC(vkGetDeviceProcAddr);
RETFUNC(vkCreateDevice);
RETFUNC(vkDestroyDevice);
RETFUNC(vkEnumerateInstanceExtensionProperties);
RETFUNC(vkEnumerateDeviceExtensionProperties);
RETFUNC(vkEnumerateInstanceLayerProperties);
RETFUNC(vkEnumerateDeviceLayerProperties);
RETFUNC(vkGetDeviceQueue);
RETFUNC(vkQueueSubmit);
RETFUNC(vkQueueWaitIdle);
RETFUNC(vkDeviceWaitIdle);
RETFUNC(vkAllocateMemory);
RETFUNC(vkFreeMemory);
RETFUNC(vkMapMemory);
RETFUNC(vkUnmapMemory);
RETFUNC(vkFlushMappedMemoryRanges);
RETFUNC(vkInvalidateMappedMemoryRanges);
RETFUNC(vkGetDeviceMemoryCommitment);
RETFUNC(vkBindBufferMemory);
RETFUNC(vkBindImageMemory);
RETFUNC(vkGetBufferMemoryRequirements);
RETFUNC(vkGetImageMemoryRequirements);
RETFUNC(vkGetImageSparseMemoryRequirements);
RETFUNC(vkGetPhysicalDeviceSparseImageFormatProperties);
RETFUNC(vkQueueBindSparse);
RETFUNC(vkCreateFence);
RETFUNC(vkDestroyFence);
RETFUNC(vkResetFences);
RETFUNC(vkGetFenceStatus);
RETFUNC(vkWaitForFences);
RETFUNC(vkCreateSemaphore);
RETFUNC(vkDestroySemaphore);
RETFUNC(vkCreateEvent);
RETFUNC(vkDestroyEvent);
RETFUNC(vkGetEventStatus);
RETFUNC(vkSetEvent);
RETFUNC(vkResetEvent);
RETFUNC(vkCreateQueryPool);
RETFUNC(vkDestroyQueryPool);
RETFUNC(vkGetQueryPoolResults);
RETFUNC(vkCreateBuffer);
RETFUNC(vkDestroyBuffer);
RETFUNC(vkCreateBufferView);
RETFUNC(vkDestroyBufferView);
RETFUNC(vkCreateImage);
RETFUNC(vkDestroyImage);
RETFUNC(vkGetImageSubresourceLayout);
RETFUNC(vkCreateImageView);
RETFUNC(vkDestroyImageView);
RETFUNC(vkCreateShaderModule);
RETFUNC(vkDestroyShaderModule);
RETFUNC(vkCreatePipelineCache);
RETFUNC(vkDestroyPipelineCache);
RETFUNC(vkGetPipelineCacheData);
RETFUNC(vkMergePipelineCaches);
RETFUNC(vkCreateGraphicsPipelines);
RETFUNC(vkCreateComputePipelines);
RETFUNC(vkDestroyPipeline);
RETFUNC(vkCreatePipelineLayout);
RETFUNC(vkDestroyPipelineLayout);
RETFUNC(vkCreateSampler);
RETFUNC(vkDestroySampler);
RETFUNC(vkCreateDescriptorSetLayout);
RETFUNC(vkDestroyDescriptorSetLayout);
RETFUNC(vkCreateDescriptorPool);
RETFUNC(vkDestroyDescriptorPool);
RETFUNC(vkResetDescriptorPool);
RETFUNC(vkAllocateDescriptorSets);
RETFUNC(vkFreeDescriptorSets);
RETFUNC(vkUpdateDescriptorSets);
RETFUNC(vkCreateFramebuffer);
RETFUNC(vkDestroyFramebuffer);
RETFUNC(vkCreateRenderPass);
RETFUNC(vkDestroyRenderPass);
RETFUNC(vkGetRenderAreaGranularity);
RETFUNC(vkCreateCommandPool);
RETFUNC(vkDestroyCommandPool);
RETFUNC(vkResetCommandPool);
RETFUNC(vkAllocateCommandBuffers);
RETFUNC(vkFreeCommandBuffers);
RETFUNC(vkBeginCommandBuffer);
RETFUNC(vkEndCommandBuffer);
RETFUNC(vkResetCommandBuffer);
RETFUNC(vkCmdBindPipeline);
RETFUNC(vkCmdSetViewport);
RETFUNC(vkCmdSetScissor);
RETFUNC(vkCmdSetLineWidth);
RETFUNC(vkCmdSetDepthBias);
RETFUNC(vkCmdSetBlendConstants);
RETFUNC(vkCmdSetDepthBounds);
RETFUNC(vkCmdSetStencilCompareMask);
RETFUNC(vkCmdSetStencilWriteMask);
RETFUNC(vkCmdSetStencilReference);
RETFUNC(vkCmdBindDescriptorSets);
RETFUNC(vkCmdBindIndexBuffer);
RETFUNC(vkCmdBindVertexBuffers);
RETFUNC(vkCmdDraw);
RETFUNC(vkCmdDrawIndexed);
RETFUNC(vkCmdDrawIndirect);
RETFUNC(vkCmdDrawIndexedIndirect);
RETFUNC(vkCmdDispatch);
RETFUNC(vkCmdDispatchIndirect);
RETFUNC(vkCmdCopyBuffer);
RETFUNC(vkCmdCopyImage);
RETFUNC(vkCmdBlitImage);
RETFUNC(vkCmdCopyBufferToImage);
RETFUNC(vkCmdCopyImageToBuffer);
RETFUNC(vkCmdUpdateBuffer);
RETFUNC(vkCmdFillBuffer);
RETFUNC(vkCmdClearColorImage);
RETFUNC(vkCmdClearDepthStencilImage);
RETFUNC(vkCmdClearAttachments);
RETFUNC(vkCmdResolveImage);
RETFUNC(vkCmdSetEvent);
RETFUNC(vkCmdResetEvent);
RETFUNC(vkCmdWaitEvents);
RETFUNC(vkCmdPipelineBarrier);
RETFUNC(vkCmdBeginQuery);
RETFUNC(vkCmdEndQuery);
RETFUNC(vkCmdResetQueryPool);
RETFUNC(vkCmdWriteTimestamp);
RETFUNC(vkCmdCopyQueryPoolResults);
RETFUNC(vkCmdPushConstants);
RETFUNC(vkCmdBeginRenderPass);
RETFUNC(vkCmdNextSubpass);
RETFUNC(vkCmdEndRenderPass);
RETFUNC(vkCmdExecuteCommands);
RETFUNC(vkEnumeratePhysicalDeviceGroups);
RETFUNC(vkGetPhysicalDeviceFeatures2);
RETFUNC(vkGetPhysicalDeviceProperties2);
RETFUNC(vkGetPhysicalDeviceFormatProperties2);
RETFUNC(vkGetPhysicalDeviceImageFormatProperties2);
RETFUNC(vkGetPhysicalDeviceQueueFamilyProperties2);
RETFUNC(vkGetPhysicalDeviceMemoryProperties2);
RETFUNC(vkGetPhysicalDeviceSparseImageFormatProperties2);
RETFUNC(vkGetPhysicalDeviceExternalBufferProperties);
RETFUNC(vkGetPhysicalDeviceExternalFenceProperties);
RETFUNC(vkGetPhysicalDeviceExternalSemaphoreProperties);
2018-11-18 16:11:12 +01:00
RETFUNC(vkBindImageMemory2);
RETFUNC(vkGetDeviceGroupPeerMemoryFeatures);
RETFUNC(vkCmdSetDeviceMask);
RETFUNC(vkCmdDispatchBase);
RETFUNC(vkGetImageMemoryRequirements2);
RETFUNC(vkGetBufferMemoryRequirements2);
RETFUNC(vkGetImageSparseMemoryRequirements2);
RETFUNC(vkTrimCommandPool);
RETFUNC(vkGetDeviceQueue2);
RETFUNC(vkCreateSamplerYcbcrConversion);
RETFUNC(vkDestroySamplerYcbcrConversion);
RETFUNC(vkCreateDescriptorUpdateTemplate);
RETFUNC(vkDestroyDescriptorUpdateTemplate);
RETFUNC(vkUpdateDescriptorSetWithTemplate);
RETFUNC(vkGetDescriptorSetLayoutSupport);
RETFUNC(vkBindBufferMemory2);
RETFUNC(vkDestroySurfaceKHR);
RETFUNC(vkCreateSwapchainKHR);
RETFUNC(vkGetPhysicalDeviceSurfaceSupportKHR);
RETFUNC(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
RETFUNC(vkGetPhysicalDeviceSurfaceFormatsKHR);
RETFUNC(vkGetPhysicalDeviceSurfacePresentModesKHR);
2019-10-01 20:23:52 +02:00
RETFUNC(vkGetSwapchainImagesKHR);
RETFUNC(vkAcquireNextImageKHR);
RETFUNC(vkQueuePresentKHR);
2020-02-23 14:29:01 +01:00
RETFUNC(vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR);
RETFUNC(vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR);
RETFUNC(vkAcquireProfilingLockKHR);
RETFUNC(vkReleaseProfilingLockKHR);
RETFUNC(vkGetPhysicalDeviceDisplayPropertiesKHR);
RETFUNC(vkGetDisplayModePropertiesKHR);
RETFUNC(vkCreateDisplayModeKHR);
2020-04-16 18:33:46 +02:00
RETFUNC(vkCreateDisplayPlaneSurfaceKHR);
RETFUNC(vkGetDisplayPlaneSupportedDisplaysKHR);
RETFUNC(vkGetPhysicalDeviceDisplayPlanePropertiesKHR);
2020-04-17 13:06:41 +02:00
RETFUNC(vkDestroySwapchainKHR);
return 0;
}
2019-04-22 15:58:27 +02:00
2019-09-30 00:52:21 +02:00
VKAPI_ATTR VkResult VKAPI_CALL rpi_vkEnumerateInstanceLayerProperties(
2019-04-22 15:58:27 +02:00
uint32_t* pPropertyCount,
VkLayerProperties* pProperties)
{
2019-09-08 00:30:52 +02:00
//TODO handle layers
2019-04-22 15:58:27 +02:00
return VK_SUCCESS;
}