Skip to content

Commit 64fa81b

Browse files
committed
Falcor 5.0 (#291)
1 parent 942f56b commit 64fa81b

File tree

455 files changed

+14664
-3549
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

455 files changed

+14664
-3549
lines changed

Build/deploycommon.bat

+40-8
Original file line numberDiff line numberDiff line change
@@ -48,26 +48,52 @@ set NvApiDir=%ExtDir%\nvapi
4848
set NvApiTargetDir=%OutDir%\Shaders\NVAPI
4949
if exist %NvApiDir% (
5050
if not exist %NvApiTargetDir% mkdir %NvApiTargetDir% >nul
51-
copy /y %NvApiDir%\nvHLSLExtns.h %NvApiTargetDir%
52-
copy /y %NvApiDir%\nvHLSLExtnsInternal.h %NvApiTargetDir%
53-
copy /y %NvApiDir%\nvShaderExtnEnums.h %NvApiTargetDir%
51+
copy /y %NvApiDir%\nvHLSLExtns.h %NvApiTargetDir% >nul
52+
copy /y %NvApiDir%\nvHLSLExtnsInternal.h %NvApiTargetDir% >nul
53+
copy /y %NvApiDir%\nvShaderExtnEnums.h %NvApiTargetDir% >nul
54+
)
55+
56+
rem Copy NRD
57+
set NrdDir=%ExtDir%\nrd
58+
set NrdTargetDir=%OutDir%\Shaders\nrd\Shaders
59+
if exist %NrdDir% (
60+
if not exist %NrdTargetDir% mkdir %NrdTargetDir% >nul
61+
robocopy %NrdDir%\Shaders %NrdTargetDir% /s /r:0 >nul
62+
if %IsDebug% EQU 0 (
63+
robocopy %NrdDir%\Lib\Release %OutDir% *.dll /r:0 >nul
64+
) else (
65+
robocopy %NrdDir%\Lib\Debug %OutDir% *.dll /r:0 >nul
66+
)
67+
)
68+
69+
rem Copy RTXDI SDK shaders
70+
set RtxdiSDKDir=%ExtDir%\rtxdi\rtxdi-sdk\include\rtxdi
71+
set RtxdiSDKTargetDir=%OutDir%\Shaders\rtxdi
72+
if exist %RtxdiSDKDir% (
73+
if not exist %RtxdiSDKTargetDir% mkdir %RtxdiSDKTargetDir% >nul
74+
copy /y %RtxdiSDKDir%\ResamplingFunctions.hlsli %RtxdiSDKTargetDir% >nul
75+
copy /y %RtxdiSDKDir%\Reservoir.hlsli %RtxdiSDKTargetDir% >nul
76+
copy /y %RtxdiSDKDir%\RtxdiHelpers.hlsli %RtxdiSDKTargetDir% >nul
77+
copy /y %RtxdiSDKDir%\RtxdiMath.hlsli %RtxdiSDKTargetDir% >nul
78+
copy /y %RtxdiSDKDir%\RtxdiParameters.h %RtxdiSDKTargetDir% >nul
79+
copy /y %RtxdiSDKDir%\RtxdiTypes.h %RtxdiSDKTargetDir% >nul
5480
)
5581

5682
rem Copy Agility SDK Runtime
5783
set AgilitySDKDir=%ExtDir%\agility-sdk
5884
set AgilitySDKTargetDir=%OutDir%\D3D12
5985
if exist %AgilitySDKDir% (
6086
if not exist %AgilitySDKTargetDir% mkdir %AgilitySDKTargetDir% >nul
61-
copy /y %AgilitySDKDir%\build\native\bin\x64\D3D12Core.dll %AgilitySDKTargetDir%
62-
copy /y %AgilitySDKDir%\build\native\bin\x64\d3d12SDKLayers.dll %AgilitySDKTargetDir%
87+
copy /y %AgilitySDKDir%\build\native\bin\x64\D3D12Core.dll %AgilitySDKTargetDir% >nul
88+
copy /y %AgilitySDKDir%\build\native\bin\x64\d3d12SDKLayers.dll %AgilitySDKTargetDir% >nul
6389
)
6490

6591
rem Copy NanoVDB
66-
set NanoVDBApiDir=%ExtDir%\nanovdb
92+
set NanoVDBDir=%ExtDir%\nanovdb
6793
set NanoVDBTargetDir=%OutDir%\Shaders\NanoVDB
68-
if exist %NanoVDBApiDir% (
94+
if exist %NanoVDBDir% (
6995
if not exist %NanoVDBTargetDir% mkdir %NanoVDBTargetDir% >nul
70-
copy /y %NanoVDBApiDir%\include\nanovdb\PNanoVDB.h %NanoVDBTargetDir%
96+
copy /y %NanoVDBDir%\include\nanovdb\PNanoVDB.h %NanoVDBTargetDir% >nul
7197
)
7298

7399
rem Copy USD files, making sure not to overwrite dlls provided by other components, or dlls that we don't need.
@@ -94,5 +120,11 @@ if %IsDebug% EQU 0 (
94120
robocopy %ExtDir%\nvtt\lib\x64-v141\Debug %OutDir% nvtt.dll /r:0 >nul
95121
)
96122

123+
rem Copy DLSS
124+
set NGXDir=%ExtDir%\ngx
125+
if exist %NGXDir% (
126+
robocopy %NGXDir%\lib\Windows_x86_64\rel %OutDir% nvngx_dlss.dll /r:0 >nul
127+
)
128+
97129
rem robocopy sets the error level to something that is not zero even if the copy operation was successful. Set the error level to zero
98130
exit /b 0

Docs/Development/Error-Handling.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Note that error reporting is a separate topic from error handling and is discuss
2626

2727
* Use asserts to check for logic errors in C++ code; errors that should never occur and are a result of programmer mistakes rather than runtime conditions.
2828
* Use `static_assert()` to check for logic errors at compile time if possible, for example, type checking of template arguments, or checking struct sizes.
29-
* Use `assert()` to check for logic errors at runtime.
29+
* Use `FALCOR_ASSERT()` to check for logic errors at runtime.
3030
* Use asserts generously. Even trivially correct code might be affected by changes elsewhere.
3131
* Make a habit of running the application in Debug mode regularly to make sure that no asserts trigger.
3232

Docs/Usage/Materials.md

+148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
### [Index](../index.md) | [Usage](./index.md) | Materials
2+
3+
--------
4+
5+
# Materials
6+
7+
Starting with Falcor 5.0 there is a new material system that allows creation and rendering of different materials
8+
types at runtime. In previous versions, a fixed diffuse+GGX material model was assumed.
9+
10+
All materials and their resources are managed by the `MaterialSystem` C++ class and matching Slang module.
11+
The material system is owned by `Scene` object and bound together with its other resources when rendering.
12+
13+
In order to access the material system in shader code, the following module must be imported:
14+
15+
```c++
16+
import Scene.Shading;
17+
```
18+
19+
## Data layout
20+
21+
For efficient access, each material is described by a data blob of fixed size (currently 128B).
22+
The data blob consists of a header (see `MaterialHeader` declared in `Falcor/Scene/Material/MaterialData.slang`)
23+
followed by a data payload. The header always exists and holds material type ID and auxiliary flags etc.
24+
25+
The format of the data payload is opaque and depends on the material type. If a material needs more data
26+
than what fits in the payload, it can store additional sideband data in a buffer.
27+
28+
All resources (textures, samplers, buffers) are accessed via bindless resource IDs, where the actual GPU
29+
resources are managed by `MaterialSystem` and the IDs are allocated when resources are added.
30+
These bindless IDs are stored as part of the data payload, so that a material is self-contained and fully
31+
desribed by its data blob.
32+
33+
## Material class (host side)
34+
35+
On the host side, all materials are derived from the `Material` base class declared in `Scene/Material/Material.h`.
36+
37+
In order to add a new material, a new class should be added that inherits from `Material` and implements
38+
its pure virtual member functions. The most important ones are:
39+
40+
```c++
41+
// Called once per frame to prepare the material for rendering.
42+
Material::UpdateFlags Material::update(MaterialSystem* pOwner);
43+
44+
// Returns the material data blob.
45+
MaterialDataBlob Material::getDataBlob() const;
46+
```
47+
48+
The base class holds the `MaterialHeader` struct and the derived material class is responsible
49+
for holding the data payload. The `getDataBlob()` returns the final data blob, which will be uploaded to the
50+
GPU by the material system for access on the shader side.
51+
52+
## Python bindings
53+
54+
To allow creation of materials and setting of the parameters from Python scripts (including `.pyscene` files),
55+
each material class is expected to export Python bindings.
56+
57+
These bindings are defined in the `FALCOR_SCRIPT_BINDING` block, usually placed at the bottom of the material's `.cpp` file.
58+
59+
Example usage:
60+
61+
```c++
62+
glass = StandardMaterial("WindowGlass")
63+
glass.roughness = 0
64+
glass.metallic = 0
65+
glass.indexOfRefraction = 1.52
66+
glass.specularTransmission = 1
67+
glass.doubleSided = True
68+
glass.nestedPriority = 2
69+
glass.volumeAbsorption = float3(2.0, 1.0, 1.5)
70+
```
71+
72+
For more examples of how material's are created from Python, refer to the test scenes in `Media/TestScenes/`
73+
(this directory is automatically fetched when the solution is built the first time).
74+
75+
## Material module (shader side)
76+
77+
On the shader side, each material class has a corresponding Slang module stored in `Falcor/Rendering/Materials/`.
78+
These modules implement the `IMaterial` Slang interface (see `Rendering/Materials/IMaterial.slang`).
79+
80+
The main purpose of the material module is to:
81+
1. hold the material data, and
82+
2. hold the code for setting up a BSDF at a shading point.
83+
84+
The latter is referred to as "pattern generation", which may involve sampling textures, evaluating
85+
procedural functions, and any other setup needed for shading.
86+
87+
The first data field in the material module has to be the material header. This should be followed by the
88+
material payload as declared for the material type. For example, the standard material is declared:
89+
90+
```c++
91+
struct StandardMaterial : IMaterial
92+
{
93+
MaterialHeader header;
94+
BasicMaterialData data;
95+
...
96+
};
97+
```
98+
99+
An instance of the material is created by calling the material system as follows:
100+
101+
```c++
102+
IMaterial material = gScene.materials.getMaterial(materialID);
103+
```
104+
105+
Internally, this function accesses the material header to fetch the material type, and then it calls
106+
Slang's `createDynamicObject<..>` function to create an instance of the right type.
107+
The opaque material data blob is cast to the data types used in the material module, so its fields are
108+
directly accessible internally in the material module.
109+
110+
## BSDF module (shader side)
111+
112+
Each material module has an associated BSDF type, which implements the `IBSDF` Slang interface.
113+
For example, `StandardMaterial` has an associated `StandardBSDF` type.
114+
115+
An instance of the BSDF type is created for a specific shading point in the scene, and it exposes
116+
interfaces for evaluating and sampling the BSDF at that point.
117+
The `IBSDF` interface also has functions for querying additional BSDF properties
118+
at the shading point, such as albedo, emission, etc.
119+
120+
A BSDF instance is created by calling the following function on the material:
121+
122+
```c++
123+
ShadingData sd = ... // struct describing the shading point
124+
ITextureSampler lod = ... // method for texture level-of-detail computation
125+
126+
IBSDF bsdf = material.setupBSDF(gScene.materials, sd, lod);
127+
```
128+
129+
Internally, the `setupBSDF` function accesses the material system to fetch/evaluate all resources needed at the
130+
shading point. It returns an instance of the material's associated BSDF type,
131+
which the caller can then use to evaluate or sample the BSDF at the shading point.
132+
133+
Since creating the material followed by instantiating the BSDF is very common,
134+
there is a convenience function `getBSDF()` on `MaterialSystem` that does both operations in one step:
135+
136+
```c++
137+
IBSDF bsdf = gScene.materials.getBSDF(sd, lod);
138+
```
139+
140+
In the above interfaces, a `ShadingData` struct is needed to describe the shading point.
141+
This is generated at a hit point by calling the `prepareShadingData()` function.
142+
This function is responsible for setting up the shading frame (normal, tangent, bitangent)
143+
including evaluating normal mapping and material opacity for alpha testing.
144+
145+
In addition to this, a `ITextureSampler` instance is needed to describe how textures should
146+
be sampled (if there are any). The caller is responsible for deciding this based on which
147+
method for texture LOD it is using (e.g. ray cones, ray differentials, fixed mip level, etc).
148+
See available choices in `Scene/Material/TextureSampler.slang`).

Docs/Usage/Scene-Formats.md

+13-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,17 @@
44

55
# Scene Formats
66

7-
Falcor uses [Assimp](https://github.com/assimp/assimp) as its core asset loader and can load all file formats Assimp supports by default.
7+
## USD Scene Files
8+
9+
Starting with version 5.0 Falcor includes an experimental importer for Universal Scene Description (USD) files.
10+
11+
The `UsdPreviewSurface` material model is partially supported by mapping to Falcor's `StandardMaterial` at load time.
12+
13+
## FBX/GLTF Scene Files
14+
15+
Falcor uses [Assimp](https://github.com/assimp/assimp) as its asset loader for FBX and GLTF scenes. It can load all other file formats Assimp supports by default, but support may be more limited.
16+
17+
All loaded material data is mapped to Falcor's `StandardMaterial` at load time.
818

919
From assets, Falcor will import:
1020
- Scene Graph
@@ -132,7 +142,8 @@ Each vertex has a _position_, _normal_ and _texCoord_ attribute. Triangles are d
132142

133143
#### Create Materials
134144

135-
Next we need to define at least one material to use for our meshes:
145+
Next we need to define at least one material to use for our meshes.
146+
For more examples, see [Materials](./Materials.md).
136147

137148
```python
138149
# Create materials

Docs/Usage/Scenes.md

+8-9
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,7 @@ GraphicsVars::SharedPtr pProgramVars = GraphicsVars::create(pProgram->getReflect
118118
### Rasterization
119119

120120
The output of the default vertex shader includes two parameters: `instanceID`, and `materialID` which can be used to look up data for the current mesh being rendered.
121-
```c++
122-
gScene.geometryInstances[vertexOut.instanceID];
123-
gScene.materials[vertexOut.materialID];
124-
```
121+
See interfaces in `Scene/Scene.slang`.
125122

126123
For basic usage, it is not necessary to perform the lookups yourself. A helper function defined in `Scene/Raster.slang` can load and prepare data for you.
127124

@@ -131,7 +128,8 @@ import Scene.Raster;
131128
float4 main(VSOut vertexOut, float4 pixelCrd : SV_POSITION, uint triangleIndex : SV_PrimitiveID) : SV_TARGET
132129
{
133130
float3 viewDir = normalize(gScene.camera.getPosition() - vOut.posW);
134-
ShadingData sd = prepareShadingData(vertexOut, triangleIndex, viewDir);
131+
let lod = ImplicitLodTextureSampler();
132+
ShadingData sd = prepareShadingData(vertexOut, triangleIndex, viewDir, lod);
135133
...
136134
}
137135
```
@@ -146,10 +144,11 @@ import Scene.Raytracing;
146144
[shader("closesthit")]
147145
void primaryClosestHit(inout PrimaryRayData hitData, in BuiltInTriangleIntersectionAttributes attribs)
148146
{
149-
const uint globalInstanceID = getGlobalInstanceID();
150-
const VertexData v = getVertexData(globalInstanceID, PrimitiveIndex(), attribs);
151-
const uint materialID = gScene.getMaterialID(globalInstanceID);
152-
ShadingData sd = prepareShadingData(v, materialID, gScene.materials[materialID], gScene.materialResources[materialID], -WorldRayDirection(), 0);
147+
GeometryInstanceID instanceID = getGeometryInstanceID();
148+
VertexData v = getVertexData(instanceID, PrimitiveIndex(), attribs);
149+
const uint materialID = gScene.getMaterialID(instanceID);
150+
let lod = ExplicitLodTextureSampler(0.f);
151+
ShadingData sd = gScene.materials.prepareShadingData(v, materialID, -WorldRayDirection(), lod);
153152
...
154153
}
155154
```

Docs/Usage/Scripting.md

+4
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,10 @@ class falcor.**EnvMap**
444444
| `rotation` | `float3` | Rotation angles in degrees (XYZ). |
445445
| `intensity` | `float` | Intensity (scalar multiplier). |
446446

447+
| Static method | Description |
448+
|----------------------------|---------------------------------------|
449+
| `createFromFile(filename)` | Create a environment map from a file. |
450+
447451
#### Material
448452

449453
**DEPRECATED**: Use `StandardMaterial` instead.

Docs/Usage/index.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
- [Scene Creation](./Scene-Creation.md)
99
- [Scenes](./Scenes.md)
1010
- [Scene Formats](./Scene-Formats.md)
11+
- [Materials](./Materials.md)
1112
- [Scripting](./Scripting.md)
1213
- [Render Passes](./Render-Passes.md)
1314
- [Path Tracer](./Path-Tracer.md)
14-
- [Custom Primitives](./Custom-Primitives.md)
15+
- [Custom Primitives](./Custom-Primitives.md)

Falcor.sln

+44
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Visualization2D", "Source\S
9898
EndProject
9999
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PathTracer", "Source\RenderPasses\PathTracer\PathTracer.vcxproj", "{99799BA5-6503-425C-BFCC-8B94E6A40D1D}"
100100
EndProject
101+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ModulateIllumination", "Source\RenderPasses\ModulateIllumination\ModulateIllumination.vcxproj", "{4E192689-E377-4936-8A1B-94B08226FC83}"
102+
EndProject
103+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NRDPass", "Source\RenderPasses\NRDPass\NRDPass.vcxproj", "{25964C78-F3F0-4889-869F-ADFDACEF0482}"
104+
EndProject
105+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLSSPass", "Source\RenderPasses\DLSSPass\DLSSPass.vcxproj", "{0B2F90ED-3524-4F92-8A0B-F542D90F3A32}"
106+
EndProject
107+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTXDIPass", "Source\RenderPasses\RTXDIPass\RTXDIPass.vcxproj", "{8F778354-93D9-4030-B55F-19137650780D}"
108+
EndProject
101109
Global
102110
GlobalSection(SolutionConfigurationPlatforms) = preSolution
103111
DebugD3D12|x64 = DebugD3D12|x64
@@ -410,6 +418,38 @@ Global
410418
{99799BA5-6503-425C-BFCC-8B94E6A40D1D}.ReleaseD3D12|x64.Build.0 = Release|x64
411419
{99799BA5-6503-425C-BFCC-8B94E6A40D1D}.ReleaseGFX|x64.ActiveCfg = Release|x64
412420
{99799BA5-6503-425C-BFCC-8B94E6A40D1D}.ReleaseGFX|x64.Build.0 = Release|x64
421+
{4E192689-E377-4936-8A1B-94B08226FC83}.DebugD3D12|x64.ActiveCfg = Debug|x64
422+
{4E192689-E377-4936-8A1B-94B08226FC83}.DebugD3D12|x64.Build.0 = Debug|x64
423+
{4E192689-E377-4936-8A1B-94B08226FC83}.DebugGFX|x64.ActiveCfg = Debug|x64
424+
{4E192689-E377-4936-8A1B-94B08226FC83}.DebugGFX|x64.Build.0 = Debug|x64
425+
{4E192689-E377-4936-8A1B-94B08226FC83}.ReleaseD3D12|x64.ActiveCfg = Release|x64
426+
{4E192689-E377-4936-8A1B-94B08226FC83}.ReleaseD3D12|x64.Build.0 = Release|x64
427+
{4E192689-E377-4936-8A1B-94B08226FC83}.ReleaseGFX|x64.ActiveCfg = Release|x64
428+
{4E192689-E377-4936-8A1B-94B08226FC83}.ReleaseGFX|x64.Build.0 = Release|x64
429+
{25964C78-F3F0-4889-869F-ADFDACEF0482}.DebugD3D12|x64.ActiveCfg = Debug|x64
430+
{25964C78-F3F0-4889-869F-ADFDACEF0482}.DebugD3D12|x64.Build.0 = Debug|x64
431+
{25964C78-F3F0-4889-869F-ADFDACEF0482}.DebugGFX|x64.ActiveCfg = Debug|x64
432+
{25964C78-F3F0-4889-869F-ADFDACEF0482}.DebugGFX|x64.Build.0 = Debug|x64
433+
{25964C78-F3F0-4889-869F-ADFDACEF0482}.ReleaseD3D12|x64.ActiveCfg = Release|x64
434+
{25964C78-F3F0-4889-869F-ADFDACEF0482}.ReleaseD3D12|x64.Build.0 = Release|x64
435+
{25964C78-F3F0-4889-869F-ADFDACEF0482}.ReleaseGFX|x64.ActiveCfg = Release|x64
436+
{25964C78-F3F0-4889-869F-ADFDACEF0482}.ReleaseGFX|x64.Build.0 = Release|x64
437+
{0B2F90ED-3524-4F92-8A0B-F542D90F3A32}.DebugD3D12|x64.ActiveCfg = Debug|x64
438+
{0B2F90ED-3524-4F92-8A0B-F542D90F3A32}.DebugD3D12|x64.Build.0 = Debug|x64
439+
{0B2F90ED-3524-4F92-8A0B-F542D90F3A32}.DebugGFX|x64.ActiveCfg = Debug|x64
440+
{0B2F90ED-3524-4F92-8A0B-F542D90F3A32}.DebugGFX|x64.Build.0 = Debug|x64
441+
{0B2F90ED-3524-4F92-8A0B-F542D90F3A32}.ReleaseD3D12|x64.ActiveCfg = Release|x64
442+
{0B2F90ED-3524-4F92-8A0B-F542D90F3A32}.ReleaseD3D12|x64.Build.0 = Release|x64
443+
{0B2F90ED-3524-4F92-8A0B-F542D90F3A32}.ReleaseGFX|x64.ActiveCfg = Release|x64
444+
{0B2F90ED-3524-4F92-8A0B-F542D90F3A32}.ReleaseGFX|x64.Build.0 = Release|x64
445+
{8F778354-93D9-4030-B55F-19137650780D}.DebugD3D12|x64.ActiveCfg = Debug|x64
446+
{8F778354-93D9-4030-B55F-19137650780D}.DebugD3D12|x64.Build.0 = Debug|x64
447+
{8F778354-93D9-4030-B55F-19137650780D}.DebugGFX|x64.ActiveCfg = Debug|x64
448+
{8F778354-93D9-4030-B55F-19137650780D}.DebugGFX|x64.Build.0 = Debug|x64
449+
{8F778354-93D9-4030-B55F-19137650780D}.ReleaseD3D12|x64.ActiveCfg = Release|x64
450+
{8F778354-93D9-4030-B55F-19137650780D}.ReleaseD3D12|x64.Build.0 = Release|x64
451+
{8F778354-93D9-4030-B55F-19137650780D}.ReleaseGFX|x64.ActiveCfg = Release|x64
452+
{8F778354-93D9-4030-B55F-19137650780D}.ReleaseGFX|x64.Build.0 = Release|x64
413453
EndGlobalSection
414454
GlobalSection(SolutionProperties) = preSolution
415455
HideSolutionNode = FALSE
@@ -452,6 +492,10 @@ Global
452492
{05555565-706C-4633-BF8A-B99F96F2B301} = {D16038A7-B031-4181-B4A1-2C416C02330C}
453493
{99FB6CED-94F9-4A5E-8238-E694B39351C0} = {4B8EAC4B-FFDF-4CCA-A6FE-4505631E51EC}
454494
{99799BA5-6503-425C-BFCC-8B94E6A40D1D} = {D16038A7-B031-4181-B4A1-2C416C02330C}
495+
{4E192689-E377-4936-8A1B-94B08226FC83} = {D16038A7-B031-4181-B4A1-2C416C02330C}
496+
{25964C78-F3F0-4889-869F-ADFDACEF0482} = {D16038A7-B031-4181-B4A1-2C416C02330C}
497+
{0B2F90ED-3524-4F92-8A0B-F542D90F3A32} = {D16038A7-B031-4181-B4A1-2C416C02330C}
498+
{8F778354-93D9-4030-B55F-19137650780D} = {D16038A7-B031-4181-B4A1-2C416C02330C}
455499
EndGlobalSection
456500
GlobalSection(ExtensibilityGlobals) = postSolution
457501
SolutionGuid = {357B2AE0-FE30-4AC6-8D41-B580232BC0DE}

0 commit comments

Comments
 (0)