Fix some bugs with read/writePixels
authorBrian Osman <brianosman@google.com>
Tue, 18 Apr 2017 18:38:53 +0000 (14:38 -0400)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Tue, 18 Apr 2017 19:12:23 +0000 (19:12 +0000)
- On both GL and Vulkan, we must draw if writing to an MSAA surface.
  Otherwise we just write to the resolve target texture, which gets
  overwritten on the next resolve.
- On Vulkan, we must draw if the target isn't a texture. (This check
  was already present in onWritePixels).
- On Vulkan, when reading from an MSAA surface as a different config,
  we don't need the readConfig to be renderable with MSAA - the temp
  surface is always created non-MSAA.

- Added tests for these fixes, verified that they failed previously.

Bug: skia:
Change-Id: Ia2d5025d7a8f8de8630413453f83b58028dd41aa
Reviewed-on: https://skia-review.googlesource.com/13691
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
src/gpu/gl/GrGLGpu.cpp
src/gpu/vk/GrVkGpu.cpp
src/gpu/vk/GrVkGpu.h
tests/WritePixelsTest.cpp

index 714ded0e7b7adddc474dd5bca775bfbd6460eb3b..d585e097f962135130404cf90d67fa1c38aed1bb 100644 (file)
@@ -665,6 +665,11 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
         }
     }
 
+    // If the dst is MSAA, we have to draw, or we'll just be writing to the resolve target.
+    if (dstSurface->asRenderTarget() && dstSurface->asRenderTarget()->numColorSamples() > 0) {
+        ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
+    }
+
     if (GrPixelConfigIsSRGB(dstSurface->config()) != GrPixelConfigIsSRGB(srcConfig)) {
         ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
     }
@@ -2277,7 +2282,7 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height,
 
     // Depends on why we need/want a temp draw. Start off assuming no change, the surface we read
     // from will be srcConfig and we will read readConfig pixels from it.
-    // Not that if we require a draw and return a non-renderable format for the temp surface the
+    // Note that if we require a draw and return a non-renderable format for the temp surface the
     // base class will fail for us.
     tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig;
     tempDrawInfo->fReadConfig = readConfig;
index cf7a39bb9d2f3f5effe590c663059c995ae43690..c9f590397a08e943941d26f02d711c65b54cf7cd 100644 (file)
@@ -295,27 +295,28 @@ bool GrVkGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
     tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
 
     if (dstSurface->config() == srcConfig) {
+        // We only support writing pixels to textures. Forcing a draw lets us write to pure RTs.
+        if (!dstSurface->asTexture()) {
+            ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
+        }
+        // If the dst is MSAA, we have to draw, or we'll just be writing to the resolve target.
+        if (renderTarget && renderTarget->numColorSamples() > 1) {
+            ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
+        }
         return true;
     }
 
-    if (renderTarget && this->vkCaps().isConfigRenderable(renderTarget->config(),
-                                                          renderTarget->numColorSamples() > 1)) {
-        ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
+    // Any config change requires a draw
+    ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
 
-        bool configsAreRBSwaps = GrPixelConfigSwapRAndB(srcConfig) == dstSurface->config();
+    bool configsAreRBSwaps = GrPixelConfigSwapRAndB(srcConfig) == dstSurface->config();
 
-        if (!this->vkCaps().isConfigTexturable(srcConfig) && configsAreRBSwaps) {
-            if (!this->vkCaps().isConfigTexturable(dstSurface->config())) {
-                return false;
-            }
-            tempDrawInfo->fTempSurfaceDesc.fConfig = dstSurface->config();
-            tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
-            tempDrawInfo->fWriteConfig = dstSurface->config();
-        }
-        return true;
+    if (!this->vkCaps().isConfigTexturable(srcConfig) && configsAreRBSwaps) {
+        tempDrawInfo->fTempSurfaceDesc.fConfig = dstSurface->config();
+        tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
+        tempDrawInfo->fWriteConfig = dstSurface->config();
     }
-
-    return false;
+    return true;
 }
 
 bool GrVkGpu::onWritePixels(GrSurface* surface,
@@ -848,6 +849,28 @@ sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTa
     return tgt;
 }
 
+sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendTextureAsRenderTarget(
+        const GrBackendTextureDesc& wrapDesc){
+
+    const GrVkImageInfo* info =
+        reinterpret_cast<const GrVkImageInfo*>(wrapDesc.fTextureHandle);
+    if (VK_NULL_HANDLE == info->fImage) {
+        return nullptr;
+    }
+
+    GrSurfaceDesc desc;
+    desc.fFlags = (GrSurfaceFlags) wrapDesc.fFlags;
+    desc.fConfig = wrapDesc.fConfig;
+    desc.fWidth = wrapDesc.fWidth;
+    desc.fHeight = wrapDesc.fHeight;
+    desc.fSampleCnt = SkTMin(wrapDesc.fSampleCnt, this->caps()->maxSampleCount());
+
+    desc.fOrigin = resolve_origin(wrapDesc.fOrigin);
+
+    sk_sp<GrVkRenderTarget> tgt = GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, info);
+    return tgt;
+}
+
 void GrVkGpu::generateMipmap(GrVkTexture* tex) {
     // don't do anything for linearly tiled textures (can't have mipmaps)
     if (tex->isLinearTiled()) {
@@ -1653,7 +1676,7 @@ bool GrVkGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height,
 
     // Depends on why we need/want a temp draw. Start off assuming no change, the surface we read
     // from will be srcConfig and we will read readConfig pixels from it.
-    // Not that if we require a draw and return a non-renderable format for the temp surface the
+    // Note that if we require a draw and return a non-renderable format for the temp surface the
     // base class will fail for us.
     tempDrawInfo->fTempSurfaceDesc.fConfig = srcSurface->config();
     tempDrawInfo->fReadConfig = readConfig;
@@ -1662,14 +1685,12 @@ bool GrVkGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height,
         return true;
     }
 
-    if (this->vkCaps().isConfigRenderable(readConfig, srcSurface->desc().fSampleCnt > 1)) {
-        ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
-        tempDrawInfo->fTempSurfaceDesc.fConfig = readConfig;
-        tempDrawInfo->fReadConfig = readConfig;
-        return true;
-    }
+    // Any config change requires a draw
+    ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
+    tempDrawInfo->fTempSurfaceDesc.fConfig = readConfig;
+    tempDrawInfo->fReadConfig = readConfig;
 
-    return false;
+    return true;
 }
 
 bool GrVkGpu::onReadPixels(GrSurface* surface,
index 914a2ba5db48b33e4d77bba9a828b18ea55ee045..84772713a95a41d0977fec32894a69441ab44871 100644 (file)
@@ -178,9 +178,7 @@ private:
     sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTextureDesc&, GrWrapOwnership) override;
 
     sk_sp<GrRenderTarget> onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) override;
-    sk_sp<GrRenderTarget> onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&) override {
-        return nullptr;
-    }
+    sk_sp<GrRenderTarget> onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&) override;
 
     GrBuffer* onCreateBuffer(size_t size, GrBufferType type, GrAccessPattern,
                              const void* data) override;
index f5cdddccd041b71164bd3a989f063c24fd87c889..e26e134b2d39e7697cabb3352a742e87425d0baf 100644 (file)
@@ -14,6 +14,7 @@
 
 #if SK_SUPPORT_GPU
 #include "GrContext.h"
+#include "GrGpu.h"
 #endif
 
 #include <initializer_list>
@@ -410,9 +411,45 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixels_Gpu, reporter, ctxInfo) {
     const SkImageInfo ii = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
 
     for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
-        sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kNo,
-                                                             ii, 0, origin, nullptr));
-        test_write_pixels(reporter, surface.get());
+        for (int sampleCnt : {0, 4}) {
+            sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
+                                                                 SkBudgeted::kNo, ii, sampleCnt,
+                                                                 origin, nullptr));
+            if (!surface && sampleCnt > 0) {
+                // Some platforms don't support MSAA
+                continue;
+            }
+            test_write_pixels(reporter, surface.get());
+        }
+    }
+}
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsNonTexture_Gpu, reporter, ctxInfo) {
+    GrContext* context = ctxInfo.grContext();
+
+    for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
+        for (int sampleCnt : {0, 4}) {
+            GrBackendTextureDesc desc;
+            desc.fConfig = kSkia8888_GrPixelConfig;
+            desc.fWidth = DEV_W;
+            desc.fHeight = DEV_H;
+            desc.fFlags = kRenderTarget_GrBackendTextureFlag;
+            desc.fSampleCnt = sampleCnt;
+            desc.fOrigin = origin;
+            desc.fTextureHandle = context->getGpu()->createTestingOnlyBackendTexture(
+                nullptr, DEV_W, DEV_H, kSkia8888_GrPixelConfig, true);
+            sk_sp<SkSurface> surface(SkSurface::MakeFromBackendTextureAsRenderTarget(context, desc,
+                                                                                     nullptr));
+            if (!surface) {
+                context->getGpu()->deleteTestingOnlyBackendTexture(desc.fTextureHandle);
+                continue;
+            }
+
+            test_write_pixels(reporter, surface.get());
+
+            surface.reset();
+            context->getGpu()->deleteTestingOnlyBackendTexture(desc.fTextureHandle);
+        }
     }
 }
 #endif