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

DX11调用OpenSharedResource实现窗口捕获时GPU内存泄漏排查求助

DX11调用OpenSharedResource实现窗口捕获时GPU内存泄漏排查求助

我现在碰到个棘手的问题:用DX11通过OpenSharedResource做窗口捕获的时候,GPU显存一直在泄漏——我用System Informer监测"Gpu Dedicated bytes",发现每执行一次循环,显存占用就会涨一点。

我一开始怀疑是没调用CloseHandle(hDxSurface)释放共享句柄,但加上这个调用后直接抛出异常,现在完全摸不着头脑,不知道还有哪里可能导致泄漏,求各位帮忙排查下!

#include "stdafx.h"
#include <Windows.h>
#include <chrono>
#include <thread>
#include <atomic>
#include <memory>
#include <d3d11.h>
#include <dxgi1_2.h>

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")

typedef HRESULT(WINAPI* PFN_DwmDxGetWindowSharedSurface)(HWND, HANDLE*, LUID*, ULONG*, ULONG*, ULONGLONG*);
PFN_DwmDxGetWindowSharedSurface DwmGetDxSharedSurface = nullptr;

bool getDwmGetDxSharedSurface() {
    HMODULE hUser32 = LoadLibraryA("user32.dll");
    if (hUser32 != NULL)
        DwmGetDxSharedSurface = (PFN_DwmDxGetWindowSharedSurface)GetProcAddress(hUser32, "DwmGetDxSharedSurface");
    return DwmGetDxSharedSurface != nullptr;
}

class WindowCapture {
public:
    // DirectX resources (cached and reused)
    IDXGIFactory1* m_pFactory = nullptr;
    IDXGIAdapter* m_pAdapter = nullptr;
    ID3D11DeviceContext* m_pContext = nullptr;
    ID3D11Device* m_pDevice = nullptr;

    // Target window
    HWND m_hwnd = nullptr;

    // **PERFORMANCE OPTIMIZATION**: Double-buffered staging textures
    ID3D11Texture2D* m_pStagingTexture[2] = {nullptr, nullptr};
    int m_currentStagingIndex = 0;
    UINT m_lastWidth = 0;
    UINT m_lastHeight = 0;
    DXGI_FORMAT m_lastFormat = DXGI_FORMAT_UNKNOWN;

    // DIB Section for direct pixel access (cached)
    HBITMAP m_hDIBSection = nullptr;
    void* m_pDIBBits = nullptr;
    UINT m_dibWidth = 0;
    UINT m_dibHeight = 0;

    WindowCapture() {};

    bool initialize(HWND hwnd);
    bool captureToPixelBuffer(void** ppPixels, UINT* pWidth, UINT* pHeight, UINT* pPitch);
    bool captureToFile(const wchar_t* filename);
    bool initializeDirectX();
    bool createOrUpdateStagingTextures(UINT width, UINT height, DXGI_FORMAT format);
    bool createOrUpdateDIBSection(UINT width, UINT height);
    bool copyTextureDataToDIB(const D3D11_MAPPED_SUBRESOURCE& mapped, UINT width, UINT height);
};

bool WindowCapture::initialize(HWND hwnd) {
    if (!hwnd || !IsWindow(hwnd))
        return false;

    m_hwnd = hwnd;

    if (!getDwmGetDxSharedSurface()) {
        $err, "Failed to get DwmGetDxSharedSurface function";
        return false;
    }

    HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
    if (FAILED(hr) && hr != RPC_E_CHANGED_MODE) {
        $err, "Failed to initialize COM", hr;
        return false;
    }

    if (!initializeDirectX())
        return false;

    return true;
}

bool WindowCapture::initializeDirectX() {
    HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&m_pFactory));
    if (FAILED(hr) || !m_pFactory) {
        $err, "CreateDXGIFactory1 failed", hr;
        return false;
    }

    m_pFactory->EnumAdapters(0, &m_pAdapter);
    if (!m_pAdapter) {
        $err, "Failed to enumerate adapters";
        m_pFactory->Release();
        return false;
    }

    const D3D_FEATURE_LEVEL featureLevels[] = {
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_9_3,
        D3D_FEATURE_LEVEL_9_2,
        D3D_FEATURE_LEVEL_9_1
    };

    hr = D3D11CreateDevice(m_pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_BGRA_SUPPORT,
        featureLevels, 6, D3D11_SDK_VERSION, &m_pDevice, NULL, &m_pContext);
    if (FAILED(hr) || !m_pDevice) {
        $err, "D3D11CreateDevice failed", hr;
        m_pFactory->Release();
        return false;
    }

    return true;
}

bool WindowCapture::createOrUpdateStagingTextures(UINT width, UINT height, DXGI_FORMAT format) {
    // Reuse existing staging textures if dimensions and format match
    if (m_pStagingTexture[0] && m_lastWidth == width && m_lastHeight == height && m_lastFormat == format)
        return true;

    // Release old staging textures
    for (int i = 0; i < 2; ++i) {
        if (m_pStagingTexture[i]) {
            m_pStagingTexture[i]->Release();
            m_pStagingTexture[i] = nullptr;
        }
    }

    // Create new staging textures (double-buffered)
    D3D11_TEXTURE2D_DESC stagingDesc = {};
    stagingDesc.Width = width;
    stagingDesc.Height = height;
    stagingDesc.MipLevels = 1;
    stagingDesc.ArraySize = 1;
    stagingDesc.Format = format;
    stagingDesc.SampleDesc.Count = 1;
    stagingDesc.SampleDesc.Quality = 0;
    stagingDesc.Usage = D3D11_USAGE_STAGING;
    stagingDesc.BindFlags = 0;
    stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    stagingDesc.MiscFlags = 0;

    for (int i = 0; i < 2; ++i) {
        HRESULT hr = m_pDevice->CreateTexture2D(&stagingDesc, nullptr, &m_pStagingTexture[i]);
        if (FAILED(hr)) {
            $err, "Failed to create staging texture %1", i, hr;
            for (int j = 0; j < i; ++j) {
                if (m_pStagingTexture[j]) {
                    m_pStagingTexture[j]->Release();
                    m_pStagingTexture[j] = nullptr;
                }
            }
            return false;
        }
    }

    // Cache dimensions
    m_lastWidth = width;
    m_lastHeight = height;
    m_lastFormat = format;
    m_currentStagingIndex = 0;

    return true;
}

bool WindowCapture::createOrUpdateDIBSection(UINT width, UINT height) {
    // Reuse existing DIB

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 06:53:11