// Copyright 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 CC_RESOURCES_RESOURCE_PROVIDER_H_ #define CC_RESOURCES_RESOURCE_PROVIDER_H_ #include #include #include #include #include #include "base/basictypes.h" #include "base/callback.h" #include "base/containers/hash_tables.h" #include "base/memory/linked_ptr.h" #include "base/memory/scoped_ptr.h" #include "base/threading/thread_checker.h" #include "cc/base/cc_export.h" #include "cc/output/context_provider.h" #include "cc/output/output_surface.h" #include "cc/resources/release_callback.h" #include "cc/resources/resource_format.h" #include "cc/resources/return_callback.h" #include "cc/resources/shared_bitmap.h" #include "cc/resources/single_release_callback.h" #include "cc/resources/texture_mailbox.h" #include "cc/resources/transferable_resource.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" #include "ui/gfx/size.h" class GrContext; namespace gpu { namespace gles { class GLES2Interface; } } namespace gfx { class Rect; class Vector2d; } namespace cc { class IdAllocator; class SharedBitmap; class SharedBitmapManager; class TextureUploader; // This class is not thread-safe and can only be called from the thread it was // created on (in practice, the impl thread). class CC_EXPORT ResourceProvider { public: typedef unsigned ResourceId; typedef std::vector ResourceIdArray; typedef std::set ResourceIdSet; typedef base::hash_map ResourceIdMap; enum TextureUsageHint { TextureUsageAny, TextureUsageFramebuffer, }; enum ResourceType { InvalidType = 0, GLTexture = 1, Bitmap, }; static scoped_ptr Create( OutputSurface* output_surface, SharedBitmapManager* shared_bitmap_manager, int highp_threshold_min, bool use_rgba_4444_texture_format, size_t id_allocation_chunk_size, bool use_distance_field_text); virtual ~ResourceProvider(); void InitializeSoftware(); void InitializeGL(); void DidLoseOutputSurface() { lost_output_surface_ = true; } int max_texture_size() const { return max_texture_size_; } ResourceFormat memory_efficient_texture_format() const { return use_rgba_4444_texture_format_ ? RGBA_4444 : best_texture_format_; } ResourceFormat best_texture_format() const { return best_texture_format_; } bool use_sync_query() const { return use_sync_query_; } size_t num_resources() const { return resources_.size(); } // Checks whether a resource is in use by a consumer. bool InUseByConsumer(ResourceId id); bool IsLost(ResourceId id); bool AllowOverlay(ResourceId id); // Producer interface. ResourceType default_resource_type() const { return default_resource_type_; } ResourceType GetResourceType(ResourceId id); // Creates a resource of the default resource type. ResourceId CreateResource(const gfx::Size& size, GLint wrap_mode, TextureUsageHint hint, ResourceFormat format); // Creates a resource which is tagged as being managed for GPU memory // accounting purposes. ResourceId CreateManagedResource(const gfx::Size& size, GLenum target, GLint wrap_mode, TextureUsageHint hint, ResourceFormat format); // You can also explicitly create a specific resource type. ResourceId CreateGLTexture(const gfx::Size& size, GLenum target, GLenum texture_pool, GLint wrap_mode, TextureUsageHint hint, ResourceFormat format); ResourceId CreateBitmap(const gfx::Size& size, GLint wrap_mode); // Wraps an IOSurface into a GL resource. ResourceId CreateResourceFromIOSurface(const gfx::Size& size, unsigned io_surface_id); // Wraps an external texture mailbox into a GL resource. ResourceId CreateResourceFromTextureMailbox( const TextureMailbox& mailbox, scoped_ptr release_callback); void DeleteResource(ResourceId id); // Update pixels from image, copying source_rect (in image) to dest_offset (in // the resource). void SetPixels(ResourceId id, const uint8_t* image, const gfx::Rect& image_rect, const gfx::Rect& source_rect, const gfx::Vector2d& dest_offset); // Check upload status. size_t NumBlockingUploads(); void MarkPendingUploadsAsNonBlocking(); size_t EstimatedUploadsPerTick(); void FlushUploads(); void ReleaseCachedData(); base::TimeTicks EstimatedUploadCompletionTime(size_t uploads_per_tick); // Flush all context operations, kicking uploads and ensuring ordering with // respect to other contexts. void Flush(); // Finish all context operations, causing any pending callbacks to be // scheduled. void Finish(); // Only flush the command buffer if supported. // Returns true if the shallow flush occurred, false otherwise. bool ShallowFlushIfSupported(); // Creates accounting for a child. Returns a child ID. int CreateChild(const ReturnCallback& return_callback); // Destroys accounting for the child, deleting all accounted resources. void DestroyChild(int child); // Gets the child->parent resource ID map. const ResourceIdMap& GetChildToParentMap(int child) const; // Prepares resources to be transfered to the parent, moving them to // mailboxes and serializing meta-data into TransferableResources. // Resources are not removed from the ResourceProvider, but are marked as // "in use". void PrepareSendToParent(const ResourceIdArray& resources, TransferableResourceArray* transferable_resources); // Receives resources from a child, moving them from mailboxes. Resource IDs // 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_point is set on any TransferableResource, this will // wait on it. void ReceiveFromChild( int child, const TransferableResourceArray& 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 ResourceIdArray& resources_from_child); // Receives resources from the parent, moving them from mailboxes. Resource // IDs passed are in the child namespace. // NOTE: if the sync_point is set on any TransferableResource, this will // wait on it. void ReceiveReturnsFromParent( const ReturnedResourceArray& transferable_resources); // The following lock classes are part of the ResourceProvider API and are // needed to read and write the resource contents. The user must ensure // that they only use GL locks on GL resources, etc, and this is enforced // by assertions. class CC_EXPORT ScopedReadLockGL { public: ScopedReadLockGL(ResourceProvider* resource_provider, ResourceProvider::ResourceId resource_id); virtual ~ScopedReadLockGL(); unsigned texture_id() const { return texture_id_; } protected: ResourceProvider* resource_provider_; ResourceProvider::ResourceId resource_id_; private: unsigned texture_id_; DISALLOW_COPY_AND_ASSIGN(ScopedReadLockGL); }; class CC_EXPORT ScopedSamplerGL : public ScopedReadLockGL { public: ScopedSamplerGL(ResourceProvider* resource_provider, ResourceProvider::ResourceId resource_id, GLenum filter); ScopedSamplerGL(ResourceProvider* resource_provider, ResourceProvider::ResourceId resource_id, GLenum unit, GLenum filter); virtual ~ScopedSamplerGL(); GLenum target() const { return target_; } private: GLenum unit_; GLenum target_; DISALLOW_COPY_AND_ASSIGN(ScopedSamplerGL); }; class CC_EXPORT ScopedWriteLockGL { public: ScopedWriteLockGL(ResourceProvider* resource_provider, ResourceProvider::ResourceId resource_id); ~ScopedWriteLockGL(); unsigned texture_id() const { return texture_id_; } private: ResourceProvider* resource_provider_; ResourceProvider::ResourceId resource_id_; unsigned texture_id_; DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockGL); }; class CC_EXPORT ScopedReadLockSoftware { public: ScopedReadLockSoftware(ResourceProvider* resource_provider, ResourceProvider::ResourceId resource_id); ~ScopedReadLockSoftware(); const SkBitmap* sk_bitmap() const { DCHECK(valid()); return &sk_bitmap_; } GLint wrap_mode() const { return wrap_mode_; } bool valid() const { return !!sk_bitmap_.getPixels(); } private: ResourceProvider* resource_provider_; ResourceProvider::ResourceId resource_id_; SkBitmap sk_bitmap_; GLint wrap_mode_; DISALLOW_COPY_AND_ASSIGN(ScopedReadLockSoftware); }; class CC_EXPORT ScopedWriteLockSoftware { public: ScopedWriteLockSoftware(ResourceProvider* resource_provider, ResourceProvider::ResourceId resource_id); ~ScopedWriteLockSoftware(); SkCanvas* sk_canvas() { return sk_canvas_.get(); } bool valid() const { return !!sk_bitmap_.getPixels(); } private: ResourceProvider* resource_provider_; ResourceProvider::ResourceId resource_id_; SkBitmap sk_bitmap_; scoped_ptr sk_canvas_; DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockSoftware); }; class Fence : public base::RefCounted { public: Fence() {} virtual bool HasPassed() = 0; protected: friend class base::RefCounted; virtual ~Fence() {} private: DISALLOW_COPY_AND_ASSIGN(Fence); }; // Returns a canvas for direct rasterization. // Call Unmap before the resource can be read or used for compositing. // It is used for direct gpu rasterization. SkCanvas* MapDirectRasterBuffer(ResourceId id); void UnmapDirectRasterBuffer(ResourceId id); // Returns a canvas backed by an image buffer. UnmapImageRasterBuffer // returns true if canvas was written to while mapped. // Rasterizing to the canvas writes the content into the image buffer, // which is internally bound to the underlying resource when read. // Call Unmap before the resource can be read or used for compositing. // It is used by ImageRasterWorkerPool. SkCanvas* MapImageRasterBuffer(ResourceId id); bool UnmapImageRasterBuffer(ResourceId id); // Returns a canvas backed by pixel buffer. UnmapPixelRasterBuffer // returns true if canvas was written to while mapped. // The pixel buffer needs to be uploaded to the underlying resource // using BeginSetPixels before the resouce can be used for compositing. // It is used by PixelRasterWorkerPool. void AcquirePixelRasterBuffer(ResourceId id); void ReleasePixelRasterBuffer(ResourceId id); SkCanvas* MapPixelRasterBuffer(ResourceId id); bool UnmapPixelRasterBuffer(ResourceId id); // Asynchronously update pixels from acquired pixel buffer. void BeginSetPixels(ResourceId id); void ForceSetPixelsToComplete(ResourceId id); bool DidSetPixelsComplete(ResourceId id); // For tests only! This prevents detecting uninitialized reads. // Use SetPixels or LockForWrite to allocate implicitly. void AllocateForTesting(ResourceId id); // For tests only! void CreateForTesting(ResourceId id); GLenum TargetForTesting(ResourceId id); // 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(Fence* fence) { current_read_lock_fence_ = fence; } // Enable read lock fences for a specific resource. void EnableReadLockFences(ResourceProvider::ResourceId id, bool enable); // Indicates if we can currently lock this resource for write. bool CanLockForWrite(ResourceId id); // Copy pixels from source to destination. void CopyResource(ResourceId source_id, ResourceId dest_id); static GLint GetActiveTextureUnit(gpu::gles2::GLES2Interface* gl); private: class DirectRasterBuffer; class ImageRasterBuffer; class PixelRasterBuffer; struct Resource { enum Origin { Internal, External, Delegated }; Resource(); ~Resource(); Resource(unsigned texture_id, const gfx::Size& size, Origin origin, GLenum target, GLenum filter, GLenum texture_pool, GLint wrap_mode, TextureUsageHint hint, ResourceFormat format); Resource(uint8_t* pixels, SharedBitmap* bitmap, const gfx::Size& size, Origin origin, GLenum filter, GLint wrap_mode); Resource(const SharedBitmapId& bitmap_id, const gfx::Size& size, Origin origin, GLenum filter, GLint wrap_mode); int child_id; unsigned gl_id; // Pixel buffer used for set pixels without unnecessary copying. unsigned gl_pixel_buffer_id; // Query used to determine when asynchronous set pixels complete. unsigned gl_upload_query_id; // Query used to determine when read lock fence has passed. unsigned gl_read_lock_query_id; TextureMailbox mailbox; ReleaseCallback release_callback; uint8_t* pixels; int lock_for_read_count; int imported_count; int exported_count; bool dirty_image : 1; bool locked_for_write : 1; bool lost : 1; bool marked_for_deletion : 1; bool pending_set_pixels : 1; bool set_pixels_completion_forced : 1; bool allocated : 1; bool enable_read_lock_fences : 1; bool has_shared_bitmap_id : 1; bool allow_overlay : 1; scoped_refptr read_lock_fence; gfx::Size size; Origin origin; GLenum target; // TODO(skyostil): Use a separate sampler object for filter state. GLenum original_filter; GLenum filter; unsigned image_id; unsigned bound_image_id; GLenum texture_pool; GLint wrap_mode; TextureUsageHint hint; ResourceType type; ResourceFormat format; SharedBitmapId shared_bitmap_id; SharedBitmap* shared_bitmap; linked_ptr direct_raster_buffer; linked_ptr image_raster_buffer; linked_ptr pixel_raster_buffer; }; typedef base::hash_map ResourceMap; class RasterBuffer { public: virtual ~RasterBuffer(); SkCanvas* LockForWrite(); // Returns true if canvas was written to while locked. bool UnlockForWrite(); protected: RasterBuffer(const Resource* resource, ResourceProvider* resource_provider); const Resource* resource() const { return resource_; } ResourceProvider* resource_provider() const { return resource_provider_; } virtual SkCanvas* DoLockForWrite() = 0; virtual bool DoUnlockForWrite() = 0; private: const Resource* resource_; ResourceProvider* resource_provider_; SkCanvas* locked_canvas_; int canvas_save_count_; }; class DirectRasterBuffer : public RasterBuffer { public: DirectRasterBuffer(const Resource* resource, ResourceProvider* resource_provider, bool use_distance_field_text); virtual ~DirectRasterBuffer(); protected: virtual SkCanvas* DoLockForWrite() OVERRIDE; virtual bool DoUnlockForWrite() OVERRIDE; skia::RefPtr CreateSurface(); private: skia::RefPtr surface_; uint32_t surface_generation_id_; const bool use_distance_field_text_; DISALLOW_COPY_AND_ASSIGN(DirectRasterBuffer); }; class BitmapRasterBuffer : public RasterBuffer { public: virtual ~BitmapRasterBuffer(); protected: BitmapRasterBuffer(const Resource* resource, ResourceProvider* resource_provider); virtual SkCanvas* DoLockForWrite() OVERRIDE; virtual bool DoUnlockForWrite() OVERRIDE; virtual uint8_t* MapBuffer(int* stride) = 0; virtual void UnmapBuffer() = 0; private: uint8_t* mapped_buffer_; SkBitmap raster_bitmap_; uint32_t raster_bitmap_generation_id_; skia::RefPtr raster_canvas_; }; class ImageRasterBuffer : public BitmapRasterBuffer { public: ImageRasterBuffer(const Resource* resource, ResourceProvider* resource_provider); virtual ~ImageRasterBuffer(); protected: virtual uint8_t* MapBuffer(int* stride) OVERRIDE; virtual void UnmapBuffer() OVERRIDE; private: DISALLOW_COPY_AND_ASSIGN(ImageRasterBuffer); }; class PixelRasterBuffer : public BitmapRasterBuffer { public: PixelRasterBuffer(const Resource* resource, ResourceProvider* resource_provider); virtual ~PixelRasterBuffer(); protected: virtual uint8_t* MapBuffer(int* stride) OVERRIDE; virtual void UnmapBuffer() OVERRIDE; private: DISALLOW_COPY_AND_ASSIGN(PixelRasterBuffer); }; static bool CompareResourceMapIteratorsByChildId( const std::pair& a, const std::pair& b); struct Child { Child(); ~Child(); ResourceIdMap child_to_parent_map; ResourceIdMap parent_to_child_map; ReturnCallback return_callback; ResourceIdSet in_use_resources; bool marked_for_deletion; }; typedef base::hash_map ChildMap; bool ReadLockFenceHasPassed(const Resource* resource) { return !resource->read_lock_fence.get() || resource->read_lock_fence->HasPassed(); } ResourceProvider(OutputSurface* output_surface, SharedBitmapManager* shared_bitmap_manager, int highp_threshold_min, bool use_rgba_4444_texture_format, size_t id_allocation_chunk_size, bool use_distance_field_text); void CleanUpGLIfNeeded(); Resource* GetResource(ResourceId id); const Resource* LockForRead(ResourceId id); void UnlockForRead(ResourceId id); const Resource* LockForWrite(ResourceId id); void UnlockForWrite(ResourceId id); static void PopulateSkBitmapWithResource(SkBitmap* sk_bitmap, const Resource* resource); void TransferResource(gpu::gles2::GLES2Interface* gl, ResourceId id, TransferableResource* resource); enum DeleteStyle { Normal, ForShutdown, }; void DeleteResourceInternal(ResourceMap::iterator it, DeleteStyle style); void DeleteAndReturnUnusedResourcesToChild(ChildMap::iterator child_it, DeleteStyle style, const ResourceIdArray& unused); void DestroyChildInternal(ChildMap::iterator it, DeleteStyle style); void LazyCreate(Resource* resource); void LazyAllocate(Resource* resource); // TODO(alokp): Move the implementation to PixelRasterBuffer. // Acquire pixel buffer for resource. The pixel buffer can be used to // set resource pixels without performing unnecessary copying. void AcquirePixelBuffer(Resource* resource); void ReleasePixelBuffer(Resource* resource); // Map/unmap the acquired pixel buffer. uint8_t* MapPixelBuffer(const Resource* resource, int* stride); void UnmapPixelBuffer(const Resource* resource); // TODO(alokp): Move the implementation to ImageRasterBuffer. // Acquire and release an image. The image allows direct // manipulation of texture memory. void AcquireImage(Resource* resource); void ReleaseImage(Resource* resource); // Maps the acquired image so that its pixels could be modified. // Unmap is called when all pixels are set. uint8_t* MapImage(const Resource* resource, int* stride); void UnmapImage(const Resource* resource); void BindImageForSampling(Resource* resource); // 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(ResourceProvider::ResourceId resource_id, GLenum unit, GLenum filter); // Returns NULL if the output_surface_ does not have a ContextProvider. gpu::gles2::GLES2Interface* ContextGL() const; class GrContext* GrContext() const; OutputSurface* output_surface_; SharedBitmapManager* shared_bitmap_manager_; bool lost_output_surface_; int highp_threshold_min_; ResourceId next_id_; ResourceMap resources_; int next_child_; ChildMap children_; ResourceType default_resource_type_; bool use_texture_storage_ext_; bool use_texture_usage_hint_; bool use_compressed_texture_etc1_; scoped_ptr texture_uploader_; int max_texture_size_; ResourceFormat best_texture_format_; base::ThreadChecker thread_checker_; scoped_refptr current_read_lock_fence_; bool use_rgba_4444_texture_format_; const size_t id_allocation_chunk_size_; scoped_ptr texture_id_allocator_; scoped_ptr buffer_id_allocator_; bool use_sync_query_; bool use_distance_field_text_; DISALLOW_COPY_AND_ASSIGN(ResourceProvider); }; // TODO(epenner): Move these format conversions to resource_format.h // once that builds on mac (npapi.h currently #includes OpenGL.h). inline unsigned BitsPerPixel(ResourceFormat format) { DCHECK_LE(format, RESOURCE_FORMAT_MAX); static const unsigned format_bits_per_pixel[RESOURCE_FORMAT_MAX + 1] = { 32, // RGBA_8888 16, // RGBA_4444 32, // BGRA_8888 8, // LUMINANCE_8 16, // RGB_565, 4 // ETC1 }; return format_bits_per_pixel[format]; } inline GLenum GLDataType(ResourceFormat format) { DCHECK_LE(format, RESOURCE_FORMAT_MAX); static const unsigned format_gl_data_type[RESOURCE_FORMAT_MAX + 1] = { GL_UNSIGNED_BYTE, // RGBA_8888 GL_UNSIGNED_SHORT_4_4_4_4, // RGBA_4444 GL_UNSIGNED_BYTE, // BGRA_8888 GL_UNSIGNED_BYTE, // LUMINANCE_8 GL_UNSIGNED_SHORT_5_6_5, // RGB_565, GL_UNSIGNED_BYTE // ETC1 }; return format_gl_data_type[format]; } inline GLenum GLDataFormat(ResourceFormat format) { DCHECK_LE(format, RESOURCE_FORMAT_MAX); static const unsigned format_gl_data_format[RESOURCE_FORMAT_MAX + 1] = { GL_RGBA, // RGBA_8888 GL_RGBA, // RGBA_4444 GL_BGRA_EXT, // BGRA_8888 GL_LUMINANCE, // LUMINANCE_8 GL_RGB, // RGB_565 GL_ETC1_RGB8_OES // ETC1 }; return format_gl_data_format[format]; } inline GLenum GLInternalFormat(ResourceFormat format) { return GLDataFormat(format); } } // namespace cc #endif // CC_RESOURCES_RESOURCE_PROVIDER_H_