void buildCommandBuffers() { dev.WaitIdle(); cmdPool.Reset(); for (int i = 0; i < swapChain.ImageCount; ++i) { PrimaryCommandBuffer cmd = cmds[i]; FrameBuffer fb = frameBuffers[i]; cmd.Start(); pipeline.RenderPass.Begin(cmd, fb); cmd.SetViewport(fb.Width, fb.Height); cmd.SetScissor(fb.Width, fb.Height); cmd.BindDescriptorSet(pipeline.Layout, descriptorSet); pipeline.Bind(cmd); cmd.BindVertexBuffer(vbo, 0); cmd.BindIndexBuffer(ibo, VkIndexType.Uint16); cmd.DrawIndexed((uint)indices.Length); pipeline.RenderPass.End(cmd); cmd.End(); } }
void printResults() { dev.WaitIdle(); using (CommandPool cmdPoolTransfer = new CommandPool(dev, transferQ.qFamIndex)) { PrimaryCommandBuffer cmd = cmdPoolTransfer.AllocateAndStart(VkCommandBufferUsageFlags.OneTimeSubmit); imgResult.SetLayout(cmd, VkImageAspectFlags.Color, VkImageLayout.ShaderReadOnlyOptimal, VkImageLayout.TransferDstOptimal, VkPipelineStageFlags.FragmentShader, VkPipelineStageFlags.Transfer); if (pong) { outBuff.CopyTo(cmd, imgResult, VkImageLayout.ShaderReadOnlyOptimal); } else { inBuff.CopyTo(cmd, imgResult, VkImageLayout.ShaderReadOnlyOptimal); } cmd.End(); transferQ.Submit(cmd); transferQ.WaitIdle(); } }
public void update_shadow_map(CommandPool cmdPool, vke.Buffer instanceBuf, params Model.InstancedCmd[] instances) { update_light_matrices(); PrimaryCommandBuffer cmd = cmdPool.AllocateAndStart(); shadowPass.Begin(cmd, fbShadowMap); cmd.SetViewport(SHADOWMAP_SIZE, SHADOWMAP_SIZE); cmd.SetScissor(SHADOWMAP_SIZE, SHADOWMAP_SIZE); cmd.BindDescriptorSet(shadowPipeline.Layout, dsShadow); Vk.vkCmdSetDepthBias(cmd.Handle, depthBiasConstant, 0.0f, depthBiasSlope); shadowPipeline.Bind(cmd); if (renderer.model != null) { renderer.model.Bind(cmd); renderer.model.Draw(cmd, shadowPipeline.Layout, instanceBuf, true, instances); } shadowPass.End(cmd); renderer.presentQueue.EndSubmitAndWait(cmd); updateShadowMap = false; }
public override void Update() { initGpuBuffers(); using (CommandPool cmdPoolCompute = new CommandPool(dev, computeQ.qFamIndex)) { PrimaryCommandBuffer cmd = cmdPoolCompute.AllocateAndStart(VkCommandBufferUsageFlags.OneTimeSubmit); pong = false; uint stepSize = imgDim / 2; plCompute.Bind(cmd); cmd.PushConstant(plCompute.Layout, VkShaderStageFlags.Compute, imgDim, sizeof(int)); int pass = 0; while (stepSize > 0 && pass < invocationCount) { cmd.PushConstant(plCompute.Layout, VkShaderStageFlags.Compute, stepSize); if (pong) { plCompute.BindDescriptorSet(cmd, dsetPong); } else { plCompute.BindDescriptorSet(cmd, dsetPing); } cmd.Dispatch(imgDim, imgDim); VkMemoryBarrier memBar = VkMemoryBarrier.New(); memBar.srcAccessMask = VkAccessFlags.ShaderWrite; memBar.dstAccessMask = VkAccessFlags.ShaderRead; Vk.vkCmdPipelineBarrier(cmd.Handle, VkPipelineStageFlags.ComputeShader, VkPipelineStageFlags.ComputeShader, VkDependencyFlags.ByRegion, 1, ref memBar, 0, IntPtr.Zero, 0, IntPtr.Zero); pong = !pong; stepSize /= 2; pass++; } plNormalize.Bind(cmd); if (pong) { plNormalize.BindDescriptorSet(cmd, dsetPong); } else { plNormalize.BindDescriptorSet(cmd, dsetPing); } cmd.Dispatch(imgDim, imgDim); pong = !pong; cmd.End(); computeQ.Submit(cmd); computeQ.WaitIdle(); } printResults(); }
void recordDraw(PrimaryCommandBuffer cmd, FrameBuffer fb) { pbrPipeline.RenderPass.Begin(cmd, fb); cmd.SetViewport(fb.Width, fb.Height); cmd.SetScissor(fb.Width, fb.Height); pbrPipeline.RecordDraw(cmd); pbrPipeline.RenderPass.End(cmd); }
void initGpuBuffers() { using (CommandPool staggingCmdPool = new CommandPool(dev, transferQ.qFamIndex)) { PrimaryCommandBuffer cmd = staggingCmdPool.AllocateAndStart(VkCommandBufferUsageFlags.OneTimeSubmit); stagingDataBuff.CopyTo(cmd, inBuff); transferQ.EndSubmitAndWait(cmd); } }
public void buildCommandBuffers(PrimaryCommandBuffer cmd) { renderPass.Begin(cmd, frameBuffer); cmd.SetViewport(frameBuffer.Width, frameBuffer.Height); cmd.SetScissor(frameBuffer.Width, frameBuffer.Height); cmd.BindDescriptorSet(gBuffPipeline.Layout, dsMain); envCube.RecordDraw(cmd); renderPass.BeginSubPass(cmd); if (model != null) { gBuffPipeline.Bind(cmd); model.Bind(cmd); model.DrawAll(cmd, gBuffPipeline.Layout); } renderPass.BeginSubPass(cmd); //cmd.BindDescriptorSet (composePipeline.Layout, dsMain); cmd.BindDescriptorSet(composePipeline.Layout, dsGBuff, 1); if (currentDebugView == DebugView.none) { composePipeline.Bind(cmd); } else { debugPipeline.Bind(cmd); uint debugValue = (uint)currentDebugView - 1; if (currentDebugView == DebugView.shadowMap) { debugValue += (uint)((lightNumDebug << 8)); } else { debugValue += (uint)((debugFace << 8) + (debugMip << 16)); } cmd.PushConstant(debugPipeline.Layout, VkShaderStageFlags.Fragment, debugValue, (uint)Marshal.SizeOf <Matrix4x4> ()); } cmd.Draw(3, 1, 0, 0); //renderPass.BeginSubPass (cmd); //toneMappingPipeline.Bind (cmd); //cmd.Draw (3, 1, 0, 0); renderPass.End(cmd); }
public void Run() { using (CommandPool cmdPool = new CommandPool(dev, computeQ.qFamIndex)) { PrimaryCommandBuffer cmd = cmdPool.AllocateAndStart(VkCommandBufferUsageFlags.OneTimeSubmit); plCompute.Bind(cmd); plCompute.BindDescriptorSet(cmd, dset); cmd.Dispatch(data_size * sizeof(int)); cmd.End(); computeQ.Submit(cmd); computeQ.WaitIdle(); } printResults(); }
void recordDraw(PrimaryCommandBuffer cmd, FrameBuffer fb) { pipeline.RenderPass.Begin(cmd, fb); cmd.SetViewport(fb.Width, fb.Height); cmd.SetScissor(fb.Width, fb.Height); cmd.BindDescriptorSet(pipeline.Layout, descriptorSet); pipeline.Bind(cmd); cmd.BindVertexBuffer(vbo, 0); cmd.Draw(36); pipeline.RenderPass.End(cmd); }
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, dim, dim); 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.AddShaders( new ShaderInfo(Dev, VkShaderStageFlags.Vertex, "#EnvironmentPipeline.genbrdflut.vert.spv"), new ShaderInfo(Dev, VkShaderStageFlags.Fragment, "#EnvironmentPipeline.genbrdflut.frag.spv")); using (GraphicPipeline pl = new GraphicPipeline(cfg)) { cfg.Dispose(); using (FrameBuffer fb = new FrameBuffer(cfg.RenderPass, dim, dim, lutBrdf)) { PrimaryCommandBuffer cmd = cmdPool.AllocateCommandBuffer(); cmd.Start(VkCommandBufferUsageFlags.OneTimeSubmit); pl.RenderPass.Begin(cmd, fb); 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; }
void recordDraw(PrimaryCommandBuffer cmd, FrameBuffer fb) { pipeline.RenderPass.Begin(cmd, fb); cmd.SetViewport(fb.Width, fb.Height); cmd.SetScissor(fb.Width, fb.Height); cmd.BindPipeline(pipeline, descriptorSet); cmd.PushConstant(pipeline, textColor); cmd.PushConstant(pipeline, outlineColor, 0, 16); cmd.BindVertexBuffer(vbo, 0); cmd.BindIndexBuffer(ibo, VkIndexType.Uint16); cmd.DrawIndexed((uint)ibo.ElementCount, 1, 0, 0, 0); pipeline.RenderPass.End(cmd); }
public PbrModelTexArray(Queue transferQ, string path) { dev = transferQ.Dev; using (CommandPool cmdPool = new CommandPool(dev, transferQ.index)) { using (glTFLoader ctx = new glTFLoader(path, transferQ, cmdPool)) { loadSolids <Vertex> (ctx); if (ctx.ImageCount > 0) { texArray = new Image(dev, Image.DefaultTextureFormat, VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferDst | VkImageUsageFlags.TransferSrc, VkMemoryPropertyFlags.DeviceLocal, TEXTURE_DIM, TEXTURE_DIM, VkImageType.Image2D, VkSampleCountFlags.SampleCount1, VkImageTiling.Optimal, Image.ComputeMipLevels(TEXTURE_DIM), ctx.ImageCount); ctx.BuildTexArray(ref texArray, 0); } else { texArray = new Image(dev, Image.DefaultTextureFormat, VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferDst | VkImageUsageFlags.TransferSrc, VkMemoryPropertyFlags.DeviceLocal, TEXTURE_DIM, TEXTURE_DIM, VkImageType.Image2D, VkSampleCountFlags.SampleCount1, VkImageTiling.Optimal, Image.ComputeMipLevels(TEXTURE_DIM), 1); PrimaryCommandBuffer cmd = cmdPool.AllocateAndStart(VkCommandBufferUsageFlags.OneTimeSubmit); texArray.SetLayout(cmd, VkImageAspectFlags.Color, VkImageLayout.ShaderReadOnlyOptimal); transferQ.EndSubmitAndWait(cmd, true); } texArray.CreateView(VkImageViewType.ImageView2DArray, VkImageAspectFlags.Color, texArray.CreateInfo.arrayLayers); texArray.CreateSampler(); texArray.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; texArray.SetName("model texArray"); loadMaterials(ctx); materialUBO = new HostBuffer <Material> (dev, VkBufferUsageFlags.UniformBuffer, materials); } } }
public void RecordDraw(PrimaryCommandBuffer cmd) { cmd.BindDescriptorSet(Layout, dsMain); envCube.RecordDraw(cmd); drawModel(cmd); }
public void RecordDraw(PrimaryCommandBuffer cmd) { Bind(cmd); cmd.BindVertexBuffer(vboSkybox); cmd.Draw(36); }
void drawModel(PrimaryCommandBuffer cmd) { Bind(cmd); model.Bind(cmd); model.DrawAll(cmd, Layout); }
Vector4 outlineColor = new Vector4(1.0f, 0.0f, 0.0f, 0.6f); //alpha => 0:disabled 1:enabled protected override void initVulkan() { base.initVulkan(); cmds = cmdPool.AllocateCommandBuffer(swapChain.ImageCount); font = new BMFont(vke.samples.Utils.GetDataFile("font.fnt")); vbo = new GPUBuffer <float> (dev, VkBufferUsageFlags.VertexBuffer | VkBufferUsageFlags.TransferDst, 1024); ibo = new GPUBuffer <ushort> (dev, VkBufferUsageFlags.IndexBuffer | VkBufferUsageFlags.TransferDst, 2048); descriptorPool = new DescriptorPool(dev, 1, new VkDescriptorPoolSize(VkDescriptorType.UniformBuffer), new VkDescriptorPoolSize(VkDescriptorType.CombinedImageSampler) ); dsLayout = new DescriptorSetLayout(dev, 0, new VkDescriptorSetLayoutBinding(0, VkShaderStageFlags.Vertex, VkDescriptorType.UniformBuffer), new VkDescriptorSetLayoutBinding(1, VkShaderStageFlags.Fragment, VkDescriptorType.CombinedImageSampler)); using (GraphicPipelineConfig cfg = GraphicPipelineConfig.CreateDefault(VkPrimitiveTopology.TriangleList, VkSampleCountFlags.SampleCount4, false)) { cfg.Layout = new PipelineLayout(dev, dsLayout); cfg.Layout.AddPushConstants(new VkPushConstantRange(VkShaderStageFlags.Fragment, (uint)Marshal.SizeOf <Vector4> () * 2)); cfg.RenderPass = new RenderPass(dev, swapChain.ColorFormat, cfg.Samples); cfg.blendAttachments[0] = new VkPipelineColorBlendAttachmentState( true, VkBlendFactor.One, VkBlendFactor.OneMinusSrcAlpha, VkBlendOp.Add, VkBlendFactor.One, VkBlendFactor.Zero); cfg.AddVertexBinding(0, 5 * sizeof(float)); cfg.AddVertexAttributes(0, VkFormat.R32g32b32Sfloat, VkFormat.R32g32Sfloat); cfg.AddShader(dev, VkShaderStageFlags.Vertex, "#shaders.main.vert.spv"); cfg.AddShader(dev, VkShaderStageFlags.Fragment, "#shaders.main.frag.spv"); pipeline = new GraphicPipeline(cfg); } uboMats = new HostBuffer(dev, VkBufferUsageFlags.UniformBuffer, matrices); uboMats.Map(); //permanent map descriptorSet = descriptorPool.Allocate(dsLayout); fontTexture = font.GetPageTexture(0, presentQueue, cmdPool); fontTexture.CreateView(); fontTexture.CreateSampler(); fontTexture.Descriptor.imageLayout = VkImageLayout.ShaderReadOnlyOptimal; DescriptorSetWrites dsUpdate = new DescriptorSetWrites(descriptorSet, dsLayout); dsUpdate.Write(dev, uboMats.Descriptor, fontTexture.Descriptor); generateText("Vulkan", out HostBuffer <Vertex> staggingVbo, out HostBuffer <ushort> staggingIbo); PrimaryCommandBuffer cmd = cmdPool.AllocateAndStart(VkCommandBufferUsageFlags.OneTimeSubmit); staggingVbo.CopyTo(cmd, vbo); staggingIbo.CopyTo(cmd, ibo); presentQueue.EndSubmitAndWait(cmd); staggingVbo.Dispose(); staggingIbo.Dispose(); UpdateFrequency = 10; }
public static Image Load(Queue staggingQ, CommandPool staggingCmdPool, string ktxPath, VkImageUsageFlags usage = VkImageUsageFlags.Sampled, VkMemoryPropertyFlags memoryProperty = VkMemoryPropertyFlags.DeviceLocal, bool generateMipmaps = true, VkImageTiling tiling = VkImageTiling.Optimal) { Image img = null; using (Stream ktxStream = File.Open(ktxPath, FileMode.Open, FileAccess.Read)) { using (BinaryReader br = new BinaryReader(ktxStream)) { if (!br.ReadBytes(12).AreEquals(ktxSignature)) { throw new KtxException("Not a ktx file: " + ktxPath); } UInt32 endianness = br.ReadUInt32(); UInt32 glType = br.ReadUInt32(); UInt32 glTypeSize = br.ReadUInt32(); UInt32 glFormat = br.ReadUInt32(); UInt32 glInternalFormat = br.ReadUInt32(); UInt32 glBaseInternalFormat = br.ReadUInt32(); UInt32 pixelWidth = br.ReadUInt32(); UInt32 pixelHeight = br.ReadUInt32(); UInt32 pixelDepth = Math.Max(1, br.ReadUInt32()); UInt32 numberOfArrayElements = br.ReadUInt32(); //only for array text, else 0 UInt32 numberOfFaces = br.ReadUInt32(); //only for cube map, else 1 UInt32 numberOfMipmapLevels = Math.Max(1, br.ReadUInt32()); UInt32 bytesOfKeyValueData = br.ReadUInt32(); VkFormat vkFormat = GLHelper.vkGetFormatFromOpenGLInternalFormat(glInternalFormat); if (vkFormat == VkFormat.Undefined) { vkFormat = GLHelper.vkGetFormatFromOpenGLFormat(glFormat, glType); if (vkFormat == VkFormat.Undefined) { throw new KtxException("Undefined format: " + ktxPath); } } VkFormatProperties formatProperties = staggingQ.Dev.phy.GetFormatProperties(vkFormat); VkFormatFeatureFlags phyFormatSupport = (tiling == VkImageTiling.Linear) ? formatProperties.linearTilingFeatures : formatProperties.optimalTilingFeatures; uint requestedMipsLevels = numberOfMipmapLevels; if (numberOfMipmapLevels == 1) { requestedMipsLevels = (generateMipmaps && phyFormatSupport.HasFlag(VkFormatFeatureFlags.BlitSrc | VkFormatFeatureFlags.BlitDst)) ? (uint)Math.Floor(Math.Log(Math.Max(pixelWidth, pixelHeight))) + 1 : 1; } if (tiling == VkImageTiling.Optimal) { usage |= VkImageUsageFlags.TransferDst; } if (generateMipmaps) { usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst); } VkImageCreateFlags createFlags = 0; VkImageType imgType = (pixelWidth == 0) ? throw new KtxException("pixelWidth must be > 0") : (pixelHeight == 0) ? imgType = VkImageType.Image1D : (pixelDepth == 1) ? imgType = VkImageType.Image2D : imgType = VkImageType.Image3D; VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1; if (numberOfFaces > 1) { if (imgType != VkImageType.Image2D) { throw new KtxException("cubemap faces must be 2D textures"); } createFlags = VkImageCreateFlags.CubeCompatible; samples = VkSampleCountFlags.SampleCount1; numberOfArrayElements = numberOfFaces; } else { numberOfFaces = 1; if (numberOfArrayElements == 0) { numberOfArrayElements = 1; } } if (!Image.CheckFormatIsSupported(usage, phyFormatSupport)) { throw new Exception($"Unsupported image format: {vkFormat}, {tiling}, {usage}"); } img = new Image(staggingQ.Dev, vkFormat, usage, memoryProperty, pixelWidth, pixelHeight, imgType, samples, tiling, requestedMipsLevels, numberOfArrayElements, pixelDepth, createFlags); byte[] keyValueDatas = br.ReadBytes((int)bytesOfKeyValueData); uint blockW, blockH; bool isCompressed = vkFormat.TryGetCompressedFormatBlockSize(out blockW, out blockH); uint blockSize = blockW * blockH; if (memoryProperty.HasFlag(VkMemoryPropertyFlags.DeviceLocal)) { ulong staggingSize = img.AllocatedDeviceMemorySize; Console.WriteLine($"KtxStream size = {ktxStream.Length}, img Allocation = {img.AllocatedDeviceMemorySize}"); using (HostBuffer stagging = new HostBuffer(staggingQ.Dev, VkBufferUsageFlags.TransferSrc, staggingSize)) { stagging.Map(); PrimaryCommandBuffer cmd = staggingCmdPool.AllocateAndStart(VkCommandBufferUsageFlags.OneTimeSubmit); img.SetLayout(cmd, VkImageAspectFlags.Color, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.Transfer); List <VkBufferImageCopy> buffCopies = new List <VkBufferImageCopy> (); VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy { imageExtent = img.CreateInfo.extent, imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, img.CreateInfo.arrayLayers, 0) }; ulong bufferOffset = 0; uint imgWidth = img.CreateInfo.extent.width; uint imgHeight = img.CreateInfo.extent.height; for (int mips = 0; mips < numberOfMipmapLevels; mips++) { UInt32 imgSize = br.ReadUInt32(); bufferCopyRegion.bufferRowLength = imgWidth; bufferCopyRegion.bufferImageHeight = imgHeight; if (isCompressed && (imgWidth % blockW > 0 || imgHeight % blockH > 0)) { bufferCopyRegion.bufferRowLength += blockW - imgWidth % blockW; bufferCopyRegion.bufferImageHeight += blockH - imgHeight % blockH; } bufferCopyRegion.bufferOffset = bufferOffset; bufferCopyRegion.imageSubresource.mipLevel = (uint)mips; bufferCopyRegion.imageExtent.width = imgWidth; bufferCopyRegion.imageExtent.height = imgHeight; if (createFlags.HasFlag(VkImageCreateFlags.CubeCompatible)) { //TODO:handle compressed formats for (uint face = 0; face < numberOfFaces; face++) { Marshal.Copy(br.ReadBytes((int)imgSize), 0, stagging.MappedData + (int)bufferOffset, (int)imgSize); uint faceOffset = imgSize + (imgSize % 4); //cube padding bufferOffset += faceOffset; } buffCopies.Add(bufferCopyRegion); bufferCopyRegion.bufferOffset = bufferOffset; } else if (isCompressed && (imgWidth % blockW > 0 || imgHeight % blockH > 0)) { for (int line = 0; line < imgHeight; line++) { Marshal.Copy(br.ReadBytes((int)imgWidth), 0, stagging.MappedData + (int)bufferOffset, (int)imgWidth); bufferOffset += bufferCopyRegion.bufferRowLength; } buffCopies.Add(bufferCopyRegion); } else { Marshal.Copy(br.ReadBytes((int)imgSize), 0, stagging.MappedData + (int)bufferOffset, (int)imgSize); buffCopies.Add(bufferCopyRegion); bufferOffset += imgSize; } if (isCompressed && bufferOffset % blockSize > 0) { bufferOffset += blockSize - bufferOffset % blockSize; } imgWidth /= 2; imgHeight /= 2; } stagging.Unmap(); Vk.vkCmdCopyBufferToImage(cmd.Handle, stagging.handle, img.handle, VkImageLayout.TransferDstOptimal, (uint)buffCopies.Count, buffCopies.Pin()); buffCopies.Unpin(); if (requestedMipsLevels > numberOfMipmapLevels) { img.BuildMipmaps(cmd); } else { img.SetLayout(cmd, VkImageAspectFlags.Color, VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader); } cmd.End(); staggingQ.Submit(cmd); staggingQ.WaitIdle(); cmd.Free(); } } else { } } } return(img); }
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); 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.AddShaders(new ShaderInfo(Dev, VkShaderStageFlags.Vertex, "#EnvironmentPipeline.filtercube.vert.spv")); if (target == CBTarget.PREFILTEREDENV) { cfg.AddShaders(new ShaderInfo(Dev, VkShaderStageFlags.Fragment, "#EnvironmentPipeline.prefilterenvmap.frag.spv")); } else { cfg.AddShaders(new ShaderInfo(Dev, VkShaderStageFlags.Fragment, "#EnvironmentPipeline.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)) { cfg.Dispose(); 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)) { PrimaryCommandBuffer 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); }
///// <summary> ///// build texture array ///// </summary> ///// <returns>The images.</returns> ///// <param name="textureSize">Uniformized Texture size for all images</param> public void BuildTexArray (ref Image texArray, uint firstImg = 0) { int texDim = (int)texArray.CreateInfo.extent.width; PrimaryCommandBuffer cmd = cmdPool.AllocateAndStart (VkCommandBufferUsageFlags.OneTimeSubmit); texArray.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.Transfer); transferQ.EndSubmitAndWait (cmd, true); 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, loadedBuffers[bv.Buffer].Slice (bv.ByteOffset), (ulong)bv.ByteLength, VkImageUsageFlags.TransferSrc); } 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), VkImageUsageFlags.TransferSrc); } 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), VkImageUsageFlags.TransferSrc); } 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, VkAccessFlags.HostWrite, VkAccessFlags.TransferRead, VkImageLayout.Undefined, VkImageLayout.TransferSrcOptimal, VkPipelineStageFlags.Host, VkPipelineStageFlags.Transfer); Vk.vkCmdBlitImage (cmd.Handle, vkimg.Handle, VkImageLayout.TransferSrcOptimal, texArray.Handle, VkImageLayout.TransferDstOptimal, 1, ref imageBlit, VkFilter.Linear); transferQ.EndSubmitAndWait (cmd, true); vkimg.Dispose (); } cmd = cmdPool.AllocateAndStart (VkCommandBufferUsageFlags.OneTimeSubmit); uint imgCount = (uint)gltf.Images.Length; VkImageSubresourceRange mipSubRange = new VkImageSubresourceRange (VkImageAspectFlags.Color, 0, 1, firstImg, imgCount); 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) }; texArray.SetLayout (cmd, VkAccessFlags.TransferWrite, VkAccessFlags.TransferRead, VkImageLayout.TransferDstOptimal, VkImageLayout.TransferSrcOptimal, 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.TransferSrcOptimal, VkImageLayout.ShaderReadOnlyOptimal, mipSubRange, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader); mipSubRange.baseMipLevel = (uint)i; } mipSubRange.baseMipLevel = texArray.CreateInfo.mipLevels - 1; texArray.SetLayout (cmd, VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal, mipSubRange, 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 { Span<byte> stagVertPtrInit = new Span<byte>(stagging.MappedData.ToPointer (), (int)vertSize); Span<byte> stagIdxPtrInit = new Span<byte>((byte*)stagging.MappedData.ToPointer() + vertSize, (int)idxSize); Span<byte> stagVertPtr = stagVertPtrInit, 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 Span<byte> inPosPtr = Span<byte>.Empty, inNormPtr = Span<byte>.Empty, inUvPtr = Span<byte>.Empty, inUv1Ptr = Span<byte>.Empty; GL.BufferView bv = gltf.BufferViews[(int)AccPos.BufferView]; inPosPtr = loadedBuffers[bv.Buffer].Span.Slice (AccPos.ByteOffset + bv.ByteOffset); if (AccNorm != null) { bv = gltf.BufferViews[(int)AccNorm.BufferView]; inNormPtr = loadedBuffers[bv.Buffer].Span.Slice (AccNorm.ByteOffset + bv.ByteOffset); } if (AccUv != null) { bv = gltf.BufferViews[(int)AccUv.BufferView]; inUvPtr = loadedBuffers[bv.Buffer].Span.Slice (AccUv.ByteOffset + bv.ByteOffset); } if (AccUv1 != null) { bv = gltf.BufferViews[(int)AccUv1.BufferView]; inUv1Ptr = loadedBuffers[bv.Buffer].Span.Slice (AccUv1.ByteOffset + bv.ByteOffset); } //TODO: use vertex attributes scan for copying data if they exists for (int j = 0; j < prim.vertexCount; j++) { inPosPtr.Slice (0, 12).CopyTo (stagVertPtr); inPosPtr = inPosPtr.Slice(12); if (!inNormPtr.IsEmpty) { inNormPtr.Slice (0, 12).CopyTo (stagVertPtr.Slice (12)); inNormPtr = inNormPtr.Slice (12); } if (inUvPtr != null) { inUvPtr.Slice (0, 8).CopyTo (stagVertPtr.Slice (24)); inUvPtr = inUvPtr.Slice (8); } if (inUv1Ptr != null) { inUv1Ptr.Slice (0, 8).CopyTo (stagVertPtr.Slice (32)); inUv1Ptr = inUvPtr.Slice (8); } stagVertPtr = stagVertPtr.Slice (vertexByteSize); } /*Span<byte> s = stagVertPtrInit; for (int i = 0; i < s.Length; i++) Console.Write (s[i].ToString ("X2") + (i % 32 == 0 ? "\n" : " "));*/ //indices loading if (p.Indices != null) { GL.Accessor acc = gltf.Accessors[(int)p.Indices]; bv = gltf.BufferViews[(int)acc.BufferView]; Span<byte> inIdxPtr = loadedBuffers[bv.Buffer].Span.Slice (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) { inIdxPtr.Slice (0, acc.Count * 2).CopyTo (stagIdxPtr); stagIdxPtr = stagIdxPtr.Slice (acc.Count * 2); } else { Span<uint> usPtr = MemoryMarshal.Cast<byte, uint> (stagIdxPtr); Span<ushort> inPtr = MemoryMarshal.Cast < byte, ushort> (inIdxPtr); for (int i = 0; i < acc.Count; i++) usPtr[i] = inPtr[i]; stagIdxPtr = stagIdxPtr.Slice (acc.Count * 4); } } else if (acc.ComponentType == GL.Accessor.ComponentTypeEnum.UNSIGNED_INT) { if (indexType == VkIndexType.Uint32) { inIdxPtr.Slice (0, acc.Count * 4).CopyTo (stagIdxPtr); stagIdxPtr = stagIdxPtr.Slice (acc.Count * 4); } else { Span<ushort> usPtr = MemoryMarshal.Cast<byte, ushort> (stagIdxPtr); Span<uint> inPtr = MemoryMarshal.Cast<byte, uint> (inIdxPtr); for (int i = 0; i < acc.Count; i++) usPtr[i] = (ushort)inPtr[i]; stagIdxPtr = stagIdxPtr.Slice (acc.Count * 2); } } else if (acc.ComponentType == GL.Accessor.ComponentTypeEnum.UNSIGNED_BYTE) { //convert if (indexType == VkIndexType.Uint16) { Span<ushort> usPtr = MemoryMarshal.Cast<byte, ushort> (stagIdxPtr); for (int i = 0; i < acc.Count; i++) usPtr[i] = (ushort)inIdxPtr[i]; stagIdxPtr = stagIdxPtr.Slice (acc.Count * 2); } else { Span<uint> usPtr = MemoryMarshal.Cast<byte, uint> (stagIdxPtr); for (int i = 0; i < acc.Count; i++) usPtr[i] = (uint)inIdxPtr[i]; stagIdxPtr = stagIdxPtr.Slice (acc.Count * 4); } } else throw new NotImplementedException (); prim.indexCount = (uint)acc.Count; indexCount += acc.Count; } m.AddPrimitive (prim); vertexCount += AccPos.Count; } meshes.Add (m); } /*ReadOnlySpan<byte> tmp = new ReadOnlySpan<byte> (stagging.MappedData.ToPointer (), (int)size); Memory<byte> mtmp = new Memory<byte> (tmp.ToArray()); mtmp.Dump();*/ } stagging.Unmap (); PrimaryCommandBuffer 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 (); }
public void recordDraw(PrimaryCommandBuffer cmd, int imageIndex, vke.Buffer instanceBuf = null, params Model.InstancedCmd[] instances) { FrameBuffer fb = frameBuffers[imageIndex]; renderPass.Begin(cmd, fb); cmd.SetViewport(fb.Width, fb.Height); cmd.SetScissor(fb.Width, fb.Height); cmd.BindDescriptorSet(gBuffPipeline.Layout, dsMain); envCube.RecordDraw(cmd); renderPass.BeginSubPass(cmd); if (model != null) { model.Bind(cmd); depthPrepassPipeline.Bind(cmd); if (instanceBuf != null) { model.Draw(cmd, gBuffPipeline.Layout, instanceBuf, false, instances); } renderPass.BeginSubPass(cmd); gBuffPipeline.Bind(cmd); if (instanceBuf != null) { model.Draw(cmd, gBuffPipeline.Layout, instanceBuf, false, instances); } } renderPass.BeginSubPass(cmd); cmd.BindDescriptorSet(composePipeline.Layout, dsGBuff, 1); if (currentDebugView == DebugView.none) { composePipeline.Bind(cmd); } else { debugPipeline.Bind(cmd); uint debugValue = (uint)currentDebugView - 1; if (currentDebugView == DebugView.shadowMap) { debugValue += (uint)((lightNumDebug << 8)); } else { debugValue += (uint)((debugFace << 8) + (debugMip << 16)); } cmd.PushConstant(debugPipeline.Layout, VkShaderStageFlags.Fragment, debugValue, (uint)Marshal.SizeOf <Matrix4x4>()); } cmd.Draw(3, 1, 0, 0); renderPass.BeginSubPass(cmd); toneMappingPipeline.Bind(cmd); cmd.Draw(3, 1, 0, 0); renderPass.End(cmd); }