Chromium Code Reviews| 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 |