d3d12 超大图片渲染 代码
时间: 2023-07-09 21:36:24 浏览: 239
只需要用一张图片素材文档选择器.zip
下面是使用DirectX 12渲染超大图片的基本代码:
```cpp
#include <d3d12.h>
#include <dxgi1_4.h>
#include <DirectXMath.h>
#include <DirectXTex.h>
#include <wrl/client.h>
using Microsoft::WRL::ComPtr;
// 渲染窗口大小
const UINT WindowWidth = 800;
const UINT WindowHeight = 600;
// 超大图片大小
const UINT ImageWidth = 10000;
const UINT ImageHeight = 10000;
// 超大图片文件名
const wchar_t* ImageFilename = L"UltraLargeImage.jpg";
// 全局变量
ComPtr<ID3D12Device> g_Device;
ComPtr<IDXGISwapChain3> g_SwapChain;
ComPtr<ID3D12CommandQueue> g_CommandQueue;
ComPtr<ID3D12CommandAllocator> g_CommandAllocator;
ComPtr<ID3D12GraphicsCommandList> g_CommandList;
ComPtr<ID3D12Resource> g_BackBuffer[2];
ComPtr<ID3D12Fence> g_Fence;
UINT64 g_FenceValue = 0;
HANDLE g_FenceEvent;
// 初始化设备、命令队列等
bool InitializeDevice()
{
// 创建设备
HRESULT hr = D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&g_Device));
if (FAILED(hr))
return false;
// 创建命令队列
D3D12_COMMAND_QUEUE_DESC commandQueueDesc = {};
commandQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
commandQueueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
commandQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
commandQueueDesc.NodeMask = 0;
hr = g_Device->CreateCommandQueue(&commandQueueDesc, IID_PPV_ARGS(&g_CommandQueue));
if (FAILED(hr))
return false;
// 创建交换链
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.Width = WindowWidth;
swapChainDesc.Height = WindowHeight;
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
ComPtr<IDXGIFactory4> dxgiFactory;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));
if (FAILED(hr))
return false;
hr = dxgiFactory->CreateSwapChainForHwnd(g_CommandQueue.Get(), GetForegroundWindow(), &swapChainDesc, nullptr, nullptr, &g_SwapChain);
if (FAILED(hr))
return false;
// 创建命令分配器、命令列表
hr = g_Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&g_CommandAllocator));
if (FAILED(hr))
return false;
hr = g_Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, g_CommandAllocator.Get(), nullptr, IID_PPV_ARGS(&g_CommandList));
if (FAILED(hr))
return false;
// 创建RTV
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(g_Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV), 0);
for (UINT i = 0; i < 2; i++)
{
hr = g_SwapChain->GetBuffer(i, IID_PPV_ARGS(&g_BackBuffer[i]));
if (FAILED(hr))
return false;
g_Device->CreateRenderTargetView(g_BackBuffer[i].Get(), nullptr, rtvHandle);
rtvHandle.Offset(1, g_Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV));
}
// 创建围栏
hr = g_Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&g_Fence));
if (FAILED(hr))
return false;
g_FenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (g_FenceEvent == nullptr)
return false;
return true;
}
// 加载超大图片
ComPtr<ID3D12Resource> LoadImage()
{
// 加载图片
std::unique_ptr<DirectX::ScratchImage> image(new DirectX::ScratchImage());
HRESULT hr = DirectX::LoadFromWICFile(ImageFilename, DirectX::WIC_FLAGS_NONE, nullptr, *image);
if (FAILED(hr))
return nullptr;
// 创建纹理资源
ComPtr<ID3D12Resource> texture;
D3D12_RESOURCE_DESC textureDesc = {};
textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
textureDesc.Alignment = 0;
textureDesc.Width = ImageWidth;
textureDesc.Height = ImageHeight;
textureDesc.DepthOrArraySize = 1;
textureDesc.MipLevels = 1;
textureDesc.Format = image->GetMetadata().format;
textureDesc.SampleDesc.Count = 1;
textureDesc.SampleDesc.Quality = 0;
textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
hr = g_Device->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &textureDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&texture));
if (FAILED(hr))
return nullptr;
// 上传图片数据
const DirectX::Image* imageData = image->GetImage(0, 0, 0);
D3D12_SUBRESOURCE_DATA textureData = {};
textureData.pData = imageData->pixels;
textureData.RowPitch = imageData->rowPitch;
textureData.SlicePitch = imageData->slicePitch;
UpdateSubresources(g_CommandList.Get(), texture.Get(), g_BackBuffer[0].Get(), 0, 0, 1, &textureData);
// 转换资源状态
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(texture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
g_CommandList->ResourceBarrier(1, &barrier);
return texture;
}
// 渲染函数
void Render()
{
// 等待上一帧完成
const UINT currentBackBufferIndex = g_SwapChain->GetCurrentBackBufferIndex();
if (g_Fence->GetCompletedValue() < g_FenceValue)
{
hr = g_Fence->SetEventOnCompletion(g_FenceValue, g_FenceEvent);
if (FAILED(hr))
return;
WaitForSingleObject(g_FenceEvent, INFINITE);
}
// 开始渲染
g_CommandAllocator->Reset();
g_CommandList->Reset(g_CommandAllocator.Get(), nullptr);
// 设置渲染目标
CD3DX12_RESOURCE_BARRIER barrierToRenderTarget = CD3DX12_RESOURCE_BARRIER::Transition(g_BackBuffer[currentBackBufferIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
g_CommandList->ResourceBarrier(1, &barrierToRenderTarget);
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(g_Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV), currentBackBufferIndex);
g_CommandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
// 清空渲染目标
const float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
g_CommandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
// 绘制超大图片
// ...
// 结束渲染
CD3DX12_RESOURCE_BARRIER barrierToPresent = CD3DX12_RESOURCE_BARRIER::Transition(g_BackBuffer[currentBackBufferIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
g_CommandList->ResourceBarrier(1, &barrierToPresent);
g_CommandList->Close();
// 提交命令列表
ID3D12CommandList* commandLists[] = { g_CommandList.Get() };
g_CommandQueue->ExecuteCommandLists(_countof(commandLists), commandLists);
// 信号围栏
g_FenceValue++;
hr = g_CommandQueue->Signal(g_Fence.Get(), g_FenceValue);
if (FAILED(hr))
return;
// 呈现画面
g_SwapChain->Present(1, 0);
}
// 程序入口
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// 初始化窗口等
// ...
// 初始化设备、命令队列等
if (!InitializeDevice())
return -1;
// 加载超大图片
ComPtr<ID3D12Resource> texture = LoadImage();
if (texture == nullptr)
return -1;
// 进入消息循环
// ...
}
```
其中,`LoadImage`函数用于加载超大图片,返回一个纹理资源。在绘制超大图片时,可以使用多次绘制来分批渲染,或者使用视口和裁剪矩形来渲染部分区域,以避免一次渲染过多数据。
阅读全文