github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/shiny/driver/x11driver/buffer.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package x11driver
     6  
     7  import (
     8  	"image"
     9  	"image/color"
    10  	"image/draw"
    11  	"log"
    12  	"sync"
    13  	"unsafe"
    14  
    15  	"github.com/BurntSushi/xgb"
    16  	"github.com/BurntSushi/xgb/render"
    17  	"github.com/BurntSushi/xgb/shm"
    18  	"github.com/BurntSushi/xgb/xproto"
    19  
    20  	"golang.org/x/exp/shiny/driver/internal/swizzle"
    21  	"golang.org/x/exp/shiny/screen"
    22  )
    23  
    24  type bufferImpl struct {
    25  	s *screenImpl
    26  
    27  	addr unsafe.Pointer
    28  	buf  []byte
    29  	rgba image.RGBA
    30  	size image.Point
    31  	xs   shm.Seg
    32  
    33  	mu        sync.Mutex
    34  	nUpload   uint32
    35  	reusable  bool
    36  	released  bool
    37  	cleanedUp bool
    38  }
    39  
    40  func (b *bufferImpl) Size() image.Point       { return b.size }
    41  func (b *bufferImpl) Bounds() image.Rectangle { return image.Rectangle{Max: b.size} }
    42  func (b *bufferImpl) RGBA() *image.RGBA       { return &b.rgba }
    43  
    44  func (b *bufferImpl) preUpload(reusable bool) {
    45  	b.mu.Lock()
    46  	defer b.mu.Unlock()
    47  
    48  	if b.released {
    49  		panic("x11driver: Buffer.Upload called after Buffer.Release")
    50  	}
    51  	if b.nUpload == 0 {
    52  		swizzle.BGRA(b.buf)
    53  	}
    54  	b.nUpload++
    55  	b.reusable = b.reusable && reusable
    56  }
    57  
    58  func (b *bufferImpl) postUpload() {
    59  	b.mu.Lock()
    60  	defer b.mu.Unlock()
    61  
    62  	b.nUpload--
    63  	if b.nUpload != 0 {
    64  		return
    65  	}
    66  
    67  	if b.released {
    68  		go b.cleanUp()
    69  	} else if b.reusable {
    70  		swizzle.BGRA(b.buf)
    71  	}
    72  }
    73  
    74  func (b *bufferImpl) Release() {
    75  	b.mu.Lock()
    76  	defer b.mu.Unlock()
    77  
    78  	if !b.released && b.nUpload == 0 {
    79  		go b.cleanUp()
    80  	}
    81  	b.released = true
    82  }
    83  
    84  func (b *bufferImpl) cleanUp() {
    85  	b.mu.Lock()
    86  	if b.cleanedUp {
    87  		b.mu.Unlock()
    88  		panic("x11driver: Buffer clean-up occurred twice")
    89  	}
    90  	b.cleanedUp = true
    91  	b.mu.Unlock()
    92  
    93  	b.s.mu.Lock()
    94  	delete(b.s.buffers, b.xs)
    95  	b.s.mu.Unlock()
    96  
    97  	shm.Detach(b.s.xc, b.xs)
    98  	if err := shmClose(b.addr); err != nil {
    99  		log.Printf("x11driver: shmClose: %v", err)
   100  	}
   101  }
   102  
   103  func (b *bufferImpl) upload(u screen.Uploader, xd xproto.Drawable, xg xproto.Gcontext, depth uint8,
   104  	dp image.Point, sr image.Rectangle) {
   105  
   106  	b.preUpload(true)
   107  
   108  	// TODO: adjust if dp is outside dst bounds, or sr is outside src bounds.
   109  	dr := sr.Sub(sr.Min).Add(dp)
   110  
   111  	b.s.mu.Lock()
   112  	b.s.nPendingUploads++
   113  	b.s.mu.Unlock()
   114  
   115  	cookie := shm.PutImage(
   116  		b.s.xc, xd, xg,
   117  		uint16(b.size.X), uint16(b.size.Y), // TotalWidth, TotalHeight,
   118  		uint16(sr.Min.X), uint16(sr.Min.Y), // SrcX, SrcY,
   119  		uint16(dr.Dx()), uint16(dr.Dy()), // SrcWidth, SrcHeight,
   120  		int16(dr.Min.X), int16(dr.Min.Y), // DstX, DstY,
   121  		depth, xproto.ImageFormatZPixmap,
   122  		1, b.xs, 0, // 1 means send a completion event, 0 means a zero offset.
   123  	)
   124  
   125  	completion := make(chan struct{})
   126  
   127  	b.s.mu.Lock()
   128  	b.s.uploads[cookie.Sequence] = completion
   129  	b.s.nPendingUploads--
   130  	b.s.handleCompletions()
   131  	b.s.mu.Unlock()
   132  
   133  	<-completion
   134  
   135  	b.postUpload()
   136  }
   137  
   138  func fill(xc *xgb.Conn, xp render.Picture, dr image.Rectangle, src color.Color, op draw.Op) {
   139  	r, g, b, a := src.RGBA()
   140  	c := render.Color{
   141  		Red:   uint16(r),
   142  		Green: uint16(g),
   143  		Blue:  uint16(b),
   144  		Alpha: uint16(a),
   145  	}
   146  	x, y := dr.Min.X, dr.Min.Y
   147  	if x < -0x8000 || 0x7fff < x || y < -0x8000 || 0x7fff < y {
   148  		return
   149  	}
   150  	dx, dy := dr.Dx(), dr.Dy()
   151  	if dx < 0 || 0xffff < dx || dy < 0 || 0xffff < dy {
   152  		return
   153  	}
   154  	render.FillRectangles(xc, renderOp(op), xp, c, []xproto.Rectangle{{
   155  		X:      int16(x),
   156  		Y:      int16(y),
   157  		Width:  uint16(dx),
   158  		Height: uint16(dy),
   159  	}})
   160  }