COffscreenContext memory leak?

Hello,

Using VSTGUI 4.10 and the vst3 SDK 3.7.2, OSX 10.15.6. I have a question about storing a CBitmap created from COffscreenContext…

SharedPointer<CBitmap> _bitmap;
void drawSomething( CView *view,  SharedPointer<COffscreenContext> context );
void captureBitmap( CView *view )
{
    CFrame *frame = view->getFrame();
    if (!frame)
        return;
    
    const CRect &view_rect = view->getViewSize();
    
    SharedPointer<COffscreenContext> context = COffscreenContext::create( frame, view_rect.getWidth(), view_rect.getHeight(), 4. );

    context->beginDraw();
    drawSomething( view, context );
    context->endDraw();
    _bitmap = context->getBitmap();
    // _bitmap->remember();  //  <--- Is this needed?
}

I’m seeing different behavior between my VST3 and AUv2 plug-ins whether _bitmap->remember() is called or not.

It seems to me that the _bitmap shared pointer shouldn’t need an explicit remember(). However for AUv2, there is an intermittent crash after the plug-in is de-instantiated. The backtrace shows the crash inside CFRelease. If I then either comment out the line CGImageRelease (image) in the CGBitmap destructor, or call _bitmap->remember() above, then the crash does not happen.

For VST3, calling _bitmap->remember() produces a memory leak in VST3PluginTestHost as I’d expect. So I’m wondering if there’s a problem with my code above or if the problem exists externally. Any insight?

Thank you!
George

Maybe use the freestanding renderBitmapOffscreen function from coffscreencontext.h: vstgui/coffscreencontext.h at develop · steinbergmedia/vstgui · GitHub

It does what you want without a leak.

Hi,

Sorry for bumping this old thread, but my problem might be related.
I’m using OffscreenContest for drawing the whole frame and then, after getting the bitmap, use it for drawing part of it.

SharedPointer< CBitmap > cachedBitmap;
void Vcs3Edit::valueChanged (CDrawContext* context, CControl* control)
{

       COffscreenContext* AnimationOffScreen1 = COffscreenContext::create (mframeEdit,    mLargeurOffScreenAnimation, mHauteurOffScreenAnimation);

            TotalOffScreen->beginDraw ();
            mframeEdit->draw(TotalOffScreen );
            TotalOffScreen->endDraw ();
           TotalOffScreen->copyFrom (AnimationOffScreen1, SizeAnimation,Point);
            cachedBitmap = AnimationOffScreen1->getBitmap ();
  
           ...  memorizing the cachedBitmap and using it later ...

}

It’s working all fine on OSX (Built in Xcode12, test in BigSur Intel), but I have a problem on windows (Built with Visual Studio 2019, test in windows10, Cubase 10).
The bitmap is always empty (display black background)

So I wonder if there isn’t something I missed (or badly coded)

Best regards
Xavier

Have you tried to use the renderBitmapOffscreen function as stated above?

Hi Arne,
Thanks for your answer.
Actually I didn’t try it because I’m wondering how to use and write the part “std::function<void (CDrawContext& drawContext)> drawCallback”
I just want to whole current frame to be drawn and can’t see how convert that with this function

Best regards
Xavier

This is just a function… so you can do it 2 ways:

  1. write an actual function and use its name
void MyDrawFunction(CDrawContext& drawContext)
{
  // code that generate your bitmap using the drawContext
}

and you call it this way

renderBeatmapOffscreen(size, factor, MyDrawFunction);
  1. you use a lambda
renderBeatmapOffscreen(size, factor, [](CDrawContext& drawContext) {
  // code that generate your bitmap using the drawContext
});

Thanks pongasoft,
I’ll try this.
I’m still wondering how to draw the whole frame though, but I’m sure it’s my c++ understanding which have to be increased.

Best regards
Xavier

I simply tried that:

cachedBitmap=VSTGUI::renderBitmapOffscreen (SizeOffscreen,1.0,[](CDrawContext& MydrawContext) {
                            CRect Rect;
                            MydrawContext.setFillColor (kBlueCColor);
                            MydrawContext.setFrameColor (kBlueCColor);
                            Rect(50,50,500,200);
                            MydrawContext.drawRect(Rect,kDrawFilledAndStroked);
                            } );
... passing cachedBitmap to an other class to be drawn later.

and this worked on both system, OSX and windows.
But now, I have to render the whole frame which is part of a class (this).

frame->draw(TotalOffScreen );

So I’m still wondering how to pass frame to this renderBitmapOffscreen function

Best regards
Xavier

You can read up on lambdas in c++ here.
For this use case, you just have to ‘capture’ the frame variable in the lambda:

auto bmp = renderBitmapOffscreen (size, 1.0, [frame] (CDrawContext& context) {
  frame->draw (&context);
}

Thanks Arne,
That’s perfect and working fine on both system.
My skill in C++ as not as good (I prefer to focus on DSP) but is improving thank to all of you !

         cachedBitmap=VSTGUI::renderBitmapOffscreen (SizeOffscreen,1.0,[this](CDrawContext& MydrawContext) { 
                           mframeEdit->draw(&MydrawContext );
                                     } );

Best regards
Xavier

Hi again !

Finally I think that my problem is not really related with the sharedpointer bitmap but with the copyfrom function from COffscreenContext
Obviously I want to do a bit more than simply drawing the whole frame in a bitmap: I want a part of it. Here is what I wrote, which works fine on OSX but not on windows (I get a black image instead of the expected part of the frame)

      cachedBitmap=VSTGUI::renderBitmapOffscreen (SizeOffscreen,1.0,[this](CDrawContext& MydrawContext) {
                    
          CRect Rect;
          CPoint SizeOffscreen;
          CPoint Point;
          CPoint SizeAnimation;
                    
          SizeOffscreen.x=mFrameWidth;
          SizeOffscreen.y=mFrameHeight;
          auto TotalOffScreen = COffscreenContext::create (SizeOffscreen, 1.0);

          Rect.top=0;
           Rect.bottom=mWidthOffScreenAnimation;
           Rect.left=0;
           Rect.right=mHeightOffScreenAnimation;
          
           // Working on windows, but not what I want
//        mframeEdit->drawRect(&MydrawContext,Rect );
                      
           // Doesnt work on windows (black screen), workinng on OSX
           SizeAnimation.x=mWidthOffScreenAnimation;
           SizeAnimation.y=mHeightOffScreenAnimation;

           mframeEdit->draw(TotalOffScreen);
           Point(mLeftPositionX,mLeftPositionY);
           TotalOffScreen->copyFrom (&MydrawContext, SizeAnimation,Point);

           TotalOffScreen->forget();
                                     } );

So my question is do I use copyFrom the way it should be ? I also wonder why it’s working fine on OSX (Big Sur) and not on windows (10).

Thanks in advance for any help.
Best regards
Xavier

You’re doing too much here. I’m not sure why copyFrom does not work. But you don’t need it. What you have to do is something like this:

	CRect theRectYouWantToDraw = {10, 10, 20, 20};
	renderBitmapOffscreen (theRectYouWantToDraw.getSize (), 1., [&] (CDrawContext& drawContext) {
		CGraphicsTransform tm;
		tm.translate (-theRectYouWantToDraw.getTopLeft ());
		CDrawContext::Transform t (drawContext, tm);
		mFrame->drawRect (&drawContext, theRectYouWantToDraw);
	});

Thanks Arne,

That works just fine on both systems

Best regards
Xavier