| /* |
| * Copyright 2016 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| #include "src/gpu/ganesh/GrTextureRenderTargetProxy.h" |
| |
| #include "include/core/SkSize.h" |
| #include "include/gpu/GpuTypes.h" |
| #include "include/gpu/GrDirectContext.h" |
| #include "include/private/base/SkAssert.h" |
| #include "include/private/gpu/ganesh/GrTypesPriv.h" |
| #include "src/gpu/ResourceKey.h" |
| #include "src/gpu/SkBackingFit.h" |
| #include "src/gpu/ganesh/GrCaps.h" |
| #include "src/gpu/ganesh/GrDirectContextPriv.h" |
| #include "src/gpu/ganesh/GrRenderTarget.h" |
| #include "src/gpu/ganesh/GrSurface.h" |
| #include "src/gpu/ganesh/GrSurfaceProxy.h" |
| #include "src/gpu/ganesh/GrSurfaceProxyPriv.h" |
| #include "src/gpu/ganesh/GrTexture.h" |
| |
| #include <utility> |
| |
| class GrBackendFormat; |
| class GrResourceProvider; |
| |
| // Deferred version |
| // This class is virtually derived from GrSurfaceProxy (via both GrTextureProxy and |
| // GrRenderTargetProxy) so its constructor must be explicitly called. |
| GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps, |
| const GrBackendFormat& format, |
| SkISize dimensions, |
| int sampleCnt, |
| skgpu::Mipmapped mipmapped, |
| GrMipmapStatus mipmapStatus, |
| SkBackingFit fit, |
| skgpu::Budgeted budgeted, |
| GrProtected isProtected, |
| GrInternalSurfaceFlags surfaceFlags, |
| UseAllocator useAllocator, |
| GrDDLProvider creatingProvider, |
| std::string_view label) |
| : GrSurfaceProxy( |
| format, dimensions, fit, budgeted, isProtected, surfaceFlags, useAllocator, label) |
| // for now textures w/ data are always wrapped |
| , GrRenderTargetProxy(caps, |
| format, |
| dimensions, |
| sampleCnt, |
| fit, |
| budgeted, |
| isProtected, |
| surfaceFlags, |
| useAllocator, |
| label) |
| , GrTextureProxy(format, |
| dimensions, |
| mipmapped, |
| mipmapStatus, |
| fit, |
| budgeted, |
| isProtected, |
| surfaceFlags, |
| useAllocator, |
| creatingProvider, |
| label) { |
| this->initSurfaceFlags(caps); |
| } |
| |
| // Lazy-callback version |
| GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps, |
| LazyInstantiateCallback&& callback, |
| const GrBackendFormat& format, |
| SkISize dimensions, |
| int sampleCnt, |
| skgpu::Mipmapped mipmapped, |
| GrMipmapStatus mipmapStatus, |
| SkBackingFit fit, |
| skgpu::Budgeted budgeted, |
| GrProtected isProtected, |
| GrInternalSurfaceFlags surfaceFlags, |
| UseAllocator useAllocator, |
| GrDDLProvider creatingProvider, |
| std::string_view label) |
| : GrSurfaceProxy(std::move(callback), |
| format, |
| dimensions, |
| fit, |
| budgeted, |
| isProtected, |
| surfaceFlags, |
| useAllocator, |
| label) |
| // Since we have virtual inheritance, we initialize GrSurfaceProxy directly. Send null |
| // callbacks to the texture and RT proxies simply to route to the appropriate constructors. |
| , GrRenderTargetProxy(LazyInstantiateCallback(), |
| format, |
| dimensions, |
| sampleCnt, |
| fit, |
| budgeted, |
| isProtected, |
| surfaceFlags, |
| useAllocator, |
| WrapsVkSecondaryCB::kNo, |
| label) |
| , GrTextureProxy(LazyInstantiateCallback(), |
| format, |
| dimensions, |
| mipmapped, |
| mipmapStatus, |
| fit, |
| budgeted, |
| isProtected, |
| surfaceFlags, |
| useAllocator, |
| creatingProvider, |
| label) { |
| this->initSurfaceFlags(caps); |
| } |
| |
| // Wrapped version |
| // This class is virtually derived from GrSurfaceProxy (via both GrTextureProxy and |
| // GrRenderTargetProxy) so its constructor must be explicitly called. |
| GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(sk_sp<GrSurface> surf, |
| UseAllocator useAllocator, |
| GrDDLProvider creatingProvider) |
| : GrSurfaceProxy(surf, SkBackingFit::kExact, useAllocator) |
| , GrRenderTargetProxy(surf, useAllocator) |
| , GrTextureProxy(surf, useAllocator, creatingProvider) { |
| SkASSERT(surf->asTexture()); |
| SkASSERT(surf->asRenderTarget()); |
| SkASSERT(fSurfaceFlags == fTarget->flags()); |
| SkASSERT((this->numSamples() <= 1 || |
| fTarget->getContext()->priv().caps()->msaaResolvesAutomatically()) != |
| this->requiresManualMSAAResolve()); |
| } |
| |
| void GrTextureRenderTargetProxy::initSurfaceFlags(const GrCaps& caps) { |
| // FBO 0 should never be wrapped as a texture render target. |
| SkASSERT(!this->glRTFBOIDIs0()); |
| if (this->numSamples() > 1 && !caps.msaaResolvesAutomatically()) { |
| // MSAA texture-render-targets always require manual resolve if we are not using a |
| // multisampled-render-to-texture extension. |
| // |
| // NOTE: This is the only instance where we need to set the manual resolve flag on a proxy. |
| // Any other proxies that require manual resolve (e.g., wrapRenderableBackendTexture() with |
| // a sample count) will be wrapped, and the wrapped version of the GrSurface constructor |
| // will automatically get the manual resolve flag when copying the target GrSurface's flags. |
| fSurfaceFlags |= GrInternalSurfaceFlags::kRequiresManualMSAAResolve; |
| } |
| } |
| |
| size_t GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize() const { |
| int colorSamplesPerPixel = this->numSamples(); |
| if (colorSamplesPerPixel > 1) { |
| // Add one to account for the resolve buffer. |
| ++colorSamplesPerPixel; |
| } |
| |
| // TODO: do we have enough information to improve this worst case estimate? |
| return GrSurface::ComputeSize(this->backendFormat(), this->dimensions(), |
| colorSamplesPerPixel, this->proxyMipmapped(), |
| !this->priv().isExact()); |
| } |
| |
| bool GrTextureRenderTargetProxy::instantiate(GrResourceProvider* resourceProvider) { |
| if (this->isLazy()) { |
| return false; |
| } |
| |
| const skgpu::UniqueKey& key = this->getUniqueKey(); |
| |
| if (!this->instantiateImpl(resourceProvider, this->numSamples(), GrRenderable::kYes, |
| this->mipmapped(), key.isValid() ? &key : nullptr)) { |
| return false; |
| } |
| if (key.isValid()) { |
| SkASSERT(key == this->getUniqueKey()); |
| } |
| |
| SkASSERT(this->peekRenderTarget()); |
| SkASSERT(this->peekTexture()); |
| |
| return true; |
| } |
| |
| sk_sp<GrSurface> GrTextureRenderTargetProxy::createSurface( |
| GrResourceProvider* resourceProvider) const { |
| sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, this->numSamples(), |
| GrRenderable::kYes, this->mipmapped()); |
| if (!surface) { |
| return nullptr; |
| } |
| SkASSERT(surface->asRenderTarget()); |
| SkASSERT(surface->asTexture()); |
| |
| return surface; |
| } |
| |
| GrSurfaceProxy::LazySurfaceDesc GrTextureRenderTargetProxy::callbackDesc() const { |
| SkISize dims; |
| SkBackingFit fit; |
| if (this->isFullyLazy()) { |
| fit = SkBackingFit::kApprox; |
| dims = {-1, -1}; |
| } else { |
| fit = this->isFunctionallyExact() ? SkBackingFit::kExact : SkBackingFit::kApprox; |
| dims = this->dimensions(); |
| } |
| return { |
| dims, |
| fit, |
| GrRenderable::kYes, |
| this->mipmapped(), |
| this->numSamples(), |
| this->backendFormat(), |
| this->textureType(), |
| this->isProtected(), |
| this->isBudgeted(), |
| this->getLabel(), |
| }; |
| } |
| |
| #ifdef SK_DEBUG |
| void GrTextureRenderTargetProxy::onValidateSurface(const GrSurface* surface) { |
| // Anything checked here should also be checking the GrTextureProxy version |
| SkASSERT(surface->asTexture()); |
| SkASSERT(skgpu::Mipmapped::kNo == this->proxyMipmapped() || |
| skgpu::Mipmapped::kYes == surface->asTexture()->mipmapped()); |
| |
| // Anything checked here should also be checking the GrRenderTargetProxy version |
| SkASSERT(surface->asRenderTarget()); |
| SkASSERT(surface->asRenderTarget()->numSamples() == this->numSamples()); |
| |
| SkASSERT(surface->asTexture()->textureType() == this->textureType()); |
| |
| GrInternalSurfaceFlags proxyFlags = fSurfaceFlags; |
| GrInternalSurfaceFlags surfaceFlags = surface->flags(); |
| |
| // Only non-RT textures can be read only. |
| SkASSERT(!(proxyFlags & GrInternalSurfaceFlags::kReadOnly)); |
| SkASSERT(!(surfaceFlags & GrInternalSurfaceFlags::kReadOnly)); |
| |
| SkASSERT(((int)proxyFlags & kGrInternalTextureRenderTargetFlagsMask) == |
| ((int)surfaceFlags & kGrInternalTextureRenderTargetFlagsMask)); |
| |
| // We manually check the kVkRTSupportsInputAttachment since we only require it on the surface if |
| // the proxy has it set. If the proxy doesn't have the flag it is legal for the surface to |
| // have the flag. |
| if (proxyFlags & GrInternalSurfaceFlags::kVkRTSupportsInputAttachment) { |
| SkASSERT(surfaceFlags & GrInternalSurfaceFlags::kVkRTSupportsInputAttachment); |
| } |
| } |
| #endif |
| |