/// <summary> /// Releases a semaphore for a given LaunchDma method call. /// </summary> /// <param name="argument">The LaunchDma call argument</param> private void ReleaseSemaphore(int argument) { LaunchDmaSemaphoreType type = (LaunchDmaSemaphoreType)((argument >> 3) & 0x3); if (type != LaunchDmaSemaphoreType.None) { ulong address = ((ulong)_state.State.SetSemaphoreA << 32) | _state.State.SetSemaphoreB; if (type == LaunchDmaSemaphoreType.ReleaseOneWordSemaphore) { _channel.MemoryManager.Write(address, _state.State.SetSemaphorePayload); } else /* if (type == LaunchDmaSemaphoreType.ReleaseFourWordSemaphore) */ { _channel.MemoryManager.Write(address + 8, _context.GetTimestamp()); _channel.MemoryManager.Write(address, (ulong)_state.State.SetSemaphorePayload); } } }
/// <summary> /// Writes a GPU counter to guest memory. /// This also writes the current timestamp value. /// </summary> /// <param name="type">Counter to be written to memory</param> private void ReportCounter(ReportCounterType type) { ulong gpuVa = _state.State.SemaphoreAddress.Pack(); ulong ticks = _context.GetTimestamp(); ICounterEvent counter = null; void resultHandler(object evt, ulong result) { CounterData counterData = new CounterData { Counter = result, Timestamp = ticks }; if (counter?.Invalid != true) { _channel.MemoryManager.Write(gpuVa, counterData); } } switch (type) { case ReportCounterType.Zero: resultHandler(null, 0); break; case ReportCounterType.SamplesPassed: counter = _context.Renderer.ReportCounter(CounterType.SamplesPassed, resultHandler, false); break; case ReportCounterType.PrimitivesGenerated: counter = _context.Renderer.ReportCounter(CounterType.PrimitivesGenerated, resultHandler, false); break; case ReportCounterType.TransformFeedbackPrimitivesWritten: counter = _context.Renderer.ReportCounter(CounterType.TransformFeedbackPrimitivesWritten, resultHandler, false); break; } _channel.MemoryManager.CounterCache.AddOrUpdate(gpuVa, counter); }
/// <summary> /// Writes a GPU counter to guest memory. /// </summary> /// <param name="argument">Method call argument</param> public void Semaphored(int argument) { ulong address = ((ulong)_state.State.SemaphorebOffsetLower << 2) | ((ulong)_state.State.SemaphoreaOffsetUpper << 32); int value = _state.State.SemaphorecPayload; 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) { _parent.MemoryManager.Write(address, value); } else if (operation == SemaphoredOperation.Reduction) { bool signed = _state.State.SemaphoredFormat == SemaphoredFormat.Signed; int mem = _parent.MemoryManager.Read <int>(address); switch (_state.State.SemaphoredReduction) { case SemaphoredReduction.Min: value = signed ? Math.Min(mem, value) : (int)Math.Min((uint)mem, (uint)value); break; case SemaphoredReduction.Max: value = signed ? Math.Max(mem, value) : (int)Math.Max((uint)mem, (uint)value); break; case SemaphoredReduction.Xor: value ^= mem; break; case SemaphoredReduction.And: value &= mem; break; case SemaphoredReduction.Or: value |= mem; break; case SemaphoredReduction.Add: value += mem; break; case SemaphoredReduction.Inc: value = (uint)mem < (uint)value ? mem + 1 : 0; break; case SemaphoredReduction.Dec: value = (uint)mem > 0 && (uint)mem <= (uint)value ? mem - 1 : value; break; } _parent.MemoryManager.Write(address, value); } }