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>
This commit is contained in:
Stephen White 2019-07-26 17:42:06 -04:00 committed by Skia Commit-Bot
parent 6f6d2de95c
commit ff5d7a2f90
11 changed files with 98 additions and 17 deletions

View File

@ -371,8 +371,10 @@ enum GrSLType {
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 @@ static constexpr bool GrSLTypeIsFloatType(GrSLType type) {
case kInt4_GrSLType:
case kUint_GrSLType:
case kUint2_GrSLType:
case kTexture2D_GrSLType:
case kSampler_GrSLType:
return false;
}
SkUNREACHABLE;
@ -531,6 +535,8 @@ static constexpr int GrSLTypeVecLength(GrSLType type) {
case kTexture2DSampler_GrSLType:
case kTextureExternalSampler_GrSLType:
case kTexture2DRectSampler_GrSLType:
case kTexture2D_GrSLType:
case kSampler_GrSLType:
return -1;
}
SkUNREACHABLE;
@ -612,6 +618,8 @@ static constexpr bool GrSLTypeIsCombinedSamplerType(GrSLType type) {
case kUShort2_GrSLType:
case kUShort3_GrSLType:
case kUShort4_GrSLType:
case kTexture2D_GrSLType:
case kSampler_GrSLType:
return false;
}
SkUNREACHABLE;

View File

@ -92,6 +92,10 @@ const char* GrGLSLTypeString(GrSLType t) {
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

View File

@ -85,6 +85,8 @@ static uint32_t grsltype_to_alignment_mask(GrSLType type) {
case kTexture2DSampler_GrSLType:
case kTextureExternalSampler_GrSLType:
case kTexture2DRectSampler_GrSLType:
case kSampler_GrSLType:
case kTexture2D_GrSLType:
break;
}
SK_ABORT("Unexpected type");
@ -166,6 +168,8 @@ static inline uint32_t grsltype_to_mtl_size(GrSLType type) {
case kTexture2DSampler_GrSLType:
case kTextureExternalSampler_GrSLType:
case kTexture2DRectSampler_GrSLType:
case kSampler_GrSLType:
case kTexture2D_GrSLType:
break;
}
SK_ABORT("Unexpected type");

View File

@ -84,6 +84,8 @@ static uint32_t grsltype_to_alignment_mask(GrSLType type) {
case kTexture2DSampler_GrSLType:
case kTextureExternalSampler_GrSLType:
case kTexture2DRectSampler_GrSLType:
case kSampler_GrSLType:
case kTexture2D_GrSLType:
break;
}
SK_ABORT("Unexpected type");
@ -166,6 +168,8 @@ static inline uint32_t grsltype_to_vk_size(GrSLType type) {
case kTexture2DSampler_GrSLType:
case kTextureExternalSampler_GrSLType:
case kTexture2DRectSampler_GrSLType:
case kSampler_GrSLType:
case kTexture2D_GrSLType:
break;
}
SK_ABORT("Unexpected type");

View File

@ -55,6 +55,8 @@ static inline int grsltype_to_location_size(GrSLType type) {
case kHalf4x4_GrSLType:
return 4;
case kTexture2DSampler_GrSLType:
case kSampler_GrSLType:
case kTexture2D_GrSLType:
return 0;
case kTextureExternalSampler_GrSLType:
return 0;

View File

@ -211,6 +211,8 @@ Compiler::Compiler(Flags flags)
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,

View File

@ -91,8 +91,9 @@ public:
, 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 @@ public:
// 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 @@ public:
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 @@ public:
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;

View File

@ -101,6 +101,8 @@ void SPIRVCodeGenerator::setupIntrinsics() {
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 @@ void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& ou
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 @@ SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layou
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 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIn
}
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 @@ void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclaratio
} 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;

View File

@ -134,6 +134,7 @@ private:
kMod_SpecialIntrinsic,
kDFdy_SpecialIntrinsic,
kSaturate_SpecialIntrinsic,
kSampledImage_SpecialIntrinsic,
kSubpassLoad_SpecialIntrinsic,
kTexture_SpecialIntrinsic,
};

View File

@ -49,8 +49,10 @@ public:
kMatrix_Kind,
kOther_Kind,
kSampler_Kind,
kSeparateSampler_Kind,
kScalar_Kind,
kStruct_Kind,
kTexture_Kind,
kVector_Kind
};
@ -194,7 +196,7 @@ public:
// 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 @@ public:
, fIsDepth(isDepth)
, fIsArrayed(isArrayed)
, fIsMultisampled(isMultisampled)
, fIsSampled(isSampled) {
, fIsSampled(isSampled)
, fTextureType(textureType)
{
fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size();
}
@ -304,6 +308,14 @@ public:
return *fComponentType;
}
/**
* 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.
*/
@ -349,27 +361,27 @@ public:
}
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 @@ private:
bool fIsMultisampled = false;
bool fIsSampled = false;
bool fHighPrecision = false;
const Type* fTextureType = nullptr;
};
} // namespace

View File

@ -254,6 +254,7 @@ $genIType findLSB($genUType value);
$genIType findMSB($genIType value);
$genIType findMSB($genUType value);
sampler2D makeSampler2D(texture2D texture, sampler sampler);
int2 textureSize($gsampler2DRect sampler);
half4 texture($gsampler1D sampler, float P);