DirectX 窗口通过多窗口和多线程快速闪烁
DirectX window flickers rapidly with multi-windows and multi-threading
我正在尝试创建一个基本的基于DirectX的C++Windows应用程序,该应用程序可以在两个单独的窗口中显示两个图像。我可以轻松地显示单个图像。但是,我必须使用多线程 - 每个窗口一个线程 - 因为同时更新窗口的内容至关重要。
但是,目前我只专注于为两个静态图像实现多线程,每个窗口每个线程一个图像。然而,我遇到的问题是两个窗口都闪烁得有点快/随机(它们大多闪烁到黑色,偶尔闪烁为绿色)。
我怀疑这可能与我将多线程与 DirectX 相结合的方式有关,据我所知,必须使用互斥锁,这样就不会同时调用设备或上下文。因此,我怀疑当窗口重新渲染时,它们的内容在一段时间内被另一个线程阻止。
但是,我不确定是否是这种情况,如果是这样,我不知道如何解决它。
这是主要的游戏循环:
//
// Game.cpp
//
#include "pch.h"
#include "Game.h"
#include <synchapi.h>
extern void ExitGame();
using namespace DirectX;
using Microsoft::WRL::ComPtr;
ComPtr<ID3D11Texture2D> textures[4];
Game::Game() noexcept(false)
{
m_deviceResources = std::make_unique<DX::DeviceResources>(DXGI_FORMAT_R10G10B10A2_UNORM,
DXGI_FORMAT_D32_FLOAT, 2, D3D_FEATURE_LEVEL_10_0, DX::DeviceResources::c_EnableHDR);
m_deviceResources->RegisterDeviceNotify(this);
m_hdrScene[0] = std::make_unique<DX::RenderTexture>(DXGI_FORMAT_R16G16B16A16_FLOAT);
m_hdrScene[1] = std::make_unique<DX::RenderTexture>(DXGI_FORMAT_R16G16B16A16_FLOAT);
}
// Initialize the Direct3D resources required to run.
void Game::Initialize(HWND windows[], int width, int height)
{
m_deviceResources->SetWindow(0, windows[0], width, height);
m_deviceResources->SetWindow(1, windows[1], width, height);
m_deviceResources->CreateDeviceResources();
CreateDeviceDependentResources();
m_deviceResources->CreateWindowSizeDependentResources(0);
m_deviceResources->CreateWindowSizeDependentResources(1);
CreateWindowSizeDependentResources();
// TODO: Change the timer settings if you want something other than the default variable timestep mode.
// e.g. for 60 FPS fixed timestep update logic, call:
m_timer.SetFixedTimeStep(true);
m_timer.SetTargetElapsedSeconds(1.0 / 60);
}
void Game::CreateThreads()
{
std::thread one(&Game::Render, this, 0);
std::thread two(&Game::Render, this, 1);
one.join();
two.join();
}
#pragma region Frame Update
// Executes the basic game loop.
void Game::Tick()
{
m_timer.Tick([&]() { Update(m_timer); });
CreateThreads();
}
// Updates the world.
void Game::Update(DX::StepTimer const& timer)
{
float elapsedTime = float(timer.GetElapsedSeconds());
char buff[128] = {};
sprintf_s(buff, "%fn", elapsedTime);
OutputDebugStringA(buff);
// TODO: Add your game logic here.
}
#pragma endregion
std::mutex mut;
#pragma region Frame Render
// Draws the scene.
void Game::Render(int i)
{
// Don't try to render anything before the first Update.
if (m_timer.GetFrameCount() == 0)
{
return;
}
mut.lock();
Clear(i);
m_deviceResources->PIXBeginEvent(L"Render");
auto context = m_deviceResources->GetD3DDeviceContext();
m_spriteBatch = std::make_unique<SpriteBatch>(context);
mut.unlock();
// TODO: Add your rendering code here.
D3D11_SHADER_RESOURCE_VIEW_DESC desc2 = { };
desc2.Format = DXGI_FORMAT_R16G16B16A16_UNORM;
desc2.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
desc2.Texture2D.MipLevels = 1;
ComPtr<ID3D11ShaderResourceView> shaderResourceView;
mut.lock();
auto hr = m_deviceResources->m_d3dDevice->CreateShaderResourceView(
textures[i].Get(),
&desc2,
shaderResourceView.GetAddressOf()
);
try {
m_spriteBatch->Begin();
m_spriteBatch->Draw(shaderResourceView.Get(), XMFLOAT2(0, 0));
m_spriteBatch->End();
} catch (std::exception& e)
{
auto msg = e.what();
throw std::exception(msg);
}
m_deviceResources->PIXEndEvent();
auto renderTarget = m_deviceResources->GetRenderTargetView(i);
context->OMSetRenderTargets(1, &renderTarget, nullptr);
mut.unlock();
m_toneMap[i]->SetOperator(ToneMapPostProcess::None);
m_toneMap[i]->SetTransferFunction(ToneMapPostProcess::ST2084);
m_toneMap[i]->SetST2084Parameter(10000.f);
mut.lock();
m_toneMap[i]->Process(context);
ID3D11ShaderResourceView* nullsrv[] = { nullptr };
context->PSSetShaderResources(0, 1, nullsrv);
mut.unlock();
// Show the new frame.
m_deviceResources->Present(i);
}
// Helper method to clear the back buffers.
void Game::Clear(int i)
{
m_deviceResources->PIXBeginEvent(L"Clear");
// Clear the views.
auto context = m_deviceResources->GetD3DDeviceContext();
auto renderTarget = m_hdrScene[i]->GetRenderTargetView();
auto depthStencil = m_deviceResources->GetDepthStencilView();
XMVECTORF32 color;
auto actual = FXMVECTOR({ {0, 0, 0, 0} });
color.v = XMColorSRGBToRGB(actual);
context->ClearRenderTargetView(renderTarget, color);
context->ClearDepthStencilView(depthStencil, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
context->OMSetRenderTargets(1, &renderTarget, depthStencil);
// Set the viewport.
auto viewport = m_deviceResources->GetScreenViewport();
context->RSSetViewports(1, &viewport);
m_deviceResources->PIXEndEvent();
}
#pragma endregion
void Game::OnWindowMoved()
{
auto r = m_deviceResources->GetOutputSize();
m_deviceResources->WindowSizeChanged(0, r.right, r.bottom);
m_deviceResources->WindowSizeChanged(1, r.right, r.bottom);
}
void Game::OnWindowSizeChanged(int index, int width, int height)
{
if (!m_deviceResources->WindowSizeChanged(index, width, height))
return;
CreateWindowSizeDependentResources();
// TODO: Game window is being resized.
}
// Properties
void Game::GetDefaultSize(int& width, int& height) const
{
// TODO: Change to desired default window size (note minimum size is 320x200).
width = 800;
height = 600;
}
#pragma region Direct3D Resources
// These are the resources that depend on the device.
void Game::CreateDeviceDependentResources()
{
auto device = m_deviceResources->GetD3DDevice();
cv::directx::ocl::initializeContextFromD3D11Device(device);
// TODO: Initialize device dependent objects here (independent of window size).
for (int i = 0; i < 2; i++)
{
m_hdrScene[i]->SetDevice(device);
m_toneMap[i] = std::make_unique<ToneMapPostProcess>(device);
m_toneMap[i]->SetOperator(ToneMapPostProcess::None);
m_toneMap[i]->SetTransferFunction(ToneMapPostProcess::ST2084);
}
for (int i = 0; i < 4; i++) {
textures[i] = this->getImagesAsTextures()[i];
}
}
// Allocate all memory resources that change on a window SizeChanged event.
void Game::CreateWindowSizeDependentResources()
{
auto size = m_deviceResources->GetOutputSize();
for (int i = 0; i < 2; i++) {
m_hdrScene[i]->SetWindow(size);
m_toneMap[i]->SetHDRSourceTexture(m_hdrScene[i]->GetShaderResourceView());
}
}
void Game::OnDeviceLost()
{
// TODO: Add Direct3D resource cleanup here.
m_hdrScene[0]->ReleaseDevice();
m_hdrScene[1]->ReleaseDevice();
m_toneMap[0].reset();
m_toneMap[1].reset();
}
void Game::OnDeviceRestored()
{
CreateDeviceDependentResources();
CreateWindowSizeDependentResources();
CreateWindowSizeDependentResources();
}
#pragma endregion
我也收到此警告,但我不确定这意味着什么:D3D11 WARNING: ID3D11DeviceContext::DrawIndexed: The Pixel Shader expects a Render Target View bound to slot 0, but none is bound. This is OK, as writes of an unbound Render Target View are discarded. It is also possible the developer knows the data will not be used anyway. This is only a problem if the developer actually intended to bind a Render Target View here. [ EXECUTION WARNING #3146081: DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET]
此代码主要基于 DirectXTK Win32 模板。任何帮助将不胜感激,谢谢。
在渲染过程中多次手动互斥锁/解锁使整个同步毫无意义。没有同时调用设备或上下文,但可以从不同的线程修改呈现管道。例如,lock
OMSetRenderTargets
unlock
之后,另一个线程可能会获得锁并设置不同的呈现目标,使第一个呈现目标具有丢弃的内容显示在屏幕上。
- 如何在Qt窗口小部件中使用QStringView(或QStringRef)
- 问:如何使用C++中的按钮从窗口打开窗口
- SDL 窗口不会弹出
- 在createdialog创建的窗口中捕获用于编辑控件的OnMouseMove消息
- 如何在cpp文件之间切换窗口?在Qt中
- 处理闪烁窗口事件
- 在鼠标按下时移动 SDL2 窗口的功能闪烁窗口并且移动速度不够快
- DirectX 窗口通过多窗口和多线程快速闪烁
- OpenGL纹理闪烁/有时在窗口大小上移动
- 在 d3d->CreateDevice 中D3DERR_INVALIDCALL,导致在 Allegro 5 D3D 程序中启动时窗口闪烁
- CreateProcess正在调用cmd.exe,包括没有显示(闪烁)窗口的参数
- 控制台窗口闪烁C++然后消失
- 窗口闪烁,在 NVIDIA 显卡上呈现 OpenGL
- SFML 闪烁渲染窗口
- 控制台图像在窗口10中闪烁
- Win32 API:如何避免基本窗口控件的闪烁
- 上下滑动窗口在底部闪烁
- 移动窗口和调整底部闪烁大小
- win32c++弹出窗口在以编程方式调整大小时闪烁很多
- Firebreath OpenGl窗口闪烁