internal/graphicsdriver: replace Pixels with ReadPixels

Now preparing a byte slice is the caller's responsibility.
This commit is contained in:
Hajime Hoshi 2022-02-27 17:41:19 +09:00
parent 1cb7633ff6
commit b22309a0e5
9 changed files with 33 additions and 35 deletions

View File

@ -605,11 +605,9 @@ type pixelsCommand struct {
// Exec executes a pixelsCommand. // Exec executes a pixelsCommand.
func (c *pixelsCommand) Exec(indexOffset int) error { func (c *pixelsCommand) Exec(indexOffset int) error {
p, err := c.img.image.Pixels() if err := c.img.image.ReadPixels(c.result); err != nil {
if err != nil {
return err return err
} }
c.result = p
return nil return nil
} }

View File

@ -165,18 +165,19 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, offsets [gra
theCommandQueue.EnqueueDrawTrianglesCommand(i, srcs, offsets, vertices, indices, clr, mode, filter, address, dstRegion, srcRegion, shader, uniforms, evenOdd) theCommandQueue.EnqueueDrawTrianglesCommand(i, srcs, offsets, vertices, indices, clr, mode, filter, address, dstRegion, srcRegion, shader, uniforms, evenOdd)
} }
// Pixels returns the image's pixels. // ReadPixels reads the image's pixels.
// Pixels might return nil when OpenGL error happens. // ReadPixels returns an error when an error happens in the graphics driver.
func (i *Image) Pixels() ([]byte, error) { func (i *Image) ReadPixels(buf []byte) error {
i.resolveBufferedReplacePixels() i.resolveBufferedReplacePixels()
c := &pixelsCommand{ c := &pixelsCommand{
img: i, img: i,
result: buf,
} }
theCommandQueue.Enqueue(c) theCommandQueue.Enqueue(c)
if err := theCommandQueue.Flush(); err != nil { if err := theCommandQueue.Flush(); err != nil {
return nil, err return err
} }
return c.result, nil return nil
} }
func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) { func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
@ -222,8 +223,9 @@ func (i *Image) Dump(path string, blackbg bool, rect image.Rectangle) error {
} }
defer f.Close() defer f.Close()
pix, err := i.Pixels() w, h := i.InternalSize()
if err != nil { pix := make([]byte, 4*w*h)
if err := i.ReadPixels(pix); err != nil {
return err return err
} }

View File

@ -80,7 +80,7 @@ type Image interface {
ID() ImageID ID() ImageID
Dispose() Dispose()
IsInvalidated() bool IsInvalidated() bool
Pixels() ([]byte, error) ReadPixels(buf []byte) error
ReplacePixels(args []*ReplacePixelsArgs) ReplacePixels(args []*ReplacePixelsArgs)
} }

View File

@ -1186,15 +1186,18 @@ func (i *Image) syncTexture() {
cb.WaitUntilCompleted() cb.WaitUntilCompleted()
} }
func (i *Image) Pixels() ([]byte, error) { func (i *Image) ReadPixels(buf []byte) error {
if got, want := len(buf), 4*i.width*i.height; got != want {
return fmt.Errorf("metal: len(buf) must be %d but %d at ReadPixels", want, got)
}
i.graphics.flushIfNeeded(false) i.graphics.flushIfNeeded(false)
i.syncTexture() i.syncTexture()
b := make([]byte, 4*i.width*i.height) i.texture.GetBytes(&buf[0], uintptr(4*i.width), mtl.Region{
i.texture.GetBytes(&b[0], uintptr(4*i.width), mtl.Region{
Size: mtl.Size{Width: i.width, Height: i.height, Depth: 1}, Size: mtl.Size{Width: i.width, Height: i.height, Depth: 1},
}, 0) }, 0)
return b, nil return nil
} }
func (i *Image) ReplacePixels(args []*graphicsdriver.ReplacePixelsArgs) { func (i *Image) ReplacePixels(args []*graphicsdriver.ReplacePixelsArgs) {

View File

@ -162,12 +162,10 @@ func (c *context) bindFramebufferImpl(f framebufferNative) {
gl.BindFramebufferEXT(gl.FRAMEBUFFER, uint32(f)) gl.BindFramebufferEXT(gl.FRAMEBUFFER, uint32(f))
} }
func (c *context) framebufferPixels(f *framebuffer, width, height int) []byte { func (c *context) framebufferPixels(buf []byte, f *framebuffer, width, height int) {
gl.Flush() gl.Flush()
c.bindFramebuffer(f.native) c.bindFramebuffer(f.native)
pixels := make([]byte, 4*width*height) gl.ReadPixels(0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(buf))
gl.ReadPixels(0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(pixels))
return pixels
} }
func (c *context) framebufferPixelsToBuffer(f *framebuffer, buffer buffer, width, height int) { func (c *context) framebufferPixelsToBuffer(f *framebuffer, buffer buffer, width, height int) {

View File

@ -236,7 +236,7 @@ func (c *context) bindFramebufferImpl(f framebufferNative) {
gl.bindFramebuffer.Invoke(gles.FRAMEBUFFER, js.Value(f)) gl.bindFramebuffer.Invoke(gles.FRAMEBUFFER, js.Value(f))
} }
func (c *context) framebufferPixels(f *framebuffer, width, height int) []byte { func (c *context) framebufferPixels(buf []byte, f *framebuffer, width, height int) {
gl := c.gl gl := c.gl
c.bindFramebuffer(f.native) c.bindFramebuffer(f.native)
@ -244,8 +244,7 @@ func (c *context) framebufferPixels(f *framebuffer, width, height int) []byte {
l := 4 * width * height l := 4 * width * height
p := jsutil.TemporaryUint8ArrayFromUint8Slice(l, nil) p := jsutil.TemporaryUint8ArrayFromUint8Slice(l, nil)
gl.readPixels.Invoke(0, 0, width, height, gles.RGBA, gles.UNSIGNED_BYTE, p) gl.readPixels.Invoke(0, 0, width, height, gles.RGBA, gles.UNSIGNED_BYTE, p)
copy(buf, uint8ArrayToSlice(p, l))
return uint8ArrayToSlice(p, l)
} }
func (c *context) framebufferPixelsToBuffer(f *framebuffer, buffer buffer, width, height int) { func (c *context) framebufferPixelsToBuffer(f *framebuffer, buffer buffer, width, height int) {

View File

@ -148,14 +148,12 @@ func (c *context) bindFramebufferImpl(f framebufferNative) {
c.ctx.BindFramebuffer(gles.FRAMEBUFFER, uint32(f)) c.ctx.BindFramebuffer(gles.FRAMEBUFFER, uint32(f))
} }
func (c *context) framebufferPixels(f *framebuffer, width, height int) []byte { func (c *context) framebufferPixels(buf []byte, f *framebuffer, width, height int) {
c.ctx.Flush() c.ctx.Flush()
c.bindFramebuffer(f.native) c.bindFramebuffer(f.native)
pixels := make([]byte, 4*width*height) c.ctx.ReadPixels(buf, 0, 0, int32(width), int32(height), gles.RGBA, gles.UNSIGNED_BYTE)
c.ctx.ReadPixels(pixels, 0, 0, int32(width), int32(height), gles.RGBA, gles.UNSIGNED_BYTE)
return pixels
} }
func (c *context) framebufferPixelsToBuffer(f *framebuffer, buffer buffer, width, height int) { func (c *context) framebufferPixelsToBuffer(f *framebuffer, buffer buffer, width, height int) {

View File

@ -60,13 +60,13 @@ func (i *Image) setViewport() error {
return nil return nil
} }
func (i *Image) Pixels() ([]byte, error) { func (i *Image) ReadPixels(buf []byte) error {
if err := i.ensureFramebuffer(); err != nil { if err := i.ensureFramebuffer(); err != nil {
return nil, err return err
} }
p := i.graphics.context.framebufferPixels(i.framebuffer, i.width, i.height) i.graphics.context.framebufferPixels(buf, i.framebuffer, i.width, i.height)
return p, nil return nil
} }
func (i *Image) framebufferSize() (int, int) { func (i *Image) framebufferSize() (int, int) {

View File

@ -497,8 +497,8 @@ func (i *Image) makeStaleIfDependingOnShader(shader *Shader) {
// readPixelsFromGPU reads the pixels from GPU and resolves the image's 'stale' state. // readPixelsFromGPU reads the pixels from GPU and resolves the image's 'stale' state.
func (i *Image) readPixelsFromGPU() error { func (i *Image) readPixelsFromGPU() error {
pix, err := i.image.Pixels() pix := make([]byte, 4*i.width*i.height)
if err != nil { if err := i.image.ReadPixels(pix); err != nil {
return err return err
} }
i.basePixels = Pixels{} i.basePixels = Pixels{}
@ -626,8 +626,8 @@ func (i *Image) restore() error {
if len(i.drawTrianglesHistory) > 0 { if len(i.drawTrianglesHistory) > 0 {
i.basePixels = Pixels{} i.basePixels = Pixels{}
pix, err := gimg.Pixels() pix := make([]byte, 4*w*h)
if err != nil { if err := gimg.ReadPixels(pix); err != nil {
return err return err
} }
i.basePixels.AddOrReplace(pix, 0, 0, w, h) i.basePixels.AddOrReplace(pix, 0, 0, w, h)