OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "gpu/ipc/service/direct_composition_surface_win.h" | 5 #include "gpu/ipc/service/direct_composition_surface_win.h" |
6 | 6 |
7 #include "base/optional.h" | |
7 #include "gpu/ipc/service/gpu_channel_manager.h" | 8 #include "gpu/ipc/service/gpu_channel_manager.h" |
8 #include "gpu/ipc/service/gpu_channel_manager_delegate.h" | 9 #include "gpu/ipc/service/gpu_channel_manager_delegate.h" |
9 #include "ui/gfx/native_widget_types.h" | 10 #include "ui/gfx/native_widget_types.h" |
10 #include "ui/gl/egl_util.h" | 11 #include "ui/gl/egl_util.h" |
12 #include "ui/gl/gl_angle_util_win.h" | |
11 #include "ui/gl/gl_context.h" | 13 #include "ui/gl/gl_context.h" |
12 #include "ui/gl/gl_surface_egl.h" | 14 #include "ui/gl/gl_surface_egl.h" |
15 #include "ui/gl/scoped_make_current.h" | |
16 | |
17 #ifndef EGL_ANGLE_flexible_surface_compatibility | |
18 #define EGL_ANGLE_flexible_surface_compatibility 1 | |
19 #define EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE 0x33A6 | |
20 #endif /* EGL_ANGLE_flexible_surface_compatibility */ | |
21 | |
22 #ifndef EGL_ANGLE_d3d_texture_client_buffer | |
23 #define EGL_ANGLE_d3d_texture_client_buffer 1 | |
24 #define EGL_D3D_TEXTURE_ANGLE 0x33A3 | |
25 #endif /* EGL_ANGLE_d3d_texture_client_buffer */ | |
13 | 26 |
14 namespace gpu { | 27 namespace gpu { |
28 namespace { | |
29 | |
30 // This class is used to make sure a specified surface isn't current, and upon | |
31 // destruction it will make the surface current again if it had been before. | |
32 class ScopedReleaseCurrent { | |
33 public: | |
34 explicit ScopedReleaseCurrent(gl::GLSurface* this_surface) { | |
35 gl::GLContext* current_context = gl::GLContext::GetCurrent(); | |
36 bool was_current = | |
37 current_context && current_context->IsCurrent(this_surface); | |
sunnyps
2017/01/28 01:33:59
nit: DCHECK(current_context->IsCurrent(this_surfac
| |
38 if (was_current) { | |
39 make_current_.emplace(current_context, this_surface); | |
40 current_context->ReleaseCurrent(this_surface); | |
41 } | |
42 } | |
43 | |
44 private: | |
45 base::Optional<ui::ScopedMakeCurrent> make_current_; | |
46 }; | |
47 | |
48 // Only one DirectComposition surface can be rendered into at a time. Track | |
49 // here which IDCompositionSurface is being rendered into. If another context | |
50 // is made current, then this surface will be suspended. | |
51 IDCompositionSurface* g_current_surface; | |
52 | |
53 } // namespace | |
15 | 54 |
16 DirectCompositionSurfaceWin::DirectCompositionSurfaceWin( | 55 DirectCompositionSurfaceWin::DirectCompositionSurfaceWin( |
17 base::WeakPtr<ImageTransportSurfaceDelegate> delegate, | 56 base::WeakPtr<ImageTransportSurfaceDelegate> delegate, |
18 HWND parent_window) | 57 HWND parent_window) |
19 : gl::GLSurfaceEGL(), | 58 : gl::GLSurfaceEGL(), |
20 child_window_(delegate, parent_window), | 59 child_window_(delegate, parent_window), |
21 window_(nullptr), | 60 window_(nullptr), |
22 surface_(0), | 61 default_surface_(0), |
62 real_surface_(0), | |
63 size_(1, 1), | |
23 first_swap_(true) {} | 64 first_swap_(true) {} |
24 | 65 |
25 bool DirectCompositionSurfaceWin::InitializeNativeWindow() { | 66 bool DirectCompositionSurfaceWin::InitializeNativeWindow() { |
26 if (window_) | 67 if (window_) |
27 return true; | 68 return true; |
28 | 69 |
29 bool result = child_window_.Initialize(); | 70 bool result = child_window_.Initialize(); |
30 window_ = child_window_.window(); | 71 window_ = child_window_.window(); |
31 return result; | 72 return result; |
32 } | 73 } |
33 | 74 |
34 bool DirectCompositionSurfaceWin::Initialize(gl::GLSurfaceFormat format) { | 75 bool DirectCompositionSurfaceWin::Initialize(gl::GLSurfaceFormat format) { |
76 d3d11_device_ = gl::QueryD3D11DeviceObjectFromANGLE(); | |
77 dcomp_device_ = gl::QueryDirectCompositionDevice(d3d11_device_); | |
78 if (!dcomp_device_) | |
79 return false; | |
80 | |
35 EGLDisplay display = GetDisplay(); | 81 EGLDisplay display = GetDisplay(); |
36 if (!window_) { | 82 if (!window_) { |
37 if (!InitializeNativeWindow()) { | 83 if (!InitializeNativeWindow()) { |
38 LOG(ERROR) << "Failed to initialize native window"; | 84 LOG(ERROR) << "Failed to initialize native window"; |
39 return false; | 85 return false; |
40 } | 86 } |
41 } | 87 } |
88 | |
89 base::win::ScopedComPtr<IDCompositionDesktopDevice> desktop_device; | |
90 dcomp_device_.QueryInterface(desktop_device.Receive()); | |
91 | |
92 HRESULT hr = desktop_device->CreateTargetForHwnd(window_, TRUE, | |
93 dcomp_target_.Receive()); | |
94 if (FAILED(hr)) | |
95 return false; | |
96 | |
97 hr = dcomp_device_->CreateVisual(visual_.Receive()); | |
98 if (FAILED(hr)) | |
99 return false; | |
100 | |
101 dcomp_target_->SetRoot(visual_.get()); | |
102 | |
42 std::vector<EGLint> pbuffer_attribs; | 103 std::vector<EGLint> pbuffer_attribs; |
43 pbuffer_attribs.push_back(EGL_WIDTH); | 104 pbuffer_attribs.push_back(EGL_WIDTH); |
44 pbuffer_attribs.push_back(1); | 105 pbuffer_attribs.push_back(1); |
45 pbuffer_attribs.push_back(EGL_HEIGHT); | 106 pbuffer_attribs.push_back(EGL_HEIGHT); |
46 pbuffer_attribs.push_back(1); | 107 pbuffer_attribs.push_back(1); |
47 | 108 |
48 pbuffer_attribs.push_back(EGL_NONE); | 109 pbuffer_attribs.push_back(EGL_NONE); |
49 surface_ = eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]); | 110 default_surface_ = |
50 CHECK(!!surface_); | 111 eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]); |
112 CHECK(!!default_surface_); | |
113 | |
114 InitializeSurface(); | |
51 | 115 |
52 return true; | 116 return true; |
53 } | 117 } |
54 | 118 |
55 void DirectCompositionSurfaceWin::Destroy() { | 119 void DirectCompositionSurfaceWin::Destroy() { |
56 if (surface_) { | 120 if (default_surface_) { |
57 if (!eglDestroySurface(GetDisplay(), surface_)) { | 121 if (!eglDestroySurface(GetDisplay(), default_surface_)) { |
58 LOG(ERROR) << "eglDestroySurface failed with error " | 122 LOG(ERROR) << "eglDestroySurface failed with error " |
59 << ui::GetLastEGLErrorString(); | 123 << ui::GetLastEGLErrorString(); |
60 } | 124 } |
61 surface_ = NULL; | 125 default_surface_ = NULL; |
62 } | 126 } |
127 if (real_surface_) { | |
128 if (!eglDestroySurface(GetDisplay(), real_surface_)) { | |
129 LOG(ERROR) << "eglDestroySurface failed with error " | |
130 << ui::GetLastEGLErrorString(); | |
131 } | |
132 real_surface_ = NULL; | |
133 } | |
134 if (dcomp_surface_ == g_current_surface) | |
135 g_current_surface = nullptr; | |
136 draw_texture_.Release(); | |
137 dcomp_surface_.Release(); | |
63 } | 138 } |
64 | 139 |
65 gfx::Size DirectCompositionSurfaceWin::GetSize() { | 140 gfx::Size DirectCompositionSurfaceWin::GetSize() { |
66 return size_; | 141 return size_; |
67 } | 142 } |
68 | 143 |
69 bool DirectCompositionSurfaceWin::IsOffscreen() { | 144 bool DirectCompositionSurfaceWin::IsOffscreen() { |
70 return false; | 145 return false; |
71 } | 146 } |
72 | 147 |
73 void* DirectCompositionSurfaceWin::GetHandle() { | 148 void* DirectCompositionSurfaceWin::GetHandle() { |
74 return surface_; | 149 return real_surface_ ? real_surface_ : default_surface_; |
75 } | 150 } |
76 | 151 |
77 bool DirectCompositionSurfaceWin::Resize(const gfx::Size& size, | 152 bool DirectCompositionSurfaceWin::Resize(const gfx::Size& size, |
78 float scale_factor, | 153 float scale_factor, |
79 bool has_alpha) { | 154 bool has_alpha) { |
80 if (size == GetSize()) | 155 if (size == GetSize()) |
81 return true; | 156 return true; |
82 | 157 |
83 // Force a resize and redraw (but not a move, activate, etc.). | 158 // Force a resize and redraw (but not a move, activate, etc.). |
84 if (!SetWindowPos(window_, nullptr, 0, 0, size.width(), size.height(), | 159 if (!SetWindowPos(window_, nullptr, 0, 0, size.width(), size.height(), |
85 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS | | 160 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS | |
86 SWP_NOOWNERZORDER | SWP_NOZORDER)) { | 161 SWP_NOOWNERZORDER | SWP_NOZORDER)) { |
87 return false; | 162 return false; |
88 } | 163 } |
89 size_ = size; | 164 size_ = size; |
165 InitializeSurface(); | |
166 | |
90 return true; | 167 return true; |
91 } | 168 } |
92 | 169 |
93 gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers() { | 170 gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers() { |
94 CommitAndClearPendingOverlays(); | 171 { |
172 ScopedReleaseCurrent release_current(this); | |
173 ReleaseDrawTexture(); | |
174 visual_->SetContent(dcomp_surface_.get()); | |
175 | |
176 CommitAndClearPendingOverlays(); | |
177 dcomp_device_->Commit(); | |
178 } | |
95 // Force the driver to finish drawing before clearing the contents to | 179 // Force the driver to finish drawing before clearing the contents to |
96 // transparent, to reduce or eliminate the period of time where the contents | 180 // transparent, to reduce or eliminate the period of time where the contents |
97 // have flashed black. | 181 // have flashed black. |
98 if (first_swap_) { | 182 if (first_swap_) { |
99 glFinish(); | 183 glFinish(); |
100 first_swap_ = false; | 184 first_swap_ = false; |
101 } | 185 } |
102 child_window_.ClearInvalidContents(); | 186 child_window_.ClearInvalidContents(); |
103 return gfx::SwapResult::SWAP_ACK; | 187 return gfx::SwapResult::SWAP_ACK; |
104 } | 188 } |
105 | 189 |
106 gfx::SwapResult DirectCompositionSurfaceWin::PostSubBuffer(int x, | 190 gfx::SwapResult DirectCompositionSurfaceWin::PostSubBuffer(int x, |
107 int y, | 191 int y, |
108 int width, | 192 int width, |
109 int height) { | 193 int height) { |
194 ScopedReleaseCurrent release_current(this); | |
195 ReleaseDrawTexture(); | |
196 visual_->SetContent(dcomp_surface_.get()); | |
110 CommitAndClearPendingOverlays(); | 197 CommitAndClearPendingOverlays(); |
198 dcomp_device_->Commit(); | |
111 child_window_.ClearInvalidContents(); | 199 child_window_.ClearInvalidContents(); |
112 return gfx::SwapResult::SWAP_ACK; | 200 return gfx::SwapResult::SWAP_ACK; |
113 } | 201 } |
114 | 202 |
115 gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() { | 203 gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() { |
116 return vsync_provider_.get(); | 204 return vsync_provider_.get(); |
117 } | 205 } |
118 | 206 |
119 bool DirectCompositionSurfaceWin::Initialize( | 207 bool DirectCompositionSurfaceWin::Initialize( |
120 std::unique_ptr<gfx::VSyncProvider> vsync_provider) { | 208 std::unique_ptr<gfx::VSyncProvider> vsync_provider) { |
121 vsync_provider_ = std::move(vsync_provider); | 209 vsync_provider_ = std::move(vsync_provider); |
122 return Initialize(gl::GLSurfaceFormat()); | 210 return Initialize(gl::GLSurfaceFormat()); |
123 } | 211 } |
124 | 212 |
125 bool DirectCompositionSurfaceWin::ScheduleOverlayPlane( | 213 bool DirectCompositionSurfaceWin::ScheduleOverlayPlane( |
126 int z_order, | 214 int z_order, |
127 gfx::OverlayTransform transform, | 215 gfx::OverlayTransform transform, |
128 gl::GLImage* image, | 216 gl::GLImage* image, |
129 const gfx::Rect& bounds_rect, | 217 const gfx::Rect& bounds_rect, |
130 const gfx::RectF& crop_rect) { | 218 const gfx::RectF& crop_rect) { |
131 pending_overlays_.push_back( | 219 pending_overlays_.push_back( |
132 Overlay(z_order, transform, image, bounds_rect, crop_rect)); | 220 Overlay(z_order, transform, image, bounds_rect, crop_rect)); |
133 return true; | 221 return true; |
134 } | 222 } |
135 | 223 |
224 bool DirectCompositionSurfaceWin::FlipsVertically() const { | |
225 return true; | |
226 } | |
227 | |
136 bool DirectCompositionSurfaceWin::SupportsPostSubBuffer() { | 228 bool DirectCompositionSurfaceWin::SupportsPostSubBuffer() { |
137 return true; | 229 return true; |
138 } | 230 } |
139 | 231 |
232 bool DirectCompositionSurfaceWin::OnMakeCurrent(gl::GLContext* context) { | |
233 if (g_current_surface != dcomp_surface_) { | |
234 if (g_current_surface) { | |
235 HRESULT hr = g_current_surface->SuspendDraw(); | |
236 CHECK(SUCCEEDED(hr)); | |
237 g_current_surface = nullptr; | |
238 } | |
239 if (draw_texture_) { | |
240 HRESULT hr = dcomp_surface_->ResumeDraw(); | |
241 CHECK(SUCCEEDED(hr)); | |
242 g_current_surface = dcomp_surface_.get(); | |
243 } | |
244 } | |
245 return true; | |
246 } | |
247 | |
248 bool DirectCompositionSurfaceWin::SupportsSetDrawRectangle() const { | |
249 return true; | |
250 } | |
251 | |
252 bool DirectCompositionSurfaceWin::SetDrawRectangle(const gfx::Rect& rectangle) { | |
253 if (draw_texture_) | |
254 return false; | |
255 if (!gfx::Rect(size_).Contains(rectangle)) { | |
256 LOG(ERROR) << "Draw rectangle must be contained within size of surface"; | |
257 return false; | |
258 } | |
259 if (gfx::Rect(size_) != rectangle && !has_been_rendered_to_) { | |
260 LOG(ERROR) << "First draw to surface must draw to everything"; | |
261 return false; | |
262 } | |
263 | |
264 DCHECK(!real_surface_); | |
265 CHECK(!g_current_surface); | |
266 ScopedReleaseCurrent release_current(this); | |
267 | |
268 RECT rect = rectangle.ToRECT(); | |
269 // TODO(jbauman): Use update_offset | |
270 POINT update_offset; | |
271 | |
272 HRESULT hr = dcomp_surface_->BeginDraw( | |
273 &rect, IID_PPV_ARGS(draw_texture_.Receive()), &update_offset); | |
274 CHECK(SUCCEEDED(hr)); | |
275 has_been_rendered_to_ = true; | |
276 | |
277 g_current_surface = dcomp_surface_.get(); | |
278 | |
279 std::vector<EGLint> pbuffer_attribs; | |
280 pbuffer_attribs.push_back(EGL_WIDTH); | |
281 pbuffer_attribs.push_back(size_.width()); | |
282 pbuffer_attribs.push_back(EGL_HEIGHT); | |
283 pbuffer_attribs.push_back(size_.height()); | |
284 pbuffer_attribs.push_back(EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE); | |
285 pbuffer_attribs.push_back(EGL_TRUE); | |
286 pbuffer_attribs.push_back(EGL_NONE); | |
287 | |
288 EGLClientBuffer buffer = | |
289 reinterpret_cast<EGLClientBuffer>(draw_texture_.get()); | |
290 real_surface_ = eglCreatePbufferFromClientBuffer( | |
291 GetDisplay(), EGL_D3D_TEXTURE_ANGLE, buffer, GetConfig(), | |
292 &pbuffer_attribs[0]); | |
293 | |
294 return true; | |
295 } | |
296 | |
140 DirectCompositionSurfaceWin::Overlay::Overlay(int z_order, | 297 DirectCompositionSurfaceWin::Overlay::Overlay(int z_order, |
141 gfx::OverlayTransform transform, | 298 gfx::OverlayTransform transform, |
142 scoped_refptr<gl::GLImage> image, | 299 scoped_refptr<gl::GLImage> image, |
143 gfx::Rect bounds_rect, | 300 gfx::Rect bounds_rect, |
144 gfx::RectF crop_rect) | 301 gfx::RectF crop_rect) |
145 : z_order(z_order), | 302 : z_order(z_order), |
146 transform(transform), | 303 transform(transform), |
147 image(image), | 304 image(image), |
148 bounds_rect(bounds_rect), | 305 bounds_rect(bounds_rect), |
149 crop_rect(crop_rect) {} | 306 crop_rect(crop_rect) {} |
150 | 307 |
151 DirectCompositionSurfaceWin::Overlay::Overlay(const Overlay& overlay) = default; | 308 DirectCompositionSurfaceWin::Overlay::Overlay(const Overlay& overlay) = default; |
152 | 309 |
153 DirectCompositionSurfaceWin::Overlay::~Overlay() {} | 310 DirectCompositionSurfaceWin::Overlay::~Overlay() {} |
154 | 311 |
155 bool DirectCompositionSurfaceWin::CommitAndClearPendingOverlays() { | 312 bool DirectCompositionSurfaceWin::CommitAndClearPendingOverlays() { |
sunnyps
2017/01/28 01:33:58
nit: Can you move this next to ScheduleOverlayPlan
| |
156 pending_overlays_.clear(); | 313 pending_overlays_.clear(); |
157 return true; | 314 return true; |
158 } | 315 } |
159 | 316 |
160 DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin() {} | 317 void DirectCompositionSurfaceWin::InitializeSurface() { |
sunnyps
2017/01/28 01:33:59
nit: can you move this and ReleaseDrawTexture next
| |
318 ScopedReleaseCurrent release_current(this); | |
319 ReleaseDrawTexture(); | |
320 dcomp_surface_.Release(); | |
321 HRESULT hr = dcomp_device_->CreateSurface( | |
322 size_.width(), size_.height(), DXGI_FORMAT_B8G8R8A8_UNORM, | |
323 DXGI_ALPHA_MODE_PREMULTIPLIED, dcomp_surface_.Receive()); | |
324 has_been_rendered_to_ = false; | |
325 | |
326 CHECK(SUCCEEDED(hr)); | |
327 } | |
328 | |
329 void DirectCompositionSurfaceWin::ReleaseDrawTexture() { | |
330 if (real_surface_) { | |
331 eglDestroySurface(GetDisplay(), real_surface_); | |
332 real_surface_ = nullptr; | |
333 } | |
334 if (draw_texture_) { | |
335 draw_texture_.Release(); | |
336 HRESULT hr = dcomp_surface_->EndDraw(); | |
337 CHECK(SUCCEEDED(hr)); | |
338 } | |
339 if (dcomp_surface_ == g_current_surface) | |
340 g_current_surface = nullptr; | |
341 } | |
342 | |
343 DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin() { | |
sunnyps
2017/01/28 01:33:59
nit: can you move this next to the ctor?
| |
344 Destroy(); | |
345 } | |
161 | 346 |
162 } // namespace gpu | 347 } // namespace gpu |
OLD | NEW |