public InstancedObject( RenderScene scene, Mesh mesh, TextureInfo[] textureInfos, int maxInstances = 100_000) { if (scene == null) { throw new ArgumentNullException(nameof(scene)); } if (mesh == null) { throw new ArgumentNullException(nameof(mesh)); } //Prepare the inputs inputs = new IShaderInput[textureInfos.Length]; for (int i = 0; i < inputs.Length; i++) { DeviceTexture texture = DeviceTexture.UploadTexture( texture: textureInfos[i].Texture as IInternalTexture, scene, generateMipMaps: textureInfos[i].UseMipMaps); inputs[i] = new DeviceSampler( scene.LogicalDevice, texture, disposeTexture: true, repeat: textureInfos[i].Repeat, maxAnisotropy: 8f); } //Upload our mesh to the gpu deviceMesh = new DeviceMesh(mesh, scene); //Allocate a buffers for the instance data and indirect args instanceDataBuffer = new Memory.HostBuffer( logicalDevice: scene.LogicalDevice, memoryPool: scene.MemoryPool, usages: BufferUsages.VertexBuffer, size: InstanceData.SIZE * maxInstances); indirectArgumentsBuffer = new Memory.HostBuffer( logicalDevice: scene.LogicalDevice, memoryPool: scene.MemoryPool, usages: BufferUsages.IndirectBuffer, size: DrawIndexedIndirectCommand.SIZE); //Write defaults to the indirect args buffer indirectArgumentsBuffer.Write(new DrawIndexedIndirectCommand( indexCount: (uint)deviceMesh.IndexCount, instanceCount: 0, firstIndex: 0, vertexOffset: 0, firstInstance: 0)); }
internal static DeviceBuffer UploadData <T>( ReadOnlySpan <T> data, Device logicalDevice, Pool memoryPool, BufferUsages usages, HostBuffer stagingBuffer, TransientExecutor executor) where T : struct { //First write the data to the staging buffer int size = stagingBuffer.Write <T>(data, offset: 0); //Then create a device buffer with that size DeviceBuffer targetBuffer = new DeviceBuffer(logicalDevice, memoryPool, usages, size); //Then copy the data from the staging buffer to the devicebuffer executor.ExecuteBlocking(commandBuffer => { commandBuffer.CmdCopyBuffer( srcBuffer: stagingBuffer.VulkanBuffer, dstBuffer: targetBuffer.VulkanBuffer, new BufferCopy(size: size, srcOffset: 0, dstOffset: 0)); }); return(targetBuffer); }
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)); }
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); }