diff options
-rw-r--r-- | chrome/test/ppapi/ppapi_browsertest.cc | 10 | ||||
-rw-r--r-- | content/renderer/pepper/pepper_compositor_host.cc | 54 | ||||
-rw-r--r-- | content/renderer/pepper/pepper_compositor_host.h | 15 | ||||
-rw-r--r-- | content/renderer/pepper/pepper_plugin_instance_impl.cc | 17 | ||||
-rw-r--r-- | content/renderer/pepper/pepper_plugin_instance_impl.h | 5 | ||||
-rw-r--r-- | ppapi/examples/compositor/compositor.cc | 52 | ||||
-rw-r--r-- | ppapi/ppapi_sources.gypi | 2 | ||||
-rw-r--r-- | ppapi/proxy/compositor_layer_resource.cc | 17 | ||||
-rw-r--r-- | ppapi/proxy/compositor_layer_resource.h | 2 | ||||
-rw-r--r-- | ppapi/proxy/compositor_resource.cc | 29 | ||||
-rw-r--r-- | ppapi/proxy/compositor_resource.h | 11 | ||||
-rw-r--r-- | ppapi/tests/test_compositor.cc | 430 | ||||
-rw-r--r-- | ppapi/tests/test_compositor.h | 52 |
13 files changed, 617 insertions, 79 deletions
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc index 9642cc36..0a679c6 100644 --- a/chrome/test/ppapi/ppapi_browsertest.cc +++ b/chrome/test/ppapi/ppapi_browsertest.cc @@ -1208,6 +1208,16 @@ IN_PROC_BROWSER_TEST_F(OutOfProcessPPAPITest, MAYBE_FlashMessageLoop) { RUN_FLASH_MESSAGE_LOOP_SUBTESTS; } +#if defined(OS_WIN) && defined(USE_AURA) +// These tests fail with the test compositor which is what's used by default for +// browser tests on Windows Aura. Renable when the software compositor is +// available. +#define MAYBE_Compositor DISABLED_Compositor +#else // defined(OS_WIN) && defined(USE_AURA) +#define MAYBE_Compositor Compositor +#endif // defined(OS_WIN) && defined(USE_AURA) +TEST_PPAPI_NACL(MAYBE_Compositor) + TEST_PPAPI_NACL(MediaStreamAudioTrack) TEST_PPAPI_NACL(MediaStreamVideoTrack) diff --git a/content/renderer/pepper/pepper_compositor_host.cc b/content/renderer/pepper/pepper_compositor_host.cc index baba5b8..f7e32b6 100644 --- a/content/renderer/pepper/pepper_compositor_host.cc +++ b/content/renderer/pepper/pepper_compositor_host.cc @@ -158,10 +158,35 @@ bool PepperCompositorHost::BindToInstance( if (bound_instance_ && new_instance) return false; // Can't change a bound device. bound_instance_ = new_instance; + if (!bound_instance_) + SendCommitLayersReplyIfNecessary(); + return true; } void PepperCompositorHost::ViewInitiatedPaint() { + SendCommitLayersReplyIfNecessary(); +} + +void PepperCompositorHost::ViewFlushedPaint() {} + +void PepperCompositorHost::ImageReleased( + int32_t id, + const scoped_ptr<base::SharedMemory>& shared_memory, + uint32_t sync_point, + bool is_lost) { + ResourceReleased(id, sync_point, is_lost); +} + +void PepperCompositorHost::ResourceReleased(int32_t id, + uint32_t sync_point, + bool is_lost) { + host()->SendUnsolicitedReply( + pp_resource(), + PpapiPluginMsg_Compositor_ReleaseResource(id, sync_point, is_lost)); +} + +void PepperCompositorHost::SendCommitLayersReplyIfNecessary() { if (!commit_layers_reply_context_.is_valid()) return; host()->SendReply(commit_layers_reply_context_, @@ -169,8 +194,6 @@ void PepperCompositorHost::ViewInitiatedPaint() { commit_layers_reply_context_ = ppapi::host::ReplyMessageContext(); } -void PepperCompositorHost::ViewFlushedPaint() {} - void PepperCompositorHost::UpdateLayer( const scoped_refptr<cc::Layer>& layer, const ppapi::CompositorLayerData* old_layer, @@ -277,22 +300,6 @@ void PepperCompositorHost::UpdateLayer( NOTREACHED(); } -void PepperCompositorHost::ResourceReleased(int32_t id, - uint32_t sync_point, - bool is_lost) { - host()->SendUnsolicitedReply( - pp_resource(), - PpapiPluginMsg_Compositor_ReleaseResource(id, sync_point, is_lost)); -} - -void PepperCompositorHost::ImageReleased( - int32_t id, - const scoped_ptr<base::SharedMemory>& shared_memory, - uint32_t sync_point, - bool is_lost) { - ResourceReleased(id, sync_point, is_lost); -} - int32_t PepperCompositorHost::OnResourceMessageReceived( const IPC::Message& msg, HostMessageContext* context) { @@ -311,15 +318,9 @@ int32_t PepperCompositorHost::OnHostMsgCommitLayers( HostMessageContext* context, const std::vector<ppapi::CompositorLayerData>& layers, bool reset) { - // Do not support CommitLayers() on an unbounded compositor. - if (!bound_instance_) - return PP_ERROR_FAILED; - if (commit_layers_reply_context_.is_valid()) return PP_ERROR_INPROGRESS; - commit_layers_reply_context_ = context->MakeReplyMessageContext(); - scoped_ptr<scoped_ptr<base::SharedMemory>[]> image_shms; if (layers.size() > 0) { image_shms.reset(new scoped_ptr<base::SharedMemory>[layers.size()]); @@ -373,6 +374,11 @@ int32_t PepperCompositorHost::OnHostMsgCommitLayers( if (layer_->layer_tree_host()) layer_->layer_tree_host()->SetNeedsCommit(); + // If the host is not bound to the instance, return PP_OK immediately. + if (!bound_instance_) + return PP_OK; + + commit_layers_reply_context_ = context->MakeReplyMessageContext(); return PP_OK_COMPLETIONPENDING; } diff --git a/content/renderer/pepper/pepper_compositor_host.h b/content/renderer/pepper/pepper_compositor_host.h index 6d5a3ef..de2f72b 100644 --- a/content/renderer/pepper/pepper_compositor_host.h +++ b/content/renderer/pepper/pepper_compositor_host.h @@ -44,17 +44,18 @@ class PepperCompositorHost : public ppapi::host::ResourceHost { private: virtual ~PepperCompositorHost(); - void UpdateLayer(const scoped_refptr<cc::Layer>& layer, - const ppapi::CompositorLayerData* old_layer, - const ppapi::CompositorLayerData* new_layer, - scoped_ptr<base::SharedMemory> image_shm); - void ResourceReleased(int32_t id, - uint32_t sync_point, - bool is_lost); void ImageReleased(int32_t id, const scoped_ptr<base::SharedMemory>& shared_memory, uint32_t sync_point, bool is_lost); + void ResourceReleased(int32_t id, + uint32_t sync_point, + bool is_lost); + void SendCommitLayersReplyIfNecessary(); + void UpdateLayer(const scoped_refptr<cc::Layer>& layer, + const ppapi::CompositorLayerData* old_layer, + const ppapi::CompositorLayerData* new_layer, + scoped_ptr<base::SharedMemory> image_shm); // ResourceMessageHandler overrides: virtual int32_t OnResourceMessageReceived( diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc index 9aa3354..4aaad86 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc @@ -1877,7 +1877,7 @@ void PepperPluginInstanceImpl::UpdateFlashFullscreenState( return; } - UpdateLayer(); + UpdateLayer(false); bool old_plugin_focus = PluginHasFocus(); flash_fullscreen_ = flash_fullscreen; @@ -2016,7 +2016,7 @@ bool PepperPluginInstanceImpl::PrintPDFOutput(PP_Resource print_output, #endif } -void PepperPluginInstanceImpl::UpdateLayer() { +void PepperPluginInstanceImpl::UpdateLayer(bool device_changed) { if (!container_) return; @@ -2031,7 +2031,8 @@ void PepperPluginInstanceImpl::UpdateLayer() { bool want_texture_layer = want_3d_layer || want_2d_layer; bool want_compositor_layer = !!bound_compositor_; - if ((want_texture_layer == !!texture_layer_.get()) && + if (!device_changed && + (want_texture_layer == !!texture_layer_.get()) && (want_3d_layer == layer_is_hardware_) && (want_compositor_layer == !!compositor_layer_) && layer_bound_to_fullscreen_ == !!fullscreen_container_) { @@ -2272,7 +2273,7 @@ PP_Bool PepperPluginInstanceImpl::BindGraphics(PP_Instance instance, // Special-case clearing the current device. if (!device) { - UpdateLayer(); + UpdateLayer(true); InvalidateRect(gfx::Rect()); return PP_TRUE; } @@ -2308,13 +2309,13 @@ PP_Bool PepperPluginInstanceImpl::BindGraphics(PP_Instance instance, if (compositor) { if (compositor->BindToInstance(this)) { bound_compositor_ = compositor; - UpdateLayer(); + UpdateLayer(true); return PP_TRUE; } } else if (graphics_2d) { if (graphics_2d->BindToInstance(this)) { bound_graphics_2d_platform_ = graphics_2d; - UpdateLayer(); + UpdateLayer(true); return PP_TRUE; } } else if (graphics_3d) { @@ -2323,7 +2324,7 @@ PP_Bool PepperPluginInstanceImpl::BindGraphics(PP_Instance instance, if (graphics_3d->pp_instance() == pp_instance() && graphics_3d->BindToInstance(true)) { bound_graphics_3d_ = graphics_3d; - UpdateLayer(); + UpdateLayer(true); return PP_TRUE; } } @@ -3094,7 +3095,7 @@ bool PepperPluginInstanceImpl::FlashSetFullscreen(bool fullscreen, DCHECK(!fullscreen_container_); fullscreen_container_ = render_frame_->CreatePepperFullscreenContainer(this); - UpdateLayer(); + UpdateLayer(false); } else { DCHECK(fullscreen_container_); fullscreen_container_->Destroy(); diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.h b/content/renderer/pepper/pepper_plugin_instance_impl.h index ea21418..ee66136 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.h +++ b/content/renderer/pepper/pepper_plugin_instance_impl.h @@ -635,7 +635,10 @@ class CONTENT_EXPORT PepperPluginInstanceImpl // - we are not in Flash full-screen mode (or transitioning to it) // Otherwise it destroys the layer. // It does either operation lazily. - void UpdateLayer(); + // device_changed: true if the bound device has been changed, and + // UpdateLayer() will be forced to recreate the layer and attaches to the + // container. + void UpdateLayer(bool device_changed); // Internal helper function for PrintPage(). bool PrintPageHelper(PP_PrintPageNumberRange_Dev* page_ranges, diff --git a/ppapi/examples/compositor/compositor.cc b/ppapi/examples/compositor/compositor.cc index 360bfba..e7e3f1f 100644 --- a/ppapi/examples/compositor/compositor.cc +++ b/ppapi/examples/compositor/compositor.cc @@ -72,6 +72,7 @@ class DemoInstance : public pp::Instance, public pp::Graphics3DClient { void InitGL(int32_t result); GLuint PrepareFramebuffer(); pp::ImageData PrepareImage(); + void PrepareLayers(int32_t frame); void Paint(int32_t result, int32_t frame); void OnTextureReleased(int32_t result, GLuint texture); void OnImageReleased(int32_t result, const pp::ImageData& image); @@ -106,8 +107,7 @@ DemoInstance::DemoInstance(PP_Instance instance) context_(NULL), fbo_(0), rbo_(0), - compositor_(this), - rebuild_layers_(false), + rebuild_layers_(true), total_resource_(0), cube_(new SpinningCube()) { RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE); @@ -147,11 +147,7 @@ bool DemoInstance::HandleInputEvent(const pp::InputEvent& event) { void DemoInstance::Graphics3DContextLost() { fbo_ = 0; rbo_ = 0; - compositor_.ResetLayers(); - color_layer_ = pp::CompositorLayer(); - stable_texture_layer_ = pp::CompositorLayer(); - texture_layer_ = pp::CompositorLayer(); - image_layer_ = pp::CompositorLayer(); + rebuild_layers_ = true; total_resource_ -= static_cast<int32_t>(textures_.size()); textures_.clear(); delete context_; @@ -260,14 +256,12 @@ pp::ImageData DemoInstance::PrepareImage() { void DemoInstance::Paint(int32_t result, int32_t frame) { assert(result == PP_OK); - if (result != PP_OK || !context_) return; - int32_t rv; - if (rebuild_layers_) { - compositor_.ResetLayers(); + compositor_ = pp::Compositor(this); + assert(BindGraphics(compositor_)); color_layer_ = pp::CompositorLayer(); stable_texture_layer_ = pp::CompositorLayer(); texture_layer_ = pp::CompositorLayer(); @@ -276,6 +270,21 @@ void DemoInstance::Paint(int32_t result, int32_t frame) { rebuild_layers_ = false; } + PrepareLayers(frame); + + int32_t rv = compositor_.CommitLayers( + callback_factory_.NewCallback(&DemoInstance::Paint, ++frame)); + assert(rv == PP_OK_COMPLETIONPENDING); + + pp::VarDictionary dict; + dict.Set("total_resource", total_resource_); + size_t free_resource = textures_.size() + images_.size(); + dict.Set("free_resource", static_cast<int32_t>(free_resource)); + PostMessage(dict); +} + +void DemoInstance::PrepareLayers(int32_t frame) { + int32_t rv; float factor_sin = sin(M_PI / 180 * frame); float factor_cos = cos(M_PI / 180 * frame); { @@ -395,26 +404,23 @@ void DemoInstance::Paint(int32_t result, int32_t frame) { rv = texture_layer_.SetPremultipliedAlpha(PP_FALSE); assert(rv == PP_OK); } - - rv = compositor_.CommitLayers( - callback_factory_.NewCallback(&DemoInstance::Paint, ++frame)); - assert(rv == PP_OK_COMPLETIONPENDING); - - pp::VarDictionary dict; - dict.Set(pp::Var("total_resource"), pp::Var(total_resource_)); - dict.Set(pp::Var("free_resource"), - pp::Var((int32_t)(textures_.size() + images_.size()))); - PostMessage(dict); } void DemoInstance::OnTextureReleased(int32_t result, GLuint texture) { - if (result == PP_OK) + if (result == PP_OK) { textures_.push_back(texture); + } else { + glDeleteTextures(1, &texture); + total_resource_--; + } } void DemoInstance::OnImageReleased(int32_t result, const pp::ImageData& image) { - if (result == PP_OK) + if (result == PP_OK) { images_.push_back(image); + } else { + total_resource_--; + } } // This object is the global object representing this plugin library as long diff --git a/ppapi/ppapi_sources.gypi b/ppapi/ppapi_sources.gypi index 8c0c531..10f2d16 100644 --- a/ppapi/ppapi_sources.gypi +++ b/ppapi/ppapi_sources.gypi @@ -406,6 +406,8 @@ 'tests/test_audio_config.h', 'tests/test_case.cc', 'tests/test_case.h', + 'tests/test_compositor.cc', + 'tests/test_compositor.h', 'tests/test_console.cc', 'tests/test_console.h', 'tests/test_core.cc', diff --git a/ppapi/proxy/compositor_layer_resource.cc b/ppapi/proxy/compositor_layer_resource.cc index a33f7c1..17bc7b2 100644 --- a/ppapi/proxy/compositor_layer_resource.cc +++ b/ppapi/proxy/compositor_layer_resource.cc @@ -32,11 +32,17 @@ void OnTextureReleased( const ScopedPPResource& context, uint32_t texture, const scoped_refptr<TrackedCallback>& release_callback, + int32_t result, uint32_t sync_point, bool is_lost) { if (!TrackedCallback::IsPending(release_callback)) return; + if (result != PP_OK) { + release_callback->Run(result); + return; + } + do { if (!sync_point) break; @@ -59,11 +65,12 @@ void OnImageReleased( const ScopedPPResource& layer, const ScopedPPResource& image, const scoped_refptr<TrackedCallback>& release_callback, + int32_t result, uint32_t sync_point, bool is_lost) { if (!TrackedCallback::IsPending(release_callback)) return; - release_callback->Run(PP_OK); + release_callback->Run(result); } } // namespace @@ -105,7 +112,6 @@ int32_t CompositorLayerResource::SetColor(float red, if (!size) return PP_ERROR_BADARGUMENT; - data_.color->red = clamp(red); data_.color->green = clamp(green); data_.color->blue = clamp(blue); @@ -207,6 +213,11 @@ int32_t CompositorLayerResource::SetImage( data_.image->source_rect.point = PP_MakeFloatPoint(0.0f, 0.0f); data_.image->source_rect.size = source_size_; + // If the PP_Resource of this layer is released by the plugin, the + // release_callback will be aborted immediately, but the texture or image + // in this layer may still being used by chromium compositor. So we have to + // use ScopedPPResource to keep this resource alive until the texture or image + // is released by the chromium compositor. release_callback_ = base::Bind( &OnImageReleased, ScopedPPResource(pp_resource()), // Keep layer alive. @@ -333,7 +344,7 @@ bool CompositorLayerResource::SetType(LayerType type) { int32_t CompositorLayerResource::CheckForSetTextureAndImage( LayerType type, const scoped_refptr<TrackedCallback>& release_callback) { - if (!compositor_) + if (!compositor_) return PP_ERROR_BADRESOURCE; if (compositor_->IsInProgress()) diff --git a/ppapi/proxy/compositor_layer_resource.h b/ppapi/proxy/compositor_layer_resource.h index fafaa98..a31d8fe 100644 --- a/ppapi/proxy/compositor_layer_resource.h +++ b/ppapi/proxy/compositor_layer_resource.h @@ -22,7 +22,7 @@ class PPAPI_PROXY_EXPORT CompositorLayerResource public thunk::PPB_CompositorLayer_API { public: // Release callback for texture or image layer. - typedef base::Callback<void(uint32_t, bool)> ReleaseCallback; + typedef base::Callback<void(int32_t, uint32_t, bool)> ReleaseCallback; CompositorLayerResource(Connection connection, PP_Instance instance, diff --git a/ppapi/proxy/compositor_resource.cc b/ppapi/proxy/compositor_resource.cc index 3ada734..443d7a9 100644 --- a/ppapi/proxy/compositor_resource.cc +++ b/ppapi/proxy/compositor_resource.cc @@ -6,6 +6,7 @@ #include "base/logging.h" #include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/thunk/enter.h" namespace ppapi { namespace proxy { @@ -18,8 +19,25 @@ CompositorResource::CompositorResource(Connection connection, SendCreate(RENDERER, PpapiHostMsg_Compositor_Create()); } +bool CompositorResource::IsInProgress() const { + ProxyLock::AssertAcquiredDebugOnly(); + return TrackedCallback::IsPending(commit_callback_); +} + +int32_t CompositorResource::GenerateResourceId() const { + ProxyLock::AssertAcquiredDebugOnly(); + return ++last_resource_id_; +} + CompositorResource::~CompositorResource() { - ResetLayersInternal(); + ResetLayersInternal(true); + + // Abort all release callbacks. + for (ReleaseCallbackMap::iterator it = release_callback_map_.begin(); + it != release_callback_map_.end(); ++it) { + if (!it->second.is_null()) + it->second.Run(PP_ERROR_ABORTED, 0, false); + } } thunk::PPB_Compositor_API* CompositorResource::AsPPB_Compositor_API() { @@ -74,7 +92,8 @@ int32_t CompositorResource::CommitLayers( int32_t CompositorResource::ResetLayers() { if (IsInProgress()) return PP_ERROR_INPROGRESS; - ResetLayersInternal(); + + ResetLayersInternal(false); return PP_OK; } @@ -112,16 +131,16 @@ void CompositorResource::OnPluginMsgReleaseResource( ReleaseCallbackMap::iterator it = release_callback_map_.find(id); DCHECK(it != release_callback_map_.end()) << "Can not found release_callback_ by id(" << id << ")!"; - it->second.Run(sync_point, is_lost); + it->second.Run(PP_OK, sync_point, is_lost); release_callback_map_.erase(it); } -void CompositorResource::ResetLayersInternal() { +void CompositorResource::ResetLayersInternal(bool is_aborted) { for (LayerList::iterator it = layers_.begin(); it != layers_.end(); ++it) { ReleaseCallback release_callback = (*it)->release_callback(); if (!release_callback.is_null()) { - release_callback.Run(0, false); + release_callback.Run(is_aborted ? PP_ERROR_ABORTED : PP_OK, 0, false); (*it)->ResetReleaseCallback(); } (*it)->Invalidate(); diff --git a/ppapi/proxy/compositor_resource.h b/ppapi/proxy/compositor_resource.h index f3d13d4..8bdeb3f 100644 --- a/ppapi/proxy/compositor_resource.h +++ b/ppapi/proxy/compositor_resource.h @@ -10,6 +10,7 @@ #include "ppapi/proxy/compositor_layer_resource.h" #include "ppapi/proxy/plugin_resource.h" #include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/proxy_lock.h" #include "ppapi/thunk/ppb_compositor_api.h" namespace ppapi { @@ -22,13 +23,9 @@ class PPAPI_PROXY_EXPORT CompositorResource CompositorResource(Connection connection, PP_Instance instance); - bool IsInProgress() const { - return TrackedCallback::IsPending(commit_callback_); - } + bool IsInProgress() const; - int32_t GenerateResourceId() const { - return ++last_resource_id_; - } + int32_t GenerateResourceId() const; private: virtual ~CompositorResource(); @@ -54,7 +51,7 @@ class PPAPI_PROXY_EXPORT CompositorResource uint32_t sync_point, bool is_lost); - void ResetLayersInternal(); + void ResetLayersInternal(bool is_aborted); // Callback for CommitLayers(). scoped_refptr<TrackedCallback> commit_callback_; diff --git a/ppapi/tests/test_compositor.cc b/ppapi/tests/test_compositor.cc new file mode 100644 index 0000000..e844e8d --- /dev/null +++ b/ppapi/tests/test_compositor.cc @@ -0,0 +1,430 @@ +// Copyright (c) 2014 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 "ppapi/tests/test_compositor.h" + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "ppapi/c/ppb_opengles2.h" +#include "ppapi/cpp/compositor.h" +#include "ppapi/cpp/compositor_layer.h" +#include "ppapi/cpp/image_data.h" +#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h" +#include "ppapi/lib/gl/include/GLES2/gl2.h" +#include "ppapi/lib/gl/include/GLES2/gl2ext.h" +#include "ppapi/tests/test_utils.h" + +namespace { + +const float kMatrix[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, +}; + +} // namespace + +REGISTER_TEST_CASE(Compositor); + +#define VERIFY(r) do { \ + std::string result = (r); \ + if (result != "") \ + return result; \ + } while (false) + +bool TestCompositor::Init() { + if (!CheckTestingInterface()) + return false; + + if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) + return false; + + return true; +} + +void TestCompositor::RunTests(const std::string& filter) { + RUN_CALLBACK_TEST(TestCompositor, Release, filter); + RUN_CALLBACK_TEST(TestCompositor, ReleaseWithoutCommit, filter); + RUN_CALLBACK_TEST(TestCompositor, CommitTwoTimesWithoutChange, filter); + RUN_CALLBACK_TEST(TestCompositor, General, filter); + + RUN_CALLBACK_TEST(TestCompositor, ReleaseUnbound, filter); + RUN_CALLBACK_TEST(TestCompositor, ReleaseWithoutCommitUnbound, filter); + RUN_CALLBACK_TEST(TestCompositor, CommitTwoTimesWithoutChangeUnbound, filter); + RUN_CALLBACK_TEST(TestCompositor, GeneralUnbound, filter); + + RUN_CALLBACK_TEST(TestCompositor, BindUnbind, filter); +} + +std::string TestCompositor::TestRelease() { + return TestReleaseInternal(true); +} + +std::string TestCompositor::TestReleaseWithoutCommit() { + return TestReleaseWithoutCommitInternal(true); +} + +std::string TestCompositor::TestCommitTwoTimesWithoutChange() { + return TestCommitTwoTimesWithoutChangeInternal(true); +} + +std::string TestCompositor::TestGeneral() { + return TestGeneralInternal(true); +} + +std::string TestCompositor::TestReleaseUnbound() { + return TestReleaseInternal(false); +} + +std::string TestCompositor::TestReleaseWithoutCommitUnbound() { + return TestReleaseWithoutCommitInternal(false); +} + +std::string TestCompositor::TestCommitTwoTimesWithoutChangeUnbound() { + return TestCommitTwoTimesWithoutChangeInternal(false); +} + +std::string TestCompositor::TestGeneralUnbound() { + return TestGeneralInternal(false); +} + +// TODO(penghuang): refactor common part in all tests to a member function. +std::string TestCompositor::TestBindUnbind() { + // Setup GLES2 + const int32_t attribs[] = { + PP_GRAPHICS3DATTRIB_WIDTH, 16, + PP_GRAPHICS3DATTRIB_HEIGHT, 16, + PP_GRAPHICS3DATTRIB_NONE + }; + pp::Graphics3D graphics_3d(instance_, attribs); + ASSERT_FALSE(graphics_3d.is_null()); + glSetCurrentContextPPAPI(graphics_3d.pp_resource()); + + pp::Compositor compositor = pp::Compositor(instance_); + ASSERT_FALSE(compositor.is_null()); + + // Add layers on an unbound compositor. + pp::CompositorLayer color_layer = compositor.AddLayer(); + ASSERT_FALSE(color_layer.is_null()); + + VERIFY(SetColorLayer(color_layer, PP_OK)); + + uint32_t texture = 0; + VERIFY(CreateTexture(&texture)); + pp::CompositorLayer texture_layer = compositor.AddLayer(); + ASSERT_FALSE(texture_layer.is_null()); + TestCompletionCallback texture_release_callback(instance_->pp_instance(), + PP_REQUIRED); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, + texture_layer.SetTexture(graphics_3d, texture, pp::Size(100, 100), + texture_release_callback.GetCallback())); + + pp::ImageData image; + VERIFY(CreateImage(&image)); + pp::CompositorLayer image_layer = compositor.AddLayer(); + TestCompletionCallback image_release_callback(instance_->pp_instance(), + PP_REQUIRED); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, + image_layer.SetImage(image, pp::Size(100, 100), + image_release_callback.GetCallback())); + + // Commit layers to the chromium compositor. + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + callback.WaitForResult(compositor.CommitLayers(callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + // Bind the compositor and call CommitLayers() again. + ASSERT_TRUE(instance_->BindGraphics(compositor)); + callback.WaitForResult(compositor.CommitLayers(callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + // Unbind the compositor and call CommitLayers() again. + ASSERT_TRUE(instance_->BindGraphics(pp::Compositor())); + callback.WaitForResult(compositor.CommitLayers(callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + // Reset layers and call CommitLayers() again. + ASSERT_EQ(PP_OK, compositor.ResetLayers()); + callback.WaitForResult(compositor.CommitLayers(callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + texture_release_callback.WaitForResult(PP_OK_COMPLETIONPENDING); + ASSERT_EQ(PP_OK, texture_release_callback.result()); + ReleaseTexture(texture); + + image_release_callback.WaitForResult(PP_OK_COMPLETIONPENDING); + ASSERT_EQ(PP_OK, image_release_callback.result()); + + // Reset + glSetCurrentContextPPAPI(0); + + PASS(); +} + +std::string TestCompositor::TestReleaseInternal(bool bind) { + // Setup GLES2 + const int32_t attribs[] = { + PP_GRAPHICS3DATTRIB_WIDTH, 16, + PP_GRAPHICS3DATTRIB_HEIGHT, 16, + PP_GRAPHICS3DATTRIB_NONE + }; + pp::Graphics3D graphics_3d(instance_, attribs); + ASSERT_FALSE(graphics_3d.is_null()); + glSetCurrentContextPPAPI(graphics_3d.pp_resource()); + + pp::Compositor compositor = pp::Compositor(instance_); + ASSERT_FALSE(compositor.is_null()); + + // Bind the compositor to the instance + if (bind) + ASSERT_TRUE(instance_->BindGraphics(compositor)); + + pp::CompositorLayer color_layer = compositor.AddLayer(); + ASSERT_FALSE(color_layer.is_null()); + + VERIFY(SetColorLayer(color_layer, PP_OK)); + + uint32_t texture = 0; + VERIFY(CreateTexture(&texture)); + pp::CompositorLayer texture_layer = compositor.AddLayer(); + ASSERT_FALSE(texture_layer.is_null()); + TestCompletionCallback texture_release_callback(instance_->pp_instance(), + PP_REQUIRED); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, + texture_layer.SetTexture(graphics_3d, texture, pp::Size(100, 100), + texture_release_callback.GetCallback())); + + pp::ImageData image; + VERIFY(CreateImage(&image)); + pp::CompositorLayer image_layer = compositor.AddLayer(); + TestCompletionCallback image_release_callback(instance_->pp_instance(), + PP_REQUIRED); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, + image_layer.SetImage(image, pp::Size(100, 100), + image_release_callback.GetCallback())); + + // Commit layers to the chromium compositor. + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + callback.WaitForResult(compositor.CommitLayers(callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + // Release the compositor, and then release_callback will be aborted. + compositor = pp::Compositor(); + + texture_release_callback.WaitForResult(PP_OK_COMPLETIONPENDING); + ASSERT_EQ(PP_ERROR_ABORTED, texture_release_callback.result()); + ReleaseTexture(texture); + + image_release_callback.WaitForResult(PP_OK_COMPLETIONPENDING); + ASSERT_EQ(PP_ERROR_ABORTED, image_release_callback.result()); + + // Reset + glSetCurrentContextPPAPI(0); + + PASS(); +} + +std::string TestCompositor::TestReleaseWithoutCommitInternal(bool bind) { + // Setup GLES2 + const int32_t attribs[] = { + PP_GRAPHICS3DATTRIB_WIDTH, 16, + PP_GRAPHICS3DATTRIB_HEIGHT, 16, + PP_GRAPHICS3DATTRIB_NONE + }; + pp::Graphics3D graphics_3d(instance_, attribs); + ASSERT_FALSE(graphics_3d.is_null()); + glSetCurrentContextPPAPI(graphics_3d.pp_resource()); + + pp::Compositor compositor = pp::Compositor(instance_); + ASSERT_FALSE(compositor.is_null()); + + // Bind the compositor to the instance + if (bind) + ASSERT_TRUE(instance_->BindGraphics(compositor)); + + pp::CompositorLayer color_layer = compositor.AddLayer(); + ASSERT_FALSE(color_layer.is_null()); + + VERIFY(SetColorLayer(color_layer, PP_OK)); + + uint32_t texture = 0; + VERIFY(CreateTexture(&texture)); + pp::CompositorLayer texture_layer = compositor.AddLayer(); + ASSERT_FALSE(texture_layer.is_null()); + TestCompletionCallback texture_release_callback(instance_->pp_instance(), + PP_REQUIRED); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, + texture_layer.SetTexture(graphics_3d, texture, pp::Size(100, 100), + texture_release_callback.GetCallback())); + + pp::ImageData image; + VERIFY(CreateImage(&image)); + pp::CompositorLayer image_layer = compositor.AddLayer(); + TestCompletionCallback image_release_callback(instance_->pp_instance(), + PP_REQUIRED); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, + image_layer.SetImage(image, pp::Size(100, 100), + image_release_callback.GetCallback())); + + // Release the compositor, and then release_callback will be aborted. + compositor = pp::Compositor(); + + // All release_callbacks should be called. + texture_release_callback.WaitForResult(PP_OK_COMPLETIONPENDING); + ASSERT_EQ(PP_ERROR_ABORTED, texture_release_callback.result()); + ReleaseTexture(texture); + + image_release_callback.WaitForResult(PP_OK_COMPLETIONPENDING); + ASSERT_EQ(PP_ERROR_ABORTED, image_release_callback.result()); + + // The layer associated to the compositor will become invalidated. + VERIFY(SetColorLayer(color_layer, PP_ERROR_BADRESOURCE)); + + // Reset + glSetCurrentContextPPAPI(0); + + PASS(); +} + +std::string TestCompositor::TestCommitTwoTimesWithoutChangeInternal(bool bind) { + pp::Compositor compositor(instance_); + ASSERT_FALSE(compositor.is_null()); + if (bind) + ASSERT_TRUE(instance_->BindGraphics(compositor)); + pp::CompositorLayer layer = compositor.AddLayer(); + ASSERT_FALSE(layer.is_null()); + VERIFY(SetColorLayer(layer, PP_OK)); + + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + callback.WaitForResult(compositor.CommitLayers(callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + // CommitLayers() without any change. + callback.WaitForResult(compositor.CommitLayers(callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + PASS(); +} + +std::string TestCompositor::TestGeneralInternal(bool bind) { + // Setup GLES2 + const int32_t attribs[] = { + PP_GRAPHICS3DATTRIB_WIDTH, 16, + PP_GRAPHICS3DATTRIB_HEIGHT, 16, + PP_GRAPHICS3DATTRIB_NONE + }; + pp::Graphics3D graphics_3d(instance_, attribs); + ASSERT_FALSE(graphics_3d.is_null()); + glSetCurrentContextPPAPI(graphics_3d.pp_resource()); + + // All functions should work with a bound compositor + pp::Compositor compositor(instance_); + ASSERT_FALSE(compositor.is_null()); + if (bind) + ASSERT_TRUE(instance_->BindGraphics(compositor)); + + pp::CompositorLayer color_layer = compositor.AddLayer(); + ASSERT_FALSE(color_layer.is_null()); + VERIFY(SetColorLayer(color_layer, PP_OK)); + + uint32_t texture = 0; + VERIFY(CreateTexture(&texture)); + pp::CompositorLayer texture_layer = compositor.AddLayer(); + ASSERT_FALSE(texture_layer.is_null()); + TestCompletionCallback texture_release_callback(instance_->pp_instance(), + PP_REQUIRED); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, + texture_layer.SetTexture(graphics_3d, texture, pp::Size(100, 100), + texture_release_callback.GetCallback())); + + pp::ImageData image; + VERIFY(CreateImage(&image)); + pp::CompositorLayer image_layer = compositor.AddLayer(); + TestCompletionCallback image_release_callback(instance_->pp_instance(), + PP_REQUIRED); + ASSERT_EQ(PP_OK_COMPLETIONPENDING, + image_layer.SetImage(image, pp::Size(100, 100), + image_release_callback.GetCallback())); + + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + callback.WaitForResult(compositor.CommitLayers(callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + // After ResetLayers(), all layers should be invalidated. + ASSERT_EQ(PP_OK, compositor.ResetLayers()); + VERIFY(SetColorLayer(color_layer, PP_ERROR_BADRESOURCE)); + + // Commit empty layer stack to the chromium compositor, and then the texture + // and the image will be released by the chromium compositor soon. + callback.WaitForResult(compositor.CommitLayers(callback.GetCallback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + texture_release_callback.WaitForResult(PP_OK_COMPLETIONPENDING); + ASSERT_EQ(PP_OK, texture_release_callback.result()); + ReleaseTexture(texture); + + image_release_callback.WaitForResult(PP_OK_COMPLETIONPENDING); + ASSERT_EQ(PP_OK, image_release_callback.result()); + + // Reset + glSetCurrentContextPPAPI(0); + + PASS(); +} + +std::string TestCompositor::CreateTexture(uint32_t* texture) { + glGenTextures(1, texture); + ASSERT_NE(0, *texture); + glBindTexture(GL_TEXTURE_2D, *texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 400, 400, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, 0); + + return std::string(); +} + +std::string TestCompositor::ReleaseTexture(uint32_t texture) { + ASSERT_NE(0u, texture); + glDeleteTextures(1, &texture); + + return std::string(); +} + +std::string TestCompositor::CreateImage(pp::ImageData* image) { + *image = pp::ImageData(instance_, PP_IMAGEDATAFORMAT_RGBA_PREMUL, + pp::Size(400, 400), false); + ASSERT_FALSE(image->is_null()); + + return std::string(); +} + +std::string TestCompositor::SetColorLayer( + pp::CompositorLayer layer, int32_t result) { + ASSERT_EQ(result, layer.SetColor(255, 255, 255, 255, pp::Size(100, 100))); + ASSERT_EQ(result, layer.SetClipRect(pp::Rect(0, 0, 50, 50))); + ASSERT_EQ(result, layer.SetTransform(kMatrix)); + ASSERT_EQ(result, layer.SetOpacity(128)); + + return std::string(); +} + + diff --git a/ppapi/tests/test_compositor.h b/ppapi/tests/test_compositor.h new file mode 100644 index 0000000..6287e6d --- /dev/null +++ b/ppapi/tests/test_compositor.h @@ -0,0 +1,52 @@ +// Copyright (c) 2014 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 PAPPI_TESTS_TEST_COMPOSITOR_H_ +#define PAPPI_TESTS_TEST_COMPOSITOR_H_ + +#include <set> +#include <string> + +#include "ppapi/cpp/compositor.h" +#include "ppapi/cpp/compositor_layer.h" +#include "ppapi/cpp/graphics_3d.h" +#include "ppapi/lib/gl/include/GLES2/gl2.h" +#include "ppapi/tests/test_case.h" + +class TestCompositor : public TestCase { + public: + TestCompositor(TestingInstance* instance) : TestCase(instance) {} + + // TestCase implementation. + virtual bool Init(); + virtual void RunTests(const std::string& filter); + + private: + // Various tests. + std::string TestRelease(); + std::string TestReleaseWithoutCommit(); + std::string TestCommitTwoTimesWithoutChange(); + std::string TestGeneral(); + + std::string TestReleaseUnbound(); + std::string TestReleaseWithoutCommitUnbound(); + std::string TestCommitTwoTimesWithoutChangeUnbound(); + std::string TestGeneralUnbound(); + + std::string TestBindUnbind(); + + std::string TestReleaseInternal(bool bind); + std::string TestReleaseWithoutCommitInternal(bool bind); + std::string TestCommitTwoTimesWithoutChangeInternal(bool bind); + std::string TestGeneralInternal(bool bind); + + // Helper functions + std::string CreateTexture(uint32_t* texture); + std::string ReleaseTexture(uint32_t texture); + std::string CreateImage(pp::ImageData* image); + std::string SetColorLayer(pp::CompositorLayer layer, int32_t result); + +}; + +#endif // PAPPI_TESTS_TEST_COMPOSItor_H_ |