| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173 |
- using Ryujinx.Common.Memory;
- using Ryujinx.Graphics.GAL;
- using Silk.NET.Vulkan;
- using System;
- using System.Collections.Generic;
- using VkBuffer = Silk.NET.Vulkan.Buffer;
- using VkFormat = Silk.NET.Vulkan.Format;
- namespace Ryujinx.Graphics.Vulkan
- {
- class TextureView : ITexture, IDisposable
- {
- private readonly VulkanRenderer _gd;
- private readonly Device _device;
- private readonly Auto<DisposableImageView> _imageView;
- private readonly Auto<DisposableImageView> _imageViewIdentity;
- private readonly Auto<DisposableImageView> _imageView2dArray;
- private Dictionary<GAL.Format, TextureView> _selfManagedViews;
- private TextureCreateInfo _info;
- public TextureCreateInfo Info => _info;
- public TextureStorage Storage { get; }
- public int Width => Info.Width;
- public int Height => Info.Height;
- public int Layers => Info.GetDepthOrLayers();
- public int FirstLayer { get; }
- public int FirstLevel { get; }
- public float ScaleFactor => Storage.ScaleFactor;
- public VkFormat VkFormat { get; }
- public bool Valid { get; private set; }
- public TextureView(
- VulkanRenderer gd,
- Device device,
- TextureCreateInfo info,
- TextureStorage storage,
- int firstLayer,
- int firstLevel)
- {
- _gd = gd;
- _device = device;
- _info = info;
- Storage = storage;
- FirstLayer = firstLayer;
- FirstLevel = firstLevel;
- storage.IncrementViewsCount();
- gd.Textures.Add(this);
- var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format);
- var levels = (uint)info.Levels;
- var layers = (uint)info.GetLayers();
- VkFormat = format;
- var type = info.Target.ConvertView();
- var swizzleR = info.SwizzleR.Convert();
- var swizzleG = info.SwizzleG.Convert();
- var swizzleB = info.SwizzleB.Convert();
- var swizzleA = info.SwizzleA.Convert();
- if (info.Format == GAL.Format.R5G5B5A1Unorm ||
- info.Format == GAL.Format.R5G5B5X1Unorm ||
- info.Format == GAL.Format.R5G6B5Unorm)
- {
- var temp = swizzleR;
- swizzleR = swizzleB;
- swizzleB = temp;
- }
- else if (VkFormat == VkFormat.R4G4B4A4UnormPack16 || info.Format == GAL.Format.A1B5G5R5Unorm)
- {
- var tempB = swizzleB;
- var tempA = swizzleA;
- swizzleB = swizzleG;
- swizzleA = swizzleR;
- swizzleR = tempA;
- swizzleG = tempB;
- }
- var componentMapping = new ComponentMapping(swizzleR, swizzleG, swizzleB, swizzleA);
- var aspectFlags = info.Format.ConvertAspectFlags(info.DepthStencilMode);
- var aspectFlagsDepth = info.Format.ConvertAspectFlags(DepthStencilMode.Depth);
- var subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, layers);
- var subresourceRangeDepth = new ImageSubresourceRange(aspectFlagsDepth, (uint)firstLevel, levels, (uint)firstLayer, layers);
- unsafe Auto<DisposableImageView> CreateImageView(ComponentMapping cm, ImageSubresourceRange sr, ImageViewType viewType)
- {
- var imageCreateInfo = new ImageViewCreateInfo()
- {
- SType = StructureType.ImageViewCreateInfo,
- Image = storage.GetImageForViewCreation(),
- ViewType = viewType,
- Format = format,
- Components = cm,
- SubresourceRange = sr
- };
- gd.Api.CreateImageView(device, imageCreateInfo, null, out var imageView).ThrowOnError();
- return new Auto<DisposableImageView>(new DisposableImageView(gd.Api, device, imageView), null, storage.GetImage());
- }
- _imageView = CreateImageView(componentMapping, subresourceRange, type);
- // Framebuffer attachments and storage images requires a identity component mapping.
- var identityComponentMapping = new ComponentMapping(
- ComponentSwizzle.R,
- ComponentSwizzle.G,
- ComponentSwizzle.B,
- ComponentSwizzle.A);
- _imageViewIdentity = CreateImageView(identityComponentMapping, subresourceRangeDepth, type);
- // Framebuffer attachments also require 3D textures to be bound as 2D array.
- if (info.Target == Target.Texture3D)
- {
- subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth);
- _imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.ImageViewType2DArray);
- }
- Valid = true;
- }
- public Auto<DisposableImage> GetImage()
- {
- return Storage.GetImage();
- }
- public Auto<DisposableImageView> GetImageView()
- {
- return _imageView;
- }
- public Auto<DisposableImageView> GetIdentityImageView()
- {
- return _imageViewIdentity;
- }
- public Auto<DisposableImageView> GetImageViewForAttachment()
- {
- return _imageView2dArray ?? _imageViewIdentity;
- }
- public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
- {
- var src = this;
- var dst = (TextureView)destination;
- if (!Valid || !dst.Valid)
- {
- return;
- }
- _gd.PipelineInternal.EndRenderPass();
- var cbs = _gd.PipelineInternal.CurrentCommandBuffer;
- var srcImage = src.GetImage().Get(cbs).Value;
- var dstImage = dst.GetImage().Get(cbs).Value;
- if (src.Info.Target.IsMultisample())
- {
- int depth = Math.Min(src.Info.Depth, dst.Info.Depth - firstLayer);
- int levels = Math.Min(src.Info.Levels, dst.Info.Levels - firstLevel);
- CopyMSToNonMS(_gd, cbs, src, dst, srcImage, dstImage, 0, firstLayer, 0, firstLevel, depth, levels);
- }
- else
- {
- TextureCopy.Copy(
- _gd.Api,
- cbs.CommandBuffer,
- srcImage,
- dstImage,
- src.Info,
- dst.Info,
- src.FirstLayer,
- dst.FirstLayer,
- src.FirstLevel,
- dst.FirstLevel,
- 0,
- firstLayer,
- 0,
- firstLevel);
- }
- }
- public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
- {
- var src = this;
- var dst = (TextureView)destination;
- if (!Valid || !dst.Valid)
- {
- return;
- }
- _gd.PipelineInternal.EndRenderPass();
- var cbs = _gd.PipelineInternal.CurrentCommandBuffer;
- var srcImage = src.GetImage().Get(cbs).Value;
- var dstImage = dst.GetImage().Get(cbs).Value;
- if (src.Info.Target.IsMultisample())
- {
- CopyMSToNonMS(_gd, cbs, src, dst, srcImage, dstImage, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
- }
- else
- {
- TextureCopy.Copy(
- _gd.Api,
- cbs.CommandBuffer,
- srcImage,
- dstImage,
- src.Info,
- dst.Info,
- src.FirstLayer,
- dst.FirstLayer,
- src.FirstLevel,
- dst.FirstLevel,
- srcLayer,
- dstLayer,
- srcLevel,
- dstLevel,
- 1,
- 1);
- }
- }
- private static void CopyMSToNonMS(
- VulkanRenderer gd,
- CommandBufferScoped cbs,
- TextureView src,
- TextureView dst,
- Image srcImage,
- Image dstImage,
- int srcLayer,
- int dstLayer,
- int srcLevel,
- int dstLevel,
- int layers,
- int levels)
- {
- bool differentFormats = src.Info.Format != dst.Info.Format;
- var target = src.Info.Target switch
- {
- Target.Texture2D => Target.Texture2DMultisample,
- Target.Texture2DArray => Target.Texture2DMultisampleArray,
- Target.Texture2DMultisampleArray => Target.Texture2DArray,
- _ => Target.Texture2D
- };
- var intermmediateTarget = differentFormats ? dst.Info.Target : target;
- using var intermmediate = CreateIntermmediateTexture(gd, src, ref dst._info, intermmediateTarget, layers, levels);
- var intermmediateImage = intermmediate.GetImage().Get(cbs).Value;
- if (differentFormats)
- {
- // If the formats are different, the resolve would perform format conversion.
- // So we need yet another intermmediate texture and do a copy to reinterpret the
- // data into the correct (destination) format, without doing any sort of conversion.
- using var intermmediate2 = CreateIntermmediateTexture(gd, src, ref src._info, target, layers, levels);
- var intermmediate2Image = intermmediate2.GetImage().Get(cbs).Value;
- TextureCopy.Copy(
- gd.Api,
- cbs.CommandBuffer,
- srcImage,
- intermmediate2Image,
- src.Info,
- intermmediate2.Info,
- src.FirstLayer,
- 0,
- src.FirstLevel,
- 0,
- srcLayer,
- 0,
- srcLevel,
- 0,
- layers,
- levels);
- TextureCopy.Copy(
- gd.Api,
- cbs.CommandBuffer,
- intermmediate2Image,
- intermmediateImage,
- intermmediate2.Info,
- intermmediate.Info,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- layers,
- levels);
- }
- else
- {
- TextureCopy.Copy(
- gd.Api,
- cbs.CommandBuffer,
- srcImage,
- intermmediateImage,
- src.Info,
- intermmediate.Info,
- src.FirstLayer,
- 0,
- src.FirstLevel,
- 0,
- srcLayer,
- 0,
- srcLevel,
- 0,
- layers,
- levels);
- }
- var srcRegion = new Extents2D(0, 0, src.Width, src.Height);
- var dstRegion = new Extents2D(0, 0, dst.Width, dst.Height);
- TextureCopy.Blit(
- gd.Api,
- cbs.CommandBuffer,
- intermmediateImage,
- dstImage,
- intermmediate.Info,
- dst.Info,
- srcRegion,
- dstRegion,
- 0,
- dst.FirstLevel + dstLevel,
- 0,
- dst.FirstLayer + dstLayer,
- layers,
- levels,
- true,
- ImageAspectFlags.ImageAspectColorBit,
- ImageAspectFlags.ImageAspectColorBit);
- }
- private static TextureView CreateIntermmediateTexture(VulkanRenderer gd, TextureView src, ref TextureCreateInfo formatInfo, Target target, int depth, int levels)
- {
- return gd.CreateTextureView(new GAL.TextureCreateInfo(
- src.Width,
- src.Height,
- depth,
- levels,
- 1,
- formatInfo.BlockWidth,
- formatInfo.BlockHeight,
- formatInfo.BytesPerPixel,
- formatInfo.Format,
- DepthStencilMode.Depth,
- target,
- SwizzleComponent.Red,
- SwizzleComponent.Green,
- SwizzleComponent.Blue,
- SwizzleComponent.Alpha), 1f);
- }
- public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
- {
- var dst = (TextureView)destination;
- if (_gd.CommandBufferPool.OwnedByCurrentThread)
- {
- _gd.PipelineInternal.EndRenderPass();
- var cbs = _gd.PipelineInternal.CurrentCommandBuffer;
- CopyToImpl(cbs, dst, srcRegion, dstRegion, linearFilter);
- }
- else
- {
- var cbp = _gd.BackgroundResources.Get().GetPool();
- using var cbs = cbp.Rent();
- CopyToImpl(cbs, dst, srcRegion, dstRegion, linearFilter);
- }
- }
- private void CopyToImpl(CommandBufferScoped cbs, TextureView dst, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
- {
- var src = this;
- var srcFormat = GetCompatibleGalFormat(src.Info.Format);
- var dstFormat = GetCompatibleGalFormat(dst.Info.Format);
- bool srcUsesStorageFormat = src.VkFormat == src.Storage.VkFormat;
- bool dstUsesStorageFormat = dst.VkFormat == dst.Storage.VkFormat;
- int layers = Math.Min(dst.Info.GetDepthOrLayers(), src.Info.GetDepthOrLayers());
- int levels = Math.Min(dst.Info.Levels, src.Info.Levels);
- if (srcUsesStorageFormat && dstUsesStorageFormat)
- {
- if ((srcRegion.X1 | dstRegion.X1) == 0 &&
- (srcRegion.Y1 | dstRegion.Y1) == 0 &&
- srcRegion.X2 == src.Width &&
- srcRegion.Y2 == src.Height &&
- dstRegion.X2 == dst.Width &&
- dstRegion.Y2 == dst.Height &&
- src.Width == dst.Width &&
- src.Height == dst.Height &&
- src.VkFormat == dst.VkFormat)
- {
- TextureCopy.Copy(
- _gd.Api,
- cbs.CommandBuffer,
- src.GetImage().Get(cbs).Value,
- dst.GetImage().Get(cbs).Value,
- src.Info,
- dst.Info,
- src.FirstLayer,
- dst.FirstLayer,
- src.FirstLevel,
- dst.FirstLevel,
- 0,
- 0,
- 0,
- 0,
- layers,
- levels);
- return;
- }
- else if (_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.FormatFeatureBlitSrcBit, srcFormat) &&
- _gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.FormatFeatureBlitDstBit, dstFormat))
- {
- TextureCopy.Blit(
- _gd.Api,
- cbs.CommandBuffer,
- src.GetImage().Get(cbs).Value,
- dst.GetImage().Get(cbs).Value,
- src.Info,
- dst.Info,
- srcRegion,
- dstRegion,
- src.FirstLayer,
- dst.FirstLayer,
- src.FirstLevel,
- dst.FirstLevel,
- layers,
- levels,
- linearFilter);
- return;
- }
- else if (srcFormat == GAL.Format.D32FloatS8Uint && srcFormat == dstFormat && SupportsBlitFromD32FS8ToD32FAndS8())
- {
- BlitDepthStencilWithBuffer(_gd, cbs, src, dst, srcRegion, dstRegion);
- return;
- }
- }
- if (VulkanConfiguration.UseSlowSafeBlitOnAmd &&
- _gd.Vendor == Vendor.Amd &&
- src.Info.Target == Target.Texture2D &&
- dst.Info.Target == Target.Texture2D &&
- !dst.Info.Format.IsDepthOrStencil())
- {
- _gd.HelperShader.Blit(
- _gd,
- src,
- dst.GetIdentityImageView(),
- dst.Width,
- dst.Height,
- dst.VkFormat,
- srcRegion,
- dstRegion,
- linearFilter);
- return;
- }
- Auto<DisposableImage> srcImage;
- Auto<DisposableImage> dstImage;
- if (dst.Info.Format.IsDepthOrStencil())
- {
- srcImage = src.Storage.CreateAliasedColorForDepthStorageUnsafe(srcFormat).GetImage();
- dstImage = dst.Storage.CreateAliasedColorForDepthStorageUnsafe(dstFormat).GetImage();
- }
- else
- {
- srcImage = src.Storage.CreateAliasedStorageUnsafe(srcFormat).GetImage();
- dstImage = dst.Storage.CreateAliasedStorageUnsafe(dstFormat).GetImage();
- }
- TextureCopy.Blit(
- _gd.Api,
- cbs.CommandBuffer,
- srcImage.Get(cbs).Value,
- dstImage.Get(cbs).Value,
- src.Info,
- dst.Info,
- srcRegion,
- dstRegion,
- src.FirstLevel,
- dst.FirstLevel,
- src.FirstLayer,
- dst.FirstLayer,
- layers,
- levels,
- linearFilter,
- ImageAspectFlags.ImageAspectColorBit,
- ImageAspectFlags.ImageAspectColorBit);
- }
- private static void BlitDepthStencilWithBuffer(
- VulkanRenderer gd,
- CommandBufferScoped cbs,
- TextureView src,
- TextureView dst,
- Extents2D srcRegion,
- Extents2D dstRegion)
- {
- int drBaseX = Math.Min(dstRegion.X1, dstRegion.X2);
- int drBaseY = Math.Min(dstRegion.Y1, dstRegion.Y2);
- int drWidth = Math.Abs(dstRegion.X2 - dstRegion.X1);
- int drHeight = Math.Abs(dstRegion.Y2 - dstRegion.Y1);
- var drOriginZero = new Extents2D(
- dstRegion.X1 - drBaseX,
- dstRegion.Y1 - drBaseY,
- dstRegion.X2 - drBaseX,
- dstRegion.Y2 - drBaseY);
- var d32SrcStorageInfo = TextureStorage.NewCreateInfoWith(ref src._info, GAL.Format.D32Float, 4);
- var d32DstStorageInfo = TextureStorage.NewCreateInfoWith(ref dst._info, GAL.Format.D32Float, 4, drWidth, drHeight);
- var s8SrcStorageInfo = TextureStorage.NewCreateInfoWith(ref src._info, GAL.Format.S8Uint, 1);
- var s8DstStorageInfo = TextureStorage.NewCreateInfoWith(ref dst._info, GAL.Format.S8Uint, 1, drWidth, drHeight);
- using var d32SrcStorage = gd.CreateTextureStorage(d32SrcStorageInfo, src.Storage.ScaleFactor);
- using var d32DstStorage = gd.CreateTextureStorage(d32DstStorageInfo, dst.Storage.ScaleFactor);
- using var s8SrcStorage = gd.CreateTextureStorage(s8SrcStorageInfo, src.Storage.ScaleFactor);
- using var s8DstStorage = gd.CreateTextureStorage(s8DstStorageInfo, dst.Storage.ScaleFactor);
- void SlowBlit(TextureStorage srcTemp, TextureStorage dstTemp, ImageAspectFlags aspectFlags)
- {
- int levels = Math.Min(src.Info.Levels, dst.Info.Levels);
- int srcSize = 0;
- int dstSize = 0;
- for (int l = 0; l < levels; l++)
- {
- srcSize += srcTemp.Info.GetMipSize2D(l);
- dstSize += dstTemp.Info.GetMipSize2D(l);
- }
- using var srcTempBuffer = gd.BufferManager.Create(gd, srcSize, deviceLocal: true);
- using var dstTempBuffer = gd.BufferManager.Create(gd, dstSize, deviceLocal: true);
- src.Storage.CopyFromOrToBuffer(
- cbs.CommandBuffer,
- srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value,
- src.GetImage().Get(cbs).Value,
- srcSize,
- to: true,
- 0,
- 0,
- src.FirstLayer,
- src.FirstLevel,
- 1,
- levels,
- true,
- aspectFlags,
- false);
- BufferHolder.InsertBufferBarrier(
- gd,
- cbs.CommandBuffer,
- srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value,
- AccessFlags.AccessTransferWriteBit,
- AccessFlags.AccessTransferReadBit,
- PipelineStageFlags.PipelineStageTransferBit,
- PipelineStageFlags.PipelineStageTransferBit,
- 0,
- srcSize);
- srcTemp.CopyFromOrToBuffer(
- cbs.CommandBuffer,
- srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value,
- srcTemp.GetImage().Get(cbs).Value,
- srcSize,
- to: false,
- 0,
- 0,
- 0,
- 0,
- 1,
- levels,
- true,
- aspectFlags,
- false);
- InsertImageBarrier(
- gd.Api,
- cbs.CommandBuffer,
- srcTemp.GetImage().Get(cbs).Value,
- AccessFlags.AccessTransferWriteBit,
- AccessFlags.AccessTransferReadBit,
- PipelineStageFlags.PipelineStageTransferBit,
- PipelineStageFlags.PipelineStageTransferBit,
- aspectFlags,
- 0,
- 0,
- 1,
- levels);
- TextureCopy.Blit(
- gd.Api,
- cbs.CommandBuffer,
- srcTemp.GetImage().Get(cbs).Value,
- dstTemp.GetImage().Get(cbs).Value,
- srcTemp.Info,
- dstTemp.Info,
- srcRegion,
- drOriginZero,
- 0,
- 0,
- 0,
- 0,
- 1,
- levels,
- false,
- aspectFlags,
- aspectFlags);
- InsertImageBarrier(
- gd.Api,
- cbs.CommandBuffer,
- dstTemp.GetImage().Get(cbs).Value,
- AccessFlags.AccessTransferWriteBit,
- AccessFlags.AccessTransferReadBit,
- PipelineStageFlags.PipelineStageTransferBit,
- PipelineStageFlags.PipelineStageTransferBit,
- aspectFlags,
- 0,
- 0,
- 1,
- levels);
- dstTemp.CopyFromOrToBuffer(
- cbs.CommandBuffer,
- dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value,
- dstTemp.GetImage().Get(cbs).Value,
- dstSize,
- to: true,
- 0,
- 0,
- 0,
- 0,
- 1,
- levels,
- true,
- aspectFlags,
- false);
- BufferHolder.InsertBufferBarrier(
- gd,
- cbs.CommandBuffer,
- dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value,
- AccessFlags.AccessTransferWriteBit,
- AccessFlags.AccessTransferReadBit,
- PipelineStageFlags.PipelineStageTransferBit,
- PipelineStageFlags.PipelineStageTransferBit,
- 0,
- dstSize);
- dst.Storage.CopyFromOrToBuffer(
- cbs.CommandBuffer,
- dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value,
- dst.GetImage().Get(cbs).Value,
- dstSize,
- to: false,
- drBaseX,
- drBaseY,
- dst.FirstLayer,
- dst.FirstLevel,
- 1,
- levels,
- true,
- aspectFlags,
- false);
- }
- SlowBlit(d32SrcStorage, d32DstStorage, ImageAspectFlags.ImageAspectDepthBit);
- SlowBlit(s8SrcStorage, s8DstStorage, ImageAspectFlags.ImageAspectStencilBit);
- }
- public static unsafe void InsertImageBarrier(
- Vk api,
- CommandBuffer commandBuffer,
- Image image,
- AccessFlags srcAccessMask,
- AccessFlags dstAccessMask,
- PipelineStageFlags srcStageMask,
- PipelineStageFlags dstStageMask,
- ImageAspectFlags aspectFlags,
- int firstLayer,
- int firstLevel,
- int layers,
- int levels)
- {
- ImageMemoryBarrier memoryBarrier = new ImageMemoryBarrier()
- {
- SType = StructureType.ImageMemoryBarrier,
- SrcAccessMask = srcAccessMask,
- DstAccessMask = dstAccessMask,
- SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
- DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
- Image = image,
- OldLayout = ImageLayout.General,
- NewLayout = ImageLayout.General,
- SubresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, (uint)levels, (uint)firstLayer, (uint)layers)
- };
- api.CmdPipelineBarrier(
- commandBuffer,
- srcStageMask,
- dstStageMask,
- 0,
- 0,
- null,
- 0,
- null,
- 1,
- memoryBarrier);
- }
- private bool SupportsBlitFromD32FS8ToD32FAndS8()
- {
- var formatFeatureFlags = FormatFeatureFlags.FormatFeatureBlitSrcBit | FormatFeatureFlags.FormatFeatureBlitDstBit;
- return _gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.D32Float) &&
- _gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.S8Uint);
- }
- public TextureView GetView(GAL.Format format)
- {
- if (format == Info.Format)
- {
- return this;
- }
- if (_selfManagedViews != null && _selfManagedViews.TryGetValue(format, out var view))
- {
- return view;
- }
- view = CreateViewImpl(new TextureCreateInfo(
- Info.Width,
- Info.Height,
- Info.Depth,
- Info.Levels,
- Info.Samples,
- Info.BlockWidth,
- Info.BlockHeight,
- Info.BytesPerPixel,
- format,
- Info.DepthStencilMode,
- Info.Target,
- Info.SwizzleR,
- Info.SwizzleG,
- Info.SwizzleB,
- Info.SwizzleA), 0, 0);
- (_selfManagedViews ??= new Dictionary<GAL.Format, TextureView>()).Add(format, view);
- return view;
- }
- public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
- {
- return CreateViewImpl(info, firstLayer, firstLevel);
- }
- private TextureView CreateViewImpl(TextureCreateInfo info, int firstLayer, int firstLevel)
- {
- return new TextureView(_gd, _device, info, Storage, FirstLayer + firstLayer, FirstLevel + firstLevel);
- }
- public byte[] GetData(int x, int y, int width, int height)
- {
- int size = width * height * Info.BytesPerPixel;
- using var bufferHolder = _gd.BufferManager.Create(_gd, size);
- using (var cbs = _gd.CommandBufferPool.Rent())
- {
- var buffer = bufferHolder.GetBuffer(cbs.CommandBuffer).Get(cbs).Value;
- var image = GetImage().Get(cbs).Value;
- CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, size, true, 0, 0, x, y, width, height);
- }
- bufferHolder.WaitForFences();
- byte[] bitmap = new byte[size];
- GetDataFromBuffer(bufferHolder.GetDataStorage(0, size), size, Span<byte>.Empty).CopyTo(bitmap);
- return bitmap;
- }
- public ReadOnlySpan<byte> GetData()
- {
- BackgroundResource resources = _gd.BackgroundResources.Get();
- if (_gd.CommandBufferPool.OwnedByCurrentThread)
- {
- _gd.FlushAllCommands();
- return GetData(_gd.CommandBufferPool, resources.GetFlushBuffer());
- }
- else
- {
- return GetData(resources.GetPool(), resources.GetFlushBuffer());
- }
- }
- public ReadOnlySpan<byte> GetData(int layer, int level)
- {
- BackgroundResource resources = _gd.BackgroundResources.Get();
- if (_gd.CommandBufferPool.OwnedByCurrentThread)
- {
- _gd.FlushAllCommands();
- return GetData(_gd.CommandBufferPool, resources.GetFlushBuffer(), layer, level);
- }
- else
- {
- return GetData(resources.GetPool(), resources.GetFlushBuffer(), layer, level);
- }
- }
- private ReadOnlySpan<byte> GetData(CommandBufferPool cbp, PersistentFlushBuffer flushBuffer)
- {
- int size = 0;
- for (int level = 0; level < Info.Levels; level++)
- {
- size += Info.GetMipSize(level);
- }
- size = GetBufferDataLength(size);
- Span<byte> result = flushBuffer.GetTextureData(cbp, this, size);
- return GetDataFromBuffer(result, size, result);
- }
- private ReadOnlySpan<byte> GetData(CommandBufferPool cbp, PersistentFlushBuffer flushBuffer, int layer, int level)
- {
- int size = GetBufferDataLength(Info.GetMipSize(level));
- Span<byte> result = flushBuffer.GetTextureData(cbp, this, size, layer, level);
- return GetDataFromBuffer(result, size, result);
- }
- public void SetData(SpanOrArray<byte> data)
- {
- SetData(data, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
- }
- public void SetData(SpanOrArray<byte> data, int layer, int level)
- {
- SetData(data, layer, level, 1, 1, singleSlice: true);
- }
- public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
- {
- SetData(data, layer, level, 1, 1, singleSlice: true, region);
- }
- private void SetData(ReadOnlySpan<byte> data, int layer, int level, int layers, int levels, bool singleSlice, Rectangle<int>? region = null)
- {
- int bufferDataLength = GetBufferDataLength(data.Length);
- using var bufferHolder = _gd.BufferManager.Create(_gd, bufferDataLength);
- Auto<DisposableImage> imageAuto = GetImage();
- // Load texture data inline if the texture has been used on the current command buffer.
- bool loadInline = Storage.HasCommandBufferDependency(_gd.PipelineInternal.CurrentCommandBuffer);
- var cbs = loadInline ? _gd.PipelineInternal.CurrentCommandBuffer : _gd.PipelineInternal.GetPreloadCommandBuffer();
- if (loadInline)
- {
- _gd.PipelineInternal.EndRenderPass();
- }
- CopyDataToBuffer(bufferHolder.GetDataStorage(0, bufferDataLength), data);
- var buffer = bufferHolder.GetBuffer(cbs.CommandBuffer).Get(cbs).Value;
- var image = imageAuto.Get(cbs).Value;
- if (region.HasValue)
- {
- CopyFromOrToBuffer(
- cbs.CommandBuffer,
- buffer,
- image,
- bufferDataLength,
- false,
- layer,
- level,
- region.Value.X,
- region.Value.Y,
- region.Value.Width,
- region.Value.Height);
- }
- else
- {
- CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, bufferDataLength, false, layer, level, layers, levels, singleSlice);
- }
- }
- private int GetBufferDataLength(int length)
- {
- if (NeedsD24S8Conversion())
- {
- return length * 2;
- }
- return length;
- }
- private GAL.Format GetCompatibleGalFormat(GAL.Format format)
- {
- if (NeedsD24S8Conversion())
- {
- return GAL.Format.D32FloatS8Uint;
- }
- return format;
- }
- private void CopyDataToBuffer(Span<byte> storage, ReadOnlySpan<byte> input)
- {
- if (NeedsD24S8Conversion())
- {
- FormatConverter.ConvertD24S8ToD32FS8(storage, input);
- return;
- }
- input.CopyTo(storage);
- }
- private ReadOnlySpan<byte> GetDataFromBuffer(ReadOnlySpan<byte> storage, int size, Span<byte> output)
- {
- if (NeedsD24S8Conversion())
- {
- if (output.IsEmpty)
- {
- output = new byte[GetBufferDataLength(size)];
- }
- FormatConverter.ConvertD32FS8ToD24S8(output, storage);
- return output;
- }
- return storage;
- }
- private bool NeedsD24S8Conversion()
- {
- return FormatCapabilities.IsD24S8(Info.Format) && VkFormat == VkFormat.D32SfloatS8Uint;
- }
- public void CopyFromOrToBuffer(
- CommandBuffer commandBuffer,
- VkBuffer buffer,
- Image image,
- int size,
- bool to,
- int dstLayer,
- int dstLevel,
- int dstLayers,
- int dstLevels,
- bool singleSlice)
- {
- bool is3D = Info.Target == Target.Texture3D;
- int width = Math.Max(1, Info.Width >> dstLevel);
- int height = Math.Max(1, Info.Height >> dstLevel);
- int depth = is3D && !singleSlice ? Math.Max(1, Info.Depth >> dstLevel) : 1;
- int layer = is3D ? 0 : dstLayer;
- int layers = dstLayers;
- int levels = dstLevels;
- int offset = 0;
- for (int level = 0; level < levels; level++)
- {
- int mipSize = GetBufferDataLength(Info.GetMipSize(dstLevel + level));
- int endOffset = offset + mipSize;
- if ((uint)endOffset > (uint)size)
- {
- break;
- }
- int rowLength = (Info.GetMipStride(dstLevel + level) / Info.BytesPerPixel) * Info.BlockWidth;
- var aspectFlags = Info.Format.ConvertAspectFlags();
- if (aspectFlags == (ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit))
- {
- aspectFlags = ImageAspectFlags.ImageAspectDepthBit;
- }
- var sl = new ImageSubresourceLayers(
- aspectFlags,
- (uint)(FirstLevel + dstLevel + level),
- (uint)(FirstLayer + layer),
- (uint)layers);
- var extent = new Extent3D((uint)width, (uint)height, (uint)depth);
- int z = is3D ? dstLayer : 0;
- var region = new BufferImageCopy(
- (ulong)offset,
- (uint)AlignUpNpot(rowLength, Info.BlockWidth),
- (uint)AlignUpNpot(height, Info.BlockHeight),
- sl,
- new Offset3D(0, 0, z),
- extent);
- if (to)
- {
- _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region);
- }
- else
- {
- _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region);
- }
- offset += mipSize;
- width = Math.Max(1, width >> 1);
- height = Math.Max(1, height >> 1);
- if (Info.Target == Target.Texture3D)
- {
- depth = Math.Max(1, depth >> 1);
- }
- }
- }
- private void CopyFromOrToBuffer(
- CommandBuffer commandBuffer,
- VkBuffer buffer,
- Image image,
- int size,
- bool to,
- int dstLayer,
- int dstLevel,
- int x,
- int y,
- int width,
- int height)
- {
- var aspectFlags = Info.Format.ConvertAspectFlags();
- if (aspectFlags == (ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit))
- {
- aspectFlags = ImageAspectFlags.ImageAspectDepthBit;
- }
- var sl = new ImageSubresourceLayers(aspectFlags, (uint)(FirstLevel + dstLevel), (uint)(FirstLayer + dstLayer), 1);
- var extent = new Extent3D((uint)width, (uint)height, 1);
- int rowLengthAlignment = Info.BlockWidth;
- // We expect all data being written into the texture to have a stride aligned by 4.
- if (!to && Info.BytesPerPixel < 4)
- {
- rowLengthAlignment = 4 / Info.BytesPerPixel;
- }
- var region = new BufferImageCopy(
- 0,
- (uint)AlignUpNpot(width, rowLengthAlignment),
- (uint)AlignUpNpot(height, Info.BlockHeight),
- sl,
- new Offset3D(x, y, 0),
- extent);
- if (to)
- {
- _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region);
- }
- else
- {
- _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region);
- }
- }
- private static int AlignUpNpot(int size, int alignment)
- {
- int remainder = size % alignment;
- if (remainder == 0)
- {
- return size;
- }
- return size + (alignment - remainder);
- }
- public void SetStorage(BufferRange buffer)
- {
- throw new NotImplementedException();
- }
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
- Valid = false;
- if (_gd.Textures.Remove(this))
- {
- _imageView.Dispose();
- _imageViewIdentity.Dispose();
- _imageView2dArray?.Dispose();
- Storage.DecrementViewsCount();
- }
- }
- }
- public void Dispose()
- {
- if (_selfManagedViews != null)
- {
- foreach (var view in _selfManagedViews.Values)
- {
- view.Dispose();
- }
- _selfManagedViews = null;
- }
- Dispose(true);
- }
- public void Release()
- {
- Dispose();
- }
- }
- }
|