-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmaterial_texture_test.go
More file actions
77 lines (64 loc) · 2.49 KB
/
Copy pathmaterial_texture_test.go
File metadata and controls
77 lines (64 loc) · 2.49 KB
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
package pix
import (
"testing"
)
import "github.com/bluescreen10/pix/textures"
// Reproduces what loaders/gltf does: one cached texture handed to two map slots.
func TestSharedTextureOwnership(t *testing.T) {
r, _ := NewOffscreenRenderer(16, 16)
defer r.Destroy()
tex := r.TextureStore.Create([]byte{255, 255, 255, 255}, 1, 1, textures.Linear)
m := r.NewPBRMaterial()
m.SetMetallicMap(tex)
m.SetRoughnessMap(tex) // same handle into a second slot
m.Release()
if !tex.Valid() {
t.Fatal("the caller's own texture reference was freed by the material")
}
tex.Release()
}
// TestSetMapSelfRebind pins the reason every SetXMap copies the incoming texture
// BEFORE releasing the one it is replacing: rebinding a map to the texture it already
// holds (m.SetColorMap(m.ColorMap())) is a valid, if unusual, caller pattern. Releasing
// first can drop the shared refcount to 0 and dispose the texture; the following Copy
// then re-bumps a refcount whose slot the store has already retired, leaving the
// material holding a corrupted Ref (see TestSetMapSelfRebindThenReleaseIsSafe for the
// worse consequence of that).
func TestSetMapSelfRebind(t *testing.T) {
r, err := NewOffscreenRenderer(16, 16)
if err != nil {
t.Fatal(err)
}
defer r.Destroy()
tex := r.TextureStore.Create([]byte{255, 255, 255, 255}, 1, 1, textures.Linear)
m := r.NewBasicMaterial()
m.SetColorMap(tex)
tex.Release() // the material should hold the only remaining reference
m.SetColorMap(m.ColorMap()) // rebind to itself
if !m.ColorMap().Valid() {
t.Fatal("self-rebind destroyed the texture")
}
}
// TestSetMapSelfRebindThenReleaseIsSafe is the sharper form of the same hazard: a
// release-before-copy ordering does not just invalidate the self-rebound handle, it
// leaks its refcount to a nonzero value tied to a retired generation. Releasing the
// material later then disposes whatever texture has since been allocated into that
// same store slot — a completely unrelated resource.
func TestSetMapSelfRebindThenReleaseIsSafe(t *testing.T) {
r, err := NewOffscreenRenderer(16, 16)
if err != nil {
t.Fatal(err)
}
defer r.Destroy()
tex := r.TextureStore.Create([]byte{255, 255, 255, 255}, 1, 1, textures.Linear)
m := r.NewBasicMaterial()
m.SetColorMap(tex)
tex.Release()
m.SetColorMap(m.ColorMap())
other := r.TextureStore.Create([]byte{0, 0, 0, 255}, 1, 1, textures.Linear)
defer other.Release()
m.Release()
if !other.Valid() {
t.Fatal("releasing the material after a self-rebind disposed an unrelated texture")
}
}