]> O.S.I.I.S - jp/vkvg.git/commitdiff
build tests in same project to ease sharing of vkh
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Fri, 6 Apr 2018 02:47:10 +0000 (04:47 +0200)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Fri, 6 Apr 2018 02:47:10 +0000 (04:47 +0200)
CMakeLists.txt
include/vkvg.h
src/vkvg_context.c
src/vkvg_context_internal.c
src/vkvg_surface.c
tests/test1.c [new file with mode: 0644]
tests/vke.c [new file with mode: 0644]
tests/vke.h [new file with mode: 0644]
vkh

index 65034540d302996838a870aaf12e47d836cd2a38..fba41991fb889db51697cecd0bee79d443d98f01 100644 (file)
@@ -118,6 +118,7 @@ TARGET_LINK_LIBRARIES(${PROJECT_NAME}
        ${FREETYPE_LIBRARY}
        ${HARFBUZZ_LIBRARIES}
        ${FONTCONFIG_LIBRARIES}
+       vkh_static
 )
 
 CONFIGURE_FILE(vkvg.pc.in vkvg.pc @ONLY)
@@ -126,3 +127,13 @@ INSTALL(TARGETS vkvg
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
 
+ADD_EXECUTABLE(${PROJECT_NAME}_test tests/test1.c)
+TARGET_LINK_LIBRARIES(${PROJECT_NAME}_test
+       ${Vulkan_LIBRARY}
+       ${GLFW3_LIBRARY}
+       ${FREETYPE_LIBRARY}
+       ${HARFBUZZ_LIBRARIES}
+       ${FONTCONFIG_LIBRARIES}
+       vkh_static
+       vkvg
+)
index 635b27dbc067f8e89afb331bce174dfe252e19c4..bb016255baa6000db954d558af0e118727796cea 100644 (file)
@@ -4,7 +4,7 @@
 #include <vulkan/vulkan.h>
 #include <math.h>
 
-#define VKVG_SAMPLES VK_SAMPLE_COUNT_8_BIT
+#define VKVG_SAMPLES VK_SAMPLE_COUNT_4_BIT
 
 typedef enum VkvgDirection {
     VKVG_HORIZONTAL    = 0,
index a5a47e5fa2ebc14e0ba65d5da39379505ebe2ffa..21d3b9caf54ad16b21fdb05be4de06b414f57881 100644 (file)
@@ -493,8 +493,8 @@ void vkvg_set_text_direction (vkvg_context* ctx, VkvgDirection direction){
 }
 
 void vkvg_show_text (VkvgContext ctx, const char* text){
-    _show_text(ctx,text);
-    _record_draw_cmd(ctx);
+    _show_text (ctx, text);
+    _record_draw_cmd (ctx);
 }
 
 void vkvg_save (VkvgContext ctx){
index 779efb8f215c962443c43414e5ad1de1cf8bab3a..e1056fd44983eaae28bfe925d730a6a26afe66a8 100644 (file)
@@ -32,11 +32,11 @@ float _normalizeAngle(float a)
         return res;
 }
 void _create_vertices_buff (VkvgContext ctx){
-    vkvg_buffer_create ((VkhDevice*)ctx->pSurf->dev,
+    vkvg_buffer_create (ctx->pSurf->dev,
         VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
         VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
         ctx->sizeVertices * sizeof(Vertex), &ctx->vertices);
-    vkvg_buffer_create ((VkhDevice*)ctx->pSurf->dev,
+    vkvg_buffer_create (ctx->pSurf->dev,
         VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
         VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
         ctx->sizeIndices * sizeof(uint32_t), &ctx->indices);
@@ -226,9 +226,9 @@ void _update_font_descriptor_set (VkvgContext ctx){
 }
 void _createDescriptorPool (VkvgContext ctx) {
     VkvgDevice dev = ctx->pSurf->dev;
-    VkDescriptorPoolSize descriptorPoolSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 4 };
+    VkDescriptorPoolSize descriptorPoolSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2 };
     VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
-                                                            .maxSets = 4,
+                                                            .maxSets = 2,
                                                             .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
                                                             .poolSizeCount = 1,
                                                             .pPoolSizes = &descriptorPoolSize };
index ef0f9a13a9a58a7ded5ecf2d9fc991f1da881612..4e36af209c120fb5ede2b370b700a5054aead4ca 100644 (file)
@@ -77,7 +77,7 @@ VkImage vkvg_surface_get_vk_image(VkvgSurface surf)
 {
     return vkh_image_get_vkimage (surf->img);
 }
-VkImage vkvg_surface_get_vkh_image(VkvgSurface surf)
+/*VkhImage vkvg_surface_get_vkh_image(VkvgSurface surf)
 {
     return surf->img;
-}
+}*/
diff --git a/tests/test1.c b/tests/test1.c
new file mode 100644 (file)
index 0000000..6d17b5e
--- /dev/null
@@ -0,0 +1,675 @@
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+#include "vke.h"
+//#include "compute.h"
+#include "vkh.h"
+
+#include "vkvg.h"
+
+VkvgDevice device;
+VkvgSurface surf = NULL;
+
+void vke_swapchain_destroy (vkh_presenter* r);
+void vke_swapchain_create (VkEngine* e);
+
+bool vkeCheckPhyPropBlitSource (VkEngine *e) {
+    VkFormatProperties formatProps;
+    vkGetPhysicalDeviceFormatProperties(e->phy, e->renderer.format, &formatProps);
+    assert((formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) && "Format cannot be used as transfer source");
+}
+
+void initPhySurface(VkEngine* e, VkFormat preferedFormat, VkPresentModeKHR presentMode){
+    vkh_presenter* r = &e->renderer;
+
+    uint32_t count;
+    VK_CHECK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR (e->phy, r->surface, &count, NULL));
+    assert (count>0);
+    VkSurfaceFormatKHR formats[count];
+    VK_CHECK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR (e->phy, r->surface, &count, formats));
+
+    for (int i=0; i<count; i++){
+        if (formats[i].format == preferedFormat) {
+            r->format = formats[i].format;
+            r->colorSpace = formats[i].colorSpace;
+            break;
+        }
+    }
+    assert (r->format != VK_FORMAT_UNDEFINED);
+
+    VK_CHECK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(e->phy, r->surface, &count, NULL));
+    assert (count>0);
+    VkPresentModeKHR presentModes[count];
+    VK_CHECK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(e->phy, r->surface, &count, presentModes));
+    r->presentMode = -1;
+    for (int i=0; i<count; i++){
+        if (presentModes[i] == presentMode) {
+            r->presentMode = presentModes[i];
+            break;
+        }
+    }
+    assert (r->presentMode >= 0);
+}
+
+void vke_swapchain_create (VkEngine* e){
+    // Ensure all operations on the device have been finished before destroying resources
+    vkDeviceWaitIdle(e->dev);
+    vkh_presenter* r = &e->renderer;
+
+    VkSurfaceCapabilitiesKHR surfCapabilities;
+    VK_CHECK_RESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(e->phy, r->surface, &surfCapabilities));
+    assert (surfCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT);
+
+
+    // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
+    if (surfCapabilities.currentExtent.width == 0xFFFFFFFF) {
+        // If the surface size is undefined, the size is set to
+        // the size of the images requested
+        if (r->width < surfCapabilities.minImageExtent.width)
+            r->width = surfCapabilities.minImageExtent.width;
+        else if (r->width > surfCapabilities.maxImageExtent.width)
+            r->width = surfCapabilities.maxImageExtent.width;
+        if (r->height < surfCapabilities.minImageExtent.height)
+            r->height = surfCapabilities.minImageExtent.height;
+        else if (r->height > surfCapabilities.maxImageExtent.height)
+            r->height = surfCapabilities.maxImageExtent.height;
+    } else {
+        // If the surface size is defined, the swap chain size must match
+        r->width = surfCapabilities.currentExtent.width;
+        r->height= surfCapabilities.currentExtent.height;
+    }
+
+    VkSwapchainKHR newSwapchain;
+    VkSwapchainCreateInfoKHR createInfo = { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+                                            .surface = r->surface,
+                                            .minImageCount = surfCapabilities.minImageCount,
+                                            .imageFormat = r->format,
+                                            .imageColorSpace = r->colorSpace,
+                                            .imageExtent = {r->width,r->height},
+                                            .imageArrayLayers = 1,
+                                            .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
+                                            .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
+                                            .preTransform = surfCapabilities.currentTransform,
+                                            .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+                                            .presentMode = r->presentMode,
+                                            .clipped = VK_TRUE,
+                                            .oldSwapchain = r->swapChain};
+
+    VK_CHECK_RESULT(vkCreateSwapchainKHR (e->dev, &createInfo, NULL, &newSwapchain));
+    if (r->swapChain != VK_NULL_HANDLE)
+        vke_swapchain_destroy(r);
+    r->swapChain = newSwapchain;
+
+    VK_CHECK_RESULT(vkGetSwapchainImagesKHR(e->dev, r->swapChain, &r->imgCount, NULL));
+    assert (r->imgCount>0);
+
+    VkImage images[r->imgCount];
+    VK_CHECK_RESULT(vkGetSwapchainImagesKHR(e->dev, r->swapChain, &r->imgCount,images));
+
+    r->ScBuffers = (ImageBuffer*)malloc(sizeof(ImageBuffer)*r->imgCount);
+    r->cmdBuffs = (VkCommandBuffer*)malloc(sizeof(VkCommandBuffer)*r->imgCount);
+
+    for (int i=0; i<r->imgCount; i++) {
+        ImageBuffer sc_buffer = {};
+        VkImageViewCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+                                             .image = images[i],
+                                             .viewType = VK_IMAGE_VIEW_TYPE_2D,
+                                             .format = r->format,
+                                             .components = {VK_COMPONENT_SWIZZLE_R,VK_COMPONENT_SWIZZLE_G,VK_COMPONENT_SWIZZLE_B,VK_COMPONENT_SWIZZLE_A},
+                                             .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1}};
+        VK_CHECK_RESULT(vkCreateImageView(e->dev, &createInfo, NULL, &sc_buffer.view));
+        sc_buffer.image = images[i];
+        r->ScBuffers [i] = sc_buffer;
+        r->cmdBuffs [i] = vkh_cmd_buff_create(e->dev, e->renderer.cmdPool,VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+    }
+    r->currentScBufferIndex = 0;
+}
+void vke_swapchain_destroy (vkh_presenter* r){
+    for (uint32_t i = 0; i < r->imgCount; i++)
+    {
+        vkDestroyImageView (r->dev, r->ScBuffers[i].view, NULL);
+        vkFreeCommandBuffers (r->dev, r->cmdPool, 1, &r->cmdBuffs[i]);
+    }
+    vkDestroySwapchainKHR(r->dev, r->swapChain, NULL);
+    free(r->ScBuffers);
+    free(r->cmdBuffs);
+}
+
+VkSampleCountFlagBits getMaxUsableSampleCount(VkSampleCountFlags counts)
+{
+    if (counts & VK_SAMPLE_COUNT_64_BIT) { return VK_SAMPLE_COUNT_64_BIT; }
+    if (counts & VK_SAMPLE_COUNT_32_BIT) { return VK_SAMPLE_COUNT_32_BIT; }
+    if (counts & VK_SAMPLE_COUNT_16_BIT) { return VK_SAMPLE_COUNT_16_BIT; }
+    if (counts & VK_SAMPLE_COUNT_8_BIT) { return VK_SAMPLE_COUNT_8_BIT; }
+    if (counts & VK_SAMPLE_COUNT_4_BIT) { return VK_SAMPLE_COUNT_4_BIT; }
+    if (counts & VK_SAMPLE_COUNT_2_BIT) { return VK_SAMPLE_COUNT_2_BIT; }
+    return VK_SAMPLE_COUNT_1_BIT;
+}
+
+void vkengine_DumpInfos (VkEngine* e){
+    printf("max samples = %d\n", getMaxUsableSampleCount(e->gpu_props.limits.framebufferColorSampleCounts));
+    printf("max tex2d size = %d\n", e->gpu_props.limits.maxImageDimension2D);
+    printf("max tex array layers = %d\n", e->gpu_props.limits.maxImageArrayLayers);
+    printf("max mem alloc count = %d\n", e->gpu_props.limits.maxMemoryAllocationCount);
+
+    for (int i = 0; i < e->memory_properties.memoryHeapCount; i++) {
+        printf("Mem Heap %d\n", i);
+        printf("\tflags= %d\n", e->memory_properties.memoryHeaps[i].flags);
+        printf("\tsize = %d Mo\n", e->memory_properties.memoryHeaps[i].size/ (1024*1024));
+    }
+    for (int i = 0; i < e->memory_properties.memoryTypeCount; i++) {
+        printf("Mem type %d\n", i);
+        printf("\theap %d: ", e->memory_properties.memoryTypes[i].heapIndex);
+        if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
+            printf("VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT|");
+        if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+            printf("VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT|");
+        if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
+            printf("VK_MEMORY_PROPERTY_HOST_COHERENT_BIT|");
+        if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)
+            printf("VK_MEMORY_PROPERTY_HOST_CACHED_BIT|");
+        if (e->memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT)
+            printf("VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT|");
+        printf("\n");
+    }
+}
+void vkengine_get_queues_properties (VkEngine* e, VkQueueFamilyProperties** qFamProps, uint32_t* count){
+    vkGetPhysicalDeviceQueueFamilyProperties (e->phy, count, NULL);
+    (*qFamProps) = (VkQueueFamilyProperties*)malloc((*count) * sizeof(VkQueueFamilyProperties));
+    vkGetPhysicalDeviceQueueFamilyProperties (e->phy, count, (*qFamProps));
+}
+void EngineInit (VkEngine* e) {
+    glfwInit();
+    assert (glfwVulkanSupported()==GLFW_TRUE);
+    e->ExtensionNames = glfwGetRequiredInstanceExtensions (&e->EnabledExtensionsCount);
+
+
+    e->infos.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+    e->infos.pNext = NULL;
+    e->infos.pApplicationName = APP_SHORT_NAME;
+    e->infos.applicationVersion = 1;
+    e->infos.pEngineName = APP_SHORT_NAME;
+    e->infos.engineVersion = 1;
+    e->infos.apiVersion = VK_API_VERSION_1_0;
+    e->renderer.width = 1024;
+    e->renderer.height = 800;
+
+    const uint32_t enabledLayersCount = 1;
+
+    //const char* enabledLayers[] = {"VK_LAYER_LUNARG_core_validation"};
+    const char* enabledExtentions[] = {"VK_KHR_surface", "VK_KHR_swapchain","VK_KHR_xcb_surface"};
+    const char* enabledLayers[] = {"VK_LAYER_LUNARG_standard_validation"};
+
+    VkInstanceCreateInfo inst_info = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+                                       .pNext = NULL,
+                                       .flags = 0,
+                                       .pApplicationInfo = &e->infos,
+                                       .enabledExtensionCount = e->EnabledExtensionsCount,
+                                       .ppEnabledExtensionNames = e->ExtensionNames,
+                                       .enabledLayerCount = 1,
+                                       .ppEnabledLayerNames = enabledLayers };
+
+    VK_CHECK_RESULT(vkCreateInstance (&inst_info, NULL, &e->inst));
+
+    e->phy = vkh_find_phy (e->inst, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU);
+
+    vkGetPhysicalDeviceMemoryProperties (e->phy, &e->memory_properties);
+    vkGetPhysicalDeviceProperties       (e->phy, &e->gpu_props);
+
+    /*VkImageFormatProperties imgProps = {};
+    vkGetPhysicalDeviceImageFormatProperties(e->phy,
+                                             VK_FORMAT_R8_UNORM,
+                                             VK_IMAGE_TYPE_2D,
+                                             VK_IMAGE_TILING_OPTIMAL,
+                                             VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT,
+                                             NULL,&imgProps );*/
+
+    int cQueue = -1, gQueue = -1, tQueue = -1;
+    uint32_t queue_family_count = 0;
+    VkQueueFamilyProperties *qfams;
+    vkengine_get_queues_properties(e,&qfams,&queue_family_count);
+
+    //try to find dedicated queues
+    for (int j=0; j<queue_family_count; j++){
+        switch (qfams[j].queueFlags) {
+        case VK_QUEUE_GRAPHICS_BIT:
+            if (gQueue<0)
+                gQueue = j;
+            break;
+        case VK_QUEUE_COMPUTE_BIT:
+            if (cQueue<0)
+                cQueue = j;
+            break;
+        case VK_QUEUE_TRANSFER_BIT:
+            if (tQueue<0)
+                tQueue = j;
+            break;
+        }
+    }
+    //try to find suitable queue if no dedicated one found
+    for (int j=0; j<queue_family_count; j++){
+        if ((qfams[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) && (gQueue < 0))
+            gQueue = j;
+        if ((qfams[j].queueFlags & VK_QUEUE_COMPUTE_BIT) && (cQueue < 0))
+            cQueue = j;
+        if ((qfams[j].queueFlags & VK_QUEUE_TRANSFER_BIT) && (tQueue < 0))
+            tQueue = j;
+    }
+
+    free (qfams);
+
+    if (gQueue<0||cQueue<0||tQueue<0){
+        fprintf (stderr, "Missing Queue type\n");
+        exit (-1);
+    }
+
+    uint32_t qCount = 0;
+    VkDeviceQueueCreateInfo pQueueInfos[3];
+    float queue_priorities[] = {0.0};
+
+    VkDeviceQueueCreateInfo qiG = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+                                   .queueCount = 1,
+                                   .queueFamilyIndex = gQueue,
+                                   .pQueuePriorities = queue_priorities };
+    VkDeviceQueueCreateInfo qiC = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+                                   .queueCount = 1,
+                                   .queueFamilyIndex = cQueue,
+                                   .pQueuePriorities = queue_priorities };
+    VkDeviceQueueCreateInfo qiT = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+                                   .queueCount = 1,
+                                   .queueFamilyIndex = tQueue,
+                                   .pQueuePriorities = queue_priorities };
+
+    if (gQueue == cQueue){
+        if(gQueue == tQueue){
+            qCount=1;
+            pQueueInfos[0] = qiG;
+        }else{
+            qCount=2;
+            pQueueInfos[0] = qiG;
+            pQueueInfos[1] = qiT;
+        }
+    }else{
+        if((gQueue == tQueue) || (cQueue==tQueue)){
+            qCount=2;
+            pQueueInfos[0] = qiG;
+            pQueueInfos[1] = qiC;
+        }else{
+            qCount=3;
+            pQueueInfos[0] = qiG;
+            pQueueInfos[1] = qiC;
+            pQueueInfos[2] = qiT;
+        }
+    }
+
+    VkDeviceCreateInfo device_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+                                       .queueCreateInfoCount = qCount,
+                                       .pQueueCreateInfos = &pQueueInfos};
+
+    VK_CHECK_RESULT(vkCreateDevice(e->phy, &device_info, NULL, &e->dev));
+
+    assert (glfwGetPhysicalDevicePresentationSupport (e->inst, e->phy, gQueue)==GLFW_TRUE);
+
+    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+    glfwWindowHint(GLFW_RESIZABLE,  GLFW_TRUE);
+    glfwWindowHint(GLFW_FLOATING,   GLFW_FALSE);
+    glfwWindowHint(GLFW_DECORATED,  GLFW_FALSE);
+
+    vkh_presenter* r = &e->renderer;
+    r->dev = e->dev;
+
+    r->window = glfwCreateWindow(r->width, r->height, "Window Title", NULL, NULL);
+
+    assert (glfwCreateWindowSurface(e->inst, r->window, NULL, &r->surface)==VK_SUCCESS);
+
+    VkBool32 isSupported;
+    vkGetPhysicalDeviceSurfaceSupportKHR(e->phy, gQueue, r->surface, &isSupported);
+    assert (isSupported && "vkGetPhysicalDeviceSurfaceSupportKHR");
+
+    vkGetDeviceQueue(e->dev, gQueue, 0, &e->renderer.queue);
+    e->renderer.qFam = gQueue;
+    vkGetDeviceQueue(e->dev, cQueue, 0, &e->computer.queue);
+    vkGetDeviceQueue(e->dev, tQueue, 0, &e->loader.queue);
+
+    e->renderer.cmdPool = vkh_cmd_pool_create (e->dev, gQueue, 0);
+    e->computer.cmdPool = vkh_cmd_pool_create (e->dev, cQueue, 0);
+    e->loader.cmdPool = vkh_cmd_pool_create (e->dev, tQueue, 0);
+
+    r->semaPresentEnd = vkh_semaphore_create(e->dev);
+    r->semaDrawEnd = vkh_semaphore_create(e->dev);
+
+    initPhySurface(e,VK_FORMAT_B8G8R8A8_UNORM,VK_PRESENT_MODE_FIFO_KHR);
+}
+
+void EngineTerminate (VkEngine* e) {
+    vkDeviceWaitIdle(e->dev);
+    vkh_presenter* r = &e->renderer;
+
+    vkDestroySemaphore(e->dev, r->semaDrawEnd, NULL);
+    vkDestroySemaphore(e->dev, r->semaPresentEnd, NULL);
+
+    vkDestroyCommandPool (e->dev, e->renderer.cmdPool, NULL);
+    vkDestroyCommandPool (e->dev, e->computer.cmdPool, NULL);
+    vkDestroyCommandPool (e->dev, e->loader.cmdPool, NULL);
+
+    vkDestroyDevice (e->dev, NULL);
+    vkDestroySurfaceKHR (e->inst, r->surface, NULL);
+    glfwDestroyWindow (r->window);
+    glfwTerminate ();
+
+    vkDestroyInstance (e->inst, NULL);
+}
+
+static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
+    if (action != GLFW_PRESS)
+        return;
+    switch (key) {
+    case GLFW_KEY_ESCAPE :
+        glfwSetWindowShouldClose(window, GLFW_TRUE);
+        break;
+    }
+}
+static void char_callback (GLFWwindow* window, uint32_t c){}
+static void mouse_move_callback(GLFWwindow* window, double x, double y){}
+static void mouse_button_callback(GLFWwindow* window, int but, int state, int modif){}
+
+
+void setupSimpleBlit(vkh_presenter* r){
+    for (int32_t i = 0; i < r->imgCount; ++i)
+    {
+        VkImage bltDstImage = r->ScBuffers[i].image;
+        VkImage bltSrcImage = vkvg_surface_get_vk_image(surf);
+
+        VkCommandBuffer cb = r->cmdBuffs[i];
+        vkh_cmd_begin(cb,VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT);
+
+        set_image_layout(cb, bltDstImage, VK_IMAGE_ASPECT_COLOR_BIT,
+                VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
+
+        set_image_layout(cb, bltSrcImage, VK_IMAGE_ASPECT_COLOR_BIT,
+                VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
+
+        VkImageCopy cregion = { .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
+                                .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
+                                .srcOffset = {},
+                                .dstOffset = {0,0,0},
+                                .extent = {1024,800,1}};
+
+        vkCmdCopyImage(cb, bltSrcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, bltDstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                       1, &cregion);
+
+        set_image_layout(cb, bltDstImage, VK_IMAGE_ASPECT_COLOR_BIT,
+                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+                         VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
+
+        vkh_cmd_end(cb);
+    }
+}
+void submitCommandBuffer(VkQueue queue, VkCommandBuffer *pCmdBuff, VkSemaphore* pWaitSemaphore, VkSemaphore* pSignalSemaphore){
+    VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    VkSubmitInfo submit_info = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+                                 .commandBufferCount = 1,
+                                 .signalSemaphoreCount = 1,
+                                 .pSignalSemaphores = pSignalSemaphore,
+                                 .waitSemaphoreCount = 1,
+                                 .pWaitSemaphores = pWaitSemaphore,
+                                 .pWaitDstStageMask = &dstStageMask,
+                                 .pCommandBuffers = pCmdBuff};
+    VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submit_info, NULL));
+}
+void draw(VkEngine* e) {
+    vkh_presenter* r = &e->renderer;
+    // Get the index of the next available swapchain image:
+    VkResult err = vkAcquireNextImageKHR(e->dev, r->swapChain, UINT64_MAX, r->semaPresentEnd, VK_NULL_HANDLE,
+                                &r->currentScBufferIndex);
+    if ((err == VK_ERROR_OUT_OF_DATE_KHR) || (err == VK_SUBOPTIMAL_KHR)){
+        vke_swapchain_create(e);
+        setupSimpleBlit(r);
+    }else{
+        VK_CHECK_RESULT(err);
+        submitCommandBuffer (r->queue, &r->cmdBuffs[r->currentScBufferIndex], &r->semaPresentEnd, &r->semaDrawEnd);
+
+        /* Now present the image in the window */
+        VkPresentInfoKHR present = { .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
+                                     .swapchainCount = 1,
+                                     .pSwapchains = &r->swapChain,
+                                     .waitSemaphoreCount = 1,
+                                     .pWaitSemaphores = &r->semaDrawEnd,
+                                     .pImageIndices = &r->currentScBufferIndex };
+
+        /* Make sure command buffer is finished before presenting */
+        VK_CHECK_RESULT(vkQueuePresentKHR(r->queue, &present));
+    }
+}
+void vkvg_test_fill(VkvgContext ctx){
+    vkvg_set_rgba(ctx,0.1,0.1,0.8,1.0);
+    vkvg_move_to(ctx,100,100);
+    vkvg_line_to(ctx,400,350);
+    vkvg_line_to(ctx,900,150);
+    vkvg_line_to(ctx,700,450);
+    vkvg_line_to(ctx,900,750);
+    vkvg_line_to(ctx,500,650);
+    vkvg_line_to(ctx,100,800);
+    vkvg_line_to(ctx,150,400);
+    vkvg_close_path(ctx);
+    vkvg_fill(ctx);
+}
+
+void vkvg_rectangle(VkvgContext ctx, float x, float y, float width, float height){
+    vkvg_move_to(ctx,x,y);
+    vkvg_line_to(ctx,x+width,y);
+    vkvg_line_to(ctx,x+width,y+height);
+    vkvg_line_to(ctx,x,y+height);
+    vkvg_close_path(ctx);
+}
+
+void vkvg_test_stroke(VkvgContext ctx){
+    vkvg_set_linewidth(ctx, 2);
+    vkvg_set_rgba(ctx,1,0,0,1);
+    vkvg_move_to(ctx,200.5,200.5);
+    vkvg_line_to(ctx,400.5,200.5);
+    vkvg_line_to(ctx,400.5,400.5);
+    vkvg_line_to(ctx,200.5,400.5);
+    vkvg_close_path(ctx);
+    vkvg_save (ctx);
+    vkvg_stroke_preserve(ctx);
+    vkvg_set_rgba(ctx,0,0.2,0.35,1);
+    vkvg_fill(ctx);
+    vkvg_set_rgba(ctx,0.5,1,0,1);
+    vkvg_move_to(ctx,300.5,300.5);
+    vkvg_line_to(ctx,500.5,300.5);
+    vkvg_line_to(ctx,500.5,500.5);
+    vkvg_line_to(ctx,300.5,500.5);
+    vkvg_close_path(ctx);
+    vkvg_stroke(ctx);
+    vkvg_set_linewidth(ctx, 40);
+    vkvg_restore(ctx);
+    vkvg_set_rgba(ctx,0.5,0.6,1,1.0);
+    vkvg_move_to(ctx,700,475);
+    vkvg_line_to(ctx,400,475);
+    vkvg_stroke(ctx);
+    vkvg_set_rgba(ctx,0,0.5,0.5,0.5);
+    vkvg_move_to(ctx,300,200);
+    vkvg_arc(ctx, 200,200,100,0, M_PI);
+    vkvg_stroke(ctx);
+
+    vkvg_set_linewidth(ctx, 20);
+    vkvg_set_rgba(ctx,0.1,0.1,0.1,0.5);
+    vkvg_move_to(ctx,100,60);
+    vkvg_line_to(ctx,400,600);
+    vkvg_stroke(ctx);
+}
+
+
+
+int main(int argc, char *argv[]) {
+    dumpLayerExts();
+
+    VkEngine e = {};
+
+    EngineInit(&e);
+
+    device = vkvg_device_create(e.phy, e.dev, e.renderer.queue, e.renderer.qFam);
+
+    surf = vkvg_surface_create (device,1024,800);
+
+    vkeCheckPhyPropBlitSource (&e);
+    glfwSetKeyCallback(e.renderer.window, key_callback);
+
+    vke_swapchain_create(&e);
+
+    VkvgSurface surf2 = vkvg_surface_create (device,1024,800);;
+    VkvgContext ctx = vkvg_create(surf2);
+    VkvgContext ctx2 = vkvg_create(surf);
+    vkvg_destroy(ctx2);
+    /*vkvg_destroy(ctx);
+    ctx = vkvg_create(surf);
+    vkvg_destroy(ctx);
+
+
+    ctx = vkvg_create(surf);*/
+    vkvg_set_rgba(ctx,0.5,0,0,1);
+    vkvg_rectangle(ctx,0,0,1024,800);
+    vkvg_fill (ctx);
+
+    vkvg_set_rgba(ctx,1,1,0,1);
+    vkvg_rectangle(ctx,200,200,400,400);
+    vkvg_fill (ctx);
+    vkvg_set_rgba(ctx,0,0,1,1);
+    vkvg_rectangle(ctx,300,300,400,400);
+    vkvg_stroke(ctx);
+    //vkvg_clip_preserve(ctx);
+    //vkvg_clip(ctx);
+    //vkvg_fill_preserve(ctx);
+    //vkvg_set_rgba(ctx,1,0,1,1);
+
+
+    //vkvg_select_font_face(ctx, "/usr/local/share/fonts/DroidSansMono.ttf");
+
+    //vkvg_select_font_face(ctx, "/usr/share/fonts/truetype/unifont/unifont.ttf");
+
+    int size = 19;
+    int penY = 50;
+    int penX = 10;
+
+    /*vkvg_rectangle(ctx,30,0,100,400);
+    vkvg_clip(ctx);*/
+
+    vkvg_set_font_size(ctx,size-10);
+    vkvg_select_font_face(ctx, "droid");
+    vkvg_move_to(ctx, penX,penY);
+    vkvg_set_rgba(ctx,0.7,0.7,0.7,1);
+    vkvg_show_text (ctx,"abcdefghijk");
+    penY+=size;
+
+
+    vkvg_select_font_face(ctx, "times");
+    vkvg_set_rgba(ctx,0.9,0.7,0.7,1);
+    vkvg_move_to(ctx, penX,penY);
+    vkvg_show_text (ctx,"abcdefghijklmnopqrstuvwxyz");
+    penY+=size;
+
+
+
+    vkvg_select_font_face(ctx, "droid");
+    vkvg_move_to(ctx, penX,penY);
+    vkvg_show_text (ctx,"lmnopqrstuvwxyz123456789");
+    penY+=size;
+
+
+
+    vkvg_select_font_face(ctx, "times:bold");
+    vkvg_move_to(ctx, penX,penY);
+    vkvg_show_text (ctx,"abcdefghijklmnopqrstuvwxyz");
+    penY+=size;
+
+
+    vkvg_select_font_face(ctx, "droid");
+    vkvg_move_to(ctx, penX,penY);
+    vkvg_show_text (ctx,"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+    penY+=size;
+
+
+
+    vkvg_select_font_face(ctx, "arial:italic");
+    vkvg_move_to(ctx, penX,penY);
+    vkvg_show_text (ctx,"abcdefghijklmnopqrstuvwxyz");
+    penY+=size;
+
+
+    vkvg_select_font_face(ctx, "arial");
+    vkvg_move_to(ctx, penX,penY);
+    vkvg_show_text (ctx,"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+    penY+=size;
+
+    vkvg_select_font_face(ctx, "mono");
+    vkvg_move_to(ctx, penX,penY);
+    vkvg_show_text (ctx,"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+    penY+=size;
+
+
+    //vkvg_show_text (ctx,"ABCDABCD");
+    //vkvg_show_text (ctx,"j");
+
+    vkvg_test_fill(ctx);
+
+
+    //vkvg_rectangle(ctx,300,300,400,400);
+    //vkvg_clip(ctx);
+
+
+    vkvg_test_stroke(ctx);
+
+    //vkvg_reset_clip(ctx);
+    /*vkvg_set_rgba(ctx,1.0,0.0,0.0,0.1);
+    vkvg_move_to(ctx, 80,400);
+    vkvg_show_text (ctx,"Ленивый рыжий кот");*/
+
+
+    /*vkvg_move_to(ctx, 150,250);
+    vkvg_show_text (ctx,"test string é€");
+    vkvg_move_to(ctx, 150,300);
+    vkvg_show_text (ctx,"كسول الزنجبيل القط");
+    vkvg_move_to(ctx, 150,350);
+    vkvg_show_text (ctx,"懶惰的姜貓");*/
+
+
+    vkvg_destroy(ctx);
+
+    ctx = vkvg_create(surf);
+
+    vkvg_set_rgba(ctx,0.0,0.0,0.3,1);
+    vkvg_paint(ctx);
+
+    vkvg_set_source_surface(ctx, surf2, 0, 0);
+
+    //vkvg_set_rgba(ctx,0.0,1.0,1.0,1);
+    //vkvg_set_rgba(ctx,1.0,1.0,0,1);
+    //vkvg_rectangle(ctx,0,0,400,400);
+
+    //vkvg_fill (ctx);
+    vkvg_paint(ctx);
+
+    vkvg_destroy(ctx);
+
+    setupSimpleBlit(&e.renderer);
+
+    while (!glfwWindowShouldClose(e.renderer.window)) {
+        glfwPollEvents();
+        draw(&e);
+    }
+
+    vkDeviceWaitIdle(e.dev);
+    vke_swapchain_destroy(&e.renderer);
+
+    vkvg_surface_destroy(surf);
+    vkvg_surface_destroy(surf2);
+
+    vkvg_device_destroy(device);
+
+    EngineTerminate (&e);
+
+    return 0;
+}
diff --git a/tests/vke.c b/tests/vke.c
new file mode 100644 (file)
index 0000000..ee03710
--- /dev/null
@@ -0,0 +1,412 @@
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+#include "vke.h"
+#include "compute.h"
+#include "vkhelpers.h"
+#include "vkcrow.h"
+
+
+bool vkeCheckPhyPropBlitSource (VkEngine *e) {
+    VkFormatProperties formatProps;
+    vkGetPhysicalDeviceFormatProperties(e->phy, e->renderer.format, &formatProps);
+    assert((formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) && "Format cannot be used as transfer source");
+}
+
+void initPhySurface(VkEngine* e, VkFormat preferedFormat, VkPresentModeKHR presentMode){
+    vkh_presenter* r = &e->renderer;
+
+    uint32_t count;
+    VK_CHECK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR (e->phy, r->surface, &count, NULL));
+    assert (count>0);
+    VkSurfaceFormatKHR formats[count];
+    VK_CHECK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR (e->phy, r->surface, &count, formats));
+
+    for (int i=0; i<count; i++){
+        if (formats[i].format == preferedFormat) {
+            r->format = formats[i].format;
+            r->colorSpace = formats[i].colorSpace;
+            break;
+        }
+    }
+    assert (r->format != VK_FORMAT_UNDEFINED);
+
+    VK_CHECK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(e->phy, r->surface, &count, NULL));
+    assert (count>0);
+    VkPresentModeKHR presentModes[count];
+    VK_CHECK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(e->phy, r->surface, &count, presentModes));
+    r->presentMode = -1;
+    for (int i=0; i<count; i++){
+        if (presentModes[i] == presentMode) {
+            r->presentMode = presentModes[i];
+            break;
+        }
+    }
+    assert (r->presentMode >= 0);
+}
+
+void createSwapChain (VkEngine* e){
+    // Ensure all operations on the device have been finished before destroying resources
+    vkDeviceWaitIdle(e->dev);
+    vkh_presenter* r = &e->renderer;
+
+    VkSurfaceCapabilitiesKHR surfCapabilities;
+    VK_CHECK_RESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(e->phy, r->surface, &surfCapabilities));
+    assert (surfCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT);
+
+
+    // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
+    if (surfCapabilities.currentExtent.width == 0xFFFFFFFF) {
+        // If the surface size is undefined, the size is set to
+        // the size of the images requested
+        if (r->width < surfCapabilities.minImageExtent.width)
+            r->width = surfCapabilities.minImageExtent.width;
+        else if (r->width > surfCapabilities.maxImageExtent.width)
+            r->width = surfCapabilities.maxImageExtent.width;
+
+        if (r->height < surfCapabilities.minImageExtent.height)
+            r->height = surfCapabilities.minImageExtent.height;
+        else if (r->height > surfCapabilities.maxImageExtent.height)
+            r->height = surfCapabilities.maxImageExtent.height;
+    } else {
+        // If the surface size is defined, the swap chain size must match
+        r->width = surfCapabilities.currentExtent.width;
+        r->height= surfCapabilities.currentExtent.height;
+    }
+
+    VkSwapchainKHR oldSwapchain = r->swapChain;
+    VkSwapchainCreateInfoKHR createInfo = { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+                                            .surface = r->surface,
+                                            .minImageCount = surfCapabilities.minImageCount,
+                                            .imageFormat = r->format,
+                                            .imageColorSpace = r->colorSpace,
+                                            .imageExtent = {r->width,r->height},
+                                            .imageArrayLayers = 1,
+                                            .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
+                                            .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
+                                            .preTransform = surfCapabilities.currentTransform,
+                                            .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+                                            .presentMode = r->presentMode,
+                                            .clipped = VK_TRUE,
+                                            .oldSwapchain = oldSwapchain};
+
+    VK_CHECK_RESULT(vkCreateSwapchainKHR (e->dev, &createInfo, NULL, &r->swapChain));
+
+    if (oldSwapchain != VK_NULL_HANDLE)
+    {
+        for (uint32_t i = 0; i < r->imgCount; i++)
+        {
+            vkDestroyImageView(e->dev, r->ScBuffers[i].view, NULL);
+            vkFreeCommandBuffers (e->dev, e->renderer.cmdPool, 1, &r->cmdBuffs[i]);
+        }
+        vkDestroySwapchainKHR(e->dev, oldSwapchain, NULL);
+        free(r->ScBuffers);
+        free(r->cmdBuffs);
+    }
+
+    VK_CHECK_RESULT(vkGetSwapchainImagesKHR(e->dev, r->swapChain, &r->imgCount, NULL));
+    assert (r->imgCount>0);
+
+    VkImage images[r->imgCount];
+    VK_CHECK_RESULT(vkGetSwapchainImagesKHR(e->dev, r->swapChain, &r->imgCount,images));
+
+    r->ScBuffers = (ImageBuffer*)malloc(sizeof(ImageBuffer)*r->imgCount);
+    r->cmdBuffs = (VkCommandBuffer*)malloc(sizeof(VkCommandBuffer)*r->imgCount);
+
+    for (int i=0; i<r->imgCount; i++) {
+        ImageBuffer sc_buffer;
+
+        VkImageViewCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+                                             .image = images[i],
+                                             .viewType = VK_IMAGE_VIEW_TYPE_2D,
+                                             .format = r->format,
+                                             .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1}};
+        assert (vkCreateImageView(e->dev, &createInfo, NULL, &sc_buffer.view) == VK_SUCCESS);
+        sc_buffer.image = images[i];
+        r->ScBuffers [i] = sc_buffer;
+        r->cmdBuffs [i] = vkh_cmd_buff_create(e->dev, e->renderer.cmdPool);
+    }
+    r->currentScBufferIndex = 0;
+}
+
+void EngineInit (VkEngine* e) {
+    glfwInit();
+    assert (glfwVulkanSupported()==GLFW_TRUE);
+    e->ExtensionNames = glfwGetRequiredInstanceExtensions (&e->EnabledExtensionsCount);
+
+    e->infos.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+    e->infos.pNext = NULL;
+    e->infos.pApplicationName = APP_SHORT_NAME;
+    e->infos.applicationVersion = 1;
+    e->infos.pEngineName = APP_SHORT_NAME;
+    e->infos.engineVersion = 1;
+    e->infos.apiVersion = VK_API_VERSION_1_0;
+    e->renderer.width = 1024;
+    e->renderer.height = 800;
+
+    const uint32_t enabledLayersCount = 1;
+    const char* enabledLayers[] = {"VK_LAYER_LUNARG_core_validation"};
+
+    VkInstanceCreateInfo inst_info = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+                                       .pNext = NULL,
+                                       .flags = 0,
+                                       .pApplicationInfo = &e->infos,
+                                       .enabledExtensionCount = e->EnabledExtensionsCount,
+                                       .ppEnabledExtensionNames = e->ExtensionNames,
+                                       .enabledLayerCount = enabledLayersCount,
+                                       .ppEnabledLayerNames = enabledLayers };
+
+    VK_CHECK_RESULT(vkCreateInstance (&inst_info, NULL, &e->inst));
+
+    e->phy = vkh_find_phy (e->inst, VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU);
+
+    vkGetPhysicalDeviceMemoryProperties(e->phy, &e->memory_properties);
+    vkGetPhysicalDeviceProperties(e->phy, &e->gpu_props);
+
+    uint32_t queue_family_count = 0;
+    int cQueue = -1, gQueue = -1, tQueue = -1;
+    vkGetPhysicalDeviceQueueFamilyProperties (e->phy, &queue_family_count, NULL);
+    VkQueueFamilyProperties qfams[queue_family_count];
+    vkGetPhysicalDeviceQueueFamilyProperties (e->phy, &queue_family_count, &qfams);
+
+    //try to find dedicated queues
+    for (int j=0; j<queue_family_count; j++){
+        switch (qfams[j].queueFlags) {
+        case VK_QUEUE_GRAPHICS_BIT:
+            if (gQueue<0)
+                gQueue = j;
+            break;
+        case VK_QUEUE_COMPUTE_BIT:
+            if (cQueue<0)
+                cQueue = j;
+            break;
+        case VK_QUEUE_TRANSFER_BIT:
+            if (tQueue<0)
+                tQueue = j;
+            break;
+        }
+    }
+    //try to find suitable queue if no dedicated one found
+    for (int j=0; j<queue_family_count; j++){
+        if ((qfams[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) && (gQueue < 0))
+            gQueue = j;
+        if ((qfams[j].queueFlags & VK_QUEUE_COMPUTE_BIT) && (cQueue < 0))
+            cQueue = j;
+        if ((qfams[j].queueFlags & VK_QUEUE_TRANSFER_BIT) && (tQueue < 0))
+            tQueue = j;
+    }
+    if (gQueue<0||cQueue<0||tQueue<0){
+        fprintf (stderr, "Missing Queue type\n");
+        exit (-1);
+    }
+
+    uint32_t qCount = 0;
+    VkDeviceQueueCreateInfo pQueueInfos[3];
+    float queue_priorities[1] = {0.0};
+
+    VkDeviceQueueCreateInfo qiG = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+                                   .queueCount = 1,
+                                   .queueFamilyIndex = gQueue,
+                                   .pQueuePriorities = queue_priorities };
+    VkDeviceQueueCreateInfo qiC = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+                                   .queueCount = 1,
+                                   .queueFamilyIndex = cQueue,
+                                   .pQueuePriorities = queue_priorities };
+    VkDeviceQueueCreateInfo qiT = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+                                   .queueCount = 1,
+                                   .queueFamilyIndex = tQueue,
+                                   .pQueuePriorities = queue_priorities };
+
+    if (gQueue == cQueue){
+        if(gQueue == tQueue){
+            qCount=1;
+            pQueueInfos[0] = qiG;
+        }else{
+            qCount=2;
+            pQueueInfos[0] = qiG;
+            pQueueInfos[1] = qiT;
+        }
+    }else{
+        if((gQueue == tQueue) || (cQueue==tQueue)){
+            qCount=2;
+            pQueueInfos[0] = qiG;
+            pQueueInfos[1] = qiC;
+        }else{
+            qCount=3;
+            pQueueInfos[0] = qiG;
+            pQueueInfos[1] = qiC;
+            pQueueInfos[2] = qiT;
+        }
+    }
+
+    VkDeviceCreateInfo device_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+                                       .queueCreateInfoCount = qCount,
+                                       .pQueueCreateInfos = &pQueueInfos};
+
+    VK_CHECK_RESULT(vkCreateDevice(e->phy, &device_info, NULL, &e->dev));
+
+    assert (glfwGetPhysicalDevicePresentationSupport (e->inst, e->phy, gQueue)==GLFW_TRUE);
+
+    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+    glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
+    glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
+    glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
+
+    vkh_presenter* r = &e->renderer;
+
+    r->window = glfwCreateWindow(r->width, r->height, "Window Title", NULL, NULL);
+
+    assert (glfwCreateWindowSurface(e->inst, r->window, NULL, &r->surface)==VK_SUCCESS);
+
+    VkBool32 isSupported;
+    vkGetPhysicalDeviceSurfaceSupportKHR(e->phy, gQueue, r->surface, &isSupported);
+    assert (isSupported && "vkGetPhysicalDeviceSurfaceSupportKHR");
+
+    vkGetDeviceQueue(e->dev, gQueue, 0, &e->renderer.queue);
+    vkGetDeviceQueue(e->dev, cQueue, 0, &e->computer.queue);
+    vkGetDeviceQueue(e->dev, tQueue, 0, &e->loader.queue);
+
+    e->renderer.cmdPool = vkh_cmd_pool_create (e->dev, gQueue, 0);
+    e->computer.cmdPool = vkh_cmd_pool_create (e->dev, cQueue, 0);
+    e->loader.cmdPool = vkh_cmd_pool_create (e->dev, tQueue, 0);
+
+    r->semaPresentEnd = vkh_semaphore_create(e->dev);
+    r->semaDrawEnd = vkh_semaphore_create(e->dev);
+
+    initPhySurface(e,VK_FORMAT_B8G8R8A8_UNORM,VK_PRESENT_MODE_FIFO_KHR);
+
+    createSwapChain(e);
+}
+void EngineTerminate (VkEngine* e) {
+    vkDeviceWaitIdle(e->dev);
+    vkcrow_terminate();
+    vkh_presenter* r = &e->renderer;
+
+    vkDestroySemaphore(e->dev, r->semaDrawEnd, NULL);
+    vkDestroySemaphore(e->dev, r->semaPresentEnd, NULL);
+
+    for (int i=0; i<r->imgCount; i++){
+        vkDestroyImageView (e->dev, r->ScBuffers[i].view, NULL);
+        vkFreeCommandBuffers (e->dev, r->cmdPool, 1, &r->cmdBuffs[i]);
+    }
+    free (r->ScBuffers);
+    free (r->cmdBuffs);
+
+    vkDestroyCommandPool (e->dev, e->renderer.cmdPool, NULL);
+    vkDestroyCommandPool (e->dev, e->computer.cmdPool, NULL);
+    vkDestroyCommandPool (e->dev, e->loader.cmdPool, NULL);
+
+    vkDestroySwapchainKHR(e->dev, r->swapChain, NULL);
+    vkDestroyDevice (e->dev, NULL);
+    vkDestroySurfaceKHR (e->inst, r->surface, NULL);
+    glfwDestroyWindow (r->window);
+    glfwTerminate ();
+
+    vkDestroyInstance (e->inst, NULL);
+}
+
+static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
+{
+    if (action == GLFW_PRESS){
+        vkcrow_key_up(scancode);
+    }else if (action == GLFW_RELEASE)
+        vkcrow_key_up(scancode);
+
+    if (action != GLFW_PRESS)
+        return;
+    switch (key) {
+    case GLFW_KEY_ESCAPE :
+        glfwSetWindowShouldClose(window, GLFW_TRUE);
+        break;
+    case GLFW_KEY_F3 :
+        vkcrow_load("ifaces/0.crow");
+        break;
+    case GLFW_KEY_F4 :
+        vkcrow_load("ifaces/1.crow");
+        break;
+    case GLFW_KEY_F5 :
+        vkcrow_load("ifaces/2.crow");
+        break;
+    }
+}
+
+static void char_callback (GLFWwindow* window, uint32_t c){
+    vkcrow_key_press(c);
+}
+
+static void mouse_move_callback(GLFWwindow* window, double x, double y){
+    vkcrow_mouse_move((int)x,(int)y);
+}
+static void mouse_button_callback(GLFWwindow* window, int but, int state, int modif){
+    if (state == GLFW_PRESS)
+        vkcrow_mouse_down(but);
+    else
+        vkcrow_mouse_up(but);
+}
+
+
+void buildCommandBuffers(vkh_presenter* r){
+    for (int i=0;i<r->imgCount;i++) {
+        vkcrow_cmd_copy_create(r->cmdBuffs[i],r->ScBuffers[i].image,r->width,r->height);
+    }
+}
+
+
+void draw(VkEngine* e) {
+    vkh_presenter* r = &e->renderer;
+    // Get the index of the next available swapchain image:
+    VkResult err = vkAcquireNextImageKHR(e->dev, r->swapChain, UINT64_MAX, r->semaPresentEnd, VK_NULL_HANDLE,
+                                &r->currentScBufferIndex);
+    if ((err == VK_ERROR_OUT_OF_DATE_KHR) || (err == VK_SUBOPTIMAL_KHR)){
+        createSwapChain(e);
+        vkcrow_resize(e->dev,e->memory_properties,e->renderer.width,e->renderer.height);
+        buildCommandBuffers(r);
+    }else{
+        VK_CHECK_RESULT(err);
+        vkcrow_cmd_copy_submit (r->queue, &r->cmdBuffs[r->currentScBufferIndex], &r->semaPresentEnd, &r->semaDrawEnd);
+
+        /* Now present the image in the window */
+        VkPresentInfoKHR present = { .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
+                                     .swapchainCount = 1,
+                                     .pSwapchains = &r->swapChain,
+                                     .waitSemaphoreCount = 1,
+                                     .pWaitSemaphores = &r->semaDrawEnd,
+                                     .pImageIndices = &r->currentScBufferIndex };
+
+        /* Make sure command buffer is finished before presenting */
+        VK_CHECK_RESULT(vkQueuePresentKHR(r->queue, &present));
+    }
+    vkcrow_buffer_update();
+}
+
+int main(int argc, char *argv[]) {
+    dumpLayerExts();
+
+    VkEngine e = {};
+
+    EngineInit(&e);
+
+    vkcrow_start();
+
+    vkeCheckPhyPropBlitSource (&e);
+
+
+    glfwSetKeyCallback(e.renderer.window, key_callback);
+    glfwSetCharCallback(e.renderer.window, char_callback);
+    glfwSetCursorPosCallback(e.renderer.window, mouse_move_callback);
+    glfwSetMouseButtonCallback(e.renderer.window, mouse_button_callback);
+    //glfwSetWindowSizeCallback(e.renderer.window, win_resize_callback);
+
+    vkcrow_resize(e.dev,e.memory_properties,e.renderer.width,e.renderer.height);
+    buildCommandBuffers(&e.renderer);
+    vkcrow_load("/mnt/devel/gts/libvk/crow/Tests/Interfaces/Divers/0.crow");
+
+    while (!glfwWindowShouldClose(e.renderer.window)) {
+        glfwPollEvents();
+        draw(&e);
+    }
+
+    EngineTerminate (&e);
+
+    return 0;
+}
diff --git a/tests/vke.h b/tests/vke.h
new file mode 100644 (file)
index 0000000..f3c63a4
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef VKE_H
+#define VKE_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdbool.h>
+
+#include <GLFW/glfw3.h>
+#include <vulkan/vulkan.h>
+
+#define APP_SHORT_NAME "vkcrow_test"
+/* Number of samples needs to be the same at image creation,      */
+/* renderpass creation and pipeline creation.                     */
+#define FENCE_TIMEOUT 100000000
+
+//#include "vkh_presenter.h"
+
+typedef struct ImageBuffer_t {
+    VkImage     image;
+    VkImageView view;
+}ImageBuffer;
+
+typedef struct vkh_presenter_t {
+    VkQueue         queue;
+    VkCommandPool   cmdPool;
+    uint32_t        qFam;
+    VkDevice        dev;
+
+    GLFWwindow*     window;
+    VkSurfaceKHR    surface;
+
+    VkSemaphore     semaPresentEnd;
+    VkSemaphore     semaDrawEnd;
+
+    VkFormat        format;
+    VkColorSpaceKHR colorSpace;
+    VkPresentModeKHR presentMode;
+    uint32_t        width;
+    uint32_t        height;
+
+    uint32_t        imgCount;
+    uint32_t        currentScBufferIndex;
+
+    VkRenderPass    renderPass;
+    VkSwapchainKHR  swapChain;
+    ImageBuffer*    ScBuffers;
+    VkCommandBuffer* cmdBuffs;
+    VkFramebuffer*  frameBuffs;
+}vkh_presenter;
+
+typedef struct VkLoader_t {
+    VkQueue queue;
+    VkCommandPool cmdPool;
+}VkLoader;
+
+typedef struct VkComputer_t {
+    VkQueue queue;
+    VkCommandPool cmdPool;
+}VkComputer;
+
+typedef struct VkEngine_t {
+    VkApplicationInfo   infos;
+    VkInstance          inst;
+    VkPhysicalDevice    phy;
+    VkPhysicalDeviceMemoryProperties    memory_properties;
+    VkPhysicalDeviceProperties          gpu_props;
+    VkDevice            dev;
+
+    uint32_t            EnabledExtensionsCount;
+    const char**        ExtensionNames;
+
+    vkh_presenter       renderer;
+    VkComputer          computer;
+    VkLoader            loader;
+}VkEngine;
+#endif
diff --git a/vkh b/vkh
index cd9a5d1cc4891788e4e9e52b170d539b077e9c1f..e5333027ccbb7bb1c1e11e1164329530eac1da96 160000 (submodule)
--- a/vkh
+++ b/vkh
@@ -1 +1 @@
-Subproject commit cd9a5d1cc4891788e4e9e52b170d539b077e9c1f
+Subproject commit e5333027ccbb7bb1c1e11e1164329530eac1da96