openspades/Sources/Gui/StartupScreenHelper.cpp

629 lines
19 KiB
C++

/*
Copyright (c) 2013 yvt
Portion of the code is based on Serverbrowser.cpp.
This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/
#include <OpenSpades.h>
#include "StartupScreenHelper.h"
#include "StartupScreen.h"
#include <Core/Settings.h>
#include <algorithm>
#include <cctype>
#include <Audio/YsrDevice.h>
#include <Audio/ALDevice.h>
#include "../Imports/OpenGL.h" //for gpu info
#include "../Imports/SDL.h"
SPADES_SETTING(r_bloom, "");
SPADES_SETTING(r_lens, "");
SPADES_SETTING(r_cameraBlur, "");
SPADES_SETTING(r_softParticles, "");
SPADES_SETTING(r_mapSoftShadow, "");
SPADES_SETTING(r_modelShadows, "");
SPADES_SETTING(r_radiosity, "");
SPADES_SETTING(r_dlights, "");
SPADES_SETTING(r_water, "");
SPADES_SETTING(r_multisamples, "");
SPADES_SETTING(r_fxaa, "");
SPADES_SETTING(r_depthBits, "");
SPADES_SETTING(r_colorBits, "");
SPADES_SETTING(r_videoWidth, "");
SPADES_SETTING(r_videoHeight, "");
SPADES_SETTING(r_fullscreen, "");
SPADES_SETTING(r_fogShadow, "");
SPADES_SETTING(r_lensFlare, "");
SPADES_SETTING(r_lensFlareDynamic, "");
SPADES_SETTING(r_blitFramebuffer, "");
SPADES_SETTING(r_srgb, "");
SPADES_SETTING(r_shadowMapSize, "");
SPADES_SETTING(s_maxPolyphonics, "");
SPADES_SETTING(s_eax, "");
SPADES_SETTING(r_maxAnisotropy, "");
SPADES_SETTING(r_colorCorrection, "");
SPADES_SETTING(r_physicalLighting, "");
SPADES_SETTING(r_occlusionQuery, "");
SPADES_SETTING(r_depthOfField, "");
SPADES_SETTING(r_vsync, "");
SPADES_SETTING(r_renderer, "");
SPADES_SETTING(r_swUndersampling, "");
namespace spades {
namespace gui {
StartupScreenHelper::StartupScreenHelper():
scr(nullptr),
shaderHighCapable(false),
postFilterHighCapable(false),
particleHighCapable(false) {
SPADES_MARK_FUNCTION();
}
StartupScreenHelper::~StartupScreenHelper() {
SPADES_MARK_FUNCTION();
}
void StartupScreenHelper::StartupScreenDestroyed() {
SPADES_MARK_FUNCTION();
scr = nullptr;
}
void StartupScreenHelper::ExamineSystem() {
SPADES_MARK_FUNCTION();
// check audio device availability
// Note: this only checks whether these libraries can be loaded.
SPLog("Checking YSR availability");
if(!audio::YsrDevice::TryLoadYsr()) {
incapableConfigs.insert
(std::make_pair
("s_audioDriver",
[](std::string value) -> std::string {
if(EqualsIgnoringCase(value, "ysr")) {
return "YSR library couldn't be loaded.";
}else{
return std::string();
}
}));
}
SPLog("Checking OpenAL availability");
if(!audio::ALDevice::TryLoad()) {
incapableConfigs.insert
(std::make_pair
("s_audioDriver",
[](std::string value) -> std::string {
if(EqualsIgnoringCase(value, "openal")) {
return "OpenAL library couldn't be loaded.";
}else{
return std::string();
}
}));
}
// FIXME: check OpenAL availability somehow
// check GL capabilities
SPLog("Performing ecapability query");
int idDisplay = 0;
int numDisplayMode = SDL_GetNumDisplayModes(idDisplay);
SDL_DisplayMode mode;
modes.clear();
if(numDisplayMode > 0){
std::set<std::pair<int,int>> foundModes;
for(int i = 0; i < numDisplayMode; i++) {
SDL_GetDisplayMode(idDisplay, i, &mode);
if(mode.w < 800 || mode.h < 600)
continue;
if(foundModes.find(std::make_pair(mode.w, mode.h)) != foundModes.end())
continue;
foundModes.insert(std::make_pair(mode.w, mode.h));
modes.push_back(spades::IntVector3::Make(mode.w, mode.h, 0));
SPLog("Video Mode Found: %dx%d", mode.w, mode.h);
}
}else{
SPLog("Failed to get video mode list. Presetting default list");
modes.push_back(spades::IntVector3::Make(800, 600, 0));
modes.push_back(spades::IntVector3::Make(1024, 768, 0));
modes.push_back(spades::IntVector3::Make(1280, 720, 0));
modes.push_back(spades::IntVector3::Make(1920, 1080, 0));
}
bool capable = true;
SDL_Window *window = SDL_CreateWindow("OpenSpades: Please wait...",
1, 1, 1, 1,
SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS);
if(window == nullptr) {
SPLog("Failed to create SDL window: %s", SDL_GetError());
}
SDL_GLContext context = window ? SDL_GL_CreateContext(window) : nullptr;
if(window != nullptr && context == nullptr) {
SPLog("Failed to create OpenGL context: %s", SDL_GetError());
}
if(!context){
// OpenGL initialization failed!
std::string err = SDL_GetError();
SPLog("SDL_SetVideoMode failed: %s", err.c_str());
AddReport("OpenGL-capable graphics accelerator is unavailable.",
MakeVector4(1.f, 0.5f, 0.5f, 1.f));
AddReport();
AddReport("OpenGL/SDL couldn't be initialized.");
AddReport("Falling back to the software renderer.");
AddReport();
AddReport("Message from SDL:",
MakeVector4(1.f, 1.f, 1.f, 0.7f));
AddReport(err,
MakeVector4(1.f, 1.f, 1.f, 0.7f));
capable = false;
shaderHighCapable = false;
postFilterHighCapable = false;
particleHighCapable = false;
}else{
SDL_GL_MakeCurrent(window, context);
shaderHighCapable = true;
postFilterHighCapable = true;
particleHighCapable = true;
const char *str;
GLint maxTextureSize;
GLint max3DTextureSize;
GLint maxCombinedTextureUnits;
GLint maxVertexTextureUnits;
GLint maxVaryingComponents;
SPLog("--- OpenGL Renderer Info ---");
AddReport("OpenGL-capable graphics accelerator is available.");
if((str = (const char*)glGetString(GL_VENDOR)) != NULL) {
SPLog("Vendor: %s", str);
AddReport(std::string("Vendor: ") + str,
MakeVector4(1.f, 1.f, 1.f, 0.7f));
}
if((str = (const char *)glGetString(GL_RENDERER)) != NULL) {
SPLog("Name: %s", str);
AddReport(std::string("Name: ") + str,
MakeVector4(1.f, 1.f, 1.f, 0.7f));
}
if((str = (const char *)glGetString(GL_VERSION)) != NULL) {
AddReport(std::string("Version: ") + str,
MakeVector4(1.f, 1.f, 1.f, 0.7f));
SPLog("Version: %s", str);
}
if((str = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION)) != NULL) {
AddReport(std::string("GLSL Version: ") + str,
MakeVector4(1.f, 1.f, 1.f, 0.7f));
SPLog("Shading Language Version: %s", str);
}
AddReport();
maxTextureSize = 0;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
if(maxTextureSize > 0) {
SPLog("Max Texture Size: %d", (int)maxTextureSize);
}
max3DTextureSize = 0;
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3DTextureSize);
if(max3DTextureSize > 0) {
SPLog("Max 3D Texture Size: %d", (int)max3DTextureSize);
}
maxCombinedTextureUnits = 0;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxCombinedTextureUnits);
if(maxCombinedTextureUnits > 0) {
SPLog("Max Combined Texture Image Units: %d", (int)maxCombinedTextureUnits);
}
maxVertexTextureUnits = 0;
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextureUnits);
if(maxVertexTextureUnits > 0) {
SPLog("Max Vertex Texture Image Units: %d", (int)maxVertexTextureUnits);
}
maxVaryingComponents = 0;
glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &maxVaryingComponents);
if(maxVaryingComponents > 0) {
SPLog("Max Varying Components: %d", (int)maxVaryingComponents);
}
str = (const char*)glGetString(GL_EXTENSIONS);
std::string extensions;
if(str)
extensions = str;
const char * const requiredExtensions[] = {
"GL_ARB_multitexture",
"GL_ARB_shader_objects",
"GL_ARB_shading_language_100",
"GL_ARB_texture_non_power_of_two",
"GL_ARB_vertex_buffer_object",
"GL_EXT_framebuffer_object",
NULL
};
SPLog("--- Extensions ---");
std::vector<std::string> strs = spades::Split(str, " ");
for(size_t i = 0; i < strs.size(); i++) {
SPLog("%s", strs[i].c_str());
}
SPLog("------------------");
for(size_t i = 0; requiredExtensions[i]; i++) {
const char *ex = requiredExtensions[i];
if(extensions.find(ex) == std::string::npos) {
// extension not found
AddReport(std::string(ex) + " is NOT SUPPORTED!",
MakeVector4(1.f, 0.5f, 0.5f, 1.f));
capable = false;
}
}
// non-requred extensions
if(extensions.find("GL_ARB_framebuffer_sRGB") ==
std::string::npos) {
if(r_srgb) {
r_srgb = 0;
SPLog("Disabling r_srgb: no GL_ARB_framebuffer_sRGB");
}
incapableConfigs.insert
(std::make_pair
("r_srgb",
[](std::string value) -> std::string {
if(std::stoi(value) != 0) {
return "SRGB framebuffer is disabled because your video card doesn't support GL_ARB_framebuffer_sRGB.";
}else{
return std::string();
}
}));
AddReport("GL_ARB_framebuffer_sRGB is NOT SUPPORTED",
MakeVector4(1.f, 1.f, 0.5f, 1.f));
AddReport(" r_srgb is disabled.",
MakeVector4(1.f, 1.f, 1.f, 0.7f));
}
if(extensions.find("GL_EXT_framebuffer_blit") ==
std::string::npos) {
if(r_blitFramebuffer) {
r_blitFramebuffer = 0;
SPLog("Disabling r_blitFramebuffer: no GL_EXT_framebuffer_blit");
}
if(r_multisamples) {
r_multisamples = 0;
SPLog("Disabling r_multisamples: no GL_EXT_framebuffer_blit");
}
incapableConfigs.insert(std::make_pair("r_blitFramebuffer",
[](std::string value) -> std::string {
if(std::stoi(value) != 0) {
return "r_blitFramebuffer is disabled because your video card doesn't support GL_EXT_framebuffer_blit.";
}else{
return std::string();
}
}));
AddReport("GL_EXT_framebuffer_blit is NOT SUPPORTED",
MakeVector4(1.f, 1.f, 0.5f, 1.f));
AddReport(" r_blitFramebuffer is disabled.",
MakeVector4(1.f, 1.f, 1.f, 0.7f));
}
if(extensions.find("GL_EXT_texture_filter_anisotropic") ==
std::string::npos) {
if((float)r_maxAnisotropy > 1.1f) {
r_maxAnisotropy = 1;
SPLog("Setting r_maxAnisotropy to 1: no GL_EXT_texture_filter_anisotropic");
}
incapableConfigs.insert
(std::make_pair
("r_maxAnisotropy",
[](std::string value) -> std::string {
if(std::stof(value) > 1.001f) {
return "Anisotropic texture filtering is disabled because your video card doesn't support GL_EXT_texture_filter_anisotropic.";
}else{
return std::string();
}
}));
AddReport("GL_EXT_texture_filter_anisotropic is NOT SUPPORTED",
MakeVector4(1.f, 1.f, 0.5f, 1.f));
AddReport(" r_maxAnisotropy is disabled.",
MakeVector4(1.f, 1.f, 1.f, 0.7f));
}
if(extensions.find("GL_ARB_occlusion_query") ==
std::string::npos) {
if(r_occlusionQuery) {
r_occlusionQuery = 0;
SPLog("Disabling r_occlusionQuery: no GL_ARB_occlusion_query");
}
incapableConfigs.insert
(std::make_pair
("r_occlusionQuery",
[](std::string value) -> std::string {
if(std::stoi(value)) {
return "Occlusion query is disabled because your video card doesn't support GL_ARB_occlusion_query.";
}else{
return std::string();
}
}));
AddReport("GL_ARB_occlusion_query is NOT SUPPORTED",
MakeVector4(1.f, 1.f, 0.5f, 1.f));
AddReport(" r_occlusionQuery is disabled.",
MakeVector4(1.f, 1.f, 1.f, 0.7f));
}
if(extensions.find("GL_NV_conditional_render") ==
std::string::npos) {
if(r_occlusionQuery) {
r_occlusionQuery = 0;
SPLog("Disabling r_occlusionQuery: no GL_NV_conditional_render");
}
incapableConfigs.insert
(std::make_pair
("r_occlusionQuery",
[](std::string value) -> std::string {
if(std::stoi(value)) {
return "Occlusion query is disabled because your video card doesn't support GL_NV_conditional_render.";
}else{
return std::string();
}
}));
AddReport("GL_NV_conditional_render is NOT SUPPORTED",
MakeVector4(1.f, 1.f, 0.5f, 1.f));
AddReport(" r_occlusionQuery is disabled.",
MakeVector4(1.f, 1.f, 1.f, 0.7f));
}
AddReport("Max Texture Size: " + std::to_string(maxTextureSize),
MakeVector4(1.f, 1.f, 1.f, 0.7f));
if(maxTextureSize < 1024) {
capable = false;
AddReport(" TOO SMALL (1024 requred)",
MakeVector4(1.f, 0.5f, 0.5f, 1.f));
}
if((int)r_shadowMapSize > maxTextureSize) {
SPLog("Changed r_shadowMapSize from %d to %d: too small GL_MAX_TEXTURE_SIZE", (int)r_shadowMapSize, maxTextureSize);
r_shadowMapSize = maxTextureSize;
}
AddReport("Max 3D Texture Size: " + std::to_string(max3DTextureSize),
MakeVector4(1.f, 1.f, 1.f, 0.7f));
if(max3DTextureSize < 512) {
AddReport(" Global Illumination is disabled (512 required)",
MakeVector4(1.f, 1.f, 0.5f, 1.f));
incapableConfigs.insert
(std::make_pair
("r_radiosity",
[](std::string value) -> std::string {
if(std::stoi(value)) {
return "Global illumination is disabled because your video card doesn't support a 3D texture of at least 512x512x64.";
}else{
return std::string();
}
}));
if(r_radiosity) {
r_radiosity = 0;
SPLog("Disabling r_radiosity: too small GL_MAX_3D_TEXTURE_SIZE");
}
}
AddReport("Max Combined Texture Image Units: " + std::to_string(maxCombinedTextureUnits),
MakeVector4(1.f, 1.f, 1.f, 0.7f));
if(maxCombinedTextureUnits < 12) {
AddReport(" Global Illumination is disabled (12 required)",
MakeVector4(1.f, 1.f, 0.5f, 1.f));
incapableConfigs.insert
(std::make_pair
("r_radiosity",
[](std::string value) -> std::string {
if(std::stoi(value)) {
return "Global illumination is disabled because your video card supports too few combined texture image units.";
}else{
return std::string();
}
}));
if(r_radiosity) {
r_radiosity = 0;
SPLog("Disabling r_radiosity: too small GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS");
}
}
AddReport("Max Vertex Texture Image Units: " + std::to_string(maxVertexTextureUnits),
MakeVector4(1.f, 1.f, 1.f, 0.7f));
if(maxVertexTextureUnits < 3) {
AddReport(" Water 2 is disabled (3 required)",
MakeVector4(1.f, 1.f, 0.5f, 1.f));
shaderHighCapable = false;
incapableConfigs.insert
(std::make_pair
("r_water",
[](std::string value) -> std::string {
if(std::stoi(value) >= 2) {
return "Water 2 is disabled because your video card supports too few vertex texture image units.";
}else{
return std::string();
}
}));
if((int)r_water >= 2) {
r_water = 1;
SPLog("Disabling Water 2: too small GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS");
}
}
AddReport("Max Varying Components: " + std::to_string(maxVaryingComponents),
MakeVector4(1.f, 1.f, 1.f, 0.7f));
if(maxVaryingComponents < 37) {
AddReport(" Shaded Particle is disabled (37 required)",
MakeVector4(1.f, 1.f, 0.5f, 1.f));
particleHighCapable = false;
incapableConfigs.insert
(std::make_pair
("r_softParticles",
[](std::string value) -> std::string {
if(std::stoi(value) >= 2) {
return "Shaded particle is disabled because your video card supports too few varying fragment shader input components.";
}else{
return std::string();
}
}));
if((int)r_softParticles >= 2) {
r_softParticles = 1;
SPLog("Disabling shaded particle: too small GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS");
}
}
AddReport();
if(capable){
AddReport("Your video card supports all "
"required OpenGL extensions/features.",
MakeVector4(0.5f, 1.f, 0.5f, 1.f));
}else{
AddReport("Your video card/driver doesn't support "
"at least one of required OpenGL extensions/features."
" Falling back to the software renderer.",
MakeVector4(1.f, 0.5f, 0.5f, 1.f));
}
SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window);
SPLog("SDL Capability Query Window finalized");
}
SPLog("OpenGL driver is OpenSpades capable: %s",
capable ? "YES": "NO");
openGLCapable = capable;
if(!openGLCapable) {
if(spades::EqualsIgnoringCase(r_renderer, "gl")){
SPLog("Switched to software renderer");
r_renderer = "sw";
}
incapableConfigs.insert
(std::make_pair
("r_renderer",
[](std::string value) -> std::string {
if(spades::EqualsIgnoringCase(value, "gl")) {
return "OpenGL renderer is disabled because "
"your video card/driver doesn't support "
"at least one of required OpenGL extensions/features.";
}else{
return std::string();
}
}));
}
}
void StartupScreenHelper::Start() {
if(scr == nullptr){
return;
}
scr->Start();
}
int StartupScreenHelper::GetNumVideoModes() {
return static_cast<int>(modes.size());
}
int StartupScreenHelper::GetVideoModeWidth(int index) {
if(index < 0 || index >= GetNumVideoModes())
SPInvalidArgument("index");
return modes[index].x;
}
int StartupScreenHelper::GetVideoModeHeight(int index) {
if(index < 0 || index >= GetNumVideoModes())
SPInvalidArgument("index");
return modes[index].y;
}
int StartupScreenHelper::GetNumReportLines() {
return static_cast<int>(reportLines.size());
}
std::string StartupScreenHelper::GetReportLineText(int index) {
if(index < 0 || index >= GetNumReportLines())
SPInvalidArgument("index");
return reportLines[index].text;
}
Vector4 StartupScreenHelper::GetReportLineColor(int index) {
if(index < 0 || index >= GetNumReportLines())
SPInvalidArgument("index");
return reportLines[index].color;
}
void StartupScreenHelper::AddReport(const std::string& text,
Vector4 color) {
ReportLine l = {text, color};
reportLines.push_back(l);
report += text;
report += '\n';
}
std::string StartupScreenHelper::CheckConfigCapability(const std::string &cfg, const std::string &value) {
auto range = incapableConfigs.equal_range(cfg);
std::string ret;
bool hasMulti = false;
for(auto it = range.first; it != range.second; it++) {
auto& f = it->second;
auto err = f(value);
if(err.size() > 0) {
if(ret.size() == 0) {
ret = err;
}else{
if(!hasMulti) {
ret = "- " + ret;
hasMulti = true;
}
ret += "\n- " + err;
}
}
}
return ret;
}
}
}