aboutsummaryrefslogtreecommitdiffstatsci
path: root/vke/src/Device.cs
blob: 869f639642f7553e8f98508755af4d05f841115d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
//
// Device.cs
//
// Author:
//       Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
//
// Copyright (c) 2019 jp
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Vulkan;
using static Vulkan.VulkanNative;

namespace VKE {
    public class Device : IDisposable {
        public readonly PhysicalDevice phy;
        VkDevice dev;
        public VkDevice VkDev => dev;

        internal List<Queue> queues = new List<Queue> ();

        public Device (PhysicalDevice _phy) {
            phy = _phy;
        }

        unsafe public void Activate (VkPhysicalDeviceFeatures enabledFeatures, params string[] extensions) {

            List<VkDeviceQueueCreateInfo> qInfos = new List<VkDeviceQueueCreateInfo> ();
			List<List<float>> prioritiesLists = new List<List<float>> ();

            foreach (IGrouping<uint, Queue> qfams in queues.GroupBy (q => q.qFamIndex)) {
                int qTot = qfams.Count ();
                uint qIndex = 0;
                List<float>priorities = new List<float> ();
                bool qCountReached = false;//true when queue count of that family is reached

                foreach (Queue q in qfams) {
                    if (!qCountReached)
                        priorities.Add (q.priority);
                    q.index = qIndex++;
                    if (qIndex == phy.QueueFamilies[qfams.Key].queueCount) {
                        qIndex = 0;
                        qCountReached = true;
                    }
                }					

                qInfos.Add (new VkDeviceQueueCreateInfo {
                    sType = VkStructureType.DeviceQueueCreateInfo,
                    queueCount = qCountReached ? phy.QueueFamilies[qfams.Key].queueCount : qIndex,
                    queueFamilyIndex = qfams.Key,
                    pQueuePriorities = priorities.Pin ()
                });
				prioritiesLists.Add (priorities);//add for unpined
            }            

            List<IntPtr> deviceExtensions = new List<IntPtr> ();
            for (int i = 0; i < extensions.Length; i++) {
                deviceExtensions.Add (new FixedUtf8String(extensions[i]));
            }

            VkPhysicalDeviceFeatures features = enabledFeatures;
            VkDeviceCreateInfo deviceCreateInfo = VkDeviceCreateInfo.New ();

            deviceCreateInfo.queueCreateInfoCount = (uint)qInfos.Count;
            deviceCreateInfo.pQueueCreateInfos = qInfos.Pin();
            deviceCreateInfo.pEnabledFeatures = &features;

            if (deviceExtensions.Count > 0) {
                deviceCreateInfo.enabledExtensionCount = (uint)deviceExtensions.Count;
                deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.Pin();
            }

            Utils.CheckResult (vkCreateDevice (phy.Handle, ref deviceCreateInfo, IntPtr.Zero, out dev));

            qInfos.Unpin ();
			foreach (List<float> fa in prioritiesLists) 
				fa.Unpin ();

            deviceExtensions.Unpin ();

            foreach (Queue q in queues)
                q.updateHandle ();
        }

        unsafe public VkSemaphore CreateSemaphore () {
            VkSemaphore tmp;
            VkSemaphoreCreateInfo info = VkSemaphoreCreateInfo.New ();
            Utils.CheckResult (vkCreateSemaphore (dev, ref info, IntPtr.Zero, out tmp));
            return tmp;
        }
        public void DestroySemaphore (VkSemaphore semaphore) {
            vkDestroySemaphore (dev, semaphore, IntPtr.Zero);
        }
        unsafe public VkFence CreateFence (bool signaled = false) {
            VkFence tmp;
            VkFenceCreateInfo info = VkFenceCreateInfo.New ();
            info.flags = signaled ? VkFenceCreateFlags.Signaled : VkFenceCreateFlags.None;
            Utils.CheckResult (vkCreateFence (dev, ref info, IntPtr.Zero, out tmp));
            return tmp;
        }
        public void DestroyFence (VkFence fence) {
            vkDestroyFence (dev, fence, IntPtr.Zero);
        }
        public void WaitForFence (VkFence fence, ulong timeOut = UInt64.MaxValue) {
            vkWaitForFences (dev, 1, ref fence, true, timeOut);
        }
        public void ResetFence (VkFence fence) {
            vkResetFences (dev, 1, ref fence);
        }
        public void WaitForFences (NativeList<VkFence> fences, ulong timeOut = UInt64.MaxValue) {
            vkWaitForFences (dev, fences.Count, fences.Data, true, timeOut);
        }
        public void ResetFences (NativeList<VkFence> fences) {
            vkResetFences (dev, fences.Count, fences.Data);
        }

        public void DestroyShaderModule (VkShaderModule module) {
            vkDestroyShaderModule (VkDev, module, IntPtr.Zero);
        }
        public void DestroyDescriptorPool (VkDescriptorPool pool) {
            vkDestroyDescriptorPool (VkDev, pool, IntPtr.Zero);
        }
        public void WaitIdle () {
            Utils.CheckResult(vkDeviceWaitIdle (dev));
        }
        public VkRenderPass CreateRenderPass (VkRenderPassCreateInfo info) {
            VkRenderPass renderPass;
            Utils.CheckResult (vkCreateRenderPass (dev, ref info, IntPtr.Zero, out renderPass));
            return renderPass;
        }
        internal VkSwapchainKHR CreateSwapChain (VkSwapchainCreateInfoKHR infos) {
            VkSwapchainKHR newSwapChain;
            Utils.CheckResult (vkCreateSwapchainKHR (dev, ref infos, IntPtr.Zero, out newSwapChain));
            return newSwapChain;
        }
        internal void DestroySwapChain (VkSwapchainKHR swapChain) {
            vkDestroySwapchainKHR (dev, swapChain, IntPtr.Zero);
        }
        unsafe public VkImage[] GetSwapChainImages (VkSwapchainKHR swapchain) {
            uint imageCount = 0;
            Utils.CheckResult (vkGetSwapchainImagesKHR (dev, swapchain, ref imageCount, IntPtr.Zero));
            if (imageCount == 0)
                throw new Exception ("Swapchain image count is 0.");
            VkImage[] imgs = new VkImage[imageCount];
            
            Utils.CheckResult (vkGetSwapchainImagesKHR (dev, swapchain, ref imageCount, imgs.Pin()));
			imgs.Unpin ();
            
            return imgs;
        }
        unsafe public VkImageView CreateImageView (VkImage image, VkFormat format, VkImageViewType viewType = VkImageViewType.Image2D, VkImageAspectFlags aspectFlags = VkImageAspectFlags.Color) {
            VkImageView view;
            VkImageViewCreateInfo infos = VkImageViewCreateInfo.New ();
            infos.image = image;
            infos.viewType = viewType;
            infos.format = format;
            infos.components = new VkComponentMapping { r = VkComponentSwizzle.R, g = VkComponentSwizzle.G, b = VkComponentSwizzle.B, a = VkComponentSwizzle.A };
            infos.subresourceRange = new VkImageSubresourceRange (aspectFlags);
                    
            Utils.CheckResult (vkCreateImageView (dev, ref infos, IntPtr.Zero, out view));
            return view;
        }
        public void DestroyImageView (VkImageView view) {
            vkDestroyImageView (dev, view, IntPtr.Zero);
        }
        public void DestroySampler (VkSampler sampler) {
            vkDestroySampler (dev, sampler, IntPtr.Zero);
        }
        public void DestroyImage (VkImage img) {
            vkDestroyImage (dev, img, IntPtr.Zero);
        }
        public void DestroyFramebuffer (VkFramebuffer fb) {
            vkDestroyFramebuffer (dev, fb, IntPtr.Zero);
        }
        public void DestroyRenderPass (VkRenderPass rp) {
            vkDestroyRenderPass (dev, rp, IntPtr.Zero);
        }

        unsafe public CommandPool CreateCommandPool (uint qFamIdx) {
            VkCommandPool pool;
            VkCommandPoolCreateInfo infos = VkCommandPoolCreateInfo.New ();
            infos.queueFamilyIndex = qFamIdx;
            Utils.CheckResult (vkCreateCommandPool (dev, ref infos, IntPtr.Zero, out pool));
            return new CommandPool (this, qFamIdx, pool);
        }
        // This function is used to request a Device memory type that supports all the property flags we request (e.g. Device local, host visibile)
        // Upon success it will return the index of the memory type that fits our requestes memory properties
        // This is necessary as implementations can offer an arbitrary number of memory types with different
        // memory properties. 
        // You can check http://vulkan.gpuinfo.org/ for details on different memory configurations
        internal unsafe  uint GetMemoryTypeIndex (uint typeBits, VkMemoryPropertyFlags properties) {
            // Iterate over all memory types available for the Device used in this example
            for (uint i = 0; i < phy.memoryProperties.memoryTypeCount; i++) {
                if ((typeBits & 1) == 1) {
                    if ((phy.memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) {
                        return i;
                    }
                }
                typeBits >>= 1;
            }

            throw new InvalidOperationException ("Could not find a suitable memory type!");
        }
        public VkFormat GetSuitableDepthFormat () {
            VkFormat[] formats = new VkFormat[] { VkFormat.D32SfloatS8Uint, VkFormat.D32Sfloat, VkFormat.D24UnormS8Uint, VkFormat.D16UnormS8Uint, VkFormat.D16Unorm };
            foreach (VkFormat f in formats) {
                if (phy.GetFormatProperties (f).optimalTilingFeatures.HasFlag(VkFormatFeatureFlags.DepthStencilAttachment))
                    return f;
            }
            throw new InvalidOperationException ("No suitable depth format found.");
        }

        public VkShaderModule LoadSPIRVShader (string filename) {
            byte[] shaderCode = File.ReadAllBytes (filename);
            ulong shaderSize = (ulong)shaderCode.Length;
            unsafe {
                fixed (byte* scPtr = shaderCode) {
                    // Create a new shader module that will be used for Pipeline creation
                    VkShaderModuleCreateInfo moduleCreateInfo = VkShaderModuleCreateInfo.New ();
                    moduleCreateInfo.codeSize = new UIntPtr (shaderSize);
                    moduleCreateInfo.pCode = (uint*)scPtr;

                    Utils.CheckResult (vkCreateShaderModule (VkDev, ref moduleCreateInfo, IntPtr.Zero, out VkShaderModule shaderModule));

                    return shaderModule;
                }
            }
        }

        #region IDisposable Support
        private bool disposedValue = false; // Pour détecter les appels redondants

        protected virtual void Dispose (bool disposing) {
            if (!disposedValue) {
                if (disposing) {
                    // TODO: supprimer l'état managé (objets managés).
                }

                vkDestroyDevice (dev, IntPtr.Zero);

                disposedValue = true;
            }
        }

        // TODO: remplacer un finaliseur seulement si la fonction Dispose(bool disposing) ci-dessus a du code pour libérer les ressources non managées.
        ~Device() {
           // Ne modifiez pas ce code. Placez le code de nettoyage dans Dispose(bool disposing) ci-dessus.
           Dispose(false);
        }

        // Ce code est ajouté pour implémenter correctement le modèle supprimable.
        public void Dispose () {
            // Ne modifiez pas ce code. Placez le code de nettoyage dans Dispose(bool disposing) ci-dessus.
            Dispose (true);
            // TODO: supprimer les marques de commentaire pour la ligne suivante si le finaliseur est remplacé ci-dessus.
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}