--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -329,22 +329,24 @@ DataTextureSourceD3D9::Update(gfx::DataS
// It will be ignored. Incremental update with a source offset is only used
// on Mac so it is not clear that we ever will need to support it for D3D.
MOZ_ASSERT(!aSrcOffset);
if (!mCompositor || !mCompositor->device()) {
NS_WARNING("No D3D device to update the texture.");
return false;
}
- mSize = aSurface->GetSize();
- uint32_t bpp = 0;
+ uint32_t bpp = BytesPerPixel(aSurface->GetFormat());
+ DeviceManagerD3D9* deviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
+
+ mSize = aSurface->GetSize();
+ mFormat = aSurface->GetFormat();
_D3DFORMAT format = D3DFMT_A8R8G8B8;
- mFormat = aSurface->GetFormat();
switch (mFormat) {
case SurfaceFormat::B8G8R8X8:
format = D3DFMT_X8R8G8B8;
bpp = 4;
break;
case SurfaceFormat::B8G8R8A8:
format = D3DFMT_A8R8G8B8;
bpp = 4;
@@ -354,49 +356,118 @@ DataTextureSourceD3D9::Update(gfx::DataS
bpp = 1;
break;
default:
NS_WARNING("Bad image format");
return false;
}
int32_t maxSize = mCompositor->GetMaxTextureSize();
- DeviceManagerD3D9* deviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
if ((mSize.width <= maxSize && mSize.height <= maxSize) ||
- (mFlags & TextureFlags::DISALLOW_BIGIMAGE)) {
- mTexture = DataToTexture(deviceManager,
- aSurface->GetData(), aSurface->Stride(),
- IntSize(mSize), format, bpp);
+ (mFlags & TextureFlags::DISALLOW_BIGIMAGE)) {
+
+ if (mTexture) {
+ D3DSURFACE_DESC currentDesc;
+ mTexture->GetLevelDesc(0, ¤tDesc);
+
+ // Make sure there's no size mismatch, if there is, recreate.
+ if (currentDesc.Width != mSize.width || currentDesc.Height != mSize.height ||
+ currentDesc.Format != format) {
+ mTexture = nullptr;
+ // Make sure we upload the whole surface.
+ aDestRegion = nullptr;
+ }
+ }
+
if (!mTexture) {
- NS_WARNING("Could not upload texture");
+ // TODO Improve: Reallocating this texture is costly enough
+ // that it causes us to skip frames on scrolling
+ // important pages like Facebook.
+ mTexture = deviceManager->CreateTexture(mSize, format, D3DPOOL_DEFAULT, this);
+ mIsTiled = false;
+ if (!mTexture) {
+ Reset();
+ return false;
+ }
+
+ if (mFlags & TextureFlags::COMPONENT_ALPHA) {
+ aDestRegion = nullptr;
+ }
+ }
+
+ DataSourceSurface::MappedSurface map;
+ if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
+ gfxCriticalError() << "Failed to map surface.";
Reset();
return false;
}
- mIsTiled = false;
- } else {
- mIsTiled = true;
- uint32_t tileCount = GetRequiredTilesD3D9(mSize.width, maxSize) *
- GetRequiredTilesD3D9(mSize.height, maxSize);
- mTileTextures.resize(tileCount);
- mTexture = nullptr;
+
+ nsIntRegion regionToUpdate = aDestRegion ? *aDestRegion : nsIntRegion(nsIntRect(0, 0, mSize.width, mSize.height));
+
+ RefPtr<IDirect3DSurface9> srcSurface;
+ HRESULT hr = mCompositor->device()->CreateOffscreenPlainSurface(mSize.width, mSize.height, format, D3DPOOL_SYSTEMMEM, getter_AddRefs(srcSurface), nullptr);
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ RefPtr<IDirect3DSurface9> destSurface;
+ mTexture->GetSurfaceLevel(0, getter_AddRefs(destSurface));
+
+ D3DLOCKED_RECT rect;
+ srcSurface->LockRect(&rect, nullptr, 0);
+
+ nsIntRegionRectIterator iter(regionToUpdate);
+ const IntRect *iterRect;
+ while ((iterRect = iter.Next())) {
+ uint8_t* src = map.mData + map.mStride * iterRect->y + BytesPerPixel(aSurface->GetFormat()) * iterRect->x;
+ uint8_t* dest = reinterpret_cast<uint8_t*>(rect.pBits) + rect.Pitch * iterRect->y + BytesPerPixel(aSurface->GetFormat()) * iterRect->x;
+
+ for (int y = 0; y < iterRect->height; y++) {
+ memcpy(dest + rect.Pitch * y,
+ src + map.mStride * y,
+ iterRect->width * bpp);
+ }
+ }
+
+ srcSurface->UnlockRect();
+ aSurface->Unmap();
- for (uint32_t i = 0; i < tileCount; i++) {
- IntRect tileRect = GetTileRect(i);
- unsigned char* data = aSurface->GetData() +
- tileRect.y * aSurface->Stride() +
- tileRect.x * bpp;
- mTileTextures[i] = DataToTexture(deviceManager,
- data,
- aSurface->Stride(),
- IntSize(tileRect.width, tileRect.height),
- format,
- bpp);
- if (!mTileTextures[i]) {
- NS_WARNING("Could not upload texture");
- Reset();
+ iter = nsIntRegionRectIterator(regionToUpdate);
+ while ((iterRect = iter.Next())) {
+
+ RECT updateRect;
+ updateRect.left = iterRect->x;
+ updateRect.top = iterRect->y;
+ updateRect.right = iterRect->XMost();
+ updateRect.bottom = iterRect->YMost();
+ POINT point = { updateRect.left, updateRect.top };
+
+ mCompositor->device()->UpdateSurface(srcSurface, &updateRect, destSurface, &point);
+ }
+ } else {
+ mIsTiled = true;
+ uint32_t tileCount = GetRequiredTilesD3D9(mSize.width, maxSize) *
+ GetRequiredTilesD3D9(mSize.height, maxSize);
+ mTileTextures.resize(tileCount);
+ mTexture = nullptr;
+
+ for (uint32_t i = 0; i < tileCount; i++) {
+ IntRect tileRect = GetTileRect(i);
+ unsigned char* data = aSurface->GetData() +
+ tileRect.y * aSurface->Stride() +
+ tileRect.x * bpp;
+ mTileTextures[i] = DataToTexture(deviceManager,
+ data,
+ aSurface->Stride(),
+ IntSize(tileRect.width, tileRect.height),
+ format,
+ bpp);
+ if (!mTileTextures[i]) {
+ NS_WARNING("Could not upload texture");
+ Reset();
return false;
}
}
}
return true;
}