예제 #1
0
        /// <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);
                }
            }
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        /// <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);
            }
        }