Revert of Refactoring of GPU NormalMap handling out into its own class (patchset #7 id:120001 of https://codereview.chromium.org/2043393002/ )
Reason for revert: Breaking build and deps roll. Need to move include of SkBitmapProcShader in SkLightingShader.cpp from gpu include list to general list. Original issue's description: > Refactoring of GPU NormalMap handling out into its own class. > > The purpose of this change is to refactor the handling of normal maps out of SkLightingShader, laying the groundwork to eventually allow for multiple normal sources. > > What this CL includes: > > - Created a new 'NormalMapFP', out of the existing normal map reading behavior in LightingFP. > > - Encapsulates this new fragment processor on a new class NormalMapSource. > > - Created a NormalSource abstraction that will interface with SkLightingShader. > > - Adapted SkLightingShader to use the normals from its NormalSource field ON THE GPU SIDE. No changes done to the CPU side yet. > > BUG=skia: > GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2043393002 > > Committed: https://skia.googlesource.com/skia/+/87b0dd00cf9409c5fc990f5d0bb7c0df837f08da TBR=reed@google.com,dvonbeck@google.com # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=skia: Review-Url: https://codereview.chromium.org/2062133004
This commit is contained in:
parent
85730abbf8
commit
da743935fa
@ -154,7 +154,6 @@
|
||||
'<(skia_src_path)/core/SkLayerInfo.h',
|
||||
'<(skia_src_path)/core/SkLightingShader.h',
|
||||
'<(skia_src_path)/core/SkLightingShader.cpp',
|
||||
'<(skia_src_path)/core/SkLightingShader_NormalSource.cpp',
|
||||
'<(skia_src_path)/core/SkLinearBitmapPipeline.cpp',
|
||||
'<(skia_src_path)/core/SkLinearBitmapPipeline.h',
|
||||
'<(skia_src_path)/core/SkLinearBitmapPipeline_core.h',
|
||||
|
@ -81,7 +81,6 @@ public:
|
||||
kSkShader_Type,
|
||||
kSkUnused_Type, // used to be SkUnitMapper
|
||||
kSkXfermode_Type,
|
||||
kNormalSource_Type,
|
||||
};
|
||||
|
||||
typedef sk_sp<SkFlattenable> (*Factory)(SkReadBuffer&);
|
||||
|
@ -305,12 +305,6 @@ bool SkBitmapProcShader::isOpaque() const {
|
||||
return fRawBitmap.isOpaque();
|
||||
}
|
||||
|
||||
bool SkBitmapProcShader::BitmapIsTooBig(const SkBitmap& bm) {
|
||||
static const int kMaxSize = 65535;
|
||||
|
||||
return bm.width() > kMaxSize || bm.height() > kMaxSize;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SkUnPreMultiply.h"
|
||||
|
@ -21,11 +21,6 @@ public:
|
||||
|
||||
bool isOpaque() const override;
|
||||
|
||||
// SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
|
||||
// communicates between its matrix-proc and its sampler-proc. Until we can
|
||||
// widen that, we have to reject bitmaps that are larger.
|
||||
static bool BitmapIsTooBig(const SkBitmap&);
|
||||
|
||||
SK_TO_STRING_OVERRIDE()
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBitmapProcShader)
|
||||
|
||||
|
@ -42,19 +42,17 @@ public:
|
||||
|
||||
/** Create a new lighting shader that uses the provided normal map and
|
||||
lights to light the diffuse bitmap.
|
||||
@param diffuse the diffuse bitmap
|
||||
@param normal the normal map
|
||||
@param lights the lights applied to the normal map
|
||||
@param invNormRotation rotation applied to the normal map's normals
|
||||
@param diffLocalM the local matrix for the diffuse coordinates
|
||||
@param normLocalM the local matrix for the normal coordinates
|
||||
@param normalSource the normal source for GPU computations
|
||||
@param diffuse the diffuse bitmap
|
||||
@param normal the normal map
|
||||
@param lights the lights applied to the normal map
|
||||
@param invNormRotation rotation applied to the normal map's normals
|
||||
@param diffLocalM the local matrix for the diffuse coordinates
|
||||
@param normLocalM the local matrix for the normal coordinates
|
||||
*/
|
||||
SkLightingShaderImpl(const SkBitmap& diffuse, const SkBitmap& normal,
|
||||
const sk_sp<SkLights> lights,
|
||||
const SkVector& invNormRotation,
|
||||
const SkMatrix* diffLocalM, const SkMatrix* normLocalM,
|
||||
sk_sp<SkLightingShader::NormalSource> normalSource)
|
||||
const SkMatrix* diffLocalM, const SkMatrix* normLocalM)
|
||||
: INHERITED(diffLocalM)
|
||||
, fDiffuseMap(diffuse)
|
||||
, fNormalMap(normal)
|
||||
@ -69,7 +67,6 @@ public:
|
||||
// Pre-cache so future calls to fNormLocalMatrix.getType() are threadsafe.
|
||||
(void)fNormLocalMatrix.getType();
|
||||
|
||||
fNormalSource = std::move(normalSource);
|
||||
}
|
||||
|
||||
bool isOpaque() const override;
|
||||
@ -120,8 +117,6 @@ private:
|
||||
SkMatrix fNormLocalMatrix;
|
||||
SkVector fInvNormRotation;
|
||||
|
||||
sk_sp<SkLightingShader::NormalSource> fNormalSource;
|
||||
|
||||
friend class SkLightingShader;
|
||||
|
||||
typedef SkShader INHERITED;
|
||||
@ -139,18 +134,24 @@ private:
|
||||
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
#include "glsl/GrGLSLProgramDataManager.h"
|
||||
#include "glsl/GrGLSLUniformHandler.h"
|
||||
#include "SkBitmapProcShader.h"
|
||||
#include "SkGr.h"
|
||||
#include "SkGrPriv.h"
|
||||
|
||||
class LightingFP : public GrFragmentProcessor {
|
||||
public:
|
||||
LightingFP(GrTexture* diffuse, const SkMatrix& diffMatrix, const GrTextureParams& diffParams,
|
||||
sk_sp<SkLights> lights, sk_sp<GrFragmentProcessor> normalFP)
|
||||
LightingFP(GrTexture* diffuse, GrTexture* normal, const SkMatrix& diffMatrix,
|
||||
const SkMatrix& normMatrix, const GrTextureParams& diffParams,
|
||||
const GrTextureParams& normParams, sk_sp<SkLights> lights,
|
||||
const SkVector& invNormRotation)
|
||||
: fDiffDeviceTransform(kLocal_GrCoordSet, diffMatrix, diffuse, diffParams.filterMode())
|
||||
, fDiffuseTextureAccess(diffuse, diffParams) {
|
||||
, fNormDeviceTransform(kLocal_GrCoordSet, normMatrix, normal, normParams.filterMode())
|
||||
, fDiffuseTextureAccess(diffuse, diffParams)
|
||||
, fNormalTextureAccess(normal, normParams)
|
||||
, fInvNormRotation(invNormRotation) {
|
||||
this->addCoordTransform(&fDiffDeviceTransform);
|
||||
this->addCoordTransform(&fNormDeviceTransform);
|
||||
this->addTextureAccess(&fDiffuseTextureAccess);
|
||||
this->addTextureAccess(&fNormalTextureAccess);
|
||||
|
||||
// fuse all ambient lights into a single one
|
||||
fAmbientColor.set(0.0f, 0.0f, 0.0f);
|
||||
@ -164,16 +165,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
this->registerChildProcessor(std::move(normalFP));
|
||||
this->initClassID<LightingFP>();
|
||||
}
|
||||
|
||||
class GLSLLightingFP : public GrGLSLFragmentProcessor {
|
||||
class LightingGLFP : public GrGLSLFragmentProcessor {
|
||||
public:
|
||||
GLSLLightingFP() {
|
||||
LightingGLFP() {
|
||||
fLightDir.fX = 10000.0f;
|
||||
fLightColor.fX = 0.0f;
|
||||
fAmbientColor.fX = 0.0f;
|
||||
fInvNormRotation.set(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
void emitCode(EmitArgs& args) override {
|
||||
@ -197,16 +198,33 @@ public:
|
||||
kVec3f_GrSLType, kDefault_GrSLPrecision,
|
||||
"AmbientColor", &ambientColorUniName);
|
||||
|
||||
const char* xformUniName = nullptr;
|
||||
fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
||||
kVec2f_GrSLType, kDefault_GrSLPrecision,
|
||||
"Xform", &xformUniName);
|
||||
|
||||
fragBuilder->codeAppend("vec4 diffuseColor = ");
|
||||
fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fTexSamplers[0],
|
||||
args.fCoords[0].c_str(),
|
||||
args.fCoords[0].getType());
|
||||
fragBuilder->codeAppend(";");
|
||||
|
||||
SkString dstNormalName("dstNormal");
|
||||
this->emitChild(0, nullptr, &dstNormalName, args);
|
||||
fragBuilder->codeAppend("vec4 normalColor = ");
|
||||
fragBuilder->appendTextureLookup(args.fTexSamplers[1],
|
||||
args.fCoords[1].c_str(),
|
||||
args.fCoords[1].getType());
|
||||
fragBuilder->codeAppend(";");
|
||||
|
||||
fragBuilder->codeAppend("vec3 normal = normalColor.rgb - vec3(0.5);");
|
||||
|
||||
fragBuilder->codeAppendf(
|
||||
"mat3 m = mat3(%s.x, -%s.y, 0.0, %s.y, %s.x, 0.0, 0.0, 0.0, 1.0);",
|
||||
xformUniName, xformUniName, xformUniName, xformUniName);
|
||||
|
||||
// TODO: inverse map the light direction vectors in the vertex shader rather than
|
||||
// transforming all the normals here!
|
||||
fragBuilder->codeAppend("normal = normalize(m*normal);");
|
||||
|
||||
fragBuilder->codeAppendf("vec3 normal = %s.xyz;", dstNormalName.c_str());
|
||||
fragBuilder->codeAppendf("float NdotL = clamp(dot(normal, %s), 0.0, 1.0);",
|
||||
lightDirUniName);
|
||||
// diffuse light
|
||||
@ -244,6 +262,12 @@ public:
|
||||
pdman.set3fv(fAmbientColorUni, 1, &ambientColor.fX);
|
||||
fAmbientColor = ambientColor;
|
||||
}
|
||||
|
||||
const SkVector& invNormRotation = lightingFP.invNormRotation();
|
||||
if (invNormRotation != fInvNormRotation) {
|
||||
pdman.set2fv(fXformUni, 1, &invNormRotation.fX);
|
||||
fInvNormRotation = invNormRotation;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
@ -255,10 +279,13 @@ public:
|
||||
|
||||
SkColor3f fAmbientColor;
|
||||
GrGLSLProgramDataManager::UniformHandle fAmbientColorUni;
|
||||
|
||||
SkVector fInvNormRotation;
|
||||
GrGLSLProgramDataManager::UniformHandle fXformUni;
|
||||
};
|
||||
|
||||
void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
|
||||
GLSLLightingFP::GenKey(*this, caps, b);
|
||||
LightingGLFP::GenKey(*this, caps, b);
|
||||
}
|
||||
|
||||
const char* name() const override { return "LightingFP"; }
|
||||
@ -270,24 +297,32 @@ public:
|
||||
const SkVector3& lightDir() const { return fLightDir; }
|
||||
const SkColor3f& lightColor() const { return fLightColor; }
|
||||
const SkColor3f& ambientColor() const { return fAmbientColor; }
|
||||
const SkVector& invNormRotation() const { return fInvNormRotation; }
|
||||
|
||||
private:
|
||||
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLLightingFP; }
|
||||
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new LightingGLFP; }
|
||||
|
||||
bool onIsEqual(const GrFragmentProcessor& proc) const override {
|
||||
const LightingFP& lightingFP = proc.cast<LightingFP>();
|
||||
return fDiffDeviceTransform == lightingFP.fDiffDeviceTransform &&
|
||||
fNormDeviceTransform == lightingFP.fNormDeviceTransform &&
|
||||
fDiffuseTextureAccess == lightingFP.fDiffuseTextureAccess &&
|
||||
fNormalTextureAccess == lightingFP.fNormalTextureAccess &&
|
||||
fLightDir == lightingFP.fLightDir &&
|
||||
fLightColor == lightingFP.fLightColor &&
|
||||
fAmbientColor == lightingFP.fAmbientColor;
|
||||
fAmbientColor == lightingFP.fAmbientColor &&
|
||||
fInvNormRotation == lightingFP.fInvNormRotation;
|
||||
}
|
||||
|
||||
GrCoordTransform fDiffDeviceTransform;
|
||||
GrCoordTransform fNormDeviceTransform;
|
||||
GrTextureAccess fDiffuseTextureAccess;
|
||||
GrTextureAccess fNormalTextureAccess;
|
||||
SkVector3 fLightDir;
|
||||
SkColor3f fLightColor;
|
||||
SkColor3f fAmbientColor;
|
||||
|
||||
SkVector fInvNormRotation;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@ -322,39 +357,56 @@ sk_sp<GrFragmentProcessor> SkLightingShaderImpl::asFragmentProcessor(
|
||||
SkFilterQuality filterQuality,
|
||||
SkSourceGammaTreatment gammaTreatment) const {
|
||||
// we assume diffuse and normal maps have same width and height
|
||||
// TODO: support different sizes, will be addressed when diffuse maps are factored out of
|
||||
// SkLightingShader in a future CL
|
||||
// TODO: support different sizes
|
||||
SkASSERT(fDiffuseMap.width() == fNormalMap.width() &&
|
||||
fDiffuseMap.height() == fNormalMap.height());
|
||||
SkMatrix diffM;
|
||||
SkMatrix diffM, normM;
|
||||
|
||||
if (!make_mat(fDiffuseMap, this->getLocalMatrix(), localMatrix, &diffM)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!make_mat(fNormalMap, fNormLocalMatrix, localMatrix, &normM)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool doBicubic;
|
||||
GrTextureParams::FilterMode diffFilterMode = GrSkFilterQualityToGrFilterMode(
|
||||
SkTMin(filterQuality, kMedium_SkFilterQuality),
|
||||
viewM,
|
||||
this->getLocalMatrix(),
|
||||
&doBicubic);
|
||||
SkTMin(filterQuality, kMedium_SkFilterQuality),
|
||||
viewM,
|
||||
this->getLocalMatrix(),
|
||||
&doBicubic);
|
||||
SkASSERT(!doBicubic);
|
||||
|
||||
GrTextureParams::FilterMode normFilterMode = GrSkFilterQualityToGrFilterMode(
|
||||
SkTMin(filterQuality, kMedium_SkFilterQuality),
|
||||
viewM,
|
||||
fNormLocalMatrix,
|
||||
&doBicubic);
|
||||
SkASSERT(!doBicubic);
|
||||
|
||||
// TODO: support other tile modes
|
||||
GrTextureParams diffParams(kClamp_TileMode, diffFilterMode);
|
||||
SkAutoTUnref<GrTexture> diffuseTexture(GrRefCachedBitmapTexture(context, fDiffuseMap,
|
||||
diffParams, gammaTreatment));
|
||||
SkAutoTUnref<GrTexture> diffuseTexture(GrRefCachedBitmapTexture(context,
|
||||
fDiffuseMap, diffParams,
|
||||
gammaTreatment));
|
||||
if (!diffuseTexture) {
|
||||
SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<GrFragmentProcessor> normalFP(
|
||||
fNormalSource->asFragmentProcessor(context, viewM, localMatrix, filterQuality,
|
||||
gammaTreatment));
|
||||
sk_sp<GrFragmentProcessor> inner (
|
||||
new LightingFP(diffuseTexture, diffM, diffParams, fLights, std::move(normalFP)));
|
||||
GrTextureParams normParams(kClamp_TileMode, normFilterMode);
|
||||
SkAutoTUnref<GrTexture> normalTexture(GrRefCachedBitmapTexture(context,
|
||||
fNormalMap, normParams,
|
||||
gammaTreatment));
|
||||
if (!normalTexture) {
|
||||
SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<GrFragmentProcessor> inner (
|
||||
new LightingFP(diffuseTexture, normalTexture, diffM, normM, diffParams, normParams, fLights,
|
||||
fInvNormRotation));
|
||||
return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
|
||||
}
|
||||
|
||||
@ -366,14 +418,14 @@ bool SkLightingShaderImpl::isOpaque() const {
|
||||
return fDiffuseMap.isOpaque();
|
||||
}
|
||||
|
||||
SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(
|
||||
const SkLightingShaderImpl& shader,
|
||||
const ContextRec& rec,
|
||||
SkBitmapProcState* diffuseState,
|
||||
SkBitmapProcState* normalState)
|
||||
SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(const SkLightingShaderImpl& shader,
|
||||
const ContextRec& rec,
|
||||
SkBitmapProcState* diffuseState,
|
||||
SkBitmapProcState* normalState)
|
||||
: INHERITED(shader, rec)
|
||||
, fDiffuseState(diffuseState)
|
||||
, fNormalState(normalState) {
|
||||
, fNormalState(normalState)
|
||||
{
|
||||
const SkPixmap& pixmap = fDiffuseState->fPixmap;
|
||||
bool isOpaque = pixmap.isOpaque();
|
||||
|
||||
@ -563,11 +615,8 @@ sk_sp<SkFlattenable> SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) {
|
||||
invNormRotation = buf.readPoint();
|
||||
}
|
||||
|
||||
sk_sp<SkLightingShader::NormalSource> normalSource(
|
||||
buf.readFlattenable<SkLightingShader::NormalSource>());
|
||||
|
||||
return sk_make_sp<SkLightingShaderImpl>(diffuse, normal, std::move(lights), invNormRotation,
|
||||
&diffLocalM, &normLocalM, std::move(normalSource));
|
||||
&diffLocalM, &normLocalM);
|
||||
}
|
||||
|
||||
void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const {
|
||||
@ -595,8 +644,6 @@ void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const {
|
||||
}
|
||||
}
|
||||
buf.writePoint(fInvNormRotation);
|
||||
|
||||
buf.writeFlattenable(fNormalSource.get());
|
||||
}
|
||||
|
||||
bool SkLightingShaderImpl::computeNormTotalInverse(const ContextRec& rec,
|
||||
@ -638,9 +685,7 @@ SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* normalStateStorage = (char*)storage +
|
||||
sizeof(LightingShaderContext) +
|
||||
sizeof(SkBitmapProcState);
|
||||
void* normalStateStorage = (char*)storage + sizeof(LightingShaderContext) + sizeof(SkBitmapProcState);
|
||||
SkBitmapProcState* normalState = new (normalStateStorage) SkBitmapProcState(fNormalMap,
|
||||
SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
|
||||
SkMipMap::DeduceTreatment(rec));
|
||||
@ -656,23 +701,31 @@ SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec,
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool bitmap_is_too_big(const SkBitmap& bm) {
|
||||
// SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
|
||||
// communicates between its matrix-proc and its sampler-proc. Until we can
|
||||
// widen that, we have to reject bitmaps that are larger.
|
||||
//
|
||||
static const int kMaxSize = 65535;
|
||||
|
||||
return bm.width() > kMaxSize || bm.height() > kMaxSize;
|
||||
}
|
||||
|
||||
sk_sp<SkShader> SkLightingShader::Make(const SkBitmap& diffuse, const SkBitmap& normal,
|
||||
sk_sp<SkLights> lights,
|
||||
const SkVector& invNormRotation,
|
||||
const SkMatrix* diffLocalM, const SkMatrix* normLocalM) {
|
||||
if (diffuse.isNull() || SkBitmapProcShader::BitmapIsTooBig(diffuse) ||
|
||||
normal.isNull() || SkBitmapProcShader::BitmapIsTooBig(normal) ||
|
||||
diffuse.width() != normal.width() ||
|
||||
if (diffuse.isNull() || bitmap_is_too_big(diffuse) ||
|
||||
normal.isNull() || bitmap_is_too_big(normal) ||
|
||||
diffuse.width() != normal.width() ||
|
||||
diffuse.height() != normal.height()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkASSERT(SkScalarNearlyEqual(invNormRotation.lengthSqd(), SK_Scalar1));
|
||||
|
||||
sk_sp<SkLightingShader::NormalSource> normalSource =
|
||||
SkLightingShader::NormalMapSource::Make(normal, invNormRotation, normLocalM);
|
||||
|
||||
return sk_make_sp<SkLightingShaderImpl>(diffuse, normal, std::move(lights),
|
||||
invNormRotation, diffLocalM, normLocalM, std::move(normalSource));
|
||||
invNormRotation, diffLocalM, normLocalM);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -16,58 +16,6 @@ class SkMatrix;
|
||||
|
||||
class SK_API SkLightingShader {
|
||||
public:
|
||||
/** Abstract class that generates or reads in normals for use by SkLightingShader. Currently
|
||||
implements the GPU side only. Not to be used as part of the API yet. Used internally by
|
||||
SkLightingShader.
|
||||
*/
|
||||
class NormalSource : public SkFlattenable {
|
||||
public:
|
||||
virtual ~NormalSource();
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
/** Returns a fragment processor that takes no input and outputs a normal (already rotated)
|
||||
as its output color. To be used as a child fragment processor.
|
||||
*/
|
||||
virtual sk_sp<GrFragmentProcessor> asFragmentProcessor(
|
||||
GrContext* context,
|
||||
const SkMatrix& viewM,
|
||||
const SkMatrix* localMatrix,
|
||||
SkFilterQuality filterQuality,
|
||||
SkSourceGammaTreatment gammaTreatment) const = 0;
|
||||
#endif
|
||||
|
||||
SK_DEFINE_FLATTENABLE_TYPE(NormalSource)
|
||||
};
|
||||
|
||||
/** Returns a normal source that provides normals sourced from the the normal map argument.
|
||||
Not to be used as part of the API yet. Used internally by SkLightingShader.
|
||||
|
||||
@param normal the normal map
|
||||
@param invNormRotation rotation applied to the normal map's normals
|
||||
@param normLocalM the local matrix for the normal map
|
||||
|
||||
nullptr will be returned if
|
||||
'normal' is empty
|
||||
'normal' too big (> 65535 on either side)
|
||||
|
||||
The normal map is currently assumed to be an 8888 image where the normal at a texel
|
||||
is retrieved by:
|
||||
N.x = R-127;
|
||||
N.y = G-127;
|
||||
N.z = B-127;
|
||||
N.normalize();
|
||||
The +Z axis is thus encoded in RGB as (127, 127, 255) while the -Z axis is
|
||||
(127, 127, 0).
|
||||
*/
|
||||
class NormalMapSource {
|
||||
public:
|
||||
static sk_sp<NormalSource> Make(const SkBitmap& normal, const SkVector& invNormRotation,
|
||||
const SkMatrix* normLocalM);
|
||||
|
||||
SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
|
||||
};
|
||||
|
||||
/** Returns a shader that lights the diffuse and normal maps with a set of lights.
|
||||
|
||||
It returns a shader with a reference count of 1.
|
||||
|
@ -1,290 +0,0 @@
|
||||
/*
|
||||
* 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 "SkBitmapProcShader.h"
|
||||
#include "SkError.h"
|
||||
#include "SkErrorInternals.h"
|
||||
#include "SkLightingShader.h"
|
||||
#include "SkReadBuffer.h"
|
||||
#include "SkWriteBuffer.h"
|
||||
|
||||
// Genretating vtable
|
||||
SkLightingShader::NormalSource::~NormalSource() {}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SK_API NormalMapSourceImpl : public SkLightingShader::NormalSource {
|
||||
public:
|
||||
NormalMapSourceImpl(const SkBitmap &normal, const SkVector &invNormRotation,
|
||||
const SkMatrix *normLocalM)
|
||||
: fNormalMap(normal)
|
||||
, fInvNormRotation(invNormRotation) {
|
||||
|
||||
if (normLocalM) {
|
||||
fNormLocalMatrix = *normLocalM;
|
||||
} else {
|
||||
fNormLocalMatrix.reset();
|
||||
}
|
||||
// Pre-cache so future calls to fNormLocalMatrix.getType() are threadsafe.
|
||||
(void)fNormLocalMatrix.getType();
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*,
|
||||
const SkMatrix& viewM,
|
||||
const SkMatrix* localMatrix,
|
||||
SkFilterQuality,
|
||||
SkSourceGammaTreatment) const override;
|
||||
#endif
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(NormalMapSourceImpl)
|
||||
|
||||
protected:
|
||||
void flatten(SkWriteBuffer& buf) const override;
|
||||
|
||||
private:
|
||||
SkBitmap fNormalMap;
|
||||
SkMatrix fNormLocalMatrix;
|
||||
SkVector fInvNormRotation;
|
||||
|
||||
friend class SkLightingShader::NormalMapSource;
|
||||
|
||||
typedef SkLightingShader::NormalSource INHERITED;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
#include "GrCoordTransform.h"
|
||||
#include "GrInvariantOutput.h"
|
||||
#include "GrTextureParams.h"
|
||||
#include "glsl/GrGLSLFragmentProcessor.h"
|
||||
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
#include "SkGr.h"
|
||||
|
||||
class NormalMapFP : public GrFragmentProcessor {
|
||||
public:
|
||||
NormalMapFP(GrTexture* normal, const SkMatrix& normMatrix, const GrTextureParams& normParams,
|
||||
const SkVector& invNormRotation)
|
||||
: fNormDeviceTransform(kLocal_GrCoordSet, normMatrix, normal, normParams.filterMode())
|
||||
, fNormalTextureAccess(normal, normParams)
|
||||
, fInvNormRotation(invNormRotation) {
|
||||
this->addCoordTransform(&fNormDeviceTransform);
|
||||
this->addTextureAccess(&fNormalTextureAccess);
|
||||
|
||||
this->initClassID<NormalMapFP>();
|
||||
}
|
||||
|
||||
class GLSLNormalMapFP : public GrGLSLFragmentProcessor {
|
||||
public:
|
||||
GLSLNormalMapFP() {
|
||||
fInvNormRotation.set(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
void emitCode(EmitArgs& args) override {
|
||||
|
||||
GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
|
||||
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
|
||||
|
||||
// add uniform
|
||||
const char* xformUniName = nullptr;
|
||||
fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
||||
kVec2f_GrSLType, kDefault_GrSLPrecision,
|
||||
"Xform", &xformUniName);
|
||||
|
||||
fragBuilder->codeAppend("vec4 normalColor = ");
|
||||
fragBuilder->appendTextureLookup(args.fTexSamplers[0],
|
||||
args.fCoords[0].c_str(),
|
||||
args.fCoords[0].getType());
|
||||
fragBuilder->codeAppend(";");
|
||||
|
||||
fragBuilder->codeAppend("vec3 normal = normalColor.rgb - vec3(0.5);");
|
||||
|
||||
// TODO: inverse map the light direction vectors in the vertex shader rather than
|
||||
// transforming all the normals here!
|
||||
fragBuilder->codeAppendf(
|
||||
"mat3 m = mat3(%s.x, -%s.y, 0.0, %s.y, %s.x, 0.0, 0.0, 0.0, 1.0);",
|
||||
xformUniName, xformUniName, xformUniName, xformUniName);
|
||||
|
||||
fragBuilder->codeAppend("normal = normalize(m*normal);");
|
||||
fragBuilder->codeAppendf("%s = vec4(normal, 0);", args.fOutputColor);
|
||||
}
|
||||
|
||||
static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
|
||||
GrProcessorKeyBuilder* b) {
|
||||
b->add32(0x0);
|
||||
}
|
||||
|
||||
protected:
|
||||
void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
|
||||
const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
|
||||
|
||||
const SkVector& invNormRotation = normalMapFP.invNormRotation();
|
||||
if (invNormRotation != fInvNormRotation) {
|
||||
pdman.set2fv(fXformUni, 1, &invNormRotation.fX);
|
||||
fInvNormRotation = invNormRotation;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SkVector fInvNormRotation;
|
||||
GrGLSLProgramDataManager::UniformHandle fXformUni;
|
||||
};
|
||||
|
||||
void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
|
||||
GLSLNormalMapFP::GenKey(*this, caps, b);
|
||||
}
|
||||
|
||||
const char* name() const override { return "NormalMapFP"; }
|
||||
|
||||
void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
|
||||
inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput);
|
||||
}
|
||||
|
||||
const SkVector& invNormRotation() const { return fInvNormRotation; }
|
||||
|
||||
private:
|
||||
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalMapFP; }
|
||||
|
||||
bool onIsEqual(const GrFragmentProcessor& proc) const override {
|
||||
const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
|
||||
return fNormDeviceTransform == normalMapFP.fNormDeviceTransform &&
|
||||
fNormalTextureAccess == normalMapFP.fNormalTextureAccess &&
|
||||
fInvNormRotation == normalMapFP.fInvNormRotation;
|
||||
}
|
||||
|
||||
GrCoordTransform fNormDeviceTransform;
|
||||
GrTextureAccess fNormalTextureAccess;
|
||||
SkVector fInvNormRotation;
|
||||
};
|
||||
|
||||
// TODO same code at SkLightingShader.cpp. Refactor to common source!
|
||||
static bool make_mat(const SkBitmap& bm,
|
||||
const SkMatrix& localMatrix1,
|
||||
const SkMatrix* localMatrix2,
|
||||
SkMatrix* result) {
|
||||
|
||||
result->setIDiv(bm.width(), bm.height());
|
||||
|
||||
SkMatrix lmInverse;
|
||||
if (!localMatrix1.invert(&lmInverse)) {
|
||||
return false;
|
||||
}
|
||||
if (localMatrix2) {
|
||||
SkMatrix inv;
|
||||
if (!localMatrix2->invert(&inv)) {
|
||||
return false;
|
||||
}
|
||||
lmInverse.postConcat(inv);
|
||||
}
|
||||
result->preConcat(lmInverse);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
sk_sp<GrFragmentProcessor> NormalMapSourceImpl::asFragmentProcessor(
|
||||
GrContext *context,
|
||||
const SkMatrix &viewM,
|
||||
const SkMatrix *localMatrix,
|
||||
SkFilterQuality filterQuality,
|
||||
SkSourceGammaTreatment gammaTreatment) const {
|
||||
|
||||
// TODO Here, the old code was checking that diffuse map and normal map are same size, that
|
||||
// will be addressed when diffuse maps are factored out of SkLightingShader in a future CL
|
||||
|
||||
SkMatrix normM;
|
||||
if (!make_mat(fNormalMap, fNormLocalMatrix, localMatrix, &normM)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool doBicubic;
|
||||
GrTextureParams::FilterMode normFilterMode = GrSkFilterQualityToGrFilterMode(
|
||||
SkTMin(filterQuality, kMedium_SkFilterQuality),
|
||||
viewM,
|
||||
fNormLocalMatrix,
|
||||
&doBicubic);
|
||||
SkASSERT(!doBicubic);
|
||||
|
||||
// TODO: support other tile modes
|
||||
GrTextureParams normParams(SkShader::kClamp_TileMode, normFilterMode);
|
||||
SkAutoTUnref<GrTexture> normalTexture(GrRefCachedBitmapTexture(context,
|
||||
fNormalMap,
|
||||
normParams,
|
||||
gammaTreatment));
|
||||
if (!normalTexture) {
|
||||
SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return sk_make_sp<NormalMapFP>(normalTexture, normM, normParams, fInvNormRotation);
|
||||
}
|
||||
|
||||
#endif // SK_SUPPORT_GPU
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sk_sp<SkFlattenable> NormalMapSourceImpl::CreateProc(SkReadBuffer& buf) {
|
||||
|
||||
SkMatrix normLocalM;
|
||||
bool hasNormLocalM = buf.readBool();
|
||||
if (hasNormLocalM) {
|
||||
buf.readMatrix(&normLocalM);
|
||||
} else {
|
||||
normLocalM.reset();
|
||||
}
|
||||
|
||||
SkBitmap normal;
|
||||
if (!buf.readBitmap(&normal)) {
|
||||
return nullptr;
|
||||
}
|
||||
normal.setImmutable();
|
||||
|
||||
SkVector invNormRotation = {1,0};
|
||||
if (!buf.isVersionLT(SkReadBuffer::kLightingShaderWritesInvNormRotation)) {
|
||||
invNormRotation = buf.readPoint();
|
||||
}
|
||||
|
||||
return sk_make_sp<NormalMapSourceImpl>(normal, invNormRotation, &normLocalM);
|
||||
}
|
||||
|
||||
void NormalMapSourceImpl::flatten(SkWriteBuffer& buf) const {
|
||||
this->INHERITED::flatten(buf);
|
||||
|
||||
bool hasNormLocalM = !fNormLocalMatrix.isIdentity();
|
||||
buf.writeBool(hasNormLocalM);
|
||||
if (hasNormLocalM) {
|
||||
buf.writeMatrix(fNormLocalMatrix);
|
||||
}
|
||||
|
||||
buf.writeBitmap(fNormalMap);
|
||||
buf.writePoint(fInvNormRotation);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sk_sp<SkLightingShader::NormalSource> SkLightingShader::NormalMapSource::Make(
|
||||
const SkBitmap &normal, const SkVector &invNormRotation, const SkMatrix *normLocalM) {
|
||||
|
||||
// TODO not checking normal and diffuse maps to be same size, will be addressed when diffuse
|
||||
// maps are factored out of SkLightingShader in a future CL
|
||||
if (normal.isNull() || SkBitmapProcShader::BitmapIsTooBig(normal)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkASSERT(SkScalarNearlyEqual(invNormRotation.lengthSqd(), SK_Scalar1));
|
||||
|
||||
return sk_make_sp<NormalMapSourceImpl>(normal, invNormRotation, normLocalM);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader::NormalMapSource)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(NormalMapSourceImpl)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
@ -88,8 +88,6 @@ void SkFlattenable::PrivateInitializer::InitEffects() {
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPerlinNoiseShader)
|
||||
SkGradientShader::InitializeFlattenables();
|
||||
SkLightingShader::InitializeFlattenables();
|
||||
SkLightingShader::NormalMapSource::InitializeFlattenables();
|
||||
|
||||
|
||||
// PathEffect
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArcToPathEffect)
|
||||
|
@ -5,14 +5,13 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "Resources.h"
|
||||
#include "SkAnnotationKeys.h"
|
||||
#include "Resources.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkFixed.h"
|
||||
#include "SkFontDescriptor.h"
|
||||
#include "SkImage.h"
|
||||
#include "SkImageSource.h"
|
||||
#include "SkLightingShader.h"
|
||||
#include "SkMallocPixelRef.h"
|
||||
#include "SkOSFile.h"
|
||||
#include "SkPictureRecorder.h"
|
||||
@ -22,7 +21,6 @@
|
||||
#include "SkWriteBuffer.h"
|
||||
#include "SkValidatingReadBuffer.h"
|
||||
#include "SkXfermodeImageFilter.h"
|
||||
#include "sk_tool_utils.h"
|
||||
#include "Test.h"
|
||||
|
||||
static const uint32_t kArraySize = 64;
|
||||
@ -184,8 +182,8 @@ static T* TestFlattenableSerialization(T* testObj, bool shouldSucceed,
|
||||
size_t bytesWritten = writer.bytesWritten();
|
||||
REPORTER_ASSERT(reporter, SkAlign4(bytesWritten) == bytesWritten);
|
||||
|
||||
SkASSERT(bytesWritten <= 4096);
|
||||
unsigned char dataWritten[4096];
|
||||
SkASSERT(bytesWritten <= sizeof(dataWritten));
|
||||
writer.writeToMemory(dataWritten);
|
||||
|
||||
// Make sure this fails when it should (test with smaller size, but still multiple of 4)
|
||||
@ -548,43 +546,6 @@ DEF_TEST(Serialization, reporter) {
|
||||
}
|
||||
|
||||
TestPictureTypefaceSerialization(reporter);
|
||||
|
||||
// Test SkLightingShader/NormalMapSource serialization
|
||||
{
|
||||
const int kTexSize = 2;
|
||||
|
||||
SkLights::Builder builder;
|
||||
|
||||
builder.add(SkLights::Light(SkColor3f::Make(1.0f, 1.0f, 1.0f),
|
||||
SkVector3::Make(1.0f, 0.0f, 0.0f)));
|
||||
builder.add(SkLights::Light(SkColor3f::Make(0.2f, 0.2f, 0.2f)));
|
||||
|
||||
sk_sp<SkLights> fLights = builder.finish();
|
||||
|
||||
SkBitmap diffuse = sk_tool_utils::create_checkerboard_bitmap(
|
||||
kTexSize, kTexSize,
|
||||
sk_tool_utils::color_to_565(0x0),
|
||||
sk_tool_utils::color_to_565(0xFF804020),
|
||||
8);
|
||||
|
||||
SkRect bitmapBounds = SkRect::MakeIWH(diffuse.width(), diffuse.height());
|
||||
|
||||
SkMatrix matrix;
|
||||
SkRect r = SkRect::MakeWH(SkIntToScalar(kTexSize), SkIntToScalar(kTexSize));
|
||||
matrix.setRectToRect(bitmapBounds, r, SkMatrix::kFill_ScaleToFit);
|
||||
|
||||
SkVector invNormRotation = { SkScalarSqrt(0.3f), SkScalarSqrt(0.7f) };
|
||||
SkBitmap normals;
|
||||
normals.allocN32Pixels(kTexSize, kTexSize);
|
||||
|
||||
sk_tool_utils::create_frustum_normal_map(&normals, SkIRect::MakeWH(kTexSize, kTexSize));
|
||||
sk_sp<SkShader> lightingShader = SkLightingShader::Make(diffuse, normals, fLights,
|
||||
invNormRotation, &matrix, &matrix);
|
||||
|
||||
TestFlattenableSerialization(lightingShader.get(), true, reporter);
|
||||
// TODO test equality?
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user