-
Notifications
You must be signed in to change notification settings - Fork 282
/
texture-registry.go
151 lines (127 loc) · 4.02 KB
/
texture-registry.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package flutter
import (
"fmt"
"sync"
"github.com/go-flutter-desktop/go-flutter/embedder"
"github.com/go-flutter-desktop/go-flutter/internal/opengl"
"github.com/go-flutter-desktop/go-flutter/internal/tasker"
"github.com/go-gl/glfw/v3.3/glfw"
"github.com/pkg/errors"
)
// once is used for the lazy initialization of go-gl/gl.
// The initialization occur on the first requested texture's frame.
var once sync.Once
// TextureRegistry is a registry entry for a managed Texture.
type TextureRegistry struct {
window *glfw.Window
engine *embedder.FlutterEngine
channels map[int64]*externalTextureHanlder
channelsLock sync.RWMutex
// engineTasker holds tasks which must be executed in the engine thread
engineTasker *tasker.Tasker
texture int64
texturesLock sync.Mutex
}
type externalTextureHanlder struct {
// handle is called when flutter needs the PixelBuffer
handle ExternalTextureHanlderFunc
// gl texture to refer to for this handler
texture uint32
}
func newTextureRegistry(engine *embedder.FlutterEngine, window *glfw.Window) *TextureRegistry {
return &TextureRegistry{
window: window,
engine: engine,
channels: make(map[int64]*externalTextureHanlder),
engineTasker: tasker.New(),
}
}
// init must happen in engine thread
func (t *TextureRegistry) init() error {
t.window.MakeContextCurrent()
// Important! Call open.Init only under the presence of an active OpenGL context,
// i.e., after MakeContextCurrent.
if err := opengl.Init(); err != nil {
return errors.Wrap(err, "TextureRegistry gl init failed")
}
return nil
}
// NewTexture creates a new Texture
func (t *TextureRegistry) NewTexture() Texture {
t.texturesLock.Lock()
defer t.texturesLock.Unlock()
t.texture++
return Texture{ID: t.texture, registry: t}
}
// ExternalTextureHanlderFunc describes the function that handles external
// Texture on a given ID.
type ExternalTextureHanlderFunc func(width int, height int) (bool, *PixelBuffer)
// PixelBuffer is an in-memory (RGBA) image.
type PixelBuffer struct {
// Pix holds the image's pixels, in R, G, B, A order.
Pix []uint8
// Width and Height of the image's bounds
Width, Height int
}
// setTextureHandler registers a handler to be invoked when the Flutter
// application want to get a PixelBuffer to draw into the scene.
//
// Registration overwrites any previous registration for the same textureID
// name. Use nil as handler to deregister.
func (t *TextureRegistry) setTextureHandler(textureID int64, handler ExternalTextureHanlderFunc) {
t.channelsLock.Lock()
if handler == nil {
texture := t.channels[textureID]
if texture != nil {
t.engineTasker.Do(func() {
// Must run on the main tread
opengl.DeleteTextures(1, &texture.texture)
})
}
delete(t.channels, textureID)
} else {
t.channels[textureID] = &externalTextureHanlder{
handle: handler,
}
}
t.channelsLock.Unlock()
}
// handleExternalTexture receive low level C calls to create and/or update the
// content of a OpenGL TexImage2D.
// Calls must happen on the engine thread, no need to use engineTasker as this
// function is a callback directly managed by the engine.
func (t *TextureRegistry) handleExternalTexture(textureID int64,
width int, height int) *embedder.FlutterOpenGLTexture {
once.Do(func() {
t.init()
})
t.channelsLock.RLock()
registration, registrationExists := t.channels[textureID]
t.channelsLock.RUnlock()
if !registrationExists {
fmt.Printf("go-flutter: no texture handler found for Texture ID: %v\n", textureID)
return nil
}
res, pixelBuffer := registration.handle(width, height)
if !res || pixelBuffer == nil {
return nil
}
if len(pixelBuffer.Pix) == 0 {
return nil
}
t.window.MakeContextCurrent()
if registration.texture == 0 {
opengl.CreateTexture(®istration.texture)
}
opengl.BindTexture(registration.texture)
opengl.TexImage2D(
int32(pixelBuffer.Width),
int32(pixelBuffer.Height),
opengl.Ptr(pixelBuffer.Pix),
)
return &embedder.FlutterOpenGLTexture{
Target: opengl.TEXTURE2D,
Name: registration.texture,
Format: opengl.RGBA8,
}
}