From 8a304130d6d53bae89ae6023e64b261624ed5ddf Mon Sep 17 00:00:00 2001 From: "kbr@chromium.org" Date: Thu, 11 Mar 2010 01:26:00 +0000 Subject: Added support for O3D in Chrome on Mac OS X using CoreGraphics drawing model by rendering offscreen, reading back the frame buffer, and drawing the rendering results into the CGContextRef. This code path is currently Chrome-specific, but could be used for any browser with similar characteristics. This will require refactoring of the drawing and event model selection code, which may be done in a subsequent bug. Changed the RenderSurface APIs to allow the Bitmap for readback to be passed in. Added Client::SetOffscreenRenderingSurfaces so that the entry point Client::RenderClient() can be used unchanged. Fixed problem with plugin_enable_fullscreen_msg gyp variable which needs to be in top-level gypi so #define is consistent throughout project. Fixed minor issue in Cocoa key event handling. Fixed log message causing crashes when render target attachment fails. Chrome currently blacklists the O3D plugin's MIME type, so to enable support for O3D this blacklist entry needs to be removed from Chrome. Ran nearly all O3D samples in Chrome on Mac OS X. There are a couple of failures which will be fixed in subsequent bugs. Also ran samples in Safari and Firefox on Mac and verified no performance regressions. BUG=http://code.google.com/p/o3d/issues/detail?id=215 TEST=ran O3D samples in Chrome, Safari and Firefox Review URL: http://codereview.chromium.org/669220 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@41233 0039d316-1c4b-4281-b951-d872f2087c98 --- o3d/plugin/cross/o3d_glue.cc | 104 ++++++++++++++++++++++++++++++++++++++++++- o3d/plugin/cross/o3d_glue.h | 37 +++++++++++++++ 2 files changed, 140 insertions(+), 1 deletion(-) (limited to 'o3d/plugin/cross') diff --git a/o3d/plugin/cross/o3d_glue.cc b/o3d/plugin/cross/o3d_glue.cc index 6a2d53f..0d66e9c 100644 --- a/o3d/plugin/cross/o3d_glue.cc +++ b/o3d/plugin/cross/o3d_glue.cc @@ -37,7 +37,9 @@ #include #include +#include "core/cross/image_utils.h" #include "core/cross/renderer.h" +#include "core/cross/texture.h" #include "core/cross/client_info.h" #include "plugin/cross/o3d_glue.h" #include "plugin/cross/config.h" @@ -56,6 +58,10 @@ namespace glue { namespace _o3d { +using o3d::Bitmap; +using o3d::Texture; +using o3d::Texture2D; + void RegisterType(NPP npp, const ObjectBase::Class *clientclass, NPClass *npclass) { PluginObject *plugin_object = static_cast(npp->pdata); @@ -134,6 +140,7 @@ PluginObject::PluginObject(NPP npp) mac_2d_context_(0), mac_agl_context_(0), mac_cgl_context_(0), + mac_cgl_pbuffer_(0), last_mac_event_time_(0), #ifdef O3D_PLUGIN_ENABLE_FULLSCREEN_MSG time_to_hide_overlay_(0.0), @@ -165,7 +172,8 @@ PluginObject::PluginObject(NPP npp) stream_manager_(new StreamManager(npp)), cursor_type_(o3d::Cursor::DEFAULT), prev_width_(0), - prev_height_(0) { + prev_height_(0), + offscreen_rendering_enabled_(false) { #if defined(OS_WIN) || defined(OS_LINUX) memset(cursors_, 0, sizeof(cursors_)); #endif @@ -218,6 +226,7 @@ void PluginObject::Init(int argc, char* argn[], char* argv[]) { } void PluginObject::TearDown() { + DisableOffscreenRendering(); #ifdef OS_WIN ClearPluginProperty(hWnd_); #elif defined(OS_MACOSX) @@ -717,6 +726,12 @@ void PluginObject::Resize(int width, int height) { prev_height_ = height; if (renderer_ && !fullscreen_) { + // If we are rendering offscreen, we may need to reallocate the + // render surfaces. + if (offscreen_rendering_enabled_) { + AllocateOffscreenRenderSurfaces(width, height); + } + // Tell the renderer and client that our window has been resized. // If we're in fullscreen mode when this happens, we don't want to pass // the information through; the renderer will pick it up when we switch @@ -1053,6 +1068,93 @@ void PluginObject::Tick() { } } +void PluginObject::EnableOffscreenRendering() { + if (!offscreen_rendering_enabled_) { + AllocateOffscreenRenderSurfaces(width(), height()); + offscreen_rendering_enabled_ = true; + } +} + +void PluginObject::DisableOffscreenRendering() { + if (offscreen_rendering_enabled_) { + DeallocateOffscreenRenderSurfaces(); + offscreen_rendering_enabled_ = false; + } +} + +bool PluginObject::IsOffscreenRenderingEnabled() const { + return offscreen_rendering_enabled_; +} + +RenderSurface::Ref PluginObject::GetOffscreenRenderSurface() const { + return offscreen_render_surface_; +} + +Bitmap::Ref PluginObject::GetOffscreenBitmap() const { + return offscreen_readback_bitmap_; +} + +bool PluginObject::AllocateOffscreenRenderSurfaces(int width, int height) { + int pot_width = + static_cast(o3d::image::ComputePOTSize(width)); + int pot_height = + static_cast(o3d::image::ComputePOTSize(height)); + if (!renderer_ || pot_width == 0 || pot_height == 0) { + return false; + } + bool must_reallocate_render_surfaces = + (offscreen_render_surface_.IsNull() || + offscreen_depth_render_surface_.IsNull() || + offscreen_render_surface_->width() != pot_width || + offscreen_render_surface_->height() != pot_height); + if (must_reallocate_render_surfaces) { + Texture2D::Ref texture = renderer_->CreateTexture2D( + pot_width, + pot_height, + Texture::ARGB8, + 1, + true); + if (texture.IsNull()) { + return false; + } + RenderSurface::Ref surface(texture->GetRenderSurface(0)); + if (surface.IsNull()) { + return false; + } + RenderDepthStencilSurface::Ref depth(renderer_->CreateDepthStencilSurface( + pot_width, + pot_height)); + if (depth.IsNull()) { + return false; + } + offscreen_texture_ = texture; + offscreen_render_surface_ = surface; + offscreen_depth_render_surface_ = depth; + } + offscreen_render_surface_->SetClipSize(width, height); + offscreen_depth_render_surface_->SetClipSize(width, height); + if (offscreen_readback_bitmap_.IsNull() || + offscreen_readback_bitmap_->width() != width || + offscreen_readback_bitmap_->height() != height) { + o3d::Bitmap::Ref bitmap = Bitmap::Ref( + new Bitmap(service_locator())); + bitmap->Allocate(Texture::ARGB8, + width, height, 1, Bitmap::IMAGE); + offscreen_readback_bitmap_ = bitmap; + } + // Tell the Client about the newly allocated surfaces so that normal + // calls to RenderClient can automatically do the right thing. + client_->SetOffscreenRenderingSurfaces(offscreen_render_surface_, + offscreen_depth_render_surface_); + return true; +} + +void PluginObject::DeallocateOffscreenRenderSurfaces() { + offscreen_render_surface_.Reset(); + offscreen_depth_render_surface_.Reset(); + offscreen_readback_bitmap_.Reset(); +} + } // namespace _o3d namespace globals { diff --git a/o3d/plugin/cross/o3d_glue.h b/o3d/plugin/cross/o3d_glue.h index 8911804..c335665 100644 --- a/o3d/plugin/cross/o3d_glue.h +++ b/o3d/plugin/cross/o3d_glue.h @@ -53,6 +53,7 @@ #include #include "base/scoped_ptr.h" #include "base/hash_tables.h" +#include "core/cross/bitmap.h" #include "core/cross/display_mode.h" #include "core/cross/display_window.h" #include "core/cross/object_base.h" @@ -65,6 +66,8 @@ #include "core/cross/object_manager.h" #include "core/cross/error.h" #include "core/cross/profiler.h" +#include "core/cross/render_surface.h" +#include "core/cross/texture.h" #include "plugin/cross/main_thread_task_poster.h" #include "plugin/cross/np_v8_bridge.h" #include "client_glue.h" @@ -116,6 +119,7 @@ class StreamManager; namespace _o3d { using o3d::Id; using o3d::ObjectBase; +using o3d::Bitmap; using o3d::Client; using o3d::ClassManager; using o3d::ClientInfoManager; @@ -126,7 +130,10 @@ using o3d::MainThreadTaskPoster; using o3d::ObjectManager; using o3d::Profiler; using o3d::Renderer; +using o3d::RenderSurface; +using o3d::RenderDepthStencilSurface; using o3d::ServiceLocator; +using o3d::Texture2D; class NPAPIObject: public NPObject { NPP npp_; @@ -268,6 +275,9 @@ class PluginObject: public NPObject { // either can be NULL depending on drawing_model AGLContext mac_agl_context_; CGLContextObj mac_cgl_context_; + // If in Chrome, we actually do all of our rendering offscreen, and + // bootstrap off a 1x1 pbuffer + CGLPBufferObj mac_cgl_pbuffer_; // Fullscreen related stuff. @@ -475,6 +485,19 @@ class PluginObject: public NPObject { } #endif + // Support for rendering the plugin's content into render surfaces. + // This is currently different than offscreen rendering support in + // the renderer. It is a bit of a mess because only the PluginObject + // and Renderer have the necessary information about the viewport + // size, and only the Client has enough information to properly + // initiate a render. + void EnableOffscreenRendering(); + void DisableOffscreenRendering(); + bool IsOffscreenRenderingEnabled() const; + RenderSurface::Ref GetOffscreenRenderSurface() const; + RenderDepthStencilSurface::Ref GetOffscreenDepthRenderSurface() const; + Bitmap::Ref GetOffscreenBitmap() const; + private: bool fullscreen_region_valid_; int fullscreen_region_x_; @@ -497,6 +520,20 @@ class PluginObject: public NPObject { #if defined(CB_SERVICE_REMOTE) NPObject* gpu_plugin_object_; #endif + + // Support for offscreen rendering and thereby windowless plugins. + // Currently used only for the CoreGraphics drawing model on Mac OS + // X when there is no WindowRef. It would be nicer to put this in + // the Renderer and/or make its off_screen mode work everywhere, but + // this is only a legacy solution for older browsers. + bool offscreen_rendering_enabled_; + Texture2D::Ref offscreen_texture_; + RenderSurface::Ref offscreen_render_surface_; + RenderDepthStencilSurface::Ref offscreen_depth_render_surface_; + Bitmap::Ref offscreen_readback_bitmap_; + + bool AllocateOffscreenRenderSurfaces(int width, int height); + void DeallocateOffscreenRenderSurfaces(); }; } // namespace o3d -- cgit v1.1