blob: e85900127a6185c8f6fc2744e9738990d0b8fe60 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/zbi-format/graphics.h>
#include <map>
#include <fuzzer/FuzzedDataProvider.h>
#include "gfx/gfx.h"
static const unsigned kMaxDimension = 4096;
static bool IsBlendable(gfx_surface* a, gfx_surface* b) {
if (a->format != b->format) {
return false;
}
switch (a->format) {
case ZBI_PIXEL_FORMAT_ARGB_8888:
return true;
case ZBI_PIXEL_FORMAT_RGB_X888:
return true;
case ZBI_PIXEL_FORMAT_MONO_8:
return true;
default:
return false;
}
}
static gfx_surface* LookupSurface(FuzzedDataProvider* input,
const std::map<unsigned, gfx_surface*>* surfaces) {
auto id = input->ConsumeIntegral<unsigned>();
auto it = surfaces->find(id);
if (it == surfaces->end()) {
return nullptr;
}
return it->second;
}
unsigned ReadPixelFormat(FuzzedDataProvider* input) {
static const unsigned LEGAL_PIXEL_FORMATS[] = {
ZBI_PIXEL_FORMAT_RGB_565, ZBI_PIXEL_FORMAT_RGB_332, ZBI_PIXEL_FORMAT_RGB_2220,
ZBI_PIXEL_FORMAT_ARGB_8888, ZBI_PIXEL_FORMAT_RGB_X888, ZBI_PIXEL_FORMAT_MONO_8,
ZBI_PIXEL_FORMAT_NV12, ZBI_PIXEL_FORMAT_RGB_888,
};
return LEGAL_PIXEL_FORMATS[input->ConsumeIntegralInRange<uint8_t>(
0, sizeof(LEGAL_PIXEL_FORMATS) / sizeof(*LEGAL_PIXEL_FORMATS) - 1)];
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
FuzzedDataProvider input(data, size);
std::map<unsigned, gfx_surface*> surfaces;
while (true) {
switch (input.ConsumeIntegral<uint8_t>()) {
default:
case 0: {
for (auto [id, surface] : surfaces) {
gfx_surface_destroy(surface);
}
surfaces.clear();
return 0;
}
case 1: {
auto id = input.ConsumeIntegral<unsigned>();
if (surfaces.count(id)) {
break;
}
auto width = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension);
auto height = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension);
auto stride = width + input.ConsumeIntegral<uint8_t>();
auto pixel_format = ReadPixelFormat(&input);
auto flags = input.ConsumeIntegral<unsigned>() & (GFX_FLAG_FLUSH_CPU_CACHE);
if (auto* surface =
gfx_create_surface(nullptr, width, height, stride, pixel_format, flags)) {
surfaces[id] = surface;
}
break;
}
case 2: {
auto id = input.ConsumeIntegral<unsigned>();
auto it = surfaces.find(id);
if (it == surfaces.end()) {
break;
}
gfx_surface_destroy(it->second);
surfaces.erase(it);
break;
}
case 3:
if (auto* surface = LookupSurface(&input, &surfaces)) {
gfx_flush(surface);
}
break;
case 4:
if (auto* surface = LookupSurface(&input, &surfaces)) {
auto x = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto y = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto width = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension);
auto height = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension);
auto x2 = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto y2 = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
gfx_copyrect(surface, x, y, width, height, x2, y2);
}
break;
case 5:
if (auto* surface = LookupSurface(&input, &surfaces)) {
auto x = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto y = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto width = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension);
auto height = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension);
auto color = input.ConsumeIntegral<unsigned>();
gfx_fillrect(surface, x, y, width, height, color);
}
break;
case 6:
if (auto* surface = LookupSurface(&input, &surfaces)) {
auto x = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto y = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto color = input.ConsumeIntegral<unsigned>();
gfx_putpixel(surface, x, y, color);
}
break;
case 7:
if (auto* surface = LookupSurface(&input, &surfaces)) {
auto x = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto y = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto x2 = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto y2 = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto color = input.ConsumeIntegral<unsigned>();
gfx_line(surface, x, y, x2, y2, color);
}
break;
case 8:
if (auto* surface1 = LookupSurface(&input, &surfaces)) {
if (auto* surface2 = LookupSurface(&input, &surfaces)) {
if (!IsBlendable(surface1, surface2)) {
break;
}
auto destx = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto desty = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
gfx_surface_blend(surface1, surface2, destx, desty);
}
}
break;
case 9:
if (auto* surface1 = LookupSurface(&input, &surfaces)) {
if (auto* surface2 = LookupSurface(&input, &surfaces)) {
if (!IsBlendable(surface1, surface2)) {
break;
}
auto srcx = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto srcy = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto width = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension);
auto height = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension);
auto destx = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto desty = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
gfx_blend(surface1, surface2, srcx, srcy, width, height, destx, desty);
}
}
break;
case 10:
if (auto* surface1 = LookupSurface(&input, &surfaces)) {
if (auto* surface2 = LookupSurface(&input, &surfaces)) {
auto srcy = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto desty = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension);
auto height = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension);
gfx_copylines(surface1, surface2, srcy, desty, height);
}
}
break;
case 11:
if (auto* surface = LookupSurface(&input, &surfaces)) {
auto color = input.ConsumeIntegral<unsigned>();
gfx_clear(surface, color);
}
break;
}
}
}