Skip to content

Conversation

@ide
Copy link
Contributor

@ide ide commented Feb 20, 2015

For a very simple view I was observing that the text background was black and had to manually be set to transparent. This ensures that text nodes have a transparent background by default.

Test Plan: This example component no longer renders what looks like a black block, and instead displays legible text.

var Example = React.createClass({
  render: function() {
      return (
        <View style={styles.container}>
          <Text>hello</Text>
        </View>
      );
  },
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
  },
};

@vjeux
Copy link
Contributor

vjeux commented Feb 20, 2015

The way it is setup (at least in fb repo, not sure how open source is yet) is that we propagate the background color from the parent. In most of cases this is working as intended and gives the nice property that the layers do not need to be blended. This makes the gpu part faster at only a small cost.

@ide
Copy link
Contributor Author

ide commented Feb 20, 2015

I will try to profile this later on a device to see the performance difference (or do you have numbers?). One thing is that UILabels are transparent but they are fast enough for UIKit apps so I don't know if the cost of blending is really a problem. The other thing is that I believe "opaque" on a UIView is a rendering hint, and iOS may optimize views with opaque background colors even if opaque = NO.

@vjeux
Copy link
Contributor

vjeux commented Feb 20, 2015

Cc @sahrens who implemented it and @a2 @nicklockwood who may have insight in terms of performance

@ide
Copy link
Contributor Author

ide commented Feb 20, 2015

I made a simple scroll view with 5000 text views:

  render() {
    var textRows = [];
    for (var ii = 0; ii < 5000; ii++) {
      textRows.push(
          <Text key={ii} style={styles.text}>
          This is a line of text
        </Text>
      );
    }
    return (
      <ScrollView>
        {textRows}
      </ScrollView>
    );
  }

var styles = StyleSheet.create({
  text: {
    color: 'blue',
  },
};

I profiled loading the screen on an iPhone 6 with iOS 8.2, waiting for it to render (this takes awhile) and then scrolling. This is what it looks like with opaque = NO:
translucent

Here it is with the default opaque = YES:
opaque

The demo consistently crashed when I set the background color of the scroll view's content container style, so I could not test inherited background colors.

I don't see a performance regression looking at the profiler charts so I believe this diff doesn't slow performance, or at least not in a way that matters. Additionally when I gave the text views an opaque background color (just "white"), toggling the "Color Blended Layers" option in the Core Animation profiler showed that they were not blended even though opaque = NO.

So my takeaway is: setting opaque = NO doesn't affect blending if the text views have a solid background color, which is what React usually will try to do. And if they don't have a solid background color and default to being transparent, then the performance difference is nominal and definitely not the bottleneck.

@sahrens
Copy link
Contributor

sahrens commented Feb 20, 2015

I think it's more of an issue with text overlaid on complex hierarchies (and semi-transparent views overlaid on those, e.g. the groups photo viewer shadow while swiping to dismiss), and on worse devices like iphone 4/4s.

Our groups app definitely shows tons of blending with this feature turned off.

Even if it's not enough of a win to save dropped frames, there can still be meaningful benefit from saving battery by doing less work on the GPU, and it saves developers who fire up the blended layers mode from thinking they need to manually fix all the red (since most everything will automatically come up green out of the box).

Finally, the Paper team mentioned that text renders more crisply into opaque buffers - I'm not sure if this is still true on iOS 8.

-Spencer

On Feb 19, 2015, at 11:23 PM, James Ide [email protected] wrote:

I made a simple scroll view with 5000 text views:

render() {
var textRows = [];
for (var ii = 0; ii < 5000; ii++) {
textRows.push(

This is a line of text

);
}
return (

{textRows}

);
}

var styles = StyleSheet.create({
text: {
color: 'blue',
},
};
I profiled loading the screen on an iPhone 6 with iOS 8.2, waiting for it to render (this takes awhile) and then scrolling. This is what it looks like with opaque = NO:

Here it is with the default opaque = YES:

The demo consistently crashed when I set the background color of the scroll view's content container style, so I could not test inherited background colors.

I don't see a performance regression looking at the profiler charts so I believe this diff doesn't slow performance, or at least not in a way that matters. Additionally when I gave the text views an opaque background color (just "white"), toggling the "Color Blended Layers" option in the Core Animation profiler showed that they were not blended even though opaque = NO.

So my takeaway is: setting opaque = NO doesn't affect blending if the text views have a solid background color, which is what React usually will try to do. And if they don't have a solid background color and default to being transparent, then the performance difference is nominal and definitely not the bottleneck.


Reply to this email directly or view it on GitHub.

@sahrens
Copy link
Contributor

sahrens commented Feb 20, 2015

That said, defaulting to transparent for the meantime seems ok.

-Spencer

On Feb 19, 2015, at 11:23 PM, James Ide [email protected] wrote:

I made a simple scroll view with 5000 text views:

render() {
var textRows = [];
for (var ii = 0; ii < 5000; ii++) {
textRows.push(

This is a line of text

);
}
return (

{textRows}

);
}

var styles = StyleSheet.create({
text: {
color: 'blue',
},
};
I profiled loading the screen on an iPhone 6 with iOS 8.2, waiting for it to render (this takes awhile) and then scrolling. This is what it looks like with opaque = NO:

Here it is with the default opaque = YES:

The demo consistently crashed when I set the background color of the scroll view's content container style, so I could not test inherited background colors.

I don't see a performance regression looking at the profiler charts so I believe this diff doesn't slow performance, or at least not in a way that matters. Additionally when I gave the text views an opaque background color (just "white"), toggling the "Color Blended Layers" option in the Core Animation profiler showed that they were not blended even though opaque = NO.

So my takeaway is: setting opaque = NO doesn't affect blending if the text views have a solid background color, which is what React usually will try to do. And if they don't have a solid background color and default to being transparent, then the performance difference is nominal and definitely not the bottleneck.


Reply to this email directly or view it on GitHub.

@ide
Copy link
Contributor Author

ide commented Feb 20, 2015

Hi Spencer,

That's really good to know. I hadn't thought about the the opaque bit letting the renderer optimizer transparent overlays. The text crispness is interesting too. It looks like the system pre-renders the glyphs with subpixel anti-aliasing in the opaque case. I believe on the latest screens (thinking about the 6 Plus) the visual fidelity will always be high since individual pixels are actually finer than subpixels on older devices. Cool stuff.

Our groups app definitely shows tons of blending with this feature turned off.

From what I understand, React propagates background color down the view hierarchy, so if an ancestor view were to set an opaque background color, all descendant text views would inherit it. Since the Core Animation debugger was showing all green even with opaque=NO as long the text views had an opaque background color, I believe this diff wouldn't deoptimize nor lower the rendering quality of the groups app but I'd like to know for sure.

For a very simple view I was observing that the text background was black and had to manually be set to transparent. This ensures that text nodes have a transparent background by default.

Test Plan: This example component no longer renders what looks like a black block, and instead displays legible text.

    var Example = React.createClass({
      render: function() {
          return (
            <View style={styles.container}>
              <Text>hello</Text>
            </View>
          );
      },
    });

    var styles = StyleSheet.create({
      container: {
        flex: 1,
      },
    };
@ide
Copy link
Contributor Author

ide commented Mar 25, 2015

This might be a helpful patch for new users who are trying out React Native, since when I first wrote some components they were rendered as black boxes (black text on a black background) without this diff. As far as I know this doesn't affect performance in cases where the text would have been displayed correctly (that is, not against a black background) and it's simple enough to get the no-blending optimization by setting a background color if blending ever becomes an issue.

@nicklockwood
Copy link
Contributor

I'm happy to land this.

@arasmussen arasmussen force-pushed the master branch 5 times, most recently from 9b61be2 to 41453a5 Compare March 26, 2015 02:57
@ide
Copy link
Contributor Author

ide commented Mar 26, 2015

See #256. Closing this since GitHub didn't handle the private -> public transition well.

@ide ide closed this Mar 26, 2015
harrykiselev pushed a commit to harrykiselev/react-native that referenced this pull request Aug 5, 2015
harrykiselev pushed a commit to harrykiselev/react-native that referenced this pull request Aug 5, 2015
acoates-ms pushed a commit to acoates-ms/react-native that referenced this pull request Jun 10, 2019
react-one pushed a commit to react-one/react-native that referenced this pull request Sep 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants