github.com/as/shiny@v0.8.2/driver/windriver/texture.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  // +build windows
     6  
     7  package windriver
     8  
     9  import (
    10  	"github.com/as/shiny/driver/internal/swizzle"
    11  	"github.com/as/shiny/driver/win32"
    12  	"github.com/as/shiny/screen"
    13  	"image"
    14  	"image/color"
    15  	"image/draw"
    16  	"sync"
    17  	"syscall"
    18  	"unsafe"
    19  )
    20  
    21  type textureImpl struct {
    22  	size   image.Point
    23  	dc     syscall.Handle
    24  	bitmap syscall.Handle
    25  
    26  	mu       sync.Mutex
    27  	released bool
    28  }
    29  
    30  type handleCreateTextureParams struct {
    31  	size   image.Point
    32  	dc     syscall.Handle
    33  	bitmap syscall.Handle
    34  	err    error
    35  }
    36  
    37  var msgCreateTexture = win32.AddScreenMsg(handleCreateTexture)
    38  
    39  func newTexture(size image.Point) (screen.Texture, error) {
    40  	p := handleCreateTextureParams{size: size}
    41  	win32.SendScreenMessage(msgCreateTexture, 0, uintptr(unsafe.Pointer(&p)))
    42  	if p.err != nil {
    43  		return nil, p.err
    44  	}
    45  	return &textureImpl{
    46  		size:   size,
    47  		dc:     p.dc,
    48  		bitmap: p.bitmap,
    49  	}, nil
    50  }
    51  
    52  func handleCreateTexture(hwnd syscall.Handle, uMsg uint32, wParam, lParam uintptr) {
    53  	// This code needs to run on Windows message pump thread.
    54  	// Firstly, it calls GetDC(nil) and, according to Windows documentation
    55  	// (https://msdn.microsoft.com/en-us/library/windows/desktop/dd144871(v=vs.85).aspx),
    56  	// has to be released on the same thread.
    57  	// Secondly, according to Windows documentation
    58  	// (https://msdn.microsoft.com/en-us/library/windows/desktop/dd183489(v=vs.85).aspx),
    59  	// ... thread that calls CreateCompatibleDC owns the HDC that is created.
    60  	// When this thread is destroyed, the HDC is no longer valid. ...
    61  	// So making Windows message pump thread own returned HDC makes DC
    62  	// live as long as we want to.
    63  	p := (*handleCreateTextureParams)(unsafe.Pointer(lParam))
    64  
    65  	screenDC, err := win32.GetDC(0)
    66  	if err != nil {
    67  		p.err = err
    68  		return
    69  	}
    70  	defer win32.ReleaseDC(0, screenDC)
    71  
    72  	dc, err := win32.CreateCompatibleDC(screenDC)
    73  	if err != nil {
    74  		p.err = err
    75  		return
    76  	}
    77  	bitmap, err := win32.CreateCompatibleBitmap(screenDC, int32(p.size.X), int32(p.size.Y))
    78  	if err != nil {
    79  		win32.DeleteDC(dc)
    80  		p.err = err
    81  		return
    82  	}
    83  	p.dc = dc
    84  	p.bitmap = bitmap
    85  }
    86  
    87  func (t *textureImpl) Bounds() image.Rectangle {
    88  	return image.Rectangle{Max: t.size}
    89  }
    90  
    91  func (t *textureImpl) Fill(r image.Rectangle, c color.Color, op draw.Op) {
    92  	err := t.update(func(dc syscall.Handle) error {
    93  		return fill(dc, r, c, op)
    94  	})
    95  	if err != nil {
    96  		panic(err) // TODO handle error
    97  	}
    98  }
    99  
   100  func (t *textureImpl) Release() {
   101  	if err := t.release(); err != nil {
   102  		panic(err) // TODO handle error
   103  	}
   104  }
   105  
   106  func (t *textureImpl) release() error {
   107  	t.mu.Lock()
   108  	defer t.mu.Unlock()
   109  
   110  	if t.released {
   111  		return nil
   112  	}
   113  	t.released = true
   114  
   115  	err := win32.DeleteObject(t.bitmap)
   116  	if err != nil {
   117  		return err
   118  	}
   119  	return win32.DeleteDC(t.dc)
   120  }
   121  
   122  func (t *textureImpl) Size() image.Point {
   123  	return t.size
   124  }
   125  
   126  func (t *textureImpl) Upload(dp image.Point, src screen.Buffer, sr image.Rectangle) {
   127  	b := src.(*bufferImpl).buf
   128  	b2 := src.(*bufferImpl).buf2
   129  	swizzle.Swizzle(b2, b)
   130  	src.(*bufferImpl).blitToDC(t.dc, dp, sr)
   131  }
   132  
   133  // update prepares texture t for update and executes f over texture device
   134  // context dc in a safe manner.
   135  func (t *textureImpl) update(f func(dc syscall.Handle) error) (retErr error) {
   136  
   137  	// Select t.bitmap into t.dc, so our drawing gets recorded
   138  	// into t.bitmap and not into 1x1 default bitmap created
   139  	// during CreateCompatibleDC call.
   140  	_, err := win32.SelectObject(t.dc, t.bitmap)
   141  	if err != nil {
   142  		return err
   143  	}
   144  
   145  	return f(t.dc)
   146  }