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

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1536671.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【23-24年】年度总结与迎新引荐

文章目录 相关连接前言1 忙碌的备研与本科毕设2 暑期阿里之旅3 团队荣誉与迎新引荐4 项目合作意向 相关连接 个人博客&#xff1a;issey的博客 - 愿无岁月可回首 前言 自从2023年4月更新了两篇关于NLP的文章后&#xff0c;我便消失了一年半的时间。如今&#xff0c;随着学业…

SpringBoot 图书管理系统

文章目录 一、删除图书二、批量删除三、强制登录3.1 不使用拦截器3.2 使用拦截器 四、更新图书 一、删除图书 并不使用delete语句&#xff1a; 原因&#xff1a;企业开发中&#xff0c;因为数据就意味着金钱&#xff0c;所以我们不会使用delete去删除&#xff08;delete删除是…

基于SpringBoot的人事管理系统【附源码】

基于SpringBoot的人事管理系统&#xff08;源码L文说明文档&#xff09; 目录 4 系统设计 4.1 系统概述 4.2系统功能结构设计 4.3数据库设计 4.3.1数据库E-R图设计 4.3.2 数据库表结构设计 5 系统实现 5.1管理员功能介绍 5.1.1管理员登…

2分钟解决联想电脑wifi功能消失 网络适配器错误代码56

分钟解决联想电脑wifi功能消失 网络适配器错误代码56 现象 原因 电脑装了虚拟机&#xff0c;导致网络适配器冲突。我的电脑是装了vm虚拟机&#xff0c;上次更新系统后wifi图标就消失了。 解决方案 1、先卸载虚拟机 2、键盘按winr&#xff0c;弹出运行窗口&#xff0c;输入“…

LLVM PASS-PWN-前置

文章目录 参考环境搭建基础知识![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/dced705dcbb045ceb8df2237c9b0fd71.png)LLVM IR实例1. **.ll 格式&#xff08;人类可读的文本格式&#xff09;**2. **.bc 格式&#xff08;二进制格式&#xff09;**3. **内存表示** …

『功能项目』伤害数字UI显示【53】

我们打开上一篇52眩晕图标显示的项目&#xff0c; 本章要做的事情是在Boss受到伤害时显示伤害数字 首先打开Boss01预制体空间在Canvas下创建一个Text文本 设置Text文本 重命名为DamageUI 设置为隐藏 编写脚本&#xff1a;PlayerCtrl.cs 运行项目 本章做了怪物受伤血量的显示UI…

C语言 ——— 写一个宏,将一个整数的二进制位的奇数位和偶数位交换

目录 题目要求 代码实现 题目要求 写一个宏&#xff0c;将一个整数的二进制位的奇数位和偶数位交换 举例说明&#xff1a; 输入&#xff1a;10 10 的二进制为 1010 &#xff0c;奇数位和偶数位交换后得 0101 &#xff0c;也就是 5 输出&#xff1a;5 代码实现 代码演示&…

RK3568驱动指南|第十六篇 SPI-第190章 配置模式下寄存器的配置

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

电流镜与恒流源

在两个晶体管完全对称的情况下&#xff0c;电源通过R1给两个晶体管提供相同的偏置电流&#xff0c; 这样他们流过集电极和发射极的电流就相同。 电流镜原视频链接&#xff1a; 【电流镜电路】https://www.bilibili.com/video/BV1b5411k7rh?vd_source3cc3c07b09206097d0d8b0ae…

Linux基础3-基础工具3(make,makefile,gdb详解)

上篇文章&#xff1a;Linux基础3-基础工具2&#xff08;vim详解&#xff0c;gcc详解&#xff09;-CSDN博客 本章重点&#xff1a; 1.自动化构建工具make,makefile 2.linux调试工具gdb 目录 一. 自动化构建工具make,makefile 1.1 make使用 1.2 使用make注意点 a. make和文件时…

Python数据分析案例60——扩展变量后的神经网络风速预测(tsfresh)

案例背景 时间序列的预测一直是经久不衰的实际应用和学术研究的对象&#xff0c;但是绝大多数的时间序列可能就没有太多的其他的变量&#xff0c;例如一个股票的股价&#xff0c;还有一个企业的用电量&#xff0c;人的血糖浓度等等&#xff0c;空气的质量&#xff0c;温度这些…

揭秘LLM计算数字的障碍的底层原理

LLM的 Tokenizer与数字切分 大语言模型在处理语言时&#xff0c;通常依赖Tokenization技术来将文本切分为可操作的单元。早期版本的Tokenizer对数字处理不够精确&#xff0c;常常将多个连续数字合并为一个Token。比如“13579”可能被切分为“13”、“57”和“9”。在这种情况…

【Linux修行路】网络套接字编程——UDP

目录 ⛳️推荐 前言 六、Udp Server 端代码 6.1 socket——创建套接字 6.2 bind——将套接字与一个 IP 和端口号进行绑定 6.3 recvfrom——从服务器的套接字里读取数据 6.4 sendto——向指定套接字中发送数据 6.5 绑定 ip 和端口号时的注意事项 6.5.1 云服务器禁止直接…

AIGC图片相关知识和实战经验(Flux.1,ComfyUI等等)

最近看了网上的一些新闻&#xff0c;flux.1火出圈了&#xff0c;因此自己也尝试跑了一下&#xff0c;作图的质量还是蛮高的&#xff0c;在这里做个知识总结回顾。 flux.1是什么&#xff1f; 根据介绍&#xff0c;flux.1是由stable diffusion 一作&#xff0c;Stability AI的核…

数据结构----栈和队列

&#xff08;一&#xff09;栈 1.栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First …

【数据结构】十大经典排序算法总结与分析

文章目录 前言1. 十大经典排序算法分类2. 相关概念3. 十大经典算法总结4. 补充内容4.1 比较排序和非比较排序的区别4.2 稳定的算法就真的稳定了吗&#xff1f;4.3 稳定的意义4.4 时间复杂度的补充4.5 空间复杂度补充 结语 前言 排序算法是《数据结构与算法》中最基本的算法之一…

PHP Swoole实现简易聊天室,附加小程序端连接websocket简易代码

目录 用到的工具&#xff1a; PHP Swoole拓展 | PHP Redis拓展 | Redis 7 一、安装上述必要工具&#xff08;下面是以宝塔面板中操作为例&#xff09; 给PHP安装Swoole和Redis拓展&#xff1a; 安装Redis软件 二、创建websocket服务器文件"wss_server.php" 具…

19 MDIO 接口读写以太网PHY寄存器

以太网概述 以太网&#xff08;Ethernet&#xff09;是应用最普遍的局域网技术。IEEE组织的 IEEE 802.3标准制定了以太网的技术标准&#xff0c;它规定了包括物理层的连线、电子信号和介质访问层协议的内容。以太网凭借其成本低、通信速率高、抗干扰性强等优点被广泛应用在网络…

2024 RSTCONCTF re 部分wp

Unknown Architect DIE查看&#xff0c;RISC_V架构&#xff0c;直接交即可 Duke of the Kingdom 附件拖入jadx 比较简单。脚本 Keypad 附件拖入ida。一共四遍check&#xff0c;都比较简单 Pico-Cypher 文本编辑器打开附件 稍微问一问gpt&#xff0c;得知这是micropython&#x…

2024年【浙江省安全员-C证】考试试卷及浙江省安全员-C证模拟考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 浙江省安全员-C证考试试卷是安全生产模拟考试一点通总题库中生成的一套浙江省安全员-C证模拟考试题库&#xff0c;安全生产模拟考试一点通上浙江省安全员-C证作业手机同步练习。2024年【浙江省安全员-C证】考试试卷及…