| 1 | /* |
| 2 | * Copyright 2015 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 | #include "include/gpu/GrBackendSurface.h" |
| 9 | #include "include/gpu/GrContextOptions.h" |
| 10 | #include "include/private/GrTypesPriv.h" |
| 11 | #include "src/gpu/GrCaps.h" |
| 12 | #include "src/gpu/GrSurface.h" |
| 13 | #include "src/gpu/GrSurfaceProxy.h" |
| 14 | #include "src/gpu/GrWindowRectangles.h" |
| 15 | #include "src/utils/SkJSONWriter.h" |
| 16 | |
| 17 | GrCaps::GrCaps(const GrContextOptions& options) { |
| 18 | fMipMapSupport = false; |
| 19 | fNPOTTextureTileSupport = false; |
| 20 | fReuseScratchTextures = true; |
| 21 | fReuseScratchBuffers = true; |
| 22 | fGpuTracingSupport = false; |
| 23 | fOversizedStencilSupport = false; |
| 24 | fTextureBarrierSupport = false; |
| 25 | fSampleLocationsSupport = false; |
| 26 | fMultisampleDisableSupport = false; |
| 27 | fDrawInstancedSupport = false; |
| 28 | fNativeDrawIndirectSupport = false; |
| 29 | fMixedSamplesSupport = false; |
| 30 | fConservativeRasterSupport = false; |
| 31 | fWireframeSupport = false; |
| 32 | fMSAAResolvesAutomatically = false; |
| 33 | fUsePrimitiveRestart = false; |
| 34 | fPreferClientSideDynamicBuffers = false; |
| 35 | fPreferFullscreenClears = false; |
| 36 | fMustClearUploadedBufferData = false; |
| 37 | fShouldInitializeTextures = false; |
| 38 | fSupportsAHardwareBufferImages = false; |
| 39 | fFenceSyncSupport = false; |
| 40 | fSemaphoreSupport = false; |
| 41 | fCrossContextTextureSupport = false; |
| 42 | fHalfFloatVertexAttributeSupport = false; |
| 43 | fDynamicStateArrayGeometryProcessorTextureSupport = false; |
| 44 | fPerformPartialClearsAsDraws = false; |
| 45 | fPerformColorClearsAsDraws = false; |
| 46 | fAvoidLargeIndexBufferDraws = false; |
| 47 | fPerformStencilClearsAsDraws = false; |
| 48 | fAllowCoverageCounting = false; |
| 49 | fTransferFromBufferToTextureSupport = false; |
| 50 | fTransferFromSurfaceToBufferSupport = false; |
| 51 | fWritePixelsRowBytesSupport = false; |
| 52 | fReadPixelsRowBytesSupport = false; |
| 53 | fShouldCollapseSrcOverToSrcWhenAble = false; |
| 54 | fDriverBlacklistCCPR = false; |
| 55 | fDriverBlacklistMSAACCPR = false; |
| 56 | |
| 57 | fBlendEquationSupport = kBasic_BlendEquationSupport; |
| 58 | fAdvBlendEqBlacklist = 0; |
| 59 | |
| 60 | fMapBufferFlags = kNone_MapFlags; |
| 61 | |
| 62 | fMaxVertexAttributes = 0; |
| 63 | fMaxRenderTargetSize = 1; |
| 64 | fMaxPreferredRenderTargetSize = 1; |
| 65 | fMaxTextureSize = 1; |
| 66 | fMaxWindowRectangles = 0; |
| 67 | fInternalMultisampleCount = 0; |
| 68 | |
| 69 | fSuppressPrints = options.fSuppressPrints; |
| 70 | #if GR_TEST_UTILS |
| 71 | fWireframeMode = options.fWireframeMode; |
| 72 | #else |
| 73 | fWireframeMode = false; |
| 74 | #endif |
| 75 | fBufferMapThreshold = options.fBufferMapThreshold; |
| 76 | fAvoidStencilBuffers = false; |
| 77 | fAvoidWritePixelsFastPath = false; |
| 78 | fRequiresManualFBBarrierAfterTessellatedStencilDraw = false; |
| 79 | fNativeDrawIndexedIndirectIsBroken = false; |
| 80 | |
| 81 | fPreferVRAMUseOverFlushes = true; |
| 82 | |
| 83 | fPreferTrianglesOverSampleMask = false; |
| 84 | |
| 85 | // Default to true, allow older versions of OpenGL to disable explicitly |
| 86 | fClampToBorderSupport = true; |
| 87 | |
| 88 | fDriverBugWorkarounds = options.fDriverBugWorkarounds; |
| 89 | } |
| 90 | |
| 91 | void GrCaps::finishInitialization(const GrContextOptions& options) { |
| 92 | if (fMixedSamplesSupport) { |
| 93 | // We need multisample disable and dual source blending in order to support mixed samples. |
| 94 | fMixedSamplesSupport = this->multisampleDisableSupport() && |
| 95 | this->shaderCaps()->dualSourceBlendingSupport(); |
| 96 | } |
| 97 | |
| 98 | // Overrides happen last. |
| 99 | this->applyOptionsOverrides(options); |
| 100 | } |
| 101 | |
| 102 | void GrCaps::applyOptionsOverrides(const GrContextOptions& options) { |
| 103 | fShaderCaps->applyOptionsOverrides(options); |
| 104 | this->onApplyOptionsOverrides(options); |
| 105 | if (options.fDisableDriverCorrectnessWorkarounds) { |
| 106 | SkASSERT(!fDriverBlacklistCCPR); |
| 107 | SkASSERT(!fDriverBlacklistMSAACCPR); |
| 108 | SkASSERT(!fAvoidStencilBuffers); |
| 109 | SkASSERT(!fAvoidWritePixelsFastPath); |
| 110 | SkASSERT(!fRequiresManualFBBarrierAfterTessellatedStencilDraw); |
| 111 | SkASSERT(!fNativeDrawIndexedIndirectIsBroken); |
| 112 | SkASSERT(!fAdvBlendEqBlacklist); |
| 113 | SkASSERT(!fPerformColorClearsAsDraws); |
| 114 | SkASSERT(!fPerformStencilClearsAsDraws); |
| 115 | // Don't check the partial-clear workaround, since that is a backend limitation, not a |
| 116 | // driver workaround (it just so happens the fallbacks are the same). |
| 117 | } |
| 118 | if (GrContextOptions::Enable::kNo == options.fUseDrawInsteadOfClear) { |
| 119 | fPerformColorClearsAsDraws = false; |
| 120 | fPerformStencilClearsAsDraws = false; |
| 121 | } else if (GrContextOptions::Enable::kYes == options.fUseDrawInsteadOfClear) { |
| 122 | fPerformColorClearsAsDraws = true; |
| 123 | fPerformStencilClearsAsDraws = true; |
| 124 | } |
| 125 | |
| 126 | fAllowCoverageCounting = !options.fDisableCoverageCountingPaths; |
| 127 | |
| 128 | fMaxTextureSize = std::min(fMaxTextureSize, options.fMaxTextureSizeOverride); |
| 129 | fMaxTileSize = fMaxTextureSize; |
| 130 | #if GR_TEST_UTILS |
| 131 | // If the max tile override is zero, it means we should use the max texture size. |
| 132 | if (options.fMaxTileSizeOverride && options.fMaxTileSizeOverride < fMaxTextureSize) { |
| 133 | fMaxTileSize = options.fMaxTileSizeOverride; |
| 134 | } |
| 135 | if (options.fSuppressDualSourceBlending) { |
| 136 | // GrShaderCaps::applyOptionsOverrides already handled the rest; here we just need to make |
| 137 | // sure mixed samples gets disabled if dual source blending is suppressed. |
| 138 | fMixedSamplesSupport = false; |
| 139 | } |
| 140 | if (options.fClearAllTextures) { |
| 141 | fShouldInitializeTextures = true; |
| 142 | } |
| 143 | #endif |
| 144 | |
| 145 | if (fMaxWindowRectangles > GrWindowRectangles::kMaxWindows) { |
| 146 | SkDebugf("WARNING: capping window rectangles at %i. HW advertises support for %i.\n" , |
| 147 | GrWindowRectangles::kMaxWindows, fMaxWindowRectangles); |
| 148 | fMaxWindowRectangles = GrWindowRectangles::kMaxWindows; |
| 149 | } |
| 150 | |
| 151 | fInternalMultisampleCount = options.fInternalMultisampleCount; |
| 152 | |
| 153 | fAvoidStencilBuffers = options.fAvoidStencilBuffers; |
| 154 | |
| 155 | fDriverBugWorkarounds.applyOverrides(options.fDriverBugWorkarounds); |
| 156 | } |
| 157 | |
| 158 | |
| 159 | #ifdef SK_ENABLE_DUMP_GPU |
| 160 | #include "src/gpu/GrTestUtils.h" |
| 161 | |
| 162 | static SkString map_flags_to_string(uint32_t flags) { |
| 163 | SkString str; |
| 164 | if (GrCaps::kNone_MapFlags == flags) { |
| 165 | str = "none" ; |
| 166 | } else { |
| 167 | SkASSERT(GrCaps::kCanMap_MapFlag & flags); |
| 168 | SkDEBUGCODE(flags &= ~GrCaps::kCanMap_MapFlag); |
| 169 | str = "can_map" ; |
| 170 | |
| 171 | if (GrCaps::kSubset_MapFlag & flags) { |
| 172 | str.append(" partial" ); |
| 173 | } else { |
| 174 | str.append(" full" ); |
| 175 | } |
| 176 | SkDEBUGCODE(flags &= ~GrCaps::kSubset_MapFlag); |
| 177 | if (GrCaps::kAsyncRead_MapFlag & flags) { |
| 178 | str.append(" async_read" ); |
| 179 | } else { |
| 180 | str.append(" sync_read" ); |
| 181 | } |
| 182 | SkDEBUGCODE(flags &= ~GrCaps::kAsyncRead_MapFlag); |
| 183 | } |
| 184 | SkASSERT(0 == flags); // Make sure we handled all the flags. |
| 185 | return str; |
| 186 | } |
| 187 | |
| 188 | void GrCaps::dumpJSON(SkJSONWriter* writer) const { |
| 189 | writer->beginObject(); |
| 190 | |
| 191 | writer->appendBool("MIP Map Support" , fMipMapSupport); |
| 192 | writer->appendBool("NPOT Texture Tile Support" , fNPOTTextureTileSupport); |
| 193 | writer->appendBool("Reuse Scratch Textures" , fReuseScratchTextures); |
| 194 | writer->appendBool("Reuse Scratch Buffers" , fReuseScratchBuffers); |
| 195 | writer->appendBool("Gpu Tracing Support" , fGpuTracingSupport); |
| 196 | writer->appendBool("Oversized Stencil Support" , fOversizedStencilSupport); |
| 197 | writer->appendBool("Texture Barrier Support" , fTextureBarrierSupport); |
| 198 | writer->appendBool("Sample Locations Support" , fSampleLocationsSupport); |
| 199 | writer->appendBool("Multisample disable support" , fMultisampleDisableSupport); |
| 200 | writer->appendBool("Draw Instanced Support" , fDrawInstancedSupport); |
| 201 | writer->appendBool("Native Draw Indirect Support" , fNativeDrawIndirectSupport); |
| 202 | writer->appendBool("Mixed Samples Support" , fMixedSamplesSupport); |
| 203 | writer->appendBool("Conservative Raster Support" , fConservativeRasterSupport); |
| 204 | writer->appendBool("Wireframe Support" , fWireframeSupport); |
| 205 | writer->appendBool("MSAA Resolves Automatically" , fMSAAResolvesAutomatically); |
| 206 | writer->appendBool("Use primitive restart" , fUsePrimitiveRestart); |
| 207 | writer->appendBool("Prefer client-side dynamic buffers" , fPreferClientSideDynamicBuffers); |
| 208 | writer->appendBool("Prefer fullscreen clears (and stencil discard)" , fPreferFullscreenClears); |
| 209 | writer->appendBool("Must clear buffer memory" , fMustClearUploadedBufferData); |
| 210 | writer->appendBool("Should initialize textures" , fShouldInitializeTextures); |
| 211 | writer->appendBool("Supports importing AHardwareBuffers" , fSupportsAHardwareBufferImages); |
| 212 | writer->appendBool("Fence sync support" , fFenceSyncSupport); |
| 213 | writer->appendBool("Semaphore support" , fSemaphoreSupport); |
| 214 | writer->appendBool("Cross context texture support" , fCrossContextTextureSupport); |
| 215 | writer->appendBool("Half float vertex attribute support" , fHalfFloatVertexAttributeSupport); |
| 216 | writer->appendBool("Specify GeometryProcessor textures as a dynamic state array" , |
| 217 | fDynamicStateArrayGeometryProcessorTextureSupport); |
| 218 | writer->appendBool("Use draws for partial clears" , fPerformPartialClearsAsDraws); |
| 219 | writer->appendBool("Use draws for color clears" , fPerformColorClearsAsDraws); |
| 220 | writer->appendBool("Avoid Large IndexBuffer Draws" , fAvoidLargeIndexBufferDraws); |
| 221 | writer->appendBool("Use draws for stencil clip clears" , fPerformStencilClearsAsDraws); |
| 222 | writer->appendBool("Allow coverage counting shortcuts" , fAllowCoverageCounting); |
| 223 | writer->appendBool("Supports transfers from buffers to textures" , |
| 224 | fTransferFromBufferToTextureSupport); |
| 225 | writer->appendBool("Supports transfers from textures to buffers" , |
| 226 | fTransferFromSurfaceToBufferSupport); |
| 227 | writer->appendBool("Write pixels row bytes support" , fWritePixelsRowBytesSupport); |
| 228 | writer->appendBool("Read pixels row bytes support" , fReadPixelsRowBytesSupport); |
| 229 | writer->appendBool("Blacklist CCPR on current driver [workaround]" , fDriverBlacklistCCPR); |
| 230 | writer->appendBool("Blacklist MSAA version of CCPR on current driver [workaround]" , |
| 231 | fDriverBlacklistMSAACCPR); |
| 232 | writer->appendBool("Clamp-to-border" , fClampToBorderSupport); |
| 233 | |
| 234 | writer->appendBool("Prefer VRAM Use over flushes [workaround]" , fPreferVRAMUseOverFlushes); |
| 235 | writer->appendBool("Prefer more triangles over sample mask [MSAA only]" , |
| 236 | fPreferTrianglesOverSampleMask); |
| 237 | writer->appendBool("Avoid stencil buffers [workaround]" , fAvoidStencilBuffers); |
| 238 | writer->appendBool("Avoid writePixels fast path [workaround]" , fAvoidWritePixelsFastPath); |
| 239 | writer->appendBool("Requires manual FB barrier after tessellated stencilDraw [workaround]" , |
| 240 | fRequiresManualFBBarrierAfterTessellatedStencilDraw); |
| 241 | writer->appendBool("Native draw indexed indirect is broken [workaround]" , |
| 242 | fNativeDrawIndexedIndirectIsBroken); |
| 243 | |
| 244 | if (this->advancedBlendEquationSupport()) { |
| 245 | writer->appendHexU32("Advanced Blend Equation Blacklist" , fAdvBlendEqBlacklist); |
| 246 | } |
| 247 | |
| 248 | writer->appendS32("Max Vertex Attributes" , fMaxVertexAttributes); |
| 249 | writer->appendS32("Max Texture Size" , fMaxTextureSize); |
| 250 | writer->appendS32("Max Render Target Size" , fMaxRenderTargetSize); |
| 251 | writer->appendS32("Max Preferred Render Target Size" , fMaxPreferredRenderTargetSize); |
| 252 | writer->appendS32("Max Window Rectangles" , fMaxWindowRectangles); |
| 253 | writer->appendS32("Preferred Sample Count for Internal MSAA and Mixed Samples" , |
| 254 | fInternalMultisampleCount); |
| 255 | |
| 256 | static const char* kBlendEquationSupportNames[] = { |
| 257 | "Basic" , |
| 258 | "Advanced" , |
| 259 | "Advanced Coherent" , |
| 260 | }; |
| 261 | static_assert(0 == kBasic_BlendEquationSupport); |
| 262 | static_assert(1 == kAdvanced_BlendEquationSupport); |
| 263 | static_assert(2 == kAdvancedCoherent_BlendEquationSupport); |
| 264 | static_assert(SK_ARRAY_COUNT(kBlendEquationSupportNames) == kLast_BlendEquationSupport + 1); |
| 265 | |
| 266 | writer->appendString("Blend Equation Support" , |
| 267 | kBlendEquationSupportNames[fBlendEquationSupport]); |
| 268 | writer->appendString("Map Buffer Support" , map_flags_to_string(fMapBufferFlags).c_str()); |
| 269 | |
| 270 | this->onDumpJSON(writer); |
| 271 | |
| 272 | writer->appendName("shaderCaps" ); |
| 273 | this->shaderCaps()->dumpJSON(writer); |
| 274 | |
| 275 | writer->endObject(); |
| 276 | } |
| 277 | #else |
| 278 | void GrCaps::dumpJSON(SkJSONWriter* writer) const { } |
| 279 | #endif |
| 280 | |
| 281 | bool GrCaps::surfaceSupportsWritePixels(const GrSurface* surface) const { |
| 282 | return surface->readOnly() ? false : this->onSurfaceSupportsWritePixels(surface); |
| 283 | } |
| 284 | |
| 285 | bool GrCaps::canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src, |
| 286 | const SkIRect& srcRect, const SkIPoint& dstPoint) const { |
| 287 | if (dst->readOnly()) { |
| 288 | return false; |
| 289 | } |
| 290 | |
| 291 | if (dst->backendFormat() != src->backendFormat()) { |
| 292 | return false; |
| 293 | } |
| 294 | return this->onCanCopySurface(dst, src, srcRect, dstPoint); |
| 295 | } |
| 296 | |
| 297 | bool GrCaps::validateSurfaceParams(const SkISize& dimensions, const GrBackendFormat& format, |
| 298 | GrRenderable renderable, int renderTargetSampleCnt, |
| 299 | GrMipMapped mipped) const { |
| 300 | if (!this->isFormatTexturable(format)) { |
| 301 | return false; |
| 302 | } |
| 303 | |
| 304 | if (GrMipMapped::kYes == mipped && !this->mipMapSupport()) { |
| 305 | return false; |
| 306 | } |
| 307 | |
| 308 | if (dimensions.width() < 1 || dimensions.height() < 1) { |
| 309 | return false; |
| 310 | } |
| 311 | |
| 312 | if (renderable == GrRenderable::kYes) { |
| 313 | if (!this->isFormatRenderable(format, renderTargetSampleCnt)) { |
| 314 | return false; |
| 315 | } |
| 316 | int maxRTSize = this->maxRenderTargetSize(); |
| 317 | if (dimensions.width() > maxRTSize || dimensions.height() > maxRTSize) { |
| 318 | return false; |
| 319 | } |
| 320 | } else { |
| 321 | // We currently do not support multisampled textures |
| 322 | if (renderTargetSampleCnt != 1) { |
| 323 | return false; |
| 324 | } |
| 325 | int maxSize = this->maxTextureSize(); |
| 326 | if (dimensions.width() > maxSize || dimensions.height() > maxSize) { |
| 327 | return false; |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | return true; |
| 332 | } |
| 333 | |
| 334 | GrCaps::SupportedRead GrCaps::supportedReadPixelsColorType(GrColorType srcColorType, |
| 335 | const GrBackendFormat& srcFormat, |
| 336 | GrColorType dstColorType) const { |
| 337 | SupportedRead read = this->onSupportedReadPixelsColorType(srcColorType, srcFormat, |
| 338 | dstColorType); |
| 339 | |
| 340 | // There are known problems with 24 vs 32 bit BPP with this color type. Just fail for now if |
| 341 | // using a transfer buffer. |
| 342 | if (GrColorType::kRGB_888x == read.fColorType) { |
| 343 | read.fOffsetAlignmentForTransferBuffer = 0; |
| 344 | } |
| 345 | // It's very convenient to access 1 byte-per-channel 32 bit color types as uint32_t on the CPU. |
| 346 | // Make those aligned reads out of the buffer even if the underlying API doesn't require it. |
| 347 | auto channelFlags = GrColorTypeChannelFlags(read.fColorType); |
| 348 | if ((channelFlags == kRGBA_SkColorChannelFlags || channelFlags == kRGB_SkColorChannelFlags || |
| 349 | channelFlags == kAlpha_SkColorChannelFlag || channelFlags == kGray_SkColorChannelFlag) && |
| 350 | GrColorTypeBytesPerPixel(read.fColorType) == 4) { |
| 351 | switch (read.fOffsetAlignmentForTransferBuffer & 0b11) { |
| 352 | // offset alignment already a multiple of 4 |
| 353 | case 0: |
| 354 | break; |
| 355 | // offset alignment is a multiple of 2 but not 4. |
| 356 | case 2: |
| 357 | read.fOffsetAlignmentForTransferBuffer *= 2; |
| 358 | // offset alignment is not a multiple of 2. |
| 359 | default: |
| 360 | read.fOffsetAlignmentForTransferBuffer *= 4; |
| 361 | } |
| 362 | } |
| 363 | return read; |
| 364 | } |
| 365 | |
| 366 | GrBackendFormat GrCaps::getDefaultBackendFormat(GrColorType colorType, |
| 367 | GrRenderable renderable) const { |
| 368 | auto format = this->onGetDefaultBackendFormat(colorType); |
| 369 | if (!this->isFormatTexturable(format)) { |
| 370 | return {}; |
| 371 | } |
| 372 | if (!this->areColorTypeAndFormatCompatible(colorType, format)) { |
| 373 | return {}; |
| 374 | } |
| 375 | // Currently we require that it be possible to write pixels into the "default" format. Perhaps, |
| 376 | // that could be a separate requirement from the caller. It seems less necessary if |
| 377 | // renderability was requested. |
| 378 | if (this->supportedWritePixelsColorType(colorType, format, colorType).fColorType == |
| 379 | GrColorType::kUnknown) { |
| 380 | return {}; |
| 381 | } |
| 382 | if (renderable == GrRenderable::kYes && |
| 383 | !this->isFormatAsColorTypeRenderable(colorType, format)) { |
| 384 | return {}; |
| 385 | } |
| 386 | return format; |
| 387 | } |
| 388 | |