/*
* 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 "GrTextureMaker.h"
#include "GrColorSpaceXform.h"
#include "GrContext.h"
#include "GrContextPriv.h"
#include "GrGpu.h"
#include "GrProxyProvider.h"
sk_sp<GrTextureProxy> GrTextureMaker::refTextureProxyForParams(const GrSamplerState& params,
SkColorSpace* dstColorSpace,
sk_sp<SkColorSpace>* texColorSpace,
SkScalar scaleAdjust[2]) {
CopyParams copyParams;
bool willBeMipped = params.filter() == GrSamplerState::Filter::kMipMap;
if (!fContext->caps()->mipMapSupport()) {
willBeMipped = false;
}
if (texColorSpace) {
*texColorSpace = this->getColorSpace(dstColorSpace);
}
GrGpu* gpu = fContext->contextPriv().getGpu();
sk_sp<GrTextureProxy> original(this->refOriginalTextureProxy(willBeMipped, dstColorSpace,
AllowedTexGenType::kCheap));
if (original) {
if (!gpu->isACopyNeededForTextureParams(original.get(), params, ©Params, scaleAdjust)) {
return original;
}
} else {
if (!gpu->isACopyNeededForTextureParams(this->width(), this->height(),
params, ©Params, scaleAdjust)) {
return this->refOriginalTextureProxy(willBeMipped, dstColorSpace,
AllowedTexGenType::kAny);
}
}
GrProxyProvider* proxyProvider = fContext->contextPriv().proxyProvider();
GrSurfaceOrigin origOrigin = original ? original->origin() : kTopLeft_GrSurfaceOrigin;
GrUniqueKey copyKey;
this->makeCopyKey(copyParams, ©Key, dstColorSpace);
sk_sp<GrTextureProxy> cachedProxy;
if (copyKey.isValid()) {
cachedProxy = proxyProvider->findOrCreateProxyByUniqueKey(copyKey, origOrigin);
if (cachedProxy && (!willBeMipped || GrMipMapped::kYes == cachedProxy->mipMapped())) {
return cachedProxy;
}
}
sk_sp<GrTextureProxy> result;
if (original) {
result = std::move(original);
} else if (cachedProxy) {
result = cachedProxy;
} else {
// Since we will be copying this texture there is no reason to make it mipped
result = this->refOriginalTextureProxy(false, dstColorSpace,
AllowedTexGenType::kAny);
}
if (!result) {
return nullptr;
}
result = CopyOnGpu(fContext, std::move(result), copyParams, willBeMipped);
if (!result) {
return nullptr;
}
if (copyKey.isValid()) {
SkASSERT(result->origin() == origOrigin);
if (cachedProxy) {
SkASSERT(GrMipMapped::kYes == result->mipMapped() &&
GrMipMapped::kNo == cachedProxy->mipMapped());
// If we had a cachedProxy, that means there already is a proxy in the cache which
// matches the key, but it does not have mip levels and we require them. Thus we must
// remove the unique key from that proxy.
proxyProvider->removeUniqueKeyFromProxy(copyKey, cachedProxy.get());
}
proxyProvider->assignUniqueKeyToProxy(copyKey, result.get());
this->didCacheCopy(copyKey);
}
return result;
}
std::unique_ptr<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor(
const SkMatrix& textureMatrix,
const SkRect& constraintRect,
FilterConstraint filterConstraint,
bool coordsLimitedToConstraintRect,
const GrSamplerState::Filter* filterOrNullForBicubic,
SkColorSpace* dstColorSpace) {
const GrSamplerState::Filter* fmForDetermineDomain = filterOrNullForBicubic;
if (filterOrNullForBicubic && GrSamplerState::Filter::kMipMap == *filterOrNullForBicubic &&
kYes_FilterConstraint == filterConstraint) {
// TODo: Here we should force a copy restricted to the constraintRect since MIP maps will
// read outside the constraint rect. However, as in the adjuster case, we aren't currently
// doing that.
// We instead we compute the domain as though were bilerping which is only correct if we
// only sample level 0.
static const GrSamplerState::Filter kBilerp = GrSamplerState::Filter::kBilerp;
fmForDetermineDomain = &kBilerp;
}
GrSamplerState samplerState;
if (filterOrNullForBicubic) {
samplerState = GrSamplerState(GrSamplerState::WrapMode::kClamp, *filterOrNullForBicubic);
} else {
// Bicubic doesn't use filtering for it's texture accesses.
samplerState = GrSamplerState::ClampNearest();
}
sk_sp<SkColorSpace> texColorSpace;
SkScalar scaleAdjust[2] = { 1.0f, 1.0f };
sk_sp<GrTextureProxy> proxy(this->refTextureProxyForParams(samplerState, dstColorSpace,
&texColorSpace, scaleAdjust));
if (!proxy) {
return nullptr;
}
SkMatrix adjustedMatrix = textureMatrix;
adjustedMatrix.postScale(scaleAdjust[0], scaleAdjust[1]);
SkRect domain;
DomainMode domainMode =
DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
proxy.get(), fmForDetermineDomain, &domain);
SkASSERT(kTightCopy_DomainMode != domainMode);
GrPixelConfig config = proxy->config();
auto fp = CreateFragmentProcessorForDomainAndFilter(std::move(proxy), adjustedMatrix,
domainMode, domain, filterOrNullForBicubic);
return GrColorSpaceXformEffect::Make(std::move(fp), texColorSpace.get(), config, dstColorSpace);
}
sk_sp<GrTextureProxy> GrTextureMaker::generateTextureProxyForParams(const CopyParams& copyParams,
bool willBeMipped,
SkColorSpace* dstColorSpace) {
sk_sp<GrTextureProxy> original(this->refOriginalTextureProxy(willBeMipped, dstColorSpace,
AllowedTexGenType::kAny));
if (!original) {
return nullptr;
}
return CopyOnGpu(fContext, std::move(original), copyParams, willBeMipped);
}