From 01d768b811505b7c01c16fda20d15e907f909b64 Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Mon, 24 May 2010 17:28:51 +0200 Subject: [PATCH] Bug 546515: Part 1: Add a layers backend based on Direct3D9. r=jrmuizel --- gfx/layers/Layers.h | 3 +- gfx/layers/Makefile.in | 19 + gfx/layers/d3d9/CanvasLayerD3D9.cpp | 231 ++++++++ gfx/layers/d3d9/CanvasLayerD3D9.h | 90 +++ gfx/layers/d3d9/ColorLayerD3D9.cpp | 91 +++ gfx/layers/d3d9/ColorLayerD3D9.h | 74 +++ gfx/layers/d3d9/ContainerLayerD3D9.cpp | 252 ++++++++ gfx/layers/d3d9/ContainerLayerD3D9.h | 80 +++ gfx/layers/d3d9/ImageLayerD3D9.cpp | 463 +++++++++++++++ gfx/layers/d3d9/ImageLayerD3D9.h | 155 +++++ gfx/layers/d3d9/LayerManagerD3D9.cpp | 578 +++++++++++++++++++ gfx/layers/d3d9/LayerManagerD3D9.h | 239 ++++++++ gfx/layers/d3d9/LayerManagerD3D9Shaders.h | 435 ++++++++++++++ gfx/layers/d3d9/LayerManagerD3D9Shaders.hlsl | 61 ++ gfx/layers/d3d9/ThebesLayerD3D9.cpp | 216 +++++++ gfx/layers/d3d9/ThebesLayerD3D9.h | 92 +++ 16 files changed, 3078 insertions(+), 1 deletion(-) create mode 100644 gfx/layers/d3d9/CanvasLayerD3D9.cpp create mode 100644 gfx/layers/d3d9/CanvasLayerD3D9.h create mode 100644 gfx/layers/d3d9/ColorLayerD3D9.cpp create mode 100644 gfx/layers/d3d9/ColorLayerD3D9.h create mode 100644 gfx/layers/d3d9/ContainerLayerD3D9.cpp create mode 100644 gfx/layers/d3d9/ContainerLayerD3D9.h create mode 100644 gfx/layers/d3d9/ImageLayerD3D9.cpp create mode 100644 gfx/layers/d3d9/ImageLayerD3D9.h create mode 100644 gfx/layers/d3d9/LayerManagerD3D9.cpp create mode 100644 gfx/layers/d3d9/LayerManagerD3D9.h create mode 100644 gfx/layers/d3d9/LayerManagerD3D9Shaders.h create mode 100644 gfx/layers/d3d9/LayerManagerD3D9Shaders.hlsl create mode 100644 gfx/layers/d3d9/ThebesLayerD3D9.cpp create mode 100644 gfx/layers/d3d9/ThebesLayerD3D9.h diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 0f7780f4ca3e..f6cd66861042 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -122,7 +122,8 @@ class THEBES_API LayerManager { public: enum LayersBackend { LAYERS_BASIC = 0, - LAYERS_OPENGL + LAYERS_OPENGL, + LAYERS_D3D9 }; virtual ~LayerManager() {} diff --git a/gfx/layers/Makefile.in b/gfx/layers/Makefile.in index 82271f0727f8..cb4659cf30d2 100644 --- a/gfx/layers/Makefile.in +++ b/gfx/layers/Makefile.in @@ -42,6 +42,7 @@ VPATH = \ $(srcdir) \ $(srcdir)/basic \ $(srcdir)/opengl \ + $(srcdir)/d3d9 \ $(NULL) include $(DEPTH)/config/autoconf.mk @@ -52,6 +53,9 @@ LIBXUL_LIBRARY = 1 FORCE_STATIC_LIB = 1 DEFINES += -DIMPL_THEBES +ifdef MOZ_DEBUG +DEFINES += -DD3D_DEBUG_INFO +endif EXPORTS = \ BasicLayers.h \ @@ -70,6 +74,21 @@ CPPSRCS = \ ImageLayerOGL.cpp \ CanvasLayerOGL.cpp \ $(NULL) + +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +ifndef WINCE +EXPORTS += LayerManagerD3D9.h + +CPPSRCS += \ + LayerManagerD3D9.cpp \ + ThebesLayerD3D9.cpp \ + ContainerLayerD3D9.cpp \ + ImageLayerD3D9.cpp \ + ColorLayerD3D9.cpp \ + CanvasLayerD3D9.cpp \ + $(NULL) +endif +endif include $(topsrcdir)/config/rules.mk diff --git a/gfx/layers/d3d9/CanvasLayerD3D9.cpp b/gfx/layers/d3d9/CanvasLayerD3D9.cpp new file mode 100644 index 000000000000..7fedd8bd311d --- /dev/null +++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp @@ -0,0 +1,231 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Vladimir Vukicevic + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "CanvasLayerD3D9.h" + +#include "gfxImageSurface.h" +#include "gfxWindowsSurface.h" + +namespace mozilla { +namespace layers { + +CanvasLayerD3D9::~CanvasLayerD3D9() +{ +} + +void +CanvasLayerD3D9::Initialize(const Data& aData) +{ + NS_ASSERTION(mSurface == nsnull, "BasicCanvasLayer::Initialize called twice!"); + + if (aData.mSurface) { + mSurface = aData.mSurface; + NS_ASSERTION(aData.mGLContext == nsnull, + "CanvasLayer can't have both surface and GLContext"); + mNeedsYFlip = PR_FALSE; + } else if (aData.mGLContext) { + mGLContext = aData.mGLContext; + mGLBufferIsPremultiplied = aData.mGLBufferIsPremultiplied; + mNeedsYFlip = PR_TRUE; + } else { + NS_ERROR("CanvasLayer created without mSurface or mGLContext?"); + } + + mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); + + device()->CreateTexture(mBounds.width, mBounds.height, 1, 0, + D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, + getter_AddRefs(mTexture), NULL); +} + +void +CanvasLayerD3D9::Updated(const nsIntRect& aRect) +{ + if (!mTexture) { + NS_WARNING("CanvasLayerD3D9::Updated called but no texture present!"); + return; + } + + if (mGLContext) { + // WebGL reads entire surface. + D3DLOCKED_RECT r; + mTexture->LockRect(0, &r, NULL, 0); + + PRUint8 *destination; + if (r.Pitch != mBounds.width * 4) { + destination = new PRUint8[mBounds.width * mBounds.height * 4]; + } else { + destination = (PRUint8*)r.pBits; + } + + // We have to flush to ensure that any buffered GL operations are + // in the framebuffer before we read. + mGLContext->fFlush(); + + // For simplicity, we read the entire framebuffer for now -- in + // the future we should use aRect, though with WebGL we don't + // have an easy way to generate one. + mGLContext->fReadPixels(0, 0, mBounds.width, mBounds.height, + LOCAL_GL_BGRA, LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV, + destination); + + if (r.Pitch != mBounds.width * 4) { + for (int y = 0; y < mBounds.height; y++) { + memcpy((PRUint8*)r.pBits + r.Pitch * y, + destination + mBounds.width * 4 * y, + mBounds.width * 4); + } + delete [] destination; + } + mTexture->UnlockRect(0); + } else if (mSurface) { + RECT r; + r.left = aRect.x; + r.top = aRect.y; + r.right = aRect.XMost(); + r.bottom = aRect.YMost(); + + D3DLOCKED_RECT lockedRect; + mTexture->LockRect(0, &lockedRect, &r, 0); + + PRUint8 *startBits; + PRUint32 sourceStride; + + nsRefPtr sourceSurface; + + if (mSurface->GetType() == gfxASurface::SurfaceTypeWin32) { + sourceSurface = static_cast(mSurface.get())->GetImageSurface(); + startBits = sourceSurface->Data() + sourceSurface->Stride() * aRect.y + + aRect.x * 4; + sourceStride = sourceSurface->Stride(); + } else if (mSurface->GetType() == gfxASurface::SurfaceTypeImage) { + sourceSurface = static_cast(sourceSurface.get()); + if (sourceSurface->Format() != gfxASurface::ImageFormatARGB32 && + sourceSurface->Format() != gfxASurface::ImageFormatRGB24) + { + mTexture->UnlockRect(0); + return; + } + startBits = sourceSurface->Data() + sourceSurface->Stride() * aRect.y + + aRect.x * 4; + sourceStride = sourceSurface->Stride(); + } else { + sourceSurface = new gfxImageSurface(gfxIntSize(aRect.width, aRect.height), + gfxASurface::ImageFormatARGB32); + nsRefPtr ctx = new gfxContext(sourceSurface); + ctx->Translate(gfxPoint(-aRect.x, -aRect.y)); + ctx->SetOperator(gfxContext::OPERATOR_SOURCE); + ctx->SetSource(sourceSurface); + ctx->Paint(); + startBits = sourceSurface->Data(); + sourceStride = sourceSurface->Stride(); + } + + for (int y = 0; y < aRect.height; y++) { + memcpy((PRUint8*)lockedRect.pBits + lockedRect.Pitch * y, + startBits + sourceStride * y, + aRect.width * 4); + } + + mTexture->UnlockRect(0); + } +} + +LayerD3D9::LayerType +CanvasLayerD3D9::GetType() +{ + return TYPE_CANVAS; +} + +Layer* +CanvasLayerD3D9::GetLayer() +{ + return this; +} + +void +CanvasLayerD3D9::RenderLayer() +{ + float quadTransform[4][4]; + /* + * Matrix to transform the <0.0,0.0>, <1.0,1.0> quad to the correct position + * and size. To get pixel perfect mapping we offset the quad half a pixel + * to the top-left. We also flip the Y axis here, note we can only do this + * because we are in CULL_NONE mode! + * + * See: http://msdn.microsoft.com/en-us/library/bb219690%28VS.85%29.aspx + */ + memset(&quadTransform, 0, sizeof(quadTransform)); + quadTransform[0][0] = (float)mBounds.width; + if (mNeedsYFlip) { + quadTransform[1][1] = (float)-mBounds.height; + quadTransform[3][1] = (float)mBounds.height - 0.5f; + } else { + quadTransform[1][1] = (float)mBounds.height; + quadTransform[3][1] = -0.5f; + } + quadTransform[2][2] = 1.0f; + quadTransform[3][0] = -0.5f; + quadTransform[3][3] = 1.0f; + + device()->SetVertexShaderConstantF(0, &quadTransform[0][0], 4); + + device()->SetVertexShaderConstantF(4, &mTransform._11, 4); + + float opacity[4]; + /* + * We always upload a 4 component float, but the shader will use only the + * first component since it's declared as a 'float'. + */ + opacity[0] = GetOpacity(); + device()->SetPixelShaderConstantF(0, opacity, 1); + + mD3DManager->SetShaderMode(LayerManagerD3D9::RGBLAYER); + + if (!mGLBufferIsPremultiplied) { + device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + } + device()->SetTexture(0, mTexture); + device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + if (!mGLBufferIsPremultiplied) { + device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + } +} + +} /* namespace layers */ +} /* namespace mozilla */ \ No newline at end of file diff --git a/gfx/layers/d3d9/CanvasLayerD3D9.h b/gfx/layers/d3d9/CanvasLayerD3D9.h new file mode 100644 index 000000000000..c817ca5dd347 --- /dev/null +++ b/gfx/layers/d3d9/CanvasLayerD3D9.h @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Vladimir Vukicevic + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef GFX_CANVASLAYEROGL_H +#define GFX_CANVASLAYEROGL_H + +#include "LayerManagerD3D9.h" +#include "GLContext.h" +#include "gfxASurface.h" + +namespace mozilla { +namespace layers { + +class THEBES_API CanvasLayerD3D9 : + public CanvasLayer, + public LayerD3D9 +{ +public: + CanvasLayerD3D9(LayerManagerD3D9 *aManager) + : CanvasLayer(aManager, NULL), + LayerD3D9(aManager), + mTexture(0), + mGLBufferIsPremultiplied(PR_FALSE), + mNeedsYFlip(PR_FALSE) + { + mImplData = static_cast(this); + } + + ~CanvasLayerD3D9(); + + // CanvasLayer implementation + virtual void Initialize(const Data& aData); + virtual void Updated(const nsIntRect& aRect); + + // LayerD3D9 implementation + virtual LayerType GetType(); + virtual Layer* GetLayer(); + virtual void RenderLayer(); + +protected: + typedef mozilla::gl::GLContext GLContext; + + nsRefPtr mSurface; + nsRefPtr mGLContext; + nsRefPtr mTexture; + + nsIntRect mBounds; + + PRPackedBool mGLBufferIsPremultiplied; + PRPackedBool mNeedsYFlip; +}; + +} /* layers */ +} /* mozilla */ +#endif /* GFX_CANVASLAYERD3D9_H */ diff --git a/gfx/layers/d3d9/ColorLayerD3D9.cpp b/gfx/layers/d3d9/ColorLayerD3D9.cpp new file mode 100644 index 000000000000..101eceb6f59c --- /dev/null +++ b/gfx/layers/d3d9/ColorLayerD3D9.cpp @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert O'Callahan + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "ColorLayerD3D9.h" + +namespace mozilla { +namespace layers { + +LayerD3D9::LayerType +ColorLayerD3D9::GetType() +{ + return TYPE_COLOR; +} + +Layer* +ColorLayerD3D9::GetLayer() +{ + return this; +} + +void +ColorLayerD3D9::RenderLayer() +{ + // XXX we might be able to improve performance by using + // IDirect3DDevice9::Clear + + float quadTransform[4][4]; + nsIntRect visibleRect = mVisibleRegion.GetBounds(); + // Transform the quad to the size of the visible area. + memset(&quadTransform, 0, sizeof(quadTransform)); + quadTransform[0][0] = (float)visibleRect.width; + quadTransform[1][1] = (float)visibleRect.height; + quadTransform[2][2] = 1.0f; + quadTransform[3][0] = (float)visibleRect.x; + quadTransform[3][1] = (float)visibleRect.y; + quadTransform[3][3] = 1.0f; + + device()->SetVertexShaderConstantF(0, &quadTransform[0][0], 4); + device()->SetVertexShaderConstantF(4, &mTransform._11, 4); + + float color[4]; + // color is premultiplied, so we need to adjust all channels + color[0] = (float)(mColor.r * GetOpacity()); + color[1] = (float)(mColor.g * GetOpacity()); + color[2] = (float)(mColor.b * GetOpacity()); + color[3] = (float)(mColor.a * GetOpacity()); + + device()->SetPixelShaderConstantF(0, color, 1); + + mD3DManager->SetShaderMode(LayerManagerD3D9::SOLIDCOLORLAYER); + + device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); +} + +} /* layers */ +} /* mozilla */ diff --git a/gfx/layers/d3d9/ColorLayerD3D9.h b/gfx/layers/d3d9/ColorLayerD3D9.h new file mode 100644 index 000000000000..bd3c34d033f5 --- /dev/null +++ b/gfx/layers/d3d9/ColorLayerD3D9.h @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert O'Callahan + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef GFX_COLORLAYERD3D9_H +#define GFX_COLORLAYERD3D9_H + +#include "LayerManagerD3D9.h" + +namespace mozilla { +namespace layers { + +class THEBES_API ColorLayerD3D9 : public ColorLayer, + public LayerD3D9 +{ +public: + ColorLayerD3D9(LayerManagerD3D9 *aManager) + : ColorLayer(aManager, NULL) + , LayerD3D9(aManager) + { + mImplData = static_cast(this); + } + + virtual void SetVisibleRegion(const nsIntRegion& aRegion) { mVisibleRegion = aRegion; } + + // LayerD3D9 Implementation + virtual LayerType GetType(); + + virtual Layer* GetLayer(); + + virtual void RenderLayer(); + +protected: + nsIntRegion mVisibleRegion; +}; + +} /* layers */ +} /* mozilla */ + +#endif /* GFX_COLORLAYERD3D9_H */ diff --git a/gfx/layers/d3d9/ContainerLayerD3D9.cpp b/gfx/layers/d3d9/ContainerLayerD3D9.cpp new file mode 100644 index 000000000000..e585ca0b9140 --- /dev/null +++ b/gfx/layers/d3d9/ContainerLayerD3D9.cpp @@ -0,0 +1,252 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "ContainerLayerD3D9.h" + +namespace mozilla { +namespace layers { + +ContainerLayerD3D9::ContainerLayerD3D9(LayerManagerD3D9 *aManager) + : ContainerLayer(aManager, NULL) + , LayerD3D9(aManager) +{ + mImplData = static_cast(this); +} + +const nsIntRect& +ContainerLayerD3D9::GetVisibleRect() +{ + return mVisibleRect; +} + +void +ContainerLayerD3D9::SetVisibleRegion(const nsIntRegion &aRegion) +{ + mVisibleRect = aRegion.GetBounds(); +} + +void +ContainerLayerD3D9::InsertAfter(Layer* aChild, Layer* aAfter) +{ + LayerD3D9 *newChild = static_cast(aChild->ImplData()); + aChild->SetParent(this); + if (!aAfter) { + LayerD3D9 *oldFirstChild = GetFirstChildD3D9(); + mFirstChild = newChild->GetLayer(); + newChild->SetNextSibling(oldFirstChild); + return; + } + for (LayerD3D9 *child = GetFirstChildD3D9(); + child; child = child->GetNextSibling()) { + if (aAfter == child->GetLayer()) { + LayerD3D9 *oldNextSibling = child->GetNextSibling(); + child->SetNextSibling(newChild); + child->GetNextSibling()->SetNextSibling(oldNextSibling); + return; + } + } + NS_WARNING("Failed to find aAfter layer!"); +} + +void +ContainerLayerD3D9::RemoveChild(Layer *aChild) +{ + if (GetFirstChild() == aChild) { + mFirstChild = GetFirstChildD3D9()->GetNextSibling() ? + GetFirstChildD3D9()->GetNextSibling()->GetLayer() : nsnull; + return; + } + LayerD3D9 *lastChild = NULL; + for (LayerD3D9 *child = GetFirstChildD3D9(); child; + child = child->GetNextSibling()) { + if (child->GetLayer() == aChild) { + // We're sure this is not our first child. So lastChild != NULL. + lastChild->SetNextSibling(child->GetNextSibling()); + child->SetNextSibling(NULL); + child->GetLayer()->SetParent(NULL); + return; + } + lastChild = child; + } +} + +LayerD3D9::LayerType +ContainerLayerD3D9::GetType() +{ + return TYPE_CONTAINER; +} + +Layer* +ContainerLayerD3D9::GetLayer() +{ + return this; +} + +LayerD3D9* +ContainerLayerD3D9::GetFirstChildD3D9() +{ + if (!mFirstChild) { + return nsnull; + } + return static_cast(mFirstChild->ImplData()); +} + +void +ContainerLayerD3D9::RenderLayer() +{ + float opacity = GetOpacity(); + nsRefPtr previousRenderTarget; + nsRefPtr renderTexture; + float previousRenderTargetOffset[4]; + float renderTargetOffset[] = { 0, 0, 0, 0 }; + float oldViewMatrix[4][4]; + + PRBool useIntermediate = (opacity != 1.0 || !mTransform.IsIdentity()); + + if (useIntermediate) { + device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget)); + device()->CreateTexture(mVisibleRect.width, mVisibleRect.height, 1, + D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, getter_AddRefs(renderTexture), + NULL); + nsRefPtr renderSurface; + renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface)); + device()->SetRenderTarget(0, renderSurface); + device()->GetVertexShaderConstantF(12, previousRenderTargetOffset, 1); + renderTargetOffset[0] = (float)GetVisibleRect().x; + renderTargetOffset[1] = (float)GetVisibleRect().y; + device()->SetVertexShaderConstantF(12, renderTargetOffset, 1); + + float viewMatrix[4][4]; + /* + * Matrix to transform to viewport space ( <-1.0, 1.0> topleft, + * <1.0, -1.0> bottomright) + */ + memset(&viewMatrix, 0, sizeof(viewMatrix)); + viewMatrix[0][0] = 2.0f / mVisibleRect.width; + viewMatrix[1][1] = -2.0f / mVisibleRect.height; + viewMatrix[2][2] = 1.0f; + viewMatrix[3][0] = -1.0f; + viewMatrix[3][1] = 1.0f; + viewMatrix[3][3] = 1.0f; + + device()->GetVertexShaderConstantF(8, &oldViewMatrix[0][0], 4); + device()->SetVertexShaderConstantF(8, &viewMatrix[0][0], 4); + } + + /* + * Render this container's contents. + */ + LayerD3D9 *layerToRender = GetFirstChildD3D9(); + while (layerToRender) { + const nsIntRect *clipRect = layerToRender->GetLayer()->GetClipRect(); + RECT r; + if (clipRect) { + r.left = (LONG)(clipRect->x - renderTargetOffset[0]); + r.top = (LONG)(clipRect->y - renderTargetOffset[1]); + r.right = (LONG)(clipRect->x - renderTargetOffset[0] + clipRect->width); + r.bottom = (LONG)(clipRect->y - renderTargetOffset[1] + clipRect->height); + } else { + if (useIntermediate) { + r.left = 0; + r.top = 0; + } else { + r.left = GetVisibleRect().x; + r.top = GetVisibleRect().y; + } + r.right = r.left + GetVisibleRect().width; + r.bottom = r.top + GetVisibleRect().height; + } + + nsRefPtr renderSurface; + device()->GetRenderTarget(0, getter_AddRefs(renderSurface)); + + D3DSURFACE_DESC desc; + renderSurface->GetDesc(&desc); + + r.left = NS_MAX(0, r.left); + r.top = NS_MAX(0, r.top); + r.bottom = NS_MIN(r.bottom, desc.Height); + r.right = NS_MIN(r.right, desc.Width); + + device()->SetScissorRect(&r); + + layerToRender->RenderLayer(); + layerToRender = layerToRender->GetNextSibling(); + } + + if (useIntermediate) { + device()->SetRenderTarget(0, previousRenderTarget); + device()->SetVertexShaderConstantF(12, previousRenderTargetOffset, 1); + device()->SetVertexShaderConstantF(8, &oldViewMatrix[0][0], 4); + + float quadTransform[4][4]; + /* + * Matrix to transform the <0.0,0.0>, <1.0,1.0> quad to the correct position + * and size. To get pixel perfect mapping we offset the quad half a pixel + * to the top-left. + * + * See: http://msdn.microsoft.com/en-us/library/bb219690%28VS.85%29.aspx + */ + memset(&quadTransform, 0, sizeof(quadTransform)); + quadTransform[0][0] = (float)GetVisibleRect().width; + quadTransform[1][1] = (float)GetVisibleRect().height; + quadTransform[2][2] = 1.0f; + quadTransform[3][0] = (float)GetVisibleRect().x - 0.5f; + quadTransform[3][1] = (float)GetVisibleRect().y - 0.5f; + quadTransform[3][3] = 1.0f; + + device()->SetVertexShaderConstantF(0, &quadTransform[0][0], 4); + device()->SetVertexShaderConstantF(4, &mTransform._11, 4); + + float opacityVector[4]; + /* + * We always upload a 4 component float, but the shader will use only the + * first component since it's declared as a 'float'. + */ + opacityVector[0] = opacity; + device()->SetPixelShaderConstantF(0, opacityVector, 1); + + mD3DManager->SetShaderMode(LayerManagerD3D9::RGBLAYER); + + device()->SetTexture(0, renderTexture); + device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + } +} + +} /* layers */ +} /* mozilla */ diff --git a/gfx/layers/d3d9/ContainerLayerD3D9.h b/gfx/layers/d3d9/ContainerLayerD3D9.h new file mode 100644 index 000000000000..12dfd0fc9dd1 --- /dev/null +++ b/gfx/layers/d3d9/ContainerLayerD3D9.h @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef GFX_CONTAINERLAYERD3D9_H +#define GFX_CONTAINERLAYERD3D9_H + +#include "Layers.h" +#include "LayerManagerD3D9.h" + +namespace mozilla { +namespace layers { + +class ContainerLayerD3D9 : public ContainerLayer, + public LayerD3D9 +{ +public: + ContainerLayerD3D9(LayerManagerD3D9 *aManager); + + const nsIntRect &GetVisibleRect(); + + /* ContainerLayer implementation */ + void SetVisibleRegion(const nsIntRegion& aRegion); + + void InsertAfter(Layer* aChild, Layer* aAfter); + + void RemoveChild(Layer* aChild); + + /* LayerD3D9 implementation */ + LayerType GetType(); + + Layer* GetLayer(); + + LayerD3D9* GetFirstChildD3D9(); + + PRBool IsEmpty(); + + void RenderLayer(); + +private: + nsIntRect mVisibleRect; +}; + +} /* layers */ +} /* mozilla */ + +#endif /* GFX_CONTAINERLAYERD3D9_H */ diff --git a/gfx/layers/d3d9/ImageLayerD3D9.cpp b/gfx/layers/d3d9/ImageLayerD3D9.cpp new file mode 100644 index 000000000000..11569d3e9a07 --- /dev/null +++ b/gfx/layers/d3d9/ImageLayerD3D9.cpp @@ -0,0 +1,463 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "ImageLayerD3D9.h" +#include "gfxImageSurface.h" +#include "yuv_convert.h" + +namespace mozilla { +namespace layers { + +using mozilla::MutexAutoLock; + +ImageContainerD3D9::ImageContainerD3D9(LayerManagerD3D9 *aManager) + : ImageContainer(aManager) + , mActiveImageLock("mozilla.layers.ImageContainerD3D9.mActiveImageLock") +{ +} + +already_AddRefed +ImageContainerD3D9::CreateImage(const Image::Format *aFormats, + PRUint32 aNumFormats) +{ + if (!aNumFormats) { + return nsnull; + } + nsRefPtr img; + if (aFormats[0] == Image::PLANAR_YCBCR) { + img = new PlanarYCbCrImageD3D9(static_cast(mManager)); + } else if (aFormats[0] == Image::CAIRO_SURFACE) { + img = new CairoImageD3D9(static_cast(mManager)); + } + return img.forget(); +} + +void +ImageContainerD3D9::SetCurrentImage(Image *aImage) +{ + MutexAutoLock lock(mActiveImageLock); + + mActiveImage = aImage; +} + +already_AddRefed +ImageContainerD3D9::GetCurrentImage() +{ + MutexAutoLock lock(mActiveImageLock); + + nsRefPtr retval = mActiveImage; + return retval.forget(); +} + +already_AddRefed +ImageContainerD3D9::GetCurrentAsSurface(gfxIntSize *aSize) +{ + MutexAutoLock lock(mActiveImageLock); + if (!mActiveImage) { + return nsnull; + } + + if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) { + PlanarYCbCrImageD3D9 *yuvImage = + static_cast(mActiveImage.get()); + if (yuvImage->HasData()) { + *aSize = yuvImage->mSize; + } + } else if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) { + CairoImageD3D9 *cairoImage = + static_cast(mActiveImage.get()); + *aSize = cairoImage->mSize; + } + + return static_cast(mActiveImage->GetImplData())->GetAsSurface(); +} + +gfxIntSize +ImageContainerD3D9::GetCurrentSize() +{ + MutexAutoLock lock(mActiveImageLock); + if (!mActiveImage) { + return gfxIntSize(0,0); + } + if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) { + PlanarYCbCrImageD3D9 *yuvImage = + static_cast(mActiveImage.get()); + if (!yuvImage->HasData()) { + return gfxIntSize(0,0); + } + return yuvImage->mSize; + + } else if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) { + CairoImageD3D9 *cairoImage = + static_cast(mActiveImage.get()); + return cairoImage->mSize; + } + + return gfxIntSize(0,0); +} + +LayerD3D9::LayerType +ImageLayerD3D9::GetType() +{ + return TYPE_IMAGE; +} + +Layer* +ImageLayerD3D9::GetLayer() +{ + return this; +} + +void +ImageLayerD3D9::RenderLayer() +{ + if (!GetContainer()) { + return; + } + + nsRefPtr image = GetContainer()->GetCurrentImage(); + + if (image->GetFormat() == Image::PLANAR_YCBCR) { + PlanarYCbCrImageD3D9 *yuvImage = + static_cast(image.get()); + + if (!yuvImage->HasData()) { + return; + } + yuvImage->AllocateTextures(); + + float quadTransform[4][4]; + /* + * Matrix to transform the <0.0,0.0>, <1.0,1.0> quad to the correct position + * and size. To get pixel perfect mapping we extend the quad half a pixel + * beyond all edges. + */ + memset(&quadTransform, 0, sizeof(quadTransform)); + quadTransform[0][0] = (float)yuvImage->mSize.width + 0.5f; + quadTransform[1][1] = (float)yuvImage->mSize.height + 0.5f; + quadTransform[2][2] = 1.0f; + quadTransform[3][3] = 1.0f; + + + device()->SetVertexShaderConstantF(0, &quadTransform[0][0], 4); + device()->SetVertexShaderConstantF(4, &mTransform._11, 4); + + float opacity[4]; + /* + * We always upload a 4 component float, but the shader will + * only use the the first component since it's declared as a 'float'. + */ + opacity[0] = GetOpacity(); + device()->SetPixelShaderConstantF(0, opacity, 1); + + mD3DManager->SetShaderMode(LayerManagerD3D9::YCBCRLAYER); + + device()->SetTexture(0, yuvImage->mYTexture); + device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + device()->SetTexture(1, yuvImage->mCbTexture); + device()->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + device()->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + device()->SetTexture(2, yuvImage->mCrTexture); + device()->SetSamplerState(2, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + device()->SetSamplerState(2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + } else if (image->GetFormat() == Image::CAIRO_SURFACE) { + CairoImageD3D9 *cairoImage = + static_cast(image.get()); + + float quadTransform[4][4]; + /* + * Matrix to transform the <0.0,0.0>, <1.0,1.0> quad to the correct position + * and size. To get pixel perfect mapping we extend the quad half a pixel + * beyond all edges. + */ + memset(&quadTransform, 0, sizeof(quadTransform)); + quadTransform[0][0] = (float)cairoImage->mSize.width + 0.5f; + quadTransform[1][1] = (float)cairoImage->mSize.height + 0.5f; + quadTransform[2][2] = 1.0f; + quadTransform[3][3] = 1.0f; + + + device()->SetVertexShaderConstantF(0, &quadTransform[0][0], 4); + device()->SetVertexShaderConstantF(4, &mTransform._11, 4); + + float opacity[4]; + /* + * We always upload a 4 component float, but the shader will + * only use the the first component since it's declared as a 'float'. + */ + opacity[0] = GetOpacity(); + device()->SetPixelShaderConstantF(0, opacity, 1); + + mD3DManager->SetShaderMode(LayerManagerD3D9::RGBLAYER); + + device()->SetTexture(0, cairoImage->mTexture); + device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + } +} + +PlanarYCbCrImageD3D9::PlanarYCbCrImageD3D9(mozilla::layers::LayerManagerD3D9* aManager) + : PlanarYCbCrImage(static_cast(this)) + , mManager(aManager) + , mHasData(PR_FALSE) +{ +} + +void +PlanarYCbCrImageD3D9::SetData(const PlanarYCbCrImage::Data &aData) +{ + // For now, we copy the data + int width_shift = 0; + int height_shift = 0; + if (aData.mYSize.width == aData.mCbCrSize.width && + aData.mYSize.height == aData.mCbCrSize.height) { + // YV24 format + width_shift = 0; + height_shift = 0; + } else if (aData.mYSize.width / 2 == aData.mCbCrSize.width && + aData.mYSize.height == aData.mCbCrSize.height) { + // YV16 format + width_shift = 1; + height_shift = 0; + } else if (aData.mYSize.width / 2 == aData.mCbCrSize.width && + aData.mYSize.height / 2 == aData.mCbCrSize.height ) { + // YV12 format + width_shift = 1; + height_shift = 1; + } else { + NS_ERROR("YCbCr format not supported"); + } + + mData = aData; + mData.mCbCrStride = mData.mCbCrSize.width = aData.mPicSize.width >> width_shift; + mData.mCbCrSize.height = aData.mPicSize.height >> height_shift; + mData.mYSize = aData.mPicSize; + mData.mYStride = mData.mYSize.width; + + mBuffer = new PRUint8[mData.mCbCrStride * mData.mCbCrSize.height * 2 + + mData.mYStride * mData.mYSize.height]; + mData.mYChannel = mBuffer; + mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height; + mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height; + + mData.mCrChannel = new PRUint8[mData.mCbCrStride * mData.mCbCrSize.height]; + int cbcr_x = aData.mPicX >> width_shift; + int cbcr_y = aData.mPicY >> height_shift; + + for (int i = 0; i < mData.mYSize.height; i++) { + memcpy(mData.mYChannel + i * mData.mYStride, + aData.mYChannel + ((aData.mPicY + i) * aData.mYStride) + aData.mPicX, + mData.mYStride); + } + for (int i = 0; i < mData.mCbCrSize.height; i++) { + memcpy(mData.mCbChannel + i * mData.mCbCrStride, + aData.mCbChannel + ((cbcr_y + i) * aData.mCbCrStride) + cbcr_x, + mData.mCbCrStride); + } + for (int i = 0; i < mData.mCbCrSize.height; i++) { + memcpy(mData.mCrChannel + i * mData.mCbCrStride, + aData.mCrChannel + ((cbcr_y + i) * aData.mCbCrStride) + cbcr_x, + mData.mCbCrStride); + } + + // Fix picture rect to be correct + mData.mPicX = mData.mPicY = 0; + mSize = aData.mPicSize; + + mHasData = PR_TRUE; +} + +void +PlanarYCbCrImageD3D9::AllocateTextures() +{ + + + D3DLOCKED_RECT lockrect; + PRUint8* src; + PRUint8* dest; + //XXX: ensure correct usage flags + mManager->device()->CreateTexture(mData.mYSize.width, mData.mYSize.height, + 1, 0, D3DFMT_L8, D3DPOOL_MANAGED, + getter_AddRefs(mYTexture), NULL); + + + /* lock the entire texture */ + mYTexture->LockRect(0, &lockrect, NULL, 0); + + src = mData.mYChannel; + //FIX cast + dest = (PRUint8*)lockrect.pBits; + + // copy over data + for (int h=0; hUnlockRect(0); + + //XXX: ensure correct usage flags + mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height, + 1, 0, D3DFMT_L8, D3DPOOL_MANAGED, + getter_AddRefs(mCbTexture), NULL); + + + /* lock the entire texture */ + mCbTexture->LockRect(0, &lockrect, NULL, 0); + + src = mData.mCbChannel; + //FIX cast + dest = (PRUint8*)lockrect.pBits; + + // copy over data + for (int h=0; hUnlockRect(0); + + + //XXX: ensure correct usage flags + mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height, + 1, 0, D3DFMT_L8, D3DPOOL_MANAGED, + getter_AddRefs(mCrTexture), NULL); + + + /* lock the entire texture */ + mCrTexture->LockRect(0, &lockrect, NULL, 0); + + src = mData.mCrChannel; + //FIX cast + dest = (PRUint8*)lockrect.pBits; + + // copy over data + for (int h=0; hUnlockRect(0); + +} + +void +PlanarYCbCrImageD3D9::FreeTextures() +{ +} + +already_AddRefed +PlanarYCbCrImageD3D9::GetAsSurface() +{ + nsRefPtr imageSurface = + new gfxImageSurface(mSize, gfxASurface::ImageFormatRGB24); + + // Convert from YCbCr to RGB now + gfx::ConvertYCbCrToRGB32(mData.mYChannel, + mData.mCbChannel, + mData.mCrChannel, + imageSurface->Data(), + 0, + 0, + mSize.width, + mSize.height, + mData.mYStride, + mData.mCbCrStride, + imageSurface->Stride(), + gfx::YV12); + + return imageSurface.forget().get(); +} + +CairoImageD3D9::~CairoImageD3D9() +{ +} + +void +CairoImageD3D9::SetData(const CairoImage::Data &aData) +{ + mSize = aData.mSize; + + nsRefPtr imageSurface = + new gfxImageSurface(aData.mSize, gfxASurface::ImageFormatARGB32); + + nsRefPtr context = new gfxContext(imageSurface); + + context->SetSource(aData.mSurface); + context->Paint(); + + //XXX: make sure we're using the correct usage flags + mManager->device()->CreateTexture(aData.mSize.width, aData.mSize.height, + 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, + getter_AddRefs(mTexture), NULL); + + D3DLOCKED_RECT lockrect; + /* lock the entire texture */ + mTexture->LockRect(0, &lockrect, NULL, 0); + + PRUint8* src = imageSurface->Data(); + //FIX cast + PRUint8* dest = (PRUint8*)lockrect.pBits; + + // copy over data. If we don't need to do any swaping we can + // use memcpy + for (int i=0; iUnlockRect(0); +} + +already_AddRefed +CairoImageD3D9::GetAsSurface() +{ + return nsnull; +} + +} /* layers */ +} /* mozilla */ diff --git a/gfx/layers/d3d9/ImageLayerD3D9.h b/gfx/layers/d3d9/ImageLayerD3D9.h new file mode 100644 index 000000000000..f57df6f36aa7 --- /dev/null +++ b/gfx/layers/d3d9/ImageLayerD3D9.h @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef GFX_IMAGELAYERD3D9_H +#define GFX_IMAGELAYERD3D9_H + +#include "LayerManagerD3D9.h" +#include "ImageLayers.h" +#include "mozilla/Mutex.h" + +namespace mozilla { +namespace layers { + +class THEBES_API ImageContainerD3D9 : public ImageContainer +{ +public: + ImageContainerD3D9(LayerManagerD3D9 *aManager); + virtual ~ImageContainerD3D9() {} + + virtual already_AddRefed CreateImage(const Image::Format* aFormats, + PRUint32 aNumFormats); + + virtual void SetCurrentImage(Image* aImage); + + virtual already_AddRefed GetCurrentImage(); + + virtual already_AddRefed GetCurrentAsSurface(gfxIntSize* aSize); + + virtual gfxIntSize GetCurrentSize(); + +private: + typedef mozilla::Mutex Mutex; + + nsRefPtr mActiveImage; + + Mutex mActiveImageLock; +}; + +class THEBES_API ImageLayerD3D9 : public ImageLayer, + public LayerD3D9 +{ +public: + ImageLayerD3D9(LayerManagerD3D9 *aManager) + : ImageLayer(aManager, NULL) + , LayerD3D9(aManager) + { + mImplData = static_cast(this); + } + + // LayerD3D9 Implementation + virtual LayerType GetType(); + + virtual Layer* GetLayer(); + + virtual void RenderLayer(); +}; + +class THEBES_API ImageD3D9 +{ +public: + virtual already_AddRefed GetAsSurface() = 0; +}; + +class THEBES_API PlanarYCbCrImageD3D9 : public PlanarYCbCrImage, + public ImageD3D9 +{ +public: + PlanarYCbCrImageD3D9(LayerManagerD3D9 *aManager); + + virtual void SetData(const Data &aData); + + /* + * Upload the data from out mData into our textures. For now we use this to + * make sure the textures are created and filled on the main thread. + */ + void AllocateTextures(); + /* + * XXX + * Free the textures, we call this from the main thread when we're done + * drawing this frame. We cannot free this from the constructor since it may + * be destroyed off the main-thread and might not be able to properly clean + * up its textures + */ + void FreeTextures(); + PRBool HasData() { return mHasData; } + + virtual already_AddRefed GetAsSurface(); + + nsAutoArrayPtr mBuffer; + LayerManagerD3D9 *mManager; + Data mData; + gfxIntSize mSize; + nsRefPtr mYTexture; + nsRefPtr mCrTexture; + nsRefPtr mCbTexture; + PRPackedBool mHasData; +}; + + +class THEBES_API CairoImageD3D9 : public CairoImage, + public ImageD3D9 +{ +public: + CairoImageD3D9(LayerManagerD3D9 *aManager) + : CairoImage(static_cast(this)) + , mManager(aManager) + { } + ~CairoImageD3D9(); + + virtual void SetData(const Data &aData); + + virtual already_AddRefed GetAsSurface(); + + nsRefPtr mTexture; + gfxIntSize mSize; + LayerManagerD3D9 *mManager; +}; + +} /* layers */ +} /* mozilla */ +#endif /* GFX_IMAGELAYERD3D9_H */ diff --git a/gfx/layers/d3d9/LayerManagerD3D9.cpp b/gfx/layers/d3d9/LayerManagerD3D9.cpp new file mode 100644 index 000000000000..7524e5ef8ff3 --- /dev/null +++ b/gfx/layers/d3d9/LayerManagerD3D9.cpp @@ -0,0 +1,578 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "LayerManagerD3D9.h" + +#include "ThebesLayerD3D9.h" +#include "ContainerLayerD3D9.h" +#include "ImageLayerD3D9.h" +#include "ColorLayerD3D9.h" +#include "CanvasLayerD3D9.h" + +#include "LayerManagerD3D9Shaders.h" + +#include "nsIServiceManager.h" +#include "nsIConsoleService.h" +#include "nsPrintfCString.h" + +namespace mozilla { +namespace layers { + +struct vertex { + float x, y; +}; + +IDirect3D9 *LayerManagerD3D9::mD3D9 = NULL; + +typedef IDirect3D9* (WINAPI*Direct3DCreate9Func)( + UINT SDKVersion +); + + +LayerManagerD3D9::LayerManagerD3D9(nsIWidget *aWidget) +{ + mWidget = aWidget; + mCurrentCallbackInfo.Callback = NULL; + mCurrentCallbackInfo.CallbackData = NULL; +} + +LayerManagerD3D9::~LayerManagerD3D9() +{ +} + +#define HAS_CAP(a, b) (((a) & (b)) == (b)) +#define LACKS_CAP(a, b) !(((a) & (b)) == (b)) + +PRBool +LayerManagerD3D9::Initialize() +{ + if (!mD3D9) { + Direct3DCreate9Func d3d9create = (Direct3DCreate9Func) + GetProcAddress(LoadLibraryW(L"d3d9.dll"), "Direct3DCreate9"); + if (!d3d9create) { + return PR_FALSE; + } + + mD3D9 = d3d9create(D3D_SDK_VERSION); + if (!mD3D9) { + return PR_FALSE; + } + } + + D3DPRESENT_PARAMETERS pp; + memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS)); + + pp.BackBufferFormat = D3DFMT_A8R8G8B8; + pp.SwapEffect = D3DSWAPEFFECT_COPY; + pp.Windowed = TRUE; + pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + pp.hDeviceWindow = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW); + + HRESULT hr = mD3D9->CreateDevice(D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + NULL, + D3DCREATE_FPU_PRESERVE | + D3DCREATE_MULTITHREADED | + D3DCREATE_MIXED_VERTEXPROCESSING, + &pp, + getter_AddRefs(mDevice)); + + if (FAILED(hr)) { + return PR_FALSE; + } + + if (!VerifyCaps()) { + return PR_FALSE; + } + + hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVS, + getter_AddRefs(mLayerVS)); + + if (FAILED(hr)) { + return PR_FALSE; + } + + hr = mDevice->CreatePixelShader((DWORD*)RGBShaderPS, + getter_AddRefs(mRGBPS)); + + if (FAILED(hr)) { + return PR_FALSE; + } + + hr = mDevice->CreatePixelShader((DWORD*)YCbCrShaderPS, + getter_AddRefs(mYCbCrPS)); + + if (FAILED(hr)) { + return PR_FALSE; + } + + hr = mDevice->CreatePixelShader((DWORD*)SolidColorShaderPS, + getter_AddRefs(mSolidColorPS)); + + if (FAILED(hr)) { + return PR_FALSE; + } + + hr = mDevice->CreateVertexBuffer(sizeof(vertex) * 4, + 0, + 0, + D3DPOOL_MANAGED, + getter_AddRefs(mVB), + NULL); + + if (FAILED(hr)) { + return PR_FALSE; + } + + vertex *vertices; + hr = mVB->Lock(0, 0, (void**)&vertices, 0); + if (FAILED(hr)) { + return PR_FALSE; + } + + vertices[0].x = vertices[0].y = 0; + vertices[1].x = 1; vertices[1].y = 0; + vertices[2].x = 0; vertices[2].y = 1; + vertices[3].x = 1; vertices[3].y = 1; + + mVB->Unlock(); + + hr = mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex)); + if (FAILED(hr)) { + return PR_FALSE; + } + + D3DVERTEXELEMENT9 elements[] = { + { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, + D3DDECLUSAGE_POSITION, 0 }, + D3DDECL_END() + }; + + mDevice->CreateVertexDeclaration(elements, getter_AddRefs(mVD)); + + SetupRenderState(); + + nsCOMPtr + console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); + + D3DADAPTER_IDENTIFIER9 identifier; + mD3D9->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &identifier); + + if (console) { + nsString msg; + msg += + NS_LITERAL_STRING("Direct3D 9 LayerManager Initialized Succesfully.\nDriver: "); + msg += NS_ConvertUTF8toUTF16( + nsDependentCString((const char*)identifier.Driver)); + msg += NS_LITERAL_STRING("\nDescription: "); + msg += NS_ConvertUTF8toUTF16( + nsDependentCString((const char*)identifier.Description)); + msg += NS_LITERAL_STRING("\nVersion: "); + msg += NS_ConvertUTF8toUTF16( + nsPrintfCString("%d.%d.%d.%d", + HIWORD(identifier.DriverVersion.HighPart), + LOWORD(identifier.DriverVersion.HighPart), + HIWORD(identifier.DriverVersion.LowPart), + LOWORD(identifier.DriverVersion.LowPart))); + console->LogStringMessage(msg.get()); + } + + return PR_TRUE; +} + +void +LayerManagerD3D9::SetClippingRegion(const nsIntRegion &aClippingRegion) +{ + mClippingRegion = aClippingRegion; +} + +void +LayerManagerD3D9::BeginTransaction() +{ +} + +void +LayerManagerD3D9::BeginTransactionWithTarget(gfxContext *aTarget) +{ + mTarget = aTarget; +} + +void +LayerManagerD3D9::EndConstruction() +{ +} + +void +LayerManagerD3D9::EndTransaction(DrawThebesLayerCallback aCallback, + void* aCallbackData) +{ + mCurrentCallbackInfo.Callback = aCallback; + mCurrentCallbackInfo.CallbackData = aCallbackData; + Render(); + /* Clean this out for sanity */ + mCurrentCallbackInfo.Callback = NULL; + mCurrentCallbackInfo.CallbackData = NULL; +} + +void +LayerManagerD3D9::SetRoot(Layer *aLayer) +{ + mRootLayer = static_cast(aLayer->ImplData()); +} + +already_AddRefed +LayerManagerD3D9::CreateThebesLayer() +{ + nsRefPtr layer = new ThebesLayerD3D9(this); + return layer.forget(); +} + +already_AddRefed +LayerManagerD3D9::CreateContainerLayer() +{ + nsRefPtr layer = new ContainerLayerD3D9(this); + return layer.forget(); +} + +already_AddRefed +LayerManagerD3D9::CreateImageLayer() +{ + nsRefPtr layer = new ImageLayerD3D9(this); + return layer.forget(); +} + +already_AddRefed +LayerManagerD3D9::CreateColorLayer() +{ + nsRefPtr layer = new ColorLayerD3D9(this); + return layer.forget(); +} + +already_AddRefed +LayerManagerD3D9::CreateCanvasLayer() +{ + nsRefPtr layer = new CanvasLayerD3D9(this); + return layer.forget(); +} + +already_AddRefed +LayerManagerD3D9::CreateImageContainer() +{ + nsRefPtr container = new ImageContainerD3D9(this); + return container.forget(); +} + +void +LayerManagerD3D9::SetShaderMode(ShaderMode aMode) +{ + switch (aMode) { + case RGBLAYER: + mDevice->SetVertexShader(mLayerVS); + mDevice->SetPixelShader(mRGBPS); + break; + case YCBCRLAYER: + mDevice->SetVertexShader(mLayerVS); + mDevice->SetPixelShader(mYCbCrPS); + break; + case SOLIDCOLORLAYER: + mDevice->SetVertexShader(mLayerVS); + mDevice->SetPixelShader(mSolidColorPS); + break; + } +} + +void +LayerManagerD3D9::Render() +{ + if (!SetupBackBuffer()) { + return; + } + SetupPipeline(); + nsIntRect rect; + mWidget->GetBounds(rect); + + mDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0xffffffff, 0, 0); + + mDevice->BeginScene(); + + if (mRootLayer) { + const nsIntRect *clipRect = mRootLayer->GetLayer()->GetClipRect(); + RECT r; + if (clipRect) { + r.left = (LONG)clipRect->x; + r.top = (LONG)clipRect->y; + r.right = (LONG)(clipRect->x + clipRect->width); + r.bottom = (LONG)(clipRect->y + clipRect->height); + } else { + r.left = r.top = 0; + r.right = rect.width; + r.bottom = rect.height; + } + mDevice->SetScissorRect(&r); + + mRootLayer->RenderLayer(); + } + + mDevice->EndScene(); + + if (!mTarget) { + const nsIntRect *r; + for (nsIntRegionRectIterator iter(mClippingRegion); + (r = iter.Next()) != nsnull;) { + RECT rect; + rect.left = r->x; + rect.top = r->y; + rect.right = r->XMost(); + rect.bottom = r->YMost(); + + mDevice->Present(&rect, &rect, NULL, NULL); + } + } else { + PaintToTarget(); + } +} + +void +LayerManagerD3D9::SetupPipeline() +{ + nsIntRect rect; + mWidget->GetBounds(rect); + + float viewMatrix[4][4]; + /* + * Matrix to transform to viewport space ( <-1.0, 1.0> topleft, + * <1.0, -1.0> bottomright) + */ + memset(&viewMatrix, 0, sizeof(viewMatrix)); + viewMatrix[0][0] = 2.0f / rect.width; + viewMatrix[1][1] = -2.0f / rect.height; + viewMatrix[2][2] = 1.0f; + viewMatrix[3][0] = -1.0f; + viewMatrix[3][1] = 1.0f; + viewMatrix[3][3] = 1.0f; + + HRESULT hr = mDevice->SetVertexShaderConstantF(8, &viewMatrix[0][0], 4); + + if (FAILED(hr)) { + NS_WARNING("Failed to set projection shader constant!"); + } +} + +PRBool +LayerManagerD3D9::SetupBackBuffer() +{ + nsRefPtr backBuffer; + mDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, + getter_AddRefs(backBuffer)); + + D3DSURFACE_DESC desc; + nsIntRect rect; + mWidget->GetBounds(rect); + backBuffer->GetDesc(&desc); + + HRESULT hr = mDevice->TestCooperativeLevel(); + + /* The device is lost or something else is wrong, failure */ + if (FAILED(hr) && hr != D3DERR_DEVICENOTRESET) { + return PR_FALSE; + } + + /* + * If the backbuffer is the right size, and the device is not lost, we can + * safely render without doing anything. + */ + if ((desc.Width == rect.width && desc.Height == rect.height) && + SUCCEEDED(hr)) { + return PR_TRUE; + } + + /* + * Our device is lost or our backbuffer needs resizing, start by clearing + * out all D3DPOOL_DEFAULT surfaces. + */ + for(unsigned int i = 0; i < mThebesLayers.Length(); i++) { + mThebesLayers[i]->CleanResources(); + } + + backBuffer = NULL; + + D3DPRESENT_PARAMETERS pp; + memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS)); + + pp.BackBufferFormat = D3DFMT_A8R8G8B8; + pp.SwapEffect = D3DSWAPEFFECT_COPY; + pp.Windowed = TRUE; + pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + pp.hDeviceWindow = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW); + + hr = mDevice->Reset(&pp); + if (FAILED(hr)) { + return PR_FALSE; + } + + SetupRenderState(); + + return PR_TRUE; +} + +void +LayerManagerD3D9::PaintToTarget() +{ + nsRefPtr backBuff; + nsRefPtr destSurf; + mDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, + getter_AddRefs(backBuff)); + + D3DSURFACE_DESC desc; + backBuff->GetDesc(&desc); + + mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, + D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, + getter_AddRefs(destSurf), NULL); + + mDevice->GetRenderTargetData(backBuff, destSurf); + + D3DLOCKED_RECT rect; + destSurf->LockRect(&rect, NULL, D3DLOCK_READONLY); + + nsRefPtr imageSurface = + new gfxImageSurface((unsigned char*)rect.pBits, + gfxIntSize(desc.Width, desc.Height), + rect.Pitch, + gfxASurface::ImageFormatARGB32); + + mTarget->SetSource(imageSurface); + mTarget->SetOperator(gfxContext::OPERATOR_OVER); + mTarget->Paint(); + destSurf->UnlockRect(); +} + +void +LayerManagerD3D9::SetupRenderState() +{ + mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex)); + mDevice->SetVertexDeclaration(mVD); + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + mDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + mDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + mDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + mDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + mDevice->SetSamplerState(2, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + mDevice->SetSamplerState(2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); +} + +PRBool +LayerManagerD3D9::VerifyCaps() +{ + D3DCAPS9 caps; + HRESULT hr = mDevice->GetDeviceCaps(&caps); + + if (FAILED(hr)) { + return PR_FALSE; + } + + if (LACKS_CAP(caps.DevCaps, D3DDEVCAPS_TEXTUREVIDEOMEMORY)) { + return PR_FALSE; + } + + if (LACKS_CAP(caps.PrimitiveMiscCaps, D3DPMISCCAPS_CULLNONE)) { + return PR_FALSE; + } + + if (LACKS_CAP(caps.SrcBlendCaps, D3DPBLENDCAPS_ONE) || + LACKS_CAP(caps.SrcBlendCaps, D3DBLEND_SRCALPHA) || + LACKS_CAP(caps.DestBlendCaps, D3DPBLENDCAPS_INVSRCALPHA)) { + return PR_FALSE; + } + + if (LACKS_CAP(caps.RasterCaps, D3DPRASTERCAPS_SCISSORTEST)) { + return PR_FALSE; + } + + if (LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_ALPHA) || + HAS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_SQUAREONLY) || + (HAS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_POW2) && + LACKS_CAP(caps.TextureCaps, D3DPTEXTURECAPS_NONPOW2CONDITIONAL))) { + return PR_FALSE; + } + + if (LACKS_CAP(caps.TextureFilterCaps, D3DPTFILTERCAPS_MAGFLINEAR) || + LACKS_CAP(caps.TextureFilterCaps, D3DPTFILTERCAPS_MINFLINEAR)) { + return PR_FALSE; + } + + if (LACKS_CAP(caps.TextureAddressCaps, D3DPTADDRESSCAPS_CLAMP)) { + return PR_FALSE; + } + + if (caps.MaxTextureHeight < 4096 || + caps.MaxTextureWidth < 4096) { + return PR_FALSE; + } + + if ((caps.PixelShaderVersion & 0xffff) < 0x200 || + (caps.VertexShaderVersion & 0xffff) < 0x200) { + return PR_FALSE; + } + return PR_TRUE; +} + +LayerD3D9::LayerD3D9(LayerManagerD3D9 *aManager) + : mD3DManager(aManager) + , mNextSibling(NULL) +{ +} + +LayerD3D9* +LayerD3D9::GetNextSibling() +{ + return mNextSibling; +} + +void +LayerD3D9::SetNextSibling(LayerD3D9 *aNextSibling) +{ + mNextSibling = aNextSibling; +} + +} /* namespace layers */ +} /* namespace mozilla */ diff --git a/gfx/layers/d3d9/LayerManagerD3D9.h b/gfx/layers/d3d9/LayerManagerD3D9.h new file mode 100644 index 000000000000..a0c1e4b962c0 --- /dev/null +++ b/gfx/layers/d3d9/LayerManagerD3D9.h @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef GFX_LAYERMANAGERD3D9_H +#define GFX_LAYERMANAGERD3D9_H + +#include "Layers.h" + +#include +#include + +#include "gfxContext.h" +#include "nsIWidget.h" + +namespace mozilla { +namespace layers { + +class LayerD3D9; +class ThebesLayerD3D9; + +/* + * This is the LayerManager used for Direct3D 9. For now this will render on + * the main thread. + */ +class THEBES_API LayerManagerD3D9 : public LayerManager { +public: + LayerManagerD3D9(nsIWidget *aWidget); + virtual ~LayerManagerD3D9(); + + /* + * Initializes the layer manager, this is when the layer manager will + * actually access the device and attempt to create the swap chain used + * to draw to the window. If this method fails the device cannot be used. + * This function is not threadsafe. + * + * \return True is initialization was succesful, false when it was not. + */ + PRBool Initialize(); + + /* + * Sets the clipping region for this layer manager. This is important on + * windows because using OGL we no longer have GDI's native clipping. Therefor + * widget must tell us what part of the screen is being invalidated, + * and we should clip to this. + * + * \param aClippingRegion Region to clip to. Setting an empty region + * will disable clipping. + */ + void SetClippingRegion(const nsIntRegion& aClippingRegion); + + /* + * LayerManager implementation. + */ + void BeginTransaction(); + + void BeginTransactionWithTarget(gfxContext* aTarget); + + void EndConstruction(); + + struct CallbackInfo { + DrawThebesLayerCallback Callback; + void *CallbackData; + }; + + void EndTransaction(DrawThebesLayerCallback aCallback, + void* aCallbackData); + + const CallbackInfo &GetCallbackInfo() { return mCurrentCallbackInfo; } + + void SetRoot(Layer* aLayer); + + virtual already_AddRefed CreateThebesLayer(); + + virtual already_AddRefed CreateContainerLayer(); + + virtual already_AddRefed CreateImageLayer(); + + virtual already_AddRefed CreateColorLayer(); + + virtual already_AddRefed CreateCanvasLayer(); + + virtual already_AddRefed CreateImageContainer(); + + virtual LayersBackend GetBackendType() { return LAYERS_D3D9; } + + /* + * Helper methods. + */ + void SetClippingEnabled(PRBool aEnabled); + + IDirect3DDevice9 *device() const { return mDevice; } + + enum ShaderMode { + RGBLAYER, + YCBCRLAYER, + SOLIDCOLORLAYER + }; + + void SetShaderMode(ShaderMode aMode); + + nsTArray mThebesLayers; + +private: + /* Direct3D9 instance */ + static IDirect3D9 *mD3D9; + + /* Widget associated with this layer manager */ + nsIWidget *mWidget; + /* + * Context target, NULL when drawing directly to our swap chain. + */ + nsRefPtr mTarget; + + nsRefPtr mDevice; + + /* Vertex shader used for layer quads */ + nsRefPtr mLayerVS; + + /* Pixel shader used for RGB textures */ + nsRefPtr mRGBPS; + + /* Pixel shader used for RGB textures */ + nsRefPtr mYCbCrPS; + + /* Pixel shader used for solid colors */ + nsRefPtr mSolidColorPS; + + /* Vertex buffer containing our basic vertex structure */ + nsRefPtr mVB; + + /* Our vertex declaration */ + nsRefPtr mVD; + + /* Current root layer. */ + LayerD3D9 *mRootLayer; + + /* Callback info for current transaction */ + CallbackInfo mCurrentCallbackInfo; + + /* + * Region we're clipping our current drawing to. + */ + nsIntRegion mClippingRegion; + /* + * Render the current layer tree to the active target. + */ + void Render(); + /* + * Setup the pipeline. + */ + void SetupPipeline(); + /* + * Setup the backbuffer. + * + * \return PR_TRUE if setup was succesful + */ + PRBool SetupBackBuffer(); + /* + * Setup the render state for the surface. + */ + void SetupRenderState(); + /* + * Copies the content of our backbuffer to the set transaction target. + */ + void PaintToTarget(); + /* + * Verifies all required device capabilities are present. + */ + PRBool VerifyCaps(); + +}; + +/* + * General information and tree management for OGL layers. + */ +class LayerD3D9 +{ +public: + LayerD3D9(LayerManagerD3D9 *aManager); + + enum LayerType { TYPE_THEBES, TYPE_CONTAINER, TYPE_IMAGE, TYPE_COLOR, + TYPE_CANVAS }; + + virtual LayerType GetType() = 0; + + LayerD3D9 *GetNextSibling(); + virtual LayerD3D9 *GetFirstChildD3D9() { return nsnull; } + + void SetNextSibling(LayerD3D9 *aParent); + void SetFirstChild(LayerD3D9 *aParent); + + virtual Layer* GetLayer() = 0; + + virtual void RenderLayer() = 0; + + IDirect3DDevice9 *device() const { return mD3DManager->device(); } +protected: + LayerManagerD3D9 *mD3DManager; + LayerD3D9 *mNextSibling; +}; + +} /* layers */ +} /* mozilla */ + +#endif /* GFX_LAYERMANAGERD3D9_H */ diff --git a/gfx/layers/d3d9/LayerManagerD3D9Shaders.h b/gfx/layers/d3d9/LayerManagerD3D9Shaders.h new file mode 100644 index 000000000000..e28593760de1 --- /dev/null +++ b/gfx/layers/d3d9/LayerManagerD3D9Shaders.h @@ -0,0 +1,435 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.27.952.3022 +// +// fxc LayerManagerD3D9Shaders.hlsl /ELayerQuadVS /nologo +// /FhLayerManagerD3D9Shaders.h /VnLayerQuadVS +// +// +// Parameters: +// +// float4x4 mLayerQuadTransform; +// float4x4 mLayerTransform; +// float4x4 mProjection; +// float4 vRenderTargetOffset; +// +// +// Registers: +// +// Name Reg Size +// ------------------- ----- ---- +// mLayerQuadTransform c0 4 +// mLayerTransform c4 4 +// mProjection c8 4 +// vRenderTargetOffset c12 1 +// + + vs_2_0 + dcl_position v0 + mul r0, v0.y, c1 + mad r0, c0, v0.x, r0 + mad r0, c2, v0.z, r0 + mad r0, c3, v0.w, r0 + mul r1, r0.y, c5 + mad r1, c4, r0.x, r1 + mad r1, c6, r0.z, r1 + mad r0, c7, r0.w, r1 + add r0, r0, -c12 + mul r1, r0.y, c9 + mad r1, c8, r0.x, r1 + mad r1, c10, r0.z, r1 + mad oPos, c11, r0.w, r1 + mov oT0.xy, v0 + +// approximately 14 instruction slots used +#endif + +const BYTE LayerQuadVS[] = +{ + 0, 2, 254, 255, 254, 255, + 67, 0, 67, 84, 65, 66, + 28, 0, 0, 0, 215, 0, + 0, 0, 0, 2, 254, 255, + 4, 0, 0, 0, 28, 0, + 0, 0, 0, 1, 0, 0, + 208, 0, 0, 0, 108, 0, + 0, 0, 2, 0, 0, 0, + 4, 0, 0, 0, 128, 0, + 0, 0, 0, 0, 0, 0, + 144, 0, 0, 0, 2, 0, + 4, 0, 4, 0, 0, 0, + 128, 0, 0, 0, 0, 0, + 0, 0, 160, 0, 0, 0, + 2, 0, 8, 0, 4, 0, + 0, 0, 128, 0, 0, 0, + 0, 0, 0, 0, 172, 0, + 0, 0, 2, 0, 12, 0, + 1, 0, 0, 0, 192, 0, + 0, 0, 0, 0, 0, 0, + 109, 76, 97, 121, 101, 114, + 81, 117, 97, 100, 84, 114, + 97, 110, 115, 102, 111, 114, + 109, 0, 3, 0, 3, 0, + 4, 0, 4, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 109, 76, 97, 121, 101, 114, + 84, 114, 97, 110, 115, 102, + 111, 114, 109, 0, 109, 80, + 114, 111, 106, 101, 99, 116, + 105, 111, 110, 0, 118, 82, + 101, 110, 100, 101, 114, 84, + 97, 114, 103, 101, 116, 79, + 102, 102, 115, 101, 116, 0, + 1, 0, 3, 0, 1, 0, + 4, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 118, 115, + 95, 50, 95, 48, 0, 77, + 105, 99, 114, 111, 115, 111, + 102, 116, 32, 40, 82, 41, + 32, 72, 76, 83, 76, 32, + 83, 104, 97, 100, 101, 114, + 32, 67, 111, 109, 112, 105, + 108, 101, 114, 32, 57, 46, + 50, 55, 46, 57, 53, 50, + 46, 51, 48, 50, 50, 0, + 31, 0, 0, 2, 0, 0, + 0, 128, 0, 0, 15, 144, + 5, 0, 0, 3, 0, 0, + 15, 128, 0, 0, 85, 144, + 1, 0, 228, 160, 4, 0, + 0, 4, 0, 0, 15, 128, + 0, 0, 228, 160, 0, 0, + 0, 144, 0, 0, 228, 128, + 4, 0, 0, 4, 0, 0, + 15, 128, 2, 0, 228, 160, + 0, 0, 170, 144, 0, 0, + 228, 128, 4, 0, 0, 4, + 0, 0, 15, 128, 3, 0, + 228, 160, 0, 0, 255, 144, + 0, 0, 228, 128, 5, 0, + 0, 3, 1, 0, 15, 128, + 0, 0, 85, 128, 5, 0, + 228, 160, 4, 0, 0, 4, + 1, 0, 15, 128, 4, 0, + 228, 160, 0, 0, 0, 128, + 1, 0, 228, 128, 4, 0, + 0, 4, 1, 0, 15, 128, + 6, 0, 228, 160, 0, 0, + 170, 128, 1, 0, 228, 128, + 4, 0, 0, 4, 0, 0, + 15, 128, 7, 0, 228, 160, + 0, 0, 255, 128, 1, 0, + 228, 128, 2, 0, 0, 3, + 0, 0, 15, 128, 0, 0, + 228, 128, 12, 0, 228, 161, + 5, 0, 0, 3, 1, 0, + 15, 128, 0, 0, 85, 128, + 9, 0, 228, 160, 4, 0, + 0, 4, 1, 0, 15, 128, + 8, 0, 228, 160, 0, 0, + 0, 128, 1, 0, 228, 128, + 4, 0, 0, 4, 1, 0, + 15, 128, 10, 0, 228, 160, + 0, 0, 170, 128, 1, 0, + 228, 128, 4, 0, 0, 4, + 0, 0, 15, 192, 11, 0, + 228, 160, 0, 0, 255, 128, + 1, 0, 228, 128, 1, 0, + 0, 2, 0, 0, 3, 224, + 0, 0, 228, 144, 255, 255, + 0, 0 +}; + +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.27.952.3022 +// +// fxc LayerManagerD3D9Shaders.hlsl /ERGBShader /nologo /Tps_2_0 +// /FhLayerManagerD3D9Shaders.h /VnRGBShaderPS +// +// +// Parameters: +// +// float fLayerOpacity; +// sampler2D s2D; +// +// +// Registers: +// +// Name Reg Size +// ------------- ----- ---- +// fLayerOpacity c0 1 +// s2D s0 1 +// + + ps_2_0 + dcl t0.xy + dcl_2d s0 + texld r0, t0, s0 + mul r0, r0, c0.x + mov oC0, r0 + +// approximately 3 instruction slots used (1 texture, 2 arithmetic) +#endif + +const BYTE RGBShaderPS[] = +{ + 0, 2, 255, 255, 254, 255, + 45, 0, 67, 84, 65, 66, + 28, 0, 0, 0, 127, 0, + 0, 0, 0, 2, 255, 255, + 2, 0, 0, 0, 28, 0, + 0, 0, 0, 1, 0, 0, + 120, 0, 0, 0, 68, 0, + 0, 0, 2, 0, 0, 0, + 1, 0, 0, 0, 84, 0, + 0, 0, 0, 0, 0, 0, + 100, 0, 0, 0, 3, 0, + 0, 0, 1, 0, 0, 0, + 104, 0, 0, 0, 0, 0, + 0, 0, 102, 76, 97, 121, + 101, 114, 79, 112, 97, 99, + 105, 116, 121, 0, 171, 171, + 0, 0, 3, 0, 1, 0, + 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 115, 50, + 68, 0, 4, 0, 12, 0, + 1, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 112, 115, 95, 50, 95, 48, + 0, 77, 105, 99, 114, 111, + 115, 111, 102, 116, 32, 40, + 82, 41, 32, 72, 76, 83, + 76, 32, 83, 104, 97, 100, + 101, 114, 32, 67, 111, 109, + 112, 105, 108, 101, 114, 32, + 57, 46, 50, 55, 46, 57, + 53, 50, 46, 51, 48, 50, + 50, 0, 31, 0, 0, 2, + 0, 0, 0, 128, 0, 0, + 3, 176, 31, 0, 0, 2, + 0, 0, 0, 144, 0, 8, + 15, 160, 66, 0, 0, 3, + 0, 0, 15, 128, 0, 0, + 228, 176, 0, 8, 228, 160, + 5, 0, 0, 3, 0, 0, + 15, 128, 0, 0, 228, 128, + 0, 0, 0, 160, 1, 0, + 0, 2, 0, 8, 15, 128, + 0, 0, 228, 128, 255, 255, + 0, 0 +}; + +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.27.952.3022 +// +// fxc LayerManagerD3D9Shaders.hlsl /EYCbCrShader /nologo /Tps_2_0 +// /FhLayerManagerD3D9Shaders.h /VnYCbCrShaderPS +// +// +// Parameters: +// +// float fLayerOpacity; +// sampler2D s2DCb; +// sampler2D s2DCr; +// sampler2D s2DY; +// +// +// Registers: +// +// Name Reg Size +// ------------- ----- ---- +// fLayerOpacity c0 1 +// s2DY s0 1 +// s2DCb s1 1 +// s2DCr s2 1 +// + + ps_2_0 + def c1, -0.5, -0.0625, 1.16400003, 1.59599996 + def c2, 0.813000023, 0.391000003, 2.01799989, 1 + dcl t0.xy + dcl_2d s0 + dcl_2d s1 + dcl_2d s2 + texld r0, t0, s2 + texld r1, t0, s0 + texld r2, t0, s1 + add r0.x, r0.x, c1.x + add r0.y, r1.x, c1.y + mul r0.y, r0.y, c1.z + mad r0.z, r0.x, -c2.x, r0.y + mad r1.x, r0.x, c1.w, r0.y + add r0.x, r2.x, c1.x + mad r1.y, r0.x, -c2.y, r0.z + mad r1.z, r0.x, c2.z, r0.y + mov r1.w, c2.w + mul r0, r1, c0.x + mov oC0, r0 + +// approximately 14 instruction slots used (3 texture, 11 arithmetic) +#endif + +const BYTE YCbCrShaderPS[] = +{ + 0, 2, 255, 255, 254, 255, + 68, 0, 67, 84, 65, 66, + 28, 0, 0, 0, 219, 0, + 0, 0, 0, 2, 255, 255, + 4, 0, 0, 0, 28, 0, + 0, 0, 0, 1, 0, 0, + 212, 0, 0, 0, 108, 0, + 0, 0, 2, 0, 0, 0, + 1, 0, 0, 0, 124, 0, + 0, 0, 0, 0, 0, 0, + 140, 0, 0, 0, 3, 0, + 1, 0, 1, 0, 0, 0, + 148, 0, 0, 0, 0, 0, + 0, 0, 164, 0, 0, 0, + 3, 0, 2, 0, 1, 0, + 0, 0, 172, 0, 0, 0, + 0, 0, 0, 0, 188, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 196, 0, + 0, 0, 0, 0, 0, 0, + 102, 76, 97, 121, 101, 114, + 79, 112, 97, 99, 105, 116, + 121, 0, 171, 171, 0, 0, + 3, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 115, 50, 68, 67, + 98, 0, 171, 171, 4, 0, + 12, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 115, 50, 68, 67, + 114, 0, 171, 171, 4, 0, + 12, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 115, 50, 68, 89, + 0, 171, 171, 171, 4, 0, + 12, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 112, 115, 95, 50, + 95, 48, 0, 77, 105, 99, + 114, 111, 115, 111, 102, 116, + 32, 40, 82, 41, 32, 72, + 76, 83, 76, 32, 83, 104, + 97, 100, 101, 114, 32, 67, + 111, 109, 112, 105, 108, 101, + 114, 32, 57, 46, 50, 55, + 46, 57, 53, 50, 46, 51, + 48, 50, 50, 0, 81, 0, + 0, 5, 1, 0, 15, 160, + 0, 0, 0, 191, 0, 0, + 128, 189, 244, 253, 148, 63, + 186, 73, 204, 63, 81, 0, + 0, 5, 2, 0, 15, 160, + 197, 32, 80, 63, 39, 49, + 200, 62, 233, 38, 1, 64, + 0, 0, 128, 63, 31, 0, + 0, 2, 0, 0, 0, 128, + 0, 0, 3, 176, 31, 0, + 0, 2, 0, 0, 0, 144, + 0, 8, 15, 160, 31, 0, + 0, 2, 0, 0, 0, 144, + 1, 8, 15, 160, 31, 0, + 0, 2, 0, 0, 0, 144, + 2, 8, 15, 160, 66, 0, + 0, 3, 0, 0, 15, 128, + 0, 0, 228, 176, 2, 8, + 228, 160, 66, 0, 0, 3, + 1, 0, 15, 128, 0, 0, + 228, 176, 0, 8, 228, 160, + 66, 0, 0, 3, 2, 0, + 15, 128, 0, 0, 228, 176, + 1, 8, 228, 160, 2, 0, + 0, 3, 0, 0, 1, 128, + 0, 0, 0, 128, 1, 0, + 0, 160, 2, 0, 0, 3, + 0, 0, 2, 128, 1, 0, + 0, 128, 1, 0, 85, 160, + 5, 0, 0, 3, 0, 0, + 2, 128, 0, 0, 85, 128, + 1, 0, 170, 160, 4, 0, + 0, 4, 0, 0, 4, 128, + 0, 0, 0, 128, 2, 0, + 0, 161, 0, 0, 85, 128, + 4, 0, 0, 4, 1, 0, + 1, 128, 0, 0, 0, 128, + 1, 0, 255, 160, 0, 0, + 85, 128, 2, 0, 0, 3, + 0, 0, 1, 128, 2, 0, + 0, 128, 1, 0, 0, 160, + 4, 0, 0, 4, 1, 0, + 2, 128, 0, 0, 0, 128, + 2, 0, 85, 161, 0, 0, + 170, 128, 4, 0, 0, 4, + 1, 0, 4, 128, 0, 0, + 0, 128, 2, 0, 170, 160, + 0, 0, 85, 128, 1, 0, + 0, 2, 1, 0, 8, 128, + 2, 0, 255, 160, 5, 0, + 0, 3, 0, 0, 15, 128, + 1, 0, 228, 128, 0, 0, + 0, 160, 1, 0, 0, 2, + 0, 8, 15, 128, 0, 0, + 228, 128, 255, 255, 0, 0 +}; + +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.27.952.3022 +// +// fxc LayerManagerD3D9Shaders.hlsl /ESolidColorShader /nologo /Tps_2_0 +// /FhLayerManagerD3D9Shaders.h /VnSolidColorShaderPS +// +// +// Parameters: +// +// float4 fLayerColor; +// +// +// Registers: +// +// Name Reg Size +// ------------ ----- ---- +// fLayerColor c0 1 +// + + ps_2_0 + mov oC0, c0 + +// approximately 1 instruction slot used +#endif + +const BYTE SolidColorShaderPS[] = +{ + 0, 2, 255, 255, 254, 255, + 34, 0, 67, 84, 65, 66, + 28, 0, 0, 0, 83, 0, + 0, 0, 0, 2, 255, 255, + 1, 0, 0, 0, 28, 0, + 0, 0, 0, 1, 0, 0, + 76, 0, 0, 0, 48, 0, + 0, 0, 2, 0, 0, 0, + 1, 0, 0, 0, 60, 0, + 0, 0, 0, 0, 0, 0, + 102, 76, 97, 121, 101, 114, + 67, 111, 108, 111, 114, 0, + 1, 0, 3, 0, 1, 0, + 4, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 112, 115, + 95, 50, 95, 48, 0, 77, + 105, 99, 114, 111, 115, 111, + 102, 116, 32, 40, 82, 41, + 32, 72, 76, 83, 76, 32, + 83, 104, 97, 100, 101, 114, + 32, 67, 111, 109, 112, 105, + 108, 101, 114, 32, 57, 46, + 50, 55, 46, 57, 53, 50, + 46, 51, 48, 50, 50, 0, + 1, 0, 0, 2, 0, 8, + 15, 128, 0, 0, 228, 160, + 255, 255, 0, 0 +}; diff --git a/gfx/layers/d3d9/LayerManagerD3D9Shaders.hlsl b/gfx/layers/d3d9/LayerManagerD3D9Shaders.hlsl new file mode 100644 index 000000000000..b38d017841e3 --- /dev/null +++ b/gfx/layers/d3d9/LayerManagerD3D9Shaders.hlsl @@ -0,0 +1,61 @@ +float4x4 mLayerQuadTransform; +float4x4 mLayerTransform; +float4 vRenderTargetOffset; +float4x4 mProjection; + +texture tex0; +sampler s2D; +sampler s2DY; +sampler s2DCb; +sampler s2DCr; + +float fLayerOpacity; +float4 fLayerColor; + +struct VS_INPUT { + float4 vPosition : POSITION; +}; + +struct VS_OUTPUT { + float4 vPosition : POSITION; + float2 vTexCoords : TEXCOORD0; +}; + +VS_OUTPUT LayerQuadVS(const VS_INPUT aVertex) +{ + VS_OUTPUT outp; + outp.vPosition = aVertex.vPosition; + outp.vPosition = mul(mLayerQuadTransform, outp.vPosition); + outp.vPosition = mul(mLayerTransform, outp.vPosition); + outp.vPosition = outp.vPosition - vRenderTargetOffset; + outp.vPosition = mul(mProjection, outp.vPosition); + outp.vTexCoords = aVertex.vPosition.xy; + return outp; +} + +float4 RGBShader(const VS_OUTPUT aVertex) : COLOR +{ + return tex2D(s2D, aVertex.vTexCoords) * fLayerOpacity; +} + +float4 YCbCrShader(const VS_OUTPUT aVertex) : COLOR +{ + float4 yuv; + float4 color; + + yuv.r = tex2D(s2DCr, aVertex.vTexCoords).r - 0.5; + yuv.g = tex2D(s2DY, aVertex.vTexCoords).r - 0.0625; + yuv.b = tex2D(s2DCb, aVertex.vTexCoords).r - 0.5; + + color.r = yuv.g * 1.164 + yuv.r * 1.596; + color.g = yuv.g * 1.164 - 0.813 * yuv.r - 0.391 * yuv.b; + color.b = yuv.g * 1.164 + yuv.b * 2.018; + color.a = 1.0f; + + return color * fLayerOpacity; +} + +float4 SolidColorShader(const VS_OUTPUT aVertex) : COLOR +{ + return fLayerColor; +} diff --git a/gfx/layers/d3d9/ThebesLayerD3D9.cpp b/gfx/layers/d3d9/ThebesLayerD3D9.cpp new file mode 100644 index 000000000000..156262b336e9 --- /dev/null +++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp @@ -0,0 +1,216 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "ThebesLayerD3D9.h" +#include "gfxPlatform.h" + +namespace mozilla { +namespace layers { + +ThebesLayerD3D9::ThebesLayerD3D9(LayerManagerD3D9 *aManager) + : ThebesLayer(aManager, NULL) + , LayerD3D9(aManager) +{ + mImplData = static_cast(this); + aManager->mThebesLayers.AppendElement(this); +} + +ThebesLayerD3D9::~ThebesLayerD3D9() +{ + mD3DManager->mThebesLayers.RemoveElement(this); +} + + +void +ThebesLayerD3D9::SetVisibleRegion(const nsIntRegion &aRegion) +{ + if (aRegion.GetBounds() == mVisibleRect) { + return; + } + mVisibleRect = aRegion.GetBounds(); + + device()->CreateTexture(mVisibleRect.width, mVisibleRect.height, 1, + D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, getter_AddRefs(mTexture), NULL); + + mInvalidatedRect = mVisibleRect; +} + + +void +ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion) +{ + nsIntRegion invalidatedRegion; + invalidatedRegion.Or(aRegion, mInvalidatedRect); + invalidatedRegion.And(invalidatedRegion, mVisibleRect); + mInvalidatedRect = invalidatedRegion.GetBounds(); +} + +LayerD3D9::LayerType +ThebesLayerD3D9::GetType() +{ + return TYPE_THEBES; +} + +const nsIntRect& +ThebesLayerD3D9::GetVisibleRect() +{ + return mVisibleRect; +} + +void +ThebesLayerD3D9::RenderLayer() +{ + if (!mTexture) { + device()->CreateTexture(mVisibleRect.width, mVisibleRect.height, 1, + D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, getter_AddRefs(mTexture), NULL); + mInvalidatedRect = mVisibleRect; + } + if (!mInvalidatedRect.IsEmpty()) { + nsIntRegion region = mInvalidatedRect; + + gfxASurface::gfxImageFormat imageFormat = gfxASurface::ImageFormatARGB32;; + nsRefPtr destinationSurface; + nsRefPtr context; + + destinationSurface = + gfxPlatform::GetPlatform()-> + CreateOffscreenSurface(gfxIntSize(mInvalidatedRect.width, + mInvalidatedRect.height), + imageFormat); + + context = new gfxContext(destinationSurface); + context->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y)); + LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); + cbInfo.Callback(this, context, region, cbInfo.CallbackData); + + nsRefPtr tmpTexture; + device()->CreateTexture(mInvalidatedRect.width, mInvalidatedRect.height, 1, + 0, D3DFMT_A8R8G8B8, + D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), NULL); + + D3DLOCKED_RECT r; + tmpTexture->LockRect(0, &r, NULL, 0); + + nsRefPtr imgSurface = + new gfxImageSurface((unsigned char *)r.pBits, + gfxIntSize(mInvalidatedRect.width, + mInvalidatedRect.height), + r.Pitch, + imageFormat); + + context = new gfxContext(imgSurface); + context->SetSource(destinationSurface); + context->SetOperator(gfxContext::OPERATOR_SOURCE); + context->Paint(); + + imgSurface = NULL; + + tmpTexture->UnlockRect(0); + + nsRefPtr srcSurface; + nsRefPtr dstSurface; + + mTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface)); + tmpTexture->GetSurfaceLevel(0, getter_AddRefs(srcSurface)); + + POINT point; + point.x = mInvalidatedRect.x - mVisibleRect.x; + point.y = mInvalidatedRect.y - mVisibleRect.y; + device()->UpdateSurface(srcSurface, NULL, dstSurface, &point); + } + + float quadTransform[4][4]; + /* + * Matrix to transform the <0.0,0.0>, <1.0,1.0> quad to the correct position + * and size. To get pixel perfect mapping we offset the quad half a pixel + * to the top-left. + * + * See: http://msdn.microsoft.com/en-us/library/bb219690%28VS.85%29.aspx + */ + memset(&quadTransform, 0, sizeof(quadTransform)); + quadTransform[0][0] = (float)GetVisibleRect().width; + quadTransform[1][1] = (float)GetVisibleRect().height; + quadTransform[2][2] = 1.0f; + quadTransform[3][0] = (float)GetVisibleRect().x - 0.5f; + quadTransform[3][1] = (float)GetVisibleRect().y - 0.5f; + quadTransform[3][3] = 1.0f; + + device()->SetVertexShaderConstantF(0, &quadTransform[0][0], 4); + device()->SetVertexShaderConstantF(4, &mTransform._11, 4); + + float opacity[4]; + /* + * We always upload a 4 component float, but the shader will use only the + * first component since it's declared as a 'float'. + */ + opacity[0] = GetOpacity(); + device()->SetPixelShaderConstantF(0, opacity, 1); + + mD3DManager->SetShaderMode(LayerManagerD3D9::RGBLAYER); + + device()->SetTexture(0, mTexture); + device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); +} + +void +ThebesLayerD3D9::CleanResources() +{ + mTexture = nsnull; +} + +const nsIntRect& +ThebesLayerD3D9::GetInvalidatedRect() +{ + return mInvalidatedRect; +} + +Layer* +ThebesLayerD3D9::GetLayer() +{ + return this; +} + +PRBool +ThebesLayerD3D9::IsEmpty() +{ + return !mTexture; +} + +} /* namespace layers */ +} /* namespace mozilla */ \ No newline at end of file diff --git a/gfx/layers/d3d9/ThebesLayerD3D9.h b/gfx/layers/d3d9/ThebesLayerD3D9.h new file mode 100644 index 000000000000..5dc4f9d00aad --- /dev/null +++ b/gfx/layers/d3d9/ThebesLayerD3D9.h @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef GFX_THEBESLAYERD3D9_H +#define GFX_THEBESLAYERD3D9_H + +#include "Layers.h" +#include "LayerManagerD3D9.h" +#include "gfxImageSurface.h" + + +namespace mozilla { +namespace layers { + +class ThebesLayerD3D9 : public ThebesLayer, + public LayerD3D9 +{ +public: + ThebesLayerD3D9(LayerManagerD3D9 *aManager); + virtual ~ThebesLayerD3D9(); + + /* Layer implementation */ + void SetVisibleRegion(const nsIntRegion& aRegion); + + /* ThebesLayer implementation */ + void InvalidateRegion(const nsIntRegion& aRegion); + + /* LayerD3D9 implementation */ + LayerType GetType(); + Layer* GetLayer(); + virtual PRBool IsEmpty(); + virtual void RenderLayer(); + virtual void CleanResources(); + + /* ThebesLayerD3D9 */ + const nsIntRect &GetVisibleRect(); + const nsIntRect &GetInvalidatedRect(); + +private: + /* + * Visible rectangle, this is used to know the size and position of the quad + * when doing the rendering of this layer. + */ + nsIntRect mVisibleRect; + /* + * Currently invalidated rectangular area. + */ + nsIntRect mInvalidatedRect; + + /* + * D3D9 texture + */ + nsRefPtr mTexture; +}; + +} /* layers */ +} /* mozilla */ +#endif /* GFX_THEBESLAYERD3D9_H */