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