Commit f62cc8a9 authored by nicholss's avatar nicholss Committed by Commit bot

Adding drawable to CRD andorid and iOS gl rendering pipeline.

This work is to support more generic rendering for mobile platforms.
The thinking behind using a stack of 'drawable' objects is we could
add future features like fps stats or more animations, and also add
debug screens to apps in development for gesture feedback and connection
health.

R=yuweih@chromium.org
BUG=671692

Review-Url: https://codereview.chromium.org/2591363002
Cr-Commit-Position: refs/heads/master@{#443246}
parent 39f5b80c
......@@ -4,6 +4,8 @@
source_set("display") {
sources = [
"canvas.h",
"drawable.h",
"gl_canvas.cc",
"gl_canvas.h",
"gl_cursor.cc",
......@@ -22,6 +24,7 @@ source_set("display") {
"gl_render_layer.h",
"gl_renderer.cc",
"gl_renderer.h",
"sys_opengl.h",
]
deps = [
......@@ -30,7 +33,11 @@ source_set("display") {
"//third_party/webrtc/base:rtc_base",
]
configs += [ "//third_party/khronos:khronos_headers" ]
public_configs = [ "//third_party/khronos:khronos_headers" ]
if (is_android) {
libs = [ "GLESv2" ]
}
if (is_linux) {
libs = [ "GL" ]
......@@ -52,30 +59,33 @@ source_set("display") {
}
}
source_set("unit_tests") {
testonly = true
sources = [
"gl_renderer_unittest.cc",
]
if (is_win) {
# Windows clang builder fails to link the test binary with ANGLE GLESv2.
# crbug.com/642027
group("unit_tests") {
deps = []
}
} else {
source_set("unit_tests") {
testonly = true
configs += [
"//remoting/build/config:version",
"//remoting/build/config:enable_webrtc_remoting_client",
]
sources = [
"fake_canvas.cc",
"fake_canvas.h",
"gl_renderer_unittest.cc",
]
deps = [
":display",
"//remoting/proto",
"//testing/gmock",
"//testing/gtest",
"//third_party/webrtc/base:rtc_base",
]
configs += [
"//remoting/build/config:version",
"//remoting/build/config:enable_webrtc_remoting_client",
]
if (is_win) {
# Windows clang builder fails to link the test binary with ANGLE GLESv2.
# crbug.com/642027
sources -= [ "gl_renderer_unittest.cc" ]
deps -= [ ":display" ]
deps = [
":display",
"//remoting/proto",
"//testing/gmock",
"//testing/gtest",
"//third_party/webrtc/base:rtc_base",
]
}
}
// 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.
#ifndef REMOTING_CLIENT_DISPLAY_CANVAS_H_
#define REMOTING_CLIENT_DISPLAY_CANVAS_H_
#include <array>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
namespace remoting {
// This class holds zoom and pan configurations of the canvas and is used to
// draw textures on the canvas.
class Canvas {
public:
Canvas() {}
virtual ~Canvas() {}
// Clears the frame.
virtual void Clear() = 0;
// Sets the transformation matrix. This matrix defines how the canvas should
// be shown on the view.
// 3 by 3 transformation matrix, [ m0, m1, m2, m3, m4, m5, m6, m7, m8 ].
// The matrix will be multiplied with the positions (with projective space,
// (x, y, 1)) to draw the textures with the right zoom and pan configuration.
//
// | m0, m1, m2, | | x |
// | m3, m4, m5, | * | y |
// | m6, m7, m8 | | 1 |
//
// For a typical transformation matrix such that m1=m3=m6=m7=0 and m8=1, m0
// and m4 defines the scaling factor of the canvas and m2 and m5 defines the
// offset of the upper-left corner in pixel.
virtual void SetTransformationMatrix(const std::array<float, 9>& matrix) = 0;
// Sets the size of the view in pixels.
virtual void SetViewSize(int width, int height) = 0;
// Draws the texture on the canvas. Nothing will happen if
// SetNormalizedTransformation() has not been called.
// vertex_buffer: reference to the 2x4x2 float vertex buffer.
// [ four (x, y) position of the texture vertices in pixel
// with respect to the canvas,
// four (x, y) position of the vertices in percentage
// defining the visible area of the texture ]
// alpha_multiplier: Will be multiplied with the alpha channel of the texture.
// Passing 1 means no change of the transparency of the
// texture.
virtual void DrawTexture(int texture_id,
int texture_handle,
int vertex_buffer,
float alpha_multiplier) = 0;
// Version if applicable to implementation. Default 0 if unused.
virtual int GetVersion() const = 0;
// Returns the maximum texture resolution limitation. Neither the width nor
// the height of the texture can exceed this limitation.
virtual int GetMaxTextureSize() const = 0;
// Intended to be given to a Drawable to draw onto.
virtual base::WeakPtr<Canvas> GetWeakPtr() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Canvas);
};
} // namespace remoting
#endif // REMOTING_CLIENT_DISPLAY_CANVAS_H_
// 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.
#ifndef REMOTING_CLIENT_DISPLAY_DRAWABLE_H_
#define REMOTING_CLIENT_DISPLAY_DRAWABLE_H_
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
namespace remoting {
class Canvas;
// Interface for drawing on a Canvas from a renderer.
class Drawable {
public:
Drawable() {}
virtual ~Drawable() {}
// Sets the canvas on which the object will be drawn.
// If |canvas| is nullptr, nothing will happen when calling Draw().
virtual void SetCanvas(base::WeakPtr<Canvas> canvas) = 0;
// Draws the object on the canvas.
// Returns true if there is a pending next frame.
virtual bool Draw() = 0;
// Used for the renderer to keep a stack of drawables.
virtual base::WeakPtr<Drawable> GetWeakPtr() = 0;
// ZIndex is a recommendation for Z Index of drawable components.
enum ZIndex {
DESKTOP = 100,
CURSOR_FEEDBACK = 200,
CURSOR = 300,
};
// A higher Z Index shiould be draw ontop of a lower z index. Elements with
// the same Z Index should draw in order inserted into the renderer.
virtual int GetZIndex() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Drawable);
};
} // namespace remoting
#endif // REMOTING_CLIENT_DISPLAY_DRAWABLE_H_
// 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/display/fake_canvas.h"
namespace remoting {
FakeCanvas::FakeCanvas() : weak_factory_(this) {}
FakeCanvas::~FakeCanvas() {}
void FakeCanvas::Clear() {}
void FakeCanvas::SetTransformationMatrix(const std::array<float, 9>& matrix) {}
void FakeCanvas::SetViewSize(int width, int height) {}
void FakeCanvas::DrawTexture(int texture_id,
int texture_handle,
int vertex_buffer,
float alpha_multiplier) {}
int FakeCanvas::GetVersion() const {
return 0;
}
int FakeCanvas::GetMaxTextureSize() const {
return 0;
}
base::WeakPtr<Canvas> FakeCanvas::GetWeakPtr() {
DCHECK(thread_checker_.CalledOnValidThread());
return weak_factory_.GetWeakPtr();
}
} // namespace remoting
// 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.
#ifndef REMOTING_CLIENT_DISPLAY_FAKE_CANVAS_H_
#define REMOTING_CLIENT_DISPLAY_FAKE_CANVAS_H_
#include <array>
#include "base/macros.h"
#include "base/threading/thread_checker.h"
#include "remoting/client/display/gl_canvas.h"
#include "remoting/client/display/sys_opengl.h"
namespace remoting {
class FakeCanvas : public Canvas {
public:
FakeCanvas();
~FakeCanvas() override;
// Drawable implementation.
void Clear() override;
void SetTransformationMatrix(const std::array<float, 9>& matrix) override;
void SetViewSize(int width, int height) override;
void DrawTexture(int texture_id,
int texture_handle,
int vertex_buffer,
float alpha_multiplier) override;
int GetVersion() const override;
int GetMaxTextureSize() const override;
base::WeakPtr<Canvas> GetWeakPtr() override;
private:
base::ThreadChecker thread_checker_;
base::WeakPtrFactory<Canvas> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FakeCanvas);
};
} // namespace remoting
#endif // REMOTING_CLIENT_DISPLAY_FAKE_CANVAS_H_
......@@ -65,7 +65,8 @@ const char kDrawTexFrag[] =
namespace remoting {
GlCanvas::GlCanvas(int gl_version) : gl_version_(gl_version) {
GlCanvas::GlCanvas(int gl_version)
: gl_version_(gl_version), weak_factory_(this) {
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
vertex_shader_ = CompileShader(GL_VERTEX_SHADER, kTexCoordToViewVert);
......@@ -96,6 +97,17 @@ GlCanvas::~GlCanvas() {
glDeleteShader(fragment_shader_);
}
void GlCanvas::Clear() {
#ifndef NDEBUG
// Set the background clear color to bright green for debugging purposes.
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
#else
// Set the background clear color to black.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
#endif
glClear(GL_COLOR_BUFFER_BIT);
}
void GlCanvas::SetTransformationMatrix(const std::array<float, 9>& matrix) {
DCHECK(thread_checker_.CalledOnValidThread());
std::array<float, 9> transposed_matrix = matrix;
......@@ -114,8 +126,8 @@ void GlCanvas::SetViewSize(int width, int height) {
}
void GlCanvas::DrawTexture(int texture_id,
GLuint texture_handle,
GLuint vertex_buffer,
int texture_handle,
int vertex_buffer,
float alpha_multiplier) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!view_size_set_ || !transformation_set_) {
......@@ -137,7 +149,7 @@ void GlCanvas::DrawTexture(int texture_id,
glBindTexture(GL_TEXTURE_2D, 0);
}
int GlCanvas::GetGlVersion() const {
int GlCanvas::GetVersion() const {
return gl_version_;
}
......@@ -145,4 +157,9 @@ int GlCanvas::GetMaxTextureSize() const {
return max_texture_size_;
}
base::WeakPtr<Canvas> GlCanvas::GetWeakPtr() {
DCHECK(thread_checker_.CalledOnValidThread());
return weak_factory_.GetWeakPtr();
}
} // namespace remoting
......@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/threading/thread_checker.h"
#include "remoting/client/display/canvas.h"
#include "remoting/client/display/sys_opengl.h"
namespace remoting {
......@@ -17,52 +18,23 @@ namespace remoting {
// draw textures on the canvas.
// Must be constructed after the OpenGL surface is created and destroyed before
// the surface is destroyed.
class GlCanvas {
class GlCanvas : public Canvas {
public:
// gl_version: version number of the OpenGL ES context. Either 2 or 3.
GlCanvas(int gl_version);
~GlCanvas() override;
~GlCanvas();
// Sets the transformation matrix. This matrix defines how the canvas should
// be shown on the view.
// 3 by 3 transformation matrix, [ m0, m1, m2, m3, m4, m5, m6, m7, m8 ].
// The matrix will be multiplied with the positions (with projective space,
// (x, y, 1)) to draw the textures with the right zoom and pan configuration.
//
// | m0, m1, m2, | | x |
// | m3, m4, m5, | * | y |
// | m6, m7, m8 | | 1 |
//
// For a typical transformation matrix such that m1=m3=m6=m7=0 and m8=1, m0
// and m4 defines the scaling factor of the canvas and m2 and m5 defines the
// offset of the upper-left corner in pixel.
void SetTransformationMatrix(const std::array<float, 9>& matrix);
// Sets the size of the view in pixels.
void SetViewSize(int width, int height);
// Draws the texture on the canvas. Nothing will happen if
// SetNormalizedTransformation() has not been called.
// vertex_buffer: reference to the 2x4x2 float vertex buffer.
// [ four (x, y) position of the texture vertices in pixel
// with respect to the canvas,
// four (x, y) position of the vertices in percentage
// defining the visible area of the texture ]
// alpha_multiplier: Will be multiplied with the alpha channel of the texture.
// Passing 1 means no change of the transparency of the
// texture.
// Canvas implementation.
void Clear() override;
void SetTransformationMatrix(const std::array<float, 9>& matrix) override;
void SetViewSize(int width, int height) override;
void DrawTexture(int texture_id,
GLuint texture_handle,
GLuint vertex_buffer,
float alpha_multiplier);
// Returns the version number of current OpenGL ES context. Either 2 or 3.
int GetGlVersion() const;
// Returns the maximum texture resolution limitation. Neither the width nor
// the height of the texture can exceed this limitation.
int GetMaxTextureSize() const;
int texture_handle,
int vertex_buffer,
float alpha_multiplier) override;
int GetVersion() const override;
int GetMaxTextureSize() const override;
base::WeakPtr<Canvas> GetWeakPtr() override;
private:
int gl_version_;
......@@ -85,6 +57,7 @@ class GlCanvas {
GLuint tex_cord_location_;
base::ThreadChecker thread_checker_;
base::WeakPtrFactory<Canvas> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(GlCanvas);
};
......
......@@ -18,7 +18,7 @@ namespace {
const int kDefaultCursorDataSize = 32 * 32 * GlRenderLayer::kBytesPerPixel;
} // namespace
GlCursor::GlCursor() {}
GlCursor::GlCursor() : weak_factory_(this) {}
GlCursor::~GlCursor() {}
......@@ -68,7 +68,7 @@ void GlCursor::SetCursorVisible(bool visible) {
visible_ = visible;
}
void GlCursor::SetCanvas(GlCanvas* canvas) {
void GlCursor::SetCanvas(base::WeakPtr<Canvas> canvas) {
if (!canvas) {
layer_.reset();
return;
......@@ -80,10 +80,16 @@ void GlCursor::SetCanvas(GlCanvas* canvas) {
SetCursorPosition(cursor_x_, cursor_y_);
}
void GlCursor::Draw() {
bool GlCursor::Draw() {
DCHECK(thread_checker_.CalledOnValidThread());
if (layer_ && current_cursor_data_ && visible_) {
layer_->Draw(1.f);
}
return false;
}
int GlCursor::GetZIndex() {
return Drawable::ZIndex::CURSOR;
}
void GlCursor::SetCurrentCursorShape(bool size_changed) {
......@@ -98,4 +104,9 @@ void GlCursor::SetCurrentCursorShape(bool size_changed) {
}
}
base::WeakPtr<Drawable> GlCursor::GetWeakPtr() {
DCHECK(thread_checker_.CalledOnValidThread());
return weak_factory_.GetWeakPtr();
}
} // namespace remoting
......@@ -10,6 +10,9 @@
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "remoting/client/display/drawable.h"
namespace remoting {
......@@ -17,14 +20,14 @@ namespace protocol {
class CursorShapeInfo;
} // namespace protocol
class GlCanvas;
class Canvas;
class GlRenderLayer;
// This class draws the cursor on the canvas.
class GlCursor {
class GlCursor : public Drawable {
public:
GlCursor();
~GlCursor();
~GlCursor() override;
void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape);
......@@ -35,12 +38,11 @@ class GlCursor {
// Draw() will do nothing if cursor is not visible.
void SetCursorVisible(bool visible);
// Sets the canvas on which the cursor will be drawn. Resumes the current
// state of the cursor to the context of the new canvas.
// If |canvas| is nullptr, nothing will happen when calling Draw().
void SetCanvas(GlCanvas* canvas);
void Draw();
// Drawable implementation.
void SetCanvas(base::WeakPtr<Canvas> canvas) override;
bool Draw() override;
int GetZIndex() override;
base::WeakPtr<Drawable> GetWeakPtr() override;
private:
void SetCurrentCursorShape(bool size_changed);
......@@ -59,6 +61,9 @@ class GlCursor {
float cursor_x_ = 0;
float cursor_y_ = 0;
base::ThreadChecker thread_checker_;
base::WeakPtrFactory<Drawable> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(GlCursor);
};
......
......@@ -9,7 +9,7 @@
#include <array>
#include "base/logging.h"
#include "remoting/client/display/gl_canvas.h"
#include "remoting/client/display/canvas.h"
#include "remoting/client/display/gl_cursor_feedback_texture.h"
#include "remoting/client/display/gl_math.h"
#include "remoting/client/display/gl_render_layer.h"
......@@ -43,11 +43,11 @@ float GetExpansionCoefficient(float progress) {
namespace remoting {
GlCursorFeedback::GlCursorFeedback() {}
GlCursorFeedback::GlCursorFeedback() : weak_factory_(this) {}
GlCursorFeedback::~GlCursorFeedback() {}
void GlCursorFeedback::SetCanvas(GlCanvas* canvas) {
void GlCursorFeedback::SetCanvas(base::WeakPtr<Canvas> canvas) {
if (!canvas) {
layer_.reset();
return;
......@@ -67,6 +67,7 @@ void GlCursorFeedback::StartAnimation(float x, float y, float diameter) {
}
bool GlCursorFeedback::Draw() {
DCHECK(thread_checker_.CalledOnValidThread());
if (!layer_ || animation_start_time_.is_null()) {
return false;
}
......@@ -89,4 +90,13 @@ bool GlCursorFeedback::Draw() {
return true;
}
int GlCursorFeedback::GetZIndex() {
return Drawable::ZIndex::CURSOR_FEEDBACK;
}
base::WeakPtr<Drawable> GlCursorFeedback::GetWeakPtr() {
DCHECK(thread_checker_.CalledOnValidThread());
return weak_factory_.GetWeakPtr();
}
} // namespace remoting
......@@ -5,34 +5,34 @@
#ifndef REMOTING_CLIENT_DISPLAY_GL_CURSOR_FEEDBACK_H_
#define REMOTING_CLIENT_DISPLAY_GL_CURSOR_FEEDBACK_H_
#include <stdint.h>
#include <cstdint>
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "remoting/client/display/drawable.h"
namespace remoting {
class GlCanvas;
class Canvas;
class GlRenderLayer;
// This class draws the cursor feedback on the canvas.
class GlCursorFeedback {
class GlCursorFeedback : public Drawable {
public:
GlCursorFeedback();
~GlCursorFeedback();
// Sets the canvas on which the cursor feedback will be drawn. Resumes the
// feedback texture to the context of the new canvas.
// If |canvas| is nullptr, nothing will happen when calling Draw().
void SetCanvas(GlCanvas* canvas);
~GlCursorFeedback() override;
void StartAnimation(float x, float y, float diameter);
// Returns true if animation is not finished, false otherwise. Does nothing
// if the animation has stopped.
bool Draw();
// Drawable implementation.
void SetCanvas(base::WeakPtr<Canvas> canvas) override;
bool Draw() override;
int GetZIndex() override;
base::WeakPtr<Drawable> GetWeakPtr() override;
private:
std::unique_ptr<GlRenderLayer> layer_;
......@@ -41,6 +41,9 @@ class GlCursorFeedback {
float cursor_y_ = 0;
base::TimeTicks animation_start_time_;
base::ThreadChecker thread_checker_;
base::WeakPtrFactory<Drawable> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(GlCursorFeedback);
};
......
......@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "remoting/client/display/gl_canvas.h"
#include "remoting/client/display/canvas.h"
#include "remoting/client/display/gl_math.h"
#include "remoting/client/display/gl_render_layer.h"
#include "remoting/client/display/gl_texture_ids.h"
......@@ -57,11 +57,11 @@ struct GlDesktop::GlDesktopTextureContainer {
webrtc::DesktopRect rect;
};
GlDesktop::GlDesktop() {}
GlDesktop::GlDesktop() : weak_factory_(this) {}
GlDesktop::~GlDesktop() {}
void GlDesktop::SetCanvas(GlCanvas* canvas) {
void GlDesktop::SetCanvas(base::WeakPtr<Canvas> canvas) {
last_desktop_size_.set(0, 0);
textures_.clear();
canvas_ = canvas;
......@@ -83,12 +83,18 @@ void GlDesktop::SetVideoFrame(const webrtc::DesktopFrame& frame) {
}
}
void GlDesktop::Draw() {
bool GlDesktop::Draw() {
DCHECK(thread_checker_.CalledOnValidThread());
if (!textures_.empty() && !last_desktop_size_.is_empty()) {
for (std::unique_ptr<GlDesktopTextureContainer>& texture : textures_) {
texture->layer->Draw(1.0f);
}
}
return false;
}
int GlDesktop::GetZIndex() {
return Drawable::ZIndex::DESKTOP;
}
void GlDesktop::ReallocateTextures(const webrtc::DesktopSize& size) {
......@@ -112,9 +118,10 @@ void GlDesktop::ReallocateTextures(const webrtc::DesktopSize& size) {
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});
std::unique_ptr<GlDesktopTextureContainer> container = base::WrapUnique(
new GlDesktopTextureContainer{base::MakeUnique<GlRenderLayer>(
texture_id, canvas_->GetWeakPtr()),
rect});
FillRectangleVertexPositions(rect.left(), rect.top(), rect.width(),
rect.height(), &positions);
container->layer->SetVertexPositions(positions);
......@@ -124,4 +131,9 @@ void GlDesktop::ReallocateTextures(const webrtc::DesktopSize& size) {
}
}
base::WeakPtr<Drawable> GlDesktop::GetWeakPtr() {
DCHECK(thread_checker_.CalledOnValidThread());
return weak_factory_.GetWeakPtr();
}
} // namespace remoting
......@@ -9,6 +9,9 @@
#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "remoting/client/display/drawable.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
namespace webrtc {
......@@ -17,24 +20,22 @@ class DesktopFrame;
namespace remoting {
class GlCanvas;
class Canvas;
// This class draws the desktop on the canvas.
class GlDesktop {
class GlDesktop : public Drawable {
public:
GlDesktop();
virtual ~GlDesktop();
~GlDesktop() override;
// |frame| can be either a full frame or updated regions only frame.
void SetVideoFrame(const webrtc::DesktopFrame& frame);
// Sets the canvas on which the desktop will be drawn. Caller must feed a
// full desktop frame after calling this function.
// If |canvas| is nullptr, nothing will happen when calling Draw().
void SetCanvas(GlCanvas* canvas);
// Draws the desktop on the canvas.
void Draw();
// Drawable implementation.
void SetCanvas(base::WeakPtr<Canvas> canvas) override;
bool Draw() override;
int GetZIndex() override;
base::WeakPtr<Drawable> GetWeakPtr() override;
private:
struct GlDesktopTextureContainer;
......@@ -45,7 +46,9 @@ class GlDesktop {
webrtc::DesktopSize last_desktop_size_;
int max_texture_size_ = 0;
GlCanvas* canvas_ = nullptr;
base::WeakPtr<Canvas> canvas_ = nullptr;
base::ThreadChecker thread_checker_;
base::WeakPtrFactory<Drawable> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(GlDesktop);
};
......
......@@ -39,7 +39,7 @@ void PackDirtyRegion(uint8_t* dest,
} // namespace
GlRenderLayer::GlRenderLayer(int texture_id, GlCanvas* canvas)
GlRenderLayer::GlRenderLayer(int texture_id, base::WeakPtr<Canvas> canvas)
: texture_id_(texture_id), canvas_(canvas) {
texture_handle_ = CreateTexture();
buffer_handle_ = CreateBuffer(kVertices, sizeof(kVertices));
......@@ -146,7 +146,7 @@ const uint8_t* GlRenderLayer::PrepareTextureBuffer(
return data;
}
if (stride_multiple_of_bytes_per_pixel && canvas_->GetGlVersion() >= 3) {
if (stride_multiple_of_bytes_per_pixel && canvas_->GetVersion() >= 3) {
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / kBytesPerPixel);
*should_reset_row_length = true;
return data;
......
......@@ -9,11 +9,13 @@
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "remoting/client/display/sys_opengl.h"
namespace remoting {
class GlCanvas;
class Canvas;
// This class is for drawing a texture on the canvas. Must be deleted before the
// canvas is deleted.
......@@ -23,7 +25,7 @@ class GlRenderLayer {
// texture_id: An integer in range [0, GL_MAX_TEXTURE_IMAGE_UNITS], defining
// which slot to store the texture.
GlRenderLayer(int texture_id, GlCanvas* canvas);
GlRenderLayer(int texture_id, base::WeakPtr<Canvas> canvas);
~GlRenderLayer();
// Sets the texture (RGBA 8888) to be drawn. Please use UpdateTexture() if the
......@@ -78,7 +80,7 @@ class GlRenderLayer {
bool* should_reset_row_length);
int texture_id_;
GlCanvas* canvas_;
base::WeakPtr<Canvas> canvas_;
GLuint texture_handle_;
GLuint buffer_handle_;
......
......@@ -4,9 +4,12 @@
#include "remoting/client/display/gl_renderer.h"
#include <algorithm>
#include "base/bind.h"
#include "base/logging.h"
#include "base/threading/thread_task_runner_handle.h"
#include "remoting/client/display/drawable.h"
#include "remoting/client/display/gl_canvas.h"
#include "remoting/client/display/gl_math.h"
#include "remoting/client/display/gl_renderer_delegate.h"
......@@ -15,14 +18,22 @@
namespace remoting {
namespace {
bool CompareDrawableZOrder(base::WeakPtr<Drawable> a,
base::WeakPtr<Drawable> b) {
return a->GetZIndex() < b->GetZIndex();
}
} // namespace
GlRenderer::GlRenderer() :
weak_factory_(this) {
weak_ptr_ = weak_factory_.GetWeakPtr();
thread_checker_.DetachFromThread();
}
GlRenderer::~GlRenderer() {
}
GlRenderer::~GlRenderer() {}
void GlRenderer::SetDelegate(base::WeakPtr<GlRendererDelegate> delegate) {
DCHECK(!delegate_);
......@@ -90,19 +101,12 @@ void GlRenderer::OnCursorShapeChanged(const protocol::CursorShapeInfo& shape) {
RequestRender();
}
void GlRenderer::OnSurfaceCreated(int gl_version) {
void GlRenderer::OnSurfaceCreated(std::unique_ptr<Canvas> canvas) {
DCHECK(thread_checker_.CalledOnValidThread());
#ifndef NDEBUG
// Set the background clear color to bright green for debugging purposes.
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
#else
// Set the background clear color to black.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
#endif
canvas_.reset(new GlCanvas(gl_version));
desktop_.SetCanvas(canvas_.get());
cursor_.SetCanvas(canvas_.get());
cursor_feedback_.SetCanvas(canvas_.get());
canvas_ = std::move(canvas);
for (auto& drawable : drawables_) {
drawable->SetCanvas(canvas_->GetWeakPtr());
}
}
void GlRenderer::OnSurfaceChanged(int view_width, int view_height) {
......@@ -137,6 +141,12 @@ void GlRenderer::RequestRender() {
render_scheduled_ = true;
}
void GlRenderer::AddDrawable(base::WeakPtr<Drawable> drawable) {
drawable->SetCanvas(canvas_ ? canvas_->GetWeakPtr() : nullptr);
drawables_.push_back(drawable);
std::sort(drawables_.begin(), drawables_.end(), CompareDrawableZOrder);
}
void GlRenderer::OnRender() {
DCHECK(thread_checker_.CalledOnValidThread());
render_scheduled_ = false;
......@@ -145,18 +155,13 @@ void GlRenderer::OnRender() {
}
if (canvas_) {
glClear(GL_COLOR_BUFFER_BIT);
// Layers will be drawn from bottom to top.
desktop_.Draw();
// |cursor_feedback_| should be drawn before |cursor_| so that the cursor
// won't be covered by the feedback animation.
if (cursor_feedback_.Draw()) {
RequestRender();
canvas_->Clear();
// Draw each drawable in order.
for (auto& drawable : drawables_) {
if (drawable->Draw()) {
RequestRender();
}
}
cursor_.Draw();
}
delegate_->OnFrameRendered();
......@@ -167,4 +172,12 @@ void GlRenderer::OnRender() {
}
}
std::unique_ptr<GlRenderer> GlRenderer::CreateGlRendererWithDesktop() {
std::unique_ptr<GlRenderer> renderer(new GlRenderer());
renderer->AddDrawable(renderer->desktop_.GetWeakPtr());
renderer->AddDrawable(renderer->cursor_.GetWeakPtr());
renderer->AddDrawable(renderer->cursor_feedback_.GetWeakPtr());
return renderer;
}
} // namespace remoting
......@@ -6,6 +6,7 @@
#define REMOTING_CLIENT_DISPLAY_GL_RENDERER_H_
#include <queue>
#include <vector>
#include "base/callback.h"
#include "base/macros.h"
......@@ -26,7 +27,7 @@ namespace protocol {
class CursorShapeInfo;
} // namespace protocol
class GlCanvas;
class Canvas;
class GlRendererDelegate;
class GlRendererTest;
......@@ -82,7 +83,7 @@ class GlRenderer {
// lost after calling this function.
// Caller must call OnSurfaceDestroyed() before calling this function if the
// surface is recreated.
void OnSurfaceCreated(int gl_version);
void OnSurfaceCreated(std::unique_ptr<Canvas> canvas);
// Sets the size of the view. Called right after OnSurfaceCreated() or
// whenever the view size is changed.
......@@ -91,9 +92,14 @@ class GlRenderer {
// Called when the surface is destroyed.
void OnSurfaceDestroyed();
void AddDrawable(base::WeakPtr<Drawable> drawable);
// Returns the weak pointer to be used on the display thread.
base::WeakPtr<GlRenderer> GetWeakPtr();
// Convenience method to create a Renderer with standard desktop components.
static std::unique_ptr<GlRenderer> CreateGlRendererWithDesktop();
private:
friend class GlRendererTest;
......@@ -119,12 +125,14 @@ class GlRenderer {
int canvas_width_ = 0;
int canvas_height_ = 0;
std::unique_ptr<GlCanvas> canvas_;
std::unique_ptr<Canvas> canvas_;
GlCursor cursor_;
GlCursorFeedback cursor_feedback_;
GlDesktop desktop_;
std::vector<base::WeakPtr<Drawable>> drawables_;
base::ThreadChecker thread_checker_;
base::WeakPtr<GlRenderer> weak_ptr_;
base::WeakPtrFactory<GlRenderer> weak_factory_;
......
......@@ -10,6 +10,7 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "remoting/client/display/fake_canvas.h"
#include "remoting/client/display/gl_renderer_delegate.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
......@@ -67,8 +68,43 @@ class FakeGlRendererDelegate : public GlRendererDelegate {
int canvas_height_ = 0;
base::Closure on_frame_rendered_callback_;
base::WeakPtrFactory<FakeGlRendererDelegate> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FakeGlRendererDelegate);
};
class FakeDrawable : public Drawable {
public:
FakeDrawable() : weak_factory_(this) {}
void SetId(int id) { id_ = id; }
int GetId() { return id_; }
base::WeakPtr<Drawable> GetWeakPtr() override {
return weak_factory_.GetWeakPtr();
}
void SetCanvas(base::WeakPtr<Canvas> canvas) override {}
bool Draw() override {
drawn_++;
return false;
}
void SetZIndex(int z_index) { z_index_ = z_index; }
int GetZIndex() override { return z_index_; }
int DrawnCount() { return drawn_; }
private:
int drawn_ = 0;
int id_ = -1;
int z_index_ = -1;
base::WeakPtrFactory<FakeDrawable> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FakeDrawable);
};
class GlRendererTest : public testing::Test {
......@@ -76,6 +112,8 @@ class GlRendererTest : public testing::Test {
void SetUp() override;
void SetDesktopFrameWithSize(const webrtc::DesktopSize& size);
void PostSetDesktopFrameTasks(const webrtc::DesktopSize& size, int count);
int GetDrawablesCount();
std::vector<base::WeakPtr<Drawable>> GetDrawables();
protected:
void RequestRender();
......@@ -103,6 +141,14 @@ void GlRendererTest::RequestRender() {
renderer_->RequestRender();
}
int GlRendererTest::GetDrawablesCount() {
return renderer_->drawables_.size();
}
std::vector<base::WeakPtr<Drawable>> GlRendererTest::GetDrawables() {
return renderer_->drawables_;
}
void GlRendererTest::SetDesktopFrameWithSize(const webrtc::DesktopSize& size) {
renderer_->OnFrameReceived(
base::MakeUnique<webrtc::BasicDesktopFrame>(size),
......@@ -167,24 +213,24 @@ TEST_F(GlRendererTest, TestRequestRenderOnlyScheduleOnce) {
TEST_F(GlRendererTest, TestDelegateOnSizeChanged) {
SetDesktopFrameWithSize(webrtc::DesktopSize(16, 16));
EXPECT_EQ(1, delegate_.on_size_changed_call_count());
EXPECT_EQ(16, delegate_.canvas_width());
EXPECT_EQ(16, delegate_.canvas_height());
ASSERT_EQ(1, delegate_.on_size_changed_call_count());
ASSERT_EQ(16, delegate_.canvas_width());
ASSERT_EQ(16, delegate_.canvas_height());
SetDesktopFrameWithSize(webrtc::DesktopSize(16, 16));
EXPECT_EQ(1, delegate_.on_size_changed_call_count());
EXPECT_EQ(16, delegate_.canvas_width());
EXPECT_EQ(16, delegate_.canvas_height());
ASSERT_EQ(1, delegate_.on_size_changed_call_count());
ASSERT_EQ(16, delegate_.canvas_width());
ASSERT_EQ(16, delegate_.canvas_height());
SetDesktopFrameWithSize(webrtc::DesktopSize(32, 32));
EXPECT_EQ(2, delegate_.on_size_changed_call_count());
EXPECT_EQ(32, delegate_.canvas_width());
EXPECT_EQ(32, delegate_.canvas_height());
ASSERT_EQ(2, delegate_.on_size_changed_call_count());
ASSERT_EQ(32, delegate_.canvas_width());
ASSERT_EQ(32, delegate_.canvas_height());
renderer_->RequestCanvasSize();
EXPECT_EQ(3, delegate_.on_size_changed_call_count());
EXPECT_EQ(32, delegate_.canvas_width());
EXPECT_EQ(32, delegate_.canvas_height());
ASSERT_EQ(3, delegate_.on_size_changed_call_count());
ASSERT_EQ(32, delegate_.canvas_width());
ASSERT_EQ(32, delegate_.canvas_height());
}
TEST_F(GlRendererTest, TestOnFrameReceivedDoneCallbacks) {
......@@ -199,10 +245,110 @@ TEST_F(GlRendererTest, TestOnFrameReceivedDoneCallbacks) {
PostSetDesktopFrameTasks(webrtc::DesktopSize(16, 16), 20);
RunUntilRendered();
EXPECT_EQ(2, delegate_.on_frame_rendered_call_count());
EXPECT_EQ(21, on_desktop_frame_processed_call_count());
ASSERT_EQ(2, delegate_.on_frame_rendered_call_count());
ASSERT_EQ(21, on_desktop_frame_processed_call_count());
}
// TODO(yuweih): Add tests to validate the rendered output.
TEST_F(GlRendererTest, TestAddDrawable) {
std::unique_ptr<FakeDrawable> drawable0 = base::MakeUnique<FakeDrawable>();
drawable0->SetId(0);
renderer_->AddDrawable(drawable0->GetWeakPtr());
ASSERT_EQ(1, GetDrawablesCount());
}
TEST_F(GlRendererTest, TestAddDrawableDefaultOrder) {
std::unique_ptr<FakeDrawable> drawable0 = base::MakeUnique<FakeDrawable>();
drawable0->SetId(0);
renderer_->AddDrawable(drawable0->GetWeakPtr());
ASSERT_EQ(1, GetDrawablesCount());
std::unique_ptr<FakeDrawable> drawable1 = base::MakeUnique<FakeDrawable>();
drawable1->SetId(1);
renderer_->AddDrawable(drawable1->GetWeakPtr());
ASSERT_EQ(2, GetDrawablesCount());
std::unique_ptr<FakeDrawable> drawable2 = base::MakeUnique<FakeDrawable>();
drawable2->SetId(2);
renderer_->AddDrawable(drawable2->GetWeakPtr());
ASSERT_EQ(3, GetDrawablesCount());
int i = 0;
for (auto& drawable : GetDrawables()) {
FakeDrawable* fg = static_cast<FakeDrawable*>(drawable.get());
ASSERT_EQ(i, fg->GetId());
i++;
}
ASSERT_EQ(3, i);
}
TEST_F(GlRendererTest, TestAddDrawableOrder) {
std::unique_ptr<FakeDrawable> drawable2 = base::MakeUnique<FakeDrawable>();
drawable2->SetId(2);
drawable2->SetZIndex(2);
renderer_->AddDrawable(drawable2->GetWeakPtr());
ASSERT_EQ(1, GetDrawablesCount());
std::unique_ptr<FakeDrawable> drawable0 = base::MakeUnique<FakeDrawable>();
drawable0->SetId(0);
renderer_->AddDrawable(drawable0->GetWeakPtr());
ASSERT_EQ(2, GetDrawablesCount());
std::unique_ptr<FakeDrawable> drawable1 = base::MakeUnique<FakeDrawable>();
drawable1->SetId(1);
drawable1->SetZIndex(1);
renderer_->AddDrawable(drawable1->GetWeakPtr());
ASSERT_EQ(3, GetDrawablesCount());
int i = 0;
for (auto& drawable : GetDrawables()) {
FakeDrawable* fg = static_cast<FakeDrawable*>(drawable.get());
ASSERT_EQ(i, fg->GetId());
i++;
}
ASSERT_EQ(3, i);
}
TEST_F(GlRendererTest, TestAddDrawableDrawn) {
std::unique_ptr<Canvas> fakeCanvas = base::MakeUnique<FakeCanvas>();
renderer_->OnSurfaceCreated(std::move(fakeCanvas));
delegate_.can_render_frame_ = true;
PostSetDesktopFrameTasks(webrtc::DesktopSize(16, 16), 1);
std::unique_ptr<FakeDrawable> drawable0 = base::MakeUnique<FakeDrawable>();
drawable0->SetId(3);
renderer_->AddDrawable(drawable0->GetWeakPtr());
RequestRender();
RunTasksInCurrentQueue();
std::unique_ptr<FakeDrawable> drawable1 = base::MakeUnique<FakeDrawable>();
drawable1->SetId(2);
drawable1->SetZIndex(1);
renderer_->AddDrawable(drawable1->GetWeakPtr());
RequestRender();
RunTasksInCurrentQueue();
std::unique_ptr<FakeDrawable> drawable2 = base::MakeUnique<FakeDrawable>();
drawable2->SetId(1);
drawable2->SetZIndex(2);
renderer_->AddDrawable(drawable2->GetWeakPtr());
ASSERT_EQ(3, GetDrawablesCount());
RequestRender();
RunTasksInCurrentQueue();
for (auto& drawable : GetDrawables()) {
FakeDrawable* fg = static_cast<FakeDrawable*>(drawable.get());
EXPECT_EQ(fg->GetId(), fg->DrawnCount());
}
}
TEST_F(GlRendererTest, TestCreateGlRendererWithDesktop) {
renderer_ = GlRenderer::CreateGlRendererWithDesktop();
renderer_->SetDelegate(delegate_.GetWeakPtr());
ASSERT_EQ(3, GetDrawablesCount());
}
// TODO(nicholss): Add a test where the drawable is destructed and the renderer
// gets a dead weakptr.
} // namespace remoting
......@@ -13,6 +13,7 @@
#include "base/memory/ptr_util.h"
#include "jni/GlDisplay_jni.h"
#include "remoting/client/cursor_shape_stub_proxy.h"
#include "remoting/client/display/gl_canvas.h"
#include "remoting/client/dual_buffer_frame_consumer.h"
#include "remoting/client/jni/chromoting_jni_runtime.h"
#include "remoting/client/jni/egl_thread_context.h"
......@@ -62,7 +63,7 @@ class JniGlDisplayHandler::Core : public protocol::CursorShapeStub,
ANativeWindow* window_ = nullptr;
std::unique_ptr<EglThreadContext> egl_context_;
GlRenderer renderer_;
std::unique_ptr<GlRenderer> renderer_;
// Used on display thread.
base::WeakPtr<Core> weak_ptr_;
......@@ -74,12 +75,13 @@ class JniGlDisplayHandler::Core : public protocol::CursorShapeStub,
JniGlDisplayHandler::Core::Core(ChromotingJniRuntime* runtime,
base::WeakPtr<JniGlDisplayHandler> shell)
: runtime_(runtime), shell_(shell), weak_factory_(this) {
renderer_ = GlRenderer::CreateGlRendererWithDesktop();
weak_ptr_ = weak_factory_.GetWeakPtr();
renderer_.SetDelegate(weak_ptr_);
renderer_->SetDelegate(weak_ptr_);
owned_frame_consumer_.reset(new DualBufferFrameConsumer(
base::Bind(&GlRenderer::OnFrameReceived, renderer_.GetWeakPtr()),
runtime_->display_task_runner(),
protocol::FrameConsumer::PixelFormat::FORMAT_RGBA));
base::Bind(&GlRenderer::OnFrameReceived, renderer_->GetWeakPtr()),
runtime_->display_task_runner(),
protocol::FrameConsumer::PixelFormat::FORMAT_RGBA));
frame_consumer_ = owned_frame_consumer_->GetWeakPtr();
}
......@@ -107,7 +109,7 @@ void JniGlDisplayHandler::Core::OnSizeChanged(int width, int height) {
void JniGlDisplayHandler::Core::SetCursorShape(
const protocol::CursorShapeInfo& cursor_shape) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_.OnCursorShapeChanged(cursor_shape);
renderer_->OnCursorShapeChanged(cursor_shape);
}
std::unique_ptr<protocol::FrameConsumer>
......@@ -121,12 +123,15 @@ void JniGlDisplayHandler::Core::SurfaceCreated(
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
DCHECK(!egl_context_);
DCHECK(!window_);
renderer_.RequestCanvasSize();
renderer_->RequestCanvasSize();
window_ = ANativeWindow_fromSurface(base::android::AttachCurrentThread(),
surface.obj());
egl_context_.reset(new EglThreadContext());
egl_context_->BindToWindow(window_);
renderer_.OnSurfaceCreated(static_cast<int>(egl_context_->client_version()));
renderer_->OnSurfaceCreated(base::MakeUnique<GlCanvas>(
static_cast<int>(egl_context_->client_version())));
runtime_->network_task_runner()->PostTask(
FROM_HERE, base::Bind(&DualBufferFrameConsumer::RequestFullDesktopFrame,
frame_consumer_));
......@@ -134,14 +139,14 @@ void JniGlDisplayHandler::Core::SurfaceCreated(
void JniGlDisplayHandler::Core::SurfaceChanged(int width, int height) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_.OnSurfaceChanged(width, height);
renderer_->OnSurfaceChanged(width, height);
}
void JniGlDisplayHandler::Core::SurfaceDestroyed() {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
DCHECK(egl_context_);
DCHECK(window_);
renderer_.OnSurfaceDestroyed();
renderer_->OnSurfaceDestroyed();
egl_context_.reset();
ANativeWindow_release(window_);
window_ = nullptr;
......@@ -150,24 +155,24 @@ void JniGlDisplayHandler::Core::SurfaceDestroyed() {
void JniGlDisplayHandler::Core::SetTransformation(
const std::array<float, 9>& matrix) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_.OnPixelTransformationChanged(matrix);
renderer_->OnPixelTransformationChanged(matrix);
}
void JniGlDisplayHandler::Core::MoveCursor(float x, float y) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_.OnCursorMoved(x, y);
renderer_->OnCursorMoved(x, y);
}
void JniGlDisplayHandler::Core::SetCursorVisibility(bool visible) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_.OnCursorVisibilityChanged(visible);
renderer_->OnCursorVisibilityChanged(visible);
}
void JniGlDisplayHandler::Core::StartInputFeedback(float x,
float y,
float diameter) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_.OnCursorInputFeedback(x, y, diameter);
renderer_->OnCursorInputFeedback(x, y, diameter);
}
base::WeakPtr<JniGlDisplayHandler::Core>
......
......@@ -4,6 +4,13 @@
import("//third_party/protobuf/proto_library.gni")
group("proto_lite") {
public_deps = [
":proto",
"//third_party/protobuf:protobuf_lite",
]
}
proto_library("proto") {
sources = [
"audio.proto",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment