From e7f0aae994656c2b8893bbf673d3659ea7bd8f7f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Fri, 18 Feb 2022 15:49:55 +0100 Subject: [PATCH] buggy font cache mutex guarding, multithreaded tests --- src/vkvg_context.c | 9 ++-- src/vkvg_context_internal.c | 7 +-- src/vkvg_context_internal.h | 31 ++++++------ src/vkvg_device.c | 4 +- src/vkvg_device_internal.c | 9 ---- src/vkvg_device_internal.h | 1 - src/vkvg_fonts.c | 54 +++++++++++++++------ src/vkvg_fonts.h | 2 + tests/multithreading/multithreaded.c | 6 ++- tests/multithreading/multithreaded2.c | 17 +++---- tests/multithreading/threaded_create_surf.c | 50 +++++++++++++++++++ vkh | 2 +- 12 files changed, 133 insertions(+), 59 deletions(-) create mode 100644 tests/multithreading/threaded_create_surf.c diff --git a/src/vkvg_context.c b/src/vkvg_context.c index dca954e..ed073b9 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -132,10 +132,10 @@ VkvgContext vkvg_create(VkvgSurface surf) _init_ctx (ctx); - ctx->points = (vec2*)malloc (VKVG_VBO_SIZE*sizeof(vec2)); - ctx->pathes = (uint32_t*)malloc (VKVG_PATHES_SIZE*sizeof(uint32_t)); - ctx->vertexCache = (Vertex*)malloc(ctx->sizeVertices * sizeof(Vertex)); - ctx->indexCache = (VKVG_IBO_INDEX_TYPE*)malloc(ctx->sizeIndices * sizeof(VKVG_IBO_INDEX_TYPE)); + ctx->points = (vec2*)malloc (VKVG_VBO_SIZE * sizeof(vec2)); + ctx->pathes = (uint32_t*)malloc (VKVG_PATHES_SIZE * sizeof(uint32_t)); + ctx->vertexCache = (Vertex*)malloc (ctx->sizeVertices * sizeof(Vertex)); + ctx->indexCache = (VKVG_IBO_INDEX_TYPE*)malloc (ctx->sizeIndices * sizeof(VKVG_IBO_INDEX_TYPE)); if (!ctx->points || !ctx->pathes || !ctx->vertexCache || !ctx->indexCache) { dev->status = VKVG_STATUS_NO_MEMORY; @@ -159,6 +159,7 @@ VkvgContext vkvg_create(VkvgSurface surf) _create_cmd_buff (ctx); _createDescriptorPool (ctx); _init_descriptor_sets (ctx); + _font_cache_update_context_descset (ctx); _update_descriptor_set (ctx, ctx->dev->fontCache->texture, ctx->dsFont); _update_descriptor_set (ctx, surf->dev->emptyImg, ctx->dsSrc); _update_gradient_desc_set(ctx); diff --git a/src/vkvg_context_internal.c b/src/vkvg_context_internal.c index c9fc67b..b1bd258 100644 --- a/src/vkvg_context_internal.c +++ b/src/vkvg_context_internal.c @@ -424,8 +424,8 @@ bool _wait_and_submit_cmd (VkvgContext ctx){ if (!_wait_flush_fence (ctx)) return false; - _device_reset_fence(ctx->pSurf->dev, ctx->flushFence); - _device_submit_cmd (ctx->pSurf->dev, &ctx->cmd, ctx->flushFence); + _device_reset_fence(ctx->dev, ctx->flushFence); + _device_submit_cmd (ctx->dev, &ctx->cmd, ctx->flushFence); if (ctx->cmd == ctx->cmdBuffers[0]) ctx->cmd = ctx->cmdBuffers[1]; @@ -591,7 +591,7 @@ void _start_cmd_for_render_pass (VkvgContext ctx) { LOG(VKVG_LOG_INFO, "START RENDER PASS: ctx = %p\n", ctx); vkh_cmd_begin (ctx->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - if (ctx->pSurf->img->layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL){ + if (ctx->pSurf->img->layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || ctx->dev->threadAware){ VkhImage imgMs = ctx->pSurf->imgMS; if (imgMs != NULL) vkh_image_set_layout(ctx->cmd, imgMs, VK_IMAGE_ASPECT_COLOR_BIT, @@ -870,6 +870,7 @@ void _release_context_ressources (VkvgContext ctx) { free(ctx->vertexCache); free(ctx->indexCache); + vkh_image_destroy (ctx->fontCacheImg); //TODO:check this for source counter //vkh_image_destroy (ctx->source); diff --git a/src/vkvg_context_internal.h b/src/vkvg_context_internal.h index cf01d58..71017be 100644 --- a/src/vkvg_context_internal.h +++ b/src/vkvg_context_internal.h @@ -126,22 +126,25 @@ typedef struct _vkvg_context_save_t { typedef struct _vkvg_context_t { //VkvgContext pPrev; //double linked list of contexts //VkvgContext pNext; - uint32_t references; //reference count + uint32_t references; //reference count VkvgDevice dev; - VkvgSurface pSurf; //surface bound to context, set on creation of ctx - VkFence flushFence; //context fence - VkhImage source; //source of painting operation - - VkCommandPool cmdPool; //local pools ensure thread safety - VkCommandBuffer cmdBuffers[2];//double cmd buff for context operations - VkCommandBuffer cmd; //current recording buffer - bool cmdStarted; //prevent flushing empty renderpass - bool pushCstDirty;//prevent pushing to gpu if not requested - VkDescriptorPool descriptorPool;//one pool per thread - VkDescriptorSet dsFont; //fonts glyphs texture atlas descriptor (local for thread safety) - VkDescriptorSet dsSrc; //source ds - VkDescriptorSet dsGrad; //gradient uniform buffer + VkvgSurface pSurf; //surface bound to context, set on creation of ctx + VkFence flushFence; //context fence + VkhImage source; //source of painting operation + + VkCommandPool cmdPool; //local pools ensure thread safety + VkCommandBuffer cmdBuffers[2]; //double cmd buff for context operations + VkCommandBuffer cmd; //current recording buffer + bool cmdStarted; //prevent flushing empty renderpass + bool pushCstDirty; //prevent pushing to gpu if not requested + VkDescriptorPool descriptorPool; //one pool per thread + VkDescriptorSet dsFont; //fonts glyphs texture atlas descriptor (local for thread safety) + VkDescriptorSet dsSrc; //source ds + VkDescriptorSet dsGrad; //gradient uniform buffer + + VkhImage fontCacheImg; //current font cache, may not be the last one, updated only if new glyphs are + //uploaded by the current context VkRect2D bounds; diff --git a/src/vkvg_device.c b/src/vkvg_device.c index 6beb912..a23c251 100644 --- a/src/vkvg_device.c +++ b/src/vkvg_device.c @@ -301,9 +301,9 @@ void vkvg_device_destroy (VkvgDevice dev) vkDestroyRenderPass (dev->vkDev, dev->renderPass_ClearAll, NULL); vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); - vkDestroyFence (dev->vkDev, dev->fence,NULL); - vkFreeCommandBuffers (dev->vkDev, dev->cmdPool, 1, &dev->cmd); + + //vkFreeCommandBuffers (dev->vkDev, dev->cmdPool, 1, &dev->cmd); vkDestroyCommandPool (dev->vkDev, dev->cmdPool, NULL); vkh_queue_destroy(dev->gQueue); diff --git a/src/vkvg_device_internal.c b/src/vkvg_device_internal.c index ca112ad..e5d26c8 100644 --- a/src/vkvg_device_internal.c +++ b/src/vkvg_device_internal.c @@ -64,15 +64,6 @@ bool _device_try_get_phyinfo (VkhPhyInfo* phys, uint32_t phyCount, VkPhysicalDev } return false; } -void _device_flush_all_contexes (VkvgDevice dev){ - /*VkvgContext ctx = dev->lastCtx; - while (ctx != NULL){ - if (ctx->cmdStarted) - _flush_cmd_until_vx_base (ctx); - - ctx = ctx->pPrev; - }*/ -} //TODO:save/reload cache in user temp directory void _device_create_pipeline_cache(VkvgDevice dev){ diff --git a/src/vkvg_device_internal.h b/src/vkvg_device_internal.h index 834664e..6cce240 100644 --- a/src/vkvg_device_internal.h +++ b/src/vkvg_device_internal.h @@ -135,7 +135,6 @@ VkRenderPass _device_createRenderPassMS (VkvgDevice dev, VkAttachmentLoadOp load VkRenderPass _device_createRenderPassNoResolve(VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp); void _device_setupPipelines (VkvgDevice dev); void _device_createDescriptorSetLayout (VkvgDevice dev); -void _device_flush_all_contexes (VkvgDevice dev); void _device_wait_idle (VkvgDevice dev); void _device_wait_and_reset_device_fence(VkvgDevice dev); void _device_submit_cmd (VkvgDevice dev, VkCommandBuffer* cmd, VkFence fence); diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c index 61fd138..17d5958 100644 --- a/src/vkvg_fonts.c +++ b/src/vkvg_fonts.c @@ -102,8 +102,6 @@ void _fonts_cache_create (VkvgDevice dev){ void _increase_font_tex_array (VkvgDevice dev){ LOG(VKVG_LOG_INFO, "_increase_font_tex_array\n"); - _device_flush_all_contexes (dev); - _font_cache_t* cache = dev->fontCache; vkWaitForFences (dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); @@ -150,9 +148,12 @@ void _increase_font_tex_array (VkvgDevice dev){ void* tmp = memset (&cache->pensY[cache->texLength],0,FONT_CACHE_INIT_LAYERS*sizeof(int)); vkh_image_destroy (cache->texture); + cache->texLength = newSize; cache->texture = newImg; + //_font_cache_update_context_descset(dev, ); + /*VkvgContext next = dev->lastCtx; while (next != NULL){ _update_descriptor_set (next, cache->texture, next->dsFont); @@ -287,6 +288,19 @@ void _font_cache_destroy (VkvgDevice dev){ } +void _font_cache_update_context_descset (VkvgContext ctx) { + if (ctx->fontCacheImg) + vkh_image_destroy (ctx->fontCacheImg); + + LOCK_FONTCACHE (ctx->dev) + + ctx->fontCacheImg = ctx->dev->fontCache->texture; + vkh_image_reference (ctx->fontCacheImg); + + _update_descriptor_set (ctx, ctx->fontCacheImg, ctx->dsFont); + + UNLOCK_FONTCACHE (ctx->dev) +} //create a new char entry and put glyph in stagging buffer, ready for upload. _char_ref* _prepare_char (VkvgDevice dev, VkvgText tr, uint32_t gindex){ _vkvg_font_t* f = tr->font; @@ -464,6 +478,8 @@ bool _tryFindFontByName (VkvgContext ctx, _vkvg_font_identity_t** font){ } return false; } + +#ifdef VKVG_USE_FONTCONFIG bool _tryResolveFontNameWithFontConfig (VkvgContext ctx, _vkvg_font_identity_t** resolvedFont) { LOCK_FONTCACHE(ctx->dev) @@ -471,7 +487,6 @@ bool _tryResolveFontNameWithFontConfig (VkvgContext ctx, _vkvg_font_identity_t** _font_cache_t* cache = (_font_cache_t*)ctx->dev->fontCache; char* fontFile = NULL; -#ifdef VKVG_USE_FONTCONFIG FcPattern* pat = FcNameParse((const FcChar8*)ctx->selectedFontName); FcConfigSubstitute(cache->config, pat, FcMatchPattern); FcDefaultSubstitute(pat); @@ -479,7 +494,6 @@ bool _tryResolveFontNameWithFontConfig (VkvgContext ctx, _vkvg_font_identity_t** FcPattern* font = FcFontMatch(cache->config, pat, &result); if (font) FcPatternGetString(font, FC_FILE, 0, (FcChar8 **)&fontFile); -#endif *resolvedFont = NULL; if (fontFile) { //try find font in cache by path @@ -498,15 +512,14 @@ bool _tryResolveFontNameWithFontConfig (VkvgContext ctx, _vkvg_font_identity_t** } } -#ifdef VKVG_USE_FONTCONFIG FcPatternDestroy(pat); FcPatternDestroy(font); -#endif UNLOCK_FONTCACHE(ctx->dev) return (fontFile != NULL); } +#endif //try to find corresponding font in cache (defined by context selectedFont) and create a new font entry if not found. @@ -516,8 +529,16 @@ void _update_current_font (VkvgContext ctx) { if (ctx->selectedFontName[0] == 0) _select_font_face (ctx, "sans"); - if (!_tryFindFontByName(ctx, &ctx->currentFont)) + if (!_tryFindFontByName (ctx, &ctx->currentFont)) { +#ifdef VKVG_USE_FONTCONFIG _tryResolveFontNameWithFontConfig (ctx, &ctx->currentFont); +#else + LOG(VKVG_LOG_ERR, "Unresolved font: %s\n", ctx->selectedFontName); + UNLOCK_FONTCACHE(ctx->dev) + ctx->status = VKVG_STATUS_INVALID_FONT; + return; +#endif + } ctx->currentFontSize = _find_or_create_font_size (ctx); UNLOCK_FONTCACHE(ctx->dev) @@ -635,6 +656,11 @@ void _font_cache_create_text_run (VkvgContext ctx, const char* text, VkvgText te UNLOCK_FONTCACHE (ctx->dev) + if (ctx->fontCacheImg != ctx->dev->fontCache->texture) { + vkvg_flush (ctx); + _font_cache_update_context_descset (ctx); + } + unsigned int string_width_in_pixels = 0; for (uint32_t i=0; i < textRun->glyph_count; ++i) string_width_in_pixels += textRun->glyphs[i].x_advance >> 6; @@ -697,14 +723,14 @@ void _font_cache_show_text_run (VkvgContext ctx, VkvgText tr) { for (uint32_t i=0; i < glyph_count; ++i) { _char_ref* cr = tr->font->charLookup[glyph_info[i].codepoint]; - - if (cr==NULL) - cr = _prepare_char(tr->dev, tr, glyph_info[i].codepoint); + assert((cr!=NULL) && "char lookup failed in _show_text_run."); + /*if (cr==NULL) + cr = _prepare_char(tr->dev, tr, glyph_info[i].codepoint);*/ //continue; - if (cr!=NULL){ - float uvWidth = cr->bounds.width / (float)FONT_PAGE_SIZE; - float uvHeight = cr->bounds.height / (float)FONT_PAGE_SIZE; + //if (cr!=NULL){ + float uvWidth = cr->bounds.width / (float)FONT_PAGE_SIZE; + float uvHeight = cr->bounds.height / (float)FONT_PAGE_SIZE; vec2 p0 = {pen.x + cr->bmpDiff.x + (tr->glyphs[i].x_offset >> 6), pen.y - cr->bmpDiff.y + (tr->glyphs[i].y_offset >> 6)}; v.pos = p0; @@ -732,7 +758,7 @@ void _font_cache_show_text_run (VkvgContext ctx, VkvgText tr) { _add_vertex(ctx,v); _add_tri_indices_for_rect (ctx, firstIdx); - } + //} pen.x += (tr->glyphs[i].x_advance >> 6); pen.y -= (tr->glyphs[i].y_advance >> 6); diff --git a/src/vkvg_fonts.h b/src/vkvg_fonts.h index d7d656a..33cdccd 100644 --- a/src/vkvg_fonts.h +++ b/src/vkvg_fonts.h @@ -201,4 +201,6 @@ void _font_cache_create_text_run (VkvgContext ctx, const char* text, VkvgText t void _font_cache_destroy_text_run (VkvgText textRun); //Draw text run void _font_cache_show_text_run (VkvgContext ctx, VkvgText tr); +//update context font cache descriptor set +void _font_cache_update_context_descset (VkvgContext ctx); #endif diff --git a/tests/multithreading/multithreaded.c b/tests/multithreading/multithreaded.c index bd14e84..4981860 100644 --- a/tests/multithreading/multithreaded.c +++ b/tests/multithreading/multithreaded.c @@ -1,7 +1,11 @@ +/* + * multiple contexts in separate thread on temp surface for each thread + * guarded blit on final surface. + */ #include "test.h" #include "tinycthread.h" -#define THREAD_COUNT 16 +#define THREAD_COUNT 64 static int finishedThreadCount = 0; diff --git a/tests/multithreading/multithreaded2.c b/tests/multithreading/multithreaded2.c index 0485d13..7821581 100644 --- a/tests/multithreading/multithreaded2.c +++ b/tests/multithreading/multithreaded2.c @@ -1,3 +1,6 @@ +/* + * drawing from multiple contexts in separate threads on a single unguarded surface + */ #include "test.h" #include "tinycthread.h" @@ -17,23 +20,16 @@ void drawRandomRect (VkvgContext ctx, float s) { vkvg_rectangle(ctx, x, y, s, s); } -void _before_submit (void* data) { - mtx_lock((mtx_t*)data); -} -void _after_submit (void* data) { - mtx_unlock((mtx_t*)data); -} - int drawRectsThread () { VkvgContext ctx = vkvg_create(surf); for (uint32_t i=0; i