diff --git a/3RDPARTY b/3RDPARTY index 4e495291..ae466a74 100644 --- a/3RDPARTY +++ b/3RDPARTY @@ -1,5 +1,5 @@ -# $OpenBSD: 3RDPARTY,v 1.421 2024/01/16 13:14:26 matthieu Exp $ +# $OpenBSD: 3RDPARTY,v 1.422 2024/01/30 07:50:26 jsg Exp $ # Package: Freetype Version: 2.13.0 @@ -15,12 +15,12 @@ Archive Site: https://invisible-island.net/xterm/xterm.html Package: Mesa Version 23.1.9 -Current Vers: 23.3.2 +Current Vers: 23.3.4 Maintainer: Brian Paul Archive Site: https://archive.mesa3d.org/ Package: libdrm -Version: 2.4.115 +Version: 2.4.120 Current Vers: 2.4.120 Maintainer: Freedesktop.org Archive Site: https://dri.freedesktop.org/libdrm/ diff --git a/distrib/sets/lists/xbase/md.amd64 b/distrib/sets/lists/xbase/md.amd64 index a3c66f7f..49a5b9c5 100644 --- a/distrib/sets/lists/xbase/md.amd64 +++ b/distrib/sets/lists/xbase/md.amd64 @@ -268,9 +268,9 @@ ./usr/X11R6/lib/libOSMesa.so.13.0 ./usr/X11R6/lib/libOSMesa_p.a ./usr/X11R6/lib/libdrm.a -./usr/X11R6/lib/libdrm.so.7.12 +./usr/X11R6/lib/libdrm.so.7.13 ./usr/X11R6/lib/libdrm_amdgpu.a -./usr/X11R6/lib/libdrm_amdgpu.so.1.12 +./usr/X11R6/lib/libdrm_amdgpu.so.1.13 ./usr/X11R6/lib/libdrm_amdgpu_p.a ./usr/X11R6/lib/libdrm_intel.a ./usr/X11R6/lib/libdrm_intel.so.5.4 diff --git a/distrib/sets/lists/xbase/md.arm64 b/distrib/sets/lists/xbase/md.arm64 index 7b9a4419..59f894cd 100644 --- a/distrib/sets/lists/xbase/md.arm64 +++ b/distrib/sets/lists/xbase/md.arm64 @@ -259,9 +259,9 @@ ./usr/X11R6/lib/libOSMesa.so.13.0 ./usr/X11R6/lib/libOSMesa_p.a ./usr/X11R6/lib/libdrm.a -./usr/X11R6/lib/libdrm.so.7.12 +./usr/X11R6/lib/libdrm.so.7.13 ./usr/X11R6/lib/libdrm_amdgpu.a -./usr/X11R6/lib/libdrm_amdgpu.so.1.12 +./usr/X11R6/lib/libdrm_amdgpu.so.1.13 ./usr/X11R6/lib/libdrm_amdgpu_p.a ./usr/X11R6/lib/libdrm_p.a ./usr/X11R6/lib/libdrm_radeon.a diff --git a/distrib/sets/lists/xbase/md.armv7 b/distrib/sets/lists/xbase/md.armv7 index 62fcdf34..ca239854 100644 --- a/distrib/sets/lists/xbase/md.armv7 +++ b/distrib/sets/lists/xbase/md.armv7 @@ -259,9 +259,9 @@ ./usr/X11R6/lib/libOSMesa.so.13.0 ./usr/X11R6/lib/libOSMesa_p.a ./usr/X11R6/lib/libdrm.a -./usr/X11R6/lib/libdrm.so.7.12 +./usr/X11R6/lib/libdrm.so.7.13 ./usr/X11R6/lib/libdrm_amdgpu.a -./usr/X11R6/lib/libdrm_amdgpu.so.1.12 +./usr/X11R6/lib/libdrm_amdgpu.so.1.13 ./usr/X11R6/lib/libdrm_amdgpu_p.a ./usr/X11R6/lib/libdrm_p.a ./usr/X11R6/lib/libdrm_radeon.a diff --git a/distrib/sets/lists/xbase/md.i386 b/distrib/sets/lists/xbase/md.i386 index 2e399e14..d0260e92 100644 --- a/distrib/sets/lists/xbase/md.i386 +++ b/distrib/sets/lists/xbase/md.i386 @@ -268,9 +268,9 @@ ./usr/X11R6/lib/libOSMesa.so.13.0 ./usr/X11R6/lib/libOSMesa_p.a ./usr/X11R6/lib/libdrm.a -./usr/X11R6/lib/libdrm.so.7.12 +./usr/X11R6/lib/libdrm.so.7.13 ./usr/X11R6/lib/libdrm_amdgpu.a -./usr/X11R6/lib/libdrm_amdgpu.so.1.12 +./usr/X11R6/lib/libdrm_amdgpu.so.1.13 ./usr/X11R6/lib/libdrm_amdgpu_p.a ./usr/X11R6/lib/libdrm_intel.a ./usr/X11R6/lib/libdrm_intel.so.5.4 diff --git a/lib/libdrm/amdgpu/amdgpu-symbols.txt b/lib/libdrm/amdgpu/amdgpu-symbols.txt index d41d9c24..530b343b 100644 --- a/lib/libdrm/amdgpu/amdgpu-symbols.txt +++ b/lib/libdrm/amdgpu/amdgpu-symbols.txt @@ -63,6 +63,7 @@ amdgpu_query_crtc_from_id amdgpu_query_firmware_version amdgpu_query_gds_info amdgpu_query_gpu_info +amdgpu_query_gpuvm_fault_info amdgpu_query_heap_info amdgpu_query_hw_ip_count amdgpu_query_hw_ip_info @@ -72,6 +73,7 @@ amdgpu_query_video_caps_info amdgpu_read_mm_registers amdgpu_va_range_alloc amdgpu_va_range_free +amdgpu_va_get_start_addr amdgpu_va_range_query amdgpu_vm_reserve_vmid amdgpu_vm_unreserve_vmid diff --git a/lib/libdrm/amdgpu/amdgpu.h b/lib/libdrm/amdgpu/amdgpu.h index 5ef2524a..9bdbf366 100644 --- a/lib/libdrm/amdgpu/amdgpu.h +++ b/lib/libdrm/amdgpu/amdgpu.h @@ -1282,6 +1282,22 @@ int amdgpu_query_sensor_info(amdgpu_device_handle dev, unsigned sensor_type, int amdgpu_query_video_caps_info(amdgpu_device_handle dev, unsigned cap_type, unsigned size, void *value); +/** + * Query information about VM faults + * + * The return sizeof(struct drm_amdgpu_info_gpuvm_fault) + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param size - \c [in] Size of the returned value. + * \param value - \c [out] Pointer to the return value. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_query_gpuvm_fault_info(amdgpu_device_handle dev, unsigned size, + void *value); + /** * Read a set of consecutive memory-mapped registers. * Not all registers are allowed to be read by userspace. @@ -1368,6 +1384,11 @@ int amdgpu_va_range_alloc(amdgpu_device_handle dev, */ int amdgpu_va_range_free(amdgpu_va_handle va_range_handle); +/** + * Return the starting address of the allocated virtual address range. + */ +uint64_t amdgpu_va_get_start_addr(amdgpu_va_handle va_handle); + /** * Query virtual address range * diff --git a/lib/libdrm/amdgpu/amdgpu_bo.c b/lib/libdrm/amdgpu/amdgpu_bo.c index f4e04352..672f000d 100644 --- a/lib/libdrm/amdgpu/amdgpu_bo.c +++ b/lib/libdrm/amdgpu/amdgpu_bo.c @@ -551,7 +551,7 @@ drm_public int amdgpu_find_bo_by_cpu_mapping(amdgpu_device_handle dev, if (!bo || !bo->cpu_ptr || size > bo->alloc_size) continue; if (cpu >= bo->cpu_ptr && - cpu < (void*)((uintptr_t)bo->cpu_ptr + bo->alloc_size)) + cpu < (void*)((uintptr_t)bo->cpu_ptr + (size_t)bo->alloc_size)) break; } diff --git a/lib/libdrm/amdgpu/amdgpu_cs.c b/lib/libdrm/amdgpu/amdgpu_cs.c index 638fd7d6..49fc16c3 100644 --- a/lib/libdrm/amdgpu/amdgpu_cs.c +++ b/lib/libdrm/amdgpu/amdgpu_cs.c @@ -56,10 +56,22 @@ drm_public int amdgpu_cs_ctx_create2(amdgpu_device_handle dev, union drm_amdgpu_ctx args; int i, j, k; int r; + char *override_priority; if (!dev || !context) return -EINVAL; + override_priority = getenv("AMD_PRIORITY"); + if (override_priority) { + /* The priority is a signed integer. The variable type is + * wrong. If parsing fails, priority is unchanged. + */ + if (sscanf(override_priority, "%i", &priority) == 1) { + printf("amdgpu: context priority changed to %i\n", + priority); + } + } + gpu_context = calloc(1, sizeof(struct amdgpu_context)); if (!gpu_context) return -ENOMEM; @@ -128,8 +140,8 @@ drm_public int amdgpu_cs_ctx_free(amdgpu_context_handle context) for (i = 0; i < AMDGPU_HW_IP_NUM; i++) { for (j = 0; j < AMDGPU_HW_IP_INSTANCE_MAX_COUNT; j++) { for (k = 0; k < AMDGPU_CS_MAX_RINGS; k++) { - amdgpu_semaphore_handle sem; - LIST_FOR_EACH_ENTRY(sem, &context->sem_list[i][j][k], list) { + amdgpu_semaphore_handle sem, tmp; + LIST_FOR_EACH_ENTRY_SAFE(sem, tmp, &context->sem_list[i][j][k], list) { list_del(&sem->list); amdgpu_cs_reset_sem(sem); amdgpu_cs_unreference_sem(sem); diff --git a/lib/libdrm/amdgpu/amdgpu_gpu_info.c b/lib/libdrm/amdgpu/amdgpu_gpu_info.c index 9f8695ce..1a5143a6 100644 --- a/lib/libdrm/amdgpu/amdgpu_gpu_info.c +++ b/lib/libdrm/amdgpu/amdgpu_gpu_info.c @@ -346,3 +346,17 @@ drm_public int amdgpu_query_video_caps_info(amdgpu_device_handle dev, unsigned c return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, sizeof(struct drm_amdgpu_info)); } + +drm_public int amdgpu_query_gpuvm_fault_info(amdgpu_device_handle dev, + unsigned size, void *value) +{ + struct drm_amdgpu_info request; + + memset(&request, 0, sizeof(request)); + request.return_pointer = (uintptr_t)value; + request.return_size = size; + request.query = AMDGPU_INFO_GPUVM_FAULT; + + return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, + sizeof(struct drm_amdgpu_info)); +} diff --git a/lib/libdrm/amdgpu/amdgpu_internal.h b/lib/libdrm/amdgpu/amdgpu_internal.h index 37a7c9d5..2834c9c6 100644 --- a/lib/libdrm/amdgpu/amdgpu_internal.h +++ b/lib/libdrm/amdgpu/amdgpu_internal.h @@ -57,7 +57,6 @@ struct amdgpu_bo_va_mgr { }; struct amdgpu_va { - amdgpu_device_handle dev; uint64_t address; uint64_t size; enum amdgpu_gpu_va_range range; diff --git a/lib/libdrm/amdgpu/amdgpu_vamgr.c b/lib/libdrm/amdgpu/amdgpu_vamgr.c index 077a9fc8..2c4c9dba 100644 --- a/lib/libdrm/amdgpu/amdgpu_vamgr.c +++ b/lib/libdrm/amdgpu/amdgpu_vamgr.c @@ -274,7 +274,6 @@ drm_public int amdgpu_va_range_alloc(amdgpu_device_handle dev, amdgpu_vamgr_free_va(vamgr, *va_base_allocated, size); return -ENOMEM; } - va->dev = dev; va->address = *va_base_allocated; va->size = size; va->range = va_range_type; @@ -296,3 +295,8 @@ drm_public int amdgpu_va_range_free(amdgpu_va_handle va_range_handle) free(va_range_handle); return 0; } + +drm_public uint64_t amdgpu_va_get_start_addr(amdgpu_va_handle va_handle) +{ + return va_handle->address; +} diff --git a/lib/libdrm/amdgpu/meson.build b/lib/libdrm/amdgpu/meson.build index a1cca5a2..679de94d 100644 --- a/lib/libdrm/amdgpu/meson.build +++ b/lib/libdrm/amdgpu/meson.build @@ -36,7 +36,7 @@ libdrm_amdgpu = library( ], include_directories : [inc_root, inc_drm], link_with : libdrm, - dependencies : [dep_pthread_stubs, dep_atomic_ops, dep_rt], + dependencies : [dep_threads, dep_atomic_ops, dep_rt], version : '1.0.0', install : true, ) @@ -65,6 +65,6 @@ test( args : [ '--lib', libdrm_amdgpu, '--symbols-file', files('amdgpu-symbols.txt'), - '--nm', prog_nm.path(), + '--nm', prog_nm.full_path(), ], ) diff --git a/lib/libdrm/core-symbols.txt b/lib/libdrm/core-symbols.txt index 9f8a323b..766c342d 100644 --- a/lib/libdrm/core-symbols.txt +++ b/lib/libdrm/core-symbols.txt @@ -70,6 +70,7 @@ drmGetLibVersion drmGetLock drmGetMagic drmGetMap +drmGetNodeTypeFromDevId drmGetNodeTypeFromFd drmGetPrimaryDeviceNameFromFd drmGetRenderDeviceNameFromFd @@ -103,6 +104,7 @@ drmModeAtomicGetCursor drmModeAtomicMerge drmModeAtomicSetCursor drmModeAttachMode +drmModeCloseFB drmModeConnectorGetPossibleCrtcs drmModeConnectorSetProperty drmModeCreateDumbBuffer @@ -187,6 +189,7 @@ drmSLNext drmSwitchToContext drmSyncobjCreate drmSyncobjDestroy +drmSyncobjEventfd drmSyncobjExportSyncFile drmSyncobjFDToHandle drmSyncobjHandleToFD diff --git a/lib/libdrm/data/amdgpu.ids b/lib/libdrm/data/amdgpu.ids index 53cf61cb..0e79a583 100644 --- a/lib/libdrm/data/amdgpu.ids +++ b/lib/libdrm/data/amdgpu.ids @@ -396,8 +396,20 @@ 743F, CC, AMD Radeon 6550S 743F, CF, AMD Radeon RX 6300M 743F, D7, AMD Radeon RX 6400 +7448, 00, AMD Radeon Pro W7900 744C, C8, AMD Radeon RX 7900 XTX 744C, CC, AMD Radeon RX 7900 XT +744C, CE, AMD Radeon RX 7900 GRE +745E, CC, AMD Radeon Pro W7800 +747E, C8, AMD Radeon RX 7800 XT +747E, FF, AMD Radeon RX 7700 XT +7480, 00, AMD Radeon Pro W7600 +7480, C1, AMD Radeon RX 7700S +7480, C3, AMD Radeon RX 7600S +7480, C7, AMD Radeon RX 7600M XT +7480, CF, AMD Radeon RX 7600 +7483, CF, AMD Radeon RX 7600M +7489, 00, AMD Radeon Pro W7500 9830, 00, AMD Radeon HD 8400 / R3 Series 9831, 00, AMD Radeon HD 8400E 9832, 00, AMD Radeon HD 8330 diff --git a/lib/libdrm/etnaviv/meson.build b/lib/libdrm/etnaviv/meson.build index 591f20f0..9ccf8696 100644 --- a/lib/libdrm/etnaviv/meson.build +++ b/lib/libdrm/etnaviv/meson.build @@ -32,7 +32,7 @@ libdrm_etnaviv = library( link_with : libdrm, c_args : libdrm_c_args, gnu_symbol_visibility : 'hidden', - dependencies : [dep_pthread_stubs, dep_rt, dep_atomic_ops], + dependencies : [dep_threads, dep_rt, dep_atomic_ops], version : '1.0.0', install : true, ) diff --git a/lib/libdrm/exynos/meson.build b/lib/libdrm/exynos/meson.build index 2f02ae71..6b4fe1e9 100644 --- a/lib/libdrm/exynos/meson.build +++ b/lib/libdrm/exynos/meson.build @@ -25,7 +25,7 @@ libdrm_exynos = library( gnu_symbol_visibility : 'hidden', include_directories : [inc_root, inc_drm], link_with : libdrm, - dependencies : [dep_pthread_stubs], + dependencies : [dep_threads], version : '1.0.0', install : true, ) diff --git a/lib/libdrm/freedreno/meson.build b/lib/libdrm/freedreno/meson.build index de9ee148..5ba1a3f1 100644 --- a/lib/libdrm/freedreno/meson.build +++ b/lib/libdrm/freedreno/meson.build @@ -44,7 +44,7 @@ libdrm_freedreno = library( [files_freedreno, config_file], c_args : libdrm_c_args, include_directories : [inc_root, inc_drm], - dependencies : [dep_valgrind, dep_pthread_stubs, dep_rt, dep_atomic_ops], + dependencies : [dep_valgrind, dep_threads, dep_rt, dep_atomic_ops], link_with : libdrm, version : '1.0.0', install : true, diff --git a/lib/libdrm/generated/generated_static_table_fourcc.h b/lib/libdrm/generated/generated_static_table_fourcc.h index 7e795a8b..468b84e2 100644 --- a/lib/libdrm/generated/generated_static_table_fourcc.h +++ b/lib/libdrm/generated/generated_static_table_fourcc.h @@ -15,6 +15,9 @@ static const struct drmFormatModifierInfo drm_format_modifier_table[] = { { DRM_MODIFIER_INTEL(4_TILED_DG2_RC_CCS, 4_TILED_DG2_RC_CCS) }, { DRM_MODIFIER_INTEL(4_TILED_DG2_MC_CCS, 4_TILED_DG2_MC_CCS) }, { DRM_MODIFIER_INTEL(4_TILED_DG2_RC_CCS_CC, 4_TILED_DG2_RC_CCS_CC) }, + { DRM_MODIFIER_INTEL(4_TILED_MTL_RC_CCS, 4_TILED_MTL_RC_CCS) }, + { DRM_MODIFIER_INTEL(4_TILED_MTL_MC_CCS, 4_TILED_MTL_MC_CCS) }, + { DRM_MODIFIER_INTEL(4_TILED_MTL_RC_CCS_CC, 4_TILED_MTL_RC_CCS_CC) }, { DRM_MODIFIER(SAMSUNG, 64_32_TILE, 64_32_TILE) }, { DRM_MODIFIER(SAMSUNG, 16_16_TILE, 16_16_TILE) }, { DRM_MODIFIER(QCOM, COMPRESSED, COMPRESSED) }, diff --git a/lib/libdrm/include/drm/amdgpu_drm.h b/lib/libdrm/include/drm/amdgpu_drm.h index c0a0ad10..ad21c613 100644 --- a/lib/libdrm/include/drm/amdgpu_drm.h +++ b/lib/libdrm/include/drm/amdgpu_drm.h @@ -94,6 +94,9 @@ extern "C" { * * %AMDGPU_GEM_DOMAIN_OA Ordered append, used by 3D or Compute engines * for appending data. + * + * %AMDGPU_GEM_DOMAIN_DOORBELL Doorbell. It is an MMIO region for + * signalling user mode queues. */ #define AMDGPU_GEM_DOMAIN_CPU 0x1 #define AMDGPU_GEM_DOMAIN_GTT 0x2 @@ -101,12 +104,14 @@ extern "C" { #define AMDGPU_GEM_DOMAIN_GDS 0x8 #define AMDGPU_GEM_DOMAIN_GWS 0x10 #define AMDGPU_GEM_DOMAIN_OA 0x20 +#define AMDGPU_GEM_DOMAIN_DOORBELL 0x40 #define AMDGPU_GEM_DOMAIN_MASK (AMDGPU_GEM_DOMAIN_CPU | \ AMDGPU_GEM_DOMAIN_GTT | \ AMDGPU_GEM_DOMAIN_VRAM | \ AMDGPU_GEM_DOMAIN_GDS | \ AMDGPU_GEM_DOMAIN_GWS | \ - AMDGPU_GEM_DOMAIN_OA) + AMDGPU_GEM_DOMAIN_OA | \ + AMDGPU_GEM_DOMAIN_DOORBELL) /* Flag that CPU access will be required for the case of VRAM domain */ #define AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED (1 << 0) @@ -140,6 +145,32 @@ extern "C" { * not require GTT memory accounting */ #define AMDGPU_GEM_CREATE_PREEMPTIBLE (1 << 11) +/* Flag that BO can be discarded under memory pressure without keeping the + * content. + */ +#define AMDGPU_GEM_CREATE_DISCARDABLE (1 << 12) +/* Flag that BO is shared coherently between multiple devices or CPU threads. + * May depend on GPU instructions to flush caches to system scope explicitly. + * + * This influences the choice of MTYPE in the PTEs on GFXv9 and later GPUs and + * may override the MTYPE selected in AMDGPU_VA_OP_MAP. + */ +#define AMDGPU_GEM_CREATE_COHERENT (1 << 13) +/* Flag that BO should not be cached by GPU. Coherent without having to flush + * GPU caches explicitly + * + * This influences the choice of MTYPE in the PTEs on GFXv9 and later GPUs and + * may override the MTYPE selected in AMDGPU_VA_OP_MAP. + */ +#define AMDGPU_GEM_CREATE_UNCACHED (1 << 14) +/* Flag that BO should be coherent across devices when using device-level + * atomics. May depend on GPU instructions to flush caches to device scope + * explicitly, promoting them to system scope automatically. + * + * This influences the choice of MTYPE in the PTEs on GFXv9 and later GPUs and + * may override the MTYPE selected in AMDGPU_VA_OP_MAP. + */ +#define AMDGPU_GEM_CREATE_EXT_COHERENT (1 << 15) struct drm_amdgpu_gem_create_in { /** the requested memory size */ @@ -218,15 +249,17 @@ union drm_amdgpu_bo_list { /* unknown cause */ #define AMDGPU_CTX_UNKNOWN_RESET 3 -/* indicate gpu reset occured after ctx created */ +/* indicate gpu reset occurred after ctx created */ #define AMDGPU_CTX_QUERY2_FLAGS_RESET (1<<0) -/* indicate vram lost occured after ctx created */ +/* indicate vram lost occurred after ctx created */ #define AMDGPU_CTX_QUERY2_FLAGS_VRAMLOST (1<<1) /* indicate some job from this context once cause gpu hang */ #define AMDGPU_CTX_QUERY2_FLAGS_GUILTY (1<<2) /* indicate some errors are detected by RAS */ #define AMDGPU_CTX_QUERY2_FLAGS_RAS_CE (1<<3) #define AMDGPU_CTX_QUERY2_FLAGS_RAS_UE (1<<4) +/* indicate that the reset hasn't completed yet */ +#define AMDGPU_CTX_QUERY2_FLAGS_RESET_IN_PROGRESS (1<<5) /* Context priority level */ #define AMDGPU_CTX_PRIORITY_UNSET -2048 @@ -529,6 +562,8 @@ struct drm_amdgpu_gem_op { #define AMDGPU_VM_MTYPE_UC (4 << 5) /* Use Read Write MTYPE instead of default MTYPE */ #define AMDGPU_VM_MTYPE_RW (5 << 5) +/* don't allocate MALL */ +#define AMDGPU_VM_PAGE_NOALLOC (1 << 9) struct drm_amdgpu_gem_va { /** GEM object handle */ @@ -559,7 +594,8 @@ struct drm_amdgpu_gem_va { */ #define AMDGPU_HW_IP_VCN_ENC 7 #define AMDGPU_HW_IP_VCN_JPEG 8 -#define AMDGPU_HW_IP_NUM 9 +#define AMDGPU_HW_IP_VPE 9 +#define AMDGPU_HW_IP_NUM 10 #define AMDGPU_HW_IP_INSTANCE_MAX_COUNT 1 @@ -572,6 +608,7 @@ struct drm_amdgpu_gem_va { #define AMDGPU_CHUNK_ID_SCHEDULED_DEPENDENCIES 0x07 #define AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_WAIT 0x08 #define AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_SIGNAL 0x09 +#define AMDGPU_CHUNK_ID_CP_GFX_SHADOW 0x0a struct drm_amdgpu_cs_chunk { __u32 chunk_id; @@ -688,6 +725,15 @@ struct drm_amdgpu_cs_chunk_data { }; }; +#define AMDGPU_CS_CHUNK_CP_GFX_SHADOW_FLAGS_INIT_SHADOW 0x1 + +struct drm_amdgpu_cs_chunk_cp_gfx_shadow { + __u64 shadow_va; + __u64 csa_va; + __u64 gds_va; + __u64 flags; +}; + /* * Query h/w info: Flag that this is integrated (a.h.a. fusion) GPU * @@ -695,6 +741,7 @@ struct drm_amdgpu_cs_chunk_data { #define AMDGPU_IDS_FLAGS_FUSION 0x1 #define AMDGPU_IDS_FLAGS_PREEMPTION 0x2 #define AMDGPU_IDS_FLAGS_TMZ 0x4 +#define AMDGPU_IDS_FLAGS_CONFORMANT_TRUNC_COORD 0x8 /* indicate if acceleration can be working */ #define AMDGPU_INFO_ACCEL_WORKING 0x00 @@ -747,6 +794,20 @@ struct drm_amdgpu_cs_chunk_data { #define AMDGPU_INFO_FW_DMCUB 0x14 /* Subquery id: Query TOC firmware version */ #define AMDGPU_INFO_FW_TOC 0x15 + /* Subquery id: Query CAP firmware version */ + #define AMDGPU_INFO_FW_CAP 0x16 + /* Subquery id: Query GFX RLCP firmware version */ + #define AMDGPU_INFO_FW_GFX_RLCP 0x17 + /* Subquery id: Query GFX RLCV firmware version */ + #define AMDGPU_INFO_FW_GFX_RLCV 0x18 + /* Subquery id: Query MES_KIQ firmware version */ + #define AMDGPU_INFO_FW_MES_KIQ 0x19 + /* Subquery id: Query MES firmware version */ + #define AMDGPU_INFO_FW_MES 0x1a + /* Subquery id: Query IMU firmware version */ + #define AMDGPU_INFO_FW_IMU 0x1b + /* Subquery id: Query VPE firmware version */ + #define AMDGPU_INFO_FW_VPE 0x1c /* number of bytes moved for TTM migration */ #define AMDGPU_INFO_NUM_BYTES_MOVED 0x0f @@ -800,6 +861,10 @@ struct drm_amdgpu_cs_chunk_data { #define AMDGPU_INFO_SENSOR_STABLE_PSTATE_GFX_SCLK 0x8 /* Subquery id: Query GPU stable pstate memory clock */ #define AMDGPU_INFO_SENSOR_STABLE_PSTATE_GFX_MCLK 0x9 + /* Subquery id: Query GPU peak pstate shader clock */ + #define AMDGPU_INFO_SENSOR_PEAK_PSTATE_GFX_SCLK 0xa + /* Subquery id: Query GPU peak pstate memory clock */ + #define AMDGPU_INFO_SENSOR_PEAK_PSTATE_GFX_MCLK 0xb /* Number of VRAM page faults on CPU access. */ #define AMDGPU_INFO_NUM_VRAM_CPU_PAGE_FAULTS 0x1E #define AMDGPU_INFO_VRAM_LOST_COUNTER 0x1F @@ -839,6 +904,10 @@ struct drm_amdgpu_cs_chunk_data { #define AMDGPU_INFO_VIDEO_CAPS_DECODE 0 /* Subquery id: Encode */ #define AMDGPU_INFO_VIDEO_CAPS_ENCODE 1 +/* Query the max number of IBs per gang per submission */ +#define AMDGPU_INFO_MAX_IBS 0x22 +/* query last page fault info */ +#define AMDGPU_INFO_GPUVM_FAULT 0x23 #define AMDGPU_INFO_MMR_SE_INDEX_SHIFT 0 #define AMDGPU_INFO_MMR_SE_INDEX_MASK 0xff @@ -990,6 +1059,8 @@ struct drm_amdgpu_info_vbios { #define AMDGPU_VRAM_TYPE_DDR4 8 #define AMDGPU_VRAM_TYPE_GDDR6 9 #define AMDGPU_VRAM_TYPE_DDR5 10 +#define AMDGPU_VRAM_TYPE_LPDDR4 11 +#define AMDGPU_VRAM_TYPE_LPDDR5 12 struct drm_amdgpu_info_device { /** PCI Device ID */ @@ -1015,7 +1086,8 @@ struct drm_amdgpu_info_device { __u32 enabled_rb_pipes_mask; __u32 num_rb_pipes; __u32 num_hw_gfx_contexts; - __u32 _pad; + /* PCIe version (the smaller of the GPU and the CPU/motherboard) */ + __u32 pcie_gen; __u64 ids_flags; /** Starting virtual address for UMDs. */ __u64 virtual_address_offset; @@ -1062,7 +1134,8 @@ struct drm_amdgpu_info_device { __u32 gs_prim_buffer_depth; /* max gs wavefront per vgt*/ __u32 max_gs_waves_per_vgt; - __u32 _pad1; + /* PCIe number of lanes (the smaller of the GPU and the CPU/motherboard) */ + __u32 pcie_num_lanes; /* always on cu bitmap */ __u32 cu_ao_bitmap[4][4]; /** Starting high virtual address for UMDs. */ @@ -1073,6 +1146,26 @@ struct drm_amdgpu_info_device { __u32 pa_sc_tile_steering_override; /* disabled TCCs */ __u64 tcc_disabled_mask; + __u64 min_engine_clock; + __u64 min_memory_clock; + /* The following fields are only set on gfx11+, older chips set 0. */ + __u32 tcp_cache_size; /* AKA GL0, VMEM cache */ + __u32 num_sqc_per_wgp; + __u32 sqc_data_cache_size; /* AKA SMEM cache */ + __u32 sqc_inst_cache_size; + __u32 gl1c_cache_size; + __u32 gl2c_cache_size; + __u64 mall_size; /* AKA infinity cache */ + /* high 32 bits of the rb pipes mask */ + __u32 enabled_rb_pipes_mask_hi; + /* shadow area size for gfx11 */ + __u32 shadow_size; + /* shadow area base virtual alignment for gfx11 */ + __u32 shadow_alignment; + /* context save area size for gfx11 */ + __u32 csa_size; + /* context save area base virtual alignment for gfx11 */ + __u32 csa_alignment; }; struct drm_amdgpu_info_hw_ip { @@ -1087,7 +1180,8 @@ struct drm_amdgpu_info_hw_ip { __u32 ib_size_alignment; /** Bitmask of available rings. Bit 0 means ring 0, etc. */ __u32 available_rings; - __u32 _pad; + /** version info: bits 23:16 major, 15:8 minor, 7:0 revision */ + __u32 ip_discovery_version; }; struct drm_amdgpu_info_num_handles { @@ -1139,6 +1233,20 @@ struct drm_amdgpu_info_video_caps { struct drm_amdgpu_info_video_codec_info codec_info[AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_COUNT]; }; +#define AMDGPU_VMHUB_TYPE_MASK 0xff +#define AMDGPU_VMHUB_TYPE_SHIFT 0 +#define AMDGPU_VMHUB_TYPE_GFX 0 +#define AMDGPU_VMHUB_TYPE_MM0 1 +#define AMDGPU_VMHUB_TYPE_MM1 2 +#define AMDGPU_VMHUB_IDX_MASK 0xff00 +#define AMDGPU_VMHUB_IDX_SHIFT 8 + +struct drm_amdgpu_info_gpuvm_fault { + __u64 addr; + __u32 status; + __u32 vmhub; +}; + /* * Supported GPU families */ @@ -1152,7 +1260,12 @@ struct drm_amdgpu_info_video_caps { #define AMDGPU_FAMILY_RV 142 /* Raven */ #define AMDGPU_FAMILY_NV 143 /* Navi10 */ #define AMDGPU_FAMILY_VGH 144 /* Van Gogh */ +#define AMDGPU_FAMILY_GC_11_0_0 145 /* GC 11.0.0 */ #define AMDGPU_FAMILY_YC 146 /* Yellow Carp */ +#define AMDGPU_FAMILY_GC_11_0_1 148 /* GC 11.0.1 */ +#define AMDGPU_FAMILY_GC_10_3_6 149 /* GC 10.3.6 */ +#define AMDGPU_FAMILY_GC_10_3_7 151 /* GC 10.3.7 */ +#define AMDGPU_FAMILY_GC_11_5_0 150 /* GC 11.5.0 */ #if defined(__cplusplus) } diff --git a/lib/libdrm/include/drm/drm.h b/lib/libdrm/include/drm/drm.h index 398c396f..4e4f7c2c 100644 --- a/lib/libdrm/include/drm/drm.h +++ b/lib/libdrm/include/drm/drm.h @@ -629,8 +629,8 @@ struct drm_gem_open { /** * DRM_CAP_VBLANK_HIGH_CRTC * - * If set to 1, the kernel supports specifying a CRTC index in the high bits of - * &drm_wait_vblank_request.type. + * If set to 1, the kernel supports specifying a :ref:`CRTC index` + * in the high bits of &drm_wait_vblank_request.type. * * Starting kernel version 2.6.39, this capability is always set to 1. */ @@ -667,8 +667,11 @@ struct drm_gem_open { * Bitfield of supported PRIME sharing capabilities. See &DRM_PRIME_CAP_IMPORT * and &DRM_PRIME_CAP_EXPORT. * - * PRIME buffers are exposed as dma-buf file descriptors. See - * Documentation/gpu/drm-mm.rst, section "PRIME Buffer Sharing". + * Starting from kernel version 6.6, both &DRM_PRIME_CAP_IMPORT and + * &DRM_PRIME_CAP_EXPORT are always advertised. + * + * PRIME buffers are exposed as dma-buf file descriptors. + * See :ref:`prime_buffer_sharing`. */ #define DRM_CAP_PRIME 0x5 /** @@ -676,6 +679,8 @@ struct drm_gem_open { * * If this bit is set in &DRM_CAP_PRIME, the driver supports importing PRIME * buffers via the &DRM_IOCTL_PRIME_FD_TO_HANDLE ioctl. + * + * Starting from kernel version 6.6, this bit is always set in &DRM_CAP_PRIME. */ #define DRM_PRIME_CAP_IMPORT 0x1 /** @@ -683,6 +688,8 @@ struct drm_gem_open { * * If this bit is set in &DRM_CAP_PRIME, the driver supports exporting PRIME * buffers via the &DRM_IOCTL_PRIME_HANDLE_TO_FD ioctl. + * + * Starting from kernel version 6.6, this bit is always set in &DRM_CAP_PRIME. */ #define DRM_PRIME_CAP_EXPORT 0x2 /** @@ -700,7 +707,8 @@ struct drm_gem_open { /** * DRM_CAP_ASYNC_PAGE_FLIP * - * If set to 1, the driver supports &DRM_MODE_PAGE_FLIP_ASYNC. + * If set to 1, the driver supports &DRM_MODE_PAGE_FLIP_ASYNC for legacy + * page-flips. */ #define DRM_CAP_ASYNC_PAGE_FLIP 0x7 /** @@ -750,17 +758,23 @@ struct drm_gem_open { /** * DRM_CAP_SYNCOBJ * - * If set to 1, the driver supports sync objects. See - * Documentation/gpu/drm-mm.rst, section "DRM Sync Objects". + * If set to 1, the driver supports sync objects. See :ref:`drm_sync_objects`. */ #define DRM_CAP_SYNCOBJ 0x13 /** * DRM_CAP_SYNCOBJ_TIMELINE * * If set to 1, the driver supports timeline operations on sync objects. See - * Documentation/gpu/drm-mm.rst, section "DRM Sync Objects". + * :ref:`drm_sync_objects`. */ #define DRM_CAP_SYNCOBJ_TIMELINE 0x14 +/** + * DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP + * + * If set to 1, the driver supports &DRM_MODE_PAGE_FLIP_ASYNC for atomic + * commits. + */ +#define DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP 0x15 /* DRM_IOCTL_GET_CAP ioctl argument type */ struct drm_get_cap { @@ -830,6 +844,31 @@ struct drm_get_cap { */ #define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS 5 +/** + * DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT + * + * Drivers for para-virtualized hardware (e.g. vmwgfx, qxl, virtio and + * virtualbox) have additional restrictions for cursor planes (thus + * making cursor planes on those drivers not truly universal,) e.g. + * they need cursor planes to act like one would expect from a mouse + * cursor and have correctly set hotspot properties. + * If this client cap is not set the DRM core will hide cursor plane on + * those virtualized drivers because not setting it implies that the + * client is not capable of dealing with those extra restictions. + * Clients which do set cursor hotspot and treat the cursor plane + * like a mouse cursor should set this property. + * The client must enable &DRM_CLIENT_CAP_ATOMIC first. + * + * Setting this property on drivers which do not special case + * cursor planes (i.e. non-virtualized drivers) will return + * EOPNOTSUPP, which can be used by userspace to gauge + * requirements of the hardware/drivers they're running on. + * + * This capability is always supported for atomic-capable virtualized + * drivers starting from kernel version 6.6. + */ +#define DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT 6 + /* DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ struct drm_set_client_cap { __u64 capability; @@ -881,6 +920,7 @@ struct drm_syncobj_transfer { #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0) #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1) #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2) /* wait for time point to become available */ +#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE (1 << 3) /* set fence deadline to deadline_nsec */ struct drm_syncobj_wait { __u64 handles; /* absolute timeout */ @@ -889,6 +929,14 @@ struct drm_syncobj_wait { __u32 flags; __u32 first_signaled; /* only valid when not waiting all */ __u32 pad; + /** + * @deadline_nsec - fence deadline hint + * + * Deadline hint, in absolute CLOCK_MONOTONIC, to set on backing + * fence(s) if the DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE flag is + * set. + */ + __u64 deadline_nsec; }; struct drm_syncobj_timeline_wait { @@ -901,6 +949,35 @@ struct drm_syncobj_timeline_wait { __u32 flags; __u32 first_signaled; /* only valid when not waiting all */ __u32 pad; + /** + * @deadline_nsec - fence deadline hint + * + * Deadline hint, in absolute CLOCK_MONOTONIC, to set on backing + * fence(s) if the DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE flag is + * set. + */ + __u64 deadline_nsec; +}; + +/** + * struct drm_syncobj_eventfd + * @handle: syncobj handle. + * @flags: Zero to wait for the point to be signalled, or + * &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE to wait for a fence to be + * available for the point. + * @point: syncobj timeline point (set to zero for binary syncobjs). + * @fd: Existing eventfd to sent events to. + * @pad: Must be zero. + * + * Register an eventfd to be signalled by a syncobj. The eventfd counter will + * be incremented by one. + */ +struct drm_syncobj_eventfd { + __u32 handle; + __u32 flags; + __u64 point; + __s32 fd; + __u32 pad; }; @@ -966,6 +1043,19 @@ extern "C" { #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) #define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) #define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) +/** + * DRM_IOCTL_GEM_CLOSE - Close a GEM handle. + * + * GEM handles are not reference-counted by the kernel. User-space is + * responsible for managing their lifetime. For example, if user-space imports + * the same memory object twice on the same DRM file description, the same GEM + * handle is returned by both imports, and user-space needs to ensure + * &DRM_IOCTL_GEM_CLOSE is performed once only. The same situation can happen + * when a memory object is allocated, then exported and imported again on the + * same DRM file description. The &DRM_IOCTL_MODE_GETFB2 IOCTL is an exception + * and always returns fresh new GEM handles even if an existing GEM handle + * already refers to the same memory object before the IOCTL is performed. + */ #define DRM_IOCTL_GEM_CLOSE DRM_IOW (0x09, struct drm_gem_close) #define DRM_IOCTL_GEM_FLINK DRM_IOWR(0x0a, struct drm_gem_flink) #define DRM_IOCTL_GEM_OPEN DRM_IOWR(0x0b, struct drm_gem_open) @@ -1006,7 +1096,37 @@ extern "C" { #define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, struct drm_lock) #define DRM_IOCTL_FINISH DRM_IOW( 0x2c, struct drm_lock) +/** + * DRM_IOCTL_PRIME_HANDLE_TO_FD - Convert a GEM handle to a DMA-BUF FD. + * + * User-space sets &drm_prime_handle.handle with the GEM handle to export and + * &drm_prime_handle.flags, and gets back a DMA-BUF file descriptor in + * &drm_prime_handle.fd. + * + * The export can fail for any driver-specific reason, e.g. because export is + * not supported for this specific GEM handle (but might be for others). + * + * Support for exporting DMA-BUFs is advertised via &DRM_PRIME_CAP_EXPORT. + */ #define DRM_IOCTL_PRIME_HANDLE_TO_FD DRM_IOWR(0x2d, struct drm_prime_handle) +/** + * DRM_IOCTL_PRIME_FD_TO_HANDLE - Convert a DMA-BUF FD to a GEM handle. + * + * User-space sets &drm_prime_handle.fd with a DMA-BUF file descriptor to + * import, and gets back a GEM handle in &drm_prime_handle.handle. + * &drm_prime_handle.flags is unused. + * + * If an existing GEM handle refers to the memory object backing the DMA-BUF, + * that GEM handle is returned. Therefore user-space which needs to handle + * arbitrary DMA-BUFs must have a user-space lookup data structure to manually + * reference-count duplicated GEM handles. For more information see + * &DRM_IOCTL_GEM_CLOSE. + * + * The import can fail for any driver-specific reason, e.g. because import is + * only supported for DMA-BUFs allocated on this DRM device. + * + * Support for importing DMA-BUFs is advertised via &DRM_PRIME_CAP_IMPORT. + */ #define DRM_IOCTL_PRIME_FD_TO_HANDLE DRM_IOWR(0x2e, struct drm_prime_handle) #define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30) @@ -1044,10 +1164,40 @@ extern "C" { #define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xAC, struct drm_mode_get_blob) #define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xAD, struct drm_mode_fb_cmd) #define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd) +/** + * DRM_IOCTL_MODE_RMFB - Remove a framebuffer. + * + * This removes a framebuffer previously added via ADDFB/ADDFB2. The IOCTL + * argument is a framebuffer object ID. + * + * Warning: removing a framebuffer currently in-use on an enabled plane will + * disable that plane. The CRTC the plane is linked to may also be disabled + * (depending on driver capabilities). + */ #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, unsigned int) #define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOWR(0xB0, struct drm_mode_crtc_page_flip) #define DRM_IOCTL_MODE_DIRTYFB DRM_IOWR(0xB1, struct drm_mode_fb_dirty_cmd) +/** + * DRM_IOCTL_MODE_CREATE_DUMB - Create a new dumb buffer object. + * + * KMS dumb buffers provide a very primitive way to allocate a buffer object + * suitable for scanout and map it for software rendering. KMS dumb buffers are + * not suitable for hardware-accelerated rendering nor video decoding. KMS dumb + * buffers are not suitable to be displayed on any other device than the KMS + * device where they were allocated from. Also see + * :ref:`kms_dumb_buffer_objects`. + * + * The IOCTL argument is a struct drm_mode_create_dumb. + * + * User-space is expected to create a KMS dumb buffer via this IOCTL, then add + * it as a KMS framebuffer via &DRM_IOCTL_MODE_ADDFB and map it via + * &DRM_IOCTL_MODE_MAP_DUMB. + * + * &DRM_CAP_DUMB_BUFFER indicates whether this IOCTL is supported. + * &DRM_CAP_DUMB_PREFERRED_DEPTH and &DRM_CAP_DUMB_PREFER_SHADOW indicate + * driver preferences for dumb buffers. + */ #define DRM_IOCTL_MODE_CREATE_DUMB DRM_IOWR(0xB2, struct drm_mode_create_dumb) #define DRM_IOCTL_MODE_MAP_DUMB DRM_IOWR(0xB3, struct drm_mode_map_dumb) #define DRM_IOCTL_MODE_DESTROY_DUMB DRM_IOWR(0xB4, struct drm_mode_destroy_dumb) @@ -1080,8 +1230,58 @@ extern "C" { #define DRM_IOCTL_SYNCOBJ_TRANSFER DRM_IOWR(0xCC, struct drm_syncobj_transfer) #define DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL DRM_IOWR(0xCD, struct drm_syncobj_timeline_array) +/** + * DRM_IOCTL_MODE_GETFB2 - Get framebuffer metadata. + * + * This queries metadata about a framebuffer. User-space fills + * &drm_mode_fb_cmd2.fb_id as the input, and the kernels fills the rest of the + * struct as the output. + * + * If the client is DRM master or has &CAP_SYS_ADMIN, &drm_mode_fb_cmd2.handles + * will be filled with GEM buffer handles. Fresh new GEM handles are always + * returned, even if another GEM handle referring to the same memory object + * already exists on the DRM file description. The caller is responsible for + * removing the new handles, e.g. via the &DRM_IOCTL_GEM_CLOSE IOCTL. The same + * new handle will be returned for multiple planes in case they use the same + * memory object. Planes are valid until one has a zero handle -- this can be + * used to compute the number of planes. + * + * Otherwise, &drm_mode_fb_cmd2.handles will be zeroed and planes are valid + * until one has a zero &drm_mode_fb_cmd2.pitches. + * + * If the framebuffer has a format modifier, &DRM_MODE_FB_MODIFIERS will be set + * in &drm_mode_fb_cmd2.flags and &drm_mode_fb_cmd2.modifier will contain the + * modifier. Otherwise, user-space must ignore &drm_mode_fb_cmd2.modifier. + * + * To obtain DMA-BUF FDs for each plane without leaking GEM handles, user-space + * can export each handle via &DRM_IOCTL_PRIME_HANDLE_TO_FD, then immediately + * close each unique handle via &DRM_IOCTL_GEM_CLOSE, making sure to not + * double-close handles which are specified multiple times in the array. + */ #define DRM_IOCTL_MODE_GETFB2 DRM_IOWR(0xCE, struct drm_mode_fb_cmd2) +#define DRM_IOCTL_SYNCOBJ_EVENTFD DRM_IOWR(0xCF, struct drm_syncobj_eventfd) + +/** + * DRM_IOCTL_MODE_CLOSEFB - Close a framebuffer. + * + * This closes a framebuffer previously added via ADDFB/ADDFB2. The IOCTL + * argument is a framebuffer object ID. + * + * This IOCTL is similar to &DRM_IOCTL_MODE_RMFB, except it doesn't disable + * planes and CRTCs. As long as the framebuffer is used by a plane, it's kept + * alive. When the plane no longer uses the framebuffer (because the + * framebuffer is replaced with another one, or the plane is disabled), the + * framebuffer is cleaned up. + * + * This is useful to implement flicker-free transitions between two processes. + * + * Depending on the threat model, user-space may want to ensure that the + * framebuffer doesn't expose any sensitive user information: closed + * framebuffers attached to a plane can be read back by the next DRM master. + */ +#define DRM_IOCTL_MODE_CLOSEFB DRM_IOWR(0xD0, struct drm_mode_closefb) + /* * Device specific ioctls should only be in their respective headers * The device specific ioctl range is from 0x40 to 0x9f. @@ -1093,25 +1293,50 @@ extern "C" { #define DRM_COMMAND_BASE 0x40 #define DRM_COMMAND_END 0xA0 -/* - * Header for events written back to userspace on the drm fd. The - * type defines the type of event, the length specifies the total - * length of the event (including the header), and user_data is - * typically a 64 bit value passed with the ioctl that triggered the - * event. A read on the drm fd will always only return complete - * events, that is, if for example the read buffer is 100 bytes, and - * there are two 64 byte events pending, only one will be returned. +/** + * struct drm_event - Header for DRM events + * @type: event type. + * @length: total number of payload bytes (including header). * - * Event types 0 - 0x7fffffff are generic drm events, 0x80000000 and - * up are chipset specific. + * This struct is a header for events written back to user-space on the DRM FD. + * A read on the DRM FD will always only return complete events: e.g. if the + * read buffer is 100 bytes large and there are two 64 byte events pending, + * only one will be returned. + * + * Event types 0 - 0x7fffffff are generic DRM events, 0x80000000 and + * up are chipset specific. Generic DRM events include &DRM_EVENT_VBLANK, + * &DRM_EVENT_FLIP_COMPLETE and &DRM_EVENT_CRTC_SEQUENCE. */ struct drm_event { __u32 type; __u32 length; }; +/** + * DRM_EVENT_VBLANK - vertical blanking event + * + * This event is sent in response to &DRM_IOCTL_WAIT_VBLANK with the + * &_DRM_VBLANK_EVENT flag set. + * + * The event payload is a struct drm_event_vblank. + */ #define DRM_EVENT_VBLANK 0x01 +/** + * DRM_EVENT_FLIP_COMPLETE - page-flip completion event + * + * This event is sent in response to an atomic commit or legacy page-flip with + * the &DRM_MODE_PAGE_FLIP_EVENT flag set. + * + * The event payload is a struct drm_event_vblank. + */ #define DRM_EVENT_FLIP_COMPLETE 0x02 +/** + * DRM_EVENT_CRTC_SEQUENCE - CRTC sequence event + * + * This event is sent in response to &DRM_IOCTL_CRTC_QUEUE_SEQUENCE. + * + * The event payload is a struct drm_event_crtc_sequence. + */ #define DRM_EVENT_CRTC_SEQUENCE 0x03 struct drm_event_vblank { diff --git a/lib/libdrm/include/drm/drm_fourcc.h b/lib/libdrm/include/drm/drm_fourcc.h index 0e70e36c..9b250480 100644 --- a/lib/libdrm/include/drm/drm_fourcc.h +++ b/lib/libdrm/include/drm/drm_fourcc.h @@ -88,6 +88,18 @@ extern "C" { * * The authoritative list of format modifier codes is found in * `include/uapi/drm/drm_fourcc.h` + * + * Open Source User Waiver + * ----------------------- + * + * Because this is the authoritative source for pixel formats and modifiers + * referenced by GL, Vulkan extensions and other standards and hence used both + * by open source and closed source driver stacks, the usual requirement for an + * upstream in-kernel or open source userspace user does not apply. + * + * To ensure, as much as feasible, compatibility across stacks and avoid + * confusion with incompatible enumerations stakeholders for all relevant driver + * stacks should approve additions. */ #define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \ @@ -311,6 +323,8 @@ extern "C" { * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian */ #define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV20 fourcc_code('N', 'V', '2', '0') /* 2x1 subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV30 fourcc_code('N', 'V', '3', '0') /* non-subsampled Cr:Cb plane */ /* * 2 plane YCbCr MSB aligned @@ -645,6 +659,49 @@ extern "C" { */ #define I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC fourcc_mod_code(INTEL, 12) +/* + * Intel Color Control Surfaces (CCS) for display ver. 14 render compression. + * + * The main surface is tile4 and at plane index 0, the CCS is linear and + * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in + * main surface. In other words, 4 bits in CCS map to a main surface cache + * line pair. The main surface pitch is required to be a multiple of four + * tile4 widths. + */ +#define I915_FORMAT_MOD_4_TILED_MTL_RC_CCS fourcc_mod_code(INTEL, 13) + +/* + * Intel Color Control Surfaces (CCS) for display ver. 14 media compression + * + * The main surface is tile4 and at plane index 0, the CCS is linear and + * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in + * main surface. In other words, 4 bits in CCS map to a main surface cache + * line pair. The main surface pitch is required to be a multiple of four + * tile4 widths. For semi-planar formats like NV12, CCS planes follow the + * Y and UV planes i.e., planes 0 and 1 are used for Y and UV surfaces, + * planes 2 and 3 for the respective CCS. + */ +#define I915_FORMAT_MOD_4_TILED_MTL_MC_CCS fourcc_mod_code(INTEL, 14) + +/* + * Intel Color Control Surface with Clear Color (CCS) for display ver. 14 render + * compression. + * + * The main surface is tile4 and is at plane index 0 whereas CCS is linear + * and at index 1. The clear color is stored at index 2, and the pitch should + * be ignored. The clear color structure is 256 bits. The first 128 bits + * represents Raw Clear Color Red, Green, Blue and Alpha color each represented + * by 32 bits. The raw clear color is consumed by the 3d engine and generates + * the converted clear color of size 64 bits. The first 32 bits store the Lower + * Converted Clear Color value and the next 32 bits store the Higher Converted + * Clear Color value when applicable. The Converted Clear Color values are + * consumed by the DE. The last 64 bits are used to store Color Discard Enable + * and Depth Clear Value Valid which are ignored by the DE. A CCS cache line + * corresponds to an area of 4x1 tiles in the main surface. The main surface + * pitch is required to be a multiple of 4 tile widths. + */ +#define I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC fourcc_mod_code(INTEL, 15) + /* * Tiled, NV12MT, grouped in 64 (pixels) x 32 (lines) -sized macroblocks * diff --git a/lib/libdrm/include/drm/drm_mode.h b/lib/libdrm/include/drm/drm_mode.h index 9b6722d4..95630f17 100644 --- a/lib/libdrm/include/drm/drm_mode.h +++ b/lib/libdrm/include/drm/drm_mode.h @@ -312,16 +312,48 @@ struct drm_mode_set_plane { __u32 src_w; }; +/** + * struct drm_mode_get_plane - Get plane metadata. + * + * Userspace can perform a GETPLANE ioctl to retrieve information about a + * plane. + * + * To retrieve the number of formats supported, set @count_format_types to zero + * and call the ioctl. @count_format_types will be updated with the value. + * + * To retrieve these formats, allocate an array with the memory needed to store + * @count_format_types formats. Point @format_type_ptr to this array and call + * the ioctl again (with @count_format_types still set to the value returned in + * the first ioctl call). + */ struct drm_mode_get_plane { + /** + * @plane_id: Object ID of the plane whose information should be + * retrieved. Set by caller. + */ __u32 plane_id; + /** @crtc_id: Object ID of the current CRTC. */ __u32 crtc_id; + /** @fb_id: Object ID of the current fb. */ __u32 fb_id; + /** + * @possible_crtcs: Bitmask of CRTC's compatible with the plane. CRTC's + * are created and they receive an index, which corresponds to their + * position in the bitmask. Bit N corresponds to + * :ref:`CRTC index` N. + */ __u32 possible_crtcs; + /** @gamma_size: Never used. */ __u32 gamma_size; + /** @count_format_types: Number of formats. */ __u32 count_format_types; + /** + * @format_type_ptr: Pointer to ``__u32`` array of formats that are + * supported by the plane. These formats do not require modifiers. + */ __u64 format_type_ptr; }; @@ -456,6 +488,9 @@ struct drm_mode_get_connector { * This is not an object ID. This is a per-type connector number. Each * (type, type_id) combination is unique across all connectors of a DRM * device. + * + * The (type, type_id) combination is not a stable identifier: the + * type_id can change depending on the driver probe order. */ __u32 connector_type_id; @@ -509,22 +544,74 @@ struct drm_mode_get_connector { */ #define DRM_MODE_PROP_ATOMIC 0x80000000 +/** + * struct drm_mode_property_enum - Description for an enum/bitfield entry. + * @value: numeric value for this enum entry. + * @name: symbolic name for this enum entry. + * + * See struct drm_property_enum for details. + */ struct drm_mode_property_enum { __u64 value; char name[DRM_PROP_NAME_LEN]; }; +/** + * struct drm_mode_get_property - Get property metadata. + * + * User-space can perform a GETPROPERTY ioctl to retrieve information about a + * property. The same property may be attached to multiple objects, see + * "Modeset Base Object Abstraction". + * + * The meaning of the @values_ptr field changes depending on the property type. + * See &drm_property.flags for more details. + * + * The @enum_blob_ptr and @count_enum_blobs fields are only meaningful when the + * property has the type &DRM_MODE_PROP_ENUM or &DRM_MODE_PROP_BITMASK. For + * backwards compatibility, the kernel will always set @count_enum_blobs to + * zero when the property has the type &DRM_MODE_PROP_BLOB. User-space must + * ignore these two fields if the property has a different type. + * + * User-space is expected to retrieve values and enums by performing this ioctl + * at least twice: the first time to retrieve the number of elements, the + * second time to retrieve the elements themselves. + * + * To retrieve the number of elements, set @count_values and @count_enum_blobs + * to zero, then call the ioctl. @count_values will be updated with the number + * of elements. If the property has the type &DRM_MODE_PROP_ENUM or + * &DRM_MODE_PROP_BITMASK, @count_enum_blobs will be updated as well. + * + * To retrieve the elements themselves, allocate an array for @values_ptr and + * set @count_values to its capacity. If the property has the type + * &DRM_MODE_PROP_ENUM or &DRM_MODE_PROP_BITMASK, allocate an array for + * @enum_blob_ptr and set @count_enum_blobs to its capacity. Calling the ioctl + * again will fill the arrays. + */ struct drm_mode_get_property { - __u64 values_ptr; /* values and blob lengths */ - __u64 enum_blob_ptr; /* enum and blob id ptrs */ + /** @values_ptr: Pointer to a ``__u64`` array. */ + __u64 values_ptr; + /** @enum_blob_ptr: Pointer to a struct drm_mode_property_enum array. */ + __u64 enum_blob_ptr; + /** + * @prop_id: Object ID of the property which should be retrieved. Set + * by the caller. + */ __u32 prop_id; + /** + * @flags: ``DRM_MODE_PROP_*`` bitfield. See &drm_property.flags for + * a definition of the flags. + */ __u32 flags; + /** + * @name: Symbolic property name. User-space should use this field to + * recognize properties. + */ char name[DRM_PROP_NAME_LEN]; + /** @count_values: Number of elements in @values_ptr. */ __u32 count_values; - /* This is only used to count enum values, not blobs. The _blobs is - * simply because of a historical reason, i.e. backwards compat. */ + /** @count_enum_blobs: Number of elements in @enum_blob_ptr. */ __u32 count_enum_blobs; }; @@ -579,41 +666,73 @@ struct drm_mode_fb_cmd { #define DRM_MODE_FB_INTERLACED (1<<0) /* for interlaced framebuffers */ #define DRM_MODE_FB_MODIFIERS (1<<1) /* enables ->modifer[] */ +/** + * struct drm_mode_fb_cmd2 - Frame-buffer metadata. + * + * This struct holds frame-buffer metadata. There are two ways to use it: + * + * - User-space can fill this struct and perform a &DRM_IOCTL_MODE_ADDFB2 + * ioctl to register a new frame-buffer. The new frame-buffer object ID will + * be set by the kernel in @fb_id. + * - User-space can set @fb_id and perform a &DRM_IOCTL_MODE_GETFB2 ioctl to + * fetch metadata about an existing frame-buffer. + * + * In case of planar formats, this struct allows up to 4 buffer objects with + * offsets and pitches per plane. The pitch and offset order are dictated by + * the format FourCC as defined by ``drm_fourcc.h``, e.g. NV12 is described as: + * + * YUV 4:2:0 image with a plane of 8-bit Y samples followed by an + * interleaved U/V plane containing 8-bit 2x2 subsampled colour difference + * samples. + * + * So it would consist of a Y plane at ``offsets[0]`` and a UV plane at + * ``offsets[1]``. + * + * To accommodate tiled, compressed, etc formats, a modifier can be specified. + * For more information see the "Format Modifiers" section. Note that even + * though it looks like we have a modifier per-plane, we in fact do not. The + * modifier for each plane must be identical. Thus all combinations of + * different data layouts for multi-plane formats must be enumerated as + * separate modifiers. + * + * All of the entries in @handles, @pitches, @offsets and @modifier must be + * zero when unused. Warning, for @offsets and @modifier zero can't be used to + * figure out whether the entry is used or not since it's a valid value (a zero + * offset is common, and a zero modifier is &DRM_FORMAT_MOD_LINEAR). + */ struct drm_mode_fb_cmd2 { + /** @fb_id: Object ID of the frame-buffer. */ __u32 fb_id; + /** @width: Width of the frame-buffer. */ __u32 width; + /** @height: Height of the frame-buffer. */ __u32 height; - __u32 pixel_format; /* fourcc code from drm_fourcc.h */ - __u32 flags; /* see above flags */ + /** + * @pixel_format: FourCC format code, see ``DRM_FORMAT_*`` constants in + * ``drm_fourcc.h``. + */ + __u32 pixel_format; + /** + * @flags: Frame-buffer flags (see &DRM_MODE_FB_INTERLACED and + * &DRM_MODE_FB_MODIFIERS). + */ + __u32 flags; - /* - * In case of planar formats, this ioctl allows up to 4 - * buffer objects with offsets and pitches per plane. - * The pitch and offset order is dictated by the fourcc, - * e.g. NV12 (https://fourcc.org/yuv.php#NV12) is described as: - * - * YUV 4:2:0 image with a plane of 8 bit Y samples - * followed by an interleaved U/V plane containing - * 8 bit 2x2 subsampled colour difference samples. - * - * So it would consist of Y as offsets[0] and UV as - * offsets[1]. Note that offsets[0] will generally - * be 0 (but this is not required). - * - * To accommodate tiled, compressed, etc formats, a - * modifier can be specified. The default value of zero - * indicates "native" format as specified by the fourcc. - * Vendor specific modifier token. Note that even though - * it looks like we have a modifier per-plane, we in fact - * do not. The modifier for each plane must be identical. - * Thus all combinations of different data layouts for - * multi plane formats must be enumerated as separate - * modifiers. + /** + * @handles: GEM buffer handle, one per plane. Set to 0 if the plane is + * unused. The same handle can be used for multiple planes. */ __u32 handles[4]; - __u32 pitches[4]; /* pitch for each plane */ - __u32 offsets[4]; /* offset of each plane */ - __u64 modifier[4]; /* ie, tiling, compress */ + /** @pitches: Pitch (aka. stride) in bytes, one per plane. */ + __u32 pitches[4]; + /** @offsets: Offset into the buffer in bytes, one per plane. */ + __u32 offsets[4]; + /** + * @modifier: Format modifier, one per plane. See ``DRM_FORMAT_MOD_*`` + * constants in ``drm_fourcc.h``. All planes must use the same + * modifier. Ignored unless &DRM_MODE_FB_MODIFIERS is set in @flags. + */ + __u64 modifier[4]; }; #define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01 @@ -718,6 +837,11 @@ struct drm_color_ctm { /* * Conversion matrix in S31.32 sign-magnitude * (not two's complement!) format. + * + * out matrix in + * |R| |0 1 2| |R| + * |G| = |3 4 5| x |G| + * |B| |6 7 8| |B| */ __u64 matrix[9]; }; @@ -762,7 +886,7 @@ struct hdr_metadata_infoframe { */ struct { __u16 x, y; - } display_primaries[3]; + } display_primaries[3]; /** * @white_point: White Point of Colorspace Data. * These are coded as unsigned 16-bit values in units of @@ -773,7 +897,7 @@ struct hdr_metadata_infoframe { */ struct { __u16 x, y; - } white_point; + } white_point; /** * @max_display_mastering_luminance: Max Mastering Display Luminance. * This value is coded as an unsigned 16-bit value in units of 1 cd/m2, @@ -819,12 +943,40 @@ struct hdr_output_metadata { }; }; +/** + * DRM_MODE_PAGE_FLIP_EVENT + * + * Request that the kernel sends back a vblank event (see + * struct drm_event_vblank) with the &DRM_EVENT_FLIP_COMPLETE type when the + * page-flip is done. + */ #define DRM_MODE_PAGE_FLIP_EVENT 0x01 +/** + * DRM_MODE_PAGE_FLIP_ASYNC + * + * Request that the page-flip is performed as soon as possible, ie. with no + * delay due to waiting for vblank. This may cause tearing to be visible on + * the screen. + * + * When used with atomic uAPI, the driver will return an error if the hardware + * doesn't support performing an asynchronous page-flip for this update. + * User-space should handle this, e.g. by falling back to a regular page-flip. + * + * Note, some hardware might need to perform one last synchronous page-flip + * before being able to switch to asynchronous page-flips. As an exception, + * the driver will return success even though that first page-flip is not + * asynchronous. + */ #define DRM_MODE_PAGE_FLIP_ASYNC 0x02 #define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4 #define DRM_MODE_PAGE_FLIP_TARGET_RELATIVE 0x8 #define DRM_MODE_PAGE_FLIP_TARGET (DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE | \ DRM_MODE_PAGE_FLIP_TARGET_RELATIVE) +/** + * DRM_MODE_PAGE_FLIP_FLAGS + * + * Bitmask of flags suitable for &drm_mode_crtc_page_flip_target.flags. + */ #define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT | \ DRM_MODE_PAGE_FLIP_ASYNC | \ DRM_MODE_PAGE_FLIP_TARGET) @@ -889,13 +1041,25 @@ struct drm_mode_crtc_page_flip_target { __u64 user_data; }; -/* create a dumb scanout buffer */ +/** + * struct drm_mode_create_dumb - Create a KMS dumb buffer for scanout. + * @height: buffer height in pixels + * @width: buffer width in pixels + * @bpp: bits per pixel + * @flags: must be zero + * @handle: buffer object handle + * @pitch: number of bytes between two consecutive lines + * @size: size of the whole buffer in bytes + * + * User-space fills @height, @width, @bpp and @flags. If the IOCTL succeeds, + * the kernel fills @handle, @pitch and @size. + */ struct drm_mode_create_dumb { __u32 height; __u32 width; __u32 bpp; __u32 flags; - /* handle, pitch, size will be returned */ + __u32 handle; __u32 pitch; __u64 size; @@ -918,11 +1082,53 @@ struct drm_mode_destroy_dumb { __u32 handle; }; -/* page-flip flags are valid, plus: */ +/** + * DRM_MODE_ATOMIC_TEST_ONLY + * + * Do not apply the atomic commit, instead check whether the hardware supports + * this configuration. + * + * See &drm_mode_config_funcs.atomic_check for more details on test-only + * commits. + */ #define DRM_MODE_ATOMIC_TEST_ONLY 0x0100 +/** + * DRM_MODE_ATOMIC_NONBLOCK + * + * Do not block while applying the atomic commit. The &DRM_IOCTL_MODE_ATOMIC + * IOCTL returns immediately instead of waiting for the changes to be applied + * in hardware. Note, the driver will still check that the update can be + * applied before retuning. + */ #define DRM_MODE_ATOMIC_NONBLOCK 0x0200 +/** + * DRM_MODE_ATOMIC_ALLOW_MODESET + * + * Allow the update to result in temporary or transient visible artifacts while + * the update is being applied. Applying the update may also take significantly + * more time than a page flip. All visual artifacts will disappear by the time + * the update is completed, as signalled through the vblank event's timestamp + * (see struct drm_event_vblank). + * + * This flag must be set when the KMS update might cause visible artifacts. + * Without this flag such KMS update will return a EINVAL error. What kind of + * update may cause visible artifacts depends on the driver and the hardware. + * User-space that needs to know beforehand if an update might cause visible + * artifacts can use &DRM_MODE_ATOMIC_TEST_ONLY without + * &DRM_MODE_ATOMIC_ALLOW_MODESET to see if it fails. + * + * To the best of the driver's knowledge, visual artifacts are guaranteed to + * not appear when this flag is not set. Some sinks might display visual + * artifacts outside of the driver's control. + */ #define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400 +/** + * DRM_MODE_ATOMIC_FLAGS + * + * Bitfield of flags accepted by the &DRM_IOCTL_MODE_ATOMIC IOCTL in + * &drm_mode_atomic.flags. + */ #define DRM_MODE_ATOMIC_FLAGS (\ DRM_MODE_PAGE_FLIP_EVENT |\ DRM_MODE_PAGE_FLIP_ASYNC |\ @@ -1026,6 +1232,10 @@ struct drm_mode_destroy_blob { * struct drm_mode_create_lease - Create lease * * Lease mode resources, creating another drm_master. + * + * The @object_ids array must reference at least one CRTC, one connector and + * one plane if &DRM_CLIENT_CAP_UNIVERSAL_PLANES is enabled. Alternatively, + * the lease can be completely empty. */ struct drm_mode_create_lease { /** @object_ids: Pointer to array of object ids (__u32) */ @@ -1122,6 +1332,16 @@ struct drm_mode_rect { __s32 y2; }; +/** + * struct drm_mode_closefb + * @fb_id: Framebuffer ID. + * @pad: Must be zero. + */ +struct drm_mode_closefb { + __u32 fb_id; + __u32 pad; +}; + #if defined(__cplusplus) } #endif diff --git a/lib/libdrm/intel/meson.build b/lib/libdrm/intel/meson.build index beea42a6..4af2a357 100644 --- a/lib/libdrm/intel/meson.build +++ b/lib/libdrm/intel/meson.build @@ -29,7 +29,7 @@ libdrm_intel = library( ], include_directories : [inc_root, inc_drm], link_with : libdrm, - dependencies : [dep_pciaccess, dep_pthread_stubs, dep_rt, dep_valgrind, dep_atomic_ops], + dependencies : [dep_pciaccess, dep_threads, dep_rt, dep_valgrind, dep_atomic_ops], c_args : libdrm_c_args, gnu_symbol_visibility : 'hidden', version : '1.0.0', diff --git a/lib/libdrm/intel/uthash.h b/lib/libdrm/intel/uthash.h index 45d1f9fc..62e16508 100644 --- a/lib/libdrm/intel/uthash.h +++ b/lib/libdrm/intel/uthash.h @@ -648,11 +648,11 @@ do { #define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL) #define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL) #define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) -#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#ifdef HAVE_BIG_ENDIAN #define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) -#else /* assume little endian non-intel */ +#else /* little endian non-intel */ #define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) diff --git a/lib/libdrm/meson.build b/lib/libdrm/meson.build index 8dcacb94..1a7dbbe4 100644 --- a/lib/libdrm/meson.build +++ b/lib/libdrm/meson.build @@ -21,9 +21,9 @@ project( 'libdrm', ['c'], - version : '2.4.115', + version : '2.4.120', license : 'MIT', - meson_version : '>= 0.53', + meson_version : '>= 0.59', default_options : ['buildtype=debugoptimized', 'c_std=c11'], ) @@ -40,11 +40,6 @@ with_freedreno_kgsl = get_option('freedreno-kgsl') with_install_tests = get_option('install-test-programs') with_tests = get_option('tests') -if ['freebsd', 'dragonfly', 'netbsd'].contains(host_machine.system()) - dep_pthread_stubs = dependency('pthread-stubs', version : '>= 0.4') -else - dep_pthread_stubs = [] -endif dep_threads = dependency('threads') cc = meson.get_compiler('c') @@ -89,109 +84,61 @@ config.set10('HAVE_LIB_ATOMIC_OPS', lib_atomics) dep_pciaccess = dependency('pciaccess', version : '>= 0.10', required : get_option('intel')) -with_intel = false -_intel = get_option('intel') -if not _intel.disabled() - if _intel.enabled() and not with_atomics - error('libdrm_intel requires atomics.') - else - with_intel = (_intel.enabled() or host_machine.cpu_family().startswith('x86')) and with_atomics and dep_pciaccess.found() - endif -endif +with_intel = get_option('intel') \ + .require(with_atomics, error_message : 'libdrm_intel requires atomics') \ + .require(dep_pciaccess.found(), error_message : 'libdrm_intel requires libpciaccess') \ + .disable_auto_if(not host_machine.cpu_family().startswith('x86')) \ + .allowed() summary('Intel', with_intel) -with_radeon = false -_radeon = get_option('radeon') -if not _radeon.disabled() - if _radeon.enabled() and not with_atomics - error('libdrm_radeon requires atomics.') - endif - with_radeon = with_atomics -endif +with_radeon = get_option('radeon') \ + .require(with_atomics, error_message : 'libdrm_radeon requires atomics') \ + .allowed() summary('Radeon', with_radeon) -with_amdgpu = false -_amdgpu = get_option('amdgpu') -if not _amdgpu.disabled() - if _amdgpu.enabled() and not with_atomics - error('libdrm_amdgpu requires atomics.') - endif - with_amdgpu = with_atomics -endif +with_amdgpu = get_option('amdgpu') \ + .require(with_atomics, error_message : 'libdrm_amdgpu requires atomics') \ + .allowed() summary('AMDGPU', with_amdgpu) -with_nouveau = false -_nouveau = get_option('nouveau') -if not _nouveau.disabled() - if _nouveau.enabled() and not with_atomics - error('libdrm_nouveau requires atomics.') - endif - with_nouveau = with_atomics -endif +with_nouveau = get_option('nouveau') \ + .require(with_atomics, error_message : 'libdrm_nouveau requires atomics') \ + .allowed() summary('Nouveau', with_nouveau) -with_vmwgfx = false -_vmwgfx = get_option('vmwgfx') -if not _vmwgfx.disabled() - with_vmwgfx = true -endif +with_vmwgfx = get_option('vmwgfx').allowed() summary('vmwgfx', with_vmwgfx) -with_omap = false -_omap = get_option('omap') -if _omap.enabled() - if not with_atomics - error('libdrm_omap requires atomics.') - endif - with_omap = true -endif +with_omap = get_option('omap') \ + .require(with_atomics, error_message : 'libdrm_omap requires atomics') \ + .enabled() summary('OMAP', with_omap) -with_freedreno = false -_freedreno = get_option('freedreno') -if not _freedreno.disabled() - if _freedreno.enabled() and not with_atomics - error('libdrm_freedreno requires atomics.') - else - with_freedreno = (_freedreno.enabled() or ['arm', 'aarch64'].contains(host_machine.cpu_family())) and with_atomics - endif -endif +with_freedreno = get_option('freedreno') \ + .require(with_atomics, error_message : 'libdrm_freedreno requires atomics') \ + .disable_auto_if(not ['arm', 'aarch64'].contains(host_machine.cpu_family())) \ + .allowed() summary('Freedreno', with_freedreno) summary('Freedreon-kgsl', with_freedreno_kgsl) -with_tegra = false -_tegra = get_option('tegra') -if _tegra.enabled() - if not with_atomics - error('libdrm_tegra requires atomics.') - endif - with_tegra = true -endif +with_tegra = get_option('tegra') \ + .require(with_atomics, error_message : 'libdrm_tegra requires atomics') \ + .disable_auto_if(not ['arm', 'aarch64'].contains(host_machine.cpu_family())) \ + .enabled() summary('Tegra', with_tegra) -with_etnaviv = false -_etnaviv = get_option('etnaviv') -if not _etnaviv.disabled() - if _etnaviv.enabled() and not with_atomics - error('libdrm_etnaviv requires atomics.') - endif - with_etnaviv = _etnaviv.enabled() or ( - with_atomics and [ - 'loongarch64', 'mips', 'mips64', - 'arm', 'aarch64', 'arc', - ].contains(host_machine.cpu_family()) - ) -endif +with_etnaviv = get_option('etnaviv') \ + .require(with_atomics, error_message : 'libdrm_etnaviv requires atomics') \ + .disable_auto_if(not ['arm', 'aarch64', 'arc', 'mips', 'mips64', 'loongarch64'].contains(host_machine.cpu_family())) \ + .allowed() summary('Etnaviv', with_etnaviv) with_exynos = get_option('exynos').enabled() summary('EXYNOS', with_exynos) -with_vc4 = false -_vc4 = get_option('vc4') -if not _vc4.disabled() - with_vc4 = _vc4.enabled() or ['arm', 'aarch64'].contains(host_machine.cpu_family()) -endif +with_vc4 = get_option('vc4') \ + .disable_auto_if(not ['arm', 'aarch64'].contains(host_machine.cpu_family())) \ + .allowed() summary('VC4', with_vc4) # Among others FreeBSD does not have a separate dl library. @@ -279,6 +226,11 @@ if with_freedreno_kgsl and not with_freedreno error('cannot enable freedreno-kgsl without freedreno support') endif config.set10('_GNU_SOURCE', true) + +if target_machine.endian() == 'big' + config.set('HAVE_BIG_ENDIAN', 1) +endif + config_file = configure_file( configuration : config, output : 'config.h', @@ -319,7 +271,7 @@ test( args : [ '--lib', libdrm, '--symbols-file', files('core-symbols.txt'), - '--nm', prog_nm.path(), + '--nm', prog_nm.full_path(), ], ) diff --git a/lib/libdrm/mk/libdrm/shlib_version b/lib/libdrm/mk/libdrm/shlib_version index 14ead84e..f33cb8e7 100644 --- a/lib/libdrm/mk/libdrm/shlib_version +++ b/lib/libdrm/mk/libdrm/shlib_version @@ -1,2 +1,2 @@ major=7 -minor=12 +minor=13 diff --git a/lib/libdrm/mk/libdrm_amdgpu/shlib_version b/lib/libdrm/mk/libdrm_amdgpu/shlib_version index 07ff2759..783f55bf 100644 --- a/lib/libdrm/mk/libdrm_amdgpu/shlib_version +++ b/lib/libdrm/mk/libdrm_amdgpu/shlib_version @@ -1,2 +1,2 @@ major=1 -minor=12 +minor=13 diff --git a/lib/libdrm/nouveau/meson.build b/lib/libdrm/nouveau/meson.build index 350f34c4..71c8f552 100644 --- a/lib/libdrm/nouveau/meson.build +++ b/lib/libdrm/nouveau/meson.build @@ -60,6 +60,6 @@ test( args : [ '--lib', libdrm_nouveau, '--symbols-file', files('nouveau-symbols.txt'), - '--nm', prog_nm.path(), + '--nm', prog_nm.full_path(), ], ) diff --git a/lib/libdrm/nouveau/nouveau-symbols.txt b/lib/libdrm/nouveau/nouveau-symbols.txt index 598465f1..7e9b103b 100644 --- a/lib/libdrm/nouveau/nouveau-symbols.txt +++ b/lib/libdrm/nouveau/nouveau-symbols.txt @@ -1,3 +1,4 @@ +nouveau_bo_make_global nouveau_bo_map nouveau_bo_name_get nouveau_bo_name_ref diff --git a/lib/libdrm/nouveau/nouveau.c b/lib/libdrm/nouveau/nouveau.c index 7b4efded..62914a3b 100644 --- a/lib/libdrm/nouveau/nouveau.c +++ b/lib/libdrm/nouveau/nouveau.c @@ -711,7 +711,7 @@ nouveau_bo_wrap_locked(struct nouveau_device *dev, uint32_t handle, } static void -nouveau_bo_make_global(struct nouveau_bo_priv *nvbo) +nouveau_nvbo_make_global(struct nouveau_bo_priv *nvbo) { if (!nvbo->head.next) { struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device); @@ -722,6 +722,14 @@ nouveau_bo_make_global(struct nouveau_bo_priv *nvbo) } } +drm_public void +nouveau_bo_make_global(struct nouveau_bo *bo) +{ + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + + nouveau_nvbo_make_global(nvbo); +} + drm_public int nouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle, struct nouveau_bo **pbo) @@ -780,7 +788,7 @@ nouveau_bo_name_get(struct nouveau_bo *bo, uint32_t *name) } nvbo->name = *name = req.name; - nouveau_bo_make_global(nvbo); + nouveau_nvbo_make_global(nvbo); } return 0; } @@ -830,7 +838,7 @@ nouveau_bo_set_prime(struct nouveau_bo *bo, int *prime_fd) if (ret) return ret; - nouveau_bo_make_global(nvbo); + nouveau_nvbo_make_global(nvbo); return 0; } diff --git a/lib/libdrm/nouveau/nouveau.h b/lib/libdrm/nouveau/nouveau.h index 0c632feb..a5119f98 100644 --- a/lib/libdrm/nouveau/nouveau.h +++ b/lib/libdrm/nouveau/nouveau.h @@ -137,6 +137,7 @@ struct nouveau_bo { int nouveau_bo_new(struct nouveau_device *, uint32_t flags, uint32_t align, uint64_t size, union nouveau_bo_config *, struct nouveau_bo **); +void nouveau_bo_make_global(struct nouveau_bo *); int nouveau_bo_wrap(struct nouveau_device *, uint32_t handle, struct nouveau_bo **); int nouveau_bo_name_ref(struct nouveau_device *v, uint32_t name, diff --git a/lib/libdrm/omap/meson.build b/lib/libdrm/omap/meson.build index 22159184..eebd1420 100644 --- a/lib/libdrm/omap/meson.build +++ b/lib/libdrm/omap/meson.build @@ -25,7 +25,7 @@ libdrm_omap = library( c_args : libdrm_c_args, gnu_symbol_visibility : 'hidden', link_with : libdrm, - dependencies : [dep_pthread_stubs, dep_atomic_ops], + dependencies : [dep_threads, dep_atomic_ops], version : '1.0.0', install : true, ) diff --git a/lib/libdrm/radeon/meson.build b/lib/libdrm/radeon/meson.build index 4c1c71e0..7aa9b705 100644 --- a/lib/libdrm/radeon/meson.build +++ b/lib/libdrm/radeon/meson.build @@ -32,7 +32,7 @@ libdrm_radeon = library( gnu_symbol_visibility : 'hidden', include_directories : [inc_root, inc_drm], link_with : libdrm, - dependencies : [dep_pthread_stubs, dep_atomic_ops], + dependencies : [dep_threads, dep_atomic_ops], version : '1.0.1', install : true, ) @@ -65,6 +65,6 @@ test( args : [ '--lib', libdrm_radeon, '--symbols-file', files('radeon-symbols.txt'), - '--nm', prog_nm.path(), + '--nm', prog_nm.full_path(), ], ) diff --git a/lib/libdrm/radeon/radeon_surface.c b/lib/libdrm/radeon/radeon_surface.c index ea0a27a9..0ff53a3e 100644 --- a/lib/libdrm/radeon/radeon_surface.c +++ b/lib/libdrm/radeon/radeon_surface.c @@ -2205,6 +2205,7 @@ static int cik_surface_sanity(struct radeon_surface_manager *surf_man, break; case RADEON_SURF_MODE_LINEAR_ALIGNED: default: + *stencil_tile_mode = SI_TILE_MODE_COLOR_LINEAR_ALIGNED; *tile_mode = SI_TILE_MODE_COLOR_LINEAR_ALIGNED; } diff --git a/lib/libdrm/tegra/meson.build b/lib/libdrm/tegra/meson.build index 0b63d789..5325ed74 100644 --- a/lib/libdrm/tegra/meson.build +++ b/lib/libdrm/tegra/meson.build @@ -28,7 +28,7 @@ libdrm_tegra = library( ], include_directories : [inc_root, inc_drm], link_with : libdrm, - dependencies : [dep_pthread_stubs, dep_atomic_ops], + dependencies : [dep_threads, dep_atomic_ops], c_args : libdrm_c_args, gnu_symbol_visibility : 'hidden', version : '0.0.0', diff --git a/lib/libdrm/tests/amdgpu/amdgpu_stress.c b/lib/libdrm/tests/amdgpu/amdgpu_stress.c index 5c5c88c5..f919351e 100644 --- a/lib/libdrm/tests/amdgpu/amdgpu_stress.c +++ b/lib/libdrm/tests/amdgpu/amdgpu_stress.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "drm.h" #include "xf86drmMode.h" @@ -175,7 +176,7 @@ int alloc_bo(uint32_t domain, uint64_t size) resources[num_buffers] = bo; virtual[num_buffers] = addr; - fprintf(stdout, "Allocated BO number %u at 0x%lx, domain 0x%x, size %lu\n", + fprintf(stdout, "Allocated BO number %u at 0x%" PRIx64 ", domain 0x%x, size %" PRIu64 "\n", num_buffers++, addr, domain, size); return 0; } @@ -273,7 +274,7 @@ int submit_ib(uint32_t from, uint32_t to, uint64_t size, uint32_t count) delta = stop.tv_nsec + stop.tv_sec * 1000000000UL; delta -= start.tv_nsec + start.tv_sec * 1000000000UL; - fprintf(stdout, "Submitted %u IBs to copy from %u(%lx) to %u(%lx) %lu bytes took %lu usec\n", + fprintf(stdout, "Submitted %u IBs to copy from %u(%" PRIx64 ") to %u(%" PRIx64 ") %" PRIu64 " bytes took %" PRIu64 " usec\n", count, from, virtual[from], to, virtual[to], copied, delta / 1000); return 0; } @@ -293,7 +294,7 @@ uint64_t parse_size(void) char ext[2]; ext[0] = 0; - if (sscanf(optarg, "%li%1[kmgKMG]", &size, ext) < 1) { + if (sscanf(optarg, "%" PRIi64 "%1[kmgKMG]", &size, ext) < 1) { fprintf(stderr, "Can't parse size arg: %s\n", optarg); exit(EXIT_FAILURE); } @@ -375,7 +376,7 @@ int main(int argc, char **argv) next_arg(argc, argv, "Missing buffer size"); size = parse_size(); if (size < getpagesize()) { - fprintf(stderr, "Buffer size to small %lu\n", size); + fprintf(stderr, "Buffer size to small %" PRIu64 "\n", size); exit(EXIT_FAILURE); } r = alloc_bo(domain, size); diff --git a/lib/libdrm/tests/amdgpu/amdgpu_test.c b/lib/libdrm/tests/amdgpu/amdgpu_test.c index 9abe5730..ec787889 100644 --- a/lib/libdrm/tests/amdgpu/amdgpu_test.c +++ b/lib/libdrm/tests/amdgpu/amdgpu_test.c @@ -296,18 +296,23 @@ static void display_test_suites(void) /** Help string for command line parameters */ static const char usage[] = - "Usage: %s [-hlpr] [<-s > [-t ] [-f]] " - "[-b [-d ]]\n" - "where:\n" - " l - Display all suites and their tests\n" - " r - Run the tests on render node\n" - " b - Specify device's PCI bus id to run tests\n" - " d - Specify device's PCI device id to run tests (optional)\n" - " p - Display information of AMDGPU devices in system\n" - " f - Force executing inactive suite or test\n" - " h - Display this help\n"; + "Usage: %s [-hlpr] [-s ] [-e [.] [-e ...]] [-t ] [-f] " + "[-b ] [-d ]\n" + "Where,\n" + " -b Specify device's PCI bus id to run tests\n" + " -d Specify device's PCI device id to run tests (optional)\n" + " -e [.] Disable test of suite . If only is given, then disable\n" + " the whole suite. Can be specified more than once on the command line\n" + " to disable multiple tests or suites.\n" + " -f Force executing inactive suite or test\n" + " -h Display this help\n" + " -l Display all test suites and their tests\n" + " -p Display information of AMDGPU devices in system\n" + " -r Run the tests on render node\n" + " -s Enable only test suite \n" + " -t Enable only test of test suite \n"; /** Specified options strings for getopt */ -static const char options[] = "hlrps:t:b:d:f"; +static const char options[] = "hlrps:t:e:b:d:f"; /* Open AMD devices. * Return the number of AMD device opened. @@ -662,6 +667,48 @@ char *amdgpu_get_device_from_fd(int fd) #endif } +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(_A) (sizeof(_A)/sizeof(_A[0])) +#endif + +static void amdgpu_test_disable(long suite, long test) +{ + const char *suite_name; + + if (suite < 1) + return; + + /* The array is 0-based, so subract 1. */ + suite--; + if (suite >= ARRAY_SIZE(suites) - 1) + return; + + suite_name = suites[suite].pName; + if (test < 1) { + fprintf(stderr, "Deactivating suite %s\n", suite_name); + amdgpu_set_suite_active(suite_name, CU_FALSE); + } else { + int ii; + + /* The array is 0-based so subtract 1. */ + test--; + for (ii = 0; suites[suite].pTests[ii].pName; ii++) { + if (ii == test) { + fprintf(stderr, "Deactivating %s:%s\n", + suite_name, + suites[suite].pTests[ii].pName); + amdgpu_set_test_active(suite_name, + suites[suite].pTests[ii].pName, + CU_FALSE); + break; + } + } + + if (suites[suite].pTests[ii].pName == NULL) + fprintf(stderr, "No such suite.test %ld.%ld\n", suite, test); + } +} + /* The main() function for setting up and running the tests. * Returns a CUE_SUCCESS on successful running, another * CUnit error code on failure. @@ -680,48 +727,21 @@ int main(int argc, char **argv) int display_list = 0; int force_run = 0; - for (i = 0; i < MAX_CARDS_SUPPORTED; i++) - drm_amdgpu[i] = -1; - - - /* Parse command line string */ + /* Parse command line string. + * Process various command line options as early as possible. + */ opterr = 0; /* Do not print error messages from getopt */ while ((c = getopt(argc, argv, options)) != -1) { switch (c) { - case 'l': - display_list = 1; - break; - case 's': - suite_id = atoi(optarg); - break; - case 't': - test_id = atoi(optarg); - break; - case 'b': - pci_bus_id = atoi(optarg); - break; - case 'd': - sscanf(optarg, "%x", &pci_device_id); - break; - case 'p': - display_devices = 1; - break; - case 'r': - open_render_node = 1; - break; - case 'f': - force_run = 1; - break; - case '?': case 'h': fprintf(stderr, usage, argv[0]); exit(EXIT_SUCCESS); - default: - fprintf(stderr, usage, argv[0]); - exit(EXIT_FAILURE); } } + for (i = 0; i < MAX_CARDS_SUPPORTED; i++) + drm_amdgpu[i] = -1; + if (amdgpu_open_devices(open_render_node) <= 0) { perror("Cannot open AMDGPU device"); exit(EXIT_FAILURE); @@ -732,12 +752,37 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + /* Parse command line string */ + opterr = 0; /* Do not print error messages from getopt */ + optind = 1; + while ((c = getopt(argc, argv, options)) != -1) { + switch (c) { + case 'p': + display_devices = 1; + break; + } + } + if (display_devices) { amdgpu_print_devices(); amdgpu_close_devices(); exit(EXIT_SUCCESS); } + /* Parse command line string */ + opterr = 0; /* Do not print error messages from getopt */ + optind = 1; + while ((c = getopt(argc, argv, options)) != -1) { + switch (c) { + case 'b': + pci_bus_id = atoi(optarg); + break; + case 'd': + sscanf(optarg, "%x", &pci_device_id); + break; + } + } + if (pci_bus_id > 0 || pci_device_id) { /* A device was specified to run the test */ test_device_index = amdgpu_find_device(pci_bus_id, @@ -780,11 +825,85 @@ int main(int argc, char **argv) /* Disable suites and individual tests based on misc. conditions */ amdgpu_disable_suites(); + /* Parse command line string */ + opterr = 0; /* Do not print error messages from getopt */ + optind = 1; + while ((c = getopt(argc, argv, options)) != -1) { + switch (c) { + case 'l': + display_list = 1; + break; + } + } + if (display_list) { display_test_suites(); goto end; } + /* Parse command line string */ + opterr = 0; /* Do not print error messages from getopt */ + optind = 1; + while ((c = getopt(argc, argv, options)) != -1) { + long esuite = -1; + long etest = -1; + char *endp; + switch (c) { + case 's': + suite_id = atoi(optarg); + break; + case 't': + test_id = atoi(optarg); + break; + case 'r': + open_render_node = 1; + break; + case 'f': + force_run = 1; + break; + case 'e': + esuite = strtol(optarg, &endp, 0); + if (endp == optarg) { + fprintf(stderr, "No digits given for -e argument\n"); + goto end; + } else if (endp && *endp == '.' && esuite > 0) { + char *tt = endp + 1; + etest = strtol(tt, &endp, 0); + if (endp == tt) { + fprintf(stderr, "No digits given for test in -e s.t argument\n"); + goto end; + } else if (endp && *endp != '\0') { + fprintf(stderr, "Bad input given for test in -e s.t argument\n"); + goto end; + } else if (etest < 1) { + fprintf(stderr, "Test in -e s.t argument cannot be smaller than 1\n"); + goto end; + } + } else if (endp && *endp != '\0') { + fprintf(stderr, "Bad input given for suite for -e s argument\n"); + goto end; + } else if (esuite < 1) { + fprintf(stderr, "Suite in -e s argument cannot be smaller than 1\n"); + goto end; + } + amdgpu_test_disable(esuite, etest); + break; + case 'h': + case 'p': + case 'b': + case 'd': + case 'l': + /* Those have been processed earlier. + */ + break; + case '?': + default: + fprintf(stderr, "Unknown command line option '%c'. Try -h.\n", + c == '?' ? optopt : c); + goto end; + } + } + if (suite_id != -1) { /* If user specify particular suite? */ pSuite = CU_get_suite_by_index((unsigned int) suite_id, CU_get_registry()); diff --git a/lib/libdrm/tests/amdgpu/hotunplug_tests.c b/lib/libdrm/tests/amdgpu/hotunplug_tests.c index 2b265673..af933b19 100644 --- a/lib/libdrm/tests/amdgpu/hotunplug_tests.c +++ b/lib/libdrm/tests/amdgpu/hotunplug_tests.c @@ -70,6 +70,10 @@ CU_BOOL suite_hotunplug_tests_enable(void) if (minor_version < 46) enable = false; + /* skip hotplug test on APUs */ + if(device_handle->dev_info.ids_flags & AMDGPU_IDS_FLAGS_FUSION) + enable = false; + if (amdgpu_device_deinitialize(device_handle)) return CU_FALSE; diff --git a/lib/libdrm/tests/amdgpu/vcn_tests.c b/lib/libdrm/tests/amdgpu/vcn_tests.c index 5e20fb65..c83fdb53 100644 --- a/lib/libdrm/tests/amdgpu/vcn_tests.c +++ b/lib/libdrm/tests/amdgpu/vcn_tests.c @@ -177,6 +177,7 @@ static uint32_t *ib_checksum; static uint32_t *ib_size_in_dw; static rvcn_decode_buffer_t *decode_buffer; +struct amdgpu_vcn_bo session_ctx_buf; static amdgpu_bo_handle resources[MAX_RESOURCES]; static unsigned num_resources; @@ -561,7 +562,9 @@ static void amdgpu_cs_vcn_dec_create(void) num_resources = 0; alloc_resource(&msg_buf, 4096, AMDGPU_GEM_DOMAIN_GTT); + alloc_resource(&session_ctx_buf, 32 * 4096, AMDGPU_GEM_DOMAIN_VRAM); resources[num_resources++] = msg_buf.handle; + resources[num_resources++] = session_ctx_buf.handle; resources[num_resources++] = ib_handle; r = amdgpu_bo_cpu_map(msg_buf.handle, (void **)&msg_buf.ptr); @@ -571,9 +574,11 @@ static void amdgpu_cs_vcn_dec_create(void) memcpy(msg_buf.ptr, vcn_dec_create_msg, sizeof(vcn_dec_create_msg)); len = 0; - if (vcn_dec_sw_ring == true) + + vcn_dec_cmd(session_ctx_buf.addr, 5, &len); + if (vcn_dec_sw_ring == true) { vcn_dec_cmd(msg_buf.addr, 0, &len); - else { + } else { ib_cpu[len++] = reg[vcn_reg_index].data0; ib_cpu[len++] = msg_buf.addr; ib_cpu[len++] = reg[vcn_reg_index].data1; @@ -650,6 +655,7 @@ static void amdgpu_cs_vcn_dec_decode(void) dt_addr = ALIGN(dpb_addr + dpb_size, 4*1024); len = 0; + vcn_dec_cmd(session_ctx_buf.addr, 0x5, &len); vcn_dec_cmd(msg_addr, 0x0, &len); vcn_dec_cmd(dpb_addr, 0x1, &len); vcn_dec_cmd(dt_addr, 0x2, &len); @@ -702,9 +708,10 @@ static void amdgpu_cs_vcn_dec_destroy(void) memcpy(msg_buf.ptr, vcn_dec_destroy_msg, sizeof(vcn_dec_destroy_msg)); len = 0; - if (vcn_dec_sw_ring == true) + vcn_dec_cmd(session_ctx_buf.addr, 5, &len); + if (vcn_dec_sw_ring == true) { vcn_dec_cmd(msg_buf.addr, 0, &len); - else { + } else { ib_cpu[len++] = reg[vcn_reg_index].data0; ib_cpu[len++] = msg_buf.addr; ib_cpu[len++] = reg[vcn_reg_index].data1; @@ -727,6 +734,7 @@ static void amdgpu_cs_vcn_dec_destroy(void) CU_ASSERT_EQUAL(r, 0); free_resource(&msg_buf); + free_resource(&session_ctx_buf); } static void amdgpu_cs_vcn_enc_create(void) @@ -808,6 +816,8 @@ static void amdgpu_cs_vcn_enc_create(void) ib_cpu[len++] = 0; ib_cpu[len++] = 0; /* pre encode mode */ ib_cpu[len++] = 0; /* chroma enabled : false */ + ib_cpu[len++] = 0; + ib_cpu[len++] = 0; *st_size = (len - st_offset) * 4; /* slice control */ @@ -829,7 +839,7 @@ static void amdgpu_cs_vcn_enc_create(void) ib_cpu[len++] = 1; /* quarter pel enabled */ ib_cpu[len++] = 100; /* BASELINE profile */ ib_cpu[len++] = 11; /* level */ - if (vcn_ip_version_major == 3) { + if (vcn_ip_version_major >= 3) { ib_cpu[len++] = 0; /* b_picture_enabled */ ib_cpu[len++] = 0; /* weighted_bipred_idc */ } @@ -870,7 +880,7 @@ static void amdgpu_cs_vcn_enc_create(void) ib_cpu[len++] = 0; /* scene change sensitivity */ ib_cpu[len++] = 0; /* scene change min idr interval */ ib_cpu[len++] = 0; - if (vcn_ip_version_major == 3) + if (vcn_ip_version_major >= 3) ib_cpu[len++] = 0; *st_size = (len - st_offset) * 4; @@ -913,6 +923,7 @@ static void amdgpu_cs_vcn_enc_create(void) ib_cpu[len++] = 1; ib_cpu[len++] = 0; ib_cpu[len++] = 1; + ib_cpu[len++] = 0; *st_size = (len - st_offset) * 4; /* op init rc */ @@ -1265,10 +1276,16 @@ static void check_result(struct amdgpu_vcn_bo fb_buf, struct amdgpu_vcn_bo bs_bu CU_ASSERT_EQUAL(r, 0); } +static void amdgpu_cs_vcn_ib_zero_count(int *len, int num) +{ + for (int i = 0; i < num; i++) + ib_cpu[(*len)++] = 0; +} + static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) { - struct amdgpu_vcn_bo bs_buf, fb_buf, vbv_buf; - int len, r, i; + struct amdgpu_vcn_bo bs_buf, fb_buf, input_buf; + int len, r; unsigned width = 160, height = 128, buf_size; uint32_t *p_task_size = NULL; uint32_t task_offset = 0, st_offset; @@ -1288,12 +1305,12 @@ static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) num_resources = 0; alloc_resource(&bs_buf, 4096, AMDGPU_GEM_DOMAIN_GTT); alloc_resource(&fb_buf, 4096, AMDGPU_GEM_DOMAIN_GTT); - alloc_resource(&vbv_buf, buf_size, AMDGPU_GEM_DOMAIN_GTT); + alloc_resource(&input_buf, buf_size, AMDGPU_GEM_DOMAIN_GTT); resources[num_resources++] = enc_buf.handle; resources[num_resources++] = cpb_buf.handle; resources[num_resources++] = bs_buf.handle; resources[num_resources++] = fb_buf.handle; - resources[num_resources++] = vbv_buf.handle; + resources[num_resources++] = input_buf.handle; resources[num_resources++] = ib_handle; @@ -1305,13 +1322,13 @@ static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) memset(fb_buf.ptr, 0, 4096); r = amdgpu_bo_cpu_unmap(fb_buf.handle); - r = amdgpu_bo_cpu_map(vbv_buf.handle, (void **)&vbv_buf.ptr); + r = amdgpu_bo_cpu_map(input_buf.handle, (void **)&input_buf.ptr); CU_ASSERT_EQUAL(r, 0); for (int i = 0; i < ALIGN(height, 32) * 3 / 2; i++) - memcpy(vbv_buf.ptr + i * ALIGN(width, 256), frame + i * width, width); + memcpy(input_buf.ptr + i * ALIGN(width, 256), frame + i * width, width); - r = amdgpu_bo_cpu_unmap(vbv_buf.handle); + r = amdgpu_bo_cpu_unmap(input_buf.handle); CU_ASSERT_EQUAL(r, 0); len = 0; @@ -1346,7 +1363,7 @@ static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) if(vcn_ip_version_major == 1) ib_cpu[len++] = 0x00000020; /* RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU vcn 1 */ else - ib_cpu[len++] = 0x0000000a; /* RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU vcn 2,3 */ + ib_cpu[len++] = 0x0000000a; /* RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU other vcn */ ib_cpu[len++] = 0x00000002; /* RENCODE_DIRECT_OUTPUT_NALU_TYPE_SPS */ ib_cpu[len++] = 0x00000011; /* sps len */ ib_cpu[len++] = 0x00000001; /* start code */ @@ -1362,7 +1379,7 @@ static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) if(vcn_ip_version_major == 1) ib_cpu[len++] = 0x00000020; /* RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU vcn 1*/ else - ib_cpu[len++] = 0x0000000a; /* RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU vcn 2,3*/ + ib_cpu[len++] = 0x0000000a; /* RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU other vcn*/ ib_cpu[len++] = 0x00000003; /* RENCODE_DIRECT_OUTPUT_NALU_TYPE_PPS */ ib_cpu[len++] = 0x00000008; /* pps len */ ib_cpu[len++] = 0x00000001; /* start code */ @@ -1376,7 +1393,7 @@ static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) if(vcn_ip_version_major == 1) ib_cpu[len++] = 0x0000000a; /* RENCODE_IB_PARAM_SLICE_HEADER vcn 1 */ else - ib_cpu[len++] = 0x0000000b; /* RENCODE_IB_PARAM_SLICE_HEADER vcn 2,3 */ + ib_cpu[len++] = 0x0000000b; /* RENCODE_IB_PARAM_SLICE_HEADER other vcn */ if (frame_type == 2) { ib_cpu[len++] = 0x65000000; ib_cpu[len++] = 0x11040000; @@ -1385,8 +1402,7 @@ static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) ib_cpu[len++] = 0x34210000; } ib_cpu[len++] = 0xe0000000; - for(i = 0; i < 13; i++) - ib_cpu[len++] = 0x00000000; + amdgpu_cs_vcn_ib_zero_count(&len, 13); ib_cpu[len++] = 0x00000001; ib_cpu[len++] = 0x00000008; @@ -1398,24 +1414,22 @@ static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) ib_cpu[len++] = 0x00000000; ib_cpu[len++] = 0x00000001; ib_cpu[len++] = 0x00000003; - for(i = 0; i < 22; i++) - ib_cpu[len++] = 0x00000000; - + amdgpu_cs_vcn_ib_zero_count(&len, 22); *st_size = (len - st_offset) * 4; /* encode params */ st_offset = len; st_size = &ib_cpu[len++]; /* size */ if(vcn_ip_version_major == 1) - ib_cpu[len++] = 0x0000000b; /* RENCODE_IB_PARAM_ENCODE_PARAMS vcn 1*/ + ib_cpu[len++] = 0x0000000b; /* RENCODE_IB_PARAM_ENCODE_PARAMS vcn 1 */ else - ib_cpu[len++] = 0x0000000f; /* RENCODE_IB_PARAM_ENCODE_PARAMS vcn 2,3*/ + ib_cpu[len++] = 0x0000000f; /* RENCODE_IB_PARAM_ENCODE_PARAMS other vcn */ ib_cpu[len++] = frame_type; ib_cpu[len++] = 0x0001f000; - ib_cpu[len++] = vbv_buf.addr >> 32; - ib_cpu[len++] = vbv_buf.addr; - ib_cpu[len++] = (vbv_buf.addr + ALIGN(width, 256) * ALIGN(height, 32)) >> 32; - ib_cpu[len++] = vbv_buf.addr + ALIGN(width, 256) * ALIGN(height, 32); + ib_cpu[len++] = input_buf.addr >> 32; + ib_cpu[len++] = input_buf.addr; + ib_cpu[len++] = (input_buf.addr + ALIGN(width, 256) * ALIGN(height, 32)) >> 32; + ib_cpu[len++] = input_buf.addr + ALIGN(width, 256) * ALIGN(height, 32); ib_cpu[len++] = 0x00000100; ib_cpu[len++] = 0x00000080; ib_cpu[len++] = 0x00000000; @@ -1427,7 +1441,7 @@ static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) st_offset = len; st_size = &ib_cpu[len++]; /* size */ ib_cpu[len++] = 0x00200003; /* RENCODE_H264_IB_PARAM_ENCODE_PARAMS */ - if (vcn_ip_version_major != 3) { + if (vcn_ip_version_major <= 2) { ib_cpu[len++] = 0x00000000; ib_cpu[len++] = 0x00000000; ib_cpu[len++] = 0x00000000; @@ -1450,6 +1464,7 @@ static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) ib_cpu[len++] = 0x00000000; ib_cpu[len++] = 0x00000000; ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000001; } *st_size = (len - st_offset) * 4; @@ -1459,20 +1474,21 @@ static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) if(vcn_ip_version_major == 1) ib_cpu[len++] = 0x0000000d; /* ENCODE_CONTEXT_BUFFER vcn 1 */ else - ib_cpu[len++] = 0x00000011; /* ENCODE_CONTEXT_BUFFER vcn 2,3 */ + ib_cpu[len++] = 0x00000011; /* ENCODE_CONTEXT_BUFFER other vcn */ ib_cpu[len++] = cpb_buf.addr >> 32; ib_cpu[len++] = cpb_buf.addr; ib_cpu[len++] = 0x00000000; /* swizzle mode */ ib_cpu[len++] = 0x00000100; /* luma pitch */ ib_cpu[len++] = 0x00000100; /* chroma pitch */ - ib_cpu[len++] = 0x00000003; /* no reconstructed picture */ + ib_cpu[len++] = 0x00000002; /* no reconstructed picture */ ib_cpu[len++] = 0x00000000; /* reconstructed pic 1 luma offset */ ib_cpu[len++] = ALIGN(width, 256) * ALIGN(height, 32); /* pic1 chroma offset */ + if(vcn_ip_version_major == 4) + amdgpu_cs_vcn_ib_zero_count(&len, 2); ib_cpu[len++] = ALIGN(width, 256) * ALIGN(height, 32) * 3 / 2; /* pic2 luma offset */ ib_cpu[len++] = ALIGN(width, 256) * ALIGN(height, 32) * 5 / 2; /* pic2 chroma offset */ - for (int i = 0; i < 136; i++) - ib_cpu[len++] = 0x00000000; + amdgpu_cs_vcn_ib_zero_count(&len, 280); *st_size = (len - st_offset) * 4; /* bitstream buffer */ @@ -1481,7 +1497,8 @@ static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) if(vcn_ip_version_major == 1) ib_cpu[len++] = 0x0000000e; /* VIDEO_BITSTREAM_BUFFER vcn 1 */ else - ib_cpu[len++] = 0x00000012; /* VIDEO_BITSTREAM_BUFFER vcn 2,3 */ + ib_cpu[len++] = 0x00000012; /* VIDEO_BITSTREAM_BUFFER other vcn */ + ib_cpu[len++] = 0x00000000; /* mode */ ib_cpu[len++] = bs_buf.addr >> 32; ib_cpu[len++] = bs_buf.addr; @@ -1564,7 +1581,7 @@ static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) free_resource(&fb_buf); free_resource(&bs_buf); - free_resource(&vbv_buf); + free_resource(&input_buf); } static void amdgpu_cs_vcn_enc_encode(void) diff --git a/lib/libdrm/tests/modetest/buffers.c b/lib/libdrm/tests/modetest/buffers.c index 0b55aedd..576e2cc7 100644 --- a/lib/libdrm/tests/modetest/buffers.c +++ b/lib/libdrm/tests/modetest/buffers.c @@ -124,16 +124,36 @@ bo_create(int fd, unsigned int format, int ret; switch (format) { + case DRM_FORMAT_C1: + bpp = 1; + break; + + case DRM_FORMAT_C2: + bpp = 2; + break; + + case DRM_FORMAT_C4: + bpp = 4; + break; + case DRM_FORMAT_C8: case DRM_FORMAT_NV12: case DRM_FORMAT_NV21: case DRM_FORMAT_NV16: case DRM_FORMAT_NV61: + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: case DRM_FORMAT_YUV420: case DRM_FORMAT_YVU420: bpp = 8; break; + case DRM_FORMAT_NV15: + case DRM_FORMAT_NV20: + case DRM_FORMAT_NV30: + bpp = 10; + break; + case DRM_FORMAT_ARGB4444: case DRM_FORMAT_XRGB4444: case DRM_FORMAT_ABGR4444: @@ -144,6 +164,7 @@ bo_create(int fd, unsigned int format, case DRM_FORMAT_BGRX4444: case DRM_FORMAT_ARGB1555: case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN: case DRM_FORMAT_ABGR1555: case DRM_FORMAT_XBGR1555: case DRM_FORMAT_RGBA5551: @@ -151,6 +172,7 @@ bo_create(int fd, unsigned int format, case DRM_FORMAT_BGRA5551: case DRM_FORMAT_BGRX5551: case DRM_FORMAT_RGB565: + case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN: case DRM_FORMAT_BGR565: case DRM_FORMAT_UYVY: case DRM_FORMAT_VYUY: @@ -198,6 +220,7 @@ bo_create(int fd, unsigned int format, switch (format) { case DRM_FORMAT_NV12: case DRM_FORMAT_NV21: + case DRM_FORMAT_NV15: case DRM_FORMAT_YUV420: case DRM_FORMAT_YVU420: virtual_height = height * 3 / 2; @@ -205,9 +228,16 @@ bo_create(int fd, unsigned int format, case DRM_FORMAT_NV16: case DRM_FORMAT_NV61: + case DRM_FORMAT_NV20: virtual_height = height * 2; break; + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: + case DRM_FORMAT_NV30: + virtual_height = height * 3; + break; + default: virtual_height = height; break; @@ -244,6 +274,8 @@ bo_create(int fd, unsigned int format, case DRM_FORMAT_NV21: case DRM_FORMAT_NV16: case DRM_FORMAT_NV61: + case DRM_FORMAT_NV15: + case DRM_FORMAT_NV20: offsets[0] = 0; handles[0] = bo->handle; pitches[0] = bo->pitch; @@ -255,6 +287,20 @@ bo_create(int fd, unsigned int format, planes[1] = virtual + offsets[1]; break; + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: + case DRM_FORMAT_NV30: + offsets[0] = 0; + handles[0] = bo->handle; + pitches[0] = bo->pitch; + pitches[1] = pitches[0] * 2; + offsets[1] = pitches[0] * height; + handles[1] = bo->handle; + + planes[0] = virtual; + planes[1] = virtual + offsets[1]; + break; + case DRM_FORMAT_YUV420: case DRM_FORMAT_YVU420: offsets[0] = 0; @@ -272,6 +318,9 @@ bo_create(int fd, unsigned int format, planes[2] = virtual + offsets[2]; break; + case DRM_FORMAT_C1: + case DRM_FORMAT_C2: + case DRM_FORMAT_C4: case DRM_FORMAT_C8: case DRM_FORMAT_ARGB4444: case DRM_FORMAT_XRGB4444: @@ -283,6 +332,7 @@ bo_create(int fd, unsigned int format, case DRM_FORMAT_BGRX4444: case DRM_FORMAT_ARGB1555: case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN: case DRM_FORMAT_ABGR1555: case DRM_FORMAT_XBGR1555: case DRM_FORMAT_RGBA5551: @@ -290,6 +340,7 @@ bo_create(int fd, unsigned int format, case DRM_FORMAT_BGRA5551: case DRM_FORMAT_BGRX5551: case DRM_FORMAT_RGB565: + case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN: case DRM_FORMAT_BGR565: case DRM_FORMAT_BGR888: case DRM_FORMAT_RGB888: @@ -338,3 +389,22 @@ void bo_destroy(struct bo *bo) free(bo); } + +void bo_dump(struct bo *bo, const char *filename) +{ + FILE *fp; + + if (!bo || !filename) + return; + + fp = fopen(filename, "wb"); + if (fp) { + void *addr; + + bo_map(bo, &addr); + printf("Dumping buffer %p to file %s.\n", bo->ptr, filename); + fwrite(bo->ptr, 1, bo->size, fp); + bo_unmap(bo); + fclose(fp); + } +} diff --git a/lib/libdrm/tests/modetest/buffers.h b/lib/libdrm/tests/modetest/buffers.h index 7f95396b..cbd54e9e 100644 --- a/lib/libdrm/tests/modetest/buffers.h +++ b/lib/libdrm/tests/modetest/buffers.h @@ -36,5 +36,6 @@ struct bo *bo_create(int fd, unsigned int format, unsigned int handles[4], unsigned int pitches[4], unsigned int offsets[4], enum util_fill_pattern pattern); void bo_destroy(struct bo *bo); +void bo_dump(struct bo *bo, const char *filename); #endif diff --git a/lib/libdrm/tests/modetest/meson.build b/lib/libdrm/tests/modetest/meson.build index 23d84a1d..5ed1638c 100644 --- a/lib/libdrm/tests/modetest/meson.build +++ b/lib/libdrm/tests/modetest/meson.build @@ -25,5 +25,6 @@ modetest = executable( include_directories : [inc_root, inc_tests, inc_drm], dependencies : [dep_threads, dep_cairo], link_with : [libdrm, libutil], + link_args: '-lm', install : with_install_tests, ) diff --git a/lib/libdrm/tests/modetest/modetest.c b/lib/libdrm/tests/modetest/modetest.c index 42e2d1f4..d9e761e6 100644 --- a/lib/libdrm/tests/modetest/modetest.c +++ b/lib/libdrm/tests/modetest/modetest.c @@ -70,6 +70,7 @@ static enum util_fill_pattern primary_fill = UTIL_PATTERN_SMPTE; static enum util_fill_pattern secondary_fill = UTIL_PATTERN_TILES; +static drmModeModeInfo user_mode; struct crtc { drmModeCrtc *crtc; @@ -128,6 +129,7 @@ struct device { int use_atomic; drmModeAtomicReq *req; + int32_t writeback_fence_fd; }; static inline int64_t U642I64(uint64_t val) @@ -137,8 +139,19 @@ static inline int64_t U642I64(uint64_t val) static float mode_vrefresh(drmModeModeInfo *mode) { - return mode->clock * 1000.00 - / (mode->htotal * mode->vtotal); + unsigned int num, den; + + num = mode->clock; + den = mode->htotal * mode->vtotal; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + num *= 2; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + den *= 2; + if (mode->vscan > 1) + den *= mode->vscan; + + return num * 1000.00 / den; } #define bit_name_fn(res) \ @@ -317,7 +330,7 @@ static void dump_in_formats(struct device *dev, uint32_t blob_id) printf(": "); } - printf(" %s", modifier_to_string(iter.mod)); + printf(" %s(0x%"PRIx64")", modifier_to_string(iter.mod), iter.mod); } printf("\n"); @@ -804,13 +817,15 @@ struct pipe_arg { unsigned int num_cons; uint32_t crtc_id; char mode_str[64]; - char format_str[5]; + char format_str[8]; /* need to leave room for "_BE" and terminating \0 */ float vrefresh; unsigned int fourcc; drmModeModeInfo *mode; struct crtc *crtc; unsigned int fb_id[2], current_fb_id; struct timeval start; + unsigned int out_fb_id; + struct bo *out_bo; int swap_count; }; @@ -826,7 +841,7 @@ struct plane_arg { unsigned int old_fb_id; struct bo *bo; struct bo *old_bo; - char format_str[5]; /* need to leave room for terminating \0 */ + char format_str[8]; /* need to leave room for "_BE" and terminating \0 */ unsigned int fourcc; }; @@ -839,7 +854,25 @@ connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str, int i; connector = get_connector_by_id(dev, con_id); - if (!connector || !connector->count_modes) + if (!connector) + return NULL; + + if (strchr(mode_str, ',')) { + i = sscanf(mode_str, "%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu", + &user_mode.hdisplay, &user_mode.hsync_start, + &user_mode.hsync_end, &user_mode.htotal, + &user_mode.vdisplay, &user_mode.vsync_start, + &user_mode.vsync_end, &user_mode.vtotal); + if (i == 8) { + user_mode.clock = roundf(user_mode.htotal * user_mode.vtotal * vrefresh / 1000); + user_mode.vrefresh = roundf(vrefresh); + snprintf(user_mode.name, sizeof(user_mode.name), "custom%dx%d", user_mode.hdisplay, user_mode.vdisplay); + + return &user_mode; + } + } + + if (!connector->count_modes) return NULL; /* Pick by Index */ @@ -1040,7 +1073,7 @@ static bool set_property(struct device *dev, struct property_arg *p) if (ret < 0) fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n", - obj_type, p->obj_id, p->name, p->value, strerror(errno)); + obj_type, p->obj_id, p->name, p->value, strerror(-ret)); return true; } @@ -1116,15 +1149,23 @@ static bool add_property_optional(struct device *dev, uint32_t obj_id, static void set_gamma(struct device *dev, unsigned crtc_id, unsigned fourcc) { unsigned blob_id = 0; + const struct util_format_info *info; /* TODO: support 1024-sized LUTs, when the use-case arises */ struct drm_color_lut gamma_lut[256]; int i, ret; - if (fourcc == DRM_FORMAT_C8) { - /* TODO: Add C8 support for more patterns */ - util_smpte_c8_gamma(256, gamma_lut); + info = util_format_info_find(fourcc); + if (info->ncolors) { + memset(gamma_lut, 0, sizeof(gamma_lut)); + /* TODO: Add index support for more patterns */ + util_smpte_fill_lut(info->ncolors, gamma_lut); drmModeCreatePropertyBlob(dev->fd, gamma_lut, sizeof(gamma_lut), &blob_id); } else { + /* + * Initialize gamma_lut to a linear table for the legacy API below. + * The modern property API resets to a linear/pass-thru table if blob_id + * is 0, hence no PropertyBlob is created here. + */ for (i = 0; i < 256; i++) { gamma_lut[i].red = gamma_lut[i].green = @@ -1135,6 +1176,7 @@ static void set_gamma(struct device *dev, unsigned crtc_id, unsigned fourcc) add_property_optional(dev, crtc_id, "DEGAMMA_LUT", 0); add_property_optional(dev, crtc_id, "CTM", 0); if (!add_property_optional(dev, crtc_id, "GAMMA_LUT", blob_id)) { + /* If we can't add the GAMMA_LUT property, try the legacy API. */ uint16_t r[256], g[256], b[256]; for (i = 0; i < 256; i++) { @@ -1144,7 +1186,7 @@ static void set_gamma(struct device *dev, unsigned crtc_id, unsigned fourcc) } ret = drmModeCrtcSetGamma(dev->fd, crtc_id, 256, r, g, b); - if (ret) + if (ret && errno != ENOSYS) fprintf(stderr, "failed to set gamma: %s\n", strerror(errno)); } } @@ -1441,6 +1483,24 @@ static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe) return 0; } +static bool pipe_has_writeback_connector(struct device *dev, struct pipe_arg *pipes, + unsigned int count) +{ + drmModeConnector *connector; + unsigned int i, j; + + for (j = 0; j < count; j++) { + struct pipe_arg *pipe = &pipes[j]; + + for (i = 0; i < pipe->num_cons; i++) { + connector = get_connector_by_id(dev, pipe->con_ids[i]); + if (connector && connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + return true; + } + } + return false; +} + static int pipe_attempt_connector(struct device *dev, drmModeConnector *con, struct pipe_arg *pipe) { @@ -1503,7 +1563,8 @@ static int pipe_find_preferred(struct device *dev, struct pipe_arg **out_pipes) for (i = 0; i < res->count_connectors; i++) { con = res->connectors[i].connector; - if (!con || con->connection != DRM_MODE_CONNECTED) + if (!con || con->connection != DRM_MODE_CONNECTED || + con->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) continue; connected++; } @@ -1550,32 +1611,35 @@ static struct plane *get_primary_plane_by_crtc(struct device *dev, struct crtc * return NULL; } -static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) +static unsigned int set_mode(struct device *dev, struct pipe_arg **pipe_args, unsigned int count) { unsigned int i, j; int ret, x = 0; int preferred = count == 0; + struct pipe_arg *pipes; - for (i = 0; i < count; i++) { - struct pipe_arg *pipe = &pipes[i]; - - ret = pipe_resolve_connectors(dev, pipe); - if (ret < 0) - return; - - ret = pipe_find_crtc_and_mode(dev, pipe); - if (ret < 0) - continue; - } if (preferred) { - struct pipe_arg *pipe_args; - - count = pipe_find_preferred(dev, &pipe_args); + count = pipe_find_preferred(dev, pipe_args); if (!count) { fprintf(stderr, "can't find any preferred connector/mode.\n"); - return; + return 0; + } + + pipes = *pipe_args; + } else { + pipes = *pipe_args; + + for (i = 0; i < count; i++) { + struct pipe_arg *pipe = &pipes[i]; + + ret = pipe_resolve_connectors(dev, pipe); + if (ret < 0) + return 0; + + ret = pipe_find_crtc_and_mode(dev, pipe); + if (ret < 0) + continue; } - pipes = pipe_args; } if (!dev->use_atomic) { @@ -1602,7 +1666,7 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height, primary_fill, &dev->mode.bo, &dev->mode.fb_id)) - return; + return 0; } for (i = 0; i < count; i++) { @@ -1634,7 +1698,7 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co if (ret) { fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); - return; + return 0; } set_gamma(dev, pipe->crtc_id, pipe->fourcc); @@ -1660,6 +1724,77 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co } } } + + return count; +} + +static void writeback_config(struct device *dev, struct pipe_arg *pipes, unsigned int count) +{ + drmModeConnector *connector; + unsigned int i, j; + + for (j = 0; j < count; j++) { + struct pipe_arg *pipe = &pipes[j]; + + for (i = 0; i < pipe->num_cons; i++) { + connector = get_connector_by_id(dev, pipe->con_ids[i]); + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) { + if (!pipe->mode) { + fprintf(stderr, "no mode for writeback\n"); + return; + } + bo_fb_create(dev->fd, pipes[j].fourcc, + pipe->mode->hdisplay, pipe->mode->vdisplay, + UTIL_PATTERN_PLAIN, + &pipe->out_bo, &pipe->out_fb_id); + add_property(dev, pipe->con_ids[i], "WRITEBACK_FB_ID", + pipe->out_fb_id); + add_property(dev, pipe->con_ids[i], "WRITEBACK_OUT_FENCE_PTR", + (uintptr_t)(&dev->writeback_fence_fd)); + } + } + } +} + +static int poll_writeback_fence(int fd, int timeout) +{ + struct pollfd fds = { fd, POLLIN }; + int ret; + + do { + ret = poll(&fds, 1, timeout); + if (ret > 0) { + if (fds.revents & (POLLERR | POLLNVAL)) + return -EINVAL; + + return 0; + } else if (ret == 0) { + return -ETIMEDOUT; + } else { + ret = -errno; + if (ret == -EINTR || ret == -EAGAIN) + continue; + return ret; + } + } while (1); + +} + +static void dump_output_fb(struct device *dev, struct pipe_arg *pipes, char *dump_path, + unsigned int count) +{ + drmModeConnector *connector; + unsigned int i, j; + + for (j = 0; j < count; j++) { + struct pipe_arg *pipe = &pipes[j]; + + for (i = 0; i < pipe->num_cons; i++) { + connector = get_connector_by_id(dev, pipe->con_ids[i]); + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + bo_dump(pipe->out_bo, dump_path); + } + } } static void atomic_clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) @@ -1897,8 +2032,9 @@ static int parse_connector(struct pipe_arg *pipe, const char *arg) } if (*p == '@') { - strncpy(pipe->format_str, p + 1, 4); - pipe->format_str[4] = '\0'; + len = sizeof(pipe->format_str) - 1; + strncpy(pipe->format_str, p + 1, len); + pipe->format_str[len] = '\0'; } pipe->fourcc = util_format_fourcc(pipe->format_str); @@ -1912,6 +2048,7 @@ static int parse_connector(struct pipe_arg *pipe, const char *arg) static int parse_plane(struct plane_arg *plane, const char *p) { + unsigned int len; char *end; plane->plane_id = strtoul(p, &end, 10); @@ -1950,8 +2087,9 @@ static int parse_plane(struct plane_arg *plane, const char *p) } if (*end == '@') { - strncpy(plane->format_str, end + 1, 4); - plane->format_str[4] = '\0'; + len = sizeof(plane->format_str) - 1; + strncpy(plane->format_str, end + 1, len); + plane->format_str[len] = '\0'; } else { strcpy(plane->format_str, "XR24"); } @@ -1990,7 +2128,7 @@ static void parse_fill_patterns(char *arg) static void usage(char *name) { - fprintf(stderr, "usage: %s [-acDdefMPpsCvrw]\n", name); + fprintf(stderr, "usage: %s [-acDdefMoPpsCvrw]\n", name); fprintf(stderr, "\n Query options:\n\n"); fprintf(stderr, "\t-c\tlist connectors\n"); @@ -1999,14 +2137,19 @@ static void usage(char *name) fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n"); fprintf(stderr, "\n Test options:\n\n"); - fprintf(stderr, "\t-P @:x[++][*][@]\tset a plane\n"); - fprintf(stderr, "\t-s [,][@]:[#][-][@]\tset a mode\n"); + fprintf(stderr, "\t-P @:x[++][*][@]\tset a plane, see 'plane-topology'\n"); + fprintf(stderr, "\t-s [,][@]:mode[@]\tset a mode, see 'mode-topology'\n"); + fprintf(stderr, "\t\twhere mode can be specified as:\n"); + fprintf(stderr, "\t\tx[-]\n"); + fprintf(stderr, "\t\t,,,,,,,-\n"); + fprintf(stderr, "\t\t#\n"); fprintf(stderr, "\t-C\ttest hw cursor\n"); fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); fprintf(stderr, "\t-r\tset the preferred mode for all connectors\n"); - fprintf(stderr, "\t-w ::\tset property\n"); + fprintf(stderr, "\t-w ::\tset property, see 'property'\n"); fprintf(stderr, "\t-a \tuse atomic API\n"); fprintf(stderr, "\t-F pattern1,pattern2\tspecify fill patterns\n"); + fprintf(stderr, "\t-o \t Dump writeback output buffer to file\n"); fprintf(stderr, "\n Generic options:\n\n"); fprintf(stderr, "\t-d\tdrop master after mode set\n"); @@ -2014,10 +2157,29 @@ static void usage(char *name) fprintf(stderr, "\t-D device\tuse the given device\n"); fprintf(stderr, "\n\tDefault is to dump all info.\n"); + + fprintf(stderr, "\n"); + fprintf(stderr, "Plane Topology is defined as:\n"); + fprintf(stderr, "\tplane-topology\t::= plane-id '@' crtc-id ':' width 'x' height ( )? ;\n"); + fprintf(stderr, "\tplane-offsets\t::= '+' x-offset '+' y-offset ( )? ;\n"); + fprintf(stderr, "\tplane-scale\t::= '*' scale ( )? ;\n"); + fprintf(stderr, "\tplane-format\t::= '@' format ;\n"); + + fprintf(stderr, "\n"); + fprintf(stderr, "Mode Topology is defined as:\n"); + fprintf(stderr, "\tmode-topology\t::= connector-id ( ',' connector-id )* ( '@' crtc-id )? ':' ( '@' format )? ;\n"); + fprintf(stderr, "\tmode-selection\t::= | | ;\n"); + fprintf(stderr, "\tindexed-mode\t::= '#' mode-index ;\n"); + fprintf(stderr, "\tnamed-mode\t::= width 'x' height ( '-' vrefresh )? ;\n"); + fprintf(stderr, "\tcustom-mode\t::= hdisplay ',' hsyncstart ',' hsyncend ',' htotal ',' vdisplay ',' vsyncstart ',' vsyncend ',' vtotal '-' vrefresh ;\n"); + + fprintf(stderr, "\n"); + fprintf(stderr, "Property is defined as:\n"); + fprintf(stderr, "\tproperty\t::= object-id ':' property-name ':' value ;\n"); exit(0); } -static char optstr[] = "acdD:efF:M:P:ps:Cvrw:"; +static char optstr[] = "acdD:efF:M:P:ps:Cvrw:o:"; int main(int argc, char **argv) { @@ -2040,6 +2202,7 @@ int main(int argc, char **argv) struct property_arg *prop_args = NULL; unsigned int args = 0; int ret; + char *dump_path = NULL; memset(&dev, 0, sizeof dev); @@ -2078,6 +2241,9 @@ int main(int argc, char **argv) /* Preserve the default behaviour of dumping all information. */ args--; break; + case 'o': + dump_path = optarg; + break; case 'P': plane_args = realloc(plane_args, (plane_count + 1) * sizeof *plane_args); @@ -2143,8 +2309,8 @@ int main(int argc, char **argv) if (!args) encoders = connectors = crtcs = planes = framebuffers = 1; - if (test_vsync && !count) { - fprintf(stderr, "page flipping requires at least one -s option.\n"); + if (test_vsync && !count && !set_preferred) { + fprintf(stderr, "page flipping requires at least one -s or -r option.\n"); return -1; } if (set_preferred && count) { @@ -2152,17 +2318,13 @@ int main(int argc, char **argv) return -1; } - if (set_preferred && plane_count) { - fprintf(stderr, "cannot use -r (preferred) when -P (plane) is set\n"); - return -1; - } - dev.fd = util_open(device, module); if (dev.fd < 0) return -1; if (use_atomic) { ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1); + drmSetClientCap(dev.fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1); if (ret) { fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno)); drmClose(dev.fd); @@ -2186,12 +2348,13 @@ int main(int argc, char **argv) dump_resource(&dev, planes); dump_resource(&dev, framebuffers); + if (dev.use_atomic) + dev.req = drmModeAtomicAlloc(); + for (i = 0; i < prop_count; ++i) set_property(&dev, &prop_args[i]); if (dev.use_atomic) { - dev.req = drmModeAtomicAlloc(); - if (set_preferred || (count && plane_count)) { uint64_t cap = 0; @@ -2202,7 +2365,16 @@ int main(int argc, char **argv) } if (set_preferred || count) - set_mode(&dev, pipe_args, count); + count = set_mode(&dev, &pipe_args, count); + + if (dump_path) { + if (!pipe_has_writeback_connector(&dev, pipe_args, count)) { + fprintf(stderr, "No writeback connector found, can not dump.\n"); + return 1; + } + + writeback_config(&dev, pipe_args, count); + } if (plane_count) atomic_set_planes(&dev, plane_args, plane_count, false); @@ -2213,6 +2385,18 @@ int main(int argc, char **argv) return 1; } + /* + * Since only writeback connectors have an output fb, this should only be + * called for writeback. + */ + if (dump_path) { + ret = poll_writeback_fence(dev.writeback_fence_fd, 1000); + if (ret) + fprintf(stderr, "Poll for writeback error: %d. Skipping Dump.\n", + ret); + dump_output_fb(&dev, pipe_args, dump_path, count); + } + if (test_vsync) atomic_test_page_flip(&dev, pipe_args, plane_args, plane_count); @@ -2230,17 +2414,22 @@ int main(int argc, char **argv) if (count) atomic_clear_mode(&dev, pipe_args, count); - - ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); - if (ret) - fprintf(stderr, "Atomic Commit failed\n"); - - if (plane_count) - atomic_clear_FB(&dev, plane_args, plane_count); } + ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); + if (ret) + fprintf(stderr, "Atomic Commit failed\n"); + + if (count && plane_count) + atomic_clear_FB(&dev, plane_args, plane_count); + drmModeAtomicFree(dev.req); } else { + if (dump_path) { + fprintf(stderr, "writeback / dump is only supported in atomic mode\n"); + return 1; + } + if (set_preferred || count || plane_count) { uint64_t cap = 0; @@ -2251,7 +2440,7 @@ int main(int argc, char **argv) } if (set_preferred || count) - set_mode(&dev, pipe_args, count); + count = set_mode(&dev, &pipe_args, count); if (plane_count) set_planes(&dev, plane_args, plane_count); diff --git a/lib/libdrm/tests/util/format.c b/lib/libdrm/tests/util/format.c index 1ca1b82c..eda3c671 100644 --- a/lib/libdrm/tests/util/format.c +++ b/lib/libdrm/tests/util/format.c @@ -40,7 +40,10 @@ static const struct util_format_info format_info[] = { /* Indexed */ - { DRM_FORMAT_C8, "C8" }, + { DRM_FORMAT_C1, "C1", .ncolors = 2 }, + { DRM_FORMAT_C2, "C2", .ncolors = 4 }, + { DRM_FORMAT_C4, "C4", .ncolors = 16 }, + { DRM_FORMAT_C8, "C8", .ncolors = 256 }, /* YUV packed */ { DRM_FORMAT_UYVY, "UYVY", MAKE_YUV_INFO(YUV_YCbCr | YUV_CY, 2, 2, 2) }, { DRM_FORMAT_VYUY, "VYUY", MAKE_YUV_INFO(YUV_YCrCb | YUV_CY, 2, 2, 2) }, @@ -51,6 +54,11 @@ static const struct util_format_info format_info[] = { { DRM_FORMAT_NV21, "NV21", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 2) }, { DRM_FORMAT_NV16, "NV16", MAKE_YUV_INFO(YUV_YCbCr, 2, 1, 2) }, { DRM_FORMAT_NV61, "NV61", MAKE_YUV_INFO(YUV_YCrCb, 2, 1, 2) }, + { DRM_FORMAT_NV24, "NV24", MAKE_YUV_INFO(YUV_YCbCr, 1, 1, 2) }, + { DRM_FORMAT_NV42, "NV42", MAKE_YUV_INFO(YUV_YCrCb, 1, 1, 2) }, + { DRM_FORMAT_NV15, "NV15", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 2) }, + { DRM_FORMAT_NV20, "NV20", MAKE_YUV_INFO(YUV_YCbCr, 2, 1, 2) }, + { DRM_FORMAT_NV30, "NV30", MAKE_YUV_INFO(YUV_YCbCr, 1, 1, 2) }, /* YUV planar */ { DRM_FORMAT_YUV420, "YU12", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 1) }, { DRM_FORMAT_YVU420, "YV12", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 1) }, @@ -73,6 +81,9 @@ static const struct util_format_info format_info[] = { { DRM_FORMAT_BGRX5551, "BX15", MAKE_RGB_INFO(5, 1, 5, 6, 5, 11, 0, 0) }, { DRM_FORMAT_RGB565, "RG16", MAKE_RGB_INFO(5, 11, 6, 5, 5, 0, 0, 0) }, { DRM_FORMAT_BGR565, "BG16", MAKE_RGB_INFO(5, 0, 6, 5, 5, 11, 0, 0) }, + /* Big-endian RGB16 */ + { DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN, "XR15_BE", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 0, 0) }, + { DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN, "RG16_BE", MAKE_RGB_INFO(5, 11, 6, 5, 5, 0, 0, 0) }, /* RGB24 */ { DRM_FORMAT_BGR888, "BG24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) }, { DRM_FORMAT_RGB888, "RG24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) }, diff --git a/lib/libdrm/tests/util/format.h b/lib/libdrm/tests/util/format.h index 2ce1c021..b847c9f2 100644 --- a/lib/libdrm/tests/util/format.h +++ b/lib/libdrm/tests/util/format.h @@ -55,6 +55,7 @@ struct util_yuv_info { struct util_format_info { uint32_t format; const char *name; + unsigned int ncolors; const struct util_rgb_info rgb; const struct util_yuv_info yuv; }; diff --git a/lib/libdrm/tests/util/kms.c b/lib/libdrm/tests/util/kms.c index 95b7a455..34a84180 100644 --- a/lib/libdrm/tests/util/kms.c +++ b/lib/libdrm/tests/util/kms.c @@ -125,6 +125,7 @@ static const char * const modules[] = { "mxsfb-drm", "simpledrm", "imx-lcdif", + "vkms", }; int util_open(const char *device, const char *module) diff --git a/lib/libdrm/tests/util/pattern.c b/lib/libdrm/tests/util/pattern.c index 158c0b16..2ff9c033 100644 --- a/lib/libdrm/tests/util/pattern.c +++ b/lib/libdrm/tests/util/pattern.c @@ -23,6 +23,7 @@ * IN THE SOFTWARE. */ +#include #include #include #include @@ -61,6 +62,33 @@ struct color_yuv { .u = MAKE_YUV_601_U(r, g, b), \ .v = MAKE_YUV_601_V(r, g, b) } +static inline uint16_t swap16(uint16_t x) +{ + return ((x & 0x00ffU) << 8) | ((x & 0xff00U) >> 8); +} + +static inline uint32_t swap32(uint32_t x) +{ + return ((x & 0x000000ffU) << 24) | + ((x & 0x0000ff00U) << 8) | + ((x & 0x00ff0000U) >> 8) | + ((x & 0xff000000U) >> 24); +} + +#ifdef HAVE_BIG_ENDIAN +#define cpu_to_be16(x) (x) +#define cpu_to_le16(x) swap16(x) +#define cpu_to_le32(x) swap32(x) +#define fb_foreign_endian(format) (!((format) & DRM_FORMAT_BIG_ENDIAN)) +#else +#define cpu_to_be16(x) swap16(x) +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define fb_foreign_endian(format) ((format) & DRM_FORMAT_BIG_ENDIAN) +#endif + +#define cpu_to_fb16(x) (fb_be ? cpu_to_be16(x) : cpu_to_le16(x)) + /* This function takes 8-bit color values */ static inline uint32_t shiftcolor8(const struct util_color_component *comp, uint32_t value) @@ -162,7 +190,7 @@ static void fill_smpte_yuv_planar(const struct util_yuv_info *yuv, unsigned int height, unsigned int stride) { const struct color_yuv colors_top[] = { - MAKE_YUV_601(191, 192, 192), /* grey */ + MAKE_YUV_601(192, 192, 192), /* grey */ MAKE_YUV_601(192, 192, 0), /* yellow */ MAKE_YUV_601(0, 192, 192), /* cyan */ MAKE_YUV_601(0, 192, 0), /* green */ @@ -260,12 +288,154 @@ static void fill_smpte_yuv_planar(const struct util_yuv_info *yuv, } } +static void write_pixels_10bpp(unsigned char *mem, + unsigned short a, + unsigned short b, + unsigned short c, + unsigned short d) +{ + mem[0] = (a & 0xff); + mem[1] = ((a >> 8) & 0x3) | ((b & 0x3f) << 2); + mem[2] = ((b >> 6) & 0xf) | ((c & 0xf) << 4); + mem[3] = ((c >> 4) & 0x3f) | ((d & 0x3) << 6); + mem[4] = ((d >> 2) & 0xff); +} + +static void fill_smpte_yuv_planar_10bpp(const struct util_yuv_info *yuv, + unsigned char *y_mem, + unsigned char *uv_mem, + unsigned int width, + unsigned int height, + unsigned int stride) +{ + const struct color_yuv colors_top[] = { + MAKE_YUV_601(192, 192, 192), /* grey */ + MAKE_YUV_601(192, 192, 0), /* yellow */ + MAKE_YUV_601(0, 192, 192), /* cyan */ + MAKE_YUV_601(0, 192, 0), /* green */ + MAKE_YUV_601(192, 0, 192), /* magenta */ + MAKE_YUV_601(192, 0, 0), /* red */ + MAKE_YUV_601(0, 0, 192), /* blue */ + }; + const struct color_yuv colors_middle[] = { + MAKE_YUV_601(0, 0, 192), /* blue */ + MAKE_YUV_601(19, 19, 19), /* black */ + MAKE_YUV_601(192, 0, 192), /* magenta */ + MAKE_YUV_601(19, 19, 19), /* black */ + MAKE_YUV_601(0, 192, 192), /* cyan */ + MAKE_YUV_601(19, 19, 19), /* black */ + MAKE_YUV_601(192, 192, 192), /* grey */ + }; + const struct color_yuv colors_bottom[] = { + MAKE_YUV_601(0, 33, 76), /* in-phase */ + MAKE_YUV_601(255, 255, 255), /* super white */ + MAKE_YUV_601(50, 0, 106), /* quadrature */ + MAKE_YUV_601(19, 19, 19), /* black */ + MAKE_YUV_601(9, 9, 9), /* 3.5% */ + MAKE_YUV_601(19, 19, 19), /* 7.5% */ + MAKE_YUV_601(29, 29, 29), /* 11.5% */ + MAKE_YUV_601(19, 19, 19), /* black */ + }; + unsigned int cs = yuv->chroma_stride; + unsigned int xsub = yuv->xsub; + unsigned int ysub = yuv->ysub; + unsigned int xstep = cs * xsub; + unsigned int x; + unsigned int y; + + /* Luma */ + for (y = 0; y < height * 6 / 9; ++y) { + for (x = 0; x < width; x += 4) + write_pixels_10bpp(&y_mem[(x * 5) / 4], + colors_top[(x+0) * 7 / width].y << 2, + colors_top[(x+1) * 7 / width].y << 2, + colors_top[(x+2) * 7 / width].y << 2, + colors_top[(x+3) * 7 / width].y << 2); + y_mem += stride; + } + + for (; y < height * 7 / 9; ++y) { + for (x = 0; x < width; x += 4) + write_pixels_10bpp(&y_mem[(x * 5) / 4], + colors_middle[(x+0) * 7 / width].y << 2, + colors_middle[(x+1) * 7 / width].y << 2, + colors_middle[(x+2) * 7 / width].y << 2, + colors_middle[(x+3) * 7 / width].y << 2); + y_mem += stride; + } + + for (; y < height; ++y) { + for (x = 0; x < width * 5 / 7; x += 4) + write_pixels_10bpp(&y_mem[(x * 5) / 4], + colors_bottom[(x+0) * 4 / (width * 5 / 7)].y << 2, + colors_bottom[(x+1) * 4 / (width * 5 / 7)].y << 2, + colors_bottom[(x+2) * 4 / (width * 5 / 7)].y << 2, + colors_bottom[(x+3) * 4 / (width * 5 / 7)].y << 2); + for (; x < width * 6 / 7; x += 4) + write_pixels_10bpp(&y_mem[(x * 5) / 4], + colors_bottom[((x+0) - width * 5 / 7) * 3 / (width / 7) + 4].y << 2, + colors_bottom[((x+1) - width * 5 / 7) * 3 / (width / 7) + 4].y << 2, + colors_bottom[((x+2) - width * 5 / 7) * 3 / (width / 7) + 4].y << 2, + colors_bottom[((x+3) - width * 5 / 7) * 3 / (width / 7) + 4].y << 2); + for (; x < width; x += 4) + write_pixels_10bpp(&y_mem[(x * 5) / 4], + colors_bottom[7].y << 2, + colors_bottom[7].y << 2, + colors_bottom[7].y << 2, + colors_bottom[7].y << 2); + y_mem += stride; + } + + /* Chroma */ + for (y = 0; y < height * 6 / 9; y += ysub) { + for (x = 0; x < width; x += xstep) + write_pixels_10bpp(&uv_mem[(x * 5) / xstep], + colors_top[(x+0) * 7 / width].u << 2, + colors_top[(x+0) * 7 / width].v << 2, + colors_top[(x+xsub) * 7 / width].u << 2, + colors_top[(x+xsub) * 7 / width].v << 2); + uv_mem += stride * cs / xsub; + } + + for (; y < height * 7 / 9; y += ysub) { + for (x = 0; x < width; x += xstep) + write_pixels_10bpp(&uv_mem[(x * 5) / xstep], + colors_middle[(x+0) * 7 / width].u << 2, + colors_middle[(x+0) * 7 / width].v << 2, + colors_middle[(x+xsub) * 7 / width].u << 2, + colors_middle[(x+xsub) * 7 / width].v << 2); + uv_mem += stride * cs / xsub; + } + + for (; y < height; y += ysub) { + for (x = 0; x < width * 5 / 7; x += xstep) + write_pixels_10bpp(&uv_mem[(x * 5) / xstep], + colors_bottom[(x+0) * 4 / (width * 5 / 7)].u << 2, + colors_bottom[(x+0) * 4 / (width * 5 / 7)].v << 2, + colors_bottom[(x+xsub) * 4 / (width * 5 / 7)].u << 2, + colors_bottom[(x+xsub) * 4 / (width * 5 / 7)].v << 2); + for (; x < width * 6 / 7; x += xstep) + write_pixels_10bpp(&uv_mem[(x * 5) / xstep], + colors_bottom[((x+0) - width * 5 / 7) * 3 / (width / 7) + 4].u << 2, + colors_bottom[((x+0) - width * 5 / 7) * 3 / (width / 7) + 4].v << 2, + colors_bottom[((x+xsub) - width * 5 / 7) * 3 / (width / 7) + 4].u << 2, + colors_bottom[((x+xsub) - width * 5 / 7) * 3 / (width / 7) + 4].v << 2); + for (; x < width; x += xstep) + write_pixels_10bpp(&uv_mem[(x * 5) / xstep], + colors_bottom[7].u << 2, + colors_bottom[7].v << 2, + colors_bottom[7].u << 2, + colors_bottom[7].v << 2); + uv_mem += stride * cs / xsub; + } +} + static void fill_smpte_yuv_packed(const struct util_yuv_info *yuv, void *mem, unsigned int width, unsigned int height, unsigned int stride) { const struct color_yuv colors_top[] = { - MAKE_YUV_601(191, 192, 192), /* grey */ + MAKE_YUV_601(192, 192, 192), /* grey */ MAKE_YUV_601(192, 192, 0), /* yellow */ MAKE_YUV_601(0, 192, 192), /* cyan */ MAKE_YUV_601(0, 192, 0), /* green */ @@ -361,7 +531,7 @@ static void fill_smpte_yuv_packed(const struct util_yuv_info *yuv, void *mem, static void fill_smpte_rgb16(const struct util_rgb_info *rgb, void *mem, unsigned int width, unsigned int height, - unsigned int stride) + unsigned int stride, bool fb_be) { const uint16_t colors_top[] = { MAKE_RGBA(rgb, 192, 192, 192, 255), /* grey */ @@ -396,26 +566,26 @@ static void fill_smpte_rgb16(const struct util_rgb_info *rgb, void *mem, for (y = 0; y < height * 6 / 9; ++y) { for (x = 0; x < width; ++x) - ((uint16_t *)mem)[x] = colors_top[x * 7 / width]; + ((uint16_t *)mem)[x] = cpu_to_fb16(colors_top[x * 7 / width]); mem += stride; } for (; y < height * 7 / 9; ++y) { for (x = 0; x < width; ++x) - ((uint16_t *)mem)[x] = colors_middle[x * 7 / width]; + ((uint16_t *)mem)[x] = cpu_to_fb16(colors_middle[x * 7 / width]); mem += stride; } for (; y < height; ++y) { for (x = 0; x < width * 5 / 7; ++x) ((uint16_t *)mem)[x] = - colors_bottom[x * 4 / (width * 5 / 7)]; + cpu_to_fb16(colors_bottom[x * 4 / (width * 5 / 7)]); for (; x < width * 6 / 7; ++x) ((uint16_t *)mem)[x] = - colors_bottom[(x - width * 5 / 7) * 3 - / (width / 7) + 4]; + cpu_to_fb16(colors_bottom[(x - width * 5 / 7) * 3 + / (width / 7) + 4]); for (; x < width; ++x) - ((uint16_t *)mem)[x] = colors_bottom[7]; + ((uint16_t *)mem)[x] = cpu_to_fb16(colors_bottom[7]); mem += stride; } } @@ -520,26 +690,26 @@ static void fill_smpte_rgb32(const struct util_rgb_info *rgb, void *mem, for (y = 0; y < height * 6 / 9; ++y) { for (x = 0; x < width; ++x) - ((uint32_t *)mem)[x] = colors_top[x * 7 / width]; + ((uint32_t *)mem)[x] = cpu_to_le32(colors_top[x * 7 / width]); mem += stride; } for (; y < height * 7 / 9; ++y) { for (x = 0; x < width; ++x) - ((uint32_t *)mem)[x] = colors_middle[x * 7 / width]; + ((uint32_t *)mem)[x] = cpu_to_le32(colors_middle[x * 7 / width]); mem += stride; } for (; y < height; ++y) { for (x = 0; x < width * 5 / 7; ++x) ((uint32_t *)mem)[x] = - colors_bottom[x * 4 / (width * 5 / 7)]; + cpu_to_le32(colors_bottom[x * 4 / (width * 5 / 7)]); for (; x < width * 6 / 7; ++x) ((uint32_t *)mem)[x] = - colors_bottom[(x - width * 5 / 7) * 3 - / (width / 7) + 4]; + cpu_to_le32(colors_bottom[(x - width * 5 / 7) * 3 + / (width / 7) + 4]); for (; x < width; ++x) - ((uint32_t *)mem)[x] = colors_bottom[7]; + ((uint32_t *)mem)[x] = cpu_to_le32(colors_bottom[7]); mem += stride; } } @@ -605,6 +775,370 @@ static void fill_smpte_rgb16fp(const struct util_rgb_info *rgb, void *mem, } } +enum smpte_colors { + SMPTE_COLOR_GREY, + SMPTE_COLOR_YELLOW, + SMPTE_COLOR_CYAN, + SMPTE_COLOR_GREEN, + SMPTE_COLOR_MAGENTA, + SMPTE_COLOR_RED, + SMPTE_COLOR_BLUE, + SMPTE_COLOR_BLACK, + SMPTE_COLOR_IN_PHASE, + SMPTE_COLOR_SUPER_WHITE, + SMPTE_COLOR_QUADRATURE, + SMPTE_COLOR_3PC5, + SMPTE_COLOR_11PC5, +}; + +static unsigned int smpte_top[7] = { + SMPTE_COLOR_GREY, + SMPTE_COLOR_YELLOW, + SMPTE_COLOR_CYAN, + SMPTE_COLOR_GREEN, + SMPTE_COLOR_MAGENTA, + SMPTE_COLOR_RED, + SMPTE_COLOR_BLUE, +}; + +static unsigned int smpte_middle[7] = { + SMPTE_COLOR_BLUE, + SMPTE_COLOR_BLACK, + SMPTE_COLOR_MAGENTA, + SMPTE_COLOR_BLACK, + SMPTE_COLOR_CYAN, + SMPTE_COLOR_BLACK, + SMPTE_COLOR_GREY, +}; + +static unsigned int smpte_bottom[8] = { + SMPTE_COLOR_IN_PHASE, + SMPTE_COLOR_SUPER_WHITE, + SMPTE_COLOR_QUADRATURE, + SMPTE_COLOR_BLACK, + SMPTE_COLOR_3PC5, + SMPTE_COLOR_BLACK, + SMPTE_COLOR_11PC5, + SMPTE_COLOR_BLACK, +}; + +#define EXPAND_COLOR(r, g, b) { (r) * 0x101, (g) * 0x101, (b) * 0x101 } + +static const struct drm_color_lut bw_color_lut[] = { + EXPAND_COLOR( 0, 0, 0), /* black */ + EXPAND_COLOR(255, 255, 255), /* white */ +}; + +static const struct drm_color_lut pentile_color_lut[] = { + /* PenTile RG-GB */ + EXPAND_COLOR( 0, 0, 0), /* black */ + EXPAND_COLOR(255, 0, 0), /* red */ + EXPAND_COLOR( 0, 207, 0), /* green */ + EXPAND_COLOR( 0, 0, 255), /* blue */ +}; + +static const struct drm_color_lut smpte_color_lut[] = { + [SMPTE_COLOR_GREY] = EXPAND_COLOR(192, 192, 192), + [SMPTE_COLOR_YELLOW] = EXPAND_COLOR(192, 192, 0), + [SMPTE_COLOR_CYAN] = EXPAND_COLOR( 0, 192, 192), + [SMPTE_COLOR_GREEN] = EXPAND_COLOR( 0, 192, 0), + [SMPTE_COLOR_MAGENTA] = EXPAND_COLOR(192, 0, 192), + [SMPTE_COLOR_RED] = EXPAND_COLOR(192, 0, 0), + [SMPTE_COLOR_BLUE] = EXPAND_COLOR( 0, 0, 192), + [SMPTE_COLOR_BLACK] = EXPAND_COLOR( 19, 19, 19), + [SMPTE_COLOR_IN_PHASE] = EXPAND_COLOR( 0, 33, 76), + [SMPTE_COLOR_SUPER_WHITE] = EXPAND_COLOR(255, 255, 255), + [SMPTE_COLOR_QUADRATURE] = EXPAND_COLOR( 50, 0, 106), + [SMPTE_COLOR_3PC5] = EXPAND_COLOR( 9, 9, 9), + [SMPTE_COLOR_11PC5] = EXPAND_COLOR( 29, 29, 29), +}; + +#undef EXPAND_COLOR + +/* + * Floyd-Steinberg dithering + */ + +struct fsd { + unsigned int width; + unsigned int x; + unsigned int i; + int red; + int green; + int blue; + int error[]; +}; + +static struct fsd *fsd_alloc(unsigned int width) +{ + unsigned int n = 3 * (width + 1); + struct fsd *fsd = malloc(sizeof(*fsd) + n * sizeof(fsd->error[0])); + + fsd->width = width; + fsd->x = 0; + fsd->i = 0; + memset(fsd->error, 0, n * sizeof(fsd->error[0])); + + return fsd; +} + +static inline int clamp(int val, int min, int max) +{ + if (val < min) + return min; + if (val > max) + return max; + return val; +} + +static void fsd_dither(struct fsd *fsd, struct drm_color_lut *color) +{ + unsigned int i = fsd->i; + + fsd->red = (int)color->red + (fsd->error[3 * i] + 8) / 16; + fsd->green = (int)color->green + (fsd->error[3 * i + 1] + 8) / 16; + fsd->blue = (int)color->blue + (fsd->error[3 * i + 2] + 8) / 16; + + color->red = clamp(fsd->red, 0, 65535); + color->green = clamp(fsd->green, 0, 65535); + color->blue = clamp(fsd->blue, 0, 65535); +} + +static void fsd_update(struct fsd *fsd, const struct drm_color_lut *actual) +{ + int error_red = fsd->red - (int)actual->red; + int error_green = fsd->green - (int)actual->green; + int error_blue = fsd->blue - (int)actual->blue; + unsigned int width = fsd->width; + unsigned int i = fsd->i, j; + unsigned int n = width + 1; + + /* Distribute errors over neighboring pixels */ + if (fsd->x == width - 1) { + /* Last pixel on this scanline */ + /* South East: initialize to zero */ + fsd->error[3 * i] = 0; + fsd->error[3 * i + 1] = 0; + fsd->error[3 * i + 2] = 0; + } else { + /* East: accumulate error */ + j = (i + 1) % n; + fsd->error[3 * j] += 7 * error_red; + fsd->error[3 * j + 1] += 7 * error_green; + fsd->error[3 * j + 2] += 7 * error_blue; + + /* South East: initial error */ + fsd->error[3 * i] = error_red; + fsd->error[3 * i + 1] = error_green; + fsd->error[3 * i + 2] = error_blue; + } + /* South West: accumulate error */ + j = (i + width - 1) % n; + fsd->error[3 * j] += 3 * error_red; + fsd->error[3 * j + 1] += 3 * error_green; + fsd->error[3 * j + 2] += 3 * error_blue; + + /* South: accumulate error */ + j = (i + width) % n; + fsd->error[3 * j] += 5 * error_red; + fsd->error[3 * j + 1] += 5 * error_green; + fsd->error[3 * j + 2] += 5 * error_blue; + + fsd->x = (fsd->x + 1) % width; + fsd->i = (fsd->i + 1) % n; +} + +static void write_pixel_1(uint8_t *mem, unsigned int x, unsigned int pixel) +{ + unsigned int shift = 7 - (x & 7); + unsigned int mask = 1U << shift; + + mem[x / 8] = (mem[x / 8] & ~mask) | ((pixel << shift) & mask); +} + +static void write_color_1(struct fsd *fsd, uint8_t *mem, unsigned int x, + unsigned int index) +{ + struct drm_color_lut color = smpte_color_lut[index]; + unsigned int pixel; + + fsd_dither(fsd, &color); + + /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */ + if (3 * color.red + 6 * color.green + color.blue >= 10 * 32768) { + pixel = 1; + color.red = color.green = color.blue = 65535; + } else { + pixel = 0; + color.red = color.green = color.blue = 0; + } + + fsd_update(fsd, &color); + + write_pixel_1(mem, x, pixel); +} + +static void fill_smpte_c1(void *mem, unsigned int width, unsigned int height, + unsigned int stride) +{ + struct fsd *fsd = fsd_alloc(width); + unsigned int x; + unsigned int y; + + for (y = 0; y < height * 6 / 9; ++y) { + for (x = 0; x < width; ++x) + write_color_1(fsd, mem, x, smpte_top[x * 7 / width]); + mem += stride; + } + + for (; y < height * 7 / 9; ++y) { + for (x = 0; x < width; ++x) + write_color_1(fsd, mem, x, smpte_middle[x * 7 / width]); + mem += stride; + } + + for (; y < height; ++y) { + for (x = 0; x < width * 5 / 7; ++x) + write_color_1(fsd, mem, x, + smpte_bottom[x * 4 / (width * 5 / 7)]); + for (; x < width * 6 / 7; ++x) + write_color_1(fsd, mem, x, + smpte_bottom[(x - width * 5 / 7) * 3 / + (width / 7) + 4]); + for (; x < width; ++x) + write_color_1(fsd, mem, x, smpte_bottom[7]); + mem += stride; + } + + free(fsd); +} + +static void write_pixel_2(uint8_t *mem, unsigned int x, unsigned int pixel) +{ + unsigned int shift = 6 - 2 * (x & 3); + unsigned int mask = 3U << shift; + + mem[x / 4] = (mem[x / 4] & ~mask) | ((pixel << shift) & mask); +} + +static void write_color_2(struct fsd *fsd, uint8_t *mem, unsigned int stride, + unsigned int x, unsigned int index) +{ + struct drm_color_lut color = smpte_color_lut[index]; + unsigned int r, g, b; + + fsd_dither(fsd, &color); + + if (color.red >= 32768) { + r = 1; + color.red = 65535; + } else { + r = 0; + color.red = 0; + } + if (color.green >= 32768) { + g = 2; + color.green = 65535; + } else { + g = 0; + color.green = 0; + } + if (color.blue >= 32768) { + b = 3; + color.blue = 65535; + } else { + b = 0; + color.blue = 0; + } + + fsd_update(fsd, &color); + + /* Use PenTile RG-GB */ + write_pixel_2(mem, 2 * x, r); + write_pixel_2(mem, 2 * x + 1, g); + write_pixel_2(mem + stride, 2 * x, g); + write_pixel_2(mem + stride, 2 * x + 1, b); +} + +static void fill_smpte_c2(void *mem, unsigned int width, unsigned int height, + unsigned int stride) +{ + struct fsd *fsd = fsd_alloc(width); + unsigned int x; + unsigned int y; + + /* Half resolution for PenTile RG-GB */ + width /= 2; + height /= 2; + + for (y = 0; y < height * 6 / 9; ++y) { + for (x = 0; x < width; ++x) + write_color_2(fsd, mem, stride, x, smpte_top[x * 7 / width]); + mem += 2 * stride; + } + + for (; y < height * 7 / 9; ++y) { + for (x = 0; x < width; ++x) + write_color_2(fsd, mem, stride, x, smpte_middle[x * 7 / width]); + mem += 2 * stride; + } + + for (; y < height; ++y) { + for (x = 0; x < width * 5 / 7; ++x) + write_color_2(fsd, mem, stride, x, + smpte_bottom[x * 4 / (width * 5 / 7)]); + for (; x < width * 6 / 7; ++x) + write_color_2(fsd, mem, stride, x, + smpte_bottom[(x - width * 5 / 7) * 3 / + (width / 7) + 4]); + for (; x < width; ++x) + write_color_2(fsd, mem, stride, x, smpte_bottom[7]); + mem += 2 * stride; + } + + free(fsd); +} + +static void write_pixel_4(uint8_t *mem, unsigned int x, unsigned int pixel) +{ + if (x & 1) + mem[x / 2] = (mem[x / 2] & 0xf0) | (pixel & 0x0f); + else + mem[x / 2] = (mem[x / 2] & 0x0f) | (pixel << 4); +} + +static void fill_smpte_c4(void *mem, unsigned int width, unsigned int height, + unsigned int stride) +{ + unsigned int x; + unsigned int y; + + for (y = 0; y < height * 6 / 9; ++y) { + for (x = 0; x < width; ++x) + write_pixel_4(mem, x, smpte_top[x * 7 / width]); + mem += stride; + } + + for (; y < height * 7 / 9; ++y) { + for (x = 0; x < width; ++x) + write_pixel_4(mem, x, smpte_middle[x * 7 / width]); + mem += stride; + } + + for (; y < height; ++y) { + for (x = 0; x < width * 5 / 7; ++x) + write_pixel_4(mem, x, + smpte_bottom[x * 4 / (width * 5 / 7)]); + for (; x < width * 6 / 7; ++x) + write_pixel_4(mem, x, + smpte_bottom[(x - width * 5 / 7) * 3 / + (width / 7) + 4]); + for (; x < width; ++x) + write_pixel_4(mem, x, smpte_bottom[7]); + mem += stride; + } +} + static void fill_smpte_c8(void *mem, unsigned int width, unsigned int height, unsigned int stride) { @@ -613,69 +1147,45 @@ static void fill_smpte_c8(void *mem, unsigned int width, unsigned int height, for (y = 0; y < height * 6 / 9; ++y) { for (x = 0; x < width; ++x) - ((uint8_t *)mem)[x] = x * 7 / width; + ((uint8_t *)mem)[x] = smpte_top[x * 7 / width]; mem += stride; } for (; y < height * 7 / 9; ++y) { for (x = 0; x < width; ++x) - ((uint8_t *)mem)[x] = 7 + (x * 7 / width); + ((uint8_t *)mem)[x] = smpte_middle[x * 7 / width]; mem += stride; } for (; y < height; ++y) { for (x = 0; x < width * 5 / 7; ++x) ((uint8_t *)mem)[x] = - 14 + (x * 4 / (width * 5 / 7)); + smpte_bottom[x * 4 / (width * 5 / 7)]; for (; x < width * 6 / 7; ++x) ((uint8_t *)mem)[x] = - 14 + ((x - width * 5 / 7) * 3 - / (width / 7) + 4); + smpte_bottom[(x - width * 5 / 7) * 3 + / (width / 7) + 4]; for (; x < width; ++x) - ((uint8_t *)mem)[x] = 14 + 7; + ((uint8_t *)mem)[x] = smpte_bottom[7]; mem += stride; } } -void util_smpte_c8_gamma(unsigned size, struct drm_color_lut *lut) +void util_smpte_fill_lut(unsigned int ncolors, struct drm_color_lut *lut) { - if (size < 7 + 7 + 8) { - printf("Error: gamma too small: %d < %d\n", size, 7 + 7 + 8); + if (ncolors < ARRAY_SIZE(bw_color_lut)) { + printf("Error: lut too small: %u < %zu\n", ncolors, + ARRAY_SIZE(bw_color_lut)); return; } - memset(lut, 0, size * sizeof(struct drm_color_lut)); + memset(lut, 0, ncolors * sizeof(struct drm_color_lut)); -#define FILL_COLOR(idx, r, g, b) \ - lut[idx].red = (r) << 8; \ - lut[idx].green = (g) << 8; \ - lut[idx].blue = (b) << 8 - - FILL_COLOR( 0, 192, 192, 192); /* grey */ - FILL_COLOR( 1, 192, 192, 0 ); /* yellow */ - FILL_COLOR( 2, 0, 192, 192); /* cyan */ - FILL_COLOR( 3, 0, 192, 0 ); /* green */ - FILL_COLOR( 4, 192, 0, 192); /* magenta */ - FILL_COLOR( 5, 192, 0, 0 ); /* red */ - FILL_COLOR( 6, 0, 0, 192); /* blue */ - - FILL_COLOR( 7, 0, 0, 192); /* blue */ - FILL_COLOR( 8, 19, 19, 19 ); /* black */ - FILL_COLOR( 9, 192, 0, 192); /* magenta */ - FILL_COLOR(10, 19, 19, 19 ); /* black */ - FILL_COLOR(11, 0, 192, 192); /* cyan */ - FILL_COLOR(12, 19, 19, 19 ); /* black */ - FILL_COLOR(13, 192, 192, 192); /* grey */ - - FILL_COLOR(14, 0, 33, 76); /* in-phase */ - FILL_COLOR(15, 255, 255, 255); /* super white */ - FILL_COLOR(16, 50, 0, 106); /* quadrature */ - FILL_COLOR(17, 19, 19, 19); /* black */ - FILL_COLOR(18, 9, 9, 9); /* 3.5% */ - FILL_COLOR(19, 19, 19, 19); /* 7.5% */ - FILL_COLOR(20, 29, 29, 29); /* 11.5% */ - FILL_COLOR(21, 19, 19, 19); /* black */ - -#undef FILL_COLOR + if (ncolors < ARRAY_SIZE(pentile_color_lut)) + memcpy(lut, bw_color_lut, sizeof(bw_color_lut)); + else if (ncolors < ARRAY_SIZE(smpte_color_lut)) + memcpy(lut, pentile_color_lut, sizeof(pentile_color_lut)); + else + memcpy(lut, smpte_color_lut, sizeof(smpte_color_lut)); } static void fill_smpte(const struct util_format_info *info, void *planes[3], @@ -685,6 +1195,12 @@ static void fill_smpte(const struct util_format_info *info, void *planes[3], unsigned char *u, *v; switch (info->format) { + case DRM_FORMAT_C1: + return fill_smpte_c1(planes[0], width, height, stride); + case DRM_FORMAT_C2: + return fill_smpte_c2(planes[0], width, height, stride); + case DRM_FORMAT_C4: + return fill_smpte_c4(planes[0], width, height, stride); case DRM_FORMAT_C8: return fill_smpte_c8(planes[0], width, height, stride); case DRM_FORMAT_UYVY: @@ -698,11 +1214,20 @@ static void fill_smpte(const struct util_format_info *info, void *planes[3], case DRM_FORMAT_NV21: case DRM_FORMAT_NV16: case DRM_FORMAT_NV61: + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: u = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1; v = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1; return fill_smpte_yuv_planar(&info->yuv, planes[0], u, v, width, height, stride); + case DRM_FORMAT_NV15: + case DRM_FORMAT_NV20: + case DRM_FORMAT_NV30: + return fill_smpte_yuv_planar_10bpp(&info->yuv, planes[0], + planes[1], width, height, + stride); + case DRM_FORMAT_YUV420: return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[1], planes[2], width, height, stride); @@ -720,9 +1245,11 @@ static void fill_smpte(const struct util_format_info *info, void *planes[3], case DRM_FORMAT_BGRA4444: case DRM_FORMAT_BGRX4444: case DRM_FORMAT_RGB565: + case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN: case DRM_FORMAT_BGR565: case DRM_FORMAT_ARGB1555: case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN: case DRM_FORMAT_ABGR1555: case DRM_FORMAT_XBGR1555: case DRM_FORMAT_RGBA5551: @@ -730,7 +1257,8 @@ static void fill_smpte(const struct util_format_info *info, void *planes[3], case DRM_FORMAT_BGRA5551: case DRM_FORMAT_BGRX5551: return fill_smpte_rgb16(&info->rgb, planes[0], - width, height, stride); + width, height, stride, + info->format & DRM_FORMAT_BIG_ENDIAN); case DRM_FORMAT_BGR888: case DRM_FORMAT_RGB888: @@ -764,10 +1292,31 @@ static void fill_smpte(const struct util_format_info *info, void *planes[3], } } -/* swap these for big endian.. */ -#define RED 2 -#define GREEN 1 -#define BLUE 0 +#if HAVE_CAIRO +static void byteswap_buffer16(void *mem, unsigned int width, unsigned int height, + unsigned int stride) +{ + unsigned int x, y; + + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) + ((uint16_t *)mem)[x] = swap16(((uint16_t *)mem)[x]); + mem += stride; + } +} + +static void byteswap_buffer32(void *mem, unsigned int width, unsigned int height, + unsigned int stride) +{ + unsigned int x, y; + + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) + ((uint32_t *)mem)[x] = swap32(((uint32_t *)mem)[x]); + mem += stride; + } +} +#endif static void make_pwetty(void *data, unsigned int width, unsigned int height, unsigned int stride, uint32_t format) @@ -776,6 +1325,8 @@ static void make_pwetty(void *data, unsigned int width, unsigned int height, cairo_surface_t *surface; cairo_t *cr; cairo_format_t cairo_format; + bool swap16 = false; + bool swap32 = false; /* we can ignore the order of R,G,B channels */ switch (format) { @@ -786,8 +1337,10 @@ static void make_pwetty(void *data, unsigned int width, unsigned int height, cairo_format = CAIRO_FORMAT_ARGB32; break; case DRM_FORMAT_RGB565: + case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN: case DRM_FORMAT_BGR565: cairo_format = CAIRO_FORMAT_RGB16_565; + swap16 = fb_foreign_endian(format); break; #if CAIRO_VERSION_MAJOR > 1 || (CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR >= 12) case DRM_FORMAT_ARGB2101010: @@ -795,12 +1348,19 @@ static void make_pwetty(void *data, unsigned int width, unsigned int height, case DRM_FORMAT_ABGR2101010: case DRM_FORMAT_XBGR2101010: cairo_format = CAIRO_FORMAT_RGB30; + swap32 = fb_foreign_endian(format); break; #endif default: return; } + /* Cairo uses native byte order, so we may have to byteswap before... */ + if (swap16) + byteswap_buffer16(data, width, height, stride); + if (swap32) + byteswap_buffer32(data, width, height, stride); + surface = cairo_image_surface_create_for_data(data, cairo_format, width, height, @@ -836,9 +1396,27 @@ static void make_pwetty(void *data, unsigned int width, unsigned int height, } cairo_destroy(cr); + + /* ... and after */ + if (swap16) + byteswap_buffer16(data, width, height, stride); + if (swap32) + byteswap_buffer32(data, width, height, stride); #endif } +static struct color_yuv make_tiles_yuv_color(unsigned int x, unsigned int y, + unsigned int width) +{ + div_t d = div(x+y, width); + uint32_t rgb32 = 0x00130502 * (d.quot >> 6) + + 0x000a1120 * (d.rem >> 6); + struct color_yuv color = + MAKE_YUV_601((rgb32 >> 16) & 0xff, (rgb32 >> 8) & 0xff, + rgb32 & 0xff); + return color; +} + static void fill_tiles_yuv_planar(const struct util_format_info *info, unsigned char *y_mem, unsigned char *u_mem, unsigned char *v_mem, unsigned int width, @@ -853,12 +1431,8 @@ static void fill_tiles_yuv_planar(const struct util_format_info *info, for (y = 0; y < height; ++y) { for (x = 0; x < width; ++x) { - div_t d = div(x+y, width); - uint32_t rgb32 = 0x00130502 * (d.quot >> 6) - + 0x000a1120 * (d.rem >> 6); struct color_yuv color = - MAKE_YUV_601((rgb32 >> 16) & 0xff, - (rgb32 >> 8) & 0xff, rgb32 & 0xff); + make_tiles_yuv_color(x, y, width); y_mem[x] = color.y; u_mem[x/xsub*cs] = color.u; @@ -873,6 +1447,45 @@ static void fill_tiles_yuv_planar(const struct util_format_info *info, } } +static void fill_tiles_yuv_planar_10bpp(const struct util_format_info *info, + unsigned char *y_mem, + unsigned char *uv_mem, + unsigned int width, + unsigned int height, + unsigned int stride) +{ + const struct util_yuv_info *yuv = &info->yuv; + unsigned int cs = yuv->chroma_stride; + unsigned int xsub = yuv->xsub; + unsigned int ysub = yuv->ysub; + unsigned int xstep = cs * xsub; + unsigned int x; + unsigned int y; + + for (y = 0; y < height; ++y) { + for (x = 0; x < width; x += 4) { + struct color_yuv a = make_tiles_yuv_color(x+0, y, width); + struct color_yuv b = make_tiles_yuv_color(x+1, y, width); + struct color_yuv c = make_tiles_yuv_color(x+2, y, width); + struct color_yuv d = make_tiles_yuv_color(x+3, y, width); + + write_pixels_10bpp(&y_mem[(x * 5) / 4], + a.y << 2, b.y << 2, c.y << 2, d.y << 2); + } + y_mem += stride; + } + for (y = 0; y < height; y += ysub) { + for (x = 0; x < width; x += xstep) { + struct color_yuv a = make_tiles_yuv_color(x+0, y, width); + struct color_yuv b = make_tiles_yuv_color(x+xsub, y, width); + + write_pixels_10bpp(&uv_mem[(x * 5) / xstep], + a.u << 2, a.v << 2, b.u << 2, b.v << 2); + } + uv_mem += stride * cs / xsub; + } +} + static void fill_tiles_yuv_packed(const struct util_format_info *info, void *mem, unsigned int width, unsigned int height, unsigned int stride) @@ -887,12 +1500,8 @@ static void fill_tiles_yuv_packed(const struct util_format_info *info, for (y = 0; y < height; ++y) { for (x = 0; x < width; x += 2) { - div_t d = div(x+y, width); - uint32_t rgb32 = 0x00130502 * (d.quot >> 6) - + 0x000a1120 * (d.rem >> 6); struct color_yuv color = - MAKE_YUV_601((rgb32 >> 16) & 0xff, - (rgb32 >> 8) & 0xff, rgb32 & 0xff); + make_tiles_yuv_color(x, y, width); y_mem[2*x] = color.y; c_mem[2*x+u] = color.u; @@ -907,7 +1516,7 @@ static void fill_tiles_yuv_packed(const struct util_format_info *info, static void fill_tiles_rgb16(const struct util_format_info *info, void *mem, unsigned int width, unsigned int height, - unsigned int stride) + unsigned int stride, bool fb_be) { const struct util_rgb_info *rgb = &info->rgb; void *mem_base = mem; @@ -923,7 +1532,7 @@ static void fill_tiles_rgb16(const struct util_format_info *info, void *mem, (rgb32 >> 8) & 0xff, rgb32 & 0xff, 255); - ((uint16_t *)mem)[x] = color; + ((uint16_t *)mem)[x] = cpu_to_fb16(color); } mem += stride; } @@ -972,7 +1581,7 @@ static void fill_tiles_rgb32(const struct util_format_info *info, void *mem, (rgb32 >> 8) & 0xff, rgb32 & 0xff, alpha); - ((uint32_t *)mem)[x] = color; + ((uint32_t *)mem)[x] = cpu_to_le32(color); } mem += stride; } @@ -1023,11 +1632,19 @@ static void fill_tiles(const struct util_format_info *info, void *planes[3], case DRM_FORMAT_NV21: case DRM_FORMAT_NV16: case DRM_FORMAT_NV61: + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: u = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1; v = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1; return fill_tiles_yuv_planar(info, planes[0], u, v, width, height, stride); + case DRM_FORMAT_NV15: + case DRM_FORMAT_NV20: + case DRM_FORMAT_NV30: + return fill_tiles_yuv_planar_10bpp(info, planes[0], planes[1], + width, height, stride); + case DRM_FORMAT_YUV420: return fill_tiles_yuv_planar(info, planes[0], planes[1], planes[2], width, height, stride); @@ -1045,9 +1662,11 @@ static void fill_tiles(const struct util_format_info *info, void *planes[3], case DRM_FORMAT_BGRA4444: case DRM_FORMAT_BGRX4444: case DRM_FORMAT_RGB565: + case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN: case DRM_FORMAT_BGR565: case DRM_FORMAT_ARGB1555: case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN: case DRM_FORMAT_ABGR1555: case DRM_FORMAT_XBGR1555: case DRM_FORMAT_RGBA5551: @@ -1055,7 +1674,8 @@ static void fill_tiles(const struct util_format_info *info, void *planes[3], case DRM_FORMAT_BGRA5551: case DRM_FORMAT_BGRX5551: return fill_tiles_rgb16(info, planes[0], - width, height, stride); + width, height, stride, + info->format & DRM_FORMAT_BIG_ENDIAN); case DRM_FORMAT_BGR888: case DRM_FORMAT_RGB888: @@ -1119,7 +1739,7 @@ static void fill_gradient_rgb32(const struct util_rgb_info *rgb, for (j = 0; j < width / 2; j++) { uint32_t value = MAKE_RGBA10(rgb, j & 0x3ff, j & 0x3ff, j & 0x3ff, 0); - row[2*j] = row[2*j+1] = value; + row[2*j] = row[2*j+1] = cpu_to_le32(value); } mem += stride; } @@ -1129,7 +1749,7 @@ static void fill_gradient_rgb32(const struct util_rgb_info *rgb, for (j = 0; j < width / 2; j++) { uint32_t value = MAKE_RGBA10(rgb, j & 0x3fc, j & 0x3fc, j & 0x3fc, 0); - row[2*j] = row[2*j+1] = value; + row[2*j] = row[2*j+1] = cpu_to_le32(value); } mem += stride; } diff --git a/lib/libdrm/tests/util/pattern.h b/lib/libdrm/tests/util/pattern.h index ea38cafd..e500aba3 100644 --- a/lib/libdrm/tests/util/pattern.h +++ b/lib/libdrm/tests/util/pattern.h @@ -39,7 +39,7 @@ void util_fill_pattern(uint32_t format, enum util_fill_pattern pattern, void *planes[3], unsigned int width, unsigned int height, unsigned int stride); -void util_smpte_c8_gamma(unsigned size, struct drm_color_lut *lut); +void util_smpte_fill_lut(unsigned int ncolors, struct drm_color_lut *lut); enum util_fill_pattern util_pattern_enum(const char *name); diff --git a/lib/libdrm/xf86drm.c b/lib/libdrm/xf86drm.c index e61e3e88..4cd0a488 100644 --- a/lib/libdrm/xf86drm.c +++ b/lib/libdrm/xf86drm.c @@ -833,8 +833,6 @@ static const char *drmGetDeviceName(int type) switch (type) { case DRM_NODE_PRIMARY: return DRM_DEV_NAME; - case DRM_NODE_CONTROL: - return DRM_CONTROL_DEV_NAME; case DRM_NODE_RENDER: return DRM_RENDER_DEV_NAME; } @@ -1053,8 +1051,6 @@ static int drmGetMinorBase(int type) switch (type) { case DRM_NODE_PRIMARY: return 0; - case DRM_NODE_CONTROL: - return 64; case DRM_NODE_RENDER: return 128; default: @@ -1075,8 +1071,6 @@ static int drmGetMinorType(int major, int minor) // If not in /dev/drm/ we have the type in the name if (sscanf(name, "dri/card%d\n", &id) >= 1) return DRM_NODE_PRIMARY; - else if (sscanf(name, "dri/control%d\n", &id) >= 1) - return DRM_NODE_CONTROL; else if (sscanf(name, "dri/renderD%d\n", &id) >= 1) return DRM_NODE_RENDER; return -1; @@ -1084,19 +1078,20 @@ static int drmGetMinorType(int major, int minor) minor = id; #endif - int type = minor >> 6; + char path[DRM_NODE_NAME_MAX]; + const char *dev_name; + int i; - if (minor < 0) - return -1; - - switch (type) { - case DRM_NODE_PRIMARY: - case DRM_NODE_CONTROL: - case DRM_NODE_RENDER: - return type; - default: - return -1; + for (i = DRM_NODE_PRIMARY; i < DRM_NODE_MAX; i++) { + dev_name = drmGetDeviceName(i); + if (!dev_name) + continue; + snprintf(path, sizeof(path), dev_name, DRM_DIR_NAME, minor); + if (!access(path, F_OK)) + return i; } + + return -1; } static const char *drmGetMinorName(int type) @@ -1104,8 +1099,6 @@ static const char *drmGetMinorName(int type) switch (type) { case DRM_NODE_PRIMARY: return DRM_PRIMARY_MINOR_NAME; - case DRM_NODE_CONTROL: - return DRM_CONTROL_MINOR_NAME; case DRM_NODE_RENDER: return DRM_RENDER_MINOR_NAME; default: @@ -1292,7 +1285,7 @@ drm_public int drmOpen(const char *name, const char *busid) * * \param name driver name. Not referenced if bus ID is supplied. * \param busid bus ID. Zero if not known. - * \param type the device node type to open, PRIMARY, CONTROL or RENDER + * \param type the device node type to open, PRIMARY or RENDER * * \return a file descriptor on success, or a negative value on error. * @@ -1325,7 +1318,7 @@ drm_public int drmOpenWithType(const char *name, const char *busid, int type) drm_public int drmOpenControl(int minor) { - return drmOpenMinor(minor, 0, DRM_NODE_CONTROL); + return -EINVAL; } drm_public int drmOpenRender(int minor) @@ -3735,12 +3728,9 @@ static int get_sysctl_pci_bus_info(int maj, int min, drmPciBusInfoPtr info) switch (type) { case DRM_NODE_PRIMARY: break; - case DRM_NODE_CONTROL: - id -= 64; - break; case DRM_NODE_RENDER: id -= 128; - break; + break; } if (id < 0) return -EINVAL; @@ -3852,10 +3842,6 @@ drm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b) static int drmGetNodeType(const char *name) { - if (strncmp(name, DRM_CONTROL_MINOR_NAME, - sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0) - return DRM_NODE_CONTROL; - if (strncmp(name, DRM_RENDER_MINOR_NAME, sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0) return DRM_NODE_RENDER; @@ -4684,6 +4670,23 @@ drm_public int drmGetDeviceFromDevId(dev_t find_rdev, uint32_t flags, drmDeviceP return 0; } +drm_public int drmGetNodeTypeFromDevId(dev_t devid) +{ + int maj, min, node_type; + + maj = major(devid); + min = minor(devid); + + if (!drmNodeIsDRM(maj, min)) + return -EINVAL; + + node_type = drmGetMinorType(maj, min); + if (node_type == -1) + return -ENODEV; + + return node_type; +} + /** * Get information about the opened drm device * @@ -5101,6 +5104,20 @@ drm_public int drmSyncobjTransfer(int fd, return ret; } +drm_public int drmSyncobjEventfd(int fd, uint32_t handle, uint64_t point, int ev_fd, + uint32_t flags) +{ + struct drm_syncobj_eventfd args; + + memclear(args); + args.handle = handle; + args.point = point; + args.fd = ev_fd; + args.flags = flags; + + return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_EVENTFD, &args); +} + static char * drmGetFormatModifierFromSimpleTokens(uint64_t modifier) { diff --git a/lib/libdrm/xf86drm.h b/lib/libdrm/xf86drm.h index 9c626e92..01be1878 100644 --- a/lib/libdrm/xf86drm.h +++ b/lib/libdrm/xf86drm.h @@ -44,7 +44,7 @@ extern "C" { #endif #ifndef DRM_MAX_MINOR -#define DRM_MAX_MINOR 16 +#define DRM_MAX_MINOR 64 /* deprecated */ #endif #if defined(__linux__) @@ -78,12 +78,12 @@ extern "C" { #define DRM_DIR_NAME "/dev/dri" #define DRM_PRIMARY_MINOR_NAME "card" -#define DRM_CONTROL_MINOR_NAME "controlD" +#define DRM_CONTROL_MINOR_NAME "controlD" /* deprecated */ #define DRM_RENDER_MINOR_NAME "renderD" #define DRM_PROC_NAME "/proc/dri/" /* For backward Linux compatibility */ #define DRM_DEV_NAME "%s/" DRM_PRIMARY_MINOR_NAME "%d" -#define DRM_CONTROL_DEV_NAME "%s/" DRM_CONTROL_MINOR_NAME "%d" +#define DRM_CONTROL_DEV_NAME "%s/" DRM_CONTROL_MINOR_NAME "%d" /* deprecated */ #define DRM_RENDER_DEV_NAME "%s/" DRM_RENDER_MINOR_NAME "%d" #define DRM_NODE_NAME_MAX \ @@ -91,7 +91,7 @@ extern "C" { + MAX3(sizeof(DRM_PRIMARY_MINOR_NAME), \ sizeof(DRM_CONTROL_MINOR_NAME), \ sizeof(DRM_RENDER_MINOR_NAME)) \ - + sizeof("144") /* highest possible node number */ \ + + sizeof("1048575") /* highest possible node number 2^MINORBITS - 1 */ \ + 1) /* NULL-terminator */ #define DRM_ERR_NO_DEVICE (-1001) @@ -589,14 +589,14 @@ extern int drmAvailable(void); extern int drmOpen(const char *name, const char *busid); #define DRM_NODE_PRIMARY 0 -#define DRM_NODE_CONTROL 1 +#define DRM_NODE_CONTROL 1 /* deprecated: never returned */ #define DRM_NODE_RENDER 2 #define DRM_NODE_MAX 3 extern int drmOpenWithType(const char *name, const char *busid, int type); -extern int drmOpenControl(int minor); +extern int drmOpenControl(int minor); /* deprecated: always fails */ extern int drmOpenRender(int minor); extern int drmClose(int fd); extern drmVersionPtr drmGetVersion(int fd); @@ -801,7 +801,7 @@ extern int drmHandleEvent(int fd, drmEventContextPtr evctx); extern char *drmGetDeviceNameFromFd(int fd); /* Improved version of drmGetDeviceNameFromFd which attributes for any type of - * device/node - card, control or renderD. + * device/node - card or renderD. */ extern char *drmGetDeviceNameFromFd2(int fd); extern int drmGetNodeTypeFromFd(int fd); @@ -912,6 +912,13 @@ extern int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_device extern int drmGetDeviceFromDevId(dev_t dev_id, uint32_t flags, drmDevicePtr *device); +/** + * Get the node type (DRM_NODE_PRIMARY or DRM_NODE_RENDER) from a device ID. + * + * Returns negative errno on error. + */ +extern int drmGetNodeTypeFromDevId(dev_t devid); + extern int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b); extern int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle); @@ -940,6 +947,8 @@ extern int drmSyncobjTransfer(int fd, uint32_t dst_handle, uint64_t dst_point, uint32_t src_handle, uint64_t src_point, uint32_t flags); +extern int drmSyncobjEventfd(int fd, uint32_t handle, uint64_t point, int ev_fd, + uint32_t flags); extern char * drmGetFormatModifierVendor(uint64_t modifier); diff --git a/lib/libdrm/xf86drmMode.c b/lib/libdrm/xf86drmMode.c index 22a8a7c2..a4873a0f 100644 --- a/lib/libdrm/xf86drmMode.c +++ b/lib/libdrm/xf86drmMode.c @@ -320,6 +320,16 @@ drm_public int drmModeRmFB(int fd, uint32_t bufferId) return DRM_IOCTL(fd, DRM_IOCTL_MODE_RMFB, &bufferId); } +drm_public int drmModeCloseFB(int fd, uint32_t buffer_id) +{ + struct drm_mode_closefb closefb; + + memclear(closefb); + closefb.fb_id = buffer_id; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_CLOSEFB, &closefb); +} + drm_public drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) { struct drm_mode_fb_cmd info; @@ -1004,8 +1014,8 @@ drm_public int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size, } drm_public int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, - uint16_t *red, uint16_t *green, - uint16_t *blue) + const uint16_t *red, const uint16_t *green, + const uint16_t *blue) { struct drm_mode_crtc_lut l; diff --git a/lib/libdrm/xf86drmMode.h b/lib/libdrm/xf86drmMode.h index d911c9a1..08487887 100644 --- a/lib/libdrm/xf86drmMode.h +++ b/lib/libdrm/xf86drmMode.h @@ -314,6 +314,13 @@ int drmModeAddFB2WithModifiers(int fd, uint32_t width, uint32_t height, */ extern int drmModeRmFB(int fd, uint32_t bufferId); +/** + * Close a framebuffer. + * + * Same as drmModeRmFB(), except it doesn't implicitly disable planes and CRTCs. + */ +extern int drmModeCloseFB(int fd, uint32_t buffer_id); + /** * Mark a region of a framebuffer as dirty. */ @@ -416,7 +423,7 @@ extern int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t p extern int drmCheckModesettingSupported(const char *busid); extern int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, - uint16_t *red, uint16_t *green, uint16_t *blue); + const uint16_t *red, const uint16_t *green, const uint16_t *blue); extern int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size, uint16_t *red, uint16_t *green, uint16_t *blue); extern int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id,