| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "remoting/client/gl_desktop.h" |
| |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "remoting/client/gl_canvas.h" |
| #include "remoting/client/gl_math.h" |
| #include "remoting/client/gl_render_layer.h" |
| #include "remoting/client/gl_texture_ids.h" |
| #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" |
| |
| namespace remoting { |
| |
| namespace { |
| |
| void UpdateDesktopRegion(const webrtc::DesktopFrame& frame, |
| const webrtc::DesktopRegion& region, |
| const webrtc::DesktopRect& texture_rect, |
| GlRenderLayer* layer) { |
| for (webrtc::DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) { |
| const uint8_t* rect_start = frame.GetFrameDataAtPos(i.rect().top_left()); |
| webrtc::DesktopVector update_pos = |
| i.rect().top_left().subtract(texture_rect.top_left()); |
| layer->UpdateTexture(rect_start, update_pos.x(), update_pos.y(), |
| i.rect().width(), i.rect().height(), frame.stride()); |
| } |
| } |
| |
| void SetFrameForTexture(const webrtc::DesktopFrame& frame, |
| GlRenderLayer* layer, |
| const webrtc::DesktopRect& rect) { |
| if (!layer->is_texture_set()) { |
| // First frame received. |
| layer->SetTexture(frame.GetFrameDataAtPos(rect.top_left()), rect.width(), |
| rect.height(), frame.stride()); |
| return; |
| } |
| // Incremental update. |
| if (frame.size().equals(rect.size())) { |
| // Single texture. No intersection is needed. |
| UpdateDesktopRegion(frame, frame.updated_region(), rect, layer); |
| } else { |
| webrtc::DesktopRegion intersected_region = frame.updated_region(); |
| intersected_region.IntersectWith(rect); |
| UpdateDesktopRegion(frame, intersected_region, rect, layer); |
| } |
| } |
| |
| } // namespace |
| |
| struct GlDesktop::GlDesktopTextureContainer { |
| std::unique_ptr<GlRenderLayer> layer; |
| webrtc::DesktopRect rect; |
| }; |
| |
| GlDesktop::GlDesktop() {} |
| |
| GlDesktop::~GlDesktop() {} |
| |
| void GlDesktop::SetCanvas(GlCanvas* canvas) { |
| last_desktop_size_.set(0, 0); |
| textures_.clear(); |
| canvas_ = canvas; |
| if (canvas) { |
| max_texture_size_ = canvas->GetMaxTextureSize(); |
| } |
| } |
| |
| void GlDesktop::SetVideoFrame(const webrtc::DesktopFrame& frame) { |
| if (!canvas_) { |
| return; |
| } |
| if (!frame.size().equals(last_desktop_size_)) { |
| last_desktop_size_.set(frame.size().width(), frame.size().height()); |
| ReallocateTextures(last_desktop_size_); |
| } |
| for (std::unique_ptr<GlDesktopTextureContainer>& texture : textures_) { |
| SetFrameForTexture(frame, texture->layer.get(), texture->rect); |
| } |
| } |
| |
| void GlDesktop::Draw() { |
| if (!textures_.empty() && !last_desktop_size_.is_empty()) { |
| for (std::unique_ptr<GlDesktopTextureContainer>& texture : textures_) { |
| texture->layer->Draw(1.0f); |
| } |
| } |
| } |
| |
| void GlDesktop::ReallocateTextures(const webrtc::DesktopSize& size) { |
| DCHECK(max_texture_size_); |
| DCHECK(canvas_); |
| textures_.clear(); |
| |
| int textures_per_row = |
| (size.width() + max_texture_size_ - 1) / max_texture_size_; |
| |
| int textures_per_column = |
| (size.height() + max_texture_size_ - 1) / max_texture_size_; |
| |
| webrtc::DesktopRect desktop_rect = webrtc::DesktopRect::MakeSize(size); |
| |
| int texture_id = kGlDesktopFirstTextureId; |
| std::array<float, 8> positions; |
| for (int x = 0; x < textures_per_row; x++) { |
| for (int y = 0; y < textures_per_column; y++) { |
| webrtc::DesktopRect rect = webrtc::DesktopRect::MakeXYWH( |
| x * max_texture_size_, y * max_texture_size_, max_texture_size_, |
| max_texture_size_); |
| rect.IntersectWith(desktop_rect); |
| std::unique_ptr<GlDesktopTextureContainer> container = |
| base::WrapUnique(new GlDesktopTextureContainer{ |
| base::MakeUnique<GlRenderLayer>(texture_id, canvas_), rect}); |
| FillRectangleVertexPositions(rect.left(), rect.top(), rect.width(), |
| rect.height(), &positions); |
| container->layer->SetVertexPositions(positions); |
| textures_.push_back(std::move(container)); |
| texture_id++; |
| } |
| } |
| } |
| |
| } // namespace remoting |