mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-01-23 17:32:02 +01:00
restorable: Add Shader (WIP)
This commit is contained in:
parent
9bf24ba545
commit
732f288d20
@ -76,6 +76,8 @@ type drawTrianglesHistoryItem struct {
|
|||||||
mode driver.CompositeMode
|
mode driver.CompositeMode
|
||||||
filter driver.Filter
|
filter driver.Filter
|
||||||
address driver.Address
|
address driver.Address
|
||||||
|
shader *Shader
|
||||||
|
uniforms map[int]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image represents an image that can be restored when GL context is lost.
|
// Image represents an image that can be restored when GL context is lost.
|
||||||
@ -339,6 +341,20 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convertUniformVariables converts the uniform variables for the lower layer (graphicscommand).
|
||||||
|
func convertUniformVariables(uniforms map[int]interface{}) map[int]interface{} {
|
||||||
|
us := map[int]interface{}{}
|
||||||
|
for k, v := range uniforms {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case *Image:
|
||||||
|
us[k] = v.image
|
||||||
|
default:
|
||||||
|
us[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return us
|
||||||
|
}
|
||||||
|
|
||||||
// DrawTriangles draws triangles with the given image.
|
// DrawTriangles draws triangles with the given image.
|
||||||
//
|
//
|
||||||
// The vertex floats are:
|
// The vertex floats are:
|
||||||
@ -355,7 +371,7 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
|||||||
// 9: Color G
|
// 9: Color G
|
||||||
// 10: Color B
|
// 10: Color B
|
||||||
// 11: Color Y
|
// 11: Color Y
|
||||||
func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address) {
|
func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader, uniforms map[int]interface{}) {
|
||||||
if i.priority {
|
if i.priority {
|
||||||
panic("restorable: DrawTriangles cannot be called on a priority image")
|
panic("restorable: DrawTriangles cannot be called on a priority image")
|
||||||
}
|
}
|
||||||
@ -364,16 +380,25 @@ func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16,
|
|||||||
}
|
}
|
||||||
theImages.makeStaleIfDependingOn(i)
|
theImages.makeStaleIfDependingOn(i)
|
||||||
|
|
||||||
if img.stale || img.volatile || i.screen || !needsRestoring() || i.volatile {
|
if (img != nil && (img.stale || img.volatile)) || i.screen || !needsRestoring() || i.volatile {
|
||||||
i.makeStale()
|
i.makeStale()
|
||||||
} else {
|
} else {
|
||||||
i.appendDrawTrianglesHistory(img, vertices, indices, colorm, mode, filter, address)
|
// TODO: Need to copy uniform variables?
|
||||||
|
i.appendDrawTrianglesHistory(img, vertices, indices, colorm, mode, filter, address, shader, uniforms)
|
||||||
}
|
}
|
||||||
i.image.DrawTriangles(img.image, vertices, indices, colorm, mode, filter, address, nil, nil)
|
var s *graphicscommand.Shader
|
||||||
|
if shader != nil {
|
||||||
|
s = shader.shader
|
||||||
|
}
|
||||||
|
var gimg *graphicscommand.Image
|
||||||
|
if img != nil {
|
||||||
|
gimg = img.image
|
||||||
|
}
|
||||||
|
i.image.DrawTriangles(gimg, vertices, indices, colorm, mode, filter, address, s, convertUniformVariables(uniforms))
|
||||||
}
|
}
|
||||||
|
|
||||||
// appendDrawTrianglesHistory appends a draw-image history item to the image.
|
// appendDrawTrianglesHistory appends a draw-image history item to the image.
|
||||||
func (i *Image) appendDrawTrianglesHistory(image *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address) {
|
func (i *Image) appendDrawTrianglesHistory(image *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader, uniforms map[int]interface{}) {
|
||||||
if i.stale || i.volatile || i.screen {
|
if i.stale || i.volatile || i.screen {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -390,6 +415,7 @@ func (i *Image) appendDrawTrianglesHistory(image *Image, vertices []float32, ind
|
|||||||
copy(vs, vertices)
|
copy(vs, vertices)
|
||||||
is := make([]uint16, len(indices))
|
is := make([]uint16, len(indices))
|
||||||
copy(is, indices)
|
copy(is, indices)
|
||||||
|
|
||||||
item := &drawTrianglesHistoryItem{
|
item := &drawTrianglesHistoryItem{
|
||||||
image: image,
|
image: image,
|
||||||
vertices: vs,
|
vertices: vs,
|
||||||
@ -398,6 +424,8 @@ func (i *Image) appendDrawTrianglesHistory(image *Image, vertices []float32, ind
|
|||||||
mode: mode,
|
mode: mode,
|
||||||
filter: filter,
|
filter: filter,
|
||||||
address: address,
|
address: address,
|
||||||
|
shader: shader,
|
||||||
|
uniforms: uniforms,
|
||||||
}
|
}
|
||||||
i.drawTrianglesHistory = append(i.drawTrianglesHistory, item)
|
i.drawTrianglesHistory = append(i.drawTrianglesHistory, item)
|
||||||
}
|
}
|
||||||
@ -479,6 +507,11 @@ func (i *Image) dependsOn(target *Image) bool {
|
|||||||
if c.image == target {
|
if c.image == target {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
for _, v := range c.uniforms {
|
||||||
|
if img, ok := v.(*Image); ok && img == target {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -487,8 +520,15 @@ func (i *Image) dependsOn(target *Image) bool {
|
|||||||
func (i *Image) dependingImages() map[*Image]struct{} {
|
func (i *Image) dependingImages() map[*Image]struct{} {
|
||||||
r := map[*Image]struct{}{}
|
r := map[*Image]struct{}{}
|
||||||
for _, c := range i.drawTrianglesHistory {
|
for _, c := range i.drawTrianglesHistory {
|
||||||
|
if c.image != nil {
|
||||||
r[c.image] = struct{}{}
|
r[c.image] = struct{}{}
|
||||||
}
|
}
|
||||||
|
for _, v := range c.uniforms {
|
||||||
|
if img, ok := v.(*Image); ok {
|
||||||
|
r[img] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,10 +573,19 @@ func (i *Image) restore() error {
|
|||||||
i.basePixels.Apply(gimg)
|
i.basePixels.Apply(gimg)
|
||||||
|
|
||||||
for _, c := range i.drawTrianglesHistory {
|
for _, c := range i.drawTrianglesHistory {
|
||||||
if c.image.hasDependency() {
|
if c.image != nil && c.image.hasDependency() {
|
||||||
panic("restorable: all dependencies must be already resolved but not")
|
panic("restorable: all dependencies must be already resolved but not")
|
||||||
}
|
}
|
||||||
gimg.DrawTriangles(c.image.image, c.vertices, c.indices, c.colorm, c.mode, c.filter, c.address, nil, nil)
|
// TODO: Check the uniform variable's images.
|
||||||
|
var img *graphicscommand.Image
|
||||||
|
if c.image != nil {
|
||||||
|
img = c.image.image
|
||||||
|
}
|
||||||
|
var s *graphicscommand.Shader
|
||||||
|
if c.shader != nil {
|
||||||
|
s = c.shader.shader
|
||||||
|
}
|
||||||
|
gimg.DrawTriangles(img, c.vertices, c.indices, c.colorm, c.mode, c.filter, c.address, s, convertUniformVariables(c.uniforms))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(i.drawTrianglesHistory) > 0 {
|
if len(i.drawTrianglesHistory) > 0 {
|
||||||
|
@ -40,12 +40,14 @@ func EnableRestoringForTesting() {
|
|||||||
// images is a set of Image objects.
|
// images is a set of Image objects.
|
||||||
type images struct {
|
type images struct {
|
||||||
images map[*Image]struct{}
|
images map[*Image]struct{}
|
||||||
|
shaders map[*Shader]struct{}
|
||||||
lastTarget *Image
|
lastTarget *Image
|
||||||
}
|
}
|
||||||
|
|
||||||
// theImages represents the images for the current process.
|
// theImages represents the images for the current process.
|
||||||
var theImages = &images{
|
var theImages = &images{
|
||||||
images: map[*Image]struct{}{},
|
images: map[*Image]struct{}{},
|
||||||
|
shaders: map[*Shader]struct{}{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResolveStaleImages flushes the queued draw commands and resolves
|
// ResolveStaleImages flushes the queued draw commands and resolves
|
||||||
@ -118,12 +120,23 @@ func (i *images) add(img *Image) {
|
|||||||
i.images[img] = struct{}{}
|
i.images[img] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *images) addShader(shader *Shader) {
|
||||||
|
i.shaders[shader] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
// remove removes img from the images.
|
// remove removes img from the images.
|
||||||
func (i *images) remove(img *Image) {
|
func (i *images) remove(img *Image) {
|
||||||
i.makeStaleIfDependingOnImpl(img)
|
i.makeStaleIfDependingOnImpl(img)
|
||||||
delete(i.images, img)
|
delete(i.images, img)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *images) removeShader(shader *Shader) {
|
||||||
|
// TODO: Do we have to make images stale?
|
||||||
|
// However, dependencies are determiend by uniform variables...
|
||||||
|
// ??
|
||||||
|
delete(i.shaders, shader)
|
||||||
|
}
|
||||||
|
|
||||||
// resolveStaleImages resolves stale images.
|
// resolveStaleImages resolves stale images.
|
||||||
func (i *images) resolveStaleImages() error {
|
func (i *images) resolveStaleImages() error {
|
||||||
i.lastTarget = nil
|
i.lastTarget = nil
|
||||||
@ -165,6 +178,15 @@ func (i *images) restore() error {
|
|||||||
panic("restorable: restore cannot be called when restoring is disabled")
|
panic("restorable: restore cannot be called when restoring is disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dispose all the shaders ahead of restoring. A current shader ID and a new shader ID can be duplicated.
|
||||||
|
for s := range i.shaders {
|
||||||
|
s.shader.Dispose()
|
||||||
|
s.shader = nil
|
||||||
|
}
|
||||||
|
for s := range i.shaders {
|
||||||
|
s.restore()
|
||||||
|
}
|
||||||
|
|
||||||
// Dispose all the images ahead of restoring. A current texture ID and a new texture ID can be duplicated.
|
// Dispose all the images ahead of restoring. A current texture ID and a new texture ID can be duplicated.
|
||||||
// TODO: Write a test to confirm that ID duplication never happens.
|
// TODO: Write a test to confirm that ID duplication never happens.
|
||||||
for i := range i.images {
|
for i := range i.images {
|
||||||
|
@ -131,7 +131,7 @@ func TestRestoreChain(t *testing.T) {
|
|||||||
for i := 0; i < num-1; i++ {
|
for i := 0; i < num-1; i++ {
|
||||||
vs := quadVertices(1, 1, 0, 0)
|
vs := quadVertices(1, 1, 0, 0)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
imgs[i+1].DrawTriangles(imgs[i], vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero)
|
imgs[i+1].DrawTriangles(imgs[i], vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
}
|
}
|
||||||
if err := ResolveStaleImages(); err != nil {
|
if err := ResolveStaleImages(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -173,10 +173,10 @@ func TestRestoreChain2(t *testing.T) {
|
|||||||
imgs[8].ReplacePixels([]byte{clr8.R, clr8.G, clr8.B, clr8.A}, 0, 0, w, h)
|
imgs[8].ReplacePixels([]byte{clr8.R, clr8.G, clr8.B, clr8.A}, 0, 0, w, h)
|
||||||
|
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
imgs[8].DrawTriangles(imgs[7], quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero)
|
imgs[8].DrawTriangles(imgs[7], quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
imgs[9].DrawTriangles(imgs[8], quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero)
|
imgs[9].DrawTriangles(imgs[8], quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
for i := 0; i < 7; i++ {
|
for i := 0; i < 7; i++ {
|
||||||
imgs[i+1].DrawTriangles(imgs[i], quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero)
|
imgs[i+1].DrawTriangles(imgs[i], quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ResolveStaleImages(); err != nil {
|
if err := ResolveStaleImages(); err != nil {
|
||||||
@ -216,10 +216,10 @@ func TestRestoreOverrideSource(t *testing.T) {
|
|||||||
clr1 := color.RGBA{0x00, 0x00, 0x01, 0xff}
|
clr1 := color.RGBA{0x00, 0x00, 0x01, 0xff}
|
||||||
img1.ReplacePixels([]byte{clr0.R, clr0.G, clr0.B, clr0.A}, 0, 0, w, h)
|
img1.ReplacePixels([]byte{clr0.R, clr0.G, clr0.B, clr0.A}, 0, 0, w, h)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img2.DrawTriangles(img1, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img2.DrawTriangles(img1, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
img3.DrawTriangles(img2, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img3.DrawTriangles(img2, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
img0.ReplacePixels([]byte{clr1.R, clr1.G, clr1.B, clr1.A}, 0, 0, w, h)
|
img0.ReplacePixels([]byte{clr1.R, clr1.G, clr1.B, clr1.A}, 0, 0, w, h)
|
||||||
img1.DrawTriangles(img0, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img1.DrawTriangles(img0, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
if err := ResolveStaleImages(); err != nil {
|
if err := ResolveStaleImages(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -298,23 +298,23 @@ func TestRestoreComplexGraph(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
vs := quadVertices(w, h, 0, 0)
|
vs := quadVertices(w, h, 0, 0)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img3.DrawTriangles(img0, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img3.DrawTriangles(img0, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
vs = quadVertices(w, h, 1, 0)
|
vs = quadVertices(w, h, 1, 0)
|
||||||
img3.DrawTriangles(img1, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img3.DrawTriangles(img1, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
vs = quadVertices(w, h, 1, 0)
|
vs = quadVertices(w, h, 1, 0)
|
||||||
img4.DrawTriangles(img1, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img4.DrawTriangles(img1, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
vs = quadVertices(w, h, 2, 0)
|
vs = quadVertices(w, h, 2, 0)
|
||||||
img4.DrawTriangles(img2, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img4.DrawTriangles(img2, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
vs = quadVertices(w, h, 0, 0)
|
vs = quadVertices(w, h, 0, 0)
|
||||||
img5.DrawTriangles(img3, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img5.DrawTriangles(img3, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
vs = quadVertices(w, h, 0, 0)
|
vs = quadVertices(w, h, 0, 0)
|
||||||
img6.DrawTriangles(img3, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img6.DrawTriangles(img3, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
vs = quadVertices(w, h, 1, 0)
|
vs = quadVertices(w, h, 1, 0)
|
||||||
img6.DrawTriangles(img4, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img6.DrawTriangles(img4, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
vs = quadVertices(w, h, 0, 0)
|
vs = quadVertices(w, h, 0, 0)
|
||||||
img7.DrawTriangles(img2, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img7.DrawTriangles(img2, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
vs = quadVertices(w, h, 2, 0)
|
vs = quadVertices(w, h, 2, 0)
|
||||||
img7.DrawTriangles(img3, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img7.DrawTriangles(img3, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
if err := ResolveStaleImages(); err != nil {
|
if err := ResolveStaleImages(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -406,8 +406,8 @@ func TestRestoreRecursive(t *testing.T) {
|
|||||||
img0.Dispose()
|
img0.Dispose()
|
||||||
}()
|
}()
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img1.DrawTriangles(img0, quadVertices(w, h, 1, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img1.DrawTriangles(img0, quadVertices(w, h, 1, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
img0.DrawTriangles(img1, quadVertices(w, h, 1, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
img0.DrawTriangles(img1, quadVertices(w, h, 1, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
if err := ResolveStaleImages(); err != nil {
|
if err := ResolveStaleImages(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -501,7 +501,7 @@ func TestDrawTrianglesAndReplacePixels(t *testing.T) {
|
|||||||
|
|
||||||
vs := quadVertices(1, 1, 0, 0)
|
vs := quadVertices(1, 1, 0, 0)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img1.DrawTriangles(img0, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero)
|
img1.DrawTriangles(img0, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
img1.ReplacePixels([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 0, 0, 2, 1)
|
img1.ReplacePixels([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 0, 0, 2, 1)
|
||||||
|
|
||||||
if err := ResolveStaleImages(); err != nil {
|
if err := ResolveStaleImages(); err != nil {
|
||||||
@ -538,8 +538,8 @@ func TestDispose(t *testing.T) {
|
|||||||
defer img2.Dispose()
|
defer img2.Dispose()
|
||||||
|
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img1.DrawTriangles(img2, quadVertices(1, 1, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero)
|
img1.DrawTriangles(img2, quadVertices(1, 1, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
img0.DrawTriangles(img1, quadVertices(1, 1, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero)
|
img0.DrawTriangles(img1, quadVertices(1, 1, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
img1.Dispose()
|
img1.Dispose()
|
||||||
|
|
||||||
if err := ResolveStaleImages(); err != nil {
|
if err := ResolveStaleImages(); err != nil {
|
||||||
@ -647,7 +647,7 @@ func TestReplacePixelsOnly(t *testing.T) {
|
|||||||
|
|
||||||
vs := quadVertices(1, 1, 0, 0)
|
vs := quadVertices(1, 1, 0, 0)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
img1.DrawTriangles(img0, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero)
|
img1.DrawTriangles(img0, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
img0.ReplacePixels([]byte{5, 6, 7, 8}, 0, 0, 1, 1)
|
img0.ReplacePixels([]byte{5, 6, 7, 8}, 0, 0, 1, 1)
|
||||||
|
|
||||||
// BasePixelsForTesting is available without GPU accessing.
|
// BasePixelsForTesting is available without GPU accessing.
|
||||||
@ -700,7 +700,7 @@ func TestReadPixelsFromVolatileImage(t *testing.T) {
|
|||||||
src.ReplacePixels(pix, 0, 0, w, h)
|
src.ReplacePixels(pix, 0, 0, w, h)
|
||||||
vs := quadVertices(1, 1, 0, 0)
|
vs := quadVertices(1, 1, 0, 0)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero)
|
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
|
|
||||||
// Read the pixels. If the implementation is correct, dst tries to read its pixels from GPU due to being
|
// Read the pixels. If the implementation is correct, dst tries to read its pixels from GPU due to being
|
||||||
// stale.
|
// stale.
|
||||||
@ -721,7 +721,7 @@ func TestAllowReplacePixelsAfterDrawTriangles(t *testing.T) {
|
|||||||
|
|
||||||
vs := quadVertices(w, h, 0, 0)
|
vs := quadVertices(w, h, 0, 0)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
dst.ReplacePixels(make([]byte, 4*w*h), 0, 0, w, h)
|
dst.ReplacePixels(make([]byte, 4*w*h), 0, 0, w, h)
|
||||||
// ReplacePixels for a whole image doesn't panic.
|
// ReplacePixels for a whole image doesn't panic.
|
||||||
}
|
}
|
||||||
@ -739,7 +739,7 @@ func TestDisallowReplacePixelsForPartAfterDrawTriangles(t *testing.T) {
|
|||||||
|
|
||||||
vs := quadVertices(w, h, 0, 0)
|
vs := quadVertices(w, h, 0, 0)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
dst.ReplacePixels(make([]byte, 4), 0, 0, 1, 1)
|
dst.ReplacePixels(make([]byte, 4), 0, 0, 1, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -835,7 +835,7 @@ func TestMutateSlices(t *testing.T) {
|
|||||||
vs := quadVertices(w, h, 0, 0)
|
vs := quadVertices(w, h, 0, 0)
|
||||||
is := make([]uint16, len(graphics.QuadIndices()))
|
is := make([]uint16, len(graphics.QuadIndices()))
|
||||||
copy(is, graphics.QuadIndices())
|
copy(is, graphics.QuadIndices())
|
||||||
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero)
|
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
for i := range vs {
|
for i := range vs {
|
||||||
vs[i] = 0
|
vs[i] = 0
|
||||||
}
|
}
|
||||||
|
45
internal/restorable/shader.go
Normal file
45
internal/restorable/shader.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Copyright 2020 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 restorable
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/graphicscommand"
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/shaderir"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Shader struct {
|
||||||
|
shader *graphicscommand.Shader
|
||||||
|
ir *shaderir.Program
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewShader(program *shaderir.Program) *Shader {
|
||||||
|
s := &Shader{
|
||||||
|
shader: graphicscommand.NewShader(program),
|
||||||
|
ir: program,
|
||||||
|
}
|
||||||
|
theImages.addShader(s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Shader) Dispose() {
|
||||||
|
theImages.removeShader(s)
|
||||||
|
s.shader.Dispose()
|
||||||
|
s.shader = nil
|
||||||
|
s.ir = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Shader) restore() {
|
||||||
|
s.shader = graphicscommand.NewShader(s.ir)
|
||||||
|
}
|
57
internal/restorable/shader_test.go
Normal file
57
internal/restorable/shader_test.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// 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 restorable_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/driver"
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/graphics"
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/graphicscommand"
|
||||||
|
. "github.com/hajimehoshi/ebiten/internal/restorable"
|
||||||
|
etesting "github.com/hajimehoshi/ebiten/internal/testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestShader(t *testing.T) {
|
||||||
|
if !graphicscommand.IsShaderAvailable() {
|
||||||
|
t.Skip("shader is not available on this environment")
|
||||||
|
}
|
||||||
|
|
||||||
|
img := newImageFromImage(image.NewRGBA(image.Rect(0, 0, 1, 1)))
|
||||||
|
defer img.Dispose()
|
||||||
|
|
||||||
|
ir := etesting.ShaderProgramFill(0xff, 0, 0, 0xff)
|
||||||
|
s := NewShader(&ir)
|
||||||
|
is := graphics.QuadIndices()
|
||||||
|
us := map[int]interface{}{
|
||||||
|
0: []float32{1, 1},
|
||||||
|
}
|
||||||
|
img.DrawTriangles(nil, quadVertices(1, 1, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, s, us)
|
||||||
|
|
||||||
|
if err := ResolveStaleImages(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := RestoreIfNeeded(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := color.RGBA{0xff, 0, 0, 0xff}
|
||||||
|
got := pixelsToColor(img.BasePixelsForTesting(), 0, 0)
|
||||||
|
if !sameColors(got, want, 1) {
|
||||||
|
t.Errorf("got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
@ -214,7 +214,7 @@ func (i *Image) ensureNotShared() {
|
|||||||
dx1, dy1, sx1, sy1, sx0, sy0, sx1, sy1, 1, 1, 1, 1,
|
dx1, dy1, sx1, sy1, sx0, sy0, sx1, sy1, 1, 1, 1, 1,
|
||||||
}
|
}
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
newImg.DrawTriangles(i.backend.restorable, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero)
|
newImg.DrawTriangles(i.backend.restorable, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
|
||||||
|
|
||||||
i.dispose(false)
|
i.dispose(false)
|
||||||
i.backend = &backend{
|
i.backend = &backend{
|
||||||
@ -316,7 +316,7 @@ func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16,
|
|||||||
vertices[i*graphics.VertexFloatNum+7] += oyf
|
vertices[i*graphics.VertexFloatNum+7] += oyf
|
||||||
}
|
}
|
||||||
|
|
||||||
i.backend.restorable.DrawTriangles(img.backend.restorable, vertices, indices, colorm, mode, filter, address)
|
i.backend.restorable.DrawTriangles(img.backend.restorable, vertices, indices, colorm, mode, filter, address, nil, nil)
|
||||||
|
|
||||||
i.nonUpdatedCount = 0
|
i.nonUpdatedCount = 0
|
||||||
delete(imagesToMakeShared, i)
|
delete(imagesToMakeShared, i)
|
||||||
|
Loading…
Reference in New Issue
Block a user