diff options
author | senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-02-04 17:29:51 +0000 |
---|---|---|
committer | senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-02-04 17:29:51 +0000 |
commit | ed8659b51d9f2bad3f004df6033d72cc32d71c0d (patch) | |
tree | c9882164b3ce1c63e164bf0434c9505c95f80b6f | |
parent | 83f7c659461d602e498569dab63f04b1b578b742 (diff) |
Implement support for origin-TopLeft render targets in GL backend.
Review URL: https://codereview.appspot.com/7230049
git-svn-id: http://skia.googlecode.com/svn/trunk@7545 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | include/gpu/GrRenderTarget.h | 5 | ||||
-rw-r--r-- | include/gpu/GrSurface.h | 11 | ||||
-rw-r--r-- | include/gpu/GrTexture.h | 4 | ||||
-rw-r--r-- | include/gpu/GrTypes.h | 10 | ||||
-rw-r--r-- | samplecode/SampleApp.cpp | 1 | ||||
-rw-r--r-- | src/gpu/GrContext.cpp | 64 | ||||
-rw-r--r-- | src/gpu/GrGpu.cpp | 4 | ||||
-rw-r--r-- | src/gpu/GrGpu.h | 6 | ||||
-rw-r--r-- | src/gpu/GrTexture.cpp | 8 | ||||
-rw-r--r-- | src/gpu/gl/GrGLIRect.h | 11 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.cpp | 1 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.h | 5 | ||||
-rw-r--r-- | src/gpu/gl/GrGLRenderTarget.cpp | 13 | ||||
-rw-r--r-- | src/gpu/gl/GrGLRenderTarget.h | 13 | ||||
-rw-r--r-- | src/gpu/gl/GrGLShaderBuilder.cpp | 13 | ||||
-rw-r--r-- | src/gpu/gl/GrGLTexture.cpp | 5 | ||||
-rw-r--r-- | src/gpu/gl/GrGLTexture.h | 1 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGL.cpp | 63 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGL.h | 9 | ||||
-rw-r--r-- | src/gpu/gl/GrGpuGL_program.cpp | 32 | ||||
-rw-r--r-- | tests/ReadPixelsTest.cpp | 13 | ||||
-rw-r--r-- | tests/WritePixelsTest.cpp | 26 |
22 files changed, 175 insertions, 143 deletions
diff --git a/include/gpu/GrRenderTarget.h b/include/gpu/GrRenderTarget.h index 19a37a5d8b..fcb4c3d3b1 100644 --- a/include/gpu/GrRenderTarget.h +++ b/include/gpu/GrRenderTarget.h @@ -141,9 +141,8 @@ protected: GrRenderTarget(GrGpu* gpu, bool isWrapped, GrTexture* texture, - const GrTextureDesc& desc, - GrSurfaceOrigin origin) - : INHERITED(gpu, isWrapped, desc, origin) + const GrTextureDesc& desc) + : INHERITED(gpu, isWrapped, desc) , fStencilBuffer(NULL) , fTexture(texture) { fResolveRect.setLargestInverted(); diff --git a/include/gpu/GrSurface.h b/include/gpu/GrSurface.h index 3429cc6d80..02fc0d5dea 100644 --- a/include/gpu/GrSurface.h +++ b/include/gpu/GrSurface.h @@ -34,8 +34,8 @@ public: int height() const { return fDesc.fHeight; } GrSurfaceOrigin origin() const { - GrAssert(kTopLeft_GrSurfaceOrigin == fOrigin || kBottomLeft_GrSurfaceOrigin == fOrigin); - return fOrigin; + GrAssert(kTopLeft_GrSurfaceOrigin == fDesc.fOrigin || kBottomLeft_GrSurfaceOrigin == fDesc.fOrigin); + return fDesc.fOrigin; } /** @@ -104,17 +104,14 @@ public: uint32_t pixelOpsFlags = 0) = 0; protected: - GrSurface(GrGpu* gpu, bool isWrapped, const GrTextureDesc& desc, GrSurfaceOrigin origin) + GrSurface(GrGpu* gpu, bool isWrapped, const GrTextureDesc& desc) : INHERITED(gpu, isWrapped) - , fDesc(desc) - , fOrigin(origin) { + , fDesc(desc) { } GrTextureDesc fDesc; private: - GrSurfaceOrigin fOrigin; - typedef GrResource INHERITED; }; diff --git a/include/gpu/GrTexture.h b/include/gpu/GrTexture.h index 94d578894b..c088bdd582 100644 --- a/include/gpu/GrTexture.h +++ b/include/gpu/GrTexture.h @@ -140,8 +140,8 @@ protected: // base class cons sets to NULL // subclass cons can create and set - GrTexture(GrGpu* gpu, bool isWrapped, const GrTextureDesc& desc, GrSurfaceOrigin origin) - : INHERITED(gpu, isWrapped, desc, origin) + GrTexture(GrGpu* gpu, bool isWrapped, const GrTextureDesc& desc) + : INHERITED(gpu, isWrapped, desc) , fRenderTarget(NULL) { // only make sense if alloc size is pow2 diff --git a/include/gpu/GrTypes.h b/include/gpu/GrTypes.h index 055750dd11..88c5771cbf 100644 --- a/include/gpu/GrTypes.h +++ b/include/gpu/GrTypes.h @@ -428,13 +428,14 @@ enum { /** * Some textures will be stored such that the upper and left edges of the content meet at the * the origin (in texture coord space) and for other textures the lower and left edges meet at - * the origin. Render-targets are always consistent with the convention of the underlying - * backend API to make it easier to mix native backend rendering with Skia rendering. + * the origin. kDefault_GrSurfaceOrigin sets textures to TopLeft, and render targets + * to BottomLeft. */ enum GrSurfaceOrigin { - kBottomLeft_GrSurfaceOrigin, + kDefault_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin, + kBottomLeft_GrSurfaceOrigin, }; /** @@ -443,6 +444,7 @@ enum GrSurfaceOrigin { struct GrTextureDesc { GrTextureDesc() : fFlags(kNone_GrTextureFlags) + , fOrigin(kDefault_GrSurfaceOrigin) , fWidth(0) , fHeight(0) , fConfig(kUnknown_GrPixelConfig) @@ -450,6 +452,7 @@ struct GrTextureDesc { } GrTextureFlags fFlags; //!< bitfield of TextureFlags + GrSurfaceOrigin fOrigin; //!< origin of the texture int fWidth; //!< Width of the texture int fHeight; //!< Height of the texture @@ -640,6 +643,7 @@ struct GrBackendRenderTargetDesc { int fWidth; //<! width in pixels int fHeight; //<! height in pixels GrPixelConfig fConfig; //<! color format + GrSurfaceOrigin fOrigin; //<! pixel origin /** * The number of samples per pixel. Gr uses this to influence decisions * about applying other forms of anti-aliasing. diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp index dbc779f338..7657813627 100644 --- a/samplecode/SampleApp.cpp +++ b/samplecode/SampleApp.cpp @@ -295,6 +295,7 @@ public: desc.fWidth = SkScalarRound(win->width()); desc.fHeight = SkScalarRound(win->height()); desc.fConfig = kSkia8888_PM_GrPixelConfig; + desc.fOrigin = kBottomLeft_GrSurfaceOrigin; GR_GL_GetIntegerv(fCurIntf, GR_GL_SAMPLES, &desc.fSampleCnt); GR_GL_GetIntegerv(fCurIntf, GR_GL_STENCIL_BITS, &desc.fStencilBits); GrGLint buffer; diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index b729d6971e..52e200309c 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -1328,10 +1328,6 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags); - // flipY will get set to false when it is handled below using a scratch. However, in that case - // we still want to do the read upside down. - bool readUpsideDown = flipY; - if (unpremul && kRGBA_8888_GrPixelConfig != config && kBGRA_8888_GrPixelConfig != config) { // The unpremul flag is only allowed for these two configs. return false; @@ -1359,6 +1355,7 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, desc.fWidth = width; desc.fHeight = height; desc.fConfig = readConfig; + desc.fOrigin = kTopLeft_GrSurfaceOrigin; // When a full readback is faster than a partial we could always make the scratch exactly // match the passed rect. However, if we see many different size rectangles we will trash @@ -1377,13 +1374,7 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, if (texture) { // compute a matrix to perform the draw SkMatrix textureMatrix; - if (flipY) { - textureMatrix.setTranslate(SK_Scalar1 * left, - SK_Scalar1 * (top + height)); - textureMatrix.set(SkMatrix::kMScaleY, -SK_Scalar1); - } else { - textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top); - } + textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top); textureMatrix.postIDiv(src->width(), src->height()); SkAutoTUnref<const GrEffectRef> effect; @@ -1404,7 +1395,6 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, textureMatrix)); } swapRAndB = false; // we will handle the swap in the draw. - flipY = false; // we already incorporated the y flip in the matrix GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit); GrDrawState* drawState = fGpu->drawState(); @@ -1423,11 +1413,11 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, } if (!fGpu->readPixels(target, left, top, width, height, - readConfig, buffer, rowBytes, readUpsideDown)) { + readConfig, buffer, rowBytes)) { return false; } // Perform any conversions we weren't able to perform using a scratch texture. - if (unpremul || swapRAndB || flipY) { + if (unpremul || swapRAndB) { // These are initialized to suppress a warning SkCanvas::Config8888 srcC8888 = SkCanvas::kNative_Premul_Config8888; SkCanvas::Config8888 dstC8888 = SkCanvas::kNative_Premul_Config8888; @@ -1439,47 +1429,11 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target, GrAssert(c8888IsValid); // we should only do r/b swap on 8888 configs srcC8888 = swap_config8888_red_and_blue(srcC8888); } - if (flipY) { - size_t tightRB = width * GrBytesPerPixel(config); - if (0 == rowBytes) { - rowBytes = tightRB; - } - SkAutoSTMalloc<256, uint8_t> tempRow(tightRB); - intptr_t top = reinterpret_cast<intptr_t>(buffer); - intptr_t bot = top + (height - 1) * rowBytes; - while (top < bot) { - uint32_t* t = reinterpret_cast<uint32_t*>(top); - uint32_t* b = reinterpret_cast<uint32_t*>(bot); - uint32_t* temp = reinterpret_cast<uint32_t*>(tempRow.get()); - memcpy(temp, t, tightRB); - if (c8888IsValid) { - SkConvertConfig8888Pixels(t, tightRB, dstC8888, - b, tightRB, srcC8888, - width, 1); - SkConvertConfig8888Pixels(b, tightRB, dstC8888, - temp, tightRB, srcC8888, - width, 1); - } else { - memcpy(t, b, tightRB); - memcpy(b, temp, tightRB); - } - top += rowBytes; - bot -= rowBytes; - } - // The above loop does nothing on the middle row when height is odd. - if (top == bot && c8888IsValid && dstC8888 != srcC8888) { - uint32_t* mid = reinterpret_cast<uint32_t*>(top); - SkConvertConfig8888Pixels(mid, tightRB, dstC8888, mid, tightRB, srcC8888, width, 1); - } - } else { - // if we aren't flipping Y then we have no reason to be here other than doing - // conversions for 8888 (r/b swap or upm). - GrAssert(c8888IsValid); - uint32_t* b32 = reinterpret_cast<uint32_t*>(buffer); - SkConvertConfig8888Pixels(b32, rowBytes, dstC8888, - b32, rowBytes, srcC8888, - width, height); - } + GrAssert(c8888IsValid); + uint32_t* b32 = reinterpret_cast<uint32_t*>(buffer); + SkConvertConfig8888Pixels(b32, rowBytes, dstC8888, + b32, rowBytes, srcC8888, + width, height); } return true; } diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index 3da8219e69..47d406903c 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -231,10 +231,10 @@ void GrGpu::forceRenderTargetFlush() { bool GrGpu::readPixels(GrRenderTarget* target, int left, int top, int width, int height, GrPixelConfig config, void* buffer, - size_t rowBytes, bool invertY) { + size_t rowBytes) { this->handleDirtyContext(); return this->onReadPixels(target, left, top, width, height, - config, buffer, rowBytes, invertY); + config, buffer, rowBytes); } void GrGpu::writeTexturePixels(GrTexture* texture, diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index bcda2574f5..85cbd3f8fd 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -234,8 +234,7 @@ public: */ bool readPixels(GrRenderTarget* renderTarget, int left, int top, int width, int height, - GrPixelConfig config, void* buffer, size_t rowBytes, - bool invertY); + GrPixelConfig config, void* buffer, size_t rowBytes); /** * Updates the pixels in a rectangle of a texture. @@ -473,8 +472,7 @@ private: int left, int top, int width, int height, GrPixelConfig, void* buffer, - size_t rowBytes, - bool invertY) = 0; + size_t rowBytes) = 0; // overridden by backend-specific derived class to perform the texture update virtual void onWriteTexturePixels(GrTexture* texture, diff --git a/src/gpu/GrTexture.cpp b/src/gpu/GrTexture.cpp index 614d7711c2..4dea2a6d5f 100644 --- a/src/gpu/GrTexture.cpp +++ b/src/gpu/GrTexture.cpp @@ -165,14 +165,16 @@ GrResourceKey GrTexture::ComputeScratchKey(const GrTextureDesc& desc) { GrCacheID::Key idKey; // Instead of a client-provided key of the texture contents we create a key from the // descriptor. - GR_STATIC_ASSERT(sizeof(idKey) >= 12); + GR_STATIC_ASSERT(sizeof(idKey) >= 16); GrAssert(desc.fHeight < (1 << 16)); GrAssert(desc.fWidth < (1 << 16)); idKey.fData32[0] = (desc.fWidth) | (desc.fHeight << 16); idKey.fData32[1] = desc.fConfig | desc.fSampleCnt << 16; idKey.fData32[2] = desc.fFlags; - static const int kPadSize = sizeof(idKey) - 12; - memset(idKey.fData8 + 12, 0, kPadSize); + idKey.fData32[3] = desc.fOrigin; // Only needs 2 bits actually + static const int kPadSize = sizeof(idKey) - 16; + GR_STATIC_ASSERT(kPadSize >= 0); + memset(idKey.fData8 + 16, 0, kPadSize); GrCacheID cacheID(GrResourceKey::ScratchDomain(), idKey); return GrResourceKey(cacheID, texture_resource_type(), 0); diff --git a/src/gpu/gl/GrGLIRect.h b/src/gpu/gl/GrGLIRect.h index 038520d238..cbc4cb89f6 100644 --- a/src/gpu/gl/GrGLIRect.h +++ b/src/gpu/gl/GrGLIRect.h @@ -38,15 +38,20 @@ struct GrGLIRect { // sometimes we have a GrIRect from the client that we // want to simultaneously make relative to GL's viewport - // and convert from top-down to bottom-up. + // and (optionally) convert from top-down to bottom-up. void setRelativeTo(const GrGLIRect& glRect, int leftOffset, int topOffset, int width, - int height) { + int height, + GrSurfaceOrigin origin) { fLeft = glRect.fLeft + leftOffset; fWidth = width; - fBottom = glRect.fBottom + (glRect.fHeight - topOffset - height); + if (kBottomLeft_GrSurfaceOrigin == origin) { + fBottom = glRect.fBottom + (glRect.fHeight - topOffset - height); + } else { + fBottom = glRect.fBottom + topOffset; + } fHeight = height; GrAssert(fLeft >= 0); diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index 2aa723619b..a4f0df2fed 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -64,6 +64,7 @@ GrGLProgram::GrGLProgram(const GrGLContextInfo& gl, fViewMatrix = SkMatrix::InvalidMatrix(); fViewportSize.set(-1, -1); + fOrigin = (GrSurfaceOrigin) -1; fColor = GrColor_ILLEGAL; fColorFilterColor = GrColor_ILLEGAL; fRTHeight = -1; diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index 513bf75d23..8b494c8cef 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -199,10 +199,11 @@ private: GrGLuint fGShaderID; GrGLuint fFShaderID; GrGLuint fProgramID; - // The matrix sent to GL is determined by both the client's matrix and - // the size of the viewport. + // The matrix sent to GL is determined by the client's matrix, + // the size of the viewport, and the origin of the render target. SkMatrix fViewMatrix; SkISize fViewportSize; + GrSurfaceOrigin fOrigin; // these reflect the current values of uniforms (GL uniform values travel with program) GrColor fColor; diff --git a/src/gpu/gl/GrGLRenderTarget.cpp b/src/gpu/gl/GrGLRenderTarget.cpp index 47128e7064..69d7b9ca58 100644 --- a/src/gpu/gl/GrGLRenderTarget.cpp +++ b/src/gpu/gl/GrGLRenderTarget.cpp @@ -27,13 +27,15 @@ void GrGLRenderTarget::init(const Desc& desc, namespace { GrTextureDesc MakeDesc(GrTextureFlags flags, int width, int height, - GrPixelConfig config, int sampleCnt) { + GrPixelConfig config, int sampleCnt, + GrSurfaceOrigin origin) { GrTextureDesc temp; temp.fFlags = flags; temp.fWidth = width; temp.fHeight = height; temp.fConfig = config; temp.fSampleCnt = sampleCnt; + temp.fOrigin = origin; return temp; } @@ -49,9 +51,8 @@ GrGLRenderTarget::GrGLRenderTarget(GrGpuGL* gpu, texture, MakeDesc(kNone_GrTextureFlags, viewport.fWidth, viewport.fHeight, - desc.fConfig, desc.fSampleCnt), - texture->origin()) { - GrAssert(kBottomLeft_GrSurfaceOrigin == texture->origin()); + desc.fConfig, desc.fSampleCnt, + desc.fOrigin)) { GrAssert(NULL != texID); GrAssert(NULL != texture); // FBO 0 can't also be a texture, right? @@ -73,8 +74,8 @@ GrGLRenderTarget::GrGLRenderTarget(GrGpuGL* gpu, NULL, MakeDesc(kNone_GrTextureFlags, viewport.fWidth, viewport.fHeight, - desc.fConfig, desc.fSampleCnt), - kBottomLeft_GrSurfaceOrigin) { + desc.fConfig, desc.fSampleCnt, + desc.fOrigin)) { this->init(desc, viewport, NULL); } diff --git a/src/gpu/gl/GrGLRenderTarget.h b/src/gpu/gl/GrGLRenderTarget.h index 9a39ca1c2c..ea6ae87b99 100644 --- a/src/gpu/gl/GrGLRenderTarget.h +++ b/src/gpu/gl/GrGLRenderTarget.h @@ -25,12 +25,13 @@ public: enum { kUnresolvableFBOID = 0 }; struct Desc { - GrGLuint fRTFBOID; - GrGLuint fTexFBOID; - GrGLuint fMSColorRenderbufferID; - bool fIsWrapped; - GrPixelConfig fConfig; - int fSampleCnt; + GrGLuint fRTFBOID; + GrGLuint fTexFBOID; + GrGLuint fMSColorRenderbufferID; + bool fIsWrapped; + GrPixelConfig fConfig; + int fSampleCnt; + GrSurfaceOrigin fOrigin; }; // creates a GrGLRenderTarget associated with a texture diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp index a8514ad471..1618fe5416 100644 --- a/src/gpu/gl/GrGLShaderBuilder.cpp +++ b/src/gpu/gl/GrGLShaderBuilder.cpp @@ -260,6 +260,7 @@ void GrGLShaderBuilder::addVarying(GrSLType type, } const char* GrGLShaderBuilder::fragmentPosition() { +#if 1 if (fContext.caps().fragCoordConventionsSupport()) { if (!fSetupFragPosition) { fFSHeader.append("#extension GL_ARB_fragment_coord_conventions: require\n"); @@ -294,6 +295,18 @@ const char* GrGLShaderBuilder::fragmentPosition() { GrAssert(GrGLUniformManager::kInvalidUniformHandle != fRTHeightUniform); return kCoordName; } +#else + // This is the path we'll need to use once we have support for TopLeft + // render targets. + if (!fSetupFragPosition) { + fFSInputs.push_back().set(kVec4f_GrSLType, + GrGLShaderVar::kIn_TypeModifier, + "gl_FragCoord", + GrGLShaderVar::kDefault_Precision); + fSetupFragPosition = true; + } + return "gl_FragCoord"; +#endif } diff --git a/src/gpu/gl/GrGLTexture.cpp b/src/gpu/gl/GrGLTexture.cpp index f798b31ea0..66d6371f06 100644 --- a/src/gpu/gl/GrGLTexture.cpp +++ b/src/gpu/gl/GrGLTexture.cpp @@ -28,7 +28,6 @@ void GrGLTexture::init(GrGpuGL* gpu, textureDesc.fIsWrapped)); if (NULL != rtDesc) { - GrAssert(kBottomLeft_GrSurfaceOrigin == textureDesc.fOrigin); GrGLIRect vp; vp.fLeft = 0; vp.fWidth = textureDesc.fWidth; @@ -42,14 +41,14 @@ void GrGLTexture::init(GrGpuGL* gpu, GrGLTexture::GrGLTexture(GrGpuGL* gpu, const Desc& textureDesc) - : INHERITED(gpu, textureDesc.fIsWrapped, textureDesc, textureDesc.fOrigin) { + : INHERITED(gpu, textureDesc.fIsWrapped, textureDesc) { this->init(gpu, textureDesc, NULL); } GrGLTexture::GrGLTexture(GrGpuGL* gpu, const Desc& textureDesc, const GrGLRenderTarget::Desc& rtDesc) - : INHERITED(gpu, textureDesc.fIsWrapped, textureDesc, textureDesc.fOrigin) { + : INHERITED(gpu, textureDesc.fIsWrapped, textureDesc) { this->init(gpu, textureDesc, &rtDesc); } diff --git a/src/gpu/gl/GrGLTexture.h b/src/gpu/gl/GrGLTexture.h index 231482134b..79cea08663 100644 --- a/src/gpu/gl/GrGLTexture.h +++ b/src/gpu/gl/GrGLTexture.h @@ -59,7 +59,6 @@ public: struct Desc : public GrTextureDesc { GrGLuint fTextureID; bool fIsWrapped; - GrSurfaceOrigin fOrigin; }; // creates a texture that is also an RT diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp index 7ca07a0623..7f5f999e10 100644 --- a/src/gpu/gl/GrGpuGL.cpp +++ b/src/gpu/gl/GrGpuGL.cpp @@ -147,6 +147,17 @@ static bool fbo_test(const GrGLInterface* gl, int w, int h) { return status == GR_GL_FRAMEBUFFER_COMPLETE; } +static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin, bool renderTarget) { + // By default, GrRenderTargets are GL's normal orientation so that they + // can be drawn to by the outside world without the client having + // to render upside down. + if (kDefault_GrSurfaceOrigin == origin) { + return renderTarget ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin; + } else { + return origin; + } +} + GrGpuGL::GrGpuGL(const GrGLContextInfo& ctxInfo) : fGLContextInfo(ctxInfo) { GrAssert(ctxInfo.isInitialized()); @@ -485,12 +496,6 @@ GrTexture* GrGpuGL::onWrapBackendTexture(const GrBackendTextureDesc& desc) { return NULL; } - // FIXME: add support for TopLeft RT's by flipping all draws. - if (desc.fFlags & kRenderTarget_GrBackendTextureFlag && - kBottomLeft_GrSurfaceOrigin != desc.fOrigin) { - return NULL; - } - int maxSize = this->getCaps().maxTextureSize(); if (desc.fWidth > maxSize || desc.fHeight > maxSize) { return NULL; @@ -505,16 +510,18 @@ GrTexture* GrGpuGL::onWrapBackendTexture(const GrBackendTextureDesc& desc) { glTexDesc.fSampleCnt = desc.fSampleCnt; glTexDesc.fTextureID = static_cast<GrGLuint>(desc.fTextureHandle); glTexDesc.fIsWrapped = true; - glTexDesc.fOrigin = desc.fOrigin; + bool renderTarget = 0 != (desc.fFlags & kRenderTarget_GrBackendTextureFlag); + glTexDesc.fOrigin = resolve_origin(desc.fOrigin, renderTarget); GrGLTexture* texture = NULL; - if (desc.fFlags & kRenderTarget_GrBackendTextureFlag) { + if (renderTarget) { GrGLRenderTarget::Desc glRTDesc; glRTDesc.fRTFBOID = 0; glRTDesc.fTexFBOID = 0; glRTDesc.fMSColorRenderbufferID = 0; glRTDesc.fConfig = desc.fConfig; glRTDesc.fSampleCnt = desc.fSampleCnt; + glRTDesc.fOrigin = glTexDesc.fOrigin; if (!this->createRenderTargetObjects(glTexDesc.fWidth, glTexDesc.fHeight, glTexDesc.fTextureID, @@ -541,6 +548,12 @@ GrRenderTarget* GrGpuGL::onWrapBackendRenderTarget(const GrBackendRenderTargetDe glDesc.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID; glDesc.fSampleCnt = desc.fSampleCnt; glDesc.fIsWrapped = true; + glDesc.fOrigin = desc.fOrigin; + if (glDesc.fRTFBOID == 0) { + GrAssert(desc.fOrigin == kBottomLeft_GrSurfaceOrigin); + } + + glDesc.fOrigin = resolve_origin(desc.fOrigin, true); GrGLIRect viewport; viewport.fLeft = 0; viewport.fBottom = 0; @@ -960,10 +973,8 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc, const Caps& caps = this->getCaps(); - // We keep GrRenderTargets in GL's normal orientation so that they - // can be drawn to by the outside world without the client having - // to render upside down. - glTexDesc.fOrigin = renderTarget ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin; + glTexDesc.fOrigin = resolve_origin(desc.fOrigin, renderTarget); + glRTDesc.fOrigin = glTexDesc.fOrigin; glRTDesc.fSampleCnt = desc.fSampleCnt; if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType() && @@ -1278,7 +1289,8 @@ void GrGpuGL::flushScissor() { fScissorState.fRect.fLeft, fScissorState.fRect.fTop, fScissorState.fRect.width(), - fScissorState.fRect.height()); + fScissorState.fRect.height(), + rt->origin()); // if the scissor fully contains the viewport then we fall through and // disable the scissor test. if (!scissor.contains(vp)) { @@ -1404,6 +1416,11 @@ bool GrGpuGL::readPixelsWillPayForYFlip(GrRenderTarget* renderTarget, int width, int height, GrPixelConfig config, size_t rowBytes) const { + // If this rendertarget is aready TopLeft, we don't need to flip. + if (kTopLeft_GrSurfaceOrigin == renderTarget->origin()) { + return false; + } + // if GL can do the flip then we'll never pay for it. if (this->glCaps().packFlipYSupport()) { return false; @@ -1430,10 +1447,10 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, int width, int height, GrPixelConfig config, void* buffer, - size_t rowBytes, - bool invertY) { + size_t rowBytes) { GrGLenum format; GrGLenum type; + bool flipY = kBottomLeft_GrSurfaceOrigin == target->origin(); if (!this->configToGLFormats(config, false, NULL, &format, &type)) { return false; } @@ -1469,7 +1486,7 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, // the read rect is viewport-relative GrGLIRect readRect; - readRect.setRelativeTo(glvp, left, top, width, height); + readRect.setRelativeTo(glvp, left, top, width, height, target->origin()); size_t tightRowBytes = bpp * width; if (0 == rowBytes) { @@ -1491,7 +1508,7 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, readDst = scratch.get(); } } - if (!invertY && this->glCaps().packFlipYSupport()) { + if (flipY && this->glCaps().packFlipYSupport()) { GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, 1)); } GL_CALL(ReadPixels(readRect.fLeft, readRect.fBottom, @@ -1501,9 +1518,9 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, GrAssert(this->glCaps().packRowLengthSupport()); GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0)); } - if (!invertY && this->glCaps().packFlipYSupport()) { + if (flipY && this->glCaps().packFlipYSupport()) { GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, 0)); - invertY = true; + flipY = false; } // now reverse the order of the rows, since GL's are bottom-to-top, but our @@ -1511,7 +1528,7 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, // that the above readPixels did not overwrite the padding. if (readDst == buffer) { GrAssert(rowBytes == readDstRowBytes); - if (!invertY) { + if (flipY) { scratch.reset(tightRowBytes); void* tmpRow = scratch.get(); // flip y in-place by rows @@ -1532,13 +1549,13 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, // const int halfY = height >> 1; const char* src = reinterpret_cast<const char*>(readDst); char* dst = reinterpret_cast<char*>(buffer); - if (!invertY) { + if (flipY) { dst += (height-1) * rowBytes; } for (int y = 0; y < height; y++) { memcpy(dst, src, tightRowBytes); src += readDstRowBytes; - if (invertY) { + if (!flipY) { dst += rowBytes; } else { dst -= rowBytes; @@ -1735,7 +1752,7 @@ void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) { const GrIRect dirtyRect = rt->getResolveRect(); GrGLIRect r; r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop, - dirtyRect.width(), dirtyRect.height()); + dirtyRect.width(), dirtyRect.height(), target->origin()); GrAutoTRestore<ScissorState> asr; if (GrGLCaps::kAppleES_MSFBOType == this->glCaps().msFBOType()) { diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h index 3b8c16fabf..5b24d40578 100644 --- a/src/gpu/gl/GrGpuGL.h +++ b/src/gpu/gl/GrGpuGL.h @@ -86,8 +86,7 @@ private: int width, int height, GrPixelConfig, void* buffer, - size_t rowBytes, - bool invertY) SK_OVERRIDE; + size_t rowBytes) SK_OVERRIDE; virtual void onWriteTexturePixels(GrTexture* texture, int left, int top, int width, int height, @@ -322,11 +321,13 @@ private: } fHWAAState; struct { - SkMatrix fViewMatrix; - SkISize fRTSize; + SkMatrix fViewMatrix; + SkISize fRTSize; + GrSurfaceOrigin fLastOrigin; void invalidate() { fViewMatrix = SkMatrix::InvalidMatrix(); fRTSize.fWidth = -1; // just make the first value compared illegal. + fLastOrigin = (GrSurfaceOrigin) -1; } } fHWPathMatrixState; diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp index d5e8fbdd79..28f76de2ac 100644 --- a/src/gpu/gl/GrGpuGL_program.cpp +++ b/src/gpu/gl/GrGpuGL_program.cpp @@ -92,13 +92,19 @@ void GrGpuGL::flushViewMatrix(DrawType type) { const SkMatrix& vm = this->getDrawState().getViewMatrix(); if (kStencilPath_DrawType == type) { - if (fHWPathMatrixState.fViewMatrix != vm || + if (fHWPathMatrixState.fLastOrigin != rt->origin() || + fHWPathMatrixState.fViewMatrix != vm || fHWPathMatrixState.fRTSize != viewportSize) { // rescale the coords from skia's "device" coords to GL's normalized coords, - // and perform a y-flip. + // and perform a y-flip if required. SkMatrix m; - m.setScale(SkIntToScalar(2) / rt->width(), SkIntToScalar(-2) / rt->height()); - m.postTranslate(-SK_Scalar1, SK_Scalar1); + if (kBottomLeft_GrSurfaceOrigin == rt->origin()) { + m.setScale(SkIntToScalar(2) / rt->width(), SkIntToScalar(-2) / rt->height()); + m.postTranslate(-SK_Scalar1, SK_Scalar1); + } else { + m.setScale(SkIntToScalar(2) / rt->width(), SkIntToScalar(2) / rt->height()); + m.postTranslate(-SK_Scalar1, -SK_Scalar1); + } m.preConcat(vm); // GL wants a column-major 4x4. @@ -128,14 +134,23 @@ void GrGpuGL::flushViewMatrix(DrawType type) { GL_CALL(LoadMatrixf(mv)); fHWPathMatrixState.fViewMatrix = vm; fHWPathMatrixState.fRTSize = viewportSize; + fHWPathMatrixState.fLastOrigin = rt->origin(); } - } else if (!fCurrentProgram->fViewMatrix.cheapEqualTo(vm) || + } else if (fCurrentProgram->fOrigin != rt->origin() || + !fCurrentProgram->fViewMatrix.cheapEqualTo(vm) || fCurrentProgram->fViewportSize != viewportSize) { SkMatrix m; - m.setAll( - SkIntToScalar(2) / viewportSize.fWidth, 0, -SK_Scalar1, - 0,-SkIntToScalar(2) / viewportSize.fHeight, SK_Scalar1, + if (kBottomLeft_GrSurfaceOrigin == rt->origin()) { + m.setAll( + SkIntToScalar(2) / viewportSize.fWidth, 0, -SK_Scalar1, + 0,-SkIntToScalar(2) / viewportSize.fHeight, SK_Scalar1, + 0, 0, SkMatrix::I()[8]); + } else { + m.setAll( + SkIntToScalar(2) / viewportSize.fWidth, 0, -SK_Scalar1, + 0, SkIntToScalar(2) / viewportSize.fHeight,-SK_Scalar1, 0, 0, SkMatrix::I()[8]); + } m.setConcat(m, vm); // ES doesn't allow you to pass true to the transpose param, @@ -156,6 +171,7 @@ void GrGpuGL::flushViewMatrix(DrawType type) { mt); fCurrentProgram->fViewMatrix = vm; fCurrentProgram->fViewportSize = viewportSize; + fCurrentProgram->fOrigin = rt->origin(); } } diff --git a/tests/ReadPixelsTest.cpp b/tests/ReadPixelsTest.cpp index 41ecccff35..df51a19a94 100644 --- a/tests/ReadPixelsTest.cpp +++ b/tests/ReadPixelsTest.cpp @@ -303,7 +303,7 @@ void ReadPixelsTest(skiatest::Reporter* reporter, GrContextFactory* factory) { SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10), }; - for (int dtype = 0; dtype < 2; ++dtype) { + for (int dtype = 0; dtype < 3; ++dtype) { int glCtxTypeCnt = 1; #if SK_SUPPORT_GPU if (0 != dtype) { @@ -325,7 +325,16 @@ void ReadPixelsTest(skiatest::Reporter* reporter, GrContextFactory* factory) { if (NULL == context) { continue; } - device.reset(new SkGpuDevice(context, SkBitmap::kARGB_8888_Config, DEV_W, DEV_H)); + GrTextureDesc desc; + desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; + desc.fWidth = DEV_W; + desc.fHeight = DEV_H; + desc.fConfig = kSkia8888_PM_GrPixelConfig; + desc.fOrigin = 1 == dtype ? kBottomLeft_GrSurfaceOrigin + : kTopLeft_GrSurfaceOrigin; + GrAutoScratchTexture ast(context, desc, GrContext::kExact_ScratchTexMatch); + SkAutoTUnref<GrTexture> tex(ast.detach()); + device.reset(new SkGpuDevice(context, tex)); #else continue; #endif diff --git a/tests/WritePixelsTest.cpp b/tests/WritePixelsTest.cpp index 14b2c51e9a..83e0784305 100644 --- a/tests/WritePixelsTest.cpp +++ b/tests/WritePixelsTest.cpp @@ -286,7 +286,8 @@ bool checkWrite(skiatest::Reporter* reporter, enum DevType { kRaster_DevType, #if SK_SUPPORT_GPU - kGpu_DevType, + kGpu_BottomLeft_DevType, + kGpu_TopLeft_DevType, #endif }; @@ -299,7 +300,8 @@ static const CanvasConfig gCanvasConfigs[] = { {kRaster_DevType, true}, {kRaster_DevType, false}, #if SK_SUPPORT_GPU && defined(SK_SCALAR_IS_FLOAT) - {kGpu_DevType, true}, // row bytes has no meaning on gpu devices + {kGpu_BottomLeft_DevType, true}, // row bytes has no meaning on gpu devices + {kGpu_TopLeft_DevType, true}, // row bytes has no meaning on gpu devices #endif }; @@ -321,8 +323,18 @@ SkDevice* createDevice(const CanvasConfig& c, GrContext* grCtx) { return new SkDevice(bmp); } #if SK_SUPPORT_GPU - case kGpu_DevType: - return new SkGpuDevice(grCtx, SkBitmap::kARGB_8888_Config, DEV_W, DEV_H); + case kGpu_BottomLeft_DevType: + case kGpu_TopLeft_DevType: + GrTextureDesc desc; + desc.fFlags = kRenderTarget_GrTextureFlagBit; + desc.fWidth = DEV_W; + desc.fHeight = DEV_H; + desc.fConfig = kSkia8888_PM_GrPixelConfig; + desc.fOrigin = kGpu_TopLeft_DevType == c.fDevType ? + kTopLeft_GrSurfaceOrigin : kBottomLeft_GrSurfaceOrigin; + GrAutoScratchTexture ast(grCtx, desc, GrContext::kExact_ScratchTexMatch); + SkAutoTUnref<GrTexture> tex(ast.detach()); + return new SkGpuDevice(grCtx, tex); #endif } return NULL; @@ -401,14 +413,16 @@ void WritePixelsTest(skiatest::Reporter* reporter, GrContextFactory* factory) { for (size_t i = 0; i < SK_ARRAY_COUNT(gCanvasConfigs); ++i) { int glCtxTypeCnt = 1; #if SK_SUPPORT_GPU - if (kGpu_DevType == gCanvasConfigs[i].fDevType) { + bool isGPUDevice = kGpu_TopLeft_DevType == gCanvasConfigs[i].fDevType || + kGpu_BottomLeft_DevType == gCanvasConfigs[i].fDevType; + if (isGPUDevice) { glCtxTypeCnt = GrContextFactory::kGLContextTypeCnt; } #endif for (int glCtxType = 0; glCtxType < glCtxTypeCnt; ++glCtxType) { GrContext* context = NULL; #if SK_SUPPORT_GPU - if (kGpu_DevType == gCanvasConfigs[i].fDevType) { + if (isGPUDevice) { GrContextFactory::GLContextType type = static_cast<GrContextFactory::GLContextType>(glCtxType); #if SK_ANGLE // This test breaks ANGLE with GL errors in texsubimage2D. Disable until debugged. |