public:
GrTexture* asTexture() override { return this; }
const GrTexture* asTexture() const override { return this; }
+ GrSLType samplerType() const { return fSamplerType; }
/**
* Return the native ID or handle to the texture, depending on the
inline const GrTexturePriv texturePriv() const;
protected:
- GrTexture(GrGpu*, LifeCycle, const GrSurfaceDesc&, bool wasMipMapDataProvided);
+ GrTexture(GrGpu*, LifeCycle, const GrSurfaceDesc&, GrSLType, bool wasMipMapDataProvided);
void validateDesc() const;
kValid_MipMapsStatus
};
+ GrSLType fSamplerType;
MipMapsStatus fMipMapsStatus;
- int fMaxMipMapLevel;
+ int fMaxMipMapLevel;
friend class GrTexturePriv;
explicit GrTextureAccess(GrTexture*,
GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode,
- SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode);
+ SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode,
+ GrShaderFlags visibility = kFragment_GrShaderFlag);
- void reset(GrTexture*, const GrTextureParams&);
+ void reset(GrTexture*, const GrTextureParams&,
+ GrShaderFlags visibility = kFragment_GrShaderFlag);
void reset(GrTexture*,
GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode,
- SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode);
+ SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode,
+ GrShaderFlags visibility = kFragment_GrShaderFlag);
bool operator==(const GrTextureAccess& that) const {
- return this->getTexture() == that.getTexture() && fParams == that.fParams;
+ return this->getTexture() == that.getTexture() &&
+ fParams == that.fParams &&
+ fVisibility == that.fVisibility;
}
bool operator!=(const GrTextureAccess& other) const { return !(*this == other); }
GrTexture* getTexture() const { return fTexture.get(); }
+ GrShaderFlags getVisibility() const { return fVisibility; }
/**
* For internal use by GrProcessor.
ProgramTexture fTexture;
GrTextureParams fParams;
+ GrShaderFlags fVisibility;
typedef SkNoncopyable INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
GrTexture::GrTexture(GrGpu* gpu, LifeCycle lifeCycle, const GrSurfaceDesc& desc,
- bool wasMipMapDataProvided)
- : INHERITED(gpu, lifeCycle, desc) {
+ GrSLType samplerType, bool wasMipMapDataProvided)
+ : INHERITED(gpu, lifeCycle, desc)
+ , fSamplerType(samplerType) {
if (!this->isExternal() && !GrPixelConfigIsCompressed(desc.fConfig) &&
!desc.fTextureStorageAllocator.fAllocateTextureStorage) {
GrScratchKey key;
GrTextureAccess::GrTextureAccess(GrTexture* texture,
GrTextureParams::FilterMode filterMode,
- SkShader::TileMode tileXAndY) {
- this->reset(texture, filterMode, tileXAndY);
+ SkShader::TileMode tileXAndY,
+ GrShaderFlags visibility) {
+ this->reset(texture, filterMode, tileXAndY, visibility);
}
-
void GrTextureAccess::reset(GrTexture* texture,
- const GrTextureParams& params) {
+ const GrTextureParams& params,
+ GrShaderFlags visibility) {
SkASSERT(texture);
fTexture.set(SkRef(texture), kRead_GrIOType);
fParams = params;
+ fVisibility = visibility;
}
void GrTextureAccess::reset(GrTexture* texture,
GrTextureParams::FilterMode filterMode,
- SkShader::TileMode tileXAndY) {
+ SkShader::TileMode tileXAndY,
+ GrShaderFlags visibility) {
SkASSERT(texture);
fTexture.set(SkRef(texture), kRead_GrIOType);
fParams.reset(tileXAndY, filterMode);
+ fVisibility = visibility;
}
fTransferBufferType = kNone_TransferBufferType;
fMaxFragmentUniformVectors = 0;
fMaxVertexAttributes = 0;
- fMaxFragmentTextureUnits = 0;
fUnpackRowLengthSupport = false;
fUnpackFlipYSupport = false;
fPackRowLengthSupport = false;
fUseNonVBOVertexAndIndexDynamicData = false;
fIsCoreProfile = false;
fBindFragDataLocationSupport = false;
- fExternalTextureSupport = false;
fRectangleTextureSupport = false;
fTextureSwizzleSupport = false;
fSRGBWriteControl = false;
}
}
GR_GL_GetIntegerv(gli, GR_GL_MAX_VERTEX_ATTRIBS, &fMaxVertexAttributes);
- GR_GL_GetIntegerv(gli, GR_GL_MAX_TEXTURE_IMAGE_UNITS, &fMaxFragmentTextureUnits);
if (kGL_GrGLStandard == standard) {
fUnpackRowLengthSupport = true;
fBindUniformLocationSupport = false;
#endif
- if (ctxInfo.hasExtension("GL_OES_EGL_image_external")) {
- if (ctxInfo.glslGeneration() == k110_GrGLSLGeneration) {
- fExternalTextureSupport = true;
- } else if (ctxInfo.hasExtension("GL_OES_EGL_image_external_essl3") ||
- ctxInfo.hasExtension("OES_EGL_image_external_essl3")) {
- // At least one driver has been found that has this extension without the "GL_" prefix.
- fExternalTextureSupport = true;
- }
- }
-
if (kGL_GrGLStandard == standard) {
if (version >= GR_GL_VER(3, 1) || ctxInfo.hasExtension("GL_ARB_texture_rectangle")) {
// We also require textureSize() support for rectangle 2D samplers which was added in
glslCaps->fPLSPathRenderingSupport = false;
}
+ // Protect ourselves against tracking huge amounts of texture state.
+ static const uint8_t kMaxSaneSamplers = 32;
+ GrGLint maxSamplers;
+ GR_GL_GetIntegerv(gli, GR_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxSamplers);
+ glslCaps->fMaxVertexSamplers = SkTMin<GrGLint>(kMaxSaneSamplers, maxSamplers);
+ if (glslCaps->fGeometryShaderSupport) {
+ GR_GL_GetIntegerv(gli, GR_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &maxSamplers);
+ glslCaps->fMaxGeometrySamplers = SkTMin<GrGLint>(kMaxSaneSamplers, maxSamplers);
+ }
+ GR_GL_GetIntegerv(gli, GR_GL_MAX_TEXTURE_IMAGE_UNITS, &maxSamplers);
+ glslCaps->fMaxFragmentSamplers = SkTMin<GrGLint>(kMaxSaneSamplers, maxSamplers);
+ GR_GL_GetIntegerv(gli, GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxSamplers);
+ glslCaps->fMaxCombinedSamplers = SkTMin<GrGLint>(kMaxSaneSamplers, maxSamplers);
+
/**************************************************************************
* GrCaps fields
**************************************************************************/
glslCaps->fSecondaryOutputExtensionString = "GL_EXT_blend_func_extended";
}
- if (fExternalTextureSupport) {
+ if (ctxInfo.hasExtension("GL_OES_EGL_image_external")) {
+ if (ctxInfo.glslGeneration() == k110_GrGLSLGeneration) {
+ glslCaps->fExternalTextureSupport = true;
+ } else if (ctxInfo.hasExtension("GL_OES_EGL_image_external_essl3") ||
+ ctxInfo.hasExtension("OES_EGL_image_external_essl3")) {
+ // At least one driver has been found that has this extension without the "GL_" prefix.
+ glslCaps->fExternalTextureSupport = true;
+ }
+ }
+
+ if (glslCaps->fExternalTextureSupport) {
if (ctxInfo.glslGeneration() == k110_GrGLSLGeneration) {
glslCaps->fExternalTextureExtensionString = "GL_OES_EGL_image_external";
} else {
r.appendf("Invalidate FB Type: %s\n", kInvalidateFBTypeStr[fInvalidateFBType]);
r.appendf("Map Buffer Type: %s\n", kMapBufferTypeStr[fMapBufferType]);
r.appendf("Max FS Uniform Vectors: %d\n", fMaxFragmentUniformVectors);
- r.appendf("Max FS Texture Units: %d\n", fMaxFragmentTextureUnits);
r.appendf("Max Vertex Attributes: %d\n", fMaxVertexAttributes);
r.appendf("Unpack Row length support: %s\n", (fUnpackRowLengthSupport ? "YES": "NO"));
r.appendf("Unpack Flip Y support: %s\n", (fUnpackFlipYSupport ? "YES": "NO"));
r.appendf("RGBA 8888 pixel ops are slow: %s\n", (fRGBA8888PixelsOpsAreSlow ? "YES" : "NO"));
r.appendf("Partial FBO read is slow: %s\n", (fPartialFBOReadIsSlow ? "YES" : "NO"));
r.appendf("Bind uniform location support: %s\n", (fBindUniformLocationSupport ? "YES" : "NO"));
- r.appendf("External texture support: %s\n", (fExternalTextureSupport ? "YES" : "NO"));
r.appendf("Rectangle texture support: %s\n", (fRectangleTextureSupport? "YES" : "NO"));
r.appendf("Texture swizzle support: %s\n", (fTextureSwizzleSupport ? "YES" : "NO"));
/// maximum number of attribute values per vertex
int maxVertexAttributes() const { return fMaxVertexAttributes; }
- /// maximum number of texture units accessible in the fragment shader.
- int maxFragmentTextureUnits() const { return fMaxFragmentTextureUnits; }
-
/**
* Depending on the ES extensions present the BGRA external format may
* correspond to either a BGRA or RGBA internalFormat. On desktop GL it is
bool bindUniformLocationSupport() const { return fBindUniformLocationSupport; }
- /// Are textures with GL_TEXTURE_EXTERNAL_OES type supported.
- bool externalTextureSupport() const { return fExternalTextureSupport; }
-
/// Are textures with GL_TEXTURE_RECTANGLE type supported.
bool rectangleTextureSupport() const { return fRectangleTextureSupport; }
int fMaxFragmentUniformVectors;
int fMaxVertexAttributes;
- int fMaxFragmentTextureUnits;
MSFBOType fMSFBOType;
InvalidateFBType fInvalidateFBType;
bool fRGBA8888PixelsOpsAreSlow : 1;
bool fPartialFBOReadIsSlow : 1;
bool fBindUniformLocationSupport : 1;
- bool fExternalTextureSupport : 1;
bool fRectangleTextureSupport : 1;
bool fTextureSwizzleSupport : 1;
bool fMipMapLevelAndLodControlSupport : 1;
#define GR_GL_MAX_VARYING_VECTORS 0x8DFC
#define GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
#define GR_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GR_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29
#define GR_GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
#define GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
#define GR_GL_SHADER_TYPE 0x8B4F
SkASSERT(ctx);
fCaps.reset(SkRef(ctx->caps()));
- fHWBoundTextureUniqueIDs.reset(this->glCaps().maxFragmentTextureUnits());
+ fHWBoundTextureUniqueIDs.reset(this->glCaps().glslCaps()->maxCombinedSamplers());
GrGLClearErr(this->glInterface());
if (gPrintStartupSpew) {
// This combination is not supported.
return nullptr;
}
- if (!this->glCaps().externalTextureSupport()) {
+ if (!this->glCaps().glslCaps()->externalTextureSupport()) {
return nullptr;
}
} else if (GR_GL_TEXTURE_RECTANGLE == idDesc.fInfo.fTarget) {
SkASSERT(3 == SK_ARRAY_COUNT(fCopyPrograms));
for (int i = 0; i < 3; ++i) {
if (kSamplerExternal_GrSLType == kSamplerTypes[i] &&
- !this->glCaps().externalTextureSupport()) {
+ !this->glCaps().glslCaps()->externalTextureSupport()) {
continue;
}
if (kSampler2DRect_GrSLType == kSamplerTypes[i] &&
params[2] = 800;
params[3] = 600;
break;
+ case GR_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
+ case GR_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS:
case GR_GL_MAX_TEXTURE_IMAGE_UNITS:
+ case GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
*params = 8;
break;
case GR_GL_MAX_TEXTURE_COORDS:
#define GPUGL static_cast<GrGLGpu*>(this->getGpu())
#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
+inline static GrSLType sampler_type(const GrGLTexture::IDDesc& idDesc, const GrGLGpu* gpu) {
+ if (idDesc.fInfo.fTarget == GR_GL_TEXTURE_EXTERNAL) {
+ SkASSERT(gpu->glCaps().glslCaps()->externalTextureSupport());
+ return kSamplerExternal_GrSLType;
+ } else if (idDesc.fInfo.fTarget == GR_GL_TEXTURE_RECTANGLE) {
+ SkASSERT(gpu->glCaps().rectangleTextureSupport());
+ return kSampler2DRect_GrSLType;
+ } else {
+ SkASSERT(idDesc.fInfo.fTarget == GR_GL_TEXTURE_2D);
+ return kSampler2D_GrSLType;
+ }
+}
+
// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrGLTexture::GrGLTexture(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc)
: GrSurface(gpu, idDesc.fLifeCycle, desc)
- , INHERITED(gpu, idDesc.fLifeCycle, desc, false) {
+ , INHERITED(gpu, idDesc.fLifeCycle, desc, sampler_type(idDesc, gpu), false) {
this->init(desc, idDesc);
this->registerWithCache();
}
GrGLTexture::GrGLTexture(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc,
bool wasMipMapDataProvided)
: GrSurface(gpu, idDesc.fLifeCycle, desc)
- , INHERITED(gpu, idDesc.fLifeCycle, desc, wasMipMapDataProvided) {
+ , INHERITED(gpu, idDesc.fLifeCycle, desc, sampler_type(idDesc, gpu), wasMipMapDataProvided) {
this->init(desc, idDesc);
this->registerWithCache();
}
GrGLTexture::GrGLTexture(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc, Derived)
: GrSurface(gpu, idDesc.fLifeCycle, desc)
- , INHERITED(gpu, idDesc.fLifeCycle, desc, false) {
+ , INHERITED(gpu, idDesc.fLifeCycle, desc, sampler_type(idDesc, gpu), false) {
this->init(desc, idDesc);
}
GrGLSLExpr4 inputColor;
GrGLSLExpr4 inputCoverage;
- if (!builder.emitAndInstallProcs(&inputColor,
- &inputCoverage,
- gpu->glCaps().maxFragmentTextureUnits())) {
+ if (!builder.emitAndInstallProcs(&inputColor, &inputCoverage)) {
builder.cleanupFragmentProcessors();
return nullptr;
}
GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
: INHERITED(args)
, fGpu(gpu)
- , fSamplerUniforms(4)
, fVaryingHandler(this)
, fUniformHandler(this) {
}
return fGpu->ctxInfo().caps()->glslCaps();
}
-static GrSLType get_sampler_type(const GrTextureAccess& access) {
- GrGLTexture* glTexture = static_cast<GrGLTexture*>(access.getTexture());
- if (glTexture->target() == GR_GL_TEXTURE_EXTERNAL) {
- return kSamplerExternal_GrSLType;
- } else if (glTexture->target() == GR_GL_TEXTURE_RECTANGLE) {
- return kSampler2DRect_GrSLType;
- } else {
- SkASSERT(glTexture->target() == GR_GL_TEXTURE_2D);
- return kSampler2D_GrSLType;
- }
-}
-
-void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor,
- GrGLSLTextureSampler::TextureSamplerArray* outSamplers) {
- int numTextures = processor.numTextures();
- UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures);
- SkString name;
- for (int t = 0; t < numTextures; ++t) {
- name.printf("Sampler%d", t);
- GrSLType samplerType = get_sampler_type(processor.textureAccess(t));
- localSamplerUniforms[t] = fUniformHandler.addUniform(kFragment_GrShaderFlag, samplerType,
- kDefault_GrSLPrecision, name.c_str());
- outSamplers->emplace_back(localSamplerUniforms[t], processor.textureAccess(t));
- if (kSamplerExternal_GrSLType == samplerType) {
- const char* externalFeatureString = this->glslCaps()->externalTextureExtensionString();
- // We shouldn't ever create a GrGLTexture that requires external sampler type
- SkASSERT(externalFeatureString);
- fFS.addFeature(1 << GrGLSLFragmentShaderBuilder::kExternalTexture_GLSLPrivateFeature,
- externalFeatureString);
- }
- }
-}
-
bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader,
GrGLuint programId,
GrGLenum type,
private:
GrGLProgramBuilder(GrGLGpu*, const DrawArgs&);
- void emitSamplers(const GrProcessor&,
- GrGLSLTextureSampler::TextureSamplerArray* outSamplers) override;
-
bool compileAndAttachShaders(GrGLSLShaderBuilder& shader,
GrGLuint programId,
GrGLenum type,
GrGLSLVaryingHandler* varyingHandler() override { return &fVaryingHandler; }
- GrGLGpu* fGpu;
- typedef GrGLSLUniformHandler::UniformHandle UniformHandle;
- SkTArray<UniformHandle> fSamplerUniforms;
-
- GrGLVaryingHandler fVaryingHandler;
- GrGLUniformHandler fUniformHandler;
+ GrGLGpu* fGpu;
+ GrGLVaryingHandler fVaryingHandler;
+ GrGLUniformHandler fUniformHandler;
typedef GrGLSLProgramBuilder INHERITED;
};
fMultisampleInterpolationSupport = false;
fSampleVariablesSupport = false;
fSampleMaskOverrideCoverageSupport = false;
+ fExternalTextureSupport = false;
fVersionDeclString = nullptr;
fShaderDerivativeExtensionString = nullptr;
fFragCoordConventionsExtensionString = nullptr;
fSampleVariablesExtensionString = nullptr;
fFBFetchColorName = nullptr;
fFBFetchExtensionString = nullptr;
+ fMaxVertexSamplers = 0;
+ fMaxGeometrySamplers = 0;
+ fMaxFragmentSamplers = 0;
+ fMaxCombinedSamplers = 0;
fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction;
}
r.appendf("Sample variables support: %s\n", (fSampleVariablesSupport ? "YES" : "NO"));
r.appendf("Sample mask override coverage support: %s\n", (fSampleMaskOverrideCoverageSupport ?
"YES" : "NO"));
+ r.appendf("External texture support: %s\n", (fExternalTextureSupport ? "YES" : "NO"));
+ r.appendf("Max VS Samplers: %d\n", fMaxVertexSamplers);
+ r.appendf("Max GS Samplers: %d\n", fMaxGeometrySamplers);
+ r.appendf("Max FS Samplers: %d\n", fMaxFragmentSamplers);
+ r.appendf("Max Combined Samplers: %d\n", fMaxFragmentSamplers);
r.appendf("Advanced blend equation interaction: %s\n",
kAdvBlendEqInteractionStr[fAdvBlendEqInteraction]);
return r;
bool sampleMaskOverrideCoverageSupport() const { return fSampleMaskOverrideCoverageSupport; }
+ bool externalTextureSupport() const { return fExternalTextureSupport; }
+
AdvBlendEqInteraction advBlendEqInteraction() const { return fAdvBlendEqInteraction; }
bool mustEnableAdvBlendEqs() const {
}
const char* externalTextureExtensionString() const {
+ SkASSERT(this->externalTextureSupport());
return fExternalTextureExtensionString;
}
return fSampleVariablesExtensionString;
}
+ int maxVertexSamplers() const { return fMaxVertexSamplers; }
+
+ int maxGeometrySamplers() const { return fMaxGeometrySamplers; }
+
+ int maxFragmentSamplers() const { return fMaxFragmentSamplers; }
+
+ int maxCombinedSamplers() const { return fMaxCombinedSamplers; }
+
/**
* Given a texture's config, this determines what swizzle must be appended to accesses to the
* texture in generated shader code. Swizzling may be implemented in texture parameters or a
bool fMultisampleInterpolationSupport : 1;
bool fSampleVariablesSupport : 1;
bool fSampleMaskOverrideCoverageSupport : 1;
+ bool fExternalTextureSupport : 1;
// Used for specific driver bug work arounds
bool fCanUseMinAndAbsTogether : 1;
const char* fFBFetchColorName;
const char* fFBFetchExtensionString;
+ uint8_t fMaxVertexSamplers;
+ uint8_t fMaxGeometrySamplers;
+ uint8_t fMaxFragmentSamplers;
+ uint8_t fMaxCombinedSamplers;
+
AdvBlendEqInteraction fAdvBlendEqInteraction;
GrSwizzle fConfigTextureSwizzle[kGrPixelConfigCnt];
, fStageIndex(-1)
, fArgs(args)
, fGeometryProcessor(nullptr)
- , fXferProcessor(nullptr) {
+ , fXferProcessor(nullptr)
+ , fSamplerUniforms(4)
+ , fNumVertexSamplers(0)
+ , fNumGeometrySamplers(0)
+ , fNumFragmentSamplers(0) {
+}
+
+void GrGLSLProgramBuilder::addFeature(GrShaderFlags shaders,
+ uint32_t featureBit,
+ const char* extensionName) {
+ if (shaders & kVertex_GrShaderFlag) {
+ fVS.addFeature(featureBit, extensionName);
+ }
+ if (shaders & kGeometry_GrShaderFlag) {
+ SkASSERT(this->glslCaps()->geometryShaderSupport());
+ fGS.addFeature(featureBit, extensionName);
+ }
+ if (shaders & kFragment_GrShaderFlag) {
+ fFS.addFeature(featureBit, extensionName);
+ }
}
bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor,
- GrGLSLExpr4* inputCoverage,
- int maxTextures) {
+ GrGLSLExpr4* inputCoverage) {
// First we loop over all of the installed processors and collect coord transforms. These will
// be sent to the GrGLSLPrimitiveProcessor in its emitCode function
const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
- int totalTextures = primProc.numTextures();
for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) {
const GrFragmentProcessor& processor = this->pipeline().getFragmentProcessor(i);
SkTArray<const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
processor.gatherCoordTransforms(&procCoords);
}
-
- totalTextures += processor.numTextures();
- if (totalTextures >= maxTextures) {
- GrCapsDebugf(this->caps(), "Program would use too many texture units\n");
- return false;
- }
}
this->emitAndInstallPrimProc(primProc, inputColor, inputCoverage);
primProc.getPixelLocalStorageState());
this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
}
- return true;
+
+ return this->checkSamplerCounts();
}
void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc,
fFS.codeAppend("}");
}
+void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor,
+ GrGLSLTextureSampler::TextureSamplerArray* outSamplers) {
+ int numTextures = processor.numTextures();
+ UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures);
+ SkString name;
+ for (int t = 0; t < numTextures; ++t) {
+ const GrTextureAccess& access = processor.textureAccess(t);
+ GrShaderFlags visibility = access.getVisibility();
+ if (visibility & kVertex_GrShaderFlag) {
+ ++fNumVertexSamplers;
+ }
+ if (visibility & kGeometry_GrShaderFlag) {
+ SkASSERT(this->primitiveProcessor().willUseGeoShader());
+ ++fNumGeometrySamplers;
+ }
+ if (visibility & kFragment_GrShaderFlag) {
+ ++fNumFragmentSamplers;
+ }
+ GrSLType samplerType = access.getTexture()->samplerType();
+ if (kSamplerExternal_GrSLType == samplerType) {
+ const char* externalFeatureString = this->glslCaps()->externalTextureExtensionString();
+ // We shouldn't ever create a GrGLTexture that requires external sampler type
+ SkASSERT(externalFeatureString);
+ this->addFeature(visibility,
+ 1 << GrGLSLShaderBuilder::kExternalTexture_GLSLPrivateFeature,
+ externalFeatureString);
+ }
+ name.printf("Sampler%d", t);
+ localSamplerUniforms[t] = this->uniformHandler()->addUniform(access.getVisibility(),
+ samplerType,
+ kDefault_GrSLPrecision,
+ name.c_str());
+ outSamplers->emplace_back(localSamplerUniforms[t], access);
+ }
+}
+
void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
// Swizzle the fragment shader outputs if necessary.
GrSwizzle swizzle;
}
}
+bool GrGLSLProgramBuilder::checkSamplerCounts() {
+ const GrGLSLCaps& glslCaps = *this->glslCaps();
+ if (fNumVertexSamplers > glslCaps.maxVertexSamplers()) {
+ GrCapsDebugf(this->caps(), "Program would use too many vertex samplers\n");
+ return false;
+ }
+ if (fNumGeometrySamplers > glslCaps.maxGeometrySamplers()) {
+ GrCapsDebugf(this->caps(), "Program would use too many geometry samplers\n");
+ return false;
+ }
+ if (fNumFragmentSamplers > glslCaps.maxFragmentSamplers()) {
+ GrCapsDebugf(this->caps(), "Program would use too many fragment samplers\n");
+ return false;
+ }
+ // If the same sampler is used in two different shaders, it counts as two combined samplers.
+ int numCombinedSamplers = fNumVertexSamplers + fNumGeometrySamplers + fNumFragmentSamplers;
+ if (numCombinedSamplers > glslCaps.maxCombinedSamplers()) {
+ GrCapsDebugf(this->caps(), "Program would use too many combined samplers\n");
+ return false;
+ }
+ return true;
+}
+
#ifdef SK_DEBUG
void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
SkASSERT(fFS.usedProcessorFeatures() == gp.requiredFeatures());
protected:
explicit GrGLSLProgramBuilder(const DrawArgs& args);
- bool emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage, int maxTextures);
+ void addFeature(GrShaderFlags shaders, uint32_t featureBit, const char* extensionName);
+
+ bool emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage);
void cleanupFragmentProcessors();
void finalizeShaders();
+ SkTArray<UniformHandle> fSamplerUniforms;
+
private:
// reset is called by program creator between each processor's emit code. It increments the
// stage offset for variable name mangling, and also ensures verfication variables in the
const GrGLSLExpr4& coverageIn,
bool ignoresCoverage,
GrPixelLocalStorageState plsState);
+ void emitSamplers(const GrProcessor& processor,
+ GrGLSLTextureSampler::TextureSamplerArray* outSamplers);
void emitFSOutputSwizzle(bool hasSecondaryOutput);
+ bool checkSamplerCounts();
#ifdef SK_DEBUG
void verify(const GrPrimitiveProcessor&);
void verify(const GrFragmentProcessor&);
#endif
- virtual void emitSamplers(const GrProcessor& processor,
- GrGLSLTextureSampler::TextureSamplerArray* outSamplers) = 0;
-
- GrGLSLPrimitiveProcessor::TransformsIn fCoordTransforms;
- GrGLSLPrimitiveProcessor::TransformsOut fOutCoords;
+ GrGLSLPrimitiveProcessor::TransformsIn fCoordTransforms;
+ GrGLSLPrimitiveProcessor::TransformsOut fOutCoords;
+ int fNumVertexSamplers;
+ int fNumGeometrySamplers;
+ int fNumFragmentSamplers;
};
#endif
GrGLSLShaderBuilder(GrGLSLProgramBuilder* program);
virtual ~GrGLSLShaderBuilder() {}
- /*
- * We put texture lookups in the base class because it is TECHNICALLY possible to do texture
- * lookups in any kind of shader. However, for the time being using these calls on non-fragment
- * shaders will result in a shader compilation error as texture sampler uniforms are only
- * visible to the fragment shader. It would not be hard to change this behavior, if someone
- * actually wants to do texture lookups in a non-fragment shader
- *
- * TODO if append texture lookup is used on a non-fragment shader, sampler uniforms should be
- * made visible to that shaders
- */
/** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
order of the result depends on the GrTextureAccess associated with the GrGLSLTextureSampler.
fShaderCaps.reset(new GrGLSLCaps(contextOptions));
- /**************************************************************************
- * GrVkCaps fields
- **************************************************************************/
- fMaxSampledTextures = 16; // Spec requires a minimum of 16 sampled textures per stage
-
this->init(contextOptions, vkInterface, physDev);
}
GR_VK_CALL(vkInterface, GetPhysicalDeviceMemoryProperties(physDev, &memoryProperties));
this->initGrCaps(properties, features, memoryProperties);
- this->initGLSLCaps(features);
+ this->initGLSLCaps(features, properties);
this->initConfigTexturableTable(vkInterface, physDev);
this->initConfigRenderableTable(vkInterface, physDev);
this->initStencilFormats(vkInterface, physDev);
this->initSampleCount(properties);
- fMaxSampledTextures = SkTMin(properties.limits.maxPerStageDescriptorSampledImages,
- properties.limits.maxPerStageDescriptorSamplers);
-
// Assuming since we will always map in the end to upload the data we might as well just map
// from the get go. There is no hard data to suggest this is faster or slower.
fGeometryBufferMapThreshold = 0;
fOversizedStencilSupport = true;
}
-void GrVkCaps::initGLSLCaps(const VkPhysicalDeviceFeatures& features) {
+void GrVkCaps::initGLSLCaps(const VkPhysicalDeviceFeatures& features,
+ const VkPhysicalDeviceProperties& properties) {
GrGLSLCaps* glslCaps = static_cast<GrGLSLCaps*>(fShaderCaps.get());
glslCaps->fVersionDeclString = "#version 310 es\n";
glslCaps->fDualSourceBlendingSupport = features.dualSrcBlend;
#endif
glslCaps->fIntegerSupport = true;
+
+ glslCaps->fMaxVertexSamplers =
+ glslCaps->fMaxGeometrySamplers =
+ glslCaps->fMaxFragmentSamplers = SkTMin(properties.limits.maxPerStageDescriptorSampledImages,
+ properties.limits.maxPerStageDescriptorSamplers);
+ glslCaps->fMaxCombinedSamplers = SkTMin(properties.limits.maxDescriptorSetSampledImages,
+ properties.limits.maxDescriptorSetSamplers);
}
static void format_supported_for_feature(const GrVkInterface* interface,
return fLinearStencilFormats;
}
- /**
- * Returns the max number of sampled textures we can use in a program. This number is the max of
- * max samplers and max sampled images. This number is technically the max sampled textures we
- * can have per stage, but we'll use it for the whole program since for now we only do texture
- * lookups in the fragment shader.
- */
- int maxSampledTextures() const {
- return fMaxSampledTextures;
- }
-
-
GrGLSLCaps* glslCaps() const { return reinterpret_cast<GrGLSLCaps*>(fShaderCaps.get()); }
private:
void initGrCaps(const VkPhysicalDeviceProperties&,
const VkPhysicalDeviceFeatures&,
const VkPhysicalDeviceMemoryProperties&);
- void initGLSLCaps(const VkPhysicalDeviceFeatures& features);
+ void initGLSLCaps(const VkPhysicalDeviceFeatures&, const VkPhysicalDeviceProperties&);
void initSampleCount(const VkPhysicalDeviceProperties& properties);
void initConfigRenderableTable(const GrVkInterface* interface, VkPhysicalDevice physDev);
void initConfigTexturableTable(const GrVkInterface* interface, VkPhysicalDevice physDev);
SkTArray<StencilFormat, true> fLinearStencilFormats;
SkTArray<StencilFormat, true> fStencilFormats;
- int fMaxSampledTextures;
-
typedef GrCaps INHERITED;
};
GrGLSLExpr4 inputColor;
GrGLSLExpr4 inputCoverage;
- if (!builder.emitAndInstallProcs(&inputColor,
- &inputCoverage,
- gpu->vkCaps().maxSampledTextures())) {
+ if (!builder.emitAndInstallProcs(&inputColor, &inputCoverage)) {
builder.cleanupFragmentProcessors();
return nullptr;
}
outputColor.setLayoutQualifier("location = 0");
}
-void GrVkProgramBuilder::emitSamplers(const GrProcessor& processor,
- GrGLSLTextureSampler::TextureSamplerArray* outSamplers) {
- int numTextures = processor.numTextures();
- UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures);
- SkString name;
- for (int t = 0; t < numTextures; ++t) {
- name.printf("%d", t);
- localSamplerUniforms[t] =
- fUniformHandler.addUniform(kFragment_GrShaderFlag,
- kSampler2D_GrSLType, kDefault_GrSLPrecision,
- name.c_str());
- outSamplers->emplace_back(localSamplerUniforms[t], processor.textureAccess(t));
- }
-}
-
VkShaderStageFlags visibility_to_vk_stage_flags(uint32_t visibility) {
VkShaderStageFlags flags = 0;
private:
GrVkProgramBuilder(GrVkGpu*, const DrawArgs&);
- void emitSamplers(const GrProcessor&,
- GrGLSLTextureSampler::TextureSamplerArray* outSamplers) override;
-
GrVkProgram* finalize(const DrawArgs& args,
GrPrimitiveType primitiveType,
const GrVkRenderPass& renderPass);
typedef GrGLSLProgramBuilder INHERITED;
};
-#endif
\ No newline at end of file
+#endif
const GrVkImageView* view)
: GrSurface(gpu, lifeCycle, desc)
, GrVkImage(imageResource)
- , INHERITED(gpu, lifeCycle, desc, false) // false because we don't upload MIP data in Vk yet
+ , INHERITED(gpu, lifeCycle, desc, kSampler2D_GrSLType,
+ false) // false because we don't upload MIP data in Vk yet
, fTextureView(view) {
this->registerWithCache();
}
Derived)
: GrSurface(gpu, lifeCycle, desc)
, GrVkImage(imageResource)
- , INHERITED(gpu, lifeCycle, desc, false) // false because we don't upload MIP data in Vk yet
+ , INHERITED(gpu, lifeCycle, desc, kSampler2D_GrSLType,
+ false) // false because we don't upload MIP data in Vk yet
, fTextureView(view) {}
return;
}
GrGLGpu* gpu0 = static_cast<GrGLGpu*>(context0->getGpu());
- if (!gpu0->glCaps().externalTextureSupport()) {
+ if (!gpu0->glCaps().glslCaps()->externalTextureSupport()) {
return;
}