Chromium Code Reviews| Index: gpu/command_buffer/service/gles2_cmd_decoder.cc |
| diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
| index 77aa684d64747cef8b723d01b931a554c8e97832..c59161ee49de62e2a277b363aea0b684b28745f9 100644 |
| --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc |
| +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
| @@ -594,7 +594,11 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { |
| const std::vector<int32_t>& attribs) override; |
| void Destroy(bool have_context) override; |
| void SetSurface(const scoped_refptr<gfx::GLSurface>& surface) override; |
| + void ReleaseSurface() override; |
| void ProduceFrontBuffer(const Mailbox& mailbox) override; |
| + void TakeFrontBuffer(const Mailbox& mailbox) override; |
| + void ReturnFrontBuffer(const Mailbox& mailbox, |
| + bool is_lost) override; |
| bool ResizeOffscreenFrameBuffer(const gfx::Size& size) override; |
| void UpdateParentTextureInfo(); |
| bool MakeCurrent() override; |
| @@ -2044,6 +2048,33 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { |
| scoped_refptr<TextureRef> |
| offscreen_saved_color_texture_info_; |
| + // When a client requests ownership of the swapped front buffer, all |
| + // information is saved in this structure, and |in_use| is set to true. When a |
| + // client releases ownership, |in_use| is set to false. |
| + // |
| + // An instance of this struct, with |in_use| = false may be reused instead of |
| + // making a new BackTexture. |
| + struct SavedBackTexture { |
| + std::unique_ptr<BackTexture> back_texture; |
| + scoped_refptr<TextureRef> texture_ref; |
| + bool in_use; |
| + }; |
| + std::vector<SavedBackTexture> saved_back_textures_; |
| + |
| + // If there's a SavedBackTexture that's not in use, takes that. Otherwise, |
| + // generates a new back texture. |
| + void CreateBackTexture(); |
| + size_t create_back_texture_count_for_test_ = 0; |
| + |
| + // Releases all saved BackTextures that are not in use by a client. |
| + void ReleaseNotInUseBackTextures(); |
| + |
| + // Releases all saved BackTextures. |
| + void ReleaseAllBackTextures(); |
| + |
| + size_t GetSavedBackTextureCountForTest() override; |
| + size_t GetCreatedBackTextureCountForTest() override; |
| + |
| // The copy that is used as the destination for multi-sample resolves. |
| std::unique_ptr<BackFramebuffer> offscreen_resolved_frame_buffer_; |
| std::unique_ptr<BackTexture> offscreen_resolved_color_texture_; |
| @@ -4146,6 +4177,7 @@ void GLES2DecoderImpl::Destroy(bool have_context) { |
| offscreen_saved_color_texture_->Invalidate(); |
| offscreen_saved_color_texture_info_ = NULL; |
| } |
| + ReleaseAllBackTextures(); |
| if (have_context) { |
| if (copy_texture_CHROMIUM_.get()) { |
| copy_texture_CHROMIUM_->Destroy(); |
| @@ -4284,7 +4316,19 @@ void GLES2DecoderImpl::SetSurface( |
| RestoreCurrentFramebufferBindings(); |
| } |
| +void GLES2DecoderImpl::ReleaseSurface() { |
| + if (!context_.get()) |
| + return; |
| + if (WasContextLost()) { |
| + DLOG(ERROR) << " GLES2DecoderImpl: Trying to release lost context."; |
| + return; |
| + } |
| + context_->ReleaseCurrent(surface_.get()); |
| + surface_ = nullptr; |
| +} |
| + |
| void GLES2DecoderImpl::ProduceFrontBuffer(const Mailbox& mailbox) { |
| + NOTREACHED(); |
|
ccameron
2016/04/22 18:25:55
Should this be "TODO: delete me" as well?
|
| if (!offscreen_saved_color_texture_.get()) { |
| LOG(ERROR) << "Called ProduceFrontBuffer on a non-offscreen context"; |
| return; |
| @@ -4301,6 +4345,109 @@ void GLES2DecoderImpl::ProduceFrontBuffer(const Mailbox& mailbox) { |
| mailbox, offscreen_saved_color_texture_info_->texture()); |
| } |
| +void GLES2DecoderImpl::TakeFrontBuffer(const Mailbox& mailbox) { |
| + if (!offscreen_saved_color_texture_.get()) { |
| + LOG(ERROR) << "Called TakeFrontBuffer on a non-offscreen context"; |
| + return; |
| + } |
| + |
| + if (!offscreen_saved_color_texture_info_.get()) { |
| + GLuint service_id = offscreen_saved_color_texture_->id(); |
| + offscreen_saved_color_texture_info_ = TextureRef::Create( |
| + texture_manager(), 0, service_id); |
| + texture_manager()->SetTarget(offscreen_saved_color_texture_info_.get(), |
| + GL_TEXTURE_2D); |
| + UpdateParentTextureInfo(); |
| + } |
| + |
| + mailbox_manager()->ProduceTexture( |
| + mailbox, offscreen_saved_color_texture_info_->texture()); |
| + |
| + // Save the BackTexture and TextureRef. |
| + SavedBackTexture save; |
| + save.back_texture.swap(offscreen_saved_color_texture_); |
| + save.texture_ref = offscreen_saved_color_texture_info_; |
| + offscreen_saved_color_texture_info_ = nullptr; |
| + save.in_use = true; |
| + saved_back_textures_.push_back(std::move(save)); |
| + |
| + CreateBackTexture(); |
| +} |
| + |
| +void GLES2DecoderImpl::ReturnFrontBuffer(const Mailbox& mailbox, |
| + bool is_lost) { |
| + for (auto it = saved_back_textures_.begin(); it != saved_back_textures_.end(); |
| + ++it) { |
| + Texture* texture = mailbox_manager()->ConsumeTexture(mailbox); |
|
ccameron
2016/04/22 18:25:55
Pull the ConsumeTexture above the loop?
erikchen
2016/04/25 20:58:23
Done.
|
| + if (texture != it->texture_ref->texture()) |
| + continue; |
| + |
| + if (is_lost || it->back_texture->size() != offscreen_size_) { |
| + it->back_texture->Invalidate(); |
| + saved_back_textures_.erase(it); |
| + return; |
| + } |
| + |
| + it->in_use = false; |
|
ccameron
2016/04/22 18:25:55
Are there circumstances where we would be concerne
erikchen
2016/04/25 20:58:23
If this becomes a problem, we can deal with it. I'
|
| + return; |
| + } |
| + |
| + NOTREACHED(); |
| +} |
| + |
| +void GLES2DecoderImpl::CreateBackTexture() { |
| + for (auto it = saved_back_textures_.begin(); it != saved_back_textures_.end(); |
| + ++it) { |
| + if (it->in_use) |
| + continue; |
| + |
| + if (it->back_texture->size() != offscreen_size_) |
| + continue; |
| + offscreen_saved_color_texture_ = std::move(it->back_texture); |
| + offscreen_saved_color_texture_info_ = it->texture_ref; |
| + saved_back_textures_.erase(it); |
| + return; |
| + } |
| + |
| + ++create_back_texture_count_for_test_; |
| + offscreen_saved_color_texture_.reset( |
| + new BackTexture(memory_tracker(), &state_)); |
| + offscreen_saved_color_texture_->Create(); |
| + offscreen_saved_color_texture_->AllocateStorage( |
| + offscreen_size_, offscreen_saved_color_format_, false); |
| + offscreen_saved_frame_buffer_->AttachRenderTexture( |
| + offscreen_saved_color_texture_.get()); |
| +} |
| + |
| +void GLES2DecoderImpl::ReleaseNotInUseBackTextures() { |
| + for (auto& saved_back_texture : saved_back_textures_) { |
| + if (!saved_back_texture.in_use) |
| + saved_back_texture.back_texture->Invalidate(); |
| + } |
| + |
| + std::remove_if(saved_back_textures_.begin(), saved_back_textures_.end(), |
| + [](const SavedBackTexture& saved_back_texture) { |
| + return !saved_back_texture.in_use; |
| + }); |
| +} |
| + |
| +void GLES2DecoderImpl::ReleaseAllBackTextures() { |
| + for (auto& saved_back_texture : saved_back_textures_) { |
| + // The texture will be destroyed by texture_ref's destructor. |
| + DCHECK(saved_back_texture.texture_ref); |
| + saved_back_texture.back_texture->Invalidate(); |
| + } |
| + saved_back_textures_.clear(); |
| +} |
| + |
| +size_t GLES2DecoderImpl::GetSavedBackTextureCountForTest() { |
| + return saved_back_textures_.size(); |
| +} |
| + |
| +size_t GLES2DecoderImpl::GetCreatedBackTextureCountForTest() { |
| + return create_back_texture_count_for_test_; |
| +} |
| + |
| bool GLES2DecoderImpl::ResizeOffscreenFrameBuffer(const gfx::Size& size) { |
| bool is_offscreen = !!offscreen_target_frame_buffer_.get(); |
| if (!is_offscreen) { |
| @@ -12843,6 +12990,10 @@ void GLES2DecoderImpl::DoSwapBuffers() { |
| glFinish(); |
| } |
| + // The size has changed, so none of the cached BackTextures are useful |
| + // anymore. |
| + ReleaseNotInUseBackTextures(); |
| + |
| // Allocate the offscreen saved color texture. |
| DCHECK(offscreen_saved_color_format_); |
| offscreen_saved_color_texture_->AllocateStorage( |