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

View File

@ -92,6 +92,10 @@ const char* GrGLSLTypeString(GrSLType t) {
return "ubyte3"; return "ubyte3";
case kUByte4_GrSLType: case kUByte4_GrSLType:
return "ubyte4"; return "ubyte4";
case kTexture2D_GrSLType:
return "texture2D";
case kSampler_GrSLType:
return "sampler";
} }
SK_ABORT("Unknown shader var type."); SK_ABORT("Unknown shader var type.");
return ""; // suppress warning return ""; // suppress warning

View File

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

View File

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

View File

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

View File

@ -211,6 +211,8 @@ Compiler::Compiler(Flags flags)
ADD_TYPE(GSamplerCubeArrayShadow); ADD_TYPE(GSamplerCubeArrayShadow);
ADD_TYPE(FragmentProcessor); ADD_TYPE(FragmentProcessor);
ADD_TYPE(SkRasterPipeline); ADD_TYPE(SkRasterPipeline);
ADD_TYPE(Sampler);
ADD_TYPE(Texture2D);
StringFragment skCapsName("sk_Caps"); StringFragment skCapsName("sk_Caps");
Variable* skCaps = new Variable(-1, Modifiers(), skCapsName, Variable* skCaps = new Variable(-1, Modifiers(), skCapsName,

View File

@ -91,8 +91,9 @@ public:
, fDouble4x2_Type(new Type("double4x2", *fDouble_Type, 4, 2)) , fDouble4x2_Type(new Type("double4x2", *fDouble_Type, 4, 2))
, fDouble4x3_Type(new Type("double4x3", *fDouble_Type, 4, 3)) , fDouble4x3_Type(new Type("double4x3", *fDouble_Type, 4, 3))
, fDouble4x4_Type(new Type("double4x4", *fDouble_Type, 4, 4)) , 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)) , 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)) , fSampler3D_Type(new Type("sampler3D", SpvDim3D, false, false, false, true))
, fSamplerExternalOES_Type(new Type("samplerExternalOES", SpvDim2D, false, false, , fSamplerExternalOES_Type(new Type("samplerExternalOES", SpvDim2D, false, false,
false, true)) false, true))
@ -116,6 +117,7 @@ public:
// Related to below FIXME, gsampler*s don't currently expand to cover integer case. // Related to below FIXME, gsampler*s don't currently expand to cover integer case.
, fISampler2D_Type(new Type("isampler2D", SpvDim2D, false, false, false, true)) , 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. // FIXME express these as "gimage2D" that expand to image2D, iimage2D, and uimage2D.
, fImage2D_Type(new Type("image2D", SpvDim2D, false, false, false, true)) , fImage2D_Type(new Type("image2D", SpvDim2D, false, false, false, true))
, fIImage2D_Type(new Type("iimage2D", 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> fDouble4x3_Type;
const std::unique_ptr<Type> fDouble4x4_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> fSampler1D_Type;
const std::unique_ptr<Type> fSampler2D_Type; const std::unique_ptr<Type> fSampler2D_Type;
const std::unique_ptr<Type> fSampler3D_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> fSamplerCubeArrayShadow_Type;
const std::unique_ptr<Type> fISampler2D_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> fImage2D_Type;
const std::unique_ptr<Type> fIImage2D_Type; const std::unique_ptr<Type> fIImage2D_Type;

View File

@ -101,6 +101,8 @@ void SPIRVCodeGenerator::setupIntrinsics() {
fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy); fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy);
fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth, fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
SpvOpUndef, SpvOpUndef, SpvOpUndef); SpvOpUndef, SpvOpUndef, SpvOpUndef);
fIntrinsicMap[String("makeSampler2D")] = SPECIAL(SampledImage);
fIntrinsicMap[String("texture")] = SPECIAL(Texture); fIntrinsicMap[String("texture")] = SPECIAL(Texture);
fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad); fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
@ -206,6 +208,7 @@ void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& ou
case SpvOpTypeStruct: // fall through case SpvOpTypeStruct: // fall through
case SpvOpTypeImage: // fall through case SpvOpTypeImage: // fall through
case SpvOpTypeSampledImage: // fall through case SpvOpTypeSampledImage: // fall through
case SpvOpTypeSampler: // fall through
case SpvOpVariable: // fall through case SpvOpVariable: // fall through
case SpvOpFunction: // fall through case SpvOpFunction: // fall through
case SpvOpFunctionParameter: // fall through case SpvOpFunctionParameter: // fall through
@ -526,22 +529,42 @@ SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layou
case Type::kSampler_Kind: { case Type::kSampler_Kind: {
SpvId image = result; SpvId image = result;
if (SpvDimSubpassData != type.dimensions()) { if (SpvDimSubpassData != type.dimensions()) {
image = this->nextId(); if (type.textureType()) {
image = this->getType(*type.textureType(), layout);
} else {
image = nextId();
}
} }
if (SpvDimBuffer == type.dimensions()) { if (SpvDimBuffer == type.dimensions()) {
fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer); fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
} }
this->writeInstruction(SpvOpTypeImage, image, if (!type.textureType()) {
this->getType(*fContext.fFloat_Type, layout), this->writeInstruction(SpvOpTypeImage, image,
type.dimensions(), type.isDepth(), type.isArrayed(), this->getType(*fContext.fFloat_Type, layout),
type.isMultisampled(), type.isSampled() ? 1 : 2, type.dimensions(), type.isDepth(), type.isArrayed(),
SpvImageFormatUnknown, fConstantBuffer); type.isMultisampled(), type.isSampled() ? 1 : 2,
fImageTypeMap[key] = image; SpvImageFormatUnknown, fConstantBuffer);
fImageTypeMap[key] = image;
}
if (SpvDimSubpassData != type.dimensions()) { if (SpvDimSubpassData != type.dimensions()) {
this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer); this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
} }
break; 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: default:
if (type == *fContext.fVoid_Type) { if (type == *fContext.fVoid_Type) {
this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer); this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
@ -819,6 +842,18 @@ SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIn
} }
break; 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: { case kSubpassLoad_SpecialIntrinsic: {
SpvId img = this->writeExpression(*c.fArguments[0], out); SpvId img = this->writeExpression(*c.fArguments[0], out);
std::vector<std::unique_ptr<Expression>> args; 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) { } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
storageClass = SpvStorageClassOutput; storageClass = SpvStorageClassOutput;
} else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) { } 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; storageClass = SpvStorageClassUniformConstant;
} else { } else {
storageClass = SpvStorageClassUniform; storageClass = SpvStorageClassUniform;

View File

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

View File

@ -49,8 +49,10 @@ public:
kMatrix_Kind, kMatrix_Kind,
kOther_Kind, kOther_Kind,
kSampler_Kind, kSampler_Kind,
kSeparateSampler_Kind,
kScalar_Kind, kScalar_Kind,
kStruct_Kind, kStruct_Kind,
kTexture_Kind,
kVector_Kind kVector_Kind
}; };
@ -194,7 +196,7 @@ public:
// Create a sampler type. // Create a sampler type.
Type(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed, bool isMultisampled, Type(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayed, bool isMultisampled,
bool isSampled) bool isSampled, Type* textureType = nullptr)
: INHERITED(-1, kType_Kind, StringFragment()) : INHERITED(-1, kType_Kind, StringFragment())
, fNameString(name) , fNameString(name)
, fTypeKind(kSampler_Kind) , fTypeKind(kSampler_Kind)
@ -203,7 +205,9 @@ public:
, fIsDepth(isDepth) , fIsDepth(isDepth)
, fIsArrayed(isArrayed) , fIsArrayed(isArrayed)
, fIsMultisampled(isMultisampled) , fIsMultisampled(isMultisampled)
, fIsSampled(isSampled) { , fIsSampled(isSampled)
, fTextureType(textureType)
{
fName.fChars = fNameString.c_str(); fName.fChars = fNameString.c_str();
fName.fLength = fNameString.size(); fName.fLength = fNameString.size();
} }
@ -304,6 +308,14 @@ public:
return *fComponentType; 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. * For nullable types, returns the base type, otherwise returns the type itself.
*/ */
@ -349,27 +361,27 @@ public:
} }
SpvDim_ dimensions() const { SpvDim_ dimensions() const {
SkASSERT(kSampler_Kind == fTypeKind); SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fDimensions; return fDimensions;
} }
bool isDepth() const { bool isDepth() const {
SkASSERT(kSampler_Kind == fTypeKind); SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fIsDepth; return fIsDepth;
} }
bool isArrayed() const { bool isArrayed() const {
SkASSERT(kSampler_Kind == fTypeKind); SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fIsArrayed; return fIsArrayed;
} }
bool isMultisampled() const { bool isMultisampled() const {
SkASSERT(kSampler_Kind == fTypeKind); SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fIsMultisampled; return fIsMultisampled;
} }
bool isSampled() const { bool isSampled() const {
SkASSERT(kSampler_Kind == fTypeKind); SkASSERT(kSampler_Kind == fTypeKind || kTexture_Kind == fTypeKind);
return fIsSampled; return fIsSampled;
} }
@ -405,6 +417,7 @@ private:
bool fIsMultisampled = false; bool fIsMultisampled = false;
bool fIsSampled = false; bool fIsSampled = false;
bool fHighPrecision = false; bool fHighPrecision = false;
const Type* fTextureType = nullptr;
}; };
} // namespace } // namespace

View File

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