Home | History | Annotate | Download | only in compositor
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Needed on Windows to get |M_PI| from math.h.
      6 #ifdef _WIN32
      7 #define _USE_MATH_DEFINES
      8 #endif
      9 
     10 #include <math.h>
     11 
     12 #include <vector>
     13 
     14 #include "ppapi/c/pp_errors.h"
     15 #include "ppapi/c/pp_input_event.h"
     16 #include "ppapi/cpp/compositor.h"
     17 #include "ppapi/cpp/compositor_layer.h"
     18 #include "ppapi/cpp/graphics_3d.h"
     19 #include "ppapi/cpp/graphics_3d_client.h"
     20 #include "ppapi/cpp/image_data.h"
     21 #include "ppapi/cpp/input_event.h"
     22 #include "ppapi/cpp/instance.h"
     23 #include "ppapi/cpp/module.h"
     24 #include "ppapi/cpp/rect.h"
     25 #include "ppapi/cpp/var_dictionary.h"
     26 #include "ppapi/examples/compositor/spinning_cube.h"
     27 #include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
     28 #include "ppapi/lib/gl/include/GLES2/gl2.h"
     29 #include "ppapi/lib/gl/include/GLES2/gl2ext.h"
     30 #include "ppapi/utility/completion_callback_factory.h"
     31 
     32 // Use assert as a poor-man's CHECK, even in non-debug mode.
     33 // Since <assert.h> redefines assert on every inclusion (it doesn't use
     34 // include-guards), make sure this is the last file #include'd in this file.
     35 #undef NDEBUG
     36 #include <assert.h>
     37 
     38 // When compiling natively on Windows, PostMessage can be #define-d to
     39 // something else.
     40 #ifdef PostMessage
     41 #undef PostMessage
     42 #endif
     43 
     44 // Assert |context_| isn't holding any GL Errors.  Done as a macro instead of a
     45 // function to preserve line number information in the failure message.
     46 #define AssertNoGLError() \
     47   PP_DCHECK(!glGetError());
     48 
     49 namespace {
     50 
     51 const int32_t kTextureWidth = 800;
     52 const int32_t kTextureHeight = 800;
     53 const int32_t kImageWidth = 256;
     54 const int32_t kImageHeight = 256;
     55 
     56 class DemoInstance : public pp::Instance, public pp::Graphics3DClient {
     57  public:
     58   DemoInstance(PP_Instance instance);
     59   virtual ~DemoInstance();
     60 
     61   // pp::Instance implementation (see PPP_Instance).
     62   virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
     63   virtual void DidChangeView(const pp::Rect& position,
     64                              const pp::Rect& clip);
     65   virtual bool HandleInputEvent(const pp::InputEvent& event);
     66 
     67   // pp::Graphics3DClient implementation.
     68   virtual void Graphics3DContextLost();
     69 
     70  private:
     71   // GL-related functions.
     72   void InitGL(int32_t result);
     73   GLuint PrepareFramebuffer();
     74   pp::ImageData PrepareImage();
     75   void PrepareLayers(int32_t frame);
     76   void Paint(int32_t result, int32_t frame);
     77   void OnTextureReleased(int32_t result, GLuint texture);
     78   void OnImageReleased(int32_t result, const pp::ImageData& image);
     79 
     80   pp::CompletionCallbackFactory<DemoInstance> callback_factory_;
     81 
     82   // Owned data.
     83   pp::Graphics3D* context_;
     84 
     85   GLuint fbo_;
     86   GLuint rbo_;
     87 
     88   std::vector<GLuint> textures_;
     89   std::vector<pp::ImageData> images_;
     90 
     91   pp::Compositor compositor_;
     92   pp::CompositorLayer color_layer_;
     93   pp::CompositorLayer stable_texture_layer_;
     94   pp::CompositorLayer texture_layer_;
     95   pp::CompositorLayer image_layer_;
     96 
     97   bool rebuild_layers_;
     98   int32_t total_resource_;
     99 
    100   SpinningCube* cube_;
    101 };
    102 
    103 DemoInstance::DemoInstance(PP_Instance instance)
    104     : pp::Instance(instance),
    105       pp::Graphics3DClient(this),
    106       callback_factory_(this),
    107       context_(NULL),
    108       fbo_(0),
    109       rbo_(0),
    110       rebuild_layers_(true),
    111       total_resource_(0),
    112       cube_(new SpinningCube()) {
    113   RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
    114 }
    115 
    116 DemoInstance::~DemoInstance() {
    117   delete cube_;
    118   assert(glTerminatePPAPI());
    119   delete context_;
    120 }
    121 
    122 bool DemoInstance::Init(uint32_t /*argc*/,
    123                         const char* /*argn*/[],
    124                         const char* /*argv*/[]) {
    125   return !!glInitializePPAPI(pp::Module::Get()->get_browser_interface());
    126 }
    127 
    128 void DemoInstance::DidChangeView(
    129     const pp::Rect& position, const pp::Rect& /*clip*/) {
    130   if (position.width() == 0 || position.height() == 0)
    131     return;
    132   // Initialize graphics.
    133   InitGL(0);
    134 }
    135 
    136 bool DemoInstance::HandleInputEvent(const pp::InputEvent& event) {
    137   switch (event.GetType()) {
    138     case PP_INPUTEVENT_TYPE_MOUSEDOWN:
    139       rebuild_layers_ = true;
    140       return true;
    141     default:
    142       break;
    143   }
    144   return false;
    145 }
    146 
    147 void DemoInstance::Graphics3DContextLost() {
    148   fbo_ = 0;
    149   rbo_ = 0;
    150   rebuild_layers_ = true;
    151   total_resource_ -= static_cast<int32_t>(textures_.size());
    152   textures_.clear();
    153   delete context_;
    154   context_ = NULL;
    155   cube_->OnGLContextLost();
    156   pp::CompletionCallback cb = callback_factory_.NewCallback(
    157       &DemoInstance::InitGL);
    158   pp::Module::Get()->core()->CallOnMainThread(0, cb, 0);
    159 }
    160 
    161 void DemoInstance::InitGL(int32_t /*result*/) {
    162   if (context_)
    163     return;
    164   int32_t context_attributes[] = {
    165     PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
    166     PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8,
    167     PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8,
    168     PP_GRAPHICS3DATTRIB_RED_SIZE, 8,
    169     PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0,
    170     PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0,
    171     PP_GRAPHICS3DATTRIB_SAMPLES, 0,
    172     PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0,
    173     PP_GRAPHICS3DATTRIB_WIDTH, 32,
    174     PP_GRAPHICS3DATTRIB_HEIGHT, 32,
    175     PP_GRAPHICS3DATTRIB_NONE,
    176   };
    177   context_ = new pp::Graphics3D(this, context_attributes);
    178   assert(!context_->is_null());
    179   assert(BindGraphics(compositor_));
    180 
    181   glSetCurrentContextPPAPI(context_->pp_resource());
    182 
    183   cube_->Init(kTextureWidth, kTextureHeight);
    184 
    185   Paint(PP_OK, 0);
    186 }
    187 
    188 GLuint DemoInstance::PrepareFramebuffer() {
    189   GLuint texture = 0;
    190   if (textures_.empty()) {
    191     total_resource_++;
    192     // Create a texture object
    193     glGenTextures(1, &texture);
    194     glBindTexture(GL_TEXTURE_2D, texture);
    195     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureWidth, kTextureHeight, 0,
    196                  GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    197     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    198     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    199     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    200     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    201     glBindTexture(GL_TEXTURE_2D, 0);
    202   } else {
    203     texture = textures_.back();
    204     textures_.pop_back();
    205   }
    206 
    207   if (!rbo_) {
    208     // create a renderbuffer object to store depth info
    209     glGenRenderbuffers(1, &rbo_);
    210     glBindRenderbuffer(GL_RENDERBUFFER, rbo_);
    211     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
    212         kTextureWidth, kTextureHeight);
    213     glBindRenderbuffer(GL_RENDERBUFFER, 0);
    214   }
    215 
    216   if (!fbo_) {
    217     // create a framebuffer object
    218     glGenFramebuffers(1, &fbo_);
    219   }
    220 
    221   glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
    222 
    223   // attach the texture to FBO color attachment point
    224   glFramebufferTexture2D(GL_FRAMEBUFFER,
    225                          GL_COLOR_ATTACHMENT0,
    226                          GL_TEXTURE_2D,
    227                          texture,
    228                          0);
    229 
    230   // attach the renderbuffer to depth attachment point
    231   glFramebufferRenderbuffer(GL_FRAMEBUFFER,
    232                             GL_DEPTH_ATTACHMENT,
    233                             GL_RENDERBUFFER,
    234                             rbo_);
    235 
    236   // check FBO status
    237   GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    238   assert(status == GL_FRAMEBUFFER_COMPLETE);
    239 
    240   AssertNoGLError();
    241   return texture;
    242 }
    243 
    244 pp::ImageData DemoInstance::PrepareImage() {
    245   if (images_.empty()) {
    246     total_resource_++;
    247     return pp::ImageData(this,
    248                          PP_IMAGEDATAFORMAT_RGBA_PREMUL,
    249                          pp::Size(kImageWidth, kImageHeight),
    250                          false);
    251   }
    252   pp::ImageData image = images_.back();
    253   images_.pop_back();
    254   return image;
    255 }
    256 
    257 void DemoInstance::Paint(int32_t result, int32_t frame) {
    258   assert(result == PP_OK);
    259   if (result != PP_OK || !context_)
    260     return;
    261 
    262   if (rebuild_layers_) {
    263     compositor_ = pp::Compositor(this);
    264     assert(BindGraphics(compositor_));
    265     color_layer_ = pp::CompositorLayer();
    266     stable_texture_layer_ = pp::CompositorLayer();
    267     texture_layer_ = pp::CompositorLayer();
    268     image_layer_ = pp::CompositorLayer();
    269     frame = 0;
    270     rebuild_layers_ = false;
    271   }
    272 
    273   PrepareLayers(frame);
    274 
    275   int32_t rv = compositor_.CommitLayers(
    276       callback_factory_.NewCallback(&DemoInstance::Paint, ++frame));
    277   assert(rv == PP_OK_COMPLETIONPENDING);
    278 
    279   pp::VarDictionary dict;
    280   dict.Set("total_resource", total_resource_);
    281   size_t free_resource = textures_.size() + images_.size();
    282   dict.Set("free_resource", static_cast<int32_t>(free_resource));
    283   PostMessage(dict);
    284 }
    285 
    286 void DemoInstance::PrepareLayers(int32_t frame) {
    287   int32_t rv;
    288   float factor_sin = sin(M_PI / 180 * frame);
    289   float factor_cos = cos(M_PI / 180 * frame);
    290   {
    291     // Set the background color layer.
    292     if (color_layer_.is_null()) {
    293       color_layer_ = compositor_.AddLayer();
    294       assert(!color_layer_.is_null());
    295       static const float transform[16] = {
    296         1.0f, 0.0f, 0.0f, 0.0f,
    297         0.0f, 1.0f, 0.0f, 0.0f,
    298         0.0f, 0.0f, 1.0f, 0.0f,
    299         0.0f, 0.0f, 0.0f, 1.0f,
    300       };
    301       rv = color_layer_.SetTransform(transform);
    302       assert(rv == PP_OK);
    303     }
    304     rv = color_layer_.SetColor(fabs(factor_sin),
    305                                fabs(factor_cos),
    306                                fabs(factor_sin * factor_cos),
    307                                1.0f,
    308                                pp::Size(800, 600));
    309     assert(rv == PP_OK);
    310   }
    311 
    312   {
    313     // Set the image layer
    314     if (image_layer_.is_null()) {
    315       image_layer_ = compositor_.AddLayer();
    316       assert(!image_layer_.is_null());
    317     }
    318     float x = frame % 800;
    319     float y = 200 - 200 * factor_sin;
    320     const float transform[16] = {
    321       fabsf(factor_sin) + 0.2f, 0.0f, 0.0f, 0.0f,
    322       0.0f, fabsf(factor_sin) + 0.2f, 0.0f, 0.0f,
    323       0.0f, 0.0f, 1.0f, 0.0f,
    324          x,    y, 0.0f, 1.0f,
    325     };
    326     rv = image_layer_.SetTransform(transform);
    327     assert(rv == PP_OK);
    328 
    329     pp::ImageData image = PrepareImage();
    330     uint8_t *p = static_cast<uint8_t*>(image.data());
    331     for (int x = 0; x < kImageWidth; ++x) {
    332       for (int y = 0; y < kImageHeight; ++y) {
    333         *(p++) = frame;
    334         *(p++) = frame * x;
    335         *(p++) = frame * y;
    336         *(p++) = 255;
    337       }
    338     }
    339     rv = image_layer_.SetImage(image, pp::Size(kImageWidth, kImageHeight),
    340         callback_factory_.NewCallback(&DemoInstance::OnImageReleased, image));
    341     assert(rv == PP_OK_COMPLETIONPENDING);
    342   }
    343 
    344   {
    345     // Set the stable texture layer
    346     if (stable_texture_layer_.is_null()) {
    347       stable_texture_layer_ = compositor_.AddLayer();
    348       assert(!stable_texture_layer_.is_null());
    349       GLuint texture = PrepareFramebuffer();
    350       cube_->UpdateForTimeDelta(0.02f);
    351       cube_->Draw();
    352       rv = stable_texture_layer_.SetTexture(
    353           *context_,
    354           GL_TEXTURE_2D,
    355           texture,
    356           pp::Size(600, 600),
    357           callback_factory_.NewCallback(&DemoInstance::OnTextureReleased,
    358                                         texture));
    359       assert(rv == PP_OK_COMPLETIONPENDING);
    360       rv = stable_texture_layer_.SetPremultipliedAlpha(PP_FALSE);
    361       assert(rv == PP_OK);
    362     }
    363 
    364     int32_t delta = 200 * fabsf(factor_sin);
    365     if (delta != 0) {
    366       int32_t x_y = 25 + delta;
    367       int32_t w_h =  650 - delta - delta;
    368       rv = stable_texture_layer_.SetClipRect(pp::Rect(x_y, x_y, w_h, w_h));
    369     } else {
    370       rv = stable_texture_layer_.SetClipRect(pp::Rect());
    371     }
    372     assert(rv == PP_OK);
    373 
    374     const float transform[16] = {
    375       factor_cos, -factor_sin, 0.0f, 0.0f,
    376       factor_sin, factor_cos, 0.0f, 0.0f,
    377       0.0f, 0.0f, 1.0f, 0.0f,
    378       50.0f, 50.0f, 0.0f, 1.0f,
    379     };
    380     rv = stable_texture_layer_.SetTransform(transform);
    381     assert(rv == PP_OK);
    382   }
    383 
    384   {
    385     // Set the dynamic texture layer.
    386     if (texture_layer_.is_null()) {
    387       texture_layer_ = compositor_.AddLayer();
    388       assert(!texture_layer_.is_null());
    389       static const float transform[16] = {
    390         1.0f, 0.0f, 0.0f, 0.0f,
    391         0.0f, 1.0f, 0.0f, 0.0f,
    392         0.0f, 0.0f, 1.0f, 0.0f,
    393         200.0f, 0.0f, 0.0f, 1.0f,
    394       };
    395       rv = texture_layer_.SetTransform(transform);
    396       assert(rv == PP_OK);
    397      }
    398 
    399     GLuint texture = PrepareFramebuffer();
    400     cube_->UpdateForTimeDelta(0.02f);
    401     cube_->Draw();
    402     rv = texture_layer_.SetTexture(
    403         *context_,
    404         GL_TEXTURE_2D,
    405         texture,
    406         pp::Size(400, 400),
    407         callback_factory_.NewCallback(&DemoInstance::OnTextureReleased,
    408                                       texture));
    409     assert(rv == PP_OK_COMPLETIONPENDING);
    410     rv = texture_layer_.SetPremultipliedAlpha(PP_FALSE);
    411     assert(rv == PP_OK);
    412   }
    413 }
    414 
    415 void DemoInstance::OnTextureReleased(int32_t result, GLuint texture) {
    416   if (result == PP_OK) {
    417     textures_.push_back(texture);
    418   } else {
    419     glDeleteTextures(1, &texture);
    420     total_resource_--;
    421   }
    422 }
    423 
    424 void DemoInstance::OnImageReleased(int32_t result, const pp::ImageData& image) {
    425   if (result == PP_OK) {
    426     images_.push_back(image);
    427   } else {
    428     total_resource_--;
    429   }
    430 }
    431 
    432 // This object is the global object representing this plugin library as long
    433 // as it is loaded.
    434 class DemoModule : public pp::Module {
    435  public:
    436   DemoModule() : Module() {}
    437   virtual ~DemoModule() {}
    438 
    439   virtual pp::Instance* CreateInstance(PP_Instance instance) {
    440     return new DemoInstance(instance);
    441   }
    442 };
    443 
    444 }  // anonymous namespace
    445 
    446 namespace pp {
    447 // Factory function for your specialization of the Module object.
    448 Module* CreateModule() {
    449   return new DemoModule();
    450 }
    451 }  // namespace pp
    452