Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 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 "ash/laser/laser_pointer_view.h" | 5 #include "ash/laser/laser_pointer_view.h" |
| 6 | 6 |
| 7 #include <GLES2/gl2.h> | |
| 8 #include <GLES2/gl2ext.h> | |
| 9 #include <GLES2/gl2extchromium.h> | |
| 10 | |
| 7 #include <memory> | 11 #include <memory> |
| 8 | 12 |
| 9 #include "ash/laser/laser_pointer_points.h" | 13 #include "ash/laser/laser_pointer_points.h" |
| 10 #include "ash/laser/laser_segment_utils.h" | 14 #include "ash/laser/laser_segment_utils.h" |
| 11 #include "ash/public/cpp/shell_window_ids.h" | 15 #include "ash/public/cpp/shell_window_ids.h" |
| 12 #include "ash/shell.h" | 16 #include "ash/shell.h" |
| 17 #include "base/threading/thread_task_runner_handle.h" | |
| 13 #include "base/timer/timer.h" | 18 #include "base/timer/timer.h" |
| 19 #include "base/trace_event/trace_event.h" | |
| 20 #include "cc/output/context_provider.h" | |
| 21 #include "cc/quads/texture_draw_quad.h" | |
| 22 #include "cc/resources/transferable_resource.h" | |
| 23 #include "cc/surfaces/surface.h" | |
| 24 #include "cc/surfaces/surface_manager.h" | |
| 25 #include "gpu/command_buffer/client/context_support.h" | |
| 26 #include "gpu/command_buffer/client/gles2_interface.h" | |
| 27 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" | |
| 14 #include "third_party/skia/include/core/SkColor.h" | 28 #include "third_party/skia/include/core/SkColor.h" |
| 29 #include "third_party/skia/include/core/SkTypes.h" | |
| 30 #include "ui/aura/env.h" | |
| 15 #include "ui/aura/window.h" | 31 #include "ui/aura/window.h" |
| 32 #include "ui/display/display.h" | |
| 33 #include "ui/display/screen.h" | |
| 16 #include "ui/events/event.h" | 34 #include "ui/events/event.h" |
| 17 #include "ui/gfx/canvas.h" | 35 #include "ui/gfx/canvas.h" |
| 36 #include "ui/gfx/gpu_memory_buffer.h" | |
| 18 #include "ui/views/widget/widget.h" | 37 #include "ui/views/widget/widget.h" |
| 19 | 38 |
| 20 namespace ash { | 39 namespace ash { |
| 21 namespace { | 40 namespace { |
| 22 | 41 |
| 23 // Variables for rendering the laser. Radius in DIP. | 42 // Variables for rendering the laser. Radius in DIP. |
| 24 const float kPointInitialRadius = 5.0f; | 43 const float kPointInitialRadius = 5.0f; |
| 25 const float kPointFinalRadius = 0.25f; | 44 const float kPointFinalRadius = 0.25f; |
| 26 const int kPointInitialOpacity = 200; | 45 const int kPointInitialOpacity = 200; |
| 27 const int kPointFinalOpacity = 10; | 46 const int kPointFinalOpacity = 10; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 150 SkPath path() const { return path_; } | 169 SkPath path() const { return path_; } |
| 151 std::vector<gfx::PointF> path_points() const { return path_points_; } | 170 std::vector<gfx::PointF> path_points() const { return path_points_; } |
| 152 | 171 |
| 153 private: | 172 private: |
| 154 SkPath path_; | 173 SkPath path_; |
| 155 std::vector<gfx::PointF> path_points_; | 174 std::vector<gfx::PointF> path_points_; |
| 156 | 175 |
| 157 DISALLOW_COPY_AND_ASSIGN(LaserSegment); | 176 DISALLOW_COPY_AND_ASSIGN(LaserSegment); |
| 158 }; | 177 }; |
| 159 | 178 |
| 179 // This struct contains the resources associated with a laser pointer frame. | |
| 180 struct LaserResource { | |
| 181 LaserResource() {} | |
| 182 ~LaserResource() { | |
| 183 if (context_provider) { | |
| 184 gpu::gles2::GLES2Interface* gles2 = context_provider->ContextGL(); | |
| 185 if (texture) | |
| 186 gles2->DeleteTextures(1, &texture); | |
| 187 if (image) | |
| 188 gles2->DestroyImageCHROMIUM(image); | |
| 189 } | |
| 190 } | |
| 191 scoped_refptr<cc::ContextProvider> context_provider; | |
| 192 uint32_t texture = 0; | |
| 193 uint32_t image = 0; | |
| 194 gpu::Mailbox mailbox; | |
| 195 }; | |
| 196 | |
| 160 // LaserPointerView | 197 // LaserPointerView |
| 161 LaserPointerView::LaserPointerView(base::TimeDelta life_duration, | 198 LaserPointerView::LaserPointerView(base::TimeDelta life_duration, |
| 162 aura::Window* root_window) | 199 aura::Window* root_window) |
| 163 : laser_points_(life_duration) { | 200 : laser_points_(life_duration), |
| 201 frame_sink_id_(aura::Env::GetInstance() | |
| 202 ->context_factory_private() | |
| 203 ->AllocateFrameSinkId()), | |
| 204 frame_sink_support_(this, | |
| 205 aura::Env::GetInstance() | |
| 206 ->context_factory_private() | |
| 207 ->GetSurfaceManager(), | |
| 208 frame_sink_id_, | |
| 209 false /* is_root */, | |
| 210 true /* handles_frame_sink_id_invalidation */, | |
| 211 true /* needs_sync_points */), | |
| 212 weak_ptr_factory_(this) { | |
| 164 widget_.reset(new views::Widget); | 213 widget_.reset(new views::Widget); |
| 165 views::Widget::InitParams params; | 214 views::Widget::InitParams params; |
| 166 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; | 215 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; |
| 167 params.name = "LaserOverlay"; | 216 params.name = "LaserOverlay"; |
| 168 params.accept_events = false; | 217 params.accept_events = false; |
| 169 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; | 218 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; |
| 170 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 219 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| 171 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | 220 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
| 172 params.parent = | 221 params.parent = |
| 173 Shell::GetContainer(root_window, kShellWindowId_OverlayContainer); | 222 Shell::GetContainer(root_window, kShellWindowId_OverlayContainer); |
| 223 params.layer_type = ui::LAYER_SOLID_COLOR; | |
| 174 | 224 |
| 175 widget_->Init(params); | 225 widget_->Init(params); |
| 176 widget_->Show(); | 226 widget_->Show(); |
| 177 widget_->SetContentsView(this); | 227 widget_->SetContentsView(this); |
| 228 widget_->SetBounds(root_window->GetBoundsInScreen()); | |
| 178 set_owned_by_client(); | 229 set_owned_by_client(); |
| 230 | |
| 231 scale_factor_ = display::Screen::GetScreen() | |
| 232 ->GetDisplayNearestWindow(widget_->GetNativeView()) | |
| 233 .device_scale_factor(); | |
| 179 } | 234 } |
| 180 | 235 |
| 181 LaserPointerView::~LaserPointerView() {} | 236 LaserPointerView::~LaserPointerView() { |
| 237 // Make sure GPU memory buffer is unmapped before being destroyed. | |
| 238 if (gpu_memory_buffer_) | |
| 239 gpu_memory_buffer_->Unmap(); | |
| 240 } | |
| 182 | 241 |
| 183 void LaserPointerView::Stop() { | 242 void LaserPointerView::Stop() { |
| 243 buffer_damage_rect_.Union(GetBoundingBox()); | |
| 184 laser_points_.Clear(); | 244 laser_points_.Clear(); |
| 185 SchedulePaint(); | 245 OnPointsUpdated(); |
| 186 } | 246 } |
| 187 | 247 |
| 188 void LaserPointerView::AddNewPoint(const gfx::Point& new_point) { | 248 void LaserPointerView::AddNewPoint(const gfx::Point& new_point) { |
| 249 buffer_damage_rect_.Union(GetBoundingBox()); | |
| 189 laser_points_.AddPoint(new_point); | 250 laser_points_.AddPoint(new_point); |
| 251 buffer_damage_rect_.Union(GetBoundingBox()); | |
| 190 OnPointsUpdated(); | 252 OnPointsUpdated(); |
| 191 } | 253 } |
| 192 | 254 |
| 193 void LaserPointerView::UpdateTime() { | 255 void LaserPointerView::UpdateTime() { |
| 256 buffer_damage_rect_.Union(GetBoundingBox()); | |
| 194 // Do not add the point but advance the time if the view is in process of | 257 // Do not add the point but advance the time if the view is in process of |
| 195 // fading away. | 258 // fading away. |
| 196 laser_points_.MoveForwardToTime(base::Time::Now()); | 259 laser_points_.MoveForwardToTime(base::Time::Now()); |
| 260 buffer_damage_rect_.Union(GetBoundingBox()); | |
| 197 OnPointsUpdated(); | 261 OnPointsUpdated(); |
| 198 } | 262 } |
| 199 | 263 |
| 200 void LaserPointerView::OnPointsUpdated() { | 264 void LaserPointerView::SetNeedsBeginFrame(bool needs_begin_frame) { |
| 201 // The bounding box should be relative to the screen. | 265 frame_sink_support_.SetNeedsBeginFrame(needs_begin_frame); |
| 202 gfx::Point screen_offset = | |
| 203 widget_->GetNativeView()->GetRootWindow()->GetBoundsInScreen().origin(); | |
| 204 | |
| 205 // Expand the bounding box so that it includes the radius of the points on the | |
| 206 // edges. | |
| 207 gfx::Rect bounding_box; | |
| 208 bounding_box = laser_points_.GetBoundingBox(); | |
| 209 bounding_box.Offset(-kPointInitialRadius, -kPointInitialRadius); | |
| 210 bounding_box.Offset(screen_offset.x(), screen_offset.y()); | |
| 211 bounding_box.set_width(bounding_box.width() + (kPointInitialRadius * 2)); | |
| 212 bounding_box.set_height(bounding_box.height() + (kPointInitialRadius * 2)); | |
| 213 widget_->SetBounds(bounding_box); | |
| 214 SchedulePaint(); | |
| 215 } | 266 } |
| 216 | 267 |
| 217 void LaserPointerView::OnPaint(gfx::Canvas* canvas) { | 268 void LaserPointerView::SubmitCompositorFrame( |
| 218 if (laser_points_.IsEmpty()) | 269 const cc::LocalSurfaceId& local_surface_id, |
| 270 cc::CompositorFrame frame) { | |
| 271 frame_sink_support_.SubmitCompositorFrame(local_surface_id, std::move(frame)); | |
| 272 } | |
| 273 | |
| 274 void LaserPointerView::EvictFrame() { | |
| 275 frame_sink_support_.EvictFrame(); | |
| 276 } | |
| 277 | |
| 278 void LaserPointerView::Require(const cc::LocalSurfaceId& local_surface_id, | |
| 279 const cc::SurfaceSequence& sequence) { | |
| 280 frame_sink_support_.Require(local_surface_id, sequence); | |
| 281 } | |
| 282 | |
| 283 void LaserPointerView::Satisfy(const cc::SurfaceSequence& sequence) { | |
| 284 frame_sink_support_.Satisfy(sequence); | |
| 285 } | |
| 286 | |
| 287 void LaserPointerView::ReclaimResources( | |
| 288 const cc::ReturnedResourceArray& resources) { | |
| 289 DCHECK_EQ(resources.size(), 1u); | |
| 290 | |
| 291 auto it = resources_.find(resources.front().id); | |
| 292 DCHECK(it != resources_.end()); | |
| 293 std::unique_ptr<LaserResource> resource = std::move(it->second); | |
| 294 resources_.erase(it); | |
| 295 | |
| 296 gpu::gles2::GLES2Interface* gles2 = resource->context_provider->ContextGL(); | |
| 297 if (resources.front().sync_token.HasData()) | |
| 298 gles2->WaitSyncTokenCHROMIUM(resources.front().sync_token.GetConstData()); | |
| 299 | |
| 300 if (!resources.front().lost) | |
| 301 returned_resources_.push_back(std::move(resource)); | |
| 302 } | |
| 303 | |
| 304 void LaserPointerView::WillDrawSurface( | |
| 305 const cc::LocalSurfaceId& local_surface_id, | |
| 306 const gfx::Rect& damage_rect) { | |
|
jbauman
2017/03/01 01:12:01
On think this should be triggered by DidReceiveCom
reveman
2017/03/01 18:57:15
Done. Will throttle frames more aggressively. This
| |
| 307 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 308 FROM_HERE, base::Bind(&LaserPointerView::OnDidDrawSurface, | |
| 309 weak_ptr_factory_.GetWeakPtr())); | |
| 310 ; | |
| 311 } | |
| 312 | |
| 313 gfx::Rect LaserPointerView::GetBoundingBox() { | |
| 314 // Expand the bounding box so that it includes the radius of the points on the | |
| 315 // edges and antialiasing. | |
| 316 gfx::Rect bounding_box = laser_points_.GetBoundingBox(); | |
| 317 const int kOutsetForAntialiasing = 1; | |
| 318 int outset = kPointInitialRadius + kOutsetForAntialiasing; | |
| 319 bounding_box.Inset(-outset, -outset); | |
| 320 return bounding_box; | |
| 321 } | |
| 322 | |
| 323 void LaserPointerView::OnPointsUpdated() { | |
| 324 if (pending_update_buffer_) | |
| 219 return; | 325 return; |
| 220 | 326 |
| 327 pending_update_buffer_ = true; | |
| 328 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 329 FROM_HERE, base::Bind(&LaserPointerView::UpdateBuffer, | |
| 330 weak_ptr_factory_.GetWeakPtr())); | |
| 331 } | |
| 332 | |
| 333 void LaserPointerView::UpdateBuffer() { | |
| 334 TRACE_EVENT2("ui", "LaserPointerView::UpdatedBuffer", "damage", | |
| 335 buffer_damage_rect_.ToString(), "points", | |
| 336 laser_points_.GetNumberOfPoints()); | |
| 337 | |
| 338 DCHECK(pending_update_buffer_); | |
| 339 pending_update_buffer_ = false; | |
| 340 | |
| 341 gfx::Rect screen_bounds = widget_->GetNativeView()->GetBoundsInScreen(); | |
| 342 gfx::Rect update_rect = buffer_damage_rect_; | |
| 343 buffer_damage_rect_ = gfx::Rect(); | |
| 344 | |
| 345 // Create and map a single GPU memory buffer. The laser pointer will be | |
| 346 // written into this buffer without any buffering. The result is that we | |
| 347 // might be modifying the buffer while it's being displayed. This provides | |
| 348 // minimal latency but potential tearing. Note that we have to draw into | |
| 349 // a temporary surface and copy it into GPU memory buffer to avoid flicker. | |
| 350 if (!gpu_memory_buffer_) { | |
| 351 gpu_memory_buffer_ = | |
| 352 aura::Env::GetInstance() | |
| 353 ->context_factory() | |
| 354 ->GetGpuMemoryBufferManager() | |
|
jbauman
2017/03/01 01:12:01
I think we need to listen to ContextFactoryObserve
reveman
2017/03/01 18:57:15
GpuMemoryBuffers survive GPU process crashes. The
| |
| 355 ->CreateGpuMemoryBuffer( | |
| 356 gfx::ScaleToCeiledSize(screen_bounds.size(), scale_factor_), | |
| 357 SK_B32_SHIFT ? gfx::BufferFormat::RGBA_8888 | |
| 358 : gfx::BufferFormat::BGRA_8888, | |
| 359 gfx::BufferUsage::SCANOUT_CPU_READ_WRITE, | |
| 360 gpu::kNullSurfaceHandle); | |
| 361 if (!gpu_memory_buffer_) { | |
| 362 LOG(ERROR) << "Failed to allocate GPU memory buffer"; | |
| 363 return; | |
| 364 } | |
| 365 | |
| 366 // Map buffer and keep it mapped until destroyed. | |
| 367 bool rv = gpu_memory_buffer_->Map(); | |
| 368 if (!rv) { | |
| 369 LOG(ERROR) << "Failed to map GPU memory buffer"; | |
| 370 return; | |
| 371 } | |
| 372 | |
| 373 // Make sure the first update rectangle covers the whole buffer. | |
| 374 update_rect = gfx::Rect(screen_bounds.size()); | |
| 375 } | |
| 376 | |
| 377 // Constrain update rectangle to buffer size and early out if empty. | |
| 378 update_rect.Intersect(gfx::Rect(screen_bounds.size())); | |
| 379 if (update_rect.IsEmpty()) | |
| 380 return; | |
| 381 | |
| 382 // Create a temporary canvas for update rectangle. | |
| 383 gfx::Canvas canvas(update_rect.size(), scale_factor_, false); | |
|
jbauman
2017/03/01 01:12:01
You might want to have a cache for this to avoid t
reveman
2017/03/01 18:57:15
I considered that but with a good system allocator
| |
| 384 | |
| 221 cc::PaintFlags flags; | 385 cc::PaintFlags flags; |
| 222 flags.setStyle(cc::PaintFlags::kFill_Style); | 386 flags.setStyle(cc::PaintFlags::kFill_Style); |
| 223 flags.setAntiAlias(true); | 387 flags.setAntiAlias(true); |
| 224 | 388 |
| 225 // Compute the offset of the current widget. | 389 // Compute the offset of the current widget. |
| 226 gfx::Vector2d widget_offset( | 390 gfx::Vector2d widget_offset( |
| 227 widget_->GetNativeView()->GetBoundsInRootWindow().origin().x(), | 391 widget_->GetNativeView()->GetBoundsInRootWindow().origin().x(), |
| 228 widget_->GetNativeView()->GetBoundsInRootWindow().origin().y()); | 392 widget_->GetNativeView()->GetBoundsInRootWindow().origin().y()); |
| 229 | 393 |
| 230 int num_points = laser_points_.GetNumberOfPoints(); | 394 int num_points = laser_points_.GetNumberOfPoints(); |
| 231 DCHECK(num_points > 0); | 395 if (num_points) { |
| 232 LaserPointerPoints::LaserPoint previous_point = laser_points_.GetOldest(); | 396 LaserPointerPoints::LaserPoint previous_point = laser_points_.GetOldest(); |
| 233 previous_point.location -= widget_offset; | 397 previous_point.location -= widget_offset + update_rect.OffsetFromOrigin(); |
|
jbauman
2017/03/01 01:12:01
Might be easier to just translate the canvas rathe
reveman
2017/03/01 18:57:15
Good idea. I'll keep it as is in current patch to
| |
| 234 LaserPointerPoints::LaserPoint current_point; | 398 LaserPointerPoints::LaserPoint current_point; |
| 235 std::vector<gfx::PointF> previous_segment_points; | 399 std::vector<gfx::PointF> previous_segment_points; |
| 236 float previous_radius; | 400 float previous_radius; |
| 237 int current_opacity; | 401 int current_opacity; |
| 238 | 402 |
| 239 for (int i = 0; i < num_points; ++i) { | 403 for (int i = 0; i < num_points; ++i) { |
| 240 current_point = laser_points_.laser_points()[i]; | 404 current_point = laser_points_.laser_points()[i]; |
| 241 current_point.location -= widget_offset; | 405 current_point.location -= widget_offset + update_rect.OffsetFromOrigin(); |
| 242 | 406 |
| 243 // Set the radius and opacity based on the distance. | 407 // Set the radius and opacity based on the distance. |
| 244 float current_radius = LinearInterpolate( | 408 float current_radius = LinearInterpolate( |
| 245 kPointInitialRadius, kPointFinalRadius, current_point.age); | 409 kPointInitialRadius, kPointFinalRadius, current_point.age); |
| 246 current_opacity = int{LinearInterpolate( | 410 current_opacity = int{LinearInterpolate( |
| 247 kPointInitialOpacity, kPointFinalOpacity, current_point.age)}; | 411 kPointInitialOpacity, kPointFinalOpacity, current_point.age)}; |
| 248 | 412 |
| 249 // If we draw laser_points_ that are within a stroke width of each other, | 413 // If we draw laser_points_ that are within a stroke width of each other, |
| 250 // the result will be very jagged, unless we are on the last point, then we | 414 // the result will be very jagged, unless we are on the last point, then |
| 251 // draw regardless. | 415 // we draw regardless. |
| 252 float distance_threshold = current_radius * 2.0f; | 416 float distance_threshold = current_radius * 2.0f; |
| 253 if (DistanceBetweenPoints(previous_point.location, | 417 if (DistanceBetweenPoints(previous_point.location, |
| 254 current_point.location) <= distance_threshold && | 418 current_point.location) <= distance_threshold && |
| 255 i != num_points - 1) { | 419 i != num_points - 1) { |
| 256 continue; | 420 continue; |
| 421 } | |
| 422 | |
| 423 LaserSegment current_segment( | |
| 424 previous_segment_points, gfx::PointF(previous_point.location), | |
| 425 gfx::PointF(current_point.location), previous_radius, current_radius, | |
| 426 i == num_points - 1); | |
| 427 | |
| 428 SkPath path = current_segment.path(); | |
| 429 flags.setColor(SkColorSetA(kPointColor, current_opacity)); | |
| 430 canvas.DrawPath(path, flags); | |
| 431 | |
| 432 previous_segment_points = current_segment.path_points(); | |
| 433 previous_radius = current_radius; | |
| 434 previous_point = current_point; | |
| 257 } | 435 } |
| 258 | 436 |
| 259 LaserSegment current_segment( | 437 // Draw the last point as a circle. |
| 260 previous_segment_points, gfx::PointF(previous_point.location), | |
| 261 gfx::PointF(current_point.location), previous_radius, current_radius, | |
| 262 i == num_points - 1); | |
| 263 | |
| 264 SkPath path = current_segment.path(); | |
| 265 flags.setColor(SkColorSetA(kPointColor, current_opacity)); | 438 flags.setColor(SkColorSetA(kPointColor, current_opacity)); |
| 266 canvas->DrawPath(path, flags); | 439 flags.setStyle(cc::PaintFlags::kFill_Style); |
| 267 | 440 canvas.DrawCircle(current_point.location, kPointInitialRadius, flags); |
| 268 previous_segment_points = current_segment.path_points(); | 441 } |
| 269 previous_radius = current_radius; | 442 |
| 270 previous_point = current_point; | 443 // Copy result to GPU memory buffer. This is effectiely a memcpy and unlike |
| 271 } | 444 // drawing to the buffer directly this ensures that the buffer is never in a |
| 272 // Draw the last point as a circle. | 445 // state that would result in flicker. |
| 273 flags.setColor(SkColorSetA(kPointColor, current_opacity)); | 446 { |
| 274 flags.setStyle(cc::PaintFlags::kFill_Style); | 447 TRACE_EVENT0("ui", "LaserPointerView::OnPointsUpdated::Copy"); |
| 275 canvas->DrawCircle(current_point.location, kPointInitialRadius, flags); | 448 |
| 449 // Convert update rectangle to pixel coordinates. | |
| 450 gfx::Rect pixel_rect = | |
| 451 gfx::ScaleToEnclosingRect(update_rect, scale_factor_); | |
| 452 uint8_t* data = static_cast<uint8_t*>(gpu_memory_buffer_->memory(0)); | |
| 453 int stride = gpu_memory_buffer_->stride(0); | |
| 454 canvas.sk_canvas()->readPixels( | |
| 455 SkImageInfo::MakeN32Premul(pixel_rect.width(), pixel_rect.height()), | |
| 456 data + pixel_rect.y() * stride + pixel_rect.x() * 4, stride, 0, 0); | |
| 457 } | |
| 458 | |
| 459 // Update surface damage rectangle. | |
| 460 surface_damage_rect_.Union(update_rect); | |
| 461 | |
| 462 needs_update_surface_ = true; | |
| 463 | |
| 464 // Early out if waiting for last surface update to be drawn. | |
| 465 if (pending_draw_surface_) | |
| 466 return; | |
| 467 | |
| 468 UpdateSurface(); | |
| 276 } | 469 } |
| 470 | |
| 471 void LaserPointerView::UpdateSurface() { | |
|
jbauman
2017/03/01 01:12:01
We'd normally want to trigger this from OnBeginFra
reveman
2017/03/01 18:57:15
That's another good follow up that I also consider
| |
| 472 TRACE_EVENT1("ui", "LaserPointerView::UpdatedSurface", "damage", | |
| 473 surface_damage_rect_.ToString()); | |
| 474 | |
| 475 DCHECK(needs_update_surface_); | |
| 476 needs_update_surface_ = false; | |
| 477 | |
| 478 std::unique_ptr<LaserResource> resource; | |
| 479 // Reuse returned resource if available. | |
| 480 if (!returned_resources_.empty()) { | |
| 481 resource = std::move(returned_resources_.front()); | |
| 482 returned_resources_.pop_front(); | |
| 483 } | |
| 484 | |
| 485 // Create new resource if needed. | |
| 486 if (!resource) | |
| 487 resource = base::MakeUnique<LaserResource>(); | |
| 488 | |
| 489 // Acquire context provider for resource if needed. | |
| 490 if (!resource->context_provider) { | |
|
jbauman
2017/03/01 01:12:01
Check if ContextGL()->GetGraphicsResetStatusKHR()
reveman
2017/03/01 18:57:15
As I mentioned in the other comment. We don't worr
| |
| 491 resource->context_provider = aura::Env::GetInstance() | |
| 492 ->context_factory() | |
| 493 ->SharedMainThreadContextProvider(); | |
| 494 if (!resource->context_provider) { | |
| 495 LOG(ERROR) << "Failed to acquire a context provider"; | |
| 496 return; | |
| 497 } | |
| 498 } | |
| 499 | |
| 500 gpu::gles2::GLES2Interface* gles2 = resource->context_provider->ContextGL(); | |
| 501 | |
| 502 if (resource->texture) { | |
| 503 gles2->ActiveTexture(GL_TEXTURE0); | |
| 504 gles2->BindTexture(GL_TEXTURE_2D, resource->texture); | |
| 505 } else { | |
| 506 gles2->GenTextures(1, &resource->texture); | |
| 507 gles2->ActiveTexture(GL_TEXTURE0); | |
| 508 gles2->BindTexture(GL_TEXTURE_2D, resource->texture); | |
| 509 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 510 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 511 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 512 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 513 gles2->GenMailboxCHROMIUM(resource->mailbox.name); | |
| 514 gles2->ProduceTextureCHROMIUM(GL_TEXTURE_2D, resource->mailbox.name); | |
| 515 } | |
| 516 | |
| 517 gfx::Size buffer_size = gpu_memory_buffer_->GetSize(); | |
| 518 | |
| 519 if (resource->image) { | |
| 520 gles2->ReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D, resource->image); | |
| 521 } else { | |
| 522 resource->image = gles2->CreateImageCHROMIUM( | |
| 523 gpu_memory_buffer_->AsClientBuffer(), buffer_size.width(), | |
| 524 buffer_size.height(), SK_B32_SHIFT ? GL_RGBA : GL_BGRA_EXT); | |
| 525 if (!resource->image) { | |
| 526 LOG(ERROR) << "Failed to create image"; | |
| 527 return; | |
| 528 } | |
| 529 } | |
| 530 gles2->BindTexImage2DCHROMIUM(GL_TEXTURE_2D, resource->image); | |
| 531 | |
| 532 gpu::SyncToken sync_token; | |
| 533 uint64_t fence_sync = gles2->InsertFenceSyncCHROMIUM(); | |
| 534 gles2->OrderingBarrierCHROMIUM(); | |
| 535 gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); | |
| 536 | |
| 537 cc::TransferableResource transferable_resource; | |
| 538 transferable_resource.id = next_resource_id_++; | |
| 539 transferable_resource.format = cc::RGBA_8888; | |
| 540 transferable_resource.filter = GL_LINEAR; | |
| 541 transferable_resource.size = buffer_size; | |
| 542 transferable_resource.mailbox_holder = | |
| 543 gpu::MailboxHolder(resource->mailbox, sync_token, GL_TEXTURE_2D); | |
| 544 transferable_resource.is_overlay_candidate = true; | |
| 545 | |
| 546 gfx::Rect quad_rect(widget_->GetNativeView()->GetBoundsInScreen().size()); | |
| 547 | |
| 548 const int kRenderPassId = 1; | |
| 549 std::unique_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create(); | |
| 550 render_pass->SetNew(kRenderPassId, quad_rect, surface_damage_rect_, | |
| 551 gfx::Transform()); | |
| 552 surface_damage_rect_ = gfx::Rect(); | |
| 553 | |
| 554 cc::SharedQuadState* quad_state = | |
| 555 render_pass->CreateAndAppendSharedQuadState(); | |
| 556 quad_state->quad_layer_bounds = quad_rect.size(); | |
| 557 quad_state->visible_quad_layer_rect = quad_rect; | |
| 558 quad_state->opacity = 1.0f; | |
| 559 | |
| 560 cc::CompositorFrame frame; | |
| 561 cc::TextureDrawQuad* texture_quad = | |
| 562 render_pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>(); | |
| 563 float vertex_opacity[4] = {1.0, 1.0, 1.0, 1.0}; | |
| 564 gfx::PointF uv_top_left(0.f, 0.f); | |
| 565 gfx::PointF uv_bottom_right(1.f, 1.f); | |
| 566 texture_quad->SetNew(quad_state, quad_rect, gfx::Rect(), quad_rect, | |
| 567 transferable_resource.id, true, uv_top_left, | |
| 568 uv_bottom_right, SK_ColorTRANSPARENT, vertex_opacity, | |
| 569 false, false, false); | |
| 570 texture_quad->set_resource_size_in_pixels(transferable_resource.size); | |
| 571 frame.resource_list.push_back(transferable_resource); | |
| 572 frame.render_pass_list.push_back(std::move(render_pass)); | |
| 573 | |
| 574 // Set layer surface if this is the initial frame. | |
| 575 if (!local_surface_id_.is_valid()) { | |
| 576 local_surface_id_ = id_allocator_.GenerateId(); | |
| 577 widget_->GetNativeView()->layer()->SetShowSurface( | |
| 578 cc::SurfaceInfo(cc::SurfaceId(frame_sink_id_, local_surface_id_), 1.0f, | |
| 579 quad_rect.size()), | |
| 580 aura::Env::GetInstance() | |
| 581 ->context_factory_private() | |
| 582 ->GetSurfaceManager() | |
| 583 ->reference_factory()); | |
| 584 widget_->GetNativeView()->layer()->SetFillsBoundsOpaquely(false); | |
| 585 } | |
| 586 | |
| 587 SubmitCompositorFrame(local_surface_id_, std::move(frame)); | |
| 588 | |
| 589 resources_[transferable_resource.id] = std::move(resource); | |
| 590 | |
| 591 DCHECK(!pending_draw_surface_); | |
| 592 pending_draw_surface_ = true; | |
| 593 } | |
| 594 | |
| 595 void LaserPointerView::OnDidDrawSurface() { | |
| 596 pending_draw_surface_ = false; | |
| 597 if (needs_update_surface_) | |
| 598 UpdateSurface(); | |
| 599 } | |
| 600 | |
| 277 } // namespace ash | 601 } // namespace ash |
| OLD | NEW |