The JUCE 8 Preview branch is available now!

Excellent! No, you’re not doing anything wrong. That was a nice find. The sample code was very helpful.

Matt

It looks like I am getting a software image here though. Could it be the cause of the slowdown I am seeing compared to the JUCE 7 Direct2D branch?

Great job guys :slight_smile:
Noticed small thing that if child components have been rotated (via an affine transform), i don’t get same behaviour with d2d renderer vs Software renderer, with d2d component get like ‘cliped’, not sure if there is something special to do maybe…

here quick vid ex of what i mean: i double clic to rotate child red comp, first software, then d2d. can post code in case made mistakes
https://youtu.be/DBk4D74fwXw

#pragma once
#include <JuceHeader.h>

class ChildComponent : public juce::Component
{
	public:
	ChildComponent(){};
	~ChildComponent() {};

	void paint(juce::Graphics& g){g.fillAll(juce::Colour{0xFFFF0000});}
};

class MainComponent  : public juce::Component
{
public:
    //==============================================================================
    MainComponent() 
	{
		addAndMakeVisible(child_comp);
		setSize(600, 400); 
	};
    ~MainComponent() {};

    //==============================================================================
    void paint(juce::Graphics& g) 
    {
		g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
    }
	void resized() 
	{
		child_comp.setSize(600, 100);
	};

	bool is_rotated = false;
	bool use_d2d = true;

	void mouseDoubleClick(const juce::MouseEvent& e)
	{
		if (is_rotated)
		{
			child_comp.setSize(600, 100);
			child_comp.setTopLeftPosition({ 0,0 });
			child_comp.setTransform({});
		}
		else{ rotate_comp(child_comp, false, { 100,600 });}

		is_rotated = !is_rotated;
	}

	void parentHierarchyChanged() override
	{
		if (use_d2d) return;

		if (auto peer = getPeer())
		{
			int wanted_engine = 0; // software?
			peer->setCurrentRenderingEngine(wanted_engine);
		}
	}

	static void rotate_comp(juce::Component& component, bool clockWiseRotation, juce::Rectangle<int> verticalBounds)
	{
		auto angle = juce::MathConstants<float>::pi / 2.0f;

		if (!clockWiseRotation) angle *= -1.0f;

		component.setTransform({});
		component.setSize(verticalBounds.getHeight(), verticalBounds.getWidth());
		component.setCentrePosition(0, 0);
		component.setTransform(juce::AffineTransform::rotation(angle).translated(verticalBounds.getCentreX(), verticalBounds.getCentreY()));
	}

	ChildComponent child_comp;

private:
    //==============================================================================
    // Your private member variables go here...


    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};

1 Like

Thanks for the detailed report. Please go into JUCE\modules\juce_graphics\native, open juce_Direct2DGraphicsContext_windows.cpp. Find the setOrigin method and add a call to resetPendingClipList:

void Direct2DGraphicsContext::setOrigin (Point<int> o)
{
    applyPendingClipList();

    currentState->currentTransform.setOrigin (o);

    resetPendingClipList(); // add this line
}

Matt

The renderer is presenting you with a software image so you can manipulate the bitmap directly. The image should be converted to a Direct2D GPU-stored bitmap once you release the bitmap data. We still need to investigate the performance issues.

Matt

1 Like

Yeahh! fixed all my issues, you’re a master :slight_smile: thanks!

Very good to hear!

Matt

I’m still struggling to repro this. Is the assertion definitely present with the example code that you provided? If so, it might be helpful to see a stack trace at the point of the assertion. If you can work out what’s being drawn when the assertion fires, that might be helpful too.

And can we get a few warnings in choc silenced:

1 Like

Hi @reuk,

It was indeed not present in my example because I had removed the buttons that select the renderer, which appear to be the cause of the problem! Sorry about that.

Here is an example code that does trigger the assertion:

#pragma once
#include <JuceHeader.h>

class MainComponent  : public juce::Component {
public:
	MainComponent() {
		setSize(600, 200);
		addAndMakeVisible(button);

		setDirect2D(false);
		button.setButtonText("button_text");
		//button.setButtonText("different_button_text");
	}

	void resized() override {
		button.setBounds(getLocalBounds().removeFromTop(30).removeFromLeft(getWidth() / 4));
	}

private:

	void setDirect2D(bool enable) {
		juce::Timer::callAfterDelay(0, [this, enable] {
			jassert(getPeer());
			if (!getPeer()) return;
			getPeer()->setCurrentRenderingEngine(enable ? 1 : 0);
		});
	}

	juce::TextButton button;

	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};

The problem appears when you resize the window and the text gets squashed to fit the button (I guess it could trigger with drawFittedText directly). It does appear when the text cannot be squashed anymore, and the height is supposed to be reduced. It only happens with certain strings.

Here are the effects when this happens, for different combinations that you can set in the example code:

  • software renderer, “button_text” button text : assertion does trigger
  • direct2D renderer, “button_text” button text : the text disappears
  • software renderer, “different_button_text” button text: height reduced, ok
  • direct2D renderer, “different_button_text” button text : height reduced, ok

Here is the call stack:

>	NewProject.exe!juce::Path::applyTransform(const juce::AffineTransform & transform) Line 831	C++
 	NewProject.exe!juce::Typeface::getLayersForGlyph(juce::TypefaceMetricsKind kind, int glyphNumber, const juce::AffineTransform & transform, float __formal) Line 547	C++
 	NewProject.exe!<lambda_86464f4924c676fe45f23c05370598e3>::operator()<juce::RenderingHelpers::GlyphCache::Key>(const juce::RenderingHelpers::GlyphCache::Key & key) Line 209	C++
 	NewProject.exe!juce::LruCache<juce::RenderingHelpers::GlyphCache::Key,std::vector<juce::GlyphLayer,std::allocator<juce::GlyphLayer>>,128>::get<<lambda_86464f4924c676fe45f23c05370598e3>>(juce::RenderingHelpers::GlyphCache::Key key, juce::RenderingHelpers::GlyphCache::get::__l2::<lambda_86464f4924c676fe45f23c05370598e3> && fn) Line 59	C++
 	NewProject.exe!juce::RenderingHelpers::GlyphCache::get(const juce::Font & font, const int glyphNumber) Line 205	C++
 	NewProject.exe!juce::RenderingHelpers::StackBasedLowLevelGraphicsContext<juce::RenderingHelpers::SoftwareRendererSavedState>::drawGlyph::__l2::<lambda>() Line 2652	C++
 	NewProject.exe!juce::RenderingHelpers::StackBasedLowLevelGraphicsContext<juce::RenderingHelpers::SoftwareRendererSavedState>::drawGlyph(unsigned short i, const juce::AffineTransform & t) Line 2660	C++
 	NewProject.exe!juce::RenderingHelpers::StackBasedLowLevelGraphicsContext<juce::RenderingHelpers::SoftwareRendererSavedState>::drawGlyphs(juce::Span<unsigned short const ,-1> glyphs, juce::Span<juce::Point<float> const ,-1> positions, const juce::AffineTransform & t) Line 2621	C++
 	NewProject.exe!juce::GlyphArrangement::draw(const juce::Graphics & g, juce::AffineTransform transform) Line 635	C++
 	NewProject.exe!juce::`anonymous namespace'::ConfiguredArrangement::draw(const juce::Graphics & g) Line 63	C++
 	NewProject.exe!juce::Graphics::drawFittedText(const juce::String & text, juce::Rectangle<int> area, juce::Justification justification, int maximumNumberOfLines, float minimumHorizontalScale) Line 487	C++
 	NewProject.exe!juce::Graphics::drawFittedText(const juce::String & text, int x, int y, int width, int height, juce::Justification justification, int maximumNumberOfLines, float minimumHorizontalScale) Line 499	C++
 	NewProject.exe!juce::LookAndFeel_V2::drawButtonText(juce::Graphics & g, juce::TextButton & button, bool __formal, bool __formal) Line 289	C++
 	NewProject.exe!juce::TextButton::paintButton(juce::Graphics & g, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) Line 64	C++
 	NewProject.exe!juce::Button::paint(juce::Graphics & g) Line 463	C++
 	NewProject.exe!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 1640	C++
 	NewProject.exe!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 1754	C++
 	NewProject.exe!juce::Component::paintWithinParentContext(juce::Graphics & g) Line 1611	C++
 	NewProject.exe!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 1682	C++
 	NewProject.exe!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 1754	C++
 	NewProject.exe!juce::Component::paintWithinParentContext(juce::Graphics & g) Line 1611	C++
 	NewProject.exe!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 1682	C++
 	NewProject.exe!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 1754	C++
 	NewProject.exe!juce::ComponentPeer::handlePaint(juce::LowLevelGraphicsContext & contextToPaintTo) Line 170	C++
 	NewProject.exe!juce::GDIContext::performPaint(HDC__ * dc, HRGN__ * rgn, int regionType, tagPAINTSTRUCT & paintStruct) Line 4570	C++
 	NewProject.exe!juce::GDIContext::handlePaintMessage() Line 4414	C++
 	NewProject.exe!juce::HWNDComponentPeer::handlePaintMessage() Line 2589	C++
 	NewProject.exe!juce::HWNDComponentPeer::peerWindowProc(HWND__ * h, unsigned int message, unsigned __int64 wParam, __int64 lParam) Line 3600	C++
 	NewProject.exe!juce::HWNDComponentPeer::windowProc(HWND__ * h, unsigned int message, unsigned __int64 wParam, __int64 lParam) Line 3540	C++
 	[External Code]	
 	NewProject.exe!juce::HWNDComponentPeer::peerWindowProc(HWND__ * h, unsigned int message, unsigned __int64 wParam, __int64 lParam) Line 3985	C++
 	NewProject.exe!juce::HWNDComponentPeer::windowProc(HWND__ * h, unsigned int message, unsigned __int64 wParam, __int64 lParam) Line 3540	C++
 	[External Code]	
 	NewProject.exe!juce::HWNDComponentPeer::peerWindowProc(HWND__ * h, unsigned int message, unsigned __int64 wParam, __int64 lParam) Line 3985	C++
 	NewProject.exe!juce::HWNDComponentPeer::windowProc(HWND__ * h, unsigned int message, unsigned __int64 wParam, __int64 lParam) Line 3540	C++
 	[External Code]	
 	NewProject.exe!juce::InternalMessageQueue::dispatchNextMessage(bool returnIfNoPendingMessages) Line 155	C++
 	NewProject.exe!juce::detail::dispatchNextMessageOnSystemQueue(bool returnIfNoPendingMessages) Line 274	C++
 	NewProject.exe!juce::MessageManager::runDispatchLoop() Line 124	C++
 	NewProject.exe!juce::JUCEApplicationBase::main() Line 281	C++
 	NewProject.exe!WinMain(HINSTANCE__ * __formal, HINSTANCE__ * __formal, char * __formal, int __formal) Line 105	C++
 	[External Code]	

1 Like

So far I have no need to delete animators, but I just thought if there was a chain of different animations, it would be much more convenient to delete them with “clearAll()” and then add new ones with a new durationMs and “Easing”.

Btw. I did not found a way to change durationMs or Easing without constructing it from the beginning.

Despite this, I continue to be pleased with how smoothly the Component now works :slight_smile: I made a slide effect that moves the Component when the tab is pressed. If you change through setBounds() it will not be smooth (and logical, because there is int)

So I did this:

.withValueChangedCallback([this](auto value) {
   ...
   myComponent.setTransform(juce::AffineTransform::translation(currentX_, 0.0F));
}

And it’s rock!

I’m noticing some buggy behavior with the webview2 component on Windows 11.

After navigating away from the initial page loaded with goToURL(), then calling goToURL again, the page will no longer display after having been hidden with setVisible.
WebViewIssue

class MainComponent : public juce::Component
{
public:
    MainComponent()
    {
        webView.reset(new juce::WebBrowserComponent(
            juce::WebBrowserComponent::Options().withBackend(
                juce::WebBrowserComponent::Options::Backend::webview2)));
        addAndMakeVisible(webView.get());

        addAndMakeVisible(loadButton);
        loadButton.onClick = [this] { webView->goToURL("https://github.com/MishaalRahmanGH/Ultra_HDR_Samples"); };
        addAndMakeVisible(hideButton);
        hideButton.onClick = [this] { webView->setVisible(!webView->isVisible()); };

        webView->goToURL("https://github.com/MishaalRahmanGH/Ultra_HDR_Samples");

        setSize(600, 400);
    };
    ~MainComponent() override = default;

    void resized() override
    {
        webView->setBounds(10, 45, getWidth() - 20, getHeight() - 55);
        hideButton.setBounds(10, 10, 70, 25);
        loadButton.setBounds(90, 10, 70, 25);
    };

private:
    std::unique_ptr<juce::WebBrowserComponent> webView;
    juce::TextButton loadButton{ "Load", "Load" }, hideButton{ "Hide", "Hide" };

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};

As an aside, in case anyone is interested, the component is properly rendering Ultra HDR JPEG files on a HDR monitor. :sunglasses:

1 Like