| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072 |
- 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, ImageUsageFlags usageFlags = 0)
- {
- var usage = new ImageViewUsageCreateInfo()
- {
- SType = StructureType.ImageViewUsageCreateInfo,
- Usage = usageFlags
- };
- var imageCreateInfo = new ImageViewCreateInfo()
- {
- SType = StructureType.ImageViewCreateInfo,
- Image = storage.GetImageForViewCreation(),
- ViewType = viewType,
- Format = format,
- Components = cm,
- SubresourceRange = sr,
- PNext = usageFlags == 0 ? null : &usage
- };
- 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)
- {
- if (gd.Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.No3DImageView))
- {
- if (levels == 1 && (info.Format.IsRtColorCompatible() || info.Format.IsDepthOrStencil()))
- {
- subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, 1);
- _imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.Type2D, ImageUsageFlags.ColorAttachmentBit);
- }
- }
- else
- {
- subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth);
- _imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.Type2DArray);
- }
- }
- 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 (!dst.Info.Target.IsMultisample() && Info.Target.IsMultisample())
- {
- int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
- _gd.HelperShader.CopyMSToNonMS(_gd, cbs, src, dst, 0, firstLayer, layers);
- }
- else if (dst.Info.Target.IsMultisample() && !Info.Target.IsMultisample())
- {
- int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
- _gd.HelperShader.CopyNonMSToMS(_gd, cbs, src, dst, 0, firstLayer, layers);
- }
- 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 (!dst.Info.Target.IsMultisample() && Info.Target.IsMultisample())
- {
- _gd.HelperShader.CopyMSToNonMS(_gd, cbs, src, dst, srcLayer, dstLayer, 1);
- }
- else if (dst.Info.Target.IsMultisample() && !Info.Target.IsMultisample())
- {
- _gd.HelperShader.CopyNonMSToMS(_gd, cbs, src, dst, srcLayer, dstLayer, 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);
- }
- }
- 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)
- {
- if (src.Info.Samples > 1 && src.Info.Samples != dst.Info.Samples && src.Info.Format.IsDepthOrStencil())
- {
- // CmdResolveImage does not support depth-stencil resolve, so we need to use an alternative path
- // for those textures.
- TextureCopy.ResolveDepthStencil(_gd, _device, cbs, src, dst);
- }
- else
- {
- 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.BlitSrcBit, srcFormat) &&
- _gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.BlitDstBit, 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 || _gd.IsMoltenVk) &&
- 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.FirstLayer,
- dst.FirstLayer,
- src.FirstLevel,
- dst.FirstLevel,
- layers,
- levels,
- linearFilter,
- ImageAspectFlags.ColorBit,
- ImageAspectFlags.ColorBit);
- }
- 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.TransferWriteBit,
- AccessFlags.TransferReadBit,
- PipelineStageFlags.TransferBit,
- PipelineStageFlags.TransferBit,
- 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.TransferWriteBit,
- AccessFlags.TransferReadBit,
- PipelineStageFlags.TransferBit,
- PipelineStageFlags.TransferBit,
- 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.TransferWriteBit,
- AccessFlags.TransferReadBit,
- PipelineStageFlags.TransferBit,
- PipelineStageFlags.TransferBit,
- 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.TransferWriteBit,
- AccessFlags.TransferReadBit,
- PipelineStageFlags.TransferBit,
- PipelineStageFlags.TransferBit,
- 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.DepthBit);
- SlowBlit(s8SrcStorage, s8DstStorage, ImageAspectFlags.StencilBit);
- }
- 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.BlitSrcBit | FormatFeatureFlags.BlitDstBit;
- 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.DepthBit | ImageAspectFlags.StencilBit))
- {
- aspectFlags = ImageAspectFlags.DepthBit;
- }
- 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.DepthBit | ImageAspectFlags.StencilBit))
- {
- aspectFlags = ImageAspectFlags.DepthBit;
- }
- 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();
- }
- }
- }
|