1

I was working on a project which uses direct composition based on this Article:

Windows with C++ : High-Performance Window Layering Using the Windows Composition Engine

I was able to recreate the example and it is working. Currently i'm trying to apply IDCompositionGaussianBlurEffect to My Visual (variable: visual) but the Compiler Throws an Access Violation Exception. Is there any way to Apply the Blur Effect on to my visual using Direct Composition.

The Exception:

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

The Exception is thrown at this line:

 effect->SetStandardDeviation(10.0f);

Here is the Full Code:

#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);
}

I tried changing every piece of code and still it Throws Exception. I am new to Directx and IDCompositionDevice3 device in the code is actually created by myself, i don't know weather it is right or wrong since there is not much described in the Documentation Provided by Microsoft.

Here is the Full Project Code : Direct Composition Blur

trickymind
  • 557
  • 5
  • 21

2 Answers2

1

Presumably, this is using WRL's ComPtr. To access its internal interface pointer you'll want to call GetAddressOf:

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

WRL's operator& is hideous in returning a weak reference, that prevents the compiler from catching this unintended use.


Note: C++/WinRT provides a far safer COM smartpointer type (winrt::com_ptr), but doesn't give you as much COM support.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • Sir I have tried the method as you mentioned but still it's throwing exception. Is there anything wrong in my code? – trickymind Aug 12 '20 at 18:49
  • `dcompDevice->QueryInterface(__uuidof(IDCompositionDevice), (LPVOID*)&dcompDevice3)` looks wrong, for the same reason. – IInspectable Aug 12 '20 at 19:24
1

There are two problems:

1.dcomp implementation seems strange to be the least because it answers this successfully but dcompDevice3 is in fact broken somehow, hence the crash:

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

2.and your code is also bad as it should be this:

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

And now it should work, at least, continue.

Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
  • Thank you very much it worked Perfectly. I Was Actually Trying to Achieve the Microsoft Acrylic Blur Effect Using Direct Composition. – trickymind Aug 13 '20 at 03:43
  • Can you Do Me One more favor : Can you please provide me a way to get the visual behind my window so that i can blur the window in real-time to recreate the Acrylic Blur Effect. Here is the Question: [Drawing visual behind a window using directx](https://stackoverflow.com/questions/63322211/drawing-visual-behind-a-window-using-directx) Just like the magnifier does – trickymind Aug 13 '20 at 03:45
  • As I said previously, this is almost completely described here: https://notes.yvt.jp/Desktop-Apps/Enabling-Backdrop-Blur . You cannot achieve that using the "old" Win32 dcomp interfaces. You must use WinRT and the newer Windows.UI.Composition classes. This is like Direct Composition V2. Only these have access to the backdrop brush. Brush recipe is here https://github.com/microsoft/microsoft-ui-xaml/blob/master/dev/Materials/Acrylic/AcrylicBrush.cpp note they use Win2D wich is stupidly limited to UWP, but you can use Direct2D using IGraphicsEffectD2D1Interop. – Simon Mourier Aug 13 '20 at 05:09
  • See this also : https://learn.microsoft.com/en-us/archive/msdn-magazine/2015/windows-10-special-issue/graphics-and-animation-windows-composition-turns-10 and the most simple sample of using WinRT's Windows UI Composition: https://gist.github.com/kennykerr/62923cdacaba28fedc4f3dab6e0c12ec – Simon Mourier Aug 13 '20 at 05:12
  • Thank you sir, i will try and let you know. – trickymind Aug 13 '20 at 05:18
  • How does windows magnifier gets the backdrop on to the screen? – trickymind Aug 13 '20 at 11:40
  • I don't know about the magnifier. – Simon Mourier Aug 13 '20 at 18:25
  • The magnifier api could exclude itself while capturing from screen – trickymind Aug 14 '20 at 03:06
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/219787/discussion-between-trickymind-and-simon-mourier). – trickymind Aug 14 '20 at 03:06