Exemplo n.º 1
0
        private void RemoveRange(ulong gpuVa, ulong size)
        {
            int index = BinarySearch(gpuVa + size - 1);

            if (index < 0)
            {
                index = ~index;
            }

            if (index >= _items.Count || !InRange(gpuVa, size, _items[index].Address))
            {
                return;
            }

            int count = 1;

            while (index > 0 && InRange(gpuVa, size, _items[index - 1].Address))
            {
                index--;
                count++;
            }

            // Notify the removed counter events that their result should no longer be written out.
            for (int i = 0; i < count; i++)
            {
                ICounterEvent evt = _items[index + i].Event;
                if (evt != null)
                {
                    evt.Invalid = true;
                }
            }

            _items.RemoveRange(index, count);
        }
Exemplo n.º 2
0
        public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual)
        {
            if (value is CounterQueueEvent)
            {
                // Compare an event and a constant value.
                CounterQueueEvent evt = (CounterQueueEvent)value;

                // Easy host conditional rendering when the check matches what GL can do:
                //  - Event is of type samples passed.
                //  - Result is not a combination of multiple queries.
                //  - Comparing against 0.
                //  - Event has not already been flushed.

                if (evt.Disposed)
                {
                    // If the event has been flushed, then just use the values on the CPU.
                    // The query object may already be repurposed for another draw (eg. begin + end).
                    return(false);
                }

                if (compare == 0 && evt.Type == QueryTarget.SamplesPassed && evt.ClearCounter)
                {
                    GL.BeginConditionalRender(evt.Query, isEqual ? ConditionalRenderType.QueryNoWaitInverted : ConditionalRenderType.QueryNoWait);
                    return(true);
                }
            }

            // The GPU will flush the queries to CPU and evaluate the condition there instead.

            GL.Flush(); // The thread will be stalled manually flushing the counter, so flush GL commands now.
            return(false);
        }
        /// <summary>
        /// Checks if the counter at a given GPU memory address passes a specified equality comparison.
        /// </summary>
        /// <param name="gpuVa">GPU virtual address</param>
        /// <param name="isEqual">True to check if the values are equal, false to check if they are not equal</param>
        /// <returns>True if the condition is met, false otherwise. Returns host if handling with host conditional rendering</returns>
        private ConditionalRenderEnabled CounterCompare(ulong gpuVa, bool isEqual)
        {
            ICounterEvent evt  = FindEvent(gpuVa);
            ICounterEvent evt2 = FindEvent(gpuVa + 16);

            if (evt == null && evt2 == null)
            {
                return(ConditionalRenderEnabled.False);
            }

            if (_context.Renderer.Pipeline.TryHostConditionalRendering(
                    evt ?? (object)_context.MemoryAccessor.ReadUInt64(gpuVa),
                    evt2 ?? (object)_context.MemoryAccessor.ReadUInt64(gpuVa + 16),
                    isEqual))
            {
                return(ConditionalRenderEnabled.Host);
            }
            else
            {
                evt?.Flush();
                evt2?.Flush();

                ulong x = _context.MemoryAccessor.ReadUInt64(gpuVa);
                ulong y = _context.MemoryAccessor.ReadUInt64(gpuVa + 16);

                return((isEqual ? x == y : x != y) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False);
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Writes a GPU counter to guest memory.
        /// This also writes the current timestamp value.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        /// <param name="type">Counter to be written to memory</param>
        private void ReportCounter(GpuState state, ReportCounterType type)
        {
            CounterData counterData = new CounterData();

            var rs = state.Get <SemaphoreState>(MethodOffset.ReportState);

            ulong gpuVa = rs.Address.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;
            }

            ICounterEvent counter = null;

            EventHandler <ulong> resultHandler = (object evt, ulong result) =>
            {
                counterData.Counter   = result;
                counterData.Timestamp = ticks;

                Span <CounterData> counterDataSpan = MemoryMarshal.CreateSpan(ref counterData, 1);

                Span <byte> data = MemoryMarshal.Cast <CounterData, byte>(counterDataSpan);

                if (counter?.Invalid != true)
                {
                    _context.MemoryAccessor.Write(gpuVa, data);
                }
            };

            switch (type)
            {
            case ReportCounterType.Zero:
                resultHandler(null, 0);
                break;

            case ReportCounterType.SamplesPassed:
                counter = _context.Renderer.ReportCounter(CounterType.SamplesPassed, resultHandler);
                break;

            case ReportCounterType.PrimitivesGenerated:
                counter = _context.Renderer.ReportCounter(CounterType.PrimitivesGenerated, resultHandler);
                break;

            case ReportCounterType.TransformFeedbackPrimitivesWritten:
                counter = _context.Renderer.ReportCounter(CounterType.TransformFeedbackPrimitivesWritten, resultHandler);
                break;
            }

            _counterCache.AddOrUpdate(gpuVa, counter);
        }
Exemplo n.º 5
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 = 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;
            }

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

            case ReportCounterType.PrimitivesGenerated:
                counter = _context.Renderer.ReportCounter(CounterType.PrimitivesGenerated, resultHandler);
                break;

            case ReportCounterType.TransformFeedbackPrimitivesWritten:
                counter = _context.Renderer.ReportCounter(CounterType.TransformFeedbackPrimitivesWritten, resultHandler);
                break;
            }

            _channel.MemoryManager.CounterCache.AddOrUpdate(gpuVa, counter);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Adds a new counter to the counter cache, or updates a existing one.
        /// </summary>
        /// <param name="gpuVa">GPU virtual address where the counter will be written in memory</param>
        public void AddOrUpdate(ulong gpuVa, ICounterEvent evt)
        {
            int index = BinarySearch(gpuVa);

            CounterEntry entry = new CounterEntry(gpuVa, evt);

            if (index < 0)
            {
                _items.Insert(~index, entry);
            }
            else
            {
                _items[index] = entry;
            }
        }
Exemplo n.º 7
0
        public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual)
        {
            // Compare an event and a constant value.
            if (value is CounterQueueEvent evt)
            {
                // Easy host conditional rendering when the check matches what GL can do:
                //  - Event is of type samples passed.
                //  - Result is not a combination of multiple queries.
                //  - Comparing against 0.
                //  - Event has not already been flushed.

                if (compare == 0 && evt.Type == CounterType.SamplesPassed && evt.ClearCounter)
                {
                    if (!value.ReserveForHostAccess())
                    {
                        // If the event has been flushed, then just use the values on the CPU.
                        // The query object may already be repurposed for another draw (eg. begin + end).
                        return(false);
                    }

                    if (Gd.Capabilities.SupportsConditionalRendering)
                    {
                        var buffer = evt.GetBuffer().Get(Cbs, 0, sizeof(long)).Value;
                        var flags  = isEqual ? ConditionalRenderingFlagsEXT.ConditionalRenderingInvertedBitExt : 0;

                        var conditionalRenderingBeginInfo = new ConditionalRenderingBeginInfoEXT()
                        {
                            SType  = StructureType.ConditionalRenderingBeginInfoExt,
                            Buffer = buffer,
                            Flags  = flags
                        };

                        // Gd.ConditionalRenderingApi.CmdBeginConditionalRendering(CommandBuffer, conditionalRenderingBeginInfo);
                    }

                    _activeConditionalRender = evt;
                    return(true);
                }
            }

            // The GPU will flush the queries to CPU and evaluate the condition there instead.

            FlushPendingQuery(); // The thread will be stalled manually flushing the counter, so flush commands now.
            return(false);
        }
        /// <summary>
        /// Checks if the counter value at a given GPU memory address is non-zero.
        /// </summary>
        /// <param name="gpuVa">GPU virtual address of the counter value</param>
        /// <returns>True if the value is not zero, false otherwise. Returns host if handling with host conditional rendering</returns>
        private ConditionalRenderEnabled CounterNonZero(ulong gpuVa)
        {
            ICounterEvent evt = _counterCache.FindEvent(gpuVa);

            if (evt == null)
            {
                return(ConditionalRenderEnabled.False);
            }

            if (_context.Renderer.Pipeline.TryHostConditionalRendering(evt, 0L, false))
            {
                return(ConditionalRenderEnabled.Host);
            }
            else
            {
                evt.Flush();
                return((_context.MemoryAccessor.ReadUInt64(gpuVa) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False);
            }
        }
Exemplo n.º 9
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);
        }
Exemplo n.º 10
0
        /// <summary>
        /// Checks if the counter value at a given GPU memory address is non-zero.
        /// </summary>
        /// <param name="context">GPU context</param>
        /// <param name="memoryManager">Memory manager bound to the channel currently executing</param>
        /// <param name="gpuVa">GPU virtual address of the counter value</param>
        /// <returns>True if the value is not zero, false otherwise. Returns host if handling with host conditional rendering</returns>
        private static ConditionalRenderEnabled CounterNonZero(GpuContext context, MemoryManager memoryManager, ulong gpuVa)
        {
            ICounterEvent evt = memoryManager.CounterCache.FindEvent(gpuVa);

            if (evt == null)
            {
                return(ConditionalRenderEnabled.False);
            }

            if (context.Renderer.Pipeline.TryHostConditionalRendering(evt, 0L, false))
            {
                return(ConditionalRenderEnabled.Host);
            }
            else
            {
                evt.Flush();
                return((memoryManager.Read <ulong>(gpuVa) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False);
            }
        }
Exemplo n.º 11
0
        /// <summary>
        /// Checks if the counter at a given GPU memory address passes a specified equality comparison.
        /// </summary>
        /// <param name="gpuVa">GPU virtual address</param>
        /// <param name="isEqual">True to check if the values are equal, false to check if they are not equal</param>
        /// <returns>True if the condition is met, false otherwise. Returns host if handling with host conditional rendering</returns>
        private ConditionalRenderEnabled CounterCompare(ulong gpuVa, bool isEqual)
        {
            ICounterEvent evt  = FindEvent(gpuVa);
            ICounterEvent evt2 = FindEvent(gpuVa + 16);

            if (evt == null && evt2 == null)
            {
                return(ConditionalRenderEnabled.False);
            }

            bool useHost;

            if (evt != null && evt2 == null)
            {
                useHost = _context.Renderer.Pipeline.TryHostConditionalRendering(evt, _context.MemoryManager.Read <ulong>(gpuVa + 16), isEqual);
            }
            else if (evt == null && evt2 != null)
            {
                useHost = _context.Renderer.Pipeline.TryHostConditionalRendering(evt2, _context.MemoryManager.Read <ulong>(gpuVa), isEqual);
            }
            else
            {
                useHost = _context.Renderer.Pipeline.TryHostConditionalRendering(evt, evt2, isEqual);
            }

            if (useHost)
            {
                return(ConditionalRenderEnabled.Host);
            }
            else
            {
                evt?.Flush();
                evt2?.Flush();

                ulong x = _context.MemoryManager.Read <ulong>(gpuVa);
                ulong y = _context.MemoryManager.Read <ulong>(gpuVa + 16);

                return((isEqual ? x == y : x != y) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False);
            }
        }
Exemplo n.º 12
0
        /// <summary>
        /// Checks if the counter at a given GPU memory address passes a specified equality comparison.
        /// </summary>
        /// <param name="context">GPU context</param>
        /// <param name="memoryManager">Memory manager bound to the channel currently executing</param>
        /// <param name="gpuVa">GPU virtual address</param>
        /// <param name="isEqual">True to check if the values are equal, false to check if they are not equal</param>
        /// <returns>True if the condition is met, false otherwise. Returns host if handling with host conditional rendering</returns>
        private static ConditionalRenderEnabled CounterCompare(GpuContext context, MemoryManager memoryManager, ulong gpuVa, bool isEqual)
        {
            ICounterEvent evt  = FindEvent(memoryManager.CounterCache, gpuVa);
            ICounterEvent evt2 = FindEvent(memoryManager.CounterCache, gpuVa + 16);

            bool useHost;

            if (evt != null && evt2 == null)
            {
                useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt, memoryManager.Read <ulong>(gpuVa + 16), isEqual);
            }
            else if (evt == null && evt2 != null)
            {
                useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt2, memoryManager.Read <ulong>(gpuVa), isEqual);
            }
            else if (evt != null && evt2 != null)
            {
                useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt, evt2, isEqual);
            }
            else
            {
                useHost = false;
            }

            if (useHost)
            {
                return(ConditionalRenderEnabled.Host);
            }
            else
            {
                evt?.Flush();
                evt2?.Flush();

                ulong x = memoryManager.Read <ulong>(gpuVa);
                ulong y = memoryManager.Read <ulong>(gpuVa + 16);

                return((isEqual ? x == y : x != y) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False);
            }
        }
Exemplo n.º 13
0
        public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual)
        {
            var evt = value as ThreadedCounterEvent;

            if (evt != null)
            {
                if (compare == 0 && evt.Type == CounterType.SamplesPassed && evt.ClearCounter)
                {
                    if (!evt.ReserveForHostAccess())
                    {
                        return(false);
                    }

                    _renderer.New <TryHostConditionalRenderingCommand>().Set(Ref(evt), compare, isEqual);
                    _renderer.QueueCommand();
                    return(true);
                }
            }

            _renderer.New <TryHostConditionalRenderingFlushCommand>().Set(Ref(evt), Ref <ThreadedCounterEvent>(null), isEqual);
            _renderer.QueueCommand();
            return(false);
        }
Exemplo n.º 14
0
 public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual)
 {
     _renderer.New <TryHostConditionalRenderingFlushCommand>().Set(Ref(value as ThreadedCounterEvent), Ref(compare as ThreadedCounterEvent), isEqual);
     _renderer.QueueCommand();
     return(false);
 }
Exemplo n.º 15
0
 public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual)
 {
     GL.Flush();    // The GPU thread will be stalled manually flushing the counter, so flush GL commands now.
     return(false); // We don't currently have a way to compare two counters for conditional rendering.
 }
Exemplo n.º 16
0
 public CounterEntry(ulong address, ICounterEvent evt)
 {
     Address = address;
     Event   = evt;
 }
Exemplo n.º 17
0
 public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual)
 {
     FlushPendingQuery(); // The thread will be stalled manually flushing the counter, so flush commands now.
     return(false);
 }
Exemplo n.º 18
0
 public void Create(IRenderer renderer, CounterType type, System.EventHandler <ulong> eventHandler, bool hostReserved)
 {
     ThreadedHelpers.SpinUntilExchange(ref _createLock, 1, 0);
     Base = renderer.ReportCounter(type, eventHandler, hostReserved || _reserved);
     Volatile.Write(ref _createLock, 0);
 }
Exemplo n.º 19
0
 public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual)
 {
     return(false); // We don't currently have a way to compare two counters for conditional rendering.
 }