diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp index 7f764c03be..50941a9f45 100644 --- a/UWP/PPSSPP_UWPMain.cpp +++ b/UWP/PPSSPP_UWPMain.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "PPSSPP_UWPMain.h" +#include #include #include "base/basictypes.h" @@ -323,6 +324,7 @@ void PPSSPP_UWPMain::LoadStorageFile(StorageFile ^file) { UWPGraphicsContext::UWPGraphicsContext(std::shared_ptr resources) { draw_ = Draw::T3DCreateD3D11Context( resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetDeviceFeatureLevel(), 0); + assert(draw_->CreatePresets()); } void UWPGraphicsContext::Shutdown() { diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index bed1ff2f8d..0917faa2f0 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -2,6 +2,7 @@ #include "Common/CommonWindows.h" #include +#include #include "base/logging.h" #include "util/text/utf8.h" @@ -139,6 +140,7 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { #endif draw_ = Draw::T3DCreateD3D11Context(device_, context_, device1_, context1_, featureLevel_, hWnd_); + assert(draw_->CreatePresets()); // If we can run D3D11, there's a compiler installed. I think. int width; int height; diff --git a/Windows/GPU/D3D9Context.cpp b/Windows/GPU/D3D9Context.cpp index 096251677f..ec7ffdb0ca 100644 --- a/Windows/GPU/D3D9Context.cpp +++ b/Windows/GPU/D3D9Context.cpp @@ -165,6 +165,13 @@ bool D3D9Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { //deviceEx->SetMaximumFrameLatency(1); } draw_ = Draw::T3DCreateDX9Context(d3d_, d3dEx_, adapterId_, device_, deviceEx_); + if (!draw_->CreatePresets()) { + // Shader compiler not installed? Return an error so we can fall back to GL. + device_->Release(); + d3d_->Release(); + *error_message = "DirectX9 runtime not correctly installed. Please install."; + return false; + } if (draw_) draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, 0, 0, nullptr); return true; diff --git a/Windows/GPU/WindowsGLContext.cpp b/Windows/GPU/WindowsGLContext.cpp index d1b6b73563..febdcc799f 100644 --- a/Windows/GPU/WindowsGLContext.cpp +++ b/Windows/GPU/WindowsGLContext.cpp @@ -15,8 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -// TODO: What a mess this is :( - +#include #include "Common/Log.h" #include "Common/CommonWindows.h" #include "gfx/gl_common.h" @@ -358,6 +357,7 @@ bool WindowsGLContext::Init(HINSTANCE hInst, HWND window, std::string *error_mes CheckGLExtensions(); draw_ = Draw::T3DCreateGLContext(); + assert(draw_->CreatePresets()); // if we get this far, there will always be a GLSL compiler capable of compiling these. CHECK_GL_ERROR_IF_DEBUG(); return true; // Success } diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 0f4d18118f..a4cda9b9c0 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -203,7 +203,7 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m } draw_ = Draw::T3DCreateVulkanContext(g_Vulkan); - + assert(draw_->CreatePresets()); // Doesn't fail, we include the compiler. return true; } diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index c04d46c309..2c18f4fef4 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -133,6 +133,7 @@ bool AndroidEGLGraphicsContext::Init(ANativeWindow *wnd, int backbufferWidth, in gl->MakeCurrent(); CheckGLExtensions(); draw_ = Draw::T3DCreateGLContext(); + assert(draw_->CreatePresets()); // There will always be a GLSL compiler capable of compiling these. return true; } @@ -157,6 +158,7 @@ public: AndroidJavaEGLGraphicsContext() { CheckGLExtensions(); draw_ = Draw::T3DCreateGLContext(); + assert(draw_->CreatePresets()); } ~AndroidJavaEGLGraphicsContext() { delete draw_; @@ -310,6 +312,7 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX, } g_Vulkan->InitObjects(true); draw_ = Draw::T3DCreateVulkanContext(g_Vulkan); + assert(draw_->CreatePresets()); // Doesn't fail, we ship the compiler. return true; } diff --git a/ext/native/base/PCMain.cpp b/ext/native/base/PCMain.cpp index dc734a5048..64c6a7c547 100644 --- a/ext/native/base/PCMain.cpp +++ b/ext/native/base/PCMain.cpp @@ -27,6 +27,7 @@ SDLJoystick *joystick = NULL; #endif #include +#include #include "base/display.h" #include "base/logging.h" @@ -51,6 +52,7 @@ public: GLDummyGraphicsContext() { CheckGLExtensions(); draw_ = Draw::T3DCreateGLContext(); + assert(draw_->CreatePresets()); } ~GLDummyGraphicsContext() { delete draw_; } diff --git a/ext/native/base/QtMain.h b/ext/native/base/QtMain.h index 0fda2cde4a..a8e947be03 100644 --- a/ext/native/base/QtMain.h +++ b/ext/native/base/QtMain.h @@ -18,6 +18,8 @@ QTM_USE_NAMESPACE #endif #endif +#include + #include "base/display.h" #include "base/logging.h" #include "base/timeutil.h" @@ -42,6 +44,7 @@ class QtDummyGraphicsContext : public DummyGraphicsContext { public: QtDummyGraphicsContext() { draw_ = Draw::T3DCreateGLContext(); + assert(draw_->CreatePresets()); } ~QtDummyGraphicsContext() { delete draw_; diff --git a/ext/native/thin3d/thin3d.cpp b/ext/native/thin3d/thin3d.cpp index 44dc740664..1de3bbba4d 100644 --- a/ext/native/thin3d/thin3d.cpp +++ b/ext/native/thin3d/thin3d.cpp @@ -299,12 +299,14 @@ static ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const st return nullptr; } -void DrawContext::CreatePresets() { +bool DrawContext::CreatePresets() { vsPresets_[VS_TEXTURE_COLOR_2D] = CreateShader(this, ShaderStage::VERTEX, vsTexCol); vsPresets_[VS_COLOR_2D] = CreateShader(this, ShaderStage::VERTEX, vsCol); fsPresets_[FS_TEXTURE_COLOR_2D] = CreateShader(this, ShaderStage::FRAGMENT, fsTexCol); fsPresets_[FS_COLOR_2D] = CreateShader(this, ShaderStage::FRAGMENT, fsCol); + + return vsPresets_[VS_TEXTURE_COLOR_2D] && vsPresets_[VS_COLOR_2D] && fsPresets_[FS_TEXTURE_COLOR_2D] && fsPresets_[FS_COLOR_2D]; } DrawContext::~DrawContext() { diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 3c8dcc73e0..78c8ea6b2b 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -583,6 +583,7 @@ struct RenderPassInfo { class DrawContext { public: virtual ~DrawContext(); + bool CreatePresets(); virtual const DeviceCaps &GetDeviceCaps() const = 0; virtual uint32_t GetDataFormatSupport(DataFormat fmt) const = 0; @@ -691,8 +692,6 @@ public: virtual void FlushState() {} protected: - void CreatePresets(); - ShaderModule *vsPresets_[VS_MAX_PRESET]; ShaderModule *fsPresets_[FS_MAX_PRESET]; diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 45db38b91a..554bdca80b 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -242,7 +242,6 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de } dxgiDevice->Release(); } - CreatePresets(); // Temp texture for read-back of small images. Custom textures are created on demand for larger ones. // TODO: Should really benchmark if this extra complexity has any benefit. diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index 6665fa263d..ad40c89a44 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -585,7 +585,6 @@ private: D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx) : d3d_(d3d), d3dEx_(d3dEx), adapterId_(adapterId), device_(device), deviceEx_(deviceEx), caps_{} { - CreatePresets(); if (FAILED(d3d->GetAdapterIdentifier(adapterId, 0, &identifier_))) { ELOG("Failed to get adapter identifier: %d", adapterId); } @@ -633,6 +632,10 @@ Pipeline *D3D9Context::CreateGraphicsPipeline(const PipelineDesc &desc) { } D3D9Pipeline *pipeline = new D3D9Pipeline(device_); for (auto iter : desc.shaders) { + if (!iter) { + ELOG("NULL shader passed to CreateGraphicsPipeline"); + return false; + } if (iter->GetStage() == ShaderStage::FRAGMENT) { pipeline->pshader = static_cast(iter); } @@ -947,20 +950,24 @@ void D3D9Context::SetBlendFactor(float color[4]) { } bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, size_t size) { - LPD3DXMACRO defines = NULL; - LPD3DXINCLUDE includes = NULL; + LPD3DXMACRO defines = nullptr; + LPD3DXINCLUDE includes = nullptr; DWORD flags = 0; - LPD3DXBUFFER codeBuffer; - LPD3DXBUFFER errorBuffer; + LPD3DXBUFFER codeBuffer = nullptr; + LPD3DXBUFFER errorBuffer = nullptr; const char *source = (const char *)data; const char *profile = stage_ == ShaderStage::FRAGMENT ? "ps_2_0" : "vs_2_0"; HRESULT hr = dyn_D3DXCompileShader(source, (UINT)strlen(source), defines, includes, "main", profile, flags, &codeBuffer, &errorBuffer, nullptr); if (FAILED(hr)) { - const char *error = (const char *)errorBuffer->GetBufferPointer(); + const char *error = errorBuffer ? (const char *)errorBuffer->GetBufferPointer() : "(no errorbuffer returned)"; + if (hr == ERROR_MOD_NOT_FOUND) { + // No D3D9-compatible shader compiler installed. + error = "D3D9 shader compiler not installed"; + } OutputDebugStringA(source); OutputDebugStringA(error); - errorBuffer->Release(); - + if (errorBuffer) + errorBuffer->Release(); if (codeBuffer) codeBuffer->Release(); return false; diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index b8dfbb025d..65dcdd4a33 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -591,8 +591,6 @@ private: }; OpenGLContext::OpenGLContext() { - CreatePresets(); - // TODO: Detect more caps if (gl_extensions.IsGLES) { if (gl_extensions.OES_packed_depth_stencil || gl_extensions.OES_depth24) { diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index bf5fa86959..d559bc84c1 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -719,7 +719,6 @@ VKContext::VKContext(VulkanContext *vulkan) viewport_.minDepth = 0.0f; viewport_.maxDepth = 0.0f; memset(boundTextures_, 0, sizeof(boundTextures_)); - CreatePresets(); VkDescriptorPoolSize dpTypes[2]; dpTypes[0].descriptorCount = 200; diff --git a/headless/SDLHeadlessHost.cpp b/headless/SDLHeadlessHost.cpp index 8e0e1ab082..5b96f09953 100644 --- a/headless/SDLHeadlessHost.cpp +++ b/headless/SDLHeadlessHost.cpp @@ -19,6 +19,7 @@ #include #include +#include #include "gfx/gl_lost_manager.h" #include "headless/SDLHeadlessHost.h" @@ -54,6 +55,7 @@ public: GLDummyGraphicsContext() { CheckGLExtensions(); draw_ = Draw::T3DCreateGLContext(); + assert(draw_->CreatePresets()); } ~GLDummyGraphicsContext() { delete draw_; } diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 1cb6e5230f..02a3b343e1 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -8,6 +8,7 @@ #import "ViewController.h" #import "AudioEngine.h" #import +#include #include "base/display.h" #include "base/timeutil.h" @@ -38,6 +39,7 @@ public: IOSDummyGraphicsContext() { CheckGLExtensions(); draw_ = Draw::T3DCreateGLContext(); + assert(draw_->CreatePresets()); } ~IOSDummyGraphicsContext() { delete draw_;