mirror of
https://git.ryujinx.app/kenji-nx/ryujinx.git
synced 2025-12-12 19:37:06 +00:00
Revert PRs 7226(1.1.1385), 7311(1.1.1392), and 7312 (1.1.1396).
* "Vulkan: Feedback loop detection and barriers (#7226)" * "Change image format view handling to allow view incompatible formats (#7311)" * "Add support for sampler sRGB disable (#7312)" * These changes prevent slowdowns in several areas in Paper Mario: The Thousand Year Door, possibly other games.
This commit is contained in:
parent
a2c0035013
commit
02a5f75fab
49 changed files with 358 additions and 879 deletions
|
|
@ -1,33 +1,13 @@
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Common.GraphicsDriver
|
namespace Ryujinx.Common.GraphicsDriver
|
||||||
{
|
{
|
||||||
public static class DriverUtilities
|
public static class DriverUtilities
|
||||||
{
|
{
|
||||||
private static void AddMesaFlags(string envVar, string newFlags)
|
|
||||||
{
|
|
||||||
string existingFlags = Environment.GetEnvironmentVariable(envVar);
|
|
||||||
|
|
||||||
string flags = existingFlags == null ? newFlags : $"{existingFlags},{newFlags}";
|
|
||||||
|
|
||||||
OsUtils.SetEnvironmentVariableNoCaching(envVar, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void InitDriverConfig(bool oglThreading)
|
|
||||||
{
|
|
||||||
if (OperatingSystem.IsLinux())
|
|
||||||
{
|
|
||||||
AddMesaFlags("RADV_DEBUG", "nodcc");
|
|
||||||
}
|
|
||||||
|
|
||||||
ToggleOGLThreading(oglThreading);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ToggleOGLThreading(bool enabled)
|
public static void ToggleOGLThreading(bool enabled)
|
||||||
{
|
{
|
||||||
OsUtils.SetEnvironmentVariableNoCaching("mesa_glthread", enabled.ToString().ToLower());
|
Environment.SetEnvironmentVariable("mesa_glthread", enabled.ToString().ToLower());
|
||||||
OsUtils.SetEnvironmentVariableNoCaching("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0");
|
Environment.SetEnvironmentVariable("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Utilities
|
|
||||||
{
|
|
||||||
public partial class OsUtils
|
|
||||||
{
|
|
||||||
[LibraryImport("libc", SetLastError = true)]
|
|
||||||
private static partial int setenv([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value, int overwrite);
|
|
||||||
|
|
||||||
public static void SetEnvironmentVariableNoCaching(string key, string value)
|
|
||||||
{
|
|
||||||
// Set the value in the cached environment variables, too.
|
|
||||||
Environment.SetEnvironmentVariable(key, value);
|
|
||||||
|
|
||||||
if (!OperatingSystem.IsWindows())
|
|
||||||
{
|
|
||||||
int res = setenv(key, value, 1);
|
|
||||||
Debug.Assert(res != -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,6 +4,7 @@ namespace Ryujinx.Graphics.GAL
|
||||||
{
|
{
|
||||||
public interface IImageArray : IDisposable
|
public interface IImageArray : IDisposable
|
||||||
{
|
{
|
||||||
|
void SetFormats(int index, Format[] imageFormats);
|
||||||
void SetImages(int index, ITexture[] images);
|
void SetImages(int index, ITexture[] images);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.GAL
|
||||||
|
|
||||||
void SetIndexBuffer(BufferRange buffer, IndexType type);
|
void SetIndexBuffer(BufferRange buffer, IndexType type);
|
||||||
|
|
||||||
void SetImage(ShaderStage stage, int binding, ITexture texture);
|
void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat);
|
||||||
void SetImageArray(ShaderStage stage, int binding, IImageArray array);
|
void SetImageArray(ShaderStage stage, int binding, IImageArray array);
|
||||||
void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array);
|
void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||||
Register<CounterEventFlushCommand>(CommandType.CounterEventFlush);
|
Register<CounterEventFlushCommand>(CommandType.CounterEventFlush);
|
||||||
|
|
||||||
Register<ImageArrayDisposeCommand>(CommandType.ImageArrayDispose);
|
Register<ImageArrayDisposeCommand>(CommandType.ImageArrayDispose);
|
||||||
|
Register<ImageArraySetFormatsCommand>(CommandType.ImageArraySetFormats);
|
||||||
Register<ImageArraySetImagesCommand>(CommandType.ImageArraySetImages);
|
Register<ImageArraySetImagesCommand>(CommandType.ImageArraySetImages);
|
||||||
|
|
||||||
Register<ProgramDisposeCommand>(CommandType.ProgramDispose);
|
Register<ProgramDisposeCommand>(CommandType.ProgramDispose);
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||||
CounterEventFlush,
|
CounterEventFlush,
|
||||||
|
|
||||||
ImageArrayDispose,
|
ImageArrayDispose,
|
||||||
|
ImageArraySetFormats,
|
||||||
ImageArraySetImages,
|
ImageArraySetImages,
|
||||||
|
|
||||||
ProgramDispose,
|
ProgramDispose,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
||||||
|
using Ryujinx.Graphics.GAL.Multithreading.Resources;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray
|
||||||
|
{
|
||||||
|
struct ImageArraySetFormatsCommand : IGALCommand, IGALCommand<ImageArraySetFormatsCommand>
|
||||||
|
{
|
||||||
|
public readonly CommandType CommandType => CommandType.ImageArraySetFormats;
|
||||||
|
private TableRef<ThreadedImageArray> _imageArray;
|
||||||
|
private int _index;
|
||||||
|
private TableRef<Format[]> _imageFormats;
|
||||||
|
|
||||||
|
public void Set(TableRef<ThreadedImageArray> imageArray, int index, TableRef<Format[]> imageFormats)
|
||||||
|
{
|
||||||
|
_imageArray = imageArray;
|
||||||
|
_index = index;
|
||||||
|
_imageFormats = imageFormats;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Run(ref ImageArraySetFormatsCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||||
|
{
|
||||||
|
ThreadedImageArray imageArray = command._imageArray.Get(threaded);
|
||||||
|
imageArray.Base.SetFormats(command._index, command._imageFormats.Get(threaded));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,17 +10,19 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||||
private ShaderStage _stage;
|
private ShaderStage _stage;
|
||||||
private int _binding;
|
private int _binding;
|
||||||
private TableRef<ITexture> _texture;
|
private TableRef<ITexture> _texture;
|
||||||
|
private Format _imageFormat;
|
||||||
|
|
||||||
public void Set(ShaderStage stage, int binding, TableRef<ITexture> texture)
|
public void Set(ShaderStage stage, int binding, TableRef<ITexture> texture, Format imageFormat)
|
||||||
{
|
{
|
||||||
_stage = stage;
|
_stage = stage;
|
||||||
_binding = binding;
|
_binding = binding;
|
||||||
_texture = texture;
|
_texture = texture;
|
||||||
|
_imageFormat = imageFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Run(ref SetImageCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
public static void Run(ref SetImageCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||||
{
|
{
|
||||||
renderer.Pipeline.SetImage(command._stage, command._binding, command._texture.GetAs<ThreadedTexture>(threaded)?.Base);
|
renderer.Pipeline.SetImage(command._stage, command._binding, command._texture.GetAs<ThreadedTexture>(threaded)?.Base, command._imageFormat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetFormats(int index, Format[] imageFormats)
|
||||||
|
{
|
||||||
|
_renderer.New<ImageArraySetFormatsCommand>().Set(Ref(this), index, Ref(imageFormats));
|
||||||
|
_renderer.QueueCommand();
|
||||||
|
}
|
||||||
|
|
||||||
public void SetImages(int index, ITexture[] images)
|
public void SetImages(int index, ITexture[] images)
|
||||||
{
|
{
|
||||||
_renderer.New<ImageArraySetImagesCommand>().Set(Ref(this), index, Ref(images));
|
_renderer.New<ImageArraySetImagesCommand>().Set(Ref(this), index, Ref(images));
|
||||||
|
|
|
||||||
|
|
@ -177,9 +177,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetImage(ShaderStage stage, int binding, ITexture texture)
|
public void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat)
|
||||||
{
|
{
|
||||||
_renderer.New<SetImageCommand>().Set(stage, binding, Ref(texture));
|
_renderer.New<SetImageCommand>().Set(stage, binding, Ref(texture), imageFormat);
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Image;
|
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Engine
|
namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
@ -62,51 +61,51 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="format">Shader image format</param>
|
/// <param name="format">Shader image format</param>
|
||||||
/// <returns>Texture format</returns>
|
/// <returns>Texture format</returns>
|
||||||
public static FormatInfo GetFormatInfo(TextureFormat format)
|
public static Format GetFormat(TextureFormat format)
|
||||||
{
|
{
|
||||||
return format switch
|
return format switch
|
||||||
{
|
{
|
||||||
#pragma warning disable IDE0055 // Disable formatting
|
#pragma warning disable IDE0055 // Disable formatting
|
||||||
TextureFormat.R8Unorm => new(Format.R8Unorm, 1, 1, 1, 1),
|
TextureFormat.R8Unorm => Format.R8Unorm,
|
||||||
TextureFormat.R8Snorm => new(Format.R8Snorm, 1, 1, 1, 1),
|
TextureFormat.R8Snorm => Format.R8Snorm,
|
||||||
TextureFormat.R8Uint => new(Format.R8Uint, 1, 1, 1, 1),
|
TextureFormat.R8Uint => Format.R8Uint,
|
||||||
TextureFormat.R8Sint => new(Format.R8Sint, 1, 1, 1, 1),
|
TextureFormat.R8Sint => Format.R8Sint,
|
||||||
TextureFormat.R16Float => new(Format.R16Float, 1, 1, 2, 1),
|
TextureFormat.R16Float => Format.R16Float,
|
||||||
TextureFormat.R16Unorm => new(Format.R16Unorm, 1, 1, 2, 1),
|
TextureFormat.R16Unorm => Format.R16Unorm,
|
||||||
TextureFormat.R16Snorm => new(Format.R16Snorm, 1, 1, 2, 1),
|
TextureFormat.R16Snorm => Format.R16Snorm,
|
||||||
TextureFormat.R16Uint => new(Format.R16Uint, 1, 1, 2, 1),
|
TextureFormat.R16Uint => Format.R16Uint,
|
||||||
TextureFormat.R16Sint => new(Format.R16Sint, 1, 1, 2, 1),
|
TextureFormat.R16Sint => Format.R16Sint,
|
||||||
TextureFormat.R32Float => new(Format.R32Float, 1, 1, 4, 1),
|
TextureFormat.R32Float => Format.R32Float,
|
||||||
TextureFormat.R32Uint => new(Format.R32Uint, 1, 1, 4, 1),
|
TextureFormat.R32Uint => Format.R32Uint,
|
||||||
TextureFormat.R32Sint => new(Format.R32Sint, 1, 1, 4, 1),
|
TextureFormat.R32Sint => Format.R32Sint,
|
||||||
TextureFormat.R8G8Unorm => new(Format.R8G8Unorm, 1, 1, 2, 2),
|
TextureFormat.R8G8Unorm => Format.R8G8Unorm,
|
||||||
TextureFormat.R8G8Snorm => new(Format.R8G8Snorm, 1, 1, 2, 2),
|
TextureFormat.R8G8Snorm => Format.R8G8Snorm,
|
||||||
TextureFormat.R8G8Uint => new(Format.R8G8Uint, 1, 1, 2, 2),
|
TextureFormat.R8G8Uint => Format.R8G8Uint,
|
||||||
TextureFormat.R8G8Sint => new(Format.R8G8Sint, 1, 1, 2, 2),
|
TextureFormat.R8G8Sint => Format.R8G8Sint,
|
||||||
TextureFormat.R16G16Float => new(Format.R16G16Float, 1, 1, 4, 2),
|
TextureFormat.R16G16Float => Format.R16G16Float,
|
||||||
TextureFormat.R16G16Unorm => new(Format.R16G16Unorm, 1, 1, 4, 2),
|
TextureFormat.R16G16Unorm => Format.R16G16Unorm,
|
||||||
TextureFormat.R16G16Snorm => new(Format.R16G16Snorm, 1, 1, 4, 2),
|
TextureFormat.R16G16Snorm => Format.R16G16Snorm,
|
||||||
TextureFormat.R16G16Uint => new(Format.R16G16Uint, 1, 1, 4, 2),
|
TextureFormat.R16G16Uint => Format.R16G16Uint,
|
||||||
TextureFormat.R16G16Sint => new(Format.R16G16Sint, 1, 1, 4, 2),
|
TextureFormat.R16G16Sint => Format.R16G16Sint,
|
||||||
TextureFormat.R32G32Float => new(Format.R32G32Float, 1, 1, 8, 2),
|
TextureFormat.R32G32Float => Format.R32G32Float,
|
||||||
TextureFormat.R32G32Uint => new(Format.R32G32Uint, 1, 1, 8, 2),
|
TextureFormat.R32G32Uint => Format.R32G32Uint,
|
||||||
TextureFormat.R32G32Sint => new(Format.R32G32Sint, 1, 1, 8, 2),
|
TextureFormat.R32G32Sint => Format.R32G32Sint,
|
||||||
TextureFormat.R8G8B8A8Unorm => new(Format.R8G8B8A8Unorm, 1, 1, 4, 4),
|
TextureFormat.R8G8B8A8Unorm => Format.R8G8B8A8Unorm,
|
||||||
TextureFormat.R8G8B8A8Snorm => new(Format.R8G8B8A8Snorm, 1, 1, 4, 4),
|
TextureFormat.R8G8B8A8Snorm => Format.R8G8B8A8Snorm,
|
||||||
TextureFormat.R8G8B8A8Uint => new(Format.R8G8B8A8Uint, 1, 1, 4, 4),
|
TextureFormat.R8G8B8A8Uint => Format.R8G8B8A8Uint,
|
||||||
TextureFormat.R8G8B8A8Sint => new(Format.R8G8B8A8Sint, 1, 1, 4, 4),
|
TextureFormat.R8G8B8A8Sint => Format.R8G8B8A8Sint,
|
||||||
TextureFormat.R16G16B16A16Float => new(Format.R16G16B16A16Float, 1, 1, 8, 4),
|
TextureFormat.R16G16B16A16Float => Format.R16G16B16A16Float,
|
||||||
TextureFormat.R16G16B16A16Unorm => new(Format.R16G16B16A16Unorm, 1, 1, 8, 4),
|
TextureFormat.R16G16B16A16Unorm => Format.R16G16B16A16Unorm,
|
||||||
TextureFormat.R16G16B16A16Snorm => new(Format.R16G16B16A16Snorm, 1, 1, 8, 4),
|
TextureFormat.R16G16B16A16Snorm => Format.R16G16B16A16Snorm,
|
||||||
TextureFormat.R16G16B16A16Uint => new(Format.R16G16B16A16Uint, 1, 1, 8, 4),
|
TextureFormat.R16G16B16A16Uint => Format.R16G16B16A16Uint,
|
||||||
TextureFormat.R16G16B16A16Sint => new(Format.R16G16B16A16Sint, 1, 1, 8, 4),
|
TextureFormat.R16G16B16A16Sint => Format.R16G16B16A16Sint,
|
||||||
TextureFormat.R32G32B32A32Float => new(Format.R32G32B32A32Float, 1, 1, 16, 4),
|
TextureFormat.R32G32B32A32Float => Format.R32G32B32A32Float,
|
||||||
TextureFormat.R32G32B32A32Uint => new(Format.R32G32B32A32Uint, 1, 1, 16, 4),
|
TextureFormat.R32G32B32A32Uint => Format.R32G32B32A32Uint,
|
||||||
TextureFormat.R32G32B32A32Sint => new(Format.R32G32B32A32Sint, 1, 1, 16, 4),
|
TextureFormat.R32G32B32A32Sint => Format.R32G32B32A32Sint,
|
||||||
TextureFormat.R10G10B10A2Unorm => new(Format.R10G10B10A2Unorm, 1, 1, 4, 4),
|
TextureFormat.R10G10B10A2Unorm => Format.R10G10B10A2Unorm,
|
||||||
TextureFormat.R10G10B10A2Uint => new(Format.R10G10B10A2Uint, 1, 1, 4, 4),
|
TextureFormat.R10G10B10A2Uint => Format.R10G10B10A2Uint,
|
||||||
TextureFormat.R11G11B10Float => new(Format.R11G11B10Float, 1, 1, 4, 3),
|
TextureFormat.R11G11B10Float => Format.R11G11B10Float,
|
||||||
_ => FormatInfo.Invalid,
|
_ => 0,
|
||||||
#pragma warning restore IDE0055
|
#pragma warning restore IDE0055
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
readonly struct FormatInfo
|
readonly struct FormatInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// An invalid texture format.
|
|
||||||
/// </summary>
|
|
||||||
public static FormatInfo Invalid { get; } = new(0, 0, 0, 0, 0);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A default, generic RGBA8 texture format.
|
/// A default, generic RGBA8 texture format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -28,7 +23,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Must be 1 for non-compressed formats.
|
/// Must be 1 for non-compressed formats.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public byte BlockWidth { get; }
|
public int BlockWidth { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The block height for compressed formats.
|
/// The block height for compressed formats.
|
||||||
|
|
@ -36,17 +31,17 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Must be 1 for non-compressed formats.
|
/// Must be 1 for non-compressed formats.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public byte BlockHeight { get; }
|
public int BlockHeight { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The number of bytes occupied by a single pixel in memory of the texture data.
|
/// The number of bytes occupied by a single pixel in memory of the texture data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte BytesPerPixel { get; }
|
public int BytesPerPixel { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum number of components this format has defined (in RGBA order).
|
/// The maximum number of components this format has defined (in RGBA order).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte Components { get; }
|
public int Components { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whenever or not the texture format is a compressed format. Determined from block size.
|
/// Whenever or not the texture format is a compressed format. Determined from block size.
|
||||||
|
|
@ -62,10 +57,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <param name="bytesPerPixel">The number of bytes occupied by a single pixel in memory of the texture data</param>
|
/// <param name="bytesPerPixel">The number of bytes occupied by a single pixel in memory of the texture data</param>
|
||||||
public FormatInfo(
|
public FormatInfo(
|
||||||
Format format,
|
Format format,
|
||||||
byte blockWidth,
|
int blockWidth,
|
||||||
byte blockHeight,
|
int blockHeight,
|
||||||
byte bytesPerPixel,
|
int bytesPerPixel,
|
||||||
byte components)
|
int components)
|
||||||
{
|
{
|
||||||
Format = format;
|
Format = format;
|
||||||
BlockWidth = blockWidth;
|
BlockWidth = blockWidth;
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsDisposed { get; private set; }
|
public bool IsDisposed { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True if the sampler has sRGB conversion enabled, false otherwise.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsSrgb { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Host sampler object.
|
/// Host sampler object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -35,8 +30,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <param name="descriptor">The Maxwell sampler descriptor</param>
|
/// <param name="descriptor">The Maxwell sampler descriptor</param>
|
||||||
public Sampler(GpuContext context, SamplerDescriptor descriptor)
|
public Sampler(GpuContext context, SamplerDescriptor descriptor)
|
||||||
{
|
{
|
||||||
IsSrgb = descriptor.UnpackSrgb();
|
|
||||||
|
|
||||||
MinFilter minFilter = descriptor.UnpackMinFilter();
|
MinFilter minFilter = descriptor.UnpackMinFilter();
|
||||||
MagFilter magFilter = descriptor.UnpackMagFilter();
|
MagFilter magFilter = descriptor.UnpackMagFilter();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,15 +113,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
return (CompareOp)(((Word0 >> 10) & 7) + 1);
|
return (CompareOp)(((Word0 >> 10) & 7) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unpacks the sampler sRGB format flag.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True if the has sampler is sRGB conversion enabled, false otherwise</returns>
|
|
||||||
public readonly bool UnpackSrgb()
|
|
||||||
{
|
|
||||||
return (Word0 & (1 << 13)) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unpacks and converts the maximum anisotropy value used for texture anisotropic filtering.
|
/// Unpacks and converts the maximum anisotropy value used for texture anisotropic filtering.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// For images, indicates the format specified on the shader.
|
/// For images, indicates the format specified on the shader.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FormatInfo FormatInfo { get; }
|
public Format Format { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shader texture host set index.
|
/// Shader texture host set index.
|
||||||
|
|
@ -58,17 +58,17 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// Constructs the texture binding information structure.
|
/// Constructs the texture binding information structure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="target">The shader sampler target type</param>
|
/// <param name="target">The shader sampler target type</param>
|
||||||
/// <param name="formatInfo">Format of the image as declared on the shader</param>
|
/// <param name="format">Format of the image as declared on the shader</param>
|
||||||
/// <param name="set">Shader texture host set index</param>
|
/// <param name="set">Shader texture host set index</param>
|
||||||
/// <param name="binding">The shader texture binding point</param>
|
/// <param name="binding">The shader texture binding point</param>
|
||||||
/// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param>
|
/// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param>
|
||||||
/// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
|
/// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
|
||||||
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
|
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
|
||||||
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
|
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
|
||||||
public TextureBindingInfo(Target target, FormatInfo formatInfo, int set, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
|
public TextureBindingInfo(Target target, Format format, int set, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
|
||||||
{
|
{
|
||||||
Target = target;
|
Target = target;
|
||||||
FormatInfo = formatInfo;
|
Format = format;
|
||||||
Set = set;
|
Set = set;
|
||||||
Binding = binding;
|
Binding = binding;
|
||||||
ArrayLength = arrayLength;
|
ArrayLength = arrayLength;
|
||||||
|
|
@ -96,7 +96,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
int cbufSlot,
|
int cbufSlot,
|
||||||
int handle,
|
int handle,
|
||||||
TextureUsageFlags flags,
|
TextureUsageFlags flags,
|
||||||
bool isSamplerOnly) : this(target, FormatInfo.Invalid, set, binding, arrayLength, cbufSlot, handle, flags)
|
bool isSamplerOnly) : this(target, 0, set, binding, arrayLength, cbufSlot, handle, flags)
|
||||||
{
|
{
|
||||||
IsSamplerOnly = isSamplerOnly;
|
IsSamplerOnly = isSamplerOnly;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -659,6 +659,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
int length = (isSampler ? samplerPool.MaximumId : texturePool.MaximumId) + 1;
|
int length = (isSampler ? samplerPool.MaximumId : texturePool.MaximumId) + 1;
|
||||||
length = Math.Min(length, bindingInfo.ArrayLength);
|
length = Math.Min(length, bindingInfo.ArrayLength);
|
||||||
|
|
||||||
|
Format[] formats = isImage ? new Format[bindingInfo.ArrayLength] : null;
|
||||||
ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength];
|
ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength];
|
||||||
ITexture[] textures = new ITexture[bindingInfo.ArrayLength];
|
ITexture[] textures = new ITexture[bindingInfo.ArrayLength];
|
||||||
|
|
||||||
|
|
@ -673,7 +674,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(index, bindingInfo.FormatInfo, out texture);
|
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(index, out texture);
|
||||||
|
|
||||||
if (texture != null)
|
if (texture != null)
|
||||||
{
|
{
|
||||||
|
|
@ -696,6 +697,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
||||||
ISampler hostSampler = sampler?.GetHostSampler(texture);
|
ISampler hostSampler = sampler?.GetHostSampler(texture);
|
||||||
|
|
||||||
|
Format format = bindingInfo.Format;
|
||||||
|
|
||||||
if (hostTexture != null && texture.Target == Target.TextureBuffer)
|
if (hostTexture != null && texture.Target == Target.TextureBuffer)
|
||||||
{
|
{
|
||||||
// Ensure that the buffer texture is using the correct buffer as storage.
|
// Ensure that the buffer texture is using the correct buffer as storage.
|
||||||
|
|
@ -703,15 +706,26 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
// to ensure we're not using a old buffer that was already deleted.
|
// to ensure we're not using a old buffer that was already deleted.
|
||||||
if (isImage)
|
if (isImage)
|
||||||
{
|
{
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index);
|
if (format == 0 && texture != null)
|
||||||
|
{
|
||||||
|
format = texture.Format;
|
||||||
|
}
|
||||||
|
|
||||||
|
_channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index, format);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index);
|
_channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index, format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isImage)
|
else if (isImage)
|
||||||
{
|
{
|
||||||
|
if (format == 0 && texture != null)
|
||||||
|
{
|
||||||
|
format = texture.Format;
|
||||||
|
}
|
||||||
|
|
||||||
|
formats[index] = format;
|
||||||
textures[index] = hostTexture;
|
textures[index] = hostTexture;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -723,6 +737,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
if (isImage)
|
if (isImage)
|
||||||
{
|
{
|
||||||
|
entry.ImageArray.SetFormats(0, formats);
|
||||||
entry.ImageArray.SetImages(0, textures);
|
entry.ImageArray.SetImages(0, textures);
|
||||||
|
|
||||||
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||||
|
|
@ -848,6 +863,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
entry.UpdateData(cachedTextureBuffer, cachedSamplerBuffer, separateSamplerBuffer);
|
entry.UpdateData(cachedTextureBuffer, cachedSamplerBuffer, separateSamplerBuffer);
|
||||||
|
|
||||||
|
Format[] formats = isImage ? new Format[bindingInfo.ArrayLength] : null;
|
||||||
ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength];
|
ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength];
|
||||||
ITexture[] textures = new ITexture[bindingInfo.ArrayLength];
|
ITexture[] textures = new ITexture[bindingInfo.ArrayLength];
|
||||||
|
|
||||||
|
|
@ -867,7 +883,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
samplerId = TextureHandle.UnpackSamplerId(packedId);
|
samplerId = TextureHandle.UnpackSamplerId(packedId);
|
||||||
}
|
}
|
||||||
|
|
||||||
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, bindingInfo.FormatInfo, out Texture texture);
|
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, out Texture texture);
|
||||||
|
|
||||||
if (texture != null)
|
if (texture != null)
|
||||||
{
|
{
|
||||||
|
|
@ -900,6 +916,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
hostSampler = sampler?.GetHostSampler(texture);
|
hostSampler = sampler?.GetHostSampler(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Format format = bindingInfo.Format;
|
||||||
|
|
||||||
if (hostTexture != null && texture.Target == Target.TextureBuffer)
|
if (hostTexture != null && texture.Target == Target.TextureBuffer)
|
||||||
{
|
{
|
||||||
// Ensure that the buffer texture is using the correct buffer as storage.
|
// Ensure that the buffer texture is using the correct buffer as storage.
|
||||||
|
|
@ -907,15 +925,26 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
// to ensure we're not using a old buffer that was already deleted.
|
// to ensure we're not using a old buffer that was already deleted.
|
||||||
if (isImage)
|
if (isImage)
|
||||||
{
|
{
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index);
|
if (format == 0 && texture != null)
|
||||||
|
{
|
||||||
|
format = texture.Format;
|
||||||
|
}
|
||||||
|
|
||||||
|
_channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index, format);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index);
|
_channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index, format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isImage)
|
else if (isImage)
|
||||||
{
|
{
|
||||||
|
if (format == 0 && texture != null)
|
||||||
|
{
|
||||||
|
format = texture.Format;
|
||||||
|
}
|
||||||
|
|
||||||
|
formats[index] = format;
|
||||||
textures[index] = hostTexture;
|
textures[index] = hostTexture;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -927,6 +956,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
if (isImage)
|
if (isImage)
|
||||||
{
|
{
|
||||||
|
entry.ImageArray.SetFormats(0, formats);
|
||||||
entry.ImageArray.SetImages(0, textures);
|
entry.ImageArray.SetImages(0, textures);
|
||||||
|
|
||||||
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||||
|
|
|
||||||
|
|
@ -187,9 +187,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
(TexturePool texturePool, SamplerPool samplerPool) = GetPools();
|
(TexturePool texturePool, SamplerPool samplerPool) = GetPools();
|
||||||
|
|
||||||
Sampler sampler = samplerPool?.Get(samplerId);
|
return (texturePool.Get(textureId), samplerPool.Get(samplerId));
|
||||||
|
|
||||||
return (texturePool.Get(textureId, sampler?.IsSrgb ?? true), sampler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -510,12 +508,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
state.TextureHandle = textureId;
|
state.TextureHandle = textureId;
|
||||||
state.SamplerHandle = samplerId;
|
state.SamplerHandle = samplerId;
|
||||||
|
|
||||||
Sampler sampler = samplerPool?.Get(samplerId);
|
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, out Texture texture);
|
||||||
|
|
||||||
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, sampler?.IsSrgb ?? true, out Texture texture);
|
|
||||||
|
|
||||||
specStateMatches &= specState.MatchesTexture(stage, index, descriptor);
|
specStateMatches &= specState.MatchesTexture(stage, index, descriptor);
|
||||||
|
|
||||||
|
Sampler sampler = samplerPool?.Get(samplerId);
|
||||||
|
|
||||||
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
||||||
ISampler hostSampler = sampler?.GetHostSampler(texture);
|
ISampler hostSampler = sampler?.GetHostSampler(texture);
|
||||||
|
|
||||||
|
|
@ -524,7 +522,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
// Ensure that the buffer texture is using the correct buffer as storage.
|
// Ensure that the buffer texture is using the correct buffer as storage.
|
||||||
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
||||||
// to ensure we're not using a old buffer that was already deleted.
|
// to ensure we're not using a old buffer that was already deleted.
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, false);
|
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, bindingInfo.Format, false);
|
||||||
|
|
||||||
// Cache is not used for buffer texture, it must always rebind.
|
// Cache is not used for buffer texture, it must always rebind.
|
||||||
state.CachedTexture = null;
|
state.CachedTexture = null;
|
||||||
|
|
@ -618,7 +616,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
if (!poolModified &&
|
if (!poolModified &&
|
||||||
state.TextureHandle == textureId &&
|
state.TextureHandle == textureId &&
|
||||||
state.ImageFormat == bindingInfo.FormatInfo.Format &&
|
|
||||||
state.CachedTexture != null &&
|
state.CachedTexture != null &&
|
||||||
state.CachedTexture.InvalidatedSequence == state.InvalidatedSequence)
|
state.CachedTexture.InvalidatedSequence == state.InvalidatedSequence)
|
||||||
{
|
{
|
||||||
|
|
@ -632,22 +629,26 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
cachedTexture.SignalModified();
|
cachedTexture.SignalModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 && UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage))
|
Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format;
|
||||||
|
|
||||||
|
if (state.ImageFormat != format ||
|
||||||
|
((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 &&
|
||||||
|
UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage)))
|
||||||
{
|
{
|
||||||
ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target);
|
ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target);
|
||||||
|
|
||||||
state.Texture = hostTextureRebind;
|
state.Texture = hostTextureRebind;
|
||||||
|
state.ImageFormat = format;
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTextureRebind);
|
_context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTextureRebind, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.TextureHandle = textureId;
|
state.TextureHandle = textureId;
|
||||||
state.ImageFormat = bindingInfo.FormatInfo.Format;
|
|
||||||
|
|
||||||
ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, bindingInfo.FormatInfo, out Texture texture);
|
ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, out Texture texture);
|
||||||
|
|
||||||
specStateMatches &= specState.MatchesImage(stage, index, descriptor);
|
specStateMatches &= specState.MatchesImage(stage, index, descriptor);
|
||||||
|
|
||||||
|
|
@ -659,7 +660,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
||||||
// to ensure we're not using a old buffer that was already deleted.
|
// to ensure we're not using a old buffer that was already deleted.
|
||||||
|
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, true);
|
Format format = bindingInfo.Format;
|
||||||
|
|
||||||
|
if (format == 0 && texture != null)
|
||||||
|
{
|
||||||
|
format = texture.Format;
|
||||||
|
}
|
||||||
|
|
||||||
|
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, format, true);
|
||||||
|
|
||||||
// Cache is not used for buffer texture, it must always rebind.
|
// Cache is not used for buffer texture, it must always rebind.
|
||||||
state.CachedTexture = null;
|
state.CachedTexture = null;
|
||||||
|
|
@ -681,7 +689,16 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
state.Texture = hostTexture;
|
state.Texture = hostTexture;
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTexture);
|
Format format = bindingInfo.Format;
|
||||||
|
|
||||||
|
if (format == 0 && texture != null)
|
||||||
|
{
|
||||||
|
format = texture.Format;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.ImageFormat = format;
|
||||||
|
|
||||||
|
_context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTexture, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.CachedTexture = texture;
|
state.CachedTexture = texture;
|
||||||
|
|
|
||||||
|
|
@ -739,8 +739,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
}
|
}
|
||||||
|
|
||||||
return (lhsFormat.Format == Format.R8G8B8A8Unorm && rhsFormat.Format == Format.R32G32B32A32Float) ||
|
return (lhsFormat.Format == Format.R8G8B8A8Unorm && rhsFormat.Format == Format.R32G32B32A32Float) ||
|
||||||
(lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm) ||
|
(lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm);
|
||||||
(lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R32Uint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -75,76 +75,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
private readonly ConcurrentQueue<DereferenceRequest> _dereferenceQueue = new();
|
private readonly ConcurrentQueue<DereferenceRequest> _dereferenceQueue = new();
|
||||||
private TextureDescriptor _defaultDescriptor;
|
private TextureDescriptor _defaultDescriptor;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of textures that shares the same memory region, but have different formats.
|
|
||||||
/// </summary>
|
|
||||||
private class TextureAliasList
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Alias texture.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Format">Texture format</param>
|
|
||||||
/// <param name="Texture">Texture</param>
|
|
||||||
private readonly record struct Alias(Format Format, Texture Texture);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of texture aliases.
|
|
||||||
/// </summary>
|
|
||||||
private readonly List<Alias> _aliases;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the texture alias list.
|
|
||||||
/// </summary>
|
|
||||||
public TextureAliasList()
|
|
||||||
{
|
|
||||||
_aliases = new List<Alias>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a new texture alias.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="format">Alias format</param>
|
|
||||||
/// <param name="texture">Alias texture</param>
|
|
||||||
public void Add(Format format, Texture texture)
|
|
||||||
{
|
|
||||||
_aliases.Add(new Alias(format, texture));
|
|
||||||
texture.IncrementReferenceCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finds a texture with the requested format, or returns null if not found.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="format">Format to find</param>
|
|
||||||
/// <returns>Texture with the requested format, or null if not found</returns>
|
|
||||||
public Texture Find(Format format)
|
|
||||||
{
|
|
||||||
foreach (var alias in _aliases)
|
|
||||||
{
|
|
||||||
if (alias.Format == format)
|
|
||||||
{
|
|
||||||
return alias.Texture;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes all alias textures.
|
|
||||||
/// </summary>
|
|
||||||
public void Destroy()
|
|
||||||
{
|
|
||||||
foreach (var entry in _aliases)
|
|
||||||
{
|
|
||||||
entry.Texture.DecrementReferenceCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
_aliases.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Dictionary<Texture, TextureAliasList> _aliasLists;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Linked list node used on the texture pool cache.
|
/// Linked list node used on the texture pool cache.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -165,7 +95,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
public TexturePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId)
|
public TexturePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId)
|
||||||
{
|
{
|
||||||
_channel = channel;
|
_channel = channel;
|
||||||
_aliasLists = new Dictionary<Texture, TextureAliasList>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -186,13 +115,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
{
|
{
|
||||||
|
TextureInfo info = GetInfo(descriptor, out int layerSize);
|
||||||
|
|
||||||
// The dereference queue can put our texture back on the cache.
|
// The dereference queue can put our texture back on the cache.
|
||||||
if ((texture = ProcessDereferenceQueue(id)) != null)
|
if ((texture = ProcessDereferenceQueue(id)) != null)
|
||||||
{
|
{
|
||||||
return ref descriptor;
|
return ref descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureInfo info = GetInfo(descriptor, out int layerSize);
|
|
||||||
texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize);
|
texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize);
|
||||||
|
|
||||||
// If this happens, then the texture address is invalid, we can't add it to the cache.
|
// If this happens, then the texture address is invalid, we can't add it to the cache.
|
||||||
|
|
@ -227,17 +157,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
|
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
|
||||||
/// <returns>The texture with the given ID</returns>
|
/// <returns>The texture with the given ID</returns>
|
||||||
public override Texture Get(int id)
|
public override Texture Get(int id)
|
||||||
{
|
|
||||||
return Get(id, srgbSampler: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the texture with the given ID.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
|
|
||||||
/// <param name="srgbSampler">Whether the texture is being accessed with a sampler that has sRGB conversion enabled</param>
|
|
||||||
/// <returns>The texture with the given ID</returns>
|
|
||||||
public Texture Get(int id, bool srgbSampler)
|
|
||||||
{
|
{
|
||||||
if ((uint)id >= Items.Length)
|
if ((uint)id >= Items.Length)
|
||||||
{
|
{
|
||||||
|
|
@ -251,7 +170,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
SynchronizeMemory();
|
SynchronizeMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
GetForBinding(id, srgbSampler, out Texture texture);
|
GetInternal(id, out Texture texture);
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
@ -263,10 +182,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// This method assumes that the pool has been manually synchronized before doing binding.
|
/// This method assumes that the pool has been manually synchronized before doing binding.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
|
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
|
||||||
/// <param name="srgbSampler">Whether the texture is being accessed with a sampler that has sRGB conversion enabled</param>
|
|
||||||
/// <param name="texture">The texture with the given ID</param>
|
/// <param name="texture">The texture with the given ID</param>
|
||||||
/// <returns>The texture descriptor with the given ID</returns>
|
/// <returns>The texture descriptor with the given ID</returns>
|
||||||
public ref readonly TextureDescriptor GetForBinding(int id, bool srgbSampler, out Texture texture)
|
public ref readonly TextureDescriptor GetForBinding(int id, out Texture texture)
|
||||||
{
|
{
|
||||||
if ((uint)id >= Items.Length)
|
if ((uint)id >= Items.Length)
|
||||||
{
|
{
|
||||||
|
|
@ -276,66 +194,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
// When getting for binding, assume the pool has already been synchronized.
|
// When getting for binding, assume the pool has already been synchronized.
|
||||||
|
|
||||||
if (!srgbSampler)
|
|
||||||
{
|
|
||||||
// If the sampler does not have the sRGB bit enabled, then the texture can't use a sRGB format.
|
|
||||||
ref readonly TextureDescriptor tempDescriptor = ref GetDescriptorRef(id);
|
|
||||||
|
|
||||||
if (tempDescriptor.UnpackSrgb() && FormatTable.TryGetTextureFormat(tempDescriptor.UnpackFormat(), isSrgb: false, out FormatInfo formatInfo))
|
|
||||||
{
|
|
||||||
// Get a view of the texture with the right format.
|
|
||||||
return ref GetForBinding(id, formatInfo, out texture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ref GetInternal(id, out texture);
|
return ref GetInternal(id, out texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the texture descriptor and texture with the given ID.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This method assumes that the pool has been manually synchronized before doing binding.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
|
|
||||||
/// <param name="formatInfo">Texture format information</param>
|
|
||||||
/// <param name="texture">The texture with the given ID</param>
|
|
||||||
/// <returns>The texture descriptor with the given ID</returns>
|
|
||||||
public ref readonly TextureDescriptor GetForBinding(int id, FormatInfo formatInfo, out Texture texture)
|
|
||||||
{
|
|
||||||
if ((uint)id >= Items.Length)
|
|
||||||
{
|
|
||||||
texture = null;
|
|
||||||
return ref _defaultDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
ref readonly TextureDescriptor descriptor = ref GetInternal(id, out texture);
|
|
||||||
|
|
||||||
if (texture != null && formatInfo.Format != 0 && texture.Format != formatInfo.Format)
|
|
||||||
{
|
|
||||||
if (!_aliasLists.TryGetValue(texture, out TextureAliasList aliasList))
|
|
||||||
{
|
|
||||||
_aliasLists.Add(texture, aliasList = new TextureAliasList());
|
|
||||||
}
|
|
||||||
|
|
||||||
texture = aliasList.Find(formatInfo.Format);
|
|
||||||
|
|
||||||
if (texture == null)
|
|
||||||
{
|
|
||||||
TextureInfo info = GetInfo(descriptor, out int layerSize);
|
|
||||||
info = ChangeFormat(info, formatInfo);
|
|
||||||
texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize);
|
|
||||||
|
|
||||||
if (texture != null)
|
|
||||||
{
|
|
||||||
aliasList.Add(formatInfo.Format, texture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ref descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the pool was modified, and returns the last sequence number where a modification was detected.
|
/// Checks if the pool was modified, and returns the last sequence number where a modification was detected.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -373,7 +234,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
texture.DecrementReferenceCount();
|
texture.DecrementReferenceCount();
|
||||||
RemoveAliasList(texture);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -467,8 +327,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
texture.DecrementReferenceCount();
|
texture.DecrementReferenceCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveAliasList(texture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -511,7 +369,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
if (Interlocked.Exchange(ref Items[id], null) != null)
|
if (Interlocked.Exchange(ref Items[id], null) != null)
|
||||||
{
|
{
|
||||||
texture.DecrementReferenceCount(this, id);
|
texture.DecrementReferenceCount(this, id);
|
||||||
RemoveAliasList(texture);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -765,57 +622,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
component == SwizzleComponent.Green;
|
component == SwizzleComponent.Green;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Changes the format on the texture information structure, and also adjusts the width for the new format if needed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="info">Texture information</param>
|
|
||||||
/// <param name="dstFormat">New format</param>
|
|
||||||
/// <returns>Texture information with the new format</returns>
|
|
||||||
private static TextureInfo ChangeFormat(in TextureInfo info, FormatInfo dstFormat)
|
|
||||||
{
|
|
||||||
int width = info.Width;
|
|
||||||
|
|
||||||
if (info.FormatInfo.BytesPerPixel != dstFormat.BytesPerPixel)
|
|
||||||
{
|
|
||||||
int stride = width * info.FormatInfo.BytesPerPixel;
|
|
||||||
width = stride / dstFormat.BytesPerPixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new TextureInfo(
|
|
||||||
info.GpuAddress,
|
|
||||||
width,
|
|
||||||
info.Height,
|
|
||||||
info.DepthOrLayers,
|
|
||||||
info.Levels,
|
|
||||||
info.SamplesInX,
|
|
||||||
info.SamplesInY,
|
|
||||||
info.Stride,
|
|
||||||
info.IsLinear,
|
|
||||||
info.GobBlocksInY,
|
|
||||||
info.GobBlocksInZ,
|
|
||||||
info.GobBlocksInTileX,
|
|
||||||
info.Target,
|
|
||||||
dstFormat,
|
|
||||||
info.DepthStencilMode,
|
|
||||||
info.SwizzleR,
|
|
||||||
info.SwizzleG,
|
|
||||||
info.SwizzleB,
|
|
||||||
info.SwizzleA);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes all aliases for a texture.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="texture">Texture to have the aliases removed</param>
|
|
||||||
private void RemoveAliasList(Texture texture)
|
|
||||||
{
|
|
||||||
if (_aliasLists.TryGetValue(texture, out TextureAliasList aliasList))
|
|
||||||
{
|
|
||||||
_aliasLists.Remove(texture);
|
|
||||||
aliasList.Destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decrements the reference count of the texture.
|
/// Decrements the reference count of the texture.
|
||||||
/// This indicates that the texture pool is not using it anymore.
|
/// This indicates that the texture pool is not using it anymore.
|
||||||
|
|
@ -823,11 +629,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <param name="item">The texture to be deleted</param>
|
/// <param name="item">The texture to be deleted</param>
|
||||||
protected override void Delete(Texture item)
|
protected override void Delete(Texture item)
|
||||||
{
|
{
|
||||||
if (item != null)
|
item?.DecrementReferenceCount(this);
|
||||||
{
|
|
||||||
item.DecrementReferenceCount(this);
|
|
||||||
RemoveAliasList(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
|
|
|
||||||
|
|
@ -509,7 +509,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
if (binding.IsImage)
|
if (binding.IsImage)
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.SetImage(binding.Stage, binding.BindingInfo.Binding, binding.Texture);
|
_context.Renderer.Pipeline.SetImage(binding.Stage, binding.BindingInfo.Binding, binding.Texture, binding.Format);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -873,11 +873,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
ITexture texture,
|
ITexture texture,
|
||||||
MultiRange range,
|
MultiRange range,
|
||||||
TextureBindingInfo bindingInfo,
|
TextureBindingInfo bindingInfo,
|
||||||
|
Format format,
|
||||||
bool isImage)
|
bool isImage)
|
||||||
{
|
{
|
||||||
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
|
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
|
||||||
|
|
||||||
_bufferTextures.Add(new BufferTextureBinding(stage, texture, range, bindingInfo, isImage));
|
_bufferTextures.Add(new BufferTextureBinding(stage, texture, range, bindingInfo, format, isImage));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -896,11 +897,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
ITexture texture,
|
ITexture texture,
|
||||||
MultiRange range,
|
MultiRange range,
|
||||||
TextureBindingInfo bindingInfo,
|
TextureBindingInfo bindingInfo,
|
||||||
int index)
|
int index,
|
||||||
|
Format format)
|
||||||
{
|
{
|
||||||
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
|
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
|
||||||
|
|
||||||
_bufferTextureArrays.Add(new BufferTextureArrayBinding<ITextureArray>(array, texture, range, bindingInfo, index));
|
_bufferTextureArrays.Add(new BufferTextureArrayBinding<ITextureArray>(array, texture, range, bindingInfo, index, format));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -919,11 +921,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
ITexture texture,
|
ITexture texture,
|
||||||
MultiRange range,
|
MultiRange range,
|
||||||
TextureBindingInfo bindingInfo,
|
TextureBindingInfo bindingInfo,
|
||||||
int index)
|
int index,
|
||||||
|
Format format)
|
||||||
{
|
{
|
||||||
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
|
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
|
||||||
|
|
||||||
_bufferImageArrays.Add(new BufferTextureArrayBinding<IImageArray>(array, texture, range, bindingInfo, index));
|
_bufferImageArrays.Add(new BufferTextureArrayBinding<IImageArray>(array, texture, range, bindingInfo, index, format));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -34,26 +34,33 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Index { get; }
|
public int Index { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The image format for the binding.
|
||||||
|
/// </summary>
|
||||||
|
public Format Format { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new buffer texture binding.
|
/// Create a new buffer texture binding.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="array">Array</param>
|
|
||||||
/// <param name="texture">Buffer texture</param>
|
/// <param name="texture">Buffer texture</param>
|
||||||
/// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
|
/// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
|
||||||
/// <param name="bindingInfo">Binding info</param>
|
/// <param name="bindingInfo">Binding info</param>
|
||||||
/// <param name="index">Index of the binding on the array</param>
|
/// <param name="index">Index of the binding on the array</param>
|
||||||
|
/// <param name="format">Binding format</param>
|
||||||
public BufferTextureArrayBinding(
|
public BufferTextureArrayBinding(
|
||||||
T array,
|
T array,
|
||||||
ITexture texture,
|
ITexture texture,
|
||||||
MultiRange range,
|
MultiRange range,
|
||||||
TextureBindingInfo bindingInfo,
|
TextureBindingInfo bindingInfo,
|
||||||
int index)
|
int index,
|
||||||
|
Format format)
|
||||||
{
|
{
|
||||||
Array = array;
|
Array = array;
|
||||||
Texture = texture;
|
Texture = texture;
|
||||||
Range = range;
|
Range = range;
|
||||||
BindingInfo = bindingInfo;
|
BindingInfo = bindingInfo;
|
||||||
Index = index;
|
Index = index;
|
||||||
|
Format = format;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TextureBindingInfo BindingInfo { get; }
|
public TextureBindingInfo BindingInfo { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The image format for the binding.
|
||||||
|
/// </summary>
|
||||||
|
public Format Format { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the binding is for an image or a sampler.
|
/// Whether the binding is for an image or a sampler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -42,18 +47,21 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// <param name="texture">Buffer texture</param>
|
/// <param name="texture">Buffer texture</param>
|
||||||
/// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
|
/// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
|
||||||
/// <param name="bindingInfo">Binding info</param>
|
/// <param name="bindingInfo">Binding info</param>
|
||||||
|
/// <param name="format">Binding format</param>
|
||||||
/// <param name="isImage">Whether the binding is for an image or a sampler</param>
|
/// <param name="isImage">Whether the binding is for an image or a sampler</param>
|
||||||
public BufferTextureBinding(
|
public BufferTextureBinding(
|
||||||
ShaderStage stage,
|
ShaderStage stage,
|
||||||
ITexture texture,
|
ITexture texture,
|
||||||
MultiRange range,
|
MultiRange range,
|
||||||
TextureBindingInfo bindingInfo,
|
TextureBindingInfo bindingInfo,
|
||||||
|
Format format,
|
||||||
bool isImage)
|
bool isImage)
|
||||||
{
|
{
|
||||||
Stage = stage;
|
Stage = stage;
|
||||||
Texture = texture;
|
Texture = texture;
|
||||||
Range = range;
|
Range = range;
|
||||||
BindingInfo = bindingInfo;
|
BindingInfo = bindingInfo;
|
||||||
|
Format = format;
|
||||||
IsImage = isImage;
|
IsImage = isImage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,11 +86,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
ImageBindings[i] = stage.Info.Images.Select(descriptor =>
|
ImageBindings[i] = stage.Info.Images.Select(descriptor =>
|
||||||
{
|
{
|
||||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||||
FormatInfo formatInfo = ShaderTexture.GetFormatInfo(descriptor.Format);
|
Format format = ShaderTexture.GetFormat(descriptor.Format);
|
||||||
|
|
||||||
var result = new TextureBindingInfo(
|
var result = new TextureBindingInfo(
|
||||||
target,
|
target,
|
||||||
formatInfo,
|
format,
|
||||||
descriptor.Set,
|
descriptor.Set,
|
||||||
descriptor.Binding,
|
descriptor.Binding,
|
||||||
descriptor.ArrayLength,
|
descriptor.ArrayLength,
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
bool isLinear,
|
bool isLinear,
|
||||||
int gobBlocksInY,
|
int gobBlocksInY,
|
||||||
Format format,
|
Format format,
|
||||||
byte bytesPerPixel,
|
int bytesPerPixel,
|
||||||
ImageCrop crop,
|
ImageCrop crop,
|
||||||
Action<GpuContext, object> acquireCallback,
|
Action<GpuContext, object> acquireCallback,
|
||||||
Action<object> releaseCallback,
|
Action<object> releaseCallback,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.OpenGL.Image
|
namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
{
|
{
|
||||||
|
|
@ -18,6 +19,14 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
_images = new TextureRef[size];
|
_images = new TextureRef[size];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetFormats(int index, GAL.Format[] imageFormats)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < imageFormats.Length; i++)
|
||||||
|
{
|
||||||
|
_images[index + i].Format = imageFormats[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SetImages(int index, ITexture[] images)
|
public void SetImages(int index, ITexture[] images)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < images.Length; i++)
|
for (int i = 0; i < images.Length; i++)
|
||||||
|
|
@ -27,7 +36,6 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
if (image is TextureBase imageBase)
|
if (image is TextureBase imageBase)
|
||||||
{
|
{
|
||||||
_images[index + i].Handle = imageBase.Handle;
|
_images[index + i].Handle = imageBase.Handle;
|
||||||
_images[index + i].Format = imageBase.Format;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
private readonly Vector4<int>[] _fpIsBgra = new Vector4<int>[SupportBuffer.FragmentIsBgraCount];
|
private readonly Vector4<int>[] _fpIsBgra = new Vector4<int>[SupportBuffer.FragmentIsBgraCount];
|
||||||
|
|
||||||
private readonly TextureBase[] _images;
|
private readonly (TextureBase, Format)[] _images;
|
||||||
private TextureBase _unit0Texture;
|
private TextureBase _unit0Texture;
|
||||||
private Sampler _unit0Sampler;
|
private Sampler _unit0Sampler;
|
||||||
|
|
||||||
|
|
@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
_fragmentOutputMap = uint.MaxValue;
|
_fragmentOutputMap = uint.MaxValue;
|
||||||
_componentMasks = uint.MaxValue;
|
_componentMasks = uint.MaxValue;
|
||||||
|
|
||||||
_images = new TextureBase[SavedImages];
|
_images = new (TextureBase, Format)[SavedImages];
|
||||||
|
|
||||||
_tfbs = new BufferHandle[Constants.MaxTransformFeedbackBuffers];
|
_tfbs = new BufferHandle[Constants.MaxTransformFeedbackBuffers];
|
||||||
_tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers];
|
_tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers];
|
||||||
|
|
@ -935,11 +935,11 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
SetFrontFace(_frontFace = frontFace.Convert());
|
SetFrontFace(_frontFace = frontFace.Convert());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetImage(ShaderStage stage, int binding, ITexture texture)
|
public void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat)
|
||||||
{
|
{
|
||||||
if ((uint)binding < SavedImages)
|
if ((uint)binding < SavedImages)
|
||||||
{
|
{
|
||||||
_images[binding] = texture as TextureBase;
|
_images[binding] = (texture as TextureBase, imageFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
|
|
@ -950,7 +950,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
TextureBase texBase = (TextureBase)texture;
|
TextureBase texBase = (TextureBase)texture;
|
||||||
|
|
||||||
SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format);
|
SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat);
|
||||||
|
|
||||||
if (format != 0)
|
if (format != 0)
|
||||||
{
|
{
|
||||||
|
|
@ -1622,11 +1622,11 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
for (int i = 0; i < SavedImages; i++)
|
for (int i = 0; i < SavedImages; i++)
|
||||||
{
|
{
|
||||||
TextureBase texBase = _images[i];
|
(TextureBase texBase, Format imageFormat) = _images[i];
|
||||||
|
|
||||||
if (texBase != null)
|
if (texBase != null)
|
||||||
{
|
{
|
||||||
SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format);
|
SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat);
|
||||||
|
|
||||||
if (format != 0)
|
if (format != 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
CommandBuffer
|
CommandBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _feedbackLoopActive;
|
|
||||||
private PipelineStageFlags _incoherentBufferWriteStages;
|
private PipelineStageFlags _incoherentBufferWriteStages;
|
||||||
private PipelineStageFlags _incoherentTextureWriteStages;
|
private PipelineStageFlags _incoherentTextureWriteStages;
|
||||||
private PipelineStageFlags _extraStages;
|
private PipelineStageFlags _extraStages;
|
||||||
private IncoherentBarrierType _queuedIncoherentBarrier;
|
private IncoherentBarrierType _queuedIncoherentBarrier;
|
||||||
private bool _queuedFeedbackLoopBarrier;
|
|
||||||
|
|
||||||
public BarrierBatch(VulkanRenderer gd)
|
public BarrierBatch(VulkanRenderer gd)
|
||||||
{
|
{
|
||||||
|
|
@ -55,6 +53,17 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
stages |= PipelineStageFlags.TransformFeedbackBitExt;
|
stages |= PipelineStageFlags.TransformFeedbackBitExt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!gd.IsTBDR)
|
||||||
|
{
|
||||||
|
// Desktop GPUs can transform image barriers into memory barriers.
|
||||||
|
|
||||||
|
access |= AccessFlags.DepthStencilAttachmentWriteBit | AccessFlags.ColorAttachmentWriteBit;
|
||||||
|
access |= AccessFlags.DepthStencilAttachmentReadBit | AccessFlags.ColorAttachmentReadBit;
|
||||||
|
|
||||||
|
stages |= PipelineStageFlags.EarlyFragmentTestsBit | PipelineStageFlags.LateFragmentTestsBit;
|
||||||
|
stages |= PipelineStageFlags.ColorAttachmentOutputBit;
|
||||||
|
}
|
||||||
|
|
||||||
return (access, stages);
|
return (access, stages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,34 +178,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
_queuedIncoherentBarrier = IncoherentBarrierType.None;
|
_queuedIncoherentBarrier = IncoherentBarrierType.None;
|
||||||
_queuedFeedbackLoopBarrier = false;
|
|
||||||
}
|
}
|
||||||
else if (_feedbackLoopActive && _queuedFeedbackLoopBarrier)
|
|
||||||
{
|
|
||||||
// Feedback loop barrier.
|
|
||||||
|
|
||||||
MemoryBarrier barrier = new MemoryBarrier()
|
|
||||||
{
|
|
||||||
SType = StructureType.MemoryBarrier,
|
|
||||||
SrcAccessMask = AccessFlags.ShaderWriteBit,
|
|
||||||
DstAccessMask = AccessFlags.ShaderReadBit
|
|
||||||
};
|
|
||||||
|
|
||||||
QueueBarrier(barrier, PipelineStageFlags.FragmentShaderBit, PipelineStageFlags.AllGraphicsBit);
|
|
||||||
|
|
||||||
_queuedFeedbackLoopBarrier = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_feedbackLoopActive = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void Flush(CommandBufferScoped cbs, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
public unsafe void Flush(CommandBufferScoped cbs, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
||||||
{
|
{
|
||||||
Flush(cbs, null, false, inRenderPass, rpHolder, endRenderPass);
|
Flush(cbs, null, inRenderPass, rpHolder, endRenderPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void Flush(CommandBufferScoped cbs, ShaderCollection program, bool feedbackLoopActive, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
public unsafe void Flush(CommandBufferScoped cbs, ShaderCollection program, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
||||||
{
|
{
|
||||||
if (program != null)
|
if (program != null)
|
||||||
{
|
{
|
||||||
|
|
@ -204,8 +195,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_incoherentTextureWriteStages |= program.IncoherentTextureWriteStages;
|
_incoherentTextureWriteStages |= program.IncoherentTextureWriteStages;
|
||||||
}
|
}
|
||||||
|
|
||||||
_feedbackLoopActive |= feedbackLoopActive;
|
|
||||||
|
|
||||||
FlushMemoryBarrier(program, inRenderPass);
|
FlushMemoryBarrier(program, inRenderPass);
|
||||||
|
|
||||||
if (!inRenderPass && rpHolder != null)
|
if (!inRenderPass && rpHolder != null)
|
||||||
|
|
@ -417,8 +406,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
_queuedIncoherentBarrier = type;
|
_queuedIncoherentBarrier = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
_queuedFeedbackLoopBarrier = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void QueueTextureBarrier()
|
public void QueueTextureBarrier()
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ using Ryujinx.Graphics.Shader;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
|
using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
|
||||||
|
|
@ -43,15 +42,15 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private record struct TextureRef
|
private record struct TextureRef
|
||||||
{
|
{
|
||||||
public ShaderStage Stage;
|
public ShaderStage Stage;
|
||||||
public TextureView View;
|
public TextureStorage Storage;
|
||||||
public Auto<DisposableImageView> ImageView;
|
public Auto<DisposableImageView> View;
|
||||||
public Auto<DisposableSampler> Sampler;
|
public Auto<DisposableSampler> Sampler;
|
||||||
|
|
||||||
public TextureRef(ShaderStage stage, TextureView view, Auto<DisposableImageView> imageView, Auto<DisposableSampler> sampler)
|
public TextureRef(ShaderStage stage, TextureStorage storage, Auto<DisposableImageView> view, Auto<DisposableSampler> sampler)
|
||||||
{
|
{
|
||||||
Stage = stage;
|
Stage = stage;
|
||||||
|
Storage = storage;
|
||||||
View = view;
|
View = view;
|
||||||
ImageView = imageView;
|
|
||||||
Sampler = sampler;
|
Sampler = sampler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -59,14 +58,14 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private record struct ImageRef
|
private record struct ImageRef
|
||||||
{
|
{
|
||||||
public ShaderStage Stage;
|
public ShaderStage Stage;
|
||||||
public TextureView View;
|
public TextureStorage Storage;
|
||||||
public Auto<DisposableImageView> ImageView;
|
public Auto<DisposableImageView> View;
|
||||||
|
|
||||||
public ImageRef(ShaderStage stage, TextureView view, Auto<DisposableImageView> imageView)
|
public ImageRef(ShaderStage stage, TextureStorage storage, Auto<DisposableImageView> view)
|
||||||
{
|
{
|
||||||
Stage = stage;
|
Stage = stage;
|
||||||
|
Storage = storage;
|
||||||
View = view;
|
View = view;
|
||||||
ImageView = imageView;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,6 +81,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private readonly ImageRef[] _imageRefs;
|
private readonly ImageRef[] _imageRefs;
|
||||||
private readonly TextureBuffer[] _bufferTextureRefs;
|
private readonly TextureBuffer[] _bufferTextureRefs;
|
||||||
private readonly TextureBuffer[] _bufferImageRefs;
|
private readonly TextureBuffer[] _bufferImageRefs;
|
||||||
|
private readonly Format[] _bufferImageFormats;
|
||||||
|
|
||||||
private ArrayRef<TextureArray>[] _textureArrayRefs;
|
private ArrayRef<TextureArray>[] _textureArrayRefs;
|
||||||
private ArrayRef<ImageArray>[] _imageArrayRefs;
|
private ArrayRef<ImageArray>[] _imageArrayRefs;
|
||||||
|
|
@ -124,8 +124,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private readonly TextureView _dummyTexture;
|
private readonly TextureView _dummyTexture;
|
||||||
private readonly SamplerHolder _dummySampler;
|
private readonly SamplerHolder _dummySampler;
|
||||||
|
|
||||||
public List<TextureView> FeedbackLoopHazards { get; private set; }
|
|
||||||
|
|
||||||
public DescriptorSetUpdater(VulkanRenderer gd, Device device)
|
public DescriptorSetUpdater(VulkanRenderer gd, Device device)
|
||||||
{
|
{
|
||||||
_gd = gd;
|
_gd = gd;
|
||||||
|
|
@ -140,6 +138,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_imageRefs = new ImageRef[Constants.MaxImageBindings * 2];
|
_imageRefs = new ImageRef[Constants.MaxImageBindings * 2];
|
||||||
_bufferTextureRefs = new TextureBuffer[Constants.MaxTextureBindings * 2];
|
_bufferTextureRefs = new TextureBuffer[Constants.MaxTextureBindings * 2];
|
||||||
_bufferImageRefs = new TextureBuffer[Constants.MaxImageBindings * 2];
|
_bufferImageRefs = new TextureBuffer[Constants.MaxImageBindings * 2];
|
||||||
|
_bufferImageFormats = new Format[Constants.MaxImageBindings * 2];
|
||||||
|
|
||||||
_textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>();
|
_textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>();
|
||||||
_imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>();
|
_imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>();
|
||||||
|
|
@ -210,15 +209,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_templateUpdater = new();
|
_templateUpdater = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(bool isMainPipeline)
|
public void Initialize()
|
||||||
{
|
{
|
||||||
MemoryOwner<byte> dummyTextureData = MemoryOwner<byte>.RentCleared(4);
|
MemoryOwner<byte> dummyTextureData = MemoryOwner<byte>.RentCleared(4);
|
||||||
_dummyTexture.SetData(dummyTextureData);
|
_dummyTexture.SetData(dummyTextureData);
|
||||||
|
|
||||||
if (isMainPipeline)
|
|
||||||
{
|
|
||||||
FeedbackLoopHazards = new();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool BindingOverlaps(ref DescriptorBufferInfo info, int bindingOffset, int offset, int size)
|
private static bool BindingOverlaps(ref DescriptorBufferInfo info, int bindingOffset, int offset, int size)
|
||||||
|
|
@ -281,18 +275,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
public void InsertBindingBarriers(CommandBufferScoped cbs)
|
public void InsertBindingBarriers(CommandBufferScoped cbs)
|
||||||
{
|
{
|
||||||
if ((FeedbackLoopHazards?.Count ?? 0) > 0)
|
|
||||||
{
|
|
||||||
// Clear existing hazards - they will be rebuilt.
|
|
||||||
|
|
||||||
foreach (TextureView hazard in FeedbackLoopHazards)
|
|
||||||
{
|
|
||||||
hazard.DecrementHazardUses();
|
|
||||||
}
|
|
||||||
|
|
||||||
FeedbackLoopHazards.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (ResourceBindingSegment segment in _program.BindingSegments[PipelineBase.TextureSetIndex])
|
foreach (ResourceBindingSegment segment in _program.BindingSegments[PipelineBase.TextureSetIndex])
|
||||||
{
|
{
|
||||||
if (segment.Type == ResourceType.TextureAndSampler)
|
if (segment.Type == ResourceType.TextureAndSampler)
|
||||||
|
|
@ -302,7 +284,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
for (int i = 0; i < segment.Count; i++)
|
for (int i = 0; i < segment.Count; i++)
|
||||||
{
|
{
|
||||||
ref var texture = ref _textureRefs[segment.Binding + i];
|
ref var texture = ref _textureRefs[segment.Binding + i];
|
||||||
texture.View?.PrepareForUsage(cbs, texture.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
texture.Storage?.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, texture.Stage.ConvertToPipelineStageFlags());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -323,7 +305,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
for (int i = 0; i < segment.Count; i++)
|
for (int i = 0; i < segment.Count; i++)
|
||||||
{
|
{
|
||||||
ref var image = ref _imageRefs[segment.Binding + i];
|
ref var image = ref _imageRefs[segment.Binding + i];
|
||||||
image.View?.PrepareForUsage(cbs, image.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
image.Storage?.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, image.Stage.ConvertToPipelineStageFlags());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -389,25 +371,29 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_dirty = DirtyFlags.All;
|
_dirty = DirtyFlags.All;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetImage(CommandBufferScoped cbs, ShaderStage stage, int binding, ITexture image)
|
public void SetImage(
|
||||||
|
CommandBufferScoped cbs,
|
||||||
|
ShaderStage stage,
|
||||||
|
int binding,
|
||||||
|
ITexture image,
|
||||||
|
Format imageFormat)
|
||||||
{
|
{
|
||||||
if (image is TextureBuffer imageBuffer)
|
if (image is TextureBuffer imageBuffer)
|
||||||
{
|
{
|
||||||
_bufferImageRefs[binding] = imageBuffer;
|
_bufferImageRefs[binding] = imageBuffer;
|
||||||
|
_bufferImageFormats[binding] = imageFormat;
|
||||||
}
|
}
|
||||||
else if (image is TextureView view)
|
else if (image is TextureView view)
|
||||||
{
|
{
|
||||||
ref ImageRef iRef = ref _imageRefs[binding];
|
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
||||||
|
|
||||||
iRef.View?.ClearUsage(FeedbackLoopHazards);
|
_imageRefs[binding] = new(stage, view.Storage, view.GetView(imageFormat).GetIdentityImageView());
|
||||||
view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
|
||||||
|
|
||||||
iRef = new(stage, view, view.GetIdentityImageView());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_imageRefs[binding] = default;
|
_imageRefs[binding] = default;
|
||||||
_bufferImageRefs[binding] = null;
|
_bufferImageRefs[binding] = null;
|
||||||
|
_bufferImageFormats[binding] = default;
|
||||||
}
|
}
|
||||||
|
|
||||||
SignalDirty(DirtyFlags.Image);
|
SignalDirty(DirtyFlags.Image);
|
||||||
|
|
@ -500,12 +486,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
else if (texture is TextureView view)
|
else if (texture is TextureView view)
|
||||||
{
|
{
|
||||||
ref TextureRef iRef = ref _textureRefs[binding];
|
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
||||||
|
|
||||||
iRef.View?.ClearUsage(FeedbackLoopHazards);
|
_textureRefs[binding] = new(stage, view.Storage, view.GetImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
||||||
view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
|
||||||
|
|
||||||
iRef = new(stage, view, view.GetImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -527,7 +510,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
||||||
|
|
||||||
_textureRefs[binding] = new(stage, view, view.GetIdentityImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
_textureRefs[binding] = new(stage, view.Storage, view.GetIdentityImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
||||||
|
|
||||||
SignalDirty(DirtyFlags.Texture);
|
SignalDirty(DirtyFlags.Texture);
|
||||||
}
|
}
|
||||||
|
|
@ -853,7 +836,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
ref var texture = ref textures[i];
|
ref var texture = ref textures[i];
|
||||||
ref var refs = ref _textureRefs[binding + i];
|
ref var refs = ref _textureRefs[binding + i];
|
||||||
|
|
||||||
texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default;
|
texture.ImageView = refs.View?.Get(cbs).Value ?? default;
|
||||||
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
|
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
|
||||||
|
|
||||||
if (texture.ImageView.Handle == 0)
|
if (texture.ImageView.Handle == 0)
|
||||||
|
|
@ -903,7 +886,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
images[i].ImageView = _imageRefs[binding + i].ImageView?.Get(cbs).Value ?? default;
|
images[i].ImageView = _imageRefs[binding + i].View?.Get(cbs).Value ?? default;
|
||||||
}
|
}
|
||||||
|
|
||||||
tu.Push<DescriptorImageInfo>(images[..count]);
|
tu.Push<DescriptorImageInfo>(images[..count]);
|
||||||
|
|
@ -914,7 +897,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, true) ?? default;
|
bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, _bufferImageFormats[binding + i], true) ?? default;
|
||||||
}
|
}
|
||||||
|
|
||||||
tu.Push<BufferView>(bufferImages[..count]);
|
tu.Push<BufferView>(bufferImages[..count]);
|
||||||
|
|
@ -974,7 +957,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
ref var texture = ref textures[i];
|
ref var texture = ref textures[i];
|
||||||
ref var refs = ref _textureRefs[binding + i];
|
ref var refs = ref _textureRefs[binding + i];
|
||||||
|
|
||||||
texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default;
|
texture.ImageView = refs.View?.Get(cbs).Value ?? default;
|
||||||
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
|
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
|
||||||
|
|
||||||
if (texture.ImageView.Handle == 0)
|
if (texture.ImageView.Handle == 0)
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
|
||||||
_pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
_pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
|
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
|
||||||
var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
|
var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
|
||||||
|
|
||||||
_pipeline.SetImage(ShaderStage.Compute, 0, _texture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
_pipeline.SetImage(ShaderStage.Compute, 0, _texture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
|
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
|
|
||||||
buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer);
|
buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer);
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
|
||||||
_pipeline.SetImage(ShaderStage.Compute, 0, _edgeOutputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
_pipeline.SetImage(ShaderStage.Compute, 0, _edgeOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
||||||
|
|
@ -229,7 +229,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _edgeOutputTexture, _samplerLinear);
|
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _edgeOutputTexture, _samplerLinear);
|
||||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _areaTexture, _samplerLinear);
|
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _areaTexture, _samplerLinear);
|
||||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 4, _searchTexture, _samplerLinear);
|
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 4, _searchTexture, _samplerLinear);
|
||||||
_pipeline.SetImage(ShaderStage.Compute, 0, _blendOutputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
_pipeline.SetImage(ShaderStage.Compute, 0, _blendOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
||||||
|
|
@ -238,7 +238,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
_pipeline.Specialize(_specConstants);
|
_pipeline.Specialize(_specConstants);
|
||||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _blendOutputTexture, _samplerLinear);
|
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _blendOutputTexture, _samplerLinear);
|
||||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _samplerLinear);
|
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _samplerLinear);
|
||||||
_pipeline.SetImage(ShaderStage.Compute, 0, _outputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
_pipeline.SetImage(ShaderStage.Compute, 0, _outputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
|
||||||
{
|
|
||||||
[Flags]
|
|
||||||
internal enum FeedbackLoopAspects
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
Color = 1 << 0,
|
|
||||||
Depth = 1 << 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -302,27 +302,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_depthStencil?.Storage?.AddStoreOpUsage(true);
|
_depthStencil?.Storage?.AddStoreOpUsage(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearBindings()
|
|
||||||
{
|
|
||||||
_depthStencil?.Storage.ClearBindings();
|
|
||||||
|
|
||||||
for (int i = 0; i < _colorsCanonical.Length; i++)
|
|
||||||
{
|
|
||||||
_colorsCanonical[i]?.Storage.ClearBindings();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddBindings()
|
|
||||||
{
|
|
||||||
_depthStencil?.Storage.AddBinding(_depthStencil);
|
|
||||||
|
|
||||||
for (int i = 0; i < _colorsCanonical.Length; i++)
|
|
||||||
{
|
|
||||||
TextureView color = _colorsCanonical[i];
|
|
||||||
color?.Storage.AddBinding(color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
|
public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
|
||||||
VulkanRenderer gd,
|
VulkanRenderer gd,
|
||||||
Device device,
|
Device device,
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
public readonly bool SupportsViewportArray2;
|
public readonly bool SupportsViewportArray2;
|
||||||
public readonly bool SupportsHostImportedMemory;
|
public readonly bool SupportsHostImportedMemory;
|
||||||
public readonly bool SupportsDepthClipControl;
|
public readonly bool SupportsDepthClipControl;
|
||||||
public readonly bool SupportsAttachmentFeedbackLoop;
|
|
||||||
public readonly bool SupportsDynamicAttachmentFeedbackLoop;
|
|
||||||
public readonly uint SubgroupSize;
|
public readonly uint SubgroupSize;
|
||||||
public readonly SampleCountFlags SupportedSampleCounts;
|
public readonly SampleCountFlags SupportedSampleCounts;
|
||||||
public readonly PortabilitySubsetFlags PortabilitySubset;
|
public readonly PortabilitySubsetFlags PortabilitySubset;
|
||||||
|
|
@ -86,8 +84,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
bool supportsViewportArray2,
|
bool supportsViewportArray2,
|
||||||
bool supportsHostImportedMemory,
|
bool supportsHostImportedMemory,
|
||||||
bool supportsDepthClipControl,
|
bool supportsDepthClipControl,
|
||||||
bool supportsAttachmentFeedbackLoop,
|
|
||||||
bool supportsDynamicAttachmentFeedbackLoop,
|
|
||||||
uint subgroupSize,
|
uint subgroupSize,
|
||||||
SampleCountFlags supportedSampleCounts,
|
SampleCountFlags supportedSampleCounts,
|
||||||
PortabilitySubsetFlags portabilitySubset,
|
PortabilitySubsetFlags portabilitySubset,
|
||||||
|
|
@ -125,8 +121,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
SupportsViewportArray2 = supportsViewportArray2;
|
SupportsViewportArray2 = supportsViewportArray2;
|
||||||
SupportsHostImportedMemory = supportsHostImportedMemory;
|
SupportsHostImportedMemory = supportsHostImportedMemory;
|
||||||
SupportsDepthClipControl = supportsDepthClipControl;
|
SupportsDepthClipControl = supportsDepthClipControl;
|
||||||
SupportsAttachmentFeedbackLoop = supportsAttachmentFeedbackLoop;
|
|
||||||
SupportsDynamicAttachmentFeedbackLoop = supportsDynamicAttachmentFeedbackLoop;
|
|
||||||
SubgroupSize = subgroupSize;
|
SubgroupSize = subgroupSize;
|
||||||
SupportedSampleCounts = supportedSampleCounts;
|
SupportedSampleCounts = supportedSampleCounts;
|
||||||
PortabilitySubset = portabilitySubset;
|
PortabilitySubset = portabilitySubset;
|
||||||
|
|
|
||||||
|
|
@ -1039,7 +1039,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
var dstView = Create2DLayerView(dst, dstLayer + z, dstLevel + l);
|
var dstView = Create2DLayerView(dst, dstLayer + z, dstLevel + l);
|
||||||
|
|
||||||
_pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null);
|
_pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null);
|
||||||
_pipeline.SetImage(ShaderStage.Compute, 0, dstView.GetView(dstFormat));
|
_pipeline.SetImage(ShaderStage.Compute, 0, dstView, dstFormat);
|
||||||
|
|
||||||
int dispatchX = (Math.Min(srcView.Info.Width, dstView.Info.Width) + 31) / 32;
|
int dispatchX = (Math.Min(srcView.Info.Width, dstView.Info.Width) + 31) / 32;
|
||||||
int dispatchY = (Math.Min(srcView.Info.Height, dstView.Info.Height) + 31) / 32;
|
int dispatchY = (Math.Min(srcView.Info.Height, dstView.Info.Height) + 31) / 32;
|
||||||
|
|
@ -1168,7 +1168,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
var dstView = Create2DLayerView(dst, dstLayer + z, 0);
|
var dstView = Create2DLayerView(dst, dstLayer + z, 0);
|
||||||
|
|
||||||
_pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null);
|
_pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null);
|
||||||
_pipeline.SetImage(ShaderStage.Compute, 0, dstView.GetView(format));
|
_pipeline.SetImage(ShaderStage.Compute, 0, dstView, format);
|
||||||
|
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
public TextureStorage Storage;
|
public TextureStorage Storage;
|
||||||
public TextureView View;
|
public TextureView View;
|
||||||
|
public GAL.Format ImageFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly TextureRef[] _textureRefs;
|
private readonly TextureRef[] _textureRefs;
|
||||||
|
|
@ -51,6 +52,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_isBuffer = isBuffer;
|
_isBuffer = isBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetFormats(int index, GAL.Format[] imageFormats)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < imageFormats.Length; i++)
|
||||||
|
{
|
||||||
|
_textureRefs[index + i].ImageFormat = imageFormats[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDirty();
|
||||||
|
}
|
||||||
|
|
||||||
public void SetImages(int index, ITexture[] images)
|
public void SetImages(int index, ITexture[] images)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < images.Length; i++)
|
for (int i = 0; i < images.Length; i++)
|
||||||
|
|
@ -131,7 +142,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
ref var texture = ref textures[i];
|
ref var texture = ref textures[i];
|
||||||
ref var refs = ref _textureRefs[i];
|
ref var refs = ref _textureRefs[i];
|
||||||
|
|
||||||
if (i > 0 && _textureRefs[i - 1].View == refs.View)
|
if (i > 0 && _textureRefs[i - 1].View == refs.View && _textureRefs[i - 1].ImageFormat == refs.ImageFormat)
|
||||||
{
|
{
|
||||||
texture = textures[i - 1];
|
texture = textures[i - 1];
|
||||||
|
|
||||||
|
|
@ -139,7 +150,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
texture.ImageLayout = ImageLayout.General;
|
texture.ImageLayout = ImageLayout.General;
|
||||||
texture.ImageView = refs.View?.GetIdentityImageView().Get(cbs).Value ?? default;
|
texture.ImageView = refs.View?.GetView(refs.ImageFormat).GetIdentityImageView().Get(cbs).Value ?? default;
|
||||||
|
|
||||||
if (texture.ImageView.Handle == 0)
|
if (texture.ImageView.Handle == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -156,7 +167,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
for (int i = 0; i < bufferTextures.Length; i++)
|
for (int i = 0; i < bufferTextures.Length; i++)
|
||||||
{
|
{
|
||||||
bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, true) ?? default;
|
bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, _textureRefs[i].ImageFormat, true) ?? default;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bufferTextures;
|
return bufferTextures;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
@ -34,7 +33,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
public readonly Action EndRenderPassDelegate;
|
public readonly Action EndRenderPassDelegate;
|
||||||
|
|
||||||
protected PipelineDynamicState DynamicState;
|
protected PipelineDynamicState DynamicState;
|
||||||
protected bool IsMainPipeline;
|
|
||||||
private PipelineState _newState;
|
private PipelineState _newState;
|
||||||
private bool _graphicsStateDirty;
|
private bool _graphicsStateDirty;
|
||||||
private bool _computeStateDirty;
|
private bool _computeStateDirty;
|
||||||
|
|
@ -87,9 +85,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private bool _tfEnabled;
|
private bool _tfEnabled;
|
||||||
private bool _tfActive;
|
private bool _tfActive;
|
||||||
|
|
||||||
private FeedbackLoopAspects _feedbackLoop;
|
|
||||||
private bool _passWritesDepthStencil;
|
|
||||||
|
|
||||||
private readonly PipelineColorBlendAttachmentState[] _storedBlend;
|
private readonly PipelineColorBlendAttachmentState[] _storedBlend;
|
||||||
public ulong DrawCount { get; private set; }
|
public ulong DrawCount { get; private set; }
|
||||||
public bool RenderPassActive { get; private set; }
|
public bool RenderPassActive { get; private set; }
|
||||||
|
|
@ -131,7 +126,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
_descriptorSetUpdater.Initialize(IsMainPipeline);
|
_descriptorSetUpdater.Initialize();
|
||||||
|
|
||||||
QuadsToTrisPattern = new IndexBufferPattern(Gd, 4, 6, 0, new[] { 0, 1, 2, 0, 2, 3 }, 4, false);
|
QuadsToTrisPattern = new IndexBufferPattern(Gd, 4, 6, 0, new[] { 0, 1, 2, 0, 2, 3 }, 4, false);
|
||||||
TriFanToTrisPattern = new IndexBufferPattern(Gd, 3, 3, 2, new[] { int.MinValue, -1, 0 }, 1, true);
|
TriFanToTrisPattern = new IndexBufferPattern(Gd, 3, 3, 2, new[] { int.MinValue, -1, 0 }, 1, true);
|
||||||
|
|
@ -819,8 +814,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_newState.DepthTestEnable = depthTest.TestEnable;
|
_newState.DepthTestEnable = depthTest.TestEnable;
|
||||||
_newState.DepthWriteEnable = depthTest.WriteEnable;
|
_newState.DepthWriteEnable = depthTest.WriteEnable;
|
||||||
_newState.DepthCompareOp = depthTest.Func.Convert();
|
_newState.DepthCompareOp = depthTest.Func.Convert();
|
||||||
|
|
||||||
UpdatePassDepthStencil();
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -836,9 +829,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetImage(ShaderStage stage, int binding, ITexture image)
|
public void SetImage(ShaderStage stage, int binding, ITexture image, Format imageFormat)
|
||||||
{
|
{
|
||||||
_descriptorSetUpdater.SetImage(Cbs, stage, binding, image);
|
_descriptorSetUpdater.SetImage(Cbs, stage, binding, image, imageFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetImage(int binding, Auto<DisposableImageView> image)
|
public void SetImage(int binding, Auto<DisposableImageView> image)
|
||||||
|
|
@ -1086,8 +1079,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_newState.StencilFrontPassOp = stencilTest.FrontDpPass.Convert();
|
_newState.StencilFrontPassOp = stencilTest.FrontDpPass.Convert();
|
||||||
_newState.StencilFrontDepthFailOp = stencilTest.FrontDpFail.Convert();
|
_newState.StencilFrontDepthFailOp = stencilTest.FrontDpFail.Convert();
|
||||||
_newState.StencilFrontCompareOp = stencilTest.FrontFunc.Convert();
|
_newState.StencilFrontCompareOp = stencilTest.FrontFunc.Convert();
|
||||||
|
|
||||||
UpdatePassDepthStencil();
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1435,23 +1426,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsMainPipeline)
|
|
||||||
{
|
|
||||||
FramebufferParams?.ClearBindings();
|
|
||||||
}
|
|
||||||
|
|
||||||
FramebufferParams = new FramebufferParams(Device, colors, depthStencil);
|
FramebufferParams = new FramebufferParams(Device, colors, depthStencil);
|
||||||
|
|
||||||
if (IsMainPipeline)
|
|
||||||
{
|
|
||||||
FramebufferParams.AddBindings();
|
|
||||||
|
|
||||||
_newState.FeedbackLoopAspects = FeedbackLoopAspects.None;
|
|
||||||
_bindingBarriersDirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
_passWritesDepthStencil = false;
|
|
||||||
UpdatePassDepthStencil();
|
|
||||||
UpdatePipelineAttachmentFormats();
|
UpdatePipelineAttachmentFormats();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1518,82 +1493,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
Gd.Barriers.Flush(Cbs, _program, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||||
|
|
||||||
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Compute);
|
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Compute);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ChangeFeedbackLoop(FeedbackLoopAspects aspects)
|
|
||||||
{
|
|
||||||
if (_feedbackLoop != aspects)
|
|
||||||
{
|
|
||||||
if (Gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
|
|
||||||
{
|
|
||||||
DynamicState.SetFeedbackLoop(aspects);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_newState.FeedbackLoopAspects = aspects;
|
|
||||||
}
|
|
||||||
|
|
||||||
_feedbackLoop = aspects;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private bool UpdateFeedbackLoop()
|
|
||||||
{
|
|
||||||
List<TextureView> hazards = _descriptorSetUpdater.FeedbackLoopHazards;
|
|
||||||
|
|
||||||
if ((hazards?.Count ?? 0) > 0)
|
|
||||||
{
|
|
||||||
FeedbackLoopAspects aspects = 0;
|
|
||||||
|
|
||||||
foreach (TextureView view in hazards)
|
|
||||||
{
|
|
||||||
// May need to enforce feedback loop layout here in the future.
|
|
||||||
// Though technically, it should always work with the general layout.
|
|
||||||
|
|
||||||
if (view.Info.Format.IsDepthOrStencil())
|
|
||||||
{
|
|
||||||
if (_passWritesDepthStencil)
|
|
||||||
{
|
|
||||||
// If depth/stencil isn't written in the pass, it doesn't count as a feedback loop.
|
|
||||||
|
|
||||||
aspects |= FeedbackLoopAspects.Depth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aspects |= FeedbackLoopAspects.Color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ChangeFeedbackLoop(aspects);
|
|
||||||
}
|
|
||||||
else if (_feedbackLoop != 0)
|
|
||||||
{
|
|
||||||
return ChangeFeedbackLoop(FeedbackLoopAspects.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdatePassDepthStencil()
|
|
||||||
{
|
|
||||||
if (!RenderPassActive)
|
|
||||||
{
|
|
||||||
_passWritesDepthStencil = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stencil test being enabled doesn't necessarily mean a write, but it's not critical to check.
|
|
||||||
_passWritesDepthStencil |= (_newState.DepthTestEnable && _newState.DepthWriteEnable) || _newState.StencilTestEnable;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool RecreateGraphicsPipelineIfNeeded()
|
private bool RecreateGraphicsPipelineIfNeeded()
|
||||||
{
|
{
|
||||||
if (AutoFlush.ShouldFlushDraw(DrawCount))
|
if (AutoFlush.ShouldFlushDraw(DrawCount))
|
||||||
|
|
@ -1601,7 +1505,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
Gd.FlushAllCommands();
|
Gd.FlushAllCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicState.ReplayIfDirty(Gd, CommandBuffer);
|
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
||||||
|
|
||||||
if (_needsIndexBufferRebind && _indexBufferPattern == null)
|
if (_needsIndexBufferRebind && _indexBufferPattern == null)
|
||||||
{
|
{
|
||||||
|
|
@ -1635,15 +1539,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_vertexBufferUpdater.Commit(Cbs);
|
_vertexBufferUpdater.Commit(Cbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_bindingBarriersDirty)
|
if (_graphicsStateDirty || Pbp != PipelineBindPoint.Graphics)
|
||||||
{
|
|
||||||
// Stale barriers may have been activated by switching program. Emit any that are relevant.
|
|
||||||
_descriptorSetUpdater.InsertBindingBarriers(Cbs);
|
|
||||||
|
|
||||||
_bindingBarriersDirty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UpdateFeedbackLoop() || _graphicsStateDirty || Pbp != PipelineBindPoint.Graphics)
|
|
||||||
{
|
{
|
||||||
if (!CreatePipeline(PipelineBindPoint.Graphics))
|
if (!CreatePipeline(PipelineBindPoint.Graphics))
|
||||||
{
|
{
|
||||||
|
|
@ -1652,9 +1548,17 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
_graphicsStateDirty = false;
|
_graphicsStateDirty = false;
|
||||||
Pbp = PipelineBindPoint.Graphics;
|
Pbp = PipelineBindPoint.Graphics;
|
||||||
|
|
||||||
|
if (_bindingBarriersDirty)
|
||||||
|
{
|
||||||
|
// Stale barriers may have been activated by switching program. Emit any that are relevant.
|
||||||
|
_descriptorSetUpdater.InsertBindingBarriers(Cbs);
|
||||||
|
|
||||||
|
_bindingBarriersDirty = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
Gd.Barriers.Flush(Cbs, _program, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||||
|
|
||||||
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Graphics);
|
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Graphics);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using Silk.NET.Vulkan.Extensions.EXT;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
|
|
@ -22,8 +21,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
private Array4<float> _blendConstants;
|
private Array4<float> _blendConstants;
|
||||||
|
|
||||||
private FeedbackLoopAspects _feedbackLoopAspects;
|
|
||||||
|
|
||||||
public uint ViewportsCount;
|
public uint ViewportsCount;
|
||||||
public Array16<Viewport> Viewports;
|
public Array16<Viewport> Viewports;
|
||||||
|
|
||||||
|
|
@ -35,8 +32,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
Scissor = 1 << 2,
|
Scissor = 1 << 2,
|
||||||
Stencil = 1 << 3,
|
Stencil = 1 << 3,
|
||||||
Viewport = 1 << 4,
|
Viewport = 1 << 4,
|
||||||
FeedbackLoop = 1 << 5,
|
All = Blend | DepthBias | Scissor | Stencil | Viewport,
|
||||||
All = Blend | DepthBias | Scissor | Stencil | Viewport | FeedbackLoop,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DirtyFlags _dirty;
|
private DirtyFlags _dirty;
|
||||||
|
|
@ -103,22 +99,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetFeedbackLoop(FeedbackLoopAspects aspects)
|
|
||||||
{
|
|
||||||
_feedbackLoopAspects = aspects;
|
|
||||||
|
|
||||||
_dirty |= DirtyFlags.FeedbackLoop;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ForceAllDirty()
|
public void ForceAllDirty()
|
||||||
{
|
{
|
||||||
_dirty = DirtyFlags.All;
|
_dirty = DirtyFlags.All;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReplayIfDirty(VulkanRenderer gd, CommandBuffer commandBuffer)
|
public void ReplayIfDirty(Vk api, CommandBuffer commandBuffer)
|
||||||
{
|
{
|
||||||
Vk api = gd.Api;
|
|
||||||
|
|
||||||
if (_dirty.HasFlag(DirtyFlags.Blend))
|
if (_dirty.HasFlag(DirtyFlags.Blend))
|
||||||
{
|
{
|
||||||
RecordBlend(api, commandBuffer);
|
RecordBlend(api, commandBuffer);
|
||||||
|
|
@ -144,11 +131,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
RecordViewport(api, commandBuffer);
|
RecordViewport(api, commandBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dirty.HasFlag(DirtyFlags.FeedbackLoop) && gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
|
|
||||||
{
|
|
||||||
RecordFeedbackLoop(gd.DynamicFeedbackLoopApi, commandBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
_dirty = DirtyFlags.None;
|
_dirty = DirtyFlags.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -187,17 +169,5 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan());
|
api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly void RecordFeedbackLoop(ExtAttachmentFeedbackLoopDynamicState api, CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
ImageAspectFlags aspects = (_feedbackLoopAspects & FeedbackLoopAspects.Color) != 0 ? ImageAspectFlags.ColorBit : 0;
|
|
||||||
|
|
||||||
if ((_feedbackLoopAspects & FeedbackLoopAspects.Depth) != 0)
|
|
||||||
{
|
|
||||||
aspects |= ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit;
|
|
||||||
}
|
|
||||||
|
|
||||||
api.CmdSetAttachmentFeedbackLoopEnable(commandBuffer, aspects);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_activeBufferMirrors = new();
|
_activeBufferMirrors = new();
|
||||||
|
|
||||||
CommandBuffer = (Cbs = gd.CommandBufferPool.Rent()).CommandBuffer;
|
CommandBuffer = (Cbs = gd.CommandBufferPool.Rent()).CommandBuffer;
|
||||||
|
|
||||||
IsMainPipeline = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CopyPendingQuery()
|
private void CopyPendingQuery()
|
||||||
|
|
@ -237,7 +235,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
if (Pipeline != null && Pbp == PipelineBindPoint.Graphics)
|
if (Pipeline != null && Pbp == PipelineBindPoint.Graphics)
|
||||||
{
|
{
|
||||||
DynamicState.ReplayIfDirty(Gd, CommandBuffer);
|
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
struct PipelineState : IDisposable
|
struct PipelineState : IDisposable
|
||||||
{
|
{
|
||||||
private const int RequiredSubgroupSize = 32;
|
private const int RequiredSubgroupSize = 32;
|
||||||
private const int MaxDynamicStatesCount = 9;
|
|
||||||
|
|
||||||
public PipelineUid Internal;
|
public PipelineUid Internal;
|
||||||
|
|
||||||
|
|
@ -300,12 +299,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6);
|
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FeedbackLoopAspects FeedbackLoopAspects
|
|
||||||
{
|
|
||||||
readonly get => (FeedbackLoopAspects)((Internal.Id8 >> 7) & 0x3);
|
|
||||||
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFE7F) | (((ulong)value) << 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasTessellationControlShader;
|
public bool HasTessellationControlShader;
|
||||||
public NativeArray<PipelineShaderStageCreateInfo> Stages;
|
public NativeArray<PipelineShaderStageCreateInfo> Stages;
|
||||||
public PipelineLayout PipelineLayout;
|
public PipelineLayout PipelineLayout;
|
||||||
|
|
@ -571,11 +564,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
|
bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
|
||||||
bool supportsFeedbackLoopDynamicState = gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop;
|
int dynamicStatesCount = supportsExtDynamicState ? 8 : 7;
|
||||||
|
|
||||||
DynamicState* dynamicStates = stackalloc DynamicState[MaxDynamicStatesCount];
|
DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount];
|
||||||
|
|
||||||
int dynamicStatesCount = 7;
|
|
||||||
|
|
||||||
dynamicStates[0] = DynamicState.Viewport;
|
dynamicStates[0] = DynamicState.Viewport;
|
||||||
dynamicStates[1] = DynamicState.Scissor;
|
dynamicStates[1] = DynamicState.Scissor;
|
||||||
|
|
@ -587,12 +578,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
if (supportsExtDynamicState)
|
if (supportsExtDynamicState)
|
||||||
{
|
{
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.VertexInputBindingStrideExt;
|
dynamicStates[7] = DynamicState.VertexInputBindingStrideExt;
|
||||||
}
|
|
||||||
|
|
||||||
if (supportsFeedbackLoopDynamicState)
|
|
||||||
{
|
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.AttachmentFeedbackLoopEnableExt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo
|
var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo
|
||||||
|
|
@ -602,27 +588,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
PDynamicStates = dynamicStates,
|
PDynamicStates = dynamicStates,
|
||||||
};
|
};
|
||||||
|
|
||||||
PipelineCreateFlags flags = 0;
|
|
||||||
|
|
||||||
if (gd.Capabilities.SupportsAttachmentFeedbackLoop)
|
|
||||||
{
|
|
||||||
FeedbackLoopAspects aspects = FeedbackLoopAspects;
|
|
||||||
|
|
||||||
if ((aspects & FeedbackLoopAspects.Color) != 0)
|
|
||||||
{
|
|
||||||
flags |= PipelineCreateFlags.CreateColorAttachmentFeedbackLoopBitExt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((aspects & FeedbackLoopAspects.Depth) != 0)
|
|
||||||
{
|
|
||||||
flags |= PipelineCreateFlags.CreateDepthStencilAttachmentFeedbackLoopBitExt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var pipelineCreateInfo = new GraphicsPipelineCreateInfo
|
var pipelineCreateInfo = new GraphicsPipelineCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.GraphicsPipelineCreateInfo,
|
SType = StructureType.GraphicsPipelineCreateInfo,
|
||||||
Flags = flags,
|
|
||||||
StageCount = StagesCount,
|
StageCount = StagesCount,
|
||||||
PStages = Stages.Pointer,
|
PStages = Stages.Pointer,
|
||||||
PVertexInputState = &vertexInputState,
|
PVertexInputState = &vertexInputState,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private int _offset;
|
private int _offset;
|
||||||
private int _size;
|
private int _size;
|
||||||
private Auto<DisposableBufferView> _bufferView;
|
private Auto<DisposableBufferView> _bufferView;
|
||||||
|
private Dictionary<Format, Auto<DisposableBufferView>> _selfManagedViews;
|
||||||
|
|
||||||
private int _bufferCount;
|
private int _bufferCount;
|
||||||
|
|
||||||
|
|
@ -79,6 +80,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
private void ReleaseImpl()
|
private void ReleaseImpl()
|
||||||
{
|
{
|
||||||
|
if (_selfManagedViews != null)
|
||||||
|
{
|
||||||
|
foreach (var bufferView in _selfManagedViews.Values)
|
||||||
|
{
|
||||||
|
bufferView.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_selfManagedViews = null;
|
||||||
|
}
|
||||||
|
|
||||||
_bufferView?.Dispose();
|
_bufferView?.Dispose();
|
||||||
_bufferView = null;
|
_bufferView = null;
|
||||||
}
|
}
|
||||||
|
|
@ -126,5 +137,28 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
return _bufferView?.Get(cbs, _offset, _size, write).Value ?? default;
|
return _bufferView?.Get(cbs, _offset, _size, write).Value ?? default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BufferView GetBufferView(CommandBufferScoped cbs, Format format, bool write)
|
||||||
|
{
|
||||||
|
var vkFormat = FormatTable.GetFormat(format);
|
||||||
|
if (vkFormat == VkFormat)
|
||||||
|
{
|
||||||
|
return GetBufferView(cbs, write);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_selfManagedViews != null && _selfManagedViews.TryGetValue(format, out var bufferView))
|
||||||
|
{
|
||||||
|
return bufferView.Get(cbs, _offset, _size, write).Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferView = _gd.BufferManager.CreateView(_bufferHandle, vkFormat, _offset, _size, ReleaseImpl);
|
||||||
|
|
||||||
|
if (bufferView != null)
|
||||||
|
{
|
||||||
|
(_selfManagedViews ??= new Dictionary<Format, Auto<DisposableBufferView>>()).Add(format, bufferView);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bufferView?.Get(cbs, _offset, _size, write).Value ?? default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using Format = Ryujinx.Graphics.GAL.Format;
|
using Format = Ryujinx.Graphics.GAL.Format;
|
||||||
using VkBuffer = Silk.NET.Vulkan.Buffer;
|
using VkBuffer = Silk.NET.Vulkan.Buffer;
|
||||||
using VkFormat = Silk.NET.Vulkan.Format;
|
using VkFormat = Silk.NET.Vulkan.Format;
|
||||||
|
|
@ -13,11 +12,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
class TextureStorage : IDisposable
|
class TextureStorage : IDisposable
|
||||||
{
|
{
|
||||||
private struct TextureSliceInfo
|
|
||||||
{
|
|
||||||
public int BindCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private const MemoryPropertyFlags DefaultImageMemoryFlags =
|
private const MemoryPropertyFlags DefaultImageMemoryFlags =
|
||||||
MemoryPropertyFlags.DeviceLocalBit;
|
MemoryPropertyFlags.DeviceLocalBit;
|
||||||
|
|
||||||
|
|
@ -49,7 +43,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private readonly Image _image;
|
private readonly Image _image;
|
||||||
private readonly Auto<DisposableImage> _imageAuto;
|
private readonly Auto<DisposableImage> _imageAuto;
|
||||||
private readonly Auto<MemoryAllocation> _allocationAuto;
|
private readonly Auto<MemoryAllocation> _allocationAuto;
|
||||||
private readonly int _depthOrLayers;
|
|
||||||
private Auto<MemoryAllocation> _foreignAllocationAuto;
|
private Auto<MemoryAllocation> _foreignAllocationAuto;
|
||||||
|
|
||||||
private Dictionary<Format, TextureStorage> _aliasedStorages;
|
private Dictionary<Format, TextureStorage> _aliasedStorages;
|
||||||
|
|
@ -62,9 +55,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private int _viewsCount;
|
private int _viewsCount;
|
||||||
private readonly ulong _size;
|
private readonly ulong _size;
|
||||||
|
|
||||||
private int _bindCount;
|
|
||||||
private readonly TextureSliceInfo[] _slices;
|
|
||||||
|
|
||||||
public VkFormat VkFormat { get; }
|
public VkFormat VkFormat { get; }
|
||||||
|
|
||||||
public unsafe TextureStorage(
|
public unsafe TextureStorage(
|
||||||
|
|
@ -83,7 +73,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
var depth = (uint)(info.Target == Target.Texture3D ? info.Depth : 1);
|
var depth = (uint)(info.Target == Target.Texture3D ? info.Depth : 1);
|
||||||
|
|
||||||
VkFormat = format;
|
VkFormat = format;
|
||||||
_depthOrLayers = info.GetDepthOrLayers();
|
|
||||||
|
|
||||||
var type = info.Target.Convert();
|
var type = info.Target.Convert();
|
||||||
|
|
||||||
|
|
@ -91,7 +80,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
var sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples);
|
var sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples);
|
||||||
|
|
||||||
var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities);
|
var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample);
|
||||||
|
|
||||||
var flags = ImageCreateFlags.CreateMutableFormatBit | ImageCreateFlags.CreateExtendedUsageBit;
|
var flags = ImageCreateFlags.CreateMutableFormatBit | ImageCreateFlags.CreateExtendedUsageBit;
|
||||||
|
|
||||||
|
|
@ -159,8 +148,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
InitialTransition(ImageLayout.Preinitialized, ImageLayout.General);
|
InitialTransition(ImageLayout.Preinitialized, ImageLayout.General);
|
||||||
}
|
}
|
||||||
|
|
||||||
_slices = new TextureSliceInfo[levels * _depthOrLayers];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextureStorage CreateAliasedColorForDepthStorageUnsafe(Format format)
|
public TextureStorage CreateAliasedColorForDepthStorageUnsafe(Format format)
|
||||||
|
|
@ -305,7 +292,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ImageUsageFlags GetImageUsage(Format format, Target target, in HardwareCapabilities capabilities)
|
public static ImageUsageFlags GetImageUsage(Format format, Target target, bool supportsMsStorage)
|
||||||
{
|
{
|
||||||
var usage = DefaultUsageFlags;
|
var usage = DefaultUsageFlags;
|
||||||
|
|
||||||
|
|
@ -318,19 +305,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
usage |= ImageUsageFlags.ColorAttachmentBit;
|
usage |= ImageUsageFlags.ColorAttachmentBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool supportsMsStorage = capabilities.SupportsShaderStorageImageMultisample;
|
|
||||||
|
|
||||||
if (format.IsImageCompatible() && (supportsMsStorage || !target.IsMultisample()))
|
if (format.IsImageCompatible() && (supportsMsStorage || !target.IsMultisample()))
|
||||||
{
|
{
|
||||||
usage |= ImageUsageFlags.StorageBit;
|
usage |= ImageUsageFlags.StorageBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (capabilities.SupportsAttachmentFeedbackLoop &&
|
|
||||||
(usage & (ImageUsageFlags.DepthStencilAttachmentBit | ImageUsageFlags.ColorAttachmentBit)) != 0)
|
|
||||||
{
|
|
||||||
usage |= ImageUsageFlags.AttachmentFeedbackLoopBitExt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return usage;
|
return usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -531,55 +510,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddBinding(TextureView view)
|
|
||||||
{
|
|
||||||
// Assumes a view only has a first level.
|
|
||||||
|
|
||||||
int index = view.FirstLevel * _depthOrLayers + view.FirstLayer;
|
|
||||||
int layers = view.Layers;
|
|
||||||
|
|
||||||
for (int i = 0; i < layers; i++)
|
|
||||||
{
|
|
||||||
ref TextureSliceInfo info = ref _slices[index++];
|
|
||||||
|
|
||||||
info.BindCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_bindCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearBindings()
|
|
||||||
{
|
|
||||||
if (_bindCount != 0)
|
|
||||||
{
|
|
||||||
Array.Clear(_slices, 0, _slices.Length);
|
|
||||||
|
|
||||||
_bindCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool IsBound(TextureView view)
|
|
||||||
{
|
|
||||||
if (_bindCount != 0)
|
|
||||||
{
|
|
||||||
int index = view.FirstLevel * _depthOrLayers + view.FirstLayer;
|
|
||||||
int layers = view.Layers;
|
|
||||||
|
|
||||||
for (int i = 0; i < layers; i++)
|
|
||||||
{
|
|
||||||
ref TextureSliceInfo info = ref _slices[index++];
|
|
||||||
|
|
||||||
if (info.BindCount != 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void IncrementViewsCount()
|
public void IncrementViewsCount()
|
||||||
{
|
{
|
||||||
_viewsCount++;
|
_viewsCount++;
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private readonly Auto<DisposableImageView> _imageView2dArray;
|
private readonly Auto<DisposableImageView> _imageView2dArray;
|
||||||
private Dictionary<Format, TextureView> _selfManagedViews;
|
private Dictionary<Format, TextureView> _selfManagedViews;
|
||||||
|
|
||||||
private int _hazardUses;
|
|
||||||
|
|
||||||
private readonly TextureCreateInfo _info;
|
private readonly TextureCreateInfo _info;
|
||||||
|
|
||||||
private HashTableSlim<RenderPassCacheKey, RenderPassHolder> _renderPasses;
|
private HashTableSlim<RenderPassCacheKey, RenderPassHolder> _renderPasses;
|
||||||
|
|
@ -62,7 +60,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
gd.Textures.Add(this);
|
gd.Textures.Add(this);
|
||||||
|
|
||||||
var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format);
|
var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format);
|
||||||
var usage = TextureStorage.GetImageUsage(info.Format, info.Target, gd.Capabilities);
|
var usage = TextureStorage.GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample);
|
||||||
var levels = (uint)info.Levels;
|
var levels = (uint)info.Levels;
|
||||||
var layers = (uint)info.GetLayers();
|
var layers = (uint)info.GetLayers();
|
||||||
|
|
||||||
|
|
@ -1036,34 +1034,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PrepareForUsage(CommandBufferScoped cbs, PipelineStageFlags flags, List<TextureView> feedbackLoopHazards)
|
|
||||||
{
|
|
||||||
Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, flags);
|
|
||||||
|
|
||||||
if (feedbackLoopHazards != null && Storage.IsBound(this))
|
|
||||||
{
|
|
||||||
feedbackLoopHazards.Add(this);
|
|
||||||
_hazardUses++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearUsage(List<TextureView> feedbackLoopHazards)
|
|
||||||
{
|
|
||||||
if (_hazardUses != 0 && feedbackLoopHazards != null)
|
|
||||||
{
|
|
||||||
feedbackLoopHazards.Remove(this);
|
|
||||||
_hazardUses--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DecrementHazardUses()
|
|
||||||
{
|
|
||||||
if (_hazardUses != 0)
|
|
||||||
{
|
|
||||||
_hazardUses--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
|
public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
|
||||||
VulkanRenderer gd,
|
VulkanRenderer gd,
|
||||||
Device device,
|
Device device,
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
"VK_EXT_4444_formats",
|
"VK_EXT_4444_formats",
|
||||||
"VK_KHR_8bit_storage",
|
"VK_KHR_8bit_storage",
|
||||||
"VK_KHR_maintenance2",
|
"VK_KHR_maintenance2",
|
||||||
"VK_EXT_attachment_feedback_loop_layout",
|
|
||||||
"VK_EXT_attachment_feedback_loop_dynamic_state",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly string[] _requiredExtensions = {
|
private static readonly string[] _requiredExtensions = {
|
||||||
|
|
@ -359,28 +357,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
features2.PNext = &supportedFeaturesDepthClipControl;
|
features2.PNext = &supportedFeaturesDepthClipControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT supportedFeaturesAttachmentFeedbackLoopLayout = new()
|
|
||||||
{
|
|
||||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
|
|
||||||
PNext = features2.PNext,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout"))
|
|
||||||
{
|
|
||||||
features2.PNext = &supportedFeaturesAttachmentFeedbackLoopLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT supportedFeaturesDynamicAttachmentFeedbackLoopLayout = new()
|
|
||||||
{
|
|
||||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
|
|
||||||
PNext = features2.PNext,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state"))
|
|
||||||
{
|
|
||||||
features2.PNext = &supportedFeaturesDynamicAttachmentFeedbackLoopLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicalDeviceVulkan12Features supportedPhysicalDeviceVulkan12Features = new()
|
PhysicalDeviceVulkan12Features supportedPhysicalDeviceVulkan12Features = new()
|
||||||
{
|
{
|
||||||
SType = StructureType.PhysicalDeviceVulkan12Features,
|
SType = StructureType.PhysicalDeviceVulkan12Features,
|
||||||
|
|
@ -555,36 +531,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
pExtendedFeatures = &featuresDepthClipControl;
|
pExtendedFeatures = &featuresDepthClipControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT featuresAttachmentFeedbackLoopLayout;
|
|
||||||
|
|
||||||
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout") &&
|
|
||||||
supportedFeaturesAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopLayout)
|
|
||||||
{
|
|
||||||
featuresAttachmentFeedbackLoopLayout = new()
|
|
||||||
{
|
|
||||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
|
|
||||||
PNext = pExtendedFeatures,
|
|
||||||
AttachmentFeedbackLoopLayout = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
pExtendedFeatures = &featuresAttachmentFeedbackLoopLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT featuresDynamicAttachmentFeedbackLoopLayout;
|
|
||||||
|
|
||||||
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state") &&
|
|
||||||
supportedFeaturesDynamicAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopDynamicState)
|
|
||||||
{
|
|
||||||
featuresDynamicAttachmentFeedbackLoopLayout = new()
|
|
||||||
{
|
|
||||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
|
|
||||||
PNext = pExtendedFeatures,
|
|
||||||
AttachmentFeedbackLoopDynamicState = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
pExtendedFeatures = &featuresDynamicAttachmentFeedbackLoopLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray();
|
var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray();
|
||||||
|
|
||||||
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
|
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
internal KhrPushDescriptor PushDescriptorApi { get; private set; }
|
internal KhrPushDescriptor PushDescriptorApi { get; private set; }
|
||||||
internal ExtTransformFeedback TransformFeedbackApi { get; private set; }
|
internal ExtTransformFeedback TransformFeedbackApi { get; private set; }
|
||||||
internal KhrDrawIndirectCount DrawIndirectCountApi { get; private set; }
|
internal KhrDrawIndirectCount DrawIndirectCountApi { get; private set; }
|
||||||
internal ExtAttachmentFeedbackLoopDynamicState DynamicFeedbackLoopApi { get; private set; }
|
|
||||||
|
|
||||||
internal uint QueueFamilyIndex { get; private set; }
|
internal uint QueueFamilyIndex { get; private set; }
|
||||||
internal Queue Queue { get; private set; }
|
internal Queue Queue { get; private set; }
|
||||||
|
|
@ -150,11 +149,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
DrawIndirectCountApi = drawIndirectCountApi;
|
DrawIndirectCountApi = drawIndirectCountApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtAttachmentFeedbackLoopDynamicState dynamicFeedbackLoopApi))
|
|
||||||
{
|
|
||||||
DynamicFeedbackLoopApi = dynamicFeedbackLoopApi;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxQueueCount >= 2)
|
if (maxQueueCount >= 2)
|
||||||
{
|
{
|
||||||
Api.GetDeviceQueue(_device, queueFamilyIndex, 1, out var backgroundQueue);
|
Api.GetDeviceQueue(_device, queueFamilyIndex, 1, out var backgroundQueue);
|
||||||
|
|
@ -249,16 +243,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
SType = StructureType.PhysicalDeviceDepthClipControlFeaturesExt,
|
SType = StructureType.PhysicalDeviceDepthClipControlFeaturesExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT featuresAttachmentFeedbackLoop = new()
|
|
||||||
{
|
|
||||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
|
|
||||||
};
|
|
||||||
|
|
||||||
PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT featuresDynamicAttachmentFeedbackLoop = new()
|
|
||||||
{
|
|
||||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
|
|
||||||
};
|
|
||||||
|
|
||||||
PhysicalDevicePortabilitySubsetFeaturesKHR featuresPortabilitySubset = new()
|
PhysicalDevicePortabilitySubsetFeaturesKHR featuresPortabilitySubset = new()
|
||||||
{
|
{
|
||||||
SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr,
|
SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr,
|
||||||
|
|
@ -295,22 +279,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
features2.PNext = &featuresDepthClipControl;
|
features2.PNext = &featuresDepthClipControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool supportsAttachmentFeedbackLoop = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout");
|
|
||||||
|
|
||||||
if (supportsAttachmentFeedbackLoop)
|
|
||||||
{
|
|
||||||
featuresAttachmentFeedbackLoop.PNext = features2.PNext;
|
|
||||||
features2.PNext = &featuresAttachmentFeedbackLoop;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool supportsDynamicAttachmentFeedbackLoop = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state");
|
|
||||||
|
|
||||||
if (supportsDynamicAttachmentFeedbackLoop)
|
|
||||||
{
|
|
||||||
featuresDynamicAttachmentFeedbackLoop.PNext = features2.PNext;
|
|
||||||
features2.PNext = &featuresDynamicAttachmentFeedbackLoop;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool usePortability = _physicalDevice.IsDeviceExtensionPresent("VK_KHR_portability_subset");
|
bool usePortability = _physicalDevice.IsDeviceExtensionPresent("VK_KHR_portability_subset");
|
||||||
|
|
||||||
if (usePortability)
|
if (usePortability)
|
||||||
|
|
@ -433,8 +401,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"),
|
_physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"),
|
||||||
_physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName),
|
_physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName),
|
||||||
supportsDepthClipControl && featuresDepthClipControl.DepthClipControl,
|
supportsDepthClipControl && featuresDepthClipControl.DepthClipControl,
|
||||||
supportsAttachmentFeedbackLoop && featuresAttachmentFeedbackLoop.AttachmentFeedbackLoopLayout,
|
|
||||||
supportsDynamicAttachmentFeedbackLoop && featuresDynamicAttachmentFeedbackLoop.AttachmentFeedbackLoopDynamicState,
|
|
||||||
propertiesSubgroup.SubgroupSize,
|
propertiesSubgroup.SubgroupSize,
|
||||||
supportedSampleCounts,
|
supportedSampleCounts,
|
||||||
portabilityFlags,
|
portabilityFlags,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.GraphicsDriver;
|
using Ryujinx.Common.GraphicsDriver;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.SystemInterop;
|
using Ryujinx.Common.SystemInterop;
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using Ryujinx.Graphics.Vulkan.MoltenVK;
|
using Ryujinx.Graphics.Vulkan.MoltenVK;
|
||||||
using Ryujinx.Modules;
|
using Ryujinx.Modules;
|
||||||
using Ryujinx.SDL2.Common;
|
using Ryujinx.SDL2.Common;
|
||||||
|
|
@ -42,6 +41,9 @@ namespace Ryujinx
|
||||||
[LibraryImport("user32.dll", SetLastError = true)]
|
[LibraryImport("user32.dll", SetLastError = true)]
|
||||||
public static partial int MessageBoxA(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type);
|
public static partial int MessageBoxA(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type);
|
||||||
|
|
||||||
|
[LibraryImport("libc", SetLastError = true)]
|
||||||
|
private static partial int setenv([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value, int overwrite);
|
||||||
|
|
||||||
private const uint MbIconWarning = 0x30;
|
private const uint MbIconWarning = 0x30;
|
||||||
|
|
||||||
static Program()
|
static Program()
|
||||||
|
|
@ -103,7 +105,8 @@ namespace Ryujinx
|
||||||
throw new NotSupportedException("Failed to initialize multi-threading support.");
|
throw new NotSupportedException("Failed to initialize multi-threading support.");
|
||||||
}
|
}
|
||||||
|
|
||||||
OsUtils.SetEnvironmentVariableNoCaching("GDK_BACKEND", "x11");
|
Environment.SetEnvironmentVariable("GDK_BACKEND", "x11");
|
||||||
|
setenv("GDK_BACKEND", "x11", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OperatingSystem.IsMacOS())
|
if (OperatingSystem.IsMacOS())
|
||||||
|
|
@ -122,13 +125,19 @@ namespace Ryujinx
|
||||||
resourcesDataDir = baseDirectory;
|
resourcesDataDir = baseDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SetEnvironmentVariableNoCaching(string key, string value)
|
||||||
|
{
|
||||||
|
int res = setenv(key, value, 1);
|
||||||
|
Debug.Assert(res != -1);
|
||||||
|
}
|
||||||
|
|
||||||
// On macOS, GTK3 needs XDG_DATA_DIRS to be set, otherwise it will try searching for "gschemas.compiled" in system directories.
|
// On macOS, GTK3 needs XDG_DATA_DIRS to be set, otherwise it will try searching for "gschemas.compiled" in system directories.
|
||||||
OsUtils.SetEnvironmentVariableNoCaching("XDG_DATA_DIRS", Path.Combine(resourcesDataDir, "share"));
|
SetEnvironmentVariableNoCaching("XDG_DATA_DIRS", Path.Combine(resourcesDataDir, "share"));
|
||||||
|
|
||||||
// On macOS, GTK3 needs GDK_PIXBUF_MODULE_FILE to be set, otherwise it will try searching for "loaders.cache" in system directories.
|
// On macOS, GTK3 needs GDK_PIXBUF_MODULE_FILE to be set, otherwise it will try searching for "loaders.cache" in system directories.
|
||||||
OsUtils.SetEnvironmentVariableNoCaching("GDK_PIXBUF_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gdk-pixbuf-2.0", "2.10.0", "loaders.cache"));
|
SetEnvironmentVariableNoCaching("GDK_PIXBUF_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gdk-pixbuf-2.0", "2.10.0", "loaders.cache"));
|
||||||
|
|
||||||
OsUtils.SetEnvironmentVariableNoCaching("GTK_IM_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gtk-3.0", "3.0.0", "immodules.cache"));
|
SetEnvironmentVariableNoCaching("GTK_IM_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gtk-3.0", "3.0.0", "immodules.cache"));
|
||||||
}
|
}
|
||||||
|
|
||||||
string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine);
|
string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine);
|
||||||
|
|
@ -224,9 +233,9 @@ namespace Ryujinx
|
||||||
// Logging system information.
|
// Logging system information.
|
||||||
PrintSystemInfo();
|
PrintSystemInfo();
|
||||||
|
|
||||||
// Enable OGL multithreading on the driver, and some other flags.
|
// Enable OGL multithreading on the driver, when available.
|
||||||
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
||||||
DriverUtilities.InitDriverConfig(threadingMode == BackendThreading.Off);
|
DriverUtilities.ToggleOGLThreading(threadingMode == BackendThreading.Off);
|
||||||
|
|
||||||
// Initialize Gtk.
|
// Initialize Gtk.
|
||||||
Application.Init();
|
Application.Init();
|
||||||
|
|
|
||||||
|
|
@ -412,9 +412,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
|
|
||||||
Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat);
|
Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat);
|
||||||
|
|
||||||
byte bytesPerPixel =
|
int bytesPerPixel =
|
||||||
format == Format.B5G6R5Unorm ||
|
format == Format.B5G6R5Unorm ||
|
||||||
format == Format.R4G4B4A4Unorm ? (byte)2 : (byte)4;
|
format == Format.R4G4B4A4Unorm ? 2 : 4;
|
||||||
|
|
||||||
int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2;
|
int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ using Ryujinx.Common.Configuration.Hid;
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
||||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||||
using Ryujinx.Common.GraphicsDriver;
|
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Logging.Targets;
|
using Ryujinx.Common.Logging.Targets;
|
||||||
using Ryujinx.Common.SystemInterop;
|
using Ryujinx.Common.SystemInterop;
|
||||||
|
|
@ -464,8 +463,6 @@ namespace Ryujinx.Headless.SDL2
|
||||||
GraphicsConfig.ShadersDumpPath = option.GraphicsShadersDumpPath;
|
GraphicsConfig.ShadersDumpPath = option.GraphicsShadersDumpPath;
|
||||||
GraphicsConfig.EnableMacroHLE = !option.DisableMacroHLE;
|
GraphicsConfig.EnableMacroHLE = !option.DisableMacroHLE;
|
||||||
|
|
||||||
DriverUtilities.InitDriverConfig(option.BackendThreading == BackendThreading.Off);
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
LoadApplication(option);
|
LoadApplication(option);
|
||||||
|
|
|
||||||
|
|
@ -117,8 +117,8 @@ namespace Ryujinx.Ava
|
||||||
// Logging system information.
|
// Logging system information.
|
||||||
PrintSystemInfo();
|
PrintSystemInfo();
|
||||||
|
|
||||||
// Enable OGL multithreading on the driver, and some other flags.
|
// Enable OGL multithreading on the driver, when available.
|
||||||
DriverUtilities.InitDriverConfig(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off);
|
DriverUtilities.ToggleOGLThreading(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off);
|
||||||
|
|
||||||
// Check if keys exists.
|
// Check if keys exists.
|
||||||
if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))
|
if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue