| // 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 <stddef.h> |
| #include <stdint.h> |
| |
| #include <algorithm> |
| #include <list> |
| #include <memory> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include "base/containers/hash_tables.h" |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "gpu/command_buffer/service/feature_info.h" |
| #include "gpu/command_buffer/service/gl_utils.h" |
| #include "gpu/command_buffer/service/memory_tracking.h" |
| #include "gpu/command_buffer/service/sampler_manager.h" |
| #include "gpu/gpu_export.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gl/gl_image.h" |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| class GLES2Decoder; |
| class GLStreamTextureImage; |
| struct ContextState; |
| struct DecoderFramebufferState; |
| class Display; |
| class ErrorState; |
| class FeatureInfo; |
| class FramebufferManager; |
| class MailboxManager; |
| class ProgressReporter; |
| class Texture; |
| class TextureManager; |
| class TextureRef; |
| |
| class GPU_EXPORT TextureBase { |
| public: |
| explicit TextureBase(GLuint service_id); |
| virtual ~TextureBase(); |
| |
| // The service side OpenGL id of the texture. |
| GLuint service_id() const { return service_id_; } |
| |
| protected: |
| // The id of the texture. |
| GLuint service_id_; |
| |
| void DeleteFromMailboxManager(); |
| |
| private: |
| friend class MailboxManagerSync; |
| friend class MailboxManagerImpl; |
| |
| void SetMailboxManager(MailboxManager* mailbox_manager); |
| |
| MailboxManager* mailbox_manager_; |
| }; |
| |
| // A ref-counted version of the TextureBase class that deletes the texture after |
| // all references have been released. |
| class TexturePassthrough final : public TextureBase, |
| public base::RefCounted<TexturePassthrough> { |
| public: |
| explicit TexturePassthrough(GLuint service_id); |
| |
| // Notify the texture that the context is lost and it shouldn't delete the |
| // native GL texture in the destructor |
| void MarkContextLost(); |
| |
| protected: |
| ~TexturePassthrough() override; |
| |
| private: |
| friend class base::RefCounted<TexturePassthrough>; |
| |
| bool have_context_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TexturePassthrough); |
| }; |
| |
| // 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 final : public TextureBase { |
| public: |
| enum ImageState { |
| // If an image is associated with the texture and image state is UNBOUND, |
| // then sampling out of the texture or using it as a target for drawing |
| // will not read/write from/to the image. |
| UNBOUND, |
| // If image state is BOUND, then sampling from the texture will return the |
| // contents of the image and using it as a target will modify the image. |
| BOUND, |
| // Image state is set to COPIED if the contents of the image has been |
| // copied to the texture. Sampling from the texture will be equivalent |
| // to sampling out the image (assuming image has not been changed since |
| // it was copied). Using the texture as a target for drawing will only |
| // modify the texture and not the image. |
| COPIED |
| }; |
| |
| struct CompatibilitySwizzle { |
| GLenum format; |
| GLenum dest_format; |
| GLenum red; |
| GLenum green; |
| GLenum blue; |
| GLenum alpha; |
| }; |
| |
| explicit Texture(GLuint service_id); |
| |
| const SamplerState& sampler_state() const { |
| return sampler_state_; |
| } |
| |
| GLenum min_filter() const { |
| return sampler_state_.min_filter; |
| } |
| |
| GLenum mag_filter() const { |
| return sampler_state_.mag_filter; |
| } |
| |
| GLenum wrap_r() const { |
| return sampler_state_.wrap_r; |
| } |
| |
| GLenum wrap_s() const { |
| return sampler_state_.wrap_s; |
| } |
| |
| GLenum wrap_t() const { |
| return sampler_state_.wrap_t; |
| } |
| |
| GLenum usage() const { |
| return usage_; |
| } |
| |
| GLenum compare_func() const { |
| return sampler_state_.compare_func; |
| } |
| |
| GLenum compare_mode() const { |
| return sampler_state_.compare_mode; |
| } |
| |
| GLfloat max_lod() const { |
| return sampler_state_.max_lod; |
| } |
| |
| GLfloat min_lod() const { |
| return sampler_state_.min_lod; |
| } |
| |
| GLint base_level() const { |
| return base_level_; |
| } |
| |
| GLint max_level() const { |
| return max_level_; |
| } |
| |
| GLenum swizzle_r() const { return swizzle_r_; } |
| |
| GLenum swizzle_g() const { return swizzle_g_; } |
| |
| GLenum swizzle_b() const { return swizzle_b_; } |
| |
| GLenum swizzle_a() const { return swizzle_a_; } |
| |
| int num_uncleared_mips() const { |
| return num_uncleared_mips_; |
| } |
| |
| uint32_t estimated_size() const { return estimated_size_; } |
| |
| bool CanRenderTo(const FeatureInfo* feature_info, GLint level) const; |
| |
| void SetServiceId(GLuint service_id) { |
| DCHECK(service_id); |
| DCHECK_EQ(owned_service_id_, service_id_); |
| service_id_ = service_id; |
| owned_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/height/depth for a particular level. Returns false if level |
| // does not exist. |
| // |depth| is optional and can be nullptr. |
| bool GetLevelSize( |
| GLint target, GLint level, |
| GLsizei* width, GLsizei* height, GLsizei* depth) 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; |
| |
| // Set the image for a particular level. If a GLStreamTextureImage was |
| // previously set with SetLevelStreamTextureImage(), this will reset |
| // |service_id_| back to |owned_service_id_|, removing the service id override |
| // set by the GLStreamTextureImage. |
| void SetLevelImage(GLenum target, |
| GLint level, |
| gl::GLImage* image, |
| ImageState state); |
| |
| // Set the GLStreamTextureImage for a particular level. This is like |
| // SetLevelImage, but it also makes it optional to override |service_id_| with |
| // a texture bound to the stream texture, and permits |
| // GetLevelStreamTextureImage to return the image. See |
| // SetStreamTextureServiceId() for the details of how |service_id| is used. |
| void SetLevelStreamTextureImage(GLenum target, |
| GLint level, |
| GLStreamTextureImage* image, |
| ImageState state, |
| GLuint service_id); |
| |
| // Set the ImageState for the image bound to the given level. |
| void SetLevelImageState(GLenum target, GLint level, ImageState state); |
| |
| |
| // Get the image associated with a particular level. Returns NULL if level |
| // does not exist. |
| gl::GLImage* GetLevelImage(GLint target, |
| GLint level, |
| ImageState* state) const; |
| gl::GLImage* GetLevelImage(GLint target, GLint level) const; |
| |
| // Like GetLevelImage, but will return NULL if the image wasn't set via |
| // a call to SetLevelStreamTextureImage. |
| GLStreamTextureImage* GetLevelStreamTextureImage(GLint target, |
| GLint level) const; |
| |
| bool HasImages() const { |
| return has_images_; |
| } |
| |
| // Returns true of the given dimensions are inside the dimensions of the |
| // level. |
| bool ValidForTexture( |
| GLint target, |
| GLint level, |
| GLint xoffset, |
| GLint yoffset, |
| GLint zoffset, |
| GLsizei width, |
| GLsizei height, |
| GLsizei depth) 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_; |
| } |
| |
| void SetImmutable(bool immutable) { |
| immutable_ = immutable; |
| } |
| |
| bool IsImmutable() const { |
| return immutable_; |
| } |
| |
| // Return 0 if it's not immutable. |
| GLint GetImmutableLevels() const; |
| |
| // Get the cleared rectangle for a particular level. Returns an empty |
| // rectangle if level does not exist. |
| gfx::Rect GetLevelClearedRect(GLenum target, GLint level) const; |
| |
| // Whether a particular level/face is cleared. |
| bool IsLevelCleared(GLenum target, GLint level) const; |
| // Whether a particular level/face is partially cleared. |
| bool IsLevelPartiallyCleared(GLenum target, GLint level) const; |
| |
| // Whether the texture has been defined |
| bool IsDefined() const { |
| return estimated_size() > 0; |
| } |
| |
| // Initialize TEXTURE_MAX_ANISOTROPY to 1 if we haven't done so yet. |
| void InitTextureMaxAnisotropyIfNeeded(GLenum target); |
| |
| void DumpLevelMemory(base::trace_event::ProcessMemoryDump* pmd, |
| uint64_t client_tracing_id, |
| const std::string& dump_name) const; |
| |
| void ApplyFormatWorkarounds(FeatureInfo* feature_info); |
| |
| bool EmulatingRGB(); |
| |
| private: |
| friend class MailboxManagerImpl; |
| friend class MailboxManagerSync; |
| friend class MailboxManagerTest; |
| friend class TextureDefinition; |
| friend class TextureManager; |
| friend class TextureRef; |
| friend class TextureTestHelper; |
| |
| ~Texture() override; |
| 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_NEEDS_VALIDATION, |
| }; |
| |
| struct LevelInfo { |
| LevelInfo(); |
| LevelInfo(const LevelInfo& rhs); |
| ~LevelInfo(); |
| |
| gfx::Rect cleared_rect; |
| GLenum target; |
| GLint level; |
| GLenum internal_format; |
| GLsizei width; |
| GLsizei height; |
| GLsizei depth; |
| GLint border; |
| GLenum format; |
| GLenum type; |
| scoped_refptr<gl::GLImage> image; |
| scoped_refptr<GLStreamTextureImage> stream_texture_image; |
| ImageState image_state; |
| uint32_t estimated_size; |
| bool internal_workaround; |
| }; |
| |
| struct FaceInfo { |
| FaceInfo(); |
| FaceInfo(const FaceInfo& other); |
| ~FaceInfo(); |
| |
| // This is relative to base_level and max_level of a texture. |
| GLsizei num_mip_levels; |
| // This contains slots for all levels starting at 0. |
| std::vector<LevelInfo> level_infos; |
| }; |
| |
| // Helper for SetLevel*Image. |stream_texture_image| may be null. |
| void SetLevelImageInternal(GLenum target, |
| GLint level, |
| gl::GLImage* image, |
| GLStreamTextureImage* stream_texture_image, |
| ImageState state); |
| |
| // Returns the LevelInfo for |target| and |level| if it's set, else NULL. |
| const LevelInfo* GetLevelInfo(GLint target, GLint level) const; |
| |
| // Set the info for a particular level. |
| void SetLevelInfo(GLenum target, |
| GLint level, |
| GLenum internal_format, |
| GLsizei width, |
| GLsizei height, |
| GLsizei depth, |
| GLint border, |
| GLenum format, |
| GLenum type, |
| const gfx::Rect& cleared_rect); |
| |
| // Causes us to report |service_id| as our service id, but does not delete |
| // it when we are destroyed. Will rebind any OES_EXTERNAL texture units to |
| // our new service id in all contexts. If |service_id| is zero, then we |
| // revert to |owned_service_id_|. |
| void SetStreamTextureServiceId(GLuint service_id); |
| |
| void MarkLevelAsInternalWorkaround(GLenum target, GLint level); |
| |
| // 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_; |
| } |
| |
| // Marks a |rect| of a particular level as cleared. |
| void SetLevelClearedRect(GLenum target, |
| GLint level, |
| const gfx::Rect& cleared_rect); |
| |
| // 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 SetParameteriv,fv |
| // Returns GL_NO_ERROR on success. Otherwise the error to generate. |
| GLenum SetParameteri( |
| const FeatureInfo* feature_info, GLenum pname, GLint param); |
| GLenum SetParameterf( |
| const FeatureInfo* feature_info, GLenum pname, GLfloat param); |
| |
| // Makes each of the mip levels as though they were generated. |
| void MarkMipmapsGenerated(); |
| |
| bool NeedsMips() const { |
| return sampler_state_.min_filter != GL_NEAREST && |
| sampler_state_.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; |
| bool CanRenderWithSampler(const FeatureInfo* feature_info, |
| const SamplerState& sampler_state) const; |
| |
| // Returns true if mipmaps can be generated by GL. |
| bool CanGenerateMipmaps(const FeatureInfo* feature_info) const; |
| |
| // Returns true if any of the texture dimensions are not a power of two. |
| static bool TextureIsNPOT(GLsizei width, GLsizei height, GLsizei depth); |
| |
| // Returns true if texture face is complete relative to the first face. |
| static bool TextureFaceComplete(const Texture::LevelInfo& first_face, |
| size_t face_index, |
| GLenum target, |
| GLenum internal_format, |
| GLsizei width, |
| GLsizei height, |
| GLsizei depth, |
| GLenum format, |
| GLenum type); |
| |
| // Returns true if texture mip level is complete relative to base level. |
| // Note that level_diff = level - base_level. |
| static bool TextureMipComplete(const Texture::LevelInfo& base_level_face, |
| GLenum target, |
| GLint level_diff, |
| GLenum internal_format, |
| GLsizei width, |
| GLsizei height, |
| GLsizei depth, |
| GLenum format, |
| GLenum type); |
| |
| static bool ColorRenderable(const FeatureInfo* feature_info, |
| GLenum internal_format); |
| |
| static bool TextureFilterable(const FeatureInfo* feature_info, |
| GLenum internal_format, |
| GLenum type); |
| |
| // 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 |
| // GL_TEXTURE_2D_ARRAY or GL_TEXTURE_3D (for GLES3) |
| // max_levels: The maximum levels this type of target can have. |
| void SetTarget(GLenum target, GLint max_levels); |
| |
| // Update info about this texture. |
| void Update(); |
| |
| // Appends a signature for the given level. |
| void AddToSignature( |
| const FeatureInfo* feature_info, |
| GLenum target, GLint level, std::string* signature) const; |
| |
| // 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, |
| GLsizei width, |
| GLsizei height, |
| const gfx::Rect& cleared_rect); |
| |
| // Computes the CanRenderCondition flag. |
| CanRenderCondition GetCanRenderCondition() const; |
| |
| // Updates the unrenderable texture count in all the managers referencing this |
| // texture. |
| void UpdateCanRenderCondition(); |
| |
| // Updates the images count in all the managers referencing this |
| // texture. |
| void UpdateHasImages(); |
| |
| // Updates the flag that indicates whether this texture requires RGB |
| // emulation. |
| void UpdateEmulatingRGB(); |
| |
| // Increment the framebuffer state change count in all the managers |
| // referencing this texture. |
| void IncAllFramebufferStateChangeCount(); |
| |
| void UpdateBaseLevel(GLint base_level); |
| void UpdateMaxLevel(GLint max_level); |
| void UpdateNumMipLevels(); |
| |
| // Increment the generation counter for all managers that have a reference to |
| // this texture. |
| void IncrementManagerServiceIdGeneration(); |
| |
| // Return the service id of the texture that we will delete when we are |
| // destroyed. |
| GLuint owned_service_id() const { return owned_service_id_; } |
| |
| GLenum GetCompatibilitySwizzleForChannel(GLenum channel); |
| void SetCompatibilitySwizzle(const CompatibilitySwizzle* swizzle); |
| |
| // Info about each face and level of texture. |
| std::vector<FaceInfo> face_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 texture that we are responsible for deleting. Normally, this |
| // is the same as |service_id_|, unless a GLStreamTextureImage with its own |
| // service id is bound. In that case the GLStreamTextureImage service id is |
| // stored in |service_id_| and overrides the owned service id for all purposes |
| // except deleting the texture name. |
| GLuint owned_service_id_; |
| |
| // Whether all renderable mips of this texture have been cleared. |
| bool cleared_; |
| |
| int num_uncleared_mips_; |
| int num_npot_faces_; |
| |
| // The target. 0 if unset, otherwise GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP. |
| // Or GL_TEXTURE_2D_ARRAY or GL_TEXTURE_3D (for GLES3). |
| GLenum target_; |
| |
| // Texture parameters. |
| SamplerState sampler_state_; |
| GLenum usage_; |
| GLint base_level_; |
| GLint max_level_; |
| GLenum swizzle_r_; |
| GLenum swizzle_g_; |
| GLenum swizzle_b_; |
| GLenum swizzle_a_; |
| |
| // The maximum level that has been set. |
| GLint max_level_set_; |
| |
| // Whether or not this texture is "texture complete" |
| bool texture_complete_; |
| |
| // Whether mip levels have changed and should be reverified. |
| bool texture_mips_dirty_; |
| |
| // 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 the texture is immutable and no further changes to the format |
| // 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_t estimated_size_; |
| |
| // Cache of the computed CanRenderCondition flag. |
| CanRenderCondition can_render_condition_; |
| |
| // Whether we have initialized TEXTURE_MAX_ANISOTROPY to 1. |
| bool texture_max_anisotropy_initialized_; |
| |
| const CompatibilitySwizzle* compatibility_swizzle_; |
| |
| bool emulating_rgb_; |
| |
| 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. |
| 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); |
| |
| void AddObserver() { num_observers_++; } |
| void RemoveObserver() { num_observers_--; } |
| |
| 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(); } |
| GLint num_observers() const { return num_observers_; } |
| |
| // When the TextureRef is destroyed, it will assume that the context has been |
| // lost, regardless of the state of the TextureManager. |
| void ForceContextLost(); |
| |
| 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; } |
| |
| TextureManager* manager_; |
| Texture* texture_; |
| GLuint client_id_; |
| GLint num_observers_; |
| bool force_context_lost_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TextureRef); |
| }; |
| |
| // Holds data that is per gles2_cmd_decoder, but is related to to the |
| // TextureManager. |
| struct DecoderTextureState { |
| // total_texture_upload_time automatically initialized to 0 in default |
| // constructor. |
| explicit DecoderTextureState(const GpuDriverBugWorkarounds& workarounds) |
| : tex_image_failed(false), |
| texture_upload_count(0), |
| texsubimage_faster_than_teximage( |
| workarounds.texsubimage_faster_than_teximage), |
| force_cube_map_positive_x_allocation( |
| workarounds.force_cube_map_positive_x_allocation), |
| force_cube_complete(workarounds.force_cube_complete), |
| unpack_alignment_workaround_with_unpack_buffer( |
| workarounds.unpack_alignment_workaround_with_unpack_buffer), |
| unpack_overlapping_rows_separately_unpack_buffer( |
| workarounds.unpack_overlapping_rows_separately_unpack_buffer), |
| unpack_image_height_workaround_with_unpack_buffer( |
| workarounds.unpack_image_height_workaround_with_unpack_buffer) {} |
| |
| // This indicates all the following texSubImage*D calls that are part of the |
| // failed texImage*D call should be ignored. The client calls have a lock |
| // around them, so it will affect only a single texImage*D + texSubImage*D |
| // group. |
| bool tex_image_failed; |
| |
| // Command buffer stats. |
| int texture_upload_count; |
| base::TimeDelta total_texture_upload_time; |
| |
| bool texsubimage_faster_than_teximage; |
| bool force_cube_map_positive_x_allocation; |
| bool force_cube_complete; |
| bool unpack_alignment_workaround_with_unpack_buffer; |
| bool unpack_overlapping_rows_separately_unpack_buffer; |
| bool unpack_image_height_workaround_with_unpack_buffer; |
| }; |
| |
| // 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 base::trace_event::MemoryDumpProvider { |
| 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, |
| kTexture3D, |
| kTexture2DArray, |
| kCubeMap, |
| kExternalOES, |
| kRectangleARB, |
| kNumDefaultTextures |
| }; |
| |
| TextureManager(MemoryTracker* memory_tracker, |
| FeatureInfo* feature_info, |
| GLsizei max_texture_size, |
| GLsizei max_cube_map_texture_size, |
| GLsizei max_rectangle_texture_size, |
| GLsizei max_3d_texture_size, |
| GLsizei max_array_texture_layers, |
| bool use_default_textures, |
| ProgressReporter* progress_reporter); |
| ~TextureManager() override; |
| |
| void set_framebuffer_manager(FramebufferManager* manager) { |
| framebuffer_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: |
| case GL_TEXTURE_2D_ARRAY: |
| return max_levels_; |
| case GL_TEXTURE_RECTANGLE_ARB: |
| case GL_TEXTURE_EXTERNAL_OES: |
| return 1; |
| case GL_TEXTURE_3D: |
| return max_3d_levels_; |
| 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: |
| case GL_TEXTURE_2D_ARRAY: |
| return max_texture_size_; |
| case GL_TEXTURE_RECTANGLE: |
| return max_rectangle_texture_size_; |
| case GL_TEXTURE_3D: |
| return max_3d_texture_size_; |
| default: |
| return max_cube_map_texture_size_; |
| } |
| } |
| |
| GLsizei max_array_texture_layers() const { |
| return max_array_texture_layers_; |
| } |
| |
| // Returns the maxium number of levels a texture of the given size can have. |
| static GLsizei ComputeMipMapCount(GLenum target, |
| GLsizei width, |
| GLsizei height, |
| GLsizei depth); |
| |
| static GLenum ExtractFormatFromStorageFormat(GLenum internalformat); |
| static GLenum ExtractTypeFromStorageFormat(GLenum internalformat); |
| |
| // 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()); |
| } |
| |
| bool CanRenderWithSampler( |
| const TextureRef* ref, const SamplerState& sampler_state) const { |
| return ref->texture()->CanRenderWithSampler( |
| feature_info_.get(), sampler_state); |
| } |
| |
| // 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 |
| // GL_TEXTURE_2D_ARRAY or GL_TEXTURE_3D (for GLES3) |
| // max_levels: The maximum levels this type of target can have. |
| void SetTarget( |
| TextureRef* ref, |
| GLenum target); |
| |
| // 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, |
| const gfx::Rect& cleared_rect); |
| |
| 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 |rect| of mip as cleared. |
| void SetLevelClearedRect(TextureRef* ref, |
| GLenum target, |
| GLint level, |
| const gfx::Rect& cleared_rect); |
| |
| // 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 SetParameteriv,fv |
| void SetParameteri( |
| const char* function_name, ErrorState* error_state, |
| TextureRef* ref, GLenum pname, GLint param); |
| void SetParameterf( |
| const char* function_name, ErrorState* error_state, |
| TextureRef* ref, GLenum pname, GLfloat param); |
| |
| // Makes each of the mip levels as though they were generated. |
| void 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_3D: |
| return default_textures_[kTexture3D].get(); |
| case GL_TEXTURE_2D_ARRAY: |
| return default_textures_[kTexture2DArray].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 HaveUnsafeTextures() const { |
| return num_unsafe_textures_ > 0; |
| } |
| |
| bool HaveUnclearedMips() const { |
| 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: |
| return black_texture_ids_[kTexture2D]; |
| case GL_SAMPLER_3D: |
| return black_texture_ids_[kTexture3D]; |
| case GL_SAMPLER_2D_ARRAY: |
| return black_texture_ids_[kTexture2DArray]; |
| 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_type_tracker_->GetMemRepresented(); |
| } |
| |
| void SetLevelImage(TextureRef* ref, |
| GLenum target, |
| GLint level, |
| gl::GLImage* image, |
| Texture::ImageState state); |
| |
| void SetLevelStreamTextureImage(TextureRef* ref, |
| GLenum target, |
| GLint level, |
| GLStreamTextureImage* image, |
| Texture::ImageState state, |
| GLuint service_id); |
| |
| void SetLevelImageState(TextureRef* ref, |
| GLenum target, |
| GLint level, |
| Texture::ImageState state); |
| |
| size_t GetSignatureSize() const; |
| |
| void AddToSignature( |
| TextureRef* ref, |
| GLenum target, |
| GLint level, |
| std::string* signature) const; |
| |
| void AddObserver(DestructionObserver* observer) { |
| destruction_observers_.push_back(observer); |
| } |
| |
| void RemoveObserver(DestructionObserver* observer) { |
| for (unsigned int i = 0; i < destruction_observers_.size(); i++) { |
| if (destruction_observers_[i] == observer) { |
| std::swap(destruction_observers_[i], destruction_observers_.back()); |
| destruction_observers_.pop_back(); |
| return; |
| } |
| } |
| NOTREACHED(); |
| } |
| |
| struct DoTexImageArguments { |
| enum TexImageCommandType { |
| kTexImage2D, |
| kTexImage3D, |
| }; |
| |
| GLenum target; |
| GLint level; |
| GLenum internal_format; |
| GLsizei width; |
| GLsizei height; |
| GLsizei depth; |
| GLint border; |
| GLenum format; |
| GLenum type; |
| const void* pixels; |
| uint32_t pixels_size; |
| uint32_t padding; |
| TexImageCommandType command_type; |
| }; |
| |
| bool ValidateTexImage( |
| ContextState* state, |
| const char* function_name, |
| const DoTexImageArguments& args, |
| // Pointer to TextureRef filled in if validation successful. |
| // Presumes the pointer is valid. |
| TextureRef** texture_ref); |
| |
| void ValidateAndDoTexImage( |
| DecoderTextureState* texture_state, |
| ContextState* state, |
| DecoderFramebufferState* framebuffer_state, |
| const char* function_name, |
| const DoTexImageArguments& args); |
| |
| struct DoTexSubImageArguments { |
| enum TexSubImageCommandType { |
| kTexSubImage2D, |
| kTexSubImage3D, |
| }; |
| |
| GLenum target; |
| GLint level; |
| GLint xoffset; |
| GLint yoffset; |
| GLint zoffset; |
| GLsizei width; |
| GLsizei height; |
| GLsizei depth; |
| GLenum format; |
| GLenum type; |
| const void* pixels; |
| uint32_t pixels_size; |
| uint32_t padding; |
| TexSubImageCommandType command_type; |
| }; |
| |
| bool ValidateTexSubImage( |
| ContextState* state, |
| const char* function_name, |
| const DoTexSubImageArguments& args, |
| // Pointer to TextureRef filled in if validation successful. |
| // Presumes the pointer is valid. |
| TextureRef** texture_ref); |
| |
| void ValidateAndDoTexSubImage(GLES2Decoder* decoder, |
| DecoderTextureState* texture_state, |
| ContextState* state, |
| DecoderFramebufferState* framebuffer_state, |
| const char* function_name, |
| const DoTexSubImageArguments& args); |
| |
| // TODO(kloveless): Make GetTexture* private once this is no longer called |
| // from gles2_cmd_decoder. |
| TextureRef* GetTextureInfoForTarget(ContextState* state, GLenum target); |
| TextureRef* GetTextureInfoForTargetUnlessDefault( |
| ContextState* state, GLenum target); |
| |
| // This function is used to validate TexImage2D and TexSubImage2D and their |
| // variants. But internal_format only checked for callers of TexImage2D and |
| // its variants (tex_image_call is true). |
| bool ValidateTextureParameters( |
| ErrorState* error_state, const char* function_name, bool tex_image_call, |
| GLenum format, GLenum type, GLint internal_format, GLint level); |
| |
| // base::trace_event::MemoryDumpProvider implementation. |
| bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, |
| base::trace_event::ProcessMemoryDump* pmd) override; |
| |
| // Returns the union of |rect1| and |rect2| if one of the rectangles is empty, |
| // contains the other rectangle or shares an edge with the other rectangle. |
| // Part of the public interface because texture pixel data rectangle |
| // operations are also implemented in decoder at the moment. |
| static bool CombineAdjacentRects(const gfx::Rect& rect1, |
| const gfx::Rect& rect2, |
| gfx::Rect* result); |
| |
| // Get / set the current generation number of this manager. This generation |
| // number changes whenever the service_id of one or more Textures change. |
| uint32_t GetServiceIdGeneration() const; |
| void IncrementServiceIdGeneration(); |
| |
| static GLenum AdjustTexInternalFormat(const gles2::FeatureInfo* feature_info, |
| GLenum format); |
| static GLenum AdjustTexFormat(const gles2::FeatureInfo* feature_info, |
| GLenum format); |
| |
| void WorkaroundCopyTexImageCubeMap( |
| DecoderTextureState* texture_state, |
| ContextState* state, |
| DecoderFramebufferState* framebuffer_state, |
| TextureRef* texture_ref, |
| const char* function_name, |
| const DoTexImageArguments& args) { |
| DoCubeMapWorkaround(texture_state, state, framebuffer_state, |
| texture_ref, function_name, args); |
| } |
| |
| private: |
| friend class Texture; |
| friend class TextureRef; |
| |
| // Helper for Initialize(). |
| scoped_refptr<TextureRef> CreateDefaultAndBlackTextures( |
| GLenum target, |
| GLuint* black_texture); |
| |
| void DoTexImage( |
| DecoderTextureState* texture_state, |
| ContextState* state, |
| DecoderFramebufferState* framebuffer_state, |
| const char* function_name, |
| TextureRef* texture_ref, |
| const DoTexImageArguments& args); |
| |
| // Reserve memory for the texture and set its attributes so it can be filled |
| // with TexSubImage. The image contents are undefined after this function, |
| // so make sure it's subsequently filled in its entirety. |
| void ReserveTexImageToBeFilled(DecoderTextureState* texture_state, |
| ContextState* state, |
| DecoderFramebufferState* framebuffer_state, |
| const char* function_name, |
| TextureRef* texture_ref, |
| const DoTexImageArguments& args); |
| |
| void DoTexSubImageWithAlignmentWorkaround( |
| DecoderTextureState* texture_state, |
| ContextState* state, |
| const DoTexSubImageArguments& args); |
| |
| void DoTexSubImageRowByRowWorkaround(DecoderTextureState* texture_state, |
| ContextState* state, |
| const DoTexSubImageArguments& args, |
| const PixelStoreParams& unpack_params); |
| |
| void DoTexSubImageLayerByLayerWorkaround( |
| DecoderTextureState* texture_state, |
| ContextState* state, |
| const DoTexSubImageArguments& args, |
| const PixelStoreParams& unpack_params); |
| |
| void DoCubeMapWorkaround( |
| DecoderTextureState* texture_state, |
| ContextState* state, |
| DecoderFramebufferState* framebuffer_state, |
| TextureRef* texture_ref, |
| const char* function_name, |
| const DoTexImageArguments& args); |
| |
| 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 UpdateNumImages(int delta); |
| void IncFramebufferStateChangeCount(); |
| |
| // Helper function called by OnMemoryDump. |
| void DumpTextureRef(base::trace_event::ProcessMemoryDump* pmd, |
| TextureRef* ref); |
| |
| MemoryTypeTracker* GetMemTracker(); |
| std::unique_ptr<MemoryTypeTracker> memory_type_tracker_; |
| MemoryTracker* memory_tracker_; |
| |
| scoped_refptr<FeatureInfo> feature_info_; |
| |
| FramebufferManager* framebuffer_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_; |
| GLsizei max_rectangle_texture_size_; |
| GLsizei max_3d_texture_size_; |
| GLsizei max_array_texture_layers_; |
| GLint max_levels_; |
| GLint max_cube_map_levels_; |
| GLint max_3d_levels_; |
| |
| const bool use_default_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. |
| 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]; |
| |
| std::vector<DestructionObserver*> destruction_observers_; |
| |
| uint32_t current_service_id_generation_; |
| |
| // Used to notify the watchdog thread of progress during destruction, |
| // preventing time-outs when destruction takes a long time. May be null when |
| // using in-process command buffer. |
| ProgressReporter* progress_reporter_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TextureManager); |
| }; |
| |
| // This class records texture upload time when in scope. |
| class ScopedTextureUploadTimer { |
| public: |
| explicit ScopedTextureUploadTimer(DecoderTextureState* texture_state); |
| ~ScopedTextureUploadTimer(); |
| |
| private: |
| DecoderTextureState* texture_state_; |
| base::TimeTicks begin_time_; |
| DISALLOW_COPY_AND_ASSIGN(ScopedTextureUploadTimer); |
| }; |
| |
| } // namespace gles2 |
| } // namespace gpu |
| |
| #endif // GPU_COMMAND_BUFFER_SERVICE_TEXTURE_MANAGER_H_ |