GrAARectRenderer.cpp revision 363e546ed626b6dbbc42f5db87b3594bc0b5944b
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 12SK_DEFINE_INST_COUNT(GrAARectRenderer) 13 14namespace { 15 16static GrVertexLayout aa_rect_layout(bool useCoverage) { 17 GrVertexLayout layout = 0; 18 if (useCoverage) { 19 layout |= GrDrawTarget::kCoverage_VertexLayoutBit; 20 } else { 21 layout |= GrDrawTarget::kColor_VertexLayoutBit; 22 } 23 return layout; 24} 25 26static 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 34void GrAARectRenderer::reset() { 35 GrSafeSetNull(fAAFillRectIndexBuffer); 36 GrSafeSetNull(fAAStrokeRectIndexBuffer); 37} 38 39static 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 47static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx); 48static const int kVertsPerAAFillRect = 8; 49static const int kNumAAFillRectsInIndexBuffer = 256; 50 51GrIndexBuffer* 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 87static 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 104int GrAARectRenderer::aaStrokeRectIndexCount() { 105 return GR_ARRAY_COUNT(gStrokeAARectIdx); 106} 107 108GrIndexBuffer* 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 124void 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 = GrDrawTarget::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 175void 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 = GrDrawTarget::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