1package wayland
2
3import (
4 "github.com/bnema/go-wayland-bindings/server/colorrepresentation"
5 "github.com/bnema/go-wayland-bindings/server/wayland"
6 "github.com/bnema/purego-libwayland/server"
7)
8
9// The absent YUV representation defaults to BT.709 limited, type 0 chroma.
10// RGB without a representation retains premultiplied electrical samples.
11type surfaceRepresentation struct{ coefficients, rangeValue, chroma, alpha uint8 }
12
13const (
14 coefficientIdentity = uint8(colorrepresentation.WpColorRepresentationSurfaceV1CoefficientsIdentity)
15 coefficient709 = uint8(colorrepresentation.WpColorRepresentationSurfaceV1CoefficientsBt709)
16 coefficient601 = uint8(colorrepresentation.WpColorRepresentationSurfaceV1CoefficientsBt601)
17 coefficient2020 = uint8(colorrepresentation.WpColorRepresentationSurfaceV1CoefficientsBt2020)
18 rangeFull = uint8(colorrepresentation.WpColorRepresentationSurfaceV1RangeFull)
19 rangeLimited = uint8(colorrepresentation.WpColorRepresentationSurfaceV1RangeLimited)
20)
21
22func isYUV(format uint32) bool { return format == fourccNV12 || format == fourccP010 }
23
24func registerColorRepresentation(d *server.Display, s *Server) error {
25 return colorrepresentation.NewWpColorRepresentationManagerV1Global(d, 1, func(c server.Client, v, id uint32) {
26 r, err := colorrepresentation.NewWpColorRepresentationManagerV1(c, int32(v), id, representationManager{s})
27 if err != nil {
28 return
29 }
30 r.SendSupportedAlphaMode(uint32(colorrepresentation.WpColorRepresentationSurfaceV1AlphaModePremultipliedElectrical))
31 r.SendSupportedCoefficientsAndRanges(uint32(coefficientIdentity), uint32(rangeFull))
32 for _, coeff := range []uint8{coefficient601, coefficient709, coefficient2020} {
33 for _, ran := range []uint8{rangeLimited, rangeFull} {
34 r.SendSupportedCoefficientsAndRanges(uint32(coeff), uint32(ran))
35 }
36 }
37 r.SendDone()
38 })
39}
40
41type representationManager struct{ server *Server }
42
43func (representationManager) Destroy(*colorrepresentation.WpColorRepresentationManagerV1) {}
44func (m representationManager) GetSurface(r *colorrepresentation.WpColorRepresentationManagerV1, id uint32, wl *wayland.Surface) {
45 surf := m.server.surfaceOf(wl)
46 if surf != nil && surf.representationControl != nil {
47 r.PostError(uint32(colorrepresentation.WpColorRepresentationManagerV1ErrorSurfaceExists), "surface already has color representation")
48 return
49 }
50 h := &representationSurface{surf: surf}
51 res, err := colorrepresentation.NewWpColorRepresentationSurfaceV1(r.Client(), r.Version(), id, h)
52 if err != nil {
53 return
54 }
55 h.res = res
56 if surf != nil {
57 surf.representationControl = h
58 res.OnDestroy = func() {
59 if surf.representationControl == h {
60 surf.representationControl = nil
61 surf.next.representation = surfaceRepresentation{}
62 }
63 }
64 }
65}
66
67type representationSurface struct {
68 surf *surface
69 res *colorrepresentation.WpColorRepresentationSurfaceV1
70}
71
72func (h *representationSurface) Destroy(*colorrepresentation.WpColorRepresentationSurfaceV1) {
73 if h.surf != nil && !h.surf.destroyed {
74 h.surf.next.representation = surfaceRepresentation{}
75 }
76}
77func (h *representationSurface) live(r *colorrepresentation.WpColorRepresentationSurfaceV1) bool {
78 if h.surf == nil || h.surf.destroyed {
79 r.PostError(uint32(colorrepresentation.WpColorRepresentationSurfaceV1ErrorInert), "surface destroyed")
80 return false
81 }
82 return true
83}
84func (h *representationSurface) SetAlphaMode(r *colorrepresentation.WpColorRepresentationSurfaceV1, mode uint32) {
85 if !h.live(r) {
86 return
87 }
88 if mode != uint32(colorrepresentation.WpColorRepresentationSurfaceV1AlphaModePremultipliedElectrical) {
89 r.PostError(uint32(colorrepresentation.WpColorRepresentationSurfaceV1ErrorAlphaMode), "unsupported alpha mode")
90 return
91 }
92 h.surf.next.representation.alpha = uint8(mode)
93}
94func (h *representationSurface) SetCoefficientsAndRange(r *colorrepresentation.WpColorRepresentationSurfaceV1, coeff, ran uint32) {
95 if !h.live(r) {
96 return
97 }
98 valid := coeff == uint32(coefficientIdentity) && ran == uint32(rangeFull) ||
99 (coeff == uint32(coefficient601) || coeff == uint32(coefficient709) || coeff == uint32(coefficient2020)) && (ran == uint32(rangeFull) || ran == uint32(rangeLimited))
100 if !valid {
101 r.PostError(uint32(colorrepresentation.WpColorRepresentationSurfaceV1ErrorCoefficients), "unsupported coefficients or range")
102 return
103 }
104 h.surf.next.representation.coefficients, h.surf.next.representation.rangeValue = uint8(coeff), uint8(ran)
105}
106func (h *representationSurface) SetChromaLocation(r *colorrepresentation.WpColorRepresentationSurfaceV1, chroma uint32) {
107 if !h.live(r) {
108 return
109 }
110 if chroma != uint32(colorrepresentation.WpColorRepresentationSurfaceV1ChromaLocationType0) {
111 r.PostError(uint32(colorrepresentation.WpColorRepresentationSurfaceV1ErrorChromaLocation), "unsupported chroma location")
112 return
113 }
114 h.surf.next.representation.chroma = uint8(chroma)
115}
116
117// The metadata is checked against the buffer the commit will show,
118// including when a client changes representation without attaching a new
119// buffer: then the one of the last queued commit that attached, or the
120// current one.
121func (s *surface) checkRepresentationCommit() bool {
122 rep := s.next.representation
123 if rep.coefficients == 0 && rep.chroma == 0 {
124 return true
125 }
126 buffer := s.current
127 for i := len(s.queue) - 1; i >= 0; i-- {
128 if s.queue[i].attached {
129 buffer = s.queue[i].buffer
130 break
131 }
132 }
133 if s.next.attached {
134 buffer = s.next.buffer
135 }
136 if buffer == nil {
137 return true
138 }
139 b, ok := s.server.buffers[buffer.Resource]
140 if !ok {
141 return true
142 }
143 d, ok := b.(*dmabufBuffer)
144 yuv := ok && isYUV(d.buf.Format)
145 bad := rep.coefficients != 0 && (rep.coefficients == coefficientIdentity) == yuv || rep.chroma != 0 && !yuv
146 if bad && s.representationControl != nil && s.representationControl.res != nil {
147 s.representationControl.res.PostError(uint32(colorrepresentation.WpColorRepresentationSurfaceV1ErrorPixelFormat), "color representation incompatible with pixel format")
148 return false
149 }
150 return true
151}