void Mask::CreateBoundaryImageInRegion(const itk::ImageRegion<2>& region, BoundaryImageType* const boundaryImage, const HoleMaskPixelTypeEnum& whichSideOfBoundary) const { // Create a binary image of the mask unsigned char holeColor = 255; unsigned char validColor = 0; UnsignedCharImageType::Pointer fullBinaryImage = UnsignedCharImageType::New(); CreateBinaryImageInRegion(region, fullBinaryImage, holeColor, validColor); // Extract the relevant region from the binary image UnsignedCharImageType::Pointer binaryImage = UnsignedCharImageType::New(); binaryImage->SetRegions(region); binaryImage->Allocate(); CopyRegion(fullBinaryImage.GetPointer(), binaryImage.GetPointer(), region, region); // Extract the relevant region from the mask Mask::Pointer extractedRegionMask = Mask::New(); extractedRegionMask->SetRegions(region); extractedRegionMask->Allocate(); CopyRegion(this, extractedRegionMask.GetPointer(), region, region); // Since the hole is white (we have specified this at the beginning of this function), // we want the foreground value of the contour filter to be black. // This means that the boundary will be detected in the black pixel region, // which is on the outside edge of the hole like we want. However, // The BinaryContourImageFilter will change all non-boundary pixels to the background color, // so the resulting output will be inverted - the boundary pixels will be black and the // non-boundary pixels will be white. // Find the boundary typedef itk::BinaryContourImageFilter<UnsignedCharImageType, UnsignedCharImageType> binaryContourImageFilterType; binaryContourImageFilterType::Pointer binaryContourFilter = binaryContourImageFilterType::New(); binaryContourFilter->SetInput(binaryImage); binaryContourFilter->SetFullyConnected(true); if(whichSideOfBoundary == HoleMaskPixelTypeEnum::VALID) { // we want the boundary pixels to be in the valid region. binaryContourFilter->SetForegroundValue(validColor); binaryContourFilter->SetBackgroundValue(holeColor); } else if(whichSideOfBoundary == HoleMaskPixelTypeEnum::HOLE) { // we want the boundary pixels to be in the hole region. binaryContourFilter->SetForegroundValue(holeColor); binaryContourFilter->SetBackgroundValue(validColor); } else { throw std::runtime_error("An invalid side of the boundary was requested."); } binaryContourFilter->Update(); DeepCopy(binaryContourFilter->GetOutput(), boundaryImage); }
Result GraphicsInterfaceD3D11::writeTexture2D(void *dst_tex_, int width, int height, TextureFormat format, const void *src, size_t write_size) { if (write_size == 0) { return Result::OK; } if (!dst_tex_ || !src) { return Result::InvalidParameter; } auto *dst_tex = (ID3D11Texture2D*)dst_tex_; auto proc_write = [this](ID3D11Texture2D *tex, int width, int height, TextureFormat format, const void *src, size_t write_size) -> HRESULT { D3D11_MAPPED_SUBRESOURCE mapped = { 0 }; auto hr = m_context->Map(tex, 0, D3D11_MAP_WRITE, 0, &mapped); if (FAILED(hr)) { return hr; } auto *dst_pixels = (char*)mapped.pData; auto *src_pixels = (const char*)src; int dst_pitch = mapped.RowPitch; int src_pitch = width * GetTexelSize(format); int num_rows = std::min<int>(height, (int)ceildiv<size_t>(write_size, src_pitch)); CopyRegion(dst_pixels, dst_pitch, src_pixels, src_pitch, num_rows); m_context->Unmap(tex, 0); return S_OK; }; // try direct access auto hr = proc_write(dst_tex, width, height, format, src, write_size); if (SUCCEEDED(hr)) { return Result::OK; } // try copy-via-staging auto staging = createStagingTexture(width, height, format, StagingFlag::Upload); hr = proc_write(staging.Get(), width, height, format, src, write_size); m_context->CopyResource(dst_tex, staging.Get()); return TranslateReturnCode(hr); }
Result GraphicsInterfaceD3D11::readTexture2D(void *dst, size_t read_size, void *src_tex_, int width, int height, TextureFormat format) { if (read_size == 0) { return Result::OK; } if (!dst || !src_tex_) { return Result::InvalidParameter; } auto *src_tex = (ID3D11Texture2D*)src_tex_; auto proc_read = [this](void *dst, size_t dst_size, ID3D11Texture2D *tex, int width, int height, TextureFormat format) -> HRESULT { D3D11_MAPPED_SUBRESOURCE mapped = { 0 }; auto hr = m_context->Map(tex, 0, D3D11_MAP_READ, 0, &mapped); if (FAILED(hr)) { return hr; } auto *dst_pixels = (char*)dst; auto *src_pixels = (const char*)mapped.pData; int dst_pitch = width * GetTexelSize(format); int src_pitch = mapped.RowPitch; int num_rows = std::min<int>(height, (int)ceildiv<size_t>(dst_size, dst_pitch)); CopyRegion(dst_pixels, dst_pitch, src_pixels, src_pitch, num_rows); m_context->Unmap(tex, 0); return S_OK; }; // try direct access auto hr = proc_read(dst, read_size, src_tex, width, height, format); if (SUCCEEDED(hr)) { return Result::OK; } // try copy-via-staging auto staging = createStagingTexture(width, height, format, StagingFlag::Readback); m_context->CopyResource(staging.Get(), src_tex); sync(); // Map() doesn't wait completion of above CopyResource(). manual synchronization is required. hr = proc_read(dst, read_size, staging.Get(), width, height, format); return TranslateReturnCode(hr); }
void ThebesLayerD3D10::Validate(ReadbackProcessor *aReadback) { if (mVisibleRegion.IsEmpty()) { return; } nsIntRect newTextureRect = mVisibleRegion.GetBounds(); SurfaceMode mode = GetSurfaceMode(); if (mode == SURFACE_COMPONENT_ALPHA && (!mParent || !mParent->SupportsComponentAlphaChildren())) { mode = SURFACE_SINGLE_CHANNEL_ALPHA; } // If we have a transform that requires resampling of our texture, then // we need to make sure we don't sample pixels that haven't been drawn. // We clamp sample coordinates to the texture rect, but when the visible region // doesn't fill the entire texture rect we need to make sure we draw all the // pixels in the texture rect anyway in case they get sampled. nsIntRegion neededRegion = mVisibleRegion; if (!neededRegion.GetBounds().IsEqualInterior(newTextureRect) || neededRegion.GetNumRects() > 1) { gfxMatrix transform2d; if (!GetEffectiveTransform().Is2D(&transform2d) || transform2d.HasNonIntegerTranslation()) { neededRegion = newTextureRect; if (mode == SURFACE_OPAQUE) { // We're going to paint outside the visible region, but layout hasn't // promised that it will paint opaquely there, so we'll have to // treat this layer as transparent. mode = SURFACE_SINGLE_CHANNEL_ALPHA; } } } mCurrentSurfaceMode = mode; VerifyContentType(mode); nsTArray<ReadbackProcessor::Update> readbackUpdates; nsIntRegion readbackRegion; if (aReadback && UsedForReadback()) { aReadback->GetThebesLayerUpdates(this, &readbackUpdates, &readbackRegion); } if (mTexture) { if (!mTextureRect.IsEqualInterior(newTextureRect)) { nsRefPtr<ID3D10Texture2D> oldTexture = mTexture; mTexture = nullptr; nsRefPtr<ID3D10Texture2D> oldTextureOnWhite = mTextureOnWhite; mTextureOnWhite = nullptr; nsIntRegion retainRegion = mTextureRect; // Old visible region will become the region that is covered by both the // old and the new visible region. retainRegion.And(retainRegion, mVisibleRegion); // No point in retaining parts which were not valid. retainRegion.And(retainRegion, mValidRegion); CreateNewTextures(gfxIntSize(newTextureRect.width, newTextureRect.height), mode); nsIntRect largeRect = retainRegion.GetLargestRectangle(); // If we had no hardware texture before, or have no retained area larger than // the retention threshold, we're not retaining and are done here. // If our texture creation failed this can mean a device reset is pending // and we should silently ignore the failure. In the future when device // failures are properly handled we should test for the type of failure // and gracefully handle different failures. See bug 569081. if (!oldTexture || !mTexture || largeRect.width * largeRect.height < RETENTION_THRESHOLD) { mValidRegion.SetEmpty(); } else { CopyRegion(oldTexture, mTextureRect.TopLeft(), mTexture, newTextureRect.TopLeft(), retainRegion, &mValidRegion); if (oldTextureOnWhite) { CopyRegion(oldTextureOnWhite, mTextureRect.TopLeft(), mTextureOnWhite, newTextureRect.TopLeft(), retainRegion, &mValidRegion); } } } } mTextureRect = newTextureRect; if (!mTexture || (mode == SURFACE_COMPONENT_ALPHA && !mTextureOnWhite)) { CreateNewTextures(gfxIntSize(newTextureRect.width, newTextureRect.height), mode); mValidRegion.SetEmpty(); } nsIntRegion drawRegion; drawRegion.Sub(neededRegion, mValidRegion); if (!drawRegion.IsEmpty()) { LayerManagerD3D10::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); if (!cbInfo.Callback) { NS_ERROR("D3D10 should never need to update ThebesLayers in an empty transaction"); return; } DrawRegion(drawRegion, mode); if (readbackUpdates.Length() > 0) { CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, newTextureRect.width, newTextureRect.height, 1, 1, 0, D3D10_USAGE_STAGING, D3D10_CPU_ACCESS_READ); nsRefPtr<ID3D10Texture2D> readbackTexture; HRESULT hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(readbackTexture)); if (FAILED(hr)) { LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("ThebesLayerD3D10::Validate(): Failed to create texture"), hr); return; } device()->CopyResource(readbackTexture, mTexture); for (uint32_t i = 0; i < readbackUpdates.Length(); i++) { mD3DManager->readbackManager()->PostTask(readbackTexture, &readbackUpdates[i], gfxPoint(newTextureRect.x, newTextureRect.y)); } } mValidRegion = neededRegion; } }