diff --git a/app/internal/d3d11/backend_windows.go b/app/internal/d3d11/backend_windows.go index 66e32989..4a13ba8d 100644 --- a/app/internal/d3d11/backend_windows.go +++ b/app/internal/d3d11/backend_windows.go @@ -274,7 +274,8 @@ func NewBackend(d *Device) (*Backend, error) { return b, nil } -func (b *Backend) BeginFrame() { +func (b *Backend) BeginFrame() backend.Framebuffer { + return b.currentFramebuffer() } func (b *Backend) EndFrame() { @@ -368,13 +369,13 @@ func (b *Backend) NewTexture(format backend.TextureFormat, width, height int, mi return &Texture{backend: b, format: d3dfmt, tex: tex, sampler: sampler, resView: resView, bindings: bindings, width: width, height: height}, nil } -func (b *Backend) CurrentFramebuffer() backend.Framebuffer { +func (b *Backend) currentFramebuffer() backend.Framebuffer { renderTarget := b.dev.ctx.OMGetRenderTargets() if renderTarget != nil { // Assume someone else is holding on to it. _IUnknownRelease(unsafe.Pointer(renderTarget), renderTarget.vtbl.Release) } - if renderTarget == b.fbo.renderTarget { + if b.fbo != nil && renderTarget == b.fbo.renderTarget { return b.fbo } return &Framebuffer{dev: b.dev, renderTarget: renderTarget, foreign: true} @@ -823,7 +824,7 @@ func (f *Framebuffer) Invalidate() { func (f *Framebuffer) Release() { if f.foreign { - panic("cannot release Framebuffer from CurrentFramebuffer") + panic("framebuffer not created by NewBuffer") } if f.renderTarget != nil { _IUnknownRelease(unsafe.Pointer(f.renderTarget), f.renderTarget.vtbl.Release) diff --git a/gpu/backend/backend.go b/gpu/backend/backend.go index e983b8e5..34fc3b4b 100644 --- a/gpu/backend/backend.go +++ b/gpu/backend/backend.go @@ -12,7 +12,7 @@ import ( // APIs such as OpenGL, Direct3D useful for rendering Gio // operations. type Device interface { - BeginFrame() + BeginFrame() Framebuffer EndFrame() Caps() Caps NewTimer() Timer @@ -20,7 +20,6 @@ type Device interface { // are valid at the point of call. IsTimeContinuous() bool NewTexture(format TextureFormat, width, height int, minFilter, magFilter TextureFilter, bindings BufferBinding) (Texture, error) - CurrentFramebuffer() Framebuffer NewFramebuffer(tex Texture, depthBits int) (Framebuffer, error) NewImmutableBuffer(typ BufferBinding, data []byte) (Buffer, error) NewBuffer(typ BufferBinding, size int) (Buffer, error) diff --git a/gpu/compute.go b/gpu/compute.go index a4f880c9..a41c6dbb 100644 --- a/gpu/compute.go +++ b/gpu/compute.go @@ -29,7 +29,6 @@ type compute struct { cache *resourceCache maxTextureDim int - defFBO backend.Framebuffer programs struct { elements backend.Program tileAlloc backend.Program @@ -197,7 +196,6 @@ func newCompute(ctx backend.Device) (*compute, error) { } g := &compute{ ctx: ctx, - defFBO: ctx.CurrentFramebuffer(), cache: newResourceCache(), maxTextureDim: maxDim, conf: new(config), @@ -290,7 +288,7 @@ func (g *compute) Frame() error { Y: (viewport.Y + tileHeightPx - 1) / tileHeightPx, } - g.ctx.BeginFrame() + defFBO := g.ctx.BeginFrame() defer g.ctx.EndFrame() if err := g.uploadImages(g.drawOps.allImageOps); err != nil { @@ -305,6 +303,7 @@ func (g *compute) Frame() error { if err := g.render(tileDims); err != nil { return err } + g.ctx.BindFramebuffer(defFBO) g.blitOutput(viewport) g.cache.frame() g.drawOps.pathCache.frame() @@ -331,7 +330,6 @@ func (g *compute) Profile() string { // shader can only write to RGBA textures, but since we actually render in sRGB // format we can't use glBlitFramebuffer, because it does sRGB conversion. func (g *compute) blitOutput(viewport image.Point) { - g.ctx.BindFramebuffer(g.defFBO) g.ctx.Viewport(0, 0, viewport.X, viewport.Y) g.ctx.BindTexture(0, g.output.image) g.ctx.BindProgram(g.output.blitProg) diff --git a/gpu/gl/backend.go b/gpu/gl/backend.go index 99aa2296..83d72239 100644 --- a/gpu/gl/backend.go +++ b/gpu/gl/backend.go @@ -167,9 +167,10 @@ func NewBackend(ctx Context) (*Backend, error) { return b, nil } -func (b *Backend) BeginFrame() { +func (b *Backend) BeginFrame() backend.Framebuffer { // Assume GL state is reset between frames. b.state = glstate{} + return b.currentFramebuffer() } func (b *Backend) EndFrame() { @@ -228,7 +229,7 @@ func (b *Backend) NewFramebuffer(tex backend.Texture, depthBits int) (backend.Fr return fbo, nil } -func (b *Backend) CurrentFramebuffer() backend.Framebuffer { +func (b *Backend) currentFramebuffer() backend.Framebuffer { fboID := glimpl.Framebuffer(b.funcs.GetBinding(glimpl.FRAMEBUFFER_BINDING)) return &gpuFramebuffer{backend: b, obj: fboID, foreign: true} } @@ -802,7 +803,7 @@ func (f *gpuFramebuffer) Invalidate() { func (f *gpuFramebuffer) Release() { if f.foreign { - panic("cannot release framebuffer created by CurrentFramebuffer") + panic("framebuffer not created by NewBuffer") } f.backend.funcs.DeleteFramebuffer(f.obj) if f.hasDepth { diff --git a/gpu/gpu.go b/gpu/gpu.go index f48ebbab..0c621de6 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -48,7 +48,6 @@ type GPU interface { type gpu struct { cache *resourceCache - defFBO backend.Framebuffer profile string timers *timers frameStart time.Time @@ -395,10 +394,8 @@ func New(ctx backend.Device) (GPU, error) { } func newGPU(ctx backend.Device) (*gpu, error) { - defFBO := ctx.CurrentFramebuffer() g := &gpu{ - defFBO: defFBO, - cache: newResourceCache(), + cache: newResourceCache(), } g.drawOps.pathCache = newOpCache() if err := g.init(ctx); err != nil { @@ -443,7 +440,7 @@ func (g *gpu) Collect(viewport image.Point, frameOps *op.Ops) { } func (g *gpu) Frame() error { - g.ctx.BeginFrame() + defFBO := g.ctx.BeginFrame() defer g.ctx.EndFrame() viewport := g.renderer.blitter.viewport for _, img := range g.drawOps.imageOps { @@ -452,7 +449,7 @@ func (g *gpu) Frame() error { if g.drawOps.profile { g.zopsTimer.begin() } - g.ctx.BindFramebuffer(g.defFBO) + g.ctx.BindFramebuffer(defFBO) g.ctx.DepthFunc(backend.DepthFuncGreater) // Note that Clear must be before ClearDepth if nothing else is rendered // (len(zimageOps) == 0). If not, the Fairphone 2 will corrupt the depth buffer. @@ -472,13 +469,13 @@ func (g *gpu) Frame() error { g.renderer.intersect(g.drawOps.imageOps) g.stencilTimer.end() g.coverTimer.begin() - g.ctx.BindFramebuffer(g.defFBO) + g.ctx.BindFramebuffer(defFBO) g.ctx.Viewport(0, 0, viewport.X, viewport.Y) g.renderer.drawOps(g.cache, g.drawOps.imageOps) g.ctx.SetBlend(false) g.renderer.pather.stenciler.invalidateFBO() g.coverTimer.end() - g.ctx.BindFramebuffer(g.defFBO) + g.ctx.BindFramebuffer(defFBO) g.cleanupTimer.begin() g.cache.frame() g.drawOps.pathCache.frame()