Direct2D实现UWP风格Backdrop-Blur效果时渲染报错求助
问题根源与修复方案
核心问题解析
- 目标位图的使用限制:你创建的
bb位图添加了D2D1_BITMAP_OPTIONS_TARGET标记,这类位图仅能作为渲染目标使用,无法被Effect采样。GaussianBlur对输入资源有严格要求,而ScaleEffect的兼容性更强,这就是两者表现差异的原因。 - 跨上下文操作资源:用主设备上下文
target创建Effect,却在后台缓冲区backTarget绘制,容易引发资源上下文冲突。 - 冗余的后台缓冲区创建:无需先创建
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上下文:在后台缓冲区的
相关产品推荐
相关产品推荐

