diff --git a/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs b/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
index 44964b8fda..763391b407 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
@@ -115,7 +115,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
                 }
                 else /* if (type == LaunchDmaSemaphoreType.ReleaseFourWordSemaphore) */
                 {
-                    Logger.Warning?.Print(LogClass.Gpu, "DMA semaphore type ReleaseFourWordSemaphore was used, but is not currently implemented.");
+                    _channel.MemoryManager.Write(address + 8, _context.GetTimestamp());
+                    _channel.MemoryManager.Write(address, (ulong)_state.State.SetSemaphorePayload);
                 }
             }
         }
diff --git a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs
index dab4e9db63..686c2a9b67 100644
--- a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs
@@ -75,6 +75,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
 
             SemaphoredOperation operation = _state.State.SemaphoredOperation;
 
+            if (_state.State.SemaphoredReleaseSize == SemaphoredReleaseSize.SixteenBytes)
+            {
+                _parent.MemoryManager.Write(address + 4, 0);
+                _parent.MemoryManager.Write(address + 8, _context.GetTimestamp());
+            }
+
             // TODO: Acquire operations (Wait), interrupts for invalid combinations.
             if (operation == SemaphoredOperation.Release)
             {
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/SemaphoreUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/SemaphoreUpdater.cs
index cb0d593db2..986c02aba4 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/SemaphoreUpdater.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/SemaphoreUpdater.cs
@@ -1,6 +1,4 @@
-using Ryujinx.Common;
-using Ryujinx.Graphics.GAL;
-using System.Runtime.InteropServices;
+using Ryujinx.Graphics.GAL;
 
 namespace Ryujinx.Graphics.Gpu.Engine.Threed
 {
@@ -9,9 +7,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
     /// </summary>
     class SemaphoreUpdater
     {
-        private const int NsToTicksFractionNumerator = 384;
-        private const int NsToTicksFractionDenominator = 625;
-
         /// <summary>
         /// GPU semaphore operation.
         /// </summary>
@@ -154,14 +149,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
         {
             ulong gpuVa = _state.State.SemaphoreAddress.Pack();
 
-            ulong ticks = ConvertNanosecondsToTicks((ulong)PerformanceCounter.ElapsedNanoseconds);
-
-            if (GraphicsConfig.FastGpuTime)
-            {
-                // Divide by some amount to report time as if operations were performed faster than they really are.
-                // This can prevent some games from switching to a lower resolution because rendering is too slow.
-                ticks /= 256;
-            }
+            ulong ticks = _context.GetTimestamp();
 
             ICounterEvent counter = null;
 
@@ -197,27 +185,5 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
 
             _channel.MemoryManager.CounterCache.AddOrUpdate(gpuVa, counter);
         }
-
-        /// <summary>
-        /// Converts a nanoseconds timestamp value to Maxwell time ticks.
-        /// </summary>
-        /// <remarks>
-        /// The frequency is 614400000 Hz.
-        /// </remarks>
-        /// <param name="nanoseconds">Timestamp in nanoseconds</param>
-        /// <returns>Maxwell ticks</returns>
-        private static ulong ConvertNanosecondsToTicks(ulong nanoseconds)
-        {
-            // We need to divide first to avoid overflows.
-            // We fix up the result later by calculating the difference and adding
-            // that to the result.
-            ulong divided = nanoseconds / NsToTicksFractionDenominator;
-
-            ulong rounded = divided * NsToTicksFractionDenominator;
-
-            ulong errorBias = (nanoseconds - rounded) * NsToTicksFractionNumerator / NsToTicksFractionDenominator;
-
-            return divided * NsToTicksFractionNumerator + errorBias;
-        }
     }
 }
diff --git a/Ryujinx.Graphics.Gpu/GpuContext.cs b/Ryujinx.Graphics.Gpu/GpuContext.cs
index ddc95b2c0e..8ea7c91fbb 100644
--- a/Ryujinx.Graphics.Gpu/GpuContext.cs
+++ b/Ryujinx.Graphics.Gpu/GpuContext.cs
@@ -1,3 +1,4 @@
+using Ryujinx.Common;
 using Ryujinx.Graphics.GAL;
 using Ryujinx.Graphics.Gpu.Engine.GPFifo;
 using Ryujinx.Graphics.Gpu.Memory;
@@ -15,6 +16,9 @@ namespace Ryujinx.Graphics.Gpu
     /// </summary>
     public sealed class GpuContext : IDisposable
     {
+        private const int NsToTicksFractionNumerator = 384;
+        private const int NsToTicksFractionDenominator = 625;
+
         /// <summary>
         /// Event signaled when the host emulation context is ready to be used by the gpu context.
         /// </summary>
@@ -180,6 +184,46 @@ namespace Ryujinx.Graphics.Gpu
             }
         }
 
+        /// <summary>
+        /// Converts a nanoseconds timestamp value to Maxwell time ticks.
+        /// </summary>
+        /// <remarks>
+        /// The frequency is 614400000 Hz.
+        /// </remarks>
+        /// <param name="nanoseconds">Timestamp in nanoseconds</param>
+        /// <returns>Maxwell ticks</returns>
+        private static ulong ConvertNanosecondsToTicks(ulong nanoseconds)
+        {
+            // We need to divide first to avoid overflows.
+            // We fix up the result later by calculating the difference and adding
+            // that to the result.
+            ulong divided = nanoseconds / NsToTicksFractionDenominator;
+
+            ulong rounded = divided * NsToTicksFractionDenominator;
+
+            ulong errorBias = (nanoseconds - rounded) * NsToTicksFractionNumerator / NsToTicksFractionDenominator;
+
+            return divided * NsToTicksFractionNumerator + errorBias;
+        }
+
+        /// <summary>
+        /// Gets the value of the GPU timer.
+        /// </summary>
+        /// <returns>The current GPU timestamp</returns>
+        public ulong GetTimestamp()
+        {
+            ulong ticks = ConvertNanosecondsToTicks((ulong)PerformanceCounter.ElapsedNanoseconds);
+
+            if (GraphicsConfig.FastGpuTime)
+            {
+                // Divide by some amount to report time as if operations were performed faster than they really are.
+                // This can prevent some games from switching to a lower resolution because rendering is too slow.
+                ticks /= 256;
+            }
+
+            return ticks;
+        }
+
         /// <summary>
         /// Shader cache state update handler.
         /// </summary>