Merge lp://staging/~ubuntu-sdk-team/ubuntu-ui-toolkit/dpr into lp://staging/ubuntu-ui-toolkit/staging

Proposed by Gerry Boland
Status: Merged
Approved by: Zsombor Egri
Approved revision: 1205
Merged at revision: 1605
Proposed branch: lp://staging/~ubuntu-sdk-team/ubuntu-ui-toolkit/dpr
Merge into: lp://staging/ubuntu-ui-toolkit/staging
Diff against target: 1044 lines (+747/-26)
22 files modified
debian/control (+5/-0)
src/Ubuntu/Components/plugin/ucqquickimageextension.cpp (+23/-3)
src/Ubuntu/Components/plugin/ucubuntushape.cpp (+17/-13)
src/Ubuntu/Components/plugin/ucunits.cpp (+46/-5)
src/Ubuntu/Components/plugin/ucunits.h (+1/-0)
tests/unit/add_makecheck.pri (+12/-1)
tests/unit/custom_qpa/README (+15/-0)
tests/unit/custom_qpa/custom.json (+3/-0)
tests/unit/custom_qpa/custom_qpa.pro (+15/-0)
tests/unit/custom_qpa/main.cpp (+54/-0)
tests/unit/custom_qpa/qcustombackingstore.cpp (+64/-0)
tests/unit/custom_qpa/qcustombackingstore.h (+55/-0)
tests/unit/custom_qpa/qcustomintegration.cpp (+112/-0)
tests/unit/custom_qpa/qcustomintegration.h (+74/-0)
tests/unit/runtest.sh (+2/-0)
tests/unit/tst_units/dpr1/dpr1.pro (+3/-0)
tests/unit/tst_units/dpr2/dpr2.pro (+3/-0)
tests/unit/tst_units/dpr2/tst_units_dpr2.cpp (+143/-0)
tests/unit/tst_units/dpr3/dpr3.pro (+3/-0)
tests/unit/tst_units/dpr3/tst_units_dpr3.cpp (+88/-0)
tests/unit/tst_units/tst_units.pro (+6/-3)
tests/unit/unit.pro (+3/-1)
To merge this branch: bzr merge lp://staging/~ubuntu-sdk-team/ubuntu-ui-toolkit/dpr
Reviewer Review Type Date Requested Status
Zsombor Egri Approve
PS Jenkins bot continuous-integration Approve
Loïc Molinari (community) Approve
Gerry Boland (community) Needs Information
Review via email: mp+256470@code.staging.launchpad.net

This proposal supersedes a proposal from 2015-04-16.

Commit message

Compensate for Qt's device pixel ratio multiplier

Description of the change

Compensate for Qt's device pixel ratio multiplier

The UITK has flexible UI scaling support through the use of Grid Units, where one can set a grid unit to be an integer number of pixels, and the whole UI adopts to suit this. GRID_UNIT_PX=10 is the way to set this.

Qt however has its own scaling solution: QScreen::devicePixelRatio->qreal which is a multiplier applied internally to all sizing/positioning calculations. Only integer values are well supported, so 1,2,3... are the options, resulting in a x2, x3 scaling of the entire UI. For linux and X11, devicePixelRatio is specified with QT_DEVICE_PIXEL_RATIO=2. In this case, if a QML item is set to have height 100, it will be drawn 200 pixels high (but QML has no idea of this, it is still 100 in height)

This latter solution works for all Qt apps, whereas Grid units only apply to UITK-based apps. For a HighDPI desktop, we want to use both solutions.

However these two scaling solutions are cumulative. Should one set
QT_DEVICE_PIXEL_RATIO=2 GRID_UNIT_PX=16
then a box of height units.gu(1) will be drawn 32 physical pixels high.

The intention of this MR is to guarantee that GRID_UNIT_PX corresponds to physical pixels, no matter what QScreen::devicePixelRatio returns. To do this, it divides units.{gu,dp} by devicePixelRatio, so that when Qt multiplies it by devicePixelRatio again on draw, the desired physical pixel size is obtained.

To test, open the gallery with these 2 different envs:
QT_DEVICE_PIXEL_RATIO=1 GRID_UNIT_PX=16
QT_DEVICE_PIXEL_RATIO=2 GRID_UNIT_PX=16

Some visual inconsistencies at small GU values are due to exact font rendering sizes and some rounding issues causing off-by-one positioning errors. QT_DEVICE_PIXEL_RATIO=2 GRID_UNIT_PX=8 is not a realistic choice however, likely would only switch to DPR2 when GU>=16.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

Ok, think this is ready for review. I added tests where I could, but would appreciate feedback on how I could test more.

Revision history for this message
Gerry Boland (gerboland) wrote :

+++ modules/Ubuntu/Components/plugin/ucunits.h
+ float devicePixelRatio() const;
should I worry about ABI breaking?

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Loïc Molinari (loic.molinari) wrote :

Just a quick comment before going deeper in the review, the ProgressBar is broken because ucubuntushapeoverlay.cpp hasn't been modified.

review: Needs Fixing
Revision history for this message
Gerry Boland (gerboland) wrote :

Thanks for the initial look, no idea how I missed that overlay issue, it's fixed now

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Loïc Molinari (loic.molinari) wrote :

> +++ modules/Ubuntu/Components/plugin/ucunits.h
> + float devicePixelRatio() const;
> should I worry about ABI breaking?

No worries, it's not an ABI break. And actually we don't care about ABI breaks since we don't export the shared object as a lib.

Revision history for this message
Loïc Molinari (loic.molinari) wrote :

> > +++ modules/Ubuntu/Components/plugin/ucunits.h
> > + float devicePixelRatio() const;
> > should I worry about ABI breaking?
>
> No worries, it's not an ABI break. And actually we don't care about ABI
> breaks since we don't export the shared object as a lib.

(Thinking about it the added floating-point value in the class would be an ABI break if we'd expose the lib)

Revision history for this message
Loïc Molinari (loic.molinari) wrote :
Download full text (3.7 KiB)

Good stuff. Here is a bunch of questions and remarks.

1)
In the shape, storing the radius as device-independent pixel like that

- float radius = UCUnits::instance().gridUnit() * (m_radius == Small ? smallRadiusGU : mediumRadiusGU);
- const float scaledDownRadius = qMin(itemSize.width(), itemSize.height()) * dpr * 0.5f * 0.8f;
+ float radius = UCUnits::instance().gu((m_radius == Small ? smallRadiusGU : mediumRadiusGU));
+ const float scaledDownRadius = qMin(itemSize.width(), itemSize.height()) * 0.5f * 0.8f;

would remove the need to multiply the item size by the dpr for the shape coordinates attributes in updateVertices() (for both UbuntuShape and UbuntuShapeOverlay). That would require to do change updateMaterial() though, but in a less intrusive way IMO:

@@ -1217,16 +1218,18 @@
         materialData->sourceOpacity = 0;
     }

+ const float physicalRadius = UCUnits::instance().devicePixelRatio() * radius;
+
     // Mapping of radius size range from [0, 4] to [0, 1] with clamping, plus quantization.
     const float start = 0.0f + radiusSizeOffset;
     const float end = 4.0f + radiusSizeOffset;
     materialData->distanceAAFactor = qMin(
- (radius / (end - start)) - (start / (end - start)), 1.0f) * 255.0f;
+ (physicalRadius / (end - start)) - (start / (end - start)), 1.0f) * 255.0f;

     // When the radius is equal to radiusSizeOffset (which means radius size is 0), no aspect is
     // flagged so that a dedicated (statically flow controlled) shaved off shader can be used for
     // optimal performance.
- if (radius > radiusSizeOffset) {
+ if (physicalRadius > radiusSizeOffset) {
         const quint8 aspectFlags[] = {
             ShapeMaterial::Data::Flat, ShapeMaterial::Data::Inset,
             ShapeMaterial::Data::Inset | ShapeMaterial::Data::Pressed

2) The previous change would allow to move the devicePixelRatio retrieval in updateGeometryNode() to the "if (m_flags & DirtySourceTransform) {" scope.

3)
- Q_INVOKABLE float dp(float value);
- Q_INVOKABLE float gu(float value);
+ Q_INVOKABLE float dp(const float value);
+ Q_INVOKABLE float gu(const float value);

Using const for value parameters (not for reference or pointer parameters) isn't a common practice in the toolkit (neither in Qt AFAIK). Is there a particular reason for it?

4) Wouldn't it be better (faster) to inline UCUnits::devicePixelRatio() definition in the header?

5) Talking about UCUnits::devicePixelRatio(), why do we have to expose it instead of using QGuiApplication::devicePixelRation() or QWindow::devicePixelRatio() directly? Same question for the "manual" retrieval of QT_DEVICE_PIXEL_RATIO in UCUnits constructor.

6) UCUnits::gu() and UCUnits:dp() returns "qRound(value * m_gridUnit) / m_devicePixelRatio", I'm wondering if the division should be applied before the rounding?

7) It took me some time to figure out the logic because I didn't realize we had to support QtWidgets as well. I think we'd better explain the whole decision somewhere in the project, either in the README or in the UCUnits module. I'd tend to go for a good explanation in the ucunits.cpp module documentation maybe adding toolkit implementation...

Read more...

review: Needs Fixing
Revision history for this message
Gerry Boland (gerboland) wrote :
Download full text (3.7 KiB)

> Good stuff. Here is a bunch of questions and remarks.
>
> 1)
> In the shape, storing the radius as device-independent pixel like that
>
> - float radius = UCUnits::instance().gridUnit() * (m_radius == Small ?
> smallRadiusGU : mediumRadiusGU);
> - const float scaledDownRadius = qMin(itemSize.width(), itemSize.height())
> * dpr * 0.5f * 0.8f;
> + float radius = UCUnits::instance().gu((m_radius == Small ? smallRadiusGU
> : mediumRadiusGU));
> + const float scaledDownRadius = qMin(itemSize.width(), itemSize.height())
> * 0.5f * 0.8f;
>
> would remove the need to multiply the item size by the dpr for the shape
> coordinates attributes in updateVertices() (for both UbuntuShape and
> UbuntuShapeOverlay). That would require to do change updateMaterial() though,
> but in a less intrusive way IMO:
<snip>
Done!

> 2) The previous change would allow to move the devicePixelRatio retrieval in
> updateGeometryNode() to the "if (m_flags & DirtySourceTransform) {" scope.
Done

> 3)
> - Q_INVOKABLE float dp(float value);
> - Q_INVOKABLE float gu(float value);
> + Q_INVOKABLE float dp(const float value);
> + Q_INVOKABLE float gu(const float value);
>
> Using const for value parameters (not for reference or pointer parameters)
> isn't a common practice in the toolkit (neither in Qt AFAIK). Is there a
> particular reason for it?
I had thought compiler could optimize a little better with this, but I'm told it's of no use. Reverted.

> 4) Wouldn't it be better (faster) to inline UCUnits::devicePixelRatio()
> definition in the header?
>
> 5) Talking about UCUnits::devicePixelRatio(), why do we have to expose it
> instead of using QGuiApplication::devicePixelRation() or
> QWindow::devicePixelRatio() directly? Same question for the "manual" retrieval
> of QT_DEVICE_PIXEL_RATIO in UCUnits constructor.

Yeah I got rid of this. I had mainly added it to UCUnits to ease mocking it for testing. Instead I've added a custom minimal QPA plugin to mock the value of devicePixelRatio(). So UCUnits API has be left unchanged by this MR.

>
> 6) UCUnits::gu() and UCUnits:dp() returns "qRound(value * m_gridUnit) /
> m_devicePixelRatio", I'm wondering if the division should be applied before
> the rounding?

I left the division after the rounding as Qt will take this value, multiply it by devicePixelRatio to calculate the physical pixels. I.e.
physicalPixels = [qRound(value * m_gridUnit) / m_devicePixelRatio] * m_devicePixelRatio
should be more correct than
physicalPixels = qRound(value * m_gridUnit / m_devicePixelRatio) * m_devicePixelRatio

> 7) It took me some time to figure out the logic because I didn't realize we
> had to support QtWidgets as well. I think we'd better explain the whole
> decision somewhere in the project, either in the README or in the UCUnits
> module. I'd tend to go for a good explanation in the ucunits.cpp module
> documentation maybe adding toolkit implementation details in there in a "non-
> exposed" comment if needed. We should also agree on a better naming for the
> units, currently there are grid units, device pixels, value density
> independent pixels, actual pixels, physical pixels, etc, it's very confusing.
> I...

Read more...

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1195. By Gerry Boland

Add missing build dependencies

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1196. By Gerry Boland

Bump version

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1197. By Gerry Boland

Merge staging and fix conflicts

1198. By Gerry Boland

Revert rev 1196

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1199. By Gerry Boland

Merge staging, fix a conflict

1200. By Gerry Boland

Undo changes to paths for gallery launcher

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1201. By Gerry Boland

Merge staging

Revision history for this message
Zsombor Egri (zsombi) wrote :

Small fixes, and we're good.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Loïc Molinari (loic.molinari) wrote :

I guess there's a merge problem, m_relativeRadius is defined two times in UCUbuntuShape initialisation list. Apart from that, everything looks good to me now.

Thanks for the changes and sorry for the delay to take a look back at that...

review: Approve
1202. By Gerry Boland

Fix build fail - variable inited twice

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1203. By Gerry Boland

Merge staging again

1204. By Gerry Boland

Merge staging again

1205. By Gerry Boland

Revert accidental changes to examples/ubuntu-ui-toolkit-gallery/po/nl.po

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Zsombor Egri (zsombi) wrote :

Good to go now! Thanks allot!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
The diff is not available at this time. You can reload the page or download it.

Subscribers

People subscribed via source and target branches