#include "test.h" #include #include #if defined(_WIN32) || defined(_WIN64) int gettimeofday(struct timeval *tp, void *tzp) { // FILETIME Jan 1 1970 00:00:00 // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); SYSTEMTIME nSystemTime; FILETIME nFileTime; uint64_t nTime; GetSystemTime(&nSystemTime); SystemTimeToFileTime(&nSystemTime, &nFileTime); nTime = ((uint64_t)nFileTime.dwLowDateTime); nTime += ((uint64_t)nFileTime.dwHighDateTime) << 32; tp->tv_sec = (long)((nTime - EPOCH) / 10000000L); tp->tv_usec = (long)(nSystemTime.wMilliseconds * 1000); return 0; } #endif float panX = 0.f; float panY = 0.f; float lastX = 0.f; float lastY = 0.f; float zoom = 1.0f; bool mouseDown = false; VkvgDevice device = NULL; VkvgSurface surf = NULL; uint32_t test_size = 500; // items drawn in one run, or complexity uint32_t iterations = 500; // repeat test n times uint32_t test_width = 512; uint32_t test_height = 512; bool test_vsync = false; bool quiet = false; // if true, don't print details and head row bool first_test = true; // if multiple tests, dont print header row. bool no_test_size = false; // several test consist of a single draw sequence without looping 'size' times // those test must be preceded by setting no_test_size to 'true' int test_index = 0; int single_test = -1; // if not < 0, contains the index of the single test to run static bool paused = false; static bool offscreen = false; static bool threadAware = false; static VkSampleCountFlags samples = VK_SAMPLE_COUNT_4_BIT; static VkPhysicalDeviceType preferedPhysicalDeviceType = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; static vk_engine_t *e; static char *saveToPng = 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_SPACE: paused = !paused; break; case GLFW_KEY_ESCAPE: glfwSetWindowShouldClose(window, GLFW_TRUE); break; #ifdef VKVG_WIRED_DEBUG case GLFW_KEY_F1: vkvg_wired_debug ^= (1U << 0); break; case GLFW_KEY_F2: vkvg_wired_debug ^= (1U << 1); break; case GLFW_KEY_F3: vkvg_wired_debug ^= (1U << 2); break; #endif } } static void char_callback(GLFWwindow *window, uint32_t c) {} static void mouse_move_callback(GLFWwindow *window, double x, double y) { if (mouseDown) { panX += ((float)x - lastX); panY += ((float)y - lastY); } lastX = (float)x; lastY = (float)y; } static void scroll_callback(GLFWwindow *window, double x, double y) { if (y < 0.f) zoom *= 0.5f; else zoom *= 2.0f; } static void mouse_button_callback(GLFWwindow *window, int but, int state, int modif) { if (but != GLFW_MOUSE_BUTTON_1) return; if (state == GLFW_TRUE) mouseDown = true; else mouseDown = false; } 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; } /* from caskbench */ 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; 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); } /***************/ void init_test(uint32_t width, uint32_t height) { if (test_vsync) e = vkengine_create(preferedPhysicalDeviceType, VK_PRESENT_MODE_FIFO_KHR, width, height); else e = vkengine_create(preferedPhysicalDeviceType, VK_PRESENT_MODE_MAILBOX_KHR, width, height); VkhPresenter r = e->renderer; vkengine_set_key_callback(e, key_callback); vkengine_set_mouse_but_callback(e, mouse_button_callback); vkengine_set_cursor_pos_callback(e, mouse_move_callback); vkengine_set_scroll_callback(e, scroll_callback); vkvg_device_create_info_t info = {samples, false, vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0}; device = vkvg_device_create(&info); surf = vkvg_surface_create(device, width, height); vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), width, height); } void clear_test() { vkDeviceWaitIdle(e->dev->dev); vkvg_surface_destroy(surf); vkvg_device_destroy(device); vkengine_destroy(e); } #ifdef VKVG_TEST_DIRECT_DRAW VkvgSurface *surfaces; #endif void _print_usage_and_exit() { printf("\nUsage: test [options]\n\n"); printf("\t-i iterations:\tSpecify the repeat count for the test.\n"); printf("\t-s size:\tWhen applicable, specify the size of the test.\n"); printf("\t-x width:\tOutput surface width.\n"); printf("\t-y height:\tOutput surface height.\n"); printf("\t-S num samples:\tOutput surface filter, default is 1.\n"); printf("\t-g gpu_type:\tSet prefered GPU type:\n"); printf("\t\t\t - 0: Other\n"); printf("\t\t\t - 1: Integrated (second choice)\n"); printf("\t\t\t - 2: Discrete (first choice)\n"); printf("\t\t\t - 3: Virtual\n"); printf("\t\t\t - 4: Cpu\n"); printf("\t-l line_width:\tset lines width for stokes.\n"); printf("\t-j line_join:\tset line joins for strokes:\n"); printf("\t\t\t - m: Mitter(default)\n"); printf("\t\t\t - r: Rount\n"); printf("\t\t\t - b: Bevel\n"); printf("\t-c line_cap:\tset line caps for strokes:\n"); printf("\t\t\t - b: Butt (default)\n"); printf("\t\t\t - r: Rount\n"); printf("\t\t\t - s: Square\n"); printf("\t-f fill_rule:\tset current fill rule:\n"); printf("\t\t\t - 0: Even Odd\n"); printf("\t\t\t - 1: Non Zero\n"); printf("\t-d:\t\tenable dashes.\n"); printf("\t-n index:\tRun only a single test, zero based index.\n"); printf("\t-q:\t\tQuiet, don't print measures table head row, usefull for batch tests.\n"); printf("\t-t:\t\tThread aware, set device in multithreading aware mode.\n"); printf("\t-p:\t\tPrint test details and exit without performing test, usefull to print details in logs.\n"); printf("\t-vsync:\t\tEnable VSync, disabled by default.\n"); printf("\t-o:\t\tPerform test offscreen.\n"); printf("\t-w filepath:\twrite last image to png.\n"); #ifdef DEBUG printf("\t-L level:\tLog level in hexadecimal format (0xFF), 0 to disable.\n"); printf("\t\t\tsee vkvg.h for possible values.\n"); #endif printf("\t-h:\t\tThis help message.\n"); printf("\n"); exit(-1); } void _parse_args(int argc, char *argv[]) { bool printTestDetailsAndExit = false; for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-h\0") == 0) _print_usage_and_exit(); if (strcmp(argv[i], "-p\0") == 0) printTestDetailsAndExit = true; else if (strcmp(argv[i], "-vsync\0") == 0) test_vsync = true; else if (strcmp(argv[i], "-q\0") == 0) quiet = true; else if (strcmp(argv[i], "-t\0") == 0) threadAware = true; else if (strcmp(argv[i], "-i\0") == 0) { if (argc - 1 < ++i) _print_usage_and_exit(); iterations = atoi(argv[i]); } else if (strcmp(argv[i], "-x\0") == 0) { if (argc - 1 < ++i) _print_usage_and_exit(); test_width = atoi(argv[i]); } else if (strcmp(argv[i], "-y\0") == 0) { if (argc - 1 < ++i) _print_usage_and_exit(); test_height = atoi(argv[i]); } else if (strcmp(argv[i], "-n\0") == 0) { if (argc - 1 < ++i) _print_usage_and_exit(); single_test = atoi(argv[i]); } else if (strcmp(argv[i], "-s\0") == 0) { if (argc - 1 < ++i) _print_usage_and_exit(); test_size = atoi(argv[i]); } else if (strcmp(argv[i], "-S\0") == 0) { if (argc - 1 < ++i) _print_usage_and_exit(); samples = (VkSampleCountFlags)atoi(argv[i]); } else if (strcmp(argv[i], "-g\0") == 0) { if (argc - 1 < ++i) _print_usage_and_exit(); preferedPhysicalDeviceType = (VkPhysicalDeviceType)atoi(argv[i]); } else if (strcmp(argv[i], "-l\0") == 0) { if (argc - 1 < ++i) _print_usage_and_exit(); line_width = atoi(argv[i]); } else if (strcmp(argv[i], "-d\0") == 0) { dashes_count = 2; } else if (strcmp(argv[i], "-f\0") == 0) { if (argc - 1 < ++i) _print_usage_and_exit(); fill_rule = atoi(argv[i]); } else if (strcmp(argv[i], "-o\0") == 0) { offscreen = true; } else if (strcmp(argv[i], "-j\0") == 0) { if (argc - 1 < ++i) _print_usage_and_exit(); switch (argv[i][0]) { case 'm': line_join = VKVG_LINE_JOIN_MITER; break; case 'r': line_join = VKVG_LINE_JOIN_ROUND; break; case 'b': line_join = VKVG_LINE_JOIN_BEVEL; break; default: _print_usage_and_exit(); } } else if (strcmp(argv[i], "-c\0") == 0) { if (argc - 1 < ++i) _print_usage_and_exit(); switch (argv[i][0]) { case 'b': line_cap = VKVG_LINE_CAP_BUTT; break; case 'r': line_cap = VKVG_LINE_CAP_ROUND; break; case 's': line_cap = VKVG_LINE_CAP_SQUARE; break; default: _print_usage_and_exit(); } } else if (strcmp(argv[i], "-w\0") == 0) { if (argc - 1 < ++i) _print_usage_and_exit(); saveToPng = argv[i]; #ifdef DEBUG } else if (strcmp(argv[i], "-L\0") == 0) { if (argc - 1 < ++i) _print_usage_and_exit(); sscanf(argv[i], "%x", &vkvg_log_level); #endif } else _print_usage_and_exit(); } if (printTestDetailsAndExit) { #ifdef DEBUG printf("Debug build\n"); #else printf("Release build\n"); #endif #ifdef VKVG_USE_RENDERDOC printf("Render doc enabled\n"); #endif #ifdef VKVG_USE_VALIDATION printf("Validation:\tenabled\n"); #else printf("Validation:\no\n"); #endif printf("surf dims:\t%d x %d\n", test_width, test_height); printf("Samples:\t%d\n", samples); printf("Gpu type:\t"); switch (preferedPhysicalDeviceType) { case VK_PHYSICAL_DEVICE_TYPE_OTHER: printf("Other\n"); break; case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: printf("Integrated\n"); break; case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: printf("Discrete\n"); break; case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: printf("Virtual\n"); break; case VK_PHYSICAL_DEVICE_TYPE_CPU: printf("CPU\n"); break; } if (offscreen) printf("Offscreen:\ttrue\n"); else printf("Offscreen:\tfalse\n"); if (fill_rule == VKVG_FILL_RULE_EVEN_ODD) printf("Fillrule:\tEven/Odd\n"); else printf("Fillrule:\tNon zero\n"); printf("\n"); exit(0); } } typedef struct time_struct { double start_time; double stop_time; double run_time; double run_total; double min_run_time; double max_run_time; double *run_time_values; uint32_t count; } time_struct_t; time_struct_t time_struct_create (uint32_t iterations) { time_struct_t ts = {0}; ts.run_time_values = (double *)malloc(iterations * sizeof(double)); return ts; } void time_struct_destroy (time_struct_t* ts) { free(ts->run_time_values); } void time_struct_start(time_struct_t* ts) { ts->start_time = get_tick(); } void time_struct_end(time_struct_t* ts) { ts->stop_time = get_tick(); ts->run_time = ts->stop_time - ts->start_time; ts->run_time_values[ts->count] = ts->run_time; if (ts->min_run_time < 0) ts->min_run_time = ts->run_time; else ts->min_run_time = MIN(ts->run_time, ts->min_run_time); ts->max_run_time = MAX(ts->run_time, ts->max_run_time); ts->run_total += ts->run_time; ts->count++; } void _print_results(const char *testName, int argc, char *argv[], time_struct_t* ts) { char *whoami; (whoami = strrchr(argv[0], '/')) ? ++whoami : (whoami = argv[0]); double avg_run_time = ts->run_total / (double)ts->count; double med_run_time = median_run_time(ts->run_time_values, ts->count); double standard_dev = standard_deviation(ts->run_time_values, ts->count, avg_run_time); double avg_frames_per_second = (1.0 / avg_run_time); avg_frames_per_second = (avg_frames_per_second < 9999) ? avg_frames_per_second : 9999; if (!quiet && (test_index == 0 || test_index == single_test)) { #if VKVG_DBG_STATS printf("_______________________________________________________________________________________________________" "______________________\n"); printf("| N° | Test File Name | Sub Test | Iter | Size | Pts |Pathes| Vx cache | Ix cache " "| VBO | IBO |\n"); printf("|----|-----------------|---------------------------|------|------|-------|------|----------|----------|" "----------|----------|\n"); #else printf("_______________________________________________________________________________________________________" "___\n"); printf("| N° | Test File Name | Sub Test | Iter | Size | FPS | Average | Median | Sigma " " |\n"); printf("|----|-----------------|---------------------------|------|------|---------|---------|---------|-------" "--|\n"); #endif } printf("| %2d | %-15s | %-25s | %4d | ", test_index, whoami, testName, ts->count); if (no_test_size) printf("%4d | ", 1); else printf("%4d | ", test_size); #if VKVG_DBG_STATS vkvg_debug_stats_t dbgStats = vkvg_device_get_stats(device); printf("%5d | %4d | %8d | %8d | %8d | %8d |\n", dbgStats.sizePoints, dbgStats.sizePathes, dbgStats.sizeVertices, dbgStats.sizeIndices, dbgStats.sizeVBO, dbgStats.sizeIBO); #else printf("%7.2f | %6.5f | %6.5f | %6.5f |\n", avg_frames_per_second, avg_run_time, med_run_time, standard_dev); #endif } #if VKVG_DBG_STATS void _print_debug_stats() { vkvg_debug_stats_t dbgStats = vkvg_device_get_stats(device); printf("| %8d | %8d | %8d | %8d | %8d | %8d |\n", dbgStats.sizePoints, dbgStats.sizePathes, dbgStats.sizeVertices, dbgStats.sizeIndices, dbgStats.sizeVBO, dbgStats.sizeIBO); } #endif void perform_test(void (*testfunc)(void), const char *testName, int argc, char *argv[]) { setlocale(LC_ALL, ""); // dumpLayerExts(); _parse_args(argc, argv); // init random gen struct timeval currentTime; gettimeofday(¤tTime, NULL); srand((unsigned)currentTime.tv_usec); if (iterations == 0) iterations = 9999; if (single_test >= 0 && test_index != single_test) { test_index++; return; } if (offscreen) perform_test_offscreen(testfunc, testName, argc, argv); else perform_test_onscreen(testfunc, testName, argc, argv); } void perform_test_offscreen(void (*testfunc)(void), const char *testName, int argc, char *argv[]) { uint32_t enabledExtsCount = 0, phyCount = 0; const char *enabledExts[10]; #ifdef VKVG_USE_RENDERDOC const uint32_t enabledLayersCount = 2; const char *enabledLayers[] = {"VK_LAYER_KHRONOS_validation", "VK_LAYER_RENDERDOC_Capture"}; #elif defined(VKVG_USE_VALIDATION) const uint32_t enabledLayersCount = 1; const char *enabledLayers[] = {"VK_LAYER_KHRONOS_validation"}; #else const uint32_t enabledLayersCount = 0; const char *enabledLayers[] = {NULL}; #endif #if defined(DEBUG) && defined(VKVG_DBG_UTILS) enabledExts[enabledExtsCount] = "VK_EXT_debug_utils"; enabledExtsCount++; #endif VkhApp app = vkh_app_create(1, 1, "vkvgTest", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); #if defined(DEBUG) && defined(VKVG_DBG_UTILS) vkh_app_enable_debug_messenger( app, VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT //| VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT //| VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT , NULL); #endif bool deferredResolve = false; VkhPhyInfo *phys = vkh_app_get_phyinfos(app, &phyCount, VK_NULL_HANDLE); VkhPhyInfo pi = 0; if (!vkengine_try_get_phyinfo(phys, phyCount, preferedPhysicalDeviceType, &pi)) if (!vkengine_try_get_phyinfo(phys, phyCount, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, &pi)) if (!vkengine_try_get_phyinfo(phys, phyCount, VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, &pi)) pi = phys[0]; uint32_t qCount = 0; float qPriorities[] = {0.0}; VkDeviceQueueCreateInfo pQueueInfos[] = {{0}, {0}, {0}}; if (vkh_phyinfo_create_queues(pi, pi->gQueue, 1, qPriorities, &pQueueInfos[qCount])) qCount++; VkPhysicalDeviceFeatures enabledFeatures = { .fillModeNonSolid = true, }; VkDeviceCreateInfo device_info = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .queueCreateInfoCount = qCount, .pQueueCreateInfos = (VkDeviceQueueCreateInfo *)&pQueueInfos, .pEnabledFeatures = &enabledFeatures}; VkhDevice dev = vkh_device_create(app, pi, &device_info); vkvg_device_create_info_t info = { samples, deferredResolve, vkh_app_get_inst(app), dev->phy, dev->dev, pi->gQueue, 0}; device = vkvg_device_create(&info); // vkvg_device_set_dpy(device, 96, 96); vkh_app_free_phyinfos(phyCount, phys); surf = vkvg_surface_create(device, test_width, test_height); time_struct_t ts = time_struct_create(iterations); while (ts.count < iterations) { time_struct_start(&ts); testfunc(); if (deferredResolve) vkvg_surface_resolve(surf); time_struct_end(&ts); } _print_results(testName, argc, argv, &ts); time_struct_destroy(&ts); vkDeviceWaitIdle(dev->dev); if (saveToPng) vkvg_surface_write_to_png(surf, saveToPng); vkvg_surface_destroy(surf); vkvg_device_destroy(device); vkh_device_destroy(dev); vkh_app_destroy(app); test_index++; } void perform_test_onscreen(void (*testfunc)(void), const char *testName, int argc, char *argv[]) { if (test_vsync) e = vkengine_create(preferedPhysicalDeviceType, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); else e = vkengine_create(preferedPhysicalDeviceType, VK_PRESENT_MODE_MAILBOX_KHR, test_width, test_height); VkhPresenter r = e->renderer; vkengine_set_key_callback(e, key_callback); vkengine_set_mouse_but_callback(e, mouse_button_callback); vkengine_set_cursor_pos_callback(e, mouse_move_callback); vkengine_set_scroll_callback(e, scroll_callback); vkvg_device_create_info_t info = {samples, false, vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0, threadAware}; device = vkvg_device_create(&info); vkvg_device_set_dpy(device, 96, 96); #ifdef VKVG_TEST_DIRECT_DRAW surfaces = (VkvgSurface *)malloc(r->imgCount * sizeof(VkvgSurface)); for (uint32_t i = 0; i < r->imgCount; i++) surfaces[i] = vkvg_surface_create_for_VkhImage(device, r->ScBuffers[i]); #else surf = vkvg_surface_create(device, test_width, test_height); vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); #endif time_struct_t ts = time_struct_create(iterations); vkengine_set_title(e, testName); while (!vkengine_should_close(e) && ts.count < iterations) { glfwPollEvents(); time_struct_start(&ts); #ifdef VKVG_TEST_DIRECT_DRAW if (!vkh_presenter_acquireNextImage(r, NULL, NULL)) { for (uint32_t i = 0; i < r->imgCount; i++) vkvg_surface_destroy(surfaces[i]); vkh_presenter_create_swapchain(r); for (uint32_t i = 0; i < r->imgCount; i++) surfaces[i] = vkvg_surface_create_for_VkhImage(device, r->ScBuffers[i]); } else { surf = surfaces[r->currentScBufferIndex]; testfunc(); if (deferredResolve) vkvg_multisample_surface_resolve(surf); VkPresentInfoKHR present = {.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .swapchainCount = 1, .pSwapchains = &r->swapChain, .pImageIndices = &r->currentScBufferIndex}; vkQueuePresentKHR(r->queue, &present); } #else if (paused) continue; testfunc(); if (info.deferredResolve) vkvg_surface_resolve(surf); if (!vkh_presenter_draw(r)) { vkh_presenter_get_size(r, &test_width, &test_height); vkvg_surface_destroy(surf); surf = vkvg_surface_create(device, test_width, test_height); vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); vkDeviceWaitIdle(r->dev->dev); continue; } #endif time_struct_end(&ts); } if (saveToPng) vkvg_surface_write_to_png(surf, saveToPng); _print_results(testName, argc, argv, &ts); time_struct_destroy(&ts); vkDeviceWaitIdle(e->dev->dev); #ifdef VKVG_TEST_DIRECT_DRAW for (uint32_t i = 0; i < r->imgCount; i++) vkvg_surface_destroy(surfaces[i]); free(surfaces); #else vkvg_surface_destroy(surf); #endif vkvg_device_destroy(device); vkengine_destroy(e); test_index++; } /* common context init for several tests */ vkvg_fill_rule_t fill_rule = VKVG_FILL_RULE_NON_ZERO; vkvg_line_cap_t line_cap = VKVG_LINE_CAP_BUTT; vkvg_line_join_t line_join = VKVG_LINE_JOIN_MITER; float dashes[] = {10.0f, 6.0f}; // float dashes[] = {0.0f, 10.0f}; uint32_t dashes_count = 0; float dash_offset = 0; float line_width = 2.f; VkvgContext _initCtx() { VkvgContext ctx = vkvg_create(surf); vkvg_set_line_width(ctx, line_width); vkvg_set_line_join(ctx, line_join); vkvg_set_line_cap(ctx, line_cap); vkvg_set_dash(ctx, dashes, dashes_count, dash_offset); vkvg_set_fill_rule(ctx, fill_rule); vkvg_clear(ctx); return ctx; } const int star_points[11][2] = {{0, 85}, {75, 75}, {100, 10}, {125, 75}, {200, 85}, {150, 125}, {160, 190}, {100, 150}, {40, 190}, {50, 125}, {0, 85}}; void randomize_color(VkvgContext ctx) { vkvg_set_source_rgba(ctx, rndf(), rndf(), rndf(), rndf()); } void draw_random_shape(VkvgContext ctx, shape_t shape, float sizeFact) { float w = (float)test_width; float h = (float)test_height; float x, y, z, v, r; randomize_color(ctx); switch (shape) { case SHAPE_LINE: x = rndf() * w; y = rndf() * h; z = rndf() * w; v = rndf() * h; vkvg_move_to(ctx, x, y); vkvg_line_to(ctx, z, v); vkvg_stroke(ctx); break; case SHAPE_RECTANGLE: z = truncf((sizeFact * w * rndf()) + 1.f); v = truncf((sizeFact * h * rndf()) + 1.f); x = truncf((w - z) * rndf()); y = truncf((h - v) * rndf()); vkvg_rectangle(ctx, x + 1, y + 1, z, v); break; case SHAPE_ROUNDED_RECTANGLE: z = truncf((sizeFact * w * rndf()) + 1.f); v = truncf((sizeFact * h * rndf()) + 1.f); x = truncf((w - z) * rndf()); y = truncf((h - v) * rndf()); r = truncf((0.2f * z * rndf()) + 1.f); if ((r > v / 2) || (r > z / 2)) r = MIN(v / 2, z / 2); vkvg_move_to(ctx, x, y + r); vkvg_arc(ctx, x + r, y + r, r, (float)M_PI, (float)-M_PI_2); vkvg_line_to(ctx, x + z - r, y); vkvg_arc(ctx, x + z - r, y + r, r, (float)-M_PI_2, 0); vkvg_line_to(ctx, x + z, y + v - r); vkvg_arc(ctx, x + z - r, y + v - r, r, 0, (float)M_PI_2); vkvg_line_to(ctx, x + r, y + v); vkvg_arc(ctx, x + r, y + v - r, r, (float)M_PI_2, (float)M_PI); vkvg_line_to(ctx, x, y + r); vkvg_close_path(ctx); break; case SHAPE_CIRCLE: /*x = truncf((float)w * rnd()/RAND_MAX); y = truncf((float)h * rnd()/RAND_MAX); v = truncf((float)w * rnd()/RAND_MAX * 0.2f);*/ x = rndf() * w; y = rndf() * h; r = truncf((sizeFact * MIN(w, h) * rndf()) + 1.f); /*float r = 0.5f*w*rand()/RAND_MAX; float x = truncf(0.5f * w*rand()/RAND_MAX + r); float y = truncf(0.5f * w*rand()/RAND_MAX + r);*/ vkvg_arc(ctx, x, y, r, 0, (float)M_PI * 2.0f); break; case SHAPE_TRIANGLE: case SHAPE_STAR: x = rndf() * w; y = rndf() * h; z = rndf() * sizeFact + 0.15f; // scale vkvg_move_to(ctx, x + star_points[0][0] * z, y + star_points[0][1] * z); for (int s = 1; s < 11; s++) vkvg_line_to(ctx, x + star_points[s][0] * z, y + star_points[s][1] * z); vkvg_close_path(ctx); break; case SHAPE_RANDOM: draw_random_shape(ctx, 1 + (rndf() * 4), sizeFact); break; } } void draw_random_curve(VkvgContext ctx) { float w = (float)test_width; float h = (float)test_height; float x2 = w * rndf(); float y2 = h * rndf(); float cp_x1 = w * rndf(); float cp_y1 = h * rndf(); float cp_x2 = w * rndf(); float cp_y2 = h * rndf(); vkvg_curve_to(ctx, cp_x1, cp_y1, cp_x2, cp_y2, x2, y2); } /*void draw_random_shape (VkvgContext ctx, shape_t shape) { float w = (float)test_width; float h = (float)test_height; randomize_color(ctx); float z = truncf((0.5f*w*rand()/RAND_MAX)+1.f); float v = truncf((0.5f*w*rand()/RAND_MAX)+1.f); float x = truncf((w-z)*rand()/RAND_MAX); float y = truncf((h-v)*rand()/RAND_MAX); vkvg_rectangle(ctx, x, y, z, v); }*/