mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-08 02:45:38 +00:00
gpu,gpu/headless,app/internal/wm: add explicit RenderTarget API
Both the OpenGL and the Direct3D API are stateful and gpu.GPU renders to the render target current when Frame is called. Modern GPU API such as Metal don't have a concept of a current render target, and the target even changes each frame. Add RenderTarget and add an explicit target argument to GPU.Frame as well as the underlying driver.Device.BeginFrame. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -54,6 +54,13 @@ func (c *d3d11Context) API() gpu.API {
|
|||||||
return gpu.Direct3D11{Device: unsafe.Pointer(c.dev)}
|
return gpu.Direct3D11{Device: unsafe.Pointer(c.dev)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *d3d11Context) RenderTarget() gpu.RenderTarget {
|
||||||
|
return gpu.Direct3D11RenderTarget{
|
||||||
|
RenderTarget: unsafe.Pointer(c.renderTarget),
|
||||||
|
DepthStencilView: unsafe.Pointer(c.depthView),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *d3d11Context) Present() error {
|
func (c *d3d11Context) Present() error {
|
||||||
err := c.swchain.Present(1, 0)
|
err := c.swchain.Present(1, 0)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
@@ -65,6 +65,10 @@ func contextAPI() gpu.OpenGL {
|
|||||||
return gpu.OpenGL{}
|
return gpu.OpenGL{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *context) RenderTarget() gpu.RenderTarget {
|
||||||
|
return gpu.OpenGLRenderTarget(c.frameBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *context) API() gpu.API {
|
func (c *context) API() gpu.API {
|
||||||
return contextAPI()
|
return contextAPI()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ func newContext(w *window) (*context, error) {
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *context) RenderTarget() gpu.RenderTarget {
|
||||||
|
return gpu.OpenGLRenderTarget{}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *context) API() gpu.API {
|
func (c *context) API() gpu.API {
|
||||||
return gpu.OpenGL{Context: gl.Context(c.ctx)}
|
return gpu.OpenGL{Context: gl.Context(c.ctx)}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ func newContext(w *window) (*context, error) {
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *context) RenderTarget() gpu.RenderTarget {
|
||||||
|
return gpu.OpenGLRenderTarget{}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *context) API() gpu.API {
|
func (c *context) API() gpu.API {
|
||||||
return gpu.OpenGL{}
|
return gpu.OpenGL{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ type Callbacks interface {
|
|||||||
|
|
||||||
type Context interface {
|
type Context interface {
|
||||||
API() gpu.API
|
API() gpu.API
|
||||||
|
RenderTarget() gpu.RenderTarget
|
||||||
Present() error
|
Present() error
|
||||||
Refresh() error
|
Refresh() error
|
||||||
Release()
|
Release()
|
||||||
|
|||||||
+1
-1
@@ -100,7 +100,7 @@ func (l *renderLoop) renderLoop(ctx wm.Context) error {
|
|||||||
g.Collect(frame.viewport, frame.ops)
|
g.Collect(frame.viewport, frame.ops)
|
||||||
// Signal that we're done with the frame ops.
|
// Signal that we're done with the frame ops.
|
||||||
l.ack <- struct{}{}
|
l.ack <- struct{}{}
|
||||||
res.err = g.Frame()
|
res.err = g.Frame(ctx.RenderTarget())
|
||||||
if res.err == nil {
|
if res.err == nil {
|
||||||
res.err = ctx.Present()
|
res.err = ctx.Present()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,15 @@ import "gioui.org/gpu/internal/driver"
|
|||||||
// There is an API type for each supported GPU API such as OpenGL and Direct3D.
|
// There is an API type for each supported GPU API such as OpenGL and Direct3D.
|
||||||
type API = driver.API
|
type API = driver.API
|
||||||
|
|
||||||
|
// A RenderTarget denotest the destination framebuffer for a frame.
|
||||||
|
type RenderTarget = driver.RenderTarget
|
||||||
|
|
||||||
|
// OpenGLRenderTarget is a render target suitable for the OpenGL backend.
|
||||||
|
type OpenGLRenderTarget = driver.OpenGLRenderTarget
|
||||||
|
|
||||||
|
// Direct3D11RenderTarget is a render target suitable for the Direct3D 11 backend.
|
||||||
|
type Direct3D11RenderTarget = driver.Direct3D11RenderTarget
|
||||||
|
|
||||||
// OpenGL denotes the OpenGL or OpenGL ES API.
|
// OpenGL denotes the OpenGL or OpenGL ES API.
|
||||||
type OpenGL = driver.OpenGL
|
type OpenGL = driver.OpenGL
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -551,9 +551,9 @@ func (g *compute) Clear(col color.NRGBA) {
|
|||||||
g.collector.clearColor = f32color.LinearFromSRGB(col)
|
g.collector.clearColor = f32color.LinearFromSRGB(col)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *compute) Frame() error {
|
func (g *compute) Frame(target RenderTarget) error {
|
||||||
viewport := g.viewport
|
viewport := g.viewport
|
||||||
defFBO := g.ctx.BeginFrame(g.collector.clear, viewport)
|
defFBO := g.ctx.BeginFrame(target, g.collector.clear, viewport)
|
||||||
defer g.ctx.EndFrame()
|
defer g.ctx.EndFrame()
|
||||||
|
|
||||||
t := &g.timers
|
t := &g.timers
|
||||||
|
|||||||
+5
-5
@@ -42,8 +42,8 @@ type GPU interface {
|
|||||||
Clear(color color.NRGBA)
|
Clear(color color.NRGBA)
|
||||||
// Collect the graphics operations from frame, given the viewport.
|
// Collect the graphics operations from frame, given the viewport.
|
||||||
Collect(viewport image.Point, frame *op.Ops)
|
Collect(viewport image.Point, frame *op.Ops)
|
||||||
// Frame clears the color buffer and draws the collected operations.
|
// Frame draws the collected operations to target.
|
||||||
Frame() error
|
Frame(target RenderTarget) error
|
||||||
// Profile returns the last available profiling information. Profiling
|
// Profile returns the last available profiling information. Profiling
|
||||||
// information is requested when Collect sees a ProfileOp, and the result
|
// information is requested when Collect sees a ProfileOp, and the result
|
||||||
// is available through Profile at some later time.
|
// is available through Profile at some later time.
|
||||||
@@ -356,7 +356,7 @@ func New(api API) (GPU, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
d.BeginFrame(false, image.Point{})
|
d.BeginFrame(nil, false, image.Point{})
|
||||||
defer d.EndFrame()
|
defer d.EndFrame()
|
||||||
forceCompute := os.Getenv("GIORENDERER") == "forcecompute"
|
forceCompute := os.Getenv("GIORENDERER") == "forcecompute"
|
||||||
feats := d.Caps().Features
|
feats := d.Caps().Features
|
||||||
@@ -414,9 +414,9 @@ func (g *gpu) Collect(viewport image.Point, frameOps *op.Ops) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *gpu) Frame() error {
|
func (g *gpu) Frame(target RenderTarget) error {
|
||||||
viewport := g.renderer.blitter.viewport
|
viewport := g.renderer.blitter.viewport
|
||||||
defFBO := g.ctx.BeginFrame(g.drawOps.clear, viewport)
|
defFBO := g.ctx.BeginFrame(target, g.drawOps.clear, viewport)
|
||||||
defer g.ctx.EndFrame()
|
defer g.ctx.EndFrame()
|
||||||
for _, img := range g.drawOps.imageOps {
|
for _, img := range g.drawOps.imageOps {
|
||||||
expandPathOp(img.path, img.clip)
|
expandPathOp(img.path, img.clip)
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ func newDriver(t *testing.T) driver.Device {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
b.BeginFrame(true, image.Pt(1, 1))
|
b.BeginFrame(nil, true, image.Pt(1, 1))
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
b.EndFrame()
|
b.EndFrame()
|
||||||
ctx.ReleaseCurrent()
|
ctx.ReleaseCurrent()
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ func (w *Window) Frame(frame *op.Ops) error {
|
|||||||
w.dev.BindFramebuffer(w.fbo)
|
w.dev.BindFramebuffer(w.fbo)
|
||||||
w.gpu.Clear(color.NRGBA{})
|
w.gpu.Clear(color.NRGBA{})
|
||||||
w.gpu.Collect(w.size, frame)
|
w.gpu.Collect(w.size, frame)
|
||||||
return w.gpu.Frame()
|
return w.gpu.Frame(driver.RenderTarget(w.fbo))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -165,15 +165,23 @@ func newDirect3D11Device(api driver.Direct3D11) (driver.Device, error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) BeginFrame(clear bool, viewport image.Point) driver.Framebuffer {
|
func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport image.Point) driver.Framebuffer {
|
||||||
renderTarget, depthView := b.ctx.OMGetRenderTargets()
|
var (
|
||||||
// Assume someone else is holding on to the render targets.
|
renderTarget *d3d11.RenderTargetView
|
||||||
if renderTarget != nil {
|
depthView *d3d11.DepthStencilView
|
||||||
d3d11.IUnknownRelease(unsafe.Pointer(renderTarget), renderTarget.Vtbl.Release)
|
)
|
||||||
|
if target != nil {
|
||||||
|
switch t := target.(type) {
|
||||||
|
case driver.Direct3D11RenderTarget:
|
||||||
|
renderTarget = (*d3d11.RenderTargetView)(t.RenderTarget)
|
||||||
|
depthView = (*d3d11.DepthStencilView)(t.DepthStencilView)
|
||||||
|
case *Framebuffer:
|
||||||
|
renderTarget, depthView = t.renderTarget, t.depthView
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("opengl: invalid render target type: %T", target))
|
||||||
}
|
}
|
||||||
if depthView != nil {
|
|
||||||
d3d11.IUnknownRelease(unsafe.Pointer(depthView), depthView.Vtbl.Release)
|
|
||||||
}
|
}
|
||||||
|
b.ctx.OMSetRenderTargets(renderTarget, depthView)
|
||||||
return &Framebuffer{ctx: b.ctx, dev: b.dev, renderTarget: renderTarget, depthView: depthView, foreign: true}
|
return &Framebuffer{ctx: b.ctx, dev: b.dev, renderTarget: renderTarget, depthView: depthView, foreign: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -713,6 +721,8 @@ func (f *Framebuffer) Release() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Framebuffer) ImplementsRenderTarget() {}
|
||||||
|
|
||||||
func (b *Backend) BindInputLayout(layout driver.InputLayout) {
|
func (b *Backend) BindInputLayout(layout driver.InputLayout) {
|
||||||
b.ctx.IASetInputLayout(layout.(*InputLayout).layout)
|
b.ctx.IASetInputLayout(layout.(*InputLayout).layout)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,19 @@ type API interface {
|
|||||||
implementsAPI()
|
implementsAPI()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RenderTarget interface {
|
||||||
|
ImplementsRenderTarget()
|
||||||
|
}
|
||||||
|
|
||||||
|
type OpenGLRenderTarget gl.Framebuffer
|
||||||
|
|
||||||
|
type Direct3D11RenderTarget struct {
|
||||||
|
// RenderTarget is a *ID3D11RenderTargetView.
|
||||||
|
RenderTarget unsafe.Pointer
|
||||||
|
// DepthStencilView is a *ID3D11DepthStencilView.
|
||||||
|
DepthStencilView unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
type OpenGL struct {
|
type OpenGL struct {
|
||||||
// ES forces the use of ANGLE OpenGL ES libraries on macOS. It is
|
// ES forces the use of ANGLE OpenGL ES libraries on macOS. It is
|
||||||
// ignored on all other platforms.
|
// ignored on all other platforms.
|
||||||
@@ -57,3 +70,5 @@ func NewDevice(api API) (Device, error) {
|
|||||||
|
|
||||||
func (OpenGL) implementsAPI() {}
|
func (OpenGL) implementsAPI() {}
|
||||||
func (Direct3D11) implementsAPI() {}
|
func (Direct3D11) implementsAPI() {}
|
||||||
|
func (OpenGLRenderTarget) ImplementsRenderTarget() {}
|
||||||
|
func (Direct3D11RenderTarget) ImplementsRenderTarget() {}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
// APIs such as OpenGL, Direct3D useful for rendering Gio
|
// APIs such as OpenGL, Direct3D useful for rendering Gio
|
||||||
// operations.
|
// operations.
|
||||||
type Device interface {
|
type Device interface {
|
||||||
BeginFrame(clear bool, viewport image.Point) Framebuffer
|
BeginFrame(target RenderTarget, clear bool, viewport image.Point) Framebuffer
|
||||||
EndFrame()
|
EndFrame()
|
||||||
Caps() Caps
|
Caps() Caps
|
||||||
NewTimer() Timer
|
NewTimer() Timer
|
||||||
@@ -155,6 +155,7 @@ type Buffer interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Framebuffer interface {
|
type Framebuffer interface {
|
||||||
|
RenderTarget
|
||||||
Invalidate()
|
Invalidate()
|
||||||
Release()
|
Release()
|
||||||
ReadPixels(src image.Rectangle, pixels []byte) error
|
ReadPixels(src image.Rectangle, pixels []byte) error
|
||||||
|
|||||||
@@ -212,12 +212,23 @@ func newOpenGLDevice(api driver.OpenGL) (driver.Device, error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) BeginFrame(clear bool, viewport image.Point) driver.Framebuffer {
|
func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport image.Point) driver.Framebuffer {
|
||||||
b.clear = clear
|
b.clear = clear
|
||||||
b.glstate = b.queryState()
|
b.glstate = b.queryState()
|
||||||
b.savedState = b.glstate
|
b.savedState = b.glstate
|
||||||
b.state = state{}
|
b.state = state{}
|
||||||
renderFBO := b.glstate.drawFBO
|
var renderFBO gl.Framebuffer
|
||||||
|
if target != nil {
|
||||||
|
switch t := target.(type) {
|
||||||
|
case driver.OpenGLRenderTarget:
|
||||||
|
renderFBO = gl.Framebuffer(t)
|
||||||
|
case *gpuFramebuffer:
|
||||||
|
renderFBO = t.obj
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("opengl: invalid render target type: %T", target))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.glstate.bindFramebuffer(b.funcs, gl.FRAMEBUFFER, renderFBO)
|
||||||
if b.gles {
|
if b.gles {
|
||||||
// If the output framebuffer is not in the sRGB colorspace already, emulate it.
|
// If the output framebuffer is not in the sRGB colorspace already, emulate it.
|
||||||
var fbEncoding int
|
var fbEncoding int
|
||||||
@@ -1244,6 +1255,8 @@ func (f *gpuFramebuffer) Release() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *gpuFramebuffer) ImplementsRenderTarget() {}
|
||||||
|
|
||||||
func toTexFilter(f driver.TextureFilter) int {
|
func toTexFilter(f driver.TextureFilter) int {
|
||||||
switch f {
|
switch f {
|
||||||
case driver.FilterNearest:
|
case driver.FilterNearest:
|
||||||
|
|||||||
@@ -98,6 +98,10 @@ func NewContext(disp NativeDisplayType) (*Context, error) {
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Context) RenderTarget() gpu.RenderTarget {
|
||||||
|
return gpu.OpenGLRenderTarget{}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Context) API() gpu.API {
|
func (c *Context) API() gpu.API {
|
||||||
return gpu.OpenGL{}
|
return gpu.OpenGL{}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user