Esempio n. 1
0
 /// <summary>
 /// Gets the aligned sizes for the given dimensions, using the specified texture information.
 /// The alignment depends on the texture layout and format bytes per pixel.
 /// </summary>
 /// <param name="info">Texture information to calculate the aligned size from</param>
 /// <param name="width">The width to be aligned</param>
 /// <param name="height">The height to be aligned</param>
 /// <param name="depth">The depth to be aligned</param>
 /// <returns>The aligned texture size</returns>
 private static Size GetAlignedSize(TextureInfo info, int width, int height, int depth)
 {
     if (info.IsLinear)
     {
         return(SizeCalculator.GetLinearAlignedSize(
                    width,
                    height,
                    info.FormatInfo.BlockWidth,
                    info.FormatInfo.BlockHeight,
                    info.FormatInfo.BytesPerPixel));
     }
     else
     {
         return(SizeCalculator.GetBlockLinearAlignedSize(
                    width,
                    height,
                    depth,
                    info.FormatInfo.BlockWidth,
                    info.FormatInfo.BlockHeight,
                    info.FormatInfo.BytesPerPixel,
                    info.GobBlocksInY,
                    info.GobBlocksInZ,
                    info.GobBlocksInTileX));
     }
 }
        public static PatternFabricOptionsReportViewModel Build(IEnumerable <V2.PatternModel> sourceItems)
        {
            var model = new PatternFabricOptionsReportViewModel {
                Lines = new List <FabricPatterns>()
            };
            var items = sourceItems
                        .Where(x => x.FabricOptions != null && x.FabricOptions.Any())
                        .ToArray();
            var options = items
                          .SelectMany(x => x.FabricOptions)
                          .Distinct(_comparer)
                          .OrderBy(x => x.Name)
                          .ToArray();

            foreach (var option in options)
            {
                var patterns = items.Where(x => x.FabricOptions.Contains(option, _comparer));
                model.Lines.Add(new FabricPatterns
                {
                    Name     = $"{option.Name}, {option.Color} ({option.ColorName})",
                    Patterns = patterns.Select(x => $"{x.Title}, {SizeCalculator.SizeInSm(x.Size.Width, x.Size.Height, option.Name)}")
                });
            }

            return(model);
        }
Esempio n. 3
0
 /// <summary>
 /// Calculates the size information from the texture information.
 /// </summary>
 /// <param name="layerSize">Optional size of each texture layer in bytes</param>
 /// <returns>Texture size information</returns>
 public SizeInfo CalculateSizeInfo(int layerSize = 0)
 {
     if (Target == Target.TextureBuffer)
     {
         return(new SizeInfo(Width * FormatInfo.BytesPerPixel));
     }
     else if (IsLinear)
     {
         return(SizeCalculator.GetLinearTextureSize(
                    Stride,
                    Height,
                    FormatInfo.BlockHeight));
     }
     else
     {
         return(SizeCalculator.GetBlockLinearTextureSize(
                    Width,
                    Height,
                    GetDepth(),
                    Levels,
                    GetLayers(),
                    FormatInfo.BlockWidth,
                    FormatInfo.BlockHeight,
                    FormatInfo.BytesPerPixel,
                    GobBlocksInY,
                    GobBlocksInZ,
                    GobBlocksInTileX,
                    layerSize));
     }
 }
        /// <summary>
        /// Gets the aligned sizes of the specified texture information.
        /// The alignment depends on the texture layout and format bytes per pixel.
        /// </summary>
        /// <param name="info">Texture information to calculate the aligned size from</param>
        /// <param name="level">Mipmap level for texture views</param>
        /// <returns>The aligned texture size</returns>
        public static Size GetAlignedSize(TextureInfo info, int level = 0)
        {
            int width  = Math.Max(1, info.Width >> level);
            int height = Math.Max(1, info.Height >> level);

            if (info.IsLinear)
            {
                return(SizeCalculator.GetLinearAlignedSize(
                           width,
                           height,
                           info.FormatInfo.BlockWidth,
                           info.FormatInfo.BlockHeight,
                           info.FormatInfo.BytesPerPixel));
            }
            else
            {
                int depth = Math.Max(1, info.GetDepth() >> level);

                return(SizeCalculator.GetBlockLinearAlignedSize(
                           width,
                           height,
                           depth,
                           info.FormatInfo.BlockWidth,
                           info.FormatInfo.BlockHeight,
                           info.FormatInfo.BytesPerPixel,
                           info.GobBlocksInY,
                           info.GobBlocksInZ,
                           info.GobBlocksInTileX));
            }
        }
        /// <summary>
        /// Check if it's possible to create a view with the layout of the second texture information from the first.
        /// The layout information is composed of the Stride for linear textures, or GOB block size
        /// for block linear textures.
        /// </summary>
        /// <param name="lhs">Texture information of the texture view</param>
        /// <param name="rhs">Texture information of the texture view to compare against</param>
        /// <param name="level">Start level of the texture view, in relation with the first texture</param>
        /// <returns>True if the layout is compatible, false otherwise</returns>
        public static bool ViewLayoutCompatible(TextureInfo lhs, TextureInfo rhs, int level)
        {
            if (lhs.IsLinear != rhs.IsLinear)
            {
                return(false);
            }

            // For linear textures, gob block sizes are ignored.
            // For block linear textures, the stride is ignored.
            if (rhs.IsLinear)
            {
                int width  = Math.Max(1, lhs.Width >> level);
                int stride = width * lhs.FormatInfo.BytesPerPixel;
                stride = BitUtils.AlignUp(stride, 32);

                return(stride == rhs.Stride);
            }
            else
            {
                int height = Math.Max(1, lhs.Height >> level);
                int depth  = Math.Max(1, lhs.GetDepth() >> level);

                (int gobBlocksInY, int gobBlocksInZ) = SizeCalculator.GetMipGobBlockSizes(
                    height,
                    depth,
                    lhs.FormatInfo.BlockHeight,
                    lhs.GobBlocksInY,
                    lhs.GobBlocksInZ);

                return(gobBlocksInY == rhs.GobBlocksInY &&
                       gobBlocksInZ == rhs.GobBlocksInZ);
            }
        }
Esempio n. 6
0
        public void TestCalculationOfAbsoluteFromPercentageWorks(int percent, int currentWidth, int currentHeight, int expectedWidth, int expectedHeight)
        {
            var newSize = SizeCalculator.CalcAbsoluteFromPercentage(percent, new System.Drawing.Size(currentWidth, currentHeight));

            Assert.Equal(expectedWidth, newSize.Width);
            Assert.Equal(expectedHeight, newSize.Height);
        }
Esempio n. 7
0
        static void Main(string[] args)
        {
            var routeDirectory = args.Length == 1 ? args[0] : Directory.GetCurrentDirectory();

            var calculator = new SizeCalculator(routeDirectory);

            calculator.PrintOutput();
        }
Esempio n. 8
0
        public CodeGen(ASTNodeBase astTree, GlobalSymbolTable globalSymbolTable, CodeWriter codeStream)
        {
            _astTree           = astTree;
            _globalSymbolTable = globalSymbolTable;
            _writer            = codeStream;

            _sizeCalculator = new SizeCalculator(_astTree, _globalSymbolTable);
        }
Esempio n. 9
0
        /// <summary>
        /// Enqueues a frame for presentation.
        /// This method is thread safe and can be called from any thread.
        /// When the texture is presented and not needed anymore, the release callback is called.
        /// It's an error to modify the texture after calling this method, before the release callback is called.
        /// </summary>
        /// <param name="address">CPU virtual address of the texture data</param>
        /// <param name="width">Texture width</param>
        /// <param name="height">Texture height</param>
        /// <param name="stride">Texture stride for linear texture, should be zero otherwise</param>
        /// <param name="isLinear">Indicates if the texture is linear, normally false</param>
        /// <param name="gobBlocksInY">GOB blocks in the Y direction, for block linear textures</param>
        /// <param name="format">Texture format</param>
        /// <param name="bytesPerPixel">Texture format bytes per pixel (must match the format)</param>
        /// <param name="crop">Texture crop region</param>
        /// <param name="acquireCallback">Texture acquire callback</param>
        /// <param name="releaseCallback">Texture release callback</param>
        /// <param name="userObj">User defined object passed to the release callback</param>
        public void EnqueueFrameThreadSafe(
            ulong address,
            int width,
            int height,
            int stride,
            bool isLinear,
            int gobBlocksInY,
            Format format,
            int bytesPerPixel,
            ImageCrop crop,
            Action <GpuContext, object> acquireCallback,
            Action <object> releaseCallback,
            object userObj)
        {
            FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel, 4);

            TextureInfo info = new TextureInfo(
                0UL,
                width,
                height,
                1,
                1,
                1,
                1,
                stride,
                isLinear,
                gobBlocksInY,
                1,
                1,
                Target.Texture2D,
                formatInfo);

            int size = SizeCalculator.GetBlockLinearTextureSize(
                width,
                height,
                1,
                1,
                1,
                1,
                1,
                bytesPerPixel,
                gobBlocksInY,
                1,
                1).TotalSize;

            MultiRange range = new MultiRange(address, (ulong)size);

            _frameQueue.Enqueue(new PresentationTexture(info, range, crop, acquireCallback, releaseCallback, userObj));
        }
Esempio n. 10
0
        public void Start()
        {
            var spriteRenderer = GetSpriteRenderer();

            if (spriteRenderer != null)
            {
                spriteRenderer.sprite = BaseUnitData.unitSprite;

                var scale = SizeCalculator.SpriteScale(this.SizeCategory);
                spriteRenderer.transform.localScale = new Vector3(scale, scale);
                AlignSpriteRenderer();
            }

            Initialize();
        }
Esempio n. 11
0
        /// <summary>
        /// Check if it's possible to create a view with the layout of the second texture information from the first.
        /// The layout information is composed of the Stride for linear textures, or GOB block size
        /// for block linear textures.
        /// </summary>
        /// <param name="lhs">Texture information of the texture view</param>
        /// <param name="rhs">Texture information of the texture view to compare against</param>
        /// <param name="lhsLevel">Start level of the texture view, in relation with the first texture</param>
        /// <param name="rhsLevel">Start level of the texture view, in relation with the second texture</param>
        /// <returns>True if the layout is compatible, false otherwise</returns>
        public static bool ViewLayoutCompatible(TextureInfo lhs, TextureInfo rhs, int lhsLevel, int rhsLevel)
        {
            if (lhs.IsLinear != rhs.IsLinear)
            {
                return(false);
            }

            // For linear textures, gob block sizes are ignored.
            // For block linear textures, the stride is ignored.
            if (rhs.IsLinear)
            {
                int lhsStride = Math.Max(1, lhs.Stride >> lhsLevel);
                lhsStride = BitUtils.AlignUp(lhsStride, Constants.StrideAlignment);

                int rhsStride = Math.Max(1, rhs.Stride >> rhsLevel);
                rhsStride = BitUtils.AlignUp(rhsStride, Constants.StrideAlignment);

                return(lhsStride == rhsStride);
            }
            else
            {
                int lhsHeight = Math.Max(1, lhs.Height >> lhsLevel);
                int lhsDepth  = Math.Max(1, lhs.GetDepth() >> lhsLevel);

                (int lhsGobBlocksInY, int lhsGobBlocksInZ) = SizeCalculator.GetMipGobBlockSizes(
                    lhsHeight,
                    lhsDepth,
                    lhs.FormatInfo.BlockHeight,
                    lhs.GobBlocksInY,
                    lhs.GobBlocksInZ);

                int rhsHeight = Math.Max(1, rhs.Height >> rhsLevel);
                int rhsDepth  = Math.Max(1, rhs.GetDepth() >> rhsLevel);

                (int rhsGobBlocksInY, int rhsGobBlocksInZ) = SizeCalculator.GetMipGobBlockSizes(
                    rhsHeight,
                    rhsDepth,
                    rhs.FormatInfo.BlockHeight,
                    rhs.GobBlocksInY,
                    rhs.GobBlocksInZ);

                return(lhsGobBlocksInY == rhsGobBlocksInY &&
                       lhsGobBlocksInZ == rhsGobBlocksInZ);
            }
        }
Esempio n. 12
0
        /// <summary>
        /// Creates a new instance of the state update tracker.
        /// </summary>
        /// <param name="entries">Update tracker callback entries</param>
        public StateUpdateTracker(StateUpdateCallbackEntry[] entries)
        {
            _registerToGroupMapping = new byte[BlockSize];
            _callbacks = new Action[entries.Length];

            var fieldToDelegate = new Dictionary <string, int>();

            for (int entryIndex = 0; entryIndex < entries.Length; entryIndex++)
            {
                var entry = entries[entryIndex];

                foreach (var fieldName in entry.FieldNames)
                {
                    fieldToDelegate.Add(fieldName, entryIndex);
                }

                _callbacks[entryIndex] = entry.Callback;
            }

            var fields = typeof(TState).GetFields();
            int offset = 0;

            for (int fieldIndex = 0; fieldIndex < fields.Length; fieldIndex++)
            {
                var field = fields[fieldIndex];

                int sizeOfField = SizeCalculator.SizeOf(field.FieldType);

                if (fieldToDelegate.TryGetValue(field.Name, out int entryIndex))
                {
                    for (int i = 0; i < ((sizeOfField + 3) & ~3); i += 4)
                    {
                        _registerToGroupMapping[(offset + i) / RegisterSize] = (byte)(entryIndex + 1);
                    }
                }

                offset += sizeOfField;
            }

            Debug.Assert(offset == Unsafe.SizeOf <TState>());
        }
Esempio n. 13
0
        /// <summary>
        /// Processes the <paramref name="inputImage"/>.
        /// </summary>
        /// <param name="inputImage">Image to process.</param>
        /// <returns>Processed image.</returns>
        public Image Process(Image inputImage)
        {
            if (inputImage == null)
            {
                throw new ArgumentNullException(nameof(inputImage));
            }

            var newSize = SizeCalculator.GetCalculatedSize(inputImage);

            if (Mode == ScaleMode.NearestNeighbor)
            {
                return(ProcessNearestNeighbor(inputImage, newSize));
            }
            else if (Mode == ScaleMode.Bilinear)
            {
                return(ProcessBiliniar(inputImage, newSize));
            }
            else
            {
                throw new ArgumentException("Unknown scale mode");
            }
        }
Esempio n. 14
0
        /// <summary>
        /// Enqueues a frame for presentation.
        /// This method is thread safe and can be called from any thread.
        /// When the texture is presented and not needed anymore, the release callback is called.
        /// It's an error to modify the texture after calling this method, before the release callback is called.
        /// </summary>
        /// <param name="pid">Process ID of the process that owns the texture pointed to by <paramref name="address"/></param>
        /// <param name="address">CPU virtual address of the texture data</param>
        /// <param name="width">Texture width</param>
        /// <param name="height">Texture height</param>
        /// <param name="stride">Texture stride for linear texture, should be zero otherwise</param>
        /// <param name="isLinear">Indicates if the texture is linear, normally false</param>
        /// <param name="gobBlocksInY">GOB blocks in the Y direction, for block linear textures</param>
        /// <param name="format">Texture format</param>
        /// <param name="bytesPerPixel">Texture format bytes per pixel (must match the format)</param>
        /// <param name="crop">Texture crop region</param>
        /// <param name="acquireCallback">Texture acquire callback</param>
        /// <param name="releaseCallback">Texture release callback</param>
        /// <param name="userObj">User defined object passed to the release callback</param>
        /// <exception cref="ArgumentException">Thrown when <paramref name="pid"/> is invalid</exception>
        public void EnqueueFrameThreadSafe(
            long pid,
            ulong address,
            int width,
            int height,
            int stride,
            bool isLinear,
            int gobBlocksInY,
            Format format,
            int bytesPerPixel,
            ImageCrop crop,
            Action <GpuContext, object> acquireCallback,
            Action <object> releaseCallback,
            object userObj)
        {
            if (!_context.PhysicalMemoryRegistry.TryGetValue(pid, out var physicalMemory))
            {
                throw new ArgumentException("The PID is invalid or the process was not registered", nameof(pid));
            }

            FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel, 4);

            TextureInfo info = new TextureInfo(
                0UL,
                width,
                height,
                1,
                1,
                1,
                1,
                stride,
                isLinear,
                gobBlocksInY,
                1,
                1,
                Target.Texture2D,
                formatInfo);

            int size = SizeCalculator.GetBlockLinearTextureSize(
                width,
                height,
                1,
                1,
                1,
                1,
                1,
                bytesPerPixel,
                gobBlocksInY,
                1,
                1).TotalSize;

            MultiRange range = new MultiRange(address, (ulong)size);

            _frameQueue.Enqueue(new PresentationTexture(
                                    physicalMemory.TextureCache,
                                    info,
                                    range,
                                    crop,
                                    acquireCallback,
                                    releaseCallback,
                                    userObj));
        }
Esempio n. 15
0
        public void TestCalculationOfPercentageFromAbsoluteWorks(int currentSize, int initSize, int expectedPerc)
        {
            var perc = SizeCalculator.CalcPercentageFromAbsolute(initSize, currentSize);

            Assert.Equal(perc, expectedPerc);
        }
Esempio n. 16
0
        public void CreateDamageModifiers(AbilityExecuteParameters parameters, AbilityResultContainer abilityResultContainer)
        {
            var user = parameters.UnitExecuting;

            if (!(parameters.Target is IGameUnit))
            {
                return;
            }
            var target = parameters.Target as IGameUnit;

            var sizeDifference    = SizeCalculator.GetSizeDifference(user.SizeCategory, target.SizeCategory);
            var absSizeDifference = Math.Abs(sizeDifference);

            // Static size difference modifiers
            if (sizeDifference > 0)
            {
                var multiplier = Mathf.Pow(1.2f, absSizeDifference);
                abilityResultContainer.DamageModifiers.Add(new DamageModifierContainer {
                    DamageMultiplier = multiplier, Name = "Bigger Size Bonus"
                });
            }
            else if (sizeDifference < 0)
            {
                var multiplier = Mathf.Pow(0.8f, absSizeDifference);
                abilityResultContainer.DamageModifiers.Add(new DamageModifierContainer {
                    DamageMultiplier = multiplier, Name = "Smaller Size Bonus"
                });
            }

            // Ability-based Size Difference
            if (_damageParameters.SizeBiggerDamageMultiplier > 1 && sizeDifference > 0)
            {
                var multiplier = Mathf.Pow(_damageParameters.SizeBiggerDamageMultiplier, absSizeDifference);
                abilityResultContainer.DamageModifiers.Add(new DamageModifierContainer {
                    DamageMultiplier = multiplier, Name = "Ability Bigger Size Bonus"
                });
            }
            else if (_damageParameters.SizeBiggerDamageMultiplier < 1 && sizeDifference > 0)
            {
                var multiplier = Mathf.Pow(_damageParameters.SizeBiggerDamageMultiplier, absSizeDifference);
                abilityResultContainer.DamageModifiers.Add(new DamageModifierContainer {
                    DamageMultiplier = multiplier, Name = "Ability Bigger Size Penalty"
                });
            }


            if (_damageParameters.SizeSmallerDamageMultiplier > 1 && sizeDifference < 0)
            {
                var multiplier = Mathf.Pow(_damageParameters.SizeSmallerDamageMultiplier, absSizeDifference);
                abilityResultContainer.DamageModifiers.Add(new DamageModifierContainer {
                    DamageMultiplier = multiplier, Name = "Ability Smaller Size Bonus"
                });
            }
            else if (_damageParameters.SizeSmallerDamageMultiplier < 1 && sizeDifference < 0)
            {
                var multiplier = Mathf.Pow(_damageParameters.SizeSmallerDamageMultiplier, absSizeDifference);
                abilityResultContainer.DamageModifiers.Add(new DamageModifierContainer {
                    DamageMultiplier = multiplier, Name = "Ability Smaller Size Penalty"
                });
            }
        }
Esempio n. 17
0
        /// <summary>
        /// Tries to find an existing texture, or create a new one if not found.
        /// </summary>
        /// <param name="info">Texture information of the texture to be found or created</param>
        /// <param name="flags">The texture search flags, defines texture comparison rules</param>
        /// <returns>The texture</returns>
        public Texture FindOrCreateTexture(TextureInfo info, TextureSearchFlags flags = TextureSearchFlags.None)
        {
            bool isSamplerTexture = (flags & TextureSearchFlags.Sampler) != 0;

            // Try to find a perfect texture match, with the same address and parameters.
            int sameAddressOverlapsCount = _textures.FindOverlaps(info.Address, ref _textureOverlaps);

            for (int index = 0; index < sameAddressOverlapsCount; index++)
            {
                Texture overlap = _textureOverlaps[index];

                if (overlap.IsPerfectMatch(info, flags))
                {
                    if (!isSamplerTexture)
                    {
                        // If not a sampler texture, it is managed by the auto delete
                        // cache, ensure that it is on the "top" of the list to avoid
                        // deletion.
                        _cache.Lift(overlap);
                    }
                    else if (!overlap.SizeMatches(info))
                    {
                        // If this is used for sampling, the size must match,
                        // otherwise the shader would sample garbage data.
                        // To fix that, we create a new texture with the correct
                        // size, and copy the data from the old one to the new one.
                        overlap.ChangeSize(info.Width, info.Height, info.DepthOrLayers);
                    }

                    return(overlap);
                }
            }

            // Calculate texture sizes, used to find all overlapping textures.
            SizeInfo sizeInfo;

            if (info.IsLinear)
            {
                sizeInfo = SizeCalculator.GetLinearTextureSize(
                    info.Stride,
                    info.Height,
                    info.FormatInfo.BlockHeight);
            }
            else
            {
                sizeInfo = SizeCalculator.GetBlockLinearTextureSize(
                    info.Width,
                    info.Height,
                    info.GetDepth(),
                    info.Levels,
                    info.GetLayers(),
                    info.FormatInfo.BlockWidth,
                    info.FormatInfo.BlockHeight,
                    info.FormatInfo.BytesPerPixel,
                    info.GobBlocksInY,
                    info.GobBlocksInZ,
                    info.GobBlocksInTileX);
            }

            // Find view compatible matches.
            ulong size = (ulong)sizeInfo.TotalSize;

            int overlapsCount = _textures.FindOverlaps(info.Address, size, ref _textureOverlaps);

            Texture texture = null;

            for (int index = 0; index < overlapsCount; index++)
            {
                Texture overlap = _textureOverlaps[index];

                if (overlap.IsViewCompatible(info, size, out int firstLayer, out int firstLevel))
                {
                    if (!isSamplerTexture)
                    {
                        info = AdjustSizes(overlap, info, firstLevel);
                    }

                    texture = overlap.CreateView(info, sizeInfo, firstLayer, firstLevel);

                    if (IsTextureModified(overlap))
                    {
                        CacheTextureModified(texture);
                    }

                    // The size only matters (and is only really reliable) when the
                    // texture is used on a sampler, because otherwise the size will be
                    // aligned.
                    if (!overlap.SizeMatches(info, firstLevel) && isSamplerTexture)
                    {
                        texture.ChangeSize(info.Width, info.Height, info.DepthOrLayers);
                    }

                    break;
                }
            }

            // No match, create a new texture.
            if (texture == null)
            {
                texture = new Texture(_context, info, sizeInfo);

                // We need to synchronize before copying the old view data to the texture,
                // otherwise the copied data would be overwritten by a future synchronization.
                texture.SynchronizeMemory();

                for (int index = 0; index < overlapsCount; index++)
                {
                    Texture overlap = _textureOverlaps[index];

                    if (texture.IsViewCompatible(overlap.Info, overlap.Size, out int firstLayer, out int firstLevel))
                    {
                        TextureInfo overlapInfo = AdjustSizes(texture, overlap.Info, firstLevel);

                        TextureCreateInfo createInfo = GetCreateInfo(overlapInfo, _context.Capabilities);

                        ITexture newView = texture.HostTexture.CreateView(createInfo, firstLayer, firstLevel);

                        overlap.HostTexture.CopyTo(newView, 0, 0);

                        // Inherit modification from overlapping texture, do that before replacing
                        // the view since the replacement operation removes it from the list.
                        if (IsTextureModified(overlap))
                        {
                            CacheTextureModified(texture);
                        }

                        overlap.ReplaceView(texture, overlapInfo, newView);
                    }
                }

                // If the texture is a 3D texture, we need to additionally copy any slice
                // of the 3D texture to the newly created 3D texture.
                if (info.Target == Target.Texture3D)
                {
                    for (int index = 0; index < overlapsCount; index++)
                    {
                        Texture overlap = _textureOverlaps[index];

                        if (texture.IsViewCompatible(
                                overlap.Info,
                                overlap.Size,
                                isCopy: true,
                                out int firstLayer,
                                out int firstLevel))
                        {
                            overlap.HostTexture.CopyTo(texture.HostTexture, firstLayer, firstLevel);

                            if (IsTextureModified(overlap))
                            {
                                CacheTextureModified(texture);
                            }
                        }
                    }
                }
            }

            // Sampler textures are managed by the texture pool, all other textures
            // are managed by the auto delete cache.
            if (!isSamplerTexture)
            {
                _cache.Add(texture);
                texture.Modified += CacheTextureModified;
                texture.Disposed += CacheTextureDisposed;
            }

            _textures.Add(texture);

            ShrinkOverlapsBufferIfNeeded();

            return(texture);
        }
Esempio n. 18
0
 public static int GetBlockLinearSize(int width, int height, int bytesPerPixel)
 {
     return(SizeCalculator.GetBlockLinearTextureSize(width, height, 1, 1, 1, 1, 1, bytesPerPixel, 2, 1, 1).TotalSize);
 }
Esempio n. 19
0
        /// <summary>
        /// Tries to find an existing texture, or create a new one if not found.
        /// </summary>
        /// <param name="info">Texture information of the texture to be found or created</param>
        /// <param name="flags">The texture search flags, defines texture comparison rules</param>
        /// <returns>The texture</returns>
        public Texture FindOrCreateTexture(TextureInfo info, TextureSearchFlags flags = TextureSearchFlags.None)
        {
            bool isSamplerTexture = (flags & TextureSearchFlags.ForSampler) != 0;

            bool isScalable = IsUpscaleCompatible(info);

            TextureScaleMode scaleMode = TextureScaleMode.Blacklisted;

            if (isScalable)
            {
                scaleMode = (flags & TextureSearchFlags.WithUpscale) != 0 ? TextureScaleMode.Scaled : TextureScaleMode.Eligible;
            }

            int sameAddressOverlapsCount;

            lock (_textures)
            {
                // Try to find a perfect texture match, with the same address and parameters.
                sameAddressOverlapsCount = _textures.FindOverlaps(info.Address, ref _textureOverlaps);
            }

            for (int index = 0; index < sameAddressOverlapsCount; index++)
            {
                Texture overlap = _textureOverlaps[index];

                if (overlap.IsPerfectMatch(info, flags))
                {
                    if (!isSamplerTexture)
                    {
                        // If not a sampler texture, it is managed by the auto delete
                        // cache, ensure that it is on the "top" of the list to avoid
                        // deletion.
                        _cache.Lift(overlap);
                    }
                    else if (!TextureCompatibility.SizeMatches(overlap.Info, info))
                    {
                        // If this is used for sampling, the size must match,
                        // otherwise the shader would sample garbage data.
                        // To fix that, we create a new texture with the correct
                        // size, and copy the data from the old one to the new one.
                        overlap.ChangeSize(info.Width, info.Height, info.DepthOrLayers);
                    }

                    overlap.SynchronizeMemory();

                    return(overlap);
                }
            }

            // Calculate texture sizes, used to find all overlapping textures.
            SizeInfo sizeInfo;

            if (info.Target == Target.TextureBuffer)
            {
                sizeInfo = new SizeInfo(info.Width * info.FormatInfo.BytesPerPixel);
            }
            else if (info.IsLinear)
            {
                sizeInfo = SizeCalculator.GetLinearTextureSize(
                    info.Stride,
                    info.Height,
                    info.FormatInfo.BlockHeight);
            }
            else
            {
                sizeInfo = SizeCalculator.GetBlockLinearTextureSize(
                    info.Width,
                    info.Height,
                    info.GetDepth(),
                    info.Levels,
                    info.GetLayers(),
                    info.FormatInfo.BlockWidth,
                    info.FormatInfo.BlockHeight,
                    info.FormatInfo.BytesPerPixel,
                    info.GobBlocksInY,
                    info.GobBlocksInZ,
                    info.GobBlocksInTileX);
            }

            // Find view compatible matches.
            ulong size = (ulong)sizeInfo.TotalSize;
            int   overlapsCount;

            lock (_textures)
            {
                overlapsCount = _textures.FindOverlaps(info.Address, size, ref _textureOverlaps);
            }

            Texture texture = null;

            for (int index = 0; index < overlapsCount; index++)
            {
                Texture overlap = _textureOverlaps[index];

                if (overlap.IsViewCompatible(info, size, out int firstLayer, out int firstLevel) == TextureViewCompatibility.Full)
                {
                    if (!isSamplerTexture)
                    {
                        info = AdjustSizes(overlap, info, firstLevel);
                    }

                    texture = overlap.CreateView(info, sizeInfo, firstLayer, firstLevel);

                    if (IsTextureModified(overlap))
                    {
                        texture.SignalModified();
                    }

                    // The size only matters (and is only really reliable) when the
                    // texture is used on a sampler, because otherwise the size will be
                    // aligned.
                    if (!TextureCompatibility.SizeMatches(overlap.Info, info, firstLevel) && isSamplerTexture)
                    {
                        texture.ChangeSize(info.Width, info.Height, info.DepthOrLayers);
                    }

                    break;
                }
            }

            // No match, create a new texture.
            if (texture == null)
            {
                texture = new Texture(_context, info, sizeInfo, scaleMode);

                // Step 1: Find textures that are view compatible with the new texture.
                // Any textures that are incompatible will contain garbage data, so they should be removed where possible.

                int  viewCompatible = 0;
                bool setData        = isSamplerTexture || overlapsCount == 0;

                for (int index = 0; index < overlapsCount; index++)
                {
                    Texture overlap        = _textureOverlaps[index];
                    bool    overlapInCache = overlap.CacheNode != null;

                    TextureViewCompatibility compatibility = texture.IsViewCompatible(overlap.Info, overlap.Size, out int firstLayer, out int firstLevel);

                    if (compatibility != TextureViewCompatibility.Incompatible)
                    {
                        if (_overlapInfo.Length != _textureOverlaps.Length)
                        {
                            Array.Resize(ref _overlapInfo, _textureOverlaps.Length);
                        }

                        _overlapInfo[viewCompatible]       = new OverlapInfo(compatibility, firstLayer, firstLevel);
                        _textureOverlaps[viewCompatible++] = overlap;
                    }
                    else if (overlapInCache || !setData)
                    {
                        if (info.GobBlocksInZ > 1 && info.GobBlocksInZ == overlap.Info.GobBlocksInZ)
                        {
                            // Allow overlapping slices of 3D textures. Could be improved in future by making sure the textures don't overlap.
                            continue;
                        }

                        // The overlap texture is going to contain garbage data after we draw, or is generally incompatible.
                        // If the texture cannot be entirely contained in the new address space, and one of its view children is compatible with us,
                        // it must be flushed before removal, so that the data is not lost.

                        // If the texture was modified since its last use, then that data is probably meant to go into this texture.
                        // If the data has been modified by the CPU, then it also shouldn't be flushed.
                        bool modified = overlap.ConsumeModified();

                        bool flush = overlapInCache && !modified && (overlap.Address <texture.Address || overlap.EndAddress> texture.EndAddress) && overlap.HasViewCompatibleChild(texture);

                        setData |= modified || flush;

                        if (overlapInCache)
                        {
                            _cache.Remove(overlap, flush);
                        }
                    }
                }

                // We need to synchronize before copying the old view data to the texture,
                // otherwise the copied data would be overwritten by a future synchronization.
                texture.InitializeData(false, setData);

                for (int index = 0; index < viewCompatible; index++)
                {
                    Texture     overlap = _textureOverlaps[index];
                    OverlapInfo oInfo   = _overlapInfo[index];

                    if (oInfo.Compatibility != TextureViewCompatibility.Full)
                    {
                        continue; // Copy only compatibilty.
                    }

                    TextureInfo overlapInfo = AdjustSizes(texture, overlap.Info, oInfo.FirstLevel);

                    TextureCreateInfo createInfo = GetCreateInfo(overlapInfo, _context.Capabilities);

                    if (texture.ScaleFactor != overlap.ScaleFactor)
                    {
                        // A bit tricky, our new texture may need to contain an existing texture that is upscaled, but isn't itself.
                        // In that case, we prefer the higher scale only if our format is render-target-like, otherwise we scale the view down before copy.

                        texture.PropagateScale(overlap);
                    }

                    ITexture newView = texture.HostTexture.CreateView(createInfo, oInfo.FirstLayer, oInfo.FirstLevel);

                    overlap.HostTexture.CopyTo(newView, 0, 0);

                    // Inherit modification from overlapping texture, do that before replacing
                    // the view since the replacement operation removes it from the list.
                    if (IsTextureModified(overlap))
                    {
                        texture.SignalModified();
                    }

                    overlap.ReplaceView(texture, overlapInfo, newView, oInfo.FirstLayer, oInfo.FirstLevel);
                }

                // If the texture is a 3D texture, we need to additionally copy any slice
                // of the 3D texture to the newly created 3D texture.
                if (info.Target == Target.Texture3D)
                {
                    for (int index = 0; index < viewCompatible; index++)
                    {
                        Texture     overlap = _textureOverlaps[index];
                        OverlapInfo oInfo   = _overlapInfo[index];

                        if (oInfo.Compatibility != TextureViewCompatibility.Incompatible)
                        {
                            overlap.BlacklistScale();

                            overlap.HostTexture.CopyTo(texture.HostTexture, oInfo.FirstLayer, oInfo.FirstLevel);

                            if (IsTextureModified(overlap))
                            {
                                texture.SignalModified();
                            }
                        }
                    }
                }
            }

            // Sampler textures are managed by the texture pool, all other textures
            // are managed by the auto delete cache.
            if (!isSamplerTexture)
            {
                _cache.Add(texture);
                texture.Modified += CacheTextureModified;
                texture.Disposed += CacheTextureDisposed;
            }

            lock (_textures)
            {
                _textures.Add(texture);
            }

            ShrinkOverlapsBufferIfNeeded();

            return(texture);
        }
Esempio n. 20
0
        /// <summary>
        /// Gets texture information from a texture descriptor.
        /// </summary>
        /// <param name="descriptor">The texture descriptor</param>
        /// <param name="layerSize">Layer size for textures using a sub-range of mipmap levels, otherwise 0</param>
        /// <returns>The texture information</returns>
        private TextureInfo GetInfo(TextureDescriptor descriptor, out int layerSize)
        {
            int width         = descriptor.UnpackWidth();
            int height        = descriptor.UnpackHeight();
            int depthOrLayers = descriptor.UnpackDepth();
            int levels        = descriptor.UnpackLevels();

            TextureMsaaMode msaaMode = descriptor.UnpackTextureMsaaMode();

            int samplesInX = msaaMode.SamplesInX();
            int samplesInY = msaaMode.SamplesInY();

            int stride = descriptor.UnpackStride();

            TextureDescriptorType descriptorType = descriptor.UnpackTextureDescriptorType();

            bool isLinear = descriptorType == TextureDescriptorType.Linear;

            Target target = descriptor.UnpackTextureTarget().Convert((samplesInX | samplesInY) != 1);

            // We use 2D targets for 1D textures as that makes texture cache
            // management easier. We don't know the target for render target
            // and copies, so those would normally use 2D targets, which are
            // not compatible with 1D targets. By doing that we also allow those
            // to match when looking for compatible textures on the cache.
            if (target == Target.Texture1D)
            {
                target = Target.Texture2D;
                height = 1;
            }
            else if (target == Target.Texture1DArray)
            {
                target = Target.Texture2DArray;
                height = 1;
            }

            uint format = descriptor.UnpackFormat();
            bool srgb   = descriptor.UnpackSrgb();

            ulong gpuVa = descriptor.UnpackAddress();

            if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo))
            {
                if (Context.MemoryManager.IsMapped(gpuVa) && (int)format > 0)
                {
                    Logger.Error?.Print(LogClass.Gpu, $"Invalid texture format 0x{format:X} (sRGB: {srgb}).");
                }

                formatInfo = FormatInfo.Default;
            }

            int gobBlocksInY = descriptor.UnpackGobBlocksInY();
            int gobBlocksInZ = descriptor.UnpackGobBlocksInZ();

            int gobBlocksInTileX = descriptor.UnpackGobBlocksInTileX();

            layerSize = 0;

            int minLod = descriptor.UnpackBaseLevel();
            int maxLod = descriptor.UnpackMaxLevelInclusive();

            // Linear textures don't support mipmaps, so we don't handle this case here.
            if ((minLod != 0 || maxLod + 1 != levels) && target != Target.TextureBuffer && !isLinear)
            {
                int depth  = TextureInfo.GetDepth(target, depthOrLayers);
                int layers = TextureInfo.GetLayers(target, depthOrLayers);

                SizeInfo sizeInfo = SizeCalculator.GetBlockLinearTextureSize(
                    width,
                    height,
                    depth,
                    levels,
                    layers,
                    formatInfo.BlockWidth,
                    formatInfo.BlockHeight,
                    formatInfo.BytesPerPixel,
                    gobBlocksInY,
                    gobBlocksInZ,
                    gobBlocksInTileX);

                layerSize = sizeInfo.LayerSize;

                if (minLod != 0 && minLod < levels)
                {
                    // If the base level is not zero, we additionally add the mip level offset
                    // to the address, this allows the texture manager to find the base level from the
                    // address if there is a overlapping texture on the cache that can contain the new texture.
                    gpuVa += (ulong)sizeInfo.GetMipOffset(minLod);

                    width  = Math.Max(1, width >> minLod);
                    height = Math.Max(1, height >> minLod);

                    if (target == Target.Texture3D)
                    {
                        depthOrLayers = Math.Max(1, depthOrLayers >> minLod);
                    }

                    (gobBlocksInY, gobBlocksInZ) = SizeCalculator.GetMipGobBlockSizes(height, depth, formatInfo.BlockHeight, gobBlocksInY, gobBlocksInZ);
                }

                levels = (maxLod - minLod) + 1;
            }

            SwizzleComponent swizzleR = descriptor.UnpackSwizzleR().Convert();
            SwizzleComponent swizzleG = descriptor.UnpackSwizzleG().Convert();
            SwizzleComponent swizzleB = descriptor.UnpackSwizzleB().Convert();
            SwizzleComponent swizzleA = descriptor.UnpackSwizzleA().Convert();

            DepthStencilMode depthStencilMode = GetDepthStencilMode(
                formatInfo.Format,
                swizzleR,
                swizzleG,
                swizzleB,
                swizzleA);

            if (formatInfo.Format.IsDepthOrStencil())
            {
                swizzleR = SwizzleComponent.Red;
                swizzleG = SwizzleComponent.Red;
                swizzleB = SwizzleComponent.Red;

                if (depthStencilMode == DepthStencilMode.Depth)
                {
                    swizzleA = SwizzleComponent.One;
                }
                else
                {
                    swizzleA = SwizzleComponent.Red;
                }
            }

            return(new TextureInfo(
                       gpuVa,
                       width,
                       height,
                       depthOrLayers,
                       levels,
                       samplesInX,
                       samplesInY,
                       stride,
                       isLinear,
                       gobBlocksInY,
                       gobBlocksInZ,
                       gobBlocksInTileX,
                       target,
                       formatInfo,
                       depthStencilMode,
                       swizzleR,
                       swizzleG,
                       swizzleB,
                       swizzleA));
        }