Don't consider a Bluetooth adapter present until it has an address.
[chromium-blink-merge.git] / cc / CCResourceProvider.cpp
blob780539f48b327d3d2c519496b3ce82ce6b2325ac
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 "config.h"
7 #include "CCResourceProvider.h"
8 #ifdef LOG
9 #undef LOG
10 #endif
12 #include "base/string_split.h"
13 #include "base/string_util.h"
14 #include "CCProxy.h"
15 #include "CCRendererGL.h" // For the GLC() macro.
16 #include "Extensions3DChromium.h"
17 #include "IntRect.h"
18 #include "LayerTextureSubImage.h"
19 #include <limits.h>
20 #include <public/WebGraphicsContext3D.h>
21 #include <wtf/HashSet.h>
23 using WebKit::WebGraphicsContext3D;
25 namespace WebCore {
27 static GC3Denum textureToStorageFormat(GC3Denum textureFormat)
29 GC3Denum storageFormat = Extensions3D::RGBA8_OES;
30 switch (textureFormat) {
31 case GraphicsContext3D::RGBA:
32 break;
33 case Extensions3D::BGRA_EXT:
34 storageFormat = Extensions3DChromium::BGRA8_EXT;
35 break;
36 default:
37 ASSERT_NOT_REACHED();
38 break;
41 return storageFormat;
44 static bool isTextureFormatSupportedForStorage(GC3Denum format)
46 return (format == GraphicsContext3D::RGBA || format == Extensions3D::BGRA_EXT);
49 PassOwnPtr<CCResourceProvider> CCResourceProvider::create(CCGraphicsContext* context)
51 OwnPtr<CCResourceProvider> resourceProvider(adoptPtr(new CCResourceProvider(context)));
52 if (!resourceProvider->initialize())
53 return nullptr;
54 return resourceProvider.release();
57 CCResourceProvider::~CCResourceProvider()
61 WebGraphicsContext3D* CCResourceProvider::graphicsContext3D()
63 ASSERT(CCProxy::isImplThread());
64 return m_context->context3D();
67 bool CCResourceProvider::inUseByConsumer(ResourceId id)
69 ASSERT(CCProxy::isImplThread());
70 ResourceMap::iterator it = m_resources.find(id);
71 ASSERT(it != m_resources.end());
72 return !!it->second.lockForReadCount || it->second.exported;
75 CCResourceProvider::ResourceId CCResourceProvider::createResource(int pool, const IntSize& size, GC3Denum format, TextureUsageHint hint)
77 switch (m_defaultResourceType) {
78 case GLTexture:
79 return createGLTexture(pool, size, format, hint);
80 case Bitmap:
81 ASSERT(format == GraphicsContext3D::RGBA);
82 return createBitmap(pool, size);
85 CRASH();
86 return 0;
89 CCResourceProvider::ResourceId CCResourceProvider::createGLTexture(int pool, const IntSize& size, GC3Denum format, TextureUsageHint hint)
91 ASSERT(CCProxy::isImplThread());
92 unsigned textureId = 0;
93 WebGraphicsContext3D* context3d = m_context->context3D();
94 ASSERT(context3d);
95 GLC(context3d, textureId = context3d->createTexture());
96 GLC(context3d, context3d->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId));
97 GLC(context3d, context3d->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR));
98 GLC(context3d, context3d->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR));
99 GLC(context3d, context3d->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE));
100 GLC(context3d, context3d->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE));
102 if (m_useTextureUsageHint && hint == TextureUsageFramebuffer)
103 GLC(context3d, context3d->texParameteri(GraphicsContext3D::TEXTURE_2D, Extensions3DChromium::GL_TEXTURE_USAGE_ANGLE, Extensions3DChromium::GL_FRAMEBUFFER_ATTACHMENT_ANGLE));
104 if (m_useTextureStorageExt && isTextureFormatSupportedForStorage(format)) {
105 GC3Denum storageFormat = textureToStorageFormat(format);
106 GLC(context3d, context3d->texStorage2DEXT(GraphicsContext3D::TEXTURE_2D, 1, storageFormat, size.width(), size.height()));
107 } else
108 GLC(context3d, context3d->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, format, size.width(), size.height(), 0, format, GraphicsContext3D::UNSIGNED_BYTE, 0));
109 ResourceId id = m_nextId++;
110 Resource resource(textureId, pool, size, format);
111 m_resources.add(id, resource);
112 return id;
115 CCResourceProvider::ResourceId CCResourceProvider::createBitmap(int pool, const IntSize& size)
117 ASSERT(CCProxy::isImplThread());
119 uint8_t* pixels = new uint8_t[size.width() * size.height() * 4];
121 ResourceId id = m_nextId++;
122 Resource resource(pixels, pool, size, GraphicsContext3D::RGBA);
123 m_resources.add(id, resource);
124 return id;
127 CCResourceProvider::ResourceId CCResourceProvider::createResourceFromExternalTexture(unsigned textureId)
129 ASSERT(CCProxy::isImplThread());
130 ASSERT(m_context->context3D());
131 ResourceId id = m_nextId++;
132 Resource resource(textureId, 0, IntSize(), 0);
133 resource.external = true;
134 m_resources.add(id, resource);
135 return id;
138 void CCResourceProvider::deleteResource(ResourceId id)
140 ASSERT(CCProxy::isImplThread());
141 ResourceMap::iterator it = m_resources.find(id);
142 ASSERT(it != m_resources.end());
143 ASSERT(!it->second.lockedForWrite);
144 ASSERT(!it->second.lockForReadCount);
146 if (it->second.glId && !it->second.external) {
147 WebGraphicsContext3D* context3d = m_context->context3D();
148 ASSERT(context3d);
149 GLC(context3d, context3d->deleteTexture(it->second.glId));
151 if (it->second.pixels)
152 delete it->second.pixels;
154 m_resources.remove(it);
157 void CCResourceProvider::deleteOwnedResources(int pool)
159 ASSERT(CCProxy::isImplThread());
160 ResourceIdArray toDelete;
161 for (ResourceMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
162 if (it->second.pool == pool && !it->second.external)
163 toDelete.append(it->first);
165 for (ResourceIdArray::iterator it = toDelete.begin(); it != toDelete.end(); ++it)
166 deleteResource(*it);
169 CCResourceProvider::ResourceType CCResourceProvider::resourceType(ResourceId id)
171 ResourceMap::iterator it = m_resources.find(id);
172 ASSERT(it != m_resources.end());
173 return it->second.type;
176 void CCResourceProvider::upload(ResourceId id, const uint8_t* image, const IntRect& imageRect, const IntRect& sourceRect, const IntSize& destOffset)
178 ASSERT(CCProxy::isImplThread());
179 ResourceMap::iterator it = m_resources.find(id);
180 ASSERT(it != m_resources.end());
181 ASSERT(!it->second.lockedForWrite);
182 ASSERT(!it->second.lockForReadCount);
183 ASSERT(!it->second.external);
185 if (it->second.glId) {
186 WebGraphicsContext3D* context3d = m_context->context3D();
187 ASSERT(context3d);
188 ASSERT(m_texSubImage.get());
189 context3d->bindTexture(GraphicsContext3D::TEXTURE_2D, it->second.glId);
190 m_texSubImage->upload(image, imageRect, sourceRect, destOffset, it->second.format, context3d);
193 if (it->second.pixels) {
194 SkBitmap srcFull;
195 srcFull.setConfig(SkBitmap::kARGB_8888_Config, imageRect.width(), imageRect.height());
196 srcFull.setPixels(const_cast<uint8_t*>(image));
197 SkBitmap srcSubset;
198 SkIRect skSourceRect = SkIRect::MakeXYWH(sourceRect.x(), sourceRect.y(), sourceRect.width(), sourceRect.height());
199 skSourceRect.offset(-imageRect.x(), -imageRect.y());
200 srcFull.extractSubset(&srcSubset, skSourceRect);
202 ScopedWriteLockSoftware lock(this, id);
203 SkCanvas* dest = lock.skCanvas();
204 dest->writePixels(srcSubset, destOffset.width(), destOffset.height());
208 void CCResourceProvider::flush()
210 ASSERT(CCProxy::isImplThread());
211 WebGraphicsContext3D* context3d = m_context->context3D();
212 if (context3d)
213 context3d->flush();
216 bool CCResourceProvider::shallowFlushIfSupported()
218 ASSERT(CCProxy::isImplThread());
219 WebGraphicsContext3D* context3d = m_context->context3D();
220 if (!context3d || !m_useShallowFlush)
221 return false;
223 context3d->shallowFlushCHROMIUM();
224 return true;
227 const CCResourceProvider::Resource* CCResourceProvider::lockForRead(ResourceId id)
229 ASSERT(CCProxy::isImplThread());
230 ResourceMap::iterator it = m_resources.find(id);
231 ASSERT(it != m_resources.end());
232 ASSERT(!it->second.lockedForWrite);
233 it->second.lockForReadCount++;
234 return &it->second;
237 void CCResourceProvider::unlockForRead(ResourceId id)
239 ASSERT(CCProxy::isImplThread());
240 ResourceMap::iterator it = m_resources.find(id);
241 ASSERT(it != m_resources.end());
242 ASSERT(it->second.lockForReadCount > 0);
243 it->second.lockForReadCount--;
246 const CCResourceProvider::Resource* CCResourceProvider::lockForWrite(ResourceId id)
248 ASSERT(CCProxy::isImplThread());
249 ResourceMap::iterator it = m_resources.find(id);
250 ASSERT(it != m_resources.end());
251 ASSERT(!it->second.lockedForWrite);
252 ASSERT(!it->second.lockForReadCount);
253 ASSERT(!it->second.external);
254 it->second.lockedForWrite = true;
255 return &it->second;
258 void CCResourceProvider::unlockForWrite(ResourceId id)
260 ASSERT(CCProxy::isImplThread());
261 ResourceMap::iterator it = m_resources.find(id);
262 ASSERT(it != m_resources.end());
263 ASSERT(it->second.lockedForWrite);
264 ASSERT(!it->second.external);
265 it->second.lockedForWrite = false;
268 CCResourceProvider::ScopedReadLockGL::ScopedReadLockGL(CCResourceProvider* resourceProvider, CCResourceProvider::ResourceId resourceId)
269 : m_resourceProvider(resourceProvider)
270 , m_resourceId(resourceId)
271 , m_textureId(resourceProvider->lockForRead(resourceId)->glId)
273 ASSERT(m_textureId);
276 CCResourceProvider::ScopedReadLockGL::~ScopedReadLockGL()
278 m_resourceProvider->unlockForRead(m_resourceId);
281 CCResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(CCResourceProvider* resourceProvider, CCResourceProvider::ResourceId resourceId)
282 : m_resourceProvider(resourceProvider)
283 , m_resourceId(resourceId)
284 , m_textureId(resourceProvider->lockForWrite(resourceId)->glId)
286 ASSERT(m_textureId);
289 CCResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL()
291 m_resourceProvider->unlockForWrite(m_resourceId);
294 void CCResourceProvider::populateSkBitmapWithResource(SkBitmap* skBitmap, const Resource* resource)
296 ASSERT(resource->pixels);
297 ASSERT(resource->format == GraphicsContext3D::RGBA);
298 skBitmap->setConfig(SkBitmap::kARGB_8888_Config, resource->size.width(), resource->size.height());
299 skBitmap->setPixels(resource->pixels);
302 CCResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(CCResourceProvider* resourceProvider, CCResourceProvider::ResourceId resourceId)
303 : m_resourceProvider(resourceProvider)
304 , m_resourceId(resourceId)
306 CCResourceProvider::populateSkBitmapWithResource(&m_skBitmap, resourceProvider->lockForRead(resourceId));
309 CCResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware()
311 m_resourceProvider->unlockForRead(m_resourceId);
314 CCResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(CCResourceProvider* resourceProvider, CCResourceProvider::ResourceId resourceId)
315 : m_resourceProvider(resourceProvider)
316 , m_resourceId(resourceId)
318 CCResourceProvider::populateSkBitmapWithResource(&m_skBitmap, resourceProvider->lockForWrite(resourceId));
319 m_skCanvas.setBitmapDevice(m_skBitmap);
322 CCResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware()
324 m_resourceProvider->unlockForWrite(m_resourceId);
327 CCResourceProvider::CCResourceProvider(CCGraphicsContext* context)
328 : m_context(context)
329 , m_nextId(1)
330 , m_nextChild(1)
331 , m_defaultResourceType(GLTexture)
332 , m_useTextureStorageExt(false)
333 , m_useTextureUsageHint(false)
334 , m_useShallowFlush(false)
335 , m_maxTextureSize(0)
339 bool CCResourceProvider::initialize()
341 ASSERT(CCProxy::isImplThread());
342 WebGraphicsContext3D* context3d = m_context->context3D();
343 if (!context3d) {
344 m_maxTextureSize = INT_MAX;
346 // FIXME: Implement this path for software compositing.
347 return false;
349 if (!context3d->makeContextCurrent())
350 return false;
352 std::string extensionsString = UTF16ToASCII(context3d->getString(GraphicsContext3D::EXTENSIONS));
353 std::vector<std::string> extensions;
354 base::SplitString(extensionsString, ' ', &extensions);
355 bool useMapSub = false;
356 for (size_t i = 0; i < extensions.size(); ++i) {
357 if (extensions[i] == "GL_EXT_texture_storage")
358 m_useTextureStorageExt = true;
359 else if (extensions[i] == "GL_ANGLE_texture_usage")
360 m_useTextureUsageHint = true;
361 else if (extensions[i] == "GL_CHROMIUM_map_sub")
362 useMapSub = true;
363 else if (extensions[i] == "GL_CHROMIUM_shallow_flush")
364 m_useShallowFlush = true;
367 m_texSubImage = adoptPtr(new LayerTextureSubImage(useMapSub));
368 GLC(context3d, context3d->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize));
369 return true;
372 int CCResourceProvider::createChild(int pool)
374 ASSERT(CCProxy::isImplThread());
375 Child childInfo;
376 childInfo.pool = pool;
377 int child = m_nextChild++;
378 m_children.add(child, childInfo);
379 return child;
382 void CCResourceProvider::destroyChild(int child)
384 ASSERT(CCProxy::isImplThread());
385 ChildMap::iterator it = m_children.find(child);
386 ASSERT(it != m_children.end());
387 deleteOwnedResources(it->second.pool);
388 m_children.remove(it);
389 trimMailboxDeque();
392 const CCResourceProvider::ResourceIdMap& CCResourceProvider::getChildToParentMap(int child) const
394 ASSERT(CCProxy::isImplThread());
395 ChildMap::const_iterator it = m_children.find(child);
396 ASSERT(it != m_children.end());
397 return it->second.childToParentMap;
400 CCResourceProvider::TransferableResourceList CCResourceProvider::prepareSendToParent(const ResourceIdArray& resources)
402 ASSERT(CCProxy::isImplThread());
403 TransferableResourceList list;
404 list.syncPoint = 0;
405 WebGraphicsContext3D* context3d = m_context->context3D();
406 if (!context3d || !context3d->makeContextCurrent()) {
407 // FIXME: Implement this path for software compositing.
408 return list;
410 for (ResourceIdArray::const_iterator it = resources.begin(); it != resources.end(); ++it) {
411 TransferableResource resource;
412 if (transferResource(context3d, *it, &resource)) {
413 m_resources.find(*it)->second.exported = true;
414 list.resources.append(resource);
417 if (list.resources.size())
418 list.syncPoint = context3d->insertSyncPoint();
419 return list;
422 CCResourceProvider::TransferableResourceList CCResourceProvider::prepareSendToChild(int child, const ResourceIdArray& resources)
424 ASSERT(CCProxy::isImplThread());
425 TransferableResourceList list;
426 list.syncPoint = 0;
427 WebGraphicsContext3D* context3d = m_context->context3D();
428 if (!context3d || !context3d->makeContextCurrent()) {
429 // FIXME: Implement this path for software compositing.
430 return list;
432 Child& childInfo = m_children.find(child)->second;
433 for (ResourceIdArray::const_iterator it = resources.begin(); it != resources.end(); ++it) {
434 TransferableResource resource;
435 if (!transferResource(context3d, *it, &resource))
436 ASSERT_NOT_REACHED();
437 resource.id = childInfo.parentToChildMap.get(*it);
438 childInfo.parentToChildMap.remove(*it);
439 childInfo.childToParentMap.remove(resource.id);
440 list.resources.append(resource);
441 deleteResource(*it);
443 if (list.resources.size())
444 list.syncPoint = context3d->insertSyncPoint();
445 return list;
448 void CCResourceProvider::receiveFromChild(int child, const TransferableResourceList& resources)
450 ASSERT(CCProxy::isImplThread());
451 WebGraphicsContext3D* context3d = m_context->context3D();
452 if (!context3d || !context3d->makeContextCurrent()) {
453 // FIXME: Implement this path for software compositing.
454 return;
456 if (resources.syncPoint) {
457 // NOTE: If the parent is a browser and the child a renderer, the parent
458 // is not supposed to have its context wait, because that could induce
459 // deadlocks and/or security issues. The caller is responsible for
460 // waiting asynchronously, and resetting syncPoint before calling this.
461 // However if the parent is a renderer (e.g. browser tag), it may be ok
462 // (and is simpler) to wait.
463 GLC(context3d, context3d->waitSyncPoint(resources.syncPoint));
465 Child& childInfo = m_children.find(child)->second;
466 for (Vector<TransferableResource>::const_iterator it = resources.resources.begin(); it != resources.resources.end(); ++it) {
467 unsigned textureId;
468 GLC(context3d, textureId = context3d->createTexture());
469 GLC(context3d, context3d->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId));
470 GLC(context3d, context3d->consumeTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, it->mailbox.name));
471 ResourceId id = m_nextId++;
472 Resource resource(textureId, childInfo.pool, it->size, it->format);
473 m_resources.add(id, resource);
474 m_mailboxes.append(it->mailbox);
475 childInfo.parentToChildMap.add(id, it->id);
476 childInfo.childToParentMap.add(it->id, id);
480 void CCResourceProvider::receiveFromParent(const TransferableResourceList& resources)
482 ASSERT(CCProxy::isImplThread());
483 WebGraphicsContext3D* context3d = m_context->context3D();
484 if (!context3d || !context3d->makeContextCurrent()) {
485 // FIXME: Implement this path for software compositing.
486 return;
488 if (resources.syncPoint)
489 GLC(context3d, context3d->waitSyncPoint(resources.syncPoint));
490 for (Vector<TransferableResource>::const_iterator it = resources.resources.begin(); it != resources.resources.end(); ++it) {
491 Resource& resource = m_resources.find(it->id)->second;
492 ASSERT(resource.exported);
493 resource.exported = false;
494 GLC(context3d, context3d->bindTexture(GraphicsContext3D::TEXTURE_2D, resource.glId));
495 GLC(context3d, context3d->consumeTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, it->mailbox.name));
496 m_mailboxes.append(it->mailbox);
500 bool CCResourceProvider::transferResource(WebGraphicsContext3D* context, ResourceId id, TransferableResource* resource)
502 ASSERT(CCProxy::isImplThread());
503 ResourceMap::const_iterator it = m_resources.find(id);
504 ASSERT(it != m_resources.end());
505 ASSERT(!it->second.lockedForWrite);
506 ASSERT(!it->second.lockForReadCount);
507 ASSERT(!it->second.external);
508 if (it->second.exported)
509 return false;
510 resource->id = id;
511 resource->format = it->second.format;
512 resource->size = it->second.size;
513 if (!m_mailboxes.isEmpty())
514 resource->mailbox = m_mailboxes.takeFirst();
515 else
516 GLC(context, context->genMailboxCHROMIUM(resource->mailbox.name));
517 GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, it->second.glId));
518 GLC(context, context->produceTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, resource->mailbox.name));
519 return true;
522 void CCResourceProvider::trimMailboxDeque()
524 // Trim the mailbox deque to the maximum number of resources we may need to
525 // send.
526 // If we have a parent, any non-external resource not already transfered is
527 // eligible to be sent to the parent. Otherwise, all resources belonging to
528 // a child might need to be sent back to the child.
529 size_t maxMailboxCount = 0;
530 if (m_context->capabilities().hasParentCompositor) {
531 for (ResourceMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
532 if (!it->second.exported && !it->second.external)
533 ++maxMailboxCount;
535 } else {
536 HashSet<int> childPoolSet;
537 for (ChildMap::iterator it = m_children.begin(); it != m_children.end(); ++it)
538 childPoolSet.add(it->second.pool);
539 for (ResourceMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
540 if (childPoolSet.contains(it->second.pool))
541 ++maxMailboxCount;
544 while (m_mailboxes.size() > maxMailboxCount)
545 m_mailboxes.removeFirst();