Как я могу найти утечку памяти в моей программе UWP DIrectX 11 C ++? - PullRequest
0 голосов
/ 22 июня 2019

Visual Studio, в режиме отладки, показывает мне, что моя игра, которую я программирую, занимает все больше памяти, когда я меняю размер Windows.Все хорошо, пока я не изменяю размер экрана.Я обнаружил, что я теряю от 5 до 10 Кбайт за изменение размера окна.

Я проверил свой код несколько раз и не смог найти, где теряю память.Это может быть только в функции DX :: DeviceResources :: CreateWindowSizeDependentResources ().Вот эта функция:

    void DX::DeviceResources::CreateWindowSizeDependentResources() 
    {
        // Effacer le précédent contexte spécifique à la taille de la fenêtre.
        ID3D11RenderTargetView* nullViews[] = {nullptr};
        m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
        m_finalScreenRenderTargetView = nullptr;
        m_d2dContext->SetTarget(nullptr);
        m_d2dTargetBitmapSwapChain = nullptr;
    //  m_d3dDepthStencilView = nullptr;
        m_d3dContext->Flush1(D3D11_CONTEXT_TYPE_ALL, nullptr);
        m_screen1920X1080_RenderTargetView = nullptr;
        m_screen1920X1080_ResourceView = nullptr;
        m_d2dTargetBitmap1920Screen = nullptr;

        UpdateRenderTargetSize();

        if (m_need_intermediate_1920X1080_screen)
        {
            // Create screen 1920 X 1080
            D3D11_TEXTURE2D_DESC desc;
            desc.Width = 1920;
            desc.Height = 1080;
            desc.MipLevels = 1;
            desc.ArraySize = 1;
            desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
            desc.SampleDesc.Count = 1;
            desc.SampleDesc.Quality = 0;
            desc.Usage = D3D11_USAGE_DEFAULT;
            desc.BindFlags = D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE;
            desc.CPUAccessFlags = 0;
            desc.MiscFlags = 0;

            ComPtr<ID3D11Texture2D> pTexture;

            m_d3dDevice->CreateTexture2D(&desc, NULL, pTexture.GetAddressOf());

            DX::ThrowIfFailed(
                m_d3dDevice->CreateRenderTargetView1(
                    pTexture.Get(),
                    nullptr,
                    &m_screen1920X1080_RenderTargetView
                )
            );
            D3D11_SHADER_RESOURCE_VIEW_DESC rvDesc;
            rvDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;//desc.Format; // Use format from the texture
            rvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; // Resource is a 2D texture
            rvDesc.Texture2D.MostDetailedMip = 0;
            rvDesc.Texture2D.MipLevels = 1;
            DX::ThrowIfFailed(m_d3dDevice->CreateShaderResourceView(pTexture.Get(), &rvDesc, m_screen1920X1080_ResourceView.GetAddressOf()));

            //  Create bitmap for Direct2D target  for Screen 1920
            D2D1_BITMAP_PROPERTIES1 bitmapProperties =
                D2D1::BitmapProperties1(
                    D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
                    D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
                    m_dpi,
                    m_dpi
                );

            ComPtr<IDXGISurface2> dxgi1920Screen;
            DX::ThrowIfFailed(
                pTexture->QueryInterface<IDXGISurface2>(dxgi1920Screen.GetAddressOf())
            );

            DX::ThrowIfFailed(
                m_d2dContext->CreateBitmapFromDxgiSurface(
                    dxgi1920Screen.Get(),
                    &bitmapProperties,
                    &m_d2dTargetBitmap1920Screen
                )
            );
            pTexture = nullptr;  // release pTexture
            dxgi1920Screen = nullptr;  // release
        }

        // La largeur et la hauteur de la chaîne de permutation doivent être basées sur la
        // largeur et hauteur en orientation native. Si la fenêtre n'est pas en orientation native
        // l'orientation portrait, les dimensions doivent être inversées.
        DXGI_MODE_ROTATION displayRotation = ComputeDisplayRotation();

        bool swapDimensions = displayRotation == DXGI_MODE_ROTATION_ROTATE90 || displayRotation == DXGI_MODE_ROTATION_ROTATE270;
        m_d3dRenderTargetSize.Width = swapDimensions ? m_outputSize.Height : m_outputSize.Width;
        m_d3dRenderTargetSize.Height = swapDimensions ? m_outputSize.Width : m_outputSize.Height;

        if (m_swapChain != nullptr)
        {
            // Si la chaîne de permutation existe déjà, la redimensionner.
            HRESULT hr = m_swapChain->ResizeBuffers(
                2, // Chaîne de permutation mise deux fois en mémoire tampon.
                lround(m_d3dRenderTargetSize.Width),
                lround(m_d3dRenderTargetSize.Height),
                DXGI_FORMAT_B8G8R8A8_UNORM,
                0
                );

            if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
            {
                // Si le périphérique a été supprimé pour une raison quelconque, un périphérique et une chaîne de permutation doivent être créés.
                HandleDeviceLost();

                // Tout est maintenant configuré. Ne poursuivez pas l'exécution de cette méthode. HandleDeviceLost entrera à nouveau cette méthode 
                // et configurer correctement le nouveau périphérique.
                return;
            }
            else
            {
                DX::ThrowIfFailed(hr);
            }
        }
        else
        {
            // Sinon, en créer une nouvelle en utilisant le même adaptateur que le périphérique Direct3D existant.
            DXGI_SCALING scaling = DisplayMetrics::SupportHighResolutions ? DXGI_SCALING_NONE : DXGI_SCALING_STRETCH;
            DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};

            swapChainDesc.Width = lround(m_d3dRenderTargetSize.Width);      // Faire correspondre avec la taille de la fenêtre.
            swapChainDesc.Height = lround(m_d3dRenderTargetSize.Height);
            swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;              // Il s'agit du format de chaîne de permutation le plus courant.
            swapChainDesc.Stereo = false;
            swapChainDesc.SampleDesc.Count = 1;                             // Ne pas utiliser l'échantillonnage multiple.
            swapChainDesc.SampleDesc.Quality = 0;
            swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
            swapChainDesc.BufferCount = 2;                                  // Utiliser la double mise en mémoire tampon pour réduire la latence.
            swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;    // Toutes les applications Windows Store doivent utiliser ce SwapEffect.
            swapChainDesc.Flags = 0;
            swapChainDesc.Scaling = DXGI_SCALING_NONE;// scaling;
            swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;

            // Cette séquence obtient la fabrique DXGI utilisée pour créer le périphérique Direct3D ci-dessus.
            ComPtr<IDXGIDevice3> dxgiDevice;
            DX::ThrowIfFailed(
                m_d3dDevice.As(&dxgiDevice)
                );

            ComPtr<IDXGIAdapter> dxgiAdapter;
            DX::ThrowIfFailed(
                dxgiDevice->GetAdapter(&dxgiAdapter)
                );

            ComPtr<IDXGIFactory4> dxgiFactory;
            DX::ThrowIfFailed(
                dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory))
                );

            ComPtr<IDXGISwapChain1> swapChain;
            DX::ThrowIfFailed(
                dxgiFactory->CreateSwapChainForCoreWindow(
                    m_d3dDevice.Get(),
                    reinterpret_cast<IUnknown*>(m_window.Get()),
                    &swapChainDesc,
                    nullptr,
                    &swapChain
                    )
                );
            DX::ThrowIfFailed(
                swapChain.As(&m_swapChain)
                );

            // Vérifier que DXGI ne met pas plus d'un frame à la fois en file d'attente. Cela permet de réduire la latence et
            // de veiller à ce que l'application effectue le rendu uniquement après chaque VSync, réduisant de ce fait la consommation d'énergie.
            DX::ThrowIfFailed(
                dxgiDevice->SetMaximumFrameLatency(1)
                );

        }

        // Définir l'orientation appropriée pour la chaîne de permutation et générer des
        // transformations de matrices 2D et 3D pour effectuer le rendu vers la chaîne de permutation pivotée.
        // Noter que l’angle de rotation des transformations 2D et 3D est différent.
        // Ceci est dû à la différence entre les espaces de coordonnées.  En outre,
        // la matrice 3D est spécifiée de manière explicite pour éviter les erreurs d'arrondi.

        switch (displayRotation)
        {
        case DXGI_MODE_ROTATION_IDENTITY:
            m_orientationTransform2D = Matrix3x2F::Identity();
            m_orientationTransform3D = ScreenRotation::Rotation0;
            break;

        case DXGI_MODE_ROTATION_ROTATE90:
            m_orientationTransform2D = 
                Matrix3x2F::Rotation(90.0f) *
                Matrix3x2F::Translation(m_logicalSize.Height, 0.0f);
            m_orientationTransform3D = ScreenRotation::Rotation270;
            break;

        case DXGI_MODE_ROTATION_ROTATE180:
            m_orientationTransform2D = 
                Matrix3x2F::Rotation(180.0f) *
                Matrix3x2F::Translation(m_logicalSize.Width, m_logicalSize.Height);
            m_orientationTransform3D = ScreenRotation::Rotation180;
            break;

        case DXGI_MODE_ROTATION_ROTATE270:
            m_orientationTransform2D = 
                Matrix3x2F::Rotation(270.0f) *
                Matrix3x2F::Translation(0.0f, m_logicalSize.Width);
            m_orientationTransform3D = ScreenRotation::Rotation90;
            break;

        default:
            throw ref new FailureException();
        }

        DX::ThrowIfFailed(
            m_swapChain->SetRotation(displayRotation)
            );

        // Créer un affichage cible de rendu de la mémoire tampon d'arrière-plan de la chaîne de permutation.
        ComPtr<ID3D11Texture2D1> backBuffer;
        DX::ThrowIfFailed(
            m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
            );

        DX::ThrowIfFailed(
            m_d3dDevice->CreateRenderTargetView1(
                backBuffer.Get(),
                nullptr,
                &m_finalScreenRenderTargetView
                )
            );

        backBuffer = nullptr; // Release

    /*  // Créer un affichage gabarit à utiliser avec le rendu 3D si nécessaire.
        CD3D11_TEXTURE2D_DESC1 depthStencilDesc(
            DXGI_FORMAT_D24_UNORM_S8_UINT, 
            lround(m_d3dRenderTargetSize.Width),
            lround(m_d3dRenderTargetSize.Height),
            1, // Cette vue du stencil de profondeur n’a qu’une texture.
            1, // Utiliser un niveau mipmap unique.
            D3D11_BIND_DEPTH_STENCIL
            );

        ComPtr<ID3D11Texture2D1> depthStencil;
        DX::ThrowIfFailed(
            m_d3dDevice->CreateTexture2D1(
                &depthStencilDesc,
                nullptr,
                &depthStencil
                )
            );
    */
    /*  CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D);
        DX::ThrowIfFailed(
            m_d3dDevice->CreateDepthStencilView(
                depthStencil.Get(),
                &depthStencilViewDesc,
                &m_d3dDepthStencilView
                )
            );
    */  

        // swapchain viewport
        m_screenSwapchainViewport = CD3D11_VIEWPORT(
            0.0f,
            0.0f,
            m_d3dRenderTargetSize.Width,
            m_d3dRenderTargetSize.Height
        );

        // screen 960 X 540 viewport
        m_screen960X540Viewport = CD3D11_VIEWPORT(
            0.0f,
            0.0f,
            960,
            540
        );

        // screen 1920 X 1080 viewport
        m_screen1920X1080Viewport = CD3D11_VIEWPORT(
            0.0f,
            0.0f,
            1920,
            1080
        );

        m_d3dContext->RSSetViewports(1, &m_screenSwapchainViewport);

        // Créer une image bitmap cible Direct2D associée à la
        // mémoire tampon d'arrière-plan de la chaîne de permutation et la définir en tant que cible actuelle.
        D2D1_BITMAP_PROPERTIES1 bitmapProperties = 
            D2D1::BitmapProperties1(
                D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
                D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
                m_dpi,
                m_dpi
                );

        ComPtr<IDXGISurface2> dxgiBackBuffer;
        DX::ThrowIfFailed(
            m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer))
            );

        DX::ThrowIfFailed(
            m_d2dContext->CreateBitmapFromDxgiSurface(
                dxgiBackBuffer.Get(),
                &bitmapProperties,
                &m_d2dTargetBitmapSwapChain
                )
            );
        dxgiBackBuffer = nullptr; // Release

        m_d2dContext->SetTarget(m_d2dTargetBitmapSwapChain.Get());
        m_d2dContext->SetDpi(m_effectiveDpi, m_effectiveDpi);

        // L'anticrénelage du texte en nuances de gris est recommandé pour toutes les applications Windows Store.
        m_d2dContext->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
    }

А вот ссылка на весь проект на моем OneDrive, в случае, если вы хотите увидеть утечку самостоятельно или если вы хотите увидеть другие части кода:

https://1drv.ms/f/s!Aj7wxGmZTdftgZAZT5YAbLDxbtMNVg Компилировать как код X64.Продолжайте изменять размер окна, перетаскивая правый угол нижнего края игрового окна по кругу, и наблюдайте, как используемая память постоянно увеличивается.

...