From: Jean-Philippe Bruyère Date: Wed, 26 Jan 2022 21:01:48 +0000 (+0100) Subject: test threadctx X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=refs%2Fheads%2Fthreadctxtests;p=jp%2Fvkvg.git test threadctx --- diff --git a/src/vkvg_context.c b/src/vkvg_context.c index 152bbb1..981ad55 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -128,7 +128,8 @@ VkvgContext vkvg_create(VkvgSurface surf) return NULL; } - ctx->flushFence = vkh_fence_create_signaled ((VkhDevice)dev); + _sync_context_init ((VkhDevice)dev, &ctx->syncCtx); + //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); @@ -154,7 +155,9 @@ VkvgContext vkvg_create(VkvgSurface surf) vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_POOL, (uint64_t)ctx->cmdPool, "CTX Cmd Pool"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)ctx->cmdBuffers[0], "CTX Cmd Buff A"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)ctx->cmdBuffers[1], "CTX Cmd Buff B"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_FENCE, (uint64_t)ctx->flushFence, "CTX Flush Fence"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_FENCE, (uint64_t)ctx->syncCtx.fence, "CTX Flush Fence"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_SEMAPHORE, (uint64_t)ctx->syncCtx.signals[0], "CTX Semaphore A"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_SEMAPHORE, (uint64_t)ctx->syncCtx.signals[1], "CTX Semaphore B"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_POOL, (uint64_t)ctx->descriptorPool, "CTX Descriptor Pool"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsSrc, "CTX DescSet SOURCE"); @@ -235,10 +238,12 @@ void vkvg_destroy (VkvgContext ctx) #endif - vkDestroyFence (dev, ctx->flushFence,NULL); + vkFreeCommandBuffers(dev, ctx->cmdPool, 2, ctx->cmdBuffers); vkDestroyCommandPool(dev, ctx->cmdPool, NULL); + _sync_context_clear (&ctx->syncCtx); + VkDescriptorSet dss[] = {ctx->dsFont,ctx->dsSrc, ctx->dsGrad}; vkFreeDescriptorSets (dev, ctx->descriptorPool, 3, dss); diff --git a/src/vkvg_context_internal.c b/src/vkvg_context_internal.c index c191c4e..39471b8 100644 --- a/src/vkvg_context_internal.c +++ b/src/vkvg_context_internal.c @@ -410,7 +410,7 @@ void _clear_attachment (VkvgContext ctx) { } bool _wait_flush_fence (VkvgContext ctx) { LOG(VKVG_LOG_INFO, "CTX: _wait_flush_fence\n"); - if (WaitForFences (ctx->pSurf->dev->vkDev, 1, &ctx->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT) == VK_SUCCESS) + if (WaitForFences (ctx->pSurf->dev->vkDev, 1, &ctx->syncCtx.fence, VK_TRUE, VKVG_FENCE_TIMEOUT) == VK_SUCCESS) return true; LOG(VKVG_LOG_DEBUG, "CTX: _wait_flush_fence timeout\n"); ctx->status = VKVG_STATUS_TIMEOUT; @@ -418,7 +418,7 @@ bool _wait_flush_fence (VkvgContext ctx) { } void _reset_flush_fence (VkvgContext ctx) { LOG(VKVG_LOG_INFO, "CTX: _reset_flush_fence\n"); - ResetFences (ctx->pSurf->dev->vkDev, 1, &ctx->flushFence); + ResetFences (ctx->pSurf->dev->vkDev, 1, &ctx->syncCtx.fence); } bool _wait_and_submit_cmd (VkvgContext ctx){ if (!ctx->cmdStarted)//current cmd buff is empty, be aware that wait is also canceled!! @@ -426,11 +426,11 @@ bool _wait_and_submit_cmd (VkvgContext ctx){ LOG(VKVG_LOG_INFO, "CTX: _wait_and_submit_cmd\n"); - if (!_wait_flush_fence (ctx)) + /*if (!_wait_flush_fence (ctx)) return false; - _reset_flush_fence(ctx); - - _submit_cmd (ctx->pSurf->dev, &ctx->cmd, ctx->flushFence); + _reset_flush_fence(ctx);*/ + _sync_context_wait_and_reset (&ctx->syncCtx, VKVG_FENCE_TIMEOUT); + _submit_cmd (ctx->pSurf->dev, &ctx->cmd, &ctx->syncCtx); if (ctx->cmd == ctx->cmdBuffers[0]) ctx->cmd = ctx->cmdBuffers[1]; diff --git a/src/vkvg_context_internal.h b/src/vkvg_context_internal.h index 6747d7d..bb3ab7f 100644 --- a/src/vkvg_context_internal.h +++ b/src/vkvg_context_internal.h @@ -27,6 +27,7 @@ #include "vkvg_buff.h" #include "vkh.h" #include "vkvg_fonts.h" +#include "vkvg_sync_context_internal.h" #if VKVG_RECORDING #include "recording/vkvg_record_internal.h" @@ -130,7 +131,8 @@ typedef struct _vkvg_context_t { uint32_t references; //reference count VkvgSurface pSurf; //surface bound to context, set on creation of ctx - VkFence flushFence; //context fence + vkvg_sync_context syncCtx; + VkhImage source; //source of painting operation VkCommandPool cmdPool; //local pools ensure thread safety diff --git a/src/vkvg_device.c b/src/vkvg_device.c index da5820d..6acb1c9 100644 --- a/src/vkvg_device.c +++ b/src/vkvg_device.c @@ -29,14 +29,15 @@ if (vkh_phyinfo_try_get_extension_properties(pi, #ext, NULL)) \ enabledExts[enabledExtsCount++] = #ext; \ } + void _device_init (VkvgDevice dev, VkInstance inst, VkPhysicalDevice phy, VkDevice vkdev, uint32_t qFamIdx, uint32_t qIndex, VkSampleCountFlags samples, bool deferredResolve) { - dev->instance = inst; - dev->hdpi = 72; - dev->vdpi = 72; - dev->samples= samples; + dev->instance = inst; + dev->hdpi = 72; + dev->vdpi = 72; + dev->samples = samples; + dev->vkDev = vkdev; + dev->phy = phy; dev->deferredResolve = deferredResolve; - dev->vkDev = vkdev; - dev->phy = phy; #if VKVG_DBG_STATS dev->debug_stats = (vkvg_debug_stats_t) {0}; @@ -69,8 +70,8 @@ void _device_init (VkvgDevice dev, VkInstance inst, VkPhysicalDevice phy, VkDevi dev->cmdPool= vkh_cmd_pool_create ((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); dev->cmd = vkh_cmd_buff_create ((VkhDevice)dev, dev->cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); - dev->fence = vkh_fence_create_signaled ((VkhDevice)dev); + _sync_context_init ((VkhDevice)dev, &dev->syncCtx); _create_pipeline_cache (dev); _init_fonts_cache (dev); if (dev->deferredResolve || dev->samples == VK_SAMPLE_COUNT_1_BIT){ @@ -90,7 +91,9 @@ void _device_init (VkvgDevice dev, VkInstance inst, VkPhysicalDevice phy, VkDevi #if defined(DEBUG) && defined (VKVG_DBG_UTILS) vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_POOL, (uint64_t)dev->cmdPool, "Device Cmd Pool"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)dev->cmd, "Device Cmd Buff"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_FENCE, (uint64_t)dev->fence, "Device Fence"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_FENCE, (uint64_t)dev->syncCtx.fence, "Device Fence"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_SEMAPHORE, (uint64_t)dev->syncCtx.signals[0], "Device Semaphore A"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_SEMAPHORE, (uint64_t)dev->syncCtx.signals[1], "Device Semaphore B"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass, "RP load img/stencil"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass_ClearStencil, "RP clear stencil"); vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass_ClearAll, "RP clear all"); @@ -286,9 +289,9 @@ void vkvg_device_destroy (VkvgDevice dev) vkDestroyRenderPass (dev->vkDev, dev->renderPass_ClearStencil, NULL); vkDestroyRenderPass (dev->vkDev, dev->renderPass_ClearAll, NULL); - vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); + _sync_context_wait (&dev->syncCtx, UINT64_MAX); + _sync_context_clear (&dev->syncCtx); - vkDestroyFence (dev->vkDev, dev->fence,NULL); vkFreeCommandBuffers (dev->vkDev, dev->cmdPool, 1, &dev->cmd); vkDestroyCommandPool (dev->vkDev, dev->cmdPool, NULL); @@ -328,8 +331,8 @@ void vkvg_device_get_dpy (VkvgDevice dev, int* hdpy, int* vdpy) { *vdpy = dev->vdpi; } void vkvg_device_set_queue_guards (VkvgDevice dev, vkvg_queue_guard before_submit, vkvg_queue_guard after_submit, void* user_data) { - dev->gQBeforeSubmitGuard = before_submit; - dev->gQAfterSubmitGuard = after_submit; + dev->gQLockGuard = before_submit; + dev->gQUnlockGuard = after_submit; dev->gQGuardUserData = user_data; } #if VKVG_DBG_STATS diff --git a/src/vkvg_device_internal.c b/src/vkvg_device_internal.c index d66df4c..8319630 100644 --- a/src/vkvg_device_internal.c +++ b/src/vkvg_device_internal.c @@ -423,16 +423,35 @@ void _wait_idle (VkvgDevice dev) { vkDeviceWaitIdle (dev->vkDev); } void _wait_and_reset_device_fence (VkvgDevice dev) { - vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); - vkResetFences (dev->vkDev, 1, &dev->fence); + vkWaitForFences (dev->vkDev, 1, &dev->syncCtx.fence, VK_TRUE, UINT64_MAX); + vkResetFences (dev->vkDev, 1, &dev->syncCtx.fence); } -void _submit_cmd (VkvgDevice dev, VkCommandBuffer* cmd, VkFence fence) { - if (dev->gQBeforeSubmitGuard) - dev->gQBeforeSubmitGuard (dev->gQGuardUserData); - vkh_cmd_submit (dev->gQueue, cmd, fence); - if (dev->gQAfterSubmitGuard) - dev->gQAfterSubmitGuard (dev->gQGuardUserData); +void _submit_cmd (VkvgDevice dev, VkCommandBuffer* cmd, vkvg_sync_context* sync) { + if (dev->gQLockGuard) + dev->gQLockGuard (dev->gQGuardUserData); + + _sync_context_dbg_print("sync:", sync); + _sync_context_dbg_print("signaled:", dev->gQLastSignaledSync); + //_sync_context_dbg_print("awaited :", dev->gQLastAwaitedSync); + + if (dev->gQLastSignaledSync) + vkh_cmd_submit_with_semaphores(dev->gQueue, cmd, + dev->gQLastSignaledSync->signals[!dev->gQLastSignaledSync->nextSubmIdx], + sync->signals[sync->nextSubmIdx], sync->fence); + else + vkh_cmd_submit_with_semaphores(dev->gQueue, cmd, VK_NULL_HANDLE, sync->signals[sync->nextSubmIdx], sync->fence); + + sync->nextSubmIdx ^= true; + + if (dev->gQLastSignaledSync) { + dev->gQLastSignaledSync->awaitedBy = sync; + sync->awaiting = dev->gQLastSignaledSync; + } + dev->gQLastSignaledSync = sync; + + if (dev->gQUnlockGuard) + dev->gQUnlockGuard (dev->gQGuardUserData); } bool _init_function_pointers (VkvgDevice dev) { @@ -476,7 +495,7 @@ void _create_empty_texture (VkvgDevice dev, VkFormat format, VkImageTiling tilin VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); vkh_cmd_end (dev->cmd); - _submit_cmd (dev, &dev->cmd, dev->fence); + _submit_cmd (dev, &dev->cmd, &dev->syncCtx); } void _check_best_image_tiling (VkvgDevice dev, VkFormat format) { diff --git a/src/vkvg_device_internal.h b/src/vkvg_device_internal.h index 376b9c2..be1d1b4 100644 --- a/src/vkvg_device_internal.h +++ b/src/vkvg_device_internal.h @@ -25,6 +25,7 @@ #include "vkvg_internal.h" #include "vkvg.h" #include "vkvg_fonts.h" +#include "vkvg_sync_context_internal.h" #define STENCIL_FILL_BIT 0x1 #define STENCIL_CLIP_BIT 0x2 @@ -63,8 +64,8 @@ typedef struct _vkvg_device_t{ VkFormat pngStagFormat; /**< Supported vulkan image format png write staging img */ VkImageTiling pngStagTiling; /**< tiling for the blit operation */ - vkvg_queue_guard gQBeforeSubmitGuard; - vkvg_queue_guard gQAfterSubmitGuard; + vkvg_queue_guard gQLockGuard; + vkvg_queue_guard gQUnlockGuard; void* gQGuardUserData; VkhQueue gQueue; /**< Vulkan Queue with Graphic flag */ @@ -75,7 +76,9 @@ typedef struct _vkvg_device_t{ uint32_t references; /**< Reference count, prevent destroying device if still in use */ VkCommandPool cmdPool; /**< Global command pool for processing on surfaces without context */ VkCommandBuffer cmd; /**< Global command buffer */ - VkFence fence; /**< this fence is kept signaled when idle, wait and reset are called before each recording. */ + vkvg_sync_context syncCtx; /**< device cmds sync context */ + //vkvg_sync_context* gQLastAwaitedSync; /**< Last sync context whose signal semaphore is waited in cmd submission */ + vkvgSync gQLastSignaledSync; /**< Last sync context submitted with signal semaphore */ VkPipeline pipe_OVER; /**< default operator */ VkPipeline pipe_SUB; @@ -124,5 +127,5 @@ void _createDescriptorSetLayout (VkvgDevice dev); void _flush_all_contexes (VkvgDevice dev); void _wait_idle (VkvgDevice dev); void _wait_and_reset_device_fence (VkvgDevice dev); -void _submit_cmd (VkvgDevice dev, VkCommandBuffer* cmd, VkFence fence); +void _submit_cmd (VkvgDevice dev, VkCommandBuffer* cmd, vkvg_sync_context *sync); #endif diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c index d4ed5fd..8863c53 100644 --- a/src/vkvg_fonts.c +++ b/src/vkvg_fonts.c @@ -70,7 +70,7 @@ void _init_fonts_cache (VkvgDevice dev){ vkh_image_create_descriptor (cache->texture, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); - cache->uploadFence = vkh_fence_create((VkhDevice)dev); + _sync_context_init ((VkhDevice)dev,&cache->uploadSync); uint32_t buffLength = FONT_PAGE_SIZE*FONT_PAGE_SIZE*cache->texPixelSize; @@ -88,7 +88,7 @@ void _init_fonts_cache (VkvgDevice dev){ VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); - _submit_cmd (dev, &cache->cmd, cache->uploadFence); + _submit_cmd (dev, &cache->cmd, &cache->uploadSync); cache->hostBuff = (uint8_t*)malloc(buffLength); cache->pensY = (int*)calloc(cache->texLength, sizeof(int)); @@ -103,9 +103,8 @@ void _increase_font_tex_array (VkvgDevice dev){ _font_cache_t* cache = dev->fontCache; - vkWaitForFences (dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); - vkResetCommandBuffer(cache->cmd, 0); - vkResetFences (dev->vkDev, 1, &cache->uploadFence); + _sync_context_wait_and_reset (&cache->uploadSync, UINT64_MAX); + vkResetCommandBuffer (cache->cmd, 0); uint8_t newSize = cache->texLength + FONT_CACHE_INIT_LAYERS; VkhImage newImg = vkh_tex2d_array_create ((VkhDevice)dev, cache->texFormat, FONT_PAGE_SIZE, FONT_PAGE_SIZE, @@ -139,8 +138,8 @@ void _increase_font_tex_array (VkvgDevice dev){ VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); - _submit_cmd (dev, &cache->cmd, cache->uploadFence); - vkWaitForFences (dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); + _submit_cmd (dev, &cache->cmd, &cache->uploadSync); + _sync_context_wait (&cache->uploadSync, UINT64_MAX); cache->pensY = (int*)realloc(cache->pensY, newSize * sizeof(int)); void* tmp = memset (&cache->pensY[cache->texLength],0,FONT_CACHE_INIT_LAYERS*sizeof(int)); @@ -215,11 +214,10 @@ void _destroy_font_cache (VkvgDevice dev){ free(cache->fonts); free(cache->pensY); - vkvg_buffer_destroy (&cache->buff); vkh_image_destroy (cache->texture); //vkFreeCommandBuffers(dev->vkDev,dev->cmdPool, 1, &cache->cmd); - vkDestroyFence (dev->vkDev,cache->uploadFence,NULL); + _sync_context_clear (&cache->uploadSync); #ifdef VKVG_USE_FREETYPE FT_Done_FreeType(cache->library); #endif @@ -240,9 +238,8 @@ void _flush_chars_to_tex (VkvgDevice dev, _vkvg_font_t* f) { return; LOG(VKVG_LOG_INFO, "_flush_chars_to_tex pen(%d, %d)\n",f->curLine.penX, f->curLine.penY); - vkWaitForFences (dev->vkDev,1,&cache->uploadFence,VK_TRUE,UINT64_MAX); + _sync_context_wait_and_reset(&cache->uploadSync, UINT64_MAX); vkResetCommandBuffer(cache->cmd,0); - vkResetFences (dev->vkDev,1,&cache->uploadFence); memcpy(cache->buff.allocInfo.pMappedData, cache->hostBuff, (uint64_t)f->curLine.height * FONT_PAGE_SIZE * cache->texPixelSize); @@ -268,7 +265,7 @@ void _flush_chars_to_tex (VkvgDevice dev, _vkvg_font_t* f) { VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); - _submit_cmd (dev, &cache->cmd, cache->uploadFence); + _submit_cmd (dev, &cache->cmd, &cache->uploadSync); f->curLine.penX += cache->stagingX; cache->stagingX = 0; diff --git a/src/vkvg_fonts.h b/src/vkvg_fonts.h index 3a2be10..c84a299 100644 --- a/src/vkvg_fonts.h +++ b/src/vkvg_fonts.h @@ -64,6 +64,7 @@ #include "vkvg_buff.h" #include "vkh.h" #include "vectors.h" +#include "vkvg_sync_context_internal.h" //texture coordinates of one character in font cache array texture. @@ -142,7 +143,7 @@ typedef struct { uint8_t texPixelSize; /* Size in byte of a single pixel in a font texture */ uint8_t texLength; /* layer count of 2d array texture, starts with FONT_CACHE_INIT_LAYERS count and increased when needed */ int* pensY; /* array of current y pen positions for each texture in cache 2d array */ - VkFence uploadFence; /* Signaled when upload is finished */ + vkvg_sync_context uploadSync; /* upload sync context */ _vkvg_font_identity_t* fonts; /* Loaded fonts structure array */ int32_t fontsCount; /* Loaded fonts array count*/ diff --git a/src/vkvg_surface.c b/src/vkvg_surface.c index 89ff376..9055b52 100644 --- a/src/vkvg_surface.c +++ b/src/vkvg_surface.c @@ -148,10 +148,10 @@ VkvgSurface vkvg_surface_create_from_bitmap (VkvgDevice dev, unsigned char* img, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); vkh_cmd_end (cmd); - _submit_cmd (dev, &cmd, dev->fence); + _submit_cmd (dev, &cmd, &dev->syncCtx); //don't reset fence after completion as this is the last cmd. (signaled idle fence) - vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); + WaitForFences (dev->vkDev, 1, &dev->syncCtx.fence, VK_TRUE, UINT64_MAX); vkvg_buffer_destroy (&buff); vkh_image_destroy (stagImg); @@ -298,7 +298,7 @@ vkvg_status_t vkvg_surface_write_to_png (VkvgSurface surf, const char* path){ vkh_image_get_vkimage (stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_NEAREST); vkh_cmd_end (cmd); - _submit_cmd (dev, &cmd, dev->fence); + _submit_cmd (dev, &cmd, &dev->syncCtx); VkhImage stagImgLinear = stagImg; @@ -327,12 +327,12 @@ vkvg_status_t vkvg_surface_write_to_png (VkvgSurface surf, const char* path){ vkh_image_get_vkimage (stagImgLinear), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cpy); vkh_cmd_end (cmd); - _submit_cmd (dev, &cmd, dev->fence); + _submit_cmd (dev, &cmd, &dev->syncCtx); - vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); + vkWaitForFences (dev->vkDev, 1, &dev->syncCtx.fence, VK_TRUE, UINT64_MAX); vkh_image_destroy (stagImg); } else - vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); + vkWaitForFences (dev->vkDev, 1, &dev->syncCtx.fence, VK_TRUE, UINT64_MAX); void* img = vkh_image_map (stagImgLinear); @@ -386,8 +386,8 @@ vkvg_status_t vkvg_surface_write_to_memory (VkvgSurface surf, unsigned char* con vkh_image_get_vkimage (stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_NEAREST); vkh_cmd_end (cmd); - _submit_cmd (dev, &cmd, dev->fence); - vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); + _submit_cmd (dev, &cmd, &dev->syncCtx); + vkWaitForFences (dev->vkDev, 1, &dev->syncCtx.fence, VK_TRUE, UINT64_MAX); uint64_t stride = vkh_image_get_stride(stagImg); uint32_t dest_stride = surf->width * 4; diff --git a/src/vkvg_surface_internal.c b/src/vkvg_surface_internal.c index a8cc8ff..307845a 100644 --- a/src/vkvg_surface_internal.c +++ b/src/vkvg_surface_internal.c @@ -53,7 +53,7 @@ void _explicit_ms_resolve (VkvgSurface surf){ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); vkh_cmd_end (cmd); - _submit_cmd (dev, &cmd, dev->fence); + _submit_cmd (dev, &cmd, &dev->syncCtx); } void _clear_surface (VkvgSurface surf, VkImageAspectFlags aspect) @@ -101,7 +101,7 @@ void _clear_surface (VkvgSurface surf, VkImageAspectFlags aspect) } vkh_cmd_end (cmd); - _submit_cmd (dev, &cmd, dev->fence); + _submit_cmd (dev, &cmd, &dev->syncCtx); } void _create_surface_main_image (VkvgSurface surf){ diff --git a/src/vkvg_sync_context_internal.c b/src/vkvg_sync_context_internal.c new file mode 100644 index 0000000..b74292e --- /dev/null +++ b/src/vkvg_sync_context_internal.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2018-2022 Jean-Philippe Bruyère + * + * 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 "vkvg_sync_context_internal.h" +#include "vkvg_device_internal.h" + +void _sync_context_init (VkvgDevice dev, vkvg_sync_context* ctx) { + VkhDevice d = (VkhDevice)dev; + ctx->dev = dev; + ctx->fence = vkh_fence_create_signaled (d); + ctx->signals[0] = vkh_semaphore_create (d); + ctx->signals[1] = vkh_semaphore_create (d); +} +void _sync_context_clear (vkvgSync ctx) { + if (ctx->dev->gQLockGuard) + ctx->dev->gQLockGuard (ctx->dev->gQGuardUserData); + + _sync_context_dbg_print("cleared:", ctx); + //_sync_context_dbg_print("signaled:", ctx->dev->gQLastSignaledSync); + //_sync_context_dbg_print("awaited :", ctx->dev->gQLastAwaitedSync); + + /*if (ctx->dev->gQLastAwaitedSync == ctx) { + vkWaitForFences(ctx->dev->vkDev, 1, &ctx->dev->gQLastAwaitedSync->fence, VK_TRUE, UINT64_MAX); + if (ctx->dev->gQLastSignaledSync) + vkWaitForFences(ctx->dev->vkDev, 1, &ctx->dev->gQLastSignaledSync->fence, VK_TRUE, UINT64_MAX); + ctx->dev->gQLastAwaitedSync = NULL; + ctx->dev->gQLastSignaledSync = NULL; + }*/ + if (ctx->dev->gQLastSignaledSync == ctx) + ctx->dev->gQLastSignaledSync = NULL; + + VkDevice dev = ctx->dev->vkDev; + + if (ctx->awaiting) { + ctx->awaiting->awaitedBy = NULL; + ctx->awaiting = NULL; + } + + if (ctx->awaitedBy) { + vkWaitForFences(dev, 1, &ctx->awaitedBy->fence, VK_TRUE, UINT64_MAX); + ctx->awaitedBy = NULL; + } + vkWaitForFences(dev, 1, &ctx->fence, VK_TRUE, UINT64_MAX); + + vkDestroyFence (dev, ctx->fence, NULL); + vkDestroySemaphore (dev, ctx->signals[0], NULL); + vkDestroySemaphore (dev, ctx->signals[1], NULL); + + if (ctx->dev->gQUnlockGuard) + ctx->dev->gQUnlockGuard (ctx->dev->gQGuardUserData); +} +VkResult _sync_context_wait (vkvgSync ctx, uint64_t timeout) { + return vkWaitForFences (ctx->dev->vkDev, 1, &ctx->fence, VK_TRUE, timeout); +} +VkResult _sync_context_wait_and_reset (vkvgSync ctx, uint64_t timeout) { + VkResult res = vkWaitForFences (ctx->dev->vkDev, 1, &ctx->fence, VK_TRUE, timeout); + if (ctx->dev->gQLockGuard) + ctx->dev->gQLockGuard (ctx->dev->gQGuardUserData); + _sync_context_dbg_print("reset:", ctx); + vkResetFences (ctx->dev->vkDev, 1, &ctx->fence); + if (ctx->dev->gQUnlockGuard) + ctx->dev->gQUnlockGuard (ctx->dev->gQGuardUserData); + return res; +} +void _sync_context_dbg_print (const char* label, vkvg_sync_context* ctx) { + if (ctx) + printf("\t\t%20s ctx: %16p sigA: %16p sigB: %16p\n", label, ctx, ctx->signals[0], ctx->signals[1]); + else + printf("\t\t%20s ctx: %16p\n", label, ctx); +} + diff --git a/src/vkvg_sync_context_internal.h b/src/vkvg_sync_context_internal.h new file mode 100644 index 0000000..d1581b0 --- /dev/null +++ b/src/vkvg_sync_context_internal.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018-2022 Jean-Philippe Bruyère + * + * 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 VKVG_SYNC_CONTEXT_INTERNAL_H +#define VKVG_SYNC_CONTEXT_INTERNAL_H + +#include "vkvg_internal.h" +#include "vkvg.h" +#include "vkh.h" + +typedef struct _vkvg_sync_context* vkvgSync; + +typedef struct _vkvg_sync_context { + VkvgDevice dev; + VkFence fence; // this fence is kept signaled when idle, wait and reset are called before each recording. + VkSemaphore signals[2]; // dual signal semaphore couple with the fence guard ensure sync in multithreaded. + bool nextSubmIdx; // switch between signal[0] and [1], index of the next sema to use as signal + + vkvgSync awaitedBy; + vkvgSync awaiting; +}vkvg_sync_context; + +void _sync_context_init (VkvgDevice dev, vkvg_sync_context* ctx); +void _sync_context_clear (vkvgSync ctx); +VkResult _sync_context_wait (vkvgSync ctx, uint64_t timeout); +VkResult _sync_context_wait_and_reset (vkvgSync ctx, uint64_t timeout); + +void _sync_context_dbg_print (const char *label, vkvg_sync_context* ctx); +#endif diff --git a/tests/multithreading/multithreaded.c b/tests/multithreading/multithreaded.c index cc4aa0a..2b2afc9 100644 --- a/tests/multithreading/multithreaded.c +++ b/tests/multithreading/multithreaded.c @@ -1,7 +1,7 @@ #include "test.h" #include "tinycthread.h" -#define THREAD_COUNT 2 +#define THREAD_COUNT 8 static int finishedThreadCount = 0; @@ -19,16 +19,14 @@ void drawRandomRect (VkvgContext ctx, float s) { } void _before_submit (void* data) { mtx_lock((mtx_t*)data); + printf("sumbit 0x%lx\n", thrd_current()); } void _after_submit (void* data) { + printf("release 0x%lx\n", thrd_current()); mtx_unlock((mtx_t*)data); } int drawRectsThread () { - mtx_t gQMutex; - mtx_init (&gQMutex, mtx_plain); - vkvg_device_set_queue_guards (device, _before_submit, _after_submit, &gQMutex); - VkvgSurface s = vkvg_surface_create(device, test_width, test_height); VkvgContext ctx = vkvg_create(s); for (uint32_t i=0; imain 0x%lx\n", thrd_current()); + mtx_t gQMutex; + mtx_init (&gQMutex, mtx_plain); + vkvg_device_set_queue_guards (device, _before_submit, _after_submit, &gQMutex); thrd_t threads[THREAD_COUNT]; + finishedThreadCount = 0; mtx_init (&mutex,mtx_plain); for (uint32_t i=0; i