michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "CanvasLayerD3D10.h" michael@0: michael@0: #include "../d3d9/Nv3DVUtils.h" michael@0: #include "gfxWindowsSurface.h" michael@0: #include "gfxWindowsPlatform.h" michael@0: #include "SurfaceStream.h" michael@0: #include "SharedSurfaceANGLE.h" michael@0: #include "SharedSurfaceGL.h" michael@0: #include "gfxContext.h" michael@0: #include "GLContext.h" michael@0: #include "gfxPrefs.h" michael@0: michael@0: using namespace mozilla::gl; michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: CanvasLayerD3D10::CanvasLayerD3D10(LayerManagerD3D10 *aManager) michael@0: : CanvasLayer(aManager, nullptr) michael@0: , LayerD3D10(aManager) michael@0: , mDataIsPremultiplied(false) michael@0: , mNeedsYFlip(false) michael@0: , mHasAlpha(true) michael@0: { michael@0: mImplData = static_cast(this); michael@0: } michael@0: michael@0: CanvasLayerD3D10::~CanvasLayerD3D10() michael@0: { michael@0: } michael@0: michael@0: void michael@0: CanvasLayerD3D10::Initialize(const Data& aData) michael@0: { michael@0: NS_ASSERTION(mSurface == nullptr, "BasicCanvasLayer::Initialize called twice!"); michael@0: michael@0: if (aData.mGLContext) { michael@0: mGLContext = aData.mGLContext; michael@0: NS_ASSERTION(mGLContext->IsOffscreen(), "Canvas GLContext must be offscreen."); michael@0: mDataIsPremultiplied = aData.mIsGLAlphaPremult; michael@0: mNeedsYFlip = true; michael@0: michael@0: GLScreenBuffer* screen = mGLContext->Screen(); michael@0: SurfaceStreamType streamType = michael@0: SurfaceStream::ChooseGLStreamType(SurfaceStream::MainThread, michael@0: screen->PreserveBuffer()); michael@0: michael@0: SurfaceFactory_GL* factory = nullptr; michael@0: if (!gfxPrefs::WebGLForceLayersReadback()) { michael@0: if (mGLContext->IsANGLE()) { michael@0: factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, michael@0: device(), michael@0: screen->Caps()); michael@0: } michael@0: } michael@0: michael@0: if (factory) { michael@0: screen->Morph(factory, streamType); michael@0: } michael@0: } else if (aData.mDrawTarget) { michael@0: mDrawTarget = aData.mDrawTarget; michael@0: mNeedsYFlip = false; michael@0: mDataIsPremultiplied = true; michael@0: void *texture = mDrawTarget->GetNativeSurface(NativeSurfaceType::D3D10_TEXTURE); michael@0: michael@0: if (texture) { michael@0: mTexture = static_cast(texture); michael@0: michael@0: NS_ASSERTION(!aData.mGLContext, michael@0: "CanvasLayer can't have both DrawTarget and WebGLContext/Surface"); michael@0: michael@0: mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); michael@0: device()->CreateShaderResourceView(mTexture, nullptr, getter_AddRefs(mSRView)); michael@0: return; michael@0: } michael@0: michael@0: // XXX we should store mDrawTarget and use it directly in UpdateSurface, michael@0: // bypassing Thebes michael@0: mSurface = mDrawTarget->Snapshot(); michael@0: } else { michael@0: NS_ERROR("CanvasLayer created without mSurface, mDrawTarget or mGLContext?"); michael@0: } michael@0: michael@0: mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); michael@0: mIsD2DTexture = false; michael@0: michael@0: // Create a texture in case we need to readback. michael@0: CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, mBounds.width, mBounds.height, 1, 1); michael@0: desc.Usage = D3D10_USAGE_DYNAMIC; michael@0: desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; michael@0: michael@0: HRESULT hr = device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(mTexture)); michael@0: if (FAILED(hr)) { michael@0: NS_WARNING("Failed to create texture for CanvasLayer!"); michael@0: return; michael@0: } michael@0: michael@0: device()->CreateShaderResourceView(mTexture, nullptr, getter_AddRefs(mUploadSRView)); michael@0: } michael@0: michael@0: void michael@0: CanvasLayerD3D10::UpdateSurface() michael@0: { michael@0: if (!IsDirty()) michael@0: return; michael@0: Painted(); michael@0: michael@0: if (mDrawTarget) { michael@0: mDrawTarget->Flush(); michael@0: } else if (mIsD2DTexture) { michael@0: return; michael@0: } michael@0: michael@0: if (!mTexture) { michael@0: return; michael@0: } michael@0: michael@0: if (mGLContext) { michael@0: SharedSurface_GL* surf = mGLContext->RequestFrame(); michael@0: if (!surf) { michael@0: return; michael@0: } michael@0: michael@0: switch (surf->Type()) { michael@0: case SharedSurfaceType::EGLSurfaceANGLE: { michael@0: SharedSurface_ANGLEShareHandle* shareSurf = SharedSurface_ANGLEShareHandle::Cast(surf); michael@0: michael@0: mSRView = shareSurf->GetSRV(); michael@0: return; michael@0: } michael@0: case SharedSurfaceType::Basic: { michael@0: SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf); michael@0: // WebGL reads entire surface. michael@0: D3D10_MAPPED_TEXTURE2D map; michael@0: michael@0: HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map); michael@0: michael@0: if (FAILED(hr)) { michael@0: NS_WARNING("Failed to map CanvasLayer texture."); michael@0: return; michael@0: } michael@0: michael@0: DataSourceSurface* frameData = shareSurf->GetData(); michael@0: // Scope for DrawTarget, so it's destroyed before Unmap. michael@0: { michael@0: IntSize boundsSize(mBounds.width, mBounds.height); michael@0: RefPtr mapDt = Factory::CreateDrawTargetForData(BackendType::CAIRO, michael@0: (uint8_t*)map.pData, michael@0: boundsSize, michael@0: map.RowPitch, michael@0: SurfaceFormat::B8G8R8A8); michael@0: michael@0: Rect drawRect(0, 0, frameData->GetSize().width, frameData->GetSize().height); michael@0: mapDt->DrawSurface(frameData, drawRect, drawRect, michael@0: DrawSurfaceOptions(), DrawOptions(1.0F, CompositionOp::OP_SOURCE)); michael@0: mapDt->Flush(); michael@0: } michael@0: michael@0: mTexture->Unmap(0); michael@0: mSRView = mUploadSRView; michael@0: break; michael@0: } michael@0: michael@0: default: michael@0: MOZ_CRASH("Unhandled SharedSurfaceType."); michael@0: } michael@0: } else if (mSurface) { michael@0: D3D10_MAPPED_TEXTURE2D map; michael@0: HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map); michael@0: michael@0: if (FAILED(hr)) { michael@0: NS_WARNING("Failed to lock CanvasLayer texture."); michael@0: return; michael@0: } michael@0: michael@0: RefPtr destTarget = michael@0: Factory::CreateDrawTargetForD3D10Texture(mTexture, michael@0: SurfaceFormat::R8G8B8A8); michael@0: Rect r(Point(0, 0), ToRect(mBounds).Size()); michael@0: destTarget->DrawSurface(mSurface, r, r, DrawSurfaceOptions(), michael@0: DrawOptions(1.0F, CompositionOp::OP_SOURCE)); michael@0: michael@0: mTexture->Unmap(0); michael@0: mSRView = mUploadSRView; michael@0: } michael@0: } michael@0: michael@0: Layer* michael@0: CanvasLayerD3D10::GetLayer() michael@0: { michael@0: return this; michael@0: } michael@0: michael@0: void michael@0: CanvasLayerD3D10::RenderLayer() michael@0: { michael@0: FirePreTransactionCallback(); michael@0: UpdateSurface(); michael@0: FireDidTransactionCallback(); michael@0: michael@0: if (!mTexture) michael@0: return; michael@0: michael@0: nsIntRect visibleRect = mVisibleRegion.GetBounds(); michael@0: michael@0: SetEffectTransformAndOpacity(); michael@0: michael@0: uint8_t shaderFlags = 0; michael@0: shaderFlags |= LoadMaskTexture(); michael@0: shaderFlags |= mDataIsPremultiplied michael@0: ? SHADER_PREMUL : SHADER_NON_PREMUL | SHADER_RGBA; michael@0: shaderFlags |= mHasAlpha ? SHADER_RGBA : SHADER_RGB; michael@0: shaderFlags |= mFilter == GraphicsFilter::FILTER_NEAREST michael@0: ? SHADER_POINT : SHADER_LINEAR; michael@0: ID3D10EffectTechnique* technique = SelectShader(shaderFlags); michael@0: michael@0: if (mSRView) { michael@0: effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(mSRView); michael@0: } michael@0: michael@0: effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector( michael@0: ShaderConstantRectD3D10( michael@0: (float)mBounds.x, michael@0: (float)mBounds.y, michael@0: (float)mBounds.width, michael@0: (float)mBounds.height) michael@0: ); michael@0: michael@0: if (mNeedsYFlip) { michael@0: effect()->GetVariableByName("vTextureCoords")->AsVector()->SetFloatVector( michael@0: ShaderConstantRectD3D10( michael@0: 0, michael@0: 1.0f, michael@0: 1.0f, michael@0: -1.0f) michael@0: ); michael@0: } michael@0: michael@0: technique->GetPassByIndex(0)->Apply(0); michael@0: device()->Draw(4, 0); michael@0: michael@0: if (mNeedsYFlip) { michael@0: effect()->GetVariableByName("vTextureCoords")->AsVector()-> michael@0: SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f)); michael@0: } michael@0: } michael@0: michael@0: } /* namespace layers */ michael@0: } /* namespace mozilla */