using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Gpu.State;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Gpu.Engine
{
partial class Methods
{
// State associated with direct uniform buffer updates.
// This state is used to attempt to batch together consecutive updates.
private ulong _ubBeginCpuAddress = 0;
private ulong _ubFollowUpAddress = 0;
private ulong _ubByteCount = 0;
///
/// Flushes any queued ubo updates.
///
/// GPU memory manager where the uniform buffer is mapped
private void FlushUboDirty(MemoryManager memoryManager)
{
if (_ubFollowUpAddress != 0)
{
memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount);
_ubFollowUpAddress = 0;
}
}
///
/// Updates the uniform buffer data with inline data.
///
/// Current GPU state
/// New uniform buffer data word
private void UniformBufferUpdate(GpuState state, int argument)
{
var uniformBuffer = state.Get(MethodOffset.UniformBufferState);
ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
if (_ubFollowUpAddress != address)
{
FlushUboDirty(state.Channel.MemoryManager);
_ubByteCount = 0;
_ubBeginCpuAddress = state.Channel.MemoryManager.Translate(address);
}
var byteData = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref argument, 1));
state.Channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
_ubFollowUpAddress = address + 4;
_ubByteCount += 4;
state.SetUniformBufferOffset(uniformBuffer.Offset + 4);
}
///
/// Updates the uniform buffer data with inline data.
///
/// Current GPU state
/// Data to be written to the uniform buffer
public void UniformBufferUpdate(GpuState state, ReadOnlySpan data)
{
var uniformBuffer = state.Get(MethodOffset.UniformBufferState);
ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
ulong size = (ulong)data.Length * 4;
if (_ubFollowUpAddress != address)
{
FlushUboDirty(state.Channel.MemoryManager);
_ubByteCount = 0;
_ubBeginCpuAddress = state.Channel.MemoryManager.Translate(address);
}
var byteData = MemoryMarshal.Cast(data);
state.Channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
_ubFollowUpAddress = address + size;
_ubByteCount += size;
state.SetUniformBufferOffset(uniformBuffer.Offset + data.Length * 4);
}
}
}