您的位置:首页 > 娱乐 > 明星 > Qt集成Direct2D绘制,实现离屏渲染

Qt集成Direct2D绘制,实现离屏渲染

2024/10/6 0:28:14 来源:https://blog.csdn.net/qq_45523399/article/details/142305028  浏览:    关键词:Qt集成Direct2D绘制,实现离屏渲染

没搜到关于Qt中使用Direct2D的方式,想了个办法,在此做个记录。

需要引入这两个库:

在这里插入图片描述

代码:

#pragma once
#include <QWidget>
#include <QImage>
#include <QPainter>
#include <QMouseEvent>#include "d2d1.h"
#include "wincodec.h"
#include "dwrite.h"#define SAFE_RELEASE(P) if(P){P->Release(); P = nullptr;}#define START_RECORD_TIME(name) auto s_##name = std::chrono::high_resolution_clock::now();#define END_RECORD_TIME_MS(name) auto e_##name = std::chrono::high_resolution_clock::now();             \
auto du_##name = std::chrono::duration_cast<std::chrono::milliseconds>(e_##name - s_##name).count();             \
OutputDebugStringA(std::string(std::string(__FUNCTION__) + " " + std::to_string(__LINE__) + " : " + #name + " " + std::to_string(du_##name) + " ms\n").c_str());             \

#define END_RECORD_TIME_US(name) auto e_##name = std::chrono::high_resolution_clock::now();             \
auto du_##name = std::chrono::duration_cast<std::chrono::microseconds>(e_##name - s_##name).count();             \
OutputDebugStringA(std::string(std::string(__FUNCTION__) + " " + std::to_string(__LINE__) + " : " + #name + " " + std::to_string(du_##name) + " us\n").c_str());             \

class CanvasWidget :public QWidget
{
public:CanvasWidget(QWidget* parent = nullptr);~CanvasWidget();void mousePressEvent(QMouseEvent* event) override;void mouseReleaseEvent(QMouseEvent* event) override;void mouseMoveEvent(QMouseEvent* event) override;void paintEvent(QPaintEvent* event) override;void CreateD2DInit();void Draw();void Cleanup();void TransImage();HWND hWnd;ID2D1Factory* pD2DFactory = nullptr;ID2D1RenderTarget* pRenderTarget = nullptr;ID2D1SolidColorBrush* pBrush = nullptr;IDWriteFactory* pDWFactory = nullptr;IDWriteTextFormat* pTextFormat = nullptr;IWICImagingFactory* pWICFactory = nullptr;IWICBitmap* pWICBitmap = nullptr;QImage* pBufferImage = nullptr;std::vector<std::vector<int>> rects;std::vector<D2D1::ColorF> colors;int count = 100;int wh = 8;int drawStartX = 0;int drawStartY = 0;QPoint pressPoint;bool pressFlag = false;
};
#include "CanvasWidget.h"#include <chrono>
#include <random>CanvasWidget::CanvasWidget(QWidget* parent)
{hWnd = (HWND)this->winId();std::random_device rd;std::uniform_int_distribution<int> dist(0, 255);for (int i = 0; i < count; i++) {for (int j = 0; j < count; j++){std::vector<int> rect;rect.push_back(j * wh);rect.push_back(i * wh);rects.push_back(rect);colors.push_back(D2D1::ColorF(dist(rd) / 255.0, dist(rd) / 255.0, dist(rd) / 255.0));}}Draw();
}CanvasWidget::~CanvasWidget()
{Cleanup();
}void CanvasWidget::mousePressEvent(QMouseEvent* event)
{pressFlag = true;pressPoint = event->pos();QWidget::mousePressEvent(event);
}void CanvasWidget::mouseReleaseEvent(QMouseEvent* event)
{pressFlag = false;QWidget::mouseReleaseEvent(event);
}void CanvasWidget::mouseMoveEvent(QMouseEvent* event)
{if (pressFlag){QPoint delta = event->pos() - pressPoint;drawStartX += delta.x();drawStartY += delta.y();pressPoint = event->pos();this->update();}QWidget::mouseMoveEvent(event);
}void CanvasWidget::paintEvent(QPaintEvent* event)
{if (pBufferImage != nullptr) {START_RECORD_TIME(drawImage)QPainter painter(this);painter.drawImage(drawStartX, drawStartY, *pBufferImage);END_RECORD_TIME_MS(drawImage)}QWidget::paintEvent(event);
}void CanvasWidget::CreateD2DInit()
{RECT rc;GetClientRect(hWnd, &rc);HRESULT hr;// 创建WIC工厂hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pWICFactory));if (SUCCEEDED(hr)){// 创建WIC Bitmaphr = pWICFactory->CreateBitmap(rc.right - rc.left, rc.bottom - rc.top, GUID_WICPixelFormat32bppPRGBA, WICBitmapCacheOnLoad, &pWICBitmap);}// 创建Direct2D工厂hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);if (FAILED(hr)) { MessageBox(hWnd, L"Create D2D factory failed!", L"Error", 0); return; }// 创建Render Targethr = pD2DFactory->CreateWicBitmapRenderTarget(pWICBitmap, D2D1::RenderTargetProperties(), &pRenderTarget);if (FAILED(hr)){ MessageBox(hWnd, L"Create render target failed!", L"Error", 0);	return; }// 创建一个画刷hr = pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Red), &pBrush);if (FAILED(hr)) { MessageBox(hWnd, L"Create brush failed!", L"Error", 0); return; }// 创建DirectWrite工厂hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&pDWFactory));if (FAILED(hr)){MessageBox(hWnd, L"Create DirectWrite factory failed!", L"Error", 0);return;}// 创建文本格式hr = pDWFactory->CreateTextFormat(L"Gabriola", nullptr, DWRITE_FONT_WEIGHT_REGULAR, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 50.0f, L"en-us", &pTextFormat);if (FAILED(hr)){MessageBox(hWnd, L"Create IDWriteTextFormat failed!", L"Error", 0);return;}
}void CanvasWidget::Draw()
{CreateD2DInit(); // 创建初始化一下START_RECORD_TIME(all)pRenderTarget->BeginDraw(); // 开始绘画  绘画一定要在 BeginDraw 和 EndDraw 之间/*************************************************/pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::YellowGreen));int i = 0;for (auto& p : rects) {pBrush->SetColor(colors[i]);pRenderTarget->FillRectangle(D2D1::RectF(p[0], p[1], p[0] + wh, p[1] + wh), pBrush);pRenderTarget->DrawRectangle(D2D1::RectF(p[0], p[1], p[0] + wh, p[1] + wh), pBrush, 1.0f);i++;}pBrush->SetColor(D2D1::ColorF(D2D1::ColorF::White));pRenderTarget->DrawTextW(L"Hello World !", std::strlen("Hello World !"), pTextFormat, D2D1::RectF(0, 0, 640, 480), pBrush);/*************************************************/HRESULT hr = pRenderTarget->EndDraw(); // 结束绘画if (FAILED(hr)) { MessageBox(nullptr, L"Draw failed!", L"Error", 0);return; }END_RECORD_TIME_MS(all)TransImage();
}void CanvasWidget::Cleanup()
{SAFE_RELEASE(pRenderTarget);SAFE_RELEASE(pBrush);SAFE_RELEASE(pD2DFactory);
}void CanvasWidget::TransImage()
{UINT wicWidth, wicHeight;pWICBitmap->GetSize(&wicWidth, &wicHeight);WICPixelFormatGUID wicPixelFormat;pWICBitmap->GetPixelFormat(&wicPixelFormat);UINT32 pitch = wicWidth * sizeof(DWORD);UINT32 bufferSize = pitch * wicHeight;BYTE* buffer = new BYTE[bufferSize];HRESULT hr;WICRect rcLock = { 0,0,wicWidth,wicHeight };START_RECORD_TIME(trans)// 通过Lock获取远快于CopyPixels(30us && 1000us)IWICBitmapLock* pLock = nullptr;hr = pWICBitmap->Lock(&rcLock, WICBitmapLockWrite, &pLock);UINT lockBufferSize, lockWidth, lockHeight;BYTE* lockBuffer = nullptr;pLock->GetSize(&lockWidth, &lockHeight);pLock->GetDataPointer(&lockBufferSize, &lockBuffer);pLock->Release();pBufferImage = new QImage(lockBuffer, lockWidth, lockHeight, QImage::Format_RGBA8888);/*hr = pWICBitmap->CopyPixels(&rcLock, pitch, bufferSize, buffer);pBufferImage = new QImage(buffer, wicWidth, wicHeight, QImage::Format_RGBA8888);*/END_RECORD_TIME_US(trans)this->update();
}

运行效果:
性能:目前绘制 100*100 个填充矩形 + "Hello World !"文本
CPU:i5-1235U 1帧需要100ms

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com