1 /* 2 Copyright 2011 Google Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #include "GrContext.h" 18 #include "GrGpu.h" 19 #include "GrTextureCache.h" 20 #include "GrTextStrike.h" 21 #include "GrMemory.h" 22 #include "GrClipIterator.h" 23 #include "GrIndexBuffer.h" 24 #include "GrInOrderDrawBuffer.h" 25 #include "GrBufferAllocPool.h" 26 #include "GrPathRenderer.h" 27 28 // larger than this, and we don't AA. set to 0 for no AA 29 #ifndef GR_MAX_OFFSCREEN_AA_DIM 30 #define GR_MAX_OFFSCREEN_AA_DIM 0 31 #endif 32 33 #define DEFER_TEXT_RENDERING 1 34 35 #define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB) 36 37 static const size_t MAX_TEXTURE_CACHE_COUNT = 128; 38 static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024; 39 40 static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18; 41 static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4; 42 43 // We are currently only batching Text and drawRectToRect, both 44 // of which use the quad index buffer. 45 static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0; 46 static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0; 47 48 GrContext* GrContext::Create(GrEngine engine, 49 GrPlatform3DContext context3D) { 50 GrContext* ctx = NULL; 51 GrGpu* fGpu = GrGpu::Create(engine, context3D); 52 if (NULL != fGpu) { 53 ctx = new GrContext(fGpu); 54 fGpu->unref(); 55 } 56 return ctx; 57 } 58 59 GrContext* GrContext::CreateGLShaderContext() { 60 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0); 61 } 62 63 GrContext::~GrContext() { 64 this->flush(); 65 delete fTextureCache; 66 delete fFontCache; 67 delete fDrawBuffer; 68 delete fDrawBufferVBAllocPool; 69 delete fDrawBufferIBAllocPool; 70 GrSafeUnref(fCustomPathRenderer); 71 GrSafeUnref(fAAFillRectIndexBuffer); 72 GrSafeUnref(fAAStrokeRectIndexBuffer); 73 fGpu->unref(); 74 } 75 76 void GrContext::contextLost() { 77 contextDestroyed(); 78 this->setupDrawBuffer(); 79 } 80 81 void GrContext::contextDestroyed() { 82 // abandon first to so destructors 83 // don't try to free the resources in the API. 84 fGpu->abandonResources(); 85 86 delete fDrawBuffer; 87 fDrawBuffer = NULL; 88 89 delete fDrawBufferVBAllocPool; 90 fDrawBufferVBAllocPool = NULL; 91 92 delete fDrawBufferIBAllocPool; 93 fDrawBufferIBAllocPool = NULL; 94 95 GrSafeSetNull(fAAFillRectIndexBuffer); 96 GrSafeSetNull(fAAStrokeRectIndexBuffer); 97 98 fTextureCache->removeAll(); 99 fFontCache->freeAll(); 100 fGpu->markContextDirty(); 101 } 102 103 void GrContext::resetContext() { 104 fGpu->markContextDirty(); 105 } 106 107 void GrContext::freeGpuResources() { 108 this->flush(); 109 fTextureCache->removeAll(); 110 fFontCache->freeAll(); 111 } 112 113 //////////////////////////////////////////////////////////////////////////////// 114 115 int GrContext::PaintStageVertexLayoutBits( 116 const GrPaint& paint, 117 const bool hasTexCoords[GrPaint::kTotalStages]) { 118 int stageMask = paint.getActiveStageMask(); 119 int layout = 0; 120 for (int i = 0; i < GrPaint::kTotalStages; ++i) { 121 if ((1 << i) & stageMask) { 122 if (NULL != hasTexCoords && hasTexCoords[i]) { 123 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i); 124 } else { 125 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i); 126 } 127 } 128 } 129 return layout; 130 } 131 132 133 //////////////////////////////////////////////////////////////////////////////// 134 135 enum { 136 kNPOTBit = 0x1, 137 kFilterBit = 0x2, 138 kKeylessBit = 0x4, 139 }; 140 141 bool GrContext::finalizeTextureKey(GrTextureKey* key, 142 const GrSamplerState& sampler, 143 bool keyless) const { 144 uint32_t bits = 0; 145 uint16_t width = key->width(); 146 uint16_t height = key->height(); 147 148 if (!fGpu->npotTextureTileSupport()) { 149 bool isPow2 = GrIsPow2(width) && GrIsPow2(height); 150 151 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) || 152 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode); 153 154 if (tiled && !isPow2) { 155 bits |= kNPOTBit; 156 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) { 157 bits |= kFilterBit; 158 } 159 } 160 } 161 162 if (keyless) { 163 bits |= kKeylessBit; 164 } 165 key->finalize(bits); 166 return 0 != bits; 167 } 168 169 GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key, 170 const GrSamplerState& sampler) { 171 finalizeTextureKey(key, sampler, false); 172 return fTextureCache->findAndLock(*key); 173 } 174 175 static void stretchImage(void* dst, 176 int dstW, 177 int dstH, 178 void* src, 179 int srcW, 180 int srcH, 181 int bpp) { 182 GrFixed dx = (srcW << 16) / dstW; 183 GrFixed dy = (srcH << 16) / dstH; 184 185 GrFixed y = dy >> 1; 186 187 int dstXLimit = dstW*bpp; 188 for (int j = 0; j < dstH; ++j) { 189 GrFixed x = dx >> 1; 190 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp; 191 void* dstRow = (uint8_t*)dst + j*dstW*bpp; 192 for (int i = 0; i < dstXLimit; i += bpp) { 193 memcpy((uint8_t*) dstRow + i, 194 (uint8_t*) srcRow + (x>>16)*bpp, 195 bpp); 196 x += dx; 197 } 198 y += dy; 199 } 200 } 201 202 GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, 203 const GrSamplerState& sampler, 204 const GrTextureDesc& desc, 205 void* srcData, size_t rowBytes) { 206 GrAssert(key->width() == desc.fWidth); 207 GrAssert(key->height() == desc.fHeight); 208 209 #if GR_DUMP_TEXTURE_UPLOAD 210 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight); 211 #endif 212 213 GrTextureEntry* entry = NULL; 214 bool special = finalizeTextureKey(key, sampler, false); 215 if (special) { 216 GrTextureEntry* clampEntry; 217 GrTextureKey clampKey(*key); 218 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter()); 219 220 if (NULL == clampEntry) { 221 clampEntry = createAndLockTexture(&clampKey, 222 GrSamplerState::ClampNoFilter(), 223 desc, srcData, rowBytes); 224 GrAssert(NULL != clampEntry); 225 if (NULL == clampEntry) { 226 return NULL; 227 } 228 } 229 GrTextureDesc rtDesc = desc; 230 rtDesc.fFlags = rtDesc.fFlags | 231 kRenderTarget_GrTextureFlagBit | 232 kNoStencil_GrTextureFlagBit; 233 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth, 234 fGpu->minRenderTargetWidth())); 235 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight, 236 fGpu->minRenderTargetHeight())); 237 238 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0); 239 240 if (NULL != texture) { 241 GrDrawTarget::AutoStateRestore asr(fGpu); 242 fGpu->setRenderTarget(texture->asRenderTarget()); 243 fGpu->setTexture(0, clampEntry->texture()); 244 fGpu->disableStencil(); 245 fGpu->setViewMatrix(GrMatrix::I()); 246 fGpu->setAlpha(0xff); 247 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff); 248 fGpu->disableState(GrDrawTarget::kDither_StateBit | 249 GrDrawTarget::kClip_StateBit | 250 GrDrawTarget::kAntialias_StateBit); 251 GrSamplerState::Filter filter; 252 // if filtering is not desired then we want to ensure all 253 // texels in the resampled image are copies of texels from 254 // the original. 255 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) { 256 filter = GrSamplerState::kNearest_Filter; 257 } else { 258 filter = GrSamplerState::kBilinear_Filter; 259 } 260 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode, 261 GrSamplerState::kClamp_WrapMode, 262 filter); 263 fGpu->setSamplerState(0, stretchSampler); 264 265 static const GrVertexLayout layout = 266 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0); 267 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0); 268 269 if (arg.succeeded()) { 270 GrPoint* verts = (GrPoint*) arg.vertices(); 271 verts[0].setIRectFan(0, 0, 272 texture->width(), 273 texture->height(), 274 2*sizeof(GrPoint)); 275 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint)); 276 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 277 0, 4); 278 entry = fTextureCache->createAndLock(*key, texture); 279 } 280 texture->releaseRenderTarget(); 281 } else { 282 // TODO: Our CPU stretch doesn't filter. But we create separate 283 // stretched textures when the sampler state is either filtered or 284 // not. Either implement filtered stretch blit on CPU or just create 285 // one when FBO case fails. 286 287 rtDesc.fFlags = kNone_GrTextureFlags; 288 // no longer need to clamp at min RT size. 289 rtDesc.fWidth = GrNextPow2(desc.fWidth); 290 rtDesc.fHeight = GrNextPow2(desc.fHeight); 291 int bpp = GrBytesPerPixel(desc.fFormat); 292 GrAutoSMalloc<128*128*4> stretchedPixels(bpp * 293 rtDesc.fWidth * 294 rtDesc.fHeight); 295 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight, 296 srcData, desc.fWidth, desc.fHeight, bpp); 297 298 size_t stretchedRowBytes = rtDesc.fWidth * bpp; 299 300 GrTexture* texture = fGpu->createTexture(rtDesc, 301 stretchedPixels.get(), 302 stretchedRowBytes); 303 GrAssert(NULL != texture); 304 entry = fTextureCache->createAndLock(*key, texture); 305 } 306 fTextureCache->unlock(clampEntry); 307 308 } else { 309 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes); 310 if (NULL != texture) { 311 entry = fTextureCache->createAndLock(*key, texture); 312 } else { 313 entry = NULL; 314 } 315 } 316 return entry; 317 } 318 319 GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) { 320 uint32_t p0 = desc.fFormat; 321 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags; 322 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight); 323 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true); 324 325 GrTextureEntry* entry = fTextureCache->findAndLock(key); 326 if (NULL == entry) { 327 GrTexture* texture = fGpu->createTexture(desc, NULL, 0); 328 if (NULL != texture) { 329 entry = fTextureCache->createAndLock(key, texture); 330 } 331 } 332 // If the caller gives us the same desc/sampler twice we don't want 333 // to return the same texture the second time (unless it was previously 334 // released). So we detach the entry from the cache and reattach at release. 335 if (NULL != entry) { 336 fTextureCache->detach(entry); 337 } 338 return entry; 339 } 340 341 void GrContext::unlockTexture(GrTextureEntry* entry) { 342 if (kKeylessBit & entry->key().getPrivateBits()) { 343 fTextureCache->reattachAndUnlock(entry); 344 } else { 345 fTextureCache->unlock(entry); 346 } 347 } 348 349 GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc, 350 void* srcData, 351 size_t rowBytes) { 352 return fGpu->createTexture(desc, srcData, rowBytes); 353 } 354 355 void GrContext::getTextureCacheLimits(int* maxTextures, 356 size_t* maxTextureBytes) const { 357 fTextureCache->getLimits(maxTextures, maxTextureBytes); 358 } 359 360 void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) { 361 fTextureCache->setLimits(maxTextures, maxTextureBytes); 362 } 363 364 int GrContext::getMaxTextureDimension() { 365 return fGpu->maxTextureDimension(); 366 } 367 368 /////////////////////////////////////////////////////////////////////////////// 369 370 GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) { 371 // validate flags here so that GrGpu subclasses don't have to check 372 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType && 373 0 != desc.fRenderTargetFlags) { 374 return NULL; 375 } 376 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) && 377 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) { 378 return NULL; 379 } 380 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType && 381 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) && 382 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) { 383 return NULL; 384 } 385 return fGpu->createPlatformSurface(desc); 386 } 387 388 GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() { 389 return fGpu->createRenderTargetFrom3DApiState(); 390 } 391 392 /////////////////////////////////////////////////////////////////////////////// 393 394 bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler, 395 int width, int height) { 396 if (!fGpu->supports8BitPalette()) { 397 return false; 398 } 399 400 401 bool isPow2 = GrIsPow2(width) && GrIsPow2(height); 402 403 if (!isPow2) { 404 if (!fGpu->npotTextureSupport()) { 405 return false; 406 } 407 408 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode || 409 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode; 410 if (tiled && !fGpu->npotTextureTileSupport()) { 411 return false; 412 } 413 } 414 return true; 415 } 416 417 //////////////////////////////////////////////////////////////////////////////// 418 419 const GrClip& GrContext::getClip() const { return fGpu->getClip(); } 420 421 void GrContext::setClip(const GrClip& clip) { 422 fGpu->setClip(clip); 423 fGpu->enableState(GrDrawTarget::kClip_StateBit); 424 } 425 426 void GrContext::setClip(const GrIRect& rect) { 427 GrClip clip; 428 clip.setFromIRect(rect); 429 fGpu->setClip(clip); 430 } 431 432 //////////////////////////////////////////////////////////////////////////////// 433 434 void GrContext::clear(const GrIRect* rect, const GrColor color) { 435 this->flush(); 436 fGpu->clear(rect, color); 437 } 438 439 void GrContext::drawPaint(const GrPaint& paint) { 440 // set rect to be big enough to fill the space, but not super-huge, so we 441 // don't overflow fixed-point implementations 442 GrRect r; 443 r.setLTRB(0, 0, 444 GrIntToScalar(getRenderTarget()->width()), 445 GrIntToScalar(getRenderTarget()->height())); 446 GrMatrix inverse; 447 if (fGpu->getViewInverse(&inverse)) { 448 inverse.mapRect(&r); 449 } else { 450 GrPrintf("---- fGpu->getViewInverse failed\n"); 451 } 452 this->drawRect(paint, r); 453 } 454 455 //////////////////////////////////////////////////////////////////////////////// 456 457 bool GrContext::doOffscreenAA(GrDrawTarget* target, 458 const GrPaint& paint, 459 bool isLines) const { 460 #if GR_MAX_OFFSCREEN_AA_DIM==0 461 return false; 462 #else 463 if (!paint.fAntiAlias) { 464 return false; 465 } 466 if (isLines && fGpu->supportsAALines()) { 467 return false; 468 } 469 if (target->getRenderTarget()->isMultisampled()) { 470 return false; 471 } 472 // we have to be sure that the blend equation is expressible 473 // as simple src / dst coeffecients when the source 474 // is already modulated by the coverage fraction. 475 // We could use dual-source blending to get the correct per-pixel 476 // dst coeffecient for the remaining cases. 477 if (kISC_BlendCoeff != paint.fDstBlendCoeff && 478 kOne_BlendCoeff != paint.fDstBlendCoeff && 479 kISA_BlendCoeff != paint.fDstBlendCoeff) { 480 return false; 481 } 482 return true; 483 #endif 484 } 485 486 bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target, 487 bool requireStencil, 488 const GrIRect& boundRect, 489 OffscreenRecord* record) { 490 GrAssert(GR_MAX_OFFSCREEN_AA_DIM > 0); 491 492 GrAssert(NULL == record->fEntry0); 493 GrAssert(NULL == record->fEntry1); 494 495 int boundW = boundRect.width(); 496 int boundH = boundRect.height(); 497 int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH))); 498 499 GrTextureDesc desc; 500 if (requireStencil) { 501 desc.fFlags = kRenderTarget_GrTextureFlagBit; 502 } else { 503 desc.fFlags = kRenderTarget_GrTextureFlagBit | 504 kNoStencil_GrTextureFlagBit; 505 } 506 507 desc.fFormat = kRGBA_8888_GrPixelConfig; 508 509 int scale; 510 // Using MSAA seems to be slower for some yet unknown reason. 511 if (false && fGpu->supportsFullsceneAA()) { 512 record->fDownsample = OffscreenRecord::kFSAA_Downsample; 513 scale = GR_Scalar1; 514 desc.fAALevel = kMed_GrAALevel; 515 } else { 516 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ? 517 OffscreenRecord::k4x4SinglePass_Downsample : 518 OffscreenRecord::k4x4TwoPass_Downsample; 519 scale = 4; 520 desc.fAALevel = kNone_GrAALevel; 521 } 522 523 desc.fWidth = scale * size; 524 desc.fHeight = scale * size; 525 526 record->fEntry0 = this->lockKeylessTexture(desc); 527 528 if (NULL == record->fEntry0) { 529 return false; 530 } 531 532 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) { 533 desc.fWidth /= 2; 534 desc.fHeight /= 2; 535 record->fEntry1 = this->lockKeylessTexture(desc); 536 if (NULL == record->fEntry1) { 537 this->unlockTexture(record->fEntry0); 538 record->fEntry0 = NULL; 539 return false; 540 } 541 } 542 543 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget(); 544 GrAssert(NULL != offRT0); 545 546 target->saveCurrentDrawState(&record->fSavedState); 547 548 GrPaint tempPaint; 549 tempPaint.reset(); 550 SetPaint(tempPaint, target); 551 target->setRenderTarget(offRT0); 552 553 GrMatrix transM; 554 transM.setTranslate(-boundRect.fLeft, -boundRect.fTop); 555 target->postConcatViewMatrix(transM); 556 GrMatrix scaleM; 557 scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1); 558 target->postConcatViewMatrix(scaleM); 559 560 // clip gets applied in second pass 561 target->disableState(GrDrawTarget::kClip_StateBit); 562 563 GrIRect clear = SkIRect::MakeWH(scale * boundW, scale * boundH); 564 target->clear(&clear, 0x0); 565 566 return true; 567 } 568 569 void GrContext::offscreenAAPass2(GrDrawTarget* target, 570 const GrPaint& paint, 571 const GrIRect& boundRect, 572 OffscreenRecord* record) { 573 574 GrAssert(NULL != record->fEntry0); 575 576 GrSamplerState::Filter filter; 577 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) { 578 filter = GrSamplerState::k4x4Downsample_Filter; 579 } else { 580 filter = GrSamplerState::kBilinear_Filter; 581 } 582 583 GrMatrix sampleM; 584 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode, 585 GrSamplerState::kClamp_WrapMode, filter); 586 587 GrTexture* src = record->fEntry0->texture(); 588 int scale; 589 590 enum { 591 kOffscreenStage = GrPaint::kTotalStages, 592 }; 593 594 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) { 595 GrAssert(NULL != record->fEntry1); 596 scale = 2; 597 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget(); 598 599 // Do 2x2 downsample from first to second 600 target->setTexture(kOffscreenStage, src); 601 target->setRenderTarget(dst); 602 target->setViewMatrix(GrMatrix::I()); 603 sampleM.setScale(scale * GR_Scalar1 / src->width(), 604 scale * GR_Scalar1 / src->height()); 605 sampler.setMatrix(sampleM); 606 target->setSamplerState(kOffscreenStage, sampler); 607 GrRect rect = SkRect::MakeWH(scale * boundRect.width(), 608 scale * boundRect.height()); 609 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage); 610 611 src = record->fEntry1->texture(); 612 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) { 613 scale = 1; 614 GrIRect rect = SkIRect::MakeWH(boundRect.width(), boundRect.height()); 615 src->asRenderTarget()->overrideResolveRect(rect); 616 } else { 617 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample == 618 record->fDownsample); 619 scale = 4; 620 } 621 622 // setup for draw back to main RT 623 int stageMask = paint.getActiveStageMask(); 624 625 target->restoreDrawState(record->fSavedState); 626 627 if (stageMask) { 628 GrMatrix invVM; 629 if (target->getViewInverse(&invVM)) { 630 target->preConcatSamplerMatrices(stageMask, invVM); 631 } 632 } 633 target->setViewMatrix(GrMatrix::I()); 634 635 target->setTexture(kOffscreenStage, src); 636 sampleM.setScale(scale * GR_Scalar1 / src->width(), 637 scale * GR_Scalar1 / src->height()); 638 sampler.setMatrix(sampleM); 639 sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop); 640 sampler.preConcatMatrix(sampleM); 641 target->setSamplerState(kOffscreenStage, sampler); 642 643 GrRect dstRect; 644 int stages = (1 << kOffscreenStage) | stageMask; 645 dstRect.set(boundRect); 646 target->drawSimpleRect(dstRect, NULL, stages); 647 648 this->unlockTexture(record->fEntry0); 649 record->fEntry0 = NULL; 650 if (NULL != record->fEntry1) { 651 this->unlockTexture(record->fEntry1); 652 record->fEntry1 = NULL; 653 } 654 target->restoreDrawState(record->fSavedState); 655 } 656 657 //////////////////////////////////////////////////////////////////////////////// 658 659 /* create a triangle strip that strokes the specified triangle. There are 8 660 unique vertices, but we repreat the last 2 to close up. Alternatively we 661 could use an indices array, and then only send 8 verts, but not sure that 662 would be faster. 663 */ 664 static void setStrokeRectStrip(GrPoint verts[10], GrRect rect, 665 GrScalar width) { 666 const GrScalar rad = GrScalarHalf(width); 667 rect.sort(); 668 669 verts[0].set(rect.fLeft + rad, rect.fTop + rad); 670 verts[1].set(rect.fLeft - rad, rect.fTop - rad); 671 verts[2].set(rect.fRight - rad, rect.fTop + rad); 672 verts[3].set(rect.fRight + rad, rect.fTop - rad); 673 verts[4].set(rect.fRight - rad, rect.fBottom - rad); 674 verts[5].set(rect.fRight + rad, rect.fBottom + rad); 675 verts[6].set(rect.fLeft + rad, rect.fBottom - rad); 676 verts[7].set(rect.fLeft - rad, rect.fBottom + rad); 677 verts[8] = verts[0]; 678 verts[9] = verts[1]; 679 } 680 681 static GrColor getColorForMesh(const GrPaint& paint) { 682 // FIXME: This was copied from SkGpuDevice, seems like 683 // we should have already smeared a in caller if that 684 // is what is desired. 685 if (paint.hasTexture()) { 686 unsigned a = GrColorUnpackA(paint.fColor); 687 return GrColorPackRGBA(a, a, a, a); 688 } else { 689 return paint.fColor; 690 } 691 } 692 693 static void setInsetFan(GrPoint* pts, size_t stride, 694 const GrRect& r, GrScalar dx, GrScalar dy) { 695 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride); 696 } 697 698 static const uint16_t gFillAARectIdx[] = { 699 0, 1, 5, 5, 4, 0, 700 1, 2, 6, 6, 5, 1, 701 2, 3, 7, 7, 6, 2, 702 3, 0, 4, 4, 7, 3, 703 4, 5, 6, 6, 7, 4, 704 }; 705 706 int GrContext::aaFillRectIndexCount() const { 707 return GR_ARRAY_COUNT(gFillAARectIdx); 708 } 709 710 GrIndexBuffer* GrContext::aaFillRectIndexBuffer() { 711 if (NULL == fAAFillRectIndexBuffer) { 712 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx), 713 false); 714 GrAssert(NULL != fAAFillRectIndexBuffer); 715 #if GR_DEBUG 716 bool updated = 717 #endif 718 fAAFillRectIndexBuffer->updateData(gFillAARectIdx, 719 sizeof(gFillAARectIdx)); 720 GR_DEBUGASSERT(updated); 721 } 722 return fAAFillRectIndexBuffer; 723 } 724 725 static const uint16_t gStrokeAARectIdx[] = { 726 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0, 727 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0, 728 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0, 729 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0, 730 731 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4, 732 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4, 733 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4, 734 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4, 735 736 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8, 737 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8, 738 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8, 739 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8, 740 }; 741 742 int GrContext::aaStrokeRectIndexCount() const { 743 return GR_ARRAY_COUNT(gStrokeAARectIdx); 744 } 745 746 GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() { 747 if (NULL == fAAStrokeRectIndexBuffer) { 748 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx), 749 false); 750 GrAssert(NULL != fAAStrokeRectIndexBuffer); 751 #if GR_DEBUG 752 bool updated = 753 #endif 754 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx, 755 sizeof(gStrokeAARectIdx)); 756 GR_DEBUGASSERT(updated); 757 } 758 return fAAStrokeRectIndexBuffer; 759 } 760 761 void GrContext::fillAARect(GrDrawTarget* target, 762 const GrPaint& paint, 763 const GrRect& devRect) { 764 765 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) | 766 GrDrawTarget::kColor_VertexLayoutBit; 767 768 size_t vsize = GrDrawTarget::VertexSize(layout); 769 770 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0); 771 772 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); 773 774 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts); 775 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); 776 777 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf); 778 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf); 779 780 verts += sizeof(GrPoint); 781 for (int i = 0; i < 4; ++i) { 782 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; 783 } 784 785 GrColor innerColor = getColorForMesh(paint); 786 verts += 4 * vsize; 787 for (int i = 0; i < 4; ++i) { 788 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; 789 } 790 791 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer()); 792 793 target->drawIndexed(kTriangles_PrimitiveType, 0, 794 0, 8, this->aaFillRectIndexCount()); 795 } 796 797 void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint, 798 const GrRect& devRect, const GrVec& devStrokeSize) { 799 const GrScalar& dx = devStrokeSize.fX; 800 const GrScalar& dy = devStrokeSize.fY; 801 const GrScalar rx = GrMul(dx, GR_ScalarHalf); 802 const GrScalar ry = GrMul(dy, GR_ScalarHalf); 803 804 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) | 805 GrDrawTarget::kColor_VertexLayoutBit; 806 807 GrScalar spare; 808 { 809 GrScalar w = devRect.width() - dx; 810 GrScalar h = devRect.height() - dy; 811 spare = GrMin(w, h); 812 } 813 814 if (spare <= 0) { 815 GrRect r(devRect); 816 r.inset(-rx, -ry); 817 fillAARect(target, paint, r); 818 return; 819 } 820 821 size_t vsize = GrDrawTarget::VertexSize(layout); 822 823 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0); 824 825 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); 826 827 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts); 828 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); 829 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize); 830 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize); 831 832 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf); 833 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf); 834 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf); 835 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf); 836 837 verts += sizeof(GrPoint); 838 for (int i = 0; i < 4; ++i) { 839 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; 840 } 841 842 GrColor innerColor = getColorForMesh(paint); 843 verts += 4 * vsize; 844 for (int i = 0; i < 8; ++i) { 845 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; 846 } 847 848 verts += 8 * vsize; 849 for (int i = 0; i < 8; ++i) { 850 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; 851 } 852 853 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer()); 854 target->drawIndexed(kTriangles_PrimitiveType, 855 0, 0, 16, aaStrokeRectIndexCount()); 856 } 857 858 /** 859 * Returns true if the rects edges are integer-aligned. 860 */ 861 static bool isIRect(const GrRect& r) { 862 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) && 863 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom); 864 } 865 866 static bool apply_aa_to_rect(GrDrawTarget* target, 867 GrGpu* gpu, 868 const GrPaint& paint, 869 const GrRect& rect, 870 GrScalar width, 871 const GrMatrix* matrix, 872 GrMatrix* combinedMatrix, 873 GrRect* devRect) { 874 // we use a simple alpha ramp to do aa on axis-aligned rects 875 // do AA with alpha ramp if the caller requested AA, the rect 876 // will be axis-aligned,the render target is not 877 // multisampled, and the rect won't land on integer coords. 878 879 if (!paint.fAntiAlias) { 880 return false; 881 } 882 883 if (target->getRenderTarget()->isMultisampled()) { 884 return false; 885 } 886 887 if (0 == width && gpu->supportsAALines()) { 888 return false; 889 } 890 891 if (!target->getViewMatrix().preservesAxisAlignment()) { 892 return false; 893 } 894 895 if (NULL != matrix && 896 !matrix->preservesAxisAlignment()) { 897 return false; 898 } 899 900 *combinedMatrix = target->getViewMatrix(); 901 if (NULL != matrix) { 902 combinedMatrix->preConcat(*matrix); 903 GrAssert(combinedMatrix->preservesAxisAlignment()); 904 } 905 906 combinedMatrix->mapRect(devRect, rect); 907 devRect->sort(); 908 909 if (width < 0) { 910 return !isIRect(*devRect); 911 } else { 912 return true; 913 } 914 } 915 916 void GrContext::drawRect(const GrPaint& paint, 917 const GrRect& rect, 918 GrScalar width, 919 const GrMatrix* matrix) { 920 921 922 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 923 int stageMask = paint.getActiveStageMask(); 924 925 GrRect devRect = rect; 926 GrMatrix combinedMatrix; 927 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix, 928 &combinedMatrix, &devRect); 929 930 if (doAA) { 931 GrDrawTarget::AutoViewMatrixRestore avm(target); 932 if (stageMask) { 933 GrMatrix inv; 934 if (combinedMatrix.invert(&inv)) { 935 target->preConcatSamplerMatrices(stageMask, inv); 936 } 937 } 938 target->setViewMatrix(GrMatrix::I()); 939 if (width >= 0) { 940 GrVec strokeSize;; 941 if (width > 0) { 942 strokeSize.set(width, width); 943 combinedMatrix.mapVectors(&strokeSize, 1); 944 strokeSize.setAbs(strokeSize); 945 } else { 946 strokeSize.set(GR_Scalar1, GR_Scalar1); 947 } 948 strokeAARect(target, paint, devRect, strokeSize); 949 } else { 950 fillAARect(target, paint, devRect); 951 } 952 return; 953 } 954 955 if (width >= 0) { 956 // TODO: consider making static vertex buffers for these cases. 957 // Hairline could be done by just adding closing vertex to 958 // unitSquareVertexBuffer() 959 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL); 960 961 static const int worstCaseVertCount = 10; 962 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0); 963 964 if (!geo.succeeded()) { 965 return; 966 } 967 968 GrPrimitiveType primType; 969 int vertCount; 970 GrPoint* vertex = geo.positions(); 971 972 if (width > 0) { 973 vertCount = 10; 974 primType = kTriangleStrip_PrimitiveType; 975 setStrokeRectStrip(vertex, rect, width); 976 } else { 977 // hairline 978 vertCount = 5; 979 primType = kLineStrip_PrimitiveType; 980 vertex[0].set(rect.fLeft, rect.fTop); 981 vertex[1].set(rect.fRight, rect.fTop); 982 vertex[2].set(rect.fRight, rect.fBottom); 983 vertex[3].set(rect.fLeft, rect.fBottom); 984 vertex[4].set(rect.fLeft, rect.fTop); 985 } 986 987 GrDrawTarget::AutoViewMatrixRestore avmr; 988 if (NULL != matrix) { 989 avmr.set(target); 990 target->preConcatViewMatrix(*matrix); 991 target->preConcatSamplerMatrices(stageMask, *matrix); 992 } 993 994 target->drawNonIndexed(primType, 0, vertCount); 995 } else { 996 #if GR_STATIC_RECT_VB 997 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL); 998 999 target->setVertexSourceToBuffer(layout, 1000 fGpu->getUnitSquareVertexBuffer()); 1001 GrDrawTarget::AutoViewMatrixRestore avmr(target); 1002 GrMatrix m; 1003 m.setAll(rect.width(), 0, rect.fLeft, 1004 0, rect.height(), rect.fTop, 1005 0, 0, GrMatrix::I()[8]); 1006 1007 if (NULL != matrix) { 1008 m.postConcat(*matrix); 1009 } 1010 1011 target->preConcatViewMatrix(m); 1012 target->preConcatSamplerMatrices(stageMask, m); 1013 1014 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4); 1015 #else 1016 target->drawSimpleRect(rect, matrix, stageMask); 1017 #endif 1018 } 1019 } 1020 1021 void GrContext::drawRectToRect(const GrPaint& paint, 1022 const GrRect& dstRect, 1023 const GrRect& srcRect, 1024 const GrMatrix* dstMatrix, 1025 const GrMatrix* srcMatrix) { 1026 1027 // srcRect refers to paint's first texture 1028 if (NULL == paint.getTexture(0)) { 1029 drawRect(paint, dstRect, -1, dstMatrix); 1030 return; 1031 } 1032 1033 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB); 1034 1035 #if GR_STATIC_RECT_VB 1036 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1037 1038 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL); 1039 GrDrawTarget::AutoViewMatrixRestore avmr(target); 1040 1041 GrMatrix m; 1042 1043 m.setAll(dstRect.width(), 0, dstRect.fLeft, 1044 0, dstRect.height(), dstRect.fTop, 1045 0, 0, GrMatrix::I()[8]); 1046 if (NULL != dstMatrix) { 1047 m.postConcat(*dstMatrix); 1048 } 1049 target->preConcatViewMatrix(m); 1050 1051 // srcRect refers to first stage 1052 int otherStageMask = paint.getActiveStageMask() & 1053 (~(1 << GrPaint::kFirstTextureStage)); 1054 if (otherStageMask) { 1055 target->preConcatSamplerMatrices(otherStageMask, m); 1056 } 1057 1058 m.setAll(srcRect.width(), 0, srcRect.fLeft, 1059 0, srcRect.height(), srcRect.fTop, 1060 0, 0, GrMatrix::I()[8]); 1061 if (NULL != srcMatrix) { 1062 m.postConcat(*srcMatrix); 1063 } 1064 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m); 1065 1066 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer()); 1067 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4); 1068 #else 1069 1070 GrDrawTarget* target; 1071 #if BATCH_RECT_TO_RECT 1072 target = this->prepareToDraw(paint, kBuffered_DrawCategory); 1073 #else 1074 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1075 #endif 1076 1077 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL}; 1078 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL}; 1079 srcRects[0] = &srcRect; 1080 srcMatrices[0] = srcMatrix; 1081 1082 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices); 1083 #endif 1084 } 1085 1086 void GrContext::drawVertices(const GrPaint& paint, 1087 GrPrimitiveType primitiveType, 1088 int vertexCount, 1089 const GrPoint positions[], 1090 const GrPoint texCoords[], 1091 const GrColor colors[], 1092 const uint16_t indices[], 1093 int indexCount) { 1094 1095 GrDrawTarget::AutoReleaseGeometry geo; 1096 1097 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1098 1099 bool hasTexCoords[GrPaint::kTotalStages] = { 1100 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords 1101 0 // remaining stages use positions 1102 }; 1103 1104 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords); 1105 1106 if (NULL != colors) { 1107 layout |= GrDrawTarget::kColor_VertexLayoutBit; 1108 } 1109 int vertexSize = GrDrawTarget::VertexSize(layout); 1110 1111 bool doAA = false; 1112 OffscreenRecord record; 1113 GrIRect bounds; 1114 1115 if (sizeof(GrPoint) != vertexSize) { 1116 if (!geo.set(target, layout, vertexCount, 0)) { 1117 GrPrintf("Failed to get space for vertices!"); 1118 return; 1119 } 1120 int texOffsets[GrDrawTarget::kMaxTexCoords]; 1121 int colorOffset; 1122 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout, 1123 texOffsets, 1124 &colorOffset); 1125 void* curVertex = geo.vertices(); 1126 1127 for (int i = 0; i < vertexCount; ++i) { 1128 *((GrPoint*)curVertex) = positions[i]; 1129 1130 if (texOffsets[0] > 0) { 1131 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i]; 1132 } 1133 if (colorOffset > 0) { 1134 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i]; 1135 } 1136 curVertex = (void*)((intptr_t)curVertex + vertexSize); 1137 } 1138 } else { 1139 // we don't do offscreen AA when we have per-vertex tex coords or colors 1140 if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) { 1141 GrRect b; 1142 b.setBounds(positions, vertexCount); 1143 target->getViewMatrix().mapRect(&b); 1144 b.roundOut(&bounds); 1145 1146 if (this->setupOffscreenAAPass1(target, false, bounds, &record)) { 1147 doAA = true; 1148 } 1149 } 1150 target->setVertexSourceToArray(layout, positions, vertexCount); 1151 } 1152 1153 if (NULL != indices) { 1154 target->setIndexSourceToArray(indices, indexCount); 1155 } 1156 1157 if (NULL != indices) { 1158 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); 1159 } else { 1160 target->drawNonIndexed(primitiveType, 0, vertexCount); 1161 } 1162 1163 if (doAA) { 1164 this->offscreenAAPass2(target, paint, bounds, &record); 1165 } 1166 } 1167 1168 1169 /////////////////////////////////////////////////////////////////////////////// 1170 1171 void GrContext::drawPath(const GrPaint& paint, const GrPath& path, 1172 GrPathFill fill, const GrPoint* translate) { 1173 1174 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1175 GrPathRenderer* pr = this->getPathRenderer(target, path, fill); 1176 1177 if (!IsFillInverted(fill) && // will be relaxed soon 1178 !pr->supportsAA(target, path, fill) && 1179 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) { 1180 1181 OffscreenRecord record; 1182 bool needsStencil = pr->requiresStencilPass(target, path, fill); 1183 1184 // compute bounds as intersection of rt size, clip, and path 1185 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(), 1186 target->getRenderTarget()->height()); 1187 if (target->getClip().hasConservativeBounds()) { 1188 GrIRect clipIBounds; 1189 target->getClip().getConservativeBounds().roundOut(&clipIBounds); 1190 if (!bound.intersect(clipIBounds)) { 1191 return; 1192 } 1193 } 1194 1195 GrRect pathBounds = path.getBounds(); 1196 GrIRect pathIBounds; 1197 if (!pathBounds.isEmpty()) { 1198 if (NULL != translate) { 1199 pathBounds.offset(*translate); 1200 } 1201 target->getViewMatrix().mapRect(&pathBounds, pathBounds); 1202 pathBounds.roundOut(&pathIBounds); 1203 if (!bound.intersect(pathIBounds)) { 1204 return; 1205 } 1206 } 1207 1208 // for now, abort antialiasing if our bounds are too big, so we don't 1209 // hit the FBO size limit 1210 if (pathIBounds.width() > GR_MAX_OFFSCREEN_AA_DIM || 1211 pathIBounds.height() > GR_MAX_OFFSCREEN_AA_DIM) { 1212 goto NO_AA; 1213 } 1214 1215 if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) { 1216 pr->drawPath(target, 0, path, fill, translate); 1217 this->offscreenAAPass2(target, paint, bound, &record); 1218 return; 1219 } 1220 } 1221 1222 // we can fall out of the AA section for some reasons, and land here 1223 NO_AA: 1224 GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask(); 1225 1226 pr->drawPath(target, enabledStages, path, fill, translate); 1227 } 1228 1229 //////////////////////////////////////////////////////////////////////////////// 1230 1231 void GrContext::flush(int flagsBitfield) { 1232 if (kDiscard_FlushBit & flagsBitfield) { 1233 fDrawBuffer->reset(); 1234 } else { 1235 flushDrawBuffer(); 1236 } 1237 1238 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) { 1239 fGpu->forceRenderTargetFlush(); 1240 } 1241 } 1242 1243 void GrContext::flushText() { 1244 if (kText_DrawCategory == fLastDrawCategory) { 1245 flushDrawBuffer(); 1246 } 1247 } 1248 1249 void GrContext::flushDrawBuffer() { 1250 #if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING 1251 if (fDrawBuffer) { 1252 fDrawBuffer->playback(fGpu); 1253 fDrawBuffer->reset(); 1254 } 1255 #endif 1256 } 1257 1258 bool GrContext::readTexturePixels(GrTexture* texture, 1259 int left, int top, int width, int height, 1260 GrPixelConfig config, void* buffer) { 1261 1262 // TODO: code read pixels for textures that aren't rendertargets 1263 1264 this->flush(); 1265 GrRenderTarget* target = texture->asRenderTarget(); 1266 if (NULL != target) { 1267 return fGpu->readPixels(target, 1268 left, top, width, height, 1269 config, buffer); 1270 } else { 1271 return false; 1272 } 1273 } 1274 1275 bool GrContext::readRenderTargetPixels(GrRenderTarget* target, 1276 int left, int top, int width, int height, 1277 GrPixelConfig config, void* buffer) { 1278 uint32_t flushFlags = 0; 1279 if (NULL == target) { 1280 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit; 1281 } 1282 1283 this->flush(flushFlags); 1284 return fGpu->readPixels(target, 1285 left, top, width, height, 1286 config, buffer); 1287 } 1288 1289 void GrContext::writePixels(int left, int top, int width, int height, 1290 GrPixelConfig config, const void* buffer, 1291 size_t stride) { 1292 1293 // TODO: when underlying api has a direct way to do this we should use it 1294 // (e.g. glDrawPixels on desktop GL). 1295 1296 const GrTextureDesc desc = { 1297 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config 1298 }; 1299 GrTexture* texture = fGpu->createTexture(desc, buffer, stride); 1300 if (NULL == texture) { 1301 return; 1302 } 1303 1304 this->flush(true); 1305 1306 GrAutoUnref aur(texture); 1307 GrDrawTarget::AutoStateRestore asr(fGpu); 1308 1309 GrMatrix matrix; 1310 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top)); 1311 fGpu->setViewMatrix(matrix); 1312 1313 fGpu->setColorFilter(0, SkXfermode::kDst_Mode); 1314 fGpu->disableState(GrDrawTarget::kClip_StateBit); 1315 fGpu->setAlpha(0xFF); 1316 fGpu->setBlendFunc(kOne_BlendCoeff, 1317 kZero_BlendCoeff); 1318 fGpu->setTexture(0, texture); 1319 1320 GrSamplerState sampler; 1321 sampler.setClampNoFilter(); 1322 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height); 1323 sampler.setMatrix(matrix); 1324 fGpu->setSamplerState(0, sampler); 1325 1326 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0); 1327 static const int VCOUNT = 4; 1328 1329 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0); 1330 if (!geo.succeeded()) { 1331 return; 1332 } 1333 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height); 1334 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT); 1335 } 1336 //////////////////////////////////////////////////////////////////////////////// 1337 1338 void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) { 1339 1340 for (int i = 0; i < GrPaint::kMaxTextures; ++i) { 1341 int s = i + GrPaint::kFirstTextureStage; 1342 target->setTexture(s, paint.getTexture(i)); 1343 target->setSamplerState(s, *paint.getTextureSampler(i)); 1344 } 1345 1346 target->setFirstCoverageStage(GrPaint::kFirstMaskStage); 1347 1348 for (int i = 0; i < GrPaint::kMaxMasks; ++i) { 1349 int s = i + GrPaint::kFirstMaskStage; 1350 target->setTexture(s, paint.getMask(i)); 1351 target->setSamplerState(s, *paint.getMaskSampler(i)); 1352 } 1353 1354 target->setColor(paint.fColor); 1355 1356 if (paint.fDither) { 1357 target->enableState(GrDrawTarget::kDither_StateBit); 1358 } else { 1359 target->disableState(GrDrawTarget::kDither_StateBit); 1360 } 1361 if (paint.fAntiAlias) { 1362 target->enableState(GrDrawTarget::kAntialias_StateBit); 1363 } else { 1364 target->disableState(GrDrawTarget::kAntialias_StateBit); 1365 } 1366 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff); 1367 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode); 1368 } 1369 1370 GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint, 1371 DrawCategory category) { 1372 if (category != fLastDrawCategory) { 1373 flushDrawBuffer(); 1374 fLastDrawCategory = category; 1375 } 1376 SetPaint(paint, fGpu); 1377 GrDrawTarget* target = fGpu; 1378 switch (category) { 1379 case kText_DrawCategory: 1380 #if DEFER_TEXT_RENDERING 1381 target = fDrawBuffer; 1382 fDrawBuffer->initializeDrawStateAndClip(*fGpu); 1383 #else 1384 target = fGpu; 1385 #endif 1386 break; 1387 case kUnbuffered_DrawCategory: 1388 target = fGpu; 1389 break; 1390 case kBuffered_DrawCategory: 1391 target = fDrawBuffer; 1392 fDrawBuffer->initializeDrawStateAndClip(*fGpu); 1393 break; 1394 } 1395 return target; 1396 } 1397 1398 //////////////////////////////////////////////////////////////////////////////// 1399 1400 void GrContext::setRenderTarget(GrRenderTarget* target) { 1401 this->flush(false); 1402 fGpu->setRenderTarget(target); 1403 } 1404 1405 GrRenderTarget* GrContext::getRenderTarget() { 1406 return fGpu->getRenderTarget(); 1407 } 1408 1409 const GrRenderTarget* GrContext::getRenderTarget() const { 1410 return fGpu->getRenderTarget(); 1411 } 1412 1413 const GrMatrix& GrContext::getMatrix() const { 1414 return fGpu->getViewMatrix(); 1415 } 1416 1417 void GrContext::setMatrix(const GrMatrix& m) { 1418 fGpu->setViewMatrix(m); 1419 } 1420 1421 void GrContext::concatMatrix(const GrMatrix& m) const { 1422 fGpu->preConcatViewMatrix(m); 1423 } 1424 1425 static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) { 1426 intptr_t mask = 1 << shift; 1427 if (pred) { 1428 bits |= mask; 1429 } else { 1430 bits &= ~mask; 1431 } 1432 return bits; 1433 } 1434 1435 void GrContext::resetStats() { 1436 fGpu->resetStats(); 1437 } 1438 1439 const GrGpuStats& GrContext::getStats() const { 1440 return fGpu->getStats(); 1441 } 1442 1443 void GrContext::printStats() const { 1444 fGpu->printStats(); 1445 } 1446 1447 GrContext::GrContext(GrGpu* gpu) : 1448 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(), 1449 gpu->supportsStencilWrapOps()) { 1450 1451 fGpu = gpu; 1452 fGpu->ref(); 1453 fGpu->setContext(this); 1454 1455 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer(); 1456 fGpu->setClipPathRenderer(fCustomPathRenderer); 1457 1458 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT, 1459 MAX_TEXTURE_CACHE_BYTES); 1460 fFontCache = new GrFontCache(fGpu); 1461 1462 fLastDrawCategory = kUnbuffered_DrawCategory; 1463 1464 fDrawBuffer = NULL; 1465 fDrawBufferVBAllocPool = NULL; 1466 fDrawBufferIBAllocPool = NULL; 1467 1468 fAAFillRectIndexBuffer = NULL; 1469 fAAStrokeRectIndexBuffer = NULL; 1470 1471 this->setupDrawBuffer(); 1472 } 1473 1474 void GrContext::setupDrawBuffer() { 1475 1476 GrAssert(NULL == fDrawBuffer); 1477 GrAssert(NULL == fDrawBufferVBAllocPool); 1478 GrAssert(NULL == fDrawBufferIBAllocPool); 1479 1480 #if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT 1481 fDrawBufferVBAllocPool = 1482 new GrVertexBufferAllocPool(fGpu, false, 1483 DRAW_BUFFER_VBPOOL_BUFFER_SIZE, 1484 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS); 1485 fDrawBufferIBAllocPool = 1486 new GrIndexBufferAllocPool(fGpu, false, 1487 DRAW_BUFFER_IBPOOL_BUFFER_SIZE, 1488 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS); 1489 1490 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool, 1491 fDrawBufferIBAllocPool); 1492 #endif 1493 1494 #if BATCH_RECT_TO_RECT 1495 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer()); 1496 #endif 1497 } 1498 1499 GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) { 1500 GrDrawTarget* target; 1501 #if DEFER_TEXT_RENDERING 1502 target = prepareToDraw(paint, kText_DrawCategory); 1503 #else 1504 target = prepareToDraw(paint, kUnbuffered_DrawCategory); 1505 #endif 1506 SetPaint(paint, target); 1507 return target; 1508 } 1509 1510 const GrIndexBuffer* GrContext::getQuadIndexBuffer() const { 1511 return fGpu->getQuadIndexBuffer(); 1512 } 1513 1514 GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target, 1515 const GrPath& path, 1516 GrPathFill fill) { 1517 if (NULL != fCustomPathRenderer && 1518 fCustomPathRenderer->canDrawPath(target, path, fill)) { 1519 return fCustomPathRenderer; 1520 } else { 1521 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill)); 1522 return &fDefaultPathRenderer; 1523 } 1524 } 1525 1526