GrDrawTarget.cpp revision 054ae99d93711c26e40682a0e3a03a47ea605c53
1
2/*
3 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10
11#include "GrDrawTarget.h"
12#include "GrContext.h"
13#include "GrDrawTargetCaps.h"
14#include "GrRenderTarget.h"
15#include "GrTexture.h"
16#include "GrVertexBuffer.h"
17
18#include "SkStrokeRec.h"
19
20SK_DEFINE_INST_COUNT(GrDrawTarget)
21
22////////////////////////////////////////////////////////////////////////////////
23
24GrDrawTarget::DrawInfo& GrDrawTarget::DrawInfo::operator =(const DrawInfo& di) {
25    fPrimitiveType  = di.fPrimitiveType;
26    fStartVertex    = di.fStartVertex;
27    fStartIndex     = di.fStartIndex;
28    fVertexCount    = di.fVertexCount;
29    fIndexCount     = di.fIndexCount;
30
31    fInstanceCount          = di.fInstanceCount;
32    fVerticesPerInstance    = di.fVerticesPerInstance;
33    fIndicesPerInstance     = di.fIndicesPerInstance;
34
35    if (NULL != di.fDevBounds) {
36        GrAssert(di.fDevBounds == &di.fDevBoundsStorage);
37        fDevBoundsStorage = di.fDevBoundsStorage;
38        fDevBounds = &fDevBoundsStorage;
39    } else {
40        fDevBounds = NULL;
41    }
42
43    fDstCopy = di.fDstCopy;
44
45    return *this;
46}
47
48#if GR_DEBUG
49bool GrDrawTarget::DrawInfo::isInstanced() const {
50    if (fInstanceCount > 0) {
51        GrAssert(0 == fIndexCount % fIndicesPerInstance);
52        GrAssert(0 == fVertexCount % fVerticesPerInstance);
53        GrAssert(fIndexCount / fIndicesPerInstance == fInstanceCount);
54        GrAssert(fVertexCount / fVerticesPerInstance == fInstanceCount);
55        // there is no way to specify a non-zero start index to drawIndexedInstances().
56        GrAssert(0 == fStartIndex);
57        return true;
58    } else {
59        GrAssert(!fVerticesPerInstance);
60        GrAssert(!fIndicesPerInstance);
61        return false;
62    }
63}
64#endif
65
66void GrDrawTarget::DrawInfo::adjustInstanceCount(int instanceOffset) {
67    GrAssert(this->isInstanced());
68    GrAssert(instanceOffset + fInstanceCount >= 0);
69    fInstanceCount += instanceOffset;
70    fVertexCount = fVerticesPerInstance * fInstanceCount;
71    fIndexCount = fIndicesPerInstance * fInstanceCount;
72}
73
74void GrDrawTarget::DrawInfo::adjustStartVertex(int vertexOffset) {
75    fStartVertex += vertexOffset;
76    GrAssert(fStartVertex >= 0);
77}
78
79void GrDrawTarget::DrawInfo::adjustStartIndex(int indexOffset) {
80    GrAssert(this->isIndexed());
81    fStartIndex += indexOffset;
82    GrAssert(fStartIndex >= 0);
83}
84
85////////////////////////////////////////////////////////////////////////////////
86
87#define DEBUG_INVAL_BUFFER 0xdeadcafe
88#define DEBUG_INVAL_START_IDX -1
89
90GrDrawTarget::GrDrawTarget(GrContext* context)
91    : fClip(NULL)
92    , fContext(context) {
93    GrAssert(NULL != context);
94
95    fDrawState = &fDefaultDrawState;
96    // We assume that fDrawState always owns a ref to the object it points at.
97    fDefaultDrawState.ref();
98    GeometrySrcState& geoSrc = fGeoSrcStateStack.push_back();
99#if GR_DEBUG
100    geoSrc.fVertexCount = DEBUG_INVAL_START_IDX;
101    geoSrc.fVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
102    geoSrc.fIndexCount = DEBUG_INVAL_START_IDX;
103    geoSrc.fIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
104#endif
105    geoSrc.fVertexSrc = kNone_GeometrySrcType;
106    geoSrc.fIndexSrc  = kNone_GeometrySrcType;
107}
108
109GrDrawTarget::~GrDrawTarget() {
110    GrAssert(1 == fGeoSrcStateStack.count());
111    SkDEBUGCODE(GeometrySrcState& geoSrc = fGeoSrcStateStack.back());
112    GrAssert(kNone_GeometrySrcType == geoSrc.fIndexSrc);
113    GrAssert(kNone_GeometrySrcType == geoSrc.fVertexSrc);
114    fDrawState->unref();
115}
116
117void GrDrawTarget::releaseGeometry() {
118    int popCnt = fGeoSrcStateStack.count() - 1;
119    while (popCnt) {
120        this->popGeometrySource();
121        --popCnt;
122    }
123    this->resetVertexSource();
124    this->resetIndexSource();
125}
126
127void GrDrawTarget::setClip(const GrClipData* clip) {
128    clipWillBeSet(clip);
129    fClip = clip;
130}
131
132const GrClipData* GrDrawTarget::getClip() const {
133    return fClip;
134}
135
136void GrDrawTarget::setDrawState(GrDrawState*  drawState) {
137    GrAssert(NULL != fDrawState);
138    if (NULL == drawState) {
139        drawState = &fDefaultDrawState;
140    }
141    if (fDrawState != drawState) {
142        fDrawState->unref();
143        drawState->ref();
144        fDrawState = drawState;
145    }
146}
147
148bool GrDrawTarget::reserveVertexSpace(size_t vertexSize,
149                                      int vertexCount,
150                                      void** vertices) {
151    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
152    bool acquired = false;
153    if (vertexCount > 0) {
154        GrAssert(NULL != vertices);
155        this->releasePreviousVertexSource();
156        geoSrc.fVertexSrc = kNone_GeometrySrcType;
157
158        acquired = this->onReserveVertexSpace(vertexSize,
159                                              vertexCount,
160                                              vertices);
161    }
162    if (acquired) {
163        geoSrc.fVertexSrc = kReserved_GeometrySrcType;
164        geoSrc.fVertexCount = vertexCount;
165        geoSrc.fVertexSize = vertexSize;
166    } else if (NULL != vertices) {
167        *vertices = NULL;
168    }
169    return acquired;
170}
171
172bool GrDrawTarget::reserveIndexSpace(int indexCount,
173                                     void** indices) {
174    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
175    bool acquired = false;
176    if (indexCount > 0) {
177        GrAssert(NULL != indices);
178        this->releasePreviousIndexSource();
179        geoSrc.fIndexSrc = kNone_GeometrySrcType;
180
181        acquired = this->onReserveIndexSpace(indexCount, indices);
182    }
183    if (acquired) {
184        geoSrc.fIndexSrc = kReserved_GeometrySrcType;
185        geoSrc.fIndexCount = indexCount;
186    } else if (NULL != indices) {
187        *indices = NULL;
188    }
189    return acquired;
190
191}
192
193bool GrDrawTarget::reserveVertexAndIndexSpace(int vertexCount,
194                                              int indexCount,
195                                              void** vertices,
196                                              void** indices) {
197    size_t vertexSize = this->drawState()->getVertexSize();
198    this->willReserveVertexAndIndexSpace(vertexCount, indexCount);
199    if (vertexCount) {
200        if (!this->reserveVertexSpace(vertexSize, vertexCount, vertices)) {
201            if (indexCount) {
202                this->resetIndexSource();
203            }
204            return false;
205        }
206    }
207    if (indexCount) {
208        if (!this->reserveIndexSpace(indexCount, indices)) {
209            if (vertexCount) {
210                this->resetVertexSource();
211            }
212            return false;
213        }
214    }
215    return true;
216}
217
218bool GrDrawTarget::geometryHints(int32_t* vertexCount,
219                                 int32_t* indexCount) const {
220    if (NULL != vertexCount) {
221        *vertexCount = -1;
222    }
223    if (NULL != indexCount) {
224        *indexCount = -1;
225    }
226    return false;
227}
228
229void GrDrawTarget::releasePreviousVertexSource() {
230    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
231    switch (geoSrc.fVertexSrc) {
232        case kNone_GeometrySrcType:
233            break;
234        case kArray_GeometrySrcType:
235            this->releaseVertexArray();
236            break;
237        case kReserved_GeometrySrcType:
238            this->releaseReservedVertexSpace();
239            break;
240        case kBuffer_GeometrySrcType:
241            geoSrc.fVertexBuffer->unref();
242#if GR_DEBUG
243            geoSrc.fVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
244#endif
245            break;
246        default:
247            GrCrash("Unknown Vertex Source Type.");
248            break;
249    }
250}
251
252void GrDrawTarget::releasePreviousIndexSource() {
253    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
254    switch (geoSrc.fIndexSrc) {
255        case kNone_GeometrySrcType:   // these two don't require
256            break;
257        case kArray_GeometrySrcType:
258            this->releaseIndexArray();
259            break;
260        case kReserved_GeometrySrcType:
261            this->releaseReservedIndexSpace();
262            break;
263        case kBuffer_GeometrySrcType:
264            geoSrc.fIndexBuffer->unref();
265#if GR_DEBUG
266            geoSrc.fIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
267#endif
268            break;
269        default:
270            GrCrash("Unknown Index Source Type.");
271            break;
272    }
273}
274
275void GrDrawTarget::setVertexSourceToArray(const void* vertexArray,
276                                          int vertexCount) {
277    this->releasePreviousVertexSource();
278    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
279    geoSrc.fVertexSrc = kArray_GeometrySrcType;
280    geoSrc.fVertexSize = this->drawState()->getVertexSize();
281    geoSrc.fVertexCount = vertexCount;
282    this->onSetVertexSourceToArray(vertexArray, vertexCount);
283}
284
285void GrDrawTarget::setIndexSourceToArray(const void* indexArray,
286                                         int indexCount) {
287    this->releasePreviousIndexSource();
288    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
289    geoSrc.fIndexSrc = kArray_GeometrySrcType;
290    geoSrc.fIndexCount = indexCount;
291    this->onSetIndexSourceToArray(indexArray, indexCount);
292}
293
294void GrDrawTarget::setVertexSourceToBuffer(const GrVertexBuffer* buffer) {
295    this->releasePreviousVertexSource();
296    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
297    geoSrc.fVertexSrc    = kBuffer_GeometrySrcType;
298    geoSrc.fVertexBuffer = buffer;
299    buffer->ref();
300    geoSrc.fVertexSize = this->drawState()->getVertexSize();
301}
302
303void GrDrawTarget::setIndexSourceToBuffer(const GrIndexBuffer* buffer) {
304    this->releasePreviousIndexSource();
305    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
306    geoSrc.fIndexSrc     = kBuffer_GeometrySrcType;
307    geoSrc.fIndexBuffer  = buffer;
308    buffer->ref();
309}
310
311void GrDrawTarget::resetVertexSource() {
312    this->releasePreviousVertexSource();
313    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
314    geoSrc.fVertexSrc = kNone_GeometrySrcType;
315}
316
317void GrDrawTarget::resetIndexSource() {
318    this->releasePreviousIndexSource();
319    GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
320    geoSrc.fIndexSrc = kNone_GeometrySrcType;
321}
322
323void GrDrawTarget::pushGeometrySource() {
324    this->geometrySourceWillPush();
325    GeometrySrcState& newState = fGeoSrcStateStack.push_back();
326    newState.fIndexSrc = kNone_GeometrySrcType;
327    newState.fVertexSrc = kNone_GeometrySrcType;
328#if GR_DEBUG
329    newState.fVertexCount  = ~0;
330    newState.fVertexBuffer = (GrVertexBuffer*)~0;
331    newState.fIndexCount   = ~0;
332    newState.fIndexBuffer = (GrIndexBuffer*)~0;
333#endif
334}
335
336void GrDrawTarget::popGeometrySource() {
337    // if popping last element then pops are unbalanced with pushes
338    GrAssert(fGeoSrcStateStack.count() > 1);
339
340    this->geometrySourceWillPop(fGeoSrcStateStack.fromBack(1));
341    this->releasePreviousVertexSource();
342    this->releasePreviousIndexSource();
343    fGeoSrcStateStack.pop_back();
344}
345
346////////////////////////////////////////////////////////////////////////////////
347
348bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex,
349                             int startIndex, int vertexCount,
350                             int indexCount) const {
351    const GrDrawState& drawState = this->getDrawState();
352#if GR_DEBUG
353    const GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
354    int maxVertex = startVertex + vertexCount;
355    int maxValidVertex;
356    switch (geoSrc.fVertexSrc) {
357        case kNone_GeometrySrcType:
358            GrCrash("Attempting to draw without vertex src.");
359        case kReserved_GeometrySrcType: // fallthrough
360        case kArray_GeometrySrcType:
361            maxValidVertex = geoSrc.fVertexCount;
362            break;
363        case kBuffer_GeometrySrcType:
364            maxValidVertex = geoSrc.fVertexBuffer->sizeInBytes() / geoSrc.fVertexSize;
365            break;
366    }
367    if (maxVertex > maxValidVertex) {
368        GrCrash("Drawing outside valid vertex range.");
369    }
370    if (indexCount > 0) {
371        int maxIndex = startIndex + indexCount;
372        int maxValidIndex;
373        switch (geoSrc.fIndexSrc) {
374            case kNone_GeometrySrcType:
375                GrCrash("Attempting to draw indexed geom without index src.");
376            case kReserved_GeometrySrcType: // fallthrough
377            case kArray_GeometrySrcType:
378                maxValidIndex = geoSrc.fIndexCount;
379                break;
380            case kBuffer_GeometrySrcType:
381                maxValidIndex = geoSrc.fIndexBuffer->sizeInBytes() / sizeof(uint16_t);
382                break;
383        }
384        if (maxIndex > maxValidIndex) {
385            GrCrash("Index reads outside valid index range.");
386        }
387    }
388
389    GrAssert(NULL != drawState.getRenderTarget());
390    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
391        if (drawState.isStageEnabled(s)) {
392            const GrEffectRef& effect = *drawState.getStage(s).getEffect();
393            int numTextures = effect->numTextures();
394            for (int t = 0; t < numTextures; ++t) {
395                GrTexture* texture = effect->texture(t);
396                GrAssert(texture->asRenderTarget() != drawState.getRenderTarget());
397            }
398        }
399    }
400
401    GrAssert(drawState.validateVertexAttribs());
402#endif
403    if (NULL == drawState.getRenderTarget()) {
404        return false;
405    }
406    return true;
407}
408
409bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) {
410    if (!this->getDrawState().willEffectReadDst()) {
411        return true;
412    }
413    GrRenderTarget* rt = this->drawState()->getRenderTarget();
414    // If the dst is not a texture then we don't currently have a way of copying the
415    // texture. TODO: make copying RT->Tex (or Surface->Surface) a GrDrawTarget operation that can
416    // be built on top of GL/D3D APIs.
417    if (NULL == rt->asTexture()) {
418        GrPrintf("Reading Dst of non-texture render target is not currently supported.\n");
419        return false;
420    }
421
422    const GrClipData* clip = this->getClip();
423    GrIRect copyRect;
424    clip->getConservativeBounds(this->getDrawState().getRenderTarget(), &copyRect);
425    SkIRect drawIBounds;
426    if (info->getDevIBounds(&drawIBounds)) {
427        if (!copyRect.intersect(drawIBounds)) {
428#if GR_DEBUG
429            GrPrintf("Missed an early reject. Bailing on draw from setupDstReadIfNecessary.\n");
430#endif
431            return false;
432        }
433    } else {
434#if GR_DEBUG
435        //GrPrintf("No dev bounds when dst copy is made.\n");
436#endif
437    }
438
439    GrDrawTarget::AutoGeometryAndStatePush agasp(this, kReset_ASRInit);
440
441    // The draw will resolve dst if it has MSAA. Two things to consider in the future:
442    // 1) to make the dst values be pre-resolve we'd need to be able to copy to MSAA
443    // texture and sample it correctly in the shader. 2) If 1 isn't available then we
444    // should just resolve and use the resolved texture directly rather than making a
445    // copy of it.
446    GrTextureDesc desc;
447    desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
448    desc.fWidth = copyRect.width();
449    desc.fHeight = copyRect.height();
450    desc.fSampleCnt = 0;
451    desc.fConfig = rt->config();
452
453    GrAutoScratchTexture ast(fContext, desc, GrContext::kApprox_ScratchTexMatch);
454
455    if (NULL == ast.texture()) {
456        GrPrintf("Failed to create temporary copy of destination texture.\n");
457        return false;
458    }
459    this->drawState()->disableState(GrDrawState::kClip_StateBit);
460    this->drawState()->setRenderTarget(ast.texture()->asRenderTarget());
461    static const int kTextureStage = 0;
462    SkMatrix matrix;
463    matrix.setIDiv(rt->width(), rt->height());
464    this->drawState()->createTextureEffect(kTextureStage, rt->asTexture(), matrix);
465
466    SkRect srcRect = SkRect::MakeFromIRect(copyRect);
467    SkRect dstRect = SkRect::MakeWH(SkIntToScalar(copyRect.width()),
468                                    SkIntToScalar(copyRect.height()));
469    this->drawRect(dstRect, NULL, &srcRect, NULL);
470
471    info->fDstCopy.setTexture(ast.texture());
472    info->fDstCopy.setOffset(copyRect.fLeft, copyRect.fTop);
473    return true;
474}
475
476void GrDrawTarget::drawIndexed(GrPrimitiveType type,
477                               int startVertex,
478                               int startIndex,
479                               int vertexCount,
480                               int indexCount,
481                               const SkRect* devBounds) {
482    if (indexCount > 0 && this->checkDraw(type, startVertex, startIndex, vertexCount, indexCount)) {
483        DrawInfo info;
484        info.fPrimitiveType = type;
485        info.fStartVertex   = startVertex;
486        info.fStartIndex    = startIndex;
487        info.fVertexCount   = vertexCount;
488        info.fIndexCount    = indexCount;
489
490        info.fInstanceCount         = 0;
491        info.fVerticesPerInstance   = 0;
492        info.fIndicesPerInstance    = 0;
493
494        if (NULL != devBounds) {
495            info.setDevBounds(*devBounds);
496        }
497        // TODO: We should continue with incorrect blending.
498        if (!this->setupDstReadIfNecessary(&info)) {
499            return;
500        }
501        this->onDraw(info);
502    }
503}
504
505void GrDrawTarget::drawNonIndexed(GrPrimitiveType type,
506                                  int startVertex,
507                                  int vertexCount,
508                                  const SkRect* devBounds) {
509    if (vertexCount > 0 && this->checkDraw(type, startVertex, -1, vertexCount, -1)) {
510        DrawInfo info;
511        info.fPrimitiveType = type;
512        info.fStartVertex   = startVertex;
513        info.fStartIndex    = 0;
514        info.fVertexCount   = vertexCount;
515        info.fIndexCount    = 0;
516
517        info.fInstanceCount         = 0;
518        info.fVerticesPerInstance   = 0;
519        info.fIndicesPerInstance    = 0;
520
521        if (NULL != devBounds) {
522            info.setDevBounds(*devBounds);
523        }
524        // TODO: We should continue with incorrect blending.
525        if (!this->setupDstReadIfNecessary(&info)) {
526            return;
527        }
528        this->onDraw(info);
529    }
530}
531
532void GrDrawTarget::stencilPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType fill) {
533    // TODO: extract portions of checkDraw that are relevant to path stenciling.
534    GrAssert(NULL != path);
535    GrAssert(this->caps()->pathStencilingSupport());
536    GrAssert(!stroke.isHairlineStyle());
537    GrAssert(!SkPath::IsInverseFillType(fill));
538    this->onStencilPath(path, stroke, fill);
539}
540
541////////////////////////////////////////////////////////////////////////////////
542
543bool GrDrawTarget::willUseHWAALines() const {
544    // There is a conflict between using smooth lines and our use of premultiplied alpha. Smooth
545    // lines tweak the incoming alpha value but not in a premul-alpha way. So we only use them when
546    // our alpha is 0xff and tweaking the color for partial coverage is OK
547    if (!this->caps()->hwAALineSupport() ||
548        !this->getDrawState().isHWAntialiasState()) {
549        return false;
550    }
551    GrDrawState::BlendOptFlags opts = this->getDrawState().getBlendOpts();
552    return (GrDrawState::kDisableBlend_BlendOptFlag & opts) &&
553           (GrDrawState::kCoverageAsAlpha_BlendOptFlag & opts);
554}
555
556bool GrDrawTarget::canApplyCoverage() const {
557    // we can correctly apply coverage if a) we have dual source blending
558    // or b) one of our blend optimizations applies.
559    return this->caps()->dualSourceBlendingSupport() ||
560           GrDrawState::kNone_BlendOpt != this->getDrawState().getBlendOpts(true);
561}
562
563////////////////////////////////////////////////////////////////////////////////
564
565void GrDrawTarget::drawIndexedInstances(GrPrimitiveType type,
566                                        int instanceCount,
567                                        int verticesPerInstance,
568                                        int indicesPerInstance,
569                                        const SkRect* devBounds) {
570    if (!verticesPerInstance || !indicesPerInstance) {
571        return;
572    }
573
574    int maxInstancesPerDraw = this->indexCountInCurrentSource() / indicesPerInstance;
575    if (!maxInstancesPerDraw) {
576        return;
577    }
578
579    DrawInfo info;
580    info.fPrimitiveType = type;
581    info.fStartIndex = 0;
582    info.fStartVertex = 0;
583    info.fIndicesPerInstance = indicesPerInstance;
584    info.fVerticesPerInstance = verticesPerInstance;
585
586    // Set the same bounds for all the draws.
587    if (NULL != devBounds) {
588        info.setDevBounds(*devBounds);
589    }
590    // TODO: We should continue with incorrect blending.
591    if (!this->setupDstReadIfNecessary(&info)) {
592        return;
593    }
594
595    while (instanceCount) {
596        info.fInstanceCount = GrMin(instanceCount, maxInstancesPerDraw);
597        info.fVertexCount = info.fInstanceCount * verticesPerInstance;
598        info.fIndexCount = info.fInstanceCount * indicesPerInstance;
599
600        if (this->checkDraw(type,
601                            info.fStartVertex,
602                            info.fStartIndex,
603                            info.fVertexCount,
604                            info.fIndexCount)) {
605            this->onDraw(info);
606        }
607        info.fStartVertex += info.fVertexCount;
608        instanceCount -= info.fInstanceCount;
609    }
610}
611
612////////////////////////////////////////////////////////////////////////////////
613
614void GrDrawTarget::drawRect(const GrRect& rect,
615                            const SkMatrix* matrix,
616                            const GrRect* localRect,
617                            const SkMatrix* localMatrix) {
618    // position + (optional) texture coord
619    static const GrVertexAttrib kAttribs[] = {
620        {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
621        {kVec2f_GrVertexAttribType, sizeof(GrPoint), kLocalCoord_GrVertexAttribBinding}
622    };
623    int attribCount = 1;
624
625    if (NULL != localRect) {
626        attribCount = 2;
627    }
628
629    GrDrawState::AutoViewMatrixRestore avmr;
630    if (NULL != matrix) {
631        avmr.set(this->drawState(), *matrix);
632    }
633
634    this->drawState()->setVertexAttribs(kAttribs, attribCount);
635    AutoReleaseGeometry geo(this, 4, 0);
636    if (!geo.succeeded()) {
637        GrPrintf("Failed to get space for vertices!\n");
638        return;
639    }
640
641    size_t vsize = this->drawState()->getVertexSize();
642    geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vsize);
643    if (NULL != localRect) {
644        GrAssert(attribCount == 2);
645        GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(geo.vertices()) +
646                                            kAttribs[1].fOffset);
647        coords->setRectFan(localRect->fLeft, localRect->fTop,
648                           localRect->fRight, localRect->fBottom,
649                           vsize);
650        if (NULL != localMatrix) {
651            localMatrix->mapPointsWithStride(coords, vsize, 4);
652        }
653    }
654    SkTLazy<SkRect> bounds;
655    if (this->getDrawState().willEffectReadDst()) {
656        bounds.init();
657        this->getDrawState().getViewMatrix().mapRect(bounds.get(), rect);
658    }
659
660    this->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4, bounds.getMaybeNull());
661}
662
663void GrDrawTarget::clipWillBeSet(const GrClipData* clipData) {
664}
665
666////////////////////////////////////////////////////////////////////////////////
667
668GrDrawTarget::AutoStateRestore::AutoStateRestore() {
669    fDrawTarget = NULL;
670}
671
672GrDrawTarget::AutoStateRestore::AutoStateRestore(GrDrawTarget* target,
673                                                 ASRInit init) {
674    fDrawTarget = NULL;
675    this->set(target, init);
676}
677
678GrDrawTarget::AutoStateRestore::~AutoStateRestore() {
679    if (NULL != fDrawTarget) {
680        fDrawTarget->setDrawState(fSavedState);
681        fSavedState->unref();
682    }
683}
684
685void GrDrawTarget::AutoStateRestore::set(GrDrawTarget* target, ASRInit init) {
686    GrAssert(NULL == fDrawTarget);
687    fDrawTarget = target;
688    fSavedState = target->drawState();
689    GrAssert(fSavedState);
690    fSavedState->ref();
691    if (kReset_ASRInit == init) {
692        // calls the default cons
693        fTempState.init();
694    } else {
695        GrAssert(kPreserve_ASRInit == init);
696        // calls the copy cons
697        fTempState.set(*fSavedState);
698    }
699    target->setDrawState(fTempState.get());
700}
701
702////////////////////////////////////////////////////////////////////////////////
703
704GrDrawTarget::AutoReleaseGeometry::AutoReleaseGeometry(
705                                         GrDrawTarget*  target,
706                                         int vertexCount,
707                                         int indexCount) {
708    fTarget = NULL;
709    this->set(target, vertexCount, indexCount);
710}
711
712GrDrawTarget::AutoReleaseGeometry::AutoReleaseGeometry() {
713    fTarget = NULL;
714}
715
716GrDrawTarget::AutoReleaseGeometry::~AutoReleaseGeometry() {
717    this->reset();
718}
719
720bool GrDrawTarget::AutoReleaseGeometry::set(GrDrawTarget*  target,
721                                            int vertexCount,
722                                            int indexCount) {
723    this->reset();
724    fTarget = target;
725    bool success = true;
726    if (NULL != fTarget) {
727        fTarget = target;
728        success = target->reserveVertexAndIndexSpace(vertexCount,
729                                                     indexCount,
730                                                     &fVertices,
731                                                     &fIndices);
732        if (!success) {
733            fTarget = NULL;
734            this->reset();
735        }
736    }
737    GrAssert(success == (NULL != fTarget));
738    return success;
739}
740
741void GrDrawTarget::AutoReleaseGeometry::reset() {
742    if (NULL != fTarget) {
743        if (NULL != fVertices) {
744            fTarget->resetVertexSource();
745        }
746        if (NULL != fIndices) {
747            fTarget->resetIndexSource();
748        }
749        fTarget = NULL;
750    }
751    fVertices = NULL;
752    fIndices = NULL;
753}
754
755GrDrawTarget::AutoClipRestore::AutoClipRestore(GrDrawTarget* target, const SkIRect& newClip) {
756    fTarget = target;
757    fClip = fTarget->getClip();
758    fStack.init();
759    fStack.get()->clipDevRect(newClip, SkRegion::kReplace_Op);
760    fReplacementClip.fClipStack = fStack.get();
761    target->setClip(&fReplacementClip);
762}
763
764///////////////////////////////////////////////////////////////////////////////
765
766SK_DEFINE_INST_COUNT(GrDrawTargetCaps)
767
768void GrDrawTargetCaps::reset() {
769    f8BitPaletteSupport = false;
770    fNPOTTextureTileSupport = false;
771    fTwoSidedStencilSupport = false;
772    fStencilWrapOpsSupport = false;
773    fHWAALineSupport = false;
774    fShaderDerivativeSupport = false;
775    fGeometryShaderSupport = false;
776    fDualSourceBlendingSupport = false;
777    fBufferLockSupport = false;
778    fPathStencilingSupport = false;
779
780    fMaxRenderTargetSize = 0;
781    fMaxTextureSize = 0;
782    fMaxSampleCount = 0;
783}
784
785GrDrawTargetCaps& GrDrawTargetCaps::operator=(const GrDrawTargetCaps& other) {
786    f8BitPaletteSupport = other.f8BitPaletteSupport;
787    fNPOTTextureTileSupport = other.fNPOTTextureTileSupport;
788    fTwoSidedStencilSupport = other.fTwoSidedStencilSupport;
789    fStencilWrapOpsSupport = other.fStencilWrapOpsSupport;
790    fHWAALineSupport = other.fHWAALineSupport;
791    fShaderDerivativeSupport = other.fShaderDerivativeSupport;
792    fGeometryShaderSupport = other.fGeometryShaderSupport;
793    fDualSourceBlendingSupport = other.fDualSourceBlendingSupport;
794    fBufferLockSupport = other.fBufferLockSupport;
795    fPathStencilingSupport = other.fPathStencilingSupport;
796
797    fMaxRenderTargetSize = other.fMaxRenderTargetSize;
798    fMaxTextureSize = other.fMaxTextureSize;
799    fMaxSampleCount = other.fMaxSampleCount;
800
801    return *this;
802}
803
804void GrDrawTargetCaps::print() const {
805    static const char* gNY[] = {"NO", "YES"};
806    GrPrintf("8 Bit Palette Support       : %s\n", gNY[f8BitPaletteSupport]);
807    GrPrintf("NPOT Texture Tile Support   : %s\n", gNY[fNPOTTextureTileSupport]);
808    GrPrintf("Two Sided Stencil Support   : %s\n", gNY[fTwoSidedStencilSupport]);
809    GrPrintf("Stencil Wrap Ops  Support   : %s\n", gNY[fStencilWrapOpsSupport]);
810    GrPrintf("HW AA Lines Support         : %s\n", gNY[fHWAALineSupport]);
811    GrPrintf("Shader Derivative Support   : %s\n", gNY[fShaderDerivativeSupport]);
812    GrPrintf("Geometry Shader Support     : %s\n", gNY[fGeometryShaderSupport]);
813    GrPrintf("Dual Source Blending Support: %s\n", gNY[fDualSourceBlendingSupport]);
814    GrPrintf("Buffer Lock Support         : %s\n", gNY[fBufferLockSupport]);
815    GrPrintf("Path Stenciling Support     : %s\n", gNY[fPathStencilingSupport]);
816    GrPrintf("Max Texture Size            : %d\n", fMaxTextureSize);
817    GrPrintf("Max Render Target Size      : %d\n", fMaxRenderTargetSize);
818    GrPrintf("Max Sample Count            : %d\n", fMaxSampleCount);
819}
820