| // Copyright 2017 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 COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_H_ |
| #define COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_H_ |
| |
| #include <stddef.h> |
| #include <map> |
| #include <unordered_map> |
| #include <vector> |
| |
| #include "base/containers/flat_map.h" |
| #include "base/containers/small_map.h" |
| #include "base/macros.h" |
| #include "base/threading/thread_checker.h" |
| #include "base/trace_event/memory_dump_provider.h" |
| #include "build/build_config.h" |
| #include "components/viz/common/resources/resource_id.h" |
| #include "components/viz/common/resources/return_callback.h" |
| #include "components/viz/common/resources/shared_bitmap.h" |
| #include "components/viz/common/resources/transferable_resource.h" |
| #include "components/viz/service/display/external_use_client.h" |
| #include "components/viz/service/display/overlay_candidate.h" |
| #include "components/viz/service/display/resource_fence.h" |
| #include "components/viz/service/display/resource_metadata.h" |
| #include "components/viz/service/viz_service_export.h" |
| #include "gpu/command_buffer/common/sync_token.h" |
| #include "third_party/khronos/GLES2/gl2.h" |
| #include "third_party/khronos/GLES2/gl2ext.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace gfx { |
| class ColorSpace; |
| } // namespace gfx |
| |
| namespace gpu { |
| namespace gles2 { |
| class GLES2Interface; |
| } |
| } // namespace gpu |
| |
| namespace viz { |
| |
| class ContextProvider; |
| class SharedBitmapManager; |
| |
| // This class provides abstractions for receiving and using resources from other |
| // modules/threads/processes. It abstracts away GL textures vs GpuMemoryBuffers |
| // vs software bitmaps behind a single ResourceId so that code in common can |
| // hold onto ResourceIds, as long as the code using them knows the correct type. |
| // It accepts as input TransferableResources which it holds internally, tracks |
| // state on, and exposes as a ResourceId. |
| // |
| // The resource's underlying type is accessed through locks that help to |
| // scope and safeguard correct usage with DCHECKs. |
| // |
| // This class is not thread-safe and can only be called from the thread it was |
| // created on. |
| class VIZ_SERVICE_EXPORT DisplayResourceProvider |
| : public base::trace_event::MemoryDumpProvider { |
| public: |
| enum Mode { |
| kGpu, |
| kSoftware, |
| }; |
| // TODO(cblume, crbug.com/900973): |enable_shared_images| is a temporary |
| // solution that unblocks us until SharedImages are threadsafe in WebView. |
| DisplayResourceProvider(Mode mode, |
| ContextProvider* compositor_context_provider, |
| SharedBitmapManager* shared_bitmap_manager, |
| bool enable_shared_images = true); |
| ~DisplayResourceProvider() override; |
| |
| bool IsSoftware() const { return mode_ == kSoftware; } |
| void DidLoseContextProvider() { lost_context_provider_ = true; } |
| size_t num_resources() const { return resources_.size(); } |
| |
| // base::trace_event::MemoryDumpProvider implementation. |
| bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, |
| base::trace_event::ProcessMemoryDump* pmd) override; |
| |
| #if defined(OS_ANDROID) |
| // Send an overlay promotion hint to all resources that requested it via |
| // |requestor_set|. |promotable_hints| contains all the resources that should |
| // be told that they're promotable. Others will be told that they're not. |
| // |
| // We don't use |wants_promotion_hints_set_| in place of |requestor_set|, |
| // since we might have resources that aren't used for drawing. Sending a hint |
| // for a resource that wasn't even considered for overlay would be misleading |
| // to the requestor; the resource might be overlayable except that nobody |
| // tried to do it. |
| void SendPromotionHints( |
| const OverlayCandidateList::PromotionHintInfoMap& promotion_hints, |
| const ResourceIdSet& requestor_set); |
| |
| // Indicates if this resource is backed by an Android SurfaceTexture, and thus |
| // can't really be promoted to an overlay. |
| bool IsBackedBySurfaceTexture(ResourceId id); |
| |
| // Return the number of resources that request promotion hints. |
| size_t CountPromotionHintRequestsForTesting(); |
| #endif |
| |
| // Indicates if this resource wants to receive promotion hints. |
| bool DoesResourceWantPromotionHint(ResourceId id) const; |
| |
| // Return true if and only if any resource wants a promotion hint. |
| bool DoAnyResourcesWantPromotionHints() const; |
| |
| bool IsResourceSoftwareBacked(ResourceId id); |
| GLenum GetResourceTextureTarget(ResourceId id); |
| // Return the format of the underlying buffer that can be used for scanout. |
| gfx::BufferFormat GetBufferFormat(ResourceId id); |
| const gfx::ColorSpace& GetColorSpace(ResourceId id); |
| // Indicates if this resource may be used for a hardware overlay plane. |
| bool IsOverlayCandidate(ResourceId id); |
| |
| void WaitSyncToken(ResourceId id); |
| |
| // Checks whether a resource is in use. |
| bool InUse(ResourceId id); |
| |
| // The following lock classes are part of the DisplayResourceProvider API and |
| // are needed to read the resource contents. The user must ensure that they |
| // only use GL locks on GL resources, etc, and this is enforced by assertions. |
| class VIZ_SERVICE_EXPORT ScopedReadLockGL { |
| public: |
| ScopedReadLockGL(DisplayResourceProvider* resource_provider, |
| ResourceId resource_id); |
| ~ScopedReadLockGL(); |
| |
| GLuint texture_id() const { return texture_id_; } |
| GLenum target() const { return target_; } |
| const gfx::Size& size() const { return size_; } |
| const gfx::ColorSpace& color_space() const { return color_space_; } |
| |
| private: |
| DisplayResourceProvider* const resource_provider_; |
| const ResourceId resource_id_; |
| |
| GLuint texture_id_ = 0; |
| GLenum target_ = GL_TEXTURE_2D; |
| gfx::Size size_; |
| gfx::ColorSpace color_space_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScopedReadLockGL); |
| }; |
| |
| class VIZ_SERVICE_EXPORT ScopedSamplerGL { |
| public: |
| ScopedSamplerGL(DisplayResourceProvider* resource_provider, |
| ResourceId resource_id, |
| GLenum filter); |
| ScopedSamplerGL(DisplayResourceProvider* resource_provider, |
| ResourceId resource_id, |
| GLenum unit, |
| GLenum filter); |
| ~ScopedSamplerGL(); |
| |
| GLuint texture_id() const { return resource_lock_.texture_id(); } |
| GLenum target() const { return target_; } |
| const gfx::ColorSpace& color_space() const { |
| return resource_lock_.color_space(); |
| } |
| |
| private: |
| const ScopedReadLockGL resource_lock_; |
| const GLenum unit_; |
| const GLenum target_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScopedSamplerGL); |
| }; |
| |
| class VIZ_SERVICE_EXPORT ScopedReadLockSkImage { |
| public: |
| ScopedReadLockSkImage(DisplayResourceProvider* resource_provider, |
| ResourceId resource_id, |
| SkAlphaType alpha_type = kPremul_SkAlphaType, |
| GrSurfaceOrigin origin = kTopLeft_GrSurfaceOrigin); |
| ~ScopedReadLockSkImage(); |
| |
| const SkImage* sk_image() const { return sk_image_.get(); } |
| |
| bool valid() const { return !!sk_image_; } |
| |
| private: |
| DisplayResourceProvider* const resource_provider_; |
| const ResourceId resource_id_; |
| sk_sp<SkImage> sk_image_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScopedReadLockSkImage); |
| }; |
| |
| // Maintains set of resources locked for external use by SkiaRenderer. |
| class VIZ_SERVICE_EXPORT LockSetForExternalUse { |
| public: |
| // There should be at most one instance of this class per |
| // |resource_provider|. Both |resource_provider| and |client| outlive this |
| // class. |
| LockSetForExternalUse(DisplayResourceProvider* resource_provider, |
| ExternalUseClient* client); |
| ~LockSetForExternalUse(); |
| |
| // Lock a resource for external use. |
| ResourceMetadata LockResource(ResourceId resource_id); |
| |
| // Unlock all locked resources with a |sync_token|. |
| // See UnlockForExternalUse for the detail. All resources must be unlocked |
| // before destroying this class. |
| void UnlockResources(const gpu::SyncToken& sync_token); |
| |
| private: |
| DisplayResourceProvider* const resource_provider_; |
| std::vector<ResourceId> resources_; |
| |
| DISALLOW_COPY_AND_ASSIGN(LockSetForExternalUse); |
| }; |
| |
| // All resources that are returned to children while an instance of this |
| // class exists will be stored and returned when the instance is destroyed. |
| class VIZ_SERVICE_EXPORT ScopedBatchReturnResources { |
| public: |
| explicit ScopedBatchReturnResources( |
| DisplayResourceProvider* resource_provider); |
| ~ScopedBatchReturnResources(); |
| |
| private: |
| DisplayResourceProvider* const resource_provider_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScopedBatchReturnResources); |
| }; |
| |
| class VIZ_SERVICE_EXPORT SynchronousFence : public ResourceFence { |
| public: |
| explicit SynchronousFence(gpu::gles2::GLES2Interface* gl); |
| |
| // ResourceFence implementation. |
| void Set() override; |
| bool HasPassed() override; |
| |
| // Returns true if fence has been set but not yet synchornized. |
| bool has_synchronized() const { return has_synchronized_; } |
| |
| private: |
| ~SynchronousFence() override; |
| |
| void Synchronize(); |
| |
| gpu::gles2::GLES2Interface* gl_; |
| bool has_synchronized_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SynchronousFence); |
| }; |
| |
| // Sets the current read fence. If a resource is locked for read |
| // and has read fences enabled, the resource will not allow writes |
| // until this fence has passed. |
| void SetReadLockFence(ResourceFence* fence) { |
| current_read_lock_fence_ = fence; |
| } |
| |
| // Creates accounting for a child. Returns a child ID. |needs_sync_tokens| |
| // sets whether resources need sync points set on them when returned to this |
| // child. |
| int CreateChild(const ReturnCallback& return_callback, |
| bool needs_sync_tokens); |
| |
| // Destroys accounting for the child, deleting all accounted resources. |
| void DestroyChild(int child); |
| |
| // Gets the child->parent resource ID map. |
| const std::unordered_map<ResourceId, ResourceId>& GetChildToParentMap( |
| int child) const; |
| |
| // Receives resources from a child, moving them from mailboxes. ResourceIds |
| // passed are in the child namespace, and will be translated to the parent |
| // namespace, added to the child->parent map. |
| // This adds the resources to the working set in the ResourceProvider without |
| // declaring which resources are in use. Use DeclareUsedResourcesFromChild |
| // after calling this method to do that. All calls to ReceiveFromChild should |
| // be followed by a DeclareUsedResourcesFromChild. |
| // NOTE: if the sync_token is set on any TransferableResource, this will |
| // wait on it. |
| void ReceiveFromChild( |
| int child, |
| const std::vector<TransferableResource>& transferable_resources); |
| |
| // Once a set of resources have been received, they may or may not be used. |
| // This declares what set of resources are currently in use from the child, |
| // releasing any other resources back to the child. |
| void DeclareUsedResourcesFromChild(int child, |
| const ResourceIdSet& resources_from_child); |
| |
| private: |
| enum DeleteStyle { |
| NORMAL, |
| FOR_SHUTDOWN, |
| }; |
| |
| enum SynchronizationState { |
| // The LOCALLY_USED state is the state each resource defaults to when |
| // constructed or modified or read. This state indicates that the |
| // resource has not been properly synchronized and it would be an error |
| // to return this resource to a client. |
| LOCALLY_USED, |
| |
| // The NEEDS_WAIT state is the state that indicates a resource has been |
| // modified but it also has an associated sync token assigned to it. |
| // The sync token has not been waited on with the local context. When |
| // a sync token arrives from a client, it is automatically initialized as |
| // NEEDS_WAIT as well since we still need to wait on it before the resource |
| // is synchronized on the current context. It is an error to use the |
| // resource locally for reading or writing if the resource is in this state. |
| NEEDS_WAIT, |
| |
| // The SYNCHRONIZED state indicates that the resource has been properly |
| // synchronized locally. This can either synchronized externally (such |
| // as the case of software rasterized bitmaps), or synchronized |
| // internally using a sync token that has been waited upon. In the |
| // former case where the resource was synchronized externally, a |
| // corresponding sync token will not exist. In the latter case which was |
| // synchronized from the NEEDS_WAIT state, a corresponding sync token will |
| // exist which is associated with the resource. This sync token is still |
| // valid and still associated with the resource and can be passed as an |
| // external resource for others to wait on. |
| SYNCHRONIZED, |
| }; |
| |
| struct Child { |
| Child(); |
| Child(const Child& other); |
| ~Child(); |
| |
| std::unordered_map<ResourceId, ResourceId> child_to_parent_map; |
| ReturnCallback return_callback; |
| bool marked_for_deletion = false; |
| bool needs_sync_tokens = true; |
| }; |
| |
| // The data structure used to track state of Gpu and Software-based |
| // resources and the service, for resources transferred |
| // between the two. This is an implementation detail of the resource tracking |
| // for client and service libraries and should not be used directly from |
| // external client code. |
| struct ChildResource { |
| ChildResource(int child_id, const TransferableResource& transferable); |
| ChildResource(ChildResource&& other); |
| ~ChildResource(); |
| |
| bool is_gpu_resource_type() const { return !transferable.is_software; } |
| bool needs_sync_token() const { |
| return is_gpu_resource_type() && synchronization_state_ == LOCALLY_USED; |
| } |
| const gpu::SyncToken& sync_token() const { return sync_token_; } |
| SynchronizationState synchronization_state() const { |
| return synchronization_state_; |
| } |
| // If true the gpu resource needs its SyncToken waited on in order to be |
| // synchronized for use. |
| bool ShouldWaitSyncToken() const { |
| return synchronization_state_ == NEEDS_WAIT; |
| } |
| |
| void SetLocallyUsed(); |
| void SetSynchronized(); |
| void UpdateSyncToken(const gpu::SyncToken& sync_token); |
| |
| // This is the id of the client the resource comes from. |
| const int child_id; |
| // Data received from the client that describes the resource fully. |
| const TransferableResource transferable; |
| |
| // The number of times the resource has been received from a client. It must |
| // have this many number of references returned back to the client in order |
| // for it to know it is no longer in use in the service. This is used to |
| // avoid races where a resource is in flight to the service while also being |
| // returned to the client. It starts with an initial count of 1, for the |
| // first time the resource is received. |
| int imported_count = 1; |
| |
| // The number of active users of a resource in the display compositor. While |
| // a resource is in use, it will not be returned back to the client even if |
| // the ResourceId is deleted. |
| int lock_for_read_count = 0; |
| // When true, the resource is currently being used externally. This is a |
| // parallel counter to |lock_for_read_count| which can only go to 1. |
| bool locked_for_external_use = false; |
| |
| // When the resource should be deleted until it is actually reaped. |
| bool marked_for_deletion = false; |
| |
| // Texture id for texture-backed resources, when the mailbox is mapped into |
| // a client GL id in this process. |
| GLuint gl_id = 0; |
| // The current min/mag filter for GL texture-backed resources. The original |
| // filter as given from the client is saved in |transferable|. |
| GLenum filter; |
| // A pointer to the shared memory structure for software-backed resources, |
| // when it is mapped into memory in this process. |
| std::unique_ptr<SharedBitmap> shared_bitmap; |
| // A GUID for reporting the |shared_bitmap| to memory tracing. The GUID is |
| // known by other components in the system as well to give the same id for |
| // this shared memory bitmap everywhere. This is empty until the resource is |
| // mapped for use in the display compositor. |
| base::UnguessableToken shared_bitmap_tracing_guid; |
| |
| // A fence used for accessing a gpu resource for reading, that ensures any |
| // writing done to the resource has been completed. This is implemented and |
| // used to implement transferring ownership of the resource from the client |
| // to the service, and in the GL drawing code before reading from the |
| // texture. |
| scoped_refptr<ResourceFence> read_lock_fence; |
| |
| private: |
| // Tracks if a sync token needs to be waited on before using the resource. |
| SynchronizationState synchronization_state_; |
| // A SyncToken associated with a texture-backed or GpuMemoryBuffer-backed |
| // resource. It is given from a child to the service, and waited on in order |
| // to use the resource, and this is tracked by the |synchronization_state_|. |
| gpu::SyncToken sync_token_; |
| }; |
| |
| using ChildMap = std::unordered_map<int, Child>; |
| using ResourceMap = std::unordered_map<ResourceId, ChildResource>; |
| |
| ChildResource* InsertResource(ResourceId id, ChildResource resource); |
| ChildResource* GetResource(ResourceId id); |
| |
| // TODO(ericrk): TryGetResource is part of a temporary workaround for cases |
| // where resources which should be available are missing. This version may |
| // return nullptr if a resource is not found. https://crbug.com/811858 |
| ChildResource* TryGetResource(ResourceId id); |
| |
| void PopulateSkBitmapWithResource(SkBitmap* sk_bitmap, |
| const ChildResource* resource); |
| |
| void DeleteResourceInternal(ResourceMap::iterator it, DeleteStyle style); |
| |
| void WaitSyncTokenInternal(ChildResource* resource); |
| |
| // Returns null if we do not have a ContextProvider. |
| gpu::gles2::GLES2Interface* ContextGL() const; |
| |
| const ChildResource* LockForRead(ResourceId id); |
| void UnlockForRead(ResourceId id); |
| |
| // Lock a resource for external use. |
| ResourceMetadata LockForExternalUse(ResourceId id); |
| |
| // Unlock a resource which locked by LockForExternalUse. |
| // The |sync_token| should be waited on before reusing the resouce's backing |
| // to ensure that any external use of it is completed. This |sync_token| |
| // should have been verified. |
| void UnlockForExternalUse(ResourceId id, const gpu::SyncToken& sync_token); |
| |
| void TryReleaseResource(ResourceMap::iterator it); |
| // Binds the given GL resource to a texture target for sampling using the |
| // specified filter for both minification and magnification. Returns the |
| // texture target used. The resource must be locked for reading. |
| GLenum BindForSampling(ResourceId resource_id, GLenum unit, GLenum filter); |
| bool ReadLockFenceHasPassed(const ChildResource* resource); |
| #if defined(OS_ANDROID) |
| void DeletePromotionHint(ResourceMap::iterator it, DeleteStyle style); |
| #endif |
| |
| void DeleteAndReturnUnusedResourcesToChild( |
| ChildMap::iterator child_it, |
| DeleteStyle style, |
| const std::vector<ResourceId>& unused); |
| void DestroyChildInternal(ChildMap::iterator it, DeleteStyle style); |
| |
| void SetBatchReturnResources(bool aggregate); |
| |
| THREAD_CHECKER(thread_checker_); |
| const Mode mode_; |
| ContextProvider* const compositor_context_provider_; |
| SharedBitmapManager* const shared_bitmap_manager_; |
| |
| ResourceMap resources_; |
| ChildMap children_; |
| base::flat_map<ResourceId, sk_sp<SkImage>> resource_sk_images_; |
| // Used to release resources held by an external consumer. |
| ExternalUseClient* external_use_client_ = nullptr; |
| |
| base::flat_map<int, std::vector<ResourceId>> batched_returning_resources_; |
| scoped_refptr<ResourceFence> current_read_lock_fence_; |
| // Keep track of whether deleted resources should be batched up or returned |
| // immediately. |
| int batch_return_resources_lock_count_ = 0; |
| // Set to true when the ContextProvider becomes lost, to inform that resources |
| // modified by this class are now in an indeterminate state. |
| bool lost_context_provider_ = false; |
| // The ResourceIds in DisplayResourceProvider start from 2 to avoid |
| // conflicts with id from ClientResourceProvider. |
| ResourceId next_id_ = 2; |
| // Used as child id when creating a child. |
| int next_child_ = 1; |
| // A process-unique ID used for disambiguating memory dumps from different |
| // resource providers. |
| int tracing_id_; |
| |
| #if defined(OS_ANDROID) |
| // Set of ResourceIds that would like to be notified about promotion hints. |
| ResourceIdSet wants_promotion_hints_set_; |
| #endif |
| |
| bool enable_shared_images_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DisplayResourceProvider); |
| }; |
| |
| } // namespace viz |
| |
| #endif // COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_H_ |