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:
Brian Salomon 2016-11-29 11:59:17 -05:00 committed by Skia Commit-Bot
parent e18c97b73a
commit f9f451213a
48 changed files with 1351 additions and 432 deletions

View File

@ -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",

View File

@ -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; }

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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)) {

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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. */

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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),

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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.

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -237,6 +237,7 @@ GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
programID,
fUniformHandler.fUniforms,
fUniformHandler.fSamplers,
fUniformHandler.fImageStorages,
fVaryingHandler.fPathProcVaryingInfos,
fGeometryProcessor,
fXferProcessor,

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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");

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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) {

View File

@ -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;
};

View File

@ -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;

View File

@ -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.
*/

View File

@ -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,

View File

@ -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;
};
/**

View File

@ -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);
}

View File

@ -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);

View File

@ -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) {

View File

@ -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; }

View File

@ -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;

View File

@ -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()) {

View File

@ -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);
}

View File

@ -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);

View File

@ -96,6 +96,11 @@ struct Token {
UNIFORM,
FLAT,
NOPERSPECTIVE,
READONLY,
WRITEONLY,
COHERENT,
VOLATILE,
RESTRICT,
STRUCT,
LAYOUT,
DIRECTIVE,

View File

@ -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

View File

@ -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
View 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

View File

@ -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;
};