diff --git a/gpu/backend.go b/gpu/backend.go index d38c8815..95e84d39 100644 --- a/gpu/backend.go +++ b/gpu/backend.go @@ -20,7 +20,7 @@ type Backend interface { IsTimeContinuous() bool NewTexture(format TextureFormat, width, height int, minFilter, magFilter TextureFilter, bindings BufferBinding) Texture DefaultFramebuffer() Framebuffer - NewFramebuffer(tex Texture) Framebuffer + NewFramebuffer(tex Texture) (Framebuffer, error) NewImmutableBuffer(typ BufferBinding, data []byte) Buffer NewBuffer(typ BufferBinding, size int) Buffer NewProgram(vertexShader, fragmentShader ShaderSources) (Program, error) @@ -127,7 +127,6 @@ type Framebuffer interface { Bind() Invalidate() Release() - IsComplete() error } type Timer interface { diff --git a/gpu/gl/backend.go b/gpu/gl/backend.go index 124321b6..2417629c 100644 --- a/gpu/gl/backend.go +++ b/gpu/gl/backend.go @@ -139,7 +139,7 @@ func NewBackend(f Functions) (*Backend, error) { } func (b *Backend) BeginFrame() { - // Assume GL state is reset. + // Assume GL state is reset between frames. b.state = glstate{} } @@ -162,13 +162,17 @@ func (b *Backend) IsTimeContinuous() bool { return b.funcs.GetInteger(GPU_DISJOINT_EXT) == FALSE } -func (b *Backend) NewFramebuffer(tex gpu.Texture) gpu.Framebuffer { +func (b *Backend) NewFramebuffer(tex gpu.Texture) (gpu.Framebuffer, error) { gltex := tex.(*gpuTexture) fb := b.funcs.CreateFramebuffer() fbo := &gpuFramebuffer{funcs: b.funcs, obj: fb} fbo.Bind() b.funcs.FramebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_2D, gltex.obj, 0) - return fbo + if st := b.funcs.CheckFramebufferStatus(FRAMEBUFFER); st != FRAMEBUFFER_COMPLETE { + fbo.Release() + return nil, fmt.Errorf("incomplete framebuffer, status = 0x%x, err = %d", st, b.funcs.GetError()) + } + return fbo, nil } func (b *Backend) DefaultFramebuffer() gpu.Framebuffer { @@ -536,13 +540,6 @@ func (b *gpuBuffer) BindIndex() { b.backend.funcs.BindBuffer(ELEMENT_ARRAY_BUFFER, b.obj) } -func (f *gpuFramebuffer) IsComplete() error { - if st := f.funcs.CheckFramebufferStatus(FRAMEBUFFER); st != FRAMEBUFFER_COMPLETE { - return fmt.Errorf("incomplete framebuffer, status = 0x%x, err = %d", st, f.funcs.GetError()) - } - return nil -} - func (f *gpuFramebuffer) Bind() { f.funcs.BindFramebuffer(FRAMEBUFFER, f.obj) } diff --git a/gpu/gpu.go b/gpu/gpu.go index 00460f14..d777f0c5 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -489,7 +489,7 @@ func (r *renderer) stencilClips(pathCache *opCache, ops []*pathOp) { if fbo != p.place.Idx { fbo = p.place.Idx f := r.pather.stenciler.cover(fbo) - bindFramebuffer(f.fbo) + f.fbo.Bind() r.ctx.Clear(BufferAttachmentColor) } data, _ := pathCache.get(p.pathKey) @@ -513,7 +513,7 @@ func (r *renderer) intersect(ops []imageOp) { if fbo != img.place.Idx { fbo = img.place.Idx f := r.pather.stenciler.intersections.fbos[fbo] - bindFramebuffer(f.fbo) + f.fbo.Bind() r.ctx.Clear(BufferAttachmentColor) } r.ctx.Viewport(img.place.Pos.X, img.place.Pos.Y, img.clip.Dx(), img.clip.Dy()) @@ -990,13 +990,6 @@ func clipSpaceTransform(r image.Rectangle, viewport image.Point) (f32.Point, f32 return scale, offset } -func bindFramebuffer(fbo Framebuffer) { - fbo.Bind() - if err := fbo.IsComplete(); err != nil { - panic(fmt.Errorf("AA FBO not complete: %v", err)) - } -} - // Fill in maximal Y coordinates of the NW and NE corners. func fillMaxY(verts []byte) { contour := 0 diff --git a/gpu/path.go b/gpu/path.go index d76d02a9..4ed88f6e 100644 --- a/gpu/path.go +++ b/gpu/path.go @@ -211,7 +211,11 @@ func (s *fboSet) resize(ctx Backend, sizes []image.Point) { f.size = sz f.tex = ctx.NewTexture(TextureFormatFloat, sz.X, sz.Y, FilterNearest, FilterNearest, BufferBindingTexture|BufferBindingFramebuffer) - f.fbo = ctx.NewFramebuffer(f.tex) + fbo, err := ctx.NewFramebuffer(f.tex) + if err != nil { + panic(err) + } + f.fbo = fbo } } // Delete extra fbos.