anchor.diff:  open Microsoft.FSharp.NativeInterop
   
   open Aardvark.Base
  +open Aardvark.Base.Rendering
   open Aardvark.Base.Incremental
   
   #nowarn "9"
  
positive.code: 
      interface IResource with
          member x.Level = x.Level
          member x.Outputs = x.Outputs
          member x.Update() = x.Update()
          member x.NeedsUpdate(i,f) = x.NeedsUpdate(i,f)
  
negative.code:         // CMD buffers need to be re-filled when descriptorsets get updated
          UpdateKind.HandleChanged
  
  type PipelineResource(  program : IResource<ShaderProgram>, 
                          vertexInputState : Map<Symbol, VertexInputDescription>, 
                          inputState : INativeResource<VkPipelineVertexInputStateCreateInfo>,
                          inputAssembly : INativeResource<VkPipelineInputAssemblyStateCreateInfo>,
                          rasterizerState : INativeResource<VkPipelineRasterizationStateCreateInfo>,
                          colorBlendState : INativeResource<VkPipelineColorBlendStateCreateInfo>,
                          multisample : MultisampleState,
                          depthStencil : INativeResource<VkPipelineDepthStencilStateCreateInfo>
                       ) =
      inherit AbstractResource<Pipeline, VkPipeline>(Seq.ofList [program :> IResource; inputState :> _; inputAssembly :> _; rasterizerState :> _; colorBlendState :> _; depthStencil :> _])
      static let check str err =
          if err <> VkResult.VkSuccess then failwithf "[Vulkan] %s" str
  
  
      let device = program.Handle.Device
  
      let create () =
          let prog = program.Handle
  
          prog.ShaderCreateInfos |> NativePtr.withA (fun pShaderCreateInfos ->
  
              let mutable viewportState =
                  let vp = prog.RenderPass.AttachmentCount
                  VkPipelineViewportStateCreateInfo(
                      VkStructureType.PipelineViewportStateCreateInfo, 0n,
                      VkPipelineViewportStateCreateFlags.MinValue,
                  
                      uint32 vp,
                      NativePtr.zero,
  
                      uint32 vp,
                      NativePtr.zero
                  )
  
              let pSampleMasks = NativePtr.pushStackArray multisample.sampleMask
              let mutable multisampleState =
                  let ms = multisample
                  VkPipelineMultisampleStateCreateInfo(
                      VkStructureType.PipelineMultisampleStateCreateInfo, 0n,
                      VkPipelineMultisampleStateCreateFlags.MinValue,
                  
                      unbox ms.samples,
                      (if ms.sampleShadingEnable then 1u else 0u),
                      float32 ms.minSampleShading,
                      pSampleMasks,
                      (if ms.alphaToCoverageEnable then 1u else 0u),
                      (if ms.alphaToOneEnable then 1u else 0u)
                  )
              
              let dynamicStates = [| VkDynamicState.Viewport; VkDynamicState.Scissor |]
          
              let pDynamicStates = NativePtr.pushStackArray dynamicStates
              
              let mutable dynamicStates =
                  VkPipelineDynamicStateCreateInfo(
                      VkStructureType.PipelineDynamicStateCreateInfo, 0n,
                      VkPipelineDynamicStateCreateFlags.MinValue, 
  
                      uint32 dynamicStates.Length,
                      pDynamicStates
                  )
  
              // TODO: tessellation input-patch-size
  
              let mutable desc =
                  VkGraphicsPipelineCreateInfo(
                      VkStructureType.GraphicsPipelineCreateInfo, 0n,
                      VkPipelineCreateFlags.None,
                      uint32 prog.ShaderCreateInfos.Length,
                      pShaderCreateInfos,
                      inputState.Pointer,
                      inputAssembly.Pointer,
                      NativePtr.zero, // tessellation
                      &&viewportState,
                      rasterizerState.Pointer,
                      &&multisampleState,
                      depthStencil.Pointer,
                      colorBlendState.Pointer,
                      &&dynamicStates, //dynamic
                      prog.PipelineLayout.Handle,
                      prog.RenderPass.Handle,
                      0u,
                      VkPipeline.Null,
                      0
                  )
  
              let mutable handle = VkPipeline.Null
              VkRaw.vkCreateGraphicsPipelines(device.Handle, VkPipelineCache.Null, 1u, &&desc, NativePtr.zero, &&handle)
                  |> check "could not create pipeline"
  
              Pipeline(device, handle, Unchecked.defaultof<_>)
          )
  
      let mutable current = create()
      let pointer = NativePtr.create current.Handle
  
      override x.PerformUpdate() =
          device.Delete current
          current <- create()
          NativePtr.write pointer current.Handle
          UpdateKind.HandleChanged
  
      override x.Destroy() =
          device.Delete current
          NativePtr.free pointer
  
      override x.Handle = current
      override x.Pointer = pointer
  
      override x.InputChanged(i : IResource, k : UpdateKind) =
          true
  
      override x.LockedInputs = HSet.empty
  
  type IndirectDrawCallResource(indexed : bool, calls : IResource<IndirectBuffer>) =
      inherit AbstractResource<DrawCall, DrawCall>([calls :> IResource])
  
      let mutable call = DrawCall.Indirect(indexed, calls.Handle)
      let mutable pointer = NativePtr.create call
  
      override x.PerformUpdate() =
          call.Dispose()
          call <- DrawCall.Indirect(indexed, calls.Handle)
          NativePtr.write pointer call
          UpdateKind.HandleChanged
  
      override x.Destroy() = 
          call.Dispose()
          NativePtr.free pointer
  
      override x.Handle = call
      override x.Pointer = pointer
  
      override x.LockedInputs = HSet.empty
      override x.InputChanged(_,_) = true
  
  type BufferBindingResource(buffers : list<IResource<Buffer> * int64>) =
      inherit AbstractResource<VertexBufferBinding, VertexBufferBinding>(buffers |> Seq.map fst |> Seq.cast)
  
      let create() =
          let bindings = buffers |> List.map (fun (r,o) -> r.Handle, o) |> List.toArray
          new VertexBufferBinding(0, bindings)
  
      let mutable handle = create()
      let pointer = NativePtr.create handle
  
      override x.PerformUpdate() =
          handle.Dispose()
          handle <- create()
          NativePtr.write pointer handle
          UpdateKind.HandleChanged
  
      override x.Destroy() =
          handle.Dispose()
          NativePtr.free pointer
  
      override x.InputChanged(r : IResource, kind : UpdateKind) =
          kind = UpdateKind.HandleChanged
  
      override x.LockedInputs = HSet.empty
      override x.Handle = handle
      override x.Pointer = pointer
  
  type DescriptorSetBindingResource(layout : PipelineLayout, sets : list<IResource<DescriptorSet>>) =
      inherit AbstractResource<DescriptorSetBinding, DescriptorSetBinding>(Seq.cast sets)
  
      let create() =
          let sets = sets |> List.map (fun r -> r.Handle) |> List.toArray
          new DescriptorSetBinding(layout, 0, sets)
  
      let mutable handle = create()
      let pointer = NativePtr.create handle
  
      override x.PerformUpdate() =
          handle.Dispose()
          handle <- create()
          NativePtr.write pointer handle
          UpdateKind.HandleChanged
  
      override x.Destroy() =
          handle.Dispose()
          NativePtr.free pointer
  
      override x.InputChanged(_,_) = true
  
      override x.Handle = handle
      override x.Pointer = pointer
      override x.LockedInputs = HSet.empty
   
  type IndexBufferBindingResource(indexType : VkIndexType, index : IResource<Buffer>) =
      inherit AbstractResource<IndexBufferBinding, IndexBufferBinding>([index :> IResource])
  
      let mutable handle = IndexBufferBinding(index.Handle.Handle, indexType)
      let pointer = NativePtr.create handle
  
      override x.PerformUpdate() =
          handle <- IndexBufferBinding(index.Handle.Handle, indexType)
          NativePtr.write pointer handle
          UpdateKind.HandleChanged
  
      override x.Destroy() =
          NativePtr.free pointer
  
      override x.InputChanged(r : IResource, k : UpdateKind) =
          k = UpdateKind.HandleChanged
  
      override x.Handle = handle
      override x.Pointer = pointer
      override x.LockedInputs = HSet.empty
  
  type ResourceCache() =
      let entries = System.Collections.Concurrent.ConcurrentDictionary<list<obj>, IResource>()
  
      member x.GetOrCreate(key : list<obj>, create : unit -> #IResource<'h, 'n>) =
          let result = 
              entries.GetOrAdd(key, fun _ ->
                  create() :> IResource
  