mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 11:18:54 +01:00
d3d56c076d
CopyPixels is basically Pixels and ReplacePixels, but executed lazily while Pixels reads pixels from GPU immediately. Thanks to this, restorable.Image no longer need to keep pixel data if not needed.
298 lines
7.8 KiB
Go
298 lines
7.8 KiB
Go
// Copyright 2018 The Ebiten Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package shareable_test
|
|
|
|
import (
|
|
"errors"
|
|
"image/color"
|
|
"os"
|
|
"runtime"
|
|
"testing"
|
|
|
|
"github.com/hajimehoshi/ebiten"
|
|
"github.com/hajimehoshi/ebiten/internal/graphics"
|
|
. "github.com/hajimehoshi/ebiten/internal/shareable"
|
|
"github.com/hajimehoshi/ebiten/internal/testflock"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
testflock.Lock()
|
|
defer testflock.Unlock()
|
|
|
|
code := 0
|
|
regularTermination := errors.New("regular termination")
|
|
f := func(screen *ebiten.Image) error {
|
|
code = m.Run()
|
|
return regularTermination
|
|
}
|
|
if err := ebiten.Run(f, 320, 240, 1, "Test"); err != nil && err != regularTermination {
|
|
panic(err)
|
|
}
|
|
os.Exit(code)
|
|
}
|
|
|
|
const bigSize = 2049
|
|
|
|
func TestEnsureNotShared(t *testing.T) {
|
|
// Create img1 and img2 with this size so that the next images are allocated
|
|
// with non-upper-left location.
|
|
img1 := NewImage(bigSize, 100)
|
|
defer img1.Dispose()
|
|
// Ensure img1's region is allocated.
|
|
img1.ReplacePixels(make([]byte, 4*bigSize*100))
|
|
|
|
img2 := NewImage(100, bigSize)
|
|
defer img2.Dispose()
|
|
img2.ReplacePixels(make([]byte, 4*100*bigSize))
|
|
|
|
const size = 32
|
|
|
|
img3 := NewImage(size/2, size/2)
|
|
defer img3.Dispose()
|
|
img3.ReplacePixels(make([]byte, (size/2)*(size/2)*4))
|
|
|
|
img4 := NewImage(size, size)
|
|
defer img4.Dispose()
|
|
|
|
pix := make([]byte, size*size*4)
|
|
for j := 0; j < size; j++ {
|
|
for i := 0; i < size; i++ {
|
|
pix[4*(i+j*size)] = byte(i + j)
|
|
pix[4*(i+j*size)+1] = byte(i + j)
|
|
pix[4*(i+j*size)+2] = byte(i + j)
|
|
pix[4*(i+j*size)+3] = byte(i + j)
|
|
}
|
|
}
|
|
img4.ReplacePixels(pix)
|
|
|
|
const (
|
|
dx0 = size / 4
|
|
dy0 = size / 4
|
|
dx1 = size * 3 / 4
|
|
dy1 = size * 3 / 4
|
|
)
|
|
// img4.ensureNotShared() should be called.
|
|
vs := img3.QuadVertices(0, 0, size/2, size/2, 1, 0, 0, 1, size/4, size/4, 1, 1, 1, 1)
|
|
is := graphics.QuadIndices()
|
|
img4.DrawImage(img3, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
|
want := false
|
|
if got := img4.IsSharedForTesting(); got != want {
|
|
t.Errorf("got: %v, want: %v", got, want)
|
|
}
|
|
|
|
for j := 0; j < size; j++ {
|
|
for i := 0; i < size; i++ {
|
|
r, g, b, a := img4.At(i, j)
|
|
got := color.RGBA{r, g, b, a}
|
|
var want color.RGBA
|
|
if i < dx0 || dx1 <= i || j < dy0 || dy1 <= j {
|
|
c := byte(i + j)
|
|
want = color.RGBA{c, c, c, c}
|
|
}
|
|
if got != want {
|
|
t.Errorf("img4.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check further drawing doesn't cause panic.
|
|
// This bug was fixed by 03dcd948.
|
|
img4.DrawImage(img3, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
|
}
|
|
|
|
func Disabled_TestReshared(t *testing.T) {
|
|
const size = 16
|
|
|
|
img0 := NewImage(size, size)
|
|
defer img0.Dispose()
|
|
img0.ReplacePixels(make([]byte, 4*size*size))
|
|
|
|
img1 := NewImage(size, size)
|
|
defer img1.Dispose()
|
|
img1.ReplacePixels(make([]byte, 4*size*size))
|
|
want := true
|
|
if got := img1.IsSharedForTesting(); got != want {
|
|
t.Errorf("got: %v, want: %v", got, want)
|
|
}
|
|
|
|
img2 := NewImage(size, size)
|
|
defer img2.Dispose()
|
|
pix := make([]byte, 4*size*size)
|
|
for j := 0; j < size; j++ {
|
|
for i := 0; i < size; i++ {
|
|
pix[4*(i+j*size)] = byte(i + j)
|
|
pix[4*(i+j*size)+1] = byte(i + j)
|
|
pix[4*(i+j*size)+2] = byte(i + j)
|
|
pix[4*(i+j*size)+3] = byte(i + j)
|
|
}
|
|
}
|
|
img2.ReplacePixels(pix)
|
|
|
|
img3 := NewVolatileImage(size, size)
|
|
defer img3.Dispose()
|
|
img1.ReplacePixels(make([]byte, 4*size*size))
|
|
want = false
|
|
if got := img3.IsSharedForTesting(); got != want {
|
|
t.Errorf("got: %v, want: %v", got, want)
|
|
}
|
|
|
|
// Use img1 as a render target.
|
|
vs := img2.QuadVertices(0, 0, size, size, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
|
is := graphics.QuadIndices()
|
|
img1.DrawImage(img2, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
|
want = false
|
|
if got := img1.IsSharedForTesting(); got != want {
|
|
t.Errorf("got: %v, want: %v", got, want)
|
|
}
|
|
|
|
// Use img1 as a render source.
|
|
for i := 0; i < MaxCountForShare-1; i++ {
|
|
img0.DrawImage(img1, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
|
want := false
|
|
if got := img1.IsSharedForTesting(); got != want {
|
|
t.Errorf("got: %v, want: %v", got, want)
|
|
}
|
|
}
|
|
|
|
for j := 0; j < size; j++ {
|
|
for i := 0; i < size; i++ {
|
|
want := color.RGBA{byte(i + j), byte(i + j), byte(i + j), byte(i + j)}
|
|
r, g, b, a := img1.At(i, j)
|
|
got := color.RGBA{r, g, b, a}
|
|
if got != want {
|
|
t.Errorf("got: %v, want: %v", got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
img0.DrawImage(img1, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
|
want = true
|
|
if got := img1.IsSharedForTesting(); got != want {
|
|
t.Errorf("got: %v, want: %v", got, want)
|
|
}
|
|
|
|
for j := 0; j < size; j++ {
|
|
for i := 0; i < size; i++ {
|
|
want := color.RGBA{byte(i + j), byte(i + j), byte(i + j), byte(i + j)}
|
|
r, g, b, a := img1.At(i, j)
|
|
got := color.RGBA{r, g, b, a}
|
|
if got != want {
|
|
t.Errorf("got: %v, want: %v", got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Use img3 as a render source. img3 never uses a shared texture.
|
|
for i := 0; i < MaxCountForShare*2; i++ {
|
|
img0.DrawImage(img3, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
|
want := false
|
|
if got := img3.IsSharedForTesting(); got != want {
|
|
t.Errorf("got: %v, want: %v", got, want)
|
|
}
|
|
}
|
|
|
|
runtime.GC()
|
|
}
|
|
|
|
func TestExtend(t *testing.T) {
|
|
const w0, h0 = 100, 100
|
|
img0 := NewImage(w0, h0)
|
|
defer img0.Dispose()
|
|
p0 := make([]byte, 4*w0*h0)
|
|
for i := 0; i < w0*h0; i++ {
|
|
p0[4*i] = byte(i)
|
|
p0[4*i+1] = byte(i)
|
|
p0[4*i+2] = byte(i)
|
|
p0[4*i+3] = byte(i)
|
|
}
|
|
img0.ReplacePixels(p0)
|
|
|
|
const w1, h1 = 1025, 100
|
|
img1 := NewImage(w1, h1)
|
|
defer img1.Dispose()
|
|
p1 := make([]byte, 4*w1*h1)
|
|
for i := 0; i < w1*h1; i++ {
|
|
p1[4*i] = byte(i)
|
|
p1[4*i+1] = byte(i)
|
|
p1[4*i+2] = byte(i)
|
|
p1[4*i+3] = byte(i)
|
|
}
|
|
// Ensure to allocate
|
|
img1.ReplacePixels(p1)
|
|
|
|
for j := 0; j < h0; j++ {
|
|
for i := 0; i < w0; i++ {
|
|
r, g, b, a := img0.At(i, j)
|
|
got := color.RGBA{r, g, b, a}
|
|
c := byte(i + w0*j)
|
|
want := color.RGBA{c, c, c, c}
|
|
if got != want {
|
|
t.Errorf("img0.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
for j := 0; j < h1; j++ {
|
|
for i := 0; i < w1; i++ {
|
|
r, g, b, a := img1.At(i, j)
|
|
got := color.RGBA{r, g, b, a}
|
|
c := byte(i + w1*j)
|
|
want := color.RGBA{c, c, c, c}
|
|
if got != want {
|
|
t.Errorf("img1.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
img0.Dispose()
|
|
img1.Dispose()
|
|
}
|
|
|
|
func TestReplacePixelsAfterDrawImage(t *testing.T) {
|
|
const w, h = 256, 256
|
|
src := NewImage(w, h)
|
|
defer src.Dispose()
|
|
dst := NewImage(w, h)
|
|
defer dst.Dispose()
|
|
|
|
pix := make([]byte, 4*w*h)
|
|
for i := 0; i < w*h; i++ {
|
|
pix[4*i] = byte(i)
|
|
pix[4*i+1] = byte(i)
|
|
pix[4*i+2] = byte(i)
|
|
pix[4*i+3] = byte(i)
|
|
}
|
|
src.ReplacePixels(pix)
|
|
|
|
vs := src.QuadVertices(0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
|
is := graphics.QuadIndices()
|
|
dst.DrawImage(src, vs, is, nil, graphics.CompositeModeCopy, graphics.FilterNearest, graphics.AddressClampToZero)
|
|
dst.ReplacePixels(pix)
|
|
|
|
for j := 0; j < h; j++ {
|
|
for i := 0; i < w; i++ {
|
|
r, g, b, a := dst.At(i, j)
|
|
got := color.RGBA{r, g, b, a}
|
|
c := byte(i + w*j)
|
|
want := color.RGBA{c, c, c, c}
|
|
if got != want {
|
|
t.Errorf("dst.At(%d, %d): got %v, want: %v", i, j, got, want)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: Add tests to extend shareable image out of the main loop
|