From f9f451213a3951d8a61568998de2ddbd643f6693 Mon Sep 17 00:00:00 2001 From: Brian Salomon Date: Tue, 29 Nov 2016 11:59:17 -0500 Subject: [PATCH] Reland image storage with fixes. Revert "Revert "Initial OpenGL Image support."" This reverts commit 59dc41175d99d0a31c046aec0c26c4d82a3a3574. BUG=skia: Change-Id: Ibe3c87ce7f746f065fdbcc5a518388cc291112f5 Reviewed-on: https://skia-review.googlesource.com/5131 Reviewed-by: Ethan Nicholas Commit-Queue: Brian Salomon --- gn/tests.gni | 1 + include/gpu/GrCaps.h | 1 + include/gpu/GrGpuResourceRef.h | 4 + include/gpu/GrProcessor.h | 73 +++- include/gpu/GrShaderVar.h | 25 +- include/gpu/GrTypesPriv.h | 74 ++++ src/gpu/GrFragmentProcessor.cpp | 2 +- src/gpu/GrProcessor.cpp | 52 ++- src/gpu/GrProgramDesc.cpp | 104 +++-- src/gpu/GrShaderVar.cpp | 74 +++- src/gpu/GrTexturePriv.h | 8 + src/gpu/gl/GrGLCaps.cpp | 49 ++- src/gpu/gl/GrGLCaps.h | 11 +- src/gpu/gl/GrGLGpu.cpp | 26 ++ src/gpu/gl/GrGLGpu.h | 8 + src/gpu/gl/GrGLProgram.cpp | 7 + src/gpu/gl/GrGLProgram.h | 7 +- src/gpu/gl/GrGLProgramDataManager.cpp | 10 + src/gpu/gl/GrGLProgramDataManager.h | 1 + src/gpu/gl/GrGLUniformHandler.cpp | 61 ++- src/gpu/gl/GrGLUniformHandler.h | 12 +- src/gpu/gl/builders/GrGLProgramBuilder.cpp | 1 + src/gpu/glsl/GrGLSL.h | 4 + src/gpu/glsl/GrGLSLCaps.cpp | 16 +- src/gpu/glsl/GrGLSLCaps.h | 16 +- src/gpu/glsl/GrGLSLFragmentProcessor.cpp | 2 + src/gpu/glsl/GrGLSLFragmentProcessor.h | 18 +- src/gpu/glsl/GrGLSLPrimitiveProcessor.h | 10 +- src/gpu/glsl/GrGLSLProgramBuilder.cpp | 112 +++-- src/gpu/glsl/GrGLSLProgramBuilder.h | 32 +- src/gpu/glsl/GrGLSLShaderBuilder.cpp | 10 + src/gpu/glsl/GrGLSLShaderBuilder.h | 8 +- src/gpu/glsl/GrGLSLUniformHandler.h | 10 +- src/gpu/glsl/GrGLSLXferProcessor.h | 8 +- src/gpu/vk/GrVkCaps.h | 2 + src/gpu/vk/GrVkPipelineState.cpp | 2 + src/gpu/vk/GrVkUniformHandler.cpp | 6 +- src/gpu/vk/GrVkUniformHandler.h | 13 + src/gpu/vk/GrVkVaryingHandler.cpp | 4 + src/sksl/SkSLGLSLCodeGenerator.cpp | 19 +- src/sksl/SkSLParser.cpp | 23 +- src/sksl/SkSLSPIRVCodeGenerator.cpp | 14 + src/sksl/SkSLToken.h | 5 + src/sksl/ir/SkSLModifiers.h | 40 +- src/sksl/lex.sksl.c | 647 +++++++++++++++++------------ src/sksl/sksl.flex | 10 + tests/ImageStorageTest.cpp | 163 ++++++++ tools/gpu/GrTest.cpp | 2 + 48 files changed, 1363 insertions(+), 444 deletions(-) create mode 100644 tests/ImageStorageTest.cpp diff --git a/gn/tests.gni b/gn/tests.gni index 98980ec..8473e0e 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/GrCaps.h b/include/gpu/GrCaps.h index c44f6c1..60d0c70 100644 --- a/include/gpu/GrCaps.h +++ b/include/gpu/GrCaps.h @@ -269,6 +269,7 @@ public: virtual bool isConfigTexturable(GrPixelConfig config) const = 0; virtual bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const = 0; + virtual bool canConfigBeImageStorage(GrPixelConfig config) const = 0; bool suppressPrints() const { return fSuppressPrints; } diff --git a/include/gpu/GrGpuResourceRef.h b/include/gpu/GrGpuResourceRef.h index a91dcfe..a51d814 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 e4f59ea..95a669e 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,42 @@ 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 texture, GrIOType ioType, GrSLMemoryModel, GrSLRestrict, + 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; } + GrSLMemoryModel memoryModel() const { return fMemoryModel; } + GrSLRestrict restrict() const { return fRestrict; } + + /** + * For internal use by GrProcessor. + */ + const GrGpuResourceRef* programTexture() const { return &fTexture; } + +private: + GrTGpuResourceRef fTexture; + GrShaderFlags fVisibility; + GrImageStorageFormat fFormat; + GrSLMemoryModel fMemoryModel; + GrSLRestrict fRestrict; + typedef SkNoncopyable INHERITED; +}; + #endif diff --git a/include/gpu/GrShaderVar.h b/include/gpu/GrShaderVar.h index aaae107..1149f84 100644 --- a/include/gpu/GrShaderVar.h +++ b/include/gpu/GrShaderVar.h @@ -284,6 +284,14 @@ public: } } + void setImageStorageFormat(GrImageStorageFormat format); + + void setMemoryModel(GrSLMemoryModel); + + void setRestrict(GrSLRestrict); + + void setIOType(GrIOType); + void addModifier(const char* modifier) { if (modifier) { fExtraModifiers.appendf("%s ", modifier); @@ -310,23 +318,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 4ecab9c..51dccc5 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,40 @@ static inline GrSLType GrVertexAttribTypeToSLType(GrVertexAttribType type) { ////////////////////////////////////////////////////////////////////////////// +enum class GrImageStorageFormat { + kRGBA8, + kRGBA8i, + kRGBA16f, + kRGBA32f, +}; + +/** + * Describes types of caching and compiler optimizations allowed for certain variable types + * (currently only image storages). + **/ +enum class GrSLMemoryModel { + /** No special restrctions on memory accesses or compiler optimizations */ + kNone, + /** Cache coherent across shader invocations */ + kCoherent, + /** + * Disallows compiler from eliding loads or stores that appear redundant in a single + * invocation. Implies coherent. + */ + kVolatile +}; + +/** + * If kYes then the memory backing the varialble is only accessed via the variable. This is + * currently only used with image storages. + */ +enum class GrSLRestrict { + kYes, + kNo, +}; + +////////////////////////////////////////////////////////////////////////////// + /** * 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 820b428..de4ab9e 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 1e100e4..f4f7ccb 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,37 @@ void GrProcessor::TextureSampler::reset(GrTexture* texture, /////////////////////////////////////////////////////////////////////////////////////////////////// +GrProcessor::ImageStorageAccess::ImageStorageAccess(sk_sp texture, GrIOType ioType, + GrSLMemoryModel memoryModel, + GrSLRestrict restrict, + GrShaderFlags visibility) { + SkASSERT(texture); + fTexture.set(texture.release(), ioType); + fMemoryModel = memoryModel; + fRestrict = restrict; + 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; +int32_t GrXPFactory::gCurrXPFClassID = GrXPFactory::kIllegalXPFClassID; diff --git a/src/gpu/GrProgramDesc.cpp b/src/gpu/GrProgramDesc.cpp index cdbbc23..9f3278c 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(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 ef305cb..75142ca 100644 --- a/src/gpu/GrShaderVar.cpp +++ b/src/gpu/GrShaderVar.cpp @@ -9,14 +9,86 @@ #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::setMemoryModel(GrSLMemoryModel model) { + switch (model) { + case GrSLMemoryModel::kNone: + return; + case GrSLMemoryModel::kCoherent: + this->addModifier("coherent"); + return; + case GrSLMemoryModel::kVolatile: + this->addModifier("volatile"); + return; + } + SkFAIL("Unknown memory model."); +} + +void GrShaderVar::setRestrict(GrSLRestrict restrict) { + switch (restrict) { + case GrSLRestrict::kNo: + return; + case GrSLRestrict::kYes: + this->addModifier("restrict"); + return; + } + SkFAIL("Unknown restrict."); +} + +void GrShaderVar::setIOType(GrIOType ioType) { + switch (ioType) { + case kRW_GrIOType: + return; + case kRead_GrIOType: + this->addModifier("readonly"); + return; + case kWrite_GrIOType: + this->addModifier("writeonly"); + return; + } + SkFAIL("Unknown io type."); +} + 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 d68eb79..0420611 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 3e9f82a..c4f7560 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -324,16 +324,29 @@ 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); + if (glslCaps->fGeometryShaderSupport) { + 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); + // HACK: Currently we only use images in a unit test in the fragment shader. The individual + // stage image limits aren't exposed through GrShaderCaps. Soon GrShaderCaps and GrGLSLCaps + // will merge and the test can look for fragment support. + if (!glslCaps->fMaxFragmentImageStorages) { + glslCaps->fImageLoadStoreSupport = false; + } } /************************************************************************** @@ -2023,6 +2036,24 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa } } + // We currently only support images on rgba textures formats. We could add additional formats + // if desired. The shader builder would have to be updated to add swizzles where appropriate + // (e.g. where we use GL_RED textures to implement alpha configs). + if (this->shaderCaps()->imageLoadStoreSupport()) { + fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFlags |= + ConfigInfo::kCanUseAsImageStorage_Flag; + // In OpenGL ES a texture may only be used with BindImageTexture if it has been made + // immutable via TexStorage. We create non-integer textures as mutable textures using + // TexImage because we may lazily add MIP levels. Thus, on ES we currently disable image + // storage support for non-integer textures. + if (kGL_GrGLStandard == ctxInfo.standard()) { + fConfigTable[kRGBA_8888_GrPixelConfig].fFlags |= ConfigInfo::kCanUseAsImageStorage_Flag; + fConfigTable[kRGBA_float_GrPixelConfig].fFlags |= + ConfigInfo::kCanUseAsImageStorage_Flag; + fConfigTable[kRGBA_half_GrPixelConfig].fFlags |= ConfigInfo::kCanUseAsImageStorage_Flag; + } + } + #ifdef SK_DEBUG // Make sure we initialized everything. ConfigInfo defaultEntry; diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index 496635d..63843a5 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -126,7 +126,9 @@ public: return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag); } } - + bool canConfigBeImageStorage(GrPixelConfig config) const override { + return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kCanUseAsImageStorage_Flag); + } bool canConfigBeFBOColorAttachment(GrPixelConfig config) const { return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kFBOColorAttachment_Flag); } @@ -159,6 +161,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 +458,6 @@ private: GrGLenum fExternalFormat[kExternalFormatUsageCnt]; GrGLenum fExternalType; - // Either the base or sized internal format depending on the GL and config. GrGLenum fInternalFormatTexImage; GrGLenum fInternalFormatRenderbuffer; @@ -489,6 +495,7 @@ private: kFBOColorAttachment_Flag = 0x10, kCanUseTexStorage_Flag = 0x20, kCanUseWithTexelBuffer_Flag = 0x40, + kCanUseAsImageStorage_Flag = 0x80, }; uint32_t fFlags; diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index 9485778..af44af4 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 dff342d..c6e7935 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 fHWBoundTextureUniqueIDs; + struct Image { + GrGpuResource::UniqueID fTextureUniqueID; + GrIOType fIOType; + }; + SkTArray 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 820b55c..f09b668 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -31,6 +31,7 @@ GrGLProgram::GrGLProgram(GrGLGpu* gpu, GrGLuint programID, const UniformInfoArray& uniforms, const UniformInfoArray& samplers, + const UniformInfoArray& imageStorages, const VaryingInfoArray& pathProcVaryings, GrGLSLPrimitiveProcessor* geometryProcessor, GrGLSLXferProcessor* xferProcessor, @@ -46,6 +47,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() { @@ -161,6 +163,11 @@ void GrGLProgram::bindTextures(const GrProcessor& processor, fGpu->bindTexelBuffer((*nextSamplerIdx)++, access.texelConfig(), static_cast(access.buffer())); } + for (int i = 0; i < processor.numImageStorages(); ++i) { + const GrProcessor::ImageStorageAccess& access = processor.imageStorageAccess(i); + fGpu->bindImageStorage((*nextSamplerIdx)++, access.ioType(), + static_cast(access.texture())); + } } void GrGLProgram::generateMipmaps(const GrProcessor& processor, diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index d129dda..9c42978 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -102,9 +102,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&, @@ -112,6 +112,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 3245bd7..863eab7 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 0ef902c..62af4b8 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 2def001..81755d5 100644 --- a/src/gpu/gl/GrGLUniformHandler.cpp +++ b/src/gpu/gl/GrGLUniformHandler.cpp @@ -80,11 +80,38 @@ GrGLSLUniformHandler::SamplerHandle GrGLUniformHandler::addSampler(uint32_t visi return GrGLSLUniformHandler::SamplerHandle(fSamplers.count() - 1); } +GrGLSLUniformHandler::ImageStorageHandle GrGLUniformHandler::addImageStorage( + uint32_t visibility, GrSLType type, GrImageStorageFormat format, GrSLMemoryModel model, + GrSLRestrict restrict, GrIOType ioType, 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.fVariable.setMemoryModel(model); + imageStorage.fVariable.setRestrict(restrict); + imageStorage.fVariable.setIOType(ioType); + imageStorage.fVariable.setPrecision(kHigh_GrSLPrecision); + 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 +120,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 +160,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 d3aa2f8..da7b13c 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,18 @@ private: return fSamplers[handle.toIndex()].fVariable; } + ImageStorageHandle addImageStorage(uint32_t visibility, GrSLType, GrImageStorageFormat, + GrSLMemoryModel, GrSLRestrict, GrIOType, + 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 +75,7 @@ private: UniformInfoArray fUniforms; UniformInfoArray fSamplers; SkTArray fSamplerSwizzles; + UniformInfoArray fImageStorages; friend class GrGLProgramBuilder; diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp index a1ad572..a774570 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 d27b25f..417f6d7 100644 --- a/src/gpu/glsl/GrGLSL.h +++ b/src/gpu/glsl/GrGLSL.h @@ -121,6 +121,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 5bb22b3..57e5a0c 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 4c53ad0..11ce754 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 5ae7fee..8c32482 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 aba68b7..c815423 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; + using ImageStorages = BuilderInputProvider; /** 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 1991639..b398cfd 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 e8097c7..0c1661d 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* outTexSamplers, - SkTArray* outBufferSamplers) { +void GrGLSLProgramBuilder::emitSamplersAndImageStorages( + const GrProcessor& processor, + SkTArray* outTexSamplerHandles, + SkTArray* outBufferSamplerHandles, + SkTArray* 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* outSamplers) { + SkTArray* outSamplerHandles) { if (visibility & kVertex_GrShaderFlag) { ++fNumVertexSamplers; } @@ -298,12 +318,31 @@ 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* 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(), access.memoryModel(), access.restrict(), access.ioType(), + name); + outImageStorageHandles->emplace_back(handle); } void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) { @@ -345,6 +384,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 +456,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 6c1eb3b..5543537 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* outTexSamplers, - SkTArray* outBufferSamplers); - void emitSampler(GrSLType samplerType, - GrPixelConfig, - const char* name, - GrShaderFlags visibility, - SkTArray* outSamplers); + void emitSamplersAndImageStorages(const GrProcessor& processor, + SkTArray* outTexSamplerHandles, + SkTArray* outBufferSamplerHandles, + SkTArray* outImageStorageHandles); + void emitSampler(GrSLType samplerType, GrPixelConfig, const char* name, + GrShaderFlags visibility, SkTArray* outSamplerHandles); + void emitImageStorage(const GrProcessor::ImageStorageAccess&, + const char* name, + SkTArray* 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 b6e7ce9..79e977c 100644 --- a/src/gpu/glsl/GrGLSLShaderBuilder.cpp +++ b/src/gpu/glsl/GrGLSLShaderBuilder.cpp @@ -162,6 +162,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 b568369..983d50b 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 d49fbd4..3d21c1c 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,11 @@ 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, GrSLMemoryModel, GrSLRestrict, + GrIOType, 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 bf6ee64..69e0072 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/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h index abc0dc9..7b40e0d 100644 --- a/src/gpu/vk/GrVkCaps.h +++ b/src/gpu/vk/GrVkCaps.h @@ -37,6 +37,8 @@ public: return SkToBool(ConfigInfo::kRenderable_Flag & fConfigTable[config].fOptimalFlags); } + bool canConfigBeImageStorage(GrPixelConfig) const override { return false; } + bool isConfigTexturableLinearly(GrPixelConfig config) const { return SkToBool(ConfigInfo::kTextureable_Flag & fConfigTable[config].fLinearFlags); } diff --git a/src/gpu/vk/GrVkPipelineState.cpp b/src/gpu/vk/GrVkPipelineState.cpp index 2d53cd8..75b8baa 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* 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 3998c0f..8c4f851 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 e5d4a4c..808eed7 100644 --- a/src/gpu/vk/GrVkUniformHandler.h +++ b/src/gpu/vk/GrVkUniformHandler.h @@ -76,6 +76,19 @@ private: return fSamplers[handle.toIndex()].fVisibility; } + ImageStorageHandle addImageStorage(uint32_t visibility, GrSLType, GrImageStorageFormat, + GrSLMemoryModel, GrSLRestrict, GrIOType, + 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."); + static const 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 9bab292..d7d08c9 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/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp index 7c26287..5b74724 100644 --- a/src/sksl/SkSLGLSLCodeGenerator.cpp +++ b/src/sksl/SkSLGLSLCodeGenerator.cpp @@ -455,11 +455,26 @@ void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) { void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers, bool globalContext) { + if (modifiers.fFlags & Modifiers::kFlat_Flag) { + this->write("flat "); + } if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) { this->write("noperspective "); } - if (modifiers.fFlags & Modifiers::kFlat_Flag) { - this->write("flat "); + if (modifiers.fFlags & Modifiers::kReadOnly_Flag) { + this->write("readonly "); + } + if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) { + this->write("writeonly "); + } + if (modifiers.fFlags & Modifiers::kCoherent_Flag) { + this->write("coherent "); + } + if (modifiers.fFlags & Modifiers::kVolatile_Flag) { + this->write("volatile "); + } + if (modifiers.fFlags & Modifiers::kRestrict_Flag) { + this->write("restrict "); } SkString layout = modifiers.fLayout.description(); if (layout.size()) { diff --git a/src/sksl/SkSLParser.cpp b/src/sksl/SkSLParser.cpp index 3920b00..cd0ae6a 100644 --- a/src/sksl/SkSLParser.cpp +++ b/src/sksl/SkSLParser.cpp @@ -601,7 +601,8 @@ Layout Parser::layout() { pushConstant); } -/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE)* */ +/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE | + READONLY | WRITEONLY | COHERENT | VOLATILE | RESTRICT)* */ Modifiers Parser::modifiers() { Layout layout = this->layout(); int flags = 0; @@ -649,6 +650,26 @@ Modifiers Parser::modifiers() { this->nextToken(); flags |= Modifiers::kNoPerspective_Flag; break; + case Token::READONLY: + this->nextToken(); + flags |= Modifiers::kReadOnly_Flag; + break; + case Token::WRITEONLY: + this->nextToken(); + flags |= Modifiers::kWriteOnly_Flag; + break; + case Token::COHERENT: + this->nextToken(); + flags |= Modifiers::kCoherent_Flag; + break; + case Token::VOLATILE: + this->nextToken(); + flags |= Modifiers::kVolatile_Flag; + break; + case Token::RESTRICT: + this->nextToken(); + flags |= Modifiers::kRestrict_Flag; + break; default: return Modifiers(layout, flags); } diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp index 62c0c50..b2857f4 100644 --- a/src/sksl/SkSLSPIRVCodeGenerator.cpp +++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp @@ -2460,6 +2460,13 @@ void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclaratio for (size_t i = 0; i < decl.fVars.size(); i++) { const VarDeclaration& varDecl = decl.fVars[i]; const Variable* var = varDecl.fVar; + // These haven't been implemented in our SPIR-V generator yet and we only currently use them + // in the OpenGL backend. + ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag | + Modifiers::kWriteOnly_Flag | + Modifiers::kCoherent_Flag | + Modifiers::kVolatile_Flag | + Modifiers::kRestrict_Flag))); if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) { continue; } @@ -2514,6 +2521,13 @@ void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclaratio void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, SkWStream& out) { for (const auto& varDecl : decl.fVars) { const Variable* var = varDecl.fVar; + // These haven't been implemented in our SPIR-V generator yet and we only currently use them + // in the OpenGL backend. + ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag | + Modifiers::kWriteOnly_Flag | + Modifiers::kCoherent_Flag | + Modifiers::kVolatile_Flag | + Modifiers::kRestrict_Flag))); SpvId id = this->nextId(); fVariableMap[var] = id; SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction); diff --git a/src/sksl/SkSLToken.h b/src/sksl/SkSLToken.h index 6fe130f..5c8c2bd 100644 --- a/src/sksl/SkSLToken.h +++ b/src/sksl/SkSLToken.h @@ -96,6 +96,11 @@ struct Token { UNIFORM, FLAT, NOPERSPECTIVE, + READONLY, + WRITEONLY, + COHERENT, + VOLATILE, + RESTRICT, STRUCT, LAYOUT, DIRECTIVE, diff --git a/src/sksl/ir/SkSLModifiers.h b/src/sksl/ir/SkSLModifiers.h index dbb9b6b..c7a5639 100644 --- a/src/sksl/ir/SkSLModifiers.h +++ b/src/sksl/ir/SkSLModifiers.h @@ -17,16 +17,21 @@ namespace SkSL { */ struct Modifiers { enum Flag { - kNo_Flag = 0, - kConst_Flag = 1, - kIn_Flag = 2, - kOut_Flag = 4, - kLowp_Flag = 8, - kMediump_Flag = 16, - kHighp_Flag = 32, - kUniform_Flag = 64, - kFlat_Flag = 128, - kNoPerspective_Flag = 256 + kNo_Flag = 0, + kConst_Flag = 1, + kIn_Flag = 2, + kOut_Flag = 4, + kLowp_Flag = 8, + kMediump_Flag = 16, + kHighp_Flag = 32, + kUniform_Flag = 64, + kFlat_Flag = 128, + kNoPerspective_Flag = 256, + kReadOnly_Flag = 512, + kWriteOnly_Flag = 1024, + kCoherent_Flag = 2048, + kVolatile_Flag = 4096, + kRestrict_Flag = 8192 }; Modifiers() @@ -60,6 +65,21 @@ struct Modifiers { if (fFlags & kNoPerspective_Flag) { result += "noperspective "; } + if (fFlags & kReadOnly_Flag) { + result += "readonly "; + } + if (fFlags & kWriteOnly_Flag) { + result += "writeonly "; + } + if (fFlags & kCoherent_Flag) { + result += "coherent "; + } + if (fFlags & kVolatile_Flag) { + result += "volatile "; + } + if (fFlags & kRestrict_Flag) { + result += "restrict "; + } if ((fFlags & kIn_Flag) && (fFlags & kOut_Flag)) { result += "inout "; diff --git a/src/sksl/lex.sksl.c b/src/sksl/lex.sksl.c index 710b67b..4cff376 100644 --- a/src/sksl/lex.sksl.c +++ b/src/sksl/lex.sksl.c @@ -4,7 +4,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - + #line 3 "lex.sksl.c" #define YY_INT_ALIGNED short int @@ -13,8 +13,8 @@ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 35 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 0 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif @@ -52,7 +52,6 @@ typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; -typedef uint64_t flex_uint64_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; @@ -60,7 +59,6 @@ typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; -#endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN @@ -91,6 +89,8 @@ typedef unsigned int flex_uint32_t; #define UINT32_MAX (4294967295U) #endif +#endif /* ! C99 */ + #endif /* ! FLEXINT_H */ #ifdef __cplusplus @@ -164,7 +164,15 @@ typedef void* yyscan_t; /* Size of default input buffer. */ #ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else #define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. @@ -194,11 +202,18 @@ typedef size_t yy_size_t; */ #define YY_LESS_LINENO(n) \ do { \ - yy_size_t yyl;\ + int yyl;\ for ( yyl = n; yyl < yyleng; ++yyl )\ if ( yytext[yyl] == '\n' )\ --yylineno;\ }while(0) + #define YY_LINENO_REWIND_TO(dst) \ + do {\ + const char *p;\ + for ( p = yy_cp-1; p >= (dst); --p)\ + if ( *p == '\n' )\ + --yylineno;\ + }while(0) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ @@ -233,7 +248,7 @@ struct yy_buffer_state /* Number of characters read into yy_ch_buf, not including EOB * characters. */ - yy_size_t yy_n_chars; + int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to @@ -353,6 +368,9 @@ typedef int yy_state_type; static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); static int yy_get_next_buffer (yyscan_t yyscanner ); +#if defined(__GNUC__) && __GNUC__ >= 3 +__attribute__((__noreturn__)) +#endif static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); /* Done after the current pattern has been matched and before the @@ -360,13 +378,13 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); */ #define YY_DO_BEFORE_ACTION \ yyg->yytext_ptr = yy_bp; \ - yyleng = (yy_size_t) (yy_cp - yy_bp); \ + yyleng = (size_t) (yy_cp - yy_bp); \ yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 84 -#define YY_END_OF_BUFFER 85 +#define YY_NUM_RULES 89 +#define YY_END_OF_BUFFER 90 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -374,34 +392,37 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[205] = +static yyconst flex_int16_t yy_accept[239] = { 0, - 0, 0, 85, 83, 82, 82, 56, 83, 30, 46, - 51, 32, 33, 44, 42, 39, 43, 38, 45, 4, - 4, 58, 79, 63, 59, 62, 57, 36, 37, 50, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 34, 49, 35, - 52, 82, 61, 31, 30, 70, 55, 75, 68, 40, - 66, 41, 67, 1, 0, 80, 69, 2, 4, 0, - 0, 47, 65, 60, 64, 48, 74, 54, 30, 30, - 30, 12, 30, 30, 30, 30, 30, 8, 17, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - - 73, 53, 31, 78, 0, 0, 0, 80, 1, 0, - 0, 3, 5, 71, 72, 77, 30, 30, 30, 30, - 30, 30, 10, 30, 30, 30, 30, 30, 30, 18, - 30, 30, 30, 30, 30, 30, 76, 0, 1, 81, - 0, 0, 2, 30, 30, 30, 30, 9, 30, 25, - 30, 30, 30, 22, 30, 30, 30, 30, 30, 6, - 30, 30, 0, 1, 13, 21, 30, 30, 7, 24, - 19, 30, 30, 30, 30, 30, 30, 30, 11, 30, - 30, 28, 30, 30, 30, 16, 27, 30, 30, 15, - 23, 30, 30, 20, 14, 30, 30, 30, 29, 30, - - 30, 30, 26, 0 + 0, 0, 90, 88, 87, 87, 61, 88, 35, 51, + 56, 37, 38, 49, 47, 44, 48, 43, 50, 4, + 4, 63, 84, 68, 64, 67, 62, 41, 42, 55, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 39, 54, + 40, 57, 87, 66, 36, 35, 75, 60, 80, 73, + 45, 71, 46, 72, 1, 0, 85, 74, 2, 4, + 0, 0, 52, 70, 65, 69, 53, 79, 59, 35, + 35, 35, 12, 35, 35, 35, 35, 35, 8, 17, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + + 35, 35, 35, 78, 58, 36, 83, 0, 0, 0, + 85, 1, 0, 0, 3, 5, 76, 77, 82, 35, + 35, 35, 35, 35, 35, 35, 10, 35, 35, 35, + 35, 35, 35, 18, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 81, 0, 1, 86, 0, 0, + 2, 35, 35, 35, 35, 35, 9, 35, 25, 35, + 35, 35, 22, 35, 35, 35, 35, 35, 35, 35, + 6, 35, 35, 35, 35, 0, 1, 13, 35, 21, + 35, 35, 7, 24, 19, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 11, 35, 35, 35, 35, + + 33, 35, 35, 35, 35, 35, 16, 32, 35, 35, + 35, 35, 35, 15, 23, 35, 35, 35, 35, 20, + 35, 35, 29, 14, 35, 35, 27, 31, 30, 35, + 35, 34, 28, 35, 35, 35, 26, 0 } ; -static yyconst flex_int32_t yy_ec[256] = +static yyconst YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, @@ -433,7 +454,7 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst flex_int32_t yy_meta[57] = +static yyconst YY_CHAR yy_meta[57] = { 0, 1, 1, 2, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, @@ -443,101 +464,113 @@ static yyconst flex_int32_t yy_meta[57] = 3, 3, 1, 1, 1, 1 } ; -static yyconst flex_int16_t yy_base[211] = +static yyconst flex_uint16_t yy_base[245] = { 0, - 0, 0, 273, 274, 55, 57, 250, 0, 0, 249, - 53, 274, 274, 248, 50, 274, 49, 47, 57, 52, - 59, 274, 274, 59, 247, 60, 274, 274, 274, 62, - 223, 224, 49, 226, 58, 227, 54, 64, 230, 220, - 214, 216, 226, 212, 213, 215, 219, 274, 68, 274, - 274, 97, 274, 0, 0, 274, 233, 274, 274, 274, - 274, 274, 274, 87, 243, 0, 274, 91, 97, 112, - 0, 231, 274, 274, 274, 230, 274, 229, 216, 207, - 202, 0, 201, 206, 215, 199, 207, 0, 199, 189, - 190, 206, 194, 190, 202, 188, 189, 185, 194, 193, - - 274, 208, 0, 274, 120, 218, 212, 0, 93, 127, - 118, 125, 0, 274, 274, 274, 197, 100, 194, 191, - 178, 176, 0, 185, 173, 177, 175, 180, 183, 0, - 184, 167, 166, 179, 177, 171, 274, 131, 133, 274, - 140, 138, 142, 171, 162, 170, 177, 0, 172, 0, - 161, 157, 155, 0, 154, 156, 162, 154, 166, 0, - 154, 162, 144, 146, 0, 0, 153, 149, 0, 0, - 0, 146, 151, 145, 144, 147, 141, 142, 0, 138, - 147, 0, 122, 109, 102, 0, 0, 92, 94, 0, - 0, 86, 75, 0, 0, 84, 64, 55, 0, 59, - - 46, 32, 0, 274, 162, 165, 168, 173, 178, 180 + 0, 0, 306, 307, 55, 57, 283, 0, 0, 282, + 53, 307, 307, 281, 50, 307, 49, 47, 57, 52, + 59, 307, 307, 59, 280, 60, 307, 307, 307, 62, + 256, 257, 49, 259, 58, 260, 54, 64, 263, 253, + 247, 249, 259, 245, 246, 248, 246, 60, 307, 68, + 307, 307, 97, 307, 0, 0, 307, 266, 307, 307, + 307, 307, 307, 307, 91, 276, 0, 307, 93, 97, + 112, 0, 264, 307, 307, 307, 263, 307, 262, 249, + 76, 236, 0, 235, 240, 249, 233, 241, 0, 233, + 223, 224, 240, 228, 224, 236, 74, 224, 220, 229, + + 226, 227, 226, 307, 241, 0, 307, 120, 251, 245, + 0, 118, 128, 130, 132, 0, 307, 307, 307, 230, + 225, 107, 226, 223, 210, 208, 0, 217, 205, 209, + 207, 212, 215, 0, 216, 214, 199, 197, 196, 209, + 207, 211, 200, 192, 307, 138, 140, 307, 147, 145, + 149, 199, 192, 189, 197, 204, 0, 199, 0, 188, + 184, 182, 0, 181, 183, 189, 183, 180, 179, 191, + 0, 179, 174, 186, 185, 151, 153, 0, 184, 0, + 175, 171, 0, 0, 0, 168, 173, 167, 166, 169, + 172, 167, 161, 162, 168, 0, 162, 162, 155, 169, + + 0, 157, 156, 161, 158, 165, 0, 0, 155, 155, + 152, 146, 153, 0, 0, 139, 117, 99, 96, 0, + 107, 99, 0, 0, 101, 86, 0, 0, 0, 64, + 59, 0, 0, 64, 46, 32, 0, 307, 169, 172, + 175, 180, 185, 187 } ; -static yyconst flex_int16_t yy_def[211] = +static yyconst flex_int16_t yy_def[245] = { 0, - 204, 1, 204, 204, 204, 204, 204, 205, 206, 204, - 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, - 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, - 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, - 206, 206, 206, 206, 206, 206, 206, 204, 204, 204, - 204, 204, 204, 207, 206, 204, 204, 204, 204, 204, - 204, 204, 204, 204, 208, 209, 204, 204, 204, 204, - 210, 204, 204, 204, 204, 204, 204, 204, 206, 206, - 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, - 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, - - 204, 204, 207, 204, 204, 208, 208, 209, 204, 204, - 204, 204, 210, 204, 204, 204, 206, 206, 206, 206, - 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, - 206, 206, 206, 206, 206, 206, 204, 204, 204, 204, - 204, 204, 204, 206, 206, 206, 206, 206, 206, 206, - 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, - 206, 206, 204, 204, 206, 206, 206, 206, 206, 206, - 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, - 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, - 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, - - 206, 206, 206, 0, 204, 204, 204, 204, 204, 204 + 238, 1, 238, 238, 238, 238, 238, 239, 240, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 238, 238, + 238, 238, 238, 238, 241, 240, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 242, 243, 238, 238, 238, + 238, 244, 238, 238, 238, 238, 238, 238, 238, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + + 240, 240, 240, 238, 238, 241, 238, 238, 242, 242, + 243, 238, 238, 238, 238, 244, 238, 238, 238, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 238, 238, 238, 238, 238, 238, + 238, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 238, 238, 240, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 0, 238, 238, + 238, 238, 238, 238 } ; -static yyconst flex_int16_t yy_nxt[331] = +static yyconst flex_uint16_t yy_nxt[364] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 9, 9, 28, 29, 30, 9, 31, 32, 33, 34, 35, 9, 36, 37, 9, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 9, 47, - 9, 9, 48, 49, 50, 51, 52, 52, 52, 52, - 57, 60, 62, 64, 64, 203, 68, 65, 69, 69, - 63, 61, 66, 68, 58, 69, 69, 70, 67, 72, - 73, 75, 76, 77, 70, 70, 81, 84, 88, 101, - 78, 82, 70, 90, 202, 89, 201, 85, 52, 52, - - 86, 200, 71, 64, 64, 199, 91, 109, 109, 109, - 109, 68, 105, 69, 69, 198, 110, 197, 141, 196, - 105, 102, 70, 111, 110, 111, 141, 195, 112, 112, - 70, 138, 194, 138, 112, 112, 139, 139, 142, 193, - 142, 112, 112, 143, 143, 145, 146, 139, 139, 139, - 139, 163, 192, 163, 143, 143, 164, 164, 143, 143, - 164, 164, 164, 164, 54, 191, 54, 55, 55, 55, - 103, 103, 103, 106, 106, 106, 106, 106, 108, 190, - 108, 108, 108, 113, 113, 189, 188, 187, 186, 185, - 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, - - 174, 173, 172, 171, 170, 169, 168, 167, 166, 165, - 162, 161, 160, 159, 158, 157, 156, 155, 154, 153, - 152, 151, 150, 149, 148, 147, 144, 140, 107, 137, - 136, 135, 134, 133, 132, 131, 130, 129, 128, 127, - 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, - 116, 115, 114, 107, 104, 100, 99, 98, 97, 96, - 95, 94, 93, 92, 87, 83, 80, 79, 74, 59, - 56, 53, 204, 3, 204, 204, 204, 204, 204, 204, - 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, - 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, - - 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, - 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, - 204, 204, 204, 204, 204, 204, 204, 204, 204, 204 + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 9, 9, 49, 50, 51, 52, 53, 53, 53, 53, + 58, 61, 63, 65, 65, 237, 69, 66, 70, 70, + 64, 62, 67, 69, 59, 70, 70, 71, 68, 73, + 74, 76, 77, 78, 71, 71, 82, 85, 89, 104, + 79, 83, 71, 91, 236, 90, 102, 86, 53, 53, + + 87, 235, 72, 136, 103, 234, 92, 65, 65, 112, + 112, 69, 121, 70, 70, 233, 108, 122, 113, 137, + 138, 105, 71, 114, 108, 114, 113, 232, 115, 115, + 71, 146, 231, 146, 112, 112, 147, 147, 230, 150, + 229, 150, 228, 149, 151, 151, 115, 115, 115, 115, + 227, 149, 154, 155, 147, 147, 147, 147, 176, 226, + 176, 151, 151, 177, 177, 151, 151, 177, 177, 177, + 177, 55, 225, 55, 56, 56, 56, 106, 106, 106, + 109, 109, 109, 109, 109, 111, 224, 111, 111, 111, + 116, 116, 223, 222, 221, 220, 219, 218, 217, 216, + + 215, 214, 213, 212, 211, 210, 209, 208, 207, 206, + 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, + 195, 194, 193, 192, 191, 190, 189, 188, 187, 186, + 185, 184, 183, 182, 181, 180, 179, 178, 175, 174, + 173, 172, 171, 170, 169, 168, 167, 166, 165, 164, + 163, 162, 161, 160, 159, 158, 157, 156, 153, 152, + 148, 110, 145, 144, 143, 142, 141, 140, 139, 135, + 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, + 124, 123, 120, 119, 118, 117, 110, 107, 101, 100, + 99, 98, 97, 96, 95, 94, 93, 88, 84, 81, + + 80, 75, 60, 57, 54, 238, 3, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238 } ; -static yyconst flex_int16_t yy_chk[331] = +static yyconst flex_int16_t yy_chk[364] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -545,46 +578,50 @@ static yyconst flex_int16_t yy_chk[331] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 6, 6, - 11, 15, 17, 18, 18, 202, 20, 19, 20, 20, + 11, 15, 17, 18, 18, 236, 20, 19, 20, 20, 17, 15, 19, 21, 11, 21, 21, 20, 19, 24, - 24, 26, 26, 30, 21, 20, 33, 35, 37, 49, - 30, 33, 21, 38, 201, 37, 200, 35, 52, 52, - - 35, 198, 20, 64, 64, 197, 38, 68, 68, 109, - 109, 69, 64, 69, 69, 196, 68, 193, 109, 192, - 64, 49, 69, 70, 68, 70, 109, 189, 70, 70, - 69, 105, 188, 105, 111, 111, 105, 105, 110, 185, - 110, 112, 112, 110, 110, 118, 118, 138, 138, 139, - 139, 141, 184, 141, 142, 142, 141, 141, 143, 143, - 163, 163, 164, 164, 205, 183, 205, 206, 206, 206, - 207, 207, 207, 208, 208, 208, 208, 208, 209, 181, - 209, 209, 209, 210, 210, 180, 178, 177, 176, 175, - 174, 173, 172, 168, 167, 162, 161, 159, 158, 157, - - 156, 155, 153, 152, 151, 149, 147, 146, 145, 144, - 136, 135, 134, 133, 132, 131, 129, 128, 127, 126, - 125, 124, 122, 121, 120, 119, 117, 107, 106, 102, - 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, - 90, 89, 87, 86, 85, 84, 83, 81, 80, 79, - 78, 76, 72, 65, 57, 47, 46, 45, 44, 43, - 42, 41, 40, 39, 36, 34, 32, 31, 25, 14, - 10, 7, 3, 204, 204, 204, 204, 204, 204, 204, - 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, - 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, - - 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, - 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, - 204, 204, 204, 204, 204, 204, 204, 204, 204, 204 + 24, 26, 26, 30, 21, 20, 33, 35, 37, 50, + 30, 33, 21, 38, 235, 37, 48, 35, 53, 53, + + 35, 234, 20, 97, 48, 231, 38, 65, 65, 69, + 69, 70, 81, 70, 70, 230, 65, 81, 69, 97, + 97, 50, 70, 71, 65, 71, 69, 226, 71, 71, + 70, 108, 225, 108, 112, 112, 108, 108, 222, 113, + 221, 113, 219, 112, 113, 113, 114, 114, 115, 115, + 218, 112, 122, 122, 146, 146, 147, 147, 149, 217, + 149, 150, 150, 149, 149, 151, 151, 176, 176, 177, + 177, 239, 216, 239, 240, 240, 240, 241, 241, 241, + 242, 242, 242, 242, 242, 243, 213, 243, 243, 243, + 244, 244, 212, 211, 210, 209, 206, 205, 204, 203, + + 202, 200, 199, 198, 197, 195, 194, 193, 192, 191, + 190, 189, 188, 187, 186, 182, 181, 179, 175, 174, + 173, 172, 170, 169, 168, 167, 166, 165, 164, 162, + 161, 160, 158, 156, 155, 154, 153, 152, 144, 143, + 142, 141, 140, 139, 138, 137, 136, 135, 133, 132, + 131, 130, 129, 128, 126, 125, 124, 123, 121, 120, + 110, 109, 105, 103, 102, 101, 100, 99, 98, 96, + 95, 94, 93, 92, 91, 90, 88, 87, 86, 85, + 84, 82, 80, 79, 77, 73, 66, 58, 47, 46, + 45, 44, 43, 42, 41, 40, 39, 36, 34, 32, + + 31, 25, 14, 10, 7, 3, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238 } ; /* Table of booleans, true if rule could match eol. */ -static yyconst flex_int32_t yy_rule_can_match_eol[85] = +static yyconst flex_int32_t yy_rule_can_match_eol[90] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 0, 0, }; + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, }; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. @@ -607,7 +644,7 @@ static yyconst flex_int32_t yy_rule_can_match_eol[85] = */ #define YY_NO_UNISTD_H 1 -#line 605 "lex.sksl.c" +#line 642 "lex.sksl.c" #define INITIAL 0 @@ -636,7 +673,7 @@ struct yyguts_t size_t yy_buffer_stack_max; /**< capacity of stack. */ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ char yy_hold_char; - yy_size_t yy_n_chars; + int yy_n_chars; yy_size_t yyleng_r; char *yy_c_buf_p; int yy_init; @@ -678,11 +715,11 @@ void skslset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); FILE *skslget_in (yyscan_t yyscanner ); -void skslset_in (FILE * in_str ,yyscan_t yyscanner ); +void skslset_in (FILE * _in_str ,yyscan_t yyscanner ); FILE *skslget_out (yyscan_t yyscanner ); -void skslset_out (FILE * out_str ,yyscan_t yyscanner ); +void skslset_out (FILE * _out_str ,yyscan_t yyscanner ); yy_size_t skslget_leng (yyscan_t yyscanner ); @@ -690,7 +727,11 @@ char *skslget_text (yyscan_t yyscanner ); int skslget_lineno (yyscan_t yyscanner ); -void skslset_lineno (int line_number ,yyscan_t yyscanner ); +void skslset_lineno (int _line_number ,yyscan_t yyscanner ); + +int skslget_column (yyscan_t yyscanner ); + +void skslset_column (int _column_no ,yyscan_t yyscanner ); /* Macros after this point can all be overridden by user definitions in * section 1. @@ -704,8 +745,12 @@ extern int skslwrap (yyscan_t yyscanner ); #endif #endif +#ifndef YY_NO_UNPUT + static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner); +#endif + #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); #endif @@ -726,7 +771,12 @@ static int input (yyscan_t yyscanner ); /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else #define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ @@ -734,7 +784,7 @@ static int input (yyscan_t yyscanner ); /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ -#define ECHO fwrite( yytext, yyleng, 1, yyout ) +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, @@ -745,7 +795,7 @@ static int input (yyscan_t yyscanner ); if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ - yy_size_t n; \ + size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ @@ -813,7 +863,7 @@ extern int sksllex (yyscan_t yyscanner); /* Code executed at the end of each rule. */ #ifndef YY_BREAK -#define YY_BREAK break; +#define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ @@ -823,16 +873,11 @@ extern int sksllex (yyscan_t yyscanner); */ YY_DECL { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; -#line 23 "sksl.flex" - - -#line 829 "lex.sksl.c" - if ( !yyg->yy_init ) { yyg->yy_init = 1; @@ -859,7 +904,13 @@ YY_DECL sksl_load_buffer_state(yyscanner ); } - while ( 1 ) /* loops until end-of-file is reached */ + { +#line 23 "sksl.flex" + + +#line 906 "lex.sksl.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = yyg->yy_c_buf_p; @@ -875,7 +926,7 @@ YY_DECL yy_match: do { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -884,13 +935,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 205 ) + if ( yy_current_state >= 239 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_current_state != 204 ); + while ( yy_current_state != 238 ); yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; @@ -1055,296 +1106,321 @@ YY_RULE_SETUP case 27: YY_RULE_SETUP #line 77 "sksl.flex" -{ return SkSL::Token::STRUCT; } +{ return SkSL::Token::READONLY; } YY_BREAK case 28: YY_RULE_SETUP #line 79 "sksl.flex" -{ return SkSL::Token::LAYOUT; } +{ return SkSL::Token::WRITEONLY; } YY_BREAK case 29: YY_RULE_SETUP #line 81 "sksl.flex" -{ return SkSL::Token::PRECISION; } +{ return SkSL::Token::COHERENT; } YY_BREAK case 30: YY_RULE_SETUP #line 83 "sksl.flex" -{ return SkSL::Token::IDENTIFIER; } +{ return SkSL::Token::VOLATILE; } YY_BREAK case 31: YY_RULE_SETUP #line 85 "sksl.flex" -{ return SkSL::Token::DIRECTIVE; } +{ return SkSL::Token::RESTRICT; } YY_BREAK case 32: YY_RULE_SETUP #line 87 "sksl.flex" -{ return SkSL::Token::LPAREN; } +{ return SkSL::Token::STRUCT; } YY_BREAK case 33: YY_RULE_SETUP #line 89 "sksl.flex" -{ return SkSL::Token::RPAREN; } +{ return SkSL::Token::LAYOUT; } YY_BREAK case 34: YY_RULE_SETUP #line 91 "sksl.flex" -{ return SkSL::Token::LBRACE; } +{ return SkSL::Token::PRECISION; } YY_BREAK case 35: YY_RULE_SETUP #line 93 "sksl.flex" -{ return SkSL::Token::RBRACE; } +{ return SkSL::Token::IDENTIFIER; } YY_BREAK case 36: YY_RULE_SETUP #line 95 "sksl.flex" -{ return SkSL::Token::LBRACKET; } +{ return SkSL::Token::DIRECTIVE; } YY_BREAK case 37: YY_RULE_SETUP #line 97 "sksl.flex" -{ return SkSL::Token::RBRACKET; } +{ return SkSL::Token::LPAREN; } YY_BREAK case 38: YY_RULE_SETUP #line 99 "sksl.flex" -{ return SkSL::Token::DOT; } +{ return SkSL::Token::RPAREN; } YY_BREAK case 39: YY_RULE_SETUP #line 101 "sksl.flex" -{ return SkSL::Token::COMMA; } +{ return SkSL::Token::LBRACE; } YY_BREAK case 40: YY_RULE_SETUP #line 103 "sksl.flex" -{ return SkSL::Token::PLUSPLUS; } +{ return SkSL::Token::RBRACE; } YY_BREAK case 41: YY_RULE_SETUP #line 105 "sksl.flex" -{ return SkSL::Token::MINUSMINUS; } +{ return SkSL::Token::LBRACKET; } YY_BREAK case 42: YY_RULE_SETUP #line 107 "sksl.flex" -{ return SkSL::Token::PLUS; } +{ return SkSL::Token::RBRACKET; } YY_BREAK case 43: YY_RULE_SETUP #line 109 "sksl.flex" -{ return SkSL::Token::MINUS; } +{ return SkSL::Token::DOT; } YY_BREAK case 44: YY_RULE_SETUP #line 111 "sksl.flex" -{ return SkSL::Token::STAR; } +{ return SkSL::Token::COMMA; } YY_BREAK case 45: YY_RULE_SETUP #line 113 "sksl.flex" -{ return SkSL::Token::SLASH; } +{ return SkSL::Token::PLUSPLUS; } YY_BREAK case 46: YY_RULE_SETUP #line 115 "sksl.flex" -{ return SkSL::Token::PERCENT; } +{ return SkSL::Token::MINUSMINUS; } YY_BREAK case 47: YY_RULE_SETUP #line 117 "sksl.flex" -{ return SkSL::Token::SHL; } +{ return SkSL::Token::PLUS; } YY_BREAK case 48: YY_RULE_SETUP #line 119 "sksl.flex" -{ return SkSL::Token::SHR; } +{ return SkSL::Token::MINUS; } YY_BREAK case 49: YY_RULE_SETUP #line 121 "sksl.flex" -{ return SkSL::Token::BITWISEOR; } +{ return SkSL::Token::STAR; } YY_BREAK case 50: YY_RULE_SETUP #line 123 "sksl.flex" -{ return SkSL::Token::BITWISEXOR; } +{ return SkSL::Token::SLASH; } YY_BREAK case 51: YY_RULE_SETUP #line 125 "sksl.flex" -{ return SkSL::Token::BITWISEAND; } +{ return SkSL::Token::PERCENT; } YY_BREAK case 52: YY_RULE_SETUP #line 127 "sksl.flex" -{ return SkSL::Token::BITWISENOT; } +{ return SkSL::Token::SHL; } YY_BREAK case 53: YY_RULE_SETUP #line 129 "sksl.flex" -{ return SkSL::Token::LOGICALOR; } +{ return SkSL::Token::SHR; } YY_BREAK case 54: YY_RULE_SETUP #line 131 "sksl.flex" -{ return SkSL::Token::LOGICALXOR; } +{ return SkSL::Token::BITWISEOR; } YY_BREAK case 55: YY_RULE_SETUP #line 133 "sksl.flex" -{ return SkSL::Token::LOGICALAND; } +{ return SkSL::Token::BITWISEXOR; } YY_BREAK case 56: YY_RULE_SETUP #line 135 "sksl.flex" -{ return SkSL::Token::LOGICALNOT; } +{ return SkSL::Token::BITWISEAND; } YY_BREAK case 57: YY_RULE_SETUP #line 137 "sksl.flex" -{ return SkSL::Token::QUESTION; } +{ return SkSL::Token::BITWISENOT; } YY_BREAK case 58: YY_RULE_SETUP #line 139 "sksl.flex" -{ return SkSL::Token::COLON; } +{ return SkSL::Token::LOGICALOR; } YY_BREAK case 59: YY_RULE_SETUP #line 141 "sksl.flex" -{ return SkSL::Token::EQ; } +{ return SkSL::Token::LOGICALXOR; } YY_BREAK case 60: YY_RULE_SETUP #line 143 "sksl.flex" -{ return SkSL::Token::EQEQ; } +{ return SkSL::Token::LOGICALAND; } YY_BREAK case 61: YY_RULE_SETUP #line 145 "sksl.flex" -{ return SkSL::Token::NEQ; } +{ return SkSL::Token::LOGICALNOT; } YY_BREAK case 62: YY_RULE_SETUP #line 147 "sksl.flex" -{ return SkSL::Token::GT; } +{ return SkSL::Token::QUESTION; } YY_BREAK case 63: YY_RULE_SETUP #line 149 "sksl.flex" -{ return SkSL::Token::LT; } +{ return SkSL::Token::COLON; } YY_BREAK case 64: YY_RULE_SETUP #line 151 "sksl.flex" -{ return SkSL::Token::GTEQ; } +{ return SkSL::Token::EQ; } YY_BREAK case 65: YY_RULE_SETUP #line 153 "sksl.flex" -{ return SkSL::Token::LTEQ; } +{ return SkSL::Token::EQEQ; } YY_BREAK case 66: YY_RULE_SETUP #line 155 "sksl.flex" -{ return SkSL::Token::PLUSEQ; } +{ return SkSL::Token::NEQ; } YY_BREAK case 67: YY_RULE_SETUP #line 157 "sksl.flex" -{ return SkSL::Token::MINUSEQ; } +{ return SkSL::Token::GT; } YY_BREAK case 68: YY_RULE_SETUP #line 159 "sksl.flex" -{ return SkSL::Token::STAREQ; } +{ return SkSL::Token::LT; } YY_BREAK case 69: YY_RULE_SETUP #line 161 "sksl.flex" -{ return SkSL::Token::SLASHEQ; } +{ return SkSL::Token::GTEQ; } YY_BREAK case 70: YY_RULE_SETUP #line 163 "sksl.flex" -{ return SkSL::Token::PERCENTEQ; } +{ return SkSL::Token::LTEQ; } YY_BREAK case 71: YY_RULE_SETUP #line 165 "sksl.flex" -{ return SkSL::Token::SHLEQ; } +{ return SkSL::Token::PLUSEQ; } YY_BREAK case 72: YY_RULE_SETUP #line 167 "sksl.flex" -{ return SkSL::Token::SHREQ; } +{ return SkSL::Token::MINUSEQ; } YY_BREAK case 73: YY_RULE_SETUP #line 169 "sksl.flex" -{ return SkSL::Token::BITWISEOREQ; } +{ return SkSL::Token::STAREQ; } YY_BREAK case 74: YY_RULE_SETUP #line 171 "sksl.flex" -{ return SkSL::Token::BITWISEXOREQ; } +{ return SkSL::Token::SLASHEQ; } YY_BREAK case 75: YY_RULE_SETUP #line 173 "sksl.flex" -{ return SkSL::Token::BITWISEANDEQ; } +{ return SkSL::Token::PERCENTEQ; } YY_BREAK case 76: YY_RULE_SETUP #line 175 "sksl.flex" -{ return SkSL::Token::LOGICALOREQ; } +{ return SkSL::Token::SHLEQ; } YY_BREAK case 77: YY_RULE_SETUP #line 177 "sksl.flex" -{ return SkSL::Token::LOGICALXOREQ; } +{ return SkSL::Token::SHREQ; } YY_BREAK case 78: YY_RULE_SETUP #line 179 "sksl.flex" -{ return SkSL::Token::LOGICALANDEQ; } +{ return SkSL::Token::BITWISEOREQ; } YY_BREAK case 79: YY_RULE_SETUP #line 181 "sksl.flex" -{ return SkSL::Token::SEMICOLON; } +{ return SkSL::Token::BITWISEXOREQ; } YY_BREAK case 80: YY_RULE_SETUP #line 183 "sksl.flex" -/* line comment */ +{ return SkSL::Token::BITWISEANDEQ; } YY_BREAK case 81: -/* rule 81 can match eol */ YY_RULE_SETUP #line 185 "sksl.flex" -/* block comment */ +{ return SkSL::Token::LOGICALOREQ; } YY_BREAK case 82: -/* rule 82 can match eol */ YY_RULE_SETUP #line 187 "sksl.flex" -/* whitespace */ +{ return SkSL::Token::LOGICALXOREQ; } YY_BREAK case 83: YY_RULE_SETUP #line 189 "sksl.flex" -{ return SkSL::Token::INVALID_TOKEN; } +{ return SkSL::Token::LOGICALANDEQ; } YY_BREAK case 84: YY_RULE_SETUP #line 191 "sksl.flex" +{ return SkSL::Token::SEMICOLON; } + YY_BREAK +case 85: +YY_RULE_SETUP +#line 193 "sksl.flex" +/* line comment */ + YY_BREAK +case 86: +/* rule 86 can match eol */ +YY_RULE_SETUP +#line 195 "sksl.flex" +/* block comment */ + YY_BREAK +case 87: +/* rule 87 can match eol */ +YY_RULE_SETUP +#line 197 "sksl.flex" +/* whitespace */ + YY_BREAK +case 88: +YY_RULE_SETUP +#line 199 "sksl.flex" +{ return SkSL::Token::INVALID_TOKEN; } + YY_BREAK +case 89: +YY_RULE_SETUP +#line 201 "sksl.flex" ECHO; YY_BREAK -#line 1342 "lex.sksl.c" +#line 1418 "lex.sksl.c" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -1476,6 +1552,7 @@ case YY_STATE_EOF(INITIAL): "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ + } /* end of user's declarations */ } /* end of sksllex */ /* yy_get_next_buffer - try to read in a new buffer @@ -1488,9 +1565,9 @@ case YY_STATE_EOF(INITIAL): static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = yyg->yytext_ptr; - register int number_to_move, i; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + yy_size_t number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) @@ -1519,7 +1596,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) /* Try to read more data. */ /* First move last chars to start of buffer. */ - number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + number_to_move = (yy_size_t) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); @@ -1539,7 +1616,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) (yyg->yy_c_buf_p - b->yy_ch_buf); @@ -1601,9 +1678,9 @@ static int yy_get_next_buffer (yyscan_t yyscanner) else ret_val = EOB_ACT_CONTINUE_SCAN; - if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + if ((int) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ - yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) skslrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); @@ -1622,15 +1699,15 @@ static int yy_get_next_buffer (yyscan_t yyscanner) static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { - register yy_state_type yy_current_state; - register char *yy_cp; + yy_state_type yy_current_state; + char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1639,7 +1716,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 205 ) + if ( yy_current_state >= 239 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1655,11 +1732,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { - register int yy_is_jam; + int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ - register char *yy_cp = yyg->yy_c_buf_p; + char *yy_cp = yyg->yy_c_buf_p; - register YY_CHAR yy_c = 1; + YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; @@ -1668,18 +1745,21 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 205 ) + if ( yy_current_state >= 239 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 204); + yy_is_jam = (yy_current_state == 238); + (void)yyg; return yy_is_jam ? 0 : yy_current_state; } - static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner) +#ifndef YY_NO_UNPUT + + static void yyunput (int c, char * yy_bp , yyscan_t yyscanner) { - register char *yy_cp; + char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_cp = yyg->yy_c_buf_p; @@ -1690,10 +1770,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner) if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ - register yy_size_t number_to_move = yyg->yy_n_chars + 2; - register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + yy_size_t number_to_move = yyg->yy_n_chars + 2; + char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; - register char *source = + char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) @@ -1719,6 +1799,8 @@ static int yy_get_next_buffer (yyscan_t yyscanner) yyg->yy_c_buf_p = yy_cp; } +#endif + #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (yyscan_t yyscanner) @@ -1768,7 +1850,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) case EOB_ACT_END_OF_FILE: { if ( skslwrap(yyscanner ) ) - return 0; + return EOF; if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; @@ -1879,7 +1961,7 @@ static void sksl_load_buffer_state (yyscan_t yyscanner) if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in sksl_create_buffer()" ); - b->yy_buf_size = size; + b->yy_buf_size = (yy_size_t)size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. @@ -2040,7 +2122,7 @@ static void skslensure_buffer_stack (yyscan_t yyscanner) * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ - num_to_alloc = 1; + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ yyg->yy_buffer_stack = (struct yy_buffer_state**)skslalloc (num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); @@ -2057,7 +2139,7 @@ static void skslensure_buffer_stack (yyscan_t yyscanner) if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ /* Increase the buffer to prepare for a possible push. */ - int grow_size = 8 /* arbitrary grow size */; + yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = yyg->yy_buffer_stack_max + grow_size; yyg->yy_buffer_stack = (struct yy_buffer_state**)skslrealloc @@ -2124,8 +2206,8 @@ YY_BUFFER_STATE sksl_scan_string (yyconst char * yystr , yyscan_t yyscanner) /** Setup the input buffer state to scan the given bytes. The next call to sksllex() will * scan from a @e copy of @a bytes. - * @param bytes the byte buffer to scan - * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ @@ -2133,7 +2215,8 @@ YY_BUFFER_STATE sksl_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_le { YY_BUFFER_STATE b; char *buf; - yy_size_t n, i; + yy_size_t n; + yy_size_t i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; @@ -2164,7 +2247,9 @@ YY_BUFFER_STATE sksl_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_le static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) { - (void) fprintf( stderr, "%s\n", msg ); + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } @@ -2270,51 +2355,51 @@ void skslset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) } /** Set the current line number. - * @param line_number + * @param _line_number line number * @param yyscanner The scanner object. */ -void skslset_lineno (int line_number , yyscan_t yyscanner) +void skslset_lineno (int _line_number , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* lineno is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) - yy_fatal_error( "skslset_lineno called with no buffer" , yyscanner); + YY_FATAL_ERROR( "skslset_lineno called with no buffer" ); - yylineno = line_number; + yylineno = _line_number; } /** Set the current column. - * @param line_number + * @param _column_no column number * @param yyscanner The scanner object. */ -void skslset_column (int column_no , yyscan_t yyscanner) +void skslset_column (int _column_no , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* column is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) - yy_fatal_error( "skslset_column called with no buffer" , yyscanner); + YY_FATAL_ERROR( "skslset_column called with no buffer" ); - yycolumn = column_no; + yycolumn = _column_no; } /** Set the input stream. This does not discard the current * input buffer. - * @param in_str A readable stream. + * @param _in_str A readable stream. * @param yyscanner The scanner object. * @see sksl_switch_to_buffer */ -void skslset_in (FILE * in_str , yyscan_t yyscanner) +void skslset_in (FILE * _in_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyin = in_str ; + yyin = _in_str ; } -void skslset_out (FILE * out_str , yyscan_t yyscanner) +void skslset_out (FILE * _out_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyout = out_str ; + yyout = _out_str ; } int skslget_debug (yyscan_t yyscanner) @@ -2323,10 +2408,10 @@ int skslget_debug (yyscan_t yyscanner) return yy_flex_debug; } -void skslset_debug (int bdebug , yyscan_t yyscanner) +void skslset_debug (int _bdebug , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yy_flex_debug = bdebug ; + yy_flex_debug = _bdebug ; } /* Accessor methods for yylval and yylloc */ @@ -2465,7 +2550,10 @@ int sksllex_destroy (yyscan_t yyscanner) #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) { - register int i; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } @@ -2474,7 +2562,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yysca #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) { - register int n; + int n; for ( n = 0; s[n]; ++n ) ; @@ -2484,11 +2572,16 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) void *skslalloc (yy_size_t size , yyscan_t yyscanner) { + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; return (void *) malloc( size ); } void *skslrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) { + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter @@ -2501,12 +2594,14 @@ void *skslrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) void skslfree (void * ptr , yyscan_t yyscanner) { + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; free( (char *) ptr ); /* see skslrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" -#line 191 "sksl.flex" +#line 201 "sksl.flex" diff --git a/src/sksl/sksl.flex b/src/sksl/sksl.flex index 4455f50..25216bd 100644 --- a/src/sksl/sksl.flex +++ b/src/sksl/sksl.flex @@ -74,6 +74,16 @@ flat { return SkSL::Token::FLAT; } noperspective { return SkSL::Token::NOPERSPECTIVE; } +readonly { return SkSL::Token::READONLY; } + +writeonly { return SkSL::Token::WRITEONLY; } + +coherent { return SkSL::Token::COHERENT; } + +volatile { return SkSL::Token::VOLATILE; } + +restrict { return SkSL::Token::RESTRICT; } + struct { return SkSL::Token::STRUCT; } layout { return SkSL::Token::LAYOUT; } diff --git a/tests/ImageStorageTest.cpp b/tests/ImageStorageTest.cpp new file mode 100644 index 0000000..415774a --- /dev/null +++ b/tests/ImageStorageTest.cpp @@ -0,0 +1,163 @@ +/* + * 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 Make(sk_sp texture, GrSLMemoryModel mm, + GrSLRestrict restrict) { + return sk_sp(new TestFP(std::move(texture), mm, restrict)); + } + + const char* name() const override { return "Image Load Test FP"; } + + private: + TestFP(sk_sp texture, GrSLMemoryModel mm, GrSLRestrict restrict) + : fImageStorageAccess(std::move(texture), kRead_GrIOType, mm, restrict) { + this->initClassID(); + 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(); + GrGLSLFPFragmentBuilder* fb = args.fFragBuilder; + SkString imageLoadStr; + fb->codeAppendf("highp 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("highp 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)/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 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 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 fData; + } tests[] = { + { + kRGBA_8888_GrPixelConfig, + std::move(data) + }, + { + kRGBA_8888_sint_GrPixelConfig, + std::move(idata) + }, + }; + for (const auto& test : tests) { + // This test should work with any memory model and with or without restrict + for (auto mm : {GrSLMemoryModel::kNone, + GrSLMemoryModel::kCoherent, + GrSLMemoryModel::kVolatile}) { + for (auto restrict : {GrSLRestrict::kNo, GrSLRestrict::kYes}) { + if (!context->caps()->canConfigBeImageStorage(test.fConfig)) { + continue; + } + desc.fConfig = test.fConfig; + sk_sp imageStorageTexture(context->textureProvider()->createTexture(desc, + SkBudgeted::kYes, test.fData.get(), 0)); + + sk_sp rtContext = + context->makeRenderTargetContext(SkBackingFit::kExact, kS, kS, + kRGBA_8888_GrPixelConfig, nullptr); + GrPaint paint; + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + paint.addColorFragmentProcessor(TestFP::Make(imageStorageTexture, mm, restrict)); + rtContext->drawPaint(GrNoClip(), paint, SkMatrix::I()); + std::unique_ptr 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 diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp index 8574399..14390ec 100644 --- a/tools/gpu/GrTest.cpp +++ b/tools/gpu/GrTest.cpp @@ -287,6 +287,8 @@ public: explicit MockCaps(const GrContextOptions& options) : INHERITED(options) {} bool isConfigTexturable(GrPixelConfig config) const override { return false; } bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override { return false; } + bool canConfigBeImageStorage(GrPixelConfig) const override { return false; } + private: typedef GrCaps INHERITED; }; -- 2.7.4