OLD | NEW |
| (Empty) |
1 /* | |
2 | |
3 Copyright (C) 2012 Zeno Albisser <zeno@webkit.org> | |
4 | |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Library General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2 of the License, or (at your option) any later version. | |
9 | |
10 This library is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 Library General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Library General Public License | |
16 along with this library; see the file COPYING.LIB. If not, write to | |
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
18 Boston, MA 02110-1301, USA. | |
19 */ | |
20 | |
21 #include "config.h" | |
22 #include "GraphicsSurface.h" | |
23 | |
24 #if USE(GRAPHICS_SURFACE) | |
25 #include "TextureMapperGL.h" | |
26 | |
27 #define EGL_EGLEXT_PROTOTYPES // This must be defined before including egl.h and
eglext.h. | |
28 #include <EGL/egl.h> | |
29 #include <EGL/eglext.h> | |
30 | |
31 namespace WebCore { | |
32 | |
33 #define STRINGIFY(...) #__VA_ARGS__ | |
34 | |
35 static GLuint loadShader(GLenum type, const GLchar *shaderSrc) | |
36 { | |
37 GLuint shader; | |
38 GLint compiled; | |
39 | |
40 shader = glCreateShader(type); | |
41 if (!shader) | |
42 return 0; | |
43 | |
44 glShaderSource(shader, 1, &shaderSrc, 0); | |
45 glCompileShader(shader); | |
46 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); | |
47 if (!compiled) { | |
48 glDeleteShader(shader); | |
49 return 0; | |
50 } | |
51 return shader; | |
52 } | |
53 | |
54 struct GraphicsSurfacePrivate { | |
55 public: | |
56 GraphicsSurfacePrivate(const IntSize& size, GraphicsSurfaceToken token) | |
57 : m_token(token) | |
58 , m_detachedContext(0) | |
59 , m_detachedReadSurface(0) | |
60 , m_detachedDrawSurface(0) | |
61 , m_size(size) | |
62 , m_eglDisplay(0) | |
63 , m_eglContext(0) | |
64 , m_eglConfig(0) | |
65 , m_eglFrontBufferSurface(0) | |
66 , m_eglBackBufferSurface(0) | |
67 , m_initialFrontBufferShareHandle(token.frontBufferHandle) | |
68 , m_frontBufferShareHandle(token.frontBufferHandle) | |
69 , m_backBufferShareHandle(token.backBufferHandle) | |
70 , m_frontBufferTexture(0) | |
71 , m_shaderProgram(0) | |
72 { | |
73 initializeShaderProgram(); | |
74 } | |
75 | |
76 | |
77 GraphicsSurfacePrivate(const PlatformGraphicsContext3D shareContext, const I
ntSize& size, GraphicsSurface::Flags flags) | |
78 : m_detachedContext(0) | |
79 , m_detachedReadSurface(0) | |
80 , m_detachedDrawSurface(0) | |
81 , m_size(size) | |
82 , m_eglDisplay(0) | |
83 , m_eglContext(0) | |
84 , m_eglConfig(0) | |
85 , m_eglFrontBufferSurface(0) | |
86 , m_eglBackBufferSurface(0) | |
87 , m_initialFrontBufferShareHandle(0) | |
88 , m_frontBufferShareHandle(0) | |
89 , m_backBufferShareHandle(0) | |
90 , m_frontBufferTexture(0) | |
91 , m_shaderProgram(0) | |
92 { | |
93 initializeShaderProgram(); | |
94 | |
95 static PFNEGLQUERYSURFACEPOINTERANGLEPROC eglQuerySurfacePointerANGLE =
0; | |
96 if (!eglQuerySurfacePointerANGLE) { | |
97 eglQuerySurfacePointerANGLE = reinterpret_cast<PFNEGLQUERYSURFACEPOI
NTERANGLEPROC>(eglGetProcAddress("eglQuerySurfacePointerANGLE")); | |
98 if (!eglQuerySurfacePointerANGLE) | |
99 return; | |
100 } | |
101 | |
102 if (!m_eglDisplay || !m_eglContext || !m_eglConfig) { | |
103 m_eglDisplay = eglGetCurrentDisplay(); | |
104 EGLint contextAttributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NO
NE }; | |
105 m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, eglShareC
ontext, contextAttributes); | |
106 } | |
107 | |
108 EGLint attributes[] = { | |
109 EGL_WIDTH, size.width(), | |
110 EGL_HEIGHT, size.height(), | |
111 EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB, | |
112 EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, | |
113 EGL_NONE | |
114 }; | |
115 | |
116 m_eglFrontBufferSurface = eglCreatePbufferSurface(m_eglDisplay, m_eglCon
fig, attributes); | |
117 m_eglBackBufferSurface = eglCreatePbufferSurface(m_eglDisplay, m_eglConf
ig, attributes); | |
118 if (m_eglFrontBufferSurface == EGL_NO_SURFACE || m_eglBackBufferSurface
== EGL_NO_SURFACE) | |
119 return; | |
120 | |
121 eglQuerySurfacePointerANGLE(m_eglDisplay, m_eglFrontBufferSurface, EGL_D
3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, &m_frontBufferShareHandle); | |
122 eglQuerySurfacePointerANGLE(m_eglDisplay, m_eglBackBufferSurface, EGL_D3
D_TEXTURE_2D_SHARE_HANDLE_ANGLE, &m_backBufferShareHandle); | |
123 | |
124 m_initialFrontBufferShareHandle = m_frontBufferShareHandle; | |
125 | |
126 m_token = GraphicsSurfaceToken(m_frontBufferShareHandle, m_backBufferSha
reHandle); | |
127 } | |
128 | |
129 ~GraphicsSurfacePrivate() | |
130 { | |
131 releaseFrontBufferTexture(); | |
132 | |
133 if (m_eglBackBufferSurface) | |
134 eglDestroySurface(m_eglDisplay, m_eglBackBufferSurface); | |
135 | |
136 if (m_shaderProgram) | |
137 glDeleteProgram(m_shaderProgram); | |
138 m_shaderProgram = 0; | |
139 | |
140 if (m_eglDisplay && m_eglContext) | |
141 eglDestroyContext(m_eglDisplay, m_eglContext); | |
142 } | |
143 | |
144 void copyFromTexture(uint32_t texture, const IntRect& sourceRect) | |
145 { | |
146 if (!makeCurrent()) | |
147 return; | |
148 glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
149 drawTexture(texture); | |
150 glFinish(); | |
151 doneCurrent(); | |
152 } | |
153 | |
154 bool makeCurrent() | |
155 { | |
156 m_detachedContext = eglGetCurrentContext(); | |
157 m_detachedReadSurface = eglGetCurrentSurface(EGL_READ); | |
158 m_detachedDrawSurface = eglGetCurrentSurface(EGL_DRAW); | |
159 | |
160 return eglMakeCurrent(m_eglDisplay, m_eglBackBufferSurface, m_eglBackBuf
ferSurface, m_eglContext); | |
161 } | |
162 | |
163 bool doneCurrent() | |
164 { | |
165 if (!m_detachedContext || !m_detachedDrawSurface || !m_detachedReadSurfa
ce) | |
166 return false; | |
167 | |
168 bool success = eglMakeCurrent(m_eglDisplay, m_detachedDrawSurface, m_det
achedReadSurface, m_detachedContext); | |
169 m_detachedContext = 0; | |
170 m_detachedReadSurface = 0; | |
171 m_detachedDrawSurface = 0; | |
172 return success; | |
173 } | |
174 | |
175 PlatformGraphicsSurface swapBuffers() | |
176 { | |
177 if (m_frontBufferTexture) | |
178 releaseFrontBufferTexture(); | |
179 std::swap(m_eglFrontBufferSurface, m_eglBackBufferSurface); | |
180 std::swap(m_frontBufferShareHandle, m_backBufferShareHandle); | |
181 | |
182 return m_frontBufferShareHandle; | |
183 } | |
184 | |
185 GraphicsSurfaceToken token() const | |
186 { | |
187 return m_token; | |
188 } | |
189 | |
190 uint32_t frontBufferTextureID() | |
191 { | |
192 if (!m_eglFrontBufferSurface) { | |
193 m_eglFrontBufferSurface = createSurfaceFromShareHandle(m_size, m_fro
ntBufferShareHandle); | |
194 | |
195 glGenTextures(1, &m_frontBufferTexture); | |
196 glActiveTexture(GL_TEXTURE0); | |
197 glBindTexture(GL_TEXTURE_2D, m_frontBufferTexture); | |
198 eglBindTexImage(m_eglDisplay, m_eglFrontBufferSurface, EGL_BACK_BUFF
ER); | |
199 | |
200 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
201 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
202 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
203 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
204 } | |
205 | |
206 return m_frontBufferTexture; | |
207 } | |
208 | |
209 PlatformGraphicsSurface initialFrontBufferShareHandle() const | |
210 { | |
211 return m_initialFrontBufferShareHandle; | |
212 } | |
213 | |
214 PlatformGraphicsSurface frontBufferShareHandle() const | |
215 { | |
216 return m_frontBufferShareHandle; | |
217 } | |
218 | |
219 PlatformGraphicsSurface backBufferShareHandle() const | |
220 { | |
221 return m_backBufferShareHandle; | |
222 } | |
223 | |
224 void releaseFrontBufferTexture() | |
225 { | |
226 if (m_frontBufferTexture) { | |
227 eglReleaseTexImage(m_eglDisplay, m_eglFrontBufferSurface, EGL_BACK_B
UFFER); | |
228 glDeleteTextures(1, &m_frontBufferTexture); | |
229 m_frontBufferTexture = 0; | |
230 } | |
231 | |
232 if (m_eglFrontBufferSurface) | |
233 eglDestroySurface(m_eglDisplay, m_eglFrontBufferSurface); | |
234 m_eglFrontBufferSurface = 0; | |
235 } | |
236 | |
237 IntSize size() const | |
238 { | |
239 return m_size; | |
240 } | |
241 | |
242 protected: | |
243 void initializeShaderProgram() | |
244 { | |
245 if (m_shaderProgram) | |
246 return; | |
247 | |
248 GLchar vShaderStr[] = | |
249 STRINGIFY( | |
250 attribute highp vec2 vertex; | |
251 attribute highp vec2 textureCoordinates; | |
252 varying highp vec2 textureCoords; | |
253 void main(void) | |
254 { | |
255 gl_Position = vec4(vertex, 0.0, 1.0); | |
256 textureCoords = textureCoordinates; | |
257 } | |
258 ); | |
259 | |
260 GLchar fShaderStr[] = | |
261 STRINGIFY( | |
262 varying highp vec2 textureCoords; | |
263 uniform sampler2D texture; | |
264 void main(void) | |
265 { | |
266 highp vec3 color = texture2D(texture, textureCoords).rgb; | |
267 gl_FragColor = vec4(clamp(color, 0.0, 1.0), 1.0); | |
268 } | |
269 ); | |
270 | |
271 GLuint vertexShader; | |
272 GLuint fragmentShader; | |
273 GLint linked; | |
274 | |
275 vertexShader = loadShader(GL_VERTEX_SHADER, vShaderStr); | |
276 fragmentShader = loadShader(GL_FRAGMENT_SHADER, fShaderStr); | |
277 if (!vertexShader || !fragmentShader) | |
278 return; | |
279 | |
280 m_shaderProgram = glCreateProgram(); | |
281 if (!m_shaderProgram) | |
282 return; | |
283 | |
284 glAttachShader(m_shaderProgram, vertexShader); | |
285 glAttachShader(m_shaderProgram, fragmentShader); | |
286 | |
287 glLinkProgram(m_shaderProgram); | |
288 glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, &linked); | |
289 if (!linked) { | |
290 glDeleteProgram(m_shaderProgram); | |
291 m_shaderProgram = 0; | |
292 } | |
293 | |
294 m_vertexAttr = glGetAttribLocation(m_shaderProgram, "vertex"); | |
295 m_textureCoordinatesAttr = glGetAttribLocation(m_shaderProgram, "texture
Coordinates"); | |
296 m_textureUniform = glGetAttribLocation(m_shaderProgram, "texture"); | |
297 | |
298 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
299 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
300 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
301 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
302 } | |
303 | |
304 EGLSurface createSurfaceFromShareHandle(const IntSize& size, HANDLE shareHan
dle) | |
305 { | |
306 if (!m_eglDisplay || !m_eglConfig) | |
307 m_eglDisplay = eglGetCurrentDisplay(); | |
308 | |
309 EGLint attributes[] = { | |
310 EGL_WIDTH, size.width(), | |
311 EGL_HEIGHT, size.height(), | |
312 EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB, | |
313 EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, | |
314 EGL_NONE | |
315 }; | |
316 | |
317 EGLSurface surface = eglCreatePbufferFromClientBuffer(m_eglDisplay, EGL_
D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, reinterpret_cast<EGLClientBuffer>(shareHandle
), m_eglConfig, attributes); | |
318 ASSERT(surface); | |
319 | |
320 return surface; | |
321 } | |
322 | |
323 void drawTexture(uint32_t texture) | |
324 { | |
325 glUseProgram(m_shaderProgram); | |
326 | |
327 glBindBuffer(GL_ARRAY_BUFFER, 0); | |
328 glBindTexture(GL_TEXTURE_2D, texture); | |
329 | |
330 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
331 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
332 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
333 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
334 | |
335 GLfloat afVertices[] = { | |
336 -1, -1, | |
337 1, -1, | |
338 -1, 1, | |
339 1, 1 | |
340 }; | |
341 glVertexAttribPointer(m_vertexAttr, 2, GL_FLOAT, GL_FALSE, 0, afVertices
); | |
342 | |
343 GLfloat aftextureCoordinates[] = { | |
344 0, 1, | |
345 1, 1, | |
346 0, 0, | |
347 1, 0 | |
348 }; | |
349 glVertexAttribPointer(m_textureCoordinatesAttr, 2, GL_FLOAT, GL_FALSE, 0
, aftextureCoordinates); | |
350 | |
351 glUniform1i(m_textureUniform, 0); | |
352 | |
353 glEnableVertexAttribArray(m_vertexAttr); | |
354 glEnableVertexAttribArray(m_textureCoordinatesAttr); | |
355 | |
356 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
357 | |
358 glDisableVertexAttribArray(m_vertexAttr); | |
359 glDisableVertexAttribArray(m_textureCoordinatesAttr); | |
360 | |
361 glBindTexture(GL_TEXTURE_2D, 0); | |
362 } | |
363 | |
364 private: | |
365 GraphicsSurfaceToken m_token; | |
366 EGLContext m_detachedContext; | |
367 EGLSurface m_detachedReadSurface; | |
368 EGLSurface m_detachedDrawSurface; | |
369 IntSize m_size; | |
370 EGLDisplay m_eglDisplay; | |
371 EGLContext m_eglContext; | |
372 EGLConfig m_eglConfig; | |
373 EGLSurface m_eglFrontBufferSurface; | |
374 EGLSurface m_eglBackBufferSurface; | |
375 PlatformGraphicsSurface m_initialFrontBufferShareHandle; | |
376 PlatformGraphicsSurface m_frontBufferShareHandle; | |
377 PlatformGraphicsSurface m_backBufferShareHandle; | |
378 GLuint m_frontBufferTexture; | |
379 GLint m_shaderProgram; | |
380 | |
381 GLuint m_vertexAttr; | |
382 GLuint m_textureCoordinatesAttr; | |
383 GLuint m_textureUniform; | |
384 }; | |
385 | |
386 GraphicsSurfaceToken GraphicsSurface::platformExport() | |
387 { | |
388 return m_private->token(); | |
389 } | |
390 | |
391 uint32_t GraphicsSurface::platformGetTextureID() | |
392 { | |
393 return m_private->frontBufferTextureID(); | |
394 } | |
395 | |
396 void GraphicsSurface::platformCopyToGLTexture(uint32_t target, uint32_t id, cons
t IntRect& targetRect, const IntPoint& offset) | |
397 { | |
398 // Currently not implemented. | |
399 } | |
400 | |
401 void GraphicsSurface::platformCopyFromTexture(uint32_t texture, const IntRect& s
ourceRect) | |
402 { | |
403 m_private->copyFromTexture(texture, sourceRect); | |
404 } | |
405 | |
406 void GraphicsSurface::platformPaintToTextureMapper(TextureMapper* textureMapper,
const FloatRect& targetRect, const TransformationMatrix& transform, float opaci
ty) | |
407 { | |
408 IntSize size = m_private->size(); | |
409 FloatRect rectOnContents(FloatPoint::zero(), size); | |
410 TransformationMatrix adjustedTransform = transform; | |
411 adjustedTransform.multiply(TransformationMatrix::rectToRect(rectOnContents,
targetRect)); | |
412 static_cast<TextureMapperGL*>(textureMapper)->drawTexture(platformGetTexture
ID(), 0, size, rectOnContents, adjustedTransform, opacity); | |
413 } | |
414 | |
415 uint32_t GraphicsSurface::platformFrontBuffer() const | |
416 { | |
417 if (m_private->initialFrontBufferShareHandle() == m_private->frontBufferShar
eHandle()) | |
418 return 0; | |
419 if (m_private->initialFrontBufferShareHandle() == m_private->backBufferShare
Handle()) | |
420 return 1; | |
421 return 0xFFFF; | |
422 } | |
423 | |
424 uint32_t GraphicsSurface::platformSwapBuffers() | |
425 { | |
426 m_private->swapBuffers(); | |
427 return platformFrontBuffer(); | |
428 } | |
429 | |
430 IntSize GraphicsSurface::platformSize() const | |
431 { | |
432 return m_private->size(); | |
433 } | |
434 | |
435 PassRefPtr<GraphicsSurface> GraphicsSurface::platformCreate(const IntSize& size,
Flags flags, const PlatformGraphicsContext3D shareContext) | |
436 { | |
437 // Single buffered GraphicsSurface is currently not supported. | |
438 if (flags & SupportsCopyToTexture || flags & SupportsSingleBuffered) | |
439 return PassRefPtr<GraphicsSurface>(); | |
440 | |
441 RefPtr<GraphicsSurface> surface = adoptRef(new GraphicsSurface(size, flags))
; | |
442 surface->m_private = new GraphicsSurfacePrivate(shareContext, size, flags); | |
443 | |
444 if (!surface->m_private->frontBufferShareHandle() || !surface->m_private->ba
ckBufferShareHandle()) | |
445 return PassRefPtr<GraphicsSurface>(); | |
446 | |
447 return surface; | |
448 } | |
449 | |
450 PassRefPtr<GraphicsSurface> GraphicsSurface::platformImport(const IntSize& size,
Flags flags, const GraphicsSurfaceToken& token) | |
451 { | |
452 // Single buffered GraphicsSurface is currently not supported. | |
453 if (flags & SupportsCopyToTexture || flags & SupportsSingleBuffered) | |
454 return PassRefPtr<GraphicsSurface>(); | |
455 | |
456 RefPtr<GraphicsSurface> surface = adoptRef(new GraphicsSurface(size, flags))
; | |
457 surface->m_private = new GraphicsSurfacePrivate(size, token); | |
458 | |
459 if (!surface->m_private->frontBufferShareHandle() || !surface->m_private->ba
ckBufferShareHandle()) | |
460 return PassRefPtr<GraphicsSurface>(); | |
461 | |
462 return surface; | |
463 } | |
464 | |
465 char* GraphicsSurface::platformLock(const IntRect& rect, int* outputStride, Lock
Options lockOptions) | |
466 { | |
467 // GraphicsSurface is currently only being used for WebGL, which does not re
quire this locking mechanism. | |
468 return 0; | |
469 } | |
470 | |
471 void GraphicsSurface::platformUnlock() | |
472 { | |
473 // GraphicsSurface is currently only being used for WebGL, which does not re
quire this locking mechanism. | |
474 } | |
475 | |
476 void GraphicsSurface::platformDestroy() | |
477 { | |
478 delete m_private; | |
479 m_private = 0; | |
480 } | |
481 | |
482 } | |
483 #endif | |
OLD | NEW |