| Index: tests/GLProgramsTest.cpp
|
| diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
|
| index c31aa1e0da6b909a3d884f8d9e0ffcea7dfdd0a3..4d1c59734bddca29bd6db4f8188795be57c0f8d6 100644
|
| --- a/tests/GLProgramsTest.cpp
|
| +++ b/tests/GLProgramsTest.cpp
|
| @@ -12,7 +12,7 @@
|
|
|
| #if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
|
|
|
| -#include "GrBackendProcessorFactory.h"
|
| +#include "GrTBackendProcessorFactory.h"
|
| #include "GrContextFactory.h"
|
| #include "GrOptDrawState.h"
|
| #include "effects/GrConfigConversionEffect.h"
|
| @@ -23,180 +23,122 @@
|
| #include "SkRandom.h"
|
| #include "Test.h"
|
|
|
| -static void get_stage_stats(const GrFragmentStage stage, bool* readsDst,
|
| - bool* readsFragPosition, bool* requiresVertexShader) {
|
| - if (stage.getProcessor()->willReadDstColor()) {
|
| - *readsDst = true;
|
| - }
|
| - if (stage.getProcessor()->willReadFragmentPosition()) {
|
| - *readsFragPosition = true;
|
| - }
|
| -}
|
| +/*
|
| + * A dummy effect which just tries to insert a massive key and verify that it can retrieve the
|
| + * whole thing correctly
|
| + */
|
| +static const uint32_t kMaxKeySize = 1024;
|
|
|
| -bool GrGLProgramDesc::setRandom(SkRandom* random,
|
| - GrGpuGL* gpu,
|
| - const GrRenderTarget* dstRenderTarget,
|
| - const GrTexture* dstCopyTexture,
|
| - const GrGeometryStage* geometryProcessor,
|
| - const GrFragmentStage* stages[],
|
| - int numColorStages,
|
| - int numCoverageStages,
|
| - int currAttribIndex,
|
| - GrGpu::DrawType drawType) {
|
| - bool isPathRendering = GrGpu::IsPathRenderingDrawType(drawType);
|
| - bool useLocalCoords = !isPathRendering &&
|
| - random->nextBool() &&
|
| - currAttribIndex < GrDrawState::kMaxVertexAttribCnt;
|
| -
|
| - int numStages = numColorStages + numCoverageStages;
|
| - fKey.reset();
|
| -
|
| - GR_STATIC_ASSERT(0 == kEffectKeyOffsetsAndLengthOffset % sizeof(uint32_t));
|
| -
|
| - // Make room for everything up to and including the array of offsets to effect keys.
|
| - fKey.push_back_n(kEffectKeyOffsetsAndLengthOffset + 2 * sizeof(uint16_t) * (numStages +
|
| - (geometryProcessor ? 1 : 0)));
|
| -
|
| - bool dstRead = false;
|
| - bool fragPos = false;
|
| - bool vertexShader = SkToBool(geometryProcessor);
|
| - int offset = 0;
|
| - if (geometryProcessor) {
|
| - const GrGeometryStage* stage = geometryProcessor;
|
| - uint16_t* offsetAndSize = reinterpret_cast<uint16_t*>(fKey.begin() +
|
| - kEffectKeyOffsetsAndLengthOffset +
|
| - offset * 2 * sizeof(uint16_t));
|
| - uint32_t effectKeyOffset = fKey.count();
|
| - if (effectKeyOffset > SK_MaxU16) {
|
| - fKey.reset();
|
| - return false;
|
| - }
|
| - GrProcessorKeyBuilder b(&fKey);
|
| - uint16_t effectKeySize;
|
| - if (!GetProcessorKey(*stage, gpu->glCaps(), useLocalCoords, &b, &effectKeySize)) {
|
| - fKey.reset();
|
| - return false;
|
| - }
|
| - vertexShader = true;
|
| - fragPos = stage->getProcessor()->willReadFragmentPosition();
|
| - offsetAndSize[0] = effectKeyOffset;
|
| - offsetAndSize[1] = effectKeySize;
|
| - offset++;
|
| - }
|
| +class GLBigKeyProcessor;
|
|
|
| - for (int s = 0; s < numStages; ++s, ++offset) {
|
| - const GrFragmentStage* stage = stages[s];
|
| - uint16_t* offsetAndSize = reinterpret_cast<uint16_t*>(fKey.begin() +
|
| - kEffectKeyOffsetsAndLengthOffset +
|
| - offset * 2 * sizeof(uint16_t));
|
| - uint32_t effectKeyOffset = fKey.count();
|
| - if (effectKeyOffset > SK_MaxU16) {
|
| - fKey.reset();
|
| - return false;
|
| - }
|
| - GrProcessorKeyBuilder b(&fKey);
|
| - uint16_t effectKeySize;
|
| - if (!GetProcessorKey(*stages[s], gpu->glCaps(), useLocalCoords, &b, &effectKeySize)) {
|
| - fKey.reset();
|
| - return false;
|
| - }
|
| - get_stage_stats(*stage, &dstRead, &fragPos, &vertexShader);
|
| - offsetAndSize[0] = effectKeyOffset;
|
| - offsetAndSize[1] = effectKeySize;
|
| +class BigKeyProcessor : public GrFragmentProcessor {
|
| +public:
|
| + static GrFragmentProcessor* Create() {
|
| + GR_CREATE_STATIC_FRAGMENT_PROCESSOR(gBigKeyProcessor, BigKeyProcessor, ())
|
| + return SkRef(gBigKeyProcessor);
|
| }
|
|
|
| - KeyHeader* header = this->header();
|
| - memset(header, 0, kHeaderSize);
|
| - header->fEmitsPointSize = random->nextBool();
|
| + static const char* Name() { return "Big ol' Key"; }
|
|
|
| - header->fPositionAttributeIndex = 0;
|
| + virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE {
|
| + return GrTBackendFragmentProcessorFactory<BigKeyProcessor>::getInstance();
|
| + }
|
|
|
| - // if the effects have used up all off the available attributes,
|
| - // don't try to use color or coverage attributes as input
|
| - do {
|
| - header->fColorInput = static_cast<GrGLProgramDesc::ColorInput>(
|
| - random->nextULessThan(kColorInputCnt));
|
| - } while ((GrDrawState::kMaxVertexAttribCnt <= currAttribIndex || isPathRendering) &&
|
| - kAttribute_ColorInput == header->fColorInput);
|
| - header->fColorAttributeIndex = (header->fColorInput == kAttribute_ColorInput) ?
|
| - currAttribIndex++ :
|
| - -1;
|
| + typedef GLBigKeyProcessor GLProcessor;
|
|
|
| - do {
|
| - header->fCoverageInput = static_cast<GrGLProgramDesc::ColorInput>(
|
| - random->nextULessThan(kColorInputCnt));
|
| - } while ((GrDrawState::kMaxVertexAttribCnt <= currAttribIndex || isPathRendering) &&
|
| - kAttribute_ColorInput == header->fCoverageInput);
|
| - header->fCoverageAttributeIndex = (header->fCoverageInput == kAttribute_ColorInput) ?
|
| - currAttribIndex++ :
|
| - -1;
|
| - bool useGS = random->nextBool();
|
| -#if GR_GL_EXPERIMENTAL_GS
|
| - header->fExperimentalGS = gpu->caps()->geometryShaderSupport() && useGS;
|
| -#else
|
| - (void) useGS;
|
| -#endif
|
| +private:
|
| + BigKeyProcessor() { }
|
| + virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE { return true; }
|
| + virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE { }
|
|
|
| - header->fLocalCoordAttributeIndex = useLocalCoords ? currAttribIndex++ : -1;
|
| + GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
|
|
|
| - header->fColorEffectCnt = numColorStages;
|
| - header->fCoverageEffectCnt = numCoverageStages;
|
| + typedef GrFragmentProcessor INHERITED;
|
| +};
|
|
|
| - if (dstRead) {
|
| - header->fDstReadKey = SkToU8(GrGLFragmentShaderBuilder::KeyForDstRead(dstCopyTexture,
|
| - gpu->glCaps()));
|
| - } else {
|
| - header->fDstReadKey = 0;
|
| - }
|
| - if (fragPos) {
|
| - header->fFragPosKey = SkToU8(GrGLFragmentShaderBuilder::KeyForFragmentPosition(dstRenderTarget,
|
| - gpu->glCaps()));
|
| - } else {
|
| - header->fFragPosKey = 0;
|
| - }
|
| +GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor);
|
|
|
| - header->fUseFragShaderOnly = isPathRendering && gpu->glPathRendering()->texturingMode() ==
|
| - GrGLPathRendering::FixedFunction_TexturingMode;
|
| - header->fHasGeometryProcessor = vertexShader;
|
| +GrFragmentProcessor* BigKeyProcessor::TestCreate(SkRandom*,
|
| + GrContext*,
|
| + const GrDrawTargetCaps&,
|
| + GrTexture*[]) {
|
| + return BigKeyProcessor::Create();
|
| +}
|
|
|
| - GrOptDrawState::PrimaryOutputType primaryOutput;
|
| - GrOptDrawState::SecondaryOutputType secondaryOutput;
|
| - if (!dstRead) {
|
| - primaryOutput = GrOptDrawState::kModulate_PrimaryOutputType;
|
| - } else {
|
| - primaryOutput = static_cast<GrOptDrawState::PrimaryOutputType>(
|
| - random->nextULessThan(GrOptDrawState::kPrimaryOutputTypeCnt));
|
| +class GLBigKeyProcessor : public GrGLFragmentProcessor {
|
| +public:
|
| + GLBigKeyProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&)
|
| + : INHERITED(factory) {}
|
| +
|
| + virtual void emitCode(GrGLProgramBuilder* builder,
|
| + const GrFragmentProcessor& fp,
|
| + const GrProcessorKey& key,
|
| + const char* outputColor,
|
| + const char* inputColor,
|
| + const TransformedCoordsArray&,
|
| + const TextureSamplerArray&) {
|
| + for (uint32_t i = 0; i < kMaxKeySize; i++) {
|
| + SkASSERT(key.get32(i) == i);
|
| + }
|
| }
|
|
|
| - if (GrOptDrawState::kCombineWithDst_PrimaryOutputType == primaryOutput ||
|
| - !gpu->caps()->dualSourceBlendingSupport()) {
|
| - secondaryOutput = GrOptDrawState::kNone_SecondaryOutputType;
|
| - } else {
|
| - secondaryOutput = static_cast<GrOptDrawState::SecondaryOutputType>(
|
| - random->nextULessThan(GrOptDrawState::kSecondaryOutputTypeCnt));
|
| + static void GenKey(const GrProcessor& processor, const GrGLCaps&, GrProcessorKeyBuilder* b) {
|
| + for (uint32_t i = 0; i < kMaxKeySize; i++) {
|
| + b->add32(i);
|
| + }
|
| }
|
|
|
| - header->fPrimaryOutputType = primaryOutput;
|
| - header->fSecondaryOutputType = secondaryOutput;
|
| +private:
|
| + typedef GrGLFragmentProcessor INHERITED;
|
| +};
|
|
|
| - this->finalize();
|
| - return true;
|
| +/*
|
| + * Begin test code
|
| + */
|
| +static const int kRenderTargetHeight = 1;
|
| +static const int kRenderTargetWidth = 1;
|
| +
|
| +static GrRenderTarget* random_render_target(GrGpuGL* gpu,
|
| + const GrCacheID& cacheId,
|
| + SkRandom* random) {
|
| + // setup render target
|
| + GrTextureParams params;
|
| + GrTextureDesc texDesc;
|
| + texDesc.fWidth = kRenderTargetWidth;
|
| + texDesc.fHeight = kRenderTargetHeight;
|
| + texDesc.fFlags = kRenderTarget_GrTextureFlagBit;
|
| + texDesc.fConfig = kRGBA_8888_GrPixelConfig;
|
| + texDesc.fOrigin = random->nextBool() == true ? kTopLeft_GrSurfaceOrigin :
|
| + kBottomLeft_GrSurfaceOrigin;
|
| +
|
| + GrTexture* texture = gpu->getContext()->findAndRefTexture(texDesc, cacheId, ¶ms);
|
| + if (NULL == texture) {
|
| + texture = gpu->getContext()->createTexture(¶ms, texDesc, cacheId, 0, 0);
|
| + if (NULL == texture) {
|
| + return NULL;
|
| + }
|
| + }
|
| + return texture->asRenderTarget();
|
| }
|
|
|
| // TODO clean this up, we have to do this to test geometry processors but there has got to be
|
| // a better way. In the mean time, we actually fill out these generic vertex attribs below with
|
| // the correct vertex attribs from the GP. We have to ensure, however, we don't try to add more
|
| -// than two attributes.
|
| -GrVertexAttrib genericVertexAttribs[] = {
|
| +// than two attributes. In addition, we 'pad' the below array with GPs up to 6 entries, 4 fixed
|
| +// function vertex attributes and 2 GP custom attributes.
|
| +GrVertexAttrib kGenericVertexAttribs[] = {
|
| { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
|
| { kVec2f_GrVertexAttribType, 0, kGeometryProcessor_GrVertexAttribBinding },
|
| + { kVec2f_GrVertexAttribType, 0, kGeometryProcessor_GrVertexAttribBinding },
|
| + { kVec2f_GrVertexAttribType, 0, kGeometryProcessor_GrVertexAttribBinding },
|
| + { kVec2f_GrVertexAttribType, 0, kGeometryProcessor_GrVertexAttribBinding },
|
| { kVec2f_GrVertexAttribType, 0, kGeometryProcessor_GrVertexAttribBinding }
|
| };
|
|
|
| /*
|
| * convert sl type to vertexattrib type, not a complete implementation, only use for debugging
|
| */
|
| -GrVertexAttribType convert_sltype_to_attribtype(GrSLType type) {
|
| +static GrVertexAttribType convert_sltype_to_attribtype(GrSLType type) {
|
| switch (type) {
|
| case kFloat_GrSLType:
|
| return kFloat_GrVertexAttribType;
|
| @@ -211,11 +153,227 @@ GrVertexAttribType convert_sltype_to_attribtype(GrSLType type) {
|
| return kFloat_GrVertexAttribType;
|
| }
|
| }
|
| -// TODO end test hack
|
| +// end test hack
|
| +
|
| +static void setup_random_ff_attribute(GrVertexAttribBinding binding, GrVertexAttribType type,
|
| + SkRandom* random, int* attribIndex, int* runningStride) {
|
| + if (random->nextBool()) {
|
| + kGenericVertexAttribs[*attribIndex].fType = type;
|
| + kGenericVertexAttribs[*attribIndex].fOffset = *runningStride;
|
| + kGenericVertexAttribs[*attribIndex].fBinding = binding;
|
| + *runningStride += GrVertexAttribTypeSize(kGenericVertexAttribs[(*attribIndex)++].fType);
|
| + }
|
| +}
|
|
|
| +static void set_random_gp(GrGpuGL* gpu, SkRandom* random, GrTexture* dummyTextures[]) {
|
| + GrProgramElementRef<const GrGeometryProcessor> gp(
|
| + GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(random,
|
| + gpu->getContext(),
|
| + *gpu->caps(),
|
| + dummyTextures));
|
| + SkASSERT(gp);
|
| +
|
| + // we have to set dummy vertex attributes, first we setup the fixed function attributes
|
| + // always leave the position attribute untouched in the array
|
| + int attribIndex = 1;
|
| + int runningStride = GrVertexAttribTypeSize(kGenericVertexAttribs[0].fType);
|
| +
|
| + // local coords
|
| + setup_random_ff_attribute(kLocalCoord_GrVertexAttribBinding, kVec2f_GrVertexAttribType,
|
| + random, &attribIndex, &runningStride);
|
| +
|
| + // color
|
| + setup_random_ff_attribute(kColor_GrVertexAttribBinding, kVec4f_GrVertexAttribType,
|
| + random, &attribIndex, &runningStride);
|
| +
|
| + // coverage
|
| + setup_random_ff_attribute(kCoverage_GrVertexAttribBinding, kVec4f_GrVertexAttribType,
|
| + random, &attribIndex, &runningStride);
|
| +
|
| + // Update the geometry processor attributes
|
| + const GrGeometryProcessor::VertexAttribArray& v = gp->getVertexAttribs();
|
| + int numGPAttribs = v.count();
|
| + SkASSERT(numGPAttribs <= GrGeometryProcessor::kMaxVertexAttribs &&
|
| + GrGeometryProcessor::kMaxVertexAttribs == 2);
|
| +
|
| + // we actually can't overflow if kMaxVertexAttribs == 2, but GCC 4.8 wants more proof
|
| + int maxIndex = SK_ARRAY_COUNT(kGenericVertexAttribs);
|
| + for (int i = 0; i < numGPAttribs && i + attribIndex < maxIndex; i++) {
|
| + kGenericVertexAttribs[i + attribIndex].fType =
|
| + convert_sltype_to_attribtype(v[i].getType());
|
| + kGenericVertexAttribs[i + attribIndex].fOffset = runningStride;
|
| + kGenericVertexAttribs[i + attribIndex].fBinding = kGeometryProcessor_GrVertexAttribBinding;
|
| + runningStride += GrVertexAttribTypeSize(kGenericVertexAttribs[i + attribIndex].fType);
|
| + }
|
|
|
| -bool GrGpuGL::programUnitTest(int maxStages) {
|
| + // update the vertex attributes with the ds
|
| + GrDrawState* ds = gpu->drawState();
|
| + ds->setVertexAttribs<kGenericVertexAttribs>(attribIndex + numGPAttribs, runningStride);
|
| + ds->setGeometryProcessor(gp);
|
| +}
|
| +
|
| +static void set_random_color_coverage_stages(GrGpuGL* gpu,
|
| + int maxStages,
|
| + bool usePathRendering,
|
| + SkRandom* random,
|
| + GrTexture* dummyTextures[]) {
|
| + int numProcs = random->nextULessThan(maxStages + 1);
|
| + int numColorProcs = random->nextULessThan(numProcs + 1);
|
| +
|
| + int currTextureCoordSet = 0;
|
| + for (int s = 0; s < numProcs;) {
|
| + GrProgramElementRef<GrFragmentProcessor> fp(
|
| + GrProcessorTestFactory<GrFragmentProcessor>::CreateStage(random,
|
| + gpu->getContext(),
|
| + *gpu->caps(),
|
| + dummyTextures));
|
| + SkASSERT(fp);
|
| +
|
| + // don't add dst color reads to coverage stage
|
| + if (s >= numColorProcs && fp->willReadDstColor()) {
|
| + continue;
|
| + }
|
| +
|
| + // If adding this effect would exceed the max texture coord set count then generate a
|
| + // new random effect.
|
| + if (usePathRendering && gpu->glPathRendering()->texturingMode() ==
|
| + GrGLPathRendering::FixedFunction_TexturingMode) {;
|
| + int numTransforms = fp->numTransforms();
|
| + if (currTextureCoordSet + numTransforms >
|
| + gpu->glCaps().maxFixedFunctionTextureCoords()) {
|
| + continue;
|
| + }
|
| + currTextureCoordSet += numTransforms;
|
| + }
|
| +
|
| + // finally add the stage to the correct pipeline in the drawstate
|
| + GrDrawState* ds = gpu->drawState();
|
| + if (s < numColorProcs) {
|
| + ds->addColorProcessor(fp);
|
| + } else {
|
| + ds->addCoverageProcessor(fp);
|
| + }
|
| + ++s;
|
| + }
|
| +}
|
| +
|
| +// There are only a few cases of random colors which interest us
|
| +enum ColorMode {
|
| + kAllOnes_ColorMode,
|
| + kAllZeros_ColorMode,
|
| + kAlphaOne_ColorMode,
|
| + kRandom_ColorMode,
|
| + kLast_ColorMode = kRandom_ColorMode
|
| +};
|
| +
|
| +static void set_random_color(GrGpuGL* gpu, SkRandom* random) {
|
| + ColorMode colorMode = ColorMode(random->nextULessThan(kLast_ColorMode + 1));
|
| + GrColor color;
|
| + switch (colorMode) {
|
| + case kAllOnes_ColorMode:
|
| + color = GrColorPackRGBA(0xFF, 0xFF, 0xFF, 0xFF);
|
| + break;
|
| + case kAllZeros_ColorMode:
|
| + color = GrColorPackRGBA(0, 0, 0, 0);
|
| + break;
|
| + case kAlphaOne_ColorMode:
|
| + color = GrColorPackRGBA(random->nextULessThan(256),
|
| + random->nextULessThan(256),
|
| + random->nextULessThan(256),
|
| + 0xFF);
|
| + break;
|
| + case kRandom_ColorMode:
|
| + uint8_t alpha = random->nextULessThan(256);
|
| + color = GrColorPackRGBA(random->nextRangeU(0, alpha),
|
| + random->nextRangeU(0, alpha),
|
| + random->nextRangeU(0, alpha),
|
| + alpha);
|
| + break;
|
| + }
|
| + GrColorIsPMAssert(color);
|
| + gpu->drawState()->setColor(color);
|
| +}
|
| +
|
| +// There are only a few cases of random coverages which interest us
|
| +enum CoverageMode {
|
| + kZero_CoverageMode,
|
| + kFF_CoverageMode,
|
| + kRandom_CoverageMode,
|
| + kLast_CoverageMode = kRandom_CoverageMode
|
| +};
|
| +
|
| +static void set_random_coverage(GrGpuGL* gpu, SkRandom* random) {
|
| + CoverageMode coverageMode = CoverageMode(random->nextULessThan(kLast_CoverageMode + 1));
|
| + uint8_t coverage;
|
| + switch (coverageMode) {
|
| + case kZero_CoverageMode:
|
| + coverage = 0;
|
| + break;
|
| + case kFF_CoverageMode:
|
| + coverage = 0xFF;
|
| + break;
|
| + case kRandom_CoverageMode:
|
| + coverage = uint8_t(random->nextU());
|
| + break;
|
| + }
|
| + gpu->drawState()->setCoverage(coverage);
|
| +}
|
| +
|
| +static void set_random_hints(GrGpuGL* gpu, SkRandom* random) {
|
| + for (int i = 1; i <= GrDrawState::kLast_Hint; i <<= 1) {
|
| + gpu->drawState()->setHint(GrDrawState::Hints(i), random->nextBool());
|
| + }
|
| +}
|
| +
|
| +static void set_random_state(GrGpuGL* gpu, SkRandom* random) {
|
| + int state = 0;
|
| + for (int i = 1; i <= GrDrawState::kLastPublicStateBit; i <<= 1) {
|
| + state |= random->nextBool() * i;
|
| + }
|
| + gpu->drawState()->enableState(state);
|
| +}
|
| +
|
| +// this function will randomly pick non-self referencing blend modes
|
| +static void set_random_blend_func(GrGpuGL* gpu, SkRandom* random) {
|
| + GrBlendCoeff src;
|
| + do {
|
| + src = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff));
|
| + } while (GrBlendCoeffRefsSrc(src));
|
|
|
| + GrBlendCoeff dst;
|
| + do {
|
| + dst = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff));
|
| + } while (GrBlendCoeffRefsDst(dst));
|
| +
|
| + gpu->drawState()->setBlendFunc(src, dst);
|
| +}
|
| +
|
| +// right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
|
| +static void set_random_stencil(GrGpuGL* gpu, SkRandom* random) {
|
| + GR_STATIC_CONST_SAME_STENCIL(kDoesWriteStencil,
|
| + kReplace_StencilOp,
|
| + kReplace_StencilOp,
|
| + kAlways_StencilFunc,
|
| + 0xffff,
|
| + 0xffff,
|
| + 0xffff);
|
| + GR_STATIC_CONST_SAME_STENCIL(kDoesNotWriteStencil,
|
| + kKeep_StencilOp,
|
| + kKeep_StencilOp,
|
| + kNever_StencilFunc,
|
| + 0xffff,
|
| + 0xffff,
|
| + 0xffff);
|
| +
|
| + if (random->nextBool()) {
|
| + gpu->drawState()->setStencil(kDoesWriteStencil);
|
| + } else {
|
| + gpu->drawState()->setStencil(kDoesNotWriteStencil);
|
| + }
|
| +}
|
| +
|
| +bool GrGpuGL::programUnitTest(int maxStages) {
|
| + // setup dummy textures
|
| GrTextureDesc dummyDesc;
|
| dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit;
|
| dummyDesc.fConfig = kSkia8888_GrPixelConfig;
|
| @@ -229,130 +387,116 @@ bool GrGpuGL::programUnitTest(int maxStages) {
|
| SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));
|
|
|
| if (!dummyTexture1 || ! dummyTexture2) {
|
| + SkDebugf("Could not allocate dummy textures");
|
| return false;
|
| }
|
|
|
| - static const int NUM_TESTS = 512;
|
| + GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
|
|
|
| - SkRandom random;
|
| - for (int t = 0; t < NUM_TESTS; ++t) {
|
| + // Setup texture cache id key
|
| + const GrCacheID::Domain glProgramsDomain = GrCacheID::GenerateDomain();
|
| + GrCacheID::Key key;
|
| + memset(&key, 0, sizeof(key));
|
| + key.fData32[0] = kRenderTargetWidth;
|
| + key.fData32[1] = kRenderTargetHeight;
|
| + GrCacheID glProgramsCacheID(glProgramsDomain, key);
|
|
|
| -#if 0
|
| - GrPrintf("\nTest Program %d\n-------------\n", t);
|
| - static const int stop = -1;
|
| - if (t == stop) {
|
| - int breakpointhere = 9;
|
| - }
|
| -#endif
|
| + // setup clip
|
| + SkRect screen =
|
| + SkRect::MakeWH(SkIntToScalar(kRenderTargetWidth), SkIntToScalar(kRenderTargetHeight));
|
|
|
| - GrGLProgramDesc pdesc;
|
| + SkClipStack stack;
|
| + stack.clipDevRect(screen, SkRegion::kReplace_Op, false);
|
|
|
| - int currAttribIndex = 1; // we need to always leave room for position
|
| - int currTextureCoordSet = 0;
|
| - GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
|
| + // wrap the SkClipStack in a GrClipData
|
| + GrClipData clipData;
|
| + clipData.fClipStack = &stack;
|
| + this->setClip(&clipData);
|
|
|
| - int numStages = random.nextULessThan(maxStages + 1);
|
| - int numColorStages = random.nextULessThan(numStages + 1);
|
| - int numCoverageStages = numStages - numColorStages;
|
| + SkRandom random;
|
| + static const int NUM_TESTS = 512;
|
| + for (int t = 0; t < NUM_TESTS;) {
|
| + // setup random render target(can fail)
|
| + GrRenderTarget* rtPtr = random_render_target(this, glProgramsCacheID, &random);
|
| + if (!rtPtr) {
|
| + SkDebugf("Could not allocate render target");
|
| + return false;
|
| + }
|
| + GrTGpuResourceRef<GrRenderTarget> rt(SkRef(rtPtr), kWrite_GrIOType);
|
|
|
| - SkAutoSTMalloc<8, const GrFragmentStage*> stages(numStages);
|
| + GrDrawState* ds = this->drawState();
|
| + ds->setRenderTarget(rt.get());
|
|
|
| + // if path rendering we have to setup a couple of things like the draw type
|
| bool usePathRendering = this->glCaps().pathRenderingSupport() && random.nextBool();
|
|
|
| GrGpu::DrawType drawType = usePathRendering ? GrGpu::kDrawPath_DrawType :
|
| GrGpu::kDrawPoints_DrawType;
|
|
|
| - SkAutoTDelete<GrGeometryStage> geometryProcessor;
|
| + // twiddle drawstate knobs randomly
|
| bool hasGeometryProcessor = usePathRendering ? false : random.nextBool();
|
| if (hasGeometryProcessor) {
|
| - while (true) {
|
| - SkAutoTUnref<const GrGeometryProcessor> effect(
|
| - GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(&random, this->getContext(), *this->caps(),
|
| - dummyTextures));
|
| - SkASSERT(effect);
|
| - // Only geometryProcessor can use vertex shader
|
| - GrGeometryStage* stage = SkNEW_ARGS(GrGeometryStage, (effect.get()));
|
| - geometryProcessor.reset(stage);
|
| -
|
| - // we have to set dummy vertex attribs
|
| - const GrGeometryProcessor::VertexAttribArray& v = effect->getVertexAttribs();
|
| - int numVertexAttribs = v.count();
|
| -
|
| - SkASSERT(GrGeometryProcessor::kMaxVertexAttribs == 2 &&
|
| - GrGeometryProcessor::kMaxVertexAttribs >= numVertexAttribs);
|
| - size_t runningStride = GrVertexAttribTypeSize(genericVertexAttribs[0].fType);
|
| - for (int i = 0; i < numVertexAttribs; i++) {
|
| - genericVertexAttribs[i + 1].fOffset = runningStride;
|
| - genericVertexAttribs[i + 1].fType =
|
| - convert_sltype_to_attribtype(v[i].getType());
|
| - runningStride += GrVertexAttribTypeSize(genericVertexAttribs[i + 1].fType);
|
| - }
|
| -
|
| - // update the vertex attributes with the ds
|
| - GrDrawState* ds = this->drawState();
|
| - ds->setVertexAttribs<genericVertexAttribs>(numVertexAttribs + 1, runningStride);
|
| - currAttribIndex = numVertexAttribs + 1;
|
| - break;
|
| - }
|
| + set_random_gp(this, &random, dummyTextures);
|
| }
|
| - for (int s = 0; s < numStages;) {
|
| - SkAutoTUnref<const GrFragmentProcessor> effect(
|
| - GrProcessorTestFactory<GrFragmentProcessor>::CreateStage(
|
| - &random,
|
| - this->getContext(),
|
| - *this->caps(),
|
| - dummyTextures));
|
| - SkASSERT(effect);
|
| -
|
| - // If adding this effect would exceed the max texture coord set count then generate a
|
| - // new random effect.
|
| - if (usePathRendering && this->glPathRendering()->texturingMode() ==
|
| - GrGLPathRendering::FixedFunction_TexturingMode) {;
|
| - int numTransforms = effect->numTransforms();
|
| - if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) {
|
| - continue;
|
| - }
|
| - currTextureCoordSet += numTransforms;
|
| - }
|
| - GrFragmentStage* stage = SkNEW_ARGS(GrFragmentStage, (effect.get()));
|
| -
|
| - stages[s] = stage;
|
| - ++s;
|
| + set_random_color_coverage_stages(this, maxStages - hasGeometryProcessor, usePathRendering,
|
| + &random, dummyTextures);
|
| + set_random_color(this, &random);
|
| + set_random_coverage(this, &random);
|
| + set_random_hints(this, &random);
|
| + set_random_state(this, &random);
|
| + set_random_blend_func(this, &random);
|
| + set_random_stencil(this, &random);
|
| +
|
| + // create optimized draw state, setup readDst texture if required, and build a descriptor
|
| + // and program. ODS creation can fail, so we have to check
|
| + SkAutoTUnref<GrOptDrawState> ods(GrOptDrawState::Create(this->getDrawState(),
|
| + *this->caps(),
|
| + drawType));
|
| + if (!ods.get()) {
|
| + ds->reset();
|
| + continue;
|
| }
|
| - const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1];
|
| - if (!pdesc.setRandom(&random,
|
| - this,
|
| - dummyTextures[0]->asRenderTarget(),
|
| - dstTexture,
|
| - geometryProcessor.get(),
|
| - stages.get(),
|
| - numColorStages,
|
| - numCoverageStages,
|
| - currAttribIndex,
|
| - drawType)) {
|
| + const GrGeometryStage* geometryProcessor = NULL;
|
| + SkSTArray<8, const GrFragmentStage*, true> colorStages;
|
| + SkSTArray<8, const GrFragmentStage*, true> coverageStages;
|
| + GrGLProgramDesc desc;
|
| + GrDeviceCoordTexture dstCopy;
|
| +
|
| + if (!this->setupDstReadIfNecessary(&dstCopy, NULL)) {
|
| + SkDebugf("Couldn't setup dst read texture");
|
| return false;
|
| }
|
| -
|
| - SkAutoTUnref<GrOptDrawState> optState(GrOptDrawState::Create(this->getDrawState(),
|
| - *this->caps(),
|
| - drawType));
|
| - SkAutoTUnref<GrGLProgram> program(
|
| - GrGLProgramBuilder::CreateProgram(*optState,
|
| - pdesc,
|
| - drawType,
|
| - geometryProcessor,
|
| - stages,
|
| - stages + numColorStages,
|
| - this));
|
| - for (int s = 0; s < numStages; ++s) {
|
| - SkDELETE(stages[s]);
|
| + if (!GrGLProgramDesc::Build(*ods,
|
| + drawType,
|
| + ods->getSrcBlendCoeff(),
|
| + ods->getDstBlendCoeff(),
|
| + this,
|
| + dstCopy.texture() ? &dstCopy : NULL,
|
| + &geometryProcessor,
|
| + &colorStages,
|
| + &coverageStages,
|
| + &desc)) {
|
| + SkDebugf("Failed to generate GL program descriptor");
|
| + return false;
|
| }
|
| + SkAutoTUnref<GrGLProgram> program(GrGLProgramBuilder::CreateProgram(*ods,
|
| + desc,
|
| + drawType,
|
| + geometryProcessor,
|
| + colorStages.begin(),
|
| + coverageStages.begin(),
|
| + this));
|
| if (NULL == program.get()) {
|
| + SkDebugf("Failed to create program!");
|
| return false;
|
| }
|
|
|
| // We have to reset the drawstate because we might have added a gp
|
| - this->drawState()->reset();
|
| + ds->reset();
|
| +
|
| + // because occasionally optimized drawstate creation will fail for valid reasons, we only
|
| + // want to increment on success
|
| + ++t;
|
| }
|
| return true;
|
| }
|
|
|