diff options
-rw-r--r-- | gyp/tests.gyp | 1 | ||||
-rw-r--r-- | include/gpu/gl/GrGLDefines.h | 2 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.cpp | 10 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.h | 4 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.cpp | 10 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.h | 25 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGL.cpp | 41 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGLShaders.cpp | 16 | ||||
-rw-r--r-- | tests/ReadWriteAlphaTest.cpp | 103 |
9 files changed, 189 insertions, 23 deletions
diff --git a/gyp/tests.gyp b/gyp/tests.gyp index a3a8002881..8c9c98542a 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 3697d604cb..22685105ba 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 d690ff3fe1..8b14a1b678 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -30,6 +30,7 @@ void GrGLCaps::reset() { fPackFlipYSupport = false; fTextureUsageSupport = false; fTexStorageSupport = false; + fTextureRedSupport = false; } GrGLCaps::GrGLCaps(const GrGLCaps& caps) { @@ -52,6 +53,7 @@ GrGLCaps& GrGLCaps::operator = (const GrGLCaps& caps) { fPackFlipYSupport = caps.fPackFlipYSupport; fTextureUsageSupport = caps.fTextureUsageSupport; fTexStorageSupport = caps.fTexStorageSupport; + fTextureRedSupport = caps.fTextureRedSupport; return *this; } @@ -129,6 +131,14 @@ void GrGLCaps::init(const GrGLContextInfo& ctxInfo) { 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 a5318ebde8..8b3f9e70a0 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -158,6 +158,9 @@ public: /// 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 @@ private: 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 a39b0b91bf..f2776474af 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -1897,11 +1897,17 @@ void GrGLProgram::genStageCode(const GrGLContextInfo& gl, 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 @@ void GrGLProgram::genStageCode(const GrGLContextInfo& gl, 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 76f9c9006f..0d8c39a786 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -120,7 +120,7 @@ public: 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 @@ public: 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 @@ public: 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 8214b6ea53..8481b74ab4 100644 --- a/src/gpu/gl/GrGpuGL.cpp +++ b/src/gpu/gl/GrGpuGL.cpp @@ -1947,12 +1947,20 @@ unsigned gr_to_gl_filter(GrSamplerState::Filter filter) { } } -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 @@ bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) { 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 @@ bool GrGpuGL::configToGLFormats(GrPixelConfig config, } 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 b416b5cdd1..9627107e79 100644 --- a/src/gpu/gl/GrGpuGLShaders.cpp +++ b/src/gpu/gl/GrGpuGLShaders.cpp @@ -178,6 +178,7 @@ bool GrGpuGLShaders::programUnitTest() { StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag, StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag, StageDesc::kSmearAlpha_InConfigFlag, + StageDesc::kSmearRed_InConfigFlag, }; GrGLProgram program; ProgramDesc& pdesc = program.fProgramDesc; @@ -271,6 +272,7 @@ bool GrGpuGLShaders::programUnitTest() { 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 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type, 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 0000000000..2d6da96d79 --- /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) + |