Drawing text with macOS 10.15

I have some code that works fine on macOS 10.14, here is what I get:


And here is what it looks like on macOS 10.15 (notice how the background is not blue anymore and the text, barely visible, is twice as wide and therefore gets cropped):


Does anyone have an idea what could be the problem?


Here is the code:


AppDelegate.swift

import Cocoa
import MetalKit

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, MTKViewDelegate {

    struct Vertex {
        var position: vector_float2
        var textureCoordinates: vector_float2
  
        init(position: vector_float2, textureCoordinates: vector_float2) {
            self.position = position
            self.textureCoordinates = textureCoordinates
        }
    }

    @IBOutlet var window: NSWindow!

    var commandQueue: MTLCommandQueue!
    var texturePipelineState: MTLRenderPipelineState!
    var texture: MTLTexture!
    var textFrame = NSRect.zero

    func applicationWillFinishLaunching(_ aNotification: Notification) {
        let mtkView = window.contentView as! MTKView
        mtkView.delegate = self
        mtkView.clearColor = .init(red: 1, green: 1, blue: 1, alpha: 1)
        let device = MTLCreateSystemDefaultDevice()!
        mtkView.device = device
        mtkView.isPaused = true
        mtkView.enableSetNeedsDisplay = true
        let defaultLibrary = device.makeDefaultLibrary()!
        let texturePipelineDescriptor = MTLRenderPipelineDescriptor()
        texturePipelineDescriptor.vertexFunction = defaultLibrary.makeFunction(name: "textureVertexShader")
        texturePipelineDescriptor.fragmentFunction = defaultLibrary.makeFunction(name: "textureFragmentShader")
        texturePipelineDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat
        texturePipelineDescriptor.colorAttachments[0].isBlendingEnabled = true
        texturePipelineDescriptor.colorAttachments[0].rgbBlendOperation = .add
        texturePipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
        texturePipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
        texturePipelineState = try! device.makeRenderPipelineState(descriptor: texturePipelineDescriptor)
        commandQueue = device.makeCommandQueue()
  
        let textureDescriptor = MTLTextureDescriptor()
        textureDescriptor.pixelFormat = mtkView.colorPixelFormat
        let attributedString = NSAttributedString(string: "asdf", attributes: [.font: NSFontManager.shared.convert(.labelFont(ofSize: 15), toHaveTrait: .boldFontMask), .foregroundColor: NSColor.white])
        let frameSize = attributedString.size()
        let image = NSImage(size: frameSize)
        image.lockFocus()
        textFrame = NSRect(x: 0, y: 0, width: frameSize.width, height: frameSize.height)
        if true {
            NSColor.red.set()
            NSBezierPath(rect: textFrame).fill()
        }
        attributedString.draw(in: textFrame)
        let bitmap = NSBitmapImageRep(focusedViewRect: textFrame)!
        image.unlockFocus()
        let textureSize = NSSize(width: CGFloat(bitmap.pixelsWide), height: CGFloat(bitmap.pixelsHigh))
        textureDescriptor.width = Int(textureSize.width)
        textureDescriptor.height = Int(textureSize.height)
        texture = device.makeTexture(descriptor: textureDescriptor)!
        let region = MTLRegionMake2D(0, 0, Int(textureSize.width), Int(textureSize.height))
        texture.replace(region: region, mipmapLevel: 0, withBytes: bitmap.bitmapData!, bytesPerRow: bitmap.bytesPerRow)
    }

    func draw(in view: MTKView) {
        guard let currentDrawable = view.currentDrawable, let renderPassDescriptor = view.currentRenderPassDescriptor else {
            return
        }
        let commandBuffer = commandQueue.makeCommandBuffer()!
        let renderCommandEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor)!
        let viewSize = view.frame.size
        var viewportSize = vector_uint2(x: UInt32(viewSize.width), y: UInt32(viewSize.height))
        renderCommandEncoder.setVertexBytes(&viewportSize, length: MemoryLayout<vector_uint2>.size, index: Int(VertexInputIndexViewportSize.rawValue))
  
        renderCommandEncoder.setRenderPipelineState(texturePipelineState)
        let vertices = [Vertex(position: vector_float2(Float(textFrame.minX), Float(textFrame.minY)), textureCoordinates: vector_float2(0, 1)),
                        Vertex(position: vector_float2(Float(textFrame.maxX), Float(textFrame.minY)), textureCoordinates: vector_float2(1, 1)),
                        Vertex(position: vector_float2(Float(textFrame.minX), Float(textFrame.maxY)), textureCoordinates: vector_float2(0, 0)),
                        Vertex(position: vector_float2(Float(textFrame.maxX), Float(textFrame.maxY)), textureCoordinates: vector_float2(1, 0))]
        renderCommandEncoder.setVertexBytes(vertices, length: MemoryLayout.size * vertices.count, index: Int(VertexInputIndexVertices.rawValue))
        renderCommandEncoder.setFragmentTexture(texture, index: Int(FragmentInputIndexTexture.rawValue))
        renderCommandEncoder.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 4)

        renderCommandEncoder.endEncoding()
        commandBuffer.present(currentDrawable)
        commandBuffer.commit()
    }

    func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
    }

}


ShaderTypes.h

#import 

typedefenum VertexInputIndex: int {
    VertexInputIndexVertices = 0,
    VertexInputIndexViewportSize = 1,
} VertexInputIndex;

typedef enum FragmentInputIndex: int {
    FragmentInputIndexTexture = 0,
} FragmentInputIndex;

typedef struct {
    vector_float2 position;
    vector_float2 textureCoordinates;
} Vertex;


Shaders.metal

#include <metal_stdlib>
#include "ShaderTypes.h"

using namespace metal;

typedef struct {
    float4 clipSpacePosition [[position]];
    float2 textureCoordinates;
} TextureRasterizerData;

vertex TextureRasterizerData textureVertexShader(uint vertexID [[vertex_id]],
                                          constant Vertex *texturedVertices [[buffer(VertexInputIndexVertices)]],
                                          constant vector_uint2 *viewportSizePointer [[buffer(VertexInputIndexViewportSize)]]) {
    TextureRasterizerData out;
    out.clipSpacePosition = float4(0.0, 0.0, 0.0, 1.0);
    float2 pixelSpacePosition = texturedVertices[vertexID].position;
    float2 viewportSize = float2(*viewportSizePointer);
    out.clipSpacePosition.xy = pixelSpacePosition / (viewportSize / 2.0);
    out.textureCoordinates = texturedVertices[vertexID].textureCoordinates;
    return out;
}

constexpr sampler textureSampler (mag_filter::linear, min_filter::linear);

fragment float4 textureFragmentShader(TextureRasterizerData in [[stage_in]],
                               texture2d colorTexture [[texture(FragmentInputIndexTexture)]]) {
    half4 colorSample = colorTexture.sample(textureSampler, in.textureCoordinates);
    return float4(colorSample);
}

Replies

Does anybody now why images are only displayed while editing the post, but not once it is submitted?