Add test with empty locations + fix directx 11 && 12 nil first argument

This commit is contained in:
Zyko 2024-04-13 13:56:13 +02:00
parent 0b53525808
commit d706d38ada
7 changed files with 65 additions and 25 deletions

View File

@ -36,9 +36,9 @@ var (
ebiten.NewImage(dstSize, dstSize), ebiten.NewImage(dstSize, dstSize),
ebiten.NewImage(dstSize, dstSize), ebiten.NewImage(dstSize, dstSize),
ebiten.NewImage(dstSize, dstSize),*/ ebiten.NewImage(dstSize, dstSize),*/
ebiten.NewImageWithOptions(image.Rect(0, 0, dstSize, dstSize), &ebiten.NewImageOptions{ nil,/*ebiten.NewImageWithOptions(image.Rect(0, 0, dstSize, dstSize), &ebiten.NewImageOptions{
Unmanaged: true, Unmanaged: true,
}), }),*/
ebiten.NewImageWithOptions(image.Rect(0, 0, dstSize, dstSize), &ebiten.NewImageOptions{ ebiten.NewImageWithOptions(image.Rect(0, 0, dstSize, dstSize), &ebiten.NewImageOptions{
Unmanaged: true, Unmanaged: true,
}), }),
@ -101,7 +101,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
indices := []uint16{0, 1, 2, 1, 2, 3} indices := []uint16{0, 1, 2, 1, 2, 3}
ebiten.DrawTrianglesShaderMRT(dsts, vertices, indices, s, nil) ebiten.DrawTrianglesShaderMRT(dsts, vertices, indices, s, nil)
// Dst 0 // Dst 0
screen.DrawImage(dsts[0], nil) //screen.DrawImage(dsts[0], nil)
// Dst 1 // Dst 1
opts := &ebiten.DrawImageOptions{} opts := &ebiten.DrawImageOptions{}
opts.GeoM.Translate(dstSize, 0) opts.GeoM.Translate(dstSize, 0)

View File

@ -711,10 +711,8 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader
// //
// When the image i is disposed, DrawTrianglesShader does nothing. // When the image i is disposed, DrawTrianglesShader does nothing.
func DrawTrianglesShaderMRT(dsts [graphics.ShaderDstImageCount]*Image, vertices []Vertex, indices []uint16, shader *Shader, options *DrawTrianglesShaderOptions) { func DrawTrianglesShaderMRT(dsts [graphics.ShaderDstImageCount]*Image, vertices []Vertex, indices []uint16, shader *Shader, options *DrawTrianglesShaderOptions) {
if dsts[0] == nil || dsts[0].isDisposed() {
panic("ebiten: the first destination image given to DrawTrianglesShaderMRT must not be nil or disposed")
}
var dstImgs [graphics.ShaderDstImageCount]*ui.Image var dstImgs [graphics.ShaderDstImageCount]*ui.Image
var firstDst *Image
for i, dst := range dsts { for i, dst := range dsts {
if dst == nil { if dst == nil {
continue continue
@ -723,6 +721,9 @@ func DrawTrianglesShaderMRT(dsts [graphics.ShaderDstImageCount]*Image, vertices
if dst.isDisposed() { if dst.isDisposed() {
panic("ebiten: the destination images given to DrawTrianglesShaderMRT must not be disposed") panic("ebiten: the destination images given to DrawTrianglesShaderMRT must not be disposed")
} }
if firstDst == nil {
firstDst = dst
}
dstImgs[i] = dst.image dstImgs[i] = dst.image
} }
@ -754,7 +755,7 @@ func DrawTrianglesShaderMRT(dsts [graphics.ShaderDstImageCount]*Image, vertices
blend = options.CompositeMode.blend().internalBlend() blend = options.CompositeMode.blend().internalBlend()
} }
dst := dsts[0] dst := firstDst
vs := dst.ensureTmpVertices(len(vertices) * graphics.VertexFloatCount) vs := dst.ensureTmpVertices(len(vertices) * graphics.VertexFloatCount)
src := options.Images[0] src := options.Images[0]
for i, v := range vertices { for i, v := range vertices {

View File

@ -576,12 +576,14 @@ func drawTrianglesMRT(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.
src.backend.sourceInThisFrame = true src.backend.sourceInThisFrame = true
} }
var firstDst *Image
var dstImgs [graphics.ShaderDstImageCount]*graphicscommand.Image var dstImgs [graphics.ShaderDstImageCount]*graphicscommand.Image
for i, dst := range dsts { for i, dst := range dsts {
if dst == nil { if dst == nil {
continue continue
} }
dst.ensureIsolatedFromSource(backends) dst.ensureIsolatedFromSource(backends)
firstDst = dst
dstImgs[i] = dst.backend.image dstImgs[i] = dst.backend.image
} }
@ -595,7 +597,7 @@ func drawTrianglesMRT(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.
} }
} }
r := dsts[0].regionWithPadding() r := firstDst.regionWithPadding()
// TODO: Check if dstRegion does not to violate the region. // TODO: Check if dstRegion does not to violate the region.
dstRegion = dstRegion.Add(r.Min) dstRegion = dstRegion.Add(r.Min)

View File

@ -330,7 +330,14 @@ func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shade
copy(uniforms[graphics.PreservedUniformUint32Count:], origUniforms) copy(uniforms[graphics.PreservedUniformUint32Count:], origUniforms)
// Set the destination texture size. // Set the destination texture size.
dw, dh := dsts[0].InternalSize() var firstDst *Image
for _, dst := range dsts {
if dst != nil {
firstDst = dst
break
}
}
dw, dh := firstDst.InternalSize()
uniforms[0] = math.Float32bits(float32(dw)) uniforms[0] = math.Float32bits(float32(dw))
uniforms[1] = math.Float32bits(float32(dh)) uniforms[1] = math.Float32bits(float32(dh))
uniformIndex := 2 uniformIndex := 2

View File

@ -517,6 +517,7 @@ func (g *graphics11) removeShader(s *shader11) {
func (g *graphics11) setAsRenderTargets(dsts []*image11, useStencil bool) error { func (g *graphics11) setAsRenderTargets(dsts []*image11, useStencil bool) error {
var rtvs []*_ID3D11RenderTargetView var rtvs []*_ID3D11RenderTargetView
var dsv *_ID3D11DepthStencilView
for _, i := range dsts { for _, i := range dsts {
// Ignore a nil image in case of MRT // Ignore a nil image in case of MRT
if i == nil { if i == nil {
@ -532,7 +533,7 @@ func (g *graphics11) setAsRenderTargets(dsts []*image11, useStencil bool) error
} }
rtvs = append(rtvs, i.renderTargetView) rtvs = append(rtvs, i.renderTargetView)
if !useStencil { if !useStencil || dsv != nil {
continue continue
} }
@ -567,12 +568,13 @@ func (g *graphics11) setAsRenderTargets(dsts []*image11, useStencil bool) error
return err return err
} }
i.stencilView = sv i.stencilView = sv
dsv = sv
} }
} }
g.deviceContext.OMSetRenderTargets(rtvs, dsts[0].stencilView) g.deviceContext.OMSetRenderTargets(rtvs, dsv)
if useStencil { if useStencil {
g.deviceContext.ClearDepthStencilView(dsts[0].stencilView, uint8(_D3D11_CLEAR_STENCIL), 0, 0) g.deviceContext.ClearDepthStencilView(dsv, uint8(_D3D11_CLEAR_STENCIL), 0, 0)
} }
return nil return nil
@ -585,7 +587,7 @@ func (g *graphics11) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics
g.deviceContext.PSSetShaderResources(0, srvs[:]) g.deviceContext.PSSetShaderResources(0, srvs[:])
var dsts [graphics.ShaderDstImageCount]*image11 var dsts [graphics.ShaderDstImageCount]*image11
var viewports [graphics.ShaderDstImageCount]_D3D11_VIEWPORT var vp _D3D11_VIEWPORT
var targetCount int var targetCount int
firstTarget := -1 firstTarget := -1
for i, id := range dstIDs { for i, id := range dstIDs {
@ -598,7 +600,7 @@ func (g *graphics11) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics
} }
dsts[i] = img dsts[i] = img
w, h := img.internalSize() w, h := img.internalSize()
viewports[i] = _D3D11_VIEWPORT{ vp = _D3D11_VIEWPORT{
TopLeftX: 0, TopLeftX: 0,
TopLeftY: 0, TopLeftY: 0,
Width: float32(w), Width: float32(w),
@ -621,13 +623,12 @@ func (g *graphics11) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics
// If the number of targets is more than one, or if the only target is the first one, then // If the number of targets is more than one, or if the only target is the first one, then
// it is safe to assume that MRT is used. // it is safe to assume that MRT is used.
// Also, it only matters in order to specify empty targets/viewports when not all slots are // Also, it only matters in order to specify empty targets/viewports when not all slots are
// being filled. // being filled, even though it's not a MRT scenario.
if targetCount > 1 || firstTarget > 0 { if targetCount > 1 || firstTarget > 0 {
targetCount = graphics.ShaderDstImageCount targetCount = graphics.ShaderDstImageCount
} }
g.deviceContext.RSSetViewports(viewports[:targetCount])
g.deviceContext.RSSetViewports([]_D3D11_VIEWPORT{vp})
if err := g.setAsRenderTargets(dsts[:targetCount], fillRule != graphicsdriver.FillAll); err != nil { if err := g.setAsRenderTargets(dsts[:targetCount], fillRule != graphicsdriver.FillAll); err != nil {
return err return err
} }

View File

@ -1177,7 +1177,7 @@ func (g *graphics12) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics
var resourceBarriers []_D3D12_RESOURCE_BARRIER_Transition var resourceBarriers []_D3D12_RESOURCE_BARRIER_Transition
var dsts [graphics.ShaderDstImageCount]*image12 var dsts [graphics.ShaderDstImageCount]*image12
var viewports [graphics.ShaderDstImageCount]_D3D12_VIEWPORT var vp _D3D12_VIEWPORT
var targetCount int var targetCount int
firstTarget := -1 firstTarget := -1
for i, id := range dstIDs { for i, id := range dstIDs {
@ -1190,7 +1190,7 @@ func (g *graphics12) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics
} }
dsts[i] = img dsts[i] = img
w, h := img.internalSize() w, h := img.internalSize()
viewports[i] = _D3D12_VIEWPORT{ vp = _D3D12_VIEWPORT{
TopLeftX: 0, TopLeftX: 0,
TopLeftY: 0, TopLeftY: 0,
Width: float32(w), Width: float32(w),
@ -1231,8 +1231,7 @@ func (g *graphics12) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics
targetCount = graphics.ShaderDstImageCount targetCount = graphics.ShaderDstImageCount
} }
g.drawCommandList.RSSetViewports(viewports[:targetCount]) g.drawCommandList.RSSetViewports([]_D3D12_VIEWPORT{vp})
if err := g.setAsRenderTargets(dsts[:targetCount], fillRule != graphicsdriver.FillAll); err != nil { if err := g.setAsRenderTargets(dsts[:targetCount], fillRule != graphicsdriver.FillAll); err != nil {
return err return err
} }

View File

@ -2652,7 +2652,7 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) (vec4, vec4, vec4, vec4, vec
}, },
} }
indices := []uint16{0, 1, 2, 1, 2, 3} indices := []uint16{0, 1, 2, 1, 2, 3}
t.Run("8 slots", func(t *testing.T) { t.Run("8 locations", func(t *testing.T) {
wantColors := [8]color.RGBA{ wantColors := [8]color.RGBA{
{R: 0xff, G: 0, B: 0, A: 0xff}, {R: 0xff, G: 0, B: 0, A: 0xff},
{R: 0, G: 0xff, B: 0, A: 0xff}, {R: 0, G: 0xff, B: 0, A: 0xff},
@ -2663,9 +2663,8 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) (vec4, vec4, vec4, vec4, vec
{R: 0xff, G: 0xff, B: 0xff, A: 0xff}, {R: 0xff, G: 0xff, B: 0xff, A: 0xff},
{R: 0xff, G: 0xff, B: 0xff, A: 0}, {R: 0xff, G: 0xff, B: 0xff, A: 0},
} }
dsts := imgs ebiten.DrawTrianglesShaderMRT(imgs, vertices, indices, s, nil)
ebiten.DrawTrianglesShaderMRT(dsts, vertices, indices, s, nil) for k, dst := range imgs {
for k, dst := range dsts {
for j := 0; j < h; j++ { for j := 0; j < h; j++ {
for i := 0; i < w; i++ { for i := 0; i < w; i++ {
got := dst.At(i, j).(color.RGBA) got := dst.At(i, j).(color.RGBA)
@ -2677,4 +2676,35 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) (vec4, vec4, vec4, vec4, vec
} }
} }
}) })
for _, img := range imgs {
img.Clear()
}
t.Run("Empty locations", func(t *testing.T) {
wantColors := [8]color.RGBA{
{},
{R: 0, G: 0xff, B: 0, A: 0xff},
{},
{R: 0xff, G: 0, B: 0xff, A: 0xff},
{},
{R: 0, G: 0xff, B: 0xff, A: 0xff},
{},
{R: 0xff, G: 0xff, B: 0xff, A: 0},
}
dsts := [8]*ebiten.Image{
nil, imgs[1], nil, imgs[3], nil, imgs[5], nil, imgs[7],
}
ebiten.DrawTrianglesShaderMRT(dsts, vertices, indices, s, nil)
for k, dst := range imgs {
for j := 0; j < h; j++ {
for i := 0; i < w; i++ {
got := dst.At(i, j).(color.RGBA)
want := wantColors[k]
if !sameColors(got, want, 1) {
t.Errorf("%d dst.At(%d, %d): got: %v, want: %v", k, i, j, got, want)
}
}
}
}
})
} }