OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "ui/ozone/platform/drm/gpu/gbm_surfaceless.h" | 5 #include "ui/ozone/platform/drm/gpu/gbm_surfaceless.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/logging.h" |
9 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
| 12 #include "base/threading/worker_pool.h" |
10 #include "base/trace_event/trace_event.h" | 13 #include "base/trace_event/trace_event.h" |
11 #include "third_party/khronos/EGL/egl.h" | |
12 #include "ui/ozone/common/egl_util.h" | 14 #include "ui/ozone/common/egl_util.h" |
13 #include "ui/ozone/platform/drm/gpu/drm_device.h" | |
14 #include "ui/ozone/platform/drm/gpu/drm_vsync_provider.h" | 15 #include "ui/ozone/platform/drm/gpu/drm_vsync_provider.h" |
15 #include "ui/ozone/platform/drm/gpu/drm_window_proxy.h" | 16 #include "ui/ozone/platform/drm/gpu/drm_window_proxy.h" |
16 #include "ui/ozone/platform/drm/gpu/gbm_surface_factory.h" | 17 #include "ui/ozone/platform/drm/gpu/gbm_surface_factory.h" |
17 #include "ui/ozone/platform/drm/gpu/scanout_buffer.h" | 18 #include "ui/ozone/platform/drm/gpu/scanout_buffer.h" |
18 | 19 |
19 namespace ui { | 20 namespace ui { |
20 | 21 |
21 GbmSurfaceless::GbmSurfaceless(std::unique_ptr<DrmWindowProxy> window, | 22 namespace { |
22 GbmSurfaceFactory* surface_manager) | 23 |
23 : window_(std::move(window)), surface_manager_(surface_manager) { | 24 void WaitForFence(EGLDisplay display, EGLSyncKHR fence) { |
24 surface_manager_->RegisterSurface(window_->widget(), this); | 25 eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, |
25 } | 26 EGL_FOREVER_KHR); |
26 | 27 } |
27 GbmSurfaceless::~GbmSurfaceless() { | 28 |
28 surface_manager_->UnregisterSurface(window_->widget()); | 29 } // namespace |
| 30 |
| 31 GbmSurfaceless::GbmSurfaceless(GbmSurfaceFactory* surface_factory, |
| 32 std::unique_ptr<DrmWindowProxy> window, |
| 33 gfx::AcceleratedWidget widget) |
| 34 : SurfacelessEGL(gfx::Size()), |
| 35 surface_factory_(surface_factory), |
| 36 window_(std::move(window)), |
| 37 widget_(widget), |
| 38 has_implicit_external_sync_( |
| 39 HasEGLExtension("EGL_ARM_implicit_external_sync")), |
| 40 has_image_flush_external_( |
| 41 HasEGLExtension("EGL_EXT_image_flush_external")), |
| 42 weak_factory_(this) { |
| 43 surface_factory_->RegisterSurface(window_->widget(), this); |
| 44 unsubmitted_frames_.push_back(new PendingFrame()); |
29 } | 45 } |
30 | 46 |
31 void GbmSurfaceless::QueueOverlayPlane(const OverlayPlane& plane) { | 47 void GbmSurfaceless::QueueOverlayPlane(const OverlayPlane& plane) { |
32 planes_.push_back(plane); | 48 planes_.push_back(plane); |
33 } | 49 } |
34 | 50 |
35 intptr_t GbmSurfaceless::GetNativeWindow() { | 51 bool GbmSurfaceless::Initialize(gl::GLSurface::Format format) { |
| 52 if (!SurfacelessEGL::Initialize(format)) |
| 53 return false; |
| 54 vsync_provider_ = base::MakeUnique<DrmVSyncProvider>(window_.get()); |
| 55 if (!vsync_provider_) |
| 56 return false; |
| 57 return true; |
| 58 } |
| 59 |
| 60 gfx::SwapResult GbmSurfaceless::SwapBuffers() { |
36 NOTREACHED(); | 61 NOTREACHED(); |
37 return 0; | 62 return gfx::SwapResult::SWAP_FAILED; |
38 } | 63 } |
39 | 64 |
40 bool GbmSurfaceless::ResizeNativeWindow(const gfx::Size& viewport_size) { | 65 bool GbmSurfaceless::ScheduleOverlayPlane(int z_order, |
41 return true; | 66 gfx::OverlayTransform transform, |
42 } | 67 gl::GLImage* image, |
43 | 68 const gfx::Rect& bounds_rect, |
44 bool GbmSurfaceless::OnSwapBuffers() { | 69 const gfx::RectF& crop_rect) { |
| 70 unsubmitted_frames_.back()->overlays.push_back( |
| 71 gl::GLSurfaceOverlay(z_order, transform, image, bounds_rect, crop_rect)); |
| 72 return true; |
| 73 } |
| 74 |
| 75 bool GbmSurfaceless::IsOffscreen() { |
| 76 return false; |
| 77 } |
| 78 |
| 79 gfx::VSyncProvider* GbmSurfaceless::GetVSyncProvider() { |
| 80 return vsync_provider_.get(); |
| 81 } |
| 82 |
| 83 bool GbmSurfaceless::SupportsAsyncSwap() { |
| 84 return true; |
| 85 } |
| 86 |
| 87 bool GbmSurfaceless::SupportsPostSubBuffer() { |
| 88 return true; |
| 89 } |
| 90 |
| 91 gfx::SwapResult GbmSurfaceless::PostSubBuffer(int x, |
| 92 int y, |
| 93 int width, |
| 94 int height) { |
| 95 // The actual sub buffer handling is handled at higher layers. |
45 NOTREACHED(); | 96 NOTREACHED(); |
46 return false; | 97 return gfx::SwapResult::SWAP_FAILED; |
47 } | 98 } |
48 | 99 |
49 void GbmSurfaceless::OnSwapBuffersAsync( | 100 void GbmSurfaceless::SwapBuffersAsync(const SwapCompletionCallback& callback) { |
| 101 TRACE_EVENT0("drm", "GbmSurfaceless::SwapBuffersAsync"); |
| 102 // If last swap failed, don't try to schedule new ones. |
| 103 if (!last_swap_buffers_result_) { |
| 104 callback.Run(gfx::SwapResult::SWAP_FAILED); |
| 105 return; |
| 106 } |
| 107 |
| 108 glFlush(); |
| 109 unsubmitted_frames_.back()->Flush(); |
| 110 |
| 111 SwapCompletionCallback surface_swap_callback = base::Bind( |
| 112 &GbmSurfaceless::SwapCompleted, weak_factory_.GetWeakPtr(), callback); |
| 113 |
| 114 PendingFrame* frame = unsubmitted_frames_.back(); |
| 115 frame->callback = surface_swap_callback; |
| 116 unsubmitted_frames_.push_back(new PendingFrame()); |
| 117 |
| 118 // TODO: the following should be replaced by a per surface flush as it gets |
| 119 // implemented in GL drivers. |
| 120 if (has_implicit_external_sync_ || has_image_flush_external_) { |
| 121 EGLSyncKHR fence = InsertFence(has_implicit_external_sync_); |
| 122 if (!fence) { |
| 123 callback.Run(gfx::SwapResult::SWAP_FAILED); |
| 124 return; |
| 125 } |
| 126 |
| 127 base::Closure fence_wait_task = |
| 128 base::Bind(&WaitForFence, GetDisplay(), fence); |
| 129 |
| 130 base::Closure fence_retired_callback = |
| 131 base::Bind(&GbmSurfaceless::FenceRetired, weak_factory_.GetWeakPtr(), |
| 132 fence, frame); |
| 133 |
| 134 base::WorkerPool::PostTaskAndReply(FROM_HERE, fence_wait_task, |
| 135 fence_retired_callback, false); |
| 136 return; // Defer frame submission until fence signals. |
| 137 } |
| 138 |
| 139 frame->ready = true; |
| 140 SubmitFrame(); |
| 141 } |
| 142 |
| 143 void GbmSurfaceless::PostSubBufferAsync( |
| 144 int x, |
| 145 int y, |
| 146 int width, |
| 147 int height, |
50 const SwapCompletionCallback& callback) { | 148 const SwapCompletionCallback& callback) { |
51 TRACE_EVENT0("drm", "GbmSurfaceless::OnSwapBuffersAsync"); | 149 // The actual sub buffer handling is handled at higher layers. |
52 window_->SchedulePageFlip(planes_, callback); | 150 SwapBuffersAsync(callback); |
53 planes_.clear(); | 151 } |
54 } | 152 |
55 | 153 EGLConfig GbmSurfaceless::GetConfig() { |
56 std::unique_ptr<gfx::VSyncProvider> GbmSurfaceless::CreateVSyncProvider() { | 154 if (!config_) { |
57 return base::WrapUnique(new DrmVSyncProvider(window_.get())); | 155 EGLint config_attribs[] = {EGL_BUFFER_SIZE, |
| 156 32, |
| 157 EGL_ALPHA_SIZE, |
| 158 8, |
| 159 EGL_BLUE_SIZE, |
| 160 8, |
| 161 EGL_GREEN_SIZE, |
| 162 8, |
| 163 EGL_RED_SIZE, |
| 164 8, |
| 165 EGL_RENDERABLE_TYPE, |
| 166 EGL_OPENGL_ES2_BIT, |
| 167 EGL_SURFACE_TYPE, |
| 168 EGL_DONT_CARE, |
| 169 EGL_NONE}; |
| 170 config_ = ChooseEGLConfig(GetDisplay(), config_attribs); |
| 171 } |
| 172 return config_; |
| 173 } |
| 174 |
| 175 GbmSurfaceless::~GbmSurfaceless() { |
| 176 Destroy(); // The EGL surface must be destroyed before SurfaceOzone. |
| 177 surface_factory_->UnregisterSurface(window_->widget()); |
| 178 } |
| 179 |
| 180 GbmSurfaceless::PendingFrame::PendingFrame() {} |
| 181 |
| 182 GbmSurfaceless::PendingFrame::~PendingFrame() {} |
| 183 |
| 184 bool GbmSurfaceless::PendingFrame::ScheduleOverlayPlanes( |
| 185 gfx::AcceleratedWidget widget) { |
| 186 for (const auto& overlay : overlays) |
| 187 if (!overlay.ScheduleOverlayPlane(widget)) |
| 188 return false; |
| 189 return true; |
| 190 } |
| 191 |
| 192 void GbmSurfaceless::PendingFrame::Flush() { |
| 193 for (const auto& overlay : overlays) |
| 194 overlay.Flush(); |
| 195 } |
| 196 |
| 197 void GbmSurfaceless::SubmitFrame() { |
| 198 DCHECK(!unsubmitted_frames_.empty()); |
| 199 |
| 200 if (unsubmitted_frames_.front()->ready && !swap_buffers_pending_) { |
| 201 std::unique_ptr<PendingFrame> frame(unsubmitted_frames_.front()); |
| 202 unsubmitted_frames_.weak_erase(unsubmitted_frames_.begin()); |
| 203 swap_buffers_pending_ = true; |
| 204 |
| 205 if (!frame->ScheduleOverlayPlanes(widget_)) { |
| 206 // |callback| is a wrapper for SwapCompleted(). Call it to properly |
| 207 // propagate the failed state. |
| 208 frame->callback.Run(gfx::SwapResult::SWAP_FAILED); |
| 209 return; |
| 210 } |
| 211 |
| 212 if (IsUniversalDisplayLinkDevice()) |
| 213 glFinish(); |
| 214 |
| 215 window_->SchedulePageFlip(planes_, frame->callback); |
| 216 planes_.clear(); |
| 217 } |
| 218 } |
| 219 |
| 220 EGLSyncKHR GbmSurfaceless::InsertFence(bool implicit) { |
| 221 const EGLint attrib_list[] = {EGL_SYNC_CONDITION_KHR, |
| 222 EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM, |
| 223 EGL_NONE}; |
| 224 return eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR, |
| 225 implicit ? attrib_list : NULL); |
| 226 } |
| 227 |
| 228 void GbmSurfaceless::FenceRetired(EGLSyncKHR fence, PendingFrame* frame) { |
| 229 eglDestroySyncKHR(GetDisplay(), fence); |
| 230 frame->ready = true; |
| 231 SubmitFrame(); |
| 232 } |
| 233 |
| 234 void GbmSurfaceless::SwapCompleted(const SwapCompletionCallback& callback, |
| 235 gfx::SwapResult result) { |
| 236 callback.Run(result); |
| 237 swap_buffers_pending_ = false; |
| 238 if (result == gfx::SwapResult::SWAP_FAILED) { |
| 239 last_swap_buffers_result_ = false; |
| 240 return; |
| 241 } |
| 242 |
| 243 SubmitFrame(); |
58 } | 244 } |
59 | 245 |
60 bool GbmSurfaceless::IsUniversalDisplayLinkDevice() { | 246 bool GbmSurfaceless::IsUniversalDisplayLinkDevice() { |
61 return planes_.empty() ? false : planes_[0].buffer->RequiresGlFinish(); | 247 return planes_.empty() ? false : planes_[0].buffer->RequiresGlFinish(); |
62 } | 248 } |
63 | 249 |
64 void* /* EGLConfig */ GbmSurfaceless::GetEGLSurfaceConfig( | |
65 const EglConfigCallbacks& egl) { | |
66 EGLint config_attribs[] = {EGL_BUFFER_SIZE, | |
67 32, | |
68 EGL_ALPHA_SIZE, | |
69 8, | |
70 EGL_BLUE_SIZE, | |
71 8, | |
72 EGL_GREEN_SIZE, | |
73 8, | |
74 EGL_RED_SIZE, | |
75 8, | |
76 EGL_RENDERABLE_TYPE, | |
77 EGL_OPENGL_ES2_BIT, | |
78 EGL_SURFACE_TYPE, | |
79 EGL_DONT_CARE, | |
80 EGL_NONE}; | |
81 return ChooseEGLConfig(egl, config_attribs); | |
82 } | |
83 | |
84 } // namespace ui | 250 } // namespace ui |
OLD | NEW |