diff options
Diffstat (limited to 'vendor/golang.org/x/exp/shiny/driver/x11driver/buffer_fallback.go')
-rw-r--r-- | vendor/golang.org/x/exp/shiny/driver/x11driver/buffer_fallback.go | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/vendor/golang.org/x/exp/shiny/driver/x11driver/buffer_fallback.go b/vendor/golang.org/x/exp/shiny/driver/x11driver/buffer_fallback.go new file mode 100644 index 0000000..bfdd9c7 --- /dev/null +++ b/vendor/golang.org/x/exp/shiny/driver/x11driver/buffer_fallback.go @@ -0,0 +1,123 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package x11driver + +import ( + "image" + "sync" + + "github.com/BurntSushi/xgb" + "github.com/BurntSushi/xgb/xproto" + "golang.org/x/exp/shiny/driver/internal/swizzle" +) + +const ( + xPutImageReqSizeMax = (1 << 16) * 4 + xPutImageReqSizeFixed = 28 + xPutImageReqDataSize = xPutImageReqSizeMax - xPutImageReqSizeFixed +) + +type bufferFallbackImpl struct { + xc *xgb.Conn + + buf []byte + rgba image.RGBA + size image.Point + + mu sync.Mutex + nUpload uint32 + released bool +} + +func (b *bufferFallbackImpl) Size() image.Point { return b.size } +func (b *bufferFallbackImpl) Bounds() image.Rectangle { return image.Rectangle{Max: b.size} } +func (b *bufferFallbackImpl) RGBA() *image.RGBA { return &b.rgba } + +func (b *bufferFallbackImpl) preUpload() { + // Check that the program hasn't tried to modify the rgba field via the + // pointer returned by the bufferFallbackImpl.RGBA method. This check doesn't catch + // 100% of all cases; it simply tries to detect some invalid uses of a + // screen.Buffer such as: + // *buffer.RGBA() = anotherImageRGBA + if len(b.buf) != 0 && len(b.rgba.Pix) != 0 && &b.buf[0] != &b.rgba.Pix[0] { + panic("x11driver: invalid Buffer.RGBA modification") + } + + b.mu.Lock() + defer b.mu.Unlock() + + if b.released { + panic("x11driver: Buffer.Upload called after Buffer.Release") + } + if b.nUpload == 0 { + swizzle.BGRA(b.buf) + } + b.nUpload++ +} + +func (b *bufferFallbackImpl) postUpload() { + b.mu.Lock() + defer b.mu.Unlock() + + b.nUpload-- + if b.nUpload != 0 { + return + } + + if !b.released { + swizzle.BGRA(b.buf) + } +} + +func (b *bufferFallbackImpl) Release() { + b.mu.Lock() + defer b.mu.Unlock() + + b.released = true +} + +func (b *bufferFallbackImpl) upload(xd xproto.Drawable, xg xproto.Gcontext, depth uint8, dp image.Point, sr image.Rectangle) { + originalSRMin := sr.Min + sr = sr.Intersect(b.Bounds()) + if sr.Empty() { + return + } + dp = dp.Add(sr.Min.Sub(originalSRMin)) + b.preUpload() + + b.putImage(xd, xg, depth, dp, sr) + + b.postUpload() +} + +// putImage issues xproto.PutImage requests in batches. +func (b *bufferFallbackImpl) putImage(xd xproto.Drawable, xg xproto.Gcontext, depth uint8, dp image.Point, sr image.Rectangle) { + widthPerReq := b.size.X + rowPerReq := xPutImageReqDataSize / (widthPerReq * 4) + dataPerReq := rowPerReq * widthPerReq * 4 + dstX := dp.X + dstY := dp.Y + start := 0 + end := 0 + + for end < len(b.buf) { + end = start + dataPerReq + if end > len(b.buf) { + end = len(b.buf) + } + + data := b.buf[start:end] + heightPerReq := len(data) / (widthPerReq * 4) + + xproto.PutImage( + b.xc, xproto.ImageFormatZPixmap, xd, xg, + uint16(widthPerReq), uint16(heightPerReq), + int16(dstX), int16(dstY), + 0, depth, data) + + start = end + dstY += rowPerReq + } +} |