static already_AddRefed<ID3D10Texture2D> SurfaceToTexture(ID3D10Device *aDevice, gfxASurface *aSurface, const gfxIntSize &aSize) { if (!aSurface) { return NULL; } if (aSurface->GetType() == gfxASurface::SurfaceTypeD2D) { void *data = aSurface->GetData(&gKeyD3D10Texture); if (data) { nsRefPtr<ID3D10Texture2D> texture = static_cast<ID3D10Texture2D*>(data); ID3D10Device *dev; texture->GetDevice(&dev); if (dev == aDevice) { return texture.forget(); } } } nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface(); if (!imageSurface) { imageSurface = new gfxImageSurface(aSize, gfxASurface::ImageFormatARGB32); nsRefPtr<gfxContext> context = new gfxContext(imageSurface); context->SetSource(aSurface); context->SetOperator(gfxContext::OPERATOR_SOURCE); context->Paint(); } return DataToTexture(aDevice, imageSurface->Data(), imageSurface->Stride(), aSize); }
/** * Returns a shader resource view for a Cairo or remote image. * Returns nsnull if unsuccessful. * If successful, aHasAlpha will be true iff the resulting texture * has an alpha component. */ ID3D10ShaderResourceView* ImageLayerD3D10::GetImageSRView(Image* aImage, bool& aHasAlpha) { NS_ASSERTION(aImage, "Null image."); if (aImage->GetFormat() == Image::REMOTE_IMAGE_BITMAP) { RemoteBitmapImage *remoteImage = static_cast<RemoteBitmapImage*>(aImage); if (!aImage->GetBackendData(LayerManager::LAYERS_D3D10)) { nsAutoPtr<TextureD3D10BackendData> dat = new TextureD3D10BackendData(); dat->mTexture = DataToTexture(device(), remoteImage->mData, remoteImage->mStride, remoteImage->mSize); if (dat->mTexture) { device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView)); aImage->SetBackendData(LayerManager::LAYERS_D3D10, dat.forget()); } } aHasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32; } else if (aImage->GetFormat() == Image::CAIRO_SURFACE) { CairoImage *cairoImage = static_cast<CairoImage*>(aImage); if (!cairoImage->mSurface) { return nsnull; } if (!aImage->GetBackendData(LayerManager::LAYERS_D3D10)) { nsAutoPtr<TextureD3D10BackendData> dat = new TextureD3D10BackendData(); dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize); if (dat->mTexture) { device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView)); aImage->SetBackendData(LayerManager::LAYERS_D3D10, dat.forget()); } } aHasAlpha = cairoImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA; } else { NS_WARNING("Incorrect image type."); return nsnull; } TextureD3D10BackendData *data = static_cast<TextureD3D10BackendData*>(aImage->GetBackendData(LayerManager::LAYERS_D3D10)); if (!data) { return nsnull; } nsRefPtr<ID3D10Device> dev; data->mTexture->GetDevice(getter_AddRefs(dev)); if (dev != device()) { return nsnull; } return data->mSRView; }
/** * Returns a shader resource view for a Cairo or remote image. * Returns nullptr if unsuccessful. * If successful, aHasAlpha will be true iff the resulting texture * has an alpha component. */ ID3D10ShaderResourceView* ImageLayerD3D10::GetImageSRView(Image* aImage, bool& aHasAlpha, IDXGIKeyedMutex **aMutex) { NS_ASSERTION(aImage, "Null image."); if (aImage->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP) { RemoteBitmapImage *remoteImage = static_cast<RemoteBitmapImage*>(aImage); if (!aImage->GetBackendData(mozilla::layers::LAYERS_D3D10)) { nsAutoPtr<TextureD3D10BackendData> dat(new TextureD3D10BackendData()); dat->mTexture = DataToTexture(device(), remoteImage->mData, remoteImage->mStride, remoteImage->mSize); if (dat->mTexture) { device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView)); aImage->SetBackendData(mozilla::layers::LAYERS_D3D10, dat.forget()); } } aHasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32; } else if (aImage->GetFormat() == ImageFormat::REMOTE_IMAGE_DXGI_TEXTURE) { RemoteDXGITextureImage *remoteImage = static_cast<RemoteDXGITextureImage*>(aImage); remoteImage->GetD3D10TextureBackendData(device()); aHasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32; } else if (aImage->GetFormat() == ImageFormat::CAIRO_SURFACE) { CairoImage *cairoImage = static_cast<CairoImage*>(aImage); if (!cairoImage->mSurface) { return nullptr; } if (!aImage->GetBackendData(mozilla::layers::LAYERS_D3D10)) { nsAutoPtr<TextureD3D10BackendData> dat(new TextureD3D10BackendData()); dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize); if (dat->mTexture) { device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView)); aImage->SetBackendData(mozilla::layers::LAYERS_D3D10, dat.forget()); } } aHasAlpha = cairoImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA; } else if (aImage->GetFormat() == ImageFormat::D3D9_RGB32_TEXTURE) { if (!aImage->GetBackendData(mozilla::layers::LAYERS_D3D10)) { // Use resource sharing to open the D3D9 texture as a D3D10 texture, HRESULT hr; D3D9SurfaceImage* d3dImage = reinterpret_cast<D3D9SurfaceImage*>(aImage); nsRefPtr<ID3D10Texture2D> texture; hr = device()->OpenSharedResource(d3dImage->GetShareHandle(), IID_ID3D10Texture2D, (void**)getter_AddRefs(texture)); NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); nsAutoPtr<TextureD3D10BackendData> dat(new TextureD3D10BackendData()); dat->mTexture = texture; hr = device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView)); NS_ENSURE_TRUE(SUCCEEDED(hr) && dat->mSRView, nullptr); aImage->SetBackendData(mozilla::layers::LAYERS_D3D10, dat.forget()); } aHasAlpha = false; } else { NS_WARNING("Incorrect image type."); return nullptr; } TextureD3D10BackendData *data = static_cast<TextureD3D10BackendData*>(aImage->GetBackendData(mozilla::layers::LAYERS_D3D10)); if (!data) { return nullptr; } if (aMutex && SUCCEEDED(data->mTexture->QueryInterface(IID_IDXGIKeyedMutex, (void**)aMutex))) { if (FAILED((*aMutex)->AcquireSync(0, 0))) { NS_WARNING("Failed to acquire sync on keyed mutex, plugin forgot to release?"); return nullptr; } } nsRefPtr<ID3D10Device> dev; data->mTexture->GetDevice(getter_AddRefs(dev)); if (dev != device()) { return nullptr; } return data->mSRView; }
void ImageLayerD3D10::RenderLayer() { ImageContainer *container = GetContainer(); if (!container) { return; } AutoLockImage autoLock(container); Image *image = autoLock.GetImage(); if (!image) { return; } gfxIntSize size = mScaleMode == SCALE_NONE ? image->GetSize() : mScaleToSize; SetEffectTransformAndOpacity(); ID3D10EffectTechnique *technique; if (image->GetFormat() == Image::CAIRO_SURFACE || image->GetFormat() == Image::REMOTE_IMAGE_BITMAP) { bool hasAlpha = false; if (image->GetFormat() == Image::REMOTE_IMAGE_BITMAP) { RemoteBitmapImage *remoteImage = static_cast<RemoteBitmapImage*>(image); if (!image->GetBackendData(LayerManager::LAYERS_D3D10)) { nsAutoPtr<TextureD3D10BackendData> dat = new TextureD3D10BackendData(); dat->mTexture = DataToTexture(device(), remoteImage->mData, remoteImage->mStride, remoteImage->mSize); if (dat->mTexture) { device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView)); image->SetBackendData(LayerManager::LAYERS_D3D10, dat.forget()); } } hasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32; } else { CairoImage *cairoImage = static_cast<CairoImage*>(image); if (!cairoImage->mSurface) { return; } if (!image->GetBackendData(LayerManager::LAYERS_D3D10)) { nsAutoPtr<TextureD3D10BackendData> dat = new TextureD3D10BackendData(); dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize); if (dat->mTexture) { device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView)); image->SetBackendData(LayerManager::LAYERS_D3D10, dat.forget()); } } hasAlpha = cairoImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA; } TextureD3D10BackendData *data = static_cast<TextureD3D10BackendData*>(image->GetBackendData(LayerManager::LAYERS_D3D10)); if (!data) { return; } nsRefPtr<ID3D10Device> dev; data->mTexture->GetDevice(getter_AddRefs(dev)); if (dev != device()) { return; } if (hasAlpha) { if (mFilter == gfxPattern::FILTER_NEAREST) { technique = effect()->GetTechniqueByName("RenderRGBALayerPremulPoint"); } else { technique = effect()->GetTechniqueByName("RenderRGBALayerPremul"); } } else { if (mFilter == gfxPattern::FILTER_NEAREST) { technique = effect()->GetTechniqueByName("RenderRGBLayerPremulPoint"); } else { technique = effect()->GetTechniqueByName("RenderRGBLayerPremul"); } } effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(data->mSRView); effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector( ShaderConstantRectD3D10( (float)0, (float)0, (float)size.width, (float)size.height) ); } else if (image->GetFormat() == Image::PLANAR_YCBCR) { PlanarYCbCrImage *yuvImage = static_cast<PlanarYCbCrImage*>(image); if (!yuvImage->mBufferSize) { return; } if (!yuvImage->GetBackendData(LayerManager::LAYERS_D3D10)) { AllocateTexturesYCbCr(yuvImage); } PlanarYCbCrD3D10BackendData *data = static_cast<PlanarYCbCrD3D10BackendData*>(yuvImage->GetBackendData(LayerManager::LAYERS_D3D10)); if (!data) { return; } nsRefPtr<ID3D10Device> dev; data->mYTexture->GetDevice(getter_AddRefs(dev)); if (dev != device()) { return; } // TODO: At some point we should try to deal with mFilter here, you don't // really want to use point filtering in the case of NEAREST, since that // would also use point filtering for Chroma upsampling. Where most likely // the user would only want point filtering for final RGB image upsampling. technique = effect()->GetTechniqueByName("RenderYCbCrLayer"); effect()->GetVariableByName("tY")->AsShaderResource()->SetResource(data->mYView); effect()->GetVariableByName("tCb")->AsShaderResource()->SetResource(data->mCbView); effect()->GetVariableByName("tCr")->AsShaderResource()->SetResource(data->mCrView); /* * Send 3d control data and metadata to NV3DVUtils */ if (GetNv3DVUtils()) { Nv_Stereo_Mode mode; switch (yuvImage->mData.mStereoMode) { case STEREO_MODE_LEFT_RIGHT: mode = NV_STEREO_MODE_LEFT_RIGHT; break; case STEREO_MODE_RIGHT_LEFT: mode = NV_STEREO_MODE_RIGHT_LEFT; break; case STEREO_MODE_BOTTOM_TOP: mode = NV_STEREO_MODE_BOTTOM_TOP; break; case STEREO_MODE_TOP_BOTTOM: mode = NV_STEREO_MODE_TOP_BOTTOM; break; case STEREO_MODE_MONO: mode = NV_STEREO_MODE_MONO; break; } // Send control data even in mono case so driver knows to leave stereo mode. GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE); if (yuvImage->mData.mStereoMode != STEREO_MODE_MONO) { // Dst resource is optional GetNv3DVUtils()->SendNv3DVMetaData((unsigned int)yuvImage->mSize.width, (unsigned int)yuvImage->mSize.height, (HANDLE)(data->mYTexture), (HANDLE)(NULL)); } } effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector( ShaderConstantRectD3D10( (float)0, (float)0, (float)size.width, (float)size.height) ); effect()->GetVariableByName("vTextureCoords")->AsVector()->SetFloatVector( ShaderConstantRectD3D10( (float)yuvImage->mData.mPicX / yuvImage->mData.mYSize.width, (float)yuvImage->mData.mPicY / yuvImage->mData.mYSize.height, (float)yuvImage->mData.mPicSize.width / yuvImage->mData.mYSize.width, (float)yuvImage->mData.mPicSize.height / yuvImage->mData.mYSize.height) ); } bool resetTexCoords = image->GetFormat() == Image::PLANAR_YCBCR; image = nsnull; autoLock.Unlock(); technique->GetPassByIndex(0)->Apply(0); device()->Draw(4, 0); if (resetTexCoords) { effect()->GetVariableByName("vTextureCoords")->AsVector()-> SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f)); } GetContainer()->NotifyPaintedImage(image); }