370}
371
372void LayerRendererChromium::drawRenderPass(const CCRenderPass* renderPass)
373{
374 CCRenderSurface* renderSurface = renderPass->targetSurface();
375 if (!useRenderSurface(renderSurface))
376 return;
377
378 // FIXME: eventually we should place this under a debug flag.
379 clearSurfaceForDebug(renderSurface, m_defaultRenderSurface, renderPass->surfaceDamageRect());
380
381 const CCQuadList& quadList = renderPass->quadList();
382 for (size_t i = 0; i < quadList.size(); ++i)
383 drawQuad(quadList[i].get(), renderPass->surfaceDamageRect());
384}
385
386void LayerRendererChromium::drawQuad(const CCDrawQuad* quad, const FloatRect& surfaceDamageRect)
387{
388 IntRect scissorRect;
389 if (m_capabilities.usingPartialSwap) {
390 FloatRect clipAndDamageRect = surfaceDamageRect;
391 if (!quad->clipRect().isEmpty())
392 clipAndDamageRect.intersect(quad->clipRect());
393 scissorRect = enclosingIntRect(clipAndDamageRect);
394 if (scissorRect.isEmpty())
395 return;
396 } else
397 scissorRect = quad->clipRect();
398
399 if (scissorRect.isEmpty())
400 GLC(m_context.get(), m_context->disable(GraphicsContext3D::SCISSOR_TEST));
401 else
402 setScissorToRect(scissorRect);
403
404 if (quad->needsBlending())
405 GLC(m_context.get(), m_context->enable(GraphicsContext3D::BLEND));
406 else
407 GLC(m_context.get(), m_context->disable(GraphicsContext3D::BLEND));
408
409 switch (quad->material()) {
410 case CCDrawQuad::Invalid:
411 ASSERT_NOT_REACHED();
412 break;
413 case CCDrawQuad::DebugBorder:
414 drawDebugBorderQuad(quad->toDebugBorderDrawQuad());
415 break;
416 case CCDrawQuad::RenderSurface:
417 drawRenderSurfaceQuad(quad->toRenderSurfaceDrawQuad());
418 break;
419 case CCDrawQuad::SolidColor:
420 drawSolidColorQuad(quad->toSolidColorDrawQuad());
421 break;
422 case CCDrawQuad::TiledContent:
423 drawTileQuad(quad->toTileDrawQuad());
424 break;
425 case CCDrawQuad::CustomLayer:
426 drawCustomLayerQuad(quad->toCustomLayerDrawQuad());
427 break;
428 }
429}
430
431void LayerRendererChromium::drawDebugBorderQuad(const CCDebugBorderDrawQuad* quad)
432{
433 static float glMatrix[16];
434 const LayerChromium::BorderProgram* program = borderProgram();
435 ASSERT(program && program->initialized());
436 GLC(context(), context()->useProgram(program->program()));
437
438 TransformationMatrix renderMatrix = quad->layerTransform();
439 const IntRect& layerRect = quad->quadRect();
440 renderMatrix.scaleNonUniform(layerRect.width(), layerRect.height());
441 LayerRendererChromium::toGLMatrix(&glMatrix[0], projectionMatrix() * renderMatrix);
442 GLC(context(), context()->uniformMatrix4fv(program->vertexShader().matrixLocation(), false, &glMatrix[0], 1));
443
444 GLC(context(), context()->uniform4f(program->fragmentShader().colorLocation(), quad->color().red() / 255.0, quad->color().green() / 255.0, quad->color().blue() / 255.0, 1));
445
446 GLC(context(), context()->lineWidth(quad->width()));
447
448 // The indices for the line are stored in the same array as the triangle indices.
449 GLC(context(), context()->drawElements(GraphicsContext3D::LINE_LOOP, 4, GraphicsContext3D::UNSIGNED_SHORT, 6 * sizeof(unsigned short)));
450}
451
452void LayerRendererChromium::drawRenderSurfaceQuad(const CCRenderSurfaceDrawQuad* quad)
453{
454 CCLayerImpl* layer = quad->layer();
455 layer->renderSurface()->draw(this, quad->surfaceDamageRect());
456 layer->renderSurface()->releaseContentsTexture();
457}
458
459void LayerRendererChromium::drawSolidColorQuad(const CCSolidColorDrawQuad* quad)
460{
461 const LayerChromium::BorderProgram* solidColorProgram = borderProgram();
462 GLC(context(), context()->useProgram(solidColorProgram->program()));
463
464 IntRect tileRect = quad->quadRect();
465
466 TransformationMatrix tileTransform = quad->quadTransform();
467 tileTransform.translate(tileRect.x() + tileRect.width() / 2.0, tileRect.y() + tileRect.height() / 2.0);
468
469 const Color& color = quad->color();
470
471 GLC(context(), context()->uniform4f(solidColorProgram->fragmentShader().colorLocation(), color.red(), color.green(), color.blue(), color.alpha()));
472
473 float opacity = quad->opacity();
474 drawTexturedQuad(tileTransform,
475 tileRect.width(), tileRect.height(), opacity, FloatQuad(),
476 solidColorProgram->vertexShader().matrixLocation(),
477 -1, -1);
478}
479
480struct TileProgramUniforms {
481 unsigned program;
482 unsigned samplerLocation;
483 unsigned vertexTexTransformLocation;
484 unsigned fragmentTexTransformLocation;
485 unsigned edgeLocation;
486 unsigned matrixLocation;
487 unsigned alphaLocation;
488 unsigned pointLocation;
489};
490
491template<class T>
492static void tileUniformLocation(T program, TileProgramUniforms& uniforms)
493{
494 uniforms.program = program->program();
495 uniforms.vertexTexTransformLocation = program->vertexShader().vertexTexTransformLocation();
496 uniforms.matrixLocation = program->vertexShader().matrixLocation();
497 uniforms.pointLocation = program->vertexShader().pointLocation();
498
499 uniforms.samplerLocation = program->fragmentShader().samplerLocation();
500 uniforms.alphaLocation = program->fragmentShader().alphaLocation();
501 uniforms.fragmentTexTransformLocation = program->fragmentShader().fragmentTexTransformLocation();
502 uniforms.edgeLocation = program->fragmentShader().edgeLocation();
503}
504
505static void findTileProgramUniforms(LayerRendererChromium* layerRenderer, const CCTileDrawQuad* quad, TileProgramUniforms& uniforms)
506{
507 if (quad->isAntialiased()) {
508 if (quad->swizzleContents()) {
509 const CCTiledLayerImpl::ProgramSwizzleAA* program = layerRenderer->tilerProgramSwizzleAA();
510 tileUniformLocation(program, uniforms);
511 } else {
512 const CCTiledLayerImpl::ProgramAA* program = layerRenderer->tilerProgramAA();
513 tileUniformLocation(program, uniforms);
514 }
515 } else {
516 if (quad->needsBlending()) {
517 if (quad->swizzleContents()) {
518 const CCTiledLayerImpl::ProgramSwizzle* program = layerRenderer->tilerProgramSwizzle();
519 tileUniformLocation(program, uniforms);
520 } else {
521 const CCTiledLayerImpl::Program* program = layerRenderer->tilerProgram();
522 tileUniformLocation(program, uniforms);
523 }
524 } else {
525 if (quad->swizzleContents()) {
526 const CCTiledLayerImpl::ProgramSwizzleOpaque* program = layerRenderer->tilerProgramSwizzleOpaque();
527 tileUniformLocation(program, uniforms);
528 } else {
529 const CCTiledLayerImpl::ProgramOpaque* program = layerRenderer->tilerProgramOpaque();
530 tileUniformLocation(program, uniforms);
531 }
532 }
533 }
534}
535
536void LayerRendererChromium::drawTileQuad(const CCTileDrawQuad* quad)
537{
538 const IntRect& tileRect = quad->quadRect();
539
540 FloatRect clampRect(tileRect);
541 // Clamp texture coordinates to avoid sampling outside the layer
542 // by deflating the tile region half a texel or half a texel
543 // minus epsilon for one pixel layers. The resulting clamp region
544 // is mapped to the unit square by the vertex shader and mapped
545 // back to normalized texture coordinates by the fragment shader
546 // after being clamped to 0-1 range.
547 const float epsilon = 1 / 1024.0f;
548 float clampX = min(0.5, clampRect.width() / 2.0 - epsilon);
549 float clampY = min(0.5, clampRect.height() / 2.0 - epsilon);
550 clampRect.inflateX(-clampX);
551 clampRect.inflateY(-clampY);
552 FloatSize clampOffset = clampRect.minXMinYCorner() - FloatRect(tileRect).minXMinYCorner();
553
554 FloatPoint textureOffset = quad->textureOffset() + clampOffset;
555
556 // Map clamping rectangle to unit square.
557 float vertexTexTranslateX = -clampRect.x() / clampRect.width();
558 float vertexTexTranslateY = -clampRect.y() / clampRect.height();
559 float vertexTexScaleX = tileRect.width() / clampRect.width();
560 float vertexTexScaleY = tileRect.height() / clampRect.height();
561
562 // Map to normalized texture coordinates.
563 const IntSize& textureSize = quad->textureSize();
564 float fragmentTexTranslateX = textureOffset.x() / textureSize.width();
565 float fragmentTexTranslateY = textureOffset.y() / textureSize.height();
566 float fragmentTexScaleX = clampRect.width() / textureSize.width();
567 float fragmentTexScaleY = clampRect.height() / textureSize.height();
568
569 TileProgramUniforms uniforms;
570 findTileProgramUniforms(this, quad, uniforms);
571
572 GLC(context(), context()->useProgram(uniforms.program));
573 GLC(context(), context()->uniform1i(uniforms.samplerLocation, 0));
574 GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE0));
575 GLC(context(), context()->bindTexture(GraphicsContext3D::TEXTURE_2D, quad->textureId()));
576 GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, quad->textureFilter()));
577 GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, quad->textureFilter()));
578
579 FloatQuad localQuad;
580 if (quad->isAntialiased()) {
581 TransformationMatrix deviceTransform = TransformationMatrix(windowMatrix() * projectionMatrix() * quad->quadTransform()).to2dTransform();
582 if (!deviceTransform.isInvertible())
583 return;
584
585 FloatQuad deviceLayerQuad = deviceTransform.mapQuad(FloatQuad(quad->layerRect()));
586
587 CCLayerQuad deviceLayerBounds = CCLayerQuad(FloatQuad(deviceLayerQuad.boundingBox()));
588 deviceLayerBounds.inflateAntiAliasingDistance();
589
590 CCLayerQuad deviceLayerEdges = CCLayerQuad(deviceLayerQuad);
591 deviceLayerEdges.inflateAntiAliasingDistance();
592
593 float edge[24];
594 deviceLayerEdges.toFloatArray(edge);
595 deviceLayerBounds.toFloatArray(&edge[12]);
596 GLC(context(), context()->uniform3fv(uniforms.edgeLocation, edge, 8));
597
598 GLC(context(), context()->uniform4f(uniforms.vertexTexTransformLocation, vertexTexTranslateX, vertexTexTranslateY, vertexTexScaleX, vertexTexScaleY));
599 GLC(context(), context()->uniform4f(uniforms.fragmentTexTransformLocation, fragmentTexTranslateX, fragmentTexTranslateY, fragmentTexScaleX, fragmentTexScaleY));
600
601 FloatPoint bottomRight(tileRect.maxX(), tileRect.maxY());
602 FloatPoint bottomLeft(tileRect.x(), tileRect.maxY());
603 FloatPoint topLeft(tileRect.x(), tileRect.y());
604 FloatPoint topRight(tileRect.maxX(), tileRect.y());
605
606 // Map points to device space.
607 bottomRight = deviceTransform.mapPoint(bottomRight);
608 bottomLeft = deviceTransform.mapPoint(bottomLeft);
609 topLeft = deviceTransform.mapPoint(topLeft);
610 topRight = deviceTransform.mapPoint(topRight);
611
612 CCLayerQuad::Edge bottomEdge(bottomRight, bottomLeft);
613 CCLayerQuad::Edge leftEdge(bottomLeft, topLeft);
614 CCLayerQuad::Edge topEdge(topLeft, topRight);
615 CCLayerQuad::Edge rightEdge(topRight, bottomRight);
616
617 if (quad->topEdgeAA())
618 topEdge = deviceLayerEdges.top();
619 if (quad->leftEdgeAA())
620 leftEdge = deviceLayerEdges.left();
621 if (quad->rightEdgeAA())
622 rightEdge = deviceLayerEdges.right();
623 if (quad->bottomEdgeAA())
624 bottomEdge = deviceLayerEdges.bottom();
625
626 float sign = FloatQuad(tileRect).isCounterclockwise() ? -1 : 1;
627 bottomEdge.scale(sign);
628 leftEdge.scale(sign);
629 topEdge.scale(sign);
630 rightEdge.scale(sign);
631
632 // Create device space quad.
633 CCLayerQuad deviceQuad(leftEdge, topEdge, rightEdge, bottomEdge);
634
635 // Map quad to layer space.
636 TransformationMatrix inverseDeviceTransform = deviceTransform.inverse();
637 localQuad = inverseDeviceTransform.mapQuad(deviceQuad.floatQuad());
638 } else {
639 // Move fragment shader transform to vertex shader. We can do this while
640 // still producing correct results as fragmentTexTransformLocation
641 // should always be non-negative when tiles are transformed in a way
642 // that could result in sampling outside the layer.
643 vertexTexScaleX *= fragmentTexScaleX;
644 vertexTexScaleY *= fragmentTexScaleY;
645 vertexTexTranslateX *= fragmentTexScaleX;
646 vertexTexTranslateY *= fragmentTexScaleY;
647 vertexTexTranslateX += fragmentTexTranslateX;
648 vertexTexTranslateY += fragmentTexTranslateY;
649
650 GLC(context(), context()->uniform4f(uniforms.vertexTexTransformLocation, vertexTexTranslateX, vertexTexTranslateY, vertexTexScaleX, vertexTexScaleY));
651
652 localQuad = FloatRect(tileRect);
653 }
654
655 // Normalize to tileRect.
656 localQuad.scale(1.0f / tileRect.width(), 1.0f / tileRect.height());