mozart: Port the spinning cube example. Initial port of the spinning cube example to the Mozart view system. Note: This version does not support input yet. R=abarth@google.com, jamesr@chromium.org Review URL: https://codereview.chromium.org/1411103004 .
diff --git a/examples/BUILD.gn b/examples/BUILD.gn index 03860ca..b4fe608 100644 --- a/examples/BUILD.gn +++ b/examples/BUILD.gn
@@ -46,7 +46,10 @@ } if (is_linux || is_android) { - deps += [ "//examples/surfaces_app" ] + deps += [ + "//examples/ui/spinning_cube", + "//examples/surfaces_app", + ] } if (defined(go_build_tool) && go_build_tool != "") {
diff --git a/examples/ui/spinning_cube/BUILD.gn b/examples/ui/spinning_cube/BUILD.gn new file mode 100644 index 0000000..db71418 --- /dev/null +++ b/examples/ui/spinning_cube/BUILD.gn
@@ -0,0 +1,35 @@ +# Copyright 2015 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. + +import("//mojo/public/mojo_application.gni") + +mojo_native_application("spinning_cube") { + output_name = "spinning_cube_view" + + sources = [ + "main.cc", + "spinning_cube_app.cc", + "spinning_cube_app.h", + "spinning_cube_view.cc", + "spinning_cube_view.h", + ] + + deps = [ + "//base", + "//examples/spinning_cube:lib", + "//mojo/application", + "//mojo/common", + "//mojo/environment:chromium", + "//mojo/gpu", + "//mojo/public/c/gpu", + "//mojo/public/c/gpu:gpu_onscreen", + "//mojo/public/cpp/bindings", + "//mojo/public/cpp/environment", + "//mojo/public/cpp/system", + "//mojo/services/geometry/interfaces", + "//mojo/services/input_events/interfaces", + "//mojo/services/surfaces/interfaces", + "//mojo/services/ui/views/interfaces", + ] +}
diff --git a/examples/ui/spinning_cube/README.md b/examples/ui/spinning_cube/README.md new file mode 100644 index 0000000..1df5fa8 --- /dev/null +++ b/examples/ui/spinning_cube/README.md
@@ -0,0 +1,8 @@ +# Mozart Spinning Cube Example + +This directory contains a simple application which draws a spinning cube +into a View. + +## USAGE + + out/Debug/mojo_shell "mojo:launcher mojo:spinning_cube_view"
diff --git a/examples/ui/spinning_cube/main.cc b/examples/ui/spinning_cube/main.cc new file mode 100644 index 0000000..fcf0bc2 --- /dev/null +++ b/examples/ui/spinning_cube/main.cc
@@ -0,0 +1,12 @@ +// Copyright 2015 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 "examples/ui/spinning_cube/spinning_cube_app.h" +#include "mojo/application/application_runner_chromium.h" +#include "mojo/public/c/system/main.h" + +MojoResult MojoMain(MojoHandle application_request) { + mojo::ApplicationRunnerChromium runner(new examples::SpinningCubeApp); + return runner.Run(application_request); +}
diff --git a/examples/ui/spinning_cube/spinning_cube_app.cc b/examples/ui/spinning_cube/spinning_cube_app.cc new file mode 100644 index 0000000..6bee8d4 --- /dev/null +++ b/examples/ui/spinning_cube/spinning_cube_app.cc
@@ -0,0 +1,37 @@ +// Copyright 2015 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 "examples/ui/spinning_cube/spinning_cube_app.h" +#include "examples/ui/spinning_cube/spinning_cube_view.h" + +namespace examples { + +SpinningCubeApp::SpinningCubeApp() {} + +SpinningCubeApp::~SpinningCubeApp() {} + +void SpinningCubeApp::Initialize(mojo::ApplicationImpl* app_impl) { + app_impl_ = app_impl; +} + +bool SpinningCubeApp::ConfigureIncomingConnection( + mojo::ApplicationConnection* connection) { + connection->AddService<mojo::ui::ViewProvider>(this); + return true; +} + +void SpinningCubeApp::Create( + mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<mojo::ui::ViewProvider> request) { + bindings_.AddBinding(this, request.Pass()); +} + +void SpinningCubeApp::CreateView( + mojo::InterfaceRequest<mojo::ServiceProvider> services, + mojo::ServiceProviderPtr exposed_services, + const CreateViewCallback& callback) { + new SpinningCubeView(app_impl_, callback); +} + +} // namespace examples
diff --git a/examples/ui/spinning_cube/spinning_cube_app.h b/examples/ui/spinning_cube/spinning_cube_app.h new file mode 100644 index 0000000..d1e99e7 --- /dev/null +++ b/examples/ui/spinning_cube/spinning_cube_app.h
@@ -0,0 +1,50 @@ +// Copyright 2015 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 EXAMPLES_UI_SPINNING_CUBE_SPINNING_CUBE_APP_H_ +#define EXAMPLES_UI_SPINNING_CUBE_SPINNING_CUBE_APP_H_ + +#include "base/bind.h" +#include "base/memory/scoped_ptr.h" +#include "mojo/common/binding_set.h" +#include "mojo/public/c/system/main.h" +#include "mojo/public/cpp/application/application_connection.h" +#include "mojo/public/cpp/application/application_impl.h" +#include "mojo/public/cpp/system/core.h" +#include "mojo/public/cpp/system/macros.h" +#include "mojo/services/ui/views/interfaces/view_provider.mojom.h" + +namespace examples { + +class SpinningCubeApp : public mojo::ApplicationDelegate, + public mojo::InterfaceFactory<mojo::ui::ViewProvider>, + public mojo::ui::ViewProvider { + public: + SpinningCubeApp(); + ~SpinningCubeApp() override; + + private: + // |ApplicationDelegate|: + void Initialize(mojo::ApplicationImpl* app) override; + bool ConfigureIncomingConnection( + mojo::ApplicationConnection* connection) override; + + // |InterfaceFactory<mojo::ui::ViewProvider>|: + void Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest<mojo::ui::ViewProvider> request) override; + + // |ViewProvider|: + void CreateView(mojo::InterfaceRequest<mojo::ServiceProvider> services, + mojo::ServiceProviderPtr exposed_services, + const CreateViewCallback& callback) override; + + mojo::ApplicationImpl* app_impl_; + mojo::BindingSet<mojo::ui::ViewProvider> bindings_; + + DISALLOW_COPY_AND_ASSIGN(SpinningCubeApp); +}; + +} // namespace examples + +#endif // EXAMPLES_UI_SPINNING_CUBE_SPINNING_CUBE_APP_H_
diff --git a/examples/ui/spinning_cube/spinning_cube_view.cc b/examples/ui/spinning_cube/spinning_cube_view.cc new file mode 100644 index 0000000..8c3ce7a --- /dev/null +++ b/examples/ui/spinning_cube/spinning_cube_view.cc
@@ -0,0 +1,162 @@ +// Copyright 2015 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 <GLES2/gl2.h> +#include <GLES2/gl2extmojo.h> +#include <MGL/mgl.h> + +#include "base/message_loop/message_loop.h" +#include "examples/ui/spinning_cube/spinning_cube_view.h" + +namespace examples { + +SpinningCubeView::SpinningCubeView( + mojo::ApplicationImpl* app, + const mojo::ui::ViewProvider::CreateViewCallback& callback) + : callback_(callback), + binding_(this), + context_owner_(app->shell()), + texture_cache_(context_owner_.context(), &resource_returner_), + surface_id_namespace_(0), + draw_scheduled_(false), + weak_ptr_factory_(this) { + app->ConnectToService("mojo:surfaces_service", &surfaces_); + app->ConnectToService("mojo:view_manager_service", &view_manager_); + + surfaces_->SetResourceReturner(resource_returner_.Pass()); + surfaces_->GetIdNamespace( + base::Bind(&SpinningCubeView::OnSurfaceIdNamespaceAvailable, + base::Unretained(this))); + + InitCube(); +} + +SpinningCubeView::~SpinningCubeView() {} + +void SpinningCubeView::OnSurfaceIdNamespaceAvailable(uint32_t id_namespace) { + surface_id_namespace_ = id_namespace; + InitView(); +} + +void SpinningCubeView::InitView() { + mojo::ui::ViewPtr view; + binding_.Bind(mojo::GetProxy(&view)); + view_manager_->RegisterView(view.Pass(), mojo::GetProxy(&view_host_), + callback_); + + view_host_->GetServiceProvider(mojo::GetProxy(&view_service_provider_)); +} + +void SpinningCubeView::OnLayout(mojo::ui::ViewLayoutParamsPtr layout_params, + mojo::Array<uint32_t> children_needing_layout, + const OnLayoutCallback& callback) { + // Create a new surface the first time or if the size has changed. + mojo::Size new_size; + new_size.width = layout_params->constraints->max_width; + new_size.height = layout_params->constraints->max_height; + if (!surface_id_ || !size_.Equals(new_size)) { + if (!surface_id_) { + surface_id_ = mojo::SurfaceId::New(); + surface_id_->id_namespace = surface_id_namespace_; + } else { + surfaces_->DestroySurface(surface_id_->local); + } + surface_id_->local++; + size_ = new_size; + surfaces_->CreateSurface(surface_id_->local); + } + + // Submit the new layout information. + auto info = mojo::ui::ViewLayoutInfo::New(); + info->size = size_.Clone(); + info->surface_id = surface_id_->Clone(); + callback.Run(info.Pass()); + + // Draw! + ScheduleDraw(); +} + +void SpinningCubeView::OnChildUnavailable( + uint32_t child_key, + const OnChildUnavailableCallback& callback) { + callback.Run(); +} + +void SpinningCubeView::InitCube() { + context_owner_.context()->MakeCurrent(); + cube_.Init(); + last_draw_ = mojo::GetTimeTicksNow(); +} + +void SpinningCubeView::DrawCube() { + draw_scheduled_ = false; + + scoped_ptr<mojo::TextureCache::TextureInfo> texture_info = + texture_cache_.GetTexture(size_); + if (!texture_info) { + LOG(ERROR) << "Could not allocate texture of size " << size_.width << "x" + << size_.height; + return; + } + + context_owner_.context()->MakeCurrent(); + scoped_ptr<mojo::GLTexture> texture = texture_info->TakeTexture(); + + GLuint fbo = 0u; + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + GLuint depth_buffer = 0u; + glGenRenderbuffers(1, &depth_buffer); + glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size_.width, + size_.height); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + texture->texture_id(), 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depth_buffer); + DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), + glCheckFramebufferStatus(GL_FRAMEBUFFER)); + glClearColor(1, 0, 0, 0.5); + + cube_.set_size(size_.width, size_.height); + + MojoTimeTicks now = mojo::GetTimeTicksNow(); + MojoTimeTicks offset = now - last_draw_; + cube_.UpdateForTimeDelta(offset * 0.000001f); + last_draw_ = now; + + cube_.Draw(); + + glDeleteFramebuffers(1, &fbo); + glDeleteRenderbuffers(1, &depth_buffer); + + mojo::FramePtr frame = mojo::TextureUploader::GetUploadFrame( + context_owner_.context(), texture_info->resource_id(), texture); + surfaces_->SubmitFrame(surface_id_->local, frame.Pass(), + base::Bind(&SpinningCubeView::OnSurfaceSubmitted, + base::Unretained(this))); + + texture_cache_.NotifyPendingResourceReturn(texture_info->resource_id(), + texture.Pass()); +} + +void SpinningCubeView::OnSurfaceSubmitted() { + ScheduleDraw(); +} + +void SpinningCubeView::ScheduleDraw() { + if (!draw_scheduled_) { + draw_scheduled_ = true; + + // TODO(jeffbrown): For now, we need to throttle this down because + // drawing as fast as we can appears to cause starvation of the + // Mojo message loop and makes X11 unhappy. + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&SpinningCubeView::DrawCube, weak_ptr_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(30)); + } +} + +} // namespace examples
diff --git a/examples/ui/spinning_cube/spinning_cube_view.h b/examples/ui/spinning_cube/spinning_cube_view.h new file mode 100644 index 0000000..1a5b7fe --- /dev/null +++ b/examples/ui/spinning_cube/spinning_cube_view.h
@@ -0,0 +1,83 @@ +// Copyright 2015 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 EXAMPLES_UI_SPINNING_CUBE_SPINNING_CUBE_VIEW_H_ +#define EXAMPLES_UI_SPINNING_CUBE_SPINNING_CUBE_VIEW_H_ + +#include <memory> + +#include "base/bind.h" +#include "base/memory/weak_ptr.h" +#include "examples/spinning_cube/spinning_cube.h" +#include "mojo/gpu/gl_context.h" +#include "mojo/gpu/gl_context_owner.h" +#include "mojo/gpu/gl_texture.h" +#include "mojo/gpu/texture_cache.h" +#include "mojo/gpu/texture_uploader.h" +#include "mojo/public/cpp/application/application_impl.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/system/core.h" +#include "mojo/public/cpp/system/macros.h" +#include "mojo/services/surfaces/interfaces/quads.mojom.h" +#include "mojo/services/surfaces/interfaces/surfaces.mojom.h" +#include "mojo/services/ui/views/interfaces/view_manager.mojom.h" +#include "mojo/services/ui/views/interfaces/view_provider.mojom.h" +#include "mojo/services/ui/views/interfaces/views.mojom.h" + +namespace examples { + +class SpinningCubeView : public mojo::ui::View { + public: + SpinningCubeView(mojo::ApplicationImpl* app, + const mojo::ui::ViewProvider::CreateViewCallback& callback); + + ~SpinningCubeView() override; + + private: + // |View|: + void OnLayout(mojo::ui::ViewLayoutParamsPtr layout_params, + mojo::Array<uint32_t> children_needing_layout, + const OnLayoutCallback& callback) override; + void OnChildUnavailable(uint32_t child_key, + const OnChildUnavailableCallback& callback) override; + + void OnSurfaceIdNamespaceAvailable(uint32_t id_namespace); + + void InitView(); + + void InitCube(); + void DrawCube(); + void OnSurfaceSubmitted(); + void ScheduleDraw(); + + mojo::ui::ViewProvider::CreateViewCallback callback_; + mojo::StrongBinding<mojo::ui::View> binding_; + + mojo::GLContextOwner context_owner_; + mojo::ResourceReturnerPtr resource_returner_; // must be before texture cache + mojo::TextureCache texture_cache_; + + mojo::SurfacePtr surfaces_; + mojo::SurfaceIdPtr surface_id_; + uint32_t surface_id_namespace_; + + mojo::ui::ViewManagerPtr view_manager_; + mojo::ui::ViewHostPtr view_host_; + mojo::ServiceProviderPtr view_service_provider_; + + mojo::Size size_; + + SpinningCube cube_; + MojoTimeTicks last_draw_; + bool draw_scheduled_; + + base::WeakPtrFactory<SpinningCubeView> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(SpinningCubeView); +}; + +} // namespace examples + +#endif // EXAMPLES_UI_SPINNING_CUBE_SPINNING_CUBE_VIEW_H_
diff --git a/mojo/gpu/texture_cache.cc b/mojo/gpu/texture_cache.cc index f97a2ed..a76fedb 100644 --- a/mojo/gpu/texture_cache.cc +++ b/mojo/gpu/texture_cache.cc
@@ -56,6 +56,7 @@ // If the texture is the right size, use it. if (texture_size.width == requested_size.width && texture_size.height == requested_size.height) { + gl_context_->MakeCurrent(); glWaitSyncPointCHROMIUM(sync_point); return texture_info; }