blob: 6fc2072df1c7dedd27a324f33492a9cb2b4a6585 [file] [log] [blame]
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "tests/Test.h"
#include "include/core/SkColorSpace.h"
#include "include/gpu/graphite/BackendTexture.h"
#include "include/gpu/graphite/Context.h"
#include "include/gpu/graphite/Recorder.h"
#include "src/core/SkAutoPixmapStorage.h"
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "src/gpu/graphite/Surface_Graphite.h"
#include "tests/TestUtils.h"
#include "tools/ToolUtils.h"
using namespace skgpu;
using namespace skgpu::graphite;
namespace {
const SkISize kSize = { 32, 32 };
constexpr int kNumMipLevels = 6;
void check_solid_pixmap(skiatest::Reporter* reporter,
const SkColor4f& expected,
const SkPixmap& actual,
SkColorType ct,
const char* label) {
const float kTols[4] = { 0.01f, 0.01f, 0.01f, 0.01f };
auto error = std::function<ComparePixmapsErrorReporter>(
[reporter, ct, label, expected](int x, int y, const float diffs[4]) {
SkASSERT(x >= 0 && y >= 0);
ERRORF(reporter, "%s %s - mismatch at %d, %d "
"expected: (%.2f, %.2f, %.2f, %.2f) "
"- diffs: (%.2f, %.2f, %.2f, %.2f)",
ToolUtils::colortype_name(ct), label, x, y,
expected.fR, expected.fG, expected.fB, expected.fA,
diffs[0], diffs[1], diffs[2], diffs[3]);
});
CheckSolidPixels(expected, actual, kTols, error);
}
void update_backend_texture(Recorder* recorder,
const BackendTexture& backendTex,
SkColorType ct,
bool withMips,
const SkColor4f colors[6]) {
SkPixmap pixmaps[6];
std::unique_ptr<char[]> memForPixmaps;
int numMipLevels = ToolUtils::make_pixmaps(ct, kPremul_SkAlphaType, withMips, colors, pixmaps,
&memForPixmaps);
SkASSERT(numMipLevels == 1 || numMipLevels == kNumMipLevels);
SkASSERT(kSize == pixmaps[0].dimensions());
recorder->updateBackendTexture(backendTex, pixmaps, numMipLevels);
}
BackendTexture create_backend_texture(skiatest::Reporter* reporter,
const Caps* caps,
Recorder* recorder,
SkColorType ct,
bool withMips,
Renderable renderable,
const SkColor4f colors[6]) {
Mipmapped mipmapped = withMips ? Mipmapped::kYes : Mipmapped::kNo;
TextureInfo info = caps->getDefaultSampledTextureInfo(ct,
mipmapped,
Protected::kNo,
renderable);
BackendTexture backendTex = recorder->createBackendTexture(kSize, info);
REPORTER_ASSERT(reporter, backendTex.isValid());
update_backend_texture(recorder, backendTex, ct, withMips, colors);
return backendTex;
}
sk_sp<SkImage> wrap_backend_texture(skiatest::Reporter* reporter,
Recorder* recorder,
const skgpu::graphite::BackendTexture& backendTex,
SkColorType ct,
bool withMips) {
sk_sp<SkImage> image = SkImage::MakeGraphiteFromBackendTexture(recorder,
backendTex,
ct,
kPremul_SkAlphaType,
/* colorSpace= */ nullptr);
REPORTER_ASSERT(reporter, image);
REPORTER_ASSERT(reporter, image->hasMipmaps() == withMips);
return image;
}
void check_levels(skiatest::Reporter* reporter,
Context* context,
Recorder* recorder,
SkImage* image,
bool withMips,
const SkColor4f colors[6]) {
int numLevels = withMips ? kNumMipLevels : 1;
SkSamplingOptions sampling = withMips
? SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNearest)
: SkSamplingOptions(SkFilterMode::kNearest);
SkImageInfo surfaceII = SkImageInfo::Make(kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
sk_sp<SkSurface> surf = SkSurface::MakeGraphite(recorder, surfaceII, Mipmapped::kNo);
SkCanvas* canvas = surf->getCanvas();
for (int i = 0, drawSize = kSize.width(); i < numLevels; ++i, drawSize /= 2) {
if (i == 5) {
// TODO: Metal currently never draws the top-most mip-level (skbug.com/13792)
continue;
}
SkImageInfo readbackII = SkImageInfo::Make({drawSize, drawSize}, kRGBA_8888_SkColorType,
kUnpremul_SkAlphaType);
SkAutoPixmapStorage actual;
SkAssertResult(actual.tryAlloc(readbackII));
actual.erase(SkColors::kTransparent);
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc);
canvas->clear(SkColors::kTransparent);
#if 0
// This option gives greater control over the tilemodes and texture scaling
SkMatrix lm;
lm.setScale(1.0f / (1 << i), 1.0f / (1 << i));
paint.setShader(image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, sampling, lm));
canvas->drawRect(SkRect::MakeWH(drawSize, drawSize), paint);
#else
canvas->drawImageRect(image, SkRect::MakeWH(drawSize, drawSize), sampling, &paint);
#endif
if (!surf->readPixels(actual, 0, 0)) {
ERRORF(reporter, "readPixels failed");
return;
}
SkString str;
str.appendf("mip-level %d", i);
check_solid_pixmap(reporter, colors[i], actual, image->colorType(), str.c_str());
}
}
} // anonymous namespace
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(UpdateImageBackendTextureTest, reporter, context) {
// TODO: Remove this check once Vulkan supports creating default TexutreInfo from caps and we
// implement createBackendTexture.
if (context->backend() == BackendApi::kVulkan) {
return;
}
const Caps* caps = context->priv().caps();
std::unique_ptr<Recorder> recorder = context->makeRecorder();
constexpr SkColor4f kColors[6] = {
{ 1.0f, 0.0f, 0.0f, 1.0f }, // R
{ 0.0f, 1.0f, 0.0f, 0.9f }, // G
{ 0.0f, 0.0f, 1.0f, 0.7f }, // B
{ 0.0f, 1.0f, 1.0f, 0.5f }, // C
{ 1.0f, 0.0f, 1.0f, 0.3f }, // M
{ 1.0f, 1.0f, 0.0f, 0.2f }, // Y
};
constexpr SkColor4f kColorsNew[6] = {
{ 1.0f, 1.0f, 0.0f, 0.2f }, // Y
{ 1.0f, 0.0f, 0.0f, 1.0f }, // R
{ 0.0f, 1.0f, 0.0f, 0.9f }, // G
{ 0.0f, 0.0f, 1.0f, 0.7f }, // B
{ 0.0f, 1.0f, 1.0f, 0.5f }, // C
{ 1.0f, 0.0f, 1.0f, 0.3f }, // M
};
// TODO: test more than just RGBA8
for (SkColorType ct : { kRGBA_8888_SkColorType }) {
for (bool withMips : { true, false }) {
for (Renderable renderable : { Renderable::kYes, Renderable::kNo }) {
BackendTexture backendTex = create_backend_texture(reporter, caps, recorder.get(),
ct, withMips, renderable,
kColors);
sk_sp<SkImage> image = wrap_backend_texture(reporter, recorder.get(), backendTex,
ct, withMips);
if (!image) {
continue;
}
check_levels(reporter, context, recorder.get(), image.get(), withMips, kColors);
image.reset();
update_backend_texture(recorder.get(), backendTex, ct, withMips, kColorsNew);
image = wrap_backend_texture(reporter, recorder.get(), backendTex, ct, withMips);
if (!image) {
continue;
}
check_levels(reporter, context, recorder.get(), image.get(), withMips, kColorsNew);
image.reset();
recorder->deleteBackendTexture(backendTex);
}
}
}
}