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

@ -296,12 +296,12 @@ FragmentShaderFunc(0, FILTER_SCREEN, ADDRESS_UNSAFE)
` `
type rpsKey struct { type rpsKey struct {
useColorM bool useColorM bool
filter driver.Filter filter driver.Filter
address driver.Address address driver.Address
compositeMode driver.CompositeMode compositeMode driver.CompositeMode
colorWriteMask bool stencilMode stencilMode
screen bool screen bool
} }
type Graphics struct { type Graphics struct {
@ -315,7 +315,8 @@ type Graphics struct {
screenDrawable ca.MetalDrawable screenDrawable ca.MetalDrawable
lastDstTexture mtl.Texture lastDstTexture mtl.Texture
lastStencilMode stencilMode
vb mtl.Buffer vb mtl.Buffer
ib mtl.Buffer ib mtl.Buffer
@ -549,9 +550,8 @@ func (g *Graphics) Reset() error {
return err return err
} }
rpld := mtl.RenderPipelineDescriptor{ rpld := mtl.RenderPipelineDescriptor{
VertexFunction: vs, VertexFunction: vs,
FragmentFunction: fs, FragmentFunction: fs,
StencilAttachmentPixelFormat: mtl.PixelFormatStencil8,
} }
rpld.ColorAttachments[0].PixelFormat = g.view.colorPixelFormat() rpld.ColorAttachments[0].PixelFormat = g.view.colorPixelFormat()
rpld.ColorAttachments[0].BlendingEnabled = true rpld.ColorAttachments[0].BlendingEnabled = true
@ -578,7 +578,11 @@ func (g *Graphics) Reset() error {
driver.FilterLinear, driver.FilterLinear,
} { } {
for c := driver.CompositeModeSourceOver; c <= driver.CompositeModeMax; c++ { for c := driver.CompositeModeSourceOver; c <= driver.CompositeModeMax; c++ {
for _, cwm := range []bool{false, true} { for _, stencil := range []stencilMode{
prepareStencil,
drawWithStencil,
noStencil,
} {
cmi := 0 cmi := 0
if cm { if cm {
cmi = 1 cmi = 1
@ -588,9 +592,11 @@ func (g *Graphics) Reset() error {
return err return err
} }
rpld := mtl.RenderPipelineDescriptor{ rpld := mtl.RenderPipelineDescriptor{
VertexFunction: vs, VertexFunction: vs,
FragmentFunction: fs, FragmentFunction: fs,
StencilAttachmentPixelFormat: mtl.PixelFormatStencil8, }
if stencil != noStencil {
rpld.StencilAttachmentPixelFormat = mtl.PixelFormatStencil8
} }
pix := mtl.PixelFormatRGBA8UNorm pix := mtl.PixelFormatRGBA8UNorm
@ -605,22 +611,22 @@ func (g *Graphics) Reset() error {
rpld.ColorAttachments[0].DestinationRGBBlendFactor = operationToBlendFactor(dst) rpld.ColorAttachments[0].DestinationRGBBlendFactor = operationToBlendFactor(dst)
rpld.ColorAttachments[0].SourceAlphaBlendFactor = operationToBlendFactor(src) rpld.ColorAttachments[0].SourceAlphaBlendFactor = operationToBlendFactor(src)
rpld.ColorAttachments[0].SourceRGBBlendFactor = operationToBlendFactor(src) rpld.ColorAttachments[0].SourceRGBBlendFactor = operationToBlendFactor(src)
if cwm { if stencil == prepareStencil {
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskAll
} else {
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskNone rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskNone
} else {
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskAll
} }
rps, err := g.view.getMTLDevice().MakeRenderPipelineState(rpld) rps, err := g.view.getMTLDevice().MakeRenderPipelineState(rpld)
if err != nil { if err != nil {
return err return err
} }
g.rpss[rpsKey{ g.rpss[rpsKey{
screen: screen, screen: screen,
useColorM: cm, useColorM: cm,
filter: f, filter: f,
address: a, address: a,
compositeMode: c, compositeMode: c,
colorWriteMask: cwm, stencilMode: stencil,
}] = rps }] = 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 // When prepareing a stencil buffer, flush the current render command encoder
// to make sure the stencil buffer is cleared when loading. // to make sure the stencil buffer is cleared when loading.
// TODO: What about clearing the stencil buffer by vertices? // 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.flushRenderCommandEncoderIfNeeded()
} }
g.lastStencilMode = stencilMode
if g.rce == (mtl.RenderCommandEncoder{}) { if g.rce == (mtl.RenderCommandEncoder{}) {
rpd := mtl.RenderPassDescriptor{} 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)) g.rce.SetDepthStencilState(g.view.getMTLDevice().MakeDepthStencilState(desc))
case noStencil: 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) g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, indexLen, mtl.IndexTypeUInt16, g.ib, indexOffset*2)
@ -775,29 +796,26 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
srcs[i] = g.images[srcID] srcs[i] = g.images[srcID]
} }
var rpss [2]mtl.RenderPipelineState rpss := map[stencilMode]mtl.RenderPipelineState{}
var uniformVars []interface{} var uniformVars []interface{}
if shaderID == driver.InvalidShaderID { if shaderID == driver.InvalidShaderID {
if dst.screen && filter == driver.FilterScreen { if dst.screen && filter == driver.FilterScreen {
rpss[1] = g.screenRPS rpss[noStencil] = g.screenRPS
} else { } else {
useColorM := colorM != nil for _, stencil := range []stencilMode{
rpss[0] = g.rpss[rpsKey{ prepareStencil,
screen: dst.screen, drawWithStencil,
useColorM: useColorM, noStencil,
filter: filter, } {
address: address, rpss[stencil] = g.rpss[rpsKey{
compositeMode: mode, screen: dst.screen,
colorWriteMask: false, useColorM: colorM != nil,
}] filter: filter,
rpss[1] = g.rpss[rpsKey{ address: address,
screen: dst.screen, compositeMode: mode,
useColorM: useColorM, stencilMode: stencil,
filter: filter, }]
address: address, }
compositeMode: mode,
colorWriteMask: true,
}]
} }
w, h := dst.internalSize() w, h := dst.internalSize()
@ -826,14 +844,16 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
}, },
} }
} else { } else {
var err error for _, stencil := range []stencilMode{
rpss[0], err = g.shaders[shaderID].RenderPipelineState(g.view.getMTLDevice(), mode, false) prepareStencil,
if err != nil { drawWithStencil,
return err noStencil,
} } {
rpss[1], err = g.shaders[shaderID].RenderPipelineState(g.view.getMTLDevice(), mode, true) var err error
if err != nil { rpss[stencil], err = g.shaders[shaderID].RenderPipelineState(g.view.getMTLDevice(), mode, stencil)
return err if err != nil {
return err
}
} }
uniformVars = make([]interface{}, graphics.PreservedUniformVariablesNum+len(uniforms)) uniformVars = make([]interface{}, graphics.PreservedUniformVariablesNum+len(uniforms))
@ -885,14 +905,14 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
} }
if evenOdd { 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 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 return err
} }
} else { } 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 return err
} }
} }

View File

@ -27,8 +27,8 @@ import (
) )
type shaderRpsKey struct { type shaderRpsKey struct {
compositeMode driver.CompositeMode compositeMode driver.CompositeMode
colorWriteMask bool stencilMode stencilMode
} }
type Shader struct { type Shader struct {
@ -88,18 +88,20 @@ func (s *Shader) init(device mtl.Device) error {
return nil 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{ if rps, ok := s.rpss[shaderRpsKey{
compositeMode: compositeMode, compositeMode: compositeMode,
colorWriteMask: colorWriteMask, stencilMode: stencilMode,
}]; ok { }]; ok {
return rps, nil return rps, nil
} }
rpld := mtl.RenderPipelineDescriptor{ rpld := mtl.RenderPipelineDescriptor{
VertexFunction: s.vs, VertexFunction: s.vs,
FragmentFunction: s.fs, 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. // 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].DestinationRGBBlendFactor = operationToBlendFactor(dst)
rpld.ColorAttachments[0].SourceAlphaBlendFactor = operationToBlendFactor(src) rpld.ColorAttachments[0].SourceAlphaBlendFactor = operationToBlendFactor(src)
rpld.ColorAttachments[0].SourceRGBBlendFactor = operationToBlendFactor(src) rpld.ColorAttachments[0].SourceRGBBlendFactor = operationToBlendFactor(src)
if colorWriteMask { if stencilMode == prepareStencil {
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskAll
} else {
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskNone rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskNone
} else {
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskAll
} }
rps, err := device.MakeRenderPipelineState(rpld) rps, err := device.MakeRenderPipelineState(rpld)
@ -123,8 +125,8 @@ func (s *Shader) RenderPipelineState(device mtl.Device, compositeMode driver.Com
} }
s.rpss[shaderRpsKey{ s.rpss[shaderRpsKey{
compositeMode: compositeMode, compositeMode: compositeMode,
colorWriteMask: colorWriteMask, stencilMode: stencilMode,
}] = rps }] = rps
return rps, nil return rps, nil
} }