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" |
| 13 #include "base/timer/timer.h" | 17 #include "base/timer/timer.h" |
| 18 #include "base/trace_event/trace_event.h" | |
| 19 #include "cc/output/context_provider.h" | |
| 20 #include "cc/quads/texture_draw_quad.h" | |
| 21 #include "cc/resources/transferable_resource.h" | |
| 22 #include "cc/surfaces/surface.h" | |
| 23 #include "cc/surfaces/surface_id_allocator.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; |
| 28 const SkColor kPointColor = SkColorSetRGB(255, 0, 0); | 47 const SkColor kPointColor = SkColorSetRGB(255, 0, 0); |
| 29 | 48 |
| 49 // Maximum resources. Surface updates are throttled when reaching this limit. | |
| 50 const size_t kMaxResources = 3; | |
| 51 | |
| 30 float DistanceBetweenPoints(const gfx::Point& point1, | 52 float DistanceBetweenPoints(const gfx::Point& point1, |
| 31 const gfx::Point& point2) { | 53 const gfx::Point& point2) { |
| 32 return (point1 - point2).Length(); | 54 return (point1 - point2).Length(); |
| 33 } | 55 } |
| 34 | 56 |
| 35 float LinearInterpolate(float initial_value, | 57 float LinearInterpolate(float initial_value, |
| 36 float final_value, | 58 float final_value, |
| 37 float progress) { | 59 float progress) { |
| 38 return initial_value + (final_value - initial_value) * progress; | 60 return initial_value + (final_value - initial_value) * progress; |
| 39 } | 61 } |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 150 SkPath path() const { return path_; } | 172 SkPath path() const { return path_; } |
| 151 std::vector<gfx::PointF> path_points() const { return path_points_; } | 173 std::vector<gfx::PointF> path_points() const { return path_points_; } |
| 152 | 174 |
| 153 private: | 175 private: |
| 154 SkPath path_; | 176 SkPath path_; |
| 155 std::vector<gfx::PointF> path_points_; | 177 std::vector<gfx::PointF> path_points_; |
| 156 | 178 |
| 157 DISALLOW_COPY_AND_ASSIGN(LaserSegment); | 179 DISALLOW_COPY_AND_ASSIGN(LaserSegment); |
| 158 }; | 180 }; |
| 159 | 181 |
| 182 // This struct contains the resources associated with a laser pointer frame. | |
| 183 struct LaserResource { | |
| 184 LaserResource() {} | |
| 185 ~LaserResource() { | |
| 186 if (context_provider) { | |
| 187 gpu::gles2::GLES2Interface* gles2 = context_provider->ContextGL(); | |
| 188 if (texture) | |
| 189 gles2->DeleteTextures(1, &texture); | |
| 190 if (image) | |
| 191 gles2->DestroyImageCHROMIUM(image); | |
| 192 } | |
| 193 } | |
| 194 scoped_refptr<cc::ContextProvider> context_provider; | |
| 195 uint32_t texture = 0; | |
| 196 uint32_t image = 0; | |
| 197 gpu::Mailbox mailbox; | |
| 198 }; | |
| 199 | |
| 160 // LaserPointerView | 200 // LaserPointerView |
| 161 LaserPointerView::LaserPointerView(base::TimeDelta life_duration, | 201 LaserPointerView::LaserPointerView(base::TimeDelta life_duration, |
| 162 aura::Window* root_window) | 202 aura::Window* root_window) |
| 163 : laser_points_(life_duration) { | 203 : laser_points_(life_duration), |
| 204 frame_sink_id_(aura::Env::GetInstance() | |
| 205 ->context_factory_private() | |
| 206 ->AllocateFrameSinkId()), | |
| 207 frame_sink_support_(this, | |
| 208 aura::Env::GetInstance() | |
| 209 ->context_factory_private() | |
| 210 ->GetSurfaceManager(), | |
| 211 frame_sink_id_, | |
| 212 false /* is_root */, | |
| 213 true /* handles_frame_sink_id_invalidation */, | |
| 214 true /* needs_sync_points */) { | |
| 164 widget_.reset(new views::Widget); | 215 widget_.reset(new views::Widget); |
| 165 views::Widget::InitParams params; | 216 views::Widget::InitParams params; |
| 166 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; | 217 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; |
| 167 params.name = "LaserOverlay"; | 218 params.name = "LaserOverlay"; |
| 168 params.accept_events = false; | 219 params.accept_events = false; |
| 169 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; | 220 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; |
| 170 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 221 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| 171 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | 222 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
| 172 params.parent = | 223 params.parent = |
| 173 Shell::GetContainer(root_window, kShellWindowId_OverlayContainer); | 224 Shell::GetContainer(root_window, kShellWindowId_OverlayContainer); |
| 225 params.layer_type = ui::LAYER_SOLID_COLOR; | |
| 174 | 226 |
| 175 widget_->Init(params); | 227 widget_->Init(params); |
| 176 widget_->Show(); | 228 widget_->Show(); |
| 177 widget_->SetContentsView(this); | 229 widget_->SetContentsView(this); |
| 230 widget_->SetBounds(root_window->GetBoundsInScreen()); | |
| 178 set_owned_by_client(); | 231 set_owned_by_client(); |
| 232 | |
| 233 scale_factor_ = display::Screen::GetScreen() | |
| 234 ->GetDisplayNearestWindow(widget_->GetNativeView()) | |
| 235 .device_scale_factor(); | |
| 179 } | 236 } |
| 180 | 237 |
| 181 LaserPointerView::~LaserPointerView() {} | 238 LaserPointerView::~LaserPointerView() { |
| 239 // Make sure GPU memory buffer is unmapped before being destroyed. | |
| 240 if (gpu_memory_buffer_) | |
| 241 gpu_memory_buffer_->Unmap(); | |
| 242 } | |
| 182 | 243 |
| 183 void LaserPointerView::Stop() { | 244 void LaserPointerView::Stop() { |
| 245 gfx::Rect damage_rect = GetBoundingBox(); | |
| 184 laser_points_.Clear(); | 246 laser_points_.Clear(); |
| 185 SchedulePaint(); | 247 OnPointsUpdated(damage_rect); |
| 186 } | 248 } |
| 187 | 249 |
| 188 void LaserPointerView::AddNewPoint(const gfx::Point& new_point) { | 250 void LaserPointerView::AddNewPoint(const gfx::Point& new_point) { |
| 251 gfx::Rect bounding_box = GetBoundingBox(); | |
| 189 laser_points_.AddPoint(new_point); | 252 laser_points_.AddPoint(new_point); |
| 190 OnPointsUpdated(); | 253 gfx::Rect damage_rect = gfx::UnionRects(bounding_box, GetBoundingBox()); |
| 254 OnPointsUpdated(damage_rect); | |
| 191 } | 255 } |
| 192 | 256 |
| 193 void LaserPointerView::UpdateTime() { | 257 void LaserPointerView::UpdateTime() { |
| 258 gfx::Rect bounding_box = GetBoundingBox(); | |
| 194 // Do not add the point but advance the time if the view is in process of | 259 // Do not add the point but advance the time if the view is in process of |
| 195 // fading away. | 260 // fading away. |
| 196 laser_points_.MoveForwardToTime(base::Time::Now()); | 261 laser_points_.MoveForwardToTime(base::Time::Now()); |
| 197 OnPointsUpdated(); | 262 gfx::Rect damage_rect = gfx::UnionRects(bounding_box, GetBoundingBox()); |
| 263 OnPointsUpdated(damage_rect); | |
| 198 } | 264 } |
| 199 | 265 |
| 200 void LaserPointerView::OnPointsUpdated() { | 266 void LaserPointerView::ReclaimResources( |
| 201 // The bounding box should be relative to the screen. | 267 const cc::ReturnedResourceArray& resources) { |
| 202 gfx::Point screen_offset = | 268 DCHECK_EQ(resources.size(), 1u); |
| 203 widget_->GetNativeView()->GetRootWindow()->GetBoundsInScreen().origin(); | |
| 204 | 269 |
| 205 // Expand the bounding box so that it includes the radius of the points on the | 270 auto it = resources_.find(resources.front().id); |
| 206 // edges. | 271 DCHECK(it != resources_.end()); |
| 207 gfx::Rect bounding_box; | 272 std::unique_ptr<LaserResource> resource = std::move(it->second); |
| 208 bounding_box = laser_points_.GetBoundingBox(); | 273 resources_.erase(it); |
| 209 bounding_box.Offset(-kPointInitialRadius, -kPointInitialRadius); | 274 |
| 210 bounding_box.Offset(screen_offset.x(), screen_offset.y()); | 275 gpu::gles2::GLES2Interface* gles2 = resource->context_provider->ContextGL(); |
| 211 bounding_box.set_width(bounding_box.width() + (kPointInitialRadius * 2)); | 276 if (resources.front().sync_token.HasData()) |
| 212 bounding_box.set_height(bounding_box.height() + (kPointInitialRadius * 2)); | 277 gles2->WaitSyncTokenCHROMIUM(resources.front().sync_token.GetConstData()); |
| 213 widget_->SetBounds(bounding_box); | 278 |
| 214 SchedulePaint(); | 279 if (!resources.front().lost) |
| 280 returned_resources_.push_back(std::move(resource)); | |
| 281 | |
| 282 if (needs_update_surface_) | |
| 283 UpdateSurface(); | |
| 215 } | 284 } |
| 216 | 285 |
| 217 void LaserPointerView::OnPaint(gfx::Canvas* canvas) { | 286 gfx::Rect LaserPointerView::GetBoundingBox() { |
| 218 if (laser_points_.IsEmpty()) | 287 // Expand the bounding box so that it includes the radius of the points on the |
| 288 // edges and antialiasing. | |
| 289 gfx::Rect bounding_box = laser_points_.GetBoundingBox(); | |
| 290 const int kOutsetForAntialiasing = 1; | |
| 291 int outset = kPointInitialRadius + kOutsetForAntialiasing; | |
| 292 bounding_box.Inset(-outset, -outset); | |
| 293 return bounding_box; | |
| 294 } | |
| 295 | |
| 296 void LaserPointerView::OnPointsUpdated(const gfx::Rect& damage_rect) { | |
| 297 TRACE_EVENT1("ui", "LaserPointerView::OnPointsUpdated", "damage_rect", | |
| 298 damage_rect.ToString()); | |
| 299 | |
| 300 gfx::Rect screen_bounds = widget_->GetNativeView()->GetBoundsInScreen(); | |
| 301 gfx::Rect update_rect = damage_rect; | |
| 302 | |
| 303 // Create and map a single GPU memory buffer. The laser pointer will be | |
| 304 // written into this buffer without any buffering. The result is that we | |
| 305 // might be modifying the buffer while it's being displayed. This provides | |
| 306 // minimal latency but potential tearing. Note that we have to draw into | |
| 307 // a temporary surface and copy it into GPU memory buffer to avoid flicker. | |
| 308 if (!gpu_memory_buffer_) { | |
| 309 gpu_memory_buffer_ = | |
| 310 aura::Env::GetInstance() | |
| 311 ->context_factory() | |
| 312 ->GetGpuMemoryBufferManager() | |
| 313 ->CreateGpuMemoryBuffer( | |
| 314 gfx::ScaleToCeiledSize(screen_bounds.size(), scale_factor_), | |
| 315 SK_B32_SHIFT ? gfx::BufferFormat::RGBA_8888 | |
| 316 : gfx::BufferFormat::BGRA_8888, | |
| 317 gfx::BufferUsage::SCANOUT_CPU_READ_WRITE, | |
| 318 gpu::kNullSurfaceHandle); | |
| 319 if (!gpu_memory_buffer_) { | |
| 320 LOG(ERROR) << "Failed to allocate GPU memory buffer"; | |
| 321 return; | |
| 322 } | |
| 323 | |
| 324 // Map buffer and keep it mapped until destroyed. | |
| 325 bool rv = gpu_memory_buffer_->Map(); | |
| 326 if (!rv) { | |
| 327 LOG(ERROR) << "Failed to map GPU memory buffer"; | |
| 328 return; | |
| 329 } | |
| 330 | |
| 331 // Make sure the first update rectangle covers the whole buffer. | |
| 332 update_rect = gfx::Rect(screen_bounds.size()); | |
| 333 } | |
| 334 | |
| 335 // Constrain update rectangle to buffer size and early out if empty. | |
| 336 update_rect.Intersect(gfx::Rect(screen_bounds.size())); | |
| 337 if (update_rect.IsEmpty()) | |
| 219 return; | 338 return; |
| 220 | 339 |
| 340 // Create a temporary canvas for update rectangle. | |
| 341 gfx::Canvas canvas(update_rect.size(), scale_factor_, false); | |
| 342 | |
| 221 cc::PaintFlags flags; | 343 cc::PaintFlags flags; |
| 222 flags.setStyle(cc::PaintFlags::kFill_Style); | 344 flags.setStyle(cc::PaintFlags::kFill_Style); |
| 223 flags.setAntiAlias(true); | 345 flags.setAntiAlias(true); |
| 224 | 346 |
| 225 // Compute the offset of the current widget. | 347 // Compute the offset of the current widget. |
| 226 gfx::Vector2d widget_offset( | 348 gfx::Vector2d widget_offset( |
| 227 widget_->GetNativeView()->GetBoundsInRootWindow().origin().x(), | 349 widget_->GetNativeView()->GetBoundsInRootWindow().origin().x(), |
| 228 widget_->GetNativeView()->GetBoundsInRootWindow().origin().y()); | 350 widget_->GetNativeView()->GetBoundsInRootWindow().origin().y()); |
| 229 | 351 |
| 230 int num_points = laser_points_.GetNumberOfPoints(); | 352 int num_points = laser_points_.GetNumberOfPoints(); |
| 231 DCHECK(num_points > 0); | 353 if (num_points) { |
| 232 LaserPointerPoints::LaserPoint previous_point = laser_points_.GetOldest(); | 354 LaserPointerPoints::LaserPoint previous_point = laser_points_.GetOldest(); |
| 233 previous_point.location -= widget_offset; | 355 previous_point.location -= widget_offset + update_rect.OffsetFromOrigin(); |
| 234 LaserPointerPoints::LaserPoint current_point; | 356 LaserPointerPoints::LaserPoint current_point; |
| 235 std::vector<gfx::PointF> previous_segment_points; | 357 std::vector<gfx::PointF> previous_segment_points; |
| 236 float previous_radius; | 358 float previous_radius; |
| 237 int current_opacity; | 359 int current_opacity; |
| 238 | 360 |
| 239 for (int i = 0; i < num_points; ++i) { | 361 for (int i = 0; i < num_points; ++i) { |
| 240 current_point = laser_points_.laser_points()[i]; | 362 current_point = laser_points_.laser_points()[i]; |
| 241 current_point.location -= widget_offset; | 363 current_point.location -= widget_offset + update_rect.OffsetFromOrigin(); |
| 242 | 364 |
| 243 // Set the radius and opacity based on the distance. | 365 // Set the radius and opacity based on the distance. |
| 244 float current_radius = LinearInterpolate( | 366 float current_radius = LinearInterpolate( |
| 245 kPointInitialRadius, kPointFinalRadius, current_point.age); | 367 kPointInitialRadius, kPointFinalRadius, current_point.age); |
| 246 current_opacity = int{LinearInterpolate( | 368 current_opacity = int{LinearInterpolate( |
| 247 kPointInitialOpacity, kPointFinalOpacity, current_point.age)}; | 369 kPointInitialOpacity, kPointFinalOpacity, current_point.age)}; |
| 248 | 370 |
| 249 // If we draw laser_points_ that are within a stroke width of each other, | 371 // 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 | 372 // the result will be very jagged, unless we are on the last point, then |
| 251 // draw regardless. | 373 // we draw regardless. |
| 252 float distance_threshold = current_radius * 2.0f; | 374 float distance_threshold = current_radius * 2.0f; |
| 253 if (DistanceBetweenPoints(previous_point.location, | 375 if (DistanceBetweenPoints(previous_point.location, |
| 254 current_point.location) <= distance_threshold && | 376 current_point.location) <= distance_threshold && |
| 255 i != num_points - 1) { | 377 i != num_points - 1) { |
| 256 continue; | 378 continue; |
| 379 } | |
| 380 | |
| 381 LaserSegment current_segment( | |
| 382 previous_segment_points, gfx::PointF(previous_point.location), | |
| 383 gfx::PointF(current_point.location), previous_radius, current_radius, | |
| 384 i == num_points - 1); | |
| 385 | |
| 386 SkPath path = current_segment.path(); | |
| 387 flags.setColor(SkColorSetA(kPointColor, current_opacity)); | |
| 388 canvas.DrawPath(path, flags); | |
| 389 | |
| 390 previous_segment_points = current_segment.path_points(); | |
| 391 previous_radius = current_radius; | |
| 392 previous_point = current_point; | |
| 257 } | 393 } |
| 258 | 394 |
| 259 LaserSegment current_segment( | 395 // Draw the last point as a circle. |
| 260 previous_segment_points, gfx::PointF(previous_point.location), | 396 flags.setColor(SkColorSetA(kPointColor, current_opacity)); |
| 261 gfx::PointF(current_point.location), previous_radius, current_radius, | 397 flags.setStyle(cc::PaintFlags::kFill_Style); |
| 262 i == num_points - 1); | 398 canvas.DrawCircle(current_point.location, kPointInitialRadius, flags); |
| 399 } | |
| 263 | 400 |
| 264 SkPath path = current_segment.path(); | 401 // Copy result to GPU memory buffer. This is effectiely a memcpy and unlike |
| 265 flags.setColor(SkColorSetA(kPointColor, current_opacity)); | 402 // drawing to the buffer directly this ensures that the buffer is never in a |
| 266 canvas->DrawPath(path, flags); | 403 // state that would result in flicker. |
| 404 { | |
| 405 TRACE_EVENT0("ui", "LaserPointerView::OnPointsUpdated::Copy"); | |
| 267 | 406 |
| 268 previous_segment_points = current_segment.path_points(); | 407 // Convert update rectangle to pixel coordinates. |
| 269 previous_radius = current_radius; | 408 gfx::Rect pixel_rect = |
| 270 previous_point = current_point; | 409 gfx::ScaleToEnclosingRect(update_rect, scale_factor_); |
| 410 uint8_t* data = static_cast<uint8_t*>(gpu_memory_buffer_->memory(0)); | |
| 411 int stride = gpu_memory_buffer_->stride(0); | |
| 412 canvas.sk_canvas()->readPixels( | |
| 413 SkImageInfo::MakeN32Premul(pixel_rect.width(), pixel_rect.height()), | |
| 414 data + pixel_rect.y() * stride + pixel_rect.x() * 4, stride, 0, 0); | |
| 271 } | 415 } |
| 272 // Draw the last point as a circle. | 416 |
| 273 flags.setColor(SkColorSetA(kPointColor, current_opacity)); | 417 // Update surface damage rectangle. |
| 274 flags.setStyle(cc::PaintFlags::kFill_Style); | 418 damage_rect_.Union(update_rect); |
| 275 canvas->DrawCircle(current_point.location, kPointInitialRadius, flags); | 419 |
| 420 UpdateSurface(); | |
| 276 } | 421 } |
| 422 | |
| 423 void LaserPointerView::UpdateSurface() { | |
| 424 std::unique_ptr<LaserResource> resource; | |
| 425 if (returned_resources_.empty()) { | |
| 426 // Defer update until resource is reclaimed if limit has been reached. | |
| 427 if ((resources_.size() + returned_resources_.size()) >= kMaxResources) { | |
| 428 needs_update_surface_ = true; | |
| 429 return; | |
| 430 } | |
| 431 resource = base::MakeUnique<LaserResource>(); | |
| 432 } else { | |
| 433 resource = std::move(returned_resources_.front()); | |
| 434 returned_resources_.pop_front(); | |
| 435 } | |
| 436 | |
| 437 // Acquire context provider for resource if needed. | |
| 438 if (!resource->context_provider) { | |
| 439 resource->context_provider = aura::Env::GetInstance() | |
| 440 ->context_factory() | |
| 441 ->SharedMainThreadContextProvider(); | |
| 442 if (!resource->context_provider) { | |
| 443 LOG(ERROR) << "Failed to acquire a context provider"; | |
| 444 return; | |
| 445 } | |
| 446 } | |
| 447 | |
| 448 gpu::gles2::GLES2Interface* gles2 = resource->context_provider->ContextGL(); | |
| 449 | |
| 450 if (resource->texture) { | |
| 451 gles2->ActiveTexture(GL_TEXTURE0); | |
| 452 gles2->BindTexture(GL_TEXTURE_2D, resource->texture); | |
| 453 } else { | |
| 454 gles2->GenTextures(1, &resource->texture); | |
| 455 gles2->ActiveTexture(GL_TEXTURE0); | |
| 456 gles2->BindTexture(GL_TEXTURE_2D, resource->texture); | |
| 457 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 458 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 459 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 460 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 461 gles2->GenMailboxCHROMIUM(resource->mailbox.name); | |
| 462 gles2->ProduceTextureCHROMIUM(GL_TEXTURE_2D, resource->mailbox.name); | |
| 463 } | |
| 464 | |
| 465 gfx::Size buffer_size = gpu_memory_buffer_->GetSize(); | |
| 466 | |
| 467 if (resource->image) { | |
| 468 gles2->ReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D, resource->image); | |
| 469 } else { | |
| 470 resource->image = gles2->CreateImageCHROMIUM( | |
| 471 gpu_memory_buffer_->AsClientBuffer(), buffer_size.width(), | |
| 472 buffer_size.height(), SK_B32_SHIFT ? GL_RGBA : GL_BGRA_EXT); | |
| 473 if (!resource->image) { | |
| 474 LOG(ERROR) << "Failed to create image"; | |
| 475 return; | |
| 476 } | |
| 477 } | |
| 478 gles2->BindTexImage2DCHROMIUM(GL_TEXTURE_2D, resource->image); | |
| 479 | |
| 480 gpu::SyncToken sync_token; | |
| 481 uint64_t fence_sync = gles2->InsertFenceSyncCHROMIUM(); | |
| 482 gles2->OrderingBarrierCHROMIUM(); | |
| 483 gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); | |
| 484 | |
| 485 cc::TransferableResource transferable_resource; | |
| 486 transferable_resource.id = next_resource_id_++; | |
| 487 transferable_resource.format = cc::RGBA_8888; | |
| 488 transferable_resource.filter = GL_LINEAR; | |
| 489 transferable_resource.size = buffer_size; | |
| 490 transferable_resource.mailbox_holder = | |
| 491 gpu::MailboxHolder(resource->mailbox, sync_token, GL_TEXTURE_2D); | |
| 492 transferable_resource.is_overlay_candidate = true; | |
| 493 | |
| 494 gfx::Rect quad_rect(widget_->GetNativeView()->GetBoundsInScreen().size()); | |
| 495 | |
| 496 const int kRenderPassId = 1; | |
| 497 std::unique_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create(); | |
| 498 render_pass->SetNew(kRenderPassId, quad_rect, damage_rect_, gfx::Transform()); | |
| 499 | |
| 500 cc::SharedQuadState* quad_state = | |
| 501 render_pass->CreateAndAppendSharedQuadState(); | |
| 502 quad_state->quad_layer_bounds = quad_rect.size(); | |
| 503 quad_state->visible_quad_layer_rect = quad_rect; | |
| 504 quad_state->opacity = 1.0f; | |
| 505 | |
| 506 cc::CompositorFrame frame; | |
| 507 cc::TextureDrawQuad* texture_quad = | |
| 508 render_pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>(); | |
| 509 float vertex_opacity[4] = {1.0, 1.0, 1.0, 1.0}; | |
| 510 gfx::PointF uv_top_left(0.f, 0.f); | |
| 511 gfx::PointF uv_bottom_right(1.f, 1.f); | |
| 512 texture_quad->SetNew(quad_state, quad_rect, gfx::Rect(), quad_rect, | |
| 513 transferable_resource.id, true, uv_top_left, | |
| 514 uv_bottom_right, SK_ColorTRANSPARENT, vertex_opacity, | |
| 515 false, false, false); | |
| 516 texture_quad->set_resource_size_in_pixels(transferable_resource.size); | |
| 517 frame.resource_list.push_back(transferable_resource); | |
| 518 frame.render_pass_list.push_back(std::move(render_pass)); | |
| 519 | |
| 520 // Set layer surface if this is the initial frame. | |
| 521 if (!local_surface_id_.is_valid()) { | |
| 522 local_surface_id_ = id_allocator_.GenerateId(); | |
|
Fady Samuel
2017/02/27 16:07:29
So you only allocate a surface ID once? Do you hav
reveman
2017/02/27 16:20:15
Correct, we allocate this ID once. The widget/view
| |
| 523 widget_->GetNativeView()->layer()->SetShowSurface( | |
| 524 cc::SurfaceInfo(cc::SurfaceId(frame_sink_id_, local_surface_id_), 1.0f, | |
| 525 quad_rect.size()), | |
| 526 aura::Env::GetInstance() | |
| 527 ->context_factory_private() | |
| 528 ->GetSurfaceManager() | |
| 529 ->reference_factory()); | |
| 530 widget_->GetNativeView()->layer()->SetFillsBoundsOpaquely(false); | |
| 531 } | |
| 532 | |
| 533 frame_sink_support_.SubmitCompositorFrame(local_surface_id_, | |
| 534 std::move(frame)); | |
| 535 | |
| 536 resources_[transferable_resource.id] = std::move(resource); | |
| 537 needs_update_surface_ = false; | |
| 538 damage_rect_ = gfx::Rect(); | |
| 539 } | |
| 540 | |
| 277 } // namespace ash | 541 } // namespace ash |
| OLD | NEW |