mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
afaa31eca8
Modern API such as Metal and Vulkan want clients to compile expensive state changes into pipeline objects. Change our GPU driver abstraction to match, thereby paving the way for future drivers. Signed-off-by: Elias Naur <mail@eliasnaur.com>
218 lines
4.7 KiB
Go
218 lines
4.7 KiB
Go
// SPDX-License-Identifier: Unlicense OR MIT
|
|
|
|
package driver
|
|
|
|
import (
|
|
"errors"
|
|
"image"
|
|
"time"
|
|
|
|
"gioui.org/shader"
|
|
)
|
|
|
|
// Device represents the abstraction of underlying GPU
|
|
// APIs such as OpenGL, Direct3D useful for rendering Gio
|
|
// operations.
|
|
type Device interface {
|
|
BeginFrame(target RenderTarget, clear bool, viewport image.Point) Framebuffer
|
|
EndFrame()
|
|
Caps() Caps
|
|
NewTimer() Timer
|
|
// IsContinuousTime reports whether all timer measurements
|
|
// are valid at the point of call.
|
|
IsTimeContinuous() bool
|
|
NewTexture(format TextureFormat, width, height int, minFilter, magFilter TextureFilter, bindings BufferBinding) (Texture, error)
|
|
NewFramebuffer(tex Texture) (Framebuffer, error)
|
|
NewImmutableBuffer(typ BufferBinding, data []byte) (Buffer, error)
|
|
NewBuffer(typ BufferBinding, size int) (Buffer, error)
|
|
NewComputeProgram(shader shader.Sources) (Program, error)
|
|
NewVertexShader(src shader.Sources) (VertexShader, error)
|
|
NewFragmentShader(src shader.Sources) (FragmentShader, error)
|
|
NewPipeline(desc PipelineDesc) (Pipeline, error)
|
|
|
|
Clear(r, g, b, a float32)
|
|
Viewport(x, y, width, height int)
|
|
DrawArrays(mode DrawMode, off, count int)
|
|
DrawElements(mode DrawMode, off, count int)
|
|
|
|
BindProgram(p Program)
|
|
BindPipeline(p Pipeline)
|
|
BindFramebuffer(f Framebuffer)
|
|
BindTexture(unit int, t Texture)
|
|
BindVertexBuffer(b Buffer, stride, offset int)
|
|
BindIndexBuffer(b Buffer)
|
|
BindImageTexture(unit int, texture Texture, access AccessBits, format TextureFormat)
|
|
BindVertexUniforms(buf Buffer)
|
|
BindFragmentUniforms(buf Buffer)
|
|
BindStorageBuffer(binding int, buf Buffer)
|
|
|
|
BlitFramebuffer(dst, src Framebuffer, srect, drect image.Rectangle)
|
|
MemoryBarrier()
|
|
DispatchCompute(x, y, z int)
|
|
|
|
Release()
|
|
}
|
|
|
|
type Pipeline interface {
|
|
Release()
|
|
}
|
|
|
|
type PipelineDesc struct {
|
|
VertexShader VertexShader
|
|
FragmentShader FragmentShader
|
|
VertexLayout []shader.InputDesc
|
|
BlendDesc BlendDesc
|
|
PixelFormat TextureFormat
|
|
}
|
|
|
|
type BlendDesc struct {
|
|
Enable bool
|
|
SrcFactor, DstFactor BlendFactor
|
|
}
|
|
|
|
type AccessBits uint8
|
|
|
|
type BlendFactor uint8
|
|
|
|
type DrawMode uint8
|
|
|
|
type TextureFilter uint8
|
|
type TextureFormat uint8
|
|
|
|
type BufferBinding uint8
|
|
|
|
type Features uint
|
|
|
|
type Caps struct {
|
|
// BottomLeftOrigin is true if the driver has the origin in the lower left
|
|
// corner. The OpenGL driver returns true.
|
|
BottomLeftOrigin bool
|
|
Features Features
|
|
MaxTextureSize int
|
|
}
|
|
|
|
type VertexShader interface {
|
|
Release()
|
|
}
|
|
|
|
type FragmentShader interface {
|
|
Release()
|
|
}
|
|
|
|
type Program interface {
|
|
Release()
|
|
}
|
|
|
|
type Buffer interface {
|
|
Release()
|
|
Upload(data []byte)
|
|
Download(data []byte) error
|
|
}
|
|
|
|
type Framebuffer interface {
|
|
RenderTarget
|
|
Invalidate()
|
|
Release()
|
|
ReadPixels(src image.Rectangle, pixels []byte) error
|
|
}
|
|
|
|
type Timer interface {
|
|
Begin()
|
|
End()
|
|
Duration() (time.Duration, bool)
|
|
Release()
|
|
}
|
|
|
|
type Texture interface {
|
|
Upload(offset, size image.Point, pixels []byte, stride int)
|
|
Release()
|
|
}
|
|
|
|
const (
|
|
BufferBindingIndices BufferBinding = 1 << iota
|
|
BufferBindingVertices
|
|
BufferBindingUniforms
|
|
BufferBindingTexture
|
|
BufferBindingFramebuffer
|
|
BufferBindingShaderStorage
|
|
)
|
|
|
|
const (
|
|
TextureFormatSRGBA TextureFormat = iota
|
|
TextureFormatFloat
|
|
TextureFormatRGBA8
|
|
// TextureFormatOutput denotes the format used by the output framebuffer.
|
|
TextureFormatOutput
|
|
)
|
|
|
|
const (
|
|
AccessRead AccessBits = 1 + iota
|
|
AccessWrite
|
|
)
|
|
|
|
const (
|
|
FilterNearest TextureFilter = iota
|
|
FilterLinear
|
|
)
|
|
|
|
const (
|
|
FeatureTimers Features = 1 << iota
|
|
FeatureFloatRenderTargets
|
|
FeatureCompute
|
|
FeatureSRGB
|
|
)
|
|
|
|
const (
|
|
DrawModeTriangleStrip DrawMode = iota
|
|
DrawModeTriangles
|
|
)
|
|
|
|
const (
|
|
BlendFactorOne BlendFactor = iota
|
|
BlendFactorOneMinusSrcAlpha
|
|
BlendFactorZero
|
|
BlendFactorDstColor
|
|
)
|
|
|
|
var ErrContentLost = errors.New("buffer content lost")
|
|
|
|
func (f Features) Has(feats Features) bool {
|
|
return f&feats == feats
|
|
}
|
|
|
|
func DownloadImage(d Device, f Framebuffer, r image.Rectangle) (*image.RGBA, error) {
|
|
img := image.NewRGBA(r)
|
|
if err := f.ReadPixels(r, img.Pix); err != nil {
|
|
return nil, err
|
|
}
|
|
if d.Caps().BottomLeftOrigin {
|
|
// OpenGL origin is in the lower-left corner. Flip the image to
|
|
// match.
|
|
flipImageY(r.Dx()*4, r.Dy(), img.Pix)
|
|
}
|
|
return img, nil
|
|
}
|
|
|
|
func flipImageY(stride, height int, pixels []byte) {
|
|
// Flip image in y-direction. OpenGL's origin is in the lower
|
|
// left corner.
|
|
row := make([]uint8, stride)
|
|
for y := 0; y < height/2; y++ {
|
|
y1 := height - y - 1
|
|
dest := y1 * stride
|
|
src := y * stride
|
|
copy(row, pixels[dest:])
|
|
copy(pixels[dest:], pixels[src:src+len(row)])
|
|
copy(pixels[src:], row)
|
|
}
|
|
}
|
|
|
|
func UploadImage(t Texture, offset image.Point, img *image.RGBA) {
|
|
var pixels []byte
|
|
size := img.Bounds().Size()
|
|
start := img.PixOffset(0, 0)
|
|
end := img.PixOffset(size.X, size.Y-1)
|
|
pixels = img.Pix[start:end]
|
|
t.Upload(offset, size, pixels, img.Stride)
|
|
}
|