vkd3d/include/private/vkd3d_common.h

335 lines
8.3 KiB
C
Raw Normal View History

2016-09-21 03:57:24 -07:00
/*
* Copyright 2016 Józef Kucia for CodeWeavers
*
2017-06-16 12:05:54 -07:00
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
2016-09-21 03:57:24 -07:00
*
2017-06-16 12:05:54 -07:00
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
2016-09-21 03:57:24 -07:00
*
2017-06-16 12:05:54 -07:00
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
2016-09-21 03:57:24 -07:00
*/
#ifndef __VKD3D_COMMON_H
#define __VKD3D_COMMON_H
#include "config.h"
#include "vkd3d_windows.h"
#include "vkd3d_types.h"
2016-09-21 03:57:24 -07:00
#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#ifdef _MSC_VER
#include <intrin.h>
#endif
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
#endif
2016-09-21 03:57:24 -07:00
#define DIV_ROUND_UP(a, b) ((a) % (b) == 0 ? (a) / (b) : (a) / (b) + 1)
#define STATIC_ASSERT(e) extern void __VKD3D_STATIC_ASSERT__(int [(e) ? 1 : -1])
#define MEMBER_SIZE(t, m) sizeof(((t *)0)->m)
#define VKD3D_MAKE_TAG(ch0, ch1, ch2, ch3) \
((uint32_t)(ch0) | ((uint32_t)(ch1) << 8) \
| ((uint32_t)(ch2) << 16) | ((uint32_t)(ch3) << 24))
2017-06-16 13:38:21 -07:00
static inline size_t align(size_t addr, size_t alignment)
{
return (addr + (alignment - 1)) & ~(alignment - 1);
}
#ifdef __GNUC__
# define VKD3D_NORETURN __attribute__((noreturn))
# define VKD3D_PRINTF_FUNC(fmt, args) __attribute__((format(printf, fmt, args)))
# define VKD3D_UNUSED __attribute__((unused))
# define VKD3D_UNREACHABLE __builtin_unreachable()
#else
# define VKD3D_NORETURN
# define VKD3D_PRINTF_FUNC(fmt, args)
# define VKD3D_UNUSED
# define VKD3D_UNREACHABLE (void)0
#endif /* __GNUC__ */
VKD3D_NORETURN static inline void vkd3d_unreachable_(const char *filename, unsigned int line)
{
fprintf(stderr, "%s:%u: Aborting, reached unreachable code.\n", filename, line);
abort();
}
#ifdef NDEBUG
#define vkd3d_unreachable() VKD3D_UNREACHABLE
#else
#define vkd3d_unreachable() vkd3d_unreachable_(__FILE__, __LINE__)
#endif
static inline unsigned int vkd3d_popcount(unsigned int v)
{
#ifdef _MSC_VER
return __popcnt(v);
#elif defined(HAVE_BUILTIN_POPCOUNT)
return __builtin_popcount(v);
#else
v -= (v >> 1) & 0x55555555;
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
return (((v + (v >> 4)) & 0x0f0f0f0f) * 0x01010101) >> 24;
#endif
}
static inline bool vkd3d_bitmask_is_contiguous(unsigned int mask)
{
unsigned int i, j;
for (i = 0, j = 0; i < sizeof(mask) * CHAR_BIT; ++i)
{
if (mask & (1u << i))
++j;
else if (j)
break;
}
return vkd3d_popcount(mask) == j;
}
/* Undefined for x == 0. */
static inline unsigned int vkd3d_log2i(unsigned int x)
{
#ifdef _WIN32
/* _BitScanReverse returns the index of the highest set bit,
* unlike clz which is 31 - index. */
ULONG result;
_BitScanReverse(&result, x);
return (unsigned int)result;
#elif defined(HAVE_BUILTIN_CLZ)
return __builtin_clz(x) ^ 0x1f;
#else
static const unsigned int l[] =
{
~0u, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
};
unsigned int i;
return (i = x >> 16) ? (x = i >> 8) ? l[x] + 24
: l[i] + 16 : (i = x >> 8) ? l[i] + 8 : l[x];
#endif
}
static inline void *vkd3d_memmem( const void *haystack, size_t haystack_len, const void *needle, size_t needle_len)
{
const char *str = haystack;
while (haystack_len >= needle_len)
{
if (!memcmp(str, needle, needle_len))
return (char *)str;
++str;
--haystack_len;
}
return NULL;
}
static inline bool vkd3d_bound_range(size_t start, size_t count, size_t limit)
{
#ifdef HAVE_BUILTIN_ADD_OVERFLOW
size_t sum;
return !__builtin_add_overflow(start, count, &sum) && sum <= limit;
#else
return start <= limit && count <= limit - start;
#endif
}
static inline uint16_t vkd3d_make_u16(uint8_t low, uint8_t high)
{
return low | ((uint16_t)high << 8);
}
static inline uint32_t vkd3d_make_u32(uint16_t low, uint16_t high)
{
return low | ((uint32_t)high << 16);
}
static inline int vkd3d_u32_compare(uint32_t x, uint32_t y)
{
return (x > y) - (x < y);
}
static inline int ascii_isupper(int c)
{
return 'A' <= c && c <= 'Z';
}
static inline int ascii_tolower(int c)
{
return ascii_isupper(c) ? c - 'A' + 'a' : c;
}
static inline int ascii_strncasecmp(const char *a, const char *b, size_t n)
{
int c_a, c_b;
while (n--)
{
c_a = ascii_tolower(*a++);
c_b = ascii_tolower(*b++);
if (c_a != c_b || !c_a)
return c_a - c_b;
}
return 0;
}
static inline int ascii_strcasecmp(const char *a, const char *b)
{
int c_a, c_b;
do
{
c_a = ascii_tolower(*a++);
c_b = ascii_tolower(*b++);
} while (c_a == c_b && c_a != '\0');
return c_a - c_b;
}
#ifndef _WIN32
# if HAVE_SYNC_ADD_AND_FETCH
static inline LONG InterlockedIncrement(LONG volatile *x)
2016-09-21 03:57:24 -07:00
{
return __sync_add_and_fetch(x, 1);
}
vkd3d: Back descriptor heaps with Vulkan descriptor sets if descriptor indexing is available. The existing implementation using virtual descriptor heaps, where Vk descriptor sets are created for the bindings in the root descriptor tables, is inefficient when multiple command lists are used with large descriptor heaps. It also cannot support updating a descriptor set after it is bound. This patch creates Vk sets for each D3D12 heap. Because D3D12 heaps can contain CBV, SRV and UAV descriptors in the same heap, multiple Vk sets are needed for each heap, however the total number of populated descriptors is never more than (heap size + UAV counter count). A new 'virtual_heaps' config option is introduced to make the old implementation available when needed. It's not always possible to determine if this is necessary when the device is created. Up to nine Vk descriptor sets may be used. It's theoretically possible to reduce this to eight by placing immutable samplers in the push descriptor set layout, but contradictions in earlier versions of the Vulkan spec made driver support inconsistent. The documentation was corrected in version 1.2.203. This patch also adds support for UAV counter descriptor arrays. It's not practical to add this in a separate patch due to complications with combining the old UAV counter implementation with the new descriptor heap implementation. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47713 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47154 Signed-off-by: Conor McCarthy <cmccarthy@codeweavers.com> Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
2022-02-21 07:18:59 -08:00
static inline LONG64 InterlockedIncrement64(LONG64 volatile *x)
{
return __sync_add_and_fetch(x, 1);
}
static inline LONG InterlockedAdd(LONG volatile *x, LONG val)
{
return __sync_add_and_fetch(x, val);
}
# else
# error "InterlockedIncrement() not implemented for this platform"
# endif /* HAVE_SYNC_ADD_AND_FETCH */
2016-09-21 03:57:24 -07:00
# if HAVE_SYNC_SUB_AND_FETCH
static inline LONG InterlockedDecrement(LONG volatile *x)
2016-09-21 03:57:24 -07:00
{
return __sync_sub_and_fetch(x, 1);
}
# else
# error "InterlockedDecrement() not implemented for this platform"
# endif
#endif /* _WIN32 */
2016-09-21 03:57:24 -07:00
static inline void vkd3d_parse_version(const char *version, int *major, int *minor)
{
*major = atoi(version);
while (isdigit(*version))
++version;
if (*version == '.')
++version;
*minor = atoi(version);
}
HRESULT hresult_from_vkd3d_result(int vkd3d_result);
#ifdef _WIN32
static inline void *vkd3d_dlopen(const char *name)
{
return LoadLibraryA(name);
}
static inline void *vkd3d_dlsym(void *handle, const char *symbol)
{
return GetProcAddress(handle, symbol);
}
static inline int vkd3d_dlclose(void *handle)
{
return FreeLibrary(handle);
}
static inline const char *vkd3d_dlerror(void)
{
unsigned int error = GetLastError();
static char message[256];
if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, message, sizeof(message), NULL))
return message;
sprintf(message, "Unknown error %u.\n", error);
return message;
}
#elif defined(HAVE_DLFCN_H)
#include <dlfcn.h>
static inline void *vkd3d_dlopen(const char *name)
{
return dlopen(name, RTLD_NOW);
}
static inline void *vkd3d_dlsym(void *handle, const char *symbol)
{
return dlsym(handle, symbol);
}
static inline int vkd3d_dlclose(void *handle)
{
return dlclose(handle);
}
static inline const char *vkd3d_dlerror(void)
{
return dlerror();
}
#else
static inline void *vkd3d_dlopen(const char *name)
{
return NULL;
}
static inline void *vkd3d_dlsym(void *handle, const char *symbol)
{
return NULL;
}
static inline int vkd3d_dlclose(void *handle)
{
return 0;
}
static inline const char *vkd3d_dlerror(void)
{
return "Not implemented for this platform.\n";
}
#endif
2016-09-21 03:57:24 -07:00
#endif /* __VKD3D_COMMON_H */