From 5fbfa9a9bd8b2758059883e814e8604729d398fa Mon Sep 17 00:00:00 2001 From: gdk Date: Mon, 15 Nov 2021 14:18:17 -0300 Subject: [PATCH] DrawTexture support --- Ryujinx.Graphics.Vulkan/HelperShader.cs | 92 ++++++++++++++++++- Ryujinx.Graphics.Vulkan/PipelineBase.cs | 47 +++++++++- .../PipelineDynamicState.cs | 11 ++- 3 files changed, 144 insertions(+), 6 deletions(-) diff --git a/Ryujinx.Graphics.Vulkan/HelperShader.cs b/Ryujinx.Graphics.Vulkan/HelperShader.cs index 922db9172..5623aa186 100644 --- a/Ryujinx.Graphics.Vulkan/HelperShader.cs +++ b/Ryujinx.Graphics.Vulkan/HelperShader.cs @@ -155,6 +155,20 @@ void main() region[2] = (float)srcRegion.Y1 / src.Height; region[3] = (float)srcRegion.Y2 / src.Height; + if (dstRegion.X1 > dstRegion.X2) + { + float temp = region[0]; + region[0] = region[1]; + region[1] = temp; + } + + if (dstRegion.Y1 > dstRegion.Y2) + { + float temp = region[2]; + region[2] = region[3]; + region[3] = temp; + } + var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize); gd.BufferManager.SetData(bufferHandle, 0, region); @@ -167,8 +181,14 @@ void main() Span viewports = stackalloc GAL.Viewport[1]; + var rect = new Rectangle( + MathF.Min(dstRegion.X1, dstRegion.X2), + MathF.Min(dstRegion.Y1, dstRegion.Y2), + MathF.Abs(dstRegion.X2 - dstRegion.X1), + MathF.Abs(dstRegion.Y2 - dstRegion.Y1)); + viewports[0] = new GAL.Viewport( - new Rectangle(dstRegion.X1, dstRegion.Y1, dstRegion.X2 - dstRegion.X1, dstRegion.Y2 - dstRegion.Y1), + rect, ViewportSwizzle.PositiveX, ViewportSwizzle.PositiveY, ViewportSwizzle.PositiveZ, @@ -198,6 +218,76 @@ void main() gd.BufferManager.Delete(bufferHandle); } + public void DrawTexture( + VulkanGraphicsDevice gd, + PipelineBase pipeline, + TextureView src, + ISampler srcSampler, + Extents2DF srcRegion, + Extents2DF dstRegion) + { + const int RegionBufferSize = 16; + + pipeline.SetTextureAndSampler(32, src, srcSampler); + + Span region = stackalloc float[RegionBufferSize / sizeof(float)]; + + region[0] = srcRegion.X1 / src.Width; + region[1] = srcRegion.X2 / src.Width; + region[2] = srcRegion.Y1 / src.Height; + region[3] = srcRegion.Y2 / src.Height; + + if (dstRegion.X1 > dstRegion.X2) + { + float temp = region[0]; + region[0] = region[1]; + region[1] = temp; + } + + if (dstRegion.Y1 > dstRegion.Y2) + { + float temp = region[2]; + region[2] = region[3]; + region[3] = temp; + } + + var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize); + + gd.BufferManager.SetData(bufferHandle, 0, region); + + Span bufferRanges = stackalloc BufferRange[1]; + + bufferRanges[0] = new BufferRange(bufferHandle, 0, RegionBufferSize); + + pipeline.SetUniformBuffers(1, bufferRanges); + + Span viewports = stackalloc GAL.Viewport[1]; + + var rect = new Rectangle( + MathF.Min(dstRegion.X1, dstRegion.X2), + MathF.Min(dstRegion.Y1, dstRegion.Y2), + MathF.Abs(dstRegion.X2 - dstRegion.X1), + MathF.Abs(dstRegion.Y2 - dstRegion.Y1)); + + viewports[0] = new GAL.Viewport( + rect, + ViewportSwizzle.PositiveX, + ViewportSwizzle.PositiveY, + ViewportSwizzle.PositiveZ, + ViewportSwizzle.PositiveW, + 0f, + 1f); + + Span> scissors = stackalloc Rectangle[1]; + + pipeline.SetProgram(_programColorBlit); + pipeline.SetViewports(0, viewports); + pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip); + pipeline.Draw(4, 1, 0, 0); + + gd.BufferManager.Delete(bufferHandle); + } + public unsafe void ConvertI8ToI16(VulkanGraphicsDevice gd, CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size) { // TODO: Do this with a compute shader? diff --git a/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/Ryujinx.Graphics.Vulkan/PipelineBase.cs index c02b13517..007cb9c83 100644 --- a/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -292,7 +292,50 @@ namespace Ryujinx.Graphics.Vulkan public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion) { - throw new NotImplementedException(); + if (texture is TextureView srcTexture) + { + var oldCullMode = _newState.CullMode; + var oldStencilTestEnable = _newState.StencilTestEnable; + var oldDepthTestEnable = _newState.DepthTestEnable; + var oldDepthWriteEnable = _newState.DepthWriteEnable; + var oldTopology = _newState.Topology; + var oldViewports = VulkanConfiguration.UseDynamicState ? _dynamicState.Viewports : _newState.Internal.Viewports; + var oldViewportsCount = _newState.ViewportsCount; + + _newState.CullMode = CullModeFlags.CullModeNone; + _newState.StencilTestEnable = false; + _newState.DepthTestEnable = false; + _newState.DepthWriteEnable = false; + SignalStateChange(); + + Gd.HelperShader.DrawTexture( + Gd, + this, + srcTexture, + sampler, + srcRegion, + dstRegion); + + _newState.CullMode = oldCullMode; + _newState.StencilTestEnable = oldStencilTestEnable; + _newState.DepthTestEnable = oldDepthTestEnable; + _newState.DepthWriteEnable = oldDepthWriteEnable; + _newState.Topology = oldTopology; + + if (VulkanConfiguration.UseDynamicState) + { + _dynamicState.Viewports = oldViewports; + _dynamicState.ViewportsCount = (int)oldViewportsCount; + _dynamicState.SetViewportsDirty(); + } + else + { + _newState.Internal.Viewports = oldViewports; + } + + _newState.ViewportsCount = oldViewportsCount; + SignalStateChange(); + } } public void EndTransformFeedback() @@ -425,7 +468,7 @@ namespace Ryujinx.Graphics.Vulkan public void SetFaceCulling(bool enable, Face face) { - _newState.CullMode = enable ? face.Convert() : 0; + _newState.CullMode = enable ? face.Convert() : CullModeFlags.CullModeNone; SignalStateChange(); } diff --git a/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs b/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs index 96b961800..2553101d7 100644 --- a/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs +++ b/Ryujinx.Graphics.Vulkan/PipelineDynamicState.cs @@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Vulkan private uint _frontReference; public int ViewportsCount; - private Array16 _viewports; + public Array16 Viewports; private enum DirtyFlags { @@ -70,11 +70,16 @@ namespace Ryujinx.Graphics.Vulkan public void SetViewport(int index, Viewport viewport) { - _viewports[index] = viewport; + Viewports[index] = viewport; _dirty |= DirtyFlags.Viewport; } + public void SetViewportsDirty() + { + _dirty |= DirtyFlags.Viewport; + } + public void ForceAllDirty() { _dirty = DirtyFlags.All; @@ -127,7 +132,7 @@ namespace Ryujinx.Graphics.Vulkan private void RecordViewport(Vk api, CommandBuffer commandBuffer) { - api.CmdSetViewport(commandBuffer, 0, (uint)ViewportsCount, _viewports.ToSpan()); + api.CmdSetViewport(commandBuffer, 0, (uint)ViewportsCount, Viewports.ToSpan()); } } }