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