// 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; }
void CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) { auto gl = aLayer->mGLContext; gl->MakeCurrent(); RefPtr<TextureClient> newFront; if (aLayer->mGLFrontbuffer) { mShSurfClient = CloneSurface(aLayer->mGLFrontbuffer.get(), aLayer->mFactory.get()); if (!mShSurfClient) { gfxCriticalError() << "Invalid canvas front buffer"; return; } } else { mShSurfClient = gl->Screen()->Front(); if (!mShSurfClient) { return; } } MOZ_ASSERT(mShSurfClient); newFront = mShSurfClient; SharedSurface* surf = mShSurfClient->Surf(); // Readback if needed. mReadbackClient = nullptr; auto forwarder = GetForwarder(); bool needsReadback = (surf->mType == SharedSurfaceType::Basic); if (needsReadback) { TextureFlags flags = aLayer->Flags() | TextureFlags::IMMUTABLE; auto manager = aLayer->ClientManager(); auto shadowForwarder = manager->AsShadowForwarder(); auto layersBackend = shadowForwarder->GetCompositorBackendType(); mReadbackClient = TexClientFromReadback(surf, forwarder, flags, layersBackend); newFront = mReadbackClient; } else { mReadbackClient = nullptr; } MOZ_ASSERT(newFront); if (!newFront) { // May happen in a release build in case of memory pressure. gfxCriticalError() << "Failed to allocate a TextureClient for SharedSurface Canvas. Size: " << aSize; return; } if (mFront) { if (mFront->GetFlags() & TextureFlags::RECYCLE) { mFront->WaitForCompositorRecycle(); } } mFront = newFront; // Add the new TexClient. MOZ_ALWAYS_TRUE( AddTextureClient(mFront) ); forwarder->UseTexture(this, mFront); }
void CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) { if (mFront) { mPrevFront = mFront; mFront = nullptr; } auto gl = aLayer->mGLContext; gl->MakeCurrent(); if (aLayer->mGLFrontbuffer) { mFront = CloneSurface(aLayer->mGLFrontbuffer.get(), aLayer->mFactory.get()); if (mFront) mFront->Surf()->Fence(); } else { mFront = gl->Screen()->Front(); if (!mFront) return; } MOZ_ASSERT(mFront); // Alright, now sort out the IPC goop. SharedSurface* surf = mFront->Surf(); auto forwarder = GetForwarder(); auto flags = GetTextureFlags() | TextureFlags::IMMUTABLE; // Get a TexClient from our surf. RefPtr<TextureClient> newTex = TexClientFromShSurf(GetForwarder(), surf, flags); if (!newTex) { auto manager = aLayer->ClientManager(); auto shadowForwarder = manager->AsShadowForwarder(); auto layersBackend = shadowForwarder->GetCompositorBackendType(); newTex = TexClientFromReadback(surf, forwarder, flags, layersBackend); } MOZ_ASSERT(newTex); if (!newTex) { // May happen in a release build in case of memory pressure. gfxCriticalError() << "Failed to allocate a TextureClient for SharedSurface Canvas. size: " << aSize; return; } // Add the new TexClient. MOZ_ALWAYS_TRUE( AddTextureClient(newTex) ); // Remove the old TexClient. if (mFrontTex) { // remove old buffer from CompositableHost RefPtr<AsyncTransactionTracker> tracker = new RemoveTextureFromCompositableTracker(); // Hold TextureClient until transaction complete. tracker->SetTextureClient(mFrontTex); mFrontTex->SetRemoveFromCompositableTracker(tracker); // RemoveTextureFromCompositableAsync() expects CompositorChild's presence. GetForwarder()->RemoveTextureFromCompositableAsync(tracker, this, mFrontTex); mFrontTex = nullptr; } // Use the new TexClient. mFrontTex = newTex; forwarder->UseTexture(this, mFrontTex); }
bool D3D11YCbCrImage::SetData(KnowsCompositor* aAllocator, ImageContainer* aContainer, const PlanarYCbCrData& aData) { mPictureRect = IntRect( aData.mPicX, aData.mPicY, aData.mPicSize.width, aData.mPicSize.height); mYSize = aData.mYSize; mCbCrSize = aData.mCbCrSize; mColorSpace = aData.mYUVColorSpace; D3D11YCbCrRecycleAllocator* allocator = aContainer->GetD3D11YCbCrRecycleAllocator(aAllocator); if (!allocator) { return false; } allocator->SetSizes(aData.mYSize, aData.mCbCrSize); mTextureClient = allocator->CreateOrRecycle(SurfaceFormat::A8, mYSize, BackendSelector::Content, TextureFlags::DEFAULT); if (!mTextureClient) { return false; } DXGIYCbCrTextureData *data = static_cast<DXGIYCbCrTextureData*>(mTextureClient->GetInternalData()); ID3D11Texture2D* textureY = data->GetD3D11Texture(0); ID3D11Texture2D* textureCb = data->GetD3D11Texture(1); ID3D11Texture2D* textureCr = data->GetD3D11Texture(2); RefPtr<ID3D10Multithread> mt; HRESULT hr = allocator->GetDevice()->QueryInterface( (ID3D10Multithread**)getter_AddRefs(mt)); if (FAILED(hr) || !mt) { gfxCriticalError() << "Multithread safety interface not supported. " << hr; return false; } if (!mt->GetMultithreadProtected()) { gfxCriticalError() << "Device used not marked as multithread-safe."; return false; } D3D11MTAutoEnter mtAutoEnter(mt.forget()); RefPtr<ID3D11DeviceContext> ctx; allocator->GetDevice()->GetImmediateContext(getter_AddRefs(ctx)); AutoLockD3D11Texture lockY(textureY); AutoLockD3D11Texture lockCb(textureCb); AutoLockD3D11Texture lockCr(textureCr); ctx->UpdateSubresource(textureY, 0, nullptr, aData.mYChannel, aData.mYStride, aData.mYStride * aData.mYSize.height); ctx->UpdateSubresource(textureCb, 0, nullptr, aData.mCbChannel, aData.mCbCrStride, aData.mCbCrStride * aData.mCbCrSize.height); ctx->UpdateSubresource(textureCr, 0, nullptr, aData.mCrChannel, aData.mCbCrStride, aData.mCbCrStride * aData.mCbCrSize.height); return true; }
DIBTextureData* ShmemDIBTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, LayersIPCChannel* aAllocator) { MOZ_ASSERT(aAllocator->GetParentPid() != base::ProcessId()); DWORD mapSize = aSize.width * aSize.height * BytesPerPixel(aFormat); HANDLE fileMapping = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, mapSize, NULL); if (!fileMapping) { gfxCriticalError() << "Failed to create memory file mapping for " << mapSize << " bytes."; return nullptr; } BITMAPV4HEADER header; memset(&header, 0, sizeof(BITMAPV4HEADER)); header.bV4Size = sizeof(BITMAPV4HEADER); header.bV4Width = aSize.width; header.bV4Height = -LONG(aSize.height); // top-to-buttom DIB header.bV4Planes = 1; header.bV4BitCount = 32; header.bV4V4Compression = BI_BITFIELDS; header.bV4RedMask = 0x00FF0000; header.bV4GreenMask = 0x0000FF00; header.bV4BlueMask = 0x000000FF; HDC nulldc = ::GetDC(NULL); HDC dc = ::CreateCompatibleDC(nulldc); ::ReleaseDC(nullptr, nulldc); if (!dc) { ::CloseHandle(fileMapping); gfxCriticalError() << "Failed to create DC for bitmap."; return nullptr; } void* bits; HBITMAP bitmap = ::CreateDIBSection(dc, (BITMAPINFO*)&header, DIB_RGB_COLORS, &bits, fileMapping, 0); if (!bitmap) { gfxCriticalError() << "Failed to create DIB section for a bitmap of size " << aSize << " and mapSize " << mapSize; ::CloseHandle(fileMapping); ::DeleteDC(dc); return nullptr; } ::SelectObject(dc, bitmap); RefPtr<gfxWindowsSurface> surface = new gfxWindowsSurface(dc, 0); if (surface->CairoStatus()) { ::DeleteObject(bitmap); ::DeleteDC(dc); ::CloseHandle(fileMapping); gfxCriticalError() << "Could not create surface, status: " << surface->CairoStatus(); return nullptr; } HANDLE hostHandle = NULL; if (!ipc::DuplicateHandle(fileMapping, aAllocator->GetParentPid(), &hostHandle, 0, DUPLICATE_SAME_ACCESS)) { gfxCriticalError() << "Failed to duplicate handle to parent process for surface."; ::DeleteObject(bitmap); ::DeleteDC(dc); ::CloseHandle(fileMapping); return nullptr; } return new ShmemDIBTextureData(aSize, aFormat, surface, fileMapping, hostHandle, dc, bitmap); }
void D3D11LayersCrashGuard::LogCrashRecovery() { RecordTelemetry(TelemetryState::RecoveredFromCrash); gfxCriticalError(CriticalLog::DefaultOptions(false)) << "D3D11 layers just crashed; D3D11 will be disabled."; }
already_AddRefed<SourceSurface> D3D11YCbCrImage::GetAsSourceSurface() { if (!mTextureClient) { gfxWarning() << "GetAsSourceSurface() called on uninitialized D3D11YCbCrImage."; return nullptr; } gfx::IntSize size(mPictureRect.Size()); gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(gfxVars::OffscreenFormat()); HRESULT hr; PlanarYCbCrData data; DXGIYCbCrTextureData *dxgiData = static_cast<DXGIYCbCrTextureData*>(mTextureClient->GetInternalData()); if (!dxgiData) { gfxCriticalError() << "Failed to get texture client internal data."; return nullptr; } RefPtr<ID3D11Texture2D> texY = dxgiData->GetD3D11Texture(0); RefPtr<ID3D11Texture2D> texCb = dxgiData->GetD3D11Texture(1); RefPtr<ID3D11Texture2D> texCr = dxgiData->GetD3D11Texture(2); RefPtr<ID3D11Texture2D> softTexY, softTexCb, softTexCr; D3D11_TEXTURE2D_DESC desc; RefPtr<ID3D11Device> dev; texY->GetDevice(getter_AddRefs(dev)); RefPtr<ID3D10Multithread> mt; hr = dev->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt)); if (FAILED(hr) || !mt) { gfxCriticalError() << "Multithread safety interface not supported."; return nullptr; } if (!mt->GetMultithreadProtected()) { gfxCriticalError() << "Device used not marked as multithread-safe."; return nullptr; } D3D11MTAutoEnter mtAutoEnter(mt.forget()); texY->GetDesc(&desc); desc.BindFlags = 0; desc.MiscFlags = 0; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.Usage = D3D11_USAGE_STAGING; dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexY)); texCb->GetDesc(&desc); desc.BindFlags = 0; desc.MiscFlags = 0; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.Usage = D3D11_USAGE_STAGING; dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexCb)); dev->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexCr)); RefPtr<ID3D11DeviceContext> ctx; dev->GetImmediateContext(getter_AddRefs(ctx)); { AutoLockD3D11Texture lockY(texY); AutoLockD3D11Texture lockCb(texCb); AutoLockD3D11Texture lockCr(texCr); ctx->CopyResource(softTexY, texY); ctx->CopyResource(softTexCb, texCb); ctx->CopyResource(softTexCr, texCr); } D3D11_MAPPED_SUBRESOURCE mapY, mapCb, mapCr; RefPtr<gfx::DataSourceSurface> surface; mapY.pData = mapCb.pData = mapCr.pData = nullptr; hr = ctx->Map(softTexY, 0, D3D11_MAP_READ, 0, &mapY); if (FAILED(hr)) { gfxCriticalError() << "Failed to map Y plane (" << hr << ")"; return nullptr; } hr = ctx->Map(softTexCb, 0, D3D11_MAP_READ, 0, &mapCb); if (FAILED(hr)) { gfxCriticalError() << "Failed to map Y plane (" << hr << ")"; return nullptr; } hr = ctx->Map(softTexCr, 0, D3D11_MAP_READ, 0, &mapCr); if (FAILED(hr)) { gfxCriticalError() << "Failed to map Y plane (" << hr << ")"; return nullptr; } MOZ_ASSERT(mapCb.RowPitch == mapCr.RowPitch); data.mPicX = mPictureRect.x; data.mPicY = mPictureRect.y; data.mPicSize = mPictureRect.Size(); data.mStereoMode = StereoMode::MONO; data.mYUVColorSpace = mColorSpace; data.mYSkip = data.mCbSkip = data.mCrSkip = 0; data.mYSize = mYSize; data.mCbCrSize = mCbCrSize; data.mYChannel = static_cast<uint8_t*>(mapY.pData); data.mYStride = mapY.RowPitch; data.mCbChannel = static_cast<uint8_t*>(mapCb.pData); data.mCrChannel = static_cast<uint8_t*>(mapCr.pData); data.mCbCrStride = mapCb.RowPitch; gfx::GetYCbCrToRGBDestFormatAndSize(data, format, size); if (size.width > PlanarYCbCrImage::MAX_DIMENSION || size.height > PlanarYCbCrImage::MAX_DIMENSION) { gfxCriticalError() << "Illegal image dest width or height"; return nullptr; } surface = gfx::Factory::CreateDataSourceSurface(size, format); if (!surface) { gfxCriticalError() << "Failed to create DataSourceSurface for image: " << size << " " << format; return nullptr; } DataSourceSurface::ScopedMap mapping(surface, DataSourceSurface::WRITE); if (!mapping.IsMapped()) { gfxCriticalError() << "Failed to map DataSourceSurface for D3D11YCbCrImage"; return nullptr; } gfx::ConvertYCbCrToRGB( data, format, size, mapping.GetData(), mapping.GetStride()); ctx->Unmap(softTexY, 0); ctx->Unmap(softTexCb, 0); ctx->Unmap(softTexCr, 0); return surface.forget(); }
CompositorChild::~CompositorChild() { if (mCanSend) { gfxCriticalError() << "CompositorChild was not deinitialized"; } }
bool FixedSizeSmallShmemSectionAllocator::AllocShmemSection(uint32_t aSize, ShmemSection* aShmemSection) { // For now we only support sizes of 4. If we want to support different sizes // some more complicated bookkeeping should be added. MOZ_ASSERT(aSize == sSupportedBlockSize); MOZ_ASSERT(aShmemSection); if (!IPCOpen()) { gfxCriticalError() << "Attempt to allocate a ShmemSection after shutdown."; return false; } uint32_t allocationSize = (aSize + sizeof(ShmemSectionHeapAllocation)); for (size_t i = 0; i < mUsedShmems.size(); i++) { ShmemSectionHeapHeader* header = mUsedShmems[i].get<ShmemSectionHeapHeader>(); if ((header->mAllocatedBlocks + 1) * allocationSize + sizeof(ShmemSectionHeapHeader) < sShmemPageSize) { aShmemSection->shmem() = mUsedShmems[i]; MOZ_ASSERT(mUsedShmems[i].IsWritable()); break; } } if (!aShmemSection->shmem().IsWritable()) { ipc::Shmem tmp; if (!GetShmAllocator()->AllocUnsafeShmem(sShmemPageSize, OptimalShmemType(), &tmp)) { return false; } ShmemSectionHeapHeader* header = tmp.get<ShmemSectionHeapHeader>(); header->mTotalBlocks = 0; header->mAllocatedBlocks = 0; mUsedShmems.push_back(tmp); aShmemSection->shmem() = tmp; } MOZ_ASSERT(aShmemSection->shmem().IsWritable()); ShmemSectionHeapHeader* header = aShmemSection->shmem().get<ShmemSectionHeapHeader>(); uint8_t* heap = aShmemSection->shmem().get<uint8_t>() + sizeof(ShmemSectionHeapHeader); ShmemSectionHeapAllocation* allocHeader = nullptr; if (header->mTotalBlocks > header->mAllocatedBlocks) { // Search for the first available block. for (size_t i = 0; i < header->mTotalBlocks; i++) { allocHeader = reinterpret_cast<ShmemSectionHeapAllocation*>(heap); if (allocHeader->mStatus == STATUS_FREED) { break; } heap += allocationSize; } MOZ_ASSERT(allocHeader && allocHeader->mStatus == STATUS_FREED); MOZ_ASSERT(allocHeader->mSize == sSupportedBlockSize); } else { heap += header->mTotalBlocks * allocationSize; header->mTotalBlocks++; allocHeader = reinterpret_cast<ShmemSectionHeapAllocation*>(heap); allocHeader->mSize = aSize; } MOZ_ASSERT(allocHeader); header->mAllocatedBlocks++; allocHeader->mStatus = STATUS_ALLOCATED; aShmemSection->size() = aSize; aShmemSection->offset() = (heap + sizeof(ShmemSectionHeapAllocation)) - aShmemSection->shmem().get<uint8_t>(); ShrinkShmemSectionHeap(); return true; }
void GLContextCrashGuard::LogCrashRecovery() { gfxCriticalError(CriticalLog::DefaultOptions(false)) << "GLContext just crashed and is now disabled."; }
void GLContextCrashGuard::LogFeatureDisabled() { gfxCriticalError(CriticalLog::DefaultOptions(false)) << "GLContext is disabled due to a previous crash."; }
void D3D9VideoCrashGuard::LogFeatureDisabled() { gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DXVA2D3D9 video decoding is disabled due to a previous crash."; }
void D3D9VideoCrashGuard::LogCrashRecovery() { gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DXVA2D3D9 just crashed; hardware video will be disabled."; }
void D3D11LayersCrashGuard::LogFeatureDisabled() { RecordTelemetry(TelemetryState::FeatureDisabled); gfxCriticalError(CriticalLog::DefaultOptions(false)) << "D3D11 layers disabled due to a prior crash."; }
void CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer) { GLContext* gl = nullptr; ClientCanvasLayer* layer = nullptr; AsyncCanvasRenderer* asyncRenderer = nullptr; if (aRenderer.constructed<ClientCanvasLayer*>()) { layer = aRenderer.ref<ClientCanvasLayer*>(); gl = layer->mGLContext; } else { asyncRenderer = aRenderer.ref<AsyncCanvasRenderer*>(); gl = asyncRenderer->mGLContext; } gl->MakeCurrent(); RefPtr<TextureClient> newFront; if (layer && layer->mGLFrontbuffer) { mShSurfClient = CloneSurface(layer->mGLFrontbuffer.get(), layer->mFactory.get()); if (!mShSurfClient) { gfxCriticalError() << "Invalid canvas front buffer"; return; } } else { mShSurfClient = gl->Screen()->Front(); if (!mShSurfClient) { return; } } MOZ_ASSERT(mShSurfClient); newFront = mShSurfClient; SharedSurface* surf = mShSurfClient->Surf(); // Readback if needed. mReadbackClient = nullptr; auto forwarder = GetForwarder(); bool needsReadback = (surf->mType == SharedSurfaceType::Basic); if (needsReadback) { TextureFlags flags = TextureFlags::IMMUTABLE; CompositableForwarder* shadowForwarder = nullptr; if (layer) { flags |= layer->Flags(); shadowForwarder = layer->ClientManager()->AsShadowForwarder(); } else { MOZ_ASSERT(asyncRenderer); flags |= mTextureFlags; shadowForwarder = GetForwarder(); } auto layersBackend = shadowForwarder->GetCompositorBackendType(); mReadbackClient = TexClientFromReadback(surf, forwarder, flags, layersBackend); if (asyncRenderer) { // Above codes will readback the GLContext to mReadbackClient // in order to send frame to compositor. We copy from this // TextureClient directly by calling CopyFromTextureClient(). // Therefore, if main-thread want the content of GLContext, // it don't have to readback it again. asyncRenderer->CopyFromTextureClient(mReadbackClient); } newFront = mReadbackClient; } else { mReadbackClient = nullptr; } MOZ_ASSERT(newFront); if (!newFront) { // May happen in a release build in case of memory pressure. gfxCriticalError() << "Failed to allocate a TextureClient for SharedSurface Canvas. Size: " << aSize; return; } mNewFront = newFront; }
bool WebGLTexture::EnsureInitializedImageData(TexImageTarget imageTarget, GLint level) { const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level); if (!imageInfo.HasUninitializedImageData()) return true; mContext->MakeContextCurrent(); // Try to clear with glClear. if (imageTarget == LOCAL_GL_TEXTURE_2D) { bool cleared = ClearWithTempFB(mContext, mGLName, imageTarget, level, imageInfo.mEffectiveInternalFormat, imageInfo.mHeight, imageInfo.mWidth); if (cleared) { SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData); return true; } } // That didn't work. Try uploading zeros then. size_t bitspertexel = GetBitsPerTexel(imageInfo.mEffectiveInternalFormat); MOZ_ASSERT((bitspertexel % 8) == 0); // That would only happen for // compressed images, which cannot use // deferred initialization. size_t bytespertexel = bitspertexel / 8; CheckedUint32 checked_byteLength = WebGLContext::GetImageSize( imageInfo.mHeight, imageInfo.mWidth, imageInfo.mDepth, bytespertexel, mContext->mPixelStoreUnpackAlignment); MOZ_ASSERT(checked_byteLength.isValid()); // Should have been checked // earlier. size_t byteCount = checked_byteLength.value(); UniquePtr<uint8_t> zeros((uint8_t*)calloc(1, byteCount)); if (zeros == nullptr) { // Failed to allocate memory. Lose the context. Return OOM error. mContext->ForceLoseContext(true); mContext->ErrorOutOfMemory("EnsureInitializedImageData: Failed to alloc %u " "bytes to clear image target `%s` level `%d`.", byteCount, mContext->EnumName(imageTarget.get()), level); return false; } gl::GLContext* gl = mContext->gl; gl::ScopedBindTexture autoBindTex(gl, mGLName, mTarget); GLenum driverInternalFormat = LOCAL_GL_NONE; GLenum driverFormat = LOCAL_GL_NONE; GLenum driverType = LOCAL_GL_NONE; DriverFormatsFromEffectiveInternalFormat(gl, imageInfo.mEffectiveInternalFormat, &driverInternalFormat, &driverFormat, &driverType); mContext->GetAndFlushUnderlyingGLErrors(); if (imageTarget == LOCAL_GL_TEXTURE_3D) { MOZ_ASSERT(mImmutable, "Shouldn't be possible to have non-immutable-format 3D" " textures in WebGL"); gl->fTexSubImage3D(imageTarget.get(), level, 0, 0, 0, imageInfo.mWidth, imageInfo.mHeight, imageInfo.mDepth, driverFormat, driverType, zeros.get()); } else { if (mImmutable) { gl->fTexSubImage2D(imageTarget.get(), level, 0, 0, imageInfo.mWidth, imageInfo.mHeight, driverFormat, driverType, zeros.get()); } else { gl->fTexImage2D(imageTarget.get(), level, driverInternalFormat, imageInfo.mWidth, imageInfo.mHeight, 0, driverFormat, driverType, zeros.get()); } } GLenum error = mContext->GetAndFlushUnderlyingGLErrors(); if (error) { // Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover // from this here. gfxCriticalError() << "GL context GetAndFlushUnderlyingGLErrors " << gfx::hexa(error); printf_stderr("Error: 0x%4x\n", error); if (error != LOCAL_GL_OUT_OF_MEMORY) { // Errors on texture upload have been related to video // memory exposure in the past, which is a security issue. // Force loss of context. mContext->ForceLoseContext(true); return false; } // Out-of-memory uploading pixels to GL. Lose context and report OOM. mContext->ForceLoseContext(true); mContext->ErrorOutOfMemory("EnsureNoUninitializedImageData: Failed to " "upload texture of width: %u, height: %u, " "depth: %u to target %s level %d.", imageInfo.mWidth, imageInfo.mHeight, imageInfo.mDepth, mContext->EnumName(imageTarget.get()), level); return false; } SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData); return true; }
bool TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface, nsIntRegion* aDestRegion, gfx::IntPoint* aSrcOffset) { GLContext *gl = mCompositor->gl(); MOZ_ASSERT(gl); if (!gl) { NS_WARNING("trying to update TextureImageTextureSourceOGL without a GLContext"); return false; } if (!aSurface) { gfxCriticalError() << "Invalid surface for OGL update"; return false; } MOZ_ASSERT(aSurface); IntSize size = aSurface->GetSize(); if (!mTexImage || (mTexImage->GetSize() != size && !aSrcOffset) || mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) { if (mFlags & TextureFlags::DISALLOW_BIGIMAGE) { GLint maxTextureSize; gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTextureSize); if (size.width > maxTextureSize || size.height > maxTextureSize) { NS_WARNING("Texture exceeds maximum texture size, refusing upload"); return false; } // Explicitly use CreateBasicTextureImage instead of CreateTextureImage, // because CreateTextureImage might still choose to create a tiled // texture image. mTexImage = CreateBasicTextureImage(gl, size, gfx::ContentForFormat(aSurface->GetFormat()), LOCAL_GL_CLAMP_TO_EDGE, FlagsToGLFlags(mFlags), SurfaceFormatToImageFormat(aSurface->GetFormat())); } else { // XXX - clarify which size we want to use. IncrementalContentHost will // require the size of the destination surface to be different from // the size of aSurface. // See bug 893300 (tracks the implementation of ContentHost for new textures). mTexImage = CreateTextureImage(gl, size, gfx::ContentForFormat(aSurface->GetFormat()), LOCAL_GL_CLAMP_TO_EDGE, FlagsToGLFlags(mFlags), SurfaceFormatToImageFormat(aSurface->GetFormat())); } ClearCachedFilter(); if (aDestRegion && !aSrcOffset && !aDestRegion->IsEqual(gfx::IntRect(0, 0, size.width, size.height))) { // UpdateFromDataSource will ignore our specified aDestRegion since the texture // hasn't been allocated with glTexImage2D yet. Call Resize() to force the // allocation (full size, but no upload), and then we'll only upload the pixels // we care about below. mTexImage->Resize(size); } } mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset); if (mTexImage->InUpdate()) { mTexImage->EndUpdate(); } return true; }
WebGLContext::FakeBlackTexture::FakeBlackTexture(gl::GLContext* gl, TexTarget target, FakeBlackType type) : mGL(gl) , mGLName(CreateGLTexture(gl)) { GLenum texFormat; switch (type) { case FakeBlackType::RGBA0000: texFormat = LOCAL_GL_RGBA; break; case FakeBlackType::RGBA0001: texFormat = LOCAL_GL_RGB; break; default: MOZ_CRASH("bad type"); } gl::ScopedBindTexture scopedBind(mGL, mGLName, target.get()); mGL->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST); mGL->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST); // We allocate our zeros on the heap, and we overallocate (16 bytes instead of 4) to // minimize the risk of running into a driver bug in texImage2D, as it is a bit // unusual maybe to create 1x1 textures, and the stack may not have the alignment that // TexImage2D expects. const webgl::DriverUnpackInfo dui = {texFormat, texFormat, LOCAL_GL_UNSIGNED_BYTE}; UniqueBuffer zeros = moz_xcalloc(1, 16); // Infallible allocation. MOZ_ASSERT(gl->IsCurrent()); if (target == LOCAL_GL_TEXTURE_CUBE_MAP) { for (int i = 0; i < 6; ++i) { const TexImageTarget curTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; const GLenum error = DoTexImage(mGL, curTarget.get(), 0, &dui, 1, 1, 1, zeros.get()); if (error) { const nsPrintfCString text("DoTexImage failed with `error`: 0x%04x, " "for `curTarget`: 0x%04x, " "`dui`: {0x%04x, 0x%04x, 0x%04x}.", error, curTarget.get(), dui.internalFormat, dui.unpackFormat, dui.unpackType); gfxCriticalError() << text.BeginReading(); MOZ_CRASH("Unexpected error during cube map FakeBlack creation."); } } } else { const GLenum error = DoTexImage(mGL, target.get(), 0, &dui, 1, 1, 1, zeros.get()); if (error) { const nsPrintfCString text("DoTexImage failed with `error`: 0x%04x, " "for `target`: 0x%04x, " "`dui`: {0x%04x, 0x%04x, 0x%04x}.", error, target.get(), dui.internalFormat, dui.unpackFormat, dui.unpackType); gfxCriticalError() << text.BeginReading(); MOZ_CRASH("Unexpected error during FakeBlack creation."); } } }