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