]> O.S.I.I.S - jp/vkvg.git/commitdiff
thread aware option in device, simple mutex device lock
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 27 Jan 2022 21:12:10 +0000 (22:12 +0100)
committerj-p <jp_bruyere@hotmail.com>
Fri, 18 Feb 2022 20:09:23 +0000 (21:09 +0100)
18 files changed:
CMakeLists.txt
include/vkvg.h
src/cross_os.c
src/cross_os.h
src/deps/tinycthread.c [new file with mode: 0644]
src/deps/tinycthread.h [new file with mode: 0644]
src/vkvg_context.c
src/vkvg_context_internal.c
src/vkvg_device.c
src/vkvg_device_internal.c
src/vkvg_device_internal.h
src/vkvg_fonts.c
src/vkvg_internal.h
src/vkvg_surface.c
src/vkvg_surface_internal.c
src/vkvg_surface_internal.h
tests/multithreading/multithreaded.c
tests/multithreading/multithreaded2.c

index 9724a07f301316d430b8f129179c42804c0af367..44b8d181dc4af5a1d624400133eaaf80e47054c8 100644 (file)
@@ -37,7 +37,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
        OPTION(ENABLE_DBG_UTILS "enable VK_EXT_debug_utils extension" ON)
        OPTION(ENABLE_WIRED_FILL "enable wired polygon draw to check vertices and primitives" OFF)
        IF (UNIX)
-               SET(CMAKE_${LANG}_FLAGS "-Wall -Wno-extra -Wno-unknown-pragmas -Wno-missing-braces -Wno-unused-variable -Wno-switch")
+               SET(CMAKE_${LANG}_FLAGS "-rdynamic -Wall -Wno-extra -Wno-unknown-pragmas -Wno-missing-braces -Wno-unused-variable -Wno-switch")
        ELSEIF(MSVC)
                SET(CMAKE_${LANG}_FLAGS "/TC /W4 /wd4201 /wd4204 /wd4221 /wd4100") # c11 compliant
        ENDIF()
index 950882351c2ca2ba6d9c3fa2da6ead52d3886e74..8c1b36a04dc3984eccfb57074d17ccd5e14c3de7 100644 (file)
@@ -90,12 +90,11 @@ extern "C" {
 #define VKVG_LOG_INFO_IBO      0x00000040
 #define VKVG_LOG_INFO_VAO      (VKVG_LOG_INFO_VBO|VKVG_LOG_INFO_IBO)
 #define VKVG_LOG_DBG_ARRAYS    0x00001000
-//#define VKVG_LOG_THREADING   0x00000080
 #define VKVG_LOG_FULL          0xffffffff
 
 #define VKVG_LOG_INFO          0x00008000//(VKVG_LOG_INFO_PTS|VKVG_LOG_INFO_PATH|VKVG_LOG_INFO_CMD|VKVG_LOG_INFO_VAO)
 #ifdef DEBUG
-extern uint32_t vkvg_log_level;
+       extern uint32_t vkvg_log_level;
        #ifdef VKVG_WIRED_DEBUG
                typedef enum {
                        vkvg_wired_debug_mode_normal    = 0x01,
@@ -535,9 +534,9 @@ void vkvg_matrix_get_scale (const vkvg_matrix_t *matrix, float *sx, float *sy);
  * Device holds the font cache so that each time a context draws text, the same cache is used.
  *
  * @{ */
-typedef void (*vkvg_device_guard)(void* user_data);
+
 vkvg_public
-void vkvg_device_set_guards (VkvgDevice dev, vkvg_device_guard lock_callback, vkvg_device_guard unlock_callback, void* user_data);
+void vkvg_device_set_thread_aware (VkvgDevice dev, uint32_t thread_awayre);
 
 /**
  * @brief Create a new vkvg device.
index 2aa8b50254609c7ed06889b231583af67004a264..3640b11b9a7307174144d6d2c9770f85d24ca329 100644 (file)
@@ -45,3 +45,29 @@ const char* getUserDir () {
        return pw->pw_dir;
 #endif
 }
+
+#if __linux__
+#include <stdio.h>
+#include <execinfo.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void handler(int sig) {
+  void *array[100];
+  size_t size;
+
+  // get void*'s for all entries on the stack
+  size = backtrace(array, 100);
+
+  // print out all the frames to stderr
+  fprintf(stderr, "Error: signal %d:\n", sig);
+  backtrace_symbols_fd(array, size, STDERR_FILENO);
+  exit(1);
+}
+
+void _linux_register_error_handler () {
+       signal(SIGSEGV, handler);   // install our handler
+       signal(SIGABRT, handler);   // install our handler
+}
+#endif
index cc0cae0090aac01bd1d573fd48f0d355acfad887..32f05f0436449ecce8f90313013c7b8e9aa8f466 100644 (file)
@@ -53,6 +53,9 @@
        #define vkvg_inline static inline __attribute((always_inline))
        #define disable_warning (warn) #pragma GCC diagnostic ignored "-W"#warn
        #define reset_warning (warn) #pragma GCC diagnostic warning "-W"#warn
+       #if __linux__
+               void _linux_register_error_handler ();
+       #endif
 #endif
 
 const char* getUserDir ();
diff --git a/src/deps/tinycthread.c b/src/deps/tinycthread.c
new file mode 100644 (file)
index 0000000..f9cea2e
--- /dev/null
@@ -0,0 +1,594 @@
+/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*-
+Copyright (c) 2012 Marcus Geelnard
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+    1. The origin of this software must not be misrepresented; you must not
+    claim that you wrote the original software. If you use this software
+    in a product, an acknowledgment in the product documentation would be
+    appreciated but is not required.
+
+    2. Altered source versions must be plainly marked as such, and must not be
+    misrepresented as being the original software.
+
+    3. This notice may not be removed or altered from any source
+    distribution.
+*/
+
+/* 2013-01-06 Camilla Löwy <elmindreda@glfw.org>
+ *
+ * Added casts from time_t to DWORD to avoid warnings on VC++.
+ * Fixed time retrieval on POSIX systems.
+ */
+
+#include "tinycthread.h"
+#include <stdlib.h>
+
+/* Platform specific includes */
+#if defined(_TTHREAD_POSIX_)
+  #include <signal.h>
+  #include <sched.h>
+  #include <unistd.h>
+  #include <sys/time.h>
+  #include <errno.h>
+#elif defined(_TTHREAD_WIN32_)
+  #include <process.h>
+  #include <sys/timeb.h>
+#endif
+
+/* Standard, good-to-have defines */
+#ifndef NULL
+  #define NULL (void*)0
+#endif
+#ifndef TRUE
+  #define TRUE 1
+#endif
+#ifndef FALSE
+  #define FALSE 0
+#endif
+
+int mtx_init(mtx_t *mtx, int type)
+{
+#if defined(_TTHREAD_WIN32_)
+  mtx->mAlreadyLocked = FALSE;
+  mtx->mRecursive = type & mtx_recursive;
+  InitializeCriticalSection(&mtx->mHandle);
+  return thrd_success;
+#else
+  int ret;
+  pthread_mutexattr_t attr;
+  pthread_mutexattr_init(&attr);
+  if (type & mtx_recursive)
+  {
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+  }
+  ret = pthread_mutex_init(mtx, &attr);
+  pthread_mutexattr_destroy(&attr);
+  return ret == 0 ? thrd_success : thrd_error;
+#endif
+}
+
+void mtx_destroy(mtx_t *mtx)
+{
+#if defined(_TTHREAD_WIN32_)
+  DeleteCriticalSection(&mtx->mHandle);
+#else
+  pthread_mutex_destroy(mtx);
+#endif
+}
+
+int mtx_lock(mtx_t *mtx)
+{
+#if defined(_TTHREAD_WIN32_)
+  EnterCriticalSection(&mtx->mHandle);
+  if (!mtx->mRecursive)
+  {
+    while(mtx->mAlreadyLocked) Sleep(1000); /* Simulate deadlock... */
+    mtx->mAlreadyLocked = TRUE;
+  }
+  return thrd_success;
+#else
+  return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error;
+#endif
+}
+
+int mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
+{
+  /* FIXME! */
+  (void)mtx;
+  (void)ts;
+  return thrd_error;
+}
+
+int mtx_trylock(mtx_t *mtx)
+{
+#if defined(_TTHREAD_WIN32_)
+  int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy;
+  if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked)
+  {
+    LeaveCriticalSection(&mtx->mHandle);
+    ret = thrd_busy;
+  }
+  return ret;
+#else
+  return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy;
+#endif
+}
+
+int mtx_unlock(mtx_t *mtx)
+{
+#if defined(_TTHREAD_WIN32_)
+  mtx->mAlreadyLocked = FALSE;
+  LeaveCriticalSection(&mtx->mHandle);
+  return thrd_success;
+#else
+  return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;;
+#endif
+}
+
+#if defined(_TTHREAD_WIN32_)
+#define _CONDITION_EVENT_ONE 0
+#define _CONDITION_EVENT_ALL 1
+#endif
+
+int cnd_init(cnd_t *cond)
+{
+#if defined(_TTHREAD_WIN32_)
+  cond->mWaitersCount = 0;
+
+  /* Init critical section */
+  InitializeCriticalSection(&cond->mWaitersCountLock);
+
+  /* Init events */
+  cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL);
+  if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL)
+  {
+    cond->mEvents[_CONDITION_EVENT_ALL] = NULL;
+    return thrd_error;
+  }
+  cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL);
+  if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL)
+  {
+    CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]);
+    cond->mEvents[_CONDITION_EVENT_ONE] = NULL;
+    return thrd_error;
+  }
+
+  return thrd_success;
+#else
+  return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error;
+#endif
+}
+
+void cnd_destroy(cnd_t *cond)
+{
+#if defined(_TTHREAD_WIN32_)
+  if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL)
+  {
+    CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]);
+  }
+  if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL)
+  {
+    CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]);
+  }
+  DeleteCriticalSection(&cond->mWaitersCountLock);
+#else
+  pthread_cond_destroy(cond);
+#endif
+}
+
+int cnd_signal(cnd_t *cond)
+{
+#if defined(_TTHREAD_WIN32_)
+  int haveWaiters;
+
+  /* Are there any waiters? */
+  EnterCriticalSection(&cond->mWaitersCountLock);
+  haveWaiters = (cond->mWaitersCount > 0);
+  LeaveCriticalSection(&cond->mWaitersCountLock);
+
+  /* If we have any waiting threads, send them a signal */
+  if(haveWaiters)
+  {
+    if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0)
+    {
+      return thrd_error;
+    }
+  }
+
+  return thrd_success;
+#else
+  return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error;
+#endif
+}
+
+int cnd_broadcast(cnd_t *cond)
+{
+#if defined(_TTHREAD_WIN32_)
+  int haveWaiters;
+
+  /* Are there any waiters? */
+  EnterCriticalSection(&cond->mWaitersCountLock);
+  haveWaiters = (cond->mWaitersCount > 0);
+  LeaveCriticalSection(&cond->mWaitersCountLock);
+
+  /* If we have any waiting threads, send them a signal */
+  if(haveWaiters)
+  {
+    if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0)
+    {
+      return thrd_error;
+    }
+  }
+
+  return thrd_success;
+#else
+  return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error;
+#endif
+}
+
+#if defined(_TTHREAD_WIN32_)
+static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout)
+{
+  int result, lastWaiter;
+
+  /* Increment number of waiters */
+  EnterCriticalSection(&cond->mWaitersCountLock);
+  ++ cond->mWaitersCount;
+  LeaveCriticalSection(&cond->mWaitersCountLock);
+
+  /* Release the mutex while waiting for the condition (will decrease
+     the number of waiters when done)... */
+  mtx_unlock(mtx);
+
+  /* Wait for either event to become signaled due to cnd_signal() or
+     cnd_broadcast() being called */
+  result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout);
+  if (result == WAIT_TIMEOUT)
+  {
+    return thrd_timeout;
+  }
+  else if (result == (int)WAIT_FAILED)
+  {
+    return thrd_error;
+  }
+
+  /* Check if we are the last waiter */
+  EnterCriticalSection(&cond->mWaitersCountLock);
+  -- cond->mWaitersCount;
+  lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) &&
+               (cond->mWaitersCount == 0);
+  LeaveCriticalSection(&cond->mWaitersCountLock);
+
+  /* If we are the last waiter to be notified to stop waiting, reset the event */
+  if (lastWaiter)
+  {
+    if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0)
+    {
+      return thrd_error;
+    }
+  }
+
+  /* Re-acquire the mutex */
+  mtx_lock(mtx);
+
+  return thrd_success;
+}
+#endif
+
+int cnd_wait(cnd_t *cond, mtx_t *mtx)
+{
+#if defined(_TTHREAD_WIN32_)
+  return _cnd_timedwait_win32(cond, mtx, INFINITE);
+#else
+  return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error;
+#endif
+}
+
+int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
+{
+#if defined(_TTHREAD_WIN32_)
+  struct timespec now;
+  if (clock_gettime(CLOCK_REALTIME, &now) == 0)
+  {
+    DWORD delta = (DWORD) ((ts->tv_sec - now.tv_sec) * 1000 +
+                           (ts->tv_nsec - now.tv_nsec + 500000) / 1000000);
+    return _cnd_timedwait_win32(cond, mtx, delta);
+  }
+  else
+    return thrd_error;
+#else
+  int ret;
+  ret = pthread_cond_timedwait(cond, mtx, ts);
+  if (ret == ETIMEDOUT)
+  {
+    return thrd_timeout;
+  }
+  return ret == 0 ? thrd_success : thrd_error;
+#endif
+}
+
+
+/** Information to pass to the new thread (what to run). */
+typedef struct {
+  thrd_start_t mFunction; /**< Pointer to the function to be executed. */
+  void * mArg;            /**< Function argument for the thread function. */
+} _thread_start_info;
+
+/* Thread wrapper function. */
+#if defined(_TTHREAD_WIN32_)
+static unsigned WINAPI _thrd_wrapper_function(void * aArg)
+#elif defined(_TTHREAD_POSIX_)
+static void * _thrd_wrapper_function(void * aArg)
+#endif
+{
+  thrd_start_t fun;
+  void *arg;
+  int  res;
+#if defined(_TTHREAD_POSIX_)
+  void *pres;
+#endif
+
+  /* Get thread startup information */
+  _thread_start_info *ti = (_thread_start_info *) aArg;
+  fun = ti->mFunction;
+  arg = ti->mArg;
+
+  /* The thread is responsible for freeing the startup information */
+  free((void *)ti);
+
+  /* Call the actual client thread function */
+  res = fun(arg);
+
+#if defined(_TTHREAD_WIN32_)
+  return res;
+#else
+  pres = malloc(sizeof(int));
+  if (pres != NULL)
+  {
+    *(int*)pres = res;
+  }
+  return pres;
+#endif
+}
+
+int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
+{
+  /* Fill out the thread startup information (passed to the thread wrapper,
+     which will eventually free it) */
+  _thread_start_info* ti = (_thread_start_info*)malloc(sizeof(_thread_start_info));
+  if (ti == NULL)
+  {
+    return thrd_nomem;
+  }
+  ti->mFunction = func;
+  ti->mArg = arg;
+
+  /* Create the thread */
+#if defined(_TTHREAD_WIN32_)
+  *thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL);
+#elif defined(_TTHREAD_POSIX_)
+  if(pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0)
+  {
+    *thr = 0;
+  }
+#endif
+
+  /* Did we fail to create the thread? */
+  if(!*thr)
+  {
+    free(ti);
+    return thrd_error;
+  }
+
+  return thrd_success;
+}
+
+thrd_t thrd_current(void)
+{
+#if defined(_TTHREAD_WIN32_)
+  return GetCurrentThread();
+#else
+  return pthread_self();
+#endif
+}
+
+int thrd_detach(thrd_t thr)
+{
+  /* FIXME! */
+  (void)thr;
+  return thrd_error;
+}
+
+int thrd_equal(thrd_t thr0, thrd_t thr1)
+{
+#if defined(_TTHREAD_WIN32_)
+  return thr0 == thr1;
+#else
+  return pthread_equal(thr0, thr1);
+#endif
+}
+
+void thrd_exit(int res)
+{
+#if defined(_TTHREAD_WIN32_)
+  ExitThread(res);
+#else
+  void *pres = malloc(sizeof(int));
+  if (pres != NULL)
+  {
+    *(int*)pres = res;
+  }
+  pthread_exit(pres);
+#endif
+}
+
+int thrd_join(thrd_t thr, int *res)
+{
+#if defined(_TTHREAD_WIN32_)
+  if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED)
+  {
+    return thrd_error;
+  }
+  if (res != NULL)
+  {
+    DWORD dwRes;
+    GetExitCodeThread(thr, &dwRes);
+    *res = dwRes;
+  }
+#elif defined(_TTHREAD_POSIX_)
+  void *pres;
+  int ires = 0;
+  if (pthread_join(thr, &pres) != 0)
+  {
+    return thrd_error;
+  }
+  if (pres != NULL)
+  {
+    ires = *(int*)pres;
+    free(pres);
+  }
+  if (res != NULL)
+  {
+    *res = ires;
+  }
+#endif
+  return thrd_success;
+}
+
+int thrd_sleep(const struct timespec *time_point, struct timespec *remaining)
+{
+  struct timespec now;
+#if defined(_TTHREAD_WIN32_)
+  DWORD delta;
+#else
+  long delta;
+#endif
+
+  /* Get the current time */
+  if (clock_gettime(CLOCK_REALTIME, &now) != 0)
+    return -2;  // FIXME: Some specific error code?
+
+#if defined(_TTHREAD_WIN32_)
+  /* Delta in milliseconds */
+  delta = (DWORD) ((time_point->tv_sec - now.tv_sec) * 1000 +
+                   (time_point->tv_nsec - now.tv_nsec + 500000) / 1000000);
+  if (delta > 0)
+  {
+    Sleep(delta);
+  }
+#else
+  /* Delta in microseconds */
+  delta = (time_point->tv_sec - now.tv_sec) * 1000000L +
+          (time_point->tv_nsec - now.tv_nsec + 500L) / 1000L;
+
+  /* On some systems, the usleep argument must be < 1000000 */
+  while (delta > 999999L)
+  {
+    usleep(999999);
+    delta -= 999999L;
+  }
+  if (delta > 0L)
+  {
+    usleep((useconds_t)delta);
+  }
+#endif
+
+  /* We don't support waking up prematurely (yet) */
+  if (remaining)
+  {
+    remaining->tv_sec = 0;
+    remaining->tv_nsec = 0;
+  }
+  return 0;
+}
+
+void thrd_yield(void)
+{
+#if defined(_TTHREAD_WIN32_)
+  Sleep(0);
+#else
+  sched_yield();
+#endif
+}
+
+int tss_create(tss_t *key, tss_dtor_t dtor)
+{
+#if defined(_TTHREAD_WIN32_)
+  /* FIXME: The destructor function is not supported yet... */
+  if (dtor != NULL)
+  {
+    return thrd_error;
+  }
+  *key = TlsAlloc();
+  if (*key == TLS_OUT_OF_INDEXES)
+  {
+    return thrd_error;
+  }
+#else
+  if (pthread_key_create(key, dtor) != 0)
+  {
+    return thrd_error;
+  }
+#endif
+  return thrd_success;
+}
+
+void tss_delete(tss_t key)
+{
+#if defined(_TTHREAD_WIN32_)
+  TlsFree(key);
+#else
+  pthread_key_delete(key);
+#endif
+}
+
+void *tss_get(tss_t key)
+{
+#if defined(_TTHREAD_WIN32_)
+  return TlsGetValue(key);
+#else
+  return pthread_getspecific(key);
+#endif
+}
+
+int tss_set(tss_t key, void *val)
+{
+#if defined(_TTHREAD_WIN32_)
+  if (TlsSetValue(key, val) == 0)
+  {
+    return thrd_error;
+  }
+#else
+  if (pthread_setspecific(key, val) != 0)
+  {
+    return thrd_error;
+  }
+#endif
+  return thrd_success;
+}
+
+#if defined(_TTHREAD_EMULATE_CLOCK_GETTIME_)
+int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts)
+{
+#if defined(_TTHREAD_WIN32_)
+  struct _timeb tb;
+  _ftime(&tb);
+  ts->tv_sec = (time_t)tb.time;
+  ts->tv_nsec = 1000000L * (long)tb.millitm;
+#else
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  ts->tv_sec = (time_t)tv.tv_sec;
+  ts->tv_nsec = 1000L * (long)tv.tv_usec;
+#endif
+  return 0;
+}
+#endif // _TTHREAD_EMULATE_CLOCK_GETTIME_
+
diff --git a/src/deps/tinycthread.h b/src/deps/tinycthread.h
new file mode 100644 (file)
index 0000000..42958c3
--- /dev/null
@@ -0,0 +1,443 @@
+/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*-
+Copyright (c) 2012 Marcus Geelnard
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+    1. The origin of this software must not be misrepresented; you must not
+    claim that you wrote the original software. If you use this software
+    in a product, an acknowledgment in the product documentation would be
+    appreciated but is not required.
+
+    2. Altered source versions must be plainly marked as such, and must not be
+    misrepresented as being the original software.
+
+    3. This notice may not be removed or altered from any source
+    distribution.
+*/
+
+#ifndef _TINYCTHREAD_H_
+#define _TINYCTHREAD_H_
+
+/**
+* @file
+* @mainpage TinyCThread API Reference
+*
+* @section intro_sec Introduction
+* TinyCThread is a minimal, portable implementation of basic threading
+* classes for C.
+*
+* They closely mimic the functionality and naming of the C11 standard, and
+* should be easily replaceable with the corresponding standard variants.
+*
+* @section port_sec Portability
+* The Win32 variant uses the native Win32 API for implementing the thread
+* classes, while for other systems, the POSIX threads API (pthread) is used.
+*
+* @section misc_sec Miscellaneous
+* The following special keywords are available: #_Thread_local.
+*
+* For more detailed information, browse the different sections of this
+* documentation. A good place to start is:
+* tinycthread.h.
+*/
+
+/* Which platform are we on? */
+#if !defined(_TTHREAD_PLATFORM_DEFINED_)
+  #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
+    #define _TTHREAD_WIN32_
+  #else
+    #define _TTHREAD_POSIX_
+  #endif
+  #define _TTHREAD_PLATFORM_DEFINED_
+#endif
+
+/* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */
+#if defined(_TTHREAD_POSIX_)
+  #undef _FEATURES_H
+  #if !defined(_GNU_SOURCE)
+    #define _GNU_SOURCE
+  #endif
+  #if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L)
+    #undef _POSIX_C_SOURCE
+    #define _POSIX_C_SOURCE 199309L
+  #endif
+  #if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500)
+    #undef _XOPEN_SOURCE
+    #define _XOPEN_SOURCE 500
+  #endif
+#endif
+
+/* Generic includes */
+#include <time.h>
+
+/* Platform specific includes */
+#if defined(_TTHREAD_POSIX_)
+  #include <sys/time.h>
+  #include <pthread.h>
+#elif defined(_TTHREAD_WIN32_)
+  #ifndef WIN32_LEAN_AND_MEAN
+    #define WIN32_LEAN_AND_MEAN
+    #define __UNDEF_LEAN_AND_MEAN
+  #endif
+  #include <windows.h>
+  #ifdef __UNDEF_LEAN_AND_MEAN
+    #undef WIN32_LEAN_AND_MEAN
+    #undef __UNDEF_LEAN_AND_MEAN
+  #endif
+#endif
+
+/* Workaround for missing TIME_UTC: If time.h doesn't provide TIME_UTC,
+   it's quite likely that libc does not support it either. Hence, fall back to
+   the only other supported time specifier: CLOCK_REALTIME (and if that fails,
+   we're probably emulating clock_gettime anyway, so anything goes). */
+#ifndef TIME_UTC
+  #ifdef CLOCK_REALTIME
+    #define TIME_UTC CLOCK_REALTIME
+  #else
+    #define TIME_UTC 0
+  #endif
+#endif
+
+/* Workaround for missing clock_gettime (most Windows compilers, afaik) */
+#if defined(_TTHREAD_WIN32_) || defined(__APPLE_CC__)
+#define _TTHREAD_EMULATE_CLOCK_GETTIME_
+/* Emulate struct timespec */
+#if defined(_TTHREAD_WIN32_)
+struct _ttherad_timespec {
+  time_t tv_sec;
+  long   tv_nsec;
+};
+#define timespec _ttherad_timespec
+#endif
+
+/* Emulate clockid_t */
+typedef int _tthread_clockid_t;
+#define clockid_t _tthread_clockid_t
+
+/* Emulate clock_gettime */
+int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts);
+#define clock_gettime _tthread_clock_gettime
+#ifndef CLOCK_REALTIME
+  #define CLOCK_REALTIME 0
+#endif
+#endif
+
+
+/** TinyCThread version (major number). */
+#define TINYCTHREAD_VERSION_MAJOR 1
+/** TinyCThread version (minor number). */
+#define TINYCTHREAD_VERSION_MINOR 1
+/** TinyCThread version (full version). */
+#define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR)
+
+/**
+* @def _Thread_local
+* Thread local storage keyword.
+* A variable that is declared with the @c _Thread_local keyword makes the
+* value of the variable local to each thread (known as thread-local storage,
+* or TLS). Example usage:
+* @code
+* // This variable is local to each thread.
+* _Thread_local int variable;
+* @endcode
+* @note The @c _Thread_local keyword is a macro that maps to the corresponding
+* compiler directive (e.g. @c __declspec(thread)).
+* @note This directive is currently not supported on Mac OS X (it will give
+* a compiler error), since compile-time TLS is not supported in the Mac OS X
+* executable format. Also, some older versions of MinGW (before GCC 4.x) do
+* not support this directive.
+* @hideinitializer
+*/
+
+/* FIXME: Check for a PROPER value of __STDC_VERSION__ to know if we have C11 */
+#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local)
+ #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
+  #define _Thread_local __thread
+ #else
+  #define _Thread_local __declspec(thread)
+ #endif
+#endif
+
+/* Macros */
+#define TSS_DTOR_ITERATIONS 0
+
+/* Function return values */
+#define thrd_error    0 /**< The requested operation failed */
+#define thrd_success  1 /**< The requested operation succeeded */
+#define thrd_timeout  2 /**< The time specified in the call was reached without acquiring the requested resource */
+#define thrd_busy     3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */
+#define thrd_nomem    4 /**< The requested operation failed because it was unable to allocate memory */
+
+/* Mutex types */
+#define mtx_plain     1
+#define mtx_timed     2
+#define mtx_try       4
+#define mtx_recursive 8
+
+/* Mutex */
+#if defined(_TTHREAD_WIN32_)
+typedef struct {
+  CRITICAL_SECTION mHandle;   /* Critical section handle */
+  int mAlreadyLocked;         /* TRUE if the mutex is already locked */
+  int mRecursive;             /* TRUE if the mutex is recursive */
+} mtx_t;
+#else
+typedef pthread_mutex_t mtx_t;
+#endif
+
+/** Create a mutex object.
+* @param mtx A mutex object.
+* @param type Bit-mask that must have one of the following six values:
+*   @li @c mtx_plain for a simple non-recursive mutex
+*   @li @c mtx_timed for a non-recursive mutex that supports timeout
+*   @li @c mtx_try for a non-recursive mutex that supports test and return
+*   @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive)
+*   @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive)
+*   @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive)
+* @return @ref thrd_success on success, or @ref thrd_error if the request could
+* not be honored.
+*/
+int mtx_init(mtx_t *mtx, int type);
+
+/** Release any resources used by the given mutex.
+* @param mtx A mutex object.
+*/
+void mtx_destroy(mtx_t *mtx);
+
+/** Lock the given mutex.
+* Blocks until the given mutex can be locked. If the mutex is non-recursive, and
+* the calling thread already has a lock on the mutex, this call will block
+* forever.
+* @param mtx A mutex object.
+* @return @ref thrd_success on success, or @ref thrd_error if the request could
+* not be honored.
+*/
+int mtx_lock(mtx_t *mtx);
+
+/** NOT YET IMPLEMENTED.
+*/
+int mtx_timedlock(mtx_t *mtx, const struct timespec *ts);
+
+/** Try to lock the given mutex.
+* The specified mutex shall support either test and return or timeout. If the
+* mutex is already locked, the function returns without blocking.
+* @param mtx A mutex object.
+* @return @ref thrd_success on success, or @ref thrd_busy if the resource
+* requested is already in use, or @ref thrd_error if the request could not be
+* honored.
+*/
+int mtx_trylock(mtx_t *mtx);
+
+/** Unlock the given mutex.
+* @param mtx A mutex object.
+* @return @ref thrd_success on success, or @ref thrd_error if the request could
+* not be honored.
+*/
+int mtx_unlock(mtx_t *mtx);
+
+/* Condition variable */
+#if defined(_TTHREAD_WIN32_)
+typedef struct {
+  HANDLE mEvents[2];                  /* Signal and broadcast event HANDLEs. */
+  unsigned int mWaitersCount;         /* Count of the number of waiters. */
+  CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */
+} cnd_t;
+#else
+typedef pthread_cond_t cnd_t;
+#endif
+
+/** Create a condition variable object.
+* @param cond A condition variable object.
+* @return @ref thrd_success on success, or @ref thrd_error if the request could
+* not be honored.
+*/
+int cnd_init(cnd_t *cond);
+
+/** Release any resources used by the given condition variable.
+* @param cond A condition variable object.
+*/
+void cnd_destroy(cnd_t *cond);
+
+/** Signal a condition variable.
+* Unblocks one of the threads that are blocked on the given condition variable
+* at the time of the call. If no threads are blocked on the condition variable
+* at the time of the call, the function does nothing and return success.
+* @param cond A condition variable object.
+* @return @ref thrd_success on success, or @ref thrd_error if the request could
+* not be honored.
+*/
+int cnd_signal(cnd_t *cond);
+
+/** Broadcast a condition variable.
+* Unblocks all of the threads that are blocked on the given condition variable
+* at the time of the call. If no threads are blocked on the condition variable
+* at the time of the call, the function does nothing and return success.
+* @param cond A condition variable object.
+* @return @ref thrd_success on success, or @ref thrd_error if the request could
+* not be honored.
+*/
+int cnd_broadcast(cnd_t *cond);
+
+/** Wait for a condition variable to become signaled.
+* The function atomically unlocks the given mutex and endeavors to block until
+* the given condition variable is signaled by a call to cnd_signal or to
+* cnd_broadcast. When the calling thread becomes unblocked it locks the mutex
+* before it returns.
+* @param cond A condition variable object.
+* @param mtx A mutex object.
+* @return @ref thrd_success on success, or @ref thrd_error if the request could
+* not be honored.
+*/
+int cnd_wait(cnd_t *cond, mtx_t *mtx);
+
+/** Wait for a condition variable to become signaled.
+* The function atomically unlocks the given mutex and endeavors to block until
+* the given condition variable is signaled by a call to cnd_signal or to
+* cnd_broadcast, or until after the specified time. When the calling thread
+* becomes unblocked it locks the mutex before it returns.
+* @param cond A condition variable object.
+* @param mtx A mutex object.
+* @param xt A point in time at which the request will time out (absolute time).
+* @return @ref thrd_success upon success, or @ref thrd_timeout if the time
+* specified in the call was reached without acquiring the requested resource, or
+* @ref thrd_error if the request could not be honored.
+*/
+int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts);
+
+/* Thread */
+#if defined(_TTHREAD_WIN32_)
+typedef HANDLE thrd_t;
+#else
+typedef pthread_t thrd_t;
+#endif
+
+/** Thread start function.
+* Any thread that is started with the @ref thrd_create() function must be
+* started through a function of this type.
+* @param arg The thread argument (the @c arg argument of the corresponding
+*        @ref thrd_create() call).
+* @return The thread return value, which can be obtained by another thread
+* by using the @ref thrd_join() function.
+*/
+typedef int (*thrd_start_t)(void *arg);
+
+/** Create a new thread.
+* @param thr Identifier of the newly created thread.
+* @param func A function pointer to the function that will be executed in
+*        the new thread.
+* @param arg An argument to the thread function.
+* @return @ref thrd_success on success, or @ref thrd_nomem if no memory could
+* be allocated for the thread requested, or @ref thrd_error if the request
+* could not be honored.
+* @note A thread’s identifier may be reused for a different thread once the
+* original thread has exited and either been detached or joined to another
+* thread.
+*/
+int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
+
+/** Identify the calling thread.
+* @return The identifier of the calling thread.
+*/
+thrd_t thrd_current(void);
+
+/** NOT YET IMPLEMENTED.
+*/
+int thrd_detach(thrd_t thr);
+
+/** Compare two thread identifiers.
+* The function determines if two thread identifiers refer to the same thread.
+* @return Zero if the two thread identifiers refer to different threads.
+* Otherwise a nonzero value is returned.
+*/
+int thrd_equal(thrd_t thr0, thrd_t thr1);
+
+/** Terminate execution of the calling thread.
+* @param res Result code of the calling thread.
+*/
+void thrd_exit(int res);
+
+/** Wait for a thread to terminate.
+* The function joins the given thread with the current thread by blocking
+* until the other thread has terminated.
+* @param thr The thread to join with.
+* @param res If this pointer is not NULL, the function will store the result
+*        code of the given thread in the integer pointed to by @c res.
+* @return @ref thrd_success on success, or @ref thrd_error if the request could
+* not be honored.
+*/
+int thrd_join(thrd_t thr, int *res);
+
+/** Put the calling thread to sleep.
+* Suspend execution of the calling thread.
+* @param time_point A point in time at which the thread will resume (absolute time).
+* @param remaining If non-NULL, this parameter will hold the remaining time until
+*                  time_point upon return. This will typically be zero, but if
+*                  the thread was woken up by a signal that is not ignored before
+*                  time_point was reached @c remaining will hold a positive
+*                  time.
+* @return 0 (zero) on successful sleep, or -1 if an interrupt occurred.
+*/
+int thrd_sleep(const struct timespec *time_point, struct timespec *remaining);
+
+/** Yield execution to another thread.
+* Permit other threads to run, even if the current thread would ordinarily
+* continue to run.
+*/
+void thrd_yield(void);
+
+/* Thread local storage */
+#if defined(_TTHREAD_WIN32_)
+typedef DWORD tss_t;
+#else
+typedef pthread_key_t tss_t;
+#endif
+
+/** Destructor function for a thread-specific storage.
+* @param val The value of the destructed thread-specific storage.
+*/
+typedef void (*tss_dtor_t)(void *val);
+
+/** Create a thread-specific storage.
+* @param key The unique key identifier that will be set if the function is
+*        successful.
+* @param dtor Destructor function. This can be NULL.
+* @return @ref thrd_success on success, or @ref thrd_error if the request could
+* not be honored.
+* @note The destructor function is not supported under Windows. If @c dtor is
+* not NULL when calling this function under Windows, the function will fail
+* and return @ref thrd_error.
+*/
+int tss_create(tss_t *key, tss_dtor_t dtor);
+
+/** Delete a thread-specific storage.
+* The function releases any resources used by the given thread-specific
+* storage.
+* @param key The key that shall be deleted.
+*/
+void tss_delete(tss_t key);
+
+/** Get the value for a thread-specific storage.
+* @param key The thread-specific storage identifier.
+* @return The value for the current thread held in the given thread-specific
+* storage.
+*/
+void *tss_get(tss_t key);
+
+/** Set the value for a thread-specific storage.
+* @param key The thread-specific storage identifier.
+* @param val The value of the thread-specific storage to set for the current
+*        thread.
+* @return @ref thrd_success on success, or @ref thrd_error if the request could
+* not be honored.
+*/
+int tss_set(tss_t key, void *val);
+
+
+#endif /* _TINYTHREAD_H_ */
+
index c7f5faf99ff927cc1747f4ac277afaac1272f8a7..8feab5c68256526476e7586f1a5603038efcead5 100644 (file)
@@ -91,7 +91,7 @@ VkvgContext vkvg_create(VkvgSurface surf)
        VkvgDevice dev = surf->dev;
        VkvgContext ctx = NULL;
 
-       if (_vkvg_device_try_get_cached_context (dev, &ctx) ) {
+       if (_device_try_get_cached_context (dev, &ctx) ) {
                ctx->pSurf = surf;
 
                if (!surf || surf->status) {
@@ -294,7 +294,7 @@ void vkvg_destroy (VkvgContext ctx)
 #endif
 
        if (!ctx->status && ctx->dev->cachedContextCount < VKVG_MAX_CACHED_CONTEXT_COUNT) {
-               _vkvg_device_store_context (ctx);
+               _device_store_context (ctx);
                return;
        }
 
index 4e1cf778ee51c8858e1b9b9b878b7be33ea00909..0a0d2b6ead21bf77df5dddd96e1509d0aef40aa1 100644 (file)
@@ -424,8 +424,8 @@ bool _wait_and_submit_cmd (VkvgContext ctx){
 
        if (!_wait_flush_fence (ctx))
                return false;
-       _vkvg_device_reset_fence(ctx->pSurf->dev, ctx->flushFence);
-       _submit_cmd (ctx->pSurf->dev, &ctx->cmd, ctx->flushFence);
+       _device_reset_fence(ctx->pSurf->dev, ctx->flushFence);
+       _device_submit_cmd (ctx->pSurf->dev, &ctx->cmd, ctx->flushFence);
 
        if (ctx->cmd == ctx->cmdBuffers[0])
                ctx->cmd = ctx->cmdBuffers[1];
@@ -854,7 +854,8 @@ void _init_descriptor_sets (VkvgContext ctx){
 }
 void _release_context_ressources (VkvgContext ctx) {
        VkDevice dev = ctx->dev->vkDev;
-       _vkvg_device_destroy_fence (ctx->dev, ctx->flushFence);
+       
+       _device_destroy_fence (ctx->dev, ctx->flushFence);
        vkFreeCommandBuffers(dev, ctx->cmdPool, 2, ctx->cmdBuffers);
        vkDestroyCommandPool(dev, ctx->cmdPool, NULL);
 
index 2691d26ff8e1cef0ab1c4ed38749c053f3ed770e..bb2433a8f2da0be4c952f6dc5121fbd949dfb0ce 100644 (file)
@@ -89,30 +89,35 @@ void _device_init (VkvgDevice dev, VkInstance inst, VkPhysicalDevice phy, VkDevi
 
        _create_empty_texture           (dev, format, dev->supportedTiling);
 
-#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_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");
-
-       vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslSrc, "DSLayout SOURCE");
-       vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslFont, "DSLayout FONT");
-       vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslGrad, "DSLayout GRADIENT");
-       vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE_LAYOUT, (uint64_t)dev->pipelineLayout, "PLLayout dev");
-
-#ifndef __APPLE__
-       vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipelinePolyFill, "PL Poly fill");
-#endif
-       vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipelineClipping, "PL Clipping");
-       vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_OVER, "PL draw Over");
-       vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_SUB, "PL draw Substract");
-       vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_CLEAR, "PL draw Clear");
-
-       vkh_image_set_name(dev->emptyImg, "empty IMG");
-       vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(dev->emptyImg), "empty IMG VIEW");
-       vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(dev->emptyImg), "empty IMG SAMPLER");
+#ifdef DEBUG
+       #if __linux__
+               _linux_register_error_handler ();
+       #endif
+       #ifdef 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_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");
+
+               vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslSrc, "DSLayout SOURCE");
+               vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslFont, "DSLayout FONT");
+               vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslGrad, "DSLayout GRADIENT");
+               vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE_LAYOUT, (uint64_t)dev->pipelineLayout, "PLLayout dev");
+
+               #ifndef __APPLE__
+                       vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipelinePolyFill, "PL Poly fill");
+               #endif
+               vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipelineClipping, "PL Clipping");
+               vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_OVER, "PL draw Over");
+               vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_SUB, "PL draw Substract");
+               vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_CLEAR, "PL draw Clear");
+
+               vkh_image_set_name(dev->emptyImg, "empty IMG");
+               vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(dev->emptyImg), "empty IMG VIEW");
+               vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(dev->emptyImg), "empty IMG SAMPLER");
+       #endif
 #endif
        dev->status = VKVG_STATUS_SUCCESS;
 }
@@ -257,9 +262,13 @@ VkvgDevice vkvg_device_create_from_vk_multisample(VkInstance inst, VkPhysicalDev
 
 void vkvg_device_destroy (VkvgDevice dev)
 {
+       LOCK_DEVICE
        dev->references--;
-       if (dev->references > 0)
+       if (dev->references > 0) {
+               UNLOCK_DEVICE
                return;
+       }
+       UNLOCK_DEVICE
 
        while (dev->cachedContextCount > 0)
                _release_context_ressources (dev->cachedContext[--dev->cachedContextCount]);
@@ -303,6 +312,9 @@ void vkvg_device_destroy (VkvgDevice dev)
 
        vmaDestroyAllocator (dev->allocator);
 
+       if (dev->threadAware)
+               mtx_destroy (&dev->mutex);
+
        if (dev->vkhDev) {
                VkhApp app = vkh_device_get_app (dev->vkhDev);
                vkh_device_destroy (dev->vkhDev);
@@ -316,7 +328,9 @@ vkvg_status_t vkvg_device_status (VkvgDevice dev) {
        return dev->status;
 }
 VkvgDevice vkvg_device_reference (VkvgDevice dev) {
+       LOCK_DEVICE
        dev->references++;
+       UNLOCK_DEVICE
        return dev;
 }
 uint32_t vkvg_device_get_reference_count (VkvgDevice dev) {
@@ -332,10 +346,16 @@ void vkvg_device_get_dpy (VkvgDevice dev, int* hdpy, int* vdpy) {
        *hdpy = dev->hdpi;
        *vdpy = dev->vdpi;
 }
-void vkvg_device_set_guards (VkvgDevice dev, vkvg_device_guard lock_callback, vkvg_device_guard unlock_callback, void* user_data) {
-       dev->deviceLockGuard            = lock_callback;
-       dev->deviceUnlockGuard          = unlock_callback;
-       dev->deviceGuardUserData        = user_data;
+void vkvg_device_set_thread_aware (VkvgDevice dev, uint32_t thread_aware) {
+       if (thread_aware) {
+               if (dev->threadAware)
+                       return;
+               mtx_init (&dev->mutex, mtx_plain);
+               dev->threadAware = true;
+       } else if (dev->threadAware) {
+               mtx_destroy (&dev->mutex);
+               dev->threadAware = false;
+       }
 }
 #if VKVG_DBG_STATS
 vkvg_debug_stats_t vkvg_device_get_stats (VkvgDevice dev) {
index 5d08bf1cea822e0be2876fc5663991e1723381f4..b7303e8eea4593dc504b7722c4b328bfd9ac3f87 100644 (file)
@@ -64,7 +64,7 @@ bool _try_get_phyinfo (VkhPhyInfo* phys, uint32_t phyCount, VkPhysicalDeviceType
        }
        return false;
 }
-void _flush_all_contexes (VkvgDevice dev){
+void _device_flush_all_contexes (VkvgDevice dev){
        /*VkvgContext ctx = dev->lastCtx;
        while (ctx != NULL){
                if (ctx->cmdStarted)
@@ -419,81 +419,71 @@ void _createDescriptorSetLayout (VkvgDevice dev) {
        VK_CHECK_RESULT(vkCreatePipelineLayout(dev->vkDev, &pipelineLayoutCreateInfo, NULL, &dev->pipelineLayout));
 }
 
-void _wait_idle (VkvgDevice dev) {
+void _device_wait_idle (VkvgDevice dev) {
        vkDeviceWaitIdle (dev->vkDev);
 }
-void _wait_and_reset_device_fence (VkvgDevice dev) {
+void _device_wait_and_reset_device_fence (VkvgDevice dev) {
        vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX);
-       _vkvg_device_reset_fence(dev, dev->fence);
+       _device_reset_fence(dev, dev->fence);
 }
 
-void _vkvg_device_destroy_fence (VkvgDevice dev, VkFence fence) {
-       if (dev->deviceLockGuard)
-               dev->deviceLockGuard (dev->deviceGuardUserData);
+void _device_destroy_fence (VkvgDevice dev, VkFence fence) {
+       LOCK_DEVICE
 
        if (dev->gQLastFence == fence)
                dev->gQLastFence = VK_NULL_HANDLE;
 
        vkDestroyFence (dev->vkDev, fence, NULL);
 
-       if (dev->deviceUnlockGuard)
-               dev->deviceUnlockGuard (dev->deviceGuardUserData);
+       UNLOCK_DEVICE
 }
-void _vkvg_device_reset_fence (VkvgDevice dev, VkFence fence){
-       if (dev->deviceLockGuard)
-               dev->deviceLockGuard (dev->deviceGuardUserData);
+void _device_reset_fence (VkvgDevice dev, VkFence fence){
+       LOCK_DEVICE
 
        if (dev->gQLastFence == fence)
                dev->gQLastFence = VK_NULL_HANDLE;
 
        ResetFences (dev->vkDev, 1, &fence);
 
-       if (dev->deviceUnlockGuard)
-               dev->deviceUnlockGuard (dev->deviceGuardUserData);
+       UNLOCK_DEVICE
 }
-void _vkvg_device_wait_fence (VkvgDevice dev, VkFence fence){
+void _device_wait_fence (VkvgDevice dev, VkFence fence){
 
 }
-void _vkvg_device_wait_and_reset_fence (VkvgDevice dev, VkFence fence){
+void _device_wait_and_reset_fence      (VkvgDevice dev, VkFence fence){
 
 }
-bool _vkvg_device_try_get_cached_context (VkvgDevice dev, VkvgContext* pCtx) {
-       if (dev->deviceLockGuard)
-               dev->deviceLockGuard (dev->deviceGuardUserData);
+bool _device_try_get_cached_context (VkvgDevice dev, VkvgContext* pCtx) {
+       LOCK_DEVICE
 
        if (dev->cachedContextCount)
                *pCtx = dev->cachedContext[--dev->cachedContextCount];
        else
                *pCtx = NULL;
 
-       if (dev->deviceUnlockGuard)
-               dev->deviceUnlockGuard (dev->deviceGuardUserData);
+       UNLOCK_DEVICE
 
        return *pCtx != NULL;
 }
-void _vkvg_device_store_context (VkvgContext ctx) {
+void _device_store_context (VkvgContext ctx) {
        VkvgDevice dev = ctx->dev;
 
-       if (dev->deviceLockGuard)
-               dev->deviceLockGuard (dev->deviceGuardUserData);
+       LOCK_DEVICE
 
        if (dev->gQLastFence == ctx->flushFence)
                dev->gQLastFence = VK_NULL_HANDLE;
        dev->cachedContext[dev->cachedContextCount++] = ctx;
        ctx->references++;
 
-       if (dev->deviceUnlockGuard)
-               dev->deviceUnlockGuard (dev->deviceGuardUserData);
+       UNLOCK_DEVICE
 }
-void _submit_cmd (VkvgDevice dev, VkCommandBuffer* cmd, VkFence fence) {
-       if (dev->deviceLockGuard)
-               dev->deviceLockGuard (dev->deviceGuardUserData);
+void _device_submit_cmd (VkvgDevice dev, VkCommandBuffer* cmd, VkFence fence) {
+       LOCK_DEVICE
        if (dev->gQLastFence != VK_NULL_HANDLE)
                WaitForFences (dev->vkDev, 1, &dev->gQLastFence, VK_TRUE, VKVG_FENCE_TIMEOUT);
        vkh_cmd_submit (dev->gQueue, cmd, fence);
        dev->gQLastFence = fence;
-       if (dev->deviceUnlockGuard)
-               dev->deviceUnlockGuard (dev->deviceGuardUserData);
+       UNLOCK_DEVICE
 }
 
 bool _init_function_pointers (VkvgDevice dev) {
@@ -530,14 +520,14 @@ void _create_empty_texture (VkvgDevice dev, VkFormat format, VkImageTiling tilin
                                                                         VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
        vkh_image_create_descriptor(dev->emptyImg, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
 
-       _wait_and_reset_device_fence (dev);
+       _device_wait_and_reset_device_fence (dev);
 
        vkh_cmd_begin (dev->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
        vkh_image_set_layout (dev->cmd, dev->emptyImg, VK_IMAGE_ASPECT_COLOR_BIT,
                                                  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);
+       _device_submit_cmd (dev, &dev->cmd, dev->fence);
 }
 
 void _check_best_image_tiling (VkvgDevice dev, VkFormat format) {
index db2c3d3f7e360400922e8e121660c18421af4b56..33c275b189ef4a343af5ef6370f3b468e2eaa172 100644 (file)
@@ -65,9 +65,8 @@ typedef struct _vkvg_device_t{
        VkFormat                                pngStagFormat;                  /**< Supported vulkan image format png write staging img */
        VkImageTiling                   pngStagTiling;                  /**< tiling for the blit operation */
 
-       vkvg_device_guard               deviceLockGuard;
-       vkvg_device_guard               deviceUnlockGuard;
-       void*                                   deviceGuardUserData;
+       mtx_t                                   mutex;                                  /**< protect device access (queue, cahes, ...)from ctxs in separate threads */
+       bool                                    threadAware;                    /**< if true, mutex is created and guard device queue and caches access */
        VkhQueue                                gQueue;                                 /**< Vulkan Queue with Graphic flag */
        VkFence                                 gQLastFence;
 
@@ -87,21 +86,14 @@ typedef struct _vkvg_device_t{
        VkPipeline                              pipelinePolyFill;               /**< even-odd polygon filling first step */
        VkPipeline                              pipelineClipping;               /**< draw on stencil to update clipping regions */
 
-#ifdef VKVG_WIRED_DEBUG
-       VkPipeline                              pipelineWired;
-       VkPipeline                              pipelineLineList;
-#endif
-#if VKVG_DBG_STATS
-       vkvg_debug_stats_t              debug_stats;                    /**< debug statistics on memory usage and vulkan ressources */
-#endif
        VkPipelineCache                 pipelineCache;                  /**< speed up startup by caching configured pipelines on disk */
        VkPipelineLayout                pipelineLayout;                 /**< layout common to all pipelines */
        VkDescriptorSetLayout   dslFont;                                /**< font cache descriptors layout */
        VkDescriptorSetLayout   dslSrc;                                 /**< context source surface descriptors layout */
        VkDescriptorSetLayout   dslGrad;                                /**< context gradient descriptors layout */
 
-       int             hdpi,                                                                   /**< only used for FreeType fonts and svg loading */
-                       vdpi;
+       int                                             hdpi,                                   /**< only used for FreeType fonts and svg loading */
+                                                       vdpi;
 
        VkhDevice                               vkhDev;                                 /**< old VkhDev created during vulkan context creation by @ref vkvg_device_create. */
 
@@ -110,14 +102,29 @@ typedef struct _vkvg_device_t{
        bool                                    deferredResolve;                /**< if true, resolve only on context destruction and set as source */
        vkvg_status_t                   status;                                 /**< Current status of device, affected by last operation */
 
-       _font_cache_t*  fontCache;                                              /**< Store everything relative to common font caching system */
+       _font_cache_t*                  fontCache;                              /**< Store everything relative to common font caching system */
+
+       VkvgContext                             lastCtx;                                /**< last element of double linked list of context, used to trigger font caching system update on all contexts*/
 
-       VkvgContext             lastCtx;                                                /**< last element of double linked list of context, used to trigger font caching system update on all contexts*/
+       int32_t                                 cachedContextCount;
+       VkvgContext                             cachedContext[VKVG_MAX_CACHED_CONTEXT_COUNT];
 
-       int32_t                 cachedContextCount;
-       VkvgContext             cachedContext[VKVG_MAX_CACHED_CONTEXT_COUNT];
+#ifdef VKVG_WIRED_DEBUG
+       VkPipeline                              pipelineWired;
+       VkPipeline                              pipelineLineList;
+#endif
+#if VKVG_DBG_STATS
+       vkvg_debug_stats_t              debug_stats;                    /**< debug statistics on memory usage and vulkan ressources */
+#endif
 }vkvg_device;
 
+#define LOCK_DEVICE \
+       if (dev->threadAware)\
+               mtx_lock (&dev->mutex);
+#define UNLOCK_DEVICE \
+       if (dev->threadAware)\
+               mtx_unlock (&dev->mutex);
+
 bool _try_get_phyinfo                  (VkhPhyInfo* phys, uint32_t phyCount, VkPhysicalDeviceType gpuType, VkhPhyInfo* phy);
 bool _init_function_pointers   (VkvgDevice dev);
 void _create_empty_texture             (VkvgDevice dev, VkFormat format, VkImageTiling tiling);
@@ -127,16 +134,16 @@ void _create_pipeline_cache               (VkvgDevice dev);
 VkRenderPass _createRenderPassMS(VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp);
 VkRenderPass _createRenderPassNoResolve(VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp);
 void _setupPipelines                   (VkvgDevice dev);
-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 _vkvg_device_destroy_fence                        (VkvgDevice dev, VkFence fence);
-void _vkvg_device_reset_fence                  (VkvgDevice dev, VkFence fence);
-void _vkvg_device_wait_fence                   (VkvgDevice dev, VkFence fence);
-void _vkvg_device_wait_and_reset_fence (VkvgDevice dev, VkFence fence);
-bool _vkvg_device_try_get_cached_context(VkvgDevice dev, VkvgContext* pCtx);
-void _vkvg_device_store_context                        (VkvgContext ctx);
+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);
+
+void _device_destroy_fence                     (VkvgDevice dev, VkFence fence);
+void _device_reset_fence                       (VkvgDevice dev, VkFence fence);
+void _device_wait_fence                        (VkvgDevice dev, VkFence fence);
+void _device_wait_and_reset_fence      (VkvgDevice dev, VkFence fence);
+bool _device_try_get_cached_context(VkvgDevice dev, VkvgContext* pCtx);
+void _device_store_context                     (VkvgContext ctx);
 #endif
index 7d34bee7e5ed66a6ee139400c441fed04b9a8b76..90f776622a528f02348598e9533d0cb64b86e8c0 100644 (file)
@@ -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);
+       _device_submit_cmd (dev, &cache->cmd, cache->uploadFence);
 
        cache->hostBuff = (uint8_t*)malloc(buffLength);
        cache->pensY = (int*)calloc(cache->texLength, sizeof(int));
@@ -99,12 +99,12 @@ void _init_fonts_cache (VkvgDevice dev){
 void _increase_font_tex_array (VkvgDevice dev){
        LOG(VKVG_LOG_INFO, "_increase_font_tex_array\n");
 
-       _flush_all_contexes (dev);
+       _device_flush_all_contexes (dev);
 
        _font_cache_t* cache = dev->fontCache;
 
        vkWaitForFences         (dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX);
-       _vkvg_device_reset_fence (dev, cache->uploadFence);
+       _device_reset_fence (dev, cache->uploadFence);
 
        vkResetCommandBuffer(cache->cmd, 0);
 
@@ -140,7 +140,7 @@ void _increase_font_tex_array (VkvgDevice dev){
 
        VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd));
 
-       _submit_cmd                     (dev, &cache->cmd, cache->uploadFence);
+       _device_submit_cmd                      (dev, &cache->cmd, cache->uploadFence);
        vkWaitForFences         (dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX);
 
        cache->pensY = (int*)realloc(cache->pensY, newSize * sizeof(int));
@@ -155,7 +155,7 @@ void _increase_font_tex_array (VkvgDevice dev){
                _update_descriptor_set  (next, cache->texture, next->dsFont);
                next = next->pPrev;
        }*/
-       _wait_idle(dev);
+       _device_wait_idle(dev);
 }
 ///Start a new line in font cache, increase texture layer count if needed.
 void _init_next_line_in_tex_cache (VkvgDevice dev, _vkvg_font_t* f){
@@ -242,7 +242,7 @@ void _flush_chars_to_tex (VkvgDevice dev, _vkvg_font_t* f) {
 
        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);
-       _vkvg_device_reset_fence (dev, cache->uploadFence);
+       _device_reset_fence (dev, cache->uploadFence);
        vkResetCommandBuffer(cache->cmd,0);
 
        memcpy(cache->buff.allocInfo.pMappedData, cache->hostBuff, (uint64_t)f->curLine.height * FONT_PAGE_SIZE * cache->texPixelSize);
@@ -269,7 +269,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);
+       _device_submit_cmd (dev, &cache->cmd, cache->uploadFence);
 
        f->curLine.penX += cache->stagingX;
        cache->stagingX = 0;
index 2b8b5c9557e5338fac624bc837916f842255b833..120d5d476e5af5396dd58589284fd5a73ec4135d 100644 (file)
@@ -73,6 +73,7 @@
        #define MIN(a,b) ((a) < (b) ? (a) : (b))
 #endif
 
+#include "deps/tinycthread.h"
 #include "cross_os.h"
 //width of the stencil buffer will determine the number of context saving/restore layers
 //the two first bits of the stencil are the FILL and the CLIP bits, all other bits are
index 89ff376411a96122dbb416f783e3fd68cc553888..21c08de904dbda362d1c554cfd9d1b25b73e3f47 100644 (file)
@@ -46,8 +46,8 @@ VkvgSurface vkvg_surface_create (VkvgDevice dev, uint32_t width, uint32_t height
 
        _create_surface_images (surf);
 
+       surf->status = VKVG_STATUS_SUCCESS;
        vkvg_device_reference (surf->dev);
-       dev->status = VKVG_STATUS_SUCCESS;
        return surf;
 }
 VkvgSurface vkvg_surface_create_for_VkhImage (VkvgDevice dev, void* vkhImg) {
@@ -73,8 +73,8 @@ VkvgSurface vkvg_surface_create_for_VkhImage (VkvgDevice dev, void* vkhImg) {
        _create_framebuffer                                     (surf);
        _clear_surface                                          (surf, VK_IMAGE_ASPECT_STENCIL_BIT);
 
+       surf->status = VKVG_STATUS_SUCCESS;
        vkvg_device_reference (surf->dev);
-       dev->status = VKVG_STATUS_SUCCESS;
        return surf;
 }
 //TODO: it would be better to blit in original size and create ms final image with dest surf dims
@@ -112,7 +112,7 @@ VkvgSurface vkvg_surface_create_from_bitmap (VkvgDevice dev, unsigned char* img,
 
        VkCommandBuffer cmd = dev->cmd;
 
-       _wait_and_reset_device_fence (dev);
+       _device_wait_and_reset_device_fence (dev);
 
        vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
        vkh_image_set_layout (cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT,
@@ -148,7 +148,7 @@ 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);
+       _device_submit_cmd              (dev, &cmd, dev->fence);
 
        //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);
@@ -178,8 +178,8 @@ VkvgSurface vkvg_surface_create_from_bitmap (VkvgDevice dev, unsigned char* img,
 
        vkh_image_destroy       (tmpImg);
 
+       surf->status = VKVG_STATUS_SUCCESS;
        vkvg_device_reference (surf->dev);
-       dev->status = VKVG_STATUS_SUCCESS;
        return surf;
 }
 VkvgSurface vkvg_surface_create_from_image (VkvgDevice dev, const char* filePath) {
@@ -201,9 +201,13 @@ VkvgSurface vkvg_surface_create_from_image (VkvgDevice dev, const char* filePath
 
 void vkvg_surface_destroy(VkvgSurface surf)
 {
+       LOCK_SURFACE(surf)
        surf->references--;
-       if (surf->references > 0)
+       if (surf->references > 0) {
+               UNLOCK_SURFACE(surf)
                return;
+       }
+       UNLOCK_SURFACE(surf)
 
        vkDestroyFramebuffer(surf->dev->vkDev, surf->fb, NULL);
 
@@ -213,12 +217,17 @@ void vkvg_surface_destroy(VkvgSurface surf)
        vkh_image_destroy(surf->imgMS);
        vkh_image_destroy(surf->stencil);
 
+       if (surf->dev->threadAware)
+               mtx_destroy (&surf->mutex);
+
        vkvg_device_destroy (surf->dev);
        free(surf);
 }
 
 VkvgSurface vkvg_surface_reference (VkvgSurface surf) {
+       LOCK_SURFACE(surf)
        surf->references++;
+       UNLOCK_SURFACE(surf)
        return surf;
 }
 uint32_t vkvg_surface_get_reference_count (VkvgSurface surf) {
@@ -260,7 +269,7 @@ vkvg_status_t vkvg_surface_write_to_png (VkvgSurface surf, const char* path){
                LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, null path\n");
                return VKVG_STATUS_WRITE_ERROR;
        }
-
+       LOCK_SURFACE(surf)
        VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1};
        VkvgDevice dev = surf->dev;
 
@@ -277,7 +286,7 @@ vkvg_status_t vkvg_surface_write_to_png (VkvgSurface surf, const char* path){
                                                                                 VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT);
 
        VkCommandBuffer cmd = dev->cmd;
-       _wait_and_reset_device_fence (dev);
+       _device_wait_and_reset_device_fence (dev);
 
        vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
        vkh_image_set_layout (cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT,
@@ -298,7 +307,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);
+       _device_submit_cmd              (dev, &cmd, dev->fence);
 
        VkhImage stagImgLinear = stagImg;
 
@@ -313,7 +322,7 @@ vkvg_status_t vkvg_surface_write_to_png (VkvgSurface surf, const char* path){
                        .dstOffset = {0},
                        .extent = {(int32_t)surf->width, (int32_t)surf->height, 1}
                };
-               _wait_and_reset_device_fence (dev);
+               _device_wait_and_reset_device_fence (dev);
 
                vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
                vkh_image_set_layout (cmd, stagImgLinear, VK_IMAGE_ASPECT_COLOR_BIT,
@@ -327,7 +336,7 @@ 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);
+               _device_submit_cmd              (dev, &cmd, dev->fence);
 
                vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX);
                vkh_image_destroy (stagImg);
@@ -343,6 +352,7 @@ vkvg_status_t vkvg_surface_write_to_png (VkvgSurface surf, const char* path){
        vkh_image_unmap (stagImgLinear);
        vkh_image_destroy (stagImgLinear);
 
+       UNLOCK_SURFACE(surf)
        return VKVG_STATUS_SUCCESS;
 }
 
@@ -356,6 +366,8 @@ vkvg_status_t vkvg_surface_write_to_memory (VkvgSurface surf, unsigned char* con
                return VKVG_STATUS_INVALID_IMAGE;
        }
 
+       LOCK_SURFACE(surf)
+
        VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1};
        VkvgDevice dev = surf->dev;
 
@@ -365,7 +377,7 @@ vkvg_status_t vkvg_surface_write_to_memory (VkvgSurface surf, unsigned char* con
                                                                                 VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT);
 
        VkCommandBuffer cmd = dev->cmd;
-       _wait_and_reset_device_fence (dev);
+       _device_wait_and_reset_device_fence (dev);
 
        vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
        vkh_image_set_layout (cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT,
@@ -386,7 +398,7 @@ 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);
+       _device_submit_cmd              (dev, &cmd, dev->fence);
        vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX);
 
        uint64_t stride = vkh_image_get_stride(stagImg);
@@ -403,5 +415,7 @@ vkvg_status_t vkvg_surface_write_to_memory (VkvgSurface surf, unsigned char* con
        vkh_image_unmap (stagImg);
        vkh_image_destroy (stagImg);
 
+       UNLOCK_SURFACE(surf)
+
        return VKVG_STATUS_SUCCESS;
 }
index a8cc8ff6bece6cb3d9d144ff275c1eb419fad416..4bcb0c1facedbb7572bd42375794ef905f25b5a8 100644 (file)
@@ -28,7 +28,7 @@ void _explicit_ms_resolve (VkvgSurface surf){
        VkvgDevice              dev = surf->dev;
        VkCommandBuffer cmd = dev->cmd;
 
-       _wait_and_reset_device_fence (dev);
+       _device_wait_and_reset_device_fence (dev);
 
        vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
        vkh_image_set_layout (cmd, surf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT,
@@ -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);
+       _device_submit_cmd (dev, &cmd, dev->fence);
 }
 
 void _clear_surface (VkvgSurface surf, VkImageAspectFlags aspect)
@@ -61,7 +61,7 @@ void _clear_surface (VkvgSurface surf, VkImageAspectFlags aspect)
        VkvgDevice              dev = surf->dev;
        VkCommandBuffer cmd = dev->cmd;
 
-       _wait_and_reset_device_fence (dev);
+       _device_wait_and_reset_device_fence (dev);
 
        vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
 
@@ -101,7 +101,7 @@ void _clear_surface (VkvgSurface surf, VkImageAspectFlags aspect)
        }
        vkh_cmd_end (cmd);
 
-       _submit_cmd (dev, &cmd, dev->fence);
+       _device_submit_cmd (dev, &cmd, dev->fence);
 }
 
 void _create_surface_main_image (VkvgSurface surf){
@@ -186,5 +186,7 @@ VkvgSurface _create_surface (VkvgDevice dev, VkFormat format) {
        }
        surf->dev = dev;
        surf->format = format;
+       if (dev->threadAware)
+               mtx_init (&surf->mutex, mtx_plain);
        return surf;
 }
index 506cd445f3f4f443c43ff06ab295200047417a95..e01092e3bf83491fca3bb15a0bafbea19d1b32b0 100644 (file)
@@ -38,8 +38,16 @@ typedef struct _vkvg_surface_t {
        uint32_t                references;
        vkvg_status_t   status;                                 /**< Current status of surface, affected by last operation */
        bool                    new;
+       mtx_t                   mutex;
 }vkvg_surface;
 
+#define LOCK_SURFACE(surf) \
+       if (surf->dev->threadAware)\
+               mtx_lock (&surf->mutex);
+#define UNLOCK_SURFACE(surf) \
+       if (surf->dev->threadAware)\
+               mtx_unlock (&surf->mutex);
+
 void _explicit_ms_resolve (VkvgSurface surf);
 void _clear_surface (VkvgSurface surf, VkImageAspectFlags aspect);
 void _create_surface_main_image (VkvgSurface surf);
index 00e14445b7d9d90dfa1967369ea1c58c0f4f954f..bd14e84f5b12ec102ddc1542b6c693eded34b9af 100644 (file)
@@ -1,7 +1,7 @@
 #include "test.h"
 #include "tinycthread.h"
 
-#define THREAD_COUNT 8
+#define THREAD_COUNT 16
 
 
 static int finishedThreadCount = 0;
@@ -17,12 +17,6 @@ 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 () {
 
@@ -48,20 +42,17 @@ int drawRectsThread () {
        return 0;
 }
 void fixedSizeRects(){
-       mtx_t gQMutex, mutex;
-       mtx_t* pgQMutex = &gQMutex;
+       mtx_t mutex;
        pmutex = &mutex;
 
-       mtx_init (pgQMutex, mtx_plain);
-       vkvg_device_set_guards (device, _before_submit, _after_submit, pgQMutex);
+       vkvg_device_set_thread_aware (device, 1);
 
        thrd_t threads[THREAD_COUNT];
 
        finishedThreadCount = 0;
        mtx_init (pmutex, mtx_plain);
-       for (uint32_t i=0; i<THREAD_COUNT; i++) {
+       for (uint32_t i=0; i<THREAD_COUNT; i++)
                thrd_create (&threads[i], drawRectsThread, NULL);
-       }
 
        const struct timespec ts = {1,0};
        while (finishedThreadCount < THREAD_COUNT)
@@ -72,9 +63,7 @@ void fixedSizeRects(){
        mtx_destroy (pmutex);
        pmutex = NULL;
 
-       vkvg_device_set_guards (device, NULL, NULL, NULL);
-       mtx_destroy (pgQMutex);
-       pgQMutex = NULL;
+       vkvg_device_set_thread_aware (device, 0);
 }
 
 int main(int argc, char *argv[]) {
index 1b79ecb15ac680aa4516049db6678b1fca4ea478..0485d13d84f76353b5703dce09c2652ce40a6f55 100644 (file)
@@ -1,7 +1,7 @@
 #include "test.h"
 #include "tinycthread.h"
 
-#define THREAD_COUNT 8
+#define THREAD_COUNT 32
 
 
 static int finishedThreadCount = 0;
@@ -37,20 +37,17 @@ int drawRectsThread () {
        return 0;
 }
 void fixedSizeRects(){
-       mtx_t gQMutex, mutex;
-       mtx_t* pgQMutex = &gQMutex;
+       mtx_t mutex;
        pmutex = &mutex;
 
-       mtx_init (pgQMutex, mtx_plain);
-       vkvg_device_set_guards (device, _before_submit, _after_submit, pgQMutex);
+       vkvg_device_set_thread_aware (device, 1);
 
        thrd_t threads[THREAD_COUNT];
 
        finishedThreadCount = 0;
        mtx_init (pmutex, mtx_plain);
-       for (uint32_t i=0; i<THREAD_COUNT; i++) {
+       for (uint32_t i=0; i<THREAD_COUNT; i++)
                thrd_create (&threads[i], drawRectsThread, NULL);
-       }
 
        const struct timespec ts = {1,0};
        while (finishedThreadCount < THREAD_COUNT)
@@ -61,9 +58,7 @@ void fixedSizeRects(){
        mtx_destroy (pmutex);
        pmutex = NULL;
 
-       vkvg_device_set_guards (device, NULL, NULL, NULL);
-       mtx_destroy (pgQMutex);
-       pgQMutex = NULL;
+       vkvg_device_set_thread_aware (device, 0);
 }
 
 int main(int argc, char *argv[]) {