1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/d3d11/TextureD3D11.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,470 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "TextureD3D11.h" 1.10 +#include "CompositorD3D11.h" 1.11 +#include "gfxContext.h" 1.12 +#include "Effects.h" 1.13 +#include "mozilla/layers/YCbCrImageDataSerializer.h" 1.14 +#include "gfxWindowsPlatform.h" 1.15 +#include "gfxD2DSurface.h" 1.16 +#include "gfx2DGlue.h" 1.17 + 1.18 +namespace mozilla { 1.19 + 1.20 +using namespace gfx; 1.21 + 1.22 +namespace layers { 1.23 + 1.24 +static DXGI_FORMAT 1.25 +SurfaceFormatToDXGIFormat(gfx::SurfaceFormat aFormat) 1.26 +{ 1.27 + switch (aFormat) { 1.28 + case SurfaceFormat::B8G8R8A8: 1.29 + return DXGI_FORMAT_B8G8R8A8_UNORM; 1.30 + case SurfaceFormat::B8G8R8X8: 1.31 + return DXGI_FORMAT_B8G8R8A8_UNORM; 1.32 + case SurfaceFormat::A8: 1.33 + return DXGI_FORMAT_A8_UNORM; 1.34 + default: 1.35 + MOZ_ASSERT(false, "unsupported format"); 1.36 + return DXGI_FORMAT_UNKNOWN; 1.37 + } 1.38 +} 1.39 + 1.40 +static uint32_t 1.41 +GetRequiredTilesD3D11(uint32_t aSize, uint32_t aMaxSize) 1.42 +{ 1.43 + uint32_t requiredTiles = aSize / aMaxSize; 1.44 + if (aSize % aMaxSize) { 1.45 + requiredTiles++; 1.46 + } 1.47 + return requiredTiles; 1.48 +} 1.49 + 1.50 +static IntRect 1.51 +GetTileRectD3D11(uint32_t aID, IntSize aSize, uint32_t aMaxSize) 1.52 +{ 1.53 + uint32_t horizontalTiles = GetRequiredTilesD3D11(aSize.width, aMaxSize); 1.54 + uint32_t verticalTiles = GetRequiredTilesD3D11(aSize.height, aMaxSize); 1.55 + 1.56 + uint32_t verticalTile = aID / horizontalTiles; 1.57 + uint32_t horizontalTile = aID % horizontalTiles; 1.58 + 1.59 + return IntRect(horizontalTile * aMaxSize, 1.60 + verticalTile * aMaxSize, 1.61 + horizontalTile < (horizontalTiles - 1) ? aMaxSize : aSize.width % aMaxSize, 1.62 + verticalTile < (verticalTiles - 1) ? aMaxSize : aSize.height % aMaxSize); 1.63 +} 1.64 + 1.65 +DataTextureSourceD3D11::DataTextureSourceD3D11(SurfaceFormat aFormat, 1.66 + CompositorD3D11* aCompositor, 1.67 + TextureFlags aFlags) 1.68 + : mCompositor(aCompositor) 1.69 + , mFormat(aFormat) 1.70 + , mFlags(aFlags) 1.71 + , mCurrentTile(0) 1.72 + , mIsTiled(false) 1.73 + , mIterating(false) 1.74 +{ 1.75 + MOZ_COUNT_CTOR(DataTextureSourceD3D11); 1.76 +} 1.77 + 1.78 +DataTextureSourceD3D11::DataTextureSourceD3D11(SurfaceFormat aFormat, 1.79 + CompositorD3D11* aCompositor, 1.80 + ID3D11Texture2D* aTexture) 1.81 +: mCompositor(aCompositor) 1.82 +, mFormat(aFormat) 1.83 +, mFlags(0) 1.84 +, mCurrentTile(0) 1.85 +, mIsTiled(false) 1.86 +, mIterating(false) 1.87 +{ 1.88 + MOZ_COUNT_CTOR(DataTextureSourceD3D11); 1.89 + 1.90 + mTexture = aTexture; 1.91 + D3D11_TEXTURE2D_DESC desc; 1.92 + aTexture->GetDesc(&desc); 1.93 + 1.94 + mSize = IntSize(desc.Width, desc.Height); 1.95 +} 1.96 + 1.97 + 1.98 + 1.99 +DataTextureSourceD3D11::~DataTextureSourceD3D11() 1.100 +{ 1.101 + MOZ_COUNT_DTOR(DataTextureSourceD3D11); 1.102 +} 1.103 + 1.104 + 1.105 +template<typename T> // ID3D10Texture2D or ID3D11Texture2D 1.106 +static void LockD3DTexture(T* aTexture) 1.107 +{ 1.108 + MOZ_ASSERT(aTexture); 1.109 + RefPtr<IDXGIKeyedMutex> mutex; 1.110 + aTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex)); 1.111 + if (mutex) { 1.112 + mutex->AcquireSync(0, INFINITE); 1.113 + } 1.114 +} 1.115 + 1.116 +template<typename T> // ID3D10Texture2D or ID3D11Texture2D 1.117 +static void UnlockD3DTexture(T* aTexture) 1.118 +{ 1.119 + MOZ_ASSERT(aTexture); 1.120 + RefPtr<IDXGIKeyedMutex> mutex; 1.121 + aTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex)); 1.122 + if (mutex) { 1.123 + mutex->ReleaseSync(0); 1.124 + } 1.125 +} 1.126 + 1.127 +TemporaryRef<TextureHost> 1.128 +CreateTextureHostD3D11(const SurfaceDescriptor& aDesc, 1.129 + ISurfaceAllocator* aDeallocator, 1.130 + TextureFlags aFlags) 1.131 +{ 1.132 + RefPtr<TextureHost> result; 1.133 + switch (aDesc.type()) { 1.134 + case SurfaceDescriptor::TSurfaceDescriptorShmem: 1.135 + case SurfaceDescriptor::TSurfaceDescriptorMemory: { 1.136 + result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags); 1.137 + break; 1.138 + } 1.139 + case SurfaceDescriptor::TSurfaceDescriptorD3D10: { 1.140 + result = new DXGITextureHostD3D11(aFlags, 1.141 + aDesc.get_SurfaceDescriptorD3D10()); 1.142 + break; 1.143 + } 1.144 + default: { 1.145 + NS_WARNING("Unsupported SurfaceDescriptor type"); 1.146 + } 1.147 + } 1.148 + return result; 1.149 +} 1.150 + 1.151 +TextureClientD3D11::TextureClientD3D11(gfx::SurfaceFormat aFormat, TextureFlags aFlags) 1.152 + : TextureClient(aFlags) 1.153 + , mFormat(aFormat) 1.154 + , mIsLocked(false) 1.155 + , mNeedsClear(false) 1.156 +{} 1.157 + 1.158 +TextureClientD3D11::~TextureClientD3D11() 1.159 +{ 1.160 +#ifdef DEBUG 1.161 + // An Azure DrawTarget needs to be locked when it gets nullptr'ed as this is 1.162 + // when it calls EndDraw. This EndDraw should not execute anything so it 1.163 + // shouldn't -really- need the lock but the debug layer chokes on this. 1.164 + if (mDrawTarget) { 1.165 + MOZ_ASSERT(!mIsLocked); 1.166 + MOZ_ASSERT(mTexture); 1.167 + MOZ_ASSERT(mDrawTarget->refCount() == 1); 1.168 + LockD3DTexture(mTexture.get()); 1.169 + mDrawTarget = nullptr; 1.170 + UnlockD3DTexture(mTexture.get()); 1.171 + } 1.172 +#endif 1.173 +} 1.174 + 1.175 +bool 1.176 +TextureClientD3D11::Lock(OpenMode aMode) 1.177 +{ 1.178 + if (!mTexture) { 1.179 + return false; 1.180 + } 1.181 + MOZ_ASSERT(!mIsLocked, "The Texture is already locked!"); 1.182 + LockD3DTexture(mTexture.get()); 1.183 + mIsLocked = true; 1.184 + 1.185 + if (mNeedsClear) { 1.186 + mDrawTarget = GetAsDrawTarget(); 1.187 + mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height)); 1.188 + mNeedsClear = false; 1.189 + } 1.190 + 1.191 + return true; 1.192 +} 1.193 + 1.194 +void 1.195 +TextureClientD3D11::Unlock() 1.196 +{ 1.197 + MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!"); 1.198 + 1.199 + if (mDrawTarget) { 1.200 + // see the comment on TextureClient::GetAsDrawTarget. 1.201 + // This DrawTarget is internal to the TextureClient and is only exposed to the 1.202 + // outside world between Lock() and Unlock(). This assertion checks that no outside 1.203 + // reference remains by the time Unlock() is called. 1.204 + MOZ_ASSERT(mDrawTarget->refCount() == 1); 1.205 + mDrawTarget->Flush(); 1.206 + } 1.207 + 1.208 + // The DrawTarget is created only once, and is only usable between calls 1.209 + // to Lock and Unlock. 1.210 + UnlockD3DTexture(mTexture.get()); 1.211 + mIsLocked = false; 1.212 +} 1.213 + 1.214 +TemporaryRef<DrawTarget> 1.215 +TextureClientD3D11::GetAsDrawTarget() 1.216 +{ 1.217 + MOZ_ASSERT(mIsLocked, "Calling TextureClient::GetAsDrawTarget without locking :("); 1.218 + 1.219 + if (!mTexture) { 1.220 + return nullptr; 1.221 + } 1.222 + 1.223 + if (mDrawTarget) { 1.224 + return mDrawTarget; 1.225 + } 1.226 + 1.227 + mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture, mFormat); 1.228 + return mDrawTarget; 1.229 +} 1.230 + 1.231 +bool 1.232 +TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags) 1.233 +{ 1.234 + mSize = aSize; 1.235 + ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device(); 1.236 + 1.237 + CD3D10_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM, 1.238 + aSize.width, aSize.height, 1, 1, 1.239 + D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE); 1.240 + 1.241 + newDesc.MiscFlags = D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX; 1.242 + 1.243 + HRESULT hr = device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture)); 1.244 + 1.245 + if (FAILED(hr)) { 1.246 + LOGD3D11("Error creating texture for client!"); 1.247 + return false; 1.248 + } 1.249 + 1.250 + // Defer clearing to the next time we lock to avoid an extra (expensive) lock. 1.251 + mNeedsClear = aFlags & ALLOC_CLEAR_BUFFER; 1.252 + 1.253 + return true; 1.254 +} 1.255 + 1.256 +bool 1.257 +TextureClientD3D11::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) 1.258 +{ 1.259 + if (!IsAllocated()) { 1.260 + return false; 1.261 + } 1.262 + 1.263 + RefPtr<IDXGIResource> resource; 1.264 + mTexture->QueryInterface((IDXGIResource**)byRef(resource)); 1.265 + HANDLE sharedHandle; 1.266 + HRESULT hr = resource->GetSharedHandle(&sharedHandle); 1.267 + 1.268 + if (FAILED(hr)) { 1.269 + LOGD3D11("Error getting shared handle for texture."); 1.270 + return false; 1.271 + } 1.272 + 1.273 + aOutDescriptor = SurfaceDescriptorD3D10((WindowsHandle)sharedHandle, mFormat, mSize); 1.274 + return true; 1.275 +} 1.276 + 1.277 +DXGITextureHostD3D11::DXGITextureHostD3D11(TextureFlags aFlags, 1.278 + const SurfaceDescriptorD3D10& aDescriptor) 1.279 + : TextureHost(aFlags) 1.280 + , mHandle(aDescriptor.handle()) 1.281 + , mFormat(aDescriptor.format()) 1.282 + , mIsLocked(false) 1.283 +{} 1.284 + 1.285 +ID3D11Device* 1.286 +DXGITextureHostD3D11::GetDevice() 1.287 +{ 1.288 + return mCompositor ? mCompositor->GetDevice() : nullptr; 1.289 +} 1.290 + 1.291 +void 1.292 +DXGITextureHostD3D11::SetCompositor(Compositor* aCompositor) 1.293 +{ 1.294 + mCompositor = static_cast<CompositorD3D11*>(aCompositor); 1.295 +} 1.296 + 1.297 +bool 1.298 +DXGITextureHostD3D11::Lock() 1.299 +{ 1.300 + if (!GetDevice()) { 1.301 + NS_WARNING("trying to lock a TextureHost without a D3D device"); 1.302 + return false; 1.303 + } 1.304 + if (!mTextureSource) { 1.305 + RefPtr<ID3D11Texture2D> tex; 1.306 + HRESULT hr = GetDevice()->OpenSharedResource((HANDLE)mHandle, 1.307 + __uuidof(ID3D11Texture2D), 1.308 + (void**)(ID3D11Texture2D**)byRef(tex)); 1.309 + if (FAILED(hr)) { 1.310 + NS_WARNING("Failed to open shared texture"); 1.311 + return false; 1.312 + } 1.313 + 1.314 + mTextureSource = new DataTextureSourceD3D11(mFormat, mCompositor, tex); 1.315 + D3D11_TEXTURE2D_DESC desc; 1.316 + tex->GetDesc(&desc); 1.317 + mSize = IntSize(desc.Width, desc.Height); 1.318 + } 1.319 + 1.320 + LockD3DTexture(mTextureSource->GetD3D11Texture()); 1.321 + 1.322 + mIsLocked = true; 1.323 + return true; 1.324 +} 1.325 + 1.326 +void 1.327 +DXGITextureHostD3D11::Unlock() 1.328 +{ 1.329 + MOZ_ASSERT(mIsLocked); 1.330 + UnlockD3DTexture(mTextureSource->GetD3D11Texture()); 1.331 + mIsLocked = false; 1.332 +} 1.333 + 1.334 +NewTextureSource* 1.335 +DXGITextureHostD3D11::GetTextureSources() 1.336 +{ 1.337 + return mTextureSource.get(); 1.338 +} 1.339 + 1.340 +bool 1.341 +DataTextureSourceD3D11::Update(DataSourceSurface* aSurface, 1.342 + nsIntRegion* aDestRegion, 1.343 + IntPoint* aSrcOffset) 1.344 +{ 1.345 + // Right now we only support full surface update. If aDestRegion is provided, 1.346 + // It will be ignored. Incremental update with a source offset is only used 1.347 + // on Mac so it is not clear that we ever will need to support it for D3D. 1.348 + MOZ_ASSERT(!aSrcOffset); 1.349 + MOZ_ASSERT(aSurface); 1.350 + 1.351 + if (!mCompositor || !mCompositor->GetDevice()) { 1.352 + return false; 1.353 + } 1.354 + 1.355 + uint32_t bpp = BytesPerPixel(aSurface->GetFormat()); 1.356 + DXGI_FORMAT dxgiFormat = SurfaceFormatToDXGIFormat(aSurface->GetFormat()); 1.357 + 1.358 + mSize = aSurface->GetSize(); 1.359 + mFormat = aSurface->GetFormat(); 1.360 + 1.361 + CD3D11_TEXTURE2D_DESC desc(dxgiFormat, mSize.width, mSize.height, 1.362 + 1, 1, D3D11_BIND_SHADER_RESOURCE, 1.363 + D3D11_USAGE_IMMUTABLE); 1.364 + 1.365 + int32_t maxSize = mCompositor->GetMaxTextureSize(); 1.366 + if ((mSize.width <= maxSize && mSize.height <= maxSize) || 1.367 + (mFlags & TEXTURE_DISALLOW_BIGIMAGE)) { 1.368 + D3D11_SUBRESOURCE_DATA initData; 1.369 + initData.pSysMem = aSurface->GetData(); 1.370 + initData.SysMemPitch = aSurface->Stride(); 1.371 + 1.372 + mCompositor->GetDevice()->CreateTexture2D(&desc, &initData, byRef(mTexture)); 1.373 + mIsTiled = false; 1.374 + if (!mTexture) { 1.375 + Reset(); 1.376 + return false; 1.377 + } 1.378 + } else { 1.379 + mIsTiled = true; 1.380 + uint32_t tileCount = GetRequiredTilesD3D11(mSize.width, maxSize) * 1.381 + GetRequiredTilesD3D11(mSize.height, maxSize); 1.382 + 1.383 + mTileTextures.resize(tileCount); 1.384 + mTexture = nullptr; 1.385 + 1.386 + for (uint32_t i = 0; i < tileCount; i++) { 1.387 + IntRect tileRect = GetTileRect(i); 1.388 + 1.389 + desc.Width = tileRect.width; 1.390 + desc.Height = tileRect.height; 1.391 + 1.392 + D3D11_SUBRESOURCE_DATA initData; 1.393 + initData.pSysMem = aSurface->GetData() + 1.394 + tileRect.y * aSurface->Stride() + 1.395 + tileRect.x * bpp; 1.396 + initData.SysMemPitch = aSurface->Stride(); 1.397 + 1.398 + mCompositor->GetDevice()->CreateTexture2D(&desc, &initData, byRef(mTileTextures[i])); 1.399 + if (!mTileTextures[i]) { 1.400 + Reset(); 1.401 + return false; 1.402 + } 1.403 + } 1.404 + } 1.405 + return true; 1.406 +} 1.407 + 1.408 +ID3D11Texture2D* 1.409 +DataTextureSourceD3D11::GetD3D11Texture() const 1.410 +{ 1.411 + return mIterating ? mTileTextures[mCurrentTile] 1.412 + : mTexture; 1.413 +} 1.414 + 1.415 +void 1.416 +DataTextureSourceD3D11::Reset() 1.417 +{ 1.418 + mTexture = nullptr; 1.419 + mTileTextures.resize(0); 1.420 + mIsTiled = false; 1.421 + mSize.width = 0; 1.422 + mSize.height = 0; 1.423 +} 1.424 + 1.425 +IntRect 1.426 +DataTextureSourceD3D11::GetTileRect(uint32_t aIndex) const 1.427 +{ 1.428 + return GetTileRectD3D11(aIndex, mSize, mCompositor->GetMaxTextureSize()); 1.429 +} 1.430 + 1.431 +nsIntRect 1.432 +DataTextureSourceD3D11::GetTileRect() 1.433 +{ 1.434 + IntRect rect = GetTileRect(mCurrentTile); 1.435 + return nsIntRect(rect.x, rect.y, rect.width, rect.height); 1.436 +} 1.437 + 1.438 +void 1.439 +DataTextureSourceD3D11::SetCompositor(Compositor* aCompositor) 1.440 +{ 1.441 + CompositorD3D11* d3dCompositor = static_cast<CompositorD3D11*>(aCompositor); 1.442 + if (mCompositor && mCompositor != d3dCompositor) { 1.443 + Reset(); 1.444 + } 1.445 + mCompositor = d3dCompositor; 1.446 +} 1.447 + 1.448 +CompositingRenderTargetD3D11::CompositingRenderTargetD3D11(ID3D11Texture2D* aTexture, 1.449 + const gfx::IntPoint& aOrigin) 1.450 + : CompositingRenderTarget(aOrigin) 1.451 +{ 1.452 + MOZ_ASSERT(aTexture); 1.453 + 1.454 + mTexture = aTexture; 1.455 + 1.456 + RefPtr<ID3D11Device> device; 1.457 + mTexture->GetDevice(byRef(device)); 1.458 + 1.459 + HRESULT hr = device->CreateRenderTargetView(mTexture, nullptr, byRef(mRTView)); 1.460 + 1.461 + if (FAILED(hr)) { 1.462 + LOGD3D11("Failed to create RenderTargetView."); 1.463 + } 1.464 +} 1.465 + 1.466 +IntSize 1.467 +CompositingRenderTargetD3D11::GetSize() const 1.468 +{ 1.469 + return TextureSourceD3D11::GetSize(); 1.470 +} 1.471 + 1.472 +} 1.473 +}