Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2017 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkTypes.h"
      9 
     10 #if SK_SUPPORT_GPU
     11 
     12 #include "GrBackendSurface.h"
     13 #include "GrGpu.h"
     14 #include "SkCanvas.h"
     15 #include "SkDeferredDisplayListRecorder.h"
     16 #include "SkGpuDevice.h"
     17 #include "SkSurface.h"
     18 #include "SkSurface_Gpu.h"
     19 #include "SkSurfaceCharacterization.h"
     20 #include "SkSurfaceProps.h"
     21 #include "Test.h"
     22 
     23 #include "gl/GrGLDefines.h"
     24 #ifdef SK_VULKAN
     25 #include "vk/GrVkDefines.h"
     26 #endif
     27 
     28 static GrBackendFormat create_backend_format(GrContext* context, SkColorType colorType) {
     29     const GrCaps* caps = context->caps();
     30 
     31     switch (context->contextPriv().getBackend()) {
     32     case kOpenGL_GrBackend:
     33         if (kRGBA_8888_SkColorType == colorType) {
     34             GrGLenum format = caps->srgbSupport() ? GR_GL_SRGB8_ALPHA8 : GR_GL_RGBA8;
     35             return GrBackendFormat::MakeGL(format, GR_GL_TEXTURE_2D);
     36         } else if (kRGBA_F16_SkColorType == colorType) {
     37             return GrBackendFormat::MakeGL(GR_GL_RGBA16F, GR_GL_TEXTURE_2D);
     38         }
     39         break;
     40 #ifdef SK_VULKAN
     41     case kVulkan_GrBackend:
     42         if (kRGBA_8888_SkColorType == colorType) {
     43             VkFormat format =  caps->srgbSupport() ? VK_FORMAT_R8G8B8A8_SRGB
     44                                                    : VK_FORMAT_R8G8B8A8_UNORM;
     45             return GrBackendFormat::MakeVK(format);
     46         } else if (kRGBA_F16_SkColorType == colorType) {
     47             return GrBackendFormat::MakeVK(VK_FORMAT_R16G16B16A16_SFLOAT);
     48         }
     49         break;
     50 #endif
     51     case kMock_GrBackend:
     52         if (kRGBA_8888_SkColorType == colorType) {
     53             GrPixelConfig config = caps->srgbSupport() ? kSRGBA_8888_GrPixelConfig
     54                                                        : kRGBA_8888_GrPixelConfig;
     55             return GrBackendFormat::MakeMock(config);
     56         } else if (kRGBA_F16_SkColorType == colorType) {
     57             return GrBackendFormat::MakeMock(kRGBA_half_GrPixelConfig);
     58         }
     59         break;
     60     default:
     61         return GrBackendFormat(); // return an invalid format
     62     }
     63 
     64     return GrBackendFormat(); // return an invalid format
     65 }
     66 
     67 
     68 class SurfaceParameters {
     69 public:
     70     static const int kNumParams = 9;
     71     static const int kSampleCount = 5;
     72     static const int kMipMipCount = 8;
     73 
     74     SurfaceParameters()
     75             : fWidth(64)
     76             , fHeight(64)
     77             , fOrigin(kTopLeft_GrSurfaceOrigin)
     78             , fColorType(kRGBA_8888_SkColorType)
     79             , fColorSpace(SkColorSpace::MakeSRGB())
     80             , fSampleCount(1)
     81             , fSurfaceProps(0x0, kUnknown_SkPixelGeometry)
     82             , fShouldCreateMipMaps(true) {
     83     }
     84 
     85     int sampleCount() const { return fSampleCount; }
     86 
     87     // Modify the SurfaceParameters in just one way
     88     void modify(int i) {
     89         switch (i) {
     90         case 0:
     91             fWidth = 63;
     92             break;
     93         case 1:
     94             fHeight = 63;
     95             break;
     96         case 2:
     97             fOrigin = kBottomLeft_GrSurfaceOrigin;
     98             break;
     99         case 3:
    100             fColorType = kRGBA_F16_SkColorType;
    101             break;
    102         case 4:
    103             fColorSpace = SkColorSpace::MakeSRGBLinear();
    104             break;
    105         case kSampleCount:
    106             fSampleCount = 4;
    107             break;
    108         case 6:
    109             fSurfaceProps = SkSurfaceProps(0x0, kRGB_H_SkPixelGeometry);
    110             break;
    111         case 7:
    112             fSurfaceProps = SkSurfaceProps(SkSurfaceProps::kUseDeviceIndependentFonts_Flag,
    113                                            kUnknown_SkPixelGeometry);
    114             break;
    115         case 8:
    116             fShouldCreateMipMaps = false;
    117             break;
    118         }
    119     }
    120 
    121     // Create a DDL whose characterization captures the current settings
    122     std::unique_ptr<SkDeferredDisplayList> createDDL(GrContext* context) const {
    123         sk_sp<SkSurface> s = this->make(context);
    124         if (!s) {
    125             return nullptr;
    126         }
    127 
    128         int maxResourceCount;
    129         size_t maxResourceBytes;
    130         context->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
    131 
    132         // Note that Ganesh doesn't make use of the SkImageInfo's alphaType
    133         SkImageInfo ii = SkImageInfo::Make(fWidth, fHeight, fColorType,
    134                                            kPremul_SkAlphaType, fColorSpace);
    135 
    136         GrBackendFormat backendFormat = create_backend_format(context, fColorType);
    137 
    138         SkSurfaceCharacterization c = context->threadSafeProxy()->createCharacterization(
    139                                                 maxResourceBytes, ii, backendFormat, fSampleCount,
    140                                                 fOrigin, fSurfaceProps, fShouldCreateMipMaps);
    141         SkAssertResult(c.isValid());
    142 
    143         SkDeferredDisplayListRecorder r(c);
    144         SkCanvas* canvas = r.getCanvas();
    145         if (!canvas) {
    146             return nullptr;
    147         }
    148 
    149         canvas->drawRect(SkRect::MakeXYWH(10, 10, 10, 10), SkPaint());
    150         return r.detach();
    151     }
    152 
    153     // Create the surface with the current set of parameters
    154     sk_sp<SkSurface> make(GrContext* context) const {
    155         // Note that Ganesh doesn't make use of the SkImageInfo's alphaType
    156         SkImageInfo ii = SkImageInfo::Make(fWidth, fHeight, fColorType,
    157                                            kPremul_SkAlphaType, fColorSpace);
    158 
    159         return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, ii, fSampleCount,
    160                                            fOrigin, &fSurfaceProps, fShouldCreateMipMaps);
    161     }
    162 
    163     // Create a surface w/ the current parameters but make it non-textureable
    164     sk_sp<SkSurface> makeNonTextureable(GrContext* context, GrBackendTexture* backend) const {
    165         GrGpu* gpu = context->contextPriv().getGpu();
    166 
    167         GrPixelConfig config = SkImageInfo2GrPixelConfig(fColorType, nullptr, *context->caps());
    168         SkASSERT(kUnknown_GrPixelConfig != config);
    169 
    170         *backend = gpu->createTestingOnlyBackendTexture(nullptr, fWidth, fHeight,
    171                                                         config, true, GrMipMapped::kNo);
    172 
    173         if (!backend->isValid() || !gpu->isTestingOnlyBackendTexture(*backend)) {
    174             return nullptr;
    175         }
    176 
    177         sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTextureAsRenderTarget(
    178             context, *backend, fOrigin, fSampleCount, fColorType, nullptr, nullptr);
    179 
    180         if (!surface) {
    181             gpu->deleteTestingOnlyBackendTexture(backend);
    182             return nullptr;
    183         }
    184 
    185         return surface;
    186     }
    187 
    188     void cleanUpBackEnd(GrContext* context, GrBackendTexture* backend) const {
    189         GrGpu* gpu = context->contextPriv().getGpu();
    190 
    191         gpu->deleteTestingOnlyBackendTexture(backend);
    192     }
    193 
    194 private:
    195     int                 fWidth;
    196     int                 fHeight;
    197     GrSurfaceOrigin     fOrigin;
    198     SkColorType         fColorType;
    199     sk_sp<SkColorSpace> fColorSpace;
    200     int                 fSampleCount;
    201     SkSurfaceProps      fSurfaceProps;
    202     bool                fShouldCreateMipMaps;
    203 };
    204 
    205 // This tests SkSurfaceCharacterization/SkSurface compatibility
    206 DEF_GPUTEST_FOR_ALL_CONTEXTS(DDLSurfaceCharacterizationTest, reporter, ctxInfo) {
    207     GrContext* context = ctxInfo.grContext();
    208 
    209     // Create a bitmap that we can readback into
    210     SkImageInfo imageInfo = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType,
    211                                               kPremul_SkAlphaType);
    212     SkBitmap bitmap;
    213     bitmap.allocPixels(imageInfo);
    214 
    215     std::unique_ptr<SkDeferredDisplayList> ddl;
    216 
    217     // First, create a DDL using the stock SkSurface parameters
    218     {
    219         SurfaceParameters params;
    220 
    221         ddl = params.createDDL(context);
    222         SkAssertResult(ddl);
    223 
    224         // The DDL should draw into an SkSurface created with the same parameters
    225         sk_sp<SkSurface> s = params.make(context);
    226         if (!s) {
    227             return;
    228         }
    229 
    230         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
    231         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
    232     }
    233 
    234     // Then, alter each parameter in turn and check that the DDL & surface are incompatible
    235     for (int i = 0; i < SurfaceParameters::kNumParams; ++i) {
    236         SurfaceParameters params;
    237         params.modify(i);
    238 
    239         sk_sp<SkSurface> s = params.make(context);
    240         if (!s) {
    241             continue;
    242         }
    243 
    244         if (SurfaceParameters::kSampleCount == i) {
    245             SkSurface_Gpu* gpuSurf = static_cast<SkSurface_Gpu*>(s.get());
    246 
    247             int supportedSampleCount = context->caps()->getRenderTargetSampleCount(
    248                 params.sampleCount(),
    249                 gpuSurf->getDevice()->accessRenderTargetContext()->asRenderTargetProxy()->config());
    250             if (1 == supportedSampleCount) {
    251                 // If changing the sample count won't result in a different
    252                 // surface characterization, skip this step
    253                 continue;
    254             }
    255         }
    256 
    257         if (SurfaceParameters::kMipMipCount == i && !context->caps()->mipMapSupport()) {
    258             continue;
    259         }
    260 
    261         REPORTER_ASSERT(reporter, !s->draw(ddl.get()),
    262                         "DDLSurfaceCharacterizationTest failed on parameter: %d\n", i);
    263     }
    264 
    265     // Next test the compatibility of resource cache parameters
    266     {
    267         const SurfaceParameters params;
    268         sk_sp<SkSurface> s = params.make(context);
    269 
    270         int maxResourceCount;
    271         size_t maxResourceBytes;
    272         context->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
    273 
    274         context->setResourceCacheLimits(maxResourceCount, maxResourceBytes/2);
    275         REPORTER_ASSERT(reporter, !s->draw(ddl.get()));
    276 
    277         // DDL TODO: once proxies/ops can be de-instantiated we can re-enable these tests.
    278         // For now, DDLs are drawn once.
    279 #if 0
    280         // resource limits >= those at characterization time are accepted
    281         context->setResourceCacheLimits(2*maxResourceCount, maxResourceBytes);
    282         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
    283         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
    284 
    285         context->setResourceCacheLimits(maxResourceCount, 2*maxResourceBytes);
    286         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
    287         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
    288 
    289         context->setResourceCacheLimits(maxResourceCount, maxResourceBytes);
    290         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
    291         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
    292 #endif
    293     }
    294 
    295     // Test that the textureability of the DDL characterization can block a DDL draw
    296     {
    297         GrBackendTexture backend;
    298         const SurfaceParameters params;
    299         sk_sp<SkSurface> s = params.makeNonTextureable(context, &backend);
    300         if (s) {
    301             REPORTER_ASSERT(reporter, !s->draw(ddl.get()));
    302 
    303             s = nullptr;
    304             params.cleanUpBackEnd(context, &backend);
    305         }
    306     }
    307 
    308     // Make sure non-GPU-backed surfaces fail characterization
    309     {
    310         SkImageInfo ii = SkImageInfo::MakeN32(64, 64, kOpaque_SkAlphaType);
    311 
    312         sk_sp<SkSurface> rasterSurface = SkSurface::MakeRaster(ii);
    313         SkSurfaceCharacterization c;
    314         REPORTER_ASSERT(reporter, !rasterSurface->characterize(&c));
    315     }
    316 }
    317 
    318 static constexpr int kSize = 8;
    319 
    320 struct TextureReleaseChecker {
    321     TextureReleaseChecker() : fReleaseCount(0) {}
    322     int fReleaseCount;
    323     static void Release(void* self) {
    324         static_cast<TextureReleaseChecker*>(self)->fReleaseCount++;
    325     }
    326 };
    327 
    328 enum class DDLStage { kMakeImage, kDrawImage, kDetach, kDrawDDL };
    329 
    330 // This tests the ability to create and use wrapped textures in a DDL world
    331 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLWrapBackendTest, reporter, ctxInfo) {
    332     GrContext* context = ctxInfo.grContext();
    333     GrGpu* gpu = context->contextPriv().getGpu();
    334     for (auto lastStage : { DDLStage::kMakeImage, DDLStage::kDrawImage,
    335                             DDLStage::kDetach, DDLStage::kDrawDDL } ) {
    336         for (auto earlyImageReset : { false , true } ) {
    337             GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
    338                     nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, false, GrMipMapped::kNo);
    339             if (!backendTex.isValid()) {
    340                 continue;
    341             }
    342 
    343             SurfaceParameters params;
    344 
    345             sk_sp<SkSurface> s = params.make(context);
    346             if (!s) {
    347                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    348                 continue;
    349             }
    350 
    351             SkSurfaceCharacterization c;
    352             SkAssertResult(s->characterize(&c));
    353 
    354             std::unique_ptr<SkDeferredDisplayListRecorder> recorder(
    355                     new SkDeferredDisplayListRecorder(c));
    356 
    357             SkCanvas* canvas = recorder->getCanvas();
    358             if (!canvas) {
    359                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    360                 continue;
    361             }
    362 
    363             GrContext* deferredContext = canvas->getGrContext();
    364             if (!deferredContext) {
    365                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    366                 continue;
    367             }
    368 
    369             sk_sp<SkImage> image = SkImage::MakeFromAdoptedTexture(deferredContext, backendTex,
    370                                                                    kTopLeft_GrSurfaceOrigin,
    371                                                                    kRGBA_8888_SkColorType,
    372                                                                    kPremul_SkAlphaType, nullptr);
    373             // Adopted Textures are not supported in DDL
    374             REPORTER_ASSERT(reporter, !image);
    375 
    376             TextureReleaseChecker releaseChecker;
    377             image = SkImage::MakeFromTexture(deferredContext, backendTex,
    378                                              kTopLeft_GrSurfaceOrigin,
    379                                              kRGBA_8888_SkColorType,
    380                                              kPremul_SkAlphaType, nullptr,
    381                                              TextureReleaseChecker::Release, &releaseChecker);
    382 
    383             REPORTER_ASSERT(reporter, image);
    384             if (!image) {
    385                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    386                 continue;
    387             }
    388 
    389             if (DDLStage::kMakeImage == lastStage) {
    390                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    391                 image.reset();
    392                 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    393                 recorder.reset();
    394                 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    395                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    396                 continue;
    397             }
    398 
    399             canvas->drawImage(image.get(), 0, 0);
    400 
    401             if (earlyImageReset) {
    402                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    403                 image.reset();
    404                 // Ref should still be held by DDL recorder since we did the draw
    405                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    406             }
    407 
    408             if (DDLStage::kDrawImage == lastStage) {
    409                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    410                 recorder.reset();
    411                 if (earlyImageReset) {
    412                     REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    413                 } else {
    414                     REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    415                     image.reset();
    416                     REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    417                 }
    418                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    419                 continue;
    420             }
    421 
    422             std::unique_ptr<SkDeferredDisplayList> ddl = recorder->detach();
    423             if (DDLStage::kDetach == lastStage) {
    424                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    425                 recorder.reset();
    426 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION
    427                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    428 #endif
    429                 ddl.reset();
    430                 if (earlyImageReset) {
    431                     REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    432                 } else {
    433                     REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    434                     image.reset();
    435                     REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    436                 }
    437                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    438                 continue;
    439             }
    440 
    441             REPORTER_ASSERT(reporter, s->draw(ddl.get()));
    442 
    443             REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    444             recorder.reset();
    445 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION
    446             REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    447 #endif
    448             ddl.reset();
    449 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION
    450             REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    451 #endif
    452 
    453             // Force all draws to flush and sync by calling a read pixels
    454             SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
    455                                                       kPremul_SkAlphaType);
    456             SkBitmap bitmap;
    457             bitmap.allocPixels(imageInfo);
    458             s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
    459 
    460             if (earlyImageReset) {
    461                 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    462             } else {
    463                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    464                 image.reset();
    465                 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    466             }
    467 
    468             gpu->deleteTestingOnlyBackendTexture(&backendTex);
    469         }
    470     }
    471 }
    472 
    473 
    474 #endif
    475