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); } } }