driver: Add Region and sourceRegion parameter at Draw

This is a preparation to remove source-region information from
vertices.

Updates #1210
This commit is contained in:
Hajime Hoshi 2020-06-30 00:02:33 +09:00
parent dcba380827
commit 71c9e7ac40
15 changed files with 218 additions and 164 deletions

View File

@ -333,7 +333,14 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
is := make([]uint16, len(indices)) is := make([]uint16, len(indices))
copy(is, indices) copy(is, indices)
i.buffered.DrawTriangles(img.buffered, vs, is, options.ColorM.impl, mode, filter, driver.Address(options.Address), nil, nil) sr := driver.Region{
X: float32(b.Min.X),
Y: float32(b.Min.Y),
Width: float32(b.Dx()),
Height: float32(b.Dy()),
}
i.buffered.DrawTriangles(img.buffered, vs, is, options.ColorM.impl, mode, filter, driver.Address(options.Address), sr, nil, nil)
} }
type DrawTrianglesWithShaderOptions struct { type DrawTrianglesWithShaderOptions struct {
@ -402,7 +409,7 @@ func (i *Image) DrawTrianglesWithShader(vertices []Vertex, indices []uint16, sha
is := make([]uint16, len(indices)) is := make([]uint16, len(indices))
copy(is, indices) copy(is, indices)
i.buffered.DrawTriangles(nil, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, shader.shader, us) i.buffered.DrawTriangles(nil, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, shader.shader, us)
} }
// SubImage returns an image representing the portion of the image p visible through r. // SubImage returns an image representing the portion of the image p visible through r.

View File

@ -266,7 +266,7 @@ func (i *Image) drawImage(src *Image, bounds image.Rectangle, g mipmap.GeoM, col
// DrawTriangles draws the src image with the given vertices. // DrawTriangles draws the src image with the given vertices.
// //
// 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, sourceRegion driver.Region, shader *Shader, uniforms []interface{}) {
var srcs []*Image var srcs []*Image
if src != nil { if src != nil {
srcs = append(srcs, src) srcs = append(srcs, src)
@ -286,7 +286,7 @@ func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16,
if maybeCanAddDelayedCommand() { if maybeCanAddDelayedCommand() {
if tryAddDelayedCommand(func() error { if tryAddDelayedCommand(func() error {
// Arguments are not copied. Copying is the caller's responsibility. // Arguments are not copied. Copying is the caller's responsibility.
i.DrawTriangles(src, vertices, indices, colorm, mode, filter, address, shader, uniforms) i.DrawTriangles(src, vertices, indices, colorm, mode, filter, address, sourceRegion, shader, uniforms)
return nil return nil
}) { }) {
return return
@ -316,7 +316,7 @@ func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16,
if src != nil { if src != nil {
srcImg = src.img srcImg = src.img
} }
i.img.DrawTriangles(srcImg, vertices, indices, colorm, mode, filter, address, s, us) i.img.DrawTriangles(srcImg, vertices, indices, colorm, mode, filter, address, sourceRegion, s, us)
i.invalidatePendingPixels() i.invalidatePendingPixels()
} }

View File

@ -22,6 +22,13 @@ import (
"github.com/hajimehoshi/ebiten/internal/thread" "github.com/hajimehoshi/ebiten/internal/thread"
) )
type Region struct {
X float32
Y float32
Width float32
Height float32
}
type Graphics interface { type Graphics interface {
SetThread(thread *thread.Thread) SetThread(thread *thread.Thread)
Begin() Begin()
@ -31,7 +38,6 @@ type Graphics interface {
NewImage(width, height int) (Image, error) NewImage(width, height int) (Image, error)
NewScreenFramebufferImage(width, height int) (Image, error) NewScreenFramebufferImage(width, height int) (Image, error)
Reset() error Reset() error
Draw(dst, src ImageID, indexLen int, indexOffset int, mode CompositeMode, colorM *affine.ColorM, filter Filter, address Address) error
SetVsyncEnabled(enabled bool) SetVsyncEnabled(enabled bool)
FramebufferYDirection() YDirection FramebufferYDirection() YDirection
NeedsRestoring() bool NeedsRestoring() bool
@ -41,6 +47,11 @@ type Graphics interface {
NewShader(program *shaderir.Program) (Shader, error) NewShader(program *shaderir.Program) (Shader, error)
// Draw draws an image onto another image.
//
// TODO: Merge this into DrawShader.
Draw(dst, src ImageID, indexLen int, indexOffset int, mode CompositeMode, colorM *affine.ColorM, filter Filter, address Address, sourceRegion Region) error
// DrawShader draws the shader. // DrawShader draws the shader.
// //
// uniforms represents a colletion of uniform variables. The values must be one of these types: // uniforms represents a colletion of uniform variables. The values must be one of these types:

View File

@ -65,7 +65,7 @@ type command interface {
NumIndices() int NumIndices() int
AddNumVertices(n int) AddNumVertices(n int)
AddNumIndices(n int) AddNumIndices(n int)
CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader) bool CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader) bool
} }
type size struct { type size struct {
@ -143,7 +143,7 @@ func (q *commandQueue) appendIndices(indices []uint16, offset uint16) {
} }
// EnqueueDrawTrianglesCommand enqueues a drawing-image command. // EnqueueDrawTrianglesCommand enqueues a drawing-image command.
func (q *commandQueue) EnqueueDrawTrianglesCommand(dst, src *Image, vertices []float32, indices []uint16, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader, uniforms []interface{}) { func (q *commandQueue) EnqueueDrawTrianglesCommand(dst, src *Image, vertices []float32, indices []uint16, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader, uniforms []interface{}) {
if len(indices) > graphics.IndicesNum { if len(indices) > graphics.IndicesNum {
panic(fmt.Sprintf("graphicscommand: len(indices) must be <= graphics.IndicesNum but not at EnqueueDrawTrianglesCommand: len(indices): %d, graphics.IndicesNum: %d", len(indices), graphics.IndicesNum)) panic(fmt.Sprintf("graphicscommand: len(indices) must be <= graphics.IndicesNum but not at EnqueueDrawTrianglesCommand: len(indices): %d, graphics.IndicesNum: %d", len(indices), graphics.IndicesNum))
} }
@ -173,13 +173,21 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst, src *Image, vertices []f
// TODO: If dst is the screen, reorder the command to be the last. // TODO: If dst is the screen, reorder the command to be the last.
if !split && 0 < len(q.commands) { if !split && 0 < len(q.commands) {
if last := q.commands[len(q.commands)-1]; last.CanMergeWithDrawTrianglesCommand(dst, src, color, mode, filter, address, shader) { if last := q.commands[len(q.commands)-1]; last.CanMergeWithDrawTrianglesCommand(dst, src, color, mode, filter, address, sourceRegion, shader) {
last.AddNumVertices(len(vertices)) last.AddNumVertices(len(vertices))
last.AddNumIndices(len(indices)) last.AddNumIndices(len(indices))
return return
} }
} }
if address != driver.AddressUnsafe {
w, h := src.InternalSize()
sourceRegion.X /= float32(w)
sourceRegion.Y /= float32(h)
sourceRegion.Width /= float32(w)
sourceRegion.Height /= float32(h)
}
c := &drawTrianglesCommand{ c := &drawTrianglesCommand{
dst: dst, dst: dst,
src: src, src: src,
@ -189,6 +197,7 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst, src *Image, vertices []f
mode: mode, mode: mode,
filter: filter, filter: filter,
address: address, address: address,
sourceRegion: sourceRegion,
shader: shader, shader: shader,
uniforms: uniforms, uniforms: uniforms,
} }
@ -322,6 +331,7 @@ type drawTrianglesCommand struct {
mode driver.CompositeMode mode driver.CompositeMode
filter driver.Filter filter driver.Filter
address driver.Address address driver.Address
sourceRegion driver.Region
shader *Shader shader *Shader
uniforms []interface{} uniforms []interface{}
} }
@ -409,7 +419,6 @@ func (c *drawTrianglesCommand) Exec(indexOffset int) error {
if c.shader != nil { if c.shader != nil {
us := make([]interface{}, len(c.uniforms)) us := make([]interface{}, len(c.uniforms))
for i := 0; i < len(c.uniforms); i++ { for i := 0; i < len(c.uniforms); i++ {
switch v := c.uniforms[i].(type) { switch v := c.uniforms[i].(type) {
case *Image: case *Image:
@ -427,7 +436,7 @@ func (c *drawTrianglesCommand) Exec(indexOffset int) error {
return theGraphicsDriver.DrawShader(c.dst.image.ID(), c.shader.shader.ID(), c.nindices, indexOffset, c.mode, us) return theGraphicsDriver.DrawShader(c.dst.image.ID(), c.shader.shader.ID(), c.nindices, indexOffset, c.mode, us)
} }
return theGraphicsDriver.Draw(c.dst.image.ID(), c.src.image.ID(), c.nindices, indexOffset, c.mode, c.color, c.filter, c.address) return theGraphicsDriver.Draw(c.dst.image.ID(), c.src.image.ID(), c.nindices, indexOffset, c.mode, c.color, c.filter, c.address, c.sourceRegion)
} }
func (c *drawTrianglesCommand) NumVertices() int { func (c *drawTrianglesCommand) NumVertices() int {
@ -448,7 +457,7 @@ func (c *drawTrianglesCommand) AddNumIndices(n int) {
// CanMergeWithDrawTrianglesCommand returns a boolean value indicating whether the other drawTrianglesCommand can be merged // CanMergeWithDrawTrianglesCommand returns a boolean value indicating whether the other drawTrianglesCommand can be merged
// with the drawTrianglesCommand c. // with the drawTrianglesCommand c.
func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader) bool { func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader) bool {
// If a shader is used, commands are not merged. // If a shader is used, commands are not merged.
// //
// TODO: Merge shader commands considering uniform variables. // TODO: Merge shader commands considering uniform variables.
@ -473,6 +482,9 @@ func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image,
if c.address != address { if c.address != address {
return false return false
} }
if c.sourceRegion != sourceRegion {
return false
}
return true return true
} }
@ -506,7 +518,7 @@ func (c *replacePixelsCommand) AddNumVertices(n int) {
func (c *replacePixelsCommand) AddNumIndices(n int) { func (c *replacePixelsCommand) AddNumIndices(n int) {
} }
func (c *replacePixelsCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader) bool { func (c *replacePixelsCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader) bool {
return false return false
} }
@ -543,7 +555,7 @@ func (c *pixelsCommand) AddNumVertices(n int) {
func (c *pixelsCommand) AddNumIndices(n int) { func (c *pixelsCommand) AddNumIndices(n int) {
} }
func (c *pixelsCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader) bool { func (c *pixelsCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader) bool {
return false return false
} }
@ -576,7 +588,7 @@ func (c *disposeImageCommand) AddNumVertices(n int) {
func (c *disposeImageCommand) AddNumIndices(n int) { func (c *disposeImageCommand) AddNumIndices(n int) {
} }
func (c *disposeImageCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader) bool { func (c *disposeImageCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader) bool {
return false return false
} }
@ -609,7 +621,7 @@ func (c *disposeShaderCommand) AddNumVertices(n int) {
func (c *disposeShaderCommand) AddNumIndices(n int) { func (c *disposeShaderCommand) AddNumIndices(n int) {
} }
func (c *disposeShaderCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader) bool { func (c *disposeShaderCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader) bool {
return false return false
} }
@ -648,7 +660,7 @@ func (c *newImageCommand) AddNumVertices(n int) {
func (c *newImageCommand) AddNumIndices(n int) { func (c *newImageCommand) AddNumIndices(n int) {
} }
func (c *newImageCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader) bool { func (c *newImageCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader) bool {
return false return false
} }
@ -684,7 +696,7 @@ func (c *newScreenFramebufferImageCommand) AddNumVertices(n int) {
func (c *newScreenFramebufferImageCommand) AddNumIndices(n int) { func (c *newScreenFramebufferImageCommand) AddNumIndices(n int) {
} }
func (c *newScreenFramebufferImageCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader) bool { func (c *newScreenFramebufferImageCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader) bool {
return false return false
} }
@ -719,7 +731,7 @@ func (c *newShaderCommand) AddNumVertices(n int) {
func (c *newShaderCommand) AddNumIndices(n int) { func (c *newShaderCommand) AddNumIndices(n int) {
} }
func (c *newShaderCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader) bool { func (c *newShaderCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image, color *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader) bool {
return false return false
} }

View File

@ -158,7 +158,7 @@ func processSrc(src *Image) {
// //
// 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, sourceRegion driver.Region, shader *Shader, uniforms []interface{}) {
if i.lastCommand == lastCommandNone { if i.lastCommand == lastCommandNone {
if !i.screen && mode != driver.CompositeModeClear { if !i.screen && mode != driver.CompositeModeClear {
panic("graphicscommand: the image must be cleared first") panic("graphicscommand: the image must be cleared first")
@ -175,7 +175,7 @@ func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16,
} }
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, sourceRegion, shader, uniforms)
if i.lastCommand == lastCommandNone && !i.screen { if i.lastCommand == lastCommandNone && !i.screen {
i.lastCommand = lastCommandClear i.lastCommand = lastCommandClear

View File

@ -44,7 +44,7 @@ func TestClear(t *testing.T) {
vs := quadVertices(w/2, h/2) vs := quadVertices(w/2, h/2)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, nil, nil) dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
pix, err := dst.Pixels() pix, err := dst.Pixels()
if err != nil { if err != nil {
@ -74,8 +74,8 @@ func TestReplacePixelsPartAfterDrawTriangles(t *testing.T) {
dst := NewImage(w, h) dst := NewImage(w, h)
vs := quadVertices(w/2, h/2) vs := quadVertices(w/2, h/2)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dst.DrawTriangles(clr, vs, is, nil, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, nil, nil) dst.DrawTriangles(clr, vs, is, nil, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, nil, nil) dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
dst.ReplacePixels(make([]byte, 4), 0, 0, 1, 1) dst.ReplacePixels(make([]byte, 4), 0, 0, 1, 1)
} }
@ -89,14 +89,14 @@ func TestShader(t *testing.T) {
dst := NewImage(w, h) dst := NewImage(w, h)
vs := quadVertices(w, h) vs := quadVertices(w, h)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dst.DrawTriangles(clr, vs, is, nil, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, nil, nil) dst.DrawTriangles(clr, vs, is, nil, driver.CompositeModeClear, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
ir := etesting.ShaderProgramFill(0xff, 0, 0, 0xff) ir := etesting.ShaderProgramFill(0xff, 0, 0, 0xff)
s := NewShader(&ir) s := NewShader(&ir)
us := []interface{}{ us := []interface{}{
[]float32{0, 0}, []float32{0, 0},
} }
dst.DrawTriangles(nil, vs, is, nil, driver.CompositeModeSourceOver, 0, 0, s, us) dst.DrawTriangles(nil, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, s, us)
pix, err := dst.Pixels() pix, err := dst.Pixels()
if err != nil { if err != nil {

View File

@ -67,7 +67,6 @@ struct VertexIn {
struct VertexOut { struct VertexOut {
float4 position [[position]]; float4 position [[position]];
float2 tex; float2 tex;
float4 tex_region;
float4 color; float4 color;
}; };
@ -87,7 +86,6 @@ vertex VertexOut VertexShader(
VertexOut out = { VertexOut out = {
.position = projectionMatrix * float4(in.position, 0, 1), .position = projectionMatrix * float4(in.position, 0, 1),
.tex = in.tex, .tex = in.tex,
.tex_region = in.tex_region,
.color = in.color, .color = in.color,
}; };
@ -102,17 +100,17 @@ float FloorMod(float x, float y) {
} }
template<uint8_t address> template<uint8_t address>
float2 AdjustTexelByAddress(float2 p, float4 tex_region); float2 AdjustTexelByAddress(float2 p, float4 source_region);
template<> template<>
inline float2 AdjustTexelByAddress<ADDRESS_CLAMP_TO_ZERO>(float2 p, float4 tex_region) { inline float2 AdjustTexelByAddress<ADDRESS_CLAMP_TO_ZERO>(float2 p, float4 source_region) {
return p; return p;
} }
template<> template<>
inline float2 AdjustTexelByAddress<ADDRESS_REPEAT>(float2 p, float4 tex_region) { inline float2 AdjustTexelByAddress<ADDRESS_REPEAT>(float2 p, float4 source_region) {
float2 o = float2(tex_region[0], tex_region[1]); float2 o = float2(source_region[0], source_region[1]);
float2 size = float2(tex_region[2] - tex_region[0], tex_region[3] - tex_region[1]); float2 size = float2(source_region[2] - source_region[0], source_region[3] - source_region[1]);
return float2(FloorMod((p.x - o.x), size.x) + o.x, FloorMod((p.y - o.y), size.y) + o.y); return float2(FloorMod((p.x - o.x), size.x) + o.x, FloorMod((p.y - o.y), size.y) + o.y);
} }
@ -121,7 +119,7 @@ struct ColorFromTexel;
template<> template<>
struct ColorFromTexel<FILTER_NEAREST, ADDRESS_UNSAFE> { struct ColorFromTexel<FILTER_NEAREST, ADDRESS_UNSAFE> {
inline float4 Do(VertexOut v, texture2d<float> texture, constant float2& source_size, float scale) { inline float4 Do(VertexOut v, texture2d<float> texture, constant float2& source_size, float scale, constant float4& source_region) {
float2 p = v.tex; float2 p = v.tex;
constexpr sampler texture_sampler(filter::nearest); constexpr sampler texture_sampler(filter::nearest);
return texture.sample(texture_sampler, p); return texture.sample(texture_sampler, p);
@ -130,12 +128,12 @@ struct ColorFromTexel<FILTER_NEAREST, ADDRESS_UNSAFE> {
template<uint8_t address> template<uint8_t address>
struct ColorFromTexel<FILTER_NEAREST, address> { struct ColorFromTexel<FILTER_NEAREST, address> {
inline float4 Do(VertexOut v, texture2d<float> texture, constant float2& source_size, float scale) { inline float4 Do(VertexOut v, texture2d<float> texture, constant float2& source_size, float scale, constant float4& source_region) {
float2 p = AdjustTexelByAddress<address>(v.tex, v.tex_region); float2 p = AdjustTexelByAddress<address>(v.tex, source_region);
if (v.tex_region[0] <= p.x && if (source_region[0] <= p.x &&
v.tex_region[1] <= p.y && source_region[1] <= p.y &&
p.x < v.tex_region[2] && p.x < source_region[2] &&
p.y < v.tex_region[3]) { p.y < source_region[3]) {
constexpr sampler texture_sampler(filter::nearest); constexpr sampler texture_sampler(filter::nearest);
return texture.sample(texture_sampler, p); return texture.sample(texture_sampler, p);
} }
@ -145,7 +143,7 @@ struct ColorFromTexel<FILTER_NEAREST, address> {
template<> template<>
struct ColorFromTexel<FILTER_LINEAR, ADDRESS_UNSAFE> { struct ColorFromTexel<FILTER_LINEAR, ADDRESS_UNSAFE> {
inline float4 Do(VertexOut v, texture2d<float> texture, constant float2& source_size, float scale) { inline float4 Do(VertexOut v, texture2d<float> texture, constant float2& source_size, float scale, constant float4& source_region) {
constexpr sampler texture_sampler(filter::nearest); constexpr sampler texture_sampler(filter::nearest);
const float2 texel_size = 1 / source_size; const float2 texel_size = 1 / source_size;
@ -166,7 +164,7 @@ struct ColorFromTexel<FILTER_LINEAR, ADDRESS_UNSAFE> {
template<uint8_t address> template<uint8_t address>
struct ColorFromTexel<FILTER_LINEAR, address> { struct ColorFromTexel<FILTER_LINEAR, address> {
inline float4 Do(VertexOut v, texture2d<float> texture, constant float2& source_size, float scale) { inline float4 Do(VertexOut v, texture2d<float> texture, constant float2& source_size, float scale, constant float4& source_region) {
constexpr sampler texture_sampler(filter::nearest); constexpr sampler texture_sampler(filter::nearest);
const float2 texel_size = 1 / source_size; const float2 texel_size = 1 / source_size;
@ -174,27 +172,27 @@ struct ColorFromTexel<FILTER_LINEAR, address> {
// As all the vertex positions are aligned to 1/16 [pixel], this shiting should work in most cases. // As all the vertex positions are aligned to 1/16 [pixel], this shiting should work in most cases.
float2 p0 = v.tex - texel_size / 2.0 + (texel_size / 512.0); float2 p0 = v.tex - texel_size / 2.0 + (texel_size / 512.0);
float2 p1 = v.tex + texel_size / 2.0 + (texel_size / 512.0); float2 p1 = v.tex + texel_size / 2.0 + (texel_size / 512.0);
p0 = AdjustTexelByAddress<address>(p0, v.tex_region); p0 = AdjustTexelByAddress<address>(p0, source_region);
p1 = AdjustTexelByAddress<address>(p1, v.tex_region); p1 = AdjustTexelByAddress<address>(p1, source_region);
float4 c0 = texture.sample(texture_sampler, p0); float4 c0 = texture.sample(texture_sampler, p0);
float4 c1 = texture.sample(texture_sampler, float2(p1.x, p0.y)); float4 c1 = texture.sample(texture_sampler, float2(p1.x, p0.y));
float4 c2 = texture.sample(texture_sampler, float2(p0.x, p1.y)); float4 c2 = texture.sample(texture_sampler, float2(p0.x, p1.y));
float4 c3 = texture.sample(texture_sampler, p1); float4 c3 = texture.sample(texture_sampler, p1);
if (p0.x < v.tex_region[0]) { if (p0.x < source_region[0]) {
c0 = 0; c0 = 0;
c2 = 0; c2 = 0;
} }
if (p0.y < v.tex_region[1]) { if (p0.y < source_region[1]) {
c0 = 0; c0 = 0;
c1 = 0; c1 = 0;
} }
if (v.tex_region[2] <= p1.x) { if (source_region[2] <= p1.x) {
c1 = 0; c1 = 0;
c3 = 0; c3 = 0;
} }
if (v.tex_region[3] <= p1.y) { if (source_region[3] <= p1.y) {
c2 = 0; c2 = 0;
c3 = 0; c3 = 0;
} }
@ -206,7 +204,7 @@ struct ColorFromTexel<FILTER_LINEAR, address> {
template<uint8_t address> template<uint8_t address>
struct ColorFromTexel<FILTER_SCREEN, address> { struct ColorFromTexel<FILTER_SCREEN, address> {
inline float4 Do(VertexOut v, texture2d<float> texture, constant float2& source_size, float scale) { inline float4 Do(VertexOut v, texture2d<float> texture, constant float2& source_size, float scale, constant float4& source_region) {
constexpr sampler texture_sampler(filter::nearest); constexpr sampler texture_sampler(filter::nearest);
const float2 texel_size = 1 / source_size; const float2 texel_size = 1 / source_size;
@ -232,8 +230,9 @@ struct FragmentShaderImpl {
constant float2& source_size, constant float2& source_size,
constant float4x4& color_matrix_body, constant float4x4& color_matrix_body,
constant float4& color_matrix_translation, constant float4& color_matrix_translation,
constant float& scale) { constant float& scale,
float4 c = ColorFromTexel<filter, address>().Do(v, texture, source_size, scale); constant float4& source_region) {
float4 c = ColorFromTexel<filter, address>().Do(v, texture, source_size, scale, source_region);
if (useColorM) { if (useColorM) {
c.rgb /= c.a + (1.0 - sign(c.a)); c.rgb /= c.a + (1.0 - sign(c.a));
c = (color_matrix_body * c) + color_matrix_translation; c = (color_matrix_body * c) + color_matrix_translation;
@ -256,8 +255,9 @@ struct FragmentShaderImpl<useColorM, FILTER_SCREEN, address> {
constant float2& source_size, constant float2& source_size,
constant float4x4& color_matrix_body, constant float4x4& color_matrix_body,
constant float4& color_matrix_translation, constant float4& color_matrix_translation,
constant float& scale) { constant float& scale,
return ColorFromTexel<FILTER_SCREEN, address>().Do(v, texture, source_size, scale); constant float4& source_region) {
return ColorFromTexel<FILTER_SCREEN, address>().Do(v, texture, source_size, scale, source_region);
} }
}; };
@ -274,9 +274,10 @@ struct FragmentShaderImpl<useColorM, FILTER_SCREEN, address> {
constant float2& source_size [[buffer(2)]], \ constant float2& source_size [[buffer(2)]], \
constant float4x4& color_matrix_body [[buffer(3)]], \ constant float4x4& color_matrix_body [[buffer(3)]], \
constant float4& color_matrix_translation [[buffer(4)]], \ constant float4& color_matrix_translation [[buffer(4)]], \
constant float& scale [[buffer(5)]]) { \ constant float& scale [[buffer(5)]], \
constant float4& source_region [[buffer(6)]]) { \
return FragmentShaderImpl<useColorM, filter, address>().Do( \ return FragmentShaderImpl<useColorM, filter, address>().Do( \
v, texture, source_size, color_matrix_body, color_matrix_translation, scale); \ v, texture, source_size, color_matrix_body, color_matrix_translation, scale, source_region); \
} }
FragmentShaderFunc(0, FILTER_NEAREST, ADDRESS_CLAMP_TO_ZERO) FragmentShaderFunc(0, FILTER_NEAREST, ADDRESS_CLAMP_TO_ZERO)
@ -635,7 +636,9 @@ func (g *Graphics) Reset() error {
return nil return nil
} }
func (g *Graphics) Draw(dstID, srcID driver.ImageID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM *affine.ColorM, filter driver.Filter, address driver.Address) error { func (g *Graphics) Draw(dstID, srcID driver.ImageID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM *affine.ColorM, filter driver.Filter, address driver.Address, sourceRegion driver.Region) error {
// TODO: Use sourceRegion.
dst := g.images[dstID] dst := g.images[dstID]
src := g.images[srcID] src := g.images[srcID]
@ -709,6 +712,14 @@ func (g *Graphics) Draw(dstID, srcID driver.ImageID, indexLen int, indexOffset i
scale := float32(dst.width) / float32(src.width) scale := float32(dst.width) / float32(src.width)
rce.SetFragmentBytes(unsafe.Pointer(&scale), unsafe.Sizeof(scale), 5) rce.SetFragmentBytes(unsafe.Pointer(&scale), unsafe.Sizeof(scale), 5)
sr := [...]float32{
sourceRegion.X,
sourceRegion.Y,
sourceRegion.X + sourceRegion.Width,
sourceRegion.Y + sourceRegion.Height,
}
rce.SetFragmentBytes(unsafe.Pointer(&sr[0]), unsafe.Sizeof(sr), 6)
if src != nil { if src != nil {
rce.SetFragmentTexture(src.texture, 0) rce.SetFragmentTexture(src.texture, 0)
} else { } else {

View File

@ -114,12 +114,10 @@ attribute vec2 tex;
attribute vec4 tex_region; attribute vec4 tex_region;
attribute vec4 color_scale; attribute vec4 color_scale;
varying vec2 varying_tex; varying vec2 varying_tex;
varying vec4 varying_tex_region;
varying vec4 varying_color_scale; varying vec4 varying_color_scale;
void main(void) { void main(void) {
varying_tex = tex; varying_tex = tex;
varying_tex_region = tex_region;
varying_color_scale = color_scale; varying_color_scale = color_scale;
mat4 projection_matrix = mat4( mat4 projection_matrix = mat4(
@ -143,6 +141,7 @@ precision mediump float;
{{.Definitions}} {{.Definitions}}
uniform sampler2D texture; uniform sampler2D texture;
uniform vec4 source_region;
#if defined(USE_COLOR_MATRIX) #if defined(USE_COLOR_MATRIX)
uniform mat4 color_matrix_body; uniform mat4 color_matrix_body;
@ -156,7 +155,6 @@ uniform highp float scale;
#endif #endif
varying highp vec2 varying_tex; varying highp vec2 varying_tex;
varying highp vec4 varying_tex_region;
varying highp vec4 varying_color_scale; varying highp vec4 varying_color_scale;
highp float floorMod(highp float x, highp float y) { highp float floorMod(highp float x, highp float y) {
@ -190,11 +188,11 @@ void main(void) {
# if defined(ADDRESS_UNSAFE) # if defined(ADDRESS_UNSAFE)
color = texture2D(texture, pos); color = texture2D(texture, pos);
# else # else
pos = adjustTexelByAddress(pos, varying_tex_region); pos = adjustTexelByAddress(pos, source_region);
if (varying_tex_region[0] <= pos.x && if (source_region[0] <= pos.x &&
varying_tex_region[1] <= pos.y && source_region[1] <= pos.y &&
pos.x < varying_tex_region[2] && pos.x < source_region[2] &&
pos.y < varying_tex_region[3]) { pos.y < source_region[3]) {
color = texture2D(texture, pos); color = texture2D(texture, pos);
} else { } else {
color = vec4(0, 0, 0, 0); color = vec4(0, 0, 0, 0);
@ -212,8 +210,8 @@ void main(void) {
highp vec2 p1 = pos + (texel_size) / 2.0 + (texel_size / 512.0); highp vec2 p1 = pos + (texel_size) / 2.0 + (texel_size / 512.0);
# if !defined(ADDRESS_UNSAFE) # if !defined(ADDRESS_UNSAFE)
p0 = adjustTexelByAddress(p0, varying_tex_region); p0 = adjustTexelByAddress(p0, source_region);
p1 = adjustTexelByAddress(p1, varying_tex_region); p1 = adjustTexelByAddress(p1, source_region);
# endif // defined(ADDRESS_UNSAFE) # endif // defined(ADDRESS_UNSAFE)
vec4 c0 = texture2D(texture, p0); vec4 c0 = texture2D(texture, p0);
@ -221,19 +219,19 @@ void main(void) {
vec4 c2 = texture2D(texture, vec2(p0.x, p1.y)); vec4 c2 = texture2D(texture, vec2(p0.x, p1.y));
vec4 c3 = texture2D(texture, p1); vec4 c3 = texture2D(texture, p1);
# if !defined(ADDRESS_UNSAFE) # if !defined(ADDRESS_UNSAFE)
if (p0.x < varying_tex_region[0]) { if (p0.x < source_region[0]) {
c0 = vec4(0, 0, 0, 0); c0 = vec4(0, 0, 0, 0);
c2 = vec4(0, 0, 0, 0); c2 = vec4(0, 0, 0, 0);
} }
if (p0.y < varying_tex_region[1]) { if (p0.y < source_region[1]) {
c0 = vec4(0, 0, 0, 0); c0 = vec4(0, 0, 0, 0);
c1 = vec4(0, 0, 0, 0); c1 = vec4(0, 0, 0, 0);
} }
if (varying_tex_region[2] <= p1.x) { if (source_region[2] <= p1.x) {
c1 = vec4(0, 0, 0, 0); c1 = vec4(0, 0, 0, 0);
c3 = vec4(0, 0, 0, 0); c3 = vec4(0, 0, 0, 0);
} }
if (varying_tex_region[3] <= p1.y) { if (source_region[3] <= p1.y) {
c2 = vec4(0, 0, 0, 0); c2 = vec4(0, 0, 0, 0);
c3 = vec4(0, 0, 0, 0); c3 = vec4(0, 0, 0, 0);
} }

View File

@ -149,7 +149,9 @@ func (g *Graphics) SetVertices(vertices []float32, indices []uint16) {
g.context.elementArrayBufferSubData(indices) g.context.elementArrayBufferSubData(indices)
} }
func (g *Graphics) Draw(dst, src driver.ImageID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM *affine.ColorM, filter driver.Filter, address driver.Address) error { func (g *Graphics) Draw(dst, src driver.ImageID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM *affine.ColorM, filter driver.Filter, address driver.Address, sourceRegion driver.Region) error {
// TODO: Use sourceRegion.
destination := g.images[dst] destination := g.images[dst]
source := g.images[src] source := g.images[src]
@ -173,6 +175,14 @@ func (g *Graphics) Draw(dst, src driver.ImageID, indexLen int, indexOffset int,
uniforms = append(uniforms, uniformVariable{ uniforms = append(uniforms, uniformVariable{
name: "viewport_size", name: "viewport_size",
value: []float32{float32(vw), float32(vh)}, value: []float32{float32(vw), float32(vh)},
}, uniformVariable{
name: "source_region",
value: []float32{
sourceRegion.X,
sourceRegion.Y,
sourceRegion.X + sourceRegion.Width,
sourceRegion.Y + sourceRegion.Height,
},
}) })
if colorM != nil { if colorM != nil {

View File

@ -151,7 +151,7 @@ func (m *Mipmap) DrawImage(src *Mipmap, bounds image.Rectangle, geom GeoM, color
if level == 0 { if level == 0 {
vs := quadVertices(bounds.Min.X, bounds.Min.Y, bounds.Max.X, bounds.Max.Y, a, b, c, d, tx, ty, cr, cg, cb, ca, screen) vs := quadVertices(bounds.Min.X, bounds.Min.Y, bounds.Max.X, bounds.Max.Y, a, b, c, d, tx, ty, cr, cg, cb, ca, screen)
is := graphics.QuadIndices() is := graphics.QuadIndices()
m.orig.DrawTriangles(src.orig, vs, is, colorm, mode, filter, driver.AddressUnsafe, nil, nil) m.orig.DrawTriangles(src.orig, vs, is, colorm, mode, filter, driver.AddressUnsafe, driver.Region{}, nil, nil)
} else if buf := src.level(bounds, level); buf != nil { } else if buf := src.level(bounds, level); buf != nil {
w, h := sizeForLevel(bounds.Dx(), bounds.Dy(), level) w, h := sizeForLevel(bounds.Dx(), bounds.Dy(), level)
s := pow2(level) s := pow2(level)
@ -161,12 +161,12 @@ func (m *Mipmap) DrawImage(src *Mipmap, bounds image.Rectangle, geom GeoM, color
d *= s d *= s
vs := quadVertices(0, 0, w, h, a, b, c, d, tx, ty, cr, cg, cb, ca, false) vs := quadVertices(0, 0, w, h, a, b, c, d, tx, ty, cr, cg, cb, ca, false)
is := graphics.QuadIndices() is := graphics.QuadIndices()
m.orig.DrawTriangles(buf, vs, is, colorm, mode, filter, driver.AddressUnsafe, nil, nil) m.orig.DrawTriangles(buf, vs, is, colorm, mode, filter, driver.AddressUnsafe, driver.Region{}, nil, nil)
} }
m.disposeMipmaps() m.disposeMipmaps()
} }
func (m *Mipmap) DrawTriangles(src *Mipmap, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader, uniforms []interface{}) { func (m *Mipmap) DrawTriangles(src *Mipmap, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader, uniforms []interface{}) {
// TODO: Use a mipmap? (#909) // TODO: Use a mipmap? (#909)
if colorm != nil && colorm.ScaleOnly() { if colorm != nil && colorm.ScaleOnly() {
@ -205,7 +205,7 @@ func (m *Mipmap) DrawTriangles(src *Mipmap, vertices []float32, indices []uint16
srcOrig = src.orig srcOrig = src.orig
} }
m.orig.DrawTriangles(srcOrig, vertices, indices, colorm, mode, filter, address, s, us) m.orig.DrawTriangles(srcOrig, vertices, indices, colorm, mode, filter, address, sourceRegion, s, us)
m.disposeMipmaps() m.disposeMipmaps()
} }
@ -268,7 +268,7 @@ func (m *Mipmap) level(r image.Rectangle, level int) *shareable.Image {
return nil return nil
} }
s := shareable.NewImage(w2, h2, m.volatile) s := shareable.NewImage(w2, h2, m.volatile)
s.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, filter, driver.AddressUnsafe, nil, nil) s.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, filter, driver.AddressUnsafe, driver.Region{}, nil, nil)
imgs[level] = s imgs[level] = s
return imgs[level] return imgs[level]

View File

@ -76,6 +76,7 @@ type drawTrianglesHistoryItem struct {
mode driver.CompositeMode mode driver.CompositeMode
filter driver.Filter filter driver.Filter
address driver.Address address driver.Address
sourceRegion driver.Region
shader *Shader shader *Shader
uniforms []interface{} uniforms []interface{}
} }
@ -258,8 +259,7 @@ func fillImage(i *graphicscommand.Image, clr color.RGBA) {
// Add 1 pixels for paddings. // Add 1 pixels for paddings.
vs := quadVertices(0, 0, float32(dw), float32(dh), 1, 1, float32(sw-1), float32(sh-1), rf, gf, bf, af) vs := quadVertices(0, 0, float32(dw), float32(dh), 1, 1, float32(sw-1), float32(sh-1), rf, gf, bf, af)
is := graphics.QuadIndices() is := graphics.QuadIndices()
i.DrawTriangles(emptyImage.image, vs, is, nil, compositemode, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
i.DrawTriangles(emptyImage.image, vs, is, nil, compositemode, driver.FilterNearest, driver.AddressUnsafe, nil, nil)
} }
// BasePixelsForTesting returns the image's basePixels for testing. // BasePixelsForTesting returns the image's basePixels for testing.
@ -369,7 +369,7 @@ func convertUniformVariables(uniforms []interface{}) []interface{} {
// 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, shader *Shader, uniforms []interface{}) { func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader, uniforms []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")
} }
@ -397,7 +397,7 @@ func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16,
if srcstale || i.screen || !needsRestoring() || i.volatile { 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, sourceRegion, shader, uniforms)
} }
var s *graphicscommand.Shader var s *graphicscommand.Shader
if shader != nil { if shader != nil {
@ -407,11 +407,11 @@ func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16,
if img != nil { if img != nil {
gimg = img.image gimg = img.image
} }
i.image.DrawTriangles(gimg, vertices, indices, colorm, mode, filter, address, s, convertUniformVariables(uniforms)) i.image.DrawTriangles(gimg, vertices, indices, colorm, mode, filter, address, sourceRegion, 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, shader *Shader, uniforms []interface{}) { func (i *Image) appendDrawTrianglesHistory(image *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader, uniforms []interface{}) {
if i.stale || i.volatile || i.screen { if i.stale || i.volatile || i.screen {
return return
} }
@ -437,6 +437,7 @@ func (i *Image) appendDrawTrianglesHistory(image *Image, vertices []float32, ind
mode: mode, mode: mode,
filter: filter, filter: filter,
address: address, address: address,
sourceRegion: sourceRegion,
shader: shader, shader: shader,
uniforms: uniforms, uniforms: uniforms,
} }
@ -618,7 +619,7 @@ func (i *Image) restore() error {
if c.shader != nil { if c.shader != nil {
s = c.shader.shader s = c.shader.shader
} }
gimg.DrawTriangles(img, c.vertices, c.indices, c.colorm, c.mode, c.filter, c.address, s, convertUniformVariables(c.uniforms)) gimg.DrawTriangles(img, c.vertices, c.indices, c.colorm, c.mode, c.filter, c.address, c.sourceRegion, s, convertUniformVariables(c.uniforms))
} }
if len(i.drawTrianglesHistory) > 0 { if len(i.drawTrianglesHistory) > 0 {

View File

@ -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.AddressUnsafe, nil, nil) imgs[i+1].DrawTriangles(imgs[i], vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) imgs[8].DrawTriangles(imgs[7], quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
imgs[9].DrawTriangles(imgs[8], quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, nil, nil) imgs[9].DrawTriangles(imgs[8], quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) imgs[i+1].DrawTriangles(imgs[i], quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img2.DrawTriangles(img1, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
img3.DrawTriangles(img2, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, nil, nil) img3.DrawTriangles(img2, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img1.DrawTriangles(img0, quadVertices(w, h, 0, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img3.DrawTriangles(img0, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img3.DrawTriangles(img1, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img4.DrawTriangles(img1, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img4.DrawTriangles(img2, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img5.DrawTriangles(img3, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img6.DrawTriangles(img3, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img6.DrawTriangles(img4, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img7.DrawTriangles(img2, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img7.DrawTriangles(img3, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img1.DrawTriangles(img0, quadVertices(w, h, 1, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
img0.DrawTriangles(img1, quadVertices(w, h, 1, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, nil, nil) img0.DrawTriangles(img1, quadVertices(w, h, 1, 0), is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img1.DrawTriangles(img0, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img1.DrawTriangles(img2, quadVertices(1, 1, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
img0.DrawTriangles(img1, quadVertices(1, 1, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, nil, nil) img0.DrawTriangles(img1, quadVertices(1, 1, 0, 0), is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) img1.DrawTriangles(img0, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, 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.AddressUnsafe, nil, nil) dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
dst.ReplacePixels(make([]byte, 4), 0, 0, 1, 1) dst.ReplacePixels(make([]byte, 4), 0, 0, 1, 1)
} }
@ -828,7 +828,7 @@ func TestFill2(t *testing.T) {
dst := NewImage(w, h, false) dst := NewImage(w, h, false)
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.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, nil, nil) dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
// Fill src with a different color. This should not affect dst. // Fill src with a different color. This should not affect dst.
src.Fill(color.RGBA{0, 0xff, 0, 0xff}) src.Fill(color.RGBA{0, 0xff, 0, 0xff})
@ -867,7 +867,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.AddressUnsafe, nil, nil) dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
for i := range vs { for i := range vs {
vs[i] = 0 vs[i] = 0
} }

View File

@ -38,7 +38,7 @@ func TestShader(t *testing.T) {
us := []interface{}{ us := []interface{}{
[]float32{0, 0}, []float32{0, 0},
} }
img.DrawTriangles(nil, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, s, us) img.DrawTriangles(nil, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, s, us)
if err := ResolveStaleImages(); err != nil { if err := ResolveStaleImages(); err != nil {
t.Fatal(err) t.Fatal(err)
@ -76,7 +76,7 @@ func TestShaderChain(t *testing.T) {
[]float32{0, 0}, []float32{0, 0},
imgs[i], imgs[i],
} }
imgs[i+1].DrawTriangles(nil, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, s, us) imgs[i+1].DrawTriangles(nil, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, s, us)
} }
if err := ResolveStaleImages(); err != nil { if err := ResolveStaleImages(); err != nil {
@ -118,7 +118,7 @@ func TestShaderMultipleSources(t *testing.T) {
srcs[1], srcs[1],
srcs[2], srcs[2],
} }
dst.DrawTriangles(nil, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, s, us) dst.DrawTriangles(nil, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, s, us)
// Clear one of the sources after DrawTriangles. dst should not be affected. // Clear one of the sources after DrawTriangles. dst should not be affected.
srcs[0].Fill(color.RGBA{}) srcs[0].Fill(color.RGBA{})
@ -150,7 +150,7 @@ func TestShaderDispose(t *testing.T) {
us := []interface{}{ us := []interface{}{
[]float32{0, 0}, []float32{0, 0},
} }
img.DrawTriangles(nil, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, s, us) img.DrawTriangles(nil, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, s, us)
// Dispose the shader. This should invalidates all the images using this shader i.e., all the images become // Dispose the shader. This should invalidates all the images using this shader i.e., all the images become
// stale. // stale.

View File

@ -220,7 +220,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.AddressUnsafe, nil, nil) newImg.DrawTriangles(i.backend.restorable, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
i.dispose(false) i.dispose(false)
i.backend = &backend{ i.backend = &backend{
@ -309,7 +309,7 @@ func makeSharedIfNeeded(src *Image) {
// 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, shader *Shader, uniforms []interface{}) { func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader, uniforms []interface{}) {
backendsM.Lock() backendsM.Lock()
// Do not use defer for performance. // Do not use defer for performance.
@ -355,6 +355,10 @@ func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16,
vertices[i*graphics.VertexFloatNum+6] += oxf vertices[i*graphics.VertexFloatNum+6] += oxf
vertices[i*graphics.VertexFloatNum+7] += oyf vertices[i*graphics.VertexFloatNum+7] += oyf
} }
if address != driver.AddressUnsafe {
sourceRegion.X += oxf
sourceRegion.Y += oyf
}
} }
var s *restorable.Shader var s *restorable.Shader
@ -376,7 +380,7 @@ func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16,
if img != nil { if img != nil {
r = img.backend.restorable r = img.backend.restorable
} }
i.backend.restorable.DrawTriangles(r, vertices, indices, colorm, mode, filter, address, s, us) i.backend.restorable.DrawTriangles(r, vertices, indices, colorm, mode, filter, address, sourceRegion, s, us)
i.nonUpdatedCount = 0 i.nonUpdatedCount = 0
delete(imagesToMakeShared, i) delete(imagesToMakeShared, i)

View File

@ -96,7 +96,7 @@ func TestEnsureNotShared(t *testing.T) {
// img4.ensureNotShared() should be called. // img4.ensureNotShared() should be called.
vs := quadVertices(size/2, size/2, size/4, size/4, 1) vs := quadVertices(size/2, size/2, size/4, size/4, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
img4.DrawTriangles(img3, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, nil, nil) img4.DrawTriangles(img3, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
want := false want := false
if got := img4.IsSharedForTesting(); got != want { if got := img4.IsSharedForTesting(); got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
@ -126,7 +126,7 @@ func TestEnsureNotShared(t *testing.T) {
// Check further drawing doesn't cause panic. // Check further drawing doesn't cause panic.
// This bug was fixed by 03dcd948. // This bug was fixed by 03dcd948.
img4.DrawTriangles(img3, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, nil, nil) img4.DrawTriangles(img3, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
} }
func TestReshared(t *testing.T) { func TestReshared(t *testing.T) {
@ -166,7 +166,7 @@ func TestReshared(t *testing.T) {
// Use img1 as a render target. // Use img1 as a render target.
vs := quadVertices(size, size, 0, 0, 1) vs := quadVertices(size, size, 0, 0, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
img1.DrawTriangles(img2, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, nil, nil) img1.DrawTriangles(img2, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
if got, want := img1.IsSharedForTesting(), false; got != want { if got, want := img1.IsSharedForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -176,7 +176,7 @@ func TestReshared(t *testing.T) {
if err := MakeImagesSharedForTesting(); err != nil { if err := MakeImagesSharedForTesting(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
img0.DrawTriangles(img1, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, nil, nil) img0.DrawTriangles(img1, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
if got, want := img1.IsSharedForTesting(), false; got != want { if got, want := img1.IsSharedForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -203,7 +203,7 @@ func TestReshared(t *testing.T) {
} }
} }
img0.DrawTriangles(img1, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, nil, nil) img0.DrawTriangles(img1, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
if got, want := img1.IsSharedForTesting(), true; got != want { if got, want := img1.IsSharedForTesting(), true; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -231,7 +231,7 @@ func TestReshared(t *testing.T) {
if err := MakeImagesSharedForTesting(); err != nil { if err := MakeImagesSharedForTesting(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
img0.DrawTriangles(img3, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, nil, nil) img0.DrawTriangles(img3, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
if got, want := img3.IsSharedForTesting(), false; got != want { if got, want := img3.IsSharedForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -326,7 +326,7 @@ func TestReplacePixelsAfterDrawTriangles(t *testing.T) {
vs := quadVertices(w, h, 0, 0, 1) vs := quadVertices(w, h, 0, 0, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, nil, nil) dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
dst.ReplacePixels(pix) dst.ReplacePixels(pix)
pix, err := dst.Pixels(0, 0, w, h) pix, err := dst.Pixels(0, 0, w, h)
@ -368,7 +368,7 @@ func TestSmallImages(t *testing.T) {
vs := quadVertices(w, h, 0, 0, 1) vs := quadVertices(w, h, 0, 0, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, nil, nil) dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
pix, err := dst.Pixels(0, 0, w, h) pix, err := dst.Pixels(0, 0, w, h)
if err != nil { if err != nil {
@ -410,7 +410,7 @@ func TestLongImages(t *testing.T) {
const scale = 120 const scale = 120
vs := quadVertices(w, h, 0, 0, scale) vs := quadVertices(w, h, 0, 0, scale)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, nil, nil) dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
pix, err := dst.Pixels(0, 0, dstW, dstH) pix, err := dst.Pixels(0, 0, dstW, dstH)
if err != nil { if err != nil {