driver.go raw

   1  // SPDX-License-Identifier: Unlicense OR MIT
   2  
   3  package driver
   4  
   5  import (
   6  	"errors"
   7  	"image"
   8  	"time"
   9  )
  10  
  11  // Device represents the abstraction of underlying GPU
  12  // APIs such as OpenGL, Direct3D useful for rendering Gio
  13  // operations.
  14  type Device interface {
  15  	BeginFrame() Framebuffer
  16  	EndFrame()
  17  	Caps() Caps
  18  	NewTimer() Timer
  19  	// IsContinuousTime reports whether all timer measurements
  20  	// are valid at the point of call.
  21  	IsTimeContinuous() bool
  22  	NewTexture(format TextureFormat, width, height int, minFilter, magFilter TextureFilter, bindings BufferBinding) (Texture, error)
  23  	NewFramebuffer(tex Texture, depthBits int) (Framebuffer, error)
  24  	NewImmutableBuffer(typ BufferBinding, data []byte) (Buffer, error)
  25  	NewBuffer(typ BufferBinding, size int) (Buffer, error)
  26  	NewComputeProgram(shader ShaderSources) (Program, error)
  27  	NewProgram(vertexShader, fragmentShader ShaderSources) (Program, error)
  28  	NewInputLayout(vertexShader ShaderSources, layout []InputDesc) (InputLayout, error)
  29  
  30  	DepthFunc(f DepthFunc)
  31  	ClearDepth(d float32)
  32  	Clear(r, g, b, a float32)
  33  	Viewport(x, y, width, height int)
  34  	DrawArrays(mode DrawMode, off, count int)
  35  	DrawElements(mode DrawMode, off, count int)
  36  	SetBlend(enable bool)
  37  	SetDepthTest(enable bool)
  38  	DepthMask(mask bool)
  39  	BlendFunc(sfactor, dfactor BlendFactor)
  40  
  41  	BindInputLayout(i InputLayout)
  42  	BindProgram(p Program)
  43  	BindFramebuffer(f Framebuffer)
  44  	BindTexture(unit int, t Texture)
  45  	BindVertexBuffer(b Buffer, stride, offset int)
  46  	BindIndexBuffer(b Buffer)
  47  	BindImageTexture(unit int, texture Texture, access AccessBits, format TextureFormat)
  48  
  49  	MemoryBarrier()
  50  	DispatchCompute(x, y, z int)
  51  
  52  	Release()
  53  }
  54  
  55  type ShaderSources struct {
  56  	Name      string
  57  	GLSL100ES string
  58  	GLSL300ES string
  59  	GLSL310ES string
  60  	GLSL130   string
  61  	GLSL150   string
  62  	HLSL      string
  63  	Uniforms  UniformsReflection
  64  	Inputs    []InputLocation
  65  	Textures  []TextureBinding
  66  }
  67  
  68  type UniformsReflection struct {
  69  	Blocks    []UniformBlock
  70  	Locations []UniformLocation
  71  	Size      int
  72  }
  73  
  74  type TextureBinding struct {
  75  	Name    string
  76  	Binding int
  77  }
  78  
  79  type UniformBlock struct {
  80  	Name    string
  81  	Binding int
  82  }
  83  
  84  type UniformLocation struct {
  85  	Name   string
  86  	Type   DataType
  87  	Size   int
  88  	Offset int
  89  }
  90  
  91  type InputLocation struct {
  92  	// For GLSL.
  93  	Name     string
  94  	Location int
  95  	// For HLSL.
  96  	Semantic      string
  97  	SemanticIndex int
  98  
  99  	Type DataType
 100  	Size int
 101  }
 102  
 103  // InputDesc describes a vertex attribute as laid out in a Buffer.
 104  type InputDesc struct {
 105  	Type DataType
 106  	Size int
 107  
 108  	Offset int
 109  }
 110  
 111  // InputLayout is the driver specific representation of the mapping
 112  // between Buffers and shader attributes.
 113  type InputLayout interface {
 114  	Release()
 115  }
 116  
 117  type AccessBits uint8
 118  
 119  type BlendFactor uint8
 120  
 121  type DrawMode uint8
 122  
 123  type TextureFilter uint8
 124  type TextureFormat uint8
 125  
 126  type BufferBinding uint8
 127  
 128  type DataType uint8
 129  
 130  type DepthFunc uint8
 131  
 132  type Features uint
 133  
 134  type Caps struct {
 135  	// BottomLeftOrigin is true if the driver has the origin in the lower left
 136  	// corner. The OpenGL driver returns true.
 137  	BottomLeftOrigin bool
 138  	Features         Features
 139  	MaxTextureSize   int
 140  }
 141  
 142  type Program interface {
 143  	Release()
 144  	SetStorageBuffer(binding int, buf Buffer)
 145  	SetVertexUniforms(buf Buffer)
 146  	SetFragmentUniforms(buf Buffer)
 147  }
 148  
 149  type Buffer interface {
 150  	Release()
 151  	Upload(data []byte)
 152  	Download(data []byte) error
 153  }
 154  
 155  type Framebuffer interface {
 156  	Invalidate()
 157  	Release()
 158  	ReadPixels(src image.Rectangle, pixels []byte) error
 159  }
 160  
 161  type Timer interface {
 162  	Begin()
 163  	End()
 164  	Duration() (time.Duration, bool)
 165  	Release()
 166  }
 167  
 168  type Texture interface {
 169  	Upload(offset, size image.Point, pixels []byte)
 170  	Release()
 171  }
 172  
 173  const (
 174  	DepthFuncGreater DepthFunc = iota
 175  	DepthFuncGreaterEqual
 176  )
 177  
 178  const (
 179  	DataTypeFloat DataType = iota
 180  	DataTypeInt
 181  	DataTypeShort
 182  )
 183  
 184  const (
 185  	BufferBindingIndices BufferBinding = 1 << iota
 186  	BufferBindingVertices
 187  	BufferBindingUniforms
 188  	BufferBindingTexture
 189  	BufferBindingFramebuffer
 190  	BufferBindingShaderStorage
 191  )
 192  
 193  const (
 194  	TextureFormatSRGB TextureFormat = iota
 195  	TextureFormatFloat
 196  	TextureFormatRGBA8
 197  )
 198  
 199  const (
 200  	AccessRead AccessBits = 1 + iota
 201  	AccessWrite
 202  )
 203  
 204  const (
 205  	FilterNearest TextureFilter = iota
 206  	FilterLinear
 207  )
 208  
 209  const (
 210  	FeatureTimers Features = 1 << iota
 211  	FeatureFloatRenderTargets
 212  	FeatureCompute
 213  )
 214  
 215  const (
 216  	DrawModeTriangleStrip DrawMode = iota
 217  	DrawModeTriangles
 218  )
 219  
 220  const (
 221  	BlendFactorOne BlendFactor = iota
 222  	BlendFactorOneMinusSrcAlpha
 223  	BlendFactorZero
 224  	BlendFactorDstColor
 225  )
 226  
 227  var ErrContentLost = errors.New("buffer content lost")
 228  
 229  func (f Features) Has(feats Features) bool {
 230  	return f&feats == feats
 231  }
 232  
 233  func DownloadImage(d Device, f Framebuffer, r image.Rectangle) (*image.RGBA, error) {
 234  	img := image.NewRGBA(r)
 235  	if err := f.ReadPixels(r, img.Pix); err != nil {
 236  		return nil, err
 237  	}
 238  	if d.Caps().BottomLeftOrigin {
 239  		// OpenGL origin is in the lower-left corner. Flip the image to
 240  		// match.
 241  		flipImageY(r.Dx()*4, r.Dy(), img.Pix)
 242  	}
 243  	return img, nil
 244  }
 245  
 246  func flipImageY(stride, height int, pixels []byte) {
 247  	// Flip image in y-direction. OpenGL's origin is in the lower
 248  	// left corner.
 249  	row := make([]uint8, stride)
 250  	for y := 0; y < height/2; y++ {
 251  		y1 := height - y - 1
 252  		dest := y1 * stride
 253  		src := y * stride
 254  		copy(row, pixels[dest:])
 255  		copy(pixels[dest:], pixels[src:src+len(row)])
 256  		copy(pixels[src:], row)
 257  	}
 258  }
 259  
 260  func UploadImage(t Texture, offset image.Point, img *image.RGBA) {
 261  	var pixels []byte
 262  	size := img.Bounds().Size()
 263  	if img.Stride != size.X*4 {
 264  		panic("unsupported stride")
 265  	}
 266  	start := img.PixOffset(0, 0)
 267  	end := img.PixOffset(size.X, size.Y-1)
 268  	pixels = img.Pix[start:end]
 269  	t.Upload(offset, size, pixels)
 270  }
 271