showMessageBoxAsync broken on windows8

Any test-program will which uses AltertWindows or Tooltips has the problem (running without debugger the release build - VS2008 - Windows SDK 7.1 - W8 64bit - 32bit app)
So you could just open a AlertWindow:

[quote]
void initialise (const String& commandLine)
{
// Add your application’s initialisation code here…
AlertWindow::showMessageBox(AlertWindow::NoIcon,“Title”,“Message”);
JUCEApplication::quit();
}
[/quote].

[attachment=0]alert.png[/attachment]

If you have any assumption which values are wrong, i could write them in a log file…

But that’s just not what I’m seeing, even in Windows 8. I really can’t think what might be different in your setup!

Jules,

It clearly happens for more than one person, so there must be something going on…
Wouldn’t it be easier to just do 10 minutes of debugging on someone else’s machine with teamviewer? ( http://www.teamviewer.com )
If the program-to-be-debugged is super simple (i.e. the simpelest we can get to reproduce it) it shouldn’t take more than that for you to figure out what is going wrong.

In any case it would be quicker than discussing this ad infinitum :slight_smile:

  • bram

Here is something what i get, you know the code better, please tell mw where i can add log statements!!

static FileLogger logger(File("C:\\Users\\Christian\\Documents\\cpp_projects\\testlogs\\alert.txt"),IsDebuggerPresent() ? "Start log with Debugging.." : "Start log.."  );

IN void AlertWindow::updateLayout (const bool onlyIncreaseSize)

............... snip
...............

    const int textLayoutH = (int) textLayout.getHeight();
    const int textBottom = 16 + titleH + textLayoutH;
	
	logger.logMessage("textLayout.getHeight()"+String(textLayout.getHeight()));
	logger.logMessage("textLayout.getWidth()"+String(textLayout.getWidth()));

[quote]**********************************************************
Start log with Debugging…
Log started: 22 Jan 2013 12:29:54pm

textLayout.getHeight()50.890316
textLayout.getWidth()48.0132599
textLayout.getHeight()50.890316
textLayout.getWidth()48.0132599
textLayout.getHeight()50.890316
textLayout.getWidth()48.0132599


Start log…
Log started: 22 Jan 2013 12:30:15pm

textLayout.getHeight()3.4073925 <--------------!!!
textLayout.getWidth()48.0132599
textLayout.getHeight()3.4073925
textLayout.getWidth()48.0132599
textLayout.getHeight()3.4073925
textLayout.getWidth()48.0132599[/quote]

added log statements int TextLayout::createLayoutWithBalancedLineLengths

void TextLayout::createLayoutWithBalancedLineLengths (const AttributedString& text, float maxWidth)
{
    const float minimumWidth = maxWidth / 2.0f;
    float bestWidth = maxWidth;
    float bestLineProportion = 0.0f;

	logger.logMessage("minimumWidth "+String(minimumWidth));
	logger.logMessage("bestWidth "+String(bestWidth));
	logger.logMessage("maxWidth "+String(maxWidth));
	

    while (maxWidth > minimumWidth)
    {
		logger.logMessage("Result "+String(maxWidth > minimumWidth));

        createLayout (text, maxWidth);

		logger.logMessage("getNumLines() "+String(getNumLines()));

        if (getNumLines() < 2)
            return;

        const float line1 = lines.getUnchecked (lines.size() - 1)->getLineBoundsX().getLength();
        const float line2 = lines.getUnchecked (lines.size() - 2)->getLineBoundsX().getLength();
        const float shortestLine = jmin (line1, line2);
        const float prop = (shortestLine > 0) ? jmax (line1, line2) / shortestLine : 1.0f;

		logger.logMessage("line1"+String(line1));
		logger.logMessage("line2"+String(line2));
		logger.logMessage("shortestLine"+String(shortestLine));
		logger.logMessage("prop"+String(prop));

        if (prop > 0.9f)
            return;

        if (prop > bestLineProportion)
        {
            bestLineProportion = prop;
            bestWidth = maxWidth;
        }

        maxWidth -= 10.0f;
    }

    if (bestWidth != maxWidth)
        createLayout (text, bestWidth);
}

Have a look at line 380 of juce_win32_DirectWriteTypeLayout.cpp - there’s a bodge in there that’s only enabled for 64-bit builds… If you’re running 32-bit, maybe try enabling it and see what happens?

chkn, enabling it doesn’t help
my further investigations:

seems baselineOriginY is the culprit, as in http://www.rawmaterialsoftware.com/viewtopic.php?t=10039&p=57521

 JUCE_COMRESULT DrawGlyphRun (void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE,
                                     DWRITE_GLYPH_RUN const* glyphRun, DWRITE_GLYPH_RUN_DESCRIPTION const* runDescription,
                                     IUnknown* clientDrawingEffect)
        {

			


            TextLayout* const layout = static_cast<TextLayout*> (clientDrawingContext);

			logger2.logMessage("baselineOriginY "+String (baselineOriginY) );
			logger2.logMessage("lastOriginY "+String (lastOriginY) );


            if (baselineOriginY != lastOriginY)
            {
                lastOriginY = baselineOriginY;
                ++currentLine;

				

                if (currentLine >= layout->getNumLines())
                {
                    jassert (currentLine == layout->getNumLines());
					

					TextLayout::Line* const newLine = new TextLayout::Line();
					logger2.logMessage("addLine layout->getNumLines()" +String (	layout->getNumLines()		) );

                    layout->addLine (newLine);
                    newLine->lineOrigin = Point<float> (baselineOriginX, baselineOriginY);
                }
            }

            TextLayout::Line& glyphLine = layout->getLine (currentLine);

            DWRITE_FONT_METRICS dwFontMetrics;
            glyphRun->fontFace->GetMetrics (&dwFontMetrics);

            glyphLine.ascent  = jmax (glyphLine.ascent,  scaledFontSize (dwFontMetrics.ascent,  dwFontMetrics, glyphRun));
            glyphLine.descent = jmax (glyphLine.descent, scaledFontSize (dwFontMetrics.descent, dwFontMetrics, glyphRun));

            String fontFamily, fontStyle;
            getFontFamilyAndStyle (glyphRun, fontFamily, fontStyle);

            TextLayout::Run* const glyphRunLayout = new TextLayout::Run (Range<int> (runDescription->textPosition,
                                                                                     runDescription->textPosition + runDescription->stringLength),
                                                                         glyphRun->glyphCount);
            glyphLine.runs.add (glyphRunLayout);

            glyphRun->fontFace->GetMetrics (&dwFontMetrics);

            const float totalHeight = std::abs ((float) dwFontMetrics.ascent) + std::abs ((float) dwFontMetrics.descent);
            const float fontHeightToEmSizeFactor = (float) dwFontMetrics.designUnitsPerEm / totalHeight;

            glyphRunLayout->font = Font (fontFamily, fontStyle, glyphRun->fontEmSize / fontHeightToEmSizeFactor);
            glyphRunLayout->colour = getColourOf (static_cast<ID2D1SolidColorBrush*> (clientDrawingEffect));

            const Point<float> lineOrigin (layout->getLine (currentLine).lineOrigin);
            float x = baselineOriginX - lineOrigin.x;

            for (UINT32 i = 0; i < glyphRun->glyphCount; ++i)
            {
                const float advance = glyphRun->glyphAdvances[i];

                if ((glyphRun->bidiLevel & 1) != 0)
                    x -= advance;  // RTL text

                glyphRunLayout->glyphs.add (TextLayout::Glyph (glyphRun->glyphIndices[i],
                                                               Point<float> (x, baselineOriginY - lineOrigin.y),
                                                               advance));

                if ((glyphRun->bidiLevel & 1) == 0)
                    x += advance;  // LTR text
            }

            return S_OK;
        }

FFS, Microsoft! If it never returns a sensible value, how the hell are we supposed to use it??

Random idea: what optimisation flags have you got turned on in your release build? I know that if you enable one of the more extreme floating-point optimisations, the MS compiler can screw up some float calculations - perhaps that’s what’s happening here?

optimization flags, i use the standard in introjucer, it says “Optimize for size and speed”, but wait… VS2008 shows “Minimize Size (/O1)” WTF???

it seems <Tool Name="VCCLCompilerTool" AdditionalOptions="/MP" Optimization="1"
is wrong

Full Optmization is 3 , Optimize Size is 1, Optimize for Speed 2
So it should be 3 and not one!

Anyway: Changing the optimization setting “Optimization” does not help!!!

BUT:

Changing Inline function expansion from: “Only __inline (/Ob1)” to “Any Suitable (/Ob2)” works!!!
But not sure if this a random success, would like to know if other people can reconstruct that…

Thanks, I’ll change the 2 to a 3.

But how could inlining make a difference there? Bizarre!

…one other thought - if this is an audio app, have you changed the CPU’s floating point mode or messed with the float registers?

i get the problems with any project, standard introjucer without changing any settings, also introjucer/audiopluginhost projects

to my previous post, with another project inline expansion has no effect :evil:

BUT

setting the OPTIMIZATION to "FULL OPTIMIZATION"
and setting INLINE FUNCTION EXPANSION to “Any Suitable (/Ob2)”

seems to work on both projects, would be cool if you could set “Any Suitable (/Ob2)” as default in Introjucer…

would be cool if other people could change this both settings and look what they get…

but maybe the problem is still there, its only random that we don’t see it…

I’m really at a loss for what to suggest… The code that returns that float is entirely in Microsoft-land, so compiler options should make no difference.

It just makes no sense that it can call the function with all the other parameters correct, but one of them broken. I’m just stumped. The calling convention is correct because it uses JUCE_COMRESULT, so there shouldn’t be any alignment issues. It’s a total WTF!

Did you use the right mode before using the interface ?

Renderer implementations may choose different rendering modes for given measuring methods, but best results are seen when the rendering mode matches the corresponding measuring mode:
    /// DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL for DWRITE_MEASURING_MODE_NATURAL
    /// DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC for DWRITE_MEASURING_MODE_GDI_CLASSIC
    /// DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL for DWRITE_MEASURING_MODE_GDI_NATURAL

From the public repositories using this function (code.google.com/codesearch for DrawGlyphRun), there is no bug report nor any workaround, so it might be a bad initialization, not the method itself.
I wonder if FLOAT macro maps to a float or double, or if any parameters in there are not the right size (it would explain why you see bullshit value in there). One way to assert this, is to break on the debugger when this happen, load the “Memory” window, and enter “&baselineOriginY” here, so to check if it’s 4 bytes, or 8 bytes, and if the memory around contains the expected value.

jules: optimizing-level in vcproc is still wrong (your patch was wrong)

“Optimize for size and speed” in Introjucer (optimiseLevel intern in Introjucer) ==> “Minimize Size” in VS2008 (which is 1 in .vcproj)

I have turned off JUCE_USE_DIRECTWRITE and will see if it improves rendering on W8.

Jules, what do you use DirectWrite for? I was under the impression that the actual rendering was done in your own code?
With DirectWrite off, the text is slightly larger; not so much it hurts, but a little bit.

Would this bug still exist if one used for example “FreeType”?

just for my interest, Mike could you please check:

setting OPTIMIZATION to "FULL OPTIMIZATION"
and setting INLINE FUNCTION EXPANSION to “Any Suitable (/Ob2)”

if the problem still happens?

[quote=“chkn”]just for my interest, Mike could you please check:

setting OPTIMIZATION to "FULL OPTIMIZATION"
and setting INLINE FUNCTION EXPANSION to “Any Suitable (/Ob2)”

if the problem still happens?[/quote]
Actually, I haven’t seen the problem my self, only one beta tester. Besides, I use Intel C++ and not MS.

Since the issue seem (?) be originating inside DirectX (?) for W8 64 bit, any optimization settings on our side seem unlikely to do anything other than tipping the circumstances if they are already on the edge. Perhaps it’s a matter of CPU register contents or something.

DirectWrite is used for font enumeration, obtaining glyph paths and text layout. Rendering paths to pixels is done by Juce in all cases. The text layout is only used when you use AttributedString or TextLayout classes. Juce’s AlertWindow uses the TextLayout classes.

No, the bug is directly due to DirectWrite. If you turn it off, you won’t get the bug.