Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: gpu/ipc/service/direct_composition_child_surface_win.cc

Issue 2926763002: Split DirectCompositionSurfaceWin into two parts. (Closed)
Patch Set: add ScopedReleaseCurrent Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 "gpu/ipc/service/direct_composition_child_surface_win.h"
6
7 #include <d3d11_1.h>
8 #include <dcomptypes.h>
9
10 #include "base/memory/ptr_util.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/optional.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/trace_event/trace_event.h"
15 #include "ui/display/display_switches.h"
16 #include "ui/gfx/native_widget_types.h"
17 #include "ui/gl/egl_util.h"
18 #include "ui/gl/gl_angle_util_win.h"
19 #include "ui/gl/gl_context.h"
20 #include "ui/gl/gl_surface_egl.h"
21 #include "ui/gl/scoped_make_current.h"
22
23 #ifndef EGL_ANGLE_flexible_surface_compatibility
24 #define EGL_ANGLE_flexible_surface_compatibility 1
25 #define EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE 0x33A6
26 #endif /* EGL_ANGLE_flexible_surface_compatibility */
27
28 #ifndef EGL_ANGLE_d3d_texture_client_buffer
29 #define EGL_ANGLE_d3d_texture_client_buffer 1
30 #define EGL_D3D_TEXTURE_ANGLE 0x33A3
31 #endif /* EGL_ANGLE_d3d_texture_client_buffer */
32
33 namespace gpu {
34
35 namespace {
36 // Only one DirectComposition surface can be rendered into at a time. Track
37 // here which IDCompositionSurface is being rendered into. If another context
38 // is made current, then this surface will be suspended.
39 IDCompositionSurface* g_current_surface;
40
41 class ScopedReleaseCurrent {
sunnyps 2017/06/10 00:11:11 nit: This is duplicated both here and in the root
42 public:
43 explicit ScopedReleaseCurrent(gl::GLSurface* this_surface) {
44 gl::GLContext* current_context = gl::GLContext::GetCurrent();
45 bool was_current =
46 current_context && current_context->IsCurrent(this_surface);
47 if (was_current) {
48 make_current_.emplace(current_context, this_surface);
49 current_context->ReleaseCurrent(this_surface);
50 }
51 }
52
53 private:
54 base::Optional<ui::ScopedMakeCurrent> make_current_;
55 };
56 }
57
58 DirectCompositionChildSurfaceWin::DirectCompositionChildSurfaceWin(
59 const gfx::Size& size,
60 bool has_alpha,
61 bool enable_dc_layers)
62 : gl::GLSurfaceEGL(),
63 size_(size),
64 has_alpha_(has_alpha),
65 enable_dc_layers_(enable_dc_layers) {}
66
67 DirectCompositionChildSurfaceWin::~DirectCompositionChildSurfaceWin() {
68 Destroy();
69 }
70
71 bool DirectCompositionChildSurfaceWin::Initialize(gl::GLSurfaceFormat format) {
72 d3d11_device_ = gl::QueryD3D11DeviceObjectFromANGLE();
73 dcomp_device_ = gl::QueryDirectCompositionDevice(d3d11_device_);
74 if (!dcomp_device_)
75 return false;
76
77 EGLDisplay display = GetDisplay();
78
79 std::vector<EGLint> pbuffer_attribs;
80 pbuffer_attribs.push_back(EGL_WIDTH);
81 pbuffer_attribs.push_back(1);
82 pbuffer_attribs.push_back(EGL_HEIGHT);
83 pbuffer_attribs.push_back(1);
84
85 pbuffer_attribs.push_back(EGL_NONE);
86 default_surface_ =
87 eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]);
88 CHECK(!!default_surface_);
89
90 return true;
91 }
92
93 void DirectCompositionChildSurfaceWin::ReleaseCurrentSurface() {
94 ReleaseDrawTexture(true);
95 dcomp_surface_.Reset();
96 swap_chain_.Reset();
97 }
98
99 void DirectCompositionChildSurfaceWin::InitializeSurface() {
100 TRACE_EVENT1("gpu", "DirectCompositionChildSurfaceWin::InitializeSurface()",
101 "enable_dc_layers_", enable_dc_layers_);
102 DCHECK(!dcomp_surface_);
103 DCHECK(!swap_chain_);
104 DXGI_FORMAT output_format =
105 base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableHDR)
106 ? DXGI_FORMAT_R16G16B16A16_FLOAT
107 : DXGI_FORMAT_B8G8R8A8_UNORM;
108 if (enable_dc_layers_) {
109 // Always treat as premultiplied, because an underlay could cause it to
110 // become transparent.
111 HRESULT hr = dcomp_device_->CreateSurface(
112 size_.width(), size_.height(), output_format,
113 DXGI_ALPHA_MODE_PREMULTIPLIED, dcomp_surface_.GetAddressOf());
114 has_been_rendered_to_ = false;
115 CHECK(SUCCEEDED(hr));
116 } else {
117 DXGI_ALPHA_MODE alpha_mode =
118 has_alpha_ ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE;
119 base::win::ScopedComPtr<IDXGIDevice> dxgi_device;
120 d3d11_device_.CopyTo(dxgi_device.GetAddressOf());
121 base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter;
122 dxgi_device->GetAdapter(dxgi_adapter.GetAddressOf());
123 base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory;
124 dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.GetAddressOf()));
125
126 DXGI_SWAP_CHAIN_DESC1 desc = {};
127 desc.Width = size_.width();
128 desc.Height = size_.height();
129 desc.Format = output_format;
130 desc.Stereo = FALSE;
131 desc.SampleDesc.Count = 1;
132 desc.BufferCount = 2;
133 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
134 desc.Scaling = DXGI_SCALING_STRETCH;
135 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
136 desc.AlphaMode = alpha_mode;
137 desc.Flags = 0;
138 HRESULT hr = dxgi_factory->CreateSwapChainForComposition(
139 d3d11_device_.Get(), &desc, nullptr, swap_chain_.GetAddressOf());
140 has_been_rendered_to_ = false;
141 first_swap_ = true;
142 CHECK(SUCCEEDED(hr));
143 }
144 }
145
146 void DirectCompositionChildSurfaceWin::ReleaseDrawTexture(bool will_discard) {
147 if (real_surface_) {
148 eglDestroySurface(GetDisplay(), real_surface_);
149 real_surface_ = nullptr;
150 }
151 if (draw_texture_) {
152 draw_texture_.Reset();
153 if (dcomp_surface_) {
154 HRESULT hr = dcomp_surface_->EndDraw();
155 CHECK(SUCCEEDED(hr));
156 } else if (!will_discard) {
157 DXGI_PRESENT_PARAMETERS params = {};
158 RECT dirty_rect = swap_rect_.ToRECT();
159 params.DirtyRectsCount = 1;
160 params.pDirtyRects = &dirty_rect;
161 swap_chain_->Present1(first_swap_ ? 0 : 1, 0, &params);
162 if (first_swap_) {
163 // Wait for the GPU to finish executing its commands before
164 // committing the DirectComposition tree, or else the swapchain
165 // may flicker black when it's first presented.
166 base::win::ScopedComPtr<IDXGIDevice2> dxgi_device2;
167 HRESULT hr = d3d11_device_.CopyTo(dxgi_device2.GetAddressOf());
168 DCHECK(SUCCEEDED(hr));
169 base::WaitableEvent event(
170 base::WaitableEvent::ResetPolicy::AUTOMATIC,
171 base::WaitableEvent::InitialState::NOT_SIGNALED);
172 dxgi_device2->EnqueueSetEvent(event.handle());
173 event.Wait();
174 first_swap_ = false;
175 }
176 }
177 }
178 if (dcomp_surface_ == g_current_surface)
179 g_current_surface = nullptr;
180 }
181
182 void DirectCompositionChildSurfaceWin::Destroy() {
183 if (default_surface_) {
184 if (!eglDestroySurface(GetDisplay(), default_surface_)) {
185 DLOG(ERROR) << "eglDestroySurface failed with error "
186 << ui::GetLastEGLErrorString();
187 }
188 default_surface_ = nullptr;
189 }
190 if (real_surface_) {
191 if (!eglDestroySurface(GetDisplay(), real_surface_)) {
192 DLOG(ERROR) << "eglDestroySurface failed with error "
193 << ui::GetLastEGLErrorString();
194 }
195 real_surface_ = nullptr;
196 }
197 if (dcomp_surface_ && (dcomp_surface_ == g_current_surface)) {
198 HRESULT hr = dcomp_surface_->EndDraw();
199 CHECK(SUCCEEDED(hr));
200 g_current_surface = nullptr;
201 }
202 draw_texture_.Reset();
203 dcomp_surface_.Reset();
204 }
205
206 gfx::Size DirectCompositionChildSurfaceWin::GetSize() {
207 return size_;
208 }
209
210 bool DirectCompositionChildSurfaceWin::IsOffscreen() {
211 return false;
212 }
213
214 void* DirectCompositionChildSurfaceWin::GetHandle() {
215 return real_surface_ ? real_surface_ : default_surface_;
216 }
217
218 gfx::SwapResult DirectCompositionChildSurfaceWin::SwapBuffers() {
219 ReleaseDrawTexture(false);
220 return gfx::SwapResult::SWAP_ACK;
221 }
222
223 bool DirectCompositionChildSurfaceWin::FlipsVertically() const {
224 return true;
225 }
226
227 bool DirectCompositionChildSurfaceWin::SupportsPostSubBuffer() {
228 return true;
229 }
230
231 bool DirectCompositionChildSurfaceWin::OnMakeCurrent(gl::GLContext* context) {
232 if (g_current_surface != dcomp_surface_) {
233 if (g_current_surface) {
234 HRESULT hr = g_current_surface->SuspendDraw();
235 CHECK(SUCCEEDED(hr));
236 g_current_surface = nullptr;
237 }
238 if (draw_texture_) {
239 HRESULT hr = dcomp_surface_->ResumeDraw();
240 CHECK(SUCCEEDED(hr));
241 g_current_surface = dcomp_surface_.Get();
242 }
243 }
244 return true;
245 }
246
247 bool DirectCompositionChildSurfaceWin::SupportsDCLayers() const {
248 return true;
249 }
250
251 bool DirectCompositionChildSurfaceWin::SetDrawRectangle(
252 const gfx::Rect& rectangle) {
253 if (draw_texture_)
254 return false;
255 DCHECK(!real_surface_);
256 ScopedReleaseCurrent release_current(this);
257
258 if ((enable_dc_layers_ && !dcomp_surface_) ||
259 (!enable_dc_layers_ && !swap_chain_)) {
260 ReleaseCurrentSurface();
261 InitializeSurface();
262 }
263
264 if (!gfx::Rect(size_).Contains(rectangle)) {
265 DLOG(ERROR) << "Draw rectangle must be contained within size of surface";
266 return false;
267 }
268 if (gfx::Rect(size_) != rectangle && !has_been_rendered_to_) {
269 DLOG(ERROR) << "First draw to surface must draw to everything";
270 return false;
271 }
272
273 CHECK(!g_current_surface);
274
275 RECT rect = rectangle.ToRECT();
276 if (dcomp_surface_) {
277 POINT update_offset;
278 HRESULT hr = dcomp_surface_->BeginDraw(
279 &rect, IID_PPV_ARGS(draw_texture_.GetAddressOf()), &update_offset);
280 draw_offset_ = gfx::Point(update_offset) - gfx::Rect(rect).origin();
281 CHECK(SUCCEEDED(hr));
282 } else {
283 HRESULT hr =
284 swap_chain_->GetBuffer(0, IID_PPV_ARGS(draw_texture_.GetAddressOf()));
285 swap_rect_ = rectangle;
286 draw_offset_ = gfx::Vector2d();
287 CHECK(SUCCEEDED(hr));
288 }
289 has_been_rendered_to_ = true;
290
291 g_current_surface = dcomp_surface_.Get();
292
293 std::vector<EGLint> pbuffer_attribs{
294 EGL_WIDTH,
295 size_.width(),
296 EGL_HEIGHT,
297 size_.height(),
298 EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE,
299 EGL_TRUE,
300 EGL_NONE};
301
302 EGLClientBuffer buffer =
303 reinterpret_cast<EGLClientBuffer>(draw_texture_.Get());
304 real_surface_ = eglCreatePbufferFromClientBuffer(
305 GetDisplay(), EGL_D3D_TEXTURE_ANGLE, buffer, GetConfig(),
306 &pbuffer_attribs[0]);
307
308 return true;
309 }
310
311 gfx::Vector2d DirectCompositionChildSurfaceWin::GetDrawOffset() const {
312 return draw_offset_;
313 }
314
315 } // namespace gpu
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698