private void initCommon() {
    setOpaque(true);
    setBackgroundColor(null);
    metalLayer = (CAMetalLayer) getLayer();
    device = MTLDevice.getSystemDefaultDevice();
    metalLayer.setDevice(device);
    metalLayer.setPixelFormat(MTLPixelFormat.BGRA8Unorm);

    // this is the default but if we wanted to perform compute on the final
    // rendering layer we could set this to false
    metalLayer.setFramebufferOnly(true);
  }
  public void setupRenderPassDescriptor(MTLTexture texture) {
    // create lazily
    if (renderPassDescriptor == null) {
      renderPassDescriptor = new MTLRenderPassDescriptor();
    }

    // create a color attachment every frame since we have to recreate the
    // texture every frame
    MTLRenderPassColorAttachmentDescriptor colorAttachment =
        renderPassDescriptor.getColorAttachments().get(0);
    colorAttachment.setTexture(texture);

    // make sure to clear every frame for best performance
    colorAttachment.setLoadAction(MTLLoadAction.Clear);
    colorAttachment.setClearColor(new MTLClearColor(0.65, 0.65, 0.65, 1.0));

    // if sample count is greater than 1, render into using MSAA, then
    // resolve into our color texture
    if (sampleCount > 1) {
      boolean doUpdate =
          msaaTex != null
              && ((msaaTex.getWidth() != texture.getWidth())
                  || (msaaTex.getHeight() != texture.getHeight())
                  || (msaaTex.getSampleCount() != sampleCount));

      if (msaaTex == null || (msaaTex != null && doUpdate)) {
        MTLTextureDescriptor desc =
            MTLTextureDescriptor.create2DDescriptor(
                MTLPixelFormat.BGRA8Unorm, texture.getWidth(), texture.getHeight(), false);
        desc.setTextureType(MTLTextureType._2DMultisample);

        // sample count was specified to the view by the renderer.
        // this must match the sample count given to any pipeline state
        // using this render pass descriptor
        desc.setSampleCount(sampleCount);

        msaaTex = device.newTexture(desc);
      }

      // When multisampling, perform rendering to _msaaTex, then resolve
      // to 'texture' at the end of the scene
      colorAttachment.setTexture(msaaTex);
      colorAttachment.setResolveTexture(texture);

      // set store action to resolve in this case
      colorAttachment.setStoreAction(MTLStoreAction.MultisampleResolve);
    } else {
      // store only attachments that will be presented to the screen, as
      // in this case
      colorAttachment.setStoreAction(MTLStoreAction.Store);
    } // color0

    // Now create the depth and stencil attachments

    if (depthPixelFormat != MTLPixelFormat.Invalid) {
      boolean doUpdate =
          depthTex != null
              && ((depthTex.getWidth() != texture.getWidth())
                  || (depthTex.getHeight() != texture.getHeight())
                  || (depthTex.getSampleCount() != sampleCount));

      if (depthTex == null || doUpdate) {
        // If we need a depth texture and don't have one, or if the
        // depth texture we have is the wrong size
        // Then allocate one of the proper size
        MTLTextureDescriptor desc =
            MTLTextureDescriptor.create2DDescriptor(
                depthPixelFormat, texture.getWidth(), texture.getHeight(), false);

        desc.setTextureType((sampleCount > 1) ? MTLTextureType._2DMultisample : MTLTextureType._2D);
        desc.setSampleCount(sampleCount);

        depthTex = device.newTexture(desc);

        MTLRenderPassDepthAttachmentDescriptor depthAttachment =
            renderPassDescriptor.getDepthAttachment();
        depthAttachment.setTexture(depthTex);
        depthAttachment.setLoadAction(MTLLoadAction.Clear);
        depthAttachment.setStoreAction(MTLStoreAction.DontCare);
        depthAttachment.setClearDepth(1.0);
      }
    } // depth

    if (stencilPixelFormat != MTLPixelFormat.Invalid) {
      boolean doUpdate =
          stencilTex != null
              && ((stencilTex.getWidth() != texture.getWidth())
                  || (stencilTex.getHeight() != texture.getHeight())
                  || (stencilTex.getSampleCount() != sampleCount));

      if (stencilTex == null || doUpdate) {
        // If we need a stencil texture and don't have one, or if the
        // depth texture we have is the wrong size
        // Then allocate one of the proper size
        MTLTextureDescriptor desc =
            MTLTextureDescriptor.create2DDescriptor(
                stencilPixelFormat, texture.getWidth(), texture.getHeight(), false);

        desc.setTextureType((sampleCount > 1) ? MTLTextureType._2DMultisample : MTLTextureType._2D);
        desc.setSampleCount(sampleCount);

        stencilTex = device.newTexture(desc);

        MTLRenderPassStencilAttachmentDescriptor stencilAttachment =
            renderPassDescriptor.getStencilAttachment();
        stencilAttachment.setTexture(stencilTex);
        stencilAttachment.setLoadAction(MTLLoadAction.Clear);
        stencilAttachment.setStoreAction(MTLStoreAction.DontCare);
        stencilAttachment.setClearStencil(0);
      }
    } // stencil
  }