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 class SurfaceParameters {
     24 public:
     25     static const int kNumParams = 8;
     26     static const int kSampleCount = 5;
     27 
     28     SurfaceParameters()
     29             : fWidth(64)
     30             , fHeight(64)
     31             , fOrigin(kTopLeft_GrSurfaceOrigin)
     32             , fColorType(kRGBA_8888_SkColorType)
     33             , fColorSpace(SkColorSpace::MakeSRGB())
     34             , fSampleCount(1)
     35             , fSurfaceProps(0x0, kUnknown_SkPixelGeometry) {}
     36 
     37     int sampleCount() const { return fSampleCount; }
     38 
     39     // Modify the SurfaceParameters in just one way
     40     void modify(int i) {
     41         switch (i) {
     42         case 0:
     43             fWidth = 63;
     44             break;
     45         case 1:
     46             fHeight = 63;
     47             break;
     48         case 2:
     49             fOrigin = kBottomLeft_GrSurfaceOrigin;
     50             break;
     51         case 3:
     52             fColorType = kRGBA_F16_SkColorType;
     53             break;
     54         case 4:
     55             fColorSpace = SkColorSpace::MakeSRGBLinear();
     56             break;
     57         case kSampleCount:
     58             fSampleCount = 4;
     59             break;
     60         case 6:
     61             fSurfaceProps = SkSurfaceProps(0x0, kRGB_H_SkPixelGeometry);
     62             break;
     63         case 7:
     64             fSurfaceProps = SkSurfaceProps(SkSurfaceProps::kUseDeviceIndependentFonts_Flag,
     65                                            kUnknown_SkPixelGeometry);
     66             break;
     67         }
     68     }
     69 
     70     // Create the surface with the current set of parameters
     71     sk_sp<SkSurface> make(GrContext* context) const {
     72         // Note that Ganesh doesn't make use of the SkImageInfo's alphaType
     73         SkImageInfo ii = SkImageInfo::Make(fWidth, fHeight, fColorType,
     74                                            kPremul_SkAlphaType, fColorSpace);
     75 
     76         return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, ii, fSampleCount,
     77                                            fOrigin, &fSurfaceProps);
     78     }
     79 
     80 private:
     81     int                 fWidth;
     82     int                 fHeight;
     83     GrSurfaceOrigin     fOrigin;
     84     SkColorType         fColorType;
     85     sk_sp<SkColorSpace> fColorSpace;
     86     int                 fSampleCount;
     87     SkSurfaceProps      fSurfaceProps;
     88 };
     89 
     90 // This tests SkSurfaceCharacterization/SkSurface compatibility
     91 DEF_GPUTEST_FOR_ALL_CONTEXTS(SkSurfaceCharacterization, reporter, ctxInfo) {
     92     GrContext* context = ctxInfo.grContext();
     93 
     94     // Create a bitmap that we can readback into
     95     SkImageInfo imageInfo = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType,
     96                                               kPremul_SkAlphaType);
     97     SkBitmap bitmap;
     98     bitmap.allocPixels(imageInfo);
     99 
    100     std::unique_ptr<SkDeferredDisplayList> ddl;
    101 
    102     // First, create a DDL using the stock SkSurface parameters
    103     {
    104         SurfaceParameters params;
    105 
    106         sk_sp<SkSurface> s = params.make(context);
    107         if (!s) {
    108             return;
    109         }
    110 
    111         SkSurfaceCharacterization c;
    112         SkAssertResult(s->characterize(&c));
    113 
    114         SkDeferredDisplayListRecorder r(c);
    115         SkCanvas* canvas = r.getCanvas();
    116         if (!canvas) {
    117             return;
    118         }
    119 
    120         canvas->drawRect(SkRect::MakeXYWH(10, 10, 10, 10), SkPaint());
    121         ddl = r.detach();
    122 
    123         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
    124         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
    125     }
    126 
    127     // Then, alter each parameter in turn and check that the DDL & surface are incompatible
    128     for (int i = 0; i < SurfaceParameters::kNumParams; ++i) {
    129         SurfaceParameters params;
    130         params.modify(i);
    131 
    132         sk_sp<SkSurface> s = params.make(context);
    133         if (!s) {
    134             continue;
    135         }
    136 
    137         if (SurfaceParameters::kSampleCount == i) {
    138             SkSurface_Gpu* gpuSurf = static_cast<SkSurface_Gpu*>(s.get());
    139 
    140             int supportedSampleCount = context->caps()->getSampleCount(
    141                 params.sampleCount(),
    142                 gpuSurf->getDevice()->accessRenderTargetContext()->asRenderTargetProxy()->config());
    143             if (1 == supportedSampleCount) {
    144                 // If changing the sample count won't result in a different
    145                 // surface characterization, skip this step
    146                 continue;
    147             }
    148         }
    149 
    150         REPORTER_ASSERT(reporter, !s->draw(ddl.get()));
    151     }
    152 
    153     // Next test the compatibility of resource cache parameters
    154     {
    155         const SurfaceParameters params;
    156         sk_sp<SkSurface> s = params.make(context);
    157 
    158         int maxResourceCount;
    159         size_t maxResourceBytes;
    160         context->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
    161 
    162         context->setResourceCacheLimits(maxResourceCount/2, maxResourceBytes);
    163         REPORTER_ASSERT(reporter, !s->draw(ddl.get()));
    164 
    165         context->setResourceCacheLimits(maxResourceCount, maxResourceBytes/2);
    166         REPORTER_ASSERT(reporter, !s->draw(ddl.get()));
    167 
    168         // DDL TODO: once proxies/ops can be de-instantiated we can re-enable these tests.
    169         // For now, DDLs are drawn once.
    170 #if 0
    171         // resource limits >= those at characterization time are accepted
    172         context->setResourceCacheLimits(2*maxResourceCount, maxResourceBytes);
    173         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
    174         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
    175 
    176         context->setResourceCacheLimits(maxResourceCount, 2*maxResourceBytes);
    177         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
    178         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
    179 
    180         context->setResourceCacheLimits(maxResourceCount, maxResourceBytes);
    181         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
    182         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
    183 #endif
    184     }
    185 
    186     // Make sure non-GPU-backed surfaces fail characterization
    187     {
    188         SkImageInfo ii = SkImageInfo::MakeN32(64, 64, kOpaque_SkAlphaType);
    189 
    190         sk_sp<SkSurface> rasterSurface = SkSurface::MakeRaster(ii);
    191         SkSurfaceCharacterization c;
    192         REPORTER_ASSERT(reporter, !rasterSurface->characterize(&c));
    193     }
    194 }
    195 
    196 static constexpr int kSize = 8;
    197 
    198 struct TextureReleaseChecker {
    199     TextureReleaseChecker() : fReleaseCount(0) {}
    200     int fReleaseCount;
    201     static void Release(void* self) {
    202         static_cast<TextureReleaseChecker*>(self)->fReleaseCount++;
    203     }
    204 };
    205 
    206 enum class DDLStage { kMakeImage, kDrawImage, kDetach, kDrawDDL };
    207 
    208 // This tests the ability to create and use wrapped textures in a DDL world
    209 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLWrapBackendTest, reporter, ctxInfo) {
    210     GrContext* context = ctxInfo.grContext();
    211     GrGpu* gpu = context->contextPriv().getGpu();
    212     for (auto lastStage : { DDLStage::kMakeImage, DDLStage::kDrawImage,
    213                             DDLStage::kDetach, DDLStage::kDrawDDL } ) {
    214         for (auto earlyImageReset : { false , true } ) {
    215             GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
    216                     nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, false, GrMipMapped::kNo);
    217             if (!backendTex.isValid()) {
    218                 continue;
    219             }
    220 
    221             SurfaceParameters params;
    222 
    223             sk_sp<SkSurface> s = params.make(context);
    224             if (!s) {
    225                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    226                 continue;
    227             }
    228 
    229             SkSurfaceCharacterization c;
    230             SkAssertResult(s->characterize(&c));
    231 
    232             std::unique_ptr<SkDeferredDisplayListRecorder> recorder(
    233                     new SkDeferredDisplayListRecorder(c));
    234 
    235             SkCanvas* canvas = recorder->getCanvas();
    236             if (!canvas) {
    237                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    238                 continue;
    239             }
    240 
    241             GrContext* deferredContext = canvas->getGrContext();
    242             if (!deferredContext) {
    243                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    244                 continue;
    245             }
    246 
    247             sk_sp<SkImage> image = SkImage::MakeFromAdoptedTexture(deferredContext, backendTex,
    248                                                                    kTopLeft_GrSurfaceOrigin,
    249                                                                    kRGBA_8888_SkColorType,
    250                                                                    kPremul_SkAlphaType, nullptr);
    251             // Adopted Textures are not supported in DDL
    252             REPORTER_ASSERT(reporter, !image);
    253 
    254             TextureReleaseChecker releaseChecker;
    255             image = SkImage::MakeFromTexture(deferredContext, backendTex,
    256                                              kTopLeft_GrSurfaceOrigin,
    257                                              kRGBA_8888_SkColorType,
    258                                              kPremul_SkAlphaType, nullptr,
    259                                              TextureReleaseChecker::Release, &releaseChecker);
    260 
    261             REPORTER_ASSERT(reporter, image);
    262             if (!image) {
    263                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    264                 continue;
    265             }
    266 
    267             if (DDLStage::kMakeImage == lastStage) {
    268                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    269                 image.reset();
    270                 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    271                 recorder.reset();
    272                 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    273                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    274                 continue;
    275             }
    276 
    277             canvas->drawImage(image.get(), 0, 0);
    278 
    279             if (earlyImageReset) {
    280                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    281                 image.reset();
    282                 // Ref should still be held by DDL recorder since we did the draw
    283                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    284             }
    285 
    286             if (DDLStage::kDrawImage == lastStage) {
    287                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    288                 recorder.reset();
    289                 if (earlyImageReset) {
    290                     REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    291                 } else {
    292                     REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    293                     image.reset();
    294                     REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    295                 }
    296                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    297                 continue;
    298             }
    299 
    300             std::unique_ptr<SkDeferredDisplayList> ddl = recorder->detach();
    301             if (DDLStage::kDetach == lastStage) {
    302                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    303                 recorder.reset();
    304 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION
    305                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    306 #endif
    307                 ddl.reset();
    308                 if (earlyImageReset) {
    309                     REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    310                 } else {
    311                     REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    312                     image.reset();
    313                     REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    314                 }
    315                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
    316                 continue;
    317             }
    318 
    319             REPORTER_ASSERT(reporter, s->draw(ddl.get()));
    320 
    321             REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    322             recorder.reset();
    323 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION
    324             REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    325 #endif
    326             ddl.reset();
    327 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION
    328             REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    329 #endif
    330 
    331             // Force all draws to flush and sync by calling a read pixels
    332             SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
    333                                                       kPremul_SkAlphaType);
    334             SkBitmap bitmap;
    335             bitmap.allocPixels(imageInfo);
    336             s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
    337 
    338             if (earlyImageReset) {
    339                 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    340             } else {
    341                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
    342                 image.reset();
    343                 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
    344             }
    345 
    346             gpu->deleteTestingOnlyBackendTexture(&backendTex);
    347         }
    348     }
    349 }
    350 
    351 
    352 #endif
    353