What causes D2DERR_INVALID_GRAPH_CONFIGURATION?

298 views Asked by At

When I'm playing with this MSDN sample, I just fail to add a blur effect on an ID2D1Image created by DXGISurface and filled with some rectangles.

Here is my EndDraw method:

void Scenario1ImageSource::EndDraw()
{
    // Remove the transform and clip applied in BeginDraw since
    // the target area can change on every update.
    m_d2dContext->SetTransform(D2D1::IdentityMatrix());
    m_d2dContext->PopAxisAlignedClip();

    DX::ThrowIfFailed(
        m_d2dContext->Flush()
        );

    ComPtr<ID2D1Image> bitmap;
    m_d2dContext->GetTarget(&bitmap);

    DX::ThrowIfFailed(
        m_d2dContext->CreateEffect(CLSID_D2D1GaussianBlur, &m_gaussianBlurEffect)
        );

    m_gaussianBlurEffect->SetInput(0, bitmap.Get());

    DX::ThrowIfFailed(
        m_gaussianBlurEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, 3.0f)
        );
    DX::ThrowIfFailed(
        m_gaussianBlurEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_BORDER_MODE, D2D1_BORDER_MODE_HARD)
        );

    m_d2dContext->BeginDraw();

    m_d2dContext->DrawImage(m_gaussianBlurEffect.Get());


    // Remove the render target and end drawing.
    DX::ThrowIfFailed(
        m_d2dContext->EndDraw()
        );

    m_d2dContext->SetTarget(nullptr);

    // Query for ISurfaceImageSourceNative interface.
    Microsoft::WRL::ComPtr<ISurfaceImageSourceNative> sisNative;    
    DX::ThrowIfFailed(
        reinterpret_cast<IUnknown*>(this)->QueryInterface(IID_PPV_ARGS(&sisNative))
        );

    DX::ThrowIfFailed(
        sisNative->EndDraw()
        );
}

I want to blur my rectangles after they draw on the image. Why it failed by throwing exception with error code D2DERR_INVALID_GRAPH_CONFIGURATION?

1

There are 1 answers

3
Peter Kostov On BEST ANSWER

Your problem is caused because you are trying to apply an effect to a resource (bitmap/surface in your case) in a BeginDraw/EndDraw block when this resource is used by the DeviceContext as a target. Roughly said, when you call ID2D1RenderTarget.BeginDraw, its target becomes locked and you can't use it for something else than a TARGET.

A simple solution is the use of intermediate bitmap as an offscreen one. Eg (pseudocode):

// somewhere at some initialization point
deviceContext.CreateBitmap(size, nil, 0, @bitmapProps, newBitmap);

// drawing routine
deviceContext.GetTarget(yourInitialTarget);
deviceContext.SetTarget(newBitmap);

deviceContext.BeginDraw;
try
  fBrush.SetColor(getRandomColor);
  deviceContext.FillRect(getRect, fBrush);
finally
  deviceContext.EndDraw;
end;

deviceContext.CreateEffect(@CLSID_D2D1GaussianBlur, fx);
fx.SetInput(0, newBitmap);
fx.GetOutput(newBitmap);

deviceContext.SetTarget(yourInitialTarget);

deviceContext.BeginDraw;
try
  deviceContext.Clear(getRandomColor);
  deviceContext.DrawImage(newBitmap);
finally
  deviceContext.EndDraw;
end;

Keep in mind that the output bitmap from the built in GaussianBlur effect can be larger than the input one. Gaussian blur effect