From 4ca3fa5e57213fe1478514ddd66a0056b6aca2da Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Thu, 28 Sep 2023 14:29:55 +0900 Subject: [PATCH] internal/graphicsdriver: replace Region with image.Rectangle (#2791) Closes #2790 --- image.go | 39 ++--- internal/atlas/image.go | 32 ++-- internal/atlas/image_test.go | 114 ++++-------- internal/atlas/shader_test.go | 22 +-- internal/buffered/image.go | 4 +- internal/graphicscommand/command.go | 82 +++++---- internal/graphicscommand/image.go | 2 +- internal/graphicscommand/image_test.go | 31 +--- .../directx/graphics11_windows.go | 8 +- .../directx/pipeline12_windows.go | 8 +- internal/graphicsdriver/graphics.go | 9 +- .../graphicsdriver/metal/graphics_darwin.go | 8 +- internal/graphicsdriver/opengl/graphics.go | 8 +- internal/mipmap/mipmap.go | 11 +- internal/restorable/image.go | 43 ++--- internal/restorable/images_test.go | 163 +++++------------- internal/restorable/shader_test.go | 75 ++------ internal/ui/image.go | 140 ++++----------- 18 files changed, 247 insertions(+), 552 deletions(-) diff --git a/image.go b/image.go index 05ceaa10c..279c33da2 100644 --- a/image.go +++ b/image.go @@ -176,17 +176,6 @@ func (i *Image) adjustedBounds() image.Rectangle { return image.Rect(x, y, x+b.Dx(), y+b.Dy()) } -func (i *Image) adjustedRegion() graphicsdriver.Region { - b := i.Bounds() - x, y := i.adjustPosition(b.Min.X, b.Min.Y) - return graphicsdriver.Region{ - X: float32(x), - Y: float32(y), - Width: float32(b.Dx()), - Height: float32(b.Dy()), - } -} - // DrawImage draws the given image on the image i. // // DrawImage accepts the options. For details, see the document of @@ -272,7 +261,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) { }) } - i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), [graphics.ShaderImageCount]graphicsdriver.Region{img.adjustedRegion()}, shader.shader, i.tmpUniforms, false, canSkipMipmap(geoM, filter), false) + i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, false, canSkipMipmap(geoM, filter), false) } // Vertex represents a vertex passed to DrawTriangles. @@ -517,7 +506,7 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o }) } - i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), [graphics.ShaderImageCount]graphicsdriver.Region{img.adjustedRegion()}, shader.shader, i.tmpUniforms, options.FillRule == EvenOdd, filter != builtinshader.FilterLinear, options.AntiAlias) + i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, options.FillRule == EvenOdd, filter != builtinshader.FilterLinear, options.AntiAlias) } // DrawTrianglesShaderOptions represents options for DrawTrianglesShader. @@ -667,18 +656,18 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader imgs[i] = img.image } - var srcRegions [graphics.ShaderImageCount]graphicsdriver.Region + var srcRegions [graphics.ShaderImageCount]image.Rectangle for i, img := range options.Images { if img == nil { continue } - srcRegions[i] = img.adjustedRegion() + srcRegions[i] = img.adjustedBounds() } i.tmpUniforms = i.tmpUniforms[:0] i.tmpUniforms = shader.appendUniforms(i.tmpUniforms, options.Uniforms) - i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedRegion(), srcRegions, shader.shader, i.tmpUniforms, options.FillRule == EvenOdd, true, options.AntiAlias) + i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, options.FillRule == EvenOdd, true, options.AntiAlias) } // DrawRectShaderOptions represents options for DrawRectShader. @@ -773,20 +762,17 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR imgs[i] = img.image } - var srcRegions [graphics.ShaderImageCount]graphicsdriver.Region + var srcRegions [graphics.ShaderImageCount]image.Rectangle for i, img := range options.Images { if img == nil { if shader.unit == shaderir.Pixels && i == 0 { // Give the source size as pixels only when the unit is pixels so that users can get the source size via imageSrc0Size (#2166). // With the texel mode, the imageSrc0Origin and imageSrc0Size values should be in texels so the source position in pixels would not match. - srcRegions[i] = graphicsdriver.Region{ - Width: float32(width), - Height: float32(height), - } + srcRegions[i] = image.Rect(0, 0, width, height) } continue } - srcRegions[i] = img.adjustedRegion() + srcRegions[i] = img.adjustedBounds() } geoM := options.GeoM @@ -797,14 +783,17 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR cr, cg, cb, ca := options.ColorScale.elements() vs := i.ensureTmpVertices(4 * graphics.VertexFloatCount) - // Do not use srcRegions[0].Width and srcRegions[0].Height as these might be empty. - graphics.QuadVertices(vs, srcRegions[0].X, srcRegions[0].Y, srcRegions[0].X+float32(width), srcRegions[0].Y+float32(height), a, b, c, d, tx, ty, cr, cg, cb, ca) + // Do not use srcRegions[0].Dx() and srcRegions[0].Dy() as these might be empty. + graphics.QuadVertices(vs, + float32(srcRegions[0].Min.X), float32(srcRegions[0].Min.Y), + float32(srcRegions[0].Min.X+width), float32(srcRegions[0].Min.Y+height), + a, b, c, d, tx, ty, cr, cg, cb, ca) is := graphics.QuadIndices() i.tmpUniforms = i.tmpUniforms[:0] i.tmpUniforms = shader.appendUniforms(i.tmpUniforms, options.Uniforms) - i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedRegion(), srcRegions, shader.shader, i.tmpUniforms, false, true, false) + i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, false, true, false) } // SubImage returns an image representing the portion of the image p visible through r. diff --git a/internal/atlas/image.go b/internal/atlas/image.go index 9077f6a65..6811ec8b3 100644 --- a/internal/atlas/image.go +++ b/internal/atlas/image.go @@ -275,14 +275,9 @@ func (i *Image) ensureIsolatedFromSource(backends []*backend) { vs := make([]float32, 4*graphics.VertexFloatCount) graphics.QuadVertices(vs, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } + dr := image.Rect(0, 0, i.width, i.height) - newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, NearestFilterShader, nil, false, true) + newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, false, true) newI.moveTo(i) } @@ -311,13 +306,8 @@ func (i *Image) putOnSourceBackend(graphicsDriver graphicsdriver.Graphics) { vs := make([]float32, 4*graphics.VertexFloatCount) graphics.QuadVertices(vs, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, NearestFilterShader, nil, false, true) + dr := image.Rect(0, 0, i.width, i.height) + newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, false, true) newI.moveTo(i) i.usedAsSourceCount = 0 @@ -349,13 +339,13 @@ func (i *Image) regionWithPadding() image.Rectangle { // 5: Color G // 6: Color B // 7: Color Y -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { backendsM.Lock() defer backendsM.Unlock() i.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd, false) } -func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool, keepOnAtlas bool) { +func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool, keepOnAtlas bool) { if i.disposed { panic("atlas: the drawing target image must not be disposed (DrawTriangles)") } @@ -388,11 +378,10 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ } r := i.regionWithPadding() - dx, dy := float32(r.Min.X), float32(r.Min.Y) // TODO: Check if dstRegion does not to violate the region. + dstRegion = dstRegion.Add(r.Min) - dstRegion.X += dx - dstRegion.Y += dy + dx, dy := float32(r.Min.X), float32(r.Min.Y) var oxf, oyf float32 if srcs[0] != nil { @@ -428,13 +417,12 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ // A source region can be deliberately empty when this is not needed in order to avoid unexpected // performance issue (#1293). - if srcRegions[i].Width == 0 || srcRegions[i].Height == 0 { + if srcRegions[i].Empty() { continue } r := src.regionWithPadding() - srcRegions[i].X += float32(r.Min.X) - srcRegions[i].Y += float32(r.Min.Y) + srcRegions[i] = srcRegions[i].Add(r.Min) } var imgs [graphics.ShaderImageCount]*restorable.Image diff --git a/internal/atlas/image_test.go b/internal/atlas/image_test.go index 4af74dffc..2b54748dd 100644 --- a/internal/atlas/image_test.go +++ b/internal/atlas/image_test.go @@ -102,26 +102,16 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) { // img4.ensureIsolatedFromSource() should be called. vs := quadVertices(size/2, size/2, size/4, size/4, 1) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: size, - Height: size, - } - img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, size, size) + img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) if got, want := img4.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } // img5 is not allocated now, but is allocated at DrawTriangles. vs = quadVertices(0, 0, size/2, size/2, 1) - dr = graphicsdriver.Region{ - X: 0, - Y: 0, - Width: size / 2, - Height: size / 2, - } - img3.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + dr = image.Rect(0, 0, size/2, size/2) + img3.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) if got, want := img3.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -151,7 +141,7 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) { // Check further drawing doesn't cause panic. // This bug was fixed by 03dcd948. vs = quadVertices(0, 0, size/2, size/2, 1) - img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) } func TestReputOnSourceBackend(t *testing.T) { @@ -191,16 +181,11 @@ func TestReputOnSourceBackend(t *testing.T) { // Use img1 as a render target. is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: size, - Height: size, - } + dr := image.Rect(0, 0, size, size) // Render onto img1. The count should not matter. for i := 0; i < 5; i++ { vs := quadVertices(size, size, 0, 0, 1) - img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -212,7 +197,7 @@ func TestReputOnSourceBackend(t *testing.T) { for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ { atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) vs := quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -220,7 +205,7 @@ func TestReputOnSourceBackend(t *testing.T) { // Finally, img1 is on a source backend. atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) vs := quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), true; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -245,7 +230,7 @@ func TestReputOnSourceBackend(t *testing.T) { } vs = quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), true; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -271,7 +256,7 @@ func TestReputOnSourceBackend(t *testing.T) { // Use img1 as a render target again. The count should not matter. for i := 0; i < 5; i++ { vs := quadVertices(size, size, 0, 0, 1) - img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -283,7 +268,7 @@ func TestReputOnSourceBackend(t *testing.T) { atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) img1.WritePixels(make([]byte, 4*size*size), image.Rect(0, 0, size, size)) vs := quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -292,7 +277,7 @@ func TestReputOnSourceBackend(t *testing.T) { // img1 is not on an atlas due to WritePixels. vs = quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -301,7 +286,7 @@ func TestReputOnSourceBackend(t *testing.T) { for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ { atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) vs := quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) if got, want := img3.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -395,13 +380,8 @@ func TestWritePixelsAfterDrawTriangles(t *testing.T) { vs := quadVertices(w, h, 0, 0, 1) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) dst.WritePixels(pix, image.Rect(0, 0, w, h)) pix = make([]byte, 4*w*h) @@ -443,13 +423,8 @@ func TestSmallImages(t *testing.T) { vs := quadVertices(w, h, 0, 0, 1) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) pix = make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil { @@ -491,13 +466,8 @@ func TestLongImages(t *testing.T) { const scale = 120 vs := quadVertices(w, h, 0, 0, scale) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: dstW, - Height: dstH, - } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, dstW, dstH) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) pix = make([]byte, 4*dstW*dstH) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, dstW, dstH)); err != nil { @@ -608,13 +578,8 @@ func TestDisposedAndReputOnSourceBackend(t *testing.T) { // Use src as a render target so that src is not on an atlas. vs := quadVertices(size, size, 0, 0, 1) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: size, - Height: size, - } - src.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, size, size) + src.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) if got, want := src.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -623,7 +588,7 @@ func TestDisposedAndReputOnSourceBackend(t *testing.T) { for i := 0; i < atlas.BaseCountToPutOnSourceBackend/2; i++ { atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) vs := quadVertices(size, size, 0, 0, 1) - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) if got, want := src.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -653,19 +618,14 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) { // Use src as a render target so that src is not on an atlas. vs := quadVertices(size, size, 0, 0, 1) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: size, - Height: size, - } + dr := image.Rect(0, 0, size, size) // Use src2 as a rendering target, and make src2 on a destination backend. // // Call DrawTriangles multiple times. // The number of DrawTriangles doesn't matter as long as these are called in one frame. for i := 0; i < 2; i++ { - src2.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + src2.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) } if got, want := src2.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) @@ -684,7 +644,7 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) { for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ { atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) vs := quadVertices(size, size, 0, 0, 1) - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) if got, want := src2.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -802,23 +762,18 @@ func TestDestinationCountOverflow(t *testing.T) { vs := quadVertices(w, h, 0, 0, 1) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } + dr := image.Rect(0, 0, w, h) // Use dst0 as a destination for a while. for i := 0; i < 31; i++ { - dst0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + dst0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) } // Use dst0 as a source for a while. // As dst0 is used as a destination too many times (31 is a maximum), dst0's backend should never be a source backend. for i := 0; i < 100; i++ { - dst1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{dst0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + dst1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{dst0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) if dst0.IsOnSourceBackendForTesting() { t.Errorf("dst0 cannot be on a source backend: %d", i) @@ -842,14 +797,9 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) { // Use srcs as detinations once. vs := quadVertices(w, h, 0, 0, 1) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } + dr := image.Rect(0, 0, w, h) for _, img := range srcs { - img.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + img.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) } atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) @@ -857,7 +807,7 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) { // Check iterating the registered image works correctly. for i := 0; i < 100; i++ { for _, src := range srcs { - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) } atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) } diff --git a/internal/atlas/shader_test.go b/internal/atlas/shader_test.go index c0d5bb867..18e269cbd 100644 --- a/internal/atlas/shader_test.go +++ b/internal/atlas/shader_test.go @@ -33,20 +33,15 @@ func TestShaderFillTwice(t *testing.T) { vs := quadVertices(w, h, 0, 0, 1) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } + dr := image.Rect(0, 0, w, h) g := ui.GraphicsDriverForTesting() s0 := atlas.NewShader(etesting.ShaderProgramFill(0xff, 0xff, 0xff, 0xff)) - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s0, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s0, nil, false) // Vertices must be recreated (#1755) vs = quadVertices(w, h, 0, 0, 1) s1 := atlas.NewShader(etesting.ShaderProgramFill(0x80, 0x80, 0x80, 0xff)) - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s1, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s1, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(g, pix, image.Rect(0, 0, w, h)); err != nil { @@ -68,17 +63,12 @@ func TestImageDrawTwice(t *testing.T) { vs := quadVertices(w, h, 0, 0, 1) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) // Vertices must be recreated (#1755) vs = quadVertices(w, h, 0, 0, 1) - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil { diff --git a/internal/buffered/image.go b/internal/buffered/image.go index e33f7b7f7..2f2bb6a7f 100644 --- a/internal/buffered/image.go +++ b/internal/buffered/image.go @@ -149,7 +149,7 @@ func (i *Image) writePixelsImpl(pix []byte, region image.Rectangle) { // DrawTriangles draws the src image with the given vertices. // // Copying vertices and indices is the caller's responsibility. -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { for _, src := range srcs { if i == src { panic("buffered: Image.DrawTriangles: source images must be different from the receiver") @@ -172,7 +172,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ i.drawTrianglesImpl(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd) } -func (i *Image) drawTrianglesImpl(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { +func (i *Image) drawTrianglesImpl(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { var imgs [graphics.ShaderImageCount]*atlas.Image for i, img := range srcs { if img == nil { diff --git a/internal/graphicscommand/command.go b/internal/graphicscommand/command.go index 1b889dbaf..24e7240ce 100644 --- a/internal/graphicscommand/command.go +++ b/internal/graphicscommand/command.go @@ -16,6 +16,7 @@ package graphicscommand import ( "fmt" + "image" "math" "strings" "sync/atomic" @@ -111,7 +112,7 @@ func mustUseDifferentVertexBuffer(nextNumVertexFloats int) bool { } // EnqueueDrawTrianglesCommand enqueues a drawing-image command. -func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { +func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { if len(vertices) > graphics.MaxVertexFloatsCount { panic(fmt.Sprintf("graphicscommand: len(vertices) must equal to or less than %d but was %d", graphics.MaxVertexFloatsCount, len(vertices))) } @@ -662,7 +663,23 @@ func roundUpPower2(x int) int { return p2 } -func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shader, dst *Image, srcs [graphics.ShaderImageCount]*Image, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region) []uint32 { +type rectangleF32 struct { + x float32 + y float32 + width float32 + height float32 +} + +func imageRectangleToRectangleF32(r image.Rectangle) rectangleF32 { + return rectangleF32{ + x: float32(r.Min.X), + y: float32(r.Min.Y), + width: float32(r.Dx()), + height: float32(r.Dy()), + } +} + +func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shader, dst *Image, srcs [graphics.ShaderImageCount]*Image, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle) []uint32 { origUniforms := uniforms uniforms = q.uint32sBuffer.alloc(len(origUniforms) + graphics.PreservedUniformUint32Count) copy(uniforms[graphics.PreservedUniformUint32Count:], origUniforms) @@ -706,53 +723,58 @@ func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shade uniforms[9] = 0 } + dr := imageRectangleToRectangleF32(dstRegion) if shader.unit() == shaderir.Texels { - dstRegion.X /= float32(dw) - dstRegion.Y /= float32(dh) - dstRegion.Width /= float32(dw) - dstRegion.Height /= float32(dh) + dr.x /= float32(dw) + dr.y /= float32(dh) + dr.width /= float32(dw) + dr.height /= float32(dh) } // Set the destination region origin. - uniforms[10] = math.Float32bits(dstRegion.X) - uniforms[11] = math.Float32bits(dstRegion.Y) + uniforms[10] = math.Float32bits(dr.x) + uniforms[11] = math.Float32bits(dr.y) // Set the destination region size. - uniforms[12] = math.Float32bits(dstRegion.Width) - uniforms[13] = math.Float32bits(dstRegion.Height) + uniforms[12] = math.Float32bits(dr.width) + uniforms[13] = math.Float32bits(dr.height) + var srs [graphics.ShaderImageCount]rectangleF32 + for i, r := range srcRegions { + srs[i] = imageRectangleToRectangleF32(r) + } if shader.unit() == shaderir.Texels { for i, src := range srcs { if src == nil { continue } w, h := src.InternalSize() - srcRegions[i].X /= float32(w) - srcRegions[i].Y /= float32(h) - srcRegions[i].Width /= float32(w) - srcRegions[i].Height /= float32(h) + srs[i].x /= float32(w) + srs[i].y /= float32(h) + srs[i].width /= float32(w) + srs[i].height /= float32(h) } } // Set the source region origins. - uniforms[14] = math.Float32bits(srcRegions[0].X) - uniforms[15] = math.Float32bits(srcRegions[0].Y) - uniforms[16] = math.Float32bits(srcRegions[1].X) - uniforms[17] = math.Float32bits(srcRegions[1].Y) - uniforms[18] = math.Float32bits(srcRegions[2].X) - uniforms[19] = math.Float32bits(srcRegions[2].Y) - uniforms[20] = math.Float32bits(srcRegions[3].X) - uniforms[21] = math.Float32bits(srcRegions[3].Y) + uniforms[14] = math.Float32bits(srs[0].x) + uniforms[15] = math.Float32bits(srs[0].y) + uniforms[16] = math.Float32bits(srs[1].x) + uniforms[17] = math.Float32bits(srs[1].y) + uniforms[18] = math.Float32bits(srs[2].x) + uniforms[19] = math.Float32bits(srs[2].y) + uniforms[20] = math.Float32bits(srs[3].x) + uniforms[21] = math.Float32bits(srs[3].y) // Set the source region sizes. - uniforms[22] = math.Float32bits(srcRegions[0].Width) - uniforms[23] = math.Float32bits(srcRegions[0].Height) - uniforms[24] = math.Float32bits(srcRegions[1].Width) - uniforms[25] = math.Float32bits(srcRegions[1].Height) - uniforms[26] = math.Float32bits(srcRegions[2].Width) - uniforms[27] = math.Float32bits(srcRegions[2].Height) - uniforms[28] = math.Float32bits(srcRegions[3].Width) - uniforms[29] = math.Float32bits(srcRegions[3].Height) + uniforms[22] = math.Float32bits(srs[0].width) + uniforms[23] = math.Float32bits(srs[0].height) + uniforms[24] = math.Float32bits(srs[1].width) + uniforms[25] = math.Float32bits(srs[1].height) + uniforms[26] = math.Float32bits(srs[2].width) + uniforms[27] = math.Float32bits(srs[2].height) + uniforms[28] = math.Float32bits(srs[3].width) + uniforms[29] = math.Float32bits(srs[3].height) // Set the projection matrix. uniforms[30] = math.Float32bits(2 / float32(dw)) diff --git a/internal/graphicscommand/image.go b/internal/graphicscommand/image.go index 3780779d5..662ec41d2 100644 --- a/internal/graphicscommand/image.go +++ b/internal/graphicscommand/image.go @@ -147,7 +147,7 @@ func (i *Image) InternalSize() (int, int) { // // If the source image is not specified, i.e., src is nil and there is no image in the uniform variables, the // elements for the source image are not used. -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { for _, src := range srcs { if src == nil { continue diff --git a/internal/graphicscommand/image_test.go b/internal/graphicscommand/image_test.go index 4d76db75f..c4be518e0 100644 --- a/internal/graphicscommand/image_test.go +++ b/internal/graphicscommand/image_test.go @@ -58,13 +58,8 @@ func TestClear(t *testing.T) { vs := quadVertices(w/2, h/2) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, nearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), []graphicsdriver.PixelsArgs{ @@ -94,14 +89,9 @@ func TestWritePixelsPartAfterDrawTriangles(t *testing.T) { dst := graphicscommand.NewImage(w, h, false) vs := quadVertices(w/2, h/2) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, nearestFilterShader, nil, false) - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, nearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, false) dst.WritePixels(make([]byte, 4), image.Rect(0, 0, 1, 1)) // TODO: Check the result. @@ -113,17 +103,12 @@ func TestShader(t *testing.T) { dst := graphicscommand.NewImage(w, h, false) vs := quadVertices(w, h) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, nearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, false) g := ui.GraphicsDriverForTesting() s := graphicscommand.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff)) - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(g, []graphicsdriver.PixelsArgs{ diff --git a/internal/graphicsdriver/directx/graphics11_windows.go b/internal/graphicsdriver/directx/graphics11_windows.go index 1622713cf..8f301f7f8 100644 --- a/internal/graphicsdriver/directx/graphics11_windows.go +++ b/internal/graphicsdriver/directx/graphics11_windows.go @@ -578,10 +578,10 @@ func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphic for _, dstRegion := range dstRegions { g.deviceContext.RSSetScissorRects([]_D3D11_RECT{ { - left: int32(dstRegion.Region.X), - top: int32(dstRegion.Region.Y), - right: int32(dstRegion.Region.X + dstRegion.Region.Width), - bottom: int32(dstRegion.Region.Y + dstRegion.Region.Height), + left: int32(dstRegion.Region.Min.X), + top: int32(dstRegion.Region.Min.Y), + right: int32(dstRegion.Region.Max.X), + bottom: int32(dstRegion.Region.Max.Y), }, }) diff --git a/internal/graphicsdriver/directx/pipeline12_windows.go b/internal/graphicsdriver/directx/pipeline12_windows.go index f54189b37..b180d824a 100644 --- a/internal/graphicsdriver/directx/pipeline12_windows.go +++ b/internal/graphicsdriver/directx/pipeline12_windows.go @@ -296,10 +296,10 @@ func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D for _, dstRegion := range dstRegions { commandList.RSSetScissorRects([]_D3D12_RECT{ { - left: int32(dstRegion.Region.X), - top: int32(dstRegion.Region.Y), - right: int32(dstRegion.Region.X + dstRegion.Region.Width), - bottom: int32(dstRegion.Region.Y + dstRegion.Region.Height), + left: int32(dstRegion.Region.Min.X), + top: int32(dstRegion.Region.Min.Y), + right: int32(dstRegion.Region.Max.X), + bottom: int32(dstRegion.Region.Max.Y), }, }) if evenOdd { diff --git a/internal/graphicsdriver/graphics.go b/internal/graphicsdriver/graphics.go index ab9191e89..18750ddd1 100644 --- a/internal/graphicsdriver/graphics.go +++ b/internal/graphicsdriver/graphics.go @@ -21,15 +21,8 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/shaderir" ) -type Region struct { - X float32 - Y float32 - Width float32 - Height float32 -} - type DstRegion struct { - Region Region + Region image.Rectangle IndexCount int } diff --git a/internal/graphicsdriver/metal/graphics_darwin.go b/internal/graphicsdriver/metal/graphics_darwin.go index 8dd256c45..cb65f0a35 100644 --- a/internal/graphicsdriver/metal/graphics_darwin.go +++ b/internal/graphicsdriver/metal/graphics_darwin.go @@ -561,10 +561,10 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs for _, dstRegion := range dstRegions { g.rce.SetScissorRect(mtl.ScissorRect{ - X: int(dstRegion.Region.X), - Y: int(dstRegion.Region.Y), - Width: int(dstRegion.Region.Width), - Height: int(dstRegion.Region.Height), + X: dstRegion.Region.Min.X, + Y: dstRegion.Region.Min.Y, + Width: dstRegion.Region.Dx(), + Height: dstRegion.Region.Dy(), }) if evenOdd { diff --git a/internal/graphicsdriver/opengl/graphics.go b/internal/graphicsdriver/opengl/graphics.go index 87304c47e..6db68678d 100644 --- a/internal/graphicsdriver/opengl/graphics.go +++ b/internal/graphicsdriver/opengl/graphics.go @@ -251,10 +251,10 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics. for _, dstRegion := range dstRegions { g.context.ctx.Scissor( - int32(dstRegion.Region.X), - int32(dstRegion.Region.Y), - int32(dstRegion.Region.Width), - int32(dstRegion.Region.Height), + int32(dstRegion.Region.Min.X), + int32(dstRegion.Region.Min.Y), + int32(dstRegion.Region.Dx()), + int32(dstRegion.Region.Dy()), ) if evenOdd { g.context.ctx.Clear(gl.STENCIL_BUFFER_BIT) diff --git a/internal/mipmap/mipmap.go b/internal/mipmap/mipmap.go index 7e8feadda..57e6a9b20 100644 --- a/internal/mipmap/mipmap.go +++ b/internal/mipmap/mipmap.go @@ -66,7 +66,7 @@ func (m *Mipmap) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byt return m.orig.ReadPixels(graphicsDriver, pixels, region) } -func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool) { +func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool) { if len(indices) == 0 { return } @@ -187,13 +187,8 @@ func (m *Mipmap) level(level int) *buffered.Image { s := buffered.NewImage(w2, h2, m.imageType) - dstRegion := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: float32(w2), - Height: float32(h2), - } - s.DrawTriangles([graphics.ShaderImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]graphicsdriver.Region{}, shader.shader, nil, false) + dstRegion := image.Rect(0, 0, w2, h2) + s.DrawTriangles([graphics.ShaderImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]image.Rectangle{}, shader.shader, nil, false) m.setImg(level, s) return m.imgs[level] diff --git a/internal/restorable/image.go b/internal/restorable/image.go index 00e1fe533..0c6eb40b5 100644 --- a/internal/restorable/image.go +++ b/internal/restorable/image.go @@ -17,7 +17,6 @@ package restorable import ( "fmt" "image" - "math" "github.com/hajimehoshi/ebiten/v2/internal/graphics" "github.com/hajimehoshi/ebiten/v2/internal/graphicscommand" @@ -77,8 +76,8 @@ type drawTrianglesHistoryItem struct { vertices []float32 indices []uint16 blend graphicsdriver.Blend - dstRegion graphicsdriver.Region - srcRegions [graphics.ShaderImageCount]graphicsdriver.Region + dstRegion image.Rectangle + srcRegions [graphics.ShaderImageCount]image.Rectangle shader *Shader uniforms []uint32 evenOdd bool @@ -180,13 +179,8 @@ func (i *Image) Extend(width, height int) *Image { sw, sh := i.image.InternalSize() vs := quadVertices(0, 0, float32(sw), float32(sh), 0, 0, float32(sw), float32(sh), 1, 1, 1, 1) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: float32(sw), - Height: float32(sh), - } - newImg.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, NearestFilterShader, nil, false) + dr := image.Rect(0, 0, sw, sh) + newImg.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, false) i.Dispose() return newImg @@ -205,13 +199,7 @@ func quadVertices(dx0, dy0, dx1, dy1, sx0, sy0, sx1, sy1, cr, cg, cb, ca float32 func clearImage(i *graphicscommand.Image, region image.Rectangle) { vs := quadVertices(float32(region.Min.X), float32(region.Min.Y), float32(region.Max.X), float32(region.Max.Y), 0, 0, 0, 0, 0, 0, 0, 0) is := graphics.QuadIndices() - dstRegion := graphicsdriver.Region{ - X: float32(region.Min.X), - Y: float32(region.Min.Y), - Width: float32(region.Dx()), - Height: float32(region.Dy()), - } - i.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendClear, dstRegion, [graphics.ShaderImageCount]graphicsdriver.Region{}, clearShader.shader, nil, false) + i.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendClear, region, [graphics.ShaderImageCount]image.Rectangle{}, clearShader.shader, nil, false) } // BasePixelsForTesting returns the image's basePixels for testing. @@ -333,7 +321,7 @@ func (i *Image) WritePixels(pixels []byte, region image.Rectangle) { // 5: Color G // 6: Color B // 7: Color Y -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { if len(vertices) == 0 { return } @@ -353,7 +341,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ // Even if the image is already stale, call makeStale to extend the stale region. if srcstale || !needsRestoring() || !i.needsRestoring() || i.stale { - i.makeStale(regionToRectangle(dstRegion)) + i.makeStale(dstRegion) } else { i.appendDrawTrianglesHistory(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd) } @@ -369,7 +357,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ } // appendDrawTrianglesHistory appends a draw-image history item to the image. -func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { +func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool) { if i.stale || !i.needsRestoring() { panic("restorable: an image must not be stale or need restoring at appendDrawTrianglesHistory") } @@ -380,7 +368,7 @@ func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageCount]*Imag // TODO: Would it be possible to merge draw image history items? const maxDrawTrianglesHistoryCount = 1024 if len(i.drawTrianglesHistory)+1 > maxDrawTrianglesHistoryCount { - i.makeStale(regionToRectangle(dstRegion)) + i.makeStale(dstRegion) return } // All images must be resolved and not stale each after frame. @@ -704,22 +692,13 @@ func (i *Image) InternalSize() (int, int) { func (i *Image) appendRegionsForDrawTriangles(regions *[]image.Rectangle) { for _, d := range i.drawTrianglesHistory { - r := regionToRectangle(d.dstRegion) - if r.Empty() { + if d.dstRegion.Empty() { continue } - appendRegionRemovingDuplicates(regions, r) + appendRegionRemovingDuplicates(regions, d.dstRegion) } } -func regionToRectangle(region graphicsdriver.Region) image.Rectangle { - return image.Rect( - int(math.Floor(float64(region.X))), - int(math.Floor(float64(region.Y))), - int(math.Ceil(float64(region.X+region.Width))), - int(math.Ceil(float64(region.Y+region.Height)))) -} - // appendRegionRemovingDuplicates adds a region to a given list of regions, // but removes any duplicate between the newly added region and any existing regions. // diff --git a/internal/restorable/images_test.go b/internal/restorable/images_test.go index b668dafa2..8ecbbb3a1 100644 --- a/internal/restorable/images_test.go +++ b/internal/restorable/images_test.go @@ -133,13 +133,8 @@ func TestRestoreChain(t *testing.T) { for i := 0; i < num-1; i++ { vs := quadVertices(1, 1, 0, 0) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: 1, - Height: 1, - } - imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, 1, 1) + imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) } if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) @@ -181,16 +176,11 @@ func TestRestoreChain2(t *testing.T) { imgs[8].WritePixels([]byte{clr8.R, clr8.G, clr8.B, clr8.A}, image.Rect(0, 0, w, h)) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - imgs[8].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[7]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) - imgs[9].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[8]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + imgs[8].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[7]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) + imgs[9].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[8]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) for i := 0; i < 7; i++ { - imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) } if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { @@ -230,16 +220,11 @@ func TestRestoreOverrideSource(t *testing.T) { clr1 := color.RGBA{B: 0x01, A: 0xff} img1.WritePixels([]byte{clr0.R, clr0.G, clr0.B, clr0.A}, image.Rect(0, 0, w, h)) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - img2.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) - img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + img2.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img0.WritePixels([]byte{clr1.R, clr1.G, clr1.B, clr1.A}, image.Rect(0, 0, w, h)) - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } @@ -317,30 +302,25 @@ func TestRestoreComplexGraph(t *testing.T) { img0.Dispose() }() is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } + dr := image.Rect(0, 0, w, h) vs := quadVertices(w, h, 0, 0) - img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 1, 0) - img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 1, 0) - img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 2, 0) - img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 0, 0) - img5.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img5.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 0, 0) - img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 1, 0) - img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img4}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img4}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 0, 0) - img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 2, 0) - img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } @@ -432,14 +412,9 @@ func TestRestoreRecursive(t *testing.T) { img0.Dispose() }() is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) - img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } @@ -536,13 +511,8 @@ func TestDrawTrianglesAndWritePixels(t *testing.T) { vs := quadVertices(1, 1, 0, 0) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: 2, - Height: 1, - } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, 2, 1) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img1.WritePixels([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, image.Rect(0, 0, 2, 1)) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { @@ -579,14 +549,9 @@ func TestDispose(t *testing.T) { defer img2.Dispose() is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: 1, - Height: 1, - } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) - img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, 1, 1) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img1.Dispose() if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { @@ -694,13 +659,8 @@ func TestWritePixelsOnly(t *testing.T) { vs := quadVertices(1, 1, 0, 0) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: 1, - Height: 1, - } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, 1, 1) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) img0.WritePixels([]byte{5, 6, 7, 8}, image.Rect(0, 0, 1, 1)) // BasePixelsForTesting is available without GPU accessing. @@ -753,13 +713,8 @@ func TestReadPixelsFromVolatileImage(t *testing.T) { src.WritePixels(pix, image.Rect(0, 0, w, h)) vs := quadVertices(1, 1, 0, 0) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) // Read the pixels. If the implementation is correct, dst tries to read its pixels from GPU due to being // stale. @@ -782,13 +737,8 @@ func TestAllowWritePixelsAfterDrawTriangles(t *testing.T) { vs := quadVertices(w, h, 0, 0) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) dst.WritePixels(make([]byte, 4*w*h), image.Rect(0, 0, w, h)) // WritePixels for a whole image doesn't panic. } @@ -806,13 +756,8 @@ func TestAllowWritePixelsForPartAfterDrawTriangles(t *testing.T) { vs := quadVertices(w, h, 0, 0) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) dst.WritePixels(make([]byte, 4*2*2), image.Rect(0, 0, 2, 2)) // WritePixels for a part of image doesn't panic. @@ -905,13 +850,8 @@ func TestDrawTrianglesAndExtend(t *testing.T) { orig := restorable.NewImage(w, h, restorable.ImageTypeRegular) vs := quadVertices(w, h, 0, 0) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - orig.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + orig.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) extended := orig.Extend(w*2, h*2) // After this, orig is already disposed. result := make([]byte, 4*(w*2)*(h*2)) @@ -960,13 +900,8 @@ func TestMutateSlices(t *testing.T) { vs := quadVertices(w, h, 0, 0) is := make([]uint16, len(graphics.QuadIndices())) copy(is, graphics.QuadIndices()) - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) for i := range vs { vs[i] = 0 } @@ -1157,13 +1092,8 @@ func TestDrawTrianglesAndReadPixels(t *testing.T) { vs := quadVertices(w, h, 0, 0) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: w, - Height: h, - } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil { @@ -1186,13 +1116,8 @@ func TestWritePixelsAndDrawTriangles(t *testing.T) { // Call DrawTriangles at a different region second. vs := quadVertices(1, 1, 1, 0) is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 1, - Y: 0, - Width: 1, - Height: 1, - } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(1, 0, 2, 1) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) // Get the pixels. pix := make([]byte, 4*2*1) diff --git a/internal/restorable/shader_test.go b/internal/restorable/shader_test.go index cb6259a0b..4fd674005 100644 --- a/internal/restorable/shader_test.go +++ b/internal/restorable/shader_test.go @@ -45,13 +45,8 @@ func clearImage(img *restorable.Image, w, h int) { dx1, dy1, sx1, sy1, 0, 0, 0, 0, } is := graphics.QuadIndices() - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: float32(w), - Height: float32(h), - } - img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{emptyImage}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dr := image.Rect(0, 0, w, h) + img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{emptyImage}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, false) } func TestShader(t *testing.T) { @@ -59,13 +54,8 @@ func TestShader(t *testing.T) { defer img.Dispose() s := restorable.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff)) - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: 1, - Height: 1, - } - img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s, nil, false) + dr := image.Rect(0, 0, 1, 1) + img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) @@ -94,13 +84,8 @@ func TestShaderChain(t *testing.T) { s := restorable.NewShader(etesting.ShaderProgramImages(1)) for i := 0; i < num-1; i++ { - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: 1, - Height: 1, - } - imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s, nil, false) + dr := image.Rect(0, 0, 1, 1) + imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, false) } if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { @@ -131,13 +116,8 @@ func TestShaderMultipleSources(t *testing.T) { dst := restorable.NewImage(1, 1, restorable.ImageTypeRegular) s := restorable.NewShader(etesting.ShaderProgramImages(3)) - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: 1, - Height: 1, - } - dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s, nil, false) + dr := image.Rect(0, 0, 1, 1) + dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, false) // Clear one of the sources after DrawTriangles. dst should not be affected. clearImage(srcs[0], 1, 1) @@ -168,31 +148,11 @@ func TestShaderMultipleSourcesOnOneTexture(t *testing.T) { dst := restorable.NewImage(1, 1, restorable.ImageTypeRegular) s := restorable.NewShader(etesting.ShaderProgramImages(3)) - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: 1, - Height: 1, - } - srcRegions := [graphics.ShaderImageCount]graphicsdriver.Region{ - { - X: 0, - Y: 0, - Width: 1, - Height: 1, - }, - { - X: 1, - Y: 0, - Width: 1, - Height: 1, - }, - { - X: 2, - Y: 0, - Width: 1, - Height: 1, - }, + dr := image.Rect(0, 0, 1, 1) + srcRegions := [graphics.ShaderImageCount]image.Rectangle{ + image.Rect(0, 0, 1, 1), + image.Rect(1, 0, 2, 1), + image.Rect(2, 0, 3, 1), } dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, srcRegions, s, nil, false) @@ -218,13 +178,8 @@ func TestShaderDispose(t *testing.T) { defer img.Dispose() s := restorable.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff)) - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: 1, - Height: 1, - } - img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s, nil, false) + dr := image.Rect(0, 0, 1, 1) + img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, false) // Dispose the shader. This should invalidate all the images using this shader i.e., all the images become // stale. diff --git a/internal/ui/image.go b/internal/ui/image.go index d4d12ab4a..30cb4a48a 100644 --- a/internal/ui/image.go +++ b/internal/ui/image.go @@ -76,7 +76,7 @@ func (i *Image) MarkDisposed() { i.modifyCallback = nil } -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool, antialias bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool, antialias bool) { if i.modifyCallback != nil { i.modifyCallback() } @@ -245,13 +245,8 @@ func (i *Image) flushDotsBufferIfNeeded() { i.dotsBuffer = nil srcs := [graphics.ShaderImageCount]*mipmap.Mipmap{whiteImage.mipmap} - dr := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: float32(i.width), - Height: float32(i.height), - } - i.mipmap.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, NearestFilterShader.shader, nil, false, true) + dr := image.Rect(0, 0, i.width, i.height) + i.mipmap.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader.shader, nil, false, true) } func (i *Image) flushBigOffscreenBufferIfNeeded() { @@ -282,13 +277,6 @@ func (i *Image) clear() { } func (i *Image) Fill(r, g, b, a float32, region image.Rectangle) { - dstRegion := graphicsdriver.Region{ - X: float32(region.Min.X), - Y: float32(region.Min.Y), - Width: float32(region.Dx()), - Height: float32(region.Dy()), - } - if len(i.tmpVerticesForFill) < 4*graphics.VertexFloatCount { i.tmpVerticesForFill = make([]float32, 4*graphics.VertexFloatCount) } @@ -302,7 +290,7 @@ func (i *Image) Fill(r, g, b, a float32, region image.Rectangle) { srcs := [graphics.ShaderImageCount]*Image{whiteImage} - i.DrawTriangles(srcs, i.tmpVerticesForFill, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]graphicsdriver.Region{}, NearestFilterShader, nil, false, true, false) + i.DrawTriangles(srcs, i.tmpVerticesForFill, is, graphicsdriver.BlendCopy, region, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, false, true, false) } type bigOffscreenImage struct { @@ -310,7 +298,7 @@ type bigOffscreenImage struct { imageType atlas.ImageType image *Image - region graphicsdriver.Region + region image.Rectangle blend graphicsdriver.Blend dirty bool @@ -334,7 +322,7 @@ func (i *bigOffscreenImage) markDisposed() { i.dirty = false } -func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool, antialias bool) { +func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool, antialias bool) { if i.blend != blend { i.flush() } @@ -347,12 +335,12 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image i.region = r } - if i.region.Width == 0 || i.region.Height == 0 { + if i.region.Empty() { return } if i.image == nil { - i.image = NewImage(int(i.region.Width)*bigOffscreenScale, int(i.region.Height)*bigOffscreenScale, i.imageType) + i.image = NewImage(i.region.Dx()*bigOffscreenScale, i.region.Dy()*bigOffscreenScale, i.imageType) } // Copy the current rendering result to get the correct blending result. @@ -364,40 +352,26 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image // i.tmpVerticesForCopying can be resused as this is sent to DrawTriangles immediately. graphics.QuadVertices( i.tmpVerticesForCopying, - i.region.X, i.region.Y, i.region.X+i.region.Width, i.region.Y+i.region.Height, + float32(i.region.Min.X), float32(i.region.Min.Y), float32(i.region.Max.X), float32(i.region.Max.Y), bigOffscreenScale, 0, 0, bigOffscreenScale, 0, 0, 1, 1, 1, 1) is := graphics.QuadIndices() - dstRegion := graphicsdriver.Region{ - X: 0, - Y: 0, - Width: i.region.Width * bigOffscreenScale, - Height: i.region.Height * bigOffscreenScale, - } - i.image.DrawTriangles(srcs, i.tmpVerticesForCopying, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]graphicsdriver.Region{}, NearestFilterShader, nil, false, true, false) + dstRegion := image.Rect(0, 0, i.region.Dx()*bigOffscreenScale, i.region.Dy()*bigOffscreenScale) + i.image.DrawTriangles(srcs, i.tmpVerticesForCopying, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, false, true, false) } for idx := 0; idx < len(vertices); idx += graphics.VertexFloatCount { - vertices[idx] = (vertices[idx] - i.region.X) * bigOffscreenScale - vertices[idx+1] = (vertices[idx+1] - i.region.Y) * bigOffscreenScale + vertices[idx] = (vertices[idx] - float32(i.region.Min.X)) * bigOffscreenScale + vertices[idx+1] = (vertices[idx+1] - float32(i.region.Min.Y)) * bigOffscreenScale } - // Compute corners in dst coordinate space. - x0 := dstRegion.X - y0 := dstRegion.Y - x1 := dstRegion.X + dstRegion.Width - y1 := dstRegion.Y + dstRegion.Height // Translate to i.region coordinate space, and clamp against region size. - x0 = max(x0-i.region.X, 0) - y0 = max(y0-i.region.Y, 0) - x1 = min(x1-i.region.X, i.region.Width) - y1 = min(y1-i.region.Y, i.region.Height) - dstRegion = graphicsdriver.Region{ - X: x0 * bigOffscreenScale, - Y: y0 * bigOffscreenScale, - Width: (x1 - x0) * bigOffscreenScale, - Height: (y1 - y0) * bigOffscreenScale, - } + dstRegion = dstRegion.Sub(i.region.Min) + dstRegion = dstRegion.Intersect(image.Rect(0, 0, i.region.Dx(), i.region.Dy())) + dstRegion.Min.X *= bigOffscreenScale + dstRegion.Min.Y *= bigOffscreenScale + dstRegion.Max.X *= bigOffscreenScale + dstRegion.Max.Y *= bigOffscreenScale i.image.DrawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd, canSkipMipmap, false) i.dirty = true @@ -422,8 +396,8 @@ func (i *bigOffscreenImage) flush() { // i.tmpVerticesForFlushing can be reused as this is sent to DrawTriangles in this function. graphics.QuadVertices( i.tmpVerticesForFlushing, - 0, 0, i.region.Width*bigOffscreenScale, i.region.Height*bigOffscreenScale, - 1.0/bigOffscreenScale, 0, 0, 1.0/bigOffscreenScale, i.region.X, i.region.Y, + 0, 0, float32(i.region.Dx()*bigOffscreenScale), float32(i.region.Dy()*bigOffscreenScale), + 1.0/bigOffscreenScale, 0, 0, 1.0/bigOffscreenScale, float32(i.region.Min.X), float32(i.region.Min.Y), 1, 1, 1, 1) is := graphics.QuadIndices() dstRegion := i.region @@ -431,13 +405,13 @@ func (i *bigOffscreenImage) flush() { if i.blend != graphicsdriver.BlendSourceOver { blend = graphicsdriver.BlendCopy } - i.orig.DrawTriangles(srcs, i.tmpVerticesForFlushing, is, blend, dstRegion, [graphics.ShaderImageCount]graphicsdriver.Region{}, LinearFilterShader, nil, false, true, false) + i.orig.DrawTriangles(srcs, i.tmpVerticesForFlushing, is, blend, dstRegion, [graphics.ShaderImageCount]image.Rectangle{}, LinearFilterShader, nil, false, true, false) i.image.clear() i.dirty = false } -func (i *bigOffscreenImage) requiredRegion(vertices []float32) graphicsdriver.Region { +func (i *bigOffscreenImage) requiredRegion(vertices []float32) image.Rectangle { minX := float32(i.orig.width) minY := float32(i.orig.height) maxX := float32(0) @@ -460,35 +434,19 @@ func (i *bigOffscreenImage) requiredRegion(vertices []float32) graphicsdriver.Re } // Adjust the granularity of the rectangle. - minX = float32(roundDown16(int(minX))) - minY = float32(roundDown16(int(minY))) - maxX = float32(roundUp16(int(maxX))) - maxY = float32(roundUp16(int(maxY))) + r := image.Rect( + roundDown16(int(minX)), + roundDown16(int(minY)), + roundUp16(int(maxX)), + roundUp16(int(maxY))) + r = r.Intersect(image.Rect(0, 0, i.orig.width, i.orig.height)) - if minX < 0 { - minX = 0 - } - if minY < 0 { - minY = 0 - } - if maxX > float32(i.orig.width) { - maxX = float32(i.orig.width) - } - if maxY > float32(i.orig.height) { - maxY = float32(i.orig.height) - } - - r := graphicsdriver.Region{ - X: minX, - Y: minY, - Width: maxX - minX, - Height: maxY - minY, - } - if r.Width < 0 || r.Height < 0 { + // TODO: Is this check required? + if r.Dx() < 0 || r.Dy() < 0 { return i.region } - return union(r, i.region) + return r.Union(i.region) } func floor(x float32) float32 { @@ -506,37 +464,3 @@ func roundDown16(x int) int { func roundUp16(x int) int { return ((x - 1) & ^(0xf)) + 0x10 } - -func min(x, y float32) float32 { - if x < y { - return x - } - return y -} - -func max(x, y float32) float32 { - if x > y { - return x - } - return y -} - -func union(r0, r1 graphicsdriver.Region) graphicsdriver.Region { - if r0.Width == 0 || r0.Height == 0 { - return r1 - } - if r1.Width == 0 || r1.Height == 0 { - return r0 - } - - x0 := min(r0.X, r1.X) - y0 := min(r0.Y, r1.Y) - x1 := max(r0.X+r0.Width, r1.X+r1.Width) - y1 := max(r0.Y+r0.Height, r1.Y+r1.Height) - return graphicsdriver.Region{ - X: x0, - Y: y0, - Width: x1 - x0, - Height: y1 - y0, - } -}