diff options
Diffstat (limited to 'ppapi/examples/compositor/compositor.cc')
-rw-r--r-- | ppapi/examples/compositor/compositor.cc | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/ppapi/examples/compositor/compositor.cc b/ppapi/examples/compositor/compositor.cc new file mode 100644 index 0000000..d437bc84 --- /dev/null +++ b/ppapi/examples/compositor/compositor.cc @@ -0,0 +1,439 @@ +// Copyright 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. + +// Needed on Windows to get |M_PI| from math.h. +#ifdef _WIN32 +#define _USE_MATH_DEFINES +#endif + +#include <math.h> + +#include <vector> + +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_input_event.h" +#include "ppapi/cpp/compositor.h" +#include "ppapi/cpp/compositor_layer.h" +#include "ppapi/cpp/graphics_3d.h" +#include "ppapi/cpp/graphics_3d_client.h" +#include "ppapi/cpp/image_data.h" +#include "ppapi/cpp/input_event.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/module.h" +#include "ppapi/cpp/rect.h" +#include "ppapi/cpp/var_dictionary.h" +#include "ppapi/examples/compositor/spinning_cube.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/utility/completion_callback_factory.h" + +// Use assert as a poor-man's CHECK, even in non-debug mode. +// Since <assert.h> redefines assert on every inclusion (it doesn't use +// include-guards), make sure this is the last file #include'd in this file. +#undef NDEBUG +#include <assert.h> + +// When compiling natively on Windows, PostMessage can be #define-d to +// something else. +#ifdef PostMessage +#undef PostMessage +#endif + +// Assert |context_| isn't holding any GL Errors. Done as a macro instead of a +// function to preserve line number information in the failure message. +#define AssertNoGLError() \ + PP_DCHECK(!glGetError()); + +namespace { + +const int32_t kTextureWidth = 800; +const int32_t kTextureHeight = 800; +const int32_t kImageWidth = 256; +const int32_t kImageHeight = 256; + +class DemoInstance : public pp::Instance, public pp::Graphics3DClient { + public: + DemoInstance(PP_Instance instance); + virtual ~DemoInstance(); + + // pp::Instance implementation (see PPP_Instance). + virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]); + virtual void DidChangeView(const pp::Rect& position, + const pp::Rect& clip); + virtual bool HandleInputEvent(const pp::InputEvent& event); + + // pp::Graphics3DClient implementation. + virtual void Graphics3DContextLost(); + + private: + // GL-related functions. + void InitGL(int32_t result); + GLuint PrepareFramebuffer(); + pp::ImageData PrepareImage(); + void Paint(int32_t result, int32_t frame); + void OnTextureReleased(int32_t result, GLuint texture); + void OnImageReleased(int32_t result, const pp::ImageData& image); + + pp::CompletionCallbackFactory<DemoInstance> callback_factory_; + + // Owned data. + pp::Graphics3D* context_; + + GLuint fbo_; + GLuint rbo_; + + std::vector<GLuint> textures_; + std::vector<pp::ImageData> images_; + + pp::Compositor compositor_; + pp::CompositorLayer color_layer_; + pp::CompositorLayer stable_texture_layer_; + pp::CompositorLayer texture_layer_; + pp::CompositorLayer image_layer_; + + bool rebuild_layers_; + int32_t total_resource_; + + SpinningCube* cube_; +}; + +DemoInstance::DemoInstance(PP_Instance instance) + : pp::Instance(instance), + pp::Graphics3DClient(this), + callback_factory_(this), + context_(NULL), + fbo_(0), + rbo_(0), + compositor_(this), + rebuild_layers_(false), + total_resource_(0), + cube_(new SpinningCube()) { + RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE); +} + +DemoInstance::~DemoInstance() { + delete cube_; + assert(glTerminatePPAPI()); + delete context_; +} + +bool DemoInstance::Init(uint32_t /*argc*/, + const char* /*argn*/[], + const char* /*argv*/[]) { + return !!glInitializePPAPI(pp::Module::Get()->get_browser_interface()); +} + +void DemoInstance::DidChangeView( + const pp::Rect& position, const pp::Rect& /*clip*/) { + if (position.width() == 0 || position.height() == 0) + return; + // Initialize graphics. + InitGL(0); +} + +bool DemoInstance::HandleInputEvent(const pp::InputEvent& event) { + switch (event.GetType()) { + case PP_INPUTEVENT_TYPE_MOUSEDOWN: + rebuild_layers_ = true; + return true; + default: + break; + } + return false; +} + +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(); + total_resource_ -= static_cast<int32_t>(textures_.size()); + textures_.clear(); + delete context_; + context_ = NULL; + cube_->OnGLContextLost(); + pp::CompletionCallback cb = callback_factory_.NewCallback( + &DemoInstance::InitGL); + pp::Module::Get()->core()->CallOnMainThread(0, cb, 0); +} + +void DemoInstance::InitGL(int32_t /*result*/) { + if (context_) + return; + int32_t context_attributes[] = { + PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, + PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8, + PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8, + PP_GRAPHICS3DATTRIB_RED_SIZE, 8, + PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0, + PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0, + PP_GRAPHICS3DATTRIB_SAMPLES, 0, + PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, + PP_GRAPHICS3DATTRIB_WIDTH, 32, + PP_GRAPHICS3DATTRIB_HEIGHT, 32, + PP_GRAPHICS3DATTRIB_NONE, + }; + context_ = new pp::Graphics3D(this, context_attributes); + assert(!context_->is_null()); + assert(BindGraphics(compositor_)); + + glSetCurrentContextPPAPI(context_->pp_resource()); + + cube_->Init(kTextureWidth, kTextureHeight); + + Paint(PP_OK, 0); +} + +GLuint DemoInstance::PrepareFramebuffer() { + GLuint texture = 0; + if (textures_.empty()) { + total_resource_++; + // Create a texture object + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureWidth, kTextureHeight, 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); + } else { + texture = textures_.back(); + textures_.pop_back(); + } + + if (!rbo_) { + // create a renderbuffer object to store depth info + glGenRenderbuffers(1, &rbo_); + glBindRenderbuffer(GL_RENDERBUFFER, rbo_); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, + kTextureWidth, kTextureHeight); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } + + if (!fbo_) { + // create a framebuffer object + glGenFramebuffers(1, &fbo_); + } + + glBindFramebuffer(GL_FRAMEBUFFER, fbo_); + + // attach the texture to FBO color attachment point + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + texture, + 0); + + // attach the renderbuffer to depth attachment point + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, + rbo_); + + // check FBO status + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + assert(status == GL_FRAMEBUFFER_COMPLETE); + + AssertNoGLError(); + return texture; +} + +pp::ImageData DemoInstance::PrepareImage() { + if (images_.empty()) { + total_resource_++; + return pp::ImageData(this, + PP_IMAGEDATAFORMAT_RGBA_PREMUL, + pp::Size(kImageWidth, kImageHeight), + false); + } + pp::ImageData image = images_.back(); + images_.pop_back(); + return image; +} + +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(); + color_layer_ = pp::CompositorLayer(); + stable_texture_layer_ = pp::CompositorLayer(); + texture_layer_ = pp::CompositorLayer(); + image_layer_ = pp::CompositorLayer(); + frame = 0; + rebuild_layers_ = false; + } + + float factor_sin = sin(M_PI / 180 * frame); + float factor_cos = cos(M_PI / 180 * frame); + { + // Set the background color layer. + if (color_layer_.is_null()) { + color_layer_ = compositor_.AddLayer(); + assert(!color_layer_.is_null()); + static const float transform[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, + }; + rv = color_layer_.SetTransform(transform); + assert(rv == PP_OK); + } + rv = color_layer_.SetColor(fabs(factor_sin), + fabs(factor_cos), + fabs(factor_sin * factor_cos), + 1.0f, + pp::Size(800, 600)); + assert(rv == PP_OK); + } + + { + // Set the image layer + if (image_layer_.is_null()) { + image_layer_ = compositor_.AddLayer(); + assert(!image_layer_.is_null()); + } + float x = frame % 800; + float y = 200 - 200 * factor_sin; + const float transform[16] = { + fabs(factor_sin) + 0.2f, 0.0f, 0.0f, 0.0f, + 0.0f, fabs(factor_sin) + 0.2f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + x, y, 0.0f, 1.0f, + }; + rv = image_layer_.SetTransform(transform); + assert(rv == PP_OK); + + pp::ImageData image = PrepareImage(); + uint8_t *p = static_cast<uint8_t*>(image.data()); + for (int x = 0; x < kImageWidth; ++x) { + for (int y = 0; y < kImageHeight; ++y) { + *(p++) = frame; + *(p++) = frame * x; + *(p++) = frame * y; + *(p++) = 255; + } + } + rv = image_layer_.SetImage(image, pp::Size(kImageWidth, kImageHeight), + callback_factory_.NewCallback(&DemoInstance::OnImageReleased, image)); + assert(rv == PP_OK_COMPLETIONPENDING); + } + + { + // Set the stable texture layer + if (stable_texture_layer_.is_null()) { + stable_texture_layer_ = compositor_.AddLayer(); + assert(!stable_texture_layer_.is_null()); + GLuint texture = PrepareFramebuffer(); + cube_->UpdateForTimeDelta(0.02f); + cube_->Draw(); + rv = stable_texture_layer_.SetTexture( + *context_, + texture, pp::Size(600, 600), + callback_factory_.NewCallback(&DemoInstance::OnTextureReleased, + texture)); + assert(rv == PP_OK_COMPLETIONPENDING); + rv = stable_texture_layer_.SetPremultipliedAlpha(PP_FALSE); + assert(rv == PP_OK); + } + + int32_t delta = 200 * fabsf(factor_sin); + if (delta != 0) { + int32_t x_y = 25 + delta; + int32_t w_h = 650 - delta - delta; + rv = stable_texture_layer_.SetClipRect(pp::Rect(x_y, x_y, w_h, w_h)); + } else { + rv = stable_texture_layer_.SetClipRect(pp::Rect()); + } + assert(rv == PP_OK); + + const float transform[16] = { + factor_cos, -factor_sin, 0.0f, 0.0f, + factor_sin, factor_cos, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 50.0f, 50.0f, 0.0f, 1.0f, + }; + rv = stable_texture_layer_.SetTransform(transform); + assert(rv == PP_OK); + } + + { + // Set the dynamic texture layer. + if (texture_layer_.is_null()) { + texture_layer_ = compositor_.AddLayer(); + assert(!texture_layer_.is_null()); + static const float transform[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, + 200.0f, 0.0f, 0.0f, 1.0f, + }; + rv = texture_layer_.SetTransform(transform); + assert(rv == PP_OK); + } + + GLuint texture = PrepareFramebuffer(); + cube_->UpdateForTimeDelta(0.02f); + cube_->Draw(); + rv = texture_layer_.SetTexture(*context_, texture, pp::Size(400, 400), + callback_factory_.NewCallback(&DemoInstance::OnTextureReleased, + texture)); + assert(rv == PP_OK_COMPLETIONPENDING); + 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) + textures_.push_back(texture); +} + +void DemoInstance::OnImageReleased(int32_t result, const pp::ImageData& image) { + if (result == PP_OK) + images_.push_back(image); +} + +// This object is the global object representing this plugin library as long +// as it is loaded. +class DemoModule : public pp::Module { + public: + DemoModule() : Module() {} + virtual ~DemoModule() {} + + virtual pp::Instance* CreateInstance(PP_Instance instance) { + return new DemoInstance(instance); + } +}; + +} // anonymous namespace + +namespace pp { +// Factory function for your specialization of the Module object. +Module* CreateModule() { + return new DemoModule(); +} +} // namespace pp |