diff --git a/image.go b/image.go index cdbf69fd9..878679618 100644 --- a/image.go +++ b/image.go @@ -438,9 +438,6 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o if int(idx) >= len(vertices) { panic(fmt.Sprintf("ebiten: indices[%d] must be less than len(vertices) (%d) but was %d", i, len(vertices), idx)) } - if idx >= MaxVerticesCount { - panic(fmt.Sprintf("ebiten: indices[%d] must be less than MaxVerticesCount %d but was %d", i, MaxVerticesCount, idx)) - } } if options == nil { @@ -603,9 +600,6 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader if int(idx) >= len(vertices) { panic(fmt.Sprintf("ebiten: indices[%d] must be less than len(vertices) (%d) but was %d", i, len(vertices), idx)) } - if idx >= MaxVerticesCount { - panic(fmt.Sprintf("ebiten: indices[%d] must be less than MaxVerticesCount %d but was %d", i, MaxVerticesCount, idx)) - } } if options == nil { diff --git a/image_test.go b/image_test.go index 155804f73..c8e2493fc 100644 --- a/image_test.go +++ b/image_test.go @@ -2805,7 +2805,7 @@ func BenchmarkColorMScale(b *testing.B) { } } -func TestIndicesOverflow(t *testing.T) { +func TestImageMoreIndicesThanMaxUint16(t *testing.T) { const ( w = 16 h = 16 @@ -2817,10 +2817,10 @@ func TestIndicesOverflow(t *testing.T) { op := &ebiten.DrawTrianglesOptions{} vs := make([]ebiten.Vertex, 3) - is := make([]uint16, graphics.MaxVerticesCount/3*3) + is := make([]uint16, 65538) dst.DrawTriangles(vs, is, src, op) - // Cause an overflow for indices. + // The next draw call should work well (and this is likely batched). vs = []ebiten.Vertex{ { DstX: 0, @@ -2877,7 +2877,7 @@ func TestIndicesOverflow(t *testing.T) { } } -func TestVerticesOverflow(t *testing.T) { +func TestImageMoreVerticesThanMaxUint16(t *testing.T) { const ( w = 16 h = 16 @@ -2888,11 +2888,11 @@ func TestVerticesOverflow(t *testing.T) { src.Fill(color.White) op := &ebiten.DrawTrianglesOptions{} - vs := make([]ebiten.Vertex, graphics.MaxVerticesCount-1) + vs := make([]ebiten.Vertex, math.MaxUint16+1) is := make([]uint16, 3) dst.DrawTriangles(vs, is, src, op) - // Cause an overflow for vertices. + // The next draw call should work well (and this is likely batched). vs = []ebiten.Vertex{ { DstX: 0, @@ -2949,26 +2949,6 @@ func TestVerticesOverflow(t *testing.T) { } } -func TestTooManyVertices(t *testing.T) { - const ( - w = 16 - h = 16 - ) - - dst := ebiten.NewImage(w, h) - src := ebiten.NewImage(w, h) - src.Fill(color.White) - - op := &ebiten.DrawTrianglesOptions{} - vs := make([]ebiten.Vertex, graphics.MaxVerticesCount+1) - is := make([]uint16, 3) - dst.DrawTriangles(vs, is, src, op) - - // Force to cause flushing the graphics commands. - // Confirm this doesn't freeze. - dst.At(0, 0) -} - func TestImageNewImageFromEbitenImage(t *testing.T) { const ( w = 16 @@ -4318,48 +4298,6 @@ func TestImageDrawTrianglesShaderWithGreaterIndexThanVerticesCount(t *testing.T) dst.DrawTrianglesShader(vs, is, shader, nil) } -// Issue #2611 -func TestImageDrawTrianglesWithTooBigIndex(t *testing.T) { - defer func() { - if r := recover(); r == nil { - t.Errorf("DrawTriangles must panic but not") - } - }() - - const w, h = 16, 16 - dst := ebiten.NewImage(w, h) - src := ebiten.NewImage(w, h) - - vs := make([]ebiten.Vertex, ebiten.MaxVerticesCount+1) - is := []uint16{0, 1, 2, 1, 2, ebiten.MaxVerticesCount} - dst.DrawTriangles(vs, is, src, nil) -} - -// Issue #2611 -func TestImageDrawTrianglesShaderWithTooBigIndex(t *testing.T) { - defer func() { - if r := recover(); r == nil { - t.Errorf("DrawTrianglesShader must panic but not") - } - }() - - const w, h = 16, 16 - dst := ebiten.NewImage(w, h) - - vs := make([]ebiten.Vertex, ebiten.MaxVerticesCount+1) - is := []uint16{0, 1, 2, 1, 2, ebiten.MaxVerticesCount} - shader, err := ebiten.NewShader([]byte(` - package main - func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 { - return color - } - `)) - if err != nil { - t.Fatalf("could not compile shader: %v", err) - } - dst.DrawTrianglesShader(vs, is, shader, nil) -} - // Issue #2733 func TestImageGeoMAfterDraw(t *testing.T) { src := ebiten.NewImage(1, 1) diff --git a/internal/graphics/vertex.go b/internal/graphics/vertex.go index 074a36292..822cb88c1 100644 --- a/internal/graphics/vertex.go +++ b/internal/graphics/vertex.go @@ -45,13 +45,18 @@ const ( const ( VertexFloatCount = 8 + is32bit = 1 >> (^uint(0) >> 63) + is64bit = 1 - is32bit + // MaxVerticesCount is the maximum number of vertices for one draw call. - // This value is 2^16 - 1 = 65535, as the index type is uint16. - // This value cannot be exactly 2^16 == 65536 especially with WebGL 2, as 65536th vertex is not rendered correctly. + // + // On 64bit architectures, this value is 2^32-1, as the index type is uint32. + // This value cannot be exactly 2^32 especially with WebGL 2, as 2^32th vertex is not rendered correctly. // See https://registry.khronos.org/webgl/specs/latest/2.0/#5.18 . // - // TODO: Use MaxUint32 and move these values to internal/graphicscommand (#2612) - MaxVerticesCount = math.MaxUint16 + // On 32bit architectures, this value is an adjusted number so that MaxVertexFloatsCount doesn't overflow int. + MaxVerticesCount = is64bit*math.MaxUint32 + is32bit*(math.MaxInt32/VertexFloatCount) + MaxVertexFloatsCount = MaxVerticesCount * VertexFloatCount ) diff --git a/internal/ui/image.go b/internal/ui/image.go index e73675f12..77f7efa76 100644 --- a/internal/ui/image.go +++ b/internal/ui/image.go @@ -139,8 +139,7 @@ func (i *Image) WritePixels(pix []byte, region image.Rectangle) { copy(clr[:], pix) i.dotsBuffer[region.Min] = clr - // One square requires 6 indices (= 2 triangles). - if len(i.dotsBuffer) >= graphics.MaxVerticesCount/6 { + if len(i.dotsBuffer) >= 10000 { i.flushDotsBufferIfNeeded() } return