public static ShaderModule LoadShaderModule(IVulkanAppHost host, VulkanContext ctx, string path) { const int defaultBufferSize = 4096; using (Stream stream = host.Open(path)) using (var ms = new MemoryStream()) { stream.CopyTo(ms, defaultBufferSize); return(ctx.Device.CreateShaderModule(new ShaderModuleCreateInfo(ms.ToArray()))); } }
public void Initialize(IVulkanAppHost host) { Host = host; #if DEBUG const bool debug = true; #else const bool debug = false; #endif _initializingPermanent = true; // Calling ToDispose here registers the resource to be automatically disposed on exit. Instance = ToDispose(CreateInstance(debug)); DebugReportCallback = ToDispose(CreateDebugReportCallback(debug)); Surface = ToDispose(CreateSurface()); Context = ToDispose(new VulkanContext(Instance, Surface, Host.Platform)); Content = ToDispose(new ContentManager(Host, Context, "Content")); ImageAvailableSemaphore = ToDispose(Context.Device.CreateSemaphore()); RenderingFinishedSemaphore = ToDispose(Context.Device.CreateSemaphore()); if (host.Platform == Platform.MacOS) { //Setup MoltenVK specific device configuration. MVKDeviceConfiguration deviceConfig = Context.Device.GetMVKDeviceConfiguration(); deviceConfig.DebugMode = debug; deviceConfig.PerformanceTracking = debug; deviceConfig.PerformanceLoggingFrameCount = debug ? 300 : 0; Context.Device.SetMVKDeviceConfiguration(deviceConfig); } _initializingPermanent = false; // Calling ToDispose here registers the resource to be automatically disposed on events // such as window resize. Swapchain = ToDispose(CreateSwapchain()); // Acquire underlying images of the freshly created swapchain. SwapchainImages = Swapchain.GetImages(); // Create a command buffer for each swapchain image. CommandBuffers = Context.GraphicsCommandPool.AllocateBuffers( new CommandBufferAllocateInfo(CommandBufferLevel.Primary, SwapchainImages.Length)); // Create a fence for each commandbuffer so that we can wait before using it again _initializingPermanent = true; //We need our fences to be there permanently SubmitFences = new Fence[SwapchainImages.Length]; for (int i = 0; i < SubmitFences.Length; i++) { ToDispose(SubmitFences[i] = Context.Device.CreateFence(new FenceCreateInfo(FenceCreateFlags.Signaled))); } // Allow concrete samples to initialize their resources. InitializePermanent(); _initializingPermanent = false; InitializeFrame(); // Record commands for execution by Vulkan. RecordCommandBuffers(); }
public static VkShaderModule LoadShaderModule(IVulkanAppHost host, VulkanContext ctx, string path) { const int defaultBufferSize = 4096; using (Stream stream = host.Open(path)) using (var ms = new MemoryStream()) { stream.CopyTo(ms, defaultBufferSize); byte[] bytes = ms.ToArray(); // Create a new shader module that will be used for Pipeline creation VkShaderModule shaderModule; vkCreateShaderModule(ctx.Device, bytes, null, out shaderModule); return(shaderModule); } }
public void Initialize(IVulkanAppHost host) { Host = host; #if DEBUG const bool debug = true; #else const bool debug = false; #endif _initializingPermanent = true; // Calling ToDispose here registers the resource to be automatically disposed on exit. Instance = ToDispose(CreateInstance(debug)); DebugReportCallback = ToDispose(CreateDebugReportCallback(debug)); Surface = ToDispose(CreateSurface()); Context = ToDispose(new VulkanContext(Instance, Surface, Host.Platform)); Content = ToDispose(new ContentManager(Host, Context, "Content")); ImageAvailableSemaphore = ToDispose(Context.Device.CreateSemaphore()); RenderingFinishedSemaphore = ToDispose(Context.Device.CreateSemaphore()); _initializingPermanent = false; // Calling ToDispose here registers the resource to be automatically disposed on events // such as window resize. Swapchain = ToDispose(CreateSwapchain()); // Acquire underlying images of the freshly created swapchain. SwapchainImages = Swapchain.GetImages(); // Create a command buffer for each swapchain image. CommandBuffers = Context.GraphicsCommandPool.AllocateBuffers( new CommandBufferAllocateInfo(CommandBufferLevel.Primary, SwapchainImages.Length)); // Allow concrete samples to initialize their resources. _initializingPermanent = true; InitializePermanent(); _initializingPermanent = false; InitializeFrame(); // Record commands for execution by Vulkan. RecordCommandBuffers(); }
public static VulkanImage LoadKtxVulkanImage(IVulkanAppHost host, VulkanContext ctx, string path) { using (var reader = new BinaryReader(host.Open(path))) { byte[] identifier = reader.ReadBytes(12); if (!identifier.SequenceEqual(KtxIdentifier)) { throw new InvalidOperationException("File is not in Khronos Texture format."); } int endienness = reader.ReadInt32(); int glType = reader.ReadInt32(); int glTypeSize = reader.ReadInt32(); int glFormat = reader.ReadInt32(); int glInternalFormat = reader.ReadInt32(); int glBaseInternalFormat = reader.ReadInt32(); int pixelWidth = reader.ReadInt32(); int pixelHeight = reader.ReadInt32(); int pixelDepth = reader.ReadInt32(); int numberOfArrayElements = reader.ReadInt32(); int numberOfFaces = reader.ReadInt32(); int numberOfMipmapLevels = reader.ReadInt32(); int bytesOfKeyValueData = reader.ReadInt32(); // Skip key-value data. reader.ReadBytes(bytesOfKeyValueData); // Some of the values may be 0 - ensure at least 1. pixelWidth = Math.Max(pixelWidth, 1); pixelHeight = Math.Max(pixelHeight, 1); pixelDepth = Math.Max(pixelDepth, 1); numberOfArrayElements = Math.Max(numberOfArrayElements, 1); numberOfFaces = Math.Max(numberOfFaces, 1); numberOfMipmapLevels = Math.Max(numberOfMipmapLevels, 1); int numberOfSlices = Math.Max(numberOfFaces, numberOfArrayElements); if (!_glInternalFormatToVkFormat.TryGetValue(glInternalFormat, out Format format)) { throw new NotImplementedException("glInternalFormat not mapped to VkFormat."); } var data = new TextureData { Mipmaps = new TextureData.Mipmap[numberOfMipmapLevels], Format = format }; for (int i = 0; i < numberOfMipmapLevels; i++) { var mipmap = new TextureData.Mipmap(); mipmap.Size = reader.ReadInt32(); mipmap.Extent = new Extent3D(pixelWidth, pixelHeight, pixelDepth); mipmap.Data = reader.ReadBytes(mipmap.Size); data.Mipmaps[i] = mipmap; break; // TODO: impl //for (int j = 0; j < numberOfArrayElements; j++) //{ // for (int k = 0; k < numberOfFaces; k++) // { // for (int l = 0; l < pixelDepth; l++) // { // //for (int row = 0; // // row < ) // } // } //} } return(VulkanImage.Texture2D(ctx, data)); } }
public ContentManager(IVulkanAppHost host, VulkanContext ctx, string contentRoot) { _host = host; _ctx = ctx; _contentRoot = contentRoot; }
public void Initialize(IVulkanAppHost host) { Host = host; #if DEBUG const bool debug = true; #else const bool debug = false; #endif _initializingPermanent = true; VkResult result = vkInitialize(); result.CheckResult(); // Calling ToDispose here registers the resource to be automatically disposed on exit. Instance = CreateInstance(debug); Surface = CreateSurface(); Context = new VulkanContext(Instance, Surface, Host.Platform); Content = new ContentManager(Host, Context, "Content"); ImageAvailableSemaphore = CreateSemaphore(Context.Device); RenderingFinishedSemaphore = CreateSemaphore(Context.Device); _initializingPermanent = false; // Calling ToDispose here registers the resource to be automatically disposed on events // such as window resize. var swapchain = CreateSwapchain(); Swapchain = swapchain; ToDispose(new ActionDisposable(() => { vkDestroySwapchainKHR(Context.Device, swapchain, null); })); // Acquire underlying images of the freshly created swapchain. uint swapchainImageCount; result = vkGetSwapchainImagesKHR(Context.Device, Swapchain, &swapchainImageCount, null); result.CheckResult(); var swapchainImages = stackalloc VkImage[(int)swapchainImageCount]; result = vkGetSwapchainImagesKHR(Context.Device, Swapchain, &swapchainImageCount, swapchainImages); result.CheckResult(); SwapchainImages = new VkImage[swapchainImageCount]; for (int i = 0; i < swapchainImageCount; i++) { SwapchainImages[i] = swapchainImages[i]; } VkCommandBufferAllocateInfo allocInfo = new VkCommandBufferAllocateInfo() { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = Context.GraphicsCommandPool, level = VkCommandBufferLevel.Primary, commandBufferCount = (uint)SwapchainImages.Length, }; VkCommandBuffer[] commandBuffers = new VkCommandBuffer[SwapchainImages.Length]; fixed(VkCommandBuffer *commandBuffersPtr = &commandBuffers[0]) { vkAllocateCommandBuffers(Context.Device, &allocInfo, commandBuffersPtr).CheckResult(); } CommandBuffers = commandBuffers; // Create a fence for each commandbuffer so that we can wait before using it again _initializingPermanent = true; //We need our fences to be there permanently SubmitFences = new VkFence[SwapchainImages.Length]; for (int i = 0; i < SubmitFences.Length; i++) { VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo() { sType = VkStructureType.FenceCreateInfo, pNext = null, flags = VkFenceCreateFlags.Signaled }; VkFence handle; vkCreateFence(Context.Device, &fenceCreateInfo, null, out handle); SubmitFences[i] = handle; ToDispose(new ActionDisposable(() => { vkDestroyFence(Context.Device, handle, null); })); } // Allow concrete samples to initialize their resources. InitializePermanent(); _initializingPermanent = false; InitializeFrame(); // Record commands for execution by Vulkan. RecordCommandBuffers(); }