Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
595e514f18 | |||
07435ad844 |
@ -35,7 +35,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
queue,
|
queue,
|
||||||
queueLock,
|
queueLock,
|
||||||
_gd.QueueFamilyIndex,
|
_gd.QueueFamilyIndex,
|
||||||
_gd.IsConcurrentFenceWaitUnsupported,
|
_gd.IsQualcommProprietary,
|
||||||
isLight: true);
|
isLight: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1021,7 +1021,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_newState.RasterizerDiscardEnable = discard;
|
_newState.RasterizerDiscardEnable = discard;
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
|
|
||||||
if (!discard && Gd.Vendor == Vendor.Qualcomm)
|
if (!discard && Gd.IsQualcommProprietary)
|
||||||
{
|
{
|
||||||
// On Adreno, enabling rasterizer discard somehow corrupts the viewport state.
|
// On Adreno, enabling rasterizer discard somehow corrupts the viewport state.
|
||||||
// Force it to be updated on next use to work around this bug.
|
// Force it to be updated on next use to work around this bug.
|
||||||
|
@ -47,10 +47,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (componentMask != 0xf)
|
if (componentMask != 0xf || Gd.IsQualcommProprietary)
|
||||||
{
|
{
|
||||||
// We can't use CmdClearAttachments if not writing all components,
|
// We can't use CmdClearAttachments if not writing all components,
|
||||||
// because on Vulkan, the pipeline state does not affect clears.
|
// because on Vulkan, the pipeline state does not affect clears.
|
||||||
|
// On proprietary Adreno drivers, CmdClearAttachments appears to execute out of order, so it's better to not use it at all.
|
||||||
var dstTexture = FramebufferParams.GetColorView(index);
|
var dstTexture = FramebufferParams.GetColorView(index);
|
||||||
if (dstTexture == null)
|
if (dstTexture == null)
|
||||||
{
|
{
|
||||||
@ -87,10 +88,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stencilMask != 0 && stencilMask != 0xff)
|
if ((stencilMask != 0 && stencilMask != 0xff) || Gd.IsQualcommProprietary)
|
||||||
{
|
{
|
||||||
// We can't use CmdClearAttachments if not clearing all (mask is all ones, 0xFF) or none (mask is 0) of the stencil bits,
|
// We can't use CmdClearAttachments if not clearing all (mask is all ones, 0xFF) or none (mask is 0) of the stencil bits,
|
||||||
// because on Vulkan, the pipeline state does not affect clears.
|
// because on Vulkan, the pipeline state does not affect clears.
|
||||||
|
// On proprietary Adreno drivers, CmdClearAttachments appears to execute out of order, so it's better to not use it at all.
|
||||||
var dstTexture = FramebufferParams.GetDepthStencilView();
|
var dstTexture = FramebufferParams.GetDepthStencilView();
|
||||||
if (dstTexture == null)
|
if (dstTexture == null)
|
||||||
{
|
{
|
||||||
|
@ -133,7 +133,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Templates = BuildTemplates(usePushDescriptors);
|
Templates = BuildTemplates(usePushDescriptors);
|
||||||
|
|
||||||
// Updating buffer texture bindings using template updates crashes the Adreno driver on Windows.
|
// Updating buffer texture bindings using template updates crashes the Adreno driver on Windows.
|
||||||
UpdateTexturesWithoutTemplate = gd.Vendor == Vendor.Qualcomm && usesBufferTextures;
|
UpdateTexturesWithoutTemplate = gd.IsQualcommProprietary && usesBufferTextures;
|
||||||
|
|
||||||
_compileTask = Task.CompletedTask;
|
_compileTask = Task.CompletedTask;
|
||||||
_firstBackgroundUse = false;
|
_firstBackgroundUse = false;
|
||||||
|
@ -87,10 +87,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
internal bool IsAmdGcn { get; private set; }
|
internal bool IsAmdGcn { get; private set; }
|
||||||
internal bool IsNvidiaPreTuring { get; private set; }
|
internal bool IsNvidiaPreTuring { get; private set; }
|
||||||
internal bool IsIntelArc { get; private set; }
|
internal bool IsIntelArc { get; private set; }
|
||||||
|
internal bool IsQualcommProprietary { get; private set; }
|
||||||
internal bool IsMoltenVk { get; private set; }
|
internal bool IsMoltenVk { get; private set; }
|
||||||
internal bool IsTBDR { get; private set; }
|
internal bool IsTBDR { get; private set; }
|
||||||
internal bool IsSharedMemory { get; private set; }
|
internal bool IsSharedMemory { get; private set; }
|
||||||
internal bool IsConcurrentFenceWaitUnsupported { get; private set; }
|
|
||||||
|
|
||||||
public string GpuVendor { get; private set; }
|
public string GpuVendor { get; private set; }
|
||||||
public string GpuDriver { get; private set; }
|
public string GpuDriver { get; private set; }
|
||||||
@ -325,8 +325,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Vendor == Vendor.Broadcom ||
|
Vendor == Vendor.Broadcom ||
|
||||||
Vendor == Vendor.ImgTec;
|
Vendor == Vendor.ImgTec;
|
||||||
|
|
||||||
IsConcurrentFenceWaitUnsupported = Vendor == Vendor.Qualcomm;
|
|
||||||
|
|
||||||
GpuVendor = VendorUtils.GetNameFromId(properties.VendorID);
|
GpuVendor = VendorUtils.GetNameFromId(properties.VendorID);
|
||||||
GpuDriver = hasDriverProperties && !OperatingSystem.IsMacOS() ?
|
GpuDriver = hasDriverProperties && !OperatingSystem.IsMacOS() ?
|
||||||
VendorUtils.GetFriendlyDriverName(driverProperties.DriverID) : GpuVendor; // Fallback to vendor name if driver is unavailable or on MacOS where vendor is preferred.
|
VendorUtils.GetFriendlyDriverName(driverProperties.DriverID) : GpuVendor; // Fallback to vendor name if driver is unavailable or on MacOS where vendor is preferred.
|
||||||
@ -348,7 +346,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
IsNvidiaPreTuring = gpuNumber < 2000;
|
IsNvidiaPreTuring = gpuNumber < 2000;
|
||||||
}
|
}
|
||||||
else if (GpuDriver.Contains("TITAN") && !GpuDriver.Contains("RTX"))
|
else if (GpuRenderer.Contains("TITAN") && !GpuRenderer.Contains("RTX"))
|
||||||
{
|
{
|
||||||
IsNvidiaPreTuring = true;
|
IsNvidiaPreTuring = true;
|
||||||
}
|
}
|
||||||
@ -358,6 +356,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
IsIntelArc = GpuRenderer.StartsWith("Intel(R) Arc(TM)");
|
IsIntelArc = GpuRenderer.StartsWith("Intel(R) Arc(TM)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IsQualcommProprietary = hasDriverProperties && driverProperties.DriverID == DriverId.QualcommProprietary;
|
||||||
|
|
||||||
ulong minResourceAlignment = Math.Max(
|
ulong minResourceAlignment = Math.Max(
|
||||||
Math.Max(
|
Math.Max(
|
||||||
properties.Limits.MinStorageBufferOffsetAlignment,
|
properties.Limits.MinStorageBufferOffsetAlignment,
|
||||||
@ -415,7 +415,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtExternalMemoryHost hostMemoryApi);
|
Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtExternalMemoryHost hostMemoryApi);
|
||||||
HostMemoryAllocator = new HostMemoryAllocator(MemoryAllocator, Api, hostMemoryApi, _device);
|
HostMemoryAllocator = new HostMemoryAllocator(MemoryAllocator, Api, hostMemoryApi, _device);
|
||||||
|
|
||||||
CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex, IsConcurrentFenceWaitUnsupported);
|
CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex, IsQualcommProprietary);
|
||||||
|
|
||||||
PipelineLayoutCache = new PipelineLayoutCache();
|
PipelineLayoutCache = new PipelineLayoutCache();
|
||||||
|
|
||||||
@ -692,7 +692,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
GpuVendor,
|
GpuVendor,
|
||||||
memoryType: memoryType,
|
memoryType: memoryType,
|
||||||
hasFrontFacingBug: IsIntelWindows,
|
hasFrontFacingBug: IsIntelWindows,
|
||||||
hasVectorIndexingBug: Vendor == Vendor.Qualcomm,
|
hasVectorIndexingBug: IsQualcommProprietary,
|
||||||
needsFragmentOutputSpecialization: IsMoltenVk,
|
needsFragmentOutputSpecialization: IsMoltenVk,
|
||||||
reduceShaderPrecision: IsMoltenVk,
|
reduceShaderPrecision: IsMoltenVk,
|
||||||
supportsAstcCompression: features2.Features.TextureCompressionAstcLdr && supportsAstcFormats,
|
supportsAstcCompression: features2.Features.TextureCompressionAstcLdr && supportsAstcFormats,
|
||||||
|
@ -40,20 +40,17 @@ using Ryujinx.UI.Common;
|
|||||||
using Ryujinx.UI.Common.Configuration;
|
using Ryujinx.UI.Common.Configuration;
|
||||||
using Ryujinx.UI.Common.Helper;
|
using Ryujinx.UI.Common.Helper;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using SixLabors.ImageSharp;
|
using SkiaSharp;
|
||||||
using SixLabors.ImageSharp.Formats.Png;
|
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
|
||||||
using SixLabors.ImageSharp.Processing;
|
|
||||||
using SPB.Graphics.Vulkan;
|
using SPB.Graphics.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop;
|
using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop;
|
||||||
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
||||||
using Image = SixLabors.ImageSharp.Image;
|
|
||||||
using InputManager = Ryujinx.Input.HLE.InputManager;
|
using InputManager = Ryujinx.Input.HLE.InputManager;
|
||||||
using IRenderer = Ryujinx.Graphics.GAL.IRenderer;
|
using IRenderer = Ryujinx.Graphics.GAL.IRenderer;
|
||||||
using Key = Ryujinx.Input.Key;
|
using Key = Ryujinx.Input.Key;
|
||||||
@ -366,25 +363,33 @@ namespace Ryujinx.Ava
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Image image = e.IsBgra ? Image.LoadPixelData<Bgra32>(e.Data, e.Width, e.Height)
|
var colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888;
|
||||||
: Image.LoadPixelData<Rgba32>(e.Data, e.Width, e.Height);
|
using var bitmap = new SKBitmap(new SKImageInfo(e.Width, e.Height, colorType, SKAlphaType.Premul));
|
||||||
|
|
||||||
if (e.FlipX)
|
Marshal.Copy(e.Data, 0, bitmap.GetPixels(), e.Data.Length);
|
||||||
|
|
||||||
|
SKBitmap bitmapToSave = null;
|
||||||
|
|
||||||
|
if (e.FlipX || e.FlipY)
|
||||||
{
|
{
|
||||||
image.Mutate(x => x.Flip(FlipMode.Horizontal));
|
bitmapToSave = new SKBitmap(bitmap.Width, bitmap.Height);
|
||||||
|
|
||||||
|
using var canvas = new SKCanvas(bitmapToSave);
|
||||||
|
|
||||||
|
canvas.Clear(SKColors.Transparent);
|
||||||
|
|
||||||
|
float scaleX = e.FlipX ? -1 : 1;
|
||||||
|
float scaleY = e.FlipY ? -1 : 1;
|
||||||
|
|
||||||
|
var matrix = SKMatrix.CreateScale(scaleX, scaleY, bitmap.Width / 2f, bitmap.Height / 2f);
|
||||||
|
|
||||||
|
canvas.SetMatrix(matrix);
|
||||||
|
|
||||||
|
canvas.DrawBitmap(bitmap, new SKPoint(e.FlipX ? -bitmap.Width : 0, e.FlipY ? -bitmap.Height : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.FlipY)
|
SaveBitmapAsPng(bitmapToSave ?? bitmap, path);
|
||||||
{
|
bitmapToSave?.Dispose();
|
||||||
image.Mutate(x => x.Flip(FlipMode.Vertical));
|
|
||||||
}
|
|
||||||
|
|
||||||
image.SaveAsPng(path, new PngEncoder
|
|
||||||
{
|
|
||||||
ColorType = PngColorType.Rgb,
|
|
||||||
});
|
|
||||||
|
|
||||||
image.Dispose();
|
|
||||||
|
|
||||||
Logger.Notice.Print(LogClass.Application, $"Screenshot saved to {path}", "Screenshot");
|
Logger.Notice.Print(LogClass.Application, $"Screenshot saved to {path}", "Screenshot");
|
||||||
}
|
}
|
||||||
@ -396,6 +401,14 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SaveBitmapAsPng(SKBitmap bitmap, string path)
|
||||||
|
{
|
||||||
|
using var data = bitmap.Encode(SKEncodedImageFormat.Png, 100);
|
||||||
|
using var stream = File.OpenWrite(path);
|
||||||
|
|
||||||
|
data.SaveTo(stream);
|
||||||
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
|
@ -54,7 +54,6 @@
|
|||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
|
||||||
<PackageReference Include="SPB" />
|
<PackageReference Include="SPB" />
|
||||||
<PackageReference Include="SharpZipLib" />
|
<PackageReference Include="SharpZipLib" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -32,7 +32,7 @@ using Ryujinx.UI.App.Common;
|
|||||||
using Ryujinx.UI.Common;
|
using Ryujinx.UI.Common;
|
||||||
using Ryujinx.UI.Common.Configuration;
|
using Ryujinx.UI.Common.Configuration;
|
||||||
using Ryujinx.UI.Common.Helper;
|
using Ryujinx.UI.Common.Helper;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SkiaSharp;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
@ -40,7 +40,6 @@ using System.Globalization;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Image = SixLabors.ImageSharp.Image;
|
|
||||||
using Key = Ryujinx.Input.Key;
|
using Key = Ryujinx.Input.Key;
|
||||||
using MissingKeyException = LibHac.Common.Keys.MissingKeyException;
|
using MissingKeyException = LibHac.Common.Keys.MissingKeyException;
|
||||||
using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
|
using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
|
||||||
@ -1164,17 +1163,17 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
private void PrepareLoadScreen()
|
private void PrepareLoadScreen()
|
||||||
{
|
{
|
||||||
using MemoryStream stream = new(SelectedIcon);
|
using MemoryStream stream = new(SelectedIcon);
|
||||||
using var gameIconBmp = Image.Load<Bgra32>(stream);
|
using var gameIconBmp = SKBitmap.Decode(stream);
|
||||||
|
|
||||||
var dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp).ToPixel<Bgra32>();
|
var dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp);
|
||||||
|
|
||||||
const float ColorMultiple = 0.5f;
|
const float ColorMultiple = 0.5f;
|
||||||
|
|
||||||
Color progressFgColor = Color.FromRgb(dominantColor.R, dominantColor.G, dominantColor.B);
|
Color progressFgColor = Color.FromRgb(dominantColor.Red, dominantColor.Green, dominantColor.Blue);
|
||||||
Color progressBgColor = Color.FromRgb(
|
Color progressBgColor = Color.FromRgb(
|
||||||
(byte)(dominantColor.R * ColorMultiple),
|
(byte)(dominantColor.Red * ColorMultiple),
|
||||||
(byte)(dominantColor.G * ColorMultiple),
|
(byte)(dominantColor.Green * ColorMultiple),
|
||||||
(byte)(dominantColor.B * ColorMultiple));
|
(byte)(dominantColor.Blue * ColorMultiple));
|
||||||
|
|
||||||
ProgressBarForegroundColor = new SolidColorBrush(progressFgColor);
|
ProgressBarForegroundColor = new SolidColorBrush(progressFgColor);
|
||||||
ProgressBarBackgroundColor = new SolidColorBrush(progressBgColor);
|
ProgressBarBackgroundColor = new SolidColorBrush(progressBgColor);
|
||||||
|
@ -9,14 +9,14 @@ using LibHac.Tools.FsSystem;
|
|||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Ava.UI.Models;
|
using Ryujinx.Ava.UI.Models;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using SixLabors.ImageSharp;
|
using SkiaSharp;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Color = Avalonia.Media.Color;
|
using Color = Avalonia.Media.Color;
|
||||||
|
using Image = SkiaSharp.SKImage;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
namespace Ryujinx.Ava.UI.ViewModels
|
||||||
{
|
{
|
||||||
@ -130,9 +130,12 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
|
|
||||||
Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256);
|
Image avatarImage = Image.FromPixelCopy(new SKImageInfo(256, 256, SKColorType.Rgba8888, SKAlphaType.Premul), DecompressYaz0(stream));
|
||||||
|
|
||||||
avatarImage.SaveAsPng(streamPng);
|
using (SKData data = avatarImage.Encode(SKEncodedImageFormat.Png, 100))
|
||||||
|
{
|
||||||
|
data.SaveTo(streamPng);
|
||||||
|
}
|
||||||
|
|
||||||
_avatarStore.Add(item.FullPath, streamPng.ToArray());
|
_avatarStore.Add(item.FullPath, streamPng.ToArray());
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,8 @@ using Ryujinx.Ava.UI.Controls;
|
|||||||
using Ryujinx.Ava.UI.Models;
|
using Ryujinx.Ava.UI.Models;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using SixLabors.ImageSharp;
|
using SkiaSharp;
|
||||||
using SixLabors.ImageSharp.Formats.Png;
|
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
|
||||||
using SixLabors.ImageSharp.Processing;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Image = SixLabors.ImageSharp.Image;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Views.User
|
namespace Ryujinx.Ava.UI.Views.User
|
||||||
{
|
{
|
||||||
@ -70,15 +66,25 @@ namespace Ryujinx.Ava.UI.Views.User
|
|||||||
{
|
{
|
||||||
if (ViewModel.SelectedImage != null)
|
if (ViewModel.SelectedImage != null)
|
||||||
{
|
{
|
||||||
MemoryStream streamJpg = new();
|
using var streamJpg = new MemoryStream();
|
||||||
Image avatarImage = Image.Load(ViewModel.SelectedImage, new PngDecoder());
|
using var bitmap = SKBitmap.Decode(ViewModel.SelectedImage);
|
||||||
|
using var newBitmap = new SKBitmap(bitmap.Width, bitmap.Height);
|
||||||
|
|
||||||
avatarImage.Mutate(x => x.BackgroundColor(new Rgba32(
|
using (var canvas = new SKCanvas(newBitmap))
|
||||||
|
{
|
||||||
|
canvas.Clear(new SKColor(
|
||||||
ViewModel.BackgroundColor.R,
|
ViewModel.BackgroundColor.R,
|
||||||
ViewModel.BackgroundColor.G,
|
ViewModel.BackgroundColor.G,
|
||||||
ViewModel.BackgroundColor.B,
|
ViewModel.BackgroundColor.B,
|
||||||
ViewModel.BackgroundColor.A)));
|
ViewModel.BackgroundColor.A));
|
||||||
avatarImage.SaveAsJpeg(streamJpg);
|
canvas.DrawBitmap(bitmap, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var image = SKImage.FromBitmap(newBitmap))
|
||||||
|
using (var dataJpeg = image.Encode(SKEncodedImageFormat.Jpeg, 100))
|
||||||
|
{
|
||||||
|
dataJpeg.SaveTo(streamJpg);
|
||||||
|
}
|
||||||
|
|
||||||
_profile.Image = streamJpg.ToArray();
|
_profile.Image = streamJpg.ToArray();
|
||||||
|
|
||||||
|
@ -9,11 +9,9 @@ using Ryujinx.Ava.UI.Controls;
|
|||||||
using Ryujinx.Ava.UI.Models;
|
using Ryujinx.Ava.UI.Models;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using SixLabors.ImageSharp;
|
using SkiaSharp;
|
||||||
using SixLabors.ImageSharp.Processing;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Image = SixLabors.ImageSharp.Image;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Views.User
|
namespace Ryujinx.Ava.UI.Views.User
|
||||||
{
|
{
|
||||||
@ -102,13 +100,19 @@ namespace Ryujinx.Ava.UI.Views.User
|
|||||||
|
|
||||||
private static byte[] ProcessProfileImage(byte[] buffer)
|
private static byte[] ProcessProfileImage(byte[] buffer)
|
||||||
{
|
{
|
||||||
using Image image = Image.Load(buffer);
|
using var bitmap = SKBitmap.Decode(buffer);
|
||||||
|
|
||||||
image.Mutate(x => x.Resize(256, 256));
|
var resizedBitmap = bitmap.Resize(new SKImageInfo(256, 256), SKFilterQuality.High);
|
||||||
|
|
||||||
using MemoryStream streamJpg = new();
|
using var streamJpg = new MemoryStream();
|
||||||
|
|
||||||
image.SaveAsJpeg(streamJpg);
|
if (resizedBitmap != null)
|
||||||
|
{
|
||||||
|
using var image = SKImage.FromBitmap(resizedBitmap);
|
||||||
|
using var dataJpeg = image.Encode(SKEncodedImageFormat.Jpeg, 100);
|
||||||
|
|
||||||
|
dataJpeg.SaveTo(streamJpg);
|
||||||
|
}
|
||||||
|
|
||||||
return streamJpg.ToArray();
|
return streamJpg.ToArray();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using SixLabors.ImageSharp;
|
using SkiaSharp;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
@ -36,35 +35,34 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Color GetFilteredColor(Image<Bgra32> image)
|
public static SKColor GetFilteredColor(SKBitmap image)
|
||||||
{
|
{
|
||||||
var color = GetColor(image).ToPixel<Bgra32>();
|
var color = GetColor(image);
|
||||||
|
|
||||||
|
|
||||||
// We don't want colors that are too dark.
|
// We don't want colors that are too dark.
|
||||||
// If the color is too dark, make it brighter by reducing the range
|
// If the color is too dark, make it brighter by reducing the range
|
||||||
// and adding a constant color.
|
// and adding a constant color.
|
||||||
int luminosity = GetColorApproximateLuminosity(color.R, color.G, color.B);
|
int luminosity = GetColorApproximateLuminosity(color.Red, color.Green, color.Blue);
|
||||||
if (luminosity < CutOffLuminosity)
|
if (luminosity < CutOffLuminosity)
|
||||||
{
|
{
|
||||||
color = Color.FromRgb(
|
color = new SKColor(
|
||||||
(byte)Math.Min(CutOffLuminosity + color.R, byte.MaxValue),
|
(byte)Math.Min(CutOffLuminosity + color.Red, byte.MaxValue),
|
||||||
(byte)Math.Min(CutOffLuminosity + color.G, byte.MaxValue),
|
(byte)Math.Min(CutOffLuminosity + color.Green, byte.MaxValue),
|
||||||
(byte)Math.Min(CutOffLuminosity + color.B, byte.MaxValue));
|
(byte)Math.Min(CutOffLuminosity + color.Blue, byte.MaxValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Color GetColor(Image<Bgra32> image)
|
public static SKColor GetColor(SKBitmap image)
|
||||||
{
|
{
|
||||||
var colors = new PaletteColor[TotalColors];
|
var colors = new PaletteColor[TotalColors];
|
||||||
|
|
||||||
var dominantColorBin = new Dictionary<int, int>();
|
var dominantColorBin = new Dictionary<int, int>();
|
||||||
|
|
||||||
var buffer = GetBuffer(image);
|
var buffer = GetBuffer(image);
|
||||||
|
|
||||||
int w = image.Width;
|
int w = image.Width;
|
||||||
|
|
||||||
int w8 = w << 8;
|
int w8 = w << 8;
|
||||||
int h8 = image.Height << 8;
|
int h8 = image.Height << 8;
|
||||||
|
|
||||||
@ -84,9 +82,10 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
{
|
{
|
||||||
int offset = x + yOffset;
|
int offset = x + yOffset;
|
||||||
|
|
||||||
byte cb = buffer[offset].B;
|
SKColor pixel = buffer[offset];
|
||||||
byte cg = buffer[offset].G;
|
byte cr = pixel.Red;
|
||||||
byte cr = buffer[offset].R;
|
byte cg = pixel.Green;
|
||||||
|
byte cb = pixel.Blue;
|
||||||
|
|
||||||
var qck = GetQuantizedColorKey(cr, cg, cb);
|
var qck = GetQuantizedColorKey(cr, cg, cb);
|
||||||
|
|
||||||
@ -122,12 +121,22 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Color.FromRgb(bestCandidate.R, bestCandidate.G, bestCandidate.B);
|
return new SKColor(bestCandidate.R, bestCandidate.G, bestCandidate.B);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bgra32[] GetBuffer(Image<Bgra32> image)
|
public static SKColor[] GetBuffer(SKBitmap image)
|
||||||
{
|
{
|
||||||
return image.DangerousTryGetSinglePixelMemory(out var data) ? data.ToArray() : Array.Empty<Bgra32>();
|
var pixels = new SKColor[image.Width * image.Height];
|
||||||
|
|
||||||
|
for (int y = 0; y < image.Height; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < image.Width; x++)
|
||||||
|
{
|
||||||
|
pixels[x + y * image.Width] = image.GetPixel(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetColorScore(Dictionary<int, int> dominantColorBin, int maxHitCount, PaletteColor color)
|
private static int GetColorScore(Dictionary<int, int> dominantColorBin, int maxHitCount, PaletteColor color)
|
||||||
|
Reference in New Issue
Block a user