Reland image storage with fixes.
Revert "Revert "Initial OpenGL Image support.""
This reverts commit 59dc41175d
.
BUG=skia:
Change-Id: Ibe3c87ce7f746f065fdbcc5a518388cc291112f5
Reviewed-on: https://skia-review.googlesource.com/5131
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
e18c97b73a
commit
f9f451213a
@ -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",
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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<GrTexture> 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<GrTexture> fTexture;
|
||||
GrShaderFlags fVisibility;
|
||||
GrImageStorageFormat fFormat;
|
||||
GrSLMemoryModel fMemoryModel;
|
||||
GrSLRestrict fRestrict;
|
||||
typedef SkNoncopyable INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)) {
|
||||
|
@ -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<GrTexture> 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;
|
||||
|
@ -15,48 +15,88 @@
|
||||
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
#include "glsl/GrGLSLCaps.h"
|
||||
|
||||
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));
|
||||
enum {
|
||||
kSamplerOrImageTypeKeyBits = 4
|
||||
};
|
||||
|
||||
SkASSERT((int)samplerType >= kFirstSamplerType && (int)samplerType <= kLastSamplerType);
|
||||
int samplerTypeKey = samplerType - kFirstSamplerType;
|
||||
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;
|
||||
|
||||
return SkToU16(caps.configTextureSwizzle(config).asKey() |
|
||||
(samplerTypeKey << 8) |
|
||||
(caps.samplerPrecision(config, visibility) << (8 + kSamplerTypeKeyBits)));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SkASSERT((value & ((1 << kSamplerOrImageTypeKeyBits) - 1)) == value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void add_sampler_keys(GrProcessorKeyBuilder* b, const GrProcessor& proc,
|
||||
const GrGLSLCaps& caps) {
|
||||
static uint16_t sampler_key(GrSLType samplerType, GrPixelConfig config, GrShaderFlags visibility,
|
||||
const GrGLSLCaps& caps) {
|
||||
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 uint16_t storage_image_key(const GrProcessor::ImageStorageAccess& imageAccess) {
|
||||
GrSLType type = imageAccess.texture()->texturePriv().imageStorageType();
|
||||
return image_storage_or_sampler_uniform_type_key(type) |
|
||||
(int)imageAccess.format() << kSamplerOrImageTypeKeyBits;
|
||||
}
|
||||
|
||||
static void add_sampler_and_image_keys(GrProcessorKeyBuilder* b, const GrProcessor& proc,
|
||||
const GrGLSLCaps& caps) {
|
||||
int numTextureSamplers = proc.numTextureSamplers();
|
||||
int numSamplers = numTextureSamplers + proc.numBuffers();
|
||||
// Need two bytes per key (swizzle, sampler type, and precision).
|
||||
int word32Count = (numSamplers + 1) / 2;
|
||||
int numBuffers = proc.numBuffers();
|
||||
int numImageStorages = proc.numImageStorages();
|
||||
int numUniforms = numTextureSamplers + numBuffers + numImageStorages;
|
||||
// Need two bytes per key.
|
||||
int word32Count = (numUniforms + 1) / 2;
|
||||
if (0 == word32Count) {
|
||||
return;
|
||||
}
|
||||
uint16_t* k16 = SkTCast<uint16_t*>(b->add32n(word32Count));
|
||||
int i = 0;
|
||||
for (; i < numTextureSamplers; ++i) {
|
||||
const GrProcessor::TextureSampler& textureSampler = proc.textureSampler(i);
|
||||
const GrTexture* tex = textureSampler.texture();
|
||||
k16[i] = sampler_key(tex->texturePriv().samplerType(), tex->config(),
|
||||
textureSampler.visibility(), caps);
|
||||
int j = 0;
|
||||
for (int i = 0; i < numTextureSamplers; ++i, ++j) {
|
||||
const GrProcessor::TextureSampler& sampler = proc.textureSampler(i);
|
||||
const GrTexture* tex = sampler.texture();
|
||||
k16[j] = sampler_key(tex->texturePriv().samplerType(), tex->config(), sampler.visibility(),
|
||||
caps);
|
||||
}
|
||||
for (; 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 < numBuffers; ++i, ++j) {
|
||||
const GrProcessor::BufferAccess& access = proc.bufferAccess(i);
|
||||
k16[j] = sampler_key(kBufferSampler_GrSLType, access.texelConfig(), access.visibility(),
|
||||
caps);
|
||||
}
|
||||
// zero the last 16 bits if the number of samplers is odd.
|
||||
if (numSamplers & 0x1) {
|
||||
k16[numSamplers] = 0;
|
||||
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 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);
|
||||
|
@ -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();
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -62,6 +62,8 @@ public:
|
||||
|
||||
void bindTexelBuffer(int unitIdx, GrPixelConfig, GrGLBuffer*);
|
||||
|
||||
void bindImageStorage(int unitIdx, GrIOType, GrGLTexture *);
|
||||
|
||||
void generateMipmaps(const GrSamplerParams& params, bool allowSRGBInputs, GrGLTexture* texture);
|
||||
|
||||
bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes,
|
||||
@ -569,6 +571,12 @@ private:
|
||||
TriState fHWSRGBFramebuffer;
|
||||
SkTArray<GrGpuResource::UniqueID, true> fHWBoundTextureUniqueIDs;
|
||||
|
||||
struct Image {
|
||||
GrGpuResource::UniqueID fTextureUniqueID;
|
||||
GrIOType fIOType;
|
||||
};
|
||||
SkTArray<Image, true> fHWBoundImageStorages;
|
||||
|
||||
struct BufferTexture {
|
||||
BufferTexture() : fTextureID(0), fKnownBound(false),
|
||||
fAttachedBufferUniqueID(SK_InvalidUniqueID),
|
||||
|
@ -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<GrGLBuffer*>(access.buffer()));
|
||||
}
|
||||
for (int i = 0; i < processor.numImageStorages(); ++i) {
|
||||
const GrProcessor::ImageStorageAccess& access = processor.imageStorageAccess(i);
|
||||
fGpu->bindImageStorage((*nextSamplerIdx)++, access.ioType(),
|
||||
static_cast<GrGLTexture *>(access.texture()));
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLProgram::generateMipmaps(const GrProcessor& processor,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<GrSwizzle> fSamplerSwizzles;
|
||||
UniformInfoArray fImageStorages;
|
||||
|
||||
friend class GrGLProgramBuilder;
|
||||
|
||||
|
@ -237,6 +237,7 @@ GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
|
||||
programID,
|
||||
fUniformHandler.fUniforms,
|
||||
fUniformHandler.fSamplers,
|
||||
fUniformHandler.fImageStorages,
|
||||
fVaryingHandler.fPathProcVaryingInfos,
|
||||
fGeometryProcessor,
|
||||
fXferProcessor,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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");
|
||||
|
@ -11,13 +11,13 @@
|
||||
#include "GrFragmentProcessor.h"
|
||||
#include "GrShaderVar.h"
|
||||
#include "glsl/GrGLSLProgramDataManager.h"
|
||||
#include "glsl/GrGLSLUniformHandler.h"
|
||||
|
||||
class GrProcessor;
|
||||
class GrProcessorKeyBuilder;
|
||||
class GrGLSLCaps;
|
||||
class GrGLSLFPBuilder;
|
||||
class GrGLSLFPFragmentBuilder;
|
||||
class GrGLSLUniformHandler;
|
||||
|
||||
class GrGLSLFragmentProcessor {
|
||||
public:
|
||||
@ -29,8 +29,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
|
||||
typedef GrGLSLProgramDataManager::UniformHandle SamplerHandle;
|
||||
using UniformHandle = GrGLSLUniformHandler::UniformHandle;
|
||||
using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
|
||||
using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle;
|
||||
|
||||
private:
|
||||
/**
|
||||
@ -74,6 +75,8 @@ public:
|
||||
&GrProcessor::numTextureSamplers>;
|
||||
using BufferSamplers = BuilderInputProvider<SamplerHandle, GrProcessor,
|
||||
&GrProcessor::numBuffers>;
|
||||
using ImageStorages = BuilderInputProvider<ImageStorageHandle, GrProcessor,
|
||||
&GrProcessor::numImageStorages>;
|
||||
|
||||
/** Called when the program stage should insert its code into the shaders. The code in each
|
||||
shader will be in its own block ({}) and so locally scoped names will not collide across
|
||||
@ -99,6 +102,12 @@ public:
|
||||
@param bufferSamplers Contains one entry for each BufferAccess of the GrProcessor. These
|
||||
can be passed to the builder to emit buffer reads in the generated
|
||||
code.
|
||||
@param imageStorages Contains one entry for each ImageStorageAccess of the GrProcessor.
|
||||
These can be passed to the builder to emit image loads and stores
|
||||
in the generated code.
|
||||
@param gpImplementsDistanceVector
|
||||
Does the GrGeometryProcessor implement the feature where it
|
||||
provides a vector to the nearest edge of the shape being rendered.
|
||||
*/
|
||||
struct EmitArgs {
|
||||
EmitArgs(GrGLSLFPFragmentBuilder* fragBuilder,
|
||||
@ -110,6 +119,7 @@ public:
|
||||
const TransformedCoordVars& transformedCoordVars,
|
||||
const TextureSamplers& textureSamplers,
|
||||
const BufferSamplers& bufferSamplers,
|
||||
const ImageStorages& imageStorages,
|
||||
bool gpImplementsDistanceVector)
|
||||
: fFragBuilder(fragBuilder)
|
||||
, fUniformHandler(uniformHandler)
|
||||
@ -120,6 +130,7 @@ public:
|
||||
, fTransformedCoords(transformedCoordVars)
|
||||
, fTexSamplers(textureSamplers)
|
||||
, fBufferSamplers(bufferSamplers)
|
||||
, fImageStorages(imageStorages)
|
||||
, fGpImplementsDistanceVector(gpImplementsDistanceVector) {}
|
||||
GrGLSLFPFragmentBuilder* fFragBuilder;
|
||||
GrGLSLUniformHandler* fUniformHandler;
|
||||
@ -130,6 +141,7 @@ public:
|
||||
const TransformedCoordVars& fTransformedCoords;
|
||||
const TextureSamplers& fTexSamplers;
|
||||
const BufferSamplers& fBufferSamplers;
|
||||
const ImageStorages& fImageStorages;
|
||||
bool fGpImplementsDistanceVector;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -31,7 +31,10 @@ GrGLSLProgramBuilder::GrGLSLProgramBuilder(const GrPipeline& pipeline,
|
||||
, fXferProcessor(nullptr)
|
||||
, fNumVertexSamplers(0)
|
||||
, fNumGeometrySamplers(0)
|
||||
, fNumFragmentSamplers(0) {
|
||||
, fNumFragmentSamplers(0)
|
||||
, fNumVertexImageStorages(0)
|
||||
, fNumGeometryImageStorages(0)
|
||||
, fNumFragmentImageStorages(0) {
|
||||
}
|
||||
|
||||
void GrGLSLProgramBuilder::addFeature(GrShaderFlags shaders,
|
||||
@ -66,7 +69,7 @@ bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor,
|
||||
this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
|
||||
}
|
||||
|
||||
return this->checkSamplerCounts();
|
||||
return this->checkSamplerCounts() && this->checkImageStorageCounts();
|
||||
}
|
||||
|
||||
void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc,
|
||||
@ -97,9 +100,10 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr
|
||||
SkASSERT(!fGeometryProcessor);
|
||||
fGeometryProcessor = proc.createGLSLInstance(*this->glslCaps());
|
||||
|
||||
SkSTArray<4, SamplerHandle> texSamplers(proc.numTextureSamplers());
|
||||
SkSTArray<2, SamplerHandle> bufferSamplers(proc.numBuffers());
|
||||
this->emitSamplers(proc, &texSamplers, &bufferSamplers);
|
||||
SkSTArray<4, SamplerHandle> texSamplers(proc.numTextureSamplers());
|
||||
SkSTArray<2, SamplerHandle> bufferSamplers(proc.numBuffers());
|
||||
SkSTArray<2, ImageStorageHandle> imageStorages(proc.numImageStorages());
|
||||
this->emitSamplersAndImageStorages(proc, &texSamplers, &bufferSamplers, &imageStorages);
|
||||
|
||||
GrGLSLPrimitiveProcessor::FPCoordTransformHandler transformHandler(fPipeline,
|
||||
&fTransformedCoordVars);
|
||||
@ -115,6 +119,7 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr
|
||||
distanceVectorName,
|
||||
texSamplers.begin(),
|
||||
bufferSamplers.begin(),
|
||||
imageStorages.begin(),
|
||||
&transformHandler);
|
||||
fGeometryProcessor->emitCode(args);
|
||||
|
||||
@ -163,15 +168,18 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
|
||||
|
||||
SkSTArray<4, SamplerHandle> textureSamplerArray(fp.numTextureSamplers());
|
||||
SkSTArray<2, SamplerHandle> bufferSamplerArray(fp.numBuffers());
|
||||
SkSTArray<2, ImageStorageHandle> imageStorageArray(fp.numImageStorages());
|
||||
GrFragmentProcessor::Iter iter(&fp);
|
||||
while (const GrFragmentProcessor* subFP = iter.next()) {
|
||||
this->emitSamplers(*subFP, &textureSamplerArray, &bufferSamplerArray);
|
||||
this->emitSamplersAndImageStorages(*subFP, &textureSamplerArray, &bufferSamplerArray,
|
||||
&imageStorageArray);
|
||||
}
|
||||
|
||||
const GrShaderVar* coordVars = fTransformedCoordVars.begin() + transformedCoordVarsIdx;
|
||||
GrGLSLFragmentProcessor::TransformedCoordVars coords(&fp, coordVars);
|
||||
GrGLSLFragmentProcessor::TextureSamplers textureSamplers(&fp, textureSamplerArray.begin());
|
||||
GrGLSLFragmentProcessor::BufferSamplers bufferSamplers(&fp, bufferSamplerArray.begin());
|
||||
GrGLSLFragmentProcessor::ImageStorages imageStorages(&fp, imageStorageArray.begin());
|
||||
GrGLSLFragmentProcessor::EmitArgs args(&fFS,
|
||||
this->uniformHandler(),
|
||||
this->glslCaps(),
|
||||
@ -181,6 +189,7 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
|
||||
coords,
|
||||
textureSamplers,
|
||||
bufferSamplers,
|
||||
imageStorages,
|
||||
this->primitiveProcessor().implementsDistanceVector());
|
||||
|
||||
fragProc->emitCode(args);
|
||||
@ -217,9 +226,10 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
|
||||
openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
|
||||
fFS.codeAppend(openBrace.c_str());
|
||||
|
||||
SkSTArray<4, SamplerHandle> texSamplers(xp.numTextureSamplers());
|
||||
SkSTArray<2, SamplerHandle> bufferSamplers(xp.numBuffers());
|
||||
this->emitSamplers(xp, &texSamplers, &bufferSamplers);
|
||||
SkSTArray<4, SamplerHandle> texSamplers(xp.numTextureSamplers());
|
||||
SkSTArray<2, SamplerHandle> bufferSamplers(xp.numBuffers());
|
||||
SkSTArray<2, ImageStorageHandle> imageStorageArray(xp.numImageStorages());
|
||||
this->emitSamplersAndImageStorages(xp, &texSamplers, &bufferSamplers, &imageStorageArray);
|
||||
|
||||
bool usePLSDstRead = (plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState);
|
||||
GrGLSLXferProcessor::EmitArgs args(&fFS,
|
||||
@ -231,6 +241,7 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
|
||||
fFS.getSecondaryColorOutputName(),
|
||||
texSamplers.begin(),
|
||||
bufferSamplers.begin(),
|
||||
imageStorageArray.begin(),
|
||||
usePLSDstRead);
|
||||
fXferProcessor->emitCode(args);
|
||||
|
||||
@ -240,13 +251,16 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
|
||||
fFS.codeAppend("}");
|
||||
}
|
||||
|
||||
void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor,
|
||||
SkTArray<SamplerHandle>* outTexSamplers,
|
||||
SkTArray<SamplerHandle>* outBufferSamplers) {
|
||||
void GrGLSLProgramBuilder::emitSamplersAndImageStorages(
|
||||
const GrProcessor& processor,
|
||||
SkTArray<SamplerHandle>* outTexSamplerHandles,
|
||||
SkTArray<SamplerHandle>* outBufferSamplerHandles,
|
||||
SkTArray<ImageStorageHandle>* outImageStorageHandles) {
|
||||
SkString name;
|
||||
int numTextureSamplers = processor.numTextureSamplers();
|
||||
for (int t = 0; t < numTextureSamplers; ++t) {
|
||||
const GrProcessor::TextureSampler& sampler = processor.textureSampler(t);
|
||||
name.printf("TextureSampler_%d", outTexSamplerHandles->count());
|
||||
GrSLType samplerType = sampler.texture()->texturePriv().samplerType();
|
||||
if (kTextureExternalSampler_GrSLType == samplerType) {
|
||||
const char* externalFeatureString = this->glslCaps()->externalTextureExtensionString();
|
||||
@ -256,9 +270,9 @@ void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor,
|
||||
1 << GrGLSLShaderBuilder::kExternalTexture_GLSLPrivateFeature,
|
||||
externalFeatureString);
|
||||
}
|
||||
name.printf("TextureSampler_%d", outTexSamplers->count());
|
||||
this->emitSampler(samplerType, sampler.texture()->config(),
|
||||
name.c_str(), sampler.visibility(), outTexSamplers);
|
||||
this->emitSampler(samplerType, sampler.texture()->config(), name.c_str(),
|
||||
sampler.visibility(), outTexSamplerHandles);
|
||||
|
||||
}
|
||||
|
||||
if (int numBuffers = processor.numBuffers()) {
|
||||
@ -267,9 +281,9 @@ void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor,
|
||||
|
||||
for (int b = 0; b < numBuffers; ++b) {
|
||||
const GrProcessor::BufferAccess& access = processor.bufferAccess(b);
|
||||
name.printf("BufferSampler_%d", outBufferSamplers->count());
|
||||
name.printf("BufferSampler_%d", outBufferSamplerHandles->count());
|
||||
this->emitSampler(kBufferSampler_GrSLType, access.texelConfig(), name.c_str(),
|
||||
access.visibility(), outBufferSamplers);
|
||||
access.visibility(), outBufferSamplerHandles);
|
||||
texelBufferVisibility |= access.visibility();
|
||||
}
|
||||
|
||||
@ -279,13 +293,19 @@ void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor,
|
||||
extension);
|
||||
}
|
||||
}
|
||||
int numImageStorages = processor.numImageStorages();
|
||||
for (int i = 0; i < numImageStorages; ++i) {
|
||||
const GrProcessor::ImageStorageAccess& imageStorageAccess = processor.imageStorageAccess(i);
|
||||
name.printf("Image_%d", outImageStorageHandles->count());
|
||||
this->emitImageStorage(imageStorageAccess, name.c_str(), outImageStorageHandles);
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLSLProgramBuilder::emitSampler(GrSLType samplerType,
|
||||
GrPixelConfig config,
|
||||
const char* name,
|
||||
GrShaderFlags visibility,
|
||||
SkTArray<SamplerHandle>* outSamplers) {
|
||||
SkTArray<SamplerHandle>* outSamplerHandles) {
|
||||
if (visibility & kVertex_GrShaderFlag) {
|
||||
++fNumVertexSamplers;
|
||||
}
|
||||
@ -298,12 +318,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<ImageStorageHandle>* outImageStorageHandles) {
|
||||
if (access.visibility() & kVertex_GrShaderFlag) {
|
||||
++fNumVertexImageStorages;
|
||||
}
|
||||
if (access.visibility() & kGeometry_GrShaderFlag) {
|
||||
SkASSERT(this->primitiveProcessor().willUseGeoShader());
|
||||
++fNumGeometryImageStorages;
|
||||
}
|
||||
if (access.visibility() & kFragment_GrShaderFlag) {
|
||||
++fNumFragmentImageStorages;
|
||||
}
|
||||
GrSLType uniformType = access.texture()->texturePriv().imageStorageType();
|
||||
ImageStorageHandle handle = this->uniformHandler()->addImageStorage(access.visibility(),
|
||||
uniformType, access.format(), 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) {
|
||||
|
@ -28,7 +28,9 @@ typedef SkSTArray<8, GrGLSLFragmentProcessor*, true> GrGLSLFragProcs;
|
||||
|
||||
class GrGLSLProgramBuilder {
|
||||
public:
|
||||
typedef GrGLSLUniformHandler::UniformHandle UniformHandle;
|
||||
using UniformHandle = GrGLSLUniformHandler::UniformHandle;
|
||||
using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
|
||||
using ImageStorageHandle = GrGLSLUniformHandler::ImageStorageHandle;
|
||||
|
||||
virtual ~GrGLSLProgramBuilder() {}
|
||||
|
||||
@ -42,8 +44,6 @@ public:
|
||||
|
||||
void appendUniformDecls(GrShaderFlags visibility, SkString*) const;
|
||||
|
||||
typedef GrGLSLUniformHandler::SamplerHandle SamplerHandle;
|
||||
|
||||
const GrShaderVar& samplerVariable(SamplerHandle handle) const {
|
||||
return this->uniformHandler()->samplerVariable(handle);
|
||||
}
|
||||
@ -52,6 +52,10 @@ public:
|
||||
return this->uniformHandler()->samplerSwizzle(handle);
|
||||
}
|
||||
|
||||
const GrShaderVar& imageStorageVariable(ImageStorageHandle handle) const {
|
||||
return this->uniformHandler()->imageStorageVariable(handle);
|
||||
}
|
||||
|
||||
// Handles for program uniforms (other than per-effect uniforms)
|
||||
struct BuiltinUniformHandles {
|
||||
UniformHandle fRTAdjustmentUni;
|
||||
@ -156,17 +160,18 @@ private:
|
||||
const GrGLSLExpr4& coverageIn,
|
||||
bool ignoresCoverage,
|
||||
GrPixelLocalStorageState plsState);
|
||||
|
||||
void emitSamplers(const GrProcessor& processor,
|
||||
SkTArray<SamplerHandle>* outTexSamplers,
|
||||
SkTArray<SamplerHandle>* outBufferSamplers);
|
||||
void emitSampler(GrSLType samplerType,
|
||||
GrPixelConfig,
|
||||
const char* name,
|
||||
GrShaderFlags visibility,
|
||||
SkTArray<SamplerHandle>* outSamplers);
|
||||
void emitSamplersAndImageStorages(const GrProcessor& processor,
|
||||
SkTArray<SamplerHandle>* outTexSamplerHandles,
|
||||
SkTArray<SamplerHandle>* outBufferSamplerHandles,
|
||||
SkTArray<ImageStorageHandle>* outImageStorageHandles);
|
||||
void emitSampler(GrSLType samplerType, GrPixelConfig, const char* name,
|
||||
GrShaderFlags visibility, SkTArray<SamplerHandle >* outSamplerHandles);
|
||||
void emitImageStorage(const GrProcessor::ImageStorageAccess&,
|
||||
const char* name,
|
||||
SkTArray<ImageStorageHandle>* outImageStorageHandles);
|
||||
void emitFSOutputSwizzle(bool hasSecondaryOutput);
|
||||
bool checkSamplerCounts();
|
||||
bool checkImageStorageCounts();
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
void verify(const GrPrimitiveProcessor&);
|
||||
@ -177,6 +182,9 @@ private:
|
||||
int fNumVertexSamplers;
|
||||
int fNumGeometrySamplers;
|
||||
int fNumFragmentSamplers;
|
||||
int fNumVertexImageStorages;
|
||||
int fNumGeometryImageStorages;
|
||||
int fNumFragmentImageStorages;
|
||||
SkSTArray<4, GrShaderVar> fTransformedCoordVars;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
};
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -174,6 +174,8 @@ void GrVkPipelineState::abandonGPUResources() {
|
||||
|
||||
static void append_texture_bindings(const GrProcessor& processor,
|
||||
SkTArray<const GrProcessor::TextureSampler*>* textureBindings) {
|
||||
// We don't support image storages in VK.
|
||||
SkASSERT(!processor.numImageStorages());
|
||||
if (int numTextureSamplers = processor.numTextureSamplers()) {
|
||||
const GrProcessor::TextureSampler** bindings =
|
||||
textureBindings->push_back_n(numTextureSamplers);
|
||||
|
@ -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) {
|
||||
|
@ -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; }
|
||||
|
@ -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;
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -96,6 +96,11 @@ struct Token {
|
||||
UNIFORM,
|
||||
FLAT,
|
||||
NOPERSPECTIVE,
|
||||
READONLY,
|
||||
WRITEONLY,
|
||||
COHERENT,
|
||||
VOLATILE,
|
||||
RESTRICT,
|
||||
STRUCT,
|
||||
LAYOUT,
|
||||
DIRECTIVE,
|
||||
|
@ -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 ";
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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; }
|
||||
|
163
tests/ImageStorageTest.cpp
Normal file
163
tests/ImageStorageTest.cpp
Normal file
@ -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<GrFragmentProcessor> Make(sk_sp<GrTexture> texture, GrSLMemoryModel mm,
|
||||
GrSLRestrict restrict) {
|
||||
return sk_sp<GrFragmentProcessor>(new TestFP(std::move(texture), mm, restrict));
|
||||
}
|
||||
|
||||
const char* name() const override { return "Image Load Test FP"; }
|
||||
|
||||
private:
|
||||
TestFP(sk_sp<GrTexture> texture, GrSLMemoryModel mm, GrSLRestrict restrict)
|
||||
: fImageStorageAccess(std::move(texture), kRead_GrIOType, mm, restrict) {
|
||||
this->initClassID<TestFP>();
|
||||
this->setWillReadFragmentPosition();
|
||||
this->addImageStorageAccess(&fImageStorageAccess);
|
||||
}
|
||||
|
||||
void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override {}
|
||||
|
||||
void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
|
||||
inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput);
|
||||
}
|
||||
|
||||
bool onIsEqual(const GrFragmentProcessor& that) const override { return true; }
|
||||
|
||||
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
|
||||
class GLSLProcessor : public GrGLSLFragmentProcessor {
|
||||
public:
|
||||
GLSLProcessor() = default;
|
||||
void emitCode(EmitArgs& args) override {
|
||||
const TestFP& tfp = args.fFp.cast<TestFP>();
|
||||
GrGLSLFPFragmentBuilder* fb = args.fFragBuilder;
|
||||
SkString imageLoadStr;
|
||||
fb->codeAppendf("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<uint32_t[]> data(new uint32_t[kS * kS]);
|
||||
for (int j = 0; j < kS; ++j) {
|
||||
for (int i = 0; i < kS; ++i) {
|
||||
data[i + kS * j] = GrColorPackRGBA(i, j, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<uint32_t[]> idata(new uint32_t[kS * kS]);
|
||||
for (int j = 0; j < kS; ++j) {
|
||||
for (int i = 0; i < kS; ++i) {
|
||||
int8_t r = i - 128;
|
||||
int8_t g = j - 128;
|
||||
int8_t b = -128;
|
||||
int8_t a = -128;
|
||||
idata[i + kS * j] = ((uint8_t)a << 24) | ((uint8_t)b << 16) |
|
||||
((uint8_t)g << 8) | (uint8_t)r;
|
||||
}
|
||||
}
|
||||
|
||||
// Currently image accesses always have "top left" semantics.
|
||||
GrSurfaceDesc desc;
|
||||
desc.fOrigin = kTopLeft_GrSurfaceOrigin;
|
||||
desc.fWidth = kS;
|
||||
desc.fHeight = kS;
|
||||
struct {
|
||||
GrPixelConfig fConfig;
|
||||
std::unique_ptr<uint32_t[]> fData;
|
||||
} tests[] = {
|
||||
{
|
||||
kRGBA_8888_GrPixelConfig,
|
||||
std::move(data)
|
||||
},
|
||||
{
|
||||
kRGBA_8888_sint_GrPixelConfig,
|
||||
std::move(idata)
|
||||
},
|
||||
};
|
||||
for (const auto& test : tests) {
|
||||
// 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<GrTexture> imageStorageTexture(context->textureProvider()->createTexture(desc,
|
||||
SkBudgeted::kYes, test.fData.get(), 0));
|
||||
|
||||
sk_sp<GrRenderTargetContext> rtContext =
|
||||
context->makeRenderTargetContext(SkBackingFit::kExact, kS, kS,
|
||||
kRGBA_8888_GrPixelConfig, nullptr);
|
||||
GrPaint paint;
|
||||
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
|
||||
paint.addColorFragmentProcessor(TestFP::Make(imageStorageTexture, mm, restrict));
|
||||
rtContext->drawPaint(GrNoClip(), paint, SkMatrix::I());
|
||||
std::unique_ptr<uint32_t[]> readData(new uint32_t[kS * kS]);
|
||||
SkImageInfo info = SkImageInfo::Make(kS, kS, kRGBA_8888_SkColorType,
|
||||
kPremul_SkAlphaType);
|
||||
rtContext->readPixels(info, readData.get(), 0, 0, 0);
|
||||
int failed = false;
|
||||
for (int j = 0; j < kS && !failed; ++j) {
|
||||
for (int i = 0; i < kS && !failed; ++i) {
|
||||
uint32_t d = test.fData[j * kS + i];
|
||||
uint32_t rd = readData[j * kS + i];
|
||||
if (d != rd) {
|
||||
failed = true;
|
||||
ERRORF(reporter, "Expected 0x%08x, got 0x%08x at %d, %d.", d, rd, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user