gfx/layers/d3d10/ImageLayerD3D10.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:f49f32eec35b
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 "ImageLayerD3D10.h"
7 #include "gfxD2DSurface.h"
8 #include "gfxWindowsSurface.h"
9 #include "yuv_convert.h"
10 #include "../d3d9/Nv3DVUtils.h"
11 #include "D3D9SurfaceImage.h"
12 #include "mozilla/gfx/Point.h"
13 #include "gfx2DGlue.h"
14
15 #include "gfxWindowsPlatform.h"
16
17 using namespace mozilla::gfx;
18
19 namespace mozilla {
20 namespace layers {
21
22 static already_AddRefed<ID3D10Texture2D>
23 DataToTexture(ID3D10Device *aDevice,
24 unsigned char *data,
25 int stride,
26 const IntSize &aSize)
27 {
28 D3D10_SUBRESOURCE_DATA srdata;
29
30 CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
31 aSize.width,
32 aSize.height,
33 1, 1);
34 desc.Usage = D3D10_USAGE_IMMUTABLE;
35
36 srdata.pSysMem = data;
37 srdata.SysMemPitch = stride;
38
39 nsRefPtr<ID3D10Texture2D> texture;
40 HRESULT hr = aDevice->CreateTexture2D(&desc, &srdata, getter_AddRefs(texture));
41
42 if (FAILED(hr)) {
43 LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("Failed to create texture for data"),
44 hr);
45 }
46
47 return texture.forget();
48 }
49
50 static already_AddRefed<ID3D10Texture2D>
51 SurfaceToTexture(ID3D10Device *aDevice,
52 SourceSurface *aSurface,
53 const IntSize &aSize)
54 {
55 if (!aSurface) {
56 return nullptr;
57 }
58
59 void *nativeSurf =
60 aSurface->GetNativeSurface(NativeSurfaceType::D3D10_TEXTURE);
61 if (nativeSurf) {
62 nsRefPtr<ID3D10Texture2D> texture =
63 static_cast<ID3D10Texture2D*>(nativeSurf);
64 ID3D10Device *dev;
65 texture->GetDevice(&dev);
66 if (dev == aDevice) {
67 return texture.forget();
68 }
69 }
70 RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
71 if (!dataSurface) {
72 return nullptr;
73 }
74 DataSourceSurface::MappedSurface map;
75 if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
76 return nullptr;
77 }
78 nsRefPtr<ID3D10Texture2D> texture =
79 DataToTexture(aDevice, map.mData, map.mStride, aSize);
80 dataSurface->Unmap();
81 return texture.forget();
82 }
83
84 Layer*
85 ImageLayerD3D10::GetLayer()
86 {
87 return this;
88 }
89
90 /**
91 * Returns a shader resource view for a Cairo or remote image.
92 * Returns nullptr if unsuccessful.
93 * If successful, aHasAlpha will be true iff the resulting texture
94 * has an alpha component.
95 */
96 ID3D10ShaderResourceView*
97 ImageLayerD3D10::GetImageSRView(Image* aImage, bool& aHasAlpha, IDXGIKeyedMutex **aMutex)
98 {
99 NS_ASSERTION(aImage, "Null image.");
100
101 if (aImage->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP) {
102 RemoteBitmapImage *remoteImage =
103 static_cast<RemoteBitmapImage*>(aImage);
104
105 if (!aImage->GetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10)) {
106 nsAutoPtr<TextureD3D10BackendData> dat(new TextureD3D10BackendData());
107 dat->mTexture = DataToTexture(device(), remoteImage->mData, remoteImage->mStride, remoteImage->mSize);
108
109 if (dat->mTexture) {
110 device()->CreateShaderResourceView(dat->mTexture, nullptr, getter_AddRefs(dat->mSRView));
111 aImage->SetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10, dat.forget());
112 }
113 }
114
115 aHasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32;
116 } else if (aImage->GetFormat() == ImageFormat::REMOTE_IMAGE_DXGI_TEXTURE) {
117 RemoteDXGITextureImage *remoteImage =
118 static_cast<RemoteDXGITextureImage*>(aImage);
119
120 remoteImage->GetD3D10TextureBackendData(device());
121
122 aHasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32;
123 } else if (aImage->GetFormat() == ImageFormat::CAIRO_SURFACE) {
124 CairoImage *cairoImage =
125 static_cast<CairoImage*>(aImage);
126
127 RefPtr<SourceSurface> surf = cairoImage->GetAsSourceSurface();
128 if (!surf) {
129 return nullptr;
130 }
131
132 if (!aImage->GetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10)) {
133 nsAutoPtr<TextureD3D10BackendData> dat(new TextureD3D10BackendData());
134 dat->mTexture = SurfaceToTexture(device(), surf, cairoImage->GetSize());
135
136 if (dat->mTexture) {
137 device()->CreateShaderResourceView(dat->mTexture, nullptr, getter_AddRefs(dat->mSRView));
138 aImage->SetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10, dat.forget());
139 }
140 }
141
142 aHasAlpha = surf->GetFormat() == SurfaceFormat::B8G8R8A8;
143 } else if (aImage->GetFormat() == ImageFormat::D3D9_RGB32_TEXTURE) {
144 if (!aImage->GetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10)) {
145 // Use resource sharing to open the D3D9 texture as a D3D10 texture,
146 HRESULT hr;
147 D3D9SurfaceImage* d3dImage = reinterpret_cast<D3D9SurfaceImage*>(aImage);
148 nsRefPtr<ID3D10Texture2D> texture;
149 hr = device()->OpenSharedResource(d3dImage->GetShareHandle(),
150 IID_ID3D10Texture2D,
151 (void**)getter_AddRefs(texture));
152 NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
153
154 nsAutoPtr<TextureD3D10BackendData> dat(new TextureD3D10BackendData());
155 dat->mTexture = texture;
156
157 hr = device()->CreateShaderResourceView(dat->mTexture, nullptr, getter_AddRefs(dat->mSRView));
158 NS_ENSURE_TRUE(SUCCEEDED(hr) && dat->mSRView, nullptr);
159
160 aImage->SetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10, dat.forget());
161 }
162 aHasAlpha = false;
163 } else {
164 NS_WARNING("Incorrect image type.");
165 return nullptr;
166 }
167
168 TextureD3D10BackendData *data =
169 static_cast<TextureD3D10BackendData*>(aImage->GetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10));
170
171 if (!data) {
172 return nullptr;
173 }
174
175 if (aMutex &&
176 SUCCEEDED(data->mTexture->QueryInterface(IID_IDXGIKeyedMutex, (void**)aMutex))) {
177 if (FAILED((*aMutex)->AcquireSync(0, 0))) {
178 NS_WARNING("Failed to acquire sync on keyed mutex, plugin forgot to release?");
179 return nullptr;
180 }
181 }
182
183 nsRefPtr<ID3D10Device> dev;
184 data->mTexture->GetDevice(getter_AddRefs(dev));
185 if (dev != device()) {
186 return nullptr;
187 }
188
189 return data->mSRView;
190 }
191
192 void
193 ImageLayerD3D10::RenderLayer()
194 {
195 ImageContainer *container = GetContainer();
196 if (!container) {
197 return;
198 }
199
200 AutoLockImage autoLock(container);
201
202 Image *image = autoLock.GetImage();
203 if (!image) {
204 return;
205 }
206
207 IntSize size = image->GetSize();
208
209 SetEffectTransformAndOpacity();
210
211 ID3D10EffectTechnique *technique;
212 nsRefPtr<IDXGIKeyedMutex> keyedMutex;
213
214 if (image->GetFormat() == ImageFormat::CAIRO_SURFACE ||
215 image->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP ||
216 image->GetFormat() == ImageFormat::REMOTE_IMAGE_DXGI_TEXTURE ||
217 image->GetFormat() == ImageFormat::D3D9_RGB32_TEXTURE) {
218 NS_ASSERTION(image->GetFormat() != ImageFormat::CAIRO_SURFACE ||
219 !static_cast<CairoImage*>(image)->mSourceSurface ||
220 static_cast<CairoImage*>(image)->mSourceSurface->GetFormat() != SurfaceFormat::A8,
221 "Image layer has alpha image");
222 bool hasAlpha = false;
223
224 nsRefPtr<ID3D10ShaderResourceView> srView = GetImageSRView(image, hasAlpha, getter_AddRefs(keyedMutex));
225 if (!srView) {
226 return;
227 }
228
229 uint8_t shaderFlags = SHADER_PREMUL;
230 shaderFlags |= LoadMaskTexture();
231 shaderFlags |= hasAlpha
232 ? SHADER_RGBA : SHADER_RGB;
233 shaderFlags |= mFilter == GraphicsFilter::FILTER_NEAREST
234 ? SHADER_POINT : SHADER_LINEAR;
235 technique = SelectShader(shaderFlags);
236
237
238 effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(srView);
239
240 effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
241 ShaderConstantRectD3D10(
242 (float)0,
243 (float)0,
244 (float)size.width,
245 (float)size.height)
246 );
247 } else if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) {
248 PlanarYCbCrImage *yuvImage =
249 static_cast<PlanarYCbCrImage*>(image);
250
251 if (!yuvImage->IsValid()) {
252 return;
253 }
254
255 if (!yuvImage->GetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10)) {
256 AllocateTexturesYCbCr(yuvImage);
257 }
258
259 PlanarYCbCrD3D10BackendData *data =
260 static_cast<PlanarYCbCrD3D10BackendData*>(yuvImage->GetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10));
261
262 if (!data) {
263 return;
264 }
265
266 nsRefPtr<ID3D10Device> dev;
267 data->mYTexture->GetDevice(getter_AddRefs(dev));
268 if (dev != device()) {
269 return;
270 }
271
272 // TODO: At some point we should try to deal with mFilter here, you don't
273 // really want to use point filtering in the case of NEAREST, since that
274 // would also use point filtering for Chroma upsampling. Where most likely
275 // the user would only want point filtering for final RGB image upsampling.
276
277 technique = SelectShader(SHADER_YCBCR | LoadMaskTexture());
278
279 effect()->GetVariableByName("tY")->AsShaderResource()->SetResource(data->mYView);
280 effect()->GetVariableByName("tCb")->AsShaderResource()->SetResource(data->mCbView);
281 effect()->GetVariableByName("tCr")->AsShaderResource()->SetResource(data->mCrView);
282
283 /*
284 * Send 3d control data and metadata to NV3DVUtils
285 */
286 if (GetNv3DVUtils()) {
287 Nv_Stereo_Mode mode;
288 switch (yuvImage->GetData()->mStereoMode) {
289 case StereoMode::LEFT_RIGHT:
290 mode = NV_STEREO_MODE_LEFT_RIGHT;
291 break;
292 case StereoMode::RIGHT_LEFT:
293 mode = NV_STEREO_MODE_RIGHT_LEFT;
294 break;
295 case StereoMode::BOTTOM_TOP:
296 mode = NV_STEREO_MODE_BOTTOM_TOP;
297 break;
298 case StereoMode::TOP_BOTTOM:
299 mode = NV_STEREO_MODE_TOP_BOTTOM;
300 break;
301 case StereoMode::MONO:
302 mode = NV_STEREO_MODE_MONO;
303 break;
304 }
305
306 // Send control data even in mono case so driver knows to leave stereo mode.
307 GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE);
308
309 if (yuvImage->GetData()->mStereoMode != StereoMode::MONO) {
310 // Dst resource is optional
311 GetNv3DVUtils()->SendNv3DVMetaData((unsigned int)yuvImage->GetData()->mYSize.width,
312 (unsigned int)yuvImage->GetData()->mYSize.height, (HANDLE)(data->mYTexture), (HANDLE)(nullptr));
313 }
314 }
315
316 effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
317 ShaderConstantRectD3D10(
318 (float)0,
319 (float)0,
320 (float)size.width,
321 (float)size.height)
322 );
323
324 effect()->GetVariableByName("vTextureCoords")->AsVector()->SetFloatVector(
325 ShaderConstantRectD3D10(
326 (float)yuvImage->GetData()->mPicX / yuvImage->GetData()->mYSize.width,
327 (float)yuvImage->GetData()->mPicY / yuvImage->GetData()->mYSize.height,
328 (float)yuvImage->GetData()->mPicSize.width / yuvImage->GetData()->mYSize.width,
329 (float)yuvImage->GetData()->mPicSize.height / yuvImage->GetData()->mYSize.height)
330 );
331 }
332
333 bool resetTexCoords = image->GetFormat() == ImageFormat::PLANAR_YCBCR;
334 image = nullptr;
335 autoLock.Unlock();
336
337 technique->GetPassByIndex(0)->Apply(0);
338 device()->Draw(4, 0);
339
340 if (keyedMutex) {
341 keyedMutex->ReleaseSync(0);
342 }
343
344 if (resetTexCoords) {
345 effect()->GetVariableByName("vTextureCoords")->AsVector()->
346 SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
347 }
348
349 GetContainer()->NotifyPaintedImage(image);
350 }
351
352 void ImageLayerD3D10::AllocateTexturesYCbCr(PlanarYCbCrImage *aImage)
353 {
354 nsAutoPtr<PlanarYCbCrD3D10BackendData> backendData(
355 new PlanarYCbCrD3D10BackendData);
356
357 const PlanarYCbCrData *data = aImage->GetData();
358
359 D3D10_SUBRESOURCE_DATA dataY;
360 D3D10_SUBRESOURCE_DATA dataCb;
361 D3D10_SUBRESOURCE_DATA dataCr;
362 CD3D10_TEXTURE2D_DESC descY(DXGI_FORMAT_A8_UNORM,
363 data->mYSize.width,
364 data->mYSize.height, 1, 1);
365 CD3D10_TEXTURE2D_DESC descCbCr(DXGI_FORMAT_A8_UNORM,
366 data->mCbCrSize.width,
367 data->mCbCrSize.height, 1, 1);
368
369 descY.Usage = descCbCr.Usage = D3D10_USAGE_IMMUTABLE;
370
371 dataY.pSysMem = data->mYChannel;
372 dataY.SysMemPitch = data->mYStride;
373 dataCb.pSysMem = data->mCbChannel;
374 dataCb.SysMemPitch = data->mCbCrStride;
375 dataCr.pSysMem = data->mCrChannel;
376 dataCr.SysMemPitch = data->mCbCrStride;
377
378 HRESULT hr = device()->CreateTexture2D(&descY, &dataY, getter_AddRefs(backendData->mYTexture));
379 if (!FAILED(hr)) {
380 hr = device()->CreateTexture2D(&descCbCr, &dataCb, getter_AddRefs(backendData->mCbTexture));
381 }
382 if (!FAILED(hr)) {
383 hr = device()->CreateTexture2D(&descCbCr, &dataCr, getter_AddRefs(backendData->mCrTexture));
384 }
385 if (FAILED(hr)) {
386 LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("PlanarYCbCrImageD3D10::AllocateTextures(): Failed to create texture"),
387 hr);
388 return;
389 }
390 device()->CreateShaderResourceView(backendData->mYTexture, nullptr, getter_AddRefs(backendData->mYView));
391 device()->CreateShaderResourceView(backendData->mCbTexture, nullptr, getter_AddRefs(backendData->mCbView));
392 device()->CreateShaderResourceView(backendData->mCrTexture, nullptr, getter_AddRefs(backendData->mCrView));
393
394 aImage->SetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10, backendData.forget());
395 }
396
397 already_AddRefed<ID3D10ShaderResourceView>
398 ImageLayerD3D10::GetAsTexture(gfx::IntSize* aSize)
399 {
400 if (!GetContainer()) {
401 return nullptr;
402 }
403
404 AutoLockImage autoLock(GetContainer());
405
406 Image *image = autoLock.GetImage();
407 if (!image) {
408 return nullptr;
409 }
410
411 if (image->GetFormat() != ImageFormat::CAIRO_SURFACE) {
412 return nullptr;
413 }
414
415 *aSize = image->GetSize();
416 bool dontCare;
417 nsRefPtr<ID3D10ShaderResourceView> result = GetImageSRView(image, dontCare);
418 return result.forget();
419 }
420
421 TemporaryRef<gfx::SourceSurface>
422 RemoteDXGITextureImage::GetAsSourceSurface()
423 {
424 nsRefPtr<ID3D10Device1> device =
425 gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
426 if (!device) {
427 NS_WARNING("Cannot readback from shared texture because no D3D10 device is available.");
428 return nullptr;
429 }
430
431 TextureD3D10BackendData* data = GetD3D10TextureBackendData(device);
432
433 if (!data) {
434 return nullptr;
435 }
436
437 nsRefPtr<IDXGIKeyedMutex> keyedMutex;
438
439 if (FAILED(data->mTexture->QueryInterface(IID_IDXGIKeyedMutex, getter_AddRefs(keyedMutex)))) {
440 NS_WARNING("Failed to QueryInterface for IDXGIKeyedMutex, strange.");
441 return nullptr;
442 }
443
444 if (FAILED(keyedMutex->AcquireSync(0, 0))) {
445 NS_WARNING("Failed to acquire sync for keyedMutex, plugin failed to release?");
446 return nullptr;
447 }
448
449 D3D10_TEXTURE2D_DESC desc;
450
451 data->mTexture->GetDesc(&desc);
452
453 desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
454 desc.BindFlags = 0;
455 desc.MiscFlags = 0;
456 desc.Usage = D3D10_USAGE_STAGING;
457
458 nsRefPtr<ID3D10Texture2D> softTexture;
459 HRESULT hr = device->CreateTexture2D(&desc, nullptr, getter_AddRefs(softTexture));
460
461 if (FAILED(hr)) {
462 NS_WARNING("Failed to create 2D staging texture.");
463 return nullptr;
464 }
465
466 device->CopyResource(softTexture, data->mTexture);
467 keyedMutex->ReleaseSync(0);
468
469 RefPtr<gfx::DataSourceSurface> surface
470 = gfx::Factory::CreateDataSourceSurface(mSize,
471 mFormat == RemoteImageData::BGRX32
472 ? gfx::SurfaceFormat::B8G8R8X8
473 : gfx::SurfaceFormat::B8G8R8A8);
474
475 if (!surface) {
476 NS_WARNING("Failed to create SourceSurface for DXGI texture.");
477 return nullptr;
478 }
479
480 gfx::DataSourceSurface::MappedSurface mappedSurface;
481 if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
482 NS_WARNING("Failed to map source surface");
483 return nullptr;
484 }
485
486 D3D10_MAPPED_TEXTURE2D mapped;
487 softTexture->Map(0, D3D10_MAP_READ, 0, &mapped);
488
489 for (int y = 0; y < mSize.height; y++) {
490 memcpy(mappedSurface.mData + mappedSurface.mStride * y,
491 (unsigned char*)(mapped.pData) + mapped.RowPitch * y,
492 mSize.width * 4);
493 }
494
495 softTexture->Unmap(0);
496 surface->Unmap();
497
498 return surface;
499 }
500
501 TextureD3D10BackendData*
502 RemoteDXGITextureImage::GetD3D10TextureBackendData(ID3D10Device *aDevice)
503 {
504 if (GetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10)) {
505 TextureD3D10BackendData *data =
506 static_cast<TextureD3D10BackendData*>(GetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10));
507
508 nsRefPtr<ID3D10Device> device;
509 data->mTexture->GetDevice(getter_AddRefs(device));
510
511 if (device == aDevice) {
512 return data;
513 }
514 }
515 nsRefPtr<ID3D10Texture2D> texture;
516 aDevice->OpenSharedResource(mHandle, __uuidof(ID3D10Texture2D), getter_AddRefs(texture));
517
518 if (!texture) {
519 NS_WARNING("Failed to get texture for shared texture handle.");
520 return nullptr;
521 }
522
523 nsAutoPtr<TextureD3D10BackendData> data(new TextureD3D10BackendData());
524
525 data->mTexture = texture;
526
527 aDevice->CreateShaderResourceView(texture, nullptr, getter_AddRefs(data->mSRView));
528
529 SetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D10, data);
530
531 return data.forget();
532 }
533
534 } /* layers */
535 } /* mozilla */

mercurial