Merge branch 'master' of ssh://github.com/86Box/86Box into cleanup30
This commit is contained in:
@@ -179,7 +179,8 @@ if(WIN32)
|
||||
enable_language(RC)
|
||||
target_sources(86Box PUBLIC ../win/86Box-qt.rc)
|
||||
target_sources(plat PRIVATE win_joystick_rawinput.c)
|
||||
target_link_libraries(86Box hid)
|
||||
target_sources(ui PRIVATE qt_d3d9renderer.hpp qt_d3d9renderer.cpp)
|
||||
target_link_libraries(86Box hid d3d9)
|
||||
|
||||
# CMake 3.22 messed this up for clang/clang++
|
||||
# See https://gitlab.kitware.com/cmake/cmake/-/issues/22611
|
||||
@@ -239,12 +240,24 @@ if(WIN32)
|
||||
# needed for static builds
|
||||
qt_import_plugins(plat INCLUDE Qt${QT_MAJOR}::QWindowsIntegrationPlugin Qt${QT_MAJOR}::QICOPlugin Qt${QT_MAJOR}::QWindowsVistaStylePlugin)
|
||||
else()
|
||||
install(CODE "
|
||||
get_filename_component(CMAKE_INSTALL_PREFIX_ABSOLUTE \${CMAKE_INSTALL_PREFIX} ABSOLUTE)
|
||||
execute_process(
|
||||
COMMAND $<TARGET_FILE:Qt${QT_MAJOR}::windeployqt>
|
||||
\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/$<TARGET_FILE_NAME:86Box>\")
|
||||
")
|
||||
if(USE_QT6)
|
||||
install(CODE "
|
||||
get_filename_component(CMAKE_INSTALL_PREFIX_ABSOLUTE \${CMAKE_INSTALL_PREFIX} ABSOLUTE)
|
||||
execute_process(
|
||||
COMMAND $<TARGET_FILE:Qt${QT_MAJOR}::windeployqt>
|
||||
\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/$<TARGET_FILE_NAME:86Box>\")
|
||||
")
|
||||
else()
|
||||
find_program(WINDEPLOYQT_EXECUTABLE windeployqt)
|
||||
if(WINDEPLOYQT_EXECUTABLE)
|
||||
install(CODE "
|
||||
get_filename_component(CMAKE_INSTALL_PREFIX_ABSOLUTE \${CMAKE_INSTALL_PREFIX} ABSOLUTE)
|
||||
execute_process(
|
||||
COMMAND ${WINDEPLOYQT_EXECUTABLE}
|
||||
\"\${CMAKE_INSTALL_PREFIX_ABSOLUTE}/$<TARGET_FILE_NAME:86Box>\")
|
||||
")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ plat_vidapi(char* api) {
|
||||
return 3;
|
||||
} else if (!strcasecmp(api, "qt_vulkan")) {
|
||||
return 4;
|
||||
} else if (!strcasecmp(api, "qt_d3d9")) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -73,6 +75,9 @@ char* plat_vidapi_name(int api) {
|
||||
case 4:
|
||||
name = "qt_vulkan";
|
||||
break;
|
||||
case 5:
|
||||
name = "qt_d3d9";
|
||||
break;
|
||||
default:
|
||||
fatal("Unknown renderer: %i\n", api);
|
||||
break;
|
||||
|
||||
167
src/qt/qt_d3d9renderer.cpp
Normal file
167
src/qt/qt_d3d9renderer.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
#include "qt_d3d9renderer.hpp"
|
||||
#include <QResizeEvent>
|
||||
#include <QTimer>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <86box/86box.h>
|
||||
#include <86box/video.h>
|
||||
}
|
||||
|
||||
D3D9Renderer::D3D9Renderer(QWidget *parent)
|
||||
: 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;
|
||||
|
||||
RendererCommon::parentWidget = parent;
|
||||
|
||||
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 = windowHandle;
|
||||
|
||||
HRESULT result = d3d9->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, windowHandle, D3DCREATE_MULTITHREADED | D3DCREATE_HARDWARE_VERTEXPROCESSING, ¶ms, nullptr, &d3d9dev);
|
||||
if (FAILED(result)) result = d3d9->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, windowHandle, D3DCREATE_MULTITHREADED | D3DCREATE_SOFTWARE_VERTEXPROCESSING, ¶ms, 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, 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();
|
||||
dstRect.bottom = destination.bottom();
|
||||
dstRect.left = destination.left();
|
||||
dstRect.right = destination.right();
|
||||
d3d9dev->BeginScene();
|
||||
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(¶ms);
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
void D3D9Renderer::blit(int x, int y, int w, int h)
|
||||
{
|
||||
if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || surfaceInUse) {
|
||||
video_blit_complete();
|
||||
return;
|
||||
}
|
||||
surfaceInUse = true;
|
||||
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 (screenshots) {
|
||||
video_screenshot((uint32_t *) &(buffer32->line[y][x]), 0, 0, 2048);
|
||||
}
|
||||
if (SUCCEEDED(d3d9surface->LockRect(&lockRect, &srcRect, 0))) {
|
||||
for (int y1 = 0; y1 < h; y1++) {
|
||||
video_copy(((uint8_t*)lockRect.pBits) + (y1 * lockRect.Pitch), &(buffer32->line[y + y1][x]), w * 4);
|
||||
}
|
||||
video_blit_complete();
|
||||
d3d9surface->UnlockRect();
|
||||
}
|
||||
else video_blit_complete();
|
||||
surfaceInUse = false;
|
||||
QTimer::singleShot(0, this, [this] { this->update(); });
|
||||
}
|
||||
44
src/qt/qt_d3d9renderer.hpp
Normal file
44
src/qt/qt_d3d9renderer.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#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);
|
||||
~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}, finalized{false};
|
||||
bool alreadyInitialized = false;
|
||||
};
|
||||
|
||||
#endif // D3D9RENDERER_HPP
|
||||
@@ -583,24 +583,25 @@ void MachineStatus::updateTip(int tag)
|
||||
{
|
||||
int category = tag & 0xfffffff0;
|
||||
int item = tag & 0xf;
|
||||
if (!MediaMenu::ptr) return;
|
||||
switch (category) {
|
||||
case SB_CASSETTE:
|
||||
d->cassette.label->setToolTip(MediaMenu::ptr->cassetteMenu->title());
|
||||
if (d->cassette.label && MediaMenu::ptr->cassetteMenu) d->cassette.label->setToolTip(MediaMenu::ptr->cassetteMenu->title());
|
||||
break;
|
||||
case SB_CARTRIDGE:
|
||||
d->cartridge[item].label->setToolTip(MediaMenu::ptr->cartridgeMenus[item]->title());
|
||||
if (d->cartridge[item].label && MediaMenu::ptr->cartridgeMenus[item]) d->cartridge[item].label->setToolTip(MediaMenu::ptr->cartridgeMenus[item]->title());
|
||||
break;
|
||||
case SB_FLOPPY:
|
||||
d->fdd[item].label->setToolTip(MediaMenu::ptr->floppyMenus[item]->title());
|
||||
if (d->fdd[item].label && MediaMenu::ptr->floppyMenus[item]) d->fdd[item].label->setToolTip(MediaMenu::ptr->floppyMenus[item]->title());
|
||||
break;
|
||||
case SB_CDROM:
|
||||
d->cdrom[item].label->setToolTip(MediaMenu::ptr->cdromMenus[item]->title());
|
||||
if (d->cdrom[item].label && MediaMenu::ptr->cdromMenus[item]) d->cdrom[item].label->setToolTip(MediaMenu::ptr->cdromMenus[item]->title());
|
||||
break;
|
||||
case SB_ZIP:
|
||||
d->zip[item].label->setToolTip(MediaMenu::ptr->zipMenus[item]->title());
|
||||
if (d->zip[item].label && MediaMenu::ptr->zipMenus[item]) d->zip[item].label->setToolTip(MediaMenu::ptr->zipMenus[item]->title());
|
||||
break;
|
||||
case SB_MO:
|
||||
d->mo[item].label->setToolTip(MediaMenu::ptr->moMenus[item]->title());
|
||||
if (d->mo[item].label && MediaMenu::ptr->moMenus[item]) d->mo[item].label->setToolTip(MediaMenu::ptr->moMenus[item]->title());
|
||||
break;
|
||||
case SB_HDD:
|
||||
break;
|
||||
|
||||
@@ -120,10 +120,7 @@ main_thread_fn()
|
||||
}
|
||||
} else {
|
||||
/* Just so we dont overload the host OS. */
|
||||
if (drawits < -1 || dopause)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
else
|
||||
std::this_thread::yield();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
/* If needed, handle a screen resize. */
|
||||
|
||||
@@ -281,6 +281,10 @@ 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
|
||||
|
||||
#if !QT_CONFIG(vulkan)
|
||||
if (vid_api == 4) vid_api = 0;
|
||||
@@ -295,6 +299,7 @@ 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->setExclusive(true);
|
||||
|
||||
connect(actGroup, &QActionGroup::triggered, [this](QAction* action) {
|
||||
@@ -316,6 +321,9 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
case 4:
|
||||
ui->stackedWidget->switchRenderer(RendererStack::Renderer::Vulkan);
|
||||
break;
|
||||
case 5:
|
||||
ui->stackedWidget->switchRenderer(RendererStack::Renderer::Direct3D9);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1341,6 +1349,7 @@ void MainWindow::processMacKeyboardInput(bool down, const QKeyEvent* event) {
|
||||
void MainWindow::on_actionFullscreen_triggered() {
|
||||
if (video_fullscreen > 0) {
|
||||
showNormal();
|
||||
if (vid_api == 5) ui->stackedWidget->switchRenderer(RendererStack::Renderer::Direct3D9);
|
||||
ui->menubar->show();
|
||||
if (!hide_status_bar) ui->statusbar->show();
|
||||
if (!hide_tool_bar) ui->toolBar->show();
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>724</width>
|
||||
<height>23</height>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuAction">
|
||||
@@ -105,6 +105,7 @@
|
||||
<addaction name="actionHardware_Renderer_OpenGL_ES"/>
|
||||
<addaction name="actionOpenGL_3_0_Core"/>
|
||||
<addaction name="actionVulkan"/>
|
||||
<addaction name="actionDirect3D_9"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuWindow_scale_factor">
|
||||
<property name="title">
|
||||
@@ -745,6 +746,17 @@
|
||||
<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>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
||||
@@ -510,6 +510,7 @@ void MediaMenu::zipEject(int i) {
|
||||
zip_t *dev = (zip_t *) zip_drives[i].priv;
|
||||
|
||||
zip_disk_close(dev);
|
||||
zip_drives[i].image_path[0] = 0;
|
||||
if (zip_drives[i].bus_type) {
|
||||
/* Signal disk change to the emulated machine. */
|
||||
zip_insert(dev);
|
||||
@@ -609,6 +610,7 @@ void MediaMenu::moEject(int i) {
|
||||
mo_t *dev = (mo_t *) mo_drives[i].priv;
|
||||
|
||||
mo_disk_close(dev);
|
||||
mo_drives[i].image_path[0] = 0;
|
||||
if (mo_drives[i].bus_type) {
|
||||
/* Signal disk change to the emulated machine. */
|
||||
mo_insert(dev);
|
||||
|
||||
@@ -22,13 +22,16 @@ public:
|
||||
|
||||
virtual uint32_t getBytesPerRow() { return 2048 * 4; }
|
||||
|
||||
virtual std::vector<std::tuple<uint8_t *, std::atomic_flag *>> getBuffers() = 0;
|
||||
virtual std::vector<std::tuple<uint8_t *, std::atomic_flag *>> getBuffers() { std::vector<std::tuple<uint8_t*, std::atomic_flag*>> buffers; return buffers; }
|
||||
|
||||
/* Does renderer implement options dialog */
|
||||
virtual bool hasOptions() const { return false; }
|
||||
/* Returns options dialog for renderer */
|
||||
virtual QDialog *getOptions(QWidget *parent) { return nullptr; }
|
||||
|
||||
virtual bool hasBlitFunc() { return false; }
|
||||
virtual void blit(int x, int y, int w, int h) {}
|
||||
|
||||
protected:
|
||||
bool eventDelegate(QEvent *event, bool &result);
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#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"
|
||||
@@ -224,13 +227,27 @@ RendererStack::switchRenderer(Renderer renderer)
|
||||
startblit();
|
||||
if (current) {
|
||||
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);
|
||||
}
|
||||
|
||||
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); });
|
||||
connect(current.get(), &QObject::destroyed, [this, renderer](QObject *) {
|
||||
createRenderer(renderer);
|
||||
disconnect(this, &RendererStack::blit, this, &RendererStack::blitDummy);
|
||||
blitDummied = false;
|
||||
QTimer::singleShot(1000, this, [this]() { this->blitDummied = false; } );
|
||||
});
|
||||
|
||||
current.release()->deleteLater();
|
||||
rendererWindow->hasBlitFunc() ? current.reset() : current.release()->deleteLater();
|
||||
} else {
|
||||
createRenderer(renderer);
|
||||
}
|
||||
@@ -292,6 +309,30 @@ 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);
|
||||
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 = {};
|
||||
endblit();
|
||||
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:
|
||||
{
|
||||
@@ -340,18 +381,41 @@ RendererStack::createRenderer(Renderer renderer)
|
||||
|
||||
currentBuf = 0;
|
||||
|
||||
if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan) {
|
||||
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) {
|
||||
imagebufs = rendererWindow->getBuffers();
|
||||
endblit();
|
||||
emit rendererChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RendererStack::blitDummy(int x, int y, int w, int h)
|
||||
{
|
||||
video_blit_complete();
|
||||
blitDummied = true;
|
||||
}
|
||||
|
||||
void
|
||||
RendererStack::blitRenderer(int x, int y, int w, int h)
|
||||
{
|
||||
if (blitDummied) { blitDummied = false; video_blit_complete(); return; }
|
||||
directBlitting = true;
|
||||
rendererWindow->blit(x, y, w, h);
|
||||
directBlitting = false;
|
||||
}
|
||||
|
||||
// called from blitter thread
|
||||
void
|
||||
RendererStack::blit(int x, int y, int w, int h)
|
||||
RendererStack::blitCommon(int x, int y, int w, int h)
|
||||
{
|
||||
if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == 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) || (buffer32 == NULL) || imagebufs.empty() || std::get<std::atomic_flag *>(imagebufs[currentBuf])->test_and_set() || blitDummied) {
|
||||
video_blit_complete();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ public:
|
||||
OpenGL,
|
||||
OpenGLES,
|
||||
OpenGL3,
|
||||
Vulkan
|
||||
Vulkan,
|
||||
Direct3D9
|
||||
};
|
||||
void switchRenderer(Renderer renderer);
|
||||
|
||||
@@ -72,10 +73,13 @@ 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 blit(int x, int y, int w, int h);
|
||||
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 mousePoll();
|
||||
|
||||
private:
|
||||
@@ -98,6 +102,7 @@ private:
|
||||
|
||||
RendererCommon *rendererWindow { nullptr };
|
||||
std::unique_ptr<QWidget> current;
|
||||
std::atomic<bool> directBlitting{false}, blitDummied{false};
|
||||
};
|
||||
|
||||
#endif // QT_RENDERERCONTAINER_HPP
|
||||
|
||||
@@ -24,6 +24,7 @@ extern "C" {
|
||||
#include <86box/device.h>
|
||||
#include <86box/machine.h>
|
||||
#include <86box/video.h>
|
||||
#include <86box/vid_xga_device.h>
|
||||
}
|
||||
|
||||
#include "qt_deviceconfig.hpp"
|
||||
@@ -47,6 +48,7 @@ void SettingsDisplay::save() {
|
||||
gfxcard = ui->comboBoxVideo->currentData().toInt();
|
||||
voodoo_enabled = ui->checkBoxVoodoo->isChecked() ? 1 : 0;
|
||||
ibm8514_enabled = ui->checkBox8514->isChecked() ? 1 : 0;
|
||||
xga_enabled = ui->checkBoxXga->isChecked() ? 1 : 0;
|
||||
}
|
||||
|
||||
void SettingsDisplay::onCurrentMachineChanged(int machineId) {
|
||||
@@ -101,6 +103,14 @@ void SettingsDisplay::on_pushButtonConfigureVoodoo_clicked() {
|
||||
DeviceConfig::ConfigureDevice(&voodoo_device, 0, qobject_cast<Settings*>(Settings::settings));
|
||||
}
|
||||
|
||||
void SettingsDisplay::on_pushButtonConfigureXga_clicked() {
|
||||
if (machine_has_bus(machineId, MACHINE_BUS_MCA) > 0) {
|
||||
DeviceConfig::ConfigureDevice(&xga_device, 0, qobject_cast<Settings*>(Settings::settings));
|
||||
} else {
|
||||
DeviceConfig::ConfigureDevice(&xga_isa_device, 0, qobject_cast<Settings*>(Settings::settings));
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) {
|
||||
if (index < 0) {
|
||||
return;
|
||||
@@ -119,10 +129,20 @@ void SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) {
|
||||
bool has_MCA = machine_has_bus(machineId, MACHINE_BUS_MCA) > 0;
|
||||
ui->checkBox8514->setEnabled(hasIsa16 || has_MCA);
|
||||
if (hasIsa16 || has_MCA) {
|
||||
ui->checkBox8514->setChecked(ibm8514_enabled > 0);
|
||||
ui->checkBox8514->setChecked(ibm8514_enabled);
|
||||
}
|
||||
|
||||
ui->checkBoxXga->setEnabled(hasIsa16 || has_MCA);
|
||||
if (hasIsa16 || has_MCA)
|
||||
ui->checkBoxXga->setChecked(xga_enabled);
|
||||
|
||||
ui->pushButtonConfigureXga->setEnabled((hasIsa16 || has_MCA) && ui->checkBoxXga->isChecked());
|
||||
}
|
||||
|
||||
void SettingsDisplay::on_checkBoxVoodoo_stateChanged(int state) {
|
||||
ui->pushButtonConfigureVoodoo->setEnabled(state == Qt::Checked);
|
||||
}
|
||||
|
||||
void SettingsDisplay::on_checkBoxXga_stateChanged(int state) {
|
||||
ui->pushButtonConfigureXga->setEnabled(state == Qt::Checked);
|
||||
}
|
||||
|
||||
@@ -22,8 +22,10 @@ public slots:
|
||||
|
||||
private slots:
|
||||
void on_checkBoxVoodoo_stateChanged(int state);
|
||||
void on_checkBoxXga_stateChanged(int state);
|
||||
void on_comboBoxVideo_currentIndexChanged(int index);
|
||||
void on_pushButtonConfigureVoodoo_clicked();
|
||||
void on_pushButtonConfigureXga_clicked();
|
||||
void on_pushButtonConfigure_clicked();
|
||||
|
||||
private:
|
||||
|
||||
@@ -70,7 +70,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="3" column="2">
|
||||
<widget class="QPushButton" name="pushButtonConfigureXga">
|
||||
<property name="text">
|
||||
<string>Configure</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkBoxXga">
|
||||
<property name="text">
|
||||
<string>XGA</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
||||
Reference in New Issue
Block a user