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

Direct2D实现UWP风格Backdrop-Blur效果时渲染报错求助

问题根源与修复方案

核心问题解析

  1. 目标位图的使用限制:你创建的bb位图添加了D2D1_BITMAP_OPTIONS_TARGET标记,这类位图仅能作为渲染目标使用,无法被Effect采样。GaussianBlur对输入资源有严格要求,而ScaleEffect的兼容性更强,这就是两者表现差异的原因。
  2. 跨上下文操作资源:用主设备上下文target创建Effect,却在后台缓冲区backTarget绘制,容易引发资源上下文冲突。
  3. 冗余的后台缓冲区创建:无需先创建ID2D1BitmapRenderTarget再QueryInterface,直接创建ID2D1DeviceContext兼容目标更高效。

修复后的代码

#include <Windows.h>

HDC hdcDevice = GetDC(NULL);
int xw = GetDeviceCaps(hdcDevice, HORZRES);
int yw = GetDeviceCaps(hdcDevice, VERTRES);

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);

HWND hwnd;

#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <wchar.h>
#include <math.h>

#include <d2d1_1.h>
#include <d2d1helper.h>
#include <dwrite.h>
#include <wincodec.h>

#pragma comment(lib, "d2d1")
#pragma comment(lib, "dxguid.lib")

template<class Interface>
inline void SafeRelease(Interface** ppInterfaceToRelease)
{
    if (*ppInterfaceToRelease != NULL)
    {
        (*ppInterfaceToRelease)->Release();
        (*ppInterfaceToRelease) = NULL;
    }
}

#ifndef Assert
#if defined( DEBUG ) || defined( _DEBUG )
#define Assert(b) do {if (!(b)) {OutputDebugStringA("Assert: " #b "\n");}} while(0)
#else
#define Assert(b)
#endif //DEBUG || _DEBUG
#endif

#ifndef HINST_THISCOMPONENT
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
#endif

ID2D1Factory1* m_pDirect2dFactory;
ID2D1HwndRenderTarget* m_pRenderTarget;
ID2D1DeviceContext* target;
ID2D1SolidColorBrush* brush;

void Release()
{
    SafeRelease(&m_pRenderTarget);
    SafeRelease(&target);
    SafeRelease(&brush);
}

void Init()
{
    Release();
    m_pRenderTarget = NULL;

    RECT rc;
    GetClientRect(hwnd, &rc);

    D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);

    // 创建支持D2D1.1的工厂
    SUCCEEDED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory1), &m_pDirect2dFactory));

    // 创建HwndRenderTarget
    SUCCEEDED(m_pDirect2dFactory->CreateHwndRenderTarget(
        D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)),
        D2D1::HwndRenderTargetProperties(hwnd, size),
        &m_pRenderTarget));

    m_pRenderTarget->QueryInterface(&target);
}

inline void Blur(ID2D1DeviceContext* backTarget, int rad, RECT r)
{
    RECT rc;
    GetClientRect(hwnd, &rc);
    D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);

    // 绘制测试矩形
    backTarget->FillRectangle(D2D1::RectF(30, 30, 100, 100), brush);

    // 创建可采样的位图(去掉TARGET标记)
    ID2D1Bitmap1* bb = nullptr;
    backTarget->CreateBitmap(size, 0, 0, D2D1::BitmapProperties1(
        D2D1_BITMAP_OPTIONS_NONE,
        D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)
    ), &bb);

    // 复制当前渲染目标内容到位图
    bb->CopyFromRenderTarget(nullptr, backTarget, nullptr);

    // 在当前后台上下文创建Effect,避免跨上下文
    ID2D1Effect* blur = nullptr;
    backTarget->CreateEffect(CLSID_D2D1GaussianBlur, &blur);
    blur->SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, 10.0f);
    blur->SetInput(0, bb);

    // 绘制模糊效果到后台目标
    backTarget->DrawImage(blur);

    // 测试位图有效性
    auto a = D2D1::Point2F(100, 0);
    backTarget->DrawImage(bb, a);

    SafeRelease(&blur);
    SafeRelease(&bb);
}

inline void Render()
{
    RECT rc;
    GetClientRect(hwnd, &rc);
    D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);

    // 直接创建ID2D1DeviceContext的兼容目标
    ID2D1DeviceContext* backCtx = nullptr;
    target->CreateCompatibleRenderTarget(size, &backCtx);

    backCtx->CreateSolidColorBrush(D2D1::ColorF(255, 0, 0), &brush);

    backCtx->BeginDraw();
    backCtx->Clear(D2D1::ColorF(D2D1::ColorF::Blue));
    backCtx->SetTransform(D2D1::Matrix3x2F::Identity());

    // 执行模糊操作
    Blur(backCtx, 10, RECT());

    backCtx->EndDraw();

    // 获取后台目标的位图并绘制到主目标
    target->BeginDraw();
    ID2D1Bitmap* backBmp = nullptr;
    backCtx->GetBitmap(&backBmp);
    target->DrawImage(backBmp);

    // 释放资源
    SafeRelease(&backBmp);
    SafeRelease(&backCtx);
    SafeRelease(&brush);

    target->EndDraw();
}

int WINAPI WinMain(HINSTANCE hin, HINSTANCE, LPSTR, int)
{
    ReleaseDC(NULL, hdcDevice);

    WNDCLASS c = { NULL };
    c.lpszClassName = L"asd";
    c.lpfnWndProc = WndProc;
    c.hInstance = hin;
    c.style = CS_VREDRAW | CS_HREDRAW;
    c.hCursor = LoadCursor(NULL, IDC_ARROW);
    c.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
    RegisterClass(&c);

    int cx = 500, cy = 500;
    int x = xw / 2 - cx / 2, y = yw / 2 - cy / 2;

    hwnd = CreateWindowEx(NULL, L"asd", L"asd", WS_POPUP | WS_VISIBLE, x, y, cx, cy, NULL, NULL, hin, 0);

    HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
    CoInitialize(NULL);

    Init();

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

    SafeRelease(&m_pDirect2dFactory);
    CoUninitialize();

    return 0;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
    switch (message)
    {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
            return DefWindowProc(hwnd, message, wp, lp);
    }
    return NULL;
}

关键修改点

  • 工厂升级:使用ID2D1Factory1确保支持D2D1.1特性;
  • 位图创建:去掉D2D1_BITMAP_OPTIONS_TARGET标记,创建可采样的普通位图;
  • Effect上下文:在后台缓冲区的
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 23:51:04