You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于DirectX 11实现高效GetPixel,替代GDI+慢像素获取函数

DirectX 11 GetPixel Implementation for Fast Color Sampling

Why This Beats GDI+

  • GDI+ relies on cross-context surface access which introduces heavy overhead for repeated sampling. DX11 uses staging textures that directly map to GPU memory, cutting down on latency drastically.
  • Since you’re already hooking IDXGISwapChain::Present, you can reuse existing DX11 device/swap chain resources instead of spinning up new ones, eliminating redundant initialization costs.

Prerequisites

You’ll need access to these resources from your Present hook:

  • ID3D11Device* pDevice
  • ID3D11DeviceContext* pContext
  • Swap chain back buffer dimensions and format

Core Implementation

1. Initialize Staging Texture (Run Once)

Create a staging texture matching the back buffer’s specs. Do this once after hook initialization, not per frame.

ID3D11Texture2D* pStagingTexture = nullptr;
D3D11_TEXTURE2D_DESC g_StagingDesc = {};

void InitDX11StagingTexture(ID3D11Device* pDevice, UINT width, UINT height, DXGI_FORMAT format)
{
    if (pStagingTexture) pStagingTexture->Release();

    ZeroMemory(&g_StagingDesc, sizeof(g_StagingDesc));
    g_StagingDesc.Width = width;
    g_StagingDesc.Height = height;
    g_StagingDesc.MipLevels = 1;
    g_StagingDesc.ArraySize = 1;
    g_StagingDesc.Format = format;
    g_StagingDesc.SampleDesc.Count = 1;
    g_StagingDesc.Usage = D3D11_USAGE_STAGING;
    g_StagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;

    pDevice->CreateTexture2D(&g_StagingDesc, nullptr, &pStagingTexture);
}

2. Capture Back Buffer (Per Frame)

Copy the current back buffer to the staging texture once per frame—do this before any pixel sampling to avoid redundant GPU copies.

void CaptureBackBuffer(IDXGISwapChain* pSwapChain, ID3D11DeviceContext* pContext)
{
    ID3D11Texture2D* pBackBuffer = nullptr;
    pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBackBuffer);
    pContext->CopyResource(pStagingTexture, pBackBuffer);
    pBackBuffer->Release();
}

3. Single Pixel Color Retrieval

Fixes coordinate issues by accounting for GPU memory row stride (critical for correct pixel indexing):

bool GetPixelColorDX11(UINT x, UINT y, UINT& outColor)
{
    if (!pStagingTexture || x >= g_StagingDesc.Width || y >= g_StagingDesc.Height)
        return false;

    D3D11_MAPPED_SUBRESOURCE mappedRes;
    HRESULT hr = pContext->Map(pStagingTexture, 0, D3D11_MAP_READ, 0, &mappedRes);
    if (FAILED(hr)) return false;

    // Calculate pixel position (adjust data type if using non-RGBA8 formats)
    UINT* pPixels = (UINT*)mappedRes.pData;
    UINT rowStride = mappedRes.RowPitch / sizeof(UINT);
    outColor = pPixels[y * rowStride + x];

    pContext->Unmap(pStagingTexture, 0);
    return true;
}

4. Multiple Pixels Retrieval (Most Efficient)

Process all required coordinates in one map/unmap pass to minimize CPU-GPU sync overhead:

bool GetMultiplePixelsDX11(const std::vector<std::pair<UINT, UINT>>& coords, std::vector<UINT>& outColors)
{
    if (!pStagingTexture || coords.empty()) return false;
    outColors.resize(coords.size());

    D3D11_MAPPED_SUBRESOURCE mappedRes;
    HRESULT hr = pContext->Map(pStagingTexture, 0, D3D11_MAP_READ, 0, &mappedRes);
    if (FAILED(hr)) return false;

    UINT* pPixels = (UINT*)mappedRes.pData;
    UINT rowStride = mappedRes.RowPitch / sizeof(UINT);

    for (size_t i = 0; i < coords.size(); ++i)
    {
        UINT x = coords[i].first;
        UINT y = coords[i].second;
        if (x >= g_StagingDesc.Width || y >= g_StagingDesc.Height)
        {
            outColors[i] = 0; // Handle invalid coordinates as needed
            continue;
        }
        outColors[i] = pPixels[y * rowStride + x];
    }

    pContext->Unmap(pStagingTexture, 0);
    return true;
}

Usage Guidelines

  1. First Hook Call: Retrieve the swap chain’s back buffer dimensions and format, then run InitDX11StagingTexture.
  2. Per Frame: Call CaptureBackBuffer once before sampling any pixels.
  3. Sample Efficiently: Use GetMultiplePixelsDX11 for your 1-11 coordinates instead of calling the single-pixel function repeatedly—this cuts down on map/unmap overhead.
  4. Cleanup: Release pStagingTexture when your hook is unloaded to avoid memory leaks.

This implementation will eliminate the FPS drops from your GDI+ calls, as it avoids slow cross-context surface access and leverages DX11’s optimized memory handling.

内容的提问来源于stack exchange,提问作者marcoluca987

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 03:05:27