|
1 /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ |
|
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 "SharedSurfaceANGLE.h" |
|
7 |
|
8 #include "GLContextEGL.h" |
|
9 |
|
10 using namespace mozilla::gfx; |
|
11 |
|
12 namespace mozilla { |
|
13 namespace gl { |
|
14 |
|
15 SurfaceFactory_ANGLEShareHandle* |
|
16 SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl, |
|
17 ID3D10Device1* d3d, |
|
18 const SurfaceCaps& caps) |
|
19 { |
|
20 GLLibraryEGL* egl = &sEGLLibrary; |
|
21 if (!egl) |
|
22 return nullptr; |
|
23 |
|
24 if (!egl->IsExtensionSupported( |
|
25 GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle)) |
|
26 { |
|
27 return nullptr; |
|
28 } |
|
29 |
|
30 return new SurfaceFactory_ANGLEShareHandle(gl, egl, d3d, caps); |
|
31 } |
|
32 |
|
33 EGLDisplay |
|
34 SharedSurface_ANGLEShareHandle::Display() |
|
35 { |
|
36 return mEGL->Display(); |
|
37 } |
|
38 |
|
39 |
|
40 SharedSurface_ANGLEShareHandle::~SharedSurface_ANGLEShareHandle() |
|
41 { |
|
42 mEGL->fDestroySurface(Display(), mPBuffer); |
|
43 } |
|
44 |
|
45 void |
|
46 SharedSurface_ANGLEShareHandle::LockProdImpl() |
|
47 { |
|
48 GLContextEGL::Cast(mGL)->SetEGLSurfaceOverride(mPBuffer); |
|
49 } |
|
50 |
|
51 void |
|
52 SharedSurface_ANGLEShareHandle::UnlockProdImpl() |
|
53 { |
|
54 } |
|
55 |
|
56 |
|
57 void |
|
58 SharedSurface_ANGLEShareHandle::Fence() |
|
59 { |
|
60 mGL->fFinish(); |
|
61 } |
|
62 |
|
63 bool |
|
64 SharedSurface_ANGLEShareHandle::WaitSync() |
|
65 { |
|
66 // Since we glFinish in Fence(), we're always going to be resolved here. |
|
67 return true; |
|
68 } |
|
69 |
|
70 static void |
|
71 FillPBufferAttribs_ByBits(nsTArray<EGLint>& aAttrs, |
|
72 int redBits, int greenBits, |
|
73 int blueBits, int alphaBits, |
|
74 int depthBits, int stencilBits) |
|
75 { |
|
76 aAttrs.Clear(); |
|
77 |
|
78 #if defined(A1) || defined(A2) |
|
79 #error The temp-macro names we want are already defined. |
|
80 #endif |
|
81 |
|
82 #define A1(_x) do { aAttrs.AppendElement(_x); } while (0) |
|
83 #define A2(_x,_y) do { A1(_x); A1(_y); } while (0) |
|
84 |
|
85 A2(LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT); |
|
86 A2(LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT); |
|
87 |
|
88 A2(LOCAL_EGL_RED_SIZE, redBits); |
|
89 A2(LOCAL_EGL_GREEN_SIZE, greenBits); |
|
90 A2(LOCAL_EGL_BLUE_SIZE, blueBits); |
|
91 A2(LOCAL_EGL_ALPHA_SIZE, alphaBits); |
|
92 |
|
93 A2(LOCAL_EGL_DEPTH_SIZE, depthBits); |
|
94 A2(LOCAL_EGL_STENCIL_SIZE, stencilBits); |
|
95 |
|
96 A1(LOCAL_EGL_NONE); |
|
97 #undef A1 |
|
98 #undef A2 |
|
99 } |
|
100 |
|
101 static void |
|
102 FillPBufferAttribs_BySizes(nsTArray<EGLint>& attribs, |
|
103 bool bpp16, bool hasAlpha, |
|
104 int depthBits, int stencilBits) |
|
105 { |
|
106 int red = 0; |
|
107 int green = 0; |
|
108 int blue = 0; |
|
109 int alpha = 0; |
|
110 |
|
111 if (bpp16) { |
|
112 if (hasAlpha) { |
|
113 red = green = blue = alpha = 4; |
|
114 } else { |
|
115 red = 5; |
|
116 green = 6; |
|
117 blue = 5; |
|
118 } |
|
119 } else { |
|
120 red = green = blue = 8; |
|
121 if (hasAlpha) |
|
122 alpha = 8; |
|
123 } |
|
124 |
|
125 FillPBufferAttribs_ByBits(attribs, |
|
126 red, green, blue, alpha, |
|
127 depthBits, stencilBits); |
|
128 } |
|
129 |
|
130 static EGLConfig |
|
131 ChooseConfig(GLContext* gl, |
|
132 GLLibraryEGL* egl, |
|
133 const SurfaceCaps& caps) |
|
134 { |
|
135 MOZ_ASSERT(egl); |
|
136 MOZ_ASSERT(caps.color); |
|
137 |
|
138 // We might want 24-bit depth, but we're only (fairly) sure to get 16-bit. |
|
139 int depthBits = caps.depth ? 16 : 0; |
|
140 int stencilBits = caps.stencil ? 8 : 0; |
|
141 |
|
142 // Ok, now we have everything. |
|
143 nsTArray<EGLint> attribs(32); |
|
144 FillPBufferAttribs_BySizes(attribs, |
|
145 caps.bpp16, caps.alpha, |
|
146 depthBits, stencilBits); |
|
147 |
|
148 // Time to try to get this config: |
|
149 EGLConfig configs[64]; |
|
150 int numConfigs = sizeof(configs)/sizeof(EGLConfig); |
|
151 int foundConfigs = 0; |
|
152 |
|
153 if (!egl->fChooseConfig(egl->Display(), |
|
154 attribs.Elements(), |
|
155 configs, numConfigs, |
|
156 &foundConfigs) || |
|
157 !foundConfigs) |
|
158 { |
|
159 NS_WARNING("No configs found for the requested formats."); |
|
160 return EGL_NO_CONFIG; |
|
161 } |
|
162 |
|
163 // TODO: Pick a config progamatically instead of hoping that |
|
164 // the first config will be minimally matching our request. |
|
165 EGLConfig config = configs[0]; |
|
166 |
|
167 if (gl->DebugMode()) { |
|
168 egl->DumpEGLConfig(config); |
|
169 } |
|
170 |
|
171 return config; |
|
172 } |
|
173 |
|
174 |
|
175 // Returns EGL_NO_SURFACE on error. |
|
176 static EGLSurface CreatePBufferSurface(GLLibraryEGL* egl, |
|
177 EGLDisplay display, |
|
178 EGLConfig config, |
|
179 const gfx::IntSize& size) |
|
180 { |
|
181 EGLint attribs[] = { |
|
182 LOCAL_EGL_WIDTH, size.width, |
|
183 LOCAL_EGL_HEIGHT, size.height, |
|
184 LOCAL_EGL_NONE |
|
185 }; |
|
186 |
|
187 EGLSurface surface = egl->fCreatePbufferSurface(display, config, attribs); |
|
188 |
|
189 return surface; |
|
190 } |
|
191 |
|
192 SharedSurface_ANGLEShareHandle* |
|
193 SharedSurface_ANGLEShareHandle::Create(GLContext* gl, ID3D10Device1* d3d, |
|
194 EGLContext context, EGLConfig config, |
|
195 const gfx::IntSize& size, bool hasAlpha) |
|
196 { |
|
197 GLLibraryEGL* egl = &sEGLLibrary; |
|
198 MOZ_ASSERT(egl); |
|
199 MOZ_ASSERT(egl->IsExtensionSupported( |
|
200 GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle)); |
|
201 |
|
202 if (!context || !config) |
|
203 return nullptr; |
|
204 |
|
205 EGLDisplay display = egl->Display(); |
|
206 EGLSurface pbuffer = CreatePBufferSurface(egl, display, config, size); |
|
207 if (!pbuffer) |
|
208 return nullptr; |
|
209 |
|
210 |
|
211 // Declare everything before 'goto's. |
|
212 HANDLE shareHandle = nullptr; |
|
213 nsRefPtr<ID3D10Texture2D> texture; |
|
214 nsRefPtr<ID3D10ShaderResourceView> srv; |
|
215 |
|
216 // On failure, goto CleanUpIfFailed. |
|
217 // If |failed|, CleanUpIfFailed will clean up and return null. |
|
218 bool failed = true; |
|
219 HRESULT hr; |
|
220 |
|
221 // Off to the races! |
|
222 if (!egl->fQuerySurfacePointerANGLE( |
|
223 display, |
|
224 pbuffer, |
|
225 LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, |
|
226 &shareHandle)) |
|
227 { |
|
228 NS_ERROR("Failed to grab ShareHandle for PBuffer!"); |
|
229 goto CleanUpIfFailed; |
|
230 } |
|
231 |
|
232 // Ok, we have a valid PBuffer with ShareHandle. |
|
233 // Let's attach it to D3D. |
|
234 hr = d3d->OpenSharedResource(shareHandle, |
|
235 __uuidof(ID3D10Texture2D), |
|
236 getter_AddRefs(texture)); |
|
237 if (FAILED(hr)) { |
|
238 NS_ERROR("Failed to open shared resource!"); |
|
239 goto CleanUpIfFailed; |
|
240 } |
|
241 |
|
242 hr = d3d->CreateShaderResourceView(texture, nullptr, getter_AddRefs(srv)); |
|
243 if (FAILED(hr)) { |
|
244 NS_ERROR("Failed to create SRV!"); |
|
245 goto CleanUpIfFailed; |
|
246 } |
|
247 |
|
248 failed = false; |
|
249 |
|
250 CleanUpIfFailed: |
|
251 if (failed) { |
|
252 NS_WARNING("CleanUpIfFailed"); |
|
253 egl->fDestroySurface(egl->Display(), pbuffer); |
|
254 return nullptr; |
|
255 } |
|
256 |
|
257 return new SharedSurface_ANGLEShareHandle(gl, egl, |
|
258 size, hasAlpha, |
|
259 context, pbuffer, |
|
260 texture, srv); |
|
261 } |
|
262 |
|
263 |
|
264 SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl, |
|
265 GLLibraryEGL* egl, |
|
266 ID3D10Device1* d3d, |
|
267 const SurfaceCaps& caps) |
|
268 : SurfaceFactory_GL(gl, SharedSurfaceType::EGLSurfaceANGLE, caps) |
|
269 , mProdGL(gl) |
|
270 , mEGL(egl) |
|
271 , mConsD3D(d3d) |
|
272 { |
|
273 mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps); |
|
274 mContext = GLContextEGL::Cast(mProdGL)->GetEGLContext(); |
|
275 MOZ_ASSERT(mConfig && mContext); |
|
276 } |
|
277 |
|
278 } /* namespace gl */ |
|
279 } /* namespace mozilla */ |