mirror of
https://github.com/nestriness/nestri.git
synced 2026-09-19 09:15:19 +03:00
feat: nescapture capture improvements and drive mounts (#337)
Co-authored-by: DatCaptainHorse <DatCaptainHorse@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
ebc0242b49
commit
6811c93d51
@@ -73,12 +73,23 @@ ENV ARTIFACTS=/artifacts
|
||||
FROM builder AS mesa-build
|
||||
|
||||
ARG MESA_GIT=https://gitlab.freedesktop.org/mesa/mesa.git
|
||||
ARG MESA_COMMIT=b316485dd75ca6ab6c16c113480fb94c57d86c95
|
||||
ARG MESA_COMMIT=8ace865d958b0f17254afc427db21b0ad1747b4b
|
||||
ARG JOBS=
|
||||
|
||||
# Our patches to the amdgpu native-context path, applied on top of the pinned
|
||||
# commit. They are not cosmetic: upstream's winsys re-queries device-static
|
||||
# facts on a path that costs a synchronous round trip to the host under
|
||||
# virtio, and it was most of a frame's time. See each patch's own message.
|
||||
#
|
||||
# `git apply` and not `git am`: no committer identity is needed, and a patch
|
||||
# that no longer applies stops the build here rather than producing an image
|
||||
# that is quietly unpatched and slow.
|
||||
COPY build/patches/mesa /build/patches/mesa
|
||||
|
||||
RUN test -n "$JOBS" || JOBS=$(nproc) && \
|
||||
git clone --depth=1 --revision="${MESA_COMMIT}" "${MESA_GIT}" /build/mesa-src && \
|
||||
cd /build/mesa-src && \
|
||||
git apply --whitespace=nowarn /build/patches/mesa/*.patch && \
|
||||
meson setup builddir \
|
||||
-Dprefix=/usr \
|
||||
-Dbuildtype=release \
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
From 5f615ac88a6f2b962a3e0d68c995f1ab3ec12d20 Mon Sep 17 00:00:00 2001
|
||||
From: DatCaptainHorse <DatCaptainHorse@users.noreply.github.com>
|
||||
Date: Thu, 17 Sep 2026 19:33:08 +0300
|
||||
Subject: [PATCH] ac/linux_drm: cache the device's static VRAM/GTT sizes
|
||||
|
||||
AMDGPU_INFO_VRAM_GTT returns total VRAM, CPU-visible VRAM and GTT size.
|
||||
All three are fixed properties of the device and cannot change while it is
|
||||
open, but ac_drm_query_heap_info() asked for them on every call.
|
||||
|
||||
That is free on a local ioctl. It is not free on an amdgpu native context,
|
||||
where every query is a synchronous round trip to the host: measured with one
|
||||
game running under virtio, this single query was 47% of all guest-to-host
|
||||
traffic, asked roughly 15,000 times a second for an answer that never
|
||||
changed.
|
||||
|
||||
Fetch it once during ac_drm_device_initialize(), before the device is
|
||||
visible to any other thread, so reading it needs no lock. A failure there is
|
||||
not fatal -- vram_gtt_valid stays false and the old per-call path is used.
|
||||
|
||||
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||||
---
|
||||
src/amd/common/ac_linux_drm.c | 40 +++++++++++++++++++++++++++++------
|
||||
1 file changed, 34 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/amd/common/ac_linux_drm.c b/src/amd/common/ac_linux_drm.c
|
||||
index 21fb2c9e4e3..63b27058ec1 100644
|
||||
--- a/src/amd/common/ac_linux_drm.c
|
||||
+++ b/src/amd/common/ac_linux_drm.c
|
||||
@@ -28,6 +28,23 @@ struct ac_drm_device {
|
||||
struct util_sync_provider *p;
|
||||
int fd;
|
||||
bool is_virtio;
|
||||
+
|
||||
+ /* AMDGPU_INFO_VRAM_GTT, fetched once.
|
||||
+ *
|
||||
+ * The three sizes it returns -- total VRAM, CPU-visible VRAM, GTT -- are
|
||||
+ * fixed properties of the device and cannot change while it is open, but
|
||||
+ * ac_drm_query_heap_info() re-queried them on every call. That is free on a
|
||||
+ * local ioctl and is not free over virtio, where every query is a
|
||||
+ * synchronous round trip to the host: measured on an amdgpu native context,
|
||||
+ * this single query was 47% of all guest-to-host traffic, asked ~15,000
|
||||
+ * times a second for an answer that never changed.
|
||||
+ *
|
||||
+ * Filled during initialize(), before the device is visible to any other
|
||||
+ * thread, so reading it needs no lock. If the query fails there,
|
||||
+ * vram_gtt_valid stays false and the old per-call path is used.
|
||||
+ */
|
||||
+ struct drm_amdgpu_info_vram_gtt vram_gtt;
|
||||
+ bool vram_gtt_valid;
|
||||
};
|
||||
|
||||
int ac_drm_device_initialize(int fd, bool is_virtio,
|
||||
@@ -64,10 +81,17 @@ int ac_drm_device_initialize(int fd, bool is_virtio,
|
||||
}
|
||||
}
|
||||
|
||||
- if (r == 0)
|
||||
+ if (r == 0) {
|
||||
(*dev)->is_virtio = is_virtio;
|
||||
- else
|
||||
+ /* Device-static, so it is asked once here rather than on every heap
|
||||
+ * query. A failure is not fatal: the caller falls back to querying it.
|
||||
+ */
|
||||
+ (*dev)->vram_gtt_valid =
|
||||
+ ac_drm_query_info(*dev, AMDGPU_INFO_VRAM_GTT, sizeof((*dev)->vram_gtt),
|
||||
+ &(*dev)->vram_gtt) == 0;
|
||||
+ } else {
|
||||
free(*dev);
|
||||
+ }
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -757,12 +781,16 @@ int ac_drm_query_gpu_info(ac_drm_device *dev, struct amdgpu_gpu_info *info)
|
||||
int ac_drm_query_heap_info(ac_drm_device *dev, uint32_t heap, uint32_t flags,
|
||||
struct amdgpu_heap_info *info)
|
||||
{
|
||||
- struct drm_amdgpu_info_vram_gtt vram_gtt_info = {};
|
||||
+ struct drm_amdgpu_info_vram_gtt vram_gtt_info;
|
||||
int r;
|
||||
|
||||
- r = ac_drm_query_info(dev, AMDGPU_INFO_VRAM_GTT, sizeof(vram_gtt_info), &vram_gtt_info);
|
||||
- if (r)
|
||||
- return r;
|
||||
+ if (dev->vram_gtt_valid) {
|
||||
+ vram_gtt_info = dev->vram_gtt;
|
||||
+ } else {
|
||||
+ r = ac_drm_query_info(dev, AMDGPU_INFO_VRAM_GTT, sizeof(vram_gtt_info), &vram_gtt_info);
|
||||
+ if (r)
|
||||
+ return r;
|
||||
+ }
|
||||
|
||||
/* Get heap information */
|
||||
switch (heap) {
|
||||
@@ -0,0 +1,80 @@
|
||||
From ef1f613123fadfd8ef778f77090ba696cb18797e Mon Sep 17 00:00:00 2001
|
||||
From: DatCaptainHorse <DatCaptainHorse@users.noreply.github.com>
|
||||
Date: Thu, 17 Sep 2026 19:33:08 +0300
|
||||
Subject: [PATCH] radv/amdgpu: query all three heaps with one
|
||||
AMDGPU_INFO_MEMORY
|
||||
|
||||
radv_amdgpu_winsys_query_heap_info() wants the usage of VRAM, visible VRAM
|
||||
and GTT. It called ac_drm_query_heap_info() three times to get them, which
|
||||
is six ioctls: each of those calls also re-queries the device's static
|
||||
VRAM_GTT sizes, and then only .heap_usage is used out of the result.
|
||||
|
||||
AMDGPU_INFO_MEMORY returns all three heaps together, each with its usage,
|
||||
which is exactly what this function assembles. One query replaces six.
|
||||
|
||||
Six ioctls instead of one is invisible on a local device and is not
|
||||
invisible over virtio, where each is a synchronous round trip to the host.
|
||||
Measured on an amdgpu native context with one game running, this function
|
||||
alone accounted for 94% of all guest-to-host traffic -- around 300 round
|
||||
trips per frame, against 20 for the actual command submissions -- and with
|
||||
it most of the frame time.
|
||||
|
||||
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||||
---
|
||||
.../vulkan/winsys/amdgpu/radv_amdgpu_winsys.c | 36 +++++++++++--------
|
||||
1 file changed, 21 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_winsys.c b/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_winsys.c
|
||||
index 6aaf8a475c3..a7587f86d85 100644
|
||||
--- a/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_winsys.c
|
||||
+++ b/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_winsys.c
|
||||
@@ -378,7 +378,7 @@ fail:
|
||||
int
|
||||
radv_amdgpu_winsys_query_heap_info(ac_drm_device *dev, struct radeon_winsys_heap_info *heap_info)
|
||||
{
|
||||
- struct amdgpu_heap_info heap_vram = {0}, heap_vram_vis = {0}, heap_gtt = {0};
|
||||
+ struct drm_amdgpu_memory_info mem_info = {0};
|
||||
struct radv_amdgpu_alloc_tracker *alloc_tracker;
|
||||
int r;
|
||||
|
||||
@@ -393,20 +393,26 @@ radv_amdgpu_winsys_query_heap_info(ac_drm_device *dev, struct radeon_winsys_heap
|
||||
heap_info->allocated_vram_vis = alloc_tracker->allocated_vram_vis;
|
||||
heap_info->allocated_gtt = alloc_tracker->allocated_gtt;
|
||||
|
||||
- /* VRAM usage. */
|
||||
- r = ac_drm_query_heap_info(dev, AMDGPU_GEM_DOMAIN_VRAM, 0, &heap_vram);
|
||||
- if (!r)
|
||||
- heap_info->vram_usage = heap_vram.heap_usage;
|
||||
-
|
||||
- /* VRAM visible usage. */
|
||||
- r = ac_drm_query_heap_info(dev, AMDGPU_GEM_DOMAIN_VRAM, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, &heap_vram_vis);
|
||||
- if (!r)
|
||||
- heap_info->vram_vis_usage = heap_vram_vis.heap_usage;
|
||||
-
|
||||
- /* GTT usage. */
|
||||
- r = ac_drm_query_heap_info(dev, AMDGPU_GEM_DOMAIN_GTT, 0, &heap_gtt);
|
||||
- if (!r)
|
||||
- heap_info->gtt_usage = heap_gtt.heap_usage;
|
||||
+ /* One query for all three heaps.
|
||||
+ *
|
||||
+ * AMDGPU_INFO_MEMORY returns vram, cpu_accessible_vram and gtt together,
|
||||
+ * each with its usage -- which is the whole of what this function wants.
|
||||
+ * Three ac_drm_query_heap_info() calls did the same work in six ioctls,
|
||||
+ * because each of them also re-queried the device's static VRAM_GTT sizes
|
||||
+ * and then used only .heap_usage out of the result.
|
||||
+ *
|
||||
+ * Six ioctls instead of one is invisible on a local device and is not
|
||||
+ * invisible over virtio, where each is a synchronous round trip to the
|
||||
+ * host. Measured on an amdgpu native context with one game running, this
|
||||
+ * function alone accounted for 94% of all guest-to-host traffic and most of
|
||||
+ * the frame time.
|
||||
+ */
|
||||
+ r = ac_drm_query_info(dev, AMDGPU_INFO_MEMORY, sizeof(mem_info), &mem_info);
|
||||
+ if (!r) {
|
||||
+ heap_info->vram_usage = mem_info.vram.heap_usage;
|
||||
+ heap_info->vram_vis_usage = mem_info.cpu_accessible_vram.heap_usage;
|
||||
+ heap_info->gtt_usage = mem_info.gtt.heap_usage;
|
||||
+ }
|
||||
|
||||
radv_amdgpu_alloc_tracker_release(alloc_tracker);
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
From 4dcb0baf29136c90776133afb714bac3c4cb7686 Mon Sep 17 00:00:00 2001
|
||||
From: DatCaptainHorse <DatCaptainHorse@users.noreply.github.com>
|
||||
Date: Thu, 17 Sep 2026 21:50:25 +0300
|
||||
Subject: [PATCH] radv/amdgpu: cache AMDGPU_INFO_MEMORY briefly on the virtio
|
||||
path
|
||||
|
||||
Heap usage is asked for far more often than it changes. Measured on an
|
||||
amdgpu native context with one game running, RADV asked for it ~47 times
|
||||
per 8.8 ms frame -- the same answer, 47 times, each one a synchronous round
|
||||
trip to the host rather than an ioctl.
|
||||
|
||||
Serve a recent answer instead, for one millisecond. That is inside the
|
||||
contract of what the value is for: heap usage feeds VK_EXT_memory_budget
|
||||
and the winsys's own eviction decisions, and the spec calls those estimates
|
||||
that may be out of date. It is also short enough that an application
|
||||
allocating hard still sees its own pressure within a frame at any plausible
|
||||
frame rate.
|
||||
|
||||
Only on the virtio path, where a query costs a round trip; a local ioctl is
|
||||
cheap enough that caching it would be complexity for nothing. Only this
|
||||
query, and only at its natural size: every other AMDGPU_INFO_* either
|
||||
carries a caller-supplied selector in the union, so one cached answer would
|
||||
be the wrong answer to the next question, or is asked once at startup.
|
||||
|
||||
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||||
---
|
||||
src/amd/common/virtio/amdgpu_virtio.c | 53 +++++++++++++++++++
|
||||
src/amd/common/virtio/amdgpu_virtio_device.c | 1 +
|
||||
src/amd/common/virtio/amdgpu_virtio_private.h | 6 +++
|
||||
3 files changed, 60 insertions(+)
|
||||
|
||||
diff --git a/src/amd/common/virtio/amdgpu_virtio.c b/src/amd/common/virtio/amdgpu_virtio.c
|
||||
index 00494d6a750..dd38ef141f5 100644
|
||||
--- a/src/amd/common/virtio/amdgpu_virtio.c
|
||||
+++ b/src/amd/common/virtio/amdgpu_virtio.c
|
||||
@@ -19,8 +19,25 @@
|
||||
#include "drm-uapi/amdgpu_drm.h"
|
||||
|
||||
#include "util/log.h"
|
||||
+#include "util/os_time.h"
|
||||
#include "util/u_math.h"
|
||||
|
||||
+/* How long a cached AMDGPU_INFO_MEMORY answer is reused, in nanoseconds.
|
||||
+ *
|
||||
+ * Bounded by what the value is for. Heap usage feeds VK_EXT_memory_budget and
|
||||
+ * the winsys's own eviction decisions, and the spec calls those values
|
||||
+ * estimates that may be out of date -- so a millisecond of staleness is inside
|
||||
+ * the contract, while a round trip per ask is not free here the way it is on a
|
||||
+ * local ioctl.
|
||||
+ *
|
||||
+ * A millisecond rather than a frame: it is short enough that an application
|
||||
+ * allocating hard still sees its own pressure within a frame at any plausible
|
||||
+ * rate, and long enough to collapse the repeats. Measured on an amdgpu native
|
||||
+ * context with one game running, RADV asked for this ~47 times per 8.8 ms
|
||||
+ * frame -- the same answer, 47 synchronous round trips.
|
||||
+ */
|
||||
+#define AMDVGPU_MEMORY_INFO_TTL_NS (1000 * 1000)
|
||||
+
|
||||
int
|
||||
amdvgpu_query_info(amdvgpu_device_handle dev, struct drm_amdgpu_info *info)
|
||||
{
|
||||
@@ -32,6 +49,30 @@ amdvgpu_query_info(amdvgpu_device_handle dev, struct drm_amdgpu_info *info)
|
||||
struct amdgpu_ccmd_query_info_rsp *rsp;
|
||||
assert(0 == (offsetof(struct amdgpu_ccmd_query_info_rsp, payload) % 8));
|
||||
|
||||
+ /* AMDGPU_INFO_MEMORY is asked far more often than it changes, and over
|
||||
+ * virtio every ask is a synchronous round trip to the host rather than an
|
||||
+ * ioctl. Serve a recent answer instead.
|
||||
+ *
|
||||
+ * Only this query, and only at its natural size: every other query either
|
||||
+ * has a caller-supplied selector in the union -- so one cached answer would
|
||||
+ * be the wrong answer to the next question -- or is asked once at startup
|
||||
+ * and costs nothing.
|
||||
+ */
|
||||
+ bool cacheable = info->query == AMDGPU_INFO_MEMORY &&
|
||||
+ info->return_size == sizeof(struct drm_amdgpu_memory_info);
|
||||
+ if (cacheable) {
|
||||
+ int64_t now = os_time_get_nano();
|
||||
+ simple_mtx_lock(&dev->memory_info_mutex);
|
||||
+ if (dev->memory_info_stamp &&
|
||||
+ now - dev->memory_info_stamp < AMDVGPU_MEMORY_INFO_TTL_NS) {
|
||||
+ memcpy((void *)(uintptr_t)info->return_pointer, &dev->memory_info,
|
||||
+ sizeof(dev->memory_info));
|
||||
+ simple_mtx_unlock(&dev->memory_info_mutex);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ simple_mtx_unlock(&dev->memory_info_mutex);
|
||||
+ }
|
||||
+
|
||||
req->hdr = AMDGPU_CCMD(QUERY_INFO, req_len);
|
||||
memcpy(&req->info, info, sizeof(struct drm_amdgpu_info));
|
||||
|
||||
@@ -43,6 +84,18 @@ amdvgpu_query_info(amdvgpu_device_handle dev, struct drm_amdgpu_info *info)
|
||||
|
||||
memcpy((void*)(uintptr_t)info->return_pointer, rsp->payload, info->return_size);
|
||||
|
||||
+ if (cacheable) {
|
||||
+ simple_mtx_lock(&dev->memory_info_mutex);
|
||||
+ memcpy(&dev->memory_info, rsp->payload, sizeof(dev->memory_info));
|
||||
+ /* Stamped after the answer is in hand, so the window covers the time the
|
||||
+ * value is actually served rather than the round trip that fetched it.
|
||||
+ * A zero stamp means "never fetched", so a clock that returns zero here
|
||||
+ * costs a re-fetch rather than pinning a stale answer forever.
|
||||
+ */
|
||||
+ dev->memory_info_stamp = os_time_get_nano();
|
||||
+ simple_mtx_unlock(&dev->memory_info_mutex);
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/src/amd/common/virtio/amdgpu_virtio_device.c b/src/amd/common/virtio/amdgpu_virtio_device.c
|
||||
index eecfd6aa11a..7e58913d520 100644
|
||||
--- a/src/amd/common/virtio/amdgpu_virtio_device.c
|
||||
+++ b/src/amd/common/virtio/amdgpu_virtio_device.c
|
||||
@@ -136,6 +136,7 @@ int amdvgpu_device_initialize(int fd, uint32_t *drm_major, uint32_t *drm_minor,
|
||||
dev->vdev = vdev;
|
||||
|
||||
simple_mtx_init(&dev->handle_to_vbo_mutex, mtx_plain);
|
||||
+ simple_mtx_init(&dev->memory_info_mutex, mtx_plain);
|
||||
simple_mtx_init(&dev->contexts_mutex, mtx_plain);
|
||||
|
||||
dev->handle_to_vbo = _mesa_hash_table_u64_create(NULL);
|
||||
diff --git a/src/amd/common/virtio/amdgpu_virtio_private.h b/src/amd/common/virtio/amdgpu_virtio_private.h
|
||||
index 743f8f74b5c..fb877dc8d28 100644
|
||||
--- a/src/amd/common/virtio/amdgpu_virtio_private.h
|
||||
+++ b/src/amd/common/virtio/amdgpu_virtio_private.h
|
||||
@@ -60,6 +60,12 @@ struct amdvgpu_device {
|
||||
|
||||
struct drm_amdgpu_info_device dev_info;
|
||||
|
||||
+ /* AMDGPU_INFO_MEMORY, cached for a short while. See amdvgpu_query_info(). */
|
||||
+ simple_mtx_t memory_info_mutex;
|
||||
+ struct drm_amdgpu_memory_info memory_info;
|
||||
+ /* os_time_get_nano() when memory_info was fetched; 0 means never. */
|
||||
+ int64_t memory_info_stamp;
|
||||
+
|
||||
/* Blob id are per drm_file identifiers of host blobs.
|
||||
* Use a monotically increased integer to assign the blob id.
|
||||
*/
|
||||
Reference in New Issue
Block a user