mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
internal/graphicsdriver: render various destination regions as one command
Closes #2232
This commit is contained in:
parent
1ce29e2afa
commit
d73e8f785d
78
examples/subimage/main.go
Normal file
78
examples/subimage/main.go
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright 2022 The Ebitengine Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"log"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
)
|
||||
|
||||
const (
|
||||
cx = 32
|
||||
cy = 32
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
offscreen *ebiten.Image
|
||||
subImages [cx][cy]*ebiten.Image
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
if g.offscreen == nil {
|
||||
g.offscreen = ebiten.NewImage(screen.Size())
|
||||
}
|
||||
|
||||
// Use various sub-images as rendering destination.
|
||||
// This is a proof-of-concept of efficient rendering with sub-images (#2232).
|
||||
sw, sh := screen.Size()
|
||||
cw := sw / cx
|
||||
ch := sh / cy
|
||||
for j := 0; j < cy; j++ {
|
||||
for i := 0; i < cx; i++ {
|
||||
img := g.subImages[i][j]
|
||||
if img == nil {
|
||||
r := image.Rect(cw*i, ch*j, cw*(i+1), ch*(j+1))
|
||||
img = g.offscreen.SubImage(r).(*ebiten.Image)
|
||||
g.subImages[i][j] = img
|
||||
}
|
||||
|
||||
clr := color.RGBA{byte(0xff * float64(i) / cx), byte(0xff * float64(j) / cx), 0, 0xff}
|
||||
img.Fill(clr)
|
||||
}
|
||||
}
|
||||
|
||||
screen.DrawImage(g.offscreen, nil)
|
||||
ebitenutil.DebugPrint(screen, fmt.Sprintf("FPS: %0.2f, TPS: %0.2f", ebiten.ActualFPS(), ebiten.ActualTPS()))
|
||||
}
|
||||
|
||||
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
return 640, 480
|
||||
}
|
||||
|
||||
func main() {
|
||||
ebiten.SetWindowTitle("Sub-images as rendering destinations (Ebitengine Demo)")
|
||||
if err := ebiten.RunGame(&Game{}); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
5
image.go
5
image.go
@ -749,9 +749,8 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
|
||||
// If a sub-image is used as a rendering source, the image is used as if it is a small image.
|
||||
// If a sub-image is used as a rendering destination, the region being rendered is clipped.
|
||||
//
|
||||
// Successive uses of multiple various regions as rendering destination might not be efficient,
|
||||
// even though all the underlying images are the same.
|
||||
// It's because such renderings cannot be unified into one internal draw command.
|
||||
// Successive uses of multiple various regions as rendering destination is efficient
|
||||
// when all the underlying images are the same.
|
||||
func (i *Image) SubImage(r image.Rectangle) image.Image {
|
||||
i.copyCheck()
|
||||
if i.isDisposed() {
|
||||
|
@ -71,7 +71,11 @@ type commandQueue struct {
|
||||
|
||||
drawTrianglesCommandPool drawTrianglesCommandPool
|
||||
|
||||
float32sBuffer []float32
|
||||
// float32sBuffer is a reusable buffer to allocate []float32.
|
||||
// float32sBuffer's index is switched at the end of the frame,
|
||||
// and the buffer of the original index is kept until the next frame ends.
|
||||
float32sBuffer [2][]float32
|
||||
float32sBufferIndex int
|
||||
}
|
||||
|
||||
// theCommandQueue is the command queue for the current process.
|
||||
@ -118,9 +122,16 @@ 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, dstRegion, shader, uniforms, evenOdd) {
|
||||
if last.CanMergeWithDrawTrianglesCommand(dst, srcs, vertices, blend, shader, uniforms, evenOdd) {
|
||||
last.setVertices(q.lastVertices(len(vertices) + last.numVertices()))
|
||||
last.addNumIndices(len(indices))
|
||||
if last.dstRegions[len(last.dstRegions)-1].Region == dstRegion {
|
||||
last.dstRegions[len(last.dstRegions)-1].IndexCount += len(indices)
|
||||
} else {
|
||||
last.dstRegions = append(last.dstRegions, graphicsdriver.DstRegion{
|
||||
Region: dstRegion,
|
||||
IndexCount: len(indices),
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -130,9 +141,13 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh
|
||||
c.dst = dst
|
||||
c.srcs = srcs
|
||||
c.vertices = q.lastVertices(len(vertices))
|
||||
c.nindices = len(indices)
|
||||
c.blend = blend
|
||||
c.dstRegion = dstRegion
|
||||
c.dstRegions = []graphicsdriver.DstRegion{
|
||||
{
|
||||
Region: dstRegion,
|
||||
IndexCount: len(indices),
|
||||
},
|
||||
}
|
||||
c.shader = shader
|
||||
c.uniforms = uniforms
|
||||
c.evenOdd = evenOdd
|
||||
@ -157,7 +172,9 @@ func (q *commandQueue) Flush(graphicsDriver graphicsdriver.Graphics, endFrame bo
|
||||
err = q.flush(graphicsDriver, endFrame)
|
||||
})
|
||||
if endFrame {
|
||||
q.float32sBuffer = q.float32sBuffer[:0]
|
||||
q.float32sBuffer[q.float32sBufferIndex] = q.float32sBuffer[q.float32sBufferIndex][:0]
|
||||
q.float32sBufferIndex++
|
||||
q.float32sBufferIndex %= len(q.float32sBuffer)
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -252,15 +269,14 @@ func FlushCommands(graphicsDriver graphicsdriver.Graphics, endFrame bool) error
|
||||
|
||||
// drawTrianglesCommand represents a drawing command to draw an image on another image.
|
||||
type drawTrianglesCommand struct {
|
||||
dst *Image
|
||||
srcs [graphics.ShaderImageCount]*Image
|
||||
vertices []float32
|
||||
nindices int
|
||||
blend graphicsdriver.Blend
|
||||
dstRegion graphicsdriver.Region
|
||||
shader *Shader
|
||||
uniforms [][]float32
|
||||
evenOdd bool
|
||||
dst *Image
|
||||
srcs [graphics.ShaderImageCount]*Image
|
||||
vertices []float32
|
||||
blend graphicsdriver.Blend
|
||||
dstRegions []graphicsdriver.DstRegion
|
||||
shader *Shader
|
||||
uniforms [][]float32
|
||||
evenOdd bool
|
||||
}
|
||||
|
||||
func (c *drawTrianglesCommand) String() string {
|
||||
@ -290,15 +306,13 @@ func (c *drawTrianglesCommand) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
r := fmt.Sprintf("(x:%d, y:%d, width:%d, height:%d)",
|
||||
int(c.dstRegion.X), int(c.dstRegion.Y), int(c.dstRegion.Width), int(c.dstRegion.Height))
|
||||
return fmt.Sprintf("draw-triangles: dst: %s <- src: [%s], dst region: %s, num of indices: %d, blend: %s, even-odd: %t", dst, strings.Join(srcstrs[:], ", "), r, c.nindices, blend, c.evenOdd)
|
||||
return fmt.Sprintf("draw-triangles: dst: %s <- src: [%s], num of dst regions: %d, num of indices: %d, blend: %s, even-odd: %t", dst, strings.Join(srcstrs[:], ", "), len(c.dstRegions), c.numIndices(), blend, c.evenOdd)
|
||||
}
|
||||
|
||||
// Exec executes the drawTrianglesCommand.
|
||||
func (c *drawTrianglesCommand) Exec(graphicsDriver graphicsdriver.Graphics, indexOffset int) error {
|
||||
// TODO: Is it ok not to bind any framebuffer here?
|
||||
if c.nindices == 0 {
|
||||
if len(c.dstRegions) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -311,7 +325,7 @@ func (c *drawTrianglesCommand) Exec(graphicsDriver graphicsdriver.Graphics, inde
|
||||
imgs[i] = src.image.ID()
|
||||
}
|
||||
|
||||
return graphicsDriver.DrawTriangles(c.dst.image.ID(), imgs, c.shader.shader.ID(), c.nindices, indexOffset, c.blend, c.dstRegion, c.uniforms, c.evenOdd)
|
||||
return graphicsDriver.DrawTriangles(c.dst.image.ID(), imgs, c.shader.shader.ID(), c.dstRegions, indexOffset, c.blend, c.uniforms, c.evenOdd)
|
||||
}
|
||||
|
||||
func (c *drawTrianglesCommand) numVertices() int {
|
||||
@ -319,20 +333,20 @@ func (c *drawTrianglesCommand) numVertices() int {
|
||||
}
|
||||
|
||||
func (c *drawTrianglesCommand) numIndices() int {
|
||||
return c.nindices
|
||||
var nindices int
|
||||
for _, dstRegion := range c.dstRegions {
|
||||
nindices += dstRegion.IndexCount
|
||||
}
|
||||
return nindices
|
||||
}
|
||||
|
||||
func (c *drawTrianglesCommand) setVertices(vertices []float32) {
|
||||
c.vertices = vertices
|
||||
}
|
||||
|
||||
func (c *drawTrianglesCommand) addNumIndices(n int) {
|
||||
c.nindices += n
|
||||
}
|
||||
|
||||
// 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.ShaderImageCount]*Image, vertices []float32, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, shader *Shader, uniforms [][]float32, evenOdd bool) bool {
|
||||
func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, blend graphicsdriver.Blend, shader *Shader, uniforms [][]float32, evenOdd bool) bool {
|
||||
if c.shader != shader {
|
||||
return false
|
||||
}
|
||||
@ -358,9 +372,6 @@ func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs
|
||||
if c.blend != blend {
|
||||
return false
|
||||
}
|
||||
if c.dstRegion != dstRegion {
|
||||
return false
|
||||
}
|
||||
if c.evenOdd || evenOdd {
|
||||
if c.evenOdd && evenOdd {
|
||||
return !mightOverlapDstRegions(c.vertices, vertices)
|
||||
@ -580,12 +591,12 @@ func roundUpPower2(x int) int {
|
||||
}
|
||||
|
||||
func (q *commandQueue) allocFloat32s(n int) []float32 {
|
||||
buf := q.float32sBuffer
|
||||
buf := q.float32sBuffer[q.float32sBufferIndex]
|
||||
if len(buf)+n > cap(buf) {
|
||||
buf = make([]float32, 0, max(roundUpPower2(len(buf)+n), 16))
|
||||
}
|
||||
s := buf[len(buf) : len(buf)+n]
|
||||
q.float32sBuffer = buf[:len(buf)+n]
|
||||
q.float32sBuffer[q.float32sBufferIndex] = buf[:len(buf)+n]
|
||||
return s
|
||||
}
|
||||
|
||||
|
@ -1168,7 +1168,7 @@ func (g *Graphics) NewShader(program *shaderir.Program) (graphicsdriver.Shader,
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, indexLen int, indexOffset int, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, uniforms [][]float32, evenOdd bool) error {
|
||||
func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms [][]float32, evenOdd bool) error {
|
||||
if shaderID == graphicsdriver.InvalidShaderID {
|
||||
return fmt.Errorf("directx: shader ID is invalid")
|
||||
}
|
||||
@ -1239,15 +1239,6 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh
|
||||
MaxDepth: _D3D12_MAX_DEPTH,
|
||||
},
|
||||
})
|
||||
g.drawCommandList.RSSetScissorRects([]_D3D12_RECT{
|
||||
{
|
||||
left: int32(dstRegion.X),
|
||||
top: int32(dstRegion.Y),
|
||||
right: int32(dstRegion.X + dstRegion.Width),
|
||||
bottom: int32(dstRegion.Y + dstRegion.Height),
|
||||
},
|
||||
})
|
||||
|
||||
g.drawCommandList.IASetPrimitiveTopology(_D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST)
|
||||
g.drawCommandList.IASetVertexBuffers(0, []_D3D12_VERTEX_BUFFER_VIEW{
|
||||
{
|
||||
@ -1262,7 +1253,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh
|
||||
Format: _DXGI_FORMAT_R16_UINT,
|
||||
})
|
||||
|
||||
if err := g.pipelineStates.drawTriangles(g.device, g.drawCommandList, g.frameIndex, dst.screen, srcImages, shader, flattenUniforms, blend, indexLen, indexOffset, evenOdd); err != nil {
|
||||
if err := g.pipelineStates.drawTriangles(g.device, g.drawCommandList, g.frameIndex, dst.screen, srcImages, shader, dstRegions, flattenUniforms, blend, indexOffset, evenOdd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ func (p *pipelineStates) initialize(device *_ID3D12Device) (ferr error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D12GraphicsCommandList, frameIndex int, screen bool, srcs [graphics.ShaderImageCount]*Image, shader *Shader, uniforms []float32, blend graphicsdriver.Blend, indexLen int, indexOffset int, evenOdd bool) error {
|
||||
func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D12GraphicsCommandList, frameIndex int, screen bool, srcs [graphics.ShaderImageCount]*Image, shader *Shader, dstRegions []graphicsdriver.DstRegion, uniforms []float32, blend graphicsdriver.Blend, indexOffset int, evenOdd bool) error {
|
||||
idx := len(p.constantBuffers[frameIndex])
|
||||
if idx >= numDescriptorsPerFrame {
|
||||
return fmt.Errorf("directx: too many constant buffers")
|
||||
@ -255,27 +255,38 @@ func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D
|
||||
}
|
||||
commandList.SetGraphicsRootDescriptorTable(2, sh)
|
||||
|
||||
if evenOdd {
|
||||
s, err := shader.pipelineState(blend, prepareStencil, screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandList.SetPipelineState(s)
|
||||
commandList.DrawIndexedInstanced(uint32(indexLen), 1, uint32(indexOffset), 0, 0)
|
||||
for _, dstRegion := range dstRegions {
|
||||
commandList.RSSetScissorRects([]_D3D12_RECT{
|
||||
{
|
||||
left: int32(dstRegion.Region.X),
|
||||
top: int32(dstRegion.Region.Y),
|
||||
right: int32(dstRegion.Region.X + dstRegion.Region.Width),
|
||||
bottom: int32(dstRegion.Region.Y + dstRegion.Region.Height),
|
||||
},
|
||||
})
|
||||
if evenOdd {
|
||||
s, err := shader.pipelineState(blend, prepareStencil, screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandList.SetPipelineState(s)
|
||||
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
||||
|
||||
s, err = shader.pipelineState(blend, drawWithStencil, screen)
|
||||
if err != nil {
|
||||
return err
|
||||
s, err = shader.pipelineState(blend, drawWithStencil, screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandList.SetPipelineState(s)
|
||||
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
||||
} else {
|
||||
s, err := shader.pipelineState(blend, noStencil, screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandList.SetPipelineState(s)
|
||||
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
||||
}
|
||||
commandList.SetPipelineState(s)
|
||||
commandList.DrawIndexedInstanced(uint32(indexLen), 1, uint32(indexOffset), 0, 0)
|
||||
} else {
|
||||
s, err := shader.pipelineState(blend, noStencil, screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandList.SetPipelineState(s)
|
||||
commandList.DrawIndexedInstanced(uint32(indexLen), 1, uint32(indexOffset), 0, 0)
|
||||
indexOffset += dstRegion.IndexCount
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -28,6 +28,11 @@ type Region struct {
|
||||
Height float32
|
||||
}
|
||||
|
||||
type DstRegion struct {
|
||||
Region Region
|
||||
IndexCount int
|
||||
}
|
||||
|
||||
const (
|
||||
InvalidImageID = 0
|
||||
InvalidShaderID = 0
|
||||
@ -52,7 +57,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.ShaderImageCount]ImageID, shader ShaderID, indexLen int, indexOffset int, blend Blend, dstRegion Region, uniforms [][]float32, evenOdd bool) error
|
||||
DrawTriangles(dst ImageID, srcs [graphics.ShaderImageCount]ImageID, shader ShaderID, dstRegions []DstRegion, indexOffset int, blend Blend, uniforms [][]float32, evenOdd bool) error
|
||||
}
|
||||
|
||||
// GraphicsNotReady represents that the graphics driver is not ready for recovering from the context lost.
|
||||
|
@ -421,7 +421,7 @@ func (g *Graphics) flushRenderCommandEncoderIfNeeded() {
|
||||
g.lastDst = nil
|
||||
}
|
||||
|
||||
func (g *Graphics) draw(dst *Image, dstRegion graphicsdriver.Region, srcs [graphics.ShaderImageCount]*Image, indexLen int, indexOffset int, shader *Shader, uniforms [][]float32, blend graphicsdriver.Blend, evenOdd bool) error {
|
||||
func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs [graphics.ShaderImageCount]*Image, indexOffset int, shader *Shader, uniforms [][]float32, blend graphicsdriver.Blend, evenOdd bool) error {
|
||||
// When prepareing a stencil buffer, flush the current render command encoder
|
||||
// to make sure the stencil buffer is cleared when loading.
|
||||
// TODO: What about clearing the stencil buffer by vertices?
|
||||
@ -473,12 +473,6 @@ func (g *Graphics) draw(dst *Image, dstRegion graphicsdriver.Region, srcs [graph
|
||||
ZNear: -1,
|
||||
ZFar: 1,
|
||||
})
|
||||
g.rce.SetScissorRect(mtl.ScissorRect{
|
||||
X: int(dstRegion.X),
|
||||
Y: int(dstRegion.Y),
|
||||
Width: int(dstRegion.Width),
|
||||
Height: int(dstRegion.Height),
|
||||
})
|
||||
g.rce.SetVertexBuffer(g.vb, 0, 0)
|
||||
|
||||
for i, u := range uniforms {
|
||||
@ -497,38 +491,60 @@ func (g *Graphics) draw(dst *Image, dstRegion graphicsdriver.Region, srcs [graph
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
prepareStencilRpss mtl.RenderPipelineState
|
||||
drawWithStencilRpss mtl.RenderPipelineState
|
||||
noStencilRpss mtl.RenderPipelineState
|
||||
)
|
||||
if evenOdd {
|
||||
prepareStencilRpss, err := shader.RenderPipelineState(&g.view, blend, prepareStencil, dst.screen)
|
||||
s, err := shader.RenderPipelineState(&g.view, blend, prepareStencil, dst.screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
drawWithStencilRpss, err := shader.RenderPipelineState(&g.view, blend, drawWithStencil, dst.screen)
|
||||
prepareStencilRpss = s
|
||||
|
||||
s, err = shader.RenderPipelineState(&g.view, blend, drawWithStencil, dst.screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g.rce.SetDepthStencilState(g.dsss[prepareStencil])
|
||||
g.rce.SetRenderPipelineState(prepareStencilRpss)
|
||||
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, indexLen, mtl.IndexTypeUInt16, g.ib, indexOffset*2)
|
||||
|
||||
g.rce.SetDepthStencilState(g.dsss[drawWithStencil])
|
||||
g.rce.SetRenderPipelineState(drawWithStencilRpss)
|
||||
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, indexLen, mtl.IndexTypeUInt16, g.ib, indexOffset*2)
|
||||
drawWithStencilRpss = s
|
||||
} else {
|
||||
rpss, err := shader.RenderPipelineState(&g.view, blend, noStencil, dst.screen)
|
||||
s, err := shader.RenderPipelineState(&g.view, blend, noStencil, dst.screen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
noStencilRpss = s
|
||||
}
|
||||
|
||||
g.rce.SetDepthStencilState(g.dsss[noStencil])
|
||||
g.rce.SetRenderPipelineState(rpss)
|
||||
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, indexLen, mtl.IndexTypeUInt16, g.ib, indexOffset*2)
|
||||
for _, dstRegion := range dstRegions {
|
||||
g.rce.SetScissorRect(mtl.ScissorRect{
|
||||
X: int(dstRegion.Region.X),
|
||||
Y: int(dstRegion.Region.Y),
|
||||
Width: int(dstRegion.Region.Width),
|
||||
Height: int(dstRegion.Region.Height),
|
||||
})
|
||||
|
||||
if evenOdd {
|
||||
g.rce.SetDepthStencilState(g.dsss[prepareStencil])
|
||||
g.rce.SetRenderPipelineState(prepareStencilRpss)
|
||||
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt16, g.ib, indexOffset*2)
|
||||
|
||||
g.rce.SetDepthStencilState(g.dsss[drawWithStencil])
|
||||
g.rce.SetRenderPipelineState(drawWithStencilRpss)
|
||||
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt16, g.ib, indexOffset*2)
|
||||
} else {
|
||||
g.rce.SetDepthStencilState(g.dsss[noStencil])
|
||||
g.rce.SetRenderPipelineState(noStencilRpss)
|
||||
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt16, g.ib, indexOffset*2)
|
||||
}
|
||||
|
||||
indexOffset += dstRegion.IndexCount
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, indexLen int, indexOffset int, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, uniforms [][]float32, evenOdd bool) error {
|
||||
func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms [][]float32, evenOdd bool) error {
|
||||
if shaderID == graphicsdriver.InvalidShaderID {
|
||||
return fmt.Errorf("metal: shader ID is invalid")
|
||||
}
|
||||
@ -586,7 +602,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
||||
}
|
||||
}
|
||||
|
||||
if err := g.draw(dst, dstRegion, srcs, indexLen, indexOffset, g.shaders[shaderID], uniformVars, blend, evenOdd); err != nil {
|
||||
if err := g.draw(dst, dstRegions, srcs, indexOffset, g.shaders[shaderID], uniformVars, blend, evenOdd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -180,7 +180,7 @@ func (g *Graphics) uniformVariableName(idx int) string {
|
||||
return name
|
||||
}
|
||||
|
||||
func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, indexLen int, indexOffset int, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, uniforms [][]float32, evenOdd bool) error {
|
||||
func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms [][]float32, evenOdd bool) error {
|
||||
if shaderID == graphicsdriver.InvalidShaderID {
|
||||
return fmt.Errorf("opengl: shader ID is invalid")
|
||||
}
|
||||
@ -192,12 +192,6 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
||||
if err := destination.setViewport(); err != nil {
|
||||
return err
|
||||
}
|
||||
g.context.scissor(
|
||||
int(dstRegion.X),
|
||||
int(dstRegion.Y),
|
||||
int(dstRegion.Width),
|
||||
int(dstRegion.Height),
|
||||
)
|
||||
g.context.blend(blend)
|
||||
|
||||
shader := g.shaders[shaderID]
|
||||
@ -248,11 +242,24 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
||||
return err
|
||||
}
|
||||
g.context.enableStencilTest()
|
||||
g.context.beginStencilWithEvenOddRule()
|
||||
g.context.drawElements(indexLen, indexOffset*2)
|
||||
g.context.endStencilWithEvenOddRule()
|
||||
}
|
||||
g.context.drawElements(indexLen, indexOffset*2) // 2 is uint16 size in bytes
|
||||
|
||||
for _, dstRegion := range dstRegions {
|
||||
g.context.scissor(
|
||||
int(dstRegion.Region.X),
|
||||
int(dstRegion.Region.Y),
|
||||
int(dstRegion.Region.Width),
|
||||
int(dstRegion.Region.Height),
|
||||
)
|
||||
if evenOdd {
|
||||
g.context.beginStencilWithEvenOddRule()
|
||||
g.context.drawElements(dstRegion.IndexCount, indexOffset*2)
|
||||
g.context.endStencilWithEvenOddRule()
|
||||
}
|
||||
g.context.drawElements(dstRegion.IndexCount, indexOffset*2) // 2 is uint16 size in bytes
|
||||
indexOffset += dstRegion.IndexCount
|
||||
}
|
||||
|
||||
if evenOdd {
|
||||
g.context.disableStencilTest()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user