diff options
author | reveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-19 10:22:56 +0000 |
---|---|---|
committer | reveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-19 10:22:56 +0000 |
commit | 8a48e732c0dc67b22f0b2cdce8bf750e273a4628 (patch) | |
tree | a3f0260baa264de95d1ffb21815ebcf223dfdee2 | |
parent | 10ebc9183caa8dd392ec89cc6c571332c4194741 (diff) | |
download | chromium_src-8a48e732c0dc67b22f0b2cdce8bf750e273a4628.zip chromium_src-8a48e732c0dc67b22f0b2cdce8bf750e273a4628.tar.gz chromium_src-8a48e732c0dc67b22f0b2cdce8bf750e273a4628.tar.bz2 |
gpu: Add Will/DidUseTexImage to GLImage API.
WillUseTexImage/DidUseTexImage is called before/after the image is
used for sampling. The result is that the client only has to call
bind/releaseTexImage2D when contents have changed, which allows
for more efficient GLImage implementations as work required before
use can be separated from work required when contents have changed.
BUG=261649
TEST=gpu_unittests --gtest_filter=SharedTextureTest.Images && gpu_unittests --gtest_filter=GLES2DecoderWithShaderTest.UseTexImage && cc_unittests --gtest_filter=ResourceProviderTests/ResourceProviderTest.Image_GLTexture* && gl_tests --gtest_filter=MockGpuMemoryBufferTest.Lifecycle
Review URL: https://codereview.chromium.org/23129010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@229532 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | cc/resources/resource_provider.cc | 33 | ||||
-rw-r--r-- | cc/resources/resource_provider.h | 5 | ||||
-rw-r--r-- | cc/resources/resource_provider_unittest.cc | 21 | ||||
-rw-r--r-- | gpu/command_buffer/service/framebuffer_manager.cc | 26 | ||||
-rw-r--r-- | gpu/command_buffer/service/framebuffer_manager.h | 28 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 117 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc | 140 | ||||
-rw-r--r-- | gpu/command_buffer/service/texture_manager.cc | 40 | ||||
-rw-r--r-- | gpu/command_buffer/service/texture_manager.h | 17 | ||||
-rw-r--r-- | gpu/command_buffer/service/texture_manager_unittest.cc | 60 | ||||
-rw-r--r-- | ui/gl/gl_image.cc | 8 | ||||
-rw-r--r-- | ui/gl/gl_image.h | 6 | ||||
-rw-r--r-- | ui/gl/gl_image_egl.cc | 55 | ||||
-rw-r--r-- | ui/gl/gl_image_egl.h | 3 | ||||
-rw-r--r-- | ui/gl/gl_image_glx.cc | 10 | ||||
-rw-r--r-- | ui/gl/gl_image_glx.h | 2 | ||||
-rw-r--r-- | ui/gl/gl_image_shm.cc | 14 | ||||
-rw-r--r-- | ui/gl/gl_image_shm.h | 2 | ||||
-rw-r--r-- | ui/gl/gl_image_stub.cc | 13 | ||||
-rw-r--r-- | ui/gl/gl_image_stub.h | 4 |
20 files changed, 533 insertions, 71 deletions
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index e7d8c13..d76fc4b 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc @@ -111,6 +111,8 @@ ResourceProvider::Resource::Resource() original_filter(0), filter(0), image_id(0), + bound_image_id(0), + dirty_image(false), texture_pool(0), wrap_mode(0), lost(false), @@ -150,6 +152,8 @@ ResourceProvider::Resource::Resource(unsigned texture_id, original_filter(filter), filter(filter), image_id(0), + bound_image_id(0), + dirty_image(false), texture_pool(texture_pool), wrap_mode(wrap_mode), lost(false), @@ -185,6 +189,8 @@ ResourceProvider::Resource::Resource(uint8_t* pixels, original_filter(filter), filter(filter), image_id(0), + bound_image_id(0), + dirty_image(false), texture_pool(0), wrap_mode(wrap_mode), lost(false), @@ -695,7 +701,6 @@ ResourceProvider::ScopedSamplerGL::ScopedSamplerGL( } ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() { - resource_provider_->UnbindForSampling(resource_id_, target_, unit_); } ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL( @@ -1343,23 +1348,14 @@ void ResourceProvider::BindForSampling(ResourceProvider::ResourceId resource_id, resource->filter = filter; } - if (resource->image_id) + if (resource->image_id && resource->dirty_image) { + // Release image currently bound to texture. + if (resource->bound_image_id) + context3d->releaseTexImage2DCHROMIUM(target, resource->bound_image_id); context3d->bindTexImage2DCHROMIUM(target, resource->image_id); -} - -void ResourceProvider::UnbindForSampling( - ResourceProvider::ResourceId resource_id, GLenum target, GLenum unit) { - DCHECK(thread_checker_.CalledOnValidThread()); - ResourceMap::iterator it = resources_.find(resource_id); - DCHECK(it != resources_.end()); - Resource* resource = &it->second; - - if (!resource->image_id) - return; - - WebGraphicsContext3D* context3d = Context3d(); - ScopedSetActiveTexture scoped_active_tex(context3d, unit); - context3d->releaseTexImage2DCHROMIUM(target, resource->image_id); + resource->bound_image_id = resource->image_id; + resource->dirty_image = false; + } } void ResourceProvider::BeginSetPixels(ResourceId id) { @@ -1596,6 +1592,8 @@ void ResourceProvider::ReleaseImage(ResourceId id) { DCHECK(context3d); context3d->destroyImageCHROMIUM(resource->image_id); resource->image_id = 0; + resource->bound_image_id = 0; + resource->dirty_image = false; resource->allocated = false; } @@ -1627,6 +1625,7 @@ void ResourceProvider::UnmapImage(ResourceId id) { WebGraphicsContext3D* context3d = Context3d(); DCHECK(context3d); context3d->unmapImageCHROMIUM(resource->image_id); + resource->dirty_image = true; } } diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h index df17819..b8cb399 100644 --- a/cc/resources/resource_provider.h +++ b/cc/resources/resource_provider.h @@ -390,6 +390,8 @@ class CC_EXPORT ResourceProvider { GLenum original_filter; GLenum filter; unsigned image_id; + unsigned bound_image_id; + bool dirty_image; GLenum texture_pool; GLint wrap_mode; bool lost; @@ -454,9 +456,6 @@ class CC_EXPORT ResourceProvider { GLenum target, GLenum unit, GLenum filter); - void UnbindForSampling(ResourceProvider::ResourceId resource_id, - GLenum target, - GLenum unit); // Returns NULL if the output_surface_ does not have a ContextProvider. WebKit::WebGraphicsContext3D* Context3d() const; diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc index 64dcd7b..9b3e243 100644 --- a/cc/resources/resource_provider_unittest.cc +++ b/cc/resources/resource_provider_unittest.cc @@ -2419,9 +2419,30 @@ TEST_P(ResourceProviderTest, Image_GLTexture) { EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId)) .Times(1) .RetiresOnSaturation(); + { + ResourceProvider::ScopedSamplerGL lock_gl( + resource_provider.get(), id, GL_TEXTURE_2D, GL_LINEAR); + EXPECT_EQ(kTextureId, lock_gl.texture_id()); + } + + EXPECT_CALL(*context, mapImageCHROMIUM(kImageId, GL_READ_WRITE)) + .WillOnce(Return(dummy_mapped_buffer_address)) + .RetiresOnSaturation(); + resource_provider->MapImage(id); + + EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId)) + .Times(1) + .RetiresOnSaturation(); + resource_provider->UnmapImage(id); + + EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId)).Times(1) + .RetiresOnSaturation(); EXPECT_CALL(*context, releaseTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId)) .Times(1) .RetiresOnSaturation(); + EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId)) + .Times(1) + .RetiresOnSaturation(); EXPECT_CALL(*context, deleteTexture(kTextureId)) .Times(1) .RetiresOnSaturation(); diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc index aa30cd3..194fe37 100644 --- a/gpu/command_buffer/service/framebuffer_manager.cc +++ b/gpu/command_buffer/service/framebuffer_manager.cc @@ -93,7 +93,7 @@ class RenderbufferAttachment return true; } - virtual void DetachFromFramebuffer() const OVERRIDE { + virtual void DetachFromFramebuffer(Framebuffer* framebuffer) const OVERRIDE { // Nothing to do for renderbuffers. } @@ -197,8 +197,10 @@ class TextureAttachment return texture_ref_->texture()->CanRenderTo(); } - virtual void DetachFromFramebuffer() const OVERRIDE { + virtual void DetachFromFramebuffer(Framebuffer* framebuffer) + const OVERRIDE { texture_ref_->texture()->DetachFromFramebuffer(); + framebuffer->OnTextureRefDetached(texture_ref_.get()); } virtual bool ValidForAttachmentType( @@ -241,6 +243,10 @@ class TextureAttachment DISALLOW_COPY_AND_ASSIGN(TextureAttachment); }; +FramebufferManager::TextureDetachObserver::TextureDetachObserver() {} + +FramebufferManager::TextureDetachObserver::~TextureDetachObserver() {} + FramebufferManager::FramebufferManager( uint32 max_draw_buffers, uint32 max_color_attachments) : framebuffer_state_change_count_(1), @@ -263,7 +269,7 @@ void Framebuffer::MarkAsDeleted() { deleted_ = true; while (!attachments_.empty()) { Attachment* attachment = attachments_.begin()->second.get(); - attachment->DetachFromFramebuffer(); + attachment->DetachFromFramebuffer(this); attachments_.erase(attachments_.begin()); } } @@ -548,7 +554,7 @@ void Framebuffer::AttachRenderbuffer( GLenum attachment, Renderbuffer* renderbuffer) { const Attachment* a = GetAttachment(attachment); if (a) - a->DetachFromFramebuffer(); + a->DetachFromFramebuffer(this); if (renderbuffer) { attachments_[attachment] = scoped_refptr<Attachment>( new RenderbufferAttachment(renderbuffer)); @@ -563,7 +569,7 @@ void Framebuffer::AttachTexture( GLint level, GLsizei samples) { const Attachment* a = GetAttachment(attachment); if (a) - a->DetachFromFramebuffer(); + a->DetachFromFramebuffer(this); if (texture_ref) { attachments_[attachment] = scoped_refptr<Attachment>( new TextureAttachment(texture_ref, target, level, samples)); @@ -584,6 +590,10 @@ const Framebuffer::Attachment* return NULL; } +void Framebuffer::OnTextureRefDetached(TextureRef* texture) { + manager_->OnTextureRefDetached(texture); +} + bool FramebufferManager::GetClientId( GLuint service_id, GLuint* client_id) const { // This doesn't need to be fast. It's only used during slow queries. @@ -621,6 +631,12 @@ bool FramebufferManager::IsComplete( framebuffer_state_change_count_; } +void FramebufferManager::OnTextureRefDetached(TextureRef* texture) { + FOR_EACH_OBSERVER(TextureDetachObserver, + texture_detach_observers_, + OnTextureRefDetachedFromFramebuffer(texture)); +} + } // namespace gles2 } // namespace gpu diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h index 7955ac1..06a75b4 100644 --- a/gpu/command_buffer/service/framebuffer_manager.h +++ b/gpu/command_buffer/service/framebuffer_manager.h @@ -9,6 +9,7 @@ #include "base/containers/hash_tables.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/observer_list.h" #include "gpu/command_buffer/service/gl_utils.h" #include "gpu/gpu_export.h" @@ -41,7 +42,7 @@ class GPU_EXPORT Framebuffer : public base::RefCounted<Framebuffer> { virtual bool IsRenderbuffer( Renderbuffer* renderbuffer) const = 0; virtual bool CanRenderTo() const = 0; - virtual void DetachFromFramebuffer() const = 0; + virtual void DetachFromFramebuffer(Framebuffer* framebuffer) const = 0; virtual bool ValidForAttachmentType( GLenum attachment_type, uint32 max_color_attachments) = 0; virtual void AddToSignature( @@ -130,6 +131,8 @@ class GPU_EXPORT Framebuffer : public base::RefCounted<Framebuffer> { return allow_framebuffer_combo_complete_map_; } + void OnTextureRefDetached(TextureRef* texture); + private: friend class FramebufferManager; friend class base::RefCounted<Framebuffer>; @@ -197,6 +200,17 @@ struct DecoderFramebufferState { // so we can correctly clear them. class GPU_EXPORT FramebufferManager { public: + class GPU_EXPORT TextureDetachObserver { + public: + TextureDetachObserver(); + virtual ~TextureDetachObserver(); + + virtual void OnTextureRefDetachedFromFramebuffer(TextureRef* texture) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureDetachObserver); + }; + FramebufferManager(uint32 max_draw_buffers, uint32 max_color_attachments); ~FramebufferManager(); @@ -230,12 +244,22 @@ class GPU_EXPORT FramebufferManager { (framebuffer_state_change_count_ + 1) | 0x80000000U; } + void AddObserver(TextureDetachObserver* observer) { + texture_detach_observers_.AddObserver(observer); + } + + void RemoveObserver(TextureDetachObserver* observer) { + texture_detach_observers_.RemoveObserver(observer); + } + private: friend class Framebuffer; void StartTracking(Framebuffer* framebuffer); void StopTracking(Framebuffer* framebuffer); + void OnTextureRefDetached(TextureRef* texture); + // Info for each framebuffer in the system. typedef base::hash_map<GLuint, scoped_refptr<Framebuffer> > FramebufferMap; @@ -254,6 +278,8 @@ class GPU_EXPORT FramebufferManager { uint32 max_draw_buffers_; uint32 max_color_attachments_; + ObserverList<TextureDetachObserver> texture_detach_observers_; + DISALLOW_COPY_AND_ASSIGN(FramebufferManager); }; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index dd02c9c..5145daa 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -521,7 +521,8 @@ bool GLES2Decoder::IsAngle() { // This class implements GLES2Decoder so we don't have to expose all the GLES2 // cmd stuff to outside this class. -class GLES2DecoderImpl : public GLES2Decoder { +class GLES2DecoderImpl : public GLES2Decoder, + public FramebufferManager::TextureDetachObserver { public: // Used by PrepForSetUniformByLocation to validate types. struct BaseUniformInfo { @@ -642,6 +643,10 @@ class GLES2DecoderImpl : public GLES2Decoder { virtual error::ContextLostReason GetContextLostReason() OVERRIDE; + // Overridden from FramebufferManager::TextureDetachObserver: + virtual void OnTextureRefDetachedFromFramebuffer( + TextureRef* texture) OVERRIDE; + private: friend class ScopedFrameBufferBinder; friend class ScopedResolvedFrameBufferBinder; @@ -1377,9 +1382,14 @@ class GLES2DecoderImpl : public GLES2Decoder { // buffer and bind the texture implicitly. void UpdateStreamTextureIfNeeded(Texture* texture, GLuint texture_unit_index); - // Returns false if unrenderable textures were replaced. + // If an image is bound to texture, this will call Will/DidUseTexImage + // if needed. + void DoWillUseTexImageIfNeeded(Texture* texture, GLenum textarget); + void DoDidUseTexImageIfNeeded(Texture* texture, GLenum textarget); + + // Returns false if textures were replaced. bool PrepareTexturesForRender(); - void RestoreStateForNonRenderableTextures(); + void RestoreStateForTextures(); // Returns true if GL_FIXED attribs were simulated. bool SimulateFixedAttribs( @@ -2472,6 +2482,8 @@ bool GLES2DecoderImpl::Initialize( AsyncPixelTransferManager::Create(context.get())); async_pixel_transfer_manager_->Initialize(texture_manager()); + framebuffer_manager()->AddObserver(this); + return true; } @@ -3203,6 +3215,8 @@ void GLES2DecoderImpl::Destroy(bool have_context) { // by the context group. async_pixel_transfer_manager_.reset(); + framebuffer_manager()->RemoveObserver(this); + if (group_.get()) { group_->Destroy(this, have_context); group_ = NULL; @@ -4866,6 +4880,9 @@ void GLES2DecoderImpl::DoFramebufferTexture2DCommon( return; } + if (texture_ref) + DoWillUseTexImageIfNeeded(texture_ref->texture(), textarget); + LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER(name); if (0 == samples) { glFramebufferTexture2DEXT(target, attachment, textarget, service_id, level); @@ -4886,6 +4903,10 @@ void GLES2DecoderImpl::DoFramebufferTexture2DCommon( if (framebuffer == framebuffer_state_.bound_draw_framebuffer.get()) { framebuffer_state_.clear_state_dirty = true; } + + if (texture_ref) + DoDidUseTexImageIfNeeded(texture_ref->texture(), textarget); + OnFboChanged(); } @@ -5723,11 +5744,43 @@ void GLES2DecoderImpl::UpdateStreamTextureIfNeeded(Texture* texture, } } +void GLES2DecoderImpl::DoWillUseTexImageIfNeeded( + Texture* texture, GLenum textarget) { + // Image is already in use if texture is attached to a framebuffer. + if (texture && !texture->IsAttachedToFramebuffer()) { + gfx::GLImage* image = texture->GetLevelImage(textarget, 0); + if (image) { + ScopedGLErrorSuppressor suppressor( + "GLES2DecoderImpl::DoWillUseTexImageIfNeeded", + GetErrorState()); + glBindTexture(textarget, texture->service_id()); + image->WillUseTexImage(); + RestoreCurrentTexture2DBindings(); + } + } +} + +void GLES2DecoderImpl::DoDidUseTexImageIfNeeded( + Texture* texture, GLenum textarget) { + // Image is still in use if texture is attached to a framebuffer. + if (texture && !texture->IsAttachedToFramebuffer()) { + gfx::GLImage* image = texture->GetLevelImage(textarget, 0); + if (image) { + ScopedGLErrorSuppressor suppressor( + "GLES2DecoderImpl::DoDidUseTexImageIfNeeded", + GetErrorState()); + glBindTexture(textarget, texture->service_id()); + image->DidUseTexImage(); + RestoreCurrentTexture2DBindings(); + } + } +} + bool GLES2DecoderImpl::PrepareTexturesForRender() { DCHECK(state_.current_program.get()); - bool have_unrenderable_textures = - texture_manager()->HaveUnrenderableTextures(); - if (!have_unrenderable_textures && !features().oes_egl_image_external) { + if (!texture_manager()->HaveUnrenderableTextures() && + !texture_manager()->HaveImages() && + !features().oes_egl_image_external) { return true; } @@ -5742,12 +5795,9 @@ bool GLES2DecoderImpl::PrepareTexturesForRender() { GLuint texture_unit_index = uniform_info->texture_units[jj]; if (texture_unit_index < state_.texture_units.size()) { TextureUnit& texture_unit = state_.texture_units[texture_unit_index]; - TextureRef* texture = + TextureRef* texture_ref = texture_unit.GetInfoForSamplerType(uniform_info->type).get(); - if (texture) - UpdateStreamTextureIfNeeded(texture->texture(), texture_unit_index); - if (have_unrenderable_textures && - (!texture || !texture_manager()->CanRender(texture))) { + if (!texture_ref || !texture_manager()->CanRender(texture_ref)) { textures_set = true; glActiveTexture(GL_TEXTURE0 + texture_unit_index); glBindTexture( @@ -5759,7 +5809,21 @@ bool GLES2DecoderImpl::PrepareTexturesForRender() { " is not renderable. It maybe non-power-of-2 and have" " incompatible texture filtering or is not" " 'texture complete'"); + continue; + } + + Texture* texture = texture_ref->texture(); + gfx::GLImage* image = texture->GetLevelImage(texture->target(), 0); + if (image && !texture->IsAttachedToFramebuffer()) { + ScopedGLErrorSuppressor suppressor( + "GLES2DecoderImpl::PrepareTexturesForRender", GetErrorState()); + textures_set = true; + glActiveTexture(GL_TEXTURE0 + texture_unit_index); + image->WillUseTexImage(); + continue; } + + UpdateStreamTextureIfNeeded(texture, texture_unit_index); } // else: should this be an error? } @@ -5767,7 +5831,7 @@ bool GLES2DecoderImpl::PrepareTexturesForRender() { return !textures_set; } -void GLES2DecoderImpl::RestoreStateForNonRenderableTextures() { +void GLES2DecoderImpl::RestoreStateForTextures() { DCHECK(state_.current_program.get()); const Program::SamplerIndices& sampler_indices = state_.current_program->sampler_indices(); @@ -5780,9 +5844,7 @@ void GLES2DecoderImpl::RestoreStateForNonRenderableTextures() { if (texture_unit_index < state_.texture_units.size()) { TextureUnit& texture_unit = state_.texture_units[texture_unit_index]; TextureRef* texture_ref = - uniform_info->type == GL_SAMPLER_2D - ? texture_unit.bound_texture_2d.get() - : texture_unit.bound_texture_cube_map.get(); + texture_unit.GetInfoForSamplerType(uniform_info->type).get(); if (!texture_ref || !texture_manager()->CanRender(texture_ref)) { glActiveTexture(GL_TEXTURE0 + texture_unit_index); // Get the texture_ref info that was previously bound here. @@ -5791,6 +5853,17 @@ void GLES2DecoderImpl::RestoreStateForNonRenderableTextures() { : texture_unit.bound_texture_cube_map.get(); glBindTexture(texture_unit.bind_target, texture_ref ? texture_ref->service_id() : 0); + continue; + } + + Texture* texture = texture_ref->texture(); + gfx::GLImage* image = texture->GetLevelImage(texture->target(), 0); + if (image && !texture->IsAttachedToFramebuffer()) { + ScopedGLErrorSuppressor suppressor( + "GLES2DecoderImpl::RestoreStateForTextures", GetErrorState()); + glActiveTexture(GL_TEXTURE0 + texture_unit_index); + image->DidUseTexImage(); + continue; } } } @@ -6133,7 +6206,7 @@ error::Error GLES2DecoderImpl::DoDrawArrays( } ProcessPendingQueries(); if (textures_set) { - RestoreStateForNonRenderableTextures(); + RestoreStateForTextures(); } if (simulated_fixed_attribs) { RestoreStateForSimulatedFixedAttribs(); @@ -6267,7 +6340,7 @@ error::Error GLES2DecoderImpl::DoDrawElements( ProcessPendingQueries(); if (textures_set) { - RestoreStateForNonRenderableTextures(); + RestoreStateForTextures(); } if (simulated_fixed_attribs) { RestoreStateForSimulatedFixedAttribs(); @@ -9601,6 +9674,8 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( dest_texture_ref, GL_TEXTURE_2D, level, true); } + DoWillUseTexImageIfNeeded(source_texture, source_texture->target()); + // GL_TEXTURE_EXTERNAL_OES texture requires apply a transform matrix // before presenting. if (source_texture->target() == GL_TEXTURE_EXTERNAL_OES) { @@ -9633,6 +9708,8 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( unpack_premultiply_alpha_, unpack_unpremultiply_alpha_); } + + DoDidUseTexImageIfNeeded(source_texture, source_texture->target()); } static GLenum ExtractTypeFromStorageFormat(GLenum internalformat) { @@ -10298,6 +10375,12 @@ error::Error GLES2DecoderImpl::HandleWaitAsyncTexImage2DCHROMIUM( return error::kNoError; } +void GLES2DecoderImpl::OnTextureRefDetachedFromFramebuffer( + TextureRef* texture_ref) { + Texture* texture = texture_ref->texture(); + DoDidUseTexImageIfNeeded(texture, texture->target()); +} + // Include the auto-generated part of this file. We split this because it means // we can easily edit the non-auto generated parts right here in this file // instead of having to edit some template or the code generator. diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 72c2fcd..573ba6e 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -7886,6 +7886,146 @@ TEST_F(GLES2DecoderTest, ReleaseTexImage2DCHROMIUM) { EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL); } +class MockGLImage : public gfx::GLImage { + public: + MockGLImage() {} + + // Overridden from gfx::GLImage: + MOCK_METHOD0(Destroy, void()); + MOCK_METHOD0(GetSize, gfx::Size()); + MOCK_METHOD0(BindTexImage, bool()); + MOCK_METHOD0(ReleaseTexImage, void()); + MOCK_METHOD0(WillUseTexImage, void()); + MOCK_METHOD0(DidUseTexImage, void()); + + protected: + virtual ~MockGLImage() {} +}; + +TEST_F(GLES2DecoderWithShaderTest, UseTexImage) { + DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId); + DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, + kSharedMemoryId, kSharedMemoryOffset); + + TextureRef* texture_ref = group().texture_manager()->GetTexture( + client_texture_id_); + ASSERT_TRUE(texture_ref != NULL); + Texture* texture = texture_ref->texture(); + EXPECT_EQ(kServiceTextureId, texture->service_id()); + + const int32 kImageId = 1; + scoped_refptr<MockGLImage> image(new MockGLImage); + group().image_manager()->AddImage(image.get(), kImageId); + + // Bind image to texture. + EXPECT_CALL(*image, BindTexImage()) + .Times(1) + .WillOnce(Return(true)) + .RetiresOnSaturation(); + EXPECT_CALL(*image, GetSize()) + .Times(1) + .WillOnce(Return(gfx::Size(1, 1))) + .RetiresOnSaturation(); + // ScopedGLErrorSuppressor calls GetError on its constructor and destructor. + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + BindTexImage2DCHROMIUM bind_tex_image_2d_cmd; + bind_tex_image_2d_cmd.Init(GL_TEXTURE_2D, kImageId); + EXPECT_EQ(error::kNoError, ExecuteCmd(bind_tex_image_2d_cmd)); + + AddExpectationsForSimulatedAttrib0(kNumVertices, 0); + SetupExpectationsForApplyingDefaultDirtyState(); + + // ScopedGLErrorSuppressor calls GetError on its constructor and destructor. + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) + .Times(3) + .RetiresOnSaturation(); + EXPECT_CALL(*image, WillUseTexImage()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*image, DidUseTexImage()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + DrawArrays cmd; + cmd.Init(GL_TRIANGLES, 0, kNumVertices); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, + kServiceFramebufferId); + // ScopedGLErrorSuppressor calls GetError on its constructor and destructor. + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId)) + .Times(2) + .RetiresOnSaturation(); + // Image will be 'in use' as long as bound to a framebuffer. + EXPECT_CALL(*image, WillUseTexImage()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, FramebufferTexture2DEXT( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + kServiceTextureId, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + FramebufferTexture2D fbtex_cmd; + fbtex_cmd.Init( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, client_texture_id_, + 0); + EXPECT_EQ(error::kNoError, ExecuteCmd(fbtex_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // ScopedGLErrorSuppressor calls GetError on its constructor and destructor. + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, FramebufferRenderbufferEXT( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + kServiceRenderbufferId)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId)) + .Times(2) + .RetiresOnSaturation(); + // Image should no longer be 'in use' after being unbound from framebuffer. + EXPECT_CALL(*image, DidUseTexImage()) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + FramebufferRenderbuffer fbrb_cmd; + fbrb_cmd.Init( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + client_renderbuffer_id_); + EXPECT_EQ(error::kNoError, ExecuteCmd(fbrb_cmd)); +} + TEST_F(GLES2DecoderManualInitTest, GpuMemoryManagerCHROMIUM) { InitDecoder( "GL_ARB_texture_rectangle", // extensions diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index 9684493..a7f32e0 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc @@ -80,6 +80,7 @@ TextureManager::~TextureManager() { DCHECK_EQ(0, num_unrenderable_textures_); DCHECK_EQ(0, num_unsafe_textures_); DCHECK_EQ(0, num_uncleared_mips_); + DCHECK_EQ(0, num_images_); } void TextureManager::Destroy(bool have_context) { @@ -118,6 +119,7 @@ Texture::Texture(GLuint service_id) framebuffer_attachment_count_(0), stream_texture_(false), immutable_(false), + has_images_(false), estimated_size_(0), can_render_condition_(CAN_RENDER_ALWAYS) { } @@ -431,6 +433,29 @@ void Texture::UpdateCanRenderCondition() { can_render_condition_ = can_render_condition; } +void Texture::UpdateHasImages() { + if (level_infos_.empty()) + return; + + bool has_images = false; + for (size_t ii = 0; ii < level_infos_.size(); ++ii) { + for (size_t jj = 0; jj < level_infos_[ii].size(); ++jj) { + const Texture::LevelInfo& info = level_infos_[ii][jj]; + if (info.image.get() != NULL) { + has_images = true; + break; + } + } + } + + if (has_images_ == has_images) + return; + has_images_ = has_images; + int delta = has_images ? +1 : -1; + for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it) + (*it)->manager()->UpdateNumImages(delta); +} + void Texture::IncAllFramebufferStateChangeCount() { for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it) (*it)->manager()->IncFramebufferStateChangeCount(); @@ -479,6 +504,7 @@ void Texture::SetLevelInfo( Update(feature_info); UpdateCleared(); UpdateCanRenderCondition(); + UpdateHasImages(); if (IsAttachedToFramebuffer()) { // TODO(gman): If textures tracked which framebuffers they were attached to // we could just mark those framebuffers as not complete. @@ -780,6 +806,7 @@ void Texture::SetLevelImage( DCHECK_EQ(info.level, level); info.image = image; UpdateCanRenderCondition(); + UpdateHasImages(); } gfx::GLImage* Texture::GetLevelImage( @@ -845,6 +872,7 @@ TextureManager::TextureManager(MemoryTracker* memory_tracker, num_unrenderable_textures_(0), num_unsafe_textures_(0), num_uncleared_mips_(0), + num_images_(0), texture_count_(0), have_context_(true) { for (int ii = 0; ii < kNumDefaultTextures; ++ii) { @@ -1130,6 +1158,8 @@ void TextureManager::StartTracking(TextureRef* ref) { ++num_unsafe_textures_; if (!texture->CanRender(feature_info_.get())) ++num_unrenderable_textures_; + if (texture->HasImages()) + ++num_images_; } void TextureManager::StopTracking(TextureRef* ref) { @@ -1144,6 +1174,10 @@ void TextureManager::StopTracking(TextureRef* ref) { } --texture_count_; + if (texture->HasImages()) { + DCHECK_NE(0, num_images_); + --num_images_; + } if (!texture->CanRender(feature_info_.get())) { DCHECK_NE(0, num_unrenderable_textures_); --num_unrenderable_textures_; @@ -1237,10 +1271,14 @@ void TextureManager::UpdateCanRenderCondition( ++num_unrenderable_textures_; } +void TextureManager::UpdateNumImages(int delta) { + num_images_ += delta; + DCHECK_GE(num_images_, 0); +} + void TextureManager::IncFramebufferStateChangeCount() { if (framebuffer_manager_) framebuffer_manager_->IncFramebufferStateChangeCount(); - } bool TextureManager::ValidateTextureParameters( diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h index 0a6e776..3dabf6d 100644 --- a/gpu/command_buffer/service/texture_manager.h +++ b/gpu/command_buffer/service/texture_manager.h @@ -114,6 +114,10 @@ class GPU_EXPORT Texture { // does not exist. gfx::GLImage* GetLevelImage(GLint target, GLint level) const; + bool HasImages() const { + return has_images_; + } + // Returns true of the given dimensions are inside the dimensions of the // level and if the format and type match the level. bool ValidForTexture( @@ -317,6 +321,10 @@ class GPU_EXPORT Texture { // texture. void UpdateCanRenderCondition(); + // Updates the images count in all the managers referencing this + // texture. + void UpdateHasImages(); + // Increment the framebuffer state change count in all the managers // referencing this texture. void IncAllFramebufferStateChangeCount(); @@ -378,6 +386,9 @@ class GPU_EXPORT Texture { // or dimensions of the texture object can be made. bool immutable_; + // Whether or not this texture has images. + bool has_images_; + // Size in bytes this texture is assumed to take in memory. uint32 estimated_size_; @@ -656,6 +667,10 @@ class GPU_EXPORT TextureManager { return num_uncleared_mips_ > 0; } + bool HaveImages() const { + return num_images_ > 0; + } + GLuint black_texture_id(GLenum target) const { switch (target) { case GL_SAMPLER_2D: @@ -758,6 +773,7 @@ class GPU_EXPORT TextureManager { void UpdateUnclearedMips(int delta); void UpdateCanRenderCondition(Texture::CanRenderCondition old_condition, Texture::CanRenderCondition new_condition); + void UpdateNumImages(int delta); void IncFramebufferStateChangeCount(); MemoryTypeTracker* GetMemTracker(GLenum texture_pool); @@ -781,6 +797,7 @@ class GPU_EXPORT TextureManager { int num_unrenderable_textures_; int num_unsafe_textures_; int num_uncleared_mips_; + int num_images_; // Counts the number of Textures allocated with 'this' as its manager. // Allows to check no Texture will outlive this. diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc index 2f5f036..312adfd 100644 --- a/gpu/command_buffer/service/texture_manager_unittest.cc +++ b/gpu/command_buffer/service/texture_manager_unittest.cc @@ -2367,5 +2367,65 @@ TEST_F(SharedTextureTest, Memory) { memory_tracker2_->GetSize(MemoryTracker::kUnmanaged)); } +TEST_F(SharedTextureTest, Images) { + scoped_refptr<TextureRef> ref1 = texture_manager1_->CreateTexture(10, 10); + scoped_refptr<TextureRef> ref2 = + texture_manager2_->Consume(20, ref1->texture()); + + texture_manager1_->SetTarget(ref1.get(), GL_TEXTURE_2D); + texture_manager1_->SetLevelInfo(ref1.get(), + GL_TEXTURE_2D, + 1, + GL_RGBA, + 2, + 2, + 1, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + true); + EXPECT_FALSE(ref1->texture()->HasImages()); + EXPECT_FALSE(ref2->texture()->HasImages()); + EXPECT_FALSE(texture_manager1_->HaveImages()); + EXPECT_FALSE(texture_manager2_->HaveImages()); + texture_manager1_->SetLevelImage(ref1.get(), + GL_TEXTURE_2D, + 1, + gfx::GLImage::CreateGLImage(0).get()); + EXPECT_TRUE(ref1->texture()->HasImages()); + EXPECT_TRUE(ref2->texture()->HasImages()); + EXPECT_TRUE(texture_manager1_->HaveImages()); + EXPECT_TRUE(texture_manager2_->HaveImages()); + texture_manager1_->SetLevelImage(ref1.get(), + GL_TEXTURE_2D, + 1, + gfx::GLImage::CreateGLImage(0).get()); + EXPECT_TRUE(ref1->texture()->HasImages()); + EXPECT_TRUE(ref2->texture()->HasImages()); + EXPECT_TRUE(texture_manager1_->HaveImages()); + EXPECT_TRUE(texture_manager2_->HaveImages()); + texture_manager1_->SetLevelInfo(ref1.get(), + GL_TEXTURE_2D, + 1, + GL_RGBA, + 2, + 2, + 1, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + true); + EXPECT_FALSE(ref1->texture()->HasImages()); + EXPECT_FALSE(ref2->texture()->HasImages()); + EXPECT_FALSE(texture_manager1_->HaveImages()); + EXPECT_FALSE(texture_manager1_->HaveImages()); + + EXPECT_CALL(*gl_, DeleteTextures(1, _)) + .Times(1) + .RetiresOnSaturation(); + texture_manager1_->RemoveTexture(10); + texture_manager2_->RemoveTexture(20); +} + } // namespace gles2 } // namespace gpu diff --git a/ui/gl/gl_image.cc b/ui/gl/gl_image.cc index aaefb94..ff7eb56 100644 --- a/ui/gl/gl_image.cc +++ b/ui/gl/gl_image.cc @@ -19,6 +19,14 @@ void GLImage::ReleaseTexImage() { NOTIMPLEMENTED(); } +void GLImage::WillUseTexImage() { + NOTIMPLEMENTED(); +} + +void GLImage::DidUseTexImage() { + NOTIMPLEMENTED(); +} + GLImage::~GLImage() {} } // namespace gfx diff --git a/ui/gl/gl_image.h b/ui/gl/gl_image.h index 8d59bc4..859966c 100644 --- a/ui/gl/gl_image.h +++ b/ui/gl/gl_image.h @@ -33,6 +33,12 @@ class GL_EXPORT GLImage : public base::RefCounted<GLImage> { // Release image from texture currently bound to GL_TEXTURE_2D target. virtual void ReleaseTexImage(); + // Called before the texture is used for drawing. + virtual void WillUseTexImage(); + + // Called after the texture has been used for drawing. + virtual void DidUseTexImage(); + // Create a GL image for a window. static scoped_refptr<GLImage> CreateGLImage(gfx::PluginWindowHandle window); diff --git a/ui/gl/gl_image_egl.cc b/ui/gl/gl_image_egl.cc index 182117c..aeafc9a 100644 --- a/ui/gl/gl_image_egl.cc +++ b/ui/gl/gl_image_egl.cc @@ -11,7 +11,8 @@ namespace gfx { GLImageEGL::GLImageEGL(gfx::Size size) : egl_image_(EGL_NO_IMAGE_KHR), - size_(size) { + size_(size), + in_use_(false) { } GLImageEGL::~GLImageEGL() { @@ -40,25 +41,6 @@ bool GLImageEGL::Initialize(gfx::GpuMemoryBufferHandle buffer) { return true; } -bool GLImageEGL::BindTexImage() { - if (egl_image_ == EGL_NO_IMAGE_KHR) { - LOG(ERROR) << "NULL EGLImage in BindTexImage"; - return false; - } - - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_); - - if (glGetError() != GL_NO_ERROR) { - return false; - } - - return true; -} - -gfx::Size GLImageEGL::GetSize() { - return size_; -} - void GLImageEGL::Destroy() { if (egl_image_ == EGL_NO_IMAGE_KHR) return; @@ -74,7 +56,40 @@ void GLImageEGL::Destroy() { egl_image_ = EGL_NO_IMAGE_KHR; } +gfx::Size GLImageEGL::GetSize() { + return size_; +} + +bool GLImageEGL::BindTexImage() { + if (egl_image_ == EGL_NO_IMAGE_KHR) { + LOG(ERROR) << "NULL EGLImage in BindTexImage"; + return false; + } + + // Defer ImageTargetTexture2D if not currently in use. + if (!in_use_) + return true; + + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_); + DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + return true; +} + void GLImageEGL::ReleaseTexImage() { + // Nothing to do here as image is released after each use. +} + +void GLImageEGL::WillUseTexImage() { + DCHECK(egl_image_); + DCHECK(!in_use_); + in_use_ = true; + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_); + DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); +} + +void GLImageEGL::DidUseTexImage() { + DCHECK(in_use_); + in_use_ = false; char zero[4] = { 0, }; glTexImage2D(GL_TEXTURE_2D, 0, diff --git a/ui/gl/gl_image_egl.h b/ui/gl/gl_image_egl.h index 1c66bb9..2c64f4d 100644 --- a/ui/gl/gl_image_egl.h +++ b/ui/gl/gl_image_egl.h @@ -21,6 +21,8 @@ class GL_EXPORT GLImageEGL : public GLImage { virtual gfx::Size GetSize() OVERRIDE; virtual bool BindTexImage() OVERRIDE; virtual void ReleaseTexImage() OVERRIDE; + virtual void WillUseTexImage() OVERRIDE; + virtual void DidUseTexImage() OVERRIDE; protected: virtual ~GLImageEGL(); @@ -28,6 +30,7 @@ class GL_EXPORT GLImageEGL : public GLImage { private: EGLImageKHR egl_image_; gfx::Size size_; + bool in_use_; DISALLOW_COPY_AND_ASSIGN(GLImageEGL); }; diff --git a/ui/gl/gl_image_glx.cc b/ui/gl/gl_image_glx.cc index 85254f3..739b4d4 100644 --- a/ui/gl/gl_image_glx.cc +++ b/ui/gl/gl_image_glx.cc @@ -52,6 +52,10 @@ GLImageGLX::GLImageGLX(gfx::PluginWindowHandle window) glx_pixmap_(0) { } +GLImageGLX::~GLImageGLX() { + Destroy(); +} + bool GLImageGLX::Initialize() { if (!GLSurfaceGLX::IsTextureFromPixmapSupported()) { LOG(ERROR) << "GLX_EXT_texture_from_pixmap not supported."; @@ -170,8 +174,10 @@ void GLImageGLX::ReleaseTexImage() { glXReleaseTexImageEXT(display_, glx_pixmap_, GLX_FRONT_LEFT_EXT); } -GLImageGLX::~GLImageGLX() { - Destroy(); +void GLImageGLX::WillUseTexImage() { +} + +void GLImageGLX::DidUseTexImage() { } } // namespace gfx diff --git a/ui/gl/gl_image_glx.h b/ui/gl/gl_image_glx.h index bbdaa30..e1b9b4f 100644 --- a/ui/gl/gl_image_glx.h +++ b/ui/gl/gl_image_glx.h @@ -23,6 +23,8 @@ class GL_EXPORT GLImageGLX : public GLImage { virtual gfx::Size GetSize() OVERRIDE; virtual bool BindTexImage() OVERRIDE; virtual void ReleaseTexImage() OVERRIDE; + virtual void WillUseTexImage() OVERRIDE; + virtual void DidUseTexImage() OVERRIDE; protected: virtual ~GLImageGLX(); diff --git a/ui/gl/gl_image_shm.cc b/ui/gl/gl_image_shm.cc index 78e8164..5b182eb 100644 --- a/ui/gl/gl_image_shm.cc +++ b/ui/gl/gl_image_shm.cc @@ -40,6 +40,13 @@ bool GLImageShm::Initialize(gfx::GpuMemoryBufferHandle buffer) { return true; } +void GLImageShm::Destroy() { +} + +gfx::Size GLImageShm::GetSize() { + return size_; +} + bool GLImageShm::BindTexImage() { TRACE_EVENT0("gpu", "GLImageShm::BindTexImage"); DCHECK(shared_memory_); @@ -82,14 +89,13 @@ bool GLImageShm::BindTexImage() { return true; } -gfx::Size GLImageShm::GetSize() { - return size_; +void GLImageShm::ReleaseTexImage() { } -void GLImageShm::Destroy() { +void GLImageShm::WillUseTexImage() { } -void GLImageShm::ReleaseTexImage() { +void GLImageShm::DidUseTexImage() { } } // namespace gfx diff --git a/ui/gl/gl_image_shm.h b/ui/gl/gl_image_shm.h index ffdfc8b..d18938d 100644 --- a/ui/gl/gl_image_shm.h +++ b/ui/gl/gl_image_shm.h @@ -21,6 +21,8 @@ class GL_EXPORT GLImageShm : public GLImage { virtual gfx::Size GetSize() OVERRIDE; virtual bool BindTexImage() OVERRIDE; virtual void ReleaseTexImage() OVERRIDE; + virtual void WillUseTexImage() OVERRIDE; + virtual void DidUseTexImage() OVERRIDE; protected: virtual ~GLImageShm(); diff --git a/ui/gl/gl_image_stub.cc b/ui/gl/gl_image_stub.cc index 86efe6e..a1a8a85 100644 --- a/ui/gl/gl_image_stub.cc +++ b/ui/gl/gl_image_stub.cc @@ -6,6 +6,13 @@ namespace gfx { +GLImageStub::GLImageStub() { +} + +GLImageStub::~GLImageStub() { + Destroy(); +} + void GLImageStub::Destroy() { } @@ -20,6 +27,10 @@ bool GLImageStub::BindTexImage() { void GLImageStub::ReleaseTexImage() { } -GLImageStub::~GLImageStub() {} +void GLImageStub::WillUseTexImage() { +} + +void GLImageStub::DidUseTexImage() { +} } // namespace gfx diff --git a/ui/gl/gl_image_stub.h b/ui/gl/gl_image_stub.h index 8b47358..ec232fa 100644 --- a/ui/gl/gl_image_stub.h +++ b/ui/gl/gl_image_stub.h @@ -12,11 +12,15 @@ namespace gfx { // A GLImage that does nothing for unit tests. class GL_EXPORT GLImageStub : public GLImage { public: + GLImageStub(); + // Implement GLImage. virtual void Destroy() OVERRIDE; virtual gfx::Size GetSize() OVERRIDE; virtual bool BindTexImage() OVERRIDE; virtual void ReleaseTexImage() OVERRIDE; + virtual void WillUseTexImage() OVERRIDE; + virtual void DidUseTexImage() OVERRIDE; protected: virtual ~GLImageStub(); |