/// <summary> /// Implementation of the texture pool range invalidation. /// </summary> /// <param name="address">Start address of the range of the texture pool</param> /// <param name="size">Size of the range being invalidated</param> protected override void InvalidateRangeImpl(ulong address, ulong size) { ulong endAddress = address + size; for (; address < endAddress; address += DescriptorSize) { int id = (int)((address - Address) / DescriptorSize); Texture texture = Items[id]; if (texture != null) { TextureDescriptor descriptor = Context.PhysicalMemory.Read <TextureDescriptor>(address); // If the descriptors are the same, the texture is the same, // we don't need to remove as it was not modified. Just continue. if (texture.IsPerfectMatch(GetInfo(descriptor), TextureSearchFlags.Strict)) { continue; } texture.DecrementReferenceCount(); Items[id] = null; } } }
/// <summary> /// Gets the texture with the given ID. /// </summary> /// <param name="id">ID of the texture. This is effectively a zero-based index</param> /// <returns>The texture with the given ID</returns> public override Texture Get(int id) { if ((uint)id >= Items.Length) { return(null); } if (_sequenceNumber != Context.SequenceNumber) { _sequenceNumber = Context.SequenceNumber; SynchronizeMemory(); } Texture texture = Items[id]; if (texture == null) { TextureDescriptor descriptor = GetDescriptor(id); TextureInfo info = GetInfo(descriptor, out int layerSize); // Bad address. We can't add a texture with a invalid address // to the cache. if (info.Address == MemoryManager.PteUnmapped) { return(null); } texture = Context.Methods.TextureManager.FindOrCreateTexture(info, TextureSearchFlags.ForSampler, layerSize); texture.IncrementReferenceCount(); Items[id] = texture; } else { if (texture.ChangedSize) { // Texture changed size at one point - it may be a different size than the sampler expects. // This can be triggered when the size is changed by a size hint on copy or draw, but the texture has been sampled before. TextureDescriptor descriptor = GetDescriptor(id); int width = descriptor.UnpackWidth(); int height = descriptor.UnpackHeight(); if (texture.Info.Width != width || texture.Info.Height != height) { texture.ChangeSize(width, height, texture.Info.DepthOrLayers); } } // Memory is automatically synchronized on texture creation. texture.SynchronizeMemory(); } return(texture); }
/// <summary> /// Gets the texture with the given ID. /// </summary> /// <param name="id">ID of the texture. This is effectively a zero-based index</param> /// <returns>The texture with the given ID</returns> public override Texture Get(int id) { if ((uint)id >= Items.Length) { return(null); } if (_sequenceNumber != Context.SequenceNumber) { _sequenceNumber = Context.SequenceNumber; SynchronizeMemory(); } Texture texture = Items[id]; if (texture == null) { TextureDescriptor descriptor = GetDescriptor(id); TextureInfo info = GetInfo(descriptor); // Bad address. We can't add a texture with a invalid address // to the cache. if (info.Address == MemoryManager.BadAddress) { return(null); } texture = Context.Methods.TextureManager.FindOrCreateTexture(info, TextureSearchFlags.Sampler); texture.IncrementReferenceCount(); Items[id] = texture; } else { // Memory is automatically synchronized on texture creation. texture.SynchronizeMemory(); } return(texture); }
/// <summary> /// Gets texture information from a texture descriptor. /// </summary> /// <param name="descriptor">The texture descriptor</param> /// <returns>The texture information</returns> private TextureInfo GetInfo(TextureDescriptor descriptor) { ulong address = Context.MemoryManager.Translate(descriptor.UnpackAddress()); 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); uint format = descriptor.UnpackFormat(); bool srgb = descriptor.UnpackSrgb(); if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo)) { if ((long)address > 0L && (int)format > 0) { Logger.PrintError(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(); 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 (IsDepthStencil(formatInfo.Format)) { swizzleR = SwizzleComponent.Red; swizzleG = SwizzleComponent.Red; swizzleB = SwizzleComponent.Red; if (depthStencilMode == DepthStencilMode.Depth) { swizzleA = SwizzleComponent.One; } else { swizzleA = SwizzleComponent.Red; } } return(new TextureInfo( address, width, height, depthOrLayers, levels, samplesInX, samplesInY, stride, isLinear, gobBlocksInY, gobBlocksInZ, gobBlocksInTileX, target, formatInfo, depthStencilMode, swizzleR, swizzleG, swizzleB, swizzleA)); }
/// <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) { ulong address = Context.MemoryManager.Translate(descriptor.UnpackAddress()); bool addressIsValid = address != MemoryManager.PteUnmapped; 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(); if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo)) { if (addressIsValid && (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 && addressIsValid) { 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) { // 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. address += (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( address, width, height, depthOrLayers, levels, samplesInX, samplesInY, stride, isLinear, gobBlocksInY, gobBlocksInZ, gobBlocksInTileX, target, formatInfo, depthStencilMode, swizzleR, swizzleG, swizzleB, swizzleA)); }
/// <summary> /// Check if two descriptors are equal. /// </summary> /// <param name="other">The descriptor to compare against</param> /// <returns>True if they are equal, false otherwise</returns> public bool Equals(ref TextureDescriptor other) { return(Unsafe.As <TextureDescriptor, Vector256 <byte> >(ref this).Equals(Unsafe.As <TextureDescriptor, Vector256 <byte> >(ref other))); }
/// <summary> /// Gets texture information from a texture descriptor. /// </summary> /// <param name="descriptor">The texture descriptor</param> /// <returns>The texture information</returns> private TextureInfo GetInfo(TextureDescriptor descriptor) { ulong address = Context.MemoryManager.Translate(descriptor.UnpackAddress()); 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(); if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo)) { if ((long)address > 0L && (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(); 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( address, width, height, depthOrLayers, levels, samplesInX, samplesInY, stride, isLinear, gobBlocksInY, gobBlocksInZ, gobBlocksInTileX, target, formatInfo, depthStencilMode, swizzleR, swizzleG, swizzleB, swizzleA)); }