Browse Source

Merge remote-tracking branch 'origin/12.0-development' into vulkan

niki 3 years ago
parent
commit
f4ece69307

+ 10 - 0
.gitignore

@@ -1,3 +1,13 @@
+# automake products
+/config.h
+/config.h.in
+/config.log
+/config.status
+/configure
+/configure-modules-post.ac
+/configure-modules-pre.ac
+/configure.ac
+
 /extra/reshax/Release/
 /extra/reshax/Debug/
 /extra/reshax/resources.h

+ 1 - 0
CMakeLists.txt

@@ -1841,6 +1841,7 @@ if(MSVC)
 	set(LOVE_LINK_LIBRARIES ${LOVE_LINK_LIBRARIES}
 		ws2_32.lib
 		winmm.lib
+		dwmapi.lib
 	)
 
 	set(LOVE_RC

+ 1 - 1
src/common/Stream.cpp

@@ -69,7 +69,7 @@ bool Stream::write(Data *src)
 
 bool Stream::write(Data *src, int64 offset, int64 size)
 {
-	if (offset < 0 || size < 0 || offset + size > src->getSize())
+	if (offset < 0 || size < 0 || offset + size > (int64) src->getSize())
 		throw love::Exception("Offset and size parameters do not fit within the given Data's size.");
 
 	return write((const uint8 *) src->getData() + offset, size);

+ 7 - 1
src/libraries/luahttps/src/android/AndroidClient.cpp

@@ -97,6 +97,7 @@ HTTPSClient::Reply AndroidClient::request(const HTTPSClient::Request &req)
 
 	jmethodID constructor = env->GetMethodID(httpsClass, "<init>", "()V");
 	jmethodID setURL = env->GetMethodID(httpsClass, "setUrl", "(Ljava/lang/String;)V");
+	jmethodID setMethod = env->GetMethodID(httpsClass, "setMethod", "(Ljava/lang/String;)V");
 	jmethodID request = env->GetMethodID(httpsClass, "request", "()Z");
 	jmethodID getInterleavedHeaders = env->GetMethodID(httpsClass, "getInterleavedHeaders", "()[Ljava/lang/String;");
 	jmethodID getResponse = env->GetMethodID(httpsClass, "getResponse", "()[B");
@@ -109,8 +110,13 @@ HTTPSClient::Reply AndroidClient::request(const HTTPSClient::Request &req)
 	env->CallVoidMethod(httpsObject, setURL, url);
 	env->DeleteLocalRef(url);
 
+	// Set method
+	jstring method = env->NewStringUTF(req.method.c_str());
+	env->CallVoidMethod(httpsObject, setMethod, method);
+	env->DeleteLocalRef(method);
+
 	// Set post data
-	if (req.method == Request::POST)
+	if (req.postdata.size() > 0)
 	{
 		jmethodID setPostData = env->GetMethodID(httpsClass, "setPostData", "([B)V");
 		jbyteArray byteArray = env->NewByteArray((jsize) req.postdata.length());

+ 21 - 2
src/libraries/luahttps/src/android/java/org/love2d/luahttps/LuaHTTPS.java

@@ -11,6 +11,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
+import java.net.ProtocolException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -22,6 +23,7 @@ class LuaHTTPS {
     static private String TAG = "LuaHTTPS";
 
     private String urlString;
+    private String method;
     private byte[] postData;
     private byte[] response;
     private int responseCode;
@@ -34,6 +36,7 @@ class LuaHTTPS {
 
     public void reset() {
         urlString = null;
+        method = "GET";
         postData = null;
         response = null;
         responseCode = 0;
@@ -50,6 +53,11 @@ class LuaHTTPS {
         this.postData = postData;
     }
 
+    @Keep
+    public void setMethod(String method) {
+        this.method = method.toUpperCase();
+    }
+
     @Keep
     public void addHeader(String key, String value) {
         headers.put(key, value);
@@ -110,15 +118,22 @@ class LuaHTTPS {
             return false;
         }
 
+        // Set request method
+        try {
+            connection.setRequestMethod(method);
+        } catch (ProtocolException e) {
+            Log.e(TAG, "Error", e);
+            return false;
+        }
+
         // Set header
         for (Map.Entry<String, String> headerData: headers.entrySet()) {
             connection.setRequestProperty(headerData.getKey(), headerData.getValue());
         }
 
         // Set post data
-        if (postData != null) {
+        if (postData != null && canSendData()) {
             connection.setDoOutput(true);
-            connection.setChunkedStreamingMode(0);
 
             try {
                 OutputStream out = connection.getOutputStream();
@@ -168,4 +183,8 @@ class LuaHTTPS {
         connection.disconnect();
         return true;
     }
+
+    private boolean canSendData() {
+        return !method.equals("GET") && !method.equals("HEAD");
+    }
 }

+ 4 - 8
src/libraries/luahttps/src/apple/NSURLClient.mm

@@ -29,16 +29,12 @@ HTTPSClient::Reply NSURLClient::request(const HTTPSClient::Request &req)
 	NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
 
 	NSData *bodydata = nil;
-	switch(req.method)
+	[request setHTTPMethod:@(req.method.c_str())];
+
+	if (req.postdata.size() > 0 && (req.method != "GET" && req.method != "HEAD"))
 	{
-	case Request::GET:
-		[request setHTTPMethod:@"GET"];
-		break;
-	case Request::POST:
 		bodydata = [NSData dataWithBytesNoCopy:(void*) req.postdata.data() length:req.postdata.size() freeWhenDone:NO];
-		[request setHTTPMethod:@"POST"];
 		[request setHTTPBody:bodydata];
-		break;
 	}
 
 	for (auto &header : req.headers)
@@ -63,7 +59,7 @@ HTTPSClient::Reply NSURLClient::request(const HTTPSClient::Request &req)
 	dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
 
 	HTTPSClient::Reply reply;
-	reply.responseCode = 400;
+	reply.responseCode = 0;
 
 	if (body)
 	{

+ 10 - 4
src/libraries/luahttps/src/common/HTTPRequest.cpp

@@ -35,7 +35,13 @@ HTTPSClient::Reply HTTPRequest::request(const HTTPSClient::Request &req)
 	// Build the request
 	{
 		std::stringstream request;
-		request << (req.method == HTTPSClient::Request::GET ? "GET " : "POST ") << info.query << " HTTP/1.1\r\n";
+		std::string method = req.method;
+		bool hasData = req.postdata.length() > 0;
+
+		if (method.length() == 0)
+			method = hasData ? "POST" : "GET";
+
+		request << method << " " << info.query << " HTTP/1.1\r\n";
 
 		for (auto &header : req.headers)
 			request << header.first << ": " << header.second << "\r\n";
@@ -44,15 +50,15 @@ HTTPSClient::Reply HTTPRequest::request(const HTTPSClient::Request &req)
 
 		request << "Host: " << info.hostname << "\r\n";
 
-		if (req.method == HTTPSClient::Request::POST && req.headers.count("Content-Type") == 0)
+		if (hasData && req.headers.count("Content-Type") == 0)
 			request << "Content-Type: application/x-www-form-urlencoded\r\n";
 
-		if (req.method == HTTPSClient::Request::POST)
+		if (hasData)
 			request << "Content-Length: " << req.postdata.size() << "\r\n";
 
 		request << "\r\n";
 
-		if (req.method == HTTPSClient::Request::POST)
+		if (hasData)
 			request << req.postdata;
 
 		// Send it

+ 1 - 1
src/libraries/luahttps/src/common/HTTPSClient.cpp

@@ -31,7 +31,7 @@ bool HTTPSClient::ci_string_less::operator()(const std::string &lhs, const std::
 
 HTTPSClient::Request::Request(const std::string &url)
 	: url(url)
-	, method(GET)
+	, method("")
 {
 }
 

+ 1 - 6
src/libraries/luahttps/src/common/HTTPSClient.h

@@ -20,12 +20,7 @@ public:
 		header_map headers;
 		std::string url;
 		std::string postdata;
-
-		enum Method
-		{
-			GET,
-			POST,
-		} method;
+		std::string method;
 	};
 
 	struct Reply

+ 8 - 2
src/libraries/luahttps/src/generic/CurlClient.cpp

@@ -73,9 +73,15 @@ HTTPSClient::Reply CurlClient::request(const HTTPSClient::Request &req)
 	curl.easy_setopt(handle, CURLOPT_URL, req.url.c_str());
 	curl.easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);
 
-	if (req.method == Request::POST)
-	{
+	if (req.method == "PUT")
+		curl.easy_setopt(handle, CURLOPT_PUT, 1L);
+	else if (req.method == "POST")
 		curl.easy_setopt(handle, CURLOPT_POST, 1L);
+	else
+		curl.easy_setopt(handle, CURLOPT_CUSTOMREQUEST, req.method.c_str());
+
+	if (req.postdata.size() > 0 && (req.method != "GET" && req.method != "HEAD"))
+	{
 		curl.easy_setopt(handle, CURLOPT_POSTFIELDS, req.postdata.c_str());
 		curl.easy_setopt(handle, CURLOPT_POSTFIELDSIZE, req.postdata.size());
 	}

+ 22 - 11
src/libraries/luahttps/src/lua/main.cpp

@@ -1,3 +1,6 @@
+#include <algorithm>
+#include <set>
+
 extern "C"
 {
 #include <lua.h>
@@ -7,6 +10,14 @@ extern "C"
 #include "../common/HTTPS.h"
 #include "../common/config.h"
 
+static std::string validMethod[] = {"GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"};
+
+static int str_toupper(char c)
+{
+	unsigned char uc = (unsigned char) c;
+	return toupper(uc);
+}
+
 static std::string w_checkstring(lua_State *L, int idx)
 {
 	size_t len;
@@ -34,20 +45,20 @@ static void w_readheaders(lua_State *L, int idx, HTTPSClient::header_map &header
 	lua_pop(L, 1);
 }
 
-static HTTPSClient::Request::Method w_optmethod(lua_State *L, int idx, HTTPSClient::Request::Method defaultMethod)
+static std::string w_optmethod(lua_State *L, int idx, const std::string &defaultMethod)
 {
+	std::string *const validMethodEnd = validMethod + sizeof(validMethod) / sizeof(std::string);
+
 	if (lua_isnoneornil(L, idx))
 		return defaultMethod;
 
-	auto str = w_checkstring(L, idx);
-	if (str == "get")
-		return HTTPSClient::Request::GET;
-	else if (str == "post")
-		return HTTPSClient::Request::POST;
-	else
-		luaL_argerror(L, idx, "expected one of \"get\" or \"set\"");
+	std::string str = w_checkstring(L, idx);
+	std::transform(str.begin(), str.end(), str.begin(), str_toupper);
+
+	if (std::find(validMethod, validMethodEnd, str) == validMethodEnd)
+		luaL_argerror(L, idx, "expected one of \"get\", \"head\", \"post\", \"put\", \"delete\", or \"patch\"");
 
-	return defaultMethod;
+	return str;
 }
 
 static int w_request(lua_State *L)
@@ -61,13 +72,13 @@ static int w_request(lua_State *L)
 	{
 		advanced = true;
 
-		HTTPSClient::Request::Method defaultMethod = HTTPSClient::Request::GET;
+		std::string defaultMethod = "GET";
 
 		lua_getfield(L, 2, "data");
 		if (!lua_isnoneornil(L, -1))
 		{
 			req.postdata = w_checkstring(L, -1);
-			defaultMethod = HTTPSClient::Request::POST;
+			defaultMethod = "POST";
 		}
 		lua_pop(L, 1);
 

+ 6 - 2
src/libraries/luahttps/src/windows/SChannelConnection.cpp

@@ -55,8 +55,12 @@ static size_t dequeue(std::vector<char> &buffer, char *data, size_t size)
 	size_t remaining = buffer.size() - size;
 
 	memcpy(data, &buffer[0], size);
-	memmove(&buffer[0], &buffer[size], remaining);
-	buffer.resize(remaining);
+
+	if (remaining > 0)
+	{
+		memmove(&buffer[0], &buffer[size], remaining);
+		buffer.resize(remaining);
+	}
 
 	return size;
 }

+ 1 - 1
src/modules/audio/openal/Pool.cpp

@@ -34,7 +34,7 @@ static Variant::SharedTable *putSourcesAsSharedTable(std::vector<audio::Source *
 {
 	Variant::SharedTable *table = new Variant::SharedTable();
 
-	for (int i = 0; i < sources.size(); i++)
+	for (int i = 0; i < (int) sources.size(); i++)
 		table->pairs.emplace_back((double) (i + 1), Variant(&Source::type, sources[i]));
 
 	return table;

+ 7 - 7
src/modules/data/DataStream.cpp

@@ -34,19 +34,19 @@ love::Type DataStream::type("DataStream", &Stream::type);
 
 DataStream::DataStream(Data *data)
 	: data(data)
-	, offset(0)
-	, size(data->getSize())
 	, memory((const uint8 *) data->getData())
 	, writableMemory((uint8 *) data->getData()) // TODO: disallow writing sometimes?
+	, offset(0)
+	, size(data->getSize())
 {
 }
 
 DataStream::DataStream(const DataStream &other)
 	: data(other.data)
-	, offset(0)
-	, size(other.size)
 	, memory(other.memory)
 	, writableMemory(other.writableMemory)
+	, offset(0)
+	, size(other.size)
 {
 }
 
@@ -79,7 +79,7 @@ int64 DataStream::read(void* data, int64 size)
 	if (size <= 0)
 		return 0;
 
-	if (offset >= getSize())
+	if ((int64) offset >= getSize())
 		return 0;
 
 	int64 readsize = std::min<int64>(size, getSize() - offset);
@@ -95,7 +95,7 @@ bool DataStream::write(const void* data, int64 size)
 	if (size <= 0 || writableMemory == nullptr)
 		return false;
 
-	if (offset >= getSize())
+	if ((int64) offset >= getSize())
 		return false;
 
 	int64 writesize = std::min<int64>(size, getSize() - offset);
@@ -123,7 +123,7 @@ bool DataStream::seek(int64 pos, SeekOrigin origin)
 	else if (origin == SEEKORIGIN_END)
 		pos += size;
 
-	if (pos < 0 || pos > size)
+	if (pos < 0 || pos > (int64) size)
 		return false;
 
 	offset = pos;

+ 2 - 3
src/modules/graphics/Text.cpp

@@ -124,7 +124,6 @@ void Text::addTextData(const TextData &t)
 
 	size_t voffset = vertOffset;
 
-	// Must be before the early exit below.
 	if (!t.appendVertices)
 	{
 		voffset = 0;
@@ -133,8 +132,8 @@ void Text::addTextData(const TextData &t)
 		textData.clear();
 	}
 
-	if (t.useMatrix)
-		t.matrix.transformXY(&vertices[0], &vertices[0], (int) vertices.size());
+	if (t.useMatrix && !vertices.empty())
+		t.matrix.transformXY(vertices.data(), vertices.data(), (int) vertices.size());
 
 	uploadVertices(vertices, voffset);
 

+ 1 - 1
src/modules/graphics/metal/Graphics.mm

@@ -527,7 +527,7 @@ void Graphics::setActive(bool enable)
 
 void Graphics::setShaderChanged()
 {
-	dirtyRenderState |= STATE_SHADER;
+	dirtyRenderState |= STATEBIT_SHADER;
 	++shaderSwitches;
 }
 

+ 10 - 2
src/modules/graphics/opengl/Graphics.cpp

@@ -1414,12 +1414,17 @@ void Graphics::setStencilMode(StencilAction action, CompareMode compare, int val
 	if (enablestencil != gl.isStateEnabled(OpenGL::ENABLE_STENCIL_TEST))
 		gl.setEnableState(OpenGL::ENABLE_STENCIL_TEST, enablestencil);
 
-	GLenum glaction = GL_REPLACE;
+	GLenum glaction = GL_KEEP;
 
 	switch (action)
 	{
+	case STENCIL_KEEP:
+		glaction = GL_KEEP;
+		break;
+	case STENCIL_ZERO:
+		glaction = GL_ZERO;
+		break;
 	case STENCIL_REPLACE:
-	default:
 		glaction = GL_REPLACE;
 		break;
 	case STENCIL_INCREMENT:
@@ -1437,6 +1442,9 @@ void Graphics::setStencilMode(StencilAction action, CompareMode compare, int val
 	case STENCIL_INVERT:
 		glaction = GL_INVERT;
 		break;
+	case STENCIL_MAX_ENUM:
+		glaction = GL_KEEP;
+		break;
 	}
 
 	/**

+ 6 - 8
src/modules/graphics/opengl/Texture.cpp

@@ -298,20 +298,18 @@ void Texture::createTexture()
 	{
 		if (isCompressed() && (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME))
 		{
+			int slicecount = slices.getSliceCount(mip);
 			size_t mipsize = 0;
 
-			if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME)
+			for (int slice = 0; slice < slicecount; slice++)
 			{
-				for (int slice = 0; slice < slices.getSliceCount(mip); slice++)
-				{
-					auto id = slices.get(slice, mip);
-					if (id != nullptr)
-						mipsize += id->getSize();
-				}
+				auto id = slices.get(slice, mip);
+				if (id != nullptr)
+					mipsize += id->getSize();
 			}
 
 			if (mipsize > 0)
-				glCompressedTexImage3D(gltype, mip, fmt.internalformat, w, h, d, 0, mipsize, nullptr);
+				glCompressedTexImage3D(gltype, mip, fmt.internalformat, w, h, slicecount, 0, mipsize, nullptr);
 		}
 
 		for (int slice = 0; slice < slicecount; slice++)

+ 4 - 1
src/modules/system/sdl/System.cpp

@@ -25,9 +25,12 @@
 // SDL
 #include <SDL_clipboard.h>
 #include <SDL_cpuinfo.h>
-#include <SDL_locale.h>
 #include <SDL_version.h>
 
+#if SDL_VERSION_ATLEAST(2, 0, 14)
+#include <SDL_locale.h>
+#endif
+
 namespace love
 {
 namespace system

+ 5 - 5
src/modules/system/sdl/System.h

@@ -43,14 +43,14 @@ public:
 	virtual ~System() {}
 
 	// Implements Module.
-	const char *getName() const;
+	const char *getName() const override;
 
-	int getProcessorCount() const;
+	int getProcessorCount() const override;
 
-	void setClipboardText(const std::string &text) const;
-	std::string getClipboardText() const;
+	void setClipboardText(const std::string &text) const override;
+	std::string getClipboardText() const override;
 
-	PowerState getPowerInfo(int &seconds, int &percent) const;
+	PowerState getPowerInfo(int &seconds, int &percent) const override;
 	std::vector<std::string> getPreferredLocales() const override;
 
 private:

+ 5 - 0
src/modules/window/Window.cpp

@@ -28,8 +28,13 @@ namespace window
 
 static bool highDPIAllowed = false;
 
+// TODO: find a cleaner way to do this...
+// The window backend (e.g. love.window.sdl) is expected to implement this.
+void setHighDPIAllowedImplementation(bool enable);
+
 void setHighDPIAllowed(bool enable)
 {
+	setHighDPIAllowedImplementation(enable);
 	highDPIAllowed = enable;
 }
 

+ 71 - 6
src/modules/window/sdl/Window.cpp

@@ -45,6 +45,8 @@
 
 #if defined(LOVE_WINDOWS)
 #include <windows.h>
+#include <dwmapi.h>
+#include <VersionHelpers.h>
 #elif defined(LOVE_MACOS)
 #include "common/macos.h"
 #endif
@@ -53,10 +55,27 @@
 #define APIENTRY
 #endif
 
+#ifndef SDL_HINT_WINDOWS_DPI_SCALING
+#define SDL_HINT_WINDOWS_DPI_SCALING "SDL_WINDOWS_DPI_SCALING"
+#endif
+
 namespace love
 {
 namespace window
 {
+
+// See src/modules/window/Window.cpp.
+void setHighDPIAllowedImplementation(bool enable)
+{
+#if defined(LOVE_WINDOWS)
+	// Windows uses a different API than SDL_WINDOW_ALLOW_HIGHDPI.
+	// This must be set before the video subsystem is initialized.
+	SDL_SetHint(SDL_HINT_WINDOWS_DPI_SCALING, enable ? "1" : "0");
+#else
+	LOVE_UNUSED(enable);
+#endif
+}
+
 namespace sdl
 {
 
@@ -72,12 +91,6 @@ Window::Window()
 	, hasSDL203orEarlier(false)
 	, contextAttribs()
 {
-	// Windows uses a different API than SDL_WINDOW_ALLOW_HIGHDPI.
-#if defined(LOVE_WINDOWS) && defined(SDL_HINT_WINDOWS_DPI_SCALING)
-	// This must be set before the video subsystem is initialized.
-	SDL_SetHint(SDL_HINT_WINDOWS_DPI_SCALING, isHighDPIAllowed() ? "1" : "0");
-#endif
-
 	if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
 		throw love::Exception("Could not initialize SDL video subsystem (%s)", SDL_GetError());
 
@@ -1183,7 +1196,59 @@ bool Window::isMinimized() const
 void Window::swapBuffers()
 {
 	if (glcontext)
+	{
+#ifdef LOVE_WINDOWS
+		bool useDwmFlush = false;
+		int swapInterval = getVSync();
+
+		// https://github.com/love2d/love/issues/1628
+		// VSync can interact badly with Windows desktop composition (DWM) in windowed mode. DwmFlush can be used instead
+		// of vsync, but it's much less flexible so we're very conservative here with where it's used:
+		// - It won't work with exclusive or desktop fullscreen.
+		// - DWM refreshes don't always match the refresh rate of the monitor the window is in (or the requested swap
+		//   interval), so we only use it when they do match.
+		// - The user may force GL vsync, and DwmFlush shouldn't be used together with GL vsync.
+		if (!settings.fullscreen && swapInterval == 1)
+		{
+			// Desktop composition is always enabled in Windows 8+. But DwmIsCompositionEnabled won't always return true...
+			// (see DwmIsCompositionEnabled docs).
+			BOOL compositionEnabled = IsWindows8OrGreater();
+			if (compositionEnabled || (SUCCEEDED(DwmIsCompositionEnabled(&compositionEnabled)) && compositionEnabled))
+			{
+				DWM_TIMING_INFO info = {};
+				info.cbSize = sizeof(DWM_TIMING_INFO);
+				double dwmRefreshRate = 0;
+				if (SUCCEEDED(DwmGetCompositionTimingInfo(nullptr, &info)))
+					dwmRefreshRate = (double)info.rateRefresh.uiNumerator / (double)info.rateRefresh.uiDenominator;
+
+				SDL_DisplayMode dmode = {};
+				int displayindex = SDL_GetWindowDisplayIndex(window);
+
+				if (displayindex >= 0)
+					SDL_GetCurrentDisplayMode(displayindex, &dmode);
+
+				if (dmode.refresh_rate > 0 && dwmRefreshRate > 0 && (fabs(dmode.refresh_rate - dwmRefreshRate) < 2))
+				{
+					SDL_GL_SetSwapInterval(0);
+					if (SDL_GL_GetSwapInterval() == 0)
+						useDwmFlush = true;
+					else
+						SDL_GL_SetSwapInterval(swapInterval);
+				}
+			}
+		}
+#endif
+
 		SDL_GL_SwapWindow(window);
+
+#ifdef LOVE_WINDOWS
+		if (useDwmFlush)
+		{
+			DwmFlush();
+			SDL_GL_SetSwapInterval(swapInterval);
+		}
+#endif
+	}
 }
 
 bool Window::hasFocus() const