internal/restorable: refactoring: unify NewScreenFramebufferImage and NewImage

This commit is contained in:
Hajime Hoshi 2022-06-06 09:29:30 +09:00
parent 31fd736ca5
commit 73c893e977
4 changed files with 63 additions and 72 deletions

View File

@ -283,8 +283,11 @@ func (i *Image) ensureIsolated() {
sy0 /= float32(sh) sy0 /= float32(sh)
sx1 /= float32(sw) sx1 /= float32(sw)
sy1 /= float32(sh) sy1 /= float32(sh)
newImg := restorable.NewImage(w, h) typ := restorable.ImageTypeRegular
newImg.SetVolatile(i.volatile) if i.volatile {
typ = restorable.ImageTypeVolatile
}
newImg := restorable.NewImage(w, h, typ)
vs := []float32{ vs := []float32{
dx0, dy0, sx0, sy0, 1, 1, 1, 1, dx0, dy0, sx0, sy0, 1, 1, 1, 1,
dx1, dy0, sx1, sy0, 1, 1, 1, 1, dx1, dy0, sx1, sy0, 1, 1, 1, 1,
@ -757,16 +760,19 @@ func (i *Image) allocate(putOnAtlas bool) {
if i.screen { if i.screen {
// A screen image doesn't have a padding. // A screen image doesn't have a padding.
i.backend = &backend{ i.backend = &backend{
restorable: restorable.NewScreenFramebufferImage(i.width, i.height), restorable: restorable.NewImage(i.width, i.height, restorable.ImageTypeScreenFramebuffer),
} }
return return
} }
if !putOnAtlas || !i.canBePutOnAtlas() { if !putOnAtlas || !i.canBePutOnAtlas() {
i.backend = &backend{ typ := restorable.ImageTypeRegular
restorable: restorable.NewImage(i.width+2*paddingSize, i.height+2*paddingSize), if i.volatile {
typ = restorable.ImageTypeVolatile
}
i.backend = &backend{
restorable: restorable.NewImage(i.width+2*paddingSize, i.height+2*paddingSize, typ),
} }
i.backend.restorable.SetVolatile(i.volatile)
return return
} }
@ -785,11 +791,14 @@ func (i *Image) allocate(putOnAtlas bool) {
size *= 2 size *= 2
} }
typ := restorable.ImageTypeRegular
if i.volatile {
typ = restorable.ImageTypeVolatile
}
b := &backend{ b := &backend{
restorable: restorable.NewImage(size, size), restorable: restorable.NewImage(size, size, typ),
page: packing.NewPage(size, maxSize), page: packing.NewPage(size, maxSize),
} }
b.restorable.SetVolatile(i.volatile)
theBackends = append(theBackends, b) theBackends = append(theBackends, b)
n := b.page.Alloc(i.width+2*paddingSize, i.height+2*paddingSize) n := b.page.Alloc(i.width+2*paddingSize, i.height+2*paddingSize)

View File

@ -149,15 +149,16 @@ func ensureEmptyImage() *Image {
// The returned image is cleared. // The returned image is cleared.
// //
// Note that Dispose is not called automatically. // Note that Dispose is not called automatically.
func NewImage(width, height int) *Image { func NewImage(width, height int, imageType ImageType) *Image {
if !graphicsDriverInitialized { if !graphicsDriverInitialized {
panic("restorable: graphics driver must be ready at NewImage but not") panic("restorable: graphics driver must be ready at NewImage but not")
} }
i := &Image{ i := &Image{
image: graphicscommand.NewImage(width, height, false), image: graphicscommand.NewImage(width, height, imageType == ImageTypeScreenFramebuffer),
width: width, width: width,
height: height, height: height,
imageType: imageType,
} }
clearImage(i.image) clearImage(i.image)
theImages.add(i) theImages.add(i)
@ -201,8 +202,7 @@ func (i *Image) Extend(width, height int) *Image {
panic(fmt.Sprintf("restorable: the original size (%d, %d) cannot be extended to (%d, %d)", i.width, i.height, width, height)) panic(fmt.Sprintf("restorable: the original size (%d, %d) cannot be extended to (%d, %d)", i.width, i.height, width, height))
} }
newImg := NewImage(width, height) newImg := NewImage(width, height, i.imageType)
newImg.SetVolatile(i.imageType == ImageTypeVolatile)
// Use DrawTriangles instead of ReplacePixels because the image i might be stale and not have its pixels // Use DrawTriangles instead of ReplacePixels because the image i might be stale and not have its pixels
// information. // information.
@ -230,23 +230,6 @@ func (i *Image) Extend(width, height int) *Image {
return newImg return newImg
} }
// NewScreenFramebufferImage creates a special image that framebuffer is one for the screen.
//
// The returned image is cleared.
//
// Note that Dispose is not called automatically.
func NewScreenFramebufferImage(width, height int) *Image {
i := &Image{
image: graphicscommand.NewImage(width, height, true),
width: width,
height: height,
imageType: ImageTypeScreenFramebuffer,
}
clearImage(i.image)
theImages.add(i)
return i
}
// quadVertices returns vertices to render a quad. These values are passed to graphicscommand.Image. // quadVertices returns vertices to render a quad. These values are passed to graphicscommand.Image.
func quadVertices(src *Image, dx0, dy0, dx1, dy1, sx0, sy0, sx1, sy1, cr, cg, cb, ca float32) []float32 { func quadVertices(src *Image, dx0, dy0, dx1, dy1, sx0, sy0, sx1, sy1, cr, cg, cb, ca float32) []float32 {
sw, sh := src.InternalSize() sw, sh := src.InternalSize()

View File

@ -57,7 +57,7 @@ func sameColors(c1, c2 color.RGBA, delta int) bool {
} }
func TestRestore(t *testing.T) { func TestRestore(t *testing.T) {
img0 := restorable.NewImage(1, 1) img0 := restorable.NewImage(1, 1, restorable.ImageTypeRegular)
defer img0.Dispose() defer img0.Dispose()
clr0 := color.RGBA{0x00, 0x00, 0x00, 0xff} clr0 := color.RGBA{0x00, 0x00, 0x00, 0xff}
@ -76,7 +76,7 @@ func TestRestore(t *testing.T) {
} }
func TestRestoreWithoutDraw(t *testing.T) { func TestRestoreWithoutDraw(t *testing.T) {
img0 := restorable.NewImage(1024, 1024) img0 := restorable.NewImage(1024, 1024, restorable.ImageTypeRegular)
defer img0.Dispose() defer img0.Dispose()
// If there is no drawing command on img0, img0 is cleared when restored. // If there is no drawing command on img0, img0 is cleared when restored.
@ -126,7 +126,7 @@ func TestRestoreChain(t *testing.T) {
const num = 10 const num = 10
imgs := []*restorable.Image{} imgs := []*restorable.Image{}
for i := 0; i < num; i++ { for i := 0; i < num; i++ {
img := restorable.NewImage(1, 1) img := restorable.NewImage(1, 1, restorable.ImageTypeRegular)
imgs = append(imgs, img) imgs = append(imgs, img)
} }
defer func() { defer func() {
@ -170,7 +170,7 @@ func TestRestoreChain2(t *testing.T) {
) )
imgs := []*restorable.Image{} imgs := []*restorable.Image{}
for i := 0; i < num; i++ { for i := 0; i < num; i++ {
img := restorable.NewImage(w, h) img := restorable.NewImage(w, h, restorable.ImageTypeRegular)
imgs = append(imgs, img) imgs = append(imgs, img)
} }
defer func() { defer func() {
@ -222,10 +222,10 @@ func TestRestoreOverrideSource(t *testing.T) {
w = 1 w = 1
h = 1 h = 1
) )
img0 := restorable.NewImage(w, h) img0 := restorable.NewImage(w, h, restorable.ImageTypeRegular)
img1 := restorable.NewImage(w, h) img1 := restorable.NewImage(w, h, restorable.ImageTypeRegular)
img2 := restorable.NewImage(w, h) img2 := restorable.NewImage(w, h, restorable.ImageTypeRegular)
img3 := restorable.NewImage(w, h) img3 := restorable.NewImage(w, h, restorable.ImageTypeRegular)
defer func() { defer func() {
img3.Dispose() img3.Dispose()
img2.Dispose() img2.Dispose()
@ -307,11 +307,11 @@ func TestRestoreComplexGraph(t *testing.T) {
img0 := newImageFromImage(base) img0 := newImageFromImage(base)
img1 := newImageFromImage(base) img1 := newImageFromImage(base)
img2 := newImageFromImage(base) img2 := newImageFromImage(base)
img3 := restorable.NewImage(w, h) img3 := restorable.NewImage(w, h, restorable.ImageTypeRegular)
img4 := restorable.NewImage(w, h) img4 := restorable.NewImage(w, h, restorable.ImageTypeRegular)
img5 := restorable.NewImage(w, h) img5 := restorable.NewImage(w, h, restorable.ImageTypeRegular)
img6 := restorable.NewImage(w, h) img6 := restorable.NewImage(w, h, restorable.ImageTypeRegular)
img7 := restorable.NewImage(w, h) img7 := restorable.NewImage(w, h, restorable.ImageTypeRegular)
defer func() { defer func() {
img7.Dispose() img7.Dispose()
img6.Dispose() img6.Dispose()
@ -416,7 +416,7 @@ func TestRestoreComplexGraph(t *testing.T) {
func newImageFromImage(rgba *image.RGBA) *restorable.Image { func newImageFromImage(rgba *image.RGBA) *restorable.Image {
s := rgba.Bounds().Size() s := rgba.Bounds().Size()
img := restorable.NewImage(s.X, s.Y) img := restorable.NewImage(s.X, s.Y, restorable.ImageTypeRegular)
img.ReplacePixels(rgba.Pix, nil, 0, 0, s.X, s.Y) img.ReplacePixels(rgba.Pix, nil, 0, 0, s.X, s.Y)
return img return img
} }
@ -433,7 +433,7 @@ func TestRestoreRecursive(t *testing.T) {
base.Pix[3] = 0xff base.Pix[3] = 0xff
img0 := newImageFromImage(base) img0 := newImageFromImage(base)
img1 := restorable.NewImage(w, h) img1 := restorable.NewImage(w, h, restorable.ImageTypeRegular)
defer func() { defer func() {
img1.Dispose() img1.Dispose()
img0.Dispose() img0.Dispose()
@ -484,7 +484,7 @@ func TestRestoreRecursive(t *testing.T) {
} }
func TestReplacePixels(t *testing.T) { func TestReplacePixels(t *testing.T) {
img := restorable.NewImage(17, 31) img := restorable.NewImage(17, 31, restorable.ImageTypeRegular)
defer img.Dispose() defer img.Dispose()
pix := make([]byte, 4*4*4) pix := make([]byte, 4*4*4)
@ -535,7 +535,7 @@ func TestDrawTrianglesAndReplacePixels(t *testing.T) {
base.Pix[3] = 0xff base.Pix[3] = 0xff
img0 := newImageFromImage(base) img0 := newImageFromImage(base)
defer img0.Dispose() defer img0.Dispose()
img1 := restorable.NewImage(2, 1) img1 := restorable.NewImage(2, 1, restorable.ImageTypeRegular)
defer img1.Dispose() defer img1.Dispose()
vs := quadVertices(img0, 1, 1, 0, 0) vs := quadVertices(img0, 1, 1, 0, 0)
@ -616,7 +616,7 @@ func TestReplacePixelsPart(t *testing.T) {
pix[i] = 0xff pix[i] = 0xff
} }
img := restorable.NewImage(4, 4) img := restorable.NewImage(4, 4, restorable.ImageTypeRegular)
// This doesn't make the image stale. Its base pixels are available. // This doesn't make the image stale. Its base pixels are available.
img.ReplacePixels(pix, nil, 1, 1, 2, 2) img.ReplacePixels(pix, nil, 1, 1, 2, 2)
@ -687,9 +687,9 @@ func TestReplacePixelsPart(t *testing.T) {
func TestReplacePixelsOnly(t *testing.T) { func TestReplacePixelsOnly(t *testing.T) {
const w, h = 128, 128 const w, h = 128, 128
img0 := restorable.NewImage(w, h) img0 := restorable.NewImage(w, h, restorable.ImageTypeRegular)
defer img0.Dispose() defer img0.Dispose()
img1 := restorable.NewImage(1, 1) img1 := restorable.NewImage(1, 1, restorable.ImageTypeRegular)
defer img1.Dispose() defer img1.Dispose()
for i := 0; i < w*h; i += 5 { for i := 0; i < w*h; i += 5 {
@ -743,9 +743,8 @@ func TestReplacePixelsOnly(t *testing.T) {
// Issue #793 // Issue #793
func TestReadPixelsFromVolatileImage(t *testing.T) { func TestReadPixelsFromVolatileImage(t *testing.T) {
const w, h = 16, 16 const w, h = 16, 16
dst := restorable.NewImage(w, h) dst := restorable.NewImage(w, h, restorable.ImageTypeVolatile)
dst.SetVolatile(true) src := restorable.NewImage(w, h, restorable.ImageTypeRegular)
src := restorable.NewImage(w, h)
// First, make sure that dst has pixels // First, make sure that dst has pixels
dst.ReplacePixels(make([]byte, 4*w*h), nil, 0, 0, w, h) dst.ReplacePixels(make([]byte, 4*w*h), nil, 0, 0, w, h)
@ -780,8 +779,8 @@ func TestReadPixelsFromVolatileImage(t *testing.T) {
func TestAllowReplacePixelsAfterDrawTriangles(t *testing.T) { func TestAllowReplacePixelsAfterDrawTriangles(t *testing.T) {
const w, h = 16, 16 const w, h = 16, 16
src := restorable.NewImage(w, h) src := restorable.NewImage(w, h, restorable.ImageTypeRegular)
dst := restorable.NewImage(w, h) dst := restorable.NewImage(w, h, restorable.ImageTypeRegular)
vs := quadVertices(src, w, h, 0, 0) vs := quadVertices(src, w, h, 0, 0)
is := graphics.QuadIndices() is := graphics.QuadIndices()
@ -804,8 +803,8 @@ func TestDisallowReplacePixelsForPartAfterDrawTriangles(t *testing.T) {
}() }()
const w, h = 16, 16 const w, h = 16, 16
src := restorable.NewImage(w, h) src := restorable.NewImage(w, h, restorable.ImageTypeRegular)
dst := restorable.NewImage(w, h) dst := restorable.NewImage(w, h, restorable.ImageTypeRegular)
vs := quadVertices(src, w, h, 0, 0) vs := quadVertices(src, w, h, 0, 0)
is := graphics.QuadIndices() is := graphics.QuadIndices()
@ -825,7 +824,7 @@ func TestExtend(t *testing.T) {
} }
const w, h = 16, 16 const w, h = 16, 16
orig := restorable.NewImage(w, h) orig := restorable.NewImage(w, h, restorable.ImageTypeRegular)
pix := make([]byte, 4*w*h) pix := make([]byte, 4*w*h)
for j := 0; j < h; j++ { for j := 0; j < h; j++ {
for i := 0; i < w; i++ { for i := 0; i < w; i++ {
@ -860,7 +859,7 @@ func TestExtend(t *testing.T) {
func TestClearPixels(t *testing.T) { func TestClearPixels(t *testing.T) {
const w, h = 16, 16 const w, h = 16, 16
img := restorable.NewImage(w, h) img := restorable.NewImage(w, h, restorable.ImageTypeRegular)
img.ReplacePixels(make([]byte, 4*4*4), nil, 0, 0, 4, 4) img.ReplacePixels(make([]byte, 4*4*4), nil, 0, 0, 4, 4)
img.ReplacePixels(make([]byte, 4*4*4), nil, 4, 0, 4, 4) img.ReplacePixels(make([]byte, 4*4*4), nil, 4, 0, 4, 4)
img.ClearPixels(0, 0, 4, 4) img.ClearPixels(0, 0, 4, 4)
@ -872,8 +871,8 @@ func TestClearPixels(t *testing.T) {
func TestMutateSlices(t *testing.T) { func TestMutateSlices(t *testing.T) {
const w, h = 16, 16 const w, h = 16, 16
dst := restorable.NewImage(w, h) dst := restorable.NewImage(w, h, restorable.ImageTypeRegular)
src := restorable.NewImage(w, h) src := restorable.NewImage(w, h, restorable.ImageTypeRegular)
pix := make([]byte, 4*w*h) pix := make([]byte, 4*w*h)
for i := 0; i < w*h; i++ { for i := 0; i < w*h; i++ {
pix[4*i] = byte(i) pix[4*i] = byte(i)
@ -926,7 +925,7 @@ func TestMutateSlices(t *testing.T) {
} }
func TestOverlappedPixels(t *testing.T) { func TestOverlappedPixels(t *testing.T) {
dst := restorable.NewImage(3, 3) dst := restorable.NewImage(3, 3, restorable.ImageTypeRegular)
pix0 := make([]byte, 4*2*2) pix0 := make([]byte, 4*2*2)
for j := 0; j < 2; j++ { for j := 0; j < 2; j++ {
@ -1070,7 +1069,7 @@ func TestOverlappedPixels(t *testing.T) {
} }
func TestReplacePixelsWithMask(t *testing.T) { func TestReplacePixelsWithMask(t *testing.T) {
dst := restorable.NewImage(3, 3) dst := restorable.NewImage(3, 3, restorable.ImageTypeRegular)
pix0 := make([]byte, 4*2*2) pix0 := make([]byte, 4*2*2)
for j := 0; j < 2; j++ { for j := 0; j < 2; j++ {

View File

@ -27,7 +27,7 @@ import (
) )
func clearImage(img *restorable.Image, w, h int) { func clearImage(img *restorable.Image, w, h int) {
emptyImage := restorable.NewImage(3, 3) emptyImage := restorable.NewImage(3, 3, restorable.ImageTypeRegular)
defer emptyImage.Dispose() defer emptyImage.Dispose()
dx0 := float32(0) dx0 := float32(0)
@ -55,7 +55,7 @@ func clearImage(img *restorable.Image, w, h int) {
} }
func TestShader(t *testing.T) { func TestShader(t *testing.T) {
img := restorable.NewImage(1, 1) img := restorable.NewImage(1, 1, restorable.ImageTypeRegular)
defer img.Dispose() defer img.Dispose()
s := restorable.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff)) s := restorable.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff))
@ -85,7 +85,7 @@ func TestShaderChain(t *testing.T) {
const num = 10 const num = 10
imgs := []*restorable.Image{} imgs := []*restorable.Image{}
for i := 0; i < num; i++ { for i := 0; i < num; i++ {
img := restorable.NewImage(1, 1) img := restorable.NewImage(1, 1, restorable.ImageTypeRegular)
defer img.Dispose() defer img.Dispose()
imgs = append(imgs, img) imgs = append(imgs, img)
} }
@ -122,13 +122,13 @@ func TestShaderChain(t *testing.T) {
func TestShaderMultipleSources(t *testing.T) { func TestShaderMultipleSources(t *testing.T) {
var srcs [graphics.ShaderImageNum]*restorable.Image var srcs [graphics.ShaderImageNum]*restorable.Image
for i := range srcs { for i := range srcs {
srcs[i] = restorable.NewImage(1, 1) srcs[i] = restorable.NewImage(1, 1, restorable.ImageTypeRegular)
} }
srcs[0].ReplacePixels([]byte{0x40, 0, 0, 0xff}, nil, 0, 0, 1, 1) srcs[0].ReplacePixels([]byte{0x40, 0, 0, 0xff}, nil, 0, 0, 1, 1)
srcs[1].ReplacePixels([]byte{0, 0x80, 0, 0xff}, nil, 0, 0, 1, 1) srcs[1].ReplacePixels([]byte{0, 0x80, 0, 0xff}, nil, 0, 0, 1, 1)
srcs[2].ReplacePixels([]byte{0, 0, 0xc0, 0xff}, nil, 0, 0, 1, 1) srcs[2].ReplacePixels([]byte{0, 0, 0xc0, 0xff}, nil, 0, 0, 1, 1)
dst := restorable.NewImage(1, 1) dst := restorable.NewImage(1, 1, restorable.ImageTypeRegular)
s := restorable.NewShader(etesting.ShaderProgramImages(3)) s := restorable.NewShader(etesting.ShaderProgramImages(3))
var offsets [graphics.ShaderImageNum - 1][2]float32 var offsets [graphics.ShaderImageNum - 1][2]float32
@ -158,7 +158,7 @@ func TestShaderMultipleSources(t *testing.T) {
} }
func TestShaderMultipleSourcesOnOneTexture(t *testing.T) { func TestShaderMultipleSourcesOnOneTexture(t *testing.T) {
src := restorable.NewImage(3, 1) src := restorable.NewImage(3, 1, restorable.ImageTypeRegular)
src.ReplacePixels([]byte{ src.ReplacePixels([]byte{
0x40, 0, 0, 0xff, 0x40, 0, 0, 0xff,
0, 0x80, 0, 0xff, 0, 0x80, 0, 0xff,
@ -166,7 +166,7 @@ func TestShaderMultipleSourcesOnOneTexture(t *testing.T) {
}, nil, 0, 0, 3, 1) }, nil, 0, 0, 3, 1)
srcs := [graphics.ShaderImageNum]*restorable.Image{src, src, src} srcs := [graphics.ShaderImageNum]*restorable.Image{src, src, src}
dst := restorable.NewImage(1, 1) dst := restorable.NewImage(1, 1, restorable.ImageTypeRegular)
s := restorable.NewShader(etesting.ShaderProgramImages(3)) s := restorable.NewShader(etesting.ShaderProgramImages(3))
offsets := [graphics.ShaderImageNum - 1][2]float32{ offsets := [graphics.ShaderImageNum - 1][2]float32{
@ -199,7 +199,7 @@ func TestShaderMultipleSourcesOnOneTexture(t *testing.T) {
} }
func TestShaderDispose(t *testing.T) { func TestShaderDispose(t *testing.T) {
img := restorable.NewImage(1, 1) img := restorable.NewImage(1, 1, restorable.ImageTypeRegular)
defer img.Dispose() defer img.Dispose()
s := restorable.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff)) s := restorable.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff))