Compare commits

..

4 Commits

Author SHA1 Message Date
gdkchan
7c1d2bbb98 Implement OpenDataStorageWithProgramIndex partially (#3765)
* Implement OpenDataStorageWithProgramIndex partially

* Was not supposed to change this
2022-10-17 13:37:05 +00:00
mageven
beacf8c1c8 TamperMachine: Fix input mask check (#3764) 2022-10-16 19:51:52 -03:00
riperiperi
0dbe45ae37 Fix various issues caused by Vertex/Index buffer conversions (#3762)
* Fix various issues caused by #3679

- The arguments for the 0th dummy vertex buffer were incorrect - it was given an offset of 16 rather than a size of 16.
- The wrong size was used when doing `autoBuffer.Get` on a converted vertex buffer.
- The possibility of a vertex buffer being disposed and then rebound can rebindings to find a different buffer where the current range is out of bounds. Avoid binding when out of range to prevent validation errors.
- The above also affects generation of converted buffers, which was a bit more fatal. Conversion functions now attempt to bound input offset/size.

* Fix offset for converted buffer
2022-10-16 19:38:58 -03:00
riperiperi
2b50e52e48 Fix primitive count calculation for topology conversion (#3763)
Luigi's Mansion 3 performs a non-index quads draw with 6 vertices. It's meant to ignore the last two, but the index pattern's primitive count calculation was rounding up.

No idea why the game does this but this should fix random triangles in the map.
2022-10-16 19:25:40 -03:00
7 changed files with 88 additions and 24 deletions

View File

@@ -386,8 +386,25 @@ namespace Ryujinx.Graphics.Vulkan
_waitable.WaitForFences(_gd.Api, _device, offset, size); _waitable.WaitForFences(_gd.Api, _device, offset, size);
} }
private bool BoundToRange(int offset, ref int size)
{
if (offset >= Size)
{
return false;
}
size = Math.Min(Size - offset, size);
return true;
}
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, int offset, int size) public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, int offset, int size)
{ {
if (!BoundToRange(offset, ref size))
{
return null;
}
var key = new I8ToI16CacheKey(_gd); var key = new I8ToI16CacheKey(_gd);
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder)) if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
@@ -407,6 +424,11 @@ namespace Ryujinx.Graphics.Vulkan
public Auto<DisposableBuffer> GetAlignedVertexBuffer(CommandBufferScoped cbs, int offset, int size, int stride, int alignment) public Auto<DisposableBuffer> GetAlignedVertexBuffer(CommandBufferScoped cbs, int offset, int size, int stride, int alignment)
{ {
if (!BoundToRange(offset, ref size))
{
return null;
}
var key = new AlignedVertexBufferCacheKey(_gd, stride, alignment); var key = new AlignedVertexBufferCacheKey(_gd, stride, alignment);
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder)) if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
@@ -428,6 +450,11 @@ namespace Ryujinx.Graphics.Vulkan
public Auto<DisposableBuffer> GetBufferTopologyConversion(CommandBufferScoped cbs, int offset, int size, IndexBufferPattern pattern, int indexSize) public Auto<DisposableBuffer> GetBufferTopologyConversion(CommandBufferScoped cbs, int offset, int size, IndexBufferPattern pattern, int indexSize)
{ {
if (!BoundToRange(offset, ref size))
{
return null;
}
var key = new TopologyConversionCacheKey(_gd, pattern, indexSize); var key = new TopologyConversionCacheKey(_gd, pattern, indexSize);
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder)) if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))

View File

@@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Vulkan
public int GetPrimitiveCount(int vertexCount) public int GetPrimitiveCount(int vertexCount)
{ {
return Math.Max(0, ((vertexCount - BaseIndex) + IndexStride - 1) / IndexStride); return Math.Max(0, (vertexCount - BaseIndex) / IndexStride);
} }
public int GetConvertedCount(int indexCount) public int GetConvertedCount(int indexCount)

View File

@@ -49,7 +49,12 @@ namespace Ryujinx.Graphics.Vulkan
} }
else else
{ {
autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int _); autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int bufferSize);
if (_offset >= bufferSize)
{
autoBuffer = null;
}
offset = _offset; offset = _offset;
size = _size; size = _size;

View File

@@ -95,7 +95,7 @@ namespace Ryujinx.Graphics.Vulkan
using var emptyVb = gd.BufferManager.Create(gd, EmptyVbSize); using var emptyVb = gd.BufferManager.Create(gd, EmptyVbSize);
emptyVb.SetData(0, new byte[EmptyVbSize]); emptyVb.SetData(0, new byte[EmptyVbSize]);
_vertexBuffers[0] = new VertexBufferState(emptyVb.GetBuffer(), 0, EmptyVbSize, 0); _vertexBuffers[0] = new VertexBufferState(emptyVb.GetBuffer(), 0, 0, EmptyVbSize, 0);
_vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length); _vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
ClearScissor = new Rectangle<int>(0, 0, 0xffff, 0xffff); ClearScissor = new Rectangle<int>(0, 0, 0xffff, 0xffff);
@@ -1243,7 +1243,7 @@ namespace Ryujinx.Graphics.Vulkan
_vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState); _vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState);
_vertexBuffersDirty &= ~(1u << i); _vertexBuffersDirty &= ~(1UL << i);
} }
} }

View File

@@ -57,37 +57,48 @@ namespace Ryujinx.Graphics.Vulkan
if (gd.NeedsVertexBufferAlignment(AttributeScalarAlignment, out int alignment) && (_stride % alignment) != 0) if (gd.NeedsVertexBufferAlignment(AttributeScalarAlignment, out int alignment) && (_stride % alignment) != 0)
{ {
autoBuffer = gd.BufferManager.GetAlignedVertexBuffer(cbs, _handle, _offset, _size, _stride, alignment); autoBuffer = gd.BufferManager.GetAlignedVertexBuffer(cbs, _handle, _offset, _size, _stride, alignment);
int stride = (_stride + (alignment - 1)) & -alignment;
var buffer = autoBuffer.Get(cbs, _offset, _size).Value; if (autoBuffer != null)
{
int stride = (_stride + (alignment - 1)) & -alignment;
int newSize = (_size / _stride) * stride;
if (gd.Capabilities.SupportsExtendedDynamicState) var buffer = autoBuffer.Get(cbs, 0, newSize).Value;
{
gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2( if (gd.Capabilities.SupportsExtendedDynamicState)
cbs.CommandBuffer, {
binding, gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
1, cbs.CommandBuffer,
buffer, binding,
0, 1,
(ulong)(_size / _stride) * (ulong)stride, buffer,
(ulong)stride); 0,
} (ulong)newSize,
else (ulong)stride);
{ }
gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, binding, 1, buffer, 0); else
{
gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, binding, 1, buffer, 0);
}
_buffer = autoBuffer;
} }
_buffer = autoBuffer; state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)stride;
return; return;
} }
else else
{ {
autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int _); autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int size);
// The original stride must be reapplied in case it was rewritten. // The original stride must be reapplied in case it was rewritten.
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride; state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
if (_offset >= size)
{
autoBuffer = null;
}
} }
} }

View File

@@ -12,6 +12,7 @@ using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy; using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy;
using System;
using System.IO; using System.IO;
using static Ryujinx.HLE.Utilities.StringUtils; using static Ryujinx.HLE.Utilities.StringUtils;
@@ -787,6 +788,26 @@ namespace Ryujinx.HLE.HOS.Services.Fs
return ResultCode.Success; return ResultCode.Success;
} }
[CommandHipc(205)]
// OpenDataStorageWithProgramIndex(u8 program_index) -> object<nn::fssrv::sf::IStorage>
public ResultCode OpenDataStorageWithProgramIndex(ServiceCtx context)
{
byte programIndex = context.RequestData.ReadByte();
if ((context.Device.Application.TitleId & 0xf) != programIndex)
{
throw new NotImplementedException($"Accessing storage from other programs is not supported (program index = {programIndex}).");
}
var storage = context.Device.FileSystem.RomFs.AsStorage(true);
using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage);
using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref()));
MakeObject(context, new FileSystemProxy.IStorage(ref sfStorage.Ref()));
return ResultCode.Success;
}
[CommandHipc(400)] [CommandHipc(400)]
// OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage // OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage
public ResultCode OpenDeviceOperator(ServiceCtx context) public ResultCode OpenDeviceOperator(ServiceCtx context)

View File

@@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Tamper.Conditions
public bool Evaluate() public bool Evaluate()
{ {
return (_input.Value & _mask) != 0; return (_input.Value & _mask) == _mask;
} }
} }
} }