| OLD | NEW |
| (Empty) |
| 1 // Copyright 2010 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "cc/gl_renderer.h" | |
| 6 | |
| 7 #include <set> | |
| 8 #include <string> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/debug/trace_event.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/string_util.h" | |
| 14 #include "base/strings/string_split.h" | |
| 15 #include "build/build_config.h" | |
| 16 #include "cc/base/math_util.h" | |
| 17 #include "cc/compositor_frame.h" | |
| 18 #include "cc/compositor_frame_metadata.h" | |
| 19 #include "cc/context_provider.h" | |
| 20 #include "cc/damage_tracker.h" | |
| 21 #include "cc/geometry_binding.h" | |
| 22 #include "cc/gl_frame_data.h" | |
| 23 #include "cc/layer_quad.h" | |
| 24 #include "cc/output_surface.h" | |
| 25 #include "cc/priority_calculator.h" | |
| 26 #include "cc/proxy.h" | |
| 27 #include "cc/render_pass.h" | |
| 28 #include "cc/render_surface_filters.h" | |
| 29 #include "cc/scoped_resource.h" | |
| 30 #include "cc/single_thread_proxy.h" | |
| 31 #include "cc/stream_video_draw_quad.h" | |
| 32 #include "cc/texture_draw_quad.h" | |
| 33 #include "cc/video_layer_impl.h" | |
| 34 #include "gpu/GLES2/gl2extchromium.h" | |
| 35 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3
D.h" | |
| 36 #include "third_party/khronos/GLES2/gl2.h" | |
| 37 #include "third_party/khronos/GLES2/gl2ext.h" | |
| 38 #include "third_party/skia/include/core/SkBitmap.h" | |
| 39 #include "third_party/skia/include/core/SkColor.h" | |
| 40 #include "third_party/skia/include/gpu/GrContext.h" | |
| 41 #include "third_party/skia/include/gpu/GrTexture.h" | |
| 42 #include "third_party/skia/include/gpu/SkGpuDevice.h" | |
| 43 #include "third_party/skia/include/gpu/SkGrTexturePixelRef.h" | |
| 44 #include "ui/gfx/quad_f.h" | |
| 45 #include "ui/gfx/rect_conversions.h" | |
| 46 | |
| 47 using WebKit::WebGraphicsContext3D; | |
| 48 using WebKit::WebGraphicsMemoryAllocation; | |
| 49 | |
| 50 namespace cc { | |
| 51 | |
| 52 namespace { | |
| 53 | |
| 54 // TODO(epenner): This should probably be moved to output surface. | |
| 55 // | |
| 56 // This implements a simple fence based on client side swaps. | |
| 57 // This is to isolate the ResourceProvider from 'frames' which | |
| 58 // it shouldn't need to care about, while still allowing us to | |
| 59 // enforce good texture recycling behavior strictly throughout | |
| 60 // the compositor (don't recycle a texture while it's in use). | |
| 61 class SimpleSwapFence : public ResourceProvider::Fence { | |
| 62 public: | |
| 63 SimpleSwapFence() : has_passed_(false) {} | |
| 64 virtual bool HasPassed() OVERRIDE { return has_passed_; } | |
| 65 void SetHasPassed() { has_passed_ = true; } | |
| 66 private: | |
| 67 virtual ~SimpleSwapFence() {} | |
| 68 bool has_passed_; | |
| 69 }; | |
| 70 | |
| 71 bool NeedsIOSurfaceReadbackWorkaround() { | |
| 72 #if defined(OS_MACOSX) | |
| 73 return true; | |
| 74 #else | |
| 75 return false; | |
| 76 #endif | |
| 77 } | |
| 78 | |
| 79 } // anonymous namespace | |
| 80 | |
| 81 scoped_ptr<GLRenderer> GLRenderer::Create(RendererClient* client, | |
| 82 OutputSurface* output_surface, | |
| 83 ResourceProvider* resource_provider) { | |
| 84 scoped_ptr<GLRenderer> renderer( | |
| 85 new GLRenderer(client, output_surface, resource_provider)); | |
| 86 if (!renderer->Initialize()) | |
| 87 return scoped_ptr<GLRenderer>(); | |
| 88 | |
| 89 return renderer.Pass(); | |
| 90 } | |
| 91 | |
| 92 GLRenderer::GLRenderer(RendererClient* client, | |
| 93 OutputSurface* output_surface, | |
| 94 ResourceProvider* resource_provider) | |
| 95 : DirectRenderer(client, resource_provider), | |
| 96 offscreen_framebuffer_id_(0), | |
| 97 shared_geometry_quad_(gfx::RectF(-0.5f, -0.5f, 1.0f, 1.0f)), | |
| 98 output_surface_(output_surface), | |
| 99 context_(output_surface->context3d()), | |
| 100 is_viewport_changed_(false), | |
| 101 is_backbuffer_discarded_(false), | |
| 102 discard_backbuffer_when_not_visible_(false), | |
| 103 is_using_bind_uniform_(false), | |
| 104 visible_(true), | |
| 105 is_scissor_enabled_(false) { | |
| 106 DCHECK(context_); | |
| 107 } | |
| 108 | |
| 109 bool GLRenderer::Initialize() { | |
| 110 if (!context_->makeContextCurrent()) | |
| 111 return false; | |
| 112 | |
| 113 context_->setContextLostCallback(this); | |
| 114 context_->pushGroupMarkerEXT("CompositorContext"); | |
| 115 | |
| 116 std::string extensions_string = | |
| 117 UTF16ToASCII(context_->getString(GL_EXTENSIONS)); | |
| 118 std::vector<std::string> extensions_list; | |
| 119 base::SplitString(extensions_string, ' ', &extensions_list); | |
| 120 std::set<std::string> extensions(extensions_list.begin(), | |
| 121 extensions_list.end()); | |
| 122 | |
| 123 if (Settings().acceleratePainting && | |
| 124 extensions.count("GL_EXT_texture_format_BGRA8888") && | |
| 125 extensions.count("GL_EXT_read_format_bgra")) | |
| 126 capabilities_.using_accelerated_painting = true; | |
| 127 else | |
| 128 capabilities_.using_accelerated_painting = false; | |
| 129 | |
| 130 capabilities_.using_partial_swap = | |
| 131 Settings().partialSwapEnabled && | |
| 132 extensions.count("GL_CHROMIUM_post_sub_buffer"); | |
| 133 | |
| 134 // Use the swapBuffers callback only with the threaded proxy. | |
| 135 if (client_->HasImplThread()) | |
| 136 capabilities_.using_swap_complete_callback = | |
| 137 extensions.count("GL_CHROMIUM_swapbuffers_complete_callback"); | |
| 138 if (capabilities_.using_swap_complete_callback) | |
| 139 context_->setSwapBuffersCompleteCallbackCHROMIUM(this); | |
| 140 | |
| 141 capabilities_.using_set_visibility = | |
| 142 extensions.count("GL_CHROMIUM_set_visibility"); | |
| 143 | |
| 144 if (extensions.count("GL_CHROMIUM_iosurface")) | |
| 145 DCHECK(extensions.count("GL_ARB_texture_rectangle")); | |
| 146 | |
| 147 capabilities_.using_gpu_memory_manager = | |
| 148 extensions.count("GL_CHROMIUM_gpu_memory_manager") && | |
| 149 Settings().useMemoryManagement; | |
| 150 if (capabilities_.using_gpu_memory_manager) | |
| 151 context_->setMemoryAllocationChangedCallbackCHROMIUM(this); | |
| 152 | |
| 153 capabilities_.using_egl_image = extensions.count("GL_OES_EGL_image_external"); | |
| 154 | |
| 155 capabilities_.max_texture_size = resource_provider_->max_texture_size(); | |
| 156 capabilities_.best_texture_format = resource_provider_->best_texture_format(); | |
| 157 | |
| 158 // The updater can access textures while the GLRenderer is using them. | |
| 159 capabilities_.allow_partial_texture_updates = true; | |
| 160 | |
| 161 // Check for texture fast paths. Currently we always use MO8 textures, | |
| 162 // so we only need to avoid POT textures if we have an NPOT fast-path. | |
| 163 capabilities_.avoid_pow2_textures = | |
| 164 extensions.count("GL_CHROMIUM_fast_NPOT_MO8_textures"); | |
| 165 | |
| 166 capabilities_.using_offscreen_context3d = true; | |
| 167 | |
| 168 is_using_bind_uniform_ = | |
| 169 extensions.count("GL_CHROMIUM_bind_uniform_location"); | |
| 170 | |
| 171 // Make sure scissoring starts as disabled. | |
| 172 GLC(context_, context_->disable(GL_SCISSOR_TEST)); | |
| 173 DCHECK(!is_scissor_enabled_); | |
| 174 | |
| 175 if (!InitializeSharedObjects()) | |
| 176 return false; | |
| 177 | |
| 178 // Make sure the viewport and context gets initialized, even if it is to zero. | |
| 179 ViewportChanged(); | |
| 180 return true; | |
| 181 } | |
| 182 | |
| 183 GLRenderer::~GLRenderer() { | |
| 184 context_->setSwapBuffersCompleteCallbackCHROMIUM(NULL); | |
| 185 context_->setMemoryAllocationChangedCallbackCHROMIUM(NULL); | |
| 186 context_->setContextLostCallback(NULL); | |
| 187 CleanupSharedObjects(); | |
| 188 } | |
| 189 | |
| 190 const RendererCapabilities& GLRenderer::Capabilities() const { | |
| 191 return capabilities_; | |
| 192 } | |
| 193 | |
| 194 WebGraphicsContext3D* GLRenderer::Context() { return context_; } | |
| 195 | |
| 196 void GLRenderer::DebugGLCall(WebGraphicsContext3D* context, | |
| 197 const char* command, | |
| 198 const char* file, | |
| 199 int line) { | |
| 200 unsigned long error = context->getError(); | |
| 201 if (error != GL_NO_ERROR) | |
| 202 LOG(ERROR) << "GL command failed: File: " << file << "\n\tLine " << line | |
| 203 << "\n\tcommand: " << command << ", error " | |
| 204 << static_cast<int>(error) << "\n"; | |
| 205 } | |
| 206 | |
| 207 void GLRenderer::SetVisible(bool visible) { | |
| 208 if (visible_ == visible) | |
| 209 return; | |
| 210 visible_ = visible; | |
| 211 | |
| 212 EnforceMemoryPolicy(); | |
| 213 | |
| 214 // TODO: Replace setVisibilityCHROMIUM with an extension to explicitly manage | |
| 215 // front/backbuffers | |
| 216 // crbug.com/116049 | |
| 217 if (capabilities_.using_set_visibility) | |
| 218 context_->setVisibilityCHROMIUM(visible); | |
| 219 } | |
| 220 | |
| 221 void GLRenderer::SendManagedMemoryStats(size_t bytes_visible, | |
| 222 size_t bytes_visible_and_nearby, | |
| 223 size_t bytes_allocated) { | |
| 224 WebKit::WebGraphicsManagedMemoryStats stats; | |
| 225 stats.bytesVisible = bytes_visible; | |
| 226 stats.bytesVisibleAndNearby = bytes_visible_and_nearby; | |
| 227 stats.bytesAllocated = bytes_allocated; | |
| 228 stats.backbufferRequested = !is_backbuffer_discarded_; | |
| 229 context_->sendManagedMemoryStatsCHROMIUM(&stats); | |
| 230 } | |
| 231 | |
| 232 void GLRenderer::ReleaseRenderPassTextures() { render_pass_textures_.clear(); } | |
| 233 | |
| 234 void GLRenderer::ViewportChanged() { is_viewport_changed_ = true; } | |
| 235 | |
| 236 void GLRenderer::ClearFramebuffer(DrawingFrame& frame) { | |
| 237 // On DEBUG builds, opaque render passes are cleared to blue to easily see | |
| 238 // regions that were not drawn on the screen. | |
| 239 if (frame.current_render_pass->has_transparent_background) | |
| 240 GLC(context_, context_->clearColor(0, 0, 0, 0)); | |
| 241 else | |
| 242 GLC(context_, context_->clearColor(0, 0, 1, 1)); | |
| 243 | |
| 244 #ifdef NDEBUG | |
| 245 if (frame.current_render_pass->has_transparent_background) | |
| 246 #endif | |
| 247 context_->clear(GL_COLOR_BUFFER_BIT); | |
| 248 } | |
| 249 | |
| 250 void GLRenderer::BeginDrawingFrame(DrawingFrame& frame) { | |
| 251 // FIXME: Remove this once backbuffer is automatically recreated on first use | |
| 252 EnsureBackbuffer(); | |
| 253 | |
| 254 if (ViewportSize().IsEmpty()) | |
| 255 return; | |
| 256 | |
| 257 TRACE_EVENT0("cc", "GLRenderer::drawLayers"); | |
| 258 if (is_viewport_changed_) { | |
| 259 // Only reshape when we know we are going to draw. Otherwise, the reshape | |
| 260 // can leave the window at the wrong size if we never draw and the proper | |
| 261 // viewport size is never set. | |
| 262 is_viewport_changed_ = false; | |
| 263 output_surface_->Reshape(gfx::Size(ViewportWidth(), ViewportHeight())); | |
| 264 } | |
| 265 | |
| 266 MakeContextCurrent(); | |
| 267 // Bind the common vertex attributes used for drawing all the layers. | |
| 268 shared_geometry_->PrepareForDraw(); | |
| 269 | |
| 270 GLC(context_, context_->disable(GL_DEPTH_TEST)); | |
| 271 GLC(context_, context_->disable(GL_CULL_FACE)); | |
| 272 GLC(context_, context_->colorMask(true, true, true, true)); | |
| 273 GLC(context_, context_->enable(GL_BLEND)); | |
| 274 blend_shadow_ = true; | |
| 275 GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); | |
| 276 GLC(Context(), Context()->activeTexture(GL_TEXTURE0)); | |
| 277 program_shadow_ = 0; | |
| 278 } | |
| 279 | |
| 280 void GLRenderer::DoNoOp() { | |
| 281 GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, 0)); | |
| 282 GLC(context_, context_->flush()); | |
| 283 } | |
| 284 | |
| 285 void GLRenderer::DoDrawQuad(DrawingFrame& frame, const DrawQuad* quad) { | |
| 286 DCHECK(quad->rect.Contains(quad->visible_rect)); | |
| 287 if (quad->material != DrawQuad::TEXTURE_CONTENT) { | |
| 288 FlushTextureQuadCache(); | |
| 289 } | |
| 290 | |
| 291 switch (quad->material) { | |
| 292 case DrawQuad::INVALID: | |
| 293 NOTREACHED(); | |
| 294 break; | |
| 295 case DrawQuad::CHECKERBOARD: | |
| 296 DrawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad)); | |
| 297 break; | |
| 298 case DrawQuad::DEBUG_BORDER: | |
| 299 DrawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad)); | |
| 300 break; | |
| 301 case DrawQuad::IO_SURFACE_CONTENT: | |
| 302 DrawIOSurfaceQuad(frame, IOSurfaceDrawQuad::MaterialCast(quad)); | |
| 303 break; | |
| 304 case DrawQuad::RENDER_PASS: | |
| 305 DrawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad)); | |
| 306 break; | |
| 307 case DrawQuad::SOLID_COLOR: | |
| 308 DrawSolidColorQuad(frame, SolidColorDrawQuad::MaterialCast(quad)); | |
| 309 break; | |
| 310 case DrawQuad::STREAM_VIDEO_CONTENT: | |
| 311 DrawStreamVideoQuad(frame, StreamVideoDrawQuad::MaterialCast(quad)); | |
| 312 break; | |
| 313 case DrawQuad::TEXTURE_CONTENT: | |
| 314 EnqueueTextureQuad(frame, TextureDrawQuad::MaterialCast(quad)); | |
| 315 break; | |
| 316 case DrawQuad::TILED_CONTENT: | |
| 317 DrawTileQuad(frame, TileDrawQuad::MaterialCast(quad)); | |
| 318 break; | |
| 319 case DrawQuad::YUV_VIDEO_CONTENT: | |
| 320 DrawYUVVideoQuad(frame, YUVVideoDrawQuad::MaterialCast(quad)); | |
| 321 break; | |
| 322 } | |
| 323 } | |
| 324 | |
| 325 void GLRenderer::DrawCheckerboardQuad(const DrawingFrame& frame, | |
| 326 const CheckerboardDrawQuad* quad) { | |
| 327 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
| 328 | |
| 329 const TileCheckerboardProgram* program = GetTileCheckerboardProgram(); | |
| 330 DCHECK(program && (program->initialized() || IsContextLost())); | |
| 331 SetUseProgram(program->program()); | |
| 332 | |
| 333 SkColor color = quad->color; | |
| 334 GLC(Context(), | |
| 335 Context()->uniform4f(program->fragment_shader().colorLocation(), | |
| 336 SkColorGetR(color) * (1.0f / 255.0f), | |
| 337 SkColorGetG(color) * (1.0f / 255.0f), | |
| 338 SkColorGetB(color) * (1.0f / 255.0f), | |
| 339 1)); | |
| 340 | |
| 341 const int checkerboard_width = 16; | |
| 342 float frequency = 1.0f / checkerboard_width; | |
| 343 | |
| 344 gfx::Rect tile_rect = quad->rect; | |
| 345 float tex_offset_x = tile_rect.x() % checkerboard_width; | |
| 346 float tex_offset_y = tile_rect.y() % checkerboard_width; | |
| 347 float tex_scale_x = tile_rect.width(); | |
| 348 float tex_scale_y = tile_rect.height(); | |
| 349 GLC(Context(), | |
| 350 Context()->uniform4f(program->fragment_shader().texTransformLocation(), | |
| 351 tex_offset_x, | |
| 352 tex_offset_y, | |
| 353 tex_scale_x, | |
| 354 tex_scale_y)); | |
| 355 | |
| 356 GLC(Context(), | |
| 357 Context()->uniform1f(program->fragment_shader().frequencyLocation(), | |
| 358 frequency)); | |
| 359 | |
| 360 SetShaderOpacity(quad->opacity(), program->fragment_shader().alphaLocation()); | |
| 361 DrawQuadGeometry(frame, | |
| 362 quad->quadTransform(), | |
| 363 quad->rect, | |
| 364 program->vertex_shader().matrixLocation()); | |
| 365 } | |
| 366 | |
| 367 void GLRenderer::DrawDebugBorderQuad(const DrawingFrame& frame, | |
| 368 const DebugBorderDrawQuad* quad) { | |
| 369 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
| 370 | |
| 371 static float gl_matrix[16]; | |
| 372 const DebugBorderProgram* program = GetDebugBorderProgram(); | |
| 373 DCHECK(program && (program->initialized() || IsContextLost())); | |
| 374 SetUseProgram(program->program()); | |
| 375 | |
| 376 // Use the full quad_rect for debug quads to not move the edges based on | |
| 377 // partial swaps. | |
| 378 gfx::Rect layer_rect = quad->rect; | |
| 379 gfx::Transform render_matrix = quad->quadTransform(); | |
| 380 render_matrix.Translate(0.5f * layer_rect.width() + layer_rect.x(), | |
| 381 0.5f * layer_rect.height() + layer_rect.y()); | |
| 382 render_matrix.Scale(layer_rect.width(), layer_rect.height()); | |
| 383 GLRenderer::ToGLMatrix(&gl_matrix[0], | |
| 384 frame.projection_matrix * render_matrix); | |
| 385 GLC(Context(), | |
| 386 Context()->uniformMatrix4fv( | |
| 387 program->vertex_shader().matrixLocation(), 1, false, &gl_matrix[0])); | |
| 388 | |
| 389 SkColor color = quad->color; | |
| 390 float alpha = SkColorGetA(color) * (1.0f / 255.0f); | |
| 391 | |
| 392 GLC(Context(), | |
| 393 Context()->uniform4f(program->fragment_shader().colorLocation(), | |
| 394 (SkColorGetR(color) * (1.0f / 255.0f)) * alpha, | |
| 395 (SkColorGetG(color) * (1.0f / 255.0f)) * alpha, | |
| 396 (SkColorGetB(color) * (1.0f / 255.0f)) * alpha, | |
| 397 alpha)); | |
| 398 | |
| 399 GLC(Context(), Context()->lineWidth(quad->width)); | |
| 400 | |
| 401 // The indices for the line are stored in the same array as the triangle | |
| 402 // indices. | |
| 403 GLC(Context(), | |
| 404 Context()->drawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0)); | |
| 405 } | |
| 406 | |
| 407 static inline SkBitmap ApplyFilters(GLRenderer* renderer, | |
| 408 const WebKit::WebFilterOperations& filters, | |
| 409 ScopedResource* source_texture_resource) { | |
| 410 if (filters.isEmpty()) | |
| 411 return SkBitmap(); | |
| 412 | |
| 413 ContextProvider* offscreen_contexts = | |
| 414 renderer->resource_provider()->offscreen_context_provider(); | |
| 415 if (!offscreen_contexts || !offscreen_contexts->GrContext()) | |
| 416 return SkBitmap(); | |
| 417 | |
| 418 ResourceProvider::ScopedWriteLockGL lock(renderer->resource_provider(), | |
| 419 source_texture_resource->id()); | |
| 420 | |
| 421 // Flush the compositor context to ensure that textures there are available | |
| 422 // in the shared context. Do this after locking/creating the compositor | |
| 423 // texture. | |
| 424 renderer->resource_provider()->Flush(); | |
| 425 | |
| 426 // Make sure skia uses the correct GL context. | |
| 427 offscreen_contexts->Context3d()->makeContextCurrent(); | |
| 428 | |
| 429 SkBitmap source = | |
| 430 RenderSurfaceFilters::Apply(filters, | |
| 431 lock.texture_id(), | |
| 432 source_texture_resource->size(), | |
| 433 offscreen_contexts->GrContext()); | |
| 434 | |
| 435 // Flush skia context so that all the rendered stuff appears on the | |
| 436 // texture. | |
| 437 offscreen_contexts->GrContext()->flush(); | |
| 438 | |
| 439 // Flush the GL context so rendering results from this context are | |
| 440 // visible in the compositor's context. | |
| 441 offscreen_contexts->Context3d()->flush(); | |
| 442 | |
| 443 // Use the compositor's GL context again. | |
| 444 renderer->resource_provider()->GraphicsContext3D()->makeContextCurrent(); | |
| 445 return source; | |
| 446 } | |
| 447 | |
| 448 static SkBitmap ApplyImageFilter(GLRenderer* renderer, | |
| 449 SkImageFilter* filter, | |
| 450 ScopedResource* source_texture_resource) { | |
| 451 if (!filter) | |
| 452 return SkBitmap(); | |
| 453 | |
| 454 ContextProvider* offscreen_contexts = | |
| 455 renderer->resource_provider()->offscreen_context_provider(); | |
| 456 if (!offscreen_contexts || !offscreen_contexts->GrContext()) | |
| 457 return SkBitmap(); | |
| 458 | |
| 459 ResourceProvider::ScopedWriteLockGL lock(renderer->resource_provider(), | |
| 460 source_texture_resource->id()); | |
| 461 | |
| 462 // Flush the compositor context to ensure that textures there are available | |
| 463 // in the shared context. Do this after locking/creating the compositor | |
| 464 // texture. | |
| 465 renderer->resource_provider()->Flush(); | |
| 466 | |
| 467 // Make sure skia uses the correct GL context. | |
| 468 offscreen_contexts->Context3d()->makeContextCurrent(); | |
| 469 | |
| 470 // Wrap the source texture in a Ganesh platform texture. | |
| 471 GrBackendTextureDesc backend_texture_description; | |
| 472 backend_texture_description.fWidth = source_texture_resource->size().width(); | |
| 473 backend_texture_description.fHeight = | |
| 474 source_texture_resource->size().height(); | |
| 475 backend_texture_description.fConfig = kSkia8888_GrPixelConfig; | |
| 476 backend_texture_description.fTextureHandle = lock.texture_id(); | |
| 477 backend_texture_description.fOrigin = kTopLeft_GrSurfaceOrigin; | |
| 478 skia::RefPtr<GrTexture> texture = | |
| 479 skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture( | |
| 480 backend_texture_description)); | |
| 481 | |
| 482 // Place the platform texture inside an SkBitmap. | |
| 483 SkBitmap source; | |
| 484 source.setConfig(SkBitmap::kARGB_8888_Config, | |
| 485 source_texture_resource->size().width(), | |
| 486 source_texture_resource->size().height()); | |
| 487 skia::RefPtr<SkGrPixelRef> pixel_ref = | |
| 488 skia::AdoptRef(new SkGrPixelRef(texture.get())); | |
| 489 source.setPixelRef(pixel_ref.get()); | |
| 490 | |
| 491 // Create a scratch texture for backing store. | |
| 492 GrTextureDesc desc; | |
| 493 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; | |
| 494 desc.fSampleCnt = 0; | |
| 495 desc.fWidth = source.width(); | |
| 496 desc.fHeight = source.height(); | |
| 497 desc.fConfig = kSkia8888_GrPixelConfig; | |
| 498 desc.fOrigin = kTopLeft_GrSurfaceOrigin; | |
| 499 GrAutoScratchTexture scratchTexture( | |
| 500 offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch); | |
| 501 skia::RefPtr<GrTexture> backing_store = | |
| 502 skia::AdoptRef(scratchTexture.detach()); | |
| 503 | |
| 504 // Create a device and canvas using that backing store. | |
| 505 SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get()); | |
| 506 SkCanvas canvas(&device); | |
| 507 | |
| 508 // Draw the source bitmap through the filter to the canvas. | |
| 509 SkPaint paint; | |
| 510 paint.setImageFilter(filter); | |
| 511 canvas.clear(SK_ColorTRANSPARENT); | |
| 512 canvas.drawSprite(source, 0, 0, &paint); | |
| 513 | |
| 514 // Flush skia context so that all the rendered stuff appears on the | |
| 515 // texture. | |
| 516 offscreen_contexts->GrContext()->flush(); | |
| 517 | |
| 518 // Flush the GL context so rendering results from this context are | |
| 519 // visible in the compositor's context. | |
| 520 offscreen_contexts->Context3d()->flush(); | |
| 521 | |
| 522 // Use the compositor's GL context again. | |
| 523 renderer->resource_provider()->GraphicsContext3D()->makeContextCurrent(); | |
| 524 | |
| 525 return device.accessBitmap(false); | |
| 526 } | |
| 527 | |
| 528 scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( | |
| 529 DrawingFrame& frame, | |
| 530 const RenderPassDrawQuad* quad, | |
| 531 const gfx::Transform& contents_device_transform, | |
| 532 const gfx::Transform& contents_device_transform_inverse) { | |
| 533 // This method draws a background filter, which applies a filter to any pixels | |
| 534 // behind the quad and seen through its background. The algorithm works as | |
| 535 // follows: | |
| 536 // 1. Compute a bounding box around the pixels that will be visible through | |
| 537 // the quad. | |
| 538 // 2. Read the pixels in the bounding box into a buffer R. | |
| 539 // 3. Apply the background filter to R, so that it is applied in the pixels' | |
| 540 // coordinate space. | |
| 541 // 4. Apply the quad's inverse transform to map the pixels in R into the | |
| 542 // quad's content space. This implicitly clips R by the content bounds of the | |
| 543 // quad since the destination texture has bounds matching the quad's content. | |
| 544 // 5. Draw the background texture for the contents using the same transform as | |
| 545 // used to draw the contents itself. This is done without blending to replace | |
| 546 // the current background pixels with the new filtered background. | |
| 547 // 6. Draw the contents of the quad over drop of the new background with | |
| 548 // blending, as per usual. The filtered background pixels will show through | |
| 549 // any non-opaque pixels in this draws. | |
| 550 // | |
| 551 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5. | |
| 552 | |
| 553 // FIXME: When this algorithm changes, update | |
| 554 // LayerTreeHost::prioritizeTextures() accordingly. | |
| 555 | |
| 556 const WebKit::WebFilterOperations& filters = quad->background_filters; | |
| 557 if (filters.isEmpty()) | |
| 558 return scoped_ptr<ScopedResource>(); | |
| 559 | |
| 560 // FIXME: We only allow background filters on an opaque render surface because | |
| 561 // other surfaces may contain translucent pixels, and the contents behind | |
| 562 // those translucent pixels wouldn't have the filter applied. | |
| 563 if (frame.current_render_pass->has_transparent_background) | |
| 564 return scoped_ptr<ScopedResource>(); | |
| 565 DCHECK(!frame.current_texture); | |
| 566 | |
| 567 // FIXME: Do a single readback for both the surface and replica and cache the | |
| 568 // filtered results (once filter textures are not reused). | |
| 569 gfx::Rect device_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect( | |
| 570 contents_device_transform, SharedGeometryQuad().BoundingBox())); | |
| 571 | |
| 572 int top, right, bottom, left; | |
| 573 filters.getOutsets(top, right, bottom, left); | |
| 574 device_rect.Inset(-left, -top, -right, -bottom); | |
| 575 | |
| 576 device_rect.Intersect(frame.current_render_pass->output_rect); | |
| 577 | |
| 578 scoped_ptr<ScopedResource> device_background_texture = | |
| 579 ScopedResource::create(resource_provider_); | |
| 580 if (!GetFramebufferTexture(device_background_texture.get(), device_rect)) | |
| 581 return scoped_ptr<ScopedResource>(); | |
| 582 | |
| 583 SkBitmap filtered_device_background = | |
| 584 ApplyFilters(this, filters, device_background_texture.get()); | |
| 585 if (!filtered_device_background.getTexture()) | |
| 586 return scoped_ptr<ScopedResource>(); | |
| 587 | |
| 588 GrTexture* texture = | |
| 589 reinterpret_cast<GrTexture*>(filtered_device_background.getTexture()); | |
| 590 int filtered_device_background_texture_id = texture->getTextureHandle(); | |
| 591 | |
| 592 scoped_ptr<ScopedResource> background_texture = | |
| 593 ScopedResource::create(resource_provider_); | |
| 594 if (!background_texture->Allocate(quad->rect.size(), | |
| 595 GL_RGBA, | |
| 596 ResourceProvider::TextureUsageFramebuffer)) | |
| 597 return scoped_ptr<ScopedResource>(); | |
| 598 | |
| 599 const RenderPass* target_render_pass = frame.current_render_pass; | |
| 600 bool using_background_texture = | |
| 601 UseScopedTexture(frame, background_texture.get(), quad->rect); | |
| 602 | |
| 603 if (using_background_texture) { | |
| 604 // Copy the readback pixels from device to the background texture for the | |
| 605 // surface. | |
| 606 gfx::Transform device_to_framebuffer_transform; | |
| 607 device_to_framebuffer_transform.Translate( | |
| 608 quad->rect.width() * 0.5f + quad->rect.x(), | |
| 609 quad->rect.height() * 0.5f + quad->rect.y()); | |
| 610 device_to_framebuffer_transform.Scale(quad->rect.width(), | |
| 611 quad->rect.height()); | |
| 612 device_to_framebuffer_transform.PreconcatTransform( | |
| 613 contents_device_transform_inverse); | |
| 614 | |
| 615 #ifndef NDEBUG | |
| 616 GLC(Context(), Context()->clearColor(0, 0, 1, 1)); | |
| 617 Context()->clear(GL_COLOR_BUFFER_BIT); | |
| 618 #endif | |
| 619 | |
| 620 CopyTextureToFramebuffer(frame, | |
| 621 filtered_device_background_texture_id, | |
| 622 device_rect, | |
| 623 device_to_framebuffer_transform); | |
| 624 } | |
| 625 | |
| 626 UseRenderPass(frame, target_render_pass); | |
| 627 | |
| 628 if (!using_background_texture) | |
| 629 return scoped_ptr<ScopedResource>(); | |
| 630 return background_texture.Pass(); | |
| 631 } | |
| 632 | |
| 633 void GLRenderer::DrawRenderPassQuad(DrawingFrame& frame, | |
| 634 const RenderPassDrawQuad* quad) { | |
| 635 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
| 636 | |
| 637 CachedResource* contents_texture = | |
| 638 render_pass_textures_.get(quad->render_pass_id); | |
| 639 if (!contents_texture || !contents_texture->id()) | |
| 640 return; | |
| 641 | |
| 642 gfx::Transform quad_rect_matrix; | |
| 643 QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect); | |
| 644 gfx::Transform contents_device_transform = | |
| 645 frame.window_matrix * frame.projection_matrix * quad_rect_matrix; | |
| 646 contents_device_transform.FlattenTo2d(); | |
| 647 | |
| 648 // Can only draw surface if device matrix is invertible. | |
| 649 gfx::Transform contents_device_transform_inverse( | |
| 650 gfx::Transform::kSkipInitialization); | |
| 651 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) | |
| 652 return; | |
| 653 | |
| 654 scoped_ptr<ScopedResource> background_texture = | |
| 655 DrawBackgroundFilters(frame, | |
| 656 quad, | |
| 657 contents_device_transform, | |
| 658 contents_device_transform_inverse); | |
| 659 | |
| 660 // FIXME: Cache this value so that we don't have to do it for both the surface | |
| 661 // and its replica. Apply filters to the contents texture. | |
| 662 SkBitmap filter_bitmap; | |
| 663 if (quad->filter) { | |
| 664 filter_bitmap = | |
| 665 ApplyImageFilter(this, quad->filter.get(), contents_texture); | |
| 666 } else { | |
| 667 filter_bitmap = ApplyFilters(this, quad->filters, contents_texture); | |
| 668 } | |
| 669 | |
| 670 // Draw the background texture if there is one. | |
| 671 if (background_texture) { | |
| 672 DCHECK(background_texture->size() == quad->rect.size()); | |
| 673 ResourceProvider::ScopedReadLockGL lock(resource_provider_, | |
| 674 background_texture->id()); | |
| 675 CopyTextureToFramebuffer( | |
| 676 frame, lock.texture_id(), quad->rect, quad->quadTransform()); | |
| 677 } | |
| 678 | |
| 679 bool clipped = false; | |
| 680 gfx::QuadF device_quad = MathUtil::MapQuad( | |
| 681 contents_device_transform, SharedGeometryQuad(), &clipped); | |
| 682 DCHECK(!clipped); | |
| 683 LayerQuad deviceLayerBounds(gfx::QuadF(device_quad.BoundingBox())); | |
| 684 LayerQuad device_layer_edges(device_quad); | |
| 685 | |
| 686 // Use anti-aliasing programs only when necessary. | |
| 687 bool use_aa = (!device_quad.IsRectilinear() || | |
| 688 !device_quad.BoundingBox().IsExpressibleAsRect()); | |
| 689 if (use_aa) { | |
| 690 deviceLayerBounds.InflateAntiAliasingDistance(); | |
| 691 device_layer_edges.InflateAntiAliasingDistance(); | |
| 692 } | |
| 693 | |
| 694 scoped_ptr<ResourceProvider::ScopedReadLockGL> mask_resource_lock; | |
| 695 unsigned mask_texture_id = 0; | |
| 696 if (quad->mask_resource_id) { | |
| 697 mask_resource_lock.reset(new ResourceProvider::ScopedReadLockGL( | |
| 698 resource_provider_, quad->mask_resource_id)); | |
| 699 mask_texture_id = mask_resource_lock->texture_id(); | |
| 700 } | |
| 701 | |
| 702 // FIXME: use the background_texture and blend the background in with this | |
| 703 // draw instead of having a separate copy of the background texture. | |
| 704 | |
| 705 scoped_ptr<ResourceProvider::ScopedReadLockGL> contents_resource_lock; | |
| 706 if (filter_bitmap.getTexture()) { | |
| 707 GrTexture* texture = | |
| 708 reinterpret_cast<GrTexture*>(filter_bitmap.getTexture()); | |
| 709 Context()->bindTexture(GL_TEXTURE_2D, texture->getTextureHandle()); | |
| 710 } else | |
| 711 contents_resource_lock = make_scoped_ptr( | |
| 712 new ResourceProvider::ScopedSamplerGL(resource_provider_, | |
| 713 contents_texture->id(), | |
| 714 GL_TEXTURE_2D, | |
| 715 GL_LINEAR)); | |
| 716 | |
| 717 int shader_quad_location = -1; | |
| 718 int shader_edge_location = -1; | |
| 719 int shader_mask_sampler_location = -1; | |
| 720 int shader_mask_tex_coord_scale_location = -1; | |
| 721 int shader_mask_tex_coord_offset_location = -1; | |
| 722 int shader_matrix_location = -1; | |
| 723 int shader_alpha_location = -1; | |
| 724 int shader_tex_transform_location = -1; | |
| 725 int shader_tex_scale_location = -1; | |
| 726 | |
| 727 if (use_aa && mask_texture_id) { | |
| 728 const RenderPassMaskProgramAA* program = GetRenderPassMaskProgramAA(); | |
| 729 SetUseProgram(program->program()); | |
| 730 GLC(Context(), | |
| 731 Context()->uniform1i(program->fragment_shader().samplerLocation(), 0)); | |
| 732 | |
| 733 shader_quad_location = program->vertex_shader().pointLocation(); | |
| 734 shader_edge_location = program->fragment_shader().edgeLocation(); | |
| 735 shader_mask_sampler_location = | |
| 736 program->fragment_shader().maskSamplerLocation(); | |
| 737 shader_mask_tex_coord_scale_location = | |
| 738 program->fragment_shader().maskTexCoordScaleLocation(); | |
| 739 shader_mask_tex_coord_offset_location = | |
| 740 program->fragment_shader().maskTexCoordOffsetLocation(); | |
| 741 shader_matrix_location = program->vertex_shader().matrixLocation(); | |
| 742 shader_alpha_location = program->fragment_shader().alphaLocation(); | |
| 743 shader_tex_scale_location = program->vertex_shader().texScaleLocation(); | |
| 744 } else if (!use_aa && mask_texture_id) { | |
| 745 const RenderPassMaskProgram* program = GetRenderPassMaskProgram(); | |
| 746 SetUseProgram(program->program()); | |
| 747 GLC(Context(), | |
| 748 Context()->uniform1i(program->fragment_shader().samplerLocation(), 0)); | |
| 749 | |
| 750 shader_mask_sampler_location = | |
| 751 program->fragment_shader().maskSamplerLocation(); | |
| 752 shader_mask_tex_coord_scale_location = | |
| 753 program->fragment_shader().maskTexCoordScaleLocation(); | |
| 754 shader_mask_tex_coord_offset_location = | |
| 755 program->fragment_shader().maskTexCoordOffsetLocation(); | |
| 756 shader_matrix_location = program->vertex_shader().matrixLocation(); | |
| 757 shader_alpha_location = program->fragment_shader().alphaLocation(); | |
| 758 shader_tex_transform_location = | |
| 759 program->vertex_shader().texTransformLocation(); | |
| 760 } else if (use_aa && !mask_texture_id) { | |
| 761 const RenderPassProgramAA* program = GetRenderPassProgramAA(); | |
| 762 SetUseProgram(program->program()); | |
| 763 GLC(Context(), | |
| 764 Context()->uniform1i(program->fragment_shader().samplerLocation(), 0)); | |
| 765 | |
| 766 shader_quad_location = program->vertex_shader().pointLocation(); | |
| 767 shader_edge_location = program->fragment_shader().edgeLocation(); | |
| 768 shader_matrix_location = program->vertex_shader().matrixLocation(); | |
| 769 shader_alpha_location = program->fragment_shader().alphaLocation(); | |
| 770 shader_tex_scale_location = program->vertex_shader().texScaleLocation(); | |
| 771 } else { | |
| 772 const RenderPassProgram* program = GetRenderPassProgram(); | |
| 773 SetUseProgram(program->program()); | |
| 774 GLC(Context(), | |
| 775 Context()->uniform1i(program->fragment_shader().samplerLocation(), 0)); | |
| 776 | |
| 777 shader_matrix_location = program->vertex_shader().matrixLocation(); | |
| 778 shader_alpha_location = program->fragment_shader().alphaLocation(); | |
| 779 shader_tex_transform_location = | |
| 780 program->vertex_shader().texTransformLocation(); | |
| 781 } | |
| 782 | |
| 783 float tex_scale_x = | |
| 784 quad->rect.width() / static_cast<float>(contents_texture->size().width()); | |
| 785 float tex_scale_y = quad->rect.height() / | |
| 786 static_cast<float>(contents_texture->size().height()); | |
| 787 DCHECK_LE(tex_scale_x, 1.0f); | |
| 788 DCHECK_LE(tex_scale_y, 1.0f); | |
| 789 | |
| 790 if (shader_tex_transform_location != -1) { | |
| 791 GLC(Context(), | |
| 792 Context()->uniform4f(shader_tex_transform_location, | |
| 793 0.0f, | |
| 794 0.0f, | |
| 795 tex_scale_x, | |
| 796 tex_scale_y)); | |
| 797 } else if (shader_tex_scale_location != -1) { | |
| 798 GLC(Context(), | |
| 799 Context()->uniform2f( | |
| 800 shader_tex_scale_location, tex_scale_x, tex_scale_y)); | |
| 801 } else { | |
| 802 DCHECK(IsContextLost()); | |
| 803 } | |
| 804 | |
| 805 if (shader_mask_sampler_location != -1) { | |
| 806 DCHECK(shader_mask_tex_coord_scale_location != 1); | |
| 807 DCHECK(shader_mask_tex_coord_offset_location != 1); | |
| 808 GLC(Context(), Context()->activeTexture(GL_TEXTURE1)); | |
| 809 GLC(Context(), Context()->uniform1i(shader_mask_sampler_location, 1)); | |
| 810 GLC(Context(), | |
| 811 Context()->uniform2f(shader_mask_tex_coord_offset_location, | |
| 812 quad->mask_uv_rect.x(), | |
| 813 quad->mask_uv_rect.y())); | |
| 814 GLC(Context(), | |
| 815 Context()->uniform2f(shader_mask_tex_coord_scale_location, | |
| 816 quad->mask_uv_rect.width() / tex_scale_x, | |
| 817 quad->mask_uv_rect.height() / tex_scale_y)); | |
| 818 resource_provider_->BindForSampling( | |
| 819 quad->mask_resource_id, GL_TEXTURE_2D, GL_LINEAR); | |
| 820 GLC(Context(), Context()->activeTexture(GL_TEXTURE0)); | |
| 821 } | |
| 822 | |
| 823 if (shader_edge_location != -1) { | |
| 824 float edge[24]; | |
| 825 device_layer_edges.ToFloatArray(edge); | |
| 826 deviceLayerBounds.ToFloatArray(&edge[12]); | |
| 827 GLC(Context(), Context()->uniform3fv(shader_edge_location, 8, edge)); | |
| 828 } | |
| 829 | |
| 830 // Map device space quad to surface space. contents_device_transform has no 3d | |
| 831 // component since it was flattened, so we don't need to project. | |
| 832 gfx::QuadF surface_quad = MathUtil::MapQuad(contents_device_transform_inverse, | |
| 833 device_layer_edges.ToQuadF(), | |
| 834 &clipped); | |
| 835 DCHECK(!clipped); | |
| 836 | |
| 837 SetShaderOpacity(quad->opacity(), shader_alpha_location); | |
| 838 SetShaderQuadF(surface_quad, shader_quad_location); | |
| 839 DrawQuadGeometry( | |
| 840 frame, quad->quadTransform(), quad->rect, shader_matrix_location); | |
| 841 | |
| 842 // Flush the compositor context before the filter bitmap goes out of | |
| 843 // scope, so the draw gets processed before the filter texture gets deleted. | |
| 844 if (filter_bitmap.getTexture()) | |
| 845 context_->flush(); | |
| 846 } | |
| 847 | |
| 848 struct SolidColorProgramUniforms { | |
| 849 unsigned program; | |
| 850 unsigned matrix_location; | |
| 851 unsigned color_location; | |
| 852 unsigned point_location; | |
| 853 unsigned tex_scale_location; | |
| 854 unsigned edge_location; | |
| 855 }; | |
| 856 | |
| 857 template<class T> | |
| 858 static void SolidColorUniformLocation(T program, | |
| 859 SolidColorProgramUniforms* uniforms) { | |
| 860 uniforms->program = program->program(); | |
| 861 uniforms->matrix_location = program->vertex_shader().matrixLocation(); | |
| 862 uniforms->color_location = program->fragment_shader().colorLocation(); | |
| 863 uniforms->point_location = program->vertex_shader().pointLocation(); | |
| 864 uniforms->tex_scale_location = program->vertex_shader().texScaleLocation(); | |
| 865 uniforms->edge_location = program->fragment_shader().edgeLocation(); | |
| 866 } | |
| 867 | |
| 868 bool GLRenderer::SetupQuadForAntialiasing( | |
| 869 const gfx::Transform& device_transform, | |
| 870 const DrawQuad* quad, | |
| 871 gfx::QuadF* local_quad, | |
| 872 float edge[24]) const { | |
| 873 gfx::Rect tile_rect = quad->visible_rect; | |
| 874 | |
| 875 bool clipped = false; | |
| 876 gfx::QuadF device_layer_quad = MathUtil::MapQuad( | |
| 877 device_transform, gfx::QuadF(quad->visibleContentRect()), &clipped); | |
| 878 DCHECK(!clipped); | |
| 879 | |
| 880 // TODO(reveman): Axis-aligned is not enough to avoid anti-aliasing. | |
| 881 // Bounding rectangle for quad also needs to be expressible as an integer | |
| 882 // rectangle. crbug.com/169374 | |
| 883 bool is_axis_aligned_in_target = device_layer_quad.IsRectilinear(); | |
| 884 bool use_aa = !clipped && !is_axis_aligned_in_target && quad->IsEdge(); | |
| 885 | |
| 886 if (!use_aa) | |
| 887 return false; | |
| 888 | |
| 889 LayerQuad device_layer_bounds(gfx::QuadF(device_layer_quad.BoundingBox())); | |
| 890 device_layer_bounds.InflateAntiAliasingDistance(); | |
| 891 | |
| 892 LayerQuad device_layer_edges(device_layer_quad); | |
| 893 device_layer_edges.InflateAntiAliasingDistance(); | |
| 894 | |
| 895 device_layer_edges.ToFloatArray(edge); | |
| 896 device_layer_bounds.ToFloatArray(&edge[12]); | |
| 897 | |
| 898 gfx::PointF bottom_right = tile_rect.bottom_right(); | |
| 899 gfx::PointF bottom_left = tile_rect.bottom_left(); | |
| 900 gfx::PointF top_left = tile_rect.origin(); | |
| 901 gfx::PointF top_right = tile_rect.top_right(); | |
| 902 | |
| 903 // Map points to device space. | |
| 904 bottom_right = MathUtil::MapPoint(device_transform, bottom_right, &clipped); | |
| 905 DCHECK(!clipped); | |
| 906 bottom_left = MathUtil::MapPoint(device_transform, bottom_left, &clipped); | |
| 907 DCHECK(!clipped); | |
| 908 top_left = MathUtil::MapPoint(device_transform, top_left, &clipped); | |
| 909 DCHECK(!clipped); | |
| 910 top_right = MathUtil::MapPoint(device_transform, top_right, &clipped); | |
| 911 DCHECK(!clipped); | |
| 912 | |
| 913 LayerQuad::Edge bottom_edge(bottom_right, bottom_left); | |
| 914 LayerQuad::Edge left_edge(bottom_left, top_left); | |
| 915 LayerQuad::Edge top_edge(top_left, top_right); | |
| 916 LayerQuad::Edge right_edge(top_right, bottom_right); | |
| 917 | |
| 918 // Only apply anti-aliasing to edges not clipped by culling or scissoring. | |
| 919 if (quad->IsTopEdge() && tile_rect.y() == quad->rect.y()) | |
| 920 top_edge = device_layer_edges.top(); | |
| 921 if (quad->IsLeftEdge() && tile_rect.x() == quad->rect.x()) | |
| 922 left_edge = device_layer_edges.left(); | |
| 923 if (quad->IsRightEdge() && tile_rect.right() == quad->rect.right()) | |
| 924 right_edge = device_layer_edges.right(); | |
| 925 if (quad->IsBottomEdge() && tile_rect.bottom() == quad->rect.bottom()) | |
| 926 bottom_edge = device_layer_edges.bottom(); | |
| 927 | |
| 928 float sign = gfx::QuadF(tile_rect).IsCounterClockwise() ? -1 : 1; | |
| 929 bottom_edge.scale(sign); | |
| 930 left_edge.scale(sign); | |
| 931 top_edge.scale(sign); | |
| 932 right_edge.scale(sign); | |
| 933 | |
| 934 // Create device space quad. | |
| 935 LayerQuad device_quad(left_edge, top_edge, right_edge, bottom_edge); | |
| 936 | |
| 937 // Map device space quad to local space. deviceTransform has no 3d | |
| 938 // component since it was flattened, so we don't need to project. We should | |
| 939 // have already checked that the transform was uninvertible above. | |
| 940 gfx::Transform inverse_device_transform( | |
| 941 gfx::Transform::kSkipInitialization); | |
| 942 bool did_invert = device_transform.GetInverse(&inverse_device_transform); | |
| 943 DCHECK(did_invert); | |
| 944 *local_quad = MathUtil::MapQuad( | |
| 945 inverse_device_transform, device_quad.ToQuadF(), &clipped); | |
| 946 // We should not DCHECK(!clipped) here, because anti-aliasing inflation may | |
| 947 // cause deviceQuad to become clipped. To our knowledge this scenario does | |
| 948 // not need to be handled differently than the unclipped case. | |
| 949 | |
| 950 return true; | |
| 951 } | |
| 952 | |
| 953 void GLRenderer::DrawSolidColorQuad(const DrawingFrame& frame, | |
| 954 const SolidColorDrawQuad* quad) { | |
| 955 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
| 956 gfx::Rect tile_rect = quad->visible_rect; | |
| 957 | |
| 958 gfx::Transform device_transform = | |
| 959 frame.window_matrix * frame.projection_matrix * quad->quadTransform(); | |
| 960 device_transform.FlattenTo2d(); | |
| 961 if (!device_transform.IsInvertible()) | |
| 962 return; | |
| 963 | |
| 964 gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect)); | |
| 965 float edge[24]; | |
| 966 bool use_aa = SetupQuadForAntialiasing( | |
| 967 device_transform, quad, &local_quad, edge); | |
| 968 | |
| 969 SolidColorProgramUniforms uniforms; | |
| 970 if (use_aa) | |
| 971 SolidColorUniformLocation(GetSolidColorProgramAA(), &uniforms); | |
| 972 else | |
| 973 SolidColorUniformLocation(GetSolidColorProgram(), &uniforms); | |
| 974 SetUseProgram(uniforms.program); | |
| 975 | |
| 976 SkColor color = quad->color; | |
| 977 float opacity = quad->opacity(); | |
| 978 float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity; | |
| 979 | |
| 980 GLC(Context(), | |
| 981 Context()->uniform4f(uniforms.color_location, | |
| 982 (SkColorGetR(color) * (1.0f / 255.0f)) * alpha, | |
| 983 (SkColorGetG(color) * (1.0f / 255.0f)) * alpha, | |
| 984 (SkColorGetB(color) * (1.0f / 255.0f)) * alpha, | |
| 985 alpha)); | |
| 986 | |
| 987 if (use_aa) | |
| 988 GLC(Context(), Context()->uniform3fv(uniforms.edge_location, 8, edge)); | |
| 989 | |
| 990 // Enable blending when the quad properties require it or if we decided | |
| 991 // to use antialiasing. | |
| 992 SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa); | |
| 993 | |
| 994 // Normalize to tileRect. | |
| 995 local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height()); | |
| 996 | |
| 997 SetShaderQuadF(local_quad, uniforms.point_location); | |
| 998 | |
| 999 // The transform and vertex data are used to figure out the extents that the | |
| 1000 // un-antialiased quad should have and which vertex this is and the float | |
| 1001 // quad passed in via uniform is the actual geometry that gets used to draw | |
| 1002 // it. This is why this centered rect is used and not the original quadRect. | |
| 1003 gfx::RectF centered_rect(gfx::PointF(-0.5f * tile_rect.width(), | |
| 1004 -0.5f * tile_rect.height()), | |
| 1005 tile_rect.size()); | |
| 1006 DrawQuadGeometry(frame, quad->quadTransform(), | |
| 1007 centered_rect, uniforms.matrix_location); | |
| 1008 } | |
| 1009 | |
| 1010 struct TileProgramUniforms { | |
| 1011 unsigned program; | |
| 1012 unsigned sampler_location; | |
| 1013 unsigned vertex_tex_transform_location; | |
| 1014 unsigned fragment_tex_transform_location; | |
| 1015 unsigned edge_location; | |
| 1016 unsigned matrix_location; | |
| 1017 unsigned alpha_location; | |
| 1018 unsigned point_location; | |
| 1019 }; | |
| 1020 | |
| 1021 template <class T> | |
| 1022 static void TileUniformLocation(T program, TileProgramUniforms* uniforms) { | |
| 1023 uniforms->program = program->program(); | |
| 1024 uniforms->vertex_tex_transform_location = | |
| 1025 program->vertex_shader().vertexTexTransformLocation(); | |
| 1026 uniforms->matrix_location = program->vertex_shader().matrixLocation(); | |
| 1027 uniforms->point_location = program->vertex_shader().pointLocation(); | |
| 1028 | |
| 1029 uniforms->sampler_location = program->fragment_shader().samplerLocation(); | |
| 1030 uniforms->alpha_location = program->fragment_shader().alphaLocation(); | |
| 1031 uniforms->fragment_tex_transform_location = | |
| 1032 program->fragment_shader().fragmentTexTransformLocation(); | |
| 1033 uniforms->edge_location = program->fragment_shader().edgeLocation(); | |
| 1034 } | |
| 1035 | |
| 1036 void GLRenderer::DrawTileQuad(const DrawingFrame& frame, | |
| 1037 const TileDrawQuad* quad) { | |
| 1038 gfx::Rect tile_rect = quad->visible_rect; | |
| 1039 | |
| 1040 gfx::RectF tex_coord_rect = quad->tex_coord_rect; | |
| 1041 float tex_to_geom_scale_x = quad->rect.width() / tex_coord_rect.width(); | |
| 1042 float tex_to_geom_scale_y = quad->rect.height() / tex_coord_rect.height(); | |
| 1043 | |
| 1044 // tex_coord_rect corresponds to quad_rect, but quadVisibleRect may be | |
| 1045 // smaller than quad_rect due to occlusion or clipping. Adjust | |
| 1046 // tex_coord_rect to match. | |
| 1047 gfx::Vector2d top_left_diff = tile_rect.origin() - quad->rect.origin(); | |
| 1048 gfx::Vector2d bottom_right_diff = | |
| 1049 tile_rect.bottom_right() - quad->rect.bottom_right(); | |
| 1050 tex_coord_rect.Inset(top_left_diff.x() / tex_to_geom_scale_x, | |
| 1051 top_left_diff.y() / tex_to_geom_scale_y, | |
| 1052 -bottom_right_diff.x() / tex_to_geom_scale_x, | |
| 1053 -bottom_right_diff.y() / tex_to_geom_scale_y); | |
| 1054 | |
| 1055 gfx::RectF clamp_geom_rect(tile_rect); | |
| 1056 gfx::RectF clamp_tex_rect(tex_coord_rect); | |
| 1057 // Clamp texture coordinates to avoid sampling outside the layer | |
| 1058 // by deflating the tile region half a texel or half a texel | |
| 1059 // minus epsilon for one pixel layers. The resulting clamp region | |
| 1060 // is mapped to the unit square by the vertex shader and mapped | |
| 1061 // back to normalized texture coordinates by the fragment shader | |
| 1062 // after being clamped to 0-1 range. | |
| 1063 const float epsilon = 1.0f / 1024.0f; | |
| 1064 float tex_clamp_x = std::min(0.5f, 0.5f * clamp_tex_rect.width() - epsilon); | |
| 1065 float tex_clamp_y = std::min(0.5f, 0.5f * clamp_tex_rect.height() - epsilon); | |
| 1066 float geom_clamp_x = std::min(tex_clamp_x * tex_to_geom_scale_x, | |
| 1067 0.5f * clamp_geom_rect.width() - epsilon); | |
| 1068 float geom_clamp_y = std::min(tex_clamp_y * tex_to_geom_scale_y, | |
| 1069 0.5f * clamp_geom_rect.height() - epsilon); | |
| 1070 clamp_geom_rect.Inset(geom_clamp_x, geom_clamp_y, geom_clamp_x, geom_clamp_y); | |
| 1071 clamp_tex_rect.Inset(tex_clamp_x, tex_clamp_y, tex_clamp_x, tex_clamp_y); | |
| 1072 | |
| 1073 // Map clamping rectangle to unit square. | |
| 1074 float vertex_tex_translate_x = -clamp_geom_rect.x() / clamp_geom_rect.width(); | |
| 1075 float vertex_tex_translate_y = | |
| 1076 -clamp_geom_rect.y() / clamp_geom_rect.height(); | |
| 1077 float vertex_tex_scale_x = tile_rect.width() / clamp_geom_rect.width(); | |
| 1078 float vertex_tex_scale_y = tile_rect.height() / clamp_geom_rect.height(); | |
| 1079 | |
| 1080 // Map to normalized texture coordinates. | |
| 1081 gfx::Size texture_size = quad->texture_size; | |
| 1082 float fragment_tex_translate_x = clamp_tex_rect.x() / texture_size.width(); | |
| 1083 float fragment_tex_translate_y = clamp_tex_rect.y() / texture_size.height(); | |
| 1084 float fragment_tex_scale_x = clamp_tex_rect.width() / texture_size.width(); | |
| 1085 float fragment_tex_scale_y = clamp_tex_rect.height() / texture_size.height(); | |
| 1086 | |
| 1087 gfx::Transform device_transform = | |
| 1088 frame.window_matrix * frame.projection_matrix * quad->quadTransform(); | |
| 1089 device_transform.FlattenTo2d(); | |
| 1090 if (!device_transform.IsInvertible()) | |
| 1091 return; | |
| 1092 | |
| 1093 gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect)); | |
| 1094 float edge[24]; | |
| 1095 bool use_aa = SetupQuadForAntialiasing( | |
| 1096 device_transform, quad, &local_quad, edge); | |
| 1097 | |
| 1098 TileProgramUniforms uniforms; | |
| 1099 if (use_aa) { | |
| 1100 if (quad->swizzle_contents) | |
| 1101 TileUniformLocation(GetTileProgramSwizzleAA(), &uniforms); | |
| 1102 else | |
| 1103 TileUniformLocation(GetTileProgramAA(), &uniforms); | |
| 1104 } else { | |
| 1105 if (quad->ShouldDrawWithBlending()) { | |
| 1106 if (quad->swizzle_contents) | |
| 1107 TileUniformLocation(GetTileProgramSwizzle(), &uniforms); | |
| 1108 else | |
| 1109 TileUniformLocation(GetTileProgram(), &uniforms); | |
| 1110 } else { | |
| 1111 if (quad->swizzle_contents) | |
| 1112 TileUniformLocation(GetTileProgramSwizzleOpaque(), &uniforms); | |
| 1113 else | |
| 1114 TileUniformLocation(GetTileProgramOpaque(), &uniforms); | |
| 1115 } | |
| 1116 } | |
| 1117 | |
| 1118 SetUseProgram(uniforms.program); | |
| 1119 GLC(Context(), Context()->uniform1i(uniforms.sampler_location, 0)); | |
| 1120 bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f); | |
| 1121 GLenum filter = (use_aa || scaled || | |
| 1122 !quad->quadTransform().IsIdentityOrIntegerTranslation()) | |
| 1123 ? GL_LINEAR | |
| 1124 : GL_NEAREST; | |
| 1125 ResourceProvider::ScopedSamplerGL quad_resource_lock( | |
| 1126 resource_provider_, quad->resource_id, GL_TEXTURE_2D, filter); | |
| 1127 | |
| 1128 if (use_aa) { | |
| 1129 GLC(Context(), Context()->uniform3fv(uniforms.edge_location, 8, edge)); | |
| 1130 | |
| 1131 GLC(Context(), | |
| 1132 Context()->uniform4f(uniforms.vertex_tex_transform_location, | |
| 1133 vertex_tex_translate_x, | |
| 1134 vertex_tex_translate_y, | |
| 1135 vertex_tex_scale_x, | |
| 1136 vertex_tex_scale_y)); | |
| 1137 GLC(Context(), | |
| 1138 Context()->uniform4f(uniforms.fragment_tex_transform_location, | |
| 1139 fragment_tex_translate_x, | |
| 1140 fragment_tex_translate_y, | |
| 1141 fragment_tex_scale_x, | |
| 1142 fragment_tex_scale_y)); | |
| 1143 } else { | |
| 1144 // Move fragment shader transform to vertex shader. We can do this while | |
| 1145 // still producing correct results as fragment_tex_transform_location | |
| 1146 // should always be non-negative when tiles are transformed in a way | |
| 1147 // that could result in sampling outside the layer. | |
| 1148 vertex_tex_scale_x *= fragment_tex_scale_x; | |
| 1149 vertex_tex_scale_y *= fragment_tex_scale_y; | |
| 1150 vertex_tex_translate_x *= fragment_tex_scale_x; | |
| 1151 vertex_tex_translate_y *= fragment_tex_scale_y; | |
| 1152 vertex_tex_translate_x += fragment_tex_translate_x; | |
| 1153 vertex_tex_translate_y += fragment_tex_translate_y; | |
| 1154 | |
| 1155 GLC(Context(), | |
| 1156 Context()->uniform4f(uniforms.vertex_tex_transform_location, | |
| 1157 vertex_tex_translate_x, | |
| 1158 vertex_tex_translate_y, | |
| 1159 vertex_tex_scale_x, | |
| 1160 vertex_tex_scale_y)); | |
| 1161 } | |
| 1162 | |
| 1163 // Enable blending when the quad properties require it or if we decided | |
| 1164 // to use antialiasing. | |
| 1165 SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa); | |
| 1166 | |
| 1167 // Normalize to tile_rect. | |
| 1168 local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height()); | |
| 1169 | |
| 1170 SetShaderOpacity(quad->opacity(), uniforms.alpha_location); | |
| 1171 SetShaderQuadF(local_quad, uniforms.point_location); | |
| 1172 | |
| 1173 // The transform and vertex data are used to figure out the extents that the | |
| 1174 // un-antialiased quad should have and which vertex this is and the float | |
| 1175 // quad passed in via uniform is the actual geometry that gets used to draw | |
| 1176 // it. This is why this centered rect is used and not the original quad_rect. | |
| 1177 gfx::RectF centeredRect( | |
| 1178 gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()), | |
| 1179 tile_rect.size()); | |
| 1180 DrawQuadGeometry( | |
| 1181 frame, quad->quadTransform(), centeredRect, uniforms.matrix_location); | |
| 1182 } | |
| 1183 | |
| 1184 void GLRenderer::DrawYUVVideoQuad(const DrawingFrame& frame, | |
| 1185 const YUVVideoDrawQuad* quad) { | |
| 1186 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
| 1187 | |
| 1188 const VideoYUVProgram* program = GetVideoYUVProgram(); | |
| 1189 DCHECK(program && (program->initialized() || IsContextLost())); | |
| 1190 | |
| 1191 const VideoLayerImpl::FramePlane& y_plane = quad->y_plane; | |
| 1192 const VideoLayerImpl::FramePlane& u_plane = quad->u_plane; | |
| 1193 const VideoLayerImpl::FramePlane& v_plane = quad->v_plane; | |
| 1194 | |
| 1195 GLC(Context(), Context()->activeTexture(GL_TEXTURE1)); | |
| 1196 ResourceProvider::ScopedSamplerGL y_plane_lock( | |
| 1197 resource_provider_, y_plane.resource_id, GL_TEXTURE_2D, GL_LINEAR); | |
| 1198 GLC(Context(), Context()->activeTexture(GL_TEXTURE2)); | |
| 1199 ResourceProvider::ScopedSamplerGL u_plane_lock( | |
| 1200 resource_provider_, u_plane.resource_id, GL_TEXTURE_2D, GL_LINEAR); | |
| 1201 GLC(Context(), Context()->activeTexture(GL_TEXTURE3)); | |
| 1202 ResourceProvider::ScopedSamplerGL v_plane_lock( | |
| 1203 resource_provider_, v_plane.resource_id, GL_TEXTURE_2D, GL_LINEAR); | |
| 1204 | |
| 1205 SetUseProgram(program->program()); | |
| 1206 | |
| 1207 GLC(Context(), | |
| 1208 Context()->uniform2f(program->vertex_shader().texScaleLocation(), | |
| 1209 quad->tex_scale.width(), | |
| 1210 quad->tex_scale.height())); | |
| 1211 GLC(Context(), | |
| 1212 Context()->uniform1i(program->fragment_shader().yTextureLocation(), 1)); | |
| 1213 GLC(Context(), | |
| 1214 Context()->uniform1i(program->fragment_shader().uTextureLocation(), 2)); | |
| 1215 GLC(Context(), | |
| 1216 Context()->uniform1i(program->fragment_shader().vTextureLocation(), 3)); | |
| 1217 | |
| 1218 // These values are magic numbers that are used in the transformation from YUV | |
| 1219 // to RGB color values. They are taken from the following webpage: | |
| 1220 // http://www.fourcc.org/fccyvrgb.php | |
| 1221 float yuv_to_rgb[9] = { | |
| 1222 1.164f, 1.164f, 1.164f, | |
| 1223 0.0f, -.391f, 2.018f, | |
| 1224 1.596f, -.813f, 0.0f, | |
| 1225 }; | |
| 1226 GLC(Context(), | |
| 1227 Context()->uniformMatrix3fv( | |
| 1228 program->fragment_shader().yuvMatrixLocation(), 1, 0, yuv_to_rgb)); | |
| 1229 | |
| 1230 // These values map to 16, 128, and 128 respectively, and are computed | |
| 1231 // as a fraction over 256 (e.g. 16 / 256 = 0.0625). | |
| 1232 // They are used in the YUV to RGBA conversion formula: | |
| 1233 // Y - 16 : Gives 16 values of head and footroom for overshooting | |
| 1234 // U - 128 : Turns unsigned U into signed U [-128,127] | |
| 1235 // V - 128 : Turns unsigned V into signed V [-128,127] | |
| 1236 float yuv_adjust[3] = { -0.0625f, -0.5f, -0.5f, }; | |
| 1237 GLC(Context(), | |
| 1238 Context()->uniform3fv( | |
| 1239 program->fragment_shader().yuvAdjLocation(), 1, yuv_adjust)); | |
| 1240 | |
| 1241 SetShaderOpacity(quad->opacity(), program->fragment_shader().alphaLocation()); | |
| 1242 DrawQuadGeometry(frame, | |
| 1243 quad->quadTransform(), | |
| 1244 quad->rect, | |
| 1245 program->vertex_shader().matrixLocation()); | |
| 1246 | |
| 1247 // Reset active texture back to texture 0. | |
| 1248 GLC(Context(), Context()->activeTexture(GL_TEXTURE0)); | |
| 1249 } | |
| 1250 | |
| 1251 void GLRenderer::DrawStreamVideoQuad(const DrawingFrame& frame, | |
| 1252 const StreamVideoDrawQuad* quad) { | |
| 1253 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
| 1254 | |
| 1255 static float gl_matrix[16]; | |
| 1256 | |
| 1257 DCHECK(capabilities_.using_egl_image); | |
| 1258 | |
| 1259 const VideoStreamTextureProgram* program = GetVideoStreamTextureProgram(); | |
| 1260 SetUseProgram(program->program()); | |
| 1261 | |
| 1262 ToGLMatrix(&gl_matrix[0], quad->matrix); | |
| 1263 GLC(Context(), | |
| 1264 Context()->uniformMatrix4fv( | |
| 1265 program->vertex_shader().texMatrixLocation(), 1, false, gl_matrix)); | |
| 1266 | |
| 1267 GLC(Context(), | |
| 1268 Context()->bindTexture(GL_TEXTURE_EXTERNAL_OES, quad->texture_id)); | |
| 1269 | |
| 1270 GLC(Context(), | |
| 1271 Context()->uniform1i(program->fragment_shader().samplerLocation(), 0)); | |
| 1272 | |
| 1273 SetShaderOpacity(quad->opacity(), program->fragment_shader().alphaLocation()); | |
| 1274 DrawQuadGeometry(frame, | |
| 1275 quad->quadTransform(), | |
| 1276 quad->rect, | |
| 1277 program->vertex_shader().matrixLocation()); | |
| 1278 } | |
| 1279 | |
| 1280 struct TextureProgramBinding { | |
| 1281 template <class Program> | |
| 1282 void Set(Program* program, WebKit::WebGraphicsContext3D* context) { | |
| 1283 DCHECK(program && (program->initialized() || context->isContextLost())); | |
| 1284 program_id = program->program(); | |
| 1285 sampler_location = program->fragment_shader().samplerLocation(); | |
| 1286 matrix_location = program->vertex_shader().matrixLocation(); | |
| 1287 alpha_location = program->fragment_shader().alphaLocation(); | |
| 1288 } | |
| 1289 int program_id; | |
| 1290 int sampler_location; | |
| 1291 int matrix_location; | |
| 1292 int alpha_location; | |
| 1293 }; | |
| 1294 | |
| 1295 struct TexTransformTextureProgramBinding : TextureProgramBinding { | |
| 1296 template <class Program> | |
| 1297 void Set(Program* program, WebKit::WebGraphicsContext3D* context) { | |
| 1298 TextureProgramBinding::Set(program, context); | |
| 1299 tex_transform_location = program->vertex_shader().texTransformLocation(); | |
| 1300 vertex_opacity_location = program->vertex_shader().vertexOpacityLocation(); | |
| 1301 } | |
| 1302 int tex_transform_location; | |
| 1303 int vertex_opacity_location; | |
| 1304 }; | |
| 1305 | |
| 1306 void GLRenderer::FlushTextureQuadCache() { | |
| 1307 // Check to see if we have anything to draw. | |
| 1308 if (draw_cache_.program_id == 0) | |
| 1309 return; | |
| 1310 | |
| 1311 // Set the correct blending mode. | |
| 1312 SetBlendEnabled(draw_cache_.needs_blending); | |
| 1313 | |
| 1314 // Bind the program to the GL state. | |
| 1315 SetUseProgram(draw_cache_.program_id); | |
| 1316 | |
| 1317 // Bind the correct texture sampler location. | |
| 1318 GLC(Context(), Context()->uniform1i(draw_cache_.sampler_location, 0)); | |
| 1319 | |
| 1320 // Assume the current active textures is 0. | |
| 1321 ResourceProvider::ScopedReadLockGL locked_quad(resource_provider_, | |
| 1322 draw_cache_.resource_id); | |
| 1323 GLC(Context(), | |
| 1324 Context()->bindTexture(GL_TEXTURE_2D, locked_quad.texture_id())); | |
| 1325 | |
| 1326 // set up premultiplied alpha. | |
| 1327 if (!draw_cache_.use_premultiplied_alpha) { | |
| 1328 // As it turns out, the premultiplied alpha blending function (ONE, | |
| 1329 // ONE_MINUS_SRC_ALPHA) will never cause the alpha channel to be set to | |
| 1330 // anything less than 1.0f if it is initialized to that value! Therefore, | |
| 1331 // premultipliedAlpha being false is the first situation we can generally | |
| 1332 // see an alpha channel less than 1.0f coming out of the compositor. This is | |
| 1333 // causing platform differences in some layout tests (see | |
| 1334 // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use | |
| 1335 // a separate blend function for the alpha channel to avoid modifying it. | |
| 1336 // Don't use colorMask for this as it has performance implications on some | |
| 1337 // platforms. | |
| 1338 GLC(Context(), | |
| 1339 Context()->blendFuncSeparate( | |
| 1340 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE)); | |
| 1341 } | |
| 1342 | |
| 1343 COMPILE_ASSERT(sizeof(Float4) == 4 * sizeof(float), struct_is_densely_packed); | |
| 1344 COMPILE_ASSERT(sizeof(Float16) == 16 * sizeof(float), | |
| 1345 struct_is_densely_packed); | |
| 1346 | |
| 1347 // Upload the tranforms for both points and uvs. | |
| 1348 GLC(context_, | |
| 1349 context_->uniformMatrix4fv( | |
| 1350 static_cast<int>(draw_cache_.matrix_location), | |
| 1351 static_cast<int>(draw_cache_.matrix_data.size()), | |
| 1352 false, | |
| 1353 reinterpret_cast<float*>(&draw_cache_.matrix_data.front()))); | |
| 1354 GLC(context_, | |
| 1355 context_->uniform4fv( | |
| 1356 static_cast<int>(draw_cache_.uv_xform_location), | |
| 1357 static_cast<int>(draw_cache_.uv_xform_data.size()), | |
| 1358 reinterpret_cast<float*>(&draw_cache_.uv_xform_data.front()))); | |
| 1359 GLC(context_, | |
| 1360 context_->uniform1fv( | |
| 1361 static_cast<int>(draw_cache_.vertex_opacity_location), | |
| 1362 static_cast<int>(draw_cache_.vertex_opacity_data.size()), | |
| 1363 static_cast<float*>(&draw_cache_.vertex_opacity_data.front()))); | |
| 1364 | |
| 1365 // Draw the quads! | |
| 1366 GLC(context_, | |
| 1367 context_->drawElements(GL_TRIANGLES, | |
| 1368 6 * draw_cache_.matrix_data.size(), | |
| 1369 GL_UNSIGNED_SHORT, | |
| 1370 0)); | |
| 1371 | |
| 1372 // Clean up after ourselves (reset state set above). | |
| 1373 if (!draw_cache_.use_premultiplied_alpha) | |
| 1374 GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); | |
| 1375 | |
| 1376 // Clear the cache. | |
| 1377 draw_cache_.program_id = 0; | |
| 1378 draw_cache_.uv_xform_data.resize(0); | |
| 1379 draw_cache_.vertex_opacity_data.resize(0); | |
| 1380 draw_cache_.matrix_data.resize(0); | |
| 1381 } | |
| 1382 | |
| 1383 void GLRenderer::EnqueueTextureQuad(const DrawingFrame& frame, | |
| 1384 const TextureDrawQuad* quad) { | |
| 1385 // Choose the correct texture program binding | |
| 1386 TexTransformTextureProgramBinding binding; | |
| 1387 if (quad->flipped) | |
| 1388 binding.Set(GetTextureProgramFlip(), Context()); | |
| 1389 else | |
| 1390 binding.Set(GetTextureProgram(), Context()); | |
| 1391 | |
| 1392 int resource_id = quad->resource_id; | |
| 1393 | |
| 1394 if (draw_cache_.program_id != binding.program_id || | |
| 1395 draw_cache_.resource_id != resource_id || | |
| 1396 draw_cache_.use_premultiplied_alpha != quad->premultiplied_alpha || | |
| 1397 draw_cache_.needs_blending != quad->ShouldDrawWithBlending() || | |
| 1398 draw_cache_.matrix_data.size() >= 8) { | |
| 1399 FlushTextureQuadCache(); | |
| 1400 draw_cache_.program_id = binding.program_id; | |
| 1401 draw_cache_.resource_id = resource_id; | |
| 1402 draw_cache_.use_premultiplied_alpha = quad->premultiplied_alpha; | |
| 1403 draw_cache_.needs_blending = quad->ShouldDrawWithBlending(); | |
| 1404 | |
| 1405 draw_cache_.uv_xform_location = binding.tex_transform_location; | |
| 1406 draw_cache_.vertex_opacity_location = binding.vertex_opacity_location; | |
| 1407 draw_cache_.matrix_location = binding.matrix_location; | |
| 1408 draw_cache_.sampler_location = binding.sampler_location; | |
| 1409 } | |
| 1410 | |
| 1411 // Generate the uv-transform | |
| 1412 gfx::PointF uv0 = quad->uv_top_left; | |
| 1413 gfx::PointF uv1 = quad->uv_bottom_right; | |
| 1414 Float4 uv = { { uv0.x(), uv0.y(), uv1.x() - uv0.x(), uv1.y() - uv0.y() } }; | |
| 1415 draw_cache_.uv_xform_data.push_back(uv); | |
| 1416 | |
| 1417 // Generate the vertex opacity | |
| 1418 const float opacity = quad->opacity(); | |
| 1419 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[0] * opacity); | |
| 1420 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[1] * opacity); | |
| 1421 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[2] * opacity); | |
| 1422 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[3] * opacity); | |
| 1423 | |
| 1424 // Generate the transform matrix | |
| 1425 gfx::Transform quad_rect_matrix; | |
| 1426 QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect); | |
| 1427 quad_rect_matrix = frame.projection_matrix * quad_rect_matrix; | |
| 1428 | |
| 1429 Float16 m; | |
| 1430 quad_rect_matrix.matrix().asColMajorf(m.data); | |
| 1431 draw_cache_.matrix_data.push_back(m); | |
| 1432 } | |
| 1433 | |
| 1434 void GLRenderer::DrawTextureQuad(const DrawingFrame& frame, | |
| 1435 const TextureDrawQuad* quad) { | |
| 1436 TexTransformTextureProgramBinding binding; | |
| 1437 if (quad->flipped) | |
| 1438 binding.Set(GetTextureProgramFlip(), Context()); | |
| 1439 else | |
| 1440 binding.Set(GetTextureProgram(), Context()); | |
| 1441 SetUseProgram(binding.program_id); | |
| 1442 GLC(Context(), Context()->uniform1i(binding.sampler_location, 0)); | |
| 1443 gfx::PointF uv0 = quad->uv_top_left; | |
| 1444 gfx::PointF uv1 = quad->uv_bottom_right; | |
| 1445 GLC(Context(), | |
| 1446 Context()->uniform4f(binding.tex_transform_location, | |
| 1447 uv0.x(), | |
| 1448 uv0.y(), | |
| 1449 uv1.x() - uv0.x(), | |
| 1450 uv1.y() - uv0.y())); | |
| 1451 | |
| 1452 GLC(Context(), | |
| 1453 Context()->uniform1fv( | |
| 1454 binding.vertex_opacity_location, 4, quad->vertex_opacity)); | |
| 1455 | |
| 1456 ResourceProvider::ScopedSamplerGL quad_resource_lock( | |
| 1457 resource_provider_, quad->resource_id, GL_TEXTURE_2D, GL_LINEAR); | |
| 1458 | |
| 1459 if (!quad->premultiplied_alpha) { | |
| 1460 // As it turns out, the premultiplied alpha blending function (ONE, | |
| 1461 // ONE_MINUS_SRC_ALPHA) will never cause the alpha channel to be set to | |
| 1462 // anything less than 1.0f if it is initialized to that value! Therefore, | |
| 1463 // premultipliedAlpha being false is the first situation we can generally | |
| 1464 // see an alpha channel less than 1.0f coming out of the compositor. This is | |
| 1465 // causing platform differences in some layout tests (see | |
| 1466 // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use | |
| 1467 // a separate blend function for the alpha channel to avoid modifying it. | |
| 1468 // Don't use colorMask for this as it has performance implications on some | |
| 1469 // platforms. | |
| 1470 GLC(Context(), | |
| 1471 Context()->blendFuncSeparate( | |
| 1472 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE)); | |
| 1473 } | |
| 1474 | |
| 1475 DrawQuadGeometry( | |
| 1476 frame, quad->quadTransform(), quad->rect, binding.matrix_location); | |
| 1477 | |
| 1478 if (!quad->premultiplied_alpha) | |
| 1479 GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); | |
| 1480 } | |
| 1481 | |
| 1482 void GLRenderer::DrawIOSurfaceQuad(const DrawingFrame& frame, | |
| 1483 const IOSurfaceDrawQuad* quad) { | |
| 1484 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
| 1485 | |
| 1486 TexTransformTextureProgramBinding binding; | |
| 1487 binding.Set(GetTextureIOSurfaceProgram(), Context()); | |
| 1488 | |
| 1489 SetUseProgram(binding.program_id); | |
| 1490 GLC(Context(), Context()->uniform1i(binding.sampler_location, 0)); | |
| 1491 if (quad->orientation == IOSurfaceDrawQuad::FLIPPED) { | |
| 1492 GLC(Context(), | |
| 1493 Context()->uniform4f(binding.tex_transform_location, | |
| 1494 0, | |
| 1495 quad->io_surface_size.height(), | |
| 1496 quad->io_surface_size.width(), | |
| 1497 quad->io_surface_size.height() * -1.0f)); | |
| 1498 } else { | |
| 1499 GLC(Context(), | |
| 1500 Context()->uniform4f(binding.tex_transform_location, | |
| 1501 0, | |
| 1502 0, | |
| 1503 quad->io_surface_size.width(), | |
| 1504 quad->io_surface_size.height())); | |
| 1505 } | |
| 1506 | |
| 1507 const float vertex_opacity[] = { quad->opacity(), quad->opacity(), | |
| 1508 quad->opacity(), quad->opacity() }; | |
| 1509 GLC(Context(), | |
| 1510 Context()->uniform1fv( | |
| 1511 binding.vertex_opacity_location, 4, vertex_opacity)); | |
| 1512 | |
| 1513 GLC(Context(), | |
| 1514 Context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB, | |
| 1515 quad->io_surface_texture_id)); | |
| 1516 | |
| 1517 DrawQuadGeometry( | |
| 1518 frame, quad->quadTransform(), quad->rect, binding.matrix_location); | |
| 1519 | |
| 1520 GLC(Context(), Context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB, 0)); | |
| 1521 } | |
| 1522 | |
| 1523 void GLRenderer::FinishDrawingFrame(DrawingFrame& frame) { | |
| 1524 current_framebuffer_lock_.reset(); | |
| 1525 swap_buffer_rect_.Union(gfx::ToEnclosingRect(frame.root_damage_rect)); | |
| 1526 | |
| 1527 GLC(context_, context_->disable(GL_BLEND)); | |
| 1528 blend_shadow_ = false; | |
| 1529 | |
| 1530 if (Settings().compositorFrameMessage) { | |
| 1531 CompositorFrame compositor_frame; | |
| 1532 compositor_frame.metadata = client_->MakeCompositorFrameMetadata(); | |
| 1533 output_surface_->SendFrameToParentCompositor(&compositor_frame); | |
| 1534 } | |
| 1535 } | |
| 1536 | |
| 1537 void GLRenderer::FinishDrawingQuadList() { FlushTextureQuadCache(); } | |
| 1538 | |
| 1539 bool GLRenderer::FlippedFramebuffer() const { return true; } | |
| 1540 | |
| 1541 void GLRenderer::EnsureScissorTestEnabled() { | |
| 1542 if (is_scissor_enabled_) | |
| 1543 return; | |
| 1544 | |
| 1545 FlushTextureQuadCache(); | |
| 1546 GLC(context_, context_->enable(GL_SCISSOR_TEST)); | |
| 1547 is_scissor_enabled_ = true; | |
| 1548 } | |
| 1549 | |
| 1550 void GLRenderer::EnsureScissorTestDisabled() { | |
| 1551 if (!is_scissor_enabled_) | |
| 1552 return; | |
| 1553 | |
| 1554 FlushTextureQuadCache(); | |
| 1555 GLC(context_, context_->disable(GL_SCISSOR_TEST)); | |
| 1556 is_scissor_enabled_ = false; | |
| 1557 } | |
| 1558 | |
| 1559 void GLRenderer::ToGLMatrix(float* gl_matrix, const gfx::Transform& transform) { | |
| 1560 transform.matrix().asColMajorf(gl_matrix); | |
| 1561 } | |
| 1562 | |
| 1563 void GLRenderer::SetShaderQuadF(const gfx::QuadF& quad, int quad_location) { | |
| 1564 if (quad_location == -1) | |
| 1565 return; | |
| 1566 | |
| 1567 float point[8]; | |
| 1568 point[0] = quad.p1().x(); | |
| 1569 point[1] = quad.p1().y(); | |
| 1570 point[2] = quad.p2().x(); | |
| 1571 point[3] = quad.p2().y(); | |
| 1572 point[4] = quad.p3().x(); | |
| 1573 point[5] = quad.p3().y(); | |
| 1574 point[6] = quad.p4().x(); | |
| 1575 point[7] = quad.p4().y(); | |
| 1576 GLC(context_, context_->uniform2fv(quad_location, 4, point)); | |
| 1577 } | |
| 1578 | |
| 1579 void GLRenderer::SetShaderOpacity(float opacity, int alpha_location) { | |
| 1580 if (alpha_location != -1) | |
| 1581 GLC(context_, context_->uniform1f(alpha_location, opacity)); | |
| 1582 } | |
| 1583 | |
| 1584 void GLRenderer::SetBlendEnabled(bool enabled) { | |
| 1585 if (enabled == blend_shadow_) | |
| 1586 return; | |
| 1587 | |
| 1588 if (enabled) | |
| 1589 GLC(context_, context_->enable(GL_BLEND)); | |
| 1590 else | |
| 1591 GLC(context_, context_->disable(GL_BLEND)); | |
| 1592 blend_shadow_ = enabled; | |
| 1593 } | |
| 1594 | |
| 1595 void GLRenderer::SetUseProgram(unsigned program) { | |
| 1596 if (program == program_shadow_) | |
| 1597 return; | |
| 1598 GLC(context_, context_->useProgram(program)); | |
| 1599 program_shadow_ = program; | |
| 1600 } | |
| 1601 | |
| 1602 void GLRenderer::DrawQuadGeometry(const DrawingFrame& frame, | |
| 1603 const gfx::Transform& draw_transform, | |
| 1604 const gfx::RectF& quad_rect, | |
| 1605 int matrix_location) { | |
| 1606 gfx::Transform quad_rect_matrix; | |
| 1607 QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect); | |
| 1608 static float gl_matrix[16]; | |
| 1609 ToGLMatrix(&gl_matrix[0], frame.projection_matrix * quad_rect_matrix); | |
| 1610 GLC(context_, | |
| 1611 context_->uniformMatrix4fv(matrix_location, 1, false, &gl_matrix[0])); | |
| 1612 | |
| 1613 GLC(context_, context_->drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0)); | |
| 1614 } | |
| 1615 | |
| 1616 void GLRenderer::CopyTextureToFramebuffer(const DrawingFrame& frame, | |
| 1617 int texture_id, | |
| 1618 gfx::Rect rect, | |
| 1619 const gfx::Transform& draw_matrix) { | |
| 1620 const RenderPassProgram* program = GetRenderPassProgram(); | |
| 1621 | |
| 1622 GLC(Context(), Context()->bindTexture(GL_TEXTURE_2D, texture_id)); | |
| 1623 | |
| 1624 SetUseProgram(program->program()); | |
| 1625 GLC(Context(), | |
| 1626 Context()->uniform1i(program->fragment_shader().samplerLocation(), 0)); | |
| 1627 GLC(Context(), | |
| 1628 Context()->uniform4f(program->vertex_shader().texTransformLocation(), | |
| 1629 0.0f, | |
| 1630 0.0f, | |
| 1631 1.0f, | |
| 1632 1.0f)); | |
| 1633 SetShaderOpacity(1, program->fragment_shader().alphaLocation()); | |
| 1634 DrawQuadGeometry( | |
| 1635 frame, draw_matrix, rect, program->vertex_shader().matrixLocation()); | |
| 1636 } | |
| 1637 | |
| 1638 void GLRenderer::Finish() { | |
| 1639 TRACE_EVENT0("cc", "GLRenderer::finish"); | |
| 1640 context_->finish(); | |
| 1641 } | |
| 1642 | |
| 1643 bool GLRenderer::SwapBuffers() { | |
| 1644 DCHECK(visible_); | |
| 1645 DCHECK(!is_backbuffer_discarded_); | |
| 1646 | |
| 1647 TRACE_EVENT0("cc", "GLRenderer::swapBuffers"); | |
| 1648 // We're done! Time to swapbuffers! | |
| 1649 | |
| 1650 if (capabilities_.using_partial_swap) { | |
| 1651 // If supported, we can save significant bandwidth by only swapping the | |
| 1652 // damaged/scissored region (clamped to the viewport) | |
| 1653 swap_buffer_rect_.Intersect(gfx::Rect(gfx::Point(), ViewportSize())); | |
| 1654 int flipped_y_pos_of_rect_bottom = | |
| 1655 ViewportHeight() - swap_buffer_rect_.y() - swap_buffer_rect_.height(); | |
| 1656 output_surface_->PostSubBuffer(gfx::Rect(swap_buffer_rect_.x(), | |
| 1657 flipped_y_pos_of_rect_bottom, | |
| 1658 swap_buffer_rect_.width(), | |
| 1659 swap_buffer_rect_.height())); | |
| 1660 } else { | |
| 1661 output_surface_->SwapBuffers(); | |
| 1662 } | |
| 1663 | |
| 1664 swap_buffer_rect_ = gfx::Rect(); | |
| 1665 | |
| 1666 // We don't have real fences, so we mark read fences as passed | |
| 1667 // assuming a double-buffered GPU pipeline. A texture can be | |
| 1668 // written to after one full frame has past since it was last read. | |
| 1669 if (last_swap_fence_) | |
| 1670 static_cast<SimpleSwapFence*>(last_swap_fence_.get())->SetHasPassed(); | |
| 1671 last_swap_fence_ = resource_provider_->GetReadLockFence(); | |
| 1672 resource_provider_->SetReadLockFence(new SimpleSwapFence()); | |
| 1673 | |
| 1674 return true; | |
| 1675 } | |
| 1676 | |
| 1677 void GLRenderer::ReceiveCompositorFrameAck(const CompositorFrameAck& ack) { | |
| 1678 onSwapBuffersComplete(); | |
| 1679 } | |
| 1680 | |
| 1681 void GLRenderer::onSwapBuffersComplete() { client_->OnSwapBuffersComplete(); } | |
| 1682 | |
| 1683 void GLRenderer::onMemoryAllocationChanged( | |
| 1684 WebGraphicsMemoryAllocation allocation) { | |
| 1685 // Just ignore the memory manager when it says to set the limit to zero | |
| 1686 // bytes. This will happen when the memory manager thinks that the renderer | |
| 1687 // is not visible (which the renderer knows better). | |
| 1688 if (allocation.bytesLimitWhenVisible) { | |
| 1689 ManagedMemoryPolicy policy( | |
| 1690 allocation.bytesLimitWhenVisible, | |
| 1691 PriorityCutoff(allocation.priorityCutoffWhenVisible), | |
| 1692 allocation.bytesLimitWhenNotVisible, | |
| 1693 PriorityCutoff(allocation.priorityCutoffWhenNotVisible)); | |
| 1694 | |
| 1695 if (allocation.enforceButDoNotKeepAsPolicy) | |
| 1696 client_->EnforceManagedMemoryPolicy(policy); | |
| 1697 else | |
| 1698 client_->SetManagedMemoryPolicy(policy); | |
| 1699 } | |
| 1700 | |
| 1701 bool old_discard_backbuffer_when_not_visible = | |
| 1702 discard_backbuffer_when_not_visible_; | |
| 1703 discard_backbuffer_when_not_visible_ = !allocation.suggestHaveBackbuffer; | |
| 1704 EnforceMemoryPolicy(); | |
| 1705 if (allocation.enforceButDoNotKeepAsPolicy) | |
| 1706 discard_backbuffer_when_not_visible_ = | |
| 1707 old_discard_backbuffer_when_not_visible; | |
| 1708 } | |
| 1709 | |
| 1710 ManagedMemoryPolicy::PriorityCutoff GLRenderer::PriorityCutoff( | |
| 1711 WebKit::WebGraphicsMemoryAllocation::PriorityCutoff priority_cutoff) { | |
| 1712 // This is simple a 1:1 map, the names differ only because the WebKit names | |
| 1713 // should be to match the cc names. | |
| 1714 switch (priority_cutoff) { | |
| 1715 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowNothing: | |
| 1716 return ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING; | |
| 1717 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleOnly: | |
| 1718 return ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY; | |
| 1719 case WebKit::WebGraphicsMemoryAllocation:: | |
| 1720 PriorityCutoffAllowVisibleAndNearby: | |
| 1721 return ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE; | |
| 1722 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowEverything: | |
| 1723 return ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING; | |
| 1724 } | |
| 1725 NOTREACHED(); | |
| 1726 return ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING; | |
| 1727 } | |
| 1728 | |
| 1729 void GLRenderer::EnforceMemoryPolicy() { | |
| 1730 if (!visible_) { | |
| 1731 TRACE_EVENT0("cc", "GLRenderer::enforceMemoryPolicy dropping resources"); | |
| 1732 ReleaseRenderPassTextures(); | |
| 1733 if (discard_backbuffer_when_not_visible_) | |
| 1734 DiscardBackbuffer(); | |
| 1735 resource_provider_->ReleaseCachedData(); | |
| 1736 GLC(context_, context_->flush()); | |
| 1737 } | |
| 1738 } | |
| 1739 | |
| 1740 void GLRenderer::DiscardBackbuffer() { | |
| 1741 if (is_backbuffer_discarded_) | |
| 1742 return; | |
| 1743 | |
| 1744 output_surface_->DiscardBackbuffer(); | |
| 1745 | |
| 1746 is_backbuffer_discarded_ = true; | |
| 1747 | |
| 1748 // Damage tracker needs a full reset every time framebuffer is discarded. | |
| 1749 client_->SetFullRootLayerDamage(); | |
| 1750 } | |
| 1751 | |
| 1752 void GLRenderer::EnsureBackbuffer() { | |
| 1753 if (!is_backbuffer_discarded_) | |
| 1754 return; | |
| 1755 | |
| 1756 output_surface_->EnsureBackbuffer(); | |
| 1757 is_backbuffer_discarded_ = false; | |
| 1758 } | |
| 1759 | |
| 1760 void GLRenderer::onContextLost() { client_->DidLoseOutputSurface(); } | |
| 1761 | |
| 1762 void GLRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) { | |
| 1763 DCHECK(rect.right() <= ViewportWidth()); | |
| 1764 DCHECK(rect.bottom() <= ViewportHeight()); | |
| 1765 | |
| 1766 if (!pixels) | |
| 1767 return; | |
| 1768 | |
| 1769 MakeContextCurrent(); | |
| 1770 | |
| 1771 bool do_workaround = NeedsIOSurfaceReadbackWorkaround(); | |
| 1772 | |
| 1773 GLuint temporary_texture = 0; | |
| 1774 GLuint temporary_fbo = 0; | |
| 1775 | |
| 1776 if (do_workaround) { | |
| 1777 // On Mac OS X, calling glReadPixels against an FBO whose color attachment | |
| 1778 // is an IOSurface-backed texture causes corruption of future glReadPixels | |
| 1779 // calls, even those on different OpenGL contexts. It is believed that this | |
| 1780 // is the root cause of top crasher | |
| 1781 // http://crbug.com/99393. <rdar://problem/10949687> | |
| 1782 | |
| 1783 temporary_texture = context_->createTexture(); | |
| 1784 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, temporary_texture)); | |
| 1785 GLC(context_, | |
| 1786 context_->texParameteri( | |
| 1787 GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); | |
| 1788 GLC(context_, | |
| 1789 context_->texParameteri( | |
| 1790 GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); | |
| 1791 GLC(context_, | |
| 1792 context_->texParameteri( | |
| 1793 GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); | |
| 1794 GLC(context_, | |
| 1795 context_->texParameteri( | |
| 1796 GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); | |
| 1797 // Copy the contents of the current (IOSurface-backed) framebuffer into a | |
| 1798 // temporary texture. | |
| 1799 GLC(context_, | |
| 1800 context_->copyTexImage2D(GL_TEXTURE_2D, | |
| 1801 0, | |
| 1802 GL_RGBA, | |
| 1803 0, | |
| 1804 0, | |
| 1805 ViewportSize().width(), | |
| 1806 ViewportSize().height(), | |
| 1807 0)); | |
| 1808 temporary_fbo = context_->createFramebuffer(); | |
| 1809 // Attach this texture to an FBO, and perform the readback from that FBO. | |
| 1810 GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, temporary_fbo)); | |
| 1811 GLC(context_, | |
| 1812 context_->framebufferTexture2D(GL_FRAMEBUFFER, | |
| 1813 GL_COLOR_ATTACHMENT0, | |
| 1814 GL_TEXTURE_2D, | |
| 1815 temporary_texture, | |
| 1816 0)); | |
| 1817 | |
| 1818 DCHECK(context_->checkFramebufferStatus(GL_FRAMEBUFFER) == | |
| 1819 GL_FRAMEBUFFER_COMPLETE); | |
| 1820 } | |
| 1821 | |
| 1822 scoped_array<uint8_t> src_pixels( | |
| 1823 new uint8_t[rect.width() * rect.height() * 4]); | |
| 1824 GLC(context_, | |
| 1825 context_->readPixels(rect.x(), | |
| 1826 ViewportSize().height() - rect.bottom(), | |
| 1827 rect.width(), | |
| 1828 rect.height(), | |
| 1829 GL_RGBA, | |
| 1830 GL_UNSIGNED_BYTE, | |
| 1831 src_pixels.get())); | |
| 1832 | |
| 1833 uint8_t* dest_pixels = static_cast<uint8_t*>(pixels); | |
| 1834 size_t row_bytes = rect.width() * 4; | |
| 1835 int num_rows = rect.height(); | |
| 1836 size_t total_bytes = num_rows * row_bytes; | |
| 1837 for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) { | |
| 1838 // Flip Y axis. | |
| 1839 size_t src_y = total_bytes - dest_y - row_bytes; | |
| 1840 // Swizzle BGRA -> RGBA. | |
| 1841 for (size_t x = 0; x < row_bytes; x += 4) { | |
| 1842 dest_pixels[dest_y + (x + 0)] = src_pixels.get()[src_y + (x + 2)]; | |
| 1843 dest_pixels[dest_y + (x + 1)] = src_pixels.get()[src_y + (x + 1)]; | |
| 1844 dest_pixels[dest_y + (x + 2)] = src_pixels.get()[src_y + (x + 0)]; | |
| 1845 dest_pixels[dest_y + (x + 3)] = src_pixels.get()[src_y + (x + 3)]; | |
| 1846 } | |
| 1847 } | |
| 1848 | |
| 1849 if (do_workaround) { | |
| 1850 // Clean up. | |
| 1851 GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, 0)); | |
| 1852 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0)); | |
| 1853 GLC(context_, context_->deleteFramebuffer(temporary_fbo)); | |
| 1854 GLC(context_, context_->deleteTexture(temporary_texture)); | |
| 1855 } | |
| 1856 | |
| 1857 EnforceMemoryPolicy(); | |
| 1858 } | |
| 1859 | |
| 1860 bool GLRenderer::GetFramebufferTexture(ScopedResource* texture, | |
| 1861 gfx::Rect device_rect) { | |
| 1862 DCHECK(!texture->id() || (texture->size() == device_rect.size() && | |
| 1863 texture->format() == GL_RGB)); | |
| 1864 | |
| 1865 if (!texture->id() && !texture->Allocate(device_rect.size(), | |
| 1866 GL_RGB, | |
| 1867 ResourceProvider::TextureUsageAny)) | |
| 1868 return false; | |
| 1869 | |
| 1870 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, texture->id()); | |
| 1871 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, lock.texture_id())); | |
| 1872 GLC(context_, | |
| 1873 context_->copyTexImage2D(GL_TEXTURE_2D, | |
| 1874 0, | |
| 1875 texture->format(), | |
| 1876 device_rect.x(), | |
| 1877 device_rect.y(), | |
| 1878 device_rect.width(), | |
| 1879 device_rect.height(), | |
| 1880 0)); | |
| 1881 return true; | |
| 1882 } | |
| 1883 | |
| 1884 bool GLRenderer::UseScopedTexture(DrawingFrame& frame, | |
| 1885 const ScopedResource* texture, | |
| 1886 gfx::Rect viewport_rect) { | |
| 1887 DCHECK(texture->id()); | |
| 1888 frame.current_render_pass = 0; | |
| 1889 frame.current_texture = texture; | |
| 1890 | |
| 1891 return BindFramebufferToTexture(frame, texture, viewport_rect); | |
| 1892 } | |
| 1893 | |
| 1894 void GLRenderer::BindFramebufferToOutputSurface(DrawingFrame& frame) { | |
| 1895 current_framebuffer_lock_.reset(); | |
| 1896 output_surface_->BindFramebuffer(); | |
| 1897 } | |
| 1898 | |
| 1899 bool GLRenderer::BindFramebufferToTexture(DrawingFrame& frame, | |
| 1900 const ScopedResource* texture, | |
| 1901 gfx::Rect framebuffer_rect) { | |
| 1902 DCHECK(texture->id()); | |
| 1903 | |
| 1904 GLC(context_, | |
| 1905 context_->bindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_)); | |
| 1906 current_framebuffer_lock_ = | |
| 1907 make_scoped_ptr(new ResourceProvider::ScopedWriteLockGL( | |
| 1908 resource_provider_, texture->id())); | |
| 1909 unsigned texture_id = current_framebuffer_lock_->texture_id(); | |
| 1910 GLC(context_, | |
| 1911 context_->framebufferTexture2D( | |
| 1912 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0)); | |
| 1913 | |
| 1914 DCHECK(context_->checkFramebufferStatus(GL_FRAMEBUFFER) == | |
| 1915 GL_FRAMEBUFFER_COMPLETE || IsContextLost()); | |
| 1916 | |
| 1917 InitializeMatrices(frame, framebuffer_rect, false); | |
| 1918 SetDrawViewportSize(framebuffer_rect.size()); | |
| 1919 | |
| 1920 return true; | |
| 1921 } | |
| 1922 | |
| 1923 void GLRenderer::SetScissorTestRect(gfx::Rect scissor_rect) { | |
| 1924 EnsureScissorTestEnabled(); | |
| 1925 | |
| 1926 // Don't unnecessarily ask the context to change the scissor, because it | |
| 1927 // may cause undesired GPU pipeline flushes. | |
| 1928 if (scissor_rect == scissor_rect_) | |
| 1929 return; | |
| 1930 | |
| 1931 scissor_rect_ = scissor_rect; | |
| 1932 FlushTextureQuadCache(); | |
| 1933 GLC(context_, | |
| 1934 context_->scissor(scissor_rect.x(), | |
| 1935 scissor_rect.y(), | |
| 1936 scissor_rect.width(), | |
| 1937 scissor_rect.height())); | |
| 1938 } | |
| 1939 | |
| 1940 void GLRenderer::SetDrawViewportSize(gfx::Size viewport_size) { | |
| 1941 GLC(context_, | |
| 1942 context_->viewport(0, 0, viewport_size.width(), viewport_size.height())); | |
| 1943 } | |
| 1944 | |
| 1945 bool GLRenderer::MakeContextCurrent() { return context_->makeContextCurrent(); } | |
| 1946 | |
| 1947 bool GLRenderer::InitializeSharedObjects() { | |
| 1948 TRACE_EVENT0("cc", "GLRenderer::initializeSharedObjects"); | |
| 1949 MakeContextCurrent(); | |
| 1950 | |
| 1951 // Create an FBO for doing offscreen rendering. | |
| 1952 GLC(context_, offscreen_framebuffer_id_ = context_->createFramebuffer()); | |
| 1953 | |
| 1954 // We will always need these programs to render, so create the programs | |
| 1955 // eagerly so that the shader compilation can start while we do other work. | |
| 1956 // Other programs are created lazily on first access. | |
| 1957 shared_geometry_ = | |
| 1958 make_scoped_ptr(new GeometryBinding(context_, QuadVertexRect())); | |
| 1959 render_pass_program_ = make_scoped_ptr(new RenderPassProgram(context_)); | |
| 1960 tile_program_ = make_scoped_ptr(new TileProgram(context_)); | |
| 1961 tile_program_opaque_ = make_scoped_ptr(new TileProgramOpaque(context_)); | |
| 1962 | |
| 1963 GLC(context_, context_->flush()); | |
| 1964 | |
| 1965 return true; | |
| 1966 } | |
| 1967 | |
| 1968 const GLRenderer::TileCheckerboardProgram* | |
| 1969 GLRenderer::GetTileCheckerboardProgram() { | |
| 1970 if (!tile_checkerboard_program_) { | |
| 1971 tile_checkerboard_program_ = | |
| 1972 make_scoped_ptr(new TileCheckerboardProgram(context_)); | |
| 1973 } | |
| 1974 if (!tile_checkerboard_program_->initialized()) { | |
| 1975 TRACE_EVENT0("cc", "GLRenderer::checkerboardProgram::initalize"); | |
| 1976 tile_checkerboard_program_->Initialize(context_, is_using_bind_uniform_); | |
| 1977 } | |
| 1978 return tile_checkerboard_program_.get(); | |
| 1979 } | |
| 1980 | |
| 1981 const GLRenderer::DebugBorderProgram* GLRenderer::GetDebugBorderProgram() { | |
| 1982 if (!debug_border_program_) | |
| 1983 debug_border_program_ = make_scoped_ptr(new DebugBorderProgram(context_)); | |
| 1984 if (!debug_border_program_->initialized()) { | |
| 1985 TRACE_EVENT0("cc", "GLRenderer::debugBorderProgram::initialize"); | |
| 1986 debug_border_program_->Initialize(context_, is_using_bind_uniform_); | |
| 1987 } | |
| 1988 return debug_border_program_.get(); | |
| 1989 } | |
| 1990 | |
| 1991 const GLRenderer::SolidColorProgram* GLRenderer::GetSolidColorProgram() { | |
| 1992 if (!solid_color_program_) | |
| 1993 solid_color_program_ = make_scoped_ptr(new SolidColorProgram(context_)); | |
| 1994 if (!solid_color_program_->initialized()) { | |
| 1995 TRACE_EVENT0("cc", "GLRenderer::solidColorProgram::initialize"); | |
| 1996 solid_color_program_->Initialize(context_, is_using_bind_uniform_); | |
| 1997 } | |
| 1998 return solid_color_program_.get(); | |
| 1999 } | |
| 2000 | |
| 2001 const GLRenderer::SolidColorProgramAA* GLRenderer::GetSolidColorProgramAA() { | |
| 2002 if (!solid_color_program_aa_) { | |
| 2003 solid_color_program_aa_ = | |
| 2004 make_scoped_ptr(new SolidColorProgramAA(context_)); | |
| 2005 } | |
| 2006 if (!solid_color_program_aa_->initialized()) { | |
| 2007 TRACE_EVENT0("cc", "GLRenderer::solidColorProgramAA::initialize"); | |
| 2008 solid_color_program_aa_->Initialize(context_, is_using_bind_uniform_); | |
| 2009 } | |
| 2010 return solid_color_program_aa_.get(); | |
| 2011 } | |
| 2012 | |
| 2013 const GLRenderer::RenderPassProgram* GLRenderer::GetRenderPassProgram() { | |
| 2014 DCHECK(render_pass_program_); | |
| 2015 if (!render_pass_program_->initialized()) { | |
| 2016 TRACE_EVENT0("cc", "GLRenderer::renderPassProgram::initialize"); | |
| 2017 render_pass_program_->Initialize(context_, is_using_bind_uniform_); | |
| 2018 } | |
| 2019 return render_pass_program_.get(); | |
| 2020 } | |
| 2021 | |
| 2022 const GLRenderer::RenderPassProgramAA* GLRenderer::GetRenderPassProgramAA() { | |
| 2023 if (!render_pass_program_aa_) | |
| 2024 render_pass_program_aa_ = | |
| 2025 make_scoped_ptr(new RenderPassProgramAA(context_)); | |
| 2026 if (!render_pass_program_aa_->initialized()) { | |
| 2027 TRACE_EVENT0("cc", "GLRenderer::renderPassProgramAA::initialize"); | |
| 2028 render_pass_program_aa_->Initialize(context_, is_using_bind_uniform_); | |
| 2029 } | |
| 2030 return render_pass_program_aa_.get(); | |
| 2031 } | |
| 2032 | |
| 2033 const GLRenderer::RenderPassMaskProgram* | |
| 2034 GLRenderer::GetRenderPassMaskProgram() { | |
| 2035 if (!render_pass_mask_program_) | |
| 2036 render_pass_mask_program_ = | |
| 2037 make_scoped_ptr(new RenderPassMaskProgram(context_)); | |
| 2038 if (!render_pass_mask_program_->initialized()) { | |
| 2039 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgram::initialize"); | |
| 2040 render_pass_mask_program_->Initialize(context_, is_using_bind_uniform_); | |
| 2041 } | |
| 2042 return render_pass_mask_program_.get(); | |
| 2043 } | |
| 2044 | |
| 2045 const GLRenderer::RenderPassMaskProgramAA* | |
| 2046 GLRenderer::GetRenderPassMaskProgramAA() { | |
| 2047 if (!render_pass_mask_program_aa_) | |
| 2048 render_pass_mask_program_aa_ = | |
| 2049 make_scoped_ptr(new RenderPassMaskProgramAA(context_)); | |
| 2050 if (!render_pass_mask_program_aa_->initialized()) { | |
| 2051 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgramAA::initialize"); | |
| 2052 render_pass_mask_program_aa_->Initialize(context_, is_using_bind_uniform_); | |
| 2053 } | |
| 2054 return render_pass_mask_program_aa_.get(); | |
| 2055 } | |
| 2056 | |
| 2057 const GLRenderer::TileProgram* GLRenderer::GetTileProgram() { | |
| 2058 DCHECK(tile_program_); | |
| 2059 if (!tile_program_->initialized()) { | |
| 2060 TRACE_EVENT0("cc", "GLRenderer::tileProgram::initialize"); | |
| 2061 tile_program_->Initialize(context_, is_using_bind_uniform_); | |
| 2062 } | |
| 2063 return tile_program_.get(); | |
| 2064 } | |
| 2065 | |
| 2066 const GLRenderer::TileProgramOpaque* GLRenderer::GetTileProgramOpaque() { | |
| 2067 DCHECK(tile_program_opaque_); | |
| 2068 if (!tile_program_opaque_->initialized()) { | |
| 2069 TRACE_EVENT0("cc", "GLRenderer::tileProgramOpaque::initialize"); | |
| 2070 tile_program_opaque_->Initialize(context_, is_using_bind_uniform_); | |
| 2071 } | |
| 2072 return tile_program_opaque_.get(); | |
| 2073 } | |
| 2074 | |
| 2075 const GLRenderer::TileProgramAA* GLRenderer::GetTileProgramAA() { | |
| 2076 if (!tile_program_aa_) | |
| 2077 tile_program_aa_ = make_scoped_ptr(new TileProgramAA(context_)); | |
| 2078 if (!tile_program_aa_->initialized()) { | |
| 2079 TRACE_EVENT0("cc", "GLRenderer::tileProgramAA::initialize"); | |
| 2080 tile_program_aa_->Initialize(context_, is_using_bind_uniform_); | |
| 2081 } | |
| 2082 return tile_program_aa_.get(); | |
| 2083 } | |
| 2084 | |
| 2085 const GLRenderer::TileProgramSwizzle* GLRenderer::GetTileProgramSwizzle() { | |
| 2086 if (!tile_program_swizzle_) | |
| 2087 tile_program_swizzle_ = make_scoped_ptr(new TileProgramSwizzle(context_)); | |
| 2088 if (!tile_program_swizzle_->initialized()) { | |
| 2089 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzle::initialize"); | |
| 2090 tile_program_swizzle_->Initialize(context_, is_using_bind_uniform_); | |
| 2091 } | |
| 2092 return tile_program_swizzle_.get(); | |
| 2093 } | |
| 2094 | |
| 2095 const GLRenderer::TileProgramSwizzleOpaque* | |
| 2096 GLRenderer::GetTileProgramSwizzleOpaque() { | |
| 2097 if (!tile_program_swizzle_opaque_) | |
| 2098 tile_program_swizzle_opaque_ = | |
| 2099 make_scoped_ptr(new TileProgramSwizzleOpaque(context_)); | |
| 2100 if (!tile_program_swizzle_opaque_->initialized()) { | |
| 2101 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleOpaque::initialize"); | |
| 2102 tile_program_swizzle_opaque_->Initialize(context_, is_using_bind_uniform_); | |
| 2103 } | |
| 2104 return tile_program_swizzle_opaque_.get(); | |
| 2105 } | |
| 2106 | |
| 2107 const GLRenderer::TileProgramSwizzleAA* GLRenderer::GetTileProgramSwizzleAA() { | |
| 2108 if (!tile_program_swizzle_aa_) | |
| 2109 tile_program_swizzle_aa_ = | |
| 2110 make_scoped_ptr(new TileProgramSwizzleAA(context_)); | |
| 2111 if (!tile_program_swizzle_aa_->initialized()) { | |
| 2112 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleAA::initialize"); | |
| 2113 tile_program_swizzle_aa_->Initialize(context_, is_using_bind_uniform_); | |
| 2114 } | |
| 2115 return tile_program_swizzle_aa_.get(); | |
| 2116 } | |
| 2117 | |
| 2118 const GLRenderer::TextureProgram* GLRenderer::GetTextureProgram() { | |
| 2119 if (!texture_program_) | |
| 2120 texture_program_ = make_scoped_ptr(new TextureProgram(context_)); | |
| 2121 if (!texture_program_->initialized()) { | |
| 2122 TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize"); | |
| 2123 texture_program_->Initialize(context_, is_using_bind_uniform_); | |
| 2124 } | |
| 2125 return texture_program_.get(); | |
| 2126 } | |
| 2127 | |
| 2128 const GLRenderer::TextureProgramFlip* GLRenderer::GetTextureProgramFlip() { | |
| 2129 if (!texture_program_flip_) | |
| 2130 texture_program_flip_ = make_scoped_ptr(new TextureProgramFlip(context_)); | |
| 2131 if (!texture_program_flip_->initialized()) { | |
| 2132 TRACE_EVENT0("cc", "GLRenderer::textureProgramFlip::initialize"); | |
| 2133 texture_program_flip_->Initialize(context_, is_using_bind_uniform_); | |
| 2134 } | |
| 2135 return texture_program_flip_.get(); | |
| 2136 } | |
| 2137 | |
| 2138 const GLRenderer::TextureIOSurfaceProgram* | |
| 2139 GLRenderer::GetTextureIOSurfaceProgram() { | |
| 2140 if (!texture_io_surface_program_) | |
| 2141 texture_io_surface_program_ = | |
| 2142 make_scoped_ptr(new TextureIOSurfaceProgram(context_)); | |
| 2143 if (!texture_io_surface_program_->initialized()) { | |
| 2144 TRACE_EVENT0("cc", "GLRenderer::textureIOSurfaceProgram::initialize"); | |
| 2145 texture_io_surface_program_->Initialize(context_, is_using_bind_uniform_); | |
| 2146 } | |
| 2147 return texture_io_surface_program_.get(); | |
| 2148 } | |
| 2149 | |
| 2150 const GLRenderer::VideoYUVProgram* GLRenderer::GetVideoYUVProgram() { | |
| 2151 if (!video_yuv_program_) | |
| 2152 video_yuv_program_ = make_scoped_ptr(new VideoYUVProgram(context_)); | |
| 2153 if (!video_yuv_program_->initialized()) { | |
| 2154 TRACE_EVENT0("cc", "GLRenderer::videoYUVProgram::initialize"); | |
| 2155 video_yuv_program_->Initialize(context_, is_using_bind_uniform_); | |
| 2156 } | |
| 2157 return video_yuv_program_.get(); | |
| 2158 } | |
| 2159 | |
| 2160 const GLRenderer::VideoStreamTextureProgram* | |
| 2161 GLRenderer::GetVideoStreamTextureProgram() { | |
| 2162 if (!Capabilities().using_egl_image) | |
| 2163 return NULL; | |
| 2164 if (!video_stream_texture_program_) | |
| 2165 video_stream_texture_program_ = | |
| 2166 make_scoped_ptr(new VideoStreamTextureProgram(context_)); | |
| 2167 if (!video_stream_texture_program_->initialized()) { | |
| 2168 TRACE_EVENT0("cc", "GLRenderer::streamTextureProgram::initialize"); | |
| 2169 video_stream_texture_program_->Initialize(context_, is_using_bind_uniform_); | |
| 2170 } | |
| 2171 return video_stream_texture_program_.get(); | |
| 2172 } | |
| 2173 | |
| 2174 void GLRenderer::CleanupSharedObjects() { | |
| 2175 MakeContextCurrent(); | |
| 2176 | |
| 2177 shared_geometry_.reset(); | |
| 2178 | |
| 2179 if (tile_program_) | |
| 2180 tile_program_->Cleanup(context_); | |
| 2181 if (tile_program_opaque_) | |
| 2182 tile_program_opaque_->Cleanup(context_); | |
| 2183 if (tile_program_swizzle_) | |
| 2184 tile_program_swizzle_->Cleanup(context_); | |
| 2185 if (tile_program_swizzle_opaque_) | |
| 2186 tile_program_swizzle_opaque_->Cleanup(context_); | |
| 2187 if (tile_program_aa_) | |
| 2188 tile_program_aa_->Cleanup(context_); | |
| 2189 if (tile_program_swizzle_aa_) | |
| 2190 tile_program_swizzle_aa_->Cleanup(context_); | |
| 2191 if (tile_checkerboard_program_) | |
| 2192 tile_checkerboard_program_->Cleanup(context_); | |
| 2193 | |
| 2194 if (render_pass_mask_program_) | |
| 2195 render_pass_mask_program_->Cleanup(context_); | |
| 2196 if (render_pass_program_) | |
| 2197 render_pass_program_->Cleanup(context_); | |
| 2198 if (render_pass_mask_program_aa_) | |
| 2199 render_pass_mask_program_aa_->Cleanup(context_); | |
| 2200 if (render_pass_program_aa_) | |
| 2201 render_pass_program_aa_->Cleanup(context_); | |
| 2202 | |
| 2203 if (texture_program_) | |
| 2204 texture_program_->Cleanup(context_); | |
| 2205 if (texture_program_flip_) | |
| 2206 texture_program_flip_->Cleanup(context_); | |
| 2207 if (texture_io_surface_program_) | |
| 2208 texture_io_surface_program_->Cleanup(context_); | |
| 2209 | |
| 2210 if (video_yuv_program_) | |
| 2211 video_yuv_program_->Cleanup(context_); | |
| 2212 if (video_stream_texture_program_) | |
| 2213 video_stream_texture_program_->Cleanup(context_); | |
| 2214 | |
| 2215 if (debug_border_program_) | |
| 2216 debug_border_program_->Cleanup(context_); | |
| 2217 if (solid_color_program_) | |
| 2218 solid_color_program_->Cleanup(context_); | |
| 2219 if (solid_color_program_aa_) | |
| 2220 solid_color_program_aa_->Cleanup(context_); | |
| 2221 | |
| 2222 if (offscreen_framebuffer_id_) | |
| 2223 GLC(context_, context_->deleteFramebuffer(offscreen_framebuffer_id_)); | |
| 2224 | |
| 2225 ReleaseRenderPassTextures(); | |
| 2226 } | |
| 2227 | |
| 2228 bool GLRenderer::IsContextLost() { | |
| 2229 return (context_->getGraphicsResetStatusARB() != GL_NO_ERROR); | |
| 2230 } | |
| 2231 | |
| 2232 } // namespace cc | |
| OLD | NEW |