mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-12 22:17:26 +01:00
internal/graphicsdriver: refactoring: use image.Rectangle
This commit is contained in:
parent
d2c991b774
commit
e98acd3dc7
@ -16,6 +16,7 @@ package graphicscommand
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -427,15 +428,12 @@ func (c *writePixelsCommand) Exec(graphicsDriver graphicsdriver.Graphics, indexO
|
|||||||
type readPixelsCommand struct {
|
type readPixelsCommand struct {
|
||||||
result []byte
|
result []byte
|
||||||
img *Image
|
img *Image
|
||||||
x int
|
region image.Rectangle
|
||||||
y int
|
|
||||||
width int
|
|
||||||
height int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes a readPixelsCommand.
|
// Exec executes a readPixelsCommand.
|
||||||
func (c *readPixelsCommand) Exec(graphicsDriver graphicsdriver.Graphics, indexOffset int) error {
|
func (c *readPixelsCommand) Exec(graphicsDriver graphicsdriver.Graphics, indexOffset int) error {
|
||||||
if err := c.img.image.ReadPixels(c.result, c.x, c.y, c.width, c.height); err != nil {
|
if err := c.img.image.ReadPixels(c.result, c.region); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -163,14 +163,11 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, offsets [g
|
|||||||
|
|
||||||
// ReadPixels reads the image's pixels.
|
// ReadPixels reads the image's pixels.
|
||||||
// ReadPixels returns an error when an error happens in the graphics driver.
|
// ReadPixels returns an error when an error happens in the graphics driver.
|
||||||
func (i *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, buf []byte, x, y, width, height int) error {
|
func (i *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, buf []byte, region image.Rectangle) error {
|
||||||
i.flushBufferedWritePixels()
|
i.flushBufferedWritePixels()
|
||||||
c := &readPixelsCommand{
|
c := &readPixelsCommand{
|
||||||
img: i,
|
img: i,
|
||||||
x: x,
|
region: region,
|
||||||
y: y,
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
result: buf,
|
result: buf,
|
||||||
}
|
}
|
||||||
theCommandQueue.Enqueue(c)
|
theCommandQueue.Enqueue(c)
|
||||||
@ -180,13 +177,10 @@ func (i *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, buf []byte, x
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) WritePixels(pixels []byte, x, y, width, height int) {
|
func (i *Image) WritePixels(pixels []byte, region image.Rectangle) {
|
||||||
i.bufferedWP = append(i.bufferedWP, &graphicsdriver.WritePixelsArgs{
|
i.bufferedWP = append(i.bufferedWP, &graphicsdriver.WritePixelsArgs{
|
||||||
Pixels: pixels,
|
Pixels: pixels,
|
||||||
X: x,
|
Region: region,
|
||||||
Y: y,
|
|
||||||
Width: width,
|
|
||||||
Height: height,
|
|
||||||
})
|
})
|
||||||
addImageWithBuffer(i)
|
addImageWithBuffer(i)
|
||||||
}
|
}
|
||||||
@ -228,7 +222,7 @@ func (i *Image) dumpTo(w io.Writer, graphicsDriver graphicsdriver.Graphics, blac
|
|||||||
}
|
}
|
||||||
|
|
||||||
pix := make([]byte, 4*i.width*i.height)
|
pix := make([]byte, 4*i.width*i.height)
|
||||||
if err := i.ReadPixels(graphicsDriver, pix, 0, 0, i.width, i.height); err != nil {
|
if err := i.ReadPixels(graphicsDriver, pix, image.Rect(0, 0, i.width, i.height)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ package graphicscommand_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ func TestClear(t *testing.T) {
|
|||||||
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendClear, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false)
|
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendClear, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false)
|
||||||
|
|
||||||
pix := make([]byte, 4*w*h)
|
pix := make([]byte, 4*w*h)
|
||||||
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, 0, 0, w, h); err != nil {
|
if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
for j := 0; j < h/2; j++ {
|
for j := 0; j < h/2; j++ {
|
||||||
@ -96,7 +97,7 @@ func TestWritePixelsPartAfterDrawTriangles(t *testing.T) {
|
|||||||
}
|
}
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendClear, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false)
|
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendClear, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false)
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false)
|
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false)
|
||||||
dst.WritePixels(make([]byte, 4), 0, 0, 1, 1)
|
dst.WritePixels(make([]byte, 4), image.Rect(0, 0, 1, 1))
|
||||||
|
|
||||||
// TODO: Check the result.
|
// TODO: Check the result.
|
||||||
}
|
}
|
||||||
@ -120,7 +121,7 @@ func TestShader(t *testing.T) {
|
|||||||
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, s, nil, false)
|
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, s, nil, false)
|
||||||
|
|
||||||
pix := make([]byte, 4*w*h)
|
pix := make([]byte, 4*w*h)
|
||||||
if err := dst.ReadPixels(g, pix, 0, 0, w, h); err != nil {
|
if err := dst.ReadPixels(g, pix, image.Rect(0, 0, w, h)); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
for j := 0; j < h; j++ {
|
for j := 0; j < h; j++ {
|
||||||
|
@ -16,6 +16,7 @@ package directx
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||||
@ -79,10 +80,10 @@ func (i *image11) IsInvalidated() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *image11) ReadPixels(buf []byte, x, y, width, height int) error {
|
func (i *image11) ReadPixels(buf []byte, region image.Rectangle) error {
|
||||||
staging, err := i.graphics.device.CreateTexture2D(&_D3D11_TEXTURE2D_DESC{
|
staging, err := i.graphics.device.CreateTexture2D(&_D3D11_TEXTURE2D_DESC{
|
||||||
Width: uint32(width),
|
Width: uint32(region.Dx()),
|
||||||
Height: uint32(height),
|
Height: uint32(region.Dy()),
|
||||||
MipLevels: 0,
|
MipLevels: 0,
|
||||||
ArraySize: 1,
|
ArraySize: 1,
|
||||||
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
|
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||||
@ -101,11 +102,11 @@ func (i *image11) ReadPixels(buf []byte, x, y, width, height int) error {
|
|||||||
defer staging.Release()
|
defer staging.Release()
|
||||||
|
|
||||||
i.graphics.deviceContext.CopySubresourceRegion(unsafe.Pointer(staging), 0, 0, 0, 0, unsafe.Pointer(i.texture), 0, &_D3D11_BOX{
|
i.graphics.deviceContext.CopySubresourceRegion(unsafe.Pointer(staging), 0, 0, 0, 0, unsafe.Pointer(i.texture), 0, &_D3D11_BOX{
|
||||||
left: uint32(x),
|
left: uint32(region.Min.X),
|
||||||
top: uint32(y),
|
top: uint32(region.Min.Y),
|
||||||
front: 0,
|
front: 0,
|
||||||
right: uint32(x + width),
|
right: uint32(region.Max.X),
|
||||||
bottom: uint32(y + height),
|
bottom: uint32(region.Max.Y),
|
||||||
back: 1,
|
back: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -115,12 +116,12 @@ func (i *image11) ReadPixels(buf []byte, x, y, width, height int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stride := int(mapped.RowPitch)
|
stride := int(mapped.RowPitch)
|
||||||
src := unsafe.Slice((*byte)(mapped.pData), stride*height)
|
src := unsafe.Slice((*byte)(mapped.pData), stride*region.Dy())
|
||||||
if stride == 4*width {
|
if stride == 4*region.Dx() {
|
||||||
copy(buf, src)
|
copy(buf, src)
|
||||||
} else {
|
} else {
|
||||||
for j := 0; j < height; j++ {
|
for j := 0; j < region.Dy(); j++ {
|
||||||
copy(buf[j*4*width:(j+1)*4*width], src[j*stride:j*stride+4*width])
|
copy(buf[j*4*region.Dx():(j+1)*4*region.Dx()], src[j*stride:j*stride+4*region.Dx()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,13 +133,13 @@ func (i *image11) ReadPixels(buf []byte, x, y, width, height int) error {
|
|||||||
func (i *image11) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
|
func (i *image11) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
i.graphics.deviceContext.UpdateSubresource(unsafe.Pointer(i.texture), 0, &_D3D11_BOX{
|
i.graphics.deviceContext.UpdateSubresource(unsafe.Pointer(i.texture), 0, &_D3D11_BOX{
|
||||||
left: uint32(a.X),
|
left: uint32(a.Region.Min.X),
|
||||||
top: uint32(a.Y),
|
top: uint32(a.Region.Min.Y),
|
||||||
front: 0,
|
front: 0,
|
||||||
right: uint32(a.X + a.Width),
|
right: uint32(a.Region.Max.X),
|
||||||
bottom: uint32(a.Y + a.Height),
|
bottom: uint32(a.Region.Max.Y),
|
||||||
back: 1,
|
back: 1,
|
||||||
}, unsafe.Pointer(&a.Pixels[0]), uint32(4*a.Width), 0)
|
}, unsafe.Pointer(&a.Pixels[0]), uint32(4*a.Region.Dx()), 0)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ package directx
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||||
@ -71,7 +72,7 @@ func (*image12) IsInvalidated() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *image12) ReadPixels(buf []byte, x, y, width, height int) error {
|
func (i *image12) ReadPixels(buf []byte, region image.Rectangle) error {
|
||||||
if i.screen {
|
if i.screen {
|
||||||
return errors.New("directx: Pixels cannot be called on the screen")
|
return errors.New("directx: Pixels cannot be called on the screen")
|
||||||
}
|
}
|
||||||
@ -83,8 +84,8 @@ func (i *image12) ReadPixels(buf []byte, x, y, width, height int) error {
|
|||||||
desc := _D3D12_RESOURCE_DESC{
|
desc := _D3D12_RESOURCE_DESC{
|
||||||
Dimension: _D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
Dimension: _D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
||||||
Alignment: 0,
|
Alignment: 0,
|
||||||
Width: uint64(width),
|
Width: uint64(region.Dx()),
|
||||||
Height: uint32(height),
|
Height: uint32(region.Dy()),
|
||||||
DepthOrArraySize: 1,
|
DepthOrArraySize: 1,
|
||||||
MipLevels: 0,
|
MipLevels: 0,
|
||||||
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
|
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||||
@ -126,11 +127,11 @@ func (i *image12) ReadPixels(buf []byte, x, y, width, height int) error {
|
|||||||
i.graphics.needFlushCopyCommandList = true
|
i.graphics.needFlushCopyCommandList = true
|
||||||
i.graphics.copyCommandList.CopyTextureRegion_PlacedFootPrint_SubresourceIndex(
|
i.graphics.copyCommandList.CopyTextureRegion_PlacedFootPrint_SubresourceIndex(
|
||||||
&dst, 0, 0, 0, &src, &_D3D12_BOX{
|
&dst, 0, 0, 0, &src, &_D3D12_BOX{
|
||||||
left: uint32(x),
|
left: uint32(region.Min.X),
|
||||||
top: uint32(y),
|
top: uint32(region.Min.Y),
|
||||||
front: 0,
|
front: 0,
|
||||||
right: uint32(x + width),
|
right: uint32(region.Max.X),
|
||||||
bottom: uint32(y + height),
|
bottom: uint32(region.Max.Y),
|
||||||
back: 1,
|
back: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -139,8 +140,8 @@ func (i *image12) ReadPixels(buf []byte, x, y, width, height int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dstBytes := unsafe.Slice((*byte)(unsafe.Pointer(m)), totalBytes)
|
dstBytes := unsafe.Slice((*byte)(unsafe.Pointer(m)), totalBytes)
|
||||||
for j := 0; j < height; j++ {
|
for j := 0; j < region.Dy(); j++ {
|
||||||
copy(buf[j*width*4:(j+1)*width*4], dstBytes[j*int(layouts.Footprint.RowPitch):])
|
copy(buf[j*region.Dx()*4:(j+1)*region.Dx()*4], dstBytes[j*int(layouts.Footprint.RowPitch):])
|
||||||
}
|
}
|
||||||
|
|
||||||
readingStagingBuffer.Unmap(0, nil)
|
readingStagingBuffer.Unmap(0, nil)
|
||||||
@ -157,30 +158,16 @@ func (i *image12) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
minX := i.width
|
var region image.Rectangle
|
||||||
minY := i.height
|
|
||||||
maxX := 0
|
|
||||||
maxY := 0
|
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
if minX > a.X {
|
region = region.Union(a.Region)
|
||||||
minX = a.X
|
|
||||||
}
|
|
||||||
if minY > a.Y {
|
|
||||||
minY = a.Y
|
|
||||||
}
|
|
||||||
if maxX < a.X+a.Width {
|
|
||||||
maxX = a.X + a.Width
|
|
||||||
}
|
|
||||||
if maxY < a.Y+a.Height {
|
|
||||||
maxY = a.Y + a.Height
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
desc := _D3D12_RESOURCE_DESC{
|
desc := _D3D12_RESOURCE_DESC{
|
||||||
Dimension: _D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
Dimension: _D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
||||||
Alignment: 0,
|
Alignment: 0,
|
||||||
Width: uint64(maxX - minX),
|
Width: uint64(region.Dx()),
|
||||||
Height: uint32(maxY - minY),
|
Height: uint32(region.Dy()),
|
||||||
DepthOrArraySize: 1,
|
DepthOrArraySize: 1,
|
||||||
MipLevels: 0,
|
MipLevels: 0,
|
||||||
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
|
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||||
@ -211,8 +198,8 @@ func (i *image12) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
|
|||||||
|
|
||||||
srcBytes := unsafe.Slice((*byte)(unsafe.Pointer(m)), totalBytes)
|
srcBytes := unsafe.Slice((*byte)(unsafe.Pointer(m)), totalBytes)
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
for j := 0; j < a.Height; j++ {
|
for j := 0; j < a.Region.Dy(); j++ {
|
||||||
copy(srcBytes[((a.Y-minY)+j)*int(layouts.Footprint.RowPitch)+(a.X-minX)*4:], a.Pixels[j*a.Width*4:(j+1)*a.Width*4])
|
copy(srcBytes[((a.Region.Min.Y-region.Min.Y)+j)*int(layouts.Footprint.RowPitch)+(a.Region.Min.X-region.Min.X)*4:], a.Pixels[j*a.Region.Dx()*4:(j+1)*a.Region.Dx()*4])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,12 +215,12 @@ func (i *image12) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
|
|||||||
PlacedFootprint: layouts,
|
PlacedFootprint: layouts,
|
||||||
}
|
}
|
||||||
i.graphics.copyCommandList.CopyTextureRegion_SubresourceIndex_PlacedFootPrint(
|
i.graphics.copyCommandList.CopyTextureRegion_SubresourceIndex_PlacedFootPrint(
|
||||||
&dst, uint32(a.X), uint32(a.Y), 0, &src, &_D3D12_BOX{
|
&dst, uint32(a.Region.Min.X), uint32(a.Region.Min.Y), 0, &src, &_D3D12_BOX{
|
||||||
left: uint32(a.X - minX),
|
left: uint32(a.Region.Min.X - region.Min.X),
|
||||||
top: uint32(a.Y - minY),
|
top: uint32(a.Region.Min.Y - region.Min.Y),
|
||||||
front: 0,
|
front: 0,
|
||||||
right: uint32(a.X - minX + a.Width),
|
right: uint32(a.Region.Max.X - region.Min.X),
|
||||||
bottom: uint32(a.Y - minY + a.Height),
|
bottom: uint32(a.Region.Max.Y - region.Min.Y),
|
||||||
back: 1,
|
back: 1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
package graphicsdriver
|
package graphicsdriver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"image"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||||
)
|
)
|
||||||
@ -65,7 +67,7 @@ type Image interface {
|
|||||||
ID() ImageID
|
ID() ImageID
|
||||||
Dispose()
|
Dispose()
|
||||||
IsInvalidated() bool
|
IsInvalidated() bool
|
||||||
ReadPixels(buf []byte, x, y, width, height int) error
|
ReadPixels(buf []byte, region image.Rectangle) error
|
||||||
WritePixels(args []*WritePixelsArgs) error
|
WritePixels(args []*WritePixelsArgs) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,10 +75,7 @@ type ImageID int
|
|||||||
|
|
||||||
type WritePixelsArgs struct {
|
type WritePixelsArgs struct {
|
||||||
Pixels []byte
|
Pixels []byte
|
||||||
X int
|
Region image.Rectangle
|
||||||
Y int
|
|
||||||
Width int
|
|
||||||
Height int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Shader interface {
|
type Shader interface {
|
||||||
|
@ -16,6 +16,7 @@ package metal
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"math"
|
"math"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
@ -815,17 +816,17 @@ func (i *Image) syncTexture() {
|
|||||||
cb.WaitUntilCompleted()
|
cb.WaitUntilCompleted()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) ReadPixels(buf []byte, x, y, width, height int) error {
|
func (i *Image) ReadPixels(buf []byte, region image.Rectangle) error {
|
||||||
if got, want := len(buf), 4*width*height; got != want {
|
if got, want := len(buf), 4*region.Dx()*region.Dy(); got != want {
|
||||||
return fmt.Errorf("metal: len(buf) must be %d but %d at ReadPixels", want, got)
|
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()
|
||||||
|
|
||||||
i.texture.GetBytes(&buf[0], uintptr(4*width), mtl.Region{
|
i.texture.GetBytes(&buf[0], uintptr(4*region.Dx()), mtl.Region{
|
||||||
Origin: mtl.Origin{X: x, Y: y},
|
Origin: mtl.Origin{X: region.Min.X, Y: region.Min.Y},
|
||||||
Size: mtl.Size{Width: width, Height: height, Depth: 1},
|
Size: mtl.Size{Width: region.Dx(), Height: region.Dy(), Depth: 1},
|
||||||
}, 0)
|
}, 0)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -836,26 +837,10 @@ func (i *Image) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
|
|||||||
g.flushRenderCommandEncoderIfNeeded()
|
g.flushRenderCommandEncoderIfNeeded()
|
||||||
|
|
||||||
// Calculate the smallest texture size to include all the values in args.
|
// Calculate the smallest texture size to include all the values in args.
|
||||||
minX := math.MaxInt32
|
var region image.Rectangle
|
||||||
minY := math.MaxInt32
|
|
||||||
maxX := 0
|
|
||||||
maxY := 0
|
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
if minX > a.X {
|
region = region.Union(a.Region)
|
||||||
minX = a.X
|
|
||||||
}
|
|
||||||
if maxX < a.X+a.Width {
|
|
||||||
maxX = a.X + a.Width
|
|
||||||
}
|
|
||||||
if minY > a.Y {
|
|
||||||
minY = a.Y
|
|
||||||
}
|
|
||||||
if maxY < a.Y+a.Height {
|
|
||||||
maxY = a.Y + a.Height
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
w := maxX - minX
|
|
||||||
h := maxY - minY
|
|
||||||
|
|
||||||
// Use a temporary texture to send pixels asynchronously, whichever the memory is shared (e.g., iOS) or
|
// Use a temporary texture to send pixels asynchronously, whichever the memory is shared (e.g., iOS) or
|
||||||
// managed (e.g., macOS). A temporary texture is needed since ReplaceRegion tries to sync the pixel
|
// managed (e.g., macOS). A temporary texture is needed since ReplaceRegion tries to sync the pixel
|
||||||
@ -864,8 +849,8 @@ func (i *Image) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
|
|||||||
td := mtl.TextureDescriptor{
|
td := mtl.TextureDescriptor{
|
||||||
TextureType: mtl.TextureType2D,
|
TextureType: mtl.TextureType2D,
|
||||||
PixelFormat: mtl.PixelFormatRGBA8UNorm,
|
PixelFormat: mtl.PixelFormatRGBA8UNorm,
|
||||||
Width: w,
|
Width: region.Dx(),
|
||||||
Height: h,
|
Height: region.Dy(),
|
||||||
StorageMode: storageMode,
|
StorageMode: storageMode,
|
||||||
Usage: mtl.TextureUsageShaderRead | mtl.TextureUsageRenderTarget,
|
Usage: mtl.TextureUsageShaderRead | mtl.TextureUsageRenderTarget,
|
||||||
}
|
}
|
||||||
@ -874,9 +859,9 @@ func (i *Image) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
|
|||||||
|
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
t.ReplaceRegion(mtl.Region{
|
t.ReplaceRegion(mtl.Region{
|
||||||
Origin: mtl.Origin{X: a.X - minX, Y: a.Y - minY, Z: 0},
|
Origin: mtl.Origin{X: a.Region.Min.X - region.Min.X, Y: a.Region.Min.Y - region.Min.Y, Z: 0},
|
||||||
Size: mtl.Size{Width: a.Width, Height: a.Height, Depth: 1},
|
Size: mtl.Size{Width: a.Region.Dx(), Height: a.Region.Dy(), Depth: 1},
|
||||||
}, 0, unsafe.Pointer(&a.Pixels[0]), 4*a.Width)
|
}, 0, unsafe.Pointer(&a.Pixels[0]), 4*a.Region.Dx())
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.cb == (mtl.CommandBuffer{}) {
|
if g.cb == (mtl.CommandBuffer{}) {
|
||||||
@ -884,9 +869,9 @@ func (i *Image) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
|
|||||||
}
|
}
|
||||||
bce := g.cb.MakeBlitCommandEncoder()
|
bce := g.cb.MakeBlitCommandEncoder()
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
so := mtl.Origin{X: a.X - minX, Y: a.Y - minY, Z: 0}
|
so := mtl.Origin{X: a.Region.Min.X - region.Min.X, Y: a.Region.Min.Y - region.Min.Y, Z: 0}
|
||||||
ss := mtl.Size{Width: a.Width, Height: a.Height, Depth: 1}
|
ss := mtl.Size{Width: a.Region.Dx(), Height: a.Region.Dy(), Depth: 1}
|
||||||
do := mtl.Origin{X: a.X, Y: a.Y, Z: 0}
|
do := mtl.Origin{X: a.Region.Min.X, Y: a.Region.Min.Y, Z: 0}
|
||||||
bce.CopyFromTexture(t, 0, 0, so, ss, i.texture, 0, 0, do)
|
bce.CopyFromTexture(t, 0, 0, so, ss, i.texture, 0, 0, do)
|
||||||
}
|
}
|
||||||
bce.EndEncoding()
|
bce.EndEncoding()
|
||||||
|
@ -17,6 +17,7 @@ package opengl
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||||
@ -242,14 +243,18 @@ func (c *context) newTexture(width, height int) (textureNative, error) {
|
|||||||
return textureNative(t), nil
|
return textureNative(t), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) framebufferPixels(buf []byte, f *framebuffer, x, y, width, height int) error {
|
func (c *context) framebufferPixels(buf []byte, f *framebuffer, region image.Rectangle) error {
|
||||||
if got, want := len(buf), 4*width*height; got != want {
|
if got, want := len(buf), 4*region.Dx()*region.Dy(); got != want {
|
||||||
return fmt.Errorf("opengl: len(buf) must be %d but was %d at framebufferPixels", got, want)
|
return fmt.Errorf("opengl: len(buf) must be %d but was %d at framebufferPixels", got, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ctx.Flush()
|
c.ctx.Flush()
|
||||||
c.bindFramebuffer(f.native)
|
c.bindFramebuffer(f.native)
|
||||||
c.ctx.ReadPixels(buf, int32(x), int32(y), int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE)
|
x := int32(region.Min.X)
|
||||||
|
y := int32(region.Min.Y)
|
||||||
|
width := int32(region.Dx())
|
||||||
|
height := int32(region.Dy())
|
||||||
|
c.ctx.ReadPixels(buf, x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ package opengl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"image"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||||
@ -71,11 +72,11 @@ func (i *Image) setViewport() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) ReadPixels(buf []byte, x, y, width, height int) error {
|
func (i *Image) ReadPixels(buf []byte, region image.Rectangle) error {
|
||||||
if err := i.ensureFramebuffer(); err != nil {
|
if err := i.ensureFramebuffer(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := i.graphics.context.framebufferPixels(buf, i.framebuffer, x, y, width, height); err != nil {
|
if err := i.graphics.context.framebufferPixels(buf, i.framebuffer, region); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -147,7 +148,11 @@ func (i *Image) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
|
|||||||
|
|
||||||
i.graphics.context.bindTexture(i.texture)
|
i.graphics.context.bindTexture(i.texture)
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
i.graphics.context.ctx.TexSubImage2D(gl.TEXTURE_2D, 0, int32(a.X), int32(a.Y), int32(a.Width), int32(a.Height), gl.RGBA, gl.UNSIGNED_BYTE, a.Pixels)
|
x := int32(a.Region.Min.X)
|
||||||
|
y := int32(a.Region.Min.Y)
|
||||||
|
width := int32(a.Region.Dx())
|
||||||
|
height := int32(a.Region.Dy())
|
||||||
|
i.graphics.context.ctx.TexSubImage2D(gl.TEXTURE_2D, 0, x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, a.Pixels)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -282,12 +282,12 @@ func (i *Image) WritePixels(pixels []byte, region image.Rectangle) {
|
|||||||
theImages.makeStaleIfDependingOn(i)
|
theImages.makeStaleIfDependingOn(i)
|
||||||
|
|
||||||
if pixels != nil {
|
if pixels != nil {
|
||||||
i.image.WritePixels(pixels, region.Min.X, region.Min.Y, region.Dx(), region.Dy())
|
i.image.WritePixels(pixels, region)
|
||||||
} else {
|
} else {
|
||||||
// TODO: When pixels == nil, we don't have to care the pixel state there. In such cases, the image
|
// TODO: When pixels == nil, we don't have to care the pixel state there. In such cases, the image
|
||||||
// accepts only WritePixels and not Fill or DrawTriangles.
|
// accepts only WritePixels and not Fill or DrawTriangles.
|
||||||
// TODO: Separate Image struct into two: images for WritePixels-only, and the others.
|
// TODO: Separate Image struct into two: images for WritePixels-only, and the others.
|
||||||
i.image.WritePixels(make([]byte, 4*region.Dx()*region.Dy()), region.Min.X, region.Min.Y, region.Dx(), region.Dy())
|
i.image.WritePixels(make([]byte, 4*region.Dx()*region.Dy()), region)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even if the image is already stale, call makeStale to extend the stale region.
|
// Even if the image is already stale, call makeStale to extend the stale region.
|
||||||
@ -429,7 +429,7 @@ func (i *Image) readPixelsFromGPUIfNeeded(graphicsDriver graphicsdriver.Graphics
|
|||||||
|
|
||||||
func (i *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byte, region image.Rectangle) error {
|
func (i *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byte, region image.Rectangle) error {
|
||||||
if AlwaysReadPixelsFromGPU() {
|
if AlwaysReadPixelsFromGPU() {
|
||||||
if err := i.image.ReadPixels(graphicsDriver, pixels, region.Min.X, region.Min.Y, region.Dx(), region.Dy()); err != nil {
|
if err := i.image.ReadPixels(graphicsDriver, pixels, region); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -494,7 +494,7 @@ func (i *Image) readPixelsFromGPU(graphicsDriver graphicsdriver.Graphics) error
|
|||||||
pix = make([]byte, 4*r.Dx()*r.Dy())
|
pix = make([]byte, 4*r.Dx()*r.Dy())
|
||||||
i.pixelsCache[r] = pix
|
i.pixelsCache[r] = pix
|
||||||
}
|
}
|
||||||
if err := i.image.ReadPixels(graphicsDriver, pix, r.Min.X, r.Min.Y, r.Dx(), r.Dy()); err != nil {
|
if err := i.image.ReadPixels(graphicsDriver, pix, r); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
i.basePixels.AddOrReplace(pix, r)
|
i.basePixels.AddOrReplace(pix, r)
|
||||||
@ -633,7 +633,7 @@ func (i *Image) restore(graphicsDriver graphicsdriver.Graphics) error {
|
|||||||
pix = make([]byte, 4*r.Dx()*r.Dy())
|
pix = make([]byte, 4*r.Dx()*r.Dy())
|
||||||
i.pixelsCache[r] = pix
|
i.pixelsCache[r] = pix
|
||||||
}
|
}
|
||||||
if err := gimg.ReadPixels(graphicsDriver, pix, r.Min.X, r.Min.Y, r.Dx(), r.Dy()); err != nil {
|
if err := gimg.ReadPixels(graphicsDriver, pix, r); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
i.basePixels.AddOrReplace(pix, r)
|
i.basePixels.AddOrReplace(pix, r)
|
||||||
|
@ -122,7 +122,7 @@ func (pr *pixelsRecords) readPixels(pixels []byte, region image.Rectangle, image
|
|||||||
func (pr *pixelsRecords) apply(img *graphicscommand.Image) {
|
func (pr *pixelsRecords) apply(img *graphicscommand.Image) {
|
||||||
// TODO: Isn't this too heavy? Can we merge the operations?
|
// TODO: Isn't this too heavy? Can we merge the operations?
|
||||||
for _, r := range pr.records {
|
for _, r := range pr.records {
|
||||||
img.WritePixels(r.pix, r.rect.Min.X, r.rect.Min.Y, r.rect.Dx(), r.rect.Dy())
|
img.WritePixels(r.pix, r.rect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user