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