Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(317)

Side by Side Diff: src/effects/gradients/SkTwoPointConicalGradient.cpp

Issue 25645006: Allow gradient optimization with perspective (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: updated skipped tests Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright 2012 Google Inc. 2 * Copyright 2012 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkTwoPointConicalGradient.h" 8 #include "SkTwoPointConicalGradient.h"
9 9
10 static int valid_divide(float numer, float denom, float* ratio) { 10 static int valid_divide(float numer, float denom, float* ratio) {
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 const char* outputColor, 348 const char* outputColor,
349 const char* inputColor, 349 const char* inputColor,
350 const TransformedCoordsArray&, 350 const TransformedCoordsArray&,
351 const TextureSamplerArray&) SK_OVERRIDE; 351 const TextureSamplerArray&) SK_OVERRIDE;
352 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER RIDE; 352 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER RIDE;
353 353
354 static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps& caps); 354 static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps& caps);
355 355
356 protected: 356 protected:
357 357
358 UniformHandle fVSParamUni; 358 UniformHandle fParamUni;
359 UniformHandle fFSParamUni;
360 359
361 const char* fVSVaryingName; 360 const char* fVSVaryingName;
362 const char* fFSVaryingName; 361 const char* fFSVaryingName;
363 362
364 bool fIsDegenerate; 363 bool fIsDegenerate;
365 364
366 // @{ 365 // @{
367 /// Values last uploaded as uniforms 366 /// Values last uploaded as uniforms
368 367
369 SkScalar fCachedCenter; 368 SkScalar fCachedCenter;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 this->fDiffRadius == s.fDiffRadius); 414 this->fDiffRadius == s.fDiffRadius);
416 } 415 }
417 416
418 GrConical2Gradient(GrContext* ctx, 417 GrConical2Gradient(GrContext* ctx,
419 const SkTwoPointConicalGradient& shader, 418 const SkTwoPointConicalGradient& shader,
420 const SkMatrix& matrix, 419 const SkMatrix& matrix,
421 SkShader::TileMode tm) 420 SkShader::TileMode tm)
422 : INHERITED(ctx, shader, matrix, tm) 421 : INHERITED(ctx, shader, matrix, tm)
423 , fCenterX1(shader.getCenterX1()) 422 , fCenterX1(shader.getCenterX1())
424 , fRadius0(shader.getStartRadius()) 423 , fRadius0(shader.getStartRadius())
425 , fDiffRadius(shader.getDiffRadius()) { } 424 , fDiffRadius(shader.getDiffRadius()) {
425 // We pass the linear part of the quadratic as a varying.
426 // float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z)
427 fBTransform = this->getCoordTransform();
428 SkMatrix& bMatrix = *fBTransform.accessMatrix();
429 SkScalar r0dr = SkScalarMul(fRadius0, fDiffRadius);
430 bMatrix[SkMatrix::kMScaleX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMat rix::kMScaleX]) +
431 SkScalarMul(r0dr, bMatrix[SkMatrix:: kMPersp0]));
432 bMatrix[SkMatrix::kMSkewX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatr ix::kMSkewX]) +
433 SkScalarMul(r0dr, bMatrix[SkMatrix::k MPersp1]));
434 bMatrix[SkMatrix::kMTransX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMat rix::kMTransX]) +
435 SkScalarMul(r0dr, bMatrix[SkMatrix:: kMPersp2]));
436 this->addCoordTransform(&fBTransform);
437 }
426 438
427 GR_DECLARE_EFFECT_TEST; 439 GR_DECLARE_EFFECT_TEST;
428 440
429 // @{ 441 // @{
430 // Cache of values - these can change arbitrarily, EXCEPT 442 // Cache of values - these can change arbitrarily, EXCEPT
431 // we shouldn't change between degenerate and non-degenerate?! 443 // we shouldn't change between degenerate and non-degenerate?!
432 444
433 SkScalar fCenterX1; 445 GrCoordTransform fBTransform;
434 SkScalar fRadius0; 446 SkScalar fCenterX1;
435 SkScalar fDiffRadius; 447 SkScalar fRadius0;
448 SkScalar fDiffRadius;
436 449
437 // @} 450 // @}
438 451
439 typedef GrGradientEffect INHERITED; 452 typedef GrGradientEffect INHERITED;
440 }; 453 };
441 454
442 GR_DEFINE_EFFECT_TEST(GrConical2Gradient); 455 GR_DEFINE_EFFECT_TEST(GrConical2Gradient);
443 456
444 GrEffectRef* GrConical2Gradient::TestCreate(SkRandom* random, 457 GrEffectRef* GrConical2Gradient::TestCreate(SkRandom* random,
445 GrContext* context, 458 GrContext* context,
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 } 498 }
486 499
487 void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, 500 void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder,
488 const GrDrawEffect&, 501 const GrDrawEffect&,
489 EffectKey key, 502 EffectKey key,
490 const char* outputColor, 503 const char* outputColor,
491 const char* inputColor, 504 const char* inputColor,
492 const TransformedCoordsArray& coords, 505 const TransformedCoordsArray& coords,
493 const TextureSamplerArray& samplers) { 506 const TextureSamplerArray& samplers) {
494 this->emitUniforms(builder, key); 507 this->emitUniforms(builder, key);
495 // 2 copies of uniform array, 1 for each of vertex & fragment shader, 508 fParamUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility ,
496 // to work around Xoom bug. Doesn't seem to cause performance decrease 509 kFloat_GrSLType, "Conical2FSParams", 6) ;
497 // in test apps, but need to keep an eye on it.
498 fVSParamUni = builder->addUniformArray(GrGLShaderBuilder::kVertex_Visibility ,
499 kFloat_GrSLType, "Conical2VSParams", 6);
500 fFSParamUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibili ty,
501 kFloat_GrSLType, "Conical2FSParams", 6);
502 510
503 // For radial gradients without perspective we can pass the linear 511 SkString cName("c");
504 // part of the quadratic as a varying. 512 SkString ac4Name("ac4");
505 GrGLShaderBuilder::VertexBuilder* vertexBuilder = 513 SkString dName("d");
506 (kVec2f_GrSLType == coords[0].type()) ? builder->getVertexBuilder() : NU LL; 514 SkString qName("q");
507 if (NULL != vertexBuilder) { 515 SkString r0Name("r0");
508 vertexBuilder->addVarying(kFloat_GrSLType, "Conical2BCoeff", 516 SkString r1Name("r1");
509 &fVSVaryingName, &fFSVaryingName); 517 SkString tName("t");
518 SkString p0; // 4a
519 SkString p1; // 1/a
520 SkString p2; // distance between centers
521 SkString p3; // start radius
522 SkString p4; // start radius squared
523 SkString p5; // difference in radii (r1 - r0)
524
525 builder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
526 builder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
527 builder->getUniformVariable(fParamUni).appendArrayAccess(2, &p2);
528 builder->getUniformVariable(fParamUni).appendArrayAccess(3, &p3);
529 builder->getUniformVariable(fParamUni).appendArrayAccess(4, &p4);
530 builder->getUniformVariable(fParamUni).appendArrayAccess(5, &p5);
531
532 // We interpolate the linear component in coords[1].
533 SkASSERT(coords[0].type() == coords[1].type());
534 const char* coords2D;
535 SkString bVar;
536 if (kVec3f_GrSLType == coords[0].type()) {
537 builder->fsCodeAppendf("\tvec3 interpolants = vec3(%s.xy, %s.x) / %s.z;\ n",
538 coords[0].c_str(), coords[1].c_str(), coords[0].c _str());
539 coords2D = "interpolants.xy";
540 bVar = "interpolants.z";
541 } else {
542 coords2D = coords[0].c_str();
543 bVar.printf("%s.x", coords[1].c_str());
510 } 544 }
511 545
512 // VS 546 // output will default to transparent black (we simply won't write anything
513 { 547 // else to it if invalid, instead of discarding or returning prematurely)
514 SkString p2; // distance between centers 548 builder->fsCodeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
515 SkString p3; // start radius
516 SkString p5; // difference in radii (r1 - r0)
517 builder->getUniformVariable(fVSParamUni).appendArrayAccess(2, &p2);
518 builder->getUniformVariable(fVSParamUni).appendArrayAccess(3, &p3);
519 builder->getUniformVariable(fVSParamUni).appendArrayAccess(5, &p5);
520 549
521 // For radial gradients without perspective we can pass the linear 550 // c = (x^2)+(y^2) - params[4]
522 // part of the quadratic as a varying. 551 builder->fsCodeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
523 if (NULL != vertexBuilder) { 552 cName.c_str(), coords2D, coords2D, p4.c_str());
524 // r2Var = -2 * (r2Parm[2] * varCoord.x - r2Param[3] * r2Param[5])
525 vertexBuilder->vsCodeAppendf("\t%s = -2.0 * (%s * %s.x + %s * %s);\n ",
526 fVSVaryingName, p2.c_str(),
527 coords[0].getVSName().c_str(), p3.c_ str(), p5.c_str());
528 }
529 }
530 553
531 // FS 554 // Non-degenerate case (quadratic)
532 { 555 if (!fIsDegenerate) {
533 SkString coords2D = builder->ensureFSCoords2D(coords, 0);
534 SkString cName("c");
535 SkString ac4Name("ac4");
536 SkString dName("d");
537 SkString qName("q");
538 SkString r0Name("r0");
539 SkString r1Name("r1");
540 SkString tName("t");
541 SkString p0; // 4a
542 SkString p1; // 1/a
543 SkString p2; // distance between centers
544 SkString p3; // start radius
545 SkString p4; // start radius squared
546 SkString p5; // difference in radii (r1 - r0)
547 556
548 builder->getUniformVariable(fFSParamUni).appendArrayAccess(0, &p0); 557 // ac4 = params[0] * c
549 builder->getUniformVariable(fFSParamUni).appendArrayAccess(1, &p1); 558 builder->fsCodeAppendf("\tfloat %s = %s * %s;\n", ac4Name.c_str(), p0.c_ str(),
550 builder->getUniformVariable(fFSParamUni).appendArrayAccess(2, &p2); 559 cName.c_str());
551 builder->getUniformVariable(fFSParamUni).appendArrayAccess(3, &p3);
552 builder->getUniformVariable(fFSParamUni).appendArrayAccess(4, &p4);
553 builder->getUniformVariable(fFSParamUni).appendArrayAccess(5, &p5);
554 560
555 // If we we're able to interpolate the linear component, 561 // d = b^2 - ac4
556 // bVar is the varying; otherwise compute it 562 builder->fsCodeAppendf("\tfloat %s = %s * %s - %s;\n", dName.c_str(),
557 SkString bVar; 563 bVar.c_str(), bVar.c_str(), ac4Name.c_str());
558 if (NULL != vertexBuilder) {
559 bVar = fFSVaryingName;
560 } else {
561 bVar = "b";
562 builder->fsCodeAppendf("\tfloat %s = -2.0 * (%s * %s.x + %s * %s);\n ",
563 bVar.c_str(), p2.c_str(), coords2D.c_str(),
564 p3.c_str(), p5.c_str());
565 }
566 564
567 // output will default to transparent black (we simply won't write anyth ing 565 // only proceed if discriminant is >= 0
568 // else to it if invalid, instead of discarding or returning prematurely ) 566 builder->fsCodeAppendf("\tif (%s >= 0.0) {\n", dName.c_str());
569 builder->fsCodeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
570 567
571 // c = (x^2)+(y^2) - params[4] 568 // intermediate value we'll use to compute the roots
572 builder->fsCodeAppendf("\tfloat %s = dot(%s, %s) - %s;\n", cName.c_str() , 569 // q = -0.5 * (b +/- sqrt(d))
573 coords2D.c_str(), coords2D.c_str(), 570 builder->fsCodeAppendf("\t\tfloat %s = -0.5 * (%s + (%s < 0.0 ? -1.0 : 1 .0)"
574 p4.c_str()); 571 " * sqrt(%s));\n", qName.c_str(), bVar.c_str(),
572 bVar.c_str(), dName.c_str());
575 573
576 // Non-degenerate case (quadratic) 574 // compute both roots
577 if (!fIsDegenerate) { 575 // r0 = q * params[1]
576 builder->fsCodeAppendf("\t\tfloat %s = %s * %s;\n", r0Name.c_str(),
577 qName.c_str(), p1.c_str());
578 // r1 = c / q
579 builder->fsCodeAppendf("\t\tfloat %s = %s / %s;\n", r1Name.c_str(),
580 cName.c_str(), qName.c_str());
578 581
579 // ac4 = params[0] * c 582 // Note: If there are two roots that both generate radius(t) > 0, the
580 builder->fsCodeAppendf("\tfloat %s = %s * %s;\n", ac4Name.c_str(), p 0.c_str(), 583 // Canvas spec says to choose the larger t.
581 cName.c_str());
582 584
583 // d = b^2 - ac4 585 // so we'll look at the larger one first:
584 builder->fsCodeAppendf("\tfloat %s = %s * %s - %s;\n", dName.c_str() , 586 builder->fsCodeAppendf("\t\tfloat %s = max(%s, %s);\n", tName.c_str(),
585 bVar.c_str(), bVar.c_str(), ac4Name.c_str()); 587 r0Name.c_str(), r1Name.c_str());
586 588
587 // only proceed if discriminant is >= 0 589 // if r(t) > 0, then we're done; t will be our x coordinate
588 builder->fsCodeAppendf("\tif (%s >= 0.0) {\n", dName.c_str()); 590 builder->fsCodeAppendf("\t\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
591 p5.c_str(), p3.c_str());
589 592
590 // intermediate value we'll use to compute the roots 593 builder->fsCodeAppend("\t\t");
591 // q = -0.5 * (b +/- sqrt(d)) 594 this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, sa mplers);
592 builder->fsCodeAppendf("\t\tfloat %s = -0.5 * (%s + (%s < 0.0 ? -1.0 : 1.0)"
593 " * sqrt(%s));\n", qName.c_str(), bVar.c_str( ),
594 bVar.c_str(), dName.c_str());
595 595
596 // compute both roots 596 // otherwise, if r(t) for the larger root was <= 0, try the other root
597 // r0 = q * params[1] 597 builder->fsCodeAppend("\t\t} else {\n");
598 builder->fsCodeAppendf("\t\tfloat %s = %s * %s;\n", r0Name.c_str(), 598 builder->fsCodeAppendf("\t\t\t%s = min(%s, %s);\n", tName.c_str(),
599 qName.c_str(), p1.c_str()); 599 r0Name.c_str(), r1Name.c_str());
600 // r1 = c / q
601 builder->fsCodeAppendf("\t\tfloat %s = %s / %s;\n", r1Name.c_str(),
602 cName.c_str(), qName.c_str());
603 600
604 // Note: If there are two roots that both generate radius(t) > 0, th e 601 // if r(t) > 0 for the smaller root, then t will be our x coordinate
605 // Canvas spec says to choose the larger t. 602 builder->fsCodeAppendf("\t\t\tif (%s * %s + %s > 0.0) {\n",
603 tName.c_str(), p5.c_str(), p3.c_str());
606 604
607 // so we'll look at the larger one first: 605 builder->fsCodeAppend("\t\t\t");
608 builder->fsCodeAppendf("\t\tfloat %s = max(%s, %s);\n", tName.c_str( ), 606 this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, sa mplers);
609 r0Name.c_str(), r1Name.c_str());
610 607
611 // if r(t) > 0, then we're done; t will be our x coordinate 608 // end if (r(t) > 0) for smaller root
612 builder->fsCodeAppendf("\t\tif (%s * %s + %s > 0.0) {\n", tName.c_st r(), 609 builder->fsCodeAppend("\t\t\t}\n");
613 p5.c_str(), p3.c_str()); 610 // end if (r(t) > 0), else, for larger root
611 builder->fsCodeAppend("\t\t}\n");
612 // end if (discriminant >= 0)
613 builder->fsCodeAppend("\t}\n");
614 } else {
614 615
615 builder->fsCodeAppend("\t\t"); 616 // linear case: t = -c/b
616 this->emitColor(builder, tName.c_str(), key, outputColor, inputColor , samplers); 617 builder->fsCodeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
618 cName.c_str(), bVar.c_str());
617 619
618 // otherwise, if r(t) for the larger root was <= 0, try the other ro ot 620 // if r(t) > 0, then t will be the x coordinate
619 builder->fsCodeAppend("\t\t} else {\n"); 621 builder->fsCodeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
620 builder->fsCodeAppendf("\t\t\t%s = min(%s, %s);\n", tName.c_str(), 622 p5.c_str(), p3.c_str());
621 r0Name.c_str(), r1Name.c_str()); 623 builder->fsCodeAppend("\t");
622 624 this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, sa mplers);
623 // if r(t) > 0 for the smaller root, then t will be our x coordinate 625 builder->fsCodeAppend("\t}\n");
624 builder->fsCodeAppendf("\t\t\tif (%s * %s + %s > 0.0) {\n",
625 tName.c_str(), p5.c_str(), p3.c_str());
626
627 builder->fsCodeAppend("\t\t\t");
628 this->emitColor(builder, tName.c_str(), key, outputColor, inputColor , samplers);
629
630 // end if (r(t) > 0) for smaller root
631 builder->fsCodeAppend("\t\t\t}\n");
632 // end if (r(t) > 0), else, for larger root
633 builder->fsCodeAppend("\t\t}\n");
634 // end if (discriminant >= 0)
635 builder->fsCodeAppend("\t}\n");
636 } else {
637
638 // linear case: t = -c/b
639 builder->fsCodeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
640 cName.c_str(), bVar.c_str());
641
642 // if r(t) > 0, then t will be the x coordinate
643 builder->fsCodeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str( ),
644 p5.c_str(), p3.c_str());
645 builder->fsCodeAppend("\t");
646 this->emitColor(builder, tName.c_str(), key, outputColor, inputColor , samplers);
647 builder->fsCodeAppend("\t}\n");
648 }
649 } 626 }
650 } 627 }
651 628
652 void GrGLConical2Gradient::setData(const GrGLUniformManager& uman, 629 void GrGLConical2Gradient::setData(const GrGLUniformManager& uman,
653 const GrDrawEffect& drawEffect) { 630 const GrDrawEffect& drawEffect) {
654 INHERITED::setData(uman, drawEffect); 631 INHERITED::setData(uman, drawEffect);
655 const GrConical2Gradient& data = drawEffect.castEffect<GrConical2Gradient>() ; 632 const GrConical2Gradient& data = drawEffect.castEffect<GrConical2Gradient>() ;
656 SkASSERT(data.isDegenerate() == fIsDegenerate); 633 SkASSERT(data.isDegenerate() == fIsDegenerate);
657 SkScalar centerX1 = data.center(); 634 SkScalar centerX1 = data.center();
658 SkScalar radius0 = data.radius(); 635 SkScalar radius0 = data.radius();
(...skipping 12 matching lines...) Expand all
671 // down). 648 // down).
672 float values[6] = { 649 float values[6] = {
673 SkScalarToFloat(a * 4), 650 SkScalarToFloat(a * 4),
674 1.f / (SkScalarToFloat(a)), 651 1.f / (SkScalarToFloat(a)),
675 SkScalarToFloat(centerX1), 652 SkScalarToFloat(centerX1),
676 SkScalarToFloat(radius0), 653 SkScalarToFloat(radius0),
677 SkScalarToFloat(SkScalarMul(radius0, radius0)), 654 SkScalarToFloat(SkScalarMul(radius0, radius0)),
678 SkScalarToFloat(diffRadius) 655 SkScalarToFloat(diffRadius)
679 }; 656 };
680 657
681 uman.set1fv(fVSParamUni, 0, 6, values); 658 uman.set1fv(fParamUni, 0, 6, values);
682 uman.set1fv(fFSParamUni, 0, 6, values);
683 fCachedCenter = centerX1; 659 fCachedCenter = centerX1;
684 fCachedRadius = radius0; 660 fCachedRadius = radius0;
685 fCachedDiffRadius = diffRadius; 661 fCachedDiffRadius = diffRadius;
686 } 662 }
687 } 663 }
688 664
689 GrGLEffect::EffectKey GrGLConical2Gradient::GenKey(const GrDrawEffect& drawEffec t, 665 GrGLEffect::EffectKey GrGLConical2Gradient::GenKey(const GrDrawEffect& drawEffec t,
690 const GrGLCaps&) { 666 const GrGLCaps&) {
691 enum { 667 enum {
692 kIsDegenerate = 1 << kBaseKeyBitCnt, 668 kIsDegenerate = 1 << kBaseKeyBitCnt,
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
751 str->appendScalar(fCenter2.fY); 727 str->appendScalar(fCenter2.fY);
752 str->append(") radius2: "); 728 str->append(") radius2: ");
753 str->appendScalar(fRadius2); 729 str->appendScalar(fRadius2);
754 str->append(" "); 730 str->append(" ");
755 731
756 this->INHERITED::toString(str); 732 this->INHERITED::toString(str);
757 733
758 str->append(")"); 734 str->append(")");
759 } 735 }
760 #endif 736 #endif
OLDNEW
« no previous file with comments | « src/effects/gradients/SkGradientShaderPriv.h ('k') | src/effects/gradients/SkTwoPointRadialGradient.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698