问题
I am working on a metal-backed painting application in which I divide the drawing of a stroke in two steps: the first step draws the leading edge of a stroke to screen and captures the entire to an MTLTexture via:
metalTextureComposite = self.currentDrawable!.texture
the second step draws an updated leading edge of the advancing stroke, and composites atop a polygon textured with the last saved metalTextureComposite.
This method allows me to draw infinitely long strokes without sacrificing performance, as these two steps get repeated for each frame of the drawing cycle.
The problem I'm having is that, using the desired source-over composite mode (see below code), I am only seeing the leading edge of the stroke being drawn to screen. This tells me that either I am not adequately capturing metalTextureComposite from the currentDrawable, or that I am making the wrong assumptions regarding the blending mode to use, which incidentally is as follows:
renderPipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
renderPipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
renderPipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha
renderPipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha
If I use different blending modes, I do see the entirety of the stroke being drawn, but not necessarily the appearance I'm after. Below is the part of the code I'm including inside the MTKView's draw() method.
func metalRenderStampArray() {
// first encode uber-stamp with previous loop's metalTextureComposite in a background polygon
// note metalTexture= metalTextureComposite contains previous loop's drawable contents
metalCommandEncode(renderCommandEncoder: renderCommandEncoder, stampLayer: stampLayerMode.stampLayerBG, vertexArrayStamps: vertexArrayStampsBG, metalTexture: metalTextureComposite) // background uber-stamp
// empty out uber-stamp in preparation for the next cycle
initializeStampArrays(stampLayer: stampLayerMode.stampLayerBG)
// next, encode current subCurve chunk polygons in foreground
// note metalTexture=brushTexture.texture is a round brush texture with alpha
metalCommandEncode(renderCommandEncoder: renderCommandEncoder, stampLayer: stampLayerMode.stampLayerFG, vertexArrayStamps: vertexArrayStampsFG, metalTexture: brushTexture.texture) // foreground sub-curve chunk
renderCommandEncoder?.endEncoding() // finalize renderEncoder set up
// now present bg + fg composite which is where I see the problem
commandBuffer?.present(self.currentDrawable!)
// 7b. Render to pipeline
commandBuffer?.commit() // commit and send task to gpu
metalTextureComposite = nil // empty out before re-populating
metalTextureComposite = self.currentDrawable!.texture // set up bg texture for next iteration
metalStampComputeComposite() // compute coordinates for the background composite stamp for the next iteration
} // end of func metalRenderStampArray()
Should I be handling metalTextureComposite differently (since it is being written to at 1/fps) and if so, how should I handle it? The goal is to use a single blending mode for the background poly and the leading stroke polygons. Any help would be appreciated.
回答1:
You seem to be storing a reference to drawable's texture and then using it the next frame.
I can see 2 possible problems with this: - at the next frame draw cycle, the previous frame's texture might not yet be drawn to by the graphics processor - drawable's texture might be used by the system and app's code at the same time
I'd suggest try copy drawable's texture for your use in commandBuffer?.addCompletedHandler { }
来源:https://stackoverflow.com/questions/55272262/mtkview-blend-issues-when-re-using-currentdrawable-texture-in-draw-loop