public CommandBuffer AllocateAndStart(VkCommandBufferUsageFlags usage = 0, VkCommandBufferLevel level = VkCommandBufferLevel.Primary) { CommandBuffer cmd = AllocateCommandBuffer(level); cmd.Start(usage); return(cmd); }
public void BuildMipmaps(Queue copyQ, CommandPool copyCmdPool) { if (info.mipLevels == 1) { Debug.WriteLine("Invoking BuildMipmaps on image that has only one mipLevel"); return; } CommandBuffer cmd = copyCmdPool.AllocateCommandBuffer(); cmd.Start(VkCommandBufferUsageFlags.OneTimeSubmit); BuildMipmaps(cmd); cmd.End(); copyQ.Submit(cmd); copyQ.WaitIdle(); cmd.Free(); }
void generateBRDFLUT(Queue staggingQ, CommandPool cmdPool) { const VkFormat format = VkFormat.R16g16Sfloat; const int dim = 512; lutBrdf = new Image(Dev, format, VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.Sampled, VkMemoryPropertyFlags.DeviceLocal, dim, dim); lutBrdf.SetName("lutBrdf"); lutBrdf.CreateView(); lutBrdf.CreateSampler(VkSamplerAddressMode.ClampToEdge); GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault(VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false); cfg.Layout = new PipelineLayout(Dev, new DescriptorSetLayout(Dev)); cfg.RenderPass = new RenderPass(Dev); cfg.RenderPass.AddAttachment(format, VkImageLayout.ShaderReadOnlyOptimal); cfg.RenderPass.ClearValues.Add(new VkClearValue { color = new VkClearColorValue(0, 0, 0) }); cfg.RenderPass.AddSubpass(new SubPass(VkImageLayout.ColorAttachmentOptimal)); cfg.AddShader(VkShaderStageFlags.Vertex, "shaders/genbrdflut.vert.spv"); cfg.AddShader(VkShaderStageFlags.Fragment, "shaders/genbrdflut.frag.spv"); using (GraphicPipeline pl = new GraphicPipeline(cfg)) { using (Framebuffer fb = new Framebuffer(cfg.RenderPass, dim, dim, lutBrdf)) { CommandBuffer cmd = cmdPool.AllocateCommandBuffer(); cmd.Start(VkCommandBufferUsageFlags.OneTimeSubmit); pl.RenderPass.Begin(cmd, fb); cmd.SetViewport(dim, dim); cmd.SetScissor(dim, dim); pl.Bind(cmd); cmd.Draw(3, 1, 0, 0); pl.RenderPass.End(cmd); cmd.End(); staggingQ.Submit(cmd); staggingQ.WaitIdle(); cmd.Free(); } } lutBrdf.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; }
/// <summary> /// load bitmap from pointer /// </summary> void load(Queue staggingQ, CommandPool staggingCmdPool, IntPtr bitmap, bool generateMipmaps = true) { long size = info.extent.width * info.extent.height * 4 * info.extent.depth; if (MemoryFlags.HasFlag(VkMemoryPropertyFlags.HostVisible)) { Map(); unsafe { System.Buffer.MemoryCopy(bitmap.ToPointer(), MappedData.ToPointer(), size, size); } Unmap(); if (generateMipmaps) { BuildMipmaps(staggingQ, staggingCmdPool); } } else { using (HostBuffer stagging = new HostBuffer(Dev, VkBufferUsageFlags.TransferSrc, (UInt64)size, bitmap)) { CommandBuffer cmd = staggingCmdPool.AllocateCommandBuffer(); cmd.Start(VkCommandBufferUsageFlags.OneTimeSubmit); stagging.CopyTo(cmd, this); if (generateMipmaps) { BuildMipmaps(cmd); } cmd.End(); staggingQ.Submit(cmd); staggingQ.WaitIdle(); cmd.Free(); } } }
public Image generateCubeMap(Queue staggingQ, CommandPool cmdPool, CBTarget target) { const float deltaPhi = (2.0f * (float)Math.PI) / 180.0f; const float deltaTheta = (0.5f * (float)Math.PI) / 64.0f; VkFormat format = VkFormat.R32g32b32a32Sfloat; uint dim = 64; if (target == CBTarget.PREFILTEREDENV) { format = VkFormat.R16g16b16a16Sfloat; dim = 512; } uint numMips = (uint)Math.Floor(Math.Log(dim, 2)) + 1; Image imgFbOffscreen = new Image(Dev, format, VkImageUsageFlags.TransferSrc | VkImageUsageFlags.ColorAttachment, VkMemoryPropertyFlags.DeviceLocal, dim, dim); imgFbOffscreen.SetName("offscreenfb"); imgFbOffscreen.CreateView(); Image cmap = new Image(Dev, format, VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled, VkMemoryPropertyFlags.DeviceLocal, dim, dim, VkImageType.Image2D, VkSampleCountFlags.SampleCount1, VkImageTiling.Optimal, numMips, 6, 1, VkImageCreateFlags.CubeCompatible); if (target == CBTarget.PREFILTEREDENV) { cmap.SetName("prefilterenvmap"); } else { cmap.SetName("irradianceCube"); } cmap.CreateView(VkImageViewType.Cube, VkImageAspectFlags.Color, 6, 0, numMips); cmap.CreateSampler(VkSamplerAddressMode.ClampToEdge); DescriptorPool dsPool = new DescriptorPool(Dev, 2, new VkDescriptorPoolSize(VkDescriptorType.CombinedImageSampler)); DescriptorSetLayout dsLayout = new DescriptorSetLayout(Dev, new VkDescriptorSetLayoutBinding(0, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler)); GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault(VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount1, false); cfg.Layout = new PipelineLayout(Dev, dsLayout); cfg.Layout.AddPushConstants( new VkPushConstantRange(VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf <Matrix4x4> () + 8)); cfg.RenderPass = new RenderPass(Dev); cfg.RenderPass.AddAttachment(format, VkImageLayout.ColorAttachmentOptimal); cfg.RenderPass.ClearValues.Add(new VkClearValue { color = new VkClearColorValue(0, 0, 0) }); cfg.RenderPass.AddSubpass(new SubPass(VkImageLayout.ColorAttachmentOptimal)); cfg.AddVertexBinding(0, 3 * sizeof(float)); cfg.AddVertexAttributes(0, VkFormat.R32g32b32Sfloat); cfg.AddShader(VkShaderStageFlags.Vertex, "shaders/filtercube.vert.spv"); if (target == CBTarget.PREFILTEREDENV) { cfg.AddShader(VkShaderStageFlags.Fragment, "shaders/prefilterenvmap.frag.spv"); } else { cfg.AddShader(VkShaderStageFlags.Fragment, "shaders/irradiancecube.frag.spv"); } Matrix4x4[] matrices = { // POSITIVE_X Matrix4x4.CreateRotationX(Utils.DegreesToRadians(180)) * Matrix4x4.CreateRotationY(Utils.DegreesToRadians(90)), // NEGATIVE_X Matrix4x4.CreateRotationX(Utils.DegreesToRadians(180)) * Matrix4x4.CreateRotationY(Utils.DegreesToRadians(-90)), // POSITIVE_Y Matrix4x4.CreateRotationX(Utils.DegreesToRadians(-90)), // NEGATIVE_Y Matrix4x4.CreateRotationX(Utils.DegreesToRadians(90)), // POSITIVE_Z Matrix4x4.CreateRotationX(Utils.DegreesToRadians(180)), // NEGATIVE_Z Matrix4x4.CreateRotationZ(Utils.DegreesToRadians(180)) }; VkImageSubresourceRange subRes = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, numMips, 0, 6); using (GraphicPipeline pl = new GraphicPipeline(cfg)) { DescriptorSet dset = dsPool.Allocate(dsLayout); DescriptorSetWrites dsUpdate = new DescriptorSetWrites(dsLayout); dsUpdate.Write(Dev, dset, cubemap.Descriptor); Dev.WaitIdle(); using (Framebuffer fb = new Framebuffer(pl.RenderPass, dim, dim, imgFbOffscreen)) { CommandBuffer cmd = cmdPool.AllocateCommandBuffer(); cmd.Start(VkCommandBufferUsageFlags.OneTimeSubmit); cmap.SetLayout(cmd, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, subRes); float roughness = 0; cmd.SetScissor(dim, dim); cmd.SetViewport((float)(dim), (float)dim); for (int m = 0; m < numMips; m++) { roughness = (float)m / ((float)numMips - 1f); for (int f = 0; f < 6; f++) { pl.RenderPass.Begin(cmd, fb); pl.Bind(cmd); float viewPortSize = (float)Math.Pow(0.5, m) * dim; cmd.SetViewport(viewPortSize, viewPortSize); cmd.PushConstant(pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, matrices[f] * Matrix4x4.CreatePerspectiveFieldOfView(Utils.DegreesToRadians(90), 1f, 0.1f, 512f)); if (target == CBTarget.IRRADIANCE) { cmd.PushConstant(pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, deltaPhi, (uint)Marshal.SizeOf <Matrix4x4> ()); cmd.PushConstant(pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, deltaTheta, (uint)Marshal.SizeOf <Matrix4x4> () + 4); } else { cmd.PushConstant(pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, roughness, (uint)Marshal.SizeOf <Matrix4x4> ()); cmd.PushConstant(pl.Layout, VkShaderStageFlags.Vertex | VkShaderStageFlags.Fragment, 64u, (uint)Marshal.SizeOf <Matrix4x4> () + 4); } cmd.BindDescriptorSet(pl.Layout, dset); cmd.BindVertexBuffer(vboSkybox); cmd.Draw(36); pl.RenderPass.End(cmd); imgFbOffscreen.SetLayout(cmd, VkImageAspectFlags.Color, VkImageLayout.ColorAttachmentOptimal, VkImageLayout.TransferSrcOptimal); VkImageCopy region = new VkImageCopy(); region.srcSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, 1); region.dstSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, 1, (uint)m, (uint)f); region.extent = new VkExtent3D { width = (uint)viewPortSize, height = (uint)viewPortSize, depth = 1 }; Vk.vkCmdCopyImage(cmd.Handle, imgFbOffscreen.Handle, VkImageLayout.TransferSrcOptimal, cmap.Handle, VkImageLayout.TransferDstOptimal, 1, region.Pin()); region.Unpin(); imgFbOffscreen.SetLayout(cmd, VkImageAspectFlags.Color, VkImageLayout.TransferSrcOptimal, VkImageLayout.ColorAttachmentOptimal); } } cmap.SetLayout(cmd, VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal, subRes); cmd.End(); staggingQ.Submit(cmd); staggingQ.WaitIdle(); cmd.Free(); } } cmap.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; dsLayout.Dispose(); imgFbOffscreen.Dispose(); dsPool.Dispose(); return(cmap); }
//TODO: some buffer data are reused between primitives, and I duplicate the datas //buffers must be constructed without duplications public Mesh[] LoadMeshes <TVertex> (VkIndexType indexType, Buffer vbo, ulong vboOffset, Buffer ibo, ulong iboOffset) { ulong vCount, iCount; VkIndexType idxType; GetVertexCount(out vCount, out iCount, out idxType); int vertexByteSize = Marshal.SizeOf <TVertex> (); ulong vertSize = vCount * (ulong)vertexByteSize; ulong idxSize = iCount * (indexType == VkIndexType.Uint16 ? 2ul : 4ul); ulong size = vertSize + idxSize; int vertexCount = 0, indexCount = 0; int autoNamedMesh = 1; meshes = new List <Mesh> (); using (HostBuffer stagging = new HostBuffer(dev, VkBufferUsageFlags.TransferSrc, size)) { stagging.Map(); unsafe { byte *stagVertPtrInit = (byte *)stagging.MappedData.ToPointer(); byte *stagIdxPtrInit = (byte *)(stagging.MappedData.ToPointer()) + vertSize; byte *stagVertPtr = stagVertPtrInit; byte *stagIdxPtr = stagIdxPtrInit; foreach (GL.Mesh mesh in gltf.Meshes) { string meshName = mesh.Name; if (string.IsNullOrEmpty(meshName)) { meshName = "mesh_" + autoNamedMesh.ToString(); autoNamedMesh++; } Mesh m = new Mesh { Name = meshName }; foreach (GL.MeshPrimitive p in mesh.Primitives) { GL.Accessor AccPos = null, AccNorm = null, AccUv = null, AccUv1 = null; int accessorIdx; if (p.Attributes.TryGetValue("POSITION", out accessorIdx)) { AccPos = gltf.Accessors[accessorIdx]; EnsureBufferIsLoaded(gltf.BufferViews[(int)AccPos.BufferView].Buffer); } if (p.Attributes.TryGetValue("NORMAL", out accessorIdx)) { AccNorm = gltf.Accessors[accessorIdx]; EnsureBufferIsLoaded(gltf.BufferViews[(int)AccNorm.BufferView].Buffer); } if (p.Attributes.TryGetValue("TEXCOORD_0", out accessorIdx)) { AccUv = gltf.Accessors[accessorIdx]; EnsureBufferIsLoaded(gltf.BufferViews[(int)AccUv.BufferView].Buffer); } if (p.Attributes.TryGetValue("TEXCOORD_1", out accessorIdx)) { AccUv1 = gltf.Accessors[accessorIdx]; EnsureBufferIsLoaded(gltf.BufferViews[(int)AccUv1.BufferView].Buffer); } Primitive prim = new Primitive { indexBase = (uint)indexCount, vertexBase = vertexCount, vertexCount = (uint)AccPos.Count, material = (uint)(p.Material ?? 0) }; prim.bb.min.ImportFloatArray(AccPos.Min); prim.bb.max.ImportFloatArray(AccPos.Max); prim.bb.isValid = true; //Interleaving vertices byte *inPosPtr = null, inNormPtr = null, inUvPtr = null, inUv1Ptr = null; GL.BufferView bv = gltf.BufferViews[(int)AccPos.BufferView]; inPosPtr = (byte *)bufferHandles[bv.Buffer].AddrOfPinnedObject().ToPointer(); inPosPtr += AccPos.ByteOffset + bv.ByteOffset; if (AccNorm != null) { bv = gltf.BufferViews[(int)AccNorm.BufferView]; inNormPtr = (byte *)bufferHandles[bv.Buffer].AddrOfPinnedObject().ToPointer(); inNormPtr += AccNorm.ByteOffset + bv.ByteOffset; } if (AccUv != null) { bv = gltf.BufferViews[(int)AccUv.BufferView]; inUvPtr = (byte *)bufferHandles[bv.Buffer].AddrOfPinnedObject().ToPointer(); inUvPtr += AccUv.ByteOffset + bv.ByteOffset; } if (AccUv1 != null) { bv = gltf.BufferViews[(int)AccUv1.BufferView]; inUv1Ptr = (byte *)bufferHandles[bv.Buffer].AddrOfPinnedObject().ToPointer(); inUv1Ptr += AccUv1.ByteOffset + bv.ByteOffset; } for (int j = 0; j < prim.vertexCount; j++) { System.Buffer.MemoryCopy(inPosPtr, stagVertPtr, 12, 12); inPosPtr += 12; if (inNormPtr != null) { System.Buffer.MemoryCopy(inNormPtr, stagVertPtr + 12, 12, 12); inNormPtr += 12; } if (inUvPtr != null) { System.Buffer.MemoryCopy(inUvPtr, stagVertPtr + 24, 8, 8); inUvPtr += 8; } if (inUv1Ptr != null) { System.Buffer.MemoryCopy(inUv1Ptr, stagVertPtr + 32, 8, 8); inUv1Ptr += 8; } stagVertPtr += vertexByteSize; } //indices loading if (p.Indices != null) { GL.Accessor acc = gltf.Accessors[(int)p.Indices]; bv = gltf.BufferViews[(int)acc.BufferView]; byte *inIdxPtr = (byte *)bufferHandles[bv.Buffer].AddrOfPinnedObject().ToPointer(); inIdxPtr += acc.ByteOffset + bv.ByteOffset; //TODO:double check this, I dont seems to increment stag pointer if (acc.ComponentType == GL.Accessor.ComponentTypeEnum.UNSIGNED_SHORT) { if (indexType == VkIndexType.Uint16) { System.Buffer.MemoryCopy(inIdxPtr, stagIdxPtr, (long)acc.Count * 2, (long)acc.Count * 2); stagIdxPtr += (long)acc.Count * 2; } else { uint * usPtr = (uint *)stagIdxPtr; ushort *inPtr = (ushort *)inIdxPtr; for (int i = 0; i < acc.Count; i++) { usPtr[i] = inPtr[i]; } stagIdxPtr += (long)acc.Count * 4; } } else if (acc.ComponentType == GL.Accessor.ComponentTypeEnum.UNSIGNED_INT) { if (indexType == VkIndexType.Uint32) { System.Buffer.MemoryCopy(inIdxPtr, stagIdxPtr, (long)acc.Count * 4, (long)acc.Count * 4); stagIdxPtr += (long)acc.Count * 4; } else { ushort *usPtr = (ushort *)stagIdxPtr; uint * inPtr = (uint *)inIdxPtr; for (int i = 0; i < acc.Count; i++) { usPtr[i] = (ushort)inPtr[i]; } stagIdxPtr += (long)acc.Count * 2; } } else if (acc.ComponentType == GL.Accessor.ComponentTypeEnum.UNSIGNED_BYTE) { //convert if (indexType == VkIndexType.Uint16) { ushort *usPtr = (ushort *)stagIdxPtr; for (int i = 0; i < acc.Count; i++) { usPtr[i] = (ushort)inIdxPtr[i]; } stagIdxPtr += (long)acc.Count * 2; } else { uint *usPtr = (uint *)stagIdxPtr; for (int i = 0; i < acc.Count; i++) { usPtr[i] = (uint)inIdxPtr[i]; } stagIdxPtr += (long)acc.Count * 4; } } else { throw new NotImplementedException(); } prim.indexCount = (uint)acc.Count; indexCount += acc.Count; } m.AddPrimitive(prim); vertexCount += AccPos.Count; } meshes.Add(m); } } stagging.Unmap(); CommandBuffer cmd = cmdPool.AllocateCommandBuffer(); cmd.Start(VkCommandBufferUsageFlags.OneTimeSubmit); stagging.CopyTo(cmd, vbo, vertSize, 0, vboOffset); if (iCount > 0) { stagging.CopyTo(cmd, ibo, idxSize, vertSize, iboOffset); } cmd.End(); transferQ.Submit(cmd); dev.WaitIdle(); cmd.Free(); } return(meshes.ToArray()); }