-
Notifications
You must be signed in to change notification settings - Fork 20
/
glsl_dbgscr.go
255 lines (221 loc) · 9.31 KB
/
glsl_dbgscr.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
// This file is part of Gopher2600.
//
// Gopher2600 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Gopher2600 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
package sdlimgui
import (
"github.com/go-gl/gl/v3.2-core/gl"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/gui/sdlimgui/shaders"
"github.com/jetsetilly/gopher2600/hardware/television/specification"
)
type dbgScrHelper struct {
showCursor int32 // uniform
isCropped int32 // uniform
screenDim int32 // uniform
scalingX int32 // uniform
scalingY int32 // uniform
lastX int32 // uniform
lastY int32 // uniform
hblank int32 // uniform
visibleTop int32 // uniform
visibleBottom int32 // uniform
magShow int32 // uniform
magXmin int32 // uniform
magXmax int32 // uniform
magYmin int32 // uniform
magYmax int32 // uniform
lastNewFrameAtScanline int32 // uniform
}
func (attr *dbgScrHelper) get(sh shader) {
attr.isCropped = gl.GetUniformLocation(sh.handle, gl.Str("IsCropped"+"\x00"))
attr.showCursor = gl.GetUniformLocation(sh.handle, gl.Str("ShowCursor"+"\x00"))
attr.screenDim = gl.GetUniformLocation(sh.handle, gl.Str("ScreenDim"+"\x00"))
attr.scalingX = gl.GetUniformLocation(sh.handle, gl.Str("ScalingX"+"\x00"))
attr.scalingY = gl.GetUniformLocation(sh.handle, gl.Str("ScalingY"+"\x00"))
attr.lastX = gl.GetUniformLocation(sh.handle, gl.Str("LastX"+"\x00"))
attr.lastY = gl.GetUniformLocation(sh.handle, gl.Str("LastY"+"\x00"))
attr.hblank = gl.GetUniformLocation(sh.handle, gl.Str("Hblank"+"\x00"))
attr.lastNewFrameAtScanline = gl.GetUniformLocation(sh.handle, gl.Str("LastNewFrameAtScanline"+"\x00"))
attr.visibleTop = gl.GetUniformLocation(sh.handle, gl.Str("VisibleTop"+"\x00"))
attr.visibleBottom = gl.GetUniformLocation(sh.handle, gl.Str("VisibleBottom"+"\x00"))
attr.magShow = gl.GetUniformLocation(sh.handle, gl.Str("MagShow"+"\x00"))
attr.magXmin = gl.GetUniformLocation(sh.handle, gl.Str("MagXmin"+"\x00"))
attr.magXmax = gl.GetUniformLocation(sh.handle, gl.Str("MagXmax"+"\x00"))
attr.magYmin = gl.GetUniformLocation(sh.handle, gl.Str("MagYmin"+"\x00"))
attr.magYmax = gl.GetUniformLocation(sh.handle, gl.Str("MagYmax"+"\x00"))
}
func (attr *dbgScrHelper) set(img *SdlImgui) {
// dimensions of screen
width := img.wm.dbgScr.scaledWidth
height := img.wm.dbgScr.scaledHeight
// scaling of screen
yscaling := img.wm.dbgScr.yscaling
xscaling := img.wm.dbgScr.xscaling
// critical section
img.screen.crit.section.Lock()
gl.Uniform1f(attr.scalingX, img.wm.dbgScr.xscaling)
gl.Uniform1f(attr.scalingY, img.wm.dbgScr.yscaling)
gl.Uniform2f(attr.screenDim, width, height)
// cursor is the coordinates of the *most recent* pixel to be drawn
cursorX := img.screen.crit.lastX
cursorY := img.screen.crit.lastY
// if crt preview is enabled then force cropping
if img.wm.dbgScr.cropped || img.wm.dbgScr.crtPreview {
gl.Uniform1f(attr.lastX, float32(cursorX-specification.ClksHBlank)*xscaling)
gl.Uniform1i(attr.isCropped, boolToInt32(true))
} else {
gl.Uniform1f(attr.lastX, float32(cursorX)*xscaling)
gl.Uniform1i(attr.isCropped, boolToInt32(false))
}
gl.Uniform1f(attr.lastY, float32(cursorY)*yscaling)
// screen geometry
gl.Uniform1f(attr.hblank, (specification.ClksHBlank)*xscaling)
gl.Uniform1f(attr.visibleTop, float32(img.screen.crit.frameInfo.VisibleTop)*yscaling)
gl.Uniform1f(attr.visibleBottom, float32(img.screen.crit.frameInfo.VisibleBottom)*yscaling)
gl.Uniform1f(attr.lastNewFrameAtScanline, float32(img.screen.crit.frameInfo.TotalScanlines)*yscaling)
// window magnification
var magXmin, magYmin, magXmax, magYmax float32
if img.wm.dbgScr.cropped || img.wm.dbgScr.crtPreview {
magXmin = float32(img.wm.dbgScr.magnifyWindow.clip.Min.X-specification.ClksHBlank) * xscaling
magYmin = float32(img.wm.dbgScr.magnifyWindow.clip.Min.Y-img.screen.crit.frameInfo.VisibleTop) * yscaling
magXmax = float32(img.wm.dbgScr.magnifyWindow.clip.Max.X-specification.ClksHBlank) * xscaling
magYmax = float32(img.wm.dbgScr.magnifyWindow.clip.Max.Y-img.screen.crit.frameInfo.VisibleTop) * yscaling
} else {
magXmin = float32(img.wm.dbgScr.magnifyWindow.clip.Min.X) * xscaling
magYmin = float32(img.wm.dbgScr.magnifyWindow.clip.Min.Y) * yscaling
magXmax = float32(img.wm.dbgScr.magnifyWindow.clip.Max.X) * xscaling
magYmax = float32(img.wm.dbgScr.magnifyWindow.clip.Max.Y) * yscaling
}
gl.Uniform1i(attr.magShow, boolToInt32(img.wm.dbgScr.magnifyWindow.open))
gl.Uniform1f(attr.magXmin, magXmin)
gl.Uniform1f(attr.magYmin, magYmin)
gl.Uniform1f(attr.magXmax, magXmax)
gl.Uniform1f(attr.magYmax, magYmax)
img.screen.crit.section.Unlock()
// end of critical section
// show cursor
switch img.dbg.State() {
case govern.Paused:
gl.Uniform1i(attr.showCursor, 1)
case govern.Running:
gl.Uniform1i(attr.showCursor, 0)
case govern.Stepping:
gl.Uniform1i(attr.showCursor, 1)
case govern.Rewinding:
gl.Uniform1i(attr.showCursor, 1)
}
}
type dbgScrShader struct {
shader
dbgScrHelper
img *SdlImgui
crt *crtSequencer
}
func newDbgScrShader(img *SdlImgui) shaderProgram {
sh := &dbgScrShader{
img: img,
}
sh.crt = newCRTSequencer(img)
sh.createProgram(string(shaders.StraightVertexShader), string(shaders.DbgScrHelpersShader), string(shaders.DbgScrShader))
sh.dbgScrHelper.get(sh.shader)
return sh
}
func (sh *dbgScrShader) destroy() {
sh.crt.destroy()
}
func (sh *dbgScrShader) setAttributes(env shaderEnvironment) {
env.width = int32(sh.img.wm.dbgScr.scaledWidth)
env.height = int32(sh.img.wm.dbgScr.scaledHeight)
ox := int32(sh.img.wm.dbgScr.screenOrigin.X)
oy := int32(sh.img.wm.dbgScr.screenOrigin.Y)
gl.Viewport(-ox, -oy, env.width+ox, env.height+oy)
gl.Scissor(-ox, -oy, env.width+ox, env.height+oy)
env.internalProj = [4][4]float32{
{2.0 / (sh.img.wm.dbgScr.scaledWidth + sh.img.wm.dbgScr.screenOrigin.X), 0.0, 0.0, 0.0},
{0.0, -2.0 / (sh.img.wm.dbgScr.scaledHeight + sh.img.wm.dbgScr.screenOrigin.Y), 0.0, 0.0},
{0.0, 0.0, -1.0, 0.0},
{-1.0, 1.0, 0.0, 1.0},
}
if sh.img.wm.dbgScr.crtPreview {
// this is a bit weird but in the case of crtPreview we need to force
// the use of the dbgscr's normalTexture. this is because for a period
// of one frame the value of crtPreview and the texture being used in
// the dbgscr's image button may not agree.
//
// consider the sequence and interaction of dbgscr with glsl:
//
// 1) crtPreview is checked to decide whether to show the normalTexture
// 2) if it is false and elements is true then the elementsTexture is
// selected
// 3) the crt checkbox is shown and clicked. the crtPreview value is
// changed on this frame
// 4) for one frame therefore, it is possible to reach this point
// (crtPreview is true) but for the elementsTexture to have
// been chosen
//
// forcing the use of the normalTexture at this point seems the least
// obtrusive solution. another solutions could be to defer otion
// changes to the following frame but that would involve a manager of
// some sort.
//
// altenatively, we could try a more structured method of attaching a
// texture to an imgui.Image and packaging texture specific options
// within that structure.
//
// both alternative solutions seem baroque for a single use case. maybe
// something for the future.
env.srcTextureID = sh.img.wm.dbgScr.displayTexture
prefs := newCrtSeqPrefs(sh.img.crtPrefs)
prefs.Enabled = true
prefs.Bevel = false
env.srcTextureID = sh.crt.process(env, true,
sh.img.wm.dbgScr.numScanlines, specification.ClksVisible,
sh.img.wm.dbgScr, prefs)
} else {
// if crtPreview is disabled we still go through the crt process. we do
// this for two reasons.
//
// 1) to scale the image to the correct size
//
// 2) the phosphor is kept up to date, which is important for the
// moment the crtPreview is enabled.
//
// note that we specify integer scaling for the non-CRT preview image,
// this is so that the overlay is aligned properly with the TV image
prefs := newCrtSeqPrefs(sh.img.crtPrefs)
prefs.Enabled = false
env.srcTextureID = sh.crt.process(env, true,
sh.img.wm.dbgScr.numScanlines, specification.ClksVisible,
sh.img.wm.dbgScr, prefs)
}
sh.shader.setAttributes(env)
sh.dbgScrHelper.set(sh.img)
}
type dbgScrOverlayShader struct {
shader
dbgScrHelper
img *SdlImgui
}
func newDbgScrOverlayShader(img *SdlImgui) shaderProgram {
sh := &dbgScrOverlayShader{
img: img,
}
sh.createProgram(string(shaders.StraightVertexShader), string(shaders.DbgScrHelpersShader), string(shaders.DbgScrOverlayShader))
sh.dbgScrHelper.get(sh.shader)
return sh
}
func (sh *dbgScrOverlayShader) setAttributes(env shaderEnvironment) {
sh.shader.setAttributes(env)
sh.dbgScrHelper.set(sh.img)
}