internal/graphicsdriver/metal: Bug fix: Crashed with METAL_DEVICE_WRAPPER_TYPE=1

Closes #1697
This commit is contained in:
Hajime Hoshi 2021-07-06 14:05:01 +09:00
parent 315f87896b
commit 17d8cb5311
2 changed files with 90 additions and 68 deletions

View File

@ -300,7 +300,7 @@ type rpsKey struct {
filter driver.Filter
address driver.Address
compositeMode driver.CompositeMode
colorWriteMask bool
stencilMode stencilMode
screen bool
}
@ -316,6 +316,7 @@ type Graphics struct {
screenDrawable ca.MetalDrawable
lastDstTexture mtl.Texture
lastStencilMode stencilMode
vb mtl.Buffer
ib mtl.Buffer
@ -551,7 +552,6 @@ func (g *Graphics) Reset() error {
rpld := mtl.RenderPipelineDescriptor{
VertexFunction: vs,
FragmentFunction: fs,
StencilAttachmentPixelFormat: mtl.PixelFormatStencil8,
}
rpld.ColorAttachments[0].PixelFormat = g.view.colorPixelFormat()
rpld.ColorAttachments[0].BlendingEnabled = true
@ -578,7 +578,11 @@ func (g *Graphics) Reset() error {
driver.FilterLinear,
} {
for c := driver.CompositeModeSourceOver; c <= driver.CompositeModeMax; c++ {
for _, cwm := range []bool{false, true} {
for _, stencil := range []stencilMode{
prepareStencil,
drawWithStencil,
noStencil,
} {
cmi := 0
if cm {
cmi = 1
@ -590,7 +594,9 @@ func (g *Graphics) Reset() error {
rpld := mtl.RenderPipelineDescriptor{
VertexFunction: vs,
FragmentFunction: fs,
StencilAttachmentPixelFormat: mtl.PixelFormatStencil8,
}
if stencil != noStencil {
rpld.StencilAttachmentPixelFormat = mtl.PixelFormatStencil8
}
pix := mtl.PixelFormatRGBA8UNorm
@ -605,10 +611,10 @@ func (g *Graphics) Reset() error {
rpld.ColorAttachments[0].DestinationRGBBlendFactor = operationToBlendFactor(dst)
rpld.ColorAttachments[0].SourceAlphaBlendFactor = operationToBlendFactor(src)
rpld.ColorAttachments[0].SourceRGBBlendFactor = operationToBlendFactor(src)
if cwm {
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskAll
} else {
if stencil == prepareStencil {
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskNone
} else {
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskAll
}
rps, err := g.view.getMTLDevice().MakeRenderPipelineState(rpld)
if err != nil {
@ -620,7 +626,7 @@ func (g *Graphics) Reset() error {
filter: f,
address: a,
compositeMode: c,
colorWriteMask: cwm,
stencilMode: stencil,
}] = rps
}
}
@ -646,9 +652,10 @@ func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion drive
// 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?
if g.lastDstTexture != dst.mtlTexture() || stencilMode == prepareStencil {
if g.lastDstTexture != dst.mtlTexture() || (g.lastStencilMode == noStencil) != (stencilMode == noStencil) {
g.flushRenderCommandEncoderIfNeeded()
}
g.lastStencilMode = stencilMode
if g.rce == (mtl.RenderCommandEncoder{}) {
rpd := mtl.RenderPassDescriptor{}
@ -755,7 +762,21 @@ func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion drive
}
g.rce.SetDepthStencilState(g.view.getMTLDevice().MakeDepthStencilState(desc))
case noStencil:
g.rce.SetDepthStencilState(mtl.DepthStencilState{})
desc := mtl.DepthStencilDescriptor{
BackFaceStencil: mtl.StencilDescriptor{
StencilFailureOperation: mtl.StencilOperationKeep,
DepthFailureOperation: mtl.StencilOperationKeep,
DepthStencilPassOperation: mtl.StencilOperationKeep,
StencilCompareFunction: mtl.CompareFunctionAlways,
},
FrontFaceStencil: mtl.StencilDescriptor{
StencilFailureOperation: mtl.StencilOperationKeep,
DepthFailureOperation: mtl.StencilOperationKeep,
DepthStencilPassOperation: mtl.StencilOperationKeep,
StencilCompareFunction: mtl.CompareFunctionAlways,
},
}
g.rce.SetDepthStencilState(g.view.getMTLDevice().MakeDepthStencilState(desc))
}
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, indexLen, mtl.IndexTypeUInt16, g.ib, indexOffset*2)
@ -775,30 +796,27 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
srcs[i] = g.images[srcID]
}
var rpss [2]mtl.RenderPipelineState
rpss := map[stencilMode]mtl.RenderPipelineState{}
var uniformVars []interface{}
if shaderID == driver.InvalidShaderID {
if dst.screen && filter == driver.FilterScreen {
rpss[1] = g.screenRPS
rpss[noStencil] = g.screenRPS
} else {
useColorM := colorM != nil
rpss[0] = g.rpss[rpsKey{
for _, stencil := range []stencilMode{
prepareStencil,
drawWithStencil,
noStencil,
} {
rpss[stencil] = g.rpss[rpsKey{
screen: dst.screen,
useColorM: useColorM,
useColorM: colorM != nil,
filter: filter,
address: address,
compositeMode: mode,
colorWriteMask: false,
}]
rpss[1] = g.rpss[rpsKey{
screen: dst.screen,
useColorM: useColorM,
filter: filter,
address: address,
compositeMode: mode,
colorWriteMask: true,
stencilMode: stencil,
}]
}
}
w, h := dst.internalSize()
sourceSize := []float32{0, 0}
@ -826,14 +844,16 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
},
}
} else {
for _, stencil := range []stencilMode{
prepareStencil,
drawWithStencil,
noStencil,
} {
var err error
rpss[0], err = g.shaders[shaderID].RenderPipelineState(g.view.getMTLDevice(), mode, false)
rpss[stencil], err = g.shaders[shaderID].RenderPipelineState(g.view.getMTLDevice(), mode, stencil)
if err != nil {
return err
}
rpss[1], err = g.shaders[shaderID].RenderPipelineState(g.view.getMTLDevice(), mode, true)
if err != nil {
return err
}
uniformVars = make([]interface{}, graphics.PreservedUniformVariablesNum+len(uniforms))
@ -885,14 +905,14 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
}
if evenOdd {
if err := g.draw(rpss[0], dst, dstRegion, srcs, indexLen, indexOffset, uniformVars, prepareStencil); err != nil {
if err := g.draw(rpss[prepareStencil], dst, dstRegion, srcs, indexLen, indexOffset, uniformVars, prepareStencil); err != nil {
return err
}
if err := g.draw(rpss[1], dst, dstRegion, srcs, indexLen, indexOffset, uniformVars, drawWithStencil); err != nil {
if err := g.draw(rpss[drawWithStencil], dst, dstRegion, srcs, indexLen, indexOffset, uniformVars, drawWithStencil); err != nil {
return err
}
} else {
if err := g.draw(rpss[1], dst, dstRegion, srcs, indexLen, indexOffset, uniformVars, noStencil); err != nil {
if err := g.draw(rpss[noStencil], dst, dstRegion, srcs, indexLen, indexOffset, uniformVars, noStencil); err != nil {
return err
}
}

View File

@ -28,7 +28,7 @@ import (
type shaderRpsKey struct {
compositeMode driver.CompositeMode
colorWriteMask bool
stencilMode stencilMode
}
type Shader struct {
@ -88,10 +88,10 @@ func (s *Shader) init(device mtl.Device) error {
return nil
}
func (s *Shader) RenderPipelineState(device mtl.Device, compositeMode driver.CompositeMode, colorWriteMask bool) (mtl.RenderPipelineState, error) {
func (s *Shader) RenderPipelineState(device mtl.Device, compositeMode driver.CompositeMode, stencilMode stencilMode) (mtl.RenderPipelineState, error) {
if rps, ok := s.rpss[shaderRpsKey{
compositeMode: compositeMode,
colorWriteMask: colorWriteMask,
stencilMode: stencilMode,
}]; ok {
return rps, nil
}
@ -99,7 +99,9 @@ func (s *Shader) RenderPipelineState(device mtl.Device, compositeMode driver.Com
rpld := mtl.RenderPipelineDescriptor{
VertexFunction: s.vs,
FragmentFunction: s.fs,
StencilAttachmentPixelFormat: mtl.PixelFormatStencil8,
}
if stencilMode != noStencil {
rpld.StencilAttachmentPixelFormat = mtl.PixelFormatStencil8
}
// TODO: For the precise pixel format, whether the render target is the screen or not must be considered.
@ -111,10 +113,10 @@ func (s *Shader) RenderPipelineState(device mtl.Device, compositeMode driver.Com
rpld.ColorAttachments[0].DestinationRGBBlendFactor = operationToBlendFactor(dst)
rpld.ColorAttachments[0].SourceAlphaBlendFactor = operationToBlendFactor(src)
rpld.ColorAttachments[0].SourceRGBBlendFactor = operationToBlendFactor(src)
if colorWriteMask {
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskAll
} else {
if stencilMode == prepareStencil {
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskNone
} else {
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskAll
}
rps, err := device.MakeRenderPipelineState(rpld)
@ -124,7 +126,7 @@ func (s *Shader) RenderPipelineState(device mtl.Device, compositeMode driver.Com
s.rpss[shaderRpsKey{
compositeMode: compositeMode,
colorWriteMask: colorWriteMask,
stencilMode: stencilMode,
}] = rps
return rps, nil
}