Example #1
0
        /// <summary>
        /// Tries to find an existing texture, or create a new one if not found.
        /// </summary>
        /// <param name="colorState">Color buffer texture to find or create</param>
        /// <param name="samplesInX">Number of samples in the X direction, for MSAA</param>
        /// <param name="samplesInY">Number of samples in the Y direction, for MSAA</param>
        /// <returns>The texture</returns>
        public Texture FindOrCreateTexture(RtColorState colorState, int samplesInX, int samplesInY)
        {
            ulong address = _context.MemoryManager.Translate(colorState.Address.Pack());

            if (address == MemoryManager.BadAddress)
            {
                return(null);
            }

            bool isLinear = colorState.MemoryLayout.UnpackIsLinear();

            int gobBlocksInY = colorState.MemoryLayout.UnpackGobBlocksInY();
            int gobBlocksInZ = colorState.MemoryLayout.UnpackGobBlocksInZ();

            Target target;

            if (colorState.MemoryLayout.UnpackIsTarget3D())
            {
                target = Target.Texture3D;
            }
            else if ((samplesInX | samplesInY) != 1)
            {
                target = colorState.Depth > 1
                    ? Target.Texture2DMultisampleArray
                    : Target.Texture2DMultisample;
            }
            else
            {
                target = colorState.Depth > 1
                    ? Target.Texture2DArray
                    : Target.Texture2D;
            }

            FormatInfo formatInfo = colorState.Format.Convert();

            int width, stride;

            // For linear textures, the width value is actually the stride.
            // We can easily get the width by dividing the stride by the bpp,
            // since the stride is the total number of bytes occupied by a
            // line. The stride should also meet alignment constraints however,
            // so the width we get here is the aligned width.
            if (isLinear)
            {
                width  = colorState.WidthOrStride / formatInfo.BytesPerPixel;
                stride = colorState.WidthOrStride;
            }
            else
            {
                width  = colorState.WidthOrStride;
                stride = 0;
            }

            TextureInfo info = new TextureInfo(
                address,
                width,
                colorState.Height,
                colorState.Depth,
                1,
                samplesInX,
                samplesInY,
                stride,
                isLinear,
                gobBlocksInY,
                gobBlocksInZ,
                1,
                target,
                formatInfo);

            Texture texture = FindOrCreateTexture(info, TextureSearchFlags.WithUpscale);

            texture.SynchronizeMemory();

            return(texture);
        }
Example #2
0
        /// <summary>
        /// Gets a texture creation information from texture information.
        /// This can be used to create new host textures.
        /// </summary>
        /// <param name="info">Texture information</param>
        /// <param name="caps">GPU capabilities</param>
        /// <param name="scale">Texture scale factor, to be applied to the texture size</param>
        /// <returns>The texture creation information</returns>
        public static TextureCreateInfo GetCreateInfo(TextureInfo info, Capabilities caps, float scale)
        {
            FormatInfo formatInfo = TextureCompatibility.ToHostCompatibleFormat(info, caps);

            if (info.Target == Target.TextureBuffer)
            {
                // We assume that the host does not support signed normalized format
                // (as is the case with OpenGL), so we just use a unsigned format.
                // The shader will need the appropriate conversion code to compensate.
                switch (formatInfo.Format)
                {
                case Format.R8Snorm:
                    formatInfo = new FormatInfo(Format.R8Sint, 1, 1, 1, 1);
                    break;

                case Format.R16Snorm:
                    formatInfo = new FormatInfo(Format.R16Sint, 1, 1, 2, 1);
                    break;

                case Format.R8G8Snorm:
                    formatInfo = new FormatInfo(Format.R8G8Sint, 1, 1, 2, 2);
                    break;

                case Format.R16G16Snorm:
                    formatInfo = new FormatInfo(Format.R16G16Sint, 1, 1, 4, 2);
                    break;

                case Format.R8G8B8A8Snorm:
                    formatInfo = new FormatInfo(Format.R8G8B8A8Sint, 1, 1, 4, 4);
                    break;

                case Format.R16G16B16A16Snorm:
                    formatInfo = new FormatInfo(Format.R16G16B16A16Sint, 1, 1, 8, 4);
                    break;
                }
            }

            int width  = info.Width / info.SamplesInX;
            int height = info.Height / info.SamplesInY;

            int depth = info.GetDepth() * info.GetLayers();

            if (scale != 1f)
            {
                width  = (int)MathF.Ceiling(width * scale);
                height = (int)MathF.Ceiling(height * scale);
            }

            return(new TextureCreateInfo(
                       width,
                       height,
                       depth,
                       info.Levels,
                       info.Samples,
                       formatInfo.BlockWidth,
                       formatInfo.BlockHeight,
                       formatInfo.BytesPerPixel,
                       formatInfo.Format,
                       info.DepthStencilMode,
                       info.Target,
                       info.SwizzleR,
                       info.SwizzleG,
                       info.SwizzleB,
                       info.SwizzleA));
        }
Example #3
0
        /// <summary>
        /// Try getting the texture format from an encoded format integer from the Maxwell texture descriptor.
        /// </summary>
        /// <param name="encoded">The encoded format integer from the texture descriptor</param>
        /// <param name="isSrgb">Indicates if the format is a sRGB format</param>
        /// <param name="format">The output texture format</param>
        /// <returns>True if the format is valid, false otherwise</returns>
        public static bool TryGetTextureFormat(uint encoded, bool isSrgb, out FormatInfo format)
        {
            encoded |= (isSrgb ? 1u << 19 : 0u);

            return(_textureFormats.TryGetValue(encoded, out format));
        }
Example #4
0
        /// <summary>
        /// Tries to find an existing texture matching the given buffer copy destination. If none is found, returns null.
        /// </summary>
        /// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
        /// <param name="tex">The texture information</param>
        /// <param name="gpuVa">GPU virtual address of the texture</param>
        /// <param name="bpp">Bytes per pixel</param>
        /// <param name="stride">If <paramref name="linear"/> is true, should have the texture stride, otherwise ignored</param>
        /// <param name="xCount">Number of pixels to be copied per line</param>
        /// <param name="yCount">Number of lines to be copied</param>
        /// <param name="linear">True if the texture has a linear layout, false otherwise</param>
        /// <returns>A matching texture, or null if there is no match</returns>
        public Texture FindTexture(
            MemoryManager memoryManager,
            DmaTexture tex,
            ulong gpuVa,
            int bpp,
            int stride,
            int xCount,
            int yCount,
            bool linear)
        {
            ulong address = memoryManager.Translate(gpuVa);

            if (address == MemoryManager.PteUnmapped)
            {
                return(null);
            }

            int     addressMatches = _textures.FindOverlaps(address, ref _textureOverlaps);
            Texture textureMatch   = null;

            for (int i = 0; i < addressMatches; i++)
            {
                Texture    texture = _textureOverlaps[i];
                FormatInfo format  = texture.Info.FormatInfo;

                if (texture.Info.DepthOrLayers > 1 || texture.Info.Levels > 1 || texture.Info.FormatInfo.IsCompressed)
                {
                    // Don't support direct buffer copies to anything that isn't a single 2D image, uncompressed.
                    continue;
                }

                bool match;

                if (linear)
                {
                    // Size is not available for linear textures. Use the stride and end of the copy region instead.

                    match = texture.Info.IsLinear && texture.Info.Stride == stride && tex.RegionY + yCount <= texture.Info.Height;
                }
                else
                {
                    // Bpp may be a mismatch between the target texture and the param.
                    // Due to the way linear strided and block layouts work, widths can be multiplied by Bpp for comparison.
                    // Note: tex.Width is the aligned texture size. Prefer param.XCount, as the destination should be a texture with that exact size.

                    bool sizeMatch   = xCount * bpp == texture.Info.Width * format.BytesPerPixel && tex.Height == texture.Info.Height;
                    bool formatMatch = !texture.Info.IsLinear &&
                                       texture.Info.GobBlocksInY == tex.MemoryLayout.UnpackGobBlocksInY() &&
                                       texture.Info.GobBlocksInZ == tex.MemoryLayout.UnpackGobBlocksInZ();

                    match = sizeMatch && formatMatch;
                }

                if (match)
                {
                    if (textureMatch == null)
                    {
                        textureMatch = texture;
                    }
                    else if (texture.Group != textureMatch.Group)
                    {
                        return(null); // It's ambiguous which texture should match between multiple choices, so leave it up to the slow path.
                    }
                }
            }

            return(textureMatch);
        }