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 }