Roll src/third_party/skia 99c7c07:4af6580
[chromium-blink-merge.git] / cc / resources / resource_provider.cc
blob522150cfd1b1f985a7ec4d2ae869f52e873cafb6
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() {}
248 ResourceProvider::Resource::Resource(GLuint texture_id,
249 const gfx::Size& size,
250 Origin origin,
251 GLenum target,
252 GLenum filter,
253 GLenum texture_pool,
254 GLint wrap_mode,
255 TextureHint hint,
256 ResourceFormat format)
257 : child_id(0),
258 gl_id(texture_id),
259 gl_pixel_buffer_id(0),
260 gl_upload_query_id(0),
261 gl_read_lock_query_id(0),
262 pixels(NULL),
263 lock_for_read_count(0),
264 imported_count(0),
265 exported_count(0),
266 dirty_image(false),
267 locked_for_write(false),
268 lost(false),
269 marked_for_deletion(false),
270 pending_set_pixels(false),
271 set_pixels_completion_forced(false),
272 allocated(false),
273 read_lock_fences_enabled(false),
274 has_shared_bitmap_id(false),
275 allow_overlay(false),
276 read_lock_fence(NULL),
277 size(size),
278 origin(origin),
279 target(target),
280 original_filter(filter),
281 filter(filter),
282 image_id(0),
283 bound_image_id(0),
284 texture_pool(texture_pool),
285 wrap_mode(wrap_mode),
286 hint(hint),
287 type(RESOURCE_TYPE_GL_TEXTURE),
288 format(format),
289 shared_bitmap(NULL),
290 gpu_memory_buffer(NULL) {
291 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
292 DCHECK_EQ(origin == INTERNAL, !!texture_pool);
295 ResourceProvider::Resource::Resource(uint8_t* pixels,
296 SharedBitmap* bitmap,
297 const gfx::Size& size,
298 Origin origin,
299 GLenum filter,
300 GLint wrap_mode)
301 : child_id(0),
302 gl_id(0),
303 gl_pixel_buffer_id(0),
304 gl_upload_query_id(0),
305 gl_read_lock_query_id(0),
306 pixels(pixels),
307 lock_for_read_count(0),
308 imported_count(0),
309 exported_count(0),
310 dirty_image(false),
311 locked_for_write(false),
312 lost(false),
313 marked_for_deletion(false),
314 pending_set_pixels(false),
315 set_pixels_completion_forced(false),
316 allocated(false),
317 read_lock_fences_enabled(false),
318 has_shared_bitmap_id(!!bitmap),
319 allow_overlay(false),
320 read_lock_fence(NULL),
321 size(size),
322 origin(origin),
323 target(0),
324 original_filter(filter),
325 filter(filter),
326 image_id(0),
327 bound_image_id(0),
328 texture_pool(0),
329 wrap_mode(wrap_mode),
330 hint(TEXTURE_HINT_IMMUTABLE),
331 type(RESOURCE_TYPE_BITMAP),
332 format(RGBA_8888),
333 shared_bitmap(bitmap),
334 gpu_memory_buffer(NULL) {
335 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
336 DCHECK(origin == DELEGATED || pixels);
337 if (bitmap)
338 shared_bitmap_id = bitmap->id();
341 ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id,
342 const gfx::Size& size,
343 Origin origin,
344 GLenum filter,
345 GLint wrap_mode)
346 : child_id(0),
347 gl_id(0),
348 gl_pixel_buffer_id(0),
349 gl_upload_query_id(0),
350 gl_read_lock_query_id(0),
351 pixels(NULL),
352 lock_for_read_count(0),
353 imported_count(0),
354 exported_count(0),
355 dirty_image(false),
356 locked_for_write(false),
357 lost(false),
358 marked_for_deletion(false),
359 pending_set_pixels(false),
360 set_pixels_completion_forced(false),
361 allocated(false),
362 read_lock_fences_enabled(false),
363 has_shared_bitmap_id(true),
364 allow_overlay(false),
365 read_lock_fence(NULL),
366 size(size),
367 origin(origin),
368 target(0),
369 original_filter(filter),
370 filter(filter),
371 image_id(0),
372 bound_image_id(0),
373 texture_pool(0),
374 wrap_mode(wrap_mode),
375 hint(TEXTURE_HINT_IMMUTABLE),
376 type(RESOURCE_TYPE_BITMAP),
377 format(RGBA_8888),
378 shared_bitmap_id(bitmap_id),
379 shared_bitmap(NULL),
380 gpu_memory_buffer(NULL) {
381 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
384 ResourceProvider::Child::Child()
385 : marked_for_deletion(false), needs_sync_points(true) {
388 ResourceProvider::Child::~Child() {}
390 scoped_ptr<ResourceProvider> ResourceProvider::Create(
391 OutputSurface* output_surface,
392 SharedBitmapManager* shared_bitmap_manager,
393 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
394 BlockingTaskRunner* blocking_main_thread_task_runner,
395 int highp_threshold_min,
396 bool use_rgba_4444_texture_format,
397 size_t id_allocation_chunk_size) {
398 ContextProvider* context_provider = output_surface->context_provider();
399 GLES2Interface* gl =
400 context_provider ? context_provider->ContextGL() : nullptr;
401 ResourceType default_resource_type =
402 gl ? RESOURCE_TYPE_GL_TEXTURE : RESOURCE_TYPE_BITMAP;
404 scoped_ptr<ResourceProvider> resource_provider(new ResourceProvider(
405 output_surface, shared_bitmap_manager, gpu_memory_buffer_manager,
406 blocking_main_thread_task_runner, highp_threshold_min,
407 default_resource_type, use_rgba_4444_texture_format,
408 id_allocation_chunk_size));
410 if (gl)
411 resource_provider->InitializeGL();
412 else
413 resource_provider->InitializeSoftware();
415 return resource_provider.Pass();
418 ResourceProvider::~ResourceProvider() {
419 while (!children_.empty())
420 DestroyChildInternal(children_.begin(), FOR_SHUTDOWN);
421 while (!resources_.empty())
422 DeleteResourceInternal(resources_.begin(), FOR_SHUTDOWN);
424 GLES2Interface* gl = ContextGL();
425 if (default_resource_type_ != RESOURCE_TYPE_GL_TEXTURE) {
426 // We are not in GL mode, but double check before returning.
427 DCHECK(!gl);
428 DCHECK(!texture_uploader_);
429 return;
432 DCHECK(gl);
433 #if DCHECK_IS_ON()
434 // Check that all GL resources has been deleted.
435 for (ResourceMap::const_iterator itr = resources_.begin();
436 itr != resources_.end(); ++itr) {
437 DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, itr->second.type);
439 #endif // DCHECK_IS_ON()
441 texture_uploader_ = nullptr;
442 texture_id_allocator_ = nullptr;
443 buffer_id_allocator_ = nullptr;
444 gl->Finish();
447 bool ResourceProvider::InUseByConsumer(ResourceId id) {
448 Resource* resource = GetResource(id);
449 return resource->lock_for_read_count > 0 || resource->exported_count > 0 ||
450 resource->lost;
453 bool ResourceProvider::IsLost(ResourceId id) {
454 Resource* resource = GetResource(id);
455 return resource->lost;
458 bool ResourceProvider::AllowOverlay(ResourceId id) {
459 Resource* resource = GetResource(id);
460 return resource->allow_overlay;
463 ResourceProvider::ResourceId ResourceProvider::CreateResource(
464 const gfx::Size& size,
465 GLint wrap_mode,
466 TextureHint hint,
467 ResourceFormat format) {
468 DCHECK(!size.IsEmpty());
469 switch (default_resource_type_) {
470 case RESOURCE_TYPE_GL_TEXTURE:
471 return CreateGLTexture(size,
472 GL_TEXTURE_2D,
473 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
474 wrap_mode,
475 hint,
476 format);
477 case RESOURCE_TYPE_BITMAP:
478 DCHECK_EQ(RGBA_8888, format);
479 return CreateBitmap(size, wrap_mode);
482 LOG(FATAL) << "Invalid default resource type.";
483 return 0;
486 ResourceProvider::ResourceId ResourceProvider::CreateManagedResource(
487 const gfx::Size& size,
488 GLenum target,
489 GLint wrap_mode,
490 TextureHint hint,
491 ResourceFormat format) {
492 DCHECK(!size.IsEmpty());
493 switch (default_resource_type_) {
494 case RESOURCE_TYPE_GL_TEXTURE:
495 return CreateGLTexture(size,
496 target,
497 GL_TEXTURE_POOL_MANAGED_CHROMIUM,
498 wrap_mode,
499 hint,
500 format);
501 case RESOURCE_TYPE_BITMAP:
502 DCHECK_EQ(RGBA_8888, format);
503 return CreateBitmap(size, wrap_mode);
506 LOG(FATAL) << "Invalid default resource type.";
507 return 0;
510 ResourceProvider::ResourceId ResourceProvider::CreateGLTexture(
511 const gfx::Size& size,
512 GLenum target,
513 GLenum texture_pool,
514 GLint wrap_mode,
515 TextureHint hint,
516 ResourceFormat format) {
517 DCHECK_LE(size.width(), max_texture_size_);
518 DCHECK_LE(size.height(), max_texture_size_);
519 DCHECK(thread_checker_.CalledOnValidThread());
521 ResourceId id = next_id_++;
522 Resource* resource = InsertResource(
523 id, Resource(0, size, Resource::INTERNAL, target, GL_LINEAR, texture_pool,
524 wrap_mode, hint, format));
525 resource->allocated = false;
526 return id;
529 ResourceProvider::ResourceId ResourceProvider::CreateBitmap(
530 const gfx::Size& size, GLint wrap_mode) {
531 DCHECK(thread_checker_.CalledOnValidThread());
533 scoped_ptr<SharedBitmap> bitmap =
534 shared_bitmap_manager_->AllocateSharedBitmap(size);
535 uint8_t* pixels = bitmap->pixels();
536 DCHECK(pixels);
538 ResourceId id = next_id_++;
539 Resource* resource =
540 InsertResource(id, Resource(pixels, bitmap.release(), size,
541 Resource::INTERNAL, GL_LINEAR, wrap_mode));
542 resource->allocated = true;
543 return id;
546 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromIOSurface(
547 const gfx::Size& size,
548 unsigned io_surface_id) {
549 DCHECK(thread_checker_.CalledOnValidThread());
551 ResourceId id = next_id_++;
552 Resource* resource = InsertResource(
553 id, Resource(0, gfx::Size(), Resource::INTERNAL, GL_TEXTURE_RECTANGLE_ARB,
554 GL_LINEAR, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
555 GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888));
556 LazyCreate(resource);
557 GLES2Interface* gl = ContextGL();
558 DCHECK(gl);
559 gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource->gl_id);
560 gl->TexImageIOSurface2DCHROMIUM(
561 GL_TEXTURE_RECTANGLE_ARB, size.width(), size.height(), io_surface_id, 0);
562 resource->allocated = true;
563 return id;
566 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
567 const TextureMailbox& mailbox,
568 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl) {
569 DCHECK(thread_checker_.CalledOnValidThread());
570 // Just store the information. Mailbox will be consumed in LockForRead().
571 ResourceId id = next_id_++;
572 DCHECK(mailbox.IsValid());
573 Resource* resource = nullptr;
574 if (mailbox.IsTexture()) {
575 resource = InsertResource(
576 id, Resource(0, gfx::Size(), Resource::EXTERNAL, mailbox.target(),
577 mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR, 0,
578 GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888));
579 } else {
580 DCHECK(mailbox.IsSharedMemory());
581 SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
582 uint8_t* pixels = shared_bitmap->pixels();
583 DCHECK(pixels);
584 resource = InsertResource(
585 id, Resource(pixels, shared_bitmap, mailbox.shared_memory_size(),
586 Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE));
588 resource->allocated = true;
589 resource->mailbox = mailbox;
590 resource->release_callback_impl =
591 base::Bind(&SingleReleaseCallbackImpl::Run,
592 base::Owned(release_callback_impl.release()));
593 resource->allow_overlay = mailbox.allow_overlay();
594 return id;
597 void ResourceProvider::DeleteResource(ResourceId id) {
598 DCHECK(thread_checker_.CalledOnValidThread());
599 ResourceMap::iterator it = resources_.find(id);
600 CHECK(it != resources_.end());
601 Resource* resource = &it->second;
602 DCHECK(!resource->marked_for_deletion);
603 DCHECK_EQ(resource->imported_count, 0);
604 DCHECK(resource->pending_set_pixels || !resource->locked_for_write);
606 if (resource->exported_count > 0 || resource->lock_for_read_count > 0) {
607 resource->marked_for_deletion = true;
608 return;
609 } else {
610 DeleteResourceInternal(it, NORMAL);
614 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
615 DeleteStyle style) {
616 TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal");
617 Resource* resource = &it->second;
618 bool lost_resource = resource->lost;
620 DCHECK(resource->exported_count == 0 || style != NORMAL);
621 if (style == FOR_SHUTDOWN && resource->exported_count > 0)
622 lost_resource = true;
624 if (resource->image_id) {
625 DCHECK(resource->origin == Resource::INTERNAL);
626 GLES2Interface* gl = ContextGL();
627 DCHECK(gl);
628 gl->DestroyImageCHROMIUM(resource->image_id);
630 if (resource->gl_upload_query_id) {
631 DCHECK(resource->origin == Resource::INTERNAL);
632 GLES2Interface* gl = ContextGL();
633 DCHECK(gl);
634 gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id);
636 if (resource->gl_read_lock_query_id) {
637 DCHECK(resource->origin == Resource::INTERNAL);
638 GLES2Interface* gl = ContextGL();
639 DCHECK(gl);
640 gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id);
642 if (resource->gl_pixel_buffer_id) {
643 DCHECK(resource->origin == Resource::INTERNAL);
644 GLES2Interface* gl = ContextGL();
645 DCHECK(gl);
646 gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id);
648 if (resource->origin == Resource::EXTERNAL) {
649 DCHECK(resource->mailbox.IsValid());
650 GLuint sync_point = resource->mailbox.sync_point();
651 if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
652 DCHECK(resource->mailbox.IsTexture());
653 lost_resource |= lost_output_surface_;
654 GLES2Interface* gl = ContextGL();
655 DCHECK(gl);
656 if (resource->gl_id) {
657 gl->DeleteTextures(1, &resource->gl_id);
658 resource->gl_id = 0;
659 if (!lost_resource)
660 sync_point = gl->InsertSyncPointCHROMIUM();
662 } else {
663 DCHECK(resource->mailbox.IsSharedMemory());
664 resource->shared_bitmap = nullptr;
665 resource->pixels = nullptr;
667 resource->release_callback_impl.Run(
668 sync_point, lost_resource, blocking_main_thread_task_runner_);
670 if (resource->gl_id) {
671 GLES2Interface* gl = ContextGL();
672 DCHECK(gl);
673 gl->DeleteTextures(1, &resource->gl_id);
674 resource->gl_id = 0;
676 if (resource->shared_bitmap) {
677 DCHECK(resource->origin != Resource::EXTERNAL);
678 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
679 delete resource->shared_bitmap;
680 resource->pixels = NULL;
682 if (resource->pixels) {
683 DCHECK(resource->origin == Resource::INTERNAL);
684 delete[] resource->pixels;
685 resource->pixels = NULL;
687 if (resource->gpu_memory_buffer) {
688 DCHECK(resource->origin == Resource::INTERNAL);
689 delete resource->gpu_memory_buffer;
690 resource->gpu_memory_buffer = NULL;
692 resources_.erase(it);
695 ResourceProvider::ResourceType ResourceProvider::GetResourceType(
696 ResourceId id) {
697 return GetResource(id)->type;
700 void ResourceProvider::SetPixels(ResourceId id,
701 const uint8_t* image,
702 const gfx::Rect& image_rect,
703 const gfx::Rect& source_rect,
704 const gfx::Vector2d& dest_offset) {
705 Resource* resource = GetResource(id);
706 DCHECK(!resource->locked_for_write);
707 DCHECK(!resource->lock_for_read_count);
708 DCHECK(resource->origin == Resource::INTERNAL);
709 DCHECK_EQ(resource->exported_count, 0);
710 DCHECK(ReadLockFenceHasPassed(resource));
711 LazyAllocate(resource);
713 if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
714 DCHECK(resource->gl_id);
715 DCHECK(!resource->pending_set_pixels);
716 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
717 GLES2Interface* gl = ContextGL();
718 DCHECK(gl);
719 DCHECK(texture_uploader_.get());
720 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
721 texture_uploader_->Upload(image,
722 image_rect,
723 source_rect,
724 dest_offset,
725 resource->format,
726 resource->size);
727 } else {
728 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
729 DCHECK(resource->allocated);
730 DCHECK_EQ(RGBA_8888, resource->format);
731 DCHECK(source_rect.x() >= image_rect.x());
732 DCHECK(source_rect.y() >= image_rect.y());
733 DCHECK(source_rect.right() <= image_rect.right());
734 DCHECK(source_rect.bottom() <= image_rect.bottom());
735 SkImageInfo source_info =
736 SkImageInfo::MakeN32Premul(source_rect.width(), source_rect.height());
737 size_t image_row_bytes = image_rect.width() * 4;
738 gfx::Vector2d source_offset = source_rect.origin() - image_rect.origin();
739 image += source_offset.y() * image_row_bytes + source_offset.x() * 4;
741 ScopedWriteLockSoftware lock(this, id);
742 SkCanvas dest(lock.sk_bitmap());
743 dest.writePixels(source_info, image, image_row_bytes, dest_offset.x(),
744 dest_offset.y());
748 void ResourceProvider::CopyToResource(ResourceId id,
749 const uint8_t* image,
750 const gfx::Size& image_size) {
751 Resource* resource = GetResource(id);
752 DCHECK(!resource->locked_for_write);
753 DCHECK(!resource->lock_for_read_count);
754 DCHECK(resource->origin == Resource::INTERNAL);
755 DCHECK_EQ(resource->exported_count, 0);
756 DCHECK(ReadLockFenceHasPassed(resource));
757 LazyAllocate(resource);
759 DCHECK_EQ(image_size.width(), resource->size.width());
760 DCHECK_EQ(image_size.height(), resource->size.height());
762 if (resource->type == RESOURCE_TYPE_BITMAP) {
763 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
764 DCHECK(resource->allocated);
765 DCHECK_EQ(RGBA_8888, resource->format);
766 SkImageInfo source_info =
767 SkImageInfo::MakeN32Premul(image_size.width(), image_size.height());
768 size_t image_stride = image_size.width() * 4;
770 ScopedWriteLockSoftware lock(this, id);
771 SkCanvas dest(lock.sk_bitmap());
772 dest.writePixels(source_info, image, image_stride, 0, 0);
773 } else {
774 DCHECK(resource->gl_id);
775 DCHECK(!resource->pending_set_pixels);
776 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
777 GLES2Interface* gl = ContextGL();
778 DCHECK(gl);
779 DCHECK(texture_uploader_.get());
780 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
782 if (resource->format == ETC1) {
783 size_t num_bytes = static_cast<size_t>(image_size.width()) *
784 image_size.height() * BitsPerPixel(ETC1) / 8;
785 gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1),
786 image_size.width(), image_size.height(), 0,
787 num_bytes, image);
788 } else {
789 gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(),
790 image_size.height(), GLDataFormat(resource->format),
791 GLDataType(resource->format), image);
796 size_t ResourceProvider::NumBlockingUploads() {
797 if (!texture_uploader_)
798 return 0;
800 return texture_uploader_->NumBlockingUploads();
803 void ResourceProvider::MarkPendingUploadsAsNonBlocking() {
804 if (!texture_uploader_)
805 return;
807 texture_uploader_->MarkPendingUploadsAsNonBlocking();
810 size_t ResourceProvider::EstimatedUploadsPerTick() {
811 if (!texture_uploader_)
812 return 1u;
814 double textures_per_second = texture_uploader_->EstimatedTexturesPerSecond();
815 size_t textures_per_tick = floor(
816 kTextureUploadTickRate * textures_per_second);
817 return textures_per_tick ? textures_per_tick : 1u;
820 void ResourceProvider::FlushUploads() {
821 if (!texture_uploader_)
822 return;
824 texture_uploader_->Flush();
827 void ResourceProvider::ReleaseCachedData() {
828 if (!texture_uploader_)
829 return;
831 texture_uploader_->ReleaseCachedQueries();
834 base::TimeTicks ResourceProvider::EstimatedUploadCompletionTime(
835 size_t uploads_per_tick) {
836 if (lost_output_surface_)
837 return base::TimeTicks();
839 // Software resource uploads happen on impl thread, so don't bother batching
840 // them up and trying to wait for them to complete.
841 if (!texture_uploader_) {
842 return gfx::FrameTime::Now() + base::TimeDelta::FromMicroseconds(
843 base::Time::kMicrosecondsPerSecond * kSoftwareUploadTickRate);
846 base::TimeDelta upload_one_texture_time =
847 base::TimeDelta::FromMicroseconds(
848 base::Time::kMicrosecondsPerSecond * kTextureUploadTickRate) /
849 uploads_per_tick;
851 size_t total_uploads = NumBlockingUploads() + uploads_per_tick;
852 return gfx::FrameTime::Now() + upload_one_texture_time * total_uploads;
855 ResourceProvider::Resource* ResourceProvider::InsertResource(
856 ResourceId id,
857 const Resource& resource) {
858 std::pair<ResourceMap::iterator, bool> result =
859 resources_.insert(ResourceMap::value_type(id, resource));
860 DCHECK(result.second);
861 return &result.first->second;
864 ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) {
865 DCHECK(thread_checker_.CalledOnValidThread());
866 DCHECK(id);
867 ResourceMap::iterator it = resources_.find(id);
868 DCHECK(it != resources_.end());
869 return &it->second;
872 const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
873 Resource* resource = GetResource(id);
874 DCHECK(!resource->locked_for_write ||
875 resource->set_pixels_completion_forced) <<
876 "locked for write: " << resource->locked_for_write <<
877 " pixels completion forced: " << resource->set_pixels_completion_forced;
878 DCHECK_EQ(resource->exported_count, 0);
879 // Uninitialized! Call SetPixels or LockForWrite first.
880 DCHECK(resource->allocated);
882 LazyCreate(resource);
884 if (resource->type == RESOURCE_TYPE_GL_TEXTURE && !resource->gl_id) {
885 DCHECK(resource->origin != Resource::INTERNAL);
886 DCHECK(resource->mailbox.IsTexture());
888 // Mailbox sync_points must be processed by a call to
889 // WaitSyncPointIfNeeded() prior to calling LockForRead().
890 DCHECK(!resource->mailbox.sync_point());
892 GLES2Interface* gl = ContextGL();
893 DCHECK(gl);
894 resource->gl_id = gl->CreateAndConsumeTextureCHROMIUM(
895 resource->mailbox.target(), resource->mailbox.name());
898 if (!resource->pixels && resource->has_shared_bitmap_id &&
899 shared_bitmap_manager_) {
900 scoped_ptr<SharedBitmap> bitmap =
901 shared_bitmap_manager_->GetSharedBitmapFromId(
902 resource->size, resource->shared_bitmap_id);
903 if (bitmap) {
904 resource->shared_bitmap = bitmap.release();
905 resource->pixels = resource->shared_bitmap->pixels();
909 resource->lock_for_read_count++;
910 if (resource->read_lock_fences_enabled) {
911 if (current_read_lock_fence_.get())
912 current_read_lock_fence_->Set();
913 resource->read_lock_fence = current_read_lock_fence_;
916 return resource;
919 void ResourceProvider::UnlockForRead(ResourceId id) {
920 DCHECK(thread_checker_.CalledOnValidThread());
921 ResourceMap::iterator it = resources_.find(id);
922 CHECK(it != resources_.end());
924 Resource* resource = &it->second;
925 DCHECK_GT(resource->lock_for_read_count, 0);
926 DCHECK_EQ(resource->exported_count, 0);
927 resource->lock_for_read_count--;
928 if (resource->marked_for_deletion && !resource->lock_for_read_count) {
929 if (!resource->child_id) {
930 // The resource belongs to this ResourceProvider, so it can be destroyed.
931 DeleteResourceInternal(it, NORMAL);
932 } else {
933 ChildMap::iterator child_it = children_.find(resource->child_id);
934 ResourceIdArray unused;
935 unused.push_back(id);
936 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
941 ResourceProvider::Resource* ResourceProvider::LockForWrite(ResourceId id) {
942 Resource* resource = GetResource(id);
943 DCHECK(CanLockForWrite(id));
945 resource->locked_for_write = true;
946 return resource;
949 bool ResourceProvider::CanLockForWrite(ResourceId id) {
950 Resource* resource = GetResource(id);
951 return !resource->locked_for_write && !resource->lock_for_read_count &&
952 !resource->exported_count && resource->origin == Resource::INTERNAL &&
953 !resource->lost && ReadLockFenceHasPassed(resource);
956 void ResourceProvider::UnlockForWrite(ResourceProvider::Resource* resource) {
957 DCHECK(resource->locked_for_write);
958 DCHECK_EQ(resource->exported_count, 0);
959 DCHECK(resource->origin == Resource::INTERNAL);
960 resource->locked_for_write = false;
963 ResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
964 ResourceProvider* resource_provider,
965 ResourceProvider::ResourceId resource_id)
966 : resource_provider_(resource_provider),
967 resource_id_(resource_id),
968 texture_id_(resource_provider->LockForRead(resource_id)->gl_id) {
969 DCHECK(texture_id_);
972 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
973 resource_provider_->UnlockForRead(resource_id_);
976 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
977 ResourceProvider* resource_provider,
978 ResourceProvider::ResourceId resource_id,
979 GLenum filter)
980 : ScopedReadLockGL(resource_provider, resource_id),
981 unit_(GL_TEXTURE0),
982 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
985 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
986 ResourceProvider* resource_provider,
987 ResourceProvider::ResourceId resource_id,
988 GLenum unit,
989 GLenum filter)
990 : ScopedReadLockGL(resource_provider, resource_id),
991 unit_(unit),
992 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
995 ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() {
998 ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(
999 ResourceProvider* resource_provider,
1000 ResourceProvider::ResourceId resource_id)
1001 : resource_provider_(resource_provider),
1002 resource_(resource_provider->LockForWrite(resource_id)) {
1003 resource_provider_->LazyAllocate(resource_);
1004 texture_id_ = resource_->gl_id;
1005 DCHECK(texture_id_);
1008 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() {
1009 resource_provider_->UnlockForWrite(resource_);
1012 void ResourceProvider::PopulateSkBitmapWithResource(
1013 SkBitmap* sk_bitmap, const Resource* resource) {
1014 DCHECK_EQ(RGBA_8888, resource->format);
1015 SkImageInfo info = SkImageInfo::MakeN32Premul(resource->size.width(),
1016 resource->size.height());
1017 sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes());
1020 ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(
1021 ResourceProvider* resource_provider,
1022 ResourceProvider::ResourceId resource_id)
1023 : resource_provider_(resource_provider),
1024 resource_id_(resource_id) {
1025 const Resource* resource = resource_provider->LockForRead(resource_id);
1026 wrap_mode_ = resource->wrap_mode;
1027 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource);
1030 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() {
1031 resource_provider_->UnlockForRead(resource_id_);
1034 ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(
1035 ResourceProvider* resource_provider,
1036 ResourceProvider::ResourceId resource_id)
1037 : resource_provider_(resource_provider),
1038 resource_(resource_provider->LockForWrite(resource_id)) {
1039 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource_);
1040 DCHECK(valid());
1043 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() {
1044 DCHECK(thread_checker_.CalledOnValidThread());
1045 resource_provider_->UnlockForWrite(resource_);
1048 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
1049 ScopedWriteLockGpuMemoryBuffer(ResourceProvider* resource_provider,
1050 ResourceProvider::ResourceId resource_id)
1051 : resource_provider_(resource_provider),
1052 resource_(resource_provider->LockForWrite(resource_id)),
1053 gpu_memory_buffer_manager_(resource_provider->gpu_memory_buffer_manager_),
1054 gpu_memory_buffer_(nullptr),
1055 size_(resource_->size),
1056 format_(resource_->format) {
1057 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource_->type);
1058 std::swap(gpu_memory_buffer_, resource_->gpu_memory_buffer);
1061 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
1062 ~ScopedWriteLockGpuMemoryBuffer() {
1063 DCHECK(thread_checker_.CalledOnValidThread());
1064 resource_provider_->UnlockForWrite(resource_);
1065 if (!gpu_memory_buffer_)
1066 return;
1068 if (!resource_->image_id) {
1069 GLES2Interface* gl = resource_provider_->ContextGL();
1070 DCHECK(gl);
1072 #if defined(OS_CHROMEOS)
1073 // TODO(reveman): GL_COMMANDS_ISSUED_CHROMIUM is used for synchronization
1074 // on ChromeOS to avoid some performance issues. This only works with
1075 // shared memory backed buffers. crbug.com/436314
1076 DCHECK_EQ(gpu_memory_buffer_->GetHandle().type, gfx::SHARED_MEMORY_BUFFER);
1077 #endif
1079 resource_->image_id = gl->CreateImageCHROMIUM(
1080 gpu_memory_buffer_->AsClientBuffer(), size_.width(), size_.height(),
1081 GLInternalFormat(resource_->format));
1084 std::swap(resource_->gpu_memory_buffer, gpu_memory_buffer_);
1085 resource_->allocated = true;
1086 resource_->dirty_image = true;
1088 // GpuMemoryBuffer provides direct access to the memory used by the GPU.
1089 // Read lock fences are required to ensure that we're not trying to map a
1090 // buffer that is currently in-use by the GPU.
1091 resource_->read_lock_fences_enabled = true;
1094 gfx::GpuMemoryBuffer*
1095 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::GetGpuMemoryBuffer() {
1096 if (!gpu_memory_buffer_) {
1097 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
1098 gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer(
1099 size_, ToGpuMemoryBufferFormat(format_), gfx::GpuMemoryBuffer::MAP);
1100 gpu_memory_buffer_ = gpu_memory_buffer.release();
1103 return gpu_memory_buffer_;
1106 ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr(
1107 ResourceProvider* resource_provider,
1108 ResourceProvider::ResourceId resource_id)
1109 : resource_provider_(resource_provider),
1110 resource_(resource_provider->LockForWrite(resource_id)) {
1111 DCHECK(thread_checker_.CalledOnValidThread());
1112 resource_provider_->LazyAllocate(resource_);
1115 ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
1116 DCHECK(thread_checker_.CalledOnValidThread());
1117 DCHECK(resource_->locked_for_write);
1118 resource_provider_->UnlockForWrite(resource_);
1121 void ResourceProvider::ScopedWriteLockGr::InitSkSurface(
1122 bool use_distance_field_text,
1123 bool can_use_lcd_text,
1124 int msaa_sample_count) {
1125 DCHECK(resource_->locked_for_write);
1127 GrBackendTextureDesc desc;
1128 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
1129 desc.fWidth = resource_->size.width();
1130 desc.fHeight = resource_->size.height();
1131 desc.fConfig = ToGrPixelConfig(resource_->format);
1132 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1133 desc.fTextureHandle = resource_->gl_id;
1134 desc.fSampleCnt = msaa_sample_count;
1136 bool use_worker_context = true;
1137 class GrContext* gr_context =
1138 resource_provider_->GrContext(use_worker_context);
1139 skia::RefPtr<GrTexture> gr_texture =
1140 skia::AdoptRef(gr_context->wrapBackendTexture(desc));
1141 if (gr_texture) {
1142 uint32_t flags = use_distance_field_text
1143 ? SkSurfaceProps::kUseDistanceFieldFonts_Flag
1144 : 0;
1145 // Use unknown pixel geometry to disable LCD text.
1146 SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
1147 if (can_use_lcd_text) {
1148 // LegacyFontHost will get LCD text and skia figures out what type to use.
1149 surface_props =
1150 SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
1152 sk_surface_ = skia::AdoptRef(SkSurface::NewRenderTargetDirect(
1153 gr_texture->asRenderTarget(), &surface_props));
1154 return;
1156 sk_surface_.clear();
1159 void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() {
1160 sk_surface_.clear();
1163 ResourceProvider::SynchronousFence::SynchronousFence(
1164 gpu::gles2::GLES2Interface* gl)
1165 : gl_(gl), has_synchronized_(true) {
1168 ResourceProvider::SynchronousFence::~SynchronousFence() {
1171 void ResourceProvider::SynchronousFence::Set() {
1172 has_synchronized_ = false;
1175 bool ResourceProvider::SynchronousFence::HasPassed() {
1176 if (!has_synchronized_) {
1177 has_synchronized_ = true;
1178 Synchronize();
1180 return true;
1183 void ResourceProvider::SynchronousFence::Wait() {
1184 HasPassed();
1187 void ResourceProvider::SynchronousFence::Synchronize() {
1188 TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize");
1189 gl_->Finish();
1192 ResourceProvider::ResourceProvider(
1193 OutputSurface* output_surface,
1194 SharedBitmapManager* shared_bitmap_manager,
1195 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
1196 BlockingTaskRunner* blocking_main_thread_task_runner,
1197 int highp_threshold_min,
1198 ResourceType default_resource_type,
1199 bool use_rgba_4444_texture_format,
1200 size_t id_allocation_chunk_size)
1201 : output_surface_(output_surface),
1202 shared_bitmap_manager_(shared_bitmap_manager),
1203 gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
1204 blocking_main_thread_task_runner_(blocking_main_thread_task_runner),
1205 lost_output_surface_(false),
1206 highp_threshold_min_(highp_threshold_min),
1207 next_id_(1),
1208 next_child_(1),
1209 default_resource_type_(default_resource_type),
1210 use_texture_storage_ext_(false),
1211 use_texture_format_bgra_(false),
1212 use_texture_usage_hint_(false),
1213 use_compressed_texture_etc1_(false),
1214 yuv_resource_format_(LUMINANCE_8),
1215 max_texture_size_(0),
1216 best_texture_format_(RGBA_8888),
1217 use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
1218 id_allocation_chunk_size_(id_allocation_chunk_size),
1219 use_sync_query_(false) {
1220 DCHECK(output_surface_->HasClient());
1221 DCHECK(id_allocation_chunk_size_);
1224 void ResourceProvider::InitializeSoftware() {
1225 DCHECK(thread_checker_.CalledOnValidThread());
1226 DCHECK_EQ(default_resource_type_, RESOURCE_TYPE_BITMAP);
1227 // Pick an arbitrary limit here similar to what hardware might.
1228 max_texture_size_ = 16 * 1024;
1229 best_texture_format_ = RGBA_8888;
1232 void ResourceProvider::InitializeGL() {
1233 DCHECK(thread_checker_.CalledOnValidThread());
1234 DCHECK_EQ(default_resource_type_, RESOURCE_TYPE_GL_TEXTURE);
1235 DCHECK(!texture_uploader_);
1236 DCHECK(!texture_id_allocator_);
1237 DCHECK(!buffer_id_allocator_);
1239 const ContextProvider::Capabilities& caps =
1240 output_surface_->context_provider()->ContextCapabilities();
1242 bool use_bgra = caps.gpu.texture_format_bgra8888;
1243 use_texture_storage_ext_ = caps.gpu.texture_storage;
1244 use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888;
1245 use_texture_usage_hint_ = caps.gpu.texture_usage;
1246 use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1;
1247 yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8;
1248 use_sync_query_ = caps.gpu.sync_query;
1250 GLES2Interface* gl = ContextGL();
1251 DCHECK(gl);
1253 texture_uploader_ = TextureUploader::Create(gl);
1254 max_texture_size_ = 0; // Context expects cleared value.
1255 gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
1256 best_texture_format_ = PlatformColor::BestTextureFormat(use_bgra);
1258 texture_id_allocator_.reset(
1259 new TextureIdAllocator(gl, id_allocation_chunk_size_));
1260 buffer_id_allocator_.reset(
1261 new BufferIdAllocator(gl, id_allocation_chunk_size_));
1264 int ResourceProvider::CreateChild(const ReturnCallback& return_callback) {
1265 DCHECK(thread_checker_.CalledOnValidThread());
1267 Child child_info;
1268 child_info.return_callback = return_callback;
1270 int child = next_child_++;
1271 children_[child] = child_info;
1272 return child;
1275 void ResourceProvider::SetChildNeedsSyncPoints(int child_id, bool needs) {
1276 ChildMap::iterator it = children_.find(child_id);
1277 DCHECK(it != children_.end());
1278 it->second.needs_sync_points = needs;
1281 void ResourceProvider::DestroyChild(int child_id) {
1282 ChildMap::iterator it = children_.find(child_id);
1283 DCHECK(it != children_.end());
1284 DestroyChildInternal(it, NORMAL);
1287 void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
1288 DeleteStyle style) {
1289 DCHECK(thread_checker_.CalledOnValidThread());
1291 Child& child = it->second;
1292 DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion);
1294 ResourceIdArray resources_for_child;
1296 for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin();
1297 child_it != child.child_to_parent_map.end();
1298 ++child_it) {
1299 ResourceId id = child_it->second;
1300 resources_for_child.push_back(id);
1303 child.marked_for_deletion = true;
1305 DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child);
1308 const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap(
1309 int child) const {
1310 DCHECK(thread_checker_.CalledOnValidThread());
1311 ChildMap::const_iterator it = children_.find(child);
1312 DCHECK(it != children_.end());
1313 DCHECK(!it->second.marked_for_deletion);
1314 return it->second.child_to_parent_map;
1317 void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
1318 TransferableResourceArray* list) {
1319 DCHECK(thread_checker_.CalledOnValidThread());
1320 GLES2Interface* gl = ContextGL();
1321 bool need_sync_point = false;
1322 for (ResourceIdArray::const_iterator it = resources.begin();
1323 it != resources.end();
1324 ++it) {
1325 TransferableResource resource;
1326 TransferResource(gl, *it, &resource);
1327 if (!resource.mailbox_holder.sync_point && !resource.is_software)
1328 need_sync_point = true;
1329 ++resources_.find(*it)->second.exported_count;
1330 list->push_back(resource);
1332 if (need_sync_point &&
1333 output_surface_->capabilities().delegated_sync_points_required) {
1334 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1335 for (TransferableResourceArray::iterator it = list->begin();
1336 it != list->end();
1337 ++it) {
1338 if (!it->mailbox_holder.sync_point)
1339 it->mailbox_holder.sync_point = sync_point;
1344 void ResourceProvider::ReceiveFromChild(
1345 int child, const TransferableResourceArray& resources) {
1346 DCHECK(thread_checker_.CalledOnValidThread());
1347 GLES2Interface* gl = ContextGL();
1348 Child& child_info = children_.find(child)->second;
1349 DCHECK(!child_info.marked_for_deletion);
1350 for (TransferableResourceArray::const_iterator it = resources.begin();
1351 it != resources.end();
1352 ++it) {
1353 ResourceIdMap::iterator resource_in_map_it =
1354 child_info.child_to_parent_map.find(it->id);
1355 if (resource_in_map_it != child_info.child_to_parent_map.end()) {
1356 Resource* resource = GetResource(resource_in_map_it->second);
1357 resource->marked_for_deletion = false;
1358 resource->imported_count++;
1359 continue;
1362 if ((!it->is_software && !gl) ||
1363 (it->is_software && !shared_bitmap_manager_)) {
1364 TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
1365 ReturnedResourceArray to_return;
1366 to_return.push_back(it->ToReturnedResource());
1367 child_info.return_callback.Run(to_return,
1368 blocking_main_thread_task_runner_);
1369 continue;
1372 ResourceId local_id = next_id_++;
1373 Resource* resource = nullptr;
1374 if (it->is_software) {
1375 resource = InsertResource(
1376 local_id,
1377 Resource(it->mailbox_holder.mailbox, it->size, Resource::DELEGATED,
1378 GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
1379 } else {
1380 resource = InsertResource(
1381 local_id, Resource(0, it->size, Resource::DELEGATED,
1382 it->mailbox_holder.texture_target, it->filter, 0,
1383 it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE,
1384 TEXTURE_HINT_IMMUTABLE, it->format));
1385 resource->mailbox = TextureMailbox(it->mailbox_holder.mailbox,
1386 it->mailbox_holder.texture_target,
1387 it->mailbox_holder.sync_point);
1389 resource->child_id = child;
1390 // Don't allocate a texture for a child.
1391 resource->allocated = true;
1392 resource->imported_count = 1;
1393 resource->allow_overlay = it->allow_overlay;
1394 child_info.parent_to_child_map[local_id] = it->id;
1395 child_info.child_to_parent_map[it->id] = local_id;
1399 void ResourceProvider::DeclareUsedResourcesFromChild(
1400 int child,
1401 const ResourceIdSet& resources_from_child) {
1402 DCHECK(thread_checker_.CalledOnValidThread());
1404 ChildMap::iterator child_it = children_.find(child);
1405 DCHECK(child_it != children_.end());
1406 Child& child_info = child_it->second;
1407 DCHECK(!child_info.marked_for_deletion);
1409 ResourceIdArray unused;
1410 for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin();
1411 it != child_info.child_to_parent_map.end();
1412 ++it) {
1413 ResourceId local_id = it->second;
1414 bool resource_is_in_use = resources_from_child.count(it->first) > 0;
1415 if (!resource_is_in_use)
1416 unused.push_back(local_id);
1418 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
1421 void ResourceProvider::ReceiveReturnsFromParent(
1422 const ReturnedResourceArray& resources) {
1423 DCHECK(thread_checker_.CalledOnValidThread());
1424 GLES2Interface* gl = ContextGL();
1426 base::hash_map<int, ResourceIdArray> resources_for_child;
1428 for (const ReturnedResource& returned : resources) {
1429 ResourceId local_id = returned.id;
1430 ResourceMap::iterator map_iterator = resources_.find(local_id);
1431 // Resource was already lost (e.g. it belonged to a child that was
1432 // destroyed).
1433 if (map_iterator == resources_.end())
1434 continue;
1436 Resource* resource = &map_iterator->second;
1438 CHECK_GE(resource->exported_count, returned.count);
1439 resource->exported_count -= returned.count;
1440 resource->lost |= returned.lost;
1441 if (resource->exported_count)
1442 continue;
1444 // Need to wait for the current read lock fence to pass before we can
1445 // recycle this resource.
1446 if (resource->read_lock_fences_enabled) {
1447 if (current_read_lock_fence_.get())
1448 current_read_lock_fence_->Set();
1449 resource->read_lock_fence = current_read_lock_fence_;
1452 if (returned.sync_point) {
1453 DCHECK(!resource->has_shared_bitmap_id);
1454 if (resource->origin == Resource::INTERNAL) {
1455 DCHECK(resource->gl_id);
1456 gl->WaitSyncPointCHROMIUM(returned.sync_point);
1457 } else {
1458 DCHECK(!resource->gl_id);
1459 resource->mailbox.set_sync_point(returned.sync_point);
1463 if (!resource->marked_for_deletion)
1464 continue;
1466 if (!resource->child_id) {
1467 // The resource belongs to this ResourceProvider, so it can be destroyed.
1468 DeleteResourceInternal(map_iterator, NORMAL);
1469 continue;
1472 DCHECK(resource->origin == Resource::DELEGATED);
1473 resources_for_child[resource->child_id].push_back(local_id);
1476 for (const auto& children : resources_for_child) {
1477 ChildMap::iterator child_it = children_.find(children.first);
1478 DCHECK(child_it != children_.end());
1479 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, children.second);
1483 void ResourceProvider::TransferResource(GLES2Interface* gl,
1484 ResourceId id,
1485 TransferableResource* resource) {
1486 Resource* source = GetResource(id);
1487 DCHECK(!source->locked_for_write);
1488 DCHECK(!source->lock_for_read_count);
1489 DCHECK(source->origin != Resource::EXTERNAL || source->mailbox.IsValid());
1490 DCHECK(source->allocated);
1491 resource->id = id;
1492 resource->format = source->format;
1493 resource->mailbox_holder.texture_target = source->target;
1494 resource->filter = source->filter;
1495 resource->size = source->size;
1496 resource->is_repeated = (source->wrap_mode == GL_REPEAT);
1497 resource->allow_overlay = source->allow_overlay;
1499 if (source->type == RESOURCE_TYPE_BITMAP) {
1500 resource->mailbox_holder.mailbox = source->shared_bitmap_id;
1501 resource->is_software = true;
1502 } else if (!source->mailbox.IsValid()) {
1503 LazyCreate(source);
1504 DCHECK(source->gl_id);
1505 DCHECK(source->origin == Resource::INTERNAL);
1506 if (source->image_id) {
1507 DCHECK(source->dirty_image);
1508 BindImageForSampling(source);
1510 // This is a resource allocated by the compositor, we need to produce it.
1511 // Don't set a sync point, the caller will do it.
1512 gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name);
1513 gl->ProduceTextureDirectCHROMIUM(source->gl_id,
1514 resource->mailbox_holder.texture_target,
1515 resource->mailbox_holder.mailbox.name);
1517 source->mailbox = TextureMailbox(resource->mailbox_holder);
1518 } else {
1519 DCHECK(source->mailbox.IsTexture());
1520 if (source->image_id && source->dirty_image) {
1521 DCHECK(source->gl_id);
1522 DCHECK(source->origin == Resource::INTERNAL);
1523 gl->BindTexture(resource->mailbox_holder.texture_target, source->gl_id);
1524 BindImageForSampling(source);
1526 // This is either an external resource, or a compositor resource that we
1527 // already exported. Make sure to forward the sync point that we were given.
1528 resource->mailbox_holder.mailbox = source->mailbox.mailbox();
1529 resource->mailbox_holder.texture_target = source->mailbox.target();
1530 resource->mailbox_holder.sync_point = source->mailbox.sync_point();
1531 source->mailbox.set_sync_point(0);
1535 void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
1536 ChildMap::iterator child_it,
1537 DeleteStyle style,
1538 const ResourceIdArray& unused) {
1539 DCHECK(thread_checker_.CalledOnValidThread());
1540 DCHECK(child_it != children_.end());
1541 Child* child_info = &child_it->second;
1543 if (unused.empty() && !child_info->marked_for_deletion)
1544 return;
1546 ReturnedResourceArray to_return;
1548 GLES2Interface* gl = ContextGL();
1549 bool need_sync_point = false;
1550 for (size_t i = 0; i < unused.size(); ++i) {
1551 ResourceId local_id = unused[i];
1553 ResourceMap::iterator it = resources_.find(local_id);
1554 CHECK(it != resources_.end());
1555 Resource& resource = it->second;
1557 DCHECK(!resource.locked_for_write);
1558 DCHECK(child_info->parent_to_child_map.count(local_id));
1560 ResourceId child_id = child_info->parent_to_child_map[local_id];
1561 DCHECK(child_info->child_to_parent_map.count(child_id));
1563 bool is_lost =
1564 resource.lost ||
1565 (resource.type == RESOURCE_TYPE_GL_TEXTURE && lost_output_surface_);
1566 if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
1567 if (style != FOR_SHUTDOWN) {
1568 // Defer this until we receive the resource back from the parent or
1569 // the read lock is released.
1570 resource.marked_for_deletion = true;
1571 continue;
1574 // We still have an exported_count, so we'll have to lose it.
1575 is_lost = true;
1578 if (gl && resource.filter != resource.original_filter) {
1579 DCHECK(resource.target);
1580 DCHECK(resource.gl_id);
1582 gl->BindTexture(resource.target, resource.gl_id);
1583 gl->TexParameteri(resource.target, GL_TEXTURE_MIN_FILTER,
1584 resource.original_filter);
1585 gl->TexParameteri(resource.target, GL_TEXTURE_MAG_FILTER,
1586 resource.original_filter);
1589 ReturnedResource returned;
1590 returned.id = child_id;
1591 returned.sync_point = resource.mailbox.sync_point();
1592 if (!returned.sync_point && resource.type == RESOURCE_TYPE_GL_TEXTURE)
1593 need_sync_point = true;
1594 returned.count = resource.imported_count;
1595 returned.lost = is_lost;
1596 to_return.push_back(returned);
1598 child_info->parent_to_child_map.erase(local_id);
1599 child_info->child_to_parent_map.erase(child_id);
1600 resource.imported_count = 0;
1601 DeleteResourceInternal(it, style);
1603 if (need_sync_point && child_info->needs_sync_points) {
1604 DCHECK(gl);
1605 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1606 for (size_t i = 0; i < to_return.size(); ++i) {
1607 if (!to_return[i].sync_point)
1608 to_return[i].sync_point = sync_point;
1612 if (!to_return.empty())
1613 child_info->return_callback.Run(to_return,
1614 blocking_main_thread_task_runner_);
1616 if (child_info->marked_for_deletion &&
1617 child_info->parent_to_child_map.empty()) {
1618 DCHECK(child_info->child_to_parent_map.empty());
1619 children_.erase(child_it);
1623 void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
1624 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1625 "ResourceProvider::AcquirePixelBuffer");
1627 Resource* resource = GetResource(id);
1628 DCHECK(resource->origin == Resource::INTERNAL);
1629 DCHECK_EQ(resource->exported_count, 0);
1630 DCHECK(!resource->image_id);
1631 DCHECK_NE(ETC1, resource->format);
1633 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1634 GLES2Interface* gl = ContextGL();
1635 DCHECK(gl);
1636 if (!resource->gl_pixel_buffer_id)
1637 resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId();
1638 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1639 resource->gl_pixel_buffer_id);
1640 unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8;
1641 gl->BufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1642 resource->size.height() *
1643 RoundUp(bytes_per_pixel * resource->size.width(), 4u),
1644 NULL,
1645 GL_DYNAMIC_DRAW);
1646 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1649 void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
1650 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1651 "ResourceProvider::ReleasePixelBuffer");
1653 Resource* resource = GetResource(id);
1654 DCHECK(resource->origin == Resource::INTERNAL);
1655 DCHECK_EQ(resource->exported_count, 0);
1656 DCHECK(!resource->image_id);
1658 // The pixel buffer can be released while there is a pending "set pixels"
1659 // if completion has been forced. Any shared memory associated with this
1660 // pixel buffer will not be freed until the waitAsyncTexImage2DCHROMIUM
1661 // command has been processed on the service side. It is also safe to
1662 // reuse any query id associated with this resource before they complete
1663 // as each new query has a unique submit count.
1664 if (resource->pending_set_pixels) {
1665 DCHECK(resource->set_pixels_completion_forced);
1666 resource->pending_set_pixels = false;
1667 resource->locked_for_write = false;
1670 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1671 if (!resource->gl_pixel_buffer_id)
1672 return;
1673 GLES2Interface* gl = ContextGL();
1674 DCHECK(gl);
1675 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1676 resource->gl_pixel_buffer_id);
1677 gl->BufferData(
1678 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW);
1679 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1682 uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id, int* stride) {
1683 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1684 "ResourceProvider::MapPixelBuffer");
1686 Resource* resource = GetResource(id);
1687 DCHECK(resource->origin == Resource::INTERNAL);
1688 DCHECK_EQ(resource->exported_count, 0);
1689 DCHECK(!resource->image_id);
1691 *stride = 0;
1692 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1693 GLES2Interface* gl = ContextGL();
1694 DCHECK(gl);
1695 DCHECK(resource->gl_pixel_buffer_id);
1696 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1697 resource->gl_pixel_buffer_id);
1698 uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
1699 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
1700 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1701 // Buffer is required to be 4-byte aligned.
1702 CHECK(!(reinterpret_cast<intptr_t>(image) & 3));
1703 return image;
1706 void ResourceProvider::UnmapPixelBuffer(ResourceId id) {
1707 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1708 "ResourceProvider::UnmapPixelBuffer");
1710 Resource* resource = GetResource(id);
1711 DCHECK(resource->origin == Resource::INTERNAL);
1712 DCHECK_EQ(resource->exported_count, 0);
1713 DCHECK(!resource->image_id);
1715 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1716 GLES2Interface* gl = ContextGL();
1717 DCHECK(gl);
1718 DCHECK(resource->gl_pixel_buffer_id);
1719 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1720 resource->gl_pixel_buffer_id);
1721 gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
1722 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1725 GLenum ResourceProvider::BindForSampling(ResourceId resource_id,
1726 GLenum unit,
1727 GLenum filter) {
1728 DCHECK(thread_checker_.CalledOnValidThread());
1729 GLES2Interface* gl = ContextGL();
1730 ResourceMap::iterator it = resources_.find(resource_id);
1731 DCHECK(it != resources_.end());
1732 Resource* resource = &it->second;
1733 DCHECK(resource->lock_for_read_count);
1734 DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced);
1736 ScopedSetActiveTexture scoped_active_tex(gl, unit);
1737 GLenum target = resource->target;
1738 gl->BindTexture(target, resource->gl_id);
1739 if (filter != resource->filter) {
1740 gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
1741 gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
1742 resource->filter = filter;
1745 if (resource->image_id && resource->dirty_image)
1746 BindImageForSampling(resource);
1748 return target;
1751 void ResourceProvider::BeginSetPixels(ResourceId id) {
1752 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1753 "ResourceProvider::BeginSetPixels");
1755 Resource* resource = GetResource(id);
1756 DCHECK(!resource->pending_set_pixels);
1758 LazyCreate(resource);
1759 DCHECK(resource->origin == Resource::INTERNAL);
1760 DCHECK(resource->gl_id || resource->allocated);
1761 DCHECK(ReadLockFenceHasPassed(resource));
1762 DCHECK(!resource->image_id);
1764 bool allocate = !resource->allocated;
1765 resource->allocated = true;
1766 LockForWrite(id);
1768 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1769 DCHECK(resource->gl_id);
1770 GLES2Interface* gl = ContextGL();
1771 DCHECK(gl);
1772 DCHECK(resource->gl_pixel_buffer_id);
1773 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
1774 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1775 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1776 resource->gl_pixel_buffer_id);
1777 if (!resource->gl_upload_query_id)
1778 gl->GenQueriesEXT(1, &resource->gl_upload_query_id);
1779 gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM,
1780 resource->gl_upload_query_id);
1781 if (allocate) {
1782 gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D,
1783 0, /* level */
1784 GLInternalFormat(resource->format),
1785 resource->size.width(),
1786 resource->size.height(),
1787 0, /* border */
1788 GLDataFormat(resource->format),
1789 GLDataType(resource->format),
1790 NULL);
1791 } else {
1792 gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D,
1793 0, /* level */
1794 0, /* x */
1795 0, /* y */
1796 resource->size.width(),
1797 resource->size.height(),
1798 GLDataFormat(resource->format),
1799 GLDataType(resource->format),
1800 NULL);
1802 gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM);
1803 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1805 resource->pending_set_pixels = true;
1806 resource->set_pixels_completion_forced = false;
1809 void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) {
1810 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1811 "ResourceProvider::ForceSetPixelsToComplete");
1813 Resource* resource = GetResource(id);
1815 DCHECK(resource->locked_for_write);
1816 DCHECK(resource->pending_set_pixels);
1817 DCHECK(!resource->set_pixels_completion_forced);
1819 if (resource->gl_id) {
1820 GLES2Interface* gl = ContextGL();
1821 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1822 gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D);
1823 gl->BindTexture(GL_TEXTURE_2D, 0);
1826 resource->set_pixels_completion_forced = true;
1829 bool ResourceProvider::DidSetPixelsComplete(ResourceId id) {
1830 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1831 "ResourceProvider::DidSetPixelsComplete");
1833 Resource* resource = GetResource(id);
1835 DCHECK(resource->locked_for_write);
1836 DCHECK(resource->pending_set_pixels);
1838 if (resource->gl_id) {
1839 GLES2Interface* gl = ContextGL();
1840 DCHECK(gl);
1841 DCHECK(resource->gl_upload_query_id);
1842 GLuint complete = 1;
1843 gl->GetQueryObjectuivEXT(
1844 resource->gl_upload_query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete);
1845 if (!complete)
1846 return false;
1849 resource->pending_set_pixels = false;
1850 UnlockForWrite(resource);
1852 // Async set pixels commands are not necessarily processed in-sequence with
1853 // drawing commands. Read lock fences are required to ensure that async
1854 // commands don't access the resource while used for drawing.
1855 resource->read_lock_fences_enabled = true;
1857 return true;
1860 void ResourceProvider::CreateForTesting(ResourceId id) {
1861 LazyCreate(GetResource(id));
1864 GLenum ResourceProvider::TargetForTesting(ResourceId id) {
1865 Resource* resource = GetResource(id);
1866 return resource->target;
1869 void ResourceProvider::LazyCreate(Resource* resource) {
1870 if (resource->type != RESOURCE_TYPE_GL_TEXTURE ||
1871 resource->origin != Resource::INTERNAL)
1872 return;
1874 if (resource->gl_id)
1875 return;
1877 DCHECK(resource->texture_pool);
1878 DCHECK(resource->origin == Resource::INTERNAL);
1879 DCHECK(!resource->mailbox.IsValid());
1880 resource->gl_id = texture_id_allocator_->NextId();
1882 GLES2Interface* gl = ContextGL();
1883 DCHECK(gl);
1885 // Create and set texture properties. Allocation is delayed until needed.
1886 gl->BindTexture(resource->target, resource->gl_id);
1887 gl->TexParameteri(resource->target, GL_TEXTURE_MIN_FILTER,
1888 resource->original_filter);
1889 gl->TexParameteri(resource->target, GL_TEXTURE_MAG_FILTER,
1890 resource->original_filter);
1891 gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode);
1892 gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode);
1893 gl->TexParameteri(resource->target, GL_TEXTURE_POOL_CHROMIUM,
1894 resource->texture_pool);
1895 if (use_texture_usage_hint_ && (resource->hint & TEXTURE_HINT_FRAMEBUFFER)) {
1896 gl->TexParameteri(resource->target, GL_TEXTURE_USAGE_ANGLE,
1897 GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1901 void ResourceProvider::AllocateForTesting(ResourceId id) {
1902 LazyAllocate(GetResource(id));
1905 void ResourceProvider::LazyAllocate(Resource* resource) {
1906 DCHECK(resource);
1907 if (resource->allocated)
1908 return;
1909 LazyCreate(resource);
1910 if (!resource->gl_id)
1911 return;
1912 resource->allocated = true;
1913 GLES2Interface* gl = ContextGL();
1914 gfx::Size& size = resource->size;
1915 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
1916 ResourceFormat format = resource->format;
1917 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1918 if (use_texture_storage_ext_ &&
1919 IsFormatSupportedForStorage(format, use_texture_format_bgra_) &&
1920 (resource->hint & TEXTURE_HINT_IMMUTABLE)) {
1921 GLenum storage_format = TextureToStorageFormat(format);
1922 gl->TexStorage2DEXT(GL_TEXTURE_2D, 1, storage_format, size.width(),
1923 size.height());
1924 } else {
1925 // ETC1 does not support preallocation.
1926 if (format != ETC1) {
1927 gl->TexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(format), size.width(),
1928 size.height(), 0, GLDataFormat(format), GLDataType(format),
1929 NULL);
1934 void ResourceProvider::BindImageForSampling(Resource* resource) {
1935 GLES2Interface* gl = ContextGL();
1936 DCHECK(resource->gl_id);
1937 DCHECK(resource->image_id);
1939 // Release image currently bound to texture.
1940 if (resource->bound_image_id)
1941 gl->ReleaseTexImage2DCHROMIUM(resource->target, resource->bound_image_id);
1942 gl->BindTexImage2DCHROMIUM(resource->target, resource->image_id);
1943 resource->bound_image_id = resource->image_id;
1944 resource->dirty_image = false;
1947 void ResourceProvider::CopyResource(ResourceId source_id, ResourceId dest_id) {
1948 TRACE_EVENT0("cc", "ResourceProvider::CopyResource");
1950 Resource* source_resource = GetResource(source_id);
1951 DCHECK(!source_resource->lock_for_read_count);
1952 DCHECK(source_resource->origin == Resource::INTERNAL);
1953 DCHECK_EQ(source_resource->exported_count, 0);
1954 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, source_resource->type);
1955 DCHECK(source_resource->allocated);
1956 LazyCreate(source_resource);
1958 Resource* dest_resource = GetResource(dest_id);
1959 DCHECK(!dest_resource->locked_for_write);
1960 DCHECK(!dest_resource->lock_for_read_count);
1961 DCHECK(dest_resource->origin == Resource::INTERNAL);
1962 DCHECK_EQ(dest_resource->exported_count, 0);
1963 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, dest_resource->type);
1964 LazyAllocate(dest_resource);
1966 DCHECK_EQ(source_resource->type, dest_resource->type);
1967 DCHECK_EQ(source_resource->format, dest_resource->format);
1968 DCHECK(source_resource->size == dest_resource->size);
1970 GLES2Interface* gl = ContextGL();
1971 DCHECK(gl);
1972 if (source_resource->image_id && source_resource->dirty_image) {
1973 gl->BindTexture(source_resource->target, source_resource->gl_id);
1974 BindImageForSampling(source_resource);
1976 if (use_sync_query_) {
1977 if (!source_resource->gl_read_lock_query_id)
1978 gl->GenQueriesEXT(1, &source_resource->gl_read_lock_query_id);
1979 #if defined(OS_CHROMEOS)
1980 // TODO(reveman): This avoids a performance problem on some ChromeOS
1981 // devices. This needs to be removed to support native GpuMemoryBuffer
1982 // implementations. crbug.com/436314
1983 gl->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM,
1984 source_resource->gl_read_lock_query_id);
1985 #else
1986 gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM,
1987 source_resource->gl_read_lock_query_id);
1988 #endif
1990 DCHECK(!dest_resource->image_id);
1991 dest_resource->allocated = true;
1992 gl->CopySubTextureCHROMIUM(dest_resource->target, source_resource->gl_id,
1993 dest_resource->gl_id, 0, 0);
1994 if (source_resource->gl_read_lock_query_id) {
1995 // End query and create a read lock fence that will prevent access to
1996 // source resource until CopySubTextureCHROMIUM command has completed.
1997 #if defined(OS_CHROMEOS)
1998 gl->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
1999 #else
2000 gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
2001 #endif
2002 source_resource->read_lock_fence = make_scoped_refptr(
2003 new CopyTextureFence(gl, source_resource->gl_read_lock_query_id));
2004 } else {
2005 // Create a SynchronousFence when CHROMIUM_sync_query extension is missing.
2006 // Try to use one synchronous fence for as many CopyResource operations as
2007 // possible as that reduce the number of times we have to synchronize with
2008 // the GL.
2009 if (!synchronous_fence_.get() || synchronous_fence_->has_synchronized())
2010 synchronous_fence_ = make_scoped_refptr(new SynchronousFence(gl));
2011 source_resource->read_lock_fence = synchronous_fence_;
2012 source_resource->read_lock_fence->Set();
2016 void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) {
2017 Resource* resource = GetResource(id);
2018 DCHECK_EQ(resource->exported_count, 0);
2019 DCHECK(resource->allocated);
2020 if (resource->type != RESOURCE_TYPE_GL_TEXTURE || resource->gl_id)
2021 return;
2022 if (!resource->mailbox.sync_point())
2023 return;
2024 DCHECK(resource->mailbox.IsValid());
2025 GLES2Interface* gl = ContextGL();
2026 DCHECK(gl);
2027 gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point());
2028 resource->mailbox.set_sync_point(0);
2031 void ResourceProvider::WaitReadLockIfNeeded(ResourceId id) {
2032 Resource* resource = GetResource(id);
2033 DCHECK_EQ(resource->exported_count, 0);
2034 if (!resource->read_lock_fence.get())
2035 return;
2037 resource->read_lock_fence->Wait();
2040 GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) {
2041 GLint active_unit = 0;
2042 gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
2043 return active_unit;
2046 void ResourceProvider::ValidateResource(ResourceId id) const {
2047 DCHECK(thread_checker_.CalledOnValidThread());
2048 DCHECK(id);
2049 DCHECK(resources_.find(id) != resources_.end());
2052 GLES2Interface* ResourceProvider::ContextGL() const {
2053 ContextProvider* context_provider = output_surface_->context_provider();
2054 return context_provider ? context_provider->ContextGL() : NULL;
2057 class GrContext* ResourceProvider::GrContext(bool worker_context) const {
2058 ContextProvider* context_provider =
2059 worker_context ? output_surface_->worker_context_provider()
2060 : output_surface_->context_provider();
2061 return context_provider ? context_provider->GrContext() : NULL;
2064 } // namespace cc