Fix high-DPI rendering/input on Windows

This commit is contained in:
Henrik Rydgård 2017-01-16 19:08:26 +07:00
parent da82237118
commit 8b5048be72
10 changed files with 69 additions and 61 deletions

View file

@ -130,12 +130,21 @@ bool Core_GetPowerSaving() {
return powerSaving;
}
// TODO: Feels like this belongs elsewhere.
bool UpdateScreenScale(int width, int height, bool smallWindow) {
g_dpi = 72;
#ifdef _WIN32
// Use legacy DPI handling, because we still compile as XP compatible we don't get the new SDK, unless
// we do unholy tricks.
HDC screenDC = GetDC(nullptr);
double hPixelsPerInch = GetDeviceCaps(screenDC, LOGPIXELSY);
ReleaseDC(nullptr, screenDC);
g_dpi = hPixelsPerInch;
g_dpi_scale = 96.0f / g_dpi;
#else
g_dpi = 96;
g_dpi_scale = 1.0f;
if (smallWindow) {
g_dpi_scale = 2.0f;
}
#endif
pixel_in_dps = 1.0f / g_dpi_scale;

View file

@ -28,6 +28,7 @@
#include <map>
#include <string>
#include "base/display.h"
#include "base/NativeApp.h"
#include "Globals.h"
@ -207,8 +208,8 @@ namespace MainWindow
// Can't take this from config as it will not be set if windows is maximized.
RECT rc;
GetWindowRect(hwndMain, &rc);
int width = rc.right - rc.left;
int height = rc.bottom - rc.top;
int width = (int)((rc.right - rc.left) * g_dpi_scale);
int height = (int)((rc.bottom - rc.top) * g_dpi_scale);
return g_Config.IsPortrait() ? (height < 480 + 80) : (width < 480 + 80);
}
@ -516,8 +517,6 @@ namespace MainWindow
}
LRESULT CALLBACK DisplayProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
// Only apply a factor > 1 in windowed mode.
int factor = !IsZoomed(GetHWND()) && !g_Config.bFullScreen && IsWindowSmall() ? 2 : 1;
static bool firstErase = true;
switch (message) {
@ -555,8 +554,8 @@ namespace MainWindow
input_state.mouse_valid = true;
input_state.pointer_down[0] = true;
input_state.pointer_x[0] = GET_X_LPARAM(lParam) * factor;
input_state.pointer_y[0] = GET_Y_LPARAM(lParam) * factor;
input_state.pointer_x[0] = GET_X_LPARAM(lParam) * g_dpi_scale;
input_state.pointer_y[0] = GET_Y_LPARAM(lParam) * g_dpi_scale;
}
TouchInput touch;
@ -598,8 +597,8 @@ namespace MainWindow
{
lock_guard guard(input_state.lock);
input_state.pointer_x[0] = GET_X_LPARAM(lParam) * factor;
input_state.pointer_y[0] = GET_Y_LPARAM(lParam) * factor;
input_state.pointer_x[0] = GET_X_LPARAM(lParam) * g_dpi_scale;
input_state.pointer_y[0] = GET_Y_LPARAM(lParam) * g_dpi_scale;
}
if (wParam & MK_LBUTTON) {
@ -622,8 +621,8 @@ namespace MainWindow
{
lock_guard guard(input_state.lock);
input_state.pointer_down[0] = false;
input_state.pointer_x[0] = GET_X_LPARAM(lParam) * factor;
input_state.pointer_y[0] = GET_Y_LPARAM(lParam) * factor;
input_state.pointer_x[0] = GET_X_LPARAM(lParam) * g_dpi_scale;
input_state.pointer_y[0] = GET_Y_LPARAM(lParam) * g_dpi_scale;
}
TouchInput touch;
touch.id = 0;

View file

@ -31,7 +31,8 @@
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<!-- Should really use True/PM (per-monitor) here but as we are XP-compatible, we don't have access to the headers. -->
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True</dpiAware>
</windowsSettings>
</application>
</assembly>

View file

@ -20,6 +20,7 @@
#include <vector>
#include "base/NativeApp.h"
#include "base/display.h"
#include "Common/Log.h"
#include "input/input_state.h"
#include "Windows/RawInput.h"
@ -202,8 +203,8 @@ namespace WindowsRawInput {
KeyInput key;
key.deviceId = DEVICE_ID_MOUSE;
mouseDeltaX += raw->data.mouse.lLastX;
mouseDeltaY += raw->data.mouse.lLastY;
g_mouseDeltaX += raw->data.mouse.lLastX;
g_mouseDeltaY += raw->data.mouse.lLastY;
if (raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) {
key.flags = KEY_DOWN;

View file

@ -4,6 +4,7 @@
#include <algorithm>
#include "base/display.h"
#include "Common/CommonWindows.h"
#include "input/input_state.h"
#include "base/NativeApp.h"
@ -71,8 +72,8 @@ void TouchInputHandler::handleTouchEvent(HWND hWnd, UINT message, WPARAM wParam,
}
POINT point;
point.x = TOUCH_COORD_TO_PIXEL(inputs[i].x);
point.y = TOUCH_COORD_TO_PIXEL(inputs[i].y);
point.x = (float)(TOUCH_COORD_TO_PIXEL(inputs[i].x)) * g_dpi_scale;
point.y = (float)(TOUCH_COORD_TO_PIXEL(inputs[i].y)) * g_dpi_scale;
if (ScreenToClient(hWnd, &point)){
if (inputs[i].dwFlags & TOUCHEVENTF_DOWN)

View file

@ -24,10 +24,13 @@
#include "objbase.h"
#include "objidl.h"
#include "shlguid.h"
#pragma warning(push)
#pragma warning(disable:4091) // workaround bug in VS2015 headers
#include "shlobj.h"
#pragma warning(pop)
// native stuff
#include "base/display.h"
#include "base/NativeApp.h"
#include "file/file_util.h"
#include "input/input_state.h"
@ -62,8 +65,8 @@
static const int numCPUs = 1;
float mouseDeltaX = 0;
float mouseDeltaY = 0;
float g_mouseDeltaX = 0;
float g_mouseDeltaY = 0;
static BOOL PostDialogMessage(Dialog *dialog, UINT message, WPARAM wParam = 0, LPARAM lParam = 0) {
return PostMessage(dialog->GetDlgHandle(), message, wParam, lParam);
@ -74,8 +77,8 @@ WindowsHost::WindowsHost(HINSTANCE hInstance, HWND mainWindow, HWND displayWindo
mainWindow_(mainWindow),
displayWindow_(displayWindow)
{
mouseDeltaX = 0;
mouseDeltaY = 0;
g_mouseDeltaX = 0;
g_mouseDeltaY = 0;
//add first XInput device to respond
input.push_back(std::shared_ptr<InputDevice>(new XinputDevice()));
@ -201,12 +204,14 @@ void WindowsHost::PollControllers(InputState &input_state) {
doPad = false;
}
mouseDeltaX *= 0.9f;
mouseDeltaY *= 0.9f;
g_mouseDeltaX *= 0.9f;
g_mouseDeltaY *= 0.9f;
// TODO: Tweak!
float mx = std::max(-1.0f, std::min(1.0f, mouseDeltaX * 0.01f));
float my = std::max(-1.0f, std::min(1.0f, mouseDeltaY * 0.01f));
float scaleFactor = g_dpi_scale * 0.01f;
float mx = std::max(-1.0f, std::min(1.0f, g_mouseDeltaX * scaleFactor));
float my = std::max(-1.0f, std::min(1.0f, g_mouseDeltaY * scaleFactor));
AxisInput axisX, axisY;
axisX.axisId = JOYSTICK_AXIS_MOUSE_REL_X;
axisX.deviceId = DEVICE_ID_MOUSE;

View file

@ -21,8 +21,8 @@
#include <list>
#include <memory>
extern float mouseDeltaX;
extern float mouseDeltaY;
extern float g_mouseDeltaX;
extern float g_mouseDeltaY;
class GraphicsContext;

View file

@ -23,6 +23,7 @@
#include <shellapi.h>
#include <mmsystem.h>
#include "base/display.h"
#include "file/vfs.h"
#include "file/zip_read.h"
#include "base/NativeApp.h"
@ -367,8 +368,7 @@ std::vector<std::wstring> GetWideCmdLine() {
return wideArgs;
}
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
{
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) {
setCurrentThreadName("Main");
CoInitializeEx(NULL, COINIT_MULTITHREADED);

View file

@ -1,3 +1,4 @@
#include "base/display.h"
#include "base/logging.h"
#include "base/stringutil.h"
#include "thin3d/thin3d.h"
@ -51,6 +52,7 @@ struct TextDrawerContext {
};
TextDrawer::TextDrawer(Draw::DrawContext *thin3d) : thin3d_(thin3d), ctx_(nullptr) {
// These probably shouldn't be state.
fontScaleX_ = 1.0f;
fontScaleY_ = 1.0f;
@ -73,16 +75,11 @@ TextDrawer::TextDrawer(Draw::DrawContext *thin3d) : thin3d_(thin3d), ctx_(nullpt
}
TextDrawer::~TextDrawer() {
for (auto iter : cache_) {
for (auto &iter : cache_) {
if (iter.second->texture)
iter.second->texture->Release();
delete iter.second;
}
cache_.clear();
for (auto iter : sizeCache_) {
delete iter.second;
}
sizeCache_.clear();
for (auto iter = fontMap_.begin(); iter != fontMap_.end(); ++iter) {
@ -118,6 +115,7 @@ uint32_t TextDrawer::SetFont(const char *fontName, int size, int flags) {
float textScale = 1.0f;
// TODO: Should the 72 really be 96? Oh well...
INT nHeight = -MulDiv( size, (INT)(GetDeviceCaps(ctx_->hDC, LOGPIXELSY) * textScale), 72 );
int dwBold = FW_LIGHT; ///FW_BOLD
font->hFont = CreateFont(nHeight, 0, 0, 0, dwBold, 0,
@ -147,7 +145,7 @@ void TextDrawer::MeasureString(const char *str, size_t len, float *w, float *h)
TextMeasureEntry *entry;
auto iter = sizeCache_.find(entryHash);
if (iter != sizeCache_.end()) {
entry = iter->second;
entry = iter->second.get();
} else {
auto iter = fontMap_.find(fontHash_);
if (iter != fontMap_.end()) {
@ -161,12 +159,12 @@ void TextDrawer::MeasureString(const char *str, size_t len, float *w, float *h)
entry = new TextMeasureEntry();
entry->width = size.cx;
entry->height = size.cy;
sizeCache_[entryHash] = entry;
sizeCache_[entryHash] = std::unique_ptr<TextMeasureEntry>(entry);
}
entry->lastUsedFrame = frameCount_;
*w = entry->width * fontScaleX_;
*h = entry->height * fontScaleY_;
*w = entry->width * fontScaleX_ * g_dpi_scale;
*h = entry->height * fontScaleY_ * g_dpi_scale;
}
void TextDrawer::MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align) {
@ -192,7 +190,7 @@ void TextDrawer::MeasureStringRect(const char *str, size_t len, const Bounds &bo
TextMeasureEntry *entry;
auto iter = sizeCache_.find(entryHash);
if (iter != sizeCache_.end()) {
entry = iter->second;
entry = iter->second.get();
} else {
SIZE size;
std::wstring wstr = ConvertUTF8ToWString(lines[i].length() == 0 ? " " : lines[i]);
@ -201,7 +199,7 @@ void TextDrawer::MeasureStringRect(const char *str, size_t len, const Bounds &bo
entry = new TextMeasureEntry();
entry->width = size.cx;
entry->height = size.cy;
sizeCache_[entryHash] = entry;
sizeCache_[entryHash] = std::unique_ptr<TextMeasureEntry>(entry);
}
entry->lastUsedFrame = frameCount_;
@ -210,8 +208,8 @@ void TextDrawer::MeasureStringRect(const char *str, size_t len, const Bounds &bo
}
total_h += entry->height * fontScaleY_;
}
*w = total_w;
*h = total_h;
*w = total_w * g_dpi_scale;
*h = total_h * g_dpi_scale;
}
void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) {
@ -228,7 +226,7 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float
auto iter = cache_.find(entryHash);
if (iter != cache_.end()) {
entry = iter->second;
entry = iter->second.get();
entry->lastUsedFrame = frameCount_;
} else {
// Render the string to our bitmap and save to a GL texture.
@ -285,14 +283,14 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float
entry->texture->Finalize(0);
delete [] bitmapData;
cache_[entryHash] = entry;
cache_[entryHash] = std::unique_ptr<TextStringEntry>(entry);
}
thin3d_->BindTexture(0, entry->texture);
// Okay, the texture is bound, let's draw.
float w = entry->bmWidth * fontScaleX_;
float h = entry->bmHeight * fontScaleY_;
float w = entry->bmWidth * fontScaleX_ * g_dpi_scale;
float h = entry->bmHeight * fontScaleY_ * g_dpi_scale;
DrawBuffer::DoAlign(align, &x, &y, &w, &h);
target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color);
target.Flush(true);
@ -306,16 +304,11 @@ TextDrawer::TextDrawer(Draw::DrawContext *thin3d) : thin3d_(thin3d), ctx_(NULL)
}
TextDrawer::~TextDrawer() {
for (auto iter : cache_) {
for (auto &iter : cache_) {
if (iter.second->texture)
iter.second->texture->Release();
delete iter.second;
}
cache_.clear();
for (auto iter : sizeCache_) {
delete iter.second;
}
sizeCache_.clear();
}
@ -398,7 +391,7 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float
auto iter = cache_.find(entryHash);
if (iter != cache_.end()) {
entry = iter->second;
entry = iter->second.get();
entry->lastUsedFrame = frameCount_;
thin3d_->BindTexture(0, entry->texture);
} else {
@ -436,7 +429,7 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float
delete [] bitmapData;
cache_[entryHash] = entry;
cache_[entryHash] = std::unique_ptr<TextStringEntry>(entry);
}
float w = entry->bmWidth * fontScaleX_;
float h = entry->bmHeight * fontScaleY_;
@ -489,7 +482,6 @@ void TextDrawer::OncePerFrame() {
if (frameCount_ - iter->second->lastUsedFrame > 100) {
if (iter->second->texture)
iter->second->texture->Release();
delete iter->second;
cache_.erase(iter++);
} else {
iter++;
@ -498,7 +490,6 @@ void TextDrawer::OncePerFrame() {
for (auto iter = sizeCache_.begin(); iter != sizeCache_.end(); ) {
if (frameCount_ - iter->second->lastUsedFrame > 100) {
delete iter->second;
sizeCache_.erase(iter++);
} else {
iter++;

View file

@ -9,6 +9,7 @@
#pragma once
#include <map>
#include <memory>
#include "base/basictypes.h"
#include "gfx_es2/draw_buffer.h"
@ -82,6 +83,6 @@ private:
uint32_t fontHash_;
// The key is the CityHash of the string xor the fontHash_.
std::map<uint32_t, TextStringEntry *> cache_;
std::map<uint32_t, TextMeasureEntry *> sizeCache_;
std::map<uint32_t, std::unique_ptr<TextStringEntry> > cache_;
std::map<uint32_t, std::unique_ptr<TextMeasureEntry> > sizeCache_;
};