| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef GPU_COMMAND_BUFFER_SERVICE_TEXTURE_MANAGER_H_ |
| #define GPU_COMMAND_BUFFER_SERVICE_TEXTURE_MANAGER_H_ |
| |
| #include <list> |
| #include <set> |
| #include <string> |
| #include <vector> |
| #include "base/basictypes.h" |
| #include "base/containers/hash_tables.h" |
| #include "base/logging.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/observer_list.h" |
| #include "gpu/command_buffer/service/async_pixel_transfer_delegate.h" |
| #include "gpu/command_buffer/service/gl_utils.h" |
| #include "gpu/command_buffer/service/memory_tracking.h" |
| #include "gpu/gpu_export.h" |
| #include "ui/gl/gl_image.h" |
| |
| namespace gpu { |
| |
| class StreamTextureManager; |
| |
| namespace gles2 { |
| |
| class GLES2Decoder; |
| class Display; |
| class ErrorState; |
| class FeatureInfo; |
| class FramebufferManager; |
| class MailboxManager; |
| class TextureManager; |
| class TextureRef; |
| |
| // Info about Textures currently in the system. |
| // This class wraps a real GL texture, keeping track of its meta-data. It is |
| // jointly owned by possibly multiple TextureRef. |
| class GPU_EXPORT Texture { |
| public: |
| explicit Texture(GLuint service_id); |
| |
| GLenum min_filter() const { |
| return min_filter_; |
| } |
| |
| GLenum mag_filter() const { |
| return mag_filter_; |
| } |
| |
| GLenum wrap_s() const { |
| return wrap_s_; |
| } |
| |
| GLenum wrap_t() const { |
| return wrap_t_; |
| } |
| |
| GLenum usage() const { |
| return usage_; |
| } |
| |
| GLenum pool() const { |
| return pool_; |
| } |
| |
| int num_uncleared_mips() const { |
| return num_uncleared_mips_; |
| } |
| |
| uint32 estimated_size() const { |
| return estimated_size_; |
| } |
| |
| bool CanRenderTo() const { |
| return !stream_texture_ && target_ != GL_TEXTURE_EXTERNAL_OES; |
| } |
| |
| // The service side OpenGL id of the texture. |
| GLuint service_id() const { |
| return service_id_; |
| } |
| |
| void SetServiceId(GLuint service_id) { |
| DCHECK(service_id); |
| service_id_ = service_id; |
| } |
| |
| // Returns the target this texure was first bound to or 0 if it has not |
| // been bound. Once a texture is bound to a specific target it can never be |
| // bound to a different target. |
| GLenum target() const { |
| return target_; |
| } |
| |
| bool SafeToRenderFrom() const { |
| return cleared_; |
| } |
| |
| // Get the width and height for a particular level. Returns false if level |
| // does not exist. |
| bool GetLevelSize( |
| GLint target, GLint level, GLsizei* width, GLsizei* height) const; |
| |
| // Get the type of a level. Returns false if level does not exist. |
| bool GetLevelType( |
| GLint target, GLint level, GLenum* type, GLenum* internal_format) const; |
| |
| // Get the image bound to a particular level. Returns NULL if level |
| // does not exist. |
| gfx::GLImage* GetLevelImage(GLint target, GLint level) const; |
| |
| // Returns true of the given dimensions are inside the dimensions of the |
| // level and if the format and type match the level. |
| bool ValidForTexture( |
| GLint target, |
| GLint level, |
| GLint xoffset, |
| GLint yoffset, |
| GLsizei width, |
| GLsizei height, |
| GLenum format, |
| GLenum type) const; |
| |
| bool IsValid() const { |
| return !!target(); |
| } |
| |
| bool IsAttachedToFramebuffer() const { |
| return framebuffer_attachment_count_ != 0; |
| } |
| |
| void AttachToFramebuffer() { |
| ++framebuffer_attachment_count_; |
| } |
| |
| void DetachFromFramebuffer() { |
| DCHECK_GT(framebuffer_attachment_count_, 0); |
| --framebuffer_attachment_count_; |
| } |
| |
| bool IsStreamTexture() const { |
| return stream_texture_; |
| } |
| |
| void SetImmutable(bool immutable) { |
| immutable_ = immutable; |
| } |
| |
| bool IsImmutable() const { |
| return immutable_; |
| } |
| |
| // Whether a particular level/face is cleared. |
| bool IsLevelCleared(GLenum target, GLint level) const; |
| |
| // Whether the texture has been defined |
| bool IsDefined() const { |
| return estimated_size() > 0; |
| } |
| |
| private: |
| friend class MailboxManager; |
| friend class MailboxManagerTest; |
| friend class TextureManager; |
| friend class TextureRef; |
| friend class TextureTestHelper; |
| |
| ~Texture(); |
| void AddTextureRef(TextureRef* ref); |
| void RemoveTextureRef(TextureRef* ref, bool have_context); |
| MemoryTypeTracker* GetMemTracker(); |
| |
| // Condition on which this texture is renderable. Can be ONLY_IF_NPOT if it |
| // depends on context support for non-power-of-two textures (i.e. will be |
| // renderable if NPOT support is in the context, otherwise not, e.g. texture |
| // with a NPOT level). ALWAYS means it doesn't depend on context features |
| // (e.g. complete POT), NEVER means it's not renderable regardless (e.g. |
| // incomplete). |
| enum CanRenderCondition { |
| CAN_RENDER_ALWAYS, |
| CAN_RENDER_NEVER, |
| CAN_RENDER_ONLY_IF_NPOT |
| }; |
| |
| struct LevelInfo { |
| LevelInfo(); |
| LevelInfo(const LevelInfo& rhs); |
| ~LevelInfo(); |
| |
| bool cleared; |
| GLenum target; |
| GLint level; |
| GLenum internal_format; |
| GLsizei width; |
| GLsizei height; |
| GLsizei depth; |
| GLint border; |
| GLenum format; |
| GLenum type; |
| scoped_refptr<gfx::GLImage> image; |
| uint32 estimated_size; |
| }; |
| |
| // Set the info for a particular level. |
| void SetLevelInfo( |
| const FeatureInfo* feature_info, |
| GLenum target, |
| GLint level, |
| GLenum internal_format, |
| GLsizei width, |
| GLsizei height, |
| GLsizei depth, |
| GLint border, |
| GLenum format, |
| GLenum type, |
| bool cleared); |
| |
| // In GLES2 "texture complete" means it has all required mips for filtering |
| // down to a 1x1 pixel texture, they are in the correct order, they are all |
| // the same format. |
| bool texture_complete() const { |
| return texture_complete_; |
| } |
| |
| // In GLES2 "cube complete" means all 6 faces level 0 are defined, all the |
| // same format, all the same dimensions and all width = height. |
| bool cube_complete() const { |
| return cube_complete_; |
| } |
| |
| // Whether or not this texture is a non-power-of-two texture. |
| bool npot() const { |
| return npot_; |
| } |
| |
| void SetStreamTexture(bool stream_texture) { |
| stream_texture_ = stream_texture; |
| UpdateCanRenderCondition(); |
| } |
| |
| // Marks a particular level as cleared or uncleared. |
| void SetLevelCleared(GLenum target, GLint level, bool cleared); |
| |
| // Updates the cleared flag for this texture by inspecting all the mips. |
| void UpdateCleared(); |
| |
| // Clears any renderable uncleared levels. |
| // Returns false if a GL error was generated. |
| bool ClearRenderableLevels(GLES2Decoder* decoder); |
| |
| // Clears the level. |
| // Returns false if a GL error was generated. |
| bool ClearLevel(GLES2Decoder* decoder, GLenum target, GLint level); |
| |
| // Sets a texture parameter. |
| // TODO(gman): Expand to SetParameteri,f,iv,fv |
| // Returns GL_NO_ERROR on success. Otherwise the error to generate. |
| GLenum SetParameter( |
| const FeatureInfo* feature_info, GLenum pname, GLint param); |
| |
| // Makes each of the mip levels as though they were generated. |
| bool MarkMipmapsGenerated(const FeatureInfo* feature_info); |
| |
| bool NeedsMips() const { |
| return min_filter_ != GL_NEAREST && min_filter_ != GL_LINEAR; |
| } |
| |
| // True if this texture meets all the GLES2 criteria for rendering. |
| // See section 3.8.2 of the GLES2 spec. |
| bool CanRender(const FeatureInfo* feature_info) const; |
| |
| // Returns true if mipmaps can be generated by GL. |
| bool CanGenerateMipmaps(const FeatureInfo* feature_info) const; |
| |
| // Sets the Texture's target |
| // Parameters: |
| // target: GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP or |
| // GL_TEXTURE_EXTERNAL_OES or GL_TEXTURE_RECTANGLE_ARB |
| // max_levels: The maximum levels this type of target can have. |
| void SetTarget( |
| const FeatureInfo* feature_info, GLenum target, GLint max_levels); |
| |
| // Update info about this texture. |
| void Update(const FeatureInfo* feature_info); |
| |
| // Set the image for a particular level. |
| void SetLevelImage( |
| const FeatureInfo* feature_info, |
| GLenum target, |
| GLint level, |
| gfx::GLImage* image); |
| |
| // Appends a signature for the given level. |
| void AddToSignature( |
| const FeatureInfo* feature_info, |
| GLenum target, GLint level, std::string* signature) const; |
| |
| void SetMailboxManager(MailboxManager* mailbox_manager); |
| |
| // Updates the unsafe textures count in all the managers referencing this |
| // texture. |
| void UpdateSafeToRenderFrom(bool cleared); |
| |
| // Updates the uncleared mip count in all the managers referencing this |
| // texture. |
| void UpdateMipCleared(LevelInfo* info, bool cleared); |
| |
| // Computes the CanRenderCondition flag. |
| CanRenderCondition GetCanRenderCondition() const; |
| |
| // Updates the unrenderable texture count in all the managers referencing this |
| // texture. |
| void UpdateCanRenderCondition(); |
| |
| // Increment the framebuffer state change count in all the managers |
| // referencing this texture. |
| void IncAllFramebufferStateChangeCount(); |
| |
| MailboxManager* mailbox_manager_; |
| |
| // Info about each face and level of texture. |
| std::vector<std::vector<LevelInfo> > level_infos_; |
| |
| // The texture refs that point to this Texture. |
| typedef std::set<TextureRef*> RefSet; |
| RefSet refs_; |
| |
| // The single TextureRef that accounts for memory for this texture. Must be |
| // one of refs_. |
| TextureRef* memory_tracking_ref_; |
| |
| // The id of the texure |
| GLuint service_id_; |
| |
| // Whether all renderable mips of this texture have been cleared. |
| bool cleared_; |
| |
| int num_uncleared_mips_; |
| |
| // The target. 0 if unset, otherwise GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP. |
| GLenum target_; |
| |
| // Texture parameters. |
| GLenum min_filter_; |
| GLenum mag_filter_; |
| GLenum wrap_s_; |
| GLenum wrap_t_; |
| GLenum usage_; |
| GLenum pool_; |
| |
| // The maximum level that has been set. |
| GLint max_level_set_; |
| |
| // Whether or not this texture is "texture complete" |
| bool texture_complete_; |
| |
| // Whether or not this texture is "cube complete" |
| bool cube_complete_; |
| |
| // Whether or not this texture is non-power-of-two |
| bool npot_; |
| |
| // Whether this texture has ever been bound. |
| bool has_been_bound_; |
| |
| // The number of framebuffers this texture is attached to. |
| int framebuffer_attachment_count_; |
| |
| // Whether this is a special streaming texture. |
| bool stream_texture_; |
| |
| // Whether the texture is immutable and no further changes to the format |
| // or dimensions of the texture object can be made. |
| bool immutable_; |
| |
| // Size in bytes this texture is assumed to take in memory. |
| uint32 estimated_size_; |
| |
| // Cache of the computed CanRenderCondition flag. |
| CanRenderCondition can_render_condition_; |
| |
| DISALLOW_COPY_AND_ASSIGN(Texture); |
| }; |
| |
| // This class represents a texture in a client context group. It's mostly 1:1 |
| // with a client id, though it can outlive the client id if it's still bound to |
| // a FBO or another context when destroyed. |
| // Multiple TextureRef can point to the same texture with cross-context sharing. |
| // |
| // Note: for stream textures, the TextureRef that created the stream texture is |
| // set as the "owner" of the stream texture, i.e. it will call |
| // DestroyStreamTexture on destruction. This is because the StreamTextureManager |
| // isn't generally shared between ContextGroups, so ownership can't be at the |
| // Texture level. We also can't have multiple StreamTexture on the same service |
| // id, so there can be only one owner. |
| class GPU_EXPORT TextureRef : public base::RefCounted<TextureRef> { |
| public: |
| TextureRef(TextureManager* manager, GLuint client_id, Texture* texture); |
| static scoped_refptr<TextureRef> Create(TextureManager* manager, |
| GLuint client_id, |
| GLuint service_id); |
| const Texture* texture() const { return texture_; } |
| Texture* texture() { return texture_; } |
| GLuint client_id() const { return client_id_; } |
| GLuint service_id() const { return texture_->service_id(); } |
| |
| private: |
| friend class base::RefCounted<TextureRef>; |
| friend class Texture; |
| friend class TextureManager; |
| |
| ~TextureRef(); |
| const TextureManager* manager() const { return manager_; } |
| TextureManager* manager() { return manager_; } |
| void reset_client_id() { client_id_ = 0; } |
| void set_is_stream_texture_owner(bool owner) { |
| is_stream_texture_owner_ = owner; |
| } |
| bool is_stream_texture_owner() const { return is_stream_texture_owner_; } |
| |
| TextureManager* manager_; |
| Texture* texture_; |
| GLuint client_id_; |
| bool is_stream_texture_owner_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TextureRef); |
| }; |
| |
| // This class keeps track of the textures and their sizes so we can do NPOT and |
| // texture complete checking. |
| // |
| // NOTE: To support shared resources an instance of this class will need to be |
| // shared by multiple GLES2Decoders. |
| class GPU_EXPORT TextureManager { |
| public: |
| class GPU_EXPORT DestructionObserver { |
| public: |
| DestructionObserver(); |
| virtual ~DestructionObserver(); |
| |
| // Called in ~TextureManager. |
| virtual void OnTextureManagerDestroying(TextureManager* manager) = 0; |
| |
| // Called via ~TextureRef. |
| virtual void OnTextureRefDestroying(TextureRef* texture) = 0; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(DestructionObserver); |
| }; |
| |
| enum DefaultAndBlackTextures { |
| kTexture2D, |
| kCubeMap, |
| kExternalOES, |
| kRectangleARB, |
| kNumDefaultTextures |
| }; |
| |
| TextureManager(MemoryTracker* memory_tracker, |
| FeatureInfo* feature_info, |
| GLsizei max_texture_size, |
| GLsizei max_cube_map_texture_size); |
| ~TextureManager(); |
| |
| void set_framebuffer_manager(FramebufferManager* manager) { |
| framebuffer_manager_ = manager; |
| } |
| |
| void set_stream_texture_manager(StreamTextureManager* manager) { |
| stream_texture_manager_ = manager; |
| } |
| |
| // Init the texture manager. |
| bool Initialize(); |
| |
| // Must call before destruction. |
| void Destroy(bool have_context); |
| |
| // Returns the maximum number of levels. |
| GLint MaxLevelsForTarget(GLenum target) const { |
| switch (target) { |
| case GL_TEXTURE_2D: |
| return max_levels_; |
| case GL_TEXTURE_EXTERNAL_OES: |
| return 1; |
| default: |
| return max_cube_map_levels_; |
| } |
| } |
| |
| // Returns the maximum size. |
| GLsizei MaxSizeForTarget(GLenum target) const { |
| switch (target) { |
| case GL_TEXTURE_2D: |
| case GL_TEXTURE_EXTERNAL_OES: |
| return max_texture_size_; |
| default: |
| return max_cube_map_texture_size_; |
| } |
| } |
| |
| // Returns the maxium number of levels a texture of the given size can have. |
| static GLsizei ComputeMipMapCount( |
| GLsizei width, GLsizei height, GLsizei depth); |
| |
| // Checks if a dimensions are valid for a given target. |
| bool ValidForTarget( |
| GLenum target, GLint level, |
| GLsizei width, GLsizei height, GLsizei depth); |
| |
| // True if this texture meets all the GLES2 criteria for rendering. |
| // See section 3.8.2 of the GLES2 spec. |
| bool CanRender(const TextureRef* ref) const { |
| return ref->texture()->CanRender(feature_info_.get()); |
| } |
| |
| // Returns true if mipmaps can be generated by GL. |
| bool CanGenerateMipmaps(const TextureRef* ref) const { |
| return ref->texture()->CanGenerateMipmaps(feature_info_.get()); |
| } |
| |
| // Sets the Texture's target |
| // Parameters: |
| // target: GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP |
| // max_levels: The maximum levels this type of target can have. |
| void SetTarget( |
| TextureRef* ref, |
| GLenum target); |
| |
| // Marks a texture as a stream texture, and the ref as the stream texture |
| // owner. |
| void SetStreamTexture(TextureRef* ref, bool stream_texture); |
| |
| // Whether the TextureRef is the stream texture owner. |
| bool IsStreamTextureOwner(TextureRef* ref); |
| |
| // Set the info for a particular level in a TexureInfo. |
| void SetLevelInfo( |
| TextureRef* ref, |
| GLenum target, |
| GLint level, |
| GLenum internal_format, |
| GLsizei width, |
| GLsizei height, |
| GLsizei depth, |
| GLint border, |
| GLenum format, |
| GLenum type, |
| bool cleared); |
| |
| // Adapter to call above function. |
| void SetLevelInfoFromParams(TextureRef* ref, |
| const gpu::AsyncTexImage2DParams& params) { |
| SetLevelInfo( |
| ref, params.target, params.level, params.internal_format, |
| params.width, params.height, 1 /* depth */, |
| params.border, params.format, |
| params.type, true /* cleared */ ); |
| } |
| |
| Texture* Produce(TextureRef* ref); |
| |
| // Maps an existing texture into the texture manager, at a given client ID. |
| TextureRef* Consume(GLuint client_id, Texture* texture); |
| |
| // Sets a mip as cleared. |
| void SetLevelCleared(TextureRef* ref, GLenum target, |
| GLint level, bool cleared); |
| |
| // Sets a texture parameter of a Texture |
| // Returns GL_NO_ERROR on success. Otherwise the error to generate. |
| // TODO(gman): Expand to SetParameteri,f,iv,fv |
| void SetParameter( |
| const char* function_name, ErrorState* error_state, |
| TextureRef* ref, GLenum pname, GLint param); |
| |
| // Makes each of the mip levels as though they were generated. |
| // Returns false if that's not allowed for the given texture. |
| bool MarkMipmapsGenerated(TextureRef* ref); |
| |
| // Clears any uncleared renderable levels. |
| bool ClearRenderableLevels(GLES2Decoder* decoder, TextureRef* ref); |
| |
| // Clear a specific level. |
| bool ClearTextureLevel( |
| GLES2Decoder* decoder, TextureRef* ref, GLenum target, GLint level); |
| |
| // Creates a new texture info. |
| TextureRef* CreateTexture(GLuint client_id, GLuint service_id); |
| |
| // Gets the texture info for the given texture. |
| TextureRef* GetTexture(GLuint client_id) const; |
| |
| // Removes a texture info. |
| void RemoveTexture(GLuint client_id); |
| |
| // Gets a Texture for a given service id (note: it assumes the texture object |
| // is still mapped in this TextureManager). |
| Texture* GetTextureForServiceId(GLuint service_id) const; |
| |
| TextureRef* GetDefaultTextureInfo(GLenum target) { |
| switch (target) { |
| case GL_TEXTURE_2D: |
| return default_textures_[kTexture2D].get(); |
| case GL_TEXTURE_CUBE_MAP: |
| return default_textures_[kCubeMap].get(); |
| case GL_TEXTURE_EXTERNAL_OES: |
| return default_textures_[kExternalOES].get(); |
| case GL_TEXTURE_RECTANGLE_ARB: |
| return default_textures_[kRectangleARB].get(); |
| default: |
| NOTREACHED(); |
| return NULL; |
| } |
| } |
| |
| bool HaveUnrenderableTextures() const { |
| return num_unrenderable_textures_ > 0; |
| } |
| |
| bool HaveUnsafeTextures() const { |
| return num_unsafe_textures_ > 0; |
| } |
| |
| bool HaveUnclearedMips() const { |
| return num_uncleared_mips_ > 0; |
| } |
| |
| GLuint black_texture_id(GLenum target) const { |
| switch (target) { |
| case GL_SAMPLER_2D: |
| return black_texture_ids_[kTexture2D]; |
| case GL_SAMPLER_CUBE: |
| return black_texture_ids_[kCubeMap]; |
| case GL_SAMPLER_EXTERNAL_OES: |
| return black_texture_ids_[kExternalOES]; |
| case GL_SAMPLER_2D_RECT_ARB: |
| return black_texture_ids_[kRectangleARB]; |
| default: |
| NOTREACHED(); |
| return 0; |
| } |
| } |
| |
| size_t mem_represented() const { |
| return |
| memory_tracker_managed_->GetMemRepresented() + |
| memory_tracker_unmanaged_->GetMemRepresented(); |
| } |
| |
| void SetLevelImage( |
| TextureRef* ref, |
| GLenum target, |
| GLint level, |
| gfx::GLImage* image); |
| |
| void AddToSignature( |
| TextureRef* ref, |
| GLenum target, |
| GLint level, |
| std::string* signature) const; |
| |
| void AddObserver(DestructionObserver* observer) { |
| destruction_observers_.AddObserver(observer); |
| } |
| |
| void RemoveObserver(DestructionObserver* observer) { |
| destruction_observers_.RemoveObserver(observer); |
| } |
| |
| private: |
| friend class Texture; |
| friend class TextureRef; |
| |
| // Helper for Initialize(). |
| scoped_refptr<TextureRef> CreateDefaultAndBlackTextures( |
| GLenum target, |
| GLuint* black_texture); |
| |
| void StartTracking(TextureRef* texture); |
| void StopTracking(TextureRef* texture); |
| |
| void UpdateSafeToRenderFrom(int delta); |
| void UpdateUnclearedMips(int delta); |
| void UpdateCanRenderCondition(Texture::CanRenderCondition old_condition, |
| Texture::CanRenderCondition new_condition); |
| void IncFramebufferStateChangeCount(); |
| |
| MemoryTypeTracker* GetMemTracker(GLenum texture_pool); |
| scoped_ptr<MemoryTypeTracker> memory_tracker_managed_; |
| scoped_ptr<MemoryTypeTracker> memory_tracker_unmanaged_; |
| |
| scoped_refptr<FeatureInfo> feature_info_; |
| |
| FramebufferManager* framebuffer_manager_; |
| StreamTextureManager* stream_texture_manager_; |
| |
| // Info for each texture in the system. |
| typedef base::hash_map<GLuint, scoped_refptr<TextureRef> > TextureMap; |
| TextureMap textures_; |
| |
| GLsizei max_texture_size_; |
| GLsizei max_cube_map_texture_size_; |
| GLint max_levels_; |
| GLint max_cube_map_levels_; |
| |
| int num_unrenderable_textures_; |
| int num_unsafe_textures_; |
| int num_uncleared_mips_; |
| |
| // Counts the number of Textures allocated with 'this' as its manager. |
| // Allows to check no Texture will outlive this. |
| unsigned int texture_count_; |
| |
| bool have_context_; |
| |
| // Black (0,0,0,1) textures for when non-renderable textures are used. |
| // NOTE: There is no corresponding Texture for these textures. |
| // TextureInfos are only for textures the client side can access. |
| GLuint black_texture_ids_[kNumDefaultTextures]; |
| |
| // The default textures for each target (texture name = 0) |
| scoped_refptr<TextureRef> default_textures_[kNumDefaultTextures]; |
| |
| ObserverList<DestructionObserver> destruction_observers_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TextureManager); |
| }; |
| |
| } // namespace gles2 |
| } // namespace gpu |
| |
| #endif // GPU_COMMAND_BUFFER_SERVICE_TEXTURE_MANAGER_H_ |