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 @@ ...@@ -4,6 +4,8 @@
source_set("display") { source_set("display") {
sources = [ sources = [
"canvas.h",
"drawable.h",
"gl_canvas.cc", "gl_canvas.cc",
"gl_canvas.h", "gl_canvas.h",
"gl_cursor.cc", "gl_cursor.cc",
...@@ -22,6 +24,7 @@ source_set("display") { ...@@ -22,6 +24,7 @@ source_set("display") {
"gl_render_layer.h", "gl_render_layer.h",
"gl_renderer.cc", "gl_renderer.cc",
"gl_renderer.h", "gl_renderer.h",
"sys_opengl.h",
] ]
deps = [ deps = [
...@@ -30,7 +33,11 @@ source_set("display") { ...@@ -30,7 +33,11 @@ source_set("display") {
"//third_party/webrtc/base:rtc_base", "//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) { if (is_linux) {
libs = [ "GL" ] libs = [ "GL" ]
...@@ -52,30 +59,33 @@ source_set("display") { ...@@ -52,30 +59,33 @@ source_set("display") {
} }
} }
source_set("unit_tests") { if (is_win) {
testonly = true # Windows clang builder fails to link the test binary with ANGLE GLESv2.
# crbug.com/642027
sources = [ group("unit_tests") {
"gl_renderer_unittest.cc", deps = []
] }
} else {
source_set("unit_tests") {
testonly = true
configs += [ sources = [
"//remoting/build/config:version", "fake_canvas.cc",
"//remoting/build/config:enable_webrtc_remoting_client", "fake_canvas.h",
] "gl_renderer_unittest.cc",
]
deps = [ configs += [
":display", "//remoting/build/config:version",
"//remoting/proto", "//remoting/build/config:enable_webrtc_remoting_client",
"//testing/gmock", ]
"//testing/gtest",
"//third_party/webrtc/base:rtc_base",
]
if (is_win) { deps = [
# Windows clang builder fails to link the test binary with ANGLE GLESv2. ":display",
# crbug.com/642027 "//remoting/proto",
sources -= [ "gl_renderer_unittest.cc" ] "//testing/gmock",
deps -= [ ":display" ] "//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[] = ...@@ -65,7 +65,8 @@ const char kDrawTexFrag[] =
namespace remoting { 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_); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
vertex_shader_ = CompileShader(GL_VERTEX_SHADER, kTexCoordToViewVert); vertex_shader_ = CompileShader(GL_VERTEX_SHADER, kTexCoordToViewVert);
...@@ -96,6 +97,17 @@ GlCanvas::~GlCanvas() { ...@@ -96,6 +97,17 @@ GlCanvas::~GlCanvas() {
glDeleteShader(fragment_shader_); 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) { void GlCanvas::SetTransformationMatrix(const std::array<float, 9>& matrix) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
std::array<float, 9> transposed_matrix = matrix; std::array<float, 9> transposed_matrix = matrix;
...@@ -114,8 +126,8 @@ void GlCanvas::SetViewSize(int width, int height) { ...@@ -114,8 +126,8 @@ void GlCanvas::SetViewSize(int width, int height) {
} }
void GlCanvas::DrawTexture(int texture_id, void GlCanvas::DrawTexture(int texture_id,
GLuint texture_handle, int texture_handle,
GLuint vertex_buffer, int vertex_buffer,
float alpha_multiplier) { float alpha_multiplier) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
if (!view_size_set_ || !transformation_set_) { if (!view_size_set_ || !transformation_set_) {
...@@ -137,7 +149,7 @@ void GlCanvas::DrawTexture(int texture_id, ...@@ -137,7 +149,7 @@ void GlCanvas::DrawTexture(int texture_id,
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
} }
int GlCanvas::GetGlVersion() const { int GlCanvas::GetVersion() const {
return gl_version_; return gl_version_;
} }
...@@ -145,4 +157,9 @@ int GlCanvas::GetMaxTextureSize() const { ...@@ -145,4 +157,9 @@ int GlCanvas::GetMaxTextureSize() const {
return max_texture_size_; return max_texture_size_;
} }
base::WeakPtr<Canvas> GlCanvas::GetWeakPtr() {
DCHECK(thread_checker_.CalledOnValidThread());
return weak_factory_.GetWeakPtr();
}
} // namespace remoting } // namespace remoting
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/threading/thread_checker.h" #include "base/threading/thread_checker.h"
#include "remoting/client/display/canvas.h"
#include "remoting/client/display/sys_opengl.h" #include "remoting/client/display/sys_opengl.h"
namespace remoting { namespace remoting {
...@@ -17,52 +18,23 @@ namespace remoting { ...@@ -17,52 +18,23 @@ namespace remoting {
// draw textures on the canvas. // draw textures on the canvas.
// Must be constructed after the OpenGL surface is created and destroyed before // Must be constructed after the OpenGL surface is created and destroyed before
// the surface is destroyed. // the surface is destroyed.
class GlCanvas { class GlCanvas : public Canvas {
public: public:
// gl_version: version number of the OpenGL ES context. Either 2 or 3. // gl_version: version number of the OpenGL ES context. Either 2 or 3.
GlCanvas(int gl_version); GlCanvas(int gl_version);
~GlCanvas() override;
~GlCanvas(); // Canvas implementation.
void Clear() override;
// Sets the transformation matrix. This matrix defines how the canvas should void SetTransformationMatrix(const std::array<float, 9>& matrix) override;
// be shown on the view. void SetViewSize(int width, int height) override;
// 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.
void DrawTexture(int texture_id, void DrawTexture(int texture_id,
GLuint texture_handle, int texture_handle,
GLuint vertex_buffer, int vertex_buffer,
float alpha_multiplier); float alpha_multiplier) override;
int GetVersion() const override;
// Returns the version number of current OpenGL ES context. Either 2 or 3. int GetMaxTextureSize() const override;
int GetGlVersion() const; base::WeakPtr<Canvas> GetWeakPtr() override;
// Returns the maximum texture resolution limitation. Neither the width nor
// the height of the texture can exceed this limitation.
int GetMaxTextureSize() const;
private: private:
int gl_version_; int gl_version_;
...@@ -85,6 +57,7 @@ class GlCanvas { ...@@ -85,6 +57,7 @@ class GlCanvas {
GLuint tex_cord_location_; GLuint tex_cord_location_;
base::ThreadChecker thread_checker_; base::ThreadChecker thread_checker_;
base::WeakPtrFactory<Canvas> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(GlCanvas); DISALLOW_COPY_AND_ASSIGN(GlCanvas);
}; };
......
...@@ -18,7 +18,7 @@ namespace { ...@@ -18,7 +18,7 @@ namespace {
const int kDefaultCursorDataSize = 32 * 32 * GlRenderLayer::kBytesPerPixel; const int kDefaultCursorDataSize = 32 * 32 * GlRenderLayer::kBytesPerPixel;
} // namespace } // namespace
GlCursor::GlCursor() {} GlCursor::GlCursor() : weak_factory_(this) {}
GlCursor::~GlCursor() {} GlCursor::~GlCursor() {}
...@@ -68,7 +68,7 @@ void GlCursor::SetCursorVisible(bool visible) { ...@@ -68,7 +68,7 @@ void GlCursor::SetCursorVisible(bool visible) {
visible_ = visible; visible_ = visible;
} }
void GlCursor::SetCanvas(GlCanvas* canvas) { void GlCursor::SetCanvas(base::WeakPtr<Canvas> canvas) {
if (!canvas) { if (!canvas) {
layer_.reset(); layer_.reset();
return; return;
...@@ -80,10 +80,16 @@ void GlCursor::SetCanvas(GlCanvas* canvas) { ...@@ -80,10 +80,16 @@ void GlCursor::SetCanvas(GlCanvas* canvas) {
SetCursorPosition(cursor_x_, cursor_y_); SetCursorPosition(cursor_x_, cursor_y_);
} }
void GlCursor::Draw() { bool GlCursor::Draw() {
DCHECK(thread_checker_.CalledOnValidThread());
if (layer_ && current_cursor_data_ && visible_) { if (layer_ && current_cursor_data_ && visible_) {
layer_->Draw(1.f); layer_->Draw(1.f);
} }
return false;
}
int GlCursor::GetZIndex() {
return Drawable::ZIndex::CURSOR;
} }
void GlCursor::SetCurrentCursorShape(bool size_changed) { void GlCursor::SetCurrentCursorShape(bool size_changed) {
...@@ -98,4 +104,9 @@ 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 } // namespace remoting
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
#include <memory> #include <memory>
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "remoting/client/display/drawable.h"
namespace remoting { namespace remoting {
...@@ -17,14 +20,14 @@ namespace protocol { ...@@ -17,14 +20,14 @@ namespace protocol {
class CursorShapeInfo; class CursorShapeInfo;
} // namespace protocol } // namespace protocol
class GlCanvas; class Canvas;
class GlRenderLayer; class GlRenderLayer;
// This class draws the cursor on the canvas. // This class draws the cursor on the canvas.
class GlCursor { class GlCursor : public Drawable {
public: public:
GlCursor(); GlCursor();
~GlCursor(); ~GlCursor() override;
void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape); void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape);
...@@ -35,12 +38,11 @@ class GlCursor { ...@@ -35,12 +38,11 @@ class GlCursor {
// Draw() will do nothing if cursor is not visible. // Draw() will do nothing if cursor is not visible.
void SetCursorVisible(bool visible); void SetCursorVisible(bool visible);
// Sets the canvas on which the cursor will be drawn. Resumes the current // Drawable implementation.
// state of the cursor to the context of the new canvas. void SetCanvas(base::WeakPtr<Canvas> canvas) override;
// If |canvas| is nullptr, nothing will happen when calling Draw(). bool Draw() override;
void SetCanvas(GlCanvas* canvas); int GetZIndex() override;
base::WeakPtr<Drawable> GetWeakPtr() override;
void Draw();
private: private:
void SetCurrentCursorShape(bool size_changed); void SetCurrentCursorShape(bool size_changed);
...@@ -59,6 +61,9 @@ class GlCursor { ...@@ -59,6 +61,9 @@ class GlCursor {
float cursor_x_ = 0; float cursor_x_ = 0;
float cursor_y_ = 0; float cursor_y_ = 0;
base::ThreadChecker thread_checker_;
base::WeakPtrFactory<Drawable> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(GlCursor); DISALLOW_COPY_AND_ASSIGN(GlCursor);
}; };
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include <array> #include <array>
#include "base/logging.h" #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_cursor_feedback_texture.h"
#include "remoting/client/display/gl_math.h" #include "remoting/client/display/gl_math.h"
#include "remoting/client/display/gl_render_layer.h" #include "remoting/client/display/gl_render_layer.h"
...@@ -43,11 +43,11 @@ float GetExpansionCoefficient(float progress) { ...@@ -43,11 +43,11 @@ float GetExpansionCoefficient(float progress) {
namespace remoting { namespace remoting {
GlCursorFeedback::GlCursorFeedback() {} GlCursorFeedback::GlCursorFeedback() : weak_factory_(this) {}
GlCursorFeedback::~GlCursorFeedback() {} GlCursorFeedback::~GlCursorFeedback() {}
void GlCursorFeedback::SetCanvas(GlCanvas* canvas) { void GlCursorFeedback::SetCanvas(base::WeakPtr<Canvas> canvas) {
if (!canvas) { if (!canvas) {
layer_.reset(); layer_.reset();
return; return;
...@@ -67,6 +67,7 @@ void GlCursorFeedback::StartAnimation(float x, float y, float diameter) { ...@@ -67,6 +67,7 @@ void GlCursorFeedback::StartAnimation(float x, float y, float diameter) {
} }
bool GlCursorFeedback::Draw() { bool GlCursorFeedback::Draw() {
DCHECK(thread_checker_.CalledOnValidThread());
if (!layer_ || animation_start_time_.is_null()) { if (!layer_ || animation_start_time_.is_null()) {
return false; return false;
} }
...@@ -89,4 +90,13 @@ bool GlCursorFeedback::Draw() { ...@@ -89,4 +90,13 @@ bool GlCursorFeedback::Draw() {
return true; 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 } // namespace remoting
...@@ -5,34 +5,34 @@ ...@@ -5,34 +5,34 @@
#ifndef REMOTING_CLIENT_DISPLAY_GL_CURSOR_FEEDBACK_H_ #ifndef REMOTING_CLIENT_DISPLAY_GL_CURSOR_FEEDBACK_H_
#define REMOTING_CLIENT_DISPLAY_GL_CURSOR_FEEDBACK_H_ #define REMOTING_CLIENT_DISPLAY_GL_CURSOR_FEEDBACK_H_
#include <stdint.h> #include <cstdint>
#include <memory> #include <memory>
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "remoting/client/display/drawable.h"
namespace remoting { namespace remoting {
class GlCanvas; class Canvas;
class GlRenderLayer; class GlRenderLayer;
// This class draws the cursor feedback on the canvas. // This class draws the cursor feedback on the canvas.
class GlCursorFeedback { class GlCursorFeedback : public Drawable {
public: public:
GlCursorFeedback(); GlCursorFeedback();
~GlCursorFeedback(); ~GlCursorFeedback() override;
// 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);
void StartAnimation(float x, float y, float diameter); void StartAnimation(float x, float y, float diameter);
// Returns true if animation is not finished, false otherwise. Does nothing // Drawable implementation.
// if the animation has stopped. void SetCanvas(base::WeakPtr<Canvas> canvas) override;
bool Draw(); bool Draw() override;
int GetZIndex() override;
base::WeakPtr<Drawable> GetWeakPtr() override;
private: private:
std::unique_ptr<GlRenderLayer> layer_; std::unique_ptr<GlRenderLayer> layer_;
...@@ -41,6 +41,9 @@ class GlCursorFeedback { ...@@ -41,6 +41,9 @@ class GlCursorFeedback {
float cursor_y_ = 0; float cursor_y_ = 0;
base::TimeTicks animation_start_time_; base::TimeTicks animation_start_time_;
base::ThreadChecker thread_checker_;
base::WeakPtrFactory<Drawable> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(GlCursorFeedback); DISALLOW_COPY_AND_ASSIGN(GlCursorFeedback);
}; };
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ptr_util.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_math.h"
#include "remoting/client/display/gl_render_layer.h" #include "remoting/client/display/gl_render_layer.h"
#include "remoting/client/display/gl_texture_ids.h" #include "remoting/client/display/gl_texture_ids.h"
...@@ -57,11 +57,11 @@ struct GlDesktop::GlDesktopTextureContainer { ...@@ -57,11 +57,11 @@ struct GlDesktop::GlDesktopTextureContainer {
webrtc::DesktopRect rect; webrtc::DesktopRect rect;
}; };
GlDesktop::GlDesktop() {} GlDesktop::GlDesktop() : weak_factory_(this) {}
GlDesktop::~GlDesktop() {} GlDesktop::~GlDesktop() {}
void GlDesktop::SetCanvas(GlCanvas* canvas) { void GlDesktop::SetCanvas(base::WeakPtr<Canvas> canvas) {
last_desktop_size_.set(0, 0); last_desktop_size_.set(0, 0);
textures_.clear(); textures_.clear();
canvas_ = canvas; canvas_ = canvas;
...@@ -83,12 +83,18 @@ void GlDesktop::SetVideoFrame(const webrtc::DesktopFrame& frame) { ...@@ -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()) { if (!textures_.empty() && !last_desktop_size_.is_empty()) {
for (std::unique_ptr<GlDesktopTextureContainer>& texture : textures_) { for (std::unique_ptr<GlDesktopTextureContainer>& texture : textures_) {
texture->layer->Draw(1.0f); texture->layer->Draw(1.0f);
} }
} }
return false;
}
int GlDesktop::GetZIndex() {
return Drawable::ZIndex::DESKTOP;
} }
void GlDesktop::ReallocateTextures(const webrtc::DesktopSize& size) { void GlDesktop::ReallocateTextures(const webrtc::DesktopSize& size) {
...@@ -112,9 +118,10 @@ 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_, x * max_texture_size_, y * max_texture_size_, max_texture_size_,
max_texture_size_); max_texture_size_);
rect.IntersectWith(desktop_rect); rect.IntersectWith(desktop_rect);
std::unique_ptr<GlDesktopTextureContainer> container = std::unique_ptr<GlDesktopTextureContainer> container = base::WrapUnique(
base::WrapUnique(new GlDesktopTextureContainer{ new GlDesktopTextureContainer{base::MakeUnique<GlRenderLayer>(
base::MakeUnique<GlRenderLayer>(texture_id, canvas_), rect}); texture_id, canvas_->GetWeakPtr()),
rect});
FillRectangleVertexPositions(rect.left(), rect.top(), rect.width(), FillRectangleVertexPositions(rect.left(), rect.top(), rect.width(),
rect.height(), &positions); rect.height(), &positions);
container->layer->SetVertexPositions(positions); container->layer->SetVertexPositions(positions);
...@@ -124,4 +131,9 @@ void GlDesktop::ReallocateTextures(const webrtc::DesktopSize& size) { ...@@ -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 } // namespace remoting
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
#include <vector> #include <vector>
#include "base/macros.h" #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" #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
namespace webrtc { namespace webrtc {
...@@ -17,24 +20,22 @@ class DesktopFrame; ...@@ -17,24 +20,22 @@ class DesktopFrame;
namespace remoting { namespace remoting {
class GlCanvas; class Canvas;
// This class draws the desktop on the canvas. // This class draws the desktop on the canvas.
class GlDesktop { class GlDesktop : public Drawable {
public: public:
GlDesktop(); GlDesktop();
virtual ~GlDesktop(); ~GlDesktop() override;
// |frame| can be either a full frame or updated regions only frame. // |frame| can be either a full frame or updated regions only frame.
void SetVideoFrame(const webrtc::DesktopFrame& frame); void SetVideoFrame(const webrtc::DesktopFrame& frame);
// Sets the canvas on which the desktop will be drawn. Caller must feed a // Drawable implementation.
// full desktop frame after calling this function. void SetCanvas(base::WeakPtr<Canvas> canvas) override;
// If |canvas| is nullptr, nothing will happen when calling Draw(). bool Draw() override;
void SetCanvas(GlCanvas* canvas); int GetZIndex() override;
base::WeakPtr<Drawable> GetWeakPtr() override;
// Draws the desktop on the canvas.
void Draw();
private: private:
struct GlDesktopTextureContainer; struct GlDesktopTextureContainer;
...@@ -45,7 +46,9 @@ class GlDesktop { ...@@ -45,7 +46,9 @@ class GlDesktop {
webrtc::DesktopSize last_desktop_size_; webrtc::DesktopSize last_desktop_size_;
int max_texture_size_ = 0; 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); DISALLOW_COPY_AND_ASSIGN(GlDesktop);
}; };
......
...@@ -39,7 +39,7 @@ void PackDirtyRegion(uint8_t* dest, ...@@ -39,7 +39,7 @@ void PackDirtyRegion(uint8_t* dest,
} // namespace } // namespace
GlRenderLayer::GlRenderLayer(int texture_id, GlCanvas* canvas) GlRenderLayer::GlRenderLayer(int texture_id, base::WeakPtr<Canvas> canvas)
: texture_id_(texture_id), canvas_(canvas) { : texture_id_(texture_id), canvas_(canvas) {
texture_handle_ = CreateTexture(); texture_handle_ = CreateTexture();
buffer_handle_ = CreateBuffer(kVertices, sizeof(kVertices)); buffer_handle_ = CreateBuffer(kVertices, sizeof(kVertices));
...@@ -146,7 +146,7 @@ const uint8_t* GlRenderLayer::PrepareTextureBuffer( ...@@ -146,7 +146,7 @@ const uint8_t* GlRenderLayer::PrepareTextureBuffer(
return data; 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); glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / kBytesPerPixel);
*should_reset_row_length = true; *should_reset_row_length = true;
return data; return data;
......
...@@ -9,11 +9,13 @@ ...@@ -9,11 +9,13 @@
#include <memory> #include <memory>
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h" #include "base/threading/thread_checker.h"
#include "remoting/client/display/sys_opengl.h" #include "remoting/client/display/sys_opengl.h"
namespace remoting { namespace remoting {
class GlCanvas;
class Canvas;
// This class is for drawing a texture on the canvas. Must be deleted before the // This class is for drawing a texture on the canvas. Must be deleted before the
// canvas is deleted. // canvas is deleted.
...@@ -23,7 +25,7 @@ class GlRenderLayer { ...@@ -23,7 +25,7 @@ class GlRenderLayer {
// texture_id: An integer in range [0, GL_MAX_TEXTURE_IMAGE_UNITS], defining // texture_id: An integer in range [0, GL_MAX_TEXTURE_IMAGE_UNITS], defining
// which slot to store the texture. // which slot to store the texture.
GlRenderLayer(int texture_id, GlCanvas* canvas); GlRenderLayer(int texture_id, base::WeakPtr<Canvas> canvas);
~GlRenderLayer(); ~GlRenderLayer();
// Sets the texture (RGBA 8888) to be drawn. Please use UpdateTexture() if the // Sets the texture (RGBA 8888) to be drawn. Please use UpdateTexture() if the
...@@ -78,7 +80,7 @@ class GlRenderLayer { ...@@ -78,7 +80,7 @@ class GlRenderLayer {
bool* should_reset_row_length); bool* should_reset_row_length);
int texture_id_; int texture_id_;
GlCanvas* canvas_; base::WeakPtr<Canvas> canvas_;
GLuint texture_handle_; GLuint texture_handle_;
GLuint buffer_handle_; GLuint buffer_handle_;
......
...@@ -4,9 +4,12 @@ ...@@ -4,9 +4,12 @@
#include "remoting/client/display/gl_renderer.h" #include "remoting/client/display/gl_renderer.h"
#include <algorithm>
#include "base/bind.h" #include "base/bind.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/threading/thread_task_runner_handle.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_canvas.h"
#include "remoting/client/display/gl_math.h" #include "remoting/client/display/gl_math.h"
#include "remoting/client/display/gl_renderer_delegate.h" #include "remoting/client/display/gl_renderer_delegate.h"
...@@ -15,14 +18,22 @@ ...@@ -15,14 +18,22 @@
namespace remoting { namespace remoting {
namespace {
bool CompareDrawableZOrder(base::WeakPtr<Drawable> a,
base::WeakPtr<Drawable> b) {
return a->GetZIndex() < b->GetZIndex();
}
} // namespace
GlRenderer::GlRenderer() : GlRenderer::GlRenderer() :
weak_factory_(this) { weak_factory_(this) {
weak_ptr_ = weak_factory_.GetWeakPtr(); weak_ptr_ = weak_factory_.GetWeakPtr();
thread_checker_.DetachFromThread(); thread_checker_.DetachFromThread();
} }
GlRenderer::~GlRenderer() { GlRenderer::~GlRenderer() {}
}
void GlRenderer::SetDelegate(base::WeakPtr<GlRendererDelegate> delegate) { void GlRenderer::SetDelegate(base::WeakPtr<GlRendererDelegate> delegate) {
DCHECK(!delegate_); DCHECK(!delegate_);
...@@ -90,19 +101,12 @@ void GlRenderer::OnCursorShapeChanged(const protocol::CursorShapeInfo& shape) { ...@@ -90,19 +101,12 @@ void GlRenderer::OnCursorShapeChanged(const protocol::CursorShapeInfo& shape) {
RequestRender(); RequestRender();
} }
void GlRenderer::OnSurfaceCreated(int gl_version) { void GlRenderer::OnSurfaceCreated(std::unique_ptr<Canvas> canvas) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
#ifndef NDEBUG canvas_ = std::move(canvas);
// Set the background clear color to bright green for debugging purposes. for (auto& drawable : drawables_) {
glClearColor(0.0f, 1.0f, 0.0f, 1.0f); drawable->SetCanvas(canvas_->GetWeakPtr());
#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());
} }
void GlRenderer::OnSurfaceChanged(int view_width, int view_height) { void GlRenderer::OnSurfaceChanged(int view_width, int view_height) {
...@@ -137,6 +141,12 @@ void GlRenderer::RequestRender() { ...@@ -137,6 +141,12 @@ void GlRenderer::RequestRender() {
render_scheduled_ = true; 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() { void GlRenderer::OnRender() {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
render_scheduled_ = false; render_scheduled_ = false;
...@@ -145,18 +155,13 @@ void GlRenderer::OnRender() { ...@@ -145,18 +155,13 @@ void GlRenderer::OnRender() {
} }
if (canvas_) { if (canvas_) {
glClear(GL_COLOR_BUFFER_BIT); canvas_->Clear();
// Draw each drawable in order.
// Layers will be drawn from bottom to top. for (auto& drawable : drawables_) {
desktop_.Draw(); if (drawable->Draw()) {
RequestRender();
// |cursor_feedback_| should be drawn before |cursor_| so that the cursor }
// won't be covered by the feedback animation.
if (cursor_feedback_.Draw()) {
RequestRender();
} }
cursor_.Draw();
} }
delegate_->OnFrameRendered(); delegate_->OnFrameRendered();
...@@ -167,4 +172,12 @@ void GlRenderer::OnRender() { ...@@ -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 } // namespace remoting
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define REMOTING_CLIENT_DISPLAY_GL_RENDERER_H_ #define REMOTING_CLIENT_DISPLAY_GL_RENDERER_H_
#include <queue> #include <queue>
#include <vector>
#include "base/callback.h" #include "base/callback.h"
#include "base/macros.h" #include "base/macros.h"
...@@ -26,7 +27,7 @@ namespace protocol { ...@@ -26,7 +27,7 @@ namespace protocol {
class CursorShapeInfo; class CursorShapeInfo;
} // namespace protocol } // namespace protocol
class GlCanvas; class Canvas;
class GlRendererDelegate; class GlRendererDelegate;
class GlRendererTest; class GlRendererTest;
...@@ -82,7 +83,7 @@ class GlRenderer { ...@@ -82,7 +83,7 @@ class GlRenderer {
// lost after calling this function. // lost after calling this function.
// Caller must call OnSurfaceDestroyed() before calling this function if the // Caller must call OnSurfaceDestroyed() before calling this function if the
// surface is recreated. // 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 // Sets the size of the view. Called right after OnSurfaceCreated() or
// whenever the view size is changed. // whenever the view size is changed.
...@@ -91,9 +92,14 @@ class GlRenderer { ...@@ -91,9 +92,14 @@ class GlRenderer {
// Called when the surface is destroyed. // Called when the surface is destroyed.
void OnSurfaceDestroyed(); void OnSurfaceDestroyed();
void AddDrawable(base::WeakPtr<Drawable> drawable);
// Returns the weak pointer to be used on the display thread. // Returns the weak pointer to be used on the display thread.
base::WeakPtr<GlRenderer> GetWeakPtr(); base::WeakPtr<GlRenderer> GetWeakPtr();
// Convenience method to create a Renderer with standard desktop components.
static std::unique_ptr<GlRenderer> CreateGlRendererWithDesktop();
private: private:
friend class GlRendererTest; friend class GlRendererTest;
...@@ -119,12 +125,14 @@ class GlRenderer { ...@@ -119,12 +125,14 @@ class GlRenderer {
int canvas_width_ = 0; int canvas_width_ = 0;
int canvas_height_ = 0; int canvas_height_ = 0;
std::unique_ptr<GlCanvas> canvas_; std::unique_ptr<Canvas> canvas_;
GlCursor cursor_; GlCursor cursor_;
GlCursorFeedback cursor_feedback_; GlCursorFeedback cursor_feedback_;
GlDesktop desktop_; GlDesktop desktop_;
std::vector<base::WeakPtr<Drawable>> drawables_;
base::ThreadChecker thread_checker_; base::ThreadChecker thread_checker_;
base::WeakPtr<GlRenderer> weak_ptr_; base::WeakPtr<GlRenderer> weak_ptr_;
base::WeakPtrFactory<GlRenderer> weak_factory_; base::WeakPtrFactory<GlRenderer> weak_factory_;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.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 "remoting/client/display/gl_renderer_delegate.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
...@@ -67,8 +68,43 @@ class FakeGlRendererDelegate : public GlRendererDelegate { ...@@ -67,8 +68,43 @@ class FakeGlRendererDelegate : public GlRendererDelegate {
int canvas_height_ = 0; int canvas_height_ = 0;
base::Closure on_frame_rendered_callback_; base::Closure on_frame_rendered_callback_;
base::WeakPtrFactory<FakeGlRendererDelegate> weak_factory_; 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 { class GlRendererTest : public testing::Test {
...@@ -76,6 +112,8 @@ class GlRendererTest : public testing::Test { ...@@ -76,6 +112,8 @@ class GlRendererTest : public testing::Test {
void SetUp() override; void SetUp() override;
void SetDesktopFrameWithSize(const webrtc::DesktopSize& size); void SetDesktopFrameWithSize(const webrtc::DesktopSize& size);
void PostSetDesktopFrameTasks(const webrtc::DesktopSize& size, int count); void PostSetDesktopFrameTasks(const webrtc::DesktopSize& size, int count);
int GetDrawablesCount();
std::vector<base::WeakPtr<Drawable>> GetDrawables();
protected: protected:
void RequestRender(); void RequestRender();
...@@ -103,6 +141,14 @@ void GlRendererTest::RequestRender() { ...@@ -103,6 +141,14 @@ void GlRendererTest::RequestRender() {
renderer_->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) { void GlRendererTest::SetDesktopFrameWithSize(const webrtc::DesktopSize& size) {
renderer_->OnFrameReceived( renderer_->OnFrameReceived(
base::MakeUnique<webrtc::BasicDesktopFrame>(size), base::MakeUnique<webrtc::BasicDesktopFrame>(size),
...@@ -167,24 +213,24 @@ TEST_F(GlRendererTest, TestRequestRenderOnlyScheduleOnce) { ...@@ -167,24 +213,24 @@ TEST_F(GlRendererTest, TestRequestRenderOnlyScheduleOnce) {
TEST_F(GlRendererTest, TestDelegateOnSizeChanged) { TEST_F(GlRendererTest, TestDelegateOnSizeChanged) {
SetDesktopFrameWithSize(webrtc::DesktopSize(16, 16)); SetDesktopFrameWithSize(webrtc::DesktopSize(16, 16));
EXPECT_EQ(1, delegate_.on_size_changed_call_count()); ASSERT_EQ(1, delegate_.on_size_changed_call_count());
EXPECT_EQ(16, delegate_.canvas_width()); ASSERT_EQ(16, delegate_.canvas_width());
EXPECT_EQ(16, delegate_.canvas_height()); ASSERT_EQ(16, delegate_.canvas_height());
SetDesktopFrameWithSize(webrtc::DesktopSize(16, 16)); SetDesktopFrameWithSize(webrtc::DesktopSize(16, 16));
EXPECT_EQ(1, delegate_.on_size_changed_call_count()); ASSERT_EQ(1, delegate_.on_size_changed_call_count());
EXPECT_EQ(16, delegate_.canvas_width()); ASSERT_EQ(16, delegate_.canvas_width());
EXPECT_EQ(16, delegate_.canvas_height()); ASSERT_EQ(16, delegate_.canvas_height());
SetDesktopFrameWithSize(webrtc::DesktopSize(32, 32)); SetDesktopFrameWithSize(webrtc::DesktopSize(32, 32));
EXPECT_EQ(2, delegate_.on_size_changed_call_count()); ASSERT_EQ(2, delegate_.on_size_changed_call_count());
EXPECT_EQ(32, delegate_.canvas_width()); ASSERT_EQ(32, delegate_.canvas_width());
EXPECT_EQ(32, delegate_.canvas_height()); ASSERT_EQ(32, delegate_.canvas_height());
renderer_->RequestCanvasSize(); renderer_->RequestCanvasSize();
EXPECT_EQ(3, delegate_.on_size_changed_call_count()); ASSERT_EQ(3, delegate_.on_size_changed_call_count());
EXPECT_EQ(32, delegate_.canvas_width()); ASSERT_EQ(32, delegate_.canvas_width());
EXPECT_EQ(32, delegate_.canvas_height()); ASSERT_EQ(32, delegate_.canvas_height());
} }
TEST_F(GlRendererTest, TestOnFrameReceivedDoneCallbacks) { TEST_F(GlRendererTest, TestOnFrameReceivedDoneCallbacks) {
...@@ -199,10 +245,110 @@ TEST_F(GlRendererTest, TestOnFrameReceivedDoneCallbacks) { ...@@ -199,10 +245,110 @@ TEST_F(GlRendererTest, TestOnFrameReceivedDoneCallbacks) {
PostSetDesktopFrameTasks(webrtc::DesktopSize(16, 16), 20); PostSetDesktopFrameTasks(webrtc::DesktopSize(16, 16), 20);
RunUntilRendered(); RunUntilRendered();
EXPECT_EQ(2, delegate_.on_frame_rendered_call_count()); ASSERT_EQ(2, delegate_.on_frame_rendered_call_count());
EXPECT_EQ(21, on_desktop_frame_processed_call_count()); ASSERT_EQ(21, on_desktop_frame_processed_call_count());
} }
// TODO(yuweih): Add tests to validate the rendered output. // 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 } // namespace remoting
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "jni/GlDisplay_jni.h" #include "jni/GlDisplay_jni.h"
#include "remoting/client/cursor_shape_stub_proxy.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/dual_buffer_frame_consumer.h"
#include "remoting/client/jni/chromoting_jni_runtime.h" #include "remoting/client/jni/chromoting_jni_runtime.h"
#include "remoting/client/jni/egl_thread_context.h" #include "remoting/client/jni/egl_thread_context.h"
...@@ -62,7 +63,7 @@ class JniGlDisplayHandler::Core : public protocol::CursorShapeStub, ...@@ -62,7 +63,7 @@ class JniGlDisplayHandler::Core : public protocol::CursorShapeStub,
ANativeWindow* window_ = nullptr; ANativeWindow* window_ = nullptr;
std::unique_ptr<EglThreadContext> egl_context_; std::unique_ptr<EglThreadContext> egl_context_;
GlRenderer renderer_; std::unique_ptr<GlRenderer> renderer_;
// Used on display thread. // Used on display thread.
base::WeakPtr<Core> weak_ptr_; base::WeakPtr<Core> weak_ptr_;
...@@ -74,12 +75,13 @@ class JniGlDisplayHandler::Core : public protocol::CursorShapeStub, ...@@ -74,12 +75,13 @@ class JniGlDisplayHandler::Core : public protocol::CursorShapeStub,
JniGlDisplayHandler::Core::Core(ChromotingJniRuntime* runtime, JniGlDisplayHandler::Core::Core(ChromotingJniRuntime* runtime,
base::WeakPtr<JniGlDisplayHandler> shell) base::WeakPtr<JniGlDisplayHandler> shell)
: runtime_(runtime), shell_(shell), weak_factory_(this) { : runtime_(runtime), shell_(shell), weak_factory_(this) {
renderer_ = GlRenderer::CreateGlRendererWithDesktop();
weak_ptr_ = weak_factory_.GetWeakPtr(); weak_ptr_ = weak_factory_.GetWeakPtr();
renderer_.SetDelegate(weak_ptr_); renderer_->SetDelegate(weak_ptr_);
owned_frame_consumer_.reset(new DualBufferFrameConsumer( owned_frame_consumer_.reset(new DualBufferFrameConsumer(
base::Bind(&GlRenderer::OnFrameReceived, renderer_.GetWeakPtr()), base::Bind(&GlRenderer::OnFrameReceived, renderer_->GetWeakPtr()),
runtime_->display_task_runner(), runtime_->display_task_runner(),
protocol::FrameConsumer::PixelFormat::FORMAT_RGBA)); protocol::FrameConsumer::PixelFormat::FORMAT_RGBA));
frame_consumer_ = owned_frame_consumer_->GetWeakPtr(); frame_consumer_ = owned_frame_consumer_->GetWeakPtr();
} }
...@@ -107,7 +109,7 @@ void JniGlDisplayHandler::Core::OnSizeChanged(int width, int height) { ...@@ -107,7 +109,7 @@ void JniGlDisplayHandler::Core::OnSizeChanged(int width, int height) {
void JniGlDisplayHandler::Core::SetCursorShape( void JniGlDisplayHandler::Core::SetCursorShape(
const protocol::CursorShapeInfo& cursor_shape) { const protocol::CursorShapeInfo& cursor_shape) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_.OnCursorShapeChanged(cursor_shape); renderer_->OnCursorShapeChanged(cursor_shape);
} }
std::unique_ptr<protocol::FrameConsumer> std::unique_ptr<protocol::FrameConsumer>
...@@ -121,12 +123,15 @@ void JniGlDisplayHandler::Core::SurfaceCreated( ...@@ -121,12 +123,15 @@ void JniGlDisplayHandler::Core::SurfaceCreated(
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
DCHECK(!egl_context_); DCHECK(!egl_context_);
DCHECK(!window_); DCHECK(!window_);
renderer_.RequestCanvasSize(); renderer_->RequestCanvasSize();
window_ = ANativeWindow_fromSurface(base::android::AttachCurrentThread(), window_ = ANativeWindow_fromSurface(base::android::AttachCurrentThread(),
surface.obj()); surface.obj());
egl_context_.reset(new EglThreadContext()); egl_context_.reset(new EglThreadContext());
egl_context_->BindToWindow(window_); 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( runtime_->network_task_runner()->PostTask(
FROM_HERE, base::Bind(&DualBufferFrameConsumer::RequestFullDesktopFrame, FROM_HERE, base::Bind(&DualBufferFrameConsumer::RequestFullDesktopFrame,
frame_consumer_)); frame_consumer_));
...@@ -134,14 +139,14 @@ void JniGlDisplayHandler::Core::SurfaceCreated( ...@@ -134,14 +139,14 @@ void JniGlDisplayHandler::Core::SurfaceCreated(
void JniGlDisplayHandler::Core::SurfaceChanged(int width, int height) { void JniGlDisplayHandler::Core::SurfaceChanged(int width, int height) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_.OnSurfaceChanged(width, height); renderer_->OnSurfaceChanged(width, height);
} }
void JniGlDisplayHandler::Core::SurfaceDestroyed() { void JniGlDisplayHandler::Core::SurfaceDestroyed() {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
DCHECK(egl_context_); DCHECK(egl_context_);
DCHECK(window_); DCHECK(window_);
renderer_.OnSurfaceDestroyed(); renderer_->OnSurfaceDestroyed();
egl_context_.reset(); egl_context_.reset();
ANativeWindow_release(window_); ANativeWindow_release(window_);
window_ = nullptr; window_ = nullptr;
...@@ -150,24 +155,24 @@ void JniGlDisplayHandler::Core::SurfaceDestroyed() { ...@@ -150,24 +155,24 @@ void JniGlDisplayHandler::Core::SurfaceDestroyed() {
void JniGlDisplayHandler::Core::SetTransformation( void JniGlDisplayHandler::Core::SetTransformation(
const std::array<float, 9>& matrix) { const std::array<float, 9>& matrix) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_.OnPixelTransformationChanged(matrix); renderer_->OnPixelTransformationChanged(matrix);
} }
void JniGlDisplayHandler::Core::MoveCursor(float x, float y) { void JniGlDisplayHandler::Core::MoveCursor(float x, float y) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_.OnCursorMoved(x, y); renderer_->OnCursorMoved(x, y);
} }
void JniGlDisplayHandler::Core::SetCursorVisibility(bool visible) { void JniGlDisplayHandler::Core::SetCursorVisibility(bool visible) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_.OnCursorVisibilityChanged(visible); renderer_->OnCursorVisibilityChanged(visible);
} }
void JniGlDisplayHandler::Core::StartInputFeedback(float x, void JniGlDisplayHandler::Core::StartInputFeedback(float x,
float y, float y,
float diameter) { float diameter) {
DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread());
renderer_.OnCursorInputFeedback(x, y, diameter); renderer_->OnCursorInputFeedback(x, y, diameter);
} }
base::WeakPtr<JniGlDisplayHandler::Core> base::WeakPtr<JniGlDisplayHandler::Core>
......
...@@ -4,6 +4,13 @@ ...@@ -4,6 +4,13 @@
import("//third_party/protobuf/proto_library.gni") import("//third_party/protobuf/proto_library.gni")
group("proto_lite") {
public_deps = [
":proto",
"//third_party/protobuf:protobuf_lite",
]
}
proto_library("proto") { proto_library("proto") {
sources = [ sources = [
"audio.proto", "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