• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "cc/resources/resource_provider.h"
6 
7 #include <algorithm>
8 #include <limits>
9 
10 #include "base/containers/hash_tables.h"
11 #include "base/debug/trace_event.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/string_util.h"
15 #include "cc/base/util.h"
16 #include "cc/output/gl_renderer.h"  // For the GLC() macro.
17 #include "cc/resources/platform_color.h"
18 #include "cc/resources/returned_resource.h"
19 #include "cc/resources/shared_bitmap_manager.h"
20 #include "cc/resources/transferable_resource.h"
21 #include "cc/scheduler/texture_uploader.h"
22 #include "gpu/GLES2/gl2extchromium.h"
23 #include "gpu/command_buffer/client/gles2_interface.h"
24 #include "third_party/khronos/GLES2/gl2.h"
25 #include "third_party/khronos/GLES2/gl2ext.h"
26 #include "ui/gfx/frame_time.h"
27 #include "ui/gfx/rect.h"
28 #include "ui/gfx/vector2d.h"
29 
30 using gpu::gles2::GLES2Interface;
31 
32 namespace cc {
33 
34 class IdAllocator {
35  public:
~IdAllocator()36   virtual ~IdAllocator() {}
37 
38   virtual GLuint NextId() = 0;
39 
40  protected:
IdAllocator(GLES2Interface * gl,size_t id_allocation_chunk_size)41   IdAllocator(GLES2Interface* gl, size_t id_allocation_chunk_size)
42       : gl_(gl),
43         id_allocation_chunk_size_(id_allocation_chunk_size),
44         ids_(new GLuint[id_allocation_chunk_size]),
45         next_id_index_(id_allocation_chunk_size) {
46     DCHECK(id_allocation_chunk_size_);
47   }
48 
49   GLES2Interface* gl_;
50   const size_t id_allocation_chunk_size_;
51   scoped_ptr<GLuint[]> ids_;
52   size_t next_id_index_;
53 };
54 
55 namespace {
56 
57 // Measured in seconds.
58 const double kSoftwareUploadTickRate = 0.000250;
59 const double kTextureUploadTickRate = 0.004;
60 
TextureToStorageFormat(ResourceFormat format)61 GLenum TextureToStorageFormat(ResourceFormat format) {
62   GLenum storage_format = GL_RGBA8_OES;
63   switch (format) {
64     case RGBA_8888:
65       break;
66     case BGRA_8888:
67       storage_format = GL_BGRA8_EXT;
68       break;
69     case RGBA_4444:
70     case LUMINANCE_8:
71     case RGB_565:
72     case ETC1:
73       NOTREACHED();
74       break;
75   }
76 
77   return storage_format;
78 }
79 
IsFormatSupportedForStorage(ResourceFormat format)80 bool IsFormatSupportedForStorage(ResourceFormat format) {
81   switch (format) {
82     case RGBA_8888:
83     case BGRA_8888:
84       return true;
85     case RGBA_4444:
86     case LUMINANCE_8:
87     case RGB_565:
88     case ETC1:
89       return false;
90   }
91   return false;
92 }
93 
94 class ScopedSetActiveTexture {
95  public:
ScopedSetActiveTexture(GLES2Interface * gl,GLenum unit)96   ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit)
97       : gl_(gl), unit_(unit) {
98     DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_));
99 
100     if (unit_ != GL_TEXTURE0)
101       GLC(gl_, gl_->ActiveTexture(unit_));
102   }
103 
~ScopedSetActiveTexture()104   ~ScopedSetActiveTexture() {
105     // Active unit being GL_TEXTURE0 is effectively the ground state.
106     if (unit_ != GL_TEXTURE0)
107       GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0));
108   }
109 
110  private:
111   GLES2Interface* gl_;
112   GLenum unit_;
113 };
114 
115 class TextureIdAllocator : public IdAllocator {
116  public:
TextureIdAllocator(GLES2Interface * gl,size_t texture_id_allocation_chunk_size)117   TextureIdAllocator(GLES2Interface* gl,
118                      size_t texture_id_allocation_chunk_size)
119       : IdAllocator(gl, texture_id_allocation_chunk_size) {}
~TextureIdAllocator()120   virtual ~TextureIdAllocator() {
121     gl_->DeleteTextures(id_allocation_chunk_size_ - next_id_index_,
122                         ids_.get() + next_id_index_);
123   }
124 
125   // Overridden from IdAllocator:
NextId()126   virtual GLuint NextId() OVERRIDE {
127     if (next_id_index_ == id_allocation_chunk_size_) {
128       gl_->GenTextures(id_allocation_chunk_size_, ids_.get());
129       next_id_index_ = 0;
130     }
131 
132     return ids_[next_id_index_++];
133   }
134 
135  private:
136   DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator);
137 };
138 
139 class BufferIdAllocator : public IdAllocator {
140  public:
BufferIdAllocator(GLES2Interface * gl,size_t buffer_id_allocation_chunk_size)141   BufferIdAllocator(GLES2Interface* gl, size_t buffer_id_allocation_chunk_size)
142       : IdAllocator(gl, buffer_id_allocation_chunk_size) {}
~BufferIdAllocator()143   virtual ~BufferIdAllocator() {
144     gl_->DeleteBuffers(id_allocation_chunk_size_ - next_id_index_,
145                        ids_.get() + next_id_index_);
146   }
147 
148   // Overridden from IdAllocator:
NextId()149   virtual GLuint NextId() OVERRIDE {
150     if (next_id_index_ == id_allocation_chunk_size_) {
151       gl_->GenBuffers(id_allocation_chunk_size_, ids_.get());
152       next_id_index_ = 0;
153     }
154 
155     return ids_[next_id_index_++];
156   }
157 
158  private:
159   DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator);
160 };
161 
162 }  // namespace
163 
Resource()164 ResourceProvider::Resource::Resource()
165     : child_id(0),
166       gl_id(0),
167       gl_pixel_buffer_id(0),
168       gl_upload_query_id(0),
169       pixels(NULL),
170       pixel_buffer(NULL),
171       lock_for_read_count(0),
172       imported_count(0),
173       exported_count(0),
174       locked_for_write(false),
175       external(false),
176       marked_for_deletion(false),
177       pending_set_pixels(false),
178       set_pixels_completion_forced(false),
179       allocated(false),
180       enable_read_lock_fences(false),
181       read_lock_fence(NULL),
182       size(),
183       target(0),
184       original_filter(0),
185       filter(0),
186       image_id(0),
187       bound_image_id(0),
188       dirty_image(false),
189       texture_pool(0),
190       wrap_mode(0),
191       lost(false),
192       hint(TextureUsageAny),
193       type(static_cast<ResourceType>(0)),
194       format(RGBA_8888),
195       shared_bitmap(NULL) {}
196 
~Resource()197 ResourceProvider::Resource::~Resource() {}
198 
Resource(GLuint texture_id,gfx::Size size,GLenum target,GLenum filter,GLenum texture_pool,GLint wrap_mode,TextureUsageHint hint,ResourceFormat format)199 ResourceProvider::Resource::Resource(GLuint texture_id,
200                                      gfx::Size size,
201                                      GLenum target,
202                                      GLenum filter,
203                                      GLenum texture_pool,
204                                      GLint wrap_mode,
205                                      TextureUsageHint hint,
206                                      ResourceFormat format)
207     : child_id(0),
208       gl_id(texture_id),
209       gl_pixel_buffer_id(0),
210       gl_upload_query_id(0),
211       pixels(NULL),
212       pixel_buffer(NULL),
213       lock_for_read_count(0),
214       imported_count(0),
215       exported_count(0),
216       locked_for_write(false),
217       external(false),
218       marked_for_deletion(false),
219       pending_set_pixels(false),
220       set_pixels_completion_forced(false),
221       allocated(false),
222       enable_read_lock_fences(false),
223       read_lock_fence(NULL),
224       size(size),
225       target(target),
226       original_filter(filter),
227       filter(filter),
228       image_id(0),
229       bound_image_id(0),
230       dirty_image(false),
231       texture_pool(texture_pool),
232       wrap_mode(wrap_mode),
233       lost(false),
234       hint(hint),
235       type(GLTexture),
236       format(format),
237       shared_bitmap(NULL) {
238   DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
239 }
240 
Resource(uint8_t * pixels,SharedBitmap * bitmap,gfx::Size size,GLenum filter,GLint wrap_mode)241 ResourceProvider::Resource::Resource(uint8_t* pixels,
242                                      SharedBitmap* bitmap,
243                                      gfx::Size size,
244                                      GLenum filter,
245                                      GLint wrap_mode)
246     : child_id(0),
247       gl_id(0),
248       gl_pixel_buffer_id(0),
249       gl_upload_query_id(0),
250       pixels(pixels),
251       pixel_buffer(NULL),
252       lock_for_read_count(0),
253       imported_count(0),
254       exported_count(0),
255       locked_for_write(false),
256       external(false),
257       marked_for_deletion(false),
258       pending_set_pixels(false),
259       set_pixels_completion_forced(false),
260       allocated(false),
261       enable_read_lock_fences(false),
262       read_lock_fence(NULL),
263       size(size),
264       target(0),
265       original_filter(filter),
266       filter(filter),
267       image_id(0),
268       bound_image_id(0),
269       dirty_image(false),
270       texture_pool(0),
271       wrap_mode(wrap_mode),
272       lost(false),
273       hint(TextureUsageAny),
274       type(Bitmap),
275       format(RGBA_8888),
276       shared_bitmap(bitmap) {
277   DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
278 }
279 
Child()280 ResourceProvider::Child::Child() : marked_for_deletion(false) {}
281 
~Child()282 ResourceProvider::Child::~Child() {}
283 
Create(OutputSurface * output_surface,SharedBitmapManager * shared_bitmap_manager,int highp_threshold_min,bool use_rgba_4444_texture_format,size_t id_allocation_chunk_size)284 scoped_ptr<ResourceProvider> ResourceProvider::Create(
285     OutputSurface* output_surface,
286     SharedBitmapManager* shared_bitmap_manager,
287     int highp_threshold_min,
288     bool use_rgba_4444_texture_format,
289     size_t id_allocation_chunk_size) {
290   scoped_ptr<ResourceProvider> resource_provider(
291       new ResourceProvider(output_surface,
292                            shared_bitmap_manager,
293                            highp_threshold_min,
294                            use_rgba_4444_texture_format,
295                            id_allocation_chunk_size));
296 
297   bool success = false;
298   if (resource_provider->ContextGL()) {
299     success = resource_provider->InitializeGL();
300   } else {
301     resource_provider->InitializeSoftware();
302     success = true;
303   }
304 
305   if (!success)
306     return scoped_ptr<ResourceProvider>();
307 
308   DCHECK_NE(InvalidType, resource_provider->default_resource_type());
309   return resource_provider.Pass();
310 }
311 
~ResourceProvider()312 ResourceProvider::~ResourceProvider() {
313   while (!children_.empty())
314     DestroyChildInternal(children_.begin(), ForShutdown);
315   while (!resources_.empty())
316     DeleteResourceInternal(resources_.begin(), ForShutdown);
317 
318   CleanUpGLIfNeeded();
319 }
320 
InUseByConsumer(ResourceId id)321 bool ResourceProvider::InUseByConsumer(ResourceId id) {
322   Resource* resource = GetResource(id);
323   return resource->lock_for_read_count > 0 || resource->exported_count > 0 ||
324          resource->lost;
325 }
326 
IsLost(ResourceId id)327 bool ResourceProvider::IsLost(ResourceId id) {
328   Resource* resource = GetResource(id);
329   return resource->lost;
330 }
331 
CreateResource(gfx::Size size,GLint wrap_mode,TextureUsageHint hint,ResourceFormat format)332 ResourceProvider::ResourceId ResourceProvider::CreateResource(
333     gfx::Size size,
334     GLint wrap_mode,
335     TextureUsageHint hint,
336     ResourceFormat format) {
337   DCHECK(!size.IsEmpty());
338   switch (default_resource_type_) {
339     case GLTexture:
340       return CreateGLTexture(size,
341                              GL_TEXTURE_2D,
342                              GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
343                              wrap_mode,
344                              hint,
345                              format);
346     case Bitmap:
347       DCHECK_EQ(RGBA_8888, format);
348       return CreateBitmap(size, wrap_mode);
349     case InvalidType:
350       break;
351   }
352 
353   LOG(FATAL) << "Invalid default resource type.";
354   return 0;
355 }
356 
CreateManagedResource(gfx::Size size,GLenum target,GLint wrap_mode,TextureUsageHint hint,ResourceFormat format)357 ResourceProvider::ResourceId ResourceProvider::CreateManagedResource(
358     gfx::Size size,
359     GLenum target,
360     GLint wrap_mode,
361     TextureUsageHint hint,
362     ResourceFormat format) {
363   DCHECK(!size.IsEmpty());
364   switch (default_resource_type_) {
365     case GLTexture:
366       return CreateGLTexture(size,
367                              target,
368                              GL_TEXTURE_POOL_MANAGED_CHROMIUM,
369                              wrap_mode,
370                              hint,
371                              format);
372     case Bitmap:
373       DCHECK_EQ(RGBA_8888, format);
374       return CreateBitmap(size, wrap_mode);
375     case InvalidType:
376       break;
377   }
378 
379   LOG(FATAL) << "Invalid default resource type.";
380   return 0;
381 }
382 
CreateGLTexture(gfx::Size size,GLenum target,GLenum texture_pool,GLint wrap_mode,TextureUsageHint hint,ResourceFormat format)383 ResourceProvider::ResourceId ResourceProvider::CreateGLTexture(
384     gfx::Size size,
385     GLenum target,
386     GLenum texture_pool,
387     GLint wrap_mode,
388     TextureUsageHint hint,
389     ResourceFormat format) {
390   DCHECK_LE(size.width(), max_texture_size_);
391   DCHECK_LE(size.height(), max_texture_size_);
392   DCHECK(thread_checker_.CalledOnValidThread());
393 
394   ResourceId id = next_id_++;
395   Resource resource(
396       0, size, target, GL_LINEAR, texture_pool, wrap_mode, hint, format);
397   resource.allocated = false;
398   resources_[id] = resource;
399   return id;
400 }
401 
CreateBitmap(gfx::Size size,GLint wrap_mode)402 ResourceProvider::ResourceId ResourceProvider::CreateBitmap(
403     gfx::Size size, GLint wrap_mode) {
404   DCHECK(thread_checker_.CalledOnValidThread());
405 
406   scoped_ptr<SharedBitmap> bitmap;
407   if (shared_bitmap_manager_)
408     bitmap = shared_bitmap_manager_->AllocateSharedBitmap(size);
409 
410   uint8_t* pixels;
411   if (bitmap)
412     pixels = bitmap->pixels();
413   else
414     pixels = new uint8_t[4 * size.GetArea()];
415 
416   ResourceId id = next_id_++;
417   Resource resource(
418       pixels, bitmap.release(), size, GL_LINEAR, wrap_mode);
419   resource.allocated = true;
420   resources_[id] = resource;
421   return id;
422 }
423 
424 ResourceProvider::ResourceId
CreateResourceFromExternalTexture(GLuint texture_target,GLuint texture_id)425 ResourceProvider::CreateResourceFromExternalTexture(
426     GLuint texture_target,
427     GLuint texture_id) {
428   DCHECK(thread_checker_.CalledOnValidThread());
429 
430   GLES2Interface* gl = ContextGL();
431   DCHECK(gl);
432   GLC(gl, gl->BindTexture(texture_target, texture_id));
433   GLC(gl, gl->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
434   GLC(gl, gl->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
435   GLC(gl,
436       gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
437   GLC(gl,
438       gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
439 
440   ResourceId id = next_id_++;
441   Resource resource(texture_id,
442                     gfx::Size(),
443                     texture_target,
444                     GL_LINEAR,
445                     0,
446                     GL_CLAMP_TO_EDGE,
447                     TextureUsageAny,
448                     RGBA_8888);
449   resource.external = true;
450   resource.allocated = true;
451   resources_[id] = resource;
452   return id;
453 }
454 
CreateResourceFromTextureMailbox(const TextureMailbox & mailbox,scoped_ptr<SingleReleaseCallback> release_callback)455 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
456     const TextureMailbox& mailbox,
457     scoped_ptr<SingleReleaseCallback> release_callback) {
458   DCHECK(thread_checker_.CalledOnValidThread());
459   // Just store the information. Mailbox will be consumed in LockForRead().
460   ResourceId id = next_id_++;
461   DCHECK(mailbox.IsValid());
462   Resource& resource = resources_[id];
463   if (mailbox.IsTexture()) {
464     resource = Resource(0,
465                         gfx::Size(),
466                         mailbox.target(),
467                         GL_LINEAR,
468                         0,
469                         GL_CLAMP_TO_EDGE,
470                         TextureUsageAny,
471                         RGBA_8888);
472   } else {
473     DCHECK(mailbox.IsSharedMemory());
474     base::SharedMemory* shared_memory = mailbox.shared_memory();
475     DCHECK(shared_memory->memory());
476     uint8_t* pixels = reinterpret_cast<uint8_t*>(shared_memory->memory());
477     scoped_ptr<SharedBitmap> shared_bitmap;
478     if (shared_bitmap_manager_) {
479       shared_bitmap =
480           shared_bitmap_manager_->GetBitmapForSharedMemory(shared_memory);
481     }
482     resource = Resource(pixels,
483                         shared_bitmap.release(),
484                         mailbox.shared_memory_size(),
485                         GL_LINEAR,
486                         GL_CLAMP_TO_EDGE);
487   }
488   resource.external = true;
489   resource.allocated = true;
490   resource.mailbox = mailbox;
491   resource.release_callback =
492       base::Bind(&SingleReleaseCallback::Run,
493                  base::Owned(release_callback.release()));
494   return id;
495 }
496 
DeleteResource(ResourceId id)497 void ResourceProvider::DeleteResource(ResourceId id) {
498   DCHECK(thread_checker_.CalledOnValidThread());
499   ResourceMap::iterator it = resources_.find(id);
500   CHECK(it != resources_.end());
501   Resource* resource = &it->second;
502   DCHECK(!resource->lock_for_read_count);
503   DCHECK(!resource->marked_for_deletion);
504   DCHECK_EQ(resource->imported_count, 0);
505   DCHECK(resource->pending_set_pixels || !resource->locked_for_write);
506 
507   if (resource->exported_count > 0) {
508     resource->marked_for_deletion = true;
509     return;
510   } else {
511     DeleteResourceInternal(it, Normal);
512   }
513 }
514 
DeleteResourceInternal(ResourceMap::iterator it,DeleteStyle style)515 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
516                                               DeleteStyle style) {
517   TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal");
518   Resource* resource = &it->second;
519   bool lost_resource = resource->lost;
520 
521   DCHECK(resource->exported_count == 0 || style != Normal);
522   if (style == ForShutdown && resource->exported_count > 0)
523     lost_resource = true;
524 
525   if (resource->image_id) {
526     GLES2Interface* gl = ContextGL();
527     DCHECK(gl);
528     GLC(gl, gl->DestroyImageCHROMIUM(resource->image_id));
529   }
530 
531   if (resource->gl_id && !resource->external) {
532     GLES2Interface* gl = ContextGL();
533     DCHECK(gl);
534     GLC(gl, gl->DeleteTextures(1, &resource->gl_id));
535   }
536   if (resource->gl_upload_query_id) {
537     GLES2Interface* gl = ContextGL();
538     DCHECK(gl);
539     GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id));
540   }
541   if (resource->gl_pixel_buffer_id) {
542     GLES2Interface* gl = ContextGL();
543     DCHECK(gl);
544     GLC(gl, gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id));
545   }
546   if (resource->mailbox.IsValid() && resource->external) {
547     GLuint sync_point = resource->mailbox.sync_point();
548     if (resource->mailbox.IsTexture()) {
549       lost_resource |= lost_output_surface_;
550       GLES2Interface* gl = ContextGL();
551       DCHECK(gl);
552       if (resource->gl_id)
553         GLC(gl, gl->DeleteTextures(1, &resource->gl_id));
554       if (!lost_resource && resource->gl_id)
555         sync_point = gl->InsertSyncPointCHROMIUM();
556     } else {
557       DCHECK(resource->mailbox.IsSharedMemory());
558       base::SharedMemory* shared_memory = resource->mailbox.shared_memory();
559       if (resource->pixels && shared_memory) {
560         DCHECK(shared_memory->memory() == resource->pixels);
561         resource->pixels = NULL;
562         delete resource->shared_bitmap;
563         resource->shared_bitmap = NULL;
564       }
565     }
566     resource->release_callback.Run(sync_point, lost_resource);
567   }
568   if (resource->shared_bitmap) {
569     delete resource->shared_bitmap;
570     resource->pixels = NULL;
571   }
572   if (resource->pixels)
573     delete[] resource->pixels;
574   if (resource->pixel_buffer)
575     delete[] resource->pixel_buffer;
576 
577   resources_.erase(it);
578 }
579 
GetResourceType(ResourceId id)580 ResourceProvider::ResourceType ResourceProvider::GetResourceType(
581     ResourceId id) {
582   return GetResource(id)->type;
583 }
584 
SetPixels(ResourceId id,const uint8_t * image,gfx::Rect image_rect,gfx::Rect source_rect,gfx::Vector2d dest_offset)585 void ResourceProvider::SetPixels(ResourceId id,
586                                  const uint8_t* image,
587                                  gfx::Rect image_rect,
588                                  gfx::Rect source_rect,
589                                  gfx::Vector2d dest_offset) {
590   Resource* resource = GetResource(id);
591   DCHECK(!resource->locked_for_write);
592   DCHECK(!resource->lock_for_read_count);
593   DCHECK(!resource->external);
594   DCHECK_EQ(resource->exported_count, 0);
595   DCHECK(ReadLockFenceHasPassed(resource));
596   LazyAllocate(resource);
597 
598   if (resource->gl_id) {
599     DCHECK(!resource->pending_set_pixels);
600     DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
601     GLES2Interface* gl = ContextGL();
602     DCHECK(gl);
603     DCHECK(texture_uploader_.get());
604     gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
605     texture_uploader_->Upload(image,
606                               image_rect,
607                               source_rect,
608                               dest_offset,
609                               resource->format,
610                               resource->size);
611   }
612 
613   if (resource->pixels) {
614     DCHECK(resource->allocated);
615     DCHECK_EQ(RGBA_8888, resource->format);
616     SkBitmap src_full;
617     src_full.setConfig(
618         SkBitmap::kARGB_8888_Config, image_rect.width(), image_rect.height());
619     src_full.setPixels(const_cast<uint8_t*>(image));
620     SkBitmap src_subset;
621     SkIRect sk_source_rect = SkIRect::MakeXYWH(source_rect.x(),
622                                                source_rect.y(),
623                                                source_rect.width(),
624                                                source_rect.height());
625     sk_source_rect.offset(-image_rect.x(), -image_rect.y());
626     src_full.extractSubset(&src_subset, sk_source_rect);
627 
628     ScopedWriteLockSoftware lock(this, id);
629     SkCanvas* dest = lock.sk_canvas();
630     dest->writePixels(src_subset, dest_offset.x(), dest_offset.y());
631   }
632 }
633 
NumBlockingUploads()634 size_t ResourceProvider::NumBlockingUploads() {
635   if (!texture_uploader_)
636     return 0;
637 
638   return texture_uploader_->NumBlockingUploads();
639 }
640 
MarkPendingUploadsAsNonBlocking()641 void ResourceProvider::MarkPendingUploadsAsNonBlocking() {
642   if (!texture_uploader_)
643     return;
644 
645   texture_uploader_->MarkPendingUploadsAsNonBlocking();
646 }
647 
EstimatedUploadsPerTick()648 size_t ResourceProvider::EstimatedUploadsPerTick() {
649   if (!texture_uploader_)
650     return 1u;
651 
652   double textures_per_second = texture_uploader_->EstimatedTexturesPerSecond();
653   size_t textures_per_tick = floor(
654       kTextureUploadTickRate * textures_per_second);
655   return textures_per_tick ? textures_per_tick : 1u;
656 }
657 
FlushUploads()658 void ResourceProvider::FlushUploads() {
659   if (!texture_uploader_)
660     return;
661 
662   texture_uploader_->Flush();
663 }
664 
ReleaseCachedData()665 void ResourceProvider::ReleaseCachedData() {
666   if (!texture_uploader_)
667     return;
668 
669   texture_uploader_->ReleaseCachedQueries();
670 }
671 
EstimatedUploadCompletionTime(size_t uploads_per_tick)672 base::TimeTicks ResourceProvider::EstimatedUploadCompletionTime(
673     size_t uploads_per_tick) {
674   if (lost_output_surface_)
675     return base::TimeTicks();
676 
677   // Software resource uploads happen on impl thread, so don't bother batching
678   // them up and trying to wait for them to complete.
679   if (!texture_uploader_) {
680     return gfx::FrameTime::Now() + base::TimeDelta::FromMicroseconds(
681         base::Time::kMicrosecondsPerSecond * kSoftwareUploadTickRate);
682   }
683 
684   base::TimeDelta upload_one_texture_time =
685       base::TimeDelta::FromMicroseconds(
686           base::Time::kMicrosecondsPerSecond * kTextureUploadTickRate) /
687       uploads_per_tick;
688 
689   size_t total_uploads = NumBlockingUploads() + uploads_per_tick;
690   return gfx::FrameTime::Now() + upload_one_texture_time * total_uploads;
691 }
692 
Flush()693 void ResourceProvider::Flush() {
694   DCHECK(thread_checker_.CalledOnValidThread());
695   GLES2Interface* gl = ContextGL();
696   if (gl)
697     gl->Flush();
698 }
699 
Finish()700 void ResourceProvider::Finish() {
701   DCHECK(thread_checker_.CalledOnValidThread());
702   GLES2Interface* gl = ContextGL();
703   if (gl)
704     gl->Finish();
705 }
706 
ShallowFlushIfSupported()707 bool ResourceProvider::ShallowFlushIfSupported() {
708   DCHECK(thread_checker_.CalledOnValidThread());
709   GLES2Interface* gl = ContextGL();
710   if (!gl)
711     return false;
712 
713   gl->ShallowFlushCHROMIUM();
714   return true;
715 }
716 
GetResource(ResourceId id)717 ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) {
718   DCHECK(thread_checker_.CalledOnValidThread());
719   ResourceMap::iterator it = resources_.find(id);
720   CHECK(it != resources_.end());
721   return &it->second;
722 }
723 
LockForRead(ResourceId id)724 const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
725   Resource* resource = GetResource(id);
726   DCHECK(!resource->locked_for_write ||
727          resource->set_pixels_completion_forced) <<
728       "locked for write: " << resource->locked_for_write <<
729       " pixels completion forced: " << resource->set_pixels_completion_forced;
730   DCHECK_EQ(resource->exported_count, 0);
731   // Uninitialized! Call SetPixels or LockForWrite first.
732   DCHECK(resource->allocated);
733 
734   LazyCreate(resource);
735 
736   if (resource->external) {
737     if (!resource->gl_id && resource->mailbox.IsTexture()) {
738       GLES2Interface* gl = ContextGL();
739       DCHECK(gl);
740       if (resource->mailbox.sync_point()) {
741         GLC(gl, gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point()));
742         resource->mailbox.ResetSyncPoint();
743       }
744       resource->gl_id = texture_id_allocator_->NextId();
745       GLC(gl, gl->BindTexture(resource->target, resource->gl_id));
746       GLC(gl,
747           gl->ConsumeTextureCHROMIUM(resource->target,
748                                      resource->mailbox.data()));
749     }
750   }
751 
752   resource->lock_for_read_count++;
753   if (resource->enable_read_lock_fences)
754     resource->read_lock_fence = current_read_lock_fence_;
755 
756   return resource;
757 }
758 
UnlockForRead(ResourceId id)759 void ResourceProvider::UnlockForRead(ResourceId id) {
760   Resource* resource = GetResource(id);
761   DCHECK_GT(resource->lock_for_read_count, 0);
762   DCHECK_EQ(resource->exported_count, 0);
763   resource->lock_for_read_count--;
764 }
765 
LockForWrite(ResourceId id)766 const ResourceProvider::Resource* ResourceProvider::LockForWrite(
767     ResourceId id) {
768   Resource* resource = GetResource(id);
769   DCHECK(!resource->locked_for_write);
770   DCHECK(!resource->lock_for_read_count);
771   DCHECK_EQ(resource->exported_count, 0);
772   DCHECK(!resource->external);
773   DCHECK(!resource->lost);
774   DCHECK(ReadLockFenceHasPassed(resource));
775   LazyAllocate(resource);
776 
777   resource->locked_for_write = true;
778   return resource;
779 }
780 
CanLockForWrite(ResourceId id)781 bool ResourceProvider::CanLockForWrite(ResourceId id) {
782   Resource* resource = GetResource(id);
783   return !resource->locked_for_write && !resource->lock_for_read_count &&
784          !resource->exported_count && !resource->external && !resource->lost &&
785          ReadLockFenceHasPassed(resource);
786 }
787 
UnlockForWrite(ResourceId id)788 void ResourceProvider::UnlockForWrite(ResourceId id) {
789   Resource* resource = GetResource(id);
790   DCHECK(resource->locked_for_write);
791   DCHECK_EQ(resource->exported_count, 0);
792   DCHECK(!resource->external);
793   resource->locked_for_write = false;
794 }
795 
ScopedReadLockGL(ResourceProvider * resource_provider,ResourceProvider::ResourceId resource_id)796 ResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
797     ResourceProvider* resource_provider,
798     ResourceProvider::ResourceId resource_id)
799     : resource_provider_(resource_provider),
800       resource_id_(resource_id),
801       texture_id_(resource_provider->LockForRead(resource_id)->gl_id) {
802   DCHECK(texture_id_);
803 }
804 
~ScopedReadLockGL()805 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
806   resource_provider_->UnlockForRead(resource_id_);
807 }
808 
ScopedSamplerGL(ResourceProvider * resource_provider,ResourceProvider::ResourceId resource_id,GLenum filter)809 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
810     ResourceProvider* resource_provider,
811     ResourceProvider::ResourceId resource_id,
812     GLenum filter)
813     : ScopedReadLockGL(resource_provider, resource_id),
814       unit_(GL_TEXTURE0),
815       target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
816 }
817 
ScopedSamplerGL(ResourceProvider * resource_provider,ResourceProvider::ResourceId resource_id,GLenum unit,GLenum filter)818 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
819     ResourceProvider* resource_provider,
820     ResourceProvider::ResourceId resource_id,
821     GLenum unit,
822     GLenum filter)
823     : ScopedReadLockGL(resource_provider, resource_id),
824       unit_(unit),
825       target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
826 }
827 
~ScopedSamplerGL()828 ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() {
829 }
830 
ScopedWriteLockGL(ResourceProvider * resource_provider,ResourceProvider::ResourceId resource_id)831 ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(
832     ResourceProvider* resource_provider,
833     ResourceProvider::ResourceId resource_id)
834     : resource_provider_(resource_provider),
835       resource_id_(resource_id),
836       texture_id_(resource_provider->LockForWrite(resource_id)->gl_id) {
837   DCHECK(texture_id_);
838 }
839 
~ScopedWriteLockGL()840 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() {
841   resource_provider_->UnlockForWrite(resource_id_);
842 }
843 
PopulateSkBitmapWithResource(SkBitmap * sk_bitmap,const Resource * resource)844 void ResourceProvider::PopulateSkBitmapWithResource(
845     SkBitmap* sk_bitmap, const Resource* resource) {
846   DCHECK(resource->pixels);
847   DCHECK_EQ(RGBA_8888, resource->format);
848   sk_bitmap->setConfig(SkBitmap::kARGB_8888_Config,
849                        resource->size.width(),
850                        resource->size.height());
851   sk_bitmap->setPixels(resource->pixels);
852 }
853 
ScopedReadLockSoftware(ResourceProvider * resource_provider,ResourceProvider::ResourceId resource_id)854 ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(
855     ResourceProvider* resource_provider,
856     ResourceProvider::ResourceId resource_id)
857     : resource_provider_(resource_provider),
858       resource_id_(resource_id) {
859   const Resource* resource = resource_provider->LockForRead(resource_id);
860   wrap_mode_ = resource->wrap_mode;
861   ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource);
862 }
863 
~ScopedReadLockSoftware()864 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() {
865   resource_provider_->UnlockForRead(resource_id_);
866 }
867 
ScopedWriteLockSoftware(ResourceProvider * resource_provider,ResourceProvider::ResourceId resource_id)868 ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(
869     ResourceProvider* resource_provider,
870     ResourceProvider::ResourceId resource_id)
871     : resource_provider_(resource_provider),
872       resource_id_(resource_id) {
873   ResourceProvider::PopulateSkBitmapWithResource(
874       &sk_bitmap_, resource_provider->LockForWrite(resource_id));
875   sk_canvas_.reset(new SkCanvas(sk_bitmap_));
876 }
877 
~ScopedWriteLockSoftware()878 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() {
879   resource_provider_->UnlockForWrite(resource_id_);
880 }
881 
ResourceProvider(OutputSurface * output_surface,SharedBitmapManager * shared_bitmap_manager,int highp_threshold_min,bool use_rgba_4444_texture_format,size_t id_allocation_chunk_size)882 ResourceProvider::ResourceProvider(OutputSurface* output_surface,
883                                    SharedBitmapManager* shared_bitmap_manager,
884                                    int highp_threshold_min,
885                                    bool use_rgba_4444_texture_format,
886                                    size_t id_allocation_chunk_size)
887     : output_surface_(output_surface),
888       shared_bitmap_manager_(shared_bitmap_manager),
889       lost_output_surface_(false),
890       highp_threshold_min_(highp_threshold_min),
891       next_id_(1),
892       next_child_(1),
893       default_resource_type_(InvalidType),
894       use_texture_storage_ext_(false),
895       use_texture_usage_hint_(false),
896       use_compressed_texture_etc1_(false),
897       max_texture_size_(0),
898       best_texture_format_(RGBA_8888),
899       use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
900       id_allocation_chunk_size_(id_allocation_chunk_size) {
901   DCHECK(output_surface_->HasClient());
902   DCHECK(id_allocation_chunk_size_);
903 }
904 
InitializeSoftware()905 void ResourceProvider::InitializeSoftware() {
906   DCHECK(thread_checker_.CalledOnValidThread());
907   DCHECK_NE(Bitmap, default_resource_type_);
908 
909   CleanUpGLIfNeeded();
910 
911   default_resource_type_ = Bitmap;
912   // Pick an arbitrary limit here similar to what hardware might.
913   max_texture_size_ = 16 * 1024;
914   best_texture_format_ = RGBA_8888;
915 }
916 
InitializeGL()917 bool ResourceProvider::InitializeGL() {
918   DCHECK(thread_checker_.CalledOnValidThread());
919   DCHECK(!texture_uploader_);
920   DCHECK_NE(GLTexture, default_resource_type_);
921   DCHECK(!texture_id_allocator_);
922   DCHECK(!buffer_id_allocator_);
923 
924   default_resource_type_ = GLTexture;
925 
926   const ContextProvider::Capabilities& caps =
927       output_surface_->context_provider()->ContextCapabilities();
928 
929   bool use_bgra = caps.texture_format_bgra8888;
930   use_texture_storage_ext_ = caps.texture_storage;
931   use_texture_usage_hint_ = caps.texture_usage;
932   use_compressed_texture_etc1_ = caps.texture_format_etc1;
933 
934   GLES2Interface* gl = ContextGL();
935   DCHECK(gl);
936 
937   texture_uploader_ = TextureUploader::Create(gl);
938   max_texture_size_ = 0;  // Context expects cleared value.
939   GLC(gl, gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_));
940   best_texture_format_ = PlatformColor::BestTextureFormat(use_bgra);
941 
942   texture_id_allocator_.reset(
943       new TextureIdAllocator(gl, id_allocation_chunk_size_));
944   buffer_id_allocator_.reset(
945       new BufferIdAllocator(gl, id_allocation_chunk_size_));
946 
947   return true;
948 }
949 
CleanUpGLIfNeeded()950 void ResourceProvider::CleanUpGLIfNeeded() {
951   GLES2Interface* gl = ContextGL();
952   if (default_resource_type_ != GLTexture) {
953     // We are not in GL mode, but double check before returning.
954     DCHECK(!gl);
955     DCHECK(!texture_uploader_);
956     return;
957   }
958 
959   DCHECK(gl);
960   texture_uploader_.reset();
961   texture_id_allocator_.reset();
962   buffer_id_allocator_.reset();
963   Finish();
964 }
965 
CreateChild(const ReturnCallback & return_callback)966 int ResourceProvider::CreateChild(const ReturnCallback& return_callback) {
967   DCHECK(thread_checker_.CalledOnValidThread());
968 
969   Child child_info;
970   child_info.return_callback = return_callback;
971 
972   int child = next_child_++;
973   children_[child] = child_info;
974   return child;
975 }
976 
DestroyChild(int child_id)977 void ResourceProvider::DestroyChild(int child_id) {
978   ChildMap::iterator it = children_.find(child_id);
979   DCHECK(it != children_.end());
980   DestroyChildInternal(it, Normal);
981 }
982 
DestroyChildInternal(ChildMap::iterator it,DeleteStyle style)983 void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
984                                             DeleteStyle style) {
985   DCHECK(thread_checker_.CalledOnValidThread());
986 
987   Child& child = it->second;
988   DCHECK(style == ForShutdown || !child.marked_for_deletion);
989 
990   ResourceIdArray resources_for_child;
991 
992   for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin();
993        child_it != child.child_to_parent_map.end();
994        ++child_it) {
995     ResourceId id = child_it->second;
996     resources_for_child.push_back(id);
997   }
998 
999   // If the child is going away, don't consider any resources in use.
1000   child.in_use_resources.clear();
1001   child.marked_for_deletion = true;
1002 
1003   DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child);
1004 }
1005 
GetChildToParentMap(int child) const1006 const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap(
1007     int child) const {
1008   DCHECK(thread_checker_.CalledOnValidThread());
1009   ChildMap::const_iterator it = children_.find(child);
1010   DCHECK(it != children_.end());
1011   DCHECK(!it->second.marked_for_deletion);
1012   return it->second.child_to_parent_map;
1013 }
1014 
PrepareSendToParent(const ResourceIdArray & resources,TransferableResourceArray * list)1015 void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
1016                                            TransferableResourceArray* list) {
1017   DCHECK(thread_checker_.CalledOnValidThread());
1018   GLES2Interface* gl = ContextGL();
1019   bool need_sync_point = false;
1020   for (ResourceIdArray::const_iterator it = resources.begin();
1021        it != resources.end();
1022        ++it) {
1023     TransferableResource resource;
1024     TransferResource(gl, *it, &resource);
1025     if (!resource.sync_point && !resource.is_software)
1026       need_sync_point = true;
1027     ++resources_.find(*it)->second.exported_count;
1028     list->push_back(resource);
1029   }
1030   if (need_sync_point) {
1031     GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1032     for (TransferableResourceArray::iterator it = list->begin();
1033          it != list->end();
1034          ++it) {
1035       if (!it->sync_point)
1036         it->sync_point = sync_point;
1037     }
1038   }
1039 }
1040 
ReceiveFromChild(int child,const TransferableResourceArray & resources)1041 void ResourceProvider::ReceiveFromChild(
1042     int child, const TransferableResourceArray& resources) {
1043   DCHECK(thread_checker_.CalledOnValidThread());
1044   GLES2Interface* gl = ContextGL();
1045   Child& child_info = children_.find(child)->second;
1046   DCHECK(!child_info.marked_for_deletion);
1047   for (TransferableResourceArray::const_iterator it = resources.begin();
1048        it != resources.end();
1049        ++it) {
1050     ResourceIdMap::iterator resource_in_map_it =
1051         child_info.child_to_parent_map.find(it->id);
1052     if (resource_in_map_it != child_info.child_to_parent_map.end()) {
1053       resources_[resource_in_map_it->second].imported_count++;
1054       continue;
1055     }
1056 
1057     scoped_ptr<SharedBitmap> bitmap;
1058     uint8_t* pixels = NULL;
1059     if (it->is_software) {
1060       if (shared_bitmap_manager_)
1061         bitmap = shared_bitmap_manager_->GetSharedBitmapFromId(it->size,
1062                                                                it->mailbox);
1063       if (bitmap)
1064         pixels = bitmap->pixels();
1065     }
1066 
1067     if ((!it->is_software && !gl) || (it->is_software && !pixels)) {
1068       TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
1069       ReturnedResourceArray to_return;
1070       to_return.push_back(it->ToReturnedResource());
1071       child_info.return_callback.Run(to_return);
1072       continue;
1073     }
1074 
1075     ResourceId local_id = next_id_++;
1076     Resource& resource = resources_[local_id];
1077     if (it->is_software) {
1078       resource = Resource(
1079           pixels, bitmap.release(), it->size, GL_LINEAR, GL_CLAMP_TO_EDGE);
1080     } else {
1081       GLuint texture_id;
1082       // NOTE: If the parent is a browser and the child a renderer, the parent
1083       // is not supposed to have its context wait, because that could induce
1084       // deadlocks and/or security issues. The caller is responsible for
1085       // waiting asynchronously, and resetting sync_point before calling this.
1086       // However if the parent is a renderer (e.g. browser tag), it may be ok
1087       // (and is simpler) to wait.
1088       if (it->sync_point)
1089         GLC(gl, gl->WaitSyncPointCHROMIUM(it->sync_point));
1090       texture_id = texture_id_allocator_->NextId();
1091       GLC(gl, gl->BindTexture(it->target, texture_id));
1092       GLC(gl, gl->ConsumeTextureCHROMIUM(it->target, it->mailbox.name));
1093       resource = Resource(texture_id,
1094                           it->size,
1095                           it->target,
1096                           it->filter,
1097                           0,
1098                           GL_CLAMP_TO_EDGE,
1099                           TextureUsageAny,
1100                           it->format);
1101       resource.mailbox.SetName(it->mailbox);
1102     }
1103     resource.child_id = child;
1104     // Don't allocate a texture for a child.
1105     resource.allocated = true;
1106     resource.imported_count = 1;
1107     child_info.parent_to_child_map[local_id] = it->id;
1108     child_info.child_to_parent_map[it->id] = local_id;
1109   }
1110 }
1111 
DeclareUsedResourcesFromChild(int child,const ResourceIdArray & resources_from_child)1112 void ResourceProvider::DeclareUsedResourcesFromChild(
1113     int child,
1114     const ResourceIdArray& resources_from_child) {
1115   DCHECK(thread_checker_.CalledOnValidThread());
1116 
1117   ChildMap::iterator child_it = children_.find(child);
1118   DCHECK(child_it != children_.end());
1119   Child& child_info = child_it->second;
1120   DCHECK(!child_info.marked_for_deletion);
1121   child_info.in_use_resources.clear();
1122 
1123   for (size_t i = 0; i < resources_from_child.size(); ++i) {
1124     ResourceIdMap::iterator it =
1125         child_info.child_to_parent_map.find(resources_from_child[i]);
1126     DCHECK(it != child_info.child_to_parent_map.end());
1127 
1128     ResourceId local_id = it->second;
1129     child_info.in_use_resources.insert(local_id);
1130   }
1131 
1132   ResourceIdArray unused;
1133   for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin();
1134        it != child_info.child_to_parent_map.end();
1135        ++it) {
1136     ResourceId local_id = it->second;
1137     bool resource_is_in_use = child_info.in_use_resources.count(local_id) > 0;
1138     if (!resource_is_in_use)
1139       unused.push_back(local_id);
1140   }
1141   DeleteAndReturnUnusedResourcesToChild(child_it, Normal, unused);
1142 }
1143 
1144 // static
CompareResourceMapIteratorsByChildId(const std::pair<ReturnedResource,ResourceMap::iterator> & a,const std::pair<ReturnedResource,ResourceMap::iterator> & b)1145 bool ResourceProvider::CompareResourceMapIteratorsByChildId(
1146     const std::pair<ReturnedResource, ResourceMap::iterator>& a,
1147     const std::pair<ReturnedResource, ResourceMap::iterator>& b) {
1148   const ResourceMap::iterator& a_it = a.second;
1149   const ResourceMap::iterator& b_it = b.second;
1150   const Resource& a_resource = a_it->second;
1151   const Resource& b_resource = b_it->second;
1152   return a_resource.child_id < b_resource.child_id;
1153 }
1154 
ReceiveReturnsFromParent(const ReturnedResourceArray & resources)1155 void ResourceProvider::ReceiveReturnsFromParent(
1156     const ReturnedResourceArray& resources) {
1157   DCHECK(thread_checker_.CalledOnValidThread());
1158   GLES2Interface* gl = ContextGL();
1159 
1160   int child_id = 0;
1161   ResourceIdArray resources_for_child;
1162 
1163   std::vector<std::pair<ReturnedResource, ResourceMap::iterator> >
1164       sorted_resources;
1165 
1166   for (ReturnedResourceArray::const_iterator it = resources.begin();
1167        it != resources.end();
1168        ++it) {
1169     ResourceId local_id = it->id;
1170     ResourceMap::iterator map_iterator = resources_.find(local_id);
1171 
1172     // Resource was already lost (e.g. it belonged to a child that was
1173     // destroyed).
1174     if (map_iterator == resources_.end())
1175       continue;
1176 
1177     sorted_resources.push_back(
1178         std::pair<ReturnedResource, ResourceMap::iterator>(*it, map_iterator));
1179   }
1180 
1181   std::sort(sorted_resources.begin(),
1182             sorted_resources.end(),
1183             CompareResourceMapIteratorsByChildId);
1184 
1185   ChildMap::iterator child_it = children_.end();
1186   for (size_t i = 0; i < sorted_resources.size(); ++i) {
1187     ReturnedResource& returned = sorted_resources[i].first;
1188     ResourceMap::iterator& map_iterator = sorted_resources[i].second;
1189     ResourceId local_id = map_iterator->first;
1190     Resource* resource = &map_iterator->second;
1191 
1192     CHECK_GE(resource->exported_count, returned.count);
1193     resource->exported_count -= returned.count;
1194     resource->lost |= returned.lost;
1195     if (resource->exported_count)
1196       continue;
1197 
1198     if (resource->gl_id) {
1199       if (returned.sync_point)
1200         GLC(gl, gl->WaitSyncPointCHROMIUM(returned.sync_point));
1201     } else if (!resource->shared_bitmap) {
1202       resource->mailbox =
1203           TextureMailbox(resource->mailbox.name(), returned.sync_point);
1204     }
1205 
1206     if (!resource->marked_for_deletion)
1207       continue;
1208 
1209     if (!resource->child_id) {
1210       // The resource belongs to this ResourceProvider, so it can be destroyed.
1211       DeleteResourceInternal(map_iterator, Normal);
1212       continue;
1213     }
1214 
1215     // Delete the resource and return it to the child it came from one.
1216     if (resource->child_id != child_id) {
1217       if (child_id) {
1218         DCHECK_NE(resources_for_child.size(), 0u);
1219         DCHECK(child_it != children_.end());
1220         DeleteAndReturnUnusedResourcesToChild(
1221             child_it, Normal, resources_for_child);
1222         resources_for_child.clear();
1223       }
1224 
1225       child_it = children_.find(resource->child_id);
1226       DCHECK(child_it != children_.end());
1227       child_id = resource->child_id;
1228     }
1229     resources_for_child.push_back(local_id);
1230   }
1231 
1232   if (child_id) {
1233     DCHECK_NE(resources_for_child.size(), 0u);
1234     DCHECK(child_it != children_.end());
1235     DeleteAndReturnUnusedResourcesToChild(
1236         child_it, Normal, resources_for_child);
1237   }
1238 }
1239 
TransferResource(GLES2Interface * gl,ResourceId id,TransferableResource * resource)1240 void ResourceProvider::TransferResource(GLES2Interface* gl,
1241                                         ResourceId id,
1242                                         TransferableResource* resource) {
1243   Resource* source = GetResource(id);
1244   DCHECK(!source->locked_for_write);
1245   DCHECK(!source->lock_for_read_count);
1246   DCHECK(!source->external || (source->external && source->mailbox.IsValid()));
1247   DCHECK(source->allocated);
1248   DCHECK_EQ(source->wrap_mode, GL_CLAMP_TO_EDGE);
1249   resource->id = id;
1250   resource->format = source->format;
1251   resource->target = source->target;
1252   resource->filter = source->filter;
1253   resource->size = source->size;
1254 
1255   if (source->shared_bitmap) {
1256     resource->mailbox = source->shared_bitmap->id();
1257     resource->is_software = true;
1258   } else if (!source->mailbox.IsValid()) {
1259     // This is a resource allocated by the compositor, we need to produce it.
1260     // Don't set a sync point, the caller will do it.
1261     DCHECK(source->gl_id);
1262     GLC(gl, gl->BindTexture(resource->target, source->gl_id));
1263     GLC(gl, gl->GenMailboxCHROMIUM(resource->mailbox.name));
1264     GLC(gl,
1265         gl->ProduceTextureCHROMIUM(resource->target, resource->mailbox.name));
1266     source->mailbox.SetName(resource->mailbox);
1267   } else {
1268     DCHECK(source->mailbox.IsTexture());
1269     // This is either an external resource, or a compositor resource that we
1270     // already exported. Make sure to forward the sync point that we were given.
1271     resource->mailbox = source->mailbox.name();
1272     resource->sync_point = source->mailbox.sync_point();
1273     source->mailbox.ResetSyncPoint();
1274   }
1275 }
1276 
DeleteAndReturnUnusedResourcesToChild(ChildMap::iterator child_it,DeleteStyle style,const ResourceIdArray & unused)1277 void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
1278     ChildMap::iterator child_it,
1279     DeleteStyle style,
1280     const ResourceIdArray& unused) {
1281   DCHECK(thread_checker_.CalledOnValidThread());
1282   DCHECK(child_it != children_.end());
1283   Child* child_info = &child_it->second;
1284 
1285   if (unused.empty() && !child_info->marked_for_deletion)
1286     return;
1287 
1288   ReturnedResourceArray to_return;
1289 
1290   GLES2Interface* gl = ContextGL();
1291   bool need_sync_point = false;
1292   for (size_t i = 0; i < unused.size(); ++i) {
1293     ResourceId local_id = unused[i];
1294 
1295     ResourceMap::iterator it = resources_.find(local_id);
1296     CHECK(it != resources_.end());
1297     Resource& resource = it->second;
1298 
1299     DCHECK(!resource.locked_for_write);
1300     DCHECK(!resource.lock_for_read_count);
1301     DCHECK_EQ(0u, child_info->in_use_resources.count(local_id));
1302     DCHECK(child_info->parent_to_child_map.count(local_id));
1303 
1304     ResourceId child_id = child_info->parent_to_child_map[local_id];
1305     DCHECK(child_info->child_to_parent_map.count(child_id));
1306 
1307     bool is_lost =
1308         resource.lost || (!resource.shared_bitmap && lost_output_surface_);
1309     if (resource.exported_count > 0) {
1310       if (style != ForShutdown) {
1311         // Defer this until we receive the resource back from the parent.
1312         resource.marked_for_deletion = true;
1313         continue;
1314       }
1315 
1316       // We still have an exported_count, so we'll have to lose it.
1317       is_lost = true;
1318     }
1319 
1320     if (gl && resource.filter != resource.original_filter) {
1321       DCHECK(resource.target);
1322       DCHECK(resource.gl_id);
1323 
1324       GLC(gl, gl->BindTexture(resource.target, resource.gl_id));
1325       GLC(gl,
1326           gl->TexParameteri(resource.target,
1327                             GL_TEXTURE_MIN_FILTER,
1328                             resource.original_filter));
1329       GLC(gl,
1330           gl->TexParameteri(resource.target,
1331                             GL_TEXTURE_MAG_FILTER,
1332                             resource.original_filter));
1333     }
1334 
1335     ReturnedResource returned;
1336     returned.id = child_id;
1337     returned.sync_point = resource.mailbox.sync_point();
1338     if (!returned.sync_point && !resource.shared_bitmap)
1339       need_sync_point = true;
1340     returned.count = resource.imported_count;
1341     returned.lost = is_lost;
1342     to_return.push_back(returned);
1343 
1344     child_info->parent_to_child_map.erase(local_id);
1345     child_info->child_to_parent_map.erase(child_id);
1346     resource.imported_count = 0;
1347     DeleteResourceInternal(it, style);
1348   }
1349   if (need_sync_point) {
1350     DCHECK(gl);
1351     GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1352     for (size_t i = 0; i < to_return.size(); ++i) {
1353       if (!to_return[i].sync_point)
1354         to_return[i].sync_point = sync_point;
1355     }
1356   }
1357 
1358   if (!to_return.empty())
1359     child_info->return_callback.Run(to_return);
1360 
1361   if (child_info->marked_for_deletion &&
1362       child_info->parent_to_child_map.empty()) {
1363     DCHECK(child_info->child_to_parent_map.empty());
1364     children_.erase(child_it);
1365   }
1366 }
1367 
AcquirePixelBuffer(ResourceId id)1368 void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
1369   Resource* resource = GetResource(id);
1370   DCHECK(!resource->external);
1371   DCHECK_EQ(resource->exported_count, 0);
1372   DCHECK(!resource->image_id);
1373   DCHECK_NE(ETC1, resource->format);
1374 
1375   if (resource->type == GLTexture) {
1376     GLES2Interface* gl = ContextGL();
1377     DCHECK(gl);
1378     if (!resource->gl_pixel_buffer_id)
1379       resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId();
1380     gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1381                    resource->gl_pixel_buffer_id);
1382     unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8;
1383     gl->BufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1384                    resource->size.height() *
1385                        RoundUp(bytes_per_pixel * resource->size.width(), 4u),
1386                    NULL,
1387                    GL_DYNAMIC_DRAW);
1388     gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1389   }
1390 
1391   if (resource->pixels) {
1392     if (resource->pixel_buffer)
1393       return;
1394 
1395     resource->pixel_buffer = new uint8_t[4 * resource->size.GetArea()];
1396   }
1397 }
1398 
ReleasePixelBuffer(ResourceId id)1399 void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
1400   Resource* resource = GetResource(id);
1401   DCHECK(!resource->external);
1402   DCHECK_EQ(resource->exported_count, 0);
1403   DCHECK(!resource->image_id);
1404 
1405   // The pixel buffer can be released while there is a pending "set pixels"
1406   // if completion has been forced. Any shared memory associated with this
1407   // pixel buffer will not be freed until the waitAsyncTexImage2DCHROMIUM
1408   // command has been processed on the service side. It is also safe to
1409   // reuse any query id associated with this resource before they complete
1410   // as each new query has a unique submit count.
1411   if (resource->pending_set_pixels) {
1412     DCHECK(resource->set_pixels_completion_forced);
1413     resource->pending_set_pixels = false;
1414     UnlockForWrite(id);
1415   }
1416 
1417   if (resource->type == GLTexture) {
1418     if (!resource->gl_pixel_buffer_id)
1419       return;
1420     GLES2Interface* gl = ContextGL();
1421     DCHECK(gl);
1422     gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1423                    resource->gl_pixel_buffer_id);
1424     gl->BufferData(
1425         GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW);
1426     gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1427   }
1428 
1429   if (resource->pixels) {
1430     if (!resource->pixel_buffer)
1431       return;
1432     delete[] resource->pixel_buffer;
1433     resource->pixel_buffer = NULL;
1434   }
1435 }
1436 
MapPixelBuffer(ResourceId id)1437 uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id) {
1438   Resource* resource = GetResource(id);
1439   DCHECK(!resource->external);
1440   DCHECK_EQ(resource->exported_count, 0);
1441   DCHECK(!resource->image_id);
1442 
1443   if (resource->type == GLTexture) {
1444     GLES2Interface* gl = ContextGL();
1445     DCHECK(gl);
1446     DCHECK(resource->gl_pixel_buffer_id);
1447     gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1448                    resource->gl_pixel_buffer_id);
1449     uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
1450         GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
1451     gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1452     // Buffer is required to be 4-byte aligned.
1453     CHECK(!(reinterpret_cast<intptr_t>(image) & 3));
1454     return image;
1455   }
1456 
1457   if (resource->pixels)
1458     return resource->pixel_buffer;
1459 
1460   return NULL;
1461 }
1462 
UnmapPixelBuffer(ResourceId id)1463 void ResourceProvider::UnmapPixelBuffer(ResourceId id) {
1464   Resource* resource = GetResource(id);
1465   DCHECK(!resource->external);
1466   DCHECK_EQ(resource->exported_count, 0);
1467   DCHECK(!resource->image_id);
1468 
1469   if (resource->type == GLTexture) {
1470     GLES2Interface* gl = ContextGL();
1471     DCHECK(gl);
1472     DCHECK(resource->gl_pixel_buffer_id);
1473     gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1474                    resource->gl_pixel_buffer_id);
1475     gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
1476     gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1477   }
1478 }
1479 
BindForSampling(ResourceProvider::ResourceId resource_id,GLenum unit,GLenum filter)1480 GLenum ResourceProvider::BindForSampling(
1481     ResourceProvider::ResourceId resource_id,
1482     GLenum unit,
1483     GLenum filter) {
1484   DCHECK(thread_checker_.CalledOnValidThread());
1485   GLES2Interface* gl = ContextGL();
1486   ResourceMap::iterator it = resources_.find(resource_id);
1487   DCHECK(it != resources_.end());
1488   Resource* resource = &it->second;
1489   DCHECK(resource->lock_for_read_count);
1490   DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced);
1491 
1492   ScopedSetActiveTexture scoped_active_tex(gl, unit);
1493   GLenum target = resource->target;
1494   GLC(gl, gl->BindTexture(target, resource->gl_id));
1495   if (filter != resource->filter) {
1496     GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter));
1497     GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter));
1498     resource->filter = filter;
1499   }
1500 
1501   if (resource->image_id && resource->dirty_image) {
1502     // Release image currently bound to texture.
1503     if (resource->bound_image_id)
1504       gl->ReleaseTexImage2DCHROMIUM(target, resource->bound_image_id);
1505     gl->BindTexImage2DCHROMIUM(target, resource->image_id);
1506     resource->bound_image_id = resource->image_id;
1507     resource->dirty_image = false;
1508   }
1509 
1510   return target;
1511 }
1512 
BeginSetPixels(ResourceId id)1513 void ResourceProvider::BeginSetPixels(ResourceId id) {
1514   Resource* resource = GetResource(id);
1515   DCHECK(!resource->pending_set_pixels);
1516 
1517   LazyCreate(resource);
1518   DCHECK(resource->gl_id || resource->allocated);
1519   DCHECK(ReadLockFenceHasPassed(resource));
1520   DCHECK(!resource->image_id);
1521 
1522   bool allocate = !resource->allocated;
1523   resource->allocated = true;
1524   LockForWrite(id);
1525 
1526   if (resource->gl_id) {
1527     GLES2Interface* gl = ContextGL();
1528     DCHECK(gl);
1529     DCHECK(resource->gl_pixel_buffer_id);
1530     DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
1531     gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1532     gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1533                    resource->gl_pixel_buffer_id);
1534     if (!resource->gl_upload_query_id)
1535       gl->GenQueriesEXT(1, &resource->gl_upload_query_id);
1536     gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM,
1537                       resource->gl_upload_query_id);
1538     if (allocate) {
1539       gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D,
1540                                   0, /* level */
1541                                   GLInternalFormat(resource->format),
1542                                   resource->size.width(),
1543                                   resource->size.height(),
1544                                   0, /* border */
1545                                   GLDataFormat(resource->format),
1546                                   GLDataType(resource->format),
1547                                   NULL);
1548     } else {
1549       gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D,
1550                                      0, /* level */
1551                                      0, /* x */
1552                                      0, /* y */
1553                                      resource->size.width(),
1554                                      resource->size.height(),
1555                                      GLDataFormat(resource->format),
1556                                      GLDataType(resource->format),
1557                                      NULL);
1558     }
1559     gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM);
1560     gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1561   }
1562 
1563   if (resource->pixels) {
1564     DCHECK(!resource->mailbox.IsValid());
1565     DCHECK(resource->pixel_buffer);
1566     DCHECK_EQ(RGBA_8888, resource->format);
1567 
1568     std::swap(resource->pixels, resource->pixel_buffer);
1569     delete[] resource->pixel_buffer;
1570     resource->pixel_buffer = NULL;
1571   }
1572 
1573   resource->pending_set_pixels = true;
1574   resource->set_pixels_completion_forced = false;
1575 }
1576 
ForceSetPixelsToComplete(ResourceId id)1577 void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) {
1578   Resource* resource = GetResource(id);
1579   DCHECK(resource->locked_for_write);
1580   DCHECK(resource->pending_set_pixels);
1581   DCHECK(!resource->set_pixels_completion_forced);
1582 
1583   if (resource->gl_id) {
1584     GLES2Interface* gl = ContextGL();
1585     GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id));
1586     GLC(gl, gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D));
1587     GLC(gl, gl->BindTexture(GL_TEXTURE_2D, 0));
1588   }
1589 
1590   resource->set_pixels_completion_forced = true;
1591 }
1592 
DidSetPixelsComplete(ResourceId id)1593 bool ResourceProvider::DidSetPixelsComplete(ResourceId id) {
1594   Resource* resource = GetResource(id);
1595   DCHECK(resource->locked_for_write);
1596   DCHECK(resource->pending_set_pixels);
1597 
1598   if (resource->gl_id) {
1599     GLES2Interface* gl = ContextGL();
1600     DCHECK(gl);
1601     DCHECK(resource->gl_upload_query_id);
1602     GLuint complete = 1;
1603     gl->GetQueryObjectuivEXT(
1604         resource->gl_upload_query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete);
1605     if (!complete)
1606       return false;
1607   }
1608 
1609   resource->pending_set_pixels = false;
1610   UnlockForWrite(id);
1611 
1612   return true;
1613 }
1614 
CreateForTesting(ResourceId id)1615 void ResourceProvider::CreateForTesting(ResourceId id) {
1616   LazyCreate(GetResource(id));
1617 }
1618 
TargetForTesting(ResourceId id)1619 GLenum ResourceProvider::TargetForTesting(ResourceId id) {
1620   Resource* resource = GetResource(id);
1621   return resource->target;
1622 }
1623 
LazyCreate(Resource * resource)1624 void ResourceProvider::LazyCreate(Resource* resource) {
1625   if (resource->type != GLTexture || resource->gl_id != 0)
1626     return;
1627 
1628   // Early out for resources that don't require texture creation.
1629   if (resource->texture_pool == 0)
1630     return;
1631 
1632   resource->gl_id = texture_id_allocator_->NextId();
1633 
1634   GLES2Interface* gl = ContextGL();
1635   DCHECK(gl);
1636 
1637   // Create and set texture properties. Allocation is delayed until needed.
1638   GLC(gl, gl->BindTexture(resource->target, resource->gl_id));
1639   GLC(gl,
1640       gl->TexParameteri(resource->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
1641   GLC(gl,
1642       gl->TexParameteri(resource->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
1643   GLC(gl,
1644       gl->TexParameteri(
1645           resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode));
1646   GLC(gl,
1647       gl->TexParameteri(
1648           resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode));
1649   GLC(gl,
1650       gl->TexParameteri(
1651           resource->target, GL_TEXTURE_POOL_CHROMIUM, resource->texture_pool));
1652   if (use_texture_usage_hint_ && resource->hint == TextureUsageFramebuffer) {
1653     GLC(gl,
1654         gl->TexParameteri(resource->target,
1655                           GL_TEXTURE_USAGE_ANGLE,
1656                           GL_FRAMEBUFFER_ATTACHMENT_ANGLE));
1657   }
1658 }
1659 
AllocateForTesting(ResourceId id)1660 void ResourceProvider::AllocateForTesting(ResourceId id) {
1661   LazyAllocate(GetResource(id));
1662 }
1663 
LazyAllocate(Resource * resource)1664 void ResourceProvider::LazyAllocate(Resource* resource) {
1665   DCHECK(resource);
1666   LazyCreate(resource);
1667 
1668   DCHECK(resource->gl_id || resource->allocated);
1669   if (resource->allocated || !resource->gl_id)
1670     return;
1671   resource->allocated = true;
1672   GLES2Interface* gl = ContextGL();
1673   gfx::Size& size = resource->size;
1674   DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
1675   ResourceFormat format = resource->format;
1676   GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id));
1677   if (use_texture_storage_ext_ && IsFormatSupportedForStorage(format) &&
1678       resource->hint != TextureUsageFramebuffer) {
1679     GLenum storage_format = TextureToStorageFormat(format);
1680     GLC(gl,
1681         gl->TexStorage2DEXT(
1682             GL_TEXTURE_2D, 1, storage_format, size.width(), size.height()));
1683   } else {
1684     // ETC1 does not support preallocation.
1685     if (format != ETC1) {
1686       GLC(gl,
1687           gl->TexImage2D(GL_TEXTURE_2D,
1688                          0,
1689                          GLInternalFormat(format),
1690                          size.width(),
1691                          size.height(),
1692                          0,
1693                          GLDataFormat(format),
1694                          GLDataType(format),
1695                          NULL));
1696     }
1697   }
1698 }
1699 
EnableReadLockFences(ResourceProvider::ResourceId id,bool enable)1700 void ResourceProvider::EnableReadLockFences(ResourceProvider::ResourceId id,
1701                                             bool enable) {
1702   Resource* resource = GetResource(id);
1703   resource->enable_read_lock_fences = enable;
1704 }
1705 
AcquireImage(ResourceId id)1706 void ResourceProvider::AcquireImage(ResourceId id) {
1707   Resource* resource = GetResource(id);
1708   DCHECK(!resource->external);
1709   DCHECK_EQ(resource->exported_count, 0);
1710 
1711   if (resource->type != GLTexture)
1712     return;
1713 
1714   if (resource->image_id)
1715     return;
1716 
1717   resource->allocated = true;
1718   GLES2Interface* gl = ContextGL();
1719   DCHECK(gl);
1720   resource->image_id =
1721       gl->CreateImageCHROMIUM(resource->size.width(),
1722                               resource->size.height(),
1723                               TextureToStorageFormat(resource->format));
1724   DCHECK(resource->image_id);
1725 }
1726 
ReleaseImage(ResourceId id)1727 void ResourceProvider::ReleaseImage(ResourceId id) {
1728   Resource* resource = GetResource(id);
1729   DCHECK(!resource->external);
1730   DCHECK_EQ(resource->exported_count, 0);
1731 
1732   if (!resource->image_id)
1733     return;
1734 
1735   GLES2Interface* gl = ContextGL();
1736   DCHECK(gl);
1737   gl->DestroyImageCHROMIUM(resource->image_id);
1738   resource->image_id = 0;
1739   resource->bound_image_id = 0;
1740   resource->dirty_image = false;
1741   resource->allocated = false;
1742 }
1743 
MapImage(ResourceId id)1744 uint8_t* ResourceProvider::MapImage(ResourceId id) {
1745   Resource* resource = GetResource(id);
1746   DCHECK(ReadLockFenceHasPassed(resource));
1747   DCHECK(!resource->external);
1748   DCHECK_EQ(resource->exported_count, 0);
1749 
1750   if (resource->image_id) {
1751     GLES2Interface* gl = ContextGL();
1752     DCHECK(gl);
1753     return static_cast<uint8_t*>(
1754         gl->MapImageCHROMIUM(resource->image_id, GL_READ_WRITE));
1755   }
1756 
1757   if (resource->pixels)
1758     return resource->pixels;
1759 
1760   return NULL;
1761 }
1762 
UnmapImage(ResourceId id)1763 void ResourceProvider::UnmapImage(ResourceId id) {
1764   Resource* resource = GetResource(id);
1765   DCHECK(!resource->external);
1766   DCHECK_EQ(resource->exported_count, 0);
1767 
1768   if (resource->image_id) {
1769     GLES2Interface* gl = ContextGL();
1770     DCHECK(gl);
1771     gl->UnmapImageCHROMIUM(resource->image_id);
1772     resource->dirty_image = true;
1773   }
1774 }
1775 
GetImageStride(ResourceId id)1776 int ResourceProvider::GetImageStride(ResourceId id) {
1777   Resource* resource = GetResource(id);
1778   DCHECK(!resource->external);
1779   DCHECK_EQ(resource->exported_count, 0);
1780 
1781   int stride = 0;
1782 
1783   if (resource->image_id) {
1784     GLES2Interface* gl = ContextGL();
1785     DCHECK(gl);
1786     gl->GetImageParameterivCHROMIUM(
1787         resource->image_id, GL_IMAGE_ROWBYTES_CHROMIUM, &stride);
1788   }
1789 
1790   return stride;
1791 }
1792 
GetSharedMemory(ResourceId id)1793 base::SharedMemory* ResourceProvider::GetSharedMemory(ResourceId id) {
1794   Resource* resource = GetResource(id);
1795   DCHECK(!resource->external);
1796   DCHECK_EQ(resource->exported_count, 0);
1797 
1798   if (!resource->shared_bitmap)
1799     return NULL;
1800   return resource->shared_bitmap->memory();
1801 }
1802 
GetActiveTextureUnit(GLES2Interface * gl)1803 GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) {
1804   GLint active_unit = 0;
1805   gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
1806   return active_unit;
1807 }
1808 
ContextGL() const1809 GLES2Interface* ResourceProvider::ContextGL() const {
1810   ContextProvider* context_provider = output_surface_->context_provider();
1811   return context_provider ? context_provider->ContextGL() : NULL;
1812 }
1813 
1814 }  // namespace cc
1815