FileSystem mods: Changes to snapshot file creation to remove dependencies on blobs.
[chromium-blink-merge.git] / cc / resource_provider.cc
blobd3940622ee46e643a781449bbfb6112538fb76ca
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/resource_provider.h"
7 #include <limits.h>
9 #include "base/debug/alias.h"
10 #include "base/hash_tables.h"
11 #include "base/stl_util.h"
12 #include "base/string_split.h"
13 #include "base/string_util.h"
14 #include "cc/gl_renderer.h" // For the GLC() macro.
15 #include "cc/platform_color.h"
16 #include "cc/texture_uploader.h"
17 #include "cc/transferable_resource.h"
18 #include "gpu/GLES2/gl2extchromium.h"
19 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
20 #include "third_party/khronos/GLES2/gl2.h"
21 #include "third_party/khronos/GLES2/gl2ext.h"
22 #include "ui/gfx/rect.h"
23 #include "ui/gfx/vector2d.h"
25 using WebKit::WebGraphicsContext3D;
27 namespace cc {
29 static GLenum textureToStorageFormat(GLenum textureFormat)
31 GLenum storageFormat = GL_RGBA8_OES;
32 switch (textureFormat) {
33 case GL_RGBA:
34 break;
35 case GL_BGRA_EXT:
36 storageFormat = GL_BGRA8_EXT;
37 break;
38 default:
39 NOTREACHED();
40 break;
43 return storageFormat;
46 static bool isTextureFormatSupportedForStorage(GLenum format)
48 return (format == GL_RGBA || format == GL_BGRA_EXT);
51 static unsigned createTextureId(WebGraphicsContext3D* context3d)
53 unsigned textureId = 0;
54 GLC(context3d, textureId = context3d->createTexture());
55 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, textureId));
56 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
57 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
58 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
59 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
60 return textureId;
63 ResourceProvider::Resource::Resource()
64 : glId(0)
65 , glPixelBufferId(0)
66 , glUploadQueryId(0)
67 , pixels(0)
68 , pixelBuffer(0)
69 , lockForReadCount(0)
70 , lockedForWrite(false)
71 , external(false)
72 , exported(false)
73 , markedForDeletion(false)
74 , pendingSetPixels(false)
75 , allocated(false)
76 , enableReadLockFences(false)
77 , readLockFence(NULL)
78 , size()
79 , format(0)
80 , filter(0)
81 , type(static_cast<ResourceType>(0))
85 ResourceProvider::Resource::~Resource()
89 ResourceProvider::Resource::Resource(unsigned textureId, const gfx::Size& size, GLenum format, GLenum filter)
90 : glId(textureId)
91 , glPixelBufferId(0)
92 , glUploadQueryId(0)
93 , pixels(0)
94 , pixelBuffer(0)
95 , lockForReadCount(0)
96 , lockedForWrite(false)
97 , external(false)
98 , exported(false)
99 , markedForDeletion(false)
100 , pendingSetPixels(false)
101 , allocated(false)
102 , enableReadLockFences(false)
103 , readLockFence(NULL)
104 , size(size)
105 , format(format)
106 , filter(filter)
107 , type(GLTexture)
111 ResourceProvider::Resource::Resource(uint8_t* pixels, const gfx::Size& size, GLenum format, GLenum filter)
112 : glId(0)
113 , glPixelBufferId(0)
114 , glUploadQueryId(0)
115 , pixels(pixels)
116 , pixelBuffer(0)
117 , lockForReadCount(0)
118 , lockedForWrite(false)
119 , external(false)
120 , exported(false)
121 , markedForDeletion(false)
122 , pendingSetPixels(false)
123 , allocated(false)
124 , enableReadLockFences(false)
125 , readLockFence(NULL)
126 , size(size)
127 , format(format)
128 , filter(filter)
129 , type(Bitmap)
133 ResourceProvider::Child::Child()
137 ResourceProvider::Child::~Child()
141 scoped_ptr<ResourceProvider> ResourceProvider::create(OutputSurface* context)
143 scoped_ptr<ResourceProvider> resourceProvider(new ResourceProvider(context));
144 if (!resourceProvider->initialize())
145 return scoped_ptr<ResourceProvider>();
146 return resourceProvider.Pass();
149 ResourceProvider::~ResourceProvider()
151 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
152 if (!context3d || !context3d->makeContextCurrent())
153 return;
154 m_textureUploader.reset();
155 m_textureCopier.reset();
158 WebGraphicsContext3D* ResourceProvider::graphicsContext3D()
160 DCHECK(m_threadChecker.CalledOnValidThread());
161 return m_outputSurface->context3d();
164 bool ResourceProvider::inUseByConsumer(ResourceId id)
166 DCHECK(m_threadChecker.CalledOnValidThread());
167 ResourceMap::iterator it = m_resources.find(id);
168 CHECK(it != m_resources.end());
169 Resource* resource = &it->second;
170 return !!resource->lockForReadCount || resource->exported;
173 ResourceProvider::ResourceId ResourceProvider::createResource(const gfx::Size& size, GLenum format, TextureUsageHint hint)
175 switch (m_defaultResourceType) {
176 case GLTexture:
177 return createGLTexture(size, format, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, hint);
178 case Bitmap:
179 DCHECK(format == GL_RGBA);
180 return createBitmap(size);
183 LOG(FATAL) << "Invalid default resource type.";
184 return 0;
187 ResourceProvider::ResourceId ResourceProvider::createManagedResource(const gfx::Size& size, GLenum format, TextureUsageHint hint)
189 switch (m_defaultResourceType) {
190 case GLTexture:
191 return createGLTexture(size, format, GL_TEXTURE_POOL_MANAGED_CHROMIUM, hint);
192 case Bitmap:
193 DCHECK(format == GL_RGBA);
194 return createBitmap(size);
197 LOG(FATAL) << "Invalid default resource type.";
198 return 0;
201 ResourceProvider::ResourceId ResourceProvider::createGLTexture(const gfx::Size& size, GLenum format, GLenum texturePool, TextureUsageHint hint)
203 DCHECK_LE(size.width(), m_maxTextureSize);
204 DCHECK_LE(size.height(), m_maxTextureSize);
206 DCHECK(m_threadChecker.CalledOnValidThread());
207 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
208 DCHECK(context3d);
210 // Create and set texture properties. Allocation is delayed until needed.
211 unsigned textureId = createTextureId(context3d);
212 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_POOL_CHROMIUM, texturePool));
213 if (m_useTextureUsageHint && hint == TextureUsageFramebuffer)
214 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE));
216 ResourceId id = m_nextId++;
217 Resource resource(textureId, size, format, GL_LINEAR);
218 resource.allocated = false;
219 m_resources[id] = resource;
220 return id;
223 ResourceProvider::ResourceId ResourceProvider::createBitmap(const gfx::Size& size)
225 DCHECK(m_threadChecker.CalledOnValidThread());
227 uint8_t* pixels = new uint8_t[size.width() * size.height() * 4];
229 ResourceId id = m_nextId++;
230 Resource resource(pixels, size, GL_RGBA, GL_LINEAR);
231 resource.allocated = true;
232 m_resources[id] = resource;
233 return id;
236 ResourceProvider::ResourceId ResourceProvider::createResourceFromExternalTexture(unsigned textureId)
238 DCHECK(m_threadChecker.CalledOnValidThread());
240 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
241 DCHECK(context3d);
242 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, textureId));
243 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
244 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
245 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
246 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
248 ResourceId id = m_nextId++;
249 Resource resource(textureId, gfx::Size(), 0, GL_LINEAR);
250 resource.external = true;
251 resource.allocated = true;
252 m_resources[id] = resource;
253 return id;
256 ResourceProvider::ResourceId ResourceProvider::createResourceFromTextureMailbox(const TextureMailbox& mailbox)
258 DCHECK(m_threadChecker.CalledOnValidThread());
259 // Just store the information. Mailbox will be consumed in lockForRead().
260 ResourceId id = m_nextId++;
261 unsigned textureId = 0;
262 Resource resource(textureId, gfx::Size(), 0, GL_LINEAR);
263 resource.external = true;
264 resource.allocated = true;
265 resource.mailbox = mailbox;
266 m_resources[id] = resource;
267 return id;
270 void ResourceProvider::deleteResource(ResourceId id)
272 DCHECK(m_threadChecker.CalledOnValidThread());
273 ResourceMap::iterator it = m_resources.find(id);
274 CHECK(it != m_resources.end());
275 Resource* resource = &it->second;
276 DCHECK(!resource->lockForReadCount);
277 DCHECK(!resource->markedForDeletion);
278 DCHECK(resource->pendingSetPixels || !resource->lockedForWrite);
280 if (resource->exported) {
281 resource->markedForDeletion = true;
282 return;
283 } else
284 deleteResourceInternal(it);
287 void ResourceProvider::deleteResourceInternal(ResourceMap::iterator it)
289 Resource* resource = &it->second;
290 if (resource->glId && !resource->external) {
291 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
292 DCHECK(context3d);
293 GLC(context3d, context3d->deleteTexture(resource->glId));
295 if (resource->glUploadQueryId) {
296 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
297 DCHECK(context3d);
298 GLC(context3d, context3d->deleteQueryEXT(resource->glUploadQueryId));
300 if (resource->glPixelBufferId) {
301 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
302 DCHECK(context3d);
303 GLC(context3d, context3d->deleteBuffer(resource->glPixelBufferId));
305 if (!resource->mailbox.IsEmpty() && resource->external) {
306 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
307 DCHECK(context3d);
308 unsigned syncPoint = resource->mailbox.sync_point();
309 if (resource->glId) {
310 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, resource->glId));
311 GLC(context3d, context3d->produceTextureCHROMIUM(GL_TEXTURE_2D, resource->mailbox.data()));
312 GLC(context3d, context3d->deleteTexture(resource->glId));
313 syncPoint = context3d->insertSyncPoint();
315 resource->mailbox.RunReleaseCallback(syncPoint);
317 if (resource->pixels)
318 delete[] resource->pixels;
319 if (resource->pixelBuffer)
320 delete[] resource->pixelBuffer;
322 m_resources.erase(it);
325 ResourceProvider::ResourceType ResourceProvider::resourceType(ResourceId id)
327 ResourceMap::iterator it = m_resources.find(id);
328 CHECK(it != m_resources.end());
329 Resource* resource = &it->second;
330 return resource->type;
333 void ResourceProvider::setPixels(ResourceId id, const uint8_t* image, const gfx::Rect& imageRect, const gfx::Rect& sourceRect, const gfx::Vector2d& destOffset)
335 DCHECK(m_threadChecker.CalledOnValidThread());
336 ResourceMap::iterator it = m_resources.find(id);
337 CHECK(it != m_resources.end());
338 Resource* resource = &it->second;
339 DCHECK(!resource->lockedForWrite);
340 DCHECK(!resource->lockForReadCount);
341 DCHECK(!resource->external);
342 DCHECK(!resource->exported);
343 DCHECK(readLockFenceHasPassed(resource));
344 lazyAllocate(resource);
346 if (resource->glId) {
347 DCHECK(!resource->pendingSetPixels);
348 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
349 DCHECK(context3d);
350 DCHECK(m_textureUploader.get());
351 context3d->bindTexture(GL_TEXTURE_2D, resource->glId);
352 m_textureUploader->upload(image,
353 imageRect,
354 sourceRect,
355 destOffset,
356 resource->format,
357 resource->size);
360 if (resource->pixels) {
361 DCHECK(resource->allocated);
362 DCHECK(resource->format == GL_RGBA);
363 SkBitmap srcFull;
364 srcFull.setConfig(SkBitmap::kARGB_8888_Config, imageRect.width(), imageRect.height());
365 srcFull.setPixels(const_cast<uint8_t*>(image));
366 SkBitmap srcSubset;
367 SkIRect skSourceRect = SkIRect::MakeXYWH(sourceRect.x(), sourceRect.y(), sourceRect.width(), sourceRect.height());
368 skSourceRect.offset(-imageRect.x(), -imageRect.y());
369 srcFull.extractSubset(&srcSubset, skSourceRect);
371 ScopedWriteLockSoftware lock(this, id);
372 SkCanvas* dest = lock.skCanvas();
373 dest->writePixels(srcSubset, destOffset.x(), destOffset.y());
377 size_t ResourceProvider::numBlockingUploads()
379 if (!m_textureUploader)
380 return 0;
382 return m_textureUploader->numBlockingUploads();
385 void ResourceProvider::markPendingUploadsAsNonBlocking()
387 if (!m_textureUploader)
388 return;
390 m_textureUploader->markPendingUploadsAsNonBlocking();
393 double ResourceProvider::estimatedUploadsPerSecond()
395 if (!m_textureUploader)
396 return 0.0;
398 return m_textureUploader->estimatedTexturesPerSecond();
401 void ResourceProvider::flushUploads()
403 if (!m_textureUploader)
404 return;
406 m_textureUploader->flush();
409 void ResourceProvider::flush()
411 DCHECK(m_threadChecker.CalledOnValidThread());
412 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
413 if (context3d)
414 context3d->flush();
417 bool ResourceProvider::shallowFlushIfSupported()
419 DCHECK(m_threadChecker.CalledOnValidThread());
420 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
421 if (!context3d || !m_useShallowFlush)
422 return false;
424 context3d->shallowFlushCHROMIUM();
425 return true;
428 const ResourceProvider::Resource* ResourceProvider::lockForRead(ResourceId id)
430 DCHECK(m_threadChecker.CalledOnValidThread());
431 ResourceMap::iterator it = m_resources.find(id);
432 CHECK(it != m_resources.end());
433 Resource* resource = &it->second;
434 DCHECK(!resource->lockedForWrite);
435 DCHECK(!resource->exported);
436 DCHECK(resource->allocated); // Uninitialized! Call setPixels or lockForWrite first.
438 if (!resource->glId && resource->external && !resource->mailbox.IsEmpty()) {
439 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
440 DCHECK(context3d);
441 if (resource->mailbox.sync_point()) {
442 GLC(context3d, context3d->waitSyncPoint(resource->mailbox.sync_point()));
443 resource->mailbox.ResetSyncPoint();
445 resource->glId = context3d->createTexture();
446 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, resource->glId));
447 GLC(context3d, context3d->consumeTextureCHROMIUM(GL_TEXTURE_2D, resource->mailbox.data()));
450 resource->lockForReadCount++;
451 if (resource->enableReadLockFences)
452 resource->readLockFence = m_currentReadLockFence;
454 return resource;
457 void ResourceProvider::unlockForRead(ResourceId id)
459 DCHECK(m_threadChecker.CalledOnValidThread());
460 ResourceMap::iterator it = m_resources.find(id);
461 CHECK(it != m_resources.end());
462 Resource* resource = &it->second;
463 DCHECK(resource->lockForReadCount > 0);
464 DCHECK(!resource->exported);
465 resource->lockForReadCount--;
468 const ResourceProvider::Resource* ResourceProvider::lockForWrite(ResourceId id)
470 DCHECK(m_threadChecker.CalledOnValidThread());
471 ResourceMap::iterator it = m_resources.find(id);
472 CHECK(it != m_resources.end());
473 Resource* resource = &it->second;
474 DCHECK(!resource->lockedForWrite);
475 DCHECK(!resource->lockForReadCount);
476 DCHECK(!resource->exported);
477 DCHECK(!resource->external);
478 DCHECK(readLockFenceHasPassed(resource));
479 lazyAllocate(resource);
481 resource->lockedForWrite = true;
482 return resource;
485 bool ResourceProvider::canLockForWrite(ResourceId id)
487 DCHECK(m_threadChecker.CalledOnValidThread());
488 ResourceMap::iterator it = m_resources.find(id);
489 CHECK(it != m_resources.end());
490 Resource* resource = &it->second;
491 return !resource->lockedForWrite &&
492 !resource->lockForReadCount &&
493 !resource->exported &&
494 !resource->external &&
495 readLockFenceHasPassed(resource);
498 void ResourceProvider::unlockForWrite(ResourceId id)
500 DCHECK(m_threadChecker.CalledOnValidThread());
501 ResourceMap::iterator it = m_resources.find(id);
502 CHECK(it != m_resources.end());
503 Resource* resource = &it->second;
504 DCHECK(resource->lockedForWrite);
505 DCHECK(!resource->exported);
506 DCHECK(!resource->external);
507 resource->lockedForWrite = false;
510 ResourceProvider::ScopedReadLockGL::ScopedReadLockGL(ResourceProvider* resourceProvider, ResourceProvider::ResourceId resourceId)
511 : m_resourceProvider(resourceProvider)
512 , m_resourceId(resourceId)
513 , m_textureId(resourceProvider->lockForRead(resourceId)->glId)
515 DCHECK(m_textureId);
518 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL()
520 m_resourceProvider->unlockForRead(m_resourceId);
523 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(ResourceProvider* resourceProvider, ResourceProvider::ResourceId resourceId, GLenum target, GLenum filter)
524 : ScopedReadLockGL(resourceProvider, resourceId)
526 resourceProvider->bindForSampling(resourceId, target, filter);
529 ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(ResourceProvider* resourceProvider, ResourceProvider::ResourceId resourceId)
530 : m_resourceProvider(resourceProvider)
531 , m_resourceId(resourceId)
532 , m_textureId(resourceProvider->lockForWrite(resourceId)->glId)
534 DCHECK(m_textureId);
537 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL()
539 m_resourceProvider->unlockForWrite(m_resourceId);
542 void ResourceProvider::populateSkBitmapWithResource(SkBitmap* skBitmap, const Resource* resource)
544 DCHECK(resource->pixels);
545 DCHECK(resource->format == GL_RGBA);
546 skBitmap->setConfig(SkBitmap::kARGB_8888_Config, resource->size.width(), resource->size.height());
547 skBitmap->setPixels(resource->pixels);
550 ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(ResourceProvider* resourceProvider, ResourceProvider::ResourceId resourceId)
551 : m_resourceProvider(resourceProvider)
552 , m_resourceId(resourceId)
554 ResourceProvider::populateSkBitmapWithResource(&m_skBitmap, resourceProvider->lockForRead(resourceId));
557 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware()
559 m_resourceProvider->unlockForRead(m_resourceId);
562 ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(ResourceProvider* resourceProvider, ResourceProvider::ResourceId resourceId)
563 : m_resourceProvider(resourceProvider)
564 , m_resourceId(resourceId)
566 ResourceProvider::populateSkBitmapWithResource(&m_skBitmap, resourceProvider->lockForWrite(resourceId));
567 m_skCanvas.reset(new SkCanvas(m_skBitmap));
570 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware()
572 m_resourceProvider->unlockForWrite(m_resourceId);
575 ResourceProvider::ResourceProvider(OutputSurface* context)
576 : m_outputSurface(context)
577 , m_nextId(1)
578 , m_nextChild(1)
579 , m_defaultResourceType(GLTexture)
580 , m_useTextureStorageExt(false)
581 , m_useTextureUsageHint(false)
582 , m_useShallowFlush(false)
583 , m_maxTextureSize(0)
584 , m_bestTextureFormat(0)
588 bool ResourceProvider::initialize()
590 DCHECK(m_threadChecker.CalledOnValidThread());
591 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
592 if (!context3d) {
593 m_maxTextureSize = INT_MAX / 2;
594 m_bestTextureFormat = GL_RGBA;
595 return true;
597 if (!context3d->makeContextCurrent())
598 return false;
600 std::string extensionsString = UTF16ToASCII(context3d->getString(GL_EXTENSIONS));
601 std::vector<std::string> extensions;
602 base::SplitString(extensionsString, ' ', &extensions);
603 bool useMapSub = false;
604 bool useBindUniform = false;
605 bool useBGRA = false;
606 for (size_t i = 0; i < extensions.size(); ++i) {
607 if (extensions[i] == "GL_EXT_texture_storage")
608 m_useTextureStorageExt = true;
609 else if (extensions[i] == "GL_ANGLE_texture_usage")
610 m_useTextureUsageHint = true;
611 else if (extensions[i] == "GL_CHROMIUM_map_sub")
612 useMapSub = true;
613 else if (extensions[i] == "GL_CHROMIUM_shallow_flush")
614 m_useShallowFlush = true;
615 else if (extensions[i] == "GL_CHROMIUM_bind_uniform_location")
616 useBindUniform = true;
617 else if (extensions[i] == "GL_EXT_texture_format_BGRA8888")
618 useBGRA = true;
621 m_textureCopier = AcceleratedTextureCopier::create(context3d, useBindUniform);
623 m_textureUploader = TextureUploader::create(context3d, useMapSub, m_useShallowFlush);
624 GLC(context3d, context3d->getIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize));
625 m_bestTextureFormat = PlatformColor::bestTextureFormat(context3d, useBGRA);
626 return true;
629 int ResourceProvider::createChild()
631 DCHECK(m_threadChecker.CalledOnValidThread());
632 Child childInfo;
633 int child = m_nextChild++;
634 m_children[child] = childInfo;
635 return child;
638 void ResourceProvider::destroyChild(int child_id)
640 DCHECK(m_threadChecker.CalledOnValidThread());
641 ChildMap::iterator it = m_children.find(child_id);
642 DCHECK(it != m_children.end());
643 Child& child = it->second;
644 for (ResourceIdMap::iterator child_it = child.childToParentMap.begin(); child_it != child.childToParentMap.end(); ++child_it)
645 deleteResource(child_it->second);
646 m_children.erase(it);
649 const ResourceProvider::ResourceIdMap& ResourceProvider::getChildToParentMap(int child) const
651 DCHECK(m_threadChecker.CalledOnValidThread());
652 ChildMap::const_iterator it = m_children.find(child);
653 DCHECK(it != m_children.end());
654 return it->second.childToParentMap;
657 void ResourceProvider::prepareSendToParent(const ResourceIdArray& resources, TransferableResourceList* list)
659 DCHECK(m_threadChecker.CalledOnValidThread());
660 list->sync_point = 0;
661 list->resources.clear();
662 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
663 if (!context3d || !context3d->makeContextCurrent()) {
664 // FIXME: Implement this path for software compositing.
665 return;
667 for (ResourceIdArray::const_iterator it = resources.begin(); it != resources.end(); ++it) {
668 TransferableResource resource;
669 if (transferResource(context3d, *it, &resource)) {
670 m_resources.find(*it)->second.exported = true;
671 list->resources.push_back(resource);
674 if (list->resources.size())
675 list->sync_point = context3d->insertSyncPoint();
678 void ResourceProvider::prepareSendToChild(int child, const ResourceIdArray& resources, TransferableResourceList* list)
680 DCHECK(m_threadChecker.CalledOnValidThread());
681 list->sync_point = 0;
682 list->resources.clear();
683 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
684 if (!context3d || !context3d->makeContextCurrent()) {
685 // FIXME: Implement this path for software compositing.
686 return;
688 Child& childInfo = m_children.find(child)->second;
689 for (ResourceIdArray::const_iterator it = resources.begin(); it != resources.end(); ++it) {
690 TransferableResource resource;
691 if (!transferResource(context3d, *it, &resource))
692 NOTREACHED();
693 DCHECK(childInfo.parentToChildMap.find(*it) != childInfo.parentToChildMap.end());
694 resource.id = childInfo.parentToChildMap[*it];
695 childInfo.parentToChildMap.erase(*it);
696 childInfo.childToParentMap.erase(resource.id);
697 list->resources.push_back(resource);
698 deleteResource(*it);
700 if (list->resources.size())
701 list->sync_point = context3d->insertSyncPoint();
704 void ResourceProvider::receiveFromChild(int child, const TransferableResourceList& resources)
706 DCHECK(m_threadChecker.CalledOnValidThread());
707 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
708 if (!context3d || !context3d->makeContextCurrent()) {
709 // FIXME: Implement this path for software compositing.
710 return;
712 if (resources.sync_point) {
713 // NOTE: If the parent is a browser and the child a renderer, the parent
714 // is not supposed to have its context wait, because that could induce
715 // deadlocks and/or security issues. The caller is responsible for
716 // waiting asynchronously, and resetting sync_point before calling this.
717 // However if the parent is a renderer (e.g. browser tag), it may be ok
718 // (and is simpler) to wait.
719 GLC(context3d, context3d->waitSyncPoint(resources.sync_point));
721 Child& childInfo = m_children.find(child)->second;
722 for (TransferableResourceArray::const_iterator it = resources.resources.begin(); it != resources.resources.end(); ++it) {
723 unsigned textureId;
724 GLC(context3d, textureId = context3d->createTexture());
725 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, textureId));
726 GLC(context3d, context3d->consumeTextureCHROMIUM(GL_TEXTURE_2D, it->mailbox.name));
727 ResourceId id = m_nextId++;
728 Resource resource(textureId, it->size, it->format, it->filter);
729 resource.mailbox.SetName(it->mailbox);
730 // Don't allocate a texture for a child.
731 resource.allocated = true;
732 m_resources[id] = resource;
733 childInfo.parentToChildMap[id] = it->id;
734 childInfo.childToParentMap[it->id] = id;
738 void ResourceProvider::receiveFromParent(const TransferableResourceList& resources)
740 DCHECK(m_threadChecker.CalledOnValidThread());
741 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
742 if (!context3d || !context3d->makeContextCurrent()) {
743 // FIXME: Implement this path for software compositing.
744 return;
746 if (resources.sync_point)
747 GLC(context3d, context3d->waitSyncPoint(resources.sync_point));
748 for (TransferableResourceArray::const_iterator it = resources.resources.begin(); it != resources.resources.end(); ++it) {
749 ResourceMap::iterator mapIterator = m_resources.find(it->id);
750 DCHECK(mapIterator != m_resources.end());
751 Resource* resource = &mapIterator->second;
752 DCHECK(resource->exported);
753 resource->exported = false;
754 DCHECK(resource->mailbox.Equals(it->mailbox));
755 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, resource->glId));
756 GLC(context3d, context3d->consumeTextureCHROMIUM(GL_TEXTURE_2D, it->mailbox.name));
757 if (resource->markedForDeletion)
758 deleteResourceInternal(mapIterator);
762 bool ResourceProvider::transferResource(WebGraphicsContext3D* context, ResourceId id, TransferableResource* resource)
764 DCHECK(m_threadChecker.CalledOnValidThread());
765 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
766 ResourceMap::iterator it = m_resources.find(id);
767 CHECK(it != m_resources.end());
768 Resource* source = &it->second;
769 DCHECK(!source->lockedForWrite);
770 DCHECK(!source->lockForReadCount);
771 DCHECK(!source->external || (source->external && !source->mailbox.IsEmpty()));
772 DCHECK(source->allocated);
773 if (source->exported)
774 return false;
775 resource->id = id;
776 resource->format = source->format;
777 resource->filter = source->filter;
778 resource->size = source->size;
780 if (source->mailbox.IsEmpty()) {
781 GLC(context3d, context3d->genMailboxCHROMIUM(resource->mailbox.name));
782 source->mailbox.SetName(resource->mailbox);
783 } else
784 resource->mailbox = source->mailbox.name();
786 GLC(context, context->bindTexture(GL_TEXTURE_2D, source->glId));
787 GLC(context, context->produceTextureCHROMIUM(GL_TEXTURE_2D, resource->mailbox.name));
788 return true;
791 void ResourceProvider::acquirePixelBuffer(ResourceId id)
793 DCHECK(m_threadChecker.CalledOnValidThread());
794 ResourceMap::iterator it = m_resources.find(id);
795 CHECK(it != m_resources.end());
796 Resource* resource = &it->second;
797 DCHECK(!resource->external);
798 DCHECK(!resource->exported);
800 if (resource->glId) {
801 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
802 DCHECK(context3d);
803 if (!resource->glPixelBufferId)
804 resource->glPixelBufferId = context3d->createBuffer();
805 context3d->bindBuffer(
806 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
807 resource->glPixelBufferId);
808 context3d->bufferData(
809 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
810 resource->size.width() * resource->size.height() * 4,
811 NULL,
812 GL_DYNAMIC_DRAW);
813 context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
816 if (resource->pixels) {
817 if (resource->pixelBuffer)
818 return;
820 resource->pixelBuffer = new uint8_t[
821 resource->size.width() * resource->size.height() * 4];
825 void ResourceProvider::releasePixelBuffer(ResourceId id)
827 DCHECK(m_threadChecker.CalledOnValidThread());
828 ResourceMap::iterator it = m_resources.find(id);
829 CHECK(it != m_resources.end());
830 Resource* resource = &it->second;
831 DCHECK(!resource->external);
832 DCHECK(!resource->exported);
834 if (resource->glId) {
835 DCHECK(resource->glPixelBufferId);
836 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
837 DCHECK(context3d);
838 context3d->bindBuffer(
839 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
840 resource->glPixelBufferId);
841 context3d->bufferData(
842 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
844 NULL,
845 GL_DYNAMIC_DRAW);
846 context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
849 if (resource->pixels) {
850 if (!resource->pixelBuffer)
851 return;
852 delete[] resource->pixelBuffer;
853 resource->pixelBuffer = 0;
857 uint8_t* ResourceProvider::mapPixelBuffer(ResourceId id)
859 DCHECK(m_threadChecker.CalledOnValidThread());
860 ResourceMap::iterator it = m_resources.find(id);
861 CHECK(it != m_resources.end());
862 Resource* resource = &it->second;
863 DCHECK(!resource->external);
864 DCHECK(!resource->exported);
866 if (resource->glId) {
867 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
868 DCHECK(context3d);
869 DCHECK(resource->glPixelBufferId);
870 context3d->bindBuffer(
871 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
872 resource->glPixelBufferId);
873 uint8_t* image = static_cast<uint8_t*>(
874 context3d->mapBufferCHROMIUM(
875 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
876 context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
877 DCHECK(image);
878 return image;
881 if (resource->pixels)
882 return resource->pixelBuffer;
884 return NULL;
887 void ResourceProvider::unmapPixelBuffer(ResourceId id)
889 DCHECK(m_threadChecker.CalledOnValidThread());
890 ResourceMap::iterator it = m_resources.find(id);
891 CHECK(it != m_resources.end());
892 Resource* resource = &it->second;
893 DCHECK(!resource->external);
894 DCHECK(!resource->exported);
896 if (resource->glId) {
897 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
898 DCHECK(context3d);
899 DCHECK(resource->glPixelBufferId);
900 context3d->bindBuffer(
901 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
902 resource->glPixelBufferId);
903 context3d->unmapBufferCHROMIUM(
904 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
905 context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
909 void ResourceProvider::setPixelsFromBuffer(ResourceId id)
911 DCHECK(m_threadChecker.CalledOnValidThread());
912 ResourceMap::iterator it = m_resources.find(id);
913 CHECK(it != m_resources.end());
914 Resource* resource = &it->second;
915 DCHECK(!resource->lockedForWrite);
916 DCHECK(!resource->lockForReadCount);
917 DCHECK(!resource->external);
918 DCHECK(!resource->exported);
919 DCHECK(readLockFenceHasPassed(resource));
920 lazyAllocate(resource);
922 if (resource->glId) {
923 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
924 DCHECK(context3d);
925 DCHECK(resource->glPixelBufferId);
926 context3d->bindTexture(GL_TEXTURE_2D, resource->glId);
927 context3d->bindBuffer(
928 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
929 resource->glPixelBufferId);
930 context3d->texSubImage2D(GL_TEXTURE_2D,
931 0, /* level */
932 0, /* x */
933 0, /* y */
934 resource->size.width(),
935 resource->size.height(),
936 resource->format,
937 GL_UNSIGNED_BYTE,
938 NULL);
939 context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
942 if (resource->pixels) {
943 DCHECK(resource->pixelBuffer);
944 DCHECK(resource->format == GL_RGBA);
945 SkBitmap src;
946 src.setConfig(SkBitmap::kARGB_8888_Config,
947 resource->size.width(),
948 resource->size.height());
949 src.setPixels(resource->pixelBuffer);
951 ScopedWriteLockSoftware lock(this, id);
952 SkCanvas* dest = lock.skCanvas();
953 dest->writePixels(src, 0, 0);
957 void ResourceProvider::bindForSampling(ResourceProvider::ResourceId resourceId, GLenum target, GLenum filter)
959 DCHECK(m_threadChecker.CalledOnValidThread());
960 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
961 ResourceMap::iterator it = m_resources.find(resourceId);
962 DCHECK(it != m_resources.end());
963 Resource* resource = &it->second;
964 DCHECK(resource->lockForReadCount);
965 DCHECK(!resource->lockedForWrite);
967 GLC(context3d, context3d->bindTexture(target, resource->glId));
968 if (filter != resource->filter) {
969 GLC(context3d, context3d->texParameteri(target, GL_TEXTURE_MIN_FILTER, filter));
970 GLC(context3d, context3d->texParameteri(target, GL_TEXTURE_MAG_FILTER, filter));
971 resource->filter = filter;
975 void ResourceProvider::beginSetPixels(ResourceId id)
977 DCHECK(m_threadChecker.CalledOnValidThread());
978 ResourceMap::iterator it = m_resources.find(id);
979 CHECK(it != m_resources.end());
980 Resource* resource = &it->second;
981 DCHECK(!resource->pendingSetPixels);
982 DCHECK(resource->glId || resource->allocated);
983 DCHECK(readLockFenceHasPassed(resource));
985 bool allocate = !resource->allocated;
986 resource->allocated = true;
987 lockForWrite(id);
989 if (resource->glId) {
990 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
991 DCHECK(context3d);
992 DCHECK(resource->glPixelBufferId);
993 context3d->bindTexture(GL_TEXTURE_2D, resource->glId);
994 context3d->bindBuffer(
995 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
996 resource->glPixelBufferId);
997 if (!resource->glUploadQueryId)
998 resource->glUploadQueryId = context3d->createQueryEXT();
999 context3d->beginQueryEXT(
1000 GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM,
1001 resource->glUploadQueryId);
1002 if (allocate) {
1003 context3d->asyncTexImage2DCHROMIUM(GL_TEXTURE_2D,
1004 0, /* level */
1005 resource->format,
1006 resource->size.width(),
1007 resource->size.height(),
1008 0, /* border */
1009 resource->format,
1010 GL_UNSIGNED_BYTE,
1011 NULL);
1012 } else {
1013 context3d->asyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D,
1014 0, /* level */
1015 0, /* x */
1016 0, /* y */
1017 resource->size.width(),
1018 resource->size.height(),
1019 resource->format,
1020 GL_UNSIGNED_BYTE,
1021 NULL);
1023 context3d->endQueryEXT(GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM);
1024 context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1027 if (resource->pixels)
1028 setPixelsFromBuffer(id);
1030 resource->pendingSetPixels = true;
1033 bool ResourceProvider::didSetPixelsComplete(ResourceId id) {
1034 DCHECK(m_threadChecker.CalledOnValidThread());
1035 ResourceMap::iterator it = m_resources.find(id);
1036 CHECK(it != m_resources.end());
1037 Resource* resource = &it->second;
1038 DCHECK(resource->lockedForWrite);
1039 DCHECK(resource->pendingSetPixels);
1041 if (resource->glId) {
1042 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
1043 DCHECK(context3d);
1044 DCHECK(resource->glUploadQueryId);
1045 unsigned complete = 1;
1046 context3d->getQueryObjectuivEXT(
1047 resource->glUploadQueryId,
1048 GL_QUERY_RESULT_AVAILABLE_EXT,
1049 &complete);
1050 if (!complete)
1051 return false;
1054 resource->pendingSetPixels = false;
1055 unlockForWrite(id);
1057 return true;
1060 void ResourceProvider::abortSetPixels(ResourceId id) {
1061 DCHECK(m_threadChecker.CalledOnValidThread());
1062 ResourceMap::iterator it = m_resources.find(id);
1063 CHECK(it != m_resources.end());
1064 Resource* resource = &it->second;
1065 DCHECK(resource->lockedForWrite);
1066 DCHECK(resource->pendingSetPixels);
1068 if (resource->glId) {
1069 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
1070 DCHECK(context3d);
1071 DCHECK(resource->glUploadQueryId);
1072 // CHROMIUM_async_pixel_transfers currently doesn't have a way to
1073 // abort an upload. The best we can do is delete the query and
1074 // the texture.
1075 context3d->deleteQueryEXT(resource->glUploadQueryId);
1076 resource->glUploadQueryId = 0;
1077 context3d->deleteTexture(resource->glId);
1078 resource->glId = createTextureId(context3d);
1079 resource->allocated = false;
1082 resource->pendingSetPixels = false;
1083 unlockForWrite(id);
1086 void ResourceProvider::allocateForTesting(ResourceId id) {
1087 ResourceMap::iterator it = m_resources.find(id);
1088 CHECK(it != m_resources.end());
1089 Resource* resource = &it->second;
1090 lazyAllocate(resource);
1093 void ResourceProvider::lazyAllocate(Resource* resource) {
1094 DCHECK(resource);
1095 DCHECK(resource->glId || resource->allocated);
1097 if (resource->allocated || !resource->glId)
1098 return;
1099 resource->allocated = true;
1100 WebGraphicsContext3D* context3d = m_outputSurface->context3d();
1101 gfx::Size& size = resource->size;
1102 GLenum format = resource->format;
1103 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, resource->glId));
1104 if (m_useTextureStorageExt && isTextureFormatSupportedForStorage(format)) {
1105 GLenum storageFormat = textureToStorageFormat(format);
1106 GLC(context3d, context3d->texStorage2DEXT(GL_TEXTURE_2D, 1, storageFormat, size.width(), size.height()));
1107 } else
1108 GLC(context3d, context3d->texImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0, format, GL_UNSIGNED_BYTE, 0));
1111 void ResourceProvider::enableReadLockFences(ResourceProvider::ResourceId id, bool enable) {
1112 DCHECK(m_threadChecker.CalledOnValidThread());
1113 ResourceMap::iterator it = m_resources.find(id);
1114 CHECK(it != m_resources.end());
1115 Resource* resource = &it->second;
1116 resource->enableReadLockFences = enable;
1119 } // namespace cc