shader: Fix the case when the source image is nil for shaders

This commit is contained in:
Hajime Hoshi 2020-06-04 01:35:35 +09:00
parent fc44589705
commit 2f843c49a6
5 changed files with 110 additions and 35 deletions

View File

@ -288,8 +288,20 @@ func (i *Image) drawImage(src *Image, bounds image.Rectangle, g mipmap.GeoM, col
// //
// Copying vertices and indices is the caller's responsibility. // Copying vertices and indices is the caller's responsibility.
func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader, uniforms []interface{}) { func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader, uniforms []interface{}) {
if i == src { var srcs []*Image
panic("buffered: Image.DrawTriangles: src must be different from the receiver") if src != nil {
srcs = append(srcs, src)
}
for _, u := range uniforms {
if src, ok := u.(*Image); ok {
srcs = append(srcs, src)
}
}
for _, src := range srcs {
if i == src {
panic("buffered: Image.DrawTriangles: src must be different from the receiver")
}
} }
delayedCommandsM.Lock() delayedCommandsM.Lock()
@ -304,7 +316,9 @@ func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16,
return return
} }
src.resolvePendingPixels(true) for _, src := range srcs {
src.resolvePendingPixels(true)
}
i.resolvePendingPixels(false) i.resolvePendingPixels(false)
var s *mipmap.Shader var s *mipmap.Shader
@ -322,7 +336,11 @@ func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16,
} }
} }
i.img.DrawTriangles(src.img, vertices, indices, colorm, mode, filter, address, s, us) var srcImg *mipmap.Mipmap
if src != nil {
srcImg = src.img
}
i.img.DrawTriangles(srcImg, vertices, indices, colorm, mode, filter, address, s, us)
} }
type Shader struct { type Shader struct {

View File

@ -152,8 +152,20 @@ 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 // 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. // elements for the source image are not used.
func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16, clr *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader, uniforms []interface{}) { func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16, clr *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader, uniforms []interface{}) {
if src != nil && src.screen { var srcs []*Image
panic("graphicscommand: the screen image cannot be the rendering source") if src != nil {
srcs = append(srcs, src)
}
for _, u := range uniforms {
if src, ok := u.(*Image); ok {
srcs = append(srcs, src)
}
}
for _, src := range srcs {
if src.screen {
panic("graphicscommand: the screen image cannot be the rendering source")
}
} }
if i.lastCommand == lastCommandNone { if i.lastCommand == lastCommandNone {
@ -162,14 +174,9 @@ func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16,
} }
} }
if src != nil { for _, src := range srcs {
src.resolveBufferedReplacePixels() src.resolveBufferedReplacePixels()
} }
for _, v := range uniforms {
if img, ok := v.(*Image); ok {
img.resolveBufferedReplacePixels()
}
}
i.resolveBufferedReplacePixels() i.resolveBufferedReplacePixels()
theCommandQueue.EnqueueDrawTrianglesCommand(i, src, vertices, indices, clr, mode, filter, address, shader, uniforms) theCommandQueue.EnqueueDrawTrianglesCommand(i, src, vertices, indices, clr, mode, filter, address, shader, uniforms)

View File

@ -200,7 +200,12 @@ func (m *Mipmap) DrawTriangles(src *Mipmap, vertices []float32, indices []uint16
} }
} }
m.orig.DrawTriangles(src.orig, vertices, indices, colorm, mode, filter, address, s, us) var srcOrig *shareable.Image
if src != nil {
srcOrig = src.orig
}
m.orig.DrawTriangles(srcOrig, vertices, indices, colorm, mode, filter, address, s, us)
m.disposeMipmaps() m.disposeMipmaps()
} }

View File

@ -384,7 +384,26 @@ func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16,
} }
theImages.makeStaleIfDependingOn(i) theImages.makeStaleIfDependingOn(i)
if (img != nil && (img.stale || img.volatile)) || i.screen || !needsRestoring() || i.volatile { var srcs []*Image
if img != nil {
srcs = append(srcs, img)
}
for _, u := range uniforms {
if src, ok := u.(*Image); ok {
srcs = append(srcs, src)
}
}
// TODO: Add tests to confirm this logic.
var srcstale bool
for _, src := range srcs {
if src.stale || src.volatile {
srcstale = true
break
}
}
if srcstale || i.screen || !needsRestoring() || i.volatile {
i.makeStale() i.makeStale()
} else { } else {
i.appendDrawTrianglesHistory(img, vertices, indices, colorm, mode, filter, address, shader, uniforms) i.appendDrawTrianglesHistory(img, vertices, indices, colorm, mode, filter, address, shader, uniforms)

View File

@ -286,34 +286,54 @@ func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16,
backendsM.Lock() backendsM.Lock()
// Do not use defer for performance. // Do not use defer for performance.
if img.disposed { var srcs []*Image
panic("shareable: the drawing source image must not be disposed (DrawTriangles)") if img != nil {
srcs = append(srcs, img)
}
for _, u := range uniforms {
if src, ok := u.(*Image); ok {
srcs = append(srcs, src)
}
}
for _, src := range srcs {
if src.disposed {
panic("shareable: the drawing source image must not be disposed (DrawTriangles)")
}
} }
if i.disposed { if i.disposed {
panic("shareable: the drawing target image must not be disposed (DrawTriangles)") panic("shareable: the drawing target image must not be disposed (DrawTriangles)")
} }
if img.backend == nil {
img.allocate(true) for _, src := range srcs {
if src.backend == nil {
src.allocate(true)
}
} }
i.ensureNotShared() i.ensureNotShared()
// Compare i and img after ensuring i is not shared, or // Compare i and source images after ensuring i is not shared, or
// i and img might share the same texture even though i != img. // i and a source image might share the same texture even though i != src.
if i.backend.restorable == img.backend.restorable { for _, src := range srcs {
panic("shareable: Image.DrawTriangles: img must be different from the receiver") if i.backend.restorable == src.backend.restorable {
panic("shareable: Image.DrawTriangles: source must be different from the receiver")
}
} }
ox, oy, _, _ := img.region() var oxf, oyf float32
oxf, oyf := float32(ox), float32(oy) if len(srcs) > 0 {
n := len(vertices) / graphics.VertexFloatNum ox, oy, _, _ := srcs[0].region()
for i := 0; i < n; i++ { oxf, oyf = float32(ox), float32(oy)
vertices[i*graphics.VertexFloatNum+2] += oxf n := len(vertices) / graphics.VertexFloatNum
vertices[i*graphics.VertexFloatNum+3] += oyf for i := 0; i < n; i++ {
vertices[i*graphics.VertexFloatNum+4] += oxf vertices[i*graphics.VertexFloatNum+2] += oxf
vertices[i*graphics.VertexFloatNum+5] += oyf vertices[i*graphics.VertexFloatNum+3] += oyf
vertices[i*graphics.VertexFloatNum+6] += oxf vertices[i*graphics.VertexFloatNum+4] += oxf
vertices[i*graphics.VertexFloatNum+7] += oyf vertices[i*graphics.VertexFloatNum+5] += oyf
vertices[i*graphics.VertexFloatNum+6] += oxf
vertices[i*graphics.VertexFloatNum+7] += oyf
}
} }
var s *restorable.Shader var s *restorable.Shader
@ -343,13 +363,19 @@ func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16,
} }
} }
i.backend.restorable.DrawTriangles(img.backend.restorable, vertices, indices, colorm, mode, filter, address, s, us) var r *restorable.Image
if img != nil {
r = img.backend.restorable
}
i.backend.restorable.DrawTriangles(r, vertices, indices, colorm, mode, filter, address, s, us)
i.nonUpdatedCount = 0 i.nonUpdatedCount = 0
delete(imagesToMakeShared, i) delete(imagesToMakeShared, i)
if !img.isShared() && img.shareable() { for _, src := range srcs {
imagesToMakeShared[img] = struct{}{} if !src.isShared() && src.shareable() {
imagesToMakeShared[src] = struct{}{}
}
} }
backendsM.Unlock() backendsM.Unlock()