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));
        }
Beispiel #4
0
        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);
        }