mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
7f6e376424
It saves a roundtrip to scratch memory when the CPU fallback renderer downloads rendered materials. Signed-off-by: Elias Naur <mail@eliasnaur.com>
248 lines
5.2 KiB
Go
248 lines
5.2 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)
|
|
|
|
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, a LoadDesc)
|
|
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)
|
|
|
|
CopyTexture(dst Texture, dstOrigin image.Point, src Framebuffer, srcRect image.Rectangle)
|
|
MemoryBarrier()
|
|
DispatchCompute(x, y, z int)
|
|
|
|
Release()
|
|
}
|
|
|
|
type LoadDesc struct {
|
|
Action LoadAction
|
|
ClearColor struct {
|
|
R float32
|
|
G float32
|
|
B float32
|
|
A float32
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|