Create new target to hold gpu test code, enable direct testing of GrEffects in GM.

R=robertphillips@google.com, jvanverth@google.com, egdaniel@google.com

Author: bsalomon@google.com

Review URL: https://chromiumcodereview.appspot.com/23352003

git-svn-id: http://skia.googlecode.com/svn/trunk@10866 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
commit-bot@chromium.org 2013-08-21 19:27:48 +00:00
parent 05f85ade78
commit 78a1078f17
11 changed files with 303 additions and 8 deletions

179
gm/beziereffects.cpp Normal file
View File

@ -0,0 +1,179 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
// This test only works with the GPU backend.
#include "gm.h"
#if SK_SUPPORT_GPU && 0 // Can be enabled when cubic effect is checked in.
#include "GrContext.h"
#include "GrPathUtils.h"
#include "GrTest.h"
#include "SkColorPriv.h"
#include "SkDevice.h"
// Position & KLM line eq values. These are the vertex attributes for Bezier curves. The last value
// of the Vec4f is ignored.
extern const GrVertexAttrib kAttribs[] = {
{kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
{kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
};
static inline SkScalar eval_line(const SkPoint& p, const SkScalar lineEq[3], SkScalar sign) {
return sign * (lineEq[0] * p.fX + lineEq[1] * p.fY + lineEq[2]);
}
namespace skiagm {
/**
* This GM directly exercises effects that draw Bezier curves in the GPU backend.
*/
class BezierEffects : public GM {
public:
BezierEffects() {
this->setBGColor(0xFFFFFFFF);
}
protected:
virtual SkString onShortName() SK_OVERRIDE {
return SkString("bezier_effects");
}
virtual SkISize onISize() SK_OVERRIDE {
return make_isize(800, 800);
}
virtual uint32_t onGetFlags() const SK_OVERRIDE {
// This is a GPU-specific GM.
return kGPUOnly_Flag;
}
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
SkDevice* device = canvas->getTopDevice();
GrRenderTarget* rt = device->accessRenderTarget();
if (NULL == rt) {
return;
}
GrContext* context = rt->getContext();
if (NULL == context) {
return;
}
struct Vertex {
SkPoint fPosition;
float fKLM[4]; // The last value is ignored. The effect expects a vec4f.
};
static const int kNumCubics = 10;
SkMWCRandom rand;
int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics)));
int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics) / numCols);
SkScalar w = SkIntToScalar(rt->width()) / numCols;
SkScalar h = SkIntToScalar(rt->height()) / numRows;
int row = 0;
int col = 0;
for (int i = 0; i < kNumCubics; ++i) {
SkScalar x = SkScalarMul(col, w);
SkScalar y = SkScalarMul(row, h);
SkPoint controlPts[] = {
{x + rand.nextRangeF(0, w), y + rand.nextRangeF(0, h)},
{x + rand.nextRangeF(0, w), y + rand.nextRangeF(0, h)},
{x + rand.nextRangeF(0, w), y + rand.nextRangeF(0, h)},
{x + rand.nextRangeF(0, w), y + rand.nextRangeF(0, h)}
};
SkPoint chopped[10];
SkScalar klmEqs[9];
SkScalar klmSigns[3];
int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
chopped,
klmEqs,
klmSigns,
controlPts);
SkPaint ctrlPtPaint;
ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
for (int i = 0; i < 4; ++i) {
canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
}
SkPaint polyPaint;
polyPaint.setColor(0xffA0A0A0);
polyPaint.setStrokeWidth(0);
polyPaint.setStyle(SkPaint::kStroke_Style);
canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
SkPaint choppedPtPaint;
choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
for (int c = 0; c < cnt; ++c) {
SkPoint* pts = chopped + 3 * c;
for (int i = 0; i < 4; ++i) {
canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
}
SkRect bounds;
bounds.set(pts, 4);
SkPaint boundsPaint;
boundsPaint.setColor(0xff808080);
boundsPaint.setStrokeWidth(0);
boundsPaint.setStyle(SkPaint::kStroke_Style);
canvas->drawRect(bounds, boundsPaint);
Vertex verts[4];
verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop,
bounds.fRight, bounds.fBottom,
sizeof(Vertex));
for (int v = 0; v < 4; ++v) {
verts[v].fKLM[0] = eval_line(verts[v].fPosition, klmEqs + 0, klmSigns[c]);
verts[v].fKLM[1] = eval_line(verts[v].fPosition, klmEqs + 3, klmSigns[c]);
verts[v].fKLM[2] = eval_line(verts[v].fPosition, klmEqs + 6, 1.f);
}
GrTestTarget tt;
context->getTestTarget(&tt);
if (NULL == tt.target()) {
continue;
}
GrDrawState* drawState = tt.target()->drawState();
drawState->setVertexAttribs<kAttribs>(2);
SkAutoTUnref<GrEffectRef> effect(HairCubicEdgeEffect::Create());
if (!effect) {
continue;
}
drawState->addCoverageEffect(effect, 1);
drawState->setRenderTarget(rt);
drawState->setColor(0xff000000);
tt.target()->setVertexSourceToArray(verts, 4);
tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
}
++col;
if (numCols == col) {
col = 0;
++row;
}
}
}
private:
typedef GM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_GM( return SkNEW(BezierEffects); )
}
#endif

View File

@ -15,10 +15,6 @@
namespace skiagm {
extern GrContext* GetGr();
};
void GrContext::setMaxTextureSizeOverride(int maxTextureSizeOverride) {
fMaxTextureSizeOverride = maxTextureSizeOverride;
}
#endif
// Create a black&white checked texture with a 1-pixel red ring

View File

@ -43,6 +43,8 @@ namespace skiagm {
kSkipScaledReplay_Flag = 1 << 6,
kSkipGPU_Flag = 1 << 7,
kSkipPDFRasterization_Flag = 1 << 8,
kGPUOnly_Flag = 1 << 9,
};
void draw(SkCanvas*);

View File

@ -1559,8 +1559,8 @@ ErrorCombination run_multiple_configs(GMMain &gmmain, GM *gm,
errorsForAllConfigs.add(kIntentionallySkipped_ErrorType);
continue;
}
if ((gmFlags & GM::kSkipGPU_Flag) &&
kGPU_Backend == config.fBackend) {
if (((gmFlags & GM::kSkipGPU_Flag) && kGPU_Backend == config.fBackend) ||
((gmFlags & GM::kGPUOnly_Flag) && kGPU_Backend != config.fBackend)) {
gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
renderModeDescriptor);
errorsForAllConfigs.add(kIntentionallySkipped_ErrorType);

View File

@ -300,8 +300,8 @@
],
}],
[ 'skia_gpu == 1', {
'include_dirs': [
'../src/gpu', # To pull gl/GrGLUtil.h
'dependencies': [
'gputest.gyp:skgputest',
],
}],
[ 'skia_os == "nacl"', {

View File

@ -94,6 +94,9 @@
'include_dirs': [
'../src/gpu',
],
'dependencies': [
'gputest.gyp:skgputest',
],
}],
],
},

View File

@ -6,6 +6,7 @@
'../gm/alphagradients.cpp',
'../gm/arcofzorro.cpp',
'../gm/arithmode.cpp',
'../gm/beziereffects.cpp',
'../gm/bicubicfilter.cpp',
'../gm/bigmatrix.cpp',
'../gm/bigtext.cpp',

38
gyp/gputest.gyp Normal file
View File

@ -0,0 +1,38 @@
{
'targets': [
{
'target_name': 'skgputest',
'product_name': 'skia_skgputest',
'type': 'static_library',
'standalone_static_library': 1,
'dependencies': [
'core.gyp:core',
'gpu.gyp:skgpu',
],
'include_dirs': [
'../include/gpu',
'../include/utils',
'../src/core',
'../src/gpu',
],
'direct_dependent_settings': {
'include_dirs': [
'../src/gpu',
],
},
'sources': [
'<(skia_src_path)/gpu/GrTest.cpp',
'<(skia_src_path)/gpu/GrTest.h',
],
'defines': [
'GR_IMPLEMENTATION=1',
],
},
],
}
# Local Variables:
# tab-width:2
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=2 shiftwidth=2:

View File

@ -33,6 +33,7 @@ class GrPathRenderer;
class GrResourceEntry;
class GrResourceCache;
class GrStencilBuffer;
class GrTestTarget;
class GrTextureParams;
class GrVertexBuffer;
class GrVertexBufferAllocPool;
@ -825,6 +826,9 @@ public:
GrDrawTarget* getTextTarget();
const GrIndexBuffer* getQuadIndexBuffer() const;
// Called by tests that draw directly to the context via GrDrawTarget
void getTestTarget(GrTestTarget*);
/**
* Stencil buffers add themselves to the cache using addStencilBuffer. findStencilBuffer is
* called to check the cache for a SB that matches an RT's criteria.

37
src/gpu/GrTest.cpp Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrTest.h"
#include "GrGpu.h"
void GrTestTarget::init(GrContext* ctx, GrDrawTarget* target) {
SkASSERT(!fContext);
fContext.reset(SkRef(ctx));
fDrawTarget.reset(SkRef(target));
SkNEW_IN_TLAZY(&fASR, GrDrawTarget::AutoStateRestore, (target, GrDrawTarget::kReset_ASRInit));
SkNEW_IN_TLAZY(&fACR, GrDrawTarget::AutoClipRestore, (target));
SkNEW_IN_TLAZY(&fAGP, GrDrawTarget::AutoGeometryPush, (target));
}
void GrContext::getTestTarget(GrTestTarget* tar) {
this->flush();
// We could create a proxy GrDrawTarget that passes through to fGpu until ~GrTextTarget() and
// then disconnects. This would help prevent test writers from mixing using the returned
// GrDrawTarget and regular drawing. We could also assert or fail in GrContext drawing methods
// until ~GrTestTarget().
tar->init(this, fGpu);
}
///////////////////////////////////////////////////////////////////////////////
void GrContext::setMaxTextureSizeOverride(int maxTextureSizeOverride) {
fMaxTextureSizeOverride = maxTextureSizeOverride;
}

35
src/gpu/GrTest.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrTest_DEFINED
#define GrTest_DEFINED
#include "GrContext.h"
#include "GrDrawTarget.h"
/** Allows a test to temporarily draw to a GrDrawTarget owned by a GrContext. Tests that use this
should be careful not to mix using the GrDrawTarget directly and drawing via SkCanvas or
GrContext. In the future this object may provide some guards to prevent this. */
class GrTestTarget {
public:
GrTestTarget() {};
void init(GrContext*, GrDrawTarget*);
GrDrawTarget* target() { return fDrawTarget.get(); }
private:
SkTLazy<GrDrawTarget::AutoStateRestore> fASR;
SkTLazy<GrDrawTarget::AutoClipRestore> fACR;
SkTLazy<GrDrawTarget::AutoGeometryPush> fAGP;
SkAutoTUnref<GrDrawTarget> fDrawTarget;
SkAutoTUnref<GrContext> fContext;
};
#endif