Пример #1
0
        /// <summary>
        /// Determines if data is compatible between the source and destination texture.
        /// The two textures must have the same size, layout, and bytes per pixel.
        /// </summary>
        /// <param name="lhs">Info for the first texture</param>
        /// <param name="rhs">Info for the second texture</param>
        /// <param name="lhsFormat">Format of the first texture</param>
        /// <param name="rhsFormat">Format of the second texture</param>
        /// <returns>True if the data is compatible, false otherwise</returns>
        private bool IsDataCompatible(TwodTexture lhs, TwodTexture rhs, FormatInfo lhsFormat, FormatInfo rhsFormat)
        {
            if (lhsFormat.BytesPerPixel != rhsFormat.BytesPerPixel ||
                lhs.Height != rhs.Height ||
                lhs.Depth != rhs.Depth ||
                lhs.LinearLayout != rhs.LinearLayout ||
                lhs.MemoryLayout.Packed != rhs.MemoryLayout.Packed)
            {
                return(false);
            }

            if (lhs.LinearLayout)
            {
                return(lhs.Stride == rhs.Stride);
            }
            else
            {
                return(lhs.Width == rhs.Width);
            }
        }
Пример #2
0
        /// <summary>
        /// Determine if the given region covers the full texture, also considering width alignment.
        /// </summary>
        /// <param name="texture">The texture to check</param>
        /// <param name="formatInfo"></param>
        /// <param name="x1">Region start x</param>
        /// <param name="y1">Region start y</param>
        /// <param name="x2">Region end x</param>
        /// <param name="y2">Region end y</param>
        /// <returns>True if the region covers the full texture, false otherwise</returns>
        private bool IsCopyRegionComplete(TwodTexture texture, FormatInfo formatInfo, int x1, int y1, int x2, int y2)
        {
            if (x1 != 0 || y1 != 0 || y2 != texture.Height)
            {
                return(false);
            }

            int width;
            int widthAlignment;

            if (texture.LinearLayout)
            {
                widthAlignment = 1;
                width          = texture.Stride / formatInfo.BytesPerPixel;
            }
            else
            {
                widthAlignment = Constants.GobAlignment / formatInfo.BytesPerPixel;
                width          = texture.Width;
            }

            return(width == BitUtils.AlignUp(x2, widthAlignment));
        }
Пример #3
0
        /// <summary>
        /// Performs a full data copy between two textures, reading and writing guest memory directly.
        /// The textures must have a matching layout, size, and bytes per pixel.
        /// </summary>
        /// <param name="src">The source texture</param>
        /// <param name="dst">The destination texture</param>
        /// <param name="w">Copy width</param>
        /// <param name="h">Copy height</param>
        /// <param name="bpp">Bytes per pixel</param>
        private void UnscaledFullCopy(TwodTexture src, TwodTexture dst, int w, int h, int bpp)
        {
            var srcCalculator = new OffsetCalculator(
                w,
                h,
                src.Stride,
                src.LinearLayout,
                src.MemoryLayout.UnpackGobBlocksInY(),
                src.MemoryLayout.UnpackGobBlocksInZ(),
                bpp);

            (int _, int srcSize) = srcCalculator.GetRectangleRange(0, 0, w, h);

            var memoryManager = _channel.MemoryManager;

            ulong srcGpuVa = src.Address.Pack();
            ulong dstGpuVa = dst.Address.Pack();

            ReadOnlySpan <byte> srcSpan = memoryManager.GetSpan(srcGpuVa, srcSize, true);

            int width;
            int height = src.Height;

            if (src.LinearLayout)
            {
                width = src.Stride / bpp;
            }
            else
            {
                width = src.Width;
            }

            // If the copy is not equal to the width and height of the texture, we will need to copy partially.
            // It's worth noting that it has already been established that the src and dst are the same size.

            if (w == width && h == height)
            {
                memoryManager.Write(dstGpuVa, srcSpan);
            }
            else
            {
                using WritableRegion dstRegion = memoryManager.GetWritableRegion(dstGpuVa, srcSize, true);
                Span <byte> dstSpan = dstRegion.Memory.Span;

                if (src.LinearLayout)
                {
                    int stride   = src.Stride;
                    int offset   = 0;
                    int lineSize = width * bpp;

                    for (int y = 0; y < height; y++)
                    {
                        srcSpan.Slice(offset, lineSize).CopyTo(dstSpan.Slice(offset));

                        offset += stride;
                    }
                }
                else
                {
                    // Copy with the block linear layout in mind.
                    // Recreate the offset calculate with bpp 1 for copy.

                    int stride = w * bpp;

                    srcCalculator = new OffsetCalculator(
                        stride,
                        h,
                        0,
                        false,
                        src.MemoryLayout.UnpackGobBlocksInY(),
                        src.MemoryLayout.UnpackGobBlocksInZ(),
                        1);

                    int strideTrunc = BitUtils.AlignDown(stride, 16);

                    ReadOnlySpan <Vector128 <byte> > srcVec = MemoryMarshal.Cast <byte, Vector128 <byte> >(srcSpan);
                    Span <Vector128 <byte> >         dstVec = MemoryMarshal.Cast <byte, Vector128 <byte> >(dstSpan);

                    for (int y = 0; y < h; y++)
                    {
                        int x = 0;

                        srcCalculator.SetY(y);

                        for (; x < strideTrunc; x += 16)
                        {
                            int offset = srcCalculator.GetOffset(x) >> 4;

                            dstVec[offset] = srcVec[offset];
                        }

                        for (; x < stride; x++)
                        {
                            int offset = srcCalculator.GetOffset(x);

                            dstSpan[offset] = srcSpan[offset];
                        }
                    }
                }
            }
        }