1 /* 2 * Copyright 2010 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 9 #include "GrGpu.h" 10 11 #include "GrBuffer.h" 12 #include "GrCaps.h" 13 #include "GrContext.h" 14 #include "GrGpuResourcePriv.h" 15 #include "GrMesh.h" 16 #include "GrPathRendering.h" 17 #include "GrPipeline.h" 18 #include "GrResourceCache.h" 19 #include "GrResourceProvider.h" 20 #include "GrRenderTargetPriv.h" 21 #include "GrStencilAttachment.h" 22 #include "GrStencilSettings.h" 23 #include "GrSurfacePriv.h" 24 #include "GrTexturePriv.h" 25 #include "SkMathPriv.h" 26 27 GrMesh& GrMesh::operator =(const GrMesh& di) { 28 fPrimitiveType = di.fPrimitiveType; 29 fStartVertex = di.fStartVertex; 30 fStartIndex = di.fStartIndex; 31 fVertexCount = di.fVertexCount; 32 fIndexCount = di.fIndexCount; 33 34 fInstanceCount = di.fInstanceCount; 35 fVerticesPerInstance = di.fVerticesPerInstance; 36 fIndicesPerInstance = di.fIndicesPerInstance; 37 fMaxInstancesPerDraw = di.fMaxInstancesPerDraw; 38 39 fVertexBuffer.reset(di.vertexBuffer()); 40 fIndexBuffer.reset(di.indexBuffer()); 41 42 return *this; 43 } 44 45 //////////////////////////////////////////////////////////////////////////////// 46 47 GrGpu::GrGpu(GrContext* context) 48 : fResetTimestamp(kExpiredTimestamp+1) 49 , fResetBits(kAll_GrBackendState) 50 , fContext(context) { 51 fMultisampleSpecs.emplace_back(0, 0, nullptr); // Index 0 is an invalid unique id. 52 } 53 54 GrGpu::~GrGpu() {} 55 56 void GrGpu::disconnect(DisconnectType) {} 57 58 //////////////////////////////////////////////////////////////////////////////// 59 60 bool GrGpu::isACopyNeededForTextureParams(int width, int height, 61 const GrSamplerParams& textureParams, 62 GrTextureProducer::CopyParams* copyParams, 63 SkScalar scaleAdjust[2]) const { 64 const GrCaps& caps = *this->caps(); 65 if (textureParams.isTiled() && !caps.npotTextureTileSupport() && 66 (!SkIsPow2(width) || !SkIsPow2(height))) { 67 SkASSERT(scaleAdjust); 68 copyParams->fWidth = GrNextPow2(width); 69 copyParams->fHeight = GrNextPow2(height); 70 scaleAdjust[0] = ((SkScalar) copyParams->fWidth) / width; 71 scaleAdjust[1] = ((SkScalar) copyParams->fHeight) / height; 72 switch (textureParams.filterMode()) { 73 case GrSamplerParams::kNone_FilterMode: 74 copyParams->fFilter = GrSamplerParams::kNone_FilterMode; 75 break; 76 case GrSamplerParams::kBilerp_FilterMode: 77 case GrSamplerParams::kMipMap_FilterMode: 78 // We are only ever scaling up so no reason to ever indicate kMipMap. 79 copyParams->fFilter = GrSamplerParams::kBilerp_FilterMode; 80 break; 81 } 82 return true; 83 } 84 return false; 85 } 86 87 static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin, bool renderTarget) { 88 // By default, GrRenderTargets are GL's normal orientation so that they 89 // can be drawn to by the outside world without the client having 90 // to render upside down. 91 if (kDefault_GrSurfaceOrigin == origin) { 92 return renderTarget ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin; 93 } else { 94 return origin; 95 } 96 } 97 98 /** 99 * Prior to creating a texture, make sure the type of texture being created is 100 * supported by calling check_texture_creation_params. 101 * 102 * @param caps The capabilities of the GL device. 103 * @param desc The descriptor of the texture to create. 104 * @param isRT Indicates if the texture can be a render target. 105 */ 106 static bool check_texture_creation_params(const GrCaps& caps, const GrSurfaceDesc& desc, 107 bool* isRT, const SkTArray<GrMipLevel>& texels) { 108 if (!caps.isConfigTexturable(desc.fConfig)) { 109 return false; 110 } 111 112 if (GrPixelConfigIsSint(desc.fConfig) && texels.count() > 1) { 113 return false; 114 } 115 116 *isRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); 117 if (*isRT && !caps.isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { 118 return false; 119 } 120 121 // We currently do not support multisampled textures 122 if (!*isRT && desc.fSampleCnt > 0) { 123 return false; 124 } 125 126 if (*isRT) { 127 int maxRTSize = caps.maxRenderTargetSize(); 128 if (desc.fWidth > maxRTSize || desc.fHeight > maxRTSize) { 129 return false; 130 } 131 } else { 132 int maxSize = caps.maxTextureSize(); 133 if (desc.fWidth > maxSize || desc.fHeight > maxSize) { 134 return false; 135 } 136 } 137 138 for (int i = 0; i < texels.count(); ++i) { 139 if (!texels[i].fPixels) { 140 return false; 141 } 142 } 143 return true; 144 } 145 146 GrTexture* GrGpu::createTexture(const GrSurfaceDesc& origDesc, SkBudgeted budgeted, 147 const SkTArray<GrMipLevel>& texels) { 148 GrSurfaceDesc desc = origDesc; 149 150 const GrCaps* caps = this->caps(); 151 bool isRT = false; 152 bool textureCreationParamsValid = check_texture_creation_params(*caps, desc, &isRT, texels); 153 if (!textureCreationParamsValid) { 154 return nullptr; 155 } 156 157 desc.fSampleCnt = SkTMin(desc.fSampleCnt, caps->maxSampleCount()); 158 // Attempt to catch un- or wrongly intialized sample counts; 159 SkASSERT(desc.fSampleCnt >= 0 && desc.fSampleCnt <= 64); 160 161 desc.fOrigin = resolve_origin(desc.fOrigin, isRT); 162 163 GrTexture* tex = nullptr; 164 165 if (GrPixelConfigIsCompressed(desc.fConfig)) { 166 // We shouldn't be rendering into this 167 SkASSERT(!isRT); 168 SkASSERT(0 == desc.fSampleCnt); 169 170 if (!caps->npotTextureTileSupport() && 171 (!SkIsPow2(desc.fWidth) || !SkIsPow2(desc.fHeight))) { 172 return nullptr; 173 } 174 175 this->handleDirtyContext(); 176 tex = this->onCreateCompressedTexture(desc, budgeted, texels); 177 } else { 178 this->handleDirtyContext(); 179 tex = this->onCreateTexture(desc, budgeted, texels); 180 } 181 if (tex) { 182 if (!caps->reuseScratchTextures() && !isRT) { 183 tex->resourcePriv().removeScratchKey(); 184 } 185 fStats.incTextureCreates(); 186 if (!texels.empty()) { 187 if (texels[0].fPixels) { 188 fStats.incTextureUploads(); 189 } 190 } 191 // This is a current work around to get discards into newly created textures. Once we are in 192 // MDB world, we should remove this code a rely on the draw target having specified load 193 // operations. 194 if (isRT && texels.empty()) { 195 GrRenderTarget* rt = tex->asRenderTarget(); 196 SkASSERT(rt); 197 rt->discard(); 198 } 199 } 200 return tex; 201 } 202 203 sk_sp<GrTexture> GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc, 204 GrWrapOwnership ownership) { 205 this->handleDirtyContext(); 206 if (!this->caps()->isConfigTexturable(desc.fConfig)) { 207 return nullptr; 208 } 209 if ((desc.fFlags & kRenderTarget_GrBackendTextureFlag) && 210 !this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { 211 return nullptr; 212 } 213 int maxSize = this->caps()->maxTextureSize(); 214 if (desc.fWidth > maxSize || desc.fHeight > maxSize) { 215 return nullptr; 216 } 217 sk_sp<GrTexture> tex = this->onWrapBackendTexture(desc, ownership); 218 if (!tex) { 219 return nullptr; 220 } 221 // TODO: defer this and attach dynamically 222 GrRenderTarget* tgt = tex->asRenderTarget(); 223 if (tgt && !fContext->resourceProvider()->attachStencilAttachment(tgt)) { 224 return nullptr; 225 } 226 return tex; 227 } 228 229 sk_sp<GrRenderTarget> GrGpu::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) { 230 if (!this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { 231 return nullptr; 232 } 233 this->handleDirtyContext(); 234 return this->onWrapBackendRenderTarget(desc); 235 } 236 237 sk_sp<GrRenderTarget> GrGpu::wrapBackendTextureAsRenderTarget(const GrBackendTextureDesc& desc) { 238 this->handleDirtyContext(); 239 if (!(desc.fFlags & kRenderTarget_GrBackendTextureFlag)) { 240 return nullptr; 241 } 242 if (!this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { 243 return nullptr; 244 } 245 int maxSize = this->caps()->maxTextureSize(); 246 if (desc.fWidth > maxSize || desc.fHeight > maxSize) { 247 return nullptr; 248 } 249 return this->onWrapBackendTextureAsRenderTarget(desc); 250 } 251 252 GrBuffer* GrGpu::createBuffer(size_t size, GrBufferType intendedType, 253 GrAccessPattern accessPattern, const void* data) { 254 this->handleDirtyContext(); 255 GrBuffer* buffer = this->onCreateBuffer(size, intendedType, accessPattern, data); 256 if (!this->caps()->reuseScratchBuffers()) { 257 buffer->resourcePriv().removeScratchKey(); 258 } 259 return buffer; 260 } 261 262 gr_instanced::InstancedRendering* GrGpu::createInstancedRendering() { 263 SkASSERT(GrCaps::InstancedSupport::kNone != this->caps()->instancedSupport()); 264 return this->onCreateInstancedRendering(); 265 } 266 267 bool GrGpu::copySurface(GrSurface* dst, 268 GrSurface* src, 269 const SkIRect& srcRect, 270 const SkIPoint& dstPoint) { 271 SkASSERT(dst && src); 272 this->handleDirtyContext(); 273 // We don't allow conversion between integer configs and float/fixed configs. 274 if (GrPixelConfigIsSint(dst->config()) != GrPixelConfigIsSint(src->config())) { 275 return false; 276 } 277 if (GrPixelConfigIsCompressed(dst->config())) { 278 return false; 279 } 280 return this->onCopySurface(dst, src, srcRect, dstPoint); 281 } 282 283 bool GrGpu::getReadPixelsInfo(GrSurface* srcSurface, int width, int height, size_t rowBytes, 284 GrPixelConfig readConfig, DrawPreference* drawPreference, 285 ReadPixelTempDrawInfo* tempDrawInfo) { 286 SkASSERT(drawPreference); 287 SkASSERT(tempDrawInfo); 288 SkASSERT(srcSurface); 289 SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference); 290 291 // We don't allow conversion between integer configs and float/fixed configs. 292 if (GrPixelConfigIsSint(srcSurface->config()) != GrPixelConfigIsSint(readConfig)) { 293 return false; 294 } 295 296 // We currently do not support reading into a compressed buffer 297 if (GrPixelConfigIsCompressed(readConfig)) { 298 return false; 299 } 300 301 // We currently do not support reading into the packed formats 565 or 4444 as they are not 302 // required to have read back support on all devices and backends. 303 if (kRGB_565_GrPixelConfig == readConfig || kRGBA_4444_GrPixelConfig == readConfig) { 304 return false; 305 } 306 307 if (!this->onGetReadPixelsInfo(srcSurface, width, height, rowBytes, readConfig, drawPreference, 308 tempDrawInfo)) { 309 return false; 310 } 311 312 // Check to see if we're going to request that the caller draw when drawing is not possible. 313 if (!srcSurface->asTexture() || 314 !this->caps()->isConfigRenderable(tempDrawInfo->fTempSurfaceDesc.fConfig, false)) { 315 // If we don't have a fallback to a straight read then fail. 316 if (kRequireDraw_DrawPreference == *drawPreference) { 317 return false; 318 } 319 *drawPreference = kNoDraw_DrawPreference; 320 } 321 322 return true; 323 } 324 bool GrGpu::getWritePixelsInfo(GrSurface* dstSurface, int width, int height, 325 GrPixelConfig srcConfig, DrawPreference* drawPreference, 326 WritePixelTempDrawInfo* tempDrawInfo) { 327 SkASSERT(drawPreference); 328 SkASSERT(tempDrawInfo); 329 SkASSERT(dstSurface); 330 SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference); 331 332 if (GrPixelConfigIsCompressed(dstSurface->desc().fConfig) && 333 dstSurface->desc().fConfig != srcConfig) { 334 return false; 335 } 336 337 // We don't allow conversion between integer configs and float/fixed configs. 338 if (GrPixelConfigIsSint(dstSurface->config()) != GrPixelConfigIsSint(srcConfig)) { 339 return false; 340 } 341 342 if (SkToBool(dstSurface->asRenderTarget())) { 343 if (this->caps()->useDrawInsteadOfAllRenderTargetWrites()) { 344 ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); 345 } else if (this->caps()->useDrawInsteadOfPartialRenderTargetWrite() && 346 (width < dstSurface->width() || height < dstSurface->height())) { 347 ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); 348 } 349 } 350 351 if (!this->onGetWritePixelsInfo(dstSurface, width, height, srcConfig, drawPreference, 352 tempDrawInfo)) { 353 return false; 354 } 355 356 // Check to see if we're going to request that the caller draw when drawing is not possible. 357 if (!dstSurface->asRenderTarget() || 358 !this->caps()->isConfigTexturable(tempDrawInfo->fTempSurfaceDesc.fConfig)) { 359 // If we don't have a fallback to a straight upload then fail. 360 if (kRequireDraw_DrawPreference == *drawPreference || 361 !this->caps()->isConfigTexturable(srcConfig)) { 362 return false; 363 } 364 *drawPreference = kNoDraw_DrawPreference; 365 } 366 return true; 367 } 368 369 bool GrGpu::readPixels(GrSurface* surface, 370 int left, int top, int width, int height, 371 GrPixelConfig config, void* buffer, 372 size_t rowBytes) { 373 SkASSERT(surface); 374 375 // We don't allow conversion between integer configs and float/fixed configs. 376 if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) { 377 return false; 378 } 379 380 // We cannot read pixels into a compressed buffer 381 if (GrPixelConfigIsCompressed(config)) { 382 return false; 383 } 384 385 size_t bpp = GrBytesPerPixel(config); 386 if (!GrSurfacePriv::AdjustReadPixelParams(surface->width(), surface->height(), bpp, 387 &left, &top, &width, &height, 388 &buffer, 389 &rowBytes)) { 390 return false; 391 } 392 393 this->handleDirtyContext(); 394 395 return this->onReadPixels(surface, 396 left, top, width, height, 397 config, buffer, 398 rowBytes); 399 } 400 401 bool GrGpu::writePixels(GrSurface* surface, 402 int left, int top, int width, int height, 403 GrPixelConfig config, const SkTArray<GrMipLevel>& texels) { 404 SkASSERT(surface); 405 for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { 406 if (!texels[currentMipLevel].fPixels ) { 407 return false; 408 } 409 } 410 411 // We don't allow conversion between integer configs and float/fixed configs. 412 if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) { 413 return false; 414 } 415 416 this->handleDirtyContext(); 417 if (this->onWritePixels(surface, left, top, width, height, config, texels)) { 418 SkIRect rect = SkIRect::MakeXYWH(left, top, width, height); 419 this->didWriteToSurface(surface, &rect, texels.count()); 420 fStats.incTextureUploads(); 421 return true; 422 } 423 return false; 424 } 425 426 bool GrGpu::writePixels(GrSurface* surface, 427 int left, int top, int width, int height, 428 GrPixelConfig config, const void* buffer, 429 size_t rowBytes) { 430 GrMipLevel mipLevel; 431 mipLevel.fPixels = buffer; 432 mipLevel.fRowBytes = rowBytes; 433 SkSTArray<1, GrMipLevel> texels; 434 texels.push_back(mipLevel); 435 436 return this->writePixels(surface, left, top, width, height, config, texels); 437 } 438 439 bool GrGpu::transferPixels(GrSurface* surface, 440 int left, int top, int width, int height, 441 GrPixelConfig config, GrBuffer* transferBuffer, 442 size_t offset, size_t rowBytes, GrFence* fence) { 443 SkASSERT(transferBuffer); 444 SkASSERT(fence); 445 446 // We don't allow conversion between integer configs and float/fixed configs. 447 if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) { 448 return false; 449 } 450 451 this->handleDirtyContext(); 452 if (this->onTransferPixels(surface, left, top, width, height, config, 453 transferBuffer, offset, rowBytes)) { 454 SkIRect rect = SkIRect::MakeXYWH(left, top, width, height); 455 this->didWriteToSurface(surface, &rect); 456 fStats.incTransfersToTexture(); 457 458 if (*fence) { 459 this->deleteFence(*fence); 460 } 461 *fence = this->insertFence(); 462 463 return true; 464 } 465 return false; 466 } 467 468 void GrGpu::resolveRenderTarget(GrRenderTarget* target) { 469 SkASSERT(target); 470 this->handleDirtyContext(); 471 this->onResolveRenderTarget(target); 472 } 473 474 void GrGpu::didWriteToSurface(GrSurface* surface, const SkIRect* bounds, uint32_t mipLevels) const { 475 SkASSERT(surface); 476 // Mark any MIP chain and resolve buffer as dirty if and only if there is a non-empty bounds. 477 if (nullptr == bounds || !bounds->isEmpty()) { 478 if (GrRenderTarget* target = surface->asRenderTarget()) { 479 target->flagAsNeedingResolve(bounds); 480 } 481 GrTexture* texture = surface->asTexture(); 482 if (texture && 1 == mipLevels) { 483 texture->texturePriv().dirtyMipMaps(true); 484 } 485 } 486 } 487 488 const GrGpu::MultisampleSpecs& GrGpu::queryMultisampleSpecs(const GrPipeline& pipeline) { 489 GrRenderTarget* rt = pipeline.getRenderTarget(); 490 SkASSERT(rt->desc().fSampleCnt > 1); 491 492 GrStencilSettings stencil; 493 if (pipeline.isStencilEnabled()) { 494 // TODO: attach stencil and create settings during render target flush. 495 SkASSERT(rt->renderTargetPriv().getStencilAttachment()); 496 stencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(), 497 rt->renderTargetPriv().numStencilBits()); 498 } 499 500 int effectiveSampleCnt; 501 SkSTArray<16, SkPoint, true> pattern; 502 this->onQueryMultisampleSpecs(rt, stencil, &effectiveSampleCnt, &pattern); 503 SkASSERT(effectiveSampleCnt >= rt->desc().fSampleCnt); 504 505 uint8_t id; 506 if (this->caps()->sampleLocationsSupport()) { 507 SkASSERT(pattern.count() == effectiveSampleCnt); 508 const auto& insertResult = fMultisampleSpecsIdMap.insert( 509 MultisampleSpecsIdMap::value_type(pattern, SkTMin(fMultisampleSpecs.count(), 255))); 510 id = insertResult.first->second; 511 if (insertResult.second) { 512 // This means the insert did not find the pattern in the map already, and therefore an 513 // actual insertion took place. (We don't expect to see many unique sample patterns.) 514 const SkPoint* sampleLocations = insertResult.first->first.begin(); 515 SkASSERT(id == fMultisampleSpecs.count()); 516 fMultisampleSpecs.emplace_back(id, effectiveSampleCnt, sampleLocations); 517 } 518 } else { 519 id = effectiveSampleCnt; 520 for (int i = fMultisampleSpecs.count(); i <= id; ++i) { 521 fMultisampleSpecs.emplace_back(i, i, nullptr); 522 } 523 } 524 SkASSERT(id > 0); 525 526 return fMultisampleSpecs[id]; 527 } 528 529 bool GrGpu::SamplePatternComparator::operator()(const SamplePattern& a, 530 const SamplePattern& b) const { 531 if (a.count() != b.count()) { 532 return a.count() < b.count(); 533 } 534 for (int i = 0; i < a.count(); ++i) { 535 // This doesn't have geometric meaning. We just need to define an ordering for std::map. 536 if (a[i].x() != b[i].x()) { 537 return a[i].x() < b[i].x(); 538 } 539 if (a[i].y() != b[i].y()) { 540 return a[i].y() < b[i].y(); 541 } 542 } 543 return false; // Equal. 544 } 545