DirectX12(d3d12)初始化

news2024/11/24 14:42:12

在这里插入图片描述

一、前置要求

  • Windows 10及以上(安装有DirectX12)
  • VisualStudio 2022

二、DirectX12入门

1.引用头文件

#include<Windows.h>
#include<d3d12.h>
#include<dxgi1_4.h>

2.注册窗口类并初始化窗口

这里我们调用Windows API 通过应用程序的句柄来注册一个唯一的窗口类,并创建窗口实例。我们可以根据需求去创建多个窗口,或者唯一窗口。

注意这里并不是DX12的功能,而是WinAPI的功能。

int Window::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	//注册窗口类
	WNDCLASSEX wc = { 0 };
	//结构大小
	wc.cbSize = sizeof(WNDCLASSEX);
	//窗口样式:   水平大小改变重绘|竖直大小改变重绘|窗口拥有自己的绘制设备|检测鼠标双击事件
	wc.style = CS_HREDRAW | CS_VREDRAW|CS_OWNDC| CS_DBLCLKS;
	//这一句是窗口过程函数的初始化,如果有需要可以在Window里定义一个静态函数
	//函数签名如下,也可也不定义,自己处理MSG(下文会提到)
	//LRESULT CALLBACK Window::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
	//wc.lpfnWndProc = Window::WndProc;
	//指向应用程序实例的句柄
	wc.hInstance = hInstance;
	//指定窗口的鼠标样式
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	//设备窗口背景刷
	wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
	//唯一的窗口类名称,确保窗口类在系统中是唯一的,不会与其他窗口类冲突。
	wc.lpszClassName = L"DXRenderer";

	//注册窗口类,在这里我们可以实现一个应用只能打开一次的效果
	if (!RegisterClassExW(&wc))
	{
		MessageBox(NULL, L"窗口类注册失败", L"错误", MB_ICONERROR);
	}
	//创建窗口句柄

	HWND hwnd = CreateWindow (L"DXRenderer", L"DXRenderer", WS_OVERLAPPEDWINDOW, 			CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
	//展示窗口,nCmdShow有大量的宏标志可以使用,表示不同的打开方式
	ShowWindow(hwnd, nCmdShow);
	//一般在Show后立刻调用一次,立即更新窗口,保证良好的响应
	UpdateWindow(hwnd);
}

3.创建绘图设备接口(Device)

绘图设备接口是沟通GPU的重要接口,是对硬件层的隔离和隔离,并提供了更低级的GPU控制,以及对资源的管理,任务调度(可以创建多个命令队列以多线程方式进行绘图)。

在这一步,我们不需要将Device绑定到窗口,而是在后文通过交换链进行绑定。

//创建绘图设备
ID3D12Device* device = nullptr;
D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device));

4.创建Fence

Fence翻译为栅栏,是CPU与GPU同步的主要手段,Fence提供了跟踪GPU任务的能力。

//创建Fence
ID3D12Fence* fence = nullptr;
UINT64 fenceValue = 0; 
d3d12Device->CreateFence(fenceValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));

5.获取RTV,DSV,[CBV,SRV,UAV]描述符大小

  • RTV (渲染目标视图) : 将渲染目标与图形渲染管线相关联。它允许图形程序将渲染的结果输出到一个或多个渲染目标上。
  • DSV (深度/模板视图):通常与深度缓冲区和模板缓冲区相关联。深度缓冲区用于存储场景中各个像素的深度信息,而模板缓冲区用于存储与像素相关的模板信息。DSV允许GPU读取或写入深度和模板信息
  • CBV (常量缓冲视图) :用于将常量缓冲区与着色器绑定。常量缓冲区包含了常量数据,如变换矩阵、材质属性等,这些数据可以在渲染过程中传递给着色器,以影响渲染结果。CBV允许GPU在着色器中访问这些常量数据。
  • SRV (着色资源视图) :用于将纹理、缓冲区和其他资源与着色器绑定。它允许GPU在着色器中读取纹理数据、结构化缓冲区数据等。SRV是一种通用视图,可以与各种不同类型的资源相关联。
  • UAV (无序访问视图) :允许GPU在着色器中对缓冲区进行无序访问,通常用于实现计算着色器中的并行计算任务。UAV允许着色器读取、写入和重新排序缓冲区中的数据,而不需要显式的同步。

// 获取RTV描述符大小
UINT rtvSize = d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
// 获取DSV描述符大小
UINT dsvSize = d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
//获取CBV,SRV,UAV描述符大小
//在DX12中,这三者的描述符都存储在相同的堆,使用相同的API获取
UINT cbvSrvUavSize = d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

注意要保存这些大小,并不是一次性就丢弃。

6.检测多重采样抗锯齿(MSAA)的支持性

MSAA的原理是在渲染图像时,对每个像素位置进行多次采样。根据像素覆盖的多个采样点的值来计算最终像素的颜色。这些采样点通常位于像素中心和其周围的位置。

D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaQualityLevels;
// 根据你的渲染目标格式设置,默认是32位RGBA
msaaQualityLevels.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 
//采样数量
msaaQualityLevels.SampleCount = 4;
//无特殊标志
msaaQualityLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
//质量级别设置
msaaQualityLevels.NumQualityLevels = 0;
//检测MSAA支持,会修改NumQualityLevels的值,如果不支持则为0
HRESULT hr = d3d12Device->CheckFeatureSupport(
    D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
    &msaaQualityLevels,
    sizeof(msaaQualityLevels)
);

//根据MSAA支持来启用
if (SUCCEEDED(hr) && msaaQualityLevels.NumQualityLevels > 0) 
{
    // MSAA支持,msaaQualityLevels.NumQualityLevels表示支持的质量级别
} 
else 
{
    // 不支持MSAA
}

7.创建命令队列(Command Queue)

命令队列是从属于Device的,一个Device可以有多个命令队列(你可以创建不同的队列以负责不同类型的职责),CPU的可以通过任意线程把渲染命令添加到命令队列。

在这一部分,我们不介绍如何把绘制命令添加到命令队列里。而是在后文交换链之后再进行介绍,以拥有一个合适的基础。

//创建命令队列
ID3D12CommandQueue* commandQueue = nullptr;
//创建命令队列描述信息
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
// 指定命令队列类型为图形命令队列
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; 
// 队列优先级设为正常
queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; 
// 无特殊标志
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; 
//为绘图设备创建命令队列
d3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue));

8.创建命令分配器(Command Allocator)

在介绍命令分配器之前,我们先介绍命令列表(Command List),在DX12等图形编程API中,通常不允许直接向命令队列提交绘制命令,一般只允许向命令队列提交命令列表,在提交命令列表时,会按照命令列表中相同命令顺序为命令队列添加命令。

而命令列表的创建重用,一般情况下依赖于命令分配器,所以我们先创建一个命令分配器,并在下一个步骤中进行命令列表的创建,并对命令列表进行详细介绍。

//创建命令分配器
ID3D12CommandAllocator* commandAllocator;
HRESULT hr = d3d12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator));

9.创建命令列表(Command List)

通过命令列表,我们对低级的指令进行抽象和封装,使得功能变得更加易用

每个命令分配器都与命令列表一一对应,命令分配器为命令列表分配内存,管理资源和状态。

命令列表可以重用,具体的方式在后文解释,同样的,命令列表的提交也将在后文进行。
这些都需要交换链作为基础才能成功被绘制。

//创建命令列表
ID3D12GraphicsCommandList* commandList;
HRESULT hr = d3d12Device->CreateCommandList(
    0, // NodeMask,默认为0
    D3D12_COMMAND_LIST_TYPE_DIRECT, // 使用Direct Command List
    commandAllocator, // 命令分配器
    nullptr, // Pipeline State Object(PSO),可以稍后设置
    IID_PPV_ARGS(&commandList)
);

10.创建交换链(Swap Chain)

交换链的作用是在这一帧图像未渲染完毕时,保留上一帧的图像,等待这一帧渲染完毕后直接替换上一帧的画面。这样使得我们看到连续的画面,而不是介于两帧之间的未渲染完成的画面。
一般来说,如果不使用这种技术,将导致画面闪烁图像撕裂等问题

同时交换链内维护有缓冲区,存储渲染结果,待合适时机一起输出,同时这种缓冲区大小与Windows窗口紧密相关,自动维护合适的大小。

SwapChain有多个版本,这里以SwapChain1作为案例升级SwapChain3,Windows版本不同可能对支持的交换链API有影响。

//创建交换链3
ComPtr<IDXGISwapChain3> swapChain ;

//交换链描述符
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
//窗口大小信息
swapChainDesc.Width = width;                     // 窗口宽度
swapChainDesc.Height = height;                   // 窗口高度
//像素格式
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 像素格式
//是否启用3D展示(通常用于3D眼镜,需要硬件支持,一般false)
swapChainDesc.Stereo = false;
//不与MSAA冲突的多重采样
swapChainDesc.SampleDesc.Count = 1;              // 多重采样设置
swapChainDesc.SampleDesc.Quality = 0;
//设置后台缓冲区的用途是作为渲染目标(还可以用作着色器读取)
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
//缓冲区数量
swapChainDesc.BufferCount = bufferCount;      
//  设置渲染目标与窗口大小不匹配时的缩放模式
//DXGI_SCALING_NONE:不进行缩放
//DXGI_SCALING_STRETCH:渲染目标将被拉伸以完全填充窗口
//DXGI_SCALING_ASPECT_RATIO_STRETCH:保持渲染目标的宽高比的情况下,将其拉伸以填充窗口
swapChainDesc.Scaling = DXGI_SCALING_ASPECT_RATIO_STRETCH;
// 交换效果,定义了在每次呈现后如何处理后台缓冲区,并如何切换前台和后台缓冲区
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; 
//设置交换链如何处置透明像素 (DXGI_ALPHA_MODE_PREMULTIPLIED 或 DXGI_ALPHA_MODE_STRAIGHT)
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
//无标志
swapChainDesc.Flags = 0;

//创建交换链1(较为低级)
ComPtr<IDXGISwapChain1> swapChain1;
ThrowIfFailed(dxgiFactory->CreateSwapChainForHwnd(
    commandQueue.Get(),                       // 命令队列
    hwnd,                                     // 窗口句柄
    &swapChainDesc,                           // 交换链描述符
    nullptr,                                  // 全屏模式
    nullptr,                                  // 允许输出
    &swapChain1                               // 交换链对象
));

// 尝试升级到IDXGISwapChain3接口
ThrowIfFailed(swapChain1.As(&swapChain));

//升级成功
if(swapChain3)
{

}
//升级失败
else
{
	
}

11.创建RTV/DSV描述符堆

这里假设我们只是双重缓冲(1个显示,1个后缓冲),我们需要建立数量为2的RTV描述符。
并且我们需要一个深度缓冲描述符用于当前GPU计算使用

这里也假定交换链升级成功

//创建描述符堆的描述符,并指定属性
D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
rtvHeapDesc.NumDescriptors = 2; // 描述符数量,通常等于后台缓冲区的数量
rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; // 描述符堆类型,RTV
rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; // 无特殊标志

ComPtr<ID3D12Resource> backBuffer;
//获取缓冲区索引
UINT bufferIndex = swapChain->GetCurrentBackBufferIndex(); 
//获取后台缓冲区
HRESULT hr = swapChain->GetBuffer(bufferIndex, IID_PPV_ARGS(backBuffer.GetAddressOf()));

//创建描述符堆
ComPtr<ID3D12DescriptorHeap> rtvHeap;
HRESULT hr = device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(rtvHeap.GetAddressOf()));

//创建RTV句柄
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap->GetCPUDescriptorHandleForHeapStart();
// 假设 backBuffer 是后台缓冲区的资源对象
device->CreateRenderTargetView(backBuffer.Get(), nullptr, rtvHandle);
// 移动到下一个描述符
rtvHandle.ptr += rtvDescriptorSize; // rtvDescriptorSize 是描述符的大小


//创建DSV描述符堆的描述符
D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
dsvHeapDesc.NumDescriptors = 1; // 单个深度/模板视图
dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; // 描述符堆类型,DSV
dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; // 无特殊标志
//创建dsv描述符堆
ComPtr<ID3D12DescriptorHeap> dsvHeap;
hr = device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(dsvHeap.GetAddressOf()));
D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsvHeap->GetCPUDescriptorHandleForHeapStart();


//创建深度缓冲区资源对象 depthBuffer
UINT width = 1920; // 深度缓冲区的宽度
UINT height = 1080; // 深度缓冲区的高度
DXGI_FORMAT format = DXGI_FORMAT_D24_UNORM_S8_UINT; // 深度/模板格式
UINT sampleCount = 1; // 采样数(通常为 1,不使用多重采样)
UINT sampleQuality = 0; // 采样质量级别
//----------------------------------------------------
D3D12_RESOURCE_DESC depthDesc = {};
depthDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; // 资源维度
depthDesc.Width = width; // 宽度
depthDesc.Height = height; // 高度
depthDesc.DepthOrArraySize = 1; // 深度或数组大小(通常为 1)
depthDesc.MipLevels = 1; // Mip 层级数量
depthDesc.Format = format; // 像素格式
depthDesc.SampleDesc.Count = sampleCount; // 采样数
depthDesc.SampleDesc.Quality = sampleQuality; // 采样质量级别
depthDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // 布局类型
depthDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; // 资源标志,允许深度/模板
//深度缓冲区清除值
D3D12_CLEAR_VALUE clearValue = {};
clearValue.Format = format; // 清除值的格式必须与深度缓冲区的格式匹配
clearValue.DepthStencil.Depth = 1.0f; // 初始深度值(通常为 1.0)
clearValue.DepthStencil.Stencil = 0; // 初始模板值(通常为 0)

ComPtr<ID3D12Resource> depthBuffer; // 用于存储深度缓冲区资源
HRESULT hr = device->CreateCommittedResource(
    &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), // 堆属性
    D3D12_HEAP_FLAG_NONE, // 堆标志
    &depthDesc, // 资源描述符
    D3D12_RESOURCE_STATE_COMMON, // 初始资源状态
    &clearValue, // 清除值
    IID_PPV_ARGS(depthBuffer.GetAddressOf()) // 输出深度缓冲区资源对象
);

// 假设 depthBuffer 是深度缓冲区的资源对象
device->CreateDepthStencilView(depthBuffer.Get(), nullptr, dsvHandle);

12.设置视口

D3D12_VIEWPORT viewport = {}; // 创建视口对象
viewport.TopLeftX = 0.0f; // 视口左上角的X坐标
viewport.TopLeftY = 0.0f; // 视口左上角的Y坐标
viewport.Width = static_cast<float>(clientWidth); // 视口的宽度
viewport.Height = static_cast<float>(clientHeight); // 视口的高度
viewport.MinDepth = 0.0f; // 最小深度
viewport.MaxDepth = 1.0f; // 最大深度

//在渲染过程中,在每次渲染前,将视口的属性设置到渲染管道中的命令列表(Command List)中,以便将其传递给GPU。
commandList->RSSetViewports(1, &viewport); // 设置视口


13.提交和重用命令列表

(1)重置

//命令列表的重置是可选的
commandList->Reset(commandAllocator.Get(), nullptr);
//重置分配器是必须的
commandAllocator->Reset();

(2)提交

// 记录需要的GPU命令
commandList->SetGraphicsRootSignature(rootSignature.Get());
commandList->SetPipelineState(pipelineState.Get());
commandList->SetGraphicsRootDescriptorTable(0, descriptorHeap.GetGPUDescriptorHandleForHeapStart());

// 执行绘制操作
commandList->DrawIndexedInstanced(/*参数*/);

//记录命令之后需要关闭
commandList->Close();
//commandQueue 是命令队列对象,ppCommandLists 是指向命令列表指针的数组。
commandQueue->ExecuteCommandLists(1, CommandListType, ppCommandLists);


14.可运行时调整的设定

  • 用来渲染到屏幕上的RTV本身的格式(也就是说我们如果需要更改渲染贴图的大小,只需要在运行时直接更改RTV描述符并且替换掉原本的RTV)

  • Swap Chain 也可以在运行时更改设定,比如说运行时启用/停用MSAA

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

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

相关文章

操作系统基本概念

目录 一、基本概述 二、操作系统的特点 &#xff08;一&#xff09;并发性&#xff08;实质是微观的串行、宏观的并行&#xff09; 1. 对比看&#xff1a;并行性 2. 单核CPU和多核CPU &#xff08;二&#xff09;共享性 &#xff08;三&#xff09;虚拟性 &#xff08;…

数字大时代 韧性向未来 | 2023数字韧性保险峰会圆满召开

2023年9月7日&#xff0c;由同创永益主办的2023数字韧性保险峰会在上海成功举办。ITSS DCMG组长肖建一等数十位保险行业专家、企业代表出席本次会议&#xff0c;同创永益与多方共同探讨保险行业数字化发展与数字韧性体系建设&#xff0c;共话行业数智化未来。 会议伊始&#xf…

Qt(day1)

思维导图 Qt实现第一个web的基础页面 #include "mywnd.h" #include "ui_mywnd.h" #include<QLabel> #include<QLineEdit> #include<qpushbutton.h>MyWnd::MyWnd(QWidget *parent): QMainWindow(parent), ui(new Ui::MyWnd) {ui->set…

【SpringSecurity】三更草堂项目案例分析3 - 鉴权操作

目录 鉴权RBAC 模型前置准备redis 实现角色权限获取 鉴权 RBAC 模型 参考 CSDN 文章 RBAC&#xff08;Role-Based Access Control&#xff09;&#xff0c;基于角色的访问控制&#xff0c;现在主流的权限管理系统的权限设计都是 RBAC 模型 所谓的 RBAC 模型&#xff0c;可以理…

农民朋友有福利啦!建行江门市分行“裕农通+农资结算”平台正式上线

随着广东广圣农业发展有限公司办公室内的裕农通“智慧眼”结算机“叮”的一声到账提醒&#xff0c;标志着全国首个“裕农通农资结算“平台的成功上线&#xff0c;也标志着建行广东省江门市分行的裕农通业务又迈上了一个新的台阶。 广东广圣农业发展有限公司&#xff08;以下简…

【业务功能118】微服务-springcloud-springboot-Kubernetes集群-k8s集群-KubeSphere-OpenELB部署及应用

OpenELB部署及应用 一、OpenELB介绍 网址&#xff1a; openelb.io OpenELB 是一个开源的云原生负载均衡器实现&#xff0c;可以在基于裸金属服务器、边缘以及虚拟化的 Kubernetes 环境中使用 LoadBalancer 类型的 Service 对外暴露服务。OpenELB 项目最初由 KubeSphere 社区发…

Iterator设计模式

目录 1、示例 1.1 Aggregate接口 1.2 Iterator接口 1.3 Book类 1.4 BookShelf类 1.6 BookShelfIterator 类 1.7 Main类 2、解释Iterator模式中的角色 2.1 Iterator模式的存在意义 2.2 抽象类和接口 2.3 Aggregate 和 Iterator的对应 2.4 容易弄错"下一个"…

【AI视野·今日CV 计算机视觉论文速览 第248期】Mon, 18 Sep 2023

AI视野今日CS.CV 计算机视觉论文速览 Mon, 18 Sep 2023 Totally 83 papers &#x1f449;上期速览✈更多精彩请移步主页 Interesting: &#x1f4da;Robust e-NeRF,处理高速且大噪声事件相机流的NERF模型。(from NUS新加坡国立) 稀疏噪声事件与稠密事件数据的区别&#xff1a;…

0918hw

字节序概念&#xff1a; 字节序是不同cpu主机&#xff0c;存储多字节整数序列的存储方式 1.大端存储&#xff1a;低字节序存储在地址高位 2.小端存储&#xff1a;低字节序存储在地址低位 3.无论大小端存储&#xff0c;首地址都是低地址&#xff0c;数据都是先读取低地址&am…

Word 文档转换 PDF、图片

工作有需要 Word 文档转换 PDF、图片 的场景&#xff0c;我们来看看 Java 开发中怎么解决这个问题的。 Word 转 PDF Word 转 PDF 分为商用 Aspose 方案和开源 Apache POIiText 方案。 Aspose 方案 这种方式在目前来看应该是最好的&#xff0c;无论是转换的速度还是成功的概…

DuckDB 的 AsOf 连接:模糊时态查找

概要 DuckDB 支持 AsOf Joins——一种匹配附近值的方法。 它们对于搜索事件表以进行时间分析特别有用。 有想要连接的时间序列数据但时间戳不太匹配&#xff1f; 或者想使用另一个表中的时间查找随时间变化的值&#xff1f; 最终是否编写了复杂&#xff08;且缓慢&#xff09;…

【uniapp】Dcloud的uni手机号一键登录,具体实现及踩过的坑,调用uniCloud.getPhoneNumber(),uni.login()等

一键登录Dcloud官网请戳这里&#xff0c;感兴趣的可以看看官网&#xff0c;有很详细的示例&#xff0c;选择App一键登录&#xff0c;可以看到一些常用的概述 比如&#xff1a; 1、调用uni.login就能弹出一键登录的页面 2、一键登录的流程&#xff0c;可以选择先预登录uni.prelo…

mybatis学习记录(四)-----MyBatis核心配置文件详解

目录 MyBatis核心配置文件详解 4.1 environment 4.2 transactionManager 4.3 dataSource 4.4 properties 4.5 mapper MyBatis核心配置文件详解 mybatis-config.xml : <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE configurationPUB…

安防视频监控平台EasyNVR无法控制云台,该如何解决?

TSINGSEE青犀视频安防监控平台EasyNVR可支持设备通过RTSP/Onvif协议接入&#xff0c;并能对接入的视频流进行处理与多端分发&#xff0c;包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等多种格式。在智慧安防等视频监控场景中&#xff0c;EasyNVR可提供视频实时监控直播、云端…

高云FPGA系列教程(6):ARM定时器使用

文章目录 [toc]1. ARM定时器简介2. FPGA配置3. 常用函数4. MCU程序设计5. 工程下载 本文是高云FPGA系列教程的第6篇文章。 本篇文章介绍片上ARM Cortex-M3硬核处理器定时器外设的使用&#xff0c;演示定时器溢出中断的配置方法&#xff0c;基于TangNano 4K开发板。 参考文档&a…

虚拟机(VM)监控工具

什么是虚拟机&#xff08;VM&#xff09;监控 虚拟机监控是监视在虚拟化环境中创建的各个虚拟机和 VM 的过程&#xff0c;使用虚拟机监控软件&#xff0c;您可以查看可用性状态、性能统计信息并管理连接到主机的虚拟机及其相应的来宾虚拟机。 虚拟机监控有什么作用 在主机上…

Python:函数和代码复用

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 &#x1f447; &#x1f447; &#x1f447; 更多精彩机密、教程&#xff0c;尽在下方&#xff0c;赶紧点击了解吧~ python源码、视频教程、插件安装教程、资料我都准备好了&#xff0c;直接在文末名片自取就可 1、关于递归函…

通义千问杀疯了!首发Qwen-VL-Chat模型的A卡本地部署教程

阿里云最新开源的通义千问视觉语言模型&#xff1a;Qwen-VL Qwen-VL 是一款支持中英文等多种语言的视觉语言&#xff08;Vision Language&#xff0c;VL&#xff09;模型&#xff0c;相较于此前的 VL 模型&#xff0c;其除了具备基本的图文识别、描述、问答及对话能力之外&…

明星翻包视频的崛起:探究背后的驱动力

近年来&#xff0c;社交媒体上涌现出越来越多的明星翻包视频&#xff0c;成为广大粉丝和观众们的追捧对象。这个趋势的背后是什么原因&#xff1f;为什么现今的明星都热衷于分享自己的私人物品和生活片段&#xff1f; 在明星翻包视频的制作和推广过程中&#xff0c;媒介易作为专…

【CSP认证考试】202303-1:田地丈量解题思路+代码

问题描述 西西艾弗岛上散落着 n 块田地。每块田地可视为平面直角坐标系下的一块矩形区域&#xff0c;由左下角坐标 (x1,y1) 和右上角坐标 (x2,y2) 唯一确定&#xff0c;且满足 x1<x2、y1<y2。这 n 块田地中&#xff0c;任意两块的交集面积均为 0&#xff0c;仅边界处可能…