OLD | NEW |
| (Empty) |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "cc/resources/resource_provider.h" | |
6 | |
7 #include <algorithm> | |
8 #include <limits> | |
9 | |
10 #include "base/containers/hash_tables.h" | |
11 #include "base/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" | |
34 | |
35 using gpu::gles2::GLES2Interface; | |
36 | |
37 namespace cc { | |
38 | |
39 class 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 | |
60 namespace { | |
61 | |
62 // Measured in seconds. | |
63 const double kSoftwareUploadTickRate = 0.000250; | |
64 const double kTextureUploadTickRate = 0.004; | |
65 | |
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; | |
82 } | |
83 | |
84 return storage_format; | |
85 } | |
86 | |
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; | |
100 } | |
101 return false; | |
102 } | |
103 | |
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; | |
114 } | |
115 DCHECK(false) << "Unsupported resource format."; | |
116 return kSkia8888_GrPixelConfig; | |
117 } | |
118 | |
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; | |
132 } | |
133 NOTREACHED(); | |
134 return gfx::GpuMemoryBuffer::Format::RGBA_8888; | |
135 } | |
136 | |
137 class 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 | |
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_); | |
166 } | |
167 | |
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; | |
173 } | |
174 | |
175 return ids_[next_id_index_++]; | |
176 } | |
177 | |
178 private: | |
179 DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator); | |
180 }; | |
181 | |
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_); | |
189 } | |
190 | |
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; | |
196 } | |
197 | |
198 return ids_[next_id_index_++]; | |
199 } | |
200 | |
201 private: | |
202 DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator); | |
203 }; | |
204 | |
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) {} | |
211 | |
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; | |
220 | |
221 ProcessResult(); | |
222 return true; | |
223 } | |
224 void Wait() override { | |
225 // ProcessResult() will wait for result to become available. | |
226 ProcessResult(); | |
227 } | |
228 | |
229 private: | |
230 ~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 } | |
238 | |
239 gpu::gles2::GLES2Interface* gl_; | |
240 unsigned query_id_; | |
241 | |
242 DISALLOW_COPY_AND_ASSIGN(CopyTextureFence); | |
243 }; | |
244 | |
245 } // namespace | |
246 | |
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) { | |
282 } | |
283 | |
284 ResourceProvider::Resource::~Resource() {} | |
285 | |
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); | |
331 } | |
332 | |
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(); | |
377 } | |
378 | |
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); | |
420 } | |
421 | |
422 ResourceProvider::Child::Child() : marked_for_deletion(false) {} | |
423 | |
424 ResourceProvider::Child::~Child() {} | |
425 | |
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)); | |
442 | |
443 if (resource_provider->ContextGL()) | |
444 resource_provider->InitializeGL(); | |
445 else | |
446 resource_provider->InitializeSoftware(); | |
447 | |
448 DCHECK_NE(RESOURCE_TYPE_INVALID, resource_provider->default_resource_type()); | |
449 return resource_provider.Pass(); | |
450 } | |
451 | |
452 ResourceProvider::~ResourceProvider() { | |
453 while (!children_.empty()) | |
454 DestroyChildInternal(children_.begin(), FOR_SHUTDOWN); | |
455 while (!resources_.empty()) | |
456 DeleteResourceInternal(resources_.begin(), FOR_SHUTDOWN); | |
457 | |
458 CleanUpGLIfNeeded(); | |
459 } | |
460 | |
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; | |
465 } | |
466 | |
467 bool ResourceProvider::IsLost(ResourceId id) { | |
468 Resource* resource = GetResource(id); | |
469 return resource->lost; | |
470 } | |
471 | |
472 bool ResourceProvider::AllowOverlay(ResourceId id) { | |
473 Resource* resource = GetResource(id); | |
474 return resource->allow_overlay; | |
475 } | |
476 | |
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; | |
496 } | |
497 | |
498 LOG(FATAL) << "Invalid default resource type."; | |
499 return 0; | |
500 } | |
501 | |
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; | |
522 } | |
523 | |
524 LOG(FATAL) << "Invalid default resource type."; | |
525 return 0; | |
526 } | |
527 | |
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()); | |
538 | |
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; | |
545 } | |
546 | |
547 ResourceProvider::ResourceId ResourceProvider::CreateBitmap( | |
548 const gfx::Size& size, GLint wrap_mode) { | |
549 DCHECK(thread_checker_.CalledOnValidThread()); | |
550 | |
551 scoped_ptr<SharedBitmap> bitmap = | |
552 shared_bitmap_manager_->AllocateSharedBitmap(size); | |
553 uint8_t* pixels = bitmap->pixels(); | |
554 DCHECK(pixels); | |
555 | |
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; | |
562 } | |
563 | |
564 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromIOSurface( | |
565 const gfx::Size& size, | |
566 unsigned io_surface_id) { | |
567 DCHECK(thread_checker_.CalledOnValidThread()); | |
568 | |
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; | |
583 } | |
584 | |
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); | |
604 } | |
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; | |
612 } | |
613 | |
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); | |
622 | |
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); | |
628 } | |
629 } | |
630 | |
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; | |
636 | |
637 DCHECK(resource->exported_count == 0 || style != NORMAL); | |
638 if (style == FOR_SHUTDOWN && resource->exported_count > 0) | |
639 lost_resource = true; | |
640 | |
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)); | |
646 } | |
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)); | |
652 } | |
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)); | |
658 } | |
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)); | |
664 } | |
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(); | |
678 } | |
679 } else { | |
680 DCHECK(resource->mailbox.IsSharedMemory()); | |
681 resource->shared_bitmap = nullptr; | |
682 resource->pixels = nullptr; | |
683 } | |
684 resource->release_callback_impl.Run( | |
685 sync_point, lost_resource, blocking_main_thread_task_runner_); | |
686 } | |
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; | |
692 } | |
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; | |
698 } | |
699 if (resource->pixels) { | |
700 DCHECK(resource->origin == Resource::INTERNAL); | |
701 delete[] resource->pixels; | |
702 resource->pixels = NULL; | |
703 } | |
704 if (resource->gpu_memory_buffer) { | |
705 DCHECK(resource->origin == Resource::INTERNAL); | |
706 delete resource->gpu_memory_buffer; | |
707 resource->gpu_memory_buffer = NULL; | |
708 } | |
709 resources_.erase(it); | |
710 } | |
711 | |
712 ResourceProvider::ResourceType ResourceProvider::GetResourceType( | |
713 ResourceId id) { | |
714 return GetResource(id)->type; | |
715 } | |
716 | |
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); | |
729 | |
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; | |
757 | |
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()); | |
762 } | |
763 } | |
764 | |
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); | |
775 | |
776 DCHECK_EQ(image_size.width(), resource->size.width()); | |
777 DCHECK_EQ(image_size.height(), resource->size.height()); | |
778 | |
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; | |
786 | |
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); | |
798 | |
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); | |
809 } | |
810 } | |
811 } | |
812 | |
813 size_t ResourceProvider::NumBlockingUploads() { | |
814 if (!texture_uploader_) | |
815 return 0; | |
816 | |
817 return texture_uploader_->NumBlockingUploads(); | |
818 } | |
819 | |
820 void ResourceProvider::MarkPendingUploadsAsNonBlocking() { | |
821 if (!texture_uploader_) | |
822 return; | |
823 | |
824 texture_uploader_->MarkPendingUploadsAsNonBlocking(); | |
825 } | |
826 | |
827 size_t ResourceProvider::EstimatedUploadsPerTick() { | |
828 if (!texture_uploader_) | |
829 return 1u; | |
830 | |
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; | |
835 } | |
836 | |
837 void ResourceProvider::FlushUploads() { | |
838 if (!texture_uploader_) | |
839 return; | |
840 | |
841 texture_uploader_->Flush(); | |
842 } | |
843 | |
844 void ResourceProvider::ReleaseCachedData() { | |
845 if (!texture_uploader_) | |
846 return; | |
847 | |
848 texture_uploader_->ReleaseCachedQueries(); | |
849 } | |
850 | |
851 base::TimeTicks ResourceProvider::EstimatedUploadCompletionTime( | |
852 size_t uploads_per_tick) { | |
853 if (lost_output_surface_) | |
854 return base::TimeTicks(); | |
855 | |
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); | |
861 } | |
862 | |
863 base::TimeDelta upload_one_texture_time = | |
864 base::TimeDelta::FromMicroseconds( | |
865 base::Time::kMicrosecondsPerSecond * kTextureUploadTickRate) / | |
866 uploads_per_tick; | |
867 | |
868 size_t total_uploads = NumBlockingUploads() + uploads_per_tick; | |
869 return gfx::FrameTime::Now() + upload_one_texture_time * total_uploads; | |
870 } | |
871 | |
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; | |
877 } | |
878 | |
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); | |
888 | |
889 LazyCreate(resource); | |
890 | |
891 if (resource->type == RESOURCE_TYPE_GL_TEXTURE && !resource->gl_id) { | |
892 DCHECK(resource->origin != Resource::INTERNAL); | |
893 DCHECK(resource->mailbox.IsTexture()); | |
894 | |
895 // Mailbox sync_points must be processed by a call to | |
896 // WaitSyncPointIfNeeded() prior to calling LockForRead(). | |
897 DCHECK(!resource->mailbox.sync_point()); | |
898 | |
899 GLES2Interface* gl = ContextGL(); | |
900 DCHECK(gl); | |
901 resource->gl_id = | |
902 GLC(gl, gl->CreateAndConsumeTextureCHROMIUM(resource->mailbox.target(), | |
903 resource->mailbox.name())); | |
904 } | |
905 | |
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(); | |
914 } | |
915 } | |
916 | |
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_; | |
922 } | |
923 | |
924 return resource; | |
925 } | |
926 | |
927 void ResourceProvider::UnlockForRead(ResourceId id) { | |
928 DCHECK(thread_checker_.CalledOnValidThread()); | |
929 ResourceMap::iterator it = resources_.find(id); | |
930 CHECK(it != resources_.end()); | |
931 | |
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); | |
945 } | |
946 } | |
947 } | |
948 | |
949 ResourceProvider::Resource* ResourceProvider::LockForWrite(ResourceId id) { | |
950 Resource* resource = GetResource(id); | |
951 DCHECK(CanLockForWrite(id)); | |
952 | |
953 resource->locked_for_write = true; | |
954 return resource; | |
955 } | |
956 | |
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); | |
962 } | |
963 | |
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; | |
969 } | |
970 | |
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_); | |
978 } | |
979 | |
980 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() { | |
981 resource_provider_->UnlockForRead(resource_id_); | |
982 } | |
983 | |
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)) { | |
991 } | |
992 | |
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)) { | |
1001 } | |
1002 | |
1003 ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() { | |
1004 } | |
1005 | |
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_); | |
1014 } | |
1015 | |
1016 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() { | |
1017 resource_provider_->UnlockForWrite(resource_); | |
1018 } | |
1019 | |
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()); | |
1026 } | |
1027 | |
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); | |
1036 } | |
1037 | |
1038 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() { | |
1039 resource_provider_->UnlockForRead(resource_id_); | |
1040 } | |
1041 | |
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()); | |
1049 } | |
1050 | |
1051 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() { | |
1052 DCHECK(thread_checker_.CalledOnValidThread()); | |
1053 resource_provider_->UnlockForWrite(resource_); | |
1054 } | |
1055 | |
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); | |
1067 } | |
1068 | |
1069 ResourceProvider::ScopedWriteLockGpuMemoryBuffer:: | |
1070 ~ScopedWriteLockGpuMemoryBuffer() { | |
1071 DCHECK(thread_checker_.CalledOnValidThread()); | |
1072 resource_provider_->UnlockForWrite(resource_); | |
1073 if (!gpu_memory_buffer_) | |
1074 return; | |
1075 | |
1076 if (!resource_->image_id) { | |
1077 GLES2Interface* gl = resource_provider_->ContextGL(); | |
1078 DCHECK(gl); | |
1079 | |
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 | |
1086 | |
1087 resource_->image_id = | |
1088 gl->CreateImageCHROMIUM(gpu_memory_buffer_->AsClientBuffer(), | |
1089 size_.width(), | |
1090 size_.height(), | |
1091 GL_RGBA); | |
1092 } | |
1093 | |
1094 std::swap(resource_->gpu_memory_buffer, gpu_memory_buffer_); | |
1095 resource_->allocated = true; | |
1096 resource_->dirty_image = true; | |
1097 | |
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; | |
1102 } | |
1103 | |
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(); | |
1111 } | |
1112 | |
1113 return gpu_memory_buffer_; | |
1114 } | |
1115 | |
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_); | |
1123 } | |
1124 | |
1125 ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() { | |
1126 DCHECK(thread_checker_.CalledOnValidThread()); | |
1127 DCHECK(resource_->locked_for_write); | |
1128 resource_provider_->UnlockForWrite(resource_); | |
1129 } | |
1130 | |
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); | |
1137 | |
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; | |
1146 | |
1147 class GrContext* gr_context = | |
1148 resource_provider_->GrContext(use_worker_context); | |
1149 skia::RefPtr<GrTexture> gr_texture = | |
1150 skia::AdoptRef(gr_context->textureProvider()->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); | |
1161 } | |
1162 sk_surface_ = skia::AdoptRef(SkSurface::NewRenderTargetDirect( | |
1163 gr_texture->asRenderTarget(), &surface_props)); | |
1164 return; | |
1165 } | |
1166 sk_surface_.clear(); | |
1167 } | |
1168 | |
1169 void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() { | |
1170 sk_surface_.clear(); | |
1171 } | |
1172 | |
1173 ResourceProvider::SynchronousFence::SynchronousFence( | |
1174 gpu::gles2::GLES2Interface* gl) | |
1175 : gl_(gl), has_synchronized_(true) { | |
1176 } | |
1177 | |
1178 ResourceProvider::SynchronousFence::~SynchronousFence() { | |
1179 } | |
1180 | |
1181 void ResourceProvider::SynchronousFence::Set() { | |
1182 has_synchronized_ = false; | |
1183 } | |
1184 | |
1185 bool ResourceProvider::SynchronousFence::HasPassed() { | |
1186 if (!has_synchronized_) { | |
1187 has_synchronized_ = true; | |
1188 Synchronize(); | |
1189 } | |
1190 return true; | |
1191 } | |
1192 | |
1193 void ResourceProvider::SynchronousFence::Wait() { | |
1194 HasPassed(); | |
1195 } | |
1196 | |
1197 void ResourceProvider::SynchronousFence::Synchronize() { | |
1198 TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize"); | |
1199 gl_->Finish(); | |
1200 } | |
1201 | |
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_); | |
1231 } | |
1232 | |
1233 void ResourceProvider::InitializeSoftware() { | |
1234 DCHECK(thread_checker_.CalledOnValidThread()); | |
1235 DCHECK_NE(RESOURCE_TYPE_BITMAP, default_resource_type_); | |
1236 | |
1237 CleanUpGLIfNeeded(); | |
1238 | |
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; | |
1243 } | |
1244 | |
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_); | |
1251 | |
1252 default_resource_type_ = RESOURCE_TYPE_GL_TEXTURE; | |
1253 | |
1254 const ContextProvider::Capabilities& caps = | |
1255 output_surface_->context_provider()->ContextCapabilities(); | |
1256 | |
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; | |
1264 | |
1265 GLES2Interface* gl = ContextGL(); | |
1266 DCHECK(gl); | |
1267 | |
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); | |
1272 | |
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_)); | |
1277 } | |
1278 | |
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; | |
1286 } | |
1287 | |
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); | |
1295 } | |
1296 #endif // DCHECK_IS_ON() | |
1297 | |
1298 texture_uploader_ = nullptr; | |
1299 texture_id_allocator_ = nullptr; | |
1300 buffer_id_allocator_ = nullptr; | |
1301 gl->Finish(); | |
1302 } | |
1303 | |
1304 int ResourceProvider::CreateChild(const ReturnCallback& return_callback) { | |
1305 DCHECK(thread_checker_.CalledOnValidThread()); | |
1306 | |
1307 Child child_info; | |
1308 child_info.return_callback = return_callback; | |
1309 | |
1310 int child = next_child_++; | |
1311 children_[child] = child_info; | |
1312 return child; | |
1313 } | |
1314 | |
1315 void ResourceProvider::DestroyChild(int child_id) { | |
1316 ChildMap::iterator it = children_.find(child_id); | |
1317 DCHECK(it != children_.end()); | |
1318 DestroyChildInternal(it, NORMAL); | |
1319 } | |
1320 | |
1321 void ResourceProvider::DestroyChildInternal(ChildMap::iterator it, | |
1322 DeleteStyle style) { | |
1323 DCHECK(thread_checker_.CalledOnValidThread()); | |
1324 | |
1325 Child& child = it->second; | |
1326 DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion); | |
1327 | |
1328 ResourceIdArray resources_for_child; | |
1329 | |
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); | |
1335 } | |
1336 | |
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; | |
1340 | |
1341 DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child); | |
1342 } | |
1343 | |
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; | |
1351 } | |
1352 | |
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); | |
1367 } | |
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; | |
1375 } | |
1376 } | |
1377 } | |
1378 | |
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; | |
1395 } | |
1396 | |
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; | |
1405 } | |
1406 | |
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); | |
1421 } | |
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; | |
1429 } | |
1430 } | |
1431 | |
1432 void ResourceProvider::DeclareUsedResourcesFromChild( | |
1433 int child, | |
1434 const ResourceIdArray& resources_from_child) { | |
1435 DCHECK(thread_checker_.CalledOnValidThread()); | |
1436 | |
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(); | |
1442 | |
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()); | |
1447 | |
1448 ResourceId local_id = it->second; | |
1449 DCHECK(!resources_[local_id].marked_for_deletion); | |
1450 child_info.in_use_resources.insert(local_id); | |
1451 } | |
1452 | |
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); | |
1461 } | |
1462 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused); | |
1463 } | |
1464 | |
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; | |
1474 } | |
1475 | |
1476 void ResourceProvider::ReceiveReturnsFromParent( | |
1477 const ReturnedResourceArray& resources) { | |
1478 DCHECK(thread_checker_.CalledOnValidThread()); | |
1479 GLES2Interface* gl = ContextGL(); | |
1480 | |
1481 int child_id = 0; | |
1482 ResourceIdArray resources_for_child; | |
1483 | |
1484 std::vector<std::pair<ReturnedResource, ResourceMap::iterator>> | |
1485 sorted_resources; | |
1486 | |
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); | |
1492 | |
1493 // Resource was already lost (e.g. it belonged to a child that was | |
1494 // destroyed). | |
1495 if (map_iterator == resources_.end()) | |
1496 continue; | |
1497 | |
1498 sorted_resources.push_back( | |
1499 std::pair<ReturnedResource, ResourceMap::iterator>(*it, map_iterator)); | |
1500 } | |
1501 | |
1502 std::sort(sorted_resources.begin(), | |
1503 sorted_resources.end(), | |
1504 CompareResourceMapIteratorsByChildId); | |
1505 | |
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; | |
1512 | |
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; | |
1518 | |
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_; | |
1525 } | |
1526 | |
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); | |
1535 } | |
1536 } | |
1537 | |
1538 if (!resource->marked_for_deletion) | |
1539 continue; | |
1540 | |
1541 if (!resource->child_id) { | |
1542 // The resource belongs to this ResourceProvider, so it can be destroyed. | |
1543 DeleteResourceInternal(map_iterator, NORMAL); | |
1544 continue; | |
1545 } | |
1546 | |
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(); | |
1556 } | |
1557 | |
1558 child_it = children_.find(resource->child_id); | |
1559 DCHECK(child_it != children_.end()); | |
1560 child_id = resource->child_id; | |
1561 } | |
1562 resources_for_child.push_back(local_id); | |
1563 } | |
1564 | |
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); | |
1570 } | |
1571 } | |
1572 | |
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; | |
1588 | |
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); | |
1599 } | |
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)); | |
1606 | |
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); | |
1617 } | |
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); | |
1624 } | |
1625 } | |
1626 | |
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; | |
1634 | |
1635 if (unused.empty() && !child_info->marked_for_deletion) | |
1636 return; | |
1637 | |
1638 ReturnedResourceArray to_return; | |
1639 | |
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]; | |
1644 | |
1645 ResourceMap::iterator it = resources_.find(local_id); | |
1646 CHECK(it != resources_.end()); | |
1647 Resource& resource = it->second; | |
1648 | |
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)); | |
1652 | |
1653 ResourceId child_id = child_info->parent_to_child_map[local_id]; | |
1654 DCHECK(child_info->child_to_parent_map.count(child_id)); | |
1655 | |
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; | |
1665 } | |
1666 | |
1667 // We still have an exported_count, so we'll have to lose it. | |
1668 is_lost = true; | |
1669 } | |
1670 | |
1671 if (gl && resource.filter != resource.original_filter) { | |
1672 DCHECK(resource.target); | |
1673 DCHECK(resource.gl_id); | |
1674 | |
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)); | |
1684 } | |
1685 | |
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); | |
1694 | |
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); | |
1699 } | |
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; | |
1706 } | |
1707 } | |
1708 | |
1709 if (!to_return.empty()) | |
1710 child_info->return_callback.Run(to_return, | |
1711 blocking_main_thread_task_runner_); | |
1712 | |
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); | |
1717 } | |
1718 } | |
1719 | |
1720 void ResourceProvider::AcquirePixelBuffer(ResourceId id) { | |
1721 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
1722 "ResourceProvider::AcquirePixelBuffer"); | |
1723 | |
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); | |
1729 | |
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); | |
1744 } | |
1745 | |
1746 void ResourceProvider::ReleasePixelBuffer(ResourceId id) { | |
1747 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
1748 "ResourceProvider::ReleasePixelBuffer"); | |
1749 | |
1750 Resource* resource = GetResource(id); | |
1751 DCHECK(resource->origin == Resource::INTERNAL); | |
1752 DCHECK_EQ(resource->exported_count, 0); | |
1753 DCHECK(!resource->image_id); | |
1754 | |
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; | |
1765 } | |
1766 | |
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); | |
1777 } | |
1778 | |
1779 uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id, int* stride) { | |
1780 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
1781 "ResourceProvider::MapPixelBuffer"); | |
1782 | |
1783 Resource* resource = GetResource(id); | |
1784 DCHECK(resource->origin == Resource::INTERNAL); | |
1785 DCHECK_EQ(resource->exported_count, 0); | |
1786 DCHECK(!resource->image_id); | |
1787 | |
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; | |
1801 } | |
1802 | |
1803 void ResourceProvider::UnmapPixelBuffer(ResourceId id) { | |
1804 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
1805 "ResourceProvider::UnmapPixelBuffer"); | |
1806 | |
1807 Resource* resource = GetResource(id); | |
1808 DCHECK(resource->origin == Resource::INTERNAL); | |
1809 DCHECK_EQ(resource->exported_count, 0); | |
1810 DCHECK(!resource->image_id); | |
1811 | |
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); | |
1820 } | |
1821 | |
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); | |
1832 | |
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; | |
1840 } | |
1841 | |
1842 if (resource->image_id && resource->dirty_image) | |
1843 BindImageForSampling(resource); | |
1844 | |
1845 return target; | |
1846 } | |
1847 | |
1848 void ResourceProvider::BeginSetPixels(ResourceId id) { | |
1849 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
1850 "ResourceProvider::BeginSetPixels"); | |
1851 | |
1852 Resource* resource = GetResource(id); | |
1853 DCHECK(!resource->pending_set_pixels); | |
1854 | |
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); | |
1860 | |
1861 bool allocate = !resource->allocated; | |
1862 resource->allocated = true; | |
1863 LockForWrite(id); | |
1864 | |
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); | |
1898 } | |
1899 gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM); | |
1900 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); | |
1901 | |
1902 resource->pending_set_pixels = true; | |
1903 resource->set_pixels_completion_forced = false; | |
1904 } | |
1905 | |
1906 void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) { | |
1907 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
1908 "ResourceProvider::ForceSetPixelsToComplete"); | |
1909 | |
1910 Resource* resource = GetResource(id); | |
1911 | |
1912 DCHECK(resource->locked_for_write); | |
1913 DCHECK(resource->pending_set_pixels); | |
1914 DCHECK(!resource->set_pixels_completion_forced); | |
1915 | |
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)); | |
1921 } | |
1922 | |
1923 resource->set_pixels_completion_forced = true; | |
1924 } | |
1925 | |
1926 bool ResourceProvider::DidSetPixelsComplete(ResourceId id) { | |
1927 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
1928 "ResourceProvider::DidSetPixelsComplete"); | |
1929 | |
1930 Resource* resource = GetResource(id); | |
1931 | |
1932 DCHECK(resource->locked_for_write); | |
1933 DCHECK(resource->pending_set_pixels); | |
1934 | |
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; | |
1944 } | |
1945 | |
1946 resource->pending_set_pixels = false; | |
1947 UnlockForWrite(resource); | |
1948 | |
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; | |
1953 | |
1954 return true; | |
1955 } | |
1956 | |
1957 void ResourceProvider::CreateForTesting(ResourceId id) { | |
1958 LazyCreate(GetResource(id)); | |
1959 } | |
1960 | |
1961 GLenum ResourceProvider::TargetForTesting(ResourceId id) { | |
1962 Resource* resource = GetResource(id); | |
1963 return resource->target; | |
1964 } | |
1965 | |
1966 void ResourceProvider::LazyCreate(Resource* resource) { | |
1967 if (resource->type != RESOURCE_TYPE_GL_TEXTURE || | |
1968 resource->origin != Resource::INTERNAL) | |
1969 return; | |
1970 | |
1971 if (resource->gl_id) | |
1972 return; | |
1973 | |
1974 DCHECK(resource->texture_pool); | |
1975 DCHECK(resource->origin == Resource::INTERNAL); | |
1976 DCHECK(!resource->mailbox.IsValid()); | |
1977 resource->gl_id = texture_id_allocator_->NextId(); | |
1978 | |
1979 GLES2Interface* gl = ContextGL(); | |
1980 DCHECK(gl); | |
1981 | |
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)); | |
2004 } | |
2005 } | |
2006 | |
2007 void ResourceProvider::AllocateForTesting(ResourceId id) { | |
2008 LazyAllocate(GetResource(id)); | |
2009 } | |
2010 | |
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, | |
2036 0, | |
2037 GLInternalFormat(format), | |
2038 size.width(), | |
2039 size.height(), | |
2040 0, | |
2041 GLDataFormat(format), | |
2042 GLDataType(format), | |
2043 NULL)); | |
2044 } | |
2045 } | |
2046 } | |
2047 | |
2048 void ResourceProvider::BindImageForSampling(Resource* resource) { | |
2049 GLES2Interface* gl = ContextGL(); | |
2050 DCHECK(resource->gl_id); | |
2051 DCHECK(resource->image_id); | |
2052 | |
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; | |
2059 } | |
2060 | |
2061 void ResourceProvider::CopyResource(ResourceId source_id, ResourceId dest_id) { | |
2062 TRACE_EVENT0("cc", "ResourceProvider::CopyResource"); | |
2063 | |
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); | |
2071 | |
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); | |
2079 | |
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); | |
2083 | |
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); | |
2089 } | |
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 | |
2103 } | |
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(); | |
2127 } | |
2128 } | |
2129 | |
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); | |
2143 } | |
2144 | |
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; | |
2150 | |
2151 resource->read_lock_fence->Wait(); | |
2152 } | |
2153 | |
2154 GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) { | |
2155 GLint active_unit = 0; | |
2156 gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit); | |
2157 return active_unit; | |
2158 } | |
2159 | |
2160 GLES2Interface* ResourceProvider::ContextGL() const { | |
2161 ContextProvider* context_provider = output_surface_->context_provider(); | |
2162 return context_provider ? context_provider->ContextGL() : NULL; | |
2163 } | |
2164 | |
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; | |
2170 } | |
2171 | |
2172 } // namespace cc | |
OLD | NEW |