diff options
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 |