| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gl/gl_surface.h" | 5 #include "ui/gl/gl_surface.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback.h" | 8 #include "base/callback.h" |
| 9 #include "base/location.h" | 9 #include "base/location.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 | 37 |
| 38 // A thin wrapper around GLSurfaceEGL that owns the EGLNativeWindow | 38 // A thin wrapper around GLSurfaceEGL that owns the EGLNativeWindow |
| 39 class GL_EXPORT GLSurfaceOzoneEGL : public NativeViewGLSurfaceEGL { | 39 class GL_EXPORT GLSurfaceOzoneEGL : public NativeViewGLSurfaceEGL { |
| 40 public: | 40 public: |
| 41 GLSurfaceOzoneEGL(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface, | 41 GLSurfaceOzoneEGL(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface, |
| 42 AcceleratedWidget widget); | 42 AcceleratedWidget widget); |
| 43 | 43 |
| 44 // GLSurface: | 44 // GLSurface: |
| 45 bool Initialize() override; | 45 bool Initialize() override; |
| 46 bool Resize(const gfx::Size& size) override; | 46 bool Resize(const gfx::Size& size) override; |
| 47 bool SwapBuffers() override; | 47 gfx::SwapResult SwapBuffers() override; |
| 48 bool ScheduleOverlayPlane(int z_order, | 48 bool ScheduleOverlayPlane(int z_order, |
| 49 OverlayTransform transform, | 49 OverlayTransform transform, |
| 50 GLImage* image, | 50 GLImage* image, |
| 51 const Rect& bounds_rect, | 51 const Rect& bounds_rect, |
| 52 const RectF& crop_rect) override; | 52 const RectF& crop_rect) override; |
| 53 | 53 |
| 54 private: | 54 private: |
| 55 using NativeViewGLSurfaceEGL::Initialize; | 55 using NativeViewGLSurfaceEGL::Initialize; |
| 56 | 56 |
| 57 ~GLSurfaceOzoneEGL() override; | 57 ~GLSurfaceOzoneEGL() override; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 80 bool GLSurfaceOzoneEGL::Resize(const gfx::Size& size) { | 80 bool GLSurfaceOzoneEGL::Resize(const gfx::Size& size) { |
| 81 if (!ozone_surface_->ResizeNativeWindow(size)) { | 81 if (!ozone_surface_->ResizeNativeWindow(size)) { |
| 82 if (!ReinitializeNativeSurface() || | 82 if (!ReinitializeNativeSurface() || |
| 83 !ozone_surface_->ResizeNativeWindow(size)) | 83 !ozone_surface_->ResizeNativeWindow(size)) |
| 84 return false; | 84 return false; |
| 85 } | 85 } |
| 86 | 86 |
| 87 return NativeViewGLSurfaceEGL::Resize(size); | 87 return NativeViewGLSurfaceEGL::Resize(size); |
| 88 } | 88 } |
| 89 | 89 |
| 90 bool GLSurfaceOzoneEGL::SwapBuffers() { | 90 gfx::SwapResult GLSurfaceOzoneEGL::SwapBuffers() { |
| 91 if (!NativeViewGLSurfaceEGL::SwapBuffers()) | 91 gfx::SwapResult result = NativeViewGLSurfaceEGL::SwapBuffers(); |
| 92 return false; | 92 if (result != gfx::SwapResult::SWAP_ACK) |
| 93 return result; |
| 93 | 94 |
| 94 return ozone_surface_->OnSwapBuffers(); | 95 return ozone_surface_->OnSwapBuffers() ? gfx::SwapResult::SWAP_ACK |
| 96 : gfx::SwapResult::SWAP_FAILED; |
| 95 } | 97 } |
| 96 | 98 |
| 97 bool GLSurfaceOzoneEGL::ScheduleOverlayPlane(int z_order, | 99 bool GLSurfaceOzoneEGL::ScheduleOverlayPlane(int z_order, |
| 98 OverlayTransform transform, | 100 OverlayTransform transform, |
| 99 GLImage* image, | 101 GLImage* image, |
| 100 const Rect& bounds_rect, | 102 const Rect& bounds_rect, |
| 101 const RectF& crop_rect) { | 103 const RectF& crop_rect) { |
| 102 return image->ScheduleOverlayPlane(widget_, z_order, transform, bounds_rect, | 104 return image->ScheduleOverlayPlane(widget_, z_order, transform, bounds_rect, |
| 103 crop_rect); | 105 crop_rect); |
| 104 } | 106 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 134 } | 136 } |
| 135 | 137 |
| 136 class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { | 138 class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { |
| 137 public: | 139 public: |
| 138 GLSurfaceOzoneSurfaceless(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface, | 140 GLSurfaceOzoneSurfaceless(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface, |
| 139 AcceleratedWidget widget); | 141 AcceleratedWidget widget); |
| 140 | 142 |
| 141 // GLSurface: | 143 // GLSurface: |
| 142 bool Initialize() override; | 144 bool Initialize() override; |
| 143 bool Resize(const gfx::Size& size) override; | 145 bool Resize(const gfx::Size& size) override; |
| 144 bool SwapBuffers() override; | 146 gfx::SwapResult SwapBuffers() override; |
| 145 bool ScheduleOverlayPlane(int z_order, | 147 bool ScheduleOverlayPlane(int z_order, |
| 146 OverlayTransform transform, | 148 OverlayTransform transform, |
| 147 GLImage* image, | 149 GLImage* image, |
| 148 const Rect& bounds_rect, | 150 const Rect& bounds_rect, |
| 149 const RectF& crop_rect) override; | 151 const RectF& crop_rect) override; |
| 150 bool IsOffscreen() override; | 152 bool IsOffscreen() override; |
| 151 VSyncProvider* GetVSyncProvider() override; | 153 VSyncProvider* GetVSyncProvider() override; |
| 152 bool SupportsPostSubBuffer() override; | 154 bool SupportsPostSubBuffer() override; |
| 153 bool PostSubBuffer(int x, int y, int width, int height) override; | 155 gfx::SwapResult PostSubBuffer(int x, int y, int width, int height) override; |
| 154 bool SwapBuffersAsync(const SwapCompletionCallback& callback) override; | 156 bool SwapBuffersAsync(const SwapCompletionCallback& callback) override; |
| 155 bool PostSubBufferAsync(int x, | 157 bool PostSubBufferAsync(int x, |
| 156 int y, | 158 int y, |
| 157 int width, | 159 int width, |
| 158 int height, | 160 int height, |
| 159 const SwapCompletionCallback& callback) override; | 161 const SwapCompletionCallback& callback) override; |
| 160 | 162 |
| 161 protected: | 163 protected: |
| 162 struct Overlay { | 164 struct Overlay { |
| 163 Overlay(int z_order, | 165 Overlay(int z_order, |
| (...skipping 21 matching lines...) Expand all Loading... |
| 185 SwapCompletionCallback callback; | 187 SwapCompletionCallback callback; |
| 186 }; | 188 }; |
| 187 | 189 |
| 188 ~GLSurfaceOzoneSurfaceless() override; | 190 ~GLSurfaceOzoneSurfaceless() override; |
| 189 | 191 |
| 190 void SubmitFrame(); | 192 void SubmitFrame(); |
| 191 | 193 |
| 192 EGLSyncKHR InsertFence(); | 194 EGLSyncKHR InsertFence(); |
| 193 void FenceRetired(EGLSyncKHR fence, PendingFrame* frame); | 195 void FenceRetired(EGLSyncKHR fence, PendingFrame* frame); |
| 194 | 196 |
| 195 void SwapCompleted(const SwapCompletionCallback& callback); | 197 void SwapCompleted(const SwapCompletionCallback& callback, |
| 198 gfx::SwapResult result); |
| 196 | 199 |
| 197 // The native surface. Deleting this is allowed to free the EGLNativeWindow. | 200 // The native surface. Deleting this is allowed to free the EGLNativeWindow. |
| 198 scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface_; | 201 scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface_; |
| 199 AcceleratedWidget widget_; | 202 AcceleratedWidget widget_; |
| 200 scoped_ptr<VSyncProvider> vsync_provider_; | 203 scoped_ptr<VSyncProvider> vsync_provider_; |
| 201 ScopedVector<PendingFrame> unsubmitted_frames_; | 204 ScopedVector<PendingFrame> unsubmitted_frames_; |
| 202 bool has_implicit_external_sync_; | 205 bool has_implicit_external_sync_; |
| 203 bool last_swap_buffers_result_; | 206 bool last_swap_buffers_result_; |
| 204 bool swap_buffers_pending_; | 207 bool swap_buffers_pending_; |
| 205 | 208 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 if (!vsync_provider_) | 261 if (!vsync_provider_) |
| 259 return false; | 262 return false; |
| 260 return true; | 263 return true; |
| 261 } | 264 } |
| 262 bool GLSurfaceOzoneSurfaceless::Resize(const gfx::Size& size) { | 265 bool GLSurfaceOzoneSurfaceless::Resize(const gfx::Size& size) { |
| 263 if (!ozone_surface_->ResizeNativeWindow(size)) | 266 if (!ozone_surface_->ResizeNativeWindow(size)) |
| 264 return false; | 267 return false; |
| 265 | 268 |
| 266 return SurfacelessEGL::Resize(size); | 269 return SurfacelessEGL::Resize(size); |
| 267 } | 270 } |
| 268 bool GLSurfaceOzoneSurfaceless::SwapBuffers() { | 271 gfx::SwapResult GLSurfaceOzoneSurfaceless::SwapBuffers() { |
| 269 glFlush(); | 272 glFlush(); |
| 270 // TODO: the following should be replaced by a per surface flush as it gets | 273 // TODO: the following should be replaced by a per surface flush as it gets |
| 271 // implemented in GL drivers. | 274 // implemented in GL drivers. |
| 272 if (has_implicit_external_sync_) { | 275 if (has_implicit_external_sync_) { |
| 273 EGLSyncKHR fence = InsertFence(); | 276 EGLSyncKHR fence = InsertFence(); |
| 274 if (!fence) | 277 if (!fence) |
| 275 return false; | 278 return SwapResult::SWAP_FAILED; |
| 276 | 279 |
| 277 EGLDisplay display = GetDisplay(); | 280 EGLDisplay display = GetDisplay(); |
| 278 WaitForFence(display, fence); | 281 WaitForFence(display, fence); |
| 279 eglDestroySyncKHR(display, fence); | 282 eglDestroySyncKHR(display, fence); |
| 280 } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) { | 283 } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) { |
| 281 glFinish(); | 284 glFinish(); |
| 282 } | 285 } |
| 283 | 286 |
| 284 unsubmitted_frames_.back()->ScheduleOverlayPlanes(widget_); | 287 unsubmitted_frames_.back()->ScheduleOverlayPlanes(widget_); |
| 285 unsubmitted_frames_.back()->overlays.clear(); | 288 unsubmitted_frames_.back()->overlays.clear(); |
| 286 | 289 |
| 287 return ozone_surface_->OnSwapBuffers(); | 290 return ozone_surface_->OnSwapBuffers() ? gfx::SwapResult::SWAP_ACK |
| 291 : gfx::SwapResult::SWAP_FAILED; |
| 288 } | 292 } |
| 289 bool GLSurfaceOzoneSurfaceless::ScheduleOverlayPlane(int z_order, | 293 bool GLSurfaceOzoneSurfaceless::ScheduleOverlayPlane(int z_order, |
| 290 OverlayTransform transform, | 294 OverlayTransform transform, |
| 291 GLImage* image, | 295 GLImage* image, |
| 292 const Rect& bounds_rect, | 296 const Rect& bounds_rect, |
| 293 const RectF& crop_rect) { | 297 const RectF& crop_rect) { |
| 294 unsubmitted_frames_.back()->overlays.push_back( | 298 unsubmitted_frames_.back()->overlays.push_back( |
| 295 Overlay(z_order, transform, image, bounds_rect, crop_rect)); | 299 Overlay(z_order, transform, image, bounds_rect, crop_rect)); |
| 296 return true; | 300 return true; |
| 297 } | 301 } |
| 298 bool GLSurfaceOzoneSurfaceless::IsOffscreen() { | 302 bool GLSurfaceOzoneSurfaceless::IsOffscreen() { |
| 299 return false; | 303 return false; |
| 300 } | 304 } |
| 301 VSyncProvider* GLSurfaceOzoneSurfaceless::GetVSyncProvider() { | 305 VSyncProvider* GLSurfaceOzoneSurfaceless::GetVSyncProvider() { |
| 302 return vsync_provider_.get(); | 306 return vsync_provider_.get(); |
| 303 } | 307 } |
| 304 bool GLSurfaceOzoneSurfaceless::SupportsPostSubBuffer() { | 308 bool GLSurfaceOzoneSurfaceless::SupportsPostSubBuffer() { |
| 305 return true; | 309 return true; |
| 306 } | 310 } |
| 307 bool GLSurfaceOzoneSurfaceless::PostSubBuffer(int x, | 311 gfx::SwapResult GLSurfaceOzoneSurfaceless::PostSubBuffer(int x, |
| 308 int y, | 312 int y, |
| 309 int width, | 313 int width, |
| 310 int height) { | 314 int height) { |
| 311 // The actual sub buffer handling is handled at higher layers. | 315 // The actual sub buffer handling is handled at higher layers. |
| 312 SwapBuffers(); | 316 SwapBuffers(); |
| 313 return true; | 317 return gfx::SwapResult::SWAP_ACK; |
| 314 } | 318 } |
| 315 bool GLSurfaceOzoneSurfaceless::SwapBuffersAsync( | 319 bool GLSurfaceOzoneSurfaceless::SwapBuffersAsync( |
| 316 const SwapCompletionCallback& callback) { | 320 const SwapCompletionCallback& callback) { |
| 317 // If last swap failed, don't try to schedule new ones. | 321 // If last swap failed, don't try to schedule new ones. |
| 318 if (!last_swap_buffers_result_) | 322 if (!last_swap_buffers_result_) |
| 319 return false; | 323 return false; |
| 320 | 324 |
| 321 glFlush(); | 325 glFlush(); |
| 322 | 326 |
| 323 base::Closure surface_swap_callback = | 327 SwapCompletionCallback surface_swap_callback = |
| 324 base::Bind(&GLSurfaceOzoneSurfaceless::SwapCompleted, | 328 base::Bind(&GLSurfaceOzoneSurfaceless::SwapCompleted, |
| 325 weak_factory_.GetWeakPtr(), callback); | 329 weak_factory_.GetWeakPtr(), callback); |
| 326 | 330 |
| 327 PendingFrame* frame = unsubmitted_frames_.back(); | 331 PendingFrame* frame = unsubmitted_frames_.back(); |
| 328 frame->callback = surface_swap_callback; | 332 frame->callback = surface_swap_callback; |
| 329 unsubmitted_frames_.push_back(new PendingFrame()); | 333 unsubmitted_frames_.push_back(new PendingFrame()); |
| 330 | 334 |
| 331 // TODO: the following should be replaced by a per surface flush as it gets | 335 // TODO: the following should be replaced by a per surface flush as it gets |
| 332 // implemented in GL drivers. | 336 // implemented in GL drivers. |
| 333 if (has_implicit_external_sync_) { | 337 if (has_implicit_external_sync_) { |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 } | 392 } |
| 389 | 393 |
| 390 void GLSurfaceOzoneSurfaceless::FenceRetired(EGLSyncKHR fence, | 394 void GLSurfaceOzoneSurfaceless::FenceRetired(EGLSyncKHR fence, |
| 391 PendingFrame* frame) { | 395 PendingFrame* frame) { |
| 392 eglDestroySyncKHR(GetDisplay(), fence); | 396 eglDestroySyncKHR(GetDisplay(), fence); |
| 393 frame->ready = true; | 397 frame->ready = true; |
| 394 SubmitFrame(); | 398 SubmitFrame(); |
| 395 } | 399 } |
| 396 | 400 |
| 397 void GLSurfaceOzoneSurfaceless::SwapCompleted( | 401 void GLSurfaceOzoneSurfaceless::SwapCompleted( |
| 398 const SwapCompletionCallback& callback) { | 402 const SwapCompletionCallback& callback, |
| 399 callback.Run(); | 403 gfx::SwapResult result) { |
| 404 callback.Run(result); |
| 400 swap_buffers_pending_ = false; | 405 swap_buffers_pending_ = false; |
| 401 | 406 |
| 402 SubmitFrame(); | 407 SubmitFrame(); |
| 403 } | 408 } |
| 404 | 409 |
| 405 // This provides surface-like semantics implemented through surfaceless. | 410 // This provides surface-like semantics implemented through surfaceless. |
| 406 // A framebuffer is bound automatically. | 411 // A framebuffer is bound automatically. |
| 407 class GL_EXPORT GLSurfaceOzoneSurfacelessSurfaceImpl | 412 class GL_EXPORT GLSurfaceOzoneSurfacelessSurfaceImpl |
| 408 : public GLSurfaceOzoneSurfaceless { | 413 : public GLSurfaceOzoneSurfaceless { |
| 409 public: | 414 public: |
| 410 GLSurfaceOzoneSurfacelessSurfaceImpl( | 415 GLSurfaceOzoneSurfacelessSurfaceImpl( |
| 411 scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface, | 416 scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface, |
| 412 AcceleratedWidget widget); | 417 AcceleratedWidget widget); |
| 413 | 418 |
| 414 // GLSurface: | 419 // GLSurface: |
| 415 unsigned int GetBackingFrameBufferObject() override; | 420 unsigned int GetBackingFrameBufferObject() override; |
| 416 bool OnMakeCurrent(GLContext* context) override; | 421 bool OnMakeCurrent(GLContext* context) override; |
| 417 bool Resize(const gfx::Size& size) override; | 422 bool Resize(const gfx::Size& size) override; |
| 418 bool SupportsPostSubBuffer() override; | 423 bool SupportsPostSubBuffer() override; |
| 419 bool SwapBuffers() override; | 424 gfx::SwapResult SwapBuffers() override; |
| 420 bool SwapBuffersAsync(const SwapCompletionCallback& callback) override; | 425 bool SwapBuffersAsync(const SwapCompletionCallback& callback) override; |
| 421 void Destroy() override; | 426 void Destroy() override; |
| 422 | 427 |
| 423 private: | 428 private: |
| 424 class SurfaceImage : public GLImageLinuxDMABuffer { | 429 class SurfaceImage : public GLImageLinuxDMABuffer { |
| 425 public: | 430 public: |
| 426 SurfaceImage(const gfx::Size& size, unsigned internalformat); | 431 SurfaceImage(const gfx::Size& size, unsigned internalformat); |
| 427 | 432 |
| 428 bool Initialize(scoped_refptr<ui::NativePixmap> pixmap, | 433 bool Initialize(scoped_refptr<ui::NativePixmap> pixmap, |
| 429 gfx::GpuMemoryBuffer::Format format); | 434 gfx::GpuMemoryBuffer::Format format); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 bool GLSurfaceOzoneSurfacelessSurfaceImpl::Resize(const gfx::Size& size) { | 517 bool GLSurfaceOzoneSurfacelessSurfaceImpl::Resize(const gfx::Size& size) { |
| 513 if (size == GetSize()) | 518 if (size == GetSize()) |
| 514 return true; | 519 return true; |
| 515 return GLSurfaceOzoneSurfaceless::Resize(size) && CreatePixmaps(); | 520 return GLSurfaceOzoneSurfaceless::Resize(size) && CreatePixmaps(); |
| 516 } | 521 } |
| 517 | 522 |
| 518 bool GLSurfaceOzoneSurfacelessSurfaceImpl::SupportsPostSubBuffer() { | 523 bool GLSurfaceOzoneSurfacelessSurfaceImpl::SupportsPostSubBuffer() { |
| 519 return false; | 524 return false; |
| 520 } | 525 } |
| 521 | 526 |
| 522 bool GLSurfaceOzoneSurfacelessSurfaceImpl::SwapBuffers() { | 527 gfx::SwapResult GLSurfaceOzoneSurfacelessSurfaceImpl::SwapBuffers() { |
| 523 if (!images_[current_surface_]->ScheduleOverlayPlane( | 528 if (!images_[current_surface_]->ScheduleOverlayPlane( |
| 524 widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE, | 529 widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE, |
| 525 gfx::Rect(GetSize()), gfx::RectF(1, 1))) | 530 gfx::Rect(GetSize()), gfx::RectF(1, 1))) |
| 526 return false; | 531 return gfx::SwapResult::SWAP_FAILED; |
| 527 if (!GLSurfaceOzoneSurfaceless::SwapBuffers()) | 532 gfx::SwapResult result = GLSurfaceOzoneSurfaceless::SwapBuffers(); |
| 528 return false; | 533 if (result != gfx::SwapResult::SWAP_ACK) |
| 534 return result; |
| 529 current_surface_ ^= 1; | 535 current_surface_ ^= 1; |
| 530 BindFramebuffer(); | 536 BindFramebuffer(); |
| 531 return true; | 537 return gfx::SwapResult::SWAP_ACK; |
| 532 } | 538 } |
| 533 | 539 |
| 534 bool GLSurfaceOzoneSurfacelessSurfaceImpl::SwapBuffersAsync( | 540 bool GLSurfaceOzoneSurfacelessSurfaceImpl::SwapBuffersAsync( |
| 535 const SwapCompletionCallback& callback) { | 541 const SwapCompletionCallback& callback) { |
| 536 if (!images_[current_surface_]->ScheduleOverlayPlane( | 542 if (!images_[current_surface_]->ScheduleOverlayPlane( |
| 537 widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE, | 543 widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE, |
| 538 gfx::Rect(GetSize()), gfx::RectF(1, 1))) | 544 gfx::Rect(GetSize()), gfx::RectF(1, 1))) |
| 539 return false; | 545 return false; |
| 540 if (!GLSurfaceOzoneSurfaceless::SwapBuffersAsync(callback)) | 546 if (!GLSurfaceOzoneSurfaceless::SwapBuffersAsync(callback)) |
| 541 return false; | 547 return false; |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 709 NOTREACHED(); | 715 NOTREACHED(); |
| 710 return NULL; | 716 return NULL; |
| 711 } | 717 } |
| 712 } | 718 } |
| 713 | 719 |
| 714 EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() { | 720 EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() { |
| 715 return ui::SurfaceFactoryOzone::GetInstance()->GetNativeDisplay(); | 721 return ui::SurfaceFactoryOzone::GetInstance()->GetNativeDisplay(); |
| 716 } | 722 } |
| 717 | 723 |
| 718 } // namespace gfx | 724 } // namespace gfx |
| OLD | NEW |