| 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 |