qt: Remove the Direct3D 9 renderer

This commit is contained in:
Alexander Babikov
2024-02-13 18:40:07 +05:00
parent c7563f802c
commit 5acec5dfa4
11 changed files with 18 additions and 389 deletions

View File

@@ -197,8 +197,7 @@ if(WIN32)
else()
target_sources(plat PRIVATE win_joystick_rawinput.c)
endif()
target_sources(ui PRIVATE qt_d3d9renderer.hpp qt_d3d9renderer.cpp)
target_link_libraries(86Box hid d3d9)
target_link_libraries(86Box hid)
# CMake 3.22 messed this up for clang/clang++
# See https://gitlab.kitware.com/cmake/cmake/-/issues/22611

View File

@@ -52,10 +52,8 @@ plat_vidapi(char *api)
return 3;
} else if (!strcasecmp(api, "qt_vulkan")) {
return 4;
} else if (!strcasecmp(api, "qt_d3d9")) {
return 5;
} else if (!strcasecmp(api, "vnc")) {
return 6;
return 5;
}
return 0;
@@ -83,9 +81,6 @@ plat_vidapi_name(int api)
name = "qt_vulkan";
break;
case 5:
name = "qt_d3d9";
break;
case 6:
name = "vnc";
break;
default:

View File

@@ -1,200 +0,0 @@
#include "qt_mainwindow.hpp"
#include "qt_d3d9renderer.hpp"
#include <QResizeEvent>
#include <QTimer>
extern "C" {
#include <86box/86box.h>
#include <86box/video.h>
}
D3D9Renderer::D3D9Renderer(QWidget *parent, int monitor_index)
: QWidget { parent }
, RendererCommon()
{
QPalette pal = palette();
pal.setColor(QPalette::Window, Qt::black);
setAutoFillBackground(true);
setPalette(pal);
setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_PaintOnScreen);
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_OpaquePaintEvent);
windowHandle = (HWND) winId();
surfaceInUse = true;
finalized = true;
RendererCommon::parentWidget = parent;
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
this->m_monitor_index = monitor_index;
d3d9surface = nullptr;
d3d9dev = nullptr;
d3d9 = nullptr;
}
D3D9Renderer::~D3D9Renderer()
{
finalize();
}
void
D3D9Renderer::finalize()
{
if (!finalized) {
while (surfaceInUse) { }
finalized = true;
}
surfaceInUse = true;
if (d3d9surface) {
d3d9surface->Release();
d3d9surface = nullptr;
}
if (d3d9dev) {
d3d9dev->Release();
d3d9dev = nullptr;
}
if (d3d9) {
d3d9->Release();
d3d9 = nullptr;
}
}
void
D3D9Renderer::hideEvent(QHideEvent *event)
{
finalize();
}
void
D3D9Renderer::showEvent(QShowEvent *event)
{
if (d3d9) finalize();
params = {};
if (FAILED(Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9))) {
return error("Failed to create Direct3D 9 context");
}
params.Windowed = true;
params.SwapEffect = D3DSWAPEFFECT_FLIPEX;
params.BackBufferWidth = width() * devicePixelRatioF();
params.BackBufferHeight = height() * devicePixelRatioF();
params.BackBufferCount = 1;
params.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
params.hDeviceWindow = (HWND) winId();
HRESULT result = d3d9->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, windowHandle, D3DCREATE_MULTITHREADED | D3DCREATE_HARDWARE_VERTEXPROCESSING, &params, nullptr, &d3d9dev);
if (FAILED(result))
result = d3d9->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, windowHandle, D3DCREATE_MULTITHREADED | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &params, nullptr, &d3d9dev);
if (FAILED(result)) {
return error("Failed to create Direct3D 9 device");
}
result = d3d9dev->CreateOffscreenPlainSurface(2048, 2048, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d9surface, nullptr);
if (FAILED(result))
result = d3d9dev->CreateOffscreenPlainSurface(1024, 1024, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d9surface, nullptr);
if (FAILED(result)) {
return error("Failed to create Direct3D 9 surface");
}
if (!alreadyInitialized) {
emit initialized();
alreadyInitialized = true;
}
surfaceInUse = false;
finalized = false;
}
void
D3D9Renderer::paintEvent(QPaintEvent *event)
{
IDirect3DSurface9 *backbuffer = nullptr;
RECT srcRect;
RECT dstRect;
HRESULT result = d3d9dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
if (FAILED(result)) {
return;
}
srcRect.top = source.top();
srcRect.bottom = source.bottom();
srcRect.left = source.left();
srcRect.right = source.right();
dstRect.top = destination.top() * devicePixelRatioF();
dstRect.bottom = destination.bottom() * devicePixelRatioF();
dstRect.left = destination.left() * devicePixelRatioF();
dstRect.right = destination.right() * devicePixelRatioF();
d3d9dev->BeginScene();
d3d9dev->Clear(0, nullptr, D3DCLEAR_TARGET, 0xFF000000, 0, 0);
while (surfaceInUse) { }
surfaceInUse = true;
d3d9dev->StretchRect(d3d9surface, &srcRect, backbuffer, &dstRect, video_filter_method == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR);
result = d3d9dev->EndScene();
surfaceInUse = false;
if (SUCCEEDED(result)) {
if (FAILED(d3d9dev->PresentEx(nullptr, nullptr, 0, nullptr, 0))) {
finalize();
showEvent(nullptr);
}
}
}
bool
D3D9Renderer::event(QEvent *event)
{
bool res = false;
if (!eventDelegate(event, res))
return QWidget::event(event);
return res;
}
void
D3D9Renderer::resizeEvent(QResizeEvent *event)
{
onResize(event->size().width() * devicePixelRatioF(), event->size().height() * devicePixelRatioF());
params.BackBufferWidth = event->size().width() * devicePixelRatioF();
params.BackBufferHeight = event->size().height() * devicePixelRatioF();
if (d3d9dev)
d3d9dev->Reset(&params);
QWidget::resizeEvent(event);
}
void
D3D9Renderer::blit(int x, int y, int w, int h)
{
if (blitDummied || (x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (monitors[m_monitor_index].target_buffer == NULL) || surfaceInUse) {
video_blit_complete_monitor(m_monitor_index);
return;
}
surfaceInUse = true;
auto origSource = source;
source.setRect(x, y, w, h);
RECT srcRect;
D3DLOCKED_RECT lockRect;
srcRect.top = source.top();
srcRect.bottom = source.bottom();
srcRect.left = source.left();
srcRect.right = source.right();
if (monitors[m_monitor_index].mon_screenshots) {
video_screenshot_monitor((uint32_t *) &(monitors[m_monitor_index].target_buffer->line[y][x]), 0, 0, 2048, m_monitor_index);
}
if (SUCCEEDED(d3d9surface->LockRect(&lockRect, &srcRect, 0))) {
for (int y1 = 0; y1 < h; y1++) {
video_copy(((uint8_t *) lockRect.pBits) + (y1 * lockRect.Pitch), &(monitors[m_monitor_index].target_buffer->line[y + y1][x]), w * 4);
}
video_blit_complete_monitor(m_monitor_index);
d3d9surface->UnlockRect();
} else
video_blit_complete_monitor(m_monitor_index);
if (origSource != source)
onResize(this->width() * devicePixelRatioF(), this->height() * devicePixelRatioF());
surfaceInUse = false;
QTimer::singleShot(0, this, [this] { this->update(); });
}

View File

@@ -1,45 +0,0 @@
#ifndef D3D9RENDERER_HPP
#define D3D9RENDERER_HPP
#include <QWidget>
#include "qt_renderercommon.hpp"
#include <windows.h>
#include <d3d9.h>
#include <atomic>
class D3D9Renderer : public QWidget, public RendererCommon {
Q_OBJECT
public:
explicit D3D9Renderer(QWidget *parent = nullptr, int monitor_index = 0);
~D3D9Renderer();
bool hasBlitFunc() override { return true; }
void blit(int x, int y, int w, int h) override;
void finalize() override;
protected:
void showEvent(QShowEvent *event) override;
void hideEvent(QHideEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void paintEvent(QPaintEvent *event) override;
bool event(QEvent *event) override;
QPaintEngine *paintEngine() const override { return nullptr; }
signals:
void initialized();
void error(QString);
private:
HWND windowHandle = 0;
D3DPRESENT_PARAMETERS params {};
IDirect3D9Ex *d3d9 = nullptr;
IDirect3DDevice9Ex *d3d9dev = nullptr;
IDirect3DSurface9 *d3d9surface = nullptr;
std::atomic<bool> surfaceInUse { false };
std::atomic<bool> finalized { false };
bool alreadyInitialized = false;
int m_monitor_index = 0;
};
#endif // D3D9RENDERER_HPP

View File

@@ -342,7 +342,7 @@ main(int argc, char *argv[])
/* Set the PAUSE mode depending on the renderer. */
#ifdef USE_VNC
if (vnc_enabled && vid_api != 6)
if (vnc_enabled && vid_api != 5)
plat_pause(1);
else
#endif

View File

@@ -157,8 +157,6 @@ keyb_filter(BMessage *message, BHandler **target, BMessageFilter *filter)
static BMessageFilter *filter;
#endif
std::atomic<bool> blitDummied { false };
extern void qt_mouse_capture(int);
extern "C" void qt_blit(int x, int y, int w, int h, int monitor_index);
@@ -369,14 +367,9 @@ MainWindow::MainWindow(QWidget *parent)
ui->actionVulkan->setVisible(false);
ui->actionOpenGL_3_0_Core->setVisible(false);
}
#if !defined Q_OS_WINDOWS
ui->actionDirect3D_9->setVisible(false);
if (vid_api == 5)
vid_api = 0;
#endif
#ifndef USE_VNC
if (vid_api == 6)
if (vid_api == 5)
vid_api = 0;
ui->actionVNC->setVisible(false);
#endif
@@ -410,14 +403,13 @@ MainWindow::MainWindow(QWidget *parent)
actGroup->addAction(ui->actionHardware_Renderer_OpenGL_ES);
actGroup->addAction(ui->actionOpenGL_3_0_Core);
actGroup->addAction(ui->actionVulkan);
actGroup->addAction(ui->actionDirect3D_9);
actGroup->addAction(ui->actionVNC);
actGroup->setExclusive(true);
connect(actGroup, &QActionGroup::triggered, [this](QAction *action) {
vid_api = action->property("vid_api").toInt();
#ifdef USE_VNC
if (vnc_enabled && vid_api != 6) {
if (vnc_enabled && vid_api != 5) {
startblit();
vnc_enabled = 0;
vnc_close();
@@ -442,11 +434,8 @@ MainWindow::MainWindow(QWidget *parent)
case 4:
newVidApi = RendererStack::Renderer::Vulkan;
break;
case 5:
newVidApi = RendererStack::Renderer::Direct3D9;
break;
#ifdef USE_VNC
case 6:
case 5:
{
newVidApi = RendererStack::Renderer::Software;
startblit();
@@ -612,7 +601,7 @@ MainWindow::MainWindow(QWidget *parent)
video_setblit(qt_blit);
if (start_in_fullscreen) {
connect(ui->stackedWidget, &RendererStack::blit, this, [this] () {
connect(ui->stackedWidget, &RendererStack::blitToRenderer, this, [this] () {
if (start_in_fullscreen) {
QTimer::singleShot(100, ui->actionFullscreen, &QAction::trigger);
start_in_fullscreen = 0;
@@ -1156,8 +1145,6 @@ MainWindow::on_actionFullscreen_triggered()
{
if (video_fullscreen > 0) {
showNormal();
if (vid_api == 5)
QTimer::singleShot(0, this, [this]() { ui->stackedWidget->switchRenderer(RendererStack::Renderer::Direct3D9); });
ui->menubar->show();
if (!hide_status_bar)
ui->statusbar->show();
@@ -1193,8 +1180,6 @@ MainWindow::on_actionFullscreen_triggered()
ui->toolBar->hide();
ui->stackedWidget->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
showFullScreen();
if (vid_api == 5)
QTimer::singleShot(0, this, [this]() { ui->stackedWidget->switchRenderer(RendererStack::Renderer::Direct3D9); });
}
ui->stackedWidget->onResize(width(), height());
}
@@ -1316,7 +1301,7 @@ void
MainWindow::blitToWidget(int x, int y, int w, int h, int monitor_index)
{
if (monitor_index >= 1) {
if (!blitDummied && renderers[monitor_index] && renderers[monitor_index]->isVisible())
if (renderers[monitor_index] && renderers[monitor_index]->isVisible())
renderers[monitor_index]->blit(x, y, w, h);
else
video_blit_complete_monitor(monitor_index);
@@ -1976,8 +1961,6 @@ MainWindow::on_actionShow_non_primary_monitors_triggered()
{
show_second_monitors = (int) ui->actionShow_non_primary_monitors->isChecked();
blitDummied = true;
if (show_second_monitors) {
for (int monitor_index = 1; monitor_index < MONITORS_NUM; monitor_index++) {
auto &secondaryRenderer = renderers[monitor_index];
@@ -2007,8 +1990,6 @@ MainWindow::on_actionShow_non_primary_monitors_triggered()
}
}
}
blitDummied = false;
}
void

View File

@@ -12,8 +12,6 @@
class MediaMenu;
class RendererStack;
extern std::atomic<bool> blitDummied;
namespace Ui {
class MainWindow;
}

View File

@@ -117,7 +117,6 @@
<addaction name="actionHardware_Renderer_OpenGL_ES"/>
<addaction name="actionOpenGL_3_0_Core"/>
<addaction name="actionVulkan"/>
<addaction name="actionDirect3D_9"/>
<addaction name="actionVNC"/>
</widget>
<widget class="QMenu" name="menuWindow_scale_factor">
@@ -831,17 +830,6 @@
<string>MCA devices...</string>
</property>
</action>
<action name="actionDirect3D_9">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Direct3D 9</string>
</property>
<property name="vid_api" stdset="0">
<number>5</number>
</property>
</action>
<action name="actionShow_non_primary_monitors">
<property name="checkable">
<bool>true</bool>

View File

@@ -35,9 +35,6 @@ public:
/* Reloads options of renderer */
virtual void reloadOptions() { }
virtual bool hasBlitFunc() { return false; }
virtual void blit(int x, int y, int w, int h) { }
int r_monitor_index = 0;
protected:

View File

@@ -25,9 +25,6 @@
#include "qt_openglrenderer.hpp"
#include "qt_softwarerenderer.hpp"
#include "qt_vulkanwindowrenderer.hpp"
#ifdef Q_OS_WIN
# include "qt_d3d9renderer.hpp"
#endif
#include "qt_mainwindow.hpp"
#include "qt_util.hpp"
@@ -279,40 +276,14 @@ RendererStack::switchRenderer(Renderer renderer)
{
startblit();
if (current) {
if ((current_vid_api == Renderer::Direct3D9 && renderer != Renderer::Direct3D9)
|| (current_vid_api != Renderer::Direct3D9 && renderer == Renderer::Direct3D9)) {
rendererWindow->finalize();
if (rendererWindow->hasBlitFunc()) {
while (directBlitting) { }
connect(this, &RendererStack::blit, this, &RendererStack::blitDummy, Qt::DirectConnection);
disconnect(this, &RendererStack::blit, this, &RendererStack::blitRenderer);
} else {
connect(this, &RendererStack::blit, this, &RendererStack::blitDummy, Qt::DirectConnection);
disconnect(this, &RendererStack::blit, this, &RendererStack::blitCommon);
}
rendererWindow->finalize();
removeWidget(current.get());
disconnect(this, &RendererStack::blitToRenderer, nullptr, nullptr);
removeWidget(current.get());
disconnect(this, &RendererStack::blitToRenderer, nullptr, nullptr);
/* Create new renderer only after previous is destroyed! */
connect(current.get(), &QObject::destroyed, [this, renderer](QObject *) { createRenderer(renderer); });
/* Create new renderer only after previous is destroyed! */
connect(current.get(), &QObject::destroyed, [this, renderer](QObject *) {
createRenderer(renderer);
disconnect(this, &RendererStack::blit, this, &RendererStack::blitDummy);
blitDummied = false;
QTimer::singleShot(1000, this, []() { blitDummied = false; });
});
rendererWindow->hasBlitFunc() ? current.reset() : current.release()->deleteLater();
} else {
rendererWindow->finalize();
removeWidget(current.get());
disconnect(this, &RendererStack::blitToRenderer, nullptr, nullptr);
/* Create new renderer only after previous is destroyed! */
connect(current.get(), &QObject::destroyed, [this, renderer](QObject *) { createRenderer(renderer); });
current.release()->deleteLater();
}
current.release()->deleteLater();
} else {
createRenderer(renderer);
}
@@ -321,7 +292,6 @@ RendererStack::switchRenderer(Renderer renderer)
void
RendererStack::createRenderer(Renderer renderer)
{
current_vid_api = renderer;
switch (renderer) {
default:
case Renderer::Software:
@@ -374,27 +344,6 @@ RendererStack::createRenderer(Renderer renderer)
current.reset(this->createWindowContainer(hw, this));
break;
}
#ifdef Q_OS_WIN
case Renderer::Direct3D9:
{
this->createWinId();
auto hw = new D3D9Renderer(this, m_monitor_index);
rendererWindow = hw;
connect(hw, &D3D9Renderer::error, this, [this](QString str) {
auto msgBox = new QMessageBox(QMessageBox::Critical, "86Box", QString("Failed to initialize D3D9 renderer. Falling back to software rendering.\n\n") + str, QMessageBox::Ok);
msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->show();
imagebufs = {};
QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); });
});
connect(hw, &D3D9Renderer::initialized, this, [this]() {
endblit();
emit rendererChanged();
});
current.reset(hw);
break;
}
#endif
#if QT_CONFIG(vulkan)
case Renderer::Vulkan:
{
@@ -444,44 +393,18 @@ RendererStack::createRenderer(Renderer renderer)
currentBuf = 0;
if (rendererWindow->hasBlitFunc()) {
connect(this, &RendererStack::blit, this, &RendererStack::blitRenderer, Qt::DirectConnection);
} else {
connect(this, &RendererStack::blit, this, &RendererStack::blitCommon, Qt::DirectConnection);
}
if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan && renderer != Renderer::Direct3D9) {
if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan) {
imagebufs = rendererWindow->getBuffers();
endblit();
emit rendererChanged();
}
}
void
RendererStack::blitDummy(int x, int y, int w, int h)
{
video_blit_complete_monitor(m_monitor_index);
blitDummied = true;
}
void
RendererStack::blitRenderer(int x, int y, int w, int h)
{
if (blitDummied) {
blitDummied = false;
video_blit_complete_monitor(m_monitor_index);
return;
}
directBlitting = true;
rendererWindow->blit(x, y, w, h);
directBlitting = false;
}
// called from blitter thread
void
RendererStack::blitCommon(int x, int y, int w, int h)
RendererStack::blit(int x, int y, int w, int h)
{
if (blitDummied || (x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (monitors[m_monitor_index].target_buffer == NULL) || imagebufs.empty() || std::get<std::atomic_flag *>(imagebufs[currentBuf])->test_and_set()) {
if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (monitors[m_monitor_index].target_buffer == NULL) || imagebufs.empty() || std::get<std::atomic_flag *>(imagebufs[currentBuf])->test_and_set()) {
video_blit_complete_monitor(m_monitor_index);
return;
}

View File

@@ -59,7 +59,6 @@ public:
OpenGLES,
OpenGL3,
Vulkan,
Direct3D9,
None = -1
};
void switchRenderer(Renderer renderer);
@@ -81,13 +80,10 @@ public:
signals:
void blitToRenderer(int buf_idx, int x, int y, int w, int h);
void blit(int x, int y, int w, int h);
void rendererChanged();
public slots:
void blitCommon(int x, int y, int w, int h);
void blitRenderer(int x, int y, int w, int h);
void blitDummy(int x, int y, int w, int h);
void blit(int x, int y, int w, int h);
private:
void createRenderer(Renderer renderer);
@@ -107,13 +103,10 @@ private:
int isMouseDown = 0;
int m_monitor_index = 0;
Renderer current_vid_api = Renderer::None;
std::vector<std::tuple<uint8_t *, std::atomic_flag *>> imagebufs;
RendererCommon *rendererWindow { nullptr };
std::unique_ptr<QWidget> current;
std::atomic<bool> directBlitting { false };
};
#endif // QT_RENDERERCONTAINER_HPP