text: /**
   ******************************************************************************
   * Xenia : Xbox 360 Emulator Research Project                                 *
   ******************************************************************************
   * Copyright 2013 Ben Vanik. All rights reserved.                             *
   * Released under the BSD license - see LICENSE in the root for more details. *
   ******************************************************************************
   */
  
  #include <xenia/gpu/d3d11/d3d11_window.h>
  
  
  using namespace xe;
  using namespace xe::gpu;
  using namespace xe::gpu::d3d11;
  using namespace xe::ui;
  using namespace xe::ui::win32;
  
  
  D3D11Window::D3D11Window(
      xe_run_loop_ref run_loop,
      IDXGIFactory1* dxgi_factory, ID3D11Device* device) :
      Win32Window(run_loop) {
    dxgi_factory_ = dxgi_factory;
    dxgi_factory_->AddRef();
    device_ = device;
    device_->AddRef();
    device_->GetImmediateContext(&context_);
  
    swap_chain_ = 0;
    render_target_view_ = 0;
  
    closing.AddListener([](UIEvent& e) {
      xe_run_loop_quit(e.window()->run_loop());
    });
  }
  
  D3D11Window::~D3D11Window() {
    if (context_) {
      context_->ClearState();
    }
    XESAFERELEASE(render_target_view_);
    XESAFERELEASE(context_);
    XESAFERELEASE(swap_chain_);
    XESAFERELEASE(device_);
    XESAFERELEASE(dxgi_factory_);
  }
  
  int D3D11Window::Initialize(const char* title, uint32_t width, uint32_t height) {
    int result = Win32Window::Initialize(title, width, height);
    if (result) {
      return result;
    }
  
    // Setup swap chain.
    DXGI_SWAP_CHAIN_DESC desc;
    xe_zero_struct(&desc, sizeof(desc));
    desc.OutputWindow       = handle();
    desc.Windowed           = TRUE;
    desc.SwapEffect         = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
    desc.Flags              = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
  
    // Setup buffers.
    desc.BufferCount        = 2;
    desc.BufferUsage        = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    desc.BufferDesc.Width   = width;
    desc.BufferDesc.Height  = height;
    desc.BufferDesc.Format  = DXGI_FORMAT_R8G8B8A8_UNORM;
    desc.BufferDesc.RefreshRate.Numerator   = 60;
    desc.BufferDesc.RefreshRate.Denominator = 1;
  
    // Disable multisampling.
    desc.SampleDesc.Count   = 1;
    desc.SampleDesc.Quality = 0;
  
    // Create!
    HRESULT hr = dxgi_factory_->CreateSwapChain(
        device_,
        &desc,
        &swap_chain_);
    if (FAILED(hr)) {
      XELOGE("CreateSwapChain failed with %.8X", hr);
      return 1;
    }
  
    // Create a render target view to draw into.
    ID3D11Texture2D* back_buffer = 0;
    hr = swap_chain_->GetBuffer(
        0, __uuidof(ID3D11Texture2D), (void**)&back_buffer);
    if (FAILED(hr)) {
      XELOGE("GetBuffer (back_buffer) failed with %.8X", hr);
      return 1;
    }
    hr = device_->CreateRenderTargetView(
        back_buffer, NULL, &render_target_view_);
    back_buffer->Release();
    if (FAILED(hr)) {
      XELOGE("CreateRenderTargetView (back_buffer) failed with %.8X", hr);
      return 1;
    }
    context_->OMSetRenderTargets(1, &render_target_view_, NULL);
  
    return 0;
  }
  
  void D3D11Window::Swap() {
    // Swap buffers.
    // TODO(benvanik): control vsync with flag.
    bool vsync = true;
    HRESULT hr = swap_chain_->Present(vsync ? 1 : 0, 0);
    if (FAILED(hr)) {
      XELOGE("Present failed with %.8X", hr);
    }
  }
  
  bool D3D11Window::OnResize(uint32_t width, uint32_t height) {
    if (!Win32Window::OnResize(width, height)) {
      return false;
    }
  
    // TODO(benvanik): resize swap buffers?
  
    return true;
  }
  
  