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