diff --git a/internal/graphics/vertex.go b/internal/graphics/vertex.go index a11fc18c3..f9951a118 100644 --- a/internal/graphics/vertex.go +++ b/internal/graphics/vertex.go @@ -16,6 +16,8 @@ package graphics const ( ShaderSrcImageCount = 4 + // ShaderDstImageCount is the number of the destination image. This is 1 so far, but this might change in the future. + ShaderDstImageCount = 1 // PreservedUniformVariablesCount represents the number of preserved uniform variables. // Any shaders in Ebitengine must have these uniform variables. diff --git a/internal/graphicscommand/command.go b/internal/graphicscommand/command.go index b9a921fc9..f14faeb41 100644 --- a/internal/graphicscommand/command.go +++ b/internal/graphicscommand/command.go @@ -61,7 +61,7 @@ func (p *drawTrianglesCommandPool) put(v *drawTrianglesCommand) { // drawTrianglesCommand represents a drawing command to draw an image on another image. type drawTrianglesCommand struct { - dst *Image + dsts [graphics.ShaderDstImageCount]*Image srcs [graphics.ShaderSrcImageCount]*Image vertices []float32 blend graphicsdriver.Blend @@ -81,9 +81,16 @@ func (c *drawTrianglesCommand) String() string { c.blend.BlendOperationRGB, c.blend.BlendOperationAlpha) - dst := fmt.Sprintf("%d", c.dst.id) - if c.dst.screen { - dst += " (screen)" + var dststrs [graphics.ShaderDstImageCount]string + for i, dst := range c.dsts { + if dst == nil { + dststrs[i] = "(nil)" + continue + } + dststrs[i] = fmt.Sprintf("%d", dst.id) + if dst.screen { + dststrs[i] += " (screen)" + } } var srcstrs [graphics.ShaderSrcImageCount]string @@ -98,7 +105,7 @@ func (c *drawTrianglesCommand) String() string { } } - return fmt.Sprintf("draw-triangles: dst: %s <- src: [%s], num of dst regions: %d, num of indices: %d, blend: %s, fill rule: %s, shader id: %d", dst, strings.Join(srcstrs[:], ", "), len(c.dstRegions), c.numIndices(), blend, c.fillRule, c.shader.id) + return fmt.Sprintf("draw-triangles: dst: [%s] <- src: [%s], num of dst regions: %d, num of indices: %d, blend: %s, fill rule: %s, shader id: %d", strings.Join(dststrs[:], ", "), strings.Join(srcstrs[:], ", "), len(c.dstRegions), c.numIndices(), blend, c.fillRule, c.shader.id) } // Exec executes the drawTrianglesCommand. @@ -108,16 +115,25 @@ func (c *drawTrianglesCommand) Exec(commandQueue *commandQueue, graphicsDriver g return nil } - var imgs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID - for i, src := range c.srcs { - if src == nil { - imgs[i] = graphicsdriver.InvalidImageID + var dsts [graphics.ShaderDstImageCount]graphicsdriver.ImageID + for i, dst := range c.dsts { + if dst == nil { + dsts[i] = graphicsdriver.InvalidImageID continue } - imgs[i] = src.image.ID() + dsts[i] = dst.image.ID() } - return graphicsDriver.DrawTriangles(c.dst.image.ID(), imgs, c.shader.shader.ID(), c.dstRegions, indexOffset, c.blend, c.uniforms, c.fillRule) + var srcs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID + for i, src := range c.srcs { + if src == nil { + srcs[i] = graphicsdriver.InvalidImageID + continue + } + srcs[i] = src.image.ID() + } + + return graphicsDriver.DrawTriangles(dsts, srcs, c.shader.shader.ID(), c.dstRegions, indexOffset, c.blend, c.uniforms, c.fillRule) } func (c *drawTrianglesCommand) NeedsSync() bool { @@ -142,7 +158,7 @@ func (c *drawTrianglesCommand) setVertices(vertices []float32) { // CanMergeWithDrawTrianglesCommand returns a boolean value indicating whether the other drawTrianglesCommand can be merged // with the drawTrianglesCommand c. -func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, blend graphicsdriver.Blend, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) bool { +func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, blend graphicsdriver.Blend, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) bool { if c.shader != shader { return false } @@ -154,7 +170,7 @@ func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs return false } } - if c.dst != dst { + if c.dsts != dsts { return false } if c.srcs != srcs { diff --git a/internal/graphicscommand/commandqueue.go b/internal/graphicscommand/commandqueue.go index 0f24dbf42..d38853f0c 100644 --- a/internal/graphicscommand/commandqueue.go +++ b/internal/graphicscommand/commandqueue.go @@ -105,7 +105,7 @@ func mustUseDifferentVertexBuffer(nextNumVertexFloats int) bool { } // EnqueueDrawTrianglesCommand enqueues a drawing-image command. -func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) { +func (q *commandQueue) EnqueueDrawTrianglesCommand(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) { if len(vertices) > maxVertexFloatCount { panic(fmt.Sprintf("graphicscommand: len(vertices) must equal to or less than %d but was %d", maxVertexFloatCount, len(vertices))) } @@ -125,7 +125,7 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh // prependPreservedUniforms not only prepends values to the given slice but also creates a new slice. // Allocating a new slice is necessary to make EnqueueDrawTrianglesCommand safe so far. // TODO: This might cause a performance issue (#2601). - uniforms = q.prependPreservedUniforms(uniforms, shader, dst, srcs, dstRegion, srcRegions) + uniforms = q.prependPreservedUniforms(uniforms, shader, dsts, srcs, dstRegion, srcRegions) // Remove unused uniform variables so that more commands can be merged. shader.ir.FilterUniformVariables(uniforms) @@ -133,7 +133,7 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh // TODO: If dst is the screen, reorder the command to be the last. if !split && 0 < len(q.commands) { if last, ok := q.commands[len(q.commands)-1].(*drawTrianglesCommand); ok { - if last.CanMergeWithDrawTrianglesCommand(dst, srcs, vertices, blend, shader, uniforms, fillRule) { + if last.CanMergeWithDrawTrianglesCommand(dsts, srcs, vertices, blend, shader, uniforms, fillRule) { last.setVertices(q.lastVertices(len(vertices) + last.numVertices())) if last.dstRegions[len(last.dstRegions)-1].Region == dstRegion { last.dstRegions[len(last.dstRegions)-1].IndexCount += len(indices) @@ -149,7 +149,7 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh } c := q.drawTrianglesCommandPool.get() - c.dst = dst + c.dsts = dsts c.srcs = srcs c.vertices = q.lastVertices(len(vertices)) c.blend = blend @@ -324,13 +324,14 @@ func imageRectangleToRectangleF32(r image.Rectangle) rectangleF32 { } } -func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shader, dst *Image, srcs [graphics.ShaderSrcImageCount]*Image, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle) []uint32 { +func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shader, dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.ShaderSrcImageCount]*Image, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle) []uint32 { origUniforms := uniforms uniforms = q.uint32sBuffer.alloc(len(origUniforms) + graphics.PreservedUniformUint32Count) copy(uniforms[graphics.PreservedUniformUint32Count:], origUniforms) // Set the destination texture size. - dw, dh := dst.InternalSize() + // The number of destination images is always 1 but this might change in the future. + dw, dh := dsts[0].InternalSize() uniforms[0] = math.Float32bits(float32(dw)) uniforms[1] = math.Float32bits(float32(dh)) uniformIndex := 2 @@ -469,11 +470,11 @@ func (c *commandQueueManager) putCommandQueue(commandQueue *commandQueue) { c.pool.put(commandQueue) } -func (c *commandQueueManager) enqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) { +func (c *commandQueueManager) enqueueDrawTrianglesCommand(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) { if c.current == nil { c.current, _ = c.pool.get() } - c.current.EnqueueDrawTrianglesCommand(dst, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule) + c.current.EnqueueDrawTrianglesCommand(dsts, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule) } func (c *commandQueueManager) flush(graphicsDriver graphicsdriver.Graphics, endFrame bool) error { diff --git a/internal/graphicscommand/image.go b/internal/graphicscommand/image.go index 01d366a11..7ef528daa 100644 --- a/internal/graphicscommand/image.go +++ b/internal/graphicscommand/image.go @@ -142,7 +142,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertice } i.flushBufferedWritePixels() - theCommandQueueManager.enqueueDrawTrianglesCommand(i, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule) + theCommandQueueManager.enqueueDrawTrianglesCommand([graphics.ShaderDstImageCount]*Image{i}, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule) } // ReadPixels reads the image's pixels. diff --git a/internal/graphicsdriver/directx/graphics11_windows.go b/internal/graphicsdriver/directx/graphics11_windows.go index 6a111edbf..7765eec6f 100644 --- a/internal/graphicsdriver/directx/graphics11_windows.go +++ b/internal/graphicsdriver/directx/graphics11_windows.go @@ -514,13 +514,13 @@ func (g *graphics11) removeShader(s *shader11) { delete(g.shaders, s.id) } -func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error { +func (g *graphics11) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdriver.ImageID, srcIDs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error { // Remove bound textures first. This is needed to avoid warnings on the debugger. g.deviceContext.OMSetRenderTargets([]*_ID3D11RenderTargetView{nil}, nil) srvs := [graphics.ShaderSrcImageCount]*_ID3D11ShaderResourceView{} g.deviceContext.PSSetShaderResources(0, srvs[:]) - dst := g.images[dstID] + dst := g.images[dstIDs[0]] var srcs [graphics.ShaderSrcImageCount]*image11 for i, id := range srcIDs { img := g.images[id] diff --git a/internal/graphicsdriver/directx/graphics12_windows.go b/internal/graphicsdriver/directx/graphics12_windows.go index 5e0341215..c05358db7 100644 --- a/internal/graphicsdriver/directx/graphics12_windows.go +++ b/internal/graphicsdriver/directx/graphics12_windows.go @@ -1081,7 +1081,7 @@ func (g *graphics12) NewShader(program *shaderir.Program) (graphicsdriver.Shader return s, nil } -func (g *graphics12) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error { +func (g *graphics12) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdriver.ImageID, srcs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error { if shaderID == graphicsdriver.InvalidShaderID { return fmt.Errorf("directx: shader ID is invalid") } @@ -1102,7 +1102,7 @@ func (g *graphics12) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics. g.pipelineStates.releaseConstantBuffers(g.frameIndex) } - dst := g.images[dstID] + dst := g.images[dstIDs[0]] var resourceBarriers []_D3D12_RESOURCE_BARRIER_Transition if rb, ok := dst.transiteState(_D3D12_RESOURCE_STATE_RENDER_TARGET); ok { resourceBarriers = append(resourceBarriers, rb) diff --git a/internal/graphicsdriver/graphics.go b/internal/graphicsdriver/graphics.go index 1c40b16ea..2f6fa144e 100644 --- a/internal/graphicsdriver/graphics.go +++ b/internal/graphicsdriver/graphics.go @@ -68,7 +68,7 @@ type Graphics interface { NewShader(program *shaderir.Program) (Shader, error) // DrawTriangles draws an image onto another image with the given parameters. - DrawTriangles(dst ImageID, srcs [graphics.ShaderSrcImageCount]ImageID, shader ShaderID, dstRegions []DstRegion, indexOffset int, blend Blend, uniforms []uint32, fillRule FillRule) error + DrawTriangles(dsts [graphics.ShaderDstImageCount]ImageID, srcs [graphics.ShaderSrcImageCount]ImageID, shader ShaderID, dstRegions []DstRegion, indexOffset int, blend Blend, uniforms []uint32, fillRule FillRule) error } type Resetter interface { diff --git a/internal/graphicsdriver/metal/graphics_darwin.go b/internal/graphicsdriver/metal/graphics_darwin.go index 685fbe483..d4437f603 100644 --- a/internal/graphicsdriver/metal/graphics_darwin.go +++ b/internal/graphicsdriver/metal/graphics_darwin.go @@ -605,12 +605,12 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs return nil } -func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error { +func (g *Graphics) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdriver.ImageID, srcIDs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error { if shaderID == graphicsdriver.InvalidShaderID { return fmt.Errorf("metal: shader ID is invalid") } - dst := g.images[dstID] + dst := g.images[dstIDs[0]] if dst.screen { g.view.update() diff --git a/internal/graphicsdriver/opengl/graphics.go b/internal/graphicsdriver/opengl/graphics.go index cac47988b..6173f69b4 100644 --- a/internal/graphicsdriver/opengl/graphics.go +++ b/internal/graphicsdriver/opengl/graphics.go @@ -198,12 +198,12 @@ func (g *Graphics) uniformVariableName(idx int) string { return name } -func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error { +func (g *Graphics) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdriver.ImageID, srcIDs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error { if shaderID == graphicsdriver.InvalidShaderID { return fmt.Errorf("opengl: shader ID is invalid") } - destination := g.images[dstID] + destination := g.images[dstIDs[0]] g.drawCalled = true diff --git a/internal/graphicsdriver/playstation5/graphics_playstation5.go b/internal/graphicsdriver/playstation5/graphics_playstation5.go index 63cd09091..711debf17 100644 --- a/internal/graphicsdriver/playstation5/graphics_playstation5.go +++ b/internal/graphicsdriver/playstation5/graphics_playstation5.go @@ -116,7 +116,7 @@ func (g *Graphics) NewShader(program *shaderir.Program) (graphicsdriver.Shader, }, nil } -func (g *Graphics) DrawTriangles(dst graphicsdriver.ImageID, srcs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shader graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error { +func (g *Graphics) DrawTriangles(dsts [graphics.ShaderDstImageCount]graphicsdriver.ImageID, srcs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shader graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error { return nil }