使用DirectXTK SpriteBatch闪烁

时间:2014-09-30 22:33:54

标签: c++ directx directx-11 flicker spritebatch

我正在使用DirectXTK SpriteBatch类来渲染精灵。问题是精灵闪烁。我想这是由于前/后缓冲切换。

是否可以避免这种闪烁效应?

我的渲染代码如下:

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();
}

与Windows大小相关的初始化代码如下:

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);
}

提前致谢!

0 个答案:

没有答案