Closed Bug 192795 Opened 22 years ago Closed 17 years ago

Scrolling w/backing store enabled causes black flashes

Categories

(Core :: Web Painting, defect)

x86
Linux
defect
Not set
normal

Tracking

()

RESOLVED WONTFIX

People

(Reporter: jay, Assigned: blizzard)

Details

User-Agent:       Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.0.3705)
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2b) Gecko/20021016

When scrolling the screen over an X-Window connection, Mozilla doesn't draw 
into the backing store until after the scroll has completed.  This results in 
a flashing black rectangle as the virgin backing store scrolls into view.  

This behavior can be duplicated with all 7.x and 8.x versions of Hummingbird 
Exceed when default backing store is set to "When Mapped" or "Always".  
According to a Hummingbird developer, Exceed is doing the right thing, and 
Mozilla should be drawing into the backing store before scrolling.  Makes 
sense to me.  Their QA # is 32740, and their incident # is 2531098.

I cannot duplicate this using XFree86 instead of Exceed, but I am very 
unfamiliar with XFree, and it may not support backing stores.

Reproducible: Always

Steps to Reproduce:
1. Open the Mozilla browser over an X Window connection on a PC running 
Hummingbird Exceed 
2. Make sure the default backing store is set to "When Mapped".  (Under Exceed 
8.0, right-click on the tray icon, select Tools | Configuration, go to Other 
Server Settings, and look at the Performance tab.)
3. Load any web page in Mozilla and scroll down.

Actual Results:  
A black flashing rectangle briefly appears while the screen is redrawn.

Expected Results:  
No black flashing rectangle should appear.
I bet roc wants this....
Assignee: other → roc+moz
Component: Layout → Layout: View Rendering
I know nothing about X backing stores. Reassigning to blizzard.

Although I suspect there's not much we can do about this except disable
scrolling completely and do a full repaint, though that would really suck for
remote connections. AFAIK there is simply no way to ensure that a bitblt scroll
operation and a repaint operation are done simultaneously in the X server.
Assignee: roc+moz → blizzard
I know nothing at all about X, but the phrase "When Mapped" suggests that 
there's some way for the application to say "No thanks, no backing store".  I 
am using Mozilla over a LAN, so I don't know what the behavior is over a 
dialup connection.  Does using the backing store gain you speed at the expense 
of this flashing?  It doesn't affect speed over the LAN, so if you can't 
guarantee ordering, maybe the fix is to have Mozilla not use the backing 
store - or if it's useful on a remote connection, make it an option.
The backing store shouldn't have anything to do with this because Mozilla
doesn't turn it on.*  In fact, turning it on in the application would cause very
different effects than what you are describing.

When you scroll a window, the area that is being scrolled into view is painted
even before the expose event that is generated is handled.  It might be that
some of the assumptions about what order events are generated is incorrect with
the Hummingbird server.  If that's the case it would be the first time I've
heard of it.

* I messed with using a backing store a couple of years ago but it doesn't work
with scrolled windows for a few reasons.
Hmm.. that's odd.  The unnamed Hummingbird developer (who I've invited, via 
their trouble ticket system, to join this discussion) seemed to indicate that 
Mozilla was explicitly using the backing store.  Here's what he wrote:

"We are doing exactly what Mozilla is asking us to do. The black is the
contents of the BackingStore that are being shown when the window moves.
 
You will see the exposed lines on the screen doubled when you aren't using
BackingStores. You will see them black when you are using BackingStores.
 
Feel free to change Mozilla (you might need to change GTK, too) to draw into
the BackingStore _before_ scrolling the window instead of _after_."

I'm not familiar with X as a developer, only a user, but I would be willing to 
do whatever debugging I can do to see what's really happening here.  Any 
suggestions on where I might start?  What I might be looking for in the X 
trace output on the PC, or in gdb on the Linux box running Mozilla?
> "We are doing exactly what Mozilla is asking us to do. The black is the
> contents of the BackingStore that are being shown when the window moves.

No, we don't use a backing store at all.

> You will see the exposed lines on the screen doubled when you aren't using
> BackingStores. You will see them black when you are using BackingStores.

I'm not sure what he means here.  I think he means that you will see crap when
you aren't using a backing store and black when you are.  However, since we're
not using a backing store and we are drawing when scrolling a window we should
see something, at least, but not black.

> Feel free to change Mozilla (you might need to change GTK, too) to draw into
> the BackingStore _before_ scrolling the window instead of _after_."

haha.  This is funny.  You can't draw into a BackingStore explicitly.  It's
automatic.  The only difference between having a backing store and not having a
backing store in the X world is that you don't get expose events anymore if the
backing store happens to be on.

> 
> I'm not familiar with X as a developer, only a user, but I would be willing to 
> do whatever debugging I can do to see what's really happening here.  Any 
> suggestions on where I might start?  What I might be looking for in the X 
> trace output on the PC, or in gdb on the Linux box running Mozilla?

You can try to get him involved.

I'm going to take a wild stab in the dark here and guess what's going on with
the Hummingbird X server.  Here's how we do things in Mozilla during a window
scroll:

1. Do the window scroll (this is actually a size change, window move and another
size change since X doesn't have a scrolling API.)
2. Draw immediately to the newly damaged area
3. Save the dimensions of the damaged area to avoid double-painting
4. Re-enter our mainloop

The window scroll will always generate an expose event (sometimes more than one
expose event.)  When we re-enter the mainloop and we get the expose event we
will generally drop it on the floor so that we don't repaint that area over again.

There's one of two things going on here:

1. After the scroll, before the draw is processed, the background of the window
is painted black.  I set window properties so that this shouldn't happen.  This
is all in the server.

2. When the draw event comes into the server the area that's being drawn in
might not be listed as "exposed" because the moves and resizes from the scroll
have yet to be processed or handled or something, so it's just drawn as black.

I'm guessing that we're actually seeing the first problem, but it's just a
guess.  If it were the second problem it would probably never finish drawing the
contents of the window.
>> "We are doing exactly what Mozilla is asking us to do. The black is the
>> contents of the BackingStore that are being shown when the window moves.
>
> No, we don't use a backing store at all.

You might set the backing-store hint to 'NotUseful', but the X Server may choose
to provide BackingStores anyway. (See the X Window System Protocol, Version 11,
under 'CreateWindow') In this particular case, Jay has set the configuration on
his X Server to "Ignore what the app wants, give everything a BackingStore".
Which is a perfectly valid thing to do.

>> Feel free to change Mozilla (you might need to change GTK, too) to draw into
>> the BackingStore _before_ scrolling the window instead of _after_."
>
> haha.  This is funny.  You can't draw into a BackingStore explicitly.

No, of course not. It was just a whole lot easier to write than "...draw into
the BackingStore by way of drawing into the parts of the Window that aren't yet
visible _before_..."

>  Here's how we do things in Mozilla during a window
> scroll:
>
> 1. Do the window scroll (this is actually a size change, window move and another
> size change since X doesn't have a scrolling API.)
> 2. Draw immediately to the newly damaged area
> [steps 3 and 4]

When you have a BackingStore, you should probably modify that to:
1. Start the scroll by doing the first size change
2. Draw immediately to the newly damaged area
2a. Finish the scroll with the window move and the second size change
[steps 3 and 4]

Which leaves us with the question of detecting forced-BackingStores. The
standard seems to be quiet on this issue.

Exceed specific (unless this is standard behaviour, and I just haven't found the
right part of the spec yet): GetWindowAttributes->backing_store will return what
Exceed is actually doing to your window, rather than what you asked Exceed to do
to your window.
>In this particular case, Jay has set the configuration on
>his X Server to "Ignore what the app wants, give everything a BackingStore".
>Which is a perfectly valid thing to do.

Unless I'm misunderstanding - and I may well be - it sounds like you're 
describing the "Default Backing Store: Always" behavior.  While I did 
initially have that set, I changed it to "When Mapped", which sounds like the 
kind of thing that should obey what the app wants..? The bug still occurs 
under When Mapped.

Thanks for coming here, by the way... it's always good to get the actual 
developers talking to each other.
>Unless I'm misunderstanding - and I may well be - it sounds like you're 
>describing the "Default Backing Store: Always" behavior.

I am talking about "Minimum Backing Store: When Mapped", actually.
Unfortunately, TechSupport didn't get a trace or a config file from you, so I
can't say for sure that this is your setting. (Default: Always isn't even an
option. When Mapped is the highest default setting we allow; only Maximum can be
set to Always).

>  While I did 
>initially have that set, I changed it to "When Mapped", which sounds like the 
>kind of thing that should obey what the app wants..?

"When Mapped" means "When not minimized" (not exactly, but close enough).

> The bug still occurs 
>under When Mapped.

Try changing your "Minimum Backing Store" setting to "None".

Mozilla 1.0.0 (the one that comes with Debian-woody) doesn't even set the
backing-store hint to "Not Useful", so you'd have to set "Default Backing Store"
to "None" also. Have newever versions of Mozilla changed this?

A quick grep of the 1.2b source tarball I downloaded on the 4th does not turn up
any hits for the constant "NotUseful", so I'm guessing the answer is "no".

>Thanks for coming here, by the way... it's always good to get the actual 
>developers talking to each other.

You're welcome.
> I am talking about "Minimum Backing Store: When Mapped", actually.
> Unfortunately, TechSupport didn't get a trace or a config file from you, so I
> can't say for sure that this is your setting. (Default: Always isn't even an
> option. When Mapped is the highest default setting we allow; only Maximum 
> can be set to Always).

OIC now.

The bug occurs under the following reasonable-looking settings: 
Maximum backing store: Always
Default backing store: When mapped
Minimum backing store: None

Changing "Default" to none makes the bug go away.

> "When Mapped" means "When not minimized" (not exactly, but close enough).

Ah, ok.  I assumed it meant something like "when the app asks for it." 

BTW - and I forgot to mention this earlier - according to the Hummingbird tech 
rep, when he tried this on a Windows 2000 box, it didn't occur; he could only 
duplicate it on XP.  That's what made me assume it was a Hummingbird bug in 
the first place.
>The bug occurs under the following reasonable-looking settings: 
> Maximum backing store: Always
> Default backing store: When mapped
> Minimum backing store: None
> 
> Changing "Default" to none makes the bug go away.

Right. As I mentioned previously, Mozilla does not say whether or not it 
wants BackingStores, so it gets the Default setting.

> BTW - and I forgot to mention this earlier - according to the Hummingbird tech 
> rep, when he tried this on a Windows 2000 box, it didn't occur; he could only 
> duplicate it on XP.  That's what made me assume it was a Hummingbird bug in 
> the first place.

Silly tech rep.

I assure you that the same thing happens on my Win2k box.

The same thing ought to happen on Linux/XFree86 when you set 
BackingStores as the default. (XFree86 has no equivilant of the Maximum 
setting, but there is a Default setting). Most people don't use it 
though, as it isn't nearly as useful on a local machine. This may be 
why the Mozilla developers haven't noticed until now.
> When you have a BackingStore, you should probably modify that to:
> 1. Start the scroll by doing the first size change
> 2. Draw immediately to the newly damaged area
> 2a. Finish the scroll with the window move and the second size change
> [steps 3 and 4]

This is exactly what Mozilla does, backing store or no backing store.  The thing
that Mozilla does that is not listed here is that it keeps track of the X serial
after that first size change and ignores the expose event that is generated as a
result of the window move.
[Previous Message]
> 1. Do the window scroll (this is actually a size change, window move and another
> size change since X doesn't have a scrolling API.)
> 2. Draw immediately to the newly damaged area
> [steps 3 and 4]

[Most recent message]
>> 1. Start the scroll by doing the first size change
>> 2. Draw immediately to the newly damaged area
>> 2a. Finish the scroll with the window move and the second size change
>> [steps 3 and 4]
>
>This is exactly what Mozilla does, backing store or no backing store.

Care to try again, this time without contradicting yourself?

If Mozilla did exactly this with no backing store, the window would never get
updated, because you tried to update the new region before (2a) scrolling it
onto a visible part of the screen.

With a BackingStore, the "newly damaged area" (and associated Expose event, not
that you pay attention to it) is created by the first resize, not by the move.
> Care to try again, this time without contradicting yourself?
> 

Here's the code I'm talking about:

http://lxr.mozilla.org/seamonkey/source/widget/src/gtksuperwin/gdksuperwin.c#331

1. It dose a move/resize.
2. Saves the value of NextRequest
3. Moves the window (this is the actual scroll)
4. Draws the newly exposed area
5. Adds any necessary anti-exposes to make sure that we don't paint twice.
6. Saves any required event translation values.
6. Does an XSync().
>Here's the code I'm talking about:
>
>http://lxr.mozilla.org/seamonkey/source/widget/src/gtksuperwin/gdksuperwin.c#331
>
>1. It dose a move/resize.
>2. Saves the value of NextRequest
>3. Moves the window (this is the actual scroll)
>4. Draws the newly exposed area
>5. Adds any necessary anti-exposes to make sure that we don't paint twice.
>6. Saves any required event translation values.
>7. Does an XSync().

In the case where you have a backing store, you want to move step 4 up to
between step 1 and step 2.

Looking at the link you gave me, you probably want to move lines 339-357 down to
line 421 or so (which is more like moving both steps 4 and 5, but I'm sure
that's obvious to you). You also need to do all your x and y calculations for
gtk_superwin_expose_area in the intervening lines differently.

Again, this is for the backing store codepath only. It obviously won't work if
you don't have a backing store.
That won't work because then you can't save the serial of the expose event
that's generated and you end up painting twice.  This is a huuuuge performance
hit when scrolling.
> That won't work because then you can't save the serial of the expose event
> that's generated and you end up painting twice.

Sure you can. In fact, you already do. It's called "first_resize_serial".

> This is a huuuuge performance hit when scrolling.

Actually, looking at this trace here, you already end up painting twice when you
have a backing store because you're grabbing the wrong serial number.

Ugh. Looking at this trace a little more closely, it appears as though
gdk_superwin_expose_area() doesn't do the painting, so my proposed solution is
incomplete. I suspect you also need to do something like a gdk_superwin_flush()
before you do the gdk_window_move().
Reporter, do you still see this problem with the latest nightly (or even 1.7.3)?
If not, this bug has probably been fixed and can be closed. Thanks.
Yep, still occurs on 1.7.3.
This is an automated message, with ID "auto-resolve01".

This bug has had no comments for a long time. Statistically, we have found that
bug reports that have not been confirmed by a second user after three months are
highly unlikely to be the source of a fix to the code.

While your input is very important to us, our resources are limited and so we
are asking for your help in focussing our efforts. If you can still reproduce
this problem in the latest version of the product (see below for how to obtain a
copy) or, for feature requests, if it's not present in the latest version and
you still believe we should implement it, please visit the URL of this bug
(given at the top of this mail) and add a comment to that effect, giving more
reproduction information if you have it.

If it is not a problem any longer, you need take no action. If this bug is not
changed in any way in the next two weeks, it will be automatically resolved.
Thank you for your help in this matter.

The latest beta releases can be obtained from:
Firefox:     http://www.mozilla.org/projects/firefox/
Thunderbird: http://www.mozilla.org/products/thunderbird/releases/1.5beta1.html
Seamonkey:   http://www.mozilla.org/projects/seamonkey/
Peter Harris, are you agreeding this is a bug?
Is Chris saying it isn't?

(I don't understand the technical issues.)
I can confirm that the reported behavior still happens on Firefox 1.5.0.1, Exceed release 10.0.0.15.  

As to Wayne's question: I can follow Peter and Chris's discussion, but have no background or standing to say who's right - if it's a bug (and on whose part), a disagreement on the standard, a vagueness in the standard that's interpreted differently, or what.  They're each pretty convincing till the other one posts.
  
(Mendel: He's right, and he's right.. how can they both be right?  Tevye: You are also right!)
(In reply to comment #21)
> Peter Harris, are you agreeding this is a bug?
> Is Chris saying it isn't?

Yes, I am confirming that this is a bug in Mozilla.

Well, "bug" is a strong word. "Behaviour causing poor performance" is more accurate, but harder to say. This might be why Chris doesn't think it's a bug.

> (I don't understand the technical issues.)

I'll do my best to explain.

Basically, Chris is saying "Nobody sane uses BackingStores, and by relying on this fact, we can boost performance a bit". What I'm saying, is that anybody sane on a slow network will be using BackingStores, and your hack to boost performance when backing stores are off is actually reducing performance 100%.

Muddying the waters is the fact that Xfree/X.org defaults to not providing BackingStores, and X configuration files are enough of a pain to change that (effectively) nobody on Linux ever uses BackingStores, so the "BackingStores On" case gets very little testing. As of X11R6.9, run the server with the flags "+bs -wm"; I don't see any way to turn the BackingStore options on in the configuration file.

After editing my gdm.conf file to add those flags, I can confirm that the problem still happens (at least the first time I scroll to a given location on the page) in Debian/1.5.dfsg+1.5.0.1-4 Firefox/1.5.0.1

If you extend your hack to also support BackingStores, not only do you get your performance back, but you also eliminate some visual glitches.

You know how when you scroll the main window on a slow computer, the newly scrolled area has a duplicate of the bottom of the window until the refresh finishes? When BackingStores are on, you get a black area instead. If you extended your hack to support BackingStores, you could have a seamless update of the screen.

The real problem comes with this part of the X11 spec: The spec says that the server must report weather it supports BackingStores or not. The spec does not provide any way to discern what the default is (what the "-wm" flag is doing on the X command line). Mozilla does not ask for BackingStores or No BackingStores (and even if it did, the spec says the server is free to ignore the application's BackingStore hint and provide, or not provide, BackingStores as it sees fit).

I'm not a Mozilla committer, so I'm not sure if I'm allowed to "Confirm bug (change status to NEW)". The OS should be changed to "Linux", since that's where Mozilla is running, even though the X11 server is on a Windows XP machine in the original reporter's case. (I just tried to change it, but Bugzilla won't let me)
let's move this on to confirmed so a developer can decide if it's valid or WONTFIX.
Status: UNCONFIRMED → NEW
Ever confirmed: true
OS: Windows XP → Linux
WONTFIX.  This was an issue a long time ago when people used backing stores but given that it hasn't had any comments in 2 years it's probably not an issue.  And I don't think that anyone is going to put in the effort to fix it on the Mozilla team.
Status: NEW → RESOLVED
Closed: 17 years ago
Resolution: --- → WONTFIX
Component: Layout: View Rendering → Layout: Web Painting
You need to log in before you can comment on or make changes to this bug.