Implement texel buffers
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
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 4798a81..0b8c2e8 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -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',
diff --git a/src/gpu/GrBuffer.h b/include/gpu/GrBuffer.h
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
index 0000000..183d43d
--- /dev/null
+++ b/include/gpu/GrBufferAccess.h
@@ -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
diff --git a/include/gpu/GrFragmentProcessor.h b/include/gpu/GrFragmentProcessor.h
index 55b2f90..c3f291c 100644
--- a/include/gpu/GrFragmentProcessor.h
+++ b/include/gpu/GrFragmentProcessor.h
@@ -59,6 +59,7 @@
: INHERITED()
, fUsesLocalCoords(false)
, fNumTexturesExclChildren(0)
+ , fNumBuffersExclChildren(0)
, fNumTransformsExclChildren(0) {}
~GrFragmentProcessor() override;
@@ -74,6 +75,8 @@
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 @@
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 @@
*/
SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms;
int fNumTexturesExclChildren;
+ int fNumBuffersExclChildren;
int fNumTransformsExclChildren;
SkSTArray<1, const GrFragmentProcessor*, true> fChildProcessors;
diff --git a/include/gpu/GrProcessor.h b/include/gpu/GrProcessor.h
index 3e892c6..27fce2e 100644
--- a/include/gpu/GrProcessor.h
+++ b/include/gpu/GrProcessor.h
@@ -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 @@
/** 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 @@
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 @@
uint32_t fClassID;
SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses;
+ SkSTArray<2, const GrBufferAccess*, true> fBufferAccesses;
private:
static uint32_t GenClassID() {
diff --git a/include/gpu/GrTypesPriv.h b/include/gpu/GrTypesPriv.h
index 39386f0..9a96521 100644
--- a/include/gpu/GrTypesPriv.h
+++ b/include/gpu/GrTypesPriv.h
@@ -27,6 +27,7 @@
kSampler2D_GrSLType,
kSamplerExternal_GrSLType,
kSampler2DRect_GrSLType,
+ kSamplerBuffer_GrSLType,
kBool_GrSLType,
kInt_GrSLType,
kUint_GrSLType,
@@ -76,7 +77,7 @@
*/
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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);
}
diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp
index 46efd80..9524c84 100644
--- a/src/gpu/GrFragmentProcessor.cpp
+++ b/src/gpu/GrFragmentProcessor.cpp
@@ -27,7 +27,7 @@
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 @@
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
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index fdfbbb5..0d3f8d9 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -106,6 +106,11 @@
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 @@
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 @@
return false;
}
}
+ for (int i = 0; i < this->numBuffers(); ++i) {
+ if (this->bufferAccess(i) != that.bufferAccess(i)) {
+ return false;
+ }
+ }
return true;
}
diff --git a/src/gpu/gl/GrGLBuffer.cpp b/src/gpu/gl/GrGLBuffer.cpp
index 6e1ce58..24fd592 100644
--- a/src/gpu/gl/GrGLBuffer.cpp
+++ b/src/gpu/gl/GrGLBuffer.cpp
@@ -96,7 +96,8 @@
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 @@
GL_CALL(DeleteBuffers(1, &fBufferID));
fBufferID = 0;
fGLSizeInBytes = 0;
+ this->glGpu()->notifyBufferReleased(this);
}
fMapPtr = nullptr;
VALIDATE();
diff --git a/src/gpu/gl/GrGLBuffer.h b/src/gpu/gl/GrGLBuffer.h
index b3b4feb..84d05be 100644
--- a/src/gpu/gl/GrGLBuffer.h
+++ b/src/gpu/gl/GrGLBuffer.h
@@ -27,6 +27,15 @@
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 @@
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;
};
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 0322a0f..f3e494a 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -1382,6 +1382,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index e2bc100..1602a0f 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -135,11 +135,19 @@
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 @@
kRenderable_Flag = 0x4,
kRenderableWithMSAA_Flag = 0x8,
kCanUseTexStorage_Flag = 0x10,
+ kCanUseWithTexelBuffer_Flag = 0x20,
};
uint32_t fFlags;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index e8b5755..af59550 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -194,6 +194,7 @@
, fTempSrcFBOID(0)
, fTempDstFBOID(0)
, fStencilClearFBOID(0)
+ , fHWMaxUsedBufferTextureUnit(-1)
, fHWPLSEnabled(false)
, fPLSHasBeenUsed(false)
, fHWMinSampleShading(0.0) {
@@ -223,6 +224,10 @@
}
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 @@
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 @@
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 @@
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,23 +3291,80 @@
(setAll || memcmp(newTexParams.fSwizzleRGBA,
oldTexParams.fSwizzleRGBA,
sizeof(newTexParams.fSwizzleRGBA)))) {
- 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));
- }
+ 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);
+ 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)));
+ }
+}
+
void GrGLGpu::flushColorWrite(bool writeColor) {
if (!writeColor) {
if (kNo_TriState != fHWWriteToColor) {
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index c2dda0a..c8b5d70 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -60,6 +60,8 @@
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 @@
// 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 @@
// 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 @@
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;
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index aa828a2..6a433e1 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -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 @@
///////////////////////////////////////////////////////////////////////////////
-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 @@
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()));
+ }
+}
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 22678cb..c70b1bd 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -94,8 +94,7 @@
* 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 @@
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;
diff --git a/src/gpu/gl/GrGLProgramDataManager.cpp b/src/gpu/gl/GrGLProgramDataManager.cpp
index d5b48f7..6b2e111 100644
--- a/src/gpu/gl/GrGLProgramDataManager.cpp
+++ b/src/gpu/gl/GrGLProgramDataManager.cpp
@@ -63,8 +63,7 @@
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
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index 5e9fe5f..801224c 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -17,11 +17,11 @@
#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 @@
(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);
}
- // zero the last 16 bits if the number of textures is odd.
- if (numTextures & 0x1) {
- k16[numTextures] = 0;
+ 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 samplers is odd.
+ if (numSamplers & 0x1) {
+ k16[numSamplers] = 0;
}
}
@@ -76,7 +83,7 @@
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);
diff --git a/src/gpu/glsl/GrGLSL.h b/src/gpu/glsl/GrGLSL.h
index 9f5f2b0..844b7c7 100644
--- a/src/gpu/glsl/GrGLSL.h
+++ b/src/gpu/glsl/GrGLSL.h
@@ -58,7 +58,7 @@
*/
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 @@
return "samplerExternalOES";
case kSampler2DRect_GrSLType:
return "sampler2DRect";
+ case kSamplerBuffer_GrSLType:
+ return "samplerBuffer";
case kBool_GrSLType:
return "bool";
case kInt_GrSLType:
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
index c3e57bc..42538ea 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
@@ -75,18 +75,25 @@
* 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 @@
outputColor,
inputColor,
childCoords,
- childTexSamplers);
+ childTexSamplers,
+ childBufferSamplers);
this->childProcessor(childIndex)->emitCode(childArgs);
fragBuilder->codeAppend("}\n");
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.h b/src/gpu/glsl/GrGLSLFragmentProcessor.h
index 5c71340..9fc4a8c 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.h
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.h
@@ -60,7 +60,8 @@
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 @@
, fOutputColor(outputColor)
, fInputColor(inputColor)
, fCoords(coords)
- , fTexSamplers(texSamplers) {}
+ , fTexSamplers(texSamplers)
+ , fBufferSamplers(bufferSamplers) {}
GrGLSLFPFragmentBuilder* fFragBuilder;
GrGLSLUniformHandler* fUniformHandler;
const GrGLSLCaps* fGLSLCaps;
@@ -77,6 +79,7 @@
const char* fInputColor;
const GrGLSLTransformedCoordsArray& fCoords;
const SamplerArray& fTexSamplers;
+ const SamplerArray& fBufferSamplers;
};
virtual void emitCode(EmitArgs&) = 0;
diff --git a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
index fc0c478..4bd5fef 100644
--- a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
+++ b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
@@ -43,6 +43,7 @@
const char* outputColor,
const char* outputCoverage,
const SamplerArray& texSamplers,
+ const SamplerArray& bufferSamplers,
const TransformsIn& transformsIn,
TransformsOut* transformsOut)
: fVertBuilder(vertBuilder)
@@ -54,6 +55,7 @@
, fOutputColor(outputColor)
, fOutputCoverage(outputCoverage)
, fTexSamplers(texSamplers)
+ , fBufferSamplers(bufferSamplers)
, fTransformsIn(transformsIn)
, fTransformsOut(transformsOut) {}
GrGLSLVertexBuilder* fVertBuilder;
@@ -65,6 +67,7 @@
const char* fOutputColor;
const char* fOutputCoverage;
const SamplerArray& fTexSamplers;
+ const SamplerArray& fBufferSamplers;
const TransformsIn& fTransformsIn;
TransformsOut* fTransformsOut;
};
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index ccb078b..88ef5b9 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -98,7 +98,8 @@
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 @@
outputColor->c_str(),
outputCoverage->c_str(),
texSamplers,
+ bufferSamplers,
fCoordTransforms,
&fOutCoords);
fGeometryProcessor->emitCode(args);
@@ -149,7 +151,8 @@
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 @@
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 @@
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 @@
fFS.getPrimaryColorOutputName(),
fFS.getSecondaryColorOutputName(),
texSamplers,
+ bufferSamplers,
usePLSDstRead);
fXferProcessor->emitCode(args);
@@ -215,41 +221,65 @@
}
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) {
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h
index 4d253c7..3ce7daf 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.h
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.h
@@ -146,7 +146,14 @@
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();
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.h b/src/gpu/glsl/GrGLSLShaderBuilder.h
index c14df53..ef7963f 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.h
@@ -153,6 +153,7 @@
kBlendEquationAdvanced_GLSLPrivateFeature,
kBlendFuncExtended_GLSLPrivateFeature,
kExternalTexture_GLSLPrivateFeature,
+ kTexelBuffer_GLSLPrivateFeature,
kFramebufferFetch_GLSLPrivateFeature,
kNoPerspectiveInterpolation_GLSLPrivateFeature,
kSampleVariables_GLSLPrivateFeature,
diff --git a/src/gpu/glsl/GrGLSLXferProcessor.h b/src/gpu/glsl/GrGLSLXferProcessor.h
index 3f190ce..adc3d41 100644
--- a/src/gpu/glsl/GrGLSLXferProcessor.h
+++ b/src/gpu/glsl/GrGLSLXferProcessor.h
@@ -33,6 +33,7 @@
const char* outputPrimary,
const char* outputSecondary,
const SamplerArray& texSamplers,
+ const SamplerArray& bufferSamplers,
const bool usePLSDstRead)
: fXPFragBuilder(fragBuilder)
, fUniformHandler(uniformHandler)
@@ -43,6 +44,7 @@
, fOutputPrimary(outputPrimary)
, fOutputSecondary(outputSecondary)
, fTexSamplers(texSamplers)
+ , fBufferSamplers(bufferSamplers)
, fUsePLSDstRead(usePLSDstRead) {}
GrGLSLXPFragmentBuilder* fXPFragBuilder;
@@ -54,6 +56,7 @@
const char* fOutputPrimary;
const char* fOutputSecondary;
const SamplerArray& fTexSamplers;
+ const SamplerArray& fBufferSamplers;
bool fUsePLSDstRead;
};
/**
diff --git a/src/gpu/vk/GrVkProgramDesc.cpp b/src/gpu/vk/GrVkProgramDesc.cpp
index f4bd2bf..4619bcf 100644
--- a/src/gpu/vk/GrVkProgramDesc.cpp
+++ b/src/gpu/vk/GrVkProgramDesc.cpp
@@ -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) {