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