Search code examples
winrt-xamldirect2dwinrt-component

What causes D2DERR_INVALID_GRAPH_CONFIGURATION?


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?


Solution

  • 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