Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "GrAARectRenderer.h"
      9 #include "GrRefCnt.h"
     10 #include "GrGpu.h"
     11 
     12 SK_DEFINE_INST_COUNT(GrAARectRenderer)
     13 
     14 namespace {
     15 
     16 static GrVertexLayout aa_rect_layout(bool useCoverage) {
     17     GrVertexLayout layout = 0;
     18     if (useCoverage) {
     19         layout |= GrDrawState::kCoverage_VertexLayoutBit;
     20     } else {
     21         layout |= GrDrawState::kColor_VertexLayoutBit;
     22     }
     23     return layout;
     24 }
     25 
     26 static void set_inset_fan(GrPoint* pts, size_t stride,
     27                           const GrRect& r, SkScalar dx, SkScalar dy) {
     28     pts->setRectFan(r.fLeft + dx, r.fTop + dy,
     29                     r.fRight - dx, r.fBottom - dy, stride);
     30 }
     31 
     32 };
     33 
     34 void GrAARectRenderer::reset() {
     35     GrSafeSetNull(fAAFillRectIndexBuffer);
     36     GrSafeSetNull(fAAStrokeRectIndexBuffer);
     37 }
     38 
     39 static const uint16_t gFillAARectIdx[] = {
     40     0, 1, 5, 5, 4, 0,
     41     1, 2, 6, 6, 5, 1,
     42     2, 3, 7, 7, 6, 2,
     43     3, 0, 4, 4, 7, 3,
     44     4, 5, 6, 6, 7, 4,
     45 };
     46 
     47 static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
     48 static const int kVertsPerAAFillRect = 8;
     49 static const int kNumAAFillRectsInIndexBuffer = 256;
     50 
     51 GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
     52     static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
     53                                                      sizeof(uint16_t) *
     54                                                      kNumAAFillRectsInIndexBuffer;
     55 
     56     if (NULL == fAAFillRectIndexBuffer) {
     57         fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
     58         if (NULL != fAAFillRectIndexBuffer) {
     59             uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
     60             bool useTempData = (NULL == data);
     61             if (useTempData) {
     62                 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
     63             }
     64             for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
     65                 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
     66                 // the inner rect (for AA) and 2 for the inner rect.
     67                 int baseIdx = i * kIndicesPerAAFillRect;
     68                 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
     69                 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
     70                     data[baseIdx+j] = baseVert + gFillAARectIdx[j];
     71                 }
     72             }
     73             if (useTempData) {
     74                 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
     75                     GrCrash("Can't get AA Fill Rect indices into buffer!");
     76                 }
     77                 SkDELETE_ARRAY(data);
     78             } else {
     79                 fAAFillRectIndexBuffer->unlock();
     80             }
     81         }
     82     }
     83 
     84     return fAAFillRectIndexBuffer;
     85 }
     86 
     87 static const uint16_t gStrokeAARectIdx[] = {
     88     0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
     89     1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
     90     2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
     91     3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
     92 
     93     0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
     94     1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
     95     2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
     96     3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
     97 
     98     0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
     99     1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
    100     2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
    101     3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
    102 };
    103 
    104 int GrAARectRenderer::aaStrokeRectIndexCount() {
    105     return GR_ARRAY_COUNT(gStrokeAARectIdx);
    106 }
    107 
    108 GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
    109     if (NULL == fAAStrokeRectIndexBuffer) {
    110         fAAStrokeRectIndexBuffer =
    111                   gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
    112         if (NULL != fAAStrokeRectIndexBuffer) {
    113 #if GR_DEBUG
    114             bool updated =
    115 #endif
    116             fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
    117                                                  sizeof(gStrokeAARectIdx));
    118             GR_DEBUGASSERT(updated);
    119         }
    120     }
    121     return fAAStrokeRectIndexBuffer;
    122 }
    123 
    124 void GrAARectRenderer::fillAARect(GrGpu* gpu,
    125                                   GrDrawTarget* target,
    126                                   const GrRect& devRect,
    127                                   bool useVertexCoverage) {
    128     GrVertexLayout layout = aa_rect_layout(useVertexCoverage);
    129 
    130     size_t vsize = GrDrawState::VertexSize(layout);
    131 
    132     GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
    133     if (!geo.succeeded()) {
    134         GrPrintf("Failed to get space for vertices!\n");
    135         return;
    136     }
    137 
    138     GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
    139     if (NULL == indexBuffer) {
    140         GrPrintf("Failed to create index buffer!\n");
    141         return;
    142     }
    143 
    144     intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
    145 
    146     GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
    147     GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
    148 
    149     set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
    150     set_inset_fan(fan1Pos, vsize, devRect,  SK_ScalarHalf,  SK_ScalarHalf);
    151 
    152     verts += sizeof(GrPoint);
    153     for (int i = 0; i < 4; ++i) {
    154         *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
    155     }
    156 
    157     GrColor innerColor;
    158     if (useVertexCoverage) {
    159         innerColor = 0xffffffff;
    160     } else {
    161         innerColor = target->getDrawState().getColor();
    162     }
    163 
    164     verts += 4 * vsize;
    165     for (int i = 0; i < 4; ++i) {
    166         *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
    167     }
    168 
    169     target->setIndexSourceToBuffer(indexBuffer);
    170     target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
    171                                  kVertsPerAAFillRect,
    172                                  kIndicesPerAAFillRect);
    173 }
    174 
    175 void GrAARectRenderer::strokeAARect(GrGpu* gpu,
    176                                     GrDrawTarget* target,
    177                                     const GrRect& devRect,
    178                                     const GrVec& devStrokeSize,
    179                                     bool useVertexCoverage) {
    180     const SkScalar& dx = devStrokeSize.fX;
    181     const SkScalar& dy = devStrokeSize.fY;
    182     const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
    183     const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
    184 
    185     SkScalar spare;
    186     {
    187         SkScalar w = devRect.width() - dx;
    188         SkScalar h = devRect.height() - dy;
    189         spare = GrMin(w, h);
    190     }
    191 
    192     if (spare <= 0) {
    193         GrRect r(devRect);
    194         r.inset(-rx, -ry);
    195         this->fillAARect(gpu, target, r, useVertexCoverage);
    196         return;
    197     }
    198     GrVertexLayout layout = aa_rect_layout(useVertexCoverage);
    199     size_t vsize = GrDrawState::VertexSize(layout);
    200 
    201     GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
    202     if (!geo.succeeded()) {
    203         GrPrintf("Failed to get space for vertices!\n");
    204         return;
    205     }
    206     GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
    207     if (NULL == indexBuffer) {
    208         GrPrintf("Failed to create index buffer!\n");
    209         return;
    210     }
    211 
    212     intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
    213 
    214     // We create vertices for four nested rectangles. There are two ramps from 0 to full
    215     // coverage, one on the exterior of the stroke and the other on the interior.
    216     // The following pointers refer to the four rects, from outermost to innermost.
    217     GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
    218     GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
    219     GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
    220     GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
    221 
    222     set_inset_fan(fan0Pos, vsize, devRect,
    223                   -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
    224     set_inset_fan(fan1Pos, vsize, devRect,
    225                   -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
    226     set_inset_fan(fan2Pos, vsize, devRect,
    227                   rx - SK_ScalarHalf,  ry - SK_ScalarHalf);
    228     set_inset_fan(fan3Pos, vsize, devRect,
    229                   rx + SK_ScalarHalf,  ry + SK_ScalarHalf);
    230 
    231     // The outermost rect has 0 coverage
    232     verts += sizeof(GrPoint);
    233     for (int i = 0; i < 4; ++i) {
    234         *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
    235     }
    236 
    237     // The inner two rects have full coverage
    238     GrColor innerColor;
    239     if (useVertexCoverage) {
    240         innerColor = 0xffffffff;
    241     } else {
    242         innerColor = target->getDrawState().getColor();
    243     }
    244     verts += 4 * vsize;
    245     for (int i = 0; i < 8; ++i) {
    246         *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
    247     }
    248 
    249     // The innermost rect has full coverage
    250     verts += 8 * vsize;
    251     for (int i = 0; i < 4; ++i) {
    252         *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
    253     }
    254 
    255     target->setIndexSourceToBuffer(indexBuffer);
    256     target->drawIndexed(kTriangles_GrPrimitiveType,
    257                         0, 0, 16, aaStrokeRectIndexCount());
    258 }
    259