D3D11延迟上下文(Deferred Context)
DirectX 11引入了延迟上下文(Deferred Context) 和命令列表(Command List)机制,允许在多线程CPU环境中并行录制渲染命令
Deferred Context是辅助线程使用的上下文,仅用来录制Command List,没有提交功能,其录制的Command List要通过Immediate Context(渲染线程上下文)提交到GPU端执行

D3D11 Deferred Context多线程录制示例
初始化和游戏主循环(main.cpp)
// ============================================================================= // main.cpp // 程序入口:创建 Win32 窗口、初始化 D3D11 设备与渲染器,运行消息/渲染循环。 // // 本示例演示 D3D11 "多 Deferred Context 多线程录制 + Immediate Context 回放": // - 主线程创建所有资源(设备、交换链、几何、着色器、状态、常量缓冲) // - 每帧由多个工作线程各自用一个 Deferred Context 并行录制绘制命令 // - 每个线程 FinishCommandList 生成 ID3D11CommandList // - 主线程在 Immediate Context 上按顺序 ExecuteCommandList 回放后 Present // ============================================================================= #include <windows.h> #include <chrono> #include <string> #include "DeviceResources.h" #include "DeferredRenderer.h" // ---- 可调参数:线程(Deferred Context)数量与立方体数量 ---- static const UINT kThreadCount = 4; // Deferred Context / 工作线程数量 static const UINT kCubeCount = 8; // 场景立方体数量(平均分配到各线程) static const wchar_t* kWindowClass = L"D3D11DeferredContextWndClass"; static const wchar_t* kWindowTitle = L"D3D11 多 Deferred Context 多线程录制示例"; namespace { DeviceResources g_device; DeferredRenderer g_renderer; bool g_initialized = false; } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_SIZE: if (g_initialized && wParam != SIZE_MINIMIZED) { UINT w = LOWORD(lParam); UINT h = HIWORD(lParam); g_device.Resize(w, h); } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; case WM_KEYDOWN: if (wParam == VK_ESCAPE) { PostQuitMessage(0); } return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int nCmdShow) { // ---- 注册并创建窗口 ---- WNDCLASSEX wc = {}; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(nullptr, IDC_ARROW); wc.lpszClassName = kWindowClass; RegisterClassEx(&wc); const UINT width = 1280; const UINT height = 720; RECT rc = { 0, 0, static_cast<LONG>(width), static_cast<LONG>(height) }; AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); HWND hwnd = CreateWindow( kWindowClass, kWindowTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, nullptr, nullptr, hInstance, nullptr); if (!hwnd) { MessageBox(nullptr, L"窗口创建失败", L"错误", MB_ICONERROR); return -1; } // ---- 初始化 D3D11 与渲染器 ---- try { g_device.Initialize(hwnd, width, height); g_renderer.Initialize(&g_device, kThreadCount, kCubeCount); g_initialized = true; } catch (const std::exception& e) { std::string msg = e.what(); MessageBoxA(nullptr, msg.c_str(), "初始化失败", MB_ICONERROR); return -1; } ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); // ---- 主循环:消息处理 + 每帧渲染 ---- using clock = std::chrono::high_resolution_clock; auto prev = clock::now(); MSG msg = {}; while (msg.message != WM_QUIT) { if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { auto now = clock::now(); float dt = std::chrono::duration<float>(now - prev).count(); prev = now; try { g_renderer.Update(dt); g_renderer.RenderFrame(); } catch (const std::exception& e) { MessageBoxA(nullptr, e.what(), "渲染错误", MB_ICONERROR); break; } } } return static_cast<int>(msg.wParam); }
D3D11核心设备资源管理(DeviceResources.h / DeviceResources.cpp)
#pragma once // ============================================================================= // DeviceResources.h // 管理 D3D11 核心设备资源:device、immediate context、swapchain、RTV、DSV、视口。 // 负责设备/交换链创建以及窗口尺寸变化时的后备缓冲重建。 // ============================================================================= #include <d3d11.h> #include <dxgi1_2.h> #include "DXHelpers.h" class DeviceResources { public: DeviceResources() = default; ~DeviceResources() = default; // 根据窗口句柄创建设备、交换链与后备缓冲 void Initialize(HWND hwnd, UINT width, UINT height); // 窗口尺寸变化时调用,重建 RTV / DSV void Resize(UINT width, UINT height); // 呈现当前帧(垂直同步) void Present(); // -------- 访问器 -------- ID3D11Device* GetDevice() const { return mDevice.Get(); } ID3D11DeviceContext* GetImmediateContext() const { return mImmediateContext.Get(); } ID3D11RenderTargetView* GetRTV() const { return mRTV.Get(); } ID3D11DepthStencilView* GetDSV() const { return mDSV.Get(); } const D3D11_VIEWPORT& GetViewport() const { return mViewport; } UINT GetWidth() const { return mWidth; } UINT GetHeight() const { return mHeight; } float GetAspectRatio() const { return mHeight ? static_cast<float>(mWidth) / mHeight : 1.0f; } private: void CreateBackBufferResources(); // 创建/重建 RTV 与 DSV HWND mHwnd = nullptr; UINT mWidth = 0; UINT mHeight = 0; ComPtr<ID3D11Device> mDevice; ComPtr<ID3D11DeviceContext> mImmediateContext; // 唯一的立即上下文(用于回放命令列表与 Present) ComPtr<IDXGISwapChain1> mSwapChain; ComPtr<ID3D11RenderTargetView> mRTV; ComPtr<ID3D11Texture2D> mDepthStencilBuffer; ComPtr<ID3D11DepthStencilView> mDSV; D3D11_VIEWPORT mViewport = {}; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ============================================================================= // DeviceResources.cpp // ============================================================================= #include "DeviceResources.h" void DeviceResources::Initialize(HWND hwnd, UINT width, UINT height) { mHwnd = hwnd; mWidth = width; mHeight = height; UINT createFlags = 0; #if defined(_DEBUG) // Debug 构建启用调试层,便于捕获 D3D 错误与资源泄漏报告 createFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif const D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, }; // ---- 创建 D3D11 设备与 Immediate Context ---- ComPtr<ID3D11Device> baseDevice; ComPtr<ID3D11DeviceContext> baseContext; D3D_FEATURE_LEVEL obtainedLevel{}; HRESULT hr = D3D11CreateDevice( nullptr, // 默认适配器 D3D_DRIVER_TYPE_HARDWARE, nullptr, createFlags, featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, baseDevice.GetAddressOf(), &obtainedLevel, baseContext.GetAddressOf()); if (FAILED(hr)) { // 回退到 WARP 软件渲染(无独显环境也能运行示例) ThrowIfFailed(D3D11CreateDevice( nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createFlags, featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, baseDevice.GetAddressOf(), &obtainedLevel, baseContext.GetAddressOf())); } ThrowIfFailed(baseDevice.As(&mDevice)); ThrowIfFailed(baseContext.As(&mImmediateContext)); // ---- 通过 DXGI 创建交换链 ---- ComPtr<IDXGIDevice> dxgiDevice; ThrowIfFailed(mDevice.As(&dxgiDevice)); ComPtr<IDXGIAdapter> adapter; ThrowIfFailed(dxgiDevice->GetAdapter(adapter.GetAddressOf())); ComPtr<IDXGIFactory2> factory; ThrowIfFailed(adapter->GetParent(__uuidof(IDXGIFactory2), reinterpret_cast<void**>(factory.GetAddressOf()))); DXGI_SWAP_CHAIN_DESC1 scDesc = {}; scDesc.Width = mWidth; scDesc.Height = mHeight; scDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scDesc.SampleDesc.Count = 1; // 不使用 MSAA,保持示例简单 scDesc.SampleDesc.Quality = 0; scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scDesc.BufferCount = 2; scDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; ThrowIfFailed(factory->CreateSwapChainForHwnd( mDevice.Get(), mHwnd, &scDesc, nullptr, nullptr, mSwapChain.GetAddressOf())); // 禁用 Alt+Enter 全屏切换,避免示例状态混乱 factory->MakeWindowAssociation(mHwnd, DXGI_MWA_NO_ALT_ENTER); CreateBackBufferResources(); } void DeviceResources::CreateBackBufferResources() { // 重建前先释放旧的视图 mRTV.Reset(); mDSV.Reset(); mDepthStencilBuffer.Reset(); // ---- 渲染目标视图(来自交换链后备缓冲)---- ComPtr<ID3D11Texture2D> backBuffer; ThrowIfFailed(mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(backBuffer.GetAddressOf()))); ThrowIfFailed(mDevice->CreateRenderTargetView(backBuffer.Get(), nullptr, mRTV.GetAddressOf())); // ---- 深度模板缓冲与视图 ---- D3D11_TEXTURE2D_DESC dsDesc = {}; dsDesc.Width = mWidth; dsDesc.Height = mHeight; dsDesc.MipLevels = 1; dsDesc.ArraySize = 1; dsDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; dsDesc.SampleDesc.Count = 1; dsDesc.Usage = D3D11_USAGE_DEFAULT; dsDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; ThrowIfFailed(mDevice->CreateTexture2D(&dsDesc, nullptr, mDepthStencilBuffer.GetAddressOf())); ThrowIfFailed(mDevice->CreateDepthStencilView(mDepthStencilBuffer.Get(), nullptr, mDSV.GetAddressOf())); // ---- 视口 ---- mViewport.TopLeftX = 0.0f; mViewport.TopLeftY = 0.0f; mViewport.Width = static_cast<float>(mWidth); mViewport.Height = static_cast<float>(mHeight); mViewport.MinDepth = 0.0f; mViewport.MaxDepth = 1.0f; } void DeviceResources::Resize(UINT width, UINT height) { if (width == 0 || height == 0) return; // 最小化时忽略 if (width == mWidth && height == mHeight) return; // 尺寸未变 mWidth = width; mHeight = height; // 释放对后备缓冲的引用后才能 ResizeBuffers mRTV.Reset(); mDSV.Reset(); mDepthStencilBuffer.Reset(); ThrowIfFailed(mSwapChain->ResizeBuffers(0, mWidth, mHeight, DXGI_FORMAT_UNKNOWN, 0)); CreateBackBufferResources(); } void DeviceResources::Present() { // 第二参数 0:允许撕裂关闭,垂直同步呈现 HRESULT hr = mSwapChain->Present(1, 0); ThrowIfFailed(hr); }
核心渲染器:管理 N 个 Deferred Context 与对应工作线程,多线程并行录制绘制(DeferredRenderer.h / DeferredRenderer.cpp)
#pragma once // ============================================================================= // DeferredRenderer.h // 核心渲染器:管理 N 个 Deferred Context 与对应工作线程,多线程并行录制绘制 // 命令并由 Immediate Context 顺序回放。 // ============================================================================= #include <d3d11.h> #include <DirectXMath.h> #include <vector> #include "DXHelpers.h" #include "CubeGeometry.h" class DeviceResources; // 单个立方体的实例数据 struct CubeInstance { DirectX::XMFLOAT3 worldPosition; // 世界位置 float rotationSpeed; // 旋转速度 float angle; // 当前角度 }; class DeferredRenderer { public: // threadCount : Deferred Context / 工作线程数量 // cubeCount : 场景中立方体数量(会平均分配到各线程录制) void Initialize(DeviceResources* res, UINT threadCount, UINT cubeCount); // 主线程:更新动画与相机/常量数据 void Update(float dt); // 多线程录制命令 -> 主线程顺序回放 -> Present void RenderFrame(); private: void CreateGeometry(); void CreateShaders(); void CreatePipelineStates(); void CreatePerObjectResources(); // 工作线程函数:使用第 threadIndex 个 Deferred Context 录制其负责的立方体 void RecordCommands(UINT threadIndex); DeviceResources* mRes = nullptr; UINT mThreadCount = 0; UINT mCubeCount = 0; // ---- 共享只读资源(主线程创建,各线程只读绑定)---- ComPtr<ID3D11Buffer> mVertexBuffer; ComPtr<ID3D11Buffer> mIndexBuffer; ComPtr<ID3D11InputLayout> mInputLayout; ComPtr<ID3D11VertexShader> mVertexShader; ComPtr<ID3D11PixelShader> mPixelShader; ComPtr<ID3D11RasterizerState> mRasterState; ComPtr<ID3D11DepthStencilState> mDepthState; // ---- 每个 Deferred Context(每线程独占一个)---- std::vector<ComPtr<ID3D11DeviceContext>> mDeferredContexts; // 每帧录制生成的命令列表 std::vector<ComPtr<ID3D11CommandList>> mCommandLists; // ---- 每个立方体一份独立常量缓冲,避免多线程 Map 竞争 ---- std::vector<ComPtr<ID3D11Buffer>> mPerObjectCB; // 场景立方体实例 std::vector<CubeInstance> mCubes; // 视图/投影矩阵(主线程更新) DirectX::XMFLOAT4X4 mViewProj; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ============================================================================= // DeferredRenderer.cpp // 演示 D3D11 多 Deferred Context 多线程录制 + Immediate Context 回放。 // ============================================================================= #include "DeferredRenderer.h" #include "DeviceResources.h" #include <thread> #include <vector> using namespace DirectX; // ----------------------------------------------------------------------------- // 内嵌着色器源码(与 Shaders.hlsl 内容一致,运行时编译,免预编译步骤) // ----------------------------------------------------------------------------- static const char* g_ShaderSource = R"( cbuffer CBPerObject : register(b0) { float4x4 gWorldViewProj; }; struct VSInput { float3 position : POSITION; float3 color : COLOR; }; struct VSOutput { float4 position : SV_POSITION; float3 color : COLOR; }; VSOutput VSMain(VSInput input) { VSOutput o; o.position = mul(float4(input.position, 1.0f), gWorldViewProj); o.color = input.color; return o; } float4 PSMain(VSOutput input) : SV_TARGET { return float4(input.color, 1.0f); } )"; void DeferredRenderer::Initialize(DeviceResources* res, UINT threadCount, UINT cubeCount) { mRes = res; mThreadCount = (threadCount == 0) ? 1 : threadCount; mCubeCount = (cubeCount == 0) ? 1 : cubeCount; CreateGeometry(); CreateShaders(); CreatePipelineStates(); CreatePerObjectResources(); ID3D11Device* device = mRes->GetDevice(); // ---- 为每个工作线程创建一个独立的 Deferred Context ---- // 注意:D3D11 设备本身支持多线程创建资源;每个 Deferred Context 仅由它所属 // 的线程使用,互不干扰,从而避免对 Immediate Context 的并发访问。 mDeferredContexts.resize(mThreadCount); mCommandLists.resize(mThreadCount); for (UINT i = 0; i < mThreadCount; ++i) { ThrowIfFailed(device->CreateDeferredContext(0, mDeferredContexts[i].GetAddressOf())); } // ---- 初始化场景立方体实例(围成一圈分布)---- mCubes.resize(mCubeCount); const float radius = 4.0f; for (UINT i = 0; i < mCubeCount; ++i) { float t = (mCubeCount > 1) ? (XM_2PI * i / mCubeCount) : 0.0f; mCubes[i].worldPosition = XMFLOAT3(radius * cosf(t), 0.0f, radius * sinf(t)); mCubes[i].rotationSpeed = 0.5f + 0.3f * (i % 4); mCubes[i].angle = t; } } void DeferredRenderer::CreateGeometry() { ID3D11Device* device = mRes->GetDevice(); // 顶点缓冲 D3D11_BUFFER_DESC vbDesc = {}; vbDesc.ByteWidth = sizeof(CubeGeometry::kVertices); vbDesc.Usage = D3D11_USAGE_IMMUTABLE; vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; D3D11_SUBRESOURCE_DATA vbData = {}; vbData.pSysMem = CubeGeometry::kVertices; ThrowIfFailed(device->CreateBuffer(&vbDesc, &vbData, mVertexBuffer.GetAddressOf())); // 索引缓冲 D3D11_BUFFER_DESC ibDesc = {}; ibDesc.ByteWidth = sizeof(CubeGeometry::kIndices); ibDesc.Usage = D3D11_USAGE_IMMUTABLE; ibDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; D3D11_SUBRESOURCE_DATA ibData = {}; ibData.pSysMem = CubeGeometry::kIndices; ThrowIfFailed(device->CreateBuffer(&ibDesc, &ibData, mIndexBuffer.GetAddressOf())); } void DeferredRenderer::CreateShaders() { ID3D11Device* device = mRes->GetDevice(); ComPtr<ID3DBlob> vsBlob = CompileShaderFromString(g_ShaderSource, "VSMain", "vs_5_0"); ComPtr<ID3DBlob> psBlob = CompileShaderFromString(g_ShaderSource, "PSMain", "ps_5_0"); ThrowIfFailed(device->CreateVertexShader( vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), nullptr, mVertexShader.GetAddressOf())); ThrowIfFailed(device->CreatePixelShader( psBlob->GetBufferPointer(), psBlob->GetBufferSize(), nullptr, mPixelShader.GetAddressOf())); // 输入布局 const D3D11_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; ThrowIfFailed(device->CreateInputLayout( layout, ARRAYSIZE(layout), vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), mInputLayout.GetAddressOf())); } void DeferredRenderer::CreatePipelineStates() { ID3D11Device* device = mRes->GetDevice(); // 光栅化状态:实心填充、背面剔除关闭以保证立方体各面可见 D3D11_RASTERIZER_DESC rsDesc = {}; rsDesc.FillMode = D3D11_FILL_SOLID; rsDesc.CullMode = D3D11_CULL_NONE; rsDesc.FrontCounterClockwise = FALSE; rsDesc.DepthClipEnable = TRUE; ThrowIfFailed(device->CreateRasterizerState(&rsDesc, mRasterState.GetAddressOf())); // 深度模板状态:开启深度测试 D3D11_DEPTH_STENCIL_DESC dsDesc = {}; dsDesc.DepthEnable = TRUE; dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; dsDesc.DepthFunc = D3D11_COMPARISON_LESS; dsDesc.StencilEnable = FALSE; ThrowIfFailed(device->CreateDepthStencilState(&dsDesc, mDepthState.GetAddressOf())); } void DeferredRenderer::CreatePerObjectResources() { ID3D11Device* device = mRes->GetDevice(); // 每个立方体一份动态常量缓冲(CPU 可写),避免多线程同时 Map 同一资源 mPerObjectCB.resize(mCubeCount); D3D11_BUFFER_DESC cbDesc = {}; cbDesc.ByteWidth = sizeof(CBPerObject); cbDesc.Usage = D3D11_USAGE_DYNAMIC; cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; for (UINT i = 0; i < mCubeCount; ++i) { ThrowIfFailed(device->CreateBuffer(&cbDesc, nullptr, mPerObjectCB[i].GetAddressOf())); } } void DeferredRenderer::Update(float dt) { // 推进每个立方体的旋转角度 for (auto& c : mCubes) { c.angle += c.rotationSpeed * dt; } // 计算视图 + 投影矩阵 XMVECTOR eye = XMVectorSet(0.0f, 6.0f, -10.0f, 1.0f); XMVECTOR at = XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f); XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); XMMATRIX view = XMMatrixLookAtLH(eye, at, up); XMMATRIX proj = XMMatrixPerspectiveFovLH(XM_PIDIV4, mRes->GetAspectRatio(), 0.1f, 100.0f); XMStoreFloat4x4(&mViewProj, view * proj); } void DeferredRenderer::RecordCommands(UINT threadIndex) { ID3D11DeviceContext* ctx = mDeferredContexts[threadIndex].Get(); // ---- 每个 Deferred Context 起始为默认状态,必须显式设置完整管线 ---- ID3D11RenderTargetView* rtv = mRes->GetRTV(); ID3D11DepthStencilView* dsv = mRes->GetDSV(); // 由 0 号线程负责清屏(命令列表按顺序回放,0 号最先执行) if (threadIndex == 0) { const float clearColor[4] = { 0.05f, 0.06f, 0.10f, 1.0f }; ctx->ClearRenderTargetView(rtv, clearColor); ctx->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); } // 绑定输出合并阶段、视口、光栅/深度状态 ctx->OMSetRenderTargets(1, &rtv, dsv); D3D11_VIEWPORT vp = mRes->GetViewport(); ctx->RSSetViewports(1, &vp); ctx->RSSetState(mRasterState.Get()); ctx->OMSetDepthStencilState(mDepthState.Get(), 0); // 绑定输入装配阶段 UINT stride = sizeof(Vertex); UINT offset = 0; ID3D11Buffer* vb = mVertexBuffer.Get(); ctx->IASetVertexBuffers(0, 1, &vb, &stride, &offset); ctx->IASetIndexBuffer(mIndexBuffer.Get(), DXGI_FORMAT_R16_UINT, 0); ctx->IASetInputLayout(mInputLayout.Get()); ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // 绑定着色器 ctx->VSSetShader(mVertexShader.Get(), nullptr, 0); ctx->PSSetShader(mPixelShader.Get(), nullptr, 0); XMMATRIX viewProj = XMLoadFloat4x4(&mViewProj); // ---- 绘制本线程负责的立方体(按 i % threadCount 分配)---- for (UINT i = threadIndex; i < mCubeCount; i += mThreadCount) { const CubeInstance& cube = mCubes[i]; // 计算世界 * 视图 * 投影 XMMATRIX world = XMMatrixRotationRollPitchYaw(cube.angle * 0.7f, cube.angle, 0.0f) * XMMatrixTranslation(cube.worldPosition.x, cube.worldPosition.y, cube.worldPosition.z); XMMATRIX wvp = world * viewProj; // 更新该立方体专属常量缓冲(HLSL 列主序 -> 这里转置) D3D11_MAPPED_SUBRESOURCE mapped; ThrowIfFailed(ctx->Map(mPerObjectCB[i].Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped)); CBPerObject* cb = reinterpret_cast<CBPerObject*>(mapped.pData); XMStoreFloat4x4(&cb->worldViewProj, XMMatrixTranspose(wvp)); ctx->Unmap(mPerObjectCB[i].Get(), 0); ID3D11Buffer* cbPtr = mPerObjectCB[i].Get(); ctx->VSSetConstantBuffers(0, 1, &cbPtr); ctx->DrawIndexed(CubeGeometry::kIndexCount, 0, 0); } // ---- 结束录制,生成命令列表 ---- // 第二参数 FALSE:不恢复 deferred context 状态(每帧重置即可) mCommandLists[threadIndex].Reset(); ThrowIfFailed(ctx->FinishCommandList(FALSE, mCommandLists[threadIndex].GetAddressOf())); } void DeferredRenderer::RenderFrame() { // ---- 启动工作线程并行录制 ---- std::vector<std::thread> workers; workers.reserve(mThreadCount); for (UINT i = 0; i < mThreadCount; ++i) { workers.emplace_back([this, i]() { RecordCommands(i); }); } for (auto& t : workers) { t.join(); // 等待线程执行完成 } // ---- 主线程:在 Immediate Context 上按顺序回放命令列表 ---- ID3D11DeviceContext* immediate = mRes->GetImmediateContext(); for (UINT i = 0; i < mThreadCount; ++i) { if (mCommandLists[i]) { // 第二参数 FALSE:执行后不恢复 immediate context 状态 immediate->ExecuteCommandList(mCommandLists[i].Get(), FALSE); mCommandLists[i].Reset(); // 命令列表用后即弃,避免泄漏 } } // 呈现 mRes->Present(); }
运行结果

浙公网安备 33010602011771号