driver.mx raw
1 // SPDX-License-Identifier: Unlicense OR MIT
2
3 // Device interface and types. OpenGL only - no D3D11/Metal/Vulkan.
4
5 package gio
6
7 import (
8 "fmt"
9 "image"
10 )
11
12 // API is the GPU API discriminator.
13 type API interface {
14 implementsAPI()
15 }
16
17 // RenderTarget is implemented by framebuffer targets.
18 type RenderTarget interface {
19 ImplementsRenderTarget()
20 }
21
22 // OpenGLRenderTarget wraps a Framebuffer as a render target.
23 type OpenGLRenderTarget Framebuffer
24
25 func (OpenGLRenderTarget) ImplementsRenderTarget() {}
26
27 // OpenGL holds the parameters to create an OpenGL device.
28 type OpenGL struct {
29 // Context is the WebGL context handle for WASM platforms.
30 Context GLContext
31 }
32
33 func (OpenGL) implementsAPI() {}
34
35 // NewDevice creates a Device for the given API.
36 func NewDevice(api API) (Device, error) {
37 switch a := api.(type) {
38 case OpenGL:
39 return newOpenGLDevice(a)
40 }
41 return nil, fmt.Errorf("gio: no driver available for the API %T", api)
42 }
43
44 // Device abstracts GPU operations.
45 type Device interface {
46 BeginFrame(target RenderTarget, clear bool, viewport image.Point) Texture
47 EndFrame()
48 Caps() Caps
49 NewTimer() Timer
50 IsTimeContinuous() bool
51 NewTexture(format TextureFormat, width, height int, minFilter, magFilter TextureFilter, bindings BufferBinding) (Texture, error)
52 NewImmutableBuffer(typ BufferBinding, data []byte) (Buffer, error)
53 NewBuffer(typ BufferBinding, size int) (Buffer, error)
54 NewComputeProgram(shader ShaderSources) (ShaderProgram, error)
55 NewVertexShader(src ShaderSources) (VertexShader, error)
56 NewFragmentShader(src ShaderSources) (FragmentShader, error)
57 NewPipeline(desc PipelineDesc) (Pipeline, error)
58
59 Viewport(x, y, width, height int)
60 DrawArrays(off, count int)
61 DrawElements(off, count int)
62
63 BeginRenderPass(t Texture, desc LoadDesc)
64 EndRenderPass()
65 PrepareTexture(t Texture)
66 BindProgram(p ShaderProgram)
67 BindPipeline(p Pipeline)
68 BindTexture(unit int, t Texture)
69 BindVertexBuffer(b Buffer, offset int)
70 BindIndexBuffer(b Buffer)
71 BindImageTexture(unit int, texture Texture)
72 BindUniforms(buf Buffer)
73 BindStorageBuffer(binding int, buf Buffer)
74
75 BeginCompute()
76 EndCompute()
77 CopyTexture(dst Texture, dstOrigin image.Point, src Texture, srcRect image.Rectangle)
78 DispatchCompute(x, y, z int)
79
80 Release()
81 }
82
83 type errorString string
84
85 func (e errorString) Error() string { return string(e) }
86
87 const ErrDeviceLost = errorString("GPU device lost")
88 const ErrContentLost = errorString("buffer content lost")
89
90 type LoadDesc struct {
91 Action LoadAction
92 ClearColor RGBA
93 }
94
95 type Pipeline interface {
96 Release()
97 }
98
99 type PipelineDesc struct {
100 VertexShader VertexShader
101 FragmentShader FragmentShader
102 VertexLayout VertexLayout
103 BlendDesc BlendDesc
104 PixelFormat TextureFormat
105 Topology Topology
106 }
107
108 type VertexLayout struct {
109 Inputs []InputDesc
110 Stride int
111 }
112
113 type InputDesc struct {
114 Type ShaderDataType
115 Size int
116 Offset int
117 }
118
119 type BlendDesc struct {
120 Enable bool
121 SrcFactor, DstFactor BlendFactor
122 }
123
124 type BlendFactor uint8
125
126 type Topology uint8
127
128 type (
129 TextureFilter uint8
130 TextureFormat uint8
131 )
132
133 type BufferBinding uint8
134
135 type LoadAction uint8
136
137 type Features uint32
138
139 type Caps struct {
140 BottomLeftOrigin bool
141 Features Features
142 MaxTextureSize int
143 }
144
145 type VertexShader interface {
146 Release()
147 }
148
149 type FragmentShader interface {
150 Release()
151 }
152
153 type ShaderProgram interface {
154 Release()
155 }
156
157 type Buffer interface {
158 Release()
159 Upload(data []byte)
160 Download(data []byte) error
161 }
162
163 type Timer interface {
164 Begin()
165 End()
166 Release()
167 }
168
169 type Texture interface {
170 RenderTarget
171 Upload(offset, size image.Point, pixels []byte, stride int)
172 ReadPixels(src image.Rectangle, pixels []byte, stride int) error
173 Release()
174 }
175
176 const (
177 BufferBindingIndices BufferBinding = 1 << iota
178 BufferBindingVertices
179 BufferBindingUniforms
180 BufferBindingTexture
181 BufferBindingFramebuffer
182 BufferBindingShaderStorageRead
183 BufferBindingShaderStorageWrite
184 )
185
186 const (
187 TextureFormatSRGBA TextureFormat = iota
188 TextureFormatFloat
189 TextureFormatRGBA8
190 TextureFormatOutput
191 )
192
193 const (
194 FilterNearest TextureFilter = iota
195 FilterLinear
196 FilterLinearMipmapLinear
197 )
198
199 const (
200 FeatureTimers Features = 1 << iota
201 FeatureFloatRenderTargets
202 FeatureCompute
203 FeatureSRGB
204 )
205
206 const (
207 TopologyTriangleStrip Topology = iota
208 TopologyTriangles
209 )
210
211 const (
212 BlendFactorOne BlendFactor = iota
213 BlendFactorOneMinusSrcAlpha
214 BlendFactorZero
215 BlendFactorDstColor
216 )
217
218 const (
219 LoadActionKeep LoadAction = iota
220 LoadActionClear
221 LoadActionInvalidate
222 )
223
224 func (f Features) Has(feats Features) bool {
225 return f&feats == feats
226 }
227
228 func DownloadImage(d Device, t Texture, img *image.RGBA) error {
229 r := img.Bounds()
230 if err := t.ReadPixels(r, img.Pix, img.Stride); err != nil {
231 return err
232 }
233 if d.Caps().BottomLeftOrigin {
234 flipImageY(r.Dx()*4, r.Dy(), img.Pix)
235 }
236 return nil
237 }
238
239 func flipImageY(stride, height int, pixels []byte) {
240 row := []byte{:stride}
241 for y := 0; y < height/2; y++ {
242 y1 := height - y - 1
243 dest := y1 * stride
244 src := y * stride
245 copy(row, pixels[dest:])
246 copy(pixels[dest:], pixels[src:src+len(row)])
247 copy(pixels[src:], row)
248 }
249 }
250
251 func UploadImage(t Texture, offset image.Point, img *image.RGBA) {
252 size := img.Bounds().Size()
253 min := img.Rect.Min
254 start := img.PixOffset(min.X, min.Y)
255 end := img.PixOffset(min.X+size.X, min.Y+size.Y-1)
256 t.Upload(offset, size, img.Pix[start:end], img.Stride)
257 }
258