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"
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
;
29 static GLenum
textureToStorageFormat(GLenum textureFormat
)
31 GLenum storageFormat
= GL_RGBA8_OES
;
32 switch (textureFormat
) {
36 storageFormat
= GL_BGRA8_EXT
;
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
));
63 ResourceProvider::Resource::Resource()
70 , lockedForWrite(false)
73 , markedForDeletion(false)
74 , pendingSetPixels(false)
76 , enableReadLockFences(false)
81 , type(static_cast<ResourceType
>(0))
85 ResourceProvider::Resource::~Resource()
89 ResourceProvider::Resource::Resource(unsigned textureId
, const gfx::Size
& size
, GLenum format
, GLenum filter
)
96 , lockedForWrite(false)
99 , markedForDeletion(false)
100 , pendingSetPixels(false)
102 , enableReadLockFences(false)
103 , readLockFence(NULL
)
111 ResourceProvider::Resource::Resource(uint8_t* pixels
, const gfx::Size
& size
, GLenum format
, GLenum filter
)
117 , lockForReadCount(0)
118 , lockedForWrite(false)
121 , markedForDeletion(false)
122 , pendingSetPixels(false)
124 , enableReadLockFences(false)
125 , readLockFence(NULL
)
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())
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
) {
177 return createGLTexture(size
, format
, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM
, hint
);
179 DCHECK(format
== GL_RGBA
);
180 return createBitmap(size
);
183 LOG(FATAL
) << "Invalid default resource type.";
187 ResourceProvider::ResourceId
ResourceProvider::createManagedResource(const gfx::Size
& size
, GLenum format
, TextureUsageHint hint
)
189 switch (m_defaultResourceType
) {
191 return createGLTexture(size
, format
, GL_TEXTURE_POOL_MANAGED_CHROMIUM
, hint
);
193 DCHECK(format
== GL_RGBA
);
194 return createBitmap(size
);
197 LOG(FATAL
) << "Invalid default resource type.";
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();
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
;
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
;
236 ResourceProvider::ResourceId
ResourceProvider::createResourceFromExternalTexture(unsigned textureId
)
238 DCHECK(m_threadChecker
.CalledOnValidThread());
240 WebGraphicsContext3D
* context3d
= m_outputSurface
->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
;
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
;
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;
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();
293 GLC(context3d
, context3d
->deleteTexture(resource
->glId
));
295 if (resource
->glUploadQueryId
) {
296 WebGraphicsContext3D
* context3d
= m_outputSurface
->context3d();
298 GLC(context3d
, context3d
->deleteQueryEXT(resource
->glUploadQueryId
));
300 if (resource
->glPixelBufferId
) {
301 WebGraphicsContext3D
* context3d
= m_outputSurface
->context3d();
303 GLC(context3d
, context3d
->deleteBuffer(resource
->glPixelBufferId
));
305 if (!resource
->mailbox
.IsEmpty() && resource
->external
) {
306 WebGraphicsContext3D
* context3d
= m_outputSurface
->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();
350 DCHECK(m_textureUploader
.get());
351 context3d
->bindTexture(GL_TEXTURE_2D
, resource
->glId
);
352 m_textureUploader
->upload(image
,
360 if (resource
->pixels
) {
361 DCHECK(resource
->allocated
);
362 DCHECK(resource
->format
== GL_RGBA
);
364 srcFull
.setConfig(SkBitmap::kARGB_8888_Config
, imageRect
.width(), imageRect
.height());
365 srcFull
.setPixels(const_cast<uint8_t*>(image
));
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
)
382 return m_textureUploader
->numBlockingUploads();
385 void ResourceProvider::markPendingUploadsAsNonBlocking()
387 if (!m_textureUploader
)
390 m_textureUploader
->markPendingUploadsAsNonBlocking();
393 double ResourceProvider::estimatedUploadsPerSecond()
395 if (!m_textureUploader
)
398 return m_textureUploader
->estimatedTexturesPerSecond();
401 void ResourceProvider::flushUploads()
403 if (!m_textureUploader
)
406 m_textureUploader
->flush();
409 void ResourceProvider::flush()
411 DCHECK(m_threadChecker
.CalledOnValidThread());
412 WebGraphicsContext3D
* context3d
= m_outputSurface
->context3d();
417 bool ResourceProvider::shallowFlushIfSupported()
419 DCHECK(m_threadChecker
.CalledOnValidThread());
420 WebGraphicsContext3D
* context3d
= m_outputSurface
->context3d();
421 if (!context3d
|| !m_useShallowFlush
)
424 context3d
->shallowFlushCHROMIUM();
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();
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
;
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;
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
)
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
)
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
)
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();
593 m_maxTextureSize
= INT_MAX
/ 2;
594 m_bestTextureFormat
= GL_RGBA
;
597 if (!context3d
->makeContextCurrent())
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")
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")
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
);
629 int ResourceProvider::createChild()
631 DCHECK(m_threadChecker
.CalledOnValidThread());
633 int child
= m_nextChild
++;
634 m_children
[child
] = childInfo
;
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.
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.
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
))
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
);
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.
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
) {
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.
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
)
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
);
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
));
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();
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,
813 context3d
->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
, 0);
816 if (resource
->pixels
) {
817 if (resource
->pixelBuffer
)
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();
838 context3d
->bindBuffer(
839 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
,
840 resource
->glPixelBufferId
);
841 context3d
->bufferData(
842 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
,
846 context3d
->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
, 0);
849 if (resource
->pixels
) {
850 if (!resource
->pixelBuffer
)
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();
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);
881 if (resource
->pixels
)
882 return resource
->pixelBuffer
;
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();
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();
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
,
934 resource
->size
.width(),
935 resource
->size
.height(),
939 context3d
->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
, 0);
942 if (resource
->pixels
) {
943 DCHECK(resource
->pixelBuffer
);
944 DCHECK(resource
->format
== GL_RGBA
);
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;
989 if (resource
->glId
) {
990 WebGraphicsContext3D
* context3d
= m_outputSurface
->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
);
1003 context3d
->asyncTexImage2DCHROMIUM(GL_TEXTURE_2D
,
1006 resource
->size
.width(),
1007 resource
->size
.height(),
1013 context3d
->asyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D
,
1017 resource
->size
.width(),
1018 resource
->size
.height(),
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();
1044 DCHECK(resource
->glUploadQueryId
);
1045 unsigned complete
= 1;
1046 context3d
->getQueryObjectuivEXT(
1047 resource
->glUploadQueryId
,
1048 GL_QUERY_RESULT_AVAILABLE_EXT
,
1054 resource
->pendingSetPixels
= false;
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();
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
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;
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
) {
1095 DCHECK(resource
->glId
|| resource
->allocated
);
1097 if (resource
->allocated
|| !resource
->glId
)
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()));
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
;