blob: b90b59477376960656266cdb0f60b87d0d8173b0 [file] [log] [blame]
James Robinson646469d2014-10-03 15:33:28 -07001// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cc/resources/resource_provider.h"
6
7#include <algorithm>
8#include <limits>
9
10#include "base/containers/hash_tables.h"
Benjamin Lerman57998902014-11-18 16:06:02 +010011#include "base/metrics/histogram.h"
James Robinson646469d2014-10-03 15:33:28 -070012#include "base/stl_util.h"
13#include "base/strings/string_split.h"
14#include "base/strings/string_util.h"
Elliot Glayshereae49292015-01-28 10:47:32 -080015#include "base/trace_event/trace_event.h"
James Robinson646469d2014-10-03 15:33:28 -070016#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"
James Robinson53b77582014-10-28 17:00:48 -070025#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
James Robinson646469d2014-10-03 15:33:28 -070026#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"
James Robinson30d547e2014-10-23 18:20:06 -070031#include "ui/gfx/geometry/rect.h"
32#include "ui/gfx/geometry/vector2d.h"
James Robinsone2ac7e82014-10-15 13:21:59 -070033#include "ui/gfx/gpu_memory_buffer.h"
James Robinson646469d2014-10-03 15:33:28 -070034
35using gpu::gles2::GLES2Interface;
36
37namespace cc {
38
39class IdAllocator {
40 public:
41 virtual ~IdAllocator() {}
42
43 virtual GLuint NextId() = 0;
44
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_);
52 }
53
54 GLES2Interface* gl_;
55 const size_t id_allocation_chunk_size_;
56 scoped_ptr<GLuint[]> ids_;
57 size_t next_id_index_;
58};
59
60namespace {
61
62// Measured in seconds.
63const double kSoftwareUploadTickRate = 0.000250;
64const double kTextureUploadTickRate = 0.004;
65
66GLenum 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:
James Robinson6a64b812014-12-03 13:38:42 -080079 case RED_8:
James Robinson646469d2014-10-03 15:33:28 -070080 NOTREACHED();
81 break;
82 }
83
84 return storage_format;
85}
86
87bool 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:
James Robinson6a64b812014-12-03 13:38:42 -080098 case RED_8:
James Robinson646469d2014-10-03 15:33:28 -070099 return false;
100 }
101 return false;
102}
103
104GrPixelConfig 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;
114 }
115 DCHECK(false) << "Unsupported resource format.";
116 return kSkia8888_GrPixelConfig;
117}
118
James Robinsone2ac7e82014-10-15 13:21:59 -0700119gfx::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:
James Robinson6a64b812014-12-03 13:38:42 -0800130 case RED_8:
James Robinsone2ac7e82014-10-15 13:21:59 -0700131 break;
132 }
133 NOTREACHED();
134 return gfx::GpuMemoryBuffer::Format::RGBA_8888;
135}
136
James Robinson646469d2014-10-03 15:33:28 -0700137class ScopedSetActiveTexture {
138 public:
139 ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit)
140 : gl_(gl), unit_(unit) {
141 DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_));
142
143 if (unit_ != GL_TEXTURE0)
144 GLC(gl_, gl_->ActiveTexture(unit_));
145 }
146
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));
151 }
152
153 private:
154 GLES2Interface* gl_;
155 GLenum unit_;
156};
157
158class 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) {}
James Robinsone1b30cf2014-10-21 12:25:40 -0700163 ~TextureIdAllocator() override {
James Robinson646469d2014-10-03 15:33:28 -0700164 gl_->DeleteTextures(id_allocation_chunk_size_ - next_id_index_,
165 ids_.get() + next_id_index_);
166 }
167
168 // Overridden from IdAllocator:
James Robinsone1b30cf2014-10-21 12:25:40 -0700169 GLuint NextId() override {
James Robinson646469d2014-10-03 15:33:28 -0700170 if (next_id_index_ == id_allocation_chunk_size_) {
171 gl_->GenTextures(id_allocation_chunk_size_, ids_.get());
172 next_id_index_ = 0;
173 }
174
175 return ids_[next_id_index_++];
176 }
177
178 private:
179 DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator);
180};
181
182class BufferIdAllocator : public IdAllocator {
183 public:
184 BufferIdAllocator(GLES2Interface* gl, size_t buffer_id_allocation_chunk_size)
185 : IdAllocator(gl, buffer_id_allocation_chunk_size) {}
James Robinsone1b30cf2014-10-21 12:25:40 -0700186 ~BufferIdAllocator() override {
James Robinson646469d2014-10-03 15:33:28 -0700187 gl_->DeleteBuffers(id_allocation_chunk_size_ - next_id_index_,
188 ids_.get() + next_id_index_);
189 }
190
191 // Overridden from IdAllocator:
James Robinsone1b30cf2014-10-21 12:25:40 -0700192 GLuint NextId() override {
James Robinson646469d2014-10-03 15:33:28 -0700193 if (next_id_index_ == id_allocation_chunk_size_) {
194 gl_->GenBuffers(id_allocation_chunk_size_, ids_.get());
195 next_id_index_ = 0;
196 }
197
198 return ids_[next_id_index_++];
199 }
200
201 private:
202 DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator);
203};
204
Benjamin Lerman57998902014-11-18 16:06:02 +0100205// Query object based fence implementation used to detect completion of copy
206// texture operations. Fence has passed when query result is available.
207class CopyTextureFence : public ResourceProvider::Fence {
James Robinson646469d2014-10-03 15:33:28 -0700208 public:
Benjamin Lerman57998902014-11-18 16:06:02 +0100209 CopyTextureFence(gpu::gles2::GLES2Interface* gl, unsigned query_id)
James Robinson646469d2014-10-03 15:33:28 -0700210 : gl_(gl), query_id_(query_id) {}
211
212 // Overridden from ResourceProvider::Fence:
James Robinsone1b30cf2014-10-21 12:25:40 -0700213 void Set() override {}
214 bool HasPassed() override {
James Robinson646469d2014-10-03 15:33:28 -0700215 unsigned available = 1;
216 gl_->GetQueryObjectuivEXT(
217 query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
Benjamin Lerman57998902014-11-18 16:06:02 +0100218 if (!available)
219 return false;
220
221 ProcessResult();
222 return true;
James Robinson646469d2014-10-03 15:33:28 -0700223 }
James Robinson7f480212014-10-31 10:28:08 -0700224 void Wait() override {
Benjamin Lerman57998902014-11-18 16:06:02 +0100225 // ProcessResult() will wait for result to become available.
226 ProcessResult();
James Robinson7f480212014-10-31 10:28:08 -0700227 }
James Robinson646469d2014-10-03 15:33:28 -0700228
229 private:
Benjamin Lerman57998902014-11-18 16:06:02 +0100230 ~CopyTextureFence() override {}
231
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);
237 }
James Robinson646469d2014-10-03 15:33:28 -0700238
239 gpu::gles2::GLES2Interface* gl_;
240 unsigned query_id_;
241
Benjamin Lerman57998902014-11-18 16:06:02 +0100242 DISALLOW_COPY_AND_ASSIGN(CopyTextureFence);
James Robinson646469d2014-10-03 15:33:28 -0700243};
244
245} // namespace
246
247ResourceProvider::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(TextureHintImmutable),
278 type(InvalidType),
279 format(RGBA_8888),
James Robinsone2ac7e82014-10-15 13:21:59 -0700280 shared_bitmap(NULL),
281 gpu_memory_buffer(NULL) {
James Robinson646469d2014-10-03 15:33:28 -0700282}
283
284ResourceProvider::Resource::~Resource() {}
285
286ResourceProvider::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(GLTexture),
326 format(format),
James Robinsone2ac7e82014-10-15 13:21:59 -0700327 shared_bitmap(NULL),
328 gpu_memory_buffer(NULL) {
James Robinson646469d2014-10-03 15:33:28 -0700329 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
330 DCHECK_EQ(origin == Internal, !!texture_pool);
331}
332
333ResourceProvider::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(TextureHintImmutable),
369 type(Bitmap),
370 format(RGBA_8888),
James Robinsone2ac7e82014-10-15 13:21:59 -0700371 shared_bitmap(bitmap),
372 gpu_memory_buffer(NULL) {
James Robinson646469d2014-10-03 15:33:28 -0700373 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();
377}
378
379ResourceProvider::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(TextureHintImmutable),
414 type(Bitmap),
415 format(RGBA_8888),
416 shared_bitmap_id(bitmap_id),
James Robinsone2ac7e82014-10-15 13:21:59 -0700417 shared_bitmap(NULL),
418 gpu_memory_buffer(NULL) {
James Robinson646469d2014-10-03 15:33:28 -0700419 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
420}
421
422ResourceProvider::Child::Child() : marked_for_deletion(false) {}
423
424ResourceProvider::Child::~Child() {}
425
426scoped_ptr<ResourceProvider> ResourceProvider::Create(
427 OutputSurface* output_surface,
428 SharedBitmapManager* shared_bitmap_manager,
James Robinson53b77582014-10-28 17:00:48 -0700429 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
James Robinson646469d2014-10-03 15:33:28 -0700430 BlockingTaskRunner* blocking_main_thread_task_runner,
431 int highp_threshold_min,
432 bool use_rgba_4444_texture_format,
James Robinson675df572014-10-22 17:20:33 -0700433 size_t id_allocation_chunk_size) {
James Robinson646469d2014-10-03 15:33:28 -0700434 scoped_ptr<ResourceProvider> resource_provider(
435 new ResourceProvider(output_surface,
436 shared_bitmap_manager,
James Robinsone2ac7e82014-10-15 13:21:59 -0700437 gpu_memory_buffer_manager,
James Robinson646469d2014-10-03 15:33:28 -0700438 blocking_main_thread_task_runner,
439 highp_threshold_min,
440 use_rgba_4444_texture_format,
James Robinson675df572014-10-22 17:20:33 -0700441 id_allocation_chunk_size));
James Robinson646469d2014-10-03 15:33:28 -0700442
443 if (resource_provider->ContextGL())
444 resource_provider->InitializeGL();
445 else
446 resource_provider->InitializeSoftware();
447
448 DCHECK_NE(InvalidType, resource_provider->default_resource_type());
449 return resource_provider.Pass();
450}
451
452ResourceProvider::~ResourceProvider() {
453 while (!children_.empty())
454 DestroyChildInternal(children_.begin(), ForShutdown);
455 while (!resources_.empty())
456 DeleteResourceInternal(resources_.begin(), ForShutdown);
457
458 CleanUpGLIfNeeded();
459}
460
461bool ResourceProvider::InUseByConsumer(ResourceId id) {
462 Resource* resource = GetResource(id);
463 return resource->lock_for_read_count > 0 || resource->exported_count > 0 ||
464 resource->lost;
465}
466
467bool ResourceProvider::IsLost(ResourceId id) {
468 Resource* resource = GetResource(id);
469 return resource->lost;
470}
471
472bool ResourceProvider::AllowOverlay(ResourceId id) {
473 Resource* resource = GetResource(id);
474 return resource->allow_overlay;
475}
476
477ResourceProvider::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 GLTexture:
485 return CreateGLTexture(size,
486 GL_TEXTURE_2D,
487 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
488 wrap_mode,
489 hint,
490 format);
491 case Bitmap:
492 DCHECK_EQ(RGBA_8888, format);
493 return CreateBitmap(size, wrap_mode);
494 case InvalidType:
495 break;
496 }
497
498 LOG(FATAL) << "Invalid default resource type.";
499 return 0;
500}
501
502ResourceProvider::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 GLTexture:
511 return CreateGLTexture(size,
512 target,
513 GL_TEXTURE_POOL_MANAGED_CHROMIUM,
514 wrap_mode,
515 hint,
516 format);
517 case Bitmap:
518 DCHECK_EQ(RGBA_8888, format);
519 return CreateBitmap(size, wrap_mode);
520 case InvalidType:
521 break;
522 }
523
524 LOG(FATAL) << "Invalid default resource type.";
525 return 0;
526}
527
528ResourceProvider::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());
538
539 ResourceId id = next_id_++;
540 Resource resource(0,
541 size,
542 Resource::Internal,
543 target,
544 GL_LINEAR,
545 texture_pool,
546 wrap_mode,
547 hint,
548 format);
549 resource.allocated = false;
550 resources_[id] = resource;
551 return id;
552}
553
554ResourceProvider::ResourceId ResourceProvider::CreateBitmap(
555 const gfx::Size& size, GLint wrap_mode) {
556 DCHECK(thread_checker_.CalledOnValidThread());
557
Etienne Membrives175837a2014-12-19 15:45:38 +0100558 scoped_ptr<SharedBitmap> bitmap =
559 shared_bitmap_manager_->AllocateSharedBitmap(size);
560 uint8_t* pixels = bitmap->pixels();
James Robinson646469d2014-10-03 15:33:28 -0700561 DCHECK(pixels);
562
563 ResourceId id = next_id_++;
564 Resource resource(
565 pixels, bitmap.release(), size, Resource::Internal, GL_LINEAR, wrap_mode);
566 resource.allocated = true;
567 resources_[id] = resource;
568 return id;
569}
570
571ResourceProvider::ResourceId ResourceProvider::CreateResourceFromIOSurface(
572 const gfx::Size& size,
573 unsigned io_surface_id) {
574 DCHECK(thread_checker_.CalledOnValidThread());
575
576 ResourceId id = next_id_++;
577 Resource resource(0,
578 gfx::Size(),
579 Resource::Internal,
580 GL_TEXTURE_RECTANGLE_ARB,
581 GL_LINEAR,
582 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
583 GL_CLAMP_TO_EDGE,
584 TextureHintImmutable,
585 RGBA_8888);
586 LazyCreate(&resource);
587 GLES2Interface* gl = ContextGL();
588 DCHECK(gl);
589 gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource.gl_id);
590 gl->TexImageIOSurface2DCHROMIUM(
591 GL_TEXTURE_RECTANGLE_ARB, size.width(), size.height(), io_surface_id, 0);
592 resource.allocated = true;
593 resources_[id] = resource;
594 return id;
595}
596
597ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
598 const TextureMailbox& mailbox,
599 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl) {
600 DCHECK(thread_checker_.CalledOnValidThread());
601 // Just store the information. Mailbox will be consumed in LockForRead().
602 ResourceId id = next_id_++;
603 DCHECK(mailbox.IsValid());
604 Resource& resource = resources_[id];
605 if (mailbox.IsTexture()) {
606 resource = Resource(0,
607 gfx::Size(),
608 Resource::External,
609 mailbox.target(),
James Robinson1027bc12014-12-04 14:51:42 -0800610 mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR,
James Robinson646469d2014-10-03 15:33:28 -0700611 0,
612 GL_CLAMP_TO_EDGE,
613 TextureHintImmutable,
614 RGBA_8888);
615 } else {
616 DCHECK(mailbox.IsSharedMemory());
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100617 SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
618 uint8_t* pixels = shared_bitmap->pixels();
James Robinson646469d2014-10-03 15:33:28 -0700619 DCHECK(pixels);
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100620 resource = Resource(pixels, shared_bitmap, mailbox.shared_memory_size(),
621 Resource::External, GL_LINEAR, GL_CLAMP_TO_EDGE);
James Robinson646469d2014-10-03 15:33:28 -0700622 }
623 resource.allocated = true;
624 resource.mailbox = mailbox;
625 resource.release_callback_impl =
626 base::Bind(&SingleReleaseCallbackImpl::Run,
627 base::Owned(release_callback_impl.release()));
628 resource.allow_overlay = mailbox.allow_overlay();
629 return id;
630}
631
632void ResourceProvider::DeleteResource(ResourceId id) {
633 DCHECK(thread_checker_.CalledOnValidThread());
634 ResourceMap::iterator it = resources_.find(id);
635 CHECK(it != resources_.end());
636 Resource* resource = &it->second;
637 DCHECK(!resource->marked_for_deletion);
638 DCHECK_EQ(resource->imported_count, 0);
639 DCHECK(resource->pending_set_pixels || !resource->locked_for_write);
640
641 if (resource->exported_count > 0 || resource->lock_for_read_count > 0) {
642 resource->marked_for_deletion = true;
643 return;
644 } else {
645 DeleteResourceInternal(it, Normal);
646 }
647}
648
649void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
650 DeleteStyle style) {
651 TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal");
652 Resource* resource = &it->second;
653 bool lost_resource = resource->lost;
654
655 DCHECK(resource->exported_count == 0 || style != Normal);
656 if (style == ForShutdown && resource->exported_count > 0)
657 lost_resource = true;
658
659 if (resource->image_id) {
660 DCHECK(resource->origin == Resource::Internal);
661 GLES2Interface* gl = ContextGL();
662 DCHECK(gl);
663 GLC(gl, gl->DestroyImageCHROMIUM(resource->image_id));
664 }
665 if (resource->gl_upload_query_id) {
666 DCHECK(resource->origin == Resource::Internal);
667 GLES2Interface* gl = ContextGL();
668 DCHECK(gl);
669 GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id));
670 }
671 if (resource->gl_read_lock_query_id) {
672 DCHECK(resource->origin == Resource::Internal);
673 GLES2Interface* gl = ContextGL();
674 DCHECK(gl);
675 GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id));
676 }
677 if (resource->gl_pixel_buffer_id) {
678 DCHECK(resource->origin == Resource::Internal);
679 GLES2Interface* gl = ContextGL();
680 DCHECK(gl);
681 GLC(gl, gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id));
682 }
683 if (resource->origin == Resource::External) {
684 DCHECK(resource->mailbox.IsValid());
685 GLuint sync_point = resource->mailbox.sync_point();
686 if (resource->type == GLTexture) {
687 DCHECK(resource->mailbox.IsTexture());
688 lost_resource |= lost_output_surface_;
689 GLES2Interface* gl = ContextGL();
690 DCHECK(gl);
691 if (resource->gl_id) {
692 GLC(gl, gl->DeleteTextures(1, &resource->gl_id));
693 resource->gl_id = 0;
694 if (!lost_resource)
695 sync_point = gl->InsertSyncPointCHROMIUM();
696 }
697 } else {
698 DCHECK(resource->mailbox.IsSharedMemory());
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100699 resource->shared_bitmap = nullptr;
700 resource->pixels = nullptr;
James Robinson646469d2014-10-03 15:33:28 -0700701 }
702 resource->release_callback_impl.Run(
703 sync_point, lost_resource, blocking_main_thread_task_runner_);
704 }
705 if (resource->gl_id) {
706 GLES2Interface* gl = ContextGL();
707 DCHECK(gl);
708 GLC(gl, gl->DeleteTextures(1, &resource->gl_id));
709 resource->gl_id = 0;
710 }
711 if (resource->shared_bitmap) {
712 DCHECK(resource->origin != Resource::External);
713 DCHECK_EQ(Bitmap, resource->type);
714 delete resource->shared_bitmap;
715 resource->pixels = NULL;
716 }
717 if (resource->pixels) {
718 DCHECK(resource->origin == Resource::Internal);
719 delete[] resource->pixels;
James Robinsone2ac7e82014-10-15 13:21:59 -0700720 resource->pixels = NULL;
721 }
722 if (resource->gpu_memory_buffer) {
James Robinson7f480212014-10-31 10:28:08 -0700723 DCHECK(resource->origin == Resource::Internal);
James Robinsone2ac7e82014-10-15 13:21:59 -0700724 delete resource->gpu_memory_buffer;
725 resource->gpu_memory_buffer = NULL;
James Robinson646469d2014-10-03 15:33:28 -0700726 }
727 resources_.erase(it);
728}
729
730ResourceProvider::ResourceType ResourceProvider::GetResourceType(
731 ResourceId id) {
732 return GetResource(id)->type;
733}
734
735void ResourceProvider::SetPixels(ResourceId id,
736 const uint8_t* image,
737 const gfx::Rect& image_rect,
738 const gfx::Rect& source_rect,
739 const gfx::Vector2d& dest_offset) {
740 Resource* resource = GetResource(id);
741 DCHECK(!resource->locked_for_write);
742 DCHECK(!resource->lock_for_read_count);
743 DCHECK(resource->origin == Resource::Internal);
744 DCHECK_EQ(resource->exported_count, 0);
745 DCHECK(ReadLockFenceHasPassed(resource));
746 LazyAllocate(resource);
747
748 if (resource->type == GLTexture) {
749 DCHECK(resource->gl_id);
750 DCHECK(!resource->pending_set_pixels);
751 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
752 GLES2Interface* gl = ContextGL();
753 DCHECK(gl);
754 DCHECK(texture_uploader_.get());
755 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
756 texture_uploader_->Upload(image,
757 image_rect,
758 source_rect,
759 dest_offset,
760 resource->format,
761 resource->size);
762 } else {
763 DCHECK_EQ(Bitmap, resource->type);
764 DCHECK(resource->allocated);
765 DCHECK_EQ(RGBA_8888, resource->format);
766 DCHECK(source_rect.x() >= image_rect.x());
767 DCHECK(source_rect.y() >= image_rect.y());
768 DCHECK(source_rect.right() <= image_rect.right());
769 DCHECK(source_rect.bottom() <= image_rect.bottom());
770 SkImageInfo source_info =
771 SkImageInfo::MakeN32Premul(source_rect.width(), source_rect.height());
772 size_t image_row_bytes = image_rect.width() * 4;
773 gfx::Vector2d source_offset = source_rect.origin() - image_rect.origin();
774 image += source_offset.y() * image_row_bytes + source_offset.x() * 4;
775
776 ScopedWriteLockSoftware lock(this, id);
James Robinsonc4c1c592014-11-21 18:27:04 -0800777 SkCanvas dest(lock.sk_bitmap());
778 dest.writePixels(source_info, image, image_row_bytes, dest_offset.x(),
779 dest_offset.y());
James Robinson646469d2014-10-03 15:33:28 -0700780 }
781}
782
783size_t ResourceProvider::NumBlockingUploads() {
784 if (!texture_uploader_)
785 return 0;
786
787 return texture_uploader_->NumBlockingUploads();
788}
789
790void ResourceProvider::MarkPendingUploadsAsNonBlocking() {
791 if (!texture_uploader_)
792 return;
793
794 texture_uploader_->MarkPendingUploadsAsNonBlocking();
795}
796
797size_t ResourceProvider::EstimatedUploadsPerTick() {
798 if (!texture_uploader_)
799 return 1u;
800
801 double textures_per_second = texture_uploader_->EstimatedTexturesPerSecond();
802 size_t textures_per_tick = floor(
803 kTextureUploadTickRate * textures_per_second);
804 return textures_per_tick ? textures_per_tick : 1u;
805}
806
807void ResourceProvider::FlushUploads() {
808 if (!texture_uploader_)
809 return;
810
811 texture_uploader_->Flush();
812}
813
814void ResourceProvider::ReleaseCachedData() {
815 if (!texture_uploader_)
816 return;
817
818 texture_uploader_->ReleaseCachedQueries();
819}
820
821base::TimeTicks ResourceProvider::EstimatedUploadCompletionTime(
822 size_t uploads_per_tick) {
823 if (lost_output_surface_)
824 return base::TimeTicks();
825
826 // Software resource uploads happen on impl thread, so don't bother batching
827 // them up and trying to wait for them to complete.
828 if (!texture_uploader_) {
829 return gfx::FrameTime::Now() + base::TimeDelta::FromMicroseconds(
830 base::Time::kMicrosecondsPerSecond * kSoftwareUploadTickRate);
831 }
832
833 base::TimeDelta upload_one_texture_time =
834 base::TimeDelta::FromMicroseconds(
835 base::Time::kMicrosecondsPerSecond * kTextureUploadTickRate) /
836 uploads_per_tick;
837
838 size_t total_uploads = NumBlockingUploads() + uploads_per_tick;
839 return gfx::FrameTime::Now() + upload_one_texture_time * total_uploads;
840}
841
842ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) {
843 DCHECK(thread_checker_.CalledOnValidThread());
844 ResourceMap::iterator it = resources_.find(id);
845 CHECK(it != resources_.end());
846 return &it->second;
847}
848
849const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
850 Resource* resource = GetResource(id);
851 DCHECK(!resource->locked_for_write ||
852 resource->set_pixels_completion_forced) <<
853 "locked for write: " << resource->locked_for_write <<
854 " pixels completion forced: " << resource->set_pixels_completion_forced;
855 DCHECK_EQ(resource->exported_count, 0);
856 // Uninitialized! Call SetPixels or LockForWrite first.
857 DCHECK(resource->allocated);
858
859 LazyCreate(resource);
860
861 if (resource->type == GLTexture && !resource->gl_id) {
862 DCHECK(resource->origin != Resource::Internal);
863 DCHECK(resource->mailbox.IsTexture());
864
865 // Mailbox sync_points must be processed by a call to
866 // WaitSyncPointIfNeeded() prior to calling LockForRead().
867 DCHECK(!resource->mailbox.sync_point());
868
869 GLES2Interface* gl = ContextGL();
870 DCHECK(gl);
871 resource->gl_id = texture_id_allocator_->NextId();
872 GLC(gl, gl->BindTexture(resource->target, resource->gl_id));
873 GLC(gl,
874 gl->ConsumeTextureCHROMIUM(resource->mailbox.target(),
875 resource->mailbox.name()));
876 }
877
878 if (!resource->pixels && resource->has_shared_bitmap_id &&
879 shared_bitmap_manager_) {
880 scoped_ptr<SharedBitmap> bitmap =
881 shared_bitmap_manager_->GetSharedBitmapFromId(
882 resource->size, resource->shared_bitmap_id);
883 if (bitmap) {
884 resource->shared_bitmap = bitmap.release();
885 resource->pixels = resource->shared_bitmap->pixels();
886 }
887 }
888
889 resource->lock_for_read_count++;
890 if (resource->read_lock_fences_enabled) {
891 if (current_read_lock_fence_.get())
892 current_read_lock_fence_->Set();
893 resource->read_lock_fence = current_read_lock_fence_;
894 }
895
896 return resource;
897}
898
899void ResourceProvider::UnlockForRead(ResourceId id) {
900 DCHECK(thread_checker_.CalledOnValidThread());
901 ResourceMap::iterator it = resources_.find(id);
902 CHECK(it != resources_.end());
903
904 Resource* resource = &it->second;
905 DCHECK_GT(resource->lock_for_read_count, 0);
906 DCHECK_EQ(resource->exported_count, 0);
907 resource->lock_for_read_count--;
908 if (resource->marked_for_deletion && !resource->lock_for_read_count) {
909 if (!resource->child_id) {
910 // The resource belongs to this ResourceProvider, so it can be destroyed.
911 DeleteResourceInternal(it, Normal);
912 } else {
913 ChildMap::iterator child_it = children_.find(resource->child_id);
914 ResourceIdArray unused;
915 unused.push_back(id);
916 DeleteAndReturnUnusedResourcesToChild(child_it, Normal, unused);
917 }
918 }
919}
920
James Robinson53b77582014-10-28 17:00:48 -0700921ResourceProvider::Resource* ResourceProvider::LockForWrite(ResourceId id) {
James Robinson646469d2014-10-03 15:33:28 -0700922 Resource* resource = GetResource(id);
James Robinsonbaf71d32014-10-08 13:00:20 -0700923 DCHECK(CanLockForWrite(id));
James Robinson646469d2014-10-03 15:33:28 -0700924
925 resource->locked_for_write = true;
926 return resource;
927}
928
929bool ResourceProvider::CanLockForWrite(ResourceId id) {
930 Resource* resource = GetResource(id);
931 return !resource->locked_for_write && !resource->lock_for_read_count &&
932 !resource->exported_count && resource->origin == Resource::Internal &&
933 !resource->lost && ReadLockFenceHasPassed(resource);
934}
935
James Robinson53b77582014-10-28 17:00:48 -0700936void ResourceProvider::UnlockForWrite(ResourceProvider::Resource* resource) {
James Robinson646469d2014-10-03 15:33:28 -0700937 DCHECK(resource->locked_for_write);
938 DCHECK_EQ(resource->exported_count, 0);
939 DCHECK(resource->origin == Resource::Internal);
940 resource->locked_for_write = false;
941}
942
943ResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
944 ResourceProvider* resource_provider,
945 ResourceProvider::ResourceId resource_id)
946 : resource_provider_(resource_provider),
947 resource_id_(resource_id),
948 texture_id_(resource_provider->LockForRead(resource_id)->gl_id) {
949 DCHECK(texture_id_);
950}
951
952ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
953 resource_provider_->UnlockForRead(resource_id_);
954}
955
956ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
957 ResourceProvider* resource_provider,
958 ResourceProvider::ResourceId resource_id,
959 GLenum filter)
960 : ScopedReadLockGL(resource_provider, resource_id),
961 unit_(GL_TEXTURE0),
962 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
963}
964
965ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
966 ResourceProvider* resource_provider,
967 ResourceProvider::ResourceId resource_id,
968 GLenum unit,
969 GLenum filter)
970 : ScopedReadLockGL(resource_provider, resource_id),
971 unit_(unit),
972 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
973}
974
975ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() {
976}
977
978ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(
979 ResourceProvider* resource_provider,
980 ResourceProvider::ResourceId resource_id)
981 : resource_provider_(resource_provider),
James Robinson53b77582014-10-28 17:00:48 -0700982 resource_(resource_provider->LockForWrite(resource_id)) {
983 resource_provider_->LazyAllocate(resource_);
984 texture_id_ = resource_->gl_id;
James Robinson646469d2014-10-03 15:33:28 -0700985 DCHECK(texture_id_);
986}
987
988ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() {
James Robinson53b77582014-10-28 17:00:48 -0700989 resource_provider_->UnlockForWrite(resource_);
James Robinson646469d2014-10-03 15:33:28 -0700990}
991
992void ResourceProvider::PopulateSkBitmapWithResource(
993 SkBitmap* sk_bitmap, const Resource* resource) {
994 DCHECK_EQ(RGBA_8888, resource->format);
995 SkImageInfo info = SkImageInfo::MakeN32Premul(resource->size.width(),
996 resource->size.height());
997 sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes());
998}
999
1000ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(
1001 ResourceProvider* resource_provider,
1002 ResourceProvider::ResourceId resource_id)
1003 : resource_provider_(resource_provider),
1004 resource_id_(resource_id) {
1005 const Resource* resource = resource_provider->LockForRead(resource_id);
1006 wrap_mode_ = resource->wrap_mode;
1007 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource);
1008}
1009
1010ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() {
1011 resource_provider_->UnlockForRead(resource_id_);
1012}
1013
1014ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(
1015 ResourceProvider* resource_provider,
1016 ResourceProvider::ResourceId resource_id)
1017 : resource_provider_(resource_provider),
James Robinson53b77582014-10-28 17:00:48 -07001018 resource_(resource_provider->LockForWrite(resource_id)) {
1019 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource_);
James Robinson646469d2014-10-03 15:33:28 -07001020 DCHECK(valid());
James Robinson646469d2014-10-03 15:33:28 -07001021}
1022
1023ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() {
James Robinson7f480212014-10-31 10:28:08 -07001024 DCHECK(thread_checker_.CalledOnValidThread());
James Robinson53b77582014-10-28 17:00:48 -07001025 resource_provider_->UnlockForWrite(resource_);
James Robinson646469d2014-10-03 15:33:28 -07001026}
1027
James Robinsonbaf71d32014-10-08 13:00:20 -07001028ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
1029 ScopedWriteLockGpuMemoryBuffer(ResourceProvider* resource_provider,
1030 ResourceProvider::ResourceId resource_id)
1031 : resource_provider_(resource_provider),
James Robinson53b77582014-10-28 17:00:48 -07001032 resource_(resource_provider->LockForWrite(resource_id)),
1033 gpu_memory_buffer_manager_(resource_provider->gpu_memory_buffer_manager_),
1034 gpu_memory_buffer_(nullptr),
1035 size_(resource_->size),
1036 format_(resource_->format) {
1037 DCHECK_EQ(GLTexture, resource_->type);
1038 std::swap(gpu_memory_buffer_, resource_->gpu_memory_buffer);
James Robinsonbaf71d32014-10-08 13:00:20 -07001039}
1040
1041ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
1042 ~ScopedWriteLockGpuMemoryBuffer() {
James Robinson7f480212014-10-31 10:28:08 -07001043 DCHECK(thread_checker_.CalledOnValidThread());
James Robinson53b77582014-10-28 17:00:48 -07001044 resource_provider_->UnlockForWrite(resource_);
1045 if (!gpu_memory_buffer_)
1046 return;
1047
1048 if (!resource_->image_id) {
1049 GLES2Interface* gl = resource_provider_->ContextGL();
1050 DCHECK(gl);
1051
James Robinsonea3edff2015-01-12 16:21:57 -08001052#if defined(OS_CHROMEOS)
1053 // TODO(reveman): GL_COMMANDS_ISSUED_CHROMIUM is used for synchronization
1054 // on ChromeOS to avoid some performance issues. This only works with
1055 // shared memory backed buffers. crbug.com/436314
1056 DCHECK_EQ(gpu_memory_buffer_->GetHandle().type, gfx::SHARED_MEMORY_BUFFER);
1057#endif
1058
James Robinson53b77582014-10-28 17:00:48 -07001059 resource_->image_id =
1060 gl->CreateImageCHROMIUM(gpu_memory_buffer_->AsClientBuffer(),
1061 size_.width(),
1062 size_.height(),
1063 GL_RGBA);
1064 }
1065
1066 std::swap(resource_->gpu_memory_buffer, gpu_memory_buffer_);
1067 resource_->allocated = true;
1068 resource_->dirty_image = true;
1069
1070 // GpuMemoryBuffer provides direct access to the memory used by the GPU.
1071 // Read lock fences are required to ensure that we're not trying to map a
1072 // buffer that is currently in-use by the GPU.
1073 resource_->read_lock_fences_enabled = true;
1074}
1075
1076gfx::GpuMemoryBuffer*
1077ResourceProvider::ScopedWriteLockGpuMemoryBuffer::GetGpuMemoryBuffer() {
1078 if (!gpu_memory_buffer_) {
1079 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
1080 gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer(
1081 size_, ToGpuMemoryBufferFormat(format_), gfx::GpuMemoryBuffer::MAP);
1082 gpu_memory_buffer_ = gpu_memory_buffer.release();
1083 }
1084
1085 return gpu_memory_buffer_;
James Robinsonbaf71d32014-10-08 13:00:20 -07001086}
1087
1088ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr(
1089 ResourceProvider* resource_provider,
Benjamin Lermancdfc88d2015-02-03 14:35:12 +01001090 ResourceProvider::ResourceId resource_id,
1091 bool use_distance_field_text,
1092 bool can_use_lcd_text,
1093 int msaa_sample_count)
James Robinson53b77582014-10-28 17:00:48 -07001094 : resource_provider_(resource_provider),
1095 resource_(resource_provider->LockForWrite(resource_id)) {
Benjamin Lermancdfc88d2015-02-03 14:35:12 +01001096 // Create the sk_surface.
James Robinson7f480212014-10-31 10:28:08 -07001097 DCHECK(thread_checker_.CalledOnValidThread());
James Robinson53b77582014-10-28 17:00:48 -07001098 DCHECK(resource_->locked_for_write);
James Robinson675df572014-10-22 17:20:33 -07001099
Benjamin Lermancdfc88d2015-02-03 14:35:12 +01001100 resource_provider_->LazyAllocate(resource_);
James Robinson675df572014-10-22 17:20:33 -07001101
Benjamin Lermancdfc88d2015-02-03 14:35:12 +01001102 GrBackendTextureDesc desc;
1103 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
1104 desc.fWidth = resource_->size.width();
1105 desc.fHeight = resource_->size.height();
1106 desc.fConfig = ToGrPixelConfig(resource_->format);
1107 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1108 desc.fTextureHandle = resource_->gl_id;
1109 desc.fSampleCnt = msaa_sample_count;
Etienne Membrivesb1556b32014-12-16 13:56:09 +01001110
Benjamin Lermancdfc88d2015-02-03 14:35:12 +01001111 class GrContext* gr_context = resource_provider_->GrContext();
1112 skia::RefPtr<GrTexture> gr_texture =
1113 skia::AdoptRef(gr_context->wrapBackendTexture(desc));
1114 if (gr_texture) {
James Robinson3f862972014-11-18 16:50:38 -08001115 uint32_t flags = use_distance_field_text
1116 ? SkSurfaceProps::kUseDistanceFieldFonts_Flag
1117 : 0;
1118 // Use unknown pixel geometry to disable LCD text.
1119 SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
1120 if (can_use_lcd_text) {
1121 // LegacyFontHost will get LCD text and skia figures out what type to use.
1122 surface_props =
1123 SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
1124 }
Benjamin Lermancdfc88d2015-02-03 14:35:12 +01001125 sk_surface_ = skia::AdoptRef(SkSurface::NewRenderTargetDirect(
James Robinson3f862972014-11-18 16:50:38 -08001126 gr_texture->asRenderTarget(), &surface_props));
James Robinson675df572014-10-22 17:20:33 -07001127 }
James Robinson675df572014-10-22 17:20:33 -07001128}
1129
Benjamin Lermancdfc88d2015-02-03 14:35:12 +01001130ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
1131 DCHECK(thread_checker_.CalledOnValidThread());
1132 resource_provider_->UnlockForWrite(resource_);
James Robinson3f862972014-11-18 16:50:38 -08001133}
1134
James Robinson7f480212014-10-31 10:28:08 -07001135ResourceProvider::SynchronousFence::SynchronousFence(
1136 gpu::gles2::GLES2Interface* gl)
1137 : gl_(gl), has_synchronized_(true) {
1138}
1139
1140ResourceProvider::SynchronousFence::~SynchronousFence() {
1141}
1142
1143void ResourceProvider::SynchronousFence::Set() {
1144 has_synchronized_ = false;
1145}
1146
1147bool ResourceProvider::SynchronousFence::HasPassed() {
1148 if (!has_synchronized_) {
1149 has_synchronized_ = true;
1150 Synchronize();
1151 }
1152 return true;
1153}
1154
1155void ResourceProvider::SynchronousFence::Wait() {
1156 HasPassed();
1157}
1158
1159void ResourceProvider::SynchronousFence::Synchronize() {
1160 TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize");
1161 gl_->Finish();
1162}
1163
James Robinson646469d2014-10-03 15:33:28 -07001164ResourceProvider::ResourceProvider(
1165 OutputSurface* output_surface,
1166 SharedBitmapManager* shared_bitmap_manager,
James Robinson53b77582014-10-28 17:00:48 -07001167 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
James Robinson646469d2014-10-03 15:33:28 -07001168 BlockingTaskRunner* blocking_main_thread_task_runner,
1169 int highp_threshold_min,
1170 bool use_rgba_4444_texture_format,
James Robinson675df572014-10-22 17:20:33 -07001171 size_t id_allocation_chunk_size)
James Robinson646469d2014-10-03 15:33:28 -07001172 : output_surface_(output_surface),
1173 shared_bitmap_manager_(shared_bitmap_manager),
James Robinsone2ac7e82014-10-15 13:21:59 -07001174 gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
James Robinson646469d2014-10-03 15:33:28 -07001175 blocking_main_thread_task_runner_(blocking_main_thread_task_runner),
1176 lost_output_surface_(false),
1177 highp_threshold_min_(highp_threshold_min),
1178 next_id_(1),
1179 next_child_(1),
1180 default_resource_type_(InvalidType),
1181 use_texture_storage_ext_(false),
1182 use_texture_format_bgra_(false),
1183 use_texture_usage_hint_(false),
1184 use_compressed_texture_etc1_(false),
James Robinson6a64b812014-12-03 13:38:42 -08001185 yuv_resource_format_(LUMINANCE_8),
James Robinson646469d2014-10-03 15:33:28 -07001186 max_texture_size_(0),
1187 best_texture_format_(RGBA_8888),
1188 use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
1189 id_allocation_chunk_size_(id_allocation_chunk_size),
James Robinson675df572014-10-22 17:20:33 -07001190 use_sync_query_(false) {
James Robinson646469d2014-10-03 15:33:28 -07001191 DCHECK(output_surface_->HasClient());
1192 DCHECK(id_allocation_chunk_size_);
1193}
1194
1195void ResourceProvider::InitializeSoftware() {
1196 DCHECK(thread_checker_.CalledOnValidThread());
1197 DCHECK_NE(Bitmap, default_resource_type_);
1198
1199 CleanUpGLIfNeeded();
1200
1201 default_resource_type_ = Bitmap;
1202 // Pick an arbitrary limit here similar to what hardware might.
1203 max_texture_size_ = 16 * 1024;
1204 best_texture_format_ = RGBA_8888;
1205}
1206
1207void ResourceProvider::InitializeGL() {
1208 DCHECK(thread_checker_.CalledOnValidThread());
1209 DCHECK(!texture_uploader_);
1210 DCHECK_NE(GLTexture, default_resource_type_);
1211 DCHECK(!texture_id_allocator_);
1212 DCHECK(!buffer_id_allocator_);
1213
1214 default_resource_type_ = GLTexture;
1215
1216 const ContextProvider::Capabilities& caps =
1217 output_surface_->context_provider()->ContextCapabilities();
1218
1219 bool use_bgra = caps.gpu.texture_format_bgra8888;
1220 use_texture_storage_ext_ = caps.gpu.texture_storage;
1221 use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888;
1222 use_texture_usage_hint_ = caps.gpu.texture_usage;
1223 use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1;
James Robinson6a64b812014-12-03 13:38:42 -08001224 yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8;
James Robinson646469d2014-10-03 15:33:28 -07001225 use_sync_query_ = caps.gpu.sync_query;
1226
1227 GLES2Interface* gl = ContextGL();
1228 DCHECK(gl);
1229
1230 texture_uploader_ = TextureUploader::Create(gl);
1231 max_texture_size_ = 0; // Context expects cleared value.
1232 GLC(gl, gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_));
1233 best_texture_format_ = PlatformColor::BestTextureFormat(use_bgra);
1234
1235 texture_id_allocator_.reset(
1236 new TextureIdAllocator(gl, id_allocation_chunk_size_));
1237 buffer_id_allocator_.reset(
1238 new BufferIdAllocator(gl, id_allocation_chunk_size_));
1239}
1240
1241void ResourceProvider::CleanUpGLIfNeeded() {
1242 GLES2Interface* gl = ContextGL();
1243 if (default_resource_type_ != GLTexture) {
1244 // We are not in GL mode, but double check before returning.
1245 DCHECK(!gl);
1246 DCHECK(!texture_uploader_);
1247 return;
1248 }
1249
1250 DCHECK(gl);
James Robinsond753aca2015-01-12 13:07:20 -08001251#if DCHECK_IS_ON()
James Robinson646469d2014-10-03 15:33:28 -07001252 // Check that all GL resources has been deleted.
1253 for (ResourceMap::const_iterator itr = resources_.begin();
1254 itr != resources_.end();
1255 ++itr) {
1256 DCHECK_NE(GLTexture, itr->second.type);
1257 }
James Robinsond753aca2015-01-12 13:07:20 -08001258#endif // DCHECK_IS_ON()
James Robinson646469d2014-10-03 15:33:28 -07001259
1260 texture_uploader_ = nullptr;
1261 texture_id_allocator_ = nullptr;
1262 buffer_id_allocator_ = nullptr;
1263 gl->Finish();
1264}
1265
1266int ResourceProvider::CreateChild(const ReturnCallback& return_callback) {
1267 DCHECK(thread_checker_.CalledOnValidThread());
1268
1269 Child child_info;
1270 child_info.return_callback = return_callback;
1271
1272 int child = next_child_++;
1273 children_[child] = child_info;
1274 return child;
1275}
1276
1277void ResourceProvider::DestroyChild(int child_id) {
1278 ChildMap::iterator it = children_.find(child_id);
1279 DCHECK(it != children_.end());
1280 DestroyChildInternal(it, Normal);
1281}
1282
1283void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
1284 DeleteStyle style) {
1285 DCHECK(thread_checker_.CalledOnValidThread());
1286
1287 Child& child = it->second;
1288 DCHECK(style == ForShutdown || !child.marked_for_deletion);
1289
1290 ResourceIdArray resources_for_child;
1291
1292 for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin();
1293 child_it != child.child_to_parent_map.end();
1294 ++child_it) {
1295 ResourceId id = child_it->second;
1296 resources_for_child.push_back(id);
1297 }
1298
1299 // If the child is going away, don't consider any resources in use.
1300 child.in_use_resources.clear();
1301 child.marked_for_deletion = true;
1302
1303 DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child);
1304}
1305
1306const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap(
1307 int child) const {
1308 DCHECK(thread_checker_.CalledOnValidThread());
1309 ChildMap::const_iterator it = children_.find(child);
1310 DCHECK(it != children_.end());
1311 DCHECK(!it->second.marked_for_deletion);
1312 return it->second.child_to_parent_map;
1313}
1314
1315void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
1316 TransferableResourceArray* list) {
1317 DCHECK(thread_checker_.CalledOnValidThread());
1318 GLES2Interface* gl = ContextGL();
1319 bool need_sync_point = false;
1320 for (ResourceIdArray::const_iterator it = resources.begin();
1321 it != resources.end();
1322 ++it) {
1323 TransferableResource resource;
1324 TransferResource(gl, *it, &resource);
1325 if (!resource.mailbox_holder.sync_point && !resource.is_software)
1326 need_sync_point = true;
1327 ++resources_.find(*it)->second.exported_count;
1328 list->push_back(resource);
1329 }
1330 if (need_sync_point) {
1331 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1332 for (TransferableResourceArray::iterator it = list->begin();
1333 it != list->end();
1334 ++it) {
1335 if (!it->mailbox_holder.sync_point)
1336 it->mailbox_holder.sync_point = sync_point;
1337 }
1338 }
1339}
1340
1341void ResourceProvider::ReceiveFromChild(
1342 int child, const TransferableResourceArray& resources) {
1343 DCHECK(thread_checker_.CalledOnValidThread());
1344 GLES2Interface* gl = ContextGL();
1345 Child& child_info = children_.find(child)->second;
1346 DCHECK(!child_info.marked_for_deletion);
1347 for (TransferableResourceArray::const_iterator it = resources.begin();
1348 it != resources.end();
1349 ++it) {
1350 ResourceIdMap::iterator resource_in_map_it =
1351 child_info.child_to_parent_map.find(it->id);
1352 if (resource_in_map_it != child_info.child_to_parent_map.end()) {
1353 Resource& resource = resources_[resource_in_map_it->second];
1354 resource.marked_for_deletion = false;
1355 resource.imported_count++;
1356 continue;
1357 }
1358
1359 if ((!it->is_software && !gl) ||
1360 (it->is_software && !shared_bitmap_manager_)) {
1361 TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
1362 ReturnedResourceArray to_return;
1363 to_return.push_back(it->ToReturnedResource());
1364 child_info.return_callback.Run(to_return,
1365 blocking_main_thread_task_runner_);
1366 continue;
1367 }
1368
1369 ResourceId local_id = next_id_++;
1370 Resource& resource = resources_[local_id];
1371 if (it->is_software) {
1372 resource = Resource(it->mailbox_holder.mailbox,
1373 it->size,
1374 Resource::Delegated,
1375 GL_LINEAR,
1376 it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE);
1377 } else {
1378 resource = Resource(0,
1379 it->size,
1380 Resource::Delegated,
1381 it->mailbox_holder.texture_target,
1382 it->filter,
1383 0,
1384 it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE,
1385 TextureHintImmutable,
1386 it->format);
1387 resource.mailbox = TextureMailbox(it->mailbox_holder.mailbox,
1388 it->mailbox_holder.texture_target,
1389 it->mailbox_holder.sync_point);
1390 }
1391 resource.child_id = child;
1392 // Don't allocate a texture for a child.
1393 resource.allocated = true;
1394 resource.imported_count = 1;
1395 resource.allow_overlay = it->allow_overlay;
1396 child_info.parent_to_child_map[local_id] = it->id;
1397 child_info.child_to_parent_map[it->id] = local_id;
1398 }
1399}
1400
1401void ResourceProvider::DeclareUsedResourcesFromChild(
1402 int child,
1403 const ResourceIdArray& resources_from_child) {
1404 DCHECK(thread_checker_.CalledOnValidThread());
1405
1406 ChildMap::iterator child_it = children_.find(child);
1407 DCHECK(child_it != children_.end());
1408 Child& child_info = child_it->second;
1409 DCHECK(!child_info.marked_for_deletion);
1410 child_info.in_use_resources.clear();
1411
1412 for (size_t i = 0; i < resources_from_child.size(); ++i) {
1413 ResourceIdMap::iterator it =
1414 child_info.child_to_parent_map.find(resources_from_child[i]);
1415 DCHECK(it != child_info.child_to_parent_map.end());
1416
1417 ResourceId local_id = it->second;
1418 DCHECK(!resources_[local_id].marked_for_deletion);
1419 child_info.in_use_resources.insert(local_id);
1420 }
1421
1422 ResourceIdArray unused;
1423 for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin();
1424 it != child_info.child_to_parent_map.end();
1425 ++it) {
1426 ResourceId local_id = it->second;
1427 bool resource_is_in_use = child_info.in_use_resources.count(local_id) > 0;
1428 if (!resource_is_in_use)
1429 unused.push_back(local_id);
1430 }
1431 DeleteAndReturnUnusedResourcesToChild(child_it, Normal, unused);
1432}
1433
1434// static
1435bool ResourceProvider::CompareResourceMapIteratorsByChildId(
1436 const std::pair<ReturnedResource, ResourceMap::iterator>& a,
1437 const std::pair<ReturnedResource, ResourceMap::iterator>& b) {
1438 const ResourceMap::iterator& a_it = a.second;
1439 const ResourceMap::iterator& b_it = b.second;
1440 const Resource& a_resource = a_it->second;
1441 const Resource& b_resource = b_it->second;
1442 return a_resource.child_id < b_resource.child_id;
1443}
1444
1445void ResourceProvider::ReceiveReturnsFromParent(
1446 const ReturnedResourceArray& resources) {
1447 DCHECK(thread_checker_.CalledOnValidThread());
1448 GLES2Interface* gl = ContextGL();
1449
1450 int child_id = 0;
1451 ResourceIdArray resources_for_child;
1452
James Robinson80d418c2014-10-16 16:00:02 -07001453 std::vector<std::pair<ReturnedResource, ResourceMap::iterator>>
James Robinson646469d2014-10-03 15:33:28 -07001454 sorted_resources;
1455
1456 for (ReturnedResourceArray::const_iterator it = resources.begin();
1457 it != resources.end();
1458 ++it) {
1459 ResourceId local_id = it->id;
1460 ResourceMap::iterator map_iterator = resources_.find(local_id);
1461
1462 // Resource was already lost (e.g. it belonged to a child that was
1463 // destroyed).
1464 if (map_iterator == resources_.end())
1465 continue;
1466
1467 sorted_resources.push_back(
1468 std::pair<ReturnedResource, ResourceMap::iterator>(*it, map_iterator));
1469 }
1470
1471 std::sort(sorted_resources.begin(),
1472 sorted_resources.end(),
1473 CompareResourceMapIteratorsByChildId);
1474
1475 ChildMap::iterator child_it = children_.end();
1476 for (size_t i = 0; i < sorted_resources.size(); ++i) {
1477 ReturnedResource& returned = sorted_resources[i].first;
1478 ResourceMap::iterator& map_iterator = sorted_resources[i].second;
1479 ResourceId local_id = map_iterator->first;
1480 Resource* resource = &map_iterator->second;
1481
1482 CHECK_GE(resource->exported_count, returned.count);
1483 resource->exported_count -= returned.count;
1484 resource->lost |= returned.lost;
1485 if (resource->exported_count)
1486 continue;
1487
1488 // Need to wait for the current read lock fence to pass before we can
1489 // recycle this resource.
1490 if (resource->read_lock_fences_enabled) {
1491 if (current_read_lock_fence_.get())
1492 current_read_lock_fence_->Set();
1493 resource->read_lock_fence = current_read_lock_fence_;
1494 }
1495
1496 if (returned.sync_point) {
1497 DCHECK(!resource->has_shared_bitmap_id);
1498 if (resource->origin == Resource::Internal) {
1499 DCHECK(resource->gl_id);
1500 GLC(gl, gl->WaitSyncPointCHROMIUM(returned.sync_point));
1501 } else {
1502 DCHECK(!resource->gl_id);
1503 resource->mailbox.set_sync_point(returned.sync_point);
1504 }
1505 }
1506
1507 if (!resource->marked_for_deletion)
1508 continue;
1509
1510 if (!resource->child_id) {
1511 // The resource belongs to this ResourceProvider, so it can be destroyed.
1512 DeleteResourceInternal(map_iterator, Normal);
1513 continue;
1514 }
1515
1516 DCHECK(resource->origin == Resource::Delegated);
1517 // Delete the resource and return it to the child it came from one.
1518 if (resource->child_id != child_id) {
1519 if (child_id) {
1520 DCHECK_NE(resources_for_child.size(), 0u);
1521 DCHECK(child_it != children_.end());
1522 DeleteAndReturnUnusedResourcesToChild(
1523 child_it, Normal, resources_for_child);
1524 resources_for_child.clear();
1525 }
1526
1527 child_it = children_.find(resource->child_id);
1528 DCHECK(child_it != children_.end());
1529 child_id = resource->child_id;
1530 }
1531 resources_for_child.push_back(local_id);
1532 }
1533
1534 if (child_id) {
1535 DCHECK_NE(resources_for_child.size(), 0u);
1536 DCHECK(child_it != children_.end());
1537 DeleteAndReturnUnusedResourcesToChild(
1538 child_it, Normal, resources_for_child);
1539 }
1540}
1541
1542void ResourceProvider::TransferResource(GLES2Interface* gl,
1543 ResourceId id,
1544 TransferableResource* resource) {
1545 Resource* source = GetResource(id);
1546 DCHECK(!source->locked_for_write);
1547 DCHECK(!source->lock_for_read_count);
1548 DCHECK(source->origin != Resource::External || source->mailbox.IsValid());
1549 DCHECK(source->allocated);
1550 resource->id = id;
1551 resource->format = source->format;
1552 resource->mailbox_holder.texture_target = source->target;
1553 resource->filter = source->filter;
1554 resource->size = source->size;
1555 resource->is_repeated = (source->wrap_mode == GL_REPEAT);
1556 resource->allow_overlay = source->allow_overlay;
1557
1558 if (source->type == Bitmap) {
1559 resource->mailbox_holder.mailbox = source->shared_bitmap_id;
1560 resource->is_software = true;
1561 } else if (!source->mailbox.IsValid()) {
1562 LazyCreate(source);
1563 DCHECK(source->gl_id);
1564 DCHECK(source->origin == Resource::Internal);
1565 GLC(gl,
1566 gl->BindTexture(resource->mailbox_holder.texture_target,
1567 source->gl_id));
1568 if (source->image_id) {
1569 DCHECK(source->dirty_image);
1570 BindImageForSampling(source);
1571 }
1572 // This is a resource allocated by the compositor, we need to produce it.
1573 // Don't set a sync point, the caller will do it.
1574 GLC(gl, gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name));
1575 GLC(gl,
1576 gl->ProduceTextureCHROMIUM(resource->mailbox_holder.texture_target,
1577 resource->mailbox_holder.mailbox.name));
1578 source->mailbox = TextureMailbox(resource->mailbox_holder);
1579 } else {
1580 DCHECK(source->mailbox.IsTexture());
1581 if (source->image_id && source->dirty_image) {
1582 DCHECK(source->gl_id);
1583 DCHECK(source->origin == Resource::Internal);
1584 GLC(gl,
1585 gl->BindTexture(resource->mailbox_holder.texture_target,
1586 source->gl_id));
1587 BindImageForSampling(source);
1588 }
1589 // This is either an external resource, or a compositor resource that we
1590 // already exported. Make sure to forward the sync point that we were given.
1591 resource->mailbox_holder.mailbox = source->mailbox.mailbox();
1592 resource->mailbox_holder.texture_target = source->mailbox.target();
1593 resource->mailbox_holder.sync_point = source->mailbox.sync_point();
1594 source->mailbox.set_sync_point(0);
1595 }
1596}
1597
1598void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
1599 ChildMap::iterator child_it,
1600 DeleteStyle style,
1601 const ResourceIdArray& unused) {
1602 DCHECK(thread_checker_.CalledOnValidThread());
1603 DCHECK(child_it != children_.end());
1604 Child* child_info = &child_it->second;
1605
1606 if (unused.empty() && !child_info->marked_for_deletion)
1607 return;
1608
1609 ReturnedResourceArray to_return;
1610
1611 GLES2Interface* gl = ContextGL();
1612 bool need_sync_point = false;
1613 for (size_t i = 0; i < unused.size(); ++i) {
1614 ResourceId local_id = unused[i];
1615
1616 ResourceMap::iterator it = resources_.find(local_id);
1617 CHECK(it != resources_.end());
1618 Resource& resource = it->second;
1619
1620 DCHECK(!resource.locked_for_write);
1621 DCHECK_EQ(0u, child_info->in_use_resources.count(local_id));
1622 DCHECK(child_info->parent_to_child_map.count(local_id));
1623
1624 ResourceId child_id = child_info->parent_to_child_map[local_id];
1625 DCHECK(child_info->child_to_parent_map.count(child_id));
1626
1627 bool is_lost =
1628 resource.lost || (resource.type == GLTexture && lost_output_surface_);
1629 if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
1630 if (style != ForShutdown) {
1631 // Defer this until we receive the resource back from the parent or
1632 // the read lock is released.
1633 resource.marked_for_deletion = true;
1634 continue;
1635 }
1636
1637 // We still have an exported_count, so we'll have to lose it.
1638 is_lost = true;
1639 }
1640
1641 if (gl && resource.filter != resource.original_filter) {
1642 DCHECK(resource.target);
1643 DCHECK(resource.gl_id);
1644
1645 GLC(gl, gl->BindTexture(resource.target, resource.gl_id));
1646 GLC(gl,
1647 gl->TexParameteri(resource.target,
1648 GL_TEXTURE_MIN_FILTER,
1649 resource.original_filter));
1650 GLC(gl,
1651 gl->TexParameteri(resource.target,
1652 GL_TEXTURE_MAG_FILTER,
1653 resource.original_filter));
1654 }
1655
1656 ReturnedResource returned;
1657 returned.id = child_id;
1658 returned.sync_point = resource.mailbox.sync_point();
1659 if (!returned.sync_point && resource.type == GLTexture)
1660 need_sync_point = true;
1661 returned.count = resource.imported_count;
1662 returned.lost = is_lost;
1663 to_return.push_back(returned);
1664
1665 child_info->parent_to_child_map.erase(local_id);
1666 child_info->child_to_parent_map.erase(child_id);
1667 resource.imported_count = 0;
1668 DeleteResourceInternal(it, style);
1669 }
1670 if (need_sync_point) {
1671 DCHECK(gl);
1672 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1673 for (size_t i = 0; i < to_return.size(); ++i) {
1674 if (!to_return[i].sync_point)
1675 to_return[i].sync_point = sync_point;
1676 }
1677 }
1678
1679 if (!to_return.empty())
1680 child_info->return_callback.Run(to_return,
1681 blocking_main_thread_task_runner_);
1682
1683 if (child_info->marked_for_deletion &&
1684 child_info->parent_to_child_map.empty()) {
1685 DCHECK(child_info->child_to_parent_map.empty());
1686 children_.erase(child_it);
1687 }
1688}
1689
1690void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
1691 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1692 "ResourceProvider::AcquirePixelBuffer");
1693
1694 Resource* resource = GetResource(id);
1695 DCHECK(resource->origin == Resource::Internal);
1696 DCHECK_EQ(resource->exported_count, 0);
1697 DCHECK(!resource->image_id);
1698 DCHECK_NE(ETC1, resource->format);
1699
1700 DCHECK_EQ(GLTexture, resource->type);
1701 GLES2Interface* gl = ContextGL();
1702 DCHECK(gl);
1703 if (!resource->gl_pixel_buffer_id)
1704 resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId();
1705 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1706 resource->gl_pixel_buffer_id);
1707 unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8;
1708 gl->BufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1709 resource->size.height() *
1710 RoundUp(bytes_per_pixel * resource->size.width(), 4u),
1711 NULL,
1712 GL_DYNAMIC_DRAW);
1713 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1714}
1715
1716void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
1717 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1718 "ResourceProvider::ReleasePixelBuffer");
1719
1720 Resource* resource = GetResource(id);
1721 DCHECK(resource->origin == Resource::Internal);
1722 DCHECK_EQ(resource->exported_count, 0);
1723 DCHECK(!resource->image_id);
1724
1725 // The pixel buffer can be released while there is a pending "set pixels"
1726 // if completion has been forced. Any shared memory associated with this
1727 // pixel buffer will not be freed until the waitAsyncTexImage2DCHROMIUM
1728 // command has been processed on the service side. It is also safe to
1729 // reuse any query id associated with this resource before they complete
1730 // as each new query has a unique submit count.
1731 if (resource->pending_set_pixels) {
1732 DCHECK(resource->set_pixels_completion_forced);
1733 resource->pending_set_pixels = false;
1734 resource->locked_for_write = false;
1735 }
1736
1737 DCHECK_EQ(GLTexture, resource->type);
1738 if (!resource->gl_pixel_buffer_id)
1739 return;
1740 GLES2Interface* gl = ContextGL();
1741 DCHECK(gl);
1742 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1743 resource->gl_pixel_buffer_id);
1744 gl->BufferData(
1745 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW);
1746 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1747}
1748
1749uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id, int* stride) {
1750 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1751 "ResourceProvider::MapPixelBuffer");
1752
1753 Resource* resource = GetResource(id);
1754 DCHECK(resource->origin == Resource::Internal);
1755 DCHECK_EQ(resource->exported_count, 0);
1756 DCHECK(!resource->image_id);
1757
1758 *stride = 0;
1759 DCHECK_EQ(GLTexture, resource->type);
1760 GLES2Interface* gl = ContextGL();
1761 DCHECK(gl);
1762 DCHECK(resource->gl_pixel_buffer_id);
1763 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1764 resource->gl_pixel_buffer_id);
1765 uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
1766 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
1767 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1768 // Buffer is required to be 4-byte aligned.
1769 CHECK(!(reinterpret_cast<intptr_t>(image) & 3));
1770 return image;
1771}
1772
1773void ResourceProvider::UnmapPixelBuffer(ResourceId id) {
1774 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1775 "ResourceProvider::UnmapPixelBuffer");
1776
1777 Resource* resource = GetResource(id);
1778 DCHECK(resource->origin == Resource::Internal);
1779 DCHECK_EQ(resource->exported_count, 0);
1780 DCHECK(!resource->image_id);
1781
1782 DCHECK_EQ(GLTexture, resource->type);
1783 GLES2Interface* gl = ContextGL();
1784 DCHECK(gl);
1785 DCHECK(resource->gl_pixel_buffer_id);
1786 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1787 resource->gl_pixel_buffer_id);
1788 gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
1789 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1790}
1791
1792GLenum ResourceProvider::BindForSampling(ResourceId resource_id,
1793 GLenum unit,
1794 GLenum filter) {
1795 DCHECK(thread_checker_.CalledOnValidThread());
1796 GLES2Interface* gl = ContextGL();
1797 ResourceMap::iterator it = resources_.find(resource_id);
1798 DCHECK(it != resources_.end());
1799 Resource* resource = &it->second;
1800 DCHECK(resource->lock_for_read_count);
1801 DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced);
1802
1803 ScopedSetActiveTexture scoped_active_tex(gl, unit);
1804 GLenum target = resource->target;
1805 GLC(gl, gl->BindTexture(target, resource->gl_id));
1806 if (filter != resource->filter) {
1807 GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter));
1808 GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter));
1809 resource->filter = filter;
1810 }
1811
1812 if (resource->image_id && resource->dirty_image)
1813 BindImageForSampling(resource);
1814
1815 return target;
1816}
1817
1818void ResourceProvider::BeginSetPixels(ResourceId id) {
1819 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1820 "ResourceProvider::BeginSetPixels");
1821
1822 Resource* resource = GetResource(id);
1823 DCHECK(!resource->pending_set_pixels);
1824
1825 LazyCreate(resource);
1826 DCHECK(resource->origin == Resource::Internal);
1827 DCHECK(resource->gl_id || resource->allocated);
1828 DCHECK(ReadLockFenceHasPassed(resource));
1829 DCHECK(!resource->image_id);
1830
1831 bool allocate = !resource->allocated;
1832 resource->allocated = true;
1833 LockForWrite(id);
1834
1835 DCHECK_EQ(GLTexture, resource->type);
1836 DCHECK(resource->gl_id);
1837 GLES2Interface* gl = ContextGL();
1838 DCHECK(gl);
1839 DCHECK(resource->gl_pixel_buffer_id);
1840 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
1841 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1842 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1843 resource->gl_pixel_buffer_id);
1844 if (!resource->gl_upload_query_id)
1845 gl->GenQueriesEXT(1, &resource->gl_upload_query_id);
1846 gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM,
1847 resource->gl_upload_query_id);
1848 if (allocate) {
1849 gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D,
1850 0, /* level */
1851 GLInternalFormat(resource->format),
1852 resource->size.width(),
1853 resource->size.height(),
1854 0, /* border */
1855 GLDataFormat(resource->format),
1856 GLDataType(resource->format),
1857 NULL);
1858 } else {
1859 gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D,
1860 0, /* level */
1861 0, /* x */
1862 0, /* y */
1863 resource->size.width(),
1864 resource->size.height(),
1865 GLDataFormat(resource->format),
1866 GLDataType(resource->format),
1867 NULL);
1868 }
1869 gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM);
1870 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1871
1872 resource->pending_set_pixels = true;
1873 resource->set_pixels_completion_forced = false;
1874}
1875
1876void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) {
1877 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1878 "ResourceProvider::ForceSetPixelsToComplete");
1879
1880 Resource* resource = GetResource(id);
1881
1882 DCHECK(resource->locked_for_write);
1883 DCHECK(resource->pending_set_pixels);
1884 DCHECK(!resource->set_pixels_completion_forced);
1885
1886 if (resource->gl_id) {
1887 GLES2Interface* gl = ContextGL();
1888 GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id));
1889 GLC(gl, gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D));
1890 GLC(gl, gl->BindTexture(GL_TEXTURE_2D, 0));
1891 }
1892
1893 resource->set_pixels_completion_forced = true;
1894}
1895
1896bool ResourceProvider::DidSetPixelsComplete(ResourceId id) {
1897 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1898 "ResourceProvider::DidSetPixelsComplete");
1899
1900 Resource* resource = GetResource(id);
1901
1902 DCHECK(resource->locked_for_write);
1903 DCHECK(resource->pending_set_pixels);
1904
1905 if (resource->gl_id) {
1906 GLES2Interface* gl = ContextGL();
1907 DCHECK(gl);
1908 DCHECK(resource->gl_upload_query_id);
1909 GLuint complete = 1;
1910 gl->GetQueryObjectuivEXT(
1911 resource->gl_upload_query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete);
1912 if (!complete)
1913 return false;
1914 }
1915
1916 resource->pending_set_pixels = false;
James Robinson53b77582014-10-28 17:00:48 -07001917 UnlockForWrite(resource);
James Robinson646469d2014-10-03 15:33:28 -07001918
James Robinsonbaf71d32014-10-08 13:00:20 -07001919 // Async set pixels commands are not necessarily processed in-sequence with
1920 // drawing commands. Read lock fences are required to ensure that async
1921 // commands don't access the resource while used for drawing.
1922 resource->read_lock_fences_enabled = true;
1923
James Robinson646469d2014-10-03 15:33:28 -07001924 return true;
1925}
1926
1927void ResourceProvider::CreateForTesting(ResourceId id) {
1928 LazyCreate(GetResource(id));
1929}
1930
1931GLenum ResourceProvider::TargetForTesting(ResourceId id) {
1932 Resource* resource = GetResource(id);
1933 return resource->target;
1934}
1935
1936void ResourceProvider::LazyCreate(Resource* resource) {
1937 if (resource->type != GLTexture || resource->origin != Resource::Internal)
1938 return;
1939
1940 if (resource->gl_id)
1941 return;
1942
1943 DCHECK(resource->texture_pool);
1944 DCHECK(resource->origin == Resource::Internal);
1945 DCHECK(!resource->mailbox.IsValid());
1946 resource->gl_id = texture_id_allocator_->NextId();
1947
1948 GLES2Interface* gl = ContextGL();
1949 DCHECK(gl);
1950
1951 // Create and set texture properties. Allocation is delayed until needed.
1952 GLC(gl, gl->BindTexture(resource->target, resource->gl_id));
1953 GLC(gl,
1954 gl->TexParameteri(
1955 resource->target, GL_TEXTURE_MIN_FILTER, resource->original_filter));
1956 GLC(gl,
1957 gl->TexParameteri(
1958 resource->target, GL_TEXTURE_MAG_FILTER, resource->original_filter));
1959 GLC(gl,
1960 gl->TexParameteri(
1961 resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode));
1962 GLC(gl,
1963 gl->TexParameteri(
1964 resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode));
1965 GLC(gl,
1966 gl->TexParameteri(
1967 resource->target, GL_TEXTURE_POOL_CHROMIUM, resource->texture_pool));
1968 if (use_texture_usage_hint_ && (resource->hint & TextureHintFramebuffer)) {
1969 GLC(gl,
1970 gl->TexParameteri(resource->target,
1971 GL_TEXTURE_USAGE_ANGLE,
1972 GL_FRAMEBUFFER_ATTACHMENT_ANGLE));
1973 }
1974}
1975
1976void ResourceProvider::AllocateForTesting(ResourceId id) {
1977 LazyAllocate(GetResource(id));
1978}
1979
1980void ResourceProvider::LazyAllocate(Resource* resource) {
1981 DCHECK(resource);
1982 if (resource->allocated)
1983 return;
1984 LazyCreate(resource);
1985 if (!resource->gl_id)
1986 return;
1987 resource->allocated = true;
1988 GLES2Interface* gl = ContextGL();
1989 gfx::Size& size = resource->size;
1990 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
1991 ResourceFormat format = resource->format;
1992 GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id));
1993 if (use_texture_storage_ext_ &&
1994 IsFormatSupportedForStorage(format, use_texture_format_bgra_) &&
1995 (resource->hint & TextureHintImmutable)) {
1996 GLenum storage_format = TextureToStorageFormat(format);
1997 GLC(gl,
1998 gl->TexStorage2DEXT(
1999 GL_TEXTURE_2D, 1, storage_format, size.width(), size.height()));
2000 } else {
2001 // ETC1 does not support preallocation.
2002 if (format != ETC1) {
2003 GLC(gl,
2004 gl->TexImage2D(GL_TEXTURE_2D,
2005 0,
2006 GLInternalFormat(format),
2007 size.width(),
2008 size.height(),
2009 0,
2010 GLDataFormat(format),
2011 GLDataType(format),
2012 NULL));
2013 }
2014 }
2015}
2016
2017void ResourceProvider::BindImageForSampling(Resource* resource) {
2018 GLES2Interface* gl = ContextGL();
2019 DCHECK(resource->gl_id);
2020 DCHECK(resource->image_id);
2021
2022 // Release image currently bound to texture.
2023 if (resource->bound_image_id)
2024 gl->ReleaseTexImage2DCHROMIUM(resource->target, resource->bound_image_id);
2025 gl->BindTexImage2DCHROMIUM(resource->target, resource->image_id);
2026 resource->bound_image_id = resource->image_id;
2027 resource->dirty_image = false;
2028}
2029
James Robinson646469d2014-10-03 15:33:28 -07002030void ResourceProvider::CopyResource(ResourceId source_id, ResourceId dest_id) {
2031 TRACE_EVENT0("cc", "ResourceProvider::CopyResource");
2032
2033 Resource* source_resource = GetResource(source_id);
2034 DCHECK(!source_resource->lock_for_read_count);
2035 DCHECK(source_resource->origin == Resource::Internal);
2036 DCHECK_EQ(source_resource->exported_count, 0);
2037 DCHECK_EQ(GLTexture, source_resource->type);
2038 DCHECK(source_resource->allocated);
2039 LazyCreate(source_resource);
2040
2041 Resource* dest_resource = GetResource(dest_id);
2042 DCHECK(!dest_resource->locked_for_write);
2043 DCHECK(!dest_resource->lock_for_read_count);
2044 DCHECK(dest_resource->origin == Resource::Internal);
2045 DCHECK_EQ(dest_resource->exported_count, 0);
2046 DCHECK_EQ(GLTexture, dest_resource->type);
James Robinsonc4c1c592014-11-21 18:27:04 -08002047 LazyAllocate(dest_resource);
James Robinson646469d2014-10-03 15:33:28 -07002048
2049 DCHECK_EQ(source_resource->type, dest_resource->type);
2050 DCHECK_EQ(source_resource->format, dest_resource->format);
2051 DCHECK(source_resource->size == dest_resource->size);
2052
2053 GLES2Interface* gl = ContextGL();
2054 DCHECK(gl);
2055 if (source_resource->image_id && source_resource->dirty_image) {
2056 gl->BindTexture(source_resource->target, source_resource->gl_id);
2057 BindImageForSampling(source_resource);
2058 }
James Robinson7f480212014-10-31 10:28:08 -07002059 if (use_sync_query_) {
2060 if (!source_resource->gl_read_lock_query_id)
2061 gl->GenQueriesEXT(1, &source_resource->gl_read_lock_query_id);
James Robinsonea3edff2015-01-12 16:21:57 -08002062#if defined(OS_CHROMEOS)
2063 // TODO(reveman): This avoids a performance problem on some ChromeOS
2064 // devices. This needs to be removed to support native GpuMemoryBuffer
2065 // implementations. crbug.com/436314
2066 gl->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM,
2067 source_resource->gl_read_lock_query_id);
2068#else
James Robinson7f480212014-10-31 10:28:08 -07002069 gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM,
2070 source_resource->gl_read_lock_query_id);
James Robinsonea3edff2015-01-12 16:21:57 -08002071#endif
James Robinson7f480212014-10-31 10:28:08 -07002072 }
James Robinson646469d2014-10-03 15:33:28 -07002073 DCHECK(!dest_resource->image_id);
2074 dest_resource->allocated = true;
2075 gl->CopyTextureCHROMIUM(dest_resource->target,
2076 source_resource->gl_id,
2077 dest_resource->gl_id,
2078 0,
2079 GLInternalFormat(dest_resource->format),
2080 GLDataType(dest_resource->format));
James Robinson7f480212014-10-31 10:28:08 -07002081 if (source_resource->gl_read_lock_query_id) {
2082 // End query and create a read lock fence that will prevent access to
2083 // source resource until CopyTextureCHROMIUM command has completed.
James Robinsonea3edff2015-01-12 16:21:57 -08002084#if defined(OS_CHROMEOS)
2085 gl->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
2086#else
James Robinson7f480212014-10-31 10:28:08 -07002087 gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
James Robinsonea3edff2015-01-12 16:21:57 -08002088#endif
James Robinson7f480212014-10-31 10:28:08 -07002089 source_resource->read_lock_fence = make_scoped_refptr(
Benjamin Lerman57998902014-11-18 16:06:02 +01002090 new CopyTextureFence(gl, source_resource->gl_read_lock_query_id));
James Robinson7f480212014-10-31 10:28:08 -07002091 } else {
2092 // Create a SynchronousFence when CHROMIUM_sync_query extension is missing.
2093 // Try to use one synchronous fence for as many CopyResource operations as
2094 // possible as that reduce the number of times we have to synchronize with
2095 // the GL.
2096 if (!synchronous_fence_.get() || synchronous_fence_->has_synchronized())
2097 synchronous_fence_ = make_scoped_refptr(new SynchronousFence(gl));
2098 source_resource->read_lock_fence = synchronous_fence_;
2099 source_resource->read_lock_fence->Set();
2100 }
James Robinson646469d2014-10-03 15:33:28 -07002101}
2102
2103void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) {
2104 Resource* resource = GetResource(id);
2105 DCHECK_EQ(resource->exported_count, 0);
2106 DCHECK(resource->allocated);
2107 if (resource->type != GLTexture || resource->gl_id)
2108 return;
2109 if (!resource->mailbox.sync_point())
2110 return;
2111 DCHECK(resource->mailbox.IsValid());
2112 GLES2Interface* gl = ContextGL();
2113 DCHECK(gl);
2114 GLC(gl, gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point()));
2115 resource->mailbox.set_sync_point(0);
2116}
2117
James Robinson7f480212014-10-31 10:28:08 -07002118void ResourceProvider::WaitReadLockIfNeeded(ResourceId id) {
2119 Resource* resource = GetResource(id);
2120 DCHECK_EQ(resource->exported_count, 0);
2121 if (!resource->read_lock_fence.get())
2122 return;
2123
2124 resource->read_lock_fence->Wait();
2125}
2126
James Robinson646469d2014-10-03 15:33:28 -07002127GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) {
2128 GLint active_unit = 0;
2129 gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
2130 return active_unit;
2131}
2132
2133GLES2Interface* ResourceProvider::ContextGL() const {
2134 ContextProvider* context_provider = output_surface_->context_provider();
2135 return context_provider ? context_provider->ContextGL() : NULL;
2136}
2137
2138class GrContext* ResourceProvider::GrContext() const {
2139 ContextProvider* context_provider = output_surface_->context_provider();
2140 return context_provider ? context_provider->GrContext() : NULL;
2141}
2142
2143} // namespace cc