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
7package windriver
8
9import (
10	"image"
11	"image/draw"
12	"sync"
13	"syscall"
14
15	"golang.org/x/exp/shiny/driver/internal/swizzle"
16)
17
18type bufferImpl struct {
19	hbitmap syscall.Handle
20	buf     []byte
21	rgba    image.RGBA
22	size    image.Point
23
24	mu        sync.Mutex
25	nUpload   uint32
26	released  bool
27	cleanedUp bool
28}
29
30func (b *bufferImpl) Size() image.Point       { return b.size }
31func (b *bufferImpl) Bounds() image.Rectangle { return image.Rectangle{Max: b.size} }
32func (b *bufferImpl) RGBA() *image.RGBA       { return &b.rgba }
33
34func (b *bufferImpl) preUpload() {
35	// Check that the program hasn't tried to modify the rgba field via the
36	// pointer returned by the bufferImpl.RGBA method. This check doesn't catch
37	// 100% of all cases; it simply tries to detect some invalid uses of a
38	// screen.Buffer such as:
39	//	*buffer.RGBA() = anotherImageRGBA
40	if len(b.buf) != 0 && len(b.rgba.Pix) != 0 && &b.buf[0] != &b.rgba.Pix[0] {
41		panic("windriver: invalid Buffer.RGBA modification")
42	}
43
44	b.mu.Lock()
45	defer b.mu.Unlock()
46
47	if b.released {
48		panic("windriver: Buffer.Upload called after Buffer.Release")
49	}
50	if b.nUpload == 0 {
51		swizzle.BGRA(b.buf)
52	}
53	b.nUpload++
54}
55
56func (b *bufferImpl) postUpload() {
57	b.mu.Lock()
58	defer b.mu.Unlock()
59
60	b.nUpload--
61	if b.nUpload != 0 {
62		return
63	}
64
65	if b.released {
66		go b.cleanUp()
67	} else {
68		swizzle.BGRA(b.buf)
69	}
70}
71
72func (b *bufferImpl) Release() {
73	b.mu.Lock()
74	defer b.mu.Unlock()
75
76	if !b.released && b.nUpload == 0 {
77		go b.cleanUp()
78	}
79	b.released = true
80}
81
82func (b *bufferImpl) cleanUp() {
83	b.mu.Lock()
84	if b.cleanedUp {
85		b.mu.Unlock()
86		panic("windriver: Buffer clean-up occurred twice")
87	}
88	b.cleanedUp = true
89	b.mu.Unlock()
90
91	b.rgba.Pix = nil
92	_DeleteObject(b.hbitmap)
93}
94
95func (b *bufferImpl) blitToDC(dc syscall.Handle, dp image.Point, sr image.Rectangle) error {
96	b.preUpload()
97	defer b.postUpload()
98
99	dr := sr.Add(dp.Sub(sr.Min))
100	return copyBitmapToDC(dc, dr, b.hbitmap, sr, draw.Src)
101}
102