aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2016-11-22 15:56:30 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2016-11-22 21:35:11 +0000
commitbe34882042048db096baca32ddf4a8b472529804 (patch)
tree2676dc4a9e6506f19728eddfe011ba4465f1c3ab
parent030cbd5f3cc60255b887fb88920fb655c8a2a9be (diff)
Initial OpenGL Image support.
This change along with recently landed changes is enough to make the new unit test work and not much else. imageLoad is support but not stores or any other image functions (atomics). Barriers in the shading language or the GL API are not yet hooked up. GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4182 Change-Id: I5958b7c89e40ae5ee05f7bbaca3b3738162fe5ce Reviewed-on: https://skia-review.googlesource.com/4182 Reviewed-by: Greg Daniel <egdaniel@google.com> Reviewed-by: Chris Dalton <csmartdalton@google.com> Commit-Queue: Brian Salomon <bsalomon@google.com>
-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