Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions services/waylandbridge/awl_bufferqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ struct awl_bq_buffer {
int release_fd; /* merged consumer fences (awl_bufferqueue_put);
* valid inside the release callback only */
uint64_t ino; /* dma-buf inode: render-side identity (0 = unknown) */
uint64_t modifier; /* DRM format modifier; CPU readers must require LINEAR */
uint32_t width, height, stride; /* stride in bytes */
uint32_t format; /* DRM fourcc */
uint64_t seq; /* process-wide frame sequence, stamped by push:
Expand Down
1 change: 1 addition & 0 deletions services/waylandbridge/awl_dmabuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ static struct awl_buffer* dmabuf_buffer_create(struct wl_client* client,
* carries it, the render side compares
* inodes with no per-frame fstat */
b->ino = fstat(fd, &st) == 0 ? (uint64_t)st.st_ino : 0;
b->modifier = modifier;
b->width = w;
b->height = h;
b->stride = stride;
Expand Down
1 change: 1 addition & 0 deletions services/waylandbridge/awl_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ struct awl_buffer {
* identity without a per-frame fstat
* (0 = fstat failed here, consumers
* fall back to their own) */
uint64_t modifier; /* DRM format modifier from linux-dmabuf */
uint32_t width, height, stride; /* stride: bytes */
uint32_t drm_format;
};
Expand Down
78 changes: 72 additions & 6 deletions services/waylandbridge/awl_renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@

#include <android/log.h>
#include <android/native_window.h>
#include <linux/dma-buf.h>
#include <math.h> /* round: pixel-grid snap of the dst */
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h> /* close (release fence) */

#include <atomic>
Expand All @@ -54,6 +57,7 @@
struct wl_layer {
struct awl_ahb_cache* cache = nullptr;
awl_gl_shm_tex shm;
bool cpu_dmabuf = false; /* sticky after vendor AHB forging is incompatible */
};

struct wl_window {
Expand Down Expand Up @@ -146,6 +150,56 @@ static void window_teardown_gl(wl_window* w) {
static void render_thread_loop(wl_window* w); /* defined at end of file */
void awl_renderer_request_render(uint64_t id); /* awl_renderer.hpp; used by render_frame's re-arm */

/* Compatibility path for vendor gralloc layouts that cannot describe Mesa's
* linear KGSL pitch (alioth: client 2048px, Android allocator skips directly
* from 1792 to 2304). The queue has already waited the acquire fence before
* this point. Copy the linear AR24/XR24 dma-buf into the same GL texture
* uploader used by wl_shm; release happens only after the upload has returned.
* Full upload is deliberate: linux-dmabuf commits do not carry a stable damage
* snapshot in the queue element. */
static GLuint dmabuf_cpu_texture(wl_layer* l, const struct awl_bq_buffer* b) {
/* DRM_FORMAT_MOD_LINEAR is zero. INVALID/implicit is not proof of a
* linear layout and must never be interpreted as rows of pixels. */
if (b->modifier != 0 || !b->height || b->stride % 4 != 0 ||
(uint64_t)b->stride < (uint64_t)b->width * 4) return 0;
size_t bytes = 0;
if (__builtin_mul_overflow((size_t)b->stride, (size_t)b->height, &bytes) ||
!bytes) return 0;
off_t alloc = lseek(b->dmabuf_fd, 0, SEEK_END);
if (alloc > 0 && (uint64_t)alloc < bytes) {
LOGE("dmabuf CPU fallback allocation too small: %lld < %zu",
(long long)alloc, bytes);
return 0;
}
struct dma_buf_sync sync = { .flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ };
bool cpu_sync = ioctl(b->dmabuf_fd, DMA_BUF_IOCTL_SYNC, &sync) == 0;
void* pixels = mmap(NULL, bytes, PROT_READ, MAP_SHARED, b->dmabuf_fd, 0);
if (pixels == MAP_FAILED) {
LOGE("dmabuf CPU fallback mmap %ux%u stride=%u failed: %s",
b->width, b->height, b->stride, strerror(errno));
if (cpu_sync) {
sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ;
ioctl(b->dmabuf_fd, DMA_BUF_IOCTL_SYNC, &sync);
}
return 0;
}
awl_shm_frame_t f = {};
f.width = b->width;
f.height = b->height;
f.stride = b->stride;
f.format = b->format;
f.pixels = pixels;
f.dmg_full = 1;
f.serial = l->shm.serial + 1;
bool ok = awl_gl_shm_update(&l->shm, &f);
munmap(pixels, bytes);
if (cpu_sync) {
sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ;
ioctl(b->dmabuf_fd, DMA_BUF_IOCTL_SYNC, &sync);
}
return ok ? l->shm.texture : 0;
}

/* Detach and reclaim a window entry (map removal inside g_map_lock, join/free
* entirely outside the lock — join must not hold g_map_lock: it would stall
* every window's request_render, which runs on the client dispatch thread).
Expand Down Expand Up @@ -291,12 +345,24 @@ static void render_frame(wl_window* w) {
uint32_t bw = 0, bh = 0, fmt = 0;
if (b && b->dmabuf_fd >= 0) {
/* dmabuf frame → forged AHB → EGLImage texture (cache hit from the second lap on) */
if (l.shm.texture) awl_gl_shm_release(&l.shm); /* the surface left wl_shm */
if (!l.cache) l.cache = awl_ahb_cache_create(awl_gl_tex_payload_destroy);
struct awl_ahb_slot* s = l.cache
? awl_ahb_cache_get(l.cache, b, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE, w->frame_no)
: nullptr;
if (s) tex = awl_gl_slot_texture(s); /* 0 = forge/import refused — retry next frame */
if (!l.cpu_dmabuf) {
if (!l.cache) l.cache = awl_ahb_cache_create(awl_gl_tex_payload_destroy);
struct awl_ahb_slot* s = l.cache
? awl_ahb_cache_get(l.cache, b, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE, w->frame_no)
: nullptr;
if (s) tex = awl_gl_slot_texture(s);
}
if (tex) {
if (l.shm.texture) awl_gl_shm_release(&l.shm);
} else {
tex = dmabuf_cpu_texture(&l, b);
if (tex && !l.cpu_dmabuf) {
l.cpu_dmabuf = true;
LOGI("window %llu layer %llu: AHB unavailable — linear dmabuf CPU upload fallback",
(unsigned long long)w->id,
(unsigned long long)lay[i].surface_id);
}
}
bw = b->width;
bh = b->height;
fmt = b->format;
Expand Down
1 change: 1 addition & 0 deletions services/waylandbridge/awl_surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ void awl_surface_apply_buffer(struct awl_surface* s, struct wl_resource* res,
e.acquire_fd = acquire_fd >= 0 ? acquire_fd : awl_dmabuf_export_sync_file(b->dmabuf_fd);
e.release_fd = -1;
e.ino = b->ino;
e.modifier = b->modifier;
e.width = b->width;
e.height = b->height;
e.stride = b->stride;
Expand Down
Loading