/// <summary> /// Sets the Scale Factor on this texture, and immediately recreates it at the correct size. /// When a texture is resized, a scaled copy is performed from the old texture to the new one, to ensure no data is lost. /// If scale is equivalent, this only propagates the blacklisted/scaled mode. /// If called on a view, its storage is resized instead. /// When resizing storage, all texture views are recreated. /// </summary> /// <param name="scale">The new scale factor for this texture</param> public void SetScale(float scale) { TextureScaleMode newScaleMode = ScaleMode == TextureScaleMode.Blacklisted ? ScaleMode : TextureScaleMode.Scaled; if (_viewStorage != this) { _viewStorage.ScaleMode = newScaleMode; _viewStorage.SetScale(scale); return; } if (ScaleFactor != scale) { Logger.Debug?.Print(LogClass.Gpu, $"Rescaling {Info.Width}x{Info.Height} {Info.FormatInfo.Format.ToString()} to ({ScaleFactor} to {scale}). "); ScaleFactor = scale; ITexture newStorage = GetScaledHostTexture(ScaleFactor); Logger.Debug?.Print(LogClass.Gpu, $" Copy performed: {HostTexture.Width}x{HostTexture.Height} to {newStorage.Width}x{newStorage.Height}"); ReplaceStorage(newStorage); // All views must be recreated against the new storage. foreach (var view in _views) { Logger.Debug?.Print(LogClass.Gpu, $" Recreating view {Info.Width}x{Info.Height} {Info.FormatInfo.Format.ToString()}."); view.ScaleFactor = scale; TextureCreateInfo viewCreateInfo = TextureManager.GetCreateInfo(view.Info, _context.Capabilities, scale); ITexture newView = HostTexture.CreateView(viewCreateInfo, view._firstLayer - _firstLayer, view._firstLevel - _firstLevel); view.ReplaceStorage(newView); view.ScaleMode = newScaleMode; } } if (ScaleMode != newScaleMode) { ScaleMode = newScaleMode; foreach (var view in _views) { view.ScaleMode = newScaleMode; } } }
/// <summary> /// Propagates the scale between this texture and another to ensure they have the same scale. /// If one texture is blacklisted from scaling, the other will become blacklisted too. /// </summary> /// <param name="other">The other texture</param> public void PropagateScale(Texture other) { if (other.ScaleMode == TextureScaleMode.Blacklisted || ScaleMode == TextureScaleMode.Blacklisted) { BlacklistScale(); other.BlacklistScale(); } else { // Prefer the configured scale if present. If not, prefer the max. float targetScale = GraphicsConfig.ResScale; float sharedScale = (ScaleFactor == targetScale || other.ScaleFactor == targetScale) ? targetScale : Math.Max(ScaleFactor, other.ScaleFactor); SetScale(sharedScale); other.SetScale(sharedScale); } }
/// <summary> /// Updates the Render Target scale, given the currently bound render targets. /// This will update scale to match the configured scale, scale textures that are eligible but not scaled, /// and propagate blacklisted status from one texture to the ones bound with it. /// </summary> /// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param> public void UpdateRenderTargetScale(int singleUse) { // Make sure all scales for render targets are at the highest they should be. Blacklisted targets should propagate their scale to the other targets. bool mismatch = false; bool blacklisted = false; bool hasUpscaled = false; float targetScale = GraphicsConfig.ResScale; void ConsiderTarget(Texture target) { if (target == null) { return; } float scale = target.ScaleFactor; switch (target.ScaleMode) { case TextureScaleMode.Blacklisted: mismatch |= scale != 1f; blacklisted = true; break; case TextureScaleMode.Eligible: mismatch = true; // We must make a decision. break; case TextureScaleMode.Scaled: hasUpscaled = true; mismatch |= scale != targetScale; // If the target scale has changed, reset the scale for all targets. break; } } if (singleUse != -1) { // If only one target is in use (by a clear, for example) the others do not need to be checked for mismatching scale. ConsiderTarget(_rtColors[singleUse]); } else { foreach (Texture color in _rtColors) { ConsiderTarget(color); } } ConsiderTarget(_rtDepthStencil); mismatch |= blacklisted && hasUpscaled; if (blacklisted) { targetScale = 1f; } if (mismatch) { if (blacklisted) { // Propagate the blacklisted state to the other textures. foreach (Texture color in _rtColors) { color?.BlacklistScale(); } _rtDepthStencil?.BlacklistScale(); } else { // Set the scale of the other textures. foreach (Texture color in _rtColors) { color?.SetScale(targetScale); } _rtDepthStencil?.SetScale(targetScale); } } RenderTargetScale = targetScale; }