1

我正在研究一个基于这篇文章使用直接合成的项目:

Windows with C++ : 使用 Windows 组合引擎的高性能窗口分层

我能够重新创建示例并且它正在工作。目前我正在尝试将 IDCompositionGaussianBlurEffect 应用于我的视觉(variable: visual),但编译器引发访问冲突异常。有什么方法可以使用直接合成将模糊效果应用于我的视觉效果。

例外:

Exception thrown at 0x6E695565 (dcomp.dll) in DirectComNoCom.exe: 0xC0000005: Access violation reading location 0x41200000.

在这一行抛出异常:

 effect->SetStandardDeviation(10.0f);

这是完整的代码:

#ifndef UNICODE
#define UNICODE
#endif 

#include <windows.h>
#include <wrl.h>
using namespace Microsoft::WRL;
#include <dxgi1_3.h>
#include <d3d11_2.h>
#include <d2d1_2.h>
#include <d2d1_2helper.h>
#include <dcomp.h>
#pragma comment(lib, "dxgi")
#pragma comment(lib, "d3d11")
#pragma comment(lib, "d2d1")
#pragma comment(lib, "dcomp")

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

ComPtr<ID3D11Device> direct3dDevice;
ComPtr<IDXGIDevice> dxgiDevice;
ComPtr<IDXGIFactory2> dxFactory;
ComPtr<IDXGISwapChain1> swapChain;
ComPtr<ID2D1Factory2> d2Factory;
ComPtr<ID2D1Device1> d2Device;
ComPtr<IDCompositionTarget> target;

struct ComException
{
    HRESULT result;
    ComException(HRESULT const value) :
        result(value)
    {}
};
void HR(HRESULT const result)
{
    if (S_OK != result)
    {
        throw ComException(result);
    }
}

void CreateVisual(HWND hwnd)
{
    HR(D3D11CreateDevice(nullptr,    // Adapter
        D3D_DRIVER_TYPE_HARDWARE,
        nullptr,    // Module
        D3D11_CREATE_DEVICE_BGRA_SUPPORT,
        nullptr, 0, // Highest available feature level
        D3D11_SDK_VERSION,
        &direct3dDevice,
        nullptr,    // Actual feature level
        nullptr));  // Device context

    HR(direct3dDevice.As(&dxgiDevice));

    HR(CreateDXGIFactory2(
        DXGI_CREATE_FACTORY_DEBUG,
        __uuidof(dxFactory),
        reinterpret_cast<void**>(dxFactory.GetAddressOf())));

    DXGI_SWAP_CHAIN_DESC1 description = {};

    description.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    description.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    description.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
    description.BufferCount = 2;
    description.SampleDesc.Count = 1;
    description.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;

    RECT rect = {};
    GetClientRect(hwnd, &rect);
    description.Width = rect.right - rect.left;
    description.Height = rect.bottom - rect.top;

    HR(dxFactory->CreateSwapChainForComposition(dxgiDevice.Get(),
        &description,
        nullptr, // Don’t restrict
        swapChain.GetAddressOf()));

    D2D1_FACTORY_OPTIONS const options = { D2D1_DEBUG_LEVEL_INFORMATION };
    HR(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
        options,
        d2Factory.GetAddressOf()));
    // Create the Direct2D device that links back to the Direct3D device
    HR(d2Factory->CreateDevice(dxgiDevice.Get(),
        d2Device.GetAddressOf()));
    // Create the Direct2D device context that is the actual render target
    // and exposes drawing commands
    ComPtr<ID2D1DeviceContext> dc;
    HR(d2Device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
        dc.GetAddressOf()));
    // Retrieve the swap chain's back buffer
    ComPtr<IDXGISurface2> surface;
    HR(swapChain->GetBuffer(
        0, // index
        __uuidof(surface),
        reinterpret_cast<void**>(surface.GetAddressOf())));
    // Create a Direct2D bitmap that points to the swap chain surface
    D2D1_BITMAP_PROPERTIES1 properties = {};
    properties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
    properties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
    properties.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET |
        D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
    ComPtr<ID2D1Bitmap1> bitmap;
    HR(dc->CreateBitmapFromDxgiSurface(surface.Get(),
        properties,
        bitmap.GetAddressOf()));
    // Point the device context to the bitmap for rendering
    dc->SetTarget(bitmap.Get());
    // Draw something
    dc->BeginDraw();
    dc->Clear();
    ComPtr<ID2D1SolidColorBrush> brush;
    D2D1_COLOR_F const brushColor = D2D1::ColorF(0.18f,  // red
        0.55f,  // green
        0.34f,  // blue
        0.75f); // alpha
    HR(dc->CreateSolidColorBrush(brushColor,
        brush.GetAddressOf()));
    D2D1_POINT_2F const ellipseCenter = D2D1::Point2F(150.0f,  // x
        150.0f); // y
    D2D1_ELLIPSE const ellipse = D2D1::Ellipse(ellipseCenter,
        100.0f,  // x radius
        100.0f); // y radius
    dc->FillEllipse(ellipse,
        brush.Get());
    HR(dc->EndDraw());
    // Make the swap chain available to the composition engine
    HR(swapChain->Present(1,   // sync
        0)); // flags

    ComPtr<IDCompositionDevice> dcompDevice;
    ComPtr<IDCompositionVisual> visual;

    HR(DCompositionCreateDevice(
        dxgiDevice.Get(),
        __uuidof(dcompDevice),
        reinterpret_cast<void**>(dcompDevice.GetAddressOf())));

    ComPtr<IDCompositionDevice3> dcompDevice3;
    
    dcompDevice->QueryInterface(__uuidof(IDCompositionDevice), (LPVOID*)&dcompDevice3);
    ComPtr<IDCompositionGaussianBlurEffect> effect;
    HR(dcompDevice3->CreateGaussianBlurEffect(&effect));
    effect->SetStandardDeviation(10.0f);
    HR(dcompDevice->CreateTargetForHwnd(hwnd,
        true, // Top most
        target.GetAddressOf()));

    HR(dcompDevice->CreateVisual(visual.GetAddressOf()));
    HR(visual->SetContent(swapChain.Get()));
    HR(target->SetRoot(visual.Get()));
    HR(dcompDevice->Commit());

}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
    // Register the window class.
    const wchar_t CLASS_NAME[] = L"Sample Window Class";

    WNDCLASS wc = { };

    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;

    RegisterClass(&wc);

    // Create the window.

    HWND hwnd = CreateWindowEx(WS_EX_NOREDIRECTIONBITMAP,
        wc.lpszClassName, L"Sample",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        nullptr, nullptr, hInstance, nullptr);

    if (hwnd == NULL)
    {
        return 0;
    }
    CreateVisual(hwnd);
    ShowWindow(hwnd, nCmdShow);

    // Run the message loop.

    MSG msg = { };
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));

        EndPaint(hwnd, &ps);
    }
    return 0;

    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

我尝试更改每段代码,但仍然引发异常。我是 Directx 的新手, IDCompositionDevice3代码中的设备实际上是我自己创建的,我不知道这是对还是错,因为 Microsoft 提供的文档中没有太多描述。

这是完整的项目代码:直接合成模糊

4

2 回答 2

1

据推测,这是使用 WRL 的ComPtr. 要访问其内部接口指针,您需要调用GetAddressOf

dcompDevice3->CreateGaussianBlurEffect(effect.GetAddressOf());

WRL 的operator&在返回一个弱引用方面是可怕的,这会阻止编译器捕获这种意外使用。


注意:C++/WinRT 提供了更安全的 COM 智能指针类型 ( winrt::com_ptr ),但没有为您提供那么多的 COM 支持。

于 2020-08-12T18:08:24.283 回答
1

有两个问题:

1.dcomp实现似乎很奇怪,因为它成功地回答了这个问题,但 dcompDevice3 实际上以某种方式被破坏,因此崩溃:

ComPtr<IDCompositionDevice3> dcompDevice3;
HR(dcompDevice->QueryInterface(__uuidof(IDCompositionDevice), (LPVOID*)&dcompDevice3))

2.你的代码也很糟糕,因为它应该是这样的:

HR(DCompositionCreateDevice3( // only this factory can give you an IDCompositionDevice3 implementation
    dxgiDevice.Get(),
    __uuidof(dcompDevice),
    reinterpret_cast<void**>(dcompDevice.GetAddressOf())));

ComPtr<IDCompositionDevice3> dcompDevice3;
HR(dcompDevice->QueryInterface(__uuidof(IDCompositionDevice3), (LPVOID*)&dcompDevice3)); // use IDCompositionDevice3 here

现在它应该工作,至少,继续。

于 2020-08-12T20:46:59.210 回答