diff options
Diffstat (limited to 'cc')
-rw-r--r-- | cc/heads_up_display_layer_impl.cc | 8 | ||||
-rw-r--r-- | cc/layer_tree_host_impl_unittest.cc | 15 | ||||
-rw-r--r-- | cc/resource_provider.cc | 86 | ||||
-rw-r--r-- | cc/resource_provider.h | 6 | ||||
-rw-r--r-- | cc/resource_provider_unittest.cc | 74 |
5 files changed, 169 insertions, 20 deletions
diff --git a/cc/heads_up_display_layer_impl.cc b/cc/heads_up_display_layer_impl.cc index 73f99d0..dd8f413 100644 --- a/cc/heads_up_display_layer_impl.cc +++ b/cc/heads_up_display_layer_impl.cc @@ -76,8 +76,14 @@ void HeadsUpDisplayLayerImpl::willDraw(ResourceProvider* resourceProvider) if (m_hudTexture->size() != bounds()) m_hudTexture->Free(); - if (!m_hudTexture->id()) + if (!m_hudTexture->id()) { m_hudTexture->Allocate(bounds(), GL_RGBA, ResourceProvider::TextureUsageAny); + // TODO(epenner): This texture was being used before setPixels was called, + // which is now not allowed (it's an uninitialized read). This should be fixed + // and this allocateForTesting() removed. + // http://crbug.com/166784 + resourceProvider->allocateForTesting(m_hudTexture->id()); + } } void HeadsUpDisplayLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQuadsData) diff --git a/cc/layer_tree_host_impl_unittest.cc b/cc/layer_tree_host_impl_unittest.cc index 992ae71..876847b 100644 --- a/cc/layer_tree_host_impl_unittest.cc +++ b/cc/layer_tree_host_impl_unittest.cc @@ -1055,6 +1055,7 @@ private: setSkipsDraw(skipsDraw); if (!tileMissing) { ResourceProvider::ResourceId resource = resourceProvider->createResource(gfx::Size(), GL_RGBA, ResourceProvider::TextureUsageAny); + resourceProvider->allocateForTesting(resource); pushTileProperties(0, 0, resource, gfx::Rect(), false); } if (animating) @@ -1680,6 +1681,7 @@ private: , m_quadVisibleRect(5, 5, 5, 5) , m_resourceId(resourceProvider->createResource(gfx::Size(1, 1), GL_RGBA, ResourceProvider::TextureUsageAny)) { + resourceProvider->allocateForTesting(m_resourceId); setAnchorPoint(gfx::PointF(0, 0)); setBounds(gfx::Size(10, 10)); setContentBounds(gfx::Size(10, 10)); @@ -2754,9 +2756,15 @@ public: ResourceProvider::TextureUsageHint hint = ResourceProvider::TextureUsageAny; setScrollbarGeometry(ScrollbarGeometryFixedThumb::create(FakeWebScrollbarThemeGeometryNonEmpty::create())); - setBackTrackResourceId(provider->createResource(size, format, hint)); - setForeTrackResourceId(provider->createResource(size, format, hint)); - setThumbResourceId(provider->createResource(size, format, hint)); + ResourceProvider::ResourceId backId = provider->createResource(size, format, hint); + ResourceProvider::ResourceId foreId = provider->createResource(size, format, hint); + ResourceProvider::ResourceId thumbId = provider->createResource(size, format, hint); + provider->allocateForTesting(backId); + provider->allocateForTesting(foreId); + provider->allocateForTesting(thumbId); + setBackTrackResourceId(backId); + setForeTrackResourceId(foreId); + setThumbResourceId(thumbId); } protected: @@ -2769,6 +2777,7 @@ protected: static inline scoped_ptr<RenderPass> createRenderPassWithResource(ResourceProvider* provider) { ResourceProvider::ResourceId resourceId = provider->createResource(gfx::Size(1, 1), GL_RGBA, ResourceProvider::TextureUsageAny); + provider->allocateForTesting(resourceId); scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); pass->SetNew(RenderPass::Id(1, 1), gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1), gfx::Transform()); diff --git a/cc/resource_provider.cc b/cc/resource_provider.cc index 2cbafae..8b7081c 100644 --- a/cc/resource_provider.cc +++ b/cc/resource_provider.cc @@ -59,6 +59,7 @@ ResourceProvider::Resource::Resource() , exported(false) , markedForDeletion(false) , pendingSetPixels(false) + , allocated(false) , size() , format(0) , filter(0) @@ -78,6 +79,7 @@ ResourceProvider::Resource::Resource(unsigned textureId, const gfx::Size& size, , exported(false) , markedForDeletion(false) , pendingSetPixels(false) + , allocated(false) , size(size) , format(format) , filter(filter) @@ -97,6 +99,7 @@ ResourceProvider::Resource::Resource(uint8_t* pixels, const gfx::Size& size, GLe , exported(false) , markedForDeletion(false) , pendingSetPixels(false) + , allocated(false) , size(size) , format(format) , filter(filter) @@ -183,22 +186,19 @@ ResourceProvider::ResourceId ResourceProvider::createGLTexture(const gfx::Size& DCHECK(context3d); GLC(context3d, textureId = context3d->createTexture()); GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, textureId)); + + // Set texture properties. Allocation is delayed until needed. GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_POOL_CHROMIUM, texturePool)); - if (m_useTextureUsageHint && hint == TextureUsageFramebuffer) GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE)); - if (m_useTextureStorageExt && isTextureFormatSupportedForStorage(format)) { - GLenum storageFormat = textureToStorageFormat(format); - GLC(context3d, context3d->texStorage2DEXT(GL_TEXTURE_2D, 1, storageFormat, size.width(), size.height())); - } else - GLC(context3d, context3d->texImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0, format, GL_UNSIGNED_BYTE, 0)); ResourceId id = m_nextId++; Resource resource(textureId, size, format, GL_LINEAR); + resource.allocated = false; m_resources[id] = resource; return id; } @@ -211,6 +211,7 @@ ResourceProvider::ResourceId ResourceProvider::createBitmap(const gfx::Size& siz ResourceId id = m_nextId++; Resource resource(pixels, size, GL_RGBA, GL_LINEAR); + resource.allocated = true; m_resources[id] = resource; return id; } @@ -230,6 +231,7 @@ ResourceProvider::ResourceId ResourceProvider::createResourceFromExternalTexture ResourceId id = m_nextId++; Resource resource(textureId, gfx::Size(), 0, GL_LINEAR); resource.external = true; + resource.allocated = true; m_resources[id] = resource; return id; } @@ -240,9 +242,9 @@ void ResourceProvider::deleteResource(ResourceId id) ResourceMap::iterator it = m_resources.find(id); CHECK(it != m_resources.end()); Resource* resource = &it->second; - DCHECK(!resource->lockedForWrite); DCHECK(!resource->lockForReadCount); DCHECK(!resource->markedForDeletion); + DCHECK(resource->pendingSetPixels || !resource->lockedForWrite); if (resource->exported) { resource->markedForDeletion = true; @@ -295,8 +297,10 @@ void ResourceProvider::setPixels(ResourceId id, const uint8_t* image, const gfx: DCHECK(!resource->lockForReadCount); DCHECK(!resource->external); DCHECK(!resource->exported); + lazyAllocate(resource); if (resource->glId) { + DCHECK(!resource->pendingSetPixels); WebGraphicsContext3D* context3d = m_outputSurface->Context3D(); DCHECK(context3d); DCHECK(m_textureUploader.get()); @@ -310,6 +314,7 @@ void ResourceProvider::setPixels(ResourceId id, const uint8_t* image, const gfx: } if (resource->pixels) { + DCHECK(resource->allocated); DCHECK(resource->format == GL_RGBA); SkBitmap srcFull; srcFull.setConfig(SkBitmap::kARGB_8888_Config, imageRect.width(), imageRect.height()); @@ -384,6 +389,8 @@ const ResourceProvider::Resource* ResourceProvider::lockForRead(ResourceId id) Resource* resource = &it->second; DCHECK(!resource->lockedForWrite); DCHECK(!resource->exported); + DCHECK(resource->allocated); // Uninitialized! Call setPixels or lockForWrite first. + resource->lockForReadCount++; return resource; } @@ -409,6 +416,8 @@ const ResourceProvider::Resource* ResourceProvider::lockForWrite(ResourceId id) DCHECK(!resource->lockForReadCount); DCHECK(!resource->exported); DCHECK(!resource->external); + lazyAllocate(resource); + resource->lockedForWrite = true; return resource; } @@ -645,6 +654,8 @@ void ResourceProvider::receiveFromChild(int child, const TransferableResourceLis ResourceId id = m_nextId++; Resource resource(textureId, it->size, it->format, it->filter); resource.mailbox.setName(it->mailbox.name); + // Don't allocate a texture for a child. + resource.allocated = true; m_resources[id] = resource; childInfo.parentToChildMap[id] = it->id; childInfo.childToParentMap[it->id] = id; @@ -685,6 +696,7 @@ bool ResourceProvider::transferResource(WebGraphicsContext3D* context, ResourceI DCHECK(!source->lockedForWrite); DCHECK(!source->lockForReadCount); DCHECK(!source->external); + DCHECK(source->allocated); if (source->exported) return false; resource->id = id; @@ -832,6 +844,7 @@ void ResourceProvider::setPixelsFromBuffer(ResourceId id) DCHECK(!resource->lockForReadCount); DCHECK(!resource->external); DCHECK(!resource->exported); + lazyAllocate(resource); if (resource->glId) { WebGraphicsContext3D* context3d = m_outputSurface->Context3D(); @@ -893,7 +906,10 @@ void ResourceProvider::beginSetPixels(ResourceId id) CHECK(it != m_resources.end()); Resource* resource = &it->second; DCHECK(!resource->pendingSetPixels); + DCHECK(resource->glId || resource->allocated); + bool allocate = !resource->allocated; + resource->allocated = true; lockForWrite(id); if (resource->glId) { @@ -909,15 +925,27 @@ void ResourceProvider::beginSetPixels(ResourceId id) context3d->beginQueryEXT( GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM, resource->glUploadQueryId); - context3d->asyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D, - 0, /* level */ - 0, /* x */ - 0, /* y */ - resource->size.width(), - resource->size.height(), - resource->format, - GL_UNSIGNED_BYTE, - NULL); + if (allocate) { + context3d->asyncTexImage2DCHROMIUM(GL_TEXTURE_2D, + 0, /* level */ + resource->format, + resource->size.width(), + resource->size.height(), + 0, /* border */ + resource->format, + GL_UNSIGNED_BYTE, + NULL); + } else { + context3d->asyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D, + 0, /* level */ + 0, /* x */ + 0, /* y */ + resource->size.width(), + resource->size.height(), + resource->format, + GL_UNSIGNED_BYTE, + NULL); + } context3d->endQueryEXT(GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM); context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); } @@ -955,4 +983,30 @@ bool ResourceProvider::didSetPixelsComplete(ResourceId id) { return true; } +void ResourceProvider::allocateForTesting(ResourceId id) { + ResourceMap::iterator it = m_resources.find(id); + CHECK(it != m_resources.end()); + Resource* resource = &it->second; + lazyAllocate(resource); +} + +void ResourceProvider::lazyAllocate(Resource* resource) { + DCHECK(resource); + DCHECK(resource->glId || resource->allocated); + + if (resource->allocated || !resource->glId) + return; + + resource->allocated = true; + WebGraphicsContext3D* context3d = m_outputSurface->Context3D(); + gfx::Size& size = resource->size; + GLenum format = resource->format; + if (m_useTextureStorageExt && isTextureFormatSupportedForStorage(format)) { + GLenum storageFormat = textureToStorageFormat(format); + GLC(context3d, context3d->texStorage2DEXT(GL_TEXTURE_2D, 1, storageFormat, size.width(), size.height())); + } else + GLC(context3d, context3d->texImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0, format, GL_UNSIGNED_BYTE, 0)); +} + + } // namespace cc diff --git a/cc/resource_provider.h b/cc/resource_provider.h index d90d224..9b5b54b 100644 --- a/cc/resource_provider.h +++ b/cc/resource_provider.h @@ -230,6 +230,10 @@ public: void beginSetPixels(ResourceId id); bool didSetPixelsComplete(ResourceId id); + // For tests only! This prevents detecting uninitialized reads. + // Use setPixels or lockForWrite to allocate implicitly. + void allocateForTesting(ResourceId id); + private: struct Resource { Resource(); @@ -250,6 +254,7 @@ private: bool exported; bool markedForDeletion; bool pendingSetPixels; + bool allocated; gfx::Size size; GLenum format; // TODO(skyostil): Use a separate sampler object for filter state. @@ -277,6 +282,7 @@ private: bool transferResource(WebKit::WebGraphicsContext3D*, ResourceId, TransferableResource*); void deleteResourceInternal(ResourceMap::iterator it); + void lazyAllocate(Resource*); OutputSurface* m_outputSurface; ResourceId m_nextId; diff --git a/cc/resource_provider_unittest.cc b/cc/resource_provider_unittest.cc index 0a737e5..f57061a 100644 --- a/cc/resource_provider_unittest.cc +++ b/cc/resource_provider_unittest.cc @@ -20,6 +20,9 @@ using namespace WebKit; using testing::Mock; +using testing::StrictMock; +using testing::NiceMock; +using testing::_; namespace cc { namespace { @@ -587,6 +590,7 @@ TEST_P(ResourceProviderTest, ScopedSampler) EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_POOL_CHROMIUM, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM)); ResourceProvider::ResourceId id = resourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny); + resourceProvider->allocateForTesting(id); // Creating a sampler with the default filter should not change any texture // parameters. @@ -640,6 +644,76 @@ TEST_P(ResourceProviderTest, ManagedResource) Mock::VerifyAndClearExpectations(context); } +class AllocationTrackingContext3D : public FakeWebGraphicsContext3D { +public: + MOCK_METHOD9(texImage2D, void(WGC3Denum target, WGC3Dint level, WGC3Denum internalformat, + WGC3Dsizei width, WGC3Dsizei height, WGC3Dint border, WGC3Denum format, + WGC3Denum type, const void* pixels)); + MOCK_METHOD9(texSubImage2D, void(WGC3Denum target, WGC3Dint level, WGC3Dint xoffset, WGC3Dint yoffset, + WGC3Dsizei width, WGC3Dsizei height, WGC3Denum format, + WGC3Denum type, const void* pixels)); + MOCK_METHOD9(asyncTexImage2DCHROMIUM, void(WGC3Denum target, WGC3Dint level, WGC3Denum internalformat, + WGC3Dsizei width, WGC3Dsizei height, WGC3Dint border, WGC3Denum format, + WGC3Denum type, const void* pixels)); + MOCK_METHOD9(asyncTexSubImage2DCHROMIUM, void(WGC3Denum target, WGC3Dint level, WGC3Dint xoffset, WGC3Dint yoffset, + WGC3Dsizei width, WGC3Dsizei height, WGC3Denum format, + WGC3Denum type, const void* pixels)); +}; + +TEST_P(ResourceProviderTest, TextureAllocation) +{ + // Only for GL textures. + if (GetParam() != ResourceProvider::GLTexture) + return; + scoped_ptr<WebKit::WebGraphicsContext3D> mock_context( + static_cast<WebKit::WebGraphicsContext3D*>(new NiceMock<AllocationTrackingContext3D>)); + scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(mock_context.Pass())); + + gfx::Size size(2, 2); + gfx::Vector2d offset(0, 0); + gfx::Rect rect(0, 0, 2, 2); + WGC3Denum format = GL_RGBA; + ResourceProvider::ResourceId id = 0; + uint8_t pixels[16] = {0}; + + AllocationTrackingContext3D* context = static_cast<AllocationTrackingContext3D*>(outputSurface->Context3D()); + scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::create(outputSurface.get())); + + // Lazy allocation. Don't allocate when creating the resource. + EXPECT_CALL(*context, texImage2D(_,_,_,_,_,_,_,_,_)).Times(0); + EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_,_,_,_,_,_,_,_,_)).Times(0); + id = resourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny); + resourceProvider->deleteResource(id); + Mock::VerifyAndClearExpectations(context); + + // Do allocate when we set the pixels. + EXPECT_CALL(*context, texImage2D(_,_,_,2,2,_,_,_,_)).Times(1); + EXPECT_CALL(*context, texSubImage2D(_,_,_,_,2,2,_,_,_)).Times(1); + id = resourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny); + resourceProvider->setPixels(id, pixels, rect, rect, offset); + resourceProvider->deleteResource(id); + Mock::VerifyAndClearExpectations(context); + + // Same for setPixelsFromBuffer + EXPECT_CALL(*context, texImage2D(_,_,_,2,2,_,_,_,_)).Times(1); + EXPECT_CALL(*context, texSubImage2D(_,_,_,_,2,2,_,_,_)).Times(1); + id = resourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny); + resourceProvider->acquirePixelBuffer(id); + resourceProvider->setPixelsFromBuffer(id); + resourceProvider->releasePixelBuffer(id); + resourceProvider->deleteResource(id); + Mock::VerifyAndClearExpectations(context); + + // Same for async version. + EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_,_,_,2,2,_,_,_,_)).Times(1); + id = resourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny); + resourceProvider->acquirePixelBuffer(id); + resourceProvider->beginSetPixels(id); + resourceProvider->releasePixelBuffer(id); + resourceProvider->deleteResource(id); + Mock::VerifyAndClearExpectations(context); +} + INSTANTIATE_TEST_CASE_P(ResourceProviderTests, ResourceProviderTest, ::testing::Values(ResourceProvider::GLTexture, |