Implement support for origin-TopLeft render targets. Note that the default behaviour...
authorsenorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 5 Feb 2013 19:50:46 +0000 (19:50 +0000)
committersenorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 5 Feb 2013 19:50:46 +0000 (19:50 +0000)
Review URL: https://codereview.appspot.com/7230049

git-svn-id: http://skia.googlecode.com/svn/trunk@7594 2bbb7eff-a529-9590-31e7-b0007b416f81

22 files changed:
include/gpu/GrRenderTarget.h
include/gpu/GrSurface.h
include/gpu/GrTexture.h
include/gpu/GrTypes.h
samplecode/SampleApp.cpp
src/gpu/GrContext.cpp
src/gpu/GrGpu.cpp
src/gpu/GrGpu.h
src/gpu/GrTexture.cpp
src/gpu/gl/GrGLIRect.h
src/gpu/gl/GrGLProgram.cpp
src/gpu/gl/GrGLProgram.h
src/gpu/gl/GrGLRenderTarget.cpp
src/gpu/gl/GrGLRenderTarget.h
src/gpu/gl/GrGLShaderBuilder.cpp
src/gpu/gl/GrGLTexture.cpp
src/gpu/gl/GrGLTexture.h
src/gpu/gl/GrGpuGL.cpp
src/gpu/gl/GrGpuGL.h
src/gpu/gl/GrGpuGL_program.cpp
tests/ReadPixelsTest.cpp
tests/WritePixelsTest.cpp

index 19a37a5..fcb4c3d 100644 (file)
@@ -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();
index 3429cc6..02fc0d5 100644 (file)
@@ -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;
 };
 
index 94d5788..c088bdd 100644 (file)
@@ -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
index 055750d..9f1eb03 100644 (file)
@@ -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,         // DEPRECATED; to be removed
     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.
index dbc779f..7657813 100644 (file)
@@ -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;
index b729d69..52e2003 100644 (file)
@@ -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;
 }
index 3da8219..47d4069 100644 (file)
@@ -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,
index bcda257..85cbd3f 100644 (file)
@@ -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,
index 614d771..4dea2a6 100644 (file)
@@ -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);
index 038520d..cbc4cb8 100644 (file)
@@ -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);
index 2aa7236..a4f0df2 100644 (file)
@@ -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;
index 513bf75..8b494c8 100644 (file)
@@ -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;
index 47128e7..69d7b9c 100644 (file)
@@ -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);
 }
 
index 9a39ca1..ea6ae87 100644 (file)
@@ -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
index a8514ad..1618fe5 100644 (file)
@@ -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
 }
 
 
index f798b31..66d6371 100644 (file)
@@ -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);
 }
 
index 2314821..79cea08 100644 (file)
@@ -59,7 +59,6 @@ public:
     struct Desc : public GrTextureDesc {
         GrGLuint        fTextureID;
         bool            fIsWrapped;
-        GrSurfaceOrigin fOrigin;
     };
 
     // creates a texture that is also an RT
index 7ca07a0..5c2e0cb 100644 (file)
@@ -476,6 +476,21 @@ void GrGpuGL::onResetContext() {
     fHWConstAttribCoverage = GrColor_ILLEGAL;
 }
 
+namespace {
+
+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;
+    }
+}
+
+}
+
 GrTexture* GrGpuGL::onWrapBackendTexture(const GrBackendTextureDesc& desc) {
     if (!this->configToGLFormats(desc.fConfig, false, NULL, NULL, NULL)) {
         return NULL;
@@ -485,12 +500,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 +514,26 @@ 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);
+    // FIXME:  this should be calling resolve_origin(), but Chrome code is currently
+    // assuming the old behaviour, which is that backend textures are always
+    // BottomLeft, even for non-RT's.  Once Chrome is fixed, change this to:
+    // glTexDesc.fOrigin = resolve_origin(desc.fOrigin, renderTarget);
+    if (kDefault_GrSurfaceOrigin == desc.fOrigin) {
+        glTexDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
+    } else {
+        glTexDesc.fOrigin = desc.fOrigin;
+    }
 
     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 +560,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 +985,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 +1301,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 +1428,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 +1459,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 +1498,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 +1520,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 +1530,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 +1540,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 +1561,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 +1764,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()) {
index df9d8fc..71cb699 100644 (file)
@@ -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;
 
index d5e8fbd..28f76de 100644 (file)
@@ -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();
     }
 }
 
index 41ecccf..df51a19 100644 (file)
@@ -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
index 14b2c51..83e0784 100644 (file)
@@ -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.