Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DPI: Simplify by removing support for non-square pixels #20010

Merged
merged 1 commit into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions Common/Render/DrawBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,14 @@ void DrawBuffer::Rect(float x, float y, float w, float h, uint32_t color, int al

void DrawBuffer::hLine(float x1, float y, float x2, uint32_t color) {
// Round Y to the closest full pixel, since we're making it 1-pixel-thin.
y -= fmodf(y, g_display.pixel_in_dps_y);
Rect(x1, y, x2 - x1, g_display.pixel_in_dps_y, color);
y -= fmodf(y, g_display.pixel_in_dps);
Rect(x1, y, x2 - x1, g_display.pixel_in_dps, color);
}

void DrawBuffer::vLine(float x, float y1, float y2, uint32_t color) {
// Round X to the closest full pixel, since we're making it 1-pixel-thin.
x -= fmodf(x, g_display.pixel_in_dps_x);
Rect(x, y1, g_display.pixel_in_dps_x, y2 - y1, color);
x -= fmodf(x, g_display.pixel_in_dps);
Rect(x, y1, g_display.pixel_in_dps, y2 - y1, color);
}

void DrawBuffer::RectVGradient(float x1, float y1, float x2, float y2, uint32_t colorTop, uint32_t colorBottom) {
Expand All @@ -129,11 +129,11 @@ void DrawBuffer::RectVGradient(float x1, float y1, float x2, float y2, uint32_t
}

void DrawBuffer::RectOutline(float x, float y, float w, float h, uint32_t color, int align) {
hLine(x, y, x + w + g_display.pixel_in_dps_x, color);
hLine(x, y + h, x + w + g_display.pixel_in_dps_x, color);
hLine(x, y, x + w + g_display.pixel_in_dps, color);
hLine(x, y + h, x + w + g_display.pixel_in_dps, color);

vLine(x, y, y + h + g_display.pixel_in_dps_y, color);
vLine(x + w, y, y + h + g_display.pixel_in_dps_y, color);
vLine(x, y, y + h + g_display.pixel_in_dps, color);
vLine(x + w, y, y + h + g_display.pixel_in_dps, color);
}

void DrawBuffer::MultiVGradient(float x, float y, float w, float h, const GradientStop *stops, int numStops) {
Expand Down
2 changes: 1 addition & 1 deletion Common/Render/Text/draw_text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void TextDrawer::SetFontScale(float xscale, float yscale) {
float TextDrawer::CalculateDPIScale() const {
if (ignoreGlobalDpi_)
return dpiScale_;
float scale = g_display.dpi_scale_y;
float scale = g_display.dpi_scale;
if (scale >= 1.0f) {
scale = 1.0f;
}
Expand Down
15 changes: 8 additions & 7 deletions Common/System/Display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ void DisplayProperties::Print() {
printf("dp_xres/yres: %d, %d\n", dp_xres, dp_yres);
printf("pixel_xres/yres: %d, %d\n", pixel_xres, pixel_yres);

printf("dpi, x, y: %f, %f, %f\n", dpi, dpi_scale_x, dpi_scale_y);
printf("pixel_in_dps: %f, %f\n", pixel_in_dps_x, pixel_in_dps_y);
printf("dpi, dpi_scale: %f, %f\n", dpi, dpi_scale);
printf("pixel_in_dps: %f\n", pixel_in_dps);

printf("dpi_real: %f, %f\n", dpi_scale_real_x, dpi_scale_real_y);
printf("dpi_real: %f\n", dpi_scale_real);
printf("display_hz: %f\n", display_hz);

printf("rotation: %d\n", (int)rotation);
Expand All @@ -77,14 +77,15 @@ Lin::Matrix4x4 ComputeOrthoMatrix(float xres, float yres, CoordConvention coordC
ortho.setOrthoD3D(0.0f, xres, 0, yres, -1.0f, 1.0f);
break;
case CoordConvention::Direct3D9:
{
ortho.setOrthoD3D(0.0f, xres, yres, 0.0f, -1.0f, 1.0f);
Matrix4x4 translation;
// Account for the small window adjustment.
translation.setTranslation(Vec3(
-0.5f * g_display.dpi_scale_x / g_display.dpi_scale_real_x,
-0.5f * g_display.dpi_scale_y / g_display.dpi_scale_real_y, 0.0f));
float half_pixel = -0.5f * g_display.dpi_scale / g_display.dpi_scale_real;
Matrix4x4 translation;
translation.setTranslation(Vec3(half_pixel, half_pixel, 0.0f));
ortho = translation * ortho;
break;
}
case CoordConvention::Direct3D11:
ortho.setOrthoD3D(0.0f, xres, yres, 0.0f, -1.0f, 1.0f);
break;
Expand Down
13 changes: 6 additions & 7 deletions Common/System/Display.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,21 @@ enum class DisplayRotation {
};

struct DisplayProperties {
// Display resolution in virtual ("display") pixels
int dp_xres;
int dp_yres;
// Display resolution in true pixels.
int pixel_xres;
int pixel_yres;

float dpi = 1.0f; // will be overwritten with a value that makes sense.
float dpi_scale_x = 1.0f;
float dpi_scale_y = 1.0f;
float dpi = 1.0f;
float dpi_scale = 1.0f;

// pixel_xres/yres in dps
float pixel_in_dps_x = 1.0f;
float pixel_in_dps_y = 1.0f;
float pixel_in_dps = 1.0f;

// If DPI is overridden (like in small window mode), these are still the original DPI.
float dpi_scale_real_x = 1.0f;
float dpi_scale_real_y = 1.0f;
float dpi_scale_real = 1.0f;

float display_hz = 60.0f;

Expand Down
11 changes: 5 additions & 6 deletions Common/UI/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,12 @@ Bounds UIContext::GetLayoutBounds() const {
void UIContext::ActivateTopScissor() {
Bounds bounds;
if (scissorStack_.size()) {
float scale_x = g_display.pixel_in_dps_x;
float scale_y = g_display.pixel_in_dps_y;
const float scale = g_display.pixel_in_dps;
bounds = scissorStack_.back();
int x = floorf(scale_x * bounds.x);
int y = floorf(scale_y * bounds.y);
int w = std::max(0.0f, ceilf(scale_x * bounds.w));
int h = std::max(0.0f, ceilf(scale_y * bounds.h));
int x = floorf(scale * bounds.x);
int y = floorf(scale * bounds.y);
int w = std::max(0.0f, ceilf(scale * bounds.w));
int h = std::max(0.0f, ceilf(scale * bounds.h));
if (x < 0 || y < 0 || x + w > g_display.pixel_xres || y + h > g_display.pixel_yres) {
DEBUG_LOG(Log::G3D, "UI scissor out of bounds: %d,%d-%d,%d / %d,%d", x, y, w, h, g_display.pixel_xres, g_display.pixel_yres);
if (x < 0) { w += x; x = 0; }
Expand Down
6 changes: 3 additions & 3 deletions Common/VR/PPSSPPVR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ void SetVRAppMode(VRAppMode mode) {
appMode = mode;
}

void UpdateVRInput(bool haptics, float dp_xscale, float dp_yscale) {
void UpdateVRInput(bool haptics, float dp_scale) {
//axis
if (pspKeys[(int)VIRTKEY_VR_CAMERA_ADJUST]) {
AxisInput axis[2] = {};
Expand Down Expand Up @@ -321,8 +321,8 @@ void UpdateVRInput(bool haptics, float dp_xscale, float dp_yscale) {
//inform engine about the status
TouchInput touch;
touch.id = mouseController;
touch.x = x * dp_xscale;
touch.y = (height - y - 1) * dp_yscale / VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT);
touch.x = x * dp_scale;
touch.y = (height - y - 1) * dp_scale / VR_GetConfigFloat(VR_CONFIG_CANVAS_ASPECT);
bool pressed = IN_VRGetButtonState(mouseController) & ovrButton_Trigger;
if (mousePressed != pressed) {
if (pressed) {
Expand Down
2 changes: 1 addition & 1 deletion Common/VR/PPSSPPVR.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void SetVRCallbacks(void(*axis)(const AxisInput *axis, size_t count), bool(*key)

// VR input integration
void SetVRAppMode(VRAppMode mode);
void UpdateVRInput(bool haptics, float dp_xscale, float dp_yscale);
void UpdateVRInput(bool haptics, float dp_scale);
bool UpdateVRAxis(const AxisInput *axes, size_t count);
bool UpdateVRKeys(const KeyInput &key);

Expand Down
4 changes: 2 additions & 2 deletions Core/HLE/sceAtrac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ static u32 AtracValidateData(const AtracBase *atrac) {
} else if (atrac->BufferState() == ATRAC_STATUS_NO_DATA) {
return hleLogError(Log::ME, ATRAC_ERROR_NO_DATA, "no data");
} else {
return 0;
return hleNoLog(0);
}
}

Expand All @@ -223,7 +223,7 @@ static u32 AtracValidateManaged(const AtracBase *atrac) {
} else if (atrac->BufferState() == ATRAC_STATUS_FOR_SCESAS) {
return hleLogError(Log::ME, ATRAC_ERROR_IS_FOR_SCESAS, "SAS stream, can't use");
} else {
return 0;
return hleNoLog(0);
}
}

Expand Down
7 changes: 3 additions & 4 deletions Core/TiltEventProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,16 +360,15 @@ void ProcessDelta(double now, float dx, float dy) {
void MouseDeltaToAxes(double now, float *mx, float *my) {
std::unique_lock<std::mutex> lock(g_mouseMutex);

float scaleFactor_x = g_display.dpi_scale_x * 0.1 * g_Config.fMouseSensitivity;
float scaleFactor_y = g_display.dpi_scale_y * 0.1 * g_Config.fMouseSensitivity;
float scaleFactor = g_display.dpi_scale * 0.1 * g_Config.fMouseSensitivity;

DecayMouse(now);

// TODO: Make configurable.
float mouseDeadZone = 0.1f;

float outX = clamp_value(g_mouseDeltaX * scaleFactor_x, -1.0f, 1.0f);
float outY = clamp_value(g_mouseDeltaY * scaleFactor_y, -1.0f, 1.0f);
float outX = clamp_value(g_mouseDeltaX * scaleFactor, -1.0f, 1.0f);
float outY = clamp_value(g_mouseDeltaY * scaleFactor, -1.0f, 1.0f);

ApplyDeadzoneXY(outX, outY, mx, my, mouseDeadZone, true);
}
Expand Down
8 changes: 4 additions & 4 deletions GPU/Common/PresentationCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ FRect GetScreenFrame(float pixelWidth, float pixelHeight) {

if (applyInset) {
// Remove the DPI scale to get back to pixels.
float left = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) / g_display.dpi_scale_x;
float right = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) / g_display.dpi_scale_x;
float top = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) / g_display.dpi_scale_y;
float bottom = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) / g_display.dpi_scale_y;
float left = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) / g_display.dpi_scale;
float right = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) / g_display.dpi_scale;
float top = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) / g_display.dpi_scale;
float bottom = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) / g_display.dpi_scale;

// Adjust left edge to compensate for cutouts (notches) if any.
rc.x += left;
Expand Down
27 changes: 13 additions & 14 deletions Qt/QtMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,15 +585,15 @@ bool MainUI::event(QEvent *e) {
break;
case Qt::TouchPointPressed:
case Qt::TouchPointReleased:
input.x = touchPoint.pos().x() * g_display.dpi_scale_x * xscale;
input.y = touchPoint.pos().y() * g_display.dpi_scale_y * yscale;
input.x = touchPoint.pos().x() * g_display.dpi_scale * xscale;
input.y = touchPoint.pos().y() * g_display.dpi_scale * yscale;
input.flags = (touchPoint.state() == Qt::TouchPointPressed) ? TOUCH_DOWN : TOUCH_UP;
input.id = touchPoint.id();
NativeTouch(input);
break;
case Qt::TouchPointMoved:
input.x = touchPoint.pos().x() * g_display.dpi_scale_x * xscale;
input.y = touchPoint.pos().y() * g_display.dpi_scale_y * yscale;
input.x = touchPoint.pos().x() * g_display.dpi_scale * xscale;
input.y = touchPoint.pos().y() * g_display.dpi_scale * yscale;
input.flags = TOUCH_MOVE;
input.id = touchPoint.id();
NativeTouch(input);
Expand All @@ -611,8 +611,8 @@ bool MainUI::event(QEvent *e) {
case QEvent::MouseButtonRelease:
switch(((QMouseEvent*)e)->button()) {
case Qt::LeftButton:
input.x = ((QMouseEvent*)e)->pos().x() * g_display.dpi_scale_x * xscale;
input.y = ((QMouseEvent*)e)->pos().y() * g_display.dpi_scale_y * yscale;
input.x = ((QMouseEvent*)e)->pos().x() * g_display.dpi_scale * xscale;
input.y = ((QMouseEvent*)e)->pos().y() * g_display.dpi_scale * yscale;
input.flags = (e->type() == QEvent::MouseButtonPress) ? TOUCH_DOWN : TOUCH_UP;
input.id = 0;
NativeTouch(input);
Expand All @@ -634,8 +634,8 @@ bool MainUI::event(QEvent *e) {
}
break;
case QEvent::MouseMove:
input.x = ((QMouseEvent*)e)->pos().x() * g_display.dpi_scale_x * xscale;
input.y = ((QMouseEvent*)e)->pos().y() * g_display.dpi_scale_y * yscale;
input.x = ((QMouseEvent*)e)->pos().x() * g_display.dpi_scale * xscale;
input.y = ((QMouseEvent*)e)->pos().y() * g_display.dpi_scale * yscale;
input.flags = TOUCH_MOVE;
input.id = 0;
NativeTouch(input);
Expand Down Expand Up @@ -842,12 +842,11 @@ int main(int argc, char *argv[])
g_display.pixel_xres = res.width();
g_display.pixel_yres = res.height();

g_display.dpi_scale_x = screen->logicalDotsPerInchX() / screen->physicalDotsPerInchX();
g_display.dpi_scale_y = screen->logicalDotsPerInchY() / screen->physicalDotsPerInchY();
g_display.dpi_scale_real_x = g_display.dpi_scale_x;
g_display.dpi_scale_real_y = g_display.dpi_scale_y;
g_display.dp_xres = (int)(g_display.pixel_xres * g_display.dpi_scale_x);
g_display.dp_yres = (int)(g_display.pixel_yres * g_display.dpi_scale_y);
g_display.dpi_scale = screen->logicalDotsPerInchX() / screen->physicalDotsPerInchX();
// We assume physicalDotsPerInchY is the same as PerInchX.
g_display.dpi_scale_real = g_display.dpi_scale;
g_display.dp_xres = (int)(g_display.pixel_xres * g_display.dpi_scale);
g_display.dp_yres = (int)(g_display.pixel_yres * g_display.dpi_scale);

refreshRate = screen->refreshRate();

Expand Down
16 changes: 8 additions & 8 deletions SDL/SDLMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -759,8 +759,8 @@ static void ProcessSDLEvent(SDL_Window *window, const SDL_Event &event, InputSta
// - SDL gives us motion events in "system DPI" points
// - Native_UpdateScreenScale expects pixels, so in a way "96 DPI" points
// - The UI code expects motion events in "logical DPI" points
float mx = event.motion.x * g_DesktopDPI * g_display.dpi_scale_x;
float my = event.motion.y * g_DesktopDPI * g_display.dpi_scale_x;
float mx = event.motion.x * g_DesktopDPI * g_display.dpi_scale;
float my = event.motion.y * g_DesktopDPI * g_display.dpi_scale;

switch (event.type) {
case SDL_QUIT:
Expand Down Expand Up @@ -913,8 +913,8 @@ static void ProcessSDLEvent(SDL_Window *window, const SDL_Event &event, InputSta
SDL_GetWindowSize(window, &w, &h);
TouchInput input;
input.id = event.tfinger.fingerId;
input.x = event.tfinger.x * w * g_DesktopDPI * g_display.dpi_scale_x;
input.y = event.tfinger.y * h * g_DesktopDPI * g_display.dpi_scale_x;
input.x = event.tfinger.x * w * g_DesktopDPI * g_display.dpi_scale;
input.y = event.tfinger.y * h * g_DesktopDPI * g_display.dpi_scale;
input.flags = TOUCH_MOVE;
input.timestamp = event.tfinger.timestamp;
NativeTouch(input);
Expand All @@ -926,8 +926,8 @@ static void ProcessSDLEvent(SDL_Window *window, const SDL_Event &event, InputSta
SDL_GetWindowSize(window, &w, &h);
TouchInput input;
input.id = event.tfinger.fingerId;
input.x = event.tfinger.x * w * g_DesktopDPI * g_display.dpi_scale_x;
input.y = event.tfinger.y * h * g_DesktopDPI * g_display.dpi_scale_x;
input.x = event.tfinger.x * w * g_DesktopDPI * g_display.dpi_scale;
input.y = event.tfinger.y * h * g_DesktopDPI * g_display.dpi_scale;
input.flags = TOUCH_DOWN;
input.timestamp = event.tfinger.timestamp;
NativeTouch(input);
Expand All @@ -945,8 +945,8 @@ static void ProcessSDLEvent(SDL_Window *window, const SDL_Event &event, InputSta
SDL_GetWindowSize(window, &w, &h);
TouchInput input;
input.id = event.tfinger.fingerId;
input.x = event.tfinger.x * w * g_DesktopDPI * g_display.dpi_scale_x;
input.y = event.tfinger.y * h * g_DesktopDPI * g_display.dpi_scale_x;
input.x = event.tfinger.x * w * g_DesktopDPI * g_display.dpi_scale;
input.y = event.tfinger.y * h * g_DesktopDPI * g_display.dpi_scale;
input.flags = TOUCH_UP;
input.timestamp = event.tfinger.timestamp;
NativeTouch(input);
Expand Down
8 changes: 4 additions & 4 deletions UI/DevScreens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1276,15 +1276,15 @@ void TouchTestScreen::DrawForeground(UIContext &dc) {
"display_res: %dx%d\n"
#endif
"dp_res: %dx%d pixel_res: %dx%d\n"
"g_dpi: %0.3f g_dpi_scale: %0.3fx%0.3f\n"
"g_dpi_scale_real: %0.3fx%0.3f\n"
"g_dpi: %0.3f g_dpi_scale: %0.3f\n"
"g_dpi_scale_real: %0.3f\n"
"delta: %0.2f ms fps: %0.3f\n%s",
#if PPSSPP_PLATFORM(ANDROID)
(int)System_GetPropertyInt(SYSPROP_DISPLAY_XRES), (int)System_GetPropertyInt(SYSPROP_DISPLAY_YRES),
#endif
g_display.dp_xres, g_display.dp_yres, g_display.pixel_xres, g_display.pixel_yres,
g_display.dpi, g_display.dpi_scale_x, g_display.dpi_scale_y,
g_display.dpi_scale_real_x, g_display.dpi_scale_real_y,
g_display.dpi, g_display.dpi_scale,
g_display.dpi_scale_real,
delta * 1000.0, 1.0 / delta,
extra_debug);

Expand Down
8 changes: 4 additions & 4 deletions UI/DisplayLayoutScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ enum Mode {

static Bounds FRectToBounds(FRect rc) {
Bounds b;
b.x = rc.x * g_display.dpi_scale_x;
b.y = rc.y * g_display.dpi_scale_y;
b.w = rc.w * g_display.dpi_scale_x;
b.h = rc.h * g_display.dpi_scale_y;
b.x = rc.x * g_display.dpi_scale;
b.y = rc.y * g_display.dpi_scale;
b.w = rc.w * g_display.dpi_scale;
b.h = rc.h * g_display.dpi_scale;
return b;
}

Expand Down
8 changes: 4 additions & 4 deletions UI/GamepadEmu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1021,8 +1021,8 @@ bool GestureGamepad::Touch(const TouchInput &input) {

if (g_Config.bAnalogGesture) {
const float k = g_Config.fAnalogGestureSensibility * 0.02;
float dx = (input.x - downX_)*g_display.dpi_scale_x * k;
float dy = (input.y - downY_)*g_display.dpi_scale_y * k;
float dx = (input.x - downX_) * g_display.dpi_scale * k;
float dy = (input.y - downY_) * g_display.dpi_scale * k;
dx = std::min(1.0f, std::max(-1.0f, dx));
dy = std::min(1.0f, std::max(-1.0f, dy));
__CtrlSetAnalogXY(0, dx, -dy);
Expand Down Expand Up @@ -1062,8 +1062,8 @@ void GestureGamepad::Draw(UIContext &dc) {

void GestureGamepad::Update() {
const float th = 1.0f;
float dx = deltaX_ * g_display.dpi_scale_x * g_Config.fSwipeSensitivity;
float dy = deltaY_ * g_display.dpi_scale_y * g_Config.fSwipeSensitivity;
float dx = deltaX_ * g_display.dpi_scale * g_Config.fSwipeSensitivity;
float dy = deltaY_ * g_display.dpi_scale * g_Config.fSwipeSensitivity;
if (g_Config.iSwipeRight != 0) {
if (dx > th) {
controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeRight-1], KEY_DOWN);
Expand Down
4 changes: 2 additions & 2 deletions UI/MiscScreens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ class WaveAnimation : public Animation {
dc.Draw()->RectVGradient(x, wave1*bounds.h, nextX, bounds.h, color, 0x00000000);

// Add some "antialiasing"
dc.Draw()->RectVGradient(x, wave0*bounds.h-3.0f * g_display.pixel_in_dps_y, nextX, wave0 * bounds.h, 0x00000000, color);
dc.Draw()->RectVGradient(x, wave1*bounds.h-3.0f * g_display.pixel_in_dps_y, nextX, wave1 * bounds.h, 0x00000000, color);
dc.Draw()->RectVGradient(x, wave0*bounds.h-3.0f * g_display.pixel_in_dps, nextX, wave0 * bounds.h, 0x00000000, color);
dc.Draw()->RectVGradient(x, wave1*bounds.h-3.0f * g_display.pixel_in_dps, nextX, wave1 * bounds.h, 0x00000000, color);
}

dc.Flush();
Expand Down
Loading
Loading