Implement separate sampler and textures in SkSL.
Dawn doesn't support old-style combined texturesampler uniforms, so
they must be expressed as separate samplers and texture uniforms.
At the SkSL Type level, I've added a Texture2D type, and expressed
the Sampler2D (combined) type in terms of it. This ensures that we
emit only a single OpTypeImage for it in the SPIRV.
Eventually, all of the Texture types (1D, 3D, Rect) could be defined
and SamplerX could simply contain a reference to TextureX. I wanted to
float this idea with a single example for now (and since it's all that
the Dawn backend needs).
This also required adding a new "makeSampler2D" function to combine
them, which maps to OpSampledImage at the SPIR-V level.
Change-Id: Iaf33a6e7d339da415be6ea9a017340cb0ef3c1eb
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/229417
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h
index 1402c4e..fd08219 100644
--- a/include/private/GrTypesPriv.h
+++ b/include/private/GrTypesPriv.h
@@ -371,8 +371,10 @@
kTexture2DSampler_GrSLType,
kTextureExternalSampler_GrSLType,
kTexture2DRectSampler_GrSLType,
+ kTexture2D_GrSLType,
+ kSampler_GrSLType,
- kLast_GrSLType = kTexture2DRectSampler_GrSLType
+ kLast_GrSLType = kSampler_GrSLType
};
static const int kGrSLTypeCount = kLast_GrSLType + 1;
@@ -474,6 +476,8 @@
case kInt4_GrSLType:
case kUint_GrSLType:
case kUint2_GrSLType:
+ case kTexture2D_GrSLType:
+ case kSampler_GrSLType:
return false;
}
SkUNREACHABLE;
@@ -531,6 +535,8 @@
case kTexture2DSampler_GrSLType:
case kTextureExternalSampler_GrSLType:
case kTexture2DRectSampler_GrSLType:
+ case kTexture2D_GrSLType:
+ case kSampler_GrSLType:
return -1;
}
SkUNREACHABLE;
@@ -612,6 +618,8 @@
case kUShort2_GrSLType:
case kUShort3_GrSLType:
case kUShort4_GrSLType:
+ case kTexture2D_GrSLType:
+ case kSampler_GrSLType:
return false;
}
SkUNREACHABLE;
diff --git a/src/gpu/glsl/GrGLSL.cpp b/src/gpu/glsl/GrGLSL.cpp
index e8fa694..a506c43 100644
--- a/src/gpu/glsl/GrGLSL.cpp
+++ b/src/gpu/glsl/GrGLSL.cpp
@@ -92,6 +92,10 @@
return "ubyte3";
case kUByte4_GrSLType:
return "ubyte4";
+ case kTexture2D_GrSLType:
+ return "texture2D";
+ case kSampler_GrSLType:
+ return "sampler";
}
SK_ABORT("Unknown shader var type.");
return ""; // suppress warning
diff --git a/src/gpu/mtl/GrMtlUniformHandler.mm b/src/gpu/mtl/GrMtlUniformHandler.mm
index 346f9a3..73eeecf 100644
--- a/src/gpu/mtl/GrMtlUniformHandler.mm
+++ b/src/gpu/mtl/GrMtlUniformHandler.mm
@@ -85,6 +85,8 @@
case kTexture2DSampler_GrSLType:
case kTextureExternalSampler_GrSLType:
case kTexture2DRectSampler_GrSLType:
+ case kSampler_GrSLType:
+ case kTexture2D_GrSLType:
break;
}
SK_ABORT("Unexpected type");
@@ -166,6 +168,8 @@
case kTexture2DSampler_GrSLType:
case kTextureExternalSampler_GrSLType:
case kTexture2DRectSampler_GrSLType:
+ case kSampler_GrSLType:
+ case kTexture2D_GrSLType:
break;
}
SK_ABORT("Unexpected type");
diff --git a/src/gpu/vk/GrVkUniformHandler.cpp b/src/gpu/vk/GrVkUniformHandler.cpp
index 2613550..32210d6 100644
--- a/src/gpu/vk/GrVkUniformHandler.cpp
+++ b/src/gpu/vk/GrVkUniformHandler.cpp
@@ -84,6 +84,8 @@
case kTexture2DSampler_GrSLType:
case kTextureExternalSampler_GrSLType:
case kTexture2DRectSampler_GrSLType:
+ case kSampler_GrSLType:
+ case kTexture2D_GrSLType:
break;
}
SK_ABORT("Unexpected type");
@@ -166,6 +168,8 @@
case kTexture2DSampler_GrSLType:
case kTextureExternalSampler_GrSLType:
case kTexture2DRectSampler_GrSLType:
+ case kSampler_GrSLType:
+ case kTexture2D_GrSLType:
break;
}
SK_ABORT("Unexpected type");
diff --git a/src/gpu/vk/GrVkVaryingHandler.cpp b/src/gpu/vk/GrVkVaryingHandler.cpp
index a4b9350..1a38e8f 100644
--- a/src/gpu/vk/GrVkVaryingHandler.cpp
+++ b/src/gpu/vk/GrVkVaryingHandler.cpp
@@ -55,6 +55,8 @@
case kHalf4x4_GrSLType:
return 4;
case kTexture2DSampler_GrSLType:
+ case kSampler_GrSLType:
+ case kTexture2D_GrSLType:
return 0;
case kTextureExternalSampler_GrSLType:
return 0;
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index 8476396..36df201 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -211,6 +211,8 @@
ADD_TYPE(GSamplerCubeArrayShadow);
ADD_TYPE(FragmentProcessor);
ADD_TYPE(SkRasterPipeline);
+ ADD_TYPE(Sampler);
+ ADD_TYPE(Texture2D);
StringFragment skCapsName("sk_Caps");
Variable* skCaps = new Variable(-1, Modifiers(), skCapsName,
diff --git a/src/sksl/SkSLContext.h b/src/sksl/SkSLContext.h
index abe7322..b566a5e 100644
--- a/src/sksl/SkSLContext.h
+++ b/src/sksl/SkSLContext.h
@@ -91,8 +91,9 @@
, fDouble4x2_Type(new Type("double4x2", *fDouble_Type, 4, 2))
, fDouble4x3_Type(new Type("double4x3", *fDouble_Type, 4, 3))
, fDouble4x4_Type(new Type("double4x4", *fDouble_Type, 4, 4))
+ , fTexture2D_Type(new Type("texture2D", Type::kTexture_Kind))
, fSampler1D_Type(new Type("sampler1D", SpvDim1D, false, false, false, true))
- , fSampler2D_Type(new Type("sampler2D", SpvDim2D, false, false, false, true))
+ , fSampler2D_Type(new Type("sampler2D", SpvDim2D, false, false, false, true, &*fTexture2D_Type))
, fSampler3D_Type(new Type("sampler3D", SpvDim3D, false, false, false, true))
, fSamplerExternalOES_Type(new Type("samplerExternalOES", SpvDim2D, false, false,
false, true))
@@ -116,6 +117,7 @@
// Related to below FIXME, gsampler*s don't currently expand to cover integer case.
, fISampler2D_Type(new Type("isampler2D", SpvDim2D, false, false, false, true))
+ , fSampler_Type(new Type("sampler", Type::kSeparateSampler_Kind))
// FIXME express these as "gimage2D" that expand to image2D, iimage2D, and uimage2D.
, fImage2D_Type(new Type("image2D", SpvDim2D, false, false, false, true))
, fIImage2D_Type(new Type("iimage2D", SpvDim2D, false, false, false, true))
@@ -293,6 +295,8 @@
const std::unique_ptr<Type> fDouble4x3_Type;
const std::unique_ptr<Type> fDouble4x4_Type;
+ const std::unique_ptr<Type> fTexture2D_Type;
+
const std::unique_ptr<Type> fSampler1D_Type;
const std::unique_ptr<Type> fSampler2D_Type;
const std::unique_ptr<Type> fSampler3D_Type;
@@ -314,6 +318,7 @@
const std::unique_ptr<Type> fSamplerCubeArrayShadow_Type;
const std::unique_ptr<Type> fISampler2D_Type;
+ const std::unique_ptr<Type> fSampler_Type;
const std::unique_ptr<Type> fImage2D_Type;
const std::unique_ptr<Type> fIImage2D_Type;
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp
index 08c0fdb..6f1ae03 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp
@@ -101,6 +101,8 @@
fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy);
fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
SpvOpUndef, SpvOpUndef, SpvOpUndef);
+ fIntrinsicMap[String("makeSampler2D")] = SPECIAL(SampledImage);
+
fIntrinsicMap[String("texture")] = SPECIAL(Texture);
fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
@@ -206,6 +208,7 @@
case SpvOpTypeStruct: // fall through
case SpvOpTypeImage: // fall through
case SpvOpTypeSampledImage: // fall through
+ case SpvOpTypeSampler: // fall through
case SpvOpVariable: // fall through
case SpvOpFunction: // fall through
case SpvOpFunctionParameter: // fall through
@@ -526,22 +529,42 @@
case Type::kSampler_Kind: {
SpvId image = result;
if (SpvDimSubpassData != type.dimensions()) {
- image = this->nextId();
+ if (type.textureType()) {
+ image = this->getType(*type.textureType(), layout);
+ } else {
+ image = nextId();
+ }
}
if (SpvDimBuffer == type.dimensions()) {
fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
}
- this->writeInstruction(SpvOpTypeImage, image,
- this->getType(*fContext.fFloat_Type, layout),
- type.dimensions(), type.isDepth(), type.isArrayed(),
- type.isMultisampled(), type.isSampled() ? 1 : 2,
- SpvImageFormatUnknown, fConstantBuffer);
- fImageTypeMap[key] = image;
+ if (!type.textureType()) {
+ this->writeInstruction(SpvOpTypeImage, image,
+ this->getType(*fContext.fFloat_Type, layout),
+ type.dimensions(), type.isDepth(), type.isArrayed(),
+ type.isMultisampled(), type.isSampled() ? 1 : 2,
+ SpvImageFormatUnknown, fConstantBuffer);
+ fImageTypeMap[key] = image;
+ }
if (SpvDimSubpassData != type.dimensions()) {
this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
}
break;
}
+ case Type::kSeparateSampler_Kind: {
+ this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
+ break;
+ }
+ case Type::kTexture_Kind: {
+ // FIXME: should support more than 2D
+ this->writeInstruction(SpvOpTypeImage, result,
+ this->getType(*fContext.fFloat_Type, layout),
+ SpvDim2D, type.isDepth(), type.isArrayed(),
+ type.isMultisampled(), 1,
+ SpvImageFormatUnknown, fConstantBuffer);
+ fImageTypeMap[key] = result;
+ break;
+ }
default:
if (type == *fContext.fVoid_Type) {
this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
@@ -819,6 +842,18 @@
}
break;
}
+ case kSampledImage_SpecialIntrinsic: {
+ SkASSERT(2 == c.fArguments.size());
+ SpvId img = this->writeExpression(*c.fArguments[0], out);
+ SpvId sampler = this->writeExpression(*c.fArguments[1], out);
+ this->writeInstruction(SpvOpSampledImage,
+ this->getType(c.fType),
+ result,
+ img,
+ sampler,
+ out);
+ break;
+ }
case kSubpassLoad_SpecialIntrinsic: {
SpvId img = this->writeExpression(*c.fArguments[0], out);
std::vector<std::unique_ptr<Expression>> args;
@@ -2708,7 +2743,9 @@
} else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
storageClass = SpvStorageClassOutput;
} else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
- if (var->fType.kind() == Type::kSampler_Kind) {
+ if (var->fType.kind() == Type::kSampler_Kind ||
+ var->fType.kind() == Type::kSeparateSampler_Kind ||
+ var->fType.kind() == Type::kTexture_Kind) {
storageClass = SpvStorageClassUniformConstant;
} else {
storageClass = SpvStorageClassUniform;
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.h b/src/sksl/SkSLSPIRVCodeGenerator.h
index aff2e7f..8f14b46 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.h
+++ b/src/sksl/SkSLSPIRVCodeGenerator.h
@@ -134,6 +134,7 @@
kMod_SpecialIntrinsic,
kDFdy_SpecialIntrinsic,
kSaturate_SpecialIntrinsic,
+ kSampledImage_SpecialIntrinsic,
kSubpassLoad_SpecialIntrinsic,
kTexture_SpecialIntrinsic,
};
diff --git a/src/sksl/ir/SkSLType.h b/src/sksl/ir/SkSLType.h
index 9c0fcc8..6b474b1 100644
--- a/src/sksl/ir/SkSLType.h
+++ b/src/sksl/ir/SkSLType.h
@@ -49,8 +49,10 @@
kMatrix_Kind,
kOther_Kind,
kSampler_Kind,
+ kSeparateSampler_Kind,
kScalar_Kind,
kStruct_Kind,
+ kTexture_Kind,
kVector_Kind
};
@@ -194,7 +196,7 @@
// Create a sampler type.
Type(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed, bool isMultisampled,
- bool isSampled)
+ bool isSampled, Type* textureType = nullptr)
: INHERITED(-1, kType_Kind, StringFragment())
, fNameString(name)
, fTypeKind(kSampler_Kind)
@@ -203,7 +205,9 @@
, fIsDepth(isDepth)
, fIsArrayed(isArrayed)
, fIsMultisampled(isMultisampled)
- , fIsSampled(isSampled) {
+ , fIsSampled(isSampled)
+ , fTextureType(textureType)
+ {
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
@@ -305,6 +309,14 @@
}
/**
+ * For texturesamplers, returns the type of texture it samples (e.g., sampler2D has
+ * a texture type of texture2D).
+ */
+ const Type* textureType() const {
+ return fTextureType;
+ }
+
+ /**
* For nullable types, returns the base type, otherwise returns the type itself.
*/
const Type& nonnullable() const {
@@ -349,27 +361,27 @@
}
SpvDim_ dimensions() const {
- SkASSERT(kSampler_Kind == fTypeKind);
+ SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fDimensions;
}
bool isDepth() const {
- SkASSERT(kSampler_Kind == fTypeKind);
+ SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fIsDepth;
}
bool isArrayed() const {
- SkASSERT(kSampler_Kind == fTypeKind);
+ SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fIsArrayed;
}
bool isMultisampled() const {
- SkASSERT(kSampler_Kind == fTypeKind);
+ SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fIsMultisampled;
}
bool isSampled() const {
- SkASSERT(kSampler_Kind == fTypeKind);
+ SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fIsSampled;
}
@@ -405,6 +417,7 @@
bool fIsMultisampled = false;
bool fIsSampled = false;
bool fHighPrecision = false;
+ const Type* fTextureType = nullptr;
};
} // namespace
diff --git a/src/sksl/sksl_gpu.inc b/src/sksl/sksl_gpu.inc
index 46fb124..dc76bda 100644
--- a/src/sksl/sksl_gpu.inc
+++ b/src/sksl/sksl_gpu.inc
@@ -254,6 +254,7 @@
$genIType findMSB($genIType value);
$genIType findMSB($genUType value);
+sampler2D makeSampler2D(texture2D texture, sampler sampler);
int2 textureSize($gsampler2DRect sampler);
half4 texture($gsampler1D sampler, float P);