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