Add support for vertex and geometry shader textures
authorcdalton <cdalton@nvidia.com>
Fri, 11 Mar 2016 18:07:37 +0000 (10:07 -0800)
committerCommit bot <commit-bot@chromium.org>
Fri, 11 Mar 2016 18:07:37 +0000 (10:07 -0800)
Adds a visibility bitfield to GrTextureAccess that controls in which
shaders the texture should be accessible. Also adds caps and
validation to ensure we don't exceed texture limits.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1782583002

Review URL: https://codereview.chromium.org/1782583002

23 files changed:
include/gpu/GrTexture.h
include/gpu/GrTextureAccess.h
src/gpu/GrTexture.cpp
src/gpu/GrTextureAccess.cpp
src/gpu/gl/GrGLCaps.cpp
src/gpu/gl/GrGLCaps.h
src/gpu/gl/GrGLDefines.h
src/gpu/gl/GrGLGpu.cpp
src/gpu/gl/GrGLNoOpInterface.cpp
src/gpu/gl/GrGLTexture.cpp
src/gpu/gl/builders/GrGLProgramBuilder.cpp
src/gpu/gl/builders/GrGLProgramBuilder.h
src/gpu/glsl/GrGLSLCaps.cpp
src/gpu/glsl/GrGLSLCaps.h
src/gpu/glsl/GrGLSLProgramBuilder.cpp
src/gpu/glsl/GrGLSLProgramBuilder.h
src/gpu/glsl/GrGLSLShaderBuilder.h
src/gpu/vk/GrVkCaps.cpp
src/gpu/vk/GrVkCaps.h
src/gpu/vk/GrVkProgramBuilder.cpp
src/gpu/vk/GrVkProgramBuilder.h
src/gpu/vk/GrVkTexture.cpp
tests/EGLImageTest.cpp

index a25c102..1d589ed 100644 (file)
@@ -20,6 +20,7 @@ class GrTexture : virtual public GrSurface {
 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
@@ -45,7 +46,7 @@ public:
     inline const GrTexturePriv texturePriv() const;
 
 protected:
-    GrTexture(GrGpu*, LifeCycle, const GrSurfaceDesc&, bool wasMipMapDataProvided);
+    GrTexture(GrGpu*, LifeCycle, const GrSurfaceDesc&, GrSLType, bool wasMipMapDataProvided);
 
     void validateDesc() const;
 
@@ -59,8 +60,9 @@ private:
         kValid_MipMapsStatus
     };
 
+    GrSLType        fSamplerType;
     MipMapsStatus   fMipMapsStatus;
-    int fMaxMipMapLevel;
+    int             fMaxMipMapLevel;
 
     friend class GrTexturePriv;
 
index 124a75a..1b5de0c 100644 (file)
@@ -29,20 +29,26 @@ public:
 
     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.
@@ -57,6 +63,7 @@ private:
 
     ProgramTexture                  fTexture;
     GrTextureParams                 fParams;
+    GrShaderFlags                   fVisibility;
 
     typedef SkNoncopyable INHERITED;
 };
index 270bcbe..28746b9 100644 (file)
@@ -88,8 +88,9 @@ GrSurfaceOrigin resolve_origin(const GrSurfaceDesc& desc) {
 
 //////////////////////////////////////////////////////////////////////////////
 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;
index 277c0e3..675bc20 100644 (file)
@@ -17,22 +17,26 @@ GrTextureAccess::GrTextureAccess(GrTexture* texture, const GrTextureParams& para
 
 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;
 }
index 5baed59..96a75b2 100644 (file)
@@ -27,7 +27,6 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
     fTransferBufferType = kNone_TransferBufferType;
     fMaxFragmentUniformVectors = 0;
     fMaxVertexAttributes = 0;
-    fMaxFragmentTextureUnits = 0;
     fUnpackRowLengthSupport = false;
     fUnpackFlipYSupport = false;
     fPackRowLengthSupport = false;
@@ -46,7 +45,6 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
     fUseNonVBOVertexAndIndexDynamicData = false;
     fIsCoreProfile = false;
     fBindFragDataLocationSupport = false;
-    fExternalTextureSupport = false;
     fRectangleTextureSupport = false;
     fTextureSwizzleSupport = false;
     fSRGBWriteControl = false;
@@ -86,7 +84,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
         }
     }
     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;
@@ -213,16 +210,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
     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
@@ -313,6 +300,20 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
         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
      **************************************************************************/
@@ -698,7 +699,17 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo) {
         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 {
@@ -1026,7 +1037,6 @@ SkString GrGLCaps::dump() const {
     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"));
@@ -1049,7 +1059,6 @@ SkString GrGLCaps::dump() const {
     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"));
 
index 06deaaf..cf16291 100644 (file)
@@ -254,9 +254,6 @@ public:
     /// 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
@@ -326,9 +323,6 @@ public:
 
     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; }
 
@@ -388,7 +382,6 @@ private:
 
     int fMaxFragmentUniformVectors;
     int fMaxVertexAttributes;
-    int fMaxFragmentTextureUnits;
 
     MSFBOType           fMSFBOType;
     InvalidateFBType    fInvalidateFBType;
@@ -417,7 +410,6 @@ private:
     bool fRGBA8888PixelsOpsAreSlow : 1;
     bool fPartialFBOReadIsSlow : 1;
     bool fBindUniformLocationSupport : 1;
-    bool fExternalTextureSupport : 1;
     bool fRectangleTextureSupport : 1;
     bool fTextureSwizzleSupport : 1;
     bool fMipMapLevelAndLodControlSupport : 1;
index a8e57a5..2553002 100644 (file)
 #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
index f9cba43..443c55c 100644 (file)
@@ -191,7 +191,7 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context)
     SkASSERT(ctx);
     fCaps.reset(SkRef(ctx->caps()));
 
-    fHWBoundTextureUniqueIDs.reset(this->glCaps().maxFragmentTextureUnits());
+    fHWBoundTextureUniqueIDs.reset(this->glCaps().glslCaps()->maxCombinedSamplers());
 
     GrGLClearErr(this->glInterface());
     if (gPrintStartupSpew) {
@@ -572,7 +572,7 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc,
             // 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) {
@@ -3684,7 +3684,7 @@ void GrGLGpu::createCopyPrograms() {
     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] &&
index 3cf9ecd..5d094e0 100644 (file)
@@ -506,7 +506,10 @@ GrGLvoid GR_GL_FUNCTION_TYPE noOpGLGetIntegerv(GrGLenum pname, GrGLint* params)
             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:
index e05006c..aff91eb 100644 (file)
 #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();
 }
@@ -23,14 +36,14 @@ GrGLTexture::GrGLTexture(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc&
 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);
 }
 
index 9f42915..1c5cf25 100644 (file)
@@ -40,9 +40,7 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gp
     GrGLSLExpr4 inputColor;
     GrGLSLExpr4 inputCoverage;
 
-    if (!builder.emitAndInstallProcs(&inputColor,
-                                     &inputCoverage,
-                                     gpu->glCaps().maxFragmentTextureUnits())) {
+    if (!builder.emitAndInstallProcs(&inputColor, &inputCoverage)) {
         builder.cleanupFragmentProcessors();
         return nullptr;
     }
@@ -55,7 +53,6 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gp
 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
     : INHERITED(args)
     , fGpu(gpu)
-    , fSamplerUniforms(4)
     , fVaryingHandler(this)
     , fUniformHandler(this) {
 }
@@ -68,39 +65,6 @@ const GrGLSLCaps* GrGLProgramBuilder::glslCaps() const {
     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,
index 2087925..a3a0fe7 100644 (file)
@@ -39,9 +39,6 @@ public:
 private:
     GrGLProgramBuilder(GrGLGpu*, const DrawArgs&);
 
-    void emitSamplers(const GrProcessor&,
-                      GrGLSLTextureSampler::TextureSamplerArray* outSamplers) override;
-
     bool compileAndAttachShaders(GrGLSLShaderBuilder& shader,
                                  GrGLuint programId,
                                  GrGLenum type,
@@ -61,12 +58,9 @@ private:
     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; 
 };
index 3b6c205..189b766 100755 (executable)
@@ -28,6 +28,7 @@ GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) {
     fMultisampleInterpolationSupport = false;
     fSampleVariablesSupport = false;
     fSampleMaskOverrideCoverageSupport = false;
+    fExternalTextureSupport = false;
     fVersionDeclString = nullptr;
     fShaderDerivativeExtensionString = nullptr;
     fFragCoordConventionsExtensionString = nullptr;
@@ -38,6 +39,10 @@ GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) {
     fSampleVariablesExtensionString = nullptr;
     fFBFetchColorName = nullptr;
     fFBFetchExtensionString = nullptr;
+    fMaxVertexSamplers = 0;
+    fMaxGeometrySamplers = 0;
+    fMaxFragmentSamplers = 0;
+    fMaxCombinedSamplers = 0;
     fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction;
 }
 
@@ -74,6 +79,11 @@ SkString GrGLSLCaps::dump() const {
     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;
index 1c79945..f907be2 100755 (executable)
@@ -64,6 +64,8 @@ public:
 
     bool sampleMaskOverrideCoverageSupport() const { return fSampleMaskOverrideCoverageSupport; }
 
+    bool externalTextureSupport() const { return fExternalTextureSupport; }
+
     AdvBlendEqInteraction advBlendEqInteraction() const { return fAdvBlendEqInteraction; }
 
     bool mustEnableAdvBlendEqs() const {
@@ -112,6 +114,7 @@ public:
     }
 
     const char* externalTextureExtensionString() const {
+        SkASSERT(this->externalTextureSupport());
         return fExternalTextureExtensionString;
     }
 
@@ -130,6 +133,14 @@ public:
         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
@@ -167,6 +178,7 @@ private:
     bool fMultisampleInterpolationSupport : 1;
     bool fSampleVariablesSupport : 1;
     bool fSampleMaskOverrideCoverageSupport : 1;
+    bool fExternalTextureSupport : 1;
 
     // Used for specific driver bug work arounds
     bool fCanUseMinAndAbsTogether : 1;
@@ -185,6 +197,11 @@ private:
     const char* fFBFetchColorName;
     const char* fFBFetchExtensionString;
 
+    uint8_t fMaxVertexSamplers;
+    uint8_t fMaxGeometrySamplers;
+    uint8_t fMaxFragmentSamplers;
+    uint8_t fMaxCombinedSamplers;
+
     AdvBlendEqInteraction fAdvBlendEqInteraction;
 
     GrSwizzle fConfigTextureSwizzle[kGrPixelConfigCnt];
index b9eaca4..bc02083 100644 (file)
@@ -22,16 +22,33 @@ GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args)
     , 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);
@@ -40,12 +57,6 @@ bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor,
             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);
@@ -61,7 +72,8 @@ bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor,
                                      primProc.getPixelLocalStorageState());
         this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
     }
-    return true;
+
+    return this->checkSamplerCounts();
 }
 
 void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc,
@@ -198,6 +210,42 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
     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;
@@ -214,6 +262,29 @@ void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
     }
 }
 
+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());
index b8669bf..83c004d 100644 (file)
@@ -93,12 +93,16 @@ public:
 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
@@ -139,7 +143,10 @@ private:
                                 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&);
@@ -147,11 +154,11 @@ private:
     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
index 7bfc610..c408c8a 100644 (file)
@@ -25,16 +25,6 @@ public:
     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.
index ca9cf35..9dbc40c 100644 (file)
@@ -39,11 +39,6 @@ GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface*
 
     fShaderCaps.reset(new GrGLSLCaps(contextOptions));
 
-    /**************************************************************************
-    * GrVkCaps fields
-    **************************************************************************/
-    fMaxSampledTextures = 16; // Spec requires a minimum of 16 sampled textures per stage
-
     this->init(contextOptions, vkInterface, physDev);
 }
 
@@ -60,7 +55,7 @@ void GrVkCaps::init(const GrContextOptions& contextOptions, const GrVkInterface*
     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);
@@ -114,9 +109,6 @@ void GrVkCaps::initGrCaps(const VkPhysicalDeviceProperties& properties,
 
     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;
@@ -127,7 +119,8 @@ void GrVkCaps::initGrCaps(const VkPhysicalDeviceProperties& properties,
     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";
 
@@ -155,6 +148,13 @@ void GrVkCaps::initGLSLCaps(const VkPhysicalDeviceFeatures& features) {
     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,
index 579f8a7..39be89e 100644 (file)
@@ -65,17 +65,6 @@ public:
         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:
@@ -84,7 +73,7 @@ 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);
@@ -103,8 +92,6 @@ private:
     SkTArray<StencilFormat, true> fLinearStencilFormats;
     SkTArray<StencilFormat, true> fStencilFormats;
 
-    int fMaxSampledTextures;
-
     typedef GrCaps INHERITED;
 };
 
index 916b8c3..06de3a0 100644 (file)
@@ -22,9 +22,7 @@ GrVkProgram* GrVkProgramBuilder::CreateProgram(GrVkGpu* gpu,
     GrGLSLExpr4 inputColor;
     GrGLSLExpr4 inputCoverage;
 
-    if (!builder.emitAndInstallProcs(&inputColor,
-                                     &inputCoverage,
-                                     gpu->vkCaps().maxSampledTextures())) {
+    if (!builder.emitAndInstallProcs(&inputColor, &inputCoverage)) {
         builder.cleanupFragmentProcessors();
         return nullptr;
     }
@@ -50,21 +48,6 @@ void GrVkProgramBuilder::finalizeFragmentOutputColor(GrGLSLShaderVar& outputColo
     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;
 
index 1d7bac6..83a7adf 100644 (file)
@@ -45,9 +45,6 @@ public:
 private:
     GrVkProgramBuilder(GrVkGpu*, const DrawArgs&);
 
-    void emitSamplers(const GrProcessor&,
-                      GrGLSLTextureSampler::TextureSamplerArray* outSamplers) override;
-
     GrVkProgram* finalize(const DrawArgs& args,
                           GrPrimitiveType primitiveType,
                           const GrVkRenderPass& renderPass);
@@ -71,4 +68,4 @@ private:
     typedef GrGLSLProgramBuilder INHERITED;
 };
 
-#endif
\ No newline at end of file
+#endif
index c8247ca..5c4c3bd 100644 (file)
@@ -20,7 +20,8 @@ GrVkTexture::GrVkTexture(GrVkGpu* gpu,
                          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();
 }
@@ -34,7 +35,8 @@ GrVkTexture::GrVkTexture(GrVkGpu* gpu,
                          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) {}
 
 
index 637055b..f19592c 100644 (file)
@@ -87,7 +87,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(EGLImageTest, reporter, context0, glCtx0) {
         return;
     }
     GrGLGpu* gpu0 = static_cast<GrGLGpu*>(context0->getGpu());
-    if (!gpu0->glCaps().externalTextureSupport()) {
+    if (!gpu0->glCaps().glslCaps()->externalTextureSupport()) {
         return;
     }