| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- using Ryujinx.Common;
- using Ryujinx.Graphics.GAL;
- using Silk.NET.Vulkan;
- using System;
- using System.Numerics;
- namespace Ryujinx.Graphics.Vulkan
- {
- static class TextureCopy
- {
- public static void Blit(
- Vk api,
- CommandBuffer commandBuffer,
- Image srcImage,
- Image dstImage,
- TextureCreateInfo srcInfo,
- TextureCreateInfo dstInfo,
- Extents2D srcRegion,
- Extents2D dstRegion,
- int srcLayer,
- int dstLayer,
- int srcLevel,
- int dstLevel,
- int layers,
- int levels,
- bool linearFilter,
- ImageAspectFlags srcAspectFlags = 0,
- ImageAspectFlags dstAspectFlags = 0)
- {
- static (Offset3D, Offset3D) ExtentsToOffset3D(Extents2D extents, int width, int height, int level)
- {
- static int Clamp(int value, int max)
- {
- return Math.Clamp(value, 0, max);
- }
- var xy1 = new Offset3D(Clamp(extents.X1, width) >> level, Clamp(extents.Y1, height) >> level, 0);
- var xy2 = new Offset3D(Clamp(extents.X2, width) >> level, Clamp(extents.Y2, height) >> level, 1);
- return (xy1, xy2);
- }
- if (srcAspectFlags == 0)
- {
- srcAspectFlags = srcInfo.Format.ConvertAspectFlags();
- }
- if (dstAspectFlags == 0)
- {
- dstAspectFlags = dstInfo.Format.ConvertAspectFlags();
- }
- var srcOffsets = new ImageBlit.SrcOffsetsBuffer();
- var dstOffsets = new ImageBlit.DstOffsetsBuffer();
- var filter = linearFilter && !dstInfo.Format.IsDepthOrStencil() ? Filter.Linear : Filter.Nearest;
- TextureView.InsertImageBarrier(
- api,
- commandBuffer,
- srcImage,
- TextureStorage.DefaultAccessMask,
- AccessFlags.AccessTransferReadBit,
- PipelineStageFlags.PipelineStageAllCommandsBit,
- PipelineStageFlags.PipelineStageTransferBit,
- srcAspectFlags,
- srcLayer,
- srcLevel,
- layers,
- levels);
- uint copySrcLevel = (uint)srcLevel;
- uint copyDstLevel = (uint)dstLevel;
- for (int level = 0; level < levels; level++)
- {
- var srcSl = new ImageSubresourceLayers(srcAspectFlags, copySrcLevel, (uint)srcLayer, (uint)layers);
- var dstSl = new ImageSubresourceLayers(dstAspectFlags, copyDstLevel, (uint)dstLayer, (uint)layers);
- (srcOffsets.Element0, srcOffsets.Element1) = ExtentsToOffset3D(srcRegion, srcInfo.Width, srcInfo.Height, level);
- (dstOffsets.Element0, dstOffsets.Element1) = ExtentsToOffset3D(dstRegion, dstInfo.Width, dstInfo.Height, level);
- var region = new ImageBlit()
- {
- SrcSubresource = srcSl,
- SrcOffsets = srcOffsets,
- DstSubresource = dstSl,
- DstOffsets = dstOffsets
- };
- api.CmdBlitImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, region, filter);
- copySrcLevel++;
- copyDstLevel++;
- if (srcInfo.Target == Target.Texture3D || dstInfo.Target == Target.Texture3D)
- {
- layers = Math.Max(1, layers >> 1);
- }
- }
- TextureView.InsertImageBarrier(
- api,
- commandBuffer,
- dstImage,
- AccessFlags.AccessTransferWriteBit,
- TextureStorage.DefaultAccessMask,
- PipelineStageFlags.PipelineStageTransferBit,
- PipelineStageFlags.PipelineStageAllCommandsBit,
- dstAspectFlags,
- dstLayer,
- dstLevel,
- layers,
- levels);
- }
- public static void Copy(
- Vk api,
- CommandBuffer commandBuffer,
- Image srcImage,
- Image dstImage,
- TextureCreateInfo srcInfo,
- TextureCreateInfo dstInfo,
- int srcViewLayer,
- int dstViewLayer,
- int srcViewLevel,
- int dstViewLevel,
- int srcLayer,
- int dstLayer,
- int srcLevel,
- int dstLevel)
- {
- int srcDepth = srcInfo.GetDepthOrLayers();
- int srcLevels = srcInfo.Levels;
- int dstDepth = dstInfo.GetDepthOrLayers();
- int dstLevels = dstInfo.Levels;
- if (dstInfo.Target == Target.Texture3D)
- {
- dstDepth = Math.Max(1, dstDepth >> dstLevel);
- }
- int depth = Math.Min(srcDepth, dstDepth);
- int levels = Math.Min(srcLevels, dstLevels);
- Copy(
- api,
- commandBuffer,
- srcImage,
- dstImage,
- srcInfo,
- dstInfo,
- srcViewLayer,
- dstViewLayer,
- srcViewLevel,
- dstViewLevel,
- srcLayer,
- dstLayer,
- srcLevel,
- dstLevel,
- depth,
- levels);
- }
- private static int ClampLevels(TextureCreateInfo info, int levels)
- {
- int width = info.Width;
- int height = info.Height;
- int depth = info.Target == Target.Texture3D ? info.Depth : 1;
- int maxLevels = 1 + BitOperations.Log2((uint)Math.Max(Math.Max(width, height), depth));
- if (levels > maxLevels)
- {
- levels = maxLevels;
- }
- return levels;
- }
- public static void Copy(
- Vk api,
- CommandBuffer commandBuffer,
- Image srcImage,
- Image dstImage,
- TextureCreateInfo srcInfo,
- TextureCreateInfo dstInfo,
- int srcViewLayer,
- int dstViewLayer,
- int srcViewLevel,
- int dstViewLevel,
- int srcDepthOrLayer,
- int dstDepthOrLayer,
- int srcLevel,
- int dstLevel,
- int depthOrLayers,
- int levels)
- {
- int srcZ;
- int srcLayer;
- int srcDepth;
- int srcLayers;
- if (srcInfo.Target == Target.Texture3D)
- {
- srcZ = srcDepthOrLayer;
- srcLayer = 0;
- srcDepth = depthOrLayers;
- srcLayers = 1;
- }
- else
- {
- srcZ = 0;
- srcLayer = srcDepthOrLayer;
- srcDepth = 1;
- srcLayers = depthOrLayers;
- }
- int dstZ;
- int dstLayer;
- int dstDepth;
- int dstLayers;
- if (dstInfo.Target == Target.Texture3D)
- {
- dstZ = dstDepthOrLayer;
- dstLayer = 0;
- dstDepth = depthOrLayers;
- dstLayers = 1;
- }
- else
- {
- dstZ = 0;
- dstLayer = dstDepthOrLayer;
- dstDepth = 1;
- dstLayers = depthOrLayers;
- }
- int srcWidth = srcInfo.Width;
- int srcHeight = srcInfo.Height;
- int dstWidth = dstInfo.Width;
- int dstHeight = dstInfo.Height;
- srcWidth = Math.Max(1, srcWidth >> srcLevel);
- srcHeight = Math.Max(1, srcHeight >> srcLevel);
- dstWidth = Math.Max(1, dstWidth >> dstLevel);
- dstHeight = Math.Max(1, dstHeight >> dstLevel);
- int blockWidth = 1;
- int blockHeight = 1;
- bool sizeInBlocks = false;
- // When copying from a compressed to a non-compressed format,
- // the non-compressed texture will have the size of the texture
- // in blocks (not in texels), so we must adjust that size to
- // match the size in texels of the compressed texture.
- if (!srcInfo.IsCompressed && dstInfo.IsCompressed)
- {
- srcWidth *= dstInfo.BlockWidth;
- srcHeight *= dstInfo.BlockHeight;
- blockWidth = dstInfo.BlockWidth;
- blockHeight = dstInfo.BlockHeight;
- sizeInBlocks = true;
- }
- else if (srcInfo.IsCompressed && !dstInfo.IsCompressed)
- {
- dstWidth *= srcInfo.BlockWidth;
- dstHeight *= srcInfo.BlockHeight;
- blockWidth = srcInfo.BlockWidth;
- blockHeight = srcInfo.BlockHeight;
- }
- int width = Math.Min(srcWidth, dstWidth);
- int height = Math.Min(srcHeight, dstHeight);
- ImageAspectFlags srcAspect = srcInfo.Format.ConvertAspectFlags();
- ImageAspectFlags dstAspect = dstInfo.Format.ConvertAspectFlags();
- TextureView.InsertImageBarrier(
- api,
- commandBuffer,
- srcImage,
- TextureStorage.DefaultAccessMask,
- AccessFlags.AccessTransferReadBit,
- PipelineStageFlags.PipelineStageAllCommandsBit,
- PipelineStageFlags.PipelineStageTransferBit,
- srcAspect,
- srcViewLayer + srcLayer,
- srcViewLevel + srcLevel,
- srcLayers,
- levels);
- for (int level = 0; level < levels; level++)
- {
- // Stop copy if we are already out of the levels range.
- if (level >= srcInfo.Levels || dstLevel + level >= dstInfo.Levels)
- {
- break;
- }
- var srcSl = new ImageSubresourceLayers(
- srcAspect,
- (uint)(srcViewLevel + srcLevel + level),
- (uint)(srcViewLayer + srcLayer),
- (uint)srcLayers);
- var dstSl = new ImageSubresourceLayers(
- dstAspect,
- (uint)(dstViewLevel + dstLevel + level),
- (uint)(dstViewLayer + dstLayer),
- (uint)dstLayers);
- int copyWidth = sizeInBlocks ? BitUtils.DivRoundUp(width, blockWidth) : width;
- int copyHeight = sizeInBlocks ? BitUtils.DivRoundUp(height, blockHeight) : height;
- var extent = new Extent3D((uint)copyWidth, (uint)copyHeight, (uint)srcDepth);
- if (srcInfo.Samples > 1 && srcInfo.Samples != dstInfo.Samples)
- {
- var region = new ImageResolve(srcSl, new Offset3D(0, 0, srcZ), dstSl, new Offset3D(0, 0, dstZ), extent);
- api.CmdResolveImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, region);
- }
- else
- {
- var region = new ImageCopy(srcSl, new Offset3D(0, 0, srcZ), dstSl, new Offset3D(0, 0, dstZ), extent);
- api.CmdCopyImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, region);
- }
- width = Math.Max(1, width >> 1);
- height = Math.Max(1, height >> 1);
- if (srcInfo.Target == Target.Texture3D)
- {
- srcDepth = Math.Max(1, srcDepth >> 1);
- }
- }
- TextureView.InsertImageBarrier(
- api,
- commandBuffer,
- dstImage,
- AccessFlags.AccessTransferWriteBit,
- TextureStorage.DefaultAccessMask,
- PipelineStageFlags.PipelineStageTransferBit,
- PipelineStageFlags.PipelineStageAllCommandsBit,
- dstAspect,
- dstViewLayer + dstLayer,
- dstViewLevel + dstLevel,
- dstLayers,
- levels);
- }
- }
- }
|