1// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CC_RESOURCES_RESOURCE_PROVIDER_H_
6#define CC_RESOURCES_RESOURCE_PROVIDER_H_
7
8#include <deque>
9#include <set>
10#include <string>
11#include <utility>
12#include <vector>
13
14#include "base/basictypes.h"
15#include "base/callback.h"
16#include "base/containers/hash_tables.h"
17#include "base/memory/scoped_ptr.h"
18#include "base/threading/thread_checker.h"
19#include "cc/base/cc_export.h"
20#include "cc/output/context_provider.h"
21#include "cc/output/output_surface.h"
22#include "cc/resources/release_callback.h"
23#include "cc/resources/resource_format.h"
24#include "cc/resources/return_callback.h"
25#include "cc/resources/single_release_callback.h"
26#include "cc/resources/texture_mailbox.h"
27#include "cc/resources/transferable_resource.h"
28#include "third_party/khronos/GLES2/gl2.h"
29#include "third_party/khronos/GLES2/gl2ext.h"
30#include "third_party/skia/include/core/SkBitmap.h"
31#include "third_party/skia/include/core/SkCanvas.h"
32#include "ui/gfx/size.h"
33
34namespace gpu {
35namespace gles {
36class GLES2Interface;
37}
38}
39
40namespace gfx {
41class Rect;
42class Vector2d;
43}
44
45namespace cc {
46class IdAllocator;
47class SharedBitmap;
48class SharedBitmapManager;
49class TextureUploader;
50
51// This class is not thread-safe and can only be called from the thread it was
52// created on (in practice, the impl thread).
53class CC_EXPORT ResourceProvider {
54 public:
55  typedef unsigned ResourceId;
56  typedef std::vector<ResourceId> ResourceIdArray;
57  typedef std::set<ResourceId> ResourceIdSet;
58  typedef base::hash_map<ResourceId, ResourceId> ResourceIdMap;
59  enum TextureUsageHint {
60    TextureUsageAny,
61    TextureUsageFramebuffer,
62  };
63  enum ResourceType {
64    InvalidType = 0,
65    GLTexture = 1,
66    Bitmap,
67  };
68
69  static scoped_ptr<ResourceProvider> Create(
70      OutputSurface* output_surface,
71      SharedBitmapManager* shared_bitmap_manager,
72      int highp_threshold_min,
73      bool use_rgba_4444_texture_format,
74      size_t id_allocation_chunk_size);
75  virtual ~ResourceProvider();
76
77  void InitializeSoftware();
78  bool InitializeGL();
79
80  void DidLoseOutputSurface() { lost_output_surface_ = true; }
81
82  int max_texture_size() const { return max_texture_size_; }
83  ResourceFormat memory_efficient_texture_format() const {
84    return use_rgba_4444_texture_format_ ? RGBA_4444 : best_texture_format_;
85  }
86  ResourceFormat best_texture_format() const { return best_texture_format_; }
87  size_t num_resources() const { return resources_.size(); }
88
89  // Checks whether a resource is in use by a consumer.
90  bool InUseByConsumer(ResourceId id);
91
92  bool IsLost(ResourceId id);
93
94  // Producer interface.
95
96  ResourceType default_resource_type() const { return default_resource_type_; }
97  ResourceType GetResourceType(ResourceId id);
98
99  // Creates a resource of the default resource type.
100  ResourceId CreateResource(gfx::Size size,
101                            GLint wrap_mode,
102                            TextureUsageHint hint,
103                            ResourceFormat format);
104
105  // Creates a resource which is tagged as being managed for GPU memory
106  // accounting purposes.
107  ResourceId CreateManagedResource(gfx::Size size,
108                                   GLenum target,
109                                   GLint wrap_mode,
110                                   TextureUsageHint hint,
111                                   ResourceFormat format);
112
113  // You can also explicitly create a specific resource type.
114  ResourceId CreateGLTexture(gfx::Size size,
115                             GLenum target,
116                             GLenum texture_pool,
117                             GLint wrap_mode,
118                             TextureUsageHint hint,
119                             ResourceFormat format);
120
121  ResourceId CreateBitmap(gfx::Size size, GLint wrap_mode);
122  // Wraps an external texture into a GL resource.
123  ResourceId CreateResourceFromExternalTexture(
124      unsigned texture_target,
125      unsigned texture_id);
126
127  // Wraps an external texture mailbox into a GL resource.
128  ResourceId CreateResourceFromTextureMailbox(
129      const TextureMailbox& mailbox,
130      scoped_ptr<SingleReleaseCallback> release_callback);
131
132  void DeleteResource(ResourceId id);
133
134  // Update pixels from image, copying source_rect (in image) to dest_offset (in
135  // the resource).
136  void SetPixels(ResourceId id,
137                 const uint8_t* image,
138                 gfx::Rect image_rect,
139                 gfx::Rect source_rect,
140                 gfx::Vector2d dest_offset);
141
142  // Check upload status.
143  size_t NumBlockingUploads();
144  void MarkPendingUploadsAsNonBlocking();
145  size_t EstimatedUploadsPerTick();
146  void FlushUploads();
147  void ReleaseCachedData();
148  base::TimeTicks EstimatedUploadCompletionTime(size_t uploads_per_tick);
149
150  // Flush all context operations, kicking uploads and ensuring ordering with
151  // respect to other contexts.
152  void Flush();
153
154  // Finish all context operations, causing any pending callbacks to be
155  // scheduled.
156  void Finish();
157
158  // Only flush the command buffer if supported.
159  // Returns true if the shallow flush occurred, false otherwise.
160  bool ShallowFlushIfSupported();
161
162  // Creates accounting for a child. Returns a child ID.
163  int CreateChild(const ReturnCallback& return_callback);
164
165  // Destroys accounting for the child, deleting all accounted resources.
166  void DestroyChild(int child);
167
168  // Gets the child->parent resource ID map.
169  const ResourceIdMap& GetChildToParentMap(int child) const;
170
171  // Prepares resources to be transfered to the parent, moving them to
172  // mailboxes and serializing meta-data into TransferableResources.
173  // Resources are not removed from the ResourceProvider, but are marked as
174  // "in use".
175  void PrepareSendToParent(const ResourceIdArray& resources,
176                           TransferableResourceArray* transferable_resources);
177
178  // Receives resources from a child, moving them from mailboxes. Resource IDs
179  // passed are in the child namespace, and will be translated to the parent
180  // namespace, added to the child->parent map.
181  // This adds the resources to the working set in the ResourceProvider without
182  // declaring which resources are in use. Use DeclareUsedResourcesFromChild
183  // after calling this method to do that. All calls to ReceiveFromChild should
184  // be followed by a DeclareUsedResourcesFromChild.
185  // NOTE: if the sync_point is set on any TransferableResource, this will
186  // wait on it.
187  void ReceiveFromChild(
188      int child, const TransferableResourceArray& transferable_resources);
189
190  // Once a set of resources have been received, they may or may not be used.
191  // This declares what set of resources are currently in use from the child,
192  // releasing any other resources back to the child.
193  void DeclareUsedResourcesFromChild(
194      int child,
195      const ResourceIdArray& resources_from_child);
196
197  // Receives resources from the parent, moving them from mailboxes. Resource
198  // IDs passed are in the child namespace.
199  // NOTE: if the sync_point is set on any TransferableResource, this will
200  // wait on it.
201  void ReceiveReturnsFromParent(
202      const ReturnedResourceArray& transferable_resources);
203
204  // The following lock classes are part of the ResourceProvider API and are
205  // needed to read and write the resource contents. The user must ensure
206  // that they only use GL locks on GL resources, etc, and this is enforced
207  // by assertions.
208  class CC_EXPORT ScopedReadLockGL {
209   public:
210    ScopedReadLockGL(ResourceProvider* resource_provider,
211                     ResourceProvider::ResourceId resource_id);
212    virtual ~ScopedReadLockGL();
213
214    unsigned texture_id() const { return texture_id_; }
215
216   protected:
217    ResourceProvider* resource_provider_;
218    ResourceProvider::ResourceId resource_id_;
219
220   private:
221    unsigned texture_id_;
222
223    DISALLOW_COPY_AND_ASSIGN(ScopedReadLockGL);
224  };
225
226  class CC_EXPORT ScopedSamplerGL : public ScopedReadLockGL {
227   public:
228    ScopedSamplerGL(ResourceProvider* resource_provider,
229                    ResourceProvider::ResourceId resource_id,
230                    GLenum filter);
231    ScopedSamplerGL(ResourceProvider* resource_provider,
232                    ResourceProvider::ResourceId resource_id,
233                    GLenum unit,
234                    GLenum filter);
235    virtual ~ScopedSamplerGL();
236
237    GLenum target() const { return target_; }
238
239   private:
240    GLenum unit_;
241    GLenum target_;
242
243    DISALLOW_COPY_AND_ASSIGN(ScopedSamplerGL);
244  };
245
246  class CC_EXPORT ScopedWriteLockGL {
247   public:
248    ScopedWriteLockGL(ResourceProvider* resource_provider,
249                      ResourceProvider::ResourceId resource_id);
250    ~ScopedWriteLockGL();
251
252    unsigned texture_id() const { return texture_id_; }
253
254   private:
255    ResourceProvider* resource_provider_;
256    ResourceProvider::ResourceId resource_id_;
257    unsigned texture_id_;
258
259    DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockGL);
260  };
261
262  class CC_EXPORT ScopedReadLockSoftware {
263   public:
264    ScopedReadLockSoftware(ResourceProvider* resource_provider,
265                           ResourceProvider::ResourceId resource_id);
266    ~ScopedReadLockSoftware();
267
268    const SkBitmap* sk_bitmap() const { return &sk_bitmap_; }
269    GLint wrap_mode() const { return wrap_mode_; }
270
271   private:
272    ResourceProvider* resource_provider_;
273    ResourceProvider::ResourceId resource_id_;
274    SkBitmap sk_bitmap_;
275    GLint wrap_mode_;
276
277    DISALLOW_COPY_AND_ASSIGN(ScopedReadLockSoftware);
278  };
279
280  class CC_EXPORT ScopedWriteLockSoftware {
281   public:
282    ScopedWriteLockSoftware(ResourceProvider* resource_provider,
283                            ResourceProvider::ResourceId resource_id);
284    ~ScopedWriteLockSoftware();
285
286    SkCanvas* sk_canvas() { return sk_canvas_.get(); }
287
288   private:
289    ResourceProvider* resource_provider_;
290    ResourceProvider::ResourceId resource_id_;
291    SkBitmap sk_bitmap_;
292    scoped_ptr<SkCanvas> sk_canvas_;
293
294    DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockSoftware);
295  };
296
297  class Fence : public base::RefCounted<Fence> {
298   public:
299    Fence() {}
300    virtual bool HasPassed() = 0;
301
302   protected:
303    friend class base::RefCounted<Fence>;
304    virtual ~Fence() {}
305
306   private:
307    DISALLOW_COPY_AND_ASSIGN(Fence);
308  };
309
310  // Acquire pixel buffer for resource. The pixel buffer can be used to
311  // set resource pixels without performing unnecessary copying.
312  void AcquirePixelBuffer(ResourceId id);
313  void ReleasePixelBuffer(ResourceId id);
314
315  // Map/unmap the acquired pixel buffer.
316  uint8_t* MapPixelBuffer(ResourceId id);
317  void UnmapPixelBuffer(ResourceId id);
318
319  // Asynchronously update pixels from acquired pixel buffer.
320  void BeginSetPixels(ResourceId id);
321  void ForceSetPixelsToComplete(ResourceId id);
322  bool DidSetPixelsComplete(ResourceId id);
323
324  // Acquire and release an image. The image allows direct
325  // manipulation of texture memory.
326  void AcquireImage(ResourceId id);
327  void ReleaseImage(ResourceId id);
328
329  // Maps the acquired image so that its pixels could be modified.
330  // Unmap is called when all pixels are set.
331  uint8_t* MapImage(ResourceId id);
332  void UnmapImage(ResourceId id);
333
334  // Returns the stride for the image.
335  int GetImageStride(ResourceId id);
336
337  base::SharedMemory* GetSharedMemory(ResourceId id);
338
339  // For tests only! This prevents detecting uninitialized reads.
340  // Use SetPixels or LockForWrite to allocate implicitly.
341  void AllocateForTesting(ResourceId id);
342
343  // For tests only!
344  void CreateForTesting(ResourceId id);
345
346  GLenum TargetForTesting(ResourceId id);
347
348  // Sets the current read fence. If a resource is locked for read
349  // and has read fences enabled, the resource will not allow writes
350  // until this fence has passed.
351  void SetReadLockFence(scoped_refptr<Fence> fence) {
352    current_read_lock_fence_ = fence;
353  }
354  Fence* GetReadLockFence() { return current_read_lock_fence_.get(); }
355
356  // Enable read lock fences for a specific resource.
357  void EnableReadLockFences(ResourceProvider::ResourceId id, bool enable);
358
359  // Indicates if we can currently lock this resource for write.
360  bool CanLockForWrite(ResourceId id);
361
362  static GLint GetActiveTextureUnit(gpu::gles2::GLES2Interface* gl);
363
364 private:
365  struct Resource {
366    Resource();
367    ~Resource();
368    Resource(unsigned texture_id,
369             gfx::Size size,
370             GLenum target,
371             GLenum filter,
372             GLenum texture_pool,
373             GLint wrap_mode,
374             TextureUsageHint hint,
375             ResourceFormat format);
376    Resource(uint8_t* pixels,
377             SharedBitmap* bitmap,
378             gfx::Size size,
379             GLenum filter,
380             GLint wrap_mode);
381
382    int child_id;
383    unsigned gl_id;
384    // Pixel buffer used for set pixels without unnecessary copying.
385    unsigned gl_pixel_buffer_id;
386    // Query used to determine when asynchronous set pixels complete.
387    unsigned gl_upload_query_id;
388    TextureMailbox mailbox;
389    ReleaseCallback release_callback;
390    uint8_t* pixels;
391    uint8_t* pixel_buffer;
392    int lock_for_read_count;
393    int imported_count;
394    int exported_count;
395    bool locked_for_write;
396    bool external;
397    bool marked_for_deletion;
398    bool pending_set_pixels;
399    bool set_pixels_completion_forced;
400    bool allocated;
401    bool enable_read_lock_fences;
402    scoped_refptr<Fence> read_lock_fence;
403    gfx::Size size;
404    GLenum target;
405    // TODO(skyostil): Use a separate sampler object for filter state.
406    GLenum original_filter;
407    GLenum filter;
408    unsigned image_id;
409    unsigned bound_image_id;
410    bool dirty_image;
411    GLenum texture_pool;
412    GLint wrap_mode;
413    bool lost;
414    TextureUsageHint hint;
415    ResourceType type;
416    ResourceFormat format;
417    SharedBitmap* shared_bitmap;
418  };
419  typedef base::hash_map<ResourceId, Resource> ResourceMap;
420
421  static bool CompareResourceMapIteratorsByChildId(
422      const std::pair<ReturnedResource, ResourceMap::iterator>& a,
423      const std::pair<ReturnedResource, ResourceMap::iterator>& b);
424
425  struct Child {
426    Child();
427    ~Child();
428
429    ResourceIdMap child_to_parent_map;
430    ResourceIdMap parent_to_child_map;
431    ReturnCallback return_callback;
432    ResourceIdSet in_use_resources;
433    bool marked_for_deletion;
434  };
435  typedef base::hash_map<int, Child> ChildMap;
436
437  bool ReadLockFenceHasPassed(Resource* resource) {
438    return !resource->read_lock_fence.get() ||
439           resource->read_lock_fence->HasPassed();
440  }
441
442  ResourceProvider(OutputSurface* output_surface,
443                   SharedBitmapManager* shared_bitmap_manager,
444                   int highp_threshold_min,
445                   bool use_rgba_4444_texture_format,
446                   size_t id_allocation_chunk_size);
447
448  void CleanUpGLIfNeeded();
449
450  Resource* GetResource(ResourceId id);
451  const Resource* LockForRead(ResourceId id);
452  void UnlockForRead(ResourceId id);
453  const Resource* LockForWrite(ResourceId id);
454  void UnlockForWrite(ResourceId id);
455  static void PopulateSkBitmapWithResource(SkBitmap* sk_bitmap,
456                                           const Resource* resource);
457
458  void TransferResource(gpu::gles2::GLES2Interface* gl,
459                        ResourceId id,
460                        TransferableResource* resource);
461  enum DeleteStyle {
462    Normal,
463    ForShutdown,
464  };
465  void DeleteResourceInternal(ResourceMap::iterator it, DeleteStyle style);
466  void DeleteAndReturnUnusedResourcesToChild(ChildMap::iterator child_it,
467                                             DeleteStyle style,
468                                             const ResourceIdArray& unused);
469  void DestroyChildInternal(ChildMap::iterator it, DeleteStyle style);
470  void LazyCreate(Resource* resource);
471  void LazyAllocate(Resource* resource);
472
473  // Binds the given GL resource to a texture target for sampling using the
474  // specified filter for both minification and magnification. Returns the
475  // texture target used. The resource must be locked for reading.
476  GLenum BindForSampling(ResourceProvider::ResourceId resource_id,
477                         GLenum unit,
478                         GLenum filter);
479
480  // Returns NULL if the output_surface_ does not have a ContextProvider.
481  gpu::gles2::GLES2Interface* ContextGL() const;
482
483  OutputSurface* output_surface_;
484  SharedBitmapManager* shared_bitmap_manager_;
485  bool lost_output_surface_;
486  int highp_threshold_min_;
487  ResourceId next_id_;
488  ResourceMap resources_;
489  int next_child_;
490  ChildMap children_;
491
492  ResourceType default_resource_type_;
493  bool use_texture_storage_ext_;
494  bool use_texture_usage_hint_;
495  bool use_compressed_texture_etc1_;
496  scoped_ptr<TextureUploader> texture_uploader_;
497  int max_texture_size_;
498  ResourceFormat best_texture_format_;
499
500  base::ThreadChecker thread_checker_;
501
502  scoped_refptr<Fence> current_read_lock_fence_;
503  bool use_rgba_4444_texture_format_;
504
505  const size_t id_allocation_chunk_size_;
506  scoped_ptr<IdAllocator> texture_id_allocator_;
507  scoped_ptr<IdAllocator> buffer_id_allocator_;
508
509  DISALLOW_COPY_AND_ASSIGN(ResourceProvider);
510};
511
512
513// TODO(epenner): Move these format conversions to resource_format.h
514// once that builds on mac (npapi.h currently #includes OpenGL.h).
515inline unsigned BitsPerPixel(ResourceFormat format) {
516  DCHECK_LE(format, RESOURCE_FORMAT_MAX);
517  static const unsigned format_bits_per_pixel[RESOURCE_FORMAT_MAX + 1] = {
518    32,  // RGBA_8888
519    16,  // RGBA_4444
520    32,  // BGRA_8888
521    8,   // LUMINANCE_8
522    16,  // RGB_565,
523    4    // ETC1
524  };
525  return format_bits_per_pixel[format];
526}
527
528inline GLenum GLDataType(ResourceFormat format) {
529  DCHECK_LE(format, RESOURCE_FORMAT_MAX);
530  static const unsigned format_gl_data_type[RESOURCE_FORMAT_MAX + 1] = {
531    GL_UNSIGNED_BYTE,           // RGBA_8888
532    GL_UNSIGNED_SHORT_4_4_4_4,  // RGBA_4444
533    GL_UNSIGNED_BYTE,           // BGRA_8888
534    GL_UNSIGNED_BYTE,           // LUMINANCE_8
535    GL_UNSIGNED_SHORT_5_6_5,    // RGB_565,
536    GL_UNSIGNED_BYTE            // ETC1
537  };
538  return format_gl_data_type[format];
539}
540
541inline GLenum GLDataFormat(ResourceFormat format) {
542  DCHECK_LE(format, RESOURCE_FORMAT_MAX);
543  static const unsigned format_gl_data_format[RESOURCE_FORMAT_MAX + 1] = {
544    GL_RGBA,           // RGBA_8888
545    GL_RGBA,           // RGBA_4444
546    GL_BGRA_EXT,       // BGRA_8888
547    GL_LUMINANCE,      // LUMINANCE_8
548    GL_RGB,            // RGB_565
549    GL_ETC1_RGB8_OES   // ETC1
550  };
551  return format_gl_data_format[format];
552}
553
554inline GLenum GLInternalFormat(ResourceFormat format) {
555  return GLDataFormat(format);
556}
557
558}  // namespace cc
559
560#endif  // CC_RESOURCES_RESOURCE_PROVIDER_H_
561