aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Graphics.GAL/ITexture.cs1
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs2
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/CommandType.cs1
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs31
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs6
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs3
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs27
-rw-r--r--Ryujinx.Graphics.Gpu/Image/Texture.cs18
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureCache.cs10
-rw-r--r--Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs5
-rw-r--r--Ryujinx.Graphics.OpenGL/Image/TextureView.cs75
-rw-r--r--Ryujinx.Graphics.Vulkan/TextureBuffer.cs5
-rw-r--r--Ryujinx.Graphics.Vulkan/TextureView.cs43
13 files changed, 196 insertions, 31 deletions
diff --git a/Ryujinx.Graphics.GAL/ITexture.cs b/Ryujinx.Graphics.GAL/ITexture.cs
index 96b59293..7f46806c 100644
--- a/Ryujinx.Graphics.GAL/ITexture.cs
+++ b/Ryujinx.Graphics.GAL/ITexture.cs
@@ -19,6 +19,7 @@ namespace Ryujinx.Graphics.GAL
void SetData(ReadOnlySpan<byte> data);
void SetData(ReadOnlySpan<byte> data, int layer, int level);
+ void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region);
void SetStorage(BufferRange buffer);
void Release();
}
diff --git a/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs b/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs
index ea4d049f..8080ab64 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs
@@ -113,6 +113,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading
TextureSetDataCommand.Run(ref GetCommand<TextureSetDataCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureSetDataSlice] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TextureSetDataSliceCommand.Run(ref GetCommand<TextureSetDataSliceCommand>(memory), threaded, renderer);
+ _lookup[(int)CommandType.TextureSetDataSliceRegion] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
+ TextureSetDataSliceRegionCommand.Run(ref GetCommand<TextureSetDataSliceRegionCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureSetStorage] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TextureSetStorageCommand.Run(ref GetCommand<TextureSetStorageCommand>(memory), threaded, renderer);
diff --git a/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs b/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs
index 8c3ad844..c25f0834 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/CommandType.cs
@@ -37,6 +37,7 @@
TextureRelease,
TextureSetData,
TextureSetDataSlice,
+ TextureSetDataSliceRegion,
TextureSetStorage,
WindowPresent,
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs
new file mode 100644
index 00000000..b4285592
--- /dev/null
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs
@@ -0,0 +1,31 @@
+using Ryujinx.Graphics.GAL.Multithreading.Model;
+using Ryujinx.Graphics.GAL.Multithreading.Resources;
+using System;
+
+namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
+{
+ struct TextureSetDataSliceRegionCommand : IGALCommand
+ {
+ public CommandType CommandType => CommandType.TextureSetDataSliceRegion;
+ private TableRef<ThreadedTexture> _texture;
+ private TableRef<byte[]> _data;
+ private int _layer;
+ private int _level;
+ private Rectangle<int> _region;
+
+ public void Set(TableRef<ThreadedTexture> texture, TableRef<byte[]> data, int layer, int level, Rectangle<int> region)
+ {
+ _texture = texture;
+ _data = data;
+ _layer = layer;
+ _level = level;
+ _region = region;
+ }
+
+ public static void Run(ref TextureSetDataSliceRegionCommand command, ThreadedRenderer threaded, IRenderer renderer)
+ {
+ ThreadedTexture texture = command._texture.Get(threaded);
+ texture.Base.SetData(new ReadOnlySpan<byte>(command._data.Get(threaded)), command._layer, command._level, command._region);
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs b/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs
index 64d8aa3b..1e7d86ba 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs
@@ -119,6 +119,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
_renderer.QueueCommand();
}
+ public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
+ {
+ _renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data.ToArray()), layer, level, region);
+ _renderer.QueueCommand();
+ }
+
public void SetStorage(BufferRange buffer)
{
_renderer.New<TextureSetStorageCommand>().Set(Ref(this), buffer);
diff --git a/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs b/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
index 5814eeb7..da25a89d 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
@@ -224,7 +224,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
xCount,
yCount,
dstLinear,
- dst.MemoryLayout);
+ dst.MemoryLayout.UnpackGobBlocksInY(),
+ dst.MemoryLayout.UnpackGobBlocksInZ());
if (target != null)
{
diff --git a/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs b/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
index c0939057..6120d295 100644
--- a/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
@@ -29,6 +29,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
private int _dstHeight;
private int _dstStride;
private int _dstGobBlocksInY;
+ private int _dstGobBlocksInZ;
private int _lineLengthIn;
private int _lineCount;
@@ -117,6 +118,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
_dstHeight = (int)state.SetDstHeight;
_dstStride = (int)state.PitchOut;
_dstGobBlocksInY = 1 << (int)state.SetDstBlockSizeHeight;
+ _dstGobBlocksInZ = 1 << (int)state.SetDstBlockSizeDepth;
_lineLengthIn = (int)state.LineLengthIn;
_lineCount = (int)state.LineCount;
@@ -176,6 +178,31 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
}
else
{
+ // TODO: Verify if the destination X/Y and width/height are taken into account
+ // for linear texture transfers. If not, we can use the fast path for that aswell.
+ // Right now the copy code at the bottom assumes that it is used on both which might be incorrect.
+ if (!_isLinear)
+ {
+ var target = memoryManager.Physical.TextureCache.FindTexture(
+ memoryManager,
+ _dstGpuVa,
+ 1,
+ _dstStride,
+ _dstHeight,
+ _lineLengthIn,
+ _lineCount,
+ _isLinear,
+ _dstGobBlocksInY,
+ _dstGobBlocksInZ);
+
+ if (target != null)
+ {
+ target.SetData(data, 0, 0, new GAL.Rectangle<int>(_dstX, _dstY, _lineLengthIn / target.Info.FormatInfo.BytesPerPixel, _lineCount));
+
+ return;
+ }
+ }
+
var dstCalculator = new OffsetCalculator(
_dstWidth,
_dstHeight,
diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs
index a598f212..320bc014 100644
--- a/Ryujinx.Graphics.Gpu/Image/Texture.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs
@@ -762,6 +762,24 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
+ /// Uploads new texture data to the host GPU for a specific layer/level and 2D sub-region.
+ /// </summary>
+ /// <param name="data">New data</param>
+ /// <param name="layer">Target layer</param>
+ /// <param name="level">Target level</param>
+ /// <param name="region">Target sub-region of the texture to update</param>
+ public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
+ {
+ BlacklistScale();
+
+ HostTexture.SetData(data, layer, level, region);
+
+ _currentData = null;
+
+ _hasData = true;
+ }
+
+ /// <summary>
/// Converts texture data to a format and layout that is supported by the host GPU.
/// </summary>
/// <param name="data">Data to be converted</param>
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index dcac9f64..d76879eb 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -905,7 +905,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="xCount">Number of pixels to be copied per line</param>
/// <param name="yCount">Number of lines to be copied</param>
/// <param name="linear">True if the texture has a linear layout, false otherwise</param>
- /// <param name="memoryLayout">If <paramref name="linear"/> is false, should have the memory layout, otherwise ignored</param>
+ /// <param name="gobBlocksInY">If <paramref name="linear"/> is false, the amount of GOB blocks in the Y axis</param>
+ /// <param name="gobBlocksInZ">If <paramref name="linear"/> is false, the amount of GOB blocks in the Z axis</param>
/// <returns>A matching texture, or null if there is no match</returns>
public Texture FindTexture(
MemoryManager memoryManager,
@@ -916,7 +917,8 @@ namespace Ryujinx.Graphics.Gpu.Image
int xCount,
int yCount,
bool linear,
- MemoryLayout memoryLayout)
+ int gobBlocksInY,
+ int gobBlocksInZ)
{
ulong address = memoryManager.Translate(gpuVa);
@@ -955,8 +957,8 @@ namespace Ryujinx.Graphics.Gpu.Image
bool sizeMatch = xCount * bpp == texture.Info.Width * format.BytesPerPixel && height == texture.Info.Height;
bool formatMatch = !texture.Info.IsLinear &&
- texture.Info.GobBlocksInY == memoryLayout.UnpackGobBlocksInY() &&
- texture.Info.GobBlocksInZ == memoryLayout.UnpackGobBlocksInZ();
+ texture.Info.GobBlocksInY == gobBlocksInY &&
+ texture.Info.GobBlocksInZ == gobBlocksInZ;
match = sizeMatch && formatMatch;
}
diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs b/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
index e5b39aa6..e46d5c48 100644
--- a/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
+++ b/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
@@ -58,6 +58,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
throw new NotSupportedException();
}
+ public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
+ {
+ throw new NotSupportedException();
+ }
+
public void SetStorage(BufferRange buffer)
{
if (_buffer != BufferHandle.Null &&
diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureView.cs b/Ryujinx.Graphics.OpenGL/Image/TextureView.cs
index 8f9e2a66..243ca1b3 100644
--- a/Ryujinx.Graphics.OpenGL/Image/TextureView.cs
+++ b/Ryujinx.Graphics.OpenGL/Image/TextureView.cs
@@ -1,4 +1,5 @@
using OpenTK.Graphics.OpenGL;
+using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
using System;
@@ -385,7 +386,34 @@ namespace Ryujinx.Graphics.OpenGL.Image
int width = Math.Max(Info.Width >> level, 1);
int height = Math.Max(Info.Height >> level, 1);
- ReadFrom2D((IntPtr)ptr, layer, level, width, height);
+ ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height);
+ }
+ }
+ }
+
+ public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
+ {
+ if (Format == Format.S8UintD24Unorm)
+ {
+ data = FormatConverter.ConvertS8D24ToD24S8(data);
+ }
+
+ int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
+ int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight);
+
+ unsafe
+ {
+ fixed (byte* ptr = data)
+ {
+ ReadFrom2D(
+ (IntPtr)ptr,
+ layer,
+ level,
+ region.X,
+ region.Y,
+ region.Width,
+ region.Height,
+ BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks);
}
}
}
@@ -397,15 +425,20 @@ namespace Ryujinx.Graphics.OpenGL.Image
public void ReadFromPbo2D(int offset, int layer, int level, int width, int height)
{
- ReadFrom2D(IntPtr.Zero + offset, layer, level, width, height);
+ ReadFrom2D(IntPtr.Zero + offset, layer, level, 0, 0, width, height);
}
- private void ReadFrom2D(IntPtr data, int layer, int level, int width, int height)
+ private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height)
{
- TextureTarget target = Target.Convert();
-
int mipSize = Info.GetMipSize2D(level);
+ ReadFrom2D(data, layer, level, x, y, width, height, mipSize);
+ }
+
+ private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height, int mipSize)
+ {
+ TextureTarget target = Target.Convert();
+
Bind(target, 0);
FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
@@ -418,7 +451,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
GL.CompressedTexSubImage1D(
target,
level,
- 0,
+ x,
width,
format.PixelFormat,
mipSize,
@@ -429,7 +462,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
GL.TexSubImage1D(
target,
level,
- 0,
+ x,
width,
format.PixelFormat,
format.PixelType,
@@ -443,7 +476,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
GL.CompressedTexSubImage2D(
target,
level,
- 0,
+ x,
layer,
width,
1,
@@ -456,7 +489,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
GL.TexSubImage2D(
target,
level,
- 0,
+ x,
layer,
width,
1,
@@ -472,8 +505,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
GL.CompressedTexSubImage2D(
target,
level,
- 0,
- 0,
+ x,
+ y,
width,
height,
format.PixelFormat,
@@ -485,8 +518,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
GL.TexSubImage2D(
target,
level,
- 0,
- 0,
+ x,
+ y,
width,
height,
format.PixelFormat,
@@ -503,8 +536,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
GL.CompressedTexSubImage3D(
target,
level,
- 0,
- 0,
+ x,
+ y,
layer,
width,
height,
@@ -518,8 +551,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
GL.TexSubImage3D(
target,
level,
- 0,
- 0,
+ x,
+ y,
layer,
width,
height,
@@ -536,8 +569,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
GL.CompressedTexSubImage2D(
TextureTarget.TextureCubeMapPositiveX + layer,
level,
- 0,
- 0,
+ x,
+ y,
width,
height,
format.PixelFormat,
@@ -549,8 +582,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
GL.TexSubImage2D(
TextureTarget.TextureCubeMapPositiveX + layer,
level,
- 0,
- 0,
+ x,
+ y,
width,
height,
format.PixelFormat,
diff --git a/Ryujinx.Graphics.Vulkan/TextureBuffer.cs b/Ryujinx.Graphics.Vulkan/TextureBuffer.cs
index c7495610..3e90a96f 100644
--- a/Ryujinx.Graphics.Vulkan/TextureBuffer.cs
+++ b/Ryujinx.Graphics.Vulkan/TextureBuffer.cs
@@ -98,6 +98,11 @@ namespace Ryujinx.Graphics.Vulkan
throw new NotSupportedException();
}
+ public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
+ {
+ throw new NotSupportedException();
+ }
+
public void SetStorage(BufferRange buffer)
{
if (_bufferHandle == buffer.Handle &&
diff --git a/Ryujinx.Graphics.Vulkan/TextureView.cs b/Ryujinx.Graphics.Vulkan/TextureView.cs
index d94587bd..2eeafae9 100644
--- a/Ryujinx.Graphics.Vulkan/TextureView.cs
+++ b/Ryujinx.Graphics.Vulkan/TextureView.cs
@@ -819,7 +819,7 @@ namespace Ryujinx.Graphics.Vulkan
var buffer = bufferHolder.GetBuffer(cbs.CommandBuffer).Get(cbs).Value;
var image = GetImage().Get(cbs).Value;
- CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, size, true, x, y, width, height);
+ CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, size, true, 0, 0, x, y, width, height);
}
bufferHolder.WaitForFences();
@@ -893,7 +893,12 @@ namespace Ryujinx.Graphics.Vulkan
SetData(data, layer, level, 1, 1, singleSlice: true);
}
- private void SetData(ReadOnlySpan<byte> data, int layer, int level, int layers, int levels, bool singleSlice)
+ public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
+ {
+ SetData(data, layer, level, 1, 1, singleSlice: true, region);
+ }
+
+ private void SetData(ReadOnlySpan<byte> data, int layer, int level, int layers, int levels, bool singleSlice, Rectangle<int>? region = null)
{
int bufferDataLength = GetBufferDataLength(data.Length);
@@ -917,7 +922,25 @@ namespace Ryujinx.Graphics.Vulkan
var buffer = bufferHolder.GetBuffer(cbs.CommandBuffer).Get(cbs).Value;
var image = imageAuto.Get(cbs).Value;
- CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, bufferDataLength, false, layer, level, layers, levels, singleSlice);
+ if (region.HasValue)
+ {
+ CopyFromOrToBuffer(
+ cbs.CommandBuffer,
+ buffer,
+ image,
+ bufferDataLength,
+ false,
+ layer,
+ level,
+ region.Value.X,
+ region.Value.Y,
+ region.Value.Width,
+ region.Value.Height);
+ }
+ else
+ {
+ CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, bufferDataLength, false, layer, level, layers, levels, singleSlice);
+ }
}
private int GetBufferDataLength(int length)
@@ -1059,6 +1082,8 @@ namespace Ryujinx.Graphics.Vulkan
Image image,
int size,
bool to,
+ int dstLayer,
+ int dstLevel,
int x,
int y,
int width,
@@ -1071,13 +1096,21 @@ namespace Ryujinx.Graphics.Vulkan
aspectFlags = ImageAspectFlags.ImageAspectDepthBit;
}
- var sl = new ImageSubresourceLayers(aspectFlags, (uint)FirstLevel, (uint)FirstLayer, 1);
+ var sl = new ImageSubresourceLayers(aspectFlags, (uint)(FirstLevel + dstLevel), (uint)(FirstLayer + dstLayer), 1);
var extent = new Extent3D((uint)width, (uint)height, 1);
+ int rowLengthAlignment = Info.BlockWidth;
+
+ // We expect all data being written into the texture to have a stride aligned by 4.
+ if (!to && Info.BytesPerPixel < 4)
+ {
+ rowLengthAlignment = 4 / Info.BytesPerPixel;
+ }
+
var region = new BufferImageCopy(
0,
- (uint)AlignUpNpot(width, Info.BlockWidth),
+ (uint)AlignUpNpot(width, rowLengthAlignment),
(uint)AlignUpNpot(height, Info.BlockHeight),
sl,
new Offset3D(x, y, 0),