Initial version of R8 support
http://codereview.appspot.com/5967067/
git-svn-id: http://skia.googlecode.com/svn/trunk@3622 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gyp/tests.gyp b/gyp/tests.gyp
index a3a8002..8c9c985 100644
--- a/gyp/tests.gyp
+++ b/gyp/tests.gyp
@@ -58,6 +58,7 @@
'../tests/QuickRejectTest.cpp',
'../tests/Reader32Test.cpp',
'../tests/ReadPixelsTest.cpp',
+ '../tests/ReadWriteAlphaTest.cpp',
'../tests/RefDictTest.cpp',
'../tests/RegionTest.cpp',
'../tests/ScalarTest.cpp',
diff --git a/include/gpu/gl/GrGLDefines.h b/include/gpu/gl/GrGLDefines.h
index 3697d60..2268510 100644
--- a/include/gpu/gl/GrGLDefines.h
+++ b/include/gpu/gl/GrGLDefines.h
@@ -296,6 +296,8 @@
#define GR_GL_PALETTE8_RGBA8 0x8B96
#define GR_GL_ALPHA8 0x803C
+#define GR_GL_R8 0x8229
+
/* PixelType */
/* GL_UNSIGNED_BYTE */
#define GR_GL_UNSIGNED_SHORT_4_4_4_4 0x8033
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index d690ff3..8b14a1b 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -30,6 +30,7 @@
fPackFlipYSupport = false;
fTextureUsageSupport = false;
fTexStorageSupport = false;
+ fTextureRedSupport = false;
}
GrGLCaps::GrGLCaps(const GrGLCaps& caps) {
@@ -52,6 +53,7 @@
fPackFlipYSupport = caps.fPackFlipYSupport;
fTextureUsageSupport = caps.fTextureUsageSupport;
fTexStorageSupport = caps.fTexStorageSupport;
+ fTextureRedSupport = caps.fTextureRedSupport;
return *this;
}
@@ -129,6 +131,14 @@
ctxInfo.hasExtension("GL_ARB_texture_storage") ||
ctxInfo.hasExtension("GL_EXT_texture_storage");
+ // ARB_texture_rg is part of OpenGL 3.0
+ if (kDesktop_GrGLBinding == binding) {
+ fTextureRedSupport = version >= GR_GL_VER(3,0) ||
+ ctxInfo.hasExtension("GL_ARB_texture_rg");
+ } else {
+ fTextureRedSupport = ctxInfo.hasExtension("GL_ARB_texture_rg");
+ }
+
this->initFSAASupport(ctxInfo);
this->initStencilFormats(ctxInfo);
}
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index a5318eb..8b3f9e7 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -158,6 +158,9 @@
/// Is there support for glTexStorage
bool texStorageSupport() const { return fTexStorageSupport; }
+ /// Is there support for GL_RED and GL_R8
+ bool textureRedSupport() const { return fTextureRedSupport; }
+
private:
/**
* Maintains a bit per GrPixelConfig. It is used to avoid redundantly
@@ -222,6 +225,7 @@
bool fPackFlipYSupport : 1;
bool fTextureUsageSupport : 1;
bool fTexStorageSupport : 1;
+ bool fTextureRedSupport : 1;
};
#endif
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index a39b0b9..f277647 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -1897,11 +1897,17 @@
const char* swizzle = "";
if (desc.fInConfigFlags & StageDesc::kSwapRAndB_InConfigFlag) {
GrAssert(!(desc.fInConfigFlags & StageDesc::kSmearAlpha_InConfigFlag));
+ GrAssert(!(desc.fInConfigFlags & StageDesc::kSmearRed_InConfigFlag));
swizzle = ".bgra";
} else if (desc.fInConfigFlags & StageDesc::kSmearAlpha_InConfigFlag) {
GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
+ GrAssert(!(desc.fInConfigFlags & StageDesc::kSmearRed_InConfigFlag));
swizzle = ".aaaa";
- }
+ } else if (desc.fInConfigFlags & StageDesc::kSmearRed_InConfigFlag) {
+ GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
+ GrAssert(!(desc.fInConfigFlags & StageDesc::kSmearAlpha_InConfigFlag));
+ swizzle = ".rrrr";
+ }
GrStringBuilder modulate;
if (NULL != fsInColor) {
@@ -1951,6 +1957,8 @@
GrAssert(GrIsPow2(kMulByAlphaMask & desc.fInConfigFlags));
GrAssert(!(desc.fInConfigFlags &
StageDesc::kSmearAlpha_InConfigFlag));
+ GrAssert(!(desc.fInConfigFlags &
+ StageDesc::kSmearRed_InConfigFlag));
segments->fFSCode.appendf("\t%s = %s(%s, %s)%s;\n",
fsOutColor, texFunc.c_str(),
samplerName, sampleCoords.c_str(),
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 76f9c90..0d8c39a 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -120,7 +120,7 @@
described are performed after reading a texel.
*/
enum InConfigFlags {
- kNone_InConfigFlag = 0x0,
+ kNone_InConfigFlag = 0x00,
/**
Swap the R and B channels. This is incompatible with
@@ -128,15 +128,24 @@
the shader using GL_ARB_texture_swizzle if possible rather
than setting this flag.
*/
- kSwapRAndB_InConfigFlag = 0x1,
+ kSwapRAndB_InConfigFlag = 0x01,
/**
Smear alpha across all four channels. This is incompatible with
- kSwapRAndB and kMulRGBByAlpha*. It is prefereable to perform
- the smear outside the shader using GL_ARB_texture_swizzle if
- possible rather than setting this flag.
+ kSwapRAndB, kMulRGBByAlpha* and kSmearRed. It is prefereable
+ to perform the smear outside the shader using
+ GL_ARB_texture_swizzle if possible rather than setting this
+ flag.
*/
- kSmearAlpha_InConfigFlag = 0x2,
+ kSmearAlpha_InConfigFlag = 0x02,
+
+ /**
+ Smear the red channel across all four channels. This flag is
+ incompatible with kSwapRAndB, kMulRGBByAlpha*and kSmearAlpha.
+ It is preferable to use GL_ARB_texture_swizzle instead of this
+ flag.
+ */
+ kSmearRed_InConfigFlag = 0x04,
/**
Multiply r,g,b by a after texture reads. This flag incompatible
@@ -147,8 +156,8 @@
of 1/255.0 and the other rounds down. At most one of these
flags may be set.
*/
- kMulRGBByAlpha_RoundUp_InConfigFlag = 0x4,
- kMulRGBByAlpha_RoundDown_InConfigFlag = 0x8,
+ kMulRGBByAlpha_RoundUp_InConfigFlag = 0x08,
+ kMulRGBByAlpha_RoundDown_InConfigFlag = 0x10,
kDummyInConfigFlag,
kInConfigBitMask = (kDummyInConfigFlag-1) |
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 8214b6e..8481b74 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -1947,12 +1947,20 @@
}
}
-const GrGLenum* get_swizzle(GrPixelConfig config,
- const GrSamplerState& sampler) {
+// get_swizzle is only called from this .cpp so it is OK to inline it here
+inline const GrGLenum* get_swizzle(GrPixelConfig config,
+ const GrSamplerState& sampler,
+ const GrGLCaps& glCaps) {
if (GrPixelConfigIsAlphaOnly(config)) {
- static const GrGLenum gAlphaSmear[] = { GR_GL_ALPHA, GR_GL_ALPHA,
- GR_GL_ALPHA, GR_GL_ALPHA };
- return gAlphaSmear;
+ if (glCaps.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 if (sampler.swapsRAndB()) {
static const GrGLenum gRedBlueSwap[] = { GR_GL_BLUE, GR_GL_GREEN,
GR_GL_RED, GR_GL_ALPHA };
@@ -2032,7 +2040,7 @@
newTexParams.fWrapS = wraps[sampler.getWrapX()];
newTexParams.fWrapT = wraps[sampler.getWrapY()];
memcpy(newTexParams.fSwizzleRGBA,
- get_swizzle(nextTexture->config(), sampler),
+ get_swizzle(nextTexture->config(), sampler, this->glCaps()),
sizeof(newTexParams.fSwizzleRGBA));
if (setAll || newTexParams.fFilter != oldTexParams.fFilter) {
setTextureUnit(s);
@@ -2274,14 +2282,25 @@
}
break;
case kAlpha_8_GrPixelConfig:
- *internalFormat = GR_GL_ALPHA;
- *externalFormat = GR_GL_ALPHA;
- if (getSizedInternalFormat) {
- *internalFormat = GR_GL_ALPHA8;
+ if (this->glCaps().textureRedSupport()) {
+ *internalFormat = GR_GL_RED;
+ *externalFormat = GR_GL_RED;
+ if (getSizedInternalFormat) {
+ *internalFormat = GR_GL_R8;
+ } else {
+ *internalFormat = GR_GL_RED;
+ }
+ *externalType = GR_GL_UNSIGNED_BYTE;
} else {
*internalFormat = GR_GL_ALPHA;
+ *externalFormat = GR_GL_ALPHA;
+ if (getSizedInternalFormat) {
+ *internalFormat = GR_GL_ALPHA8;
+ } else {
+ *internalFormat = GR_GL_ALPHA;
+ }
+ *externalType = GR_GL_UNSIGNED_BYTE;
}
- *externalType = GR_GL_UNSIGNED_BYTE;
break;
default:
return false;
diff --git a/src/gpu/gl/GrGpuGLShaders.cpp b/src/gpu/gl/GrGpuGLShaders.cpp
index b416b5c..9627107 100644
--- a/src/gpu/gl/GrGpuGLShaders.cpp
+++ b/src/gpu/gl/GrGpuGLShaders.cpp
@@ -178,6 +178,7 @@
StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag,
StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag,
StageDesc::kSmearAlpha_InConfigFlag,
+ StageDesc::kSmearRed_InConfigFlag,
};
GrGLProgram program;
ProgramDesc& pdesc = program.fProgramDesc;
@@ -271,6 +272,7 @@
static const uint32_t kMulByAlphaMask =
StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
+
switch (stage.fFetchMode) {
case StageDesc::kSingle_FetchMode:
stage.fKernelWidth = 0;
@@ -1132,9 +1134,17 @@
if (!this->glCaps().textureSwizzleSupport()) {
if (GrPixelConfigIsAlphaOnly(texture->config())) {
// if we don't have texture swizzle support then
- // the shader must do an alpha smear after reading
- // the texture
- stage.fInConfigFlags |= StageDesc::kSmearAlpha_InConfigFlag;
+ // the shader must smear the single channel after
+ // reading the texture
+ if (this->glCaps().textureRedSupport()) {
+ // we can use R8 textures so use kSmearRed
+ stage.fInConfigFlags |=
+ StageDesc::kSmearRed_InConfigFlag;
+ } else {
+ // we can use A8 textures so use kSmearAlpha
+ stage.fInConfigFlags |=
+ StageDesc::kSmearAlpha_InConfigFlag;
+ }
} else if (sampler.swapsRAndB()) {
stage.fInConfigFlags |= StageDesc::kSwapRAndB_InConfigFlag;
}
diff --git a/tests/ReadWriteAlphaTest.cpp b/tests/ReadWriteAlphaTest.cpp
new file mode 100644
index 0000000..2d6da96
--- /dev/null
+++ b/tests/ReadWriteAlphaTest.cpp
@@ -0,0 +1,103 @@
+
+/*
+ * Copyright 2012 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"
+#include "SkGpuDevice.h"
+
+static const int X_SIZE = 12;
+static const int Y_SIZE = 12;
+
+void ReadWriteAlphaTest(skiatest::Reporter* reporter, GrContext* context) {
+
+ unsigned char textureData[X_SIZE][Y_SIZE];
+
+ memset(textureData, 0, X_SIZE * Y_SIZE);
+
+ GrTextureDesc desc;
+
+ // let Skia know we will be using this texture as a render target
+ desc.fFlags = kRenderTarget_GrTextureFlagBit;
+ // it is a single channel texture
+ desc.fConfig = kAlpha_8_GrPixelConfig;
+ desc.fWidth = X_SIZE;
+ desc.fHeight = Y_SIZE;
+ desc.fSampleCnt = 0;
+
+ // We are initializing the texture with zeros here
+ GrTexture* texture = context->createUncachedTexture(desc, textureData, 0);
+ if (!texture) {
+ return;
+ }
+
+ GrAutoUnref au(texture);
+
+ // create a distinctive texture
+ for (int y = 0; y < Y_SIZE; ++y) {
+ for (int x = 0; x < X_SIZE; ++x) {
+ textureData[x][y] = x*Y_SIZE+y;
+ }
+ }
+
+ // upload the texture
+ texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
+ textureData, 0);
+
+ unsigned char readback[X_SIZE][Y_SIZE];
+
+ // clear readback to something non-zero so we can detect readback failures
+ memset(readback, 0x1, X_SIZE * Y_SIZE);
+
+ // read the texture back
+ texture->readPixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
+ readback, 0);
+
+ // make sure the original & read back versions match
+ bool match = true;
+
+ for (int y = 0; y < Y_SIZE; ++y) {
+ for (int x = 0; x < X_SIZE; ++x) {
+ if (textureData[x][y] != readback[x][y]) {
+ match = false;
+ }
+ }
+ }
+
+ REPORTER_ASSERT(reporter, match);
+
+ // Now try writing on the single channel texture
+ SkCanvas canvas;
+
+ canvas.setDevice(new SkGpuDevice(context, texture->asRenderTarget()))->unref();
+
+ SkPaint paint;
+
+ const SkRect rect = SkRect::MakeLTRB(-10, -10, X_SIZE + 10, Y_SIZE + 10);
+
+ paint.setColor(SK_ColorWHITE);
+
+ canvas.drawRect(rect, paint);
+
+ texture->readPixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
+ readback, 0);
+
+ match = true;
+
+ for (int y = 0; y < Y_SIZE; ++y) {
+ for (int x = 0; x < X_SIZE; ++x) {
+ if (0xFF != readback[x][y]) {
+ match = false;
+ }
+ }
+ }
+
+ REPORTER_ASSERT(reporter, match);
+}
+
+#include "TestClassDef.h"
+DEFINE_GPUTESTCLASS("ReadWriteAlpha", ReadWriteAlphaTestClass, ReadWriteAlphaTest)
+