diff options
author | nduca@chromium.org <nduca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-22 15:41:46 +0000 |
---|---|---|
committer | nduca@chromium.org <nduca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-22 15:41:46 +0000 |
commit | be128cfc576f164873323bb28dd8939c183af84f (patch) | |
tree | 015ced5aa04acdca20f3aa819cb3d94942ef3e11 | |
parent | cdf492d1e59e9c162f35294f30d3be52f81cbea7 (diff) | |
download | chromium_src-be128cfc576f164873323bb28dd8939c183af84f.zip chromium_src-be128cfc576f164873323bb28dd8939c183af84f.tar.gz chromium_src-be128cfc576f164873323bb28dd8939c183af84f.tar.bz2 |
Revert 97644 - Unify MacOS resizing path with glResizeCHROMIUM.
Review URL: http://codereview.chromium.org/7671035
TBR=nduca@chromium.org
Review URL: http://codereview.chromium.org/7713001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97645 0039d316-1c4b-4281-b951-d872f2087c98
19 files changed, 416 insertions, 247 deletions
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc index 6076eba..047cfa7 100644 --- a/content/common/gpu/gpu_command_buffer_stub.cc +++ b/content/common/gpu/gpu_command_buffer_stub.cc @@ -99,6 +99,11 @@ bool GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) { OnCreateVideoDecoder) IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyVideoDecoder, OnDestroyVideoDecoder) + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_ResizeOffscreenFrameBuffer, + OnResizeOffscreenFrameBuffer); +#if defined(OS_MACOSX) + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SetWindowSize, OnSetWindowSize); +#endif // defined(OS_MACOSX) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -195,18 +200,38 @@ void GpuCommandBufferStub::OnInitialize( &gpu::GpuScheduler::PutChanged)); command_buffer_->SetParseErrorCallback( NewCallback(this, &GpuCommandBufferStub::OnParseError)); - scheduler_->SetScheduledCallback( - NewCallback(channel_, &GpuChannel::OnScheduled)); scheduler_->SetSwapBuffersCallback( NewCallback(this, &GpuCommandBufferStub::OnSwapBuffers)); - if (handle_ != gfx::kNullPluginWindow) { - scheduler_->SetResizeCallback( - NewCallback(this, &GpuCommandBufferStub::OnResize)); - } + scheduler_->SetScheduledCallback( + NewCallback(channel_, &GpuChannel::OnScheduled)); if (watchdog_) scheduler_->SetCommandProcessedCallback( NewCallback(this, &GpuCommandBufferStub::OnCommandProcessed)); +#if defined(OS_MACOSX) + if (handle_) { + // This context conceptually puts its output directly on the + // screen, rendered by the accelerated plugin layer in + // RenderWidgetHostViewMac. Set up a pathway to notify the + // browser process when its contents change. + scheduler_->SetSwapBuffersCallback( + NewCallback(this, + &GpuCommandBufferStub::SwapBuffersCallback)); + } +#endif // defined(OS_MACOSX) + + // Set up a pathway for resizing the output window or framebuffer at the + // right time relative to other GL commands. +#if defined(TOUCH_UI) + if (handle_ == gfx::kNullPluginWindow) { + scheduler_->SetResizeCallback( + NewCallback(this, &GpuCommandBufferStub::ResizeCallback)); + } +#else + scheduler_->SetResizeCallback( + NewCallback(this, &GpuCommandBufferStub::ResizeCallback)); +#endif + if (parent_stub_for_initialization_) { scheduler_->SetParent(parent_stub_for_initialization_->scheduler_.get(), parent_texture_for_initialization_); @@ -402,30 +427,14 @@ void GpuCommandBufferStub::OnGetTransferBuffer( Send(reply_message); } +void GpuCommandBufferStub::OnResizeOffscreenFrameBuffer(const gfx::Size& size) { + scheduler_->ResizeOffscreenFrameBuffer(size); +} + void GpuCommandBufferStub::OnSwapBuffers() { TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnSwapBuffers"); ReportState(); - -#if defined(OS_MACOSX) - if (handle_) { - // To swap on OSX, we have to send a message to the browser to get the - // context put onscreen. - GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager(); - GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; - params.renderer_id = renderer_id_; - params.render_view_id = render_view_id_; - params.window = handle_; - params.surface_id = scheduler_->GetSurfaceId(); - params.route_id = route_id(); - params.swap_buffers_count = scheduler_->swap_buffers_count(); - gpu_channel_manager->Send( - new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params)); - scheduler_->SetScheduled(false); - } -#else - // Notify the upstream commandbuffer that the swapbuffers has completed. Send(new GpuCommandBufferMsg_SwapBuffers(route_id_)); -#endif } void GpuCommandBufferStub::OnCommandProcessed() { @@ -434,40 +443,9 @@ void GpuCommandBufferStub::OnCommandProcessed() { } #if defined(OS_MACOSX) -void GpuCommandBufferStub::AcceleratedSurfaceBuffersSwapped( - uint64 swap_buffers_count) { - TRACE_EVENT1("gpu", - "GpuCommandBufferStub::AcceleratedSurfaceBuffersSwapped", - "frame", swap_buffers_count); - DCHECK(handle_ != gfx::kNullPluginWindow); - - // Multiple swapbuffers may get consolidated together into a single - // AcceleratedSurfaceBuffersSwapped call. Upstream code listening to the - // GpuCommandBufferMsg_SwapBuffers expects to be called one time for every - // swap. So, send one SwapBuffers message for every outstanding swap. - uint64 delta = swap_buffers_count - - scheduler_->acknowledged_swap_buffers_count(); - scheduler_->set_acknowledged_swap_buffers_count(swap_buffers_count); - - for(uint64 i = 0; i < delta; i++) { - // Notify the upstream commandbuffer that the swapbuffers has completed. - Send(new GpuCommandBufferMsg_SwapBuffers(route_id_)); - - // Wake up the GpuScheduler to start doing work again. - scheduler_->SetScheduled(true); - } -} -#endif // defined(OS_MACOSX) - -void GpuCommandBufferStub::OnResize(gfx::Size size) { - if (handle_ == gfx::kNullPluginWindow) - return; - +void GpuCommandBufferStub::OnSetWindowSize(const gfx::Size& size) { GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager(); - -#if defined(OS_MACOSX) - // On Mac, we need to tell the browser about the new IOSurface handle, - // asynchronously. + // Try using the IOSurface version first. uint64 new_backing_store = scheduler_->SetWindowSizeForIOSurface(size); if (new_backing_store) { GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params params; @@ -485,22 +463,62 @@ void GpuCommandBufferStub::OnResize(gfx::Size size) { // questionable. NOTREACHED(); } -#elif defined(TOOLKIT_USES_GTK) && !defined(TOUCH_UI) || defined(OS_WIN) - // On Windows, Linux, we need to coordinate resizing of onscreen - // contexts with the resizing of the actual OS-level window. We do this by - // sending a resize message to the browser process and descheduling the - // context until the ViewResized message comes back in reply. - // Send the resize message if needed +} + +void GpuCommandBufferStub::SwapBuffersCallback() { + TRACE_EVENT0("gpu", "GpuCommandBufferStub::SwapBuffersCallback"); + GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager(); + GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; + params.renderer_id = renderer_id_; + params.render_view_id = render_view_id_; + params.window = handle_; + params.surface_id = scheduler_->GetSurfaceId(); + params.route_id = route_id(); + params.swap_buffers_count = scheduler_->swap_buffers_count(); gpu_channel_manager->Send( - new GpuHostMsg_ResizeView(renderer_id_, - render_view_id_, - route_id_, - size)); + new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params)); scheduler_->SetScheduled(false); -#endif // defined(OS_MACOSX) } +void GpuCommandBufferStub::AcceleratedSurfaceBuffersSwapped( + uint64 swap_buffers_count) { + TRACE_EVENT1("gpu", + "GpuCommandBufferStub::AcceleratedSurfaceBuffersSwapped", + "frame", swap_buffers_count); + + // Multiple swapbuffers may get consolidated together into a single + // AcceleratedSurfaceBuffersSwapped call. Since OnSwapBuffers expects to be + // called one time for every swap, make up the difference here. + uint64 delta = swap_buffers_count - + scheduler_->acknowledged_swap_buffers_count(); + scheduler_->set_acknowledged_swap_buffers_count(swap_buffers_count); + + for(uint64 i = 0; i < delta; i++) { + OnSwapBuffers(); + // Wake up the GpuScheduler to start doing work again. + scheduler_->SetScheduled(true); + } +} +#endif // defined(OS_MACOSX) + +void GpuCommandBufferStub::ResizeCallback(gfx::Size size) { + if (handle_ == gfx::kNullPluginWindow) { + scheduler_->decoder()->ResizeOffscreenFrameBuffer(size); + scheduler_->decoder()->UpdateOffscreenFrameBufferSize(); + } else { +#if defined(TOOLKIT_USES_GTK) && !defined(TOUCH_UI) || defined(OS_WIN) + GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager(); + gpu_channel_manager->Send( + new GpuHostMsg_ResizeView(renderer_id_, + render_view_id_, + route_id_, + size)); + + scheduler_->SetScheduled(false); +#endif + } +} void GpuCommandBufferStub::ViewResized() { #if defined(TOOLKIT_USES_GTK) && !defined(TOUCH_UI) || defined(OS_WIN) diff --git a/content/common/gpu/gpu_command_buffer_stub.h b/content/common/gpu/gpu_command_buffer_stub.h index ef2dabb..9ea9bdb 100644 --- a/content/common/gpu/gpu_command_buffer_stub.h +++ b/content/common/gpu/gpu_command_buffer_stub.h @@ -112,6 +112,7 @@ class GpuCommandBufferStub IPC::Message* reply_message); void OnDestroyTransferBuffer(int32 id, IPC::Message* reply_message); void OnGetTransferBuffer(int32 id, IPC::Message* reply_message); + void OnResizeOffscreenFrameBuffer(const gfx::Size& size); void OnCreateVideoDecoder(const std::vector<int32>& configs, IPC::Message* reply_message); @@ -121,7 +122,12 @@ class GpuCommandBufferStub void OnCommandProcessed(); void OnParseError(); - void OnResize(gfx::Size size); +#if defined(OS_MACOSX) + void OnSetWindowSize(const gfx::Size& size); + void SwapBuffersCallback(); +#endif // defined(OS_MACOSX) + + void ResizeCallback(gfx::Size size); void ReportState(); // The lifetime of objects of this class is managed by a GpuChannel. The diff --git a/content/renderer/gpu/command_buffer_proxy.cc b/content/renderer/gpu/command_buffer_proxy.cc index 1caeb5a..caa1de5 100644 --- a/content/renderer/gpu/command_buffer_proxy.cc +++ b/content/renderer/gpu/command_buffer_proxy.cc @@ -380,6 +380,13 @@ void CommandBufferProxy::SetSwapBuffersCallback(Callback0::Type* callback) { swap_buffers_callback_.reset(callback); } +void CommandBufferProxy::ResizeOffscreenFrameBuffer(const gfx::Size& size) { + if (last_state_.error != gpu::error::kNoError) + return; + + Send(new GpuCommandBufferMsg_ResizeOffscreenFrameBuffer(route_id_, size)); +} + void CommandBufferProxy::SetNotifyRepaintTask(Task* task) { notify_repaint_task_.reset(task); } @@ -406,6 +413,15 @@ CommandBufferProxy::CreateVideoDecoder( return decoder_host; } +#if defined(OS_MACOSX) +void CommandBufferProxy::SetWindowSize(const gfx::Size& size) { + if (last_state_.error != gpu::error::kNoError) + return; + + Send(new GpuCommandBufferMsg_SetWindowSize(route_id_, size)); +} +#endif + bool CommandBufferProxy::Send(IPC::Message* msg) { // Caller should not intentionally send a message if the context is lost. DCHECK(last_state_.error == gpu::error::kNoError); diff --git a/content/renderer/gpu/command_buffer_proxy.h b/content/renderer/gpu/command_buffer_proxy.h index 8c62508..2a2e25b 100644 --- a/content/renderer/gpu/command_buffer_proxy.h +++ b/content/renderer/gpu/command_buffer_proxy.h @@ -77,6 +77,9 @@ class CommandBufferProxy : public gpu::CommandBuffer, void SetSwapBuffersCallback(Callback0::Type* callback); void SetChannelErrorCallback(Callback0::Type* callback); + // Asynchronously resizes an offscreen frame buffer. + void ResizeOffscreenFrameBuffer(const gfx::Size& size); + // Set a task that will be invoked the next time the window becomes invalid // and needs to be repainted. Takes ownership of task. void SetNotifyRepaintTask(Task* task); @@ -91,6 +94,10 @@ class CommandBufferProxy : public gpu::CommandBuffer, const std::vector<int32>& configs, media::VideoDecodeAccelerator::Client* client); +#if defined(OS_MACOSX) + virtual void SetWindowSize(const gfx::Size& size); +#endif + private: // Send an IPC message over the GPU channel. This is private to fully diff --git a/content/renderer/gpu/renderer_gl_context.cc b/content/renderer/gpu/renderer_gl_context.cc index 53baa9b..426386e 100644 --- a/content/renderer/gpu/renderer_gl_context.cc +++ b/content/renderer/gpu/renderer_gl_context.cc @@ -107,6 +107,14 @@ RendererGLContext* RendererGLContext::CreateViewContext( #endif } +#if defined(OS_MACOSX) +void RendererGLContext::ResizeOnscreen(const gfx::Size& size) { + DCHECK(size.width() > 0 && size.height() > 0); + size_ = size; + command_buffer_->SetWindowSize(size); +} +#endif + RendererGLContext* RendererGLContext::CreateOffscreenContext( GpuChannelHost* channel, const gfx::Size& size, @@ -183,6 +191,14 @@ bool RendererGLContext::SetParent(RendererGLContext* new_parent) { return true; } +void RendererGLContext::ResizeOffscreen(const gfx::Size& size) { + DCHECK(size.width() > 0 && size.height() > 0); + if (size_ != size) { + command_buffer_->ResizeOffscreenFrameBuffer(size); + size_ = size; + } +} + uint32 RendererGLContext::GetParentTextureId() { return parent_texture_id_; } @@ -410,6 +426,8 @@ bool RendererGLContext::Initialize(bool onscreen, share_resources, bind_generates_resource); + size_ = size; + return true; } diff --git a/content/renderer/gpu/renderer_gl_context.h b/content/renderer/gpu/renderer_gl_context.h index 5013dc9..a9f9580 100644 --- a/content/renderer/gpu/renderer_gl_context.h +++ b/content/renderer/gpu/renderer_gl_context.h @@ -106,6 +106,13 @@ class RendererGLContext : public base::SupportsWeakPtr<RendererGLContext> { const int32* attrib_list, const GURL& active_arl); +#if defined(OS_MACOSX) + // On Mac OS X only, view RendererGLContexts actually behave like offscreen + // RendererGLContexts, and require an explicit resize operation which is + // slightly different from that of offscreen RendererGLContexts. + void ResizeOnscreen(const gfx::Size& size); +#endif + // Create a RendererGLContext that renders to an offscreen frame buffer. If // parent is not NULL, that RendererGLContext can access a copy of the created // RendererGLContext's frame buffer that is updated every time SwapBuffers is @@ -127,6 +134,13 @@ class RendererGLContext : public base::SupportsWeakPtr<RendererGLContext> { // another parent, it is important to delete them before changing the parent. bool SetParent(RendererGLContext* parent); + // Resize an offscreen frame buffer. The resize occurs on the next call to + // SwapBuffers. This is to avoid waiting until all pending GL calls have been + // executed by the GPU process. Everything rendered up to the call to + // SwapBuffers will be lost. A lost RendererGLContext will be reported if the + // resize fails. + void ResizeOffscreen(const gfx::Size& size); + // For an offscreen frame buffer RendererGLContext, return the texture ID with // respect to the parent RendererGLContext. Returns zero if RendererGLContext // does not have a parent. @@ -199,6 +213,7 @@ class RendererGLContext : public base::SupportsWeakPtr<RendererGLContext> { gpu::gles2::GLES2CmdHelper* gles2_helper_; int32 transfer_buffer_id_; gpu::gles2::GLES2Implementation* gles2_implementation_; + gfx::Size size_; Error last_error_; int frame_number_; diff --git a/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc b/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc index 0366725..7c721df 100644 --- a/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc +++ b/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc @@ -241,7 +241,17 @@ void WebGraphicsContext3DCommandBufferImpl::reshape(int width, int height) { cached_width_ = width; cached_height_ = height; - gl_->ResizeCHROMIUM(width, height); + if (render_directly_to_web_view_) { +#if defined(OS_MACOSX) + context_->ResizeOnscreen(gfx::Size(width, height)); +#else + gl_->ResizeCHROMIUM(width, height); +#endif + } else { + context_->ResizeOffscreen(gfx::Size(width, height)); + // Force a SwapBuffers to get the framebuffer to resize. + context_->SwapBuffers(); + } #ifdef FLIP_FRAMEBUFFER_VERTICALLY scanline_.reset(new uint8[width * 4]); diff --git a/content/renderer/render_widget_fullscreen_pepper.cc b/content/renderer/render_widget_fullscreen_pepper.cc index 0d5480b..1ccd917 100644 --- a/content/renderer/render_widget_fullscreen_pepper.cc +++ b/content/renderer/render_widget_fullscreen_pepper.cc @@ -316,7 +316,11 @@ void RenderWidgetFullscreenPepper::OnResize(const gfx::Size& size, const gfx::Rect& resizer_rect) { if (context_) { gpu::gles2::GLES2Implementation* gl = context_->GetImplementation(); +#if defined(OS_MACOSX) + context_->ResizeOnscreen(size); +#else gl->ResizeCHROMIUM(size.width(), size.height()); +#endif gl->Viewport(0, 0, size.width(), size.height()); } RenderWidget::OnResize(size, resizer_rect); diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index b09e24a..574897e 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -1727,8 +1727,7 @@ _FUNCTION_INFO = { 'GLsizei stride, GLuint offset', }, 'ResizeCHROMIUM': { - 'type': 'Custom', - 'impl_func': False, + 'decoder_func': 'DoResizeCHROMIUM', 'unit_test': False, 'extension': True, 'chromium': True, diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 956ac62..e34e476 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -2482,12 +2482,6 @@ void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) { mapped_textures_.erase(it); } -void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height) { - GPU_CLIENT_LOG("[" << this << "] glResizeCHROMIUM(" - << width << ", " << height << ")"); - helper_->ResizeCHROMIUM(width, height); -} - const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() { GPU_CLIENT_LOG("[" << this << "] glGetRequestableExtensionsCHROMIUM()"); TRACE_EVENT0("gpu", @@ -2631,3 +2625,4 @@ void GLES2Implementation::GetProgramInfoCHROMIUM( } // namespace gles2 } // namespace gpu + diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index 021e3e9..ba061a5 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h @@ -1254,7 +1254,10 @@ void* MapTexSubImage2DCHROMIUM( void UnmapTexSubImage2DCHROMIUM(const void* mem); -void ResizeCHROMIUM(GLuint width, GLuint height); +void ResizeCHROMIUM(GLuint width, GLuint height) { + GPU_CLIENT_LOG("[" << this << "] glResizeCHROMIUM(" << width << ", " << height << ")"); // NOLINT + helper_->ResizeCHROMIUM(width, height); +} const GLchar* GetRequestableExtensionsCHROMIUM(); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 5e500bb..4f35103 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -468,7 +468,8 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, virtual void Destroy(); virtual bool SetParent(GLES2Decoder* parent_decoder, uint32 parent_texture_id); - virtual bool ResizeOffscreenFrameBuffer(const gfx::Size& size); + virtual void ResizeOffscreenFrameBuffer(const gfx::Size& size); + virtual bool UpdateOffscreenFrameBufferSize(); void UpdateParentTextureInfo(); virtual bool MakeCurrent(); virtual GLES2Util* GetGLES2Util() { return &util_; } @@ -1034,6 +1035,8 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // Wrapper for glValidateProgram. void DoValidateProgram(GLuint program_client_id); + void DoResizeCHROMIUM(GLuint width, GLuint height); + void DoSetSurfaceCHROMIUM(GLint surface_id); // Gets the number of values that will be returned by glGetXXX. Returns @@ -1178,6 +1181,10 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // The parent pointer is reset if the parent is destroyed. base::WeakPtr<GLES2DecoderImpl> parent_; + // Width and height to which an offscreen frame buffer should be resized on + // the next call to SwapBuffers. + gfx::Size pending_offscreen_size_; + // Current width and height of the offscreen frame buffer. gfx::Size offscreen_size_; @@ -1910,7 +1917,8 @@ bool GLES2DecoderImpl::Initialize( // Allocate the render buffers at their initial size and check the status // of the frame buffers is okay. - if (!ResizeOffscreenFrameBuffer(size)) { + pending_offscreen_size_ = size; + if (!UpdateOffscreenFrameBufferSize()) { LOG(ERROR) << "Could not allocate offscreen buffer storage."; Destroy(); return false; @@ -2218,6 +2226,140 @@ GLenum GLES2DecoderImpl::GetBoundDrawFrameBufferInternalFormat() { } } +bool GLES2DecoderImpl::UpdateOffscreenFrameBufferSize() { + if (offscreen_size_ == pending_offscreen_size_) + return true; + + offscreen_size_ = pending_offscreen_size_; + int w = offscreen_size_.width(); + int h = offscreen_size_.height(); + if (w < 0 || h < 0 || h >= (INT_MAX / 4) / (w ? w : 1)) { + LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed " + << "to allocate storage due to excessive dimensions."; + return false; + } + + // Reallocate the offscreen target buffers. + DCHECK(offscreen_target_color_format_); + if (IsOffscreenBufferMultisampled()) { + if (!offscreen_target_color_render_buffer_->AllocateStorage( + pending_offscreen_size_, offscreen_target_color_format_, + offscreen_target_samples_)) { + LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed " + << "to allocate storage for offscreen target color buffer."; + return false; + } + } else { + if (!offscreen_target_color_texture_->AllocateStorage( + pending_offscreen_size_, offscreen_target_color_format_)) { + LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed " + << "to allocate storage for offscreen target color texture."; + return false; + } + } + if (offscreen_target_depth_format_ && + !offscreen_target_depth_render_buffer_->AllocateStorage( + pending_offscreen_size_, offscreen_target_depth_format_, + offscreen_target_samples_)) { + LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed " + << "to allocate storage for offscreen target depth buffer."; + return false; + } + if (offscreen_target_stencil_format_ && + !offscreen_target_stencil_render_buffer_->AllocateStorage( + pending_offscreen_size_, offscreen_target_stencil_format_, + offscreen_target_samples_)) { + LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed " + << "to allocate storage for offscreen target stencil buffer."; + return false; + } + + // Attach the offscreen target buffers to the target frame buffer. + if (IsOffscreenBufferMultisampled()) { + offscreen_target_frame_buffer_->AttachRenderBuffer( + GL_COLOR_ATTACHMENT0, + offscreen_target_color_render_buffer_.get()); + } else { + offscreen_target_frame_buffer_->AttachRenderTexture( + offscreen_target_color_texture_.get()); + } + if (offscreen_target_depth_format_) { + offscreen_target_frame_buffer_->AttachRenderBuffer( + GL_DEPTH_ATTACHMENT, + offscreen_target_depth_render_buffer_.get()); + } + const bool packed_depth_stencil = + offscreen_target_depth_format_ == GL_DEPTH24_STENCIL8; + if (packed_depth_stencil) { + offscreen_target_frame_buffer_->AttachRenderBuffer( + GL_STENCIL_ATTACHMENT, + offscreen_target_depth_render_buffer_.get()); + } else if (offscreen_target_stencil_format_) { + offscreen_target_frame_buffer_->AttachRenderBuffer( + GL_STENCIL_ATTACHMENT, + offscreen_target_stencil_render_buffer_.get()); + } + + if (offscreen_target_frame_buffer_->CheckStatus() != + GL_FRAMEBUFFER_COMPLETE) { + LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed " + << "because offscreen FBO was incomplete."; + return false; + } + + // Clear the target frame buffer. + { + ScopedFrameBufferBinder binder(this, offscreen_target_frame_buffer_->id()); + glClearColor(0, 0, 0, (GLES2Util::GetChannelsForFormat( + offscreen_target_color_format_) & 0x0008) != 0 ? 0 : 1); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glClearStencil(0); + glStencilMaskSeparate(GL_FRONT, -1); + glStencilMaskSeparate(GL_BACK, -1); + glClearDepth(0); + glDepthMask(GL_TRUE); + glDisable(GL_SCISSOR_TEST); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + RestoreClearState(); + } + + // Allocate the offscreen saved color texture. + DCHECK(offscreen_saved_color_format_); + offscreen_saved_color_texture_->AllocateStorage( + pending_offscreen_size_, offscreen_saved_color_format_); + + offscreen_saved_frame_buffer_->AttachRenderTexture( + offscreen_saved_color_texture_.get()); + if (offscreen_saved_frame_buffer_->CheckStatus() != + GL_FRAMEBUFFER_COMPLETE) { + LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed " + << "because offscreen saved FBO was incomplete."; + return false; + } + + // Destroy the offscreen resolved framebuffers. + if (offscreen_resolved_frame_buffer_.get()) + offscreen_resolved_frame_buffer_->Destroy(); + if (offscreen_resolved_color_texture_.get()) + offscreen_resolved_color_texture_->Destroy(); + offscreen_resolved_color_texture_.reset(); + offscreen_resolved_frame_buffer_.reset(); + + // Clear the offscreen color texture. + { + ScopedFrameBufferBinder binder(this, offscreen_saved_frame_buffer_->id()); + glClearColor(0, 0, 0, 0); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDisable(GL_SCISSOR_TEST); + glClear(GL_COLOR_BUFFER_BIT); + RestoreClearState(); + } + + UpdateParentTextureInfo(); + + return true; +} + void GLES2DecoderImpl::UpdateParentTextureInfo() { if (parent_) { // Update the info about the offscreen saved color texture in the parent. @@ -2236,8 +2378,8 @@ void GLES2DecoderImpl::UpdateParentTextureInfo() { GL_TEXTURE_2D, 0, // level GL_RGBA, - offscreen_size_.width(), - offscreen_size_.height(), + pending_offscreen_size_.width(), + pending_offscreen_size_.height(), 1, // depth 0, // border GL_RGBA, @@ -2265,8 +2407,7 @@ void GLES2DecoderImpl::UpdateParentTextureInfo() { } } -void GLES2DecoderImpl::SetResizeCallback( - Callback1<gfx::Size>::Type* callback) { +void GLES2DecoderImpl::SetResizeCallback(Callback1<gfx::Size>::Type* callback) { resize_callback_.reset(callback); } @@ -2412,166 +2553,22 @@ bool GLES2DecoderImpl::SetParent(GLES2Decoder* new_parent, return true; } -bool GLES2DecoderImpl::ResizeOffscreenFrameBuffer(const gfx::Size& size) { - bool is_offscreen = !!offscreen_target_frame_buffer_.get(); - if (!is_offscreen) { - LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer called " - << " with an onscreen framebuffer."; - return false; - } - - if (offscreen_size_ == size) - return true; - - offscreen_size_ = size; - int w = offscreen_size_.width(); - int h = offscreen_size_.height(); - if (w < 0 || h < 0 || h >= (INT_MAX / 4) / (w ? w : 1)) { - LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed " - << "to allocate storage due to excessive dimensions."; - return false; - } - - // Reallocate the offscreen target buffers. - DCHECK(offscreen_target_color_format_); - if (IsOffscreenBufferMultisampled()) { - if (!offscreen_target_color_render_buffer_->AllocateStorage( - offscreen_size_, offscreen_target_color_format_, - offscreen_target_samples_)) { - LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed " - << "to allocate storage for offscreen target color buffer."; - return false; - } - } else { - if (!offscreen_target_color_texture_->AllocateStorage( - offscreen_size_, offscreen_target_color_format_)) { - LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed " - << "to allocate storage for offscreen target color texture."; - return false; - } - } - if (offscreen_target_depth_format_ && - !offscreen_target_depth_render_buffer_->AllocateStorage( - offscreen_size_, offscreen_target_depth_format_, - offscreen_target_samples_)) { - LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed " - << "to allocate storage for offscreen target depth buffer."; - return false; - } - if (offscreen_target_stencil_format_ && - !offscreen_target_stencil_render_buffer_->AllocateStorage( - offscreen_size_, offscreen_target_stencil_format_, - offscreen_target_samples_)) { - LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed " - << "to allocate storage for offscreen target stencil buffer."; - return false; - } - - // Attach the offscreen target buffers to the target frame buffer. - if (IsOffscreenBufferMultisampled()) { - offscreen_target_frame_buffer_->AttachRenderBuffer( - GL_COLOR_ATTACHMENT0, - offscreen_target_color_render_buffer_.get()); - } else { - offscreen_target_frame_buffer_->AttachRenderTexture( - offscreen_target_color_texture_.get()); - } - if (offscreen_target_depth_format_) { - offscreen_target_frame_buffer_->AttachRenderBuffer( - GL_DEPTH_ATTACHMENT, - offscreen_target_depth_render_buffer_.get()); - } - const bool packed_depth_stencil = - offscreen_target_depth_format_ == GL_DEPTH24_STENCIL8; - if (packed_depth_stencil) { - offscreen_target_frame_buffer_->AttachRenderBuffer( - GL_STENCIL_ATTACHMENT, - offscreen_target_depth_render_buffer_.get()); - } else if (offscreen_target_stencil_format_) { - offscreen_target_frame_buffer_->AttachRenderBuffer( - GL_STENCIL_ATTACHMENT, - offscreen_target_stencil_render_buffer_.get()); - } - - if (offscreen_target_frame_buffer_->CheckStatus() != - GL_FRAMEBUFFER_COMPLETE) { - LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed " - << "because offscreen FBO was incomplete."; - return false; - } - - // Clear the target frame buffer. - { - ScopedFrameBufferBinder binder(this, offscreen_target_frame_buffer_->id()); - glClearColor(0, 0, 0, (GLES2Util::GetChannelsForFormat( - offscreen_target_color_format_) & 0x0008) != 0 ? 0 : 1); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glClearStencil(0); - glStencilMaskSeparate(GL_FRONT, -1); - glStencilMaskSeparate(GL_BACK, -1); - glClearDepth(0); - glDepthMask(GL_TRUE); - glDisable(GL_SCISSOR_TEST); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - RestoreClearState(); - } - - // Allocate the offscreen saved color texture. - DCHECK(offscreen_saved_color_format_); - offscreen_saved_color_texture_->AllocateStorage( - offscreen_size_, offscreen_saved_color_format_); - - offscreen_saved_frame_buffer_->AttachRenderTexture( - offscreen_saved_color_texture_.get()); - if (offscreen_saved_frame_buffer_->CheckStatus() != - GL_FRAMEBUFFER_COMPLETE) { - LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed " - << "because offscreen saved FBO was incomplete."; - return false; - } - - // Destroy the offscreen resolved framebuffers. - if (offscreen_resolved_frame_buffer_.get()) - offscreen_resolved_frame_buffer_->Destroy(); - if (offscreen_resolved_color_texture_.get()) - offscreen_resolved_color_texture_->Destroy(); - offscreen_resolved_color_texture_.reset(); - offscreen_resolved_frame_buffer_.reset(); - - // Clear the offscreen color texture. - { - ScopedFrameBufferBinder binder(this, offscreen_saved_frame_buffer_->id()); - glClearColor(0, 0, 0, 0); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glDisable(GL_SCISSOR_TEST); - glClear(GL_COLOR_BUFFER_BIT); - RestoreClearState(); - } - - UpdateParentTextureInfo(); - - return true; +void GLES2DecoderImpl::ResizeOffscreenFrameBuffer(const gfx::Size& size) { + // We can't resize the render buffers immediately because there might be a + // partial frame rendered into them and we don't want the tail end of that + // rendered into the reallocated storage. Defer until the next SwapBuffers. + pending_offscreen_size_ = size; } -error::Error GLES2DecoderImpl::HandleResizeCHROMIUM( - uint32 immediate_data_size, const gles2::ResizeCHROMIUM& c) { - GLuint width = static_cast<GLuint>(c.width); - GLuint height = static_cast<GLuint>(c.height); - TRACE_EVENT2("gpu", "glResizeChromium", "width", width, "height", height); +void GLES2DecoderImpl::DoResizeCHROMIUM(GLuint width, GLuint height) { #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(TOUCH_UI) // Make sure that we are done drawing to the back buffer before resizing. glFinish(); #endif - bool is_offscreen = !!offscreen_target_frame_buffer_.get(); - if (is_offscreen) { - if (!ResizeOffscreenFrameBuffer(gfx::Size(width, height))) - return error::kLostContext; + if (resize_callback_.get()) { + gfx::Size size(width, height); + resize_callback_->Run(size); } - - if (resize_callback_.get()) - resize_callback_->Run(gfx::Size(width, height)); - - return error::kNoError; } void GLES2DecoderImpl::DoSetSurfaceCHROMIUM(GLint surface_id) { @@ -6557,6 +6554,14 @@ error::Error GLES2DecoderImpl::HandleSwapBuffers( if (is_offscreen) { ScopedGLErrorSuppressor suppressor(this); + // First check to see if a deferred offscreen render buffer resize is + // pending. + if (!UpdateOffscreenFrameBufferSize()) { + LOG(ERROR) << "Context lost because reallocation of offscreen FBO " + << "failed."; + return error::kLostContext; + } + if (IsOffscreenBufferMultisampled()) { // For multisampled buffers, bind the resolved frame buffer so that // callbacks can call ReadPixels or CopyTexImage2D. diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h index fc66b3d..23c5e3a 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder.h @@ -81,7 +81,12 @@ class GLES2Decoder : public CommonDecoder { uint32 parent_texture_id) = 0; // Resize an offscreen frame buffer. - virtual bool ResizeOffscreenFrameBuffer(const gfx::Size& size) = 0; + virtual void ResizeOffscreenFrameBuffer(const gfx::Size& size) = 0; + + // Force the offscreen frame buffer's size to be updated. This + // usually occurs lazily, during SwapBuffers, but on some platforms + // (Mac OS X in particular) it must be done immediately. + virtual bool UpdateOffscreenFrameBufferSize() = 0; // Make this decoder's GL context current. virtual bool MakeCurrent() = 0; @@ -100,8 +105,7 @@ class GLES2Decoder : public CommonDecoder { // Sets a callback which is called when a glResizeCHROMIUM command // is processed. - virtual void SetResizeCallback( - Callback1<gfx::Size>::Type* callback) = 0; + virtual void SetResizeCallback(Callback1<gfx::Size>::Type* callback) = 0; // Sets a callback which is called when a SwapBuffers command is processed. virtual void SetSwapBuffersCallback(Callback0::Type* callback) = 0; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h index 27ef39b..9023cfe 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h @@ -2568,6 +2568,14 @@ error::Error GLES2DecoderImpl::HandleGetMaxValueInBufferCHROMIUM( return error::kNoError; } +error::Error GLES2DecoderImpl::HandleResizeCHROMIUM( + uint32 immediate_data_size, const gles2::ResizeCHROMIUM& c) { + GLuint width = static_cast<GLuint>(c.width); + GLuint height = static_cast<GLuint>(c.height); + DoResizeCHROMIUM(width, height); + return error::kNoError; +} + error::Error GLES2DecoderImpl::HandleSetSurfaceCHROMIUM( uint32 immediate_data_size, const gles2::SetSurfaceCHROMIUM& c) { GLint surface_id = static_cast<GLint>(c.surface_id); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h index fa9d43d..13e60bb 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h @@ -38,7 +38,8 @@ class MockGLES2Decoder : public GLES2Decoder { const std::vector<int32>& attribs)); MOCK_METHOD0(Destroy, void()); MOCK_METHOD2(SetParent, bool(GLES2Decoder* parent, uint32 parent_texture_id)); - MOCK_METHOD1(ResizeOffscreenFrameBuffer, bool(const gfx::Size& size)); + MOCK_METHOD1(ResizeOffscreenFrameBuffer, void(const gfx::Size& size)); + MOCK_METHOD0(UpdateOffscreenFrameBufferSize, bool()); MOCK_METHOD0(MakeCurrent, bool()); MOCK_METHOD1(GetServiceIdForTesting, uint32(uint32 client_id)); MOCK_METHOD0(GetGLES2Util, GLES2Util*()); diff --git a/gpu/command_buffer/service/gpu_scheduler.cc b/gpu/command_buffer/service/gpu_scheduler.cc index 6413cc1..15316ea 100644 --- a/gpu/command_buffer/service/gpu_scheduler.cc +++ b/gpu/command_buffer/service/gpu_scheduler.cc @@ -228,8 +228,11 @@ int32 GpuScheduler::GetGetOffset() { return parser_->get(); } -void GpuScheduler::SetResizeCallback( - Callback1<gfx::Size>::Type* callback) { +void GpuScheduler::ResizeOffscreenFrameBuffer(const gfx::Size& size) { + decoder_->ResizeOffscreenFrameBuffer(size); +} + +void GpuScheduler::SetResizeCallback(Callback1<gfx::Size>::Type* callback) { decoder_->SetResizeCallback(callback); } diff --git a/gpu/command_buffer/service/gpu_scheduler.h b/gpu/command_buffer/service/gpu_scheduler.h index 61c60be..75ccc63 100644 --- a/gpu/command_buffer/service/gpu_scheduler.h +++ b/gpu/command_buffer/service/gpu_scheduler.h @@ -98,6 +98,9 @@ class GpuScheduler : public CommandBufferEngine { virtual bool SetGetOffset(int32 offset); virtual int32 GetGetOffset(); + // Asynchronously resizes an offscreen frame buffer. + void ResizeOffscreenFrameBuffer(const gfx::Size& size); + #if defined(OS_MACOSX) // To prevent the GPU process from overloading the browser process, // we need to track the number of swap buffers calls issued and diff --git a/gpu/command_buffer/service/gpu_scheduler_mac.cc b/gpu/command_buffer/service/gpu_scheduler_mac.cc index 2efa9cb..cfa0d5c 100644 --- a/gpu/command_buffer/service/gpu_scheduler_mac.cc +++ b/gpu/command_buffer/service/gpu_scheduler_mac.cc @@ -74,12 +74,21 @@ void GpuScheduler::Destroy() { } uint64 GpuScheduler::SetWindowSizeForIOSurface(const gfx::Size& size) { + // This is called from an IPC handler, so it's undefined which context is + // current. Make sure the right one is. + decoder_->GetGLContext()->MakeCurrent(decoder_->GetGLSurface()); + + ResizeOffscreenFrameBuffer(size); + decoder_->UpdateOffscreenFrameBufferSize(); + // Note: The following line changes the current context again. return surface_->SetSurfaceSize(size); } TransportDIB::Handle GpuScheduler::SetWindowSizeForTransportDIB( const gfx::Size& size) { + ResizeOffscreenFrameBuffer(size); + decoder_->UpdateOffscreenFrameBufferSize(); return surface_->SetTransportDIBSize(size); } diff --git a/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc b/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc index 4c4f05e..0e3c77a9 100644 --- a/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc +++ b/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc @@ -102,6 +102,13 @@ class GLInProcessContext : public base::SupportsWeakPtr<GLInProcessContext> { const int32* attrib_list, const GURL& active_arl); +#if defined(OS_MACOSX) + // On Mac OS X only, view GLInProcessContexts actually behave like offscreen + // GLInProcessContexts, and require an explicit resize operation which is + // slightly different from that of offscreen GLInProcessContexts. + void ResizeOnscreen(const gfx::Size& size); +#endif + // Create a GLInProcessContext that renders to an offscreen frame buffer. If // parent is not NULL, that GLInProcessContext can access a copy of the // created GLInProcessContext's frame buffer that is updated every time @@ -118,6 +125,13 @@ class GLInProcessContext : public base::SupportsWeakPtr<GLInProcessContext> { const int32* attrib_list, const GURL& active_url); + // Resize an offscreen frame buffer. The resize occurs on the next call to + // SwapBuffers. This is to avoid waiting until all pending GL calls have been + // executed by the GPU process. Everything rendered up to the call to + // SwapBuffers will be lost. A lost GLInProcessContext will be reported if the + // resize fails. + void ResizeOffscreen(const gfx::Size& size); + // For an offscreen frame buffer GLInProcessContext, return the texture ID // with respect to the parent GLInProcessContext. Returns zero if // GLInProcessContext does not have a parent. @@ -185,6 +199,7 @@ class GLInProcessContext : public base::SupportsWeakPtr<GLInProcessContext> { GLES2CmdHelper* gles2_helper_; int32 transfer_buffer_id_; GLES2Implementation* gles2_implementation_; + gfx::Size size_; Error last_error_; DISALLOW_COPY_AND_ASSIGN(GLInProcessContext); @@ -251,6 +266,13 @@ GLInProcessContext* GLInProcessContext::CreateViewContext( #endif } +#if defined(OS_MACOSX) +void GLInProcessContext::ResizeOnscreen(const gfx::Size& size) { + DCHECK(size.width() > 0 && size.height() > 0); + size_ = size; +} +#endif + GLInProcessContext* GLInProcessContext::CreateOffscreenContext( GLInProcessContext* parent, const gfx::Size& size, @@ -276,6 +298,16 @@ GLInProcessContext* GLInProcessContext::CreateOffscreenContext( #endif } +void GLInProcessContext::ResizeOffscreen(const gfx::Size& size) { + DCHECK(size.width() > 0 && size.height() > 0); + if (size_ != size) { + gpu_scheduler_->ResizeOffscreenFrameBuffer(size); + // TODO(gman): See if the next line is needed. + gles2_implementation_->ResizeCHROMIUM(size.width(), size.height()); + size_ = size; + } +} + void GLInProcessContext::PumpCommands() { gpu_scheduler_->PutChanged(); ::gpu::CommandBuffer::State state = command_buffer_->GetState(); @@ -516,6 +548,8 @@ bool GLInProcessContext::Initialize(bool onscreen, true, false); + size_ = size; + return true; } @@ -732,7 +766,17 @@ void WebGraphicsContext3DInProcessCommandBufferImpl::reshape( // TODO(gmam): See if we can comment this in. // ClearContext(); - gl_->ResizeCHROMIUM(width, height); + if (web_view_) { +#if defined(OS_MACOSX) + context_->ResizeOnscreen(gfx::Size(width, height)); +#else + gl_->ResizeCHROMIUM(width, height); +#endif + } else { + context_->ResizeOffscreen(gfx::Size(width, height)); + // Force a SwapBuffers to get the framebuffer to resize. + context_->SwapBuffers(); + } #ifdef FLIP_FRAMEBUFFER_VERTICALLY scanline_.reset(new uint8[width * 4]); @@ -1594,3 +1638,4 @@ void WebGraphicsContext3DInProcessCommandBufferImpl::OnContextLost() { } // namespace webkit #endif // defined(ENABLE_GPU) + |