|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "CanvasLayerD3D10.h" |
|
7 |
|
8 #include "../d3d9/Nv3DVUtils.h" |
|
9 #include "gfxWindowsSurface.h" |
|
10 #include "gfxWindowsPlatform.h" |
|
11 #include "SurfaceStream.h" |
|
12 #include "SharedSurfaceANGLE.h" |
|
13 #include "SharedSurfaceGL.h" |
|
14 #include "gfxContext.h" |
|
15 #include "GLContext.h" |
|
16 #include "gfxPrefs.h" |
|
17 |
|
18 using namespace mozilla::gl; |
|
19 using namespace mozilla::gfx; |
|
20 |
|
21 namespace mozilla { |
|
22 namespace layers { |
|
23 |
|
24 CanvasLayerD3D10::CanvasLayerD3D10(LayerManagerD3D10 *aManager) |
|
25 : CanvasLayer(aManager, nullptr) |
|
26 , LayerD3D10(aManager) |
|
27 , mDataIsPremultiplied(false) |
|
28 , mNeedsYFlip(false) |
|
29 , mHasAlpha(true) |
|
30 { |
|
31 mImplData = static_cast<LayerD3D10*>(this); |
|
32 } |
|
33 |
|
34 CanvasLayerD3D10::~CanvasLayerD3D10() |
|
35 { |
|
36 } |
|
37 |
|
38 void |
|
39 CanvasLayerD3D10::Initialize(const Data& aData) |
|
40 { |
|
41 NS_ASSERTION(mSurface == nullptr, "BasicCanvasLayer::Initialize called twice!"); |
|
42 |
|
43 if (aData.mGLContext) { |
|
44 mGLContext = aData.mGLContext; |
|
45 NS_ASSERTION(mGLContext->IsOffscreen(), "Canvas GLContext must be offscreen."); |
|
46 mDataIsPremultiplied = aData.mIsGLAlphaPremult; |
|
47 mNeedsYFlip = true; |
|
48 |
|
49 GLScreenBuffer* screen = mGLContext->Screen(); |
|
50 SurfaceStreamType streamType = |
|
51 SurfaceStream::ChooseGLStreamType(SurfaceStream::MainThread, |
|
52 screen->PreserveBuffer()); |
|
53 |
|
54 SurfaceFactory_GL* factory = nullptr; |
|
55 if (!gfxPrefs::WebGLForceLayersReadback()) { |
|
56 if (mGLContext->IsANGLE()) { |
|
57 factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, |
|
58 device(), |
|
59 screen->Caps()); |
|
60 } |
|
61 } |
|
62 |
|
63 if (factory) { |
|
64 screen->Morph(factory, streamType); |
|
65 } |
|
66 } else if (aData.mDrawTarget) { |
|
67 mDrawTarget = aData.mDrawTarget; |
|
68 mNeedsYFlip = false; |
|
69 mDataIsPremultiplied = true; |
|
70 void *texture = mDrawTarget->GetNativeSurface(NativeSurfaceType::D3D10_TEXTURE); |
|
71 |
|
72 if (texture) { |
|
73 mTexture = static_cast<ID3D10Texture2D*>(texture); |
|
74 |
|
75 NS_ASSERTION(!aData.mGLContext, |
|
76 "CanvasLayer can't have both DrawTarget and WebGLContext/Surface"); |
|
77 |
|
78 mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); |
|
79 device()->CreateShaderResourceView(mTexture, nullptr, getter_AddRefs(mSRView)); |
|
80 return; |
|
81 } |
|
82 |
|
83 // XXX we should store mDrawTarget and use it directly in UpdateSurface, |
|
84 // bypassing Thebes |
|
85 mSurface = mDrawTarget->Snapshot(); |
|
86 } else { |
|
87 NS_ERROR("CanvasLayer created without mSurface, mDrawTarget or mGLContext?"); |
|
88 } |
|
89 |
|
90 mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); |
|
91 mIsD2DTexture = false; |
|
92 |
|
93 // Create a texture in case we need to readback. |
|
94 CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, mBounds.width, mBounds.height, 1, 1); |
|
95 desc.Usage = D3D10_USAGE_DYNAMIC; |
|
96 desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; |
|
97 |
|
98 HRESULT hr = device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(mTexture)); |
|
99 if (FAILED(hr)) { |
|
100 NS_WARNING("Failed to create texture for CanvasLayer!"); |
|
101 return; |
|
102 } |
|
103 |
|
104 device()->CreateShaderResourceView(mTexture, nullptr, getter_AddRefs(mUploadSRView)); |
|
105 } |
|
106 |
|
107 void |
|
108 CanvasLayerD3D10::UpdateSurface() |
|
109 { |
|
110 if (!IsDirty()) |
|
111 return; |
|
112 Painted(); |
|
113 |
|
114 if (mDrawTarget) { |
|
115 mDrawTarget->Flush(); |
|
116 } else if (mIsD2DTexture) { |
|
117 return; |
|
118 } |
|
119 |
|
120 if (!mTexture) { |
|
121 return; |
|
122 } |
|
123 |
|
124 if (mGLContext) { |
|
125 SharedSurface_GL* surf = mGLContext->RequestFrame(); |
|
126 if (!surf) { |
|
127 return; |
|
128 } |
|
129 |
|
130 switch (surf->Type()) { |
|
131 case SharedSurfaceType::EGLSurfaceANGLE: { |
|
132 SharedSurface_ANGLEShareHandle* shareSurf = SharedSurface_ANGLEShareHandle::Cast(surf); |
|
133 |
|
134 mSRView = shareSurf->GetSRV(); |
|
135 return; |
|
136 } |
|
137 case SharedSurfaceType::Basic: { |
|
138 SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf); |
|
139 // WebGL reads entire surface. |
|
140 D3D10_MAPPED_TEXTURE2D map; |
|
141 |
|
142 HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map); |
|
143 |
|
144 if (FAILED(hr)) { |
|
145 NS_WARNING("Failed to map CanvasLayer texture."); |
|
146 return; |
|
147 } |
|
148 |
|
149 DataSourceSurface* frameData = shareSurf->GetData(); |
|
150 // Scope for DrawTarget, so it's destroyed before Unmap. |
|
151 { |
|
152 IntSize boundsSize(mBounds.width, mBounds.height); |
|
153 RefPtr<DrawTarget> mapDt = Factory::CreateDrawTargetForData(BackendType::CAIRO, |
|
154 (uint8_t*)map.pData, |
|
155 boundsSize, |
|
156 map.RowPitch, |
|
157 SurfaceFormat::B8G8R8A8); |
|
158 |
|
159 Rect drawRect(0, 0, frameData->GetSize().width, frameData->GetSize().height); |
|
160 mapDt->DrawSurface(frameData, drawRect, drawRect, |
|
161 DrawSurfaceOptions(), DrawOptions(1.0F, CompositionOp::OP_SOURCE)); |
|
162 mapDt->Flush(); |
|
163 } |
|
164 |
|
165 mTexture->Unmap(0); |
|
166 mSRView = mUploadSRView; |
|
167 break; |
|
168 } |
|
169 |
|
170 default: |
|
171 MOZ_CRASH("Unhandled SharedSurfaceType."); |
|
172 } |
|
173 } else if (mSurface) { |
|
174 D3D10_MAPPED_TEXTURE2D map; |
|
175 HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map); |
|
176 |
|
177 if (FAILED(hr)) { |
|
178 NS_WARNING("Failed to lock CanvasLayer texture."); |
|
179 return; |
|
180 } |
|
181 |
|
182 RefPtr<DrawTarget> destTarget = |
|
183 Factory::CreateDrawTargetForD3D10Texture(mTexture, |
|
184 SurfaceFormat::R8G8B8A8); |
|
185 Rect r(Point(0, 0), ToRect(mBounds).Size()); |
|
186 destTarget->DrawSurface(mSurface, r, r, DrawSurfaceOptions(), |
|
187 DrawOptions(1.0F, CompositionOp::OP_SOURCE)); |
|
188 |
|
189 mTexture->Unmap(0); |
|
190 mSRView = mUploadSRView; |
|
191 } |
|
192 } |
|
193 |
|
194 Layer* |
|
195 CanvasLayerD3D10::GetLayer() |
|
196 { |
|
197 return this; |
|
198 } |
|
199 |
|
200 void |
|
201 CanvasLayerD3D10::RenderLayer() |
|
202 { |
|
203 FirePreTransactionCallback(); |
|
204 UpdateSurface(); |
|
205 FireDidTransactionCallback(); |
|
206 |
|
207 if (!mTexture) |
|
208 return; |
|
209 |
|
210 nsIntRect visibleRect = mVisibleRegion.GetBounds(); |
|
211 |
|
212 SetEffectTransformAndOpacity(); |
|
213 |
|
214 uint8_t shaderFlags = 0; |
|
215 shaderFlags |= LoadMaskTexture(); |
|
216 shaderFlags |= mDataIsPremultiplied |
|
217 ? SHADER_PREMUL : SHADER_NON_PREMUL | SHADER_RGBA; |
|
218 shaderFlags |= mHasAlpha ? SHADER_RGBA : SHADER_RGB; |
|
219 shaderFlags |= mFilter == GraphicsFilter::FILTER_NEAREST |
|
220 ? SHADER_POINT : SHADER_LINEAR; |
|
221 ID3D10EffectTechnique* technique = SelectShader(shaderFlags); |
|
222 |
|
223 if (mSRView) { |
|
224 effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(mSRView); |
|
225 } |
|
226 |
|
227 effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector( |
|
228 ShaderConstantRectD3D10( |
|
229 (float)mBounds.x, |
|
230 (float)mBounds.y, |
|
231 (float)mBounds.width, |
|
232 (float)mBounds.height) |
|
233 ); |
|
234 |
|
235 if (mNeedsYFlip) { |
|
236 effect()->GetVariableByName("vTextureCoords")->AsVector()->SetFloatVector( |
|
237 ShaderConstantRectD3D10( |
|
238 0, |
|
239 1.0f, |
|
240 1.0f, |
|
241 -1.0f) |
|
242 ); |
|
243 } |
|
244 |
|
245 technique->GetPassByIndex(0)->Apply(0); |
|
246 device()->Draw(4, 0); |
|
247 |
|
248 if (mNeedsYFlip) { |
|
249 effect()->GetVariableByName("vTextureCoords")->AsVector()-> |
|
250 SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f)); |
|
251 } |
|
252 } |
|
253 |
|
254 } /* namespace layers */ |
|
255 } /* namespace mozilla */ |