CapFrameX OSD with RTSS

Discussion in 'Rivatuner Statistics Server (RTSS) Forum' started by ZeroStrat, Nov 4, 2019.

  1. ZeroStrat

    ZeroStrat Member

    Messages:
    40
    Likes Received:
    17
    GPU:
    RTX 2080 Ti
    As I wrote APPFLAG_API_USAGE_MASK 0x0000FFFF = 65535, but still a difference of 1 when checking dwFflags - 65535 != 10 (Vulkan). One bit is missing.

    Or I do not understand the concept of bit masking... ^^

    Edit: This code works. I was a little bit confused using bit masks. I basically never use it in practice.

    Code:
    if ((curAppInfos.dwFlags & APPFLAG_D3D11) == APPFLAG_D3D11)
    {
        api = "D3D11";
    }
    
     
    Last edited: May 6, 2020
  2. Unwinder

    Unwinder Moderator Staff Member

    Messages:
    14,877
    Likes Received:
    2,024
    You don't need to subtract APPFLAG_API_USAGE_MASK. You need to apply bitwise AND operation to mask unnecessary bits.

    dwAPI = dwFlags & APPFLAG_API_USAGE_MASK.
     
  3. Unwinder

    Unwinder Moderator Staff Member

    Messages:
    14,877
    Likes Received:
    2,024
    Code:
    if ((curAppInfos.dwFlags & APPFLAG_D3D11) == APPFLAG_D3D11)
    {
        api = "D3D11";
    }
    
    This code is incorrect and it will work for SOME cases only, where API ID takes exactly one bit. Correct one is:

    Code:
    if ((curAppInfos.dwFlags & APPFLAG_API_USAGE_MASK) == APPFLAG_D3D11)
    {
        api = "D3D11";
    }
    
     
    ZeroStrat likes this.
  4. ZeroStrat

    ZeroStrat Member

    Messages:
    40
    Likes Received:
    17
    GPU:
    RTX 2080 Ti
    Ok, I'm gonna change it and check some different games now. Thanks for your help!
     
    Unwinder likes this.

  5. Unwinder

    Unwinder Moderator Staff Member

    Messages:
    14,877
    Likes Received:
    2,024
    No problem, glad that you've figured it out.
     
  6. ZeroStrat

    ZeroStrat Member

    Messages:
    40
    Likes Received:
    17
    GPU:
    RTX 2080 Ti
    One another question. What is D3D12AFR? Does AFR stand for "alternate frame rendering"? Is this multi-GPU stuff?
     
  7. Unwinder

    Unwinder Moderator Staff Member

    Messages:
    14,877
    Likes Received:
    2,024
    It is explicit D3D12 multi GPU mode, each frame is rendered by different GPU.
     
    ZeroStrat likes this.
  8. ZeroStrat

    ZeroStrat Member

    Messages:
    40
    Likes Received:
    17
    GPU:
    RTX 2080 Ti
    @Unwinder

    Is there a flag/property in RTSS_SHARED_MEMORY_APP_ENTRY which holds the information about the window mode (window, borderless window, full screen optimization und full screen exclusive) of the app?
     
  9. Unwinder

    Unwinder Moderator Staff Member

    Messages:
    14,877
    Likes Received:
    2,024
    Nope.
     
    ZeroStrat likes this.
  10. ZeroStrat

    ZeroStrat Member

    Messages:
    40
    Likes Received:
    17
    GPU:
    RTX 2080 Ti
    @Unwinder

    Is it possible to give a CGroupedString the information about limits and corresponding colors?

    For example: FPS < 30 -> color = red

    If this has to be defined from the outside, so to speak, how do you get the current value of the frame rates and frame times to be able to compare them to my custom limits?

    void CGroupedString::Add(LPCSTR lpValue, LPCSTR lpGroup, LPCSTR lpSeparator, LPCSTR lpGroupDataSeparator)

    The function interface does not provide such parameters.
     

  11. Unwinder

    Unwinder Moderator Staff Member

    Messages:
    14,877
    Likes Received:
    2,024
    Color tags are added from the outside as you call it. Colorizing framerate tag can be tricky because there can be multiple applications running simultaneously, each one with its own framerate. Each 3D applications's framerate (averaged with sliding window configured in RTSS) in 0.1FPS units or raw ring frametime buffers are stored in each 3D application's slot in shared memory.
     
    ZeroStrat likes this.
  12. Taxxor

    Taxxor New Member

    Messages:
    9
    Likes Received:
    1
    GPU:
    RX5700XT Nitro+
    Hmm, I tried this with AB a few days ago where I started two separate applications in window mode and made a custom profile for one of them where I limited it's framerate to 1 FPS and the other running at its internally locket 75fps.

    The RTSS Overlay showed 1 fps in both windows while the first applications window was selected, and 75fps for both while the second applications window was selected.


    So in my case the overlay always displayed the framerate for the currently active application in all applications. If that's the correct behaviour there should be no problem with colorizing the value, assuming the user isn't playing two games at the same time^^
     
  13. Unwinder

    Unwinder Moderator Staff Member

    Messages:
    14,877
    Likes Received:
    2,024
    Define "RTSS Overlay". It is hypertext renderer, it displays what you're asking it to display. If it is own framerate counter or MSI Afterburner's framerate counter displayed with special <FR> hypertextg tag - it will display application specific framerate. If you're manually and explicitly formatting framerate text from you application - you'll see the same value in all running applications of course.
     
    Taxxor likes this.
  14. Taxxor

    Taxxor New Member

    Messages:
    9
    Likes Received:
    1
    GPU:
    RX5700XT Nitro+
    I started AB and RTSS and set a limit color to the framerate in AB to test if the color would apply to both fps values when I have more than one application showing the overlay.

    Then I used RTSS to limit the framerate of one of them to get out of the specified range and the value of the other application fell with it.

    But I see, the color information was the problem here, because when I also display the frametimes that I have not set a limit for, these values keep being different for both windows.
     
  15. Unwinder

    Unwinder Moderator Staff Member

    Messages:
    14,877
    Likes Received:
    2,024
    Defining alarm threshold for process specific performance counters like framerate or frametime in MSI AB is a sepcial case and it was discussed and documented in development thread. In this case MSI AB forcibly disables per processs framerate/frametime stas display and uses hardware monitoring module's framerate and frametime graphs (which are system global and collect stats for foreground 3D process) as a data source.
     

  16. ZeroStrat

    ZeroStrat Member

    Messages:
    40
    Likes Received:
    17
    GPU:
    RTX 2080 Ti
    @Unwinder

    I implemented a funcion to get the current frame time and frame rate data from a special application identified by the process ID.

    Code:
    std::vector<float> RTSSCoreControl::GetCurrentFramerate(DWORD processId)
    {
        std::vector<float> result;
        float currentFramerate = 0;
        float currentFrametime = 0;
        HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "RTSSSharedMemoryV2");
    
        if (hMapFile)
        {
            LPVOID pMapAddr = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
            LPRTSS_SHARED_MEMORY pMem = (LPRTSS_SHARED_MEMORY)pMapAddr;
    
            if (pMem)
            {
                if ((pMem->dwSignature == 'RTSS') &&
                    (pMem->dwVersion >= 0x00020000))
                {
                    RTSS_SHARED_MEMORY::RTSS_SHARED_MEMORY_APP_ENTRY* arrAppInfos = pMem->arrApp;
    
                    for (size_t i = 0; i < 256; i++)
                    {
                        RTSS_SHARED_MEMORY::RTSS_SHARED_MEMORY_APP_ENTRY curAppInfos = arrAppInfos[i];
    
                        if (curAppInfos.dwProcessID == processId)
                        {
                            currentFrametime = curAppInfos.dwStatFrameTimeBuf[curAppInfos.dwStatFrameTimeBufPos] / 1000.0f;
                            currentFramerate = curAppInfos.dwStatFrameTimeBufFramerate / 10.0f;
                                /*1000.0f * curAppInfos.dwFrames / (curAppInfos.dwTime1 - curAppInfos.dwTime0);*/
                            break;
                        }
                    }
    
                    UnmapViewOfFile(pMapAddr);
                }
    
                CloseHandle(hMapFile);
            }
        }
    
        result.push_back(currentFramerate);
        result.push_back(currentFrametime);
        return result;
    }
    The numbers seems to be consistent in comparison to the afterburner, but we observe a slight time offset.

    Can this be prevented? Is it possible to get the frame rates and frame times without the need of a process ID? Applications, which is in the foreground or something similar...

    Is it possible to filter the array without for-loop?
     
    Last edited: Jul 11, 2020
  17. Unwinder

    Unwinder Moderator Staff Member

    Messages:
    14,877
    Likes Received:
    2,024
    Offset is a result of accessing ring frametime buffer by dwStatFrameTimeBufPos. It points to the first _free_ position inside the buffer so you're actually taking a time of the frame rendered 1024 frames before. Calculate last position as (dwStatFrameTimeBufPos - 1) & 1023 to get last instantaneous frametime.

    You may get foreground process ID using GetForegroundWindow() then GetWindowThreadProcessId(). Also I'll add the last foreground application slot index and process ID fields to shared memory for this specific task in the next beta, so it will be possible to use it directly instead of manually detecting foreground process ID and searching for it.
     
    Last edited: Jul 11, 2020
    ZeroStrat likes this.
  18. ZeroStrat

    ZeroStrat Member

    Messages:
    40
    Likes Received:
    17
    GPU:
    RTX 2080 Ti
    Thanks as always, Alex! It works fine so far.

    Greetz, Mark
     
    Unwinder likes this.
  19. Unwinder

    Unwinder Moderator Staff Member

    Messages:
    14,877
    Likes Received:
    2,024
    @ZeroStrat @Taxxor

    Can you correct "x% low" section of your blog post related to performance metrics?

    https://www.capframex.com/blog/post/Explanation of different performance metrics

    It doesn't reflect the real math used by MSI AB to calculate 1%/0.1% lows, but I keep getting questions of averaging the slowest frames in MSI AB. I don't know your source of averaging idea, most likely you took it from GN video where they try to explain the way they manually calculated 1%/0.1% lows in their reviews in the past.
    MSI AB doesn't follow their approach and uses different math, 1%/0.1% lows are also always based on frametime of single frame located on boundary of 1% of slowest frames. However, it defines "1% of slowest frames" slightly different comparing to simple 99th percentile usage.
    Instead of linear calculation of 1% as a 1% of total frames count, it uses slightly more complex but way more informative integral calculation approach. It defines 1% of slowest frames as the set of slowest frames taking 1% of total benchmark time.
     
    ZeroStrat likes this.
  20. ZeroStrat

    ZeroStrat Member

    Messages:
    40
    Likes Received:
    17
    GPU:
    RTX 2080 Ti
    Yes, we will correct this.
     

Share This Page