diff --git a/Core/Config.cpp b/Core/Config.cpp index 73135f1a82..ff0f3c40e7 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -384,6 +384,7 @@ static int DefaultAndroidHwScale() { } static ConfigSetting graphicsSettings[] = { + ReportedConfigSetting("GPUBackend", &g_Config.iGPUBackend, 0), ConfigSetting("ShowFPSCounter", &g_Config.iShowFPSCounter, 0), ReportedConfigSetting("RenderingMode", &g_Config.iRenderingMode, &DefaultRenderingMode), ConfigSetting("SoftwareRendering", &g_Config.bSoftwareRendering, false), @@ -815,6 +816,8 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { } CleanRecent(); + + iGPUBackend = 0; } void Config::Save() { diff --git a/Core/Config.h b/Core/Config.h index 9a87a7c952..0994a1d48e 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -39,6 +39,12 @@ enum { ROTATION_LOCKED_VERTICAL180 = 4, }; +// Software is not among these because it will have one of these perform the blit to display. +enum { + GPU_BACKEND_OPENGL = 0, + GPU_BACKEND_DIRECT3D9 = 1, +}; + namespace http { class Download; class Downloader; @@ -100,8 +106,8 @@ public: std::vector vPinnedPaths; std::string sLanguageIni; - // GFX + int iGPUBackend; bool bSoftwareRendering; bool bHardwareTransform; // only used in the GLES backend bool bSoftwareSkinning; // may speed up some games diff --git a/Core/Core.cpp b/Core/Core.cpp index d93d02a74a..e2fcf0c536 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -33,6 +33,7 @@ #ifdef _WIN32 #ifndef _XBOX #include "Windows/OpenGLBase.h" +#include "Windows/D3D9Base.h" #endif #include "Windows/InputDevice.h" #endif @@ -151,6 +152,19 @@ void UpdateRunLoop() { } } +void GPU_SwapBuffers() { + switch (g_Config.iGPUBackend) { + case GPU_BACKEND_OPENGL: + GL_SwapBuffers(); + break; +#ifdef _WIN32 + case GPU_BACKEND_DIRECT3D9: + D3D9_SwapBuffers(); + break; +#endif + } +} + void Core_RunLoop() { while ((GetUIState() != UISTATE_INGAME || !PSP_IsInited()) && GetUIState() != UISTATE_EXIT) { time_update(); @@ -165,7 +179,7 @@ void Core_RunLoop() { if (sleepTime > 0) Sleep(sleepTime); if (!windowHidden) { - GL_SwapBuffers(); + GPU_SwapBuffers(); } #else UpdateRunLoop(); @@ -177,7 +191,7 @@ void Core_RunLoop() { UpdateRunLoop(); #if defined(USING_WIN_UI) if (!windowHidden && !Core_IsStepping()) { - GL_SwapBuffers(); + GPU_SwapBuffers(); } #endif } diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 0e10380169..ad821d5936 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -707,7 +707,14 @@ void EmuScreen::render() { screenManager()->getUIContext()->RebindTexture(); Thin3DContext *thin3d = screenManager()->getThin3DContext(); - glstate.viewport.set(0, 0, pixel_xres, pixel_yres); + T3DViewport viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = pixel_xres; + viewport.Height = pixel_yres; + viewport.MaxDepth = 1.0; + viewport.MinDepth = 0.0; + thin3d->SetViewports(1, &viewport); glstate.viewport.restore(); thin3d->SetBlendState(thin3d->GetBlendStatePreset(BS_STANDARD_ALPHA)); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 45e42612e3..5a9b8903c3 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -38,6 +38,7 @@ #include "ext/jpge/jpge.h" #include "Windows/DSoundStream.h" #include "Windows/WndMainWindow.h" +#include "Windows/D3D9Base.h" #endif #include "base/display.h" @@ -48,7 +49,7 @@ #include "file/zip_read.h" #include "thread/thread.h" #include "net/http_client.h" -#include "gfx_es2/gl_state.h" +#include "gfx_es2/gl_state.h" // only for screenshot! #include "gfx_es2/draw_text.h" #include "gfx_es2/draw_buffer.h" #include "gfx/gl_lost_manager.h" @@ -112,7 +113,7 @@ static UI::Theme ui_theme; #include "android/android-ndk-profiler/prof.h" #endif -Texture *uiTexture; +Thin3DTexture *uiTexture; ScreenManager *screenManager; std::string config_filename; @@ -464,9 +465,12 @@ void NativeInit(int argc, const char *argv[], void NativeInitGraphics() { FPU_SetFastMode(); - thin3d = T3DCreateGLContext(); - - CheckGLExtensions(); + if (g_Config.iGPUBackend == GPU_BACKEND_OPENGL) { + thin3d = T3DCreateGLContext(); + CheckGLExtensions(); + } else { + thin3d = D3D9_CreateThin3DContext(); + } ui_draw2d.SetAtlas(&ui_atlas); ui_draw2d_front.SetAtlas(&ui_atlas); @@ -489,18 +493,6 @@ void NativeInitGraphics() { ui_theme.sliderKnob = I_CIRCLE; ui_theme.dropShadow4Grid = I_DROP_SHADOW; - /* - ui_theme.buttonStyle.background = UI::Drawable(UI::DRAW_4GRID, I_BUTTON); - ui_theme.buttonStyle.fgColor = 0xFFFFFFFF; - ui_theme.buttonStyle.image = I_BUTTON; - ui_theme.buttonFocusedStyle.background = UI::Drawable(UI::DRAW_4GRID, I_BUTTON, 0xFFe0e0e0); - ui_theme.buttonFocusedStyle.fgColor = 0xFFFFFFFF; - ui_theme.buttonDownStyle.background = UI::Drawable(UI::DRAW_4GRID, I_BUTTON_SELECTED, 0xFFFFFFFF); - ui_theme.buttonDownStyle.fgColor = 0xFFFFFFFF; - ui_theme.buttonDisabledStyle.background = UI::Drawable(UI::DRAW_4GRID, I_BUTTON, 0xFF404040); - ui_theme.buttonDisabledStyle.fgColor = 0xFF707070; - */ - ui_theme.itemStyle.background = UI::Drawable(0x55000000); ui_theme.itemStyle.fgColor = 0xFFFFFFFF; ui_theme.itemFocusedStyle.background = UI::Drawable(0xFFedc24c); @@ -531,16 +523,16 @@ void NativeInitGraphics() { ui_draw2d.Init(thin3d); ui_draw2d_front.Init(thin3d); - uiTexture = new Texture(); #ifdef USING_QT_UI - if (!uiTexture->Load("ui_atlas_lowmem.zim")) { + uiTexture = thin3d->CreateTextureFromFile("ui_atlas_lowmem.zim"); + if (!uiTexture) { #else - if (!uiTexture->Load("ui_atlas.zim")) { + uiTexture = thin3d->CreateTextureFromFile("ui_atlas.zim"); + if (!uiTexture) { #endif PanicAlert("Failed to load ui_atlas.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory."); ELOG("Failed to load ui_atlas.zim"); } - uiTexture->Bind(0); uiContext = new UIContext(); uiContext->theme = &ui_theme; @@ -571,8 +563,7 @@ void NativeShutdownGraphics() { g_gameInfoCache.Clear(); - delete uiTexture; - uiTexture = NULL; + uiTexture->Release(); delete uiContext; uiContext = NULL; @@ -584,7 +575,13 @@ void NativeShutdownGraphics() { } void TakeScreenshot() { + if (g_Config.iGPUBackend != GPU_BACKEND_OPENGL) { + // Not yet supported + return; + } + g_TakeScreenshot = false; + #if defined(_WIN32) || (defined(USING_QT_UI) && !defined(MOBILE_DEVICE)) mkDir(g_Config.memCardDirectory + "/PSP/SCREENSHOT"); @@ -675,15 +672,23 @@ void DrawDownloadsOverlay(UIContext &dc) { void NativeRender() { g_GameManager.Update(); - glstate.depthWrite.set(GL_TRUE); - glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + T3DViewport viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = pixel_xres; + viewport.Height = pixel_yres; + viewport.MaxDepth = 1.0; + viewport.MinDepth = 0.0; + thin3d->SetViewports(1, &viewport); - // Clearing the screen at the start of the frame is an optimization for tiled mobile GPUs, as it then doesn't need to keep it around between frames. - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + if (g_Config.iGPUBackend == GPU_BACKEND_OPENGL) { + glstate.depthWrite.set(GL_TRUE); + glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glstate.Restore(); + } - glstate.viewport.set(0, 0, pixel_xres, pixel_yres); - glstate.Restore(); + thin3d->Clear(T3DClear::COLOR | T3DClear::DEPTH | T3DClear::STENCIL, 0xFF000000, 0.0f, 0); + thin3d->SetTargetSize(pixel_xres, pixel_yres); float xres = dp_xres; float yres = dp_yres; @@ -695,7 +700,6 @@ void NativeRender() { ui_draw2d.SetDrawMatrix(ortho); ui_draw2d_front.SetDrawMatrix(ortho); - // glsl_bind(UIShader_Get()); screenManager->render(); diff --git a/Windows/D3D9Base.cpp b/Windows/D3D9Base.cpp new file mode 100644 index 0000000000..1b6a61d130 --- /dev/null +++ b/Windows/D3D9Base.cpp @@ -0,0 +1,109 @@ +#include "Common/CommonWindows.h" +#include + +#include "base/logging.h" +#include "util/text/utf8.h" +#include "i18n/i18n.h" + +#include "Windows/D3D9Base.h" +#include "thin3d/thin3d.h" + +static LPDIRECT3D9 d3d; +static LPDIRECT3DDEVICE9 device; +static HDC hDC; // Private GDI Device Context +static HGLRC hRC; // Permanent Rendering Context +static HWND hWnd; // Holds Our Window Handle + +static int xres, yres; + +// TODO: Make config? +static bool enableGLDebug = true; + +void D3D9_SwapBuffers() { + device->EndScene(); + device->Present(NULL, NULL, NULL, NULL); + device->BeginScene(); +} + +Thin3DContext *D3D9_CreateThin3DContext() { + return T3DCreateDX9Context(device); +} + +bool D3D9_Init(HWND hWnd, bool windowed, std::string *error_message) { + d3d = Direct3DCreate9(D3D_SDK_VERSION); + if (!d3d) { + ELOG("Failed to create D3D context"); + return false; + } + + RECT rc; + GetClientRect(hWnd, &rc); + int xres = rc.right - rc.left; + int yres = rc.bottom - rc.top; + + D3DCAPS9 d3dCaps; + + D3DDISPLAYMODE d3ddm; + if (FAILED(d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))) { + d3d->Release(); + return false; + } + + int adapter = D3DADAPTER_DEFAULT; + if (FAILED(d3d->GetDeviceCaps(adapter, D3DDEVTYPE_HAL, &d3dCaps))) { + d3d->Release(); + return false; + } + + HRESULT hr; + if (FAILED(hr = d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + d3ddm.Format, + D3DUSAGE_DEPTHSTENCIL, + D3DRTYPE_SURFACE, + D3DFMT_D16))) { + if (hr == D3DERR_NOTAVAILABLE) { + d3d->Release(); + return false; + } + } + + DWORD dwBehaviorFlags = D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE; + if (d3dCaps.VertexProcessingCaps != 0) + dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING; + else + dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; + + D3DPRESENT_PARAMETERS pp; + memset(&pp, 0, sizeof(pp)); + pp.BackBufferWidth = xres; + pp.BackBufferHeight = yres; + pp.BackBufferFormat = d3ddm.Format; + pp.MultiSampleType = D3DMULTISAMPLE_NONE; + pp.SwapEffect = D3DSWAPEFFECT_DISCARD; + pp.Windowed = windowed; + pp.hDeviceWindow = hWnd; + pp.EnableAutoDepthStencil = true; + pp.AutoDepthStencilFormat = D3DFMT_D16; + + hr = d3d->CreateDevice(adapter, D3DDEVTYPE_HAL, hWnd, dwBehaviorFlags, &pp, &device); + if (FAILED(hr)) { + ELOG("Failed to create D3D device"); + d3d->Release(); + return false; + } + + device->BeginScene(); + return true; +} + +void D3D9_Resize(HWND window) { + +} + +void D3D9_Shutdown() { + device->EndScene(); + device->Release(); + d3d->Release(); + hWnd = NULL; +} diff --git a/Windows/D3D9Base.h b/Windows/D3D9Base.h new file mode 100644 index 0000000000..716402cc14 --- /dev/null +++ b/Windows/D3D9Base.h @@ -0,0 +1,13 @@ +// Modelled on OpenD3DBase. Might make a cleaner interface later. + +#pragma once + +#include "Common/CommonWindows.h" + +class Thin3DContext; + +bool D3D9_Init(HWND window, bool windowed, std::string *error_message); +void D3D9_Shutdown(); +void D3D9_Resize(HWND window); +void D3D9_SwapBuffers(); +Thin3DContext *D3D9_CreateThin3DContext(); \ No newline at end of file diff --git a/Windows/EmuThread.cpp b/Windows/EmuThread.cpp index 29a3294e78..02fb35f110 100644 --- a/Windows/EmuThread.cpp +++ b/Windows/EmuThread.cpp @@ -106,7 +106,7 @@ unsigned int WINAPI TheThread(void *) std::string error_string; if (!host->InitGL(&error_string)) { - Reporting::ReportMessage("OpenGL init error: %s", error_string.c_str()); + Reporting::ReportMessage("Graphics init error: %s", error_string.c_str()); std::string full_error = StringFromFormat( "Failed initializing OpenGL. Try upgrading your graphics drivers.\n\nError message:\n\n%s", error_string.c_str()); MessageBox(0, ConvertUTF8ToWString(full_error).c_str(), L"OpenGL Error", MB_OK | MB_ICONERROR); ERROR_LOG(BOOT, full_error.c_str()); diff --git a/Windows/OpenGLBase.cpp b/Windows/OpenGLBase.cpp index 437bac92f3..f9694b3836 100644 --- a/Windows/OpenGLBase.cpp +++ b/Windows/OpenGLBase.cpp @@ -1,10 +1,6 @@ -// NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003. - -#include "util/text/utf8.h" #include "Common/CommonWindows.h" #include "native/gfx_es2/gl_state.h" #include "native/gfx/gl_common.h" -#include "util/text/utf8.h" #include "GL/gl.h" #include "GL/wglew.h" #include "util/text/utf8.h" diff --git a/Windows/OpenGLBase.h b/Windows/OpenGLBase.h index e900b4bed5..e103ece39e 100644 --- a/Windows/OpenGLBase.h +++ b/Windows/OpenGLBase.h @@ -1,5 +1,3 @@ -// NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003. - #pragma once #include "Common/CommonWindows.h" diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index e501733af7..833939c1a1 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -277,6 +277,7 @@ + @@ -330,6 +331,7 @@ + diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index 92331e214d..9d7a6df7c5 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -67,6 +67,9 @@ Windows\System + + Windows\System + Windows\System @@ -187,6 +190,9 @@ Windows\System + + Windows\System + Windows\System @@ -326,4 +332,4 @@ Resource Files - \ No newline at end of file + diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index e023bd69e3..b5f0060b62 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -42,6 +42,7 @@ #include "WindowsHost.h" #include "WndMainWindow.h" #include "OpenGLBase.h" +#include "D3D9Base.h" #include "Windows/Debugger/DebuggerShared.h" #include "Windows/Debugger/Debugger_Disasm.h" @@ -88,14 +89,26 @@ WindowsHost::WindowsHost(HWND mainWindow, HWND displayWindow) SetConsolePosition(); } -bool WindowsHost::InitGL(std::string *error_message) -{ - return GL_Init(displayWindow_, error_message); +bool WindowsHost::InitGL(std::string *error_message) { + switch (g_Config.iGPUBackend) { + case GPU_BACKEND_OPENGL: + return GL_Init(displayWindow_, error_message); + case GPU_BACKEND_DIRECT3D9: + return D3D9_Init(displayWindow_, true, error_message); + default: + return false; + } } -void WindowsHost::ShutdownGL() -{ - GL_Shutdown(); +void WindowsHost::ShutdownGL() { + switch (g_Config.iGPUBackend) { + case GPU_BACKEND_OPENGL: + GL_Shutdown(); + break; + case GPU_BACKEND_DIRECT3D9: + D3D9_Shutdown(); + break; + } PostMessage(mainWindow_, WM_CLOSE, 0, 0); } diff --git a/headless/Headless.cpp b/headless/Headless.cpp index db2b4c6914..4af9a6d855 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -66,7 +66,8 @@ public: }; struct InputState; -// Temporary hack around annoying linking error. +// Temporary hacks around annoying linking errors. +void D3D9_SwapBuffers() { } void GL_SwapBuffers() { } void NativeUpdate(InputState &input_state) { } void NativeRender() { }