[Scummvm-git-logs] scummvm master -> af680aeecc0bd6c173e112dc73566386bdb73144

sev- noreply at scummvm.org
Sat Oct 8 21:39:51 UTC 2022


This automated email contains information about 69 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
9f3249286f BACKENDS: OPENGL: Initial WIP import for shader support
203af422d4 BACKENDS: OPENGL: Use simpler shader as test case
daeda92d3e BACKENDS: OPENGL: Add stub for loading shader preset from config file
4f4f0b82a8 BACKENDS: OPENGL: Add very basic stock.glsl shader as fallback option
133341adf5 BACKENDS: OPENGL: Fix shader prefix path
79700ca1b0 BACKENDS: OPENGL: Move stock.glsl shader and preset to new presets location
93b46ec40d BACKENDS: OPENGL: Resolve merge conflicts
ceef8da1f3 GUI: Mark entry point where we call the shaderscaler dialog later
17857d7597 GUI: Disable obsolete GUI entries for now
851b17affa OPENGL: Fix compilation after recent changes
5e4aaf5757 OPENGL: Render the screen and cursor to a target before applying shaders
cdbb0fa32f OPENGL: Better path lookup and error handling
c5705561b0 OPENGL: Add compatibility checks for LibRetro shader support
64c359b5cb GUI: Replace the options for selecting shaders
a2c65a4521 OPENGL: Remove the stock shader preset
79fff69231 COMMON: Use Common::String for OSystem::setShader
1b2a73c62a OPENGL: Implement selecting shaders from the GUI
f6e071e99a OPENGL: Handle LibRetro shaders containing version directives
475d2e119a COMMON: Added OSystem::kTransactionShaderChangeFailed enum value
8d61963716 OPENGL: Return error when shader did not work
1ac8fde03f JANITORIAL: Whitespace fixes
51295e3a6a JANITORIAL: Whitespace fixes
ff259665c5 GUI: Restore previous shader setting on load failure
b67c4c0047 OPENGL: Gracefully restore previous graphics mode on shader failure
31100637fa GRAPHICS: OPENGL: Refactor for adding possibility to avoid calling error() directly
6d3eb64398 OPENGL: Do not error() on shader compilation failure
3dada376b1 GUI: Show test dialog when shader was changed
a8ba66c95e GUI: Implement CountdownMessageDialog
26e5ef35ab GUI: Use countdown dialog on shader test
7df3792ae3 GUI: Implement drawing mode of top dialog only
655fea0de0 GUI: Draw only confirmation dialog on shader change
7cd63b418a GUI: Do not apply shadow on single dialog draw
e11bd0f2f2 GUI: Initial code for test screen drawing
5b307826db GUI: More work on shader test screen
d9bebc379a GUI: Fixes to the test screen drawing
2fd53a9bae JANITORIAL: Whitespace fixes
3b1a1f0411 GUI: Formatting fixes, added copyright of the original work for test screen
08706d3c0f GUI: Better wording for the schader test dialog. Courtesy of Thunderforge
0614eab5de GUI: Switch test pattern to 320z240 and improve dialog message
2c9731b16a GUI: Do not run test when there is no shader
76dc20b4b5 GUI: Fix shader clear button behaviour
ff00d3feea GUI: Move shader controls to Graphics tab and hide behind radiobutton
ee9ede6681 GUI: Persist shader/scaler radiobutton state
3aef14fa99 GUI: Initial code for making game options work with shader controls
2fc93e58bd GUI: Fix scaler toggle behavior in game options
80f79f253d GUI: Make shaders/scalers work mutually exclusive
cc0740685f OPENGL: Disable kFeatureFilteringMode because it conflicts with shaders
0351b86d64 GUI: Sync classic layout with shader controls
4e4c149264 GUI: Bump theme version to 0.9.6
57cd169a17 GUI: Allow both scalers and shaders to be enabled at the same time
8d65ac4364 GUI: Regenerate theme files
3578052175 GUI: Enable filtering on platforms where shaders are not supported
4237575f65 GUI: Fix crash when shaders are not supported
3e7ec681d1 GUI: Do not show empty hole in Graphics tab when Filtering is not supported by the backend
2e814a6956 NEWS: Mention shader-based scalers
ea578eff8a OPENGL: Fix license headers in the new files
da08d87257 OPENGL: Better check if shaders are supported
885f710da3 OPENGL: Ignore comment lines in .glslp shader preset files
9167451b59 OPENGL: More robust error reporting
aa21e7226a OPENGL: Refactored filtering support
ebc79b24bb OPENGL: Added missing USE_FORCED_GLES check
347870e6ea OPENGLSDL: Remove _ignoreLoadVideoMode
e7df36a30c OPENGL: Remove obsolete comment
8c8b06e908 GRAPHICS: Move PM5544 test pattern drawing to a separate file
37ba3744f7 GRAPHICS: Use proper color names in PM5544
6f9728c9e8 GRAPHICS: Added doxygen documentation to PM5544
cb36b46864 OPENGL: Allow loading of raw shader source
04d8265e9c OPENGL: load shaders more like original libretro
af680aeecc OPENGL: Check that textures can be set up at load time


Commit: 9f3249286f73a5b1988be6ced482fcc25e877f37
    https://github.com/scummvm/scummvm/commit/9f3249286f73a5b1988be6ced482fcc25e877f37
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
BACKENDS: OPENGL: Initial WIP import for shader support

Changed paths:
  A backends/graphics/opengl/pipelines/libretro.cpp
  A backends/graphics/opengl/pipelines/libretro.h
  A backends/graphics/opengl/pipelines/libretro/parser.cpp
  A backends/graphics/opengl/pipelines/libretro/parser.h
  A backends/graphics/opengl/pipelines/libretro/types.h
    backends/graphics/opengl/opengl-graphics.cpp
    backends/graphics/opengl/texture.cpp
    backends/module.mk


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 6c7aaf2fa1a..a0da29acc3c 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -25,6 +25,7 @@
 #include "backends/graphics/opengl/pipelines/pipeline.h"
 #include "backends/graphics/opengl/pipelines/fixed.h"
 #include "backends/graphics/opengl/pipelines/shader.h"
+#include "backends/graphics/opengl/pipelines/libretro.h"
 #include "backends/graphics/opengl/shader.h"
 #include "graphics/opengl/debug.h"
 
@@ -60,6 +61,8 @@
 
 #include "common/text-to-speech.h"
 
+#include "backends/graphics/opengl/pipelines/libretro/parser.h"
+
 namespace OpenGL {
 
 OpenGLGraphicsManager::OpenGLGraphicsManager()
@@ -1079,7 +1082,8 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 #if !USE_FORCED_GLES
 	if (OpenGLContext.shadersSupported) {
 		ShaderMan.notifyCreate();
-		_pipeline = new ShaderPipeline(ShaderMan.query(ShaderManager::kDefault));
+		//_pipeline = new ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)); FIXME
+		_pipeline = new LibRetroPipeline("shaders/glsl/crt/crt-hyllian-glow.glslp");
 	}
 #endif
 
diff --git a/backends/graphics/opengl/pipelines/libretro.cpp b/backends/graphics/opengl/pipelines/libretro.cpp
new file mode 100644
index 00000000000..1cc0ba48cee
--- /dev/null
+++ b/backends/graphics/opengl/pipelines/libretro.cpp
@@ -0,0 +1,504 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "backends/graphics/opengl/opengl-sys.h"
+
+#if !USE_FORCED_GLES
+#include "backends/graphics/opengl/pipelines/libretro.h"
+#include "backends/graphics/opengl/pipelines/libretro/parser.h"
+#include "backends/graphics/opengl/shader.h"
+#include "backends/graphics/opengl/framebuffer.h"
+
+#include "common/textconsole.h"
+#include "common/fs.h"
+#include "common/stream.h"
+
+#include "graphics/surface.h"
+
+#include "image/bmp.h"
+#include "image/png.h"
+#include "image/tga.h"
+
+namespace OpenGL {
+
+template<typename DecoderType>
+static Graphics::Surface *loadViaImageDecoder(const Common::String &fileName) {
+	Common::FSNode fileNode(fileName);
+	Common::SeekableReadStream *stream = fileNode.createReadStream();
+	if (!stream) {
+		return nullptr;
+	}
+
+	DecoderType decoder;
+	const bool success = decoder.loadStream(*stream);
+	delete stream;
+	stream = nullptr;
+
+	if (!success) {
+		return nullptr;
+	}
+
+	return decoder.getSurface()->convertTo(
+#ifdef SCUMM_LITTLE_ENDIAN
+	                                       Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24),
+#else
+	                                       Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0),
+#endif
+	                                       decoder.getPalette());
+}
+
+struct ImageLoader {
+	const char *extension;
+	Graphics::Surface *(*load)(const Common::String &fileName);
+};
+
+static const ImageLoader s_imageLoaders[] = {
+	{ "bmp", loadViaImageDecoder<Image::BitmapDecoder> },
+	{ "png", loadViaImageDecoder<Image::PNGDecoder> },
+	{ "tga", loadViaImageDecoder<Image::TGADecoder> },
+	{ nullptr, nullptr }
+};
+
+LibRetroPipeline::LibRetroPipeline(const Common::String &presetFileName)
+    : ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)),
+      _shaderPreset(LibRetro::parsePreset(presetFileName)), _applyProjectionChanges(false),
+      _inputWidth(0), _inputHeight(0), _outputWidth(0), _outputHeight(0) {
+	initialize();
+}
+
+LibRetroPipeline::~LibRetroPipeline() {
+	for (TextureArray::size_type i = 0; i < _textures.size(); ++i) {
+		if (_textures[i].textureData) {
+			_textures[i].textureData->free();
+		}
+		delete _textures[i].textureData;
+		delete _textures[i].glTexture;
+	}
+
+	for (PassArray::size_type i = 0; i < _passes.size(); ++i) {
+		delete _passes[i].shader;
+		delete _passes[i].target;
+	}
+
+	delete _shaderPreset;
+}
+
+void LibRetroPipeline::drawTexture(const GLTexture &texture, const GLfloat *coordinates) {
+	Framebuffer *const targetBuffer = _activeFramebuffer;
+
+	// Set input texture for 1st pass to texture to draw.
+	_passes[0].inputTexture = &texture;
+
+	// XXX:
+	setOutputSize(coordinates[6], coordinates[7]);
+
+	// In case texture dimensions or viewport dimensions changed, we need to
+	// update the pipeline's state.
+	if (   texture.getLogicalWidth() != _inputWidth
+	    || texture.getLogicalHeight() != _inputHeight
+	    || _outputSizeChanged) {
+		_outputSizeChanged = false;
+		_inputWidth  = texture.getLogicalWidth();
+		_inputHeight = texture.getLogicalHeight();
+
+		setPipelineState();
+	}
+
+	// Now we can actually draw the texture with the setup passes.
+	for (PassArray::const_iterator i = _passes.begin(), end = _passes.end(); i != end; ++i) {
+		renderPass(*i);
+	}
+
+	// Finally, we need to render the result to the active framebuffer.
+	_applyProjectionChanges = true;
+	setFramebuffer(targetBuffer);
+	_applyProjectionChanges = false;
+
+	ShaderPipeline::activateInternal();
+	ShaderPipeline::drawTexture(*_passes[_passes.size() - 1].target->getTexture(), coordinates);
+	ShaderPipeline::deactivateInternal();
+}
+
+void LibRetroPipeline::setProjectionMatrix(const GLfloat *projectionMatrix) {
+	if (_applyProjectionChanges) {
+		ShaderPipeline::setProjectionMatrix(projectionMatrix);
+	}
+}
+
+void LibRetroPipeline::activateInternal() {
+}
+
+void LibRetroPipeline::deactivateInternal() {
+}
+
+void LibRetroPipeline::setOutputSize(uint outputWidth, uint outputHeight) {
+	_outputSizeChanged = (_outputWidth != outputWidth || _outputHeight != outputHeight);
+
+	// Save output dimensions.
+	_outputWidth  = outputWidth;
+	_outputHeight = outputHeight;
+}
+
+void LibRetroPipeline::initialize() {
+	// TODO: Error handling.
+
+	loadTextures();
+	loadPasses();
+}
+
+void LibRetroPipeline::loadTextures() {
+	for (LibRetro::ShaderPreset::TextureArray::const_iterator
+	     i = _shaderPreset->textures.begin(), end = _shaderPreset->textures.end();
+	     i != end; ++i) {
+		// TODO: proper path look up
+		Common::String fileName = Common::normalizePath(_shaderPreset->basePath + '/' + i->fileName, '/');
+
+		Texture texture = loadTexture(fileName);
+		texture.id = i->id;
+
+		// TODO: Error handling
+		if (!texture.textureData || !texture.glTexture) {
+		}
+
+		texture.glTexture->enableLinearFiltering(i->filteringMode == LibRetro::kFilteringModeLinear);
+		_textures.push_back(texture);
+	}
+}
+
+void LibRetroPipeline::loadPasses() {
+	for (LibRetro::ShaderPreset::PassArray::const_iterator
+	     i = _shaderPreset->passes.begin(), end = _shaderPreset->passes.end();
+	     i != end; ++i) {
+		// TODO: proper path look up
+		Common::String fileName = Common::normalizePath(_shaderPreset->basePath + '/' + i->fileName, '/');
+		Common::FSNode fileNode(fileName);
+
+		Common::SeekableReadStream *stream = fileNode.createReadStream();
+		if (!stream) {
+			warning("LibRetroPipeline::loadPasses: Could not open file '%s'", fileName.c_str());
+			// TODO: Error handling
+			continue;
+		}
+
+		Common::Array<char> shaderFileContents;
+		shaderFileContents.resize(stream->size() + 1);
+		shaderFileContents[stream->size()] = 0;
+		const bool readSuccess = stream->read(shaderFileContents.begin(), stream->size()) == (uint32)stream->size();
+		delete stream;
+		stream = nullptr;
+
+		if (!readSuccess) {
+			warning("LibRetroPipeline::loadPasses: Could not read file '%s'", fileName.c_str());
+			// TODO: Error handling
+		}
+
+		Shader *shader = new Shader("#define VERTEX\n" + Common::String(shaderFileContents.begin()),
+		                            "#define FRAGMENT\n" + Common::String(shaderFileContents.begin()));
+
+		// Set uniforms with fixed value throughout lifetime.
+		// We do not support rewinding, thus fix 'forward'.
+		shader->setUniform1I("FrameDirection", 1);
+		// Input texture is always bound at sampler 0.
+		shader->setUniform1I("Texture", 0);
+
+		TextureTarget *target = nullptr;
+		// TODO: float and sRGB FBO handling.
+		target = new TextureTarget();
+
+		_passes.push_back(Pass(i, shader, target));
+		Pass &pass = _passes[_passes.size() - 1];
+		const uint passId = _passes.size() - 1;
+
+		pass.vertexCoordLocation = shader->getAttributeLocation("VertexCoord");
+		pass.buildTexCoords(passId);
+		pass.buildTexSamplers(passId, _textures);
+		if (passId > 0) {
+			GLTexture *const texture = _passes[passId - 1].target->getTexture();
+			texture->enableLinearFiltering(i->filteringMode == LibRetro::kFilteringModeLinear);
+			pass.inputTexture = texture;
+		}
+	}
+}
+
+void LibRetroPipeline::setPipelineState() {
+	// Setup FBO sizes, we require this to be able to set all uniform values.
+	setupFBOs();
+
+	// Setup all pass uniforms. This makes sure all the correct video and
+	// output sizes are set.
+	for (PassArray::size_type id = 0; id < _passes.size(); ++id) {
+		setupPassUniforms(id);
+	}
+}
+
+void LibRetroPipeline::setupFBOs() {
+	float sourceW = _inputWidth;
+	float sourceH = _inputHeight;
+
+	const float viewportW = _outputWidth;
+	const float viewportH = _outputHeight;
+
+	for (PassArray::size_type i = 0; i < _passes.size(); ++i) {
+		Pass &pass = _passes[i];
+
+		// Apply scaling for current pass.
+		pass.shaderPass->applyScale(sourceW, sourceH, viewportW, viewportH, &sourceW, &sourceH);
+
+		// Resize FBO to fit the output of the pass.
+		pass.target->setSize((uint)sourceW, (uint)sourceH);
+
+		// Store draw coordinates.
+		pass.vertexCoord[0] = 0;
+		pass.vertexCoord[1] = 0;
+
+		pass.vertexCoord[2] = (uint)sourceW;
+		pass.vertexCoord[3] = 0;
+
+		pass.vertexCoord[4] = 0;
+		pass.vertexCoord[5] = (uint)sourceH;
+
+		pass.vertexCoord[6] = (uint)sourceW;
+		pass.vertexCoord[7] = (uint)sourceH;
+
+		// Set projection matrix in passes's shader.
+		pass.shader->setUniform("MVPMatrix", new ShaderUniformMatrix44(pass.target->getProjectionMatrix()));
+	}
+}
+
+void LibRetroPipeline::setupPassUniforms(const uint id) {
+	Pass &pass = _passes[id];
+	Shader *const shader = pass.shader;
+
+	// Set output dimensions.
+	shader->setUniform2F("OutputSize", _outputWidth, _outputHeight);
+
+	// Set texture dimensions for input, original, and the passes.
+	setShaderTexUniforms(Common::String(), shader, *pass.inputTexture);
+	setShaderTexUniforms("Orig", shader, *_passes[0].inputTexture);
+	for (uint passId = 1; id >= 2 && passId <= id - 1; ++passId) {
+		setShaderTexUniforms(Common::String::format("Pass%u", passId), shader, *_passes[passId].inputTexture);
+	}
+
+	// TODO: We do not support Prev right now. Instead we always use the orig
+	// texture for these.
+	setShaderTexUniforms("Prev", shader, *_passes[0].inputTexture);
+	for (uint prevId = 1; prevId <= 6; ++prevId) {
+		setShaderTexUniforms(Common::String::format("Prev%u", prevId), shader, *_passes[0].inputTexture);
+	}
+}
+
+void LibRetroPipeline::setShaderTexUniforms(const Common::String &prefix, Shader *shader, const GLTexture &texture) {
+	shader->setUniform2F(prefix + "InputSize", texture.getLogicalWidth(), texture.getLogicalHeight());
+	shader->setUniform2F(prefix + "TextureSize", texture.getWidth(), texture.getHeight());
+}
+
+LibRetroPipeline::Texture LibRetroPipeline::loadTexture(const Common::String &fileName) {
+	const char *extension = nullptr;
+	for (int dotPos = fileName.size() - 1; dotPos >= 0; --dotPos) {
+		if (fileName[dotPos] == '.') {
+			extension = fileName.c_str() + dotPos + 1;
+			break;
+		}
+	}
+
+	if (!extension) {
+		warning("LibRetroPipeline::loadTexture: File name '%s' misses extension", fileName.c_str());
+		return Texture();
+	}
+
+	for (const ImageLoader *loader = s_imageLoaders; loader->extension; ++loader) {
+		if (!scumm_stricmp(loader->extension, extension)) {
+			Graphics::Surface *textureData = loader->load(fileName);
+			if (!textureData) {
+				warning("LibRetroPipeline::loadTexture: Loader for '%s' could not load file '%s'", loader->extension, fileName.c_str());
+				return Texture();
+			}
+
+			GLTexture *texture = new GLTexture(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
+			texture->setSize(textureData->w, textureData->h);
+			texture->updateArea(Common::Rect(textureData->w, textureData->h), *textureData);
+			return Texture(textureData, texture);
+		}
+	}
+
+	warning("LibRetroPipeline::loadTexture: No loader for file '%s' present", fileName.c_str());
+	return Texture();
+}
+
+void LibRetroPipeline::Pass::buildTexCoords(const uint id) {
+	texCoords.clear();
+
+	addTexCoord(Common::String(), TexCoordAttribute::kTypePass, id);
+	addTexCoord("Orig", TexCoordAttribute::kTypePass, 0);
+	addTexCoord("LUT", TexCoordAttribute::kTypeTexture, 0);
+
+	for (uint pass = 1; id >= 2 && pass <= id - 1; ++pass) {
+		addTexCoord(Common::String::format("Pass%u", pass), TexCoordAttribute::kTypePass, pass);
+	}
+
+	addTexCoord("Prev", TexCoordAttribute::kTypePrev, 0);
+	for (uint prevId = 1; prevId <= 6; ++prevId) {
+		addTexCoord(Common::String::format("Prev%u", prevId), TexCoordAttribute::kTypePrev, prevId);
+	}
+}
+
+void LibRetroPipeline::Pass::addTexCoord(const Common::String &prefix, const TexCoordAttribute::Type type, const uint index) {
+	GLint location = shader->getAttributeLocation(prefix + "TexCoord");
+	if (location != -1) {
+		texCoords.push_back(TexCoordAttribute(location, type, index));
+	}
+}
+
+void LibRetroPipeline::Pass::buildTexSamplers(const uint id, const TextureArray &textures) {
+	texSamplers.clear();
+	uint sampler = 1;
+
+	// 1. Step: Assign shader textures to samplers.
+	for (TextureArray::size_type i = 0; i < textures.size(); ++i) {
+		addTexSampler(textures[i].id, &sampler, TextureSampler::kTypeTexture, i, true);
+	}
+
+	// 2. Step: Assign pass inputs to samplers.
+	for (uint pass = 1; id >= 2 && pass <= id - 1; ++pass) {
+		addTexSampler(Common::String::format("Pass%u", pass), &sampler, TextureSampler::kTypePass, pass);
+	}
+
+	// 3. Step: Assign original input to samplers.
+	addTexSampler("Orig", &sampler, TextureSampler::kTypePass, 0);
+
+	// 4. Step: Assign previous render inputs.
+	addTexSampler("Prev", &sampler, TextureSampler::kTypePrev, 0);
+	for (uint prevId = 1; prevId <= 6; ++prevId) {
+		addTexSampler(Common::String::format("Prev%u", prevId), &sampler, TextureSampler::kTypePrev, prevId);
+	}
+}
+
+void LibRetroPipeline::Pass::addTexSampler(const Common::String &prefix, uint *unit, const TextureSampler::Type type, const uint index, const bool prefixIsId) {
+	const Common::String id = prefixIsId ? prefix : (prefix + "Texture");
+
+	if (shader->setUniform1I(id, *unit)) {
+		texSamplers.push_back(TextureSampler((*unit)++, type, index));
+	}
+}
+
+void LibRetroPipeline::renderPass(const Pass &pass) {
+	// Activate shader and framebuffer to be used for rendering.
+	pass.shader->activate();
+	setFramebuffer(pass.target);
+
+	// Activate attribute arrays and setup matching attributes.
+	renderPassSetupCoordinates(pass);
+
+	// Bind textures to samplers.
+	renderPassSetupTextures(pass);
+
+	// Actually draw something.
+	GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
+
+	// Deactivate attribute arrays.
+	renderPassCleanupCoordinates(pass);
+
+	// Deactivate shader.
+	pass.shader->deactivate();
+}
+
+void LibRetroPipeline::renderPassSetupCoordinates(const Pass &pass) {
+	GL_CALL(glEnableVertexAttribArray(pass.vertexCoordLocation));
+	GL_CALL(glVertexAttribPointer(pass.vertexCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, pass.vertexCoord));
+
+	for (Pass::TexCoordAttributeArray::const_iterator i = pass.texCoords.begin(), end = pass.texCoords.end();
+	     i != end; ++i) {
+		const GLfloat *texCoords = nullptr;
+
+		switch (i->type) {
+		case Pass::TexCoordAttribute::kTypeTexture:
+			texCoords = _textures[i->index].glTexture->getTexCoords();
+			break;
+
+		case Pass::TexCoordAttribute::kTypePass:
+			texCoords = _passes[i->index].inputTexture->getTexCoords();
+			break;
+
+		case Pass::TexCoordAttribute::kTypePrev:
+			// TODO: Properly support Prev
+			texCoords = _passes[0].inputTexture->getTexCoords();
+			break;
+		}
+
+		if (!texCoords) {
+			continue;
+		}
+
+		GL_CALL(glEnableVertexAttribArray(i->location));
+		GL_CALL(glVertexAttribPointer(i->location, 2, GL_FLOAT, GL_FALSE, 0, texCoords));
+	}
+}
+
+void LibRetroPipeline::renderPassCleanupCoordinates(const Pass &pass) {
+	GL_CALL(glDisableVertexAttribArray(pass.vertexCoordLocation));
+
+	for (Pass::TexCoordAttributeArray::const_iterator i = pass.texCoords.begin(), end = pass.texCoords.end();
+	     i != end; ++i) {
+		GL_CALL(glDisableVertexAttribArray(i->location));
+	}
+}
+
+void LibRetroPipeline::renderPassSetupTextures(const Pass &pass) {
+	GL_CALL(glActiveTexture(GL_TEXTURE0));
+	pass.inputTexture->bind();
+
+	// In case the pass requests mipmaps for the input texture we generate
+	// we make GL generate them here.
+	if (pass.shaderPass->mipmapInput) {
+		GL_CALL(glGenerateMipmap(GL_TEXTURE_2D));
+	}
+
+	for (Pass::TextureSamplerArray::const_iterator i = pass.texSamplers.begin(), end = pass.texSamplers.end();
+	     i != end; ++i) {
+		const GLTexture *texture = nullptr;
+
+		switch (i->type) {
+		case Pass::TextureSampler::kTypeTexture:
+			texture = _textures[i->index].glTexture;
+			break;
+
+		case Pass::TextureSampler::kTypePass:
+			texture = _passes[i->index].inputTexture;
+			break;
+
+		case Pass::TextureSampler::kTypePrev:
+			// TODO: Properly support Prev
+			texture = _passes[0].inputTexture;
+			break;
+		}
+
+		if (!texture) {
+			continue;
+		}
+
+		GL_CALL(glActiveTexture(GL_TEXTURE0 + i->unit));
+		texture->bind();
+	}
+}
+
+} // End of namespace OpenGL
+#endif // !USE_FORCED_GLES
diff --git a/backends/graphics/opengl/pipelines/libretro.h b/backends/graphics/opengl/pipelines/libretro.h
new file mode 100644
index 00000000000..c615b0d5a5d
--- /dev/null
+++ b/backends/graphics/opengl/pipelines/libretro.h
@@ -0,0 +1,243 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_H
+#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_H
+
+#include "backends/graphics/opengl/opengl-sys.h"
+
+#if !USE_FORCED_GLES
+#include "backends/graphics/opengl/pipelines/shader.h"
+
+#include "common/array.h"
+
+namespace Graphics {
+struct Surface;
+}
+
+namespace OpenGL {
+
+namespace LibRetro {
+struct ShaderPreset;
+struct ShaderPass;
+} // End of namespace LibRetro
+
+class TextureTarget;
+
+/**
+ * Pipeline implementation using Libretro shader presets.
+ */
+class LibRetroPipeline : public ShaderPipeline {
+public:
+	LibRetroPipeline(const Common::String &presetFileName);
+	virtual ~LibRetroPipeline();
+
+	virtual void drawTexture(const GLTexture &texture, const GLfloat *coordinates);
+
+	virtual void setProjectionMatrix(const GLfloat *projectionMatrix);
+
+	void setOutputSize(uint outputWidth, uint outputHeight);
+
+	bool isInitialized() const { return _shaderPreset != nullptr; }
+private:
+	virtual void activateInternal();
+	virtual void deactivateInternal();
+
+	void initialize();
+	void loadTextures();
+	void loadPasses();
+
+	void setPipelineState();
+	void setupFBOs();
+	void setupPassUniforms(const uint id);
+	void setShaderTexUniforms(const Common::String &prefix, Shader *shader, const GLTexture &texture);
+
+	const LibRetro::ShaderPreset *const _shaderPreset;
+
+	bool _applyProjectionChanges;
+
+	uint _inputWidth;
+	uint _inputHeight;
+
+	bool _outputSizeChanged;
+	uint _outputWidth;
+	uint _outputHeight;
+
+	struct Texture {
+		Texture() : textureData(nullptr), glTexture(nullptr) {}
+		Texture(Graphics::Surface *tD, GLTexture *glTex) : textureData(tD), glTexture(glTex) {}
+
+		Common::String id;
+		Graphics::Surface *textureData;
+		GLTexture *glTexture;
+	};
+	Texture loadTexture(const Common::String &fileName);
+
+	typedef Common::Array<Texture> TextureArray;
+	TextureArray _textures;
+
+	struct Pass {
+		Pass()
+		    : shaderPass(nullptr), shader(nullptr), target(nullptr), vertexCoordLocation(-1),
+		      texCoords(), texSamplers(), inputTexture(nullptr), vertexCoord() {}
+		Pass(const LibRetro::ShaderPass *sP, Shader *s, TextureTarget *t)
+		    : shaderPass(sP), shader(s), target(t), vertexCoordLocation(-1), texCoords(),
+		      texSamplers(), inputTexture(nullptr), vertexCoord() {}
+
+		const LibRetro::ShaderPass *shaderPass;
+		Shader *shader;
+		TextureTarget *target;
+
+		/**
+		 * Attribute location for vertex data.
+		 */
+		GLint vertexCoordLocation;
+
+		/**
+		 * Description of texture coordinates bound to attribute.
+		 */
+		struct TexCoordAttribute {
+			/**
+			 * Attribute location to bind data to.
+			 */
+			GLint location;
+
+			enum Type {
+				/**
+				 * 'index' denotes the 'index'th shader texture's coordinates.
+				 */
+				kTypeTexture,
+
+				/**
+				 * 'index' denotes the texture coordinates given to pass 'index'.
+				 */
+				kTypePass,
+
+				/**
+				 * 'index' denotes the texture coordinates of the 'index'th previous frame.
+				 */
+				kTypePrev
+			};
+
+			/**
+			 * The type of the attribute.
+			 */
+			Type type;
+
+			/**
+			 * Index for the texture coordinates to use.
+			 */
+			uint index;
+
+			TexCoordAttribute() : location(-1), type(), index() {}
+			TexCoordAttribute(GLint l, Type t, uint i) : location(l), type(t), index(i) {}
+		};
+
+		typedef Common::Array<TexCoordAttribute> TexCoordAttributeArray;
+		TexCoordAttributeArray texCoords;
+
+		/**
+		 * Build the 'texCoords' array.
+		 *
+		 * @param id Identifier of the current pass.
+		 */
+		void buildTexCoords(const uint id);
+
+		void addTexCoord(const Common::String &prefix, const TexCoordAttribute::Type type, const uint index);
+
+		/**
+		 * Description of a texture sampler.
+		 */
+		struct TextureSampler {
+			/**
+			 * Texture unit to use.
+			 */
+			uint unit;
+
+			enum Type {
+				/**
+				 * 'index' denotes the 'index'th shader texture.
+				 */
+				kTypeTexture,
+
+				/**
+				 * 'index' denotes the input to pass 'index'.
+				 */
+				kTypePass,
+
+				/**
+				 * 'index' denotes the input of the 'index'th previous frame.
+				 */
+				kTypePrev
+			};
+
+			/**
+			 * Source type of the texture to bind.
+			 */
+			Type type;
+
+			/**
+			 * Index of the texture.
+			 */
+			uint index;
+
+			TextureSampler() : unit(), type(), index() {}
+			TextureSampler(uint u, Type t, uint i) : unit(u), type(t), index(i) {}
+		};
+
+		typedef Common::Array<TextureSampler> TextureSamplerArray;
+		TextureSamplerArray texSamplers;
+
+		/**
+		 * Build the 'texSamplers' array.
+		 *
+		 * @param id       Identifier of the current pass.
+		 * @param textures Array of shader textures available.
+		 */
+		void buildTexSamplers(const uint id, const TextureArray &textures);
+
+		void addTexSampler(const Common::String &prefix, uint *unit, const TextureSampler::Type type, const uint index, const bool prefixIsId = false);
+
+		/**
+		 * Input texture of the pass.
+		 */
+		const GLTexture *inputTexture;
+
+		/**
+		 * Vertex coordinates used for drawing.
+		 */
+		GLfloat vertexCoord[2*4];
+	};
+
+	typedef Common::Array<Pass> PassArray;
+	PassArray _passes;
+
+	void renderPass(const Pass &pass);
+	void renderPassSetupCoordinates(const Pass &pass);
+	void renderPassCleanupCoordinates(const Pass &pass);
+	void renderPassSetupTextures(const Pass &pass);
+};
+
+} // End of namespace OpenGL
+#endif // !USE_FORCED_GLES
+
+#endif
diff --git a/backends/graphics/opengl/pipelines/libretro/parser.cpp b/backends/graphics/opengl/pipelines/libretro/parser.cpp
new file mode 100644
index 00000000000..b29b32715a6
--- /dev/null
+++ b/backends/graphics/opengl/pipelines/libretro/parser.cpp
@@ -0,0 +1,479 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "backends/graphics/opengl/opengl-sys.h"
+
+#if !USE_FORCED_GLES
+#include "backends/graphics/opengl/pipelines/libretro/parser.h"
+
+#include "common/fs.h"
+#include "common/hash-str.h"
+#include "common/stream.h"
+#include "common/algorithm.h"
+#include "common/tokenizer.h"
+#include "common/ptr.h"
+#include "common/util.h"
+
+#include "common/textconsole.h"
+
+#include <limits.h>
+
+namespace OpenGL {
+namespace LibRetro {
+
+class PresetParser {
+public:
+	ShaderPreset *parseStream(Common::SeekableReadStream &stream);
+
+	const Common::String &getErrorDesc() const { return _errorDesc; }
+private:
+	bool parsePreset(Common::SeekableReadStream &stream);
+	bool lookUpValue(const Common::String &key, Common::String *value);
+	bool lookUpValue(const Common::String &key, bool *value);
+	bool lookUpValue(const Common::String &key, uint *value);
+	bool lookUpValue(const Common::String &key, float *value);
+	bool lookUpValue(const Common::String &key, FilteringMode *value, const FilteringMode defaultValue);
+	bool lookUpValue(const Common::String &key, ScaleType *value, const ScaleType defaultValue);
+	bool lookUpValueScale(const Common::String &key, float *floatValue, uint *uintValue, const ScaleType scaleType);
+
+	template<typename T, typename DefaultT>
+	bool lookUpValue(const Common::String &key, T *value, const DefaultT &defaultValue) {
+		if (_entries.contains(key)) {
+			return lookUpValue(key, value);
+		} else {
+			*value = defaultValue;
+			return true;
+		}
+	}
+
+
+	bool parseTextures();
+	bool parseTexture(const Common::String &id);
+
+	bool parsePasses();
+	bool parsePass(const uint id, const bool isLast);
+	bool parsePassScaleType(const uint id, const bool isLast, ShaderPass *pass);
+	bool parsePassScale(const uint id, ShaderPass *pass);
+
+	typedef Common::HashMap<Common::String, Common::String> StringMap;
+	StringMap _entries;
+
+	Common::String _errorDesc;
+
+	Common::ScopedPtr<ShaderPreset> _shader;
+};
+
+ShaderPreset *PresetParser::parseStream(Common::SeekableReadStream &stream) {
+	_errorDesc.clear();
+	_entries.clear();
+
+	if (!parsePreset(stream)) {
+		return nullptr;
+	}
+
+	_shader.reset(new ShaderPreset);
+	if (!parseTextures()) {
+		return nullptr;
+	}
+
+	if (!parsePasses()) {
+		return nullptr;
+	}
+
+	return _shader.release();
+}
+
+bool PresetParser::parsePreset(Common::SeekableReadStream &stream) {
+	while (!stream.eos()) {
+		Common::String line = stream.readLine();
+		if (stream.err()) {
+			_errorDesc = "Read error";
+			return false;
+		}
+
+		if (line.empty()) {
+			continue;
+		}
+
+		// Split line into key, value pair.
+		// TODO: Files can contain comments starting with '#', we need to
+		// handle this.
+		Common::String::const_iterator equalIter = Common::find(line.begin(), line.end(), '=');
+		if (equalIter == line.end()) {
+			_errorDesc = "Could not find '=' in line '" + line + '\'';
+			return false;
+		}
+
+		Common::String key(line.begin(), equalIter);
+		Common::String value(equalIter + 1);
+
+		key.trim();
+		value.trim();
+
+		// Check whether the value is put in quotation marks. This might be
+		// useful when a path contains a whitespace. But Libretro's is not
+		// mentioning any exact format, but one example for 'textures'
+		// indicates quotes are supported in this place.
+		if (!value.empty() && value[0] == '"') {
+			if (value.size() < 2 || value.lastChar() != '"') {
+				_errorDesc = "Unmatched '\"' for value in line '" + line + '\'';
+			}
+
+			value.deleteLastChar();
+			value.deleteChar(0);
+		}
+
+		_entries[key] = value;
+	}
+
+	return true;
+}
+
+bool PresetParser::lookUpValue(const Common::String &key, Common::String *value) {
+	StringMap::const_iterator iter = _entries.find(key);
+	if (iter != _entries.end()) {
+		*value = iter->_value;
+		return true;
+	} else {
+		_errorDesc = "Missing key '" + key + "'";
+		return false;
+	}
+}
+
+bool PresetParser::lookUpValue(const Common::String &key, bool *value) {
+	StringMap::const_iterator iter = _entries.find(key);
+	if (iter != _entries.end()) {
+		if (Common::parseBool(iter->_value, *value)) {
+			return true;
+		} else {
+			_errorDesc = "Invalid boolean value for key '" + key + "': '" + iter->_value + '\'';
+			return false;
+		}
+	} else {
+		_errorDesc = "Missing key '" + key + "'";
+		return false;
+	}
+}
+
+bool PresetParser::lookUpValue(const Common::String &key, uint *value) {
+	StringMap::const_iterator iter = _entries.find(key);
+	if (iter != _entries.end()) {
+		char *endptr;
+		const long uintVal = strtol(iter->_value.c_str(), &endptr, 0);
+		if (*endptr != '\0' || uintVal >= UINT_MAX || uintVal < 0) {
+			_errorDesc = "Invalid unsigned integer value for key '" + key + "': '" + iter->_value + '\'';
+			return false;
+		} else {
+			*value = uintVal;
+			return true;
+		}
+	} else {
+		_errorDesc = "Missing key '" + key + "'";
+		return false;
+	}
+}
+
+bool PresetParser::lookUpValue(const Common::String &key, float *value) {
+	StringMap::const_iterator iter = _entries.find(key);
+	if (iter != _entries.end()) {
+		char *endptr;
+		const double doubleVal = strtod(iter->_value.c_str(), &endptr);
+		if (*endptr != '\0') {
+			_errorDesc = "Invalid float value for key '" + key + "': '" + iter->_value + '\'';
+			return false;
+		} else {
+			*value = doubleVal;
+			return true;
+		}
+	} else {
+		_errorDesc = "Missing key '" + key + "'";
+		return false;
+	}
+}
+
+bool PresetParser::lookUpValue(const Common::String &key, FilteringMode *value, const FilteringMode defaultValue) {
+	StringMap::const_iterator iter = _entries.find(key);
+	if (iter != _entries.end()) {
+		bool isLinear;
+		if (Common::parseBool(iter->_value, isLinear)) {
+			*value = isLinear ? kFilteringModeLinear : kFilteringModeNearest;
+			return true;
+		} else {
+			_errorDesc = "Invalid filtering mode for key '" + key + "': '" + iter->_value + '\'';
+			return false;
+		}
+	} else {
+		*value = defaultValue;
+		return true;
+	}
+}
+
+bool PresetParser::lookUpValue(const Common::String &key, ScaleType *value, const ScaleType defaultValue) {
+	StringMap::const_iterator iter = _entries.find(key);
+	if (iter != _entries.end()) {
+		if (iter->_value == "source") {
+			*value = kScaleTypeSource;
+			return true;
+		} else if (iter->_value == "viewport") {
+			*value = kScaleTypeViewport;
+			return true;
+		} else if (iter->_value == "absolute") {
+			*value = kScaleTypeAbsolute;
+			return true;
+		} else {
+			_errorDesc = "Invalid scale type for key '" + key + "': '" + iter->_value + '\'';
+			return false;
+		}
+	} else {
+		*value = defaultValue;
+		return true;
+	}
+}
+
+bool PresetParser::lookUpValueScale(const Common::String &key, float *floatValue, uint *uintValue, const ScaleType scaleType) {
+	if (!_entries.contains(key)) {
+		switch (scaleType) {
+		case kScaleTypeSource:
+		case kScaleTypeViewport:
+			*floatValue = 1.0f;
+			return true;
+
+		case kScaleTypeAbsolute:
+			_errorDesc = "No value specified for scale '" + key + '\'';
+			return false;
+
+		case kScaleTypeFull:
+			return true;
+
+		default:
+			_errorDesc = "Internal Error: Invalid scale type";
+			return false;
+		}
+	}
+
+	switch (scaleType) {
+	case kScaleTypeSource:
+	case kScaleTypeViewport:
+		return lookUpValue(key, floatValue, 1.0f);
+
+	case kScaleTypeAbsolute:
+		return lookUpValue(key, uintValue);
+
+	case kScaleTypeFull:
+		return true;
+
+	default:
+		_errorDesc = "Internal Error: Invalid scale type";
+		return false;
+	}
+}
+
+bool PresetParser::parseTextures() {
+	Common::String textures;
+	if (!lookUpValue("textures", &textures)) {
+		return true;
+	}
+
+	// Parse all texture information from preset.
+	Common::StringTokenizer tokenizer(textures, ";");
+	while (!tokenizer.empty()) {
+		if (!parseTexture(tokenizer.nextToken())) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+bool PresetParser::parseTexture(const Common::String &id) {
+	Common::String fileName;
+	if (!lookUpValue(id, &fileName)) {
+		_errorDesc = "No file name specified for texture '" + id + '\'';
+		return false;
+	}
+
+	FilteringMode filteringMode;
+	if (!lookUpValue(id + "_linear", &filteringMode, kFilteringModeLinear)) {
+		return false;
+	}
+
+	_shader->textures.push_back(ShaderTexture(id, fileName, filteringMode));
+	return true;
+}
+
+bool PresetParser::parsePasses() {
+	uint numShaders;
+	if (!lookUpValue("shaders", &numShaders)) {
+		return false;
+	}
+
+	for (uint shaderPass = 0; shaderPass < numShaders; ++shaderPass) {
+		if (!parsePass(shaderPass, shaderPass == numShaders - 1)) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+#define passKey(x) Common::String::format(x "%u", id)
+bool PresetParser::parsePass(const uint id, const bool isLast) {
+	ShaderPass pass;
+
+	if (!lookUpValue(passKey("shader"), &pass.fileName)) {
+		_errorDesc = Common::String::format("No file name specified for pass '%u'", id);
+		return false;
+	}
+
+	if (!lookUpValue(passKey("filter_linear"), &pass.filteringMode, kFilteringModeUnspecified)) {
+		return false;
+	}
+
+	if (!lookUpValue(passKey("mipmap_input"), &pass.mipmapInput, false)) {
+		return false;
+	}
+
+	if (!lookUpValue(passKey("float_framebuffer"), &pass.floatFBO, false)) {
+		return false;
+	}
+
+	if (!lookUpValue(passKey("srgb_framebuffer"), &pass.srgbFBO, false)) {
+		return false;
+	}
+
+	if (!lookUpValue(passKey("frame_count_mod"), &pass.frameCountMod, 0)) {
+		return false;
+	}
+
+	if (!parsePassScaleType(id, isLast, &pass)) {
+		return false;
+	}
+
+	if (!parsePassScale(id, &pass)) {
+		return false;
+	}
+
+	_shader->passes.push_back(pass);
+	return true;
+}
+
+bool PresetParser::parsePassScaleType(const uint id, const bool isLast, ShaderPass *pass) {
+	// Parse scale type for the pass.
+	//
+	// This is a little more complicated because it is possible to specify the
+	// scale type per axis. However, a generic scale type overrides the axis
+	// scale types.
+	//
+	// Additionally, the default value for the passes vary. The last pass
+	// defaults to use full size, all other default to source scaling.
+
+	const ScaleType defaultScaleType = isLast ? kScaleTypeFull : kScaleTypeSource;
+
+	if (!lookUpValue(passKey("scale_type_x"), &pass->scaleTypeX, defaultScaleType)) {
+		return false;
+	}
+
+	if (!lookUpValue(passKey("scale_type_y"), &pass->scaleTypeY, defaultScaleType)) {
+		return false;
+	}
+
+	if (!lookUpValue(passKey("scale_type"), &pass->scaleTypeX, defaultScaleType)) {
+		return false;
+	} else {
+		pass->scaleTypeY = pass->scaleTypeX;
+	}
+
+	return true;
+}
+
+bool PresetParser::parsePassScale(const uint id, ShaderPass *pass) {
+	// Parse actual scale value for the pass.
+	//
+	// Like for the scale type, 'scale' overrides 'scale_x'/'scale_y'.
+	// However, in case the scale types for x/y are different the usage of
+	// 'scale' leads to undefined behavior. In our case we simply reject
+	// the shader preset.
+
+	if (!lookUpValueScale(passKey("scale_x"), &pass->scaleXFloat, &pass->scaleXUint, pass->scaleTypeX)) {
+		return false;
+	}
+
+	if (!lookUpValueScale(passKey("scale_y"), &pass->scaleYFloat, &pass->scaleYUint, pass->scaleTypeY)) {
+		return false;
+	}
+
+	if (!_entries.contains(passKey("scale"))) {
+		return true;
+	}
+
+	if (pass->scaleTypeX != pass->scaleTypeY) {
+		_errorDesc = Common::String::format("Pass %u: Scale types for x/y differ but 'scale%u' defined", id, id);
+		return false;
+	}
+
+	pass->scaleXFloat = 0;
+	pass->scaleXUint = 0;
+	if (!lookUpValueScale(passKey("scale"), &pass->scaleXFloat, &pass->scaleXUint, pass->scaleTypeX)) {
+		return false;
+	}
+
+	pass->scaleYFloat = pass->scaleXFloat;
+	pass->scaleYUint = pass->scaleXUint;
+	return true;
+}
+#undef passKey
+
+ShaderPreset *parsePreset(const Common::String &fileName) {
+	Common::FSNode fileNode(fileName);
+	if (!fileNode.exists() || !fileNode.isReadable() || fileNode.isDirectory()) {
+		warning("LibRetro Preset Parsing: No such readable file '%s'", fileName.c_str());
+		return nullptr;
+	}
+
+	Common::FSNode basePath(".");
+	if (!basePath.exists() || !basePath.isReadable() || !basePath.isDirectory()) {
+		warning("LibRetro Preset Parsing: Base path '%s' to file '%s' invalid", basePath.getPath().c_str(), fileName.c_str());
+		return nullptr;
+	}
+
+	Common::SeekableReadStream *stream = fileNode.createReadStream();
+	if (!stream) {
+		return nullptr;
+	}
+
+	PresetParser parser;
+	ShaderPreset *shader = parser.parseStream(*stream);
+	delete stream;
+	stream = nullptr;
+
+	if (!shader) {
+		warning("LibRetro Preset Parsing: Error while parsing file '%s': %s", fileName.c_str(), parser.getErrorDesc().c_str());
+		return nullptr;
+	}
+
+	shader->basePath = basePath.getPath();
+	return shader;
+}
+
+} // End of namespace LibRetro
+} // End of namespace OpenGL
+#endif // !USE_FORCED_GLES
diff --git a/backends/graphics/opengl/pipelines/libretro/parser.h b/backends/graphics/opengl/pipelines/libretro/parser.h
new file mode 100644
index 00000000000..5cb91acd42e
--- /dev/null
+++ b/backends/graphics/opengl/pipelines/libretro/parser.h
@@ -0,0 +1,42 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_PARSER_H
+#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_PARSER_H
+
+#include "backends/graphics/opengl/opengl-sys.h"
+
+#if !USE_FORCED_GLES
+#include "backends/graphics/opengl/pipelines/libretro/types.h"
+
+#include "common/str.h"
+
+namespace OpenGL {
+namespace LibRetro {
+
+ShaderPreset *parsePreset(const Common::String &fileName);
+
+} // End of namespace LibRetro
+} // End of namespace OpenGL
+#endif // !USE_FORCED_GLES
+
+#endif
diff --git a/backends/graphics/opengl/pipelines/libretro/types.h b/backends/graphics/opengl/pipelines/libretro/types.h
new file mode 100644
index 00000000000..63ee96a1b76
--- /dev/null
+++ b/backends/graphics/opengl/pipelines/libretro/types.h
@@ -0,0 +1,123 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_TYPES_H
+#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_TYPES_H
+
+#include "backends/graphics/opengl/opengl-sys.h"
+
+#if !USE_FORCED_GLES
+#include "common/str.h"
+#include "common/array.h"
+
+namespace OpenGL {
+namespace LibRetro {
+
+enum FilteringMode {
+	kFilteringModeUnspecified,
+	kFilteringModeNearest,
+	kFilteringModeLinear
+};
+
+struct ShaderTexture {
+	ShaderTexture() : id(), fileName(), filteringMode(kFilteringModeUnspecified) {}
+	ShaderTexture(const Common::String &i, const Common::String &fN, FilteringMode fM)
+	    : id(i), fileName(fN), filteringMode(fM) {}
+
+	Common::String id;
+	Common::String fileName;
+	FilteringMode filteringMode;
+};
+
+enum ScaleType {
+	kScaleTypeSource,
+	kScaleTypeViewport,
+	kScaleTypeAbsolute,
+	kScaleTypeFull
+};
+
+inline void applyScale(const ScaleType type,
+                       const float source, const float viewport,
+                       const float scaleFloat, const uint scaleUint,
+                       float *output) {
+	switch (type) {
+	case kScaleTypeSource:
+		*output = source * scaleFloat;
+		break;
+
+	case kScaleTypeViewport:
+		*output = viewport * scaleFloat;
+		break;
+
+	case kScaleTypeAbsolute:
+		*output = scaleUint;
+		break;
+
+	case kScaleTypeFull:
+		*output = viewport;
+		break;
+	}
+}
+
+struct ShaderPass {
+	Common::String fileName;
+
+	FilteringMode filteringMode;
+	bool mipmapInput;
+
+	bool floatFBO;
+	bool srgbFBO;
+
+	uint frameCountMod;
+
+	ScaleType scaleTypeX;
+	ScaleType scaleTypeY;
+
+	float scaleXFloat;
+	float scaleYFloat;
+
+	uint scaleXUint;
+	uint scaleYUint;
+
+	void applyScale(const float sourceW, const float sourceH,
+	                const float viewportW, const float viewportH,
+	                float *outputW, float *outputH) const {
+		OpenGL::LibRetro::applyScale(scaleTypeX, sourceW, viewportW, scaleXFloat, scaleXUint, outputW);
+		OpenGL::LibRetro::applyScale(scaleTypeY, sourceH, viewportH, scaleYFloat, scaleYUint, outputH);
+	}
+};
+
+struct ShaderPreset {
+	Common::String basePath;
+
+	typedef Common::Array<ShaderTexture> TextureArray;
+	TextureArray textures;
+
+	typedef Common::Array<ShaderPass> PassArray;
+	PassArray passes;
+};
+
+} // End of namespace LibRetro
+} // End of namespace OpenGL
+#endif // !USE_FORCED_GLES
+
+#endif
diff --git a/backends/graphics/opengl/texture.cpp b/backends/graphics/opengl/texture.cpp
index e525b6c323b..3faa5ed1336 100644
--- a/backends/graphics/opengl/texture.cpp
+++ b/backends/graphics/opengl/texture.cpp
@@ -107,6 +107,9 @@ void GLTexture::setSize(uint width, uint height) {
 	const uint oldWidth  = _width;
 	const uint oldHeight = _height;
 
+	_logicalWidth  = width;
+	_logicalHeight = height;
+
 	if (!OpenGLContext.NPOTSupported) {
 		_width  = Common::nextHigher2(width);
 		_height = Common::nextHigher2(height);
@@ -115,9 +118,6 @@ void GLTexture::setSize(uint width, uint height) {
 		_height = height;
 	}
 
-	_logicalWidth  = width;
-	_logicalHeight = height;
-
 	// If a size is specified, allocate memory for it.
 	if (width != 0 && height != 0) {
 		const GLfloat texWidth = (GLfloat)width / _width;
diff --git a/backends/module.mk b/backends/module.mk
index 009038af3d8..e6f8e75ff43 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -130,6 +130,8 @@ MODULE_OBJS += \
 	graphics/opengl/pipelines/clut8.o \
 	graphics/opengl/pipelines/fixed.o \
 	graphics/opengl/pipelines/pipeline.o \
+	graphics/opengl/pipelines/libretro.o \
+	graphics/opengl/pipelines/libretro/parser.o \
 	graphics/opengl/pipelines/shader.o
 endif
 


Commit: 203af422d4df354630e9726a3d11879ce997503f
    https://github.com/scummvm/scummvm/commit/203af422d4df354630e9726a3d11879ce997503f
Author: Lothar Serra Mari (mail at serra.me)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
BACKENDS: OPENGL: Use simpler shader as test case

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index a0da29acc3c..e0d4f3bcdf8 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -1083,7 +1083,8 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 	if (OpenGLContext.shadersSupported) {
 		ShaderMan.notifyCreate();
 		//_pipeline = new ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)); FIXME
-		_pipeline = new LibRetroPipeline("shaders/glsl/crt/crt-hyllian-glow.glslp");
+		//_pipeline = new LibRetroPipeline("shaders/glsl/crt/crt-hyllian-glow.glslp");
+		_pipeline = new LibRetroPipeline("shaders/glsl/crt/crt-geom.glslp");
 	}
 #endif
 


Commit: daeda92d3ea4c1c05596ba5d6dca08bff6a10374
    https://github.com/scummvm/scummvm/commit/daeda92d3ea4c1c05596ba5d6dca08bff6a10374
Author: Lothar Serra Mari (mail at serra.me)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
BACKENDS: OPENGL: Add stub for loading shader preset from config file

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp
    backends/graphics/opengl/pipelines/libretro/parser.cpp


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index e0d4f3bcdf8..b4bf51e68ae 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -1081,10 +1081,15 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 
 #if !USE_FORCED_GLES
 	if (OpenGLContext.shadersSupported) {
-		ShaderMan.notifyCreate();
-		//_pipeline = new ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)); FIXME
-		//_pipeline = new LibRetroPipeline("shaders/glsl/crt/crt-hyllian-glow.glslp");
-		_pipeline = new LibRetroPipeline("shaders/glsl/crt/crt-geom.glslp");
+			ShaderMan.notifyCreate();
+			//_pipeline = new ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)); FIXME
+
+			// Load selected shader preset from config file
+			if (ConfMan.hasKey("shader_scaler", Common::ConfigManager::kApplicationDomain)) {
+				_pipeline = new LibRetroPipeline(ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));;
+			} else {
+				// Use some sort of default value
+		}
 	}
 #endif
 
diff --git a/backends/graphics/opengl/pipelines/libretro/parser.cpp b/backends/graphics/opengl/pipelines/libretro/parser.cpp
index b29b32715a6..9a158a81f68 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.cpp
+++ b/backends/graphics/opengl/pipelines/libretro/parser.cpp
@@ -443,7 +443,7 @@ bool PresetParser::parsePassScale(const uint id, ShaderPass *pass) {
 #undef passKey
 
 ShaderPreset *parsePreset(const Common::String &fileName) {
-	Common::FSNode fileNode(fileName);
+	Common::FSNode fileNode("./shaders/presets/" + fileName);
 	if (!fileNode.exists() || !fileNode.isReadable() || fileNode.isDirectory()) {
 		warning("LibRetro Preset Parsing: No such readable file '%s'", fileName.c_str());
 		return nullptr;


Commit: 4f4f0b82a83a26ab42a7e518df073a5f7beef60f
    https://github.com/scummvm/scummvm/commit/4f4f0b82a83a26ab42a7e518df073a5f7beef60f
Author: Lothar Serra Mari (mail at serra.me)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
BACKENDS: OPENGL: Add very basic stock.glsl shader as fallback option

Changed paths:
  A shaders/presets/nearest.glslp
  A shaders/stock.glsl
    backends/graphics/opengl/opengl-graphics.cpp


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index b4bf51e68ae..40da8ac7afc 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -1081,14 +1081,23 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 
 #if !USE_FORCED_GLES
 	if (OpenGLContext.shadersSupported) {
-			ShaderMan.notifyCreate();
-			//_pipeline = new ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)); FIXME
-
-			// Load selected shader preset from config file
-			if (ConfMan.hasKey("shader_scaler", Common::ConfigManager::kApplicationDomain)) {
-				_pipeline = new LibRetroPipeline(ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));;
+		ShaderMan.notifyCreate();
+		//_pipeline = new ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)); FIXME
+
+		// Load selected shader preset from config file
+		if (ConfMan.hasKey("shader_scaler", Common::ConfigManager::kApplicationDomain)) {
+			Common::FSNode shaderPreset("./shaders/presets/" + ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));
+			if (shaderPreset.isReadable()) {
+				_pipeline = new LibRetroPipeline(ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));
 			} else {
-				// Use some sort of default value
+				// FIXME FIXME FIXME
+				_pipeline = new LibRetroPipeline("nearest.glslp");
+				warning("Loaded fallback shader since requested shader is not available");
+			}
+		} else {
+			// FIXME FIXME FIXME
+			_pipeline = new LibRetroPipeline("nearest.glslp");
+			warning("Loaded fallback shader since requested shader is not available");
 		}
 	}
 #endif
diff --git a/shaders/presets/nearest.glslp b/shaders/presets/nearest.glslp
new file mode 100644
index 00000000000..8f4466635c0
--- /dev/null
+++ b/shaders/presets/nearest.glslp
@@ -0,0 +1,4 @@
+shaders = 1
+
+shader0 = shaders/stock.glsl
+filter_linear0 = false
diff --git a/shaders/stock.glsl b/shaders/stock.glsl
new file mode 100644
index 00000000000..a60423ad99a
--- /dev/null
+++ b/shaders/stock.glsl
@@ -0,0 +1,73 @@
+#if defined(VERTEX)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING out
+#define COMPAT_ATTRIBUTE in
+#define COMPAT_TEXTURE texture
+#else
+#define COMPAT_VARYING varying 
+#define COMPAT_ATTRIBUTE attribute 
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+COMPAT_ATTRIBUTE vec4 VertexCoord;
+COMPAT_ATTRIBUTE vec4 COLOR;
+COMPAT_ATTRIBUTE vec4 TexCoord;
+COMPAT_VARYING vec4 COL0;
+COMPAT_VARYING vec4 TEX0;
+
+uniform mat4 MVPMatrix;
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+
+void main()
+{
+    gl_Position = VertexCoord.x * MVPMatrix[0] + VertexCoord.y * MVPMatrix[1] + VertexCoord.z * MVPMatrix[2] + VertexCoord.w * MVPMatrix[3];
+    TEX0.xy = TexCoord.xy;
+}
+
+#elif defined(FRAGMENT)
+
+#if __VERSION__ >= 130
+#define COMPAT_VARYING in
+#define COMPAT_TEXTURE texture
+out vec4 FragColor;
+#else
+#define COMPAT_VARYING varying
+#define FragColor gl_FragColor
+#define COMPAT_TEXTURE texture2D
+#endif
+
+#ifdef GL_ES
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+#define COMPAT_PRECISION mediump
+#else
+#define COMPAT_PRECISION
+#endif
+
+uniform COMPAT_PRECISION int FrameDirection;
+uniform COMPAT_PRECISION int FrameCount;
+uniform COMPAT_PRECISION vec2 OutputSize;
+uniform COMPAT_PRECISION vec2 TextureSize;
+uniform COMPAT_PRECISION vec2 InputSize;
+uniform sampler2D Texture;
+COMPAT_VARYING vec4 TEX0;
+
+void main()
+{
+    FragColor = COMPAT_TEXTURE(Texture, TEX0.xy);
+} 
+#endif


Commit: 133341adf5df8364eafff348aaf2f176d0d0fc51
    https://github.com/scummvm/scummvm/commit/133341adf5df8364eafff348aaf2f176d0d0fc51
Author: Lothar Serra Mari (mail at serra.me)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
BACKENDS: OPENGL: Fix shader prefix path

Changed paths:
    backends/graphics/opengl/pipelines/libretro/parser.cpp


diff --git a/backends/graphics/opengl/pipelines/libretro/parser.cpp b/backends/graphics/opengl/pipelines/libretro/parser.cpp
index 9a158a81f68..b7a3d8606e7 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.cpp
+++ b/backends/graphics/opengl/pipelines/libretro/parser.cpp
@@ -449,7 +449,7 @@ ShaderPreset *parsePreset(const Common::String &fileName) {
 		return nullptr;
 	}
 
-	Common::FSNode basePath(".");
+	Common::FSNode basePath("./shaders/presets/");
 	if (!basePath.exists() || !basePath.isReadable() || !basePath.isDirectory()) {
 		warning("LibRetro Preset Parsing: Base path '%s' to file '%s' invalid", basePath.getPath().c_str(), fileName.c_str());
 		return nullptr;


Commit: 79700ca1b0f5a7da5923f4330d1495a7c41a330e
    https://github.com/scummvm/scummvm/commit/79700ca1b0f5a7da5923f4330d1495a7c41a330e
Author: Lothar Serra Mari (mail at serra.me)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
BACKENDS: OPENGL: Move stock.glsl shader and preset to new presets location

Changed paths:
  A shaders/presets/shaders/stock.glsl
  R shaders/stock.glsl


diff --git a/shaders/stock.glsl b/shaders/presets/shaders/stock.glsl
similarity index 100%
rename from shaders/stock.glsl
rename to shaders/presets/shaders/stock.glsl


Commit: 93b46ec40dbc6dcf2e9992d7e19a1eacdb7307c5
    https://github.com/scummvm/scummvm/commit/93b46ec40dbc6dcf2e9992d7e19a1eacdb7307c5
Author: Lothar Serra Mari (mail at serra.me)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
BACKENDS: OPENGL: Resolve merge conflicts

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp
    backends/graphics/opengl/pipelines/libretro/parser.cpp
    gui/options.cpp
    gui/options.h
    gui/themes/common/highres_layout.stx
    gui/themes/common/lowres_layout.stx


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 40da8ac7afc..f9b69ebbcfe 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -1086,7 +1086,7 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 
 		// Load selected shader preset from config file
 		if (ConfMan.hasKey("shader_scaler", Common::ConfigManager::kApplicationDomain)) {
-			Common::FSNode shaderPreset("./shaders/presets/" + ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));
+			Common::FSNode shaderPreset(ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));
 			if (shaderPreset.isReadable()) {
 				_pipeline = new LibRetroPipeline(ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));
 			} else {
diff --git a/backends/graphics/opengl/pipelines/libretro/parser.cpp b/backends/graphics/opengl/pipelines/libretro/parser.cpp
index b7a3d8606e7..6702240f060 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.cpp
+++ b/backends/graphics/opengl/pipelines/libretro/parser.cpp
@@ -32,6 +32,7 @@
 #include "common/tokenizer.h"
 #include "common/ptr.h"
 #include "common/util.h"
+#include "common/config-manager.h"
 
 #include "common/textconsole.h"
 
@@ -443,13 +444,14 @@ bool PresetParser::parsePassScale(const uint id, ShaderPass *pass) {
 #undef passKey
 
 ShaderPreset *parsePreset(const Common::String &fileName) {
-	Common::FSNode fileNode("./shaders/presets/" + fileName);
+	Common::String _shaderPath = ConfMan.get("shaderpath");
+	Common::FSNode fileNode(_shaderPath + fileName);
 	if (!fileNode.exists() || !fileNode.isReadable() || fileNode.isDirectory()) {
 		warning("LibRetro Preset Parsing: No such readable file '%s'", fileName.c_str());
 		return nullptr;
 	}
 
-	Common::FSNode basePath("./shaders/presets/");
+	Common::FSNode basePath(_shaderPath);
 	if (!basePath.exists() || !basePath.isReadable() || !basePath.isDirectory()) {
 		warning("LibRetro Preset Parsing: Base path '%s' to file '%s' invalid", basePath.getPath().c_str(), fileName.c_str());
 		return nullptr;
diff --git a/gui/options.cpp b/gui/options.cpp
index 51a1b8a315d..484a60756e4 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -92,6 +92,8 @@ enum {
 	kPluginsPathClearCmd	= 'clpl',
 	kChooseThemeCmd			= 'chtf',
 	kUpdateIconsCmd			= 'upic',
+	kChooseShaderDirCmd     = 'chsh',
+	kShaderPathClearCmd     = 'chsc',
 	kUpdatesCheckCmd		= 'updc',
 	kKbdMouseSpeedChanged	= 'kmsc',
 	kJoystickDeadzoneChanged= 'jodc',
@@ -1947,6 +1949,8 @@ GlobalOptionsDialog::GlobalOptionsDialog(LauncherDialog *launcher)
 	_iconPathClearButton = nullptr;
 	_extraPath = nullptr;
 	_extraPathClearButton = nullptr;
+	_shaderPath = nullptr;
+	_shaderPathClearButton = nullptr;
 #ifdef DYNAMIC_MODULES
 	_pluginsPath = nullptr;
 	_pluginsPathClearButton = nullptr;
@@ -2218,6 +2222,7 @@ void GlobalOptionsDialog::build() {
 	setPath(_themePath, "themepath", _c("None", "path"));
 	setPath(_iconPath, "iconspath", _("Default"));
 	setPath(_extraPath, "extrapath", _c("None", "path"));
+	setPath(_shaderPath, "shaderpath", _c("None", "path"));
 
 #ifdef DYNAMIC_MODULES
 	Common::String pluginsPath(ConfMan.get("pluginspath", _domain));
@@ -2316,6 +2321,14 @@ void GlobalOptionsDialog::addPathsControls(GuiObject *boss, const Common::String
 
 	_extraPathClearButton = addClearButton(boss, prefix + "ExtraPathClearButton", kExtraPathClearCmd);
 
+	if (!lowres)
+		new ButtonWidget(boss, prefix + "ShaderButton", _("Shader Path:"), _("Specifies path to the shaders used for scaling ScummVM"), kChooseShaderDirCmd);
+	else
+		new ButtonWidget(boss, prefix + "ShaderButton", _c("Shader Path:", "lowres"), _("Specifies path to the shaders used for scaling ScummVM"), kChooseShaderDirCmd);
+	_shaderPath = new StaticTextWidget(boss, prefix + "ShaderPath", _c("None", "path"), _("Specifies path to the shaders used for scaling ScummVM"));
+
+	_shaderPathClearButton = addClearButton(boss, prefix + "ShaderPathClearButton", kShaderPathClearCmd);
+
 #ifdef DYNAMIC_MODULES
 	if (!lowres)
 		new ButtonWidget(boss, prefix + "PluginsButton", _("Plugins Path:"), Common::U32String(), kChoosePluginsDirCmd);
@@ -2712,6 +2725,12 @@ void GlobalOptionsDialog::apply() {
 	changePath(_iconPath, "iconspath", _("Default"));
 	changePath(_extraPath, "extrapath", _c("None", "path")); 
 
+	Common::U32String shaderPath(_shaderPath->getLabel());
+	if (!shaderPath.empty() && (shaderPath != _c("None", "path")))
+		ConfMan.set("shaderpath", shaderPath.encode(), _domain);
+	else
+		ConfMan.removeKey("shaderpath", _domain);
+
 #ifdef DYNAMIC_MODULES
 	Common::U32String pluginsPath(_pluginsPath->getLabel());
 	if (!pluginsPath.empty() && (pluginsPath != _c("None", "path")))
@@ -2959,6 +2978,15 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 		}
 		break;
 	}
+	case kChooseShaderDirCmd: {
+		BrowserDialog browser(_("Select directory for scaling shaders"), true);
+		if (browser.runModal() > 0) {
+			Common::FSNode dir(browser.getResult());
+			_shaderPath->setLabel(dir.getPath());
+			g_gui.scheduleTopDialogRedraw();
+		}
+		break;
+	}
 #ifdef DYNAMIC_MODULES
 	case kChoosePluginsDirCmd: {
 		BrowserDialog browser(_("Select directory for plugins"), true);
@@ -3009,6 +3037,8 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 	case kSavePathClearCmd:
 		_savePath->setLabel(_("Default"));
 		break;
+	case kShaderPathClearCmd:
+		_shaderPath->setLabel(_("Default"));
 #ifdef DYNAMIC_MODULES
 	case kPluginsPathClearCmd:
 		_pluginsPath->setLabel(_c("None", "path"));
@@ -3301,6 +3331,11 @@ void GlobalOptionsDialog::reflowLayout() {
 		_browserPathClearButton->setNext(nullptr);
 		delete _browserPathClearButton;
 		_browserPathClearButton = addClearButton(_tabWidget, "GlobalOptions_Paths.BrowserPathClearButton", kBrowserPathClearCmd);
+
+		_tabWidget->removeWidget(_shaderPathClearButton);
+		_shaderPathClearButton->setNext(nullptr);
+		delete _shaderPathClearButton;
+		_shaderPathClearButton = addClearButton(_tabWidget, "GlobalOptions_Paths.ShaderPathClearButton", kShaderPathClearCmd);
 	}
 
 	_tabWidget->setActiveTab(activeTab);
diff --git a/gui/options.h b/gui/options.h
index e21195a6d86..9f83a95c93f 100644
--- a/gui/options.h
+++ b/gui/options.h
@@ -285,6 +285,8 @@ protected:
 	ButtonWidget	 *_iconPathClearButton;
 	StaticTextWidget *_extraPath;
 	ButtonWidget	 *_extraPathClearButton;
+	StaticTextWidget *_shaderPath;
+	ButtonWidget	 *_shaderPathClearButton;
 #ifdef DYNAMIC_MODULES
 	StaticTextWidget *_pluginsPath;
 	ButtonWidget	 *_pluginsPathClearButton;
diff --git a/gui/themes/common/highres_layout.stx b/gui/themes/common/highres_layout.stx
index c40fdbdcc1e..0b54ba9b77c 100644
--- a/gui/themes/common/highres_layout.stx
+++ b/gui/themes/common/highres_layout.stx
@@ -752,6 +752,18 @@
 						width = 'Globals.Line.Height'
 				/>
 			</layout>
+			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
+				<widget name = 'ShaderButton'
+						type = 'Button'
+				/>
+				<widget name = 'ShaderPath'
+						height = 'Globals.Line.Height'
+				/>
+				<widget name = 'ShaderPathClearButton'
+						height = 'Globals.Line.Height'
+						width = 'Globals.Line.Height'
+				/>
+			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
 				<widget name = 'PluginsButton'
 						type = 'Button'
diff --git a/gui/themes/common/lowres_layout.stx b/gui/themes/common/lowres_layout.stx
index 1c529270645..bf204a5fad9 100644
--- a/gui/themes/common/lowres_layout.stx
+++ b/gui/themes/common/lowres_layout.stx
@@ -690,6 +690,18 @@
 						width = 'Globals.Line.Height'
 				/>
 			</layout>
+			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
+				<widget name = 'ShaderButton'
+						type = 'Button'
+				/>
+				<widget name = 'ShaderPath'
+						height = 'Globals.Line.Height'
+				/>
+				<widget name = 'ShaderPathClearButton'
+						height = 'Globals.Line.Height'
+						width = 'Globals.Line.Height'
+				/>
+			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' align = 'center'>
 				<widget name = 'PluginsButton'
 						type = 'Button'


Commit: ceef8da1f3a136b4358feba9f31f5170de333daf
    https://github.com/scummvm/scummvm/commit/ceef8da1f3a136b4358feba9f31f5170de333daf
Author: Lothar Serra Mari (mail at serra.me)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Mark entry point where we call the shaderscaler dialog later

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index 484a60756e4..f5b7450761f 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -2984,6 +2984,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 			Common::FSNode dir(browser.getResult());
 			_shaderPath->setLabel(dir.getPath());
 			g_gui.scheduleTopDialogRedraw();
+			warning("Dialog triggered, there be dragons and the scaling scanner dialog!");
 		}
 		break;
 	}


Commit: 17857d759759f593e3cc4893c9b23b33e65217ef
    https://github.com/scummvm/scummvm/commit/17857d759759f593e3cc4893c9b23b33e65217ef
Author: Lothar Serra Mari (mail at serra.me)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Disable obsolete GUI entries for now

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index f5b7450761f..2878d2208ca 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -1949,8 +1949,8 @@ GlobalOptionsDialog::GlobalOptionsDialog(LauncherDialog *launcher)
 	_iconPathClearButton = nullptr;
 	_extraPath = nullptr;
 	_extraPathClearButton = nullptr;
-	_shaderPath = nullptr;
-	_shaderPathClearButton = nullptr;
+	//_shaderPath = nullptr;
+	//_shaderPathClearButton = nullptr;
 #ifdef DYNAMIC_MODULES
 	_pluginsPath = nullptr;
 	_pluginsPathClearButton = nullptr;
@@ -2222,7 +2222,7 @@ void GlobalOptionsDialog::build() {
 	setPath(_themePath, "themepath", _c("None", "path"));
 	setPath(_iconPath, "iconspath", _("Default"));
 	setPath(_extraPath, "extrapath", _c("None", "path"));
-	setPath(_shaderPath, "shaderpath", _c("None", "path"));
+	// setPath(_shaderPath, "shaderpath", _c("None", "path"));
 
 #ifdef DYNAMIC_MODULES
 	Common::String pluginsPath(ConfMan.get("pluginspath", _domain));
@@ -2321,13 +2321,13 @@ void GlobalOptionsDialog::addPathsControls(GuiObject *boss, const Common::String
 
 	_extraPathClearButton = addClearButton(boss, prefix + "ExtraPathClearButton", kExtraPathClearCmd);
 
-	if (!lowres)
-		new ButtonWidget(boss, prefix + "ShaderButton", _("Shader Path:"), _("Specifies path to the shaders used for scaling ScummVM"), kChooseShaderDirCmd);
-	else
-		new ButtonWidget(boss, prefix + "ShaderButton", _c("Shader Path:", "lowres"), _("Specifies path to the shaders used for scaling ScummVM"), kChooseShaderDirCmd);
-	_shaderPath = new StaticTextWidget(boss, prefix + "ShaderPath", _c("None", "path"), _("Specifies path to the shaders used for scaling ScummVM"));
+	//if (!lowres)
+	//	new ButtonWidget(boss, prefix + "ShaderButton", _("Shader Path:"), _("Specifies path to the shaders used for scaling ScummVM"), kChooseShaderDirCmd);
+	//else
+	//		new ButtonWidget(boss, prefix + "ShaderButton", _c("Shader Path:", "lowres"), _("Specifies path to the shaders used for scaling ScummVM"), kChooseShaderDirCmd);
+	//_shaderPath = new StaticTextWidget(boss, prefix + "ShaderPath", _c("None", "path"), _("Specifies path to the shaders used for scaling ScummVM"));
 
-	_shaderPathClearButton = addClearButton(boss, prefix + "ShaderPathClearButton", kShaderPathClearCmd);
+	//_shaderPathClearButton = addClearButton(boss, prefix + "ShaderPathClearButton", kShaderPathClearCmd);
 
 #ifdef DYNAMIC_MODULES
 	if (!lowres)
@@ -2725,11 +2725,11 @@ void GlobalOptionsDialog::apply() {
 	changePath(_iconPath, "iconspath", _("Default"));
 	changePath(_extraPath, "extrapath", _c("None", "path")); 
 
-	Common::U32String shaderPath(_shaderPath->getLabel());
-	if (!shaderPath.empty() && (shaderPath != _c("None", "path")))
-		ConfMan.set("shaderpath", shaderPath.encode(), _domain);
-	else
-		ConfMan.removeKey("shaderpath", _domain);
+	//Common::U32String shaderPath(_shaderPath->getLabel());
+	//if (!shaderPath.empty() && (shaderPath != _c("None", "path")))
+	//	ConfMan.set("shaderpath", shaderPath.encode(), _domain);
+	//else
+	//	ConfMan.removeKey("shaderpath", _domain);
 
 #ifdef DYNAMIC_MODULES
 	Common::U32String pluginsPath(_pluginsPath->getLabel());
@@ -2978,16 +2978,16 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 		}
 		break;
 	}
-	case kChooseShaderDirCmd: {
-		BrowserDialog browser(_("Select directory for scaling shaders"), true);
-		if (browser.runModal() > 0) {
-			Common::FSNode dir(browser.getResult());
-			_shaderPath->setLabel(dir.getPath());
-			g_gui.scheduleTopDialogRedraw();
-			warning("Dialog triggered, there be dragons and the scaling scanner dialog!");
-		}
-		break;
-	}
+	//case kChooseShaderDirCmd: {
+	//	BrowserDialog browser(_("Select directory for scaling shaders"), true);
+	//	if (browser.runModal() > 0) {
+	//		Common::FSNode dir(browser.getResult());
+	//		_shaderPath->setLabel(dir.getPath());
+	//		g_gui.scheduleTopDialogRedraw();
+	//		warning("Dialog triggered, there be dragons and the scaling scanner dialog!");
+	//	}
+	//	break;
+	//}
 #ifdef DYNAMIC_MODULES
 	case kChoosePluginsDirCmd: {
 		BrowserDialog browser(_("Select directory for plugins"), true);
@@ -3038,8 +3038,8 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 	case kSavePathClearCmd:
 		_savePath->setLabel(_("Default"));
 		break;
-	case kShaderPathClearCmd:
-		_shaderPath->setLabel(_("Default"));
+	//case kShaderPathClearCmd:
+	//	_shaderPath->setLabel(_("Default"));
 #ifdef DYNAMIC_MODULES
 	case kPluginsPathClearCmd:
 		_pluginsPath->setLabel(_c("None", "path"));
@@ -3333,10 +3333,10 @@ void GlobalOptionsDialog::reflowLayout() {
 		delete _browserPathClearButton;
 		_browserPathClearButton = addClearButton(_tabWidget, "GlobalOptions_Paths.BrowserPathClearButton", kBrowserPathClearCmd);
 
-		_tabWidget->removeWidget(_shaderPathClearButton);
-		_shaderPathClearButton->setNext(nullptr);
-		delete _shaderPathClearButton;
-		_shaderPathClearButton = addClearButton(_tabWidget, "GlobalOptions_Paths.ShaderPathClearButton", kShaderPathClearCmd);
+		//_tabWidget->removeWidget(_shaderPathClearButton);
+		//_shaderPathClearButton->setNext(nullptr);
+		//delete _shaderPathClearButton;
+		//_shaderPathClearButton = addClearButton(_tabWidget, "GlobalOptions_Paths.ShaderPathClearButton", kShaderPathClearCmd);
 	}
 
 	_tabWidget->setActiveTab(activeTab);


Commit: 851b17affa7070f336f3e55daa1083107942b1d2
    https://github.com/scummvm/scummvm/commit/851b17affa7070f336f3e55daa1083107942b1d2
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Fix compilation after recent changes

Changed paths:
    backends/graphics/opengl/pipelines/libretro.cpp
    backends/graphics/opengl/pipelines/libretro.h
    backends/graphics/opengl/pipelines/libretro/parser.cpp
    backends/graphics/opengl/pipelines/libretro/parser.h
    backends/graphics/opengl/pipelines/libretro/types.h


diff --git a/backends/graphics/opengl/pipelines/libretro.cpp b/backends/graphics/opengl/pipelines/libretro.cpp
index 1cc0ba48cee..16431340701 100644
--- a/backends/graphics/opengl/pipelines/libretro.cpp
+++ b/backends/graphics/opengl/pipelines/libretro.cpp
@@ -20,13 +20,14 @@
  *
  */
 
-#include "backends/graphics/opengl/opengl-sys.h"
+#include "graphics/opengl/system_headers.h"
 
 #if !USE_FORCED_GLES
 #include "backends/graphics/opengl/pipelines/libretro.h"
 #include "backends/graphics/opengl/pipelines/libretro/parser.h"
 #include "backends/graphics/opengl/shader.h"
 #include "backends/graphics/opengl/framebuffer.h"
+#include "graphics/opengl/debug.h"
 
 #include "common/textconsole.h"
 #include "common/fs.h"
@@ -78,6 +79,10 @@ static const ImageLoader s_imageLoaders[] = {
 	{ nullptr, nullptr }
 };
 
+const char *const g_libretroShaderAttributes[] = {
+	"VertexCoord", nullptr
+};
+
 LibRetroPipeline::LibRetroPipeline(const Common::String &presetFileName)
     : ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)),
       _shaderPreset(LibRetro::parsePreset(presetFileName)), _applyProjectionChanges(false),
@@ -102,7 +107,7 @@ LibRetroPipeline::~LibRetroPipeline() {
 	delete _shaderPreset;
 }
 
-void LibRetroPipeline::drawTexture(const GLTexture &texture, const GLfloat *coordinates) {
+void LibRetroPipeline::drawTexture(const GLTexture &texture, const GLfloat *coordinates, const GLfloat *texcoords) {
 	Framebuffer *const targetBuffer = _activeFramebuffer;
 
 	// Set input texture for 1st pass to texture to draw.
@@ -134,7 +139,7 @@ void LibRetroPipeline::drawTexture(const GLTexture &texture, const GLfloat *coor
 	_applyProjectionChanges = false;
 
 	ShaderPipeline::activateInternal();
-	ShaderPipeline::drawTexture(*_passes[_passes.size() - 1].target->getTexture(), coordinates);
+	ShaderPipeline::drawTexture(*_passes[_passes.size() - 1].target->getTexture(), coordinates, texcoords);
 	ShaderPipeline::deactivateInternal();
 }
 
@@ -211,14 +216,16 @@ void LibRetroPipeline::loadPasses() {
 			// TODO: Error handling
 		}
 
-		Shader *shader = new Shader("#define VERTEX\n" + Common::String(shaderFileContents.begin()),
-		                            "#define FRAGMENT\n" + Common::String(shaderFileContents.begin()));
+		Shader *shader = Shader::fromStrings(fileName,
+		                                     ("#define VERTEX\n" + Common::String(shaderFileContents.begin())).c_str(),
+		                                     ("#define FRAGMENT\n" + Common::String(shaderFileContents.begin())).c_str(),
+		                                     g_libretroShaderAttributes);
 
 		// Set uniforms with fixed value throughout lifetime.
 		// We do not support rewinding, thus fix 'forward'.
-		shader->setUniform1I("FrameDirection", 1);
+		shader->setUniform("FrameDirection", 1);
 		// Input texture is always bound at sampler 0.
-		shader->setUniform1I("Texture", 0);
+		shader->setUniform("Texture", 0);
 
 		TextureTarget *target = nullptr;
 		// TODO: float and sRGB FBO handling.
@@ -228,7 +235,6 @@ void LibRetroPipeline::loadPasses() {
 		Pass &pass = _passes[_passes.size() - 1];
 		const uint passId = _passes.size() - 1;
 
-		pass.vertexCoordLocation = shader->getAttributeLocation("VertexCoord");
 		pass.buildTexCoords(passId);
 		pass.buildTexSamplers(passId, _textures);
 		if (passId > 0) {
@@ -280,7 +286,9 @@ void LibRetroPipeline::setupFBOs() {
 		pass.vertexCoord[7] = (uint)sourceH;
 
 		// Set projection matrix in passes's shader.
-		pass.shader->setUniform("MVPMatrix", new ShaderUniformMatrix44(pass.target->getProjectionMatrix()));
+		Math::Matrix4 m4;
+		m4.setData(pass.target->getProjectionMatrix());
+		pass.shader->setUniform("MVPMatrix", m4);
 	}
 }
 
@@ -289,7 +297,7 @@ void LibRetroPipeline::setupPassUniforms(const uint id) {
 	Shader *const shader = pass.shader;
 
 	// Set output dimensions.
-	shader->setUniform2F("OutputSize", _outputWidth, _outputHeight);
+	shader->setUniform("OutputSize", Math::Vector2d(_outputWidth, _outputHeight));
 
 	// Set texture dimensions for input, original, and the passes.
 	setShaderTexUniforms(Common::String(), shader, *pass.inputTexture);
@@ -307,8 +315,8 @@ void LibRetroPipeline::setupPassUniforms(const uint id) {
 }
 
 void LibRetroPipeline::setShaderTexUniforms(const Common::String &prefix, Shader *shader, const GLTexture &texture) {
-	shader->setUniform2F(prefix + "InputSize", texture.getLogicalWidth(), texture.getLogicalHeight());
-	shader->setUniform2F(prefix + "TextureSize", texture.getWidth(), texture.getHeight());
+	shader->setUniform(prefix + "InputSize", Math::Vector2d(texture.getLogicalWidth(), texture.getLogicalHeight()));
+	shader->setUniform(prefix + "TextureSize", Math::Vector2d(texture.getWidth(), texture.getHeight()));
 }
 
 LibRetroPipeline::Texture LibRetroPipeline::loadTexture(const Common::String &fileName) {
@@ -347,24 +355,23 @@ LibRetroPipeline::Texture LibRetroPipeline::loadTexture(const Common::String &fi
 void LibRetroPipeline::Pass::buildTexCoords(const uint id) {
 	texCoords.clear();
 
-	addTexCoord(Common::String(), TexCoordAttribute::kTypePass, id);
-	addTexCoord("Orig", TexCoordAttribute::kTypePass, 0);
-	addTexCoord("LUT", TexCoordAttribute::kTypeTexture, 0);
+	addTexCoord("TexCoord", TexCoordAttribute::kTypePass, id);
+	addTexCoord("OrigTexCoord", TexCoordAttribute::kTypePass, 0);
+	addTexCoord("LUTTexCoord", TexCoordAttribute::kTypeTexture, 0);
 
 	for (uint pass = 1; id >= 2 && pass <= id - 1; ++pass) {
-		addTexCoord(Common::String::format("Pass%u", pass), TexCoordAttribute::kTypePass, pass);
+		addTexCoord(Common::String::format("Pass%uTexCoord", pass), TexCoordAttribute::kTypePass, pass);
 	}
 
-	addTexCoord("Prev", TexCoordAttribute::kTypePrev, 0);
+	addTexCoord("PrevTexCoord", TexCoordAttribute::kTypePrev, 0);
 	for (uint prevId = 1; prevId <= 6; ++prevId) {
-		addTexCoord(Common::String::format("Prev%u", prevId), TexCoordAttribute::kTypePrev, prevId);
+		addTexCoord(Common::String::format("Prev%uTexCoord", prevId), TexCoordAttribute::kTypePrev, prevId);
 	}
 }
 
-void LibRetroPipeline::Pass::addTexCoord(const Common::String &prefix, const TexCoordAttribute::Type type, const uint index) {
-	GLint location = shader->getAttributeLocation(prefix + "TexCoord");
-	if (location != -1) {
-		texCoords.push_back(TexCoordAttribute(location, type, index));
+void LibRetroPipeline::Pass::addTexCoord(const Common::String &name, const TexCoordAttribute::Type type, const uint index) {
+	if (shader->addAttribute(name.c_str())) {
+		texCoords.push_back(TexCoordAttribute(name, type, index));
 	}
 }
 
@@ -395,14 +402,14 @@ void LibRetroPipeline::Pass::buildTexSamplers(const uint id, const TextureArray
 void LibRetroPipeline::Pass::addTexSampler(const Common::String &prefix, uint *unit, const TextureSampler::Type type, const uint index, const bool prefixIsId) {
 	const Common::String id = prefixIsId ? prefix : (prefix + "Texture");
 
-	if (shader->setUniform1I(id, *unit)) {
+	if (shader->setUniform(id, *unit)) {
 		texSamplers.push_back(TextureSampler((*unit)++, type, index));
 	}
 }
 
 void LibRetroPipeline::renderPass(const Pass &pass) {
 	// Activate shader and framebuffer to be used for rendering.
-	pass.shader->activate();
+	pass.shader->use();
 	setFramebuffer(pass.target);
 
 	// Activate attribute arrays and setup matching attributes.
@@ -414,16 +421,12 @@ void LibRetroPipeline::renderPass(const Pass &pass) {
 	// Actually draw something.
 	GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
 
-	// Deactivate attribute arrays.
-	renderPassCleanupCoordinates(pass);
-
-	// Deactivate shader.
-	pass.shader->deactivate();
+	// Unbind shader.
+	pass.shader->unbind();
 }
 
 void LibRetroPipeline::renderPassSetupCoordinates(const Pass &pass) {
-	GL_CALL(glEnableVertexAttribArray(pass.vertexCoordLocation));
-	GL_CALL(glVertexAttribPointer(pass.vertexCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, pass.vertexCoord));
+	pass.shader->enableVertexAttribute("VertexCoord", 2, GL_FLOAT, GL_FALSE, 0, pass.vertexCoord);
 
 	for (Pass::TexCoordAttributeArray::const_iterator i = pass.texCoords.begin(), end = pass.texCoords.end();
 	     i != end; ++i) {
@@ -448,17 +451,7 @@ void LibRetroPipeline::renderPassSetupCoordinates(const Pass &pass) {
 			continue;
 		}
 
-		GL_CALL(glEnableVertexAttribArray(i->location));
-		GL_CALL(glVertexAttribPointer(i->location, 2, GL_FLOAT, GL_FALSE, 0, texCoords));
-	}
-}
-
-void LibRetroPipeline::renderPassCleanupCoordinates(const Pass &pass) {
-	GL_CALL(glDisableVertexAttribArray(pass.vertexCoordLocation));
-
-	for (Pass::TexCoordAttributeArray::const_iterator i = pass.texCoords.begin(), end = pass.texCoords.end();
-	     i != end; ++i) {
-		GL_CALL(glDisableVertexAttribArray(i->location));
+		pass.shader->enableVertexAttribute(i->name.c_str(), 2, GL_FLOAT, GL_FALSE, 0, texCoords);
 	}
 }
 
diff --git a/backends/graphics/opengl/pipelines/libretro.h b/backends/graphics/opengl/pipelines/libretro.h
index c615b0d5a5d..a492b301854 100644
--- a/backends/graphics/opengl/pipelines/libretro.h
+++ b/backends/graphics/opengl/pipelines/libretro.h
@@ -23,7 +23,7 @@
 #ifndef BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_H
 #define BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_H
 
-#include "backends/graphics/opengl/opengl-sys.h"
+#include "graphics/opengl/system_headers.h"
 
 #if !USE_FORCED_GLES
 #include "backends/graphics/opengl/pipelines/shader.h"
@@ -51,7 +51,7 @@ public:
 	LibRetroPipeline(const Common::String &presetFileName);
 	virtual ~LibRetroPipeline();
 
-	virtual void drawTexture(const GLTexture &texture, const GLfloat *coordinates);
+	virtual void drawTexture(const GLTexture &texture, const GLfloat *coordinates, const GLfloat *texcoords);
 
 	virtual void setProjectionMatrix(const GLfloat *projectionMatrix);
 
@@ -97,29 +97,24 @@ private:
 
 	struct Pass {
 		Pass()
-		    : shaderPass(nullptr), shader(nullptr), target(nullptr), vertexCoordLocation(-1),
+		    : shaderPass(nullptr), shader(nullptr), target(nullptr),
 		      texCoords(), texSamplers(), inputTexture(nullptr), vertexCoord() {}
 		Pass(const LibRetro::ShaderPass *sP, Shader *s, TextureTarget *t)
-		    : shaderPass(sP), shader(s), target(t), vertexCoordLocation(-1), texCoords(),
+		    : shaderPass(sP), shader(s), target(t), texCoords(),
 		      texSamplers(), inputTexture(nullptr), vertexCoord() {}
 
 		const LibRetro::ShaderPass *shaderPass;
 		Shader *shader;
 		TextureTarget *target;
 
-		/**
-		 * Attribute location for vertex data.
-		 */
-		GLint vertexCoordLocation;
-
 		/**
 		 * Description of texture coordinates bound to attribute.
 		 */
 		struct TexCoordAttribute {
 			/**
-			 * Attribute location to bind data to.
+			 * Attribute name to bind data to.
 			 */
-			GLint location;
+			Common::String name;
 
 			enum Type {
 				/**
@@ -148,8 +143,8 @@ private:
 			 */
 			uint index;
 
-			TexCoordAttribute() : location(-1), type(), index() {}
-			TexCoordAttribute(GLint l, Type t, uint i) : location(l), type(t), index(i) {}
+			TexCoordAttribute() : name(), type(), index() {}
+			TexCoordAttribute(const Common::String &n, Type t, uint i) : name(n), type(t), index(i) {}
 		};
 
 		typedef Common::Array<TexCoordAttribute> TexCoordAttributeArray;
@@ -215,7 +210,7 @@ private:
 		 */
 		void buildTexSamplers(const uint id, const TextureArray &textures);
 
-		void addTexSampler(const Common::String &prefix, uint *unit, const TextureSampler::Type type, const uint index, const bool prefixIsId = false);
+		void addTexSampler(const Common::String &name, uint *unit, const TextureSampler::Type type, const uint index, const bool prefixIsId = false);
 
 		/**
 		 * Input texture of the pass.
@@ -233,7 +228,6 @@ private:
 
 	void renderPass(const Pass &pass);
 	void renderPassSetupCoordinates(const Pass &pass);
-	void renderPassCleanupCoordinates(const Pass &pass);
 	void renderPassSetupTextures(const Pass &pass);
 };
 
diff --git a/backends/graphics/opengl/pipelines/libretro/parser.cpp b/backends/graphics/opengl/pipelines/libretro/parser.cpp
index 6702240f060..a1dfa2c95cf 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.cpp
+++ b/backends/graphics/opengl/pipelines/libretro/parser.cpp
@@ -20,7 +20,7 @@
  *
  */
 
-#include "backends/graphics/opengl/opengl-sys.h"
+#include "graphics/opengl/system_headers.h"
 
 #if !USE_FORCED_GLES
 #include "backends/graphics/opengl/pipelines/libretro/parser.h"
diff --git a/backends/graphics/opengl/pipelines/libretro/parser.h b/backends/graphics/opengl/pipelines/libretro/parser.h
index 5cb91acd42e..92efc201f82 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.h
+++ b/backends/graphics/opengl/pipelines/libretro/parser.h
@@ -23,7 +23,7 @@
 #ifndef BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_PARSER_H
 #define BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_PARSER_H
 
-#include "backends/graphics/opengl/opengl-sys.h"
+#include "graphics/opengl/system_headers.h"
 
 #if !USE_FORCED_GLES
 #include "backends/graphics/opengl/pipelines/libretro/types.h"
diff --git a/backends/graphics/opengl/pipelines/libretro/types.h b/backends/graphics/opengl/pipelines/libretro/types.h
index 63ee96a1b76..33dabf7c24c 100644
--- a/backends/graphics/opengl/pipelines/libretro/types.h
+++ b/backends/graphics/opengl/pipelines/libretro/types.h
@@ -23,7 +23,7 @@
 #ifndef BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_TYPES_H
 #define BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_TYPES_H
 
-#include "backends/graphics/opengl/opengl-sys.h"
+#include "graphics/opengl/system_headers.h"
 
 #if !USE_FORCED_GLES
 #include "common/str.h"


Commit: 5e4aaf5757aa00588eec522c5e67235b922d0e42
    https://github.com/scummvm/scummvm/commit/5e4aaf5757aa00588eec522c5e67235b922d0e42
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Render the screen and cursor to a target before applying shaders

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp
    backends/graphics/opengl/opengl-graphics.h


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index f9b69ebbcfe..c899a0827dd 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -67,9 +67,9 @@ namespace OpenGL {
 
 OpenGLGraphicsManager::OpenGLGraphicsManager()
 	: _currentState(), _oldState(), _transactionMode(kTransactionNone), _screenChangeID(1 << (sizeof(int) * 8 - 2)),
-	  _pipeline(nullptr), _stretchMode(STRETCH_FIT),
+	  _pipeline(nullptr), _libretroPipeline(nullptr), _stretchMode(STRETCH_FIT),
 	  _defaultFormat(), _defaultFormatAlpha(),
-	  _gameScreen(nullptr), _overlay(nullptr),
+	  _gameScreen(nullptr), _gameScreenTarget(nullptr), _overlay(nullptr),
 	  _cursor(nullptr),
 	  _cursorHotspotX(0), _cursorHotspotY(0),
 	  _cursorHotspotXScaled(0), _cursorHotspotYScaled(0), _cursorWidthScaled(0), _cursorHeightScaled(0),
@@ -87,6 +87,7 @@ OpenGLGraphicsManager::OpenGLGraphicsManager()
 }
 
 OpenGLGraphicsManager::~OpenGLGraphicsManager() {
+	delete _gameScreenTarget;
 	delete _gameScreen;
 	delete _overlay;
 	delete _cursor;
@@ -455,6 +456,12 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
 		delete _gameScreen;
 		_gameScreen = nullptr;
 
+		if (_gameScreenTarget != nullptr) {
+			_gameScreenTarget->destroy();
+			delete _gameScreenTarget;
+			_gameScreenTarget = nullptr;
+		}
+
 		bool wantScaler = _currentState.scaleFactor > 1;
 
 #ifdef USE_RGB_COLOR
@@ -485,6 +492,12 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
 #else
 		_gameScreen->fill(0);
 #endif
+
+		if (_libretroPipeline) {
+			_gameScreenTarget = new TextureTarget();
+			_gameScreenTarget->create();
+			_gameScreenTarget->setSize(_currentState.gameWidth, _currentState.gameHeight);
+		}
 	}
 
 	// Update our display area and cursor scaling. This makes sure we pick up
@@ -591,7 +604,26 @@ void OpenGLGraphicsManager::updateScreen() {
 	_backBuffer.enableBlend(Framebuffer::kBlendModeDisabled);
 
 	// First step: Draw the (virtual) game screen.
-	Pipeline::getActivePipeline()->drawTexture(_gameScreen->getGLTexture(), _gameDrawRect.left, _gameDrawRect.top, _gameDrawRect.width(), _gameDrawRect.height());
+	if (_libretroPipeline) {
+		Framebuffer *lastFramebuffer = Pipeline::getActivePipeline()->setFramebuffer(_gameScreenTarget);
+		_gameScreenTarget->enableBlend(Framebuffer::kBlendModeDisabled);
+		Pipeline::getActivePipeline()->drawTexture(_gameScreen->getGLTexture(), 0, 0, _gameScreen->getWidth(), _gameScreen->getHeight());
+
+		// Draw the cursor if necessary.
+		if (_cursorVisible && _cursor && !_overlayVisible) {
+			int gameScreenCursorX = (_cursorX - _gameDrawRect.left) * _gameScreen->getWidth() / _gameDrawRect.width() - _cursorHotspotX;
+			int gameScreenCursorY = (_cursorY - _gameDrawRect.top) * _gameScreen->getHeight() / _gameDrawRect.height() - _cursorHotspotY;
+			_gameScreenTarget->enableBlend(Framebuffer::kBlendModePremultipliedTransparency);
+			Pipeline::getActivePipeline()->drawTexture(_cursor->getGLTexture(), gameScreenCursorX, gameScreenCursorY, _cursor->getWidth(), _cursor->getHeight());
+		}
+		Pipeline::getActivePipeline()->setFramebuffer(lastFramebuffer);
+
+		Pipeline *lastPipeline = Pipeline::setPipeline(_libretroPipeline);
+		Pipeline::getActivePipeline()->drawTexture(*_gameScreenTarget->getTexture(), _gameDrawRect.left, _gameDrawRect.top, _gameDrawRect.width(), _gameDrawRect.height());
+		Pipeline::setPipeline(lastPipeline);
+	} else {
+		Pipeline::getActivePipeline()->drawTexture(_gameScreen->getGLTexture(), _gameDrawRect.left, _gameDrawRect.top, _gameDrawRect.width(), _gameDrawRect.height());
+	}
 
 	// Second step: Draw the overlay if visible.
 	if (_overlayVisible) {
@@ -601,8 +633,8 @@ void OpenGLGraphicsManager::updateScreen() {
 		Pipeline::getActivePipeline()->drawTexture(_overlay->getGLTexture(), dstX, dstY, _overlayDrawRect.width(), _overlayDrawRect.height());
 	}
 
-	// Third step: Draw the cursor if visible.
-	if (_cursorVisible && _cursor) {
+	// Third step: Draw the cursor if necessary.
+	if (_cursorVisible && _cursor && (_overlayVisible || !_libretroPipeline)) {
 		_backBuffer.enableBlend(Framebuffer::kBlendModePremultipliedTransparency);
 
 		Pipeline::getActivePipeline()->drawTexture(_cursor->getGLTexture(),
@@ -1077,26 +1109,31 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 	delete _pipeline;
 	_pipeline = nullptr;
 
+	if (_libretroPipeline) {
+		delete _libretroPipeline;
+		_libretroPipeline = nullptr;
+	}
+
 	OpenGLContext.initialize(type);
 
 #if !USE_FORCED_GLES
 	if (OpenGLContext.shadersSupported) {
 		ShaderMan.notifyCreate();
-		//_pipeline = new ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)); FIXME
+		_pipeline = new ShaderPipeline(ShaderMan.query(ShaderManager::kDefault));
 
 		// Load selected shader preset from config file
 		if (ConfMan.hasKey("shader_scaler", Common::ConfigManager::kApplicationDomain)) {
 			Common::FSNode shaderPreset(ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));
 			if (shaderPreset.isReadable()) {
-				_pipeline = new LibRetroPipeline(ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));
+				_libretroPipeline = new LibRetroPipeline(ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));
 			} else {
 				// FIXME FIXME FIXME
-				_pipeline = new LibRetroPipeline("nearest.glslp");
+				_libretroPipeline = new LibRetroPipeline("nearest.glslp");
 				warning("Loaded fallback shader since requested shader is not available");
 			}
 		} else {
 			// FIXME FIXME FIXME
-			_pipeline = new LibRetroPipeline("nearest.glslp");
+			_libretroPipeline = new LibRetroPipeline("nearest.glslp");
 			warning("Loaded fallback shader since requested shader is not available");
 		}
 	}
@@ -1115,6 +1152,10 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 
 	_pipeline->setColor(1.0f, 1.0f, 1.0f, 1.0f);
 
+	if (_libretroPipeline) {
+		_libretroPipeline->setColor(1.0f, 1.0f, 1.0f, 1.0f);
+	}
+
 	// Setup backbuffer state.
 
 	// Default to black as clear color.
@@ -1122,6 +1163,10 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 
 	_pipeline->setFramebuffer(&_backBuffer);
 
+	if (_libretroPipeline) {
+		_libretroPipeline->setFramebuffer(&_backBuffer);
+	}
+
 	// We use a "pack" alignment (when reading from textures) to 4 here,
 	// since the only place where we really use it is the BMP screenshot
 	// code and that requires the same alignment too.
@@ -1142,6 +1187,10 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 		_gameScreen->recreate();
 	}
 
+	if (_gameScreenTarget) {
+		_gameScreenTarget->create();
+	}
+
 	if (_overlay) {
 		_overlay->recreate();
 	}
@@ -1170,6 +1219,10 @@ void OpenGLGraphicsManager::notifyContextDestroy() {
 		_gameScreen->destroy();
 	}
 
+	if (_gameScreenTarget) {
+		_gameScreenTarget->destroy();
+	}
+
 	if (_overlay) {
 		_overlay->destroy();
 	}
@@ -1199,6 +1252,11 @@ void OpenGLGraphicsManager::notifyContextDestroy() {
 	delete _pipeline;
 	_pipeline = nullptr;
 
+	if (_libretroPipeline) {
+		delete _libretroPipeline;
+		_libretroPipeline = nullptr;
+	}
+
 	// Rest our context description since the context is gone soon.
 	OpenGLContext.reset();
 }
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
index 5c894ee00ab..bb7e839bc14 100644
--- a/backends/graphics/opengl/opengl-graphics.h
+++ b/backends/graphics/opengl/opengl-graphics.h
@@ -290,6 +290,11 @@ private:
 	 */
 	Pipeline *_pipeline;
 
+	/**
+	 * OpenGL pipeline used for post-processing.
+	 */
+	Pipeline *_libretroPipeline;
+
 protected:
 	/**
 	 * Try to determine the internal parameters for a given pixel format.
@@ -328,6 +333,12 @@ protected:
 	 */
 	byte _gamePalette[3 * 256];
 
+	/**
+	 * The render target for the virtual game screen. Used when
+	 * LibRetro shaders are enabled.
+	 */
+	TextureTarget *_gameScreenTarget;
+
 	//
 	// Overlay
 	//


Commit: cdbb0fa32f4f607acd7d25098e649e22eec9073d
    https://github.com/scummvm/scummvm/commit/cdbb0fa32f4f607acd7d25098e649e22eec9073d
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Better path lookup and error handling

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp
    backends/graphics/opengl/pipelines/libretro.cpp
    backends/graphics/opengl/pipelines/libretro.h
    backends/graphics/opengl/pipelines/libretro/parser.cpp
    backends/graphics/opengl/pipelines/libretro/parser.h
    backends/graphics/opengl/pipelines/libretro/types.h


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index c899a0827dd..5973d41b625 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -1125,16 +1125,8 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 		if (ConfMan.hasKey("shader_scaler", Common::ConfigManager::kApplicationDomain)) {
 			Common::FSNode shaderPreset(ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));
 			if (shaderPreset.isReadable()) {
-				_libretroPipeline = new LibRetroPipeline(ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));
-			} else {
-				// FIXME FIXME FIXME
-				_libretroPipeline = new LibRetroPipeline("nearest.glslp");
-				warning("Loaded fallback shader since requested shader is not available");
+				_libretroPipeline = new LibRetroPipeline(shaderPreset);
 			}
-		} else {
-			// FIXME FIXME FIXME
-			_libretroPipeline = new LibRetroPipeline("nearest.glslp");
-			warning("Loaded fallback shader since requested shader is not available");
 		}
 	}
 #endif
diff --git a/backends/graphics/opengl/pipelines/libretro.cpp b/backends/graphics/opengl/pipelines/libretro.cpp
index 16431340701..2125717d7cf 100644
--- a/backends/graphics/opengl/pipelines/libretro.cpp
+++ b/backends/graphics/opengl/pipelines/libretro.cpp
@@ -30,7 +30,7 @@
 #include "graphics/opengl/debug.h"
 
 #include "common/textconsole.h"
-#include "common/fs.h"
+#include "common/tokenizer.h"
 #include "common/stream.h"
 
 #include "graphics/surface.h"
@@ -42,8 +42,7 @@
 namespace OpenGL {
 
 template<typename DecoderType>
-static Graphics::Surface *loadViaImageDecoder(const Common::String &fileName) {
-	Common::FSNode fileNode(fileName);
+static Graphics::Surface *loadViaImageDecoder(const Common::FSNode &fileNode) {
 	Common::SeekableReadStream *stream = fileNode.createReadStream();
 	if (!stream) {
 		return nullptr;
@@ -69,7 +68,7 @@ static Graphics::Surface *loadViaImageDecoder(const Common::String &fileName) {
 
 struct ImageLoader {
 	const char *extension;
-	Graphics::Surface *(*load)(const Common::String &fileName);
+	Graphics::Surface *(*load)(const Common::FSNode &fileNode);
 };
 
 static const ImageLoader s_imageLoaders[] = {
@@ -83,28 +82,21 @@ const char *const g_libretroShaderAttributes[] = {
 	"VertexCoord", nullptr
 };
 
-LibRetroPipeline::LibRetroPipeline(const Common::String &presetFileName)
+LibRetroPipeline::LibRetroPipeline()
     : ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)),
-      _shaderPreset(LibRetro::parsePreset(presetFileName)), _applyProjectionChanges(false),
+      _shaderPreset(nullptr), _applyProjectionChanges(false),
       _inputWidth(0), _inputHeight(0), _outputWidth(0), _outputHeight(0) {
-	initialize();
 }
 
-LibRetroPipeline::~LibRetroPipeline() {
-	for (TextureArray::size_type i = 0; i < _textures.size(); ++i) {
-		if (_textures[i].textureData) {
-			_textures[i].textureData->free();
-		}
-		delete _textures[i].textureData;
-		delete _textures[i].glTexture;
-	}
-
-	for (PassArray::size_type i = 0; i < _passes.size(); ++i) {
-		delete _passes[i].shader;
-		delete _passes[i].target;
-	}
+LibRetroPipeline::LibRetroPipeline(const Common::FSNode &shaderPreset)
+    : ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)),
+      _shaderPreset(nullptr), _applyProjectionChanges(false),
+      _inputWidth(0), _inputHeight(0), _outputWidth(0), _outputHeight(0) {
+	open(shaderPreset);
+}
 
-	delete _shaderPreset;
+LibRetroPipeline::~LibRetroPipeline() {
+	close();
 }
 
 void LibRetroPipeline::drawTexture(const GLTexture &texture, const GLfloat *coordinates, const GLfloat *texcoords) {
@@ -163,45 +155,80 @@ void LibRetroPipeline::setOutputSize(uint outputWidth, uint outputHeight) {
 	_outputHeight = outputHeight;
 }
 
-void LibRetroPipeline::initialize() {
-	// TODO: Error handling.
+bool LibRetroPipeline::open(const Common::FSNode &shaderPreset) {
+	_shaderPreset = LibRetro::parsePreset(shaderPreset);
+	if (!_shaderPreset)
+		return false;
+
+	if (!loadTextures()) {
+		close();
+		return false;
+	}
+
+	if (!loadPasses()) {
+		close();
+		return false;
+	}
 
-	loadTextures();
-	loadPasses();
+	return true;
 }
 
-void LibRetroPipeline::loadTextures() {
+void LibRetroPipeline::close() {
+	for (TextureArray::size_type i = 0; i < _textures.size(); ++i) {
+		if (_textures[i].textureData) {
+			_textures[i].textureData->free();
+		}
+		delete _textures[i].textureData;
+		delete _textures[i].glTexture;
+	}
+	_textures.clear();
+
+	for (PassArray::size_type i = 0; i < _passes.size(); ++i) {
+		delete _passes[i].shader;
+		delete _passes[i].target;
+	}
+	_passes.clear();
+
+	delete _shaderPreset;
+	_shaderPreset = nullptr;
+}
+
+static Common::FSNode getChildRecursive(const Common::FSNode &basePath, const Common::String &fileName) {
+	Common::FSNode finalPath = basePath;
+	Common::StringTokenizer tok(fileName, "\\/");
+	while (!tok.empty()) {
+		finalPath = finalPath.getChild(tok.nextToken());
+	}
+	return finalPath;
+}
+
+bool LibRetroPipeline::loadTextures() {
 	for (LibRetro::ShaderPreset::TextureArray::const_iterator
 	     i = _shaderPreset->textures.begin(), end = _shaderPreset->textures.end();
 	     i != end; ++i) {
-		// TODO: proper path look up
-		Common::String fileName = Common::normalizePath(_shaderPreset->basePath + '/' + i->fileName, '/');
-
-		Texture texture = loadTexture(fileName);
+		Texture texture = loadTexture(getChildRecursive( _shaderPreset->basePath, i->fileName));
 		texture.id = i->id;
 
-		// TODO: Error handling
 		if (!texture.textureData || !texture.glTexture) {
+			return false;
 		}
 
 		texture.glTexture->enableLinearFiltering(i->filteringMode == LibRetro::kFilteringModeLinear);
 		_textures.push_back(texture);
 	}
+	return true;
 }
 
-void LibRetroPipeline::loadPasses() {
+bool LibRetroPipeline::loadPasses() {
 	for (LibRetro::ShaderPreset::PassArray::const_iterator
 	     i = _shaderPreset->passes.begin(), end = _shaderPreset->passes.end();
 	     i != end; ++i) {
-		// TODO: proper path look up
-		Common::String fileName = Common::normalizePath(_shaderPreset->basePath + '/' + i->fileName, '/');
-		Common::FSNode fileNode(fileName);
+		Common::FSNode fileNode(getChildRecursive(_shaderPreset->basePath, i->fileName));
 
 		Common::SeekableReadStream *stream = fileNode.createReadStream();
 		if (!stream) {
-			warning("LibRetroPipeline::loadPasses: Could not open file '%s'", fileName.c_str());
-			// TODO: Error handling
-			continue;
+			warning("LibRetroPipeline::loadPasses: Could not open file '%s'", fileNode.getName().c_str());
+			return false;
 		}
 
 		Common::Array<char> shaderFileContents;
@@ -212,11 +239,11 @@ void LibRetroPipeline::loadPasses() {
 		stream = nullptr;
 
 		if (!readSuccess) {
-			warning("LibRetroPipeline::loadPasses: Could not read file '%s'", fileName.c_str());
-			// TODO: Error handling
+			warning("LibRetroPipeline::loadPasses: Could not read file '%s'", fileNode.getName().c_str());
+			return false;
 		}
 
-		Shader *shader = Shader::fromStrings(fileName,
+		Shader *shader = Shader::fromStrings(fileNode.getName(),
 		                                     ("#define VERTEX\n" + Common::String(shaderFileContents.begin())).c_str(),
 		                                     ("#define FRAGMENT\n" + Common::String(shaderFileContents.begin())).c_str(),
 		                                     g_libretroShaderAttributes);
@@ -243,6 +270,7 @@ void LibRetroPipeline::loadPasses() {
 			pass.inputTexture = texture;
 		}
 	}
+	return true;
 }
 
 void LibRetroPipeline::setPipelineState() {
@@ -319,7 +347,8 @@ void LibRetroPipeline::setShaderTexUniforms(const Common::String &prefix, Shader
 	shader->setUniform(prefix + "TextureSize", Math::Vector2d(texture.getWidth(), texture.getHeight()));
 }
 
-LibRetroPipeline::Texture LibRetroPipeline::loadTexture(const Common::String &fileName) {
+LibRetroPipeline::Texture LibRetroPipeline::loadTexture(const Common::FSNode &fileNode) {
+	Common::String fileName = fileNode.getName();
 	const char *extension = nullptr;
 	for (int dotPos = fileName.size() - 1; dotPos >= 0; --dotPos) {
 		if (fileName[dotPos] == '.') {
@@ -335,7 +364,7 @@ LibRetroPipeline::Texture LibRetroPipeline::loadTexture(const Common::String &fi
 
 	for (const ImageLoader *loader = s_imageLoaders; loader->extension; ++loader) {
 		if (!scumm_stricmp(loader->extension, extension)) {
-			Graphics::Surface *textureData = loader->load(fileName);
+			Graphics::Surface *textureData = loader->load(fileNode);
 			if (!textureData) {
 				warning("LibRetroPipeline::loadTexture: Loader for '%s' could not load file '%s'", loader->extension, fileName.c_str());
 				return Texture();
diff --git a/backends/graphics/opengl/pipelines/libretro.h b/backends/graphics/opengl/pipelines/libretro.h
index a492b301854..b276be1cff1 100644
--- a/backends/graphics/opengl/pipelines/libretro.h
+++ b/backends/graphics/opengl/pipelines/libretro.h
@@ -29,6 +29,7 @@
 #include "backends/graphics/opengl/pipelines/shader.h"
 
 #include "common/array.h"
+#include "common/fs.h"
 
 namespace Graphics {
 struct Surface;
@@ -48,7 +49,8 @@ class TextureTarget;
  */
 class LibRetroPipeline : public ShaderPipeline {
 public:
-	LibRetroPipeline(const Common::String &presetFileName);
+	LibRetroPipeline();
+	LibRetroPipeline(const Common::FSNode &shaderPreset);
 	virtual ~LibRetroPipeline();
 
 	virtual void drawTexture(const GLTexture &texture, const GLfloat *coordinates, const GLfloat *texcoords);
@@ -57,21 +59,23 @@ public:
 
 	void setOutputSize(uint outputWidth, uint outputHeight);
 
+	bool open(const Common::FSNode &shaderPreset);
+	void close();
+
 	bool isInitialized() const { return _shaderPreset != nullptr; }
 private:
 	virtual void activateInternal();
 	virtual void deactivateInternal();
 
-	void initialize();
-	void loadTextures();
-	void loadPasses();
+	bool loadTextures();
+	bool loadPasses();
 
 	void setPipelineState();
 	void setupFBOs();
 	void setupPassUniforms(const uint id);
 	void setShaderTexUniforms(const Common::String &prefix, Shader *shader, const GLTexture &texture);
 
-	const LibRetro::ShaderPreset *const _shaderPreset;
+	const LibRetro::ShaderPreset *_shaderPreset;
 
 	bool _applyProjectionChanges;
 
@@ -90,7 +94,7 @@ private:
 		Graphics::Surface *textureData;
 		GLTexture *glTexture;
 	};
-	Texture loadTexture(const Common::String &fileName);
+	Texture loadTexture(const Common::FSNode &fileNode);
 
 	typedef Common::Array<Texture> TextureArray;
 	TextureArray _textures;
diff --git a/backends/graphics/opengl/pipelines/libretro/parser.cpp b/backends/graphics/opengl/pipelines/libretro/parser.cpp
index a1dfa2c95cf..00893952927 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.cpp
+++ b/backends/graphics/opengl/pipelines/libretro/parser.cpp
@@ -32,7 +32,6 @@
 #include "common/tokenizer.h"
 #include "common/ptr.h"
 #include "common/util.h"
-#include "common/config-manager.h"
 
 #include "common/textconsole.h"
 
@@ -443,21 +442,19 @@ bool PresetParser::parsePassScale(const uint id, ShaderPass *pass) {
 }
 #undef passKey
 
-ShaderPreset *parsePreset(const Common::String &fileName) {
-	Common::String _shaderPath = ConfMan.get("shaderpath");
-	Common::FSNode fileNode(_shaderPath + fileName);
-	if (!fileNode.exists() || !fileNode.isReadable() || fileNode.isDirectory()) {
-		warning("LibRetro Preset Parsing: No such readable file '%s'", fileName.c_str());
+ShaderPreset *parsePreset(const Common::FSNode &shaderPreset) {
+	if (!shaderPreset.exists() || !shaderPreset.isReadable() || shaderPreset.isDirectory()) {
+		warning("LibRetro Preset Parsing: No such readable file '%s'", shaderPreset.getName().c_str());
 		return nullptr;
 	}
 
-	Common::FSNode basePath(_shaderPath);
+	Common::FSNode basePath(shaderPreset.getParent());
 	if (!basePath.exists() || !basePath.isReadable() || !basePath.isDirectory()) {
-		warning("LibRetro Preset Parsing: Base path '%s' to file '%s' invalid", basePath.getPath().c_str(), fileName.c_str());
+		warning("LibRetro Preset Parsing: Base path '%s' to file '%s' invalid", basePath.getName().c_str(), shaderPreset.getName().c_str());
 		return nullptr;
 	}
 
-	Common::SeekableReadStream *stream = fileNode.createReadStream();
+	Common::SeekableReadStream *stream = shaderPreset.createReadStream();
 	if (!stream) {
 		return nullptr;
 	}
@@ -468,11 +465,11 @@ ShaderPreset *parsePreset(const Common::String &fileName) {
 	stream = nullptr;
 
 	if (!shader) {
-		warning("LibRetro Preset Parsing: Error while parsing file '%s': %s", fileName.c_str(), parser.getErrorDesc().c_str());
+		warning("LibRetro Preset Parsing: Error while parsing file '%s': %s", shaderPreset.getName().c_str(), parser.getErrorDesc().c_str());
 		return nullptr;
 	}
 
-	shader->basePath = basePath.getPath();
+	shader->basePath = basePath;
 	return shader;
 }
 
diff --git a/backends/graphics/opengl/pipelines/libretro/parser.h b/backends/graphics/opengl/pipelines/libretro/parser.h
index 92efc201f82..42f0dcaf0a3 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.h
+++ b/backends/graphics/opengl/pipelines/libretro/parser.h
@@ -28,12 +28,12 @@
 #if !USE_FORCED_GLES
 #include "backends/graphics/opengl/pipelines/libretro/types.h"
 
-#include "common/str.h"
+#include "common/fs.h"
 
 namespace OpenGL {
 namespace LibRetro {
 
-ShaderPreset *parsePreset(const Common::String &fileName);
+ShaderPreset *parsePreset(const Common::FSNode &shaderPreset);
 
 } // End of namespace LibRetro
 } // End of namespace OpenGL
diff --git a/backends/graphics/opengl/pipelines/libretro/types.h b/backends/graphics/opengl/pipelines/libretro/types.h
index 33dabf7c24c..22e170368c4 100644
--- a/backends/graphics/opengl/pipelines/libretro/types.h
+++ b/backends/graphics/opengl/pipelines/libretro/types.h
@@ -28,6 +28,7 @@
 #if !USE_FORCED_GLES
 #include "common/str.h"
 #include "common/array.h"
+#include "common/fs.h"
 
 namespace OpenGL {
 namespace LibRetro {
@@ -107,7 +108,7 @@ struct ShaderPass {
 };
 
 struct ShaderPreset {
-	Common::String basePath;
+	Common::FSNode basePath;
 
 	typedef Common::Array<ShaderTexture> TextureArray;
 	TextureArray textures;


Commit: c5705561b03c32a63b548a88f2490f176f26ca7f
    https://github.com/scummvm/scummvm/commit/c5705561b03c32a63b548a88f2490f176f26ca7f
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Add compatibility checks for LibRetro shader support

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp
    backends/graphics/opengl/opengl-graphics.h
    backends/graphics/opengl/pipelines/libretro.h


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 5973d41b625..29f2f4854a5 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -61,19 +61,24 @@
 
 #include "common/text-to-speech.h"
 
+#if !USE_FORCED_GLES
 #include "backends/graphics/opengl/pipelines/libretro/parser.h"
+#endif
 
 namespace OpenGL {
 
 OpenGLGraphicsManager::OpenGLGraphicsManager()
 	: _currentState(), _oldState(), _transactionMode(kTransactionNone), _screenChangeID(1 << (sizeof(int) * 8 - 2)),
-	  _pipeline(nullptr), _libretroPipeline(nullptr), _stretchMode(STRETCH_FIT),
+	  _pipeline(nullptr), _stretchMode(STRETCH_FIT),
 	  _defaultFormat(), _defaultFormatAlpha(),
-	  _gameScreen(nullptr), _gameScreenTarget(nullptr), _overlay(nullptr),
+	  _gameScreen(nullptr), _overlay(nullptr),
 	  _cursor(nullptr),
 	  _cursorHotspotX(0), _cursorHotspotY(0),
 	  _cursorHotspotXScaled(0), _cursorHotspotYScaled(0), _cursorWidthScaled(0), _cursorHeightScaled(0),
 	  _cursorKeyColor(0), _cursorDontScale(false), _cursorPaletteEnabled(false), _shakeOffsetScaled()
+#if !USE_FORCED_GLES
+	  , _libretroPipeline(nullptr), _gameScreenTarget(nullptr)
+#endif
 #ifdef USE_OSD
 	  , _osdMessageChangeRequest(false), _osdMessageAlpha(0), _osdMessageFadeStartTime(0), _osdMessageSurface(nullptr),
 	  _osdIconSurface(nullptr)
@@ -87,7 +92,6 @@ OpenGLGraphicsManager::OpenGLGraphicsManager()
 }
 
 OpenGLGraphicsManager::~OpenGLGraphicsManager() {
-	delete _gameScreenTarget;
 	delete _gameScreen;
 	delete _overlay;
 	delete _cursor;
@@ -96,6 +100,7 @@ OpenGLGraphicsManager::~OpenGLGraphicsManager() {
 	delete _osdIconSurface;
 #endif
 #if !USE_FORCED_GLES
+	delete _gameScreenTarget;
 	ShaderManager::destroy();
 #endif
 }
@@ -456,11 +461,13 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
 		delete _gameScreen;
 		_gameScreen = nullptr;
 
+#if !USE_FORCED_GLES
 		if (_gameScreenTarget != nullptr) {
 			_gameScreenTarget->destroy();
 			delete _gameScreenTarget;
 			_gameScreenTarget = nullptr;
 		}
+#endif
 
 		bool wantScaler = _currentState.scaleFactor > 1;
 
@@ -493,11 +500,13 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
 		_gameScreen->fill(0);
 #endif
 
+#if !USE_FORCED_GLES
 		if (_libretroPipeline) {
 			_gameScreenTarget = new TextureTarget();
 			_gameScreenTarget->create();
 			_gameScreenTarget->setSize(_currentState.gameWidth, _currentState.gameHeight);
 		}
+#endif
 	}
 
 	// Update our display area and cursor scaling. This makes sure we pick up
@@ -603,25 +612,31 @@ void OpenGLGraphicsManager::updateScreen() {
 	// Alpha blending is disabled when drawing the screen
 	_backBuffer.enableBlend(Framebuffer::kBlendModeDisabled);
 
+	bool needsCursor = _cursorVisible && _cursor;
+
 	// First step: Draw the (virtual) game screen.
-	if (_libretroPipeline) {
+#if !USE_FORCED_GLES
+	if (_libretroPipeline && _libretroPipeline->isInitialized()) {
 		Framebuffer *lastFramebuffer = Pipeline::getActivePipeline()->setFramebuffer(_gameScreenTarget);
 		_gameScreenTarget->enableBlend(Framebuffer::kBlendModeDisabled);
 		Pipeline::getActivePipeline()->drawTexture(_gameScreen->getGLTexture(), 0, 0, _gameScreen->getWidth(), _gameScreen->getHeight());
 
 		// Draw the cursor if necessary.
-		if (_cursorVisible && _cursor && !_overlayVisible) {
+		if (needsCursor && !_overlayVisible) {
 			int gameScreenCursorX = (_cursorX - _gameDrawRect.left) * _gameScreen->getWidth() / _gameDrawRect.width() - _cursorHotspotX;
 			int gameScreenCursorY = (_cursorY - _gameDrawRect.top) * _gameScreen->getHeight() / _gameDrawRect.height() - _cursorHotspotY;
 			_gameScreenTarget->enableBlend(Framebuffer::kBlendModePremultipliedTransparency);
 			Pipeline::getActivePipeline()->drawTexture(_cursor->getGLTexture(), gameScreenCursorX, gameScreenCursorY, _cursor->getWidth(), _cursor->getHeight());
+			needsCursor = false;
 		}
 		Pipeline::getActivePipeline()->setFramebuffer(lastFramebuffer);
 
 		Pipeline *lastPipeline = Pipeline::setPipeline(_libretroPipeline);
 		Pipeline::getActivePipeline()->drawTexture(*_gameScreenTarget->getTexture(), _gameDrawRect.left, _gameDrawRect.top, _gameDrawRect.width(), _gameDrawRect.height());
 		Pipeline::setPipeline(lastPipeline);
-	} else {
+	} else
+#endif
+	{
 		Pipeline::getActivePipeline()->drawTexture(_gameScreen->getGLTexture(), _gameDrawRect.left, _gameDrawRect.top, _gameDrawRect.width(), _gameDrawRect.height());
 	}
 
@@ -634,7 +649,7 @@ void OpenGLGraphicsManager::updateScreen() {
 	}
 
 	// Third step: Draw the cursor if necessary.
-	if (_cursorVisible && _cursor && (_overlayVisible || !_libretroPipeline)) {
+	if (needsCursor) {
 		_backBuffer.enableBlend(Framebuffer::kBlendModePremultipliedTransparency);
 
 		Pipeline::getActivePipeline()->drawTexture(_cursor->getGLTexture(),
@@ -1109,10 +1124,12 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 	delete _pipeline;
 	_pipeline = nullptr;
 
+#if !USE_FORCED_GLES
 	if (_libretroPipeline) {
 		delete _libretroPipeline;
 		_libretroPipeline = nullptr;
 	}
+#endif
 
 	OpenGLContext.initialize(type);
 
@@ -1120,14 +1137,6 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 	if (OpenGLContext.shadersSupported) {
 		ShaderMan.notifyCreate();
 		_pipeline = new ShaderPipeline(ShaderMan.query(ShaderManager::kDefault));
-
-		// Load selected shader preset from config file
-		if (ConfMan.hasKey("shader_scaler", Common::ConfigManager::kApplicationDomain)) {
-			Common::FSNode shaderPreset(ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));
-			if (shaderPreset.isReadable()) {
-				_libretroPipeline = new LibRetroPipeline(shaderPreset);
-			}
-		}
 	}
 #endif
 
@@ -1144,10 +1153,6 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 
 	_pipeline->setColor(1.0f, 1.0f, 1.0f, 1.0f);
 
-	if (_libretroPipeline) {
-		_libretroPipeline->setColor(1.0f, 1.0f, 1.0f, 1.0f);
-	}
-
 	// Setup backbuffer state.
 
 	// Default to black as clear color.
@@ -1155,9 +1160,26 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 
 	_pipeline->setFramebuffer(&_backBuffer);
 
-	if (_libretroPipeline) {
+	// Setup LibRetro pipeline.
+
+#if !USE_FORCED_GLES
+	if (LibRetroPipeline::isSupportedByContext()) {
+		_libretroPipeline = new LibRetroPipeline();
+
+		// Load selected shader preset from config file
+		// TODO: Handle this in endGFXTransaction()
+		if (ConfMan.hasKey("shader_scaler", Common::ConfigManager::kApplicationDomain)) {
+			Common::FSNode shaderPreset(ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));
+			if (shaderPreset.isReadable()) {
+				if (!_libretroPipeline->open(shaderPreset))
+					warning("Failed to load %s", shaderPreset.getName().c_str());
+			}
+		}
+
+		_libretroPipeline->setColor(1.0f, 1.0f, 1.0f, 1.0f);
 		_libretroPipeline->setFramebuffer(&_backBuffer);
 	}
+#endif
 
 	// We use a "pack" alignment (when reading from textures) to 4 here,
 	// since the only place where we really use it is the BMP screenshot
@@ -1179,9 +1201,11 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 		_gameScreen->recreate();
 	}
 
+#if !USE_FORCED_GLES
 	if (_gameScreenTarget) {
 		_gameScreenTarget->create();
 	}
+#endif
 
 	if (_overlay) {
 		_overlay->recreate();
@@ -1211,9 +1235,11 @@ void OpenGLGraphicsManager::notifyContextDestroy() {
 		_gameScreen->destroy();
 	}
 
+#if !USE_FORCED_GLES
 	if (_gameScreenTarget) {
 		_gameScreenTarget->destroy();
 	}
+#endif
 
 	if (_overlay) {
 		_overlay->destroy();
@@ -1244,10 +1270,12 @@ void OpenGLGraphicsManager::notifyContextDestroy() {
 	delete _pipeline;
 	_pipeline = nullptr;
 
+#if !USE_FORCED_GLES
 	if (_libretroPipeline) {
 		delete _libretroPipeline;
 		_libretroPipeline = nullptr;
 	}
+#endif
 
 	// Rest our context description since the context is gone soon.
 	OpenGLContext.reset();
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
index bb7e839bc14..539d798776a 100644
--- a/backends/graphics/opengl/opengl-graphics.h
+++ b/backends/graphics/opengl/opengl-graphics.h
@@ -44,6 +44,9 @@ namespace OpenGL {
 
 class Surface;
 class Pipeline;
+#if !USE_FORCED_GLES
+class LibRetroPipeline;
+#endif
 
 enum {
 	GFX_OPENGL = 0
@@ -290,10 +293,12 @@ private:
 	 */
 	Pipeline *_pipeline;
 
+#if !USE_FORCED_GLES
 	/**
 	 * OpenGL pipeline used for post-processing.
 	 */
-	Pipeline *_libretroPipeline;
+	LibRetroPipeline *_libretroPipeline;
+#endif
 
 protected:
 	/**
@@ -333,11 +338,13 @@ protected:
 	 */
 	byte _gamePalette[3 * 256];
 
+#if !USE_FORCED_GLES
 	/**
 	 * The render target for the virtual game screen. Used when
 	 * LibRetro shaders are enabled.
 	 */
 	TextureTarget *_gameScreenTarget;
+#endif
 
 	//
 	// Overlay
diff --git a/backends/graphics/opengl/pipelines/libretro.h b/backends/graphics/opengl/pipelines/libretro.h
index b276be1cff1..36792bfd04c 100644
--- a/backends/graphics/opengl/pipelines/libretro.h
+++ b/backends/graphics/opengl/pipelines/libretro.h
@@ -63,6 +63,12 @@ public:
 	void close();
 
 	bool isInitialized() const { return _shaderPreset != nullptr; }
+
+	static bool isSupportedByContext() {
+		return OpenGLContext.shadersSupported
+		    && OpenGLContext.multitextureSupported
+		    && OpenGLContext.framebufferObjectSupported;
+	}
 private:
 	virtual void activateInternal();
 	virtual void deactivateInternal();


Commit: 64c359b5cb9fd3e0f49d8ff35be686dd3d4217b1
    https://github.com/scummvm/scummvm/commit/64c359b5cb9fd3e0f49d8ff35be686dd3d4217b1
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Replace the options for selecting shaders

Changed paths:
    backends/graphics/graphics.h
    backends/modular-backend.cpp
    backends/modular-backend.h
    base/main.cpp
    common/system.cpp
    common/system.h
    engines/engine.cpp
    gui/editgamedialog.cpp
    gui/options.cpp
    gui/options.h
    gui/themes/common/highres_layout.stx
    gui/themes/common/lowres_layout.stx
    gui/themes/default.inc
    gui/themes/scummclassic/classic_layout.stx
    gui/themes/scummclassic/classic_layout_lowres.stx


diff --git a/backends/graphics/graphics.h b/backends/graphics/graphics.h
index fffcd0f11a5..583e3a6c96e 100644
--- a/backends/graphics/graphics.h
+++ b/backends/graphics/graphics.h
@@ -48,13 +48,7 @@ public:
 	virtual int getDefaultGraphicsMode() const { return 0; }
 	virtual bool setGraphicsMode(int mode, uint flags = OSystem::kGfxModeNoFlags) { return (mode == 0); }
 	virtual int getGraphicsMode() const { return 0; }
-	virtual const OSystem::GraphicsMode *getSupportedShaders() const {
-		static const OSystem::GraphicsMode no_shader[2] = {{"NONE", "Normal (no shader)", 0}, {0, 0, 0}};
-		return no_shader;
-	}
-	virtual int getDefaultShader() const { return 0; }
-	virtual bool setShader(int id) { return false; }
-	virtual int getShader() const { return 0; }
+	virtual bool setShader(const Common::FSNode &fileNode) { return false; }
 	virtual const OSystem::GraphicsMode *getSupportedStretchModes() const {
 		static const OSystem::GraphicsMode noStretchModes[] = {{"NONE", "Normal", 0}, {nullptr, nullptr, 0 }};
 		return noStretchModes;
diff --git a/backends/modular-backend.cpp b/backends/modular-backend.cpp
index f2dcf706752..1e4e56da1a1 100644
--- a/backends/modular-backend.cpp
+++ b/backends/modular-backend.cpp
@@ -73,20 +73,8 @@ int ModularGraphicsBackend::getGraphicsMode() const {
 	return _graphicsManager->getGraphicsMode();
 }
 
-const OSystem::GraphicsMode *ModularGraphicsBackend::getSupportedShaders() const {
-	return _graphicsManager->getSupportedShaders();
-}
-
-int ModularGraphicsBackend::getDefaultShader() const {
-	return _graphicsManager->getDefaultShader();
-}
-
-bool ModularGraphicsBackend::setShader(int id) {
-	return _graphicsManager->setShader(id);
-}
-
-int ModularGraphicsBackend::getShader() const {
-	return _graphicsManager->getShader();
+bool ModularGraphicsBackend::setShader(const Common::FSNode &fileNode) {
+	return _graphicsManager->setShader(fileNode);
 }
 
 const OSystem::GraphicsMode *ModularGraphicsBackend::getSupportedStretchModes() const {
diff --git a/backends/modular-backend.h b/backends/modular-backend.h
index 40b9a06c37c..4c9a8e1a01b 100644
--- a/backends/modular-backend.h
+++ b/backends/modular-backend.h
@@ -67,10 +67,7 @@ public:
 	int getDefaultGraphicsMode() const override;
 	bool setGraphicsMode(int mode, uint flags = kGfxModeNoFlags) override;
 	int getGraphicsMode() const override;
-	const GraphicsMode *getSupportedShaders() const override final;
-	int getDefaultShader() const override final;
-	int getShader() const override final;
-	bool setShader(int id) override final;
+	bool setShader(const Common::FSNode &node) override final;
 	const GraphicsMode *getSupportedStretchModes() const override final;
 	int getDefaultStretchMode() const override final;
 	bool setStretchMode(int mode) override final;
diff --git a/base/main.cpp b/base/main.cpp
index 788bb33c04e..a1eed693bee 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -353,8 +353,8 @@ static void setupGraphics(OSystem &system) {
 		// Set the user specified graphics mode (if any).
 		system.setGraphicsMode(ConfMan.get("gfx_mode").c_str());
 		system.setStretchMode(ConfMan.get("stretch_mode").c_str());
-		system.setShader(ConfMan.get("shader").c_str());
 		system.setScaler(ConfMan.get("scaler").c_str(), ConfMan.getInt("scale_factor"));
+		system.setShader(Common::FSNode(ConfMan.get("shader")));
 
 		system.initSize(320, 200);
 
diff --git a/common/system.cpp b/common/system.cpp
index 6fe04a7caeb..b9a9d363fc4 100644
--- a/common/system.cpp
+++ b/common/system.cpp
@@ -141,27 +141,6 @@ bool OSystem::setGraphicsMode(const char *name) {
 	return false;
 }
 
-bool OSystem::setShader(const char *name) {
-	if (!name)
-		return false;
-
-	// Special case for the 'default' filter
-	if (!scumm_stricmp(name, "default")) {
-		return setShader(getDefaultShader());
-	}
-
-	const GraphicsMode *sm = getSupportedShaders();
-
-	while (sm->name) {
-		if (!scumm_stricmp(sm->name, name)) {
-			return setShader(sm->id);
-		}
-		sm++;
-	}
-
-	return false;
-}
-
 bool OSystem::setStretchMode(const char *name) {
 	if (!name)
 		return false;
diff --git a/common/system.h b/common/system.h
index 6418ae118b8..2ab1486999a 100644
--- a/common/system.h
+++ b/common/system.h
@@ -46,6 +46,7 @@ class OptionsContainerWidget;
 
 namespace Common {
 class EventManager;
+class FSNode;
 class MutexInternal;
 struct Rect;
 class SaveFileManager;
@@ -483,7 +484,7 @@ public:
 		/**
 		* Shaders.
 		*/
-		kFeatureShader,
+		kFeatureShaders,
 
 		/**
 		* Support for using the native system file browser dialog
@@ -765,65 +766,15 @@ public:
 #endif
 
 	/**
-	 * Retrieve a list of all hardware shaders supported by this backend.
+	 * Load the specified shader.
 	 *
-	 * This can be only hardware shaders.
-	 * It is completely up to the backend maintainer to decide what is
-	 * appropriate here and what not.
-	 * The list is terminated by an all-zero entry.
-	 *
-	 * @return List of supported shaders.
-	 */
-	virtual const GraphicsMode *getSupportedShaders() const {
-		static const OSystem::GraphicsMode no_shader[2] = {{"NONE", "Normal (no shader)", 0}, {nullptr, nullptr, 0}};
-		return no_shader;
-	}
-
-	/**
-	 * Return the ID of the 'default' shader mode.
-	 *
-	 * What exactly this means is up to the backend.
-	 * This mode is set by the client code when no user overrides
-	 * are present (i.e. if no custom shader mode is selected using
-	 * the command line or a config file).
+	 * If loading the new shader fails, this method returns false.
 	 *
-	 * @return ID of the 'default' shader mode.
-	 */
-	virtual int getDefaultShader() const { return 0; }
-
-	/**
-	 * Switch to the specified shader mode.
-	 *
-	 * If switching to the new mode fails, this method returns false.
-	 *
-	 * @param id ID of the new shader mode.
+	 * @param fileNode File node of the new shader.
 	 *
 	 * @return True if the switch was successful, false otherwise.
 	 */
-	virtual bool setShader(int id) { return false; }
-
-	/**
-	 * Switch to the shader mode with the given name.
-	 *
-	 * If @p name is unknown, or if switching to the new mode fails,
-	 * this method returns false.
-	 *
-	 * @param name Name of the new shader mode.
-	 *
-	 * @return True if the switch was successful, false otherwise.
-	 *
-	 * @note This is implemented using the setShader(int) method, as well
-	 *       as getSupportedShaders() and getDefaultShader().
-	 *       In particular, backends do not have to overload this!
-	 */
-	bool setShader(const char *name);
-
-	/**
-	 * Determine which shader is currently active.
-	 *
-	 * @return ID of the active shader.
-	 */
-	virtual int getShader() const { return 0; }
+	virtual bool setShader(const Common::FSNode &fileNode) { return false; }
 
 	/**
 	 * Retrieve a list of all stretch modes supported by this backend.
@@ -899,8 +850,8 @@ public:
 	 * Return the 'default' scale factor.
 	 *
 	 * This mode is set by the client code when no user overrides
-	 * are present (i.e. if no custom shader mode is selected using
-	 * the command line or a config file).
+	 * are present (i.e. if no custom scaler is selected using the
+	 * command line or a config file).
 	 *
 	 * @return The 'default' scale factor.
 	 */
diff --git a/engines/engine.cpp b/engines/engine.cpp
index a206d5bc8d8..a0489be4a76 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -219,7 +219,7 @@ void initCommonGFX() {
 			g_system->setScaler(ConfMan.get("scaler").c_str(), ConfMan.getInt("scale_factor"));
 
 		if (gameDomain->contains("shader"))
-			g_system->setShader(ConfMan.get("shader").c_str());
+			g_system->setShader(Common::FSNode(ConfMan.get("shader")));
 	}
 }
 
diff --git a/gui/editgamedialog.cpp b/gui/editgamedialog.cpp
index 7b3bdf5d147..2aecd2aa24d 100644
--- a/gui/editgamedialog.cpp
+++ b/gui/editgamedialog.cpp
@@ -221,7 +221,7 @@ EditGameDialog::EditGameDialog(const Common::String &domain)
 	//
 
 	_globalShaderOverride = nullptr;
-	if (g_system->hasFeature(OSystem::kFeatureShader)) {
+	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
 		tab->addTab(_("Shader"), "GameOptions_Shader");
 
 		if (g_system->getOverlayWidth() > 320)
@@ -421,7 +421,7 @@ void EditGameDialog::open() {
 		ConfMan.hasKey("antialiasing", _domain);
 	_globalGraphicsOverride->setState(e);
 
-	if (g_system->hasFeature(OSystem::kFeatureShader)) {
+	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
 		e = ConfMan.hasKey("shader", _domain);
 		_globalShaderOverride->setState(e);
 	}
diff --git a/gui/options.cpp b/gui/options.cpp
index 2878d2208ca..7417c3e1f2c 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -92,8 +92,8 @@ enum {
 	kPluginsPathClearCmd	= 'clpl',
 	kChooseThemeCmd			= 'chtf',
 	kUpdateIconsCmd			= 'upic',
-	kChooseShaderDirCmd     = 'chsh',
-	kShaderPathClearCmd     = 'chsc',
+	kChooseShaderCmd        = 'chsh',
+	kClearShaderCmd         = 'clsh',
 	kUpdatesCheckCmd		= 'updc',
 	kKbdMouseSpeedChanged	= 'kmsc',
 	kJoystickDeadzoneChanged= 'jodc',
@@ -157,12 +157,12 @@ static const int guiBaseValues[] = { 150, 125, 100, 75, -1 };
 static const char *kbdMouseSpeedLabels[] = { "3", "5", "8", "10", "13", "15", "18", "20", nullptr };
 
 OptionsDialog::OptionsDialog(const Common::String &domain, int x, int y, int w, int h)
-	: Dialog(x, y, w, h), _domain(domain), _graphicsTabId(-1), _midiTabId(-1), _pathsTabId(-1), _tabWidget(nullptr) {
+	: Dialog(x, y, w, h), _domain(domain), _graphicsTabId(-1), _shaderTabId(-1), _midiTabId(-1), _pathsTabId(-1), _tabWidget(nullptr) {
 	init();
 }
 
 OptionsDialog::OptionsDialog(const Common::String &domain, const Common::String &name)
-	: Dialog(name), _domain(domain), _graphicsTabId(-1), _midiTabId(-1), _pathsTabId(-1), _tabWidget(nullptr) {
+	: Dialog(name), _domain(domain), _graphicsTabId(-1), _shaderTabId(-1), _midiTabId(-1), _pathsTabId(-1), _tabWidget(nullptr) {
 	init();
 }
 
@@ -195,8 +195,9 @@ void OptionsDialog::init() {
 	_filteringCheckbox = nullptr;
 	_aspectCheckbox = nullptr;
 	_enableShaderSettings = false;
-	_shaderPopUpDesc = nullptr;
-	_shaderPopUp = nullptr;
+	_shader = nullptr;
+	_shaderButton = nullptr;
+	_shaderClearButton = nullptr;
 	_vsyncCheckbox = nullptr;
 	_rendererTypePopUpDesc = nullptr;
 	_rendererTypePopUp = nullptr;
@@ -420,24 +421,23 @@ void OptionsDialog::build() {
 	}
 
 	// Shader options
-	if (_shaderPopUp) {
-		_shaderPopUp->setSelected(0);
-
-		if (g_system->hasFeature(OSystem::kFeatureShader)) {
-			if (ConfMan.hasKey("shader", _domain)) {
-				const OSystem::GraphicsMode *sm = g_system->getSupportedShaders();
-				Common::String shader(ConfMan.get("shader", _domain));
-				int shaderCount = 1;
-				while (sm->name) {
-					shaderCount++;
-					if (scumm_stricmp(sm->name, shader.c_str()) == 0)
-						_shaderPopUp->setSelected(shaderCount);
-					sm++;
-				}
+	if (_shader) {
+		if (g_system->hasFeature(OSystem::kFeatureShaders)) {
+			Common::String shader(ConfMan.get("shader", _domain));
+			if (ConfMan.isKeyTemporary("shader")) {
+				_shader->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
+			}
+			if (shader.empty() || !ConfMan.hasKey("shader", _domain)) {
+				_shader->setLabel(_c("None", "shader"));
+				_shaderClearButton->setEnabled(false);
+			} else {
+				_shader->setLabel(shader);
+				_shaderClearButton->setEnabled(true);
 			}
 		} else {
-			_shaderPopUpDesc->setVisible(false);
-			_shaderPopUp->setVisible(false);
+			_shader->setVisible(false);
+			_shaderButton->setVisible(false);
+			_shaderClearButton->setVisible(false);
 		}
 	}
 
@@ -708,28 +708,27 @@ void OptionsDialog::apply() {
 	}
 
 	// Shader options
-	if (_shaderPopUp) {
+	if (_shader) {
 		if (_enableShaderSettings) {
-			bool isSet = false;
+			bool isSet;
 
-			if ((int32)_shaderPopUp->getSelectedTag() >= 0) {
-				const OSystem::GraphicsMode *sm = g_system->getSupportedShaders();
-				while (sm->name) {
-					if (sm->id == (int)_shaderPopUp->getSelectedTag()) {
-						if (ConfMan.get("shader", _domain) != sm->name)
-							graphicsModeChanged = true;
-						ConfMan.set("shader", sm->name, _domain);
-						isSet = true;
-						break;
-					}
-					sm++;
-				}
-			}
-			if (!isSet) {
-				ConfMan.removeKey("shader", _domain);
-				if (g_system->getShader() != g_system->getDefaultShader())
+			Common::U32String shader(_shader->getLabel());
+			if (shader.empty() || (shader == _c("None", "shader")))
+				isSet = false;
+			else
+				isSet = true;
+
+			if (isSet) {
+				if (!ConfMan.hasKey("shader", _domain) || shader != ConfMan.get("shader", _domain))
 					graphicsModeChanged = true;
+				ConfMan.set("shader", shader.encode(), _domain);
+			} else {
+				if (ConfMan.hasKey("shader", _domain) && !ConfMan.get("shader", _domain).empty())
+					graphicsModeChanged = true;
+				ConfMan.removeKey("shader", _domain);
 			}
+
+			_shader->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 		} else {
 			ConfMan.removeKey("shader", _domain);
 		}
@@ -741,6 +740,7 @@ void OptionsDialog::apply() {
 		g_system->setGraphicsMode(ConfMan.get("gfx_mode", _domain).c_str());
 		g_system->setStretchMode(ConfMan.get("stretch_mode", _domain).c_str());
 		g_system->setScaler(ConfMan.get("scaler", _domain).c_str(), ConfMan.getInt("scale_factor", _domain));
+		g_system->setShader(Common::FSNode(ConfMan.get("shader", _domain)));
 
 		if (ConfMan.hasKey("aspect_ratio"))
 			g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, ConfMan.getBool("aspect_ratio", _domain));
@@ -749,8 +749,6 @@ void OptionsDialog::apply() {
 		if (ConfMan.hasKey("filtering"))
 			g_system->setFeatureState(OSystem::kFeatureFilteringMode, ConfMan.getBool("filtering", _domain));
 
-		g_system->setShader(ConfMan.get("shader", _domain).c_str());
-
 		OSystem::TransactionError gfxError = g_system->endGFXTransaction();
 
 		// Since this might change the screen resolution we need to give
@@ -1007,6 +1005,11 @@ void OptionsDialog::close() {
 
 void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
 	switch (cmd) {
+	case kClearShaderCmd:
+		_shader->setLabel(_c("None", "shader"));
+		_shaderClearButton->setEnabled(false);
+		g_gui.scheduleTopDialogRedraw();
+		break;
 	case kMidiGainChanged:
 		_midiGainLabel->setLabel(Common::String::format("%.2f", (double)_midiGainSlider->getValue() / 100.0));
 		_midiGainLabel->markAsDirty();
@@ -1171,8 +1174,16 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
 void OptionsDialog::setShaderSettingsState(bool enabled) {
 	_enableShaderSettings = enabled;
 
-	_shaderPopUpDesc->setEnabled(enabled);
-	_shaderPopUp->setEnabled(enabled);
+	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
+		_shader->setEnabled(enabled);
+		_shaderButton->setEnabled(enabled);
+		_shaderClearButton->setEnabled(enabled);
+
+		if (enabled && !_shader->getLabel().empty() && (_shader->getLabel() != _c("None", "shader")))
+			_shaderClearButton->setEnabled(enabled);
+		else
+			_shaderClearButton->setEnabled(false);
+	}
 }
 
 void OptionsDialog::setAudioSettingsState(bool enabled) {
@@ -1423,24 +1434,14 @@ void OptionsDialog::addStatisticsControls(GuiObject *boss, const Common::String
 }
 
 void OptionsDialog::addShaderControls(GuiObject *boss, const Common::String &prefix) {
-	Common::String context;
-	if (g_system->getOverlayWidth() <= 320)
-		context = "lowres";
-
 	// Shader selector
 	if (g_system->getOverlayWidth() > 320)
-		_shaderPopUpDesc = new StaticTextWidget(boss, prefix + "grShaderPopUpDesc", _("HW Shader:"), _("Different hardware shaders give different visual effects"));
+		_shaderButton = new ButtonWidget(boss, prefix + "grShaderButton", _("Shader Path:"), _("Specifies path to the shaders used for scaling ScummVM"), kChooseShaderCmd);
 	else
-		_shaderPopUpDesc = new StaticTextWidget(boss, prefix + "grShaderPopUpDesc", _c("HW Shader:", "lowres"), _("Different hardware shaders give different visual effects"));
-	_shaderPopUp = new PopUpWidget(boss, prefix + "grShaderPopUp", _("Different shaders give different visual effects"));
-	const OSystem::GraphicsMode *p = g_system->getSupportedShaders();
+		_shaderButton = new ButtonWidget(boss, prefix + "grShaderButton", _c("Shader Path:", "lowres"), _("Specifies path to the shaders used for scaling ScummVM"), kChooseShaderCmd);
+	_shader = new StaticTextWidget(boss, prefix + "grShader", _c("None", "shader"), _("Specifies path to the shaders used for scaling ScummVM"));
 
-	_shaderPopUp->appendEntry(_("<default>"));
-	_shaderPopUp->appendEntry(Common::U32String());
-	while (p->name) {
-		_shaderPopUp->appendEntry(_c(p->description, context), p->id);
-		p++;
-	}
+	_shaderClearButton = addClearButton(boss, prefix + "grShaderClearButton", kClearShaderCmd);
 
 	_enableShaderSettings = true;
 }
@@ -1949,8 +1950,6 @@ GlobalOptionsDialog::GlobalOptionsDialog(LauncherDialog *launcher)
 	_iconPathClearButton = nullptr;
 	_extraPath = nullptr;
 	_extraPathClearButton = nullptr;
-	//_shaderPath = nullptr;
-	//_shaderPathClearButton = nullptr;
 #ifdef DYNAMIC_MODULES
 	_pluginsPath = nullptr;
 	_pluginsPathClearButton = nullptr;
@@ -2049,11 +2048,11 @@ void GlobalOptionsDialog::build() {
 	addGraphicControls(graphicsContainer, "GlobalOptions_Graphics_Container.");
 
 	//
-	// The shader tab (currently visible only for Vita platform), visibility checking by features
+	// The shader tab, visibility checking by features
 	//
 
-	if (g_system->hasFeature(OSystem::kFeatureShader)) {
-		tab->addTab(_("Shader"), "GlobalOptions_Shader");
+	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
+		_shaderTabId = tab->addTab(_("Shader"), "GlobalOptions_Shader");
 		addShaderControls(tab, "GlobalOptions_Shader.");
 	}
 
@@ -2222,7 +2221,6 @@ void GlobalOptionsDialog::build() {
 	setPath(_themePath, "themepath", _c("None", "path"));
 	setPath(_iconPath, "iconspath", _("Default"));
 	setPath(_extraPath, "extrapath", _c("None", "path"));
-	// setPath(_shaderPath, "shaderpath", _c("None", "path"));
 
 #ifdef DYNAMIC_MODULES
 	Common::String pluginsPath(ConfMan.get("pluginspath", _domain));
@@ -2321,14 +2319,6 @@ void GlobalOptionsDialog::addPathsControls(GuiObject *boss, const Common::String
 
 	_extraPathClearButton = addClearButton(boss, prefix + "ExtraPathClearButton", kExtraPathClearCmd);
 
-	//if (!lowres)
-	//	new ButtonWidget(boss, prefix + "ShaderButton", _("Shader Path:"), _("Specifies path to the shaders used for scaling ScummVM"), kChooseShaderDirCmd);
-	//else
-	//		new ButtonWidget(boss, prefix + "ShaderButton", _c("Shader Path:", "lowres"), _("Specifies path to the shaders used for scaling ScummVM"), kChooseShaderDirCmd);
-	//_shaderPath = new StaticTextWidget(boss, prefix + "ShaderPath", _c("None", "path"), _("Specifies path to the shaders used for scaling ScummVM"));
-
-	//_shaderPathClearButton = addClearButton(boss, prefix + "ShaderPathClearButton", kShaderPathClearCmd);
-
 #ifdef DYNAMIC_MODULES
 	if (!lowres)
 		new ButtonWidget(boss, prefix + "PluginsButton", _("Plugins Path:"), Common::U32String(), kChoosePluginsDirCmd);
@@ -2725,12 +2715,6 @@ void GlobalOptionsDialog::apply() {
 	changePath(_iconPath, "iconspath", _("Default"));
 	changePath(_extraPath, "extrapath", _c("None", "path")); 
 
-	//Common::U32String shaderPath(_shaderPath->getLabel());
-	//if (!shaderPath.empty() && (shaderPath != _c("None", "path")))
-	//	ConfMan.set("shaderpath", shaderPath.encode(), _domain);
-	//else
-	//	ConfMan.removeKey("shaderpath", _domain);
-
 #ifdef DYNAMIC_MODULES
 	Common::U32String pluginsPath(_pluginsPath->getLabel());
 	if (!pluginsPath.empty() && (pluginsPath != _c("None", "path")))
@@ -2978,16 +2962,6 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 		}
 		break;
 	}
-	//case kChooseShaderDirCmd: {
-	//	BrowserDialog browser(_("Select directory for scaling shaders"), true);
-	//	if (browser.runModal() > 0) {
-	//		Common::FSNode dir(browser.getResult());
-	//		_shaderPath->setLabel(dir.getPath());
-	//		g_gui.scheduleTopDialogRedraw();
-	//		warning("Dialog triggered, there be dragons and the scaling scanner dialog!");
-	//	}
-	//	break;
-	//}
 #ifdef DYNAMIC_MODULES
 	case kChoosePluginsDirCmd: {
 		BrowserDialog browser(_("Select directory for plugins"), true);
@@ -3038,8 +3012,6 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 	case kSavePathClearCmd:
 		_savePath->setLabel(_("Default"));
 		break;
-	//case kShaderPathClearCmd:
-	//	_shaderPath->setLabel(_("Default"));
 #ifdef DYNAMIC_MODULES
 	case kPluginsPathClearCmd:
 		_pluginsPath->setLabel(_c("None", "path"));
@@ -3058,6 +3030,22 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 		break;
 #endif
 #endif
+	case kChooseShaderCmd: {
+		BrowserDialog browser(_("Select shader"), false);
+		if (browser.runModal() > 0) {
+			// User made his choice...
+			Common::FSNode file(browser.getResult());
+			_shader->setLabel(file.getPath());
+
+			if (!file.getPath().empty() && (file.getPath().decode() != _c("None", "path")))
+				_shaderClearButton->setEnabled(true);
+			else
+				_shaderClearButton->setEnabled(false);
+
+			g_gui.scheduleTopDialogRedraw();
+		}
+		break;
+	}
 	case kChooseSoundFontCmd: {
 		BrowserDialog browser(_("Select SoundFont"), false);
 		if (browser.runModal() > 0) {
@@ -3294,6 +3282,17 @@ void GlobalOptionsDialog::reflowLayout() {
 	int firstVisible = _tabWidget->getFirstVisible();
 	int activeTab = _tabWidget->getActiveTab();
 
+	if (_shaderTabId != -1) {
+		_tabWidget->setActiveTab(_shaderTabId);
+
+		bool enabled = _shaderClearButton->isEnabled();
+		_tabWidget->removeWidget(_shaderClearButton);
+		_shaderClearButton->setNext(nullptr);
+		delete _shaderClearButton;
+		_shaderClearButton = addClearButton(_tabWidget, "GlobalOptions_Shader.grShaderClearButton", kClearShaderCmd);
+		_shaderClearButton->setEnabled(enabled);
+	}
+
 	if (_midiTabId != -1) {
 		_tabWidget->setActiveTab(_midiTabId);
 
@@ -3332,11 +3331,6 @@ void GlobalOptionsDialog::reflowLayout() {
 		_browserPathClearButton->setNext(nullptr);
 		delete _browserPathClearButton;
 		_browserPathClearButton = addClearButton(_tabWidget, "GlobalOptions_Paths.BrowserPathClearButton", kBrowserPathClearCmd);
-
-		//_tabWidget->removeWidget(_shaderPathClearButton);
-		//_shaderPathClearButton->setNext(nullptr);
-		//delete _shaderPathClearButton;
-		//_shaderPathClearButton = addClearButton(_tabWidget, "GlobalOptions_Paths.ShaderPathClearButton", kShaderPathClearCmd);
 	}
 
 	_tabWidget->setActiveTab(activeTab);
diff --git a/gui/options.h b/gui/options.h
index 9f83a95c93f..69d80505c95 100644
--- a/gui/options.h
+++ b/gui/options.h
@@ -79,6 +79,10 @@ protected:
 	/** Config domain this dialog is used to edit. */
 	Common::String _domain;
 
+	ButtonWidget *_shaderButton;
+	StaticTextWidget *_shader;
+	ButtonWidget *_shaderClearButton;
+
 	ButtonWidget *_soundFontButton;
 	StaticTextWidget *_soundFont;
 	ButtonWidget *_soundFontClearButton;
@@ -118,6 +122,7 @@ protected:
 
 	TabWidget *_tabWidget;
 	int _graphicsTabId;
+	int _shaderTabId;
 	int _midiTabId;
 	int _pathsTabId;
 
@@ -167,8 +172,6 @@ private:
 	// Shader controls
 	//
 	bool _enableShaderSettings;
-	StaticTextWidget *_shaderPopUpDesc;
-	PopUpWidget *_shaderPopUp;
 
 	//
 	// Audio controls
@@ -285,8 +288,6 @@ protected:
 	ButtonWidget	 *_iconPathClearButton;
 	StaticTextWidget *_extraPath;
 	ButtonWidget	 *_extraPathClearButton;
-	StaticTextWidget *_shaderPath;
-	ButtonWidget	 *_shaderPathClearButton;
 #ifdef DYNAMIC_MODULES
 	StaticTextWidget *_pluginsPath;
 	ButtonWidget	 *_pluginsPathClearButton;
diff --git a/gui/themes/common/highres_layout.stx b/gui/themes/common/highres_layout.stx
index 0b54ba9b77c..a690b19e86f 100644
--- a/gui/themes/common/highres_layout.stx
+++ b/gui/themes/common/highres_layout.stx
@@ -533,11 +533,15 @@
 	<dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'>
 		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'grShaderPopUpDesc'
-						type = 'OptionsLabel'
+				<widget name = 'grShaderButton'
+						type = 'Button'
 				/>
-				<widget name = 'grShaderPopUp'
-						type = 'PopUp'
+				<widget name = 'grShader'
+						height = 'Globals.Line.Height'
+				/>
+				<widget name = 'grShaderClearButton'
+						height = 'Globals.Line.Height'
+						width = 'Globals.Line.Height'
 				/>
 			</layout>
 		</layout>
@@ -752,18 +756,6 @@
 						width = 'Globals.Line.Height'
 				/>
 			</layout>
-			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'ShaderButton'
-						type = 'Button'
-				/>
-				<widget name = 'ShaderPath'
-						height = 'Globals.Line.Height'
-				/>
-				<widget name = 'ShaderPathClearButton'
-						height = 'Globals.Line.Height'
-						width = 'Globals.Line.Height'
-				/>
-			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
 				<widget name = 'PluginsButton'
 						type = 'Button'
diff --git a/gui/themes/common/lowres_layout.stx b/gui/themes/common/lowres_layout.stx
index bf204a5fad9..a81432d8e5e 100644
--- a/gui/themes/common/lowres_layout.stx
+++ b/gui/themes/common/lowres_layout.stx
@@ -472,11 +472,15 @@
 	<dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'>
 		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'grShaderPopUpDesc'
-						type = 'OptionsLabel'
+				<widget name = 'grShaderButton'
+						type = 'Button'
 				/>
-				<widget name = 'grShaderPopUp'
-						type = 'PopUp'
+				<widget name = 'grShader'
+						height = 'Globals.Line.Height'
+				/>
+				<widget name = 'grShaderClearButton'
+						height = 'Globals.Line.Height'
+						width = 'Globals.Line.Height'
 				/>
 			</layout>
 		</layout>
@@ -690,18 +694,6 @@
 						width = 'Globals.Line.Height'
 				/>
 			</layout>
-			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'ShaderButton'
-						type = 'Button'
-				/>
-				<widget name = 'ShaderPath'
-						height = 'Globals.Line.Height'
-				/>
-				<widget name = 'ShaderPathClearButton'
-						height = 'Globals.Line.Height'
-						width = 'Globals.Line.Height'
-				/>
-			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' align = 'center'>
 				<widget name = 'PluginsButton'
 						type = 'Button'
diff --git a/gui/themes/default.inc b/gui/themes/default.inc
index 8f4197ba74f..0fd281d355d 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -1782,11 +1782,15 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "<dialog name='GlobalOptions_Shader' overlays='Dialog.GlobalOptions.TabWidget'>"
 "<layout type='vertical' padding='16,16,16,16' spacing='8'>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='10' align='center'>"
-"<widget name='grShaderPopUpDesc' "
-"type='OptionsLabel' "
+"<widget name='grShaderButton' "
+"type='Button' "
 "/>"
-"<widget name='grShaderPopUp' "
-"type='PopUp' "
+"<widget name='grShader' "
+"height='Globals.Line.Height' "
+"/>"
+"<widget name='grShaderClearButton' "
+"height='Globals.Line.Height' "
+"width='Globals.Line.Height' "
 "/>"
 "</layout>"
 "</layout>"
@@ -3696,11 +3700,15 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "<dialog name='GlobalOptions_Shader' overlays='Dialog.GlobalOptions.TabWidget'>"
 "<layout type='vertical' padding='16,16,16,16' spacing='8'>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='10' align='center'>"
-"<widget name='grShaderPopUpDesc' "
-"type='OptionsLabel' "
+"<widget name='grShaderButton' "
+"type='Button' "
 "/>"
-"<widget name='grShaderPopUp' "
-"type='PopUp' "
+"<widget name='grShader' "
+"height='Globals.Line.Height' "
+"/>"
+"<widget name='grShaderClearButton' "
+"height='Globals.Line.Height' "
+"width='Globals.Line.Height' "
 "/>"
 "</layout>"
 "</layout>"
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index 98929bf1d7f..cc52b0df21e 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -385,11 +385,15 @@
 	<dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'>
 		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'grShaderPopUpDesc'
-						type = 'OptionsLabel'
+				<widget name = 'grShaderButton'
+						type = 'Button'
 				/>
-				<widget name = 'grShaderPopUp'
-						type = 'PopUp'
+				<widget name = 'grShader'
+						height = 'Globals.Line.Height'
+				/>
+				<widget name = 'grShaderClearButton'
+						height = 'Globals.Line.Height'
+						width = 'Globals.Line.Height'
 				/>
 			</layout>
 		</layout>
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index 95609beea59..a17329fed47 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -386,11 +386,15 @@
 	<dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'>
 		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'grShaderPopUpDesc'
-						type = 'OptionsLabel'
+				<widget name = 'grShaderButton'
+						type = 'Button'
 				/>
-				<widget name = 'grShaderPopUp'
-						type = 'PopUp'
+				<widget name = 'grShader'
+						height = 'Globals.Line.Height'
+				/>
+				<widget name = 'grShaderClearButton'
+						height = 'Globals.Line.Height'
+						width = 'Globals.Line.Height'
 				/>
 			</layout>
 		</layout>


Commit: a2c65a45211f8f7496700e1fe035accf3d9d2a57
    https://github.com/scummvm/scummvm/commit/a2c65a45211f8f7496700e1fe035accf3d9d2a57
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Remove the stock shader preset

Changed paths:
  R shaders/presets/nearest.glslp
  R shaders/presets/shaders/stock.glsl


diff --git a/shaders/presets/nearest.glslp b/shaders/presets/nearest.glslp
deleted file mode 100644
index 8f4466635c0..00000000000
--- a/shaders/presets/nearest.glslp
+++ /dev/null
@@ -1,4 +0,0 @@
-shaders = 1
-
-shader0 = shaders/stock.glsl
-filter_linear0 = false
diff --git a/shaders/presets/shaders/stock.glsl b/shaders/presets/shaders/stock.glsl
deleted file mode 100644
index a60423ad99a..00000000000
--- a/shaders/presets/shaders/stock.glsl
+++ /dev/null
@@ -1,73 +0,0 @@
-#if defined(VERTEX)
-
-#if __VERSION__ >= 130
-#define COMPAT_VARYING out
-#define COMPAT_ATTRIBUTE in
-#define COMPAT_TEXTURE texture
-#else
-#define COMPAT_VARYING varying 
-#define COMPAT_ATTRIBUTE attribute 
-#define COMPAT_TEXTURE texture2D
-#endif
-
-#ifdef GL_ES
-#define COMPAT_PRECISION mediump
-#else
-#define COMPAT_PRECISION
-#endif
-
-COMPAT_ATTRIBUTE vec4 VertexCoord;
-COMPAT_ATTRIBUTE vec4 COLOR;
-COMPAT_ATTRIBUTE vec4 TexCoord;
-COMPAT_VARYING vec4 COL0;
-COMPAT_VARYING vec4 TEX0;
-
-uniform mat4 MVPMatrix;
-uniform COMPAT_PRECISION int FrameDirection;
-uniform COMPAT_PRECISION int FrameCount;
-uniform COMPAT_PRECISION vec2 OutputSize;
-uniform COMPAT_PRECISION vec2 TextureSize;
-uniform COMPAT_PRECISION vec2 InputSize;
-
-void main()
-{
-    gl_Position = VertexCoord.x * MVPMatrix[0] + VertexCoord.y * MVPMatrix[1] + VertexCoord.z * MVPMatrix[2] + VertexCoord.w * MVPMatrix[3];
-    TEX0.xy = TexCoord.xy;
-}
-
-#elif defined(FRAGMENT)
-
-#if __VERSION__ >= 130
-#define COMPAT_VARYING in
-#define COMPAT_TEXTURE texture
-out vec4 FragColor;
-#else
-#define COMPAT_VARYING varying
-#define FragColor gl_FragColor
-#define COMPAT_TEXTURE texture2D
-#endif
-
-#ifdef GL_ES
-#ifdef GL_FRAGMENT_PRECISION_HIGH
-precision highp float;
-#else
-precision mediump float;
-#endif
-#define COMPAT_PRECISION mediump
-#else
-#define COMPAT_PRECISION
-#endif
-
-uniform COMPAT_PRECISION int FrameDirection;
-uniform COMPAT_PRECISION int FrameCount;
-uniform COMPAT_PRECISION vec2 OutputSize;
-uniform COMPAT_PRECISION vec2 TextureSize;
-uniform COMPAT_PRECISION vec2 InputSize;
-uniform sampler2D Texture;
-COMPAT_VARYING vec4 TEX0;
-
-void main()
-{
-    FragColor = COMPAT_TEXTURE(Texture, TEX0.xy);
-} 
-#endif


Commit: 79fff692313c332e760dec2b2250ef9d9a1e0001
    https://github.com/scummvm/scummvm/commit/79fff692313c332e760dec2b2250ef9d9a1e0001
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
COMMON: Use Common::String for OSystem::setShader

Changed paths:
    backends/graphics/graphics.h
    backends/modular-backend.cpp
    backends/modular-backend.h
    base/main.cpp
    common/system.h
    engines/engine.cpp
    gui/options.cpp


diff --git a/backends/graphics/graphics.h b/backends/graphics/graphics.h
index 583e3a6c96e..761be9bdbe6 100644
--- a/backends/graphics/graphics.h
+++ b/backends/graphics/graphics.h
@@ -48,7 +48,7 @@ public:
 	virtual int getDefaultGraphicsMode() const { return 0; }
 	virtual bool setGraphicsMode(int mode, uint flags = OSystem::kGfxModeNoFlags) { return (mode == 0); }
 	virtual int getGraphicsMode() const { return 0; }
-	virtual bool setShader(const Common::FSNode &fileNode) { return false; }
+	virtual bool setShader(const Common::String &fileName) { return false; }
 	virtual const OSystem::GraphicsMode *getSupportedStretchModes() const {
 		static const OSystem::GraphicsMode noStretchModes[] = {{"NONE", "Normal", 0}, {nullptr, nullptr, 0 }};
 		return noStretchModes;
diff --git a/backends/modular-backend.cpp b/backends/modular-backend.cpp
index 1e4e56da1a1..4f846ab00fb 100644
--- a/backends/modular-backend.cpp
+++ b/backends/modular-backend.cpp
@@ -73,8 +73,8 @@ int ModularGraphicsBackend::getGraphicsMode() const {
 	return _graphicsManager->getGraphicsMode();
 }
 
-bool ModularGraphicsBackend::setShader(const Common::FSNode &fileNode) {
-	return _graphicsManager->setShader(fileNode);
+bool ModularGraphicsBackend::setShader(const Common::String &fileName) {
+	return _graphicsManager->setShader(fileName);
 }
 
 const OSystem::GraphicsMode *ModularGraphicsBackend::getSupportedStretchModes() const {
diff --git a/backends/modular-backend.h b/backends/modular-backend.h
index 4c9a8e1a01b..7313fefa91f 100644
--- a/backends/modular-backend.h
+++ b/backends/modular-backend.h
@@ -67,7 +67,7 @@ public:
 	int getDefaultGraphicsMode() const override;
 	bool setGraphicsMode(int mode, uint flags = kGfxModeNoFlags) override;
 	int getGraphicsMode() const override;
-	bool setShader(const Common::FSNode &node) override final;
+	bool setShader(const Common::String &name) override final;
 	const GraphicsMode *getSupportedStretchModes() const override final;
 	int getDefaultStretchMode() const override final;
 	bool setStretchMode(int mode) override final;
diff --git a/base/main.cpp b/base/main.cpp
index a1eed693bee..5fc1bf9cfaa 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -354,7 +354,7 @@ static void setupGraphics(OSystem &system) {
 		system.setGraphicsMode(ConfMan.get("gfx_mode").c_str());
 		system.setStretchMode(ConfMan.get("stretch_mode").c_str());
 		system.setScaler(ConfMan.get("scaler").c_str(), ConfMan.getInt("scale_factor"));
-		system.setShader(Common::FSNode(ConfMan.get("shader")));
+		system.setShader(ConfMan.get("shader"));
 
 		system.initSize(320, 200);
 
diff --git a/common/system.h b/common/system.h
index 2ab1486999a..1e962b5c9bc 100644
--- a/common/system.h
+++ b/common/system.h
@@ -46,7 +46,6 @@ class OptionsContainerWidget;
 
 namespace Common {
 class EventManager;
-class FSNode;
 class MutexInternal;
 struct Rect;
 class SaveFileManager;
@@ -774,7 +773,7 @@ public:
 	 *
 	 * @return True if the switch was successful, false otherwise.
 	 */
-	virtual bool setShader(const Common::FSNode &fileNode) { return false; }
+	virtual bool setShader(const Common::String &fileName) { return false; }
 
 	/**
 	 * Retrieve a list of all stretch modes supported by this backend.
diff --git a/engines/engine.cpp b/engines/engine.cpp
index a0489be4a76..1a4a37cb706 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -219,7 +219,7 @@ void initCommonGFX() {
 			g_system->setScaler(ConfMan.get("scaler").c_str(), ConfMan.getInt("scale_factor"));
 
 		if (gameDomain->contains("shader"))
-			g_system->setShader(Common::FSNode(ConfMan.get("shader")));
+			g_system->setShader(ConfMan.get("shader"));
 	}
 }
 
diff --git a/gui/options.cpp b/gui/options.cpp
index 7417c3e1f2c..b9420232e2a 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -740,7 +740,7 @@ void OptionsDialog::apply() {
 		g_system->setGraphicsMode(ConfMan.get("gfx_mode", _domain).c_str());
 		g_system->setStretchMode(ConfMan.get("stretch_mode", _domain).c_str());
 		g_system->setScaler(ConfMan.get("scaler", _domain).c_str(), ConfMan.getInt("scale_factor", _domain));
-		g_system->setShader(Common::FSNode(ConfMan.get("shader", _domain)));
+		g_system->setShader(ConfMan.get("shader", _domain));
 
 		if (ConfMan.hasKey("aspect_ratio"))
 			g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, ConfMan.getBool("aspect_ratio", _domain));


Commit: 1b2a73c62aaf9e7af2fa877a24174b5938a66cea
    https://github.com/scummvm/scummvm/commit/1b2a73c62aaf9e7af2fa877a24174b5938a66cea
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Implement selecting shaders from the GUI

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp
    backends/graphics/opengl/opengl-graphics.h


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 29f2f4854a5..dfea9f1e94e 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -113,6 +113,9 @@ bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) const {
 	case OSystem::kFeatureStretchMode:
 #ifdef USE_SCALERS
 	case OSystem::kFeatureScalers:
+#endif
+#if !USE_FORCED_GLES
+	case OSystem::kFeatureShaders:
 #endif
 		return true;
 
@@ -345,6 +348,20 @@ uint OpenGLGraphicsManager::getScaleFactor() const {
 }
 #endif
 
+#if !USE_FORCED_GLES
+bool OpenGLGraphicsManager::setShader(const Common::String &fileName) {
+	assert(_transactionMode != kTransactionNone);
+
+	// Special case for the 'default' shader
+	if (fileName == "default")
+		_currentState.shader = "";
+	else
+		_currentState.shader = fileName;
+
+	return true;
+}
+#endif
+
 void OpenGLGraphicsManager::beginGFXTransaction() {
 	assert(_transactionMode == kTransactionNone);
 
@@ -509,6 +526,14 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
 #endif
 	}
 
+#if !USE_FORCED_GLES
+	// Load selected shader preset
+	if (!_currentState.shader.empty()) {
+		if (!_libretroPipeline->open(Common::FSNode(_currentState.shader)))
+			warning("Failed to load %s", _currentState.shader.c_str());
+	}
+#endif
+
 	// Update our display area and cursor scaling. This makes sure we pick up
 	// aspect ratio correction and game screen changes correctly.
 	recalculateDisplayAreas();
@@ -1165,17 +1190,6 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 #if !USE_FORCED_GLES
 	if (LibRetroPipeline::isSupportedByContext()) {
 		_libretroPipeline = new LibRetroPipeline();
-
-		// Load selected shader preset from config file
-		// TODO: Handle this in endGFXTransaction()
-		if (ConfMan.hasKey("shader_scaler", Common::ConfigManager::kApplicationDomain)) {
-			Common::FSNode shaderPreset(ConfMan.get("shader_scaler", Common::ConfigManager::kApplicationDomain));
-			if (shaderPreset.isReadable()) {
-				if (!_libretroPipeline->open(shaderPreset))
-					warning("Failed to load %s", shaderPreset.getName().c_str());
-			}
-		}
-
 		_libretroPipeline->setColor(1.0f, 1.0f, 1.0f, 1.0f);
 		_libretroPipeline->setFramebuffer(&_backBuffer);
 	}
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
index 539d798776a..6311fe4e0d0 100644
--- a/backends/graphics/opengl/opengl-graphics.h
+++ b/backends/graphics/opengl/opengl-graphics.h
@@ -85,6 +85,10 @@ public:
 	uint getScaleFactor() const override;
 #endif
 
+#if !USE_FORCED_GLES
+	bool setShader(const Common::String &fileNode) override;
+#endif
+
 	void beginGFXTransaction() override;
 	OSystem::TransactionError endGFXTransaction() override;
 
@@ -175,7 +179,7 @@ protected:
 		    gameFormat(),
 #endif
 		    aspectRatioCorrection(false), graphicsMode(GFX_OPENGL), filtering(true),
-		    scalerIndex(0), scaleFactor(1) {
+		    scalerIndex(0), scaleFactor(1), shader() {
 		}
 
 		bool valid;
@@ -191,6 +195,8 @@ protected:
 		uint scalerIndex;
 		int scaleFactor;
 
+		Common::String shader;
+
 		bool operator==(const VideoState &right) {
 			return gameWidth == right.gameWidth && gameHeight == right.gameHeight
 #ifdef USE_RGB_COLOR
@@ -198,7 +204,8 @@ protected:
 #endif
 			    && aspectRatioCorrection == right.aspectRatioCorrection
 			    && graphicsMode == right.graphicsMode
-				&& filtering == right.filtering;
+				&& filtering == right.filtering
+			    && shader == right.shader;
 		}
 
 		bool operator!=(const VideoState &right) {


Commit: f6e071e99a4bb0799835e686c2f9c86a74f75f55
    https://github.com/scummvm/scummvm/commit/f6e071e99a4bb0799835e686c2f9c86a74f75f55
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Handle LibRetro shaders containing version directives

Changed paths:
    backends/graphics/opengl/pipelines/libretro.cpp


diff --git a/backends/graphics/opengl/pipelines/libretro.cpp b/backends/graphics/opengl/pipelines/libretro.cpp
index 2125717d7cf..b0aa9eafcda 100644
--- a/backends/graphics/opengl/pipelines/libretro.cpp
+++ b/backends/graphics/opengl/pipelines/libretro.cpp
@@ -243,10 +243,22 @@ bool LibRetroPipeline::loadPasses() {
 			return false;
 		}
 
+		char *shaderFileStart = shaderFileContents.begin();
+		unsigned long shaderFileVersion = 0;
+
+		// If the shader contains a version directive, it needs to be parsed and stripped out so that the VERTEX
+		// and FRAGMENT defines can be prepended to it.
+		const char *existing_version = strstr(shaderFileStart, "#version");
+		if (existing_version) {
+			shaderFileVersion = strtoul(existing_version + 8, &shaderFileStart, 10);
+		}
+
+		// TODO: Handle alias defines
+
 		Shader *shader = Shader::fromStrings(fileNode.getName(),
-		                                     ("#define VERTEX\n" + Common::String(shaderFileContents.begin())).c_str(),
-		                                     ("#define FRAGMENT\n" + Common::String(shaderFileContents.begin())).c_str(),
-		                                     g_libretroShaderAttributes);
+		                                     ("#define VERTEX\n" + Common::String(shaderFileStart)).c_str(),
+		                                     ("#define FRAGMENT\n" + Common::String(shaderFileStart)).c_str(),
+		                                     g_libretroShaderAttributes, shaderFileVersion);
 
 		// Set uniforms with fixed value throughout lifetime.
 		// We do not support rewinding, thus fix 'forward'.


Commit: 475d2e119aa84412b2dd968126054b9d74528a75
    https://github.com/scummvm/scummvm/commit/475d2e119aa84412b2dd968126054b9d74528a75
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
COMMON: Added OSystem::kTransactionShaderChangeFailed enum value

Changed paths:
    common/system.h


diff --git a/common/system.h b/common/system.h
index 1e962b5c9bc..ee7bd43e350 100644
--- a/common/system.h
+++ b/common/system.h
@@ -991,7 +991,8 @@ public:
 		kTransactionSizeChangeFailed = (1 << 3),        /**< Failed switching the screen dimensions (initSize) */
 		kTransactionFormatNotSupported = (1 << 4),      /**< Failed setting the color format */
 		kTransactionFilteringFailed = (1 << 5),         /**< Failed setting the filtering mode */
-		kTransactionStretchModeSwitchFailed = (1 << 6)  /**< Failed setting the stretch mode */
+		kTransactionStretchModeSwitchFailed = (1 << 6), /**< Failed setting the stretch mode */
+		kTransactionShaderChangeFailed = (1 << 7),      /**< Failed setting the shader */
 	};
 
 	/**


Commit: 8d6196371656cd436be794d90f43b3f0cb8786e9
    https://github.com/scummvm/scummvm/commit/8d6196371656cd436be794d90f43b3f0cb8786e9
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Return error when shader did not work

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index dfea9f1e94e..7e130eb66b2 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -529,8 +529,10 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
 #if !USE_FORCED_GLES
 	// Load selected shader preset
 	if (!_currentState.shader.empty()) {
-		if (!_libretroPipeline->open(Common::FSNode(_currentState.shader)))
-			warning("Failed to load %s", _currentState.shader.c_str());
+		if (!_libretroPipeline->open(Common::FSNode(_currentState.shader))) {
+			warning("Failed to load shader %s", _currentState.shader.c_str());
+			transactionError |= OSystem::kTransactionShaderChangeFailed;
+		}
 	}
 #endif
 


Commit: 1ac8fde03f9b9e9b0fd604b7eeeea88c786080bc
    https://github.com/scummvm/scummvm/commit/1ac8fde03f9b9e9b0fd604b7eeeea88c786080bc
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
JANITORIAL: Whitespace fixes

Changed paths:
    backends/graphics/opengl/pipelines/libretro.cpp
    backends/graphics/opengl/pipelines/libretro.h
    backends/graphics/opengl/pipelines/libretro/types.h


diff --git a/backends/graphics/opengl/pipelines/libretro.cpp b/backends/graphics/opengl/pipelines/libretro.cpp
index b0aa9eafcda..15a35d3a047 100644
--- a/backends/graphics/opengl/pipelines/libretro.cpp
+++ b/backends/graphics/opengl/pipelines/libretro.cpp
@@ -59,11 +59,11 @@ static Graphics::Surface *loadViaImageDecoder(const Common::FSNode &fileNode) {
 
 	return decoder.getSurface()->convertTo(
 #ifdef SCUMM_LITTLE_ENDIAN
-	                                       Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24),
+										   Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24),
 #else
-	                                       Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0),
+										   Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0),
 #endif
-	                                       decoder.getPalette());
+										   decoder.getPalette());
 }
 
 struct ImageLoader {
@@ -83,15 +83,15 @@ const char *const g_libretroShaderAttributes[] = {
 };
 
 LibRetroPipeline::LibRetroPipeline()
-    : ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)),
-      _shaderPreset(nullptr), _applyProjectionChanges(false),
-      _inputWidth(0), _inputHeight(0), _outputWidth(0), _outputHeight(0) {
+	: ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)),
+	  _shaderPreset(nullptr), _applyProjectionChanges(false),
+	  _inputWidth(0), _inputHeight(0), _outputWidth(0), _outputHeight(0) {
 }
 
 LibRetroPipeline::LibRetroPipeline(const Common::FSNode &shaderPreset)
-    : ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)),
-      _shaderPreset(nullptr), _applyProjectionChanges(false),
-      _inputWidth(0), _inputHeight(0), _outputWidth(0), _outputHeight(0) {
+	: ShaderPipeline(ShaderMan.query(ShaderManager::kDefault)),
+	  _shaderPreset(nullptr), _applyProjectionChanges(false),
+	  _inputWidth(0), _inputHeight(0), _outputWidth(0), _outputHeight(0) {
 	open(shaderPreset);
 }
 
@@ -111,8 +111,8 @@ void LibRetroPipeline::drawTexture(const GLTexture &texture, const GLfloat *coor
 	// In case texture dimensions or viewport dimensions changed, we need to
 	// update the pipeline's state.
 	if (   texture.getLogicalWidth() != _inputWidth
-	    || texture.getLogicalHeight() != _inputHeight
-	    || _outputSizeChanged) {
+		|| texture.getLogicalHeight() != _inputHeight
+		|| _outputSizeChanged) {
 		_outputSizeChanged = false;
 		_inputWidth  = texture.getLogicalWidth();
 		_inputHeight = texture.getLogicalHeight();
@@ -204,8 +204,8 @@ static Common::FSNode getChildRecursive(const Common::FSNode &basePath, const Co
 
 bool LibRetroPipeline::loadTextures() {
 	for (LibRetro::ShaderPreset::TextureArray::const_iterator
-	     i = _shaderPreset->textures.begin(), end = _shaderPreset->textures.end();
-	     i != end; ++i) {
+		 i = _shaderPreset->textures.begin(), end = _shaderPreset->textures.end();
+		 i != end; ++i) {
 		Texture texture = loadTexture(getChildRecursive( _shaderPreset->basePath, i->fileName));
 		texture.id = i->id;
 
@@ -221,8 +221,8 @@ bool LibRetroPipeline::loadTextures() {
 
 bool LibRetroPipeline::loadPasses() {
 	for (LibRetro::ShaderPreset::PassArray::const_iterator
-	     i = _shaderPreset->passes.begin(), end = _shaderPreset->passes.end();
-	     i != end; ++i) {
+		 i = _shaderPreset->passes.begin(), end = _shaderPreset->passes.end();
+		 i != end; ++i) {
 		Common::FSNode fileNode(getChildRecursive(_shaderPreset->basePath, i->fileName));
 
 		Common::SeekableReadStream *stream = fileNode.createReadStream();
@@ -256,9 +256,9 @@ bool LibRetroPipeline::loadPasses() {
 		// TODO: Handle alias defines
 
 		Shader *shader = Shader::fromStrings(fileNode.getName(),
-		                                     ("#define VERTEX\n" + Common::String(shaderFileStart)).c_str(),
-		                                     ("#define FRAGMENT\n" + Common::String(shaderFileStart)).c_str(),
-		                                     g_libretroShaderAttributes, shaderFileVersion);
+											 ("#define VERTEX\n" + Common::String(shaderFileStart)).c_str(),
+											 ("#define FRAGMENT\n" + Common::String(shaderFileStart)).c_str(),
+											 g_libretroShaderAttributes, shaderFileVersion);
 
 		// Set uniforms with fixed value throughout lifetime.
 		// We do not support rewinding, thus fix 'forward'.
@@ -470,7 +470,7 @@ void LibRetroPipeline::renderPassSetupCoordinates(const Pass &pass) {
 	pass.shader->enableVertexAttribute("VertexCoord", 2, GL_FLOAT, GL_FALSE, 0, pass.vertexCoord);
 
 	for (Pass::TexCoordAttributeArray::const_iterator i = pass.texCoords.begin(), end = pass.texCoords.end();
-	     i != end; ++i) {
+		 i != end; ++i) {
 		const GLfloat *texCoords = nullptr;
 
 		switch (i->type) {
@@ -507,7 +507,7 @@ void LibRetroPipeline::renderPassSetupTextures(const Pass &pass) {
 	}
 
 	for (Pass::TextureSamplerArray::const_iterator i = pass.texSamplers.begin(), end = pass.texSamplers.end();
-	     i != end; ++i) {
+		 i != end; ++i) {
 		const GLTexture *texture = nullptr;
 
 		switch (i->type) {
diff --git a/backends/graphics/opengl/pipelines/libretro.h b/backends/graphics/opengl/pipelines/libretro.h
index 36792bfd04c..8b0ecd602bf 100644
--- a/backends/graphics/opengl/pipelines/libretro.h
+++ b/backends/graphics/opengl/pipelines/libretro.h
@@ -66,8 +66,8 @@ public:
 
 	static bool isSupportedByContext() {
 		return OpenGLContext.shadersSupported
-		    && OpenGLContext.multitextureSupported
-		    && OpenGLContext.framebufferObjectSupported;
+			&& OpenGLContext.multitextureSupported
+			&& OpenGLContext.framebufferObjectSupported;
 	}
 private:
 	virtual void activateInternal();
@@ -107,11 +107,11 @@ private:
 
 	struct Pass {
 		Pass()
-		    : shaderPass(nullptr), shader(nullptr), target(nullptr),
-		      texCoords(), texSamplers(), inputTexture(nullptr), vertexCoord() {}
+			: shaderPass(nullptr), shader(nullptr), target(nullptr),
+			  texCoords(), texSamplers(), inputTexture(nullptr), vertexCoord() {}
 		Pass(const LibRetro::ShaderPass *sP, Shader *s, TextureTarget *t)
-		    : shaderPass(sP), shader(s), target(t), texCoords(),
-		      texSamplers(), inputTexture(nullptr), vertexCoord() {}
+			: shaderPass(sP), shader(s), target(t), texCoords(),
+			  texSamplers(), inputTexture(nullptr), vertexCoord() {}
 
 		const LibRetro::ShaderPass *shaderPass;
 		Shader *shader;
diff --git a/backends/graphics/opengl/pipelines/libretro/types.h b/backends/graphics/opengl/pipelines/libretro/types.h
index 22e170368c4..69c94a94ba2 100644
--- a/backends/graphics/opengl/pipelines/libretro/types.h
+++ b/backends/graphics/opengl/pipelines/libretro/types.h
@@ -42,7 +42,7 @@ enum FilteringMode {
 struct ShaderTexture {
 	ShaderTexture() : id(), fileName(), filteringMode(kFilteringModeUnspecified) {}
 	ShaderTexture(const Common::String &i, const Common::String &fN, FilteringMode fM)
-	    : id(i), fileName(fN), filteringMode(fM) {}
+		: id(i), fileName(fN), filteringMode(fM) {}
 
 	Common::String id;
 	Common::String fileName;
@@ -57,9 +57,9 @@ enum ScaleType {
 };
 
 inline void applyScale(const ScaleType type,
-                       const float source, const float viewport,
-                       const float scaleFloat, const uint scaleUint,
-                       float *output) {
+					   const float source, const float viewport,
+					   const float scaleFloat, const uint scaleUint,
+					   float *output) {
 	switch (type) {
 	case kScaleTypeSource:
 		*output = source * scaleFloat;
@@ -100,8 +100,8 @@ struct ShaderPass {
 	uint scaleYUint;
 
 	void applyScale(const float sourceW, const float sourceH,
-	                const float viewportW, const float viewportH,
-	                float *outputW, float *outputH) const {
+					const float viewportW, const float viewportH,
+					float *outputW, float *outputH) const {
 		OpenGL::LibRetro::applyScale(scaleTypeX, sourceW, viewportW, scaleXFloat, scaleXUint, outputW);
 		OpenGL::LibRetro::applyScale(scaleTypeY, sourceH, viewportH, scaleYFloat, scaleYUint, outputH);
 	}


Commit: 51295e3a6ad5998bed5069add3de5802c1525b46
    https://github.com/scummvm/scummvm/commit/51295e3a6ad5998bed5069add3de5802c1525b46
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
JANITORIAL: Whitespace fixes

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index b9420232e2a..2a05fb146e5 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -381,8 +381,8 @@ void OptionsDialog::build() {
 		// Fullscreen setting
 		if (g_system->hasFeature(OSystem::kFeatureFullscreenMode)) {
 			_fullscreenCheckbox->setState(ConfMan.getBool("fullscreen", _domain));
-			if (ConfMan.isKeyTemporary("fullscreen")) 
-				_fullscreenCheckbox->setOverride(true); 
+			if (ConfMan.isKeyTemporary("fullscreen"))
+				_fullscreenCheckbox->setOverride(true);
 		} else {
 			_fullscreenCheckbox->setState(true);
 			_fullscreenCheckbox->setEnabled(false);
@@ -392,7 +392,7 @@ void OptionsDialog::build() {
 		if (g_system->hasFeature(OSystem::kFeatureFilteringMode)) {
 			_filteringCheckbox->setState(ConfMan.getBool("filtering", _domain));
 			if (ConfMan.isKeyTemporary("filtering"))
-				_filteringCheckbox->setOverride(true); 
+				_filteringCheckbox->setOverride(true);
 		} else {
 			_filteringCheckbox->setState(false);
 			_filteringCheckbox->setEnabled(false);
@@ -457,7 +457,7 @@ void OptionsDialog::build() {
 		// Multi midi setting
 		_multiMidiCheckbox->setState(ConfMan.getBool("multi_midi", _domain));
 		if (ConfMan.isKeyTemporary("multi_midi"))
-			_multiMidiCheckbox->setOverride(true); 
+			_multiMidiCheckbox->setOverride(true);
 
 		Common::String soundFont(ConfMan.get("soundfont", _domain));
 		if (ConfMan.isKeyTemporary("soundfont")) {
@@ -475,7 +475,7 @@ void OptionsDialog::build() {
 		_midiGainSlider->setValue(ConfMan.getInt("midi_gain", _domain));
 		_midiGainLabel->setLabel(Common::String::format("%.2f", (double)_midiGainSlider->getValue() / 100.0));
 		if (ConfMan.isKeyTemporary("midi_gain"))
-			_midiGainDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride); 
+			_midiGainDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
 	}
 
 	// MT-32 options
@@ -486,12 +486,12 @@ void OptionsDialog::build() {
 		// Native mt32 setting
 		_mt32Checkbox->setState(ConfMan.getBool("native_mt32", _domain));
 		if (ConfMan.isKeyTemporary("native_mt32"))
-			_mt32Checkbox->setOverride(true); 
+			_mt32Checkbox->setOverride(true);
 
 		// GS extensions setting
 		_enableGSCheckbox->setState(ConfMan.getBool("enable_gs", _domain));
 		if (ConfMan.isKeyTemporary("enable_gs"))
-			_enableGSCheckbox->setOverride(true); 
+			_enableGSCheckbox->setOverride(true);
 	}
 
 	// Volume options
@@ -575,12 +575,12 @@ void OptionsDialog::apply() {
 			if (ConfMan.getBool("filtering", _domain) != _filteringCheckbox->getState()) {
 				graphicsModeChanged = true;
 				ConfMan.setBool("filtering", _filteringCheckbox->getState(), _domain);
-				_filteringCheckbox->setOverride(false); 
+				_filteringCheckbox->setOverride(false);
 			}
 			if (ConfMan.getBool("fullscreen", _domain) != _fullscreenCheckbox->getState()) {
 				graphicsModeChanged = true;
 				ConfMan.setBool("fullscreen", _fullscreenCheckbox->getState(), _domain);
-				_fullscreenCheckbox->setOverride(false); 
+				_fullscreenCheckbox->setOverride(false);
 			}
 			if (ConfMan.getBool("aspect_ratio", _domain) != _aspectCheckbox->getState())
 				graphicsModeChanged = true;
@@ -598,7 +598,7 @@ void OptionsDialog::apply() {
 				while (gm->name) {
 					if (gm->id == (int)_gfxPopUp->getSelectedTag()) {
 						if (ConfMan.get("gfx_mode", _domain) != gm->name) {
-							_gfxPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 							
+							_gfxPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 							graphicsModeChanged = true;
 							ConfMan.set("gfx_mode", gm->name, _domain);
 						}
@@ -609,17 +609,17 @@ void OptionsDialog::apply() {
 				}
 			}
 			if (!isSet) {
-				_gfxPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 							
+				_gfxPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 				ConfMan.removeKey("gfx_mode", _domain);
 				if (g_system->getGraphicsMode() != g_system->getDefaultGraphicsMode())
 					graphicsModeChanged = true;
 			}
 
 			if ((int32)_renderModePopUp->getSelectedTag() >= 0) {
-				Common::String renderModeCode = Common::getRenderModeCode((Common::RenderMode)_renderModePopUp->getSelectedTag()); 
+				Common::String renderModeCode = Common::getRenderModeCode((Common::RenderMode)_renderModePopUp->getSelectedTag());
 				if (_renderModePopUp->getSelectedTag() == 0 || ConfMan.get("render_mode", _domain) != renderModeCode) {
 					ConfMan.set("render_mode", renderModeCode, _domain);
-					_renderModePopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 				
+					_renderModePopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 				}
 			}
 
@@ -632,7 +632,7 @@ void OptionsDialog::apply() {
 						if (ConfMan.get("stretch_mode", _domain) != sm->name) {
 							graphicsModeChanged = true;
 							ConfMan.set("stretch_mode", sm->name, _domain);
-							_stretchPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+							_stretchPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 						}
 						isSet = true;
 						break;
@@ -641,7 +641,7 @@ void OptionsDialog::apply() {
 				}
 			}
 			if (!isSet) {
-				_stretchPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+				_stretchPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 				ConfMan.removeKey("stretch_mode", _domain);
 				if (g_system->getStretchMode() != g_system->getDefaultStretchMode())
 					graphicsModeChanged = true;
@@ -654,21 +654,21 @@ void OptionsDialog::apply() {
 				if (ConfMan.get("scaler", _domain) != name) {
 					graphicsModeChanged = true;
 					ConfMan.set("scaler", name, _domain);
-					_scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);  
+					_scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 				}
 
 				int factor = _scaleFactorPopUp->getSelectedTag();
 				if (ConfMan.getInt("scale_factor", _domain) != factor) {
 					ConfMan.setInt("scale_factor", factor, _domain);
 					graphicsModeChanged = true;
-					_scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+					_scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 				}
 				isSet = true;
 			}
 			if (!isSet) {
 				ConfMan.removeKey("scaler", _domain);
 				ConfMan.removeKey("scale_factor", _domain);
-				_scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);  
+				_scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 
 				uint defaultScaler = g_system->getDefaultScaler();
 				uint defaultScaleFactor = g_system->getDefaultScaleFactor();
@@ -879,14 +879,14 @@ void OptionsDialog::apply() {
 			const OPL::Config::EmulatorDescription *ed = OPL::Config::findDriver(_oplPopUp->getSelectedTag());
 
 			if ((ed && ConfMan.get("opl_driver", _domain) != ed->name) || !ed) {
-				_oplPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
-				if (ed) 
+				_oplPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
+				if (ed)
 					ConfMan.set("opl_driver", ed->name, _domain);
 				else
 					ConfMan.removeKey("opl_driver", _domain);
 			}
 		} else {
-			_oplPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+			_oplPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 			ConfMan.removeKey("opl_driver", _domain);
 		}
 	}
@@ -898,29 +898,29 @@ void OptionsDialog::apply() {
 
 			if (_multiMidiCheckbox->getState() != ConfMan.getBool("multi_midi", _domain)) {
 				ConfMan.setBool("multi_midi", _multiMidiCheckbox->getState(), _domain);
-				_multiMidiCheckbox->setOverride(false); 
+				_multiMidiCheckbox->setOverride(false);
 			}
 			if (_midiGainSlider->getValue() != ConfMan.getInt("midi_gain", _domain)) {
 				ConfMan.setInt("midi_gain", _midiGainSlider->getValue(), _domain);
-				_midiGainDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+				_midiGainDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 			}
 
 			Common::U32String soundFont(_soundFont->getLabel());
 			if (soundFont != ConfMan.get("soundfont", _domain)) {
-				_soundFont->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+				_soundFont->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 				if (soundFont.empty() || (soundFont == _c("None", "soundfont")))
 					ConfMan.removeKey("soundfont", _domain);
-				else 
-					ConfMan.set("soundfont", soundFont.encode(), _domain); 
-			} 
+				else
+					ConfMan.set("soundfont", soundFont.encode(), _domain);
+			}
 		} else {
 			ConfMan.removeKey("gm_device", _domain);
 			ConfMan.removeKey("multi_midi", _domain);
-			_multiMidiCheckbox->setOverride(false); 
+			_multiMidiCheckbox->setOverride(false);
 			ConfMan.removeKey("midi_gain", _domain);
 			_midiGainDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 			ConfMan.removeKey("soundfont", _domain);
-			_soundFont->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+			_soundFont->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 		}
 	}
 
@@ -931,18 +931,18 @@ void OptionsDialog::apply() {
 			ConfMan.setBool("native_mt32", _mt32Checkbox->getState(), _domain);
 			if (ConfMan.getBool("native_mt32", _domain) != _mt32Checkbox->getState()) {
 				ConfMan.setBool("native_mt32", _mt32Checkbox->getState(), _domain);
-				_mt32Checkbox->setOverride(false); 
+				_mt32Checkbox->setOverride(false);
 			}
 			if (ConfMan.getBool("enable_gs", _domain) != _enableGSCheckbox->getState()) {
 				ConfMan.setBool("enable_gs", _enableGSCheckbox->getState(), _domain);
-				_enableGSCheckbox->setOverride(false); 
+				_enableGSCheckbox->setOverride(false);
 			}
 		} else {
 			ConfMan.removeKey("mt32_device", _domain);
 			ConfMan.removeKey("native_mt32", _domain);
-			_mt32Checkbox->setOverride(false); 
+			_mt32Checkbox->setOverride(false);
 			ConfMan.removeKey("enable_gs", _domain);
-			_enableGSCheckbox->setOverride(false); 
+			_enableGSCheckbox->setOverride(false);
 		}
 	}
 
@@ -967,12 +967,12 @@ void OptionsDialog::apply() {
 
 				if (subtitles != ConfMan.getBool("subtitles", _domain)) {
 					ConfMan.setBool("subtitles", subtitles, _domain);
-					_subToggleDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+					_subToggleDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 				}
 				ConfMan.setBool("speech_mute", speech_mute, _domain);
 			} else if (!_domain.empty()) {
 				ConfMan.removeKey("subtitles", _domain);
-				_subToggleDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+				_subToggleDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 				ConfMan.removeKey("speech_mute", _domain);
 			}
 
@@ -982,12 +982,12 @@ void OptionsDialog::apply() {
 			int talkspeed = (_subSpeedSlider->getValue() * 255 + sliderMaxValue / 2) / sliderMaxValue;
 			if (talkspeed != ConfMan.getInt("talkspeed", _domain)) {
 				ConfMan.setInt("talkspeed", talkspeed, _domain);
-				_subSpeedDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+				_subSpeedDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 			}
 		} else {
 			ConfMan.removeKey("subtitles", _domain);
 			ConfMan.removeKey("talkspeed", _domain);
-			_subSpeedDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+			_subSpeedDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 			ConfMan.removeKey("speech_mute", _domain);
 		}
 	}
@@ -1026,7 +1026,7 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
 				updateSpeechVolume(newValue);
 			}
 		}
-		_musicVolumeDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+		_musicVolumeDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 		break;
 	}
 	case kSfxVolumeChanged: {
@@ -1041,7 +1041,7 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
 		if (_guioptions.contains(GUIO_LINKSPEECHTOSFX)) {
 			updateSpeechVolume(newValue);
 		}
-		_sfxVolumeDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+		_sfxVolumeDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 		break;
 	}
 	case kSpeechVolumeChanged: {
@@ -1056,7 +1056,7 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
 				updateMusicVolume(newValue);
 			}
 		}
-		_speechVolumeDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+		_speechVolumeDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 		break;
 	}
 	case kMuteAllChanged:
@@ -1455,7 +1455,7 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
 	// The GFX mode popup
 	_gfxPopUpDesc = new StaticTextWidget(boss, prefix + "grModePopupDesc", _("Graphics mode:"));
 	if (ConfMan.isKeyTemporary("gfx_mode"))
-		_gfxPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride); 
+		_gfxPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
 	_gfxPopUp = new PopUpWidget(boss, prefix + "grModePopup");
 
 	_gfxPopUp->appendEntry(_("<default>"));
@@ -1471,7 +1471,7 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
 
 	_renderModePopUpDesc = new StaticTextWidget(boss, prefix + "grRenderPopupDesc", _("Render mode:"), _("Special dithering modes supported by some games"));
 	if (ConfMan.isKeyTemporary("render_mode"))
-		_renderModePopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride); 
+		_renderModePopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
 	_renderModePopUp = new PopUpWidget(boss, prefix + "grRenderPopup", _("Special dithering modes supported by some games"));
 	_renderModePopUp->appendEntry(_("<default>"), Common::kRenderDefault);
 	_renderModePopUp->appendEntry(Common::U32String());
@@ -1486,7 +1486,7 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
 	const OSystem::GraphicsMode *sm = g_system->getSupportedStretchModes();
 	_stretchPopUpDesc = new StaticTextWidget(boss, prefix + "grStretchModePopupDesc", _("Stretch mode:"));
 	if (ConfMan.isKeyTemporary("stretch_mode"))
-		_stretchPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride); 
+		_stretchPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
 	_stretchPopUp = new PopUpWidget(boss, prefix + "grStretchModePopup");
 
 	_stretchPopUp->appendEntry(_("<default>"));
@@ -1591,7 +1591,7 @@ void OptionsDialog::addAudioControls(GuiObject *boss, const Common::String &pref
 	// The OPL emulator popup & a label
 	_oplPopUpDesc = new StaticTextWidget(boss, prefix + "auOPLPopupDesc", _("AdLib emulator:"), _("AdLib is used for music in many games"));
 	if (ConfMan.isKeyTemporary("opl_driver"))
-		_oplPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride); 
+		_oplPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
 	_oplPopUp = new PopUpWidget(boss, prefix + "auOPLPopup", _("AdLib is used for music in many games"));
 
 	// Populate it
@@ -1726,11 +1726,11 @@ void OptionsDialog::addSubtitleControls(GuiObject *boss, const Common::String &p
 
 		_subSpeedDesc = new StaticTextWidget(boss, prefix + "subSubtitleSpeedDesc", _c("Subtitle speed:", "lowres"));
 	}
-	
+
 	if (ConfMan.isKeyTemporary("talkspeed"))
-		_subSpeedDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride); 
+		_subSpeedDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
 	if (ConfMan.isKeyTemporary("subtitles"))
-		_subToggleDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride); 
+		_subToggleDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
 
 	// Subtitle speed
 	_subSpeedSlider = new SliderWidget(boss, prefix + "subSubtitleSpeedSlider", Common::U32String(), kSubtitleSpeedChanged);
@@ -1749,8 +1749,8 @@ void OptionsDialog::addVolumeControls(GuiObject *boss, const Common::String &pre
 		_musicVolumeDesc = new StaticTextWidget(boss, prefix + "vcMusicText", _("Music volume:"));
 	else
 		_musicVolumeDesc = new StaticTextWidget(boss, prefix + "vcMusicText", _c("Music volume:", "lowres"));
-	if (ConfMan.isKeyTemporary("music_volume")) 
-		_musicVolumeDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride); 
+	if (ConfMan.isKeyTemporary("music_volume"))
+		_musicVolumeDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
 	_musicVolumeSlider = new SliderWidget(boss, prefix + "vcMusicSlider", Common::U32String(), kMusicVolumeChanged);
 	_musicVolumeLabel = new StaticTextWidget(boss, prefix + "vcMusicLabel", Common::U32String("100%"), Common::U32String(), ThemeEngine::kFontStyleBold, Common::UNK_LANG, false);
 	_musicVolumeSlider->setMinValue(0);
@@ -1776,7 +1776,7 @@ void OptionsDialog::addVolumeControls(GuiObject *boss, const Common::String &pre
 	else
 		_speechVolumeDesc = new StaticTextWidget(boss, prefix + "vcSpeechText" , _c("Speech volume:", "lowres"));
 	if (ConfMan.isKeyTemporary("speech_volume"))
-		_speechVolumeDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride); 
+		_speechVolumeDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
 	_speechVolumeSlider = new SliderWidget(boss, prefix + "vcSpeechSlider", Common::U32String(), kSpeechVolumeChanged);
 	_speechVolumeLabel = new StaticTextWidget(boss, prefix + "vcSpeechLabel", Common::U32String("100%"), Common::U32String(), ThemeEngine::kFontStyleBold, Common::UNK_LANG, false);
 	_speechVolumeSlider->setMinValue(0);
@@ -1902,7 +1902,7 @@ void OptionsDialog::setupGraphicsTab() {
 	if (g_system->hasFeature(OSystem::kFeatureScalers)) {
 		_scalerPopUpDesc->setVisible(true);
 		if (ConfMan.isKeyTemporary("scaler") || ConfMan.isKeyTemporary("scale_factor"))
-			_scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride); 
+			_scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
 		_scalerPopUp->setVisible(true);
 		_scaleFactorPopUp->setVisible(true);
 	} else {
@@ -2204,9 +2204,9 @@ void GlobalOptionsDialog::build() {
 	OptionsDialog::build();
 
 #if !defined(__DC__)
-	const auto setPath = 
+	const auto setPath =
 	[&](GUI::StaticTextWidget *const widget, const Common::String &pathType, const Common::U32String &defaultLabel) {
-		Common::String path(ConfMan.get(pathType)); 
+		Common::String path(ConfMan.get(pathType));
 		if (ConfMan.isKeyTemporary(pathType)) {
 			widget->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
 		}
@@ -2217,7 +2217,7 @@ void GlobalOptionsDialog::build() {
 		}
 	};
 
-	setPath(_savePath, "savepath", _("Default")); 
+	setPath(_savePath, "savepath", _("Default"));
 	setPath(_themePath, "themepath", _c("None", "path"));
 	setPath(_iconPath, "iconspath", _("Default"));
 	setPath(_extraPath, "extrapath", _c("None", "path"));
@@ -2335,8 +2335,8 @@ void GlobalOptionsDialog::addPathsControls(GuiObject *boss, const Common::String
 		confPath = g_system->getDefaultConfigFileName();
 	StaticTextWidget* configPathWidget = new StaticTextWidget(boss, prefix + "ConfigPath", _("ScummVM config path: ") + confPath, confPath);
 	if (ConfMan.isKeyTemporary("config"))
-		configPathWidget->setFontColor(ThemeEngine::FontColor::kFontColorOverride); 
- 
+		configPathWidget->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
+
 
 	Common::U32String browserPath = _("<default>");
 	if (ConfMan.hasKey("browser_lastpath"))
@@ -2351,7 +2351,7 @@ void GlobalOptionsDialog::addMiscControls(GuiObject *boss, const Common::String
 	new ButtonWidget(boss, prefix + "ThemeButton", _("Theme:"), Common::U32String(), kChooseThemeCmd);
 	_curTheme = new StaticTextWidget(boss, prefix + "CurTheme", g_gui.theme()->getThemeName());
 	if (ConfMan.isKeyTemporary("gui_theme"))
-		_curTheme->setFontColor(ThemeEngine::FontColor::kFontColorOverride); 
+		_curTheme->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
 
 	_guiBasePopUpDesc = new StaticTextWidget(boss, prefix + "GUIBasePopupDesc", _("GUI scale:"));
 	_guiBasePopUp = new PopUpWidget(boss, prefix + "GUIBasePopup");
@@ -2698,22 +2698,22 @@ void GlobalOptionsDialog::apply() {
 
 	bool isRebuildNeeded = false;
 
-	const auto changePath = 
+	const auto changePath =
 	[&](GUI::StaticTextWidget *const widget, const Common::String &pathType, const Common::U32String &defaultLabel) {
 		Common::U32String label(widget->getLabel());
 		if (label != ConfMan.get(pathType)) {
-			widget->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+			widget->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 			if (label.empty() || (label == defaultLabel))
-				ConfMan.removeKey(pathType, _domain); 
-			else 
-				ConfMan.set(pathType, label.encode(), _domain); 
-		} 
-	}; 
-
-	changePath(_savePath, "savepath", _("Default")); 
-	changePath(_themePath, "themepath", _c("None", "path")); 
+				ConfMan.removeKey(pathType, _domain);
+			else
+				ConfMan.set(pathType, label.encode(), _domain);
+		}
+	};
+
+	changePath(_savePath, "savepath", _("Default"));
+	changePath(_themePath, "themepath", _c("None", "path"));
 	changePath(_iconPath, "iconspath", _("Default"));
-	changePath(_extraPath, "extrapath", _c("None", "path")); 
+	changePath(_extraPath, "extrapath", _c("None", "path"));
 
 #ifdef DYNAMIC_MODULES
 	Common::U32String pluginsPath(_pluginsPath->getLabel());
@@ -3069,7 +3069,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 			// User made his choice...
 			_newTheme = browser.getSelected();
 			_curTheme->setLabel(browser.getSelectedName());
-			_curTheme->setFontColor(ThemeEngine::FontColor::kFontColorNormal); 
+			_curTheme->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 		}
 		break;
 	}


Commit: ff259665c523b9442f177ae95fb78db5d651f105
    https://github.com/scummvm/scummvm/commit/ff259665c523b9442f177ae95fb78db5d651f105
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Restore previous shader setting on load failure

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index 2a05fb146e5..568bb89a5ad 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -707,11 +707,16 @@ void OptionsDialog::apply() {
 		}
 	}
 
+	Common::U32String previousShader;
+
 	// Shader options
 	if (_shader) {
 		if (_enableShaderSettings) {
 			bool isSet;
 
+			if (ConfMan.hasKey("shader", _domain) && !ConfMan.get("shader", _domain).empty())
+				previousShader = ConfMan.get("shader", _domain);
+
 			Common::U32String shader(_shader->getLabel());
 			if (shader.empty() || (shader == _c("None", "shader")))
 				isSet = false;
@@ -811,6 +816,19 @@ void OptionsDialog::apply() {
 				message += _("the filtering setting could not be changed");
 			}
 
+			if (gfxError & OSystem::kTransactionShaderChangeFailed) {
+				if (previousShader.empty()) {
+					ConfMan.removeKey("shader", _domain);
+					_shader->setLabel(_c("None", "shader"));
+				} else {
+					ConfMan.set("shader", previousShader.encode(), _domain);
+					_shader->setLabel(previousShader);
+				}
+
+				message += Common::U32String("\n");
+				message += _("the shader could not be changed. Reverting to the previous setting.");
+			}
+
 			// And display the error
 			GUI::MessageDialog dialog(message);
 			dialog.runModal();


Commit: b67c4c004751000689e2322e171d5db64271bb7d
    https://github.com/scummvm/scummvm/commit/b67c4c004751000689e2322e171d5db64271bb7d
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Gracefully restore previous graphics mode on shader failure

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp
    backends/graphics/opengl/opengl-graphics.h


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 7e130eb66b2..ec94c82c304 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -362,6 +362,20 @@ bool OpenGLGraphicsManager::setShader(const Common::String &fileName) {
 }
 #endif
 
+bool OpenGLGraphicsManager::loadShader(const Common::String &fileName) {
+#if !USE_FORCED_GLES
+	// Load selected shader preset
+	if (!fileName.empty()) {
+		if (!_libretroPipeline->open(Common::FSNode(fileName))) {
+			warning("Failed to load shader %s", fileName.c_str());
+			return false;
+		}
+	}
+#endif
+
+	return true;
+}
+
 void OpenGLGraphicsManager::beginGFXTransaction() {
 	assert(_transactionMode == kTransactionNone);
 
@@ -414,6 +428,7 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
 		                   Graphics::PixelFormat::createFormatCLUT8()
 #endif
 		                  )
+			|| !loadShader(_currentState.shader)
 		   // HACK: This is really nasty but we don't have any guarantees of
 		   // a context existing before, which means we don't know the maximum
 		   // supported texture size before this. Thus, we check whether the
@@ -453,6 +468,11 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
 					}
 #endif
 
+#if !USE_FORCED_GLES
+					if (_oldState.shader != _currentState.shader) {
+						transactionError |= OSystem::kTransactionShaderChangeFailed;
+					}
+#endif
 					// Roll back to the old state.
 					_currentState = _oldState;
 					_transactionMode = kTransactionRollback;
@@ -526,16 +546,6 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
 #endif
 	}
 
-#if !USE_FORCED_GLES
-	// Load selected shader preset
-	if (!_currentState.shader.empty()) {
-		if (!_libretroPipeline->open(Common::FSNode(_currentState.shader))) {
-			warning("Failed to load shader %s", _currentState.shader.c_str());
-			transactionError |= OSystem::kTransactionShaderChangeFailed;
-		}
-	}
-#endif
-
 	// Update our display area and cursor scaling. This makes sure we pick up
 	// aspect ratio correction and game screen changes correctly.
 	recalculateDisplayAreas();
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
index 6311fe4e0d0..2d058a9aa08 100644
--- a/backends/graphics/opengl/opengl-graphics.h
+++ b/backends/graphics/opengl/opengl-graphics.h
@@ -269,6 +269,8 @@ protected:
 	 */
 	virtual bool loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format) = 0;
 
+	bool loadShader(const Common::String &fileName);
+
 	/**
 	 * Refresh the screen contents.
 	 */


Commit: 31100637fa1971729ad1b23559f18ab844f80eab
    https://github.com/scummvm/scummvm/commit/31100637fa1971729ad1b23559f18ab844f80eab
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GRAPHICS: OPENGL: Refactor for adding possibility to avoid calling error() directly

Changed paths:
    graphics/opengl/shader.cpp
    graphics/opengl/shader.h


diff --git a/graphics/opengl/shader.cpp b/graphics/opengl/shader.cpp
index ab308aa94f5..f894b2d39b9 100644
--- a/graphics/opengl/shader.cpp
+++ b/graphics/opengl/shader.cpp
@@ -116,7 +116,7 @@ static const GLchar *readFile(const Common::String &filename) {
 	return shaderSource;
 }
 
-static GLuint createDirectShader(const char *shaderSource, GLenum shaderType, const Common::String &name) {
+GLuint Shader::createDirectShader(const char *shaderSource, GLenum shaderType, const Common::String &name) {
 	GLuint shader;
 	GL_ASSIGN(shader, glCreateShader(shaderType));
 	GL_CALL(glShaderSource(shader, 1, &shaderSource, NULL));
@@ -129,13 +129,16 @@ static GLuint createDirectShader(const char *shaderSource, GLenum shaderType, co
 		GL_CALL(glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logSize));
 		GLchar *log = new GLchar[logSize];
 		GL_CALL(glGetShaderInfoLog(shader, logSize, nullptr, log));
-		error("Could not compile shader %s: %s", name.c_str(), log);
+
+		_error = Common::String::format("Could not compile shader %s: %s", name.c_str(), log);
+		warning("Shader::createDirectShader(): %s", _error.c_str());
+		return 0;
 	}
 
 	return shader;
 }
 
-static GLuint createCompatShader(const char *shaderSource, GLenum shaderType, const Common::String &name, int compatGLSLVersion) {
+GLuint Shader::createCompatShader(const char *shaderSource, GLenum shaderType, const Common::String &name, int compatGLSLVersion) {
 	GLchar versionSource[20];
 	if (OpenGLContext.type == kContextGLES2) {
 		switch(compatGLSLVersion) {
@@ -146,7 +149,9 @@ static GLuint createCompatShader(const char *shaderSource, GLenum shaderType, co
 				compatGLSLVersion = 100;
 				break;
 			default:
-				error("Invalid GLSL version %d", compatGLSLVersion);
+				_error = Common::String::format("Invalid GLSL version %d", compatGLSLVersion);
+				warning("Shader: createCompatShader(): %s", _error.c_str());
+				return 0;
 		}
 	} else {
 		switch(compatGLSLVersion) {
@@ -155,12 +160,17 @@ static GLuint createCompatShader(const char *shaderSource, GLenum shaderType, co
 			case 120:
 				break;
 			default:
-				error("Invalid GLSL version %d", compatGLSLVersion);
+				_error = Common::String::format("Invalid GLSL version %d", compatGLSLVersion);
+				warning("Shader: createCompatShader(): %s", _error.c_str());
+				return 0;
 		}
 	}
 
 	if (OpenGLContext.glslVersion < compatGLSLVersion) {
-		error("Required GLSL version %d is not supported (%d maximum)", compatGLSLVersion, OpenGLContext.glslVersion);
+		_error = Common::String::format("Required GLSL version %d is not supported (%d maximum)", compatGLSLVersion, OpenGLContext.glslVersion);
+
+		warning("Shader: createCompatShader(): %s", _error.c_str());
+		return 0;
 	}
 
 	sprintf(versionSource, "#version %d\n", compatGLSLVersion);
@@ -186,13 +196,16 @@ static GLuint createCompatShader(const char *shaderSource, GLenum shaderType, co
 		GL_CALL(glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logSize));
 		GLchar *log = new GLchar[logSize];
 		GL_CALL(glGetShaderInfoLog(shader, logSize, nullptr, log));
-		error("Could not compile shader %s: %s", name.c_str(), log);
+
+		_error = Common::String::format("Could not compile shader %s: %s", name.c_str(), log);
+		warning("Shader: createCompatShader(): %s", _error.c_str());
+		return 0;
 	}
 
 	return shader;
 }
 
-static GLuint loadShaderFromFile(const char *base, const char *extension, GLenum shaderType, int compatGLSLVersion) {
+GLuint Shader::loadShaderFromFile(const char *base, const char *extension, GLenum shaderType, int compatGLSLVersion) {
 	const Common::String filename = Common::String(base) + "." + extension;
 	const GLchar *shaderSource = readFile(filename);
 
@@ -223,10 +236,14 @@ struct SharedPtrProgramDeleter {
 Shader *Shader::_previousShader = nullptr;
 uint32 Shader::previousNumAttributes = 0;
 
+Shader::Shader() {
+}
 
-Shader::Shader(const Common::String &name, GLuint vertexShader, GLuint fragmentShader, const char *const *attributes)
-	: _name(name) {
+bool Shader::loadShader(const Common::String &name, GLuint vertexShader, GLuint fragmentShader, const char *const *attributes) {
 	assert(attributes);
+
+	_name = name;
+
 	GLuint shaderProgram;
 	GL_ASSIGN(shaderProgram, glCreateProgram());
 	GL_CALL(glAttachShader(shaderProgram, vertexShader));
@@ -245,7 +262,10 @@ Shader::Shader(const Common::String &name, GLuint vertexShader, GLuint fragmentS
 		GL_CALL(glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &logSize));
 		GLchar *log = new GLchar[logSize];
 		GL_CALL(glGetProgramInfoLog(shaderProgram, logSize, nullptr, log));
-		error("Could not link shader %s: %s", name.c_str(), log);
+
+		_error = Common::String::format("Could not link shader %s: %s", name.c_str(), log);
+		warning("Shader:Shader(): %s", _error.c_str());
+		return false;
 	}
 
 	GL_CALL(glDetachShader(shaderProgram, vertexShader));
@@ -256,27 +276,71 @@ Shader::Shader(const Common::String &name, GLuint vertexShader, GLuint fragmentS
 
 	_shaderNo = Common::SharedPtr<GLuint>(new GLuint(shaderProgram), SharedPtrProgramDeleter());
 	_uniforms = Common::SharedPtr<UniformsMap>(new UniformsMap());
+
+	return true;
 }
 
 Shader *Shader::fromStrings(const Common::String &name, const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion) {
+	Shader *shader = new Shader;
+
+	shader->loadFromStrings(name, vertex, fragment, attributes, compatGLSLVersion);
+
+	if (shader->hasError())
+		error("%s", shader->getError().c_str());
+
+	return shader;
+}
+
+bool Shader::loadFromStrings(const Common::String &name, const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion) {
 	GLuint vertexShader, fragmentShader;
 
 	if (compatGLSLVersion) {
 		vertexShader = createCompatShader(vertex, GL_VERTEX_SHADER, name + ".vertex", compatGLSLVersion);
+
+		if (!vertexShader)
+			return false;
+
 		fragmentShader = createCompatShader(fragment, GL_FRAGMENT_SHADER, name + ".fragment", compatGLSLVersion);
 	} else {
 		vertexShader = createDirectShader(vertex, GL_VERTEX_SHADER, name + ".vertex");
+
+		if (!vertexShader)
+			return false;
+
 		fragmentShader = createDirectShader(fragment, GL_FRAGMENT_SHADER, name + ".fragment");
 	}
-	return new Shader(name, vertexShader, fragmentShader, attributes);
+
+	if (!fragmentShader)
+		return false;
+
+	return loadShader(name, vertexShader, fragmentShader, attributes);
 }
 
 Shader *Shader::fromFiles(const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion) {
+	Shader *shader = new Shader;
+
+	shader->loadFromFiles(vertex, fragment, attributes, compatGLSLVersion);
+
+	if (shader->hasError())
+		error("%s", shader->getError().c_str());
+
+	return shader;
+}
+
+bool Shader::loadFromFiles(const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion) {
 	GLuint vertexShader = loadShaderFromFile(vertex, "vertex", GL_VERTEX_SHADER, compatGLSLVersion);
+
+	if (!vertexShader)
+		return false;
+
 	GLuint fragmentShader = loadShaderFromFile(fragment, "fragment", GL_FRAGMENT_SHADER, compatGLSLVersion);
 
+	if (!fragmentShader)
+		return false;
+
 	Common::String name = Common::String::format("%s/%s", vertex, fragment);
-	return new Shader(name, vertexShader, fragmentShader, attributes);
+
+	return loadShader(name, vertexShader, fragmentShader, attributes);
 }
 
 void Shader::use(bool forceReload) {
@@ -356,7 +420,9 @@ VertexAttrib &Shader::getAttribute(const char *attrib) {
 	for (uint32 i = 0; i < _attributes.size(); ++i)
 		if (_attributes[i]._name.equals(attrib))
 			return _attributes[i];
-	error("Could not find attribute %s in shader %s", attrib, _name.c_str());
+
+	_error = Common::String::format("Could not find attribute %s in shader %s", attrib, _name.c_str());
+	warning("Shader: getAttribute(): %s", _error.c_str());
 	return _attributes[0];
 }
 
diff --git a/graphics/opengl/shader.h b/graphics/opengl/shader.h
index 26a2d3b5fae..c9110152482 100644
--- a/graphics/opengl/shader.h
+++ b/graphics/opengl/shader.h
@@ -57,8 +57,9 @@ class Shader {
 	typedef Common::HashMap<Common::String, GLint> UniformsMap;
 
 public:
+	Shader();
 	~Shader();
-	Shader* clone() {
+	Shader *clone() {
 		return new Shader(*this);
 	}
 
@@ -169,7 +170,7 @@ public:
 	static void freeBuffer(GLuint vbo);
 
 	/**
-	 * Creates a shader object from strings
+	 * Creates a shader object from files
 	 *
 	 * For shader files (used by games), we used to require GLSL 1.20, this is the default for compatGLSLVersion.
 	 * The GLSL version is converted to GLSL ES version if needed.
@@ -203,10 +204,20 @@ public:
 	 */
 	static Shader *fromStrings(const Common::String &name, const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion = 0);
 
+	bool loadFromFiles(const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion = 120);
+	bool loadFromStrings(const Common::String &name, const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion = 0);
+
 	void unbind();
 
+	Common::String &getError() { return _error; }
+	bool hasError() { return !_error.empty(); }
+
 private:
-	Shader(const Common::String &name, GLuint vertexShader, GLuint fragmentShader, const char *const *attributes);
+	bool loadShader(const Common::String &name, GLuint vertexShader, GLuint fragmentShader, const char *const *attributes);
+
+	GLuint createCompatShader(const char *shaderSource, GLenum shaderType, const Common::String &name, int compatGLSLVersion);
+	GLuint createDirectShader(const char *shaderSource, GLenum shaderType, const Common::String &name);
+	GLuint loadShaderFromFile(const char *base, const char *extension, GLenum shaderType, int compatGLSLVersion);
 
 	// Since this class is cloned using the implicit copy constructor,
 	// a reference counting pointer is used to ensure deletion of the OpenGL
@@ -220,6 +231,8 @@ private:
 
 	static Shader *_previousShader;
 	static uint32 previousNumAttributes;
+
+	Common::String _error;
 };
 
 } // End of namespace OpenGL


Commit: 6d3eb64398eaedec6debe88e3505cb5bbcc245dd
    https://github.com/scummvm/scummvm/commit/6d3eb64398eaedec6debe88e3505cb5bbcc245dd
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Do not error() on shader compilation failure

Changed paths:
    backends/graphics/opengl/pipelines/libretro.cpp


diff --git a/backends/graphics/opengl/pipelines/libretro.cpp b/backends/graphics/opengl/pipelines/libretro.cpp
index 15a35d3a047..c56f3c93d00 100644
--- a/backends/graphics/opengl/pipelines/libretro.cpp
+++ b/backends/graphics/opengl/pipelines/libretro.cpp
@@ -255,10 +255,14 @@ bool LibRetroPipeline::loadPasses() {
 
 		// TODO: Handle alias defines
 
-		Shader *shader = Shader::fromStrings(fileNode.getName(),
-											 ("#define VERTEX\n" + Common::String(shaderFileStart)).c_str(),
-											 ("#define FRAGMENT\n" + Common::String(shaderFileStart)).c_str(),
-											 g_libretroShaderAttributes, shaderFileVersion);
+		Shader *shader = new Shader;
+
+		if (!shader->loadFromStrings(fileNode.getName(),
+				 ("#define VERTEX\n" + Common::String(shaderFileStart)).c_str(),
+				 ("#define FRAGMENT\n" + Common::String(shaderFileStart)).c_str(),
+				 g_libretroShaderAttributes, shaderFileVersion)) {
+			return false;
+		}
 
 		// Set uniforms with fixed value throughout lifetime.
 		// We do not support rewinding, thus fix 'forward'.


Commit: 3dada376b188f84d9813bdc2e645527ec52f4f14
    https://github.com/scummvm/scummvm/commit/3dada376b188f84d9813bdc2e645527ec52f4f14
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Show test dialog when shader was changed

Changed paths:
    gui/options.cpp
    gui/options.h


diff --git a/gui/options.cpp b/gui/options.cpp
index 568bb89a5ad..08487f4879b 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -826,12 +826,34 @@ void OptionsDialog::apply() {
 				}
 
 				message += Common::U32String("\n");
-				message += _("the shader could not be changed. Reverting to the previous setting.");
+				message += _("the shader could not be changed");
 			}
 
 			// And display the error
 			GUI::MessageDialog dialog(message);
 			dialog.runModal();
+		} else {
+			// Successful transaction. Check if we need to show test screen
+			Common::String shader;
+			if (ConfMan.hasKey("shader", _domain))
+				shader = ConfMan.get("shader", _domain);
+
+			// If shader was change, show the test dialog
+			if (previousShader != shader) {
+				if (!testGraphicsSettings()) {
+					if (previousShader.empty()) {
+						ConfMan.removeKey("shader", _domain);
+						_shader->setLabel(_c("None", "shader"));
+					} else {
+						ConfMan.set("shader", previousShader.encode(), _domain);
+						_shader->setLabel(previousShader);
+					}
+
+					g_system->beginGFXTransaction();
+					g_system->setShader(ConfMan.get("shader", _domain));
+					g_system->endGFXTransaction();
+				}
+			}
 		}
 	}
 
@@ -3612,4 +3634,13 @@ void GlobalOptionsDialog::storageErrorCallback(Networking::ErrorResponse respons
 #endif // USE_LIBCURL
 #endif // USE_CLOUD
 
+bool OptionsDialog::testGraphicsSettings() {
+	// And display the error
+	GUI::MessageDialog dialog(_("Your shader scaler setting has been changed. Do you want to keep these settings?"),
+				_("Yes"), _("No"));
+
+	// Reverting X seconds
+	return (dialog.runModal() == GUI::kMessageOK);
+}
+
 } // End of namespace GUI
diff --git a/gui/options.h b/gui/options.h
index 69d80505c95..29ef752f977 100644
--- a/gui/options.h
+++ b/gui/options.h
@@ -90,7 +90,7 @@ protected:
 	virtual void build();
 	virtual void clean();
 	void rebuild();
-
+	bool testGraphicsSettings();
 
 	void addControlControls(GuiObject *boss, const Common::String &prefix);
 	void addKeyMapperControls(GuiObject *boss, const Common::String &prefix, const Common::Array<Common::Keymap *> &keymaps, const Common::String &domain);


Commit: a8ba66c95e900619a9b33e2cd470e2451f77449b
    https://github.com/scummvm/scummvm/commit/a8ba66c95e900619a9b33e2cd470e2451f77449b
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Implement CountdownMessageDialog

Changed paths:
    gui/message.cpp
    gui/message.h


diff --git a/gui/message.cpp b/gui/message.cpp
index 800733a071e..6de65d1ae8f 100644
--- a/gui/message.cpp
+++ b/gui/message.cpp
@@ -42,9 +42,12 @@ void MessageDialog::init(const Common::U32String &message,
 						 const Common::U32String &defaultButton,
 						 const Common::U32StringArray &altButtons,
 						 Graphics::TextAlign alignment,
-						 const char *url) {
+						 const char *url,
+						 const Common::U32String &extraMessage) {
 	_url = url;
 
+	_extraMessage = nullptr;
+
 	const int screenW = g_system->getOverlayWidth();
 	const int screenH = g_system->getOverlayHeight();
 
@@ -102,18 +105,25 @@ void MessageDialog::init(const Common::U32String &message,
 		buttonHotKey = 0;
 		buttonPos += buttonWidth + buttonSpacing;
 	}
+
+	if (!extraMessage.empty()) {
+		_extraMessage = new StaticTextWidget(this, 10, _h, maxlineWidth, kLineHeight, extraMessage, Graphics::kTextAlignLeft);
+
+		_h += kLineHeight;
+	}
 }
 
 MessageDialog::MessageDialog(const Common::U32String &message,
 							 const Common::U32String &defaultButton,
 							 const Common::U32String &altButton,
 							 Graphics::TextAlign alignment,
-							 const char *url)
+							 const char *url,
+							 const Common::U32String &extraMessage)
 	: Dialog(30, 20, 260, 124) {
 
 	init(message, defaultButton,
 		 altButton.empty() ? Common::U32StringArray() : Common::U32StringArray(1, altButton),
-		 alignment, url);
+		 alignment, url, extraMessage);
 }
 
 MessageDialog::MessageDialog(const Common::String &message,
@@ -125,7 +135,7 @@ MessageDialog::MessageDialog(const Common::String &message,
 
 	init(Common::U32String(message), Common::U32String(defaultButton),
 		 altButton.empty() ? Common::U32StringArray() : Common::U32StringArray(1, Common::U32String(altButton)),
-		 alignment, url);
+		 alignment, url, Common::U32String());
 }
 
 MessageDialog::MessageDialog(const Common::U32String &message,
@@ -134,7 +144,7 @@ MessageDialog::MessageDialog(const Common::U32String &message,
 							 Graphics::TextAlign alignment)
 	: Dialog(30, 20, 260, 124) {
 
-	init(message, defaultButton, altButtons, alignment, nullptr);
+	init(message, defaultButton, altButtons, alignment, nullptr, Common::U32String());
 }
 
 void MessageDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
@@ -169,6 +179,41 @@ void TimedMessageDialog::handleTickle() {
 		close();
 }
 
+CountdownMessageDialog::CountdownMessageDialog(const Common::U32String &message,
+				  uint32 duration,
+				  const Common::U32String &defaultButton,
+				  const Common::U32String &altButton,
+				  Graphics::TextAlign alignment,
+				  const Common::U32String &countdownMessage)
+	: MessageDialog(message, defaultButton, altButton, alignment, nullptr, countdownMessage) {
+	_startTime = g_system->getMillis();
+	_timer = _startTime + duration;
+
+	_countdownMessage = countdownMessage;
+
+	updateCountdown();
+}
+
+void CountdownMessageDialog::handleTickle() {
+	updateCountdown();
+
+	MessageDialog::handleTickle();
+	if (g_system->getMillis() > _timer) {
+		setResult(kMessageAlt);
+		close();
+	}
+}
+
+void CountdownMessageDialog::updateCountdown() {
+	uint32 secs = (_timer - g_system->getMillis()) / 1000;
+
+	Common::U32String msg = Common::U32String::format(_countdownMessage, secs);
+
+	if (msg != _extraMessage->getLabel()) {
+		_extraMessage->setLabel(msg);
+	}
+}
+
 MessageDialogWithURL::MessageDialogWithURL(const Common::U32String &message, const char *url, const Common::U32String &defaultButton, Graphics::TextAlign alignment)
 	: MessageDialog(message, defaultButton, _("Open URL"), alignment, url) {
 }
diff --git a/gui/message.h b/gui/message.h
index 1b6c619c7f4..0789b36ee72 100644
--- a/gui/message.h
+++ b/gui/message.h
@@ -29,6 +29,7 @@
 namespace GUI {
 
 class CommandSender;
+class StaticTextWidget;
 
 enum {
 	kMessageOK = 0,
@@ -45,7 +46,8 @@ public:
 				  const Common::U32String &defaultButton = Common::U32String("OK"),
 				  const Common::U32String &altButton = Common::U32String(),
 				  Graphics::TextAlign alignment = Graphics::kTextAlignCenter,
-				  const char *url = nullptr);
+				  const char *url = nullptr,
+				  const Common::U32String &extraMessage = Common::U32String());
 	MessageDialog(const Common::String &message,
 				  const Common::String &defaultButton = "OK",
 				  const Common::String &altButton = Common::String(),
@@ -63,7 +65,11 @@ private:
 			  const Common::U32String &defaultButton,
 			  const Common::U32StringArray &altButtons,
 			  Graphics::TextAlign alignment,
-			  const char *url);
+			  const char *url,
+			  const Common::U32String &extraMessage);
+
+protected:
+	StaticTextWidget *_extraMessage;
 };
 
 /**
@@ -79,6 +85,28 @@ protected:
 	uint32 _timer;
 };
 
+/**
+ * Timed message dialog: displays a message with a countdown.
+ */
+class CountdownMessageDialog : public MessageDialog {
+public:
+	CountdownMessageDialog(const Common::U32String &message,
+				  uint32 duration,
+				  const Common::U32String &defaultButton = Common::U32String("OK"),
+				  const Common::U32String &altButton = Common::U32String(),
+				  Graphics::TextAlign alignment = Graphics::kTextAlignCenter,
+				  const Common::U32String &countdownMessage = Common::U32String(""));
+
+	void handleTickle() override;
+
+protected:
+	void updateCountdown();
+
+	uint32 _timer;
+	uint32 _startTime;
+	Common::U32String _countdownMessage;
+};
+
 /**
  * Message dialog with button to open a specified URL
  */


Commit: 26e5ef35abfe5ba4e973d290a2062f1643cea619
    https://github.com/scummvm/scummvm/commit/26e5ef35abfe5ba4e973d290a2062f1643cea619
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Use countdown dialog on shader test

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index 08487f4879b..e4a543f5dd1 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -3636,10 +3636,11 @@ void GlobalOptionsDialog::storageErrorCallback(Networking::ErrorResponse respons
 
 bool OptionsDialog::testGraphicsSettings() {
 	// And display the error
-	GUI::MessageDialog dialog(_("Your shader scaler setting has been changed. Do you want to keep these settings?"),
-				_("Yes"), _("No"));
+	GUI::CountdownMessageDialog dialog(_("Your shader scaler setting has been changed. Do you want to keep these settings?"),
+				10000,
+				_("Yes"), _("No"), Graphics::kTextAlignCenter,
+				_("Reverting in %d seconds"));
 
-	// Reverting X seconds
 	return (dialog.runModal() == GUI::kMessageOK);
 }
 


Commit: 7df3792ae360f7d0ec5ea4a50b2b7b68c1e7ccda
    https://github.com/scummvm/scummvm/commit/7df3792ae360f7d0ec5ea4a50b2b7b68c1e7ccda
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Implement drawing mode of top dialog only

Changed paths:
    gui/gui-manager.cpp
    gui/gui-manager.h


diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index 7073dabaeb4..57e4ebace04 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -78,6 +78,8 @@ GuiManager::GuiManager() : CommandSender(nullptr), _redrawStatus(kRedrawDisabled
 	_topDialogLeftPadding = 0;
 	_topDialogRightPadding = 0;
 
+	_displayTopDialogOnly = false;
+
 	// Clear the cursor
 	memset(_cursor, 0xFF, sizeof(_cursor));
 
@@ -343,6 +345,15 @@ void GuiManager::redrawFull() {
 	_system->updateScreen();
 }
 
+void GuiManager::displayTopDialogOnly(bool mode) {
+	if (mode == _displayTopDialogOnly)
+		return;
+
+	_displayTopDialogOnly = mode;
+
+	redrawFull();
+}
+
 void GuiManager::redraw() {
 	ThemeEngine::ShadingStyle shading;
 
@@ -369,9 +380,11 @@ void GuiManager::redraw() {
 			_theme->clearAll();
 			_theme->drawToBackbuffer();
 
-			for (DialogStack::size_type i = 0; i < _dialogStack.size() - 1; i++) {
-				_dialogStack[i]->drawDialog(kDrawLayerBackground);
-				_dialogStack[i]->drawDialog(kDrawLayerForeground);
+			if (!_displayTopDialogOnly) {
+				for (DialogStack::size_type i = 0; i < _dialogStack.size() - 1; i++) {
+					_dialogStack[i]->drawDialog(kDrawLayerBackground);
+					_dialogStack[i]->drawDialog(kDrawLayerForeground);
+				}
 			}
 
 			// fall through
diff --git a/gui/gui-manager.h b/gui/gui-manager.h
index 66df2f6acdb..8dfb46210ba 100644
--- a/gui/gui-manager.h
+++ b/gui/gui-manager.h
@@ -140,6 +140,8 @@ public:
 
 	void initIconsSet();
 
+	void displayTopDialogOnly(bool mode);
+
 protected:
 	enum RedrawStatus {
 		kRedrawDisabled = 0,
@@ -169,6 +171,8 @@ protected:
 	int			_topDialogLeftPadding;
 	int			_topDialogRightPadding;
 
+	bool		_displayTopDialogOnly;
+
 	Common::Mutex _iconsMutex;
 	Common::SearchSet _iconsSet;
 	bool _iconsSetChanged;


Commit: 655fea0de05ae4d837c854b6e656390b73aaf6da
    https://github.com/scummvm/scummvm/commit/655fea0de05ae4d837c854b6e656390b73aaf6da
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Draw only confirmation dialog on shader change

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index e4a543f5dd1..13b0b111648 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -3641,7 +3641,13 @@ bool OptionsDialog::testGraphicsSettings() {
 				_("Yes"), _("No"), Graphics::kTextAlignCenter,
 				_("Reverting in %d seconds"));
 
-	return (dialog.runModal() == GUI::kMessageOK);
+	g_gui.displayTopDialogOnly(true);
+
+	bool retval = (dialog.runModal() == GUI::kMessageOK);
+
+	g_gui.displayTopDialogOnly(false);
+
+	return retval;
 }
 
 } // End of namespace GUI


Commit: 7cd63b418a4f13cbd8670a539441400e21781bc5
    https://github.com/scummvm/scummvm/commit/7cd63b418a4f13cbd8670a539441400e21781bc5
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Do not apply shadow on single dialog draw

Changed paths:
    gui/gui-manager.cpp


diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index 57e4ebace04..4316086d90b 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -400,7 +400,9 @@ void GuiManager::redraw() {
 				previousDialog->drawDialog(kDrawLayerForeground);
 			}
 
-			_theme->applyScreenShading(shading);
+			if (!_displayTopDialogOnly)
+				_theme->applyScreenShading(shading);
+
 			_dialogStack.top()->drawDialog(kDrawLayerBackground);
 
 			_theme->drawToScreen();


Commit: e11bd0f2f2595719927cef525086fbf873079319
    https://github.com/scummvm/scummvm/commit/e11bd0f2f2595719927cef525086fbf873079319
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Initial code for test screen drawing

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index 13b0b111648..7b16adbbc93 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -64,6 +64,7 @@
 #endif
 #endif
 
+#include "graphics/palette.h"
 #include "graphics/renderer.h"
 #include "graphics/scalerplugin.h"
 
@@ -3634,7 +3635,33 @@ void GlobalOptionsDialog::storageErrorCallback(Networking::ErrorResponse respons
 #endif // USE_LIBCURL
 #endif // USE_CLOUD
 
+static void drawTestScreen() {
+	int xres = 640, yres = 480;
+
+	g_system->beginGFXTransaction();
+	g_system->initSize(xres, yres);
+	g_system->endGFXTransaction();
+
+	const byte palette[] = {
+		0,       0,    0,
+		0xff, 0xff, 0xff,
+	};
+
+	g_system->getPaletteManager()->setPalette(palette, 0, ARRAYSIZE(palette) / 3);
+
+	Graphics::Surface surf;
+
+	surf.create(xres, yres, Graphics::PixelFormat::createFormatCLUT8());
+	surf.fillRect(Common::Rect(0, 0, xres, yres), 1);
+
+	g_system->copyRectToScreen(surf.getPixels(), surf.pitch, 0, 0, xres, yres);
+
+	g_system->updateScreen();
+}
+
 bool OptionsDialog::testGraphicsSettings() {
+	drawTestScreen();
+
 	// And display the error
 	GUI::CountdownMessageDialog dialog(_("Your shader scaler setting has been changed. Do you want to keep these settings?"),
 				10000,


Commit: 5b307826db80db19bcc14c3f5bdb4f9007845fb3
    https://github.com/scummvm/scummvm/commit/5b307826db80db19bcc14c3f5bdb4f9007845fb3
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: More work on shader test screen

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index 7b16adbbc93..2d6b5542480 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -3635,6 +3635,118 @@ void GlobalOptionsDialog::storageErrorCallback(Networking::ErrorResponse respons
 #endif // USE_LIBCURL
 #endif // USE_CLOUD
 
+/****************************
+ * Shader test screen
+ ****************************/
+
+enum {
+	BLACK = 0,
+	WHITE,
+	RED,
+	GREEN,
+	BLUE,
+	CYAN,
+	MAGENTA,
+	YELLOW,
+	GRAY1,
+	GREEN1,
+	GREEN2,
+	RED1,
+	BLUE1,
+	BLUE2,
+	YELLOW1,
+	RED2,
+	GRAY2,
+	GRAY3,
+	GRAY4,
+	GRAY5,
+	GRAY6,
+};
+
+const uint32 paletteSrc[] = {
+	0x000000,
+	0xffffff,
+	0xFF0000,
+	0x00FF00,
+	0x0000FF,
+	0x00FFFF,
+	0xFF00FF,
+	0xFFFF00,
+	0x7F7F7F,
+	0x00C896,
+	0x649632,
+	0xC83264,
+	0x6464FF,
+	0x6496FF,
+	0xC86400,
+	0xE10000,
+	0x333333,
+	0x666666,
+	0x999999,
+	0xCCCCCC,
+	0xBFBFBF,
+};
+
+
+static void squaremesh(Graphics::Surface &surface, int xres, int yres, int width, int height, int gapsize, int meshcolor, int squarecolor) {
+    int centerx = xres / 2;
+    int centery = yres / 2;
+
+    surface.fillRect(Common::Rect(0, 0, xres, yres), squarecolor);
+    for (int x = centerx % (width + gapsize) + width / 2 - (width + gapsize); x < xres; x += gapsize + width) {
+        surface.fillRect(Common::Rect(x, 0, x + gapsize - 1, yres - 1), meshcolor);
+    }
+    for (int y = centery % (height + gapsize) + height / 2 - (height + gapsize); y < yres; y += gapsize + height) {
+        surface.fillRect(Common::Rect(0, y, xres - 1, y + gapsize - 1), meshcolor);
+    }
+}
+
+static void frame(Graphics::Surface &surface, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int color) {
+    surface.fillRect(Common::Rect(x1, y1, x2, y3), color);   //top
+    surface.fillRect(Common::Rect(x1, y4, x2, y2), color);   //bottom
+    surface.fillRect(Common::Rect(x1, y1, x3, y2), color);   //left
+    surface.fillRect(Common::Rect(x4, y1, x2, y2), color);   //right
+}
+
+static void drawRow(Graphics::Surface &surface, int offsety, int colors[], int numColors, int gap, int vsize, int xres, int offsetx) {
+    int boxsize;
+    int x;
+    boxsize = (xres - (numColors + 1) * gap) / numColors;   //-gaps between boxes
+    offsetx += gap + 1;
+    for (x = 0; x < numColors; x++) {
+        surface.fillRect(Common::Rect(offsetx, offsety, offsetx + boxsize - 1, offsety + vsize - 1), colors[x]);
+        offsetx += (boxsize + gap);
+    }
+}
+
+static void circleColorNoblend(Graphics::Surface &surface, double x, double y, double r, int color, bool invert) {
+    int sx;
+
+    r += 0.49;
+    for (sx = (int)round(x - r); sx < (int)round(x + r) + 1; sx++) {
+        double h = sqrt(r * r - pow(sx - x, 2));
+        if (invert) {
+            surface.vLine(sx, 0, -1 + (int)ceil(y - h), color);
+            surface.vLine(sx, 1 + (int)floor(y + h), surface.h, color);
+        } else
+            surface.vLine(sx, (int)ceil(y - h), (int)floor(y + h), color);
+    }
+    if (invert && sx < surface.w)
+        surface.fillRect(Common::Rect(sx, 0, surface.w - 1, surface.h - 1), color);
+    if (invert && (int)round(x - r) > 0)
+        surface.fillRect(Common::Rect(0, 0, -1 + (int)round(x - r), surface.h - 1), color);
+}
+
+static void blacksquareinwhitecircle(Graphics::Surface &surface, int x1, int y1, int gapsize, int rwidth, int rheight) {
+    double c1y = y1 - (gapsize + 1.0) / 2.0;
+    double c1x = x1 - (gapsize + 1.0) / 2.0;
+    circleColorNoblend(surface, c1x, c1y, rwidth * 1.5, WHITE, false);
+    surface.fillRect(Common::Rect(x1 - rwidth - gapsize, y1 - rheight - gapsize, x1 + rwidth - 1, y1 + rheight - 1), BLACK);
+    surface.fillRect(Common::Rect(x1 - rwidth - gapsize, y1 - gapsize, x1 + rwidth - 1, y1 - 1), WHITE);
+    surface.fillRect(Common::Rect(x1 - gapsize, y1 - rheight - gapsize, x1 - 1, y1 + rheight - 1), WHITE);
+    circleColorNoblend(surface, c1x, c1y, gapsize + 1, WHITE, false);
+}
+
 static void drawTestScreen() {
 	int xres = 640, yres = 480;
 
@@ -3642,19 +3754,169 @@ static void drawTestScreen() {
 	g_system->initSize(xres, yres);
 	g_system->endGFXTransaction();
 
-	const byte palette[] = {
-		0,       0,    0,
-		0xff, 0xff, 0xff,
-	};
+	byte palette[ARRAYSIZE(paletteSrc) * 3];
+
+	for (int i = 0; i < ARRAYSIZE(paletteSrc); i++) {
+		palette[i * 3 + 0] = (paletteSrc[i] >> 16) & 0xFF;
+		palette[i * 3 + 1] = (paletteSrc[i] >>  8) & 0xFF;
+		palette[i * 3 + 2] = (paletteSrc[i]      ) & 0xFF;
+	}
 
 	g_system->getPaletteManager()->setPalette(palette, 0, ARRAYSIZE(palette) / 3);
 
-	Graphics::Surface surf;
+	Graphics::Surface surface;
+
+	surface.create(xres, yres, Graphics::PixelFormat::createFormatCLUT8());
+	surface.fillRect(Common::Rect(0, 0, xres, yres), 0);
+
+
+    int squaresize = 8;
+    int gapsize = 2;
+
+    int width, height;
+    int rwidth, rheight;
+    int xsquares, ysquares;
+
+    int xcenter = xres / 2 - xres % 2;
+
+    bool cont = true;
+    while (cont) {
+
+        if (squaresize > 8) {
+            if (xsquares < 6 || ysquares < 6) {
+                squaresize -= 4;
+                cont = false;
+            }
+        }
+
+        squaresize += 2;
 
-	surf.create(xres, yres, Graphics::PixelFormat::createFormatCLUT8());
-	surf.fillRect(Common::Rect(0, 0, xres, yres), 1);
+        width = xres % 2 + squaresize;
+        height = yres % 2 + squaresize;
 
-	g_system->copyRectToScreen(surf.getPixels(), surf.pitch, 0, 0, xres, yres);
+        rwidth = width + gapsize;
+        rheight = height + gapsize;
+
+        xsquares = (xres - rwidth - gapsize - 16) / rwidth / 2;
+        ysquares = (yres - rheight - gapsize - 16) / rheight / 2;
+
+    }
+
+    squaremesh(surface, xres, yres, width, height, gapsize, WHITE, GRAY1);
+
+    int startx = xres / 2 - width / 2 - width % 2 - xsquares * rwidth - gapsize - 1;
+    int starty = yres / 2 - height / 2 - height % 2 - ysquares * rheight - gapsize - 1;
+    int endx = startx + rwidth * (2 * xsquares + 1) + gapsize + 1;
+    int endy = starty + rheight * (2 * ysquares + 1) + gapsize + 1;
+    int i;
+
+    frame(surface, 0, 0, xres, yres, 1, 1, xres - 2, yres - 2, WHITE);
+    frame(surface, 2, 2, xres - 3, yres - 3, startx, starty, endx, endy, BLACK);
+
+    for (i = 0; i < ysquares * 2 + 1; i++) {
+        if (i % 2 == 0) {
+            surface.fillRect(Common::Rect(0, starty + gapsize + i * rheight, startx - 2, starty + gapsize + (i + 1) * rheight - 1), WHITE);
+            surface.fillRect(Common::Rect(endx + 2, starty + gapsize + i * rheight, xres - 1, starty + gapsize + (i + 1) * rheight - 1), WHITE);
+        }
+
+    }
+    for (i = 0; i < xsquares * 2 + 1; i++) {
+        if (i % 2 == 0) {
+            surface.fillRect(Common::Rect(startx + gapsize + i * rwidth, 0, startx + gapsize + (i + 1) * rwidth - 1, starty - 2), WHITE);
+            surface.fillRect(Common::Rect(startx + gapsize + i * rwidth, endy + 2, startx + gapsize + (i + 1) * rwidth - 1, yres - 1), WHITE);
+        }
+
+    }
+
+    int monosize = 6;
+    int x1 = xres / 2 - width / 2 - width % 2 - rwidth * monosize - rwidth; //left
+    int y1 = yres / 2 - height / 2 - height % 2 - rheight * (monosize - 1); //up
+    int x2 = x1 + rwidth * (monosize * 2 + 2) + width - 1;  //right
+    int y2 = y1 + (monosize * 2 - 1) * rheight - gapsize - 1;   //bottom
+
+    if (xsquares - 1 > monosize) {
+        surface.fillRect(Common::Rect(x1, y1, x1 + width - 1, yres / 2), GREEN1);    //up left
+        surface.fillRect(Common::Rect(x2 - width + 1, y1, x2, yres / 2), GREEN2);    //up right
+        surface.fillRect(Common::Rect(x1, yres / 2 + yres % 2, x1 + width - 1, y2), RED1); //bottom left
+        surface.fillRect(Common::Rect(x2 - width + 1, yres / 2 + yres % 2, x2, y2), BLUE1); //bottom right
+        if (monosize > 2) {
+            surface.fillRect(Common::Rect(x1 + width, y1, x1 + rwidth + width - 1, y1 + 2 * rheight - gapsize - 1), BLUE2); //up left small
+            surface.fillRect(Common::Rect(x1 + width, y2 - rheight * 2 + gapsize + 1, x1 + rwidth + width - 1, y2), YELLOW1); //bottom left small
+            surface.fillRect(Common::Rect(x2 - rwidth - width + 1, y1, x2 - width, y1 + 2 * rheight - gapsize - 1), BLUE2); //up right small
+            surface.fillRect(Common::Rect(x2 - rwidth - width + 1, y2 - rheight * 2 + gapsize + 1, x2 - width, y2), YELLOW1); //bottom right small
+        }
+    }
+
+    if (xsquares - 4 > monosize) {
+        blacksquareinwhitecircle(surface, x1 - rwidth * 2, y1 + rheight, gapsize, rwidth, rheight);
+        blacksquareinwhitecircle(surface, x2 + rwidth * 2 + gapsize + 1, y1 + rheight, gapsize, rwidth, rheight);
+        blacksquareinwhitecircle(surface, x1 - rwidth * 2, y2 - height + 1, gapsize, rwidth, rheight);
+        blacksquareinwhitecircle(surface, x2 + rwidth * 2 + gapsize + 1, y2 - height + 1, gapsize, rwidth, rheight);
+    }
+
+    int monoradius = monosize * rwidth + gapsize;
+
+    // two bottom rows
+    surface.fillRect(Common::Rect(x1, y2 - rheight + gapsize / 2 + 1, x2, y2 + rheight + gapsize / 2 + 1), YELLOW);
+    surface.fillRect(Common::Rect(xcenter - rwidth / 2, y2 - rheight + gapsize / 2 + 1, xcenter - rwidth / 2 + rwidth, y2 + rheight + gapsize / 2 + 1), RED2);
+
+    surface.fillRect(Common::Rect(x1, y2 - 2 * rheight + gapsize / 2 + 1, x2, y2 - rheight + gapsize / 2), WHITE);
+    surface.fillRect(Common::Rect(xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight + gapsize / 2), BLACK);
+
+    // two top rows
+    surface.fillRect(Common::Rect(x1, y2 - 12 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 10 + gapsize / 2), WHITE);
+    surface.fillRect(Common::Rect(xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 2, y2 - rheight * 10 + gapsize / 2), BLACK);
+
+    surface.fillRect(Common::Rect(x1, y2 - 10 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 9 + gapsize / 2), BLACK);
+    surface.fillRect(Common::Rect(xres / 2 - rwidth * 3, y2 - 10 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight * 9 + gapsize / 2), WHITE);
+
+    // color (gray) bars
+    int greyColors[] = { BLACK, GRAY2, GRAY3, GRAY4, GRAY5, WHITE};
+    drawRow(surface, y2 - 3 * rheight + gapsize / 2 + 1, greyColors, 6, 0, rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
+
+    surface.fillRect(Common::Rect(x1, y2 - 6 * rheight + gapsize / 2 + 1, x2, y2 - 3 * rheight + gapsize / 2), BLACK);
+
+    int topColors[] = { YELLOW, CYAN, GREEN, MAGENTA, RED, BLUE };
+    drawRow(surface, y2 - 8 * rheight + gapsize / 2 + 1, topColors, 6, 0, 2 * rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
+
+    // periodic gray and white
+    int periodsize = monosize * (rwidth * 2) * 11 / 16 / 6;
+    int blacksize = periodsize * 6 / 11;
+    surface.fillRect(Common::Rect(x1, y2 - 9 * rheight + gapsize / 2 + 1, x2, y2 - 8 * rheight + gapsize / 2), GRAY6);
+    for (i = 0; i < 5; i++) {
+        surface.fillRect(Common::Rect(xres / 2 + i * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 + i * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2), BLACK);
+        surface.fillRect(Common::Rect(xres / 2 - (i + 1) * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 - (i + 1) * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2), BLACK);
+    }
+
+    // small lines
+    int xmin = xcenter - rwidth / 2 - rwidth * 4;
+    int xmax = xcenter - rwidth / 2 + rwidth * 5;
+    int step;
+    int alternatingColors[] = { WHITE, BLACK };
+    int blackorwhite = 0;
+    for (i = xmin; i < xmax; i++) {
+        step = 6 * (xmax - i - 1) / (xmax - xmin) + 1;
+        surface.fillRect(Common::Rect(i, y2 - 5 * rheight + gapsize / 2 + 1, i + step - 1, y2 - 3 * rheight + gapsize / 2), alternatingColors[blackorwhite++ % 2]);
+        i += step - 1;
+    }
+
+    // horizontal middle part
+    surface.fillRect(Common::Rect(xcenter - rwidth / 2, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2 + xres % 2 + rwidth / 2 - 1, y2 - 4 * rheight + gapsize / 2), BLACK);
+    surface.fillRect(Common::Rect(xres / 2 + xres % 2 - 1, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2, y2 - 4 * rheight + gapsize / 2), WHITE);
+    surface.fillRect(Common::Rect(x1, yres / 2 + yres % 2 - 1, x2, yres / 2), WHITE);
+
+    // vertical lines in the middle
+    for (i = x1 - gapsize; i < x2 + gapsize; i += rwidth) {
+        surface.fillRect(Common::Rect(i, y2 - 6 * rheight + gapsize / 2 + 1, i + gapsize - 1, y2 - 5 * rheight + gapsize / 2), WHITE);
+    }
+
+    circleColorNoblend(surface, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, 3, WHITE, false);
+    circleColorNoblend(surface, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, monoradius, BLACK, true);
+
+    //stringtobox(surface, xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 2, y2 - rheight * 10 + gapsize / 2, settings.text_top, WHITE);
+    //stringtobox(surface, xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight + gapsize / 2, settings.text_bottom, WHITE);
+
+	g_system->copyRectToScreen(surface.getPixels(), surface.pitch, 0, 0, xres, yres);
 
 	g_system->updateScreen();
 }


Commit: d9bebc379a3a61d0d8e01c9f8c947cd70f89f7fd
    https://github.com/scummvm/scummvm/commit/d9bebc379a3a61d0d8e01c9f8c947cd70f89f7fd
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Fixes to the test screen drawing

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index 2d6b5542480..f4ea71c702e 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -64,6 +64,8 @@
 #endif
 #endif
 
+#include "base/version.h"
+#include "graphics/fonts/amigafont.h"
 #include "graphics/palette.h"
 #include "graphics/renderer.h"
 #include "graphics/scalerplugin.h"
@@ -3661,6 +3663,7 @@ enum {
 	GRAY4,
 	GRAY5,
 	GRAY6,
+	TRANSCOLOR,
 };
 
 const uint32 paletteSrc[] = {
@@ -3685,27 +3688,31 @@ const uint32 paletteSrc[] = {
 	0x999999,
 	0xCCCCCC,
 	0xBFBFBF,
+	0xFE00FE,
 };
 
+static void boxColor(Graphics::Surface &surface, int x1, int y1, int x2, int y2, int color) {
+	surface.fillRect(Common::Rect(x1, y1, x2 + 1, y2 + 1), color);
+}
 
 static void squaremesh(Graphics::Surface &surface, int xres, int yres, int width, int height, int gapsize, int meshcolor, int squarecolor) {
     int centerx = xres / 2;
     int centery = yres / 2;
 
-    surface.fillRect(Common::Rect(0, 0, xres, yres), squarecolor);
+    boxColor(surface, 0, 0, xres, yres, squarecolor);
     for (int x = centerx % (width + gapsize) + width / 2 - (width + gapsize); x < xres; x += gapsize + width) {
-        surface.fillRect(Common::Rect(x, 0, x + gapsize - 1, yres - 1), meshcolor);
+        boxColor(surface, x, 0, x + gapsize - 1, yres - 1, meshcolor);
     }
     for (int y = centery % (height + gapsize) + height / 2 - (height + gapsize); y < yres; y += gapsize + height) {
-        surface.fillRect(Common::Rect(0, y, xres - 1, y + gapsize - 1), meshcolor);
+        boxColor(surface, 0, y, xres - 1, y + gapsize - 1, meshcolor);
     }
 }
 
 static void frame(Graphics::Surface &surface, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int color) {
-    surface.fillRect(Common::Rect(x1, y1, x2, y3), color);   //top
-    surface.fillRect(Common::Rect(x1, y4, x2, y2), color);   //bottom
-    surface.fillRect(Common::Rect(x1, y1, x3, y2), color);   //left
-    surface.fillRect(Common::Rect(x4, y1, x2, y2), color);   //right
+    boxColor(surface, x1, y1, x2, y3, color);   //top
+    boxColor(surface, x1, y4, x2, y2, color);   //bottom
+    boxColor(surface, x1, y1, x3, y2, color);   //left
+    boxColor(surface, x4, y1, x2, y2, color);   //right
 }
 
 static void drawRow(Graphics::Surface &surface, int offsety, int colors[], int numColors, int gap, int vsize, int xres, int offsetx) {
@@ -3714,7 +3721,7 @@ static void drawRow(Graphics::Surface &surface, int offsety, int colors[], int n
     boxsize = (xres - (numColors + 1) * gap) / numColors;   //-gaps between boxes
     offsetx += gap + 1;
     for (x = 0; x < numColors; x++) {
-        surface.fillRect(Common::Rect(offsetx, offsety, offsetx + boxsize - 1, offsety + vsize - 1), colors[x]);
+        boxColor(surface, offsetx, offsety, offsetx + boxsize - 1, offsety + vsize - 1, colors[x]);
         offsetx += (boxsize + gap);
     }
 }
@@ -3732,18 +3739,18 @@ static void circleColorNoblend(Graphics::Surface &surface, double x, double y, d
             surface.vLine(sx, (int)ceil(y - h), (int)floor(y + h), color);
     }
     if (invert && sx < surface.w)
-        surface.fillRect(Common::Rect(sx, 0, surface.w - 1, surface.h - 1), color);
+        boxColor(surface, sx, 0, surface.w - 1, surface.h - 1, color);
     if (invert && (int)round(x - r) > 0)
-        surface.fillRect(Common::Rect(0, 0, -1 + (int)round(x - r), surface.h - 1), color);
+        boxColor(surface, 0, 0, -1 + (int)round(x - r), surface.h - 1, color);
 }
 
 static void blacksquareinwhitecircle(Graphics::Surface &surface, int x1, int y1, int gapsize, int rwidth, int rheight) {
     double c1y = y1 - (gapsize + 1.0) / 2.0;
     double c1x = x1 - (gapsize + 1.0) / 2.0;
     circleColorNoblend(surface, c1x, c1y, rwidth * 1.5, WHITE, false);
-    surface.fillRect(Common::Rect(x1 - rwidth - gapsize, y1 - rheight - gapsize, x1 + rwidth - 1, y1 + rheight - 1), BLACK);
-    surface.fillRect(Common::Rect(x1 - rwidth - gapsize, y1 - gapsize, x1 + rwidth - 1, y1 - 1), WHITE);
-    surface.fillRect(Common::Rect(x1 - gapsize, y1 - rheight - gapsize, x1 - 1, y1 + rheight - 1), WHITE);
+    boxColor(surface, x1 - rwidth - gapsize, y1 - rheight - gapsize, x1 + rwidth - 1, y1 + rheight - 1, BLACK);
+    boxColor(surface, x1 - rwidth - gapsize, y1 - gapsize, x1 + rwidth - 1, y1 - 1, WHITE);
+    boxColor(surface, x1 - gapsize, y1 - rheight - gapsize, x1 - 1, y1 + rheight - 1, WHITE);
     circleColorNoblend(surface, c1x, c1y, gapsize + 1, WHITE, false);
 }
 
@@ -3769,7 +3776,6 @@ static void drawTestScreen() {
 	surface.create(xres, yres, Graphics::PixelFormat::createFormatCLUT8());
 	surface.fillRect(Common::Rect(0, 0, xres, yres), 0);
 
-
     int squaresize = 8;
     int gapsize = 2;
 
@@ -3815,15 +3821,15 @@ static void drawTestScreen() {
 
     for (i = 0; i < ysquares * 2 + 1; i++) {
         if (i % 2 == 0) {
-            surface.fillRect(Common::Rect(0, starty + gapsize + i * rheight, startx - 2, starty + gapsize + (i + 1) * rheight - 1), WHITE);
-            surface.fillRect(Common::Rect(endx + 2, starty + gapsize + i * rheight, xres - 1, starty + gapsize + (i + 1) * rheight - 1), WHITE);
+            boxColor(surface, 0, starty + gapsize + i * rheight, startx - 2, starty + gapsize + (i + 1) * rheight - 1, WHITE);
+            boxColor(surface, endx + 2, starty + gapsize + i * rheight, xres - 1, starty + gapsize + (i + 1) * rheight - 1, WHITE);
         }
 
     }
     for (i = 0; i < xsquares * 2 + 1; i++) {
         if (i % 2 == 0) {
-            surface.fillRect(Common::Rect(startx + gapsize + i * rwidth, 0, startx + gapsize + (i + 1) * rwidth - 1, starty - 2), WHITE);
-            surface.fillRect(Common::Rect(startx + gapsize + i * rwidth, endy + 2, startx + gapsize + (i + 1) * rwidth - 1, yres - 1), WHITE);
+            boxColor(surface, startx + gapsize + i * rwidth, 0, startx + gapsize + (i + 1) * rwidth - 1, starty - 2, WHITE);
+            boxColor(surface, startx + gapsize + i * rwidth, endy + 2, startx + gapsize + (i + 1) * rwidth - 1, yres - 1, WHITE);
         }
 
     }
@@ -3835,15 +3841,15 @@ static void drawTestScreen() {
     int y2 = y1 + (monosize * 2 - 1) * rheight - gapsize - 1;   //bottom
 
     if (xsquares - 1 > monosize) {
-        surface.fillRect(Common::Rect(x1, y1, x1 + width - 1, yres / 2), GREEN1);    //up left
-        surface.fillRect(Common::Rect(x2 - width + 1, y1, x2, yres / 2), GREEN2);    //up right
-        surface.fillRect(Common::Rect(x1, yres / 2 + yres % 2, x1 + width - 1, y2), RED1); //bottom left
-        surface.fillRect(Common::Rect(x2 - width + 1, yres / 2 + yres % 2, x2, y2), BLUE1); //bottom right
+        boxColor(surface, x1, y1, x1 + width - 1, yres / 2, GREEN1);    //up left
+        boxColor(surface, x2 - width + 1, y1, x2, yres / 2, GREEN2);    //up right
+        boxColor(surface, x1, yres / 2 + yres % 2, x1 + width - 1, y2, RED1); //bottom left
+        boxColor(surface, x2 - width + 1, yres / 2 + yres % 2, x2, y2, BLUE1); //bottom right
         if (monosize > 2) {
-            surface.fillRect(Common::Rect(x1 + width, y1, x1 + rwidth + width - 1, y1 + 2 * rheight - gapsize - 1), BLUE2); //up left small
-            surface.fillRect(Common::Rect(x1 + width, y2 - rheight * 2 + gapsize + 1, x1 + rwidth + width - 1, y2), YELLOW1); //bottom left small
-            surface.fillRect(Common::Rect(x2 - rwidth - width + 1, y1, x2 - width, y1 + 2 * rheight - gapsize - 1), BLUE2); //up right small
-            surface.fillRect(Common::Rect(x2 - rwidth - width + 1, y2 - rheight * 2 + gapsize + 1, x2 - width, y2), YELLOW1); //bottom right small
+            boxColor(surface, x1 + width, y1, x1 + rwidth + width - 1, y1 + 2 * rheight - gapsize - 1, BLUE2); //up left small
+            boxColor(surface, x1 + width, y2 - rheight * 2 + gapsize + 1, x1 + rwidth + width - 1, y2, YELLOW1); //bottom left small
+            boxColor(surface, x2 - rwidth - width + 1, y1, x2 - width, y1 + 2 * rheight - gapsize - 1, BLUE2); //up right small
+            boxColor(surface, x2 - rwidth - width + 1, y2 - rheight * 2 + gapsize + 1, x2 - width, y2, YELLOW1); //bottom right small
         }
     }
 
@@ -3855,37 +3861,39 @@ static void drawTestScreen() {
     }
 
     int monoradius = monosize * rwidth + gapsize;
+	Graphics::Surface monoscope;
+	monoscope.create(xres, yres, Graphics::PixelFormat::createFormatCLUT8());
 
     // two bottom rows
-    surface.fillRect(Common::Rect(x1, y2 - rheight + gapsize / 2 + 1, x2, y2 + rheight + gapsize / 2 + 1), YELLOW);
-    surface.fillRect(Common::Rect(xcenter - rwidth / 2, y2 - rheight + gapsize / 2 + 1, xcenter - rwidth / 2 + rwidth, y2 + rheight + gapsize / 2 + 1), RED2);
+    boxColor(monoscope, x1, y2 - rheight + gapsize / 2 + 1, x2, y2 + rheight + gapsize / 2 + 1, YELLOW);
+    boxColor(monoscope, xcenter - rwidth / 2, y2 - rheight + gapsize / 2 + 1, xcenter - rwidth / 2 + rwidth, y2 + rheight + gapsize / 2 + 1, RED2);
 
-    surface.fillRect(Common::Rect(x1, y2 - 2 * rheight + gapsize / 2 + 1, x2, y2 - rheight + gapsize / 2), WHITE);
-    surface.fillRect(Common::Rect(xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight + gapsize / 2), BLACK);
+    boxColor(monoscope, x1, y2 - 2 * rheight + gapsize / 2 + 1, x2, y2 - rheight + gapsize / 2, WHITE);
+    boxColor(monoscope, xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight + gapsize / 2, BLACK);
 
     // two top rows
-    surface.fillRect(Common::Rect(x1, y2 - 12 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 10 + gapsize / 2), WHITE);
-    surface.fillRect(Common::Rect(xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 2, y2 - rheight * 10 + gapsize / 2), BLACK);
+    boxColor(monoscope, x1, y2 - 12 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 10 + gapsize / 2, WHITE);
+    boxColor(monoscope, xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 2, y2 - rheight * 10 + gapsize / 2, BLACK);
 
-    surface.fillRect(Common::Rect(x1, y2 - 10 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 9 + gapsize / 2), BLACK);
-    surface.fillRect(Common::Rect(xres / 2 - rwidth * 3, y2 - 10 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight * 9 + gapsize / 2), WHITE);
+    boxColor(monoscope, x1, y2 - 10 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 9 + gapsize / 2, BLACK);
+    boxColor(monoscope, xres / 2 - rwidth * 3, y2 - 10 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight * 9 + gapsize / 2, WHITE);
 
     // color (gray) bars
     int greyColors[] = { BLACK, GRAY2, GRAY3, GRAY4, GRAY5, WHITE};
-    drawRow(surface, y2 - 3 * rheight + gapsize / 2 + 1, greyColors, 6, 0, rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
+    drawRow(monoscope, y2 - 3 * rheight + gapsize / 2 + 1, greyColors, 6, 0, rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
 
-    surface.fillRect(Common::Rect(x1, y2 - 6 * rheight + gapsize / 2 + 1, x2, y2 - 3 * rheight + gapsize / 2), BLACK);
+    boxColor(monoscope, x1, y2 - 6 * rheight + gapsize / 2 + 1, x2, y2 - 3 * rheight + gapsize / 2, BLACK);
 
     int topColors[] = { YELLOW, CYAN, GREEN, MAGENTA, RED, BLUE };
-    drawRow(surface, y2 - 8 * rheight + gapsize / 2 + 1, topColors, 6, 0, 2 * rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
+    drawRow(monoscope, y2 - 8 * rheight + gapsize / 2 + 1, topColors, 6, 0, 2 * rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
 
     // periodic gray and white
     int periodsize = monosize * (rwidth * 2) * 11 / 16 / 6;
     int blacksize = periodsize * 6 / 11;
-    surface.fillRect(Common::Rect(x1, y2 - 9 * rheight + gapsize / 2 + 1, x2, y2 - 8 * rheight + gapsize / 2), GRAY6);
+    boxColor(monoscope, x1, y2 - 9 * rheight + gapsize / 2 + 1, x2, y2 - 8 * rheight + gapsize / 2, GRAY6);
     for (i = 0; i < 5; i++) {
-        surface.fillRect(Common::Rect(xres / 2 + i * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 + i * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2), BLACK);
-        surface.fillRect(Common::Rect(xres / 2 - (i + 1) * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 - (i + 1) * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2), BLACK);
+        boxColor(monoscope, xres / 2 + i * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 + i * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2, BLACK);
+        boxColor(monoscope, xres / 2 - (i + 1) * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 - (i + 1) * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2, BLACK);
     }
 
     // small lines
@@ -3896,36 +3904,55 @@ static void drawTestScreen() {
     int blackorwhite = 0;
     for (i = xmin; i < xmax; i++) {
         step = 6 * (xmax - i - 1) / (xmax - xmin) + 1;
-        surface.fillRect(Common::Rect(i, y2 - 5 * rheight + gapsize / 2 + 1, i + step - 1, y2 - 3 * rheight + gapsize / 2), alternatingColors[blackorwhite++ % 2]);
+        boxColor(monoscope, i, y2 - 5 * rheight + gapsize / 2 + 1, i + step - 1, y2 - 3 * rheight + gapsize / 2, alternatingColors[blackorwhite++ % 2]);
         i += step - 1;
     }
 
     // horizontal middle part
-    surface.fillRect(Common::Rect(xcenter - rwidth / 2, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2 + xres % 2 + rwidth / 2 - 1, y2 - 4 * rheight + gapsize / 2), BLACK);
-    surface.fillRect(Common::Rect(xres / 2 + xres % 2 - 1, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2, y2 - 4 * rheight + gapsize / 2), WHITE);
-    surface.fillRect(Common::Rect(x1, yres / 2 + yres % 2 - 1, x2, yres / 2), WHITE);
+    boxColor(monoscope, xcenter - rwidth / 2, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2 + xres % 2 + rwidth / 2 - 1, y2 - 4 * rheight + gapsize / 2, BLACK);
+    boxColor(monoscope, xres / 2 + xres % 2 - 1, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2, y2 - 4 * rheight + gapsize / 2, WHITE);
+    boxColor(monoscope, x1, yres / 2 + yres % 2 - 1, x2, yres / 2, WHITE);
 
     // vertical lines in the middle
     for (i = x1 - gapsize; i < x2 + gapsize; i += rwidth) {
-        surface.fillRect(Common::Rect(i, y2 - 6 * rheight + gapsize / 2 + 1, i + gapsize - 1, y2 - 5 * rheight + gapsize / 2), WHITE);
+        boxColor(monoscope, i, y2 - 6 * rheight + gapsize / 2 + 1, i + gapsize - 1, y2 - 5 * rheight + gapsize / 2, WHITE);
     }
 
-    circleColorNoblend(surface, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, 3, WHITE, false);
-    circleColorNoblend(surface, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, monoradius, BLACK, true);
+    circleColorNoblend(monoscope, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, 3, WHITE, false);
+    circleColorNoblend(monoscope, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, monoradius, TRANSCOLOR, true);
 
-    //stringtobox(surface, xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 2, y2 - rheight * 10 + gapsize / 2, settings.text_top, WHITE);
-    //stringtobox(surface, xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight + gapsize / 2, settings.text_bottom, WHITE);
+	for (int y = 0; y < yres; y++) {
+		byte *src = (byte *)monoscope.getBasePtr(0, y);
+		byte *dst = (byte *)surface.getBasePtr(0, y);
 
-	g_system->copyRectToScreen(surface.getPixels(), surface.pitch, 0, 0, xres, yres);
+		for (int x = 0; x < xres; x++) {
+			if (*src != TRANSCOLOR)
+				*dst = *src;
+
+			dst++, src++;
+		}
+	}
+
+	monoscope.free();
 
+	Graphics::AmigaFont font;
+
+	y2 += (rheight - font.getFontHeight()) / 2;
+
+    font.drawString(&surface, "ScummVM", xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, rwidth * 4, WHITE, Graphics::kTextAlignCenter);
+    font.drawString(&surface, gScummVMVersion, xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, rwidth * 6, WHITE);
+
+	g_system->copyRectToScreen(surface.getPixels(), surface.pitch, 0, 0, xres, yres);
 	g_system->updateScreen();
+
+	surface.free();
 }
 
 bool OptionsDialog::testGraphicsSettings() {
 	drawTestScreen();
 
 	// And display the error
-	GUI::CountdownMessageDialog dialog(_("Your shader scaler setting has been changed. Do you want to keep these settings?"),
+	GUI::CountdownMessageDialog dialog(_("Your shader scaler setting has been changed. A test screen must be visible now. Do you want to keep these settings?"),
 				10000,
 				_("Yes"), _("No"), Graphics::kTextAlignCenter,
 				_("Reverting in %d seconds"));
@@ -3936,6 +3963,10 @@ bool OptionsDialog::testGraphicsSettings() {
 
 	g_gui.displayTopDialogOnly(false);
 
+	// Clear screen so we do not see any artefacts
+	g_system->fillScreen(BLACK);
+	g_system->updateScreen();
+
 	return retval;
 }
 


Commit: 2fd53a9bae584a92d9c21cb999e0375731c36d7a
    https://github.com/scummvm/scummvm/commit/2fd53a9bae584a92d9c21cb999e0375731c36d7a
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
JANITORIAL: Whitespace fixes

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index f4ea71c702e..cdc07910f5f 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -3696,62 +3696,62 @@ static void boxColor(Graphics::Surface &surface, int x1, int y1, int x2, int y2,
 }
 
 static void squaremesh(Graphics::Surface &surface, int xres, int yres, int width, int height, int gapsize, int meshcolor, int squarecolor) {
-    int centerx = xres / 2;
-    int centery = yres / 2;
+	int centerx = xres / 2;
+	int centery = yres / 2;
 
-    boxColor(surface, 0, 0, xres, yres, squarecolor);
-    for (int x = centerx % (width + gapsize) + width / 2 - (width + gapsize); x < xres; x += gapsize + width) {
-        boxColor(surface, x, 0, x + gapsize - 1, yres - 1, meshcolor);
-    }
-    for (int y = centery % (height + gapsize) + height / 2 - (height + gapsize); y < yres; y += gapsize + height) {
-        boxColor(surface, 0, y, xres - 1, y + gapsize - 1, meshcolor);
-    }
+	boxColor(surface, 0, 0, xres, yres, squarecolor);
+	for (int x = centerx % (width + gapsize) + width / 2 - (width + gapsize); x < xres; x += gapsize + width) {
+		boxColor(surface, x, 0, x + gapsize - 1, yres - 1, meshcolor);
+	}
+	for (int y = centery % (height + gapsize) + height / 2 - (height + gapsize); y < yres; y += gapsize + height) {
+		boxColor(surface, 0, y, xres - 1, y + gapsize - 1, meshcolor);
+	}
 }
 
 static void frame(Graphics::Surface &surface, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int color) {
-    boxColor(surface, x1, y1, x2, y3, color);   //top
-    boxColor(surface, x1, y4, x2, y2, color);   //bottom
-    boxColor(surface, x1, y1, x3, y2, color);   //left
-    boxColor(surface, x4, y1, x2, y2, color);   //right
+	boxColor(surface, x1, y1, x2, y3, color);   //top
+	boxColor(surface, x1, y4, x2, y2, color);   //bottom
+	boxColor(surface, x1, y1, x3, y2, color);   //left
+	boxColor(surface, x4, y1, x2, y2, color);   //right
 }
 
 static void drawRow(Graphics::Surface &surface, int offsety, int colors[], int numColors, int gap, int vsize, int xres, int offsetx) {
-    int boxsize;
-    int x;
-    boxsize = (xres - (numColors + 1) * gap) / numColors;   //-gaps between boxes
-    offsetx += gap + 1;
-    for (x = 0; x < numColors; x++) {
-        boxColor(surface, offsetx, offsety, offsetx + boxsize - 1, offsety + vsize - 1, colors[x]);
-        offsetx += (boxsize + gap);
-    }
+	int boxsize;
+	int x;
+	boxsize = (xres - (numColors + 1) * gap) / numColors;   //-gaps between boxes
+	offsetx += gap + 1;
+	for (x = 0; x < numColors; x++) {
+		boxColor(surface, offsetx, offsety, offsetx + boxsize - 1, offsety + vsize - 1, colors[x]);
+		offsetx += (boxsize + gap);
+	}
 }
 
 static void circleColorNoblend(Graphics::Surface &surface, double x, double y, double r, int color, bool invert) {
-    int sx;
-
-    r += 0.49;
-    for (sx = (int)round(x - r); sx < (int)round(x + r) + 1; sx++) {
-        double h = sqrt(r * r - pow(sx - x, 2));
-        if (invert) {
-            surface.vLine(sx, 0, -1 + (int)ceil(y - h), color);
-            surface.vLine(sx, 1 + (int)floor(y + h), surface.h, color);
-        } else
-            surface.vLine(sx, (int)ceil(y - h), (int)floor(y + h), color);
-    }
-    if (invert && sx < surface.w)
-        boxColor(surface, sx, 0, surface.w - 1, surface.h - 1, color);
-    if (invert && (int)round(x - r) > 0)
-        boxColor(surface, 0, 0, -1 + (int)round(x - r), surface.h - 1, color);
+	int sx;
+
+	r += 0.49;
+	for (sx = (int)round(x - r); sx < (int)round(x + r) + 1; sx++) {
+		double h = sqrt(r * r - pow(sx - x, 2));
+		if (invert) {
+			surface.vLine(sx, 0, -1 + (int)ceil(y - h), color);
+			surface.vLine(sx, 1 + (int)floor(y + h), surface.h, color);
+		} else
+			surface.vLine(sx, (int)ceil(y - h), (int)floor(y + h), color);
+	}
+	if (invert && sx < surface.w)
+		boxColor(surface, sx, 0, surface.w - 1, surface.h - 1, color);
+	if (invert && (int)round(x - r) > 0)
+		boxColor(surface, 0, 0, -1 + (int)round(x - r), surface.h - 1, color);
 }
 
 static void blacksquareinwhitecircle(Graphics::Surface &surface, int x1, int y1, int gapsize, int rwidth, int rheight) {
-    double c1y = y1 - (gapsize + 1.0) / 2.0;
-    double c1x = x1 - (gapsize + 1.0) / 2.0;
-    circleColorNoblend(surface, c1x, c1y, rwidth * 1.5, WHITE, false);
-    boxColor(surface, x1 - rwidth - gapsize, y1 - rheight - gapsize, x1 + rwidth - 1, y1 + rheight - 1, BLACK);
-    boxColor(surface, x1 - rwidth - gapsize, y1 - gapsize, x1 + rwidth - 1, y1 - 1, WHITE);
-    boxColor(surface, x1 - gapsize, y1 - rheight - gapsize, x1 - 1, y1 + rheight - 1, WHITE);
-    circleColorNoblend(surface, c1x, c1y, gapsize + 1, WHITE, false);
+	double c1y = y1 - (gapsize + 1.0) / 2.0;
+	double c1x = x1 - (gapsize + 1.0) / 2.0;
+	circleColorNoblend(surface, c1x, c1y, rwidth * 1.5, WHITE, false);
+	boxColor(surface, x1 - rwidth - gapsize, y1 - rheight - gapsize, x1 + rwidth - 1, y1 + rheight - 1, BLACK);
+	boxColor(surface, x1 - rwidth - gapsize, y1 - gapsize, x1 + rwidth - 1, y1 - 1, WHITE);
+	boxColor(surface, x1 - gapsize, y1 - rheight - gapsize, x1 - 1, y1 + rheight - 1, WHITE);
+	circleColorNoblend(surface, c1x, c1y, gapsize + 1, WHITE, false);
 }
 
 static void drawTestScreen() {
@@ -3766,7 +3766,7 @@ static void drawTestScreen() {
 	for (int i = 0; i < ARRAYSIZE(paletteSrc); i++) {
 		palette[i * 3 + 0] = (paletteSrc[i] >> 16) & 0xFF;
 		palette[i * 3 + 1] = (paletteSrc[i] >>  8) & 0xFF;
-		palette[i * 3 + 2] = (paletteSrc[i]      ) & 0xFF;
+		palette[i * 3 + 2] = (paletteSrc[i]	     ) & 0xFF;
 	}
 
 	g_system->getPaletteManager()->setPalette(palette, 0, ARRAYSIZE(palette) / 3);
@@ -3776,150 +3776,150 @@ static void drawTestScreen() {
 	surface.create(xres, yres, Graphics::PixelFormat::createFormatCLUT8());
 	surface.fillRect(Common::Rect(0, 0, xres, yres), 0);
 
-    int squaresize = 8;
-    int gapsize = 2;
-
-    int width, height;
-    int rwidth, rheight;
-    int xsquares, ysquares;
-
-    int xcenter = xres / 2 - xres % 2;
-
-    bool cont = true;
-    while (cont) {
-
-        if (squaresize > 8) {
-            if (xsquares < 6 || ysquares < 6) {
-                squaresize -= 4;
-                cont = false;
-            }
-        }
-
-        squaresize += 2;
-
-        width = xres % 2 + squaresize;
-        height = yres % 2 + squaresize;
-
-        rwidth = width + gapsize;
-        rheight = height + gapsize;
-
-        xsquares = (xres - rwidth - gapsize - 16) / rwidth / 2;
-        ysquares = (yres - rheight - gapsize - 16) / rheight / 2;
-
-    }
-
-    squaremesh(surface, xres, yres, width, height, gapsize, WHITE, GRAY1);
-
-    int startx = xres / 2 - width / 2 - width % 2 - xsquares * rwidth - gapsize - 1;
-    int starty = yres / 2 - height / 2 - height % 2 - ysquares * rheight - gapsize - 1;
-    int endx = startx + rwidth * (2 * xsquares + 1) + gapsize + 1;
-    int endy = starty + rheight * (2 * ysquares + 1) + gapsize + 1;
-    int i;
-
-    frame(surface, 0, 0, xres, yres, 1, 1, xres - 2, yres - 2, WHITE);
-    frame(surface, 2, 2, xres - 3, yres - 3, startx, starty, endx, endy, BLACK);
-
-    for (i = 0; i < ysquares * 2 + 1; i++) {
-        if (i % 2 == 0) {
-            boxColor(surface, 0, starty + gapsize + i * rheight, startx - 2, starty + gapsize + (i + 1) * rheight - 1, WHITE);
-            boxColor(surface, endx + 2, starty + gapsize + i * rheight, xres - 1, starty + gapsize + (i + 1) * rheight - 1, WHITE);
-        }
-
-    }
-    for (i = 0; i < xsquares * 2 + 1; i++) {
-        if (i % 2 == 0) {
-            boxColor(surface, startx + gapsize + i * rwidth, 0, startx + gapsize + (i + 1) * rwidth - 1, starty - 2, WHITE);
-            boxColor(surface, startx + gapsize + i * rwidth, endy + 2, startx + gapsize + (i + 1) * rwidth - 1, yres - 1, WHITE);
-        }
-
-    }
-
-    int monosize = 6;
-    int x1 = xres / 2 - width / 2 - width % 2 - rwidth * monosize - rwidth; //left
-    int y1 = yres / 2 - height / 2 - height % 2 - rheight * (monosize - 1); //up
-    int x2 = x1 + rwidth * (monosize * 2 + 2) + width - 1;  //right
-    int y2 = y1 + (monosize * 2 - 1) * rheight - gapsize - 1;   //bottom
-
-    if (xsquares - 1 > monosize) {
-        boxColor(surface, x1, y1, x1 + width - 1, yres / 2, GREEN1);    //up left
-        boxColor(surface, x2 - width + 1, y1, x2, yres / 2, GREEN2);    //up right
-        boxColor(surface, x1, yres / 2 + yres % 2, x1 + width - 1, y2, RED1); //bottom left
-        boxColor(surface, x2 - width + 1, yres / 2 + yres % 2, x2, y2, BLUE1); //bottom right
-        if (monosize > 2) {
-            boxColor(surface, x1 + width, y1, x1 + rwidth + width - 1, y1 + 2 * rheight - gapsize - 1, BLUE2); //up left small
-            boxColor(surface, x1 + width, y2 - rheight * 2 + gapsize + 1, x1 + rwidth + width - 1, y2, YELLOW1); //bottom left small
-            boxColor(surface, x2 - rwidth - width + 1, y1, x2 - width, y1 + 2 * rheight - gapsize - 1, BLUE2); //up right small
-            boxColor(surface, x2 - rwidth - width + 1, y2 - rheight * 2 + gapsize + 1, x2 - width, y2, YELLOW1); //bottom right small
-        }
-    }
-
-    if (xsquares - 4 > monosize) {
-        blacksquareinwhitecircle(surface, x1 - rwidth * 2, y1 + rheight, gapsize, rwidth, rheight);
-        blacksquareinwhitecircle(surface, x2 + rwidth * 2 + gapsize + 1, y1 + rheight, gapsize, rwidth, rheight);
-        blacksquareinwhitecircle(surface, x1 - rwidth * 2, y2 - height + 1, gapsize, rwidth, rheight);
-        blacksquareinwhitecircle(surface, x2 + rwidth * 2 + gapsize + 1, y2 - height + 1, gapsize, rwidth, rheight);
-    }
-
-    int monoradius = monosize * rwidth + gapsize;
+	int squaresize = 8;
+	int gapsize = 2;
+
+	int width, height;
+	int rwidth, rheight;
+	int xsquares, ysquares;
+
+	int xcenter = xres / 2 - xres % 2;
+
+	bool cont = true;
+	while (cont) {
+
+		if (squaresize > 8) {
+			if (xsquares < 6 || ysquares < 6) {
+				squaresize -= 4;
+				cont = false;
+			}
+		}
+
+		squaresize += 2;
+
+		width = xres % 2 + squaresize;
+		height = yres % 2 + squaresize;
+
+		rwidth = width + gapsize;
+		rheight = height + gapsize;
+
+		xsquares = (xres - rwidth - gapsize - 16) / rwidth / 2;
+		ysquares = (yres - rheight - gapsize - 16) / rheight / 2;
+
+	}
+
+	squaremesh(surface, xres, yres, width, height, gapsize, WHITE, GRAY1);
+
+	int startx = xres / 2 - width / 2 - width % 2 - xsquares * rwidth - gapsize - 1;
+	int starty = yres / 2 - height / 2 - height % 2 - ysquares * rheight - gapsize - 1;
+	int endx = startx + rwidth * (2 * xsquares + 1) + gapsize + 1;
+	int endy = starty + rheight * (2 * ysquares + 1) + gapsize + 1;
+	int i;
+
+	frame(surface, 0, 0, xres, yres, 1, 1, xres - 2, yres - 2, WHITE);
+	frame(surface, 2, 2, xres - 3, yres - 3, startx, starty, endx, endy, BLACK);
+
+	for (i = 0; i < ysquares * 2 + 1; i++) {
+		if (i % 2 == 0) {
+			boxColor(surface, 0, starty + gapsize + i * rheight, startx - 2, starty + gapsize + (i + 1) * rheight - 1, WHITE);
+			boxColor(surface, endx + 2, starty + gapsize + i * rheight, xres - 1, starty + gapsize + (i + 1) * rheight - 1, WHITE);
+		}
+
+	}
+	for (i = 0; i < xsquares * 2 + 1; i++) {
+		if (i % 2 == 0) {
+			boxColor(surface, startx + gapsize + i * rwidth, 0, startx + gapsize + (i + 1) * rwidth - 1, starty - 2, WHITE);
+			boxColor(surface, startx + gapsize + i * rwidth, endy + 2, startx + gapsize + (i + 1) * rwidth - 1, yres - 1, WHITE);
+		}
+
+	}
+
+	int monosize = 6;
+	int x1 = xres / 2 - width / 2 - width % 2 - rwidth * monosize - rwidth; //left
+	int y1 = yres / 2 - height / 2 - height % 2 - rheight * (monosize - 1); //up
+	int x2 = x1 + rwidth * (monosize * 2 + 2) + width - 1;  //right
+	int y2 = y1 + (monosize * 2 - 1) * rheight - gapsize - 1;   //bottom
+
+	if (xsquares - 1 > monosize) {
+		boxColor(surface, x1, y1, x1 + width - 1, yres / 2, GREEN1);	//up left
+		boxColor(surface, x2 - width + 1, y1, x2, yres / 2, GREEN2);	//up right
+		boxColor(surface, x1, yres / 2 + yres % 2, x1 + width - 1, y2, RED1); //bottom left
+		boxColor(surface, x2 - width + 1, yres / 2 + yres % 2, x2, y2, BLUE1); //bottom right
+		if (monosize > 2) {
+			boxColor(surface, x1 + width, y1, x1 + rwidth + width - 1, y1 + 2 * rheight - gapsize - 1, BLUE2); //up left small
+			boxColor(surface, x1 + width, y2 - rheight * 2 + gapsize + 1, x1 + rwidth + width - 1, y2, YELLOW1); //bottom left small
+			boxColor(surface, x2 - rwidth - width + 1, y1, x2 - width, y1 + 2 * rheight - gapsize - 1, BLUE2); //up right small
+			boxColor(surface, x2 - rwidth - width + 1, y2 - rheight * 2 + gapsize + 1, x2 - width, y2, YELLOW1); //bottom right small
+		}
+	}
+
+	if (xsquares - 4 > monosize) {
+		blacksquareinwhitecircle(surface, x1 - rwidth * 2, y1 + rheight, gapsize, rwidth, rheight);
+		blacksquareinwhitecircle(surface, x2 + rwidth * 2 + gapsize + 1, y1 + rheight, gapsize, rwidth, rheight);
+		blacksquareinwhitecircle(surface, x1 - rwidth * 2, y2 - height + 1, gapsize, rwidth, rheight);
+		blacksquareinwhitecircle(surface, x2 + rwidth * 2 + gapsize + 1, y2 - height + 1, gapsize, rwidth, rheight);
+	}
+
+	int monoradius = monosize * rwidth + gapsize;
 	Graphics::Surface monoscope;
 	monoscope.create(xres, yres, Graphics::PixelFormat::createFormatCLUT8());
 
-    // two bottom rows
-    boxColor(monoscope, x1, y2 - rheight + gapsize / 2 + 1, x2, y2 + rheight + gapsize / 2 + 1, YELLOW);
-    boxColor(monoscope, xcenter - rwidth / 2, y2 - rheight + gapsize / 2 + 1, xcenter - rwidth / 2 + rwidth, y2 + rheight + gapsize / 2 + 1, RED2);
-
-    boxColor(monoscope, x1, y2 - 2 * rheight + gapsize / 2 + 1, x2, y2 - rheight + gapsize / 2, WHITE);
-    boxColor(monoscope, xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight + gapsize / 2, BLACK);
-
-    // two top rows
-    boxColor(monoscope, x1, y2 - 12 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 10 + gapsize / 2, WHITE);
-    boxColor(monoscope, xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 2, y2 - rheight * 10 + gapsize / 2, BLACK);
-
-    boxColor(monoscope, x1, y2 - 10 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 9 + gapsize / 2, BLACK);
-    boxColor(monoscope, xres / 2 - rwidth * 3, y2 - 10 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight * 9 + gapsize / 2, WHITE);
-
-    // color (gray) bars
-    int greyColors[] = { BLACK, GRAY2, GRAY3, GRAY4, GRAY5, WHITE};
-    drawRow(monoscope, y2 - 3 * rheight + gapsize / 2 + 1, greyColors, 6, 0, rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
-
-    boxColor(monoscope, x1, y2 - 6 * rheight + gapsize / 2 + 1, x2, y2 - 3 * rheight + gapsize / 2, BLACK);
-
-    int topColors[] = { YELLOW, CYAN, GREEN, MAGENTA, RED, BLUE };
-    drawRow(monoscope, y2 - 8 * rheight + gapsize / 2 + 1, topColors, 6, 0, 2 * rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
-
-    // periodic gray and white
-    int periodsize = monosize * (rwidth * 2) * 11 / 16 / 6;
-    int blacksize = periodsize * 6 / 11;
-    boxColor(monoscope, x1, y2 - 9 * rheight + gapsize / 2 + 1, x2, y2 - 8 * rheight + gapsize / 2, GRAY6);
-    for (i = 0; i < 5; i++) {
-        boxColor(monoscope, xres / 2 + i * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 + i * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2, BLACK);
-        boxColor(monoscope, xres / 2 - (i + 1) * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 - (i + 1) * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2, BLACK);
-    }
-
-    // small lines
-    int xmin = xcenter - rwidth / 2 - rwidth * 4;
-    int xmax = xcenter - rwidth / 2 + rwidth * 5;
-    int step;
-    int alternatingColors[] = { WHITE, BLACK };
-    int blackorwhite = 0;
-    for (i = xmin; i < xmax; i++) {
-        step = 6 * (xmax - i - 1) / (xmax - xmin) + 1;
-        boxColor(monoscope, i, y2 - 5 * rheight + gapsize / 2 + 1, i + step - 1, y2 - 3 * rheight + gapsize / 2, alternatingColors[blackorwhite++ % 2]);
-        i += step - 1;
-    }
-
-    // horizontal middle part
-    boxColor(monoscope, xcenter - rwidth / 2, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2 + xres % 2 + rwidth / 2 - 1, y2 - 4 * rheight + gapsize / 2, BLACK);
-    boxColor(monoscope, xres / 2 + xres % 2 - 1, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2, y2 - 4 * rheight + gapsize / 2, WHITE);
-    boxColor(monoscope, x1, yres / 2 + yres % 2 - 1, x2, yres / 2, WHITE);
-
-    // vertical lines in the middle
-    for (i = x1 - gapsize; i < x2 + gapsize; i += rwidth) {
-        boxColor(monoscope, i, y2 - 6 * rheight + gapsize / 2 + 1, i + gapsize - 1, y2 - 5 * rheight + gapsize / 2, WHITE);
-    }
-
-    circleColorNoblend(monoscope, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, 3, WHITE, false);
-    circleColorNoblend(monoscope, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, monoradius, TRANSCOLOR, true);
+	// two bottom rows
+	boxColor(monoscope, x1, y2 - rheight + gapsize / 2 + 1, x2, y2 + rheight + gapsize / 2 + 1, YELLOW);
+	boxColor(monoscope, xcenter - rwidth / 2, y2 - rheight + gapsize / 2 + 1, xcenter - rwidth / 2 + rwidth, y2 + rheight + gapsize / 2 + 1, RED2);
+
+	boxColor(monoscope, x1, y2 - 2 * rheight + gapsize / 2 + 1, x2, y2 - rheight + gapsize / 2, WHITE);
+	boxColor(monoscope, xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight + gapsize / 2, BLACK);
+
+	// two top rows
+	boxColor(monoscope, x1, y2 - 12 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 10 + gapsize / 2, WHITE);
+	boxColor(monoscope, xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 2, y2 - rheight * 10 + gapsize / 2, BLACK);
+
+	boxColor(monoscope, x1, y2 - 10 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 9 + gapsize / 2, BLACK);
+	boxColor(monoscope, xres / 2 - rwidth * 3, y2 - 10 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight * 9 + gapsize / 2, WHITE);
+
+	// color (gray) bars
+	int greyColors[] = { BLACK, GRAY2, GRAY3, GRAY4, GRAY5, WHITE};
+	drawRow(monoscope, y2 - 3 * rheight + gapsize / 2 + 1, greyColors, 6, 0, rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
+
+	boxColor(monoscope, x1, y2 - 6 * rheight + gapsize / 2 + 1, x2, y2 - 3 * rheight + gapsize / 2, BLACK);
+
+	int topColors[] = { YELLOW, CYAN, GREEN, MAGENTA, RED, BLUE };
+	drawRow(monoscope, y2 - 8 * rheight + gapsize / 2 + 1, topColors, 6, 0, 2 * rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
+
+	// periodic gray and white
+	int periodsize = monosize * (rwidth * 2) * 11 / 16 / 6;
+	int blacksize = periodsize * 6 / 11;
+	boxColor(monoscope, x1, y2 - 9 * rheight + gapsize / 2 + 1, x2, y2 - 8 * rheight + gapsize / 2, GRAY6);
+	for (i = 0; i < 5; i++) {
+		boxColor(monoscope, xres / 2 + i * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 + i * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2, BLACK);
+		boxColor(monoscope, xres / 2 - (i + 1) * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 - (i + 1) * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2, BLACK);
+	}
+
+	// small lines
+	int xmin = xcenter - rwidth / 2 - rwidth * 4;
+	int xmax = xcenter - rwidth / 2 + rwidth * 5;
+	int step;
+	int alternatingColors[] = { WHITE, BLACK };
+	int blackorwhite = 0;
+	for (i = xmin; i < xmax; i++) {
+		step = 6 * (xmax - i - 1) / (xmax - xmin) + 1;
+		boxColor(monoscope, i, y2 - 5 * rheight + gapsize / 2 + 1, i + step - 1, y2 - 3 * rheight + gapsize / 2, alternatingColors[blackorwhite++ % 2]);
+		i += step - 1;
+	}
+
+	// horizontal middle part
+	boxColor(monoscope, xcenter - rwidth / 2, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2 + xres % 2 + rwidth / 2 - 1, y2 - 4 * rheight + gapsize / 2, BLACK);
+	boxColor(monoscope, xres / 2 + xres % 2 - 1, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2, y2 - 4 * rheight + gapsize / 2, WHITE);
+	boxColor(monoscope, x1, yres / 2 + yres % 2 - 1, x2, yres / 2, WHITE);
+
+	// vertical lines in the middle
+	for (i = x1 - gapsize; i < x2 + gapsize; i += rwidth) {
+		boxColor(monoscope, i, y2 - 6 * rheight + gapsize / 2 + 1, i + gapsize - 1, y2 - 5 * rheight + gapsize / 2, WHITE);
+	}
+
+	circleColorNoblend(monoscope, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, 3, WHITE, false);
+	circleColorNoblend(monoscope, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, monoradius, TRANSCOLOR, true);
 
 	for (int y = 0; y < yres; y++) {
 		byte *src = (byte *)monoscope.getBasePtr(0, y);
@@ -3939,8 +3939,8 @@ static void drawTestScreen() {
 
 	y2 += (rheight - font.getFontHeight()) / 2;
 
-    font.drawString(&surface, "ScummVM", xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, rwidth * 4, WHITE, Graphics::kTextAlignCenter);
-    font.drawString(&surface, gScummVMVersion, xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, rwidth * 6, WHITE);
+	font.drawString(&surface, "ScummVM", xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, rwidth * 4, WHITE, Graphics::kTextAlignCenter);
+	font.drawString(&surface, gScummVMVersion, xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, rwidth * 6, WHITE);
 
 	g_system->copyRectToScreen(surface.getPixels(), surface.pitch, 0, 0, xres, yres);
 	g_system->updateScreen();


Commit: 3b1a1f0411cd210c65aa7f339564e11e33ebcb7f
    https://github.com/scummvm/scummvm/commit/3b1a1f0411cd210c65aa7f339564e11e33ebcb7f
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Formatting fixes, added copyright of the original work for test screen

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index cdc07910f5f..626dcd70cfe 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -3639,55 +3639,26 @@ void GlobalOptionsDialog::storageErrorCallback(Networking::ErrorResponse respons
 
 /****************************
  * Shader test screen
+ *
+ * Based on Testcard project (https://sourceforge.net/projects/testcard/)
+ *
+ * Testpattern is a simple monitor test pattern generator
+ * Copyright 2003 Jason Giglio <jgiglio at netmar.com>
+ *
+ * Licensed under GPLv2+
  ****************************/
 
 enum {
-	BLACK = 0,
-	WHITE,
-	RED,
-	GREEN,
-	BLUE,
-	CYAN,
-	MAGENTA,
-	YELLOW,
-	GRAY1,
-	GREEN1,
-	GREEN2,
-	RED1,
-	BLUE1,
-	BLUE2,
-	YELLOW1,
-	RED2,
-	GRAY2,
-	GRAY3,
-	GRAY4,
-	GRAY5,
-	GRAY6,
+	BLACK = 0, WHITE, RED, GREEN, BLUE, CYAN, MAGENTA,
+	YELLOW, GRAY1, GREEN1, GREEN2, RED1, BLUE1, BLUE2,
+	YELLOW1, RED2, GRAY2, GRAY3, GRAY4, GRAY5, GRAY6,
 	TRANSCOLOR,
 };
 
 const uint32 paletteSrc[] = {
-	0x000000,
-	0xffffff,
-	0xFF0000,
-	0x00FF00,
-	0x0000FF,
-	0x00FFFF,
-	0xFF00FF,
-	0xFFFF00,
-	0x7F7F7F,
-	0x00C896,
-	0x649632,
-	0xC83264,
-	0x6464FF,
-	0x6496FF,
-	0xC86400,
-	0xE10000,
-	0x333333,
-	0x666666,
-	0x999999,
-	0xCCCCCC,
-	0xBFBFBF,
+	0x000000, 0xffffff, 0xFF0000, 0x00FF00, 0x0000FF, 0x00FFFF, 0xFF00FF,
+	0xFFFF00, 0x7F7F7F, 0x00C896, 0x649632, 0xC83264, 0x6464FF, 0x6496FF,
+	0xC86400, 0xE10000, 0x333333, 0x666666, 0x999999, 0xCCCCCC, 0xBFBFBF,
 	0xFE00FE,
 };
 
@@ -3716,11 +3687,9 @@ static void frame(Graphics::Surface &surface, int x1, int y1, int x2, int y2, in
 }
 
 static void drawRow(Graphics::Surface &surface, int offsety, int colors[], int numColors, int gap, int vsize, int xres, int offsetx) {
-	int boxsize;
-	int x;
-	boxsize = (xres - (numColors + 1) * gap) / numColors;   //-gaps between boxes
+	int boxsize = (xres - (numColors + 1) * gap) / numColors;   //-gaps between boxes
 	offsetx += gap + 1;
-	for (x = 0; x < numColors; x++) {
+	for (int x = 0; x < numColors; x++) {
 		boxColor(surface, offsetx, offsety, offsetx + boxsize - 1, offsety + vsize - 1, colors[x]);
 		offsetx += (boxsize + gap);
 	}


Commit: 08706d3c0f95d800c97a26872a5c36e99fa6088f
    https://github.com/scummvm/scummvm/commit/08706d3c0f95d800c97a26872a5c36e99fa6088f
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Better wording for the schader test dialog. Courtesy of Thunderforge

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index 626dcd70cfe..c7e9492a2c1 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -3921,10 +3921,10 @@ bool OptionsDialog::testGraphicsSettings() {
 	drawTestScreen();
 
 	// And display the error
-	GUI::CountdownMessageDialog dialog(_("Your shader scaler setting has been changed. A test screen must be visible now. Do you want to keep these settings?"),
+	GUI::CountdownMessageDialog dialog(_("A test screen should be displayed. Do you want to keep these shader scalar settings?"),
 				10000,
 				_("Yes"), _("No"), Graphics::kTextAlignCenter,
-				_("Reverting in %d seconds"));
+				_("Reverting automatically in %d seconds"));
 
 	g_gui.displayTopDialogOnly(true);
 


Commit: 0614eab5de403aac22b8eb5112a39754d26eff20
    https://github.com/scummvm/scummvm/commit/0614eab5de403aac22b8eb5112a39754d26eff20
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Switch test pattern to 320z240 and improve dialog message

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index c7e9492a2c1..5079865c2b0 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -3723,8 +3723,8 @@ static void blacksquareinwhitecircle(Graphics::Surface &surface, int x1, int y1,
 	circleColorNoblend(surface, c1x, c1y, gapsize + 1, WHITE, false);
 }
 
-static void drawTestScreen() {
-	int xres = 640, yres = 480;
+static void drawTestPattern() {
+	int xres = 320, yres = 240;
 
 	g_system->beginGFXTransaction();
 	g_system->initSize(xres, yres);
@@ -3918,10 +3918,10 @@ static void drawTestScreen() {
 }
 
 bool OptionsDialog::testGraphicsSettings() {
-	drawTestScreen();
+	drawTestPattern();
 
 	// And display the error
-	GUI::CountdownMessageDialog dialog(_("A test screen should be displayed. Do you want to keep these shader scalar settings?"),
+	GUI::CountdownMessageDialog dialog(_("A test pattern should be displayed.\nDo you want to keep these shader scalar settings?"),
 				10000,
 				_("Yes"), _("No"), Graphics::kTextAlignCenter,
 				_("Reverting automatically in %d seconds"));


Commit: 2c9731b16acb5a6afde841b0f9f57e46ee8b516b
    https://github.com/scummvm/scummvm/commit/2c9731b16acb5a6afde841b0f9f57e46ee8b516b
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Do not run test when there is no shader

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index 5079865c2b0..6955d13d02e 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -842,7 +842,7 @@ void OptionsDialog::apply() {
 				shader = ConfMan.get("shader", _domain);
 
 			// If shader was change, show the test dialog
-			if (previousShader != shader) {
+			if (previousShader != shader && !shader.empty()) {
 				if (!testGraphicsSettings()) {
 					if (previousShader.empty()) {
 						ConfMan.removeKey("shader", _domain);


Commit: 76dc20b4b504031058328a548bea9b02e69d2929
    https://github.com/scummvm/scummvm/commit/76dc20b4b504031058328a548bea9b02e69d2929
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Fix shader clear button behaviour

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index 6955d13d02e..72ad8a7f3cd 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -823,9 +823,11 @@ void OptionsDialog::apply() {
 				if (previousShader.empty()) {
 					ConfMan.removeKey("shader", _domain);
 					_shader->setLabel(_c("None", "shader"));
+					_shaderClearButton->setEnabled(false);
 				} else {
 					ConfMan.set("shader", previousShader.encode(), _domain);
 					_shader->setLabel(previousShader);
+					_shaderClearButton->setEnabled(true);
 				}
 
 				message += Common::U32String("\n");
@@ -841,15 +843,17 @@ void OptionsDialog::apply() {
 			if (ConfMan.hasKey("shader", _domain))
 				shader = ConfMan.get("shader", _domain);
 
-			// If shader was change, show the test dialog
+			// If shader was changed, show the test dialog
 			if (previousShader != shader && !shader.empty()) {
 				if (!testGraphicsSettings()) {
 					if (previousShader.empty()) {
 						ConfMan.removeKey("shader", _domain);
 						_shader->setLabel(_c("None", "shader"));
+						_shaderClearButton->setEnabled(false);
 					} else {
 						ConfMan.set("shader", previousShader.encode(), _domain);
 						_shader->setLabel(previousShader);
+						_shaderClearButton->setEnabled(true);
 					}
 
 					g_system->beginGFXTransaction();


Commit: ff00d3feea9c27dae949c39c727ad784817b8d07
    https://github.com/scummvm/scummvm/commit/ff00d3feea9c27dae949c39c727ad784817b8d07
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Move shader controls to Graphics tab and hide behind radiobutton

Changed paths:
    gui/editgamedialog.cpp
    gui/editgamedialog.h
    gui/options.cpp
    gui/options.h
    gui/themes/common/highres_layout.stx
    gui/themes/common/lowres_layout.stx


diff --git a/gui/editgamedialog.cpp b/gui/editgamedialog.cpp
index 2aecd2aa24d..62022e2fa87 100644
--- a/gui/editgamedialog.cpp
+++ b/gui/editgamedialog.cpp
@@ -63,7 +63,6 @@ enum {
 	kSearchClearCmd = 'SRCL',
 
 	kCmdGlobalGraphicsOverride = 'OGFX',
-	kCmdGlobalShaderOverride = 'OSHD',
 	kCmdGlobalBackendOverride = 'OBAK',
 	kCmdGlobalAudioOverride = 'OSFX',
 	kCmdGlobalMIDIOverride = 'OMID',
@@ -216,22 +215,6 @@ EditGameDialog::EditGameDialog(const Common::String &domain)
 
 	addGraphicControls(graphicsContainer, "GameOptions_Graphics_Container.");
 
-	//
-	// The shader tab (currently visible only for Vita platform), visibility checking by features
-	//
-
-	_globalShaderOverride = nullptr;
-	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
-		tab->addTab(_("Shader"), "GameOptions_Shader");
-
-		if (g_system->getOverlayWidth() > 320)
-			_globalShaderOverride = new CheckboxWidget(tab, "GameOptions_Shader.EnableTabCheckbox", _("Override global shader settings"), Common::U32String(), kCmdGlobalShaderOverride);
-		else
-			_globalShaderOverride = new CheckboxWidget(tab, "GameOptions_Shader.EnableTabCheckbox", _c("Override global shader settings", "lowres"), Common::U32String(), kCmdGlobalShaderOverride);
-
-		addShaderControls(tab, "GameOptions_Shader.");
-	}
-
 	//
 	// The Keymap tab
 	//
@@ -421,11 +404,6 @@ void EditGameDialog::open() {
 		ConfMan.hasKey("antialiasing", _domain);
 	_globalGraphicsOverride->setState(e);
 
-	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
-		e = ConfMan.hasKey("shader", _domain);
-		_globalShaderOverride->setState(e);
-	}
-
 	if (_backendOptions) {
 		e = _backendOptions->hasKeys();
 		_globalBackendOverride->setState(e);
@@ -531,10 +509,6 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 		setGraphicSettingsState(data != 0);
 		g_gui.scheduleTopDialogRedraw();
 		break;
-	case kCmdGlobalShaderOverride:
-		setShaderSettingsState(data != 0);
-		g_gui.scheduleTopDialogRedraw();
-		break;
 	case kCmdGlobalBackendOverride:
 		_backendOptions->setEnabled(data != 0);
 		g_gui.scheduleTopDialogRedraw();
diff --git a/gui/editgamedialog.h b/gui/editgamedialog.h
index 4e88756c37d..c2076bebe77 100644
--- a/gui/editgamedialog.h
+++ b/gui/editgamedialog.h
@@ -82,7 +82,6 @@ protected:
 	PopUpWidget *_platformPopUp;
 
 	CheckboxWidget *_globalGraphicsOverride;
-	CheckboxWidget *_globalShaderOverride;
 	CheckboxWidget *_globalBackendOverride;
 	CheckboxWidget *_globalAudioOverride;
 	CheckboxWidget *_globalMIDIOverride;
diff --git a/gui/options.cpp b/gui/options.cpp
index 72ad8a7f3cd..6b79c3caa6d 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -102,13 +102,19 @@ enum {
 	kJoystickDeadzoneChanged= 'jodc',
 	kGraphicsTabContainerReflowCmd = 'gtcr',
 	kScalerPopUpCmd			= 'scPU',
-	kFullscreenToggled		= 'oful'
+	kFullscreenToggled		= 'oful',
+	kScalerToggle			= 'sctg',
 };
 
 enum {
 	kSubtitlesSpeech,
 	kSubtitlesSubs,
-	kSubtitlesBoth
+	kSubtitlesBoth,
+};
+
+enum {
+	kScalerScaler,
+	kScalerShader,
 };
 
 #ifdef USE_FLUIDSYNTH
@@ -160,12 +166,12 @@ static const int guiBaseValues[] = { 150, 125, 100, 75, -1 };
 static const char *kbdMouseSpeedLabels[] = { "3", "5", "8", "10", "13", "15", "18", "20", nullptr };
 
 OptionsDialog::OptionsDialog(const Common::String &domain, int x, int y, int w, int h)
-	: Dialog(x, y, w, h), _domain(domain), _graphicsTabId(-1), _shaderTabId(-1), _midiTabId(-1), _pathsTabId(-1), _tabWidget(nullptr) {
+	: Dialog(x, y, w, h), _domain(domain), _graphicsTabId(-1), _midiTabId(-1), _pathsTabId(-1), _tabWidget(nullptr) {
 	init();
 }
 
 OptionsDialog::OptionsDialog(const Common::String &domain, const Common::String &name)
-	: Dialog(name), _domain(domain), _graphicsTabId(-1), _shaderTabId(-1), _midiTabId(-1), _pathsTabId(-1), _tabWidget(nullptr) {
+	: Dialog(name), _domain(domain), _graphicsTabId(-1), _midiTabId(-1), _pathsTabId(-1), _tabWidget(nullptr) {
 	init();
 }
 
@@ -1057,6 +1063,9 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
 		_shaderClearButton->setEnabled(false);
 		g_gui.scheduleTopDialogRedraw();
 		break;
+	case kScalerToggle:
+		setScalerControls();
+		break;
 	case kMidiGainChanged:
 		_midiGainLabel->setLabel(Common::String::format("%.2f", (double)_midiGainSlider->getValue() / 100.0));
 		_midiGainLabel->markAsDirty();
@@ -1480,19 +1489,6 @@ void OptionsDialog::addStatisticsControls(GuiObject *boss, const Common::String
 	}
 }
 
-void OptionsDialog::addShaderControls(GuiObject *boss, const Common::String &prefix) {
-	// Shader selector
-	if (g_system->getOverlayWidth() > 320)
-		_shaderButton = new ButtonWidget(boss, prefix + "grShaderButton", _("Shader Path:"), _("Specifies path to the shaders used for scaling ScummVM"), kChooseShaderCmd);
-	else
-		_shaderButton = new ButtonWidget(boss, prefix + "grShaderButton", _c("Shader Path:", "lowres"), _("Specifies path to the shaders used for scaling ScummVM"), kChooseShaderCmd);
-	_shader = new StaticTextWidget(boss, prefix + "grShader", _c("None", "shader"), _("Specifies path to the shaders used for scaling ScummVM"));
-
-	_shaderClearButton = addClearButton(boss, prefix + "grShaderClearButton", kClearShaderCmd);
-
-	_enableShaderSettings = true;
-}
-
 void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &prefix) {
 	const OSystem::GraphicsMode *gm = g_system->getSupportedGraphicsModes();
 	Common::String context;
@@ -1543,9 +1539,15 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
 		sm++;
 	}
 
+	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
+		_scalerToggleGroup = new RadiobuttonGroup(boss, kScalerToggle);
+
+		_scalerToggleScalers = new RadiobuttonWidget(boss, prefix + "grScalerRadioButton", _scalerToggleGroup, kScalerScaler, Common::U32String(""));
+	}
+
 	// The Scaler popup
 	const PluginList &scalerPlugins = ScalerMan.getPlugins();
-	_scalerPopUpDesc = new StaticTextWidget(boss, prefix + "grScalerPopupDesc", _("Scaler:"));
+	_scalerPopUpDesc = new StaticTextWidget(boss, prefix + "grScalerPopupDesc", _("Use scaler:"));
 	_scalerPopUp = new PopUpWidget(boss, prefix + "grScalerPopup", Common::U32String(), kScalerPopUpCmd);
 
 	_scalerPopUp->appendEntry(_("<default>"));
@@ -1557,6 +1559,20 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
 	_scaleFactorPopUp = new PopUpWidget(boss, prefix + "grScaleFactorPopup");
 	updateScaleFactors(_scalerPopUp->getSelectedTag());
 
+	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
+		_scalerToggleShaders = new RadiobuttonWidget(boss, prefix + "grShaderRadioButton", _scalerToggleGroup, kScalerShader, Common::U32String(""));
+
+		if (g_system->getOverlayWidth() > 320)
+			_shaderButton = new ButtonWidget(boss, prefix + "grShaderButton", _("Use Shader:"), _("Specifies path to the shader used for scaling the game screen"), kChooseShaderCmd);
+		else
+			_shaderButton = new ButtonWidget(boss, prefix + "grShaderButton", _c("Shader Path:", "lowres"), _("Specifies path to the shader used for scaling the game screen"), kChooseShaderCmd);
+		_shader = new StaticTextWidget(boss, prefix + "grShader", _c("None", "shader"), _("Specifies path to the shader used for scaling the game screen"));
+
+		_shaderClearButton = addClearButton(boss, prefix + "grShaderClearButton", kClearShaderCmd);
+
+		_enableShaderSettings = true;
+	}
+
 	// Fullscreen checkbox
 	_fullscreenCheckbox = new CheckboxWidget(boss, prefix + "grFullscreenCheckbox", _("Fullscreen mode"), Common::U32String(), kFullscreenToggled);
 
@@ -1604,6 +1620,26 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
 	_enableGraphicSettings = true;
 }
 
+void OptionsDialog::setScalerControls() {
+	bool scalers, shaders;
+
+	if (_scalerToggleGroup->getValue() == kScalerScaler) {
+		scalers = true;
+		shaders = false;
+	} else {
+		scalers = false;
+		shaders = true;
+	}
+
+	_scalerPopUpDesc->setEnabled(scalers);
+	_scalerPopUp->setEnabled(scalers);
+	_scaleFactorPopUp->setEnabled(scalers);
+
+	_shaderButton->setEnabled(shaders);
+	_shader->setEnabled(shaders);
+	_shaderClearButton->setEnabled(shaders);
+}
+
 void OptionsDialog::addAudioControls(GuiObject *boss, const Common::String &prefix) {
 	// The MIDI mode popup & a label
 	if (g_system->getOverlayWidth() > 320)
@@ -1946,6 +1982,9 @@ void OptionsDialog::setupGraphicsTab() {
 	_renderModePopUpDesc->setVisible(true);
 	_renderModePopUp->setVisible(true);
 
+	_scalerToggleGroup->setValue(kScalerScaler);
+	setScalerControls();
+
 	if (g_system->hasFeature(OSystem::kFeatureScalers)) {
 		_scalerPopUpDesc->setVisible(true);
 		if (ConfMan.isKeyTemporary("scaler") || ConfMan.isKeyTemporary("scale_factor"))
@@ -2094,15 +2133,6 @@ void GlobalOptionsDialog::build() {
 	graphicsContainer->setBackgroundType(ThemeEngine::kWidgetBackgroundNo);
 	addGraphicControls(graphicsContainer, "GlobalOptions_Graphics_Container.");
 
-	//
-	// The shader tab, visibility checking by features
-	//
-
-	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
-		_shaderTabId = tab->addTab(_("Shader"), "GlobalOptions_Shader");
-		addShaderControls(tab, "GlobalOptions_Shader.");
-	}
-
 	//
 	// The control tab (currently visible only for SDL and Vita platform, visibility checking by features
 	//
@@ -3329,17 +3359,6 @@ void GlobalOptionsDialog::reflowLayout() {
 	int firstVisible = _tabWidget->getFirstVisible();
 	int activeTab = _tabWidget->getActiveTab();
 
-	if (_shaderTabId != -1) {
-		_tabWidget->setActiveTab(_shaderTabId);
-
-		bool enabled = _shaderClearButton->isEnabled();
-		_tabWidget->removeWidget(_shaderClearButton);
-		_shaderClearButton->setNext(nullptr);
-		delete _shaderClearButton;
-		_shaderClearButton = addClearButton(_tabWidget, "GlobalOptions_Shader.grShaderClearButton", kClearShaderCmd);
-		_shaderClearButton->setEnabled(enabled);
-	}
-
 	if (_midiTabId != -1) {
 		_tabWidget->setActiveTab(_midiTabId);
 
diff --git a/gui/options.h b/gui/options.h
index 29ef752f977..298b424ccee 100644
--- a/gui/options.h
+++ b/gui/options.h
@@ -79,10 +79,6 @@ protected:
 	/** Config domain this dialog is used to edit. */
 	Common::String _domain;
 
-	ButtonWidget *_shaderButton;
-	StaticTextWidget *_shader;
-	ButtonWidget *_shaderClearButton;
-
 	ButtonWidget *_soundFontButton;
 	StaticTextWidget *_soundFont;
 	ButtonWidget *_soundFontClearButton;
@@ -97,7 +93,6 @@ protected:
 	void addAchievementsControls(GuiObject *boss, const Common::String &prefix);
 	void addStatisticsControls(GuiObject *boss, const Common::String &prefix);
 	void addGraphicControls(GuiObject *boss, const Common::String &prefix);
-	void addShaderControls(GuiObject *boss, const Common::String &prefix);
 	void addAudioControls(GuiObject *boss, const Common::String &prefix);
 	void addMIDIControls(GuiObject *boss, const Common::String &prefix);
 	void addMT32Controls(GuiObject *boss, const Common::String &prefix);
@@ -120,12 +115,16 @@ protected:
 	bool loadMusicDeviceSetting(PopUpWidget *popup, Common::String setting, MusicType preferredType = MT_AUTO);
 	void saveMusicDeviceSetting(PopUpWidget *popup, Common::String setting);
 
+	void setScalerControls();
+
 	TabWidget *_tabWidget;
 	int _graphicsTabId;
-	int _shaderTabId;
 	int _midiTabId;
 	int _pathsTabId;
 
+	StaticTextWidget *_shader;
+	ButtonWidget *_shaderClearButton;
+
 private:
 
 	//
@@ -155,8 +154,12 @@ private:
 	PopUpWidget *_gfxPopUp;
 	StaticTextWidget *_stretchPopUpDesc;
 	PopUpWidget *_stretchPopUp;
+	RadiobuttonGroup *_scalerToggleGroup;
+	RadiobuttonWidget *_scalerToggleScalers;
+	RadiobuttonWidget *_scalerToggleShaders;
 	StaticTextWidget *_scalerPopUpDesc;
 	PopUpWidget *_scalerPopUp, *_scaleFactorPopUp;
+	ButtonWidget *_shaderButton;
 	CheckboxWidget *_fullscreenCheckbox;
 	CheckboxWidget *_filteringCheckbox;
 	CheckboxWidget *_aspectCheckbox;
diff --git a/gui/themes/common/highres_layout.stx b/gui/themes/common/highres_layout.stx
index a690b19e86f..41bd2ecf4ac 100644
--- a/gui/themes/common/highres_layout.stx
+++ b/gui/themes/common/highres_layout.stx
@@ -489,6 +489,10 @@
 				/>
 			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
+				<widget name = 'grScalerRadioButton'
+						type = 'Radiobutton'
+						width = '20'
+				/>
 				<widget name = 'grScalerPopupDesc'
 						type = 'OptionsLabel'
 				/>
@@ -499,6 +503,22 @@
 						type = 'PopUp'
 				/>
 			</layout>
+			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
+				<widget name = 'grShaderRadioButton'
+						type = 'Radiobutton'
+						width = '20'
+				/>
+				<widget name = 'grShaderButton'
+						type = 'Button'
+				/>
+				<widget name = 'grShader'
+						height = 'Globals.Line.Height'
+				/>
+				<widget name = 'grShaderClearButton'
+						height = 'Globals.Line.Height'
+						width = 'Globals.Line.Height'
+				/>
+			</layout>
 			<widget name = 'grAspectCheckbox'
 					type = 'Checkbox'
 			/>
@@ -530,23 +550,6 @@
 		</layout>
 	</dialog>
 
-	<dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'>
-		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
-			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'grShaderButton'
-						type = 'Button'
-				/>
-				<widget name = 'grShader'
-						height = 'Globals.Line.Height'
-				/>
-				<widget name = 'grShaderClearButton'
-						height = 'Globals.Line.Height'
-						width = 'Globals.Line.Height'
-				/>
-			</layout>
-		</layout>
-	</dialog>
-
 	<dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'>
 		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
@@ -1260,7 +1263,7 @@
 						type = 'Button'
 				/>
 			</layout>
-		</layout>	
+		</layout>
 	</dialog>
 
 	<dialog name = 'GameOptions_KeyMapper' overlays = 'Dialog.GameOptions.TabWidget'>
@@ -1298,15 +1301,6 @@
 		</layout>
 	</dialog>
 
-	<dialog name = 'GameOptions_Shader' overlays = 'Dialog.GameOptions.TabWidget'>
-		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
-			<widget name = 'EnableTabCheckbox'
-					type = 'Checkbox'
-			/>
-			<import layout = 'Dialog.GlobalOptions_Shader' />
-		</layout>
-	</dialog>
-
 	<dialog name = 'GameOptions_Audio' overlays = 'Dialog.GameOptions.TabWidget'>
 		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
 			<widget name = 'EnableTabCheckbox'
diff --git a/gui/themes/common/lowres_layout.stx b/gui/themes/common/lowres_layout.stx
index a81432d8e5e..479b67ad109 100644
--- a/gui/themes/common/lowres_layout.stx
+++ b/gui/themes/common/lowres_layout.stx
@@ -428,6 +428,10 @@
 				/>
 			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
+				<widget name = 'grScalerRadioButton'
+						type = 'Radiobutton'
+						width = '10'
+				/>
 				<widget name = 'grScalerPopupDesc'
 						type = 'OptionsLabel'
 				/>
@@ -438,6 +442,22 @@
 						type = 'PopUp'
 				/>
 			</layout>
+			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
+				<widget name = 'grShaderRadioButton'
+						type = 'Radiobutton'
+						width = '10'
+				/>
+				<widget name = 'grShaderButton'
+						type = 'Button'
+				/>
+				<widget name = 'grShader'
+						height = 'Globals.Line.Height'
+				/>
+				<widget name = 'grShaderClearButton'
+						height = 'Globals.Line.Height'
+						width = 'Globals.Line.Height'
+				/>
+			</layout>
 			<widget name = 'grAspectCheckbox'
 					type = 'Checkbox'
 			/>
@@ -469,23 +489,6 @@
 		</layout>
 	</dialog>
 
-	<dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'>
-		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
-			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'grShaderButton'
-						type = 'Button'
-				/>
-				<widget name = 'grShader'
-						height = 'Globals.Line.Height'
-				/>
-				<widget name = 'grShaderClearButton'
-						height = 'Globals.Line.Height'
-						width = 'Globals.Line.Height'
-				/>
-			</layout>
-		</layout>
-	</dialog>
-
 	<dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'>
 		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
@@ -1229,15 +1232,6 @@
 		</layout>
 	</dialog>
 
-	<dialog name = 'GameOptions_Shader' overlays = 'Dialog.GameOptions.TabWidget'>
-		<layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'>
-			<widget name = 'EnableTabCheckbox'
-					type = 'Checkbox'
-			/>
-			<import layout = 'Dialog.GlobalOptions_Shader' />
-		</layout>
-	</dialog>
-
 	<dialog name = 'GameOptions_Audio' overlays = 'Dialog.GameOptions.TabWidget'>
 		<layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'>
 			<widget name = 'EnableTabCheckbox'


Commit: ee9ede66812b478d529928010b736e5bcd2e0a4d
    https://github.com/scummvm/scummvm/commit/ee9ede66812b478d529928010b736e5bcd2e0a4d
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Persist shader/scaler radiobutton state

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index 6b79c3caa6d..f3a5216ac45 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -357,6 +357,15 @@ void OptionsDialog::build() {
 		_scalerPopUp->setSelected(0);
 		_scaleFactorPopUp->setSelected(0);
 
+		// Set the scaler checkbox value
+		int scalerVal = kScalerScaler;
+
+		if (ConfMan.hasKey("usehaders", _domain) && ConfMan.get("usehaders", _domain) == "shaders")
+			scalerVal = kScalerShader;
+
+		_scalerToggleGroup->setValue(scalerVal);
+		setScalerControls();
+
 		if (g_system->hasFeature(OSystem::kFeatureScalers)) {
 			if (ConfMan.hasKey("scaler", _domain)) {
 				const PluginList &scalerPlugins = ScalerMan.getPlugins();
@@ -599,6 +608,13 @@ void OptionsDialog::apply() {
 			ConfMan.setBool("aspect_ratio", _aspectCheckbox->getState(), _domain);
 			ConfMan.setBool("vsync", _vsyncCheckbox->getState(), _domain);
 
+			Common::String useshader = "scalers";
+
+			if (_scalerToggleGroup->getValue() == kScalerShader)
+				useshader = "shaders";
+
+			ConfMan.set("usehaders", useshader, _domain);
+
 			bool isSet = false;
 
 			if ((int32)_gfxPopUp->getSelectedTag() >= 0) {
@@ -1982,7 +1998,6 @@ void OptionsDialog::setupGraphicsTab() {
 	_renderModePopUpDesc->setVisible(true);
 	_renderModePopUp->setVisible(true);
 
-	_scalerToggleGroup->setValue(kScalerScaler);
 	setScalerControls();
 
 	if (g_system->hasFeature(OSystem::kFeatureScalers)) {


Commit: 3aef14fa994ef564e5824da4485dee6cc87225c2
    https://github.com/scummvm/scummvm/commit/3aef14fa994ef564e5824da4485dee6cc87225c2
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Initial code for making game options work with shader controls

Changed paths:
    gui/editgamedialog.cpp
    gui/options.cpp
    gui/options.h


diff --git a/gui/editgamedialog.cpp b/gui/editgamedialog.cpp
index 62022e2fa87..1976910047e 100644
--- a/gui/editgamedialog.cpp
+++ b/gui/editgamedialog.cpp
@@ -396,6 +396,7 @@ void EditGameDialog::open() {
 		ConfMan.hasKey("stretch_mode", _domain) ||
 		ConfMan.hasKey("scaler", _domain) ||
 		ConfMan.hasKey("scale_factor", _domain) ||
+		ConfMan.hasKey("shader", _domain) ||
 		ConfMan.hasKey("aspect_ratio", _domain) ||
 		ConfMan.hasKey("fullscreen", _domain) ||
 		ConfMan.hasKey("vsync", _domain) ||
diff --git a/gui/options.cpp b/gui/options.cpp
index f3a5216ac45..9e5dfd2fb75 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -1217,16 +1217,37 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
 		_stretchPopUp->setEnabled(false);
 	}
 
+	bool scalerToggle = false;
+
 	if (g_system->hasFeature(OSystem::kFeatureScalers)) {
 		_scalerPopUpDesc->setEnabled(enabled);
 		_scalerPopUp->setEnabled(enabled);
 		_scaleFactorPopUp->setEnabled(enabled);
+
+		scalerToggle = true;
 	} else {
 		_scalerPopUpDesc->setEnabled(false);
 		_scalerPopUp->setEnabled(false);
 		_scaleFactorPopUp->setEnabled(false);
 	}
 
+	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
+		_shaderButton->setEnabled(enabled);
+		_shader->setEnabled(enabled);
+		_shaderClearButton->setEnabled(enabled);
+
+		scalerToggle = true;
+	} else {
+		_scalerPopUpDesc->setEnabled(false);
+		_scalerPopUp->setEnabled(false);
+		_scaleFactorPopUp->setEnabled(false);
+	}
+
+	_scalerToggleGroup->setEnabled(scalerToggle);
+
+	// Toggle setting based on the radiobutton state
+	setScalerControls(enabled);
+
 	if (g_system->hasFeature(OSystem::kFeatureFilteringMode))
 		_filteringCheckbox->setEnabled(enabled);
 	else
@@ -1636,7 +1657,7 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
 	_enableGraphicSettings = true;
 }
 
-void OptionsDialog::setScalerControls() {
+void OptionsDialog::setScalerControls(bool enabled) {
 	bool scalers, shaders;
 
 	if (_scalerToggleGroup->getValue() == kScalerScaler) {
@@ -1647,6 +1668,10 @@ void OptionsDialog::setScalerControls() {
 		shaders = true;
 	}
 
+	if (!enabled) {
+		scalers = shaders = false;
+	}
+
 	_scalerPopUpDesc->setEnabled(scalers);
 	_scalerPopUp->setEnabled(scalers);
 	_scaleFactorPopUp->setEnabled(scalers);
diff --git a/gui/options.h b/gui/options.h
index 298b424ccee..7254ad4c7b6 100644
--- a/gui/options.h
+++ b/gui/options.h
@@ -115,7 +115,7 @@ protected:
 	bool loadMusicDeviceSetting(PopUpWidget *popup, Common::String setting, MusicType preferredType = MT_AUTO);
 	void saveMusicDeviceSetting(PopUpWidget *popup, Common::String setting);
 
-	void setScalerControls();
+	void setScalerControls(bool enabled = true);
 
 	TabWidget *_tabWidget;
 	int _graphicsTabId;


Commit: 2fc93e58bd3bedbcb94f68e13142ad4cbaf342fa
    https://github.com/scummvm/scummvm/commit/2fc93e58bd3bedbcb94f68e13142ad4cbaf342fa
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Fix scaler toggle behavior in game options

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index 9e5dfd2fb75..25440314979 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -1224,7 +1224,7 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
 		_scalerPopUp->setEnabled(enabled);
 		_scaleFactorPopUp->setEnabled(enabled);
 
-		scalerToggle = true;
+		scalerToggle = enabled;
 	} else {
 		_scalerPopUpDesc->setEnabled(false);
 		_scalerPopUp->setEnabled(false);
@@ -1236,7 +1236,7 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
 		_shader->setEnabled(enabled);
 		_shaderClearButton->setEnabled(enabled);
 
-		scalerToggle = true;
+		scalerToggle = enabled;
 	} else {
 		_scalerPopUpDesc->setEnabled(false);
 		_scalerPopUp->setEnabled(false);


Commit: 80f79f253d899708b21b6fc129320941a2b5b1d1
    https://github.com/scummvm/scummvm/commit/80f79f253d899708b21b6fc129320941a2b5b1d1
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Make shaders/scalers work mutually exclusive

Changed paths:
    base/main.cpp
    engines/engine.cpp
    gui/options.cpp


diff --git a/base/main.cpp b/base/main.cpp
index 5fc1bf9cfaa..f15b14fb8ba 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -353,8 +353,14 @@ static void setupGraphics(OSystem &system) {
 		// Set the user specified graphics mode (if any).
 		system.setGraphicsMode(ConfMan.get("gfx_mode").c_str());
 		system.setStretchMode(ConfMan.get("stretch_mode").c_str());
-		system.setScaler(ConfMan.get("scaler").c_str(), ConfMan.getInt("scale_factor"));
-		system.setShader(ConfMan.get("shader"));
+
+		if (ConfMan.hasKey("useshaders") && ConfMan.get("useshaders") == "shaders") {
+			system.setScaler(g_system->getDefaultScaler(), g_system->getDefaultScaleFactor());
+			system.setShader(ConfMan.get("shader"));
+		} else {
+			system.setScaler(ConfMan.get("scaler").c_str(), ConfMan.getInt("scale_factor"));
+			system.setShader("");
+		}
 
 		system.initSize(320, 200);
 
diff --git a/engines/engine.cpp b/engines/engine.cpp
index 1a4a37cb706..9ce2bacb4c3 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -215,11 +215,17 @@ void initCommonGFX() {
 		if (gameDomain->contains("stretch_mode"))
 			g_system->setStretchMode(ConfMan.get("stretch_mode").c_str());
 
-		if (gameDomain->contains("scaler") || gameDomain->contains("scale_factor"))
-			g_system->setScaler(ConfMan.get("scaler").c_str(), ConfMan.getInt("scale_factor"));
-
-		if (gameDomain->contains("shader"))
-			g_system->setShader(ConfMan.get("shader"));
+		if (ConfMan.hasKey("useshaders") && ConfMan.get("useshaders") == "shaders") {
+			if (gameDomain->contains("shader")) {
+				g_system->setScaler(g_system->getDefaultScaler(), g_system->getDefaultScaleFactor());
+				g_system->setShader(ConfMan.get("shader"));
+			}
+		} else {
+			if (gameDomain->contains("scaler") || gameDomain->contains("scale_factor")) {
+				g_system->setScaler(ConfMan.get("scaler").c_str(), ConfMan.getInt("scale_factor"));
+				g_system->setShader("");
+			}
+		}
 	}
 }
 
diff --git a/gui/options.cpp b/gui/options.cpp
index 25440314979..b7efa561fca 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -360,7 +360,7 @@ void OptionsDialog::build() {
 		// Set the scaler checkbox value
 		int scalerVal = kScalerScaler;
 
-		if (ConfMan.hasKey("usehaders", _domain) && ConfMan.get("usehaders", _domain) == "shaders")
+		if (ConfMan.hasKey("useshaders", _domain) && ConfMan.get("useshaders", _domain) == "shaders")
 			scalerVal = kScalerShader;
 
 		_scalerToggleGroup->setValue(scalerVal);
@@ -608,12 +608,15 @@ void OptionsDialog::apply() {
 			ConfMan.setBool("aspect_ratio", _aspectCheckbox->getState(), _domain);
 			ConfMan.setBool("vsync", _vsyncCheckbox->getState(), _domain);
 
-			Common::String useshader = "scalers";
+			Common::String useshaders = "scalers";
 
 			if (_scalerToggleGroup->getValue() == kScalerShader)
-				useshader = "shaders";
+				useshaders = "shaders";
 
-			ConfMan.set("usehaders", useshader, _domain);
+			if (ConfMan.get("useshaders", _domain) != useshaders)
+				graphicsModeChanged = true;
+
+			ConfMan.set("useshaders", useshaders, _domain);
 
 			bool isSet = false;
 
@@ -769,8 +772,16 @@ void OptionsDialog::apply() {
 		g_system->beginGFXTransaction();
 		g_system->setGraphicsMode(ConfMan.get("gfx_mode", _domain).c_str());
 		g_system->setStretchMode(ConfMan.get("stretch_mode", _domain).c_str());
-		g_system->setScaler(ConfMan.get("scaler", _domain).c_str(), ConfMan.getInt("scale_factor", _domain));
-		g_system->setShader(ConfMan.get("shader", _domain));
+
+		if (ConfMan.hasKey("useshaders", _domain) && ConfMan.get("useshaders", _domain) == "shaders") {
+			g_system->setScaler(g_system->getDefaultScaler(), g_system->getDefaultScaleFactor());
+			g_system->setShader(ConfMan.get("shader", _domain));
+		} else {
+			// THis should stay in the fallback section for allowing more values to the toggle group
+
+			g_system->setScaler(ConfMan.get("scaler", _domain).c_str(), ConfMan.getInt("scale_factor", _domain));
+			g_system->setShader("");
+		}
 
 		if (ConfMan.hasKey("aspect_ratio"))
 			g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, ConfMan.getBool("aspect_ratio", _domain));


Commit: cc0740685f4d122a7c847e6577f1c6fda681ecca
    https://github.com/scummvm/scummvm/commit/cc0740685f4d122a7c847e6577f1c6fda681ecca
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Disable kFeatureFilteringMode because it conflicts with shaders

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index ec94c82c304..2d1b8be2e06 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -109,7 +109,7 @@ bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) const {
 	switch (f) {
 	case OSystem::kFeatureAspectRatioCorrection:
 	case OSystem::kFeatureCursorPalette:
-	case OSystem::kFeatureFilteringMode:
+	//case OSystem::kFeatureFilteringMode:
 	case OSystem::kFeatureStretchMode:
 #ifdef USE_SCALERS
 	case OSystem::kFeatureScalers:
@@ -134,6 +134,7 @@ void OpenGLGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
 		_currentState.aspectRatioCorrection = enable;
 		break;
 
+#if 0
 	case OSystem::kFeatureFilteringMode:
 		assert(_transactionMode != kTransactionNone);
 		_currentState.filtering = enable;
@@ -154,6 +155,7 @@ void OpenGLGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
 		}
 
 		break;
+#endif
 
 	case OSystem::kFeatureCursorPalette:
 		_cursorPaletteEnabled = enable;


Commit: 0351b86d6445e94536e55bb6fae55fc4dec102d3
    https://github.com/scummvm/scummvm/commit/0351b86d6445e94536e55bb6fae55fc4dec102d3
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Sync classic layout with shader controls

Changed paths:
    gui/themes/default.inc
    gui/themes/scummclassic/classic_layout.stx
    gui/themes/scummclassic/classic_layout_lowres.stx


diff --git a/gui/themes/default.inc b/gui/themes/default.inc
index 0fd281d355d..55e046611ee 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -1739,6 +1739,10 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "/>"
 "</layout>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='10' align='center'>"
+"<widget name='grScalerRadioButton' "
+"type='Radiobutton' "
+"width='20' "
+"/>"
 "<widget name='grScalerPopupDesc' "
 "type='OptionsLabel' "
 "/>"
@@ -1749,6 +1753,22 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "type='PopUp' "
 "/>"
 "</layout>"
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' align='center'>"
+"<widget name='grShaderRadioButton' "
+"type='Radiobutton' "
+"width='20' "
+"/>"
+"<widget name='grShaderButton' "
+"type='Button' "
+"/>"
+"<widget name='grShader' "
+"height='Globals.Line.Height' "
+"/>"
+"<widget name='grShaderClearButton' "
+"height='Globals.Line.Height' "
+"width='Globals.Line.Height' "
+"/>"
+"</layout>"
 "<widget name='grAspectCheckbox' "
 "type='Checkbox' "
 "/>"
@@ -1779,22 +1799,6 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "</layout>"
 "</layout>"
 "</dialog>"
-"<dialog name='GlobalOptions_Shader' overlays='Dialog.GlobalOptions.TabWidget'>"
-"<layout type='vertical' padding='16,16,16,16' spacing='8'>"
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' align='center'>"
-"<widget name='grShaderButton' "
-"type='Button' "
-"/>"
-"<widget name='grShader' "
-"height='Globals.Line.Height' "
-"/>"
-"<widget name='grShaderClearButton' "
-"height='Globals.Line.Height' "
-"width='Globals.Line.Height' "
-"/>"
-"</layout>"
-"</layout>"
-"</dialog>"
 "<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'>"
 "<layout type='vertical' padding='16,16,16,16' spacing='8'>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='10' align='center'>"
@@ -2509,14 +2513,6 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "<import layout='Dialog.GlobalOptions_Graphics_Container' />"
 "</layout>"
 "</dialog>"
-"<dialog name='GameOptions_Shader' overlays='Dialog.GameOptions.TabWidget'>"
-"<layout type='vertical' padding='16,16,16,16' spacing='8'>"
-"<widget name='EnableTabCheckbox' "
-"type='Checkbox' "
-"/>"
-"<import layout='Dialog.GlobalOptions_Shader' />"
-"</layout>"
-"</dialog>"
 "<dialog name='GameOptions_Audio' overlays='Dialog.GameOptions.TabWidget'>"
 "<layout type='vertical' padding='16,16,16,16' spacing='8'>"
 "<widget name='EnableTabCheckbox' "
@@ -3657,6 +3653,10 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "/>"
 "</layout>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='6' align='center'>"
+"<widget name='grScalerRadioButton' "
+"type='Radiobutton' "
+"width='10' "
+"/>"
 "<widget name='grScalerPopupDesc' "
 "type='OptionsLabel' "
 "/>"
@@ -3667,6 +3667,22 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "type='PopUp' "
 "/>"
 "</layout>"
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' align='center'>"
+"<widget name='grShaderRadioButton' "
+"type='Radiobutton' "
+"width='10' "
+"/>"
+"<widget name='grShaderButton' "
+"type='Button' "
+"/>"
+"<widget name='grShader' "
+"height='Globals.Line.Height' "
+"/>"
+"<widget name='grShaderClearButton' "
+"height='Globals.Line.Height' "
+"width='Globals.Line.Height' "
+"/>"
+"</layout>"
 "<widget name='grAspectCheckbox' "
 "type='Checkbox' "
 "/>"
@@ -3697,22 +3713,6 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "</layout>"
 "</layout>"
 "</dialog>"
-"<dialog name='GlobalOptions_Shader' overlays='Dialog.GlobalOptions.TabWidget'>"
-"<layout type='vertical' padding='16,16,16,16' spacing='8'>"
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' align='center'>"
-"<widget name='grShaderButton' "
-"type='Button' "
-"/>"
-"<widget name='grShader' "
-"height='Globals.Line.Height' "
-"/>"
-"<widget name='grShaderClearButton' "
-"height='Globals.Line.Height' "
-"width='Globals.Line.Height' "
-"/>"
-"</layout>"
-"</layout>"
-"</dialog>"
 "<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'>"
 "<layout type='vertical' padding='16,16,16,16' spacing='8'>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='6' align='center'>"
@@ -4434,14 +4434,6 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "<import layout='Dialog.GlobalOptions_Graphics_Container' />"
 "</layout>"
 "</dialog>"
-"<dialog name='GameOptions_Shader' overlays='Dialog.GameOptions.TabWidget'>"
-"<layout type='vertical' padding='8,8,8,8' spacing='6'>"
-"<widget name='EnableTabCheckbox' "
-"type='Checkbox' "
-"/>"
-"<import layout='Dialog.GlobalOptions_Shader' />"
-"</layout>"
-"</dialog>"
 "<dialog name='GameOptions_Audio' overlays='Dialog.GameOptions.TabWidget'>"
 "<layout type='vertical' padding='8,8,8,8' spacing='6'>"
 "<widget name='EnableTabCheckbox' "
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index cc52b0df21e..c470b5a9303 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -341,6 +341,10 @@
 				/>
 			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
+				<widget name = 'grScalerRadioButton'
+						type = 'Radiobutton'
+						width = '20'
+				/>
 				<widget name = 'grScalerPopupDesc'
 						type = 'OptionsLabel'
 				/>
@@ -351,6 +355,22 @@
 						type = 'PopUp'
 				/>
 			</layout>
+			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
+				<widget name = 'grShaderRadioButton'
+						type = 'Radiobutton'
+						width = '20'
+				/>
+				<widget name = 'grShaderButton'
+						type = 'Button'
+				/>
+				<widget name = 'grShader'
+						height = 'Globals.Line.Height'
+				/>
+				<widget name = 'grShaderClearButton'
+						height = 'Globals.Line.Height'
+						width = 'Globals.Line.Height'
+				/>
+			</layout>
 			<widget name = 'grAspectCheckbox'
 					type = 'Checkbox'
 			/>
@@ -382,23 +402,6 @@
 		</layout>
 	</dialog>
 
-	<dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'>
-		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
-			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'grShaderButton'
-						type = 'Button'
-				/>
-				<widget name = 'grShader'
-						height = 'Globals.Line.Height'
-				/>
-				<widget name = 'grShaderClearButton'
-						height = 'Globals.Line.Height'
-						width = 'Globals.Line.Height'
-				/>
-			</layout>
-		</layout>
-	</dialog>
-
 	<dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'>
 		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
@@ -1135,15 +1138,6 @@
 		</layout>
 	</dialog>
 
-	<dialog name = 'GameOptions_Shader' overlays = 'Dialog.GameOptions.TabWidget'>
-		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
-			<widget name = 'EnableTabCheckbox'
-					type = 'Checkbox'
-			/>
-			<import layout = 'Dialog.GlobalOptions_Shader' />
-		</layout>
-	</dialog>
-
 	<dialog name = 'GameOptions_Audio' overlays = 'Dialog.GameOptions.TabWidget'>
 		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
 			<widget name = 'EnableTabCheckbox'
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index a17329fed47..8b3fcd365ae 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -342,6 +342,10 @@
 				/>
 			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
+				<widget name = 'grScalerRadioButton'
+						type = 'Radiobutton'
+						width = '10'
+				/>
 				<widget name = 'grScalerPopupDesc'
 						type = 'OptionsLabel'
 				/>
@@ -352,6 +356,22 @@
 						type = 'PopUp'
 				/>
 			</layout>
+			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
+				<widget name = 'grShaderRadioButton'
+						type = 'Radiobutton'
+						width = '10'
+				/>
+				<widget name = 'grShaderButton'
+						type = 'Button'
+				/>
+				<widget name = 'grShader'
+						height = 'Globals.Line.Height'
+				/>
+				<widget name = 'grShaderClearButton'
+						height = 'Globals.Line.Height'
+						width = 'Globals.Line.Height'
+				/>
+			</layout>
 			<widget name = 'grAspectCheckbox'
 					type = 'Checkbox'
 			/>
@@ -383,23 +403,6 @@
 		</layout>
 	</dialog>
 
-	<dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'>
-		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
-			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'grShaderButton'
-						type = 'Button'
-				/>
-				<widget name = 'grShader'
-						height = 'Globals.Line.Height'
-				/>
-				<widget name = 'grShaderClearButton'
-						height = 'Globals.Line.Height'
-						width = 'Globals.Line.Height'
-				/>
-			</layout>
-		</layout>
-	</dialog>
-
 	<dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'>
 		<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
@@ -1142,15 +1145,6 @@
 		</layout>
 	</dialog>
 
-	<dialog name = 'GameOptions_Shader' overlays = 'Dialog.GameOptions.TabWidget'>
-		<layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'>
-			<widget name = 'EnableTabCheckbox'
-					type = 'Checkbox'
-			/>
-			<import layout = 'Dialog.GlobalOptions_Shader' />
-		</layout>
-	</dialog>
-
 	<dialog name = 'GameOptions_Audio' overlays = 'Dialog.GameOptions.TabWidget'>
 		<layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'>
 			<widget name = 'EnableTabCheckbox'


Commit: 4e4c14926469fa9b5f07460ad7101fe6a108314d
    https://github.com/scummvm/scummvm/commit/4e4c14926469fa9b5f07460ad7101fe6a108314d
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Bump theme version to 0.9.6

Changed paths:
    gui/ThemeEngine.h
    gui/themes/residualvm.zip
    gui/themes/residualvm/THEMERC
    gui/themes/scummclassic.zip
    gui/themes/scummclassic/THEMERC
    gui/themes/scummmodern.zip
    gui/themes/scummmodern/THEMERC
    gui/themes/scummremastered.zip
    gui/themes/scummremastered/THEMERC


diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h
index 2e21abd0e17..1c9182feda5 100644
--- a/gui/ThemeEngine.h
+++ b/gui/ThemeEngine.h
@@ -36,7 +36,7 @@
 #include "graphics/pixelformat.h"
 
 
-#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.9.5"
+#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.9.6"
 
 class OSystem;
 
diff --git a/gui/themes/residualvm.zip b/gui/themes/residualvm.zip
index 0f00fb8ded5..aaee529c667 100644
Binary files a/gui/themes/residualvm.zip and b/gui/themes/residualvm.zip differ
diff --git a/gui/themes/residualvm/THEMERC b/gui/themes/residualvm/THEMERC
index 9c388365431..24e8c2ce3b8 100644
--- a/gui/themes/residualvm/THEMERC
+++ b/gui/themes/residualvm/THEMERC
@@ -1,3 +1,3 @@
-[SCUMMVM_STX0.9.5:ResidualVM Modern Theme Remastered:No Author]
+[SCUMMVM_STX0.9.6:ResidualVM Modern Theme Remastered:No Author]
 %using ../common
 %using ../common-svg
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index d9aeb1e3d8e..264ce05a958 100644
Binary files a/gui/themes/scummclassic.zip and b/gui/themes/scummclassic.zip differ
diff --git a/gui/themes/scummclassic/THEMERC b/gui/themes/scummclassic/THEMERC
index b7aea1159d2..b76d038ff54 100644
--- a/gui/themes/scummclassic/THEMERC
+++ b/gui/themes/scummclassic/THEMERC
@@ -1 +1 @@
-[SCUMMVM_STX0.9.5:ScummVM Classic Theme:No Author]
+[SCUMMVM_STX0.9.6:ScummVM Classic Theme:No Author]
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index 7ce7a42daa4..ed61f0f9165 100644
Binary files a/gui/themes/scummmodern.zip and b/gui/themes/scummmodern.zip differ
diff --git a/gui/themes/scummmodern/THEMERC b/gui/themes/scummmodern/THEMERC
index 416407635ea..682f3f1a930 100644
--- a/gui/themes/scummmodern/THEMERC
+++ b/gui/themes/scummmodern/THEMERC
@@ -1,2 +1,2 @@
-[SCUMMVM_STX0.9.5:ScummVM Modern Theme:No Author]
+[SCUMMVM_STX0.9.6:ScummVM Modern Theme:No Author]
 %using ../common
diff --git a/gui/themes/scummremastered.zip b/gui/themes/scummremastered.zip
index 3297cacf327..63a881f3853 100644
Binary files a/gui/themes/scummremastered.zip and b/gui/themes/scummremastered.zip differ
diff --git a/gui/themes/scummremastered/THEMERC b/gui/themes/scummremastered/THEMERC
index 2edcb044c90..37a9c81c933 100644
--- a/gui/themes/scummremastered/THEMERC
+++ b/gui/themes/scummremastered/THEMERC
@@ -1,3 +1,3 @@
-[SCUMMVM_STX0.9.5:ScummVM Modern Theme Remastered:No Author]
+[SCUMMVM_STX0.9.6:ScummVM Modern Theme Remastered:No Author]
 %using ../common
 %using ../common-svg


Commit: 57cd169a172369331b45ede02a26fb87c370fb18
    https://github.com/scummvm/scummvm/commit/57cd169a172369331b45ede02a26fb87c370fb18
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Allow both scalers and shaders to be enabled at the same time

Changed paths:
    base/main.cpp
    engines/engine.cpp
    gui/options.cpp
    gui/options.h
    gui/themes/common/highres_layout.stx
    gui/themes/common/lowres_layout.stx
    gui/themes/scummclassic/classic_layout.stx
    gui/themes/scummclassic/classic_layout_lowres.stx


diff --git a/base/main.cpp b/base/main.cpp
index f15b14fb8ba..5fc1bf9cfaa 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -353,14 +353,8 @@ static void setupGraphics(OSystem &system) {
 		// Set the user specified graphics mode (if any).
 		system.setGraphicsMode(ConfMan.get("gfx_mode").c_str());
 		system.setStretchMode(ConfMan.get("stretch_mode").c_str());
-
-		if (ConfMan.hasKey("useshaders") && ConfMan.get("useshaders") == "shaders") {
-			system.setScaler(g_system->getDefaultScaler(), g_system->getDefaultScaleFactor());
-			system.setShader(ConfMan.get("shader"));
-		} else {
-			system.setScaler(ConfMan.get("scaler").c_str(), ConfMan.getInt("scale_factor"));
-			system.setShader("");
-		}
+		system.setScaler(ConfMan.get("scaler").c_str(), ConfMan.getInt("scale_factor"));
+		system.setShader(ConfMan.get("shader"));
 
 		system.initSize(320, 200);
 
diff --git a/engines/engine.cpp b/engines/engine.cpp
index 9ce2bacb4c3..1a4a37cb706 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -215,17 +215,11 @@ void initCommonGFX() {
 		if (gameDomain->contains("stretch_mode"))
 			g_system->setStretchMode(ConfMan.get("stretch_mode").c_str());
 
-		if (ConfMan.hasKey("useshaders") && ConfMan.get("useshaders") == "shaders") {
-			if (gameDomain->contains("shader")) {
-				g_system->setScaler(g_system->getDefaultScaler(), g_system->getDefaultScaleFactor());
-				g_system->setShader(ConfMan.get("shader"));
-			}
-		} else {
-			if (gameDomain->contains("scaler") || gameDomain->contains("scale_factor")) {
-				g_system->setScaler(ConfMan.get("scaler").c_str(), ConfMan.getInt("scale_factor"));
-				g_system->setShader("");
-			}
-		}
+		if (gameDomain->contains("scaler") || gameDomain->contains("scale_factor"))
+			g_system->setScaler(ConfMan.get("scaler").c_str(), ConfMan.getInt("scale_factor"));
+
+		if (gameDomain->contains("shader"))
+			g_system->setShader(ConfMan.get("shader"));
 	}
 }
 
diff --git a/gui/options.cpp b/gui/options.cpp
index b7efa561fca..24dd50a501c 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -103,7 +103,6 @@ enum {
 	kGraphicsTabContainerReflowCmd = 'gtcr',
 	kScalerPopUpCmd			= 'scPU',
 	kFullscreenToggled		= 'oful',
-	kScalerToggle			= 'sctg',
 };
 
 enum {
@@ -112,11 +111,6 @@ enum {
 	kSubtitlesBoth,
 };
 
-enum {
-	kScalerScaler,
-	kScalerShader,
-};
-
 #ifdef USE_FLUIDSYNTH
 enum {
 	kFluidSynthSettingsCmd  = 'flst'
@@ -203,7 +197,6 @@ void OptionsDialog::init() {
 	_fullscreenCheckbox = nullptr;
 	_filteringCheckbox = nullptr;
 	_aspectCheckbox = nullptr;
-	_enableShaderSettings = false;
 	_shader = nullptr;
 	_shaderButton = nullptr;
 	_shaderClearButton = nullptr;
@@ -357,15 +350,6 @@ void OptionsDialog::build() {
 		_scalerPopUp->setSelected(0);
 		_scaleFactorPopUp->setSelected(0);
 
-		// Set the scaler checkbox value
-		int scalerVal = kScalerScaler;
-
-		if (ConfMan.hasKey("useshaders", _domain) && ConfMan.get("useshaders", _domain) == "shaders")
-			scalerVal = kScalerShader;
-
-		_scalerToggleGroup->setValue(scalerVal);
-		setScalerControls();
-
 		if (g_system->hasFeature(OSystem::kFeatureScalers)) {
 			if (ConfMan.hasKey("scaler", _domain)) {
 				const PluginList &scalerPlugins = ScalerMan.getPlugins();
@@ -608,16 +592,6 @@ void OptionsDialog::apply() {
 			ConfMan.setBool("aspect_ratio", _aspectCheckbox->getState(), _domain);
 			ConfMan.setBool("vsync", _vsyncCheckbox->getState(), _domain);
 
-			Common::String useshaders = "scalers";
-
-			if (_scalerToggleGroup->getValue() == kScalerShader)
-				useshaders = "shaders";
-
-			if (ConfMan.get("useshaders", _domain) != useshaders)
-				graphicsModeChanged = true;
-
-			ConfMan.set("useshaders", useshaders, _domain);
-
 			bool isSet = false;
 
 			if ((int32)_gfxPopUp->getSelectedTag() >= 0) {
@@ -739,32 +713,28 @@ void OptionsDialog::apply() {
 
 	// Shader options
 	if (_shader) {
-		if (_enableShaderSettings) {
-			bool isSet;
-
-			if (ConfMan.hasKey("shader", _domain) && !ConfMan.get("shader", _domain).empty())
-				previousShader = ConfMan.get("shader", _domain);
+		bool isSet;
 
-			Common::U32String shader(_shader->getLabel());
-			if (shader.empty() || (shader == _c("None", "shader")))
-				isSet = false;
-			else
-				isSet = true;
+		if (ConfMan.hasKey("shader", _domain) && !ConfMan.get("shader", _domain).empty())
+			previousShader = ConfMan.get("shader", _domain);
 
-			if (isSet) {
-				if (!ConfMan.hasKey("shader", _domain) || shader != ConfMan.get("shader", _domain))
-					graphicsModeChanged = true;
-				ConfMan.set("shader", shader.encode(), _domain);
-			} else {
-				if (ConfMan.hasKey("shader", _domain) && !ConfMan.get("shader", _domain).empty())
-					graphicsModeChanged = true;
-				ConfMan.removeKey("shader", _domain);
-			}
+		Common::U32String shader(_shader->getLabel());
+		if (shader.empty() || (shader == _c("None", "shader")))
+			isSet = false;
+		else
+			isSet = true;
 
-			_shader->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
+		if (isSet) {
+			if (!ConfMan.hasKey("shader", _domain) || shader != ConfMan.get("shader", _domain))
+				graphicsModeChanged = true;
+			ConfMan.set("shader", shader.encode(), _domain);
 		} else {
+			if (ConfMan.hasKey("shader", _domain) && !ConfMan.get("shader", _domain).empty())
+				graphicsModeChanged = true;
 			ConfMan.removeKey("shader", _domain);
 		}
+
+		_shader->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
 	}
 
 	// Setup graphics again if needed
@@ -772,16 +742,8 @@ void OptionsDialog::apply() {
 		g_system->beginGFXTransaction();
 		g_system->setGraphicsMode(ConfMan.get("gfx_mode", _domain).c_str());
 		g_system->setStretchMode(ConfMan.get("stretch_mode", _domain).c_str());
-
-		if (ConfMan.hasKey("useshaders", _domain) && ConfMan.get("useshaders", _domain) == "shaders") {
-			g_system->setScaler(g_system->getDefaultScaler(), g_system->getDefaultScaleFactor());
-			g_system->setShader(ConfMan.get("shader", _domain));
-		} else {
-			// THis should stay in the fallback section for allowing more values to the toggle group
-
-			g_system->setScaler(ConfMan.get("scaler", _domain).c_str(), ConfMan.getInt("scale_factor", _domain));
-			g_system->setShader("");
-		}
+		g_system->setScaler(ConfMan.get("scaler", _domain).c_str(), ConfMan.getInt("scale_factor", _domain));
+		g_system->setShader(ConfMan.get("shader", _domain));
 
 		if (ConfMan.hasKey("aspect_ratio"))
 			g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, ConfMan.getBool("aspect_ratio", _domain));
@@ -1090,9 +1052,6 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
 		_shaderClearButton->setEnabled(false);
 		g_gui.scheduleTopDialogRedraw();
 		break;
-	case kScalerToggle:
-		setScalerControls();
-		break;
 	case kMidiGainChanged:
 		_midiGainLabel->setLabel(Common::String::format("%.2f", (double)_midiGainSlider->getValue() / 100.0));
 		_midiGainLabel->markAsDirty();
@@ -1228,14 +1187,10 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
 		_stretchPopUp->setEnabled(false);
 	}
 
-	bool scalerToggle = false;
-
 	if (g_system->hasFeature(OSystem::kFeatureScalers)) {
 		_scalerPopUpDesc->setEnabled(enabled);
 		_scalerPopUp->setEnabled(enabled);
 		_scaleFactorPopUp->setEnabled(enabled);
-
-		scalerToggle = enabled;
 	} else {
 		_scalerPopUpDesc->setEnabled(false);
 		_scalerPopUp->setEnabled(false);
@@ -1246,19 +1201,12 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
 		_shaderButton->setEnabled(enabled);
 		_shader->setEnabled(enabled);
 		_shaderClearButton->setEnabled(enabled);
-
-		scalerToggle = enabled;
 	} else {
 		_scalerPopUpDesc->setEnabled(false);
 		_scalerPopUp->setEnabled(false);
 		_scaleFactorPopUp->setEnabled(false);
 	}
 
-	_scalerToggleGroup->setEnabled(scalerToggle);
-
-	// Toggle setting based on the radiobutton state
-	setScalerControls(enabled);
-
 	if (g_system->hasFeature(OSystem::kFeatureFilteringMode))
 		_filteringCheckbox->setEnabled(enabled);
 	else
@@ -1275,21 +1223,6 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
 		_aspectCheckbox->setEnabled(enabled);
 }
 
-void OptionsDialog::setShaderSettingsState(bool enabled) {
-	_enableShaderSettings = enabled;
-
-	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
-		_shader->setEnabled(enabled);
-		_shaderButton->setEnabled(enabled);
-		_shaderClearButton->setEnabled(enabled);
-
-		if (enabled && !_shader->getLabel().empty() && (_shader->getLabel() != _c("None", "shader")))
-			_shaderClearButton->setEnabled(enabled);
-		else
-			_shaderClearButton->setEnabled(false);
-	}
-}
-
 void OptionsDialog::setAudioSettingsState(bool enabled) {
 	_enableAudioSettings = enabled;
 	_midiPopUpDesc->setEnabled(enabled);
@@ -1587,15 +1520,9 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
 		sm++;
 	}
 
-	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
-		_scalerToggleGroup = new RadiobuttonGroup(boss, kScalerToggle);
-
-		_scalerToggleScalers = new RadiobuttonWidget(boss, prefix + "grScalerRadioButton", _scalerToggleGroup, kScalerScaler, Common::U32String(""));
-	}
-
 	// The Scaler popup
 	const PluginList &scalerPlugins = ScalerMan.getPlugins();
-	_scalerPopUpDesc = new StaticTextWidget(boss, prefix + "grScalerPopupDesc", _("Use scaler:"));
+	_scalerPopUpDesc = new StaticTextWidget(boss, prefix + "grScalerPopupDesc", _("Scaler:"));
 	_scalerPopUp = new PopUpWidget(boss, prefix + "grScalerPopup", Common::U32String(), kScalerPopUpCmd);
 
 	_scalerPopUp->appendEntry(_("<default>"));
@@ -1608,17 +1535,13 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
 	updateScaleFactors(_scalerPopUp->getSelectedTag());
 
 	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
-		_scalerToggleShaders = new RadiobuttonWidget(boss, prefix + "grShaderRadioButton", _scalerToggleGroup, kScalerShader, Common::U32String(""));
-
 		if (g_system->getOverlayWidth() > 320)
-			_shaderButton = new ButtonWidget(boss, prefix + "grShaderButton", _("Use Shader:"), _("Specifies path to the shader used for scaling the game screen"), kChooseShaderCmd);
+			_shaderButton = new ButtonWidget(boss, prefix + "grShaderButton", _("Shader:"), _("Specifies path to the shader used for scaling the game screen"), kChooseShaderCmd);
 		else
 			_shaderButton = new ButtonWidget(boss, prefix + "grShaderButton", _c("Shader Path:", "lowres"), _("Specifies path to the shader used for scaling the game screen"), kChooseShaderCmd);
 		_shader = new StaticTextWidget(boss, prefix + "grShader", _c("None", "shader"), _("Specifies path to the shader used for scaling the game screen"));
 
 		_shaderClearButton = addClearButton(boss, prefix + "grShaderClearButton", kClearShaderCmd);
-
-		_enableShaderSettings = true;
 	}
 
 	// Fullscreen checkbox
@@ -1668,30 +1591,6 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
 	_enableGraphicSettings = true;
 }
 
-void OptionsDialog::setScalerControls(bool enabled) {
-	bool scalers, shaders;
-
-	if (_scalerToggleGroup->getValue() == kScalerScaler) {
-		scalers = true;
-		shaders = false;
-	} else {
-		scalers = false;
-		shaders = true;
-	}
-
-	if (!enabled) {
-		scalers = shaders = false;
-	}
-
-	_scalerPopUpDesc->setEnabled(scalers);
-	_scalerPopUp->setEnabled(scalers);
-	_scaleFactorPopUp->setEnabled(scalers);
-
-	_shaderButton->setEnabled(shaders);
-	_shader->setEnabled(shaders);
-	_shaderClearButton->setEnabled(shaders);
-}
-
 void OptionsDialog::addAudioControls(GuiObject *boss, const Common::String &prefix) {
 	// The MIDI mode popup & a label
 	if (g_system->getOverlayWidth() > 320)
@@ -2034,8 +1933,6 @@ void OptionsDialog::setupGraphicsTab() {
 	_renderModePopUpDesc->setVisible(true);
 	_renderModePopUp->setVisible(true);
 
-	setScalerControls();
-
 	if (g_system->hasFeature(OSystem::kFeatureScalers)) {
 		_scalerPopUpDesc->setVisible(true);
 		if (ConfMan.isKeyTemporary("scaler") || ConfMan.isKeyTemporary("scale_factor"))
@@ -2047,6 +1944,16 @@ void OptionsDialog::setupGraphicsTab() {
 		_scalerPopUp->setVisible(false);
 		_scaleFactorPopUp->setVisible(false);
 	}
+
+	if (g_system->hasFeature(OSystem::kFeatureShaders)) {
+		_shaderButton->setVisible(true);
+		_shader->setVisible(true);
+		_shaderClearButton->setVisible(true);
+	} else {
+		_shaderButton->setVisible(false);
+		_shader->setVisible(false);
+		_shaderClearButton->setVisible(false);
+	}
 }
 
 void OptionsDialog::updateScaleFactors(uint32 tag) {
diff --git a/gui/options.h b/gui/options.h
index 7254ad4c7b6..7c3e139a407 100644
--- a/gui/options.h
+++ b/gui/options.h
@@ -102,7 +102,6 @@ protected:
 	void addSubtitleControls(GuiObject *boss, const Common::String &prefix, int maxSliderVal = 255);
 
 	void setGraphicSettingsState(bool enabled);
-	void setShaderSettingsState(bool enabled);
 	void setAudioSettingsState(bool enabled);
 	void setMIDISettingsState(bool enabled);
 	void setMT32SettingsState(bool enabled);
@@ -115,8 +114,6 @@ protected:
 	bool loadMusicDeviceSetting(PopUpWidget *popup, Common::String setting, MusicType preferredType = MT_AUTO);
 	void saveMusicDeviceSetting(PopUpWidget *popup, Common::String setting);
 
-	void setScalerControls(bool enabled = true);
-
 	TabWidget *_tabWidget;
 	int _graphicsTabId;
 	int _midiTabId;
@@ -154,9 +151,6 @@ private:
 	PopUpWidget *_gfxPopUp;
 	StaticTextWidget *_stretchPopUpDesc;
 	PopUpWidget *_stretchPopUp;
-	RadiobuttonGroup *_scalerToggleGroup;
-	RadiobuttonWidget *_scalerToggleScalers;
-	RadiobuttonWidget *_scalerToggleShaders;
 	StaticTextWidget *_scalerPopUpDesc;
 	PopUpWidget *_scalerPopUp, *_scaleFactorPopUp;
 	ButtonWidget *_shaderButton;
@@ -171,11 +165,6 @@ private:
 	StaticTextWidget *_renderModePopUpDesc;
 	PopUpWidget *_renderModePopUp;
 
-	//
-	// Shader controls
-	//
-	bool _enableShaderSettings;
-
 	//
 	// Audio controls
 	//
diff --git a/gui/themes/common/highres_layout.stx b/gui/themes/common/highres_layout.stx
index 41bd2ecf4ac..3b1e60ac145 100644
--- a/gui/themes/common/highres_layout.stx
+++ b/gui/themes/common/highres_layout.stx
@@ -489,10 +489,6 @@
 				/>
 			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'grScalerRadioButton'
-						type = 'Radiobutton'
-						width = '20'
-				/>
 				<widget name = 'grScalerPopupDesc'
 						type = 'OptionsLabel'
 				/>
@@ -504,10 +500,6 @@
 				/>
 			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'grShaderRadioButton'
-						type = 'Radiobutton'
-						width = '20'
-				/>
 				<widget name = 'grShaderButton'
 						type = 'Button'
 				/>
diff --git a/gui/themes/common/lowres_layout.stx b/gui/themes/common/lowres_layout.stx
index 479b67ad109..8f121d1c861 100644
--- a/gui/themes/common/lowres_layout.stx
+++ b/gui/themes/common/lowres_layout.stx
@@ -428,10 +428,6 @@
 				/>
 			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
-				<widget name = 'grScalerRadioButton'
-						type = 'Radiobutton'
-						width = '10'
-				/>
 				<widget name = 'grScalerPopupDesc'
 						type = 'OptionsLabel'
 				/>
@@ -443,10 +439,6 @@
 				/>
 			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'grShaderRadioButton'
-						type = 'Radiobutton'
-						width = '10'
-				/>
 				<widget name = 'grShaderButton'
 						type = 'Button'
 				/>
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index c470b5a9303..d16bd2a9cea 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -341,10 +341,6 @@
 				/>
 			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'grScalerRadioButton'
-						type = 'Radiobutton'
-						width = '20'
-				/>
 				<widget name = 'grScalerPopupDesc'
 						type = 'OptionsLabel'
 				/>
@@ -356,10 +352,6 @@
 				/>
 			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
-				<widget name = 'grShaderRadioButton'
-						type = 'Radiobutton'
-						width = '20'
-				/>
 				<widget name = 'grShaderButton'
 						type = 'Button'
 				/>
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index 8b3fcd365ae..6a9627c4a55 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -342,10 +342,6 @@
 				/>
 			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
-				<widget name = 'grScalerRadioButton'
-						type = 'Radiobutton'
-						width = '10'
-				/>
 				<widget name = 'grScalerPopupDesc'
 						type = 'OptionsLabel'
 				/>
@@ -357,10 +353,6 @@
 				/>
 			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
-				<widget name = 'grShaderRadioButton'
-						type = 'Radiobutton'
-						width = '10'
-				/>
 				<widget name = 'grShaderButton'
 						type = 'Button'
 				/>


Commit: 8d65ac4364277805fe0f6d1e25c20ef40b00c3e0
    https://github.com/scummvm/scummvm/commit/8d65ac4364277805fe0f6d1e25c20ef40b00c3e0
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Regenerate theme files

Changed paths:
    gui/themes/default.inc
    gui/themes/residualvm.zip
    gui/themes/scummclassic.zip
    gui/themes/scummmodern.zip
    gui/themes/scummremastered.zip


diff --git a/gui/themes/default.inc b/gui/themes/default.inc
index 55e046611ee..7905798b0c4 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -1739,10 +1739,6 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "/>"
 "</layout>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='10' align='center'>"
-"<widget name='grScalerRadioButton' "
-"type='Radiobutton' "
-"width='20' "
-"/>"
 "<widget name='grScalerPopupDesc' "
 "type='OptionsLabel' "
 "/>"
@@ -1754,10 +1750,6 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "/>"
 "</layout>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='10' align='center'>"
-"<widget name='grShaderRadioButton' "
-"type='Radiobutton' "
-"width='20' "
-"/>"
 "<widget name='grShaderButton' "
 "type='Button' "
 "/>"
@@ -3653,10 +3645,6 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "/>"
 "</layout>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='6' align='center'>"
-"<widget name='grScalerRadioButton' "
-"type='Radiobutton' "
-"width='10' "
-"/>"
 "<widget name='grScalerPopupDesc' "
 "type='OptionsLabel' "
 "/>"
@@ -3668,10 +3656,6 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "/>"
 "</layout>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='6' align='center'>"
-"<widget name='grShaderRadioButton' "
-"type='Radiobutton' "
-"width='10' "
-"/>"
 "<widget name='grShaderButton' "
 "type='Button' "
 "/>"
diff --git a/gui/themes/residualvm.zip b/gui/themes/residualvm.zip
index aaee529c667..23ac149d4e1 100644
Binary files a/gui/themes/residualvm.zip and b/gui/themes/residualvm.zip differ
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index 264ce05a958..8ff0c7a8956 100644
Binary files a/gui/themes/scummclassic.zip and b/gui/themes/scummclassic.zip differ
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index ed61f0f9165..ef7023cab1c 100644
Binary files a/gui/themes/scummmodern.zip and b/gui/themes/scummmodern.zip differ
diff --git a/gui/themes/scummremastered.zip b/gui/themes/scummremastered.zip
index 63a881f3853..65be13ef047 100644
Binary files a/gui/themes/scummremastered.zip and b/gui/themes/scummremastered.zip differ


Commit: 35780521756e08291c04e54c3c5efad0a64c4f4f
    https://github.com/scummvm/scummvm/commit/35780521756e08291c04e54c3c5efad0a64c4f4f
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Enable filtering on platforms where shaders are not supported

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 2d1b8be2e06..136a7460245 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -109,7 +109,6 @@ bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) const {
 	switch (f) {
 	case OSystem::kFeatureAspectRatioCorrection:
 	case OSystem::kFeatureCursorPalette:
-	//case OSystem::kFeatureFilteringMode:
 	case OSystem::kFeatureStretchMode:
 #ifdef USE_SCALERS
 	case OSystem::kFeatureScalers:
@@ -119,6 +118,10 @@ bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) const {
 #endif
 		return true;
 
+	case OSystem::kFeatureFilteringMode:
+		// Filtering is supported only in cases when shaders are not present
+		return (g_system->getOpenGLType() == OpenGL::kContextGLES);
+
 	case OSystem::kFeatureOverlaySupportsAlpha:
 		return _defaultFormatAlpha.aBits() > 3;
 
@@ -134,8 +137,11 @@ void OpenGLGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
 		_currentState.aspectRatioCorrection = enable;
 		break;
 
-#if 0
 	case OSystem::kFeatureFilteringMode:
+		// Filtering is supported only in cases when shaders are not present
+		if (g_system->getOpenGLType() != OpenGL::kContextGLES)
+			return;
+
 		assert(_transactionMode != kTransactionNone);
 		_currentState.filtering = enable;
 
@@ -155,7 +161,6 @@ void OpenGLGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
 		}
 
 		break;
-#endif
 
 	case OSystem::kFeatureCursorPalette:
 		_cursorPaletteEnabled = enable;


Commit: 4237575f65ed2073d0c2ee6ffb14d7cf4678a58f
    https://github.com/scummvm/scummvm/commit/4237575f65ed2073d0c2ee6ffb14d7cf4678a58f
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Fix crash when shaders are not supported

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index 24dd50a501c..e01b0913ee1 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -1201,10 +1201,6 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
 		_shaderButton->setEnabled(enabled);
 		_shader->setEnabled(enabled);
 		_shaderClearButton->setEnabled(enabled);
-	} else {
-		_scalerPopUpDesc->setEnabled(false);
-		_scalerPopUp->setEnabled(false);
-		_scaleFactorPopUp->setEnabled(false);
 	}
 
 	if (g_system->hasFeature(OSystem::kFeatureFilteringMode))
@@ -1949,10 +1945,6 @@ void OptionsDialog::setupGraphicsTab() {
 		_shaderButton->setVisible(true);
 		_shader->setVisible(true);
 		_shaderClearButton->setVisible(true);
-	} else {
-		_shaderButton->setVisible(false);
-		_shader->setVisible(false);
-		_shaderClearButton->setVisible(false);
 	}
 }
 


Commit: 3e7ec681d12b731b80e4431f56d498222220496f
    https://github.com/scummvm/scummvm/commit/3e7ec681d12b731b80e4431f56d498222220496f
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GUI: Do not show empty hole in Graphics tab when Filtering is not supported by the backend

Changed paths:
    gui/options.cpp


diff --git a/gui/options.cpp b/gui/options.cpp
index e01b0913ee1..e502d64f736 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -395,9 +395,6 @@ void OptionsDialog::build() {
 			_filteringCheckbox->setState(ConfMan.getBool("filtering", _domain));
 			if (ConfMan.isKeyTemporary("filtering"))
 				_filteringCheckbox->setOverride(true);
-		} else {
-			_filteringCheckbox->setState(false);
-			_filteringCheckbox->setEnabled(false);
 		}
 
 		// Aspect ratio setting
@@ -574,11 +571,12 @@ void OptionsDialog::apply() {
 	// Graphic options
 	if (_fullscreenCheckbox) {
 		if (_enableGraphicSettings) {
-			if (ConfMan.getBool("filtering", _domain) != _filteringCheckbox->getState()) {
-				graphicsModeChanged = true;
-				ConfMan.setBool("filtering", _filteringCheckbox->getState(), _domain);
-				_filteringCheckbox->setOverride(false);
-			}
+			if (g_system->hasFeature(OSystem::kFeatureFilteringMode))
+				if (ConfMan.getBool("filtering", _domain) != _filteringCheckbox->getState()) {
+					graphicsModeChanged = true;
+					ConfMan.setBool("filtering", _filteringCheckbox->getState(), _domain);
+					_filteringCheckbox->setOverride(false);
+				}
 			if (ConfMan.getBool("fullscreen", _domain) != _fullscreenCheckbox->getState()) {
 				graphicsModeChanged = true;
 				ConfMan.setBool("fullscreen", _fullscreenCheckbox->getState(), _domain);
@@ -1205,8 +1203,6 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
 
 	if (g_system->hasFeature(OSystem::kFeatureFilteringMode))
 		_filteringCheckbox->setEnabled(enabled);
-	else
-		_filteringCheckbox->setEnabled(false);
 
 	if (g_system->hasFeature(OSystem::kFeatureFullscreenMode))
 		_fullscreenCheckbox->setEnabled(enabled);
@@ -1579,7 +1575,8 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
 	}
 
 	// Filtering checkbox
-	_filteringCheckbox = new CheckboxWidget(boss, prefix + "grFilteringCheckbox", _("Filter graphics"), _("Use linear filtering when scaling graphics"));
+	if (g_system->hasFeature(OSystem::kFeatureFilteringMode))
+		_filteringCheckbox = new CheckboxWidget(boss, prefix + "grFilteringCheckbox", _("Filter graphics"), _("Use linear filtering when scaling graphics"));
 
 	// Aspect ratio checkbox
 	_aspectCheckbox = new CheckboxWidget(boss, prefix + "grAspectCheckbox", _("Aspect ratio correction"), _("Correct aspect ratio for games"));
@@ -1923,8 +1920,7 @@ void OptionsDialog::setupGraphicsTab() {
 	_fullscreenCheckbox->setVisible(true);
 	if (g_system->hasFeature(OSystem::kFeatureFilteringMode))
 		_filteringCheckbox->setVisible(true);
-	else
-		_filteringCheckbox->setVisible(false);
+
 	_aspectCheckbox->setVisible(true);
 	_renderModePopUpDesc->setVisible(true);
 	_renderModePopUp->setVisible(true);


Commit: 2e814a6956f76ffb28d7e1831f3b9f1ebd061c6b
    https://github.com/scummvm/scummvm/commit/2e814a6956f76ffb28d7e1831f3b9f1ebd061c6b
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
NEWS: Mention shader-based scalers

Changed paths:
    NEWS.md


diff --git a/NEWS.md b/NEWS.md
index 0fd9978d801..a6a763c56c4 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -15,6 +15,7 @@ For a more comprehensive changelog of the latest experimental code, see:
  General:
    - Reduced amount of false positives in Mass Add.
    - Updated the Roland MT-32 emulation code to Munt mt32emu 2.7.0.
+   - Added support for shader-based scalers.
 
  AGI:
    - Improved support for French translations.


Commit: ea578eff8ae6a1e0b4d240962c0d219f49aa2a1b
    https://github.com/scummvm/scummvm/commit/ea578eff8ae6a1e0b4d240962c0d219f49aa2a1b
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Fix license headers in the new files

Changed paths:
    backends/graphics/opengl/pipelines/libretro.cpp
    backends/graphics/opengl/pipelines/libretro.h
    backends/graphics/opengl/pipelines/libretro/parser.cpp
    backends/graphics/opengl/pipelines/libretro/parser.h
    backends/graphics/opengl/pipelines/libretro/types.h


diff --git a/backends/graphics/opengl/pipelines/libretro.cpp b/backends/graphics/opengl/pipelines/libretro.cpp
index c56f3c93d00..cde3b9de6aa 100644
--- a/backends/graphics/opengl/pipelines/libretro.cpp
+++ b/backends/graphics/opengl/pipelines/libretro.cpp
@@ -4,10 +4,10 @@
  * are too numerous to list here. Please refer to the COPYRIGHT
  * file distributed with this source distribution.
  *
- * This program 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 2
- * of the License, or (at your option) any later version.
+ * This program 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.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,8 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
diff --git a/backends/graphics/opengl/pipelines/libretro.h b/backends/graphics/opengl/pipelines/libretro.h
index 8b0ecd602bf..874646fadb3 100644
--- a/backends/graphics/opengl/pipelines/libretro.h
+++ b/backends/graphics/opengl/pipelines/libretro.h
@@ -4,10 +4,10 @@
  * are too numerous to list here. Please refer to the COPYRIGHT
  * file distributed with this source distribution.
  *
- * This program 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 2
- * of the License, or (at your option) any later version.
+ * This program 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.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,8 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
diff --git a/backends/graphics/opengl/pipelines/libretro/parser.cpp b/backends/graphics/opengl/pipelines/libretro/parser.cpp
index 00893952927..62c6bd7a506 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.cpp
+++ b/backends/graphics/opengl/pipelines/libretro/parser.cpp
@@ -4,10 +4,10 @@
  * are too numerous to list here. Please refer to the COPYRIGHT
  * file distributed with this source distribution.
  *
- * This program 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 2
- * of the License, or (at your option) any later version.
+ * This program 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.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,8 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
diff --git a/backends/graphics/opengl/pipelines/libretro/parser.h b/backends/graphics/opengl/pipelines/libretro/parser.h
index 42f0dcaf0a3..ada4d331e78 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.h
+++ b/backends/graphics/opengl/pipelines/libretro/parser.h
@@ -4,10 +4,10 @@
  * are too numerous to list here. Please refer to the COPYRIGHT
  * file distributed with this source distribution.
  *
- * This program 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 2
- * of the License, or (at your option) any later version.
+ * This program 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.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,8 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
diff --git a/backends/graphics/opengl/pipelines/libretro/types.h b/backends/graphics/opengl/pipelines/libretro/types.h
index 69c94a94ba2..575526ec878 100644
--- a/backends/graphics/opengl/pipelines/libretro/types.h
+++ b/backends/graphics/opengl/pipelines/libretro/types.h
@@ -4,10 +4,10 @@
  * are too numerous to list here. Please refer to the COPYRIGHT
  * file distributed with this source distribution.
  *
- * This program 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 2
- * of the License, or (at your option) any later version.
+ * This program 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.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,8 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
 


Commit: da08d872576eea7df804e12b598927f50ebc6af9
    https://github.com/scummvm/scummvm/commit/da08d872576eea7df804e12b598927f50ebc6af9
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Better check if shaders are supported

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 136a7460245..256dd4451ba 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -112,15 +112,15 @@ bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) const {
 	case OSystem::kFeatureStretchMode:
 #ifdef USE_SCALERS
 	case OSystem::kFeatureScalers:
-#endif
-#if !USE_FORCED_GLES
-	case OSystem::kFeatureShaders:
 #endif
 		return true;
 
+	case OSystem::kFeatureShaders:
+		return LibRetroPipeline::isSupportedByContext();
+
 	case OSystem::kFeatureFilteringMode:
 		// Filtering is supported only in cases when shaders are not present
-		return (g_system->getOpenGLType() == OpenGL::kContextGLES);
+		return !LibRetroPipeline::isSupportedByContext();
 
 	case OSystem::kFeatureOverlaySupportsAlpha:
 		return _defaultFormatAlpha.aBits() > 3;
@@ -139,7 +139,7 @@ void OpenGLGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
 
 	case OSystem::kFeatureFilteringMode:
 		// Filtering is supported only in cases when shaders are not present
-		if (g_system->getOpenGLType() != OpenGL::kContextGLES)
+		if (!LibRetroPipeline::isSupportedByContext())
 			return;
 
 		assert(_transactionMode != kTransactionNone);


Commit: 885f710da31361911cd01ab6a2df7847b34562ed
    https://github.com/scummvm/scummvm/commit/885f710da31361911cd01ab6a2df7847b34562ed
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Ignore comment lines in .glslp shader preset files

Changed paths:
    backends/graphics/opengl/pipelines/libretro/parser.cpp


diff --git a/backends/graphics/opengl/pipelines/libretro/parser.cpp b/backends/graphics/opengl/pipelines/libretro/parser.cpp
index 62c6bd7a506..f994ba11b5b 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.cpp
+++ b/backends/graphics/opengl/pipelines/libretro/parser.cpp
@@ -113,6 +113,20 @@ bool PresetParser::parsePreset(Common::SeekableReadStream &stream) {
 			continue;
 		}
 
+		bool empty = true;
+		for (int i = 0; i < line.size(); i++) {
+			if (line[i] == '#')
+				break;
+
+			if (!Common::isSpace(line[i])) {
+				empty = false;
+				break;
+			}
+		}
+
+		if (empty)
+			continue;
+
 		// Split line into key, value pair.
 		// TODO: Files can contain comments starting with '#', we need to
 		// handle this.


Commit: 9167451b593fdb0a77c6f60fb1e9bc759de71ba9
    https://github.com/scummvm/scummvm/commit/9167451b593fdb0a77c6f60fb1e9bc759de71ba9
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: More robust error reporting

Changed paths:
    backends/graphics/opengl/pipelines/libretro.cpp


diff --git a/backends/graphics/opengl/pipelines/libretro.cpp b/backends/graphics/opengl/pipelines/libretro.cpp
index cde3b9de6aa..27b120df86c 100644
--- a/backends/graphics/opengl/pipelines/libretro.cpp
+++ b/backends/graphics/opengl/pipelines/libretro.cpp
@@ -226,7 +226,7 @@ bool LibRetroPipeline::loadPasses() {
 
 		Common::SeekableReadStream *stream = fileNode.createReadStream();
 		if (!stream) {
-			warning("LibRetroPipeline::loadPasses: Could not open file '%s'", fileNode.getName().c_str());
+			warning("LibRetroPipeline::loadPasses: Could not open file '%s'", fileNode.isReadable() ? fileNode.getName().c_str() : i->fileName.c_str());
 			return false;
 		}
 


Commit: aa21e7226a59afa2077062a1d9a66557672d4229
    https://github.com/scummvm/scummvm/commit/aa21e7226a59afa2077062a1d9a66557672d4229
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Refactored filtering support

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp
    backends/graphics/opengl/opengl-graphics.h


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 256dd4451ba..00a8c4240e1 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -109,6 +109,7 @@ bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) const {
 	switch (f) {
 	case OSystem::kFeatureAspectRatioCorrection:
 	case OSystem::kFeatureCursorPalette:
+	case OSystem::kFeatureFilteringMode:
 	case OSystem::kFeatureStretchMode:
 #ifdef USE_SCALERS
 	case OSystem::kFeatureScalers:
@@ -118,10 +119,6 @@ bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) const {
 	case OSystem::kFeatureShaders:
 		return LibRetroPipeline::isSupportedByContext();
 
-	case OSystem::kFeatureFilteringMode:
-		// Filtering is supported only in cases when shaders are not present
-		return !LibRetroPipeline::isSupportedByContext();
-
 	case OSystem::kFeatureOverlaySupportsAlpha:
 		return _defaultFormatAlpha.aBits() > 3;
 
@@ -138,28 +135,8 @@ void OpenGLGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
 		break;
 
 	case OSystem::kFeatureFilteringMode:
-		// Filtering is supported only in cases when shaders are not present
-		if (!LibRetroPipeline::isSupportedByContext())
-			return;
-
 		assert(_transactionMode != kTransactionNone);
 		_currentState.filtering = enable;
-
-		if (_gameScreen) {
-			_gameScreen->enableLinearFiltering(enable);
-		}
-
-		if (_cursor) {
-			_cursor->enableLinearFiltering(enable);
-		}
-
-		// The overlay UI should also obey the filtering choice (managed via the Filter Graphics checkbox in Graphics Tab).
-		// Thus, when overlay filtering is disabled, scaling in OPENGL is done with GL_NEAREST (nearest neighbor scaling).
-		// It may look crude, but it should be crispier and it's left to user choice to enable filtering.
-		if (_overlay) {
-			_overlay->enableLinearFiltering(enable);
-		}
-
 		break;
 
 	case OSystem::kFeatureCursorPalette:
@@ -532,7 +509,6 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
 #endif
 
 		_gameScreen->allocate(_currentState.gameWidth, _currentState.gameHeight);
-		_gameScreen->enableLinearFiltering(_currentState.filtering);
 		// We fill the screen to all black or index 0 for CLUT8.
 #ifdef USE_RGB_COLOR
 		if (_currentState.gameFormat.bytesPerPixel == 1) {
@@ -557,6 +533,7 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
 	// aspect ratio correction and game screen changes correctly.
 	recalculateDisplayAreas();
 	recalculateCursorScaling();
+	updateLinearFiltering();
 
 	// Something changed, so update the screen change ID.
 	++_screenChangeID;
@@ -903,7 +880,7 @@ void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int
 		}
 		_cursor = createSurface(textureFormat, true, wantScaler);
 		assert(_cursor);
-		_cursor->enableLinearFiltering(_currentState.filtering);
+		updateLinearFiltering();
 #ifdef USE_SCALERS
 		if (wantScaler) {
 			_cursor->setScaler(_currentState.scalerIndex, _currentState.scaleFactor);
@@ -1140,21 +1117,14 @@ void OpenGLGraphicsManager::handleResizeImpl(const int width, const int height)
 
 		_overlay = createSurface(_defaultFormatAlpha);
 		assert(_overlay);
-		// We should NOT always filter the overlay with GL_LINEAR.
-		// In previous versions we always did use GL_LINEAR to assure the UI
-		// would be readable in case it needed to be scaled -- it would not affect it otherwise.
-		// However in modern devices due to larger screen size the UI display looks blurry
-		// when using the linear filtering scaling, and we got bug report(s) for it.
-		//   eg. https://bugs.scummvm.org/ticket/11742
-		// So, we now respect the choice for "Filter Graphics" made via ScummVM GUI (under Graphics Tab)
-		_overlay->enableLinearFiltering(_currentState.filtering);
 	}
 	_overlay->allocate(overlayWidth, overlayHeight);
 	_overlay->fill(0);
 
-	// Re-setup the scaling for the screen and cursor
+	// Re-setup the scaling and filtering for the screen and cursor
 	recalculateDisplayAreas();
 	recalculateCursorScaling();
+	updateLinearFiltering();
 
 	// Something changed, so update the screen change ID.
 	++_screenChangeID;
@@ -1538,6 +1508,38 @@ void OpenGLGraphicsManager::recalculateCursorScaling() {
 	}
 }
 
+void OpenGLGraphicsManager::updateLinearFiltering() {
+#if !USE_FORCED_GLES
+	if (_libretroPipeline && _libretroPipeline->isInitialized()) {
+		// Filtering clashes with LibRetro shaders, so it's explicitly disabled here.
+		if (_gameScreen) {
+			_gameScreen->enableLinearFiltering(false);
+		}
+
+		if (_cursor) {
+			_cursor->enableLinearFiltering(_currentState.filtering && _overlayVisible);
+		}
+	} else
+#endif
+	{
+		if (_gameScreen) {
+			_gameScreen->enableLinearFiltering(_currentState.filtering);
+		}
+
+		if (_cursor) {
+			_cursor->enableLinearFiltering(_currentState.filtering);
+		}
+	}
+
+	// The overlay UI should also obey the filtering choice (managed via the Filter Graphics checkbox in Graphics Tab).
+	// Thus, when overlay filtering is disabled, scaling in OPENGL is done with GL_NEAREST (nearest neighbor scaling).
+	// It may look crude, but it should be crispier and it's left to user choice to enable filtering.
+	if (_overlay) {
+		_overlay->enableLinearFiltering(_currentState.filtering);
+	}
+
+}
+
 #ifdef USE_OSD
 const Graphics::Font *OpenGLGraphicsManager::getFontOSD() const {
 	return FontMan.getFontByUsage(Graphics::FontManager::kLocalizedFont);
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
index 2d058a9aa08..e88d9858f3e 100644
--- a/backends/graphics/opengl/opengl-graphics.h
+++ b/backends/graphics/opengl/opengl-graphics.h
@@ -322,6 +322,8 @@ protected:
 	void recalculateDisplayAreas() override;
 	void handleResizeImpl(const int width, const int height) override;
 
+	void updateLinearFiltering();
+
 	/**
 	 * The default pixel format of the backend.
 	 */


Commit: ebc79b24bb39f6e22907bdf4ed95d6bef4c2df98
    https://github.com/scummvm/scummvm/commit/ebc79b24bb39f6e22907bdf4ed95d6bef4c2df98
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Added missing USE_FORCED_GLES check

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 00a8c4240e1..bed25322f2c 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -116,8 +116,10 @@ bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) const {
 #endif
 		return true;
 
+#if !USE_FORCED_GLES
 	case OSystem::kFeatureShaders:
 		return LibRetroPipeline::isSupportedByContext();
+#endif
 
 	case OSystem::kFeatureOverlaySupportsAlpha:
 		return _defaultFormatAlpha.aBits() > 3;


Commit: 347870e6ea67cda0afe196d19a59b2124d7968b2
    https://github.com/scummvm/scummvm/commit/347870e6ea67cda0afe196d19a59b2124d7968b2
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGLSDL: Remove _ignoreLoadVideoMode

It doesn't work properly with shaders.

Changed paths:
    backends/graphics/openglsdl/openglsdl-graphics.cpp
    backends/graphics/openglsdl/openglsdl-graphics.h


diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp
index 57754aaee67..fe57e905fa0 100644
--- a/backends/graphics/openglsdl/openglsdl-graphics.cpp
+++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp
@@ -38,7 +38,7 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(SdlEventSource *eventSource,
 #else
 	  _lastVideoModeLoad(0),
 #endif
-	  _graphicsScale(2), _ignoreLoadVideoMode(false), _gotResize(false), _wantsFullScreen(false), _ignoreResizeEvents(0),
+	  _graphicsScale(2), _gotResize(false), _wantsFullScreen(false), _ignoreResizeEvents(0),
 	  _desiredFullscreenWidth(0), _desiredFullscreenHeight(0) {
 	// Setup OpenGL attributes for SDL
 	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
@@ -330,13 +330,6 @@ void OpenGLSdlGraphicsManager::notifyResize(const int width, const int height) {
 }
 
 bool OpenGLSdlGraphicsManager::loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format) {
-	// In some cases we might not want to load the requested video mode. This
-	// will assure that the window size is not altered.
-	if (_ignoreLoadVideoMode) {
-		_ignoreLoadVideoMode = false;
-		return true;
-	}
-
 	// This function should never be called from notifyResize thus we know
 	// that the requested size came from somewhere else.
 	_gotResize = false;
@@ -713,19 +706,11 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) {
 	}
 
 	case kActionToggleAspectRatioCorrection:
-		// In case the user changed the window size manually we will
-		// not change the window size again here.
-		_ignoreLoadVideoMode = _gotResize;
-
 		// Toggles the aspect ratio correction state.
 		beginGFXTransaction();
 			setFeatureState(OSystem::kFeatureAspectRatioCorrection, !getFeatureState(OSystem::kFeatureAspectRatioCorrection));
 		endGFXTransaction();
 
-		// Make sure we do not ignore the next resize. This
-		// effectively checks whether loadVideoMode has been called.
-		assert(!_ignoreLoadVideoMode);
-
 #ifdef USE_OSD
 		if (getFeatureState(OSystem::kFeatureAspectRatioCorrection))
 			displayMessageOnOSD(_("Enabled aspect ratio correction"));
@@ -736,19 +721,11 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) {
 		return true;
 
 	case kActionToggleFilteredScaling:
-		// Never ever try to resize the window when we simply want to enable or disable filtering.
-		// This assures that the window size does not change.
-		_ignoreLoadVideoMode = true;
-
 		// Ctrl+Alt+f toggles filtering on/off
 		beginGFXTransaction();
 			setFeatureState(OSystem::kFeatureFilteringMode, !getFeatureState(OSystem::kFeatureFilteringMode));
 		endGFXTransaction();
 
-		// Make sure we do not ignore the next resize. This
-		// effectively checks whether loadVideoMode has been called.
-		assert(!_ignoreLoadVideoMode);
-
 #ifdef USE_OSD
 		if (getFeatureState(OSystem::kFeatureFilteringMode)) {
 			displayMessageOnOSD(_("Filtering enabled"));
@@ -760,9 +737,6 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) {
 		return true;
 
 	case kActionCycleStretchMode: {
-		// Never try to resize the window when changing the scaling mode.
-		_ignoreLoadVideoMode = true;
-
 		// Ctrl+Alt+s cycles through stretch mode
 		int index = 0;
 		const OSystem::GraphicsMode *stretchModes = getSupportedStretchModes();
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.h b/backends/graphics/openglsdl/openglsdl-graphics.h
index 32305e40190..a9b153c6da7 100644
--- a/backends/graphics/openglsdl/openglsdl-graphics.h
+++ b/backends/graphics/openglsdl/openglsdl-graphics.h
@@ -74,7 +74,6 @@ private:
 	uint _lastRequestedWidth;
 	uint _lastRequestedHeight;
 	uint _graphicsScale;
-	bool _ignoreLoadVideoMode;
 	bool _gotResize;
 
 #if SDL_VERSION_ATLEAST(2, 0, 0)


Commit: e7df36a30c981436080c694488bdd7bf5c56e1f1
    https://github.com/scummvm/scummvm/commit/e7df36a30c981436080c694488bdd7bf5c56e1f1
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Remove obsolete comment

Changed paths:
    backends/graphics/opengl/pipelines/libretro/parser.cpp


diff --git a/backends/graphics/opengl/pipelines/libretro/parser.cpp b/backends/graphics/opengl/pipelines/libretro/parser.cpp
index f994ba11b5b..f2daadd11d7 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.cpp
+++ b/backends/graphics/opengl/pipelines/libretro/parser.cpp
@@ -128,8 +128,6 @@ bool PresetParser::parsePreset(Common::SeekableReadStream &stream) {
 			continue;
 
 		// Split line into key, value pair.
-		// TODO: Files can contain comments starting with '#', we need to
-		// handle this.
 		Common::String::const_iterator equalIter = Common::find(line.begin(), line.end(), '=');
 		if (equalIter == line.end()) {
 			_errorDesc = "Could not find '=' in line '" + line + '\'';


Commit: 8c8b06e90817d0d58cfe4974b42b111c32e80ad6
    https://github.com/scummvm/scummvm/commit/8c8b06e90817d0d58cfe4974b42b111c32e80ad6
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GRAPHICS: Move PM5544 test pattern drawing to a separate file

Changed paths:
  A graphics/pm5544.cpp
  A graphics/pm5544.h
    graphics/module.mk
    gui/options.cpp


diff --git a/graphics/module.mk b/graphics/module.mk
index 213b8ff35a4..9b7dd5abc14 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -36,6 +36,7 @@ MODULE_OBJS := \
 	opengl/shader.o \
 	palette.o \
 	pixelformat.o \
+	pm5544.o \
 	primitives.o \
 	renderer.o \
 	scalerplugin.o \
diff --git a/graphics/pm5544.cpp b/graphics/pm5544.cpp
new file mode 100644
index 00000000000..a97e8afeedb
--- /dev/null
+++ b/graphics/pm5544.cpp
@@ -0,0 +1,286 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program 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.
+ *
+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/****************************
+ * Rendering Philips PM5544 test pattern
+ *
+ * Based on Testcard project (https://sourceforge.net/projects/testcard/)
+ *
+ * Testpattern is a simple monitor test pattern generator
+ * Copyright 2003 Jason Giglio <jgiglio at netmar.com>
+ *
+ * Licensed under GPLv2+
+ ****************************/
+
+#include "base/version.h"
+
+#include "graphics/managed_surface.h"
+#include "graphics/fonts/amigafont.h"
+
+namespace Graphics {
+
+enum {
+	BLACK = 0, WHITE, RED, GREEN, BLUE, CYAN, MAGENTA,
+	YELLOW, GRAY1, GREEN1, GREEN2, RED1, BLUE1, BLUE2,
+	YELLOW1, RED2, GRAY2, GRAY3, GRAY4, GRAY5, GRAY6,
+	TRANSCOLOR,
+};
+
+const uint32 paletteSrc[] = {
+	0x000000, 0xffffff, 0xFF0000, 0x00FF00, 0x0000FF, 0x00FFFF, 0xFF00FF,
+	0xFFFF00, 0x7F7F7F, 0x00C896, 0x649632, 0xC83264, 0x6464FF, 0x6496FF,
+	0xC86400, 0xE10000, 0x333333, 0x666666, 0x999999, 0xCCCCCC, 0xBFBFBF,
+	0xFE00FE,
+};
+
+static void boxColor(ManagedSurface *surface, int x1, int y1, int x2, int y2, int color) {
+	surface->fillRect(Common::Rect(x1, y1, x2 + 1, y2 + 1), color);
+}
+
+static void squaremesh(ManagedSurface *surface, int xres, int yres, int width, int height, int gapsize, int meshcolor, int squarecolor) {
+	int centerx = xres / 2;
+	int centery = yres / 2;
+
+	boxColor(surface, 0, 0, xres, yres, squarecolor);
+	for (int x = centerx % (width + gapsize) + width / 2 - (width + gapsize); x < xres; x += gapsize + width) {
+		boxColor(surface, x, 0, x + gapsize - 1, yres - 1, meshcolor);
+	}
+	for (int y = centery % (height + gapsize) + height / 2 - (height + gapsize); y < yres; y += gapsize + height) {
+		boxColor(surface, 0, y, xres - 1, y + gapsize - 1, meshcolor);
+	}
+}
+
+static void frame(ManagedSurface *surface, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int color) {
+	boxColor(surface, x1, y1, x2, y3, color);   //top
+	boxColor(surface, x1, y4, x2, y2, color);   //bottom
+	boxColor(surface, x1, y1, x3, y2, color);   //left
+	boxColor(surface, x4, y1, x2, y2, color);   //right
+}
+
+static void drawRow(ManagedSurface *surface, int offsety, int colors[], int numColors, int gap, int vsize, int xres, int offsetx) {
+	int boxsize = (xres - (numColors + 1) * gap) / numColors;   //-gaps between boxes
+	offsetx += gap + 1;
+	for (int x = 0; x < numColors; x++) {
+		boxColor(surface, offsetx, offsety, offsetx + boxsize - 1, offsety + vsize - 1, colors[x]);
+		offsetx += (boxsize + gap);
+	}
+}
+
+static void circleColorNoblend(ManagedSurface *surface, double x, double y, double r, int color, bool invert) {
+	int sx;
+
+	r += 0.49;
+	for (sx = (int)round(x - r); sx < (int)round(x + r) + 1; sx++) {
+		double h = sqrt(r * r - pow(sx - x, 2));
+		if (invert) {
+			surface->vLine(sx, 0, -1 + (int)ceil(y - h), color);
+			surface->vLine(sx, 1 + (int)floor(y + h), surface->h, color);
+		} else
+			surface->vLine(sx, (int)ceil(y - h), (int)floor(y + h), color);
+	}
+	if (invert && sx < surface->w)
+		boxColor(surface, sx, 0, surface->w - 1, surface->h - 1, color);
+	if (invert && (int)round(x - r) > 0)
+		boxColor(surface, 0, 0, -1 + (int)round(x - r), surface->h - 1, color);
+}
+
+static void blacksquareinwhitecircle(ManagedSurface *surface, int x1, int y1, int gapsize, int rwidth, int rheight) {
+	double c1y = y1 - (gapsize + 1.0) / 2.0;
+	double c1x = x1 - (gapsize + 1.0) / 2.0;
+	circleColorNoblend(surface, c1x, c1y, rwidth * 1.5, WHITE, false);
+	boxColor(surface, x1 - rwidth - gapsize, y1 - rheight - gapsize, x1 + rwidth - 1, y1 + rheight - 1, BLACK);
+	boxColor(surface, x1 - rwidth - gapsize, y1 - gapsize, x1 + rwidth - 1, y1 - 1, WHITE);
+	boxColor(surface, x1 - gapsize, y1 - rheight - gapsize, x1 - 1, y1 + rheight - 1, WHITE);
+	circleColorNoblend(surface, c1x, c1y, gapsize + 1, WHITE, false);
+}
+
+ManagedSurface *renderPM5544(int xres, int yres) {
+	byte palette[ARRAYSIZE(paletteSrc) * 3];
+
+	for (int i = 0; i < ARRAYSIZE(paletteSrc); i++) {
+		palette[i * 3 + 0] = (paletteSrc[i] >> 16) & 0xFF;
+		palette[i * 3 + 1] = (paletteSrc[i] >>  8) & 0xFF;
+		palette[i * 3 + 2] = (paletteSrc[i]	     ) & 0xFF;
+	}
+
+	ManagedSurface *surface = new ManagedSurface(xres, yres, PixelFormat::createFormatCLUT8());
+
+    surface->setPalette(palette, 0, ARRAYSIZE(palette) / 3);
+
+	int squaresize = 8;
+	int gapsize = 2;
+
+	int width, height;
+	int rwidth, rheight;
+	int xsquares, ysquares;
+
+	int xcenter = xres / 2 - xres % 2;
+
+	bool cont = true;
+	while (cont) {
+
+		if (squaresize > 8) {
+			if (xsquares < 6 || ysquares < 6) {
+				squaresize -= 4;
+				cont = false;
+			}
+		}
+
+		squaresize += 2;
+
+		width = xres % 2 + squaresize;
+		height = yres % 2 + squaresize;
+
+		rwidth = width + gapsize;
+		rheight = height + gapsize;
+
+		xsquares = (xres - rwidth - gapsize - 16) / rwidth / 2;
+		ysquares = (yres - rheight - gapsize - 16) / rheight / 2;
+
+	}
+
+	squaremesh(surface, xres, yres, width, height, gapsize, WHITE, GRAY1);
+
+	int startx = xres / 2 - width / 2 - width % 2 - xsquares * rwidth - gapsize - 1;
+	int starty = yres / 2 - height / 2 - height % 2 - ysquares * rheight - gapsize - 1;
+	int endx = startx + rwidth * (2 * xsquares + 1) + gapsize + 1;
+	int endy = starty + rheight * (2 * ysquares + 1) + gapsize + 1;
+	int i;
+
+	frame(surface, 0, 0, xres, yres, 1, 1, xres - 2, yres - 2, WHITE);
+	frame(surface, 2, 2, xres - 3, yres - 3, startx, starty, endx, endy, BLACK);
+
+	for (i = 0; i < ysquares * 2 + 1; i++) {
+		if (i % 2 == 0) {
+			boxColor(surface, 0, starty + gapsize + i * rheight, startx - 2, starty + gapsize + (i + 1) * rheight - 1, WHITE);
+			boxColor(surface, endx + 2, starty + gapsize + i * rheight, xres - 1, starty + gapsize + (i + 1) * rheight - 1, WHITE);
+		}
+
+	}
+	for (i = 0; i < xsquares * 2 + 1; i++) {
+		if (i % 2 == 0) {
+			boxColor(surface, startx + gapsize + i * rwidth, 0, startx + gapsize + (i + 1) * rwidth - 1, starty - 2, WHITE);
+			boxColor(surface, startx + gapsize + i * rwidth, endy + 2, startx + gapsize + (i + 1) * rwidth - 1, yres - 1, WHITE);
+		}
+
+	}
+
+	int monosize = 6;
+	int x1 = xres / 2 - width / 2 - width % 2 - rwidth * monosize - rwidth; //left
+	int y1 = yres / 2 - height / 2 - height % 2 - rheight * (monosize - 1); //up
+	int x2 = x1 + rwidth * (monosize * 2 + 2) + width - 1;  //right
+	int y2 = y1 + (monosize * 2 - 1) * rheight - gapsize - 1;   //bottom
+
+	if (xsquares - 1 > monosize) {
+		boxColor(surface, x1, y1, x1 + width - 1, yres / 2, GREEN1);	//up left
+		boxColor(surface, x2 - width + 1, y1, x2, yres / 2, GREEN2);	//up right
+		boxColor(surface, x1, yres / 2 + yres % 2, x1 + width - 1, y2, RED1); //bottom left
+		boxColor(surface, x2 - width + 1, yres / 2 + yres % 2, x2, y2, BLUE1); //bottom right
+		if (monosize > 2) {
+			boxColor(surface, x1 + width, y1, x1 + rwidth + width - 1, y1 + 2 * rheight - gapsize - 1, BLUE2); //up left small
+			boxColor(surface, x1 + width, y2 - rheight * 2 + gapsize + 1, x1 + rwidth + width - 1, y2, YELLOW1); //bottom left small
+			boxColor(surface, x2 - rwidth - width + 1, y1, x2 - width, y1 + 2 * rheight - gapsize - 1, BLUE2); //up right small
+			boxColor(surface, x2 - rwidth - width + 1, y2 - rheight * 2 + gapsize + 1, x2 - width, y2, YELLOW1); //bottom right small
+		}
+	}
+
+	if (xsquares - 4 > monosize) {
+		blacksquareinwhitecircle(surface, x1 - rwidth * 2, y1 + rheight, gapsize, rwidth, rheight);
+		blacksquareinwhitecircle(surface, x2 + rwidth * 2 + gapsize + 1, y1 + rheight, gapsize, rwidth, rheight);
+		blacksquareinwhitecircle(surface, x1 - rwidth * 2, y2 - height + 1, gapsize, rwidth, rheight);
+		blacksquareinwhitecircle(surface, x2 + rwidth * 2 + gapsize + 1, y2 - height + 1, gapsize, rwidth, rheight);
+	}
+
+	int monoradius = monosize * rwidth + gapsize;
+	ManagedSurface *monoscope = new ManagedSurface(xres, yres, PixelFormat::createFormatCLUT8());
+
+	// two bottom rows
+	boxColor(monoscope, x1, y2 - rheight + gapsize / 2 + 1, x2, y2 + rheight + gapsize / 2 + 1, YELLOW);
+	boxColor(monoscope, xcenter - rwidth / 2, y2 - rheight + gapsize / 2 + 1, xcenter - rwidth / 2 + rwidth, y2 + rheight + gapsize / 2 + 1, RED2);
+
+	boxColor(monoscope, x1, y2 - 2 * rheight + gapsize / 2 + 1, x2, y2 - rheight + gapsize / 2, WHITE);
+	boxColor(monoscope, xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight + gapsize / 2, BLACK);
+
+	// two top rows
+	boxColor(monoscope, x1, y2 - 12 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 10 + gapsize / 2, WHITE);
+	boxColor(monoscope, xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 2, y2 - rheight * 10 + gapsize / 2, BLACK);
+
+	boxColor(monoscope, x1, y2 - 10 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 9 + gapsize / 2, BLACK);
+	boxColor(monoscope, xres / 2 - rwidth * 3, y2 - 10 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight * 9 + gapsize / 2, WHITE);
+
+	// color (gray) bars
+	int greyColors[] = { BLACK, GRAY2, GRAY3, GRAY4, GRAY5, WHITE};
+	drawRow(monoscope, y2 - 3 * rheight + gapsize / 2 + 1, greyColors, 6, 0, rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
+
+	boxColor(monoscope, x1, y2 - 6 * rheight + gapsize / 2 + 1, x2, y2 - 3 * rheight + gapsize / 2, BLACK);
+
+	int topColors[] = { YELLOW, CYAN, GREEN, MAGENTA, RED, BLUE };
+	drawRow(monoscope, y2 - 8 * rheight + gapsize / 2 + 1, topColors, 6, 0, 2 * rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
+
+	// periodic gray and white
+	int periodsize = monosize * (rwidth * 2) * 11 / 16 / 6;
+	int blacksize = periodsize * 6 / 11;
+	boxColor(monoscope, x1, y2 - 9 * rheight + gapsize / 2 + 1, x2, y2 - 8 * rheight + gapsize / 2, GRAY6);
+	for (i = 0; i < 5; i++) {
+		boxColor(monoscope, xres / 2 + i * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 + i * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2, BLACK);
+		boxColor(monoscope, xres / 2 - (i + 1) * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 - (i + 1) * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2, BLACK);
+	}
+
+	// small lines
+	int xmin = xcenter - rwidth / 2 - rwidth * 4;
+	int xmax = xcenter - rwidth / 2 + rwidth * 5;
+	int step;
+	int alternatingColors[] = { WHITE, BLACK };
+	int blackorwhite = 0;
+	for (i = xmin; i < xmax; i++) {
+		step = 6 * (xmax - i - 1) / (xmax - xmin) + 1;
+		boxColor(monoscope, i, y2 - 5 * rheight + gapsize / 2 + 1, i + step - 1, y2 - 3 * rheight + gapsize / 2, alternatingColors[blackorwhite++ % 2]);
+		i += step - 1;
+	}
+
+	// horizontal middle part
+	boxColor(monoscope, xcenter - rwidth / 2, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2 + xres % 2 + rwidth / 2 - 1, y2 - 4 * rheight + gapsize / 2, BLACK);
+	boxColor(monoscope, xres / 2 + xres % 2 - 1, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2, y2 - 4 * rheight + gapsize / 2, WHITE);
+	boxColor(monoscope, x1, yres / 2 + yres % 2 - 1, x2, yres / 2, WHITE);
+
+	// vertical lines in the middle
+	for (i = x1 - gapsize; i < x2 + gapsize; i += rwidth) {
+		boxColor(monoscope, i, y2 - 6 * rheight + gapsize / 2 + 1, i + gapsize - 1, y2 - 5 * rheight + gapsize / 2, WHITE);
+	}
+
+	circleColorNoblend(monoscope, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, 3, WHITE, false);
+	circleColorNoblend(monoscope, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, monoradius, TRANSCOLOR, true);
+
+    surface->transBlitFrom(*monoscope, TRANSCOLOR);
+
+	delete monoscope;
+
+	Graphics::AmigaFont font;
+
+	y2 += (rheight - font.getFontHeight()) / 2;
+
+	font.drawString(surface, "ScummVM", xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, rwidth * 4, WHITE, Graphics::kTextAlignCenter);
+	font.drawString(surface, gScummVMVersion, xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, rwidth * 6, WHITE);
+
+    return surface;
+}
+
+}  // End of namespace Graphics
diff --git a/graphics/pm5544.h b/graphics/pm5544.h
new file mode 100644
index 00000000000..c4897f9d9ea
--- /dev/null
+++ b/graphics/pm5544.h
@@ -0,0 +1,28 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program 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.
+ *
+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Graphics {
+
+class ManagedSurface;
+
+ManagedSurface *renderPM5544(int width, int height);
+
+}  // End of namespace Graphics
diff --git a/gui/options.cpp b/gui/options.cpp
index e502d64f736..243706dd9c5 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -64,9 +64,8 @@
 #endif
 #endif
 
-#include "base/version.h"
-#include "graphics/fonts/amigafont.h"
 #include "graphics/palette.h"
+#include "graphics/pm5544.h"
 #include "graphics/renderer.h"
 #include "graphics/scalerplugin.h"
 
@@ -3606,288 +3605,30 @@ void GlobalOptionsDialog::storageErrorCallback(Networking::ErrorResponse respons
 #endif // USE_LIBCURL
 #endif // USE_CLOUD
 
-/****************************
- * Shader test screen
- *
- * Based on Testcard project (https://sourceforge.net/projects/testcard/)
- *
- * Testpattern is a simple monitor test pattern generator
- * Copyright 2003 Jason Giglio <jgiglio at netmar.com>
- *
- * Licensed under GPLv2+
- ****************************/
-
-enum {
-	BLACK = 0, WHITE, RED, GREEN, BLUE, CYAN, MAGENTA,
-	YELLOW, GRAY1, GREEN1, GREEN2, RED1, BLUE1, BLUE2,
-	YELLOW1, RED2, GRAY2, GRAY3, GRAY4, GRAY5, GRAY6,
-	TRANSCOLOR,
-};
-
-const uint32 paletteSrc[] = {
-	0x000000, 0xffffff, 0xFF0000, 0x00FF00, 0x0000FF, 0x00FFFF, 0xFF00FF,
-	0xFFFF00, 0x7F7F7F, 0x00C896, 0x649632, 0xC83264, 0x6464FF, 0x6496FF,
-	0xC86400, 0xE10000, 0x333333, 0x666666, 0x999999, 0xCCCCCC, 0xBFBFBF,
-	0xFE00FE,
-};
-
-static void boxColor(Graphics::Surface &surface, int x1, int y1, int x2, int y2, int color) {
-	surface.fillRect(Common::Rect(x1, y1, x2 + 1, y2 + 1), color);
-}
-
-static void squaremesh(Graphics::Surface &surface, int xres, int yres, int width, int height, int gapsize, int meshcolor, int squarecolor) {
-	int centerx = xres / 2;
-	int centery = yres / 2;
-
-	boxColor(surface, 0, 0, xres, yres, squarecolor);
-	for (int x = centerx % (width + gapsize) + width / 2 - (width + gapsize); x < xres; x += gapsize + width) {
-		boxColor(surface, x, 0, x + gapsize - 1, yres - 1, meshcolor);
-	}
-	for (int y = centery % (height + gapsize) + height / 2 - (height + gapsize); y < yres; y += gapsize + height) {
-		boxColor(surface, 0, y, xres - 1, y + gapsize - 1, meshcolor);
-	}
-}
-
-static void frame(Graphics::Surface &surface, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int color) {
-	boxColor(surface, x1, y1, x2, y3, color);   //top
-	boxColor(surface, x1, y4, x2, y2, color);   //bottom
-	boxColor(surface, x1, y1, x3, y2, color);   //left
-	boxColor(surface, x4, y1, x2, y2, color);   //right
-}
-
-static void drawRow(Graphics::Surface &surface, int offsety, int colors[], int numColors, int gap, int vsize, int xres, int offsetx) {
-	int boxsize = (xres - (numColors + 1) * gap) / numColors;   //-gaps between boxes
-	offsetx += gap + 1;
-	for (int x = 0; x < numColors; x++) {
-		boxColor(surface, offsetx, offsety, offsetx + boxsize - 1, offsety + vsize - 1, colors[x]);
-		offsetx += (boxsize + gap);
-	}
-}
-
-static void circleColorNoblend(Graphics::Surface &surface, double x, double y, double r, int color, bool invert) {
-	int sx;
-
-	r += 0.49;
-	for (sx = (int)round(x - r); sx < (int)round(x + r) + 1; sx++) {
-		double h = sqrt(r * r - pow(sx - x, 2));
-		if (invert) {
-			surface.vLine(sx, 0, -1 + (int)ceil(y - h), color);
-			surface.vLine(sx, 1 + (int)floor(y + h), surface.h, color);
-		} else
-			surface.vLine(sx, (int)ceil(y - h), (int)floor(y + h), color);
-	}
-	if (invert && sx < surface.w)
-		boxColor(surface, sx, 0, surface.w - 1, surface.h - 1, color);
-	if (invert && (int)round(x - r) > 0)
-		boxColor(surface, 0, 0, -1 + (int)round(x - r), surface.h - 1, color);
-}
-
-static void blacksquareinwhitecircle(Graphics::Surface &surface, int x1, int y1, int gapsize, int rwidth, int rheight) {
-	double c1y = y1 - (gapsize + 1.0) / 2.0;
-	double c1x = x1 - (gapsize + 1.0) / 2.0;
-	circleColorNoblend(surface, c1x, c1y, rwidth * 1.5, WHITE, false);
-	boxColor(surface, x1 - rwidth - gapsize, y1 - rheight - gapsize, x1 + rwidth - 1, y1 + rheight - 1, BLACK);
-	boxColor(surface, x1 - rwidth - gapsize, y1 - gapsize, x1 + rwidth - 1, y1 - 1, WHITE);
-	boxColor(surface, x1 - gapsize, y1 - rheight - gapsize, x1 - 1, y1 + rheight - 1, WHITE);
-	circleColorNoblend(surface, c1x, c1y, gapsize + 1, WHITE, false);
-}
-
-static void drawTestPattern() {
+bool OptionsDialog::testGraphicsSettings() {
 	int xres = 320, yres = 240;
 
 	g_system->beginGFXTransaction();
 	g_system->initSize(xres, yres);
 	g_system->endGFXTransaction();
 
-	byte palette[ARRAYSIZE(paletteSrc) * 3];
-
-	for (int i = 0; i < ARRAYSIZE(paletteSrc); i++) {
-		palette[i * 3 + 0] = (paletteSrc[i] >> 16) & 0xFF;
-		palette[i * 3 + 1] = (paletteSrc[i] >>  8) & 0xFF;
-		palette[i * 3 + 2] = (paletteSrc[i]	     ) & 0xFF;
-	}
-
-	g_system->getPaletteManager()->setPalette(palette, 0, ARRAYSIZE(palette) / 3);
-
-	Graphics::Surface surface;
-
-	surface.create(xres, yres, Graphics::PixelFormat::createFormatCLUT8());
-	surface.fillRect(Common::Rect(0, 0, xres, yres), 0);
-
-	int squaresize = 8;
-	int gapsize = 2;
-
-	int width, height;
-	int rwidth, rheight;
-	int xsquares, ysquares;
-
-	int xcenter = xres / 2 - xres % 2;
-
-	bool cont = true;
-	while (cont) {
-
-		if (squaresize > 8) {
-			if (xsquares < 6 || ysquares < 6) {
-				squaresize -= 4;
-				cont = false;
-			}
-		}
-
-		squaresize += 2;
-
-		width = xres % 2 + squaresize;
-		height = yres % 2 + squaresize;
-
-		rwidth = width + gapsize;
-		rheight = height + gapsize;
-
-		xsquares = (xres - rwidth - gapsize - 16) / rwidth / 2;
-		ysquares = (yres - rheight - gapsize - 16) / rheight / 2;
+	Graphics::ManagedSurface *pm5544 = Graphics::renderPM5544(xres, yres);
 
-	}
-
-	squaremesh(surface, xres, yres, width, height, gapsize, WHITE, GRAY1);
-
-	int startx = xres / 2 - width / 2 - width % 2 - xsquares * rwidth - gapsize - 1;
-	int starty = yres / 2 - height / 2 - height % 2 - ysquares * rheight - gapsize - 1;
-	int endx = startx + rwidth * (2 * xsquares + 1) + gapsize + 1;
-	int endy = starty + rheight * (2 * ysquares + 1) + gapsize + 1;
-	int i;
-
-	frame(surface, 0, 0, xres, yres, 1, 1, xres - 2, yres - 2, WHITE);
-	frame(surface, 2, 2, xres - 3, yres - 3, startx, starty, endx, endy, BLACK);
-
-	for (i = 0; i < ysquares * 2 + 1; i++) {
-		if (i % 2 == 0) {
-			boxColor(surface, 0, starty + gapsize + i * rheight, startx - 2, starty + gapsize + (i + 1) * rheight - 1, WHITE);
-			boxColor(surface, endx + 2, starty + gapsize + i * rheight, xres - 1, starty + gapsize + (i + 1) * rheight - 1, WHITE);
-		}
-
-	}
-	for (i = 0; i < xsquares * 2 + 1; i++) {
-		if (i % 2 == 0) {
-			boxColor(surface, startx + gapsize + i * rwidth, 0, startx + gapsize + (i + 1) * rwidth - 1, starty - 2, WHITE);
-			boxColor(surface, startx + gapsize + i * rwidth, endy + 2, startx + gapsize + (i + 1) * rwidth - 1, yres - 1, WHITE);
-		}
-
-	}
-
-	int monosize = 6;
-	int x1 = xres / 2 - width / 2 - width % 2 - rwidth * monosize - rwidth; //left
-	int y1 = yres / 2 - height / 2 - height % 2 - rheight * (monosize - 1); //up
-	int x2 = x1 + rwidth * (monosize * 2 + 2) + width - 1;  //right
-	int y2 = y1 + (monosize * 2 - 1) * rheight - gapsize - 1;   //bottom
-
-	if (xsquares - 1 > monosize) {
-		boxColor(surface, x1, y1, x1 + width - 1, yres / 2, GREEN1);	//up left
-		boxColor(surface, x2 - width + 1, y1, x2, yres / 2, GREEN2);	//up right
-		boxColor(surface, x1, yres / 2 + yres % 2, x1 + width - 1, y2, RED1); //bottom left
-		boxColor(surface, x2 - width + 1, yres / 2 + yres % 2, x2, y2, BLUE1); //bottom right
-		if (monosize > 2) {
-			boxColor(surface, x1 + width, y1, x1 + rwidth + width - 1, y1 + 2 * rheight - gapsize - 1, BLUE2); //up left small
-			boxColor(surface, x1 + width, y2 - rheight * 2 + gapsize + 1, x1 + rwidth + width - 1, y2, YELLOW1); //bottom left small
-			boxColor(surface, x2 - rwidth - width + 1, y1, x2 - width, y1 + 2 * rheight - gapsize - 1, BLUE2); //up right small
-			boxColor(surface, x2 - rwidth - width + 1, y2 - rheight * 2 + gapsize + 1, x2 - width, y2, YELLOW1); //bottom right small
-		}
-	}
-
-	if (xsquares - 4 > monosize) {
-		blacksquareinwhitecircle(surface, x1 - rwidth * 2, y1 + rheight, gapsize, rwidth, rheight);
-		blacksquareinwhitecircle(surface, x2 + rwidth * 2 + gapsize + 1, y1 + rheight, gapsize, rwidth, rheight);
-		blacksquareinwhitecircle(surface, x1 - rwidth * 2, y2 - height + 1, gapsize, rwidth, rheight);
-		blacksquareinwhitecircle(surface, x2 + rwidth * 2 + gapsize + 1, y2 - height + 1, gapsize, rwidth, rheight);
-	}
-
-	int monoradius = monosize * rwidth + gapsize;
-	Graphics::Surface monoscope;
-	monoscope.create(xres, yres, Graphics::PixelFormat::createFormatCLUT8());
-
-	// two bottom rows
-	boxColor(monoscope, x1, y2 - rheight + gapsize / 2 + 1, x2, y2 + rheight + gapsize / 2 + 1, YELLOW);
-	boxColor(monoscope, xcenter - rwidth / 2, y2 - rheight + gapsize / 2 + 1, xcenter - rwidth / 2 + rwidth, y2 + rheight + gapsize / 2 + 1, RED2);
-
-	boxColor(monoscope, x1, y2 - 2 * rheight + gapsize / 2 + 1, x2, y2 - rheight + gapsize / 2, WHITE);
-	boxColor(monoscope, xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight + gapsize / 2, BLACK);
-
-	// two top rows
-	boxColor(monoscope, x1, y2 - 12 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 10 + gapsize / 2, WHITE);
-	boxColor(monoscope, xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 2, y2 - rheight * 10 + gapsize / 2, BLACK);
+	byte palette[768];
+	const uint32 *p = pm5544->getPalette();
 
-	boxColor(monoscope, x1, y2 - 10 * rheight + gapsize / 2 + 1, x2, y2 - rheight * 9 + gapsize / 2, BLACK);
-	boxColor(monoscope, xres / 2 - rwidth * 3, y2 - 10 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight * 9 + gapsize / 2, WHITE);
-
-	// color (gray) bars
-	int greyColors[] = { BLACK, GRAY2, GRAY3, GRAY4, GRAY5, WHITE};
-	drawRow(monoscope, y2 - 3 * rheight + gapsize / 2 + 1, greyColors, 6, 0, rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
-
-	boxColor(monoscope, x1, y2 - 6 * rheight + gapsize / 2 + 1, x2, y2 - 3 * rheight + gapsize / 2, BLACK);
-
-	int topColors[] = { YELLOW, CYAN, GREEN, MAGENTA, RED, BLUE };
-	drawRow(monoscope, y2 - 8 * rheight + gapsize / 2 + 1, topColors, 6, 0, 2 * rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
-
-	// periodic gray and white
-	int periodsize = monosize * (rwidth * 2) * 11 / 16 / 6;
-	int blacksize = periodsize * 6 / 11;
-	boxColor(monoscope, x1, y2 - 9 * rheight + gapsize / 2 + 1, x2, y2 - 8 * rheight + gapsize / 2, GRAY6);
-	for (i = 0; i < 5; i++) {
-		boxColor(monoscope, xres / 2 + i * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 + i * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2, BLACK);
-		boxColor(monoscope, xres / 2 - (i + 1) * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 - (i + 1) * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2, BLACK);
-	}
-
-	// small lines
-	int xmin = xcenter - rwidth / 2 - rwidth * 4;
-	int xmax = xcenter - rwidth / 2 + rwidth * 5;
-	int step;
-	int alternatingColors[] = { WHITE, BLACK };
-	int blackorwhite = 0;
-	for (i = xmin; i < xmax; i++) {
-		step = 6 * (xmax - i - 1) / (xmax - xmin) + 1;
-		boxColor(monoscope, i, y2 - 5 * rheight + gapsize / 2 + 1, i + step - 1, y2 - 3 * rheight + gapsize / 2, alternatingColors[blackorwhite++ % 2]);
-		i += step - 1;
+	for (int i = 0; i < 256; i++) {
+		palette[i * 3 + 0] =  p[i]        & 0xff;
+		palette[i * 3 + 1] = (p[i] >> 8)  & 0xff;
+		palette[i * 3 + 2] = (p[i] >> 16) & 0xff;
 	}
 
-	// horizontal middle part
-	boxColor(monoscope, xcenter - rwidth / 2, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2 + xres % 2 + rwidth / 2 - 1, y2 - 4 * rheight + gapsize / 2, BLACK);
-	boxColor(monoscope, xres / 2 + xres % 2 - 1, y2 - 7 * rheight + gapsize / 2 + 1, xres / 2, y2 - 4 * rheight + gapsize / 2, WHITE);
-	boxColor(monoscope, x1, yres / 2 + yres % 2 - 1, x2, yres / 2, WHITE);
-
-	// vertical lines in the middle
-	for (i = x1 - gapsize; i < x2 + gapsize; i += rwidth) {
-		boxColor(monoscope, i, y2 - 6 * rheight + gapsize / 2 + 1, i + gapsize - 1, y2 - 5 * rheight + gapsize / 2, WHITE);
-	}
-
-	circleColorNoblend(monoscope, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, 3, WHITE, false);
-	circleColorNoblend(monoscope, (xres - 1.0) / 2.0, (yres - 1.0) / 2.0, monoradius, TRANSCOLOR, true);
-
-	for (int y = 0; y < yres; y++) {
-		byte *src = (byte *)monoscope.getBasePtr(0, y);
-		byte *dst = (byte *)surface.getBasePtr(0, y);
-
-		for (int x = 0; x < xres; x++) {
-			if (*src != TRANSCOLOR)
-				*dst = *src;
+	g_system->getPaletteManager()->setPalette(palette, 0, 256);
 
-			dst++, src++;
-		}
-	}
-
-	monoscope.free();
-
-	Graphics::AmigaFont font;
-
-	y2 += (rheight - font.getFontHeight()) / 2;
-
-	font.drawString(&surface, "ScummVM", xres / 2 - rwidth * 2, y2 - 11 * rheight + gapsize / 2 + 1, rwidth * 4, WHITE, Graphics::kTextAlignCenter);
-	font.drawString(&surface, gScummVMVersion, xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, rwidth * 6, WHITE);
-
-	g_system->copyRectToScreen(surface.getPixels(), surface.pitch, 0, 0, xres, yres);
+	g_system->copyRectToScreen(pm5544->surfacePtr()->getPixels(), pm5544->surfacePtr()->pitch, 0, 0, xres, yres);
 	g_system->updateScreen();
 
-	surface.free();
-}
-
-bool OptionsDialog::testGraphicsSettings() {
-	drawTestPattern();
+	delete pm5544;
 
 	// And display the error
 	GUI::CountdownMessageDialog dialog(_("A test pattern should be displayed.\nDo you want to keep these shader scalar settings?"),
@@ -3902,7 +3643,7 @@ bool OptionsDialog::testGraphicsSettings() {
 	g_gui.displayTopDialogOnly(false);
 
 	// Clear screen so we do not see any artefacts
-	g_system->fillScreen(BLACK);
+	g_system->fillScreen(0);
 	g_system->updateScreen();
 
 	return retval;


Commit: 37ba3744f7266dc13feb9cda9dd4681db5297ad2
    https://github.com/scummvm/scummvm/commit/37ba3744f7266dc13feb9cda9dd4681db5297ad2
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GRAPHICS: Use proper color names in PM5544

Changed paths:
    graphics/pm5544.cpp


diff --git a/graphics/pm5544.cpp b/graphics/pm5544.cpp
index a97e8afeedb..097a909050c 100644
--- a/graphics/pm5544.cpp
+++ b/graphics/pm5544.cpp
@@ -38,16 +38,16 @@
 namespace Graphics {
 
 enum {
-	BLACK = 0, WHITE, RED, GREEN, BLUE, CYAN, MAGENTA,
-	YELLOW, GRAY1, GREEN1, GREEN2, RED1, BLUE1, BLUE2,
-	YELLOW1, RED2, GRAY2, GRAY3, GRAY4, GRAY5, GRAY6,
+	BLACK = 0, WHITE, RED, GREEN, BLUE, CYAN, MAGENTA, YELLOW,
+	COLOR270, COLOR180, COLOR90, COLOR0, COLOR326, COLOR146, RED88,
+	GRAY20, GRAY40, GRAY50, GRAY60, GRAY80, GRAY75,
 	TRANSCOLOR,
 };
 
 const uint32 paletteSrc[] = {
-	0x000000, 0xffffff, 0xFF0000, 0x00FF00, 0x0000FF, 0x00FFFF, 0xFF00FF,
-	0xFFFF00, 0x7F7F7F, 0x00C896, 0x649632, 0xC83264, 0x6464FF, 0x6496FF,
-	0xC86400, 0xE10000, 0x333333, 0x666666, 0x999999, 0xCCCCCC, 0xBFBFBF,
+	0x000000, 0xffffff, 0xFF0000, 0x00FF00, 0x0000FF, 0x00FFFF, 0xFF00FF, 0xFFFF00,
+	0x00C896, 0x649632, 0xC83264, 0x6464FF, 0x6496FF, 0xC86400, 0xE10000,
+	0x333333, 0x666666, 0x7F7F7F, 0x999999, 0xCCCCCC, 0xBFBFBF,
 	0xFE00FE,
 };
 
@@ -157,7 +157,7 @@ ManagedSurface *renderPM5544(int xres, int yres) {
 
 	}
 
-	squaremesh(surface, xres, yres, width, height, gapsize, WHITE, GRAY1);
+	squaremesh(surface, xres, yres, width, height, gapsize, WHITE, GRAY50);
 
 	int startx = xres / 2 - width / 2 - width % 2 - xsquares * rwidth - gapsize - 1;
 	int starty = yres / 2 - height / 2 - height % 2 - ysquares * rheight - gapsize - 1;
@@ -190,15 +190,15 @@ ManagedSurface *renderPM5544(int xres, int yres) {
 	int y2 = y1 + (monosize * 2 - 1) * rheight - gapsize - 1;   //bottom
 
 	if (xsquares - 1 > monosize) {
-		boxColor(surface, x1, y1, x1 + width - 1, yres / 2, GREEN1);	//up left
-		boxColor(surface, x2 - width + 1, y1, x2, yres / 2, GREEN2);	//up right
-		boxColor(surface, x1, yres / 2 + yres % 2, x1 + width - 1, y2, RED1); //bottom left
-		boxColor(surface, x2 - width + 1, yres / 2 + yres % 2, x2, y2, BLUE1); //bottom right
+		boxColor(surface, x1, y1, x1 + width - 1, yres / 2, COLOR270);	//up left
+		boxColor(surface, x2 - width + 1, y1, x2, yres / 2, COLOR180);	//up right
+		boxColor(surface, x1, yres / 2 + yres % 2, x1 + width - 1, y2, COLOR90); //bottom left
+		boxColor(surface, x2 - width + 1, yres / 2 + yres % 2, x2, y2, COLOR0); //bottom right
 		if (monosize > 2) {
-			boxColor(surface, x1 + width, y1, x1 + rwidth + width - 1, y1 + 2 * rheight - gapsize - 1, BLUE2); //up left small
-			boxColor(surface, x1 + width, y2 - rheight * 2 + gapsize + 1, x1 + rwidth + width - 1, y2, YELLOW1); //bottom left small
-			boxColor(surface, x2 - rwidth - width + 1, y1, x2 - width, y1 + 2 * rheight - gapsize - 1, BLUE2); //up right small
-			boxColor(surface, x2 - rwidth - width + 1, y2 - rheight * 2 + gapsize + 1, x2 - width, y2, YELLOW1); //bottom right small
+			boxColor(surface, x1 + width, y1, x1 + rwidth + width - 1, y1 + 2 * rheight - gapsize - 1, COLOR326); //up left small
+			boxColor(surface, x1 + width, y2 - rheight * 2 + gapsize + 1, x1 + rwidth + width - 1, y2, COLOR146); //bottom left small
+			boxColor(surface, x2 - rwidth - width + 1, y1, x2 - width, y1 + 2 * rheight - gapsize - 1, COLOR326); //up right small
+			boxColor(surface, x2 - rwidth - width + 1, y2 - rheight * 2 + gapsize + 1, x2 - width, y2, COLOR146); //bottom right small
 		}
 	}
 
@@ -214,7 +214,7 @@ ManagedSurface *renderPM5544(int xres, int yres) {
 
 	// two bottom rows
 	boxColor(monoscope, x1, y2 - rheight + gapsize / 2 + 1, x2, y2 + rheight + gapsize / 2 + 1, YELLOW);
-	boxColor(monoscope, xcenter - rwidth / 2, y2 - rheight + gapsize / 2 + 1, xcenter - rwidth / 2 + rwidth, y2 + rheight + gapsize / 2 + 1, RED2);
+	boxColor(monoscope, xcenter - rwidth / 2, y2 - rheight + gapsize / 2 + 1, xcenter - rwidth / 2 + rwidth, y2 + rheight + gapsize / 2 + 1, RED88);
 
 	boxColor(monoscope, x1, y2 - 2 * rheight + gapsize / 2 + 1, x2, y2 - rheight + gapsize / 2, WHITE);
 	boxColor(monoscope, xres / 2 - rwidth * 3, y2 - 2 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight + gapsize / 2, BLACK);
@@ -227,7 +227,7 @@ ManagedSurface *renderPM5544(int xres, int yres) {
 	boxColor(monoscope, xres / 2 - rwidth * 3, y2 - 10 * rheight + gapsize / 2 + 1, xres / 2 + rwidth * 3, y2 - rheight * 9 + gapsize / 2, WHITE);
 
 	// color (gray) bars
-	int greyColors[] = { BLACK, GRAY2, GRAY3, GRAY4, GRAY5, WHITE};
+	int greyColors[] = { BLACK, GRAY20, GRAY40, GRAY60, GRAY80, WHITE};
 	drawRow(monoscope, y2 - 3 * rheight + gapsize / 2 + 1, greyColors, 6, 0, rheight, monosize * (rwidth * 2) + 6, xres / 2 - rwidth * monosize - 4);
 
 	boxColor(monoscope, x1, y2 - 6 * rheight + gapsize / 2 + 1, x2, y2 - 3 * rheight + gapsize / 2, BLACK);
@@ -238,7 +238,7 @@ ManagedSurface *renderPM5544(int xres, int yres) {
 	// periodic gray and white
 	int periodsize = monosize * (rwidth * 2) * 11 / 16 / 6;
 	int blacksize = periodsize * 6 / 11;
-	boxColor(monoscope, x1, y2 - 9 * rheight + gapsize / 2 + 1, x2, y2 - 8 * rheight + gapsize / 2, GRAY6);
+	boxColor(monoscope, x1, y2 - 9 * rheight + gapsize / 2 + 1, x2, y2 - 8 * rheight + gapsize / 2, GRAY75);
 	for (i = 0; i < 5; i++) {
 		boxColor(monoscope, xres / 2 + i * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 + i * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2, BLACK);
 		boxColor(monoscope, xres / 2 - (i + 1) * periodsize, y2 - 9 * rheight + gapsize / 2 + 1, xres / 2 - (i + 1) * periodsize + blacksize - 1, y2 - 8 * rheight + gapsize / 2, BLACK);


Commit: 6f9728c9e83fcbc4837ac59e5124683b680513ba
    https://github.com/scummvm/scummvm/commit/6f9728c9e83fcbc4837ac59e5124683b680513ba
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
GRAPHICS: Added doxygen documentation to PM5544

Changed paths:
    graphics/pm5544.h


diff --git a/graphics/pm5544.h b/graphics/pm5544.h
index c4897f9d9ea..63da1b8c75b 100644
--- a/graphics/pm5544.h
+++ b/graphics/pm5544.h
@@ -23,6 +23,15 @@ namespace Graphics {
 
 class ManagedSurface;
 
+/**
+ * Renders a Philips PM5544 test pattern on a surface with given dimensions
+ *
+ * @param width  Width of the surface
+ * @param height Height of the surface
+ *
+ * @return Returns ManagedSurface in CLUT8 format with a palette
+ */
+
 ManagedSurface *renderPM5544(int width, int height);
 
 }  // End of namespace Graphics


Commit: cb36b468645f3f001240677831d5479bebedf107
    https://github.com/scummvm/scummvm/commit/cb36b468645f3f001240677831d5479bebedf107
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Allow loading of raw shader source

Changed paths:
    graphics/opengl/shader.cpp
    graphics/opengl/shader.h


diff --git a/graphics/opengl/shader.cpp b/graphics/opengl/shader.cpp
index f894b2d39b9..e1b159612a5 100644
--- a/graphics/opengl/shader.cpp
+++ b/graphics/opengl/shader.cpp
@@ -116,10 +116,10 @@ static const GLchar *readFile(const Common::String &filename) {
 	return shaderSource;
 }
 
-GLuint Shader::createDirectShader(const char *shaderSource, GLenum shaderType, const Common::String &name) {
+GLuint Shader::createDirectShader(size_t shaderSourcesCount, const char *const *shaderSources, GLenum shaderType, const Common::String &name) {
 	GLuint shader;
 	GL_ASSIGN(shader, glCreateShader(shaderType));
-	GL_CALL(glShaderSource(shader, 1, &shaderSource, NULL));
+	GL_CALL(glShaderSource(shader, shaderSourcesCount, shaderSources, NULL));
 	GL_CALL(glCompileShader(shader));
 
 	GLint status;
@@ -213,7 +213,7 @@ GLuint Shader::loadShaderFromFile(const char *base, const char *extension, GLenu
 	if (compatGLSLVersion) {
 		shader = createCompatShader(shaderSource, shaderType, filename, compatGLSLVersion);
 	} else {
-		shader = createDirectShader(shaderSource, shaderType, filename);
+		shader = createDirectShader(1, &shaderSource, shaderType, filename);
 	}
 
 	delete[] shaderSource;
@@ -302,12 +302,12 @@ bool Shader::loadFromStrings(const Common::String &name, const char *vertex, con
 
 		fragmentShader = createCompatShader(fragment, GL_FRAGMENT_SHADER, name + ".fragment", compatGLSLVersion);
 	} else {
-		vertexShader = createDirectShader(vertex, GL_VERTEX_SHADER, name + ".vertex");
+		vertexShader = createDirectShader(1, &vertex, GL_VERTEX_SHADER, name + ".vertex");
 
 		if (!vertexShader)
 			return false;
 
-		fragmentShader = createDirectShader(fragment, GL_FRAGMENT_SHADER, name + ".fragment");
+		fragmentShader = createDirectShader(1, &fragment, GL_FRAGMENT_SHADER, name + ".fragment");
 	}
 
 	if (!fragmentShader)
@@ -316,6 +316,25 @@ bool Shader::loadFromStrings(const Common::String &name, const char *vertex, con
 	return loadShader(name, vertexShader, fragmentShader, attributes);
 }
 
+bool Shader::loadFromStringsArray(const Common::String &name,
+			size_t vertexCount, const char *const *vertex,
+			size_t fragmentCount, const char *const *fragment,
+			const char *const *attributes) {
+	GLuint vertexShader, fragmentShader;
+
+	vertexShader = createDirectShader(vertexCount, vertex, GL_VERTEX_SHADER, name + ".vertex");
+
+	if (!vertexShader)
+		return false;
+
+	fragmentShader = createDirectShader(fragmentCount, fragment, GL_FRAGMENT_SHADER, name + ".fragment");
+
+	if (!fragmentShader)
+		return false;
+
+	return loadShader(name, vertexShader, fragmentShader, attributes);
+}
+
 Shader *Shader::fromFiles(const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion) {
 	Shader *shader = new Shader;
 
diff --git a/graphics/opengl/shader.h b/graphics/opengl/shader.h
index c9110152482..16d908ec63d 100644
--- a/graphics/opengl/shader.h
+++ b/graphics/opengl/shader.h
@@ -207,6 +207,25 @@ public:
 	bool loadFromFiles(const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion = 120);
 	bool loadFromStrings(const Common::String &name, const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion = 0);
 
+	/**
+	 * Creates a shader object from strings arrays
+	 *
+	 * Everything is loaded directly without any preprocessing.
+	 *
+	 * @param name The name of the shader for errors messages
+	 * @param vertexCount The number of vertex shader code parts
+	 * @param vertex The vertex shader code parts
+	 * @param fragmentCount The number of fragment shader code parts
+	 * @param fragment The fragment shader code parts
+	 * @param attributes The vertex attributes names for indexing
+	 *
+	 * @return the loading status
+	 */
+	bool loadFromStringsArray(const Common::String &name,
+			size_t vertexCount, const char *const *vertex,
+			size_t fragmentCount, const char *const *fragment,
+			const char *const *attributes);
+
 	void unbind();
 
 	Common::String &getError() { return _error; }
@@ -216,7 +235,7 @@ private:
 	bool loadShader(const Common::String &name, GLuint vertexShader, GLuint fragmentShader, const char *const *attributes);
 
 	GLuint createCompatShader(const char *shaderSource, GLenum shaderType, const Common::String &name, int compatGLSLVersion);
-	GLuint createDirectShader(const char *shaderSource, GLenum shaderType, const Common::String &name);
+	GLuint createDirectShader(size_t shaderSourcesCount, const char *const *shaderSources, GLenum shaderType, const Common::String &name);
 	GLuint loadShaderFromFile(const char *base, const char *extension, GLenum shaderType, int compatGLSLVersion);
 
 	// Since this class is cloned using the implicit copy constructor,


Commit: 04d8265e9c94c79d6f6db27d94f7aab127a5c107
    https://github.com/scummvm/scummvm/commit/04d8265e9c94c79d6f6db27d94f7aab127a5c107
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: load shaders more like original libretro

Changed paths:
    backends/graphics/opengl/pipelines/libretro.cpp
    backends/graphics/opengl/pipelines/libretro/parser.cpp


diff --git a/backends/graphics/opengl/pipelines/libretro.cpp b/backends/graphics/opengl/pipelines/libretro.cpp
index 27b120df86c..b41fb3919a5 100644
--- a/backends/graphics/opengl/pipelines/libretro.cpp
+++ b/backends/graphics/opengl/pipelines/libretro.cpp
@@ -243,23 +243,48 @@ bool LibRetroPipeline::loadPasses() {
 		}
 
 		char *shaderFileStart = shaderFileContents.begin();
-		unsigned long shaderFileVersion = 0;
+		char version[32] = { '\0' };
 
 		// If the shader contains a version directive, it needs to be parsed and stripped out so that the VERTEX
 		// and FRAGMENT defines can be prepended to it.
 		const char *existing_version = strstr(shaderFileStart, "#version");
 		if (existing_version) {
-			shaderFileVersion = strtoul(existing_version + 8, &shaderFileStart, 10);
+			const char *shaderFileVersionExtra = "";
+			unsigned long shaderFileVersion = strtoul(existing_version + 8, &shaderFileStart, 10);
+			if (OpenGLContext.type == kContextGLES2) {
+				if (shaderFileVersion < 130) {
+					shaderFileVersion = 100;
+				} else {
+					shaderFileVersionExtra = " es";
+					shaderFileVersion = 300;
+				}
+			}
+			snprintf(version, sizeof(version), "#version %lu%s\n",
+					shaderFileVersion, shaderFileVersionExtra);
 		}
 
 		// TODO: Handle alias defines
 
 		Shader *shader = new Shader;
 
-		if (!shader->loadFromStrings(fileNode.getName(),
-				 ("#define VERTEX\n" + Common::String(shaderFileStart)).c_str(),
-				 ("#define FRAGMENT\n" + Common::String(shaderFileStart)).c_str(),
-				 g_libretroShaderAttributes, shaderFileVersion)) {
+		const char *const vertexSources[] = {
+			version,
+			"#define VERTEX\n", // "#define PARAMETER_UNIFORM\n",
+			// TODO: alias defines
+			shaderFileStart,
+		};
+		const char *const fragmentSources[] = {
+			version,
+			"#define FRAGMENT\n", // "#define PARAMETER_UNIFORM\n",
+			// TODO: alias defines
+			shaderFileStart,
+		};
+
+
+		if (!shader->loadFromStringsArray(fileNode.getName(),
+				 ARRAYSIZE(vertexSources), vertexSources,
+				 ARRAYSIZE(fragmentSources), fragmentSources,
+				 g_libretroShaderAttributes)) {
 			return false;
 		}
 
diff --git a/backends/graphics/opengl/pipelines/libretro/parser.cpp b/backends/graphics/opengl/pipelines/libretro/parser.cpp
index f2daadd11d7..845bf69d9da 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.cpp
+++ b/backends/graphics/opengl/pipelines/libretro/parser.cpp
@@ -114,7 +114,7 @@ bool PresetParser::parsePreset(Common::SeekableReadStream &stream) {
 		}
 
 		bool empty = true;
-		for (int i = 0; i < line.size(); i++) {
+		for (uint i = 0; i < line.size(); i++) {
 			if (line[i] == '#')
 				break;
 


Commit: af680aeecc0bd6c173e112dc73566386bdb73144
    https://github.com/scummvm/scummvm/commit/af680aeecc0bd6c173e112dc73566386bdb73144
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2022-10-08T23:39:18+02:00

Commit Message:
OPENGL: Check that textures can be set up at load time

Changed paths:
    backends/graphics/opengl/pipelines/libretro.cpp
    backends/graphics/opengl/pipelines/libretro.h


diff --git a/backends/graphics/opengl/pipelines/libretro.cpp b/backends/graphics/opengl/pipelines/libretro.cpp
index b41fb3919a5..195feaf05f3 100644
--- a/backends/graphics/opengl/pipelines/libretro.cpp
+++ b/backends/graphics/opengl/pipelines/libretro.cpp
@@ -310,6 +310,30 @@ bool LibRetroPipeline::loadPasses() {
 			pass.inputTexture = texture;
 		}
 	}
+
+	// Now try to setup FBOs with some dummy size to make sure it could work
+	uint bakInputWidth = _inputWidth;
+	uint bakInputHeight = _inputHeight;
+	uint bakOutputWidth = _outputWidth;
+	uint bakOutputHeight = _outputHeight;
+
+	_inputWidth = 320;
+	_inputHeight = 200;
+	_outputWidth = 640;
+	_outputHeight = 480;
+
+	bool ret = setupFBOs();
+
+	_inputWidth = bakInputWidth;
+	_inputHeight = bakInputHeight;
+	_outputWidth = bakOutputWidth;
+	_outputHeight = bakOutputHeight;
+	// Force to reset everything at next draw
+	_outputSizeChanged = true;
+
+	if (!ret) {
+		return false;
+	}
 	return true;
 }
 
@@ -324,7 +348,7 @@ void LibRetroPipeline::setPipelineState() {
 	}
 }
 
-void LibRetroPipeline::setupFBOs() {
+bool LibRetroPipeline::setupFBOs() {
 	float sourceW = _inputWidth;
 	float sourceH = _inputHeight;
 
@@ -339,6 +363,13 @@ void LibRetroPipeline::setupFBOs() {
 
 		// Resize FBO to fit the output of the pass.
 		pass.target->setSize((uint)sourceW, (uint)sourceH);
+		// Make sure it has been set correctly
+		GLint width = 0, height = 0;
+		GL_CALL(glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,  GL_TEXTURE_WIDTH, &width));
+		GL_CALL(glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,  GL_TEXTURE_HEIGHT, &height));
+		if ((uint)width != (uint)sourceW || (uint)height != (uint)sourceH) {
+			return false;
+		}
 
 		// Store draw coordinates.
 		pass.vertexCoord[0] = 0;
@@ -358,6 +389,7 @@ void LibRetroPipeline::setupFBOs() {
 		m4.setData(pass.target->getProjectionMatrix());
 		pass.shader->setUniform("MVPMatrix", m4);
 	}
+	return true;
 }
 
 void LibRetroPipeline::setupPassUniforms(const uint id) {
diff --git a/backends/graphics/opengl/pipelines/libretro.h b/backends/graphics/opengl/pipelines/libretro.h
index 874646fadb3..d7005fe5b5f 100644
--- a/backends/graphics/opengl/pipelines/libretro.h
+++ b/backends/graphics/opengl/pipelines/libretro.h
@@ -76,7 +76,7 @@ private:
 	bool loadPasses();
 
 	void setPipelineState();
-	void setupFBOs();
+	bool setupFBOs();
 	void setupPassUniforms(const uint id);
 	void setShaderTexUniforms(const Common::String &prefix, Shader *shader, const GLTexture &texture);
 




More information about the Scummvm-git-logs mailing list