C++ 在QT窗口中进行DirectX11渲染而不丢失其他小部件

C++ 在QT窗口中进行DirectX11渲染而不丢失其他小部件,c++,qt,qt5,directx-11,C++,Qt,Qt5,Directx 11,我正在使用DirectX渲染我的QT窗口,在我开始添加控件之前效果很好。然后,当directx在它们上面绘制时,它们会闪烁。 winforms中的解决方案是在表单的OnPaintBackground中进行渲染,但我在QT中没有找到等效的方法。有没有类似的方法,或者可以用更好的方法 我正在考虑渲染到纹理,然后以某种方式将其转换为pixmap,然后在paintEvent()中绘制 对我来说,能够将按钮、面板和其他控件放置在正在渲染的内容之上(实时)是很重要的 编辑 塞尔吉奥·蒙特利昂的回答几乎奏效了

我正在使用DirectX渲染我的QT窗口,在我开始添加控件之前效果很好。然后,当directx在它们上面绘制时,它们会闪烁。 winforms中的解决方案是在表单的OnPaintBackground中进行渲染,但我在QT中没有找到等效的方法。有没有类似的方法,或者可以用更好的方法

我正在考虑渲染到纹理,然后以某种方式将其转换为pixmap,然后在paintEvent()中绘制

对我来说,能够将按钮、面板和其他控件放置在正在渲染的内容之上(实时)是很重要的

编辑

塞尔吉奥·蒙特利昂的回答几乎奏效了,摇曳的控件消失了。我在代码中更改控件的父控件,并将其设置为主窗口,而不是QFrame。但是现在如果我在控件之间快速移动鼠标,控件之间会出现一个奇怪的灰色框。

按钮后面和GroupBox上方的灰色矩形仅在几分之一秒的时间内可见。知道为什么吗

编辑2


我更改了问题的主题,以描述实际问题,而不是一个解决方案。

我猜您正在使用DirectX使用QWidget的本机hWnd绘图。如果是这种情况,另一个Qt控件会闪烁,因为当小部件重新绘制自身时,它也会导致完整的背景更新。然后,使用DirectX在该曲面的顶部绘制,放弃迄今为止Qt控件绘制的任何内容

那么为什么它们会闪烁而不是完全消失呢

QWidget在内部使用双缓冲(查看文档)。 所以这实际上取决于Qt back buffer何时失效


不过,您可以使用一个简单的技巧:在窗口中添加一个QFrame,将Qt控件放在它上面,然后将该帧的hWnd用作DirectX目标。此外,您可能需要将该QFrame的autoFillBackground属性设置为false。这应该允许您渲染到背景。

我假定您正在使用QWidget的本机hWnd使用DirectX绘制。如果是这种情况,另一个Qt控件会闪烁,因为当小部件重新绘制自身时,它也会导致完整的背景更新。然后,使用DirectX在该曲面的顶部绘制,放弃迄今为止Qt控件绘制的任何内容

那么为什么它们会闪烁而不是完全消失呢

QWidget在内部使用双缓冲(查看文档)。 所以这实际上取决于Qt back buffer何时失效


不过,您可以使用一个简单的技巧:在窗口中添加一个QFrame,将Qt控件放在它上面,然后将该帧的hWnd用作DirectX目标。此外,您可能需要将该QFrame的autoFillBackground属性设置为false。这应该允许您渲染到背景。

多亏了塞尔吉奥·蒙特利昂(Sergio Monteleon)的作品,我想出了两个我认为可以接受的解决方案。 我已将这两种方法上载到github:

方法1-有效但缓慢

  • 从QFRAME而不是主窗口获取HWND
  • 将DX渲染转换为纹理
  • 将其转换为QBitmap并在qframe paintEvent中绘制
  • qframe必须在每个帧更新
方法2-几乎有效,速度快,但会产生闪烁(塞尔吉奥·蒙特利昂的解决方案)

  • 在qframe上渲染DX,将控件放置在qframe顶部(不在中)

    如果您在按钮之间疯狂地移动鼠标,当vsync处于启用状态时,按钮之间会出现一个方框闪烁。 当VSync打开时,这种方法在我的机器上实际上速度较慢。这当然是因为什么都没有呈现出来。我没有尝试在这里进行任何重渲染,但我怀疑如果fps降至60左右,即使没有vsync,闪烁也会可见

编辑。在渲染到的qframe上,将UpdateEnabled设置为false,即使fps或vsync速度较慢,也不会闪烁。

如果您有兴趣查看实施,请查看repo。将DX纹理转换为QImage非常简单:

    HRESULT hr = swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast< void** >(&pSurface));

    if(hr != S_OK)
        return;

    context->CopyResource(renderTargetTex, pSurface);

    D3D11_MAP eMapType = D3D11_MAP_READ;
    D3D11_MAPPED_SUBRESOURCE mappedResource;
    context->Map(renderTargetTex, 0, eMapType, NULL, &mappedResource);

    BYTE* pYourBytes = (BYTE*)mappedResource.pData;

    bitmap = QImage(pYourBytes, windowWidth, windowHeight, QImage::Format_RGBA8888);

        context->Unmap(renderTargetTex, 0);
HRESULT hr=swapchain->GetBuffer(0,uidof(ID3D11Texture2D),重新解释强制转换(&pSurface));
如果(hr!=S_正常)
返回;
上下文->复制资源(renderTargetTex、pSurface);
D3D11_MAP eMapType=D3D11_MAP_READ;
D3D11_映射_子资源mappedResource;
上下文->映射(renderTargetTex、0、eMapType、NULL和mappedResource);
BYTE*pYourBytes=(BYTE*)mappedResource.pData;
位图=QImage(pYourBytes,windowWidth,windowHeight,QImage::Format_RGBA8888);
上下文->取消映射(renderTargetTex,0);

此代码仅用于测试该方法,它缺少大多数错误检查,可能会泄漏大量内存。

多亏了Sergio Monteleon的帮助,我想出了两个我认为可以接受的解决方案。 我已将这两种方法上载到github:

方法1-有效但缓慢

  • 从QFRAME而不是主窗口获取HWND
  • 将DX渲染转换为纹理
  • 将其转换为QBitmap并在qframe paintEvent中绘制
  • qframe必须在每个帧更新
方法2-几乎有效,速度快,但会产生闪烁(塞尔吉奥·蒙特利昂的解决方案)

  • 在qframe上渲染DX,将控件放置在qframe顶部(不在中)

    如果您在按钮之间疯狂地移动鼠标,当vsync处于启用状态时,按钮之间会出现一个方框闪烁。 当VSync打开时,这种方法在我的机器上实际上速度较慢。这当然是因为什么都没有呈现出来。我没有尝试在这里进行任何重渲染,但我怀疑如果fps降至60左右,即使没有vsync,闪烁也会可见

编辑。在渲染到的qframe上将UpdateEnabled设置为false,并且不会出现闪烁ev