Discussion:
DirectWrite bug in 3.0.2 pre-release
Greg
2011-12-09 15:40:41 UTC
Permalink
In my MFC application I have multiple CView classes, some of which a
Scintilla based, some are not. If I grab (click the mouse button in
the title bar of) another CView derived window (of any type) and shake
it around (vigorously) on top of a Sincilla-based view with
DirectWrite in use, the edges of the shaken view (which should not
change) get overwritten by the Scintilla view that is underneath. I am
running in Windows 7-64 with Aero enabled. If I disable Aero or
DirectWrite in Scintilla, this does not happen. (We have seen this
here on two machines with different video hardware).

This likely means that either the Scintilla updates are not being
clipped properly (as the CView classes all share the same DC, being
part of the main frame DC), or that the update bitblts are being
delayed until the next frame flyback, by which time the view I am
shaking about has moved.

This does not happen if I shake a modeless CDialog about over the
Scintilla view, but then this has a separate DC and in Aero there
would be no way the two DCs could interact.

This happens in both the 3.0.2 pre-release and in 3.0.1.
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Neil Hodgson
2011-12-10 00:11:47 UTC
Permalink
Post by Greg
This does not happen if I shake a modeless CDialog about over the
Scintilla view, but then this has a separate DC and in Aero there
would be no way the two DCs could interact.
OK, I am unfamiliar with CView but it sounds like these do not have
their own window. If you are sharing drawing between Direct2D and GDI
in a single WM_PAINT then I expect there has to be some layering
discipline like only drawing with GDI over fully rendered Direct2D.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2011-12-10 18:26:57 UTC
Permalink
I guess I am not being very clear.

All the windows in question are child windows of the MDI application.
Scite has a tabbed document interface, so you only see one document at
a time, but if imagine Scite as an MDI app with each document in its
own window, that is the arrangement. I have no control at all over
what is drawn... By moving a small window rapidly over the Scintilla
window I am generating invalid regions that need painting. The paint
operations in the Scintilla operation are overwriting the moving
window... but only with Aero on.

When Aero is on, all top-level windows are independent, being drawn
off-screen, then being blitted on to the screen. However, sibling
windows share the same underlying DC (with clipping handling not
drawing on each other). But, in this case, when the update happens,
the clip rectangle does not appear to protect the moving sibling
window. There can be two logical explanations: 1) the clip region is
wrong (unlikely, as it works when windows do not move rapidly), 2) the
clip region was right, but the windows have subsequently moved.

It does seem that the D2D only does screen updates once per frame...
Is it possible that the Scintilla code is not waiting for the
underlying update to occur before returning in the WM_PAINT? This
would not cause a problem unless the clip regions were changing fast
enough that by the time the screen update happened, they had already
changed.
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Neil Hodgson
2011-12-10 22:26:11 UTC
Permalink
Post by Greg
When Aero is on, all top-level windows are independent, being drawn
off-screen, then being blitted on to the screen. However, sibling
windows share the same underlying DC (with clipping handling not
drawing on each other). But, in this case, when the update happens,
the clip rectangle does not appear to protect the moving sibling
window. There can be two logical explanations: 1) the clip region is
wrong (unlikely, as it works when windows do not move rapidly), 2) the
clip region was right, but the windows have subsequently moved.
Does moving a window only overdraw the edge or does it overdraw the
whole window? If it is the whole window then it is unlikely to be a
lagging clip region.
Post by Greg
It does seem that the D2D only does screen updates once per frame...
Is it possible that the Scintilla code is not waiting for the
underlying update to occur before returning in the WM_PAINT?
Scintilla calls EndDraw on the render target before returning from
WM_PAINT. EndDraw is supposed to be the end of its responsibilities.
The render target could be released but that is something that is
avoided in Direct2D examples and may mean that no drawing is done.

Its possible that the freeing of the update region in the call to
BeginPaint is leading to Direct2D not picking up the update region -
some MS Direct2D examples do not call BeginPaint / EndPaint. But some
examples do call BeginPaint. You could try disabling BeginPaint and
EndPaint.

Drawing could be forced to the screen with DwmFlush
http://msdn.microsoft.com/en-us/library/windows/desktop/dd389405(v=VS.85).aspx

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2011-12-11 16:53:15 UTC
Permalink
   Does moving a window only overdraw the edge or does it overdraw the> whole window?It overdraws from the edge (but not only the frame).
   Its possible that the freeing of the update region in the call to> BeginPaint is leading to Direct2D not picking up the update region -> some MS Direct2D examples do not call BeginPaint / EndPaint. But some> examples do call BeginPaint. You could try disabling BeginPaint and> EndPaint.Will have to wait for weekdays as I don't have Aero-capable hardware at home. I somehow doubt that this would make any difference... As I understand it, BeginPaint picks up the invalid region, creates a suitable clip region and cleans out the invalid region... What does this function for DirectWrite?
   Drawing could be forced to the screen with DwmFlush...This seems more likely. As this only occurs with Aero ON, i.e. when we are likely rendering to an off-screen buffer that is being blitted to the screen, we need an explanation for what is happening that explains what is different about rendering to an off-screen bitmap. In my situation, the Aero off-screen bitmap gets blitted to the screen as the application bitmap (if I understand what is going on), and our scintilla window is part of this. In non-aero mode, the bitmap is the actual screen.
When a window is moved over the scintilla window, this causes a bitmap
copy of the moving window, plus invalidation of the uncovered areas of
the Scintilla window. In non-aero mode, this is always OK, which
suggests that something must be serialising access to the screen
bitmap between the D2D rendering and the bitmap copies...
In Aero mode, I suspect that the actual render to the off-screen
bitmap is being delayed and that another window move get in ahead of
it. If I "shake" the window from side to side, this move may be back
in the opposite direction to the last one, resulting in the moving
window now getting rendered over by the D2D render, whenever it
happens.
I'll see if I can find the time to try out the flush call... where
would you put it?
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Neil Hodgson
2011-12-11 22:54:25 UTC
Permalink
As I understand it, BeginPaint picks up the invalid region, creates a suitable
clip region and cleans out the invalid region... What does this function for
DirectWrite?
ID2D1HwndRenderTarget::BeginDraw could be doing this but I don't really know.
I'll see if I can find the time to try out the flush call... where
would you put it?
For testing, at the end of painting, perhaps just after ::EndPaint.
Since it doesn't appear needed by SciTE, for example, there'd have to
be a control over whether it was called if in a release version.

It may be an idea to ask about this in a Direct2D forum. I don't
know much about the DirectX world or Aero composition.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2011-12-12 12:25:32 UTC
Permalink
Adding the flush call made no difference at all.

Removing BeginPaint and EndPaint causes the entire scintilla window
including the H Scrollbar to be black, but the overwriting still
happens.
Moving the BeginPaint to just before the EndPaint leaves a black
window, but the H Scrollbar is back.

Debugging is tricky as putting in a break causes focus changes, which
repaints windows, so I added a 1 second delay in various places in
WndPaint, then dragged the window quickly diagonally up to the left.

1) Putting a delay at the start, before anything happens leaves
everything OK.
2) Putting a delay at the end, after the EndPaint causes a horrible
mess.

The critical position for the delay is putting it before pRenderTarget-
EndDraw() is OK, after causes the problem.
The damage happens in the bit blit that updates the moving window. The
first delay pause (when the dragged window typically moves 1 pixel
left and up) is either OK or 1 pixel round the frame is damaged.
However, the mouse has moved further during the delay, queuing up
another window move which is quite a few pixels in x and y and which
makes it clear what is happening. There are two processes: 1) a bit
blit of the moving window, 2) update of the invalid regions of the
Scintilla window revealed by the move. The problem is that these are
happening in the wrong order. The Scintilla window gets updated
(damaging the bitmap area where the moving window is going), then the
copy happens, corrupting the image of the moving window.

This seems to suggest that the bitmap copy for the move with Aero
enabled is happening on a different thread, possibly waiting for the
once per frame event. If we put in a 17 millisecond delay before the
EndDraw(), then all is well. Anything less and there is mess after
some moves. I have no idea how to fix this.
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2011-12-12 15:13:27 UTC
Permalink
I have reported this to Microsoft as a possible bug - maybe you cannot
mix GDI(+) and D2D:

https://connect.microsoft.com/VisualStudio/feedback/details/713420/direct2d-aero-interaction-causes-image-damage

This also has a bitmap of the screen after the damage is done - the
frame on the window is intact as it got repainted, but I'm sure you
can image what it looked like before this happened. My screen update
rate is 60 Hz (in case you are wandering where the 17 ms comes from).
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Neil Hodgson
2011-12-12 22:20:17 UTC
Permalink
Post by Greg
I have reported this to Microsoft as a possible bug - maybe you cannot
GDI and Direct2D are certainly supposed to be usable together.
There is substantial Microsoft documentation on this:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd756743(v=VS.85).aspx

While the Scintilla Direct2D code was being developed, there was a
mix of Direct2D+DirectWrite and GDI calls and the GDI calls were
converted item by item. The biggest problem with that was performance
as there were many switches between the two APIs. There had to be
EndDraw or Flush calls at some switchover points.

This was all in the context of drawing to a simple HWND/HDC and
also to some pixmaps so your scenario is more complex.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Ferdinand Prantl
2011-12-13 08:33:38 UTC
Permalink
Seeing those 17ms reminded me about synchronizing the frame rendering
frequency with the vsync. By forcing the rendering to occur just once
per page refresh you got rid of the artefacts. "Wait for vsync" is
used to get rid of image "tearing" in (usually full-screen) games - if
you have decent hardware and high refresh rate (otherwise
triple-buffering does better). However, wait for vsymc is turned on by
default in Windows Vista windowing mode. It was not in Windows XP and
I think Windows 7 with Aero would be like Vista. Power saving could
turn off the vsync interrupt but I doubt your CPU felt like saving
power when you were vigorously shaking your application :-) While I
find the resemblance intriguing I can't see a direct vsync affinity in
the GDI/D2D window rendering code.

--- Ferda
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2011-12-13 11:03:55 UTC
Permalink
A quick scan of the Microsoft doc you pointed me at suggests that the
D2D rendering is to a separate (from GDI) surface that is then copied
to the GDI surface.
With Aero on, the GDI surface is an off-screen bitmap. This off-screen
bitmap is then copied to the screen during the frame blanking period.
With Aero off, the GDI surface is the screen... it is not clear if we
wait for blanking or not.
To get the problem, the moving window and the background window must
be sibling windows... if they descend from different top level
windows, with Aero on they will have different off-screen bitmaps and
will not interact. You do not see this in Scite because you use tabbed
sibling windows for the documents. Any dialogs you create are most
likely top level windows, so you will not see this effect.
I fear that I must time out on this problem as not using D2D is a
workaround, at least for now. My theory on what is happening is that
when Aero is on, the copy to the GDI surface from the D2D rendering
surface does not wait for frame blanking (which it would do with Aero
off). The window move operation which caused the invalidate is either
being deferred to the frame flyback, or is happening in parallel (I
doubt this), either way, this gets the GDI surface updated with text
before (or during) the window move, resulting in the problem.
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Ferdinand Prantl
2011-12-13 19:38:16 UTC
Permalink
If you have not grown tired yet ;-) you can try to play with vsync
on/off in the D2D rendering target creation: setting presentOptions to
D2D1_PRESENT_OPTIONS_NONE or to D2D1_PRESENT_OPTIONS_IMMEDIATELY and
checking out what it changes.

http://msdn.microsoft.com/en-us/library/windows/desktop/dd368122(v=vs.85).aspx
http://www.gamedev.net/topic/565428-why-is-direct2d-so-slow/ (end of the thread)

--- Ferda
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2011-12-14 11:58:59 UTC
Permalink
Post by Ferdinand Prantl
If you have not grown tired yet ;-) you can try to play with vsync
on/off in the D2D rendering target creation: setting presentOptions to
D2D1_PRESENT_OPTIONS_NONE or to D2D1_PRESENT_OPTIONS_IMMEDIATELY and
checking out what it changes.
Ferda: It seems that the surface we use is created by
CreateCompatibleRenderTarget(), which doesn't have the option of
changing the presentation. If you can suggest what changes to make to
the Scintilla code to try these ideas out I can do it, but I have a
lot of other things that I should be doing and I am not a D2D expert.
In the long term, getting this to work would be good, but in the short
term I can just not use D2D.
I do think that this is a serious bug; just because Scite doesn't hit
it doesn't mean it won't occur in other situations - basically any MDI
app with a Scintilla window will have this problem in Aero mode.
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Ferdinand Prantl
2011-12-15 08:19:59 UTC
Permalink
I'm afraid I'm no D2D expert either. Neither have I an MFC application to
test. What I thought about was replacing the call:
D2D1::HwndRenderTargetProperties(hw, size)
at CreateHwndRenderTarget(...) in ScintillaWin::EnsureRenderTarget() with:
D2D1::HwndRenderTargetProperties(hw, size, D2D1_PRESENT_OPTIONS_NONE)
and then with:
D2D1::HwndRenderTargetProperties(hw, size,
D2D1_PRESENT_OPTIONS_IMMEDIATELY)
and testing how it behaves. The former should be default but vsync settings
depend on graphic settings and graphic hardware. I used the latter to make
a D2D demo running more fluently on my hardware. It is common that games
have a flag to control waiting for vsymc to tune the behavior on various
hardware. But all this stuff that it *could *be a vsync issue is my
speculation. If it helped, the solution would be cheap; if not I'm afraid
that I don't know.

You found that a cunning sleep in the drawing routine helped. Actually, the
EndDraw() should "sleep" if vsync was forced on and the rendering is "too
fast" for the vertical refresh. The waiting could be done also by an
explicit call to WaitForVerticalBlank() from DirectDraw but I saw some code
using other means to compute the right timespan to wait and waiting by
traditional timer because that method spins and thus increases CPU load.

USE_D2D is 1 by default when compiled on VS2010 maybe someone else will be
affected too.

--- Ferda
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Neil Hodgson
2011-12-15 08:25:39 UTC
Permalink
Post by Ferdinand Prantl
USE_D2D is 1 by default when compiled on VS2010 maybe someone else will be
affected too.
That just enables the Direct2D code. The application still chooses
GDI or Direct2D with SCI_SETTECHNOLOGY.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2011-12-15 10:52:12 UTC
Permalink
Ferda:
I tried what you suggested, but it made no difference to the problem.
D2D1_PRESENT_OPTIONS_NONE is the default, so was what is currently
set. Setting D2D1_PRESENT_OPTIONS_IMMEDIATELY yielded identical
results as far as I could see.

In any case, with Aero enabled, there may be no difference as the
target bitmap is an off-screen bitmap (so no Vertical Blank), which I
guess is copied (if dirty) to the screen(s) in the vertical Blank
interrupt for each screen. At this point, I should mention that I am
using two monitors, so the concept of WaitForVerticalBlank() may be
moot as there is the question of which monitor we are talking about.
And before you ask, yes, I have tried this with only one monitor,
there is no difference.

You do not need to run MFC to see the effect. As far as I can deduce,
it will happen in any situation where there is an instance of
Scintilla in a window and there is a sibling or child window that can
move over it and Aero is enabled. Aero makes off-screen bitmaps for
all top-level windows, but all windows within each top-level window
share the same off-screen bitmap and then rely on clipping to prevent
trampling on each other. I'm sure you could see this effect in Scite
if you created another Child window at the same level as the current
Scintilla windows, then dragged it over the Scintilla window.
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2011-12-16 11:06:36 UTC
Permalink
https://connect.microsoft.com/VisualStudio/feedback/details/713420/direct2d-aero-interaction-causes-image-damage#tabs

Now contains a short VS2005 project that builds an app to illustrate
the problem. You guys should be able to download it from there... if
not I can email it anyone who is interested in looking at this problem.
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Neil Hodgson
2011-12-18 03:36:50 UTC
Permalink
Managed to reproduce the problem but looks like 2 problems now. The
first is that calling BeginPaint/EndPaint and GetUpdateRgn did appear
to be causing problems so here is a patch that only uses these with
GDI drawing and avoids them for Direct2D drawing. This clears up a lot
of the image overwrite except when the horizontal scroll bar is turned
off as it is for line wrapping.

When the horizontal scroll bar is turned off, the vertical scroll
bar is often overdrawn. Sometimes it has to be clicked on to go into
this mode. A small demonstration program which illustrates this is at
http://www.scintilla.org/kruptd2d.zip . It has been simplified to not
require Scintilla.
Loading Image...
Similar drawing problems to Greg's can be shown by uncommenting the
calls to BeginPaint/EndPaint in the demonstration app.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2011-12-19 11:15:17 UTC
Permalink
I have applied your patches and the problem is not as bad, but is
still present for me. I now have an additional problem:

My text display view contains a window above the Scintilla window that
is used for buttons and status messages. When I first display the view
holding Scintilla, this additional area is now blank. It appears if I
resize the window (which will force a draw). My theory is that
Scintilla gets to draw first and is marking the entire window area as
valid when it should just be the scintilla rectangle.

If I shake the moving widow over the scintilla area, it seems less
prone to be damaged, and sometimes survives a (short) while, but it
does get damaged.

The test Scintilla application I posted on the MS system is more
resilient; maybe to do with the lack of an extra window area, which
may cause co-ordinate offsets. Anyhow, this also does show up damage.
The easiest way to show it (if you can compile it) is to open up two
windows (you can leave them empty of text), then minimise one and move
it about over the other. There seems to be no fixed pattern to the
corruption, but I can always make it happen.

I have expanded the MS report I made to include your simplified
example (please accept my apologies in advance if you object to
this...) as it seems to show at the very least that there is a
documentation problem, and quite possibly a real problem with Aero and
D2D. Although the best I have ever get from them is to acknowledge the
problem and say they will fix it in a future release, if you don't
tell them they do nothing.
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Neil Hodgson
2011-12-19 22:50:31 UTC
Permalink
Post by Greg
My text display view contains a window above the Scintilla window that
is used for buttons and status messages. When I first display the view
holding Scintilla, this additional area is now blank. It appears if I
resize the window (which will force a draw).
I have seen some similar effects with one window being treated
specially. Even with the kruptd2d simplified example, the background
window has its top right corner drawn wrong initially. Its only after
it has received focus that it draws correctly.
Post by Greg
The test Scintilla application I posted on the MS system is more
resilient; maybe to do with the lack of an extra window area, which
may cause co-ordinate offsets. Anyhow, this also does show up damage.
The easiest way to show it (if you can compile it) is to open up two
windows (you can leave them empty of text), then minimise one and move
it about over the other. There seems to be no fixed pattern to the
corruption, but I can always make it happen.
Corruption mostly occurs in the non-client area. While this could
be just because the edges are more exposed to damage and the edges are
in the non-client area, the correlation appears much stronger than
this to me. The non-client area is likely being drawn by GDI rather
than Direct2D so there could be a sequencing issue there. Changing the
non-client area from its original state (such as turning off a scroll
bar) also sounds like a good candidate for a cause as Direct2D could
be storing information about the window when the render target is
created and this could go stale.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2011-12-21 10:50:05 UTC
Permalink
Neil:
As ever, thanks for the work you do... I don't feel I can contribute
much more to this at the moment. I'll let you know if MS make any
response.
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Neil Hodgson
2011-12-22 00:12:59 UTC
Permalink
The patch that avoids BeginPaint/EndPaint and GetUpdateRgn with
Direct2D has now been committed.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Neil Hodgson
2011-12-29 10:34:56 UTC
Permalink
  The patch that avoids BeginPaint/EndPaint and GetUpdateRgn with
Direct2D has now been committed.
While this appeared better in some tests, it has caused problems
drawing the tab bar and output pane in SciTE so will have to be
reverted.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Neil Hodgson
2011-12-29 22:04:47 UTC
Permalink
  While this appeared better in some tests, it has caused problems
drawing the tab bar and output pane in SciTE so will have to be
reverted.
Reverted in Hg.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2012-02-01 10:05:39 UTC
Permalink
I have had a response from Pat Brenner at Microsoft:

"Thanks for the report. We have investigated the issue here and we
believe that the problem is caused by “concurrent” D2D calls. If you
take a look at the MFC D2D support, you will find that when we
implemented it in CWnd, each D2D rendering was wrapped by
LockRenderTarget/UnlockRenderTarget calls (see CWnd::DoD2DPaint,
CWnd::LockRenderTarget and CWnd::UnlockRenderTarget() methods).

You have commented, "If you put a Delay(17) (17 ms is my refresh rate)
before the EndDraw(), the problem goes away (at the cost of wasted
time and CPU cycles)." We believe this indicates that the problem is
that you need to synchronize your D2D calls. We suggest that you use
LockRenderTarget/UnlockRenderTarget (or something similar) to do so."

I am very happy to implement this and test it... but do you have
suggestions for where I should apply the locks?
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2012-02-01 11:09:43 UTC
Permalink
I can find the CWnd:DoD2DPaint() but in the VS2010 MFC that I have,
there are no LockRenderTarget() or UnlockRenderTarget() routines to
look at, so I suspect that this is in the next MFC release. However, I
think what they mean is that we must use a CriticalSection object to
wrap rendering. This in turn means that we need to create and kill one
off in suitable places when D2D is in use. If Neil can suggest where I
might do this I can have a shot at adding this.

One might question how we can get into such a mess when there is only
one thread in Scintilla, unless they mean that the D2D rendering is
runing in a separate thread... but if it is, how will putting a
critical section in our code stop their thread from running out of
order? If they are just deferring updates to frame flyback I still
don't see how a critical section would help.
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Neil Hodgson
2012-02-01 23:13:35 UTC
Permalink
Post by Greg
"Thanks for the report. We have investigated the issue here and we
believe that the problem is caused by “concurrent” D2D calls.
The quotes around 'concurrent' here may indicate that this is not
threading concurrency but instead refers to reentrance or simply
drawing on a single surface from two referring objects (such as two
render targets).
Post by Greg
implemented it in CWnd, each D2D rendering was wrapped by
LockRenderTarget/UnlockRenderTarget calls (see CWnd::DoD2DPaint,
CWnd::LockRenderTarget and CWnd::UnlockRenderTarget() methods).
'Lock' may be referring to threading mutexes but it could also be
referring to memory or graphics state management. A surface allocated
on the graphics card may need to be pinned while being accessed from
the CPU and there may also have to be cache flushing when switching to
drawing from another window.

Searching for 'LockRenderTarget' and similar terms doesn't produce
any exact matches but does show some Direct3D matches. It may be
necessary to access Direct3D resources behind the Direct2D render
target to call a Lock method. Methods like IDirect3DSurface9::LockRect
could be what is meant here although this is well beyond my
experience.
Post by Greg
I am very happy to implement this and test it... but do you have
suggestions for where I should apply the locks?
Without seeing the MFC code I can only guess at what is being suggested.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2012-02-02 10:20:42 UTC
Permalink
I posted a reponse to MS yesterday asking for clarification... I'll
let you know if they respond.
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2012-03-09 13:13:55 UTC
Permalink
MS have just closed the report and ignored my request for an
explanation of LockRenderTarget() - I suspect it is in the VS-Next
rather than in the current version.

Just to say that this is still an issue in 3.0.4 (i.e. the various
changes to the D2D rendering have made no difference).

Greg
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To post to this group, send email to scintilla-***@googlegroups.com.
To unsubscribe from this group, send email to scintilla-interest+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
Greg
2013-05-23 11:53:17 UTC
Permalink
As you have made a change to D2D support in 3.3.2 I retested the problem
with overwriting of a window moving over a Scintilla window and can report
that it still fails.

What is odd (to me) is that the corruption of the moving window (which is
an MFC CView derived item moving over the CView derived window that holds
the Scintilla-based control) happens on the bottom edge of the moving
window when it moved upwards... Now it is a bit hard to understand how this
can happen if the corruption happens when a Scintilla update is deferred to
the flyback time as one presumes that the moving window has moved up the
screen... so how can it get painted over... it feels like it is something
to do with view clipping (the two MFC CViews ultimately share the same
bitmap/DC) being messed up by deferred updates. The moving window is just
being bit-blitted as it is dragged... somehow the clipping out of the
moving window from the Scintilla window is getting out of sync... or
getting interleaved with the bit-blit of the moving window... perhaps this
is what the LockRenderTarget stuff is meant to prevent?
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Neil Hodgson
2013-05-24 00:27:00 UTC
Permalink
What is odd (to me) is that the corruption of the moving window (which is an MFC CView derived item moving over the CView derived window that holds the Scintilla-based control) happens on the bottom edge of the moving window when it moved upwards... Now it is a bit hard to understand how this can happen if the corruption happens when a Scintilla update is deferred to the flyback time as one presumes that the moving window has moved up the screen... so how can it get painted over... it feels like it is something to do with view clipping (the two MFC CViews ultimately share the same bitmap/DC)
I thought CViews are CWnds (and so HWNDs) and thus have separate DCs.

If you are using Direct2D for drawing content surrounding the Scintilla window then its possible your view creates a surface over a rectangle that includes Scintilla. It saves the Scintilla pixels, does some drawing, and then blitting that whole surface onto the screen is scheduled. Scintilla's drawing is also scheduled but they overlap and the final composition occurs in an unfortunate sequence. Its also possible that the surface areas are larger than asked for, perhaps scaled up to an 8x8 pixel grid or similar, leading to unexpected overlap.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Greg
2013-05-24 09:31:48 UTC
Permalink
Post by Neil Hodgson
Post by Neil Hodgson
I thought CViews are CWnds (and so HWNDs) and thus have separate DCs.
An HWnd identifies a window. A top level window (in Aero at least) has an
off-screen bitmap that is shared by all the children of the window... I
suspect that when a child gets a DC it is given a shifted and clipped (or
not clipped - ClipSiblings flags etc) version of the parent DC. In the case
of an MFC application, the main application window frame is a top level
window, all the CView (representing documents) as children of it and thus
share the bitmap.
Post by Neil Hodgson
If you are using Direct2D for drawing content surrounding the Scintilla
window then its possible your view creates a surface over a rectangle that
includes Scintilla. It saves the Scintilla pixels, does some drawing, and
then blitting that whole surface onto the screen is scheduled. Scintilla's
drawing is also scheduled but they overlap and the final composition occurs
in an unfortunate sequence. Its also possible that the surface areas are
larger than asked for, perhaps scaled up to an 8x8 pixel grid or similar,
leading to unexpected overlap.
The problem happens regardless of the technology used to draw the moving
window; it happens if the moving window is minimised so it is just the
title bar. I am pretty sure it is related to the sequence of bit blits that
update the image - but I have no idea how to control this.

MS say that they use LockRenderTarget to prevent this problem - but I am
struggling to find this code. I will keep looking.
Post by Neil Hodgson
Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Greg
2013-05-24 09:40:28 UTC
Permalink
*Just in case anyone else thinks of this, I have tried using:
D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE
in place of **D2D1_RENDER_TARGET_USAGE_NONE as the rest of my application
is probably using GDI, but it makes no difference.
*
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Neil Hodgson
2013-05-24 12:42:05 UTC
Permalink
Post by Greg
MS say that they use LockRenderTarget to prevent this problem - but I am
struggling to find this code. I will keep looking.
Do you have the version of MFC from Visual Studio 2012? I couldn't find
the documentation for this version online.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Greg
2013-05-28 12:20:39 UTC
Permalink
I do have VS2012 and have done a bit more digging. It looks like to make
this work in an MFC app (or in any app that is using GDI) there is more
syncing work to be done. In MFC, it seems that you must call
CWinApp::EnableD2DSupport() and also call CWnd::EnableD2DSupport() for the
window itself. Then they add:

afx_msg LRESULT OnDraw2D(WPARAM wParam, LPARAM lParam); // in the header


BEGIN_MESSAGE_MAP(CSciCtrl, CWnd)
ON_REGISTERED_MESSAGE(AFX_WM_DRAW2D, &CSciCtrl::OnDraw2D)
END_MESSAGE_MAP()

afx_msg LRESULT CSciCtrl::OnDraw2D(WPARAM wParam, LPARAM lParam)
{
CHwndRenderTarget* pRenderTarget = (CHwndRenderTarget*)lParam;
ASSERT_VALID(pRenderTarget);
...your code in here to render...
return TRUE;
}

I guess that this is tried before the CWnd::OnPaint()...

This seems to be saying that to make this work, MFC must handle the render
target so that it can arbitrate between the various items that are
attempting to update it. Unless you can suggest a simple method to link
this into the underlying Scintilla D2D rendering I think I will just have
to live with the GDI rendering (at least until I have a lot more time to
look at this).

The code suggested here is available on the Web, but there seems very
little help for people trying to do this.
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Greg
2013-05-28 13:45:34 UTC
Permalink
I realise that to make any sense of the previous post, I need to explain
that a CSciCtrl is a CWnd descendent that wraps up a SciDirect pointer. The
ScriCtrl::Create(...) holds:

BOOL CSciCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
UINT nID,
DWORD dwExStyle, LPVOID lpParam)
{
if ((m_hModScintilla == NULL) && // if first user...
!InitScintilla()) // ...load the
Scintilla DLL
return FALSE;
BOOL bOK = CreateEx(dwExStyle, _T("scintilla"), NULL, dwStyle, rect,
pParentWnd, nID, lpParam);
if (bOK) // if all was OK we can now send messages to the
window
{
ASSERT(::IsWindow(m_hWnd)); // moan if we
failed
m_pSciDirect = (SciFnDirect)SendMessage(SCI_GETDIRECTFUNCTION); //
get address to use
m_pSciData = SendMessage(SCI_GETDIRECTPOINTER); // get our
instance data pointer
#ifdef SCI_USED2D
EnableD2DSupport();
if (IsD2DSupportEnabled())
SetTechnology(SC_TECHNOLOGY_DIRECTWRITE); // attempt to
set direct write
if (GetTechnology() == SC_TECHNOLOGY_DIRECTWRITE) // if using
DirectWrite
{
SetBufferedDraw(false); // probably
right
SetTwoPhaseDraw(false);
}
#endif

SetFontQuality(SC_EFF_QUALITY_LCD_OPTIMIZED); // and best
quality font
}
return bOK;
}

The rest of the class is there to turn the scintilla messages into member
functions and convenience functions. To blend the MFC code with the
scintilla control we need to get scintilla to use the CHwndRenderTarget we
get from the AFX_WM_DRAW2D registered message... then there is a chance
that the GDI and D2D painting will be proprely sequenced.
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Neil Hodgson
2013-05-28 13:58:31 UTC
Permalink
The rest of the class is there to turn the scintilla messages into member functions and convenience functions. To blend the MFC code with the scintilla control we need to get scintilla to use the CHwndRenderTarget we get from the AFX_WM_DRAW2D registered message... then there is a chance that the GDI and D2D painting will be proprely sequenced.
As a proof of concept, you can just munge the Scintilla code heavily. Remove the current window handling in ScintillaWin and splice it into an MFC shell. It should be possible to only implement a few methods to get drawing working.

Then try to refactor so that minimal changes are needed to ScintillaWin - maybe some way to pass the render target into WndPaint.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
Greg Smith
2014-04-22 19:26:27 UTC
Permalink
I have tried again with the latest Scintilla (just in case the various
recent D2D fixes made any difference). I'm afraid that the problem is still
present.

I've had a look at ScintillaWin.cxx... I don't really see any simple way
through to calling the existing code. The CHwndRenderTarget* you get from
the lParam of the OnDraw2D call does contain pointers to both a
ID2D1RenderTarget and a ID2D1HwndRenderTarget, so it is likely doing a lot
of the same things as your Surface is doing. However, it also contains
other state information: list of CD2DResource objects and a default
CD2DTextFormat object.

To reiterate the problem: in WIndows 7 with Aero on, if I move a window
around on top of a scintilla window, what happens is that the moving
windows is corrupted by Scintilla text. The Scintilla window itself is
never corrupted. If I move the top window to the right, it is the left edge
of the window that is corrupted with Scintilla output. The moving window
and Scintilla are sharing the same off-screen bitmap, and then this gets
copied to the screen bitmap (with Aero on). With Aero off, the problem does
not occur.

This suggests the following to me for the case when I drag the moving
(non-scintilla) window to the right:

1) The window is dragged to the right. This books two Windows operations in
the off-screen bitmap: Bit-blit the moving rectangle right and repaint the
uncovered area.
2) The bit-blit of the moving window to the right gets handed off to the
GDI and the Scintilla update of the uncovered area is requested via D2D
3) A screen refresh comes up (requiring the off-screen bitmap to be copied
to the screen)
4) The bit-blit of the moving window gets suspended because of the screen
update, but the Scintilla update goes ahead
5) The off-screen bit-blit now happens, and copies data that has already
been written by Scintilla

This sequence exactly explains what I see on the screen. Of course, this
may well not be what actually happens, but to explain what I see on screen,
the off-screen bit-blit and the Scintilla D2D paint order must be reversed.
I have never seen a corruption (when moving right) that has other than a
clean vertical edge, so it is not likely to be simultaneous execution of
the D2D update and the bit-blit as I would expect to occasionally see an
incomplete text update, and it is an all or nothing effect.

Any thoughts?
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest.
For more options, visit https://groups.google.com/d/optout.
Neil Hodgson
2014-04-24 02:04:33 UTC
Permalink
To reiterate the problem: in WIndows 7 with Aero on, if I move a window around on top of a scintilla window, what happens is that the moving windows is corrupted by Scintilla text. The Scintilla window itself is never corrupted. If I move the top window to the right, it is the left edge of the window that is corrupted with Scintilla output. The moving window and Scintilla are sharing the same off-screen bitmap, and then this gets copied to the screen bitmap (with Aero on). With Aero off, the problem does not occur.
Its possible that having a child window displayed over a Direct2D-drawn window just isn't directly supported by Direct2D on Windows 7 with Aero. There have been problems in the past with combining DirectX with other drawing techniques. MFC could be working around this by performing clipping and draw flushing for its own windows so they can be combined like this but that doesn't extend to non-MFC windows.

It should be possible to use Direct2D drawing with some additional redirection to prevent clashes with other Windows if the clashes are due to sharing the underlying window bitmap. One approach would be to respond to the paint request by creating an offscreen Direct2D bitmap, asking Scintilla to draw into that, then using GDI to copy the bitmap contents onto the paint HDC. Pretty sure this will isolate the Direct2D drawing and so work but will cost a little memory and performance.

Another technique may be to use GDI interop and using Direct2D to draw into the paint HDC. Less likely to be isolated but could be faster.
http://msdn.microsoft.com/en-us/library/windows/desktop/dd370971(v=vs.85).aspx

One of these could then be packaged into another technology choice (SC_TECHNOLOGY_DW_INDIRECT) that could be used by applications that want to use child windows along with the benefits of Direct2D/DirectWrite drawing.

These seem to be reasonably simple to try but its not really something I'm interested in working on myself since the current Direct2D code works fine for SciTE.

There is a debug tool that may be worthwhile trying to see if it says anything interesting with the current code:
http://msdn.microsoft.com/en-us/library/windows/desktop/ee794278(v=vs.85).aspx
Even without the debug layer, there are two DXGI warnings when shutting down SciTE but that is because the factory objects aren't released at shutdown.

Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest.
For more options, visit https://groups.google.com/d/optout.
Loading...