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

This commit is contained in:
niki
2022-08-15 03:43:35 +02:00
22 changed files with 204 additions and 72 deletions
+10
View File
@@ -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/Release/
/extra/reshax/Debug/ /extra/reshax/Debug/
/extra/reshax/resources.h /extra/reshax/resources.h
+1
View File
@@ -1841,6 +1841,7 @@ if(MSVC)
set(LOVE_LINK_LIBRARIES ${LOVE_LINK_LIBRARIES} set(LOVE_LINK_LIBRARIES ${LOVE_LINK_LIBRARIES}
ws2_32.lib ws2_32.lib
winmm.lib winmm.lib
dwmapi.lib
) )
set(LOVE_RC set(LOVE_RC
+1 -1
View File
@@ -69,7 +69,7 @@ bool Stream::write(Data *src)
bool Stream::write(Data *src, int64 offset, int64 size) 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."); throw love::Exception("Offset and size parameters do not fit within the given Data's size.");
return write((const uint8 *) src->getData() + offset, size); return write((const uint8 *) src->getData() + offset, size);
@@ -97,6 +97,7 @@ HTTPSClient::Reply AndroidClient::request(const HTTPSClient::Request &req)
jmethodID constructor = env->GetMethodID(httpsClass, "<init>", "()V"); jmethodID constructor = env->GetMethodID(httpsClass, "<init>", "()V");
jmethodID setURL = env->GetMethodID(httpsClass, "setUrl", "(Ljava/lang/String;)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 request = env->GetMethodID(httpsClass, "request", "()Z");
jmethodID getInterleavedHeaders = env->GetMethodID(httpsClass, "getInterleavedHeaders", "()[Ljava/lang/String;"); jmethodID getInterleavedHeaders = env->GetMethodID(httpsClass, "getInterleavedHeaders", "()[Ljava/lang/String;");
jmethodID getResponse = env->GetMethodID(httpsClass, "getResponse", "()[B"); 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->CallVoidMethod(httpsObject, setURL, url);
env->DeleteLocalRef(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 // Set post data
if (req.method == Request::POST) if (req.postdata.size() > 0)
{ {
jmethodID setPostData = env->GetMethodID(httpsClass, "setPostData", "([B)V"); jmethodID setPostData = env->GetMethodID(httpsClass, "setPostData", "([B)V");
jbyteArray byteArray = env->NewByteArray((jsize) req.postdata.length()); jbyteArray byteArray = env->NewByteArray((jsize) req.postdata.length());
@@ -11,6 +11,7 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -22,6 +23,7 @@ class LuaHTTPS {
static private String TAG = "LuaHTTPS"; static private String TAG = "LuaHTTPS";
private String urlString; private String urlString;
private String method;
private byte[] postData; private byte[] postData;
private byte[] response; private byte[] response;
private int responseCode; private int responseCode;
@@ -34,6 +36,7 @@ class LuaHTTPS {
public void reset() { public void reset() {
urlString = null; urlString = null;
method = "GET";
postData = null; postData = null;
response = null; response = null;
responseCode = 0; responseCode = 0;
@@ -50,6 +53,11 @@ class LuaHTTPS {
this.postData = postData; this.postData = postData;
} }
@Keep
public void setMethod(String method) {
this.method = method.toUpperCase();
}
@Keep @Keep
public void addHeader(String key, String value) { public void addHeader(String key, String value) {
headers.put(key, value); headers.put(key, value);
@@ -110,15 +118,22 @@ class LuaHTTPS {
return false; return false;
} }
// Set request method
try {
connection.setRequestMethod(method);
} catch (ProtocolException e) {
Log.e(TAG, "Error", e);
return false;
}
// Set header // Set header
for (Map.Entry<String, String> headerData: headers.entrySet()) { for (Map.Entry<String, String> headerData: headers.entrySet()) {
connection.setRequestProperty(headerData.getKey(), headerData.getValue()); connection.setRequestProperty(headerData.getKey(), headerData.getValue());
} }
// Set post data // Set post data
if (postData != null) { if (postData != null && canSendData()) {
connection.setDoOutput(true); connection.setDoOutput(true);
connection.setChunkedStreamingMode(0);
try { try {
OutputStream out = connection.getOutputStream(); OutputStream out = connection.getOutputStream();
@@ -168,4 +183,8 @@ class LuaHTTPS {
connection.disconnect(); connection.disconnect();
return true; return true;
} }
private boolean canSendData() {
return !method.equals("GET") && !method.equals("HEAD");
}
} }
@@ -29,16 +29,12 @@ HTTPSClient::Reply NSURLClient::request(const HTTPSClient::Request &req)
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSData *bodydata = nil; 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]; bodydata = [NSData dataWithBytesNoCopy:(void*) req.postdata.data() length:req.postdata.size() freeWhenDone:NO];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:bodydata]; [request setHTTPBody:bodydata];
break;
} }
for (auto &header : req.headers) for (auto &header : req.headers)
@@ -63,7 +59,7 @@ HTTPSClient::Reply NSURLClient::request(const HTTPSClient::Request &req)
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
HTTPSClient::Reply reply; HTTPSClient::Reply reply;
reply.responseCode = 400; reply.responseCode = 0;
if (body) if (body)
{ {
@@ -35,7 +35,13 @@ HTTPSClient::Reply HTTPRequest::request(const HTTPSClient::Request &req)
// Build the request // Build the request
{ {
std::stringstream 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) for (auto &header : req.headers)
request << header.first << ": " << header.second << "\r\n"; 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"; 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"; 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 << "Content-Length: " << req.postdata.size() << "\r\n";
request << "\r\n"; request << "\r\n";
if (req.method == HTTPSClient::Request::POST) if (hasData)
request << req.postdata; request << req.postdata;
// Send it // Send it
@@ -31,7 +31,7 @@ bool HTTPSClient::ci_string_less::operator()(const std::string &lhs, const std::
HTTPSClient::Request::Request(const std::string &url) HTTPSClient::Request::Request(const std::string &url)
: url(url) : url(url)
, method(GET) , method("")
{ {
} }
@@ -20,12 +20,7 @@ public:
header_map headers; header_map headers;
std::string url; std::string url;
std::string postdata; std::string postdata;
std::string method;
enum Method
{
GET,
POST,
} method;
}; };
struct Reply struct Reply
@@ -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_URL, req.url.c_str());
curl.easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L); 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); 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_POSTFIELDS, req.postdata.c_str());
curl.easy_setopt(handle, CURLOPT_POSTFIELDSIZE, req.postdata.size()); curl.easy_setopt(handle, CURLOPT_POSTFIELDSIZE, req.postdata.size());
} }
+22 -11
View File
@@ -1,3 +1,6 @@
#include <algorithm>
#include <set>
extern "C" extern "C"
{ {
#include <lua.h> #include <lua.h>
@@ -7,6 +10,14 @@ extern "C"
#include "../common/HTTPS.h" #include "../common/HTTPS.h"
#include "../common/config.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) static std::string w_checkstring(lua_State *L, int idx)
{ {
size_t len; size_t len;
@@ -34,20 +45,20 @@ static void w_readheaders(lua_State *L, int idx, HTTPSClient::header_map &header
lua_pop(L, 1); 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)) if (lua_isnoneornil(L, idx))
return defaultMethod; return defaultMethod;
auto str = w_checkstring(L, idx); std::string str = w_checkstring(L, idx);
if (str == "get") std::transform(str.begin(), str.end(), str.begin(), str_toupper);
return HTTPSClient::Request::GET;
else if (str == "post")
return HTTPSClient::Request::POST;
else
luaL_argerror(L, idx, "expected one of \"get\" or \"set\"");
return defaultMethod; if (std::find(validMethod, validMethodEnd, str) == validMethodEnd)
luaL_argerror(L, idx, "expected one of \"get\", \"head\", \"post\", \"put\", \"delete\", or \"patch\"");
return str;
} }
static int w_request(lua_State *L) static int w_request(lua_State *L)
@@ -61,13 +72,13 @@ static int w_request(lua_State *L)
{ {
advanced = true; advanced = true;
HTTPSClient::Request::Method defaultMethod = HTTPSClient::Request::GET; std::string defaultMethod = "GET";
lua_getfield(L, 2, "data"); lua_getfield(L, 2, "data");
if (!lua_isnoneornil(L, -1)) if (!lua_isnoneornil(L, -1))
{ {
req.postdata = w_checkstring(L, -1); req.postdata = w_checkstring(L, -1);
defaultMethod = HTTPSClient::Request::POST; defaultMethod = "POST";
} }
lua_pop(L, 1); lua_pop(L, 1);
@@ -55,8 +55,12 @@ static size_t dequeue(std::vector<char> &buffer, char *data, size_t size)
size_t remaining = buffer.size() - size; size_t remaining = buffer.size() - size;
memcpy(data, &buffer[0], 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; return size;
} }
+1 -1
View File
@@ -34,7 +34,7 @@ static Variant::SharedTable *putSourcesAsSharedTable(std::vector<audio::Source *
{ {
Variant::SharedTable *table = new Variant::SharedTable(); 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])); table->pairs.emplace_back((double) (i + 1), Variant(&Source::type, sources[i]));
return table; return table;
+7 -7
View File
@@ -34,19 +34,19 @@ love::Type DataStream::type("DataStream", &Stream::type);
DataStream::DataStream(Data *data) DataStream::DataStream(Data *data)
: data(data) : data(data)
, offset(0)
, size(data->getSize())
, memory((const uint8 *) data->getData()) , memory((const uint8 *) data->getData())
, writableMemory((uint8 *) data->getData()) // TODO: disallow writing sometimes? , writableMemory((uint8 *) data->getData()) // TODO: disallow writing sometimes?
, offset(0)
, size(data->getSize())
{ {
} }
DataStream::DataStream(const DataStream &other) DataStream::DataStream(const DataStream &other)
: data(other.data) : data(other.data)
, offset(0)
, size(other.size)
, memory(other.memory) , memory(other.memory)
, writableMemory(other.writableMemory) , writableMemory(other.writableMemory)
, offset(0)
, size(other.size)
{ {
} }
@@ -79,7 +79,7 @@ int64 DataStream::read(void* data, int64 size)
if (size <= 0) if (size <= 0)
return 0; return 0;
if (offset >= getSize()) if ((int64) offset >= getSize())
return 0; return 0;
int64 readsize = std::min<int64>(size, getSize() - offset); 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) if (size <= 0 || writableMemory == nullptr)
return false; return false;
if (offset >= getSize()) if ((int64) offset >= getSize())
return false; return false;
int64 writesize = std::min<int64>(size, getSize() - offset); int64 writesize = std::min<int64>(size, getSize() - offset);
@@ -123,7 +123,7 @@ bool DataStream::seek(int64 pos, SeekOrigin origin)
else if (origin == SEEKORIGIN_END) else if (origin == SEEKORIGIN_END)
pos += size; pos += size;
if (pos < 0 || pos > size) if (pos < 0 || pos > (int64) size)
return false; return false;
offset = pos; offset = pos;
+2 -3
View File
@@ -124,7 +124,6 @@ void Text::addTextData(const TextData &t)
size_t voffset = vertOffset; size_t voffset = vertOffset;
// Must be before the early exit below.
if (!t.appendVertices) if (!t.appendVertices)
{ {
voffset = 0; voffset = 0;
@@ -133,8 +132,8 @@ void Text::addTextData(const TextData &t)
textData.clear(); textData.clear();
} }
if (t.useMatrix) if (t.useMatrix && !vertices.empty())
t.matrix.transformXY(&vertices[0], &vertices[0], (int) vertices.size()); t.matrix.transformXY(vertices.data(), vertices.data(), (int) vertices.size());
uploadVertices(vertices, voffset); uploadVertices(vertices, voffset);
+1 -1
View File
@@ -527,7 +527,7 @@ void Graphics::setActive(bool enable)
void Graphics::setShaderChanged() void Graphics::setShaderChanged()
{ {
dirtyRenderState |= STATE_SHADER; dirtyRenderState |= STATEBIT_SHADER;
++shaderSwitches; ++shaderSwitches;
} }
+10 -2
View File
@@ -1414,12 +1414,17 @@ void Graphics::setStencilMode(StencilAction action, CompareMode compare, int val
if (enablestencil != gl.isStateEnabled(OpenGL::ENABLE_STENCIL_TEST)) if (enablestencil != gl.isStateEnabled(OpenGL::ENABLE_STENCIL_TEST))
gl.setEnableState(OpenGL::ENABLE_STENCIL_TEST, enablestencil); gl.setEnableState(OpenGL::ENABLE_STENCIL_TEST, enablestencil);
GLenum glaction = GL_REPLACE; GLenum glaction = GL_KEEP;
switch (action) switch (action)
{ {
case STENCIL_KEEP:
glaction = GL_KEEP;
break;
case STENCIL_ZERO:
glaction = GL_ZERO;
break;
case STENCIL_REPLACE: case STENCIL_REPLACE:
default:
glaction = GL_REPLACE; glaction = GL_REPLACE;
break; break;
case STENCIL_INCREMENT: case STENCIL_INCREMENT:
@@ -1437,6 +1442,9 @@ void Graphics::setStencilMode(StencilAction action, CompareMode compare, int val
case STENCIL_INVERT: case STENCIL_INVERT:
glaction = GL_INVERT; glaction = GL_INVERT;
break; break;
case STENCIL_MAX_ENUM:
glaction = GL_KEEP;
break;
} }
/** /**
+6 -8
View File
@@ -298,20 +298,18 @@ void Texture::createTexture()
{ {
if (isCompressed() && (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME)) if (isCompressed() && (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME))
{ {
int slicecount = slices.getSliceCount(mip);
size_t mipsize = 0; 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)
auto id = slices.get(slice, mip); mipsize += id->getSize();
if (id != nullptr)
mipsize += id->getSize();
}
} }
if (mipsize > 0) 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++) for (int slice = 0; slice < slicecount; slice++)
+4 -1
View File
@@ -25,9 +25,12 @@
// SDL // SDL
#include <SDL_clipboard.h> #include <SDL_clipboard.h>
#include <SDL_cpuinfo.h> #include <SDL_cpuinfo.h>
#include <SDL_locale.h>
#include <SDL_version.h> #include <SDL_version.h>
#if SDL_VERSION_ATLEAST(2, 0, 14)
#include <SDL_locale.h>
#endif
namespace love namespace love
{ {
namespace system namespace system
+5 -5
View File
@@ -43,14 +43,14 @@ public:
virtual ~System() {} virtual ~System() {}
// Implements Module. // 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; void setClipboardText(const std::string &text) const override;
std::string getClipboardText() const; 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; std::vector<std::string> getPreferredLocales() const override;
private: private:
+5
View File
@@ -28,8 +28,13 @@ namespace window
static bool highDPIAllowed = false; 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) void setHighDPIAllowed(bool enable)
{ {
setHighDPIAllowedImplementation(enable);
highDPIAllowed = enable; highDPIAllowed = enable;
} }
+71 -6
View File
@@ -45,6 +45,8 @@
#if defined(LOVE_WINDOWS) #if defined(LOVE_WINDOWS)
#include <windows.h> #include <windows.h>
#include <dwmapi.h>
#include <VersionHelpers.h>
#elif defined(LOVE_MACOS) #elif defined(LOVE_MACOS)
#include "common/macos.h" #include "common/macos.h"
#endif #endif
@@ -53,10 +55,27 @@
#define APIENTRY #define APIENTRY
#endif #endif
#ifndef SDL_HINT_WINDOWS_DPI_SCALING
#define SDL_HINT_WINDOWS_DPI_SCALING "SDL_WINDOWS_DPI_SCALING"
#endif
namespace love namespace love
{ {
namespace window 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 namespace sdl
{ {
@@ -72,12 +91,6 @@ Window::Window()
, hasSDL203orEarlier(false) , hasSDL203orEarlier(false)
, contextAttribs() , 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) if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
throw love::Exception("Could not initialize SDL video subsystem (%s)", SDL_GetError()); throw love::Exception("Could not initialize SDL video subsystem (%s)", SDL_GetError());
@@ -1183,7 +1196,59 @@ bool Window::isMinimized() const
void Window::swapBuffers() void Window::swapBuffers()
{ {
if (glcontext) 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); SDL_GL_SwapWindow(window);
#ifdef LOVE_WINDOWS
if (useDwmFlush)
{
DwmFlush();
SDL_GL_SetSwapInterval(swapInterval);
}
#endif
}
} }
bool Window::hasFocus() const bool Window::hasFocus() const