Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/dumb-buffers: Provide helper to set pitch and size

Add drm_modes_size_dumb(), a helper to calculate the dumb-buffer
scanline pitch and allocation size. Implementations of struct
drm_driver.dumb_create can call the new helper for their size
computations.

There is currently quite a bit of code duplication among DRM's
memory managers. Each calculates scanline pitch and buffer size
from the given arguments, but the implementations are inconsistent
in how they treat alignment and format support. Later patches will
unify this code on top of drm_mode_size_dumb() as much as possible.

drm_mode_size_dumb() uses existing 4CC format helpers to interpret
the given color mode. This makes the dumb-buffer interface behave
similar the kernel's video= parameter. Current per-driver implementations
again likely have subtle differences or bugs in how they support color
modes.

The dumb-buffer UAPI is only specified for known color modes. These
values describe linear, single-plane RGB color formats or legacy index
formats. Other values should not be specified. But some user space
still does. So for unknown color modes, there are a number of known
exceptions for which drm_mode_size_dumb() calculates the pitch from
the bpp value, as before. All other values work the same but print
an error.

v6:
- document additional use cases for DUMB_CREATE2 in TODO list (Tomi)
- fix typos in documentation (Tomi)
v5:
- check for overflows with check_mul_overflow() (Tomi)
v4:
- use %u conversion specifier (Geert)
- list DRM_FORMAT_Dn in UAPI docs (Geert)
- avoid dmesg spamming with drm_warn_once() (Sima)
- add more information about bpp special case (Sima)
- clarify parameters for hardware alignment
- add a TODO item for DUMB_CREATE2
v3:
- document the UAPI semantics
- compute scanline pitch from for unknown color modes (Andy, Tomi)

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Link: https://lore.kernel.org/r/20250821081918.79786-3-tzimmermann@suse.de

+230 -1
+37
Documentation/gpu/todo.rst
··· 648 648 649 649 Level: Advanced 650 650 651 + Implement a new DUMB_CREATE2 ioctl 652 + ---------------------------------- 653 + 654 + The current DUMB_CREATE ioctl is not well defined. Instead of a pixel and 655 + framebuffer format, it only accepts a color mode of vague semantics. Assuming 656 + a linear framebuffer, the color mode gives an idea of the supported pixel 657 + format. But userspace effectively has to guess the correct values. It really 658 + only works reliably with framebuffers in XRGB8888. Userspace has begun to 659 + workaround these limitations by computing arbitrary format's buffer sizes and 660 + calculating their sizes in terms of XRGB8888 pixels. 661 + 662 + One possible solution is a new ioctl DUMB_CREATE2. It should accept a DRM 663 + format and a format modifier to resolve the color mode's ambiguity. As 664 + framebuffers can be multi-planar, the new ioctl has to return the buffer size, 665 + pitch and GEM handle for each individual color plane. 666 + 667 + In the first step, the new ioctl can be limited to the current features of 668 + the existing DUMB_CREATE. Individual drivers can then be extended to support 669 + multi-planar formats. Rockchip might require this and would be a good candidate. 670 + 671 + It might also be helpful to userspace to query information about the size of 672 + a potential buffer, if allocated. Userspace would supply geometry and format; 673 + the kernel would return minimal allocation sizes and scanline pitch. There is 674 + interest to allocate that memory from another device and provide it to the 675 + DRM driver (say via dma-buf). 676 + 677 + Another requested feature is the ability to allocate a buffer by size, without 678 + format. Accelators use this for their buffer allocation and it could likely be 679 + generalized. 680 + 681 + In addition to the kernel implementation, there must be user-space support 682 + for the new ioctl. There's code in Mesa that might be able to use the new 683 + call. 684 + 685 + Contact: Thomas Zimmermann <tzimmermann@suse.de> 686 + 687 + Level: Advanced 651 688 652 689 Better Testing 653 690 ==============
+130
drivers/gpu/drm/drm_dumb_buffers.c
··· 25 25 26 26 #include <drm/drm_device.h> 27 27 #include <drm/drm_drv.h> 28 + #include <drm/drm_dumb_buffers.h> 29 + #include <drm/drm_fourcc.h> 28 30 #include <drm/drm_gem.h> 29 31 #include <drm/drm_mode.h> 30 32 ··· 58 56 * attempted on some ARM embedded platforms. Such drivers really must have 59 57 * a hardware-specific ioctl to allocate suitable buffer objects. 60 58 */ 59 + 60 + static int drm_mode_align_dumb(struct drm_mode_create_dumb *args, 61 + unsigned long hw_pitch_align, 62 + unsigned long hw_size_align) 63 + { 64 + u32 pitch = args->pitch; 65 + u32 size; 66 + 67 + if (!pitch) 68 + return -EINVAL; 69 + 70 + if (hw_pitch_align) 71 + pitch = roundup(pitch, hw_pitch_align); 72 + 73 + if (!hw_size_align) 74 + hw_size_align = PAGE_SIZE; 75 + else if (!IS_ALIGNED(hw_size_align, PAGE_SIZE)) 76 + return -EINVAL; /* TODO: handle this if necessary */ 77 + 78 + if (check_mul_overflow(args->height, pitch, &size)) 79 + return -EINVAL; 80 + size = ALIGN(size, hw_size_align); 81 + if (!size) 82 + return -EINVAL; 83 + 84 + args->pitch = pitch; 85 + args->size = size; 86 + 87 + return 0; 88 + } 89 + 90 + /** 91 + * drm_mode_size_dumb - Calculates the scanline and buffer sizes for dumb buffers 92 + * @dev: DRM device 93 + * @args: Parameters for the dumb buffer 94 + * @hw_pitch_align: Hardware scanline alignment in bytes 95 + * @hw_size_align: Hardware buffer-size alignment in bytes 96 + * 97 + * The helper drm_mode_size_dumb() calculates the size of the buffer 98 + * allocation and the scanline size for a dumb buffer. Callers have to 99 + * set the buffers width, height and color mode in the argument @arg. 100 + * The helper validates the correctness of the input and tests for 101 + * possible overflows. If successful, it returns the dumb buffer's 102 + * required scanline pitch and size in &args. 103 + * 104 + * The parameter @hw_pitch_align allows the driver to specifies an 105 + * alignment for the scanline pitch, if the hardware requires any. The 106 + * calculated pitch will be a multiple of the alignment. The parameter 107 + * @hw_size_align allows to specify an alignment for buffer sizes. The 108 + * provided alignment should represent requirements of the graphics 109 + * hardware. drm_mode_size_dumb() handles GEM-related constraints 110 + * automatically across all drivers and hardware. For example, the 111 + * returned buffer size is always a multiple of PAGE_SIZE, which is 112 + * required by mmap(). 113 + * 114 + * Returns: 115 + * Zero on success, or a negative error code otherwise. 116 + */ 117 + int drm_mode_size_dumb(struct drm_device *dev, 118 + struct drm_mode_create_dumb *args, 119 + unsigned long hw_pitch_align, 120 + unsigned long hw_size_align) 121 + { 122 + u64 pitch = 0; 123 + u32 fourcc; 124 + 125 + /* 126 + * The scanline pitch depends on the buffer width and the color 127 + * format. The latter is specified as a color-mode constant for 128 + * which we first have to find the corresponding color format. 129 + * 130 + * Different color formats can have the same color-mode constant. 131 + * For example XRGB8888 and BGRX8888 both have a color mode of 32. 132 + * It is possible to use different formats for dumb-buffer allocation 133 + * and rendering as long as all involved formats share the same 134 + * color-mode constant. 135 + */ 136 + fourcc = drm_driver_color_mode_format(dev, args->bpp); 137 + if (fourcc != DRM_FORMAT_INVALID) { 138 + const struct drm_format_info *info = drm_format_info(fourcc); 139 + 140 + if (!info) 141 + return -EINVAL; 142 + pitch = drm_format_info_min_pitch(info, 0, args->width); 143 + } else if (args->bpp) { 144 + /* 145 + * Some userspace throws in arbitrary values for bpp and 146 + * relies on the kernel to figure it out. In this case we 147 + * fall back to the old method of using bpp directly. The 148 + * over-commitment of memory from the rounding is acceptable 149 + * for compatibility with legacy userspace. We have a number 150 + * of deprecated legacy values that are explicitly supported. 151 + */ 152 + switch (args->bpp) { 153 + default: 154 + drm_warn_once(dev, 155 + "Unknown color mode %u; guessing buffer size.\n", 156 + args->bpp); 157 + fallthrough; 158 + /* 159 + * These constants represent various YUV formats supported by 160 + * drm_gem_afbc_get_bpp(). 161 + */ 162 + case 12: // DRM_FORMAT_YUV420_8BIT 163 + case 15: // DRM_FORMAT_YUV420_10BIT 164 + case 30: // DRM_FORMAT_VUY101010 165 + fallthrough; 166 + /* 167 + * Used by Mesa and Gstreamer to allocate NV formats and others 168 + * as RGB buffers. Technically, XRGB16161616F formats are RGB, 169 + * but the dumb buffers are not supposed to be used for anything 170 + * beyond 32 bits per pixels. 171 + */ 172 + case 10: // DRM_FORMAT_NV{15,20,30}, DRM_FORMAT_P010 173 + case 64: // DRM_FORMAT_{XRGB,XBGR,ARGB,ABGR}16161616F 174 + pitch = args->width * DIV_ROUND_UP(args->bpp, SZ_8); 175 + break; 176 + } 177 + } 178 + 179 + if (!pitch || pitch > U32_MAX) 180 + return -EINVAL; 181 + 182 + args->pitch = pitch; 183 + 184 + return drm_mode_align_dumb(args, hw_pitch_align, hw_size_align); 185 + } 186 + EXPORT_SYMBOL(drm_mode_size_dumb); 61 187 62 188 int drm_mode_create_dumb(struct drm_device *dev, 63 189 struct drm_mode_create_dumb *args,
+14
include/drm/drm_dumb_buffers.h
··· 1 + /* SPDX-License-Identifier: MIT */ 2 + 3 + #ifndef __DRM_DUMB_BUFFERS_H__ 4 + #define __DRM_DUMB_BUFFERS_H__ 5 + 6 + struct drm_device; 7 + struct drm_mode_create_dumb; 8 + 9 + int drm_mode_size_dumb(struct drm_device *dev, 10 + struct drm_mode_create_dumb *args, 11 + unsigned long hw_pitch_align, 12 + unsigned long hw_size_align); 13 + 14 + #endif
+49 -1
include/uapi/drm/drm_mode.h
··· 1066 1066 * struct drm_mode_create_dumb - Create a KMS dumb buffer for scanout. 1067 1067 * @height: buffer height in pixels 1068 1068 * @width: buffer width in pixels 1069 - * @bpp: bits per pixel 1069 + * @bpp: color mode 1070 1070 * @flags: must be zero 1071 1071 * @handle: buffer object handle 1072 1072 * @pitch: number of bytes between two consecutive lines ··· 1074 1074 * 1075 1075 * User-space fills @height, @width, @bpp and @flags. If the IOCTL succeeds, 1076 1076 * the kernel fills @handle, @pitch and @size. 1077 + * 1078 + * The value of @bpp is a color-mode number describing a specific format 1079 + * or a variant thereof. The value often corresponds to the number of bits 1080 + * per pixel for most modes, although there are exceptions. Each color mode 1081 + * maps to a DRM format plus a number of modes with similar pixel layout. 1082 + * Framebuffer layout is always linear. 1083 + * 1084 + * Support for all modes and formats is optional. Even if dumb-buffer 1085 + * creation with a certain color mode succeeds, it is not guaranteed that 1086 + * the DRM driver supports any of the related formats. Most drivers support 1087 + * a color mode of 32 with a format of DRM_FORMAT_XRGB8888 on their primary 1088 + * plane. 1089 + * 1090 + * +------------+------------------------+------------------------+ 1091 + * | Color mode | Framebuffer format | Compatible formats | 1092 + * +============+========================+========================+ 1093 + * | 32 | * DRM_FORMAT_XRGB8888 | * DRM_FORMAT_BGRX8888 | 1094 + * | | | * DRM_FORMAT_RGBX8888 | 1095 + * | | | * DRM_FORMAT_XBGR8888 | 1096 + * +------------+------------------------+------------------------+ 1097 + * | 24 | * DRM_FORMAT_RGB888 | * DRM_FORMAT_BGR888 | 1098 + * +------------+------------------------+------------------------+ 1099 + * | 16 | * DRM_FORMAT_RGB565 | * DRM_FORMAT_BGR565 | 1100 + * +------------+------------------------+------------------------+ 1101 + * | 15 | * DRM_FORMAT_XRGB1555 | * DRM_FORMAT_BGRX1555 | 1102 + * | | | * DRM_FORMAT_RGBX1555 | 1103 + * | | | * DRM_FORMAT_XBGR1555 | 1104 + * +------------+------------------------+------------------------+ 1105 + * | 8 | * DRM_FORMAT_C8 | * DRM_FORMAT_D8 | 1106 + * | | | * DRM_FORMAT_R8 | 1107 + * +------------+------------------------+------------------------+ 1108 + * | 4 | * DRM_FORMAT_C4 | * DRM_FORMAT_D4 | 1109 + * | | | * DRM_FORMAT_R4 | 1110 + * +------------+------------------------+------------------------+ 1111 + * | 2 | * DRM_FORMAT_C2 | * DRM_FORMAT_D2 | 1112 + * | | | * DRM_FORMAT_R2 | 1113 + * +------------+------------------------+------------------------+ 1114 + * | 1 | * DRM_FORMAT_C1 | * DRM_FORMAT_D1 | 1115 + * | | | * DRM_FORMAT_R1 | 1116 + * +------------+------------------------+------------------------+ 1117 + * 1118 + * Color modes of 10, 12, 15, 30 and 64 are only supported for use by 1119 + * legacy user space. Please don't use them in new code. Other modes 1120 + * are not support. 1121 + * 1122 + * Do not attempt to allocate anything but linear framebuffer memory 1123 + * with single-plane RGB data. Allocation of other framebuffer 1124 + * layouts requires dedicated ioctls in the respective DRM driver. 1077 1125 */ 1078 1126 struct drm_mode_create_dumb { 1079 1127 __u32 height;