Fix for virglrenderer sandbox/lstelmach/virgl
authorŁukasz Stelmach <l.stelmach@samsung.com>
Thu, 19 Oct 2023 14:21:02 +0000 (16:21 +0200)
committerŁukasz Stelmach <l.stelmach@samsung.com>
Fri, 24 Nov 2023 12:35:08 +0000 (13:35 +0100)
virglrenderer used by QEMU together with virtio-gpu allows allocations
that are at most 16384 pixels wide or high. This means it can provide
buffers as large as 256 MiB but they need to be 16k by 16k pixels and
not 256M by 1. Square root approximation is quick and although it results
in buffers being allocated slightly larger than requested, but the error
isn't significant.

Change-Id: Ife231fd5ac4eae0181680e86ec9c239920cdef41
Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
src/tbm_backend_dumb.c

index 5963f4925fdf175451dd5ecc87acbec38ac99d80..0edb5dca78ec297dcb5220807b8cc09d4d905572 100644 (file)
@@ -640,6 +640,24 @@ tbm_dumb_bufmgr_get_plane_data(hal_tbm_bufmgr *bufmgr,
        return HAL_TBM_ERROR_NONE;
 }
 
+#define LOG2(x) ((unsigned int)(sizeof(unsigned int) * 8 - 1 - __builtin_clz(x)))
+
+static inline unsigned int dirty_sqrt(unsigned int v)
+{
+       unsigned int log2 = LOG2(v);
+
+       if (log2 < 0)
+               return 0;
+
+       if (log2 == 0)
+               return 1;
+
+       log2 += !!(v & (1 << (log2 - 1)));
+       log2 >>= 1;
+
+       return 1 << log2;
+}
+
 static hal_tbm_bo *
 tbm_dumb_bufmgr_alloc_bo(hal_tbm_bufmgr *bufmgr, unsigned int size,
                                        hal_tbm_bo_memory_type flags, hal_tbm_error *error)
@@ -662,9 +680,18 @@ tbm_dumb_bufmgr_alloc_bo(hal_tbm_bufmgr *bufmgr, unsigned int size,
 
        //as we know only size for new bo set height=1 and bpp=8 and in this case
        //width will by equal to size in bytes;
-       create_dumb_arg.height = 1;
        create_dumb_arg.bpp = 32; // virtio-gpu refuses to accept bpp=8
-       create_dumb_arg.width = (size + 4 - 1) / 4;
+       if (size <= 16384) {
+               create_dumb_arg.height = 1;
+               create_dumb_arg.width = (size + 4 - 1) / 4;
+       } else {
+               unsigned int words = (size + 4 - 1) / 4;
+               unsigned int root = dirty_sqrt(words);
+
+               create_dumb_arg.height = root;
+               create_dumb_arg.width = (words + root - 1) / root;
+       }
+
        create_dumb_arg.flags = dumb_flags;
        if (drmIoctl(bufmgr_data->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb_arg)) {
                TBM_BACKEND_ERR("fail to DRM_IOCTL_MODE_CREATE_DUMB flag:%x size:%d",