Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / ppapi / examples / compositor / compositor.cc
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           texture, pp::Size(600, 600),
355           callback_factory_.NewCallback(&DemoInstance::OnTextureReleased,
356                                         texture));
357       assert(rv == PP_OK_COMPLETIONPENDING);
358       rv = stable_texture_layer_.SetPremultipliedAlpha(PP_FALSE);
359       assert(rv == PP_OK);
360     }
361
362     int32_t delta = 200 * fabsf(factor_sin);
363     if (delta != 0) {
364       int32_t x_y = 25 + delta;
365       int32_t w_h =  650 - delta - delta;
366       rv = stable_texture_layer_.SetClipRect(pp::Rect(x_y, x_y, w_h, w_h));
367     } else {
368       rv = stable_texture_layer_.SetClipRect(pp::Rect());
369     }
370     assert(rv == PP_OK);
371
372     const float transform[16] = {
373       factor_cos, -factor_sin, 0.0f, 0.0f,
374       factor_sin, factor_cos, 0.0f, 0.0f,
375       0.0f, 0.0f, 1.0f, 0.0f,
376       50.0f, 50.0f, 0.0f, 1.0f,
377     };
378     rv = stable_texture_layer_.SetTransform(transform);
379     assert(rv == PP_OK);
380   }
381
382   {
383     // Set the dynamic texture layer.
384     if (texture_layer_.is_null()) {
385       texture_layer_ = compositor_.AddLayer();
386       assert(!texture_layer_.is_null());
387       static const float transform[16] = {
388         1.0f, 0.0f, 0.0f, 0.0f,
389         0.0f, 1.0f, 0.0f, 0.0f,
390         0.0f, 0.0f, 1.0f, 0.0f,
391         200.0f, 0.0f, 0.0f, 1.0f,
392       };
393       rv = texture_layer_.SetTransform(transform);
394       assert(rv == PP_OK);
395      }
396
397     GLuint texture = PrepareFramebuffer();
398     cube_->UpdateForTimeDelta(0.02f);
399     cube_->Draw();
400     rv = texture_layer_.SetTexture(*context_, texture, pp::Size(400, 400),
401         callback_factory_.NewCallback(&DemoInstance::OnTextureReleased,
402                                       texture));
403     assert(rv == PP_OK_COMPLETIONPENDING);
404     rv = texture_layer_.SetPremultipliedAlpha(PP_FALSE);
405     assert(rv == PP_OK);
406   }
407 }
408
409 void DemoInstance::OnTextureReleased(int32_t result, GLuint texture) {
410   if (result == PP_OK) {
411     textures_.push_back(texture);
412   } else {
413     glDeleteTextures(1, &texture);
414     total_resource_--;
415   }
416 }
417
418 void DemoInstance::OnImageReleased(int32_t result, const pp::ImageData& image) {
419   if (result == PP_OK) {
420     images_.push_back(image);
421   } else {
422     total_resource_--;
423   }
424 }
425
426 // This object is the global object representing this plugin library as long
427 // as it is loaded.
428 class DemoModule : public pp::Module {
429  public:
430   DemoModule() : Module() {}
431   virtual ~DemoModule() {}
432
433   virtual pp::Instance* CreateInstance(PP_Instance instance) {
434     return new DemoInstance(instance);
435   }
436 };
437
438 }  // anonymous namespace
439
440 namespace pp {
441 // Factory function for your specialization of the Module object.
442 Module* CreateModule() {
443   return new DemoModule();
444 }
445 }  // namespace pp