/* * Copyright 2010 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "GrDrawTarget.h" #include "GrBatch.h" #include "GrCaps.h" #include "GrContext.h" #include "GrPath.h" #include "GrPipeline.h" #include "GrMemoryPool.h" #include "GrRectBatch.h" #include "GrRenderTarget.h" #include "GrRenderTargetPriv.h" #include "GrSurfacePriv.h" #include "GrTemplates.h" #include "GrTexture.h" #include "GrVertexBuffer.h" #include "SkStrokeRec.h" //////////////////////////////////////////////////////////////////////////////// #define DEBUG_INVAL_BUFFER 0xdeadcafe #define DEBUG_INVAL_START_IDX -1 GrDrawTarget::GrDrawTarget(GrContext* context) : fContext(context) , fCaps(SkRef(context->getGpu()->caps())) , fGpuTraceMarkerCount(0) , fFlushing(false) { SkASSERT(context); } //////////////////////////////////////////////////////////////////////////////// bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder, const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, GrDeviceCoordTexture* dstCopy, const SkRect* drawBounds) { if (!pipelineBuilder.willXPNeedDstCopy(*this->caps(), colorPOI, coveragePOI)) { return true; } GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); if (this->caps()->textureBarrierSupport()) { if (GrTexture* rtTex = rt->asTexture()) { // The render target is a texture, se we can read from it directly in the shader. The XP // will be responsible to detect this situation and request a texture barrier. dstCopy->setTexture(rtTex); dstCopy->setOffset(0, 0); return true; } } SkIRect copyRect; pipelineBuilder.clip().getConservativeBounds(rt, ©Rect); if (drawBounds) { SkIRect drawIBounds; drawBounds->roundOut(&drawIBounds); if (!copyRect.intersect(drawIBounds)) { #ifdef SK_DEBUG GrContextDebugf(fContext, "Missed an early reject. " "Bailing on draw from setupDstReadIfNecessary.\n"); #endif return false; } } else { #ifdef SK_DEBUG //SkDebugf("No dev bounds when dst copy is made.\n"); #endif } // MSAA consideration: When there is support for reading MSAA samples in the shader we could // have per-sample dst values by making the copy multisampled. GrSurfaceDesc desc; if (!this->getGpu()->initCopySurfaceDstDesc(rt, &desc)) { desc.fOrigin = kDefault_GrSurfaceOrigin; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fConfig = rt->config(); } desc.fWidth = copyRect.width(); desc.fHeight = copyRect.height(); SkAutoTUnref copy(fContext->textureProvider()->refScratchTexture(desc, GrTextureProvider::kApprox_ScratchTexMatch)); if (!copy) { SkDebugf("Failed to create temporary copy of destination texture.\n"); return false; } SkIPoint dstPoint = {0, 0}; if (this->copySurface(copy, rt, copyRect, dstPoint)) { dstCopy->setTexture(copy); dstCopy->setOffset(copyRect.fLeft, copyRect.fTop); return true; } else { return false; } } void GrDrawTarget::flush() { if (fFlushing) { return; } fFlushing = true; this->getGpu()->saveActiveTraceMarkers(); this->onFlush(); this->getGpu()->restoreActiveTraceMarkers(); fFlushing = false; this->reset(); } void GrDrawTarget::drawBatch(GrPipelineBuilder* pipelineBuilder, GrBatch* batch) { SkASSERT(pipelineBuilder); // TODO some kind of checkdraw, but not at this level // Setup clip GrScissorState scissorState; GrPipelineBuilder::AutoRestoreFragmentProcessors arfp; GrPipelineBuilder::AutoRestoreStencil ars; if (!this->setupClip(pipelineBuilder, &arfp, &ars, &scissorState, &batch->bounds())) { return; } // Batch bounds are tight, so for dev copies // TODO move this into setupDstReadIfNecessary when paths are in batch SkRect bounds = batch->bounds(); bounds.outset(0.5f, 0.5f); GrDrawTarget::PipelineInfo pipelineInfo(pipelineBuilder, &scissorState, batch, &bounds, this); if (pipelineInfo.mustSkipDraw()) { return; } this->onDrawBatch(batch, pipelineInfo); } static const GrStencilSettings& winding_path_stencil_settings() { GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings, kIncClamp_StencilOp, kIncClamp_StencilOp, kAlwaysIfInClip_StencilFunc, 0xFFFF, 0xFFFF, 0xFFFF); return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings); } static const GrStencilSettings& even_odd_path_stencil_settings() { GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings, kInvert_StencilOp, kInvert_StencilOp, kAlwaysIfInClip_StencilFunc, 0xFFFF, 0xFFFF, 0xFFFF); return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings); } void GrDrawTarget::getPathStencilSettingsForFilltype(GrPathRendering::FillType fill, const GrStencilAttachment* sb, GrStencilSettings* outStencilSettings) { switch (fill) { default: SkFAIL("Unexpected path fill."); case GrPathRendering::kWinding_FillType: *outStencilSettings = winding_path_stencil_settings(); break; case GrPathRendering::kEvenOdd_FillType: *outStencilSettings = even_odd_path_stencil_settings(); break; } this->clipMaskManager()->adjustPathStencilParams(sb, outStencilSettings); } void GrDrawTarget::stencilPath(GrPipelineBuilder* pipelineBuilder, const GrPathProcessor* pathProc, const GrPath* path, GrPathRendering::FillType fill) { // TODO: extract portions of checkDraw that are relevant to path stenciling. SkASSERT(path); SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport()); SkASSERT(pipelineBuilder); // Setup clip GrScissorState scissorState; GrPipelineBuilder::AutoRestoreFragmentProcessors arfp; GrPipelineBuilder::AutoRestoreStencil ars; if (!this->setupClip(pipelineBuilder, &arfp, &ars, &scissorState, NULL)) { return; } // set stencil settings for path GrStencilSettings stencilSettings; GrRenderTarget* rt = pipelineBuilder->getRenderTarget(); GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment(); this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings); this->onStencilPath(*pipelineBuilder, pathProc, path, scissorState, stencilSettings); } void GrDrawTarget::drawPath(GrPipelineBuilder* pipelineBuilder, const GrPathProcessor* pathProc, const GrPath* path, GrPathRendering::FillType fill) { // TODO: extract portions of checkDraw that are relevant to path rendering. SkASSERT(path); SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport()); SkASSERT(pipelineBuilder); SkRect devBounds = path->getBounds(); pathProc->viewMatrix().mapRect(&devBounds); // Setup clip GrScissorState scissorState; GrPipelineBuilder::AutoRestoreFragmentProcessors arfp; GrPipelineBuilder::AutoRestoreStencil ars; if (!this->setupClip(pipelineBuilder, &arfp, &ars, &scissorState, &devBounds)) { return; } // set stencil settings for path GrStencilSettings stencilSettings; GrRenderTarget* rt = pipelineBuilder->getRenderTarget(); GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment(); this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings); GrDrawTarget::PipelineInfo pipelineInfo(pipelineBuilder, &scissorState, pathProc, &devBounds, this); if (pipelineInfo.mustSkipDraw()) { return; } this->onDrawPath(pathProc, path, stencilSettings, pipelineInfo); } void GrDrawTarget::drawPaths(GrPipelineBuilder* pipelineBuilder, const GrPathProcessor* pathProc, const GrPathRange* pathRange, const void* indices, PathIndexType indexType, const float transformValues[], PathTransformType transformType, int count, GrPathRendering::FillType fill) { SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport()); SkASSERT(pathRange); SkASSERT(indices); SkASSERT(0 == reinterpret_cast(indices) % GrPathRange::PathIndexSizeInBytes(indexType)); SkASSERT(transformValues); SkASSERT(pipelineBuilder); // Setup clip GrScissorState scissorState; GrPipelineBuilder::AutoRestoreFragmentProcessors arfp; GrPipelineBuilder::AutoRestoreStencil ars; if (!this->setupClip(pipelineBuilder, &arfp, &ars, &scissorState, NULL)) { return; } // set stencil settings for path GrStencilSettings stencilSettings; GrRenderTarget* rt = pipelineBuilder->getRenderTarget(); GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment(); this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings); // Don't compute a bounding box for dst copy texture, we'll opt // instead for it to just copy the entire dst. Realistically this is a moot // point, because any context that supports NV_path_rendering will also // support NV_blend_equation_advanced. GrDrawTarget::PipelineInfo pipelineInfo(pipelineBuilder, &scissorState, pathProc, NULL, this); if (pipelineInfo.mustSkipDraw()) { return; } this->onDrawPaths(pathProc, pathRange, indices, indexType, transformValues, transformType, count, stencilSettings, pipelineInfo); } void GrDrawTarget::drawRect(GrPipelineBuilder* pipelineBuilder, GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, const SkRect* localRect, const SkMatrix* localMatrix) { SkAutoTUnref batch(GrRectBatch::Create(color, viewMatrix, rect, localRect, localMatrix)); this->drawBatch(pipelineBuilder, batch); } void GrDrawTarget::clear(const SkIRect* rect, GrColor color, bool canIgnoreRect, GrRenderTarget* renderTarget) { if (fCaps->useDrawInsteadOfClear()) { // This works around a driver bug with clear by drawing a rect instead. // The driver will ignore a clear if it is the only thing rendered to a // target before the target is read. SkIRect rtRect = SkIRect::MakeWH(renderTarget->width(), renderTarget->height()); if (NULL == rect || canIgnoreRect || rect->contains(rtRect)) { rect = &rtRect; // We first issue a discard() since that may help tilers. this->discard(renderTarget); } GrPipelineBuilder pipelineBuilder; pipelineBuilder.setRenderTarget(renderTarget); this->drawSimpleRect(&pipelineBuilder, color, SkMatrix::I(), *rect); } else { this->onClear(rect, color, canIgnoreRect, renderTarget); } } typedef GrTraceMarkerSet::Iter TMIter; void GrDrawTarget::saveActiveTraceMarkers() { if (this->caps()->gpuTracingSupport()) { SkASSERT(0 == fStoredTraceMarkers.count()); fStoredTraceMarkers.addSet(fActiveTraceMarkers); for (TMIter iter = fStoredTraceMarkers.begin(); iter != fStoredTraceMarkers.end(); ++iter) { this->removeGpuTraceMarker(&(*iter)); } } } void GrDrawTarget::restoreActiveTraceMarkers() { if (this->caps()->gpuTracingSupport()) { SkASSERT(0 == fActiveTraceMarkers.count()); for (TMIter iter = fStoredTraceMarkers.begin(); iter != fStoredTraceMarkers.end(); ++iter) { this->addGpuTraceMarker(&(*iter)); } for (TMIter iter = fActiveTraceMarkers.begin(); iter != fActiveTraceMarkers.end(); ++iter) { this->fStoredTraceMarkers.remove(*iter); } } } void GrDrawTarget::addGpuTraceMarker(const GrGpuTraceMarker* marker) { if (this->caps()->gpuTracingSupport()) { SkASSERT(fGpuTraceMarkerCount >= 0); this->fActiveTraceMarkers.add(*marker); ++fGpuTraceMarkerCount; } } void GrDrawTarget::removeGpuTraceMarker(const GrGpuTraceMarker* marker) { if (this->caps()->gpuTracingSupport()) { SkASSERT(fGpuTraceMarkerCount >= 1); this->fActiveTraceMarkers.remove(*marker); --fGpuTraceMarkerCount; } } //////////////////////////////////////////////////////////////////////////////// namespace { // returns true if the read/written rect intersects the src/dst and false if not. bool clip_srcrect_and_dstpoint(const GrSurface* dst, const GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint, SkIRect* clippedSrcRect, SkIPoint* clippedDstPoint) { *clippedSrcRect = srcRect; *clippedDstPoint = dstPoint; // clip the left edge to src and dst bounds, adjusting dstPoint if necessary if (clippedSrcRect->fLeft < 0) { clippedDstPoint->fX -= clippedSrcRect->fLeft; clippedSrcRect->fLeft = 0; } if (clippedDstPoint->fX < 0) { clippedSrcRect->fLeft -= clippedDstPoint->fX; clippedDstPoint->fX = 0; } // clip the top edge to src and dst bounds, adjusting dstPoint if necessary if (clippedSrcRect->fTop < 0) { clippedDstPoint->fY -= clippedSrcRect->fTop; clippedSrcRect->fTop = 0; } if (clippedDstPoint->fY < 0) { clippedSrcRect->fTop -= clippedDstPoint->fY; clippedDstPoint->fY = 0; } // clip the right edge to the src and dst bounds. if (clippedSrcRect->fRight > src->width()) { clippedSrcRect->fRight = src->width(); } if (clippedDstPoint->fX + clippedSrcRect->width() > dst->width()) { clippedSrcRect->fRight = clippedSrcRect->fLeft + dst->width() - clippedDstPoint->fX; } // clip the bottom edge to the src and dst bounds. if (clippedSrcRect->fBottom > src->height()) { clippedSrcRect->fBottom = src->height(); } if (clippedDstPoint->fY + clippedSrcRect->height() > dst->height()) { clippedSrcRect->fBottom = clippedSrcRect->fTop + dst->height() - clippedDstPoint->fY; } // The above clipping steps may have inverted the rect if it didn't intersect either the src or // dst bounds. return !clippedSrcRect->isEmpty(); } } bool GrDrawTarget::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { SkASSERT(dst); SkASSERT(src); SkIRect clippedSrcRect; SkIPoint clippedDstPoint; // If the rect is outside the src or dst then we've already succeeded. if (!clip_srcrect_and_dstpoint(dst, src, srcRect, dstPoint, &clippedSrcRect, &clippedDstPoint)) { return true; } if (this->getGpu()->canCopySurface(dst, src, clippedSrcRect, clippedDstPoint)) { this->onCopySurface(dst, src, clippedSrcRect, clippedDstPoint); return true; } GrRenderTarget* rt = dst->asRenderTarget(); GrTexture* tex = src->asTexture(); if ((dst == src) || !rt || !tex) { return false; } GrPipelineBuilder pipelineBuilder; pipelineBuilder.setRenderTarget(rt); SkMatrix matrix; matrix.setTranslate(SkIntToScalar(clippedSrcRect.fLeft - clippedDstPoint.fX), SkIntToScalar(clippedSrcRect.fTop - clippedDstPoint.fY)); matrix.postIDiv(tex->width(), tex->height()); pipelineBuilder.addColorTextureProcessor(tex, matrix); SkIRect dstRect = SkIRect::MakeXYWH(clippedDstPoint.fX, clippedDstPoint.fY, clippedSrcRect.width(), clippedSrcRect.height()); this->drawSimpleRect(&pipelineBuilder, GrColor_WHITE, SkMatrix::I(), dstRect); return true; } bool GrDrawTarget::canCopySurface(const GrSurface* dst, const GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { SkASSERT(dst); SkASSERT(src); SkIRect clippedSrcRect; SkIPoint clippedDstPoint; // If the rect is outside the src or dst then we're guaranteed success if (!clip_srcrect_and_dstpoint(dst, src, srcRect, dstPoint, &clippedSrcRect, &clippedDstPoint)) { return true; } return ((dst != src) && dst->asRenderTarget() && src->asTexture()) || this->getGpu()->canCopySurface(dst, src, clippedSrcRect, clippedDstPoint); } void GrDrawTarget::setupPipeline(const PipelineInfo& pipelineInfo, GrPipeline* pipeline) { SkNEW_PLACEMENT_ARGS(pipeline, GrPipeline, (*pipelineInfo.fPipelineBuilder, pipelineInfo.fColorPOI, pipelineInfo.fCoveragePOI, *this->caps(), *pipelineInfo.fScissor, &pipelineInfo.fDstCopy)); } /////////////////////////////////////////////////////////////////////////////// GrDrawTarget::PipelineInfo::PipelineInfo(GrPipelineBuilder* pipelineBuilder, GrScissorState* scissor, const GrPrimitiveProcessor* primProc, const SkRect* devBounds, GrDrawTarget* target) : fPipelineBuilder(pipelineBuilder) , fScissor(scissor) { fColorPOI = fPipelineBuilder->colorProcInfo(primProc); fCoveragePOI = fPipelineBuilder->coverageProcInfo(primProc); if (!target->setupDstReadIfNecessary(*fPipelineBuilder, fColorPOI, fCoveragePOI, &fDstCopy, devBounds)) { fPipelineBuilder = NULL; } } GrDrawTarget::PipelineInfo::PipelineInfo(GrPipelineBuilder* pipelineBuilder, GrScissorState* scissor, const GrBatch* batch, const SkRect* devBounds, GrDrawTarget* target) : fPipelineBuilder(pipelineBuilder) , fScissor(scissor) { fColorPOI = fPipelineBuilder->colorProcInfo(batch); fCoveragePOI = fPipelineBuilder->coverageProcInfo(batch); if (!target->setupDstReadIfNecessary(*fPipelineBuilder, fColorPOI, fCoveragePOI, &fDstCopy, devBounds)) { fPipelineBuilder = NULL; } } /////////////////////////////////////////////////////////////////////////////// GrShaderCaps::GrShaderCaps() { fShaderDerivativeSupport = false; fGeometryShaderSupport = false; fPathRenderingSupport = false; fDstReadInShaderSupport = false; fDualSourceBlendingSupport = false; fMixedSamplesSupport = false; fShaderPrecisionVaries = false; } static const char* shader_type_to_string(GrShaderType type) { switch (type) { case kVertex_GrShaderType: return "vertex"; case kGeometry_GrShaderType: return "geometry"; case kFragment_GrShaderType: return "fragment"; } return ""; } static const char* precision_to_string(GrSLPrecision p) { switch (p) { case kLow_GrSLPrecision: return "low"; case kMedium_GrSLPrecision: return "medium"; case kHigh_GrSLPrecision: return "high"; } return ""; } SkString GrShaderCaps::dump() const { SkString r; static const char* gNY[] = { "NO", "YES" }; r.appendf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]); r.appendf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]); r.appendf("Path Rendering Support : %s\n", gNY[fPathRenderingSupport]); r.appendf("Dst Read In Shader Support : %s\n", gNY[fDstReadInShaderSupport]); r.appendf("Dual Source Blending Support : %s\n", gNY[fDualSourceBlendingSupport]); r.appendf("Mixed Samples Support : %s\n", gNY[fMixedSamplesSupport]); r.appendf("Shader Float Precisions (varies: %s):\n", gNY[fShaderPrecisionVaries]); for (int s = 0; s < kGrShaderTypeCount; ++s) { GrShaderType shaderType = static_cast(s); r.appendf("\t%s:\n", shader_type_to_string(shaderType)); for (int p = 0; p < kGrSLPrecisionCount; ++p) { if (fFloatPrecisions[s][p].supported()) { GrSLPrecision precision = static_cast(p); r.appendf("\t\t%s: log_low: %d log_high: %d bits: %d\n", precision_to_string(precision), fFloatPrecisions[s][p].fLogRangeLow, fFloatPrecisions[s][p].fLogRangeHigh, fFloatPrecisions[s][p].fBits); } } } return r; } /////////////////////////////////////////////////////////////////////////////// GrCaps::GrCaps() { fMipMapSupport = false; fNPOTTextureTileSupport = false; fTwoSidedStencilSupport = false; fStencilWrapOpsSupport = false; fDiscardRenderTargetSupport = false; fReuseScratchTextures = true; fGpuTracingSupport = false; fCompressedTexSubImageSupport = false; fOversizedStencilSupport = false; fTextureBarrierSupport = false; fUseDrawInsteadOfClear = false; fBlendEquationSupport = kBasic_BlendEquationSupport; fMapBufferFlags = kNone_MapFlags; fMaxRenderTargetSize = 0; fMaxTextureSize = 0; fMaxSampleCount = 0; memset(fConfigRenderSupport, 0, sizeof(fConfigRenderSupport)); memset(fConfigTextureSupport, 0, sizeof(fConfigTextureSupport)); } static SkString map_flags_to_string(uint32_t flags) { SkString str; if (GrCaps::kNone_MapFlags == flags) { str = "none"; } else { SkASSERT(GrCaps::kCanMap_MapFlag & flags); SkDEBUGCODE(flags &= ~GrCaps::kCanMap_MapFlag); str = "can_map"; if (GrCaps::kSubset_MapFlag & flags) { str.append(" partial"); } else { str.append(" full"); } SkDEBUGCODE(flags &= ~GrCaps::kSubset_MapFlag); } SkASSERT(0 == flags); // Make sure we handled all the flags. return str; } SkString GrCaps::dump() const { SkString r; static const char* gNY[] = {"NO", "YES"}; r.appendf("MIP Map Support : %s\n", gNY[fMipMapSupport]); r.appendf("NPOT Texture Tile Support : %s\n", gNY[fNPOTTextureTileSupport]); r.appendf("Two Sided Stencil Support : %s\n", gNY[fTwoSidedStencilSupport]); r.appendf("Stencil Wrap Ops Support : %s\n", gNY[fStencilWrapOpsSupport]); r.appendf("Discard Render Target Support : %s\n", gNY[fDiscardRenderTargetSupport]); r.appendf("Reuse Scratch Textures : %s\n", gNY[fReuseScratchTextures]); r.appendf("Gpu Tracing Support : %s\n", gNY[fGpuTracingSupport]); r.appendf("Compressed Update Support : %s\n", gNY[fCompressedTexSubImageSupport]); r.appendf("Oversized Stencil Support : %s\n", gNY[fOversizedStencilSupport]); r.appendf("Texture Barrier Support : %s\n", gNY[fTextureBarrierSupport]); r.appendf("Draw Instead of Clear [workaround] : %s\n", gNY[fUseDrawInsteadOfClear]); r.appendf("Max Texture Size : %d\n", fMaxTextureSize); r.appendf("Max Render Target Size : %d\n", fMaxRenderTargetSize); r.appendf("Max Sample Count : %d\n", fMaxSampleCount); static const char* kBlendEquationSupportNames[] = { "Basic", "Advanced", "Advanced Coherent", }; GR_STATIC_ASSERT(0 == kBasic_BlendEquationSupport); GR_STATIC_ASSERT(1 == kAdvanced_BlendEquationSupport); GR_STATIC_ASSERT(2 == kAdvancedCoherent_BlendEquationSupport); GR_STATIC_ASSERT(SK_ARRAY_COUNT(kBlendEquationSupportNames) == kLast_BlendEquationSupport + 1); r.appendf("Blend Equation Support : %s\n", kBlendEquationSupportNames[fBlendEquationSupport]); r.appendf("Map Buffer Support : %s\n", map_flags_to_string(fMapBufferFlags).c_str()); static const char* kConfigNames[] = { "Unknown", // kUnknown_GrPixelConfig "Alpha8", // kAlpha_8_GrPixelConfig, "Index8", // kIndex_8_GrPixelConfig, "RGB565", // kRGB_565_GrPixelConfig, "RGBA444", // kRGBA_4444_GrPixelConfig, "RGBA8888", // kRGBA_8888_GrPixelConfig, "BGRA8888", // kBGRA_8888_GrPixelConfig, "SRGBA8888",// kSRGBA_8888_GrPixelConfig, "ETC1", // kETC1_GrPixelConfig, "LATC", // kLATC_GrPixelConfig, "R11EAC", // kR11_EAC_GrPixelConfig, "ASTC12x12",// kASTC_12x12_GrPixelConfig, "RGBAFloat",// kRGBA_float_GrPixelConfig "AlphaHalf",// kAlpha_half_GrPixelConfig "RGBAHalf", // kRGBA_half_GrPixelConfig }; GR_STATIC_ASSERT(0 == kUnknown_GrPixelConfig); GR_STATIC_ASSERT(1 == kAlpha_8_GrPixelConfig); GR_STATIC_ASSERT(2 == kIndex_8_GrPixelConfig); GR_STATIC_ASSERT(3 == kRGB_565_GrPixelConfig); GR_STATIC_ASSERT(4 == kRGBA_4444_GrPixelConfig); GR_STATIC_ASSERT(5 == kRGBA_8888_GrPixelConfig); GR_STATIC_ASSERT(6 == kBGRA_8888_GrPixelConfig); GR_STATIC_ASSERT(7 == kSRGBA_8888_GrPixelConfig); GR_STATIC_ASSERT(8 == kETC1_GrPixelConfig); GR_STATIC_ASSERT(9 == kLATC_GrPixelConfig); GR_STATIC_ASSERT(10 == kR11_EAC_GrPixelConfig); GR_STATIC_ASSERT(11 == kASTC_12x12_GrPixelConfig); GR_STATIC_ASSERT(12 == kRGBA_float_GrPixelConfig); GR_STATIC_ASSERT(13 == kAlpha_half_GrPixelConfig); GR_STATIC_ASSERT(14 == kRGBA_half_GrPixelConfig); GR_STATIC_ASSERT(SK_ARRAY_COUNT(kConfigNames) == kGrPixelConfigCnt); SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][0]); SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][1]); for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i) { r.appendf("%s is renderable: %s, with MSAA: %s\n", kConfigNames[i], gNY[fConfigRenderSupport[i][0]], gNY[fConfigRenderSupport[i][1]]); } SkASSERT(!fConfigTextureSupport[kUnknown_GrPixelConfig]); for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i) { r.appendf("%s is uploadable to a texture: %s\n", kConfigNames[i], gNY[fConfigTextureSupport[i]]); } return r; } /////////////////////////////////////////////////////////////////////////////////////////////////// bool GrClipTarget::setupClip(GrPipelineBuilder* pipelineBuilder, GrPipelineBuilder::AutoRestoreFragmentProcessors* arfp, GrPipelineBuilder::AutoRestoreStencil* ars, GrScissorState* scissorState, const SkRect* devBounds) { return fClipMaskManager.setupClipping(pipelineBuilder, arfp, ars, scissorState, devBounds); }