aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Vulkan/HelperShader.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Vulkan/HelperShader.cs')
-rw-r--r--Ryujinx.Graphics.Vulkan/HelperShader.cs283
1 files changed, 219 insertions, 64 deletions
diff --git a/Ryujinx.Graphics.Vulkan/HelperShader.cs b/Ryujinx.Graphics.Vulkan/HelperShader.cs
index 658516e6..b8c21fe8 100644
--- a/Ryujinx.Graphics.Vulkan/HelperShader.cs
+++ b/Ryujinx.Graphics.Vulkan/HelperShader.cs
@@ -24,6 +24,7 @@ namespace Ryujinx.Graphics.Vulkan
private readonly ISampler _samplerLinear;
private readonly ISampler _samplerNearest;
private readonly IProgram _programColorBlit;
+ private readonly IProgram _programColorBlitMs;
private readonly IProgram _programColorBlitClearAlpha;
private readonly IProgram _programColorClearF;
private readonly IProgram _programColorClearSI;
@@ -34,7 +35,9 @@ namespace Ryujinx.Graphics.Vulkan
private readonly IProgram _programColorCopyToNonMs;
private readonly IProgram _programColorDrawToMs;
private readonly IProgram _programDepthBlit;
+ private readonly IProgram _programDepthBlitMs;
private readonly IProgram _programStencilBlit;
+ private readonly IProgram _programStencilBlitMs;
public HelperShader(VulkanRenderer gd, Device device)
{
@@ -62,6 +65,12 @@ namespace Ryujinx.Graphics.Vulkan
new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
});
+ _programColorBlitMs = gd.CreateProgramWithMinimalLayout(new[]
+ {
+ new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
+ new ShaderSource(ShaderBinaries.ColorBlitMsFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
+ });
+
_programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[]
{
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
@@ -160,6 +169,12 @@ namespace Ryujinx.Graphics.Vulkan
new ShaderSource(ShaderBinaries.DepthBlitFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
});
+ _programDepthBlitMs = gd.CreateProgramWithMinimalLayout(new[]
+ {
+ new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
+ new ShaderSource(ShaderBinaries.DepthBlitMsFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
+ });
+
if (gd.Capabilities.SupportsShaderStencilExport)
{
_programStencilBlit = gd.CreateProgramWithMinimalLayout(new[]
@@ -167,18 +182,23 @@ namespace Ryujinx.Graphics.Vulkan
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
new ShaderSource(ShaderBinaries.StencilBlitFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
});
+
+ _programStencilBlitMs = gd.CreateProgramWithMinimalLayout(new[]
+ {
+ new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
+ new ShaderSource(ShaderBinaries.StencilBlitMsFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
+ });
}
}
public void Blit(
VulkanRenderer gd,
TextureView src,
- Auto<DisposableImageView> dst,
- int dstWidth,
- int dstHeight,
- VkFormat dstFormat,
+ TextureView dst,
Extents2D srcRegion,
Extents2D dstRegion,
+ int layers,
+ int levels,
bool isDepthOrStencil,
bool linearFilter,
bool clearAlpha = false)
@@ -187,13 +207,137 @@ namespace Ryujinx.Graphics.Vulkan
using var cbs = gd.CommandBufferPool.Rent();
- if (isDepthOrStencil)
+ var dstFormat = dst.VkFormat;
+ var dstSamples = dst.Info.Samples;
+
+ for (int l = 0; l < levels; l++)
{
- BlitDepthStencil(gd, cbs, src, dst, dstWidth, dstHeight, dstFormat, srcRegion, dstRegion);
+ int srcWidth = Math.Max(1, src.Width >> l);
+ int srcHeight = Math.Max(1, src.Height >> l);
+
+ int dstWidth = Math.Max(1, dst.Width >> l);
+ int dstHeight = Math.Max(1, dst.Height >> l);
+
+ var mipSrcRegion = new Extents2D(
+ srcRegion.X1 >> l,
+ srcRegion.Y1 >> l,
+ srcRegion.X2 >> l,
+ srcRegion.Y2 >> l);
+
+ var mipDstRegion = new Extents2D(
+ dstRegion.X1 >> l,
+ dstRegion.Y1 >> l,
+ dstRegion.X2 >> l,
+ dstRegion.Y2 >> l);
+
+ for (int z = 0; z < layers; z++)
+ {
+ var srcView = Create2DLayerView(src, z, l);
+ var dstView = Create2DLayerView(dst, z, l);
+
+ if (isDepthOrStencil)
+ {
+ BlitDepthStencil(
+ gd,
+ cbs,
+ srcView,
+ dst.GetImageViewForAttachment(),
+ dstWidth,
+ dstHeight,
+ dstSamples,
+ dstFormat,
+ mipSrcRegion,
+ mipDstRegion);
+ }
+ else
+ {
+ BlitColor(
+ gd,
+ cbs,
+ srcView,
+ dst.GetImageViewForAttachment(),
+ dstWidth,
+ dstHeight,
+ dstSamples,
+ dstFormat,
+ false,
+ mipSrcRegion,
+ mipDstRegion,
+ linearFilter,
+ clearAlpha);
+ }
+
+ if (srcView != src)
+ {
+ srcView.Release();
+ }
+
+ if (dstView != dst)
+ {
+ dstView.Release();
+ }
+ }
}
- else
+ }
+
+ public void CopyColor(
+ VulkanRenderer gd,
+ CommandBufferScoped cbs,
+ TextureView src,
+ TextureView dst,
+ int srcLayer,
+ int dstLayer,
+ int srcLevel,
+ int dstLevel,
+ int depth,
+ int levels)
+ {
+ for (int l = 0; l < levels; l++)
{
- BlitColor(gd, cbs, src, dst, dstWidth, dstHeight, dstFormat, srcRegion, dstRegion, linearFilter, clearAlpha);
+ int mipSrcLevel = srcLevel + l;
+ int mipDstLevel = dstLevel + l;
+
+ int srcWidth = Math.Max(1, src.Width >> mipSrcLevel);
+ int srcHeight = Math.Max(1, src.Height >> mipSrcLevel);
+
+ int dstWidth = Math.Max(1, dst.Width >> mipDstLevel);
+ int dstHeight = Math.Max(1, dst.Height >> mipDstLevel);
+
+ var extents = new Extents2D(
+ 0,
+ 0,
+ Math.Min(srcWidth, dstWidth),
+ Math.Min(srcHeight, dstHeight));
+
+ for (int z = 0; z < depth; z++)
+ {
+ var srcView = Create2DLayerView(src, srcLayer + z, mipSrcLevel);
+ var dstView = Create2DLayerView(dst, dstLayer + z, mipDstLevel);
+
+ BlitColor(
+ gd,
+ cbs,
+ srcView,
+ dstView.GetImageViewForAttachment(),
+ dstView.Width,
+ dstView.Height,
+ dstView.Info.Samples,
+ dstView.VkFormat,
+ dstView.Info.Format.IsDepthOrStencil(),
+ extents,
+ extents,
+ false);
+
+ if (srcView != src)
+ {
+ srcView.Release();
+ }
+
+ if (dstView != dst)
+ {
+ dstView.Release();
+ }
+ }
}
}
@@ -204,7 +348,9 @@ namespace Ryujinx.Graphics.Vulkan
Auto<DisposableImageView> dst,
int dstWidth,
int dstHeight,
+ int dstSamples,
VkFormat dstFormat,
+ bool dstIsDepthOrStencil,
Extents2D srcRegion,
Extents2D dstRegion,
bool linearFilter,
@@ -262,8 +408,25 @@ namespace Ryujinx.Graphics.Vulkan
scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight);
- _pipeline.SetProgram(clearAlpha ? _programColorBlitClearAlpha : _programColorBlit);
- _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat);
+ if (dstIsDepthOrStencil)
+ {
+ _pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit);
+ _pipeline.SetDepthTest(new DepthTestDescriptor(true, true, GAL.CompareOp.Always));
+ }
+ else if (src.Info.Target.IsMultisample())
+ {
+ _pipeline.SetProgram(_programColorBlitMs);
+ }
+ else if (clearAlpha)
+ {
+ _pipeline.SetProgram(_programColorBlitClearAlpha);
+ }
+ else
+ {
+ _pipeline.SetProgram(_programColorBlit);
+ }
+
+ _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, (uint)dstSamples, dstIsDepthOrStencil, dstFormat);
_pipeline.SetRenderTargetColorMasks(new uint[] { 0xf });
_pipeline.SetScissors(scissors);
@@ -275,6 +438,12 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.SetViewports(viewports, false);
_pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
_pipeline.Draw(4, 1, 0, 0);
+
+ if (dstIsDepthOrStencil)
+ {
+ _pipeline.SetDepthTest(new DepthTestDescriptor(false, false, GAL.CompareOp.Always));
+ }
+
_pipeline.Finish(gd, cbs);
gd.BufferManager.Delete(bufferHandle);
@@ -287,6 +456,7 @@ namespace Ryujinx.Graphics.Vulkan
Auto<DisposableImageView> dst,
int dstWidth,
int dstHeight,
+ int dstSamples,
VkFormat dstFormat,
Extents2D srcRegion,
Extents2D dstRegion)
@@ -339,7 +509,7 @@ namespace Ryujinx.Graphics.Vulkan
scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight);
- _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, true, dstFormat);
+ _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, (uint)dstSamples, true, dstFormat);
_pipeline.SetScissors(scissors);
_pipeline.SetViewports(viewports, false);
_pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
@@ -406,12 +576,12 @@ namespace Ryujinx.Graphics.Vulkan
if (isDepth)
{
- _pipeline.SetProgram(_programDepthBlit);
+ _pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit);
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, GAL.CompareOp.Always));
}
else
{
- _pipeline.SetProgram(_programStencilBlit);
+ _pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programStencilBlitMs : _programStencilBlit);
_pipeline.SetStencilTest(CreateStencilTestDescriptor(true));
}
@@ -795,33 +965,25 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
- if (src.Info.Target == Target.Texture2DMultisampleArray ||
- dst.Info.Target == Target.Texture2DMultisampleArray)
+ for (int z = 0; z < depth; z++)
{
- for (int z = 0; z < depth; z++)
- {
- var srcView = Create2DLayerView(src, srcLayer + z, format);
- var dstView = Create2DLayerView(dst, dstLayer + z);
+ var srcView = Create2DLayerView(src, srcLayer + z, 0, format);
+ var dstView = Create2DLayerView(dst, dstLayer + z, 0);
- _pipeline.SetTextureAndSampler(ShaderStage.Compute, 0, srcView, null);
- _pipeline.SetImage(0, dstView, format);
+ _pipeline.SetTextureAndSampler(ShaderStage.Compute, 0, srcView, null);
+ _pipeline.SetImage(0, dstView, format);
- _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
+ _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
+ if (srcView != src)
+ {
srcView.Release();
- dstView.Release();
}
- }
- else
- {
- var srcView = Create2DLayerView(src, srcLayer, format);
-
- _pipeline.SetTextureAndSampler(ShaderStage.Compute, 0, srcView, null);
- _pipeline.SetImage(0, dst, format);
- _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
-
- srcView.Release();
+ if (dstView != dst)
+ {
+ dstView.Release();
+ }
}
gd.BufferManager.Delete(bufferHandle);
@@ -906,36 +1068,14 @@ namespace Ryujinx.Graphics.Vulkan
var format = GetFormat(src.Info.BytesPerPixel);
var vkFormat = FormatTable.GetFormat(format);
- if (src.Info.Target == Target.Texture2DMultisampleArray ||
- dst.Info.Target == Target.Texture2DMultisampleArray)
- {
- for (int z = 0; z < depth; z++)
- {
- var srcView = Create2DLayerView(src, srcLayer + z, format);
- var dstView = Create2DLayerView(dst, dstLayer + z);
-
- _pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, srcView, null);
- _pipeline.SetRenderTarget(
- ((TextureView)dstView).GetView(format).GetImageViewForAttachment(),
- (uint)dst.Width,
- (uint)dst.Height,
- (uint)samples,
- false,
- vkFormat);
-
- _pipeline.Draw(4, 1, 0, 0);
-
- srcView.Release();
- dstView.Release();
- }
- }
- else
+ for (int z = 0; z < depth; z++)
{
- var srcView = Create2DLayerView(src, srcLayer, format);
+ var srcView = Create2DLayerView(src, srcLayer + z, 0, format);
+ var dstView = Create2DLayerView(dst, dstLayer + z, 0);
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, srcView, null);
_pipeline.SetRenderTarget(
- dst.GetView(format).GetImageViewForAttachment(),
+ ((TextureView)dstView).GetView(format).GetImageViewForAttachment(),
(uint)dst.Width,
(uint)dst.Height,
(uint)samples,
@@ -944,7 +1084,15 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.Draw(4, 1, 0, 0);
- srcView.Release();
+ if (srcView != src)
+ {
+ srcView.Release();
+ }
+
+ if (dstView != dst)
+ {
+ dstView.Release();
+ }
}
gd.BufferManager.Delete(bufferHandle);
@@ -1001,14 +1149,18 @@ namespace Ryujinx.Graphics.Vulkan
return (samplesInXLog2, samplesInYLog2);
}
- private static ITexture Create2DLayerView(TextureView from, int layer, GAL.Format? format = null)
+ private static TextureView Create2DLayerView(TextureView from, int layer, int level, GAL.Format? format = null)
{
+ if (from.Info.Target == Target.Texture2D && level == 0 && (format == null || format.Value == from.Info.Format))
+ {
+ return from;
+ }
+
var target = from.Info.Target switch
{
Target.Texture1DArray => Target.Texture1D,
- Target.Texture2DArray => Target.Texture2D,
Target.Texture2DMultisampleArray => Target.Texture2DMultisample,
- _ => from.Info.Target
+ _ => Target.Texture2D
};
var info = new TextureCreateInfo(
@@ -1028,7 +1180,7 @@ namespace Ryujinx.Graphics.Vulkan
from.Info.SwizzleB,
from.Info.SwizzleA);
- return from.CreateView(info, layer, 0);
+ return from.CreateViewImpl(info, layer, level);
}
private static GAL.Format GetFormat(int bytesPerPixel)
@@ -1177,6 +1329,7 @@ namespace Ryujinx.Graphics.Vulkan
{
_programColorBlitClearAlpha.Dispose();
_programColorBlit.Dispose();
+ _programColorBlitMs.Dispose();
_programColorClearF.Dispose();
_programColorClearSI.Dispose();
_programColorClearUI.Dispose();
@@ -1186,7 +1339,9 @@ namespace Ryujinx.Graphics.Vulkan
_programColorCopyToNonMs.Dispose();
_programColorDrawToMs.Dispose();
_programDepthBlit.Dispose();
+ _programDepthBlitMs.Dispose();
_programStencilBlit?.Dispose();
+ _programStencilBlitMs?.Dispose();
_samplerNearest.Dispose();
_samplerLinear.Dispose();
_pipeline.Dispose();