void DeprecatedTextureHostDXGID3D11::LockTexture() { RefPtr<IDXGIKeyedMutex> mutex; mTextures[0]->QueryInterface((IDXGIKeyedMutex**)byRef(mutex)); mutex->AcquireSync(0, INFINITE); }
void DeprecatedTextureClientD3D11::LockTexture() { RefPtr<IDXGIKeyedMutex> mutex; mTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex)); mutex->AcquireSync(0, INFINITE); mIsLocked = true; }
HRESULT D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample, const nsIntRect& aRegion, ImageContainer* aContainer, Image** aOutImage) { NS_ENSURE_TRUE(aVideoSample, E_POINTER); NS_ENSURE_TRUE(aContainer, E_POINTER); NS_ENSURE_TRUE(aOutImage, E_POINTER); // Our video frame is stored in a non-sharable ID3D11Texture2D. We need // to create a copy of that frame as a sharable resource, save its share // handle, and put that handle into the rendering pipeline. ImageFormat format = ImageFormat::D3D11_SHARE_HANDLE_TEXTURE; nsRefPtr<Image> image(aContainer->CreateImage(format)); NS_ENSURE_TRUE(image, E_FAIL); NS_ASSERTION(image->GetFormat() == ImageFormat::D3D11_SHARE_HANDLE_TEXTURE, "Wrong format?"); D3D11ShareHandleImage* videoImage = static_cast<D3D11ShareHandleImage*>(image.get()); HRESULT hr = videoImage->SetData(D3D11ShareHandleImage::Data(mTextureClientAllocator, gfx::IntSize(mWidth, mHeight), aRegion)); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); hr = mTransform->Input(aVideoSample); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); RefPtr<IMFSample> sample; RefPtr<ID3D11Texture2D> texture = videoImage->GetTexture(); hr = CreateOutputSample(sample, texture); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); RefPtr<IDXGIKeyedMutex> keyedMutex; hr = texture->QueryInterface(static_cast<IDXGIKeyedMutex**>(byRef(keyedMutex))); NS_ENSURE_TRUE(SUCCEEDED(hr) && keyedMutex, hr); hr = keyedMutex->AcquireSync(0, INFINITE); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); hr = mTransform->Output(&sample); keyedMutex->ReleaseSync(0); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); image.forget(aOutImage); return S_OK; }
static bool LockD3DTexture(T* aTexture) { MOZ_ASSERT(aTexture); RefPtr<IDXGIKeyedMutex> mutex; aTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex)); // Textures created by the DXVA decoders don't have a mutex for synchronization if (mutex) { HRESULT hr = mutex->AcquireSync(0, INFINITE); if (FAILED(hr)) { NS_WARNING("Failed to lock the texture"); return false; } } return true; }
static bool LockD3DTexture(T* aTexture) { MOZ_ASSERT(aTexture); RefPtr<IDXGIKeyedMutex> mutex; aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex)); // Textures created by the DXVA decoders don't have a mutex for synchronization if (mutex) { HRESULT hr = mutex->AcquireSync(0, 10000); if (hr == WAIT_TIMEOUT) { gfxDevCrash(LogReason::D3DLockTimeout) << "D3D lock mutex timeout"; } if (FAILED(hr)) { NS_WARNING("Failed to lock the texture"); return false; } } return true; }
already_AddRefed<gfx::SourceSurface> D3D11ShareHandleImage::GetAsSourceSurface() { RefPtr<ID3D11Texture2D> texture = GetTexture(); if (!texture) { gfxWarning() << "Cannot readback from shared texture because no texture is available."; return nullptr; } RefPtr<ID3D11Device> device; texture->GetDevice(getter_AddRefs(device)); D3D11_TEXTURE2D_DESC desc; texture->GetDesc(&desc); HRESULT hr; if (desc.Format == DXGI_FORMAT_NV12) { nsAutoCString error; std::unique_ptr<DXVA2Manager> manager(DXVA2Manager::CreateD3D11DXVA(nullptr, error, device)); if (!manager) { gfxWarning() << "Failed to create DXVA2 manager!"; return nullptr; } RefPtr<ID3D11Texture2D> outTexture; hr = manager->CopyToBGRATexture(texture, getter_AddRefs(outTexture)); if (FAILED(hr)) { gfxWarning() << "Failed to copy NV12 to BGRA texture."; return nullptr; } texture = outTexture; texture->GetDesc(&desc); } CD3D11_TEXTURE2D_DESC softDesc(desc.Format, desc.Width, desc.Height); softDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; softDesc.BindFlags = 0; softDesc.MiscFlags = 0; softDesc.MipLevels = 1; softDesc.Usage = D3D11_USAGE_STAGING; RefPtr<ID3D11Texture2D> softTexture; hr = device->CreateTexture2D(&softDesc, NULL, static_cast<ID3D11Texture2D**>(getter_AddRefs(softTexture))); if (FAILED(hr)) { NS_WARNING("Failed to create 2D staging texture."); return nullptr; } RefPtr<ID3D11DeviceContext> context; device->GetImmediateContext(getter_AddRefs(context)); if (!context) { return nullptr; } RefPtr<IDXGIKeyedMutex> mutex; hr = texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex)); if (SUCCEEDED(hr) && mutex) { hr = mutex->AcquireSync(0, 2000); if (hr != S_OK) { NS_WARNING("Acquire sync didn't manage to return within 2 seconds."); } } context->CopyResource(softTexture, texture); if (SUCCEEDED(hr) && mutex) { mutex->ReleaseSync(0); } RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8A8); if (NS_WARN_IF(!surface)) { return nullptr; } gfx::DataSourceSurface::MappedSurface mappedSurface; if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) { return nullptr; } D3D11_MAPPED_SUBRESOURCE map; hr = context->Map(softTexture, 0, D3D11_MAP_READ, 0, &map); if (!SUCCEEDED(hr)) { surface->Unmap(); return nullptr; } for (int y = 0; y < mSize.height; y++) { memcpy(mappedSurface.mData + mappedSurface.mStride * y, (unsigned char*)(map.pData) + map.RowPitch * y, mSize.width * 4); } context->Unmap(softTexture, 0); surface->Unmap(); return surface.forget(); }
// See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails // with E_OUTOFMEMORY. static bool DoesTextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT format, UINT bindflags) { // CreateTexture2D is known to crash on lower feature levels, see bugs // 1170211 and 1089413. if (device->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) { return false; } if (gfxPrefs::Direct2DForceEnabled() || gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) { return true; } if (GetModuleHandleW(L"atidxx32.dll")) { nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); if (gfxInfo) { nsString vendorID, vendorID2; gfxInfo->GetAdapterVendorID(vendorID); gfxInfo->GetAdapterVendorID2(vendorID2); if (vendorID.EqualsLiteral("0x8086") && vendorID2.IsEmpty()) { if (!gfxPrefs::LayersAMDSwitchableGfxEnabled()) { return false; } gfxCriticalError(CriticalLog::DefaultOptions(false)) << "PossiblyBrokenSurfaceSharing_UnexpectedAMDGPU"; } } } RefPtr<ID3D11Texture2D> texture; D3D11_TEXTURE2D_DESC desc; const int texture_size = 32; desc.Width = texture_size; desc.Height = texture_size; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = format; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.CPUAccessFlags = 0; desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; desc.BindFlags = bindflags; uint32_t color[texture_size * texture_size]; for (size_t i = 0; i < sizeof(color)/sizeof(color[0]); i++) { color[i] = 0xff00ffff; } // XXX If we pass the data directly at texture creation time we // get a crash on Intel 8.5.10.[18xx-1994] drivers. // We can work around this issue by doing UpdateSubresource. if (!TryCreateTexture2D(device, &desc, nullptr, texture)) { gfxCriticalNote << "DoesD3D11TextureSharingWork_TryCreateTextureFailure"; return false; } RefPtr<IDXGIKeyedMutex> sourceSharedMutex; texture->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(sourceSharedMutex)); if (FAILED(sourceSharedMutex->AcquireSync(0, 30*1000))) { gfxCriticalError() << "DoesD3D11TextureSharingWork_SourceMutexTimeout"; // only wait for 30 seconds return false; } RefPtr<ID3D11DeviceContext> deviceContext; device->GetImmediateContext(getter_AddRefs(deviceContext)); int stride = texture_size * 4; deviceContext->UpdateSubresource(texture, 0, nullptr, color, stride, stride * texture_size); if (FAILED(sourceSharedMutex->ReleaseSync(0))) { gfxCriticalError() << "DoesD3D11TextureSharingWork_SourceReleaseSyncTimeout"; return false; } HANDLE shareHandle; RefPtr<IDXGIResource> otherResource; if (FAILED(texture->QueryInterface(__uuidof(IDXGIResource), getter_AddRefs(otherResource)))) { gfxCriticalError() << "DoesD3D11TextureSharingWork_GetResourceFailure"; return false; } if (FAILED(otherResource->GetSharedHandle(&shareHandle))) { gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure"; return false; } RefPtr<ID3D11Resource> sharedResource; RefPtr<ID3D11Texture2D> sharedTexture; if (FAILED(device->OpenSharedResource(shareHandle, __uuidof(ID3D11Resource), getter_AddRefs(sharedResource)))) { gfxCriticalError(CriticalLog::DefaultOptions(false)) << "OpenSharedResource failed for format " << format; return false; } if (FAILED(sharedResource->QueryInterface(__uuidof(ID3D11Texture2D), getter_AddRefs(sharedTexture)))) { gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure"; return false; } // create a staging texture for readback RefPtr<ID3D11Texture2D> cpuTexture; desc.Usage = D3D11_USAGE_STAGING; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.MiscFlags = 0; desc.BindFlags = 0; if (FAILED(device->CreateTexture2D(&desc, nullptr, getter_AddRefs(cpuTexture)))) { gfxCriticalError() << "DoesD3D11TextureSharingWork_CreateTextureFailure"; return false; } RefPtr<IDXGIKeyedMutex> sharedMutex; sharedResource->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(sharedMutex)); { HRESULT hr; AutoTextureLock lock(sharedMutex, hr, 30*1000); if (FAILED(hr)) { gfxCriticalError() << "DoesD3D11TextureSharingWork_AcquireSyncTimeout"; // only wait for 30 seconds return false; } // Copy to the cpu texture so that we can readback deviceContext->CopyResource(cpuTexture, sharedTexture); // We only need to hold on to the mutex during the copy. sharedMutex->ReleaseSync(0); } D3D11_MAPPED_SUBRESOURCE mapped; uint32_t resultColor = 0; if (SUCCEEDED(deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped))) { // read the texture resultColor = *(uint32_t*)mapped.pData; deviceContext->Unmap(cpuTexture, 0); } else { gfxCriticalError() << "DoesD3D11TextureSharingWork_MapFailed"; return false; } // check that the color we put in is the color we get out if (resultColor != color[0]) { // Shared surfaces seem to be broken on dual AMD & Intel HW when using the // AMD GPU gfxCriticalNote << "DoesD3D11TextureSharingWork_ColorMismatch"; return false; } RefPtr<ID3D11ShaderResourceView> sharedView; // This if(FAILED()) is the one that actually fails on systems affected by bug 1083071. if (FAILED(device->CreateShaderResourceView(sharedTexture, NULL, getter_AddRefs(sharedView)))) { gfxCriticalNote << "CreateShaderResourceView failed for format" << format; return false; } return true; }
already_AddRefed<gfx::SourceSurface> D3D11ShareHandleImage::GetAsSourceSurface() { RefPtr<ID3D11Texture2D> texture = GetTexture(); if (!texture) { NS_WARNING("Cannot readback from shared texture because no texture is available."); return nullptr; } RefPtr<ID3D11Device> device; texture->GetDevice(byRef(device)); RefPtr<IDXGIKeyedMutex> keyedMutex; if (FAILED(texture->QueryInterface(static_cast<IDXGIKeyedMutex**>(byRef(keyedMutex))))) { NS_WARNING("Failed to QueryInterface for IDXGIKeyedMutex, strange."); return nullptr; } if (FAILED(keyedMutex->AcquireSync(0, 0))) { NS_WARNING("Failed to acquire sync for keyedMutex, plugin failed to release?"); return nullptr; } D3D11_TEXTURE2D_DESC desc; texture->GetDesc(&desc); CD3D11_TEXTURE2D_DESC softDesc(desc.Format, desc.Width, desc.Height); softDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; softDesc.BindFlags = 0; softDesc.MiscFlags = 0; softDesc.MipLevels = 1; softDesc.Usage = D3D11_USAGE_STAGING; RefPtr<ID3D11Texture2D> softTexture; HRESULT hr = device->CreateTexture2D(&softDesc, NULL, static_cast<ID3D11Texture2D**>(byRef(softTexture))); if (FAILED(hr)) { NS_WARNING("Failed to create 2D staging texture."); keyedMutex->ReleaseSync(0); return nullptr; } RefPtr<ID3D11DeviceContext> context; device->GetImmediateContext(byRef(context)); if (!context) { keyedMutex->ReleaseSync(0); return nullptr; } context->CopyResource(softTexture, texture); keyedMutex->ReleaseSync(0); RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8X8); if (NS_WARN_IF(!surface)) { return nullptr; } gfx::DataSourceSurface::MappedSurface mappedSurface; if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) { return nullptr; } D3D11_MAPPED_SUBRESOURCE map; hr = context->Map(softTexture, 0, D3D11_MAP_READ, 0, &map); if (!SUCCEEDED(hr)) { surface->Unmap(); return nullptr; } for (int y = 0; y < mSize.height; y++) { memcpy(mappedSurface.mData + mappedSurface.mStride * y, (unsigned char*)(map.pData) + map.RowPitch * y, mSize.width * 4); } context->Unmap(softTexture, 0); surface->Unmap(); return surface.forget(); }
void CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion, const Rect* aClipRectIn, const Rect& aRenderBounds, Rect* aClipRectOut, Rect* aRenderBoundsOut) { // Don't composite if we are minimised. Other than for the sake of efficency, // this is important because resizing our buffers when mimised will fail and // cause a crash when we're restored. NS_ASSERTION(mHwnd, "Couldn't find an HWND when initialising?"); if (::IsIconic(mHwnd) || gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) { *aRenderBoundsOut = Rect(); return; } nsIntSize oldSize = mSize; UpdateRenderTarget(); // Failed to create a render target or the view. if (!mDefaultRT || !mDefaultRT->mRTView || mSize.width == 0 || mSize.height == 0) { *aRenderBoundsOut = Rect(); return; } mContext->IASetInputLayout(mAttachments->mInputLayout); ID3D11Buffer* buffer = mAttachments->mVertexBuffer; UINT size = sizeof(Vertex); UINT offset = 0; mContext->IASetVertexBuffers(0, 1, &buffer, &size, &offset); nsIntRect intRect = nsIntRect(nsIntPoint(0, 0), mSize); // Sometimes the invalid region is larger than we want to draw. nsIntRegion invalidRegionSafe; if (mSize != oldSize) { invalidRegionSafe = intRect; } else { invalidRegionSafe.And(aInvalidRegion, intRect); } nsIntRect invalidRect = invalidRegionSafe.GetBounds(); mInvalidRect = IntRect(invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height); mInvalidRegion = invalidRegionSafe; if (aClipRectOut) { *aClipRectOut = Rect(0, 0, mSize.width, mSize.height); } if (aRenderBoundsOut) { *aRenderBoundsOut = Rect(0, 0, mSize.width, mSize.height); } if (aClipRectIn) { invalidRect.IntersectRect(invalidRect, nsIntRect(aClipRectIn->x, aClipRectIn->y, aClipRectIn->width, aClipRectIn->height)); } mCurrentClip = IntRect(invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height); mContext->RSSetState(mAttachments->mRasterizerState); SetRenderTarget(mDefaultRT); // ClearRect will set the correct blend state for us. ClearRect(Rect(invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height)); if (mAttachments->mSyncTexture) { RefPtr<IDXGIKeyedMutex> mutex; mAttachments->mSyncTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex)); MOZ_ASSERT(mutex); HRESULT hr = mutex->AcquireSync(0, 10000); if (hr == WAIT_TIMEOUT) { MOZ_CRASH(); } mutex->ReleaseSync(0); } }