internal static DeviceTexture CreateColorTarget( Int2 size, Format format, Device logicalDevice, Memory.Pool memoryPool, TransientExecutor executor, bool allowSampling = true) { if (logicalDevice == null) { throw new ArgumentNullException(nameof(logicalDevice)); } if (memoryPool == null) { throw new ArgumentNullException(nameof(memoryPool)); } if (executor == null) { throw new ArgumentNullException(nameof(executor)); } var usage = allowSampling ? ImageUsages.ColorAttachment | ImageUsages.Sampled : ImageUsages.ColorAttachment | ImageUsages.TransientAttachment; var aspects = ImageAspects.Color; var image = CreateImage( logicalDevice, format, size, mipLevels: 1, usage, cubeMap: false); var memory = memoryPool.AllocateAndBind(image, Chunk.Location.Device); //Transition the image to the depth attachment layout TransitionImageLayout(image, aspects, baseMipLevel: 0, mipLevels: 1, baseLayer: 0, layers: 1, oldLayout: ImageLayout.Undefined, newLayout: ImageLayout.ColorAttachmentOptimal, executor: executor); var view = CreateView(image, format, mipLevels: 1, aspects, cubeMap: false); return(new DeviceTexture( size, format, ImageLayout.ShaderReadOnlyOptimal, //Used for shader reading mipLevels: 1, aspects, image, memory, view)); }
private static void BlitImage( ImageAspects aspectMask, Image fromImage, IntRect fromRegion, int fromMipLevel, int fromLayerCount, Image toImage, IntRect toRegion, int toMipLevel, int toLayerCount, TransientExecutor executor) { ImageBlit blit = new ImageBlit { SrcSubresource = new ImageSubresourceLayers( aspectMask, fromMipLevel, baseArrayLayer: 0, fromLayerCount), SrcOffset1 = new Offset3D(fromRegion.Min.X, fromRegion.Min.Y, 0), SrcOffset2 = new Offset3D(fromRegion.Max.X, fromRegion.Max.Y, 1), DstSubresource = new ImageSubresourceLayers( aspectMask, toMipLevel, baseArrayLayer: 0, toLayerCount), DstOffset1 = new Offset3D(toRegion.Min.X, toRegion.Min.Y, 0), DstOffset2 = new Offset3D(toRegion.Max.X, toRegion.Max.Y, 1) }; //Execute the blit executor.ExecuteBlocking(commandBuffer => { commandBuffer.CmdBlitImage( srcImage: fromImage, srcImageLayout: ImageLayout.TransferSrcOptimal, dstImage: toImage, dstImageLayout: ImageLayout.TransferDstOptimal, regions: new [] { blit }, filter: Filter.Linear); }); }
internal static DeviceTexture UploadTexture( IInternalTexture texture, Device logicalDevice, Memory.Pool memoryPool, Memory.HostBuffer stagingBuffer, TransientExecutor executor, bool generateMipMaps = false) { if (texture == null) { throw new ArgumentNullException(nameof(texture)); } if (logicalDevice == null) { throw new ArgumentNullException(nameof(logicalDevice)); } if (memoryPool == null) { throw new ArgumentNullException(nameof(memoryPool)); } if (stagingBuffer == null) { throw new ArgumentNullException(nameof(stagingBuffer)); } if (executor == null) { throw new ArgumentNullException(nameof(executor)); } int mipLevels = generateMipMaps ? CalculateMipLevels(texture.Size) : 1; int layers = texture.IsCubeMap ? 6 : 1; var aspects = ImageAspects.Color; var image = CreateImage( logicalDevice, texture.Format, texture.Size, mipLevels, //Also include 'TransferSrc' because we read from the image to generate the mip-maps ImageUsages.TransferSrc | ImageUsages.TransferDst | ImageUsages.Sampled, cubeMap: texture.IsCubeMap); var memory = memoryPool.AllocateAndBind(image, Chunk.Location.Device); //Transition the entire image (all mip-levels and layers) to 'TransferDstOptimal' TransitionImageLayout(image, aspects, baseMipLevel: 0, mipLevels, baseLayer: 0, layers, oldLayout: ImageLayout.Undefined, newLayout: ImageLayout.TransferDstOptimal, executor: executor); //Upload the data to mipmap 0 texture.Upload(stagingBuffer, executor, image, aspects); //Create the other mipmap levels Int2 prevMipSize = texture.Size; for (int i = 1; i < mipLevels; i++) { Int2 curMipSize = new Int2( prevMipSize.X > 1 ? prevMipSize.X / 2 : 1, prevMipSize.Y > 1 ? prevMipSize.Y / 2 : 1); //Move the previous mip-level to a transfer source layout TransitionImageLayout(image, aspects, baseMipLevel: i - 1, mipLevels: 1, baseLayer: 0, layers, oldLayout: ImageLayout.TransferDstOptimal, newLayout: ImageLayout.TransferSrcOptimal, executor: executor); //Blit the previous mip-level to the current at half the size BlitImage(aspects, fromImage: image, fromRegion: new IntRect(min: Int2.Zero, max: prevMipSize), fromMipLevel: i - 1, fromLayerCount: layers, toImage: image, toRegion: new IntRect(min: Int2.Zero, max: curMipSize), toMipLevel: i, toLayerCount: layers, executor); //Transition the previous mip-level to the shader-read layout TransitionImageLayout(image, aspects, baseMipLevel: i - 1, mipLevels: 1, baseLayer: 0, layers, oldLayout: ImageLayout.TransferSrcOptimal, newLayout: ImageLayout.ShaderReadOnlyOptimal, executor: executor); //Update the prev mip-size prevMipSize = curMipSize; } //Transition the last mip-level to the shader-read layout TransitionImageLayout(image, aspects, baseMipLevel: mipLevels - 1, mipLevels: 1, baseLayer: 0, layers, oldLayout: ImageLayout.TransferDstOptimal, newLayout: ImageLayout.ShaderReadOnlyOptimal, executor: executor); var view = CreateView( image, texture.Format, mipLevels, aspects, cubeMap: texture.IsCubeMap); return(new DeviceTexture( texture.Size, texture.Format, ImageLayout.ShaderReadOnlyOptimal, //Used for shader reading, mipLevels, aspects, image, memory, view)); }
private static void TransitionImageLayout( Image image, ImageAspects aspectMask, int baseMipLevel, int mipLevels, int baseLayer, int layers, ImageLayout oldLayout, ImageLayout newLayout, TransientExecutor executor) { //Get where this transition has to wait and what has to wait for this transition Accesses sourceAccess, destinationAccess; PipelineStages sourcePipelineStages, destinationPipelineStages; if (oldLayout == ImageLayout.Undefined && newLayout == ImageLayout.TransferDstOptimal) { sourceAccess = Accesses.None; destinationAccess = Accesses.TransferWrite; sourcePipelineStages = PipelineStages.TopOfPipe; destinationPipelineStages = PipelineStages.Transfer; } else if (oldLayout == ImageLayout.Undefined && newLayout == ImageLayout.DepthStencilAttachmentOptimal) { sourceAccess = Accesses.None; destinationAccess = Accesses.DepthStencilAttachmentRead | Accesses.DepthStencilAttachmentWrite; sourcePipelineStages = PipelineStages.TopOfPipe; destinationPipelineStages = PipelineStages.EarlyFragmentTests; } else if (oldLayout == ImageLayout.Undefined && newLayout == ImageLayout.ColorAttachmentOptimal) { sourceAccess = Accesses.None; destinationAccess = Accesses.ColorAttachmentRead | Accesses.ColorAttachmentWrite; sourcePipelineStages = PipelineStages.TopOfPipe; destinationPipelineStages = PipelineStages.ColorAttachmentOutput; } else if (oldLayout == ImageLayout.TransferDstOptimal && newLayout == ImageLayout.TransferSrcOptimal) { sourceAccess = Accesses.TransferWrite; destinationAccess = Accesses.TransferRead; sourcePipelineStages = PipelineStages.Transfer; destinationPipelineStages = PipelineStages.Transfer; } else if (oldLayout == ImageLayout.TransferDstOptimal && newLayout == ImageLayout.ShaderReadOnlyOptimal) { sourceAccess = Accesses.TransferWrite; destinationAccess = Accesses.ShaderRead; sourcePipelineStages = PipelineStages.Transfer; destinationPipelineStages = PipelineStages.FragmentShader; } else if (oldLayout == ImageLayout.TransferSrcOptimal && newLayout == ImageLayout.ShaderReadOnlyOptimal) { sourceAccess = Accesses.TransferRead; destinationAccess = Accesses.ShaderRead; sourcePipelineStages = PipelineStages.Transfer; destinationPipelineStages = PipelineStages.FragmentShader; } else { throw new Exception( $"[{nameof(DeviceTexture)}] Unsupported image transition: from: {oldLayout} to: {newLayout}"); } //Create the transition barrier var imageMemoryBarrier = new ImageMemoryBarrier( image: image, subresourceRange: new ImageSubresourceRange( aspectMask: aspectMask, baseMipLevel: baseMipLevel, levelCount: mipLevels, baseArrayLayer: baseLayer, layerCount: layers), srcAccessMask: sourceAccess, dstAccessMask: destinationAccess, oldLayout: oldLayout, newLayout: newLayout); //Execute the barrier executor.ExecuteBlocking(commandBuffer => { commandBuffer.CmdPipelineBarrier( srcStageMask: sourcePipelineStages, dstStageMask: destinationPipelineStages, dependencyFlags: Dependencies.None, memoryBarriers: null, bufferMemoryBarriers: null, imageMemoryBarriers: new [] { imageMemoryBarrier }); }); }
public RenderScene(Window window, TextureInfo reflectionTexture, ShaderProgram postVertProg, ShaderProgram bloomFragProg, ShaderProgram aoFragProg, ShaderProgram gaussBlurFragProg, ShaderProgram boxBlurFragProg, ShaderProgram compositionFragProg, Logger logger = null) { if (window == null) { throw new ArgumentNullException(nameof(window)); } if (reflectionTexture.Texture == null) { throw new ArgumentNullException(nameof(reflectionTexture)); } if (postVertProg == null) { throw new ArgumentNullException(nameof(postVertProg)); } if (bloomFragProg == null) { throw new ArgumentNullException(nameof(bloomFragProg)); } if (aoFragProg == null) { throw new ArgumentNullException(nameof(aoFragProg)); } if (gaussBlurFragProg == null) { throw new ArgumentNullException(nameof(gaussBlurFragProg)); } if (boxBlurFragProg == null) { throw new ArgumentNullException(nameof(boxBlurFragProg)); } if (compositionFragProg == null) { throw new ArgumentNullException(nameof(compositionFragProg)); } this.window = window; this.logger = logger; camera = new Camera(); //Create resources executor = new TransientExecutor(window.LogicalDevice, window.GraphicsFamilyIndex); memoryPool = new Memory.Pool(window.LogicalDevice, window.HostDevice, logger); stagingBuffer = new Memory.HostBuffer( window.LogicalDevice, memoryPool, BufferUsages.TransferSrc, size: ByteUtils.MegabyteToByte(16)); sceneDataBuffer = new Memory.HostBuffer( window.LogicalDevice, memoryPool, BufferUsages.UniformBuffer, size: SceneData.SIZE * window.SwapchainCount); inputManager = new ShaderInputManager(window.LogicalDevice, logger); //Create techniques gbufferTechnique = new GBufferTechnique(this, logger); shadowTechnique = new ShadowTechnique(this, logger); bloomTechnique = new BloomTechnique( gbufferTechnique, postVertProg, bloomFragProg, gaussBlurFragProg, this, logger); aoTechnique = new AmbientOcclusionTechnique( gbufferTechnique, postVertProg, aoFragProg, boxBlurFragProg, this, logger); deferredTechnique = new DeferredTechnique( gbufferTechnique, shadowTechnique, bloomTechnique, aoTechnique, reflectionTexture, postVertProg, compositionFragProg, this, logger); }