forked from amkovkov/GranuSightSoftware2
refactor: remove GSS2.Vulkan
This commit is contained in:
@@ -1,68 +0,0 @@
|
|||||||
// Основан на примере GpuInterop Avalonia
|
|
||||||
// https://github.com/AvaloniaUI/Avalonia/blob/5f3dbae22244e830b464fc680c6c28ca124be41a/samples/GpuInterop/VulkanDemo/ByteString.cs
|
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace GSS2.Vulkan;
|
|
||||||
|
|
||||||
unsafe sealed class ByteString : IDisposable
|
|
||||||
{
|
|
||||||
private bool _disposedValue;
|
|
||||||
private readonly byte* _pointer;
|
|
||||||
|
|
||||||
public ByteString(string s)
|
|
||||||
{
|
|
||||||
_pointer = (byte*)Marshal.StringToHGlobalAnsi(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!_disposedValue)
|
|
||||||
{
|
|
||||||
Marshal.FreeHGlobal(new IntPtr(_pointer));
|
|
||||||
_disposedValue = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~ByteString() => Dispose(disposing: false);
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(disposing: true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator byte*(ByteString obj) => obj._pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe sealed class ByteStringList : IDisposable
|
|
||||||
{
|
|
||||||
private bool _disposedValue;
|
|
||||||
private readonly List<ByteString> _list;
|
|
||||||
private readonly byte** _pointer;
|
|
||||||
|
|
||||||
public int Count => _list.Count;
|
|
||||||
|
|
||||||
public ByteStringList(IEnumerable<string> list)
|
|
||||||
{
|
|
||||||
_list = list.Select(x => new ByteString(x)).ToList();
|
|
||||||
_pointer = (byte**)Marshal.AllocHGlobal(IntPtr.Size * _list.Count + 1);
|
|
||||||
for (var c = 0; c < _list.Count; c++)
|
|
||||||
_pointer[c] = (byte*)_list[c];
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!_disposedValue)
|
|
||||||
{
|
|
||||||
Marshal.FreeHGlobal(new IntPtr(_pointer));
|
|
||||||
_disposedValue = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~ByteStringList() => Dispose(disposing: false);
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(disposing: true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator byte**(ByteStringList obj) => obj._pointer;
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
|
|
||||||
<PackageReference Include="Avalonia" Version="11.3.11" />
|
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="11.3.11" />
|
|
||||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.11" />
|
|
||||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.11" />
|
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
|
||||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.11">
|
|
||||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
|
||||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Silk.NET.Direct3D11" Version="2.22.0" />
|
|
||||||
<PackageReference Include="Silk.NET.Direct3D.Compilers" Version="2.22.0" />
|
|
||||||
<PackageReference Include="Silk.NET.Vulkan" Version="2.22.0" />
|
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
|
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,243 +0,0 @@
|
|||||||
// Основан на примере GpuInterop Avalonia
|
|
||||||
// https://github.com/AvaloniaUI/Avalonia/blob/5f3dbae22244e830b464fc680c6c28ca124be41a/samples/GpuInterop/VulkanDemo/VulkanContext.cs
|
|
||||||
|
|
||||||
using Silk.NET.Core;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
using Silk.NET.Vulkan.Extensions.KHR;
|
|
||||||
|
|
||||||
using Semaphore = Silk.NET.Vulkan.Semaphore;
|
|
||||||
|
|
||||||
namespace GSS2.Vulkan;
|
|
||||||
|
|
||||||
unsafe public class VulkanContext : IDisposable
|
|
||||||
{
|
|
||||||
private bool _disposedValue;
|
|
||||||
|
|
||||||
public Vk Api { get; init; }
|
|
||||||
public Instance Instance { get; init; }
|
|
||||||
public PhysicalDevice PhysicalDevice { get; init; }
|
|
||||||
public Device Device { get; init; }
|
|
||||||
public uint QueueFamilyIndex { get; init; }
|
|
||||||
public Queue Queue { get; init; }
|
|
||||||
public Semaphore ImageExportedSemaphore { get; init; }
|
|
||||||
public Semaphore ImageRenderedSemaphore { get; init; }
|
|
||||||
public CommandPool CommandPool { get; init; }
|
|
||||||
public CommandBuffer CommandBuffer { get; init; }
|
|
||||||
public KhrExternalMemoryFd KhrExternalMemoryFd { get; init; }
|
|
||||||
public KhrExternalSemaphoreFd KhrExternalSemaphoreFd { get; init; }
|
|
||||||
public KhrExternalFenceFd KhrExternalFenceFd { get; init; }
|
|
||||||
|
|
||||||
public VulkanContext(string applicationName, string engineName)
|
|
||||||
{
|
|
||||||
Api = Vk.GetApi();
|
|
||||||
|
|
||||||
List<string> instanceExtensions =
|
|
||||||
[
|
|
||||||
"VK_KHR_get_physical_device_properties2",
|
|
||||||
"VK_KHR_external_memory_capabilities",
|
|
||||||
"VK_KHR_external_fence_capabilities",
|
|
||||||
"VK_KHR_external_semaphore_capabilities",
|
|
||||||
"VK_EXT_debug_utils"
|
|
||||||
];
|
|
||||||
List<string> instanceLayers =
|
|
||||||
[
|
|
||||||
|
|
||||||
];
|
|
||||||
List<string> deviceExtensions =
|
|
||||||
[
|
|
||||||
"VK_KHR_external_memory",
|
|
||||||
"VK_KHR_external_memory_fd",
|
|
||||||
"VK_KHR_external_semaphore",
|
|
||||||
"VK_KHR_external_semaphore_fd",
|
|
||||||
"VK_KHR_external_fence",
|
|
||||||
"VK_KHR_external_fence_fd"
|
|
||||||
];
|
|
||||||
|
|
||||||
Instance = CreateInstance(Api, applicationName, engineName, instanceExtensions, instanceLayers);
|
|
||||||
PhysicalDevice = FindPhysicalDevice(Api, Instance, deviceExtensions);
|
|
||||||
(Device, QueueFamilyIndex) = CreateDevice(Api, Instance, PhysicalDevice, deviceExtensions);
|
|
||||||
Queue = CreateQueue(Api, Device, QueueFamilyIndex);
|
|
||||||
ImageExportedSemaphore = CreateSemaphore(Api, Device);
|
|
||||||
ImageRenderedSemaphore = CreateSemaphore(Api, Device);
|
|
||||||
CommandPool = CreateCommandPool(Api, Device, QueueFamilyIndex);
|
|
||||||
CommandBuffer = CreateCommandBuffer(Api, Device, CommandPool);
|
|
||||||
|
|
||||||
if (!Api.TryGetDeviceExtension<KhrExternalMemoryFd>(Instance, Device, out var khrExternalMemoryFd))
|
|
||||||
throw new Exception("KhrExternalMemoryFd import error");
|
|
||||||
KhrExternalMemoryFd = khrExternalMemoryFd;
|
|
||||||
if (!Api.TryGetDeviceExtension<KhrExternalSemaphoreFd>(Instance, Device, out var khrExternalSemaphoreFd))
|
|
||||||
throw new Exception("KhrExternalMemoryFd import error");
|
|
||||||
KhrExternalSemaphoreFd = khrExternalSemaphoreFd;
|
|
||||||
if (!Api.TryGetDeviceExtension<KhrExternalFenceFd>(Instance, Device, out var khrExternalFenceFd))
|
|
||||||
throw new Exception("KhrExternalFenceFd import error");
|
|
||||||
KhrExternalFenceFd = khrExternalFenceFd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Instance CreateInstance(Vk api, string applicationName, string engineName, List<string> extentions, List<string> layers)
|
|
||||||
{
|
|
||||||
using var pApplicationName = new ByteString(applicationName);
|
|
||||||
using var pEngineName = new ByteString(engineName);
|
|
||||||
var applicationInfo = new ApplicationInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.ApplicationInfo,
|
|
||||||
PApplicationName = pApplicationName,
|
|
||||||
PEngineName = pEngineName,
|
|
||||||
ApiVersion = new Version32(1, 1, 0),
|
|
||||||
EngineVersion = new Version32(1, 0, 0),
|
|
||||||
ApplicationVersion = new Version32(1, 0, 0)
|
|
||||||
};
|
|
||||||
|
|
||||||
using var pExtensions = new ByteStringList(extentions);
|
|
||||||
using var pLayers = new ByteStringList(layers);
|
|
||||||
var instanceCreateInfo = new InstanceCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.InstanceCreateInfo,
|
|
||||||
PApplicationInfo = &applicationInfo,
|
|
||||||
PpEnabledExtensionNames = pExtensions,
|
|
||||||
EnabledExtensionCount = checked((uint)pExtensions.Count),
|
|
||||||
PpEnabledLayerNames = pLayers,
|
|
||||||
EnabledLayerCount = checked((uint)pLayers.Count),
|
|
||||||
Flags = default
|
|
||||||
};
|
|
||||||
|
|
||||||
api.CreateInstance(in instanceCreateInfo, null, out var Instance).ThrowOnError();
|
|
||||||
|
|
||||||
return Instance;
|
|
||||||
}
|
|
||||||
private static PhysicalDevice FindPhysicalDevice(Vk api, Instance instance, List<string> extensions)
|
|
||||||
{
|
|
||||||
uint count = 0;
|
|
||||||
api.EnumeratePhysicalDevices(instance, ref count, null).ThrowOnError();
|
|
||||||
var physicalDevices = stackalloc PhysicalDevice[(int)count];
|
|
||||||
api.EnumeratePhysicalDevices(instance, ref count, physicalDevices).ThrowOnError();
|
|
||||||
|
|
||||||
for (uint c = 0; c < count; c++)
|
|
||||||
{
|
|
||||||
if (extensions.Any(e => !api.IsDeviceExtensionPresent(physicalDevices[c], e)))
|
|
||||||
continue;
|
|
||||||
return physicalDevices[c];
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception("Suшtable Device not found");
|
|
||||||
}
|
|
||||||
private static (Device device, uint queueFamilyIndex) CreateDevice(Vk api, Instance instance, PhysicalDevice physicalDevice, List<string> extensions)
|
|
||||||
{
|
|
||||||
uint queueFamilyCount = 0;
|
|
||||||
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, ref queueFamilyCount, null);
|
|
||||||
var queueFamilyProperties = new QueueFamilyProperties[(int)queueFamilyCount];
|
|
||||||
fixed (QueueFamilyProperties* pQueueFamilyProperties = queueFamilyProperties)
|
|
||||||
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, ref queueFamilyCount, pQueueFamilyProperties);
|
|
||||||
|
|
||||||
for (uint i = 0; i < queueFamilyCount; i++)
|
|
||||||
{
|
|
||||||
var queueFamily = queueFamilyProperties[i];
|
|
||||||
if (!queueFamily.QueueFlags.HasFlag(QueueFlags.GraphicsBit))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var queuePriorities = new float[(int)queueFamily.QueueCount];
|
|
||||||
|
|
||||||
for (var j = 0; j < queueFamily.QueueCount; j++)
|
|
||||||
queuePriorities[j] = 1f;
|
|
||||||
|
|
||||||
var features = new PhysicalDeviceFeatures();
|
|
||||||
|
|
||||||
Device device;
|
|
||||||
fixed (float* pQueuePriorities = queuePriorities)
|
|
||||||
{
|
|
||||||
var queueCreateInfo = new DeviceQueueCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.DeviceQueueCreateInfo,
|
|
||||||
QueueFamilyIndex = i,
|
|
||||||
QueueCount = queueFamily.QueueCount,
|
|
||||||
PQueuePriorities = pQueuePriorities
|
|
||||||
};
|
|
||||||
|
|
||||||
using var pEnabledDeviceExtensions = new ByteStringList(extensions);
|
|
||||||
var deviceCreateInfo = new DeviceCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.DeviceCreateInfo,
|
|
||||||
QueueCreateInfoCount = 1,
|
|
||||||
PQueueCreateInfos = &queueCreateInfo,
|
|
||||||
PpEnabledExtensionNames = pEnabledDeviceExtensions,
|
|
||||||
EnabledExtensionCount = checked((uint)pEnabledDeviceExtensions.Count),
|
|
||||||
PEnabledFeatures = &features
|
|
||||||
};
|
|
||||||
|
|
||||||
api.CreateDevice(physicalDevice, in deviceCreateInfo, null, out device).ThrowOnError();
|
|
||||||
|
|
||||||
return (device, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new Exception("Cannot create device");
|
|
||||||
}
|
|
||||||
private static Queue CreateQueue(Vk api, Device device, uint queueFamilyIndex)
|
|
||||||
{
|
|
||||||
api.GetDeviceQueue(device, queueFamilyIndex, 0, out var queue);
|
|
||||||
return queue;
|
|
||||||
}
|
|
||||||
private static Semaphore CreateSemaphore(Vk api, Device device)
|
|
||||||
{
|
|
||||||
var semaphoreExportInfo = new ExportSemaphoreCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.ExportSemaphoreCreateInfo,
|
|
||||||
HandleTypes = ExternalSemaphoreHandleTypeFlags.OpaqueFDBit
|
|
||||||
};
|
|
||||||
var semaphoreCreateInfo = new SemaphoreCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.SemaphoreCreateInfo,
|
|
||||||
PNext = &semaphoreExportInfo
|
|
||||||
};
|
|
||||||
|
|
||||||
api.CreateSemaphore(device, in semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
|
|
||||||
return semaphore;
|
|
||||||
}
|
|
||||||
private static CommandPool CreateCommandPool(Vk api, Device device, uint queueFamilyIndex)
|
|
||||||
{
|
|
||||||
var commandPoolCreateInfo = new CommandPoolCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.CommandPoolCreateInfo,
|
|
||||||
Flags = CommandPoolCreateFlags.ResetCommandBufferBit,
|
|
||||||
QueueFamilyIndex = queueFamilyIndex
|
|
||||||
};
|
|
||||||
api.CreateCommandPool(device, &commandPoolCreateInfo, null, out var commandPool).ThrowOnError();
|
|
||||||
|
|
||||||
return commandPool;
|
|
||||||
}
|
|
||||||
private static CommandBuffer CreateCommandBuffer(Vk api, Device device, CommandPool commandPool)
|
|
||||||
{
|
|
||||||
var commandBufferAllocateInfo = new CommandBufferAllocateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.CommandBufferAllocateInfo,
|
|
||||||
CommandPool = commandPool,
|
|
||||||
Level = CommandBufferLevel.Primary,
|
|
||||||
CommandBufferCount = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
api.AllocateCommandBuffers(device, &commandBufferAllocateInfo, out var commandBuffer).ThrowOnError();
|
|
||||||
|
|
||||||
return commandBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!_disposedValue)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
if (Api is null)
|
|
||||||
return;
|
|
||||||
Api.DestroySemaphore(Device, ImageExportedSemaphore, null);
|
|
||||||
Api.DestroySemaphore(Device, ImageRenderedSemaphore, null);
|
|
||||||
Api.FreeCommandBuffers(Device, CommandPool, [CommandBuffer]);
|
|
||||||
Api.DestroyCommandPool(Device, CommandPool, null);
|
|
||||||
Api.DestroyDevice(Device, null);
|
|
||||||
}
|
|
||||||
_disposedValue = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(disposing: true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// Основан на примере GpuInterop Avalonia
|
|
||||||
// https://github.com/AvaloniaUI/Avalonia/blob/5f3dbae22244e830b464fc680c6c28ca124be41a/samples/GpuInterop/VulkanDemo/VulkanExtensions.cs
|
|
||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
|
|
||||||
namespace GSS2.Vulkan;
|
|
||||||
|
|
||||||
public static class VulkanExtensions
|
|
||||||
{
|
|
||||||
public static void ThrowOnError(this Result result, [CallerMemberName] string callerMemberName = "", [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = -1)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"{callerFilePath} {callerMemberName} {callerLineNumber} {result}");
|
|
||||||
if (result != Result.Success)
|
|
||||||
throw new Exception($"Unexpected API error \"{result}\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,8 +15,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GSS2.LightsControl.CSharpCl
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GSS2.FrameDecoders", "GSS2.FrameDecoders\GSS2.FrameDecoders.csproj", "{05085293-E710-41D6-8F61-701ADBA52FA9}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GSS2.FrameDecoders", "GSS2.FrameDecoders\GSS2.FrameDecoders.csproj", "{05085293-E710-41D6-8F61-701ADBA52FA9}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GSS2.Vulkan", "GSS2.Vulkan\GSS2.Vulkan.csproj", "{CA315A5C-A9FA-44F2-A09C-08F3504ADD62}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -75,18 +73,6 @@ Global
|
|||||||
{05085293-E710-41D6-8F61-701ADBA52FA9}.Release|x64.Build.0 = Release|Any CPU
|
{05085293-E710-41D6-8F61-701ADBA52FA9}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{05085293-E710-41D6-8F61-701ADBA52FA9}.Release|x86.ActiveCfg = Release|Any CPU
|
{05085293-E710-41D6-8F61-701ADBA52FA9}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{05085293-E710-41D6-8F61-701ADBA52FA9}.Release|x86.Build.0 = Release|Any CPU
|
{05085293-E710-41D6-8F61-701ADBA52FA9}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{CA315A5C-A9FA-44F2-A09C-08F3504ADD62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{CA315A5C-A9FA-44F2-A09C-08F3504ADD62}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{CA315A5C-A9FA-44F2-A09C-08F3504ADD62}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{CA315A5C-A9FA-44F2-A09C-08F3504ADD62}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{CA315A5C-A9FA-44F2-A09C-08F3504ADD62}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{CA315A5C-A9FA-44F2-A09C-08F3504ADD62}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{CA315A5C-A9FA-44F2-A09C-08F3504ADD62}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{CA315A5C-A9FA-44F2-A09C-08F3504ADD62}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{CA315A5C-A9FA-44F2-A09C-08F3504ADD62}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{CA315A5C-A9FA-44F2-A09C-08F3504ADD62}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{CA315A5C-A9FA-44F2-A09C-08F3504ADD62}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{CA315A5C-A9FA-44F2-A09C-08F3504ADD62}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
Reference in New Issue
Block a user