diff --git a/core/cmd/dms/shellapp.go b/core/cmd/dms/shellapp.go index 6bc193b59..7fcbeef69 100644 --- a/core/cmd/dms/shellapp.go +++ b/core/cmd/dms/shellapp.go @@ -6,6 +6,7 @@ import ( "os" "github.com/AvengeMedia/DankMaterialShell/core/internal/config" + "github.com/AvengeMedia/DankMaterialShell/core/internal/gpu" "github.com/AvengeMedia/DankMaterialShell/core/internal/log" "github.com/AvengeMedia/DankMaterialShell/core/internal/server" "github.com/AvengeMedia/DankMaterialShell/core/internal/shellembed" @@ -83,5 +84,6 @@ func dmsExtraEnv(string) []string { if _, set := os.LookupEnv("MALLOC_CONF"); !set { env = append(env, "MALLOC_CONF=thp:never,narenas:4,dirty_decay_ms:3000") } + env = append(env, gpu.EGLVendorEnv()...) return env } diff --git a/core/internal/gpu/eglvendor.go b/core/internal/gpu/eglvendor.go new file mode 100644 index 000000000..d21b4c907 --- /dev/null +++ b/core/internal/gpu/eglvendor.go @@ -0,0 +1,169 @@ +package gpu + +import ( + "encoding/binary" + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + "strings" + "time" + + "github.com/AvengeMedia/DankMaterialShell/core/internal/log" + "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/linux_dmabuf" + wlclient "github.com/AvengeMedia/dankgo/wayland/client" + "golang.org/x/sys/unix" +) + +var eglVendorDirs = []string{"/etc/glvnd/egl_vendor.d", "/usr/share/glvnd/egl_vendor.d"} + +const ( + dmabufFeedbackMinVersion = 4 + // v6 stops sending main_device + dmabufMainDeviceMaxVersion = 5 + compositorProbeTimeout = 2 * time.Second + sysDevCharDir = "/sys/dev/char" +) + +func EGLVendorEnv() []string { + if os.Getenv("__EGL_VENDOR_LIBRARY_FILENAMES") != "" || os.Getenv("__EGL_VENDOR_LIBRARY_DIRS") != "" { + return nil + } + mesa, nvidia := findEGLVendorICDs(eglVendorDirs) + if mesa == "" || nvidia == "" { + return nil + } + driver, err := compositorRenderDriver() + if err != nil { + log.Debugf("egl: keeping glvnd vendor defaults: %v", err) + return nil + } + if driver == "nvidia" { + return nil + } + log.Infof("egl: compositor renders on %s, loading mesa vendor only", driver) + return []string{"__EGL_VENDOR_LIBRARY_FILENAMES=" + mesa} +} + +type eglVendorICD struct { + ICD struct { + LibraryPath string `json:"library_path"` + } `json:"ICD"` +} + +func findEGLVendorICDs(dirs []string) (mesa, nvidia string) { + for _, dir := range dirs { + entries, err := filepath.Glob(filepath.Join(dir, "*.json")) + if err != nil { + continue + } + for _, path := range entries { + switch eglVendorLibrary(path) { + case "libEGL_mesa": + if mesa == "" { + mesa = path + } + case "libEGL_nvidia": + if nvidia == "" { + nvidia = path + } + } + } + } + return mesa, nvidia +} + +func eglVendorLibrary(path string) string { + data, err := os.ReadFile(path) + if err != nil { + return "" + } + var icd eglVendorICD + if err := json.Unmarshal(data, &icd); err != nil { + return "" + } + base := filepath.Base(icd.ICD.LibraryPath) + name, _, _ := strings.Cut(base, ".so") + return name +} + +func compositorRenderDriver() (string, error) { + dev, err := compositorMainDevice() + if err != nil { + return "", err + } + return drmDeviceDriver(sysDevCharDir, dev) +} + +func drmDeviceDriver(charDir string, dev uint64) (string, error) { + link := filepath.Join(charDir, fmt.Sprintf("%d:%d", unix.Major(dev), unix.Minor(dev)), "device", "driver") + target, err := os.Readlink(link) + if err != nil { + return "", err + } + return filepath.Base(target), nil +} + +func compositorMainDevice() (uint64, error) { + display, err := wlclient.Connect("") + if err != nil { + return 0, err + } + ctx := display.Context() + defer ctx.Close() + if err := ctx.SetReadDeadline(time.Now().Add(compositorProbeTimeout)); err != nil { + return 0, err + } + + registry, err := display.GetRegistry() + if err != nil { + return 0, err + } + var dmabuf *linux_dmabuf.ZwpLinuxDmabufV1 + registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) { + if e.Interface != linux_dmabuf.ZwpLinuxDmabufV1InterfaceName || e.Version < dmabufFeedbackMinVersion { + return + } + candidate := linux_dmabuf.NewZwpLinuxDmabufV1(ctx) + if err := registry.Bind(e.Name, e.Interface, min(e.Version, dmabufMainDeviceMaxVersion), candidate); err != nil { + return + } + dmabuf = candidate + }) + if err := display.Roundtrip(); err != nil { + return 0, err + } + if dmabuf == nil { + return 0, errors.New("compositor lacks linux-dmabuf feedback") + } + defer dmabuf.Destroy() + + feedback, err := dmabuf.GetDefaultFeedback() + if err != nil { + return 0, err + } + defer feedback.Destroy() + + var device []byte + done := false + feedback.SetMainDeviceHandler(func(e linux_dmabuf.ZwpLinuxDmabufFeedbackV1MainDeviceEvent) { + device = e.Device + }) + feedback.SetDoneHandler(func(linux_dmabuf.ZwpLinuxDmabufFeedbackV1DoneEvent) { + done = true + }) + for !done { + if err := ctx.Dispatch(); err != nil { + return 0, err + } + } + return mainDeviceFromEvent(device) +} + +func mainDeviceFromEvent(device []byte) (uint64, error) { + if len(device) != 8 { + return 0, fmt.Errorf("main_device has %d bytes, want 8", len(device)) + } + return binary.NativeEndian.Uint64(device), nil +} diff --git a/core/internal/gpu/eglvendor_test.go b/core/internal/gpu/eglvendor_test.go new file mode 100644 index 000000000..507e16c16 --- /dev/null +++ b/core/internal/gpu/eglvendor_test.go @@ -0,0 +1,79 @@ +package gpu + +import ( + "encoding/binary" + "os" + "path/filepath" + "testing" +) + +func writeICD(t *testing.T, dir, name, library string) string { + t.Helper() + path := filepath.Join(dir, name) + if err := os.WriteFile(path, []byte(`{"file_format_version":"1.0.0","ICD":{"library_path":"`+library+`"}}`), 0o644); err != nil { + t.Fatal(err) + } + return path +} + +func TestFindEGLVendorICDs(t *testing.T) { + etc := t.TempDir() + usr := t.TempDir() + writeICD(t, usr, "10_nvidia.json", "libEGL_nvidia.so.0") + mesaPath := writeICD(t, usr, "50_mesa.json", "libEGL_mesa.so.0") + nvidiaPath := writeICD(t, etc, "10_nvidia.json", "/usr/lib/libEGL_nvidia.so.0") + if err := os.WriteFile(filepath.Join(etc, "broken.json"), []byte("{"), 0o644); err != nil { + t.Fatal(err) + } + + mesa, nvidia := findEGLVendorICDs([]string{etc, usr}) + if mesa != mesaPath { + t.Errorf("mesa = %q, want %q", mesa, mesaPath) + } + if nvidia != nvidiaPath { + t.Errorf("nvidia = %q, want %q", nvidia, nvidiaPath) + } + + mesa, nvidia = findEGLVendorICDs([]string{filepath.Join(etc, "missing")}) + if mesa != "" || nvidia != "" { + t.Errorf("missing dir: got %q %q, want empty", mesa, nvidia) + } +} + +func TestDrmDeviceDriver(t *testing.T) { + root := t.TempDir() + charDir := filepath.Join(root, "char") + deviceDir := filepath.Join(charDir, "226:128", "device") + if err := os.MkdirAll(deviceDir, 0o755); err != nil { + t.Fatal(err) + } + if err := os.Symlink("../../../../bus/pci/drivers/amdgpu", filepath.Join(deviceDir, "driver")); err != nil { + t.Fatal(err) + } + + driver, err := drmDeviceDriver(charDir, 226<<8|128) + if err != nil { + t.Fatal(err) + } + if driver != "amdgpu" { + t.Errorf("driver = %q, want amdgpu", driver) + } + if _, err := drmDeviceDriver(charDir, 226<<8|129); err == nil { + t.Error("unknown device: want error") + } +} + +func TestMainDeviceFromEvent(t *testing.T) { + raw := make([]byte, 8) + binary.NativeEndian.PutUint64(raw, 226<<8|128) + dev, err := mainDeviceFromEvent(raw) + if err != nil { + t.Fatal(err) + } + if dev != 226<<8|128 { + t.Errorf("dev = %d", dev) + } + if _, err := mainDeviceFromEvent(raw[:4]); err == nil { + t.Error("short array: want error") + } +} diff --git a/core/internal/proto/linux_dmabuf/linux_dmabuf.go b/core/internal/proto/linux_dmabuf/linux_dmabuf.go new file mode 100644 index 000000000..6a2da2ce8 --- /dev/null +++ b/core/internal/proto/linux_dmabuf/linux_dmabuf.go @@ -0,0 +1,1242 @@ +// Generated by go-wayland-scanner +// https://github.com/AvengeMedia/dankgo/cmd/go-wayland-scanner +// XML file : internal/proto/xml/linux-dmabuf-v1.xml +// +// linux_dmabuf_v1 Protocol Copyright: +// +// Copyright © 2014, 2015 Collabora, Ltd. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice (including the next +// paragraph) shall be included in all copies or substantial portions of the +// Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +package linux_dmabuf + +import ( + "github.com/AvengeMedia/dankgo/wayland/client" + "golang.org/x/sys/unix" +) + +// ZwpLinuxDmabufV1InterfaceName is the name of the interface as it appears in the [client.Registry]. +// It can be used to match the [client.RegistryGlobalEvent.Interface] in the +// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. +const ZwpLinuxDmabufV1InterfaceName = "zwp_linux_dmabuf_v1" + +// ZwpLinuxDmabufV1 : factory for creating dmabuf-based wl_buffers +// +// This interface offers ways to create generic dmabuf-based wl_buffers. +// +// For more information about dmabuf, see: +// https://www.kernel.org/doc/html/next/userspace-api/dma-buf-alloc-exchange.html +// +// Clients can use the get_surface_feedback request to get dmabuf feedback +// for a particular surface. If the client wants to retrieve feedback not +// tied to a surface, they can use the get_default_feedback request. +// +// The following are required from clients: +// +// - Clients must ensure that either all data in the dma-buf is +// coherent for all subsequent read access or that coherency is +// correctly handled by the underlying kernel-side dma-buf +// implementation. +// +// - Don't make any more attachments after sending the buffer to the +// compositor. Making more attachments later increases the risk of +// the compositor not being able to use (re-import) an existing +// dmabuf-based wl_buffer. +// +// The underlying graphics stack must ensure the following: +// +// - The dmabuf file descriptors relayed to the server will stay valid +// for the whole lifetime of the wl_buffer. This means the server may +// at any time use those fds to import the dmabuf into any kernel +// sub-system that might accept it. +// +// However, when the underlying graphics stack fails to deliver the +// promise, because of e.g. a device hot-unplug which raises internal +// errors, after the wl_buffer has been successfully created the +// compositor must not raise protocol errors to the client when dmabuf +// import later fails. +// +// To create a wl_buffer from one or more dmabufs, a client creates a +// zwp_linux_buffer_params_v1 object with a zwp_linux_dmabuf_v1.create_params +// request. All planes required by the intended format are added with +// the 'add' request. Finally, a 'create' or 'create_immed' request is +// issued, which has the following outcome depending on the import success. +// +// The 'create' request, +// - on success, triggers a 'created' event which provides the final +// wl_buffer to the client. +// - on failure, triggers a 'failed' event to convey that the server +// cannot use the dmabufs received from the client. +// +// For the 'create_immed' request, +// - on success, the server immediately imports the added dmabufs to +// create a wl_buffer. No event is sent from the server in this case. +// - on failure, the server can choose to either: +// - terminate the client by raising a fatal error. +// - mark the wl_buffer as failed, and send a 'failed' event to the +// client. If the client uses a failed wl_buffer as an argument to any +// request, the behaviour is compositor implementation-defined. +// +// For all DRM formats and unless specified in another protocol extension, +// pre-multiplied alpha is used for pixel values. +// +// Unless specified otherwise in another protocol extension, implicit +// synchronization is used. In other words, compositors and clients must +// wait and signal fences implicitly passed via the DMA-BUF's reservation +// mechanism. +type ZwpLinuxDmabufV1 struct { + client.BaseProxy + formatHandler ZwpLinuxDmabufV1FormatHandlerFunc + modifierHandler ZwpLinuxDmabufV1ModifierHandlerFunc +} + +// NewZwpLinuxDmabufV1 : factory for creating dmabuf-based wl_buffers +// +// This interface offers ways to create generic dmabuf-based wl_buffers. +// +// For more information about dmabuf, see: +// https://www.kernel.org/doc/html/next/userspace-api/dma-buf-alloc-exchange.html +// +// Clients can use the get_surface_feedback request to get dmabuf feedback +// for a particular surface. If the client wants to retrieve feedback not +// tied to a surface, they can use the get_default_feedback request. +// +// The following are required from clients: +// +// - Clients must ensure that either all data in the dma-buf is +// coherent for all subsequent read access or that coherency is +// correctly handled by the underlying kernel-side dma-buf +// implementation. +// +// - Don't make any more attachments after sending the buffer to the +// compositor. Making more attachments later increases the risk of +// the compositor not being able to use (re-import) an existing +// dmabuf-based wl_buffer. +// +// The underlying graphics stack must ensure the following: +// +// - The dmabuf file descriptors relayed to the server will stay valid +// for the whole lifetime of the wl_buffer. This means the server may +// at any time use those fds to import the dmabuf into any kernel +// sub-system that might accept it. +// +// However, when the underlying graphics stack fails to deliver the +// promise, because of e.g. a device hot-unplug which raises internal +// errors, after the wl_buffer has been successfully created the +// compositor must not raise protocol errors to the client when dmabuf +// import later fails. +// +// To create a wl_buffer from one or more dmabufs, a client creates a +// zwp_linux_buffer_params_v1 object with a zwp_linux_dmabuf_v1.create_params +// request. All planes required by the intended format are added with +// the 'add' request. Finally, a 'create' or 'create_immed' request is +// issued, which has the following outcome depending on the import success. +// +// The 'create' request, +// - on success, triggers a 'created' event which provides the final +// wl_buffer to the client. +// - on failure, triggers a 'failed' event to convey that the server +// cannot use the dmabufs received from the client. +// +// For the 'create_immed' request, +// - on success, the server immediately imports the added dmabufs to +// create a wl_buffer. No event is sent from the server in this case. +// - on failure, the server can choose to either: +// - terminate the client by raising a fatal error. +// - mark the wl_buffer as failed, and send a 'failed' event to the +// client. If the client uses a failed wl_buffer as an argument to any +// request, the behaviour is compositor implementation-defined. +// +// For all DRM formats and unless specified in another protocol extension, +// pre-multiplied alpha is used for pixel values. +// +// Unless specified otherwise in another protocol extension, implicit +// synchronization is used. In other words, compositors and clients must +// wait and signal fences implicitly passed via the DMA-BUF's reservation +// mechanism. +func NewZwpLinuxDmabufV1(ctx *client.Context) *ZwpLinuxDmabufV1 { + zwpLinuxDmabufV1 := &ZwpLinuxDmabufV1{} + ctx.Register(zwpLinuxDmabufV1) + return zwpLinuxDmabufV1 +} + +// Destroy : unbind the factory +// +// Objects created through this interface, especially wl_buffers, will +// remain valid. +func (i *ZwpLinuxDmabufV1) Destroy() error { + defer i.MarkZombie() + const opcode = 0 + const _reqBufLen = 8 + var _reqBuf [_reqBufLen]byte + l := 0 + client.PutUint32(_reqBuf[l:4], i.ID()) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) + l += 4 + err := i.Context().WriteMsg(_reqBuf[:], nil) + return err +} + +// CreateParams : create a temporary object for buffer parameters +// +// This temporary object is used to collect multiple dmabuf handles into +// a single batch to create a wl_buffer. It can only be used once and +// should be destroyed after a 'created' or 'failed' event has been +// received. +func (i *ZwpLinuxDmabufV1) CreateParams() (*ZwpLinuxBufferParamsV1, error) { + paramsId := NewZwpLinuxBufferParamsV1(i.Context()) + const opcode = 1 + const _reqBufLen = 8 + 4 + var _reqBuf [_reqBufLen]byte + l := 0 + client.PutUint32(_reqBuf[l:4], i.ID()) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], paramsId.ID()) + l += 4 + err := i.Context().WriteMsg(_reqBuf[:], nil) + return paramsId, err +} + +// GetDefaultFeedback : get default feedback +// +// This request creates a new zwp_linux_dmabuf_feedback_v1 object not bound +// to a particular surface. This object will deliver feedback about dmabuf +// parameters to use if the client doesn't support per-surface feedback +// (see get_surface_feedback). +func (i *ZwpLinuxDmabufV1) GetDefaultFeedback() (*ZwpLinuxDmabufFeedbackV1, error) { + id := NewZwpLinuxDmabufFeedbackV1(i.Context()) + const opcode = 2 + const _reqBufLen = 8 + 4 + var _reqBuf [_reqBufLen]byte + l := 0 + client.PutUint32(_reqBuf[l:4], i.ID()) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], id.ID()) + l += 4 + err := i.Context().WriteMsg(_reqBuf[:], nil) + return id, err +} + +// GetSurfaceFeedback : get feedback for a surface +// +// This request creates a new zwp_linux_dmabuf_feedback_v1 object for the +// specified wl_surface. This object will deliver feedback about dmabuf +// parameters to use for buffers attached to this surface. +// +// If the surface is destroyed before the zwp_linux_dmabuf_feedback_v1 object, +// the feedback object becomes inert. +func (i *ZwpLinuxDmabufV1) GetSurfaceFeedback(surface *client.Surface) (*ZwpLinuxDmabufFeedbackV1, error) { + id := NewZwpLinuxDmabufFeedbackV1(i.Context()) + const opcode = 3 + const _reqBufLen = 8 + 4 + 4 + var _reqBuf [_reqBufLen]byte + l := 0 + client.PutUint32(_reqBuf[l:4], i.ID()) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], id.ID()) + l += 4 + client.PutUint32(_reqBuf[l:l+4], surface.ID()) + l += 4 + err := i.Context().WriteMsg(_reqBuf[:], nil) + return id, err +} + +// ZwpLinuxDmabufV1FormatEvent : supported buffer format +// +// This event advertises one buffer format that the server supports. +// All the supported formats are advertised once when the client +// binds to this interface. A roundtrip after binding guarantees +// that the client has received all supported formats. +// +// For the definition of the format codes, see the +// zwp_linux_buffer_params_v1::create request. +// +// Starting version 4, the format event is deprecated and must not be +// sent by compositors. Instead, use get_default_feedback or +// get_surface_feedback. +type ZwpLinuxDmabufV1FormatEvent struct { + Format uint32 +} +type ZwpLinuxDmabufV1FormatHandlerFunc func(ZwpLinuxDmabufV1FormatEvent) + +// SetFormatHandler : sets handler for ZwpLinuxDmabufV1FormatEvent +func (i *ZwpLinuxDmabufV1) SetFormatHandler(f ZwpLinuxDmabufV1FormatHandlerFunc) { + i.formatHandler = f +} + +// ZwpLinuxDmabufV1ModifierEvent : supported buffer format modifier +// +// This event advertises the formats that the server supports, along with +// the modifiers supported for each format. All the supported modifiers +// for all the supported formats are advertised once when the client +// binds to this interface. A roundtrip after binding guarantees that +// the client has received all supported format-modifier pairs. +// +// For legacy support, DRM_FORMAT_MOD_INVALID (that is, modifier_hi == +// 0x00ffffff and modifier_lo == 0xffffffff) is allowed in this event. +// It indicates that the server can support the format with an implicit +// modifier. When a plane has DRM_FORMAT_MOD_INVALID as its modifier, it +// is as if no explicit modifier is specified. The effective modifier +// will be derived from the dmabuf. +// +// A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for +// a given format supports both explicit modifiers and implicit modifiers. +// +// For the definition of the format and modifier codes, see the +// zwp_linux_buffer_params_v1::create and zwp_linux_buffer_params_v1::add +// requests. +// +// Starting version 4, the modifier event is deprecated and must not be +// sent by compositors. Instead, use get_default_feedback or +// get_surface_feedback. +type ZwpLinuxDmabufV1ModifierEvent struct { + Format uint32 + ModifierHi uint32 + ModifierLo uint32 +} +type ZwpLinuxDmabufV1ModifierHandlerFunc func(ZwpLinuxDmabufV1ModifierEvent) + +// SetModifierHandler : sets handler for ZwpLinuxDmabufV1ModifierEvent +func (i *ZwpLinuxDmabufV1) SetModifierHandler(f ZwpLinuxDmabufV1ModifierHandlerFunc) { + i.modifierHandler = f +} + +func (i *ZwpLinuxDmabufV1) Dispatch(opcode uint32, fd int, data []byte) { + switch opcode { + case 0: + if i.formatHandler == nil { + return + } + var e ZwpLinuxDmabufV1FormatEvent + l := 0 + e.Format = client.Uint32(data[l : l+4]) + l += 4 + + i.formatHandler(e) + case 1: + if i.modifierHandler == nil { + return + } + var e ZwpLinuxDmabufV1ModifierEvent + l := 0 + e.Format = client.Uint32(data[l : l+4]) + l += 4 + e.ModifierHi = client.Uint32(data[l : l+4]) + l += 4 + e.ModifierLo = client.Uint32(data[l : l+4]) + l += 4 + + i.modifierHandler(e) + } +} + +// ZwpLinuxBufferParamsV1InterfaceName is the name of the interface as it appears in the [client.Registry]. +// It can be used to match the [client.RegistryGlobalEvent.Interface] in the +// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. +const ZwpLinuxBufferParamsV1InterfaceName = "zwp_linux_buffer_params_v1" + +// ZwpLinuxBufferParamsV1 : parameters for creating a dmabuf-based wl_buffer +// +// This temporary object is a collection of dmabufs and other +// parameters that together form a single logical buffer. The temporary +// object may eventually create one wl_buffer unless cancelled by +// destroying it before requesting 'create'. +// +// Single-planar formats only require one dmabuf, however +// multi-planar formats may require more than one dmabuf. For all +// formats, an 'add' request must be called once per plane (even if the +// underlying dmabuf fd is identical). +// +// You must use consecutive plane indices ('plane_idx' argument for 'add') +// from zero to the number of planes used by the drm_fourcc format code. +// All planes required by the format must be given exactly once, but can +// be given in any order. Each plane index can only be set once; subsequent +// calls with a plane index which has already been set will result in a +// plane_set error being generated. +type ZwpLinuxBufferParamsV1 struct { + client.BaseProxy + createdHandler ZwpLinuxBufferParamsV1CreatedHandlerFunc + failedHandler ZwpLinuxBufferParamsV1FailedHandlerFunc +} + +// NewZwpLinuxBufferParamsV1 : parameters for creating a dmabuf-based wl_buffer +// +// This temporary object is a collection of dmabufs and other +// parameters that together form a single logical buffer. The temporary +// object may eventually create one wl_buffer unless cancelled by +// destroying it before requesting 'create'. +// +// Single-planar formats only require one dmabuf, however +// multi-planar formats may require more than one dmabuf. For all +// formats, an 'add' request must be called once per plane (even if the +// underlying dmabuf fd is identical). +// +// You must use consecutive plane indices ('plane_idx' argument for 'add') +// from zero to the number of planes used by the drm_fourcc format code. +// All planes required by the format must be given exactly once, but can +// be given in any order. Each plane index can only be set once; subsequent +// calls with a plane index which has already been set will result in a +// plane_set error being generated. +func NewZwpLinuxBufferParamsV1(ctx *client.Context) *ZwpLinuxBufferParamsV1 { + zwpLinuxBufferParamsV1 := &ZwpLinuxBufferParamsV1{} + ctx.Register(zwpLinuxBufferParamsV1) + return zwpLinuxBufferParamsV1 +} + +// Destroy : delete this object, used or not +// +// Cleans up the temporary data sent to the server for dmabuf-based +// wl_buffer creation. +func (i *ZwpLinuxBufferParamsV1) Destroy() error { + defer i.MarkZombie() + const opcode = 0 + const _reqBufLen = 8 + var _reqBuf [_reqBufLen]byte + l := 0 + client.PutUint32(_reqBuf[l:4], i.ID()) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) + l += 4 + err := i.Context().WriteMsg(_reqBuf[:], nil) + return err +} + +// Add : add a dmabuf to the temporary set +// +// This request adds one dmabuf to the set in this +// zwp_linux_buffer_params_v1. +// +// The 64-bit unsigned value combined from modifier_hi and modifier_lo +// is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the +// fb modifier, which is defined in drm_mode.h of Linux UAPI. +// This is an opaque token. Drivers use this token to express tiling, +// compression, etc. driver-specific modifications to the base format +// defined by the DRM fourcc code. +// +// Starting from version 4, the invalid_format protocol error is sent if +// the format + modifier pair was not advertised as supported. +// +// Starting from version 5, the invalid_format protocol error is sent if +// all planes don't use the same modifier. +// +// This request raises the PLANE_IDX error if plane_idx is too large. +// The error PLANE_SET is raised if attempting to set a plane that +// was already set. +// +// fd: dmabuf fd +// planeIdx: plane index +// offset: offset in bytes +// stride: stride in bytes +// modifierHi: high 32 bits of layout modifier +// modifierLo: low 32 bits of layout modifier +func (i *ZwpLinuxBufferParamsV1) Add(fd int, planeIdx, offset, stride, modifierHi, modifierLo uint32) error { + const opcode = 1 + const _reqBufLen = 8 + 4 + 4 + 4 + 4 + 4 + var _reqBuf [_reqBufLen]byte + l := 0 + client.PutUint32(_reqBuf[l:4], i.ID()) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(planeIdx)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(offset)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(stride)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(modifierHi)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(modifierLo)) + l += 4 + oob := unix.UnixRights(int(fd)) + err := i.Context().WriteMsg(_reqBuf[:], oob) + return err +} + +// Create : create a wl_buffer from the given dmabufs +// +// This asks for creation of a wl_buffer from the added dmabuf +// buffers. The wl_buffer is not created immediately but returned via +// the 'created' event if the dmabuf sharing succeeds. The sharing +// may fail at runtime for reasons a client cannot predict, in +// which case the 'failed' event is triggered. +// +// The 'format' argument is a DRM_FORMAT code, as defined by the +// libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the +// authoritative source on how the format codes should work. +// +// The 'flags' is a bitfield of the flags defined in enum "flags". +// 'y_invert' means that the image needs to be y-flipped. +// +// Flag 'interlaced' means that the frame in the buffer is not +// progressive as usual, but interlaced. An interlaced buffer as +// supported here must always contain both top and bottom fields. +// The top field always begins on the first pixel row. The temporal +// ordering between the two fields is top field first, unless +// 'bottom_first' is specified. It is undefined whether 'bottom_first' +// is ignored if 'interlaced' is not set. +// +// This protocol does not convey any information about field rate, +// duration, or timing, other than the relative ordering between the +// two fields in one buffer. A compositor may have to estimate the +// intended field rate from the incoming buffer rate. It is undefined +// whether the time of receiving wl_surface.commit with a new buffer +// attached, applying the wl_surface state, wl_surface.frame callback +// trigger, presentation, or any other point in the compositor cycle +// is used to measure the frame or field times. There is no support +// for detecting missed or late frames/fields/buffers either, and +// there is no support whatsoever for cooperating with interlaced +// compositor output. +// +// The composited image quality resulting from the use of interlaced +// buffers is explicitly undefined. A compositor may use elaborate +// hardware features or software to deinterlace and create progressive +// output frames from a sequence of interlaced input buffers, or it +// may produce substandard image quality. However, compositors that +// cannot guarantee reasonable image quality in all cases are recommended +// to just reject all interlaced buffers. +// +// Any argument errors, including non-positive width or height, +// mismatch between the number of planes and the format, bad +// format, bad offset or stride, may be indicated by fatal protocol +// errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, +// OUT_OF_BOUNDS. +// +// Dmabuf import errors in the server that are not obvious client +// bugs are returned via the 'failed' event as non-fatal. This +// allows attempting dmabuf sharing and falling back in the client +// if it fails. +// +// This request can be sent only once in the object's lifetime, after +// which the only legal request is destroy. This object should be +// destroyed after issuing a 'create' request. Attempting to use this +// object after issuing 'create' raises the ALREADY_USED protocol error. +// +// It is not mandatory to issue 'create'. If a client wants to +// cancel the buffer creation, it can just destroy this object. +// +// width: base plane width in pixels +// height: base plane height in pixels +// format: DRM_FORMAT code +// flags: see enum flags +func (i *ZwpLinuxBufferParamsV1) Create(width, height int32, format, flags uint32) error { + const opcode = 2 + const _reqBufLen = 8 + 4 + 4 + 4 + 4 + var _reqBuf [_reqBufLen]byte + l := 0 + client.PutUint32(_reqBuf[l:4], i.ID()) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(width)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(height)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(format)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(flags)) + l += 4 + err := i.Context().WriteMsg(_reqBuf[:], nil) + return err +} + +// CreateImmed : immediately create a wl_buffer from the given +// +// This asks for immediate creation of a wl_buffer by importing the +// added dmabufs. +// +// In case of import success, no event is sent from the server, and the +// wl_buffer is ready to be used by the client. +// +// Upon import failure, either of the following may happen, as seen fit +// by the implementation: +// - the client is terminated with one of the following fatal protocol +// errors: +// - INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS, +// in case of argument errors such as mismatch between the number +// of planes and the format, bad format, non-positive width or +// height, or bad offset or stride. +// - INVALID_WL_BUFFER, in case the cause for failure is unknown or +// platform specific. +// - the server creates an invalid wl_buffer, marks it as failed and +// sends a 'failed' event to the client. The result of using this +// invalid wl_buffer as an argument in any request by the client is +// defined by the compositor implementation. +// +// This takes the same arguments as a 'create' request, and obeys the +// same restrictions. +// +// width: base plane width in pixels +// height: base plane height in pixels +// format: DRM_FORMAT code +// flags: see enum flags +func (i *ZwpLinuxBufferParamsV1) CreateImmed(width, height int32, format, flags uint32) (*client.Buffer, error) { + bufferId := client.NewBuffer(i.Context()) + const opcode = 3 + const _reqBufLen = 8 + 4 + 4 + 4 + 4 + 4 + var _reqBuf [_reqBufLen]byte + l := 0 + client.PutUint32(_reqBuf[l:4], i.ID()) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], bufferId.ID()) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(width)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(height)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(format)) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(flags)) + l += 4 + err := i.Context().WriteMsg(_reqBuf[:], nil) + return bufferId, err +} + +// SetSamplingDevice : set the target device of the wl_buffer +// +// Set the device the compositor should import the dmabufs to for sampling +// in the next create or create_immed request. +// +// To avoid race conditions when the compositor removes a device from the +// tranches, it is not a protocol error if the device hasn't been advertised +// by the compositor in a tranche with the sampling flag, but the import is +// likely to fail in that case. +// +// If the client doesn't know a suitable target device, it shouldn't set one, +// and the compositor should attempt import on all devices it supports. +// +// If the array is too small to contain a dev_t or larger than required, the +// invalid_dev_t_size error will be emitted. +// +// device: device dev_t value +func (i *ZwpLinuxBufferParamsV1) SetSamplingDevice(device []byte) error { + const opcode = 4 + deviceLen := len(device) + _reqBufLen := 8 + deviceLen + _reqBuf := make([]byte, _reqBufLen) + l := 0 + client.PutUint32(_reqBuf[l:4], i.ID()) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) + l += 4 + client.PutArray(_reqBuf[l:l+(4+deviceLen)], device) + l += deviceLen + err := i.Context().WriteMsg(_reqBuf, nil) + return err +} + +type ZwpLinuxBufferParamsV1Error uint32 + +// ZwpLinuxBufferParamsV1Error : +const ( + // ZwpLinuxBufferParamsV1ErrorAlreadyUsed : the zwp_linux_buffer_params_v1 object has already been used to create a wl_buffer + ZwpLinuxBufferParamsV1ErrorAlreadyUsed ZwpLinuxBufferParamsV1Error = 0 + // ZwpLinuxBufferParamsV1ErrorPlaneIdx : plane index out of bounds + ZwpLinuxBufferParamsV1ErrorPlaneIdx ZwpLinuxBufferParamsV1Error = 1 + // ZwpLinuxBufferParamsV1ErrorPlaneSet : the plane index was already set + ZwpLinuxBufferParamsV1ErrorPlaneSet ZwpLinuxBufferParamsV1Error = 2 + // ZwpLinuxBufferParamsV1ErrorIncomplete : missing or too many planes to create a buffer + ZwpLinuxBufferParamsV1ErrorIncomplete ZwpLinuxBufferParamsV1Error = 3 + // ZwpLinuxBufferParamsV1ErrorInvalidFormat : format not supported + ZwpLinuxBufferParamsV1ErrorInvalidFormat ZwpLinuxBufferParamsV1Error = 4 + // ZwpLinuxBufferParamsV1ErrorInvalidDimensions : invalid width or height + ZwpLinuxBufferParamsV1ErrorInvalidDimensions ZwpLinuxBufferParamsV1Error = 5 + // ZwpLinuxBufferParamsV1ErrorOutOfBounds : offset + stride * height goes out of dmabuf bounds + ZwpLinuxBufferParamsV1ErrorOutOfBounds ZwpLinuxBufferParamsV1Error = 6 + // ZwpLinuxBufferParamsV1ErrorInvalidWlBuffer : invalid wl_buffer resulted from importing dmabufs via + ZwpLinuxBufferParamsV1ErrorInvalidWlBuffer ZwpLinuxBufferParamsV1Error = 7 + // ZwpLinuxBufferParamsV1ErrorInvalidDevTSize : an array with mismatching size for a dev_t was used + ZwpLinuxBufferParamsV1ErrorInvalidDevTSize ZwpLinuxBufferParamsV1Error = 8 +) + +func (e ZwpLinuxBufferParamsV1Error) Name() string { + switch e { + case ZwpLinuxBufferParamsV1ErrorAlreadyUsed: + return "already_used" + case ZwpLinuxBufferParamsV1ErrorPlaneIdx: + return "plane_idx" + case ZwpLinuxBufferParamsV1ErrorPlaneSet: + return "plane_set" + case ZwpLinuxBufferParamsV1ErrorIncomplete: + return "incomplete" + case ZwpLinuxBufferParamsV1ErrorInvalidFormat: + return "invalid_format" + case ZwpLinuxBufferParamsV1ErrorInvalidDimensions: + return "invalid_dimensions" + case ZwpLinuxBufferParamsV1ErrorOutOfBounds: + return "out_of_bounds" + case ZwpLinuxBufferParamsV1ErrorInvalidWlBuffer: + return "invalid_wl_buffer" + case ZwpLinuxBufferParamsV1ErrorInvalidDevTSize: + return "invalid_dev_t_size" + default: + return "" + } +} + +func (e ZwpLinuxBufferParamsV1Error) Value() string { + switch e { + case ZwpLinuxBufferParamsV1ErrorAlreadyUsed: + return "0" + case ZwpLinuxBufferParamsV1ErrorPlaneIdx: + return "1" + case ZwpLinuxBufferParamsV1ErrorPlaneSet: + return "2" + case ZwpLinuxBufferParamsV1ErrorIncomplete: + return "3" + case ZwpLinuxBufferParamsV1ErrorInvalidFormat: + return "4" + case ZwpLinuxBufferParamsV1ErrorInvalidDimensions: + return "5" + case ZwpLinuxBufferParamsV1ErrorOutOfBounds: + return "6" + case ZwpLinuxBufferParamsV1ErrorInvalidWlBuffer: + return "7" + case ZwpLinuxBufferParamsV1ErrorInvalidDevTSize: + return "8" + default: + return "" + } +} + +func (e ZwpLinuxBufferParamsV1Error) String() string { + return e.Name() + "=" + e.Value() +} + +type ZwpLinuxBufferParamsV1Flags uint32 + +// ZwpLinuxBufferParamsV1Flags : +const ( + // ZwpLinuxBufferParamsV1FlagsYInvert : contents are y-inverted + ZwpLinuxBufferParamsV1FlagsYInvert ZwpLinuxBufferParamsV1Flags = 1 + // ZwpLinuxBufferParamsV1FlagsInterlaced : content is interlaced + ZwpLinuxBufferParamsV1FlagsInterlaced ZwpLinuxBufferParamsV1Flags = 2 + // ZwpLinuxBufferParamsV1FlagsBottomFirst : bottom field first + ZwpLinuxBufferParamsV1FlagsBottomFirst ZwpLinuxBufferParamsV1Flags = 4 +) + +func (e ZwpLinuxBufferParamsV1Flags) Name() string { + switch e { + case ZwpLinuxBufferParamsV1FlagsYInvert: + return "y_invert" + case ZwpLinuxBufferParamsV1FlagsInterlaced: + return "interlaced" + case ZwpLinuxBufferParamsV1FlagsBottomFirst: + return "bottom_first" + default: + return "" + } +} + +func (e ZwpLinuxBufferParamsV1Flags) Value() string { + switch e { + case ZwpLinuxBufferParamsV1FlagsYInvert: + return "1" + case ZwpLinuxBufferParamsV1FlagsInterlaced: + return "2" + case ZwpLinuxBufferParamsV1FlagsBottomFirst: + return "4" + default: + return "" + } +} + +func (e ZwpLinuxBufferParamsV1Flags) String() string { + return e.Name() + "=" + e.Value() +} + +// ZwpLinuxBufferParamsV1CreatedEvent : buffer creation succeeded +// +// This event indicates that the attempted buffer creation was +// successful. It provides the new wl_buffer referencing the dmabuf(s). +// +// Upon receiving this event, the client should destroy the +// zwp_linux_buffer_params_v1 object. +type ZwpLinuxBufferParamsV1CreatedEvent struct { + Buffer *client.Buffer +} +type ZwpLinuxBufferParamsV1CreatedHandlerFunc func(ZwpLinuxBufferParamsV1CreatedEvent) + +// SetCreatedHandler : sets handler for ZwpLinuxBufferParamsV1CreatedEvent +func (i *ZwpLinuxBufferParamsV1) SetCreatedHandler(f ZwpLinuxBufferParamsV1CreatedHandlerFunc) { + i.createdHandler = f +} + +// ZwpLinuxBufferParamsV1FailedEvent : buffer creation failed +// +// This event indicates that the attempted buffer creation has +// failed. It usually means that one of the dmabuf constraints +// has not been fulfilled. +// +// Upon receiving this event, the client should destroy the +// zwp_linux_buffer_params_v1 object. +type ZwpLinuxBufferParamsV1FailedEvent struct{} +type ZwpLinuxBufferParamsV1FailedHandlerFunc func(ZwpLinuxBufferParamsV1FailedEvent) + +// SetFailedHandler : sets handler for ZwpLinuxBufferParamsV1FailedEvent +func (i *ZwpLinuxBufferParamsV1) SetFailedHandler(f ZwpLinuxBufferParamsV1FailedHandlerFunc) { + i.failedHandler = f +} + +func (i *ZwpLinuxBufferParamsV1) Dispatch(opcode uint32, fd int, data []byte) { + switch opcode { + case 0: + if i.createdHandler == nil { + return + } + var e ZwpLinuxBufferParamsV1CreatedEvent + l := 0 + bufferID := client.Uint32(data[l : l+4]) + if buffer, ok := i.Context().GetProxy(bufferID).(*client.Buffer); ok && !buffer.IsZombie() { + e.Buffer = buffer + } else if bufferID != 0 { + buffer := &client.Buffer{} + i.Context().RegisterWithID(buffer, bufferID) + e.Buffer = buffer + } + l += 4 + + i.createdHandler(e) + case 1: + if i.failedHandler == nil { + return + } + var e ZwpLinuxBufferParamsV1FailedEvent + + i.failedHandler(e) + } +} + +// ZwpLinuxDmabufFeedbackV1InterfaceName is the name of the interface as it appears in the [client.Registry]. +// It can be used to match the [client.RegistryGlobalEvent.Interface] in the +// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies. +const ZwpLinuxDmabufFeedbackV1InterfaceName = "zwp_linux_dmabuf_feedback_v1" + +// ZwpLinuxDmabufFeedbackV1 : dmabuf feedback +// +// This object advertises dmabuf parameters feedback. This includes the +// preferred devices and the supported formats/modifiers. +// +// The parameters are sent once when this object is created and whenever they +// change. The done event is always sent once after all parameters have been +// sent. When a single parameter changes, all parameters are re-sent by the +// compositor. +// +// Compositors can re-send the parameters when the current client buffer +// allocations are sub-optimal. Compositors should not re-send the +// parameters if re-allocating the buffers would not result in a more optimal +// configuration. In particular, compositors should avoid sending the exact +// same parameters multiple times in a row. +// +// The tranche_target_device and tranche_formats events are grouped by +// tranches of preference. For each tranche, a tranche_target_device, one +// tranche_flags and one or more tranche_formats events are sent, followed +// by a tranche_done event finishing the list. The tranches are sent in +// descending order of preference. All formats and modifiers in the same +// tranche have the same preference. +// +// To send parameters, the compositor sends one main_device event (unless +// the client bound version 6 or above), tranches (each consisting of one +// tranche_target_device event, one tranche_flags event, tranche_formats +// events and then a tranche_done event), then one done event. +// +// With version 6 and above, the compositor must always advertise at least +// one tranche with the sampling flag set. +type ZwpLinuxDmabufFeedbackV1 struct { + client.BaseProxy + doneHandler ZwpLinuxDmabufFeedbackV1DoneHandlerFunc + formatTableHandler ZwpLinuxDmabufFeedbackV1FormatTableHandlerFunc + mainDeviceHandler ZwpLinuxDmabufFeedbackV1MainDeviceHandlerFunc + trancheDoneHandler ZwpLinuxDmabufFeedbackV1TrancheDoneHandlerFunc + trancheTargetDeviceHandler ZwpLinuxDmabufFeedbackV1TrancheTargetDeviceHandlerFunc + trancheFormatsHandler ZwpLinuxDmabufFeedbackV1TrancheFormatsHandlerFunc + trancheFlagsHandler ZwpLinuxDmabufFeedbackV1TrancheFlagsHandlerFunc +} + +// NewZwpLinuxDmabufFeedbackV1 : dmabuf feedback +// +// This object advertises dmabuf parameters feedback. This includes the +// preferred devices and the supported formats/modifiers. +// +// The parameters are sent once when this object is created and whenever they +// change. The done event is always sent once after all parameters have been +// sent. When a single parameter changes, all parameters are re-sent by the +// compositor. +// +// Compositors can re-send the parameters when the current client buffer +// allocations are sub-optimal. Compositors should not re-send the +// parameters if re-allocating the buffers would not result in a more optimal +// configuration. In particular, compositors should avoid sending the exact +// same parameters multiple times in a row. +// +// The tranche_target_device and tranche_formats events are grouped by +// tranches of preference. For each tranche, a tranche_target_device, one +// tranche_flags and one or more tranche_formats events are sent, followed +// by a tranche_done event finishing the list. The tranches are sent in +// descending order of preference. All formats and modifiers in the same +// tranche have the same preference. +// +// To send parameters, the compositor sends one main_device event (unless +// the client bound version 6 or above), tranches (each consisting of one +// tranche_target_device event, one tranche_flags event, tranche_formats +// events and then a tranche_done event), then one done event. +// +// With version 6 and above, the compositor must always advertise at least +// one tranche with the sampling flag set. +func NewZwpLinuxDmabufFeedbackV1(ctx *client.Context) *ZwpLinuxDmabufFeedbackV1 { + zwpLinuxDmabufFeedbackV1 := &ZwpLinuxDmabufFeedbackV1{} + ctx.Register(zwpLinuxDmabufFeedbackV1) + return zwpLinuxDmabufFeedbackV1 +} + +// Destroy : destroy the feedback object +// +// Using this request a client can tell the server that it is not going to +// use the zwp_linux_dmabuf_feedback_v1 object anymore. +func (i *ZwpLinuxDmabufFeedbackV1) Destroy() error { + defer i.MarkZombie() + const opcode = 0 + const _reqBufLen = 8 + var _reqBuf [_reqBufLen]byte + l := 0 + client.PutUint32(_reqBuf[l:4], i.ID()) + l += 4 + client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff)) + l += 4 + err := i.Context().WriteMsg(_reqBuf[:], nil) + return err +} + +type ZwpLinuxDmabufFeedbackV1TrancheFlags uint32 + +// ZwpLinuxDmabufFeedbackV1TrancheFlags : +const ( + ZwpLinuxDmabufFeedbackV1TrancheFlagsScanout ZwpLinuxDmabufFeedbackV1TrancheFlags = 1 + ZwpLinuxDmabufFeedbackV1TrancheFlagsSampling ZwpLinuxDmabufFeedbackV1TrancheFlags = 2 +) + +func (e ZwpLinuxDmabufFeedbackV1TrancheFlags) Name() string { + switch e { + case ZwpLinuxDmabufFeedbackV1TrancheFlagsScanout: + return "scanout" + case ZwpLinuxDmabufFeedbackV1TrancheFlagsSampling: + return "sampling" + default: + return "" + } +} + +func (e ZwpLinuxDmabufFeedbackV1TrancheFlags) Value() string { + switch e { + case ZwpLinuxDmabufFeedbackV1TrancheFlagsScanout: + return "1" + case ZwpLinuxDmabufFeedbackV1TrancheFlagsSampling: + return "2" + default: + return "" + } +} + +func (e ZwpLinuxDmabufFeedbackV1TrancheFlags) String() string { + return e.Name() + "=" + e.Value() +} + +// ZwpLinuxDmabufFeedbackV1DoneEvent : all feedback has been sent +// +// This event is sent after all parameters of a zwp_linux_dmabuf_feedback_v1 +// object have been sent. +// +// This allows changes to the zwp_linux_dmabuf_feedback_v1 parameters to be +// seen as atomic, even if they happen via multiple events. +type ZwpLinuxDmabufFeedbackV1DoneEvent struct{} +type ZwpLinuxDmabufFeedbackV1DoneHandlerFunc func(ZwpLinuxDmabufFeedbackV1DoneEvent) + +// SetDoneHandler : sets handler for ZwpLinuxDmabufFeedbackV1DoneEvent +func (i *ZwpLinuxDmabufFeedbackV1) SetDoneHandler(f ZwpLinuxDmabufFeedbackV1DoneHandlerFunc) { + i.doneHandler = f +} + +// ZwpLinuxDmabufFeedbackV1FormatTableEvent : format and modifier table +// +// This event provides a file descriptor which can be memory-mapped to +// access the format and modifier table. +// +// The table contains a tightly packed array of consecutive format + +// modifier pairs. Each pair is 16 bytes wide. It contains a format as a +// 32-bit unsigned integer, followed by 4 bytes of unused padding, and a +// modifier as a 64-bit unsigned integer. The native endianness is used. +// +// The client must map the file descriptor in read-only private mode. +// +// Compositors are not allowed to mutate the table file contents once this +// event has been sent. Instead, compositors must create a new, separate +// table file and re-send feedback parameters. Compositors are allowed to +// store duplicate format + modifier pairs in the table. +type ZwpLinuxDmabufFeedbackV1FormatTableEvent struct { + Fd int + Size uint32 +} +type ZwpLinuxDmabufFeedbackV1FormatTableHandlerFunc func(ZwpLinuxDmabufFeedbackV1FormatTableEvent) + +// SetFormatTableHandler : sets handler for ZwpLinuxDmabufFeedbackV1FormatTableEvent +func (i *ZwpLinuxDmabufFeedbackV1) SetFormatTableHandler(f ZwpLinuxDmabufFeedbackV1FormatTableHandlerFunc) { + i.formatTableHandler = f +} + +// ZwpLinuxDmabufFeedbackV1MainDeviceEvent : preferred main device +// +// This event advertises the main device that the server prefers to use +// when direct scan-out to the target device isn't possible. The +// advertised main device may be different for each +// zwp_linux_dmabuf_feedback_v1 object, and may change over time. +// +// There is exactly one main device. The compositor must send at least +// one preference tranche with tranche_target_device equal to main_device. +// +// Clients need to create buffers that the main device can import and +// read from, otherwise creating the dmabuf wl_buffer will fail (see the +// zwp_linux_buffer_params_v1.create and create_immed requests for details). +// The main device will also likely be kept active by the compositor, +// so clients can use it instead of waking up another device for power +// savings. +// +// In general the device is a DRM node. The DRM node type (primary vs. +// render) is unspecified. Clients must not rely on the compositor sending +// a particular node type. Clients cannot check two devices for equality +// by comparing the dev_t value. +// +// If explicit modifiers are not supported and the client performs buffer +// allocations on a different device than the main device, then the client +// must force the buffer to have a linear layout. +// +// With version 6 and above, this event is no longer sent. Clients should +// use a device with the sampling flag in the tranches instead. +type ZwpLinuxDmabufFeedbackV1MainDeviceEvent struct { + Device []byte +} +type ZwpLinuxDmabufFeedbackV1MainDeviceHandlerFunc func(ZwpLinuxDmabufFeedbackV1MainDeviceEvent) + +// SetMainDeviceHandler : sets handler for ZwpLinuxDmabufFeedbackV1MainDeviceEvent +func (i *ZwpLinuxDmabufFeedbackV1) SetMainDeviceHandler(f ZwpLinuxDmabufFeedbackV1MainDeviceHandlerFunc) { + i.mainDeviceHandler = f +} + +// ZwpLinuxDmabufFeedbackV1TrancheDoneEvent : a preference tranche has been sent +// +// This event splits tranche_target_device and tranche_formats events into +// preference tranches. It is sent after a set of tranche_target_device +// and tranche_formats events; it represents the end of a tranche. The +// next tranche will have a lower preference. +type ZwpLinuxDmabufFeedbackV1TrancheDoneEvent struct{} +type ZwpLinuxDmabufFeedbackV1TrancheDoneHandlerFunc func(ZwpLinuxDmabufFeedbackV1TrancheDoneEvent) + +// SetTrancheDoneHandler : sets handler for ZwpLinuxDmabufFeedbackV1TrancheDoneEvent +func (i *ZwpLinuxDmabufFeedbackV1) SetTrancheDoneHandler(f ZwpLinuxDmabufFeedbackV1TrancheDoneHandlerFunc) { + i.trancheDoneHandler = f +} + +// ZwpLinuxDmabufFeedbackV1TrancheTargetDeviceEvent : target device +// +// This event advertises the target device that the server prefers to use +// for a buffer created given this tranche. The advertised target device +// may be different for each preference tranche, and may change over time. +// +// There is exactly one target device per tranche. +// +// The target device may be a scan-out device, for example if the +// compositor prefers to directly scan-out a buffer created given this +// tranche. The target device may be a rendering device, for example if +// the compositor prefers to texture from said buffer. +// +// The client can use this hint to allocate the buffer in a way that makes +// it accessible from the target device, ideally directly. The buffer must +// still be accessible from a device with the sampling flag, either through +// direct import or a potentially more expensive fallback path. If the +// buffer can't be directly imported for sampling, then clients must be +// prepared for the compositor changing the tranche priority or making +// wl_buffer creation fail (see the zwp_linux_buffer_params_v1.create and +// create_immed requests for details). +// +// If the device is a DRM node, the DRM node type (primary vs. render) is +// unspecified. Clients must not rely on the compositor sending a +// particular node type. Clients cannot check two devices for equality by +// comparing the dev_t value. +// +// This event is tied to a preference tranche, see the tranche_done event. +type ZwpLinuxDmabufFeedbackV1TrancheTargetDeviceEvent struct { + Device []byte +} +type ZwpLinuxDmabufFeedbackV1TrancheTargetDeviceHandlerFunc func(ZwpLinuxDmabufFeedbackV1TrancheTargetDeviceEvent) + +// SetTrancheTargetDeviceHandler : sets handler for ZwpLinuxDmabufFeedbackV1TrancheTargetDeviceEvent +func (i *ZwpLinuxDmabufFeedbackV1) SetTrancheTargetDeviceHandler(f ZwpLinuxDmabufFeedbackV1TrancheTargetDeviceHandlerFunc) { + i.trancheTargetDeviceHandler = f +} + +// ZwpLinuxDmabufFeedbackV1TrancheFormatsEvent : supported buffer format modifiers +// +// This event advertises the format + modifier combinations that the +// compositor supports. +// +// It carries an array of indices, each referring to a format + modifier +// pair in the last received format table (see the format_table event). +// Each index is a 16-bit unsigned integer in native endianness. +// +// For legacy support, DRM_FORMAT_MOD_INVALID is an allowed modifier. +// It indicates that the server can support the format with an implicit +// modifier. When a buffer has DRM_FORMAT_MOD_INVALID as its modifier, it +// is as if no explicit modifier is specified. The effective modifier +// will be derived from the dmabuf. +// +// A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for +// a given format supports both explicit modifiers and implicit modifiers. +// +// Compositors must not send duplicate format + modifier pairs within the +// same tranche or across two different tranches with the same target +// device and flags. +// +// This event is tied to a preference tranche, see the tranche_done event. +// +// For the definition of the format and modifier codes, see the +// zwp_linux_buffer_params_v1.create request. +type ZwpLinuxDmabufFeedbackV1TrancheFormatsEvent struct { + Indices []byte +} +type ZwpLinuxDmabufFeedbackV1TrancheFormatsHandlerFunc func(ZwpLinuxDmabufFeedbackV1TrancheFormatsEvent) + +// SetTrancheFormatsHandler : sets handler for ZwpLinuxDmabufFeedbackV1TrancheFormatsEvent +func (i *ZwpLinuxDmabufFeedbackV1) SetTrancheFormatsHandler(f ZwpLinuxDmabufFeedbackV1TrancheFormatsHandlerFunc) { + i.trancheFormatsHandler = f +} + +// ZwpLinuxDmabufFeedbackV1TrancheFlagsEvent : tranche flags +// +// This event sets tranche-specific flags. This event is tied to a +// preference tranche, see the tranche_done event. +// With version 6 and above, the compositor must set at least one flag +// in each tranche. +type ZwpLinuxDmabufFeedbackV1TrancheFlagsEvent struct { + Flags uint32 +} +type ZwpLinuxDmabufFeedbackV1TrancheFlagsHandlerFunc func(ZwpLinuxDmabufFeedbackV1TrancheFlagsEvent) + +// SetTrancheFlagsHandler : sets handler for ZwpLinuxDmabufFeedbackV1TrancheFlagsEvent +func (i *ZwpLinuxDmabufFeedbackV1) SetTrancheFlagsHandler(f ZwpLinuxDmabufFeedbackV1TrancheFlagsHandlerFunc) { + i.trancheFlagsHandler = f +} + +func (i *ZwpLinuxDmabufFeedbackV1) Dispatch(opcode uint32, fd int, data []byte) { + switch opcode { + case 0: + if i.doneHandler == nil { + return + } + var e ZwpLinuxDmabufFeedbackV1DoneEvent + + i.doneHandler(e) + case 1: + if i.formatTableHandler == nil { + if fd != -1 { + unix.Close(fd) + } + return + } + var e ZwpLinuxDmabufFeedbackV1FormatTableEvent + l := 0 + e.Fd = fd + e.Size = client.Uint32(data[l : l+4]) + l += 4 + + i.formatTableHandler(e) + case 2: + if i.mainDeviceHandler == nil { + return + } + var e ZwpLinuxDmabufFeedbackV1MainDeviceEvent + l := 0 + deviceLen := int(client.Uint32(data[l : l+4])) + l += 4 + e.Device = make([]byte, deviceLen) + copy(e.Device, data[l:l+deviceLen]) + l += deviceLen + + i.mainDeviceHandler(e) + case 3: + if i.trancheDoneHandler == nil { + return + } + var e ZwpLinuxDmabufFeedbackV1TrancheDoneEvent + + i.trancheDoneHandler(e) + case 4: + if i.trancheTargetDeviceHandler == nil { + return + } + var e ZwpLinuxDmabufFeedbackV1TrancheTargetDeviceEvent + l := 0 + deviceLen := int(client.Uint32(data[l : l+4])) + l += 4 + e.Device = make([]byte, deviceLen) + copy(e.Device, data[l:l+deviceLen]) + l += deviceLen + + i.trancheTargetDeviceHandler(e) + case 5: + if i.trancheFormatsHandler == nil { + return + } + var e ZwpLinuxDmabufFeedbackV1TrancheFormatsEvent + l := 0 + indicesLen := int(client.Uint32(data[l : l+4])) + l += 4 + e.Indices = make([]byte, indicesLen) + copy(e.Indices, data[l:l+indicesLen]) + l += indicesLen + + i.trancheFormatsHandler(e) + case 6: + if i.trancheFlagsHandler == nil { + return + } + var e ZwpLinuxDmabufFeedbackV1TrancheFlagsEvent + l := 0 + e.Flags = client.Uint32(data[l : l+4]) + l += 4 + + i.trancheFlagsHandler(e) + } +} + +func (i *ZwpLinuxDmabufFeedbackV1) EventTakesFd(opcode uint32) bool { + switch opcode { + case 1: + return true + } + return false +} diff --git a/core/internal/proto/xml/linux-dmabuf-v1.xml b/core/internal/proto/xml/linux-dmabuf-v1.xml new file mode 100644 index 000000000..7d727f75d --- /dev/null +++ b/core/internal/proto/xml/linux-dmabuf-v1.xml @@ -0,0 +1,623 @@ + + + + + Copyright © 2014, 2015 Collabora, Ltd. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + This interface offers ways to create generic dmabuf-based wl_buffers. + + For more information about dmabuf, see: + https://www.kernel.org/doc/html/next/userspace-api/dma-buf-alloc-exchange.html + + Clients can use the get_surface_feedback request to get dmabuf feedback + for a particular surface. If the client wants to retrieve feedback not + tied to a surface, they can use the get_default_feedback request. + + The following are required from clients: + + - Clients must ensure that either all data in the dma-buf is + coherent for all subsequent read access or that coherency is + correctly handled by the underlying kernel-side dma-buf + implementation. + + - Don't make any more attachments after sending the buffer to the + compositor. Making more attachments later increases the risk of + the compositor not being able to use (re-import) an existing + dmabuf-based wl_buffer. + + The underlying graphics stack must ensure the following: + + - The dmabuf file descriptors relayed to the server will stay valid + for the whole lifetime of the wl_buffer. This means the server may + at any time use those fds to import the dmabuf into any kernel + sub-system that might accept it. + + However, when the underlying graphics stack fails to deliver the + promise, because of e.g. a device hot-unplug which raises internal + errors, after the wl_buffer has been successfully created the + compositor must not raise protocol errors to the client when dmabuf + import later fails. + + To create a wl_buffer from one or more dmabufs, a client creates a + zwp_linux_buffer_params_v1 object with a zwp_linux_dmabuf_v1.create_params + request. All planes required by the intended format are added with + the 'add' request. Finally, a 'create' or 'create_immed' request is + issued, which has the following outcome depending on the import success. + + The 'create' request, + - on success, triggers a 'created' event which provides the final + wl_buffer to the client. + - on failure, triggers a 'failed' event to convey that the server + cannot use the dmabufs received from the client. + + For the 'create_immed' request, + - on success, the server immediately imports the added dmabufs to + create a wl_buffer. No event is sent from the server in this case. + - on failure, the server can choose to either: + - terminate the client by raising a fatal error. + - mark the wl_buffer as failed, and send a 'failed' event to the + client. If the client uses a failed wl_buffer as an argument to any + request, the behaviour is compositor implementation-defined. + + For all DRM formats and unless specified in another protocol extension, + pre-multiplied alpha is used for pixel values. + + Unless specified otherwise in another protocol extension, implicit + synchronization is used. In other words, compositors and clients must + wait and signal fences implicitly passed via the DMA-BUF's reservation + mechanism. + + + + + Objects created through this interface, especially wl_buffers, will + remain valid. + + + + + + This temporary object is used to collect multiple dmabuf handles into + a single batch to create a wl_buffer. It can only be used once and + should be destroyed after a 'created' or 'failed' event has been + received. + + + + + + + This event advertises one buffer format that the server supports. + All the supported formats are advertised once when the client + binds to this interface. A roundtrip after binding guarantees + that the client has received all supported formats. + + For the definition of the format codes, see the + zwp_linux_buffer_params_v1::create request. + + Starting version 4, the format event is deprecated and must not be + sent by compositors. Instead, use get_default_feedback or + get_surface_feedback. + + + + + + + This event advertises the formats that the server supports, along with + the modifiers supported for each format. All the supported modifiers + for all the supported formats are advertised once when the client + binds to this interface. A roundtrip after binding guarantees that + the client has received all supported format-modifier pairs. + + For legacy support, DRM_FORMAT_MOD_INVALID (that is, modifier_hi == + 0x00ffffff and modifier_lo == 0xffffffff) is allowed in this event. + It indicates that the server can support the format with an implicit + modifier. When a plane has DRM_FORMAT_MOD_INVALID as its modifier, it + is as if no explicit modifier is specified. The effective modifier + will be derived from the dmabuf. + + A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for + a given format supports both explicit modifiers and implicit modifiers. + + For the definition of the format and modifier codes, see the + zwp_linux_buffer_params_v1::create and zwp_linux_buffer_params_v1::add + requests. + + Starting version 4, the modifier event is deprecated and must not be + sent by compositors. Instead, use get_default_feedback or + get_surface_feedback. + + + + + + + + + + + This request creates a new zwp_linux_dmabuf_feedback_v1 object not bound + to a particular surface. This object will deliver feedback about dmabuf + parameters to use if the client doesn't support per-surface feedback + (see get_surface_feedback). + + + + + + + This request creates a new zwp_linux_dmabuf_feedback_v1 object for the + specified wl_surface. This object will deliver feedback about dmabuf + parameters to use for buffers attached to this surface. + + If the surface is destroyed before the zwp_linux_dmabuf_feedback_v1 object, + the feedback object becomes inert. + + + + + + + + + This temporary object is a collection of dmabufs and other + parameters that together form a single logical buffer. The temporary + object may eventually create one wl_buffer unless cancelled by + destroying it before requesting 'create'. + + Single-planar formats only require one dmabuf, however + multi-planar formats may require more than one dmabuf. For all + formats, an 'add' request must be called once per plane (even if the + underlying dmabuf fd is identical). + + You must use consecutive plane indices ('plane_idx' argument for 'add') + from zero to the number of planes used by the drm_fourcc format code. + All planes required by the format must be given exactly once, but can + be given in any order. Each plane index can only be set once; subsequent + calls with a plane index which has already been set will result in a + plane_set error being generated. + + + + + + + + + + + + + + + + + Cleans up the temporary data sent to the server for dmabuf-based + wl_buffer creation. + + + + + + This request adds one dmabuf to the set in this + zwp_linux_buffer_params_v1. + + The 64-bit unsigned value combined from modifier_hi and modifier_lo + is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the + fb modifier, which is defined in drm_mode.h of Linux UAPI. + This is an opaque token. Drivers use this token to express tiling, + compression, etc. driver-specific modifications to the base format + defined by the DRM fourcc code. + + Starting from version 4, the invalid_format protocol error is sent if + the format + modifier pair was not advertised as supported. + + Starting from version 5, the invalid_format protocol error is sent if + all planes don't use the same modifier. + + This request raises the PLANE_IDX error if plane_idx is too large. + The error PLANE_SET is raised if attempting to set a plane that + was already set. + + + + + + + + + + + + + + + + + + This asks for creation of a wl_buffer from the added dmabuf + buffers. The wl_buffer is not created immediately but returned via + the 'created' event if the dmabuf sharing succeeds. The sharing + may fail at runtime for reasons a client cannot predict, in + which case the 'failed' event is triggered. + + The 'format' argument is a DRM_FORMAT code, as defined by the + libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the + authoritative source on how the format codes should work. + + The 'flags' is a bitfield of the flags defined in enum "flags". + 'y_invert' means that the image needs to be y-flipped. + + Flag 'interlaced' means that the frame in the buffer is not + progressive as usual, but interlaced. An interlaced buffer as + supported here must always contain both top and bottom fields. + The top field always begins on the first pixel row. The temporal + ordering between the two fields is top field first, unless + 'bottom_first' is specified. It is undefined whether 'bottom_first' + is ignored if 'interlaced' is not set. + + This protocol does not convey any information about field rate, + duration, or timing, other than the relative ordering between the + two fields in one buffer. A compositor may have to estimate the + intended field rate from the incoming buffer rate. It is undefined + whether the time of receiving wl_surface.commit with a new buffer + attached, applying the wl_surface state, wl_surface.frame callback + trigger, presentation, or any other point in the compositor cycle + is used to measure the frame or field times. There is no support + for detecting missed or late frames/fields/buffers either, and + there is no support whatsoever for cooperating with interlaced + compositor output. + + The composited image quality resulting from the use of interlaced + buffers is explicitly undefined. A compositor may use elaborate + hardware features or software to deinterlace and create progressive + output frames from a sequence of interlaced input buffers, or it + may produce substandard image quality. However, compositors that + cannot guarantee reasonable image quality in all cases are recommended + to just reject all interlaced buffers. + + Any argument errors, including non-positive width or height, + mismatch between the number of planes and the format, bad + format, bad offset or stride, may be indicated by fatal protocol + errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, + OUT_OF_BOUNDS. + + Dmabuf import errors in the server that are not obvious client + bugs are returned via the 'failed' event as non-fatal. This + allows attempting dmabuf sharing and falling back in the client + if it fails. + + This request can be sent only once in the object's lifetime, after + which the only legal request is destroy. This object should be + destroyed after issuing a 'create' request. Attempting to use this + object after issuing 'create' raises the ALREADY_USED protocol error. + + It is not mandatory to issue 'create'. If a client wants to + cancel the buffer creation, it can just destroy this object. + + + + + + + + + + This event indicates that the attempted buffer creation was + successful. It provides the new wl_buffer referencing the dmabuf(s). + + Upon receiving this event, the client should destroy the + zwp_linux_buffer_params_v1 object. + + + + + + + This event indicates that the attempted buffer creation has + failed. It usually means that one of the dmabuf constraints + has not been fulfilled. + + Upon receiving this event, the client should destroy the + zwp_linux_buffer_params_v1 object. + + + + + + This asks for immediate creation of a wl_buffer by importing the + added dmabufs. + + In case of import success, no event is sent from the server, and the + wl_buffer is ready to be used by the client. + + Upon import failure, either of the following may happen, as seen fit + by the implementation: + - the client is terminated with one of the following fatal protocol + errors: + - INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS, + in case of argument errors such as mismatch between the number + of planes and the format, bad format, non-positive width or + height, or bad offset or stride. + - INVALID_WL_BUFFER, in case the cause for failure is unknown or + platform specific. + - the server creates an invalid wl_buffer, marks it as failed and + sends a 'failed' event to the client. The result of using this + invalid wl_buffer as an argument in any request by the client is + defined by the compositor implementation. + + This takes the same arguments as a 'create' request, and obeys the + same restrictions. + + + + + + + + + + + Set the device the compositor should import the dmabufs to for sampling + in the next create or create_immed request. + + To avoid race conditions when the compositor removes a device from the + tranches, it is not a protocol error if the device hasn't been advertised + by the compositor in a tranche with the sampling flag, but the import is + likely to fail in that case. + + If the client doesn't know a suitable target device, it shouldn't set one, + and the compositor should attempt import on all devices it supports. + + If the array is too small to contain a dev_t or larger than required, the + invalid_dev_t_size error will be emitted. + + + + + + + + This object advertises dmabuf parameters feedback. This includes the + preferred devices and the supported formats/modifiers. + + The parameters are sent once when this object is created and whenever they + change. The done event is always sent once after all parameters have been + sent. When a single parameter changes, all parameters are re-sent by the + compositor. + + Compositors can re-send the parameters when the current client buffer + allocations are sub-optimal. Compositors should not re-send the + parameters if re-allocating the buffers would not result in a more optimal + configuration. In particular, compositors should avoid sending the exact + same parameters multiple times in a row. + + The tranche_target_device and tranche_formats events are grouped by + tranches of preference. For each tranche, a tranche_target_device, one + tranche_flags and one or more tranche_formats events are sent, followed + by a tranche_done event finishing the list. The tranches are sent in + descending order of preference. All formats and modifiers in the same + tranche have the same preference. + + To send parameters, the compositor sends one main_device event (unless + the client bound version 6 or above), tranches (each consisting of one + tranche_target_device event, one tranche_flags event, tranche_formats + events and then a tranche_done event), then one done event. + + With version 6 and above, the compositor must always advertise at least + one tranche with the sampling flag set. + + + + + Using this request a client can tell the server that it is not going to + use the zwp_linux_dmabuf_feedback_v1 object anymore. + + + + + + This event is sent after all parameters of a zwp_linux_dmabuf_feedback_v1 + object have been sent. + + This allows changes to the zwp_linux_dmabuf_feedback_v1 parameters to be + seen as atomic, even if they happen via multiple events. + + + + + + This event provides a file descriptor which can be memory-mapped to + access the format and modifier table. + + The table contains a tightly packed array of consecutive format + + modifier pairs. Each pair is 16 bytes wide. It contains a format as a + 32-bit unsigned integer, followed by 4 bytes of unused padding, and a + modifier as a 64-bit unsigned integer. The native endianness is used. + + The client must map the file descriptor in read-only private mode. + + Compositors are not allowed to mutate the table file contents once this + event has been sent. Instead, compositors must create a new, separate + table file and re-send feedback parameters. Compositors are allowed to + store duplicate format + modifier pairs in the table. + + + + + + + + This event advertises the main device that the server prefers to use + when direct scan-out to the target device isn't possible. The + advertised main device may be different for each + zwp_linux_dmabuf_feedback_v1 object, and may change over time. + + There is exactly one main device. The compositor must send at least + one preference tranche with tranche_target_device equal to main_device. + + Clients need to create buffers that the main device can import and + read from, otherwise creating the dmabuf wl_buffer will fail (see the + zwp_linux_buffer_params_v1.create and create_immed requests for details). + The main device will also likely be kept active by the compositor, + so clients can use it instead of waking up another device for power + savings. + + In general the device is a DRM node. The DRM node type (primary vs. + render) is unspecified. Clients must not rely on the compositor sending + a particular node type. Clients cannot check two devices for equality + by comparing the dev_t value. + + If explicit modifiers are not supported and the client performs buffer + allocations on a different device than the main device, then the client + must force the buffer to have a linear layout. + + With version 6 and above, this event is no longer sent. Clients should + use a device with the sampling flag in the tranches instead. + + + + + + + This event splits tranche_target_device and tranche_formats events into + preference tranches. It is sent after a set of tranche_target_device + and tranche_formats events; it represents the end of a tranche. The + next tranche will have a lower preference. + + + + + + This event advertises the target device that the server prefers to use + for a buffer created given this tranche. The advertised target device + may be different for each preference tranche, and may change over time. + + There is exactly one target device per tranche. + + The target device may be a scan-out device, for example if the + compositor prefers to directly scan-out a buffer created given this + tranche. The target device may be a rendering device, for example if + the compositor prefers to texture from said buffer. + + The client can use this hint to allocate the buffer in a way that makes + it accessible from the target device, ideally directly. The buffer must + still be accessible from a device with the sampling flag, either through + direct import or a potentially more expensive fallback path. If the + buffer can't be directly imported for sampling, then clients must be + prepared for the compositor changing the tranche priority or making + wl_buffer creation fail (see the zwp_linux_buffer_params_v1.create and + create_immed requests for details). + + If the device is a DRM node, the DRM node type (primary vs. render) is + unspecified. Clients must not rely on the compositor sending a + particular node type. Clients cannot check two devices for equality by + comparing the dev_t value. + + This event is tied to a preference tranche, see the tranche_done event. + + + + + + + This event advertises the format + modifier combinations that the + compositor supports. + + It carries an array of indices, each referring to a format + modifier + pair in the last received format table (see the format_table event). + Each index is a 16-bit unsigned integer in native endianness. + + For legacy support, DRM_FORMAT_MOD_INVALID is an allowed modifier. + It indicates that the server can support the format with an implicit + modifier. When a buffer has DRM_FORMAT_MOD_INVALID as its modifier, it + is as if no explicit modifier is specified. The effective modifier + will be derived from the dmabuf. + + A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for + a given format supports both explicit modifiers and implicit modifiers. + + Compositors must not send duplicate format + modifier pairs within the + same tranche or across two different tranches with the same target + device and flags. + + This event is tied to a preference tranche, see the tranche_done event. + + For the definition of the format and modifier codes, see the + zwp_linux_buffer_params_v1.create request. + + + + + + + + The scanout flag is a hint that direct scan-out may be attempted by + the compositor on the target device if the client appropriately + allocates a buffer. How to allocate a buffer that can be scanned out + on the target device is implementation-defined. + + + + + The sampling flag describes that the compositor is able to efficiently + sample from buffers imported to the target device if the client + appropriately allocates a buffer. How to allocate a buffer that can be + efficiently sampled on the target device is implementation defined. + + + + + + + This event sets tranche-specific flags. This event is tied to a + preference tranche, see the tranche_done event. + With version 6 and above, the compositor must set at least one flag + in each tranche. + + + + + +