[C++] 纯文本查看 复制代码
#include <Windows.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <dxgi.h>
#include <DirectXMath.h>
enum class PixelFormat {
NV12,
YUY2,
RGBA,
BGRA
};
struct VertexPosTex
{
XMFLOAT3 pos;
XMFLOAT2 tex;
static const D3D11_INPUT_ELEMENT_DESC inputLayout[2];
};
const D3D11_INPUT_ELEMENT_DESC VertexPosTex::inputLayout[2] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
// 窗口过程函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_CLOSE || message == WM_DESTROY)
{
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
// 创建窗口
HWND CreateMainWindow(HINSTANCE hInstance, int nCmdShow, int width, int height)
{
WNDCLASSEX windowClass = { 0 };
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WndProc;
windowClass.hInstance = hInstance;
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.lpszClassName = L"D3D11Class";
if (!RegisterClassEx(&windowClass))
{
MessageBox(NULL, L"注册窗口类失败", L"错误", MB_OK | MB_ICONERROR);
return NULL;
}
RECT windowRect = { 0, 0, width, height };
AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE);
HWND hwnd = CreateWindow(
L"D3D11Class",
L"D3D11 窗口",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
windowRect.right - windowRect.left,
windowRect.bottom - windowRect.top,
NULL,
NULL,
hInstance,
NULL
);
if (!hwnd)
{
MessageBox(NULL, L"创建窗口失败", L"错误", MB_OK | MB_ICONERROR);
return NULL;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
return hwnd;
}
class D3D11Renderer
{
public:
D3D11Renderer(PixelFormat format)
: device(nullptr), context(nullptr), swapChain(nullptr),
vertexShader(nullptr), pixelShader(nullptr), inputLayout(nullptr),
samplerState(nullptr), vertexBuffer(nullptr),
texture(nullptr), textureView(nullptr),
renderTargetView(nullptr), pixelFormat(format) {
}
~D3D11Renderer()
{
ReleaseResources();
}
bool Initialize(HWND hwnd, int width, int height)
{
if (!CreateD3D11DeviceAndSwapChain(hwnd, &device, &context, &swapChain, width, height))
{
return false;
}
if (!CreateShadersAndInputLayout(device, &vertexShader, &pixelShader, &inputLayout))
{
ReleaseResources();
return false;
}
if (!CreateSamplerState(device, &samplerState))
{
ReleaseResources();
return false;
}
if (!CreateVertexBuffer(device, &vertexBuffer))
{
ReleaseResources();
return false;
}
if (!CreateTextureAndSRV(device, &texture, &textureView, width, height))
{
ReleaseResources();
return false;
}
if (!CreateRenderTargetView(device, swapChain, &renderTargetView))
{
ReleaseResources();
return false;
}
SetRenderStates(context, vertexShader, pixelShader, inputLayout, vertexBuffer, samplerState, textureView, renderTargetView, width, height);
return true;
}
bool UploadData(uint8_t* pSysData, int dataSize, int texWidth, int texHeight)
{
return UploadDataToGPU(context, texture, pSysData, dataSize, texWidth, texHeight);
}
bool Render()
{
return RenderFrame(context, renderTargetView, swapChain);
}
private:
ID3D11Device* device;
ID3D11DeviceContext* context;
IDXGISwapChain* swapChain;
ID3D11VertexShader* vertexShader;
ID3D11PixelShader* pixelShader;
ID3D11InputLayout* inputLayout;
ID3D11SamplerState* samplerState;
ID3D11Buffer* vertexBuffer;
ID3D11Texture2D* texture;
ID3D11ShaderResourceView* textureView;
ID3D11RenderTargetView* renderTargetView;
PixelFormat pixelFormat;
// 创建D3D11设备、上下文和交换链
bool CreateD3D11DeviceAndSwapChain(HWND hwnd, ID3D11Device** device, ID3D11DeviceContext** context, IDXGISwapChain** swapChain, int width, int height)
{
HRESULT hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, device, NULL, context);
if (FAILED(hr))
{
MessageBox(NULL, L"创建D3D11设备失败", L"错误", MB_OK | MB_ICONERROR);
return false;
}
IDXGIDevice* dxgiDevice;
hr = (*device)->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
if (FAILED(hr))
{
MessageBox(NULL, L"获取IDXGIDevice接口失败", L"错误", MB_OK | MB_ICONERROR);
(*device)->Release();
return false;
}
IDXGIAdapter* dxgiAdapter;
hr = dxgiDevice->GetAdapter(&dxgiAdapter);
if (FAILED(hr))
{
MessageBox(NULL, L"获取IDXGIAdapter接口失败", L"错误", MB_OK | MB_ICONERROR);
dxgiDevice->Release();
(*device)->Release();
return false;
}
IDXGIFactory* dxgiFactory;
hr = dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory);
if (FAILED(hr))
{
MessageBox(NULL, L"获取IDXGIFactory接口失败", L"错误", MB_OK | MB_ICONERROR);
dxgiAdapter->Release();
dxgiDevice->Release();
(*device)->Release();
return false;
}
DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
swapChainDesc.BufferCount = 2;
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.OutputWindow = hwnd;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.Windowed = TRUE;
hr = dxgiFactory->CreateSwapChain(*device, &swapChainDesc, swapChain);
if (FAILED(hr))
{
MessageBox(NULL, L"创建交换链失败", L"错误", MB_OK | MB_ICONERROR);
dxgiFactory->Release();
dxgiAdapter->Release();
dxgiDevice->Release();
(*device)->Release();
return false;
}
dxgiFactory->Release();
dxgiAdapter->Release();
dxgiDevice->Release();
return true;
}
// 创建着色器和输入布局
bool CreateShadersAndInputLayout(ID3D11Device* device, ID3D11VertexShader** vertexShader, ID3D11PixelShader** pixelShader, ID3D11InputLayout** inputLayout)
{
const char* vertexShaderCode =
"struct VertexPosIn"
"{"
" float3 PosL : POSITION;"
" float2 Tex : TEXCOORD;"
"};"
"struct VertexPosOut"
"{"
" float4 PosH : SV_POSITION;"
" float2 Tex : TEXCOORD;"
"};"
"VertexPosOut main(VertexPosIn vIn)"
"{"
" VertexPosOut vOut;"
" vOut.PosH=float4(vIn.PosL,1.0f);"
" vOut.Tex=vIn.Tex;"
" return vOut;"
"}";
ID3DBlob* vsBlob = NULL;
HRESULT hr = D3DCompile(vertexShaderCode, strlen(vertexShaderCode), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vsBlob, NULL);
if (FAILED(hr))
{
MessageBox(NULL, L"编译顶点着色器失败", L"错误", MB_OK | MB_ICONERROR);
return false;
}
hr = device->CreateVertexShader(vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), NULL, vertexShader);
if (FAILED(hr))
{
MessageBox(NULL, L"创建顶点着色器失败", L"错误", MB_OK | MB_ICONERROR);
vsBlob->Release();
return false;
}
hr = device->CreateInputLayout(VertexPosTex::inputLayout, ARRAYSIZE(VertexPosTex::inputLayout),
vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), inputLayout);
if (FAILED(hr))
{
MessageBox(NULL, L"创建输入布局失败", L"错误", MB_OK | MB_ICONERROR);
(*vertexShader)->Release();
vsBlob->Release();
return false;
}
vsBlob->Release();
const char* pixelShaderCode;
switch (pixelFormat) {
case PixelFormat::NV12:
pixelShaderCode =
"Texture2D yTexture : register(t0);"
"Texture2D uvTexture : register(t1);"
"SamplerState samplerState : register(s0);"
"float4 main(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target"
"{"
" float y = yTexture.Sample(samplerState, uv).r;"
" float u = uvTexture.Sample(samplerState, uv).r - 0.5f;"
" float v = uvTexture.Sample(samplerState, uv).g - 0.5f;"
" float3 yuv = float3(y, u, v);"
" float3 rgb = mul(float3x3(1.0, 0.0, 1.13983, 1.0, -0.39465, -0.58060, 1.0, 2.03211, 0.0),yuv);"
" return float4(rgb, 1.0);"
"}";
break;
case PixelFormat::YUY2:
pixelShaderCode =
"Texture2D yuy2Texture : register(t0);"
"SamplerState samplerState : register(s0);"
"float4 main(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target"
"{"
" float4 yuy2 = yuy2Texture.Sample(samplerState, uv);"
" float y0 = yuy2.r;"
" float u = yuy2.g - 0.5f;"
" float y1 = yuy2.b;"
" float v = yuy2.a - 0.5f;"
" float2 uvOffset = frac(uv * float2(2.0f, 1.0f)); "
" float y = lerp(y0, y1, uvOffset.x);"
" float3 yuv = float3(y, u, v);"
" float3 rgb = mul(float3x3(1.0, 0.0, 1.13983, 1.0, -0.39465, -0.58060, 1.0, 2.03211, 0.0),yuv);"
" return float4(rgb, 1.0);"
"}";
break;
case PixelFormat::RGBA:
pixelShaderCode =
"Texture2D rgbaTexture : register(t0);"
"SamplerState samplerState : register(s0);"
"float4 main(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target"
"{"
" return rgbaTexture.Sample(samplerState, uv);"
"}";
break;
case PixelFormat::BGRA:
pixelShaderCode =
"Texture2D rgbaTexture : register(t0);"
"SamplerState samplerState : register(s0);"
"float4 main(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target"
"{"
" float4 color = rgbaTexture.Sample(samplerState, uv);"
" // 交换红色和蓝色通道的值"
" float temp = color.r;"
" color.r = color.b;"
" color.b = temp;"
" return color;"
"}";
default:
MessageBox(NULL, L"不支持的像素格式", L"错误", MB_OK | MB_ICONERROR);
return false;
}
ID3DBlob* psBlob = NULL;
hr = D3DCompile(pixelShaderCode, strlen(pixelShaderCode), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &psBlob, NULL);
if (FAILED(hr))
{
MessageBox(NULL, L"编译像素着色器失败", L"错误", MB_OK | MB_ICONERROR);
return false;
}
hr = device->CreatePixelShader(psBlob->GetBufferPointer(), psBlob->GetBufferSize(), NULL, pixelShader);
if (FAILED(hr))
{
MessageBox(NULL, L"创建像素着色器失败", L"错误", MB_OK | MB_ICONERROR);
psBlob->Release();
return false;
}
psBlob->Release();
return true;
}
// 创建采样状态
bool CreateSamplerState(ID3D11Device* device, ID3D11SamplerState** samplerState)
{
D3D11_SAMPLER_DESC sampDesc;
ZeroMemory(&sampDesc, sizeof(sampDesc));
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
HRESULT hr = device->CreateSamplerState(&sampDesc, samplerState);
if (FAILED(hr))
{
MessageBox(NULL, L"创建采样状态失败", L"错误", MB_OK | MB_ICONERROR);
return false;
}
return true;
}
// 创建顶点缓冲区
bool CreateVertexBuffer(ID3D11Device* device, ID3D11Buffer** vertexBuffer)
{
VertexPosTex quadVertices[] =
{
{ DirectX::XMFLOAT3(-1.0f, 1.0f, 0.0f), DirectX::XMFLOAT2(0.0f, 0.0f) },
{ DirectX::XMFLOAT3(1.0f, 1.0f, 0.0f), DirectX::XMFLOAT2(1.0f, 0.0f) },
{ DirectX::XMFLOAT3(-1.0f, -1.0f, 0.0f), DirectX::XMFLOAT2(0.0f, 1.0f) },
{ DirectX::XMFLOAT3(1.0f, -1.0f, 0.0f), DirectX::XMFLOAT2(1.0f, 1.0f) }
};
D3D11_BUFFER_DESC vertexBufferDesc = {};
vertexBufferDesc.ByteWidth = sizeof(quadVertices);
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA vertexData = {};
vertexData.pSysMem = quadVertices;
HRESULT hr = device->CreateBuffer(&vertexBufferDesc, &vertexData, vertexBuffer);
if (FAILED(hr))
{
MessageBox(NULL, L"创建顶点缓冲区失败", L"错误", MB_OK | MB_ICONERROR);
return false;
}
return true;
}
// 创建纹理和着色器资源视图
bool CreateTextureAndSRV(ID3D11Device* device, ID3D11Texture2D** texture, ID3D11ShaderResourceView** textureView, int width, int height)
{
D3D11_TEXTURE2D_DESC textureDesc = {};
textureDesc.Width = width;
textureDesc.Height = height;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.SampleDesc.Count = 1;
textureDesc.Usage = D3D11_USAGE_DYNAMIC;
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = textureDesc.MipLevels;
switch (pixelFormat) {
case PixelFormat::NV12:
textureDesc.Format = DXGI_FORMAT_NV12;
srvDesc.Format = DXGI_FORMAT_R8_UNORM;
break;
case PixelFormat::YUY2:
textureDesc.Format = DXGI_FORMAT_YUY2;
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
break;
case PixelFormat::RGBA:
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
break;
default:
MessageBox(NULL, L"不支持的像素格式", L"错误", MB_OK | MB_ICONERROR);
return false;
}
HRESULT hr = device->CreateTexture2D(&textureDesc, nullptr, texture);
if (FAILED(hr))
{
MessageBox(NULL, L"创建纹理失败", L"错误", MB_OK | MB_ICONERROR);
return false;
}
hr = device->CreateShaderResourceView(*texture, &srvDesc, textureView);
if (FAILED(hr))
{
MessageBox(NULL, L"创建着色器资源视图失败", L"错误", MB_OK | MB_ICONERROR);
(*texture)->Release();
return false;
}
return true;
}
// 创建渲染目标视图
bool CreateRenderTargetView(ID3D11Device* device, IDXGISwapChain* swapChain, ID3D11RenderTargetView** renderTargetView)
{
ID3D11Texture2D* backBuffer;
HRESULT hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backBuffer);
if (FAILED(hr))
{
MessageBox(NULL, L"获取后台缓冲区失败", L"错误", MB_OK | MB_ICONERROR);
return false;
}
hr = device->CreateRenderTargetView(backBuffer, NULL, renderTargetView);
if (FAILED(hr))
{
MessageBox(NULL, L"创建渲染目标视图失败", L"错误", MB_OK | MB_ICONERROR);
backBuffer->Release();
return false;
}
backBuffer->Release();
return true;
}
// 设置渲染状态
void SetRenderStates(ID3D11DeviceContext* context, ID3D11VertexShader* vertexShader,
ID3D11PixelShader* pixelShader, ID3D11InputLayout* inputLayout, ID3D11Buffer* vertexBuffer,
ID3D11SamplerState* samplerState, ID3D11ShaderResourceView* textureView, ID3D11RenderTargetView* renderTargetView,
int width, int height)
{
context->OMSetRenderTargets(1, &renderTargetView, NULL);
D3D11_VIEWPORT viewport = { 0, 0, (float)width, (float)height, 0, 1 };
context->RSSetViewports(1, &viewport);
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
context->IASetInputLayout(inputLayout);
UINT stride = sizeof(VertexPosTex);
UINT offset = 0;
context->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
context->VSSetShader(vertexShader, NULL, 0);
context->PSSetShader(pixelShader, NULL, 0);
context->PSSetSamplers(0, 1, &samplerState);
context->PSSetShaderResources(0, 1, &textureView);
}
// 上传数据到GPU
bool UploadDataToGPU(ID3D11DeviceContext* context, ID3D11Texture2D* texture, uint8_t* pSysData, int dataSize, int texWidth, int texHeight)
{
D3D11_MAPPED_SUBRESOURCE mappedData;
HRESULT hr = context->Map(texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedData);
if (FAILED(hr))
{
MessageBox(NULL, L"映射纹理失败", L"错误", MB_OK | MB_ICONERROR);
return false;
}
byte* pDest = (BYTE*)mappedData.pData;
int stride = mappedData.RowPitch;
switch (pixelFormat) {
case PixelFormat::NV12:
if (dataSize != texWidth * (texHeight + texHeight / 2)) {
MessageBox(NULL, L"NV12数据长度不匹配", L"错误", MB_OK | MB_ICONERROR);
context->Unmap(texture, 0);
return false;
}
for (int i = 0; i < texHeight; i++)
{
memcpy(pDest + i * stride, pSysData + i * texWidth, texWidth);
}
for (int i = 0; i < texHeight / 2; i++)
{
memcpy(pDest + (texHeight + i) * stride, pSysData + texWidth * texHeight + i * texWidth, texWidth);
}
break;
case PixelFormat::YUY2:
if (dataSize != texWidth * texHeight * 2) {
MessageBox(NULL, L"YUY2数据长度不匹配", L"错误", MB_OK | MB_ICONERROR);
context->Unmap(texture, 0);
return false;
}
memcpy(pDest, pSysData, dataSize);
break;
case PixelFormat::RGBA:
if (dataSize != texWidth * texHeight * 4) {
MessageBox(NULL, L"RGBA数据长度不匹配", L"错误", MB_OK | MB_ICONERROR);
context->Unmap(texture, 0);
return false;
}
for (int i = 0; i < texHeight; i++)
{
memcpy(pDest + i * stride, pSysData + i * texWidth * 4, texWidth * 4);
}
break;
default:
MessageBox(NULL, L"不支持的像素格式", L"错误", MB_OK | MB_ICONERROR);
context->Unmap(texture, 0);
return false;
}
context->Unmap(texture, 0);
return true;
}
// 渲染帧
bool RenderFrame(ID3D11DeviceContext* context, ID3D11RenderTargetView* renderTargetView, IDXGISwapChain* swapChain)
{
// 定义清屏颜色,分别对应RGBA值
float clearColor[4] = { 0.0f, 0.2f, 0.4f, 1.0f };
context->ClearRenderTargetView(renderTargetView, clearColor);
// 使用指定的清屏颜色清除渲染目标视图
context->Draw(4, 0);
HRESULT hr = swapChain->Present(1, 0);
if (FAILED(hr))
{
MessageBox(NULL, L"交换链展示失败", L"错误", MB_OK | MB_ICONERROR);
return false;
}
return true;
}
// 释放资源
void ReleaseResources()
{
if (renderTargetView) renderTargetView->Release();
if (textureView) textureView->Release();
if (texture) texture->Release();
if (vertexBuffer) vertexBuffer->Release();
if (samplerState) samplerState->Release();
if (inputLayout) inputLayout->Release();
if (pixelShader) pixelShader->Release();
if (vertexShader) vertexShader->Release();
if (swapChain) swapChain->Release();
if (context) context->Release();
if (device) device->Release();
}
};
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
int width = 800;
int height = 600;
PixelFormat format = PixelFormat::RGBA; // 可根据需要修改格式
HWND hwnd = CreateMainWindow(hInstance, iCmdShow, width, height);
if (!hwnd)
{
return 1;
}
D3D11Renderer renderer(format);
if (!renderer.Initialize(hwnd, width, height))
{
return 1;
}
// 模拟绿色数据
uint8_t* pSysData = new uint8_t[width * height * 4];
for (int i = 0; i < width * height; ++i) {
pSysData[i * 4 + 0] = 0; // 红色通道
pSysData[i * 4 + 1] = 0; // 绿色通道
pSysData[i * 4 + 2] = 255; // 蓝色通道
pSysData[i * 4 + 3] = 255; // 透明度通道
}
int dataSize = width * height * 4;
MSG msg = { 0 };
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
if (!renderer.UploadData(pSysData, dataSize, width, height))
{
break;
}
if (!renderer.Render())
{
break;
}
}
}
delete[] pSysData;
return (int)msg.wParam;
}