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