skia2/tools/fiddle/fiddle_main.cpp
Brian Salomon f4ba4ec796 Revert "Revert "Revert "Revert "Don't build GL on Metal, Vulkan, Dawn, Direct3D bots""""
Updated to use sentinel GL context even when GL backend is not built.

This reverts commit 1171d314ef.

Change-Id: Ia94bbe4865ddd4e898446c13886877c539f0eb0b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/277976
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
2020-03-20 17:11:58 +00:00

354 lines
12 KiB
C++

/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <string>
#include "src/core/SkAutoPixmapStorage.h"
#include "src/core/SkMipMap.h"
#include "src/core/SkUtils.h"
#include "tools/flags/CommandLineFlags.h"
#include "tools/fiddle/fiddle_main.h"
static DEFINE_double(duration, 1.0,
"The total duration, in seconds, of the animation we are drawing.");
static DEFINE_double(frame, 1.0,
"A double value in [0, 1] that specifies the point in animation to draw.");
#include "include/gpu/GrBackendSurface.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrGpu.h"
#include "src/gpu/GrRenderTarget.h"
#include "tools/gpu/gl/GLTestContext.h"
// Globals externed in fiddle_main.h
sk_sp<GrTexture> backingTexture; // not externed
GrBackendTexture backEndTexture;
sk_sp<GrRenderTarget> backingRenderTarget; // not externed
GrBackendRenderTarget backEndRenderTarget;
sk_sp<GrTexture> backingTextureRenderTarget; // not externed
GrBackendTexture backEndTextureRenderTarget;
SkBitmap source;
sk_sp<SkImage> image;
double duration; // The total duration of the animation in seconds.
double frame; // A value in [0, 1] of where we are in the animation.
// Global used by the local impl of SkDebugf.
std::ostringstream gTextOutput;
// Global to record the GL driver info via create_grcontext().
std::ostringstream gGLDriverInfo;
void SkDebugf(const char * fmt, ...) {
va_list args;
va_start(args, fmt);
char formatbuffer[1024];
int n = vsnprintf(formatbuffer, sizeof(formatbuffer), fmt, args);
va_end(args);
if (n>=0 && n<=int(sizeof(formatbuffer))) {
gTextOutput.write(formatbuffer, n);
}
}
static void encode_to_base64(const void* data, size_t size, FILE* out) {
const uint8_t* input = reinterpret_cast<const uint8_t*>(data);
const uint8_t* end = &input[size];
static const char codes[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz0123456789+/";
while (input != end) {
uint8_t b = (*input & 0xFC) >> 2;
fputc(codes[b], out);
b = (*input & 0x03) << 4;
++input;
if (input == end) {
fputc(codes[b], out);
fputs("==", out);
return;
}
b |= (*input & 0xF0) >> 4;
fputc(codes[b], out);
b = (*input & 0x0F) << 2;
++input;
if (input == end) {
fputc(codes[b], out);
fputc('=', out);
return;
}
b |= (*input & 0xC0) >> 6;
fputc(codes[b], out);
b = *input & 0x3F;
fputc(codes[b], out);
++input;
}
}
static void dump_output(const void* data, size_t size,
const char* name, bool last = true) {
printf("\t\"%s\": \"", name);
encode_to_base64(data, size, stdout);
fputs(last ? "\"\n" : "\",\n", stdout);
}
static void dump_output(const sk_sp<SkData>& data,
const char* name, bool last = true) {
if (data) {
dump_output(data->data(), data->size(), name, last);
}
}
static sk_sp<SkData> encode_snapshot(const sk_sp<SkSurface>& surface) {
sk_sp<SkImage> img(surface->makeImageSnapshot());
return img ? img->encodeToData() : nullptr;
}
static SkCanvas* prepare_canvas(SkCanvas * canvas) {
canvas->clear(SK_ColorWHITE);
return canvas;
}
#ifdef SK_GL
static bool setup_backend_objects(GrContext* context,
const SkBitmap& bm,
const DrawOptions& options) {
if (!context) {
fputs("Context is null.\n", stderr);
return false;
}
auto resourceProvider = context->priv().resourceProvider();
// This config must match the SkColorType used in draw.cpp in the SkImage and Surface factories
auto format = resourceProvider->caps()->getDefaultBackendFormat(
SkColorTypeToGrColorType(kRGBA_8888_SkColorType), GrRenderable::kNo);
auto renderableFormat = resourceProvider->caps()->getDefaultBackendFormat(
SkColorTypeToGrColorType(kRGBA_8888_SkColorType), GrRenderable::kYes);
if (!bm.empty()) {
SkPixmap originalPixmap;
SkPixmap* pixmap = &originalPixmap;
if (!bm.peekPixels(&originalPixmap)) {
fputs("Unable to peekPixels.\n", stderr);
return false;
}
SkAutoPixmapStorage rgbaPixmap;
if (kN32_SkColorType != kRGBA_8888_SkColorType) {
if (!rgbaPixmap.tryAlloc(bm.info().makeColorType(kRGBA_8888_SkColorType))) {
fputs("Unable to alloc rgbaPixmap.\n", stderr);
return false;
}
if (!bm.readPixels(rgbaPixmap)) {
fputs("Unable to read rgbaPixmap.\n", stderr);
return false;
}
pixmap = &rgbaPixmap;
}
int mipLevelCount = GrMipMapped::kYes == options.fMipMapping
? SkMipMap::ComputeLevelCount(bm.width(), bm.height())
: 1;
std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
texels[0].fPixels = pixmap->addr();
texels[0].fRowBytes = pixmap->rowBytes();
for (int i = 1; i < mipLevelCount; i++) {
texels[i].fPixels = nullptr;
texels[i].fRowBytes = 0;
}
backingTexture = resourceProvider->createTexture(
bm.dimensions(), format, GrColorType::kRGBA_8888, GrRenderable::kNo, 1,
SkBudgeted::kNo, GrProtected::kNo, texels.get(), mipLevelCount);
if (!backingTexture) {
fputs("Failed to create backingTexture.\n", stderr);
return false;
}
backEndTexture = backingTexture->getBackendTexture();
if (!backEndTexture.isValid()) {
fputs("BackingTexture is invalid.\n", stderr);
return false;
}
}
SkISize offscreenDims = {options.fOffScreenWidth, options.fOffScreenHeight};
SkAutoTMalloc<uint32_t> data(offscreenDims.area());
sk_memset32(data.get(), 0, offscreenDims.area());
{
// This backend object should be renderable but not textureable. Given the limitations
// of how we're creating it though it will wind up being secretly textureable.
// We use this fact to initialize it with data but don't allow mipmaps
GrMipLevel level0 = { data.get(), offscreenDims.width()*sizeof(uint32_t) };
sk_sp<GrTexture> tmp = resourceProvider->createTexture(
offscreenDims, renderableFormat, GrColorType::kRGBA_8888, GrRenderable::kYes,
options.fOffScreenSampleCount, SkBudgeted::kNo, GrProtected::kNo, &level0, 1);
if (!tmp || !tmp->asRenderTarget()) {
fputs("GrTexture is invalid.\n", stderr);
return false;
}
backingRenderTarget = sk_ref_sp(tmp->asRenderTarget());
backEndRenderTarget = backingRenderTarget->getBackendRenderTarget();
if (!backEndRenderTarget.isValid()) {
fputs("BackEndRenderTarget is invalid.\n", stderr);
return false;
}
}
{
int mipLevelCount =
GrMipMapped::kYes == options.fOffScreenMipMapping
? SkMipMap::ComputeLevelCount(offscreenDims.width(), offscreenDims.height())
: 1;
std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
texels[0].fPixels = data.get();
texels[0].fRowBytes = offscreenDims.width()*sizeof(uint32_t);
for (int i = 1; i < mipLevelCount; i++) {
texels[i].fPixels = nullptr;
texels[i].fRowBytes = 0;
}
backingTextureRenderTarget = resourceProvider->createTexture(
offscreenDims, renderableFormat, GrColorType::kRGBA_8888, GrRenderable::kYes,
options.fOffScreenSampleCount, SkBudgeted::kNo, GrProtected::kNo, texels.get(),
mipLevelCount);
if (!backingTextureRenderTarget || !backingTextureRenderTarget->asRenderTarget()) {
fputs("backingTextureRenderTarget is invalid.\n", stderr);
return false;
}
backEndTextureRenderTarget = backingTextureRenderTarget->getBackendTexture();
if (!backEndTextureRenderTarget.isValid()) {
fputs("backEndTextureRenderTarget is invalid.\n", stderr);
return false;
}
}
return true;
}
#endif
int main(int argc, char** argv) {
CommandLineFlags::Parse(argc, argv);
duration = FLAGS_duration;
frame = FLAGS_frame;
DrawOptions options = GetDrawOptions();
// If textOnly then only do one type of image, otherwise the text
// output is duplicated for each type.
if (options.textOnly) {
options.raster = true;
options.gpu = false;
options.pdf = false;
options.skp = false;
}
if (options.source) {
sk_sp<SkData> data(SkData::MakeFromFileName(options.source));
if (!data) {
perror(options.source);
return 1;
} else {
image = SkImage::MakeFromEncoded(std::move(data));
if (!image) {
perror("Unable to decode the source image.");
return 1;
}
SkAssertResult(image->asLegacyBitmap(&source));
}
}
sk_sp<SkData> rasterData, gpuData, pdfData, skpData;
SkColorType colorType = kN32_SkColorType;
sk_sp<SkColorSpace> colorSpace = nullptr;
if (options.f16) {
SkASSERT(options.srgb);
colorType = kRGBA_F16_SkColorType;
colorSpace = SkColorSpace::MakeSRGBLinear();
} else if (options.srgb) {
colorSpace = SkColorSpace::MakeSRGB();
}
SkImageInfo info = SkImageInfo::Make(options.size.width(), options.size.height(), colorType,
kPremul_SkAlphaType, colorSpace);
if (options.raster) {
auto rasterSurface = SkSurface::MakeRaster(info);
srand(0);
draw(prepare_canvas(rasterSurface->getCanvas()));
rasterData = encode_snapshot(rasterSurface);
}
#ifdef SK_GL
if (options.gpu) {
std::unique_ptr<sk_gpu_test::GLTestContext> glContext;
sk_sp<GrContext> grContext = create_grcontext(gGLDriverInfo, &glContext);
if (!grContext) {
fputs("Unable to get GrContext.\n", stderr);
} else {
if (!setup_backend_objects(grContext.get(), source, options)) {
fputs("Unable to create backend objects.\n", stderr);
exit(1);
}
auto surface = SkSurface::MakeRenderTarget(grContext.get(), SkBudgeted::kNo, info);
if (!surface) {
fputs("Unable to get render surface.\n", stderr);
exit(1);
}
srand(0);
draw(prepare_canvas(surface->getCanvas()));
gpuData = encode_snapshot(surface);
}
}
#endif
if (options.pdf) {
SkDynamicMemoryWStream pdfStream;
auto document = SkPDF::MakeDocument(&pdfStream);
if (document) {
srand(0);
draw(prepare_canvas(document->beginPage(options.size.width(), options.size.height())));
document->close();
pdfData = pdfStream.detachAsData();
}
}
if (options.skp) {
auto size = SkSize::Make(options.size);
SkPictureRecorder recorder;
srand(0);
draw(prepare_canvas(recorder.beginRecording(size.width(), size.height())));
auto picture = recorder.finishRecordingAsPicture();
SkDynamicMemoryWStream skpStream;
picture->serialize(&skpStream);
skpData = skpStream.detachAsData();
}
printf("{\n");
if (!options.textOnly) {
dump_output(rasterData, "Raster", false);
dump_output(gpuData, "Gpu", false);
dump_output(pdfData, "Pdf", false);
dump_output(skpData, "Skp", false);
} else {
std::string textoutput = gTextOutput.str();
dump_output(textoutput.c_str(), textoutput.length(), "Text", false);
}
std::string glinfo = gGLDriverInfo.str();
dump_output(glinfo.c_str(), glinfo.length(), "GLInfo", true);
printf("}\n");
return 0;
}