/* * Copyright 2023 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "tools/gpu/ganesh/GrAtlasTools.h" #include "include/core/SkAlphaType.h" #include "include/core/SkBitmap.h" #include "include/core/SkColorSpace.h" #include "include/core/SkColorType.h" #include "include/core/SkDataTable.h" #include "include/core/SkImageInfo.h" #include "include/core/SkStream.h" #include "include/core/SkString.h" #include "include/encode/SkPngEncoder.h" #include "include/gpu/ganesh/GrDirectContext.h" #include "include/private/base/SkDebug.h" #include "src/gpu/ganesh/GrDirectContextPriv.h" #include "src/gpu/ganesh/GrSurfaceProxy.h" #include "src/gpu/ganesh/GrSurfaceProxyView.h" #include "src/gpu/ganesh/SurfaceContext.h" #include #include /** * Write the contents of the surface proxy to a PNG. Returns true if successful. * @param filename Full path to desired file */ static bool save_pixels(GrDirectContext* dContext, GrSurfaceProxyView view, GrColorType colorType, const char* filename) { if (!view.proxy()) { return false; } auto ii = SkImageInfo::Make( view.proxy()->dimensions(), kRGBA_8888_SkColorType, kPremul_SkAlphaType); SkBitmap bm; if (!bm.tryAllocPixels(ii)) { return false; } auto sContext = dContext->priv().makeSC(std::move(view), {colorType, kUnknown_SkAlphaType, nullptr}); if (!sContext || !sContext->asTextureProxy()) { return false; } bool result = sContext->readPixels(dContext, bm.pixmap(), {0, 0}); if (!result) { SkDebugf("------ failed to read pixels for %s\n", filename); return false; } // remove any previous version of this file remove(filename); SkFILEWStream file(filename); if (!file.isValid()) { SkDebugf("------ failed to create file: %s\n", filename); remove(filename); // remove any partial file return false; } if (!SkPngEncoder::Encode(&file, bm.pixmap(), {})) { SkDebugf("------ failed to encode %s\n", filename); remove(filename); // remove any partial file return false; } return true; } void GrAtlasManagerTools::Dump(const GrAtlasManager* am, GrDirectContext* context) { SkASSERT(am); static int gDumpCount = 0; for (int i = 0; i < skgpu::kMaskFormatCount; ++i) { if (am->fAtlases[i]) { const GrSurfaceProxyView* views = am->fAtlases[i]->getViews(); for (uint32_t pageIdx = 0; pageIdx < am->fAtlases[i]->numActivePages(); ++pageIdx) { SkASSERT(views[pageIdx].proxy()); SkString filename; #ifdef SK_BUILD_FOR_ANDROID filename.printf("/sdcard/fontcache_%d%d%d.png", gDumpCount, i, pageIdx); #else filename.printf("fontcache_%d%d%u.png", gDumpCount, i, pageIdx); #endif SkColorType ct = MaskFormatToColorType(GrAtlasManager::AtlasIndexToMaskFormat(i)); save_pixels( context, views[pageIdx], SkColorTypeToGrColorType(ct), filename.c_str()); } } } ++gDumpCount; } void GrAtlasManagerTools::SetAtlasDimensionsToMinimum(GrAtlasManager* am) { SkASSERT(am); // Delete any old atlases. // This should be safe to do as long as we are not in the middle of a flush. for (int i = 0; i < skgpu::kMaskFormatCount; i++) { am->fAtlases[i] = nullptr; } // Set all the atlas sizes to 1x1 plot each. new (&am->fAtlasConfig) GrDrawOpAtlasConfig{}; } void GrAtlasManagerTools::SetMaxPages(GrAtlasManager* am, uint32_t maxPages) { SkASSERT(am); for (int i = 0; i < skgpu::kMaskFormatCount; i++) { if (am->fAtlases[i]) { GrDrawOpAtlasTools::SetMaxPages(am->fAtlases[i].get(), maxPages); } } } int GrDrawOpAtlasTools::NumAllocated(const GrDrawOpAtlas* doa) { SkASSERT(doa); int count = 0; for (uint32_t i = 0; i < doa->maxPages(); ++i) { if (doa->fViews[i].proxy()->isInstantiated()) { ++count; } } return count; } void GrDrawOpAtlasTools::SetMaxPages(GrDrawOpAtlas* doa, uint32_t maxPages) { SkASSERT(!doa->fNumActivePages); doa->fMaxPages = maxPages; }