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