2016-11-11 21:08:03 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2016 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "Test.h"
|
|
|
|
|
|
|
|
#if SK_SUPPORT_GPU
|
|
|
|
#include "GrContext.h"
|
|
|
|
#include "GrRenderTargetContext.h"
|
|
|
|
#include "GrTexture.h"
|
|
|
|
#include "effects/GrSimpleTextureEffect.h"
|
|
|
|
|
|
|
|
template <typename I>
|
|
|
|
static SK_WHEN(std::is_integral<I>::value && 4 == sizeof(I), void)
|
2017-01-04 19:11:36 +00:00
|
|
|
check_pixels(skiatest::Reporter* reporter, int w, int h, const I exepctedData[],
|
|
|
|
const I actualData[], const char* testName) {
|
2016-11-11 21:08:03 +00:00
|
|
|
for (int j = 0; j < h; ++j) {
|
|
|
|
for (int i = 0; i < w; ++i) {
|
|
|
|
I expected = exepctedData[j * w + i];
|
|
|
|
I actual = actualData[j * w + i];
|
|
|
|
if (expected != actual) {
|
2017-01-04 19:11:36 +00:00
|
|
|
ERRORF(reporter, "[%s] Expected 0x08%x, got 0x%08x at %d, %d.", testName, expected,
|
|
|
|
actual, i, j);
|
2016-11-11 21:08:03 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(IntTexture, reporter, ctxInfo) {
|
|
|
|
GrContext* context = ctxInfo.grContext();
|
|
|
|
if (!context->caps()->isConfigTexturable(kRGBA_8888_sint_GrPixelConfig)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
static const int kS = UINT8_MAX + 1;
|
2017-01-25 17:10:37 +00:00
|
|
|
static const size_t kRowBytes = kS * sizeof(int32_t);
|
|
|
|
|
2016-11-11 21:08:03 +00:00
|
|
|
GrSurfaceDesc desc;
|
|
|
|
desc.fConfig = kRGBA_8888_sint_GrPixelConfig;
|
|
|
|
desc.fWidth = kS;
|
|
|
|
desc.fHeight = kS;
|
|
|
|
|
|
|
|
std::unique_ptr<int32_t[]> testData(new int32_t[kS * kS]);
|
|
|
|
for (int j = 0; j < kS; ++j) {
|
|
|
|
for (int i = 0; i < kS; ++i) {
|
|
|
|
uint32_t r = i - INT8_MIN;
|
|
|
|
uint32_t g = j - INT8_MIN;
|
|
|
|
uint32_t b = INT8_MAX - r;
|
|
|
|
uint32_t a = INT8_MAX - g;
|
|
|
|
testData.get()[j * kS + i] = (a << 24) | (b << 16) | (g << 8) | r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-25 17:10:37 +00:00
|
|
|
// Test that attempting to create a integer texture with multiple MIP levels fails.
|
|
|
|
{
|
|
|
|
GrMipLevel levels[2];
|
|
|
|
levels[0].fPixels = testData.get();
|
|
|
|
levels[0].fRowBytes = kRowBytes;
|
|
|
|
levels[1].fPixels = testData.get();
|
|
|
|
levels[1].fRowBytes = (kS / 2) * sizeof(int32_t);
|
|
|
|
|
|
|
|
sk_sp<GrTexture> temp(context->textureProvider()->createMipMappedTexture(desc,
|
|
|
|
SkBudgeted::kYes,
|
|
|
|
levels, 2));
|
|
|
|
REPORTER_ASSERT(reporter, !temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that we can create an integer texture.
|
|
|
|
sk_sp<GrSurfaceProxy> proxy = GrSurfaceProxy::MakeDeferred(*context->caps(),
|
|
|
|
context->textureProvider(),
|
|
|
|
desc, SkBudgeted::kYes,
|
|
|
|
testData.get(),
|
|
|
|
kRowBytes);
|
|
|
|
REPORTER_ASSERT(reporter, proxy);
|
|
|
|
if (!proxy || !proxy->asTextureProxy()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
GrTexture* texture = proxy->asTextureProxy()->instantiate(context->textureProvider());
|
2016-11-11 21:08:03 +00:00
|
|
|
REPORTER_ASSERT(reporter, texture);
|
|
|
|
if (!texture) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<int32_t[]> readData(new int32_t[kS * kS]);
|
2017-01-25 17:10:37 +00:00
|
|
|
// Test that reading to a non-integer config fails.
|
|
|
|
{
|
|
|
|
bool success = texture->readPixels(0, 0, kS, kS, kRGBA_8888_GrPixelConfig, readData.get());
|
|
|
|
REPORTER_ASSERT(reporter, !success);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
std::unique_ptr<uint16_t[]> halfData(new uint16_t[4 * kS * kS]);
|
|
|
|
bool success = texture->readPixels(0, 0, kS, kS, kRGBA_half_GrPixelConfig, halfData.get());
|
|
|
|
REPORTER_ASSERT(reporter, !success);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// Can read back as ints. (ES only requires being able to read back into 32bit ints which
|
|
|
|
// we don't support. Right now this test is counting on GR_RGBA_INTEGER/GL_BYTE being the
|
|
|
|
// implementation-dependent second format).
|
|
|
|
sk_bzero(readData.get(), sizeof(int32_t) * kS * kS);
|
|
|
|
bool success = texture->readPixels(0, 0, kS, kS, kRGBA_8888_sint_GrPixelConfig,
|
|
|
|
readData.get());
|
|
|
|
REPORTER_ASSERT(reporter, success);
|
|
|
|
if (success) {
|
|
|
|
check_pixels(reporter, kS, kS, testData.get(), readData.get(), "readPixels");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// readPixels should fail if we attempt to use the unpremul flag with an integer texture.
|
|
|
|
bool success = texture->readPixels(0, 0, kS, kS, kRGBA_8888_sint_GrPixelConfig,
|
|
|
|
readData.get(), 0, GrContext::kUnpremul_PixelOpsFlag);
|
|
|
|
REPORTER_ASSERT(reporter, !success);
|
|
|
|
}
|
2016-11-11 21:08:03 +00:00
|
|
|
|
|
|
|
// Test that copying from one integer texture to another succeeds.
|
2016-12-15 14:23:05 +00:00
|
|
|
{
|
2017-01-25 17:10:37 +00:00
|
|
|
sk_sp<GrSurfaceContext> dstContext(GrSurfaceProxy::TestCopy(context, desc,
|
|
|
|
proxy.get()));
|
|
|
|
REPORTER_ASSERT(reporter, dstContext);
|
2017-01-30 18:27:37 +00:00
|
|
|
if (!dstContext || !dstContext->asTextureProxy()) {
|
2016-12-15 14:23:05 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-30 18:27:37 +00:00
|
|
|
GrSurface* copySurface = dstContext->asTextureProxy()->instantiate(
|
2017-01-25 17:10:37 +00:00
|
|
|
context->textureProvider());
|
2016-12-15 14:23:05 +00:00
|
|
|
REPORTER_ASSERT(reporter, copySurface);
|
|
|
|
if (!copySurface) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sk_bzero(readData.get(), sizeof(int32_t) * kS * kS);
|
2017-01-25 17:10:37 +00:00
|
|
|
bool success = copySurface->readPixels(0, 0, kS, kS,
|
|
|
|
kRGBA_8888_sint_GrPixelConfig, readData.get());
|
2016-12-15 14:23:05 +00:00
|
|
|
REPORTER_ASSERT(reporter, success);
|
|
|
|
if (success) {
|
2017-01-04 19:11:36 +00:00
|
|
|
check_pixels(reporter, kS, kS, testData.get(), readData.get(), "copyIntegerToInteger");
|
2016-12-15 14:23:05 +00:00
|
|
|
}
|
2016-12-13 18:48:08 +00:00
|
|
|
}
|
2016-12-13 20:29:42 +00:00
|
|
|
|
2016-12-15 14:23:05 +00:00
|
|
|
|
|
|
|
// Test that copying to a non-integer (8888) texture fails.
|
|
|
|
{
|
|
|
|
GrSurfaceDesc nonIntDesc = desc;
|
|
|
|
nonIntDesc.fConfig = kRGBA_8888_GrPixelConfig;
|
|
|
|
|
2017-01-25 17:10:37 +00:00
|
|
|
sk_sp<GrSurfaceContext> dstContext(GrSurfaceProxy::TestCopy(context, nonIntDesc,
|
|
|
|
proxy.get()));
|
|
|
|
REPORTER_ASSERT(reporter, !dstContext);
|
2016-12-14 12:04:46 +00:00
|
|
|
}
|
2016-12-15 14:23:05 +00:00
|
|
|
|
|
|
|
// Test that copying to a non-integer (RGBA_half) texture fails.
|
|
|
|
if (context->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig)) {
|
|
|
|
GrSurfaceDesc nonIntDesc = desc;
|
|
|
|
nonIntDesc.fConfig = kRGBA_half_GrPixelConfig;
|
|
|
|
|
2017-01-25 17:10:37 +00:00
|
|
|
sk_sp<GrSurfaceContext> dstContext(GrSurfaceProxy::TestCopy(context, nonIntDesc,
|
|
|
|
proxy.get()));
|
|
|
|
REPORTER_ASSERT(reporter, !dstContext);
|
2016-11-11 21:08:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// We overwrite the top left quarter of the texture with the bottom right quarter of the
|
|
|
|
// original data.
|
|
|
|
const void* bottomRightQuarter = testData.get() + kS / 2 * kS + kS / 2;
|
2017-01-25 17:10:37 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
// Can't write pixels from a non-int config.
|
|
|
|
bool success = texture->writePixels(0, 0, kS/2, kS/2, kRGBA_8888_GrPixelConfig,
|
|
|
|
bottomRightQuarter, kRowBytes);
|
|
|
|
REPORTER_ASSERT(reporter, !success);
|
2016-11-11 21:08:03 +00:00
|
|
|
}
|
2017-01-25 17:10:37 +00:00
|
|
|
{
|
|
|
|
// Can't use unpremul flag.
|
|
|
|
bool success = texture->writePixels(0, 0, kS/2, kS/2, kRGBA_8888_sint_GrPixelConfig,
|
|
|
|
bottomRightQuarter, kRowBytes,
|
|
|
|
GrContext::kUnpremul_PixelOpsFlag);
|
|
|
|
REPORTER_ASSERT(reporter, !success);
|
2016-11-11 21:08:03 +00:00
|
|
|
}
|
2017-01-25 17:10:37 +00:00
|
|
|
{
|
|
|
|
bool success = texture->writePixels(0, 0, kS/2, kS/2, kRGBA_8888_sint_GrPixelConfig,
|
|
|
|
bottomRightQuarter, kRowBytes);
|
|
|
|
REPORTER_ASSERT(reporter, success);
|
|
|
|
if (!success) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sk_bzero(readData.get(), sizeof(int32_t) * kS * kS);
|
|
|
|
success = texture->readPixels(0, 0, kS, kS, kRGBA_8888_sint_GrPixelConfig, readData.get());
|
|
|
|
REPORTER_ASSERT(reporter, success);
|
|
|
|
if (!success) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
std::unique_ptr<int32_t[]> overwrittenTestData(new int32_t[kS * kS]);
|
|
|
|
memcpy(overwrittenTestData.get(), testData.get(), sizeof(int32_t) * kS * kS);
|
|
|
|
char* dst = (char*)overwrittenTestData.get();
|
|
|
|
char* src = (char*)(testData.get() + kS/2 * kS + kS/2);
|
|
|
|
for (int i = 0; i < kS/2; ++i) {
|
|
|
|
memcpy(dst, src, sizeof(int32_t) * kS/2);
|
|
|
|
dst += kRowBytes;
|
|
|
|
src += kRowBytes;
|
|
|
|
}
|
|
|
|
check_pixels(reporter, kS, kS, overwrittenTestData.get(), readData.get(), "overwrite");
|
2016-11-11 21:08:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test drawing from the integer texture to a fixed point texture. To avoid any premul issues
|
|
|
|
// we init the int texture with 0s and 1s and make alpha always be 1. We expect that 1s turn
|
|
|
|
// into 0xffs and zeros stay zero.
|
|
|
|
std::unique_ptr<uint32_t[]> expectedData(new uint32_t[kS * kS]);
|
|
|
|
std::unique_ptr<uint32_t[]> actualData(new uint32_t[kS * kS]);
|
|
|
|
for (int i = 0; i < kS*kS; ++i) {
|
|
|
|
int32_t a = 0x1;
|
|
|
|
int32_t b = ((i & 0x1) ? 1 : 0);
|
|
|
|
int32_t g = ((i & 0x1) ? 0 : 1);
|
|
|
|
int32_t r = ((i & 0x2) ? 1 : 0);
|
|
|
|
testData.get()[i] = (a << 24) | (b << 16) | (g << 8) | r;
|
|
|
|
expectedData.get()[i] = ((0xFF * a) << 24) | ((0xFF * b) << 16) |
|
|
|
|
((0xFF * g) << 8) | (0xFF * r);
|
|
|
|
}
|
|
|
|
texture->writePixels(0, 0, kS, kS, kRGBA_8888_sint_GrPixelConfig, testData.get());
|
2017-01-25 17:10:37 +00:00
|
|
|
|
2016-11-11 21:08:03 +00:00
|
|
|
sk_sp<GrRenderTargetContext> rtContext = context->makeRenderTargetContext(
|
|
|
|
SkBackingFit::kExact, kS, kS, kRGBA_8888_GrPixelConfig, nullptr);
|
|
|
|
|
2017-01-04 19:11:36 +00:00
|
|
|
struct {
|
|
|
|
GrSamplerParams::FilterMode fMode;
|
|
|
|
const char* fName;
|
|
|
|
} kNamedFilters[] ={
|
|
|
|
{ GrSamplerParams::kNone_FilterMode, "filter-none" },
|
|
|
|
{ GrSamplerParams::kBilerp_FilterMode, "filter-bilerp" },
|
|
|
|
{ GrSamplerParams::kMipMap_FilterMode, "filter-mipmap" }
|
|
|
|
};
|
|
|
|
|
|
|
|
for (auto filter : kNamedFilters) {
|
2017-01-25 17:10:37 +00:00
|
|
|
sk_sp<GrFragmentProcessor> fp(GrSimpleTextureEffect::Make(texture, nullptr,
|
2017-01-20 17:44:06 +00:00
|
|
|
SkMatrix::I(),
|
2017-01-04 19:11:36 +00:00
|
|
|
filter.fMode));
|
2016-11-11 21:08:03 +00:00
|
|
|
REPORTER_ASSERT(reporter, fp);
|
|
|
|
if (!fp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
rtContext->clear(nullptr, 0xDDAABBCC, true);
|
|
|
|
GrPaint paint;
|
|
|
|
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
|
|
|
|
paint.addColorFragmentProcessor(fp);
|
2017-01-11 18:42:54 +00:00
|
|
|
rtContext->drawPaint(GrNoClip(), std::move(paint), SkMatrix::I());
|
2016-11-11 21:08:03 +00:00
|
|
|
SkImageInfo readInfo = SkImageInfo::Make(kS, kS, kRGBA_8888_SkColorType,
|
|
|
|
kPremul_SkAlphaType);
|
|
|
|
rtContext->readPixels(readInfo, actualData.get(), 0, 0, 0);
|
2017-01-04 19:11:36 +00:00
|
|
|
check_pixels(reporter, kS, kS, expectedData.get(), actualData.get(), filter.fName);
|
2016-11-11 21:08:03 +00:00
|
|
|
}
|
|
|
|
|
2017-01-25 17:10:37 +00:00
|
|
|
{
|
|
|
|
// No rendering to integer textures.
|
|
|
|
GrSurfaceDesc intRTDesc = desc;
|
|
|
|
intRTDesc.fFlags = kRenderTarget_GrSurfaceFlag;
|
|
|
|
sk_sp<GrTexture> temp(context->textureProvider()->createTexture(intRTDesc,
|
|
|
|
SkBudgeted::kYes));
|
|
|
|
REPORTER_ASSERT(reporter, !temp);
|
|
|
|
}
|
2016-11-11 21:08:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|