aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gn/tests.gni1
-rw-r--r--include/gpu/GrGpuResourceRef.h4
-rw-r--r--include/gpu/GrProcessor.h69
-rw-r--r--include/gpu/GrShaderVar.h19
-rw-r--r--include/gpu/GrTypesPriv.h49
-rw-r--r--src/gpu/GrFragmentProcessor.cpp2
-rw-r--r--src/gpu/GrProcessor.cpp45
-rw-r--r--src/gpu/GrProgramDesc.cpp104
-rw-r--r--src/gpu/GrShaderVar.cpp35
-rw-r--r--src/gpu/GrTexturePriv.h8
-rw-r--r--src/gpu/gl/GrGLCaps.cpp23
-rw-r--r--src/gpu/gl/GrGLCaps.h6
-rw-r--r--src/gpu/gl/GrGLGpu.cpp26
-rw-r--r--src/gpu/gl/GrGLGpu.h8
-rw-r--r--src/gpu/gl/GrGLProgram.cpp7
-rw-r--r--src/gpu/gl/GrGLProgram.h7
-rw-r--r--src/gpu/gl/GrGLProgramDataManager.cpp10
-rw-r--r--src/gpu/gl/GrGLProgramDataManager.h1
-rw-r--r--src/gpu/gl/GrGLUniformHandler.cpp56
-rw-r--r--src/gpu/gl/GrGLUniformHandler.h13
-rw-r--r--src/gpu/gl/builders/GrGLProgramBuilder.cpp1
-rw-r--r--src/gpu/glsl/GrGLSL.h4
-rw-r--r--src/gpu/glsl/GrGLSLCaps.cpp16
-rw-r--r--src/gpu/glsl/GrGLSLCaps.h16
-rw-r--r--src/gpu/glsl/GrGLSLFragmentProcessor.cpp2
-rw-r--r--src/gpu/glsl/GrGLSLFragmentProcessor.h18
-rw-r--r--src/gpu/glsl/GrGLSLPrimitiveProcessor.h10
-rw-r--r--src/gpu/glsl/GrGLSLProgramBuilder.cpp111
-rw-r--r--src/gpu/glsl/GrGLSLProgramBuilder.h32
-rw-r--r--src/gpu/glsl/GrGLSLShaderBuilder.cpp10
-rw-r--r--src/gpu/glsl/GrGLSLShaderBuilder.h8
-rw-r--r--src/gpu/glsl/GrGLSLUniformHandler.h9
-rw-r--r--src/gpu/glsl/GrGLSLXferProcessor.h8
-rw-r--r--src/gpu/vk/GrVkPipelineState.cpp2
-rw-r--r--src/gpu/vk/GrVkUniformHandler.cpp6
-rw-r--r--src/gpu/vk/GrVkUniformHandler.h12
-rw-r--r--src/gpu/vk/GrVkVaryingHandler.cpp4
-rw-r--r--tests/ImageStorageTest.cpp149
38 files changed, 759 insertions, 152 deletions
diff --git a/gn/tests.gni b/gn/tests.gni
index 98980ec0f6..8473e0eabe 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -106,6 +106,7 @@ tests_sources = [
"$_tests/ImageGeneratorTest.cpp",
"$_tests/ImageIsOpaqueTest.cpp",
"$_tests/ImageNewShaderTest.cpp",
+ "$_tests/ImageStorageTest.cpp",
"$_tests/ImageTest.cpp",
"$_tests/IndexedPngOverflowTest.cpp",
"$_tests/InfRectTest.cpp",
diff --git a/include/gpu/GrGpuResourceRef.h b/include/gpu/GrGpuResourceRef.h
index a91dcfeed5..a51d8148e7 100644
--- a/include/gpu/GrGpuResourceRef.h
+++ b/include/gpu/GrGpuResourceRef.h
@@ -43,6 +43,10 @@ public:
/** Does this object own a pending read or write on the resource it is wrapping. */
bool ownsPendingIO() const { return fPendingIO; }
+ /** What type of IO does this represent? This is independent of whether a normal ref or a
+ pending IO is currently held. */
+ GrIOType ioType() const { return fIOType; }
+
/** Shortcut for calling setResource() with NULL. It cannot be called after markingPendingIO
is called. */
void reset();
diff --git a/include/gpu/GrProcessor.h b/include/gpu/GrProcessor.h
index e4f59ea5ed..c2888d3bab 100644
--- a/include/gpu/GrProcessor.h
+++ b/include/gpu/GrProcessor.h
@@ -14,6 +14,7 @@
#include "GrProcessorUnitTest.h"
#include "GrProgramElement.h"
#include "GrSamplerParams.h"
+#include "GrShaderVar.h"
#include "SkMath.h"
#include "SkString.h"
#include "../private/SkAtomics.h"
@@ -62,6 +63,7 @@ class GrProcessor : public GrProgramElement {
public:
class TextureSampler;
class BufferAccess;
+ class ImageStorageAccess;
virtual ~GrProcessor();
@@ -88,7 +90,17 @@ public:
numBuffers(). */
const BufferAccess& bufferAccess(int index) const { return *fBufferAccesses[index]; }
- /** Platform specific built-in features that a processor can request for the fragment shader. */
+ int numImageStorages() const { return fImageStorageAccesses.count(); }
+
+ /** Returns the access object for the image at index. index must be valid according to
+ numImages(). */
+ const ImageStorageAccess& imageStorageAccess(int index) const {
+ return *fImageStorageAccesses[index];
+ }
+
+ /**
+ * Platform specific built-in features that a processor can request for the fragment shader.
+ */
enum RequiredFeatures {
kNone_RequiredFeatures = 0,
kFragmentPosition_RequiredFeature = 1 << 0,
@@ -118,15 +130,16 @@ protected:
GrProcessor() : fClassID(kIllegalProcessorClassID), fRequiredFeatures(kNone_RequiredFeatures) {}
/**
- * Subclasses call these from their constructor to register sampler sources. The processor
+ * Subclasses call these from their constructor to register sampler/image sources. The processor
* subclass manages the lifetime of the objects (these functions only store pointers). The
* TextureSampler and/or BufferAccess instances are typically member fields of the GrProcessor
* subclass. These must only be called from the constructor because GrProcessors are immutable.
*/
void addTextureSampler(const TextureSampler*);
- void addBufferAccess(const BufferAccess* bufferAccess);
+ void addBufferAccess(const BufferAccess*);
+ void addImageStorageAccess(const ImageStorageAccess*);
- bool hasSameSamplers(const GrProcessor&) const;
+ bool hasSameSamplersAndAccesses(const GrProcessor &) const;
/**
* If the prcoessor will generate code that uses platform specific built-in features, then it
@@ -145,7 +158,6 @@ protected:
fClassID = kClassID;
}
- uint32_t fClassID;
private:
static uint32_t GenClassID() {
// fCurrProcessorClassID has been initialized to kIllegalProcessorClassID. The
@@ -164,9 +176,11 @@ private:
};
static int32_t gCurrProcessorClassID;
- RequiredFeatures fRequiredFeatures;
- SkSTArray<4, const TextureSampler*, true> fTextureSamplers;
- SkSTArray<2, const BufferAccess*, true> fBufferAccesses;
+ uint32_t fClassID;
+ RequiredFeatures fRequiredFeatures;
+ SkSTArray<4, const TextureSampler*, true> fTextureSamplers;
+ SkSTArray<1, const BufferAccess*, true> fBufferAccesses;
+ SkSTArray<1, const ImageStorageAccess*, true> fImageStorageAccesses;
typedef GrProgramElement INHERITED;
};
@@ -175,7 +189,8 @@ GR_MAKE_BITFIELD_OPS(GrProcessor::RequiredFeatures);
/**
* Used to represent a texture that is required by a GrProcessor. It holds a GrTexture along with
- * an associated GrSamplerParams
+ * an associated GrSamplerParams. TextureSamplers don't perform any coord manipulation to account
+ * for texture origin.
*/
class GrProcessor::TextureSampler : public SkNoncopyable {
public:
@@ -257,7 +272,7 @@ public:
/**
* For internal use by GrProcessor.
*/
- const GrGpuResourceRef* getProgramBuffer() const { return &fBuffer;}
+ const GrGpuResourceRef* programBuffer() const { return &fBuffer;}
private:
GrPixelConfig fTexelConfig;
@@ -267,4 +282,38 @@ private:
typedef SkNoncopyable INHERITED;
};
+/**
+ * This is used by a GrProcessor to access a texture using image load/store in its shader code.
+ * ImageStorageAccesses don't perform any coord manipulation to account for texture origin.
+ * Currently the format of the load/store data in the shader is inferred from the texture config,
+ * though it could be made explicit.
+ */
+class GrProcessor::ImageStorageAccess : public SkNoncopyable {
+public:
+ ImageStorageAccess(sk_sp<GrTexture> texture, GrIOType ioType,
+ GrShaderFlags visibility = kFragment_GrShaderFlag);
+
+ bool operator==(const ImageStorageAccess& that) const {
+ return this->texture() == that.texture() && fVisibility == that.fVisibility;
+ }
+
+ bool operator!=(const ImageStorageAccess& that) const { return !(*this == that); }
+
+ GrTexture* texture() const { return fTexture.get(); }
+ GrShaderFlags visibility() const { return fVisibility; }
+ GrIOType ioType() const { return fTexture.ioType(); }
+ GrImageStorageFormat format() const { return fFormat; }
+
+ /**
+ * For internal use by GrProcessor.
+ */
+ const GrGpuResourceRef* programTexture() const { return &fTexture; }
+
+private:
+ GrTGpuResourceRef<GrTexture> fTexture;
+ GrShaderFlags fVisibility;
+ GrImageStorageFormat fFormat;
+ typedef SkNoncopyable INHERITED;
+};
+
#endif
diff --git a/include/gpu/GrShaderVar.h b/include/gpu/GrShaderVar.h
index aaae107c19..be2677bdd1 100644
--- a/include/gpu/GrShaderVar.h
+++ b/include/gpu/GrShaderVar.h
@@ -284,6 +284,8 @@ public:
}
}
+ void setImageStorageFormat(GrImageStorageFormat format);
+
void addModifier(const char* modifier) {
if (modifier) {
fExtraModifiers.appendf("%s ", modifier);
@@ -310,23 +312,6 @@ public:
}
private:
- static const char* TypeModifierString(TypeModifier t) {
- switch (t) {
- case kNone_TypeModifier:
- return "";
- case kIn_TypeModifier:
- return "in";
- case kInOut_TypeModifier:
- return "inout";
- case kOut_TypeModifier:
- return "out";
- case kUniform_TypeModifier:
- return "uniform";
- }
- SkFAIL("Unknown shader variable type modifier.");
- return ""; // suppress warning
- }
-
GrSLType fType;
TypeModifier fTypeModifier;
int fCount;
diff --git a/include/gpu/GrTypesPriv.h b/include/gpu/GrTypesPriv.h
index 4ecab9cc01..cd56e0e880 100644
--- a/include/gpu/GrTypesPriv.h
+++ b/include/gpu/GrTypesPriv.h
@@ -34,6 +34,8 @@ enum GrSLType {
kBufferSampler_GrSLType,
kTexture2D_GrSLType,
kSampler_GrSLType,
+ kImageStorage2D_GrSLType,
+ kIImageStorage2D_GrSLType,
};
enum GrShaderType {
@@ -103,6 +105,8 @@ static inline bool GrSLTypeIsFloatType(GrSLType type) {
case kUint_GrSLType:
case kTexture2D_GrSLType:
case kSampler_GrSLType:
+ case kImageStorage2D_GrSLType:
+ case kIImageStorage2D_GrSLType:
return false;
}
SkFAIL("Unexpected type");
@@ -131,6 +135,8 @@ static inline bool GrSLTypeIs2DCombinedSamplerType(GrSLType type) {
case kBool_GrSLType:
case kTexture2D_GrSLType:
case kSampler_GrSLType:
+ case kImageStorage2D_GrSLType:
+ case kIImageStorage2D_GrSLType:
return false;
}
SkFAIL("Unexpected type");
@@ -159,6 +165,38 @@ static inline bool GrSLTypeIsCombinedSamplerType(GrSLType type) {
case kBool_GrSLType:
case kTexture2D_GrSLType:
case kSampler_GrSLType:
+ case kImageStorage2D_GrSLType:
+ case kIImageStorage2D_GrSLType:
+ return false;
+ }
+ SkFAIL("Unexpected type");
+ return false;
+}
+
+static inline bool GrSLTypeIsImageStorage(GrSLType type) {
+ switch (type) {
+ case kImageStorage2D_GrSLType:
+ case kIImageStorage2D_GrSLType:
+ return true;
+
+ case kVoid_GrSLType:
+ case kFloat_GrSLType:
+ case kVec2f_GrSLType:
+ case kVec3f_GrSLType:
+ case kVec4f_GrSLType:
+ case kMat22f_GrSLType:
+ case kMat33f_GrSLType:
+ case kMat44f_GrSLType:
+ case kInt_GrSLType:
+ case kUint_GrSLType:
+ case kBool_GrSLType:
+ case kTexture2D_GrSLType:
+ case kSampler_GrSLType:
+ case kTexture2DSampler_GrSLType:
+ case kITexture2DSampler_GrSLType:
+ case kTextureExternalSampler_GrSLType:
+ case kTexture2DRectSampler_GrSLType:
+ case kBufferSampler_GrSLType:
return false;
}
SkFAIL("Unexpected type");
@@ -183,6 +221,8 @@ static inline bool GrSLTypeAcceptsPrecision(GrSLType type) {
case kBufferSampler_GrSLType:
case kTexture2D_GrSLType:
case kSampler_GrSLType:
+ case kImageStorage2D_GrSLType:
+ case kIImageStorage2D_GrSLType:
return true;
case kVoid_GrSLType:
@@ -300,6 +340,15 @@ static inline GrSLType GrVertexAttribTypeToSLType(GrVertexAttribType type) {
//////////////////////////////////////////////////////////////////////////////
+enum class GrImageStorageFormat {
+ kRGBA8,
+ kRGBA8i,
+ kRGBA16f,
+ kRGBA32f,
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
/**
* We have coverage effects that clip rendering to the edge of some geometric primitive.
* This enum specifies how that clipping is performed. Not all factories that take a
diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp
index 820b428313..de4ab9e860 100644
--- a/src/gpu/GrFragmentProcessor.cpp
+++ b/src/gpu/GrFragmentProcessor.cpp
@@ -27,7 +27,7 @@ GrFragmentProcessor::~GrFragmentProcessor() {
bool GrFragmentProcessor::isEqual(const GrFragmentProcessor& that) const {
if (this->classID() != that.classID() ||
- !this->hasSameSamplers(that)) {
+ !this->hasSameSamplersAndAccesses(that)) {
return false;
}
if (!this->hasSameTransforms(that)) {
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index 1e100e41fa..738ff13e51 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -122,7 +122,12 @@ void GrProcessor::addTextureSampler(const TextureSampler* access) {
void GrProcessor::addBufferAccess(const BufferAccess* access) {
fBufferAccesses.push_back(access);
- this->addGpuResource(access->getProgramBuffer());
+ this->addGpuResource(access->programBuffer());
+}
+
+void GrProcessor::addImageStorageAccess(const ImageStorageAccess* access) {
+ fImageStorageAccesses.push_back(access);
+ this->addGpuResource(access->programTexture());
}
void* GrProcessor::operator new(size_t size) {
@@ -133,9 +138,10 @@ void GrProcessor::operator delete(void* target) {
return MemoryPoolAccessor().pool()->release(target);
}
-bool GrProcessor::hasSameSamplers(const GrProcessor& that) const {
+bool GrProcessor::hasSameSamplersAndAccesses(const GrProcessor &that) const {
if (this->numTextureSamplers() != that.numTextureSamplers() ||
- this->numBuffers() != that.numBuffers()) {
+ this->numBuffers() != that.numBuffers() ||
+ this->numImageStorages() != that.numImageStorages()) {
return false;
}
for (int i = 0; i < this->numTextureSamplers(); ++i) {
@@ -148,6 +154,11 @@ bool GrProcessor::hasSameSamplers(const GrProcessor& that) const {
return false;
}
}
+ for (int i = 0; i < this->numImageStorages(); ++i) {
+ if (this->imageStorageAccess(i) != that.imageStorageAccess(i)) {
+ return false;
+ }
+ }
return true;
}
@@ -189,6 +200,34 @@ void GrProcessor::TextureSampler::reset(GrTexture* texture,
///////////////////////////////////////////////////////////////////////////////////////////////////
+GrProcessor::ImageStorageAccess::ImageStorageAccess(sk_sp<GrTexture> texture, GrIOType ioType,
+ GrShaderFlags visibility) {
+ SkASSERT(texture);
+ fTexture.set(texture.release(), ioType);
+ fVisibility = visibility;
+ // We currently infer this from the config. However, we could allow the client to specify
+ // a format that is different but compatible with the config.
+ switch (fTexture.get()->config()) {
+ case kRGBA_8888_GrPixelConfig:
+ fFormat = GrImageStorageFormat::kRGBA8;
+ break;
+ case kRGBA_8888_sint_GrPixelConfig:
+ fFormat = GrImageStorageFormat::kRGBA8i;
+ break;
+ case kRGBA_half_GrPixelConfig:
+ fFormat = GrImageStorageFormat::kRGBA16f;
+ break;
+ case kRGBA_float_GrPixelConfig:
+ fFormat = GrImageStorageFormat::kRGBA32f;
+ break;
+ default:
+ SkFAIL("Config is not (yet) supported as image storage.");
+ break;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
// Initial static variable from GrXPFactory
int32_t GrXPFactory::gCurrXPFClassID =
GrXPFactory::kIllegalXPFClassID;
diff --git a/src/gpu/GrProgramDesc.cpp b/src/gpu/GrProgramDesc.cpp
index cdbbc23534..9f3278c927 100644
--- a/src/gpu/GrProgramDesc.cpp
+++ b/src/gpu/GrProgramDesc.cpp
@@ -15,48 +15,88 @@
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLCaps.h"
+enum {
+ kSamplerOrImageTypeKeyBits = 4
+};
+
+static inline uint16_t image_storage_or_sampler_uniform_type_key(GrSLType type ) {
+ int value = UINT16_MAX;
+ switch (type) {
+ case kTexture2DSampler_GrSLType:
+ value = 0;
+ break;
+ case kITexture2DSampler_GrSLType:
+ value = 1;
+ break;
+ case kTextureExternalSampler_GrSLType:
+ value = 2;
+ break;
+ case kTexture2DRectSampler_GrSLType:
+ value = 3;
+ break;
+ case kBufferSampler_GrSLType:
+ value = 4;
+ break;
+ case kImageStorage2D_GrSLType:
+ value = 5;
+ break;
+ case kIImageStorage2D_GrSLType:
+ value = 6;
+ break;
+
+ default:
+ break;
+ }
+ SkASSERT((value & ((1 << kSamplerOrImageTypeKeyBits) - 1)) == value);
+ return value;
+}
+
static uint16_t sampler_key(GrSLType samplerType, GrPixelConfig config, GrShaderFlags visibility,
const GrGLSLCaps& caps) {
- enum {
- kFirstSamplerType = kTexture2DSampler_GrSLType,
- kLastSamplerType = kBufferSampler_GrSLType,
- kSamplerTypeKeyBits = 4
- };
- GR_STATIC_ASSERT(kLastSamplerType - kFirstSamplerType < (1 << kSamplerTypeKeyBits));
-
- SkASSERT((int)samplerType >= kFirstSamplerType && (int)samplerType <= kLastSamplerType);
- int samplerTypeKey = samplerType - kFirstSamplerType;
-
- return SkToU16(caps.configTextureSwizzle(config).asKey() |
- (samplerTypeKey << 8) |
- (caps.samplerPrecision(config, visibility) << (8 + kSamplerTypeKeyBits)));
+ int samplerTypeKey = image_storage_or_sampler_uniform_type_key(samplerType);
+
+ GR_STATIC_ASSERT(1 == sizeof(caps.configTextureSwizzle(config).asKey()));
+ return SkToU16(samplerTypeKey |
+ caps.configTextureSwizzle(config).asKey() << kSamplerOrImageTypeKeyBits |
+ (caps.samplerPrecision(config, visibility) << (8 + kSamplerOrImageTypeKeyBits)));
}
-static void add_sampler_keys(GrProcessorKeyBuilder* b, const GrProcessor& proc,
- const GrGLSLCaps& caps) {
+static uint16_t storage_image_key(const GrProcessor::ImageStorageAccess& imageAccess) {
+ GrSLType type = imageAccess.texture()->texturePriv().imageStorageType();
+ return image_storage_or_sampler_uniform_type_key(type) |
+ (int)imageAccess.format() << kSamplerOrImageTypeKeyBits;
+}
+
+static void add_sampler_and_image_keys(GrProcessorKeyBuilder* b, const GrProcessor& proc,
+ const GrGLSLCaps& caps) {
int numTextureSamplers = proc.numTextureSamplers();
- int numSamplers = numTextureSamplers + proc.numBuffers();
- // Need two bytes per key (swizzle, sampler type, and precision).
- int word32Count = (numSamplers + 1) / 2;
+ int numBuffers = proc.numBuffers();
+ int numImageStorages = proc.numImageStorages();
+ int numUniforms = numTextureSamplers + numBuffers + numImageStorages;
+ // Need two bytes per key.
+ int word32Count = (numUniforms + 1) / 2;
if (0 == word32Count) {
return;
}
uint16_t* k16 = SkTCast<uint16_t*>(b->add32n(word32Count));
- int i = 0;
- for (; i < numTextureSamplers; ++i) {
- const GrProcessor::TextureSampler& textureSampler = proc.textureSampler(i);
- const GrTexture* tex = textureSampler.texture();
- k16[i] = sampler_key(tex->texturePriv().samplerType(), tex->config(),
- textureSampler.visibility(), caps);
+ int j = 0;
+ for (int i = 0; i < numTextureSamplers; ++i, ++j) {
+ const GrProcessor::TextureSampler& sampler = proc.textureSampler(i);
+ const GrTexture* tex = sampler.texture();
+ k16[j] = sampler_key(tex->texturePriv().samplerType(), tex->config(), sampler.visibility(),
+ caps);
+ }
+ for (int i = 0; i < numBuffers; ++i, ++j) {
+ const GrProcessor::BufferAccess& access = proc.bufferAccess(i);
+ k16[j] = sampler_key(kBufferSampler_GrSLType, access.texelConfig(), access.visibility(),
+ caps);
}
- for (; i < numSamplers; ++i) {
- const GrProcessor::BufferAccess& access = proc.bufferAccess(i - numTextureSamplers);
- k16[i] = sampler_key(kBufferSampler_GrSLType, access.texelConfig(),
- access.visibility(), caps);
+ for (int i = 0; i < numImageStorages; ++i, ++j) {
+ k16[j] = storage_image_key(proc.imageStorageAccess(i));
}
- // zero the last 16 bits if the number of samplers is odd.
- if (numSamplers & 0x1) {
- k16[numSamplers] = 0;
+ // zero the last 16 bits if the number of uniforms for samplers and image storages is odd.
+ if (numUniforms & 0x1) {
+ k16[numUniforms] = 0;
}
}
@@ -82,7 +122,7 @@ static bool gen_meta_key(const GrProcessor& proc,
return false;
}
- add_sampler_keys(b, proc, glslCaps);
+ add_sampler_and_image_keys(b, proc, glslCaps);
uint32_t* key = b->add32n(2);
key[0] = (classID << 16) | SkToU32(processorKeySize);
diff --git a/src/gpu/GrShaderVar.cpp b/src/gpu/GrShaderVar.cpp
index ef305cbfc9..e1ea207e81 100644
--- a/src/gpu/GrShaderVar.cpp
+++ b/src/gpu/GrShaderVar.cpp
@@ -9,14 +9,47 @@
#include "GrShaderVar.h"
#include "glsl/GrGLSLCaps.h"
+static const char* type_modifier_string(GrShaderVar::TypeModifier t) {
+ switch (t) {
+ case GrShaderVar::kNone_TypeModifier: return "";
+ case GrShaderVar::kIn_TypeModifier: return "in";
+ case GrShaderVar::kInOut_TypeModifier: return "inout";
+ case GrShaderVar::kOut_TypeModifier: return "out";
+ case GrShaderVar::kUniform_TypeModifier: return "uniform";
+ }
+ SkFAIL("Unknown shader variable type modifier.");
+ return "";
+}
+
+void GrShaderVar::setImageStorageFormat(GrImageStorageFormat format) {
+ const char* formatStr = nullptr;
+ switch (format) {
+ case GrImageStorageFormat::kRGBA8:
+ formatStr = "rgba8";
+ break;
+ case GrImageStorageFormat::kRGBA8i:
+ formatStr = "rgba8i";
+ break;
+ case GrImageStorageFormat::kRGBA16f:
+ formatStr = "rgba16f";
+ break;
+ case GrImageStorageFormat::kRGBA32f:
+ formatStr = "rgba32f";
+ break;
+ }
+ this->addLayoutQualifier(formatStr);
+ SkASSERT(formatStr);
+}
+
void GrShaderVar::appendDecl(const GrGLSLCaps* glslCaps, SkString* out) const {
SkASSERT(kDefault_GrSLPrecision == fPrecision || GrSLTypeAcceptsPrecision(fType));
+ SkString layout = fLayoutQualifier;
if (!fLayoutQualifier.isEmpty()) {
out->appendf("layout(%s) ", fLayoutQualifier.c_str());
}
out->append(fExtraModifiers);
if (this->getTypeModifier() != kNone_TypeModifier) {
- out->append(TypeModifierString(this->getTypeModifier()));
+ out->append(type_modifier_string(this->getTypeModifier()));
out->append(" ");
}
GrSLType effectiveType = this->getType();
diff --git a/src/gpu/GrTexturePriv.h b/src/gpu/GrTexturePriv.h
index d68eb799e8..042061129d 100644
--- a/src/gpu/GrTexturePriv.h
+++ b/src/gpu/GrTexturePriv.h
@@ -49,6 +49,14 @@ public:
return fTexture->fMaxMipMapLevel;
}
+ GrSLType imageStorageType() const {
+ if (GrPixelConfigIsSint(fTexture->config())) {
+ return kIImageStorage2D_GrSLType;
+ } else {
+ return kImageStorage2D_GrSLType;
+ }
+ }
+
GrSLType samplerType() const { return fTexture->fSamplerType; }
/** The filter used is clamped to this value in GrProcessor::TextureSampler. */
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 9f24e5099d..0e6007b11a 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -324,16 +324,21 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
static constexpr int kMaxSaneImages = 4;
GrGLint maxUnits;
GR_GL_GetIntegerv(gli, GR_GL_MAX_IMAGE_UNITS, &maxUnits);
- GR_GL_GetIntegerv(gli, GR_GL_MAX_VERTEX_IMAGE_UNIFORMS, &glslCaps->fMaxVertexImages);
- GR_GL_GetIntegerv(gli, GR_GL_MAX_GEOMETRY_IMAGE_UNIFORMS, &glslCaps->fMaxGeometryImages);
- GR_GL_GetIntegerv(gli, GR_GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &glslCaps->fMaxFragmentImages);
- GR_GL_GetIntegerv(gli, GR_GL_MAX_COMBINED_IMAGE_UNIFORMS, &glslCaps->fMaxCombinedImages);
+ GR_GL_GetIntegerv(gli, GR_GL_MAX_VERTEX_IMAGE_UNIFORMS,
+ &glslCaps->fMaxVertexImageStorages);
+ GR_GL_GetIntegerv(gli, GR_GL_MAX_GEOMETRY_IMAGE_UNIFORMS,
+ &glslCaps->fMaxGeometryImageStorages);
+ GR_GL_GetIntegerv(gli, GR_GL_MAX_FRAGMENT_IMAGE_UNIFORMS,
+ &glslCaps->fMaxFragmentImageStorages);
+ GR_GL_GetIntegerv(gli, GR_GL_MAX_COMBINED_IMAGE_UNIFORMS,
+ &glslCaps->fMaxCombinedImageStorages);
// We use one unit for every image uniform
- glslCaps->fMaxCombinedImages = SkTMin(SkTMin(glslCaps->fMaxCombinedImages, maxUnits),
- kMaxSaneImages);
- glslCaps->fMaxVertexImages = SkTMin(maxUnits, glslCaps->fMaxVertexImages);
- glslCaps->fMaxGeometryImages = SkTMin(maxUnits, glslCaps->fMaxGeometryImages);
- glslCaps->fMaxFragmentImages = SkTMin(maxUnits, glslCaps->fMaxFragmentImages);
+ glslCaps->fMaxCombinedImageStorages = SkTMin(SkTMin(glslCaps->fMaxCombinedImageStorages,
+ maxUnits), kMaxSaneImages);
+ glslCaps->fMaxVertexImageStorages = SkTMin(maxUnits, glslCaps->fMaxVertexImageStorages);
+ glslCaps->fMaxGeometryImageStorages = SkTMin(maxUnits, glslCaps->fMaxGeometryImageStorages);
+ glslCaps->fMaxFragmentImageStorages = SkTMin(maxUnits,
+ glslCaps->fMaxFragmentImageStorages);
}
/**************************************************************************
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index 496635d766..c96275fc17 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -159,6 +159,11 @@ public:
bool getRenderbufferFormat(GrPixelConfig config, GrGLenum* internalFormat) const;
+ /** The format to use read/write a texture as an image in a shader */
+ GrGLenum getImageFormat(GrPixelConfig config) const {
+ return fConfigTable[config].fFormats.fSizedInternalFormat;
+ }
+
/**
* Gets an array of legal stencil formats. These formats are not guaranteed
* to be supported by the driver but are legal GLenum names given the GL
@@ -451,7 +456,6 @@ private:
GrGLenum fExternalFormat[kExternalFormatUsageCnt];
GrGLenum fExternalType;
-
// Either the base or sized internal format depending on the GL and config.
GrGLenum fInternalFormatTexImage;
GrGLenum fInternalFormatRenderbuffer;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 9c25602187..776405267d 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -217,6 +217,7 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context)
fCaps.reset(SkRef(ctx->caps()));
fHWBoundTextureUniqueIDs.reset(this->glCaps().glslCaps()->maxCombinedSamplers());
+ fHWBoundImageStorages.reset(this->glCaps().glslCaps()->maxCombinedImageStorages());
fHWBufferState[kVertex_GrBufferType].fGLTarget = GR_GL_ARRAY_BUFFER;
fHWBufferState[kIndex_GrBufferType].fGLTarget = GR_GL_ELEMENT_ARRAY_BUFFER;
@@ -557,6 +558,10 @@ void GrGLGpu::onResetContext(uint32_t resetBits) {
SkASSERT(this->caps()->shaderCaps()->texelBufferSupport());
fHWBufferTextures[b].fKnownBound = false;
}
+ for (int i = 0; i < fHWBoundImageStorages.count(); ++i) {
+ SkASSERT(this->caps()->shaderCaps()->imageLoadStoreSupport());
+ fHWBoundImageStorages[i].fTextureUniqueID.makeInvalid();
+ }
}
if (resetBits & kBlend_GrGLBackendState) {
@@ -3342,6 +3347,27 @@ void GrGLGpu::bindTexelBuffer(int unitIdx, GrPixelConfig texelConfig, GrGLBuffer
}
}
+void GrGLGpu::bindImageStorage(int unitIdx, GrIOType ioType, GrGLTexture *texture) {
+ SkASSERT(texture);
+ if (texture->uniqueID() != fHWBoundImageStorages[unitIdx].fTextureUniqueID ||
+ ioType != fHWBoundImageStorages[unitIdx].fIOType) {
+ GrGLenum access;
+ switch (ioType) {
+ case kRead_GrIOType:
+ access = GR_GL_READ_ONLY;
+ break;
+ case kWrite_GrIOType:
+ access = GR_GL_WRITE_ONLY;
+ break;
+ case kRW_GrIOType:
+ access = GR_GL_READ_WRITE;
+ break;
+ }
+ GrGLenum format = this->glCaps().getImageFormat(texture->config());
+ GL_CALL(BindImageTexture(unitIdx, texture->textureID(), 0, GR_GL_FALSE, 0, access, format));
+ }
+}
+
void GrGLGpu::generateMipmaps(const GrSamplerParams& params, bool allowSRGBInputs,
GrGLTexture* texture) {
SkASSERT(texture);
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index dff342d823..c6e7935ed0 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -62,6 +62,8 @@ public:
void bindTexelBuffer(int unitIdx, GrPixelConfig, GrGLBuffer*);
+ void bindImageStorage(int unitIdx, GrIOType, GrGLTexture *);
+
void generateMipmaps(const GrSamplerParams& params, bool allowSRGBInputs, GrGLTexture* texture);
bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes,
@@ -569,6 +571,12 @@ private:
TriState fHWSRGBFramebuffer;
SkTArray<GrGpuResource::UniqueID, true> fHWBoundTextureUniqueIDs;
+ struct Image {
+ GrGpuResource::UniqueID fTextureUniqueID;
+ GrIOType fIOType;
+ };
+ SkTArray<Image, true> fHWBoundImageStorages;
+
struct BufferTexture {
BufferTexture() : fTextureID(0), fKnownBound(false),
fAttachedBufferUniqueID(SK_InvalidUniqueID),
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 1f2e1c8446..8a61ecafa7 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -32,6 +32,7 @@ GrGLProgram::GrGLProgram(GrGLGpu* gpu,
GrGLuint programID,
const UniformInfoArray& uniforms,
const UniformInfoArray& samplers,
+ const UniformInfoArray& imageStorages,
const VaryingInfoArray& pathProcVaryings,
GrGLSLPrimitiveProcessor* geometryProcessor,
GrGLSLXferProcessor* xferProcessor,
@@ -47,6 +48,7 @@ GrGLProgram::GrGLProgram(GrGLGpu* gpu,
// Assign texture units to sampler uniforms one time up front.
GL_CALL(UseProgram(fProgramID));
fProgramDataManager.setSamplers(samplers);
+ fProgramDataManager.setImageStorages(imageStorages);
}
GrGLProgram::~GrGLProgram() {
@@ -162,6 +164,11 @@ void GrGLProgram::bindTextures(const GrProcessor& processor,
fGpu->bindTexelBuffer((*nextSamplerIdx)++, access.texelConfig(),
static_cast<GrGLBuffer*>(access.buffer()));
}
+ for (int i = 0; i < processor.numImageStorages(); ++i) {
+ const GrProcessor::ImageStorageAccess& access = processor.imageStorageAccess(i);
+ fGpu->bindImageStorage((*nextSamplerIdx)++, access.ioType(),
+ static_cast<GrGLTexture *>(access.texture()));
+ }
}
void GrGLProgram::generateMipmaps(const GrProcessor& processor,
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 3b0940e0d2..ea00df2f1e 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -103,9 +103,9 @@ public:
void generateMipmaps(const GrPrimitiveProcessor&, const GrPipeline&);
protected:
- typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
- typedef GrGLProgramDataManager::UniformInfoArray UniformInfoArray;
- typedef GrGLProgramDataManager::VaryingInfoArray VaryingInfoArray;
+ using UniformHandle = GrGLSLProgramDataManager::UniformHandle ;
+ using UniformInfoArray = GrGLProgramDataManager::UniformInfoArray;
+ using VaryingInfoArray = GrGLProgramDataManager::VaryingInfoArray;
GrGLProgram(GrGLGpu*,
const GrProgramDesc&,
@@ -113,6 +113,7 @@ protected:
GrGLuint programID,
const UniformInfoArray& uniforms,
const UniformInfoArray& samplers,
+ const UniformInfoArray& imageStorages,
const VaryingInfoArray&, // used for NVPR only currently
GrGLSLPrimitiveProcessor* geometryProcessor,
GrGLSLXferProcessor* xferProcessor,
diff --git a/src/gpu/gl/GrGLProgramDataManager.cpp b/src/gpu/gl/GrGLProgramDataManager.cpp
index 3245bd7185..863eab7abf 100644
--- a/src/gpu/gl/GrGLProgramDataManager.cpp
+++ b/src/gpu/gl/GrGLProgramDataManager.cpp
@@ -65,6 +65,16 @@ void GrGLProgramDataManager::setSamplers(const UniformInfoArray& samplers) const
}
}
+void GrGLProgramDataManager::setImageStorages(const UniformInfoArray& images) const {
+ for (int i = 0; i < images.count(); ++i) {
+ const UniformInfo& image = images[i];
+ SkASSERT(image.fVisibility);
+ if (kUnusedUniform != image.fLocation) {
+ GR_GL_CALL(fGpu->glInterface(), Uniform1i(image.fLocation, i));
+ }
+ }
+}
+
void GrGLProgramDataManager::set1i(UniformHandle u, int32_t i) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kInt_GrSLType);
diff --git a/src/gpu/gl/GrGLProgramDataManager.h b/src/gpu/gl/GrGLProgramDataManager.h
index 0ef902c10b..62af4b8cc0 100644
--- a/src/gpu/gl/GrGLProgramDataManager.h
+++ b/src/gpu/gl/GrGLProgramDataManager.h
@@ -47,6 +47,7 @@ public:
void setSamplers(const UniformInfoArray& samplers) const;
+ void setImageStorages(const UniformInfoArray &images) const;
/** Functions for uploading uniform values. The varities ending in v can be used to upload to an
* array of uniforms. arrayCount must be <= the array count of the uniform.
diff --git a/src/gpu/gl/GrGLUniformHandler.cpp b/src/gpu/gl/GrGLUniformHandler.cpp
index 2def001f43..6a2e21fb5c 100644
--- a/src/gpu/gl/GrGLUniformHandler.cpp
+++ b/src/gpu/gl/GrGLUniformHandler.cpp
@@ -80,11 +80,33 @@ GrGLSLUniformHandler::SamplerHandle GrGLUniformHandler::addSampler(uint32_t visi
return GrGLSLUniformHandler::SamplerHandle(fSamplers.count() - 1);
}
+GrGLSLUniformHandler::ImageStorageHandle GrGLUniformHandler::addImageStorage(
+ uint32_t visibility, GrSLType type, GrImageStorageFormat format, const char* name) {
+ SkASSERT(name && strlen(name));
+ SkDEBUGCODE(static const uint32_t kVisMask = kVertex_GrShaderFlag | kFragment_GrShaderFlag);
+ SkASSERT(0 == (~kVisMask & visibility));
+ SkASSERT(0 != visibility);
+ SkString mangleName;
+ char prefix = 'u';
+ fProgramBuilder->nameVariable(&mangleName, prefix, name, true);
+
+ UniformInfo& imageStorage = fImageStorages.push_back();
+ imageStorage.fVariable.setName(mangleName);
+
+ SkASSERT(GrSLTypeIsImageStorage(type));
+ imageStorage.fVariable.setType(type);
+ imageStorage.fVariable.setTypeModifier(GrShaderVar::kUniform_TypeModifier);
+ imageStorage.fVariable.setImageStorageFormat(format);
+ imageStorage.fLocation = -1;
+ imageStorage.fVisibility = visibility;
+ return GrGLSLUniformHandler::ImageStorageHandle(fImageStorages.count() - 1);
+}
+
void GrGLUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
for (int i = 0; i < fUniforms.count(); ++i) {
if (fUniforms[i].fVisibility & visibility) {
fUniforms[i].fVariable.appendDecl(fProgramBuilder->glslCaps(), out);
- out->append(";\n");
+ out->append(";");
}
}
for (int i = 0; i < fSamplers.count(); ++i) {
@@ -93,19 +115,29 @@ void GrGLUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString*
out->append(";\n");
}
}
+ for (int i = 0; i < fImageStorages.count(); ++i) {
+ if (fImageStorages[i].fVisibility & visibility) {
+ fImageStorages[i].fVariable.appendDecl(fProgramBuilder->glslCaps(), out);
+ out->append(";");
+ }
+ }
}
void GrGLUniformHandler::bindUniformLocations(GrGLuint programID, const GrGLCaps& caps) {
if (caps.bindUniformLocationSupport()) {
- int uniformCnt = fUniforms.count();
- for (int i = 0; i < uniformCnt; ++i) {
- GL_CALL(BindUniformLocation(programID, i, fUniforms[i].fVariable.c_str()));
- fUniforms[i].fLocation = i;
+ int currUniform = 0;
+ for (int i = 0; i < fUniforms.count(); ++i, ++currUniform) {
+ GL_CALL(BindUniformLocation(programID, currUniform, fUniforms[i].fVariable.c_str()));
+ fUniforms[i].fLocation = currUniform;
}
- for (int i = 0; i < fSamplers.count(); ++i) {
- GrGLint location = i + uniformCnt;
- GL_CALL(BindUniformLocation(programID, location, fSamplers[i].fVariable.c_str()));
- fSamplers[i].fLocation = location;
+ for (int i = 0; i < fSamplers.count(); ++i, ++currUniform) {
+ GL_CALL(BindUniformLocation(programID, currUniform, fSamplers[i].fVariable.c_str()));
+ fSamplers[i].fLocation = currUniform;
+ }
+ for (int i = 0; i < fImageStorages.count(); ++i) {
+ GL_CALL(BindUniformLocation(programID, currUniform,
+ fImageStorages[i].fVariable.c_str()));
+ fImageStorages[i].fLocation = currUniform;
}
}
}
@@ -123,6 +155,12 @@ void GrGLUniformHandler::getUniformLocations(GrGLuint programID, const GrGLCaps&
GL_CALL_RET(location, GetUniformLocation(programID, fSamplers[i].fVariable.c_str()));
fSamplers[i].fLocation = location;
}
+ for (int i = 0; i < fImageStorages.count(); ++i) {
+ GrGLint location;
+ GL_CALL_RET(location, GetUniformLocation(programID,
+ fImageStorages[i].fVariable.c_str()));
+ fImageStorages[i].fLocation = location;
+ }
}
}
diff --git a/src/gpu/gl/GrGLUniformHandler.h b/src/gpu/gl/GrGLUniformHandler.h
index d3aa2f8358..32663a42ef 100644
--- a/src/gpu/gl/GrGLUniformHandler.h
+++ b/src/gpu/gl/GrGLUniformHandler.h
@@ -29,7 +29,8 @@ private:
explicit GrGLUniformHandler(GrGLSLProgramBuilder* program)
: INHERITED(program)
, fUniforms(kUniformsPerBlock)
- , fSamplers(kUniformsPerBlock) {}
+ , fSamplers(kUniformsPerBlock)
+ , fImageStorages(kUniformsPerBlock) {}
UniformHandle internalAddUniformArray(uint32_t visibility,
GrSLType type,
@@ -46,10 +47,19 @@ private:
return fSamplers[handle.toIndex()].fVariable;
}
+ ImageStorageHandle addImageStorage(uint32_t visibility,
+ GrSLType,
+ GrImageStorageFormat,
+ const char* name) override;
+
GrSwizzle samplerSwizzle(SamplerHandle handle) const override {
return fSamplerSwizzles[handle.toIndex()];
}
+ const GrShaderVar& imageStorageVariable(ImageStorageHandle handle) const override {
+ return fImageStorages[handle.toIndex()].fVariable;
+ }
+
void appendUniformDecls(GrShaderFlags visibility, SkString*) const override;
// Manually set uniform locations for all our uniforms.
@@ -66,6 +76,7 @@ private:
UniformInfoArray fUniforms;
UniformInfoArray fSamplers;
SkTArray<GrSwizzle> fSamplerSwizzles;
+ UniformInfoArray fImageStorages;
friend class GrGLProgramBuilder;
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index a1ad572a86..a774570b68 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -237,6 +237,7 @@ GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
programID,
fUniformHandler.fUniforms,
fUniformHandler.fSamplers,
+ fUniformHandler.fImageStorages,
fVaryingHandler.fPathProcVaryingInfos,
fGeometryProcessor,
fXferProcessor,
diff --git a/src/gpu/glsl/GrGLSL.h b/src/gpu/glsl/GrGLSL.h
index 4461f4c60f..bc5b319465 100644
--- a/src/gpu/glsl/GrGLSL.h
+++ b/src/gpu/glsl/GrGLSL.h
@@ -146,6 +146,10 @@ static inline const char* GrGLSLTypeString(GrSLType t) {
return "texture2D";
case kSampler_GrSLType:
return "sampler";
+ case kImageStorage2D_GrSLType:
+ return "image2D";
+ case kIImageStorage2D_GrSLType:
+ return "iimage2D";
}
SkFAIL("Unknown shader var type.");
return ""; // suppress warning
diff --git a/src/gpu/glsl/GrGLSLCaps.cpp b/src/gpu/glsl/GrGLSLCaps.cpp
index 5bb22b3974..57e5a0c04e 100644
--- a/src/gpu/glsl/GrGLSLCaps.cpp
+++ b/src/gpu/glsl/GrGLSLCaps.cpp
@@ -47,10 +47,10 @@ GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) {
fMaxGeometrySamplers = 0;
fMaxFragmentSamplers = 0;
fMaxCombinedSamplers = 0;
- fMaxVertexImages = 0;
- fMaxGeometryImages = 0;
- fMaxFragmentImages = 0;
- fMaxCombinedImages = 0;
+ fMaxVertexImageStorages = 0;
+ fMaxGeometryImageStorages = 0;
+ fMaxFragmentImageStorages = 0;
+ fMaxCombinedImageStorages = 0;
fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction;
}
@@ -95,10 +95,10 @@ SkString GrGLSLCaps::dump() const {
r.appendf("Max GS Samplers: %d\n", fMaxGeometrySamplers);
r.appendf("Max FS Samplers: %d\n", fMaxFragmentSamplers);
r.appendf("Max Combined Samplers: %d\n", fMaxFragmentSamplers);
- r.appendf("Max VS Images: %d\n", fMaxVertexImages);
- r.appendf("Max GS Images: %d\n", fMaxGeometryImages);
- r.appendf("Max FS Images: %d\n", fMaxFragmentImages);
- r.appendf("Max Combined Images: %d\n", fMaxFragmentImages);
+ r.appendf("Max VS Image Storages: %d\n", fMaxVertexImageStorages);
+ r.appendf("Max GS Image Storages: %d\n", fMaxGeometryImageStorages);
+ r.appendf("Max FS Image Storages: %d\n", fMaxFragmentImageStorages);
+ r.appendf("Max Combined Image Storages: %d\n", fMaxFragmentImageStorages);
r.appendf("Advanced blend equation interaction: %s\n",
kAdvBlendEqInteractionStr[fAdvBlendEqInteraction]);
return r;
diff --git a/src/gpu/glsl/GrGLSLCaps.h b/src/gpu/glsl/GrGLSLCaps.h
index 4c53ad02fd..11ce754527 100644
--- a/src/gpu/glsl/GrGLSLCaps.h
+++ b/src/gpu/glsl/GrGLSLCaps.h
@@ -157,13 +157,13 @@ public:
int maxCombinedSamplers() const { return fMaxCombinedSamplers; }
- int maxVertexImages() const { return fMaxVertexImages; }
+ int maxVertexImageStorages() const { return fMaxVertexImageStorages; }
- int maxGeometryImages() const { return fMaxGeometryImages; }
+ int maxGeometryImageStorages() const { return fMaxGeometryImageStorages; }
- int maxFragmentImages() const { return fMaxFragmentImages; }
+ int maxFragmentImageStorages() const { return fMaxFragmentImageStorages; }
- int maxCombinedImages() const { return fMaxCombinedImages; }
+ int maxCombinedImageStorages() const { return fMaxCombinedImageStorages; }
/**
* Given a texture's config, this determines what swizzle must be appended to accesses to the
@@ -238,10 +238,10 @@ private:
int fMaxFragmentSamplers;
int fMaxCombinedSamplers;
- int fMaxVertexImages;
- int fMaxGeometryImages;
- int fMaxFragmentImages;
- int fMaxCombinedImages;
+ int fMaxVertexImageStorages;
+ int fMaxGeometryImageStorages;
+ int fMaxFragmentImageStorages;
+ int fMaxCombinedImageStorages;
AdvBlendEqInteraction fAdvBlendEqInteraction;
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
index 5ae7fee7db..8c32482d8e 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
@@ -49,6 +49,7 @@ void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* inpu
TransformedCoordVars coordVars = args.fTransformedCoords.childInputs(childIndex);
TextureSamplers textureSamplers = args.fTexSamplers.childInputs(childIndex);
BufferSamplers bufferSamplers = args.fBufferSamplers.childInputs(childIndex);
+ ImageStorages imageStorages = args.fImageStorages.childInputs(childIndex);
EmitArgs childArgs(fragBuilder,
args.fUniformHandler,
args.fGLSLCaps,
@@ -58,6 +59,7 @@ void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* inpu
coordVars,
textureSamplers,
bufferSamplers,
+ imageStorages,
args.fGpImplementsDistanceVector);
this->childProcessor(childIndex)->emitCode(childArgs);
fragBuilder->codeAppend("}\n");
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.h b/src/gpu/glsl/GrGLSLFragmentProcessor.h
index aba68b7e05..c8154231b5 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.h
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.h
@@ -11,13 +11,13 @@
#include "GrFragmentProcessor.h"
#include "GrShaderVar.h"
#include "glsl/GrGLSLProgramDataManager.h"
+#include "glsl/GrGLSLUniformHandler.h"
class GrProcessor;
class GrProcessorKeyBuilder;
class GrGLSLCaps;
class GrGLSLFPBuilder;
class GrGLSLFPFragmentBuilder;
-class GrGLSLUniformHandler;
class GrGLSLFragmentProcessor {
public:
@@ -29,8 +29,9 @@ public:
}
}
- typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
- typedef GrGLSLProgramDataManager::UniformHandle SamplerHandle;
+ using UniformHandle = GrGLSLUniformHandler::UniformHandle;
+ using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
+ using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle;
private:
/**
@@ -74,6 +75,8 @@ public:
&GrProcessor::numTextureSamplers>;
using BufferSamplers = BuilderInputProvider<SamplerHandle, GrProcessor,
&GrProcessor::numBuffers>;
+ using ImageStorages = BuilderInputProvider<ImageStorageHandle, GrProcessor,
+ &GrProcessor::numImageStorages>;
/** Called when the program stage should insert its code into the shaders. The code in each
shader will be in its own block ({}) and so locally scoped names will not collide across
@@ -99,6 +102,12 @@ public:
@param bufferSamplers Contains one entry for each BufferAccess of the GrProcessor. These
can be passed to the builder to emit buffer reads in the generated
code.
+ @param imageStorages Contains one entry for each ImageStorageAccess of the GrProcessor.
+ These can be passed to the builder to emit image loads and stores
+ in the generated code.
+ @param gpImplementsDistanceVector
+ Does the GrGeometryProcessor implement the feature where it
+ provides a vector to the nearest edge of the shape being rendered.
*/
struct EmitArgs {
EmitArgs(GrGLSLFPFragmentBuilder* fragBuilder,
@@ -110,6 +119,7 @@ public:
const TransformedCoordVars& transformedCoordVars,
const TextureSamplers& textureSamplers,
const BufferSamplers& bufferSamplers,
+ const ImageStorages& imageStorages,
bool gpImplementsDistanceVector)
: fFragBuilder(fragBuilder)
, fUniformHandler(uniformHandler)
@@ -120,6 +130,7 @@ public:
, fTransformedCoords(transformedCoordVars)
, fTexSamplers(textureSamplers)
, fBufferSamplers(bufferSamplers)
+ , fImageStorages(imageStorages)
, fGpImplementsDistanceVector(gpImplementsDistanceVector) {}
GrGLSLFPFragmentBuilder* fFragBuilder;
GrGLSLUniformHandler* fUniformHandler;
@@ -130,6 +141,7 @@ public:
const TransformedCoordVars& fTransformedCoords;
const TextureSamplers& fTexSamplers;
const BufferSamplers& fBufferSamplers;
+ const ImageStorages& fImageStorages;
bool fGpImplementsDistanceVector;
};
diff --git a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
index 199163939f..b398cfd5c7 100644
--- a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
+++ b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
@@ -11,6 +11,7 @@
#include "GrFragmentProcessor.h"
#include "GrPrimitiveProcessor.h"
#include "glsl/GrGLSLProgramDataManager.h"
+#include "glsl/GrGLSLUniformHandler.h"
class GrBatchTracker;
class GrPrimitiveProcessor;
@@ -18,7 +19,6 @@ class GrGLSLCaps;
class GrGLSLPPFragmentBuilder;
class GrGLSLGeometryBuilder;
class GrGLSLGPBuilder;
-class GrGLSLUniformHandler;
class GrGLSLVaryingHandler;
class GrGLSLVertexBuilder;
@@ -28,8 +28,9 @@ public:
virtual ~GrGLSLPrimitiveProcessor() {}
- typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
- typedef GrGLSLProgramDataManager::UniformHandle SamplerHandle;
+ using UniformHandle = GrGLSLProgramDataManager::UniformHandle;
+ using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
+ using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle;
/**
* This class provides access to the GrCoordTransforms across all GrFragmentProcessors in a
@@ -77,6 +78,7 @@ public:
const char* distanceVectorName,
const SamplerHandle* texSamplers,
const SamplerHandle* bufferSamplers,
+ const ImageStorageHandle* imageStorages,
FPCoordTransformHandler* transformHandler)
: fVertBuilder(vertBuilder)
, fGeomBuilder(geomBuilder)
@@ -90,6 +92,7 @@ public:
, fDistanceVectorName(distanceVectorName)
, fTexSamplers(texSamplers)
, fBufferSamplers(bufferSamplers)
+ , fImageStorages(imageStorages)
, fFPCoordTransformHandler(transformHandler) {}
GrGLSLVertexBuilder* fVertBuilder;
GrGLSLGeometryBuilder* fGeomBuilder;
@@ -103,6 +106,7 @@ public:
const char* fDistanceVectorName;
const SamplerHandle* fTexSamplers;
const SamplerHandle* fBufferSamplers;
+ const ImageStorageHandle* fImageStorages;
FPCoordTransformHandler* fFPCoordTransformHandler;
};
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index e8097c783f..03a9c21d26 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -31,7 +31,10 @@ GrGLSLProgramBuilder::GrGLSLProgramBuilder(const GrPipeline& pipeline,
, fXferProcessor(nullptr)
, fNumVertexSamplers(0)
, fNumGeometrySamplers(0)
- , fNumFragmentSamplers(0) {
+ , fNumFragmentSamplers(0)
+ , fNumVertexImageStorages(0)
+ , fNumGeometryImageStorages(0)
+ , fNumFragmentImageStorages(0) {
}
void GrGLSLProgramBuilder::addFeature(GrShaderFlags shaders,
@@ -66,7 +69,7 @@ bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor,
this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
}
- return this->checkSamplerCounts();
+ return this->checkSamplerCounts() && this->checkImageStorageCounts();
}
void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc,
@@ -97,9 +100,10 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr
SkASSERT(!fGeometryProcessor);
fGeometryProcessor = proc.createGLSLInstance(*this->glslCaps());
- SkSTArray<4, SamplerHandle> texSamplers(proc.numTextureSamplers());
- SkSTArray<2, SamplerHandle> bufferSamplers(proc.numBuffers());
- this->emitSamplers(proc, &texSamplers, &bufferSamplers);
+ SkSTArray<4, SamplerHandle> texSamplers(proc.numTextureSamplers());
+ SkSTArray<2, SamplerHandle> bufferSamplers(proc.numBuffers());
+ SkSTArray<2, ImageStorageHandle> imageStorages(proc.numImageStorages());
+ this->emitSamplersAndImageStorages(proc, &texSamplers, &bufferSamplers, &imageStorages);
GrGLSLPrimitiveProcessor::FPCoordTransformHandler transformHandler(fPipeline,
&fTransformedCoordVars);
@@ -115,6 +119,7 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr
distanceVectorName,
texSamplers.begin(),
bufferSamplers.begin(),
+ imageStorages.begin(),
&transformHandler);
fGeometryProcessor->emitCode(args);
@@ -163,15 +168,18 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
SkSTArray<4, SamplerHandle> textureSamplerArray(fp.numTextureSamplers());
SkSTArray<2, SamplerHandle> bufferSamplerArray(fp.numBuffers());
+ SkSTArray<2, ImageStorageHandle> imageStorageArray(fp.numImageStorages());
GrFragmentProcessor::Iter iter(&fp);
while (const GrFragmentProcessor* subFP = iter.next()) {
- this->emitSamplers(*subFP, &textureSamplerArray, &bufferSamplerArray);
+ this->emitSamplersAndImageStorages(*subFP, &textureSamplerArray, &bufferSamplerArray,
+ &imageStorageArray);
}
const GrShaderVar* coordVars = fTransformedCoordVars.begin() + transformedCoordVarsIdx;
GrGLSLFragmentProcessor::TransformedCoordVars coords(&fp, coordVars);
GrGLSLFragmentProcessor::TextureSamplers textureSamplers(&fp, textureSamplerArray.begin());
GrGLSLFragmentProcessor::BufferSamplers bufferSamplers(&fp, bufferSamplerArray.begin());
+ GrGLSLFragmentProcessor::ImageStorages imageStorages(&fp, imageStorageArray.begin());
GrGLSLFragmentProcessor::EmitArgs args(&fFS,
this->uniformHandler(),
this->glslCaps(),
@@ -181,6 +189,7 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
coords,
textureSamplers,
bufferSamplers,
+ imageStorages,
this->primitiveProcessor().implementsDistanceVector());
fragProc->emitCode(args);
@@ -217,9 +226,10 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
fFS.codeAppend(openBrace.c_str());
- SkSTArray<4, SamplerHandle> texSamplers(xp.numTextureSamplers());
- SkSTArray<2, SamplerHandle> bufferSamplers(xp.numBuffers());
- this->emitSamplers(xp, &texSamplers, &bufferSamplers);
+ SkSTArray<4, SamplerHandle> texSamplers(xp.numTextureSamplers());
+ SkSTArray<2, SamplerHandle> bufferSamplers(xp.numBuffers());
+ SkSTArray<2, ImageStorageHandle> imageStorageArray(xp.numImageStorages());
+ this->emitSamplersAndImageStorages(xp, &texSamplers, &bufferSamplers, &imageStorageArray);
bool usePLSDstRead = (plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState);
GrGLSLXferProcessor::EmitArgs args(&fFS,
@@ -231,6 +241,7 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
fFS.getSecondaryColorOutputName(),
texSamplers.begin(),
bufferSamplers.begin(),
+ imageStorageArray.begin(),
usePLSDstRead);
fXferProcessor->emitCode(args);
@@ -240,13 +251,16 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
fFS.codeAppend("}");
}
-void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor,
- SkTArray<SamplerHandle>* outTexSamplers,
- SkTArray<SamplerHandle>* outBufferSamplers) {
+void GrGLSLProgramBuilder::emitSamplersAndImageStorages(
+ const GrProcessor& processor,
+ SkTArray<SamplerHandle>* outTexSamplerHandles,
+ SkTArray<SamplerHandle>* outBufferSamplerHandles,
+ SkTArray<ImageStorageHandle>* outImageStorageHandles) {
SkString name;
int numTextureSamplers = processor.numTextureSamplers();
for (int t = 0; t < numTextureSamplers; ++t) {
const GrProcessor::TextureSampler& sampler = processor.textureSampler(t);
+ name.printf("TextureSampler_%d", outTexSamplerHandles->count());
GrSLType samplerType = sampler.texture()->texturePriv().samplerType();
if (kTextureExternalSampler_GrSLType == samplerType) {
const char* externalFeatureString = this->glslCaps()->externalTextureExtensionString();
@@ -256,9 +270,9 @@ void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor,
1 << GrGLSLShaderBuilder::kExternalTexture_GLSLPrivateFeature,
externalFeatureString);
}
- name.printf("TextureSampler_%d", outTexSamplers->count());
- this->emitSampler(samplerType, sampler.texture()->config(),
- name.c_str(), sampler.visibility(), outTexSamplers);
+ this->emitSampler(samplerType, sampler.texture()->config(), name.c_str(),
+ sampler.visibility(), outTexSamplerHandles);
+
}
if (int numBuffers = processor.numBuffers()) {
@@ -267,9 +281,9 @@ void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor,
for (int b = 0; b < numBuffers; ++b) {
const GrProcessor::BufferAccess& access = processor.bufferAccess(b);
- name.printf("BufferSampler_%d", outBufferSamplers->count());
+ name.printf("BufferSampler_%d", outBufferSamplerHandles->count());
this->emitSampler(kBufferSampler_GrSLType, access.texelConfig(), name.c_str(),
- access.visibility(), outBufferSamplers);
+ access.visibility(), outBufferSamplerHandles);
texelBufferVisibility |= access.visibility();
}
@@ -279,13 +293,19 @@ void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor,
extension);
}
}
+ int numImageStorages = processor.numImageStorages();
+ for (int i = 0; i < numImageStorages; ++i) {
+ const GrProcessor::ImageStorageAccess& imageStorageAccess = processor.imageStorageAccess(i);
+ name.printf("Image_%d", outImageStorageHandles->count());
+ this->emitImageStorage(imageStorageAccess, name.c_str(), outImageStorageHandles);
+ }
}
void GrGLSLProgramBuilder::emitSampler(GrSLType samplerType,
GrPixelConfig config,
const char* name,
GrShaderFlags visibility,
- SkTArray<SamplerHandle>* outSamplers) {
+ SkTArray<SamplerHandle>* outSamplerHandles) {
if (visibility & kVertex_GrShaderFlag) {
++fNumVertexSamplers;
}
@@ -298,12 +318,30 @@ void GrGLSLProgramBuilder::emitSampler(GrSLType samplerType,
}
GrSLPrecision precision = this->glslCaps()->samplerPrecision(config, visibility);
GrSwizzle swizzle = this->glslCaps()->configTextureSwizzle(config);
- SamplerHandle handle = this->uniformHandler()->addSampler(visibility,
- swizzle,
- samplerType,
- precision,
- name);
- outSamplers->emplace_back(handle);
+ outSamplerHandles->emplace_back(this->uniformHandler()->addSampler(visibility,
+ swizzle,
+ samplerType,
+ precision,
+ name));
+}
+
+void GrGLSLProgramBuilder::emitImageStorage(const GrProcessor::ImageStorageAccess& access,
+ const char* name,
+ SkTArray<ImageStorageHandle>* outImageStorageHandles) {
+ if (access.visibility() & kVertex_GrShaderFlag) {
+ ++fNumVertexImageStorages;
+ }
+ if (access.visibility() & kGeometry_GrShaderFlag) {
+ SkASSERT(this->primitiveProcessor().willUseGeoShader());
+ ++fNumGeometryImageStorages;
+ }
+ if (access.visibility() & kFragment_GrShaderFlag) {
+ ++fNumFragmentImageStorages;
+ }
+ GrSLType uniformType = access.texture()->texturePriv().imageStorageType();
+ ImageStorageHandle handle = this->uniformHandler()->addImageStorage(access.visibility(),
+ uniformType, access.format(), name);
+ outImageStorageHandles->emplace_back(handle);
}
void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
@@ -345,6 +383,30 @@ bool GrGLSLProgramBuilder::checkSamplerCounts() {
return true;
}
+bool GrGLSLProgramBuilder::checkImageStorageCounts() {
+ const GrGLSLCaps& glslCaps = *this->glslCaps();
+ if (fNumVertexImageStorages > glslCaps.maxVertexImageStorages()) {
+ GrCapsDebugf(this->caps(), "Program would use too many vertex images\n");
+ return false;
+ }
+ if (fNumGeometryImageStorages > glslCaps.maxGeometryImageStorages()) {
+ GrCapsDebugf(this->caps(), "Program would use too many geometry images\n");
+ return false;
+ }
+ if (fNumFragmentImageStorages > glslCaps.maxFragmentImageStorages()) {
+ GrCapsDebugf(this->caps(), "Program would use too many fragment images\n");
+ return false;
+ }
+ // If the same image is used in two different shaders, it counts as two combined images.
+ int numCombinedImages = fNumVertexImageStorages + fNumGeometryImageStorages +
+ fNumFragmentImageStorages;
+ if (numCombinedImages > glslCaps.maxCombinedImageStorages()) {
+ GrCapsDebugf(this->caps(), "Program would use too many combined images\n");
+ return false;
+ }
+ return true;
+}
+
#ifdef SK_DEBUG
void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
SkASSERT(fFS.usedProcessorFeatures() == gp.requiredFeatures());
@@ -393,7 +455,6 @@ void GrGLSLProgramBuilder::appendUniformDecls(GrShaderFlags visibility, SkString
this->uniformHandler()->appendUniformDecls(visibility, out);
}
-
void GrGLSLProgramBuilder::addRTAdjustmentUniform(GrSLPrecision precision,
const char* name,
const char** outName) {
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h
index 6c1eb3bf4b..5543537d19 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.h
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.h
@@ -28,7 +28,9 @@ typedef SkSTArray<8, GrGLSLFragmentProcessor*, true> GrGLSLFragProcs;
class GrGLSLProgramBuilder {
public:
- typedef GrGLSLUniformHandler::UniformHandle UniformHandle;
+ using UniformHandle = GrGLSLUniformHandler::UniformHandle;
+ using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
+ using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle;
virtual ~GrGLSLProgramBuilder() {}
@@ -42,8 +44,6 @@ public:
void appendUniformDecls(GrShaderFlags visibility, SkString*) const;
- typedef GrGLSLUniformHandler::SamplerHandle SamplerHandle;
-
const GrShaderVar& samplerVariable(SamplerHandle handle) const {
return this->uniformHandler()->samplerVariable(handle);
}
@@ -52,6 +52,10 @@ public:
return this->uniformHandler()->samplerSwizzle(handle);
}
+ const GrShaderVar& imageStorageVariable(ImageStorageHandle handle) const {
+ return this->uniformHandler()->imageStorageVariable(handle);
+ }
+
// Handles for program uniforms (other than per-effect uniforms)
struct BuiltinUniformHandles {
UniformHandle fRTAdjustmentUni;
@@ -156,17 +160,18 @@ private:
const GrGLSLExpr4& coverageIn,
bool ignoresCoverage,
GrPixelLocalStorageState plsState);
-
- void emitSamplers(const GrProcessor& processor,
- SkTArray<SamplerHandle>* outTexSamplers,
- SkTArray<SamplerHandle>* outBufferSamplers);
- void emitSampler(GrSLType samplerType,
- GrPixelConfig,
- const char* name,
- GrShaderFlags visibility,
- SkTArray<SamplerHandle>* outSamplers);
+ void emitSamplersAndImageStorages(const GrProcessor& processor,
+ SkTArray<SamplerHandle>* outTexSamplerHandles,
+ SkTArray<SamplerHandle>* outBufferSamplerHandles,
+ SkTArray<ImageStorageHandle>* outImageStorageHandles);
+ void emitSampler(GrSLType samplerType, GrPixelConfig, const char* name,
+ GrShaderFlags visibility, SkTArray<SamplerHandle >* outSamplerHandles);
+ void emitImageStorage(const GrProcessor::ImageStorageAccess&,
+ const char* name,
+ SkTArray<ImageStorageHandle>* outImageStorageHandles);
void emitFSOutputSwizzle(bool hasSecondaryOutput);
bool checkSamplerCounts();
+ bool checkImageStorageCounts();
#ifdef SK_DEBUG
void verify(const GrPrimitiveProcessor&);
@@ -177,6 +182,9 @@ private:
int fNumVertexSamplers;
int fNumGeometrySamplers;
int fNumFragmentSamplers;
+ int fNumVertexImageStorages;
+ int fNumGeometryImageStorages;
+ int fNumFragmentImageStorages;
SkSTArray<4, GrShaderVar> fTransformedCoordVars;
};
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.cpp b/src/gpu/glsl/GrGLSLShaderBuilder.cpp
index 28578ddf63..1647eefaec 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.cpp
@@ -169,6 +169,16 @@ void GrGLSLShaderBuilder::appendTexelFetch(SamplerHandle samplerHandle, const ch
this->appendTexelFetch(&this->code(), samplerHandle, coordExpr);
}
+void GrGLSLShaderBuilder::appendImageStorageLoad(SkString* out, ImageStorageHandle handle,
+ const char* coordExpr) {
+ const GrShaderVar& imageStorage = fProgramBuilder->imageStorageVariable(handle);
+ out->appendf("imageLoad(%s, %s)", imageStorage.c_str(), coordExpr);
+}
+
+void GrGLSLShaderBuilder::appendImageStorageLoad(ImageStorageHandle handle, const char* coordExpr) {
+ this->appendImageStorageLoad(&this->code(), handle, coordExpr);
+}
+
bool GrGLSLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionName) {
if (featureBit & fFeaturesAddedMask) {
return false;
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.h b/src/gpu/glsl/GrGLSLShaderBuilder.h
index b568369cca..983d50b926 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.h
@@ -25,7 +25,8 @@ public:
GrGLSLShaderBuilder(GrGLSLProgramBuilder* program);
virtual ~GrGLSLShaderBuilder() {}
- typedef GrGLSLUniformHandler::SamplerHandle SamplerHandle;
+ using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
+ using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle;
/** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
@@ -72,6 +73,11 @@ public:
/** Version of above that appends the result to the shader code instead.*/
void appendTexelFetch(SamplerHandle, const char* coordExpr);
+ /** Creates a string of shader code that performs an image load. */
+ void appendImageStorageLoad(SkString* out, ImageStorageHandle, const char* coordExpr);
+ /** Version of above that appends the result to the shader code instead. */
+ void appendImageStorageLoad(ImageStorageHandle, const char* coordExpr);
+
/**
* Adds a constant declaration to the top of the shader.
*/
diff --git a/src/gpu/glsl/GrGLSLUniformHandler.h b/src/gpu/glsl/GrGLSLUniformHandler.h
index d49fbd4820..11ba2f7279 100644
--- a/src/gpu/glsl/GrGLSLUniformHandler.h
+++ b/src/gpu/glsl/GrGLSLUniformHandler.h
@@ -18,8 +18,9 @@ class GrGLSLUniformHandler {
public:
virtual ~GrGLSLUniformHandler() {}
- typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
- typedef GrGLSLProgramDataManager::UniformHandle SamplerHandle;
+ using UniformHandle = GrGLSLProgramDataManager::UniformHandle;
+ GR_DEFINE_RESOURCE_HANDLE_CLASS(SamplerHandle);
+ GR_DEFINE_RESOURCE_HANDLE_CLASS(ImageStorageHandle);
/** Add a uniform variable to the current program, that has visibility in one or more shaders.
visibility is a bitfield of GrShaderFlag values indicating from which shaders the uniform
@@ -67,6 +68,10 @@ private:
virtual SamplerHandle addSampler(uint32_t visibility, GrSwizzle, GrSLType, GrSLPrecision,
const char* name) = 0;
+ virtual const GrShaderVar& imageStorageVariable(ImageStorageHandle) const = 0;
+ virtual ImageStorageHandle addImageStorage(uint32_t visibility, GrSLType type,
+ GrImageStorageFormat, const char* name) = 0;
+
virtual UniformHandle internalAddUniformArray(uint32_t visibility,
GrSLType type,
GrSLPrecision precision,
diff --git a/src/gpu/glsl/GrGLSLXferProcessor.h b/src/gpu/glsl/GrGLSLXferProcessor.h
index bf6ee64299..69e00723a8 100644
--- a/src/gpu/glsl/GrGLSLXferProcessor.h
+++ b/src/gpu/glsl/GrGLSLXferProcessor.h
@@ -9,10 +9,10 @@
#define GrGLSLXferProcessor_DEFINED
#include "glsl/GrGLSLProgramDataManager.h"
+#include "glsl/GrGLSLUniformHandler.h"
class GrXferProcessor;
class GrGLSLCaps;
-class GrGLSLUniformHandler;
class GrGLSLXPBuilder;
class GrGLSLXPFragmentBuilder;
@@ -21,7 +21,8 @@ public:
GrGLSLXferProcessor() {}
virtual ~GrGLSLXferProcessor() {}
- typedef GrGLSLProgramDataManager::UniformHandle SamplerHandle;
+ using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
+ using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle;
struct EmitArgs {
EmitArgs(GrGLSLXPFragmentBuilder* fragBuilder,
@@ -34,6 +35,7 @@ public:
const char* outputSecondary,
const SamplerHandle* texSamplers,
const SamplerHandle* bufferSamplers,
+ const ImageStorageHandle* imageStorages,
const bool usePLSDstRead)
: fXPFragBuilder(fragBuilder)
, fUniformHandler(uniformHandler)
@@ -45,6 +47,7 @@ public:
, fOutputSecondary(outputSecondary)
, fTexSamplers(texSamplers)
, fBufferSamplers(bufferSamplers)
+ , fImageStorages(imageStorages)
, fUsePLSDstRead(usePLSDstRead) {}
GrGLSLXPFragmentBuilder* fXPFragBuilder;
@@ -57,6 +60,7 @@ public:
const char* fOutputSecondary;
const SamplerHandle* fTexSamplers;
const SamplerHandle* fBufferSamplers;
+ const ImageStorageHandle* fImageStorages;
bool fUsePLSDstRead;
};
/**
diff --git a/src/gpu/vk/GrVkPipelineState.cpp b/src/gpu/vk/GrVkPipelineState.cpp
index 2d53cd8c8d..75b8baaa4f 100644
--- a/src/gpu/vk/GrVkPipelineState.cpp
+++ b/src/gpu/vk/GrVkPipelineState.cpp
@@ -174,6 +174,8 @@ void GrVkPipelineState::abandonGPUResources() {
static void append_texture_bindings(const GrProcessor& processor,
SkTArray<const GrProcessor::TextureSampler*>* textureBindings) {
+ // We don't support image storages in VK.
+ SkASSERT(!processor.numImageStorages());
if (int numTextureSamplers = processor.numTextureSamplers()) {
const GrProcessor::TextureSampler** bindings =
textureBindings->push_back_n(numTextureSamplers);
diff --git a/src/gpu/vk/GrVkUniformHandler.cpp b/src/gpu/vk/GrVkUniformHandler.cpp
index 3998c0fd23..8c4f8514b8 100644
--- a/src/gpu/vk/GrVkUniformHandler.cpp
+++ b/src/gpu/vk/GrVkUniformHandler.cpp
@@ -45,6 +45,8 @@ uint32_t grsltype_to_alignment_mask(GrSLType type) {
case kBufferSampler_GrSLType:
case kTexture2D_GrSLType:
case kSampler_GrSLType:
+ case kImageStorage2D_GrSLType:
+ case kIImageStorage2D_GrSLType:
break;
}
SkFAIL("Unexpected type");
@@ -86,6 +88,8 @@ static inline uint32_t grsltype_to_vk_size(GrSLType type) {
case kBufferSampler_GrSLType:
case kTexture2D_GrSLType:
case kSampler_GrSLType:
+ case kImageStorage2D_GrSLType:
+ case kIImageStorage2D_GrSLType:
break;
}
SkFAIL("Unexpected type");
@@ -158,7 +162,7 @@ GrGLSLUniformHandler::UniformHandle GrVkUniformHandler::internalAddUniformArray(
uni.fVariable.setTypeModifier(GrShaderVar::kNone_TypeModifier);
uint32_t* currentOffset = kVertex_GrShaderFlag == visibility ? &fCurrentVertexUBOOffset
- : &fCurrentFragmentUBOOffset;
+ : &fCurrentFragmentUBOOffset;
get_ubo_aligned_offset(&uni.fUBOffset, currentOffset, type, arrayCount);
if (outName) {
diff --git a/src/gpu/vk/GrVkUniformHandler.h b/src/gpu/vk/GrVkUniformHandler.h
index e5d4a4cf10..d8e8c686bf 100644
--- a/src/gpu/vk/GrVkUniformHandler.h
+++ b/src/gpu/vk/GrVkUniformHandler.h
@@ -76,6 +76,18 @@ private:
return fSamplers[handle.toIndex()].fVisibility;
}
+ ImageStorageHandle addImageStorage(uint32_t visibility, GrSLType, GrImageStorageFormat,
+ const char* name) override {
+ SkFAIL("Image storages not implemented for Vulkan.");
+ return 0;
+ }
+
+ const GrShaderVar& imageStorageVariable(ImageStorageHandle handle) const override {
+ SkFAIL("Image storages not implemented for Vulkan.");
+ GrShaderVar* gVar = nullptr;
+ return *gVar;
+ }
+
void appendUniformDecls(GrShaderFlags, SkString*) const override;
bool hasVertexUniforms() const { return fCurrentVertexUBOOffset > 0; }
diff --git a/src/gpu/vk/GrVkVaryingHandler.cpp b/src/gpu/vk/GrVkVaryingHandler.cpp
index 9bab292af8..d7d08c9622 100644
--- a/src/gpu/vk/GrVkVaryingHandler.cpp
+++ b/src/gpu/vk/GrVkVaryingHandler.cpp
@@ -47,6 +47,10 @@ static inline int grsltype_to_location_size(GrSLType type) {
return 0;
case kSampler_GrSLType:
return 0;
+ case kImageStorage2D_GrSLType:
+ return 0;
+ case kIImageStorage2D_GrSLType:
+ return 0;
}
SkFAIL("Unexpected type");
return -1;
diff --git a/tests/ImageStorageTest.cpp b/tests/ImageStorageTest.cpp
new file mode 100644
index 0000000000..99949d07ce
--- /dev/null
+++ b/tests/ImageStorageTest.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+
+#include "GrFragmentProcessor.h"
+#include "GrInvariantOutput.h"
+#include "GrRenderTargetContext.h"
+#include "GrTexture.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageStorageLoad, reporter, ctxInfo) {
+ class TestFP : public GrFragmentProcessor {
+ public:
+ static sk_sp<GrFragmentProcessor> Make(sk_sp<GrTexture> texture) {
+ return sk_sp<GrFragmentProcessor>(new TestFP(std::move(texture)));
+ }
+
+ const char* name() const override { return "Image Load Test FP"; }
+
+ private:
+ TestFP(sk_sp<GrTexture> texture) : fImageStorageAccess(std::move(texture), kRead_GrIOType) {
+ this->initClassID<TestFP>();
+ this->setWillReadFragmentPosition();
+ this->addImageStorageAccess(&fImageStorageAccess);
+ }
+
+ void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override {}
+
+ void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
+ inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput);
+ }
+
+ bool onIsEqual(const GrFragmentProcessor& that) const override { return true; }
+
+ GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
+ class GLSLProcessor : public GrGLSLFragmentProcessor {
+ public:
+ GLSLProcessor() = default;
+ void emitCode(EmitArgs& args) override {
+ const TestFP& tfp = args.fFp.cast<TestFP>();
+ GrGLSLFPFragmentBuilder* fb = args.fFragBuilder;
+ SkString imageLoadStr;
+ fb->codeAppendf("vec2 coord = %s.xy;", args.fFragBuilder->fragmentPosition());
+ fb->appendImageStorageLoad(&imageLoadStr, args.fImageStorages[0],
+ "ivec2(coord)");
+ if (GrPixelConfigIsSint(tfp.fImageStorageAccess.texture()->config())) {
+ // Map the signed bytes so that when then get read back as unorm values they
+ // will have their original bit pattern.
+ fb->codeAppendf("ivec4 ivals = %s;", imageLoadStr.c_str());
+ // NV gives a linker error for this:
+ // fb->codeAppend("ivals +=
+ // "mix(ivec4(0), ivec4(256), lessThan(ivals, ivec4(0)));");
+ fb->codeAppend("if (ivals.r < 0) { ivals.r += 256; }");
+ fb->codeAppend("if (ivals.g < 0) { ivals.g += 256; }");
+ fb->codeAppend("if (ivals.b < 0) { ivals.b += 256; }");
+ fb->codeAppend("if (ivals.a < 0) { ivals.a += 256; }");
+ fb->codeAppendf("%s = (vec4(ivals) + vec4(0.5))/255;", args.fOutputColor);
+ } else {
+ fb->codeAppendf("%s = %s;", args.fOutputColor, imageLoadStr.c_str());
+ }
+ }
+ };
+ return new GLSLProcessor;
+ }
+
+ ImageStorageAccess fImageStorageAccess;
+ };
+
+ static constexpr int kS = 256;
+ GrContext* context = ctxInfo.grContext();
+ if (!context->caps()->shaderCaps()->imageLoadStoreSupport()) {
+ return;
+ }
+
+ std::unique_ptr<uint32_t[]> data(new uint32_t[kS * kS]);
+ for (int j = 0; j < kS; ++j) {
+ for (int i = 0; i < kS; ++i) {
+ data[i + kS * j] = GrColorPackRGBA(i, j, 0, 0);
+ }
+ }
+
+ std::unique_ptr<uint32_t[]> idata(new uint32_t[kS * kS]);
+ for (int j = 0; j < kS; ++j) {
+ for (int i = 0; i < kS; ++i) {
+ int8_t r = i - 128;
+ int8_t g = j - 128;
+ int8_t b = -128;
+ int8_t a = -128;
+ idata[i + kS * j] = ((uint8_t)a << 24) | ((uint8_t)b << 16) |
+ ((uint8_t)g << 8) | (uint8_t)r;
+ }
+ }
+
+ // Currently image accesses always have "top left" semantics.
+ GrSurfaceDesc desc;
+ desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+ desc.fWidth = kS;
+ desc.fHeight = kS;
+ struct {
+ GrPixelConfig fConfig;
+ std::unique_ptr<uint32_t[]> fData;
+ } tests[] = {
+ {
+ kRGBA_8888_GrPixelConfig,
+ std::move(data)
+ },
+ {
+ kRGBA_8888_sint_GrPixelConfig,
+ std::move(idata)
+ },
+ };
+ for (const auto& test : tests) {
+ desc.fConfig = test.fConfig;
+ sk_sp<GrTexture> imageStorageTexture(context->textureProvider()->createTexture(desc,
+ SkBudgeted::kYes, test.fData.get(), 0));
+
+ sk_sp<GrRenderTargetContext> rtContext =
+ context->makeRenderTargetContext(SkBackingFit::kExact, kS, kS, kRGBA_8888_GrPixelConfig,
+ nullptr);
+ GrPaint paint;
+ paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
+ paint.addColorFragmentProcessor(TestFP::Make(imageStorageTexture));
+ rtContext->drawPaint(GrNoClip(), paint, SkMatrix::I());
+ std::unique_ptr<uint32_t[]> readData(new uint32_t[kS * kS]);
+ SkImageInfo info = SkImageInfo::Make(kS, kS, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+ rtContext->readPixels(info, readData.get(), 0, 0, 0);
+ int failed = false;
+ for (int j = 0; j < kS && !failed; ++j) {
+ for (int i = 0; i < kS && !failed; ++i) {
+ uint32_t d = test.fData[j * kS + i];
+ uint32_t rd = readData[j * kS + i];
+ if (d != rd) {
+ failed = true;
+ ERRORF(reporter, "Expected 0x%08x, got 0x%08x at %d, %d.", d, rd, i, j);
+ }
+ }
+ }
+ }
+}
+
+#endif