mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-04 08:55:35 +00:00
gpu: fold driver.Framebuffer functionality into driver.Texture
driver.Device.NewFramebuffer doesn't provide additional information over driver.Device.NewTexture, so Texture can hold its (optional) framebuffer on behalf of the renderers. Metal don't even need a separate framebuffer object. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -35,9 +35,6 @@ type Backend struct {
|
||||
|
||||
caps driver.Caps
|
||||
|
||||
// fbo is the currently bound fbo.
|
||||
fbo *Framebuffer
|
||||
|
||||
floatFormat uint32
|
||||
}
|
||||
|
||||
@@ -51,15 +48,18 @@ type Pipeline struct {
|
||||
}
|
||||
|
||||
type Texture struct {
|
||||
backend *Backend
|
||||
format uint32
|
||||
bindings driver.BufferBinding
|
||||
tex *d3d11.Texture2D
|
||||
sampler *d3d11.SamplerState
|
||||
resView *d3d11.ShaderResourceView
|
||||
uaView *d3d11.UnorderedAccessView
|
||||
width int
|
||||
height int
|
||||
backend *Backend
|
||||
format uint32
|
||||
bindings driver.BufferBinding
|
||||
tex *d3d11.Texture2D
|
||||
sampler *d3d11.SamplerState
|
||||
resView *d3d11.ShaderResourceView
|
||||
uaView *d3d11.UnorderedAccessView
|
||||
renderTarget *d3d11.RenderTargetView
|
||||
|
||||
width int
|
||||
height int
|
||||
foreign bool
|
||||
}
|
||||
|
||||
type VertexShader struct {
|
||||
@@ -78,15 +78,6 @@ type Program struct {
|
||||
shader *d3d11.ComputeShader
|
||||
}
|
||||
|
||||
type Framebuffer struct {
|
||||
dev *d3d11.Device
|
||||
ctx *d3d11.DeviceContext
|
||||
format uint32
|
||||
resource *d3d11.Resource
|
||||
renderTarget *d3d11.RenderTargetView
|
||||
foreign bool
|
||||
}
|
||||
|
||||
type Buffer struct {
|
||||
backend *Backend
|
||||
bind uint32
|
||||
@@ -159,7 +150,7 @@ func newDirect3D11Device(api driver.Direct3D11) (driver.Device, error) {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport image.Point) driver.Framebuffer {
|
||||
func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport image.Point) driver.Texture {
|
||||
var (
|
||||
renderTarget *d3d11.RenderTargetView
|
||||
)
|
||||
@@ -167,19 +158,19 @@ func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport im
|
||||
switch t := target.(type) {
|
||||
case driver.Direct3D11RenderTarget:
|
||||
renderTarget = (*d3d11.RenderTargetView)(t.RenderTarget)
|
||||
case *Framebuffer:
|
||||
case *Texture:
|
||||
renderTarget = t.renderTarget
|
||||
default:
|
||||
panic(fmt.Errorf("d3d11: invalid render target type: %T", target))
|
||||
}
|
||||
}
|
||||
b.ctx.OMSetRenderTargets(renderTarget, nil)
|
||||
return &Framebuffer{ctx: b.ctx, dev: b.dev, renderTarget: renderTarget, foreign: true}
|
||||
return &Texture{backend: b, renderTarget: renderTarget, foreign: true}
|
||||
}
|
||||
|
||||
func (b *Backend) CopyTexture(dstTex driver.Texture, dstOrigin image.Point, srcFBO driver.Framebuffer, srcRect image.Rectangle) {
|
||||
func (b *Backend) CopyTexture(dstTex driver.Texture, dstOrigin image.Point, srcTex driver.Texture, srcRect image.Rectangle) {
|
||||
dst := (*d3d11.Resource)(unsafe.Pointer(dstTex.(*Texture).tex))
|
||||
src := srcFBO.(*Framebuffer).resource
|
||||
src := (*d3d11.Resource)(srcTex.(*Texture).tex)
|
||||
b.ctx.CopySubresourceRegion(
|
||||
dst,
|
||||
0, // Destination subresource.
|
||||
@@ -248,6 +239,7 @@ func (b *Backend) NewTexture(format driver.TextureFormat, width, height int, min
|
||||
sampler *d3d11.SamplerState
|
||||
resView *d3d11.ShaderResourceView
|
||||
uaView *d3d11.UnorderedAccessView
|
||||
fbo *d3d11.RenderTargetView
|
||||
)
|
||||
if bindings&driver.BufferBindingTexture != 0 {
|
||||
var filter uint32
|
||||
@@ -317,21 +309,24 @@ func (b *Backend) NewTexture(format driver.TextureFormat, width, height int, min
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &Texture{backend: b, format: d3dfmt, tex: tex, sampler: sampler, resView: resView, uaView: uaView, bindings: bindings, width: width, height: height}, nil
|
||||
}
|
||||
|
||||
func (b *Backend) NewFramebuffer(tex driver.Texture) (driver.Framebuffer, error) {
|
||||
d3dtex := tex.(*Texture)
|
||||
if d3dtex.bindings&driver.BufferBindingFramebuffer == 0 {
|
||||
return nil, errors.New("the texture was created without BufferBindingFramebuffer binding")
|
||||
if bindings&driver.BufferBindingFramebuffer != 0 {
|
||||
resource := (*d3d11.Resource)(unsafe.Pointer(tex))
|
||||
fbo, err = b.dev.CreateRenderTargetView(resource)
|
||||
if err != nil {
|
||||
if uaView != nil {
|
||||
d3d11.IUnknownRelease(unsafe.Pointer(uaView), uaView.Vtbl.Release)
|
||||
}
|
||||
if sampler != nil {
|
||||
d3d11.IUnknownRelease(unsafe.Pointer(sampler), sampler.Vtbl.Release)
|
||||
}
|
||||
if resView != nil {
|
||||
d3d11.IUnknownRelease(unsafe.Pointer(resView), resView.Vtbl.Release)
|
||||
}
|
||||
d3d11.IUnknownRelease(unsafe.Pointer(tex), tex.Vtbl.Release)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
resource := (*d3d11.Resource)(unsafe.Pointer(d3dtex.tex))
|
||||
renderTarget, err := b.dev.CreateRenderTargetView(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fbo := &Framebuffer{ctx: b.ctx, dev: b.dev, format: d3dtex.format, resource: resource, renderTarget: renderTarget}
|
||||
return fbo, nil
|
||||
return &Texture{backend: b, format: d3dfmt, tex: tex, sampler: sampler, resView: resView, uaView: uaView, renderTarget: fbo, bindings: bindings, width: width, height: height}, nil
|
||||
}
|
||||
|
||||
func (b *Backend) newInputLayout(vertexShader shader.Sources, layout []driver.InputDesc) (*d3d11.InputLayout, error) {
|
||||
@@ -620,6 +615,12 @@ func (t *Texture) Upload(offset, size image.Point, pixels []byte, stride int) {
|
||||
}
|
||||
|
||||
func (t *Texture) Release() {
|
||||
if t.foreign {
|
||||
panic("texture not created by NewTexture")
|
||||
}
|
||||
if t.renderTarget != nil {
|
||||
d3d11.IUnknownRelease(unsafe.Pointer(t.renderTarget), t.renderTarget.Vtbl.Release)
|
||||
}
|
||||
if t.sampler != nil {
|
||||
d3d11.IUnknownRelease(unsafe.Pointer(t.sampler), t.sampler.Vtbl.Release)
|
||||
}
|
||||
@@ -736,17 +737,14 @@ func (b *Buffer) Release() {
|
||||
*b = Buffer{}
|
||||
}
|
||||
|
||||
func (f *Framebuffer) ReadPixels(src image.Rectangle, pixels []byte, stride int) error {
|
||||
if f.resource == nil {
|
||||
return errors.New("framebuffer does not support ReadPixels")
|
||||
}
|
||||
func (t *Texture) ReadPixels(src image.Rectangle, pixels []byte, stride int) error {
|
||||
w, h := src.Dx(), src.Dy()
|
||||
tex, err := f.dev.CreateTexture2D(&d3d11.TEXTURE2D_DESC{
|
||||
tex, err := t.backend.dev.CreateTexture2D(&d3d11.TEXTURE2D_DESC{
|
||||
Width: uint32(w),
|
||||
Height: uint32(h),
|
||||
MipLevels: 1,
|
||||
ArraySize: 1,
|
||||
Format: f.format,
|
||||
Format: t.format,
|
||||
SampleDesc: d3d11.DXGI_SAMPLE_DESC{
|
||||
Count: 1,
|
||||
Quality: 0,
|
||||
@@ -759,11 +757,11 @@ func (f *Framebuffer) ReadPixels(src image.Rectangle, pixels []byte, stride int)
|
||||
}
|
||||
defer d3d11.IUnknownRelease(unsafe.Pointer(tex), tex.Vtbl.Release)
|
||||
res := (*d3d11.Resource)(unsafe.Pointer(tex))
|
||||
f.ctx.CopySubresourceRegion(
|
||||
t.backend.ctx.CopySubresourceRegion(
|
||||
res,
|
||||
0, // Destination subresource.
|
||||
0, 0, 0, // Destination coordinates (x, y, z).
|
||||
f.resource,
|
||||
(*d3d11.Resource)(t.tex),
|
||||
0, // Source subresource.
|
||||
&d3d11.BOX{
|
||||
Left: uint32(src.Min.X),
|
||||
@@ -774,11 +772,11 @@ func (f *Framebuffer) ReadPixels(src image.Rectangle, pixels []byte, stride int)
|
||||
Back: 1,
|
||||
},
|
||||
)
|
||||
resMap, err := f.ctx.Map(res, 0, d3d11.MAP_READ, 0)
|
||||
resMap, err := t.backend.ctx.Map(res, 0, d3d11.MAP_READ, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ReadPixels: %v", err)
|
||||
}
|
||||
defer f.ctx.Unmap(res, 0)
|
||||
defer t.backend.ctx.Unmap(res, 0)
|
||||
srcPitch := stride
|
||||
dstPitch := int(resMap.RowPitch)
|
||||
mapSize := dstPitch * h
|
||||
@@ -797,30 +795,20 @@ func (b *Backend) BeginCompute() {
|
||||
func (b *Backend) EndCompute() {
|
||||
}
|
||||
|
||||
func (b *Backend) BeginRenderPass(fbo driver.Framebuffer, d driver.LoadDesc) {
|
||||
b.fbo = fbo.(*Framebuffer)
|
||||
b.ctx.OMSetRenderTargets(b.fbo.renderTarget, nil)
|
||||
func (b *Backend) BeginRenderPass(tex driver.Texture, d driver.LoadDesc) {
|
||||
t := tex.(*Texture)
|
||||
b.ctx.OMSetRenderTargets(t.renderTarget, nil)
|
||||
if d.Action == driver.LoadActionClear {
|
||||
c := d.ClearColor
|
||||
b.clearColor = [4]float32{c.R, c.G, c.B, c.A}
|
||||
b.ctx.ClearRenderTargetView(b.fbo.renderTarget, &b.clearColor)
|
||||
b.ctx.ClearRenderTargetView(t.renderTarget, &b.clearColor)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Backend) EndRenderPass() {
|
||||
}
|
||||
|
||||
func (f *Framebuffer) Release() {
|
||||
if f.foreign {
|
||||
panic("framebuffer not created by NewFramebuffer")
|
||||
}
|
||||
if f.renderTarget != nil {
|
||||
d3d11.IUnknownRelease(unsafe.Pointer(f.renderTarget), f.renderTarget.Vtbl.Release)
|
||||
f.renderTarget = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Framebuffer) ImplementsRenderTarget() {}
|
||||
func (f *Texture) ImplementsRenderTarget() {}
|
||||
|
||||
func convBufferBinding(typ driver.BufferBinding) uint32 {
|
||||
var bindings uint32
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
// APIs such as OpenGL, Direct3D useful for rendering Gio
|
||||
// operations.
|
||||
type Device interface {
|
||||
BeginFrame(target RenderTarget, clear bool, viewport image.Point) Framebuffer
|
||||
BeginFrame(target RenderTarget, clear bool, viewport image.Point) Texture
|
||||
EndFrame()
|
||||
Caps() Caps
|
||||
NewTimer() Timer
|
||||
@@ -23,7 +23,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)
|
||||
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)
|
||||
@@ -35,7 +34,7 @@ type Device interface {
|
||||
DrawArrays(off, count int)
|
||||
DrawElements(off, count int)
|
||||
|
||||
BeginRenderPass(f Framebuffer, desc LoadDesc)
|
||||
BeginRenderPass(t Texture, desc LoadDesc)
|
||||
EndRenderPass()
|
||||
PrepareTexture(t Texture)
|
||||
BindProgram(p Program)
|
||||
@@ -49,7 +48,7 @@ type Device interface {
|
||||
|
||||
BeginCompute()
|
||||
EndCompute()
|
||||
CopyTexture(dst Texture, dstOrigin image.Point, src Framebuffer, srcRect image.Rectangle)
|
||||
CopyTexture(dst Texture, dstOrigin image.Point, src Texture, srcRect image.Rectangle)
|
||||
MemoryBarrier()
|
||||
DispatchCompute(x, y, z int)
|
||||
|
||||
@@ -133,12 +132,6 @@ type Buffer interface {
|
||||
Download(data []byte) error
|
||||
}
|
||||
|
||||
type Framebuffer interface {
|
||||
RenderTarget
|
||||
Release()
|
||||
ReadPixels(src image.Rectangle, pixels []byte, stride int) error
|
||||
}
|
||||
|
||||
type Timer interface {
|
||||
Begin()
|
||||
End()
|
||||
@@ -147,7 +140,9 @@ type Timer interface {
|
||||
}
|
||||
|
||||
type Texture interface {
|
||||
RenderTarget
|
||||
Upload(offset, size image.Point, pixels []byte, stride int)
|
||||
ReadPixels(src image.Rectangle, pixels []byte, stride int) error
|
||||
Release()
|
||||
}
|
||||
|
||||
@@ -210,9 +205,9 @@ func (f Features) Has(feats Features) bool {
|
||||
return f&feats == feats
|
||||
}
|
||||
|
||||
func DownloadImage(d Device, f Framebuffer, r image.Rectangle) (*image.RGBA, error) {
|
||||
func DownloadImage(d Device, t Texture, r image.Rectangle) (*image.RGBA, error) {
|
||||
img := image.NewRGBA(r)
|
||||
if err := f.ReadPixels(r, img.Pix, img.Stride); err != nil {
|
||||
if err := t.ReadPixels(r, img.Pix, img.Stride); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if d.Caps().BottomLeftOrigin {
|
||||
|
||||
@@ -407,6 +407,7 @@ type Texture struct {
|
||||
sampler C.CFTypeRef
|
||||
width int
|
||||
height int
|
||||
foreign bool
|
||||
}
|
||||
|
||||
type Shader struct {
|
||||
@@ -424,12 +425,6 @@ type Pipeline struct {
|
||||
topology C.MTLPrimitiveType
|
||||
}
|
||||
|
||||
type Framebuffer struct {
|
||||
backend *Backend
|
||||
texture C.CFTypeRef
|
||||
foreign bool
|
||||
}
|
||||
|
||||
type Buffer struct {
|
||||
backend *Backend
|
||||
size int
|
||||
@@ -469,7 +464,7 @@ func newMetalDevice(api driver.Metal) (driver.Device, error) {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport image.Point) driver.Framebuffer {
|
||||
func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport image.Point) driver.Texture {
|
||||
if b.lastCmdBuffer != 0 {
|
||||
C.cmdBufferWaitUntilCompleted(b.lastCmdBuffer)
|
||||
b.stagingOff = 0
|
||||
@@ -477,13 +472,11 @@ func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport im
|
||||
if target == nil {
|
||||
return nil
|
||||
}
|
||||
var texture C.CFTypeRef
|
||||
switch t := target.(type) {
|
||||
case driver.MetalRenderTarget:
|
||||
texture = C.CFTypeRef(t.Texture)
|
||||
return &Framebuffer{texture: texture, foreign: true}
|
||||
case *Framebuffer:
|
||||
texture = C.CFTypeRef(t.texture)
|
||||
texture := C.CFTypeRef(t.Texture)
|
||||
return &Texture{texture: texture, foreign: true}
|
||||
case *Texture:
|
||||
return t
|
||||
default:
|
||||
panic(fmt.Sprintf("metal: unsupported render target type: %T", t))
|
||||
@@ -503,10 +496,10 @@ func (b *Backend) startBlit() C.CFTypeRef {
|
||||
return b.blitEnc
|
||||
}
|
||||
|
||||
func (b *Backend) CopyTexture(dst driver.Texture, dorig image.Point, src driver.Framebuffer, srect image.Rectangle) {
|
||||
func (b *Backend) CopyTexture(dst driver.Texture, dorig image.Point, src driver.Texture, srect image.Rectangle) {
|
||||
enc := b.startBlit()
|
||||
dstTex := dst.(*Texture).texture
|
||||
srcTex := src.(*Framebuffer).texture
|
||||
srcTex := src.(*Texture).texture
|
||||
ssz := srect.Size()
|
||||
C.blitEncCopyFromTexture(
|
||||
enc,
|
||||
@@ -718,13 +711,6 @@ func pixelFormatFor(f driver.TextureFormat) C.MTLPixelFormat {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Backend) NewFramebuffer(tex driver.Texture) (driver.Framebuffer, error) {
|
||||
t := tex.(*Texture)
|
||||
C.CFRetain(t.texture)
|
||||
fbo := &Framebuffer{backend: b, texture: t.texture}
|
||||
return fbo, nil
|
||||
}
|
||||
|
||||
func (b *Backend) NewBuffer(typ driver.BufferBinding, size int) (driver.Buffer, error) {
|
||||
// Transfer buffer contents in command encoders on every use for
|
||||
// smaller buffers. The advantage is that buffer re-use during a frame
|
||||
@@ -921,6 +907,9 @@ func (t *Texture) Upload(offset, size image.Point, pixels []byte, stride int) {
|
||||
}
|
||||
|
||||
func (t *Texture) Release() {
|
||||
if t.foreign {
|
||||
panic("metal: release of external texture")
|
||||
}
|
||||
C.CFRelease(t.texture)
|
||||
C.CFRelease(t.sampler)
|
||||
*t = Texture{}
|
||||
@@ -1076,7 +1065,7 @@ func (b *Buffer) Release() {
|
||||
*b = Buffer{}
|
||||
}
|
||||
|
||||
func (f *Framebuffer) ReadPixels(src image.Rectangle, pixels []byte, stride int) error {
|
||||
func (t *Texture) ReadPixels(src image.Rectangle, pixels []byte, stride int) error {
|
||||
if len(pixels) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -1092,10 +1081,10 @@ func (f *Framebuffer) ReadPixels(src image.Rectangle, pixels []byte, stride int)
|
||||
}
|
||||
stageStride := sz.X * 4
|
||||
n := sz.Y * stageStride
|
||||
buf, off := f.backend.stagingBuffer(n)
|
||||
enc := f.backend.startBlit()
|
||||
C.blitEncCopyTextureToBuffer(enc, f.texture, buf, C.NSUInteger(off), C.NSUInteger(stageStride), C.NSUInteger(n), msize, orig)
|
||||
f.backend.endCmdBuffer(true)
|
||||
buf, off := t.backend.stagingBuffer(n)
|
||||
enc := t.backend.startBlit()
|
||||
C.blitEncCopyTextureToBuffer(enc, t.texture, buf, C.NSUInteger(off), C.NSUInteger(stageStride), C.NSUInteger(n), msize, orig)
|
||||
t.backend.endCmdBuffer(true)
|
||||
store := bufferSlice(buf, off, n)
|
||||
var srcOff, dstOff int
|
||||
for y := 0; y < sz.Y; y++ {
|
||||
@@ -1108,10 +1097,10 @@ func (f *Framebuffer) ReadPixels(src image.Rectangle, pixels []byte, stride int)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Backend) BeginRenderPass(fbo driver.Framebuffer, d driver.LoadDesc) {
|
||||
func (b *Backend) BeginRenderPass(tex driver.Texture, d driver.LoadDesc) {
|
||||
b.endEncoder()
|
||||
b.ensureCmdBuffer()
|
||||
f := fbo.(*Framebuffer)
|
||||
f := tex.(*Texture)
|
||||
col := d.ClearColor
|
||||
var act C.MTLLoadAction
|
||||
switch d.Action {
|
||||
@@ -1151,12 +1140,4 @@ func (b *Backend) endEncoder() {
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Framebuffer) Release() {
|
||||
if f.foreign {
|
||||
panic("metal: invalid release of external framebuffer")
|
||||
}
|
||||
C.CFRelease(f.texture)
|
||||
*f = Framebuffer{}
|
||||
}
|
||||
|
||||
func (f *Framebuffer) ImplementsRenderTarget() {}
|
||||
func (f *Texture) ImplementsRenderTarget() {}
|
||||
|
||||
@@ -98,14 +98,11 @@ type timer struct {
|
||||
type texture struct {
|
||||
backend *Backend
|
||||
obj gl.Texture
|
||||
fbo gl.Framebuffer
|
||||
hasFBO bool
|
||||
triple textureTriple
|
||||
width int
|
||||
height int
|
||||
}
|
||||
|
||||
type framebuffer struct {
|
||||
backend *Backend
|
||||
obj gl.Framebuffer
|
||||
foreign bool
|
||||
}
|
||||
|
||||
@@ -213,7 +210,7 @@ func newOpenGLDevice(api driver.OpenGL) (driver.Device, error) {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport image.Point) driver.Framebuffer {
|
||||
func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport image.Point) driver.Texture {
|
||||
b.clear = clear
|
||||
b.glstate = b.queryState()
|
||||
b.savedState = b.glstate
|
||||
@@ -223,8 +220,8 @@ func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport im
|
||||
switch t := target.(type) {
|
||||
case driver.OpenGLRenderTarget:
|
||||
renderFBO = gl.Framebuffer(t)
|
||||
case *framebuffer:
|
||||
renderFBO = t.obj
|
||||
case *texture:
|
||||
renderFBO = t.ensureFBO()
|
||||
default:
|
||||
panic(fmt.Errorf("opengl: invalid render target type: %T", target))
|
||||
}
|
||||
@@ -265,7 +262,7 @@ func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport im
|
||||
if b.sRGBFBO != nil && !clear {
|
||||
b.clearOutput(0, 0, 0, 0)
|
||||
}
|
||||
return &framebuffer{backend: b, obj: renderFBO, foreign: true}
|
||||
return &texture{backend: b, fbo: renderFBO, hasFBO: true, foreign: true}
|
||||
}
|
||||
|
||||
func (b *Backend) EndFrame() {
|
||||
@@ -650,22 +647,30 @@ func (b *Backend) IsTimeContinuous() bool {
|
||||
return b.funcs.GetInteger(gl.GPU_DISJOINT_EXT) == gl.FALSE
|
||||
}
|
||||
|
||||
func (b *Backend) NewFramebuffer(tex driver.Texture) (driver.Framebuffer, error) {
|
||||
func (t *texture) ensureFBO() gl.Framebuffer {
|
||||
if t.hasFBO {
|
||||
return t.fbo
|
||||
}
|
||||
b := t.backend
|
||||
oldFBO := b.glstate.drawFBO
|
||||
defer func() {
|
||||
b.glstate.bindFramebuffer(b.funcs, gl.FRAMEBUFFER, oldFBO)
|
||||
}()
|
||||
glErr(b.funcs)
|
||||
gltex := tex.(*texture)
|
||||
fb := b.funcs.CreateFramebuffer()
|
||||
fbo := &framebuffer{backend: b, obj: fb}
|
||||
b.glstate.bindFramebuffer(b.funcs, gl.FRAMEBUFFER, fbo.obj)
|
||||
b.glstate.bindFramebuffer(b.funcs, gl.FRAMEBUFFER, fb)
|
||||
if err := glErr(b.funcs); err != nil {
|
||||
fbo.Release()
|
||||
return nil, err
|
||||
b.funcs.DeleteFramebuffer(fb)
|
||||
panic(err)
|
||||
}
|
||||
b.funcs.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, gltex.obj, 0)
|
||||
b.funcs.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, t.obj, 0)
|
||||
if st := b.funcs.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
|
||||
fbo.Release()
|
||||
return nil, fmt.Errorf("incomplete framebuffer, status = 0x%x, err = %d", st, b.funcs.GetError())
|
||||
b.funcs.DeleteFramebuffer(fb)
|
||||
panic(fmt.Errorf("incomplete framebuffer, status = 0x%x, err = %d", st, b.funcs.GetError()))
|
||||
}
|
||||
return fbo, nil
|
||||
t.fbo = fb
|
||||
t.hasFBO = true
|
||||
return fb
|
||||
}
|
||||
|
||||
func (b *Backend) NewTexture(format driver.TextureFormat, width, height int, minFilter, magFilter driver.TextureFilter, binding driver.BufferBinding) (driver.Texture, error) {
|
||||
@@ -1120,21 +1125,21 @@ func (b *Backend) BindIndexBuffer(buf driver.Buffer) {
|
||||
b.glstate.bindBuffer(b.funcs, gl.ELEMENT_ARRAY_BUFFER, gbuf.obj)
|
||||
}
|
||||
|
||||
func (b *Backend) CopyTexture(dst driver.Texture, dstOrigin image.Point, src driver.Framebuffer, srcRect image.Rectangle) {
|
||||
func (b *Backend) CopyTexture(dst driver.Texture, dstOrigin image.Point, src driver.Texture, srcRect image.Rectangle) {
|
||||
const unit = 0
|
||||
oldTex := b.glstate.texUnits.binds[unit]
|
||||
defer func() {
|
||||
b.glstate.bindTexture(b.funcs, unit, oldTex)
|
||||
}()
|
||||
b.glstate.bindTexture(b.funcs, unit, dst.(*texture).obj)
|
||||
b.glstate.bindFramebuffer(b.funcs, gl.READ_FRAMEBUFFER, src.(*framebuffer).obj)
|
||||
b.glstate.bindFramebuffer(b.funcs, gl.READ_FRAMEBUFFER, src.(*texture).ensureFBO())
|
||||
sz := srcRect.Size()
|
||||
b.funcs.CopyTexSubImage2D(gl.TEXTURE_2D, 0, dstOrigin.X, dstOrigin.Y, srcRect.Min.X, srcRect.Min.Y, sz.X, sz.Y)
|
||||
}
|
||||
|
||||
func (f *framebuffer) ReadPixels(src image.Rectangle, pixels []byte, stride int) error {
|
||||
glErr(f.backend.funcs)
|
||||
f.backend.glstate.bindFramebuffer(f.backend.funcs, gl.FRAMEBUFFER, f.obj)
|
||||
func (t *texture) ReadPixels(src image.Rectangle, pixels []byte, stride int) error {
|
||||
glErr(t.backend.funcs)
|
||||
t.backend.glstate.bindFramebuffer(t.backend.funcs, gl.FRAMEBUFFER, t.ensureFBO())
|
||||
if len(pixels) < src.Dx()*src.Dy()*4 {
|
||||
return errors.New("unexpected RGBA size")
|
||||
}
|
||||
@@ -1144,9 +1149,9 @@ func (f *framebuffer) ReadPixels(src image.Rectangle, pixels []byte, stride int)
|
||||
if n := stride / 4; n != w {
|
||||
rowLen = n
|
||||
}
|
||||
f.backend.glstate.pixelStorei(f.backend.funcs, gl.PACK_ROW_LENGTH, rowLen)
|
||||
f.backend.funcs.ReadPixels(src.Min.X, src.Min.Y, w, h, gl.RGBA, gl.UNSIGNED_BYTE, pixels)
|
||||
return glErr(f.backend.funcs)
|
||||
t.backend.glstate.pixelStorei(t.backend.funcs, gl.PACK_ROW_LENGTH, rowLen)
|
||||
t.backend.funcs.ReadPixels(src.Min.X, src.Min.Y, w, h, gl.RGBA, gl.UNSIGNED_BYTE, pixels)
|
||||
return glErr(t.backend.funcs)
|
||||
}
|
||||
|
||||
func (b *Backend) BindPipeline(pl driver.Pipeline) {
|
||||
@@ -1163,8 +1168,9 @@ func (b *Backend) BeginCompute() {
|
||||
func (b *Backend) EndCompute() {
|
||||
}
|
||||
|
||||
func (b *Backend) BeginRenderPass(fbo driver.Framebuffer, desc driver.LoadDesc) {
|
||||
b.glstate.bindFramebuffer(b.funcs, gl.FRAMEBUFFER, fbo.(*framebuffer).obj)
|
||||
func (b *Backend) BeginRenderPass(tex driver.Texture, desc driver.LoadDesc) {
|
||||
fbo := tex.(*texture).ensureFBO()
|
||||
b.glstate.bindFramebuffer(b.funcs, gl.FRAMEBUFFER, fbo)
|
||||
switch desc.Action {
|
||||
case driver.LoadActionClear:
|
||||
c := desc.ClearColor
|
||||
@@ -1177,14 +1183,7 @@ func (b *Backend) BeginRenderPass(fbo driver.Framebuffer, desc driver.LoadDesc)
|
||||
func (b *Backend) EndRenderPass() {
|
||||
}
|
||||
|
||||
func (f *framebuffer) Release() {
|
||||
if f.foreign {
|
||||
panic("framebuffer not created by NewFramebuffer")
|
||||
}
|
||||
f.backend.glstate.deleteFramebuffer(f.backend.funcs, f.obj)
|
||||
}
|
||||
|
||||
func (f *framebuffer) ImplementsRenderTarget() {}
|
||||
func (f *texture) ImplementsRenderTarget() {}
|
||||
|
||||
func (p *pipeline) Release() {
|
||||
p.prog.Release()
|
||||
@@ -1209,6 +1208,12 @@ func (b *Backend) BindTexture(unit int, t driver.Texture) {
|
||||
}
|
||||
|
||||
func (t *texture) Release() {
|
||||
if t.foreign {
|
||||
panic("texture not created by NewTexture")
|
||||
}
|
||||
if t.hasFBO {
|
||||
t.backend.glstate.deleteFramebuffer(t.backend.funcs, t.fbo)
|
||||
}
|
||||
t.backend.glstate.deleteTexture(t.backend.funcs, t.obj)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user