1// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "stdafx.h"
6#include <corewindow.h>
7#include <windows.applicationmodel.core.h>
8#include <windows.graphics.display.h>
9
10#include "win8/metro_driver/direct3d_helper.h"
11#include "base/logging.h"
12#include "base/win/windows_version.h"
13#include "ui/gfx/win/dpi.h"
14#include "win8/metro_driver/winrt_utils.h"
15
16namespace {
17
18void CheckIfFailed(HRESULT hr) {
19  DCHECK(!FAILED(hr));
20  if (FAILED(hr))
21    DVLOG(0) << "Direct3D call failed, hr = " << hr;
22}
23
24// TODO(ananta)
25// This function does not return the correct value as the IDisplayProperties
26// interface does not work correctly in Windows 8 in metro mode. Needs
27// more investigation.
28float GetLogicalDpi() {
29  mswr::ComPtr<wingfx::Display::IDisplayPropertiesStatics> display_properties;
30  CheckIfFailed(winrt_utils::CreateActivationFactory(
31      RuntimeClass_Windows_Graphics_Display_DisplayProperties,
32      display_properties.GetAddressOf()));
33  float dpi = 0.0;
34  CheckIfFailed(display_properties->get_LogicalDpi(&dpi));
35  return dpi;
36}
37
38float ConvertDipsToPixels(float dips) {
39  return floor(dips * gfx::GetDPIScale() + 0.5f);
40}
41
42}
43
44namespace metro_driver {
45
46Direct3DHelper::Direct3DHelper() {
47}
48
49Direct3DHelper::~Direct3DHelper() {
50}
51
52void Direct3DHelper::Initialize(winui::Core::ICoreWindow* window) {
53  window_ = window;
54  CreateDeviceResources();
55  CreateWindowSizeDependentResources();
56}
57
58// TODO(scottmg): Need to handle resize messages and recreation.
59
60void Direct3DHelper::CreateDeviceResources() {
61  unsigned int creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
62  D3D_FEATURE_LEVEL feature_levels[] = {
63    D3D_FEATURE_LEVEL_11_1,
64    D3D_FEATURE_LEVEL_11_0,
65    D3D_FEATURE_LEVEL_10_1,
66    D3D_FEATURE_LEVEL_10_0,
67    D3D_FEATURE_LEVEL_9_3,
68    D3D_FEATURE_LEVEL_9_2,
69    D3D_FEATURE_LEVEL_9_1,
70  };
71
72  mswr::ComPtr<ID3D11Device> device;
73  mswr::ComPtr<ID3D11DeviceContext> context;
74  CheckIfFailed(
75      D3D11CreateDevice(
76          nullptr,
77          D3D_DRIVER_TYPE_HARDWARE,
78          nullptr,
79          creation_flags,
80          feature_levels,
81          ARRAYSIZE(feature_levels),
82          D3D11_SDK_VERSION,
83          &device,
84          &feature_level_,
85          &context));
86  CheckIfFailed(device.As(&d3d_device_));
87  CheckIfFailed(context.As(&d3d_context_));
88}
89
90void Direct3DHelper::CreateWindowSizeDependentResources() {
91  float window_width = 0;
92  float window_height = 0;
93
94  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
95    // Windows 8 returns in DIPs.
96    CheckIfFailed(window_->get_Bounds(&window_bounds_));
97    window_width = ConvertDipsToPixels(window_width);
98    window_height = ConvertDipsToPixels(window_height);
99  }
100
101  // TODO(scottmg): Orientation.
102
103  if (swap_chain_ != nullptr) {
104    // TODO(scottmg): Resize if it already exists.
105    NOTIMPLEMENTED();
106  } else {
107    DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = { 0 };
108    swap_chain_desc.Width = window_width;
109    swap_chain_desc.Height = window_height;
110    swap_chain_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
111    swap_chain_desc.Stereo = false;
112    swap_chain_desc.SampleDesc.Count = 1;
113    swap_chain_desc.SampleDesc.Quality = 0;
114    swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
115    swap_chain_desc.BufferCount = 2; // TODO(scottmg): Probably 1 is fine.
116    swap_chain_desc.Scaling = DXGI_SCALING_NONE;
117    swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
118    swap_chain_desc.Flags = 0;
119
120    mswr::ComPtr<IDXGIDevice1> dxgi_device;
121    CheckIfFailed(d3d_device_.As(&dxgi_device));
122
123    mswr::ComPtr<IDXGIAdapter> dxgi_adapter;
124    CheckIfFailed(dxgi_device->GetAdapter(&dxgi_adapter));
125
126    mswr::ComPtr<IDXGIFactory2> dxgi_factory;
127    CheckIfFailed(dxgi_adapter->GetParent(
128        __uuidof(IDXGIFactory2), &dxgi_factory));
129
130    if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
131      // On Win8 we need the CoreWindow interface to create the Swapchain.
132      CheckIfFailed(dxgi_factory->CreateSwapChainForCoreWindow(
133          d3d_device_.Get(),
134          reinterpret_cast<IUnknown*>(window_),
135          &swap_chain_desc,
136          nullptr,
137          &swap_chain_));
138    } else {
139      // On Win7 we need the raw HWND to create the Swapchain.
140      mswr::ComPtr<ICoreWindowInterop> interop;
141      CheckIfFailed(window_->QueryInterface(interop.GetAddressOf()));
142      HWND window = NULL;
143      interop->get_WindowHandle(&window);
144
145      swap_chain_desc.Scaling = DXGI_SCALING_STRETCH;
146      swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
147
148      CheckIfFailed(dxgi_factory->CreateSwapChainForHwnd(
149          d3d_device_.Get(),
150          window,
151          &swap_chain_desc,
152          nullptr,
153          nullptr,
154          &swap_chain_));
155    }
156  }
157}
158
159}  // namespace metro_driver
160