-
Notifications
You must be signed in to change notification settings - Fork 1
/
renderCrtc.go
143 lines (123 loc) · 4.04 KB
/
renderCrtc.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
package frenyard
import (
"runtime"
)
type crtcContext interface{}
// Cross-Renderer Texture Cache.
// Not needed until we have to deal with multiple windows or render-targets.
type crtcRegistry struct {
// A queue of textures to delete. Must be buffered or else.
InternalTexturesToDelete chan *crtcTextureInternal
// The full set of crtcLocalTexture entries. Has to be here for Renderer deletion.
_fyCrtcRegistryAllLocalTextures map[crtcContext]map[*crtcTextureInternal]crtcLocalTexture
}
func newCRTCRegistryPtr() *crtcRegistry {
return &crtcRegistry{
make(chan *crtcTextureInternal, 1),
map[crtcContext]map[*crtcTextureInternal]crtcLocalTexture{},
}
}
// CreateTexture is at the very bottom as the creator of crtcTextureInternal
// Cleans up internal textures that are no longer referenced.
// Run this every so often.
func (cr *crtcRegistry) osFlush() {
if len(cr.InternalTexturesToDelete) > 0 {
tex := <-cr.InternalTexturesToDelete
tex.osDelete()
}
}
func (cr *crtcRegistry) osGetRendererEntry(r crtcContext) map[*crtcTextureInternal]crtcLocalTexture {
alt, altPresent := cr._fyCrtcRegistryAllLocalTextures[r]
if !altPresent {
alt = map[*crtcTextureInternal]crtcLocalTexture{}
cr._fyCrtcRegistryAllLocalTextures[r] = alt
}
return alt
}
// Use to notify CRTC that a Renderer is going away.
// This deletes all local textures for the given renderer.
func (cr *crtcRegistry) osRemoveRenderer(r crtcContext) {
remnant, present := cr._fyCrtcRegistryAllLocalTextures[r]
if present {
for _, v := range remnant {
v.osDelete()
}
delete(cr._fyCrtcRegistryAllLocalTextures, r)
}
}
type crtcLocalTexture interface {
osDelete()
}
/*
* This is an abstraction over the backend's cross-renderer image format (such as sdl.Surface)
* Inherits Texture because this is the real Texture implementation
*/
type crtcTextureData interface {
Texture
osMakeLocal(target crtcContext) crtcLocalTexture
// This does not have to delete the local textures; that is automatic.
osDelete()
}
// This is the 'cross-renderer texture' structure. This is where the cache is attached.
type crtcTextureInternal struct {
// The registry hosting this. (Creates a reference loop, but it's all cleaned up later)
Registry *crtcRegistry
// The backend's data. May be nil if this is a local-only texture.
Data crtcTextureData
// The size of the texture.
Size Vec2i
}
func (c *crtcTextureInternal) osDelete() {
if c.Data != nil {
c.Data.osDelete()
}
for _, rv := range c.Registry._fyCrtcRegistryAllLocalTextures {
purgeMe := rv[c]
if purgeMe != nil {
purgeMe.osDelete()
}
delete(rv, c)
}
}
// DO NOT HOLD IN crtcLocalTexture or fyCRTCTextureReal! This value is the outer wrapper and finalization is used as a sentinel.
type crtcTextureExternal struct {
Internal *crtcTextureInternal
}
func (cte *crtcTextureExternal) Size() Vec2i {
return cte.Internal.Size
}
func (cte *crtcTextureExternal) osGetLocalTexture(r crtcContext) crtcLocalTexture {
alt := cte.Internal.Registry.osGetRendererEntry(r)
localTexture := alt[cte.Internal]
if localTexture == nil {
if cte.Internal.Data == nil {
panic("Attempted to use local texture outside of valid renderer")
}
localTexture = cte.Internal.Data.osMakeLocal(r)
alt[cte.Internal] = localTexture
}
return localTexture
}
func fyCRTCTextureFinalizer2(t *crtcTextureInternal) {
t.Registry.InternalTexturesToDelete <- t
}
func fyCRTCTextureFinalizer(ext *crtcTextureExternal) {
go fyCRTCTextureFinalizer2(ext.Internal)
}
func (cr *crtcRegistry) osCreateTexture(data crtcTextureData) Texture {
internal := &crtcTextureInternal{
Registry: cr,
Data: data,
Size: data.Size(),
}
external := &crtcTextureExternal{internal}
runtime.SetFinalizer(external, fyCRTCTextureFinalizer)
return external
}
func (cr *crtcRegistry) osCreateLocalTexture(renderer crtcContext, data crtcLocalTexture, size Vec2i) Texture {
internal := &crtcTextureInternal{cr, nil, size}
external := &crtcTextureExternal{internal}
cr.osGetRendererEntry(renderer)[internal] = data
runtime.SetFinalizer(external, fyCRTCTextureFinalizer)
return external
}