Skip to content

Commit 827dc18

Browse files
committed
[Vulkan] Add support for pipeline caches
1 parent 620eda1 commit 827dc18

File tree

7 files changed

+198
-19
lines changed

7 files changed

+198
-19
lines changed

src/Aardvark.Rendering.Vulkan/Aardvark.Rendering.Vulkan.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
<Compile Include="Core\Queues\DeviceToken.fs" />
5757
<Compile Include="Core\Queues\DeviceQueueFamily.fs" />
5858
<Compile Include="Core\Device\DeviceCache.fs" />
59+
<Compile Include="Core\Device\PipelineCache.fs" />
5960
<Compile Include="Core\Device\CopyEngine.fs" />
6061
<Compile Include="Core\Device\Device.fs" />
6162
<Compile Include="Core\Commands.fs" />

src/Aardvark.Rendering.Vulkan/Core/Device/Device.fs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ type Device private (physicalDevice: PhysicalDevice, extensions: string seq, sel
174174
let mutable stagingMemory : IDeviceMemory = Unchecked.defaultof<_>
175175
let mutable readbackMemory : IDeviceMemory = Unchecked.defaultof<_>
176176

177+
let mutable pipelineCache : PipelineCache = Unchecked.defaultof<_>
178+
177179
let mutable runtime = Unchecked.defaultof<IRuntime>
178180

179181
let copyEngine =
@@ -214,6 +216,8 @@ type Device private (physicalDevice: PhysicalDevice, extensions: string seq, sel
214216

215217
vkvm <- new VKVM(device, pVkGetDeviceProcAddr)
216218

219+
pipelineCache <- PipelineCache.Deserialize(this)
220+
217221
static member Create(physicalDevice: PhysicalDevice, wantedExtensions: string seq, selectFeatures: DeviceFeatures -> DeviceFeatures) =
218222
let device = new Device(physicalDevice, wantedExtensions, selectFeatures)
219223
device.Initialize()
@@ -283,6 +287,7 @@ type Device private (physicalDevice: PhysicalDevice, extensions: string seq, sel
283287
member internal x.QueueFamilyCount = uint32 queueFamilies.Length
284288
member internal x.QueueFamilyIndices = pAllQueueFamilyIndices
285289
member internal x.SharingMode = sharingMode
290+
member internal x.PipelineCache = pipelineCache
286291

287292
member x.GraphicsFamily : DeviceQueueFamily =
288293
match graphicsFamily with
@@ -332,6 +337,10 @@ type Device private (physicalDevice: PhysicalDevice, extensions: string seq, sel
332337
copyEngine.Value.Dispose()
333338

334339
onDispose.Trigger()
340+
341+
pipelineCache.Serialize()
342+
pipelineCache.Dispose()
343+
335344
memoryAllocator.Dispose()
336345
for f in queueFamilies do f.Dispose()
337346
VkRaw.vkDestroyDevice(device, NativePtr.zero)
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
namespace Aardvark.Rendering.Vulkan
2+
3+
open System
4+
open System.IO
5+
open Aardvark.Base
6+
open Aardvark.Rendering.Vulkan
7+
8+
#nowarn "9"
9+
#nowarn "51"
10+
11+
type internal PipelineCacheId =
12+
{ VendorId : string
13+
DeviceId : string
14+
Driver : Version
15+
CacheId : string }
16+
17+
[<AutoOpen>]
18+
module internal ``PipelineCacheId Extensions`` =
19+
20+
type IDevice with
21+
member this.PipelineCacheId =
22+
{ VendorId = this.PhysicalDevice.Vendor
23+
DeviceId = this.PhysicalDevice.Id
24+
Driver = this.PhysicalDevice.DriverVersion
25+
CacheId = this.PhysicalDevice.Properties.PipelineCacheId }
26+
27+
type internal PipelineCacheData =
28+
{ Id : PipelineCacheId
29+
Hash : byte[]
30+
Size : uint64
31+
Data : byte[] }
32+
33+
type internal PipelineCache private (device: IDevice, handle: VkPipelineCache) =
34+
let mutable handle = handle
35+
static let serializer = MBrace.FsPickler.FsPickler.CreateBinarySerializer()
36+
37+
static let getFilePath (device: IDevice) =
38+
let assemblyName =
39+
let assembly = IntrospectionProperties.CurrentEntryAssembly
40+
let name = if notNull assembly then assembly.GetName().Name else null
41+
name ||? "unknown"
42+
43+
Path.combine [
44+
CachingProperties.CacheDirectory
45+
"Pipelines"
46+
$"{assemblyName}_{device.PhysicalDevice.Id}.pipeline_cache"
47+
]
48+
49+
let getData (size: uint64) (pData: nativeint) =
50+
let mutable size = size
51+
let result = VkRaw.vkGetPipelineCacheData(device.Handle, handle, &&size, pData)
52+
53+
if result <> VkResult.Success then
54+
failwith $"Failed to get pipeline cache data ({result})"
55+
56+
elif size > uint64 Int32.MaxValue then
57+
failwith $"Invalid pipeline cache data size ({size})"
58+
59+
size
60+
61+
let getDataArray() =
62+
let size = getData 0UL 0n
63+
64+
let mutable data = Array.zeroCreate<uint8> (int32 size)
65+
use pData = fixed data
66+
67+
let size = getData size pData.Address
68+
size, data
69+
70+
private new (device: IDevice, createInfo: byref<VkPipelineCacheCreateInfo>) =
71+
let mutable handle = VkPipelineCache.Null
72+
73+
VkRaw.vkCreatePipelineCache(device.Handle, &&createInfo, NativePtr.zero, &&handle)
74+
|> check "failed to create empty pipeline cache"
75+
76+
new PipelineCache(device, handle)
77+
78+
new (device: IDevice) =
79+
let mutable createInfo = VkPipelineCacheCreateInfo(VkPipelineCacheCreateFlags.None, 0UL, 0n)
80+
new PipelineCache(device, &createInfo)
81+
82+
member _.Handle = handle
83+
84+
static member Deserialize(device: IDevice) =
85+
Report.Begin(3, "Deserializing pipeline cache")
86+
87+
try
88+
let path = getFilePath device
89+
Report.Line(3, $"Path: {path}")
90+
91+
let data =
92+
if File.Exists path then
93+
use stream = File.OpenRead path
94+
let data = serializer.Deserialize<PipelineCacheData>(stream)
95+
let hash = serializer.ComputeHash data.Data
96+
97+
if data.Id <> device.PipelineCacheId then
98+
Report.Line(3, $"Pipeline cache ID mismatch (expected: {device.PipelineCacheId}, actual: {data.Id})")
99+
None
100+
101+
elif data.Hash <> hash.Hash then
102+
Report.Line(3, $"Pipeline cache hash mismatch")
103+
None
104+
105+
else
106+
Some data
107+
else
108+
None
109+
110+
match data with
111+
| Some data ->
112+
use pData = fixed data.Data
113+
let mutable createInfo = VkPipelineCacheCreateInfo(VkPipelineCacheCreateFlags.None, data.Size, pData.Address)
114+
let result = new PipelineCache(device, &createInfo)
115+
Report.End(3) |> ignore
116+
result
117+
118+
| None ->
119+
if File.Exists path then
120+
File.Delete path
121+
Report.End(3, " - invalidated") |> ignore
122+
else
123+
Report.End(3, " - not found") |> ignore
124+
125+
new PipelineCache(device)
126+
127+
with e ->
128+
Report.Line(3, $"{e.GetType()}: {e.Message}")
129+
Report.End(3, " - failed") |> ignore
130+
new PipelineCache(device)
131+
132+
member _.Serialize() =
133+
if handle.IsValid then
134+
Report.Begin(3, "Serializing pipeline cache")
135+
136+
try
137+
let path = getFilePath device
138+
Report.Line(3, $"Path: {path}")
139+
140+
let directory = Path.GetDirectoryName path
141+
if not <| Directory.Exists directory then
142+
Directory.CreateDirectory directory |> ignore
143+
144+
let size, data = getDataArray()
145+
let hash = serializer.ComputeHash data
146+
147+
use stream = File.OpenWrite(path)
148+
149+
serializer.Serialize(stream, {
150+
Id = device.PipelineCacheId
151+
Hash = hash.Hash
152+
Size = size
153+
Data = data
154+
})
155+
156+
Report.End(3) |> ignore
157+
with e ->
158+
Report.Line(3, $"{e.GetType()}: {e.Message}")
159+
Report.End(3, " - failed") |> ignore
160+
161+
member _.Dispose() =
162+
if handle.IsValid then
163+
VkRaw.vkDestroyPipelineCache(device.Handle, handle, NativePtr.zero)
164+
handle <- VkPipelineCache.Null
165+
166+
interface IDisposable with
167+
member this.Dispose() = this.Dispose()

src/Aardvark.Rendering.Vulkan/Core/Platform/PhysicalDevice.fs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,15 @@ type IVulkanInstance = interface end
2626

2727
type DeviceProperties =
2828
{
29-
Name : string
30-
Vendor : string
31-
Type : VkPhysicalDeviceType
32-
APIVersion : Version
33-
DriverVersion : Version
34-
UniqueId : string
35-
NodeMask : uint32
36-
Limits : DeviceLimits
29+
Name : string
30+
Vendor : string
31+
Type : VkPhysicalDeviceType
32+
APIVersion : Version
33+
DriverVersion : Version
34+
UniqueId : string
35+
PipelineCacheId : string
36+
NodeMask : uint32
37+
Limits : DeviceLimits
3738
}
3839

3940
member inline this.FullName =
@@ -134,14 +135,15 @@ type PhysicalDevice internal(instance: IVulkanInstance, handle: VkPhysicalDevice
134135
NativePtr.readOrEmpty pAcc, NativePtr.readOrEmpty pOmm
135136

136137
{
137-
Name = properties.deviceName.Value
138-
Vendor = PCI.vendorName <| int properties.vendorID
139-
Type = properties.deviceType
140-
APIVersion = Version.FromVulkan properties.apiVersion
141-
DriverVersion = Version.FromVulkan properties.driverVersion
142-
UniqueId = sprintf "{ GUID = %A; Mask = %d }" devId.deviceUUID devId.deviceNodeMask
143-
NodeMask = if devId.deviceLUIDValid = VkTrue then devId.deviceNodeMask else 1u
144-
Limits = properties.limits |> DeviceLimits.create main psub cbc rtp rtir acc omm
138+
Name = properties.deviceName.Value
139+
Vendor = PCI.vendorName <| int properties.vendorID
140+
Type = properties.deviceType
141+
APIVersion = Version.FromVulkan properties.apiVersion
142+
DriverVersion = Version.FromVulkan properties.driverVersion
143+
UniqueId = if devId.deviceLUIDValid = VkTrue then $"{devId.deviceUUID}_{devId.deviceNodeMask}" else $"{devId.deviceUUID}"
144+
PipelineCacheId = string properties.pipelineCacheUUID
145+
NodeMask = if devId.deviceLUIDValid = VkTrue then devId.deviceNodeMask else 1u
146+
Limits = properties.limits |> DeviceLimits.create main psub cbc rtp rtir acc omm
145147
}
146148

147149
let queueFamilyInfos =

src/Aardvark.Rendering.Vulkan/Management/ResourceManager.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1366,7 +1366,7 @@ module Resources =
13661366
-1
13671367
)
13681368

1369-
VkRaw.vkCreateGraphicsPipelines(device.Handle, VkPipelineCache.Null, 1u, &&createInfo, NativePtr.zero, &&result)
1369+
VkRaw.vkCreateGraphicsPipelines(device.Handle, device.PipelineCache.Handle, 1u, &&createInfo, NativePtr.zero, &&result)
13701370
|> check "could not create pipeline"
13711371

13721372
if x.HasHandle then

src/Aardvark.Rendering.Vulkan/Resources/Raytracing/RaytracingPipeline.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ module RaytracingPipeline =
106106

107107
let mutable handle = VkPipeline.Null
108108
VkRaw.vkCreateRayTracingPipelinesKHR(
109-
device.Handle, VkDeferredOperationKHR.Null, VkPipelineCache.Null,
109+
device.Handle, VkDeferredOperationKHR.Null, device.PipelineCache.Handle,
110110
1u, &&createInfo, NativePtr.zero, &&handle
111111
)
112112
|> check "Failed to create raytracing pipeline"

src/Aardvark.Rendering.Vulkan/Resources/Shaders/ComputeProgram.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ module ComputeProgram =
138138
)
139139

140140
let! pPipeline = VkPipeline.Null
141-
VkRaw.vkCreateComputePipelines(device.Handle, VkPipelineCache.Null, 1u, pPipelineInfo, NativePtr.zero, pPipeline)
141+
VkRaw.vkCreateComputePipelines(device.Handle, device.PipelineCache.Handle, 1u, pPipelineInfo, NativePtr.zero, pPipeline)
142142
|> check "could not create compute pipeline"
143143

144144
return new ComputeProgram(device, !!pPipeline, layout, module_, groupSize, glsl)

0 commit comments

Comments
 (0)