Skip to content

Commit

Permalink
gles: Rework read_texture.go and read_framebuffer.go to handle MS.
Browse files Browse the repository at this point in the history
Unify the framebuffer read-back logic for color and depth maps.
Add support for multisample resolving.
Use this logic for texture read-backs too.
  • Loading branch information
ben-clayton committed Oct 11, 2017
1 parent 283ad5d commit 0201216
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 133 deletions.
8 changes: 4 additions & 4 deletions gapis/api/gles/gles.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,16 @@ func GetFramebufferAttachmentInfoByID(
fb = c.Bound.DrawFramebuffer.GetID()
}

w, h, sizedFormat, err := s.getFramebufferAttachmentInfo(thread, fb, attachment)
if sizedFormat == 0 {
fbai, err := s.getFramebufferAttachmentInfo(thread, fb, attachment)
if fbai.format == 0 {
return 0, 0, 0, nil, fmt.Errorf("No format set")
}
if err != nil {
return 0, 0, 0, nil, err
}
fmt, ty := getUnsizedFormatAndType(sizedFormat)
fmt, ty := getUnsizedFormatAndType(fbai.format)
f, err := getImageFormat(fmt, ty)
return w, h, 0, f, err
return fbai.width, fbai.height, 0, f, err
}

// Context returns the active context for the given state and thread.
Expand Down
181 changes: 106 additions & 75 deletions gapis/api/gles/read_framebuffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,29 +55,7 @@ func (t *readFramebuffer) depth(
res replay.Result) {

t.Add(id, func(ctx context.Context, out transform.Writer) {
s := out.State()

if fb == 0 {
var err error
if fb, err = getBoundFramebufferID(thread, s); err != nil {
log.W(ctx, "Could not read framebuffer after cmd %v: err", err)
res(nil, &service.ErrDataUnavailable{Reason: messages.ErrFramebufferUnavailable()})
return
}
}

width, height, format, err := GetState(s).getFramebufferAttachmentInfo(thread, fb, api.FramebufferAttachment_Depth)
if err != nil {
log.W(ctx, "Failed to read framebuffer after cmd %v: %v", id, err)
res(nil, &service.ErrDataUnavailable{Reason: messages.ErrFramebufferUnavailable()})
return
}

t := newTweaker(out, id.Derived(), CommandBuilder{Thread: thread})
defer t.revert(ctx)
t.glBindFramebuffer_Read(ctx, fb)

postColorData(ctx, s, int32(width), int32(height), format, out, id, thread, res)
postFBData(ctx, id, thread, 0, 0, fb, api.FramebufferAttachment_Depth, out, res)
})
}

Expand All @@ -90,44 +68,81 @@ func (t *readFramebuffer) color(
res replay.Result) {

t.Add(id, func(ctx context.Context, out transform.Writer) {
s := out.State()
c := GetContext(s, thread)

if fb == 0 {
var err error
if fb, err = getBoundFramebufferID(thread, s); err != nil {
log.W(ctx, "Could not read framebuffer after cmd %v: err", err)
res(nil, &service.ErrDataUnavailable{Reason: messages.ErrFramebufferUnavailable()})
return
}
}

attachment := api.FramebufferAttachment_Color0 + api.FramebufferAttachment(bufferIdx)
w, h, fmt, err := GetState(s).getFramebufferAttachmentInfo(thread, fb, attachment)
if err != nil {
log.W(ctx, "Failed to read framebuffer after cmd %v: %v", id, err)
res(nil, &service.ErrDataUnavailable{Reason: messages.ErrFramebufferUnavailable()})
return
}
if fmt == 0 {
log.W(ctx, "Failed to read framebuffer after cmd %v: no image format", id)
postFBData(ctx, id, thread, width, height, fb, attachment, out, res)
})
}

func postFBData(ctx context.Context,
id api.CmdID,
thread uint64,
width, height uint32,
fb FramebufferId,
attachment api.FramebufferAttachment,
out transform.Writer,
res replay.Result) {

s := out.State()
c := GetContext(s, thread)

if fb == 0 {
var err error
if fb, err = getBoundFramebufferID(thread, s); err != nil {
log.W(ctx, "Could not read framebuffer after cmd %v: err", err)
res(nil, &service.ErrDataUnavailable{Reason: messages.ErrFramebufferUnavailable()})
return
}
}

var (
inW = int32(w)
inH = int32(h)
outW = int32(width)
outH = int32(height)
)
fbai, err := GetState(s).getFramebufferAttachmentInfo(thread, fb, attachment)
if err != nil {
log.W(ctx, "Failed to read framebuffer after cmd %v: %v", id, err)
res(nil, &service.ErrDataUnavailable{Reason: messages.ErrFramebufferUnavailable()})
return
}
if fbai.format == 0 {
log.W(ctx, "Failed to read framebuffer after cmd %v: no image format", id)
res(nil, &service.ErrDataUnavailable{Reason: messages.ErrFramebufferUnavailable()})
return
}
glAtt, err := attachmentToEnum(attachment)
if err != nil {
log.W(ctx, "Failed to get attachment as GLenum: %v", err)
res(nil, &service.ErrDataUnavailable{Reason: messages.ErrFramebufferUnavailable()})
return
}

dID := id.Derived()
cb := CommandBuilder{Thread: thread}
t := newTweaker(out, dID, cb)
defer t.revert(ctx)
t.glBindFramebuffer_Read(ctx, fb)
var (
inW = int32(fbai.width)
inH = int32(fbai.height)
outW = int32(width)
outH = int32(height)
)

if outW == 0 {
outW = inW
}
if outH == 0 {
outH = inH
}

dID := id.Derived()
cb := CommandBuilder{Thread: thread}
t := newTweaker(out, dID, cb)
defer t.revert(ctx)
t.glBindFramebuffer_Read(ctx, fb)

var bufferBits GLbitfield
switch {
case attachment.IsColor():
bufferBits = GLbitfield_GL_COLOR_BUFFER_BIT
case attachment.IsDepth():
bufferBits = GLbitfield_GL_DEPTH_BUFFER_BIT
case attachment.IsStencil():
bufferBits = GLbitfield_GL_STENCIL_BUFFER_BIT
}

if attachment.IsColor() {
// TODO: These glReadBuffer calls need to be changed for on-device
// replay. Note that glReadBuffer was only introduced in
// OpenGL ES 3.0, and that GL_FRONT is not a legal enum value.
Expand All @@ -140,32 +155,48 @@ func (t *readFramebuffer) color(
return nil
}))
} else {
t.glReadBuffer(ctx, GLenum_GL_COLOR_ATTACHMENT0+GLenum(bufferIdx))
t.glReadBuffer(ctx, glAtt)
}
}

if inW == outW && inH == outH {
postColorData(ctx, s, outW, outH, fmt, out, id, thread, res)
} else {
t.glScissor(ctx, 0, 0, GLsizei(inW), GLsizei(inH))
framebufferID := t.glGenFramebuffer(ctx)
t.glBindFramebuffer_Draw(ctx, framebufferID)
renderbufferID := t.glGenRenderbuffer(ctx)
t.glBindRenderbuffer(ctx, renderbufferID)

mutateAndWriteEach(ctx, out, dID,
cb.GlRenderbufferStorage(GLenum_GL_RENDERBUFFER, fmt, GLsizei(outW), GLsizei(outH)),
cb.GlFramebufferRenderbuffer(GLenum_GL_DRAW_FRAMEBUFFER, GLenum_GL_COLOR_ATTACHMENT0, GLenum_GL_RENDERBUFFER, renderbufferID),
cb.GlBlitFramebuffer(0, 0, GLint(inW), GLint(inH), 0, 0, GLint(outW), GLint(outH), GLbitfield_GL_COLOR_BUFFER_BIT, GLenum_GL_LINEAR),
)
t.glBindFramebuffer_Read(ctx, framebufferID)

postColorData(ctx, s, outW, outH, fmt, out, id, thread, res)
}
if fbai.multisampled {
// Resolve
t.glScissor(ctx, 0, 0, GLsizei(inW), GLsizei(inH))
framebufferID := t.glGenFramebuffer(ctx)
t.glBindFramebuffer_Draw(ctx, framebufferID)
renderbufferID := t.glGenRenderbuffer(ctx)
t.glBindRenderbuffer(ctx, renderbufferID)

mutateAndWriteEach(ctx, out, dID,
cb.GlRenderbufferStorage(GLenum_GL_RENDERBUFFER, fbai.format, GLsizei(inW), GLsizei(inH)),
cb.GlFramebufferRenderbuffer(GLenum_GL_DRAW_FRAMEBUFFER, glAtt, GLenum_GL_RENDERBUFFER, renderbufferID),
cb.GlBlitFramebuffer(0, 0, GLint(inW), GLint(inH), 0, 0, GLint(inW), GLint(inH), bufferBits, GLenum_GL_NEAREST),
)

})
t.glBindFramebuffer_Read(ctx, framebufferID)
}

if attachment.IsColor() && (inW != outW || inH != outH) {
// Resize
t.glScissor(ctx, 0, 0, GLsizei(inW), GLsizei(inH))
framebufferID := t.glGenFramebuffer(ctx)
t.glBindFramebuffer_Draw(ctx, framebufferID)
renderbufferID := t.glGenRenderbuffer(ctx)
t.glBindRenderbuffer(ctx, renderbufferID)

mutateAndWriteEach(ctx, out, dID,
cb.GlRenderbufferStorage(GLenum_GL_RENDERBUFFER, fbai.format, GLsizei(outW), GLsizei(outH)),
cb.GlFramebufferRenderbuffer(GLenum_GL_DRAW_FRAMEBUFFER, glAtt, GLenum_GL_RENDERBUFFER, renderbufferID),
cb.GlBlitFramebuffer(0, 0, GLint(inW), GLint(inH), 0, 0, GLint(outW), GLint(outH), bufferBits, GLenum_GL_LINEAR),
)
t.glBindFramebuffer_Read(ctx, framebufferID)
}

postColorData(ctx, s, outW, outH, fbai.format, out, id, thread, res)
}

func postColorData(ctx context.Context,
func postColorData(
ctx context.Context,
s *api.GlobalState,
width, height int32,
sizedFormat GLenum,
Expand Down
71 changes: 42 additions & 29 deletions gapis/api/gles/read_texture.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ import (
"context"
"fmt"

"github.com/google/gapid/core/data/binary"
"github.com/google/gapid/core/image"
"github.com/google/gapid/core/log"
"github.com/google/gapid/gapis/api"
"github.com/google/gapid/gapis/api/transform"
"github.com/google/gapid/gapis/replay"
"github.com/google/gapid/gapis/replay/builder"
"github.com/google/gapid/gapis/replay/value"
"github.com/google/gapid/gapis/service"
)

Expand All @@ -49,11 +48,23 @@ func (t *readTexture) add(ctx context.Context, r *ReadGPUTextureDataResolveable,

tex, ok := c.Objects.Shared.Textures[TextureId(r.Texture)]
if !ok {
panic(fmt.Errorf("Attempting to read from a texture that does not exist.\nResolvable: %+v\nTexture: %+v", r, tex))
err := fmt.Errorf("Attempting to read from a texture that does not exist.\n"+
"Resolvable: %+v"+
"Texture: %+v", r, tex)
log.W(ctx, "%v", err)
res(nil, err)
return
}
layer := tex.Levels[GLint(r.Level)].Layers[GLint(r.Layer)]
lvl := tex.Levels[GLint(r.Level)]
layer := lvl.Layers[GLint(r.Layer)]
if layer == nil {
panic(fmt.Errorf("Attempting to read from a texture layer that does not exist.\nResolvable: %+v\nTexture: %+v", r, tex))
err := fmt.Errorf("Attempting to read from a texture (Level: %v/%v, Layer: %v/%v) that does not exist.\n"+
"Resolvable: %+v\n"+
"Texture: %+v",
r.Level, len(tex.Levels), r.Layer, len(lvl.Layers), r, tex)
log.W(ctx, "%v", err)
res(nil, err)
return
}

size := uint64(f.Size(int(layer.Width), int(layer.Height), 1))
Expand All @@ -63,31 +74,33 @@ func (t *readTexture) add(ctx context.Context, r *ReadGPUTextureDataResolveable,
t := newTweaker(out, dID, cb)
defer t.revert(ctx)

t.setPackStorage(ctx, PixelStorageState{Alignment: 1}, 0)
t.glBindTexture(ctx, tex)
framebufferID := t.glGenFramebuffer(ctx)
t.glBindFramebuffer_Draw(ctx, framebufferID)

target := tex.Kind
if tex.Kind == GLenum_GL_TEXTURE_CUBE_MAP {
target = GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_X + GLenum(r.Layer)
streamFmt, err := getUncompressedStreamFormat(getUnsizedFormatAndType(layer.SizedFormat))
if err != nil {
res(nil, err)
return
}
out.MutateAndWrite(ctx, dID, cb.GlGetTexImage(target, GLint(r.Level), GLenum(r.DataFormat), GLenum(r.DataType), tmp.Ptr()))

out.MutateAndWrite(ctx, dID, cb.Custom(func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error {
b.Post(value.ObservedPointer(tmp.Address()), size, func(r binary.Reader, err error) error {
data := make([]byte, size)
if err == nil {
r.Data(data)
err = r.Error()
}
if err == nil {
res(data, nil)
} else {
res(nil, err)
}
return err
})
return nil
}))
var glAtt GLenum
var apiAtt api.FramebufferAttachment
switch {
case streamFmt.HasColorComponent():
glAtt, apiAtt = GLenum_GL_COLOR_ATTACHMENT0, api.FramebufferAttachment_Color0
case streamFmt.HasDepthComponent():
glAtt, apiAtt = GLenum_GL_DEPTH_ATTACHMENT, api.FramebufferAttachment_Depth
default:
res(nil, fmt.Errorf("Unsupported texture format %v", streamFmt))
return
}

if r.Layer == 0 {
out.MutateAndWrite(ctx, dID, cb.GlFramebufferTexture(GLenum_GL_DRAW_FRAMEBUFFER, glAtt, tex.ID, GLint(r.Level)))
} else {
out.MutateAndWrite(ctx, dID, cb.GlFramebufferTextureLayer(GLenum_GL_DRAW_FRAMEBUFFER, glAtt, tex.ID, GLint(r.Level), GLint(r.Layer)))
}
postFBData(ctx, dID, r.Thread, uint32(layer.Width), uint32(layer.Height), framebufferID, apiAtt, out, res)
})
}

Expand All @@ -104,5 +117,5 @@ func (r *ReadGPUTextureDataResolveable) Resolve(ctx context.Context) (interface{
if err != nil {
return nil, err
}
return res.([]byte), nil
return res.(*image.Data).Bytes, nil
}
Loading

0 comments on commit 0201216

Please sign in to comment.