diff --git a/services/waylandbridge/awl_bufferqueue.h b/services/waylandbridge/awl_bufferqueue.h index 0bbdd1e0..2cb3008f 100644 --- a/services/waylandbridge/awl_bufferqueue.h +++ b/services/waylandbridge/awl_bufferqueue.h @@ -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: diff --git a/services/waylandbridge/awl_dmabuf.c b/services/waylandbridge/awl_dmabuf.c index 6b10dd91..2b5b60f9 100644 --- a/services/waylandbridge/awl_dmabuf.c +++ b/services/waylandbridge/awl_dmabuf.c @@ -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; diff --git a/services/waylandbridge/awl_internal.h b/services/waylandbridge/awl_internal.h index ab6047a0..c0eb3408 100644 --- a/services/waylandbridge/awl_internal.h +++ b/services/waylandbridge/awl_internal.h @@ -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; }; diff --git a/services/waylandbridge/awl_renderer.cpp b/services/waylandbridge/awl_renderer.cpp index 31ca80e0..0f18d9c0 100644 --- a/services/waylandbridge/awl_renderer.cpp +++ b/services/waylandbridge/awl_renderer.cpp @@ -34,8 +34,11 @@ #include #include +#include #include /* round: pixel-grid snap of the dst */ #include +#include +#include #include /* close (release fence) */ #include @@ -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 { @@ -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). @@ -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; diff --git a/services/waylandbridge/awl_surface.c b/services/waylandbridge/awl_surface.c index 987bf1f3..7e00502c 100644 --- a/services/waylandbridge/awl_surface.c +++ b/services/waylandbridge/awl_surface.c @@ -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;