public void RecordDraw(CommandBuffer cmd) { cmd.BindDescriptorSet(Layout, dsMain); envCube.RecordDraw(cmd); drawModel(cmd); }
void drawModel(CommandBuffer cmd) { Bind(cmd); model.Bind(cmd); model.DrawAll(cmd, Layout); }
//TODO:destset for binding must be variable //TODO: ADD REFAULT MAT IF NO MAT DEFINED public abstract void RenderNode(CommandBuffer cmd, PipelineLayout pipelineLayout, Node node, Matrix4x4 currentTransform, bool shadowPass = false);
/// <summary> bind vertex and index buffers </summary> public virtual void Bind(CommandBuffer cmd) { cmd.BindVertexBuffer(vbo); cmd.BindIndexBuffer(ibo, IndexBufferType); }
// Create an image memory barrier for changing the layout of // an image and put it into an active command buffer // See chapter 11.4 "Image Layout" for details public void SetLayout( CommandBuffer cmdbuffer, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkImageSubresourceRange subresourceRange, VkPipelineStageFlags srcStageMask = VkPipelineStageFlags.AllCommands, VkPipelineStageFlags dstStageMask = VkPipelineStageFlags.AllCommands) { // Create an image barrier object VkImageMemoryBarrier imageMemoryBarrier = VkImageMemoryBarrier.New(); imageMemoryBarrier.srcQueueFamilyIndex = Vk.QueueFamilyIgnored; imageMemoryBarrier.dstQueueFamilyIndex = Vk.QueueFamilyIgnored; imageMemoryBarrier.oldLayout = oldImageLayout; imageMemoryBarrier.newLayout = newImageLayout; imageMemoryBarrier.image = handle; imageMemoryBarrier.subresourceRange = subresourceRange; // Source layouts (old) // Source access mask controls actions that have to be finished on the old layout // before it will be transitioned to the new layout switch (oldImageLayout) { case VkImageLayout.Undefined: // Image layout is undefined (or does not matter) // Only valid as initial layout // No flags required, listed only for completeness imageMemoryBarrier.srcAccessMask = 0; break; case VkImageLayout.Preinitialized: // Image is preinitialized // Only valid as initial layout for linear images, preserves memory contents // Make sure host writes have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.HostWrite; break; case VkImageLayout.ColorAttachmentOptimal: // Image is a color attachment // Make sure any writes to the color buffer have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.ColorAttachmentWrite; break; case VkImageLayout.DepthStencilAttachmentOptimal: // Image is a depth/stencil attachment // Make sure any writes to the depth/stencil buffer have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.DepthStencilAttachmentWrite; break; case VkImageLayout.TransferSrcOptimal: // Image is a transfer source // Make sure any reads from the image have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferRead; break; case VkImageLayout.TransferDstOptimal: // Image is a transfer destination // Make sure any writes to the image have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferWrite; break; case VkImageLayout.ShaderReadOnlyOptimal: // Image is read by a shader // Make sure any shader reads from the image have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.ShaderRead; break; } // Target layouts (new) // Destination access mask controls the dependency for the new image layout switch (newImageLayout) { case VkImageLayout.TransferDstOptimal: // Image will be used as a transfer destination // Make sure any writes to the image have been finished imageMemoryBarrier.dstAccessMask = VkAccessFlags.TransferWrite; break; case VkImageLayout.TransferSrcOptimal: // Image will be used as a transfer source // Make sure any reads from and writes to the image have been finished imageMemoryBarrier.srcAccessMask = imageMemoryBarrier.srcAccessMask | VkAccessFlags.TransferRead; imageMemoryBarrier.dstAccessMask = VkAccessFlags.TransferRead; break; case VkImageLayout.ColorAttachmentOptimal: // Image will be used as a color attachment // Make sure any writes to the color buffer have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferRead; imageMemoryBarrier.dstAccessMask = VkAccessFlags.ColorAttachmentWrite; break; case VkImageLayout.DepthStencilAttachmentOptimal: // Image layout will be used as a depth/stencil attachment // Make sure any writes to depth/stencil buffer have been finished imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VkAccessFlags.DepthStencilAttachmentWrite; break; case VkImageLayout.ShaderReadOnlyOptimal: // Image will be read in a shader (sampler, input attachment) // Make sure any writes to the image have been finished if (imageMemoryBarrier.srcAccessMask == 0) { imageMemoryBarrier.srcAccessMask = VkAccessFlags.HostWrite | VkAccessFlags.TransferWrite; } imageMemoryBarrier.dstAccessMask = VkAccessFlags.ShaderRead; break; } // Put barrier inside setup command buffer Vk.vkCmdPipelineBarrier( cmdbuffer.Handle, srcStageMask, dstStageMask, 0, 0, IntPtr.Zero, 0, IntPtr.Zero, 1, ref imageMemoryBarrier); }
///// <summary> ///// build texture array ///// </summary> ///// <returns>The images.</returns> ///// <param name="textureSize">Texture size.</param> public void BuildTexArray(ref Image texArray, uint firstImg = 0) { int texDim = (int)texArray.CreateInfo.extent.width; CommandBuffer cmd = cmdPool.AllocateAndStart(VkCommandBufferUsageFlags.OneTimeSubmit); texArray.SetLayout(cmd, VkImageAspectFlags.Color, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.Transfer); cmd.End(); transferQ.Submit(cmd); transferQ.WaitIdle(); cmd.Free(); VkImageBlit imageBlit = new VkImageBlit { srcSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, 1, 0), dstOffsets_1 = new VkOffset3D(texDim, texDim, 1) }; for (int l = 0; l < gltf.Images.Length; l++) { GL.Image img = gltf.Images[l]; Image vkimg = null; if (img.BufferView != null) //load image from gltf buffer view { GL.BufferView bv = gltf.BufferViews[(int)img.BufferView]; EnsureBufferIsLoaded(bv.Buffer); vkimg = Image.Load(dev, bufferHandles[bv.Buffer].AddrOfPinnedObject() + bv.ByteOffset, (ulong)bv.ByteLength); } else if (img.Uri.StartsWith("data:", StringComparison.Ordinal)) //load base64 encoded image { Debug.WriteLine("loading embedded image {0} : {1}", img.Name, img.MimeType); vkimg = Image.Load(dev, glTFLoader.loadDataUri(img)); } else { Debug.WriteLine("loading image {0} : {1} : {2}", img.Name, img.MimeType, img.Uri); //load image from file path in uri vkimg = Image.Load(dev, Path.Combine(baseDirectory, img.Uri)); } imageBlit.srcOffsets_1 = new VkOffset3D((int)vkimg.CreateInfo.extent.width, (int)vkimg.CreateInfo.extent.height, 1); imageBlit.dstSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, 1, 0, (uint)l + firstImg); cmd = cmdPool.AllocateAndStart(VkCommandBufferUsageFlags.OneTimeSubmit); vkimg.SetLayout(cmd, VkImageAspectFlags.Color, VkImageLayout.Undefined, VkImageLayout.TransferSrcOptimal, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.Transfer); Vk.vkCmdBlitImage(cmd.Handle, vkimg.handle, VkImageLayout.TransferSrcOptimal, texArray.handle, VkImageLayout.TransferDstOptimal, 1, ref imageBlit, VkFilter.Linear); cmd.End(); transferQ.Submit(cmd); transferQ.WaitIdle(); cmd.Free(); vkimg.Dispose(); } uint imgCount = (uint)gltf.Images.Length; VkImageSubresourceRange mipSubRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, firstImg, imgCount); cmd = cmdPool.AllocateAndStart(VkCommandBufferUsageFlags.OneTimeSubmit); texArray.SetLayout(cmd, VkImageLayout.Undefined, VkImageLayout.TransferSrcOptimal, mipSubRange, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.Transfer); for (int i = 1; i < texArray.CreateInfo.mipLevels; i++) { imageBlit = new VkImageBlit { srcSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, imgCount, (uint)i - 1, firstImg), srcOffsets_1 = new VkOffset3D((int)texDim >> (i - 1), (int)texDim >> (i - 1), 1), dstSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, imgCount, (uint)i, firstImg), dstOffsets_1 = new VkOffset3D((int)texDim >> i, (int)texDim >> i, 1) }; mipSubRange.baseMipLevel = (uint)i; texArray.SetLayout(cmd, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, mipSubRange, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.Transfer); Vk.vkCmdBlitImage(cmd.Handle, texArray.handle, VkImageLayout.TransferSrcOptimal, texArray.handle, VkImageLayout.TransferDstOptimal, 1, ref imageBlit, VkFilter.Linear); texArray.SetLayout(cmd, VkImageLayout.TransferDstOptimal, VkImageLayout.TransferSrcOptimal, mipSubRange, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.Transfer); } texArray.SetLayout(cmd, VkImageAspectFlags.Color, VkImageLayout.TransferSrcOptimal, VkImageLayout.ShaderReadOnlyOptimal, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader); cmd.End(); transferQ.Submit(cmd); transferQ.WaitIdle(); cmd.Free(); }
//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()); }