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 | |