]> O.S.I.I.S - jp/vkvg.git/commitdiff
add curve debug facility, measure frame rate CurvesDebug
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Sun, 29 Apr 2018 01:54:29 +0000 (03:54 +0200)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Mon, 16 Jul 2018 12:22:37 +0000 (14:22 +0200)
13 files changed:
CMakeLists.txt
logo.png [new file with mode: 0644]
src/vkvg_context.c
src/vkvg_context_internal.c
src/vkvg_context_internal.h
tests/cairo-tests.h [new file with mode: 0644]
tests/common/vkengine.c [new file with mode: 0644]
tests/common/vkengine.h [new file with mode: 0644]
tests/perf-test.h [new file with mode: 0644]
tests/perf_test_0.c [new file with mode: 0644]
tests/test_curves.c [new file with mode: 0644]
tests/vkengine.c [deleted file]
tests/vkengine.h [deleted file]

index e7a29e2204461b677b49edd7a2489acc690e12f0..99cae96a936cf014eb0f5c21ee69b9a6b78e5fcc 100644 (file)
@@ -16,6 +16,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
 ENDIF()
 
 OPTION(VKVG_BUILD_TESTS "build tests with glfw" ON)
+SET(CAIRO_INCLUDE_DIRECTORY "/usr/include/cairo" CACHE STRING "CAIRO include directory")
 
 set(VULKAN_SDK "$ENV{VULKAN_SDK}" CACHE STRING "LunarG Vulkan SDK path")
 if (VULKAN_SDK)
@@ -140,20 +141,30 @@ INSTALL(TARGETS vkvg
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
 
-if (GLFW3_FOUND)
-       #build test app
-       ADD_EXECUTABLE(${PROJECT_NAME}_test tests/test1.c tests/vkengine.c)
-       TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME}_test PRIVATE
-               ${Vulkan_INCLUDE_DIRS}
-               ${CMAKE_CURRENT_SOURCE_DIR}/include
-               ${CMAKE_CURRENT_SOURCE_DIR}/src
-               ${CMAKE_CURRENT_SOURCE_DIR}/vkh/include
-               ${CMAKE_CURRENT_SOURCE_DIR}/vkh/src
-       )
-       TARGET_LINK_LIBRARIES(${PROJECT_NAME}_test
-               ${Vulkan_LIBRARIES}
-               ${GLFW3_LIBRARY}
-               vkh_static
-               vkvg
-       )
+if (GLFW3_FOUND AND VKVG_BUILD_TESTS)
+       #build test apps
+       FILE(GLOB TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} tests/*.c)
+       FOREACH(TEST_FILE ${TESTS})
+               GET_FILENAME_COMPONENT(TEST_NAME ${TEST_FILE} NAME_WE)
+               ADD_EXECUTABLE(${PROJECT_NAME}_${TEST_NAME} ${TEST_FILE} tests/common/vkengine.c)
+               TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME}_${TEST_NAME} PRIVATE
+                       ${CAIRO_INCLUDE_DIRECTORY}
+                       ${Vulkan_INCLUDE_DIRS}
+                       ${CMAKE_CURRENT_SOURCE_DIR}/include
+                       ${CMAKE_CURRENT_SOURCE_DIR}/src
+                       ${CMAKE_CURRENT_SOURCE_DIR}/tests/common/
+                       ${CMAKE_CURRENT_SOURCE_DIR}/vkh/include
+                       ${CMAKE_CURRENT_SOURCE_DIR}/vkh/src
+
+                       ${FREETYPE_INCLUDE_DIRS}
+                       ${HARFBUZZ_INCLUDE_DIRS}
+                       ${FONTCONFIG_INCLUDE_DIR}
+               )
+               TARGET_LINK_LIBRARIES(${PROJECT_NAME}_${TEST_NAME}
+                       ${Vulkan_LIBRARIES}
+                       ${GLFW3_LIBRARY}
+                       vkh_static
+                       vkvg
+               )
+       ENDFOREACH()
 endif ()
diff --git a/logo.png b/logo.png
new file mode 100644 (file)
index 0000000..84fd6f6
Binary files /dev/null and b/logo.png differ
index 99ebcf9de874174115d7523e2d002776d147a067..6bdf6ed6c06dbcff6a3ddffd8d84bd0d79f5c7e4 100644 (file)
@@ -31,6 +31,16 @@ static vec2 debugLinePoints[1000];
 static uint32_t dlpCount = 0;
 #endif
 
+void _init_debug_curves (VkvgContext ctx) {
+    ctx->m_approximation_scale = 1.0;
+    ctx->m_angle_tolerance = 0.05;
+    ctx->m_distance_tolerance = 0.1;
+    ctx->m_cusp_limit = 0.25;
+    ctx->curve_recursion_limit = 16;
+    ctx->curve_collinearity_epsilon = 0.001;
+    ctx->curve_angle_tolerance_epsilon = 0.1;
+}
+
 VkvgContext vkvg_create(VkvgSurface surf)
 {
     LOG(LOG_INFO, "CREATE Context: surf = %lu\n", surf);
@@ -89,6 +99,8 @@ VkvgContext vkvg_create(VkvgSurface surf)
 
     ctx->references = 1;
 
+    _init_debug_curves      (ctx);
+
     return ctx;
 }
 void vkvg_flush (VkvgContext ctx){
index 18ba7583655378e70171117c050a3a011c0271fe..b3ca6de8bde2eae48661bb365d1a3f4d827c3199 100644 (file)
@@ -187,7 +187,7 @@ void _record_draw_cmd (VkvgContext ctx){
     //DEBUG
     /*vkCmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineWired);
     vkCmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, 0, 1);
-    vkCmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipe_OVER);*/
+    _bind_draw_pipeline(ctx);*/
     //////////
 
     ctx->curIndStart = ctx->indCount;
@@ -522,6 +522,9 @@ void _build_vb_step (vkvg_context* ctx, Vertex v, float hw, uint32_t iL, uint32_
     vec2 v0n = vec2_line_norm(ctx->points[iL], ctx->points[i]);
     vec2 v1n = vec2_line_norm(ctx->points[i], ctx->points[iR]);
 
+    if (vec2_equ(v0n,v1n))
+        return;
+
     vec2 bisec = vec2_norm(vec2_add(v0n,v1n));
 
     float alpha = acos(v0n.x * v1n.x + v0n.y * v1n.y)/2;
@@ -635,7 +638,7 @@ void _free_ctx_save (vkvg_context_save_t* sav){
     free (sav);
 }
 
-
+/*
 #define m_approximation_scale   1.0
 #define m_angle_tolerance       0.01
 #define m_distance_tolerance    1.0
@@ -643,12 +646,12 @@ void _free_ctx_save (vkvg_context_save_t* sav){
 #define curve_recursion_limit   10
 #define curve_collinearity_epsilon 1.7
 #define curve_angle_tolerance_epsilon 0.001
-
+*/
 void _recursive_bezier (VkvgContext ctx,
                         float x1, float y1, float x2, float y2,
                         float x3, float y3, float x4, float y4,
                         unsigned level) {
-    if(level > curve_recursion_limit)
+    if(level > ctx->curve_recursion_limit)
     {
         return;
     }
@@ -680,16 +683,16 @@ void _recursive_bezier (VkvgContext ctx,
 
         float da1, da2;
 
-        if(d2 > curve_collinearity_epsilon && d3 > curve_collinearity_epsilon)
+        if(d2 > ctx->curve_collinearity_epsilon && d3 > ctx->curve_collinearity_epsilon)
         {
             // Regular care
             //-----------------
-            if((d2 + d3)*(d2 + d3) <= m_distance_tolerance * (dx*dx + dy*dy))
+            if((d2 + d3)*(d2 + d3) <= ctx->m_distance_tolerance * (dx*dx + dy*dy))
             {
                 // If the curvature doesn't exceed the distance_tolerance value
                 // we tend to finish subdivisions.
                 //----------------------
-                if(m_angle_tolerance < curve_angle_tolerance_epsilon)
+                if(ctx->m_angle_tolerance < ctx->curve_angle_tolerance_epsilon)
                 {
                     _add_point (ctx, x1234, y1234);
                     return;
@@ -703,7 +706,7 @@ void _recursive_bezier (VkvgContext ctx,
                 if(da1 >= M_PI) da1 = M_2_PI - da1;
                 if(da2 >= M_PI) da2 = M_2_PI - da2;
 
-                if(da1 + da2 < m_angle_tolerance)
+                if(da1 + da2 < ctx->m_angle_tolerance)
                 {
                     // Finally we can stop the recursion
                     //----------------------
@@ -711,15 +714,15 @@ void _recursive_bezier (VkvgContext ctx,
                     return;
                 }
 
-                if(m_cusp_limit != 0.0)
+                if(ctx->m_cusp_limit != 0.0)
                 {
-                    if(da1 > m_cusp_limit)
+                    if(da1 > ctx->m_cusp_limit)
                     {
                         _add_point (ctx, x2, y2);
                         return;
                     }
 
-                    if(da2 > m_cusp_limit)
+                    if(da2 > ctx->m_cusp_limit)
                     {
                         _add_point (ctx, x3, y3);
                         return;
@@ -727,13 +730,13 @@ void _recursive_bezier (VkvgContext ctx,
                 }
             }
         } else {
-            if(d2 > curve_collinearity_epsilon)
+            if(d2 > ctx->curve_collinearity_epsilon)
             {
                 // p1,p3,p4 are collinear, p2 is considerable
                 //----------------------
-                if(d2 * d2 <= m_distance_tolerance * (dx*dx + dy*dy))
+                if(d2 * d2 <= ctx->m_distance_tolerance * (dx*dx + dy*dy))
                 {
-                    if(m_angle_tolerance < curve_angle_tolerance_epsilon)
+                    if(ctx->m_angle_tolerance < ctx->curve_angle_tolerance_epsilon)
                     {
                         _add_point (ctx, x1234, y1234);
                         return;
@@ -744,28 +747,28 @@ void _recursive_bezier (VkvgContext ctx,
                     da1 = fabs(atan2(y3 - y2, x3 - x2) - atan2(y2 - y1, x2 - x1));
                     if(da1 >= M_PI) da1 = M_2_PI - da1;
 
-                    if(da1 < m_angle_tolerance)
+                    if(da1 < ctx->m_angle_tolerance)
                     {
                         _add_point (ctx, x2, y2);
                         _add_point (ctx, x3, y3);
                         return;
                     }
 
-                    if(m_cusp_limit != 0.0)
+                    if(ctx->m_cusp_limit != 0.0)
                     {
-                        if(da1 > m_cusp_limit)
+                        if(da1 > ctx->m_cusp_limit)
                         {
                             _add_point (ctx, x2, y2);
                             return;
                         }
                     }
                 }
-            } else if(d3 > curve_collinearity_epsilon) {
+            } else if(d3 > ctx->curve_collinearity_epsilon) {
                 // p1,p2,p4 are collinear, p3 is considerable
                 //----------------------
-                if(d3 * d3 <= m_distance_tolerance * (dx*dx + dy*dy))
+                if(d3 * d3 <= ctx->m_distance_tolerance * (dx*dx + dy*dy))
                 {
-                    if(m_angle_tolerance < curve_angle_tolerance_epsilon)
+                    if(ctx->m_angle_tolerance < ctx->curve_angle_tolerance_epsilon)
                     {
                         _add_point (ctx, x1234, y1234);
                         return;
@@ -776,16 +779,16 @@ void _recursive_bezier (VkvgContext ctx,
                     da1 = fabs(atan2(y4 - y3, x4 - x3) - atan2(y3 - y2, x3 - x2));
                     if(da1 >= M_PI) da1 = M_2_PI - da1;
 
-                    if(da1 < m_angle_tolerance)
+                    if(da1 < ctx->m_angle_tolerance)
                     {
                         _add_point (ctx, x2, y2);
                         _add_point (ctx, x3, y3);
                         return;
                     }
 
-                    if(m_cusp_limit != 0.0)
+                    if(ctx->m_cusp_limit != 0.0)
                     {
-                        if(da1 > m_cusp_limit)
+                        if(da1 > ctx->m_cusp_limit)
                         {
                             _add_point (ctx, x3, y3);
                             return;
@@ -799,7 +802,7 @@ void _recursive_bezier (VkvgContext ctx,
                 //-----------------
                 dx = x1234 - (x1 + x4) / 2;
                 dy = y1234 - (y1 + y4) / 2;
-                if(dx*dx + dy*dy <= m_distance_tolerance)
+                if(dx*dx + dy*dy <= ctx->m_distance_tolerance)
                 {
                     _add_point (ctx, x1234, y1234);
                     return;
index e0282d703fcbbb91b5acf6b54d0b3cebdde5cece..0ab0e426aef300fb5a39eb69d21458383bf29a57 100644 (file)
@@ -28,7 +28,7 @@
 #include "vkh.h"
 #include "vkvg_fonts.h"
 
-#define VKVG_PTS_SIZE                          16384
+#define VKVG_PTS_SIZE                          32768
 #define VKVG_VBO_SIZE                          VKVG_PTS_SIZE * 2
 #define VKVG_IBO_SIZE                          VKVG_VBO_SIZE * 2
 #define VKVG_PATHES_SIZE                       256
@@ -137,6 +137,14 @@ typedef struct _vkvg_context_t {
     vkvg_context_save_t* pSavedCtxs;//last ctx saved ptr
 
     VkClearRect         clearRect;
+    //debug curves
+    float m_approximation_scale;
+    float m_angle_tolerance;
+    float m_distance_tolerance;
+    float m_cusp_limit;
+    float curve_recursion_limit;
+    float curve_collinearity_epsilon;
+    float curve_angle_tolerance_epsilon;
 }vkvg_context;
 
 bool _current_path_is_empty (VkvgContext ctx);
diff --git a/tests/cairo-tests.h b/tests/cairo-tests.h
new file mode 100644 (file)
index 0000000..67fdb98
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef CAIROTESTS_H
+#define CAIROTESTS_H
+
+#include "cairo.h"
+
+void* createContext() {
+
+    cairo_create();
+}
+
+#endif // CAIROTESTS_H
diff --git a/tests/common/vkengine.c b/tests/common/vkengine.c
new file mode 100644 (file)
index 0000000..e4f04fb
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2018 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vkh.h"
+#include "vkengine.h"
+#include "vkh_app.h"
+#include "vkh_phyinfo.h"
+#include "vkh_presenter.h"
+#include "vkh_image.h"
+#include "vkh_device.h"
+
+bool vkeCheckPhyPropBlitSource (VkEngine e) {
+    VkFormatProperties formatProps;
+    vkGetPhysicalDeviceFormatProperties(e->dev->phy, e->renderer->format, &formatProps);
+    assert((formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) && "Format cannot be used as transfer source");
+}
+
+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_dump_Infos (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");
+    }
+}
+vk_engine_t* vkengine_create (VkPhysicalDeviceType preferedGPU, uint32_t width, uint32_t height) {
+    vk_engine_t* e = (vk_engine_t*)calloc(1,sizeof(vk_engine_t));
+
+    glfwInit();
+    assert (glfwVulkanSupported()==GLFW_TRUE);
+
+    uint32_t enabledExtsCount = 0, phyCount = 0;
+    const char ** enabledExts = glfwGetRequiredInstanceExtensions (&enabledExtsCount);
+
+    e->app = vkh_app_create("vkvgTest", enabledExtsCount, enabledExts);
+
+    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+    glfwWindowHint(GLFW_RESIZABLE,  GLFW_TRUE);
+    glfwWindowHint(GLFW_FLOATING,   GLFW_FALSE);
+    glfwWindowHint(GLFW_DECORATED,  GLFW_FALSE);
+
+    e->window = glfwCreateWindow (width, height, "Window Title", NULL, NULL);
+    VkSurfaceKHR surf;
+
+    assert (glfwCreateWindowSurface(e->app->inst, e->window, NULL, &surf)==VK_SUCCESS);
+
+
+    VkhPhyInfo* phys = vkh_app_get_phyinfos (e->app, &phyCount, surf);
+
+    VkhPhyInfo pi = NULL;
+    for (int i=0; i<phyCount; i++){
+        pi = phys[i];
+        if (pi->properties.deviceType == preferedGPU)
+            break;
+    }
+
+    e->memory_properties = pi->memProps;
+    e->gpu_props = pi->properties;
+
+    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 = pi->gQueue,
+                                   .pQueuePriorities = queue_priorities };
+    VkDeviceQueueCreateInfo qiC = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+                                   .queueCount = 1,
+                                   .queueFamilyIndex = pi->cQueue,
+                                   .pQueuePriorities = queue_priorities };
+    VkDeviceQueueCreateInfo qiT = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+                                   .queueCount = 1,
+                                   .queueFamilyIndex = pi->tQueue,
+                                   .pQueuePriorities = queue_priorities };
+
+    if (pi->gQueue == pi->cQueue){
+        if(pi->gQueue == pi->tQueue){
+            qCount=1;
+            pQueueInfos[0] = qiG;
+        }else{
+            qCount=2;
+            pQueueInfos[0] = qiG;
+            pQueueInfos[1] = qiT;
+        }
+    }else{
+        if((pi->gQueue == pi->tQueue) || (pi->cQueue==pi->tQueue)){
+            qCount=2;
+            pQueueInfos[0] = qiG;
+            pQueueInfos[1] = qiC;
+        }else{
+            qCount=3;
+            pQueueInfos[0] = qiG;
+            pQueueInfos[1] = qiC;
+            pQueueInfos[2] = qiT;
+        }
+    }
+
+    char const * dex [] = {"VK_KHR_swapchain"};
+/*#if DEBUG
+    uint32_t dlayCpt = 1;
+    static char const * dlay [] = {"VK_LAYER_LUNARG_standard_validation"};
+#else*/
+    uint32_t dlayCpt = 0;
+    static char const * dlay [] = {};
+//#endif
+    VkPhysicalDeviceFeatures enabledFeatures = {
+        .fillModeNonSolid = true,
+    };
+
+    VkDeviceCreateInfo device_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+                                       .queueCreateInfoCount = qCount,
+                                       .pQueueCreateInfos = &pQueueInfos,
+                                       .enabledLayerCount = dlayCpt,
+                                       .ppEnabledLayerNames = dlay,
+                                       .enabledExtensionCount = 1,
+                                       .ppEnabledExtensionNames = dex,
+                                       .pEnabledFeatures = &enabledFeatures
+                                     };
+
+    VkDevice dev;
+    VK_CHECK_RESULT(vkCreateDevice (pi->phy, &device_info, NULL, &dev));
+    e->dev = vkh_device_create(pi->phy, dev);
+
+    e->renderer = vkh_presenter_create
+            (e->dev, pi->pQueue, surf, width, height, VK_FORMAT_B8G8R8A8_UNORM, VK_PRESENT_MODE_FIFO_KHR);
+
+
+    vkh_app_free_phyinfos (phyCount, phys);
+
+    return e;
+}
+
+void vkengine_destroy (VkEngine e) {
+    vkDeviceWaitIdle(e->dev->dev);
+
+    VkSurfaceKHR surf = e->renderer->surface;
+
+    vkh_presenter_destroy (e->renderer);
+    vkDestroySurfaceKHR (e->app->inst, surf, NULL);
+
+    vkDestroyDevice (e->dev->dev, NULL);
+
+    glfwDestroyWindow (e->window);
+    glfwTerminate ();
+
+    vkh_app_destroy (e->app);
+
+    free(e);
+}
+void vkengine_close (VkEngine e) {
+    glfwSetWindowShouldClose(e->window, GLFW_TRUE);
+}
+void vkengine_blitter_run (VkEngine e, VkImage img) {
+    VkhPresenter p = e->renderer;
+    vkh_presenter_build_blit_cmd (p, img);
+
+    while (!vkengine_should_close (e)) {
+        glfwPollEvents();
+        if (!vkh_presenter_draw (p))
+            vkh_presenter_build_blit_cmd (p, img);
+    }
+}
+inline bool vkengine_should_close (VkEngine e) {
+    return glfwWindowShouldClose (e->window);
+}
+
+VkDevice vkengine_get_device (VkEngine e){
+    return e->dev->dev;
+}
+VkPhysicalDevice vkengine_get_physical_device (VkEngine e){
+    return e->dev->phy;
+}
+VkQueue vkengine_get_queue (VkEngine e){
+    return e->renderer->queue;
+}
+uint32_t vkengine_get_queue_fam_idx (VkEngine e){
+    return e->renderer->qFam;
+}
+
+void vkengine_set_key_callback (VkEngine e, GLFWkeyfun key_callback){
+    glfwSetKeyCallback (e->window, key_callback);
+}
+void vkengine_set_mouse_but_callback (VkEngine e, GLFWmousebuttonfun onMouseBut){
+    glfwSetMouseButtonCallback(e->window, onMouseBut);
+}
+void vkengine_set_cursor_pos_callback (VkEngine e, GLFWcursorposfun onMouseMove){
+    glfwSetCursorPosCallback(e->window, onMouseMove);
+}
+void vkengine_set_scroll_callback (VkEngine e, GLFWscrollfun onScroll){
+    glfwSetScrollCallback(e->window, onScroll);
+}
+void vkengine_set_char_callback (VkEngine e, GLFWcharfun onChar){
+    glfwSetCharCallback(e->window, onChar);
+}
+
diff --git a/tests/common/vkengine.h b/tests/common/vkengine.h
new file mode 100644 (file)
index 0000000..1bf33a8
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef VKENGINE_H
+#define VKENGINE_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdbool.h>
+
+#include <GLFW/glfw3.h>
+#include <vulkan/vulkan.h>
+
+#include "vkh.h"
+
+/* Number of samples needs to be the same at image creation,      */
+/* renderpass creation and pipeline creation.                     */
+#define FENCE_TIMEOUT 100000000
+
+typedef struct _vk_engine_t* VkEngine;
+
+typedef struct _vk_engine_t {
+    VkhApp              app;
+    VkPhysicalDeviceMemoryProperties    memory_properties;
+    VkPhysicalDeviceProperties          gpu_props;
+    VkhDevice           dev;
+    GLFWwindow*         window;
+    VkhPresenter        renderer;
+}vk_engine_t;
+
+vk_engine_t*   vkengine_create  (VkPhysicalDeviceType preferedGPU, uint32_t width, uint32_t height);
+
+void vkengine_destroy       (VkEngine e);
+bool vkengine_should_close  (VkEngine e);
+void vkengine_close         (VkEngine e);
+void vkengine_dump_Infos    (VkEngine e);
+VkDevice            vkengine_get_device         (VkEngine e);
+VkPhysicalDevice    vkengine_get_physical_device(VkEngine e);
+VkQueue             vkengine_get_queue          (VkEngine e);
+uint32_t            vkengine_get_queue_fam_idx  (VkEngine e);
+
+void vkengine_get_queues_properties (vk_engine_t* e, VkQueueFamilyProperties** qFamProps, uint32_t* count);
+
+void vkengine_set_key_callback          (VkEngine e, GLFWkeyfun key_callback);
+void vkengine_set_mouse_but_callback    (VkEngine e, GLFWmousebuttonfun onMouseBut);
+void vkengine_set_cursor_pos_callback   (VkEngine e, GLFWcursorposfun onMouseMove);
+void vkengine_set_scroll_callback       (VkEngine e, GLFWscrollfun onScroll);
+void vkengine_set_char_callback         (VkEngine e, GLFWcharfun onChar);
+#endif
diff --git a/tests/perf-test.h b/tests/perf-test.h
new file mode 100644 (file)
index 0000000..3df035d
--- /dev/null
@@ -0,0 +1,172 @@
+#ifndef PERFTEST_H
+#define PERFTEST_H
+
+#include "vkvg.h"
+#include <stdlib.h>
+#include <float.h>
+
+enum DrawMode {
+    DM_FILL = 0x1,
+    DM_STROKE = 0x2,
+    DM_BOTH = 0x3
+};
+
+typedef struct _results {
+    double run_min;
+    double run_max;
+    double avg_time;
+    double median_time;
+    double std_deriv;
+} results_t;
+
+results_t initResults () {
+    results_t res = {};
+    res.run_min = DBL_MAX;
+    res.run_max = DBL_MIN;
+    return res;
+}
+
+typedef struct _options {
+    char*       test_name;
+    int         iterations;
+    int         count;
+    int         width;
+    int         height;
+    enum DrawMode    drawMode;
+} options_t;
+
+options_t initOptions (int argc, char *argv[]) {
+    options_t opt = {};
+    opt.iterations = 100;
+    opt.count = 1000;
+    opt.width = 1024;
+    opt.height = 800;
+    opt.drawMode = DM_FILL;
+
+    for (int i = 1; i < argc; i++) {
+        if (argv[i][0] == '-') {
+            switch (argv[i][1]) {
+            case 'w':
+                sscanf (argv[++i], "%d", &opt.width);
+                break;
+            case 'h':
+                sscanf (argv[++i], "%d", &opt.height);
+                break;
+            case 'i':
+                sscanf (argv[++i], "%d", &opt.iterations);
+                break;
+            case 'c':
+                sscanf (argv[++i], "%d", &opt.count);
+                break;
+            case 'f':
+                opt.drawMode = DM_FILL;
+                break;
+            case 's':
+                opt.drawMode = DM_STROKE;
+                break;
+            case 'b':
+                opt.drawMode = DM_BOTH;
+                break;
+            default:
+                break;
+            }
+        }
+    }
+    return opt;
+}
+
+
+void printHelp () {
+    printf ("\t-w x : Set test surface width.\n");
+    printf ("\t-h x : Set test surface height.\n");
+    printf ("\t-i x : Set iterations count.\n");
+    printf ("\t-c x : Set shape occurence count.\n");
+    printf ("\t-f :   Set shape draw mode to fill.\n");
+    printf ("\t-s :   Set shape draw mode to stroke.\n");
+    printf ("\t-b :   Set shape draw mode to fill and stroke.\n");
+}
+void outputResultsHeadRow (options_t* opt) {
+    printf ("__________________________________________________________________________________________________________\n");
+    printf ("| Test Name       | Iter | Cpt  | Resolution  |DM |   Min    |   Max    |  Average |  Median  | Std Deriv|\n");
+    printf ("|-----------------|------|------|-------------|---|----------|----------|----------|----------|----------|\n");
+}
+void outputResultsOnOneLine (options_t* opt, results_t* res) {
+    printf ("| %.15s | %4d | %4d | %4d x %4d | ",
+            opt->test_name, opt->iterations, opt->count, opt->width, opt->height);
+    switch (opt->drawMode) {
+    case DM_BOTH:
+        printf ("B | ");
+        break;
+    case DM_FILL:
+        printf ("F | ");
+        break;
+    case DM_STROKE:
+        printf ("S | ");
+        break;
+    }
+    printf ("%.6f | %.6f | %.6f | %.6f | %.6f |",
+            res->run_min, res->run_max, res->avg_time, res->median_time, res->std_deriv);
+}
+
+void outputResults (options_t* opt, results_t* res) {
+    printf ("Test name: %s\n", opt->test_name);
+    printf ("\nOptions\n");
+    printf ("=======\n");
+    printf ("Iterations  = %d\n", opt->iterations);
+    printf ("Shape count = %d\n", opt->count);
+    printf ("Canva size  = %d x %d\n", opt->width, opt->height);
+    switch (opt->drawMode) {
+    case DM_BOTH:
+        printf ("Draw Mode   = FILL and STROKE\n");
+        break;
+    case DM_FILL:
+        printf ("Draw Mode   = FILL\n");
+        break;
+    case DM_STROKE:
+        printf ("Draw Mode   = STROKE\n");
+        break;
+    }
+    printf ("\nResults\n");
+    printf ("=======\n");
+    printf ("Minimum = %f (sec)\n", res->run_min);
+    printf ("Maximum = %f (sec)\n", res->run_max);
+    printf ("Average = %f (sec)\n", res->avg_time);
+    printf ("Median  = %f (sec)\n", res->median_time);
+    printf ("Std reriv = %f \n", res->std_deriv);
+}
+
+double get_tick (void)
+{
+    struct timeval now;
+    gettimeofday (&now, NULL);
+    return (double)now.tv_sec + (double)now.tv_usec / 1000000.0;
+}
+double median_run_time (double data[], int n)
+{
+    double temp;
+    int i, j;
+    for (i = 0; i < n; i++)
+        for (j = i+1; j < n; j++)
+        {
+            if (data[i] > data[j])
+            {
+                temp = data[j];
+                data[j] = data[i];
+                data[i] = temp;
+            }
+        }
+    if (n % 2 == 0)
+        return (data[n/2] + data[n/2-1])/2;
+    else
+        return data[n/2];
+}
+double standard_deviation (const double data[], int n, double mean)
+{
+    double sum_deviation = 0.0;
+    int i;
+    for (i = 0; i < n; ++i)
+    sum_deviation += (data[i]-mean) * (data[i]-mean);
+    return sqrt (sum_deviation / n);
+}
+
+#endif // PERFTEST_H
diff --git a/tests/perf_test_0.c b/tests/perf_test_0.c
new file mode 100644 (file)
index 0000000..cff9f13
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2018 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vkengine.h"
+#include "vkvg.h"
+#include "vkh_device.h"
+#include "vkh_presenter.h"
+#include <sys/time.h>
+#include <stdlib.h>
+
+#include "perf-test.h"
+
+
+
+VkvgDevice device;
+/*VkvgSurface surf = NULL;
+
+void simple_paint () {
+    VkvgContext ctx = vkvg_create(surf);
+    vkvg_set_source_rgba(ctx,1,0,0,1);
+    vkvg_paint(ctx);
+    vkvg_destroy(ctx);
+}
+void simple_rectangle_fill () {
+    VkvgContext ctx = vkvg_create(surf);
+    vkvg_set_source_rgba(ctx,0,1,0,1);
+    vkvg_rectangle(ctx,100,100,200,200);
+    vkvg_fill(ctx);
+    vkvg_destroy(ctx);
+}
+void simple_rectangle_stroke () {
+    VkvgContext ctx = vkvg_create(surf);
+    vkvg_set_source_rgba(ctx,0,0,1,1);
+    vkvg_set_line_width(ctx,10.f);
+    vkvg_rectangle(ctx,100,100,200,200);
+    vkvg_stroke(ctx);
+    vkvg_destroy(ctx);
+}*/
+
+vkvg_color_t getRadomColor () {
+    vkvg_color_t c = {
+        (float)rand()/RAND_MAX,
+        (float)rand()/RAND_MAX,
+        (float)rand()/RAND_MAX,
+        (float)rand()/RAND_MAX,
+    };
+}
+
+void drawRandomRectangle (options_t* opt, VkvgContext ctx) {
+    for (int i=0; i<opt->count; i++) {
+        vkvg_color_t c = getRadomColor();
+        vkvg_set_source_rgba(ctx, c.r, c.g, c.b, c.a);
+
+        float x = (float)rand()/RAND_MAX * opt->width - 10;
+        float y = (float)rand()/RAND_MAX * opt->height - 10;
+        float w = (float)rand()/RAND_MAX * 200 + 10;
+        float h = (float)rand()/RAND_MAX * 200 + 10;
+
+        vkvg_rectangle(ctx, x, y, w, h);
+    }
+    if (opt->drawMode == DM_BOTH)
+        vkvg_fill_preserve(ctx);
+    else if (opt->drawMode == DM_FILL)
+        vkvg_fill (ctx);
+    if (opt->drawMode & DM_STROKE)
+        vkvg_stroke (ctx);
+}
+
+results_t performTest (options_t* opt) {
+    results_t res = initResults();
+
+    double run_time_values[opt->iterations];
+    double start_time, stop_time, run_time, run_total = 0;
+
+    VkvgSurface surf = vkvg_surface_create(device, opt->width, opt->height);
+    void* ctx = vkvg_create(surf);
+
+    for (int i=0; i<opt->iterations; i++) {
+
+        start_time = get_tick();
+
+        drawRandomRectangle (opt, ctx);
+
+        stop_time = get_tick();
+
+        run_time = stop_time - start_time;
+        run_time_values[i] = run_time;
+
+        if (run_time < res.run_min)
+            res.run_min = run_time;
+        if (run_time > res.run_max)
+            res.run_max = run_time;
+        run_total += run_time;
+    }
+
+    vkvg_destroy (ctx);
+    vkvg_surface_destroy (surf);
+
+    res.avg_time = run_total / (double)opt->iterations;
+    res.median_time = median_run_time(run_time_values, opt->iterations);
+    res.std_deriv = standard_deviation(run_time_values,opt->iterations, res.avg_time);
+
+    return res;
+}
+
+int main(int argc, char *argv[]) {
+    srand(time(NULL));
+
+    options_t opt = initOptions(argc, argv);
+    opt.test_name = "vkvg rectangles and";
+
+    vk_engine_t* e = vkengine_create (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, 1024, 800);
+    VkhPresenter r = e->renderer;
+
+    device  = vkvg_device_create (r->dev->phy, r->dev->dev, r->qFam, 0);
+
+    results_t res = performTest (&opt);
+
+    //outputResults(&opt, &res);
+    outputResultsHeadRow(&opt);
+    outputResultsOnOneLine(&opt, &res);
+
+    vkvg_device_destroy     (device);
+
+    vkengine_destroy (e);
+
+    return 0;
+}
diff --git a/tests/test_curves.c b/tests/test_curves.c
new file mode 100644 (file)
index 0000000..27eaaeb
--- /dev/null
@@ -0,0 +1,1243 @@
+/*
+ * Copyright (c) 2018 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vkengine.h"
+
+#include "vkvg.h"
+#include "string.h" //for nanosvg
+#define NANOSVG_IMPLEMENTATION // Expands implementation
+#include "nanosvg.h"
+#include "vkh_device.h"
+#include "vkh_presenter.h"
+
+#include "vkvg_context_internal.h"
+#include <sys/time.h>
+
+VkvgDevice device;
+VkvgSurface surf = NULL;
+
+static float m_approximation_scale = 1.0;
+static float m_angle_tolerance              = 0.07;
+static float m_distance_tolerance           = 1.0;
+static float m_cusp_limit                   = 0.05;
+static float curve_recursion_limit          = 10;
+static float curve_collinearity_epsilon     = 1.68;
+static float curve_angle_tolerance_epsilon  = 0.001;
+static double frameTime = 0;
+
+static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
+    if (action == GLFW_RELEASE)
+        return;
+    float step = 0.01;
+
+    if (mods & GLFW_MOD_SHIFT)
+        step = -step;
+    if (mods & GLFW_MOD_CONTROL)
+        step *= 0.1;
+    switch (key) {
+    case GLFW_KEY_F1:
+        m_angle_tolerance += step;
+        break;
+    case GLFW_KEY_F2:
+        m_distance_tolerance += step;
+        break;
+    case GLFW_KEY_F3:
+        m_cusp_limit += step;
+        break;
+    case GLFW_KEY_F4:
+        curve_recursion_limit += step * 1000.0;
+        break;
+    case GLFW_KEY_F6:
+        curve_collinearity_epsilon += step;
+        break;
+    case GLFW_KEY_F7:
+        curve_angle_tolerance_epsilon += step;
+        break;
+    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 vkvg_test_gradient (VkvgContext ctx) {
+    VkvgPattern pat = vkvg_pattern_create_linear(100,0,300,0);
+    vkvg_set_line_width(ctx, 20);
+    vkvg_patter_add_color_stop(pat, 0, 1, 0, 0, 1);
+    vkvg_patter_add_color_stop(pat, 0.5, 0, 1, 0, 1);
+    vkvg_patter_add_color_stop(pat, 1, 0, 0, 1, 1);
+    vkvg_set_source (ctx, pat);
+    vkvg_rectangle(ctx,100,100,200,200);
+    vkvg_fill (ctx);
+    //vkvg_stroke (ctx);
+    vkvg_pattern_destroy (pat);
+}
+
+void vkvg_test_clip(VkvgContext ctx){
+    vkvg_move_to(ctx,10,10);
+    vkvg_line_to(ctx,400,150);
+    vkvg_line_to(ctx,900,10);
+    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_clip(ctx);
+}
+void vkvg_test_fill(VkvgContext ctx){
+    vkvg_set_source_rgba(ctx,0.1,0.9,0.1,1.0);
+    vkvg_set_line_width(ctx,20);
+    vkvg_move_to(ctx,100,100);
+    vkvg_rel_line_to(ctx,100,100);
+    vkvg_rel_line_to(ctx,100,-50);
+    vkvg_rel_line_to(ctx,100,400);
+    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_stroke(ctx);
+}
+void vkvg_test_fill_and_stroke (VkvgContext ctx){
+    vkvg_move_to (ctx, 100, 100);
+    vkvg_rel_line_to (ctx, 50, -80);
+    vkvg_rel_line_to (ctx, 50, 80);
+    //vkvg_close_path (ctx);
+
+    vkvg_move_to (ctx, 300, 100);
+    vkvg_rel_line_to (ctx, 50, -80);
+    vkvg_rel_line_to (ctx, 50, 80);
+    vkvg_close_path (ctx);
+
+    vkvg_set_line_width (ctx, 10.0);
+    vkvg_set_source_rgb (ctx, 0, 0, 1);
+    vkvg_fill_preserve (ctx);
+    //vkvg_fill(ctx);
+    vkvg_set_source_rgb (ctx, 0, 0, 0);
+    vkvg_stroke (ctx);
+}
+void vkvg_test_curves2 (VkvgContext ctx) {
+    vkvg_move_to    (ctx, 400, 50);
+    vkvg_curve_to   (ctx, 400, 50, 600,5,600,100);
+    vkvg_curve_to   (ctx, 600, 5, 800,50,800,50);
+
+    vkvg_move_to    (ctx, 400, 150);
+    vkvg_curve_to   (ctx, 0, 0, 800, 0, 300, 350);
+    vkvg_curve_to   (ctx, 500, 500, 300, 0, 500, 700);
+
+    //vkvg_curve_to   (ctx, 1000, 100, 100, 800, 1000, 800);
+    //vkvg_curve_to   (ctx, 1000, 500, 700, 500, 700, 100);
+    //vkvg_close_path(ctx);
+
+    //vkvg_set_source_rgba   (ctx, 0.5,0.0,1.0,0.5);
+    //vkvg_fill_preserve(ctx);
+
+    vkvg_set_source_rgba   (ctx, 0,0,0,0.5);
+    vkvg_set_line_width(ctx, 40);
+    vkvg_stroke(ctx);
+}
+void vkvg_test_curves (VkvgContext ctx){
+
+    vkvg_set_line_width(ctx, 10);
+    vkvg_set_source_rgb   (ctx, 0,0,0);
+
+    vkvg_set_source_rgba   (ctx, 0.5,0.0,1.0,0.5);
+    vkvg_move_to(ctx,100,100);
+    vkvg_line_to(ctx,200,100);
+    vkvg_curve_to(ctx,250,100,300,150,300,200);
+    vkvg_line_to(ctx,300,300);
+    vkvg_curve_to(ctx,300,350,250,400,200,400);
+    vkvg_line_to(ctx,100,400);
+    vkvg_curve_to(ctx,50,400,10,350,10,300);
+    vkvg_line_to(ctx,10,200);
+    vkvg_curve_to(ctx,10,150,50,100,100,100);
+    vkvg_close_path(ctx);
+    //vkvg_curve_to(ctx, 150,100,200,150,200,200);
+    vkvg_fill_preserve(ctx);
+    vkvg_set_source_rgba   (ctx, 0,0,0,0.5);
+    vkvg_stroke(ctx);
+
+    vkvg_arc(ctx, 150, 100, 100, 0, M_PI*2);
+    vkvg_fill(ctx);
+    vkvg_arc(ctx, 200, 200, 100, 0, M_PI*2);
+    vkvg_stroke(ctx);
+
+    vkvg_set_line_width(ctx, 90);
+    vkvg_arc(ctx, 120, 500, 100, 0, M_PI*2);
+    vkvg_stroke(ctx);
+
+}
+void vkvg_test_stroke(VkvgContext ctx){
+    vkvg_set_line_width(ctx, 2);
+    vkvg_set_source_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_stroke_preserve(ctx);
+    vkvg_set_source_rgba(ctx,0,0.2,0.35,1);
+    vkvg_fill(ctx);
+    vkvg_set_source_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_line_width(ctx, 40);
+    vkvg_set_source_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_source_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_line_width(ctx, 20);
+    vkvg_set_source_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);
+}
+void test_text (VkvgContext ctx) {
+    int size = 19;
+    int penY = 50;
+    int penX = 10;
+
+    /*vkvg_rectangle(ctx,30,0,100,400);
+    vkvg_clip(ctx);*/
+
+    //vkvg_select_font_face(ctx, "/usr/local/share/fonts/DroidSansMono.ttf");
+    //vkvg_select_font_face(ctx, "/usr/share/fonts/truetype/unifont/unifont.ttf");
+
+    vkvg_set_font_size(ctx,12);
+    vkvg_select_font_face(ctx, "droid");
+    vkvg_font_extents_t fe;
+    vkvg_font_extents (ctx,&fe);
+    vkvg_move_to(ctx, penX,penY);
+    vkvg_set_source_rgba(ctx,0.7,0.7,0.7,1);
+    vkvg_text_extents_t te;
+    vkvg_text_extents(ctx,"abcdefghijk",&te);
+    vkvg_show_text (ctx,"abcdefghijk");
+    penX+= te.x_advance;
+    vkvg_move_to(ctx, penX,penY);
+    vkvg_show_text (ctx,"*abcdefghijk2");
+    penY+=2*size;
+
+
+    vkvg_select_font_face(ctx, "times");
+    vkvg_set_source_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_move_to(ctx, penX,penY);
+    vkvg_show_text (ctx,"this is a test");
+    penY+=size;
+    vkvg_move_to(ctx, penX,penY);
+    vkvg_show_text (ctx,"this is another test to see if label is working");
+    penY+=size;
+
+    vkvg_select_font_face(ctx, "mono");
+    vkvg_move_to(ctx, penX,penY);
+    vkvg_show_text (ctx,"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+    penY+=size;
+
+    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_show_text (ctx,"ABCDABCD");
+    //vkvg_show_text (ctx,"j");
+}
+void vkvg_test_stroke2(VkvgContext ctx){
+    vkvg_set_line_width(ctx,20);
+    vkvg_set_source_rgba(ctx,1,0,0,1);
+    vkvg_move_to(ctx,200,200);
+    vkvg_line_to(ctx,400,200);
+    vkvg_line_to(ctx,400,400);
+    vkvg_line_to(ctx,200,400);
+    vkvg_close_path(ctx);
+    vkvg_stroke(ctx);
+    vkvg_set_source_rgba(ctx,0.5,1,0,1);
+    vkvg_move_to(ctx,300,300);
+    vkvg_line_to(ctx,500,300);
+    vkvg_line_to(ctx,500,500);
+    vkvg_line_to(ctx,300,500);
+    vkvg_close_path(ctx);
+    vkvg_stroke(ctx);
+    vkvg_set_line_width(ctx,10);
+    vkvg_set_source_rgba(ctx,0.5,0.6,1,1);
+    vkvg_move_to(ctx,700,475);
+    vkvg_line_to(ctx,400,475);
+    vkvg_stroke(ctx);
+    vkvg_set_source_rgba(ctx,1,0,1,1);
+    vkvg_move_to(ctx,700,500);
+
+    vkvg_arc(ctx, 600,500,100,M_PI, 2.0*M_PI);
+    vkvg_stroke(ctx);
+
+
+    vkvg_set_line_width(ctx,20);
+    vkvg_set_source_rgba(ctx,1,1,0,1);
+    vkvg_move_to(ctx,100,50);
+    vkvg_line_to(ctx,400,50);
+    vkvg_stroke(ctx);
+}
+void vkvg_test_fill2(VkvgContext ctx){
+    vkvg_set_source_rgba(ctx,1,0,0,1);
+    vkvg_move_to(ctx,200,200);
+    vkvg_line_to(ctx,250,150);
+    vkvg_line_to(ctx,200,100);
+    vkvg_line_to(ctx,300,150);
+    vkvg_line_to(ctx,700,100);
+    vkvg_line_to(ctx,400,200);
+    vkvg_line_to(ctx,400,400);
+    vkvg_line_to(ctx,200,400);
+    vkvg_line_to(ctx,300,300);
+    vkvg_close_path(ctx);
+    vkvg_fill(ctx);
+}
+void test_img_surface () {
+    VkvgContext ctx = vkvg_create(surf);
+    VkvgSurface imgSurf;// = vkvg_surface_create_from_image(device, "/mnt/data/images/blason.png");
+    //VkvgSurface imgSurf = vkvg_surface_create_from_image(device, "/mnt/data/images/2000px-Tux.svg.png");
+    //VkvgSurface imgSurf = vkvg_surface_create_from_image(device, "/mnt/data/images/path2674.png");
+    //VkvgSurface imgSurf = vkvg_surface_create_from_image(device, "/mnt/data/images/horse-black-head-shape-of-a-chess-piece_318-52446.jpg");
+    /*vkvg_set_source_surface(ctx, imgSurf, 200, 200);
+    vkvg_paint(ctx);
+    vkvg_set_source_surface(ctx, imgSurf, 400, 400);
+    vkvg_paint(ctx);
+    vkvg_flush(ctx);
+    vkvg_surface_destroy(imgSurf);*/
+
+    imgSurf = vkvg_surface_create_from_image(device, "/mnt/data/images/miroir.jpg");
+    fflush(stdout);
+    vkvg_set_source_surface(ctx, imgSurf, 0, 0);
+    vkvg_paint(ctx);
+    //vkvg_flush(ctx);
+    vkvg_set_source_rgba(ctx,1,0,0,1);
+
+    vkvg_surface_destroy(imgSurf);
+    vkvg_destroy(ctx);
+}
+void test_line_caps (VkvgContext ctx) {
+
+    float x = 20, y = 20, dx = 30, dy = 60;
+
+    //vkvg_scale(ctx,5,5);
+    vkvg_set_line_width(ctx,26);
+    vkvg_set_source_rgba(ctx,0,0,0,1);
+    vkvg_move_to(ctx,x,y);
+    vkvg_rel_line_to(ctx,0,dy);
+    vkvg_stroke(ctx);
+    vkvg_set_line_cap(ctx,VKVG_LINE_CAP_SQUARE);
+    vkvg_move_to(ctx,x+dx,y);
+    vkvg_rel_line_to(ctx,0,dy);
+    vkvg_stroke(ctx);
+    vkvg_set_line_cap(ctx,VKVG_LINE_CAP_ROUND);
+    vkvg_move_to(ctx,x+2*dx,y);
+    vkvg_rel_line_to(ctx,0,dy);
+    vkvg_rel_move_to(ctx,dx,-dy);
+    vkvg_rel_line_to(ctx,dx,dy);
+    vkvg_rel_move_to(ctx,dx,-dy/2);
+    vkvg_rel_line_to(ctx,dx,0);
+    vkvg_rel_move_to(ctx,dx,dy/2);
+    vkvg_rel_line_to(ctx,dx,-dy);
+    vkvg_rel_move_to(ctx,dx,dy);
+    vkvg_rel_line_to(ctx,0,-dy);
+    vkvg_rel_move_to(ctx,2*dx,dy);
+    vkvg_rel_line_to(ctx,-dx,-dy);
+    vkvg_rel_move_to(ctx,3*dx,dy/2);
+    vkvg_rel_line_to(ctx,-dx,0);
+    //vkvg_rel_line_to(ctx,0,-dy);
+    //vkvg_rel_move_to(ctx,dx,dy/2);
+    //vkvg_rel_line_to(ctx,dx,0);
+    vkvg_stroke(ctx);
+
+    vkvg_set_line_cap(ctx,VKVG_LINE_CAP_BUTT);
+    vkvg_set_line_width(ctx,1);
+    vkvg_set_source_rgba(ctx,1,0,0,1);
+    vkvg_move_to(ctx,x,y);
+    vkvg_rel_line_to(ctx,0,dy);
+    vkvg_rel_move_to(ctx,dx,-dy);
+    vkvg_rel_line_to(ctx,0,dy);
+    vkvg_rel_move_to(ctx,dx,-dy);
+    vkvg_rel_line_to(ctx,0,dy);
+    vkvg_stroke(ctx);
+}
+void test_line_join (VkvgContext ctx){
+    float x = 50, y = 150, dx = 150, dy = 140;
+
+    //vkvg_scale(ctx,2,2);
+
+    vkvg_set_line_width(ctx,50);
+    vkvg_set_source_rgba(ctx,0,0,0,1);
+
+
+    vkvg_set_line_join(ctx,VKVG_LINE_JOIN_ROUND);
+    //vkvg_rectangle(ctx,x,y,dx,dy);
+
+    vkvg_move_to(ctx,x,y);
+    vkvg_rel_line_to(ctx,50,-30);
+    vkvg_rel_line_to(ctx,50,0);
+    vkvg_rel_line_to(ctx,50,30);
+    vkvg_rel_line_to(ctx,0,60);
+    vkvg_rel_line_to(ctx,-50,70);
+    vkvg_rel_line_to(ctx,-50,0);
+    vkvg_rel_line_to(ctx,-50,-70);
+    vkvg_close_path(ctx);
+    vkvg_stroke(ctx);
+
+    vkvg_set_source_rgba(ctx,1,0,0,1);
+    vkvg_move_to(ctx,x+200,y);
+    vkvg_rel_line_to(ctx,50,70);
+    vkvg_rel_line_to(ctx,50,0);
+    vkvg_rel_line_to(ctx,50,-70);
+    vkvg_rel_line_to(ctx,0,-60);
+    vkvg_rel_line_to(ctx,-50,-30);
+    vkvg_rel_line_to(ctx,-50,0);
+    vkvg_rel_line_to(ctx,-50,30);
+    vkvg_close_path(ctx);
+    vkvg_stroke(ctx);
+
+    vkvg_move_to(ctx,x,y);
+    vkvg_rel_line_to(ctx,50,-30);
+    vkvg_rel_line_to(ctx,50,0);
+    vkvg_rel_line_to(ctx,50,30);
+    vkvg_rel_line_to(ctx,0,60);
+    vkvg_rel_line_to(ctx,-50,70);
+    vkvg_rel_line_to(ctx,-50,0);
+    vkvg_rel_line_to(ctx,-50,-70);
+    vkvg_close_path(ctx);
+    vkvg_stroke(ctx);
+
+//    vkvg_rel_line_to(ctx,dx,-dy);
+//    vkvg_rel_line_to(ctx,dx,dy);
+//    vkvg_stroke(ctx);
+//    vkvg_set_line_join(ctx,VKVG_LINE_JOIN_BEVEL);
+//    vkvg_rel_move_to(ctx,-dx*2,abs(dy*1.5));
+//    vkvg_rel_line_to(ctx,dx,-dy);
+//    vkvg_rel_line_to(ctx,dx,dy);
+//    vkvg_stroke(ctx);
+//    vkvg_set_line_join(ctx,VKVG_LINE_JOIN_ROUND);
+//    vkvg_rel_move_to(ctx,-dx*2,abs(dy*1.5));
+//    vkvg_rel_line_to(ctx,dx,-dy);
+//    vkvg_rel_line_to(ctx,dx,dy);
+//    vkvg_stroke(ctx);
+    vkvg_set_line_join(ctx,VKVG_LINE_JOIN_MITER);
+}
+void test_colinear () {
+    VkvgContext ctx = vkvg_create(surf);
+    vkvg_set_source_rgba(ctx,0.7,0.7,0.7,1);
+    vkvg_paint(ctx);
+
+    vkvg_set_source_rgba(ctx,0,0,0,0.5);
+    vkvg_set_line_width(ctx,30);
+
+    vkvg_move_to(ctx,100,100);
+    vkvg_line_to(ctx,100,200);
+    vkvg_line_to(ctx,100,300);
+    //vkvg_line_to(ctx,100,0);
+    vkvg_stroke(ctx);
+
+    vkvg_destroy(ctx);
+}
+
+void multi_test1 () {
+    VkvgSurface surf2 = vkvg_surface_create (device,800,800);;
+    VkvgContext ctx = vkvg_create (surf2);
+
+    vkvg_set_source_rgba(ctx,0.1,0.1,0.3,1.0);
+    vkvg_paint(ctx);
+
+    vkvg_test_fill(ctx);
+    vkvg_test_fill2(ctx);
+
+
+    //test_line_join(ctx);
+
+    //vkvg_test_clip(ctx);
+
+    //test_text(ctx);
+
+
+    vkvg_test_stroke(ctx);
+
+    vkvg_translate(ctx, 100,50);
+//    vkvg_rotate(ctx, 0.2);
+    //vkvg_scale(ctx, 2,2);
+
+
+    //vkvg_test_gradient (ctx);
+
+    vkvg_test_curves(ctx);
+    vkvg_test_curves2(ctx);
+
+    /*vkvg_set_operator(ctx, VKVG_OPERATOR_CLEAR);
+    vkvg_rectangle(ctx,100,100,300,300);
+    vkvg_fill(ctx);
+    vkvg_set_operator(ctx, VKVG_OPERATOR_OVER);*/
+
+    //test_img_surface(ctx);
+    //test_line_caps(ctx);
+
+    vkvg_destroy(ctx);
+    ctx = vkvg_create(surf);
+
+    vkvg_set_source_rgba(ctx,1.0,0.0,0.0,1);
+    vkvg_paint(ctx);
+//    vkvg_set_source_rgba(ctx,0.0,0.0,1.0,1);
+//    vkvg_rectangle(ctx,100,100,500,500);
+//    vkvg_fill(ctx);
+
+    VkvgPattern pat = vkvg_pattern_create_for_surface(surf2);
+    vkvg_pattern_set_extend(pat, VKVG_EXTEND_REFLECT);
+    vkvg_pattern_set_filter(pat, VKVG_FILTER_BILINEAR);
+    vkvg_set_source (ctx, pat);
+    //vkvg_rectangle(ctx,100,100,400,400);
+    //vkvg_fill(ctx);
+    vkvg_paint(ctx);
+    vkvg_translate(ctx,200,200);
+    vkvg_paint(ctx);
+    vkvg_rotate(ctx,0.7);
+    vkvg_paint(ctx);
+    vkvg_pattern_destroy (pat);
+    vkvg_destroy(ctx);
+    vkvg_surface_destroy(surf2);
+}
+
+void cairo_test_fill_rule (VkvgContext cr){
+    vkvg_set_line_width (cr, 6);
+
+    //vkvg_scale(cr,3,3);
+    vkvg_set_source_rgba(cr,1,0,0,1);
+    vkvg_move_to(cr,50,150);
+    vkvg_rel_line_to(cr,50,70);
+    vkvg_rel_line_to(cr,50,0);
+    vkvg_rel_line_to(cr,50,-70);
+    vkvg_rel_line_to(cr,0,-60);
+    vkvg_rel_line_to(cr,-50,-30);
+    vkvg_rel_line_to(cr,-50,0);
+    vkvg_rel_line_to(cr,-50,30);
+    vkvg_close_path(cr);
+
+
+//    vkvg_set_line_join(cr,VKVG_LINE_JOIN_ROUND);
+    vkvg_set_source_rgb (cr, 0, 0.7, 0);
+    vkvg_rectangle (cr, 12, 12, 232, 70);
+    //vkvg_stroke (cr);
+//    vkvg_new_sub_path (cr);
+    vkvg_arc (cr, 64, 64, 40, 0, M_PI*2);
+    //vkvg_close_path(cr);
+
+    vkvg_new_sub_path (cr);
+    vkvg_arc_negative (cr, 192, 64, 40, 2*M_PI, 0);
+    //vkvg_close_path(cr);
+
+    //vkvg_rectangle (cr, 30, 30, 20, 200);
+    //vkvg_rectangle (cr, 130, 30, 20, 200);
+    //vkvg_set_fill_rule (cr, vkvg_FILL_RULE_EVEN_ODD);
+
+    vkvg_fill_preserve(cr);
+
+    vkvg_set_source_rgb (cr, 0, 0, 0);
+    vkvg_stroke (cr);
+}
+void cairo_test_text (VkvgContext cr) {
+    vkvg_text_extents_t extents;
+
+    const char *utf8 = "vkvg";
+    float x,y;
+
+    vkvg_select_font_face (cr, "times");
+    vkvg_set_font_size (cr, 100.0);
+    vkvg_text_extents (cr, utf8, &extents);
+    vkvg_set_source_rgb(cr,0,0,0);
+
+    x=25.0;
+    y=150.0;
+
+    vkvg_move_to (cr, x,y);
+    vkvg_show_text (cr, utf8);
+
+    /* draw helping lines */
+    vkvg_set_source_rgba (cr, 1, 0.2, 0.2, 0.6);
+    vkvg_set_line_width (cr, 6.0);
+    vkvg_arc (cr, x, y, 10.0, 0, 2*M_PI);
+    vkvg_fill (cr);
+    vkvg_move_to (cr, x,y);
+    vkvg_rel_line_to (cr, 0, -extents.height);
+    vkvg_rel_line_to (cr, extents.width, 0);
+    vkvg_rel_line_to (cr, extents.x_bearing, -extents.y_bearing);
+    vkvg_stroke (cr);
+}
+void cairo_test_clip (VkvgContext cr){
+    vkvg_arc (cr, 128.0, 128.0, 76.8, 0, 2 * M_PI);
+    vkvg_clip (cr);
+    //vkvg_new_path (cr);  /* current path is not
+    //                         consumed by vkvg_clip() */
+    vkvg_set_source_rgba(cr, 0, 0, 0, 1);
+    vkvg_rectangle (cr, 0, 0, 256, 256);
+    vkvg_fill (cr);
+    vkvg_set_source_rgba (cr, 0, 1, 0, 1);
+    vkvg_move_to (cr, -100, -100);
+    vkvg_line_to (cr, 256, 256);
+    vkvg_move_to (cr, 356, -100);
+    vkvg_line_to (cr, 0, 256);
+    vkvg_set_line_width (cr, 10.0);
+    vkvg_stroke (cr);
+}
+void cairo_test_curves (VkvgContext cr){
+    float x=25.6,  y=128.0;
+    float x1=102.4, y1=230.4,
+           x2=153.6, y2=25.6,
+           x3=230.4, y3=128.0;
+
+    vkvg_set_source_rgb (cr, 0, 0, 0);
+    vkvg_move_to (cr, x, y);
+    vkvg_curve_to (cr, x1, y1, x2, y2, x3, y3);
+
+    vkvg_set_line_width (cr, 10.0);
+    vkvg_stroke (cr);
+
+    vkvg_set_source_rgba (cr, 1, 0.2, 0.2, 0.6);
+    vkvg_set_line_width (cr, 6.0);
+    vkvg_move_to (cr,x,y);   vkvg_line_to (cr,x1,y1);
+    vkvg_move_to (cr,x2,y2); vkvg_line_to (cr,x3,y3);
+    vkvg_stroke (cr);
+}
+void cairo_test_rounded_rect (VkvgContext cr) {
+    /* a custom shape that could be wrapped in a function */
+    float x0      = 25.6,   /* parameters like vkvg_rectangle */
+           y0      = 25.6,
+           rect_width  = 204.8,
+           rect_height = 204.8,
+           radius = 102.4;   /* and an approximate curvature radius */
+
+    float x1,y1;
+
+    x1=x0+rect_width;
+    y1=y0+rect_height;
+    if (!rect_width || !rect_height)
+        return;
+    if (rect_width/2<radius) {
+        if (rect_height/2<radius) {
+            vkvg_move_to  (cr, x0, (y0 + y1)/2);
+            vkvg_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1)/2, y0);
+            vkvg_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1)/2);
+            vkvg_curve_to (cr, x1, y1, x1, y1, (x1 + x0)/2, y1);
+            vkvg_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1)/2);
+        } else {
+            vkvg_move_to  (cr, x0, y0 + radius);
+            vkvg_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1)/2, y0);
+            vkvg_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
+            vkvg_line_to (cr, x1 , y1 - radius);
+            vkvg_curve_to (cr, x1, y1, x1, y1, (x1 + x0)/2, y1);
+            vkvg_curve_to (cr, x0, y1, x0, y1, x0, y1- radius);
+        }
+    } else {
+        if (rect_height/2<radius) {
+            vkvg_move_to  (cr, x0, (y0 + y1)/2);
+            vkvg_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
+            vkvg_line_to (cr, x1 - radius, y0);
+            vkvg_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1)/2);
+            vkvg_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
+            vkvg_line_to (cr, x0 + radius, y1);
+            vkvg_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1)/2);
+        } else {
+            vkvg_move_to  (cr, x0, y0 + radius);
+            vkvg_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
+            vkvg_line_to (cr, x1 - radius, y0);
+            vkvg_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
+            vkvg_line_to (cr, x1 , y1 - radius);
+            vkvg_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
+            vkvg_line_to (cr, x0 + radius, y1);
+            vkvg_curve_to (cr, x0, y1, x0, y1, x0, y1- radius);
+        }
+    }
+    vkvg_close_path (cr);
+
+    vkvg_set_source_rgb (cr, 0.5, 0.5, 1);
+    vkvg_fill_preserve (cr);
+    vkvg_set_source_rgba (cr, 0.5, 0, 0, 0.5);
+    vkvg_set_line_width (cr, 10.0);
+    vkvg_stroke (cr);
+}
+void cairo_test_fill_and_stroke2 (VkvgContext cr){
+    vkvg_move_to (cr, 128.0, 25.6);
+    vkvg_line_to (cr, 230.4, 230.4);
+    vkvg_rel_line_to (cr, -102.4, 0.0);
+    vkvg_curve_to (cr, 51.2, 230.4, 51.2, 128.0, 128.0, 128.0);
+    vkvg_close_path (cr);
+
+    vkvg_move_to (cr, 64.0, 25.6);
+    vkvg_rel_line_to (cr, 51.2, 51.2);
+    vkvg_rel_line_to (cr, -51.2, 51.2);
+    vkvg_rel_line_to (cr, -51.2, -51.2);
+    vkvg_close_path (cr);
+
+    /*vkvg_translate(cr,100,100);
+    vkvg_move_to (cr, 100, 100);
+    vkvg_line_to(cr,300,300);
+    vkvg_line_to(cr,100,300);*/
+
+
+    vkvg_set_line_width (cr, 10.0);
+    vkvg_set_source_rgb (cr, 0, 0, 1);
+    vkvg_fill_preserve (cr);
+    vkvg_set_source_rgb (cr, 0, 0, 0);
+    vkvg_stroke (cr);
+}
+void cairo_print_arc_neg (VkvgContext cr){
+    float xc = 128.0;
+    float yc = 128.0;
+    float radius = 100.0;
+    float angle1 = 45.0  * (M_PI/180.0);  /* angles are specified */
+    float angle2 = 180.0 * (M_PI/180.0);  /* in radians           */
+
+    vkvg_set_source_rgba(cr, 0, 0, 0, 1);
+    vkvg_set_line_width (cr, 10.0);
+    vkvg_arc_negative (cr, xc, yc, radius, angle1, angle2);
+    vkvg_stroke (cr);
+
+    /* draw helping lines */
+    vkvg_set_source_rgba (cr, 1, 0.2, 0.2, 0.6);
+    vkvg_set_line_width (cr, 6.0);
+
+    vkvg_arc (cr, xc, yc, 10.0, 0, 2*M_PI);
+    vkvg_fill (cr);
+
+    vkvg_arc (cr, xc, yc, radius, angle1, angle1);
+    vkvg_line_to (cr, xc, yc);
+    vkvg_arc (cr, xc, yc, radius, angle2, angle2);
+    //vkvg_line_to (cr, xc, yc);
+    vkvg_stroke (cr);
+
+}
+void cairo_test_line_caps (VkvgContext cr) {
+    vkvg_set_source_rgb (cr, 0, 0, 0);
+    vkvg_set_line_width (cr, 30.0);
+    vkvg_set_line_cap  (cr, VKVG_LINE_CAP_BUTT); /* default */
+    vkvg_move_to (cr, 64.0, 50.0); vkvg_line_to (cr, 64.0, 200.0);
+    vkvg_stroke (cr);
+    vkvg_set_line_cap  (cr, VKVG_LINE_CAP_ROUND);
+    vkvg_move_to (cr, 128.0, 50.0); vkvg_line_to (cr, 128.0, 200.0);
+    vkvg_stroke (cr);
+    vkvg_set_line_cap  (cr, VKVG_LINE_CAP_SQUARE);
+    vkvg_move_to (cr, 192.0, 50.0); vkvg_line_to (cr, 192.0, 200.0);
+    vkvg_stroke (cr);
+
+    /* draw helping lines */
+    vkvg_set_source_rgb (cr, 1, 0.2, 0.2);
+    vkvg_set_line_width (cr, 2.56);
+    vkvg_move_to (cr, 64.0, 50.0); vkvg_line_to (cr, 64.0, 200.0);
+    vkvg_move_to (cr, 128.0, 50.0);  vkvg_line_to (cr, 128.0, 200.0);
+    vkvg_move_to (cr, 192.0, 50.0); vkvg_line_to (cr, 192.0, 200.0);
+    vkvg_stroke (cr);
+}
+void cairo_test_line_joins (VkvgContext cr) {
+    vkvg_set_source_rgb (cr, 0, 0, 0);
+    vkvg_set_line_width (cr, 40.96);
+    vkvg_move_to (cr, 76.8, 84.48);
+    vkvg_rel_line_to (cr, 51.2, -51.2);
+    vkvg_rel_line_to (cr, 51.2, 51.2);
+    vkvg_set_line_join (cr, VKVG_LINE_JOIN_MITER); /* default */
+    vkvg_stroke (cr);
+
+    vkvg_move_to (cr, 76.8, 161.28);
+    vkvg_rel_line_to (cr, 51.2, -51.2);
+    vkvg_rel_line_to (cr, 51.2, 51.2);
+    vkvg_set_line_join (cr, VKVG_LINE_JOIN_BEVEL);
+    vkvg_stroke (cr);
+
+    vkvg_move_to (cr, 76.8, 238.08);
+    vkvg_rel_line_to (cr, 51.2, -51.2);
+    vkvg_rel_line_to (cr, 51.2, 51.2);
+    vkvg_set_line_join (cr, VKVG_LINE_JOIN_ROUND);
+    vkvg_stroke (cr);
+}
+void cairo_print_arc (VkvgContext cr) {
+    float xc = 128.0;
+    float yc = 128.0;
+    float radius = 100.0;
+    float angle1 = 45.0  * (M_PI/180.0);  /* angles are specified */
+    float angle2 = 180.0 * (M_PI/180.0);  /* in radians           */
+
+    vkvg_set_source_rgba(cr, 0, 0, 0, 1);
+    vkvg_set_line_width (cr, 10.0);
+    vkvg_arc (cr, xc, yc, radius, angle1, angle2);
+    vkvg_stroke (cr);
+
+    /* draw helping lines */
+    vkvg_set_source_rgba(cr, 1, 0.2, 0.2, 0.6);
+    vkvg_set_line_width (cr, 6.0);
+
+    vkvg_arc (cr, xc, yc, 10.0, 0, 2*M_PI);
+    vkvg_fill (cr);
+
+    vkvg_arc (cr, xc, yc, radius, angle1, angle1);
+    vkvg_line_to (cr, xc, yc);
+    vkvg_arc (cr, xc, yc, radius, angle2, angle2);
+    vkvg_stroke (cr);
+}
+static float rotation = 0.f;
+void cairo_tests () {
+    rotation+=0.01f;
+
+    vkvg_matrix_t mat;
+    vkvg_matrix_init_translate (&mat, 512,400);
+    vkvg_matrix_rotate(&mat,rotation);
+    vkvg_matrix_translate(&mat,-512,-400);
+
+    VkvgContext ctx = vkvg_create(surf);
+    vkvg_set_source_rgba(ctx,0.7,0.7,0.7,1);
+    vkvg_paint(ctx);
+
+    vkvg_set_matrix(ctx,&mat);
+    /*
+    vkvg_set_source_rgba(ctx,0,1,0,1);
+    vkvg_rectangle(ctx,0,0,600,600);
+    vkvg_fill(ctx);
+
+    vkvg_clip(ctx);
+
+    vkvg_set_source_rgba(ctx,1,0,0,1);
+    vkvg_paint(ctx);
+    //vkvg_rectangle(ctx,00,00,1024,800);
+    //vkvg_fill(ctx);
+
+    vkvg_reset_clip(ctx);
+    vkvg_set_source_rgba(ctx,0,0,1,1);
+    vkvg_set_line_width(ctx,20);
+    vkvg_move_to(ctx,0,0);
+    vkvg_rel_line_to(ctx,800,800);
+    vkvg_stroke(ctx);*/
+
+//    cairo_test_clip(ctx);
+//    vkvg_reset_clip(ctx);
+    //test_img_surface (ctx);
+
+    cairo_print_arc(ctx);
+
+    vkvg_translate(ctx,200,0);
+    cairo_test_fill_rule(ctx);
+
+    vkvg_translate(ctx,250,0);
+    cairo_test_rounded_rect(ctx);
+
+
+/*
+    vkvg_set_operator(ctx, VKVG_OPERATOR_CLEAR);
+    vkvg_rectangle(ctx,100,100,500,500);
+    vkvg_fill(ctx);
+    vkvg_set_operator(ctx, VKVG_OPERATOR_OVER);
+*/
+
+
+    vkvg_translate(ctx,-450,250);
+    cairo_test_fill_and_stroke2(ctx);
+
+    vkvg_translate(ctx,250,0);
+    cairo_print_arc_neg(ctx);
+
+    vkvg_translate(ctx,250,0);
+    cairo_test_text(ctx);
+
+    vkvg_translate(ctx,-500,250);
+    cairo_test_curves(ctx);
+
+    vkvg_translate(ctx,250,0);
+    cairo_test_line_joins(ctx);
+
+    vkvg_translate(ctx,250,0);
+    cairo_test_line_caps(ctx);
+
+    vkvg_destroy(ctx);
+}
+
+void test_grad_transforms () {
+    VkvgContext ctx = vkvg_create(surf);
+
+    vkvg_translate(ctx,-100,-100);
+    vkvg_rotate(ctx,1.5);
+    //vkvg_translate(ctx,100,100);
+
+    //vkvg_scale(ctx,0.2,0.2);
+    VkvgPattern pat = vkvg_pattern_create_linear(0,0,200,0);
+    vkvg_set_line_width(ctx, 20);
+    vkvg_patter_add_color_stop(pat, 0, 1, 0, 0, 1);
+    vkvg_patter_add_color_stop(pat, 0.5, 0, 1, 0, 1);
+    vkvg_patter_add_color_stop(pat, 1, 0, 0, 1, 1);
+    vkvg_set_source (ctx, pat);
+    vkvg_rectangle(ctx,0,0,200,200);
+    vkvg_fill (ctx);
+    //vkvg_stroke (ctx);
+    vkvg_pattern_destroy (pat);
+
+    vkvg_destroy(ctx);
+}
+
+void svg_set_color (VkvgContext ctx, uint32_t c, float alpha) {
+    float a = (c >> 24 & 255) / 255.f;
+    float b = (c >> 16 & 255) / 255.f;
+    float g = (c >> 8 & 255) / 255.f;
+    float r = (c & 255) / 255.f;
+    vkvg_set_source_rgba(ctx,r,g,b,a*alpha);
+}
+
+void test_svg (VkvgContext ctx) {
+    //VkvgContext ctx = vkvg_create(surf);
+    vkvg_set_source_rgba(ctx,0.5,0.5,0.5,1);
+    vkvg_paint(ctx);
+
+    NSVGimage* svg;
+    NSVGshape* shape;
+    NSVGpath* path;
+    //svg = nsvgParseFromFile("/mnt/data/images/svg/tux.svg", "px", 96);
+    //svg = nsvgParseFromFile("/mnt/data/images/svg/world.svg", "px", 96);
+    svg = nsvgParseFromFile("/mnt/data/images/svg/tiger.svg", "px", 96);
+    //svg = nsvgParseFromFile("/mnt/data/images/svg/koch_curve.svg", "px", 96);
+    //svg = nsvgParseFromFile("/mnt/data/images/svg/diamond1.svg", "px", 96);
+    //svg = nsvgParseFromFile("/mnt/data/images/svg/diamond2.svg", "px", 96);
+    //svg = nsvgParseFromFile("/home/jp/yahweh-protosinaitic.svg", "px", 96);
+    //svg = nsvgParseFromFile("/mnt/data/images/svg/WMD-biological.svg", "px", 96);
+    //svg = nsvgParseFromFile("/mnt/data/images/svg/Skull_and_crossbones.svg", "px", 96);
+    //svg = nsvgParseFromFile("/mnt/data/images/svg/IconAlerte.svg", "px", 96);
+    //svg = nsvgParseFromFile("/mnt/data/images/svg/Svg_example4.svg", "px", 96);
+
+    //vkvg_scale(ctx, 3,3);
+    vkvg_set_source_rgba(ctx,0.0,0.0,0.0,1);
+
+    for (shape = svg->shapes; shape != NULL; shape = shape->next) {
+
+        vkvg_new_path(ctx);
+
+        float o = shape->opacity;
+
+        vkvg_set_line_width(ctx, shape->strokeWidth);
+
+        for (path = shape->paths; path != NULL; path = path->next) {
+            float* p = path->pts;
+            vkvg_move_to(ctx, p[0],p[1]);
+            for (int i = 1; i < path->npts-2; i += 3) {
+                p = &path->pts[i*2];
+                vkvg_curve_to(ctx, p[0],p[1], p[2],p[3], p[4],p[5]);
+            }
+            if (path->closed)
+                vkvg_close_path(ctx);
+        }
+
+        if (shape->fill.type == NSVG_PAINT_COLOR)
+            svg_set_color(ctx, shape->fill.color, o);
+        else if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT){
+            NSVGgradient* g = shape->fill.gradient;
+            svg_set_color(ctx, g->stops[0].color, o);
+        }
+
+        if (shape->fill.type != NSVG_PAINT_NONE){
+            if (shape->stroke.type == NSVG_PAINT_NONE){
+                vkvg_fill(ctx);
+                continue;
+            }
+            vkvg_fill_preserve (ctx);
+        }
+
+        if (shape->stroke.type == NSVG_PAINT_COLOR)
+            svg_set_color(ctx, shape->stroke.color, o);
+        else if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT){
+            NSVGgradient* g = shape->stroke.gradient;
+            svg_set_color(ctx, g->stops[0].color, o);
+        }
+
+        vkvg_stroke(ctx);
+    }
+
+    nsvgDelete(svg);
+
+
+    //vkvg_destroy(ctx);
+}
+
+void print_float (VkvgContext ctx){
+    char str[50];
+    float penY = 20, penX = 10, dy = 18;
+
+    vkvg_set_source_rgb(ctx,1,1,1);
+    vkvg_set_font_size(ctx,14   );
+    vkvg_select_font_face(ctx, "mono");
+
+    sprintf (str, "frame (µs): %.0lf", frameTime);
+    vkvg_move_to(ctx,penX,penY);
+    vkvg_show_text(ctx, str);
+    penY += dy;
+    sprintf (str, "fps: %lf", floor(1000000 / frameTime));
+    vkvg_move_to(ctx,penX,penY);
+    vkvg_show_text(ctx, str);
+    penY += dy;
+    sprintf (str, "Angle tol:    %f", ctx->m_angle_tolerance);
+    vkvg_move_to(ctx,penX,penY);
+    vkvg_show_text(ctx, str);
+    penY += dy;
+    sprintf (str, "Dist tol:     %f", ctx->m_distance_tolerance);
+    vkvg_move_to(ctx,penX,penY);
+    vkvg_show_text(ctx, str);
+    penY += dy;
+    sprintf (str, "Cups lim:     %f", ctx->m_cusp_limit);
+    vkvg_move_to(ctx,penX,penY);
+    vkvg_show_text(ctx, str);
+    penY += dy;
+    sprintf (str, "Recurs lim:   %f", ctx->curve_recursion_limit);
+    vkvg_move_to(ctx,penX,penY);
+    vkvg_show_text(ctx, str);
+    penY += dy;
+    sprintf (str, "Colinear €:   %f", ctx->curve_collinearity_epsilon);
+    vkvg_move_to(ctx,penX,penY);
+    vkvg_show_text(ctx, str);
+    penY += dy;
+    sprintf (str, "Angle tol €:  %f", ctx->curve_angle_tolerance_epsilon);
+    vkvg_move_to(ctx,penX,penY);
+    vkvg_show_text(ctx, str);
+}
+
+double time_diff(struct timeval x , struct timeval y)
+{
+    double x_ms , y_ms , diff;
+
+    x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec;
+    y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec;
+
+    diff = (double)y_ms - (double)x_ms;
+
+    return diff;
+}
+void test_1 () {
+    const char* text = "This is a petit test {}";
+
+    VkvgContext ctx = vkvg_create (surf);
+
+    vkvg_set_source_rgba(ctx,0,0,0,1.0);
+    vkvg_paint (ctx);
+    vkvg_set_source_rgba(ctx,1,1,1,1.0);
+
+    vkvg_select_font_face(ctx, "mono");
+    vkvg_set_font_size(ctx, 12);
+
+    vkvg_font_extents_t f = {};
+    vkvg_font_extents(ctx, &f);
+
+    vkvg_text_extents_t t = {};
+    vkvg_text_extents(ctx, text, &t);
+
+    vkvg_move_to(ctx,100,100);
+    vkvg_show_text(ctx, text);
+
+    vkvg_move_to(ctx,100,100.5 - f.ascent);
+    vkvg_line_to(ctx,100+t.width,100.5 - f.ascent);
+
+    vkvg_move_to(ctx,100,100.5 - f.descent);
+    vkvg_line_to(ctx,100+t.width,100.5 - f.descent);
+
+    vkvg_stroke(ctx);
+
+    vkvg_flush(ctx);
+    vkvg_destroy (ctx);
+}
+void test_painting () {
+    VkvgSurface surf2 = vkvg_surface_create (device,400,400);;
+    VkvgContext ctx = vkvg_create (surf2);
+
+    vkvg_set_source_rgba(ctx,1.0,0.,0.,1.0);
+    vkvg_paint (ctx);
+
+    vkvg_destroy (ctx);
+    ctx = vkvg_create (surf);
+
+    vkvg_set_source_rgba(ctx,0.1,0.1,0.3,1.0);
+    vkvg_paint (ctx);
+
+    //vkvg_set_source_surface(ctx,surf2,0,0);
+
+    //VkvgPattern pat = vkvg_get_source (ctx);
+    VkvgPattern pat = vkvg_pattern_create_for_surface(surf2);
+    vkvg_pattern_set_extend (pat,VKVG_EXTEND_REFLECT);
+    vkvg_set_source(ctx,pat);
+    //vkvg_paint (ctx);
+    //vkvg_set_source_rgba(ctx,0,1,0,1.0);
+    vkvg_rectangle(ctx,100,100,200,200);
+    vkvg_fill(ctx);
+
+    vkvg_destroy (ctx);
+    vkvg_surface_destroy (surf2);
+    vkvg_pattern_destroy (pat);
+}
+
+void simple_paint () {
+    VkvgContext ctx = vkvg_create(surf);
+    vkvg_set_source_rgba(ctx,1,0,0,1);
+    vkvg_paint(ctx);
+    vkvg_destroy(ctx);
+}
+void simple_rectangle_fill () {
+    VkvgContext ctx = vkvg_create(surf);
+    vkvg_set_source_rgba(ctx,0,1,0,1);
+    vkvg_rectangle(ctx,100,100,200,200);
+    vkvg_fill(ctx);
+    vkvg_destroy(ctx);
+}
+void simple_rectangle_stroke () {
+    VkvgContext ctx = vkvg_create(surf);
+    vkvg_set_source_rgba(ctx,0,0,1,1);
+    vkvg_set_line_width(ctx,10.f);
+    vkvg_rectangle(ctx,100,100,200,200);
+    vkvg_stroke(ctx);
+    vkvg_destroy(ctx);
+}
+int main(int argc, char *argv[]) {
+
+    //dumpLayerExts();
+
+    vk_engine_t* e = vkengine_create (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, 1024, 800);
+    VkhPresenter r = e->renderer;
+    vkengine_set_key_callback (e, key_callback);
+
+    device  = vkvg_device_create (r->dev->phy, r->dev->dev, r->qFam, 0);
+    surf    = vkvg_surface_create(device, 1024, 800);
+
+    //test_svg();
+    //
+
+
+    //test_grad_transforms();
+    //cairo_tests();
+    //test_colinear();
+
+    vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf));
+
+    /*
+    while (!vkengine_should_close (e)) {
+        glfwPollEvents();
+        //test_1();
+        cairo_tests();
+        //simple_paint();
+        //simple_rectangle_stroke();
+        //simple_rectangle_fill();
+        //test_img_surface();
+        //multi_test1();
+        //test_painting();
+        if (!vkh_presenter_draw (r))
+            vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf));
+    }
+    */
+    struct timeval before , after;
+
+
+    while (!vkengine_should_close (e)) {
+
+
+        VkvgContext ctx = vkvg_create(surf);
+
+        gettimeofday(&before , NULL);
+
+        vkvg_set_source_rgba(ctx,0.1,0.1,0.3,1.0);
+        vkvg_paint(ctx);
+
+        ctx->m_angle_tolerance = m_angle_tolerance;
+        ctx->m_distance_tolerance = m_distance_tolerance;
+        ctx->m_cusp_limit = m_cusp_limit;
+        ctx->curve_recursion_limit = curve_recursion_limit;
+        ctx->curve_angle_tolerance_epsilon = curve_angle_tolerance_epsilon;
+        ctx->curve_collinearity_epsilon = curve_collinearity_epsilon;
+
+        //vkvg_test_curves(ctx);
+        //vkvg_test_curves2(ctx);
+        test_svg(ctx);
+
+
+        print_float(ctx);
+
+        gettimeofday(&after , NULL);
+
+        vkvg_destroy(ctx);
+
+        glfwPollEvents();
+        if (!vkh_presenter_draw (r))
+            vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf));
+
+        frameTime = time_diff(before , after);
+    }
+
+    vkDeviceWaitIdle(e->dev->dev);
+
+    vkvg_surface_destroy    (surf);
+    vkvg_device_destroy     (device);
+
+    vkengine_destroy (e);
+
+    return 0;
+}
diff --git a/tests/vkengine.c b/tests/vkengine.c
deleted file mode 100644 (file)
index e4f04fb..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 2018 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
- * Software, and to permit persons to whom the Software is furnished to do so, subject
- * to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "vkh.h"
-#include "vkengine.h"
-#include "vkh_app.h"
-#include "vkh_phyinfo.h"
-#include "vkh_presenter.h"
-#include "vkh_image.h"
-#include "vkh_device.h"
-
-bool vkeCheckPhyPropBlitSource (VkEngine e) {
-    VkFormatProperties formatProps;
-    vkGetPhysicalDeviceFormatProperties(e->dev->phy, e->renderer->format, &formatProps);
-    assert((formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) && "Format cannot be used as transfer source");
-}
-
-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_dump_Infos (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");
-    }
-}
-vk_engine_t* vkengine_create (VkPhysicalDeviceType preferedGPU, uint32_t width, uint32_t height) {
-    vk_engine_t* e = (vk_engine_t*)calloc(1,sizeof(vk_engine_t));
-
-    glfwInit();
-    assert (glfwVulkanSupported()==GLFW_TRUE);
-
-    uint32_t enabledExtsCount = 0, phyCount = 0;
-    const char ** enabledExts = glfwGetRequiredInstanceExtensions (&enabledExtsCount);
-
-    e->app = vkh_app_create("vkvgTest", enabledExtsCount, enabledExts);
-
-    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
-    glfwWindowHint(GLFW_RESIZABLE,  GLFW_TRUE);
-    glfwWindowHint(GLFW_FLOATING,   GLFW_FALSE);
-    glfwWindowHint(GLFW_DECORATED,  GLFW_FALSE);
-
-    e->window = glfwCreateWindow (width, height, "Window Title", NULL, NULL);
-    VkSurfaceKHR surf;
-
-    assert (glfwCreateWindowSurface(e->app->inst, e->window, NULL, &surf)==VK_SUCCESS);
-
-
-    VkhPhyInfo* phys = vkh_app_get_phyinfos (e->app, &phyCount, surf);
-
-    VkhPhyInfo pi = NULL;
-    for (int i=0; i<phyCount; i++){
-        pi = phys[i];
-        if (pi->properties.deviceType == preferedGPU)
-            break;
-    }
-
-    e->memory_properties = pi->memProps;
-    e->gpu_props = pi->properties;
-
-    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 = pi->gQueue,
-                                   .pQueuePriorities = queue_priorities };
-    VkDeviceQueueCreateInfo qiC = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
-                                   .queueCount = 1,
-                                   .queueFamilyIndex = pi->cQueue,
-                                   .pQueuePriorities = queue_priorities };
-    VkDeviceQueueCreateInfo qiT = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
-                                   .queueCount = 1,
-                                   .queueFamilyIndex = pi->tQueue,
-                                   .pQueuePriorities = queue_priorities };
-
-    if (pi->gQueue == pi->cQueue){
-        if(pi->gQueue == pi->tQueue){
-            qCount=1;
-            pQueueInfos[0] = qiG;
-        }else{
-            qCount=2;
-            pQueueInfos[0] = qiG;
-            pQueueInfos[1] = qiT;
-        }
-    }else{
-        if((pi->gQueue == pi->tQueue) || (pi->cQueue==pi->tQueue)){
-            qCount=2;
-            pQueueInfos[0] = qiG;
-            pQueueInfos[1] = qiC;
-        }else{
-            qCount=3;
-            pQueueInfos[0] = qiG;
-            pQueueInfos[1] = qiC;
-            pQueueInfos[2] = qiT;
-        }
-    }
-
-    char const * dex [] = {"VK_KHR_swapchain"};
-/*#if DEBUG
-    uint32_t dlayCpt = 1;
-    static char const * dlay [] = {"VK_LAYER_LUNARG_standard_validation"};
-#else*/
-    uint32_t dlayCpt = 0;
-    static char const * dlay [] = {};
-//#endif
-    VkPhysicalDeviceFeatures enabledFeatures = {
-        .fillModeNonSolid = true,
-    };
-
-    VkDeviceCreateInfo device_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
-                                       .queueCreateInfoCount = qCount,
-                                       .pQueueCreateInfos = &pQueueInfos,
-                                       .enabledLayerCount = dlayCpt,
-                                       .ppEnabledLayerNames = dlay,
-                                       .enabledExtensionCount = 1,
-                                       .ppEnabledExtensionNames = dex,
-                                       .pEnabledFeatures = &enabledFeatures
-                                     };
-
-    VkDevice dev;
-    VK_CHECK_RESULT(vkCreateDevice (pi->phy, &device_info, NULL, &dev));
-    e->dev = vkh_device_create(pi->phy, dev);
-
-    e->renderer = vkh_presenter_create
-            (e->dev, pi->pQueue, surf, width, height, VK_FORMAT_B8G8R8A8_UNORM, VK_PRESENT_MODE_FIFO_KHR);
-
-
-    vkh_app_free_phyinfos (phyCount, phys);
-
-    return e;
-}
-
-void vkengine_destroy (VkEngine e) {
-    vkDeviceWaitIdle(e->dev->dev);
-
-    VkSurfaceKHR surf = e->renderer->surface;
-
-    vkh_presenter_destroy (e->renderer);
-    vkDestroySurfaceKHR (e->app->inst, surf, NULL);
-
-    vkDestroyDevice (e->dev->dev, NULL);
-
-    glfwDestroyWindow (e->window);
-    glfwTerminate ();
-
-    vkh_app_destroy (e->app);
-
-    free(e);
-}
-void vkengine_close (VkEngine e) {
-    glfwSetWindowShouldClose(e->window, GLFW_TRUE);
-}
-void vkengine_blitter_run (VkEngine e, VkImage img) {
-    VkhPresenter p = e->renderer;
-    vkh_presenter_build_blit_cmd (p, img);
-
-    while (!vkengine_should_close (e)) {
-        glfwPollEvents();
-        if (!vkh_presenter_draw (p))
-            vkh_presenter_build_blit_cmd (p, img);
-    }
-}
-inline bool vkengine_should_close (VkEngine e) {
-    return glfwWindowShouldClose (e->window);
-}
-
-VkDevice vkengine_get_device (VkEngine e){
-    return e->dev->dev;
-}
-VkPhysicalDevice vkengine_get_physical_device (VkEngine e){
-    return e->dev->phy;
-}
-VkQueue vkengine_get_queue (VkEngine e){
-    return e->renderer->queue;
-}
-uint32_t vkengine_get_queue_fam_idx (VkEngine e){
-    return e->renderer->qFam;
-}
-
-void vkengine_set_key_callback (VkEngine e, GLFWkeyfun key_callback){
-    glfwSetKeyCallback (e->window, key_callback);
-}
-void vkengine_set_mouse_but_callback (VkEngine e, GLFWmousebuttonfun onMouseBut){
-    glfwSetMouseButtonCallback(e->window, onMouseBut);
-}
-void vkengine_set_cursor_pos_callback (VkEngine e, GLFWcursorposfun onMouseMove){
-    glfwSetCursorPosCallback(e->window, onMouseMove);
-}
-void vkengine_set_scroll_callback (VkEngine e, GLFWscrollfun onScroll){
-    glfwSetScrollCallback(e->window, onScroll);
-}
-void vkengine_set_char_callback (VkEngine e, GLFWcharfun onChar){
-    glfwSetCharCallback(e->window, onChar);
-}
-
diff --git a/tests/vkengine.h b/tests/vkengine.h
deleted file mode 100644 (file)
index 1bf33a8..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2018 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
- * Software, and to permit persons to whom the Software is furnished to do so, subject
- * to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#ifndef VKENGINE_H
-#define VKENGINE_H
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-#include <stdbool.h>
-
-#include <GLFW/glfw3.h>
-#include <vulkan/vulkan.h>
-
-#include "vkh.h"
-
-/* Number of samples needs to be the same at image creation,      */
-/* renderpass creation and pipeline creation.                     */
-#define FENCE_TIMEOUT 100000000
-
-typedef struct _vk_engine_t* VkEngine;
-
-typedef struct _vk_engine_t {
-    VkhApp              app;
-    VkPhysicalDeviceMemoryProperties    memory_properties;
-    VkPhysicalDeviceProperties          gpu_props;
-    VkhDevice           dev;
-    GLFWwindow*         window;
-    VkhPresenter        renderer;
-}vk_engine_t;
-
-vk_engine_t*   vkengine_create  (VkPhysicalDeviceType preferedGPU, uint32_t width, uint32_t height);
-
-void vkengine_destroy       (VkEngine e);
-bool vkengine_should_close  (VkEngine e);
-void vkengine_close         (VkEngine e);
-void vkengine_dump_Infos    (VkEngine e);
-VkDevice            vkengine_get_device         (VkEngine e);
-VkPhysicalDevice    vkengine_get_physical_device(VkEngine e);
-VkQueue             vkengine_get_queue          (VkEngine e);
-uint32_t            vkengine_get_queue_fam_idx  (VkEngine e);
-
-void vkengine_get_queues_properties (vk_engine_t* e, VkQueueFamilyProperties** qFamProps, uint32_t* count);
-
-void vkengine_set_key_callback          (VkEngine e, GLFWkeyfun key_callback);
-void vkengine_set_mouse_but_callback    (VkEngine e, GLFWmousebuttonfun onMouseBut);
-void vkengine_set_cursor_pos_callback   (VkEngine e, GLFWcursorposfun onMouseMove);
-void vkengine_set_scroll_callback       (VkEngine e, GLFWscrollfun onScroll);
-void vkengine_set_char_callback         (VkEngine e, GLFWcharfun onChar);
-#endif