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
Scaled window dimensions off by 1 #123
Comments
You really need to tell us what compiler, platform, and compiler options you are using for your app and to build FLTK. The value 1.28 can be exactly represented using IEEE floating point representation (float or double); any other choice of floating point representation will likely result in floating point accuracy issues. |
@fire-eggs Are you sure that "1.28 can be exactly represented using IEEE floating point representation (float or double)"? I don't think so: 0.28 = 28/100 = 7/25 which can't be represented in a binary floating point system. What am I missing? Or did you mean "can't be exactly represented"? Which would likely explain the potential rounding error. Puzzled... |
Ha ha! I sit corrected! Microsoft VS2019, using "precise" floating point, 1.28f is 1.2799999714 or thereabouts. [Using 'fast' or 'strict' seems not to make a difference]. So now I'm confused! The output:
The program:
|
In the Google Group, @wcout out states he's on Ubuntu 16. I get the same results on Ubuntu 20 (g++ 9.3.0). Even with "Full" compliance Playing around further, the problem may be with mixing doubles and floats. To wit: |
My opinion is, that the rounding error manifests, when multiplying the scale with positions or dimensions. For me it was unexpected, that a multiplication that leads to an integral value (800*1.28 = 1024) in decimal system is not computed correctly. My suggestion would be to use a rounding function for these multiplications. This was just a test, a real change would probably be much more work as these scaling multiplications are spread over the code. Also
|
Yes, technically it would maybe be appropriate to use rounding, but this would not only introduce many, many code changes but also a speed penalty because it's used for all graphics coordinates. The "problem" with rounding is that it sometimes rounds up and sometimes down. This can be a problem with parallel lines in filled boxes with shades as in the Another option to gain a little more precision would be to use This is something only @ManoloFLTK can answer. @fire-eggs Note that in your examples even |
@wcout wrote:
Yes, from the POV of decimal arithmetic it looks unexpected, but as you see the problem lies in the limited floating point precision of the scaling factor |
Yes I agree it would be a huge change to adapt the drawing code as well, with uncertain outcome. |
@wcout: could you, please, explain what is the practical consequence, if any, of having a window About the use of type float rather than double for the scale factor: I assumed, without checking, |
@ManoloFLTK: I have an application with two monitors (each having 1024x768), where the second monitor is configured to extend the screen on the right side. Now two borderless windows of 800x600 are opened at 0/0 for the first monitor and 800/0 for the second (and scaled by FLTK). Due to the rounding error the second window is opened at 1023/0 instead of 1024/0, which disturbs the output of the first monitor on the last pixel column. This seem negligible, but in case of an animation displayed on the second monitor leads to annoying moving pixels on the first monitor. But I agree, a change to use rounding might open a lot of new potential bugs or drawing problems, as the current code is very well crafted now. |
To put it different: Is it considered inevitable, when a (borderless i.e. without window manager interaction) window is opened at say 20/60 and when that window later queries its coordinates gets reported to be at 19/59? That is what happens currently when there is scaling involved. This can at least cause failure to some unit tests. |
FYI: Even a borderless window is positioned by the window manager (WM) and, as your question implied, you're aware of the fact that x/y window coordinates are only a request to the WM for these coordinates and subject to be changed by the WM. To verify this for borderless windows I attach a modified test/hello.cxx where the borderless window "requests" position (-10, -10). The output on my Linux Mint system (WM: cinnamon) w/o scaling is:
Source: hello.cxx.txt Well, that's kinda nitpicking and doesn't resolve the issue at hand, but anyway... @wcout : were you able to resolve your positioning problem and can we close this issue now? |
Yes, true, some window managers may intercept negative top/left positions, but normally not any decent positive values.
Not without patching FLTK minimally and additionally tune the positions/dimensions of some windows of our application. |
OTOH: maybe it would be possible (w/o looking at the code actually) to round window positions only when creating windows. As you wrote:
Rounding window "dimensions" (i.e. width/height) could lead to all sorts of "pixel not drawn inside a window" issues and should certainly not be attempted. But I can see that rounding the positions would solve your (@wcout) issue and be a very limited change. Maybe we could try that ... (?) Can you tell us what you patched? Maybe this could be helpful. TIA. |
As discussed, only the window position becomes rounded to nearest integer value when a fractional GUI scale factor is applied.
Oh, thanks for tackling this issue, I will certainly try, when time permits... I'm getting a warning under Ubuntu 20.04 when compiling, that is new I think: Compiling drivers/X11/Fl_X11_Screen_Driver.cxx... drivers/X11/Fl_X11_Screen_Driver.cxx: In member function ‘virtual Fl_RGB_Image* Fl_X11_Screen_Driver::read_win_rectangle(int, int, int, int, Fl_Window*, bool, bool*)’: drivers/X11/Fl_X11_Screen_Driver.cxx:726:9: warning: ‘sy’ may be used uninitialized in this function [-Wmaybe-uninitialized] 726 | off = a - b; | ~~~~^~~~~~~ drivers/X11/Fl_X11_Screen_Driver.cxx:789:21: note: ‘sy’ was declared here 789 | int dx, dy, sx, sy, sw, sh; | ^~ Certainly it stems from line 821, where |
There's nothing to worry from that warning because no uninitialized variable is used. |
@ManoloFLTK Perhaps I'm missing something, but If |
The C language guarantees that if A is null, B is not evaluated in |
I've seen warnings in static code analyzers that really surprised me. They can check many, many cases, some of which are maybe "impossible" to be true (for human thinking) but the code analyzers still find a case ... Manolo is correct about evaluation of logical However, in that particular case (see @erco77's screenshot) I believe the point is that the compiler doesn't "know" that Fl::screen_xyhw() always returns a value in sx, sy, sw, and sh (if this is not the case for instance if the screen number is out of range then this is a fault). I've seen this in similar constructs with values returned by reference arguments. In this case the first It's probably wise to initialize these variables with 0 (zero) even if it's not really necessary (defensive programming). |
@wcout What compiler and which switches/options are you using to compile? |
Everything default (make without arguments), using g++. Ubuntu 20.04 is updated completley.
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 Copyright (C) 2019 Free Software Foundation, Inc. Disabling silent mode shows: Compiling drivers/X11/Fl_X11_Screen_Driver.cxx... g++ -I.. -I../jpeg -Os -Wall -Wunused -Wno-format-y2k -fno-exceptions -fno-strict-aliasing -ffunction-sections -fdata-sections -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_THREAD_SAFE -D_REENTRANT -I/usr/include/uuid -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/uuid -I/usr/include/freetype2 -I/usr/include/libpng16 -DFL_LIBRARY -c drivers/X11/Fl_X11_Screen_Driver.cxx -o drivers/X11/Fl_X11_Screen_Driver.o drivers/X11/Fl_X11_Screen_Driver.cxx: In member function ‘virtual Fl_RGB_Image* Fl_X11_Screen_Driver::read_win_rectangle(int, int, int, int, Fl_Window*, bool, bool*)’: drivers/X11/Fl_X11_Screen_Driver.cxx:726:9: warning: ‘sy’ may be used uninitialized in this function [-Wmaybe-uninitialized] 726 | off = a - b; | ~~~~^~~~~~~ drivers/X11/Fl_X11_Screen_Driver.cxx:789:21: note: ‘sy’ was declared here 789 | int dx, dy, sx, sy, sw, sh; | ^~ Maybe @ManoloFLTK does not use optimization? Or using cmake? |
I used the default optimization setting, that is -Os The code in Greg's screenshot is as before the commit that triggered the warning. Anyway, I agree defensive programming is the way to go. |
I think the initially reported problems have been addressed and fixed meanwhile by using rounding. |
Thanks for confirmation. Closing ... |
When setting a scale factor of 1.28 and opening a window with dimensions 800x600 xwininfo reports a size of 1023x767 pixels for the scaled window. This should be 1024x768. Same might be true with positions i.e. open at 800/600 will open at 1023/767.
The text was updated successfully, but these errors were encountered: