Implement texel buffers
authorcdalton <cdalton@nvidia.com>
Mon, 11 Apr 2016 21:47:28 +0000 (14:47 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 11 Apr 2016 21:47:28 +0000 (14:47 -0700)
Adds a mechanism for processors to add buffer accesses and implements
them in the GL backend.

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

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

27 files changed:
gyp/gpu.gypi
include/gpu/GrBuffer.h [moved from src/gpu/GrBuffer.h with 100% similarity]
include/gpu/GrBufferAccess.h [new file with mode: 0644]
include/gpu/GrFragmentProcessor.h
include/gpu/GrProcessor.h
include/gpu/GrTypesPriv.h
src/gpu/GrFragmentProcessor.cpp
src/gpu/GrProcessor.cpp
src/gpu/gl/GrGLBuffer.cpp
src/gpu/gl/GrGLBuffer.h
src/gpu/gl/GrGLCaps.cpp
src/gpu/gl/GrGLCaps.h
src/gpu/gl/GrGLGpu.cpp
src/gpu/gl/GrGLGpu.h
src/gpu/gl/GrGLProgram.cpp
src/gpu/gl/GrGLProgram.h
src/gpu/gl/GrGLProgramDataManager.cpp
src/gpu/gl/GrGLProgramDesc.cpp
src/gpu/glsl/GrGLSL.h
src/gpu/glsl/GrGLSLFragmentProcessor.cpp
src/gpu/glsl/GrGLSLFragmentProcessor.h
src/gpu/glsl/GrGLSLPrimitiveProcessor.h
src/gpu/glsl/GrGLSLProgramBuilder.cpp
src/gpu/glsl/GrGLSLProgramBuilder.h
src/gpu/glsl/GrGLSLShaderBuilder.h
src/gpu/glsl/GrGLSLXferProcessor.h
src/gpu/vk/GrVkProgramDesc.cpp

index 4798a81..0b8c2e8 100644 (file)
@@ -13,6 +13,8 @@
   'variables': {
     'skgpu_sources': [
       '<(skia_include_path)/gpu/GrBlend.h',
+      '<(skia_include_path)/gpu/GrBuffer.h',
+      '<(skia_include_path)/gpu/GrBufferAccess.h',
       '<(skia_include_path)/gpu/GrCaps.h',
       '<(skia_include_path)/gpu/GrClip.h',
       '<(skia_include_path)/gpu/GrColor.h',
@@ -72,7 +74,6 @@
       '<(skia_src_path)/gpu/GrBlend.cpp',
       '<(skia_src_path)/gpu/GrBlurUtils.cpp',
       '<(skia_src_path)/gpu/GrBlurUtils.h',
-      '<(skia_src_path)/gpu/GrBuffer.h',
       '<(skia_src_path)/gpu/GrBufferAllocPool.cpp',
       '<(skia_src_path)/gpu/GrBufferAllocPool.h',
       '<(skia_src_path)/gpu/GrCaps.cpp',
similarity index 100%
rename from src/gpu/GrBuffer.h
rename to include/gpu/GrBuffer.h
diff --git a/include/gpu/GrBufferAccess.h b/include/gpu/GrBufferAccess.h
new file mode 100644 (file)
index 0000000..183d43d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrBufferAccess_DEFINED
+#define GrBufferAccess_DEFINED
+
+#include "GrBuffer.h"
+#include "GrGpuResourceRef.h"
+
+/**
+ * Used to represent a texel buffer that will be read in a GrProcessor. It holds a GrBuffer along
+ * with an associated offset and texel config.
+ */
+class GrBufferAccess : public SkNoncopyable {
+public:
+    /**
+     * Must be initialized before adding to a GrProcessor's buffer access list.
+     */
+    void reset(intptr_t offsetInBytes, GrPixelConfig texelConfig, GrBuffer* buffer,
+               GrShaderFlags visibility = kFragment_GrShaderFlag) {
+        fOffsetInBytes = offsetInBytes;
+        fTexelConfig = texelConfig;
+        fBuffer.set(SkRef(buffer), kRead_GrIOType);
+        fVisibility = visibility;
+    }
+
+    bool operator==(const GrBufferAccess& that) const {
+        return fOffsetInBytes == that.fOffsetInBytes &&
+               fTexelConfig == that.fTexelConfig &&
+               this->buffer() == that.buffer() &&
+               fVisibility == that.fVisibility;
+    }
+
+    bool operator!=(const GrBufferAccess& that) const { return !(*this == that); }
+
+    intptr_t offsetInBytes() const { return fOffsetInBytes; }
+    GrPixelConfig texelConfig() const { return fTexelConfig; }
+    GrBuffer* buffer() const { return fBuffer.get(); }
+    GrShaderFlags visibility() const { return fVisibility; }
+
+    /**
+     * For internal use by GrProcessor.
+     */
+    const GrGpuResourceRef* getProgramBuffer() const { return &fBuffer;}
+
+private:
+    intptr_t                      fOffsetInBytes;
+    GrPixelConfig                 fTexelConfig;
+    GrTGpuResourceRef<GrBuffer>   fBuffer;
+    GrShaderFlags                 fVisibility;
+
+    typedef SkNoncopyable INHERITED;
+};
+
+#endif
index 55b2f90..c3f291c 100644 (file)
@@ -59,6 +59,7 @@ public:
         : INHERITED()
         , fUsesLocalCoords(false)
         , fNumTexturesExclChildren(0)
+        , fNumBuffersExclChildren(0)
         , fNumTransformsExclChildren(0) {}
 
     ~GrFragmentProcessor() override;
@@ -74,6 +75,8 @@ public:
 
     int numTexturesExclChildren() const { return fNumTexturesExclChildren; }
 
+    int numBuffersExclChildren() const { return fNumBuffersExclChildren; }
+
     int numTransformsExclChildren() const { return fNumTransformsExclChildren; }
 
     int numTransforms() const { return fCoordTransforms.count(); }
@@ -122,6 +125,7 @@ public:
 
 protected:
     void addTextureAccess(const GrTextureAccess* textureAccess) override;
+    void addBufferAccess(const GrBufferAccess*) override;
 
     /**
      * Fragment Processor subclasses call this from their constructor to register coordinate
@@ -210,6 +214,7 @@ private:
      */
     SkSTArray<4, const GrCoordTransform*, true>     fCoordTransforms;
     int                                             fNumTexturesExclChildren;
+    int                                             fNumBuffersExclChildren;
     int                                             fNumTransformsExclChildren;
     SkSTArray<1, const GrFragmentProcessor*, true>  fChildProcessors;
 
index 3e892c6..27fce2e 100644 (file)
@@ -12,6 +12,7 @@
 #include "GrProcessorUnitTest.h"
 #include "GrProgramElement.h"
 #include "GrTextureAccess.h"
+#include "GrBufferAccess.h"
 #include "SkMath.h"
 #include "SkString.h"
 
@@ -79,6 +80,14 @@ public:
     /** Shortcut for textureAccess(index).texture(); */
     GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); }
 
+    int numBuffers() const { return fBufferAccesses.count(); }
+
+    /** Returns the access pattern for the buffer at index. index must be valid according to
+        numBuffers(). */
+    const GrBufferAccess& bufferAccess(int index) const {
+        return *fBufferAccesses[index];
+    }
+
     /**
      * Platform specific built-in features that a processor can request for the fragment shader.
      */
@@ -113,14 +122,16 @@ protected:
     GrProcessor() : fClassID(kIllegalProcessorClassID), fRequiredFeatures(kNone_RequiredFeatures) {}
 
     /**
-     * Subclasses call this from their constructor to register GrTextureAccesses. The processor
-     * subclass manages the lifetime of the accesses (this function only stores a pointer). The
-     * GrTextureAccess is typically a member field of the GrProcessor subclass. This must only be
-     * called from the constructor because GrProcessors are immutable.
+     * Subclasses call these from their constructor to register sampler sources. The processor
+     * subclass manages the lifetime of the objects (these functions only store pointers). The
+     * GrTextureAccess and/or GrBufferAccess instances are typically member fields of the
+     * GrProcessor subclass. These must only be called from the constructor because GrProcessors
+     * are immutable.
      */
     virtual void addTextureAccess(const GrTextureAccess* textureAccess);
+    virtual void addBufferAccess(const GrBufferAccess* bufferAccess);
 
-    bool hasSameTextureAccesses(const GrProcessor&) const;
+    bool hasSameSamplers(const GrProcessor&) const;
 
     /**
      * If the prcoessor will generate code that uses platform specific built-in features, then it
@@ -141,6 +152,7 @@ protected:
 
     uint32_t fClassID;
     SkSTArray<4, const GrTextureAccess*, true>   fTextureAccesses;
+    SkSTArray<2, const GrBufferAccess*, true>    fBufferAccesses;
 
 private:
     static uint32_t GenClassID() {
index 39386f0..9a96521 100644 (file)
@@ -27,6 +27,7 @@ enum GrSLType {
     kSampler2D_GrSLType,
     kSamplerExternal_GrSLType,
     kSampler2DRect_GrSLType,
+    kSamplerBuffer_GrSLType,
     kBool_GrSLType,
     kInt_GrSLType,
     kUint_GrSLType,
@@ -76,7 +77,7 @@ static const int kGrSLPrecisionCount = kLast_GrSLPrecision + 1;
  */
 static inline int GrSLTypeVectorCount(GrSLType type) {
     SkASSERT(type >= 0 && type < static_cast<GrSLType>(kGrSLTypeCount));
-    static const int kCounts[] = { -1, 1, 2, 3, 4, -1, -1, -1, -1, -1, -1, 1, 1, 1 };
+    static const int kCounts[] = { -1, 1, 2, 3, 4, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1 };
     return kCounts[type];
 
     GR_STATIC_ASSERT(0 == kVoid_GrSLType);
@@ -90,9 +91,10 @@ static inline int GrSLTypeVectorCount(GrSLType type) {
     GR_STATIC_ASSERT(8 == kSampler2D_GrSLType);
     GR_STATIC_ASSERT(9 == kSamplerExternal_GrSLType);
     GR_STATIC_ASSERT(10 == kSampler2DRect_GrSLType);
-    GR_STATIC_ASSERT(11 == kBool_GrSLType);
-    GR_STATIC_ASSERT(12 == kInt_GrSLType);
-    GR_STATIC_ASSERT(13 == kUint_GrSLType);
+    GR_STATIC_ASSERT(11 == kSamplerBuffer_GrSLType);
+    GR_STATIC_ASSERT(12 == kBool_GrSLType);
+    GR_STATIC_ASSERT(13 == kInt_GrSLType);
+    GR_STATIC_ASSERT(14 == kUint_GrSLType);
     GR_STATIC_ASSERT(SK_ARRAY_COUNT(kCounts) == kGrSLTypeCount);
 }
 
@@ -124,10 +126,11 @@ static inline bool GrSLTypeIsFloatType(GrSLType type) {
     GR_STATIC_ASSERT(8 == kSampler2D_GrSLType);
     GR_STATIC_ASSERT(9 == kSamplerExternal_GrSLType);
     GR_STATIC_ASSERT(10 == kSampler2DRect_GrSLType);
-    GR_STATIC_ASSERT(11 == kBool_GrSLType);
-    GR_STATIC_ASSERT(12 == kInt_GrSLType);
-    GR_STATIC_ASSERT(13 == kUint_GrSLType);
-    GR_STATIC_ASSERT(14 == kGrSLTypeCount);
+    GR_STATIC_ASSERT(11 == kSamplerBuffer_GrSLType);
+    GR_STATIC_ASSERT(12 == kBool_GrSLType);
+    GR_STATIC_ASSERT(13 == kInt_GrSLType);
+    GR_STATIC_ASSERT(14 == kUint_GrSLType);
+    GR_STATIC_ASSERT(15 == kGrSLTypeCount);
 }
 
 /** Is the shading language type integral (including vectors/matrices)? */
@@ -146,10 +149,11 @@ static inline bool GrSLTypeIsIntType(GrSLType type) {
     GR_STATIC_ASSERT(8 == kSampler2D_GrSLType);
     GR_STATIC_ASSERT(9 == kSamplerExternal_GrSLType);
     GR_STATIC_ASSERT(10 == kSampler2DRect_GrSLType);
-    GR_STATIC_ASSERT(11 == kBool_GrSLType);
-    GR_STATIC_ASSERT(12 == kInt_GrSLType);
-    GR_STATIC_ASSERT(13 == kUint_GrSLType);
-    GR_STATIC_ASSERT(14 == kGrSLTypeCount);
+    GR_STATIC_ASSERT(11 == kSamplerBuffer_GrSLType);
+    GR_STATIC_ASSERT(12 == kBool_GrSLType);
+    GR_STATIC_ASSERT(13 == kInt_GrSLType);
+    GR_STATIC_ASSERT(14 == kUint_GrSLType);
+    GR_STATIC_ASSERT(15 == kGrSLTypeCount);
 }
 
 /** Is the shading language type numeric (including vectors/matrices)? */
@@ -172,6 +176,7 @@ static inline size_t GrSLTypeSize(GrSLType type) {
         0,                        // kSampler2D_GrSLType
         0,                        // kSamplerExternal_GrSLType
         0,                        // kSampler2DRect_GrSLType
+        0,                        // kSamplerBuffer_GrSLType
         0,                        // kBool_GrSLType
         0,                        // kInt_GrSLType
         0,                        // kUint_GrSLType
@@ -189,13 +194,14 @@ static inline size_t GrSLTypeSize(GrSLType type) {
     GR_STATIC_ASSERT(8 == kSampler2D_GrSLType);
     GR_STATIC_ASSERT(9 == kSamplerExternal_GrSLType);
     GR_STATIC_ASSERT(10 == kSampler2DRect_GrSLType);
-    GR_STATIC_ASSERT(11 == kBool_GrSLType);
-    GR_STATIC_ASSERT(12 == kInt_GrSLType);
-    GR_STATIC_ASSERT(13 == kUint_GrSLType);
-    GR_STATIC_ASSERT(14 == kGrSLTypeCount);
+    GR_STATIC_ASSERT(11 == kSamplerBuffer_GrSLType);
+    GR_STATIC_ASSERT(12 == kBool_GrSLType);
+    GR_STATIC_ASSERT(13 == kInt_GrSLType);
+    GR_STATIC_ASSERT(14 == kUint_GrSLType);
+    GR_STATIC_ASSERT(15 == kGrSLTypeCount);
 }
 
-static inline bool GrSLTypeIsSamplerType(GrSLType type) {
+static inline bool GrSLTypeIs2DTextureType(GrSLType type) {
     SkASSERT(type >= 0 && type < static_cast<GrSLType>(kGrSLTypeCount));
     return type >= kSampler2D_GrSLType && type <= kSampler2DRect_GrSLType;
 
@@ -204,6 +210,16 @@ static inline bool GrSLTypeIsSamplerType(GrSLType type) {
     GR_STATIC_ASSERT(10 == kSampler2DRect_GrSLType);
 }
 
+static inline bool GrSLTypeIsSamplerType(GrSLType type) {
+    SkASSERT(type >= 0 && type < static_cast<GrSLType>(kGrSLTypeCount));
+    return type >= kSampler2D_GrSLType && type <= kSamplerBuffer_GrSLType;
+
+    GR_STATIC_ASSERT(8 == kSampler2D_GrSLType);
+    GR_STATIC_ASSERT(9 == kSamplerExternal_GrSLType);
+    GR_STATIC_ASSERT(10 == kSampler2DRect_GrSLType);
+    GR_STATIC_ASSERT(11 == kSamplerBuffer_GrSLType);
+}
+
 static inline bool GrSLTypeAcceptsPrecision(GrSLType type) {
     return GrSLTypeIsNumeric(type) || GrSLTypeIsSamplerType(type);
 }
index 46efd80..9524c84 100644 (file)
@@ -27,7 +27,7 @@ GrFragmentProcessor::~GrFragmentProcessor() {
 bool GrFragmentProcessor::isEqual(const GrFragmentProcessor& that,
                                   bool ignoreCoordTransforms) const {
     if (this->classID() != that.classID() ||
-        !this->hasSameTextureAccesses(that)) {
+        !this->hasSameSamplers(that)) {
         return false;
     }
     if (ignoreCoordTransforms) {
@@ -69,6 +69,15 @@ void GrFragmentProcessor::addTextureAccess(const GrTextureAccess* textureAccess)
     fNumTexturesExclChildren++;
 }
 
+void GrFragmentProcessor::addBufferAccess(const GrBufferAccess* bufferAccess) {
+    // Can't add buffer accesses after registering any children since their buffer accesses have
+    // already been bubbled up into our fBufferAccesses array
+    SkASSERT(fChildProcessors.empty());
+
+    INHERITED::addBufferAccess(bufferAccess);
+    fNumBuffersExclChildren++;
+}
+
 void GrFragmentProcessor::addCoordTransform(const GrCoordTransform* transform) {
     // Can't add transforms after registering any children since their transforms have already been
     // bubbled up into our fCoordTransforms array
index fdfbbb5..0d3f8d9 100644 (file)
@@ -106,6 +106,11 @@ void GrProcessor::addTextureAccess(const GrTextureAccess* access) {
     this->addGpuResource(access->getProgramTexture());
 }
 
+void GrProcessor::addBufferAccess(const GrBufferAccess* access) {
+    fBufferAccesses.push_back(access);
+    this->addGpuResource(access->getProgramBuffer());
+}
+
 void* GrProcessor::operator new(size_t size) {
     return MemoryPoolAccessor().pool()->allocate(size);
 }
@@ -114,8 +119,8 @@ void GrProcessor::operator delete(void* target) {
     return MemoryPoolAccessor().pool()->release(target);
 }
 
-bool GrProcessor::hasSameTextureAccesses(const GrProcessor& that) const {
-    if (this->numTextures() != that.numTextures()) {
+bool GrProcessor::hasSameSamplers(const GrProcessor& that) const {
+    if (this->numTextures() != that.numTextures() || this->numBuffers() != that.numBuffers()) {
         return false;
     }
     for (int i = 0; i < this->numTextures(); ++i) {
@@ -123,6 +128,11 @@ bool GrProcessor::hasSameTextureAccesses(const GrProcessor& that) const {
             return false;
         }
     }
+    for (int i = 0; i < this->numBuffers(); ++i) {
+        if (this->bufferAccess(i) != that.bufferAccess(i)) {
+            return false;
+        }
+    }
     return true;
 }
 
index 6e1ce58..24fd592 100644 (file)
@@ -96,7 +96,8 @@ GrGLBuffer::GrGLBuffer(GrGLGpu* gpu, size_t size, GrBufferType intendedType,
       fBufferID(0),
       fSizeInBytes(size),
       fUsage(gr_to_gl_access_pattern(intendedType, accessPattern)),
-      fGLSizeInBytes(0) {
+      fGLSizeInBytes(0),
+      fHasAttachedToTexture(false) {
     if (this->isCPUBacked()) {
         // Core profile uses vertex array objects, which disallow client side arrays.
         SkASSERT(!gpu->glCaps().isCoreProfile());
@@ -151,6 +152,7 @@ void GrGLBuffer::onRelease() {
             GL_CALL(DeleteBuffers(1, &fBufferID));
             fBufferID = 0;
             fGLSizeInBytes = 0;
+            this->glGpu()->notifyBufferReleased(this);
         }
         fMapPtr = nullptr;
         VALIDATE();
index b3b4feb..84d05be 100644 (file)
@@ -27,6 +27,15 @@ public:
     GrGLuint bufferID() const { return fBufferID; }
     size_t baseOffset() const { return reinterpret_cast<size_t>(fCPUData); }
 
+    /**
+     * Returns the actual size of the underlying GL buffer object. In certain cases we may make this
+     * smaller than the size reported by GrBuffer.
+     */
+    size_t glSizeInBytes() const { return fGLSizeInBytes; }
+
+    void setHasAttachedToTexture() { fHasAttachedToTexture = true; }
+    bool hasAttachedToTexture() const { return fHasAttachedToTexture; }
+
 protected:
     GrGLBuffer(GrGLGpu*, size_t size, GrBufferType intendedType, GrAccessPattern, bool cpuBacked,
                const void* data);
@@ -53,8 +62,8 @@ private:
     GrGLuint       fBufferID;
     size_t         fSizeInBytes;
     GrGLenum       fUsage;
-    size_t         fGLSizeInBytes;     // In certain cases we make the size of the GL buffer object
-                                       // smaller or larger than the size in fDesc.
+    size_t         fGLSizeInBytes;
+    bool           fHasAttachedToTexture;
 
     typedef GrBuffer INHERITED;
 };
index 0322a0f..f3e494a 100644 (file)
@@ -1382,6 +1382,8 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
         texStorageSupported = false;
     }
 
+    bool texelBufferSupport = this->shaderCaps()->texelBufferSupport();
+
     fConfigTable[kUnknown_GrPixelConfig].fFormats.fBaseInternalFormat = 0;
     fConfigTable[kUnknown_GrPixelConfig].fFormats.fSizedInternalFormat = 0;
     fConfigTable[kUnknown_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = 0;
@@ -1408,6 +1410,9 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
     if (texStorageSupported) {
         fConfigTable[kRGBA_8888_GrPixelConfig].fFlags |= ConfigInfo::kCanUseTexStorage_Flag;
     }
+    if (texelBufferSupport) {
+        fConfigTable[kRGBA_8888_GrPixelConfig].fFlags |= ConfigInfo::kCanUseWithTexelBuffer_Flag;
+    }
     fConfigTable[kRGBA_8888_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] =
@@ -1567,6 +1572,9 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
         fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] =
             GR_GL_RED;
         fConfigTable[kAlpha_8_GrPixelConfig].fSwizzle = GrSwizzle::RRRR();
+        if (texelBufferSupport) {
+            fConfigTable[kAlpha_8_GrPixelConfig].fFlags |= ConfigInfo::kCanUseWithTexelBuffer_Flag;
+        }
     } else {
         fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_ALPHA;
         fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_ALPHA8;
@@ -1635,6 +1643,9 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
     if (texStorageSupported) {
         fConfigTable[kRGBA_float_GrPixelConfig].fFlags |= ConfigInfo::kCanUseTexStorage_Flag;
     }
+    if (texelBufferSupport) {
+        fConfigTable[kRGBA_float_GrPixelConfig].fFlags |= ConfigInfo::kCanUseWithTexelBuffer_Flag;
+    }
     fConfigTable[kRGBA_float_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     if (this->textureRedSupport()) {
@@ -1643,6 +1654,10 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
         fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage]
             = GR_GL_RED;
         fConfigTable[kAlpha_half_GrPixelConfig].fSwizzle = GrSwizzle::RRRR();
+        if (texelBufferSupport) {
+            fConfigTable[kAlpha_half_GrPixelConfig].fFlags |=
+                ConfigInfo::kCanUseWithTexelBuffer_Flag;
+        }
     } else {
         fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_ALPHA;
         fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_ALPHA16F;
@@ -1691,6 +1706,9 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
     if (texStorageSupported) {
         fConfigTable[kRGBA_half_GrPixelConfig].fFlags |= ConfigInfo::kCanUseTexStorage_Flag;
     }
+    if (texelBufferSupport) {
+        fConfigTable[kRGBA_half_GrPixelConfig].fFlags |= ConfigInfo::kCanUseWithTexelBuffer_Flag;
+    }
     fConfigTable[kRGBA_half_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     // Compressed texture support
index e2bc100..1602a0f 100644 (file)
@@ -135,11 +135,19 @@ public:
         return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kCanUseTexStorage_Flag);
     }
 
+    bool canUseConfigWithTexelBuffer(GrPixelConfig config) const {
+        return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kCanUseWithTexelBuffer_Flag);
+    }
+
     /** Returns the mapping between GrPixelConfig components and GL internal format components. */
     const GrSwizzle& configSwizzle(GrPixelConfig config) const {
         return fConfigTable[config].fSwizzle;
     }
 
+    GrGLenum configSizedInternalFormat(GrPixelConfig config) const {
+        return fConfigTable[config].fFormats.fSizedInternalFormat;
+    }
+
     bool getTexImageFormats(GrPixelConfig surfaceConfig, GrPixelConfig externalConfig,
                             GrGLenum* internalFormat, GrGLenum* externalFormat,
                             GrGLenum* externalType) const;
@@ -468,6 +476,7 @@ private:
             kRenderable_Flag              = 0x4,
             kRenderableWithMSAA_Flag      = 0x8,
             kCanUseTexStorage_Flag        = 0x10,
+            kCanUseWithTexelBuffer_Flag   = 0x20,
         };
         uint32_t fFlags;
 
index e8b5755..af59550 100644 (file)
@@ -194,6 +194,7 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context)
     , fTempSrcFBOID(0)
     , fTempDstFBOID(0)
     , fStencilClearFBOID(0)
+    , fHWMaxUsedBufferTextureUnit(-1)
     , fHWPLSEnabled(false)
     , fPLSHasBeenUsed(false)
     , fHWMinSampleShading(0.0) {
@@ -223,6 +224,10 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context)
     }
     GR_STATIC_ASSERT(6 == SK_ARRAY_COUNT(fHWBufferState));
 
+    if (this->caps()->shaderCaps()->texelBufferSupport()) {
+        fHWBufferTextures.reset(this->glCaps().glslCaps()->maxCombinedSamplers());
+    }
+
     if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
         fPathRendering.reset(new GrGLPathRendering(this));
     }
@@ -522,6 +527,10 @@ void GrGLGpu::onResetContext(uint32_t resetBits) {
         for (int s = 0; s < fHWBoundTextureUniqueIDs.count(); ++s) {
             fHWBoundTextureUniqueIDs[s] = SK_InvalidUniqueID;
         }
+        for (int b = 0; b < fHWBufferTextures.count(); ++b) {
+            SkASSERT(this->caps()->shaderCaps()->texelBufferSupport());
+            fHWBufferTextures[b].fKnownBound = false;
+        }
     }
 
     if (resetBits & kBlend_GrGLBackendState) {
@@ -2052,14 +2061,7 @@ bool GrGLGpu::flushGLState(const GrPipeline& pipeline, const GrPrimitiveProcesso
         this->flushBlend(blendInfo, swizzle);
     }
 
-    SkSTArray<8, const GrTextureAccess*> textureAccesses;
-    program->setData(primProc, pipeline, &textureAccesses);
-
-    int numTextureAccesses = textureAccesses.count();
-    for (int i = 0; i < numTextureAccesses; i++) {
-        this->bindTexture(i, textureAccesses[i]->getParams(), pipeline.getAllowSRGBInputs(),
-                          static_cast<GrGLTexture*>(textureAccesses[i]->getTexture()));
-    }
+    program->setData(primProc, pipeline);
 
     GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTarget());
     this->flushStencil(pipeline.getStencil());
@@ -2147,6 +2149,31 @@ GrGLenum GrGLGpu::bindBuffer(GrBufferType type, const GrGLBuffer* buffer) {
     return bufferState.fGLTarget;
 }
 
+void GrGLGpu::notifyBufferReleased(const GrGLBuffer* buffer) {
+    if (buffer->hasAttachedToTexture()) {
+        // Detach this buffer from any textures to ensure the underlying memory is freed.
+        uint32_t uniqueID = buffer->getUniqueID();
+        for (int i = fHWMaxUsedBufferTextureUnit; i >= 0; --i) {
+            auto& buffTex = fHWBufferTextures[i];
+            if (uniqueID != buffTex.fAttachedBufferUniqueID) {
+                continue;
+            }
+            if (i == fHWMaxUsedBufferTextureUnit) {
+                --fHWMaxUsedBufferTextureUnit;
+            }
+
+            this->setTextureUnit(i);
+            if (!buffTex.fKnownBound) {
+                SkASSERT(buffTex.fTextureID);
+                GL_CALL(BindTexture(GR_GL_TEXTURE_BUFFER, buffTex.fTextureID));
+                buffTex.fKnownBound = true;
+            }
+            GL_CALL(TexBuffer(GR_GL_TEXTURE_BUFFER,
+                              this->glCaps().configSizedInternalFormat(buffTex.fTexelConfig), 0));
+        }
+    }
+}
+
 void GrGLGpu::disableScissor() {
     if (kNo_TriState != fHWScissorSettings.fEnabled) {
         GL_CALL(Disable(GR_GL_SCISSOR_TEST));
@@ -3264,21 +3291,78 @@ void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, bool dstCo
         (setAll || memcmp(newTexParams.fSwizzleRGBA,
                           oldTexParams.fSwizzleRGBA,
                           sizeof(newTexParams.fSwizzleRGBA)))) {
+        this->setTextureSwizzle(unitIdx, target, newTexParams.fSwizzleRGBA);
+    }
+    texture->setCachedTexParams(newTexParams, this->getResetTimestamp());
+}
+
+void GrGLGpu::bindTexelBuffer(int unitIdx, intptr_t offsetInBytes, GrPixelConfig texelConfig,
+                              GrGLBuffer* buffer) {
+    SkASSERT(this->glCaps().canUseConfigWithTexelBuffer(texelConfig));
+    SkASSERT(unitIdx >= 0 && unitIdx < fHWBufferTextures.count());
+    SkASSERT(offsetInBytes >= 0 && offsetInBytes < (intptr_t) buffer->glSizeInBytes());
+
+    BufferTexture& buffTex = fHWBufferTextures[unitIdx];
+
+    if (!buffTex.fKnownBound) {
+        if (!buffTex.fTextureID) {
+            GL_CALL(GenTextures(1, &buffTex.fTextureID));
+            if (!buffTex.fTextureID) {
+                return;
+            }
+        }
+
         this->setTextureUnit(unitIdx);
-        if (this->glStandard() == kGLES_GrGLStandard) {
-            // ES3 added swizzle support but not GL_TEXTURE_SWIZZLE_RGBA.
-            const GrGLenum* swizzle = newTexParams.fSwizzleRGBA;
-            GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_R, swizzle[0]));
-            GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_G, swizzle[1]));
-            GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_B, swizzle[2]));
-            GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_A, swizzle[3]));
-        } else {
-            GR_STATIC_ASSERT(sizeof(newTexParams.fSwizzleRGBA[0]) == sizeof(GrGLint));
-            const GrGLint* swizzle = reinterpret_cast<const GrGLint*>(newTexParams.fSwizzleRGBA);
-            GL_CALL(TexParameteriv(target, GR_GL_TEXTURE_SWIZZLE_RGBA, swizzle));
+        GL_CALL(BindTexture(GR_GL_TEXTURE_BUFFER, buffTex.fTextureID));
+
+        buffTex.fKnownBound = true;
+    }
+
+    if (buffer->getUniqueID() != buffTex.fAttachedBufferUniqueID ||
+        buffTex.fOffsetInBytes != offsetInBytes ||
+        buffTex.fTexelConfig != texelConfig ||
+        buffTex.fAttachedSizeInBytes != buffer->glSizeInBytes() - offsetInBytes) {
+
+        size_t attachmentSizeInBytes = buffer->glSizeInBytes() - offsetInBytes;
+
+        this->setTextureUnit(unitIdx);
+        GL_CALL(TexBufferRange(GR_GL_TEXTURE_BUFFER,
+                               this->glCaps().configSizedInternalFormat(texelConfig),
+                               buffer->bufferID(),
+                               offsetInBytes,
+                               attachmentSizeInBytes));
+
+        buffTex.fOffsetInBytes = offsetInBytes;
+        buffTex.fTexelConfig = texelConfig;
+        buffTex.fAttachedSizeInBytes = attachmentSizeInBytes;
+        buffTex.fAttachedBufferUniqueID = buffer->getUniqueID();
+
+        if (this->glCaps().textureSwizzleSupport() &&
+            this->glCaps().configSwizzle(texelConfig) != buffTex.fSwizzle) {
+            GrGLenum glSwizzle[4];
+            get_tex_param_swizzle(texelConfig, this->glCaps(), glSwizzle);
+            this->setTextureSwizzle(unitIdx, GR_GL_TEXTURE_BUFFER, glSwizzle);
+            buffTex.fSwizzle = this->glCaps().configSwizzle(texelConfig);
         }
+
+        buffer->setHasAttachedToTexture();
+        fHWMaxUsedBufferTextureUnit = SkTMax(unitIdx, fHWMaxUsedBufferTextureUnit);
+    }
+}
+
+void GrGLGpu::setTextureSwizzle(int unitIdx, GrGLenum target, const GrGLenum swizzle[]) {
+    this->setTextureUnit(unitIdx);
+    if (this->glStandard() == kGLES_GrGLStandard) {
+        // ES3 added swizzle support but not GL_TEXTURE_SWIZZLE_RGBA.
+        GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_R, swizzle[0]));
+        GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_G, swizzle[1]));
+        GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_B, swizzle[2]));
+        GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_A, swizzle[3]));
+    } else {
+        GR_STATIC_ASSERT(sizeof(swizzle[0]) == sizeof(GrGLint));
+        GL_CALL(TexParameteriv(target, GR_GL_TEXTURE_SWIZZLE_RGBA,
+                               reinterpret_cast<const GrGLint*>(swizzle)));
     }
-    texture->setCachedTexParams(newTexParams, this->getResetTimestamp());
 }
 
 void GrGLGpu::flushColorWrite(bool writeColor) {
index c2dda0a..c8b5d70 100644 (file)
@@ -60,6 +60,8 @@ public:
     void bindTexture(int unitIdx, const GrTextureParams& params, bool dstConfigAllowsSRGB,
                      GrGLTexture* texture);
 
+    void bindTexelBuffer(int unitIdx, intptr_t offsetInBytes, GrPixelConfig, GrGLBuffer*);
+
     bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes,
                              GrPixelConfig readConfig, DrawPreference*,
                              ReadPixelTempDrawInfo*) override;
@@ -88,6 +90,9 @@ public:
     // If the caller wishes to bind an index buffer to a specific VAO, it can call glBind directly.
     GrGLenum bindBuffer(GrBufferType type, const GrGLBuffer*);
 
+    // Called by GrGLBuffer after its buffer object has been destroyed.
+    void notifyBufferReleased(const GrGLBuffer*);
+
     const GrGLContext* glContextForTesting() const override {
         return &this->glContext();
     }
@@ -206,6 +211,8 @@ private:
     // binds texture unit in GL
     void setTextureUnit(int unitIdx);
 
+    void setTextureSwizzle(int unitIdx, GrGLenum target, const GrGLenum swizzle[]);
+
     // Flushes state from GrPipeline to GL. Returns false if the state couldn't be set.
     bool flushGLState(const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc);
 
@@ -498,6 +505,23 @@ private:
     TriState                    fHWSRGBFramebuffer;
     SkTArray<uint32_t, true>    fHWBoundTextureUniqueIDs;
 
+    struct BufferTexture {
+        BufferTexture() : fTextureID(0), fKnownBound(false),
+                          fAttachedBufferUniqueID(SK_InvalidUniqueID),
+                          fSwizzle(GrSwizzle::RGBA()) {}
+
+        GrGLuint        fTextureID;
+        bool            fKnownBound;
+        intptr_t        fOffsetInBytes;
+        GrPixelConfig   fTexelConfig;
+        size_t          fAttachedSizeInBytes;
+        uint32_t        fAttachedBufferUniqueID;
+        GrSwizzle       fSwizzle;
+    };
+
+    SkTArray<BufferTexture, true>   fHWBufferTextures;
+    int                             fHWMaxUsedBufferTextureUnit;
+
     // EXT_raster_multisample.
     TriState                    fHWRasterMultisampleEnabled;
     int                         fHWNumRasterSamples;
index aa828a2..6a433e1 100644 (file)
@@ -11,6 +11,7 @@
 #include "GrProcessor.h"
 #include "GrCoordTransform.h"
 #include "GrGLGpu.h"
+#include "GrGLBuffer.h"
 #include "GrGLPathRendering.h"
 #include "GrPathProcessor.h"
 #include "GrPipeline.h"
@@ -66,46 +67,34 @@ void GrGLProgram::abandon() {
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static void append_texture_bindings(const GrProcessor& processor,
-                                    SkTArray<const GrTextureAccess*>* textureBindings) {
-    if (int numTextures = processor.numTextures()) {
-        const GrTextureAccess** bindings = textureBindings->push_back_n(numTextures);
-        int i = 0;
-        do {
-            bindings[i] = &processor.textureAccess(i);
-        } while (++i < numTextures);
-    }
-}
-
-void GrGLProgram::setData(const GrPrimitiveProcessor& primProc,
-                          const GrPipeline& pipeline,
-                          SkTArray<const GrTextureAccess*>* textureBindings) {
+void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline) {
     this->setRenderTargetState(primProc, pipeline);
 
     // we set the textures, and uniforms for installed processors in a generic way, but subclasses
     // of GLProgram determine how to set coord transforms
+    int nextSamplerIdx = 0;
     fGeometryProcessor->setData(fProgramDataManager, primProc);
-    append_texture_bindings(primProc, textureBindings);
+    this->bindTextures(primProc, pipeline.getAllowSRGBInputs(), &nextSamplerIdx);
 
-    this->setFragmentData(primProc, pipeline, textureBindings);
+    this->setFragmentData(primProc, pipeline, &nextSamplerIdx);
 
     if (primProc.getPixelLocalStorageState() !=
         GrPixelLocalStorageState::kDraw_GrPixelLocalStorageState) {
         const GrXferProcessor& xp = pipeline.getXferProcessor();
         fXferProcessor->setData(fProgramDataManager, xp);
-        append_texture_bindings(xp, textureBindings);
+        this->bindTextures(xp, pipeline.getAllowSRGBInputs(), &nextSamplerIdx);
     }
 }
 
 void GrGLProgram::setFragmentData(const GrPrimitiveProcessor& primProc,
                                   const GrPipeline& pipeline,
-                                  SkTArray<const GrTextureAccess*>* textureBindings) {
+                                  int* nextSamplerIdx) {
     int numProcessors = fFragmentProcessors.count();
     for (int i = 0; i < numProcessors; ++i) {
         const GrFragmentProcessor& processor = pipeline.getFragmentProcessor(i);
         fFragmentProcessors[i]->setData(fProgramDataManager, processor);
         this->setTransformData(primProc, processor, i);
-        append_texture_bindings(processor, textureBindings);
+        this->bindTextures(processor, pipeline.getAllowSRGBInputs(), nextSamplerIdx);
     }
 }
 void GrGLProgram::setTransformData(const GrPrimitiveProcessor& primProc,
@@ -145,3 +134,18 @@ void GrGLProgram::setRenderTargetState(const GrPrimitiveProcessor& primProc,
                                                      size, rt->origin());
     }
 }
+
+void GrGLProgram::bindTextures(const GrProcessor& processor,
+                               bool allowSRGBInputs,
+                               int* nextSamplerIdx) {
+    for (int i = 0; i < processor.numTextures(); ++i) {
+        const GrTextureAccess& access = processor.textureAccess(i);
+        fGpu->bindTexture((*nextSamplerIdx)++, access.getParams(),
+                          allowSRGBInputs, static_cast<GrGLTexture*>(access.getTexture()));
+    }
+    for (int i = 0; i < processor.numBuffers(); ++i) {
+        const GrBufferAccess& access = processor.bufferAccess(i);
+        fGpu->bindTexelBuffer((*nextSamplerIdx)++, access.offsetInBytes(), access.texelConfig(),
+                              static_cast<GrGLBuffer*>(access.buffer()));
+    }
+}
index 22678cb..c70b1bd 100644 (file)
@@ -94,8 +94,7 @@ public:
      * the program is bound before calling, and to bind the outgoing textures to their respective
      * units upon return. (Each index in the array corresponds to its matching GL texture unit.)
      */
-    void setData(const GrPrimitiveProcessor&, const GrPipeline&,
-                 SkTArray<const GrTextureAccess*>* textureBindings);
+    void setData(const GrPrimitiveProcessor&, const GrPipeline&);
 
 protected:
     typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
@@ -113,16 +112,16 @@ protected:
                 const GrGLSLFragProcs& fragmentProcessors,
                 SkTArray<UniformHandle>* passSamplerUniforms);
 
-    // A templated helper to loop over effects, set the transforms(via subclass) and bind textures
-    void setFragmentData(const GrPrimitiveProcessor&, const GrPipeline&,
-                         SkTArray<const GrTextureAccess*>* textureBindings);
-    void setTransformData(const GrPrimitiveProcessor&,
-                          const GrFragmentProcessor&,
-                          int index);
+    // A helper to loop over effects, set the transforms (via subclass) and bind textures
+    void setFragmentData(const GrPrimitiveProcessor&, const GrPipeline&, int* nextSamplerIdx);
+    void setTransformData(const GrPrimitiveProcessor&, const GrFragmentProcessor&, int index);
 
     // Helper for setData() that sets the view matrix and loads the render target height uniform
     void setRenderTargetState(const GrPrimitiveProcessor&, const GrPipeline&);
 
+    // Helper for setData() that binds textures and texel buffers to the appropriate texture units
+    void bindTextures(const GrProcessor&, bool allowSRGBInputs, int* nextSamplerIdx);
+
     // these reflect the current values of uniforms (GL uniform values travel with program)
     RenderTargetState fRenderTargetState;
     BuiltinUniformHandles fBuiltinUniformHandles;
index d5b48f7..6b2e111 100644 (file)
@@ -63,8 +63,7 @@ GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, GrGLuint programID,
 
 void GrGLProgramDataManager::setSampler(UniformHandle u, int texUnit) const {
     const Uniform& uni = fUniforms[u.toIndex()];
-    SkASSERT(uni.fType == kSampler2D_GrSLType || uni.fType == kSamplerExternal_GrSLType ||
-             uni.fType == kSampler2DRect_GrSLType);
+    SkASSERT(GrSLTypeIsSamplerType(uni.fType));
     SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
     // FIXME: We still insert a single sampler uniform for every stage. If the shader does not
     // reference the sampler then the compiler may have optimized it out. Uncomment this assert
index 5e9fe5f..801224c 100644 (file)
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 #include "glsl/GrGLSLCaps.h"
 
-static uint16_t texture_key(GrSLType samplerType, GrPixelConfig config, GrShaderFlags visibility,
+static uint16_t sampler_key(GrSLType samplerType, GrPixelConfig config, GrShaderFlags visibility,
                             const GrGLSLCaps& caps) {
     enum {
         kFirstSamplerType = kSampler2D_GrSLType,
-        kLastSamplerType = kSampler2DRect_GrSLType,
+        kLastSamplerType = kSamplerBuffer_GrSLType,
         kSamplerTypeKeyBits = 4
     };
     GR_STATIC_ASSERT(kLastSamplerType - kFirstSamplerType < (1 << kSamplerTypeKeyBits));
@@ -34,23 +34,30 @@ static uint16_t texture_key(GrSLType samplerType, GrPixelConfig config, GrShader
                    (caps.samplerPrecision(config, visibility) << (8 + kSamplerTypeKeyBits)));
 }
 
-static void add_texture_key(GrProcessorKeyBuilder* b, const GrProcessor& proc,
-                            const GrGLSLCaps& caps) {
+static void add_sampler_keys(GrProcessorKeyBuilder* b, const GrProcessor& proc,
+                             const GrGLSLCaps& caps) {
     int numTextures = proc.numTextures();
+    int numSamplers = numTextures + proc.numBuffers();
     // Need two bytes per key (swizzle, sampler type, and precision).
-    int word32Count = (proc.numTextures() + 1) / 2;
+    int word32Count = (numSamplers + 1) / 2;
     if (0 == word32Count) {
         return;
     }
     uint16_t* k16 = SkTCast<uint16_t*>(b->add32n(word32Count));
-    for (int i = 0; i < numTextures; ++i) {
+    int i = 0;
+    for (; i < numTextures; ++i) {
         const GrTextureAccess& access = proc.textureAccess(i);
         const GrTexture* tex = access.getTexture();
-        k16[i] = texture_key(tex->samplerType(), tex->config(), access.getVisibility(), caps);
+        k16[i] = sampler_key(tex->samplerType(), tex->config(), access.getVisibility(), caps);
+    }
+    for (; i < numSamplers; ++i) {
+        const GrBufferAccess& access = proc.bufferAccess(i - numTextures);
+        k16[i] = sampler_key(kSamplerBuffer_GrSLType, access.texelConfig(), access.visibility(),
+                             caps);
     }
-    // zero the last 16 bits if the number of textures is odd.
-    if (numTextures & 0x1) {
-        k16[numTextures] = 0;
+    // zero the last 16 bits if the number of samplers is odd.
+    if (numSamplers & 0x1) {
+        k16[numSamplers] = 0;
     }
 }
 
@@ -76,7 +83,7 @@ static bool gen_meta_key(const GrProcessor& proc,
         return false;
     }
 
-    add_texture_key(b, proc, glslCaps);
+    add_sampler_keys(b, proc, glslCaps);
 
     uint32_t* key = b->add32n(2);
     key[0] = (classID << 16) | SkToU32(processorKeySize);
index 9f5f2b0..844b7c7 100644 (file)
@@ -58,7 +58,7 @@ bool GrGLSLSupportsNamedFragmentShaderOutputs(GrGLSLGeneration);
  */
 inline const char* GrGLSLTexture2DFunctionName(GrSLType coordType, GrSLType samplerType,
                                                GrGLSLGeneration glslGen) {
-    SkASSERT(GrSLTypeIsSamplerType(samplerType));
+    SkASSERT(GrSLTypeIs2DTextureType(samplerType));
     SkASSERT(kVec2f_GrSLType == coordType || kVec3f_GrSLType == coordType);
     // GL_TEXTURE_RECTANGLE_ARB is written against OpenGL 2.0/GLSL 1.10. At that time there were
     // separate texture*() functions. In OpenGL 3.0/GLSL 1.30 the different texture*() functions
@@ -127,6 +127,8 @@ static inline const char* GrGLSLTypeString(GrSLType t) {
             return "samplerExternalOES";
         case kSampler2DRect_GrSLType:
             return "sampler2DRect";
+        case kSamplerBuffer_GrSLType:
+            return "samplerBuffer";
         case kBool_GrSLType:
             return "bool";
         case kInt_GrSLType:
index c3e57bc..42538ea 100644 (file)
@@ -75,18 +75,25 @@ void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* inpu
      * Textures work the same way as transforms.
      */
     int firstCoordAt = args.fFp.numTransformsExclChildren();
-    int firstSamplerAt = args.fFp.numTexturesExclChildren();
+    int firstTextureAt = args.fFp.numTexturesExclChildren();
+    int firstBufferAt = args.fFp.numBuffersExclChildren();
     for (int i = 0; i < childIndex; ++i) {
         firstCoordAt += args.fFp.childProcessor(i).numTransforms();
-        firstSamplerAt += args.fFp.childProcessor(i).numTextures();
+        firstTextureAt += args.fFp.childProcessor(i).numTextures();
+        firstBufferAt += args.fFp.childProcessor(i).numBuffers();
     }
     GrGLSLTransformedCoordsArray childCoords;
     SamplerArray childTexSamplers;
+    SamplerArray childBufferSamplers;
     if (childProc.numTransforms() > 0) {
         childCoords.push_back_n(childProc.numTransforms(), &args.fCoords[firstCoordAt]);
     }
     if (childProc.numTextures() > 0) {
-        childTexSamplers.push_back_n(childProc.numTextures(), &args.fTexSamplers[firstSamplerAt]);
+        childTexSamplers.push_back_n(childProc.numTextures(), &args.fTexSamplers[firstTextureAt]);
+    }
+    if (childProc.numBuffers() > 0) {
+        childBufferSamplers.push_back_n(childProc.numBuffers(),
+                                        &args.fBufferSamplers[firstBufferAt]);
     }
 
     // emit the code for the child in its own scope
@@ -100,7 +107,8 @@ void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* inpu
                        outputColor,
                        inputColor,
                        childCoords,
-                       childTexSamplers);
+                       childTexSamplers,
+                       childBufferSamplers);
     this->childProcessor(childIndex)->emitCode(childArgs);
     fragBuilder->codeAppend("}\n");
 
index 5c71340..9fc4a8c 100644 (file)
@@ -60,7 +60,8 @@ public:
                  const char* outputColor,
                  const char* inputColor,
                  const GrGLSLTransformedCoordsArray& coords,
-                 const SamplerArray& texSamplers)
+                 const SamplerArray& texSamplers,
+                 const SamplerArray& bufferSamplers)
             : fFragBuilder(fragBuilder)
             , fUniformHandler(uniformHandler)
             , fGLSLCaps(caps)
@@ -68,7 +69,8 @@ public:
             , fOutputColor(outputColor)
             , fInputColor(inputColor)
             , fCoords(coords)
-            , fTexSamplers(texSamplers) {}
+            , fTexSamplers(texSamplers)
+            , fBufferSamplers(bufferSamplers) {}
         GrGLSLFPFragmentBuilder* fFragBuilder;
         GrGLSLUniformHandler* fUniformHandler;
         const GrGLSLCaps* fGLSLCaps;
@@ -77,6 +79,7 @@ public:
         const char* fInputColor;
         const GrGLSLTransformedCoordsArray& fCoords;
         const SamplerArray& fTexSamplers;
+        const SamplerArray& fBufferSamplers;
     };
 
     virtual void emitCode(EmitArgs&) = 0;
index fc0c478..4bd5fef 100644 (file)
@@ -43,6 +43,7 @@ public:
                  const char* outputColor,
                  const char* outputCoverage,
                  const SamplerArray& texSamplers,
+                 const SamplerArray& bufferSamplers,
                  const TransformsIn& transformsIn,
                  TransformsOut* transformsOut)
             : fVertBuilder(vertBuilder)
@@ -54,6 +55,7 @@ public:
             , fOutputColor(outputColor)
             , fOutputCoverage(outputCoverage)
             , fTexSamplers(texSamplers)
+            , fBufferSamplers(bufferSamplers)
             , fTransformsIn(transformsIn)
             , fTransformsOut(transformsOut) {}
         GrGLSLVertexBuilder* fVertBuilder;
@@ -65,6 +67,7 @@ public:
         const char* fOutputColor;
         const char* fOutputCoverage;
         const SamplerArray& fTexSamplers;
+        const SamplerArray& fBufferSamplers;
         const TransformsIn& fTransformsIn;
         TransformsOut* fTransformsOut;
     };
index ccb078b..88ef5b9 100644 (file)
@@ -98,7 +98,8 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr
     fGeometryProcessor = proc.createGLSLInstance(*this->glslCaps());
 
     SkSTArray<4, GrGLSLSampler> texSamplers(proc.numTextures());
-    this->emitSamplers(proc, &texSamplers);
+    SkSTArray<2, GrGLSLSampler> bufferSamplers(proc.numBuffers());
+    this->emitSamplers(proc, &texSamplers, &bufferSamplers);
 
     GrGLSLGeometryProcessor::EmitArgs args(&fVS,
                                            &fFS,
@@ -109,6 +110,7 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr
                                            outputColor->c_str(),
                                            outputCoverage->c_str(),
                                            texSamplers,
+                                           bufferSamplers,
                                            fCoordTransforms,
                                            &fOutCoords);
     fGeometryProcessor->emitCode(args);
@@ -149,7 +151,8 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
     GrGLSLFragmentProcessor* fragProc = fp.createGLSLInstance();
 
     SkSTArray<4, GrGLSLSampler> texSamplers(fp.numTextures());
-    this->emitSamplers(fp, &texSamplers);
+    SkSTArray<2, GrGLSLSampler> bufferSamplers(fp.numBuffers());
+    this->emitSamplers(fp, &texSamplers, &bufferSamplers);
 
     GrGLSLFragmentProcessor::EmitArgs args(&fFS,
                                            this->uniformHandler(),
@@ -158,7 +161,8 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
                                            output->c_str(),
                                            input.isOnes() ? nullptr : input.c_str(),
                                            fOutCoords[index],
-                                           texSamplers);
+                                           texSamplers,
+                                           bufferSamplers);
     fragProc->emitCode(args);
 
     // We have to check that effects and the code they emit are consistent, ie if an effect
@@ -194,7 +198,8 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
     fFS.codeAppend(openBrace.c_str());
 
     SkSTArray<4, GrGLSLSampler> texSamplers(xp.numTextures());
-    this->emitSamplers(xp, &texSamplers);
+    SkSTArray<2, GrGLSLSampler> bufferSamplers(xp.numBuffers());
+    this->emitSamplers(xp, &texSamplers, &bufferSamplers);
 
     bool usePLSDstRead = (plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState);
     GrGLSLXferProcessor::EmitArgs args(&fFS,
@@ -205,6 +210,7 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
                                        fFS.getPrimaryColorOutputName(),
                                        fFS.getSecondaryColorOutputName(),
                                        texSamplers,
+                                       bufferSamplers,
                                        usePLSDstRead);
     fXferProcessor->emitCode(args);
 
@@ -215,41 +221,65 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
 }
 
 void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor,
-                                        GrGLSLSampler::SamplerArray* outTexSamplers) {
-    int numTextures = processor.numTextures();
-    UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures);
+                                        GrGLSLSampler::SamplerArray* outTexSamplers,
+                                        GrGLSLSampler::SamplerArray* outBufferSamplers) {
     SkString name;
+    int numTextures = processor.numTextures();
     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,
+            this->addFeature(access.getVisibility(),
                              1 << GrGLSLShaderBuilder::kExternalTexture_GLSLPrivateFeature,
                              externalFeatureString);
         }
-        GrSLPrecision precision = this->glslCaps()->samplerPrecision(access.getTexture()->config(),
-                                                                     visibility);
-        name.printf("Sampler%d", t);
-        localSamplerUniforms[t] = this->uniformHandler()->addUniform(visibility,
-                                                                     samplerType,
-                                                                     precision,
-                                                                     name.c_str());
-        outTexSamplers->emplace_back(localSamplerUniforms[t], access.getTexture()->config());
+        name.printf("TextureSampler%d", t);
+        this->emitSampler(samplerType, access.getTexture()->config(),
+                          name.c_str(), access.getVisibility(), outTexSamplers);
+    }
+
+    if (int numBuffers = processor.numBuffers()) {
+        SkASSERT(this->glslCaps()->texelBufferSupport());
+        GrShaderFlags texelBufferVisibility = kNone_GrShaderFlags;
+
+        for (int b = 0; b < numBuffers; ++b) {
+            const GrBufferAccess& access = processor.bufferAccess(b);
+            name.printf("BufferSampler%d", b);
+            this->emitSampler(kSamplerBuffer_GrSLType, access.texelConfig(), name.c_str(),
+                              access.visibility(), outBufferSamplers);
+            texelBufferVisibility |= access.visibility();
+        }
+
+        if (const char* extension = this->glslCaps()->texelBufferExtensionString()) {
+            this->addFeature(texelBufferVisibility,
+                             1 << GrGLSLShaderBuilder::kTexelBuffer_GLSLPrivateFeature,
+                             extension);
+        }
+    }
+}
+
+void GrGLSLProgramBuilder::emitSampler(GrSLType samplerType,
+                                       GrPixelConfig config,
+                                       const char* name,
+                                       GrShaderFlags visibility,
+                                       GrGLSLSampler::SamplerArray* outSamplers) {
+    if (visibility & kVertex_GrShaderFlag) {
+        ++fNumVertexSamplers;
+    }
+    if (visibility & kGeometry_GrShaderFlag) {
+        SkASSERT(this->primitiveProcessor().willUseGeoShader());
+        ++fNumGeometrySamplers;
+    }
+    if (visibility & kFragment_GrShaderFlag) {
+        ++fNumFragmentSamplers;
     }
+    GrSLPrecision precision = this->glslCaps()->samplerPrecision(config, visibility);
+    UniformHandle u = this->uniformHandler()->addUniform(visibility, samplerType, precision, name);
+    fSamplerUniforms.push_back(u);
+    outSamplers->emplace_back(u, config);
 }
 
 void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
index 4d253c7..3ce7daf 100644 (file)
@@ -146,7 +146,14 @@ private:
                                 const GrGLSLExpr4& coverageIn,
                                 bool ignoresCoverage,
                                 GrPixelLocalStorageState plsState);
-    void emitSamplers(const GrProcessor& processor, GrGLSLSampler::SamplerArray* outTexSamplers);
+    void emitSamplers(const GrProcessor& processor,
+                      GrGLSLSampler::SamplerArray* outTexSamplers,
+                      GrGLSLSampler::SamplerArray* outBufferSamplers);
+    void emitSampler(GrSLType samplerType,
+                     GrPixelConfig,
+                     const char* name,
+                     GrShaderFlags visibility,
+                     GrGLSLSampler::SamplerArray* outSamplers);
     void emitFSOutputSwizzle(bool hasSecondaryOutput);
     bool checkSamplerCounts();
 
index c14df53..ef7963f 100644 (file)
@@ -153,6 +153,7 @@ protected:
         kBlendEquationAdvanced_GLSLPrivateFeature,
         kBlendFuncExtended_GLSLPrivateFeature,
         kExternalTexture_GLSLPrivateFeature,
+        kTexelBuffer_GLSLPrivateFeature,
         kFramebufferFetch_GLSLPrivateFeature,
         kNoPerspectiveInterpolation_GLSLPrivateFeature,
         kSampleVariables_GLSLPrivateFeature,
index 3f190ce..adc3d41 100644 (file)
@@ -33,6 +33,7 @@ public:
                  const char* outputPrimary,
                  const char* outputSecondary,
                  const SamplerArray& texSamplers,
+                 const SamplerArray& bufferSamplers,
                  const bool usePLSDstRead)
             : fXPFragBuilder(fragBuilder)
             , fUniformHandler(uniformHandler)
@@ -43,6 +44,7 @@ public:
             , fOutputPrimary(outputPrimary)
             , fOutputSecondary(outputSecondary)
             , fTexSamplers(texSamplers)
+            , fBufferSamplers(bufferSamplers)
             , fUsePLSDstRead(usePLSDstRead) {}
 
         GrGLSLXPFragmentBuilder* fXPFragBuilder;
@@ -54,6 +56,7 @@ public:
         const char* fOutputPrimary;
         const char* fOutputSecondary;
         const SamplerArray& fTexSamplers;
+        const SamplerArray& fBufferSamplers;
         bool fUsePLSDstRead;
     };
     /**
index f4bd2bf..4619bcf 100644 (file)
@@ -22,6 +22,7 @@
 static void add_texture_key(GrProcessorKeyBuilder* b, const GrProcessor& proc,
                             const GrGLSLCaps& caps) {
     int numTextures = proc.numTextures();
+    SkASSERT(0 == proc.numBuffers());
     // Need two bytes per key (swizzle, sampler type, and precision).
     int word32Count = (proc.numTextures() + 1) / 2;
     if (0 == word32Count) {