From d9d2d2bba31ebcc34ae28843c8d4eef223d023c9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Fri, 6 Sep 2019 00:57:50 +0200 Subject: [PATCH] dyn sizing of vbo and ibo buffers --- include/vkvg.h | 1 + src/vkvg_context.c | 18 +++-- src/vkvg_context_internal.c | 148 +++++++++++++++++++++++++++--------- src/vkvg_context_internal.h | 20 ++--- tests/common/test.c | 123 +++++++++++++++++++++++------- tests/common/test.h | 12 ++- tests/hlines.c | 2 +- tests/lines.c | 6 +- tests/multilines.c | 6 +- tests/random_cirles.c | 20 ++--- tests/random_rects.c | 10 ++- tests/svg.c | 1 + tests/vlines.c | 2 +- 13 files changed, 266 insertions(+), 103 deletions(-) diff --git a/include/vkvg.h b/include/vkvg.h index 5cfdff0..c637625 100644 --- a/include/vkvg.h +++ b/include/vkvg.h @@ -40,6 +40,7 @@ extern "C" { #define LOG_DEBUG 0x10 #define LOG_INFO 0x20 #define LOG_INFO_PATH 0x40 +#define LOG_DBG_ARRAYS 0x80 #define LOG_FULL 0xff #ifdef DEBUG diff --git a/src/vkvg_context.c b/src/vkvg_context.c index edb9c19..7917f6a 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -57,8 +57,8 @@ VkvgContext vkvg_create(VkvgSurface surf) } ctx->sizePoints = VKVG_PTS_SIZE; - ctx->sizeVertices = VKVG_VBO_SIZE; - ctx->sizeIndices = VKVG_IBO_SIZE; + ctx->sizeVertices = ctx->sizeVBO = VKVG_VBO_SIZE; + ctx->sizeIndices = ctx->sizeIBO = VKVG_IBO_SIZE; ctx->sizePathes = VKVG_PATHES_SIZE; ctx->lineWidth = 1; ctx->pSurf = surf; @@ -121,6 +121,9 @@ VkvgContext vkvg_create(VkvgSurface surf) //for context to be thread safe, command pool and descriptor pool have to be created in the thread of the context. ctx->cmdPool = vkh_cmd_pool_create ((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + ctx->vertexCache = (Vertex*)malloc(ctx->sizeVertices * sizeof(Vertex)); + ctx->indexCache = (VKVG_IBO_INDEX_TYPE*)malloc(ctx->sizeIndices * sizeof(VKVG_IBO_INDEX_TYPE)); + _create_vertices_buff (ctx); _create_gradient_buff (ctx); _create_cmd_buff (ctx); @@ -136,6 +139,9 @@ VkvgContext vkvg_create(VkvgSurface surf) ctx->references = 1; ctx->status = VKVG_STATUS_SUCCESS; + + LOG(LOG_DBG_ARRAYS, "START\tctx = %lu; pathes:%d pts:%d vch:%d vbo:%d ich:%d ibo:%d\n", ctx, ctx->sizePathes, ctx->sizePoints, ctx->sizeVertices, ctx->sizeVBO, ctx->sizeIndices, ctx->sizeIBO); + return ctx; } /** @@ -240,6 +246,8 @@ void vkvg_destroy (VkvgContext ctx) ctx->pNext->pPrev = ctx->pPrev; } + LOG(LOG_DBG_ARRAYS, "END\tctx = %lu; pathes:%d pts:%d vch:%d vbo:%d ich:%d ibo:%d\n", ctx, ctx->sizePathes, ctx->sizePoints, ctx->sizeVertices, ctx->sizeVBO, ctx->sizeIndices, ctx->sizeIBO); + free(ctx); } /** @@ -502,9 +510,6 @@ void vkvg_clip_preserve (VkvgContext ctx){ LOG(LOG_INFO, "CLIP: ctx = %lu; path cpt = %d;\n", ctx, ctx->pathPtr / 2); - _check_flush_needed (ctx); - - if (ctx->curFillRule == VKVG_FILL_RULE_EVEN_ODD){ _check_cmd_buff_state(ctx); _poly_fill (ctx); @@ -535,7 +540,6 @@ void vkvg_fill_preserve (VkvgContext ctx){ LOG(LOG_INFO, "FILL: ctx = %lu; path cpt = %d;\n", ctx, ctx->pathPtr / 2); - _check_flush_needed (ctx); _check_cmd_buff_state (ctx); if (ctx->curFillRule == VKVG_FILL_RULE_EVEN_ODD){ @@ -557,8 +561,6 @@ void vkvg_stroke_preserve (VkvgContext ctx) LOG(LOG_INFO, "STROKE: ctx = %lu; path cpt = %d;\n", ctx, ctx->pathPtr / 2); - _check_flush_needed (ctx); - Vertex v = {0}; v.uv.z = -1; diff --git a/src/vkvg_context_internal.c b/src/vkvg_context_internal.c index 4be4550..f09f300 100644 --- a/src/vkvg_context_internal.c +++ b/src/vkvg_context_internal.c @@ -179,18 +179,14 @@ void _create_gradient_buff (VkvgContext ctx){ sizeof(vkvg_gradient_t), &ctx->uboGrad); } void _create_vertices_buff (VkvgContext ctx){ - - ctx->vertexCache = (Vertex*)malloc(ctx->sizeVertices * sizeof(Vertex)); - ctx->indexCache = (VKVG_IBO_INDEX_TYPE*)malloc(ctx->sizeIndices * sizeof(VKVG_IBO_INDEX_TYPE)); - vkvg_buffer_create (ctx->pSurf->dev, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU, - ctx->sizeVertices * sizeof(Vertex), &ctx->vertices); + ctx->sizeVBO * sizeof(Vertex), &ctx->vertices); vkvg_buffer_create (ctx->pSurf->dev, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU, - ctx->sizeIndices * sizeof(VKVG_IBO_INDEX_TYPE), &ctx->indices); + ctx->sizeIBO * sizeof(VKVG_IBO_INDEX_TYPE), &ctx->indices); } const vec3 blankuv = {}; void _add_vertexf (VkvgContext ctx, float x, float y){ @@ -199,15 +195,19 @@ void _add_vertexf (VkvgContext ctx, float x, float y){ pVert->pos.y = y; pVert->uv = blankuv; ctx->vertCount++; + + _check_vbo_size(ctx); } void _add_vertex(VkvgContext ctx, Vertex v){ ctx->vertexCache[ctx->vertCount] = v; ctx->vertCount++; + + _check_vbo_size(ctx); } void _set_vertex(VkvgContext ctx, uint32_t idx, Vertex v){ ctx->vertexCache[idx] = v; } -void _add_tri_indices_for_rect (VkvgContext ctx, uint32_t i){ +void _add_tri_indices_for_rect (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i){ VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache[ctx->indCount]; inds[0] = i; inds[1] = i+2; @@ -216,13 +216,17 @@ void _add_tri_indices_for_rect (VkvgContext ctx, uint32_t i){ inds[4] = i+2; inds[5] = i+3; ctx->indCount+=6; + + _check_ibo_size(ctx); } -void _add_triangle_indices(VkvgContext ctx, uint32_t i0, uint32_t i1, uint32_t i2){ +void _add_triangle_indices(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2){ VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache[ctx->indCount]; inds[0] = i0; inds[1] = i1; inds[2] = i2; ctx->indCount+=3; + + _check_ibo_size(ctx); } void _vao_add_rectangle (VkvgContext ctx, float x, float y, float width, float height){ Vertex v[4] = @@ -232,10 +236,13 @@ void _vao_add_rectangle (VkvgContext ctx, float x, float y, float width, float h {{x+width,y}, {0,0,-1}}, {{x+width,y+height},{0,0,-1}} }; - uint32_t firstIdx = ctx->vertCount; + VKVG_IBO_INDEX_TYPE firstIdx = ctx->vertCount; Vertex* pVert = &ctx->vertexCache[ctx->vertCount]; memcpy (pVert,v,4*sizeof(Vertex)); ctx->vertCount+=4; + + _check_vbo_size(ctx); + _add_tri_indices_for_rect(ctx, firstIdx); } @@ -251,22 +258,6 @@ void _create_cmd_buff (VkvgContext ctx){ vkh_device_set_object_name((VkhDevice)ctx->pSurf->dev, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)ctx->cmd, "vkvgCtxCmd"); #endif } -void _record_draw_cmd (VkvgContext ctx){ - if (ctx->indCount == ctx->curIndStart) - return; - LOG(LOG_INFO, "RECORD DRAW CMD: ctx = %lu; vertices = %d; indices = %d\n", (ulong)ctx, ctx->vertCount - ctx->indexCache[ctx->curIndStart], ctx->indCount - ctx->curIndStart); - _check_cmd_buff_state(ctx); - CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); - -#ifdef VKVG_WIRED_DEBUG - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineWired); - CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, 0, 1); - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipe_OVER); -#endif - - ctx->curIndStart = ctx->indCount; - ctx->curVertOffset = ctx->vertCount; -} void _clear_attachment (VkvgContext ctx) { } @@ -315,13 +306,25 @@ void _wait_and_submit_cmd (VkvgContext ctx){ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL , VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); }*/ -//this func expect cmdStarted to be true, so that vert and ind count are > 0 -void _end_render_pass (VkvgContext ctx) { - _record_draw_cmd (ctx); - LOG(LOG_INFO, "END RENDER PASS: ctx = %lu;\n", ctx); - CmdEndRenderPass (ctx->cmd); - ctx->renderPassBeginInfo.renderPass = ctx->pSurf->dev->renderPass; +//pre flush vertices because of vbo or ibo too small, all vertices except last draw call are flushed +//this function expects a vertex offset > 0 +void _flush_vertices_caches_until_vertex_base (VkvgContext ctx) { + _wait_flush_fence (ctx); + + memcpy(ctx->vertices.allocInfo.pMappedData, ctx->vertexCache, ctx->curVertOffset * sizeof (Vertex)); + memcpy(ctx->indices.allocInfo.pMappedData, ctx->indexCache, ctx->curIndStart * sizeof (VKVG_IBO_INDEX_TYPE)); + + //copy remaining vertices and indices to caches starts + ctx->vertCount -= ctx->curVertOffset; + ctx->indCount -= ctx->curIndStart; + memcpy(ctx->vertexCache, &ctx->vertexCache[ctx->curVertOffset], ctx->vertCount * sizeof (Vertex)); + memcpy(ctx->indexCache, &ctx->indexCache[ctx->curIndStart], ctx->indCount * sizeof (VKVG_IBO_INDEX_TYPE)); + + ctx->curVertOffset = 0; + ctx->curIndStart = 0; +} +void _flush_vertices_caches (VkvgContext ctx) { //copy vertex and index caches to the vbo and ibo vkbuffers _wait_flush_fence (ctx); @@ -330,12 +333,59 @@ void _end_render_pass (VkvgContext ctx) { ctx->vertCount = ctx->indCount = ctx->curIndStart = ctx->curVertOffset = 0; } +//this func expect cmdStarted to be true +void _end_render_pass (VkvgContext ctx) { + LOG(LOG_INFO, "END RENDER PASS: ctx = %lu;\n", ctx); + CmdEndRenderPass (ctx->cmd); + ctx->renderPassBeginInfo.renderPass = ctx->pSurf->dev->renderPass; +} +void _record_draw_cmd (VkvgContext ctx){ + if (ctx->indCount == ctx->curIndStart) + return; + + if (ctx->vertCount > ctx->sizeVBO || ctx->indCount > ctx->sizeIBO){ + //vbo or ibo buffers too small + if (ctx->cmdStarted) { + //if cmd is started buffers, are already bound, so no resize is possible + //instead we flush, and clear vbo and ibo caches + _end_render_pass (ctx); + _flush_vertices_caches_until_vertex_base (ctx); + vkh_cmd_end (ctx->cmd); + _wait_and_submit_cmd (ctx); + //we could resize here + }else{ + //should resize vbo here + _wait_flush_fence (ctx); + ctx->sizeVBO = ctx->sizeVertices; + ctx->sizeIBO = ctx->sizeIndices; + vkvg_buffer_destroy (&ctx->indices); + vkvg_buffer_destroy (&ctx->vertices); + _create_vertices_buff (ctx); + } + } + + _check_cmd_buff_state(ctx); + CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); + + LOG(LOG_INFO, "RECORD DRAW CMD: ctx = %lu; vertices = %d; indices = %d\n", (ulong)ctx, ctx->vertCount - ctx->indexCache[ctx->curIndStart], ctx->indCount - ctx->curIndStart); + +#ifdef VKVG_WIRED_DEBUG + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineWired); + CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipe_OVER); +#endif + + ctx->curIndStart = ctx->indCount; + ctx->curVertOffset = ctx->vertCount; +} void _flush_cmd_buff (VkvgContext ctx){ if (!ctx->cmdStarted) return; - _end_render_pass (ctx); - vkh_cmd_end (ctx->cmd); + _record_draw_cmd (ctx); + _end_render_pass (ctx); + _flush_vertices_caches (ctx); + vkh_cmd_end (ctx->cmd); LOG(LOG_INFO, "FLUSH CTX: ctx = %lu; vertices = %d; indices = %d\n", ctx, ctx->vertCount, ctx->indCount); _wait_and_submit_cmd(ctx); @@ -434,9 +484,11 @@ void _update_cur_pattern (VkvgContext ctx, VkvgPattern pat) { VkvgSurface surf = (VkvgSurface)pat->data; //flush ctx in two steps to add the src transitioning in the cmd buff - if (ctx->cmdStarted)//transition of img without appropriate dependencies in subpass must be done outside renderpass. + if (ctx->cmdStarted){//transition of img without appropriate dependencies in subpass must be done outside renderpass. + _record_draw_cmd (ctx);//ensure all vertices are flushed _end_render_pass (ctx); - else { + _flush_vertices_caches (ctx); + }else { vkh_cmd_begin (ctx->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); ctx->cmdStarted = true; } @@ -903,10 +955,30 @@ void _recursive_bezier (VkvgContext ctx, _recursive_bezier (ctx, x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1); } void _poly_fill (VkvgContext ctx){ + //we anticipate the check for vbo buffer size + if (ctx->vertCount + ctx->pointCount > ctx->sizeVBO) { + if (ctx->cmdStarted) { + _end_render_pass (ctx); + _flush_vertices_caches (ctx); + vkh_cmd_end (ctx->cmd); + _wait_and_submit_cmd (ctx); + //we could resize here after a wait fence + }else{ + _wait_flush_fence (ctx);//wait previous cmd if not completed + ctx->sizeVBO = ctx->vertCount + ctx->pointCount; + vkvg_buffer_destroy (&ctx->vertices); + vkvg_buffer_create (ctx->pSurf->dev, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VMA_MEMORY_USAGE_CPU_TO_GPU, + ctx->sizeVBO * sizeof(Vertex), &ctx->vertices); + } + _start_cmd_for_render_pass(ctx); + } + CmdBindPipeline (ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelinePolyFill); uint32_t ptrPath = 0; - Vertex v = {}; + Vertex v = {0}; v.uv.z = -1; while (ptrPath < ctx->pathPtr){ @@ -920,7 +992,8 @@ void _poly_fill (VkvgContext ctx){ uint32_t firstPtIdx = ctx->pathes [ptrPath] & PATH_ELT_MASK; uint32_t lastPtIdx = ctx->pathes [ptrPath+1] & PATH_ELT_MASK;//_get_last_point_of_closed_path (ctx, ptrPath); uint32_t pathPointCount = lastPtIdx - firstPtIdx + 1; - uint32_t firstVertIdx = ctx->vertCount; + + VKVG_IBO_INDEX_TYPE firstVertIdx = ctx->vertCount; for (uint i = 0; i < pathPointCount; i++) { v.pos = ctx->points [i+firstPtIdx]; @@ -932,6 +1005,7 @@ void _poly_fill (VkvgContext ctx){ ptrPath+=2; } + ctx->curVertOffset = ctx->vertCount; } void _fill_ec (VkvgContext ctx){ uint32_t ptrPath = 0;; diff --git a/src/vkvg_context_internal.h b/src/vkvg_context_internal.h index 622cbe8..d69f944 100644 --- a/src/vkvg_context_internal.h +++ b/src/vkvg_context_internal.h @@ -28,11 +28,11 @@ #include "vkh.h" #include "vkvg_fonts.h" -#define VKVG_PTS_SIZE 4096 -#define VKVG_VBO_SIZE VKVG_PTS_SIZE * 8 +#define VKVG_PTS_SIZE 256 +#define VKVG_VBO_SIZE VKVG_PTS_SIZE * 4 #define VKVG_IBO_SIZE VKVG_VBO_SIZE * 6 #define VKVG_PATHES_SIZE 16 -#define VKVG_ARRAY_THRESHOLD 4 +#define VKVG_ARRAY_THRESHOLD 8 #define VKVG_IBO_INDEX_TYPE uint16_t typedef struct{ @@ -97,15 +97,17 @@ typedef struct _vkvg_context_t { //vk buffers, holds data until flush vkvg_buff indices; //index buffer with persistent map memory + size_t sizeIBO; //size of vk ibo size size_t sizeIndices; //reserved size - uint32_t indCount; //current indice count + VKVG_IBO_INDEX_TYPE indCount; //current indice count - uint32_t curIndStart; //last index recorded in cmd buff - uint32_t curVertOffset; //vertex offset in draw indexed command + VKVG_IBO_INDEX_TYPE curIndStart; //last index recorded in cmd buff + VKVG_IBO_INDEX_TYPE curVertOffset; //vertex offset in draw indexed command vkvg_buff vertices; //vertex buffer with persistent mapped memory + size_t sizeVBO; //size of vk vbo size size_t sizeVertices; //reserved size - uint32_t vertCount; //effective vertices count + VKVG_IBO_INDEX_TYPE vertCount; //effective vertices count Vertex* vertexCache; VKVG_IBO_INDEX_TYPE* indexCache; @@ -188,8 +190,8 @@ void _create_vertices_buff (VkvgContext ctx); void _add_vertex (VkvgContext ctx, Vertex v); void _add_vertexf (VkvgContext ctx, float x, float y); void _set_vertex (VkvgContext ctx, uint32_t idx, Vertex v); -void _add_triangle_indices (VkvgContext ctx, uint32_t i0, uint32_t i1,uint32_t i2); -void _add_tri_indices_for_rect (VkvgContext ctx, uint32_t i); +void _add_triangle_indices (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2); +void _add_tri_indices_for_rect (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i); void _build_vb_step (vkvg_context* ctx, Vertex v, float hw, uint32_t iL, uint32_t i, uint32_t iR, bool isCurve); void _vao_add_rectangle (VkvgContext ctx, float x, float y, float width, float height); diff --git a/tests/common/test.c b/tests/common/test.c index 5b662e6..362ff31 100644 --- a/tests/common/test.c +++ b/tests/common/test.c @@ -10,15 +10,19 @@ bool mouseDown = false; VkvgDevice device = NULL; VkvgSurface surf = NULL; -uint iterations = 1000; // items drawn in one run, or complexity -uint runs = 10; // repeat test n times +uint test_size = 250; // items drawn in one run, or complexity +int iterations = 100; // repeat test n times +static bool paused = false; static vk_engine_t* e; 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; @@ -68,6 +72,42 @@ void randomize_color (VkvgContext ctx) { 0.5f//0.8f*rand()/RAND_MAX + 0.2f ); } +/* 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; + 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); +} +/***************/ void init_test (uint width, uint height){ e = vkengine_create (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_MAILBOX_KHR, width, height); @@ -91,15 +131,18 @@ void run_test_func (void(*testfunc)(void),uint width, uint height) { bool deferredResolve = false; VkhPresenter r = e->renderer; - struct timeval before , after; - double frameTime = 0, frameTimeAccum = 0, frameCount = 0; + double start_time, stop_time, run_time, run_total, min_run_time = -1, max_run_time; + double run_time_values[iterations]; + + int i = 0; - while (!vkengine_should_close (e)) { + while (!vkengine_should_close (e) && i < iterations) { glfwPollEvents(); - gettimeofday(&before , NULL); + start_time = get_tick(); - testfunc(); + if (!paused) + testfunc(); if (deferredResolve) vkvg_multisample_surface_resolve(surf); @@ -108,14 +151,26 @@ void run_test_func (void(*testfunc)(void),uint width, uint height) { vkDeviceWaitIdle(e->dev->dev); - gettimeofday(&after , NULL); - - frameTimeAccum += time_diff(before , after); - frameCount++; + stop_time = get_tick(); + run_time = stop_time - start_time; + run_time_values[i] = run_time; + + if (min_run_time < 0) + min_run_time = run_time; + else + min_run_time = MIN(run_time, min_run_time); + max_run_time = MAX(run_time, max_run_time); + run_total += run_time; + i++; } - frameTime = frameTimeAccum / frameCount; - printf ("frame (µs): %.0lf\nfps: %lf\n", frameTime, floor(1000000 / frameTime)); + double avg_run_time = run_total / (double)iterations; + double med_run_time = median_run_time (run_time_values, iterations); + double standard_dev = standard_deviation (run_time_values, iterations, 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; + + printf ("size:%d iter:%d avgFps: %f avg: %4.2f%% med: %4.2f%% sd: %4.2f%% \n", test_size, iterations, avg_frames_per_second, avg_run_time, med_run_time, standard_dev); } void clear_test () { @@ -143,7 +198,7 @@ void perform_test (void(*testfunc)(void),uint width, uint height) { bool deferredResolve = false; - device = vkvg_device_create_multisample(vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0, VK_SAMPLE_COUNT_4_BIT, deferredResolve); + device = vkvg_device_create_multisample(vkh_app_get_inst(e->app), r->dev->phy, r->dev->dev, r->qFam, 0, VK_SAMPLE_COUNT_1_BIT, deferredResolve); vkvg_device_set_dpy(device, 96, 96); @@ -155,13 +210,17 @@ void perform_test (void(*testfunc)(void),uint width, uint height) { surf = vkvg_surface_create(device, width, height); vkh_presenter_build_blit_cmd (r, vkvg_surface_get_vk_image(surf), width, height); #endif - struct timeval before , after; - double frameTime = 0, frameTimeAccum = 0, frameCount = 0; - while (!vkengine_should_close (e)) { + + double start_time, stop_time, run_time, run_total, min_run_time = -1, max_run_time; + double run_time_values[iterations]; + + int i = 0; + + while (!vkengine_should_close (e) && i < iterations) { glfwPollEvents(); - gettimeofday(&before , NULL); + start_time = get_tick(); #ifdef VKVG_TEST_DIRECT_DRAW @@ -189,7 +248,8 @@ void perform_test (void(*testfunc)(void),uint width, uint height) { vkQueuePresentKHR(r->queue, &present); } #else - testfunc(); + if (!paused) + testfunc(); if (deferredResolve) vkvg_multisample_surface_resolve(surf); @@ -199,15 +259,26 @@ void perform_test (void(*testfunc)(void),uint width, uint height) { vkDeviceWaitIdle(e->dev->dev); - gettimeofday(&after , NULL); - - frameTimeAccum += time_diff(before , after); - frameCount++; - //fflush(stdout); + stop_time = get_tick(); + run_time = stop_time - start_time; + run_time_values[i] = run_time; + + if (min_run_time < 0) + min_run_time = run_time; + else + min_run_time = MIN(run_time, min_run_time); + max_run_time = MAX(run_time, max_run_time); + run_total += run_time; + i++; } - frameTime = frameTimeAccum / frameCount; - printf ("frame (µs): %.0lf\nfps: %lf\n", frameTime, floor(1000000 / frameTime)); + double avg_run_time = run_total / (double)iterations; + double med_run_time = median_run_time (run_time_values, iterations); + double standard_dev = standard_deviation (run_time_values, iterations, 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; + + printf ("size:%d iter:%d avgFps: %f avg: %4.2f%% med: %4.2f%% sd: %4.2f%% \n", test_size, iterations, avg_frames_per_second, avg_run_time, med_run_time, standard_dev); vkDeviceWaitIdle(e->dev->dev); diff --git a/tests/common/test.h b/tests/common/test.h index 8d15d05..f916c45 100644 --- a/tests/common/test.h +++ b/tests/common/test.h @@ -10,6 +10,14 @@ #define M_PIF 3.14159265359f /* float pi */ #define M_PIF_MULT_2 6.28318530718f +#ifndef MIN +# define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX +# define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + #ifdef _WIN32 // MSC_VER #define WIN32_LEAN_AND_MEAN #define NOMINMAX @@ -66,8 +74,8 @@ #include #endif // _WIN32 -extern uint iterations; -extern uint runs; +extern uint test_size; +extern int iterations; extern float panX; extern float panY; diff --git a/tests/hlines.c b/tests/hlines.c index d5a40a2..90d0451 100644 --- a/tests/hlines.c +++ b/tests/hlines.c @@ -14,7 +14,7 @@ void test(){ vkvg_set_line_width(ctx,1); //vkvg_set_line_join(ctx,VKVG_LINE_JOIN_BEVEL); - for (uint i=0; i