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

#include "GrGradientEffects.h"
#include "gl/GrGLProgramStage.h"
#include "GrProgramStageFactory.h"

/////////////////////////////////////////////////////////////////////

class GrGLRadialGradient : public GrGLProgramStage {

public:

    GrGLRadialGradient(const GrProgramStageFactory& factory,
                       const GrCustomStage&) : INHERITED (factory) { }
    virtual ~GrGLRadialGradient() { }

    virtual void emitVS(GrGLShaderBuilder* state,
                        const char* vertexCoords) SK_OVERRIDE { }
    virtual void emitFS(GrGLShaderBuilder* state,
                        const char* outputColor,
                        const char* inputColor,
                        const char* samplerName) SK_OVERRIDE;

    static StageKey GenKey(const GrCustomStage& s) { return 0; }

private:

    typedef GrGLProgramStage INHERITED;

};

void GrGLRadialGradient::emitFS(GrGLShaderBuilder* state,
                        const char* outputColor,
                        const char* inputColor,
                        const char* samplerName) {
    state->fSampleCoords.printf("vec2(length(%s.xy), 0.5)",
                                state->fSampleCoords.c_str());
    state->fComplexCoord = true;

    state->emitDefaultFetch(outputColor, samplerName);
}

/////////////////////////////////////////////////////////////////////

GrRadialGradient::GrRadialGradient() {

}

GrRadialGradient::~GrRadialGradient() {

}

const GrProgramStageFactory& GrRadialGradient::getFactory() const {
    return GrTProgramStageFactory<GrRadialGradient>::getInstance();
}

bool GrRadialGradient::isEqual(const GrCustomStage& sBase) const {
    return true;
}

/////////////////////////////////////////////////////////////////////

class GrGLRadial2Gradient : public GrGLProgramStage {

public:

    GrGLRadial2Gradient(const GrProgramStageFactory& factory,
                        const GrCustomStage&);
    virtual ~GrGLRadial2Gradient() { }

    virtual void setupVariables(GrGLShaderBuilder* state,
                                int stage) SK_OVERRIDE;
    virtual void emitVS(GrGLShaderBuilder* state,
                        const char* vertexCoords) SK_OVERRIDE;
    virtual void emitFS(GrGLShaderBuilder* state,
                        const char* outputColor,
                        const char* inputColor,
                        const char* samplerName) SK_OVERRIDE;
    virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
    virtual void setData(const GrGLInterface*,
                         const GrGLTexture&,
                         const GrCustomStage&,
                         int stageNum) SK_OVERRIDE;

    static StageKey GenKey(const GrCustomStage& s) {
        return (static_cast<const GrRadial2Gradient&>(s).isDegenerate());
    }

protected:

    const GrGLShaderVar* fParamVar;
    GrGLint fParamLocation;

    const char* fVSVaryingName;
    const char* fFSVaryingName;

    bool fIsDegenerate;

    // @{
    /// Values last uploaded as uniforms

    GrScalar fCachedCenter;
    GrScalar fCachedRadius;
    bool     fCachedPosRoot;

    // @}

private:

    typedef GrGLProgramStage INHERITED;

};

GrGLRadial2Gradient::GrGLRadial2Gradient(
        const GrProgramStageFactory& factory,
        const GrCustomStage& baseData)
    : INHERITED(factory)
    , fParamVar(NULL)
    , fVSVaryingName(NULL)
    , fFSVaryingName(NULL)
    , fCachedCenter(GR_ScalarMax)
    , fCachedRadius(-GR_ScalarMax)
    , fCachedPosRoot(0) {

    const GrRadial2Gradient& data =
        static_cast<const GrRadial2Gradient&>(baseData);
    fIsDegenerate = data.isDegenerate();
}

void GrGLRadial2Gradient::setupVariables(GrGLShaderBuilder* state, int stage) {
    fParamVar = &state->addUniform(
        GrGLShaderBuilder::kBoth_VariableLifetime,
        kFloat_GrSLType, "uRadial2Params", stage, 6);

    fParamLocation = GrGLProgramStage::kUseUniform;

    // For radial gradients without perspective we can pass the linear
    // part of the quadratic as a varying.
    if (state->fVaryingDims == state->fCoordDims) {
        state->addVarying(kFloat_GrSLType, "Radial2BCoeff", stage,
                          &fVSVaryingName, &fFSVaryingName);
    }
}

void GrGLRadial2Gradient::emitVS(GrGLShaderBuilder* state,
                        const char* vertexCoords) {
    GrStringBuilder* code = &state->fVSCode;
    GrStringBuilder p2;
    GrStringBuilder p3;
    fParamVar->appendArrayAccess(2, &p2);
    fParamVar->appendArrayAccess(3, &p3);

    // For radial gradients without perspective we can pass the linear
    // part of the quadratic as a varying.
    if (state->fVaryingDims == state->fCoordDims) {
        // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
        code->appendf("\t%s = 2.0 *(%s * %s.x - %s);\n",
                      fVSVaryingName, p2.c_str(),
                      vertexCoords, p3.c_str());
    }
}

void GrGLRadial2Gradient::emitFS(GrGLShaderBuilder* state,
                        const char* outputColor,
                        const char* inputColor,
                        const char* samplerName) {
    GrStringBuilder* code = &state->fFSCode;
    GrStringBuilder cName("c");
    GrStringBuilder ac4Name("ac4");
    GrStringBuilder rootName("root");
    GrStringBuilder p0;
    GrStringBuilder p1;
    GrStringBuilder p2;
    GrStringBuilder p3;
    GrStringBuilder p4;
    GrStringBuilder p5;
    fParamVar->appendArrayAccess(0, &p0);
    fParamVar->appendArrayAccess(1, &p1);
    fParamVar->appendArrayAccess(2, &p2);
    fParamVar->appendArrayAccess(3, &p3);
    fParamVar->appendArrayAccess(4, &p4);
    fParamVar->appendArrayAccess(5, &p5);

    // If we we're able to interpolate the linear component,
    // bVar is the varying; otherwise compute it
    GrStringBuilder bVar;
    if (state->fCoordDims == state->fVaryingDims) {
        bVar = fFSVaryingName;
        GrAssert(2 == state->fVaryingDims);
    } else {
        GrAssert(3 == state->fVaryingDims);
        bVar = "b";
        //bVar.appendS32(stageNum);
        code->appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n",
                      bVar.c_str(), p2.c_str(),
                      state->fSampleCoords.c_str(), p3.c_str());
    }

    // c = (x^2)+(y^2) - params[4]
    code->appendf("\tfloat %s = dot(%s, %s) - %s;\n",
                  cName.c_str(), state->fSampleCoords.c_str(),
                  state->fSampleCoords.c_str(),
                  p4.c_str());

    // If we aren't degenerate, emit some extra code, and accept a slightly
    // more complex coord.
    if (!fIsDegenerate) {

        // ac4 = 4.0 * params[0] * c
        code->appendf("\tfloat %s = %s * 4.0 * %s;\n",
                      ac4Name.c_str(), p0.c_str(),
                      cName.c_str());

        // root = sqrt(b^2-4ac)
        // (abs to avoid exception due to fp precision)
        code->appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
                      rootName.c_str(), bVar.c_str(), bVar.c_str(),
                      ac4Name.c_str());

        // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
        // y coord is 0.5 (texture is effectively 1D)
        state->fSampleCoords.printf("vec2((-%s + %s * %s) * %s, 0.5)",
                            bVar.c_str(), p5.c_str(),
                            rootName.c_str(), p1.c_str());
    } else {
        // x coord is: -c/b
        // y coord is 0.5 (texture is effectively 1D)
        state->fSampleCoords.printf("vec2((-%s / %s), 0.5)",
                            cName.c_str(), bVar.c_str());
    }
    state->fComplexCoord = true;

    state->emitDefaultFetch(outputColor, samplerName);
}

void GrGLRadial2Gradient::initUniforms(const GrGLInterface* gl, int programID) {
    GR_GL_CALL_RET(gl, fParamLocation,
        GetUniformLocation(programID, fParamVar->getName().c_str()));
}

void GrGLRadial2Gradient::setData(const GrGLInterface* gl,
                                 const GrGLTexture& texture,
                                 const GrCustomStage& baseData,
                                 int stageNum) {
    const GrRadial2Gradient& data =
        static_cast<const GrRadial2Gradient&>(baseData);
    GrAssert(data.isDegenerate() == fIsDegenerate);
    GrScalar centerX1 = data.center();
    GrScalar radius0 = data.radius();
    if (fCachedCenter != centerX1 ||
        fCachedRadius != radius0 ||
        fCachedPosRoot != data.isPosRoot()) {

        GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;

        // When we're in the degenerate (linear) case, the second
        // value will be INF but the program doesn't read it. (We
        // use the same 6 uniforms even though we don't need them
        // all in the linear case just to keep the code complexity
        // down).
        float values[6] = {
            GrScalarToFloat(a),
            1 / (2.f * GrScalarToFloat(a)),
            GrScalarToFloat(centerX1),
            GrScalarToFloat(radius0),
            GrScalarToFloat(GrMul(radius0, radius0)),
            data.isPosRoot() ? 1.f : -1.f
        };

        GR_GL_CALL(gl, Uniform1fv(fParamLocation, 6, values));
        fCachedCenter = centerX1;
        fCachedRadius = radius0;
        fCachedPosRoot = data.isPosRoot();
    }
}

/////////////////////////////////////////////////////////////////////

GrRadial2Gradient::GrRadial2Gradient(GrScalar center,
                                     GrScalar radius,
                                     bool posRoot)
    : fCenterX1 (center)
    , fRadius0 (radius)
    , fPosRoot (posRoot) {

}

GrRadial2Gradient::~GrRadial2Gradient() {

}

const GrProgramStageFactory& GrRadial2Gradient::getFactory() const {
    return GrTProgramStageFactory<GrRadial2Gradient>::getInstance();
}

bool GrRadial2Gradient::isEqual(const GrCustomStage& sBase) const {
    const GrRadial2Gradient& s = static_cast<const GrRadial2Gradient&>(sBase);
    return (this->isDegenerate() == s.isDegenerate());
}

/////////////////////////////////////////////////////////////////////

class GrGLSweepGradient : public GrGLProgramStage {

public:

    GrGLSweepGradient(const GrProgramStageFactory& factory,
                      const GrCustomStage&) : INHERITED (factory) { }
    virtual ~GrGLSweepGradient() { }

    virtual void emitVS(GrGLShaderBuilder* state,
                        const char* vertexCoords) SK_OVERRIDE { }
    virtual void emitFS(GrGLShaderBuilder* state,
                        const char* outputColor,
                        const char* inputColor,
                        const char* samplerName) SK_OVERRIDE;

    static StageKey GenKey(const GrCustomStage& s) { return 0; }

private:

    typedef GrGLProgramStage INHERITED;

};

void GrGLSweepGradient::emitFS(GrGLShaderBuilder* state,
                              const char* outputColor,
                              const char* inputColor,
                              const char* samplerName) {
    state->fSampleCoords.printf(
        "vec2(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5, 0.5)",
        state->fSampleCoords.c_str(), state->fSampleCoords.c_str());
    state->fComplexCoord = true;

    state->emitDefaultFetch(outputColor, samplerName);
}

/////////////////////////////////////////////////////////////////////

GrSweepGradient::GrSweepGradient() {

}

GrSweepGradient::~GrSweepGradient() {

}

const GrProgramStageFactory& GrSweepGradient::getFactory() const {
    return GrTProgramStageFactory<GrSweepGradient>::getInstance();
}

bool GrSweepGradient::isEqual(const GrCustomStage& sBase) const {
    return true;
}

<commit_msg>Split two-point radial gradient parameters into two arrays of uniforms, to avoid sharing arrays between fragment & vertex shaders. Appears to work around driver bug on Xoom.<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrGradientEffects.h"
#include "gl/GrGLProgramStage.h"
#include "GrProgramStageFactory.h"

/////////////////////////////////////////////////////////////////////

class GrGLRadialGradient : public GrGLProgramStage {

public:

    GrGLRadialGradient(const GrProgramStageFactory& factory,
                       const GrCustomStage&) : INHERITED (factory) { }
    virtual ~GrGLRadialGradient() { }

    virtual void emitVS(GrGLShaderBuilder* state,
                        const char* vertexCoords) SK_OVERRIDE { }
    virtual void emitFS(GrGLShaderBuilder* state,
                        const char* outputColor,
                        const char* inputColor,
                        const char* samplerName) SK_OVERRIDE;

    static StageKey GenKey(const GrCustomStage& s) { return 0; }

private:

    typedef GrGLProgramStage INHERITED;

};

void GrGLRadialGradient::emitFS(GrGLShaderBuilder* state,
                        const char* outputColor,
                        const char* inputColor,
                        const char* samplerName) {
    state->fSampleCoords.printf("vec2(length(%s.xy), 0.5)",
                                state->fSampleCoords.c_str());
    state->fComplexCoord = true;

    state->emitDefaultFetch(outputColor, samplerName);
}

/////////////////////////////////////////////////////////////////////

GrRadialGradient::GrRadialGradient() {

}

GrRadialGradient::~GrRadialGradient() {

}

const GrProgramStageFactory& GrRadialGradient::getFactory() const {
    return GrTProgramStageFactory<GrRadialGradient>::getInstance();
}

bool GrRadialGradient::isEqual(const GrCustomStage& sBase) const {
    return true;
}

/////////////////////////////////////////////////////////////////////

class GrGLRadial2Gradient : public GrGLProgramStage {

public:

    GrGLRadial2Gradient(const GrProgramStageFactory& factory,
                        const GrCustomStage&);
    virtual ~GrGLRadial2Gradient() { }

    virtual void setupVariables(GrGLShaderBuilder* state,
                                int stage) SK_OVERRIDE;
    virtual void emitVS(GrGLShaderBuilder* state,
                        const char* vertexCoords) SK_OVERRIDE;
    virtual void emitFS(GrGLShaderBuilder* state,
                        const char* outputColor,
                        const char* inputColor,
                        const char* samplerName) SK_OVERRIDE;
    virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
    virtual void setData(const GrGLInterface*,
                         const GrGLTexture&,
                         const GrCustomStage&,
                         int stageNum) SK_OVERRIDE;

    static StageKey GenKey(const GrCustomStage& s) {
        return (static_cast<const GrRadial2Gradient&>(s).isDegenerate());
    }

protected:

    const GrGLShaderVar* fVSParamVar;
    GrGLint fVSParamLocation;
    const GrGLShaderVar* fFSParamVar;
    GrGLint fFSParamLocation;

    const char* fVSVaryingName;
    const char* fFSVaryingName;

    bool fIsDegenerate;

    // @{
    /// Values last uploaded as uniforms

    GrScalar fCachedCenter;
    GrScalar fCachedRadius;
    bool     fCachedPosRoot;

    // @}

private:

    typedef GrGLProgramStage INHERITED;

};

GrGLRadial2Gradient::GrGLRadial2Gradient(
        const GrProgramStageFactory& factory,
        const GrCustomStage& baseData)
    : INHERITED(factory)
    , fVSParamVar(NULL)
    , fFSParamVar(NULL)
    , fVSVaryingName(NULL)
    , fFSVaryingName(NULL)
    , fCachedCenter(GR_ScalarMax)
    , fCachedRadius(-GR_ScalarMax)
    , fCachedPosRoot(0) {

    const GrRadial2Gradient& data =
        static_cast<const GrRadial2Gradient&>(baseData);
    fIsDegenerate = data.isDegenerate();
}

void GrGLRadial2Gradient::setupVariables(GrGLShaderBuilder* state, int stage) {
    // 2 copies of uniform array, 1 for each of vertex & fragment shader,
    // to work around Xoom bug. Doesn't seem to cause performance decrease
    // in test apps, but need to keep an eye on it.
    fVSParamVar = &state->addUniform(
        GrGLShaderBuilder::kVertex_VariableLifetime,
        kFloat_GrSLType, "uRadial2VSParams", stage, 6);
    fFSParamVar = &state->addUniform(
        GrGLShaderBuilder::kFragment_VariableLifetime,
        kFloat_GrSLType, "uRadial2FSParams", stage, 6);

    fVSParamLocation = GrGLProgramStage::kUseUniform;
    fFSParamLocation = GrGLProgramStage::kUseUniform;

    // For radial gradients without perspective we can pass the linear
    // part of the quadratic as a varying.
    if (state->fVaryingDims == state->fCoordDims) {
        state->addVarying(kFloat_GrSLType, "Radial2BCoeff", stage,
                          &fVSVaryingName, &fFSVaryingName);
    }
}

void GrGLRadial2Gradient::emitVS(GrGLShaderBuilder* state,
                        const char* vertexCoords) {
    GrStringBuilder* code = &state->fVSCode;
    GrStringBuilder p2;
    GrStringBuilder p3;
    fVSParamVar->appendArrayAccess(2, &p2);
    fVSParamVar->appendArrayAccess(3, &p3);

    // For radial gradients without perspective we can pass the linear
    // part of the quadratic as a varying.
    if (state->fVaryingDims == state->fCoordDims) {
        // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
        code->appendf("\t%s = 2.0 *(%s * %s.x - %s);\n",
                      fVSVaryingName, p2.c_str(),
                      vertexCoords, p3.c_str());
    }
}

void GrGLRadial2Gradient::emitFS(GrGLShaderBuilder* state,
                        const char* outputColor,
                        const char* inputColor,
                        const char* samplerName) {
    GrStringBuilder* code = &state->fFSCode;
    GrStringBuilder cName("c");
    GrStringBuilder ac4Name("ac4");
    GrStringBuilder rootName("root");
    GrStringBuilder p0;
    GrStringBuilder p1;
    GrStringBuilder p2;
    GrStringBuilder p3;
    GrStringBuilder p4;
    GrStringBuilder p5;
    fFSParamVar->appendArrayAccess(0, &p0);
    fFSParamVar->appendArrayAccess(1, &p1);
    fFSParamVar->appendArrayAccess(2, &p2);
    fFSParamVar->appendArrayAccess(3, &p3);
    fFSParamVar->appendArrayAccess(4, &p4);
    fFSParamVar->appendArrayAccess(5, &p5);

    // If we we're able to interpolate the linear component,
    // bVar is the varying; otherwise compute it
    GrStringBuilder bVar;
    if (state->fCoordDims == state->fVaryingDims) {
        bVar = fFSVaryingName;
        GrAssert(2 == state->fVaryingDims);
    } else {
        GrAssert(3 == state->fVaryingDims);
        bVar = "b";
        //bVar.appendS32(stageNum);
        code->appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n",
                      bVar.c_str(), p2.c_str(),
                      state->fSampleCoords.c_str(), p3.c_str());
    }

    // c = (x^2)+(y^2) - params[4]
    code->appendf("\tfloat %s = dot(%s, %s) - %s;\n",
                  cName.c_str(), state->fSampleCoords.c_str(),
                  state->fSampleCoords.c_str(),
                  p4.c_str());

    // If we aren't degenerate, emit some extra code, and accept a slightly
    // more complex coord.
    if (!fIsDegenerate) {

        // ac4 = 4.0 * params[0] * c
        code->appendf("\tfloat %s = %s * 4.0 * %s;\n",
                      ac4Name.c_str(), p0.c_str(),
                      cName.c_str());

        // root = sqrt(b^2-4ac)
        // (abs to avoid exception due to fp precision)
        code->appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
                      rootName.c_str(), bVar.c_str(), bVar.c_str(),
                      ac4Name.c_str());

        // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
        // y coord is 0.5 (texture is effectively 1D)
        state->fSampleCoords.printf("vec2((-%s + %s * %s) * %s, 0.5)",
                            bVar.c_str(), p5.c_str(),
                            rootName.c_str(), p1.c_str());
    } else {
        // x coord is: -c/b
        // y coord is 0.5 (texture is effectively 1D)
        state->fSampleCoords.printf("vec2((-%s / %s), 0.5)",
                            cName.c_str(), bVar.c_str());
    }
    state->fComplexCoord = true;

    state->emitDefaultFetch(outputColor, samplerName);
}

void GrGLRadial2Gradient::initUniforms(const GrGLInterface* gl, int programID) {
    GR_GL_CALL_RET(gl, fVSParamLocation,
        GetUniformLocation(programID, fVSParamVar->getName().c_str()));
    GR_GL_CALL_RET(gl, fFSParamLocation,
        GetUniformLocation(programID, fFSParamVar->getName().c_str()));
}

void GrGLRadial2Gradient::setData(const GrGLInterface* gl,
                                 const GrGLTexture& texture,
                                 const GrCustomStage& baseData,
                                 int stageNum) {
    const GrRadial2Gradient& data =
        static_cast<const GrRadial2Gradient&>(baseData);
    GrAssert(data.isDegenerate() == fIsDegenerate);
    GrScalar centerX1 = data.center();
    GrScalar radius0 = data.radius();
    if (fCachedCenter != centerX1 ||
        fCachedRadius != radius0 ||
        fCachedPosRoot != data.isPosRoot()) {

        GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;

        // When we're in the degenerate (linear) case, the second
        // value will be INF but the program doesn't read it. (We
        // use the same 6 uniforms even though we don't need them
        // all in the linear case just to keep the code complexity
        // down).
        float values[6] = {
            GrScalarToFloat(a),
            1 / (2.f * GrScalarToFloat(a)),
            GrScalarToFloat(centerX1),
            GrScalarToFloat(radius0),
            GrScalarToFloat(GrMul(radius0, radius0)),
            data.isPosRoot() ? 1.f : -1.f
        };

        GR_GL_CALL(gl, Uniform1fv(fVSParamLocation, 6, values));
        GR_GL_CALL(gl, Uniform1fv(fFSParamLocation, 6, values));
        fCachedCenter = centerX1;
        fCachedRadius = radius0;
        fCachedPosRoot = data.isPosRoot();
    }
}

/////////////////////////////////////////////////////////////////////

GrRadial2Gradient::GrRadial2Gradient(GrScalar center,
                                     GrScalar radius,
                                     bool posRoot)
    : fCenterX1 (center)
    , fRadius0 (radius)
    , fPosRoot (posRoot) {

}

GrRadial2Gradient::~GrRadial2Gradient() {

}

const GrProgramStageFactory& GrRadial2Gradient::getFactory() const {
    return GrTProgramStageFactory<GrRadial2Gradient>::getInstance();
}

bool GrRadial2Gradient::isEqual(const GrCustomStage& sBase) const {
    const GrRadial2Gradient& s = static_cast<const GrRadial2Gradient&>(sBase);
    return (this->isDegenerate() == s.isDegenerate());
}

/////////////////////////////////////////////////////////////////////

class GrGLSweepGradient : public GrGLProgramStage {

public:

    GrGLSweepGradient(const GrProgramStageFactory& factory,
                      const GrCustomStage&) : INHERITED (factory) { }
    virtual ~GrGLSweepGradient() { }

    virtual void emitVS(GrGLShaderBuilder* state,
                        const char* vertexCoords) SK_OVERRIDE { }
    virtual void emitFS(GrGLShaderBuilder* state,
                        const char* outputColor,
                        const char* inputColor,
                        const char* samplerName) SK_OVERRIDE;

    static StageKey GenKey(const GrCustomStage& s) { return 0; }

private:

    typedef GrGLProgramStage INHERITED;

};

void GrGLSweepGradient::emitFS(GrGLShaderBuilder* state,
                              const char* outputColor,
                              const char* inputColor,
                              const char* samplerName) {
    state->fSampleCoords.printf(
        "vec2(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5, 0.5)",
        state->fSampleCoords.c_str(), state->fSampleCoords.c_str());
    state->fComplexCoord = true;

    state->emitDefaultFetch(outputColor, samplerName);
}

/////////////////////////////////////////////////////////////////////

GrSweepGradient::GrSweepGradient() {

}

GrSweepGradient::~GrSweepGradient() {

}

const GrProgramStageFactory& GrSweepGradient::getFactory() const {
    return GrTProgramStageFactory<GrSweepGradient>::getInstance();
}

bool GrSweepGradient::isEqual(const GrCustomStage& sBase) const {
    return true;
}

<|endoftext|>


<commit_before>#ifdef LOCAL_OPENCV
#include <opencv2/features2d.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/opencv.hpp>
#else
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#endif

#include <iomanip>
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

// http://stackoverflow.com/questions/675039/how-can-i-create-directory-tree-in-c-linux
#include <errno.h>     // errno, ENOENT, EEXIST
#include <sys/stat.h>  // stat
#include <string>
#if defined(_WIN32)
#include <direct.h>  // _mkdir
#endif

bool isDirExist(const std::string& path) {
#if defined(_WIN32)
  struct _stat info;
  if (_stat(path.c_str(), &info) != 0) {
    return false;
  }
  return (info.st_mode & _S_IFDIR) != 0;
#else
  struct stat info;
  if (stat(path.c_str(), &info) != 0) {
    return false;
  }
  return (info.st_mode & S_IFDIR) != 0;
#endif
}

bool makePath(const std::string& path) {
#if defined(_WIN32)
  int ret = _mkdir(path.c_str());
#else
  mode_t mode = 0755;
  int ret = mkdir(path.c_str(), mode);
#endif
  if (ret == 0) return true;

  switch (errno) {
    case ENOENT:
      // parent didn't exist, try to create it
      {
        int pos = path.find_last_of('/');
        if ((size_t)pos == std::string::npos)
#if defined(_WIN32)
          pos = path.find_last_of('\\');
        if (pos == std::string::npos)
#endif
          return false;
        if (!makePath(path.substr(0, pos))) return false;
      }
      // now, try to create again
#if defined(_WIN32)
      return 0 == _mkdir(path.c_str());
#else
      return 0 == mkdir(path.c_str(), mode);
#endif

    case EEXIST:
      // done!
      return isDirExist(path);

    default:
      return false;
  }
}

int main(int argc, char** argv) {

  if (argc < 3) {
    std::cout << "Dump all frames of a video into a folder\n";
    std::cout
        << "Frames are named by their timestamps in the video in nanosecs\n";
    std::cout << "Usage: " << argv[0]
              << " input_video_name /output/image/folder [start_index(=0)] "
                 "[finish_index(inclusive)]\n";
    std::cout
        << "If you are convert the video for kalibr, set start_index such that "
           "the start from has a timestamp greater than 1 sec\n";
    std::cout << "to avoid timestamp less than 9 digits causing error in "
                 "kalibr_bagcreator\n";
    std::cout << "The output does not need to exist beforehand\n";
    std::cout << "Ex:" << argv[0]
              << "/home/user/Desktop/IMG_0658.MOV /home/user/Desktop/IMG_0658/"
              << std::endl;

    return 1;
  }

  int startIndex = 0, finishIndex = 1e6;
  if (argc > 3) {
    startIndex = std::atoi(argv[3]);
  }
  if (argc > 4) {
    finishIndex = std::atoi(argv[4]);
  }
  std::cout << "start and finish index " << startIndex << " " << finishIndex
            << std::endl;
  std::string videoName(argv[1]);
  std::string imageSeqPath = argv[2];
  makePath(argv[2]);

  std::string windowName = "DisplayVideo";
  cv::namedWindow(windowName, CV_WINDOW_AUTOSIZE);

  int downscale = 1;
  cv::VideoCapture cap(videoName);
  char buffer[100];
  double rate = cap.get(CV_CAP_PROP_FPS);
  if (!rate) cerr << "Error opening video file " << videoName << endl;

  assert(cap.get(CV_CAP_PROP_POS_FRAMES) == 0);
  assert(cap.get(CV_CAP_PROP_POS_MSEC) == 0);

  cap.set(CV_CAP_PROP_POS_FRAMES, startIndex);  // start from a 0 based index
  int totalImages =
      std::min(finishIndex, (int)cap.get(CV_CAP_PROP_FRAME_COUNT) - 1);
  int width = cap.get(CV_CAP_PROP_FRAME_WIDTH),
      height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);

  cv::Mat left_img, dst, last_left_img;
  double time_frame(-1);  // unit milli sec
  double last_time_frame(-1);
  for (int numImages = startIndex; numImages <= totalImages; ++numImages) {
    int currentId = cap.get(CV_CAP_PROP_POS_FRAMES);
    if (currentId != numImages) {
      cout << "current image video id 0 based " << currentId << " and counter "
           << numImages << endl;
    }
    time_frame = cap.get(CV_CAP_PROP_POS_MSEC);

    cout << "frame time " << std::setprecision(16) << time_frame
         << "[ms] and index " << numImages;
    if (last_time_frame != -1) {
      std::cout << " " << (time_frame - last_time_frame) * 1000000 << "[ns]";
    }
    std::cout << std::endl;
    cap.read(left_img);
    if (left_img.empty()) {  // this happens when a frame is missed
      continue;
    }
    if (downscale > 1) {
      cv::pyrDown(left_img, dst, cv::Size((width + 1) / 2, (height + 1) / 2));
      left_img = dst;
    }
    if (numImages % 30 == 0)
      std::cout << "process image of index in the video " << numImages
                << std::endl;
    sprintf(buffer, "%.0f.png", time_frame * 1e6);
    string filename = imageSeqPath + '/' + buffer;
    imwrite(filename, left_img);
    imshow(windowName, left_img);
    waitKey(3);
    last_time_frame = time_frame;
  }
  cv::destroyWindow(windowName);
}
<commit_msg>Update video2images_kalibr.cpp<commit_after>#ifdef LOCAL_OPENCV
#include <opencv2/features2d.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/opencv.hpp>
#else
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#endif

#include <iomanip>
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

// http://stackoverflow.com/questions/675039/how-can-i-create-directory-tree-in-c-linux
#include <errno.h>     // errno, ENOENT, EEXIST
#include <sys/stat.h>  // stat
#include <string>
#if defined(_WIN32)
#include <direct.h>  // _mkdir
#endif

bool isDirExist(const std::string& path) {
#if defined(_WIN32)
  struct _stat info;
  if (_stat(path.c_str(), &info) != 0) {
    return false;
  }
  return (info.st_mode & _S_IFDIR) != 0;
#else
  struct stat info;
  if (stat(path.c_str(), &info) != 0) {
    return false;
  }
  return (info.st_mode & S_IFDIR) != 0;
#endif
}

bool makePath(const std::string& path) {
#if defined(_WIN32)
  int ret = _mkdir(path.c_str());
#else
  mode_t mode = 0755;
  int ret = mkdir(path.c_str(), mode);
#endif
  if (ret == 0) return true;

  switch (errno) {
    case ENOENT:
      // parent didn't exist, try to create it
      {
        int pos = path.find_last_of('/');
        if ((size_t)pos == std::string::npos)
#if defined(_WIN32)
          pos = path.find_last_of('\\');
        if (pos == std::string::npos)
#endif
          return false;
        if (!makePath(path.substr(0, pos))) return false;
      }
      // now, try to create again
#if defined(_WIN32)
      return 0 == _mkdir(path.c_str());
#else
      return 0 == mkdir(path.c_str(), mode);
#endif

    case EEXIST:
      // done!
      return isDirExist(path);

    default:
      return false;
  }
}

int main(int argc, char** argv) {

  if (argc < 3) {
    std::cout << "Dump all frames of a video into a folder\n";
    std::cout
        << "Frames are named by their timestamps in the video in nanosecs\n";
    std::cout << "Usage: " << argv[0]
              << " input_video_name /output/image/folder [start_index(=0)] "
                 "[finish_index(inclusive)]\n";
    std::cout
        << "If you are convert the video for kalibr, set start_index such that "
           "the start from has a timestamp greater than 1 sec\n";
    std::cout << "to avoid timestamp less than 9 digits causing error in "
                 "kalibr_bagcreator\n";
    std::cout << "The output does not need to exist beforehand\n";
    std::cout << "Ex: " << argv[0]
              << " /home/user/Desktop/IMG_0658.MOV /home/user/Desktop/IMG_0658/"
              << std::endl;

    return 1;
  }

  int startIndex = 0, finishIndex = 1e6;
  if (argc > 3) {
    startIndex = std::atoi(argv[3]);
  }
  if (argc > 4) {
    finishIndex = std::atoi(argv[4]);
  }
  std::cout << "start and finish index " << startIndex << " " << finishIndex
            << std::endl;
  std::string videoName(argv[1]);
  std::string imageSeqPath = argv[2];
  makePath(argv[2]);

  std::string windowName = "DisplayVideo";
  cv::namedWindow(windowName, CV_WINDOW_AUTOSIZE);

  int downscale = 1;
  cv::VideoCapture cap(videoName);
  char buffer[100];
  double rate = cap.get(CV_CAP_PROP_FPS);
  if (!rate) cerr << "Error opening video file " << videoName << endl;

  assert(cap.get(CV_CAP_PROP_POS_FRAMES) == 0);
  assert(cap.get(CV_CAP_PROP_POS_MSEC) == 0);

  cap.set(CV_CAP_PROP_POS_FRAMES, startIndex);  // start from a 0 based index
  int totalImages =
      std::min(finishIndex, (int)cap.get(CV_CAP_PROP_FRAME_COUNT) - 1);
  int width = cap.get(CV_CAP_PROP_FRAME_WIDTH),
      height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);

  cv::Mat left_img, dst, last_left_img;
  double time_frame(-1);  // unit milli sec
  double last_time_frame(-1);
  for (int numImages = startIndex; numImages <= totalImages; ++numImages) {
    int currentId = cap.get(CV_CAP_PROP_POS_FRAMES);
    if (currentId != numImages) {
      cout << "current image video id 0 based " << currentId << " and counter "
           << numImages << endl;
    }
    time_frame = cap.get(CV_CAP_PROP_POS_MSEC);

    cout << "frame time " << std::setprecision(16) << time_frame
         << "[ms] and index " << numImages;
    if (last_time_frame != -1) {
      std::cout << " " << (time_frame - last_time_frame) * 1000000 << "[ns]";
    }
    std::cout << std::endl;
    cap.read(left_img);
    if (left_img.empty()) {  // this happens when a frame is missed
      continue;
    }
    if (downscale > 1) {
      cv::pyrDown(left_img, dst, cv::Size((width + 1) / 2, (height + 1) / 2));
      left_img = dst;
    }
    if (numImages % 30 == 0)
      std::cout << "process image of index in the video " << numImages
                << std::endl;
    sprintf(buffer, "%.0f.png", time_frame * 1e6);
    string filename = imageSeqPath + '/' + buffer;
    imwrite(filename, left_img);
    imshow(windowName, left_img);
    waitKey(3);
    last_time_frame = time_frame;
  }
  cv::destroyWindow(windowName);
}
<|endoftext|>


<commit_before>#include "cinder/app/App.h"
#include "metal.h"
#include "VertexBuffer.h"
#include "Batch.h"
#include "Shader.h"

using namespace ci;
using namespace ci::app;
using namespace std;

class CubeApp : public App
{
public:

    void setup() override;
    void resize() override;
    void update() override;
    void draw() override;

    CameraPersp                     mCam;
    mat4                            mCubeRotation;

    mtl::RenderPassDescriptorRef    mRenderDescriptor;
    mtl::TextureBufferRef           mTexture;
    mtl::RenderPipelineStateRef     mPipeline;
    mtl::DepthStateRef              mDepthEnabled;
    mtl::BatchRef                   mBatchCube;

};

void CubeApp::setup()
{
    mRenderDescriptor = mtl::RenderPassDescriptor::create();

    mCam.lookAt( vec3( 3, 2, 4 ), vec3( 0 ) );

    mTexture = mtl::TextureBuffer::create(loadImage(getAssetPath("texture.jpg")),
                                          mtl::TextureBuffer::Format().mipmapLevel(3).flipVertically());

    mDepthEnabled = mtl::DepthState::create( mtl::DepthState::Format().depthWriteEnabled() );

    mPipeline = mtl::RenderPipelineState::create("batch_vertex", "cube_fragment");
    mBatchCube = mtl::Batch::create(geom::Cube(), mPipeline);

//    mPipeline = mtl::getStockPipeline(mtl::ShaderDef().texture());
//    mBatchCube = mtl::Batch::create(geom::Cube(), mPipeline);

}

void CubeApp::resize()
{
    mCam.setPerspective( 60, getWindowAspectRatio(), 1, 1000 );
}

void CubeApp::update()
{
    // Rotate the cube by 0.2 degrees around the y-axis
    mCubeRotation *= rotate( toRadians( 0.2f ), normalize( vec3( 0, 1, 0 ) ) );
}

void CubeApp::draw()
{
    mtl::ScopedRenderCommandBuffer renderBuffer;
    mtl::ScopedRenderEncoder renderEncoder = renderBuffer.scopedRenderEncoder(mRenderDescriptor);

    renderEncoder.setDepthStencilState(mDepthEnabled);
    renderEncoder.setTexture(mTexture);

    mtl::setMatrices(mCam);
    mtl::setModelMatrix(mCubeRotation);
    //mBatchCube->draw(renderEncoder);
    renderEncoder.draw(mBatchCube);
}

CINDER_APP( CubeApp, RendererMetal( RendererMetal::Options().numInflightBuffers(1) ) )
<commit_msg>Sample cleanup<commit_after>#include "cinder/app/App.h"
#include "metal.h"
#include "VertexBuffer.h"
#include "Batch.h"
#include "Shader.h"

using namespace ci;
using namespace ci::app;
using namespace std;

class CubeApp : public App
{
public:

    void setup() override;
    void resize() override;
    void update() override;
    void draw() override;

    CameraPersp                     mCam;
    mat4                            mCubeRotation;

    mtl::RenderPassDescriptorRef    mRenderDescriptor;
    mtl::TextureBufferRef           mTexture;
    mtl::RenderPipelineStateRef     mPipeline;
    mtl::DepthStateRef              mDepthEnabled;
    mtl::BatchRef                   mBatchCube;

};

void CubeApp::setup()
{
    mRenderDescriptor = mtl::RenderPassDescriptor::create();

    mCam.lookAt( vec3( 3, 2, 4 ), vec3( 0 ) );

    mTexture = mtl::TextureBuffer::create(loadImage(getAssetPath("texture.jpg")),
                                          mtl::TextureBuffer::Format().mipmapLevel(3).flipVertically());

    mDepthEnabled = mtl::DepthState::create( mtl::DepthState::Format().depthWriteEnabled() );

    mPipeline = mtl::RenderPipelineState::create("batch_vertex", "cube_fragment");
    mBatchCube = mtl::Batch::create(geom::Cube(), mPipeline);
}

void CubeApp::resize()
{
    mCam.setPerspective( 60, getWindowAspectRatio(), 1, 1000 );
}

void CubeApp::update()
{
    // Rotate the cube by 0.2 degrees around the y-axis
    mCubeRotation *= rotate( toRadians( 0.2f ), normalize( vec3( 0, 1, 0 ) ) );
}

void CubeApp::draw()
{
    mtl::ScopedRenderCommandBuffer renderBuffer;
    mtl::ScopedRenderEncoder renderEncoder = renderBuffer.scopedRenderEncoder(mRenderDescriptor);

    renderEncoder.setDepthStencilState(mDepthEnabled);
    renderEncoder.setTexture(mTexture);

    mtl::setMatrices(mCam);
    mtl::setModelMatrix(mCubeRotation);
    renderEncoder.draw(mBatchCube);
}

CINDER_APP( CubeApp, RendererMetal( RendererMetal::Options().numInflightBuffers(1) ) )
<|endoftext|>


<commit_before>#include "GameView.h"
#include "../CarrotQt5.h"
#include "../actor/Player.h"
#include "../graphics/ShaderSource.h"

GameView::GameView(std::shared_ptr<CarrotQt5> root, const uint& playerID, const sf::Vector2f& dimensions)
    : playerID(playerID), root(root) {
    canvas = std::make_shared<sf::RenderTexture>();
    canvas->create(dimensions.x, dimensions.y);
    renderAuxiliaryCanvas = std::make_shared<sf::RenderTexture>();
    renderAuxiliaryCanvas->create(dimensions.x, dimensions.y);
    playerView = std::make_unique<sf::View>(sf::FloatRect(0, 0, dimensions.x, dimensions.y));
    uiView = std::make_unique<sf::View>(sf::FloatRect(0, 0, dimensions.x, dimensions.y));
    viewSprite = std::make_unique<sf::Sprite>(canvas->getTexture());
}

void GameView::setLighting(int target, bool immediate) {
    if (target == targetLightingLevel) {
        return;
    }

    targetLightingLevel = target;
    if (immediate) {
        lightingLevel = target;
    } else {
        addTimer(3.0, false, static_cast<TimerCallbackFunc>(&GameView::setLightingStep));
    }
}

std::weak_ptr<sf::RenderTexture> GameView::getCanvas() {
    return canvas;
}

void GameView::setLightingStep() {
    if (targetLightingLevel == lightingLevel) {
        return;
    }
    short dir = (targetLightingLevel < lightingLevel) ? -1 : 1;
    lightingLevel += dir;
    addTimer(3.0, false, static_cast<TimerCallbackFunc>(&GameView::setLightingStep));
}

CoordinatePair GameView::getViewCenter() {
    return CoordinatePair(playerView->getCenter());
}

unsigned GameView::getViewWidth() {
    return playerView->getSize().x;
}

unsigned GameView::getViewHeight() {
    return playerView->getSize().y;
}

int GameView::getLightingLevel() {
    return lightingLevel;
}

void GameView::drawView(std::shared_ptr<sf::RenderTarget> windowCanvas) {
    canvas->display();
    windowCanvas->draw(*viewSprite.get());

    // Clear the drawing surface; we don't want to do this if we emulate the JJ2 behavior
    canvas->clear();
}

void GameView::drawUiElements() {
    advanceTimers();

    auto player = root->getPlayer(playerID).lock();
    if (player == nullptr) {
        return;
    }
    canvas->setView(*uiView.get());

    sf::RenderStates states;
    auto shader = ShaderSource::getShader("LightingShader");
    shader->setParameter("color", sf::Color::Black);
    shader->setParameter("lightingLevel", lightingLevel / 100.0);

    shader->setParameter("center", sf::Vector2f(
        player->getPosition().x - playerView->getCenter().x + playerView->getSize().x / 2,
        // Reverse the vertical coordinate, as the frame buffer is "upside down"
        playerView->getSize().y - ((player->getPosition().y - 15) - playerView->getCenter().y + playerView->getSize().y / 2)
    ));
    states.shader = shader.get();
    renderAuxiliaryCanvas->clear();
    renderAuxiliaryCanvas->draw(*viewSprite.get(), states);
    renderAuxiliaryCanvas->display();
    std::swap(canvas, renderAuxiliaryCanvas);
    viewSprite->setTexture(canvas->getTexture());

    // Draw the character icon; managed by the player object
    player->drawUIOverlay();

}

void GameView::centerToPlayer() {
    auto player = root->getPlayer(playerID).lock();
    if (player == nullptr) {
        return;
    }

    player->setToViewCenter();
}

void GameView::setSize(const sf::Vector2f& dimensions) {
    canvas->create(dimensions.x, dimensions.y);
    renderAuxiliaryCanvas->create(dimensions.x, dimensions.y);
    playerView->setCenter(dimensions.x / 2, dimensions.y / 2);
    playerView->setSize(dimensions);
    uiView->setCenter(dimensions.x / 2, dimensions.y / 2);
    uiView->setSize(dimensions);
    viewSprite->setTextureRect(sf::IntRect(0, 0, std::ceil(dimensions.x), std::ceil(dimensions.y)));
}

void GameView::centerView(const double& x, const double& y) {
    playerView->setCenter(x, y);
    canvas->setView(*playerView.get());
}

void GameView::centerView(const CoordinatePair& pair) {
    playerView->setCenter(pair.x, pair.y);
    canvas->setView(*playerView.get());
}
<commit_msg>Fix upside-down frames when resizing and at level start<commit_after>#include "GameView.h"
#include "../CarrotQt5.h"
#include "../actor/Player.h"
#include "../graphics/ShaderSource.h"

GameView::GameView(std::shared_ptr<CarrotQt5> root, const uint& playerID, const sf::Vector2f& dimensions)
    : playerID(playerID), root(root) {
    canvas = std::make_shared<sf::RenderTexture>();
    canvas->create(dimensions.x, dimensions.y);
    renderAuxiliaryCanvas = std::make_shared<sf::RenderTexture>();
    renderAuxiliaryCanvas->create(dimensions.x, dimensions.y);
    playerView = std::make_unique<sf::View>(sf::FloatRect(0, 0, dimensions.x, dimensions.y));
    uiView = std::make_unique<sf::View>(sf::FloatRect(0, 0, dimensions.x, dimensions.y));
    viewSprite = std::make_unique<sf::Sprite>(canvas->getTexture());
}

void GameView::setLighting(int target, bool immediate) {
    if (target == targetLightingLevel) {
        return;
    }

    targetLightingLevel = target;
    if (immediate) {
        lightingLevel = target;
    } else {
        addTimer(3.0, false, static_cast<TimerCallbackFunc>(&GameView::setLightingStep));
    }
}

std::weak_ptr<sf::RenderTexture> GameView::getCanvas() {
    return canvas;
}

void GameView::setLightingStep() {
    if (targetLightingLevel == lightingLevel) {
        return;
    }
    short dir = (targetLightingLevel < lightingLevel) ? -1 : 1;
    lightingLevel += dir;
    addTimer(3.0, false, static_cast<TimerCallbackFunc>(&GameView::setLightingStep));
}

CoordinatePair GameView::getViewCenter() {
    return CoordinatePair(playerView->getCenter());
}

unsigned GameView::getViewWidth() {
    return playerView->getSize().x;
}

unsigned GameView::getViewHeight() {
    return playerView->getSize().y;
}

int GameView::getLightingLevel() {
    return lightingLevel;
}

void GameView::drawView(std::shared_ptr<sf::RenderTarget> windowCanvas) {
    canvas->display();
    windowCanvas->draw(*viewSprite.get());

    // Clear the drawing surface; we don't want to do this if we emulate the JJ2 behavior
    canvas->clear();
}

void GameView::drawUiElements() {
    advanceTimers();

    auto player = root->getPlayer(playerID).lock();
    if (player == nullptr) {
        return;
    }
    canvas->setView(*uiView.get());
    canvas->display();

    sf::RenderStates states;
    auto shader = ShaderSource::getShader("LightingShader");
    shader->setParameter("color", sf::Color::Black);
    shader->setParameter("lightingLevel", lightingLevel / 100.0);

    shader->setParameter("center", sf::Vector2f(
        player->getPosition().x - playerView->getCenter().x + playerView->getSize().x / 2,
        // Reverse the vertical coordinate, as the frame buffer is "upside down"
        playerView->getSize().y - ((player->getPosition().y - 15) - playerView->getCenter().y + playerView->getSize().y / 2)
    ));
    states.shader = shader.get();
    renderAuxiliaryCanvas->clear();
    renderAuxiliaryCanvas->draw(*viewSprite.get(), states);
    renderAuxiliaryCanvas->display();
    std::swap(canvas, renderAuxiliaryCanvas);
    viewSprite->setTexture(canvas->getTexture());

    // Draw the character icon; managed by the player object
    player->drawUIOverlay();

}

void GameView::centerToPlayer() {
    auto player = root->getPlayer(playerID).lock();
    if (player == nullptr) {
        return;
    }

    player->setToViewCenter();
}

void GameView::setSize(const sf::Vector2f& dimensions) {
    canvas->create(dimensions.x, dimensions.y);
    renderAuxiliaryCanvas->create(dimensions.x, dimensions.y);
    playerView->setCenter(dimensions.x / 2, dimensions.y / 2);
    playerView->setSize(dimensions);
    uiView->setCenter(dimensions.x / 2, dimensions.y / 2);
    uiView->setSize(dimensions);
    viewSprite->setTextureRect(sf::IntRect(0, 0, std::ceil(dimensions.x), std::ceil(dimensions.y)));
}

void GameView::centerView(const double& x, const double& y) {
    playerView->setCenter(x, y);
    canvas->setView(*playerView.get());
}

void GameView::centerView(const CoordinatePair& pair) {
    playerView->setCenter(pair.x, pair.y);
    canvas->setView(*playerView.get());
}
<|endoftext|>


<commit_before>/*
* Copyright (C) 2008-2013 The Communi Project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*/

#include "treemenu.h"
#include "treewidget.h"
#include "treeitem.h"
#include <QContextMenuEvent>
#include <QCoreApplication>
#include <IrcConnection>
#include <IrcCommand>
#include <IrcChannel>

TreeMenu::TreeMenu(TreeWidget* tree) : QMenu(tree)
{
    d.item = 0;
    d.tree = tree;
    d.disconnectAction = addAction(tr("Disconnect"));
    d.reconnectAction = addAction(tr("Reconnect"));
    addSeparator();
    d.editAction = addAction(tr("Edit"), this, SLOT(onEditTriggered()));
    d.whoisAction = addAction(tr("Whois"), this, SLOT(onWhoisTriggered()));
    d.joinAction = addAction(tr("Join"), this, SLOT(onJoinTriggered()));
    d.partAction = addAction(tr("Part"), this, SLOT(onPartTriggered()));
    addSeparator();
    d.closeAction = addAction(tr("Close"), this, SLOT(onCloseTriggered()), QKeySequence::Close);

    tree->installEventFilter(this);
}

bool TreeMenu::eventFilter(QObject *object, QEvent *event)
{
    Q_UNUSED(object);
    if (event->type() == QEvent::ContextMenu) {
        QContextMenuEvent* cme = static_cast<QContextMenuEvent*>(event);
        QTreeWidgetItem* item = d.tree->itemAt(cme->pos());
        if (item)
            exec(static_cast<TreeItem*>(item), cme->globalPos());
        return true;
    }
    return false;
}

void TreeMenu::exec(TreeItem* item, const QPoint& pos)
{
    setup(item);
    updateActions();
    QMenu::exec(pos);
}

void TreeMenu::onEditTriggered()
{
    // TODO: QMetaObject::invokeMethod(parent(), "editConnection", Q_ARG(IrcConnection*, d.item->connection()));
}

void TreeMenu::onWhoisTriggered()
{
    IrcCommand* command = IrcCommand::createWhois(d.item->text(0));
    d.item->connection()->sendCommand(command);
}

void TreeMenu::onJoinTriggered()
{
    IrcCommand* command = IrcCommand::createJoin(d.item->text(0));
    d.item->connection()->sendCommand(command);
}

void TreeMenu::onPartTriggered()
{
    IrcChannel* channel = d.item->buffer()->toChannel();
    if (channel) {
        QString reason = tr("%1 %2 - http://%3").arg(QCoreApplication::applicationName())
                                                .arg(QCoreApplication::applicationVersion())
                                                .arg(QCoreApplication::organizationDomain());
        channel->part(reason);
    }
}

void TreeMenu::onCloseTriggered()
{
    onPartTriggered();
    d.item->buffer()->deleteLater();
}

void TreeMenu::updateActions()
{
    if (d.item) {
        const bool child = d.item->parentItem();
        const bool connected = d.item->connection()->isActive();
        const bool active = d.item->buffer()->isActive();
        const bool channel = d.item->buffer()->isChannel();
        d.disconnectAction->setVisible(connected);
        d.reconnectAction->setVisible(!connected);
        d.editAction->setVisible(!connected && !child);
        d.joinAction->setVisible(connected && channel && !active);
        d.partAction->setVisible(connected && channel && active);
        d.whoisAction->setVisible(connected && child && !channel);
    } else {
        d.disconnectAction->setVisible(false);
        d.reconnectAction->setVisible(false);
        d.editAction->setVisible(false);
        d.whoisAction->setVisible(false);
        d.joinAction->setVisible(false);
        d.partAction->setVisible(false);
    }

    d.closeAction->setVisible(d.item);
}

void TreeMenu::setup(TreeItem* item)
{
    if (d.item != item) {
        if (d.item && d.item->connection()) {
            IrcConnection* connection = d.item->connection();
            disconnect(connection, SIGNAL(connecting()), this, SLOT(updateActions()));
            disconnect(connection, SIGNAL(connected()), this, SLOT(updateActions()));
            disconnect(connection, SIGNAL(disconnected()), this, SLOT(updateActions()));

            disconnect(d.disconnectAction, SIGNAL(triggered()), connection, SLOT(setDisabled()));
            disconnect(d.disconnectAction, SIGNAL(triggered()), connection, SLOT(quit()));

            disconnect(d.reconnectAction, SIGNAL(triggered()), connection, SLOT(setEnabled()));
            disconnect(d.reconnectAction, SIGNAL(triggered()), connection, SLOT(open()));
        }
        if (item && item->connection()) {
            IrcConnection* connection = item->connection();
            connect(connection, SIGNAL(connecting()), this, SLOT(updateActions()));
            connect(connection, SIGNAL(connected()), this, SLOT(updateActions()));
            connect(connection, SIGNAL(disconnected()), this, SLOT(updateActions()));

            connect(d.disconnectAction, SIGNAL(triggered()), connection, SLOT(setDisabled()));
            connect(d.disconnectAction, SIGNAL(triggered()), connection, SLOT(quit()));

            connect(d.reconnectAction, SIGNAL(triggered()), connection, SLOT(setEnabled()));
            connect(d.reconnectAction, SIGNAL(triggered()), connection, SLOT(open()));
        }
        d.item = item;
    }
}
<commit_msg>TreeMenu: disable non-functional "Edit"<commit_after>/*
* Copyright (C) 2008-2013 The Communi Project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*/

#include "treemenu.h"
#include "treewidget.h"
#include "treeitem.h"
#include <QContextMenuEvent>
#include <QCoreApplication>
#include <IrcConnection>
#include <IrcCommand>
#include <IrcChannel>

TreeMenu::TreeMenu(TreeWidget* tree) : QMenu(tree)
{
    d.item = 0;
    d.tree = tree;
    d.disconnectAction = addAction(tr("Disconnect"));
    d.reconnectAction = addAction(tr("Reconnect"));
    addSeparator();
    // TODO: d.editAction = addAction(tr("Edit"), this, SLOT(onEditTriggered()));
    d.whoisAction = addAction(tr("Whois"), this, SLOT(onWhoisTriggered()));
    d.joinAction = addAction(tr("Join"), this, SLOT(onJoinTriggered()));
    d.partAction = addAction(tr("Part"), this, SLOT(onPartTriggered()));
    addSeparator();
    d.closeAction = addAction(tr("Close"), this, SLOT(onCloseTriggered()), QKeySequence::Close);

    tree->installEventFilter(this);
}

bool TreeMenu::eventFilter(QObject *object, QEvent *event)
{
    Q_UNUSED(object);
    if (event->type() == QEvent::ContextMenu) {
        QContextMenuEvent* cme = static_cast<QContextMenuEvent*>(event);
        QTreeWidgetItem* item = d.tree->itemAt(cme->pos());
        if (item)
            exec(static_cast<TreeItem*>(item), cme->globalPos());
        return true;
    }
    return false;
}

void TreeMenu::exec(TreeItem* item, const QPoint& pos)
{
    setup(item);
    updateActions();
    QMenu::exec(pos);
}

void TreeMenu::onEditTriggered()
{
    // TODO: QMetaObject::invokeMethod(parent(), "editConnection", Q_ARG(IrcConnection*, d.item->connection()));
}

void TreeMenu::onWhoisTriggered()
{
    IrcCommand* command = IrcCommand::createWhois(d.item->text(0));
    d.item->connection()->sendCommand(command);
}

void TreeMenu::onJoinTriggered()
{
    IrcCommand* command = IrcCommand::createJoin(d.item->text(0));
    d.item->connection()->sendCommand(command);
}

void TreeMenu::onPartTriggered()
{
    IrcChannel* channel = d.item->buffer()->toChannel();
    if (channel) {
        QString reason = tr("%1 %2 - http://%3").arg(QCoreApplication::applicationName())
                                                .arg(QCoreApplication::applicationVersion())
                                                .arg(QCoreApplication::organizationDomain());
        channel->part(reason);
    }
}

void TreeMenu::onCloseTriggered()
{
    onPartTriggered();
    d.item->buffer()->deleteLater();
}

void TreeMenu::updateActions()
{
    if (d.item) {
        const bool child = d.item->parentItem();
        const bool connected = d.item->connection()->isActive();
        const bool active = d.item->buffer()->isActive();
        const bool channel = d.item->buffer()->isChannel();
        d.disconnectAction->setVisible(connected);
        d.reconnectAction->setVisible(!connected);
        // TODO: d.editAction->setVisible(!connected && !child);
        d.joinAction->setVisible(connected && channel && !active);
        d.partAction->setVisible(connected && channel && active);
        d.whoisAction->setVisible(connected && child && !channel);
    } else {
        d.disconnectAction->setVisible(false);
        d.reconnectAction->setVisible(false);
        // TODO: d.editAction->setVisible(false);
        d.whoisAction->setVisible(false);
        d.joinAction->setVisible(false);
        d.partAction->setVisible(false);
    }

    d.closeAction->setVisible(d.item);
}

void TreeMenu::setup(TreeItem* item)
{
    if (d.item != item) {
        if (d.item && d.item->connection()) {
            IrcConnection* connection = d.item->connection();
            disconnect(connection, SIGNAL(connecting()), this, SLOT(updateActions()));
            disconnect(connection, SIGNAL(connected()), this, SLOT(updateActions()));
            disconnect(connection, SIGNAL(disconnected()), this, SLOT(updateActions()));

            disconnect(d.disconnectAction, SIGNAL(triggered()), connection, SLOT(setDisabled()));
            disconnect(d.disconnectAction, SIGNAL(triggered()), connection, SLOT(quit()));

            disconnect(d.reconnectAction, SIGNAL(triggered()), connection, SLOT(setEnabled()));
            disconnect(d.reconnectAction, SIGNAL(triggered()), connection, SLOT(open()));
        }
        if (item && item->connection()) {
            IrcConnection* connection = item->connection();
            connect(connection, SIGNAL(connecting()), this, SLOT(updateActions()));
            connect(connection, SIGNAL(connected()), this, SLOT(updateActions()));
            connect(connection, SIGNAL(disconnected()), this, SLOT(updateActions()));

            connect(d.disconnectAction, SIGNAL(triggered()), connection, SLOT(setDisabled()));
            connect(d.disconnectAction, SIGNAL(triggered()), connection, SLOT(quit()));

            connect(d.reconnectAction, SIGNAL(triggered()), connection, SLOT(setEnabled()));
            connect(d.reconnectAction, SIGNAL(triggered()), connection, SLOT(open()));
        }
        d.item = item;
    }
}
<|endoftext|>


<commit_before>#include "pluginmanager.h"

#include <QApplication>
#include <QDir>
#include <QPluginLoader>
#include <QSettings>

#include <QDebug>

namespace OpenCOR {

PluginManager::PluginManager()
{
#ifndef Q_WS_MAC
    QString pluginsDir = "plugins";
#else
    QString pluginsDir = QString("..")+QDir::separator()+"PlugIns";
#endif

    mPluginsDir =  QDir(qApp->applicationDirPath()).canonicalPath()
                  +QDir::separator()+pluginsDir;

#ifdef Q_WS_MAC
    mPluginsDir += QDir::separator()+qApp->applicationName();
#endif
}

PluginManager::~PluginManager()
{
}

void PluginManager::loadPlugins(QSettings *pSettings)
{
    // Determine which plugins are available for loading

#ifdef Q_WS_WIN
    const QString extension = ".dll";
#elif defined(Q_WS_MAC)
    const QString extension = ".dylib";
#else
    const QString extension = ".so";
#endif

    QFileInfoList files = QDir(mPluginsDir).entryInfoList(QStringList("*"+extension), QDir::Files);
    QStringList pluginFiles;

    foreach (const QFileInfo &file, files) {
        QString pluginFileName = file.canonicalFilePath();

        pluginFiles << pluginFileName;

        qDebug() << "Plugin #" << pluginFiles.count() << ":" << pluginFileName;

        QString pluginBaseName = QFileInfo(pluginFileName).baseName();

        if (!pluginBaseName.compare("Core") || !pluginBaseName.compare("Viewer")) {
            // Try to load the plugin as a 'proper' plugin

            QPluginLoader loader(pluginFileName);

            if (loader.load()) {
                qDebug() << " -" << pluginFileName << " loaded...";
            } else {
                qDebug() << " -" << pluginFileName << " NOT loaded...";
                qDebug() << "    ===>" << loader.errorString();
            }
        }
    }

    //---GRY--- TO BE DONE...
}

}
<commit_msg>Addendum to the previous commit.<commit_after>#include "pluginmanager.h"

#include <QApplication>
#include <QDir>
#include <QPluginLoader>
#include <QSettings>

#include <QDebug>

namespace OpenCOR {

PluginManager::PluginManager()
{
#ifndef Q_WS_MAC
    QString pluginsDir = "plugins";
#else
    QString pluginsDir = QString("..")+QDir::separator()+"PlugIns";
#endif

    mPluginsDir =  QDir(qApp->applicationDirPath()).canonicalPath()
                  +QDir::separator()+pluginsDir;

#ifdef Q_WS_MAC
    mPluginsDir += QDir::separator()+qApp->applicationName();
#endif
}

PluginManager::~PluginManager()
{
}

void PluginManager::loadPlugins(QSettings *pSettings)
{
    // Determine which plugins are available for loading

#ifdef Q_WS_WIN
    const QString extension = ".dll";
#elif defined(Q_WS_MAC)
    const QString extension = ".dylib";
#else
    const QString extension = ".so";
#endif

    QFileInfoList files = QDir(mPluginsDir).entryInfoList(QStringList("*"+extension), QDir::Files);
    QStringList pluginFiles;

    foreach (const QFileInfo &file, files) {
        QString pluginFileName = file.canonicalFilePath();

        pluginFiles << pluginFileName;

        qDebug() << "Plugin #" << pluginFiles.count() << ":" << pluginFileName;

        QString pluginBaseName = QFileInfo(pluginFileName).baseName();

        if (   !pluginBaseName.compare("Core") || !pluginBaseName.compare("libCore")
            || !pluginBaseName.compare("Viewer") || !pluginBaseName.compare("libViewer")) {
            // Try to load the plugin as a 'proper' plugin

            QPluginLoader loader(pluginFileName);

            if (loader.load()) {
                qDebug() << " -" << pluginFileName << " loaded...";
            } else {
                qDebug() << " -" << pluginFileName << " NOT loaded...";
                qDebug() << "    ===>" << loader.errorString();
            }
        }
    }

    //---GRY--- TO BE DONE...
}

}
<|endoftext|>


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

#include "src/gpu/vk/GrVkTexture.h"

#include "src/gpu/GrTexturePriv.h"
#include "src/gpu/vk/GrVkDescriptorSet.h"
#include "src/gpu/vk/GrVkGpu.h"
#include "src/gpu/vk/GrVkImageView.h"
#include "src/gpu/vk/GrVkTextureRenderTarget.h"
#include "src/gpu/vk/GrVkUtil.h"

#include "include/gpu/vk/GrVkTypes.h"

#define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)

// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrVkTexture::GrVkTexture(GrVkGpu* gpu,
                         SkBudgeted budgeted,
                         SkISize dimensions,
                         const GrVkImageInfo& info,
                         sk_sp<GrVkImageLayout> layout,
                         const GrVkImageView* view,
                         GrMipMapsStatus mipMapsStatus)
        : GrSurface(gpu, dimensions, info.fProtected)
        , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kOwned)
        , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
        , fTextureView(view)
        , fDescSetCache(kMaxCachedDescSets) {
    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
    // We don't support creating external GrVkTextures
    SkASSERT(!info.fYcbcrConversionInfo.isValid() || !info.fYcbcrConversionInfo.fExternalFormat);
    this->registerWithCache(budgeted);
    if (GrVkFormatIsCompressed(info.fFormat)) {
        this->setReadOnly();
    }
}

GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info,
                         sk_sp<GrVkImageLayout> layout, const GrVkImageView* view,
                         GrMipMapsStatus mipMapsStatus, GrBackendObjectOwnership ownership,
                         GrWrapCacheable cacheable, GrIOType ioType, bool isExternal)
        : GrSurface(gpu, dimensions, info.fProtected)
        , GrVkImage(info, std::move(layout), ownership)
        , INHERITED(gpu, dimensions, info.fProtected,
                    isExternal ? GrTextureType::kExternal : GrTextureType::k2D, mipMapsStatus)
        , fTextureView(view)
        , fDescSetCache(kMaxCachedDescSets) {
    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
    if (ioType == kRead_GrIOType) {
        this->setReadOnly();
    }
    this->registerWithCacheWrapped(cacheable);
}

// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrVkTexture::GrVkTexture(GrVkGpu* gpu,
                         SkISize dimensions,
                         const GrVkImageInfo& info,
                         sk_sp<GrVkImageLayout> layout,
                         const GrVkImageView* view,
                         GrMipMapsStatus mipMapsStatus,
                         GrBackendObjectOwnership ownership)
        : GrSurface(gpu, dimensions, info.fProtected)
        , GrVkImage(info, layout, ownership)
        , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
        , fTextureView(view)
        , fDescSetCache(kMaxCachedDescSets) {
    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
    // Since this ctor is only called from GrVkTextureRenderTarget, we can't have a ycbcr conversion
    // since we don't support that on render targets.
    SkASSERT(!info.fYcbcrConversionInfo.isValid());
}

sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu, SkBudgeted budgeted,
                                               SkISize dimensions,
                                               const GrVkImage::ImageDesc& imageDesc,
                                               GrMipMapsStatus mipMapsStatus) {
    SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT);

    GrVkImageInfo info;
    if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) {
        return nullptr;
    }

    const GrVkImageView* imageView = GrVkImageView::Create(
            gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
            info.fYcbcrConversionInfo);
    if (!imageView) {
        GrVkImage::DestroyImageInfo(gpu, &info);
        return nullptr;
    }
    sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout));

    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, dimensions, info, std::move(layout),
                                              imageView, mipMapsStatus));
}

sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu,
                                                   SkISize dimensions,
                                                   GrWrapOwnership wrapOwnership,
                                                   GrWrapCacheable cacheable,
                                                   GrIOType ioType,
                                                   const GrVkImageInfo& info,
                                                   sk_sp<GrVkImageLayout> layout) {
    // Adopted textures require both image and allocation because we're responsible for freeing
    SkASSERT(VK_NULL_HANDLE != info.fImage &&
             (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory));

    const GrVkImageView* imageView = GrVkImageView::Create(
            gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
            info.fYcbcrConversionInfo);
    if (!imageView) {
        return nullptr;
    }

    GrMipMapsStatus mipMapsStatus = info.fLevelCount > 1 ? GrMipMapsStatus::kValid
                                                         : GrMipMapsStatus::kNotAllocated;

    GrBackendObjectOwnership ownership = kBorrow_GrWrapOwnership == wrapOwnership
            ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned;
    bool isExternal = info.fYcbcrConversionInfo.isValid() &&
                      (info.fYcbcrConversionInfo.fExternalFormat != 0);
    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, dimensions, info, std::move(layout), imageView,
                                              mipMapsStatus, ownership, cacheable, ioType,
                                              isExternal));
}

GrVkTexture::~GrVkTexture() {
    // either release or abandon should have been called by the owner of this object.
    SkASSERT(!fTextureView);
}

void GrVkTexture::onRelease() {
    // We're about to be severed from our GrVkResource. If there are "finish" idle procs we have to
    // decide who will handle them. If the resource is still tied to a command buffer we let it
    // handle them. Otherwise, we handle them.
    if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
        this->removeFinishIdleProcs();
    }

    // we create this and don't hand it off, so we should always destroy it
    if (fTextureView) {
        fTextureView->unref(this->getVkGpu());
        fTextureView = nullptr;
    }

    fDescSetCache.reset();

    this->releaseImage(this->getVkGpu());

    INHERITED::onRelease();
}

struct GrVkTexture::DescriptorCacheEntry {
    DescriptorCacheEntry(const GrVkDescriptorSet* fDescSet, GrVkGpu* gpu)
            : fDescriptorSet(fDescSet), fGpu(gpu) {}
    ~DescriptorCacheEntry() {
        if (fDescriptorSet) {
            fDescriptorSet->recycle(fGpu);
        }
    }

    const GrVkDescriptorSet* fDescriptorSet;
    GrVkGpu* fGpu;
};

void GrVkTexture::onAbandon() {
    // We're about to be severed from our GrVkResource. If there are "finish" idle procs we have to
    // decide who will handle them. If the resource is still tied to a command buffer we let it
    // handle them. Otherwise, we handle them.
    if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
        this->removeFinishIdleProcs();
    }

    // we create this and don't hand it off, so we should always destroy it
    if (fTextureView) {
        fTextureView->unref(this->getVkGpu());
        fTextureView = nullptr;
    }

    fDescSetCache.reset();

    this->releaseImage(this->getVkGpu());
    INHERITED::onAbandon();
}

GrBackendTexture GrVkTexture::getBackendTexture() const {
    return GrBackendTexture(this->width(), this->height(), fInfo, this->grVkImageLayout());
}

GrVkGpu* GrVkTexture::getVkGpu() const {
    SkASSERT(!this->wasDestroyed());
    return static_cast<GrVkGpu*>(this->getGpu());
}

const GrVkImageView* GrVkTexture::textureView() {
    return fTextureView;
}

void GrVkTexture::addIdleProc(sk_sp<GrRefCntedCallback> idleProc, IdleState type) {
    INHERITED::addIdleProc(idleProc, type);
    if (type == IdleState::kFinished) {
        if (auto* resource = this->resource()) {
            resource->addIdleProc(this, std::move(idleProc));
        }
    }
}

void GrVkTexture::callIdleProcsOnBehalfOfResource() {
    // If we got here then the resource is being removed from its last command buffer and the
    // texture is idle in the cache. Any kFlush idle procs should already have been called. So
    // the texture and resource should have the same set of procs.
    SkASSERT(this->resource());
    SkASSERT(this->resource()->idleProcCnt() == fIdleProcs.count());
#ifdef SK_DEBUG
    for (int i = 0; i < fIdleProcs.count(); ++i) {
        SkASSERT(fIdleProcs[i] == this->resource()->idleProc(i));
    }
#endif
    fIdleProcs.reset();
    this->resource()->resetIdleProcs();
}

void GrVkTexture::willRemoveLastRef() {
    if (!fIdleProcs.count()) {
        return;
    }
    // This is called when the GrTexture is purgeable. However, we need to check whether the
    // Resource is still owned by any command buffers. If it is then it will call the proc.
    auto* resource = this->hasResource() ? this->resource() : nullptr;
    bool callFinishProcs = !resource || !resource->isOwnedByCommandBuffer();
    if (callFinishProcs) {
        // Everything must go!
        fIdleProcs.reset();
        resource->resetIdleProcs();
    } else {
        // The procs that should be called on flush but not finish are those that are owned
        // by the GrVkTexture and not the Resource. We do this by copying the resource's array
        // and thereby dropping refs to procs we own but the resource does not.
        SkASSERT(resource);
        fIdleProcs.reset(resource->idleProcCnt());
        for (int i = 0; i < fIdleProcs.count(); ++i) {
            fIdleProcs[i] = resource->idleProc(i);
        }
    }
}

void GrVkTexture::removeFinishIdleProcs() {
    // This should only be called by onRelease/onAbandon when we have already checked for a
    // resource.
    const auto* resource = this->resource();
    SkASSERT(resource);
    SkSTArray<4, sk_sp<GrRefCntedCallback>> procsToKeep;
    int resourceIdx = 0;
    // The idle procs that are common between the GrVkTexture and its Resource should be found in
    // the same order.
    for (int i = 0; i < fIdleProcs.count(); ++i) {
        if (fIdleProcs[i] == resource->idleProc(resourceIdx)) {
            ++resourceIdx;
        } else {
            procsToKeep.push_back(fIdleProcs[i]);
        }
    }
    SkASSERT(resourceIdx == resource->idleProcCnt());
    fIdleProcs = procsToKeep;
}

const GrVkDescriptorSet* GrVkTexture::cachedSingleDescSet(GrSamplerState state) {
    if (std::unique_ptr<DescriptorCacheEntry>* e = fDescSetCache.find(state)) {
        return (*e)->fDescriptorSet;
    }
    return nullptr;
}

void GrVkTexture::addDescriptorSetToCache(const GrVkDescriptorSet* descSet, GrSamplerState state) {
    SkASSERT(!fDescSetCache.find(state));
    descSet->ref();
    fDescSetCache.insert(state,
                         std::unique_ptr<DescriptorCacheEntry>(
                                 new DescriptorCacheEntry(descSet, this->getVkGpu())));
}
<commit_msg>Avoid possible nullptr dereference am: e26a98217e am: f6cc75d713<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/gpu/vk/GrVkTexture.h"

#include "src/gpu/GrTexturePriv.h"
#include "src/gpu/vk/GrVkDescriptorSet.h"
#include "src/gpu/vk/GrVkGpu.h"
#include "src/gpu/vk/GrVkImageView.h"
#include "src/gpu/vk/GrVkTextureRenderTarget.h"
#include "src/gpu/vk/GrVkUtil.h"

#include "include/gpu/vk/GrVkTypes.h"

#define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)

// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrVkTexture::GrVkTexture(GrVkGpu* gpu,
                         SkBudgeted budgeted,
                         SkISize dimensions,
                         const GrVkImageInfo& info,
                         sk_sp<GrVkImageLayout> layout,
                         const GrVkImageView* view,
                         GrMipMapsStatus mipMapsStatus)
        : GrSurface(gpu, dimensions, info.fProtected)
        , GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kOwned)
        , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
        , fTextureView(view)
        , fDescSetCache(kMaxCachedDescSets) {
    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
    // We don't support creating external GrVkTextures
    SkASSERT(!info.fYcbcrConversionInfo.isValid() || !info.fYcbcrConversionInfo.fExternalFormat);
    this->registerWithCache(budgeted);
    if (GrVkFormatIsCompressed(info.fFormat)) {
        this->setReadOnly();
    }
}

GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info,
                         sk_sp<GrVkImageLayout> layout, const GrVkImageView* view,
                         GrMipMapsStatus mipMapsStatus, GrBackendObjectOwnership ownership,
                         GrWrapCacheable cacheable, GrIOType ioType, bool isExternal)
        : GrSurface(gpu, dimensions, info.fProtected)
        , GrVkImage(info, std::move(layout), ownership)
        , INHERITED(gpu, dimensions, info.fProtected,
                    isExternal ? GrTextureType::kExternal : GrTextureType::k2D, mipMapsStatus)
        , fTextureView(view)
        , fDescSetCache(kMaxCachedDescSets) {
    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
    if (ioType == kRead_GrIOType) {
        this->setReadOnly();
    }
    this->registerWithCacheWrapped(cacheable);
}

// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
GrVkTexture::GrVkTexture(GrVkGpu* gpu,
                         SkISize dimensions,
                         const GrVkImageInfo& info,
                         sk_sp<GrVkImageLayout> layout,
                         const GrVkImageView* view,
                         GrMipMapsStatus mipMapsStatus,
                         GrBackendObjectOwnership ownership)
        : GrSurface(gpu, dimensions, info.fProtected)
        , GrVkImage(info, layout, ownership)
        , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus)
        , fTextureView(view)
        , fDescSetCache(kMaxCachedDescSets) {
    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount));
    // Since this ctor is only called from GrVkTextureRenderTarget, we can't have a ycbcr conversion
    // since we don't support that on render targets.
    SkASSERT(!info.fYcbcrConversionInfo.isValid());
}

sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu, SkBudgeted budgeted,
                                               SkISize dimensions,
                                               const GrVkImage::ImageDesc& imageDesc,
                                               GrMipMapsStatus mipMapsStatus) {
    SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT);

    GrVkImageInfo info;
    if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) {
        return nullptr;
    }

    const GrVkImageView* imageView = GrVkImageView::Create(
            gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
            info.fYcbcrConversionInfo);
    if (!imageView) {
        GrVkImage::DestroyImageInfo(gpu, &info);
        return nullptr;
    }
    sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout));

    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, dimensions, info, std::move(layout),
                                              imageView, mipMapsStatus));
}

sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu,
                                                   SkISize dimensions,
                                                   GrWrapOwnership wrapOwnership,
                                                   GrWrapCacheable cacheable,
                                                   GrIOType ioType,
                                                   const GrVkImageInfo& info,
                                                   sk_sp<GrVkImageLayout> layout) {
    // Adopted textures require both image and allocation because we're responsible for freeing
    SkASSERT(VK_NULL_HANDLE != info.fImage &&
             (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory));

    const GrVkImageView* imageView = GrVkImageView::Create(
            gpu, info.fImage, info.fFormat, GrVkImageView::kColor_Type, info.fLevelCount,
            info.fYcbcrConversionInfo);
    if (!imageView) {
        return nullptr;
    }

    GrMipMapsStatus mipMapsStatus = info.fLevelCount > 1 ? GrMipMapsStatus::kValid
                                                         : GrMipMapsStatus::kNotAllocated;

    GrBackendObjectOwnership ownership = kBorrow_GrWrapOwnership == wrapOwnership
            ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned;
    bool isExternal = info.fYcbcrConversionInfo.isValid() &&
                      (info.fYcbcrConversionInfo.fExternalFormat != 0);
    return sk_sp<GrVkTexture>(new GrVkTexture(gpu, dimensions, info, std::move(layout), imageView,
                                              mipMapsStatus, ownership, cacheable, ioType,
                                              isExternal));
}

GrVkTexture::~GrVkTexture() {
    // either release or abandon should have been called by the owner of this object.
    SkASSERT(!fTextureView);
}

void GrVkTexture::onRelease() {
    // We're about to be severed from our GrVkResource. If there are "finish" idle procs we have to
    // decide who will handle them. If the resource is still tied to a command buffer we let it
    // handle them. Otherwise, we handle them.
    if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
        this->removeFinishIdleProcs();
    }

    // we create this and don't hand it off, so we should always destroy it
    if (fTextureView) {
        fTextureView->unref(this->getVkGpu());
        fTextureView = nullptr;
    }

    fDescSetCache.reset();

    this->releaseImage(this->getVkGpu());

    INHERITED::onRelease();
}

struct GrVkTexture::DescriptorCacheEntry {
    DescriptorCacheEntry(const GrVkDescriptorSet* fDescSet, GrVkGpu* gpu)
            : fDescriptorSet(fDescSet), fGpu(gpu) {}
    ~DescriptorCacheEntry() {
        if (fDescriptorSet) {
            fDescriptorSet->recycle(fGpu);
        }
    }

    const GrVkDescriptorSet* fDescriptorSet;
    GrVkGpu* fGpu;
};

void GrVkTexture::onAbandon() {
    // We're about to be severed from our GrVkResource. If there are "finish" idle procs we have to
    // decide who will handle them. If the resource is still tied to a command buffer we let it
    // handle them. Otherwise, we handle them.
    if (this->hasResource() && this->resource()->isOwnedByCommandBuffer()) {
        this->removeFinishIdleProcs();
    }

    // we create this and don't hand it off, so we should always destroy it
    if (fTextureView) {
        fTextureView->unref(this->getVkGpu());
        fTextureView = nullptr;
    }

    fDescSetCache.reset();

    this->releaseImage(this->getVkGpu());
    INHERITED::onAbandon();
}

GrBackendTexture GrVkTexture::getBackendTexture() const {
    return GrBackendTexture(this->width(), this->height(), fInfo, this->grVkImageLayout());
}

GrVkGpu* GrVkTexture::getVkGpu() const {
    SkASSERT(!this->wasDestroyed());
    return static_cast<GrVkGpu*>(this->getGpu());
}

const GrVkImageView* GrVkTexture::textureView() {
    return fTextureView;
}

void GrVkTexture::addIdleProc(sk_sp<GrRefCntedCallback> idleProc, IdleState type) {
    INHERITED::addIdleProc(idleProc, type);
    if (type == IdleState::kFinished) {
        if (auto* resource = this->resource()) {
            resource->addIdleProc(this, std::move(idleProc));
        }
    }
}

void GrVkTexture::callIdleProcsOnBehalfOfResource() {
    // If we got here then the resource is being removed from its last command buffer and the
    // texture is idle in the cache. Any kFlush idle procs should already have been called. So
    // the texture and resource should have the same set of procs.
    SkASSERT(this->resource());
    SkASSERT(this->resource()->idleProcCnt() == fIdleProcs.count());
#ifdef SK_DEBUG
    for (int i = 0; i < fIdleProcs.count(); ++i) {
        SkASSERT(fIdleProcs[i] == this->resource()->idleProc(i));
    }
#endif
    fIdleProcs.reset();
    this->resource()->resetIdleProcs();
}

void GrVkTexture::willRemoveLastRef() {
    if (!fIdleProcs.count()) {
        return;
    }
    // This is called when the GrTexture is purgeable. However, we need to check whether the
    // Resource is still owned by any command buffers. If it is then it will call the proc.
    auto* resource = this->hasResource() ? this->resource() : nullptr;
    bool callFinishProcs = !resource || !resource->isOwnedByCommandBuffer();
    if (callFinishProcs) {
        // Everything must go!
        fIdleProcs.reset();
        if (resource) {
            resource->resetIdleProcs();
        }
    } else {
        // The procs that should be called on flush but not finish are those that are owned
        // by the GrVkTexture and not the Resource. We do this by copying the resource's array
        // and thereby dropping refs to procs we own but the resource does not.
        SkASSERT(resource);
        fIdleProcs.reset(resource->idleProcCnt());
        for (int i = 0; i < fIdleProcs.count(); ++i) {
            fIdleProcs[i] = resource->idleProc(i);
        }
    }
}

void GrVkTexture::removeFinishIdleProcs() {
    // This should only be called by onRelease/onAbandon when we have already checked for a
    // resource.
    const auto* resource = this->resource();
    SkASSERT(resource);
    SkSTArray<4, sk_sp<GrRefCntedCallback>> procsToKeep;
    int resourceIdx = 0;
    // The idle procs that are common between the GrVkTexture and its Resource should be found in
    // the same order.
    for (int i = 0; i < fIdleProcs.count(); ++i) {
        if (fIdleProcs[i] == resource->idleProc(resourceIdx)) {
            ++resourceIdx;
        } else {
            procsToKeep.push_back(fIdleProcs[i]);
        }
    }
    SkASSERT(resourceIdx == resource->idleProcCnt());
    fIdleProcs = procsToKeep;
}

const GrVkDescriptorSet* GrVkTexture::cachedSingleDescSet(GrSamplerState state) {
    if (std::unique_ptr<DescriptorCacheEntry>* e = fDescSetCache.find(state)) {
        return (*e)->fDescriptorSet;
    }
    return nullptr;
}

void GrVkTexture::addDescriptorSetToCache(const GrVkDescriptorSet* descSet, GrSamplerState state) {
    SkASSERT(!fDescSetCache.find(state));
    descSet->ref();
    fDescSetCache.insert(state,
                         std::unique_ptr<DescriptorCacheEntry>(
                                 new DescriptorCacheEntry(descSet, this->getVkGpu())));
}
<|endoftext|>