GPU workaround to simulate Out of Memory errors with large textures
[chromium-blink-merge.git] / cc / resources / resource_provider.cc
blob5428c940150edecf78004c6f99223d5b9b18d474
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.
5 #include "cc/resources/resource_provider.h"
7 #include <algorithm>
8 #include <limits>
10 #include "base/containers/hash_tables.h"
11 #include "base/metrics/histogram.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/string_util.h"
15 #include "base/trace_event/trace_event.h"
16 #include "cc/base/util.h"
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/texture_uploader.h"
21 #include "cc/resources/transferable_resource.h"
22 #include "gpu/GLES2/gl2extchromium.h"
23 #include "gpu/command_buffer/client/gles2_interface.h"
24 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
25 #include "third_party/khronos/GLES2/gl2.h"
26 #include "third_party/khronos/GLES2/gl2ext.h"
27 #include "third_party/skia/include/core/SkSurface.h"
28 #include "third_party/skia/include/gpu/GrContext.h"
29 #include "ui/gfx/frame_time.h"
30 #include "ui/gfx/geometry/rect.h"
31 #include "ui/gfx/geometry/vector2d.h"
32 #include "ui/gfx/gpu_memory_buffer.h"
34 using gpu::gles2::GLES2Interface;
36 namespace cc {
38 class IdAllocator {
39 public:
40 virtual ~IdAllocator() {}
42 virtual GLuint NextId() = 0;
44 protected:
45 IdAllocator(GLES2Interface* gl, size_t id_allocation_chunk_size)
46 : gl_(gl),
47 id_allocation_chunk_size_(id_allocation_chunk_size),
48 ids_(new GLuint[id_allocation_chunk_size]),
49 next_id_index_(id_allocation_chunk_size) {
50 DCHECK(id_allocation_chunk_size_);
53 GLES2Interface* gl_;
54 const size_t id_allocation_chunk_size_;
55 scoped_ptr<GLuint[]> ids_;
56 size_t next_id_index_;
59 namespace {
61 // Measured in seconds.
62 const double kSoftwareUploadTickRate = 0.000250;
63 const double kTextureUploadTickRate = 0.004;
65 GLenum TextureToStorageFormat(ResourceFormat format) {
66 GLenum storage_format = GL_RGBA8_OES;
67 switch (format) {
68 case RGBA_8888:
69 break;
70 case BGRA_8888:
71 storage_format = GL_BGRA8_EXT;
72 break;
73 case RGBA_4444:
74 case ALPHA_8:
75 case LUMINANCE_8:
76 case RGB_565:
77 case ETC1:
78 case RED_8:
79 NOTREACHED();
80 break;
83 return storage_format;
86 bool IsFormatSupportedForStorage(ResourceFormat format, bool use_bgra) {
87 switch (format) {
88 case RGBA_8888:
89 return true;
90 case BGRA_8888:
91 return use_bgra;
92 case RGBA_4444:
93 case ALPHA_8:
94 case LUMINANCE_8:
95 case RGB_565:
96 case ETC1:
97 case RED_8:
98 return false;
100 return false;
103 GrPixelConfig ToGrPixelConfig(ResourceFormat format) {
104 switch (format) {
105 case RGBA_8888:
106 return kRGBA_8888_GrPixelConfig;
107 case BGRA_8888:
108 return kBGRA_8888_GrPixelConfig;
109 case RGBA_4444:
110 return kRGBA_4444_GrPixelConfig;
111 default:
112 break;
114 DCHECK(false) << "Unsupported resource format.";
115 return kSkia8888_GrPixelConfig;
118 gfx::GpuMemoryBuffer::Format ToGpuMemoryBufferFormat(ResourceFormat format) {
119 switch (format) {
120 case RGBA_8888:
121 return gfx::GpuMemoryBuffer::Format::RGBA_8888;
122 case BGRA_8888:
123 return gfx::GpuMemoryBuffer::Format::BGRA_8888;
124 case RGBA_4444:
125 case ALPHA_8:
126 case LUMINANCE_8:
127 case RGB_565:
128 case ETC1:
129 case RED_8:
130 break;
132 NOTREACHED();
133 return gfx::GpuMemoryBuffer::Format::RGBA_8888;
136 class ScopedSetActiveTexture {
137 public:
138 ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit)
139 : gl_(gl), unit_(unit) {
140 DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_));
142 if (unit_ != GL_TEXTURE0)
143 gl_->ActiveTexture(unit_);
146 ~ScopedSetActiveTexture() {
147 // Active unit being GL_TEXTURE0 is effectively the ground state.
148 if (unit_ != GL_TEXTURE0)
149 gl_->ActiveTexture(GL_TEXTURE0);
152 private:
153 GLES2Interface* gl_;
154 GLenum unit_;
157 class TextureIdAllocator : public IdAllocator {
158 public:
159 TextureIdAllocator(GLES2Interface* gl,
160 size_t texture_id_allocation_chunk_size)
161 : IdAllocator(gl, texture_id_allocation_chunk_size) {}
162 ~TextureIdAllocator() override {
163 gl_->DeleteTextures(id_allocation_chunk_size_ - next_id_index_,
164 ids_.get() + next_id_index_);
167 // Overridden from IdAllocator:
168 GLuint NextId() override {
169 if (next_id_index_ == id_allocation_chunk_size_) {
170 gl_->GenTextures(id_allocation_chunk_size_, ids_.get());
171 next_id_index_ = 0;
174 return ids_[next_id_index_++];
177 private:
178 DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator);
181 class BufferIdAllocator : public IdAllocator {
182 public:
183 BufferIdAllocator(GLES2Interface* gl, size_t buffer_id_allocation_chunk_size)
184 : IdAllocator(gl, buffer_id_allocation_chunk_size) {}
185 ~BufferIdAllocator() override {
186 gl_->DeleteBuffers(id_allocation_chunk_size_ - next_id_index_,
187 ids_.get() + next_id_index_);
190 // Overridden from IdAllocator:
191 GLuint NextId() override {
192 if (next_id_index_ == id_allocation_chunk_size_) {
193 gl_->GenBuffers(id_allocation_chunk_size_, ids_.get());
194 next_id_index_ = 0;
197 return ids_[next_id_index_++];
200 private:
201 DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator);
204 // Query object based fence implementation used to detect completion of copy
205 // texture operations. Fence has passed when query result is available.
206 class CopyTextureFence : public ResourceProvider::Fence {
207 public:
208 CopyTextureFence(gpu::gles2::GLES2Interface* gl, unsigned query_id)
209 : gl_(gl), query_id_(query_id) {}
211 // Overridden from ResourceProvider::Fence:
212 void Set() override {}
213 bool HasPassed() override {
214 unsigned available = 1;
215 gl_->GetQueryObjectuivEXT(
216 query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
217 if (!available)
218 return false;
220 ProcessResult();
221 return true;
223 void Wait() override {
224 // ProcessResult() will wait for result to become available.
225 ProcessResult();
228 private:
229 ~CopyTextureFence() override {}
231 void ProcessResult() {
232 unsigned time_elapsed_us = 0;
233 gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &time_elapsed_us);
234 UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.CopyTextureLatency", time_elapsed_us,
235 0, 256000, 50);
238 gpu::gles2::GLES2Interface* gl_;
239 unsigned query_id_;
241 DISALLOW_COPY_AND_ASSIGN(CopyTextureFence);
244 } // namespace
246 ResourceProvider::Resource::Resource()
247 : child_id(0),
248 gl_id(0),
249 gl_pixel_buffer_id(0),
250 gl_upload_query_id(0),
251 gl_read_lock_query_id(0),
252 pixels(NULL),
253 lock_for_read_count(0),
254 imported_count(0),
255 exported_count(0),
256 dirty_image(false),
257 locked_for_write(false),
258 lost(false),
259 marked_for_deletion(false),
260 pending_set_pixels(false),
261 set_pixels_completion_forced(false),
262 allocated(false),
263 read_lock_fences_enabled(false),
264 has_shared_bitmap_id(false),
265 allow_overlay(false),
266 read_lock_fence(NULL),
267 size(),
268 origin(INTERNAL),
269 target(0),
270 original_filter(0),
271 filter(0),
272 image_id(0),
273 bound_image_id(0),
274 texture_pool(0),
275 wrap_mode(0),
276 hint(TEXTURE_HINT_IMMUTABLE),
277 type(RESOURCE_TYPE_INVALID),
278 format(RGBA_8888),
279 shared_bitmap(NULL),
280 gpu_memory_buffer(NULL) {
283 ResourceProvider::Resource::~Resource() {}
285 ResourceProvider::Resource::Resource(GLuint texture_id,
286 const gfx::Size& size,
287 Origin origin,
288 GLenum target,
289 GLenum filter,
290 GLenum texture_pool,
291 GLint wrap_mode,
292 TextureHint hint,
293 ResourceFormat format)
294 : child_id(0),
295 gl_id(texture_id),
296 gl_pixel_buffer_id(0),
297 gl_upload_query_id(0),
298 gl_read_lock_query_id(0),
299 pixels(NULL),
300 lock_for_read_count(0),
301 imported_count(0),
302 exported_count(0),
303 dirty_image(false),
304 locked_for_write(false),
305 lost(false),
306 marked_for_deletion(false),
307 pending_set_pixels(false),
308 set_pixels_completion_forced(false),
309 allocated(false),
310 read_lock_fences_enabled(false),
311 has_shared_bitmap_id(false),
312 allow_overlay(false),
313 read_lock_fence(NULL),
314 size(size),
315 origin(origin),
316 target(target),
317 original_filter(filter),
318 filter(filter),
319 image_id(0),
320 bound_image_id(0),
321 texture_pool(texture_pool),
322 wrap_mode(wrap_mode),
323 hint(hint),
324 type(RESOURCE_TYPE_GL_TEXTURE),
325 format(format),
326 shared_bitmap(NULL),
327 gpu_memory_buffer(NULL) {
328 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
329 DCHECK_EQ(origin == INTERNAL, !!texture_pool);
332 ResourceProvider::Resource::Resource(uint8_t* pixels,
333 SharedBitmap* bitmap,
334 const gfx::Size& size,
335 Origin origin,
336 GLenum filter,
337 GLint wrap_mode)
338 : child_id(0),
339 gl_id(0),
340 gl_pixel_buffer_id(0),
341 gl_upload_query_id(0),
342 gl_read_lock_query_id(0),
343 pixels(pixels),
344 lock_for_read_count(0),
345 imported_count(0),
346 exported_count(0),
347 dirty_image(false),
348 locked_for_write(false),
349 lost(false),
350 marked_for_deletion(false),
351 pending_set_pixels(false),
352 set_pixels_completion_forced(false),
353 allocated(false),
354 read_lock_fences_enabled(false),
355 has_shared_bitmap_id(!!bitmap),
356 allow_overlay(false),
357 read_lock_fence(NULL),
358 size(size),
359 origin(origin),
360 target(0),
361 original_filter(filter),
362 filter(filter),
363 image_id(0),
364 bound_image_id(0),
365 texture_pool(0),
366 wrap_mode(wrap_mode),
367 hint(TEXTURE_HINT_IMMUTABLE),
368 type(RESOURCE_TYPE_BITMAP),
369 format(RGBA_8888),
370 shared_bitmap(bitmap),
371 gpu_memory_buffer(NULL) {
372 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
373 DCHECK(origin == DELEGATED || pixels);
374 if (bitmap)
375 shared_bitmap_id = bitmap->id();
378 ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id,
379 const gfx::Size& size,
380 Origin origin,
381 GLenum filter,
382 GLint wrap_mode)
383 : child_id(0),
384 gl_id(0),
385 gl_pixel_buffer_id(0),
386 gl_upload_query_id(0),
387 gl_read_lock_query_id(0),
388 pixels(NULL),
389 lock_for_read_count(0),
390 imported_count(0),
391 exported_count(0),
392 dirty_image(false),
393 locked_for_write(false),
394 lost(false),
395 marked_for_deletion(false),
396 pending_set_pixels(false),
397 set_pixels_completion_forced(false),
398 allocated(false),
399 read_lock_fences_enabled(false),
400 has_shared_bitmap_id(true),
401 allow_overlay(false),
402 read_lock_fence(NULL),
403 size(size),
404 origin(origin),
405 target(0),
406 original_filter(filter),
407 filter(filter),
408 image_id(0),
409 bound_image_id(0),
410 texture_pool(0),
411 wrap_mode(wrap_mode),
412 hint(TEXTURE_HINT_IMMUTABLE),
413 type(RESOURCE_TYPE_BITMAP),
414 format(RGBA_8888),
415 shared_bitmap_id(bitmap_id),
416 shared_bitmap(NULL),
417 gpu_memory_buffer(NULL) {
418 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
421 ResourceProvider::Child::Child() : marked_for_deletion(false) {}
423 ResourceProvider::Child::~Child() {}
425 scoped_ptr<ResourceProvider> ResourceProvider::Create(
426 OutputSurface* output_surface,
427 SharedBitmapManager* shared_bitmap_manager,
428 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
429 BlockingTaskRunner* blocking_main_thread_task_runner,
430 int highp_threshold_min,
431 bool use_rgba_4444_texture_format,
432 size_t id_allocation_chunk_size) {
433 scoped_ptr<ResourceProvider> resource_provider(
434 new ResourceProvider(output_surface,
435 shared_bitmap_manager,
436 gpu_memory_buffer_manager,
437 blocking_main_thread_task_runner,
438 highp_threshold_min,
439 use_rgba_4444_texture_format,
440 id_allocation_chunk_size));
442 if (resource_provider->ContextGL())
443 resource_provider->InitializeGL();
444 else
445 resource_provider->InitializeSoftware();
447 DCHECK_NE(RESOURCE_TYPE_INVALID, resource_provider->default_resource_type());
448 return resource_provider.Pass();
451 ResourceProvider::~ResourceProvider() {
452 while (!children_.empty())
453 DestroyChildInternal(children_.begin(), FOR_SHUTDOWN);
454 while (!resources_.empty())
455 DeleteResourceInternal(resources_.begin(), FOR_SHUTDOWN);
457 CleanUpGLIfNeeded();
460 bool ResourceProvider::InUseByConsumer(ResourceId id) {
461 Resource* resource = GetResource(id);
462 return resource->lock_for_read_count > 0 || resource->exported_count > 0 ||
463 resource->lost;
466 bool ResourceProvider::IsLost(ResourceId id) {
467 Resource* resource = GetResource(id);
468 return resource->lost;
471 bool ResourceProvider::AllowOverlay(ResourceId id) {
472 Resource* resource = GetResource(id);
473 return resource->allow_overlay;
476 ResourceProvider::ResourceId ResourceProvider::CreateResource(
477 const gfx::Size& size,
478 GLint wrap_mode,
479 TextureHint hint,
480 ResourceFormat format) {
481 DCHECK(!size.IsEmpty());
482 switch (default_resource_type_) {
483 case RESOURCE_TYPE_GL_TEXTURE:
484 return CreateGLTexture(size,
485 GL_TEXTURE_2D,
486 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
487 wrap_mode,
488 hint,
489 format);
490 case RESOURCE_TYPE_BITMAP:
491 DCHECK_EQ(RGBA_8888, format);
492 return CreateBitmap(size, wrap_mode);
493 case RESOURCE_TYPE_INVALID:
494 break;
497 LOG(FATAL) << "Invalid default resource type.";
498 return 0;
501 ResourceProvider::ResourceId ResourceProvider::CreateManagedResource(
502 const gfx::Size& size,
503 GLenum target,
504 GLint wrap_mode,
505 TextureHint hint,
506 ResourceFormat format) {
507 DCHECK(!size.IsEmpty());
508 switch (default_resource_type_) {
509 case RESOURCE_TYPE_GL_TEXTURE:
510 return CreateGLTexture(size,
511 target,
512 GL_TEXTURE_POOL_MANAGED_CHROMIUM,
513 wrap_mode,
514 hint,
515 format);
516 case RESOURCE_TYPE_BITMAP:
517 DCHECK_EQ(RGBA_8888, format);
518 return CreateBitmap(size, wrap_mode);
519 case RESOURCE_TYPE_INVALID:
520 break;
523 LOG(FATAL) << "Invalid default resource type.";
524 return 0;
527 ResourceProvider::ResourceId ResourceProvider::CreateGLTexture(
528 const gfx::Size& size,
529 GLenum target,
530 GLenum texture_pool,
531 GLint wrap_mode,
532 TextureHint hint,
533 ResourceFormat format) {
534 DCHECK_LE(size.width(), max_texture_size_);
535 DCHECK_LE(size.height(), max_texture_size_);
536 DCHECK(thread_checker_.CalledOnValidThread());
538 ResourceId id = next_id_++;
539 Resource resource(0, size, Resource::INTERNAL, target, GL_LINEAR,
540 texture_pool, wrap_mode, hint, format);
541 resource.allocated = false;
542 resources_[id] = resource;
543 return id;
546 ResourceProvider::ResourceId ResourceProvider::CreateBitmap(
547 const gfx::Size& size, GLint wrap_mode) {
548 DCHECK(thread_checker_.CalledOnValidThread());
550 scoped_ptr<SharedBitmap> bitmap =
551 shared_bitmap_manager_->AllocateSharedBitmap(size);
552 uint8_t* pixels = bitmap->pixels();
553 DCHECK(pixels);
555 ResourceId id = next_id_++;
556 Resource resource(pixels, bitmap.release(), size, Resource::INTERNAL,
557 GL_LINEAR, wrap_mode);
558 resource.allocated = true;
559 resources_[id] = resource;
560 return id;
563 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromIOSurface(
564 const gfx::Size& size,
565 unsigned io_surface_id) {
566 DCHECK(thread_checker_.CalledOnValidThread());
568 ResourceId id = next_id_++;
569 Resource resource(0, gfx::Size(), Resource::INTERNAL,
570 GL_TEXTURE_RECTANGLE_ARB, GL_LINEAR,
571 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, GL_CLAMP_TO_EDGE,
572 TEXTURE_HINT_IMMUTABLE, RGBA_8888);
573 LazyCreate(&resource);
574 GLES2Interface* gl = ContextGL();
575 DCHECK(gl);
576 gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource.gl_id);
577 gl->TexImageIOSurface2DCHROMIUM(
578 GL_TEXTURE_RECTANGLE_ARB, size.width(), size.height(), io_surface_id, 0);
579 resource.allocated = true;
580 resources_[id] = resource;
581 return id;
584 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
585 const TextureMailbox& mailbox,
586 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl) {
587 DCHECK(thread_checker_.CalledOnValidThread());
588 // Just store the information. Mailbox will be consumed in LockForRead().
589 ResourceId id = next_id_++;
590 DCHECK(mailbox.IsValid());
591 Resource& resource = resources_[id];
592 if (mailbox.IsTexture()) {
593 resource = Resource(0, gfx::Size(), Resource::EXTERNAL, mailbox.target(),
594 mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR, 0,
595 GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888);
596 } else {
597 DCHECK(mailbox.IsSharedMemory());
598 SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
599 uint8_t* pixels = shared_bitmap->pixels();
600 DCHECK(pixels);
601 resource = Resource(pixels, shared_bitmap, mailbox.shared_memory_size(),
602 Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE);
604 resource.allocated = true;
605 resource.mailbox = mailbox;
606 resource.release_callback_impl =
607 base::Bind(&SingleReleaseCallbackImpl::Run,
608 base::Owned(release_callback_impl.release()));
609 resource.allow_overlay = mailbox.allow_overlay();
610 return id;
613 void ResourceProvider::DeleteResource(ResourceId id) {
614 DCHECK(thread_checker_.CalledOnValidThread());
615 ResourceMap::iterator it = resources_.find(id);
616 CHECK(it != resources_.end());
617 Resource* resource = &it->second;
618 DCHECK(!resource->marked_for_deletion);
619 DCHECK_EQ(resource->imported_count, 0);
620 DCHECK(resource->pending_set_pixels || !resource->locked_for_write);
622 if (resource->exported_count > 0 || resource->lock_for_read_count > 0) {
623 resource->marked_for_deletion = true;
624 return;
625 } else {
626 DeleteResourceInternal(it, NORMAL);
630 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
631 DeleteStyle style) {
632 TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal");
633 Resource* resource = &it->second;
634 bool lost_resource = resource->lost;
636 DCHECK(resource->exported_count == 0 || style != NORMAL);
637 if (style == FOR_SHUTDOWN && resource->exported_count > 0)
638 lost_resource = true;
640 if (resource->image_id) {
641 DCHECK(resource->origin == Resource::INTERNAL);
642 GLES2Interface* gl = ContextGL();
643 DCHECK(gl);
644 gl->DestroyImageCHROMIUM(resource->image_id);
646 if (resource->gl_upload_query_id) {
647 DCHECK(resource->origin == Resource::INTERNAL);
648 GLES2Interface* gl = ContextGL();
649 DCHECK(gl);
650 gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id);
652 if (resource->gl_read_lock_query_id) {
653 DCHECK(resource->origin == Resource::INTERNAL);
654 GLES2Interface* gl = ContextGL();
655 DCHECK(gl);
656 gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id);
658 if (resource->gl_pixel_buffer_id) {
659 DCHECK(resource->origin == Resource::INTERNAL);
660 GLES2Interface* gl = ContextGL();
661 DCHECK(gl);
662 gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id);
664 if (resource->origin == Resource::EXTERNAL) {
665 DCHECK(resource->mailbox.IsValid());
666 GLuint sync_point = resource->mailbox.sync_point();
667 if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
668 DCHECK(resource->mailbox.IsTexture());
669 lost_resource |= lost_output_surface_;
670 GLES2Interface* gl = ContextGL();
671 DCHECK(gl);
672 if (resource->gl_id) {
673 gl->DeleteTextures(1, &resource->gl_id);
674 resource->gl_id = 0;
675 if (!lost_resource)
676 sync_point = gl->InsertSyncPointCHROMIUM();
678 } else {
679 DCHECK(resource->mailbox.IsSharedMemory());
680 resource->shared_bitmap = nullptr;
681 resource->pixels = nullptr;
683 resource->release_callback_impl.Run(
684 sync_point, lost_resource, blocking_main_thread_task_runner_);
686 if (resource->gl_id) {
687 GLES2Interface* gl = ContextGL();
688 DCHECK(gl);
689 gl->DeleteTextures(1, &resource->gl_id);
690 resource->gl_id = 0;
692 if (resource->shared_bitmap) {
693 DCHECK(resource->origin != Resource::EXTERNAL);
694 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
695 delete resource->shared_bitmap;
696 resource->pixels = NULL;
698 if (resource->pixels) {
699 DCHECK(resource->origin == Resource::INTERNAL);
700 delete[] resource->pixels;
701 resource->pixels = NULL;
703 if (resource->gpu_memory_buffer) {
704 DCHECK(resource->origin == Resource::INTERNAL);
705 delete resource->gpu_memory_buffer;
706 resource->gpu_memory_buffer = NULL;
708 resources_.erase(it);
711 ResourceProvider::ResourceType ResourceProvider::GetResourceType(
712 ResourceId id) {
713 return GetResource(id)->type;
716 void ResourceProvider::SetPixels(ResourceId id,
717 const uint8_t* image,
718 const gfx::Rect& image_rect,
719 const gfx::Rect& source_rect,
720 const gfx::Vector2d& dest_offset) {
721 Resource* resource = GetResource(id);
722 DCHECK(!resource->locked_for_write);
723 DCHECK(!resource->lock_for_read_count);
724 DCHECK(resource->origin == Resource::INTERNAL);
725 DCHECK_EQ(resource->exported_count, 0);
726 DCHECK(ReadLockFenceHasPassed(resource));
727 LazyAllocate(resource);
729 if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
730 DCHECK(resource->gl_id);
731 DCHECK(!resource->pending_set_pixels);
732 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
733 GLES2Interface* gl = ContextGL();
734 DCHECK(gl);
735 DCHECK(texture_uploader_.get());
736 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
737 texture_uploader_->Upload(image,
738 image_rect,
739 source_rect,
740 dest_offset,
741 resource->format,
742 resource->size);
743 } else {
744 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
745 DCHECK(resource->allocated);
746 DCHECK_EQ(RGBA_8888, resource->format);
747 DCHECK(source_rect.x() >= image_rect.x());
748 DCHECK(source_rect.y() >= image_rect.y());
749 DCHECK(source_rect.right() <= image_rect.right());
750 DCHECK(source_rect.bottom() <= image_rect.bottom());
751 SkImageInfo source_info =
752 SkImageInfo::MakeN32Premul(source_rect.width(), source_rect.height());
753 size_t image_row_bytes = image_rect.width() * 4;
754 gfx::Vector2d source_offset = source_rect.origin() - image_rect.origin();
755 image += source_offset.y() * image_row_bytes + source_offset.x() * 4;
757 ScopedWriteLockSoftware lock(this, id);
758 SkCanvas dest(lock.sk_bitmap());
759 dest.writePixels(source_info, image, image_row_bytes, dest_offset.x(),
760 dest_offset.y());
764 void ResourceProvider::CopyToResource(ResourceId id,
765 const uint8_t* image,
766 const gfx::Size& image_size) {
767 Resource* resource = GetResource(id);
768 DCHECK(!resource->locked_for_write);
769 DCHECK(!resource->lock_for_read_count);
770 DCHECK(resource->origin == Resource::INTERNAL);
771 DCHECK_EQ(resource->exported_count, 0);
772 DCHECK(ReadLockFenceHasPassed(resource));
773 LazyAllocate(resource);
775 DCHECK_EQ(image_size.width(), resource->size.width());
776 DCHECK_EQ(image_size.height(), resource->size.height());
778 if (resource->type == RESOURCE_TYPE_BITMAP) {
779 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
780 DCHECK(resource->allocated);
781 DCHECK_EQ(RGBA_8888, resource->format);
782 SkImageInfo source_info =
783 SkImageInfo::MakeN32Premul(image_size.width(), image_size.height());
784 size_t image_stride = image_size.width() * 4;
786 ScopedWriteLockSoftware lock(this, id);
787 SkCanvas dest(lock.sk_bitmap());
788 dest.writePixels(source_info, image, image_stride, 0, 0);
789 } else {
790 DCHECK(resource->gl_id);
791 DCHECK(!resource->pending_set_pixels);
792 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
793 GLES2Interface* gl = ContextGL();
794 DCHECK(gl);
795 DCHECK(texture_uploader_.get());
796 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
798 if (resource->format == ETC1) {
799 size_t num_bytes = static_cast<size_t>(image_size.width()) *
800 image_size.height() * BitsPerPixel(ETC1) / 8;
801 gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1),
802 image_size.width(), image_size.height(), 0,
803 num_bytes, image);
804 } else {
805 gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(),
806 image_size.height(), GLDataFormat(resource->format),
807 GLDataType(resource->format), image);
812 size_t ResourceProvider::NumBlockingUploads() {
813 if (!texture_uploader_)
814 return 0;
816 return texture_uploader_->NumBlockingUploads();
819 void ResourceProvider::MarkPendingUploadsAsNonBlocking() {
820 if (!texture_uploader_)
821 return;
823 texture_uploader_->MarkPendingUploadsAsNonBlocking();
826 size_t ResourceProvider::EstimatedUploadsPerTick() {
827 if (!texture_uploader_)
828 return 1u;
830 double textures_per_second = texture_uploader_->EstimatedTexturesPerSecond();
831 size_t textures_per_tick = floor(
832 kTextureUploadTickRate * textures_per_second);
833 return textures_per_tick ? textures_per_tick : 1u;
836 void ResourceProvider::FlushUploads() {
837 if (!texture_uploader_)
838 return;
840 texture_uploader_->Flush();
843 void ResourceProvider::ReleaseCachedData() {
844 if (!texture_uploader_)
845 return;
847 texture_uploader_->ReleaseCachedQueries();
850 base::TimeTicks ResourceProvider::EstimatedUploadCompletionTime(
851 size_t uploads_per_tick) {
852 if (lost_output_surface_)
853 return base::TimeTicks();
855 // Software resource uploads happen on impl thread, so don't bother batching
856 // them up and trying to wait for them to complete.
857 if (!texture_uploader_) {
858 return gfx::FrameTime::Now() + base::TimeDelta::FromMicroseconds(
859 base::Time::kMicrosecondsPerSecond * kSoftwareUploadTickRate);
862 base::TimeDelta upload_one_texture_time =
863 base::TimeDelta::FromMicroseconds(
864 base::Time::kMicrosecondsPerSecond * kTextureUploadTickRate) /
865 uploads_per_tick;
867 size_t total_uploads = NumBlockingUploads() + uploads_per_tick;
868 return gfx::FrameTime::Now() + upload_one_texture_time * total_uploads;
871 ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) {
872 DCHECK(thread_checker_.CalledOnValidThread());
873 // TODO(danakj): crbug.com/455931
874 CHECK(id);
875 ResourceMap::iterator it = resources_.find(id);
876 CHECK(it != resources_.end());
877 return &it->second;
880 const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
881 Resource* resource = GetResource(id);
882 DCHECK(!resource->locked_for_write ||
883 resource->set_pixels_completion_forced) <<
884 "locked for write: " << resource->locked_for_write <<
885 " pixels completion forced: " << resource->set_pixels_completion_forced;
886 DCHECK_EQ(resource->exported_count, 0);
887 // Uninitialized! Call SetPixels or LockForWrite first.
888 DCHECK(resource->allocated);
890 LazyCreate(resource);
892 if (resource->type == RESOURCE_TYPE_GL_TEXTURE && !resource->gl_id) {
893 DCHECK(resource->origin != Resource::INTERNAL);
894 DCHECK(resource->mailbox.IsTexture());
896 // Mailbox sync_points must be processed by a call to
897 // WaitSyncPointIfNeeded() prior to calling LockForRead().
898 DCHECK(!resource->mailbox.sync_point());
900 GLES2Interface* gl = ContextGL();
901 DCHECK(gl);
902 resource->gl_id = gl->CreateAndConsumeTextureCHROMIUM(
903 resource->mailbox.target(), resource->mailbox.name());
906 if (!resource->pixels && resource->has_shared_bitmap_id &&
907 shared_bitmap_manager_) {
908 scoped_ptr<SharedBitmap> bitmap =
909 shared_bitmap_manager_->GetSharedBitmapFromId(
910 resource->size, resource->shared_bitmap_id);
911 if (bitmap) {
912 resource->shared_bitmap = bitmap.release();
913 resource->pixels = resource->shared_bitmap->pixels();
917 resource->lock_for_read_count++;
918 if (resource->read_lock_fences_enabled) {
919 if (current_read_lock_fence_.get())
920 current_read_lock_fence_->Set();
921 resource->read_lock_fence = current_read_lock_fence_;
924 return resource;
927 void ResourceProvider::UnlockForRead(ResourceId id) {
928 DCHECK(thread_checker_.CalledOnValidThread());
929 ResourceMap::iterator it = resources_.find(id);
930 CHECK(it != resources_.end());
932 Resource* resource = &it->second;
933 DCHECK_GT(resource->lock_for_read_count, 0);
934 DCHECK_EQ(resource->exported_count, 0);
935 resource->lock_for_read_count--;
936 if (resource->marked_for_deletion && !resource->lock_for_read_count) {
937 if (!resource->child_id) {
938 // The resource belongs to this ResourceProvider, so it can be destroyed.
939 DeleteResourceInternal(it, NORMAL);
940 } else {
941 ChildMap::iterator child_it = children_.find(resource->child_id);
942 ResourceIdArray unused;
943 unused.push_back(id);
944 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
949 ResourceProvider::Resource* ResourceProvider::LockForWrite(ResourceId id) {
950 Resource* resource = GetResource(id);
951 DCHECK(CanLockForWrite(id));
953 resource->locked_for_write = true;
954 return resource;
957 bool ResourceProvider::CanLockForWrite(ResourceId id) {
958 Resource* resource = GetResource(id);
959 return !resource->locked_for_write && !resource->lock_for_read_count &&
960 !resource->exported_count && resource->origin == Resource::INTERNAL &&
961 !resource->lost && ReadLockFenceHasPassed(resource);
964 void ResourceProvider::UnlockForWrite(ResourceProvider::Resource* resource) {
965 DCHECK(resource->locked_for_write);
966 DCHECK_EQ(resource->exported_count, 0);
967 DCHECK(resource->origin == Resource::INTERNAL);
968 resource->locked_for_write = false;
971 ResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
972 ResourceProvider* resource_provider,
973 ResourceProvider::ResourceId resource_id)
974 : resource_provider_(resource_provider),
975 resource_id_(resource_id),
976 texture_id_(resource_provider->LockForRead(resource_id)->gl_id) {
977 DCHECK(texture_id_);
980 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
981 resource_provider_->UnlockForRead(resource_id_);
984 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
985 ResourceProvider* resource_provider,
986 ResourceProvider::ResourceId resource_id,
987 GLenum filter)
988 : ScopedReadLockGL(resource_provider, resource_id),
989 unit_(GL_TEXTURE0),
990 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
993 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
994 ResourceProvider* resource_provider,
995 ResourceProvider::ResourceId resource_id,
996 GLenum unit,
997 GLenum filter)
998 : ScopedReadLockGL(resource_provider, resource_id),
999 unit_(unit),
1000 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
1003 ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() {
1006 ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(
1007 ResourceProvider* resource_provider,
1008 ResourceProvider::ResourceId resource_id)
1009 : resource_provider_(resource_provider),
1010 resource_(resource_provider->LockForWrite(resource_id)) {
1011 resource_provider_->LazyAllocate(resource_);
1012 texture_id_ = resource_->gl_id;
1013 DCHECK(texture_id_);
1016 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() {
1017 resource_provider_->UnlockForWrite(resource_);
1020 void ResourceProvider::PopulateSkBitmapWithResource(
1021 SkBitmap* sk_bitmap, const Resource* resource) {
1022 DCHECK_EQ(RGBA_8888, resource->format);
1023 SkImageInfo info = SkImageInfo::MakeN32Premul(resource->size.width(),
1024 resource->size.height());
1025 sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes());
1028 ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(
1029 ResourceProvider* resource_provider,
1030 ResourceProvider::ResourceId resource_id)
1031 : resource_provider_(resource_provider),
1032 resource_id_(resource_id) {
1033 const Resource* resource = resource_provider->LockForRead(resource_id);
1034 wrap_mode_ = resource->wrap_mode;
1035 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource);
1038 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() {
1039 resource_provider_->UnlockForRead(resource_id_);
1042 ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(
1043 ResourceProvider* resource_provider,
1044 ResourceProvider::ResourceId resource_id)
1045 : resource_provider_(resource_provider),
1046 resource_(resource_provider->LockForWrite(resource_id)) {
1047 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource_);
1048 DCHECK(valid());
1051 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() {
1052 DCHECK(thread_checker_.CalledOnValidThread());
1053 resource_provider_->UnlockForWrite(resource_);
1056 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
1057 ScopedWriteLockGpuMemoryBuffer(ResourceProvider* resource_provider,
1058 ResourceProvider::ResourceId resource_id)
1059 : resource_provider_(resource_provider),
1060 resource_(resource_provider->LockForWrite(resource_id)),
1061 gpu_memory_buffer_manager_(resource_provider->gpu_memory_buffer_manager_),
1062 gpu_memory_buffer_(nullptr),
1063 size_(resource_->size),
1064 format_(resource_->format) {
1065 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource_->type);
1066 std::swap(gpu_memory_buffer_, resource_->gpu_memory_buffer);
1069 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
1070 ~ScopedWriteLockGpuMemoryBuffer() {
1071 DCHECK(thread_checker_.CalledOnValidThread());
1072 resource_provider_->UnlockForWrite(resource_);
1073 if (!gpu_memory_buffer_)
1074 return;
1076 if (!resource_->image_id) {
1077 GLES2Interface* gl = resource_provider_->ContextGL();
1078 DCHECK(gl);
1080 #if defined(OS_CHROMEOS)
1081 // TODO(reveman): GL_COMMANDS_ISSUED_CHROMIUM is used for synchronization
1082 // on ChromeOS to avoid some performance issues. This only works with
1083 // shared memory backed buffers. crbug.com/436314
1084 DCHECK_EQ(gpu_memory_buffer_->GetHandle().type, gfx::SHARED_MEMORY_BUFFER);
1085 #endif
1087 resource_->image_id = gl->CreateImageCHROMIUM(
1088 gpu_memory_buffer_->AsClientBuffer(), size_.width(), size_.height(),
1089 GLInternalFormat(resource_->format));
1092 std::swap(resource_->gpu_memory_buffer, gpu_memory_buffer_);
1093 resource_->allocated = true;
1094 resource_->dirty_image = true;
1096 // GpuMemoryBuffer provides direct access to the memory used by the GPU.
1097 // Read lock fences are required to ensure that we're not trying to map a
1098 // buffer that is currently in-use by the GPU.
1099 resource_->read_lock_fences_enabled = true;
1102 gfx::GpuMemoryBuffer*
1103 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::GetGpuMemoryBuffer() {
1104 if (!gpu_memory_buffer_) {
1105 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
1106 gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer(
1107 size_, ToGpuMemoryBufferFormat(format_), gfx::GpuMemoryBuffer::MAP);
1108 gpu_memory_buffer_ = gpu_memory_buffer.release();
1111 return gpu_memory_buffer_;
1114 ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr(
1115 ResourceProvider* resource_provider,
1116 ResourceProvider::ResourceId resource_id)
1117 : resource_provider_(resource_provider),
1118 resource_(resource_provider->LockForWrite(resource_id)) {
1119 DCHECK(thread_checker_.CalledOnValidThread());
1120 resource_provider_->LazyAllocate(resource_);
1123 ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
1124 DCHECK(thread_checker_.CalledOnValidThread());
1125 DCHECK(resource_->locked_for_write);
1126 resource_provider_->UnlockForWrite(resource_);
1129 void ResourceProvider::ScopedWriteLockGr::InitSkSurface(
1130 bool use_distance_field_text,
1131 bool can_use_lcd_text,
1132 int msaa_sample_count) {
1133 DCHECK(resource_->locked_for_write);
1135 GrBackendTextureDesc desc;
1136 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
1137 desc.fWidth = resource_->size.width();
1138 desc.fHeight = resource_->size.height();
1139 desc.fConfig = ToGrPixelConfig(resource_->format);
1140 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1141 desc.fTextureHandle = resource_->gl_id;
1142 desc.fSampleCnt = msaa_sample_count;
1144 bool use_worker_context = true;
1145 class GrContext* gr_context =
1146 resource_provider_->GrContext(use_worker_context);
1147 skia::RefPtr<GrTexture> gr_texture =
1148 skia::AdoptRef(gr_context->wrapBackendTexture(desc));
1149 if (gr_texture) {
1150 uint32_t flags = use_distance_field_text
1151 ? SkSurfaceProps::kUseDistanceFieldFonts_Flag
1152 : 0;
1153 // Use unknown pixel geometry to disable LCD text.
1154 SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
1155 if (can_use_lcd_text) {
1156 // LegacyFontHost will get LCD text and skia figures out what type to use.
1157 surface_props =
1158 SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
1160 sk_surface_ = skia::AdoptRef(SkSurface::NewRenderTargetDirect(
1161 gr_texture->asRenderTarget(), &surface_props));
1162 return;
1164 sk_surface_.clear();
1167 void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() {
1168 sk_surface_.clear();
1171 ResourceProvider::SynchronousFence::SynchronousFence(
1172 gpu::gles2::GLES2Interface* gl)
1173 : gl_(gl), has_synchronized_(true) {
1176 ResourceProvider::SynchronousFence::~SynchronousFence() {
1179 void ResourceProvider::SynchronousFence::Set() {
1180 has_synchronized_ = false;
1183 bool ResourceProvider::SynchronousFence::HasPassed() {
1184 if (!has_synchronized_) {
1185 has_synchronized_ = true;
1186 Synchronize();
1188 return true;
1191 void ResourceProvider::SynchronousFence::Wait() {
1192 HasPassed();
1195 void ResourceProvider::SynchronousFence::Synchronize() {
1196 TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize");
1197 gl_->Finish();
1200 ResourceProvider::ResourceProvider(
1201 OutputSurface* output_surface,
1202 SharedBitmapManager* shared_bitmap_manager,
1203 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
1204 BlockingTaskRunner* blocking_main_thread_task_runner,
1205 int highp_threshold_min,
1206 bool use_rgba_4444_texture_format,
1207 size_t id_allocation_chunk_size)
1208 : output_surface_(output_surface),
1209 shared_bitmap_manager_(shared_bitmap_manager),
1210 gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
1211 blocking_main_thread_task_runner_(blocking_main_thread_task_runner),
1212 lost_output_surface_(false),
1213 highp_threshold_min_(highp_threshold_min),
1214 next_id_(1),
1215 next_child_(1),
1216 default_resource_type_(RESOURCE_TYPE_INVALID),
1217 use_texture_storage_ext_(false),
1218 use_texture_format_bgra_(false),
1219 use_texture_usage_hint_(false),
1220 use_compressed_texture_etc1_(false),
1221 yuv_resource_format_(LUMINANCE_8),
1222 max_texture_size_(0),
1223 best_texture_format_(RGBA_8888),
1224 use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
1225 id_allocation_chunk_size_(id_allocation_chunk_size),
1226 use_sync_query_(false) {
1227 DCHECK(output_surface_->HasClient());
1228 DCHECK(id_allocation_chunk_size_);
1231 void ResourceProvider::InitializeSoftware() {
1232 DCHECK(thread_checker_.CalledOnValidThread());
1233 DCHECK_NE(RESOURCE_TYPE_BITMAP, default_resource_type_);
1235 CleanUpGLIfNeeded();
1237 default_resource_type_ = RESOURCE_TYPE_BITMAP;
1238 // Pick an arbitrary limit here similar to what hardware might.
1239 max_texture_size_ = 16 * 1024;
1240 best_texture_format_ = RGBA_8888;
1243 void ResourceProvider::InitializeGL() {
1244 DCHECK(thread_checker_.CalledOnValidThread());
1245 DCHECK(!texture_uploader_);
1246 DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, default_resource_type_);
1247 DCHECK(!texture_id_allocator_);
1248 DCHECK(!buffer_id_allocator_);
1250 default_resource_type_ = RESOURCE_TYPE_GL_TEXTURE;
1252 const ContextProvider::Capabilities& caps =
1253 output_surface_->context_provider()->ContextCapabilities();
1255 bool use_bgra = caps.gpu.texture_format_bgra8888;
1256 use_texture_storage_ext_ = caps.gpu.texture_storage;
1257 use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888;
1258 use_texture_usage_hint_ = caps.gpu.texture_usage;
1259 use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1;
1260 yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8;
1261 use_sync_query_ = caps.gpu.sync_query;
1263 GLES2Interface* gl = ContextGL();
1264 DCHECK(gl);
1266 texture_uploader_ = TextureUploader::Create(gl);
1267 max_texture_size_ = 0; // Context expects cleared value.
1268 gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
1269 best_texture_format_ = PlatformColor::BestTextureFormat(use_bgra);
1271 texture_id_allocator_.reset(
1272 new TextureIdAllocator(gl, id_allocation_chunk_size_));
1273 buffer_id_allocator_.reset(
1274 new BufferIdAllocator(gl, id_allocation_chunk_size_));
1277 void ResourceProvider::CleanUpGLIfNeeded() {
1278 GLES2Interface* gl = ContextGL();
1279 if (default_resource_type_ != RESOURCE_TYPE_GL_TEXTURE) {
1280 // We are not in GL mode, but double check before returning.
1281 DCHECK(!gl);
1282 DCHECK(!texture_uploader_);
1283 return;
1286 DCHECK(gl);
1287 #if DCHECK_IS_ON()
1288 // Check that all GL resources has been deleted.
1289 for (ResourceMap::const_iterator itr = resources_.begin();
1290 itr != resources_.end();
1291 ++itr) {
1292 DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, itr->second.type);
1294 #endif // DCHECK_IS_ON()
1296 texture_uploader_ = nullptr;
1297 texture_id_allocator_ = nullptr;
1298 buffer_id_allocator_ = nullptr;
1299 gl->Finish();
1302 int ResourceProvider::CreateChild(const ReturnCallback& return_callback) {
1303 DCHECK(thread_checker_.CalledOnValidThread());
1305 Child child_info;
1306 child_info.return_callback = return_callback;
1308 int child = next_child_++;
1309 children_[child] = child_info;
1310 return child;
1313 void ResourceProvider::DestroyChild(int child_id) {
1314 ChildMap::iterator it = children_.find(child_id);
1315 DCHECK(it != children_.end());
1316 DestroyChildInternal(it, NORMAL);
1319 void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
1320 DeleteStyle style) {
1321 DCHECK(thread_checker_.CalledOnValidThread());
1323 Child& child = it->second;
1324 DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion);
1326 ResourceIdArray resources_for_child;
1328 for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin();
1329 child_it != child.child_to_parent_map.end();
1330 ++child_it) {
1331 ResourceId id = child_it->second;
1332 resources_for_child.push_back(id);
1335 // If the child is going away, don't consider any resources in use.
1336 child.in_use_resources.clear();
1337 child.marked_for_deletion = true;
1339 DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child);
1342 const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap(
1343 int child) const {
1344 DCHECK(thread_checker_.CalledOnValidThread());
1345 ChildMap::const_iterator it = children_.find(child);
1346 DCHECK(it != children_.end());
1347 DCHECK(!it->second.marked_for_deletion);
1348 return it->second.child_to_parent_map;
1351 void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
1352 TransferableResourceArray* list) {
1353 DCHECK(thread_checker_.CalledOnValidThread());
1354 GLES2Interface* gl = ContextGL();
1355 bool need_sync_point = false;
1356 for (ResourceIdArray::const_iterator it = resources.begin();
1357 it != resources.end();
1358 ++it) {
1359 TransferableResource resource;
1360 TransferResource(gl, *it, &resource);
1361 if (!resource.mailbox_holder.sync_point && !resource.is_software)
1362 need_sync_point = true;
1363 ++resources_.find(*it)->second.exported_count;
1364 list->push_back(resource);
1366 if (need_sync_point) {
1367 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1368 for (TransferableResourceArray::iterator it = list->begin();
1369 it != list->end();
1370 ++it) {
1371 if (!it->mailbox_holder.sync_point)
1372 it->mailbox_holder.sync_point = sync_point;
1377 void ResourceProvider::ReceiveFromChild(
1378 int child, const TransferableResourceArray& resources) {
1379 DCHECK(thread_checker_.CalledOnValidThread());
1380 GLES2Interface* gl = ContextGL();
1381 Child& child_info = children_.find(child)->second;
1382 DCHECK(!child_info.marked_for_deletion);
1383 for (TransferableResourceArray::const_iterator it = resources.begin();
1384 it != resources.end();
1385 ++it) {
1386 ResourceIdMap::iterator resource_in_map_it =
1387 child_info.child_to_parent_map.find(it->id);
1388 if (resource_in_map_it != child_info.child_to_parent_map.end()) {
1389 Resource& resource = resources_[resource_in_map_it->second];
1390 resource.marked_for_deletion = false;
1391 resource.imported_count++;
1392 continue;
1395 if ((!it->is_software && !gl) ||
1396 (it->is_software && !shared_bitmap_manager_)) {
1397 TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
1398 ReturnedResourceArray to_return;
1399 to_return.push_back(it->ToReturnedResource());
1400 child_info.return_callback.Run(to_return,
1401 blocking_main_thread_task_runner_);
1402 continue;
1405 ResourceId local_id = next_id_++;
1406 Resource& resource = resources_[local_id];
1407 if (it->is_software) {
1408 resource =
1409 Resource(it->mailbox_holder.mailbox, it->size, Resource::DELEGATED,
1410 GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE);
1411 } else {
1412 resource = Resource(0, it->size, Resource::DELEGATED,
1413 it->mailbox_holder.texture_target, it->filter, 0,
1414 it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE,
1415 TEXTURE_HINT_IMMUTABLE, it->format);
1416 resource.mailbox = TextureMailbox(it->mailbox_holder.mailbox,
1417 it->mailbox_holder.texture_target,
1418 it->mailbox_holder.sync_point);
1420 resource.child_id = child;
1421 // Don't allocate a texture for a child.
1422 resource.allocated = true;
1423 resource.imported_count = 1;
1424 resource.allow_overlay = it->allow_overlay;
1425 child_info.parent_to_child_map[local_id] = it->id;
1426 child_info.child_to_parent_map[it->id] = local_id;
1430 void ResourceProvider::DeclareUsedResourcesFromChild(
1431 int child,
1432 const ResourceIdArray& resources_from_child) {
1433 DCHECK(thread_checker_.CalledOnValidThread());
1435 ChildMap::iterator child_it = children_.find(child);
1436 DCHECK(child_it != children_.end());
1437 Child& child_info = child_it->second;
1438 DCHECK(!child_info.marked_for_deletion);
1439 child_info.in_use_resources.clear();
1441 for (size_t i = 0; i < resources_from_child.size(); ++i) {
1442 ResourceIdMap::iterator it =
1443 child_info.child_to_parent_map.find(resources_from_child[i]);
1444 DCHECK(it != child_info.child_to_parent_map.end());
1446 ResourceId local_id = it->second;
1447 DCHECK(!resources_[local_id].marked_for_deletion);
1448 child_info.in_use_resources.insert(local_id);
1451 ResourceIdArray unused;
1452 for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin();
1453 it != child_info.child_to_parent_map.end();
1454 ++it) {
1455 ResourceId local_id = it->second;
1456 bool resource_is_in_use = child_info.in_use_resources.count(local_id) > 0;
1457 if (!resource_is_in_use)
1458 unused.push_back(local_id);
1460 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
1463 // static
1464 bool ResourceProvider::CompareResourceMapIteratorsByChildId(
1465 const std::pair<ReturnedResource, ResourceMap::iterator>& a,
1466 const std::pair<ReturnedResource, ResourceMap::iterator>& b) {
1467 const ResourceMap::iterator& a_it = a.second;
1468 const ResourceMap::iterator& b_it = b.second;
1469 const Resource& a_resource = a_it->second;
1470 const Resource& b_resource = b_it->second;
1471 return a_resource.child_id < b_resource.child_id;
1474 void ResourceProvider::ReceiveReturnsFromParent(
1475 const ReturnedResourceArray& resources) {
1476 DCHECK(thread_checker_.CalledOnValidThread());
1477 GLES2Interface* gl = ContextGL();
1479 int child_id = 0;
1480 ResourceIdArray resources_for_child;
1482 std::vector<std::pair<ReturnedResource, ResourceMap::iterator>>
1483 sorted_resources;
1485 for (ReturnedResourceArray::const_iterator it = resources.begin();
1486 it != resources.end();
1487 ++it) {
1488 ResourceId local_id = it->id;
1489 ResourceMap::iterator map_iterator = resources_.find(local_id);
1491 // Resource was already lost (e.g. it belonged to a child that was
1492 // destroyed).
1493 if (map_iterator == resources_.end())
1494 continue;
1496 sorted_resources.push_back(
1497 std::pair<ReturnedResource, ResourceMap::iterator>(*it, map_iterator));
1500 std::sort(sorted_resources.begin(),
1501 sorted_resources.end(),
1502 CompareResourceMapIteratorsByChildId);
1504 ChildMap::iterator child_it = children_.end();
1505 for (size_t i = 0; i < sorted_resources.size(); ++i) {
1506 ReturnedResource& returned = sorted_resources[i].first;
1507 ResourceMap::iterator& map_iterator = sorted_resources[i].second;
1508 ResourceId local_id = map_iterator->first;
1509 Resource* resource = &map_iterator->second;
1511 CHECK_GE(resource->exported_count, returned.count);
1512 resource->exported_count -= returned.count;
1513 resource->lost |= returned.lost;
1514 if (resource->exported_count)
1515 continue;
1517 // Need to wait for the current read lock fence to pass before we can
1518 // recycle this resource.
1519 if (resource->read_lock_fences_enabled) {
1520 if (current_read_lock_fence_.get())
1521 current_read_lock_fence_->Set();
1522 resource->read_lock_fence = current_read_lock_fence_;
1525 if (returned.sync_point) {
1526 DCHECK(!resource->has_shared_bitmap_id);
1527 if (resource->origin == Resource::INTERNAL) {
1528 DCHECK(resource->gl_id);
1529 gl->WaitSyncPointCHROMIUM(returned.sync_point);
1530 } else {
1531 DCHECK(!resource->gl_id);
1532 resource->mailbox.set_sync_point(returned.sync_point);
1536 if (!resource->marked_for_deletion)
1537 continue;
1539 if (!resource->child_id) {
1540 // The resource belongs to this ResourceProvider, so it can be destroyed.
1541 DeleteResourceInternal(map_iterator, NORMAL);
1542 continue;
1545 DCHECK(resource->origin == Resource::DELEGATED);
1546 // Delete the resource and return it to the child it came from one.
1547 if (resource->child_id != child_id) {
1548 if (child_id) {
1549 DCHECK_NE(resources_for_child.size(), 0u);
1550 DCHECK(child_it != children_.end());
1551 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL,
1552 resources_for_child);
1553 resources_for_child.clear();
1556 child_it = children_.find(resource->child_id);
1557 DCHECK(child_it != children_.end());
1558 child_id = resource->child_id;
1560 resources_for_child.push_back(local_id);
1563 if (child_id) {
1564 DCHECK_NE(resources_for_child.size(), 0u);
1565 DCHECK(child_it != children_.end());
1566 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL,
1567 resources_for_child);
1571 void ResourceProvider::TransferResource(GLES2Interface* gl,
1572 ResourceId id,
1573 TransferableResource* resource) {
1574 Resource* source = GetResource(id);
1575 DCHECK(!source->locked_for_write);
1576 DCHECK(!source->lock_for_read_count);
1577 DCHECK(source->origin != Resource::EXTERNAL || source->mailbox.IsValid());
1578 DCHECK(source->allocated);
1579 resource->id = id;
1580 resource->format = source->format;
1581 resource->mailbox_holder.texture_target = source->target;
1582 resource->filter = source->filter;
1583 resource->size = source->size;
1584 resource->is_repeated = (source->wrap_mode == GL_REPEAT);
1585 resource->allow_overlay = source->allow_overlay;
1587 if (source->type == RESOURCE_TYPE_BITMAP) {
1588 resource->mailbox_holder.mailbox = source->shared_bitmap_id;
1589 resource->is_software = true;
1590 } else if (!source->mailbox.IsValid()) {
1591 LazyCreate(source);
1592 DCHECK(source->gl_id);
1593 DCHECK(source->origin == Resource::INTERNAL);
1594 if (source->image_id) {
1595 DCHECK(source->dirty_image);
1596 BindImageForSampling(source);
1598 // This is a resource allocated by the compositor, we need to produce it.
1599 // Don't set a sync point, the caller will do it.
1600 gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name);
1601 gl->ProduceTextureDirectCHROMIUM(source->gl_id,
1602 resource->mailbox_holder.texture_target,
1603 resource->mailbox_holder.mailbox.name);
1605 source->mailbox = TextureMailbox(resource->mailbox_holder);
1606 } else {
1607 DCHECK(source->mailbox.IsTexture());
1608 if (source->image_id && source->dirty_image) {
1609 DCHECK(source->gl_id);
1610 DCHECK(source->origin == Resource::INTERNAL);
1611 gl->BindTexture(resource->mailbox_holder.texture_target, source->gl_id);
1612 BindImageForSampling(source);
1614 // This is either an external resource, or a compositor resource that we
1615 // already exported. Make sure to forward the sync point that we were given.
1616 resource->mailbox_holder.mailbox = source->mailbox.mailbox();
1617 resource->mailbox_holder.texture_target = source->mailbox.target();
1618 resource->mailbox_holder.sync_point = source->mailbox.sync_point();
1619 source->mailbox.set_sync_point(0);
1623 void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
1624 ChildMap::iterator child_it,
1625 DeleteStyle style,
1626 const ResourceIdArray& unused) {
1627 DCHECK(thread_checker_.CalledOnValidThread());
1628 DCHECK(child_it != children_.end());
1629 Child* child_info = &child_it->second;
1631 if (unused.empty() && !child_info->marked_for_deletion)
1632 return;
1634 ReturnedResourceArray to_return;
1636 GLES2Interface* gl = ContextGL();
1637 bool need_sync_point = false;
1638 for (size_t i = 0; i < unused.size(); ++i) {
1639 ResourceId local_id = unused[i];
1641 ResourceMap::iterator it = resources_.find(local_id);
1642 CHECK(it != resources_.end());
1643 Resource& resource = it->second;
1645 DCHECK(!resource.locked_for_write);
1646 DCHECK_EQ(0u, child_info->in_use_resources.count(local_id));
1647 DCHECK(child_info->parent_to_child_map.count(local_id));
1649 ResourceId child_id = child_info->parent_to_child_map[local_id];
1650 DCHECK(child_info->child_to_parent_map.count(child_id));
1652 bool is_lost =
1653 resource.lost ||
1654 (resource.type == RESOURCE_TYPE_GL_TEXTURE && lost_output_surface_);
1655 if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
1656 if (style != FOR_SHUTDOWN) {
1657 // Defer this until we receive the resource back from the parent or
1658 // the read lock is released.
1659 resource.marked_for_deletion = true;
1660 continue;
1663 // We still have an exported_count, so we'll have to lose it.
1664 is_lost = true;
1667 if (gl && resource.filter != resource.original_filter) {
1668 DCHECK(resource.target);
1669 DCHECK(resource.gl_id);
1671 gl->BindTexture(resource.target, resource.gl_id);
1672 gl->TexParameteri(resource.target, GL_TEXTURE_MIN_FILTER,
1673 resource.original_filter);
1674 gl->TexParameteri(resource.target, GL_TEXTURE_MAG_FILTER,
1675 resource.original_filter);
1678 ReturnedResource returned;
1679 returned.id = child_id;
1680 returned.sync_point = resource.mailbox.sync_point();
1681 if (!returned.sync_point && resource.type == RESOURCE_TYPE_GL_TEXTURE)
1682 need_sync_point = true;
1683 returned.count = resource.imported_count;
1684 returned.lost = is_lost;
1685 to_return.push_back(returned);
1687 child_info->parent_to_child_map.erase(local_id);
1688 child_info->child_to_parent_map.erase(child_id);
1689 resource.imported_count = 0;
1690 DeleteResourceInternal(it, style);
1692 if (need_sync_point) {
1693 DCHECK(gl);
1694 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1695 for (size_t i = 0; i < to_return.size(); ++i) {
1696 if (!to_return[i].sync_point)
1697 to_return[i].sync_point = sync_point;
1701 if (!to_return.empty())
1702 child_info->return_callback.Run(to_return,
1703 blocking_main_thread_task_runner_);
1705 if (child_info->marked_for_deletion &&
1706 child_info->parent_to_child_map.empty()) {
1707 DCHECK(child_info->child_to_parent_map.empty());
1708 children_.erase(child_it);
1712 void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
1713 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1714 "ResourceProvider::AcquirePixelBuffer");
1716 Resource* resource = GetResource(id);
1717 DCHECK(resource->origin == Resource::INTERNAL);
1718 DCHECK_EQ(resource->exported_count, 0);
1719 DCHECK(!resource->image_id);
1720 DCHECK_NE(ETC1, resource->format);
1722 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1723 GLES2Interface* gl = ContextGL();
1724 DCHECK(gl);
1725 if (!resource->gl_pixel_buffer_id)
1726 resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId();
1727 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1728 resource->gl_pixel_buffer_id);
1729 unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8;
1730 gl->BufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1731 resource->size.height() *
1732 RoundUp(bytes_per_pixel * resource->size.width(), 4u),
1733 NULL,
1734 GL_DYNAMIC_DRAW);
1735 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1738 void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
1739 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1740 "ResourceProvider::ReleasePixelBuffer");
1742 Resource* resource = GetResource(id);
1743 DCHECK(resource->origin == Resource::INTERNAL);
1744 DCHECK_EQ(resource->exported_count, 0);
1745 DCHECK(!resource->image_id);
1747 // The pixel buffer can be released while there is a pending "set pixels"
1748 // if completion has been forced. Any shared memory associated with this
1749 // pixel buffer will not be freed until the waitAsyncTexImage2DCHROMIUM
1750 // command has been processed on the service side. It is also safe to
1751 // reuse any query id associated with this resource before they complete
1752 // as each new query has a unique submit count.
1753 if (resource->pending_set_pixels) {
1754 DCHECK(resource->set_pixels_completion_forced);
1755 resource->pending_set_pixels = false;
1756 resource->locked_for_write = false;
1759 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1760 if (!resource->gl_pixel_buffer_id)
1761 return;
1762 GLES2Interface* gl = ContextGL();
1763 DCHECK(gl);
1764 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1765 resource->gl_pixel_buffer_id);
1766 gl->BufferData(
1767 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW);
1768 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1771 uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id, int* stride) {
1772 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1773 "ResourceProvider::MapPixelBuffer");
1775 Resource* resource = GetResource(id);
1776 DCHECK(resource->origin == Resource::INTERNAL);
1777 DCHECK_EQ(resource->exported_count, 0);
1778 DCHECK(!resource->image_id);
1780 *stride = 0;
1781 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1782 GLES2Interface* gl = ContextGL();
1783 DCHECK(gl);
1784 DCHECK(resource->gl_pixel_buffer_id);
1785 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1786 resource->gl_pixel_buffer_id);
1787 uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
1788 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
1789 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1790 // Buffer is required to be 4-byte aligned.
1791 CHECK(!(reinterpret_cast<intptr_t>(image) & 3));
1792 return image;
1795 void ResourceProvider::UnmapPixelBuffer(ResourceId id) {
1796 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1797 "ResourceProvider::UnmapPixelBuffer");
1799 Resource* resource = GetResource(id);
1800 DCHECK(resource->origin == Resource::INTERNAL);
1801 DCHECK_EQ(resource->exported_count, 0);
1802 DCHECK(!resource->image_id);
1804 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1805 GLES2Interface* gl = ContextGL();
1806 DCHECK(gl);
1807 DCHECK(resource->gl_pixel_buffer_id);
1808 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1809 resource->gl_pixel_buffer_id);
1810 gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
1811 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1814 GLenum ResourceProvider::BindForSampling(ResourceId resource_id,
1815 GLenum unit,
1816 GLenum filter) {
1817 DCHECK(thread_checker_.CalledOnValidThread());
1818 GLES2Interface* gl = ContextGL();
1819 ResourceMap::iterator it = resources_.find(resource_id);
1820 DCHECK(it != resources_.end());
1821 Resource* resource = &it->second;
1822 DCHECK(resource->lock_for_read_count);
1823 DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced);
1825 ScopedSetActiveTexture scoped_active_tex(gl, unit);
1826 GLenum target = resource->target;
1827 gl->BindTexture(target, resource->gl_id);
1828 if (filter != resource->filter) {
1829 gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
1830 gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
1831 resource->filter = filter;
1834 if (resource->image_id && resource->dirty_image)
1835 BindImageForSampling(resource);
1837 return target;
1840 void ResourceProvider::BeginSetPixels(ResourceId id) {
1841 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1842 "ResourceProvider::BeginSetPixels");
1844 Resource* resource = GetResource(id);
1845 DCHECK(!resource->pending_set_pixels);
1847 LazyCreate(resource);
1848 DCHECK(resource->origin == Resource::INTERNAL);
1849 DCHECK(resource->gl_id || resource->allocated);
1850 DCHECK(ReadLockFenceHasPassed(resource));
1851 DCHECK(!resource->image_id);
1853 bool allocate = !resource->allocated;
1854 resource->allocated = true;
1855 LockForWrite(id);
1857 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1858 DCHECK(resource->gl_id);
1859 GLES2Interface* gl = ContextGL();
1860 DCHECK(gl);
1861 DCHECK(resource->gl_pixel_buffer_id);
1862 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
1863 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1864 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1865 resource->gl_pixel_buffer_id);
1866 if (!resource->gl_upload_query_id)
1867 gl->GenQueriesEXT(1, &resource->gl_upload_query_id);
1868 gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM,
1869 resource->gl_upload_query_id);
1870 if (allocate) {
1871 gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D,
1872 0, /* level */
1873 GLInternalFormat(resource->format),
1874 resource->size.width(),
1875 resource->size.height(),
1876 0, /* border */
1877 GLDataFormat(resource->format),
1878 GLDataType(resource->format),
1879 NULL);
1880 } else {
1881 gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D,
1882 0, /* level */
1883 0, /* x */
1884 0, /* y */
1885 resource->size.width(),
1886 resource->size.height(),
1887 GLDataFormat(resource->format),
1888 GLDataType(resource->format),
1889 NULL);
1891 gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM);
1892 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1894 resource->pending_set_pixels = true;
1895 resource->set_pixels_completion_forced = false;
1898 void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) {
1899 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1900 "ResourceProvider::ForceSetPixelsToComplete");
1902 Resource* resource = GetResource(id);
1904 DCHECK(resource->locked_for_write);
1905 DCHECK(resource->pending_set_pixels);
1906 DCHECK(!resource->set_pixels_completion_forced);
1908 if (resource->gl_id) {
1909 GLES2Interface* gl = ContextGL();
1910 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1911 gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D);
1912 gl->BindTexture(GL_TEXTURE_2D, 0);
1915 resource->set_pixels_completion_forced = true;
1918 bool ResourceProvider::DidSetPixelsComplete(ResourceId id) {
1919 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1920 "ResourceProvider::DidSetPixelsComplete");
1922 Resource* resource = GetResource(id);
1924 DCHECK(resource->locked_for_write);
1925 DCHECK(resource->pending_set_pixels);
1927 if (resource->gl_id) {
1928 GLES2Interface* gl = ContextGL();
1929 DCHECK(gl);
1930 DCHECK(resource->gl_upload_query_id);
1931 GLuint complete = 1;
1932 gl->GetQueryObjectuivEXT(
1933 resource->gl_upload_query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete);
1934 if (!complete)
1935 return false;
1938 resource->pending_set_pixels = false;
1939 UnlockForWrite(resource);
1941 // Async set pixels commands are not necessarily processed in-sequence with
1942 // drawing commands. Read lock fences are required to ensure that async
1943 // commands don't access the resource while used for drawing.
1944 resource->read_lock_fences_enabled = true;
1946 return true;
1949 void ResourceProvider::CreateForTesting(ResourceId id) {
1950 LazyCreate(GetResource(id));
1953 GLenum ResourceProvider::TargetForTesting(ResourceId id) {
1954 Resource* resource = GetResource(id);
1955 return resource->target;
1958 void ResourceProvider::LazyCreate(Resource* resource) {
1959 if (resource->type != RESOURCE_TYPE_GL_TEXTURE ||
1960 resource->origin != Resource::INTERNAL)
1961 return;
1963 if (resource->gl_id)
1964 return;
1966 DCHECK(resource->texture_pool);
1967 DCHECK(resource->origin == Resource::INTERNAL);
1968 DCHECK(!resource->mailbox.IsValid());
1969 resource->gl_id = texture_id_allocator_->NextId();
1971 GLES2Interface* gl = ContextGL();
1972 DCHECK(gl);
1974 // Create and set texture properties. Allocation is delayed until needed.
1975 gl->BindTexture(resource->target, resource->gl_id);
1976 gl->TexParameteri(resource->target, GL_TEXTURE_MIN_FILTER,
1977 resource->original_filter);
1978 gl->TexParameteri(resource->target, GL_TEXTURE_MAG_FILTER,
1979 resource->original_filter);
1980 gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode);
1981 gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode);
1982 gl->TexParameteri(resource->target, GL_TEXTURE_POOL_CHROMIUM,
1983 resource->texture_pool);
1984 if (use_texture_usage_hint_ && (resource->hint & TEXTURE_HINT_FRAMEBUFFER)) {
1985 gl->TexParameteri(resource->target, GL_TEXTURE_USAGE_ANGLE,
1986 GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1990 void ResourceProvider::AllocateForTesting(ResourceId id) {
1991 LazyAllocate(GetResource(id));
1994 void ResourceProvider::LazyAllocate(Resource* resource) {
1995 DCHECK(resource);
1996 if (resource->allocated)
1997 return;
1998 LazyCreate(resource);
1999 if (!resource->gl_id)
2000 return;
2001 resource->allocated = true;
2002 GLES2Interface* gl = ContextGL();
2003 gfx::Size& size = resource->size;
2004 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
2005 ResourceFormat format = resource->format;
2006 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
2007 if (use_texture_storage_ext_ &&
2008 IsFormatSupportedForStorage(format, use_texture_format_bgra_) &&
2009 (resource->hint & TEXTURE_HINT_IMMUTABLE)) {
2010 GLenum storage_format = TextureToStorageFormat(format);
2011 gl->TexStorage2DEXT(GL_TEXTURE_2D, 1, storage_format, size.width(),
2012 size.height());
2013 } else {
2014 // ETC1 does not support preallocation.
2015 if (format != ETC1) {
2016 gl->TexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(format), size.width(),
2017 size.height(), 0, GLDataFormat(format), GLDataType(format),
2018 NULL);
2023 void ResourceProvider::BindImageForSampling(Resource* resource) {
2024 GLES2Interface* gl = ContextGL();
2025 DCHECK(resource->gl_id);
2026 DCHECK(resource->image_id);
2028 // Release image currently bound to texture.
2029 if (resource->bound_image_id)
2030 gl->ReleaseTexImage2DCHROMIUM(resource->target, resource->bound_image_id);
2031 gl->BindTexImage2DCHROMIUM(resource->target, resource->image_id);
2032 resource->bound_image_id = resource->image_id;
2033 resource->dirty_image = false;
2036 void ResourceProvider::CopyResource(ResourceId source_id, ResourceId dest_id) {
2037 TRACE_EVENT0("cc", "ResourceProvider::CopyResource");
2039 Resource* source_resource = GetResource(source_id);
2040 DCHECK(!source_resource->lock_for_read_count);
2041 DCHECK(source_resource->origin == Resource::INTERNAL);
2042 DCHECK_EQ(source_resource->exported_count, 0);
2043 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, source_resource->type);
2044 DCHECK(source_resource->allocated);
2045 LazyCreate(source_resource);
2047 Resource* dest_resource = GetResource(dest_id);
2048 DCHECK(!dest_resource->locked_for_write);
2049 DCHECK(!dest_resource->lock_for_read_count);
2050 DCHECK(dest_resource->origin == Resource::INTERNAL);
2051 DCHECK_EQ(dest_resource->exported_count, 0);
2052 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, dest_resource->type);
2053 LazyAllocate(dest_resource);
2055 DCHECK_EQ(source_resource->type, dest_resource->type);
2056 DCHECK_EQ(source_resource->format, dest_resource->format);
2057 DCHECK(source_resource->size == dest_resource->size);
2059 GLES2Interface* gl = ContextGL();
2060 DCHECK(gl);
2061 if (source_resource->image_id && source_resource->dirty_image) {
2062 gl->BindTexture(source_resource->target, source_resource->gl_id);
2063 BindImageForSampling(source_resource);
2065 if (use_sync_query_) {
2066 if (!source_resource->gl_read_lock_query_id)
2067 gl->GenQueriesEXT(1, &source_resource->gl_read_lock_query_id);
2068 #if defined(OS_CHROMEOS)
2069 // TODO(reveman): This avoids a performance problem on some ChromeOS
2070 // devices. This needs to be removed to support native GpuMemoryBuffer
2071 // implementations. crbug.com/436314
2072 gl->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM,
2073 source_resource->gl_read_lock_query_id);
2074 #else
2075 gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM,
2076 source_resource->gl_read_lock_query_id);
2077 #endif
2079 DCHECK(!dest_resource->image_id);
2080 dest_resource->allocated = true;
2081 gl->CopySubTextureCHROMIUM(dest_resource->target, source_resource->gl_id,
2082 dest_resource->gl_id, 0, 0);
2083 if (source_resource->gl_read_lock_query_id) {
2084 // End query and create a read lock fence that will prevent access to
2085 // source resource until CopySubTextureCHROMIUM command has completed.
2086 #if defined(OS_CHROMEOS)
2087 gl->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
2088 #else
2089 gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
2090 #endif
2091 source_resource->read_lock_fence = make_scoped_refptr(
2092 new CopyTextureFence(gl, source_resource->gl_read_lock_query_id));
2093 } else {
2094 // Create a SynchronousFence when CHROMIUM_sync_query extension is missing.
2095 // Try to use one synchronous fence for as many CopyResource operations as
2096 // possible as that reduce the number of times we have to synchronize with
2097 // the GL.
2098 if (!synchronous_fence_.get() || synchronous_fence_->has_synchronized())
2099 synchronous_fence_ = make_scoped_refptr(new SynchronousFence(gl));
2100 source_resource->read_lock_fence = synchronous_fence_;
2101 source_resource->read_lock_fence->Set();
2105 void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) {
2106 Resource* resource = GetResource(id);
2107 DCHECK_EQ(resource->exported_count, 0);
2108 DCHECK(resource->allocated);
2109 if (resource->type != RESOURCE_TYPE_GL_TEXTURE || resource->gl_id)
2110 return;
2111 if (!resource->mailbox.sync_point())
2112 return;
2113 DCHECK(resource->mailbox.IsValid());
2114 GLES2Interface* gl = ContextGL();
2115 DCHECK(gl);
2116 gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point());
2117 resource->mailbox.set_sync_point(0);
2120 void ResourceProvider::WaitReadLockIfNeeded(ResourceId id) {
2121 Resource* resource = GetResource(id);
2122 DCHECK_EQ(resource->exported_count, 0);
2123 if (!resource->read_lock_fence.get())
2124 return;
2126 resource->read_lock_fence->Wait();
2129 GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) {
2130 GLint active_unit = 0;
2131 gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
2132 return active_unit;
2135 void ResourceProvider::ValidateResource(ResourceId id) {
2136 DCHECK(thread_checker_.CalledOnValidThread());
2137 CHECK(id);
2138 ResourceMap::iterator it = resources_.find(id);
2139 CHECK(it != resources_.end());
2142 GLES2Interface* ResourceProvider::ContextGL() const {
2143 ContextProvider* context_provider = output_surface_->context_provider();
2144 return context_provider ? context_provider->ContextGL() : NULL;
2147 class GrContext* ResourceProvider::GrContext(bool worker_context) const {
2148 ContextProvider* context_provider =
2149 worker_context ? output_surface_->worker_context_provider()
2150 : output_surface_->context_provider();
2151 return context_provider ? context_provider->GrContext() : NULL;
2154 } // namespace cc