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