Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
344f4f52c1 | |||
eb212aa91b | |||
a6dbb2ad2b | |||
595e514f18 |
@ -31,11 +31,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public int SubmissionCount;
|
||||
public CommandBuffer CommandBuffer;
|
||||
public FenceHolder Fence;
|
||||
public SemaphoreHolder Semaphore;
|
||||
|
||||
public List<IAuto> Dependants;
|
||||
public List<MultiFenceHolder> Waitables;
|
||||
public HashSet<SemaphoreHolder> Dependencies;
|
||||
|
||||
public void Initialize(Vk api, Device device, CommandPool pool)
|
||||
{
|
||||
@ -51,7 +49,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
Dependants = new List<IAuto>();
|
||||
Waitables = new List<MultiFenceHolder>();
|
||||
Dependencies = new HashSet<SemaphoreHolder>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,14 +140,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
public void AddDependency(int cbIndex, CommandBufferScoped dependencyCbs)
|
||||
{
|
||||
Debug.Assert(_commandBuffers[cbIndex].InUse);
|
||||
var semaphoreHolder = _commandBuffers[dependencyCbs.CommandBufferIndex].Semaphore;
|
||||
semaphoreHolder.Get();
|
||||
_commandBuffers[cbIndex].Dependencies.Add(semaphoreHolder);
|
||||
}
|
||||
|
||||
public void AddWaitable(int cbIndex, MultiFenceHolder waitable)
|
||||
{
|
||||
ref var entry = ref _commandBuffers[cbIndex];
|
||||
@ -354,14 +343,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
waitable.RemoveBufferUses(cbIndex);
|
||||
}
|
||||
|
||||
foreach (var dependency in entry.Dependencies)
|
||||
{
|
||||
dependency.Put();
|
||||
}
|
||||
|
||||
entry.Dependants.Clear();
|
||||
entry.Waitables.Clear();
|
||||
entry.Dependencies.Clear();
|
||||
entry.Fence?.Dispose();
|
||||
|
||||
if (refreshFence)
|
||||
|
@ -26,11 +26,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_pool.AddWaitable(CommandBufferIndex, waitable);
|
||||
}
|
||||
|
||||
public void AddDependency(CommandBufferScoped dependencyCbs)
|
||||
{
|
||||
_pool.AddDependency(CommandBufferIndex, dependencyCbs);
|
||||
}
|
||||
|
||||
public FenceHolder GetFence()
|
||||
{
|
||||
return _pool.GetFence(CommandBufferIndex);
|
||||
|
@ -1,60 +0,0 @@
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using VkSemaphore = Silk.NET.Vulkan.Semaphore;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
class SemaphoreHolder : IDisposable
|
||||
{
|
||||
private readonly Vk _api;
|
||||
private readonly Device _device;
|
||||
private VkSemaphore _semaphore;
|
||||
private int _referenceCount;
|
||||
private bool _disposed;
|
||||
|
||||
public unsafe SemaphoreHolder(Vk api, Device device)
|
||||
{
|
||||
_api = api;
|
||||
_device = device;
|
||||
|
||||
var semaphoreCreateInfo = new SemaphoreCreateInfo
|
||||
{
|
||||
SType = StructureType.SemaphoreCreateInfo,
|
||||
};
|
||||
|
||||
api.CreateSemaphore(device, in semaphoreCreateInfo, null, out _semaphore).ThrowOnError();
|
||||
|
||||
_referenceCount = 1;
|
||||
}
|
||||
|
||||
public VkSemaphore GetUnsafe()
|
||||
{
|
||||
return _semaphore;
|
||||
}
|
||||
|
||||
public VkSemaphore Get()
|
||||
{
|
||||
Interlocked.Increment(ref _referenceCount);
|
||||
return _semaphore;
|
||||
}
|
||||
|
||||
public unsafe void Put()
|
||||
{
|
||||
if (Interlocked.Decrement(ref _referenceCount) == 0)
|
||||
{
|
||||
_api.DestroySemaphore(_device, _semaphore, null);
|
||||
_semaphore = default;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
Put();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -69,27 +69,32 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
DriverId.AmdProprietary => "AMD",
|
||||
DriverId.AmdOpenSource => "AMD (Open)",
|
||||
DriverId.ArmProprietary => "ARM",
|
||||
DriverId.BroadcomProprietary => "Broadcom",
|
||||
DriverId.CoreaviProprietary => "CoreAVI",
|
||||
DriverId.GgpProprietary => "GGP",
|
||||
DriverId.GoogleSwiftshader => "SwiftShader",
|
||||
DriverId.ImaginationProprietary => "Imagination",
|
||||
DriverId.IntelOpenSourceMesa => "Intel (Open)",
|
||||
DriverId.IntelProprietaryWindows => "Intel",
|
||||
DriverId.JuiceProprietary => "Juice",
|
||||
DriverId.MesaDozen => "Dozen",
|
||||
DriverId.MesaLlvmpipe => "LLVMpipe",
|
||||
DriverId.MesaPanvk => "PanVK",
|
||||
DriverId.MesaRadv => "RADV",
|
||||
DriverId.NvidiaProprietary => "NVIDIA",
|
||||
DriverId.IntelProprietaryWindows => "Intel",
|
||||
DriverId.IntelOpenSourceMesa => "Intel (Open)",
|
||||
DriverId.ImaginationProprietary => "Imagination",
|
||||
DriverId.QualcommProprietary => "Qualcomm",
|
||||
DriverId.ArmProprietary => "ARM",
|
||||
DriverId.GoogleSwiftshader => "SwiftShader",
|
||||
DriverId.GgpProprietary => "GGP",
|
||||
DriverId.BroadcomProprietary => "Broadcom",
|
||||
DriverId.MesaLlvmpipe => "LLVMpipe",
|
||||
DriverId.Moltenvk => "MoltenVK",
|
||||
DriverId.CoreaviProprietary => "CoreAVI",
|
||||
DriverId.JuiceProprietary => "Juice",
|
||||
DriverId.VerisiliconProprietary => "Verisilicon",
|
||||
DriverId.MesaTurnip => "Turnip",
|
||||
DriverId.MesaV3DV => "V3DV",
|
||||
DriverId.MesaVenus => "Venus",
|
||||
DriverId.Moltenvk => "MoltenVK",
|
||||
DriverId.NvidiaProprietary => "NVIDIA",
|
||||
DriverId.QualcommProprietary => "Qualcomm",
|
||||
DriverId.MesaPanvk => "PanVK",
|
||||
DriverId.SamsungProprietary => "Samsung",
|
||||
DriverId.VerisiliconProprietary => "Verisilicon",
|
||||
DriverId.MesaVenus => "Venus",
|
||||
DriverId.MesaDozen => "Dozen",
|
||||
|
||||
// TODO: Use real enum when we have an up to date Silk.NET.
|
||||
(DriverId)24 => "NVK",
|
||||
(DriverId)25 => "Imagination (Open)",
|
||||
(DriverId)26 => "Honeykrisp",
|
||||
_ => id.ToString(),
|
||||
};
|
||||
}
|
||||
|
@ -474,9 +474,9 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
{
|
||||
const int MessageSize = 0x100;
|
||||
|
||||
using IMemoryOwner<byte> reqDataOwner = ByteMemoryPool.Rent(MessageSize);
|
||||
using SpanOwner<byte> reqDataOwner = SpanOwner<byte>.Rent(MessageSize);
|
||||
|
||||
Span<byte> reqDataSpan = reqDataOwner.Memory.Span;
|
||||
Span<byte> reqDataSpan = reqDataOwner.Span;
|
||||
|
||||
_selfProcess.CpuMemory.Read(_selfThread.TlsAddress, reqDataSpan);
|
||||
|
||||
|
@ -85,9 +85,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
|
||||
ReadOnlySpan<byte> inputParcel = context.Memory.GetSpan(dataPos, (int)dataSize);
|
||||
|
||||
using IMemoryOwner<byte> outputParcelOwner = ByteMemoryPool.RentCleared(replySize);
|
||||
using SpanOwner<byte> outputParcelOwner = SpanOwner<byte>.RentCleared(checked((int)replySize));
|
||||
|
||||
Span<byte> outputParcel = outputParcelOwner.Memory.Span;
|
||||
Span<byte> outputParcel = outputParcelOwner.Span;
|
||||
|
||||
ResultCode result = OnTransact(binderId, code, flags, inputParcel, outputParcel);
|
||||
|
||||
|
@ -3,7 +3,6 @@ using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
@ -13,7 +12,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
{
|
||||
sealed class Parcel : IDisposable
|
||||
{
|
||||
private readonly IMemoryOwner<byte> _rawDataOwner;
|
||||
private readonly MemoryOwner<byte> _rawDataOwner;
|
||||
|
||||
private Span<byte> Raw => _rawDataOwner.Memory.Span;
|
||||
|
||||
@ -30,7 +29,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
|
||||
public Parcel(ReadOnlySpan<byte> data)
|
||||
{
|
||||
_rawDataOwner = ByteMemoryPool.RentCopy(data);
|
||||
_rawDataOwner = MemoryOwner<byte>.RentCopy(data);
|
||||
|
||||
_payloadPosition = 0;
|
||||
_objectPosition = 0;
|
||||
@ -40,7 +39,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
{
|
||||
uint headerSize = (uint)Unsafe.SizeOf<ParcelHeader>();
|
||||
|
||||
_rawDataOwner = ByteMemoryPool.RentCleared(BitUtils.AlignUp<uint>(headerSize + payloadSize + objectsSize, 4));
|
||||
_rawDataOwner = MemoryOwner<byte>.RentCleared(checked((int)BitUtils.AlignUp<uint>(headerSize + payloadSize + objectsSize, 4)));
|
||||
|
||||
Header.PayloadSize = payloadSize;
|
||||
Header.ObjectsSize = objectsSize;
|
||||
|
@ -40,20 +40,17 @@ using Ryujinx.UI.Common;
|
||||
using Ryujinx.UI.Common.Configuration;
|
||||
using Ryujinx.UI.Common.Helper;
|
||||
using Silk.NET.Vulkan;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using SkiaSharp;
|
||||
using SPB.Graphics.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop;
|
||||
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
||||
using Image = SixLabors.ImageSharp.Image;
|
||||
using InputManager = Ryujinx.Input.HLE.InputManager;
|
||||
using IRenderer = Ryujinx.Graphics.GAL.IRenderer;
|
||||
using Key = Ryujinx.Input.Key;
|
||||
@ -366,25 +363,33 @@ namespace Ryujinx.Ava
|
||||
return;
|
||||
}
|
||||
|
||||
Image image = e.IsBgra ? Image.LoadPixelData<Bgra32>(e.Data, e.Width, e.Height)
|
||||
: Image.LoadPixelData<Rgba32>(e.Data, e.Width, e.Height);
|
||||
var colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888;
|
||||
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)
|
||||
{
|
||||
image.Mutate(x => x.Flip(FlipMode.Vertical));
|
||||
}
|
||||
|
||||
image.SaveAsPng(path, new PngEncoder
|
||||
{
|
||||
ColorType = PngColorType.Rgb,
|
||||
});
|
||||
|
||||
image.Dispose();
|
||||
SaveBitmapAsPng(bitmapToSave ?? bitmap, path);
|
||||
bitmapToSave?.Dispose();
|
||||
|
||||
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()
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
|
@ -54,7 +54,6 @@
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
|
||||
<PackageReference Include="SPB" />
|
||||
<PackageReference Include="SharpZipLib" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -32,7 +32,7 @@ using Ryujinx.UI.App.Common;
|
||||
using Ryujinx.UI.Common;
|
||||
using Ryujinx.UI.Common.Configuration;
|
||||
using Ryujinx.UI.Common.Helper;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
@ -40,7 +40,6 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Image = SixLabors.ImageSharp.Image;
|
||||
using Key = Ryujinx.Input.Key;
|
||||
using MissingKeyException = LibHac.Common.Keys.MissingKeyException;
|
||||
using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
|
||||
@ -1164,17 +1163,17 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
private void PrepareLoadScreen()
|
||||
{
|
||||
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;
|
||||
|
||||
Color progressFgColor = Color.FromRgb(dominantColor.R, dominantColor.G, dominantColor.B);
|
||||
Color progressFgColor = Color.FromRgb(dominantColor.Red, dominantColor.Green, dominantColor.Blue);
|
||||
Color progressBgColor = Color.FromRgb(
|
||||
(byte)(dominantColor.R * ColorMultiple),
|
||||
(byte)(dominantColor.G * ColorMultiple),
|
||||
(byte)(dominantColor.B * ColorMultiple));
|
||||
(byte)(dominantColor.Red * ColorMultiple),
|
||||
(byte)(dominantColor.Green * ColorMultiple),
|
||||
(byte)(dominantColor.Blue * ColorMultiple));
|
||||
|
||||
ProgressBarForegroundColor = new SolidColorBrush(progressFgColor);
|
||||
ProgressBarBackgroundColor = new SolidColorBrush(progressBgColor);
|
||||
|
@ -9,14 +9,14 @@ using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Ava.UI.Models;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using Color = Avalonia.Media.Color;
|
||||
using Image = SkiaSharp.SKImage;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
@ -130,9 +130,12 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
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());
|
||||
}
|
||||
|
@ -6,12 +6,8 @@ using Ryujinx.Ava.UI.Controls;
|
||||
using Ryujinx.Ava.UI.Models;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using SkiaSharp;
|
||||
using System.IO;
|
||||
using Image = SixLabors.ImageSharp.Image;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.User
|
||||
{
|
||||
@ -70,15 +66,25 @@ namespace Ryujinx.Ava.UI.Views.User
|
||||
{
|
||||
if (ViewModel.SelectedImage != null)
|
||||
{
|
||||
MemoryStream streamJpg = new();
|
||||
Image avatarImage = Image.Load(ViewModel.SelectedImage, new PngDecoder());
|
||||
using var streamJpg = new MemoryStream();
|
||||
using var bitmap = SKBitmap.Decode(ViewModel.SelectedImage);
|
||||
using var newBitmap = new SKBitmap(bitmap.Width, bitmap.Height);
|
||||
|
||||
avatarImage.Mutate(x => x.BackgroundColor(new Rgba32(
|
||||
ViewModel.BackgroundColor.R,
|
||||
ViewModel.BackgroundColor.G,
|
||||
ViewModel.BackgroundColor.B,
|
||||
ViewModel.BackgroundColor.A)));
|
||||
avatarImage.SaveAsJpeg(streamJpg);
|
||||
using (var canvas = new SKCanvas(newBitmap))
|
||||
{
|
||||
canvas.Clear(new SKColor(
|
||||
ViewModel.BackgroundColor.R,
|
||||
ViewModel.BackgroundColor.G,
|
||||
ViewModel.BackgroundColor.B,
|
||||
ViewModel.BackgroundColor.A));
|
||||
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();
|
||||
|
||||
|
@ -9,11 +9,9 @@ using Ryujinx.Ava.UI.Controls;
|
||||
using Ryujinx.Ava.UI.Models;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using SkiaSharp;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Image = SixLabors.ImageSharp.Image;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.User
|
||||
{
|
||||
@ -102,13 +100,19 @@ namespace Ryujinx.Ava.UI.Views.User
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
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.
|
||||
// If the color is too dark, make it brighter by reducing the range
|
||||
// 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)
|
||||
{
|
||||
color = Color.FromRgb(
|
||||
(byte)Math.Min(CutOffLuminosity + color.R, byte.MaxValue),
|
||||
(byte)Math.Min(CutOffLuminosity + color.G, byte.MaxValue),
|
||||
(byte)Math.Min(CutOffLuminosity + color.B, byte.MaxValue));
|
||||
color = new SKColor(
|
||||
(byte)Math.Min(CutOffLuminosity + color.Red, byte.MaxValue),
|
||||
(byte)Math.Min(CutOffLuminosity + color.Green, byte.MaxValue),
|
||||
(byte)Math.Min(CutOffLuminosity + color.Blue, byte.MaxValue));
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
public static Color GetColor(Image<Bgra32> image)
|
||||
public static SKColor GetColor(SKBitmap image)
|
||||
{
|
||||
var colors = new PaletteColor[TotalColors];
|
||||
|
||||
var dominantColorBin = new Dictionary<int, int>();
|
||||
|
||||
var buffer = GetBuffer(image);
|
||||
|
||||
int w = image.Width;
|
||||
|
||||
int w8 = w << 8;
|
||||
int h8 = image.Height << 8;
|
||||
|
||||
@ -84,9 +82,10 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
int offset = x + yOffset;
|
||||
|
||||
byte cb = buffer[offset].B;
|
||||
byte cg = buffer[offset].G;
|
||||
byte cr = buffer[offset].R;
|
||||
SKColor pixel = buffer[offset];
|
||||
byte cr = pixel.Red;
|
||||
byte cg = pixel.Green;
|
||||
byte cb = pixel.Blue;
|
||||
|
||||
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)
|
||||
|
Reference in New Issue
Block a user