Example #1
0
bool GrDrawingManager::ProgramUnitTest(GrContext* context, int maxStages) {
    GrDrawingManager* drawingManager = context->drawingManager();

    // setup dummy textures
    GrSurfaceDesc dummyDesc;
    dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    dummyDesc.fConfig = kSkia8888_GrPixelConfig;
    dummyDesc.fWidth = 34;
    dummyDesc.fHeight = 18;
    SkAutoTUnref<GrTexture> dummyTexture1(
        context->textureProvider()->createTexture(dummyDesc, SkBudgeted::kNo, nullptr, 0));
    dummyDesc.fFlags = kNone_GrSurfaceFlags;
    dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    dummyDesc.fWidth = 16;
    dummyDesc.fHeight = 22;
    SkAutoTUnref<GrTexture> dummyTexture2(
        context->textureProvider()->createTexture(dummyDesc, SkBudgeted::kNo, nullptr, 0));

    if (!dummyTexture1 || ! dummyTexture2) {
        SkDebugf("Could not allocate dummy textures");
        return false;
    }

    GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};

    // dummy scissor state
    GrScissorState scissor;

    SkRandom random;
    static const int NUM_TESTS = 1024;
    for (int t = 0; t < NUM_TESTS; t++) {
        // setup random render target(can fail)
        sk_sp<GrDrawContext> drawContext(random_draw_context(context, &random, context->caps()));
        if (!drawContext) {
            SkDebugf("Could not allocate drawContext");
            return false;
        }

        GrPaint grPaint;

        SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context));
        SkASSERT(batch);

        GrProcessorTestData ptd(&random, context, context->caps(),
                                drawContext.get(), dummyTextures);
        set_random_color_coverage_stages(&grPaint, &ptd, maxStages);
        set_random_xpf(&grPaint, &ptd);
        bool snapToCenters = set_random_state(&grPaint, &random);
        const GrUserStencilSettings* uss = get_random_stencil(&random);

        drawContext->drawContextPriv().testingOnly_drawBatch(grPaint, batch, uss, snapToCenters);
    }
    // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
    drawingManager->flush();

    // Validate that GrFPs work correctly without an input.
    sk_sp<GrDrawContext> drawContext(context->newDrawContext(SkBackingFit::kExact,
                                                             kRenderTargetWidth,
                                                             kRenderTargetHeight,
                                                             kRGBA_8888_GrPixelConfig));
    if (!drawContext) {
        SkDebugf("Could not allocate a drawContext");
        return false;
    }

    int fpFactoryCnt = GrProcessorTestFactory<GrFragmentProcessor>::Count();
    for (int i = 0; i < fpFactoryCnt; ++i) {
        // Since FP factories internally randomize, call each 10 times.
        for (int j = 0; j < 10; ++j) {
            SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context));
            SkASSERT(batch);
            GrProcessorTestData ptd(&random, context, context->caps(),
                                    drawContext.get(), dummyTextures);
            GrPaint grPaint;
            grPaint.setXPFactory(GrPorterDuffXPFactory::Make(SkXfermode::kSrc_Mode));

            sk_sp<GrFragmentProcessor> fp(
                GrProcessorTestFactory<GrFragmentProcessor>::MakeIdx(i, &ptd));
            sk_sp<GrFragmentProcessor> blockFP(
                BlockInputFragmentProcessor::Make(std::move(fp)));
            grPaint.addColorFragmentProcessor(std::move(blockFP));

            drawContext->drawContextPriv().testingOnly_drawBatch(grPaint, batch);
            drawingManager->flush();
        }
    }

    return true;
}
Example #2
0
bool GrGpuGL::programUnitTest(int maxStages) {

    GrTextureDesc dummyDesc;
    dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit;
    dummyDesc.fConfig = kSkia8888_GrPixelConfig;
    dummyDesc.fWidth = 34;
    dummyDesc.fHeight = 18;
    SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
    dummyDesc.fFlags = kNone_GrTextureFlags;
    dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    dummyDesc.fWidth = 16;
    dummyDesc.fHeight = 22;
    SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));

    if (!dummyTexture1 || ! dummyTexture2) {
        return false;
    }

    static const int NUM_TESTS = 512;

    SkRandom random;
    for (int t = 0; t < NUM_TESTS; ++t) {

#if 0
        GrPrintf("\nTest Program %d\n-------------\n", t);
        static const int stop = -1;
        if (t == stop) {
            int breakpointhere = 9;
        }
#endif

        GrGLProgramDesc pdesc;

        int currAttribIndex = 1;  // we need to always leave room for position
        int currTextureCoordSet = 0;
        GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};

        int numStages = random.nextULessThan(maxStages + 1);
        int numColorStages = random.nextULessThan(numStages + 1);
        int numCoverageStages = numStages - numColorStages;

        SkAutoSTMalloc<8, const GrFragmentStage*> stages(numStages);

        bool usePathRendering = this->glCaps().pathRenderingSupport() && random.nextBool();

        GrGpu::DrawType drawType = usePathRendering ? GrGpu::kDrawPath_DrawType :
                                                      GrGpu::kDrawPoints_DrawType;

        SkAutoTDelete<GrGeometryStage> geometryProcessor;
        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;
            }
        }
        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;
        }
        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)) {
            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 (NULL == program.get()) {
            return false;
        }

        // We have to reset the drawstate because we might have added a gp
        this->drawState()->reset();
    }
    return true;
}
Example #3
0
bool GrDrawingManager::ProgramUnitTest(GrContext* context,
                                       GrDrawTarget* drawTarget,
                                       int maxStages) {
    GrDrawingManager* drawingManager = context->drawingManager();

    // setup dummy textures
    GrSurfaceDesc dummyDesc;
    dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    dummyDesc.fConfig = kSkia8888_GrPixelConfig;
    dummyDesc.fWidth = 34;
    dummyDesc.fHeight = 18;
    SkAutoTUnref<GrTexture> dummyTexture1(
        context->textureProvider()->createTexture(dummyDesc, false, nullptr, 0));
    dummyDesc.fFlags = kNone_GrSurfaceFlags;
    dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    dummyDesc.fWidth = 16;
    dummyDesc.fHeight = 22;
    SkAutoTUnref<GrTexture> dummyTexture2(
        context->textureProvider()->createTexture(dummyDesc, false, nullptr, 0));

    if (!dummyTexture1 || ! dummyTexture2) {
        SkDebugf("Could not allocate dummy textures");
        return false;
    }

    GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};

    // dummy scissor state
    GrScissorState scissor;

    // wide open clip
    GrClip clip;

    SkRandom random;
    static const int NUM_TESTS = 2048;
    for (int t = 0; t < NUM_TESTS; t++) {
        // setup random render target(can fail)
        SkAutoTUnref<GrRenderTarget> rt(random_render_target(
            context->textureProvider(), &random, context->caps()));
        if (!rt.get()) {
            SkDebugf("Could not allocate render target");
            return false;
        }

        GrPipelineBuilder pipelineBuilder;
        pipelineBuilder.setRenderTarget(rt.get());
        pipelineBuilder.setClip(clip);

        SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context));
        SkASSERT(batch);

        GrProcessorTestData ptd(&random, context, context->caps(), dummyTextures);
        set_random_color_coverage_stages(&pipelineBuilder, &ptd, maxStages);
        set_random_xpf(&pipelineBuilder, &ptd);
        set_random_state(&pipelineBuilder, &random);
        set_random_stencil(&pipelineBuilder, &random);

        drawTarget->drawBatch(pipelineBuilder, batch);
    }
    // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
    drawingManager->flush();

    // Validate that GrFPs work correctly without an input.
    GrSurfaceDesc rtDesc;
    rtDesc.fWidth = kRenderTargetWidth;
    rtDesc.fHeight = kRenderTargetHeight;
    rtDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    rtDesc.fConfig = kRGBA_8888_GrPixelConfig;
    SkAutoTUnref<GrRenderTarget> rt(
        context->textureProvider()->createTexture(rtDesc, false)->asRenderTarget());
    int fpFactoryCnt = GrProcessorTestFactory<GrFragmentProcessor>::Count();
    for (int i = 0; i < fpFactoryCnt; ++i) {
        // Since FP factories internally randomize, call each 10 times.
        for (int j = 0; j < 10; ++j) {
            SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context));
            SkASSERT(batch);
            GrProcessorTestData ptd(&random, context, context->caps(), dummyTextures);
            GrPipelineBuilder builder;
            builder.setXPFactory(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
            builder.setRenderTarget(rt);
            builder.setClip(clip);

            SkAutoTUnref<const GrFragmentProcessor> fp(
                GrProcessorTestFactory<GrFragmentProcessor>::CreateIdx(i, &ptd));
            SkAutoTUnref<const GrFragmentProcessor> blockFP(
                BlockInputFragmentProcessor::Create(fp));
            builder.addColorFragmentProcessor(blockFP);

            drawTarget->drawBatch(builder, batch);
            drawingManager->flush();
        }
    }

    return true;
}
Example #4
0
bool GrGpuGL::programUnitTest(int maxStages) {

    GrTextureDesc dummyDesc;
    dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit;
    dummyDesc.fConfig = kSkia8888_GrPixelConfig;
    dummyDesc.fWidth = 34;
    dummyDesc.fHeight = 18;
    SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
    dummyDesc.fFlags = kNone_GrTextureFlags;
    dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    dummyDesc.fWidth = 16;
    dummyDesc.fHeight = 22;
    SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));

    static const int NUM_TESTS = 512;

    SkRandom random;
    for (int t = 0; t < NUM_TESTS; ++t) {

#if 0
        GrPrintf("\nTest Program %d\n-------------\n", t);
        static const int stop = -1;
        if (t == stop) {
            int breakpointhere = 9;
        }
#endif

        GrGLProgramDesc pdesc;

        int currAttribIndex = 1;  // we need to always leave room for position
        int currTextureCoordSet = 0;
        int attribIndices[2] = { 0, 0 };
        GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};

        int numStages = random.nextULessThan(maxStages + 1);
        int numColorStages = random.nextULessThan(numStages + 1);
        int numCoverageStages = numStages - numColorStages;

        SkAutoSTMalloc<8, const GrEffectStage*> stages(numStages);

        bool useFixedFunctionTexturing = this->shouldUseFixedFunctionTexturing();

        for (int s = 0; s < numStages;) {
            SkAutoTUnref<const GrEffectRef> effect(GrEffectTestFactory::CreateStage(
                                                                            &random,
                                                                            this->getContext(),
                                                                            *this->caps(),
                                                                            dummyTextures));
            SkASSERT(effect);
            int numAttribs = (*effect)->numVertexAttribs();

            // If adding this effect would exceed the max attrib count then generate a
            // new random effect.
            if (currAttribIndex + numAttribs > GrDrawState::kMaxVertexAttribCnt) {
                continue;
            }


            // If adding this effect would exceed the max texture coord set count then generate a
            // new random effect.
            if (useFixedFunctionTexturing && !(*effect)->hasVertexCode()) {
                int numTransforms = (*effect)->numTransforms();
                if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) {
                    continue;
                }
                currTextureCoordSet += numTransforms;
            }

            useFixedFunctionTexturing = useFixedFunctionTexturing && !(*effect)->hasVertexCode();

            for (int i = 0; i < numAttribs; ++i) {
                attribIndices[i] = currAttribIndex++;
            }
            GrEffectStage* stage = SkNEW_ARGS(GrEffectStage,
                                              (effect.get(), attribIndices[0], attribIndices[1]));
            stages[s] = stage;
            ++s;
        }
        const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1];
        pdesc.setRandom(&random,
                        this,
                        dummyTextures[0]->asRenderTarget(),
                        dstTexture,
                        stages.get(),
                        numColorStages,
                        numCoverageStages,
                        currAttribIndex);

        SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this,
                                                              pdesc,
                                                              stages,
                                                              stages + numColorStages));
        for (int s = 0; s < numStages; ++s) {
            SkDELETE(stages[s]);
        }
        if (NULL == program.get()) {
            return false;
        }
    }
    return true;
}
Example #5
0
bool GrGpuGL::programUnitTest() {

    GrTextureDesc dummyDesc;
    dummyDesc.fConfig = kSkia8888_PM_GrPixelConfig;
    dummyDesc.fWidth = 34;
    dummyDesc.fHeight = 18;
    SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
    dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    dummyDesc.fWidth = 16;
    dummyDesc.fHeight = 22;
    SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));

    // GrGLSLGeneration glslGeneration =
            GrGetGLSLGeneration(this->glBinding(), this->glInterface());
    static const int STAGE_OPTS[] = {
        0,
        StageDesc::kNoPerspective_OptFlagBit,
    };
    static const int IN_CONFIG_FLAGS[] = {
        StageDesc::kNone_InConfigFlag,
        StageDesc::kSmearAlpha_InConfigFlag,
    };

    static const int NUM_TESTS = 512;

    GrRandom random;
    for (int t = 0; t < NUM_TESTS; ++t) {

#if 0
        GrPrintf("\nTest Program %d\n-------------\n", t);
        static const int stop = -1;
        if (t == stop) {
            int breakpointhere = 9;
        }
#endif

        ProgramDesc pdesc;
        pdesc.fVertexLayout = 0;
        pdesc.fEmitsPointSize = random.nextF() > .5f;
        pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
        pdesc.fCoverageInput = random_int(&random, ProgramDesc::kColorInputCnt);

        pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);

        pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);

        pdesc.fVertexLayout |= random_bool(&random) ?
                                    GrDrawTarget::kCoverage_VertexLayoutBit :
                                    0;

#if GR_GL_EXPERIMENTAL_GS
        pdesc.fExperimentalGS = this->getCaps().geometryShaderSupport() &&
                                random_bool(&random);
#endif

        bool edgeAA = random_bool(&random);
        if (edgeAA) {
            pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
            if (this->getCaps().shaderDerivativeSupport()) {
                pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
            } else {
                pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
            }
        } else {
        }

        pdesc.fColorMatrixEnabled = random_bool(&random);

        if (this->getCaps().dualSourceBlendingSupport()) {
            pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
        } else {
            pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
        }

        SkAutoTUnref<const GrCustomStage> customStages[GrDrawState::kNumStages];

        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
            StageDesc& stage = pdesc.fStages[s];
            // enable the stage?
            if (random_bool(&random)) {
                // use separate tex coords?
                if (random_bool(&random)) {
                    int t = random_int(&random, GrDrawState::kMaxTexCoords);
                    pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
                }
                stage.setEnabled(true);
            }
            // use text-formatted verts?
            if (random_bool(&random)) {
                pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
            }

            stage.fCustomStageKey = 0;

            stage.fOptFlags |= STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
            stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];

            if (stage.isEnabled()) {
                GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
                customStages[s].reset(create_random_effect(&stage,
                                                           &random,
                                                           getContext(),
                                                           dummyTextures));
                if (NULL != customStages[s]) {
                    stage.fCustomStageKey =
                        customStages[s]->getFactory().glStageKey(*customStages[s], this->glCaps());
                }
            }
        }
        GR_STATIC_ASSERT(sizeof(customStages) ==
                         GrDrawState::kNumStages * sizeof(GrCustomStage*));
        const GrCustomStage** stages = reinterpret_cast<const GrCustomStage**>(&customStages);
        SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContextInfo(),
                                                              pdesc,
                                                              stages));
        if (NULL == program.get()) {
            return false;
        }
    }
    return true;
}
Example #6
0
bool GrDrawTarget::programUnitTest(GrContext* context, int maxStages) {
    // setup dummy textures
    GrSurfaceDesc dummyDesc;
    dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    dummyDesc.fConfig = kSkia8888_GrPixelConfig;
    dummyDesc.fWidth = 34;
    dummyDesc.fHeight = 18;
    SkAutoTUnref<GrTexture> dummyTexture1(
        context->textureProvider()->createTexture(dummyDesc, false, nullptr, 0));
    dummyDesc.fFlags = kNone_GrSurfaceFlags;
    dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
    dummyDesc.fWidth = 16;
    dummyDesc.fHeight = 22;
    SkAutoTUnref<GrTexture> dummyTexture2(
        context->textureProvider()->createTexture(dummyDesc, false, nullptr, 0));

    if (!dummyTexture1 || ! dummyTexture2) {
        SkDebugf("Could not allocate dummy textures");
        return false;
    }

    GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};

    // dummy scissor state
    GrScissorState scissor;

    // wide open clip
    GrClip clip;

    SkRandom random;
    static const int NUM_TESTS = 2048;
    for (int t = 0; t < NUM_TESTS; t++) {
        // setup random render target(can fail)
        SkAutoTUnref<GrRenderTarget> rt(random_render_target(
            context->textureProvider(), &random, this->caps()));
        if (!rt.get()) {
            SkDebugf("Could not allocate render target");
            return false;
        }

        GrPipelineBuilder pipelineBuilder;
        pipelineBuilder.setRenderTarget(rt.get());
        pipelineBuilder.setClip(clip);

        SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context));
        SkASSERT(batch);

        GrProcessorDataManager procDataManager;
        GrProcessorTestData ptd(&random, context, &procDataManager, fGpu->caps(), dummyTextures);
        set_random_color_coverage_stages(&pipelineBuilder, &ptd, maxStages);
        set_random_xpf(&pipelineBuilder, &ptd);
        set_random_state(&pipelineBuilder, &random);
        set_random_stencil(&pipelineBuilder, &random);

        this->drawBatch(pipelineBuilder, batch);
    }

    // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
    this->flush();
    return true;
}