C++程序  |  190行  |  7.34 KB

/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

// This is a GPU-backend specific test. It relies on static intializers to work

#include "SkTypes.h"

#include "GrContextFactory.h"
#include "GrContextPriv.h"
#include "GrGpu.h"
#include "GrResourceProvider.h"
#include "GrSurfaceProxy.h"
#include "GrTexture.h"
#include "SkGr.h"
#include "SkSurface.h"
#include "Test.h"

using sk_gpu_test::GrContextFactory;

void fill_transfer_data(int left, int top, int width, int height, int bufferWidth,
                        GrColor* data) {

    // build red-green gradient
    for (int j = top; j < top + height; ++j) {
        for (int i = left; i < left + width; ++i) {
            unsigned int red = (unsigned int)(256.f*((i - left) / (float)width));
            unsigned int green = (unsigned int)(256.f*((j - top) / (float)height));
            data[i + j*bufferWidth] = GrColorPackRGBA(red - (red>>8),
                                                      green - (green>>8), 0xff, 0xff);
        }
    }
}

bool does_full_buffer_contain_correct_values(GrColor* srcBuffer,
                                             GrColor* dstBuffer,
                                             int width,
                                             int height,
                                             int bufferWidth,
                                             int bufferHeight) {
    GrColor* srcPtr = srcBuffer;
    GrColor* dstPtr = dstBuffer;

    for (int j = 0; j < height; ++j) {
        for (int i = 0; i < width; ++i) {
            if (srcPtr[i] != dstPtr[i]) {
                return false;
            }
        }
        srcPtr += bufferWidth;
        dstPtr += bufferWidth;
    }
    return true;
}

void basic_transfer_test(skiatest::Reporter* reporter, GrContext* context, GrColorType colorType,
                         bool renderTarget) {
    if (GrCaps::kNone_MapFlags == context->contextPriv().caps()->mapBufferFlags()) {
        return;
    }

    auto resourceProvider = context->contextPriv().resourceProvider();
    GrGpu* gpu = context->contextPriv().getGpu();

    // set up the data
    const int kTextureWidth = 16;
    const int kTextureHeight = 16;
#ifdef SK_BUILD_FOR_IOS
    // UNPACK_ROW_LENGTH is broken on iOS so rowBytes needs to match data width
    const int kBufferWidth = GrBackendApi::kOpenGL == context->backend() ? 16 : 20;
#else
    const int kBufferWidth = 20;
#endif
    const int kBufferHeight = 16;
    size_t rowBytes = kBufferWidth * sizeof(GrColor);
    SkAutoTMalloc<GrColor> srcBuffer(kBufferWidth*kBufferHeight);
    SkAutoTMalloc<GrColor> dstBuffer(kBufferWidth*kBufferHeight);

    fill_transfer_data(0, 0, kTextureWidth, kTextureHeight, kBufferWidth, srcBuffer.get());

    // create and fill transfer buffer
    size_t size = rowBytes*kBufferHeight;
    auto bufferFlags = GrResourceProvider::Flags::kNoPendingIO;
    sk_sp<GrBuffer> buffer(resourceProvider->createBuffer(size,
                                                          kXferCpuToGpu_GrBufferType,
                                                          kDynamic_GrAccessPattern,
                                                          bufferFlags));
    if (!buffer) {
        return;
    }

    void* data = buffer->map();
    memcpy(data, srcBuffer.get(), size);
    buffer->unmap();

    for (auto srgbEncoding : {GrSRGBEncoded::kNo, GrSRGBEncoded::kYes}) {
        // create texture
        GrSurfaceDesc desc;
        desc.fFlags = renderTarget ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
        desc.fWidth = kTextureWidth;
        desc.fHeight = kTextureHeight;
        desc.fConfig = GrColorTypeToPixelConfig(colorType, srgbEncoding);
        desc.fSampleCnt = 1;

        if (kUnknown_GrPixelConfig == desc.fConfig) {
            SkASSERT(GrSRGBEncoded::kYes == srgbEncoding);
            continue;
        }

        if (!context->contextPriv().caps()->isConfigTexturable(desc.fConfig) ||
            (renderTarget && !context->contextPriv().caps()->isConfigRenderable(desc.fConfig))) {
            continue;
        }

        sk_sp<GrTexture> tex = resourceProvider->createTexture(desc, SkBudgeted::kNo);
        if (!tex) {
            continue;
        }

        //////////////////////////
        // transfer full data

        bool result;
        result = gpu->transferPixels(tex.get(), 0, 0, kTextureWidth, kTextureHeight, colorType,
                                     buffer.get(), 0, rowBytes);
        REPORTER_ASSERT(reporter, result);

        memset(dstBuffer.get(), 0xCDCD, size);
        result = gpu->readPixels(tex.get(), 0, 0, kTextureWidth, kTextureHeight, colorType,
                                 dstBuffer.get(), rowBytes);
        if (result) {
            REPORTER_ASSERT(reporter, does_full_buffer_contain_correct_values(srcBuffer,
                                                                              dstBuffer,
                                                                              kTextureWidth,
                                                                              kTextureHeight,
                                                                              kBufferWidth,
                                                                              kBufferHeight));
        }

        //////////////////////////
        // transfer partial data
#ifdef SK_BUILD_FOR_IOS
        // UNPACK_ROW_LENGTH is broken on iOS so we can't do partial transfers
        if (GrBackendApi::kOpenGL == context->backend()) {
            continue;
        }
#endif
        const int kLeft = 2;
        const int kTop = 10;
        const int kWidth = 10;
        const int kHeight = 2;

        // change color of subrectangle
        fill_transfer_data(kLeft, kTop, kWidth, kHeight, kBufferWidth, srcBuffer.get());
        data = buffer->map();
        memcpy(data, srcBuffer.get(), size);
        buffer->unmap();

        size_t offset = sizeof(GrColor) * (kTop * kBufferWidth + kLeft);
        result = gpu->transferPixels(tex.get(), kLeft, kTop, kWidth, kHeight, colorType,
                                     buffer.get(), offset, rowBytes);
        REPORTER_ASSERT(reporter, result);

        memset(dstBuffer.get(), 0xCDCD, size);
        result = gpu->readPixels(tex.get(), 0, 0, kTextureWidth, kTextureHeight, colorType,
                                 dstBuffer.get(), rowBytes);
        if (result) {
            REPORTER_ASSERT(reporter, does_full_buffer_contain_correct_values(srcBuffer,
                                                                              dstBuffer,
                                                                              kTextureWidth,
                                                                              kTextureHeight,
                                                                              kBufferWidth,
                                                                              kBufferHeight));
        }
    }
}

DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsTest, reporter, ctxInfo) {
    // RGBA
    basic_transfer_test(reporter, ctxInfo.grContext(), GrColorType::kRGBA_8888, false);
    basic_transfer_test(reporter, ctxInfo.grContext(), GrColorType::kRGBA_8888, true);

    // BGRA
    basic_transfer_test(reporter, ctxInfo.grContext(), GrColorType::kBGRA_8888, false);
    basic_transfer_test(reporter, ctxInfo.grContext(), GrColorType::kBGRA_8888, true);
}