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( |