mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-10-14 11:17:16 -04:00
Non-Adreno round 7: bridge command-buffer guard, Venus Zink trace, PowerVR mangoapp, Xclipse label
- vkbridge server: every command buffer a device hands out is tracked; Begin, End (stream replay) and QueueSubmit refuse one it never allocated or has freed (VK_ERROR_DEVICE_LOST, logged) instead of passing it to the driver, where Mali's vkBeginCommandBuffer crashed the app (SIGSEGV 0x10, Steam's Zink on an Edge 60 and a Tab S11). - vkbridge server: a fault inside the driver while serving a request cuts that client off (SIGSEGV/SIGBUS guard per request) and leaves its objects alone; the app and the other clients carry on. Other faults go to the previous handler. - vkbridge server: the pipeline cache directory is copied; the JNI string it pointed at was freed (garbage in the cache path). - Venus: DROIDDECK_MALI_COMPAT_TRACE=1 makes the Mali compatibility layer log what an application queries before vkCreateDevice; a failed glprobe adds a traced run and vulkaninfo --summary under the same environment. - PowerVR: mangoapp draws with llvmpipe (Zink could not make it a swapchain and it crashed at every start). - Setup: an Xclipse GPU reads "Experimental: RADV or the system Xclipse driver", not the PowerVR line.
This commit is contained in:
1 parent
ab54536886
commit
e40cd36151
10 files changed
+324
-3
No files matched your search
@@ -0,0 +1,194 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* The command buffers each device has handed out, so that a handle the driver never gave (or has
|
||||
* since freed, with its pool) is refused here instead of reaching the driver. Handles arrive from
|
||||
* clients as plain numbers; one the driver did not know took the whole app down inside Mali's
|
||||
* vkBeginCommandBuffer (SIGSEGV at 0x10, Steam's Zink on an Edge 60 and a Tab S11). A refused
|
||||
* command buffer fails its call with VK_ERROR_DEVICE_LOST, which the client reports, and is logged
|
||||
* once per handle.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include "vkb_server.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CBT_BUCKETS 1024
|
||||
|
||||
typedef struct cbt_entry {
|
||||
VkCommandBuffer cb;
|
||||
VkCommandPool pool;
|
||||
struct cbt_entry *next;
|
||||
} cbt_entry;
|
||||
|
||||
typedef struct vkb_cbtrack {
|
||||
pthread_mutex_t lock;
|
||||
cbt_entry *b[CBT_BUCKETS];
|
||||
VkCommandBuffer last_refused;
|
||||
PFN_vkAllocateCommandBuffers alloc;
|
||||
PFN_vkFreeCommandBuffers free_cbs;
|
||||
PFN_vkDestroyCommandPool destroy_pool;
|
||||
PFN_vkBeginCommandBuffer begin;
|
||||
PFN_vkQueueSubmit submit;
|
||||
PFN_vkQueueSubmit2 submit2;
|
||||
} vkb_cbtrack;
|
||||
|
||||
static unsigned bucket(VkCommandBuffer cb)
|
||||
{
|
||||
uint64_t k = (uint64_t)(uintptr_t)cb;
|
||||
k ^= k >> 31;
|
||||
k *= 0x9e3779b97f4a7c15ull;
|
||||
return (unsigned)(k >> 54) & (CBT_BUCKETS - 1);
|
||||
}
|
||||
|
||||
static vkb_cbtrack *cur(void)
|
||||
{
|
||||
vkb_srv_table *t = vkb_srv_current_table();
|
||||
return t ? t->cbtrack : NULL;
|
||||
}
|
||||
|
||||
static int known_locked(vkb_cbtrack *k, VkCommandBuffer cb)
|
||||
{
|
||||
for (cbt_entry *e = k->b[bucket(cb)]; e; e = e->next)
|
||||
if (e->cb == cb) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vkb_cbtrack_known(vkb_srv_table *t, VkCommandBuffer cb, const char *what)
|
||||
{
|
||||
vkb_cbtrack *k = t ? t->cbtrack : NULL;
|
||||
if (!k) return cb != VK_NULL_HANDLE;
|
||||
pthread_mutex_lock(&k->lock);
|
||||
int ok = cb && known_locked(k, cb);
|
||||
int first = !ok && k->last_refused != cb;
|
||||
if (!ok) k->last_refused = cb;
|
||||
pthread_mutex_unlock(&k->lock);
|
||||
if (first)
|
||||
VKB_ERR("device %u: %s on command buffer %p, which this device never allocated or has freed; refused (the client "
|
||||
"gets VK_ERROR_DEVICE_LOST)", t->id, what, (void *)cb);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static VKAPI_ATTR VkResult VKAPI_CALL cbt_AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *info,
|
||||
VkCommandBuffer *out)
|
||||
{
|
||||
vkb_cbtrack *k = cur();
|
||||
VkResult r = k->alloc(device, info, out);
|
||||
if (r != VK_SUCCESS || !info) return r;
|
||||
pthread_mutex_lock(&k->lock);
|
||||
for (uint32_t i = 0; i < info->commandBufferCount; i++) {
|
||||
if (!out[i] || known_locked(k, out[i])) continue;
|
||||
cbt_entry *e = malloc(sizeof(*e));
|
||||
if (!e) continue;
|
||||
e->cb = out[i];
|
||||
e->pool = info->commandPool;
|
||||
unsigned h = bucket(out[i]);
|
||||
e->next = k->b[h];
|
||||
k->b[h] = e;
|
||||
}
|
||||
pthread_mutex_unlock(&k->lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void forget_locked(vkb_cbtrack *k, VkCommandBuffer cb, VkCommandPool pool)
|
||||
{
|
||||
for (unsigned h = cb ? bucket(cb) : 0; h < CBT_BUCKETS; h = cb ? CBT_BUCKETS : h + 1) {
|
||||
cbt_entry **pp = &k->b[h];
|
||||
while (*pp) {
|
||||
cbt_entry *e = *pp;
|
||||
if ((cb && e->cb == cb) || (!cb && e->pool == pool)) {
|
||||
*pp = e->next;
|
||||
free(e);
|
||||
} else {
|
||||
pp = &e->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VKAPI_ATTR void VKAPI_CALL cbt_FreeCommandBuffers(VkDevice device, VkCommandPool pool, uint32_t n, const VkCommandBuffer *cbs)
|
||||
{
|
||||
vkb_cbtrack *k = cur();
|
||||
pthread_mutex_lock(&k->lock);
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
if (cbs[i]) forget_locked(k, cbs[i], pool);
|
||||
pthread_mutex_unlock(&k->lock);
|
||||
k->free_cbs(device, pool, n, cbs);
|
||||
}
|
||||
|
||||
static VKAPI_ATTR void VKAPI_CALL cbt_DestroyCommandPool(VkDevice device, VkCommandPool pool, const VkAllocationCallbacks *a)
|
||||
{
|
||||
vkb_cbtrack *k = cur();
|
||||
if (pool) {
|
||||
pthread_mutex_lock(&k->lock);
|
||||
forget_locked(k, VK_NULL_HANDLE, pool);
|
||||
pthread_mutex_unlock(&k->lock);
|
||||
}
|
||||
k->destroy_pool(device, pool, a);
|
||||
}
|
||||
|
||||
static VKAPI_ATTR VkResult VKAPI_CALL cbt_BeginCommandBuffer(VkCommandBuffer cb, const VkCommandBufferBeginInfo *info)
|
||||
{
|
||||
vkb_cbtrack *k = cur();
|
||||
if (!vkb_cbtrack_known(vkb_srv_current_table(), cb, "vkBeginCommandBuffer")) return VK_ERROR_DEVICE_LOST;
|
||||
return k->begin(cb, info);
|
||||
}
|
||||
|
||||
static VKAPI_ATTR VkResult VKAPI_CALL cbt_QueueSubmit(VkQueue queue, uint32_t n, const VkSubmitInfo *s, VkFence fence)
|
||||
{
|
||||
vkb_cbtrack *k = cur();
|
||||
vkb_srv_table *t = vkb_srv_current_table();
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
for (uint32_t j = 0; j < s[i].commandBufferCount; j++)
|
||||
if (!vkb_cbtrack_known(t, s[i].pCommandBuffers[j], "vkQueueSubmit")) return VK_ERROR_DEVICE_LOST;
|
||||
return k->submit(queue, n, s, fence);
|
||||
}
|
||||
|
||||
static VKAPI_ATTR VkResult VKAPI_CALL cbt_QueueSubmit2(VkQueue queue, uint32_t n, const VkSubmitInfo2 *s, VkFence fence)
|
||||
{
|
||||
vkb_cbtrack *k = cur();
|
||||
vkb_srv_table *t = vkb_srv_current_table();
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
for (uint32_t j = 0; j < s[i].commandBufferInfoCount; j++)
|
||||
if (!vkb_cbtrack_known(t, s[i].pCommandBufferInfos[j].commandBuffer, "vkQueueSubmit2")) return VK_ERROR_DEVICE_LOST;
|
||||
return k->submit2(queue, n, s, fence);
|
||||
}
|
||||
|
||||
void vkb_cbtrack_device_init(vkb_srv_table *t)
|
||||
{
|
||||
if (!t->dt.vkAllocateCommandBuffers || !t->dt.vkFreeCommandBuffers || !t->dt.vkDestroyCommandPool || !t->dt.vkBeginCommandBuffer ||
|
||||
!t->dt.vkQueueSubmit)
|
||||
return;
|
||||
vkb_cbtrack *k = calloc(1, sizeof(*k));
|
||||
if (!k) return;
|
||||
pthread_mutex_init(&k->lock, NULL);
|
||||
k->alloc = t->dt.vkAllocateCommandBuffers;
|
||||
k->free_cbs = t->dt.vkFreeCommandBuffers;
|
||||
k->destroy_pool = t->dt.vkDestroyCommandPool;
|
||||
k->begin = t->dt.vkBeginCommandBuffer;
|
||||
k->submit = t->dt.vkQueueSubmit;
|
||||
k->submit2 = t->dt.vkQueueSubmit2;
|
||||
t->cbtrack = k;
|
||||
t->dt.vkAllocateCommandBuffers = cbt_AllocateCommandBuffers;
|
||||
t->dt.vkFreeCommandBuffers = cbt_FreeCommandBuffers;
|
||||
t->dt.vkDestroyCommandPool = cbt_DestroyCommandPool;
|
||||
t->dt.vkBeginCommandBuffer = cbt_BeginCommandBuffer;
|
||||
t->dt.vkQueueSubmit = cbt_QueueSubmit;
|
||||
if (k->submit2) t->dt.vkQueueSubmit2 = cbt_QueueSubmit2;
|
||||
}
|
||||
|
||||
void vkb_cbtrack_device_destroy(vkb_srv_table *t)
|
||||
{
|
||||
vkb_cbtrack *k = t->cbtrack;
|
||||
if (!k) return;
|
||||
for (unsigned h = 0; h < CBT_BUCKETS; h++) {
|
||||
while (k->b[h]) {
|
||||
cbt_entry *e = k->b[h];
|
||||
k->b[h] = e->next;
|
||||
free(e);
|
||||
}
|
||||
}
|
||||
pthread_mutex_destroy(&k->lock);
|
||||
free(k);
|
||||
t->cbtrack = NULL;
|
||||
}
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "vkb_server.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -102,8 +104,14 @@ void vkb_proc_cleanup(vkb_srv_proc *p)
|
||||
if (mine) tables[i] = NULL;
|
||||
pthread_mutex_unlock(&tables_lock);
|
||||
if (!mine) continue;
|
||||
if (t->is_device) {
|
||||
if (p->driver_crashed) {
|
||||
/* The driver faulted for this process: calling into it for its objects again could
|
||||
* fault again, outside any guard. They are left to the driver. */
|
||||
VKB_WARN("process %d: %s %u left as it is (the driver crashed serving it)", p->pid, t->is_device ? "device" : "instance", t->id);
|
||||
if (t->is_device) vkb_cbtrack_device_destroy(t);
|
||||
} else if (t->is_device) {
|
||||
VKB_INFO("process %d exited without destroying device %u; cleaning up", p->pid, t->id);
|
||||
vkb_cbtrack_device_destroy(t);
|
||||
if (t->real.vkDeviceWaitIdle) t->real.vkDeviceWaitIdle(t->device);
|
||||
vkb_spvfix_device_destroy(t);
|
||||
vkb_dsmap_device_destroy(t);
|
||||
@@ -218,6 +226,12 @@ void vkb_sv_vkEndCommandBuffer(vkb_srv_call *c)
|
||||
vkb_srv_bad_message(c);
|
||||
return;
|
||||
}
|
||||
/* A command buffer the device never handed out (or has freed) is not replayed: the driver would
|
||||
* be given a pointer it does not own (server_cbtrack.c). */
|
||||
if (!vkb_cbtrack_known(c->table, cb, "vkEndCommandBuffer")) {
|
||||
vkb_enc_u32(&c->r, (uint32_t)VK_ERROR_DEVICE_LOST);
|
||||
return;
|
||||
}
|
||||
VkResult begin_r = VK_SUCCESS;
|
||||
size_t pos = 0;
|
||||
vkb_enc scratch;
|
||||
@@ -425,8 +439,55 @@ static int srv_recv(vkb_srv_conn *conn, vkb_msg_hdr *h, uint8_t **payload, int *
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ driver fault guard */
|
||||
|
||||
/*
|
||||
* A fault inside the GPU driver while serving one client used to take the whole app down (the
|
||||
* server runs in its process). Each request runs under a guard: SIGSEGV/SIGBUS on that thread
|
||||
* jumps back here, the client is cut off (it sees the bridge gone and fails or falls back), and
|
||||
* the app and the other clients go on. Any other fault goes to the handler that was there before.
|
||||
*/
|
||||
static __thread sigjmp_buf *t_guard;
|
||||
static __thread volatile sig_atomic_t t_fault;
|
||||
static struct sigaction prev_segv, prev_bus;
|
||||
static pthread_once_t guard_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void guard_handler(int sig, siginfo_t *si, void *uc)
|
||||
{
|
||||
sigjmp_buf *g = t_guard;
|
||||
if (g) {
|
||||
t_guard = NULL;
|
||||
t_fault = sig;
|
||||
siglongjmp(*g, 1);
|
||||
}
|
||||
struct sigaction *p = sig == SIGBUS ? &prev_bus : &prev_segv;
|
||||
if ((p->sa_flags & SA_SIGINFO) && p->sa_sigaction) {
|
||||
p->sa_sigaction(sig, si, uc);
|
||||
return;
|
||||
}
|
||||
if (!(p->sa_flags & SA_SIGINFO) && p->sa_handler == SIG_IGN) return;
|
||||
if (!(p->sa_flags & SA_SIGINFO) && p->sa_handler && p->sa_handler != SIG_DFL) {
|
||||
p->sa_handler(sig);
|
||||
return;
|
||||
}
|
||||
signal(sig, SIG_DFL);
|
||||
raise(sig);
|
||||
}
|
||||
|
||||
static void guard_install(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_sigaction = guard_handler;
|
||||
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaction(SIGSEGV, &sa, &prev_segv);
|
||||
sigaction(SIGBUS, &sa, &prev_bus);
|
||||
}
|
||||
|
||||
static void *conn_main(void *arg)
|
||||
{
|
||||
pthread_once(&guard_once, guard_install);
|
||||
vkb_srv_conn *conn = arg;
|
||||
vkb_srv_call c;
|
||||
vkb_enc_init(&c.r);
|
||||
@@ -467,7 +528,19 @@ static void *conn_main(void *arg)
|
||||
vkb_srv_set_current_table(c.table);
|
||||
if (vkb_verbose) VKB_DBG("-> %s", vkb_cmd_names[h.cmd]);
|
||||
vkb_srv_current_cmd = vkb_cmd_names[h.cmd];
|
||||
sigjmp_buf jb;
|
||||
if (sigsetjmp(jb, 1)) {
|
||||
VKB_ERR("the GPU driver crashed (signal %d) in %s for process %d; that client is cut off, the app and "
|
||||
"the other clients carry on", (int)t_fault, vkb_cmd_names[h.cmd], conn->proc ? conn->proc->pid : -1);
|
||||
if (conn->proc) conn->proc->driver_crashed = 1;
|
||||
vkb_srv_current_cmd = NULL;
|
||||
vkb_srv_set_current_table(NULL);
|
||||
order_done(conn->proc, h.seq);
|
||||
break;
|
||||
}
|
||||
t_guard = &jb;
|
||||
vkb_srv_handlers[h.cmd](&c);
|
||||
t_guard = NULL;
|
||||
vkb_srv_current_cmd = NULL;
|
||||
vkb_srv_set_current_table(NULL);
|
||||
if (st_period) stats_add(h.cmd, mono_ns() - t1, t1 - t0);
|
||||
|
||||
@@ -319,6 +319,7 @@ void vkb_sv_vkCreateDevice(vkb_srv_call *c)
|
||||
vkb_pcache_device_init(t);
|
||||
vkb_dsmap_device_init(t);
|
||||
vkb_spvfix_device_init(t);
|
||||
vkb_cbtrack_device_init(t); /* last: it wraps what the others installed */
|
||||
VKB_INFO("device %u created on %s (%u extensions, memory sharing %s)", id, k ? k->name : "?", n,
|
||||
vkb_mem_strategy_name(strategy));
|
||||
for (uint32_t i = 0; i < n; i++) VKB_DBG(" device extension %s", exts[i]);
|
||||
@@ -341,6 +342,7 @@ void vkb_sv_vkDestroyDevice(vkb_srv_call *c)
|
||||
return;
|
||||
}
|
||||
vkb_table_unregister(t);
|
||||
vkb_cbtrack_device_destroy(t);
|
||||
vkb_spvfix_device_destroy(t);
|
||||
vkb_dsmap_device_destroy(t);
|
||||
vkb_pcache_device_destroy(t);
|
||||
|
||||
@@ -46,7 +46,11 @@ void vkb_pcache_set_dir(const char *dir)
|
||||
{
|
||||
if (!dir || !*dir) return;
|
||||
mkdir(dir, 0700);
|
||||
pc_dir = dir;
|
||||
/* A copy: the JNI entry frees its string once the server is up, and the pointer kept before
|
||||
* printed "pipeline cache \xef\xbf\xbdRYp/13b5-..." and wrote the cache under that name. */
|
||||
char *copy = strdup(dir);
|
||||
if (!copy) return;
|
||||
pc_dir = copy;
|
||||
VKB_INFO("pipeline cache directory %s", dir);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ typedef struct vkb_srv_proc {
|
||||
uint64_t watermark; /* every async seq <= this has run */
|
||||
uint8_t done[VKB_SEQ_RING]; /* seqs above the watermark that have run */
|
||||
int conn_closed; /* a connection ended (a seq may never arrive) */
|
||||
int driver_crashed; /* the driver faulted serving it: its objects are left alone */
|
||||
} vkb_srv_proc;
|
||||
|
||||
typedef struct vkb_srv_conn {
|
||||
@@ -88,6 +89,7 @@ typedef struct vkb_srv_table {
|
||||
struct vkb_pcache *pcache; /* server_pcache.c */
|
||||
struct vkb_dsmap *dsmap; /* server_dsmap.c */
|
||||
struct vkb_spvfix *spvfix; /* server_spvfix.c */
|
||||
struct vkb_cbtrack *cbtrack; /* server_cbtrack.c */
|
||||
} vkb_srv_table;
|
||||
|
||||
/* server_main.c */
|
||||
@@ -97,6 +99,11 @@ extern int vkb_verbose;
|
||||
|
||||
void vkb_log_summary(void);
|
||||
|
||||
/* server_cbtrack.c: command buffers the device handed out; others are refused, not passed on. */
|
||||
void vkb_cbtrack_device_init(vkb_srv_table *t);
|
||||
void vkb_cbtrack_device_destroy(vkb_srv_table *t);
|
||||
int vkb_cbtrack_known(vkb_srv_table *t, VkCommandBuffer cb, const char *what);
|
||||
|
||||
/* server_spvfix.c */
|
||||
void vkb_spvfix_device_init(vkb_srv_table *t);
|
||||
void vkb_spvfix_device_destroy(vkb_srv_table *t);
|
||||
|
||||
@@ -86,7 +86,7 @@ data class GpuInfo(
|
||||
fun supportText(context: Context): String = context.getString(when (support) {
|
||||
Support.TESTED -> R.string.gpuinfo_supported
|
||||
Support.UNTESTED -> when (family) {
|
||||
Family.POWERVR -> R.string.gpuinfo_powervr
|
||||
Family.POWERVR -> if (name.contains("Xclipse", ignoreCase = true)) R.string.gpuinfo_xclipse else R.string.gpuinfo_powervr
|
||||
Family.A7XX_LOW -> R.string.gpuinfo_experimental
|
||||
Family.MALI_JM, Family.MALI_G610_G710, Family.MALI_G615, Family.MALI_G720, Family.MALI_LATEST, Family.MALI_OTHER -> R.string.gpuinfo_experimental
|
||||
else -> R.string.gpuinfo_below_tested
|
||||
|
||||
@@ -1908,6 +1908,7 @@
|
||||
<!-- GPU support line -->
|
||||
<string name="gpuinfo_not_adreno">Not an Adreno GPU</string>
|
||||
<string name="gpuinfo_powervr">System PowerVR driver: compatibility varies by device</string>
|
||||
<string name="gpuinfo_xclipse">Experimental: RADV or the system Xclipse driver</string>
|
||||
<string name="gpu_system_powervr">System PowerVR</string>
|
||||
<string name="gpu_auto_system_hint">Uses the built-in drivers for this GPU</string>
|
||||
<string name="drivers_powervr_builtin">The system PowerVR driver is selected for the runtime and display.</string>
|
||||
|
||||
@@ -1190,6 +1190,10 @@ BUSCONF
|
||||
# The loader's view first, then the variants that change what Zink asks of the device;
|
||||
# the first that starts is what the client gets.
|
||||
VK_LOADER_DEBUG=error,warn timeout 20 /usr/local/bin/droiddeck-glprobe 2>&1 | grep -v drirc | head -40 | sed 's/^/== glprobe (loader): /'
|
||||
# What Zink asked the device before it gave up (the Mali compatibility layer's trace), Mesa's
|
||||
# own debug output, and the device as Vulkan programs see it under the same environment.
|
||||
DROIDDECK_MALI_COMPAT_TRACE=1 MESA_DEBUG=1 LIBGL_DEBUG=verbose timeout 20 /usr/local/bin/droiddeck-glprobe 2>&1 | grep -v drirc | head -80 | sed 's/^/== glprobe (trace): /'
|
||||
command -v vulkaninfo >/dev/null 2>&1 && DROIDDECK_MALI_COMPAT_TRACE=1 timeout 20 vulkaninfo --summary 2>&1 | head -40 | sed 's/^/== glprobe (vulkaninfo): /'
|
||||
bl_gl_ok=
|
||||
for bl_variant in "ZINK_DEBUG=" "ZINK_DEBUG= ZINK_DESCRIPTORS=auto" "ZINK_DEBUG= LIBGL_KOPPER_DISABLE=true" "ZINK_DEBUG= DROIDDECK_MALI_COMPAT=0"; do
|
||||
if env $bl_variant timeout 20 /usr/local/bin/droiddeck-glprobe 2>&1 | grep -v drirc | head -20 | sed "s/^/== glprobe ($bl_variant): /"; [ "${PIPESTATUS[0]}" = 0 ]; then
|
||||
|
||||
@@ -18,4 +18,11 @@ if [ "$(wc -l < "$starts")" -gt 5 ]; then
|
||||
echo "mangoapp: started $(wc -l < "$starts") times in 60 s; the performance overlay stays off for this session" >&2
|
||||
exec sleep infinity
|
||||
fi
|
||||
# The system PowerVR route (BL_POWERVR_RENDER_NODE): Zink could not make mangoapp a swapchain there
|
||||
# ("zink: could not create swapchain", then GLXBadCurrentWindow) and it crashed at every start. The
|
||||
# overlay is a few text lines: llvmpipe draws it.
|
||||
if [ -n "${BL_POWERVR_RENDER_NODE:-}" ]; then
|
||||
export GALLIUM_DRIVER=llvmpipe LIBGL_ALWAYS_SOFTWARE=1
|
||||
unset MESA_LOADER_DRIVER_OVERRIDE LIBGL_KOPPER_DRI2
|
||||
fi
|
||||
LD_LIBRARY_PATH=/usr/local/lib/mangoapp${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} exec /usr/local/lib/mangoapp/mangoapp "$@"
|
||||
@@ -151,6 +151,18 @@ static bool wanted(void)
|
||||
return getenv("WINEPREFIX") != NULL;
|
||||
}
|
||||
|
||||
/* DROIDDECK_MALI_COMPAT_TRACE=1: what an application asks before it creates a device (Zink on a
|
||||
* Mali-G615 through Venus gave up before vkCreateDevice without a word). */
|
||||
static bool tracing(void)
|
||||
{
|
||||
static int on = -1;
|
||||
if (on < 0) {
|
||||
const char *v = getenv("DROIDDECK_MALI_COMPAT_TRACE");
|
||||
on = v && *v && strcmp(v, "0") != 0;
|
||||
}
|
||||
return on;
|
||||
}
|
||||
|
||||
static bool has_extension(struct instance *inst, VkPhysicalDevice physical_device, const char *name)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
@@ -337,6 +349,13 @@ static VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceFeatures2(VkPhysicalDevice ph
|
||||
inst->GetPhysicalDeviceFeatures2(physical_device, features);
|
||||
relink(dropped, dropped_count);
|
||||
report_features(&features->features, gaps);
|
||||
if (tracing()) {
|
||||
char chain[512] = "";
|
||||
size_t used = 0;
|
||||
for (VkBaseOutStructure *s = features->pNext; s && used + 16 < sizeof(chain); s = s->pNext)
|
||||
used += (size_t)snprintf(chain + used, sizeof(chain) - used, " %d", (int)s->sType);
|
||||
layer_log("trace: vkGetPhysicalDeviceFeatures2 (gaps 0x%x, %u structures held back), chain:%s", gaps, dropped_count, chain);
|
||||
}
|
||||
for (VkBaseOutStructure *s = features->pNext; s; s = s->pNext) {
|
||||
if (s->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT && (gaps & GAP_ROBUSTNESS2)) {
|
||||
((VkPhysicalDeviceRobustness2FeaturesEXT *)s)->robustBufferAccess2 = VK_TRUE;
|
||||
@@ -362,6 +381,10 @@ static VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceProperties2(VkPhysicalDevice
|
||||
struct instance *inst = instance_from_handle(physical_device);
|
||||
inst->GetPhysicalDeviceProperties2(physical_device, properties);
|
||||
report_limits(&properties->properties.limits, physical_device_gaps(inst, physical_device));
|
||||
if (tracing())
|
||||
layer_log("trace: vkGetPhysicalDeviceProperties2: %s, Vulkan %u.%u.%u, type %d", properties->properties.deviceName,
|
||||
VK_API_VERSION_MAJOR(properties->properties.apiVersion), VK_API_VERSION_MINOR(properties->properties.apiVersion),
|
||||
VK_API_VERSION_PATCH(properties->properties.apiVersion), (int)properties->properties.deviceType);
|
||||
}
|
||||
|
||||
/* The extensions the layer stands in for, added to the driver's list. */
|
||||
@@ -391,6 +414,8 @@ static VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysi
|
||||
inst->EnumerateDeviceExtensionProperties(physical_device, NULL, &own, all);
|
||||
memcpy(all + own, extra, extra_count * sizeof(*extra));
|
||||
uint32_t total = own + extra_count;
|
||||
if (tracing())
|
||||
layer_log("trace: vkEnumerateDeviceExtensionProperties: %u from the driver, %u added by the layer", own, extra_count);
|
||||
uint32_t n = *count < total ? *count : total;
|
||||
memcpy(properties, all, n * sizeof(*all));
|
||||
free(all);
|
||||
@@ -411,6 +436,10 @@ static VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo
|
||||
|
||||
PFN_vkCreateInstance create = (PFN_vkCreateInstance)gipa(VK_NULL_HANDLE, "vkCreateInstance");
|
||||
VkResult result = create(info, allocator, instance);
|
||||
if (tracing())
|
||||
layer_log("trace: vkCreateInstance for %s (API %u.%u): %d, layer %s", info->pApplicationInfo && info->pApplicationInfo->pApplicationName ?
|
||||
info->pApplicationInfo->pApplicationName : "?", info->pApplicationInfo ? VK_API_VERSION_MAJOR(info->pApplicationInfo->apiVersion) : 0,
|
||||
info->pApplicationInfo ? VK_API_VERSION_MINOR(info->pApplicationInfo->apiVersion) : 0, (int)result, wanted() ? "active" : "idle");
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
|
||||
Reference in new issue
Block a user