Make mock GrContext unit testable.

Bug: skia:
Change-Id: I959122f1f2c390832ab1033bcdbdd2ca6cfc0419
Reviewed-on: https://skia-review.googlesource.com/20699
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2017-07-06 10:51:32 -04:00 committed by Skia Commit-Bot
parent 0c26a9dbd0
commit 993e7e2521
16 changed files with 453 additions and 53 deletions

View File

@ -956,6 +956,7 @@ if (skia_enable_tools) {
"tools/gpu/gl/debug/GrTextureObj.cpp",
"tools/gpu/gl/debug/GrTextureUnitObj.cpp",
"tools/gpu/gl/null/NullGLTestContext.cpp",
"tools/gpu/mock/MockTestContext.cpp",
]
libs = []

View File

@ -459,7 +459,13 @@ skia_gpu_sources = [
"$_src/gpu/glsl/GrGLSLXferProcessor.h",
# Mock
"$_src/gpu/mock/GrMockBuffer.h",
"$_src/gpu/mock/GrMockCaps.h",
"$_src/gpu/mock/GrMockGpu.cpp",
"$_src/gpu/mock/GrMockGpu.h",
"$_src/gpu/mock/GrMockGpuCommandBuffer.h",
"$_src/gpu/mock/GrMockStencilAttachment.h",
"$_src/gpu/mock/GrMockTexture.h",
# Sk files
"$_src/gpu/SkGpuDevice.cpp",

View File

@ -196,8 +196,9 @@ const int kBackendCount = kLast_GrBackend + 1;
/**
* Backend-specific 3D context handle
* GrGLInterface* for OpenGL. If NULL will use the default GL interface.
* GrVkBackendContext* for Vulkan.
* OpenGL: const GrGLInterface*. If null will use the result of GrGLCreateNativeInterface().
* Vulkan: GrVkBackendContext*.
* Mock: const GrMockOptions* or null for default constructed GrMockContextOptions.
*/
typedef intptr_t GrBackendContext;

View File

@ -0,0 +1,38 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrMockOptions_DEFINED
#define GrMockOptions_DEFINED
#include "GrTypes.h"
/**
* A pointer to this type is used as the GrBackendContext when creating a Mock GrContext. It can be
* used to specificy capability options for the mock context. If nullptr is used a default
* constructed GrMockOptions is used.
*/
struct GrMockOptions {
GrMockOptions() {
// By default RGBA_8888 is textureable and renderable and A8 is texturable.
fConfigOptions[kRGBA_8888_GrPixelConfig].fRenderable[0] = true;
fConfigOptions[kRGBA_8888_GrPixelConfig].fTexturable = true;
fConfigOptions[kAlpha_8_GrPixelConfig].fTexturable = true;
}
struct ConfigOptions {
/** The first value is for non-MSAA rendering, the second for MSAA. */
bool fRenderable[2] = {false, false};
bool fTexturable = false;
};
int fMaxTextureSize = 16384;
int fMaxRenderTargetSize = 16384;
int fMaxVertexAttributes = 16;
ConfigOptions fConfigOptions[kGrPixelConfigCnt];
};
#endif

View File

@ -56,12 +56,12 @@ public:
SkDestinationSurfaceColorMode mipColorMode() const { return fTexture->fMipColorMode; }
static void ComputeScratchKey(const GrSurfaceDesc&, GrScratchKey*);
private:
static void ComputeScratchKey(GrPixelConfig config, int width, int height,
GrSurfaceOrigin origin, bool isRenderTarget, int sampleCnt,
bool isMipMapped, GrScratchKey* key);
private:
GrTexturePriv(GrTexture* texture) : fTexture(texture) { }
GrTexturePriv(const GrTexturePriv& that) : fTexture(that.fTexture) { }
GrTexturePriv& operator=(const GrTexturePriv&); // unimpl

View File

@ -0,0 +1,30 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrMockBuffer_DEFINED
#define GrMockBuffer_DEFINED
#include "GrBuffer.h"
#include "GrMockGpu.h"
class GrMockBuffer : public GrBuffer {
public:
GrMockBuffer(GrMockGpu* gpu, size_t sizeInBytes, GrBufferType type,
GrAccessPattern accessPattern)
: INHERITED(gpu, sizeInBytes, type, accessPattern) {
this->registerWithCache(SkBudgeted::kYes);
}
private:
void onMap() override {}
void onUnmap() override {}
bool onUpdateData(const void* src, size_t srcSizeInBytes) override { return true; }
typedef GrBuffer INHERITED;
};
#endif

41
src/gpu/mock/GrMockCaps.h Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrMockCaps_DEFINED
#define GrMockCaps_DEFINED
#include "GrCaps.h"
#include "mock/GrMockOptions.h"
class GrMockCaps : public GrCaps {
public:
GrMockCaps(const GrContextOptions& contextOptions, const GrMockOptions& options)
: INHERITED(contextOptions), fOptions(options) {
fBufferMapThreshold = SK_MaxS32;
fMaxTextureSize = options.fMaxTextureSize;
fMaxRenderTargetSize = SkTMin(options.fMaxRenderTargetSize, fMaxTextureSize);
fMaxVertexAttributes = options.fMaxVertexAttributes;
fShaderCaps.reset(new GrShaderCaps(contextOptions));
}
bool isConfigTexturable(GrPixelConfig config) const override {
return fOptions.fConfigOptions[config].fTexturable;
}
bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override {
return fOptions.fConfigOptions[config].fRenderable[withMSAA];
}
bool canConfigBeImageStorage(GrPixelConfig) const override { return false; }
bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
bool* rectsMustMatch, bool* disallowSubrect) const override {
return false;
}
private:
GrMockOptions fOptions;
typedef GrCaps INHERITED;
};
#endif

View File

@ -0,0 +1,62 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrMockGpu.h"
#include "GrMockBuffer.h"
#include "GrMockCaps.h"
#include "GrMockGpuCommandBuffer.h"
#include "GrMockStencilAttachment.h"
#include "GrMockTexture.h"
GrGpu* GrMockGpu::Create(GrBackendContext backendContext, const GrContextOptions& contextOptions,
GrContext* context) {
static const GrMockOptions kDefaultOptions = GrMockOptions();
const GrMockOptions* options = reinterpret_cast<const GrMockOptions*>(backendContext);
if (!options) {
options = &kDefaultOptions;
}
return new GrMockGpu(context, *options, contextOptions);
}
GrGpuCommandBuffer* GrMockGpu::createCommandBuffer(const GrGpuCommandBuffer::LoadAndStoreInfo&,
const GrGpuCommandBuffer::LoadAndStoreInfo&) {
return new GrMockGpuCommandBuffer(this);
}
void GrMockGpu::submitCommandBuffer(const GrMockGpuCommandBuffer* cmdBuffer) {
for (int i = 0; i < cmdBuffer->numDraws(); ++i) {
fStats.incNumDraws();
}
}
GrMockGpu::GrMockGpu(GrContext* context, const GrMockOptions& options,
const GrContextOptions& contextOptions)
: INHERITED(context) {
fCaps.reset(new GrMockCaps(contextOptions, options));
}
sk_sp<GrTexture> GrMockGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
const SkTArray<GrMipLevel>& texels) {
bool hasMipLevels = texels.count() > 1;
if (desc.fFlags & kRenderTarget_GrSurfaceFlag) {
return sk_sp<GrTexture>(new GrMockTextureRenderTarget(this, budgeted, desc, hasMipLevels));
}
return sk_sp<GrTexture>(new GrMockTexture(this, budgeted, desc, hasMipLevels));
}
GrBuffer* GrMockGpu::onCreateBuffer(size_t sizeInBytes, GrBufferType type,
GrAccessPattern accessPattern, const void*) {
return new GrMockBuffer(this, sizeInBytes, type, accessPattern);
}
GrStencilAttachment* GrMockGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
int width,
int height) {
static constexpr int kBits = 8;
fStats.incStencilAttachmentCreates();
return new GrMockStencilAttachment(this, width, height, kBits, rt->numColorSamples());
}

View File

@ -4,55 +4,36 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrMockGpu_DEFINED
#define GrMockGpu_DEFINED
#include "GrCaps.h"
#include "GrGpu.h"
#include "GrSemaphore.h"
#include "GrTexture.h"
class GrMockGpuCommandBuffer;
struct GrMockOptions;
class GrPipeline;
class GrMockCaps : public GrCaps {
public:
explicit GrMockCaps(const GrContextOptions& options) : INHERITED(options) {
fBufferMapThreshold = SK_MaxS32;
}
bool isConfigTexturable(GrPixelConfig) const override { return false; }
bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override { return false; }
bool canConfigBeImageStorage(GrPixelConfig) const override { return false; }
bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
bool* rectsMustMatch, bool* disallowSubrect) const override {
return false;
}
private:
typedef GrCaps INHERITED;
};
class GrMockGpu : public GrGpu {
public:
static GrGpu* Create(GrBackendContext backendContext, const GrContextOptions& options,
GrContext* context) {
SkASSERT((void*)backendContext == nullptr);
return new GrMockGpu(context, options);
}
static GrGpu* Create(GrBackendContext, const GrContextOptions&, GrContext*);
~GrMockGpu() override {}
bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes,
GrPixelConfig readConfig, DrawPreference*,
ReadPixelTempDrawInfo*) override { return false; }
ReadPixelTempDrawInfo*) override { return true; }
bool onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
GrPixelConfig srcConfig, DrawPreference*,
WritePixelTempDrawInfo*) override { return false; }
WritePixelTempDrawInfo*) override { return true; }
bool onCopySurface(GrSurface* dst,
GrSurface* src,
const SkIRect& srcRect,
const SkIPoint& dstPoint) override { return false; }
const SkIPoint& dstPoint) override { return true; }
void onQueryMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings&,
int* effectiveSampleCnt, SamplePattern*) override {
@ -60,9 +41,7 @@ public:
}
GrGpuCommandBuffer* createCommandBuffer(const GrGpuCommandBuffer::LoadAndStoreInfo&,
const GrGpuCommandBuffer::LoadAndStoreInfo&) override {
return nullptr;
}
const GrGpuCommandBuffer::LoadAndStoreInfo&) override;
GrFence SK_WARN_UNUSED_RESULT insertFence() override { return 0; }
bool waitFence(GrFence, uint64_t) override { return true; }
@ -77,19 +56,17 @@ public:
void waitSemaphore(sk_sp<GrSemaphore> semaphore) override {}
sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override { return nullptr; }
void submitCommandBuffer(const GrMockGpuCommandBuffer*);
private:
GrMockGpu(GrContext* context, const GrContextOptions& options) : INHERITED(context) {
fCaps.reset(new GrMockCaps(options));
}
GrMockGpu(GrContext* context, const GrMockOptions&, const GrContextOptions&);
void onResetContext(uint32_t resetBits) override {}
void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {}
sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
const SkTArray<GrMipLevel>& texels) override {
return nullptr;
}
sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&, SkBudgeted,
const SkTArray<GrMipLevel>&) override;
sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&,
GrSurfaceOrigin,
@ -110,9 +87,8 @@ private:
return nullptr;
}
GrBuffer* onCreateBuffer(size_t, GrBufferType, GrAccessPattern, const void*) override {
return nullptr;
}
GrBuffer* onCreateBuffer(size_t sizeInBytes, GrBufferType, GrAccessPattern,
const void*) override;
gr_instanced::InstancedRendering* onCreateInstancedRendering() override { return nullptr; }
@ -121,30 +97,27 @@ private:
GrPixelConfig,
void* buffer,
size_t rowBytes) override {
return false;
return true;
}
bool onWritePixels(GrSurface* surface,
int left, int top, int width, int height,
GrPixelConfig config, const SkTArray<GrMipLevel>& texels) override {
return false;
return true;
}
bool onTransferPixels(GrTexture* texture,
int left, int top, int width, int height,
GrPixelConfig config, GrBuffer* transferBuffer,
size_t offset, size_t rowBytes) override {
return false;
return true;
}
void onResolveRenderTarget(GrRenderTarget* target) override { return; }
GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*,
int width,
int height) override {
return nullptr;
}
int height) override;
void clearStencil(GrRenderTarget* target) override {}
GrBackendObject createTestingOnlyBackendTexture(void* pixels, int w, int h,
@ -156,4 +129,5 @@ private:
typedef GrGpu INHERITED;
};
#endif // GrMockGpu_DEFINED
#endif

View File

@ -0,0 +1,41 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrMockGpuCommandBuffer_DEFINED
#define GrMockGpuCommandBuffer_DEFINED
#include "GrGpuCommandBuffer.h"
#include "GrMockGpu.h"
class GrMockGpuCommandBuffer : public GrGpuCommandBuffer {
public:
GrMockGpuCommandBuffer(GrMockGpu* gpu) : fGpu(gpu) {}
GrGpu* gpu() override { return fGpu; }
void inlineUpload(GrOpFlushState*, GrDrawOp::DeferredUploadFn&, GrRenderTarget*) override {}
void discard(GrRenderTarget*) override {}
void end() override {}
int numDraws() const { return fNumDraws; }
private:
void onSubmit() override { fGpu->submitCommandBuffer(this); }
void onDraw(const GrPipeline&, const GrPrimitiveProcessor&, const GrMesh[],
const GrPipeline::DynamicState[], int meshCount, const SkRect& bounds) override {
++fNumDraws;
}
void onClear(GrRenderTarget*, const GrFixedClip&, GrColor) override {}
void onClearStencilClip(GrRenderTarget*, const GrFixedClip&, bool insideStencilMask) override {}
GrRenderTarget* renderTarget() override { return nullptr; }
GrMockGpu* fGpu;
int fNumDraws = 0;
typedef GrGpuCommandBuffer INHERITED;
};
#endif

View File

@ -0,0 +1,29 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrMockStencilAttachment_DEFINED
#define GrMockStencilAttachment_DEFINED
#include "GrMockGpu.h"
#include "GrStencilAttachment.h"
class GrMockStencilAttachment : public GrStencilAttachment {
public:
GrMockStencilAttachment(GrMockGpu* gpu, int width, int height, int bits, int sampleCnt)
: INHERITED(gpu, width, height, bits, sampleCnt) {
this->registerWithCache(SkBudgeted::kYes);
}
private:
size_t onGpuMemorySize() const override {
return SkTMax(1, (int)(this->bits() / sizeof(char))) * this->width() * this->height();
}
typedef GrStencilAttachment INHERITED;
};
#endif

View File

@ -0,0 +1,90 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrMockTexture_DEFINED
#define GrMockTexture_DEFINED
#include "GrMockGpu.h"
#include "GrTexture.h"
#include "GrTexturePriv.h"
class GrMockTexture : public GrTexture {
public:
GrMockTexture(GrMockGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc, bool hasMipLevels)
: GrMockTexture(gpu, desc, hasMipLevels) {
this->registerWithCache(budgeted);
}
~GrMockTexture() override {
if (fReleaseProc) {
fReleaseProc(fReleaseCtx);
}
}
GrBackendObject getTextureHandle() const override { return 0; }
void textureParamsModified() override {}
void setRelease(ReleaseProc proc, ReleaseCtx ctx) override {
fReleaseProc = proc;
fReleaseCtx = ctx;
}
protected:
// constructor for subclasses
GrMockTexture(GrMockGpu* gpu, const GrSurfaceDesc& desc, bool hasMipLevels)
: GrSurface(gpu, desc)
, INHERITED(gpu, desc, kITexture2DSampler_GrSLType, GrSamplerParams::kMipMap_FilterMode,
hasMipLevels)
, fReleaseProc(nullptr)
, fReleaseCtx(nullptr) {}
private:
ReleaseProc fReleaseProc;
ReleaseCtx fReleaseCtx;
typedef GrTexture INHERITED;
};
class GrMockTextureRenderTarget : public GrMockTexture, public GrRenderTarget {
public:
GrMockTextureRenderTarget(GrMockGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc,
bool hasMipLevels)
: GrSurface(gpu, desc)
, GrMockTexture(gpu, desc, hasMipLevels)
, GrRenderTarget(gpu, desc) {
this->registerWithCache(budgeted);
}
ResolveType getResolveType() const override { return kCanResolve_ResolveType; }
GrBackendObject getRenderTargetHandle() const override { return 0; }
bool canAttemptStencilAttachment() const override { return true; }
bool completeStencilAttachment() override { return true; }
GrTexture* asTexture() override { return this; }
GrRenderTarget* asRenderTarget() override { return this; }
const GrTexture* asTexture() const override { return this; }
const GrRenderTarget* asRenderTarget() const override { return this; }
private:
void onAbandon() override {
GrRenderTarget::onAbandon();
GrMockTexture::onAbandon();
}
void onRelease() override {
GrRenderTarget::onRelease();
GrMockTexture::onRelease();
}
size_t onGpuMemorySize() const override {
return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
this->numStencilSamples(),
this->texturePriv().hasMipMaps());
}
void computeScratchKey(GrScratchKey* key) const override {
GrTexturePriv::ComputeScratchKey(this->config(), this->width(), this->height(),
this->origin(), true, this->numStencilSamples(),
this->texturePriv().hasMipMaps(), key);
}
};
#endif

View File

@ -22,6 +22,7 @@
#endif
#include "gl/null/NullGLTestContext.h"
#include "gl/GrGLGpu.h"
#include "mock/MockTestContext.h"
#include "GrCaps.h"
#if defined(SK_BUILD_FOR_WIN32) && defined(SK_ENABLE_DISCRETE_GPU)
@ -220,6 +221,19 @@ ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOv
break;
}
#endif
case kMock_GrBackend: {
TestContext* sharedContext = masterContext ? masterContext->fTestContext : nullptr;
SkASSERT(kMock_ContextType == type);
if (ContextOverrides::kRequireNVPRSupport & overrides) {
return ContextInfo();
}
testCtx.reset(CreateMockTestContext(sharedContext));
if (!testCtx) {
return ContextInfo();
}
backendContext = testCtx->backendContext();
break;
}
default:
return ContextInfo();
}

View File

@ -44,7 +44,8 @@ public:
kNullGL_ContextType, //! Non-rendering OpenGL mock context.
kDebugGL_ContextType, //! Non-rendering, state verifying OpenGL context.
kVulkan_ContextType, //! Vulkan
kLastContextType = kVulkan_ContextType
kMock_ContextType, //! Mock context that does not draw.
kLastContextType = kMock_ContextType
};
static const int kContextTypeCnt = kLastContextType + 1;
@ -68,6 +69,7 @@ public:
switch (type) {
case kNullGL_ContextType:
case kDebugGL_ContextType:
case kMock_ContextType:
return false;
default:
return true;
@ -78,6 +80,8 @@ public:
switch (type) {
case kVulkan_ContextType:
return kVulkan_GrBackend;
case kMock_ContextType:
return kMock_GrBackend;
default:
return kOpenGL_GrBackend;
}
@ -109,8 +113,10 @@ public:
return "Debug GL";
case kVulkan_ContextType:
return "Vulkan";
case kMock_ContextType:
return "Mock";
}
SkDEBUGFAIL("Unreachable");
SkFAIL("Unreachable");
return "Unknown";
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GLTestContext_DEFINED
#define GLTestContext_DEFINED
#include "MockTestContext.h"
namespace {
class MockTestContext : public sk_gpu_test::TestContext {
public:
MockTestContext() {}
~MockTestContext() override {}
virtual GrBackend backend() override { return kMock_GrBackend; }
virtual GrBackendContext backendContext() override {
return reinterpret_cast<GrBackendContext>(nullptr);
}
bool isValid() const override { return true; }
void testAbandon() override {}
void submit() override {}
void finish() override {}
protected:
void teardown() override {}
void onPlatformMakeCurrent() const override {}
void onPlatformSwapBuffers() const override {}
private:
typedef sk_gpu_test::TestContext INHERITED;
};
} // anonymous namespace
namespace sk_gpu_test {
TestContext* CreateMockTestContext(TestContext*) { return new MockTestContext(); }
} // namespace sk_gpu_test
#endif

View File

@ -0,0 +1,22 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef MockTestContext_DEFINED
#define MockTestContext_DEFINED
#include "TestContext.h"
namespace sk_gpu_test {
/**
* Creates mock context object for use with GrContexts created with kMock_GrBackend. It will
* trivially succeed at everything.
*/
TestContext* CreateMockTestContext(TestContext* shareContext = nullptr);
} // namespace sk_gpu_test
#endif