aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Compute.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Methods.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs18
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs9
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TexturePool.cs5
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferManager.cs60
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs60
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs2
-rw-r--r--Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs14
-rw-r--r--Ryujinx.Graphics.OpenGL/Renderer.cs6
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs3
-rw-r--r--Ryujinx.Graphics.Shader/TextureUsageFlags.cs3
12 files changed, 154 insertions, 30 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute.cs b/Ryujinx.Graphics.Gpu/Engine/Compute.cs
index c7e059ba..bcff5953 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Compute.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Compute.cs
@@ -141,8 +141,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
TextureManager.SetComputeImages(imageBindings);
- BufferManager.CommitComputeBindings();
TextureManager.CommitComputeBindings();
+ BufferManager.CommitComputeBindings();
_context.Renderer.Pipeline.DispatchCompute(
qmd.CtaRasterWidth,
diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
index 0731f1c2..033311b2 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
@@ -304,8 +304,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
UpdateStorageBuffers();
- BufferManager.CommitGraphicsBindings();
TextureManager.CommitGraphicsBindings();
+ BufferManager.CommitGraphicsBindings();
}
/// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index 173340b3..7fea7ebe 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -303,7 +303,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// Ensure that the buffer texture is using the correct buffer as storage.
// Buffers are frequently re-created to accomodate larger data, so we need to re-bind
// to ensure we're not using a old buffer that was already deleted.
- _context.Methods.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, _isCompute);
+ _context.Methods.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, bindingInfo.Format, false);
}
Sampler sampler = _samplerPool.Get(samplerId);
@@ -349,12 +349,26 @@ namespace Ryujinx.Graphics.Gpu.Image
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
+ bool isStore = bindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
+
if (hostTexture != null && texture.Target == Target.TextureBuffer)
{
// Ensure that the buffer texture is using the correct buffer as storage.
// Buffers are frequently re-created to accomodate larger data, so we need to re-bind
// to ensure we're not using a old buffer that was already deleted.
- _context.Methods.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, _isCompute);
+
+ Format format = bindingInfo.Format;
+
+ if (format == 0 && texture != null)
+ {
+ format = texture.Format;
+ }
+
+ _context.Methods.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, format, true);
+ }
+ else if (isStore)
+ {
+ texture?.SignalModified();
}
if (_imageState[stageIndex][index].Texture != hostTexture || _rebind)
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs
index e85df136..62862e74 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs
@@ -154,6 +154,15 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
+ /// Unpack the width of a buffer texture.
+ /// </summary>
+ /// <returns>The texture width</returns>
+ public int UnpackBufferTextureWidth()
+ {
+ return (int)((Word4 & 0xffff) | (Word3 << 16)) + 1;
+ }
+
+ /// <summary>
/// Unpacks the texture sRGB format flag.
/// </summary>
/// <returns>True if the texture is sRGB, false otherwise</returns>
diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
index eece2a79..8f225f16 100644
--- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
@@ -172,8 +172,6 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>The texture information</returns>
private TextureInfo GetInfo(TextureDescriptor descriptor, out int layerSize)
{
- int width = descriptor.UnpackWidth();
- int height = descriptor.UnpackHeight();
int depthOrLayers = descriptor.UnpackDepth();
int levels = descriptor.UnpackLevels();
@@ -190,6 +188,9 @@ namespace Ryujinx.Graphics.Gpu.Image
Target target = descriptor.UnpackTextureTarget().Convert((samplesInX | samplesInY) != 1);
+ int width = target == Target.TextureBuffer ? descriptor.UnpackBufferTextureWidth() : descriptor.UnpackWidth();
+ int height = descriptor.UnpackHeight();
+
// We use 2D targets for 1D textures as that makes texture cache
// management easier. We don't know the target for render target
// and copies, so those would normally use 2D targets, which are
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
index 08d52faa..b2cd1ced 100644
--- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
@@ -1,9 +1,11 @@
using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.State;
using Ryujinx.Graphics.Shader;
using Ryujinx.Memory.Range;
using System;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
@@ -31,6 +33,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
private IndexBuffer _indexBuffer;
private VertexBuffer[] _vertexBuffers;
private BufferBounds[] _transformFeedbackBuffers;
+ private List<BufferTextureBinding> _bufferTextures;
/// <summary>
/// Holds shader stage buffer state and binding information.
@@ -138,6 +141,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
_gpStorageBuffers[index] = new BuffersPerStage(Constants.TotalGpStorageBuffers);
_gpUniformBuffers[index] = new BuffersPerStage(Constants.TotalGpUniformBuffers);
}
+
+ _bufferTextures = new List<BufferTextureBinding>();
}
/// <summary>
@@ -620,11 +625,40 @@ namespace Ryujinx.Graphics.Gpu.Memory
_context.Renderer.Pipeline.SetUniformBuffers(uRanges);
+ CommitBufferTextureBindings();
+
// Force rebind after doing compute work.
_rebind = true;
}
/// <summary>
+ /// Commit any queued buffer texture bindings.
+ /// </summary>
+ private void CommitBufferTextureBindings()
+ {
+ if (_bufferTextures.Count > 0)
+ {
+ foreach (var binding in _bufferTextures)
+ {
+ binding.Texture.SetStorage(GetBufferRange(binding.Address, binding.Size, binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore)));
+
+ // The texture must be rebound to use the new storage if it was updated.
+
+ if (binding.IsImage)
+ {
+ _context.Renderer.Pipeline.SetImage(binding.BindingInfo.Binding, binding.Texture, binding.Format);
+ }
+ else
+ {
+ _context.Renderer.Pipeline.SetTexture(binding.BindingInfo.Binding, binding.Texture);
+ }
+ }
+
+ _bufferTextures.Clear();
+ }
+ }
+
+ /// <summary>
/// Ensures that the graphics engine bindings are visible to the host GPU.
/// Note: this actually performs the binding using the host graphics API.
/// </summary>
@@ -743,6 +777,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
UpdateBuffers(_gpUniformBuffers);
}
+ CommitBufferTextureBindings();
+
_rebind = false;
}
@@ -813,31 +849,19 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
- /// Sets the buffer storage of a buffer texture.
+ /// Sets the buffer storage of a buffer texture. This will be bound when the buffer manager commits bindings.
/// </summary>
/// <param name="texture">Buffer texture</param>
/// <param name="address">Address of the buffer in memory</param>
/// <param name="size">Size of the buffer in bytes</param>
- /// <param name="compute">Indicates if the buffer texture belongs to the compute or graphics pipeline</param>
- public void SetBufferTextureStorage(ITexture texture, ulong address, ulong size, bool compute)
+ /// <param name="bindingInfo">Binding info for the buffer texture</param>
+ /// <param name="format">Format of the buffer texture</param>
+ /// <param name="isImage">Whether the binding is for an image or a sampler</param>
+ public void SetBufferTextureStorage(ITexture texture, ulong address, ulong size, TextureBindingInfo bindingInfo, Format format, bool isImage)
{
CreateBuffer(address, size);
- if (_rebind)
- {
- // We probably had to modify existing buffers to create the texture buffer,
- // so rebind everything to ensure we're using the new buffers for all bound resources.
- if (compute)
- {
- CommitComputeBindings();
- }
- else
- {
- CommitGraphicsBindings();
- }
- }
-
- texture.SetStorage(GetBufferRange(address, size));
+ _bufferTextures.Add(new BufferTextureBinding(texture, address, size, bindingInfo, format, isImage));
}
/// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs b/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs
new file mode 100644
index 00000000..cf0d225e
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs
@@ -0,0 +1,60 @@
+using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Image;
+
+namespace Ryujinx.Graphics.Gpu.Memory
+{
+ /// <summary>
+ /// A buffer binding to apply to a buffer texture.
+ /// </summary>
+ struct BufferTextureBinding
+ {
+ /// <summary>
+ /// The buffer texture.
+ /// </summary>
+ public ITexture Texture { get; }
+
+ /// <summary>
+ /// The base address of the buffer binding.
+ /// </summary>
+ public ulong Address { get; }
+
+ /// <summary>
+ /// The size of the buffer binding in bytes.
+ /// </summary>
+ public ulong Size { get; }
+
+ /// <summary>
+ /// The image or sampler binding info for the buffer texture.
+ /// </summary>
+ public TextureBindingInfo BindingInfo { get; }
+
+ /// <summary>
+ /// The image format for the binding.
+ /// </summary>
+ public Format Format { get; }
+
+ /// <summary>
+ /// Whether the binding is for an image or a sampler.
+ /// </summary>
+ public bool IsImage { get; }
+
+ /// <summary>
+ /// Create a new buffer texture binding.
+ /// </summary>
+ /// <param name="texture">Buffer texture</param>
+ /// <param name="address">Base address</param>
+ /// <param name="size">Size in bytes</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>
+ public BufferTextureBinding(ITexture texture, ulong address, ulong size, TextureBindingInfo bindingInfo, Format format, bool isImage)
+ {
+ Texture = texture;
+ Address = address;
+ Size = size;
+ BindingInfo = bindingInfo;
+ Format = format;
+ IsImage = isImage;
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index bf89f29d..768a58e7 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -35,7 +35,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary>
/// Version of the codegen (to be changed when codegen or guest format change).
/// </summary>
- private const ulong ShaderCodeGenVersion = 1961;
+ private const ulong ShaderCodeGenVersion = 2088;
// Progress reporting helpers
private int _shaderCount;
diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs b/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
index 5607fb40..f49a0647 100644
--- a/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
+++ b/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
@@ -6,12 +6,17 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
class TextureBuffer : TextureBase, ITexture
{
+ private Renderer _renderer;
private int _bufferOffset;
private int _bufferSize;
+ private int _bufferCount;
private BufferHandle _buffer;
- public TextureBuffer(TextureCreateInfo info) : base(info) {}
+ public TextureBuffer(Renderer renderer, TextureCreateInfo info) : base(info)
+ {
+ _renderer = renderer;
+ }
public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
{
@@ -50,16 +55,19 @@ namespace Ryujinx.Graphics.OpenGL.Image
public void SetStorage(BufferRange buffer)
{
- if (buffer.Handle == _buffer &&
+ if (_buffer != BufferHandle.Null &&
buffer.Offset == _bufferOffset &&
- buffer.Size == _bufferSize)
+ buffer.Size == _bufferSize &&
+ _renderer.BufferCount == _bufferCount)
{
+ // Only rebind the buffer when more have been created.
return;
}
_buffer = buffer.Handle;
_bufferOffset = buffer.Offset;
_bufferSize = buffer.Size;
+ _bufferCount = _renderer.BufferCount;
Bind(0);
diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs
index 4a3f51bf..c3d08309 100644
--- a/Ryujinx.Graphics.OpenGL/Renderer.cs
+++ b/Ryujinx.Graphics.OpenGL/Renderer.cs
@@ -30,6 +30,8 @@ namespace Ryujinx.Graphics.OpenGL
internal ResourcePool ResourcePool { get; }
+ internal int BufferCount { get; private set; }
+
public string GpuVendor { get; private set; }
public string GpuRenderer { get; private set; }
public string GpuVersion { get; private set; }
@@ -52,6 +54,8 @@ namespace Ryujinx.Graphics.OpenGL
public BufferHandle CreateBuffer(int size)
{
+ BufferCount++;
+
return Buffer.Create(size);
}
@@ -69,7 +73,7 @@ namespace Ryujinx.Graphics.OpenGL
{
if (info.Target == Target.TextureBuffer)
{
- return new TextureBuffer(info);
+ return new TextureBuffer(this, info);
}
else
{
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
index 3bfc0647..fc5b06b1 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
@@ -111,6 +111,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
if (texOp.Inst == Instruction.ImageStore)
{
+ int texIndex = context.FindImageDescriptorIndex(texOp);
+ context.ImageDescriptors[texIndex] = context.ImageDescriptors[texIndex].SetFlag(TextureUsageFlags.ImageStore);
+
VariableType type = texOp.Format.GetComponentType();
string[] cElems = new string[4];
diff --git a/Ryujinx.Graphics.Shader/TextureUsageFlags.cs b/Ryujinx.Graphics.Shader/TextureUsageFlags.cs
index 1f024309..87be0d01 100644
--- a/Ryujinx.Graphics.Shader/TextureUsageFlags.cs
+++ b/Ryujinx.Graphics.Shader/TextureUsageFlags.cs
@@ -12,6 +12,7 @@ namespace Ryujinx.Graphics.Shader
// Integer sampled textures must be noted for resolution scaling.
ResScaleUnsupported = 1 << 0,
- NeedsScaleValue = 1 << 1
+ NeedsScaleValue = 1 << 1,
+ ImageStore = 1 << 2
}
}