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/texture_uploader.h"
16 #include "cc/transferable_resource.h"
17 #include "third_party/khronos/GLES2/gl2.h"
18 #include "third_party/khronos/GLES2/gl2ext.h"
19 #include "ui/gfx/rect.h"
20 #include "ui/gfx/vector2d.h"
22 #include <public/WebGraphicsContext3D.h>
24 using WebKit::WebGraphicsContext3D
;
28 static GLenum
textureToStorageFormat(GLenum textureFormat
)
30 GLenum storageFormat
= GL_RGBA8_OES
;
31 switch (textureFormat
) {
35 storageFormat
= GL_BGRA8_EXT
;
45 static bool isTextureFormatSupportedForStorage(GLenum format
)
47 return (format
== GL_RGBA
|| format
== GL_BGRA_EXT
);
50 ResourceProvider::Resource::Resource()
55 , lockedForWrite(false)
58 , markedForDeletion(false)
61 , type(static_cast<ResourceType
>(0))
65 ResourceProvider::Resource::Resource(unsigned textureId
, int pool
, const gfx::Size
& size
, GLenum format
)
70 , lockedForWrite(false)
73 , markedForDeletion(false)
80 ResourceProvider::Resource::Resource(uint8_t* pixels
, int pool
, const gfx::Size
& size
, GLenum format
)
85 , lockedForWrite(false)
88 , markedForDeletion(false)
95 ResourceProvider::Child::Child()
99 ResourceProvider::Child::~Child()
103 scoped_ptr
<ResourceProvider
> ResourceProvider::create(GraphicsContext
* context
)
105 scoped_ptr
<ResourceProvider
> resourceProvider(new ResourceProvider(context
));
106 if (!resourceProvider
->initialize())
107 return scoped_ptr
<ResourceProvider
>();
108 return resourceProvider
.Pass();
111 ResourceProvider::~ResourceProvider()
113 WebGraphicsContext3D
* context3d
= m_context
->context3D();
114 if (!context3d
|| !context3d
->makeContextCurrent())
116 m_textureUploader
.reset();
117 m_textureCopier
.reset();
120 WebGraphicsContext3D
* ResourceProvider::graphicsContext3D()
122 DCHECK(m_threadChecker
.CalledOnValidThread());
123 return m_context
->context3D();
126 bool ResourceProvider::inUseByConsumer(ResourceId id
)
128 DCHECK(m_threadChecker
.CalledOnValidThread());
129 ResourceMap::iterator it
= m_resources
.find(id
);
130 CHECK(it
!= m_resources
.end());
131 Resource
* resource
= &it
->second
;
132 return !!resource
->lockForReadCount
|| resource
->exported
;
135 ResourceProvider::ResourceId
ResourceProvider::createResource(int pool
, const gfx::Size
& size
, GLenum format
, TextureUsageHint hint
)
137 switch (m_defaultResourceType
) {
139 return createGLTexture(pool
, size
, format
, hint
);
141 DCHECK(format
== GL_RGBA
);
142 return createBitmap(pool
, size
);
145 LOG(FATAL
) << "Invalid default resource type.";
149 ResourceProvider::ResourceId
ResourceProvider::createGLTexture(int pool
, const gfx::Size
& size
, GLenum format
, TextureUsageHint hint
)
151 DCHECK(m_threadChecker
.CalledOnValidThread());
152 unsigned textureId
= 0;
153 WebGraphicsContext3D
* context3d
= m_context
->context3D();
155 GLC(context3d
, textureId
= context3d
->createTexture());
156 GLC(context3d
, context3d
->bindTexture(GL_TEXTURE_2D
, textureId
));
157 GLC(context3d
, context3d
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
));
158 GLC(context3d
, context3d
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
));
159 GLC(context3d
, context3d
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
));
160 GLC(context3d
, context3d
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
));
162 if (m_useTextureUsageHint
&& hint
== TextureUsageFramebuffer
)
163 GLC(context3d
, context3d
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_USAGE_ANGLE
, GL_FRAMEBUFFER_ATTACHMENT_ANGLE
));
164 if (m_useTextureStorageExt
&& isTextureFormatSupportedForStorage(format
)) {
165 GLenum storageFormat
= textureToStorageFormat(format
);
166 GLC(context3d
, context3d
->texStorage2DEXT(GL_TEXTURE_2D
, 1, storageFormat
, size
.width(), size
.height()));
168 GLC(context3d
, context3d
->texImage2D(GL_TEXTURE_2D
, 0, format
, size
.width(), size
.height(), 0, format
, GL_UNSIGNED_BYTE
, 0));
170 ResourceId id
= m_nextId
++;
171 Resource
resource(textureId
, pool
, size
, format
);
172 m_resources
[id
] = resource
;
176 ResourceProvider::ResourceId
ResourceProvider::createBitmap(int pool
, const gfx::Size
& size
)
178 DCHECK(m_threadChecker
.CalledOnValidThread());
180 uint8_t* pixels
= new uint8_t[size
.width() * size
.height() * 4];
182 ResourceId id
= m_nextId
++;
183 Resource
resource(pixels
, pool
, size
, GL_RGBA
);
184 m_resources
[id
] = resource
;
188 ResourceProvider::ResourceId
ResourceProvider::createResourceFromExternalTexture(unsigned textureId
)
190 DCHECK(m_threadChecker
.CalledOnValidThread());
192 WebGraphicsContext3D
* context3d
= m_context
->context3D();
194 GLC(context3d
, context3d
->bindTexture(GL_TEXTURE_2D
, textureId
));
195 GLC(context3d
, context3d
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
));
196 GLC(context3d
, context3d
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
));
197 GLC(context3d
, context3d
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
));
198 GLC(context3d
, context3d
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
));
200 ResourceId id
= m_nextId
++;
201 Resource
resource(textureId
, 0, gfx::Size(), 0);
202 resource
.external
= true;
203 m_resources
[id
] = resource
;
207 void ResourceProvider::deleteResource(ResourceId id
)
209 DCHECK(m_threadChecker
.CalledOnValidThread());
210 ResourceMap::iterator it
= m_resources
.find(id
);
211 CHECK(it
!= m_resources
.end());
212 Resource
* resource
= &it
->second
;
213 DCHECK(!resource
->lockedForWrite
);
214 DCHECK(!resource
->lockForReadCount
);
215 DCHECK(!resource
->markedForDeletion
);
217 if (resource
->exported
) {
218 resource
->markedForDeletion
= true;
221 deleteResourceInternal(it
);
224 void ResourceProvider::deleteResourceInternal(ResourceMap::iterator it
)
226 Resource
* resource
= &it
->second
;
227 if (resource
->glId
&& !resource
->external
) {
228 WebGraphicsContext3D
* context3d
= m_context
->context3D();
230 GLC(context3d
, context3d
->deleteTexture(resource
->glId
));
232 if (resource
->pixels
)
233 delete[] resource
->pixels
;
235 m_resources
.erase(it
);
238 void ResourceProvider::deleteOwnedResources(int pool
)
240 DCHECK(m_threadChecker
.CalledOnValidThread());
241 ResourceIdArray toDelete
;
242 for (ResourceMap::iterator it
= m_resources
.begin(); it
!= m_resources
.end(); ++it
) {
243 if (it
->second
.pool
== pool
&& !it
->second
.external
&& !it
->second
.markedForDeletion
)
244 toDelete
.push_back(it
->first
);
246 for (ResourceIdArray::iterator it
= toDelete
.begin(); it
!= toDelete
.end(); ++it
)
250 ResourceProvider::ResourceType
ResourceProvider::resourceType(ResourceId id
)
252 ResourceMap::iterator it
= m_resources
.find(id
);
253 CHECK(it
!= m_resources
.end());
254 Resource
* resource
= &it
->second
;
255 return resource
->type
;
258 void ResourceProvider::setPixels(ResourceId id
, const uint8_t* image
, const gfx::Rect
& imageRect
, const gfx::Rect
& sourceRect
, const gfx::Vector2d
& destOffset
)
260 DCHECK(m_threadChecker
.CalledOnValidThread());
261 ResourceMap::iterator it
= m_resources
.find(id
);
262 CHECK(it
!= m_resources
.end());
263 Resource
* resource
= &it
->second
;
264 DCHECK(!resource
->lockedForWrite
);
265 DCHECK(!resource
->lockForReadCount
);
266 DCHECK(!resource
->external
);
267 DCHECK(!resource
->exported
);
269 if (resource
->glId
) {
270 WebGraphicsContext3D
* context3d
= m_context
->context3D();
272 DCHECK(m_textureUploader
.get());
273 context3d
->bindTexture(GL_TEXTURE_2D
, resource
->glId
);
274 m_textureUploader
->upload(image
,
282 if (resource
->pixels
) {
283 DCHECK(resource
->format
== GL_RGBA
);
285 srcFull
.setConfig(SkBitmap::kARGB_8888_Config
, imageRect
.width(), imageRect
.height());
286 srcFull
.setPixels(const_cast<uint8_t*>(image
));
288 SkIRect skSourceRect
= SkIRect::MakeXYWH(sourceRect
.x(), sourceRect
.y(), sourceRect
.width(), sourceRect
.height());
289 skSourceRect
.offset(-imageRect
.x(), -imageRect
.y());
290 srcFull
.extractSubset(&srcSubset
, skSourceRect
);
292 ScopedWriteLockSoftware
lock(this, id
);
293 SkCanvas
* dest
= lock
.skCanvas();
294 dest
->writePixels(srcSubset
, destOffset
.x(), destOffset
.y());
298 size_t ResourceProvider::numBlockingUploads()
300 if (!m_textureUploader
)
303 return m_textureUploader
->numBlockingUploads();
306 void ResourceProvider::markPendingUploadsAsNonBlocking()
308 if (!m_textureUploader
)
311 m_textureUploader
->markPendingUploadsAsNonBlocking();
314 double ResourceProvider::estimatedUploadsPerSecond()
316 if (!m_textureUploader
)
319 return m_textureUploader
->estimatedTexturesPerSecond();
322 void ResourceProvider::flushUploads()
324 if (!m_textureUploader
)
327 m_textureUploader
->flush();
330 void ResourceProvider::flush()
332 DCHECK(m_threadChecker
.CalledOnValidThread());
333 WebGraphicsContext3D
* context3d
= m_context
->context3D();
338 bool ResourceProvider::shallowFlushIfSupported()
340 DCHECK(m_threadChecker
.CalledOnValidThread());
341 WebGraphicsContext3D
* context3d
= m_context
->context3D();
342 if (!context3d
|| !m_useShallowFlush
)
345 context3d
->shallowFlushCHROMIUM();
349 const ResourceProvider::Resource
* ResourceProvider::lockForRead(ResourceId id
)
351 DCHECK(m_threadChecker
.CalledOnValidThread());
352 ResourceMap::iterator it
= m_resources
.find(id
);
353 CHECK(it
!= m_resources
.end());
354 Resource
* resource
= &it
->second
;
355 DCHECK(!resource
->lockedForWrite
);
356 DCHECK(!resource
->exported
);
357 resource
->lockForReadCount
++;
361 void ResourceProvider::unlockForRead(ResourceId id
)
363 DCHECK(m_threadChecker
.CalledOnValidThread());
364 ResourceMap::iterator it
= m_resources
.find(id
);
365 CHECK(it
!= m_resources
.end());
366 Resource
* resource
= &it
->second
;
367 DCHECK(resource
->lockForReadCount
> 0);
368 DCHECK(!resource
->exported
);
369 resource
->lockForReadCount
--;
372 const ResourceProvider::Resource
* ResourceProvider::lockForWrite(ResourceId id
)
374 DCHECK(m_threadChecker
.CalledOnValidThread());
375 ResourceMap::iterator it
= m_resources
.find(id
);
376 CHECK(it
!= m_resources
.end());
377 Resource
* resource
= &it
->second
;
378 DCHECK(!resource
->lockedForWrite
);
379 DCHECK(!resource
->lockForReadCount
);
380 DCHECK(!resource
->exported
);
381 DCHECK(!resource
->external
);
382 resource
->lockedForWrite
= true;
386 void ResourceProvider::unlockForWrite(ResourceId id
)
388 DCHECK(m_threadChecker
.CalledOnValidThread());
389 ResourceMap::iterator it
= m_resources
.find(id
);
390 CHECK(it
!= m_resources
.end());
391 Resource
* resource
= &it
->second
;
392 DCHECK(resource
->lockedForWrite
);
393 DCHECK(!resource
->exported
);
394 DCHECK(!resource
->external
);
395 resource
->lockedForWrite
= false;
398 ResourceProvider::ScopedReadLockGL::ScopedReadLockGL(ResourceProvider
* resourceProvider
, ResourceProvider::ResourceId resourceId
)
399 : m_resourceProvider(resourceProvider
)
400 , m_resourceId(resourceId
)
401 , m_textureId(resourceProvider
->lockForRead(resourceId
)->glId
)
406 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL()
408 m_resourceProvider
->unlockForRead(m_resourceId
);
411 ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(ResourceProvider
* resourceProvider
, ResourceProvider::ResourceId resourceId
)
412 : m_resourceProvider(resourceProvider
)
413 , m_resourceId(resourceId
)
414 , m_textureId(resourceProvider
->lockForWrite(resourceId
)->glId
)
419 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL()
421 m_resourceProvider
->unlockForWrite(m_resourceId
);
424 void ResourceProvider::populateSkBitmapWithResource(SkBitmap
* skBitmap
, const Resource
* resource
)
426 DCHECK(resource
->pixels
);
427 DCHECK(resource
->format
== GL_RGBA
);
428 skBitmap
->setConfig(SkBitmap::kARGB_8888_Config
, resource
->size
.width(), resource
->size
.height());
429 skBitmap
->setPixels(resource
->pixels
);
432 ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(ResourceProvider
* resourceProvider
, ResourceProvider::ResourceId resourceId
)
433 : m_resourceProvider(resourceProvider
)
434 , m_resourceId(resourceId
)
436 ResourceProvider::populateSkBitmapWithResource(&m_skBitmap
, resourceProvider
->lockForRead(resourceId
));
439 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware()
441 m_resourceProvider
->unlockForRead(m_resourceId
);
444 ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(ResourceProvider
* resourceProvider
, ResourceProvider::ResourceId resourceId
)
445 : m_resourceProvider(resourceProvider
)
446 , m_resourceId(resourceId
)
448 ResourceProvider::populateSkBitmapWithResource(&m_skBitmap
, resourceProvider
->lockForWrite(resourceId
));
449 m_skCanvas
.reset(new SkCanvas(m_skBitmap
));
452 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware()
454 m_resourceProvider
->unlockForWrite(m_resourceId
);
457 ResourceProvider::ResourceProvider(GraphicsContext
* context
)
461 , m_defaultResourceType(GLTexture
)
462 , m_useTextureStorageExt(false)
463 , m_useTextureUsageHint(false)
464 , m_useShallowFlush(false)
465 , m_maxTextureSize(0)
469 bool ResourceProvider::initialize()
471 DCHECK(m_threadChecker
.CalledOnValidThread());
472 WebGraphicsContext3D
* context3d
= m_context
->context3D();
474 m_maxTextureSize
= INT_MAX
/ 2;
477 if (!context3d
->makeContextCurrent())
480 std::string extensionsString
= UTF16ToASCII(context3d
->getString(GL_EXTENSIONS
));
481 std::vector
<std::string
> extensions
;
482 base::SplitString(extensionsString
, ' ', &extensions
);
483 bool useMapSub
= false;
484 bool useBindUniform
= false;
485 for (size_t i
= 0; i
< extensions
.size(); ++i
) {
486 if (extensions
[i
] == "GL_EXT_texture_storage")
487 m_useTextureStorageExt
= true;
488 else if (extensions
[i
] == "GL_ANGLE_texture_usage")
489 m_useTextureUsageHint
= true;
490 else if (extensions
[i
] == "GL_CHROMIUM_map_sub")
492 else if (extensions
[i
] == "GL_CHROMIUM_shallow_flush")
493 m_useShallowFlush
= true;
494 else if (extensions
[i
] == "GL_CHROMIUM_bind_uniform_location")
495 useBindUniform
= true;
498 m_textureCopier
= AcceleratedTextureCopier::create(context3d
, useBindUniform
);
500 m_textureUploader
= TextureUploader::create(context3d
, useMapSub
, m_useShallowFlush
);
501 GLC(context3d
, context3d
->getIntegerv(GL_MAX_TEXTURE_SIZE
, &m_maxTextureSize
));
505 int ResourceProvider::createChild(int pool
)
507 DCHECK(m_threadChecker
.CalledOnValidThread());
509 childInfo
.pool
= pool
;
510 int child
= m_nextChild
++;
511 m_children
[child
] = childInfo
;
515 void ResourceProvider::destroyChild(int child
)
517 DCHECK(m_threadChecker
.CalledOnValidThread());
518 ChildMap::iterator it
= m_children
.find(child
);
519 DCHECK(it
!= m_children
.end());
520 deleteOwnedResources(it
->second
.pool
);
521 m_children
.erase(it
);
524 const ResourceProvider::ResourceIdMap
& ResourceProvider::getChildToParentMap(int child
) const
526 DCHECK(m_threadChecker
.CalledOnValidThread());
527 ChildMap::const_iterator it
= m_children
.find(child
);
528 DCHECK(it
!= m_children
.end());
529 return it
->second
.childToParentMap
;
532 void ResourceProvider::prepareSendToParent(const ResourceIdArray
& resources
, TransferableResourceList
* list
)
534 DCHECK(m_threadChecker
.CalledOnValidThread());
535 list
->sync_point
= 0;
536 list
->resources
.clear();
537 WebGraphicsContext3D
* context3d
= m_context
->context3D();
538 if (!context3d
|| !context3d
->makeContextCurrent()) {
539 // FIXME: Implement this path for software compositing.
542 for (ResourceIdArray::const_iterator it
= resources
.begin(); it
!= resources
.end(); ++it
) {
543 TransferableResource resource
;
544 if (transferResource(context3d
, *it
, &resource
)) {
545 m_resources
.find(*it
)->second
.exported
= true;
546 list
->resources
.push_back(resource
);
549 if (list
->resources
.size())
550 list
->sync_point
= context3d
->insertSyncPoint();
553 void ResourceProvider::prepareSendToChild(int child
, const ResourceIdArray
& resources
, TransferableResourceList
* list
)
555 DCHECK(m_threadChecker
.CalledOnValidThread());
556 list
->sync_point
= 0;
557 list
->resources
.clear();
558 WebGraphicsContext3D
* context3d
= m_context
->context3D();
559 if (!context3d
|| !context3d
->makeContextCurrent()) {
560 // FIXME: Implement this path for software compositing.
563 Child
& childInfo
= m_children
.find(child
)->second
;
564 for (ResourceIdArray::const_iterator it
= resources
.begin(); it
!= resources
.end(); ++it
) {
565 TransferableResource resource
;
566 if (!transferResource(context3d
, *it
, &resource
))
568 DCHECK(childInfo
.parentToChildMap
.find(*it
) != childInfo
.parentToChildMap
.end());
569 resource
.id
= childInfo
.parentToChildMap
[*it
];
570 childInfo
.parentToChildMap
.erase(*it
);
571 childInfo
.childToParentMap
.erase(resource
.id
);
572 list
->resources
.push_back(resource
);
575 if (list
->resources
.size())
576 list
->sync_point
= context3d
->insertSyncPoint();
579 void ResourceProvider::receiveFromChild(int child
, const TransferableResourceList
& resources
)
581 DCHECK(m_threadChecker
.CalledOnValidThread());
582 WebGraphicsContext3D
* context3d
= m_context
->context3D();
583 if (!context3d
|| !context3d
->makeContextCurrent()) {
584 // FIXME: Implement this path for software compositing.
587 if (resources
.sync_point
) {
588 // NOTE: If the parent is a browser and the child a renderer, the parent
589 // is not supposed to have its context wait, because that could induce
590 // deadlocks and/or security issues. The caller is responsible for
591 // waiting asynchronously, and resetting sync_point before calling this.
592 // However if the parent is a renderer (e.g. browser tag), it may be ok
593 // (and is simpler) to wait.
594 GLC(context3d
, context3d
->waitSyncPoint(resources
.sync_point
));
596 Child
& childInfo
= m_children
.find(child
)->second
;
597 for (TransferableResourceArray::const_iterator it
= resources
.resources
.begin(); it
!= resources
.resources
.end(); ++it
) {
599 GLC(context3d
, textureId
= context3d
->createTexture());
600 GLC(context3d
, context3d
->bindTexture(GL_TEXTURE_2D
, textureId
));
601 GLC(context3d
, context3d
->consumeTextureCHROMIUM(GL_TEXTURE_2D
, it
->mailbox
.name
));
602 ResourceId id
= m_nextId
++;
603 Resource
resource(textureId
, childInfo
.pool
, it
->size
, it
->format
);
604 resource
.mailbox
.setName(it
->mailbox
.name
);
605 m_resources
[id
] = resource
;
606 childInfo
.parentToChildMap
[id
] = it
->id
;
607 childInfo
.childToParentMap
[it
->id
] = id
;
611 void ResourceProvider::receiveFromParent(const TransferableResourceList
& resources
)
613 DCHECK(m_threadChecker
.CalledOnValidThread());
614 WebGraphicsContext3D
* context3d
= m_context
->context3D();
615 if (!context3d
|| !context3d
->makeContextCurrent()) {
616 // FIXME: Implement this path for software compositing.
619 if (resources
.sync_point
)
620 GLC(context3d
, context3d
->waitSyncPoint(resources
.sync_point
));
621 for (TransferableResourceArray::const_iterator it
= resources
.resources
.begin(); it
!= resources
.resources
.end(); ++it
) {
622 ResourceMap::iterator mapIterator
= m_resources
.find(it
->id
);
623 DCHECK(mapIterator
!= m_resources
.end());
624 Resource
* resource
= &mapIterator
->second
;
625 DCHECK(resource
->exported
);
626 resource
->exported
= false;
627 resource
->mailbox
.setName(it
->mailbox
.name
);
628 GLC(context3d
, context3d
->bindTexture(GL_TEXTURE_2D
, resource
->glId
));
629 GLC(context3d
, context3d
->consumeTextureCHROMIUM(GL_TEXTURE_2D
, it
->mailbox
.name
));
630 if (resource
->markedForDeletion
)
631 deleteResourceInternal(mapIterator
);
635 bool ResourceProvider::transferResource(WebGraphicsContext3D
* context
, ResourceId id
, TransferableResource
* resource
)
637 DCHECK(m_threadChecker
.CalledOnValidThread());
638 WebGraphicsContext3D
* context3d
= m_context
->context3D();
639 ResourceMap::iterator it
= m_resources
.find(id
);
640 CHECK(it
!= m_resources
.end());
641 Resource
* source
= &it
->second
;
642 DCHECK(!source
->lockedForWrite
);
643 DCHECK(!source
->lockForReadCount
);
644 DCHECK(!source
->external
);
645 if (source
->exported
)
648 resource
->format
= source
->format
;
649 resource
->size
= source
->size
;
651 if (source
->mailbox
.isZero()) {
652 GLbyte name
[GL_MAILBOX_SIZE_CHROMIUM
];
653 GLC(context3d
, context3d
->genMailboxCHROMIUM(name
));
654 source
->mailbox
.setName(name
);
657 resource
->mailbox
= source
->mailbox
;
658 GLC(context
, context
->bindTexture(GL_TEXTURE_2D
, source
->glId
));
659 GLC(context
, context
->produceTextureCHROMIUM(GL_TEXTURE_2D
, resource
->mailbox
.name
));