1//go:build linux
2
3package vkdevice
4
5import (
6 "fmt"
7 "unsafe"
8
9 "github.com/bnema/purego-vulkan/vulkan"
10 "github.com/bnema/wlturbo/protocol/linuxdmabuf"
11)
12
13// Modifier is the one-plane GPU/compositor common image layout chosen in
14// compositor tranche order. XRGB and ARGB both use B8G8R8A8_UNORM on Vulkan.
15type Modifier struct {
16 DRMFormat uint32
17 Value uint64
18}
19
20const (
21 XRGB8888 uint32 = 0x34325258
22 ARGB8888 uint32 = 0x34325241
23)
24
25func ChooseModifier(tranches [][]linuxdmabuf.FormatEntry, transparent bool, supported map[uint64]bool) (Modifier, error) {
26 format := XRGB8888
27 if transparent {
28 format = ARGB8888
29 }
30 for _, tranche := range tranches {
31 for _, entry := range tranche {
32 if entry.Format == format && supported[entry.Modifier] {
33 return Modifier{format, entry.Modifier}, nil
34 }
35 }
36 }
37 return Modifier{}, fmt.Errorf("no one-plane exportable B8G8R8A8 modifier shared with compositor for DRM format %#x", format)
38}
39
40// ExportableModifiers checks the exact usage required by drawing and readback;
41// the presence of a modifier alone is not sufficient to allocate a DMA-BUF.
42func (d *Device) ExportableModifiers() (map[uint64]bool, error) {
43 props := vulkan.FormatProperties2{SType: vulkan.StructureTypeFormatProperties2}
44 mods := vulkan.DrmFormatModifierPropertiesList2EXT{SType: vulkan.StructureTypeDRMFormatModifierPropertiesList2EXT}
45 props.Next = unsafe.Pointer(&mods)
46 d.InstanceDispatch.GetPhysicalDeviceFormatProperties2(d.Physical, vulkan.FormatB8g8r8a8Unorm, &props)
47 out := make(map[uint64]bool)
48 if mods.DrmFormatModifierCount == 0 {
49 return out, nil
50 }
51 list := make([]vulkan.DrmFormatModifierProperties2EXT, mods.DrmFormatModifierCount)
52 mods.DrmFormatModifierProperties = &list[0]
53 d.InstanceDispatch.GetPhysicalDeviceFormatProperties2(d.Physical, vulkan.FormatB8g8r8a8Unorm, &props)
54 for _, m := range list[:mods.DrmFormatModifierCount] {
55 features := m.DrmFormatModifierTilingFeatures
56 if m.DrmFormatModifierPlaneCount != 1 || features&vulkan.FormatFeature2ColorAttachmentBit == 0 || features&vulkan.FormatFeature2TransferSrcBit == 0 {
57 continue
58 }
59 modifierInfo := vulkan.PhysicalDeviceImageDrmFormatModifierInfoEXT{SType: vulkan.StructureTypePhysicalDeviceImageDRMFormatModifierInfoEXT, DrmFormatModifier: m.DrmFormatModifier, SharingMode: vulkan.SharingModeExclusive}
60 externalInfo := vulkan.PhysicalDeviceExternalImageFormatInfo{SType: vulkan.StructureTypePhysicalDeviceExternalImageFormatInfo, Next: unsafe.Pointer(&modifierInfo), HandleType: vulkan.ExternalMemoryHandleTypeDMABUFBitEXT}
61 info := vulkan.PhysicalDeviceImageFormatInfo2{SType: vulkan.StructureTypePhysicalDeviceImageFormatInfo2, Next: unsafe.Pointer(&externalInfo), Format: vulkan.FormatB8g8r8a8Unorm, Type: vulkan.ImageType2d, Tiling: vulkan.ImageTilingDRMFormatModifierEXT, Usage: vulkan.ImageUsageColorAttachmentBit | vulkan.ImageUsageTransferSrcBit}
62 externalProps := vulkan.ExternalImageFormatProperties{SType: vulkan.StructureTypeExternalImageFormatProperties}
63 imageProps := vulkan.ImageFormatProperties2{SType: vulkan.StructureTypeImageFormatProperties2, Next: unsafe.Pointer(&externalProps)}
64 r := d.InstanceDispatch.GetPhysicalDeviceImageFormatProperties2(d.Physical, &info, &imageProps)
65 if r == vulkan.ErrorFormatNotSupported {
66 continue
67 }
68 if err := vulkan.Check(r); err != nil {
69 return nil, fmt.Errorf("query DRM modifier %#x: %w", m.DrmFormatModifier, err)
70 }
71 if externalProps.ExternalMemoryProperties.ExternalMemoryFeatures&vulkan.ExternalMemoryFeatureExportableBit != 0 {
72 out[m.DrmFormatModifier] = true
73 }
74 }
75 return out, nil
76}