Files
gio/gpu/internal/driver/driver.go
T
Elias Naur cc2edbaa51 gpu: introduce render passes
Modern GPU API such as Metal and Vulkan use explicit render passes
and command buffers for recording rendering commands. They don't have
global state; each render pass starts with a clean set of bound
textures, pipeline etc.

Change our GPU abstraction to better match newer API and modify our two
renderers to explicitly describe their render passes.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-09-20 15:13:00 +02:00

247 lines
5.2 KiB
Go

// SPDX-License-Identifier: Unlicense OR MIT
package driver
import (
"errors"
"image"
"time"
"gioui.org/internal/f32color"
"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)
Viewport(x, y, width, height int)
DrawArrays(mode DrawMode, off, count int)
DrawElements(mode DrawMode, off, count int)
BeginRenderPass(f Framebuffer, desc LoadDesc)
EndRenderPass()
BindProgram(p Program)
BindPipeline(p Pipeline)
BindTexture(unit int, t Texture)
BindVertexBuffer(b Buffer, 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)
BeginCompute()
EndCompute()
CopyTexture(dst Texture, dstOrigin image.Point, src Framebuffer, srcRect image.Rectangle)
MemoryBarrier()
DispatchCompute(x, y, z int)
Release()
}
type LoadDesc struct {
Action LoadAction
ClearColor f32color.RGBA
}
type Pipeline interface {
Release()
}
type PipelineDesc struct {
VertexShader VertexShader
FragmentShader FragmentShader
VertexLayout VertexLayout
BlendDesc BlendDesc
PixelFormat TextureFormat
}
type VertexLayout struct {
Inputs []InputDesc
Stride int
}
// InputDesc describes a vertex attribute as laid out in a Buffer.
type InputDesc struct {
Type shader.DataType
Size int
Offset int
}
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 LoadAction 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
Release()
ReadPixels(src image.Rectangle, pixels []byte, stride int) 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
BufferBindingShaderStorageRead
BufferBindingShaderStorageWrite
)
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
)
const (
LoadActionKeep LoadAction = iota
LoadActionClear
LoadActionInvalidate
)
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, img.Stride); 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)
}