0

I am using the DirectXTK SpriteBatch class for rendering sprites. The problem is that the sprite flickers. I suppose it's due to the front/back buffer switching.

Is it possible to avoid this flicker effect?

My render code looks like:

void Render(float elapsedTime)
{
  ID2D1DeviceContext* d2dContext = g_devResources->GetD2dDeviceContext();

  // Draw sprite
  g_SpriteBatch->Begin(SpriteSortMode_Deferred);
  {
    g_SpriteBatch->Draw(g_texture, XMFLOAT2(10, 75), nullptr, Colors::White);
  }
  g_SpriteBatch->End();
}

And the windows size dependent initialization code as follows:

void DeviceResources::InitWindowSizeDependentResources(HWND hWnd)
{
  HRESULT hr;

  // Identify the physical adapter (GPU or card) this device is runs on.
  ComPtr<IDXGIAdapter> dxgiAdapter;
  hr = m_dxgiDevice->GetAdapter(&dxgiAdapter);

  if (FAILED(hr))
  {
    throw std::exception("Identification of IDXGIAdapter failed");
  }

  // Get the factory object that created the DXGI device.
  ComPtr<IDXGIFactory2> dxgiFactory;
  hr = dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory));

  if (FAILED(hr))
  {
    throw std::exception("Get IDXGIFactory2 failed");
  }

  // Allocate a swap chain descriptor.
  DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
  swapChainDesc.Width = 0;                           // use automatic sizing
  swapChainDesc.Height = 0;
  swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format
  swapChainDesc.Stereo = false;
  swapChainDesc.SampleDesc.Count = 1;                // don't use multi-sampling
  swapChainDesc.SampleDesc.Quality = 0;
  swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
  swapChainDesc.BufferCount = 2;                     // use double buffering to enable flip
  swapChainDesc.Scaling = DXGI_SCALING_NONE;
  swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // all apps must use this SwapEffect
  swapChainDesc.Flags = 0;

  // Get the final swap chain for this window from the DXGI factory.
  hr = dxgiFactory->CreateSwapChainForHwnd(
    m_d3dDevice.Get(),
    hWnd,
    &swapChainDesc,
    NULL,
    NULL,
    &m_dxgiSwapChain
    );

  if (FAILED(hr))
  {
    throw std::exception("Creation of IDXGISwapChain failed");
  }

  // Ensure that DXGI doesn't queue more than one frame at a time (minimize power consumption).
  hr = m_dxgiDevice->SetMaximumFrameLatency(1);

  if (FAILED(hr))
  {
    throw std::exception("Set MaximumFrameLatency failed");
  }

  // Get the backbuffer for this window which is be the final 3D render target.
  ComPtr<ID3D11Texture2D> backBuffer;
  hr = m_dxgiSwapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer));

  if (FAILED(hr))
  {
    throw std::exception("Get BackBuffer failed");
  }

  hr = m_d3dDevice->CreateRenderTargetView(backBuffer.Get(), nullptr, &m_d3dRenderTargetView);

  // Now we set up the Direct2D render target bitmap linked to the swapchain. 
  // Whenever we render to this bitmap, it is directly rendered to the 
  // swap chain associated with the window.
  D2D1_BITMAP_PROPERTIES1 bitmapProperties =
    D2D1::BitmapProperties1(
    D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
    D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
    96.0f, // dpi x
    96.0f  // dpi y
    );

  // Direct2D needs the dxgi version of the backbuffer surface pointer.
  ComPtr<IDXGISurface> dxgiBackBuffer;
  hr = m_dxgiSwapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer));

  if (FAILED(hr))
  {
    throw std::exception("Get BackBuffer failed");
  }

  // Get a D2D surface from the DXGI back buffer to use as the D2D render target.
  hr = m_d2dContext->CreateBitmapFromDxgiSurface(
    dxgiBackBuffer.Get(),
    bitmapProperties,
    m_d2dRenderTargetBitmap.GetAddressOf());

  if (FAILED(hr))
  {
    throw std::exception("CreateBitmapFromDxgiSurface failed");
  }

  // Now we can set the Direct2D render target.
  m_d2dContext->SetTarget(m_d2dRenderTargetBitmap.Get());

  // tell DirectX how to scale its logical coordinate system to physical display
  float dpiX, dpiY;
  m_d2dFactory1->GetDesktopDpi(&dpiX, &dpiY);
  m_d2dContext->SetDpi(dpiX, dpiY);

  // Create depth stencil texture
  D3D11_TEXTURE2D_DESC descDepth;
  ZeroMemory(&descDepth, sizeof(descDepth));
  descDepth.Width = 640;
  descDepth.Height = 480;
  descDepth.MipLevels = 1;
  descDepth.ArraySize = 1;
  descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
  descDepth.SampleDesc.Count = 1;
  descDepth.SampleDesc.Quality = 0;
  descDepth.Usage = D3D11_USAGE_DEFAULT;
  descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
  descDepth.CPUAccessFlags = 0;
  descDepth.MiscFlags = 0;
  hr = m_d3dDevice->CreateTexture2D(&descDepth, nullptr, &m_d3dDepthStencil);

  if (FAILED(hr))
  {
    throw std::exception("CreateTexture2D failed");
  }

  // Create the depth stencil view
  D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
  ZeroMemory(&descDSV, sizeof(descDSV));
  descDSV.Format = descDepth.Format;
  descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
  descDSV.Texture2D.MipSlice = 0;
  hr = m_d3dDevice->CreateDepthStencilView(m_d3dDepthStencil.Get(), &descDSV, &m_d3dDepthStencilView);

  if (FAILED(hr))
  {
    throw std::exception("CreateDepthStencilView failed");
  }

  m_d3dContext->OMSetRenderTargets(1, m_d3dRenderTargetView.GetAddressOf(), m_d3dDepthStencilView.Get());

  // Setup the viewport 
  // todo: wozu genau? (eingebaut, damit es in SpriteBatch.End() nicht knallt...)
  D3D11_VIEWPORT vp;
  vp.Width = 640.0f;
  vp.Height = 480.0f;
  vp.MinDepth = 0.0f;
  vp.MaxDepth = 1.0f;
  vp.TopLeftX = 0;
  vp.TopLeftY = 0;
  m_d3dContext->RSSetViewports(1, &vp);
}

Thanks in advance!

n2k
  • 109
  • 2
  • 13
  • Given that you are calling ``CreateSwapChainForHwnd`` I assume you are writing a Win32 desktop app, and not a Windows Store app, correct? If you are using a Win32 desktop app, you don't need to use ``DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL`` and might have better luck using ``DXGI_SWAP_EFFECT_DISCARD``. If you are writing a Windows Store app, you need to use ``CreateSwapChainForCoreWindow`` – Chuck Walbourn Sep 30 '14 at 22:42
  • Yes, you're right. I am writing a Win32 desktop app. Thanks for your reply. After changing the swap effect to discard I get the following HRESULT error from CreateSwapChainForHwnd: 0x887a0001 (DXGI_ERROR_INVALID_CALL): "The application provided invalid parameter data; this must be debugged and fixed before the application is released.". I already checked the parameters given to CreateSwapChainForHwnd(). It looks right. I suppose that I still have inconsistency swap chain desc values. But I don't know, what's going wrong. – n2k Oct 01 '14 at 11:06
  • Try building and running the [Direct3D Win32 Tutorial](http://code.msdn.microsoft.com/Direct3D-Tutorial-Win32-829979ef). It uses this API when available--and has a fallback if you want to support DirectX 11.0 systems. – Chuck Walbourn Oct 01 '14 at 17:24
  • Hi Chuck, thanks for the link. With the help of the sample I am able to avoid the flicker effect. – n2k Oct 01 '14 at 20:13

0 Answers0