Create swizzle table inside of glsl caps

BUG=skia:

Committed: https://skia.googlesource.com/skia/+/4036674952f341dab0695c3b054fefa5bb8cdec1

Review URL: https://codereview.chromium.org/1420033005
This commit is contained in:
egdaniel 2015-11-04 04:23:53 -08:00 committed by Commit bot
parent df85a72547
commit b7e7d5748d
13 changed files with 162 additions and 105 deletions

View File

@ -100,6 +100,7 @@ protected:
PrecisionInfo fFloatPrecisions[kGrShaderTypeCount][kGrSLPrecisionCount];
private:
virtual void onApplyOptionsOverrides(const GrContextOptions&) {};
typedef SkRefCnt INHERITED;
};
@ -274,6 +275,8 @@ protected:
bool fConfigTextureSupport[kGrPixelConfigCnt];
private:
virtual void onApplyOptionsOverrides(const GrContextOptions&) {};
bool fSupressPrints : 1;
bool fDrawPathMasksToCompressedTextureSupport : 1;

View File

@ -19,7 +19,8 @@ struct GrContextOptions {
, fSuppressDualSourceBlending(false)
, fGeometryBufferMapThreshold(-1)
, fUseDrawInsteadOfPartialRenderTargetWrite(false)
, fImmediateMode(false) {}
, fImmediateMode(false)
, fUseShaderSwizzling(false) {}
// EXPERIMENTAL
// May be removed in the future, or may become standard depending
@ -50,6 +51,10 @@ struct GrContextOptions {
/** The GrContext operates in immedidate mode. It will issue all draws to the backend API
immediately. Intended to ease debugging. */
bool fImmediateMode;
/** Force us to do all swizzling manually in the shader and don't rely on extensions to do
swizzling. */
bool fUseShaderSwizzling;
};
#endif

View File

@ -77,6 +77,7 @@ SkString GrShaderCaps::dump() const {
void GrShaderCaps::applyOptionsOverrides(const GrContextOptions& options) {
fDualSourceBlendingSupport = fDualSourceBlendingSupport && !options.fSuppressDualSourceBlending;
this->onApplyOptionsOverrides(options);
}
///////////////////////////////////////////////////////////////////////////////
@ -127,6 +128,7 @@ void GrCaps::applyOptionsOverrides(const GrContextOptions& options) {
} else {
fMaxTileSize = options.fMaxTileSizeOverride;
}
this->onApplyOptionsOverrides(options);
}
static SkString map_flags_to_string(uint32_t flags) {

View File

@ -8,6 +8,7 @@
#include "GrGLCaps.h"
#include "GrContextOptions.h"
#include "GrGLContext.h"
#include "glsl/GrGLSLCaps.h"
#include "SkTSearch.h"
@ -27,7 +28,6 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
fMaxFragmentTextureUnits = 0;
fRGBA8RenderbufferSupport = false;
fBGRAIsInternalFormat = false;
fTextureSwizzleSupport = false;
fUnpackRowLengthSupport = false;
fUnpackFlipYSupport = false;
fPackRowLengthSupport = false;
@ -93,13 +93,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
ctxInfo.hasExtension("GL_ARM_rgba8");
}
if (kGL_GrGLStandard == standard) {
fTextureSwizzleSupport = version >= GR_GL_VER(3,3) ||
ctxInfo.hasExtension("GL_ARB_texture_swizzle");
} else {
fTextureSwizzleSupport = version >= GR_GL_VER(3,0);
}
if (kGL_GrGLStandard == standard) {
fUnpackRowLengthSupport = true;
fUnpackFlipYSupport = false;
@ -499,6 +492,8 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
this->initConfigTexturableTable(ctxInfo, gli, srgbSupport);
this->initConfigRenderableTable(ctxInfo, srgbSupport);
this->initShaderPrecisionTable(ctxInfo, gli, glslCaps);
// Requires fTexutreSwizzleSupport and fTextureRedSupport to be set before this point.
this->initConfigSwizzleTable(ctxInfo, glslCaps);
this->applyOptionsOverrides(contextOptions);
glslCaps->applyOptionsOverrides(contextOptions);
@ -1177,7 +1172,6 @@ SkString GrGLCaps::dump() const {
r.appendf("Max Vertex Attributes: %d\n", fMaxVertexAttributes);
r.appendf("Support RGBA8 Render Buffer: %s\n", (fRGBA8RenderbufferSupport ? "YES": "NO"));
r.appendf("BGRA is an internal format: %s\n", (fBGRAIsInternalFormat ? "YES": "NO"));
r.appendf("Support texture swizzle: %s\n", (fTextureSwizzleSupport ? "YES": "NO"));
r.appendf("Unpack Row length support: %s\n", (fUnpackRowLengthSupport ? "YES": "NO"));
r.appendf("Unpack Flip Y support: %s\n", (fUnpackFlipYSupport ? "YES": "NO"));
r.appendf("Pack Row length support: %s\n", (fPackRowLengthSupport ? "YES": "NO"));
@ -1288,6 +1282,44 @@ void GrGLCaps::initShaderPrecisionTable(const GrGLContextInfo& ctxInfo,
}
}
void GrGLCaps::initConfigSwizzleTable(const GrGLContextInfo& ctxInfo, GrGLSLCaps* glslCaps) {
GrGLStandard standard = ctxInfo.standard();
GrGLVersion version = ctxInfo.version();
glslCaps->fMustSwizzleInShader = true;
if (kGL_GrGLStandard == standard) {
if (version >= GR_GL_VER(3,3) || ctxInfo.hasExtension("GL_ARB_texture_swizzle")) {
glslCaps->fMustSwizzleInShader = false;
}
} else {
if (version >= GR_GL_VER(3,0)) {
glslCaps->fMustSwizzleInShader = false;
}
}
glslCaps->fConfigSwizzle[kUnknown_GrPixelConfig] = nullptr;
if (fTextureRedSupport) {
glslCaps->fConfigSwizzle[kAlpha_8_GrPixelConfig] = "rrrr";
glslCaps->fConfigSwizzle[kAlpha_half_GrPixelConfig] = "rrrr";
} else {
glslCaps->fConfigSwizzle[kAlpha_8_GrPixelConfig] = "aaaa";
glslCaps->fConfigSwizzle[kAlpha_half_GrPixelConfig] = "aaaa";
}
glslCaps->fConfigSwizzle[kIndex_8_GrPixelConfig] = "rgba";
glslCaps->fConfigSwizzle[kRGB_565_GrPixelConfig] = "rgba";
glslCaps->fConfigSwizzle[kRGBA_4444_GrPixelConfig] = "rgba";
glslCaps->fConfigSwizzle[kRGBA_8888_GrPixelConfig] = "rgba";
glslCaps->fConfigSwizzle[kBGRA_8888_GrPixelConfig] = "rgba";
glslCaps->fConfigSwizzle[kSRGBA_8888_GrPixelConfig] = "rgba";
glslCaps->fConfigSwizzle[kETC1_GrPixelConfig] = "rgba";
glslCaps->fConfigSwizzle[kLATC_GrPixelConfig] = "rrrr";
glslCaps->fConfigSwizzle[kR11_EAC_GrPixelConfig] = "rrrr";
glslCaps->fConfigSwizzle[kASTC_12x12_GrPixelConfig] = "rgba";
glslCaps->fConfigSwizzle[kRGBA_float_GrPixelConfig] = "rgba";
glslCaps->fConfigSwizzle[kRGBA_half_GrPixelConfig] = "rgba";
}
void GrGLCaps::onApplyOptionsOverrides(const GrContextOptions& options) {}

View File

@ -171,9 +171,6 @@ public:
*/
bool bgraIsInternalFormat() const { return fBGRAIsInternalFormat; }
/// GL_ARB_texture_swizzle support
bool textureSwizzleSupport() const { return fTextureSwizzleSupport; }
/// Is there support for GL_UNPACK_ROW_LENGTH
bool unpackRowLengthSupport() const { return fUnpackRowLengthSupport; }
@ -273,6 +270,8 @@ private:
void initGLSL(const GrGLContextInfo&);
bool hasPathRenderingSupport(const GrGLContextInfo&, const GrGLInterface*);
void onApplyOptionsOverrides(const GrContextOptions& options) override;
/**
* Maintains a bit per GrPixelConfig. It is used to avoid redundantly
* performing glCheckFrameBufferStatus for the same config.
@ -323,6 +322,8 @@ private:
const GrGLInterface* intf,
GrGLSLCaps* glslCaps);
void initConfigSwizzleTable(const GrGLContextInfo& ctxInfo, GrGLSLCaps* glslCaps);
// tracks configs that have been verified to pass the FBO completeness when
// used as a color attachment
VerifiedColorConfigs fVerifiedColorConfigs;
@ -340,7 +341,6 @@ private:
bool fRGBA8RenderbufferSupport : 1;
bool fBGRAIsInternalFormat : 1;
bool fTextureSwizzleSupport : 1;
bool fUnpackRowLengthSupport : 1;
bool fUnpackFlipYSupport : 1;
bool fPackRowLengthSupport : 1;

View File

@ -2404,19 +2404,30 @@ static inline GrGLenum tile_to_gl_wrap(SkShader::TileMode tm) {
return gWrapModes[tm];
}
const GrGLenum* GrGLGpu::GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps) {
if (caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(config)) {
if (caps.textureRedSupport()) {
static const GrGLenum gRedSmear[] = { GR_GL_RED, GR_GL_RED, GR_GL_RED, GR_GL_RED };
return gRedSmear;
} else {
static const GrGLenum gAlphaSmear[] = { GR_GL_ALPHA, GR_GL_ALPHA,
GR_GL_ALPHA, GR_GL_ALPHA };
return gAlphaSmear;
}
} else {
static const GrGLenum gStraight[] = { GR_GL_RED, GR_GL_GREEN, GR_GL_BLUE, GR_GL_ALPHA };
return gStraight;
static GrGLenum get_component_enum_from_char(char component) {
switch (component) {
case 'r':
return GR_GL_RED;
case 'g':
return GR_GL_GREEN;
case 'b':
return GR_GL_BLUE;
case 'a':
return GR_GL_ALPHA;
default:
SkFAIL("Unsupported component");
return 0;
}
}
/** If texture swizzling is available using tex parameters then it is preferred over mangling
the generated shader code. This potentially allows greater reuse of cached shaders. */
static void get_tex_param_swizzle(GrPixelConfig config,
const GrGLSLCaps& caps,
GrGLenum* glSwizzle) {
const char* swizzle = caps.getSwizzleMap(config);
for (int i = 0; i < 4; ++i) {
glSwizzle[i] = get_component_enum_from_char(swizzle[i]);
}
}
@ -2485,9 +2496,7 @@ void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, GrGLTextur
newTexParams.fWrapS = tile_to_gl_wrap(params.getTileModeX());
newTexParams.fWrapT = tile_to_gl_wrap(params.getTileModeY());
memcpy(newTexParams.fSwizzleRGBA,
GetTexParamSwizzle(texture->config(), this->glCaps()),
sizeof(newTexParams.fSwizzleRGBA));
get_tex_param_swizzle(texture->config(), *this->glCaps().glslCaps(), newTexParams.fSwizzleRGBA);
if (setAll || newTexParams.fMagFilter != oldTexParams.fMagFilter) {
this->setTextureUnit(unitIdx);
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAG_FILTER, newTexParams.fMagFilter));
@ -2504,7 +2513,7 @@ void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, GrGLTextur
this->setTextureUnit(unitIdx);
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_T, newTexParams.fWrapT));
}
if (this->glCaps().textureSwizzleSupport() &&
if (!this->glCaps().glslCaps()->mustSwizzleInShader() &&
(setAll || memcmp(newTexParams.fSwizzleRGBA,
oldTexParams.fSwizzleRGBA,
sizeof(newTexParams.fSwizzleRGBA)))) {

View File

@ -128,11 +128,6 @@ public:
bool isTestingOnlyBackendTexture(GrBackendObject id) const override;
void deleteTestingOnlyBackendTexture(GrBackendObject id) const override;
/** If texture swizzling is available using tex parameters then it is preferred over mangling
the generated shader code. This potentially allows greater reuse of cached shaders. */
static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
private:
GrGLGpu(GrGLContext* ctx, GrContext* context);

View File

@ -18,26 +18,14 @@
* present in the texture's config. swizzleComponentMask indicates the channels present in the
* shader swizzle.
*/
static bool swizzle_requires_alpha_remapping(const GrGLCaps& caps,
uint32_t configComponentMask,
uint32_t swizzleComponentMask) {
if (caps.textureSwizzleSupport()) {
static bool swizzle_requires_alpha_remapping(const GrGLSLCaps& caps, GrPixelConfig config) {
if (!caps.mustSwizzleInShader()) {
// Any remapping is handled using texture swizzling not shader modifications.
return false;
}
// check if the texture is alpha-only
if (kA_GrColorComponentFlag == configComponentMask) {
if (caps.textureRedSupport() && (kA_GrColorComponentFlag & swizzleComponentMask)) {
// we must map the swizzle 'a's to 'r'.
return true;
}
if (kRGB_GrColorComponentFlags & swizzleComponentMask) {
// The 'r', 'g', and/or 'b's must be mapped to 'a' according to our semantics that
// alpha-only textures smear alpha across all four channels when read.
return true;
}
}
return false;
const char* swizzleMap = caps.getSwizzleMap(config);
return SkToBool(memcmp(swizzleMap, "rgba", 4));
}
static uint32_t gen_texture_key(const GrProcessor& proc, const GrGLCaps& caps) {
@ -45,8 +33,7 @@ static uint32_t gen_texture_key(const GrProcessor& proc, const GrGLCaps& caps) {
int numTextures = proc.numTextures();
for (int t = 0; t < numTextures; ++t) {
const GrTextureAccess& access = proc.textureAccess(t);
uint32_t configComponentMask = GrPixelConfigComponentMask(access.getTexture()->config());
if (swizzle_requires_alpha_remapping(caps, configComponentMask, access.swizzleMask())) {
if (swizzle_requires_alpha_remapping(*caps.glslCaps(), access.getTexture()->config())) {
key |= 1 << t;
}
}

View File

@ -6,47 +6,68 @@
*/
#include "GrGLShaderBuilder.h"
#include "gl/GrGLGpu.h"
#include "gl/builders/GrGLProgramBuilder.h"
#include "glsl/GrGLSLCaps.h"
#include "glsl/GrGLSLShaderVar.h"
#include "glsl/GrGLSLTextureSampler.h"
namespace {
void append_texture_lookup(SkString* out,
GrGLGpu* gpu,
const char* samplerName,
const char* coordName,
uint32_t configComponentMask,
const char* swizzle,
GrSLType varyingType = kVec2f_GrSLType) {
static void map_swizzle(const char* swizzleMap, const char* swizzle, char* mangledSwizzle) {
int i;
for (i = 0; '\0' != swizzle[i]; ++i) {
switch (swizzle[i]) {
case 'r':
mangledSwizzle[i] = swizzleMap[0];
break;
case 'g':
mangledSwizzle[i] = swizzleMap[1];
break;
case 'b':
mangledSwizzle[i] = swizzleMap[2];
break;
case 'a':
mangledSwizzle[i] = swizzleMap[3];
break;
default:
SkFAIL("Unsupported swizzle");
}
}
mangledSwizzle[i] ='\0';
}
static void append_texture_lookup(SkString* out,
const GrGLSLCaps* glslCaps,
const char* samplerName,
const char* coordName,
GrPixelConfig config,
const char* swizzle,
GrSLType varyingType = kVec2f_GrSLType) {
SkASSERT(coordName);
out->appendf("%s(%s, %s)",
GrGLSLTexture2DFunctionName(varyingType, gpu->glslGeneration()),
GrGLSLTexture2DFunctionName(varyingType, glslCaps->generation()),
samplerName,
coordName);
char mangledSwizzle[5];
// The swizzling occurs using texture params instead of shader-mangling if ARB_texture_swizzle
// is available.
if (!gpu->glCaps().textureSwizzleSupport() &&
(kA_GrColorComponentFlag == configComponentMask)) {
char alphaChar = gpu->glCaps().textureRedSupport() ? 'r' : 'a';
int i;
for (i = 0; '\0' != swizzle[i]; ++i) {
mangledSwizzle[i] = alphaChar;
// This refers to any swizzling we may need to get from some backend internal format to the
// format used in GrPixelConfig. Some backends will automatically do the sizzling for us.
if (glslCaps->mustSwizzleInShader()) {
const char* swizzleMap = glslCaps->getSwizzleMap(config);
// if the map is simply 'rgba' then we don't need to do any manual swizzling to get us to
// a GrPixelConfig format.
if (memcmp(swizzleMap, "rgba", 4)) {
// Manually 'swizzle' the swizzle using our mapping
map_swizzle(swizzleMap, swizzle, mangledSwizzle);
swizzle = mangledSwizzle;
}
mangledSwizzle[i] ='\0';
swizzle = mangledSwizzle;
}
// For shader prettiness we omit the swizzle rather than appending ".rgba".
if (memcmp(swizzle, "rgba", 4)) {
out->appendf(".%s", swizzle);
}
}
}
GrGLShaderBuilder::GrGLShaderBuilder(GrGLProgramBuilder* program)
: fProgramBuilder(program)
@ -97,10 +118,10 @@ void GrGLShaderBuilder::appendTextureLookup(SkString* out,
const char* coordName,
GrSLType varyingType) const {
append_texture_lookup(out,
fProgramBuilder->gpu(),
fProgramBuilder->glslCaps(),
fProgramBuilder->getUniformCStr(sampler.fSamplerUniform),
coordName,
sampler.configComponentMask(),
sampler.config(),
sampler.swizzle(),
varyingType);
}
@ -134,19 +155,6 @@ void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
}
}
void GrGLShaderBuilder::appendTextureLookup(const char* samplerName,
const char* coordName,
uint32_t configComponentMask,
const char* swizzle) {
append_texture_lookup(&this->code(),
fProgramBuilder->gpu(),
samplerName,
coordName,
configComponentMask,
swizzle,
kVec2f_GrSLType);
}
void GrGLShaderBuilder::addLayoutQualifier(const char* param, InterfaceQualifier interface) {
SkASSERT(fProgramBuilder->glslCaps()->generation() >= k330_GrGLSLGeneration ||
fProgramBuilder->glslCaps()->mustEnableAdvBlendEqs());

View File

@ -125,14 +125,6 @@ protected:
typedef GrTAllocator<GrGLSLShaderVar> VarArray;
void appendDecls(const VarArray& vars, SkString* out) const;
/*
* this super low level function is just for use internally to builders
*/
void appendTextureLookup(const char* samplerName,
const char* coordName,
uint32_t configComponentMask,
const char* swizzle);
/*
* A general function which enables an extension in a shader if the feature bit is not present
*/

View File

@ -8,6 +8,8 @@
#include "GrGLSLCaps.h"
#include "GrContextOptions.h"
////////////////////////////////////////////////////////////////////////////////////////////
GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) {
@ -25,6 +27,9 @@ GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) {
fFBFetchColorName = nullptr;
fFBFetchExtensionString = nullptr;
fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction;
fMustSwizzleInShader = false;
memset(fConfigSwizzle, 0, sizeof(fConfigSwizzle));
}
SkString GrGLSLCaps::dump() const {
@ -56,3 +61,9 @@ SkString GrGLSLCaps::dump() const {
return r;
}
void GrGLSLCaps::onApplyOptionsOverrides(const GrContextOptions& options) {
if (options.fUseShaderSwizzling) {
fMustSwizzleInShader = true;
}
}

View File

@ -82,6 +82,15 @@ public:
return fShaderDerivativeExtensionString;
}
bool mustSwizzleInShader() const { return fMustSwizzleInShader; }
/**
* Returns a string which represents how to map from an internal GLFormat to a given
* GrPixelConfig. The function mustSwizzleInShader determines whether this swizzle is applied
* in the generated shader code or using sample state in the 3D API.
*/
const char* getSwizzleMap(GrPixelConfig config) const { return fConfigSwizzle[config]; }
GrGLSLGeneration generation() const { return fGLSLGeneration; }
/**
@ -90,6 +99,8 @@ public:
SkString dump() const override;
private:
void onApplyOptionsOverrides(const GrContextOptions& options) override;
GrGLSLGeneration fGLSLGeneration;
bool fDropsTileOnZeroDivide : 1;
@ -109,6 +120,9 @@ private:
AdvBlendEqInteraction fAdvBlendEqInteraction;
bool fMustSwizzleInShader;
const char* fConfigSwizzle[kGrPixelConfigCnt];
friend class GrGLCaps; // For initialization.
typedef GrShaderCaps INHERITED;

View File

@ -19,19 +19,18 @@ public:
GrGLSLTextureSampler(UniformHandle uniform, const GrTextureAccess& access)
: fSamplerUniform(uniform)
, fConfigComponentMask(GrPixelConfigComponentMask(access.getTexture()->config())) {
SkASSERT(0 != fConfigComponentMask);
, fConfig(access.getTexture()->config()) {
SkASSERT(kUnknown_GrPixelConfig != fConfig);
memcpy(fSwizzle, access.getSwizzle(), 5);
}
// bitfield of GrColorComponentFlags present in the texture's config.
uint32_t configComponentMask() const { return fConfigComponentMask; }
GrPixelConfig config() const { return fConfig; }
// this is .abcd
const char* swizzle() const { return fSwizzle; }
private:
UniformHandle fSamplerUniform;
uint32_t fConfigComponentMask;
GrPixelConfig fConfig;
char fSwizzle[5];
friend class GrGLShaderBuilder;