Web MIDI API: disallow to add custom exceptions on content settings UI
[chromium-blink-merge.git] / cc / resources / resource_provider.cc
blob25f6597c9e4ec576e1931dc1ea832af1c4e31b50
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/output/gl_renderer.h" // For the GLC() macro.
18 #include "cc/resources/platform_color.h"
19 #include "cc/resources/returned_resource.h"
20 #include "cc/resources/shared_bitmap_manager.h"
21 #include "cc/resources/texture_uploader.h"
22 #include "cc/resources/transferable_resource.h"
23 #include "gpu/GLES2/gl2extchromium.h"
24 #include "gpu/command_buffer/client/gles2_interface.h"
25 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
26 #include "third_party/khronos/GLES2/gl2.h"
27 #include "third_party/khronos/GLES2/gl2ext.h"
28 #include "third_party/skia/include/core/SkSurface.h"
29 #include "third_party/skia/include/gpu/GrContext.h"
30 #include "ui/gfx/frame_time.h"
31 #include "ui/gfx/geometry/rect.h"
32 #include "ui/gfx/geometry/vector2d.h"
33 #include "ui/gfx/gpu_memory_buffer.h"
35 using gpu::gles2::GLES2Interface;
37 namespace cc {
39 class IdAllocator {
40 public:
41 virtual ~IdAllocator() {}
43 virtual GLuint NextId() = 0;
45 protected:
46 IdAllocator(GLES2Interface* gl, size_t id_allocation_chunk_size)
47 : gl_(gl),
48 id_allocation_chunk_size_(id_allocation_chunk_size),
49 ids_(new GLuint[id_allocation_chunk_size]),
50 next_id_index_(id_allocation_chunk_size) {
51 DCHECK(id_allocation_chunk_size_);
54 GLES2Interface* gl_;
55 const size_t id_allocation_chunk_size_;
56 scoped_ptr<GLuint[]> ids_;
57 size_t next_id_index_;
60 namespace {
62 // Measured in seconds.
63 const double kSoftwareUploadTickRate = 0.000250;
64 const double kTextureUploadTickRate = 0.004;
66 GLenum TextureToStorageFormat(ResourceFormat format) {
67 GLenum storage_format = GL_RGBA8_OES;
68 switch (format) {
69 case RGBA_8888:
70 break;
71 case BGRA_8888:
72 storage_format = GL_BGRA8_EXT;
73 break;
74 case RGBA_4444:
75 case ALPHA_8:
76 case LUMINANCE_8:
77 case RGB_565:
78 case ETC1:
79 case RED_8:
80 NOTREACHED();
81 break;
84 return storage_format;
87 bool IsFormatSupportedForStorage(ResourceFormat format, bool use_bgra) {
88 switch (format) {
89 case RGBA_8888:
90 return true;
91 case BGRA_8888:
92 return use_bgra;
93 case RGBA_4444:
94 case ALPHA_8:
95 case LUMINANCE_8:
96 case RGB_565:
97 case ETC1:
98 case RED_8:
99 return false;
101 return false;
104 GrPixelConfig ToGrPixelConfig(ResourceFormat format) {
105 switch (format) {
106 case RGBA_8888:
107 return kRGBA_8888_GrPixelConfig;
108 case BGRA_8888:
109 return kBGRA_8888_GrPixelConfig;
110 case RGBA_4444:
111 return kRGBA_4444_GrPixelConfig;
112 default:
113 break;
115 DCHECK(false) << "Unsupported resource format.";
116 return kSkia8888_GrPixelConfig;
119 gfx::GpuMemoryBuffer::Format ToGpuMemoryBufferFormat(ResourceFormat format) {
120 switch (format) {
121 case RGBA_8888:
122 return gfx::GpuMemoryBuffer::Format::RGBA_8888;
123 case BGRA_8888:
124 return gfx::GpuMemoryBuffer::Format::BGRA_8888;
125 case RGBA_4444:
126 case ALPHA_8:
127 case LUMINANCE_8:
128 case RGB_565:
129 case ETC1:
130 case RED_8:
131 break;
133 NOTREACHED();
134 return gfx::GpuMemoryBuffer::Format::RGBA_8888;
137 class ScopedSetActiveTexture {
138 public:
139 ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit)
140 : gl_(gl), unit_(unit) {
141 DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_));
143 if (unit_ != GL_TEXTURE0)
144 GLC(gl_, gl_->ActiveTexture(unit_));
147 ~ScopedSetActiveTexture() {
148 // Active unit being GL_TEXTURE0 is effectively the ground state.
149 if (unit_ != GL_TEXTURE0)
150 GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0));
153 private:
154 GLES2Interface* gl_;
155 GLenum unit_;
158 class TextureIdAllocator : public IdAllocator {
159 public:
160 TextureIdAllocator(GLES2Interface* gl,
161 size_t texture_id_allocation_chunk_size)
162 : IdAllocator(gl, texture_id_allocation_chunk_size) {}
163 ~TextureIdAllocator() override {
164 gl_->DeleteTextures(id_allocation_chunk_size_ - next_id_index_,
165 ids_.get() + next_id_index_);
168 // Overridden from IdAllocator:
169 GLuint NextId() override {
170 if (next_id_index_ == id_allocation_chunk_size_) {
171 gl_->GenTextures(id_allocation_chunk_size_, ids_.get());
172 next_id_index_ = 0;
175 return ids_[next_id_index_++];
178 private:
179 DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator);
182 class BufferIdAllocator : public IdAllocator {
183 public:
184 BufferIdAllocator(GLES2Interface* gl, size_t buffer_id_allocation_chunk_size)
185 : IdAllocator(gl, buffer_id_allocation_chunk_size) {}
186 ~BufferIdAllocator() override {
187 gl_->DeleteBuffers(id_allocation_chunk_size_ - next_id_index_,
188 ids_.get() + next_id_index_);
191 // Overridden from IdAllocator:
192 GLuint NextId() override {
193 if (next_id_index_ == id_allocation_chunk_size_) {
194 gl_->GenBuffers(id_allocation_chunk_size_, ids_.get());
195 next_id_index_ = 0;
198 return ids_[next_id_index_++];
201 private:
202 DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator);
205 // Query object based fence implementation used to detect completion of copy
206 // texture operations. Fence has passed when query result is available.
207 class CopyTextureFence : public ResourceProvider::Fence {
208 public:
209 CopyTextureFence(gpu::gles2::GLES2Interface* gl, unsigned query_id)
210 : gl_(gl), query_id_(query_id) {}
212 // Overridden from ResourceProvider::Fence:
213 void Set() override {}
214 bool HasPassed() override {
215 unsigned available = 1;
216 gl_->GetQueryObjectuivEXT(
217 query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
218 if (!available)
219 return false;
221 ProcessResult();
222 return true;
224 void Wait() override {
225 // ProcessResult() will wait for result to become available.
226 ProcessResult();
229 private:
230 ~CopyTextureFence() override {}
232 void ProcessResult() {
233 unsigned time_elapsed_us = 0;
234 gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &time_elapsed_us);
235 UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.CopyTextureLatency", time_elapsed_us,
236 0, 256000, 50);
239 gpu::gles2::GLES2Interface* gl_;
240 unsigned query_id_;
242 DISALLOW_COPY_AND_ASSIGN(CopyTextureFence);
245 } // namespace
247 ResourceProvider::Resource::Resource()
248 : child_id(0),
249 gl_id(0),
250 gl_pixel_buffer_id(0),
251 gl_upload_query_id(0),
252 gl_read_lock_query_id(0),
253 pixels(NULL),
254 lock_for_read_count(0),
255 imported_count(0),
256 exported_count(0),
257 dirty_image(false),
258 locked_for_write(false),
259 lost(false),
260 marked_for_deletion(false),
261 pending_set_pixels(false),
262 set_pixels_completion_forced(false),
263 allocated(false),
264 read_lock_fences_enabled(false),
265 has_shared_bitmap_id(false),
266 allow_overlay(false),
267 read_lock_fence(NULL),
268 size(),
269 origin(INTERNAL),
270 target(0),
271 original_filter(0),
272 filter(0),
273 image_id(0),
274 bound_image_id(0),
275 texture_pool(0),
276 wrap_mode(0),
277 hint(TEXTURE_HINT_IMMUTABLE),
278 type(RESOURCE_TYPE_INVALID),
279 format(RGBA_8888),
280 shared_bitmap(NULL),
281 gpu_memory_buffer(NULL) {
284 ResourceProvider::Resource::~Resource() {}
286 ResourceProvider::Resource::Resource(GLuint texture_id,
287 const gfx::Size& size,
288 Origin origin,
289 GLenum target,
290 GLenum filter,
291 GLenum texture_pool,
292 GLint wrap_mode,
293 TextureHint hint,
294 ResourceFormat format)
295 : child_id(0),
296 gl_id(texture_id),
297 gl_pixel_buffer_id(0),
298 gl_upload_query_id(0),
299 gl_read_lock_query_id(0),
300 pixels(NULL),
301 lock_for_read_count(0),
302 imported_count(0),
303 exported_count(0),
304 dirty_image(false),
305 locked_for_write(false),
306 lost(false),
307 marked_for_deletion(false),
308 pending_set_pixels(false),
309 set_pixels_completion_forced(false),
310 allocated(false),
311 read_lock_fences_enabled(false),
312 has_shared_bitmap_id(false),
313 allow_overlay(false),
314 read_lock_fence(NULL),
315 size(size),
316 origin(origin),
317 target(target),
318 original_filter(filter),
319 filter(filter),
320 image_id(0),
321 bound_image_id(0),
322 texture_pool(texture_pool),
323 wrap_mode(wrap_mode),
324 hint(hint),
325 type(RESOURCE_TYPE_GL_TEXTURE),
326 format(format),
327 shared_bitmap(NULL),
328 gpu_memory_buffer(NULL) {
329 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
330 DCHECK_EQ(origin == INTERNAL, !!texture_pool);
333 ResourceProvider::Resource::Resource(uint8_t* pixels,
334 SharedBitmap* bitmap,
335 const gfx::Size& size,
336 Origin origin,
337 GLenum filter,
338 GLint wrap_mode)
339 : child_id(0),
340 gl_id(0),
341 gl_pixel_buffer_id(0),
342 gl_upload_query_id(0),
343 gl_read_lock_query_id(0),
344 pixels(pixels),
345 lock_for_read_count(0),
346 imported_count(0),
347 exported_count(0),
348 dirty_image(false),
349 locked_for_write(false),
350 lost(false),
351 marked_for_deletion(false),
352 pending_set_pixels(false),
353 set_pixels_completion_forced(false),
354 allocated(false),
355 read_lock_fences_enabled(false),
356 has_shared_bitmap_id(!!bitmap),
357 allow_overlay(false),
358 read_lock_fence(NULL),
359 size(size),
360 origin(origin),
361 target(0),
362 original_filter(filter),
363 filter(filter),
364 image_id(0),
365 bound_image_id(0),
366 texture_pool(0),
367 wrap_mode(wrap_mode),
368 hint(TEXTURE_HINT_IMMUTABLE),
369 type(RESOURCE_TYPE_BITMAP),
370 format(RGBA_8888),
371 shared_bitmap(bitmap),
372 gpu_memory_buffer(NULL) {
373 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
374 DCHECK(origin == DELEGATED || pixels);
375 if (bitmap)
376 shared_bitmap_id = bitmap->id();
379 ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id,
380 const gfx::Size& size,
381 Origin origin,
382 GLenum filter,
383 GLint wrap_mode)
384 : child_id(0),
385 gl_id(0),
386 gl_pixel_buffer_id(0),
387 gl_upload_query_id(0),
388 gl_read_lock_query_id(0),
389 pixels(NULL),
390 lock_for_read_count(0),
391 imported_count(0),
392 exported_count(0),
393 dirty_image(false),
394 locked_for_write(false),
395 lost(false),
396 marked_for_deletion(false),
397 pending_set_pixels(false),
398 set_pixels_completion_forced(false),
399 allocated(false),
400 read_lock_fences_enabled(false),
401 has_shared_bitmap_id(true),
402 allow_overlay(false),
403 read_lock_fence(NULL),
404 size(size),
405 origin(origin),
406 target(0),
407 original_filter(filter),
408 filter(filter),
409 image_id(0),
410 bound_image_id(0),
411 texture_pool(0),
412 wrap_mode(wrap_mode),
413 hint(TEXTURE_HINT_IMMUTABLE),
414 type(RESOURCE_TYPE_BITMAP),
415 format(RGBA_8888),
416 shared_bitmap_id(bitmap_id),
417 shared_bitmap(NULL),
418 gpu_memory_buffer(NULL) {
419 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
422 ResourceProvider::Child::Child() : marked_for_deletion(false) {}
424 ResourceProvider::Child::~Child() {}
426 scoped_ptr<ResourceProvider> ResourceProvider::Create(
427 OutputSurface* output_surface,
428 SharedBitmapManager* shared_bitmap_manager,
429 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
430 BlockingTaskRunner* blocking_main_thread_task_runner,
431 int highp_threshold_min,
432 bool use_rgba_4444_texture_format,
433 size_t id_allocation_chunk_size) {
434 scoped_ptr<ResourceProvider> resource_provider(
435 new ResourceProvider(output_surface,
436 shared_bitmap_manager,
437 gpu_memory_buffer_manager,
438 blocking_main_thread_task_runner,
439 highp_threshold_min,
440 use_rgba_4444_texture_format,
441 id_allocation_chunk_size));
443 if (resource_provider->ContextGL())
444 resource_provider->InitializeGL();
445 else
446 resource_provider->InitializeSoftware();
448 DCHECK_NE(RESOURCE_TYPE_INVALID, resource_provider->default_resource_type());
449 return resource_provider.Pass();
452 ResourceProvider::~ResourceProvider() {
453 while (!children_.empty())
454 DestroyChildInternal(children_.begin(), FOR_SHUTDOWN);
455 while (!resources_.empty())
456 DeleteResourceInternal(resources_.begin(), FOR_SHUTDOWN);
458 CleanUpGLIfNeeded();
461 bool ResourceProvider::InUseByConsumer(ResourceId id) {
462 Resource* resource = GetResource(id);
463 return resource->lock_for_read_count > 0 || resource->exported_count > 0 ||
464 resource->lost;
467 bool ResourceProvider::IsLost(ResourceId id) {
468 Resource* resource = GetResource(id);
469 return resource->lost;
472 bool ResourceProvider::AllowOverlay(ResourceId id) {
473 Resource* resource = GetResource(id);
474 return resource->allow_overlay;
477 ResourceProvider::ResourceId ResourceProvider::CreateResource(
478 const gfx::Size& size,
479 GLint wrap_mode,
480 TextureHint hint,
481 ResourceFormat format) {
482 DCHECK(!size.IsEmpty());
483 switch (default_resource_type_) {
484 case RESOURCE_TYPE_GL_TEXTURE:
485 return CreateGLTexture(size,
486 GL_TEXTURE_2D,
487 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
488 wrap_mode,
489 hint,
490 format);
491 case RESOURCE_TYPE_BITMAP:
492 DCHECK_EQ(RGBA_8888, format);
493 return CreateBitmap(size, wrap_mode);
494 case RESOURCE_TYPE_INVALID:
495 break;
498 LOG(FATAL) << "Invalid default resource type.";
499 return 0;
502 ResourceProvider::ResourceId ResourceProvider::CreateManagedResource(
503 const gfx::Size& size,
504 GLenum target,
505 GLint wrap_mode,
506 TextureHint hint,
507 ResourceFormat format) {
508 DCHECK(!size.IsEmpty());
509 switch (default_resource_type_) {
510 case RESOURCE_TYPE_GL_TEXTURE:
511 return CreateGLTexture(size,
512 target,
513 GL_TEXTURE_POOL_MANAGED_CHROMIUM,
514 wrap_mode,
515 hint,
516 format);
517 case RESOURCE_TYPE_BITMAP:
518 DCHECK_EQ(RGBA_8888, format);
519 return CreateBitmap(size, wrap_mode);
520 case RESOURCE_TYPE_INVALID:
521 break;
524 LOG(FATAL) << "Invalid default resource type.";
525 return 0;
528 ResourceProvider::ResourceId ResourceProvider::CreateGLTexture(
529 const gfx::Size& size,
530 GLenum target,
531 GLenum texture_pool,
532 GLint wrap_mode,
533 TextureHint hint,
534 ResourceFormat format) {
535 DCHECK_LE(size.width(), max_texture_size_);
536 DCHECK_LE(size.height(), max_texture_size_);
537 DCHECK(thread_checker_.CalledOnValidThread());
539 ResourceId id = next_id_++;
540 Resource resource(0, size, Resource::INTERNAL, target, GL_LINEAR,
541 texture_pool, wrap_mode, hint, format);
542 resource.allocated = false;
543 resources_[id] = resource;
544 return id;
547 ResourceProvider::ResourceId ResourceProvider::CreateBitmap(
548 const gfx::Size& size, GLint wrap_mode) {
549 DCHECK(thread_checker_.CalledOnValidThread());
551 scoped_ptr<SharedBitmap> bitmap =
552 shared_bitmap_manager_->AllocateSharedBitmap(size);
553 uint8_t* pixels = bitmap->pixels();
554 DCHECK(pixels);
556 ResourceId id = next_id_++;
557 Resource resource(pixels, bitmap.release(), size, Resource::INTERNAL,
558 GL_LINEAR, wrap_mode);
559 resource.allocated = true;
560 resources_[id] = resource;
561 return id;
564 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromIOSurface(
565 const gfx::Size& size,
566 unsigned io_surface_id) {
567 DCHECK(thread_checker_.CalledOnValidThread());
569 ResourceId id = next_id_++;
570 Resource resource(0, gfx::Size(), Resource::INTERNAL,
571 GL_TEXTURE_RECTANGLE_ARB, GL_LINEAR,
572 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, GL_CLAMP_TO_EDGE,
573 TEXTURE_HINT_IMMUTABLE, RGBA_8888);
574 LazyCreate(&resource);
575 GLES2Interface* gl = ContextGL();
576 DCHECK(gl);
577 gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource.gl_id);
578 gl->TexImageIOSurface2DCHROMIUM(
579 GL_TEXTURE_RECTANGLE_ARB, size.width(), size.height(), io_surface_id, 0);
580 resource.allocated = true;
581 resources_[id] = resource;
582 return id;
585 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
586 const TextureMailbox& mailbox,
587 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl) {
588 DCHECK(thread_checker_.CalledOnValidThread());
589 // Just store the information. Mailbox will be consumed in LockForRead().
590 ResourceId id = next_id_++;
591 DCHECK(mailbox.IsValid());
592 Resource& resource = resources_[id];
593 if (mailbox.IsTexture()) {
594 resource = Resource(0, gfx::Size(), Resource::EXTERNAL, mailbox.target(),
595 mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR, 0,
596 GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888);
597 } else {
598 DCHECK(mailbox.IsSharedMemory());
599 SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
600 uint8_t* pixels = shared_bitmap->pixels();
601 DCHECK(pixels);
602 resource = Resource(pixels, shared_bitmap, mailbox.shared_memory_size(),
603 Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE);
605 resource.allocated = true;
606 resource.mailbox = mailbox;
607 resource.release_callback_impl =
608 base::Bind(&SingleReleaseCallbackImpl::Run,
609 base::Owned(release_callback_impl.release()));
610 resource.allow_overlay = mailbox.allow_overlay();
611 return id;
614 void ResourceProvider::DeleteResource(ResourceId id) {
615 DCHECK(thread_checker_.CalledOnValidThread());
616 ResourceMap::iterator it = resources_.find(id);
617 CHECK(it != resources_.end());
618 Resource* resource = &it->second;
619 DCHECK(!resource->marked_for_deletion);
620 DCHECK_EQ(resource->imported_count, 0);
621 DCHECK(resource->pending_set_pixels || !resource->locked_for_write);
623 if (resource->exported_count > 0 || resource->lock_for_read_count > 0) {
624 resource->marked_for_deletion = true;
625 return;
626 } else {
627 DeleteResourceInternal(it, NORMAL);
631 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
632 DeleteStyle style) {
633 TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal");
634 Resource* resource = &it->second;
635 bool lost_resource = resource->lost;
637 DCHECK(resource->exported_count == 0 || style != NORMAL);
638 if (style == FOR_SHUTDOWN && resource->exported_count > 0)
639 lost_resource = true;
641 if (resource->image_id) {
642 DCHECK(resource->origin == Resource::INTERNAL);
643 GLES2Interface* gl = ContextGL();
644 DCHECK(gl);
645 GLC(gl, gl->DestroyImageCHROMIUM(resource->image_id));
647 if (resource->gl_upload_query_id) {
648 DCHECK(resource->origin == Resource::INTERNAL);
649 GLES2Interface* gl = ContextGL();
650 DCHECK(gl);
651 GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id));
653 if (resource->gl_read_lock_query_id) {
654 DCHECK(resource->origin == Resource::INTERNAL);
655 GLES2Interface* gl = ContextGL();
656 DCHECK(gl);
657 GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id));
659 if (resource->gl_pixel_buffer_id) {
660 DCHECK(resource->origin == Resource::INTERNAL);
661 GLES2Interface* gl = ContextGL();
662 DCHECK(gl);
663 GLC(gl, gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id));
665 if (resource->origin == Resource::EXTERNAL) {
666 DCHECK(resource->mailbox.IsValid());
667 GLuint sync_point = resource->mailbox.sync_point();
668 if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
669 DCHECK(resource->mailbox.IsTexture());
670 lost_resource |= lost_output_surface_;
671 GLES2Interface* gl = ContextGL();
672 DCHECK(gl);
673 if (resource->gl_id) {
674 GLC(gl, gl->DeleteTextures(1, &resource->gl_id));
675 resource->gl_id = 0;
676 if (!lost_resource)
677 sync_point = gl->InsertSyncPointCHROMIUM();
679 } else {
680 DCHECK(resource->mailbox.IsSharedMemory());
681 resource->shared_bitmap = nullptr;
682 resource->pixels = nullptr;
684 resource->release_callback_impl.Run(
685 sync_point, lost_resource, blocking_main_thread_task_runner_);
687 if (resource->gl_id) {
688 GLES2Interface* gl = ContextGL();
689 DCHECK(gl);
690 GLC(gl, gl->DeleteTextures(1, &resource->gl_id));
691 resource->gl_id = 0;
693 if (resource->shared_bitmap) {
694 DCHECK(resource->origin != Resource::EXTERNAL);
695 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
696 delete resource->shared_bitmap;
697 resource->pixels = NULL;
699 if (resource->pixels) {
700 DCHECK(resource->origin == Resource::INTERNAL);
701 delete[] resource->pixels;
702 resource->pixels = NULL;
704 if (resource->gpu_memory_buffer) {
705 DCHECK(resource->origin == Resource::INTERNAL);
706 delete resource->gpu_memory_buffer;
707 resource->gpu_memory_buffer = NULL;
709 resources_.erase(it);
712 ResourceProvider::ResourceType ResourceProvider::GetResourceType(
713 ResourceId id) {
714 return GetResource(id)->type;
717 void ResourceProvider::SetPixels(ResourceId id,
718 const uint8_t* image,
719 const gfx::Rect& image_rect,
720 const gfx::Rect& source_rect,
721 const gfx::Vector2d& dest_offset) {
722 Resource* resource = GetResource(id);
723 DCHECK(!resource->locked_for_write);
724 DCHECK(!resource->lock_for_read_count);
725 DCHECK(resource->origin == Resource::INTERNAL);
726 DCHECK_EQ(resource->exported_count, 0);
727 DCHECK(ReadLockFenceHasPassed(resource));
728 LazyAllocate(resource);
730 if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
731 DCHECK(resource->gl_id);
732 DCHECK(!resource->pending_set_pixels);
733 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
734 GLES2Interface* gl = ContextGL();
735 DCHECK(gl);
736 DCHECK(texture_uploader_.get());
737 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
738 texture_uploader_->Upload(image,
739 image_rect,
740 source_rect,
741 dest_offset,
742 resource->format,
743 resource->size);
744 } else {
745 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
746 DCHECK(resource->allocated);
747 DCHECK_EQ(RGBA_8888, resource->format);
748 DCHECK(source_rect.x() >= image_rect.x());
749 DCHECK(source_rect.y() >= image_rect.y());
750 DCHECK(source_rect.right() <= image_rect.right());
751 DCHECK(source_rect.bottom() <= image_rect.bottom());
752 SkImageInfo source_info =
753 SkImageInfo::MakeN32Premul(source_rect.width(), source_rect.height());
754 size_t image_row_bytes = image_rect.width() * 4;
755 gfx::Vector2d source_offset = source_rect.origin() - image_rect.origin();
756 image += source_offset.y() * image_row_bytes + source_offset.x() * 4;
758 ScopedWriteLockSoftware lock(this, id);
759 SkCanvas dest(lock.sk_bitmap());
760 dest.writePixels(source_info, image, image_row_bytes, dest_offset.x(),
761 dest_offset.y());
765 void ResourceProvider::CopyToResource(ResourceId id,
766 const uint8_t* image,
767 const gfx::Size& image_size) {
768 Resource* resource = GetResource(id);
769 DCHECK(!resource->locked_for_write);
770 DCHECK(!resource->lock_for_read_count);
771 DCHECK(resource->origin == Resource::INTERNAL);
772 DCHECK_EQ(resource->exported_count, 0);
773 DCHECK(ReadLockFenceHasPassed(resource));
774 LazyAllocate(resource);
776 DCHECK_EQ(image_size.width(), resource->size.width());
777 DCHECK_EQ(image_size.height(), resource->size.height());
779 if (resource->type == RESOURCE_TYPE_BITMAP) {
780 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
781 DCHECK(resource->allocated);
782 DCHECK_EQ(RGBA_8888, resource->format);
783 SkImageInfo source_info =
784 SkImageInfo::MakeN32Premul(image_size.width(), image_size.height());
785 size_t image_stride = image_size.width() * 4;
787 ScopedWriteLockSoftware lock(this, id);
788 SkCanvas dest(lock.sk_bitmap());
789 dest.writePixels(source_info, image, image_stride, 0, 0);
790 } else {
791 DCHECK(resource->gl_id);
792 DCHECK(!resource->pending_set_pixels);
793 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
794 GLES2Interface* gl = ContextGL();
795 DCHECK(gl);
796 DCHECK(texture_uploader_.get());
797 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
799 if (resource->format == ETC1) {
800 size_t num_bytes = static_cast<size_t>(image_size.width()) *
801 image_size.height() * BitsPerPixel(ETC1) / 8;
802 gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1),
803 image_size.width(), image_size.height(), 0,
804 num_bytes, image);
805 } else {
806 gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(),
807 image_size.height(), GLDataFormat(resource->format),
808 GLDataType(resource->format), image);
813 size_t ResourceProvider::NumBlockingUploads() {
814 if (!texture_uploader_)
815 return 0;
817 return texture_uploader_->NumBlockingUploads();
820 void ResourceProvider::MarkPendingUploadsAsNonBlocking() {
821 if (!texture_uploader_)
822 return;
824 texture_uploader_->MarkPendingUploadsAsNonBlocking();
827 size_t ResourceProvider::EstimatedUploadsPerTick() {
828 if (!texture_uploader_)
829 return 1u;
831 double textures_per_second = texture_uploader_->EstimatedTexturesPerSecond();
832 size_t textures_per_tick = floor(
833 kTextureUploadTickRate * textures_per_second);
834 return textures_per_tick ? textures_per_tick : 1u;
837 void ResourceProvider::FlushUploads() {
838 if (!texture_uploader_)
839 return;
841 texture_uploader_->Flush();
844 void ResourceProvider::ReleaseCachedData() {
845 if (!texture_uploader_)
846 return;
848 texture_uploader_->ReleaseCachedQueries();
851 base::TimeTicks ResourceProvider::EstimatedUploadCompletionTime(
852 size_t uploads_per_tick) {
853 if (lost_output_surface_)
854 return base::TimeTicks();
856 // Software resource uploads happen on impl thread, so don't bother batching
857 // them up and trying to wait for them to complete.
858 if (!texture_uploader_) {
859 return gfx::FrameTime::Now() + base::TimeDelta::FromMicroseconds(
860 base::Time::kMicrosecondsPerSecond * kSoftwareUploadTickRate);
863 base::TimeDelta upload_one_texture_time =
864 base::TimeDelta::FromMicroseconds(
865 base::Time::kMicrosecondsPerSecond * kTextureUploadTickRate) /
866 uploads_per_tick;
868 size_t total_uploads = NumBlockingUploads() + uploads_per_tick;
869 return gfx::FrameTime::Now() + upload_one_texture_time * total_uploads;
872 ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) {
873 DCHECK(thread_checker_.CalledOnValidThread());
874 ResourceMap::iterator it = resources_.find(id);
875 CHECK(it != resources_.end());
876 return &it->second;
879 const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
880 Resource* resource = GetResource(id);
881 DCHECK(!resource->locked_for_write ||
882 resource->set_pixels_completion_forced) <<
883 "locked for write: " << resource->locked_for_write <<
884 " pixels completion forced: " << resource->set_pixels_completion_forced;
885 DCHECK_EQ(resource->exported_count, 0);
886 // Uninitialized! Call SetPixels or LockForWrite first.
887 DCHECK(resource->allocated);
889 LazyCreate(resource);
891 if (resource->type == RESOURCE_TYPE_GL_TEXTURE && !resource->gl_id) {
892 DCHECK(resource->origin != Resource::INTERNAL);
893 DCHECK(resource->mailbox.IsTexture());
895 // Mailbox sync_points must be processed by a call to
896 // WaitSyncPointIfNeeded() prior to calling LockForRead().
897 DCHECK(!resource->mailbox.sync_point());
899 GLES2Interface* gl = ContextGL();
900 DCHECK(gl);
901 resource->gl_id =
902 GLC(gl, gl->CreateAndConsumeTextureCHROMIUM(resource->mailbox.target(),
903 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 =
1088 gl->CreateImageCHROMIUM(gpu_memory_buffer_->AsClientBuffer(),
1089 size_.width(),
1090 size_.height(),
1091 GL_RGBA);
1094 std::swap(resource_->gpu_memory_buffer, gpu_memory_buffer_);
1095 resource_->allocated = true;
1096 resource_->dirty_image = true;
1098 // GpuMemoryBuffer provides direct access to the memory used by the GPU.
1099 // Read lock fences are required to ensure that we're not trying to map a
1100 // buffer that is currently in-use by the GPU.
1101 resource_->read_lock_fences_enabled = true;
1104 gfx::GpuMemoryBuffer*
1105 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::GetGpuMemoryBuffer() {
1106 if (!gpu_memory_buffer_) {
1107 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
1108 gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer(
1109 size_, ToGpuMemoryBufferFormat(format_), gfx::GpuMemoryBuffer::MAP);
1110 gpu_memory_buffer_ = gpu_memory_buffer.release();
1113 return gpu_memory_buffer_;
1116 ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr(
1117 ResourceProvider* resource_provider,
1118 ResourceProvider::ResourceId resource_id)
1119 : resource_provider_(resource_provider),
1120 resource_(resource_provider->LockForWrite(resource_id)) {
1121 DCHECK(thread_checker_.CalledOnValidThread());
1122 resource_provider_->LazyAllocate(resource_);
1125 ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
1126 DCHECK(thread_checker_.CalledOnValidThread());
1127 DCHECK(resource_->locked_for_write);
1128 resource_provider_->UnlockForWrite(resource_);
1131 void ResourceProvider::ScopedWriteLockGr::InitSkSurface(
1132 bool use_worker_context,
1133 bool use_distance_field_text,
1134 bool can_use_lcd_text,
1135 int msaa_sample_count) {
1136 DCHECK(resource_->locked_for_write);
1138 GrBackendTextureDesc desc;
1139 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
1140 desc.fWidth = resource_->size.width();
1141 desc.fHeight = resource_->size.height();
1142 desc.fConfig = ToGrPixelConfig(resource_->format);
1143 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1144 desc.fTextureHandle = resource_->gl_id;
1145 desc.fSampleCnt = msaa_sample_count;
1147 class GrContext* gr_context =
1148 resource_provider_->GrContext(use_worker_context);
1149 skia::RefPtr<GrTexture> gr_texture =
1150 skia::AdoptRef(gr_context->wrapBackendTexture(desc));
1151 if (gr_texture) {
1152 uint32_t flags = use_distance_field_text
1153 ? SkSurfaceProps::kUseDistanceFieldFonts_Flag
1154 : 0;
1155 // Use unknown pixel geometry to disable LCD text.
1156 SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
1157 if (can_use_lcd_text) {
1158 // LegacyFontHost will get LCD text and skia figures out what type to use.
1159 surface_props =
1160 SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
1162 sk_surface_ = skia::AdoptRef(SkSurface::NewRenderTargetDirect(
1163 gr_texture->asRenderTarget(), &surface_props));
1164 return;
1166 sk_surface_.clear();
1169 void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() {
1170 sk_surface_.clear();
1173 ResourceProvider::SynchronousFence::SynchronousFence(
1174 gpu::gles2::GLES2Interface* gl)
1175 : gl_(gl), has_synchronized_(true) {
1178 ResourceProvider::SynchronousFence::~SynchronousFence() {
1181 void ResourceProvider::SynchronousFence::Set() {
1182 has_synchronized_ = false;
1185 bool ResourceProvider::SynchronousFence::HasPassed() {
1186 if (!has_synchronized_) {
1187 has_synchronized_ = true;
1188 Synchronize();
1190 return true;
1193 void ResourceProvider::SynchronousFence::Wait() {
1194 HasPassed();
1197 void ResourceProvider::SynchronousFence::Synchronize() {
1198 TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize");
1199 gl_->Finish();
1202 ResourceProvider::ResourceProvider(
1203 OutputSurface* output_surface,
1204 SharedBitmapManager* shared_bitmap_manager,
1205 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
1206 BlockingTaskRunner* blocking_main_thread_task_runner,
1207 int highp_threshold_min,
1208 bool use_rgba_4444_texture_format,
1209 size_t id_allocation_chunk_size)
1210 : output_surface_(output_surface),
1211 shared_bitmap_manager_(shared_bitmap_manager),
1212 gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
1213 blocking_main_thread_task_runner_(blocking_main_thread_task_runner),
1214 lost_output_surface_(false),
1215 highp_threshold_min_(highp_threshold_min),
1216 next_id_(1),
1217 next_child_(1),
1218 default_resource_type_(RESOURCE_TYPE_INVALID),
1219 use_texture_storage_ext_(false),
1220 use_texture_format_bgra_(false),
1221 use_texture_usage_hint_(false),
1222 use_compressed_texture_etc1_(false),
1223 yuv_resource_format_(LUMINANCE_8),
1224 max_texture_size_(0),
1225 best_texture_format_(RGBA_8888),
1226 use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
1227 id_allocation_chunk_size_(id_allocation_chunk_size),
1228 use_sync_query_(false) {
1229 DCHECK(output_surface_->HasClient());
1230 DCHECK(id_allocation_chunk_size_);
1233 void ResourceProvider::InitializeSoftware() {
1234 DCHECK(thread_checker_.CalledOnValidThread());
1235 DCHECK_NE(RESOURCE_TYPE_BITMAP, default_resource_type_);
1237 CleanUpGLIfNeeded();
1239 default_resource_type_ = RESOURCE_TYPE_BITMAP;
1240 // Pick an arbitrary limit here similar to what hardware might.
1241 max_texture_size_ = 16 * 1024;
1242 best_texture_format_ = RGBA_8888;
1245 void ResourceProvider::InitializeGL() {
1246 DCHECK(thread_checker_.CalledOnValidThread());
1247 DCHECK(!texture_uploader_);
1248 DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, default_resource_type_);
1249 DCHECK(!texture_id_allocator_);
1250 DCHECK(!buffer_id_allocator_);
1252 default_resource_type_ = RESOURCE_TYPE_GL_TEXTURE;
1254 const ContextProvider::Capabilities& caps =
1255 output_surface_->context_provider()->ContextCapabilities();
1257 bool use_bgra = caps.gpu.texture_format_bgra8888;
1258 use_texture_storage_ext_ = caps.gpu.texture_storage;
1259 use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888;
1260 use_texture_usage_hint_ = caps.gpu.texture_usage;
1261 use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1;
1262 yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8;
1263 use_sync_query_ = caps.gpu.sync_query;
1265 GLES2Interface* gl = ContextGL();
1266 DCHECK(gl);
1268 texture_uploader_ = TextureUploader::Create(gl);
1269 max_texture_size_ = 0; // Context expects cleared value.
1270 GLC(gl, gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_));
1271 best_texture_format_ = PlatformColor::BestTextureFormat(use_bgra);
1273 texture_id_allocator_.reset(
1274 new TextureIdAllocator(gl, id_allocation_chunk_size_));
1275 buffer_id_allocator_.reset(
1276 new BufferIdAllocator(gl, id_allocation_chunk_size_));
1279 void ResourceProvider::CleanUpGLIfNeeded() {
1280 GLES2Interface* gl = ContextGL();
1281 if (default_resource_type_ != RESOURCE_TYPE_GL_TEXTURE) {
1282 // We are not in GL mode, but double check before returning.
1283 DCHECK(!gl);
1284 DCHECK(!texture_uploader_);
1285 return;
1288 DCHECK(gl);
1289 #if DCHECK_IS_ON()
1290 // Check that all GL resources has been deleted.
1291 for (ResourceMap::const_iterator itr = resources_.begin();
1292 itr != resources_.end();
1293 ++itr) {
1294 DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, itr->second.type);
1296 #endif // DCHECK_IS_ON()
1298 texture_uploader_ = nullptr;
1299 texture_id_allocator_ = nullptr;
1300 buffer_id_allocator_ = nullptr;
1301 gl->Finish();
1304 int ResourceProvider::CreateChild(const ReturnCallback& return_callback) {
1305 DCHECK(thread_checker_.CalledOnValidThread());
1307 Child child_info;
1308 child_info.return_callback = return_callback;
1310 int child = next_child_++;
1311 children_[child] = child_info;
1312 return child;
1315 void ResourceProvider::DestroyChild(int child_id) {
1316 ChildMap::iterator it = children_.find(child_id);
1317 DCHECK(it != children_.end());
1318 DestroyChildInternal(it, NORMAL);
1321 void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
1322 DeleteStyle style) {
1323 DCHECK(thread_checker_.CalledOnValidThread());
1325 Child& child = it->second;
1326 DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion);
1328 ResourceIdArray resources_for_child;
1330 for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin();
1331 child_it != child.child_to_parent_map.end();
1332 ++child_it) {
1333 ResourceId id = child_it->second;
1334 resources_for_child.push_back(id);
1337 // If the child is going away, don't consider any resources in use.
1338 child.in_use_resources.clear();
1339 child.marked_for_deletion = true;
1341 DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child);
1344 const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap(
1345 int child) const {
1346 DCHECK(thread_checker_.CalledOnValidThread());
1347 ChildMap::const_iterator it = children_.find(child);
1348 DCHECK(it != children_.end());
1349 DCHECK(!it->second.marked_for_deletion);
1350 return it->second.child_to_parent_map;
1353 void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
1354 TransferableResourceArray* list) {
1355 DCHECK(thread_checker_.CalledOnValidThread());
1356 GLES2Interface* gl = ContextGL();
1357 bool need_sync_point = false;
1358 for (ResourceIdArray::const_iterator it = resources.begin();
1359 it != resources.end();
1360 ++it) {
1361 TransferableResource resource;
1362 TransferResource(gl, *it, &resource);
1363 if (!resource.mailbox_holder.sync_point && !resource.is_software)
1364 need_sync_point = true;
1365 ++resources_.find(*it)->second.exported_count;
1366 list->push_back(resource);
1368 if (need_sync_point) {
1369 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1370 for (TransferableResourceArray::iterator it = list->begin();
1371 it != list->end();
1372 ++it) {
1373 if (!it->mailbox_holder.sync_point)
1374 it->mailbox_holder.sync_point = sync_point;
1379 void ResourceProvider::ReceiveFromChild(
1380 int child, const TransferableResourceArray& resources) {
1381 DCHECK(thread_checker_.CalledOnValidThread());
1382 GLES2Interface* gl = ContextGL();
1383 Child& child_info = children_.find(child)->second;
1384 DCHECK(!child_info.marked_for_deletion);
1385 for (TransferableResourceArray::const_iterator it = resources.begin();
1386 it != resources.end();
1387 ++it) {
1388 ResourceIdMap::iterator resource_in_map_it =
1389 child_info.child_to_parent_map.find(it->id);
1390 if (resource_in_map_it != child_info.child_to_parent_map.end()) {
1391 Resource& resource = resources_[resource_in_map_it->second];
1392 resource.marked_for_deletion = false;
1393 resource.imported_count++;
1394 continue;
1397 if ((!it->is_software && !gl) ||
1398 (it->is_software && !shared_bitmap_manager_)) {
1399 TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
1400 ReturnedResourceArray to_return;
1401 to_return.push_back(it->ToReturnedResource());
1402 child_info.return_callback.Run(to_return,
1403 blocking_main_thread_task_runner_);
1404 continue;
1407 ResourceId local_id = next_id_++;
1408 Resource& resource = resources_[local_id];
1409 if (it->is_software) {
1410 resource =
1411 Resource(it->mailbox_holder.mailbox, it->size, Resource::DELEGATED,
1412 GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE);
1413 } else {
1414 resource = Resource(0, it->size, Resource::DELEGATED,
1415 it->mailbox_holder.texture_target, it->filter, 0,
1416 it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE,
1417 TEXTURE_HINT_IMMUTABLE, it->format);
1418 resource.mailbox = TextureMailbox(it->mailbox_holder.mailbox,
1419 it->mailbox_holder.texture_target,
1420 it->mailbox_holder.sync_point);
1422 resource.child_id = child;
1423 // Don't allocate a texture for a child.
1424 resource.allocated = true;
1425 resource.imported_count = 1;
1426 resource.allow_overlay = it->allow_overlay;
1427 child_info.parent_to_child_map[local_id] = it->id;
1428 child_info.child_to_parent_map[it->id] = local_id;
1432 void ResourceProvider::DeclareUsedResourcesFromChild(
1433 int child,
1434 const ResourceIdArray& resources_from_child) {
1435 DCHECK(thread_checker_.CalledOnValidThread());
1437 ChildMap::iterator child_it = children_.find(child);
1438 DCHECK(child_it != children_.end());
1439 Child& child_info = child_it->second;
1440 DCHECK(!child_info.marked_for_deletion);
1441 child_info.in_use_resources.clear();
1443 for (size_t i = 0; i < resources_from_child.size(); ++i) {
1444 ResourceIdMap::iterator it =
1445 child_info.child_to_parent_map.find(resources_from_child[i]);
1446 DCHECK(it != child_info.child_to_parent_map.end());
1448 ResourceId local_id = it->second;
1449 DCHECK(!resources_[local_id].marked_for_deletion);
1450 child_info.in_use_resources.insert(local_id);
1453 ResourceIdArray unused;
1454 for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin();
1455 it != child_info.child_to_parent_map.end();
1456 ++it) {
1457 ResourceId local_id = it->second;
1458 bool resource_is_in_use = child_info.in_use_resources.count(local_id) > 0;
1459 if (!resource_is_in_use)
1460 unused.push_back(local_id);
1462 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
1465 // static
1466 bool ResourceProvider::CompareResourceMapIteratorsByChildId(
1467 const std::pair<ReturnedResource, ResourceMap::iterator>& a,
1468 const std::pair<ReturnedResource, ResourceMap::iterator>& b) {
1469 const ResourceMap::iterator& a_it = a.second;
1470 const ResourceMap::iterator& b_it = b.second;
1471 const Resource& a_resource = a_it->second;
1472 const Resource& b_resource = b_it->second;
1473 return a_resource.child_id < b_resource.child_id;
1476 void ResourceProvider::ReceiveReturnsFromParent(
1477 const ReturnedResourceArray& resources) {
1478 DCHECK(thread_checker_.CalledOnValidThread());
1479 GLES2Interface* gl = ContextGL();
1481 int child_id = 0;
1482 ResourceIdArray resources_for_child;
1484 std::vector<std::pair<ReturnedResource, ResourceMap::iterator>>
1485 sorted_resources;
1487 for (ReturnedResourceArray::const_iterator it = resources.begin();
1488 it != resources.end();
1489 ++it) {
1490 ResourceId local_id = it->id;
1491 ResourceMap::iterator map_iterator = resources_.find(local_id);
1493 // Resource was already lost (e.g. it belonged to a child that was
1494 // destroyed).
1495 if (map_iterator == resources_.end())
1496 continue;
1498 sorted_resources.push_back(
1499 std::pair<ReturnedResource, ResourceMap::iterator>(*it, map_iterator));
1502 std::sort(sorted_resources.begin(),
1503 sorted_resources.end(),
1504 CompareResourceMapIteratorsByChildId);
1506 ChildMap::iterator child_it = children_.end();
1507 for (size_t i = 0; i < sorted_resources.size(); ++i) {
1508 ReturnedResource& returned = sorted_resources[i].first;
1509 ResourceMap::iterator& map_iterator = sorted_resources[i].second;
1510 ResourceId local_id = map_iterator->first;
1511 Resource* resource = &map_iterator->second;
1513 CHECK_GE(resource->exported_count, returned.count);
1514 resource->exported_count -= returned.count;
1515 resource->lost |= returned.lost;
1516 if (resource->exported_count)
1517 continue;
1519 // Need to wait for the current read lock fence to pass before we can
1520 // recycle this resource.
1521 if (resource->read_lock_fences_enabled) {
1522 if (current_read_lock_fence_.get())
1523 current_read_lock_fence_->Set();
1524 resource->read_lock_fence = current_read_lock_fence_;
1527 if (returned.sync_point) {
1528 DCHECK(!resource->has_shared_bitmap_id);
1529 if (resource->origin == Resource::INTERNAL) {
1530 DCHECK(resource->gl_id);
1531 GLC(gl, gl->WaitSyncPointCHROMIUM(returned.sync_point));
1532 } else {
1533 DCHECK(!resource->gl_id);
1534 resource->mailbox.set_sync_point(returned.sync_point);
1538 if (!resource->marked_for_deletion)
1539 continue;
1541 if (!resource->child_id) {
1542 // The resource belongs to this ResourceProvider, so it can be destroyed.
1543 DeleteResourceInternal(map_iterator, NORMAL);
1544 continue;
1547 DCHECK(resource->origin == Resource::DELEGATED);
1548 // Delete the resource and return it to the child it came from one.
1549 if (resource->child_id != child_id) {
1550 if (child_id) {
1551 DCHECK_NE(resources_for_child.size(), 0u);
1552 DCHECK(child_it != children_.end());
1553 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL,
1554 resources_for_child);
1555 resources_for_child.clear();
1558 child_it = children_.find(resource->child_id);
1559 DCHECK(child_it != children_.end());
1560 child_id = resource->child_id;
1562 resources_for_child.push_back(local_id);
1565 if (child_id) {
1566 DCHECK_NE(resources_for_child.size(), 0u);
1567 DCHECK(child_it != children_.end());
1568 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL,
1569 resources_for_child);
1573 void ResourceProvider::TransferResource(GLES2Interface* gl,
1574 ResourceId id,
1575 TransferableResource* resource) {
1576 Resource* source = GetResource(id);
1577 DCHECK(!source->locked_for_write);
1578 DCHECK(!source->lock_for_read_count);
1579 DCHECK(source->origin != Resource::EXTERNAL || source->mailbox.IsValid());
1580 DCHECK(source->allocated);
1581 resource->id = id;
1582 resource->format = source->format;
1583 resource->mailbox_holder.texture_target = source->target;
1584 resource->filter = source->filter;
1585 resource->size = source->size;
1586 resource->is_repeated = (source->wrap_mode == GL_REPEAT);
1587 resource->allow_overlay = source->allow_overlay;
1589 if (source->type == RESOURCE_TYPE_BITMAP) {
1590 resource->mailbox_holder.mailbox = source->shared_bitmap_id;
1591 resource->is_software = true;
1592 } else if (!source->mailbox.IsValid()) {
1593 LazyCreate(source);
1594 DCHECK(source->gl_id);
1595 DCHECK(source->origin == Resource::INTERNAL);
1596 if (source->image_id) {
1597 DCHECK(source->dirty_image);
1598 BindImageForSampling(source);
1600 // This is a resource allocated by the compositor, we need to produce it.
1601 // Don't set a sync point, the caller will do it.
1602 GLC(gl, gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name));
1603 GLC(gl, gl->ProduceTextureDirectCHROMIUM(
1604 source->gl_id, resource->mailbox_holder.texture_target,
1605 resource->mailbox_holder.mailbox.name));
1607 source->mailbox = TextureMailbox(resource->mailbox_holder);
1608 } else {
1609 DCHECK(source->mailbox.IsTexture());
1610 if (source->image_id && source->dirty_image) {
1611 DCHECK(source->gl_id);
1612 DCHECK(source->origin == Resource::INTERNAL);
1613 GLC(gl,
1614 gl->BindTexture(resource->mailbox_holder.texture_target,
1615 source->gl_id));
1616 BindImageForSampling(source);
1618 // This is either an external resource, or a compositor resource that we
1619 // already exported. Make sure to forward the sync point that we were given.
1620 resource->mailbox_holder.mailbox = source->mailbox.mailbox();
1621 resource->mailbox_holder.texture_target = source->mailbox.target();
1622 resource->mailbox_holder.sync_point = source->mailbox.sync_point();
1623 source->mailbox.set_sync_point(0);
1627 void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
1628 ChildMap::iterator child_it,
1629 DeleteStyle style,
1630 const ResourceIdArray& unused) {
1631 DCHECK(thread_checker_.CalledOnValidThread());
1632 DCHECK(child_it != children_.end());
1633 Child* child_info = &child_it->second;
1635 if (unused.empty() && !child_info->marked_for_deletion)
1636 return;
1638 ReturnedResourceArray to_return;
1640 GLES2Interface* gl = ContextGL();
1641 bool need_sync_point = false;
1642 for (size_t i = 0; i < unused.size(); ++i) {
1643 ResourceId local_id = unused[i];
1645 ResourceMap::iterator it = resources_.find(local_id);
1646 CHECK(it != resources_.end());
1647 Resource& resource = it->second;
1649 DCHECK(!resource.locked_for_write);
1650 DCHECK_EQ(0u, child_info->in_use_resources.count(local_id));
1651 DCHECK(child_info->parent_to_child_map.count(local_id));
1653 ResourceId child_id = child_info->parent_to_child_map[local_id];
1654 DCHECK(child_info->child_to_parent_map.count(child_id));
1656 bool is_lost =
1657 resource.lost ||
1658 (resource.type == RESOURCE_TYPE_GL_TEXTURE && lost_output_surface_);
1659 if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
1660 if (style != FOR_SHUTDOWN) {
1661 // Defer this until we receive the resource back from the parent or
1662 // the read lock is released.
1663 resource.marked_for_deletion = true;
1664 continue;
1667 // We still have an exported_count, so we'll have to lose it.
1668 is_lost = true;
1671 if (gl && resource.filter != resource.original_filter) {
1672 DCHECK(resource.target);
1673 DCHECK(resource.gl_id);
1675 GLC(gl, gl->BindTexture(resource.target, resource.gl_id));
1676 GLC(gl,
1677 gl->TexParameteri(resource.target,
1678 GL_TEXTURE_MIN_FILTER,
1679 resource.original_filter));
1680 GLC(gl,
1681 gl->TexParameteri(resource.target,
1682 GL_TEXTURE_MAG_FILTER,
1683 resource.original_filter));
1686 ReturnedResource returned;
1687 returned.id = child_id;
1688 returned.sync_point = resource.mailbox.sync_point();
1689 if (!returned.sync_point && resource.type == RESOURCE_TYPE_GL_TEXTURE)
1690 need_sync_point = true;
1691 returned.count = resource.imported_count;
1692 returned.lost = is_lost;
1693 to_return.push_back(returned);
1695 child_info->parent_to_child_map.erase(local_id);
1696 child_info->child_to_parent_map.erase(child_id);
1697 resource.imported_count = 0;
1698 DeleteResourceInternal(it, style);
1700 if (need_sync_point) {
1701 DCHECK(gl);
1702 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1703 for (size_t i = 0; i < to_return.size(); ++i) {
1704 if (!to_return[i].sync_point)
1705 to_return[i].sync_point = sync_point;
1709 if (!to_return.empty())
1710 child_info->return_callback.Run(to_return,
1711 blocking_main_thread_task_runner_);
1713 if (child_info->marked_for_deletion &&
1714 child_info->parent_to_child_map.empty()) {
1715 DCHECK(child_info->child_to_parent_map.empty());
1716 children_.erase(child_it);
1720 void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
1721 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1722 "ResourceProvider::AcquirePixelBuffer");
1724 Resource* resource = GetResource(id);
1725 DCHECK(resource->origin == Resource::INTERNAL);
1726 DCHECK_EQ(resource->exported_count, 0);
1727 DCHECK(!resource->image_id);
1728 DCHECK_NE(ETC1, resource->format);
1730 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1731 GLES2Interface* gl = ContextGL();
1732 DCHECK(gl);
1733 if (!resource->gl_pixel_buffer_id)
1734 resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId();
1735 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1736 resource->gl_pixel_buffer_id);
1737 unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8;
1738 gl->BufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1739 resource->size.height() *
1740 RoundUp(bytes_per_pixel * resource->size.width(), 4u),
1741 NULL,
1742 GL_DYNAMIC_DRAW);
1743 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1746 void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
1747 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1748 "ResourceProvider::ReleasePixelBuffer");
1750 Resource* resource = GetResource(id);
1751 DCHECK(resource->origin == Resource::INTERNAL);
1752 DCHECK_EQ(resource->exported_count, 0);
1753 DCHECK(!resource->image_id);
1755 // The pixel buffer can be released while there is a pending "set pixels"
1756 // if completion has been forced. Any shared memory associated with this
1757 // pixel buffer will not be freed until the waitAsyncTexImage2DCHROMIUM
1758 // command has been processed on the service side. It is also safe to
1759 // reuse any query id associated with this resource before they complete
1760 // as each new query has a unique submit count.
1761 if (resource->pending_set_pixels) {
1762 DCHECK(resource->set_pixels_completion_forced);
1763 resource->pending_set_pixels = false;
1764 resource->locked_for_write = false;
1767 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1768 if (!resource->gl_pixel_buffer_id)
1769 return;
1770 GLES2Interface* gl = ContextGL();
1771 DCHECK(gl);
1772 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1773 resource->gl_pixel_buffer_id);
1774 gl->BufferData(
1775 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW);
1776 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1779 uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id, int* stride) {
1780 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1781 "ResourceProvider::MapPixelBuffer");
1783 Resource* resource = GetResource(id);
1784 DCHECK(resource->origin == Resource::INTERNAL);
1785 DCHECK_EQ(resource->exported_count, 0);
1786 DCHECK(!resource->image_id);
1788 *stride = 0;
1789 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1790 GLES2Interface* gl = ContextGL();
1791 DCHECK(gl);
1792 DCHECK(resource->gl_pixel_buffer_id);
1793 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1794 resource->gl_pixel_buffer_id);
1795 uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
1796 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
1797 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1798 // Buffer is required to be 4-byte aligned.
1799 CHECK(!(reinterpret_cast<intptr_t>(image) & 3));
1800 return image;
1803 void ResourceProvider::UnmapPixelBuffer(ResourceId id) {
1804 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1805 "ResourceProvider::UnmapPixelBuffer");
1807 Resource* resource = GetResource(id);
1808 DCHECK(resource->origin == Resource::INTERNAL);
1809 DCHECK_EQ(resource->exported_count, 0);
1810 DCHECK(!resource->image_id);
1812 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1813 GLES2Interface* gl = ContextGL();
1814 DCHECK(gl);
1815 DCHECK(resource->gl_pixel_buffer_id);
1816 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1817 resource->gl_pixel_buffer_id);
1818 gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
1819 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1822 GLenum ResourceProvider::BindForSampling(ResourceId resource_id,
1823 GLenum unit,
1824 GLenum filter) {
1825 DCHECK(thread_checker_.CalledOnValidThread());
1826 GLES2Interface* gl = ContextGL();
1827 ResourceMap::iterator it = resources_.find(resource_id);
1828 DCHECK(it != resources_.end());
1829 Resource* resource = &it->second;
1830 DCHECK(resource->lock_for_read_count);
1831 DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced);
1833 ScopedSetActiveTexture scoped_active_tex(gl, unit);
1834 GLenum target = resource->target;
1835 GLC(gl, gl->BindTexture(target, resource->gl_id));
1836 if (filter != resource->filter) {
1837 GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter));
1838 GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter));
1839 resource->filter = filter;
1842 if (resource->image_id && resource->dirty_image)
1843 BindImageForSampling(resource);
1845 return target;
1848 void ResourceProvider::BeginSetPixels(ResourceId id) {
1849 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1850 "ResourceProvider::BeginSetPixels");
1852 Resource* resource = GetResource(id);
1853 DCHECK(!resource->pending_set_pixels);
1855 LazyCreate(resource);
1856 DCHECK(resource->origin == Resource::INTERNAL);
1857 DCHECK(resource->gl_id || resource->allocated);
1858 DCHECK(ReadLockFenceHasPassed(resource));
1859 DCHECK(!resource->image_id);
1861 bool allocate = !resource->allocated;
1862 resource->allocated = true;
1863 LockForWrite(id);
1865 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1866 DCHECK(resource->gl_id);
1867 GLES2Interface* gl = ContextGL();
1868 DCHECK(gl);
1869 DCHECK(resource->gl_pixel_buffer_id);
1870 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
1871 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1872 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1873 resource->gl_pixel_buffer_id);
1874 if (!resource->gl_upload_query_id)
1875 gl->GenQueriesEXT(1, &resource->gl_upload_query_id);
1876 gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM,
1877 resource->gl_upload_query_id);
1878 if (allocate) {
1879 gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D,
1880 0, /* level */
1881 GLInternalFormat(resource->format),
1882 resource->size.width(),
1883 resource->size.height(),
1884 0, /* border */
1885 GLDataFormat(resource->format),
1886 GLDataType(resource->format),
1887 NULL);
1888 } else {
1889 gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D,
1890 0, /* level */
1891 0, /* x */
1892 0, /* y */
1893 resource->size.width(),
1894 resource->size.height(),
1895 GLDataFormat(resource->format),
1896 GLDataType(resource->format),
1897 NULL);
1899 gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM);
1900 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1902 resource->pending_set_pixels = true;
1903 resource->set_pixels_completion_forced = false;
1906 void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) {
1907 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1908 "ResourceProvider::ForceSetPixelsToComplete");
1910 Resource* resource = GetResource(id);
1912 DCHECK(resource->locked_for_write);
1913 DCHECK(resource->pending_set_pixels);
1914 DCHECK(!resource->set_pixels_completion_forced);
1916 if (resource->gl_id) {
1917 GLES2Interface* gl = ContextGL();
1918 GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id));
1919 GLC(gl, gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D));
1920 GLC(gl, gl->BindTexture(GL_TEXTURE_2D, 0));
1923 resource->set_pixels_completion_forced = true;
1926 bool ResourceProvider::DidSetPixelsComplete(ResourceId id) {
1927 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1928 "ResourceProvider::DidSetPixelsComplete");
1930 Resource* resource = GetResource(id);
1932 DCHECK(resource->locked_for_write);
1933 DCHECK(resource->pending_set_pixels);
1935 if (resource->gl_id) {
1936 GLES2Interface* gl = ContextGL();
1937 DCHECK(gl);
1938 DCHECK(resource->gl_upload_query_id);
1939 GLuint complete = 1;
1940 gl->GetQueryObjectuivEXT(
1941 resource->gl_upload_query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete);
1942 if (!complete)
1943 return false;
1946 resource->pending_set_pixels = false;
1947 UnlockForWrite(resource);
1949 // Async set pixels commands are not necessarily processed in-sequence with
1950 // drawing commands. Read lock fences are required to ensure that async
1951 // commands don't access the resource while used for drawing.
1952 resource->read_lock_fences_enabled = true;
1954 return true;
1957 void ResourceProvider::CreateForTesting(ResourceId id) {
1958 LazyCreate(GetResource(id));
1961 GLenum ResourceProvider::TargetForTesting(ResourceId id) {
1962 Resource* resource = GetResource(id);
1963 return resource->target;
1966 void ResourceProvider::LazyCreate(Resource* resource) {
1967 if (resource->type != RESOURCE_TYPE_GL_TEXTURE ||
1968 resource->origin != Resource::INTERNAL)
1969 return;
1971 if (resource->gl_id)
1972 return;
1974 DCHECK(resource->texture_pool);
1975 DCHECK(resource->origin == Resource::INTERNAL);
1976 DCHECK(!resource->mailbox.IsValid());
1977 resource->gl_id = texture_id_allocator_->NextId();
1979 GLES2Interface* gl = ContextGL();
1980 DCHECK(gl);
1982 // Create and set texture properties. Allocation is delayed until needed.
1983 GLC(gl, gl->BindTexture(resource->target, resource->gl_id));
1984 GLC(gl,
1985 gl->TexParameteri(
1986 resource->target, GL_TEXTURE_MIN_FILTER, resource->original_filter));
1987 GLC(gl,
1988 gl->TexParameteri(
1989 resource->target, GL_TEXTURE_MAG_FILTER, resource->original_filter));
1990 GLC(gl,
1991 gl->TexParameteri(
1992 resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode));
1993 GLC(gl,
1994 gl->TexParameteri(
1995 resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode));
1996 GLC(gl,
1997 gl->TexParameteri(
1998 resource->target, GL_TEXTURE_POOL_CHROMIUM, resource->texture_pool));
1999 if (use_texture_usage_hint_ && (resource->hint & TEXTURE_HINT_FRAMEBUFFER)) {
2000 GLC(gl,
2001 gl->TexParameteri(resource->target,
2002 GL_TEXTURE_USAGE_ANGLE,
2003 GL_FRAMEBUFFER_ATTACHMENT_ANGLE));
2007 void ResourceProvider::AllocateForTesting(ResourceId id) {
2008 LazyAllocate(GetResource(id));
2011 void ResourceProvider::LazyAllocate(Resource* resource) {
2012 DCHECK(resource);
2013 if (resource->allocated)
2014 return;
2015 LazyCreate(resource);
2016 if (!resource->gl_id)
2017 return;
2018 resource->allocated = true;
2019 GLES2Interface* gl = ContextGL();
2020 gfx::Size& size = resource->size;
2021 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
2022 ResourceFormat format = resource->format;
2023 GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id));
2024 if (use_texture_storage_ext_ &&
2025 IsFormatSupportedForStorage(format, use_texture_format_bgra_) &&
2026 (resource->hint & TEXTURE_HINT_IMMUTABLE)) {
2027 GLenum storage_format = TextureToStorageFormat(format);
2028 GLC(gl,
2029 gl->TexStorage2DEXT(
2030 GL_TEXTURE_2D, 1, storage_format, size.width(), size.height()));
2031 } else {
2032 // ETC1 does not support preallocation.
2033 if (format != ETC1) {
2034 GLC(gl,
2035 gl->TexImage2D(GL_TEXTURE_2D,
2037 GLInternalFormat(format),
2038 size.width(),
2039 size.height(),
2041 GLDataFormat(format),
2042 GLDataType(format),
2043 NULL));
2048 void ResourceProvider::BindImageForSampling(Resource* resource) {
2049 GLES2Interface* gl = ContextGL();
2050 DCHECK(resource->gl_id);
2051 DCHECK(resource->image_id);
2053 // Release image currently bound to texture.
2054 if (resource->bound_image_id)
2055 gl->ReleaseTexImage2DCHROMIUM(resource->target, resource->bound_image_id);
2056 gl->BindTexImage2DCHROMIUM(resource->target, resource->image_id);
2057 resource->bound_image_id = resource->image_id;
2058 resource->dirty_image = false;
2061 void ResourceProvider::CopyResource(ResourceId source_id, ResourceId dest_id) {
2062 TRACE_EVENT0("cc", "ResourceProvider::CopyResource");
2064 Resource* source_resource = GetResource(source_id);
2065 DCHECK(!source_resource->lock_for_read_count);
2066 DCHECK(source_resource->origin == Resource::INTERNAL);
2067 DCHECK_EQ(source_resource->exported_count, 0);
2068 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, source_resource->type);
2069 DCHECK(source_resource->allocated);
2070 LazyCreate(source_resource);
2072 Resource* dest_resource = GetResource(dest_id);
2073 DCHECK(!dest_resource->locked_for_write);
2074 DCHECK(!dest_resource->lock_for_read_count);
2075 DCHECK(dest_resource->origin == Resource::INTERNAL);
2076 DCHECK_EQ(dest_resource->exported_count, 0);
2077 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, dest_resource->type);
2078 LazyAllocate(dest_resource);
2080 DCHECK_EQ(source_resource->type, dest_resource->type);
2081 DCHECK_EQ(source_resource->format, dest_resource->format);
2082 DCHECK(source_resource->size == dest_resource->size);
2084 GLES2Interface* gl = ContextGL();
2085 DCHECK(gl);
2086 if (source_resource->image_id && source_resource->dirty_image) {
2087 gl->BindTexture(source_resource->target, source_resource->gl_id);
2088 BindImageForSampling(source_resource);
2090 if (use_sync_query_) {
2091 if (!source_resource->gl_read_lock_query_id)
2092 gl->GenQueriesEXT(1, &source_resource->gl_read_lock_query_id);
2093 #if defined(OS_CHROMEOS)
2094 // TODO(reveman): This avoids a performance problem on some ChromeOS
2095 // devices. This needs to be removed to support native GpuMemoryBuffer
2096 // implementations. crbug.com/436314
2097 gl->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM,
2098 source_resource->gl_read_lock_query_id);
2099 #else
2100 gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM,
2101 source_resource->gl_read_lock_query_id);
2102 #endif
2104 DCHECK(!dest_resource->image_id);
2105 dest_resource->allocated = true;
2106 gl->CopySubTextureCHROMIUM(dest_resource->target, source_resource->gl_id,
2107 dest_resource->gl_id, 0, 0);
2108 if (source_resource->gl_read_lock_query_id) {
2109 // End query and create a read lock fence that will prevent access to
2110 // source resource until CopySubTextureCHROMIUM command has completed.
2111 #if defined(OS_CHROMEOS)
2112 gl->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
2113 #else
2114 gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
2115 #endif
2116 source_resource->read_lock_fence = make_scoped_refptr(
2117 new CopyTextureFence(gl, source_resource->gl_read_lock_query_id));
2118 } else {
2119 // Create a SynchronousFence when CHROMIUM_sync_query extension is missing.
2120 // Try to use one synchronous fence for as many CopyResource operations as
2121 // possible as that reduce the number of times we have to synchronize with
2122 // the GL.
2123 if (!synchronous_fence_.get() || synchronous_fence_->has_synchronized())
2124 synchronous_fence_ = make_scoped_refptr(new SynchronousFence(gl));
2125 source_resource->read_lock_fence = synchronous_fence_;
2126 source_resource->read_lock_fence->Set();
2130 void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) {
2131 Resource* resource = GetResource(id);
2132 DCHECK_EQ(resource->exported_count, 0);
2133 DCHECK(resource->allocated);
2134 if (resource->type != RESOURCE_TYPE_GL_TEXTURE || resource->gl_id)
2135 return;
2136 if (!resource->mailbox.sync_point())
2137 return;
2138 DCHECK(resource->mailbox.IsValid());
2139 GLES2Interface* gl = ContextGL();
2140 DCHECK(gl);
2141 GLC(gl, gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point()));
2142 resource->mailbox.set_sync_point(0);
2145 void ResourceProvider::WaitReadLockIfNeeded(ResourceId id) {
2146 Resource* resource = GetResource(id);
2147 DCHECK_EQ(resource->exported_count, 0);
2148 if (!resource->read_lock_fence.get())
2149 return;
2151 resource->read_lock_fence->Wait();
2154 GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) {
2155 GLint active_unit = 0;
2156 gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
2157 return active_unit;
2160 GLES2Interface* ResourceProvider::ContextGL() const {
2161 ContextProvider* context_provider = output_surface_->context_provider();
2162 return context_provider ? context_provider->ContextGL() : NULL;
2165 class GrContext* ResourceProvider::GrContext(bool worker_context) const {
2166 ContextProvider* context_provider =
2167 worker_context ? output_surface_->worker_context_provider()
2168 : output_surface_->context_provider();
2169 return context_provider ? context_provider->GrContext() : NULL;
2172 } // namespace cc