Allow D3D9 context creation to bail if shader compilation fails (D3D9 runtime not installed).

Fixes an issue where after switching to D3D9 on a PC without the D3D9 runtime, it's impossible to start PPSSPP anymore.
This commit is contained in:
Henrik Rydgård 2017-10-20 11:53:07 +02:00
parent a6cf2e6ca0
commit 017d3da067
16 changed files with 45 additions and 18 deletions

View file

@ -1,6 +1,7 @@
#include "pch.h" #include "pch.h"
#include "PPSSPP_UWPMain.h" #include "PPSSPP_UWPMain.h"
#include <cassert>
#include <mutex> #include <mutex>
#include "base/basictypes.h" #include "base/basictypes.h"
@ -323,6 +324,7 @@ void PPSSPP_UWPMain::LoadStorageFile(StorageFile ^file) {
UWPGraphicsContext::UWPGraphicsContext(std::shared_ptr<DX::DeviceResources> resources) { UWPGraphicsContext::UWPGraphicsContext(std::shared_ptr<DX::DeviceResources> resources) {
draw_ = Draw::T3DCreateD3D11Context( draw_ = Draw::T3DCreateD3D11Context(
resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetDeviceFeatureLevel(), 0); resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetDeviceFeatureLevel(), 0);
assert(draw_->CreatePresets());
} }
void UWPGraphicsContext::Shutdown() { void UWPGraphicsContext::Shutdown() {

View file

@ -2,6 +2,7 @@
#include "Common/CommonWindows.h" #include "Common/CommonWindows.h"
#include <d3d11.h> #include <d3d11.h>
#include <cassert>
#include "base/logging.h" #include "base/logging.h"
#include "util/text/utf8.h" #include "util/text/utf8.h"
@ -139,6 +140,7 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
#endif #endif
draw_ = Draw::T3DCreateD3D11Context(device_, context_, device1_, context1_, featureLevel_, hWnd_); 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 width;
int height; int height;

View file

@ -165,6 +165,13 @@ bool D3D9Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
//deviceEx->SetMaximumFrameLatency(1); //deviceEx->SetMaximumFrameLatency(1);
} }
draw_ = Draw::T3DCreateDX9Context(d3d_, d3dEx_, adapterId_, device_, deviceEx_); 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_) if (draw_)
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, 0, 0, nullptr); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, 0, 0, nullptr);
return true; return true;

View file

@ -15,8 +15,7 @@
// Official git repository and contact information can be found at // Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// TODO: What a mess this is :( #include <cassert>
#include "Common/Log.h" #include "Common/Log.h"
#include "Common/CommonWindows.h" #include "Common/CommonWindows.h"
#include "gfx/gl_common.h" #include "gfx/gl_common.h"
@ -358,6 +357,7 @@ bool WindowsGLContext::Init(HINSTANCE hInst, HWND window, std::string *error_mes
CheckGLExtensions(); CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext(); 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(); CHECK_GL_ERROR_IF_DEBUG();
return true; // Success return true; // Success
} }

View file

@ -203,7 +203,7 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m
} }
draw_ = Draw::T3DCreateVulkanContext(g_Vulkan); draw_ = Draw::T3DCreateVulkanContext(g_Vulkan);
assert(draw_->CreatePresets()); // Doesn't fail, we include the compiler.
return true; return true;
} }

View file

@ -133,6 +133,7 @@ bool AndroidEGLGraphicsContext::Init(ANativeWindow *wnd, int backbufferWidth, in
gl->MakeCurrent(); gl->MakeCurrent();
CheckGLExtensions(); CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext(); draw_ = Draw::T3DCreateGLContext();
assert(draw_->CreatePresets()); // There will always be a GLSL compiler capable of compiling these.
return true; return true;
} }
@ -157,6 +158,7 @@ public:
AndroidJavaEGLGraphicsContext() { AndroidJavaEGLGraphicsContext() {
CheckGLExtensions(); CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext(); draw_ = Draw::T3DCreateGLContext();
assert(draw_->CreatePresets());
} }
~AndroidJavaEGLGraphicsContext() { ~AndroidJavaEGLGraphicsContext() {
delete draw_; delete draw_;
@ -310,6 +312,7 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX,
} }
g_Vulkan->InitObjects(true); g_Vulkan->InitObjects(true);
draw_ = Draw::T3DCreateVulkanContext(g_Vulkan); draw_ = Draw::T3DCreateVulkanContext(g_Vulkan);
assert(draw_->CreatePresets()); // Doesn't fail, we ship the compiler.
return true; return true;
} }

View file

@ -27,6 +27,7 @@ SDLJoystick *joystick = NULL;
#endif #endif
#include <algorithm> #include <algorithm>
#include <cassert>
#include "base/display.h" #include "base/display.h"
#include "base/logging.h" #include "base/logging.h"
@ -51,6 +52,7 @@ public:
GLDummyGraphicsContext() { GLDummyGraphicsContext() {
CheckGLExtensions(); CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext(); draw_ = Draw::T3DCreateGLContext();
assert(draw_->CreatePresets());
} }
~GLDummyGraphicsContext() { delete draw_; } ~GLDummyGraphicsContext() { delete draw_; }

View file

@ -18,6 +18,8 @@ QTM_USE_NAMESPACE
#endif #endif
#endif #endif
#include <cassert>
#include "base/display.h" #include "base/display.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/timeutil.h" #include "base/timeutil.h"
@ -42,6 +44,7 @@ class QtDummyGraphicsContext : public DummyGraphicsContext {
public: public:
QtDummyGraphicsContext() { QtDummyGraphicsContext() {
draw_ = Draw::T3DCreateGLContext(); draw_ = Draw::T3DCreateGLContext();
assert(draw_->CreatePresets());
} }
~QtDummyGraphicsContext() { ~QtDummyGraphicsContext() {
delete draw_; delete draw_;

View file

@ -299,12 +299,14 @@ static ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const st
return nullptr; return nullptr;
} }
void DrawContext::CreatePresets() { bool DrawContext::CreatePresets() {
vsPresets_[VS_TEXTURE_COLOR_2D] = CreateShader(this, ShaderStage::VERTEX, vsTexCol); vsPresets_[VS_TEXTURE_COLOR_2D] = CreateShader(this, ShaderStage::VERTEX, vsTexCol);
vsPresets_[VS_COLOR_2D] = CreateShader(this, ShaderStage::VERTEX, vsCol); vsPresets_[VS_COLOR_2D] = CreateShader(this, ShaderStage::VERTEX, vsCol);
fsPresets_[FS_TEXTURE_COLOR_2D] = CreateShader(this, ShaderStage::FRAGMENT, fsTexCol); fsPresets_[FS_TEXTURE_COLOR_2D] = CreateShader(this, ShaderStage::FRAGMENT, fsTexCol);
fsPresets_[FS_COLOR_2D] = CreateShader(this, ShaderStage::FRAGMENT, fsCol); 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() { DrawContext::~DrawContext() {

View file

@ -583,6 +583,7 @@ struct RenderPassInfo {
class DrawContext { class DrawContext {
public: public:
virtual ~DrawContext(); virtual ~DrawContext();
bool CreatePresets();
virtual const DeviceCaps &GetDeviceCaps() const = 0; virtual const DeviceCaps &GetDeviceCaps() const = 0;
virtual uint32_t GetDataFormatSupport(DataFormat fmt) const = 0; virtual uint32_t GetDataFormatSupport(DataFormat fmt) const = 0;
@ -691,8 +692,6 @@ public:
virtual void FlushState() {} virtual void FlushState() {}
protected: protected:
void CreatePresets();
ShaderModule *vsPresets_[VS_MAX_PRESET]; ShaderModule *vsPresets_[VS_MAX_PRESET];
ShaderModule *fsPresets_[FS_MAX_PRESET]; ShaderModule *fsPresets_[FS_MAX_PRESET];

View file

@ -242,7 +242,6 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de
} }
dxgiDevice->Release(); dxgiDevice->Release();
} }
CreatePresets();
// Temp texture for read-back of small images. Custom textures are created on demand for larger ones. // 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. // TODO: Should really benchmark if this extra complexity has any benefit.

View file

@ -585,7 +585,6 @@ private:
D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx) D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx)
: d3d_(d3d), d3dEx_(d3dEx), adapterId_(adapterId), device_(device), deviceEx_(deviceEx), caps_{} { : d3d_(d3d), d3dEx_(d3dEx), adapterId_(adapterId), device_(device), deviceEx_(deviceEx), caps_{} {
CreatePresets();
if (FAILED(d3d->GetAdapterIdentifier(adapterId, 0, &identifier_))) { if (FAILED(d3d->GetAdapterIdentifier(adapterId, 0, &identifier_))) {
ELOG("Failed to get adapter identifier: %d", adapterId); ELOG("Failed to get adapter identifier: %d", adapterId);
} }
@ -633,6 +632,10 @@ Pipeline *D3D9Context::CreateGraphicsPipeline(const PipelineDesc &desc) {
} }
D3D9Pipeline *pipeline = new D3D9Pipeline(device_); D3D9Pipeline *pipeline = new D3D9Pipeline(device_);
for (auto iter : desc.shaders) { for (auto iter : desc.shaders) {
if (!iter) {
ELOG("NULL shader passed to CreateGraphicsPipeline");
return false;
}
if (iter->GetStage() == ShaderStage::FRAGMENT) { if (iter->GetStage() == ShaderStage::FRAGMENT) {
pipeline->pshader = static_cast<D3D9ShaderModule *>(iter); pipeline->pshader = static_cast<D3D9ShaderModule *>(iter);
} }
@ -947,20 +950,24 @@ void D3D9Context::SetBlendFactor(float color[4]) {
} }
bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, size_t size) { bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, size_t size) {
LPD3DXMACRO defines = NULL; LPD3DXMACRO defines = nullptr;
LPD3DXINCLUDE includes = NULL; LPD3DXINCLUDE includes = nullptr;
DWORD flags = 0; DWORD flags = 0;
LPD3DXBUFFER codeBuffer; LPD3DXBUFFER codeBuffer = nullptr;
LPD3DXBUFFER errorBuffer; LPD3DXBUFFER errorBuffer = nullptr;
const char *source = (const char *)data; const char *source = (const char *)data;
const char *profile = stage_ == ShaderStage::FRAGMENT ? "ps_2_0" : "vs_2_0"; 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); HRESULT hr = dyn_D3DXCompileShader(source, (UINT)strlen(source), defines, includes, "main", profile, flags, &codeBuffer, &errorBuffer, nullptr);
if (FAILED(hr)) { 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(source);
OutputDebugStringA(error); OutputDebugStringA(error);
errorBuffer->Release(); if (errorBuffer)
errorBuffer->Release();
if (codeBuffer) if (codeBuffer)
codeBuffer->Release(); codeBuffer->Release();
return false; return false;

View file

@ -591,8 +591,6 @@ private:
}; };
OpenGLContext::OpenGLContext() { OpenGLContext::OpenGLContext() {
CreatePresets();
// TODO: Detect more caps // TODO: Detect more caps
if (gl_extensions.IsGLES) { if (gl_extensions.IsGLES) {
if (gl_extensions.OES_packed_depth_stencil || gl_extensions.OES_depth24) { if (gl_extensions.OES_packed_depth_stencil || gl_extensions.OES_depth24) {

View file

@ -719,7 +719,6 @@ VKContext::VKContext(VulkanContext *vulkan)
viewport_.minDepth = 0.0f; viewport_.minDepth = 0.0f;
viewport_.maxDepth = 0.0f; viewport_.maxDepth = 0.0f;
memset(boundTextures_, 0, sizeof(boundTextures_)); memset(boundTextures_, 0, sizeof(boundTextures_));
CreatePresets();
VkDescriptorPoolSize dpTypes[2]; VkDescriptorPoolSize dpTypes[2];
dpTypes[0].descriptorCount = 200; dpTypes[0].descriptorCount = 200;

View file

@ -19,6 +19,7 @@
#include <stdio.h> #include <stdio.h>
#include <SDL.h> #include <SDL.h>
#include <cassert>
#include "gfx/gl_lost_manager.h" #include "gfx/gl_lost_manager.h"
#include "headless/SDLHeadlessHost.h" #include "headless/SDLHeadlessHost.h"
@ -54,6 +55,7 @@ public:
GLDummyGraphicsContext() { GLDummyGraphicsContext() {
CheckGLExtensions(); CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext(); draw_ = Draw::T3DCreateGLContext();
assert(draw_->CreatePresets());
} }
~GLDummyGraphicsContext() { delete draw_; } ~GLDummyGraphicsContext() { delete draw_; }

View file

@ -8,6 +8,7 @@
#import "ViewController.h" #import "ViewController.h"
#import "AudioEngine.h" #import "AudioEngine.h"
#import <GLKit/GLKit.h> #import <GLKit/GLKit.h>
#include <cassert>
#include "base/display.h" #include "base/display.h"
#include "base/timeutil.h" #include "base/timeutil.h"
@ -38,6 +39,7 @@ public:
IOSDummyGraphicsContext() { IOSDummyGraphicsContext() {
CheckGLExtensions(); CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext(); draw_ = Draw::T3DCreateGLContext();
assert(draw_->CreatePresets());
} }
~IOSDummyGraphicsContext() { ~IOSDummyGraphicsContext() {
delete draw_; delete draw_;