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 "GrTextureProxyPriv.h" 30 #include "GrTracing.h" 31 #include "SkJSONWriter.h" 32 #include "SkMathPriv.h" 33 34 //////////////////////////////////////////////////////////////////////////////// 35 36 GrGpu::GrGpu(GrContext* context) 37 : fResetTimestamp(kExpiredTimestamp+1) 38 , fResetBits(kAll_GrBackendState) 39 , fContext(context) { 40 } 41 42 GrGpu::~GrGpu() {} 43 44 void GrGpu::disconnect(DisconnectType) {} 45 46 //////////////////////////////////////////////////////////////////////////////// 47 48 bool GrGpu::IsACopyNeededForRepeatWrapMode(const GrCaps* caps, GrTextureProxy* texProxy, 49 int width, int height, 50 GrSamplerState::Filter filter, 51 GrTextureProducer::CopyParams* copyParams, 52 SkScalar scaleAdjust[2]) { 53 if (!caps->npotTextureTileSupport() && 54 (!SkIsPow2(width) || !SkIsPow2(height))) { 55 SkASSERT(scaleAdjust); 56 copyParams->fWidth = GrNextPow2(width); 57 copyParams->fHeight = GrNextPow2(height); 58 SkASSERT(scaleAdjust); 59 scaleAdjust[0] = ((SkScalar)copyParams->fWidth) / width; 60 scaleAdjust[1] = ((SkScalar)copyParams->fHeight) / height; 61 switch (filter) { 62 case GrSamplerState::Filter::kNearest: 63 copyParams->fFilter = GrSamplerState::Filter::kNearest; 64 break; 65 case GrSamplerState::Filter::kBilerp: 66 case GrSamplerState::Filter::kMipMap: 67 // We are only ever scaling up so no reason to ever indicate kMipMap. 68 copyParams->fFilter = GrSamplerState::Filter::kBilerp; 69 break; 70 } 71 return true; 72 } 73 74 if (texProxy) { 75 // If the texture format itself doesn't support repeat wrap mode or mipmapping (and 76 // those capabilities are required) force a copy. 77 if (texProxy->hasRestrictedSampling()) { 78 copyParams->fFilter = GrSamplerState::Filter::kNearest; 79 copyParams->fWidth = texProxy->width(); 80 copyParams->fHeight = texProxy->height(); 81 return true; 82 } 83 } 84 85 return false; 86 } 87 88 bool GrGpu::IsACopyNeededForMips(const GrCaps* caps, const GrTextureProxy* texProxy, 89 GrSamplerState::Filter filter, 90 GrTextureProducer::CopyParams* copyParams) { 91 SkASSERT(texProxy); 92 bool willNeedMips = GrSamplerState::Filter::kMipMap == filter && caps->mipMapSupport(); 93 // If the texture format itself doesn't support mipmapping (and those capabilities are required) 94 // force a copy. 95 if (willNeedMips && texProxy->mipMapped() == GrMipMapped::kNo) { 96 copyParams->fFilter = GrSamplerState::Filter::kNearest; 97 copyParams->fWidth = texProxy->width(); 98 copyParams->fHeight = texProxy->height(); 99 return true; 100 } 101 102 return false; 103 } 104 105 sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& origDesc, SkBudgeted budgeted, 106 const GrMipLevel texels[], int mipLevelCount) { 107 GR_CREATE_TRACE_MARKER_CONTEXT("GrGpu", "createTexture", fContext); 108 GrSurfaceDesc desc = origDesc; 109 110 GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo; 111 if (!this->caps()->validateSurfaceDesc(desc, mipMapped)) { 112 return nullptr; 113 } 114 115 bool isRT = desc.fFlags & kRenderTarget_GrSurfaceFlag; 116 if (isRT) { 117 desc.fSampleCnt = this->caps()->getRenderTargetSampleCount(desc.fSampleCnt, desc.fConfig); 118 } 119 // Attempt to catch un- or wrongly initialized sample counts. 120 SkASSERT(desc.fSampleCnt > 0 && desc.fSampleCnt <= 64); 121 122 if (mipLevelCount && (desc.fFlags & kPerformInitialClear_GrSurfaceFlag)) { 123 return nullptr; 124 } 125 126 // We shouldn't be rendering into compressed textures 127 SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig) || !isRT); 128 SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig) || 1 == desc.fSampleCnt); 129 130 this->handleDirtyContext(); 131 sk_sp<GrTexture> tex = this->onCreateTexture(desc, budgeted, texels, mipLevelCount); 132 if (tex) { 133 if (!this->caps()->reuseScratchTextures() && !isRT) { 134 tex->resourcePriv().removeScratchKey(); 135 } 136 fStats.incTextureCreates(); 137 if (mipLevelCount) { 138 if (texels[0].fPixels) { 139 fStats.incTextureUploads(); 140 } 141 } 142 } 143 return tex; 144 } 145 146 sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted) { 147 return this->createTexture(desc, budgeted, nullptr, 0); 148 } 149 150 sk_sp<GrTexture> GrGpu::wrapBackendTexture(const GrBackendTexture& backendTex, 151 GrWrapOwnership ownership, GrWrapCacheable cacheable, 152 GrIOType ioType) { 153 SkASSERT(ioType != kWrite_GrIOType); 154 this->handleDirtyContext(); 155 SkASSERT(this->caps()); 156 if (!this->caps()->isConfigTexturable(backendTex.config())) { 157 return nullptr; 158 } 159 if (backendTex.width() > this->caps()->maxTextureSize() || 160 backendTex.height() > this->caps()->maxTextureSize()) { 161 return nullptr; 162 } 163 return this->onWrapBackendTexture(backendTex, ownership, cacheable, ioType); 164 } 165 166 sk_sp<GrTexture> GrGpu::wrapRenderableBackendTexture(const GrBackendTexture& backendTex, 167 int sampleCnt, GrWrapOwnership ownership, 168 GrWrapCacheable cacheable) { 169 this->handleDirtyContext(); 170 if (sampleCnt < 1) { 171 return nullptr; 172 } 173 if (!this->caps()->isConfigTexturable(backendTex.config()) || 174 !this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config())) { 175 return nullptr; 176 } 177 178 if (backendTex.width() > this->caps()->maxRenderTargetSize() || 179 backendTex.height() > this->caps()->maxRenderTargetSize()) { 180 return nullptr; 181 } 182 sk_sp<GrTexture> tex = 183 this->onWrapRenderableBackendTexture(backendTex, sampleCnt, ownership, cacheable); 184 SkASSERT(!tex || tex->asRenderTarget()); 185 return tex; 186 } 187 188 sk_sp<GrRenderTarget> GrGpu::wrapBackendRenderTarget(const GrBackendRenderTarget& backendRT) { 189 if (0 == this->caps()->getRenderTargetSampleCount(backendRT.sampleCnt(), backendRT.config())) { 190 return nullptr; 191 } 192 this->handleDirtyContext(); 193 return this->onWrapBackendRenderTarget(backendRT); 194 } 195 196 sk_sp<GrRenderTarget> GrGpu::wrapBackendTextureAsRenderTarget(const GrBackendTexture& tex, 197 int sampleCnt) { 198 if (0 == this->caps()->getRenderTargetSampleCount(sampleCnt, tex.config())) { 199 return nullptr; 200 } 201 int maxSize = this->caps()->maxTextureSize(); 202 if (tex.width() > maxSize || tex.height() > maxSize) { 203 return nullptr; 204 } 205 this->handleDirtyContext(); 206 return this->onWrapBackendTextureAsRenderTarget(tex, sampleCnt); 207 } 208 209 sk_sp<GrRenderTarget> GrGpu::wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo& imageInfo, 210 const GrVkDrawableInfo& vkInfo) { 211 return this->onWrapVulkanSecondaryCBAsRenderTarget(imageInfo, vkInfo); 212 } 213 214 sk_sp<GrRenderTarget> GrGpu::onWrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo& imageInfo, 215 const GrVkDrawableInfo& vkInfo) { 216 // This is only supported on Vulkan so we default to returning nullptr here 217 return nullptr; 218 } 219 220 sk_sp<GrBuffer> GrGpu::createBuffer(size_t size, GrBufferType intendedType, 221 GrAccessPattern accessPattern, const void* data) { 222 this->handleDirtyContext(); 223 sk_sp<GrBuffer> buffer = this->onCreateBuffer(size, intendedType, accessPattern, data); 224 if (!this->caps()->reuseScratchBuffers()) { 225 buffer->resourcePriv().removeScratchKey(); 226 } 227 return buffer; 228 } 229 230 bool GrGpu::copySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, 231 GrSurface* src, GrSurfaceOrigin srcOrigin, 232 const SkIRect& srcRect, const SkIPoint& dstPoint, 233 bool canDiscardOutsideDstRect) { 234 GR_CREATE_TRACE_MARKER_CONTEXT("GrGpu", "copySurface", fContext); 235 SkASSERT(dst && src); 236 237 if (dst->readOnly()) { 238 return false; 239 } 240 241 this->handleDirtyContext(); 242 243 return this->onCopySurface(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint, 244 canDiscardOutsideDstRect); 245 } 246 247 bool GrGpu::readPixels(GrSurface* surface, int left, int top, int width, int height, 248 GrColorType dstColorType, void* buffer, size_t rowBytes) { 249 SkASSERT(surface); 250 251 int bpp = GrColorTypeBytesPerPixel(dstColorType); 252 if (!GrSurfacePriv::AdjustReadPixelParams(surface->width(), surface->height(), bpp, 253 &left, &top, &width, &height, 254 &buffer, 255 &rowBytes)) { 256 return false; 257 } 258 259 if (GrPixelConfigIsCompressed(surface->config())) { 260 return false; 261 } 262 263 this->handleDirtyContext(); 264 265 return this->onReadPixels(surface, left, top, width, height, dstColorType, buffer, rowBytes); 266 } 267 268 bool GrGpu::writePixels(GrSurface* surface, int left, int top, int width, int height, 269 GrColorType srcColorType, const GrMipLevel texels[], int mipLevelCount) { 270 SkASSERT(surface); 271 272 if (surface->readOnly()) { 273 return false; 274 } 275 276 if (1 == mipLevelCount) { 277 // We require that if we are not mipped, then the write region is contained in the surface 278 SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height); 279 SkIRect bounds = SkIRect::MakeWH(surface->width(), surface->height()); 280 if (!bounds.contains(subRect)) { 281 return false; 282 } 283 } else if (0 != left || 0 != top || width != surface->width() || height != surface->height()) { 284 // We require that if the texels are mipped, than the write region is the entire surface 285 return false; 286 } 287 288 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) { 289 if (!texels[currentMipLevel].fPixels ) { 290 return false; 291 } 292 } 293 294 this->handleDirtyContext(); 295 if (this->onWritePixels(surface, left, top, width, height, srcColorType, texels, 296 mipLevelCount)) { 297 SkIRect rect = SkIRect::MakeXYWH(left, top, width, height); 298 this->didWriteToSurface(surface, kTopLeft_GrSurfaceOrigin, &rect, mipLevelCount); 299 fStats.incTextureUploads(); 300 return true; 301 } 302 return false; 303 } 304 305 bool GrGpu::transferPixels(GrTexture* texture, int left, int top, int width, int height, 306 GrColorType bufferColorType, GrBuffer* transferBuffer, size_t offset, 307 size_t rowBytes) { 308 SkASSERT(texture); 309 SkASSERT(transferBuffer); 310 311 if (texture->readOnly()) { 312 return false; 313 } 314 315 // We require that the write region is contained in the texture 316 SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height); 317 SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height()); 318 if (!bounds.contains(subRect)) { 319 return false; 320 } 321 322 this->handleDirtyContext(); 323 if (this->onTransferPixels(texture, left, top, width, height, bufferColorType, transferBuffer, 324 offset, rowBytes)) { 325 SkIRect rect = SkIRect::MakeXYWH(left, top, width, height); 326 this->didWriteToSurface(texture, kTopLeft_GrSurfaceOrigin, &rect); 327 fStats.incTransfersToTexture(); 328 329 return true; 330 } 331 return false; 332 } 333 334 bool GrGpu::regenerateMipMapLevels(GrTexture* texture) { 335 SkASSERT(texture); 336 SkASSERT(this->caps()->mipMapSupport()); 337 SkASSERT(texture->texturePriv().mipMapped() == GrMipMapped::kYes); 338 SkASSERT(texture->texturePriv().mipMapsAreDirty()); 339 SkASSERT(!texture->asRenderTarget() || !texture->asRenderTarget()->needsResolve()); 340 if (texture->readOnly()) { 341 return false; 342 } 343 if (this->onRegenerateMipMapLevels(texture)) { 344 texture->texturePriv().markMipMapsClean(); 345 return true; 346 } 347 return false; 348 } 349 350 void GrGpu::resolveRenderTarget(GrRenderTarget* target) { 351 SkASSERT(target); 352 this->handleDirtyContext(); 353 this->onResolveRenderTarget(target); 354 } 355 356 void GrGpu::didWriteToSurface(GrSurface* surface, GrSurfaceOrigin origin, const SkIRect* bounds, 357 uint32_t mipLevels) const { 358 SkASSERT(surface); 359 SkASSERT(!surface->readOnly()); 360 // Mark any MIP chain and resolve buffer as dirty if and only if there is a non-empty bounds. 361 if (nullptr == bounds || !bounds->isEmpty()) { 362 if (GrRenderTarget* target = surface->asRenderTarget()) { 363 SkIRect flippedBounds; 364 if (kBottomLeft_GrSurfaceOrigin == origin && bounds) { 365 flippedBounds = {bounds->fLeft, surface->height() - bounds->fBottom, 366 bounds->fRight, surface->height() - bounds->fTop}; 367 bounds = &flippedBounds; 368 } 369 target->flagAsNeedingResolve(bounds); 370 } 371 GrTexture* texture = surface->asTexture(); 372 if (texture && 1 == mipLevels) { 373 texture->texturePriv().markMipMapsDirty(); 374 } 375 } 376 } 377 378 GrSemaphoresSubmitted GrGpu::finishFlush(int numSemaphores, 379 GrBackendSemaphore backendSemaphores[]) { 380 this->stats()->incNumFinishFlushes(); 381 GrResourceProvider* resourceProvider = fContext->contextPriv().resourceProvider(); 382 383 if (this->caps()->fenceSyncSupport()) { 384 for (int i = 0; i < numSemaphores; ++i) { 385 sk_sp<GrSemaphore> semaphore; 386 if (backendSemaphores[i].isInitialized()) { 387 semaphore = resourceProvider->wrapBackendSemaphore( 388 backendSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillSignal, 389 kBorrow_GrWrapOwnership); 390 } else { 391 semaphore = resourceProvider->makeSemaphore(false); 392 } 393 this->insertSemaphore(semaphore); 394 395 if (!backendSemaphores[i].isInitialized()) { 396 backendSemaphores[i] = semaphore->backendSemaphore(); 397 } 398 } 399 } 400 this->onFinishFlush((numSemaphores > 0 && this->caps()->fenceSyncSupport())); 401 return this->caps()->fenceSyncSupport() ? GrSemaphoresSubmitted::kYes 402 : GrSemaphoresSubmitted::kNo; 403 } 404 405 #ifdef SK_ENABLE_DUMP_GPU 406 void GrGpu::dumpJSON(SkJSONWriter* writer) const { 407 writer->beginObject(); 408 409 // TODO: Is there anything useful in the base class to dump here? 410 411 this->onDumpJSON(writer); 412 413 writer->endObject(); 414 } 415 #else 416 void GrGpu::dumpJSON(SkJSONWriter* writer) const { } 417 #endif 418 419 #if GR_TEST_UTILS 420 GrBackendTexture GrGpu::createTestingOnlyBackendTexture(const void* pixels, int w, int h, 421 SkColorType colorType, bool isRenderTarget, 422 GrMipMapped isMipped, size_t rowBytes) { 423 GrColorType grCT = SkColorTypeToGrColorType(colorType); 424 425 return this->createTestingOnlyBackendTexture(pixels, w, h, grCT, isRenderTarget, isMipped, 426 rowBytes); 427 } 428 #endif 429