Browse Source

Handle backbuffer MSAA manually in love.graphics code

Previously love would use SDL APIs to make the system (WGL etc) handle it, which meant the OpenGL context had to be recreated whenever MSAA changed.
Alex Szpakowski 4 years ago
parent
commit
7934ce0a66

+ 4 - 1
src/modules/graphics/Graphics.h

@@ -471,7 +471,7 @@ public:
 	 * @param width The viewport width.
 	 * @param width The viewport width.
 	 * @param height The viewport height.
 	 * @param height The viewport height.
 	 **/
 	 **/
-	virtual bool setMode(int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil) = 0;
+	virtual bool setMode(int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) = 0;
 
 
 	/**
 	/**
 	 * Un-sets the current graphics display mode (uninitializing objects if
 	 * Un-sets the current graphics display mode (uninitializing objects if
@@ -506,6 +506,9 @@ public:
 	double getCurrentDPIScale() const;
 	double getCurrentDPIScale() const;
 	double getScreenDPIScale() const;
 	double getScreenDPIScale() const;
 
 
+	virtual int getRequestedBackbufferMSAA() const = 0;
+	virtual int getBackbufferMSAA() const = 0;
+
 	/**
 	/**
 	 * Sets the current constant color.
 	 * Sets the current constant color.
 	 **/
 	 **/

+ 136 - 33
src/modules/graphics/opengl/Graphics.cpp

@@ -91,6 +91,8 @@ static GLenum getGLBlendFactor(BlendFactor factor)
 Graphics::Graphics()
 Graphics::Graphics()
 	: windowHasStencil(false)
 	: windowHasStencil(false)
 	, mainVAO(0)
 	, mainVAO(0)
+	, internalBackbufferFBO(0)
+	, requestedBackbufferMSAA(0)
 	, defaultBuffers()
 	, defaultBuffers()
 	, supportedFormats()
 	, supportedFormats()
 {
 {
@@ -105,14 +107,14 @@ Graphics::Graphics()
 		if (window->isOpen())
 		if (window->isOpen())
 		{
 		{
 			int w, h;
 			int w, h;
-			love::window::WindowSettings settings;
-			window->getWindow(w, h, settings);
+			love::window::WindowSettings s;
+			window->getWindow(w, h, s);
 
 
 			double dpiW = w;
 			double dpiW = w;
 			double dpiH = h;
 			double dpiH = h;
 			window->windowToDPICoords(&dpiW, &dpiH);
 			window->windowToDPICoords(&dpiW, &dpiH);
 
 
-			setMode((int) dpiW, (int) dpiH, window->getPixelWidth(), window->getPixelHeight(), settings.stencil);
+			setMode((int) dpiW, (int) dpiH, window->getPixelWidth(), window->getPixelHeight(), s.stencil, s.msaa);
 		}
 		}
 	}
 	}
 }
 }
@@ -171,14 +173,94 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh
 		// Set up the projection matrix
 		// Set up the projection matrix
 		projectionMatrix = Matrix4::ortho(0.0, (float) width, (float) height, 0.0, -10.0f, 10.0f);
 		projectionMatrix = Matrix4::ortho(0.0, (float) width, (float) height, 0.0, -10.0f, 10.0f);
 	}
 	}
+
+	updateBackbuffer(width, height, pixelwidth, pixelheight, requestedBackbufferMSAA);
+}
+
+void Graphics::updateBackbuffer(int width, int height, int /*pixelwidth*/, int pixelheight, int msaa)
+{
+	bool useinternalbackbuffer = false;
+	if (msaa > 1)
+		useinternalbackbuffer = true;
+
+	// Our internal backbuffer code needs glBlitFramebuffer.
+	if (!(GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object || GLAD_ES_VERSION_3_0
+		  || GLAD_EXT_framebuffer_blit || GLAD_ANGLE_framebuffer_blit || GLAD_NV_framebuffer_blit))
+	{
+		if (!(msaa > 1 && GLAD_APPLE_framebuffer_multisample))
+			useinternalbackbuffer = false;
+	}
+
+	GLuint prevFBO = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL);
+	bool restoreFBO = prevFBO != getInternalBackbufferFBO();
+
+	if (useinternalbackbuffer)
+	{
+		Texture::Settings settings;
+		settings.width = width;
+		settings.height = height;
+		settings.dpiScale = (float)pixelheight / (float)height;
+		settings.msaa = msaa;
+		settings.renderTarget = true;
+		settings.readable.set(false);
+
+		settings.format = isGammaCorrect() ? PIXELFORMAT_sRGBA8_UNORM : PIXELFORMAT_RGBA8_UNORM;
+		internalBackbuffer.set(newTexture(settings), Acquire::NORETAIN);
+
+		settings.format = PIXELFORMAT_DEPTH24_UNORM_STENCIL8;
+		internalBackbufferDepthStencil.set(newTexture(settings), Acquire::NORETAIN);
+
+		RenderTargets rts;
+		rts.colors.push_back(internalBackbuffer.get());
+		rts.depthStencil.texture = internalBackbufferDepthStencil;
+
+		internalBackbufferFBO = bindCachedFBO(rts);
+	}
+	else
+	{
+		internalBackbuffer.set(nullptr);
+		internalBackbufferDepthStencil.set(nullptr);
+		internalBackbufferFBO = 0;
+	}
+
+	requestedBackbufferMSAA = msaa;
+
+	if (restoreFBO)
+		gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, prevFBO);
+}
+
+GLuint Graphics::getInternalBackbufferFBO() const
+{
+	if (internalBackbufferFBO != 0)
+		return internalBackbufferFBO;
+	else
+		return getSystemBackbufferFBO();
+}
+
+GLuint Graphics::getSystemBackbufferFBO() const
+{
+#ifdef LOVE_IOS
+	// Hack: iOS uses a custom FBO.
+	SDL_SysWMinfo info = {};
+	SDL_VERSION(&info.version);
+	SDL_GetWindowWMInfo(SDL_GL_GetCurrentWindow(), &info);
+
+	if (info.info.uikit.resolveFramebuffer != 0)
+		return info.info.uikit.resolveFramebuffer;
+	else
+		return info.info.uikit.framebuffer;
+#else
+	return 0;
+#endif
 }
 }
 
 
-bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil)
+bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa)
 {
 {
 	this->width = width;
 	this->width = width;
 	this->height = height;
 	this->height = height;
 
 
 	this->windowHasStencil = windowhasstencil;
 	this->windowHasStencil = windowhasstencil;
+	this->requestedBackbufferMSAA = msaa;
 
 
 	// Okay, setup OpenGL.
 	// Okay, setup OpenGL.
 	gl.initContext();
 	gl.initContext();
@@ -194,8 +276,6 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
 	created = true;
 	created = true;
 	initCapabilities();
 	initCapabilities();
 
 
-	setViewportSize(width, height, pixelwidth, pixelheight);
-
 	// Enable blending
 	// Enable blending
 	gl.setEnableState(OpenGL::ENABLE_BLEND, true);
 	gl.setEnableState(OpenGL::ENABLE_BLEND, true);
 
 
@@ -235,6 +315,8 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
 
 
 	setDebug(isDebugEnabled());
 	setDebug(isDebugEnabled());
 
 
+	setViewportSize(width, height, pixelwidth, pixelheight);
+
 	if (batchedDrawState.vb[0] == nullptr)
 	if (batchedDrawState.vb[0] == nullptr)
 	{
 	{
 		// Initial sizes that should be good enough for most cases. It will
 		// Initial sizes that should be good enough for most cases. It will
@@ -318,6 +400,9 @@ void Graphics::unSetMode()
 
 
 	flushBatchedDraws();
 	flushBatchedDraws();
 
 
+	internalBackbuffer.set(nullptr);
+	internalBackbufferDepthStencil.set(nullptr);
+
 	// Unload all volatile objects. These must be reloaded after the display
 	// Unload all volatile objects. These must be reloaded after the display
 	// mode change.
 	// mode change.
 	Volatile::unloadAll();
 	Volatile::unloadAll();
@@ -536,7 +621,7 @@ void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int w, int h,
 
 
 	if (iswindow)
 	if (iswindow)
 	{
 	{
-		gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, gl.getDefaultFBO());
+		gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getInternalBackbufferFBO());
 
 
 		// The projection matrix is flipped compared to rendering to a texture,
 		// The projection matrix is flipped compared to rendering to a texture,
 		// due to OpenGL considering (0,0) bottom-left instead of top-left.
 		// due to OpenGL considering (0,0) bottom-left instead of top-left.
@@ -578,6 +663,8 @@ void Graphics::endPass()
 	// Discard the depth/stencil buffer if we're using an internal cached one.
 	// Discard the depth/stencil buffer if we're using an internal cached one.
 	if (depthstencil == nullptr && (rts.temporaryRTFlags & (TEMPORARY_RT_DEPTH | TEMPORARY_RT_STENCIL)) != 0)
 	if (depthstencil == nullptr && (rts.temporaryRTFlags & (TEMPORARY_RT_DEPTH | TEMPORARY_RT_STENCIL)) != 0)
 		discard({}, true);
 		discard({}, true);
+	else if (!rts.getFirstTarget().texture.get())
+		discard({}, true); // Backbuffer
 
 
 	// Resolve MSAA buffers. MSAA is only supported for 2D render targets so we
 	// Resolve MSAA buffers. MSAA is only supported for 2D render targets so we
 	// don't have to worry about resolving to slices.
 	// don't have to worry about resolving to slices.
@@ -796,7 +883,7 @@ void Graphics::discard(OpenGL::FramebufferTarget target, const std::vector<bool>
 	attachments.reserve(colorbuffers.size());
 	attachments.reserve(colorbuffers.size());
 
 
 	// glDiscardFramebuffer uses different attachment enums for the default FBO.
 	// glDiscardFramebuffer uses different attachment enums for the default FBO.
-	if (!isRenderTargetActive() && gl.getDefaultFBO() == 0)
+	if (!isRenderTargetActive() && getInternalBackbufferFBO() == 0)
 	{
 	{
 		if (colorbuffers.size() > 0 && colorbuffers[0])
 		if (colorbuffers.size() > 0 && colorbuffers[0])
 			attachments.push_back(GL_COLOR);
 			attachments.push_back(GL_COLOR);
@@ -863,7 +950,7 @@ void Graphics::cleanupRenderTexture(love::graphics::Texture *texture)
 	}
 	}
 }
 }
 
 
-void Graphics::bindCachedFBO(const RenderTargets &targets)
+GLuint Graphics::bindCachedFBO(const RenderTargets &targets)
 {
 {
 	GLuint fbo = framebufferObjects[targets];
 	GLuint fbo = framebufferObjects[targets];
 
 
@@ -946,6 +1033,8 @@ void Graphics::bindCachedFBO(const RenderTargets &targets)
 
 
 		framebufferObjects[targets] = fbo;
 		framebufferObjects[targets] = fbo;
 	}
 	}
+
+	return fbo;
 }
 }
 
 
 void Graphics::present(void *screenshotCallbackData)
 void Graphics::present(void *screenshotCallbackData)
@@ -961,13 +1050,34 @@ void Graphics::present(void *screenshotCallbackData)
 	flushBatchedDraws();
 	flushBatchedDraws();
 	endPass();
 	endPass();
 
 
-	gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, gl.getDefaultFBO());
+	int w = getPixelWidth();
+	int h = getPixelHeight();
 
 
-	if (!pendingScreenshotCallbacks.empty())
+	gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getInternalBackbufferFBO());
+
+	// Copy internal backbuffer to system backbuffer. When MSAA is used this
+	// is a direct MSAA resolve.
+	if (internalBackbuffer.get())
 	{
 	{
-		int w = getPixelWidth();
-		int h = getPixelHeight();
+		gl.bindFramebuffer(OpenGL::FRAMEBUFFER_DRAW, getSystemBackbufferFBO());
+
+		// Discard system backbuffer to prevent it from copying its contents
+		// from VRAM to chip memory.
+		discard(OpenGL::FRAMEBUFFER_DRAW, {true}, true);
 
 
+		// updateBackbuffer checks for glBlitFramebuffer support.
+		if (GLAD_APPLE_framebuffer_multisample && internalBackbuffer->getMSAA() > 1)
+			glResolveMultisampleFramebufferAPPLE();
+		else
+			glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+		// Discarding the internal backbuffer directly after resolving it should
+		// eliminate any copy back to vram it might need to do.
+		discard(OpenGL::FRAMEBUFFER_READ, {true}, false);
+	}
+
+	if (!pendingScreenshotCallbacks.empty())
+	{
 		size_t row = 4 * w;
 		size_t row = 4 * w;
 		size_t size = row * h;
 		size_t size = row * h;
 
 
@@ -986,26 +1096,7 @@ void Graphics::present(void *screenshotCallbackData)
 			throw love::Exception("Out of memory.");
 			throw love::Exception("Out of memory.");
 		}
 		}
 
 
-#ifdef LOVE_IOS
-		SDL_SysWMinfo info = {};
-		SDL_VERSION(&info.version);
-		SDL_GetWindowWMInfo(SDL_GL_GetCurrentWindow(), &info);
-
-		if (info.info.uikit.resolveFramebuffer != 0)
-		{
-			gl.bindFramebuffer(OpenGL::FRAMEBUFFER_DRAW, info.info.uikit.resolveFramebuffer);
-
-			// We need to do an explicit MSAA resolve on iOS, because it uses
-			// GLES FBOs rather than a system framebuffer.
-			if (GLAD_ES_VERSION_3_0)
-				glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
-			else if (GLAD_APPLE_framebuffer_multisample)
-				glResolveMultisampleFramebufferAPPLE();
-
-			gl.bindFramebuffer(OpenGL::FRAMEBUFFER_READ, info.info.uikit.resolveFramebuffer);
-		}
-#endif
-
+		gl.bindFramebuffer(OpenGL::FRAMEBUFFER_READ, getSystemBackbufferFBO());
 		glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 		glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 
 
 		// Replace alpha values with full opacity.
 		// Replace alpha values with full opacity.
@@ -1069,6 +1160,8 @@ void Graphics::present(void *screenshotCallbackData)
 	if (window != nullptr)
 	if (window != nullptr)
 		window->swapBuffers();
 		window->swapBuffers();
 
 
+	gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getInternalBackbufferFBO());
+
 	// Reset the per-frame stat counts.
 	// Reset the per-frame stat counts.
 	drawCalls = 0;
 	drawCalls = 0;
 	gl.stats.shaderSwitches = 0;
 	gl.stats.shaderSwitches = 0;
@@ -1089,6 +1182,16 @@ void Graphics::present(void *screenshotCallbackData)
 	}
 	}
 }
 }
 
 
+int Graphics::getRequestedBackbufferMSAA() const
+{
+	return requestedBackbufferMSAA;
+}
+
+int Graphics::getBackbufferMSAA() const
+{
+	return internalBackbuffer.get() ? internalBackbuffer->getMSAA() : 0;
+}
+
 void Graphics::setScissor(const Rect &rect)
 void Graphics::setScissor(const Rect &rect)
 {
 {
 	flushBatchedDraws();
 	flushBatchedDraws();

+ 14 - 2
src/modules/graphics/opengl/Graphics.h

@@ -63,7 +63,7 @@ public:
 	love::graphics::Buffer *newBuffer(const Buffer::Settings &settings, const std::vector<Buffer::DataDeclaration> &format, const void *data, size_t size, size_t arraylength) override;
 	love::graphics::Buffer *newBuffer(const Buffer::Settings &settings, const std::vector<Buffer::DataDeclaration> &format, const void *data, size_t size, size_t arraylength) override;
 
 
 	void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
 	void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
-	bool setMode(int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil) override;
+	bool setMode(int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override;
 	void unSetMode() override;
 	void unSetMode() override;
 
 
 	void setActive(bool active) override;
 	void setActive(bool active) override;
@@ -79,6 +79,9 @@ public:
 
 
 	void present(void *screenshotCallbackData) override;
 	void present(void *screenshotCallbackData) override;
 
 
+	int getRequestedBackbufferMSAA() const override;
+	int getBackbufferMSAA() const override;
+
 	void setColor(Colorf c) override;
 	void setColor(Colorf c) override;
 
 
 	void setScissor(const Rect &rect) override;
 	void setScissor(const Rect &rect) override;
@@ -138,15 +141,24 @@ private:
 	void getAPIStats(int &shaderswitches) const override;
 	void getAPIStats(int &shaderswitches) const override;
 
 
 	void endPass();
 	void endPass();
-	void bindCachedFBO(const RenderTargets &targets);
+	GLuint bindCachedFBO(const RenderTargets &targets);
 	void discard(OpenGL::FramebufferTarget target, const std::vector<bool> &colorbuffers, bool depthstencil);
 	void discard(OpenGL::FramebufferTarget target, const std::vector<bool> &colorbuffers, bool depthstencil);
 
 
+	void updateBackbuffer(int width, int height, int pixelwidth, int pixelheight, int msaa);
+	GLuint getInternalBackbufferFBO() const;
+	GLuint getSystemBackbufferFBO() const;
+
 	void setDebug(bool enable);
 	void setDebug(bool enable);
 
 
 	std::unordered_map<RenderTargets, GLuint, CachedFBOHasher> framebufferObjects;
 	std::unordered_map<RenderTargets, GLuint, CachedFBOHasher> framebufferObjects;
 	bool windowHasStencil;
 	bool windowHasStencil;
 	GLuint mainVAO;
 	GLuint mainVAO;
 
 
+	StrongRef<love::graphics::Texture> internalBackbuffer;
+	StrongRef<love::graphics::Texture> internalBackbufferDepthStencil;
+	GLuint internalBackbufferFBO;
+	int requestedBackbufferMSAA;
+
 	// Only needed for buffer types that can be bound to shaders.
 	// Only needed for buffer types that can be bound to shaders.
 	StrongRef<love::graphics::Buffer> defaultBuffers[BUFFERTYPE_MAX_ENUM];
 	StrongRef<love::graphics::Buffer> defaultBuffers[BUFFERTYPE_MAX_ENUM];
 
 

+ 19 - 38
src/modules/window/sdl/Window.cpp

@@ -93,7 +93,7 @@ void Window::setGraphics(graphics::Graphics *graphics)
 	this->graphics.set(graphics);
 	this->graphics.set(graphics);
 }
 }
 
 
-void Window::setGLFramebufferAttributes(int msaa, bool sRGB, bool stencil, int depth)
+void Window::setGLFramebufferAttributes(bool sRGB)
 {
 {
 	// Set GL window / framebuffer attributes.
 	// Set GL window / framebuffer attributes.
 	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
 	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
@@ -101,12 +101,18 @@ void Window::setGLFramebufferAttributes(int msaa, bool sRGB, bool stencil, int d
 	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
 	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
 	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
 	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
 	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
 	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, stencil ? 8 : 0);
-	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depth);
 	SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0);
 	SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0);
 
 
-	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (msaa > 0) ? 1 : 0);
-	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (msaa > 0) ? msaa : 0);
+	// Always use 24/8 depth/stencil (make sure any Graphics implementations
+	// that have their own backbuffer match this, too).
+	// Changing this after initial window creation would need the context to be
+	// destroyed and recreated, which we really don't want.
+	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
+	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
+
+	// Backbuffer MSAA is handled by the love.graphics implementation.
+	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
+	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
 
 
 	SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, sRGB ? 1 : 0);
 	SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, sRGB ? 1 : 0);
 
 
@@ -288,7 +294,7 @@ std::vector<Window::ContextAttribs> Window::getContextAttribsList() const
 	return attribslist;
 	return attribslist;
 }
 }
 
 
-bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags, int msaa, bool stencil, int depth)
+bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags)
 {
 {
 	std::vector<ContextAttribs> attribslist = getContextAttribsList();
 	std::vector<ContextAttribs> attribslist = getContextAttribsList();
 
 
@@ -350,10 +356,9 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla
 	// Try each context profile in order.
 	// Try each context profile in order.
 	for (ContextAttribs attribs : attribslist)
 	for (ContextAttribs attribs : attribslist)
 	{
 	{
-		int curMSAA  = msaa;
 		bool curSRGB = love::graphics::isGammaCorrect();
 		bool curSRGB = love::graphics::isGammaCorrect();
 
 
-		setGLFramebufferAttributes(curMSAA, curSRGB, stencil, depth);
+		setGLFramebufferAttributes(curSRGB);
 		setGLContextAttributes(attribs);
 		setGLContextAttributes(attribs);
 
 
 		windowerror.clear();
 		windowerror.clear();
@@ -361,31 +366,12 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla
 
 
 		create(attribs);
 		create(attribs);
 
 
-		if (!window && curMSAA > 0)
-		{
-			// The MSAA setting could have caused the failure.
-			setGLFramebufferAttributes(0, curSRGB, stencil, depth);
-			if (create(attribs))
-				curMSAA = 0;
-		}
-
 		if (!window && curSRGB)
 		if (!window && curSRGB)
 		{
 		{
-			// same with sRGB.
-			setGLFramebufferAttributes(curMSAA, false, stencil, depth);
-			if (create(attribs))
-				curSRGB = false;
-		}
-
-		if (!window && curMSAA > 0 && curSRGB)
-		{
-			// Or both!
-			setGLFramebufferAttributes(0, false, stencil, depth);
+			// The sRGB setting could have caused the failure.
+			setGLFramebufferAttributes(false);
 			if (create(attribs))
 			if (create(attribs))
-			{
-				curMSAA = 0;
 				curSRGB = false;
 				curSRGB = false;
-			}
 		}
 		}
 
 
 		if (window && context)
 		if (window && context)
@@ -515,7 +501,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
 
 
 	close();
 	close();
 
 
-	if (!createWindowAndContext(x, y, width, height, sdlflags, f.msaa, f.stencil, f.depth))
+	if (!createWindowAndContext(x, y, width, height, sdlflags))
 		return false;
 		return false;
 
 
 	// Make sure the window keeps any previously set icon.
 	// Make sure the window keeps any previously set icon.
@@ -540,7 +526,9 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
 	{
 	{
 		double scaledw, scaledh;
 		double scaledw, scaledh;
 		fromPixels((double) pixelWidth, (double) pixelHeight, scaledw, scaledh);
 		fromPixels((double) pixelWidth, (double) pixelHeight, scaledw, scaledh);
-		graphics->setMode((int) scaledw, (int) scaledh, pixelWidth, pixelHeight, f.stencil);
+		graphics->setMode((int) scaledw, (int) scaledh, pixelWidth, pixelHeight, f.stencil, f.msaa);
+
+		this->settings.msaa = graphics->getBackbufferMSAA();
 	}
 	}
 
 
 #ifdef LOVE_ANDROID
 #ifdef LOVE_ANDROID
@@ -617,13 +605,6 @@ void Window::updateSettings(const WindowSettings &newsettings, bool updateGraphi
 	else
 	else
 		SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
 		SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
 
 
-	// Verify MSAA setting.
-	int buffers = 0;
-	int samples = 0;
-	SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &buffers);
-	SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &samples);
-
-	settings.msaa = (buffers > 0 ? samples : 0);
 	settings.vsync = getVSync();
 	settings.vsync = getVSync();
 
 
 	settings.stencil = newsettings.stencil;
 	settings.stencil = newsettings.stencil;

+ 2 - 2
src/modules/window/sdl/Window.h

@@ -139,11 +139,11 @@ private:
 		bool debug;
 		bool debug;
 	};
 	};
 
 
-	void setGLFramebufferAttributes(int msaa, bool sRGB, bool stencil, int depth);
+	void setGLFramebufferAttributes(bool sRGB);
 	void setGLContextAttributes(const ContextAttribs &attribs);
 	void setGLContextAttributes(const ContextAttribs &attribs);
 	bool checkGLVersion(const ContextAttribs &attribs, std::string &outversion);
 	bool checkGLVersion(const ContextAttribs &attribs, std::string &outversion);
 	std::vector<ContextAttribs> getContextAttribsList() const;
 	std::vector<ContextAttribs> getContextAttribsList() const;
-	bool createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags, int msaa, bool stencil, int depth);
+	bool createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags);
 
 
 	// Update the saved window settings based on the window's actual state.
 	// Update the saved window settings based on the window's actual state.
 	void updateSettings(const WindowSettings &newsettings, bool updateGraphicsViewport);
 	void updateSettings(const WindowSettings &newsettings, bool updateGraphicsViewport);