|
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 "D3D9SurfaceImage.h" |
|
7 #include "gfx2DGlue.h" |
|
8 #include "mozilla/layers/TextureD3D9.h" |
|
9 #include "mozilla/gfx/Types.h" |
|
10 |
|
11 namespace mozilla { |
|
12 namespace layers { |
|
13 |
|
14 |
|
15 D3D9SurfaceImage::D3D9SurfaceImage() |
|
16 : Image(nullptr, ImageFormat::D3D9_RGB32_TEXTURE) |
|
17 , mSize(0, 0) |
|
18 {} |
|
19 |
|
20 D3D9SurfaceImage::~D3D9SurfaceImage() {} |
|
21 |
|
22 HRESULT |
|
23 D3D9SurfaceImage::SetData(const Data& aData) |
|
24 { |
|
25 NS_ENSURE_TRUE(aData.mSurface, E_POINTER); |
|
26 HRESULT hr; |
|
27 RefPtr<IDirect3DSurface9> surface = aData.mSurface; |
|
28 |
|
29 RefPtr<IDirect3DDevice9> device; |
|
30 hr = surface->GetDevice(byRef(device)); |
|
31 NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL); |
|
32 |
|
33 RefPtr<IDirect3D9> d3d9; |
|
34 hr = device->GetDirect3D(byRef(d3d9)); |
|
35 NS_ENSURE_TRUE(SUCCEEDED(hr), E_FAIL); |
|
36 |
|
37 D3DSURFACE_DESC desc; |
|
38 surface->GetDesc(&desc); |
|
39 // Ensure we can convert the textures format to RGB conversion |
|
40 // in StretchRect. Fail if we can't. |
|
41 hr = d3d9->CheckDeviceFormatConversion(D3DADAPTER_DEFAULT, |
|
42 D3DDEVTYPE_HAL, |
|
43 desc.Format, |
|
44 D3DFMT_X8R8G8B8); |
|
45 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
46 |
|
47 // DXVA surfaces aren't created sharable, so we need to copy the surface |
|
48 // to a sharable texture to that it's accessible to the layer manager's |
|
49 // device. |
|
50 const nsIntRect& region = aData.mRegion; |
|
51 RefPtr<IDirect3DTexture9> texture; |
|
52 HANDLE shareHandle = nullptr; |
|
53 hr = device->CreateTexture(region.width, |
|
54 region.height, |
|
55 1, |
|
56 D3DUSAGE_RENDERTARGET, |
|
57 D3DFMT_X8R8G8B8, |
|
58 D3DPOOL_DEFAULT, |
|
59 byRef(texture), |
|
60 &shareHandle); |
|
61 NS_ENSURE_TRUE(SUCCEEDED(hr) && shareHandle, hr); |
|
62 |
|
63 // Copy the image onto the texture, preforming YUV -> RGB conversion if necessary. |
|
64 RefPtr<IDirect3DSurface9> textureSurface; |
|
65 hr = texture->GetSurfaceLevel(0, byRef(textureSurface)); |
|
66 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
67 |
|
68 // Stash the surface description for later use. |
|
69 textureSurface->GetDesc(&mDesc); |
|
70 |
|
71 RECT src = { region.x, region.y, region.x+region.width, region.y+region.height }; |
|
72 hr = device->StretchRect(surface, &src, textureSurface, nullptr, D3DTEXF_NONE); |
|
73 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
74 |
|
75 // Flush the draw command now, so that by the time we come to draw this |
|
76 // image, we're less likely to need to wait for the draw operation to |
|
77 // complete. |
|
78 RefPtr<IDirect3DQuery9> query; |
|
79 hr = device->CreateQuery(D3DQUERYTYPE_EVENT, byRef(query)); |
|
80 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
81 hr = query->Issue(D3DISSUE_END); |
|
82 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
83 |
|
84 mTexture = texture; |
|
85 mShareHandle = shareHandle; |
|
86 mSize = gfx::IntSize(region.width, region.height); |
|
87 mQuery = query; |
|
88 |
|
89 return S_OK; |
|
90 } |
|
91 |
|
92 void |
|
93 D3D9SurfaceImage::EnsureSynchronized() |
|
94 { |
|
95 if (!mQuery) { |
|
96 // Not setup, or already synchronized. |
|
97 return; |
|
98 } |
|
99 int iterations = 0; |
|
100 while (iterations < 10 && S_FALSE == mQuery->GetData(nullptr, 0, D3DGETDATA_FLUSH)) { |
|
101 Sleep(1); |
|
102 iterations++; |
|
103 } |
|
104 mQuery = nullptr; |
|
105 } |
|
106 |
|
107 HANDLE |
|
108 D3D9SurfaceImage::GetShareHandle() |
|
109 { |
|
110 // Ensure the image has completed its synchronization, |
|
111 // and safe to used by the caller on another device. |
|
112 EnsureSynchronized(); |
|
113 return mShareHandle; |
|
114 } |
|
115 |
|
116 const D3DSURFACE_DESC& |
|
117 D3D9SurfaceImage::GetDesc() const |
|
118 { |
|
119 return mDesc; |
|
120 } |
|
121 |
|
122 gfx::IntSize |
|
123 D3D9SurfaceImage::GetSize() |
|
124 { |
|
125 return mSize; |
|
126 } |
|
127 |
|
128 TextureClient* |
|
129 D3D9SurfaceImage::GetTextureClient(CompositableClient* aClient) |
|
130 { |
|
131 EnsureSynchronized(); |
|
132 if (!mTextureClient) { |
|
133 RefPtr<SharedTextureClientD3D9> textureClient = |
|
134 new SharedTextureClientD3D9(gfx::SurfaceFormat::B8G8R8X8, TEXTURE_FLAGS_DEFAULT); |
|
135 textureClient->InitWith(mTexture, mShareHandle, mDesc); |
|
136 mTextureClient = textureClient; |
|
137 } |
|
138 return mTextureClient; |
|
139 } |
|
140 |
|
141 TemporaryRef<gfx::SourceSurface> |
|
142 D3D9SurfaceImage::GetAsSourceSurface() |
|
143 { |
|
144 NS_ENSURE_TRUE(mTexture, nullptr); |
|
145 |
|
146 HRESULT hr; |
|
147 RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8X8); |
|
148 |
|
149 if (!surface) { |
|
150 NS_WARNING("Failed to created SourceSurface for D3D9SurfaceImage."); |
|
151 return nullptr; |
|
152 } |
|
153 |
|
154 // Ensure that the texture is ready to be used. |
|
155 EnsureSynchronized(); |
|
156 |
|
157 // Readback the texture from GPU memory into system memory, so that |
|
158 // we can copy it into the Cairo image. This is expensive. |
|
159 RefPtr<IDirect3DSurface9> textureSurface; |
|
160 hr = mTexture->GetSurfaceLevel(0, byRef(textureSurface)); |
|
161 NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); |
|
162 |
|
163 RefPtr<IDirect3DDevice9> device; |
|
164 hr = mTexture->GetDevice(byRef(device)); |
|
165 NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); |
|
166 |
|
167 RefPtr<IDirect3DSurface9> systemMemorySurface; |
|
168 hr = device->CreateOffscreenPlainSurface(mDesc.Width, |
|
169 mDesc.Height, |
|
170 D3DFMT_X8R8G8B8, |
|
171 D3DPOOL_SYSTEMMEM, |
|
172 byRef(systemMemorySurface), |
|
173 0); |
|
174 NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); |
|
175 |
|
176 hr = device->GetRenderTargetData(textureSurface, systemMemorySurface); |
|
177 NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); |
|
178 |
|
179 D3DLOCKED_RECT rect; |
|
180 hr = systemMemorySurface->LockRect(&rect, nullptr, 0); |
|
181 NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); |
|
182 |
|
183 gfx::DataSourceSurface::MappedSurface mappedSurface; |
|
184 if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) { |
|
185 systemMemorySurface->UnlockRect(); |
|
186 return nullptr; |
|
187 } |
|
188 |
|
189 const unsigned char* src = (const unsigned char*)(rect.pBits); |
|
190 const unsigned srcPitch = rect.Pitch; |
|
191 for (int y = 0; y < mSize.height; y++) { |
|
192 memcpy(mappedSurface.mData + mappedSurface.mStride * y, |
|
193 (unsigned char*)(src) + srcPitch * y, |
|
194 mSize.width * 4); |
|
195 } |
|
196 |
|
197 systemMemorySurface->UnlockRect(); |
|
198 surface->Unmap(); |
|
199 |
|
200 return surface; |
|
201 } |
|
202 |
|
203 } /* layers */ |
|
204 } /* mozilla */ |