anchor.diff:                  | Error err ->
                       Error err
                       
  +        member x.TryGetProgramBinary(prog : Program) =
  +            use __ = x.ResourceLock
  +
  +            let mutable length = 0
  +            GL.GetProgram(prog.Handle, unbox 0x8741, &length)
  +            let err = GL.GetError()
  +            if err <> ErrorCode.NoError then 
  +                None
  +            else
  +                let data : byte[] = Array.zeroCreate length
  +                let mutable format = Unchecked.defaultof<BinaryFormat>
  +                GL.GetProgramBinary(prog.Handle, length, &length, &format, data)
  +                let err = GL.GetError()
  +                if err <> ErrorCode.NoError then 
  +                    None
  +                else
  +                    Some (format, data)
  +
  +
  +
           member x.TryCompileProgram(fboSignature : Map<string, int>, expectsRowMajorMatrices : bool, code : string) =
               using x.ResourceLock (fun _ ->
                   match x |> ShaderCompiler.tryCompileShaders true code with
  
positive.code:  
      let private codeCache = ConcurrentDictionary<Context * string * IFramebufferSignature, Error<FShade.GLSL.GLSLProgramInterface * Program>>()
      let private shaderCache = ConcurrentDictionary<Context * Surface * IFramebufferSignature, Error<FShade.GLSL.GLSLProgramInterface * IMod<Program>>>()
  
  
      type Aardvark.Rendering.GL.Context with
  
negative.code: 
          member x.TryCompileProgram(id : string, signature : IFramebufferSignature, code : Lazy<GLSL.GLSLShader>) : Error<_> =
              codeCache.GetOrAdd((x, id, signature), fun (x, id, signature) ->
  
                  let key = 
                      {
                          device      = x.Driver.vendor + "_" + x.Driver.renderer + "_" + string x.Driver.version
                          id          = id
                          outputs     = signature.ColorAttachments |> Map.toList |> List.map (fun (id,(name, s)) -> string name, (id, s.format)) |> Map.ofList
                          layered     = signature.PerLayerUniforms
                          layerCount  = signature.LayerCount
                      }
  
                  let hash = shaderPickler.ComputeHash(key).Hash |> System.Guid
                  let file = System.IO.Path.Combine(cachePath, string hash + ".bin")
  
                  let content : Option<ShaderCacheEntry> =
                      if System.IO.File.Exists file then
                          try shaderPickler.UnPickle (File.readAllBytes file) |> Some
                          with _ -> None
                      else
                          None
  
                  match content with
                      | Some c when false ->
                          
                          let prog = GL.CreateProgram()
                          GL.ProgramBinary(prog, c.format, c.binary, c.binary.Length)
                          GL.Check "could not create program from binary"
  
                          let program =
                              {
                                  Context = x
                                  Code = ""
                                  Handle = prog
                                  Shaders = []
                                  UniformGetters = SymDict.empty
                                  SupportedModes = None
                                  Interface = ShaderReflection.ShaderInterface.empty
                                  TextureInfo = Map.empty
                              }
  
                          Success(c.iface, program)
  
                      | _ -> 
                          let code = code.Value
                          let outputs = code.iface.outputs |> List.map (fun p -> p.paramName, p.paramLocation) |> Map.ofList
                          match x.TryCompileProgram(outputs, true, code.code) with
                              | Success prog ->
                                  match x.TryGetProgramBinary prog with
                                      | Some (format, binary) ->
  
                                          let entry =
                                              shaderPickler.Pickle {
                                                  iface = code.iface
                                                  format = format
                                                  binary = binary
                                              }
  
                                          File.writeAllBytes file entry
  
                                          //Log.warn "%s: %A %A" id format binary
  
                                      | None ->
                                          ()
  
                                  Success (code.iface, prog)
                              | Error e ->
                                  Error e
              )
  
  
  