diff options
Diffstat (limited to 'src')
46 files changed, 351 insertions, 302 deletions
diff --git a/src/gpu/GrBackendSurface.cpp b/src/gpu/GrBackendSurface.cpp index 406cb228ea..16fa793d25 100644 --- a/src/gpu/GrBackendSurface.cpp +++ b/src/gpu/GrBackendSurface.cpp @@ -106,7 +106,7 @@ GrBackendRenderTarget::GrBackendRenderTarget(int width, const GrVkImageInfo& vkInfo) : fWidth(width) , fHeight(height) - , fSampleCnt(sampleCnt) + , fSampleCnt(SkTMax(1, sampleCnt)) , fStencilBits(stencilBits) , fConfig(GrVkFormatToPixelConfig(vkInfo.fFormat)) , fBackend(kVulkan_GrBackend) @@ -121,7 +121,7 @@ GrBackendRenderTarget::GrBackendRenderTarget(int width, const GrGLFramebufferInfo& glInfo) : fWidth(width) , fHeight(height) - , fSampleCnt(sampleCnt) + , fSampleCnt(SkTMax(1, sampleCnt)) , fStencilBits(stencilBits) , fConfig(config) , fBackend(kOpenGL_GrBackend) @@ -134,7 +134,7 @@ GrBackendRenderTarget::GrBackendRenderTarget(int width, const GrGLFramebufferInfo& glInfo) : fWidth(width) , fHeight(height) - , fSampleCnt(sampleCnt) + , fSampleCnt(SkTMax(1, sampleCnt)) , fStencilBits(stencilBits) , fConfig(GrGLSizedFormatToPixelConfig(glInfo.fFormat)) , fBackend(kOpenGL_GrBackend) diff --git a/src/gpu/GrBackendTextureImageGenerator.cpp b/src/gpu/GrBackendTextureImageGenerator.cpp index ae27912b32..af28409cfe 100644 --- a/src/gpu/GrBackendTextureImageGenerator.cpp +++ b/src/gpu/GrBackendTextureImageGenerator.cpp @@ -186,8 +186,8 @@ sk_sp<GrTextureProxy> GrBackendTextureImageGenerator::onGenerateTexture( GrMipMapped mipMapped = willNeedMipMaps ? GrMipMapped::kYes : GrMipMapped::kNo; sk_sp<GrRenderTargetContext> rtContext(context->makeDeferredRenderTargetContext( - SkBackingFit::kExact, info.width(), info.height(), proxy->config(), nullptr, - 0, mipMapped, proxy->origin(), nullptr, SkBudgeted::kYes)); + SkBackingFit::kExact, info.width(), info.height(), proxy->config(), nullptr, 1, + mipMapped, proxy->origin(), nullptr, SkBudgeted::kYes)); if (!rtContext) { return nullptr; diff --git a/src/gpu/GrBlurUtils.cpp b/src/gpu/GrBlurUtils.cpp index b79a38a884..b6e3092d5a 100644 --- a/src/gpu/GrBlurUtils.cpp +++ b/src/gpu/GrBlurUtils.cpp @@ -110,7 +110,7 @@ static sk_sp<GrTextureProxy> create_mask_GPU(GrContext* context, int sampleCnt) { if (GrAA::kNo == aa) { // Don't need MSAA if mask isn't AA - sampleCnt = 0; + sampleCnt = 1; } sk_sp<GrRenderTargetContext> rtContext(context->makeDeferredRenderTargetContextWithFallback( diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp index 427b20425a..dd589b436f 100644 --- a/src/gpu/GrCaps.cpp +++ b/src/gpu/GrCaps.cpp @@ -196,8 +196,7 @@ void GrCaps::dumpJSON(SkJSONWriter* writer) const { kBlendEquationSupportNames[fBlendEquationSupport]); writer->appendString("Map Buffer Support", map_flags_to_string(fMapBufferFlags).c_str()); - SkASSERT(!this->isConfigRenderable(kUnknown_GrPixelConfig, false)); - SkASSERT(!this->isConfigRenderable(kUnknown_GrPixelConfig, true)); + SkASSERT(!this->isConfigRenderable(kUnknown_GrPixelConfig)); SkASSERT(!this->isConfigTexturable(kUnknown_GrPixelConfig)); writer->beginArray("configs"); @@ -206,8 +205,7 @@ void GrCaps::dumpJSON(SkJSONWriter* writer) const { GrPixelConfig config = static_cast<GrPixelConfig>(i); writer->beginObject(nullptr, false); writer->appendString("name", pixel_config_name(config)); - writer->appendBool("renderable", this->isConfigRenderable(config, false)); - writer->appendBool("renderableMSAA", this->isConfigRenderable(config, true)); + writer->appendS32("max sample count", this->maxRenderTargetSampleCount(config)); writer->appendBool("texturable", this->isConfigTexturable(config)); writer->endObject(); } @@ -222,3 +220,39 @@ void GrCaps::dumpJSON(SkJSONWriter* writer) const { writer->endObject(); } +bool GrCaps::validateSurfaceDesc(const GrSurfaceDesc& desc, GrMipMapped mipped) const { + if (!this->isConfigTexturable(desc.fConfig)) { + return false; + } + + if (GrMipMapped::kYes == mipped) { + if (GrPixelConfigIsSint(desc.fConfig) || !this->mipMapSupport()) { + return false; + } + } + + if (desc.fWidth < 1 || desc.fHeight < 1) { + return false; + } + + if (SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag)) { + if (0 == this->getRenderTargetSampleCount(desc.fSampleCnt, desc.fConfig)) { + return false; + } + int maxRTSize = this->maxRenderTargetSize(); + if (desc.fWidth > maxRTSize || desc.fHeight > maxRTSize) { + return false; + } + } else { + // We currently do not support multisampled textures + if (desc.fSampleCnt > 1) { + return false; + } + int maxSize = this->maxTextureSize(); + if (desc.fWidth > maxSize || desc.fHeight > maxSize) { + return false; + } + } + + return true; +} diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp index 8f82ea1228..24c813e654 100644 --- a/src/gpu/GrClipStackClip.cpp +++ b/src/gpu/GrClipStackClip.cpp @@ -198,7 +198,7 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar // With mixed samples (non-msaa color buffer), any coverage info is lost from color once it // hits the color buffer anyway, so we may as well use coverage AA if nothing else in the // pipe is multisampled. - if (renderTargetContext->numColorSamples() > 0 || useHWAA || hasUserStencilSettings) { + if (renderTargetContext->numColorSamples() > 1 || useHWAA || hasUserStencilSettings) { maxAnalyticFPs = 0; } SkASSERT(!context->caps()->avoidStencilBuffers()); // We disable MSAA when avoiding stencil. diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index b427e70beb..05908f4889 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -420,6 +420,18 @@ size_t GrContext::getResourceCachePurgeableBytes() const { //////////////////////////////////////////////////////////////////////////////// +bool GrContext::colorTypeSupportedAsImage(SkColorType colorType) const { + GrPixelConfig config = SkImageInfo2GrPixelConfig(colorType, nullptr, *this->caps()); + return this->caps()->isConfigTexturable(config); +} + +int GrContext::maxSurfaceSampleCountForColorType(SkColorType colorType) const { + GrPixelConfig config = SkImageInfo2GrPixelConfig(colorType, nullptr, *this->caps()); + return this->caps()->maxRenderTargetSampleCount(config); +} + +//////////////////////////////////////////////////////////////////////////////// + void GrContext::TextBlobCacheOverBudgetCB(void* data) { SkASSERT(data); // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on @@ -862,6 +874,7 @@ sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContex sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props) { ASSERT_SINGLE_OWNER_PRIV + SkASSERT(sampleCnt > 0); sk_sp<GrTextureProxy> proxy(this->proxyProvider()->createWrappedTextureProxy(tex, origin, sampleCnt)); @@ -898,7 +911,7 @@ sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRend sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props) { ASSERT_SINGLE_OWNER_PRIV - + SkASSERT(sampleCnt > 0); sk_sp<GrSurfaceProxy> proxy(this->proxyProvider()->createWrappedRenderTargetProxy(tex, origin, sampleCnt)); if (!proxy) { @@ -949,7 +962,8 @@ sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContextWithFallb GrSurfaceOrigin origin, const SkSurfaceProps* surfaceProps, SkBudgeted budgeted) { - if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) { + SkASSERT(sampleCnt > 0); + if (0 == this->caps()->getRenderTargetSampleCount(sampleCnt, config)) { config = GrPixelConfigFallback(config); } @@ -968,6 +982,7 @@ sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContext( GrSurfaceOrigin origin, const SkSurfaceProps* surfaceProps, SkBudgeted budgeted) { + SkASSERT(sampleCnt > 0); if (this->abandoned()) { return nullptr; } diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index eb005d110a..955d57ddb0 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -72,68 +72,22 @@ bool GrGpu::isACopyNeededForTextureParams(int width, int height, return false; } -/** - * Prior to creating a texture, make sure the type of texture being created is - * supported by calling check_texture_creation_params. - * - * @param caps The capabilities of the GL device. - * @param desc The descriptor of the texture to create. - * @param isRT Indicates if the texture can be a render target. - * @param texels The texel data for the mipmap levels - * @param mipLevelCount The number of GrMipLevels in 'texels' - */ -static bool check_texture_creation_params(const GrCaps& caps, const GrSurfaceDesc& desc, - bool* isRT, - const GrMipLevel texels[], int mipLevelCount) { - if (!caps.isConfigTexturable(desc.fConfig)) { - return false; - } - - if (GrPixelConfigIsSint(desc.fConfig) && mipLevelCount > 1) { - return false; - } - - *isRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); - if (*isRT && !caps.isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { - return false; - } - - // We currently do not support multisampled textures - if (!*isRT && desc.fSampleCnt > 0) { - return false; - } - - if (*isRT) { - int maxRTSize = caps.maxRenderTargetSize(); - if (desc.fWidth > maxRTSize || desc.fHeight > maxRTSize) { - return false; - } - } else { - int maxSize = caps.maxTextureSize(); - if (desc.fWidth > maxSize || desc.fHeight > maxSize) { - return false; - } - } - - return true; -} - sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& origDesc, SkBudgeted budgeted, const GrMipLevel texels[], int mipLevelCount) { GR_CREATE_TRACE_MARKER_CONTEXT("GrGpu", "createTexture", fContext); GrSurfaceDesc desc = origDesc; - const GrCaps* caps = this->caps(); - bool isRT = false; - bool textureCreationParamsValid = check_texture_creation_params(*caps, desc, &isRT, - texels, mipLevelCount); - if (!textureCreationParamsValid) { + GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo; + if (!this->caps()->validateSurfaceDesc(desc, mipMapped)) { return nullptr; } - desc.fSampleCnt = caps->getSampleCount(desc.fSampleCnt, desc.fConfig); + bool isRT = desc.fFlags & kRenderTarget_GrSurfaceFlag; + if (isRT) { + desc.fSampleCnt = this->caps()->getRenderTargetSampleCount(desc.fSampleCnt, desc.fConfig); + } // Attempt to catch un- or wrongly initialized sample counts. - SkASSERT(desc.fSampleCnt >= 0 && desc.fSampleCnt <= 64); + SkASSERT(desc.fSampleCnt > 0 && desc.fSampleCnt <= 64); if (mipLevelCount && (desc.fFlags & kPerformInitialClear_GrSurfaceFlag)) { return nullptr; @@ -142,7 +96,7 @@ sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& origDesc, SkBudgeted this->handleDirtyContext(); sk_sp<GrTexture> tex = this->onCreateTexture(desc, budgeted, texels, mipLevelCount); if (tex) { - if (!caps->reuseScratchTextures() && !isRT) { + if (!this->caps()->reuseScratchTextures() && !isRT) { tex->resourcePriv().removeScratchKey(); } fStats.incTextureCreates(); @@ -179,8 +133,11 @@ sk_sp<GrTexture> GrGpu::wrapBackendTexture(const GrBackendTexture& backendTex, sk_sp<GrTexture> GrGpu::wrapRenderableBackendTexture(const GrBackendTexture& backendTex, int sampleCnt, GrWrapOwnership ownership) { this->handleDirtyContext(); + if (sampleCnt < 1) { + return nullptr; + } if (!this->caps()->isConfigTexturable(backendTex.config()) || - !this->caps()->isConfigRenderable(backendTex.config(), sampleCnt > 0)) { + !this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config())) { return nullptr; } @@ -197,7 +154,7 @@ sk_sp<GrTexture> GrGpu::wrapRenderableBackendTexture(const GrBackendTexture& bac } sk_sp<GrRenderTarget> GrGpu::wrapBackendRenderTarget(const GrBackendRenderTarget& backendRT) { - if (!this->caps()->isConfigRenderable(backendRT.config(), backendRT.sampleCnt() > 0)) { + if (0 == this->caps()->getRenderTargetSampleCount(backendRT.sampleCnt(), backendRT.config())) { return nullptr; } this->handleDirtyContext(); @@ -206,14 +163,14 @@ sk_sp<GrRenderTarget> GrGpu::wrapBackendRenderTarget(const GrBackendRenderTarget sk_sp<GrRenderTarget> GrGpu::wrapBackendTextureAsRenderTarget(const GrBackendTexture& tex, int sampleCnt) { - this->handleDirtyContext(); - if (!this->caps()->isConfigRenderable(tex.config(), sampleCnt > 0)) { + if (0 == this->caps()->getRenderTargetSampleCount(sampleCnt, tex.config())) { return nullptr; } int maxSize = this->caps()->maxTextureSize(); if (tex.width() > maxSize || tex.height() > maxSize) { return nullptr; } + this->handleDirtyContext(); return this->onWrapBackendTextureAsRenderTarget(tex, sampleCnt); } @@ -262,7 +219,7 @@ bool GrGpu::getReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin, // Check to see if we're going to request that the caller draw when drawing is not possible. if (!srcSurface->asTexture() || - !this->caps()->isConfigRenderable(tempDrawInfo->fTempSurfaceDesc.fConfig, false)) { + !this->caps()->isConfigRenderable(tempDrawInfo->fTempSurfaceDesc.fConfig)) { // If we don't have a fallback to a straight read then fail. if (kRequireDraw_DrawPreference == *drawPreference) { return false; diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index 2f12073f8a..6527064b93 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -455,6 +455,10 @@ public: /** Creates a texture directly in the backend API without wrapping it in a GrTexture. This is only to be used for testing (particularly for testing the methods that import an externally created texture into Skia. Must be matched with a call to deleteTestingOnlyTexture(). */ + GrBackendTexture createTestingOnlyBackendTexture(void* pixels, int w, int h, SkColorType, + bool isRenderTarget, GrMipMapped); + + /** Older version based on GrPixelConfig. Currently the preferred one above devolves to this. */ virtual GrBackendTexture createTestingOnlyBackendTexture( void* pixels, int w, int h, GrPixelConfig config, diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp index e453246b62..6641bcf9a8 100644 --- a/src/gpu/GrProxyProvider.cpp +++ b/src/gpu/GrProxyProvider.cpp @@ -315,37 +315,14 @@ sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrSurfaceDesc& desc, uint32_t flags) { SkASSERT(0 == flags || GrResourceProvider::kNoPendingIO_Flag == flags); - const GrCaps* caps = this->caps(); - - // TODO: move this logic into GrResourceProvider! - // TODO: share this testing code with check_texture_creation_params - if (!caps->isConfigTexturable(desc.fConfig)) { - return nullptr; - } - - bool willBeRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); - if (willBeRT && !caps->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { + if (!this->caps()->validateSurfaceDesc(desc, GrMipMapped::kNo)) { return nullptr; } - - // We currently do not support multisampled textures - if (!willBeRT && desc.fSampleCnt > 0) { - return nullptr; - } - - int maxSize; - if (willBeRT) { - maxSize = caps->maxRenderTargetSize(); - } else { - maxSize = caps->maxTextureSize(); - } - - if (desc.fWidth > maxSize || desc.fHeight > maxSize || desc.fWidth <= 0 || desc.fHeight <= 0) { - return nullptr; - } - GrSurfaceDesc copyDesc = desc; - copyDesc.fSampleCnt = caps->getSampleCount(desc.fSampleCnt, desc.fConfig); + if (desc.fFlags & kRenderTarget_GrSurfaceFlag) { + copyDesc.fSampleCnt = + this->caps()->getRenderTargetSampleCount(desc.fSampleCnt, desc.fConfig); + } #ifdef SK_DISABLE_DEFERRED_PROXIES // Temporarily force instantiation for crbug.com/769760 and crbug.com/769898 @@ -363,11 +340,11 @@ sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrSurfaceDesc& desc, return GrSurfaceProxy::MakeWrapped(std::move(tex), copyDesc.fOrigin); #else - if (willBeRT) { + if (copyDesc.fFlags & kRenderTarget_GrSurfaceFlag) { // We know anything we instantiate later from this deferred path will be // both texturable and renderable - return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(*caps, copyDesc, fit, - budgeted, flags)); + return sk_sp<GrTextureProxy>( + new GrTextureRenderTargetProxy(*this->caps(), copyDesc, fit, budgeted, flags)); } return sk_sp<GrTextureProxy>(new GrTextureProxy(copyDesc, fit, budgeted, nullptr, 0, flags)); @@ -507,7 +484,7 @@ sk_sp<GrTextureProxy> GrProxyProvider::createFullyLazyProxy(LazyInstantiateCallb desc.fWidth = -1; desc.fHeight = -1; desc.fConfig = config; - desc.fSampleCnt = 0; + desc.fSampleCnt = 1; return this->createLazyProxy(std::move(callback), desc, GrMipMapped::kNo, SkBackingFit::kApprox, SkBudgeted::kYes); diff --git a/src/gpu/GrRenderTarget.cpp b/src/gpu/GrRenderTarget.cpp index 3090219751..36fa4ddf1b 100644 --- a/src/gpu/GrRenderTarget.cpp +++ b/src/gpu/GrRenderTarget.cpp @@ -27,7 +27,7 @@ GrRenderTarget::GrRenderTarget(GrGpu* gpu, const GrSurfaceDesc& desc, , fMultisampleSpecsID(0) , fFlags(flags) { SkASSERT(desc.fFlags & kRenderTarget_GrSurfaceFlag); - SkASSERT(!(fFlags & GrRenderTargetFlags::kMixedSampled) || fSampleCnt > 0); + SkASSERT(!(fFlags & GrRenderTargetFlags::kMixedSampled) || fSampleCnt > 1); SkASSERT(!(fFlags & GrRenderTargetFlags::kWindowRectsSupport) || gpu->caps()->maxWindowRectangles() > 0); fResolveRect = SkRectPriv::MakeILargestInverted(); diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp index 9eb37a0b2f..841d4b18fd 100644 --- a/src/gpu/GrRenderTargetProxy.cpp +++ b/src/gpu/GrRenderTargetProxy.cpp @@ -26,7 +26,7 @@ GrRenderTargetProxy::GrRenderTargetProxy(const GrCaps& caps, const GrSurfaceDesc , fRenderTargetFlags(GrRenderTargetFlags::kNone) { // Since we know the newly created render target will be internal, we are able to precompute // what the flags will ultimately end up being. - if (caps.usesMixedSamples() && fSampleCnt > 0) { + if (caps.usesMixedSamples() && fSampleCnt > 1) { fRenderTargetFlags |= GrRenderTargetFlags::kMixedSampled; } if (caps.maxWindowRectangles() > 0) { @@ -97,7 +97,11 @@ sk_sp<GrSurface> GrRenderTargetProxy::createSurface(GrResourceProvider* resource } size_t GrRenderTargetProxy::onUninstantiatedGpuMemorySize() const { - int colorSamplesPerPixel = this->numColorSamples() + 1; + int colorSamplesPerPixel = this->numColorSamples(); + if (colorSamplesPerPixel > 1) { + // Add one for the resolve buffer. + ++colorSamplesPerPixel; + } // TODO: do we have enough information to improve this worst case estimate? return GrSurface::ComputeSize(this->config(), this->width(), this->height(), diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp index 3800383581..ec94968e21 100644 --- a/src/gpu/GrResourceProvider.cpp +++ b/src/gpu/GrResourceProvider.cpp @@ -46,28 +46,6 @@ GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSin fQuadIndexBufferKey = gQuadIndexBufferKey; } -bool validate_desc(const GrSurfaceDesc& desc, const GrCaps& caps, int levelCount = 0) { - if (desc.fWidth <= 0 || desc.fHeight <= 0) { - return false; - } - if (!caps.isConfigTexturable(desc.fConfig)) { - return false; - } - if (desc.fFlags & kRenderTarget_GrSurfaceFlag) { - if (!caps.isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) { - return false; - } - } else { - if (desc.fSampleCnt) { - return false; - } - } - if (levelCount > 1 && (GrPixelConfigIsSint(desc.fConfig) || !caps.mipMapSupport())) { - return false; - } - return true; -} - sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, const GrMipLevel texels[], int mipLevelCount, SkDestinationSurfaceColorMode mipColorMode) { @@ -79,7 +57,8 @@ sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, Sk return nullptr; } - if (!validate_desc(desc, *fCaps, mipLevelCount)) { + GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo; + if (!fCaps->validateSurfaceDesc(desc, mipMapped)) { return nullptr; } @@ -125,7 +104,7 @@ sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, return nullptr; } - if (!validate_desc(desc, *fCaps)) { + if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) { return nullptr; } @@ -157,12 +136,11 @@ sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, uint32_t flags) { ASSERT_SINGLE_OWNER - if (this->isAbandoned()) { return nullptr; } - if (!validate_desc(desc, *fCaps)) { + if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) { return nullptr; } @@ -183,7 +161,7 @@ sk_sp<GrTexture> GrResourceProvider::createApproxTexture(const GrSurfaceDesc& de return nullptr; } - if (!validate_desc(desc, *fCaps)) { + if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) { return nullptr; } @@ -212,7 +190,7 @@ sk_sp<GrTexture> GrResourceProvider::refScratchTexture(const GrSurfaceDesc& desc uint32_t flags) { ASSERT_SINGLE_OWNER SkASSERT(!this->isAbandoned()); - SkASSERT(validate_desc(desc, *fCaps)); + SkASSERT(fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)); // We could make initial clears work with scratch textures but it is a rare case so we just opt // to fall back to making a new texture. diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h index 0092430846..385282d6f6 100644 --- a/src/gpu/GrResourceProvider.h +++ b/src/gpu/GrResourceProvider.h @@ -89,7 +89,7 @@ public: GrWrapOwnership = kBorrow_GrWrapOwnership); /** - * This makes the backend texture be renderable. If sampleCnt is > 0 and the underlying API + * This makes the backend texture be renderable. If sampleCnt is > 1 and the underlying API * uses separate MSAA render buffers then a MSAA render buffer is created that resolves * to the texture. */ diff --git a/src/gpu/GrSurface.cpp b/src/gpu/GrSurface.cpp index ec503d7066..b35683c548 100644 --- a/src/gpu/GrSurface.cpp +++ b/src/gpu/GrSurface.cpp @@ -29,8 +29,9 @@ size_t GrSurface::WorstCaseSize(const GrSurfaceDesc& desc, bool useNextPow2) { bool isRenderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); if (isRenderTarget) { // We own one color value for each MSAA sample. - int colorValuesPerPixel = SkTMax(1, desc.fSampleCnt); - if (desc.fSampleCnt) { + SkASSERT(desc.fSampleCnt >= 1); + int colorValuesPerPixel = desc.fSampleCnt; + if (desc.fSampleCnt > 1) { // Worse case, we own the resolve buffer so that is one more sample per pixel. colorValuesPerPixel += 1; } diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp index 64c47b56b1..4020758259 100644 --- a/src/gpu/GrSurfaceProxy.cpp +++ b/src/gpu/GrSurfaceProxy.cpp @@ -26,7 +26,7 @@ static bool is_valid_fully_lazy(const GrSurfaceDesc& desc, SkBackingFit fit) { return desc.fWidth <= 0 && desc.fHeight <= 0 && desc.fConfig != kUnknown_GrPixelConfig && - desc.fSampleCnt == 0 && + desc.fSampleCnt == 1 && SkBackingFit::kApprox == fit; } @@ -190,7 +190,7 @@ bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int s void GrSurfaceProxy::computeScratchKey(GrScratchKey* key) const { SkASSERT(LazyState::kFully != this->lazyInstantiationState()); const GrRenderTargetProxy* rtp = this->asRenderTargetProxy(); - int sampleCount = 0; + int sampleCount = 1; if (rtp) { sampleCount = rtp->numStencilSamples(); } diff --git a/src/gpu/GrTexture.cpp b/src/gpu/GrTexture.cpp index b4cefb0174..dd0631775f 100644 --- a/src/gpu/GrTexture.cpp +++ b/src/gpu/GrTexture.cpp @@ -78,7 +78,7 @@ bool GrTexture::StealBackendTexture(sk_sp<GrTexture>&& texture, void GrTexture::computeScratchKey(GrScratchKey* key) const { const GrRenderTarget* rt = this->asRenderTarget(); - int sampleCount = 0; + int sampleCount = 1; if (rt) { sampleCount = rt->numStencilSamples(); } @@ -92,8 +92,10 @@ void GrTexturePriv::ComputeScratchKey(GrPixelConfig config, int width, int heigh GrMipMapped mipMapped, GrScratchKey* key) { static const GrScratchKey::ResourceType kType = GrScratchKey::GenerateResourceType(); uint32_t flags = isRenderTarget; - - SkASSERT(0 == sampleCnt || isRenderTarget); + SkASSERT(width > 0); + SkASSERT(height > 0); + SkASSERT(sampleCnt > 0); + SkASSERT(1 == sampleCnt || isRenderTarget); // make sure desc.fConfig fits in 5 bits SkASSERT(sk_float_log2(kLast_GrPixelConfig) <= 5); diff --git a/src/gpu/GrTextureProducer.cpp b/src/gpu/GrTextureProducer.cpp index 9593cb6873..9b344cb831 100644 --- a/src/gpu/GrTextureProducer.cpp +++ b/src/gpu/GrTextureProducer.cpp @@ -25,8 +25,8 @@ sk_sp<GrTextureProxy> GrTextureProducer::CopyOnGpu(GrContext* context, GrMipMapped mipMapped = dstWillRequireMipMaps ? GrMipMapped::kYes : GrMipMapped::kNo; sk_sp<GrRenderTargetContext> copyRTC = context->makeDeferredRenderTargetContextWithFallback( - SkBackingFit::kExact, dstRect.width(), dstRect.height(), inputProxy->config(), nullptr, - 0, mipMapped, inputProxy->origin()); + SkBackingFit::kExact, dstRect.width(), dstRect.height(), inputProxy->config(), nullptr, + 1, mipMapped, inputProxy->origin()); if (!copyRTC) { return nullptr; } diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp index 8e6afbf0a7..54d0769a63 100644 --- a/src/gpu/GrTextureProxy.cpp +++ b/src/gpu/GrTextureProxy.cpp @@ -64,7 +64,7 @@ bool GrTextureProxy::instantiate(GrResourceProvider* resourceProvider) { if (LazyState::kNot != this->lazyInstantiationState()) { return false; } - if (!this->instantiateImpl(resourceProvider, 0, /* needsStencil = */ false, + if (!this->instantiateImpl(resourceProvider, 1, /* needsStencil = */ false, kNone_GrSurfaceFlags, fMipMapped, fMipColorMode, fUniqueKey.isValid() ? &fUniqueKey : nullptr)) { return false; @@ -76,7 +76,7 @@ bool GrTextureProxy::instantiate(GrResourceProvider* resourceProvider) { } sk_sp<GrSurface> GrTextureProxy::createSurface(GrResourceProvider* resourceProvider) const { - sk_sp<GrSurface> surface= this->createSurfaceImpl(resourceProvider, 0, + sk_sp<GrSurface> surface= this->createSurfaceImpl(resourceProvider, 1, /* needsStencil = */ false, kNone_GrSurfaceFlags, fMipMapped, fMipColorMode); diff --git a/src/gpu/GrTextureRenderTargetProxy.cpp b/src/gpu/GrTextureRenderTargetProxy.cpp index da8e48307d..843524c062 100644 --- a/src/gpu/GrTextureRenderTargetProxy.cpp +++ b/src/gpu/GrTextureRenderTargetProxy.cpp @@ -53,7 +53,11 @@ GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(sk_sp<GrSurface> surf, } size_t GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize() const { - int colorSamplesPerPixel = this->numColorSamples() + 1; + int colorSamplesPerPixel = this->numColorSamples(); + if (colorSamplesPerPixel > 1) { + // Add one to account for the resolve buffer. + ++colorSamplesPerPixel += 1; + } // TODO: do we have enough information to improve this worst case estimate? return GrSurface::ComputeSize(this->config(), this->width(), this->height(), diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index 3d951c4673..d7ee5c2c02 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -48,7 +48,7 @@ GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo& info, const GrCaps& ca desc.fWidth = info.width(); desc.fHeight = info.height(); desc.fConfig = SkImageInfo2GrPixelConfig(info, caps); - desc.fSampleCnt = 0; + desc.fSampleCnt = 1; return desc; } @@ -170,7 +170,7 @@ sk_sp<GrTextureProxy> GrCopyBaseMipMapToTextureProxy(GrContext* ctx, GrTexturePr desc.fWidth = baseProxy->width(); desc.fHeight = baseProxy->height(); desc.fConfig = baseProxy->config(); - desc.fSampleCnt = 0; + desc.fSampleCnt = 1; sk_sp<GrTextureProxy> proxy = proxyProvider->createMipMapProxy(desc, SkBudgeted::kYes); if (!proxy) { diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp index abe888044e..da6991745f 100644 --- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp +++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp @@ -42,7 +42,7 @@ bool GrCoverageCountingPathRenderer::IsSupported(const GrCaps& caps) { return shaderCaps.integerSupport() && shaderCaps.flatInterpolationSupport() && caps.instanceAttribSupport() && GrCaps::kNone_MapFlags != caps.mapBufferFlags() && caps.isConfigTexturable(kAlpha_half_GrPixelConfig) && - caps.isConfigRenderable(kAlpha_half_GrPixelConfig, /*withMSAA=*/false) && + caps.isConfigRenderable(kAlpha_half_GrPixelConfig) && !caps.blacklistCoverageCounting(); } diff --git a/src/gpu/ddl/GrDDLGpu.h b/src/gpu/ddl/GrDDLGpu.h index 16deab0353..e1f463f073 100644 --- a/src/gpu/ddl/GrDDLGpu.h +++ b/src/gpu/ddl/GrDDLGpu.h @@ -46,7 +46,7 @@ public: void onQueryMultisampleSpecs(GrRenderTarget* rt, GrSurfaceOrigin, const GrStencilSettings&, int* effectiveSampleCnt, SamplePattern*) override { SkASSERT(0); - *effectiveSampleCnt = 0; // ?? + *effectiveSampleCnt = 1; // ?? } GrGpuRTCommandBuffer* createCommandBuffer( diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 3b90676be1..99f56564d8 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -1958,6 +1958,8 @@ void GrGLCaps::initConfigTable(const GrContextOptions& contextOptions, for (int i = 0; i < kGrPixelConfigCnt; ++i) { if (ConfigInfo::kRenderableWithMSAA_Flag & fConfigTable[i].fFlags) { + // We assume that MSAA rendering is supported only if we support non-MSAA rendering. + SkASSERT(ConfigInfo::kRenderable_Flag & fConfigTable[i].fFlags); if ((kGL_GrGLStandard == ctxInfo.standard() && (ctxInfo.version() >= GR_GL_VER(4,2) || ctxInfo.hasExtension("GL_ARB_internalformat_query"))) || @@ -1970,10 +1972,15 @@ void GrGLCaps::initConfigTable(const GrContextOptions& contextOptions, int* temp = new int[count]; GR_GL_GetInternalformativ(gli, GR_GL_RENDERBUFFER, format, GR_GL_SAMPLES, count, temp); + // GL has a concept of MSAA rasterization with a single sample but we do not. + if (count && temp[count - 1] == 1) { + --count; + SkASSERT(!count || temp[count -1] > 1); + } fConfigTable[i].fColorSampleCounts.setCount(count+1); - // We initialize our supported values with 0 (no msaa) and reverse the order + // We initialize our supported values with 1 (no msaa) and reverse the order // returned by GL so that the array is ascending. - fConfigTable[i].fColorSampleCounts[0] = 0; + fConfigTable[i].fColorSampleCounts[0] = 1; for (int j = 0; j < count; ++j) { fConfigTable[i].fColorSampleCounts[j+1] = temp[count - j - 1]; } @@ -1982,14 +1989,16 @@ void GrGLCaps::initConfigTable(const GrContextOptions& contextOptions, } else { // Fake out the table using some semi-standard counts up to the max allowed sample // count. - int maxSampleCnt = 0; + int maxSampleCnt = 1; if (GrGLCaps::kES_IMG_MsToTexture_MSFBOType == fMSFBOType) { GR_GL_GetIntegerv(gli, GR_GL_MAX_SAMPLES_IMG, &maxSampleCnt); } else if (GrGLCaps::kNone_MSFBOType != fMSFBOType) { GR_GL_GetIntegerv(gli, GR_GL_MAX_SAMPLES, &maxSampleCnt); } + // Chrome has a mock GL implementation that returns 0. + maxSampleCnt = SkTMax(1, maxSampleCnt); - static constexpr int kDefaultSamples[] = {0, 1, 2, 4, 8}; + static constexpr int kDefaultSamples[] = {1, 2, 4, 8}; int count = SK_ARRAY_COUNT(kDefaultSamples); for (; count > 0; --count) { if (kDefaultSamples[count - 1] <= maxSampleCnt) { @@ -2000,6 +2009,9 @@ void GrGLCaps::initConfigTable(const GrContextOptions& contextOptions, fConfigTable[i].fColorSampleCounts.append(count, kDefaultSamples); } } + } else if (ConfigInfo::kRenderable_Flag & fConfigTable[i].fFlags) { + fConfigTable[i].fColorSampleCounts.setCount(1); + fConfigTable[i].fColorSampleCounts[0] = 1; } } @@ -2034,7 +2046,7 @@ bool GrGLCaps::initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* // If the src is a texture, we can implement the blit as a draw assuming the config is // renderable. - if (src->asTextureProxy() && this->isConfigRenderable(src->config(), false)) { + if (src->asTextureProxy() && !this->isConfigRenderable(src->config())) { desc->fOrigin = kBottomLeft_GrSurfaceOrigin; desc->fFlags = kRenderTarget_GrSurfaceFlag; desc->fConfig = src->config(); @@ -2059,14 +2071,14 @@ bool GrGLCaps::initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* GrSurfaceOrigin originForBlitFramebuffer = kTopLeft_GrSurfaceOrigin; bool rectsMustMatchForBlitFramebuffer = false; bool disallowSubrectForBlitFramebuffer = false; - if (src->numColorSamples() && + if (src->numColorSamples() > 1 && (this->blitFramebufferSupportFlags() & kResolveMustBeFull_BlitFrambufferFlag)) { rectsMustMatchForBlitFramebuffer = true; disallowSubrectForBlitFramebuffer = true; // Mirroring causes rects to mismatch later, don't allow it. originForBlitFramebuffer = src->origin(); - } else if (src->numColorSamples() && (this->blitFramebufferSupportFlags() & - kRectsMustMatchForMSAASrc_BlitFramebufferFlag)) { + } else if (src->numColorSamples() > 1 && (this->blitFramebufferSupportFlags() & + kRectsMustMatchForMSAASrc_BlitFramebufferFlag)) { rectsMustMatchForBlitFramebuffer = true; // Mirroring causes rects to mismatch later, don't allow it. originForBlitFramebuffer = src->origin(); @@ -2456,18 +2468,31 @@ void GrGLCaps::onApplyOptionsOverrides(const GrContextOptions& options) { } } -int GrGLCaps::getSampleCount(int requestedCount, GrPixelConfig config) const { +int GrGLCaps::getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const { + requestedCount = SkTMax(1, requestedCount); int count = fConfigTable[config].fColorSampleCounts.count(); - if (!count || !this->isConfigRenderable(config, true)) { + if (!count) { return 0; } + if (1 == requestedCount) { + return fConfigTable[config].fColorSampleCounts[0] == 1 ? 1 : 0; + } + for (int i = 0; i < count; ++i) { if (fConfigTable[config].fColorSampleCounts[i] >= requestedCount) { return fConfigTable[config].fColorSampleCounts[i]; } } - return fConfigTable[config].fColorSampleCounts[count-1]; + return 0; +} + +int GrGLCaps::maxRenderTargetSampleCount(GrPixelConfig config) const { + const auto& table = fConfigTable[config].fColorSampleCounts; + if (!table.count()) { + return 0; + } + return table[table.count() - 1]; } bool validate_sized_format(GrGLenum format, SkColorType ct, GrPixelConfig* config, diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index fd49a65598..7a443e49b0 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -112,19 +112,12 @@ public: GrGLCaps(const GrContextOptions& contextOptions, const GrGLContextInfo& ctxInfo, const GrGLInterface* glInterface); - int getSampleCount(int requestedCount, GrPixelConfig config) const override; - bool isConfigTexturable(GrPixelConfig config) const override { return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kTextureable_Flag); } - bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override { - if (withMSAA) { - return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderableWithMSAA_Flag); - } else { - return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag); - } - } + int getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const override; + int maxRenderTargetSampleCount(GrPixelConfig config) const override; bool isConfigCopyable(GrPixelConfig config) const override { // In GL we have three ways to be able to copy. CopyTexImage, blit, and draw. CopyTexImage diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index ae31495b06..b4a0341174 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -545,7 +545,7 @@ sk_sp<GrTexture> GrGLGpu::onWrapBackendTexture(const GrBackendTexture& backendTe surfDesc.fWidth = backendTex.width(); surfDesc.fHeight = backendTex.height(); surfDesc.fConfig = backendTex.config(); - surfDesc.fSampleCnt = 0; + surfDesc.fSampleCnt = 1; GrMipMapsStatus mipMapsStatus = backendTex.hasMipMaps() ? GrMipMapsStatus::kValid : GrMipMapsStatus::kNotAllocated; @@ -581,7 +581,10 @@ sk_sp<GrTexture> GrGLGpu::onWrapRenderableBackendTexture(const GrBackendTexture& surfDesc.fWidth = backendTex.width(); surfDesc.fHeight = backendTex.height(); surfDesc.fConfig = backendTex.config(); - surfDesc.fSampleCnt = this->caps()->getSampleCount(sampleCnt, backendTex.config()); + surfDesc.fSampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config()); + if (surfDesc.fSampleCnt < 1) { + return nullptr; + } GrGLRenderTarget::IDDesc rtIDDesc; if (!this->createRenderTargetObjects(surfDesc, idDesc.fInfo, &rtIDDesc)) { @@ -616,7 +619,8 @@ sk_sp<GrRenderTarget> GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTa desc.fWidth = backendRT.width(); desc.fHeight = backendRT.height(); desc.fConfig = backendRT.config(); - desc.fSampleCnt = this->caps()->getSampleCount(backendRT.sampleCnt(), backendRT.config()); + desc.fSampleCnt = + this->caps()->getRenderTargetSampleCount(backendRT.sampleCnt(), backendRT.config()); return GrGLRenderTarget::MakeWrapped(this, desc, idDesc, backendRT.stencilBits()); } @@ -645,7 +649,7 @@ sk_sp<GrRenderTarget> GrGLGpu::onWrapBackendTextureAsRenderTarget(const GrBacken surfDesc.fWidth = tex.width(); surfDesc.fHeight = tex.height(); surfDesc.fConfig = tex.config(); - surfDesc.fSampleCnt = this->caps()->getSampleCount(sampleCnt, tex.config()); + surfDesc.fSampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, tex.config()); GrGLRenderTarget::IDDesc rtIDDesc; if (!this->createRenderTargetObjects(surfDesc, texInfo, &rtIDDesc)) { @@ -686,7 +690,7 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOri } // If the dst is MSAA, we have to draw, or we'll just be writing to the resolve target. - if (dstSurface->asRenderTarget() && dstSurface->asRenderTarget()->numColorSamples() > 0) { + if (dstSurface->asRenderTarget() && dstSurface->asRenderTarget()->numColorSamples() > 1) { ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); } @@ -704,7 +708,7 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOri tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig; tempDrawInfo->fTempSurfaceDesc.fWidth = width; tempDrawInfo->fTempSurfaceDesc.fHeight = height; - tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 0; + tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 1; tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin; // no CPU y-flip for TL. bool configsAreRBSwaps = GrPixelConfigSwapRAndB(srcConfig) == dstSurface->config(); @@ -1277,13 +1281,13 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, idDesc->fTexFBOID = 0; SkASSERT((GrGLCaps::kMixedSamples_MSFBOType == this->glCaps().msFBOType()) == this->caps()->usesMixedSamples()); - idDesc->fIsMixedSampled = desc.fSampleCnt > 0 && this->caps()->usesMixedSamples(); + idDesc->fIsMixedSampled = desc.fSampleCnt > 1 && this->caps()->usesMixedSamples(); GrGLenum status; GrGLenum colorRenderbufferFormat = 0; // suppress warning - if (desc.fSampleCnt > 0 && GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) { + if (desc.fSampleCnt > 1 && GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) { goto FAILED; } @@ -1296,7 +1300,7 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, // the texture bound to the other. The exception is the IMG multisample extension. With this // extension the texture is multisampled when rendered to and then auto-resolves it when it is // rendered from. - if (desc.fSampleCnt > 0 && this->glCaps().usesMSAARenderBuffers()) { + if (desc.fSampleCnt > 1 && this->glCaps().usesMSAARenderBuffers()) { GL_CALL(GenFramebuffers(1, &idDesc->fRTFBOID)); GL_CALL(GenRenderbuffers(1, &idDesc->fMSColorRenderbufferID)); if (!idDesc->fRTFBOID || @@ -1313,7 +1317,7 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, // below here we may bind the FBO fHWBoundRenderTargetUniqueID.makeInvalid(); if (idDesc->fRTFBOID != idDesc->fTexFBOID) { - SkASSERT(desc.fSampleCnt > 0); + SkASSERT(desc.fSampleCnt > 1); GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, idDesc->fMSColorRenderbufferID)); if (!renderbuffer_storage_msaa(*fGLContext, desc.fSampleCnt, @@ -1338,7 +1342,7 @@ bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc, fStats.incRenderTargetBinds(); GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, idDesc->fTexFBOID)); - if (this->glCaps().usesImplicitMSAAResolve() && desc.fSampleCnt > 0) { + if (this->glCaps().usesImplicitMSAAResolve() && desc.fSampleCnt > 1) { GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, texInfo.fTarget, @@ -1415,7 +1419,7 @@ sk_sp<GrTexture> GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc, const GrMipLevel texels[], int mipLevelCount) { // We fail if the MSAA was requested and is not available. - if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType() && desc.fSampleCnt) { + if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType() && desc.fSampleCnt > 1) { //SkDebugf("MSAA RT requested but not supported on this platform."); return return_null_texture(); } @@ -1524,7 +1528,7 @@ void inline get_stencil_rb_sizes(const GrGLInterface* gl, int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) { static const int kSize = 16; - SkASSERT(this->caps()->isConfigRenderable(config, false)); + SkASSERT(this->caps()->isConfigRenderable(config)); if (!this->glCaps().hasStencilFormatBeenDeterminedForConfig(config)) { // Default to unsupported, set this if we find a stencil format that works. int firstWorkingStencilFormatIndex = -1; @@ -1694,7 +1698,7 @@ GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(const GrRen CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); // we do this "if" so that we don't call the multisample // version on a GL that doesn't have an MSAA extension. - if (samples > 0) { + if (samples > 1) { SkAssertResult(renderbuffer_storage_msaa(*fGLContext, samples, sFmt.fInternalFormat, @@ -2133,7 +2137,7 @@ bool GrGLGpu::readPixelsSupported(GrPixelConfig rtConfig, GrPixelConfig readConf GrSurfaceDesc desc; desc.fConfig = rtConfig; desc.fWidth = desc.fHeight = 16; - if (this->glCaps().isConfigRenderable(rtConfig, false)) { + if (this->glCaps().isConfigRenderable(rtConfig)) { desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fOrigin = kBottomLeft_GrSurfaceOrigin; temp = this->createTexture(desc, SkBudgeted::kNo); @@ -2194,7 +2198,7 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrig tempDrawInfo->fTempSurfaceDesc.fFlags = kRenderTarget_GrSurfaceFlag; tempDrawInfo->fTempSurfaceDesc.fWidth = width; tempDrawInfo->fTempSurfaceDesc.fHeight = height; - tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 0; + tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 1; tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin; // no CPU y-flip for TL. tempDrawInfo->fTempSurfaceFit = this->glCaps().partialFBOReadIsSlow() ? SkBackingFit::kExact : SkBackingFit::kApprox; @@ -2872,10 +2876,13 @@ void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA, bool stencilEnabl GL_CALL(Enable(GR_GL_RASTER_MULTISAMPLE)); fHWRasterMultisampleEnabled = kYes_TriState; } - if (rt->numStencilSamples() != fHWNumRasterSamples) { - SkASSERT(rt->numStencilSamples() <= this->caps()->maxRasterSamples()); - GL_CALL(RasterSamples(rt->numStencilSamples(), GR_GL_TRUE)); - fHWNumRasterSamples = rt->numStencilSamples(); + int numStencilSamples = rt->numStencilSamples(); + // convert to GL's understanding of sample counts where 0 means nonMSAA. + numStencilSamples = 1 == numStencilSamples ? 0 : numStencilSamples; + if (numStencilSamples != fHWNumRasterSamples) { + SkASSERT(numStencilSamples <= this->caps()->maxRasterSamples()); + GL_CALL(RasterSamples(numStencilSamples, GR_GL_TRUE)); + fHWNumRasterSamples = numStencilSamples; } } else { if (kNo_TriState != fHWRasterMultisampleEnabled) { @@ -3334,8 +3341,8 @@ static inline bool can_blit_framebuffer_for_copy_surface( } } if (GrGLCaps::kResolveMustBeFull_BlitFrambufferFlag & blitFramebufferFlags) { - if (srcRT && srcRT->numColorSamples()) { - if (dstRT && !dstRT->numColorSamples()) { + if (srcRT && srcRT->numColorSamples() > 1) { + if (dstRT && 1 == dstRT->numColorSamples()) { return false; } if (SkRect::Make(srcRect) != srcRT->getBoundsRect()) { @@ -3344,7 +3351,7 @@ static inline bool can_blit_framebuffer_for_copy_surface( } } if (GrGLCaps::kNoMSAADst_BlitFramebufferFlag & blitFramebufferFlags) { - if (dstRT && dstRT->numColorSamples() > 0) { + if (dstRT && dstRT->numColorSamples() > 1) { return false; } } @@ -3354,12 +3361,12 @@ static inline bool can_blit_framebuffer_for_copy_surface( } } else if (GrGLCaps::kNoFormatConversionForMSAASrc_BlitFramebufferFlag & blitFramebufferFlags) { const GrRenderTarget* srcRT = src->asRenderTarget(); - if (srcRT && srcRT->numColorSamples() && dst->config() != src->config()) { + if (srcRT && srcRT->numColorSamples() > 1 && dst->config() != src->config()) { return false; } } if (GrGLCaps::kRectsMustMatchForMSAASrc_BlitFramebufferFlag & blitFramebufferFlags) { - if (srcRT && srcRT->numColorSamples()) { + if (srcRT && srcRT->numColorSamples() > 1) { if (dstPoint.fX != srcRect.fLeft || dstPoint.fY != srcRect.fTop) { return false; } @@ -3376,7 +3383,7 @@ static bool rt_has_msaa_render_buffer(const GrGLRenderTarget* rt, const GrGLCaps // 1) It's multisampled // 2) We're using an extension with separate MSAA renderbuffers // 3) It's not FBO 0, which is special and always auto-resolves - return rt->numColorSamples() > 0 && glCaps.usesMSAARenderBuffers() && rt->renderFBOID() != 0; + return rt->numColorSamples() > 1 && glCaps.usesMSAARenderBuffers() && rt->renderFBOID() != 0; } static inline bool can_copy_texsubimage(const GrSurface* dst, GrSurfaceOrigin dstOrigin, diff --git a/src/gpu/gl/GrGLRenderTarget.cpp b/src/gpu/gl/GrGLRenderTarget.cpp index 443128d4d4..6f3714c504 100644 --- a/src/gpu/gl/GrGLRenderTarget.cpp +++ b/src/gpu/gl/GrGLRenderTarget.cpp @@ -224,7 +224,7 @@ int GrGLRenderTarget::msaaSamples() const { if (fTexFBOID == kUnresolvableFBOID || fTexFBOID != fRTFBOID) { // If the render target's FBO is external (fTexFBOID == kUnresolvableFBOID), or if we own // the render target's FBO (fTexFBOID == fRTFBOID) then we use the provided sample count. - return SkTMax(1, this->numStencilSamples()); + return this->numStencilSamples(); } // When fTexFBOID == fRTFBOID, we either are not using MSAA, or MSAA is auto resolving, so use diff --git a/src/gpu/gl/GrGLStencilAttachment.cpp b/src/gpu/gl/GrGLStencilAttachment.cpp index aa813ed50e..5c07a7d383 100644 --- a/src/gpu/gl/GrGLStencilAttachment.cpp +++ b/src/gpu/gl/GrGLStencilAttachment.cpp @@ -14,7 +14,7 @@ size_t GrGLStencilAttachment::onGpuMemorySize() const { uint64_t size = this->width(); size *= this->height(); size *= fFormat.fTotalBits; - size *= SkTMax(1,this->numSamples()); + size *= this->numSamples(); return static_cast<size_t>(size / 8); } diff --git a/src/gpu/mock/GrMockCaps.h b/src/gpu/mock/GrMockCaps.h index edec5563c4..1e448516d7 100644 --- a/src/gpu/mock/GrMockCaps.h +++ b/src/gpu/mock/GrMockCaps.h @@ -33,19 +33,39 @@ public: this->applyOptionsOverrides(contextOptions); } - int getSampleCount(int /*requestCount*/, GrPixelConfig /*config*/) const override { - return 0; - } bool isConfigTexturable(GrPixelConfig config) const override { return fOptions.fConfigOptions[config].fTexturable; } - bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override { - return fOptions.fConfigOptions[config].fRenderable[withMSAA]; - } + bool isConfigCopyable(GrPixelConfig config) const override { return false; } + int getRenderTargetSampleCount(int requestCount, GrPixelConfig config) const override { + requestCount = SkTMax(requestCount, 1); + switch (fOptions.fConfigOptions[config].fRenderability) { + case GrMockOptions::ConfigOptions::Renderability::kNo: + return 0; + case GrMockOptions::ConfigOptions::Renderability::kNonMSAA: + return requestCount > 1 ? 0 : 1; + case GrMockOptions::ConfigOptions::Renderability::kMSAA: + return requestCount > kMaxSampleCnt ? 0 : GrNextPow2(requestCount); + } + return 0; + } + + int maxRenderTargetSampleCount(GrPixelConfig config) const override { + switch (fOptions.fConfigOptions[config].fRenderability) { + case GrMockOptions::ConfigOptions::Renderability::kNo: + return 0; + case GrMockOptions::ConfigOptions::Renderability::kNonMSAA: + return 1; + case GrMockOptions::ConfigOptions::Renderability::kMSAA: + return kMaxSampleCnt; + } + return 0; + } + bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc, bool* rectsMustMatch, bool* disallowSubrect) const override { return false; @@ -62,6 +82,8 @@ public: } private: + static const int kMaxSampleCnt = 16; + GrMockOptions fOptions; typedef GrCaps INHERITED; }; diff --git a/src/gpu/mock/GrMockTexture.h b/src/gpu/mock/GrMockTexture.h index 9b6501a3c4..b5cc4a27c0 100644 --- a/src/gpu/mock/GrMockTexture.h +++ b/src/gpu/mock/GrMockTexture.h @@ -90,8 +90,11 @@ private: } size_t onGpuMemorySize() const override { - // The plus 1 is to account for the resolve texture. - int numColorSamples = this->numColorSamples() + 1; + int numColorSamples = this->numColorSamples(); + if (numColorSamples > 1) { + // Add one to account for the resolve buffer. + ++numColorSamples; + } return GrSurface::ComputeSize(this->config(), this->width(), this->height(), numColorSamples, this->texturePriv().mipMapped()); diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h index 6204eaac5a..935cb07822 100644 --- a/src/gpu/mtl/GrMtlCaps.h +++ b/src/gpu/mtl/GrMtlCaps.h @@ -24,20 +24,12 @@ public: GrMtlCaps(const GrContextOptions& contextOptions, id<MTLDevice> device, MTLFeatureSet featureSet); - int getSampleCount(int requestedCount, GrPixelConfig config) const override; - bool isConfigTexturable(GrPixelConfig config) const override { return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kTextureable_Flag); } - bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override { - if (withMSAA) { - return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag) && - SkToBool(fConfigTable[config].fFlags & ConfigInfo::kMSAA_Flag); - } else { - return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag); - } - } + int getRenderTargetSampleCount(int requestedCount, GrPixelConfig) const override; + int maxRenderTargetSampleCount(GrPixelConfig) const override; bool isConfigCopyable(GrPixelConfig config) const override { return true; diff --git a/src/gpu/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm index 2bce74a261..0bb7530fe2 100644 --- a/src/gpu/mtl/GrMtlCaps.mm +++ b/src/gpu/mtl/GrMtlCaps.mm @@ -121,7 +121,7 @@ void GrMtlCaps::initGrCaps(const id<MTLDevice> device) { fMaxTextureSize = fMaxRenderTargetSize; // Init sample counts. All devices support 1 (i.e. 0 in skia). - fSampleCounts.push(0); + fSampleCounts.push(1); for (auto sampleCnt : {2, 4, 8}) { if ([device supportsTextureSampleCount:sampleCnt]) { fSampleCounts.push(sampleCnt); @@ -164,19 +164,29 @@ void GrMtlCaps::initGrCaps(const id<MTLDevice> device) { fCrossContextTextureSupport = false; } -int GrMtlCaps::getSampleCount(int requestedCount, GrPixelConfig config) const { - int count = fSampleCounts.count(); - SkASSERT(count > 0); // We always add 0 as a valid sample count - if (!this->isConfigRenderable(config, true)) { - return 0; + +int GrMtlCaps::maxRenderTargetSampleCount(GrPixelConfig config) const { + if (fConfigTable[config].fFlags & ConfigInfo::kMSAA_Flag) { + return fSampleCounts[fSampleCounts.count() - 1]; + } else if (fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag) { + return 1; } + return 0; +} - for (int i = 0; i < count; ++i) { - if (fSampleCounts[i] >= requestedCount) { - return fSampleCounts[i]; +int GrMtlCaps::getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const { + requestedCount = SkTMax(requestedCount, 1); + if (fConfigTable[config].fFlags & ConfigInfo::kMSAA_Flag) { + int count = fSampleCounts.count(); + for (int i = 0; i < count; ++i) { + if (fSampleCounts[i] >= requestedCount) { + return fSampleCounts[i]; + } } + } else if (fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag) { + return 1 == requestedCount ? 1 : 0; } - return fSampleCounts[count-1]; + return 0; } void GrMtlCaps::initShaderCaps() { diff --git a/src/gpu/mtl/GrMtlRenderTarget.h b/src/gpu/mtl/GrMtlRenderTarget.h index 4dac306e7e..83e7d3c240 100644 --- a/src/gpu/mtl/GrMtlRenderTarget.h +++ b/src/gpu/mtl/GrMtlRenderTarget.h @@ -63,8 +63,11 @@ protected: // This accounts for the texture's memory and any MSAA renderbuffer's memory. size_t onGpuMemorySize() const override { + int numColorSamples = this->numColorSamples(); // The plus 1 is to account for the resolve texture or if not using msaa the RT itself - int numColorSamples = this->numColorSamples() + 1; + if (numColorSamples > 1) { + ++numColorSamples; + } return GrSurface::ComputeSize(this->config(), this->width(), this->height(), numColorSamples, GrMipMapped::kNo); } diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp index 0ae7c00995..8af81190af 100644 --- a/src/gpu/vk/GrVkCaps.cpp +++ b/src/gpu/vk/GrVkCaps.cpp @@ -346,7 +346,7 @@ void GrVkCaps::ConfigInfo::initSampleCounts(const GrVkInterface* interface, &properties)); VkSampleCountFlags flags = properties.sampleCounts; if (flags & VK_SAMPLE_COUNT_1_BIT) { - fColorSampleCounts.push(0); + fColorSampleCounts.push(1); } if (kImagination_VkVendor == physProps.vendorID) { // MSAA does not work on imagination @@ -386,18 +386,34 @@ void GrVkCaps::ConfigInfo::init(const GrVkInterface* interface, } } -int GrVkCaps::getSampleCount(int requestedCount, GrPixelConfig config) const { +int GrVkCaps::getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const { + requestedCount = SkTMax(1, requestedCount); int count = fConfigTable[config].fColorSampleCounts.count(); - if (!count || !this->isConfigRenderable(config, true)) { + + if (!count) { return 0; } + if (1 == requestedCount) { + SkASSERT(fConfigTable[config].fColorSampleCounts.count() && + fConfigTable[config].fColorSampleCounts[0] == 1); + return 1; + } + for (int i = 0; i < count; ++i) { if (fConfigTable[config].fColorSampleCounts[i] >= requestedCount) { return fConfigTable[config].fColorSampleCounts[i]; } } - return fConfigTable[config].fColorSampleCounts[count-1]; + return 0; +} + +int GrVkCaps::maxRenderTargetSampleCount(GrPixelConfig config) const { + const auto& table = fConfigTable[config].fColorSampleCounts; + if (!table.count()) { + return 0; + } + return table[table.count() - 1]; } bool validate_image_info(const GrVkImageInfo* imageInfo, SkColorType ct, GrPixelConfig* config) { diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h index d63c2ba9b5..3449dd2ccc 100644 --- a/src/gpu/vk/GrVkCaps.h +++ b/src/gpu/vk/GrVkCaps.h @@ -29,20 +29,17 @@ public: GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface, VkPhysicalDevice device, uint32_t featureFlags, uint32_t extensionFlags); - int getSampleCount(int requestedCount, GrPixelConfig config) const override; - bool isConfigTexturable(GrPixelConfig config) const override { return SkToBool(ConfigInfo::kTextureable_Flag & fConfigTable[config].fOptimalFlags); } - bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override { - return SkToBool(ConfigInfo::kRenderable_Flag & fConfigTable[config].fOptimalFlags); - } - bool isConfigCopyable(GrPixelConfig config) const override { return true; } + int getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const override; + int maxRenderTargetSampleCount(GrPixelConfig config) const override; + bool isConfigTexturableLinearly(GrPixelConfig config) const { return SkToBool(ConfigInfo::kTextureable_Flag & fConfigTable[config].fLinearFlags); } diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp index f7e3d47dd9..362ac1fa2b 100644 --- a/src/gpu/vk/GrVkGpu.cpp +++ b/src/gpu/vk/GrVkGpu.cpp @@ -352,7 +352,7 @@ bool GrVkGpu::onGetWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOri tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig; tempDrawInfo->fTempSurfaceDesc.fWidth = width; tempDrawInfo->fTempSurfaceDesc.fHeight = height; - tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 0; + tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 1; tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin; if (dstSurface->config() == srcConfig) { @@ -777,17 +777,7 @@ sk_sp<GrTexture> GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); VkFormat pixelFormat; - if (!GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat)) { - return nullptr; - } - - if (!fVkCaps->isConfigTexturable(desc.fConfig)) { - return nullptr; - } - - if (renderTarget && !fVkCaps->isConfigRenderable(desc.fConfig, false)) { - return nullptr; - } + SkAssertResult(GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat)); VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT; if (renderTarget) { @@ -914,7 +904,7 @@ sk_sp<GrTexture> GrVkGpu::onWrapBackendTexture(const GrBackendTexture& backendTe surfDesc.fWidth = backendTex.width(); surfDesc.fHeight = backendTex.height(); surfDesc.fConfig = backendTex.config(); - surfDesc.fSampleCnt = 0; + surfDesc.fSampleCnt = 1; return GrVkTexture::MakeWrappedTexture(this, surfDesc, ownership, backendTex.getVkImageInfo()); } @@ -932,7 +922,7 @@ sk_sp<GrTexture> GrVkGpu::onWrapRenderableBackendTexture(const GrBackendTexture& surfDesc.fWidth = backendTex.width(); surfDesc.fHeight = backendTex.height(); surfDesc.fConfig = backendTex.config(); - surfDesc.fSampleCnt = this->caps()->getSampleCount(sampleCnt, backendTex.config()); + surfDesc.fSampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config()); return GrVkTextureRenderTarget::MakeWrappedTextureRenderTarget(this, surfDesc, ownership, backendTex.getVkImageInfo()); @@ -943,7 +933,7 @@ sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTa // general this is not an issue since swapchain images in vulkan are never multisampled. Thus if // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle // creating and owning the MSAA images. - if (backendRT.sampleCnt()) { + if (backendRT.sampleCnt() > 1) { return nullptr; } @@ -961,7 +951,7 @@ sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTa desc.fWidth = backendRT.width(); desc.fHeight = backendRT.height(); desc.fConfig = backendRT.config(); - desc.fSampleCnt = 0; + desc.fSampleCnt = 1; sk_sp<GrVkRenderTarget> tgt = GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, info); if (tgt && backendRT.stencilBits()) { @@ -989,7 +979,10 @@ sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendTextureAsRenderTarget(const GrBacken desc.fWidth = tex.width(); desc.fHeight = tex.height(); desc.fConfig = tex.config(); - desc.fSampleCnt = this->caps()->getSampleCount(sampleCnt, tex.config()); + desc.fSampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, tex.config()); + if (!desc.fSampleCnt) { + return nullptr; + } sk_sp<GrVkRenderTarget> tgt = GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, info); return tgt; @@ -1188,7 +1181,7 @@ GrBackendTexture GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w, return GrBackendTexture(); // invalid } - if (isRenderTarget && !fVkCaps->isConfigRenderable(config, false)) { + if (isRenderTarget && !fVkCaps->isConfigRenderable(config)) { return GrBackendTexture(); // invalid } @@ -1796,7 +1789,7 @@ inline bool can_copy_as_resolve(const GrSurface* dst, GrSurfaceOrigin dstOrigin, const GrSurface* src, GrSurfaceOrigin srcOrigin, const GrVkGpu* gpu) { // Our src must be a multisampled render target - if (!src->asRenderTarget() || src->asRenderTarget()->numColorSamples() <= 1) { + if (!src->asRenderTarget() || 1 == src->asRenderTarget()->numColorSamples()) { return false; } @@ -1894,7 +1887,7 @@ bool GrVkGpu::onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrig tempDrawInfo->fTempSurfaceDesc.fFlags = kRenderTarget_GrSurfaceFlag; tempDrawInfo->fTempSurfaceDesc.fWidth = width; tempDrawInfo->fTempSurfaceDesc.fHeight = height; - tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 0; + tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 1; tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin; // no CPU y-flip for TL. tempDrawInfo->fTempSurfaceFit = SkBackingFit::kApprox; diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp index c5a8628cc4..2a745ed51c 100644 --- a/src/gpu/vk/GrVkRenderTarget.cpp +++ b/src/gpu/vk/GrVkRenderTarget.cpp @@ -39,7 +39,7 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, , fResolveAttachmentView(resolveAttachmentView) , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { - SkASSERT(desc.fSampleCnt); + SkASSERT(desc.fSampleCnt > 1); this->createFramebuffer(gpu); this->registerWithCache(budgeted); } @@ -62,7 +62,7 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, , fResolveAttachmentView(resolveAttachmentView) , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { - SkASSERT(desc.fSampleCnt); + SkASSERT(desc.fSampleCnt > 1); this->createFramebuffer(gpu); } @@ -82,7 +82,7 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, , fResolveAttachmentView(nullptr) , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { - SkASSERT(!desc.fSampleCnt); + SkASSERT(1 == desc.fSampleCnt); this->createFramebuffer(gpu); this->registerWithCache(budgeted); } @@ -102,7 +102,7 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, , fResolveAttachmentView(nullptr) , fFramebuffer(nullptr) , fCachedSimpleRenderPass(nullptr) { - SkASSERT(!desc.fSampleCnt); + SkASSERT(1 == desc.fSampleCnt); this->createFramebuffer(gpu); } @@ -121,7 +121,7 @@ GrVkRenderTarget::Create(GrVkGpu* gpu, // create msaa surface if necessary GrVkImageInfo msInfo; const GrVkImageView* resolveAttachmentView = nullptr; - if (desc.fSampleCnt) { + if (desc.fSampleCnt > 1) { GrVkImage::ImageDesc msImageDesc; msImageDesc.fImageType = VK_IMAGE_TYPE_2D; msImageDesc.fFormat = pixelFormat; @@ -158,7 +158,7 @@ GrVkRenderTarget::Create(GrVkGpu* gpu, const GrVkImageView* colorAttachmentView = GrVkImageView::Create(gpu, colorImage, pixelFormat, GrVkImageView::kColor_Type, 1); if (!colorAttachmentView) { - if (desc.fSampleCnt) { + if (desc.fSampleCnt > 1) { resolveAttachmentView->unref(gpu); GrVkImage::DestroyImageInfo(gpu, &msInfo); } @@ -166,7 +166,7 @@ GrVkRenderTarget::Create(GrVkGpu* gpu, } GrVkRenderTarget* texRT; - if (desc.fSampleCnt) { + if (desc.fSampleCnt > 1) { texRT = new GrVkRenderTarget(gpu, budgeted, desc, info, msInfo, colorAttachmentView, resolveAttachmentView, ownership); } else { @@ -237,11 +237,10 @@ void GrVkRenderTarget::createFramebuffer(GrVkGpu* gpu) { void GrVkRenderTarget::getAttachmentsDescriptor( GrVkRenderPass::AttachmentsDescriptor* desc, GrVkRenderPass::AttachmentFlags* attachmentFlags) const { - int colorSamples = this->numColorSamples(); VkFormat colorFormat; GrPixelConfigToVkFormat(this->config(), &colorFormat); desc->fColor.fFormat = colorFormat; - desc->fColor.fSamples = colorSamples ? colorSamples : 1; + desc->fColor.fSamples = this->numColorSamples(); *attachmentFlags = GrVkRenderPass::kColor_AttachmentFlag; uint32_t attachmentCount = 1; @@ -249,7 +248,7 @@ void GrVkRenderTarget::getAttachmentsDescriptor( if (stencil) { const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil); desc->fStencil.fFormat = vkStencil->vkFormat(); - desc->fStencil.fSamples = vkStencil->numSamples() ? vkStencil->numSamples() : 1; + desc->fStencil.fSamples = vkStencil->numSamples(); // Currently in vulkan stencil and color attachments must all have same number of samples SkASSERT(desc->fColor.fSamples == desc->fStencil.fSamples); *attachmentFlags |= GrVkRenderPass::kStencil_AttachmentFlag; diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h index eb297a8a1d..02d4add455 100644 --- a/src/gpu/vk/GrVkRenderTarget.h +++ b/src/gpu/vk/GrVkRenderTarget.h @@ -99,8 +99,11 @@ protected: // This accounts for the texture's memory and any MSAA renderbuffer's memory. size_t onGpuMemorySize() const override { - // The plus 1 is to account for the resolve texture or if not using msaa the RT itself - int numColorSamples = this->numColorSamples() + 1; + int numColorSamples = this->numColorSamples(); + if (numColorSamples > 1) { + // Add one to account for the resolved VkImage. + numColorSamples += 1; + } return GrSurface::ComputeSize(this->config(), this->width(), this->height(), numColorSamples, GrMipMapped::kNo); } diff --git a/src/gpu/vk/GrVkStencilAttachment.cpp b/src/gpu/vk/GrVkStencilAttachment.cpp index 5348885a6b..139c00f3b2 100644 --- a/src/gpu/vk/GrVkStencilAttachment.cpp +++ b/src/gpu/vk/GrVkStencilAttachment.cpp @@ -72,7 +72,7 @@ size_t GrVkStencilAttachment::onGpuMemorySize() const { uint64_t size = this->width(); size *= this->height(); size *= fFormat.fTotalBits; - size *= SkTMax(1,this->numSamples()); + size *= this->numSamples(); return static_cast<size_t>(size / 8); } diff --git a/src/gpu/vk/GrVkTextureRenderTarget.cpp b/src/gpu/vk/GrVkTextureRenderTarget.cpp index 9a211e208a..ee31f2364a 100644 --- a/src/gpu/vk/GrVkTextureRenderTarget.cpp +++ b/src/gpu/vk/GrVkTextureRenderTarget.cpp @@ -106,7 +106,7 @@ sk_sp<GrVkTextureRenderTarget> GrVkTextureRenderTarget::Make(GrVkGpu* gpu, // create msaa surface if necessary GrVkImageInfo msInfo; const GrVkImageView* resolveAttachmentView = nullptr; - if (desc.fSampleCnt) { + if (desc.fSampleCnt > 1) { GrVkImage::ImageDesc msImageDesc; msImageDesc.fImageType = VK_IMAGE_TYPE_2D; msImageDesc.fFormat = pixelFormat; @@ -145,7 +145,7 @@ sk_sp<GrVkTextureRenderTarget> GrVkTextureRenderTarget::Make(GrVkGpu* gpu, const GrVkImageView* colorAttachmentView = GrVkImageView::Create(gpu, colorImage, pixelFormat, GrVkImageView::kColor_Type, 1); if (!colorAttachmentView) { - if (desc.fSampleCnt) { + if (desc.fSampleCnt > 1) { resolveAttachmentView->unref(gpu); GrVkImage::DestroyImageInfo(gpu, &msInfo); } @@ -154,7 +154,7 @@ sk_sp<GrVkTextureRenderTarget> GrVkTextureRenderTarget::Make(GrVkGpu* gpu, } sk_sp<GrVkTextureRenderTarget> texRT; - if (desc.fSampleCnt) { + if (desc.fSampleCnt > 1) { if (!isWrapped) { texRT = sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget( gpu, budgeted, desc, @@ -232,7 +232,7 @@ GrVkTextureRenderTarget::MakeWrappedTextureRenderTarget(GrVkGpu* gpu, bool GrVkTextureRenderTarget::updateForMipmap(GrVkGpu* gpu, const GrVkImageInfo& newInfo) { VkFormat pixelFormat; GrPixelConfigToVkFormat(this->config(), &pixelFormat); - if (this->numStencilSamples()) { + if (this->numStencilSamples() > 1) { const GrVkImageView* resolveAttachmentView = GrVkImageView::Create(gpu, newInfo.fImage, @@ -262,8 +262,11 @@ bool GrVkTextureRenderTarget::updateForMipmap(GrVkGpu* gpu, const GrVkImageInfo& } size_t GrVkTextureRenderTarget::onGpuMemorySize() const { - // The plus 1 is to account for the resolve texture. - int numColorSamples = this->numColorSamples() + 1; + int numColorSamples = this->numColorSamples(); + if (numColorSamples > 1) { + // Add one to account for the resolve VkImage. + ++numColorSamples; + } return GrSurface::ComputeSize(this->config(), this->width(), this->height(), numColorSamples, // TODO: this still correct? this->texturePriv().mipMapped()); diff --git a/src/gpu/vk/GrVkUtil.cpp b/src/gpu/vk/GrVkUtil.cpp index cb0046e58c..12db4c111e 100644 --- a/src/gpu/vk/GrVkUtil.cpp +++ b/src/gpu/vk/GrVkUtil.cpp @@ -263,8 +263,8 @@ bool GrVkFormatIsSRGB(VkFormat format, VkFormat* linearFormat) { } bool GrSampleCountToVkSampleCount(uint32_t samples, VkSampleCountFlagBits* vkSamples) { + SkASSERT(samples >= 1); switch (samples) { - case 0: // fall through case 1: *vkSamples = VK_SAMPLE_COUNT_1_BIT; return true; diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp index c00c50d000..a136c7b49c 100644 --- a/src/image/SkImage_Gpu.cpp +++ b/src/image/SkImage_Gpu.cpp @@ -438,13 +438,8 @@ static sk_sp<SkImage> make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpac // Needs to be a render target in order to draw to it for the yuv->rgb conversion. sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeDeferredRenderTargetContext( - SkBackingFit::kExact, - width, height, - kRGBA_8888_GrPixelConfig, - std::move(imageColorSpace), - 0, - GrMipMapped::kNo, - origin)); + SkBackingFit::kExact, width, height, kRGBA_8888_GrPixelConfig, + std::move(imageColorSpace), 1, GrMipMapped::kNo, origin)); if (!renderTargetContext) { return nullptr; } diff --git a/src/image/SkImage_Lazy.cpp b/src/image/SkImage_Lazy.cpp index ed4683542f..92d3a2fed9 100644 --- a/src/image/SkImage_Lazy.cpp +++ b/src/image/SkImage_Lazy.cpp @@ -267,9 +267,8 @@ struct CacheCaps { #if SK_SUPPORT_GPU bool supportsHalfFloat() const { - return !fCaps || - (fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) && - fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig, false)); + return !fCaps || (fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) && + fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig)); } bool supportsSRGB() const { diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp index 0a684cce60..ef6d809957 100644 --- a/src/image/SkSurface.cpp +++ b/src/image/SkSurface.cpp @@ -247,8 +247,8 @@ sk_sp<SkSurface> SkSurface::MakeNull(int width, int height) { #if !SK_SUPPORT_GPU -sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext*, SkBudgeted, const SkImageInfo&, - int, GrSurfaceOrigin, const SkSurfaceProps*, bool) { +sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext*, SkBudgeted, const SkImageInfo&, int, + GrSurfaceOrigin, const SkSurfaceProps*, bool) { return nullptr; } diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp index 9f7ec3b7f5..ff66844da7 100644 --- a/src/image/SkSurface_Gpu.cpp +++ b/src/image/SkSurface_Gpu.cpp @@ -256,7 +256,7 @@ sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted if (!SkSurface_Gpu::Valid(info)) { return nullptr; } - + sampleCount = SkTMax(1, sampleCount); GrMipMapped mipMapped = shouldCreateWithMips ? GrMipMapped::kYes : GrMipMapped::kNo; if (!ctx->caps()->mipMapSupport()) { @@ -299,6 +299,7 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrB if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) { return nullptr; } + sampleCnt = SkTMax(1, sampleCnt); sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeBackendTextureRenderTargetContext( tex, @@ -333,11 +334,9 @@ bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex, GrPix return false; } - if (!ctx->caps()->isConfigRenderable(*config, sampleCnt > 0)) { - return false; - } - - if (ctx->caps()->getSampleCount(sampleCnt, *config) != sampleCnt) { + // We don't require that the client gave us an exact valid sample cnt. However, it must be + // less than the max supported sample count and 1 if MSAA is unsupported for the color type. + if (!ctx->caps()->getRenderTargetSampleCount(sampleCnt, *config)) { return false; } @@ -355,6 +354,7 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrB if (!context) { return nullptr; } + sampleCnt = SkTMax(1, sampleCnt); GrBackendTexture texCopy = tex; if (!validate_backend_texture(context, texCopy, &texCopy.fConfig, sampleCnt, colorType, colorSpace, true)) { @@ -409,7 +409,11 @@ bool validate_backend_render_target(GrContext* ctx, const GrBackendRenderTarget& return false; } - if (!ctx->caps()->isConfigRenderable(*config, false)) { + if (rt.sampleCnt() > 1) { + if (ctx->caps()->maxRenderTargetSampleCount(*config) <= 1) { + return false; + } + } else if (!ctx->caps()->isConfigRenderable(*config)) { return false; } @@ -445,6 +449,7 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* cont if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) { return nullptr; } + sampleCnt = SkTMax(1, sampleCnt); sk_sp<GrRenderTargetContext> rtc( context->contextPriv().makeBackendTextureAsRenderTargetRenderTargetContext( @@ -475,6 +480,7 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* cont if (!context) { return nullptr; } + sampleCnt = SkTMax(1, sampleCnt); GrBackendTexture texCopy = tex; if (!validate_backend_texture(context, texCopy, &texCopy.fConfig, sampleCnt, colorType, colorSpace, false)) { diff --git a/src/utils/win/SkWGL.h b/src/utils/win/SkWGL.h index c6c9479abe..cd19f2eeba 100644 --- a/src/utils/win/SkWGL.h +++ b/src/utils/win/SkWGL.h @@ -83,7 +83,8 @@ public: * priority are: * * Choose formats with the smallest sample count that is >= * desiredSampleCount (or the largest sample count if all formats have - * fewer samples than desiredSampleCount.) + * fewer samples than desiredSampleCount.) If desiredSampleCount is 1 then + * all msaa formats are excluded from consideration. * * Choose formats with the fewest color samples when coverage sampling * is available. * * If the above rules leave multiple formats, choose the one that @@ -130,8 +131,9 @@ enum SkWGLContextRequest { /** * Helper to create an OpenGL context for a DC using WGL. Configs with a sample count >= to * msaaSampleCount are preferred but if none is available then a context with a lower sample count - * (including non-MSAA) will be created. If preferCoreProfile is true but a core profile cannot be - * created then a compatible profile context will be created. + * (including non-MSAA) will be created. If msaaSampleCount is 1 then this will fail if a non-msaa + * context cannot be created. If preferCoreProfile is true but a core profile cannot be created + * then a compatible profile context will be created. */ HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor, SkWGLContextRequest context, HGLRC shareContext = nullptr); diff --git a/src/utils/win/SkWGL_win.cpp b/src/utils/win/SkWGL_win.cpp index b7c89944e0..441d7a4ebb 100644 --- a/src/utils/win/SkWGL_win.cpp +++ b/src/utils/win/SkWGL_win.cpp @@ -126,6 +126,7 @@ int SkWGLExtensions::selectFormat(const int formats[], int formatCount, HDC dc, int desiredSampleCount) const { + SkASSERT(desiredSampleCount >= 1); if (formatCount <= 0) { return -1; } @@ -146,7 +147,7 @@ int SkWGLExtensions::selectFormat(const int formats[], &kQueryAttr, &numSamples); rankedFormats[i].fFormat = formats[i]; - rankedFormats[i].fSampleCnt = numSamples; + rankedFormats[i].fSampleCnt = SkTMax(1, numSamples); rankedFormats[i].fChoosePixelFormatRank = i; } SkTQSort(rankedFormats.begin(), @@ -159,6 +160,10 @@ int SkWGLExtensions::selectFormat(const int formats[], if (idx < 0) { idx = ~idx; } + // If the caller asked for non-MSAA fail if the closest format has MSAA. + if (desiredSampleCount == 1 && rankedFormats[idx].fSampleCnt != 1) { + return -1; + } return rankedFormats[idx].fFormat; } |