diff options
author | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-05-05 12:33:22 +0000 |
---|---|---|
committer | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-05-05 12:33:22 +0000 |
commit | 6aef1fb4ebf8b8b2ed352eb81e961565fbbd56cb (patch) | |
tree | 765433fc75610281290c9ea6358b27428bf15468 | |
parent | 5fd9243fd6b82aa3f2a2fae7c62310e77ab7b6d3 (diff) |
Add 4x4 downsample filter with 4 bilinear texture reads, use for ssaa.
Review URL: http://codereview.appspot.com/4483042/
git-svn-id: http://skia.googlecode.com/svn/trunk@1250 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | gpu/include/GrContext_impl.h | 5 | ||||
-rw-r--r-- | gpu/include/GrGpu.h | 6 | ||||
-rw-r--r-- | gpu/include/GrSamplerState.h | 40 | ||||
-rw-r--r-- | gpu/src/GrContext.cpp | 41 | ||||
-rw-r--r-- | gpu/src/GrGLProgram.cpp | 167 | ||||
-rw-r--r-- | gpu/src/GrGLProgram.h | 19 | ||||
-rw-r--r-- | gpu/src/GrGpu.cpp | 2 | ||||
-rw-r--r-- | gpu/src/GrGpuGL.cpp | 8 | ||||
-rw-r--r-- | gpu/src/GrGpuGLFixed.cpp | 1 | ||||
-rw-r--r-- | gpu/src/GrGpuGLShaders.cpp | 296 | ||||
-rw-r--r-- | gpu/src/GrGpuGLShaders.h | 3 | ||||
-rw-r--r-- | gpu/src/GrGpuGLShaders2.cpp | 1 | ||||
-rw-r--r-- | gpu/src/GrTextContext.cpp | 9 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 13 |
14 files changed, 451 insertions, 160 deletions
diff --git a/gpu/include/GrContext_impl.h b/gpu/include/GrContext_impl.h index 0fa3b8d298..fae4e923f9 100644 --- a/gpu/include/GrContext_impl.h +++ b/gpu/include/GrContext_impl.h @@ -21,6 +21,11 @@ struct GrContext::OffscreenRecord { OffscreenRecord() { fEntry0 = NULL; fEntry1 = NULL; } ~OffscreenRecord() { GrAssert(NULL == fEntry0 && NULL == fEntry1); } + enum Downsample { + k4x4TwoPass_Downsample, + k4x4SinglePass_Downsample, + kFSAA_Downsample + } fDownsample; GrTextureEntry* fEntry0; GrTextureEntry* fEntry1; GrDrawTarget::SavedDrawState fSavedState; diff --git a/gpu/include/GrGpu.h b/gpu/include/GrGpu.h index 5602d1ac21..e44956f709 100644 --- a/gpu/include/GrGpu.h +++ b/gpu/include/GrGpu.h @@ -199,6 +199,11 @@ public: bool supportsAALines() const { return fAALineSupport; } /** + * Does the subclass support GrSamplerState::k4x4Downsample_Filter + */ + bool supports4x4DownsampleFilter() const { return f4X4DownsampleFilterSupport; } + + /** * Gets the minimum width of a render target. If a texture/rt is created * with a width less than this size the GrGpu object will clamp it to this * value. @@ -379,6 +384,7 @@ protected: bool fStencilWrapOpsSupport; bool fAALineSupport; bool fFSAASupport; + bool f4X4DownsampleFilterSupport; // supports GrSamplerState::k4x4Downsample_Filter // set by subclass to true if index and vertex buffers can be locked, false // otherwise. diff --git a/gpu/include/GrSamplerState.h b/gpu/include/GrSamplerState.h index 910bc74ee6..dd47c53726 100644 --- a/gpu/include/GrSamplerState.h +++ b/gpu/include/GrSamplerState.h @@ -23,6 +23,24 @@ class GrSamplerState { public: + enum Filter { + /** + * Read the closest src texel to the sample position + */ + kNearest_Filter, + /** + * Blend between closest 4 src texels to sample position (tent filter) + */ + kBilinear_Filter, + /** + * Average of 4 bilinear filterings spaced +/- 1 texel from sample + * position in x and y. Intended for averaging 16 texels in a downsample + * pass. (rasterizing such that texture samples fall exactly halfway + * between texels in x and y spaced 4 texels apart.) + */ + k4x4Downsample_Filter, + }; + /** * The intepretation of the texture matrix depends on the sample mode. The * texture matrix is applied both when the texture coordinates are explicit @@ -70,7 +88,7 @@ public: this->setClampNoFilter(); } - explicit GrSamplerState(bool filter) { + explicit GrSamplerState(Filter filter) { fWrapX = kClamp_WrapMode; fWrapY = kClamp_WrapMode; fSampleMode = kNormal_SampleMode; @@ -78,7 +96,7 @@ public: fMatrix.setIdentity(); } - GrSamplerState(WrapMode wx, WrapMode wy, bool filter) { + GrSamplerState(WrapMode wx, WrapMode wy, Filter filter) { fWrapX = wx; fWrapY = wy; fSampleMode = kNormal_SampleMode; @@ -86,7 +104,8 @@ public: fMatrix.setIdentity(); } - GrSamplerState(WrapMode wx, WrapMode wy, const GrMatrix& matrix, bool filter) { + GrSamplerState(WrapMode wx, WrapMode wy, + const GrMatrix& matrix, Filter filter) { fWrapX = wx; fWrapY = wy; fSampleMode = kNormal_SampleMode; @@ -94,7 +113,8 @@ public: fMatrix = matrix; } - GrSamplerState(WrapMode wx, WrapMode wy, SampleMode sample, const GrMatrix& matrix, bool filter) { + GrSamplerState(WrapMode wx, WrapMode wy, SampleMode sample, + const GrMatrix& matrix, Filter filter) { fWrapX = wx; fWrapY = wy; fSampleMode = sample; @@ -106,7 +126,7 @@ public: WrapMode getWrapY() const { return fWrapY; } SampleMode getSampleMode() const { return fSampleMode; } const GrMatrix& getMatrix() const { return fMatrix; } - bool isFilter() const { return fFilter; } + Filter getFilter() const { return fFilter; } bool isGradient() const { return kRadial_SampleMode == fSampleMode || @@ -138,16 +158,16 @@ public: void preConcatMatrix(const GrMatrix& matrix) { fMatrix.preConcat(matrix); } /** - * Enables or disables filtering. - * @param filter indicates whether filtering is applied. + * Sets filtering type. + * @param filter type of filtering to apply */ - void setFilter(bool filter) { fFilter = filter; } + void setFilter(Filter filter) { fFilter = filter; } void setClampNoFilter() { fWrapX = kClamp_WrapMode; fWrapY = kClamp_WrapMode; fSampleMode = kNormal_SampleMode; - fFilter = false; + fFilter = kNearest_Filter; fMatrix.setIdentity(); } @@ -176,7 +196,7 @@ private: WrapMode fWrapX; WrapMode fWrapY; SampleMode fSampleMode; - bool fFilter; + Filter fFilter; GrMatrix fMatrix; // these are undefined unless fSampleMode == kRadial2_SampleMode diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp index 399eaf8d38..ff3119a53d 100644 --- a/gpu/src/GrContext.cpp +++ b/gpu/src/GrContext.cpp @@ -128,7 +128,7 @@ bool GrContext::finalizeTextureKey(GrTextureKey* key, if (tiled && !isPow2) { bits |= kNPOTBit; - if (sampler.isFilter()) { + if (GrSamplerState::kNearest_Filter != sampler.getFilter()) { bits |= kFilterBit; } } @@ -223,9 +223,18 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, fGpu->disableState(GrDrawTarget::kDither_StateBit | GrDrawTarget::kClip_StateBit | GrDrawTarget::kAntialias_StateBit); + GrSamplerState::Filter filter; + // if filtering is not desired then we want to ensure all + // texels in the resampled image are copies of texels from + // the original. + if (GrSamplerState::kNearest_Filter == sampler.getFilter()) { + filter = GrSamplerState::kNearest_Filter; + } else { + filter = GrSamplerState::kBilinear_Filter; + } GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode, GrSamplerState::kClamp_WrapMode, - sampler.isFilter()); + filter); fGpu->setSamplerState(0, stretchSampler); static const GrVertexLayout layout = @@ -490,9 +499,13 @@ bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target, int scale; // Using MSAA seems to be slower for some yet unknown reason. if (false && fGpu->supportsFullsceneAA()) { + record->fDownsample = OffscreenRecord::kFSAA_Downsample; scale = GR_Scalar1; desc.fAALevel = kMed_GrAALevel; } else { + record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ? + OffscreenRecord::k4x4SinglePass_Downsample : + OffscreenRecord::k4x4TwoPass_Downsample; scale = 4; desc.fAALevel = kNone_GrAALevel; } @@ -506,7 +519,7 @@ bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target, return false; } - if (scale > 1) { + if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) { desc.fWidth /= 2; desc.fHeight /= 2; record->fEntry1 = this->lockKeylessTexture(desc); @@ -550,16 +563,22 @@ void GrContext::offscreenAAPass2(GrDrawTarget* target, GrAssert(NULL != record->fEntry0); - bool downsample = NULL != record->fEntry1; - + GrSamplerState::Filter filter; + if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) { + filter = GrSamplerState::k4x4Downsample_Filter; + } else { + filter = GrSamplerState::kBilinear_Filter; + } + GrMatrix sampleM; GrSamplerState sampler(GrSamplerState::kClamp_WrapMode, - GrSamplerState::kClamp_WrapMode, true); + GrSamplerState::kClamp_WrapMode, filter); GrTexture* src = record->fEntry0->texture(); int scale; - if (downsample) { + if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) { + GrAssert(NULL != record->fEntry1); scale = 2; GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget(); @@ -577,10 +596,14 @@ void GrContext::offscreenAAPass2(GrDrawTarget* target, target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage); src = record->fEntry1->texture(); - } else { + } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) { scale = 1; GrIRect rect(0, 0, boundRect.width(), boundRect.height()); src->asRenderTarget()->overrideResolveRect(rect); + } else { + GrAssert(OffscreenRecord::k4x4SinglePass_Downsample == + record->fDownsample); + scale = 4; } // setup for draw back to main RT @@ -607,7 +630,7 @@ void GrContext::offscreenAAPass2(GrDrawTarget* target, this->unlockTexture(record->fEntry0); record->fEntry0 = NULL; - if (downsample) { + if (NULL != record->fEntry1) { this->unlockTexture(record->fEntry1); record->fEntry1 = NULL; } diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp index 0365470387..ce4f00034f 100644 --- a/gpu/src/GrGLProgram.cpp +++ b/gpu/src/GrGLProgram.cpp @@ -42,6 +42,8 @@ const char* GrShaderPrecision() { } // namespace +#define PRINT_SHADERS 0 + #if GR_GL_ATTRIBUTE_MATRICES #define VIEW_MATRIX_NAME "aViewM" #else @@ -93,6 +95,11 @@ static void tex_matrix_name(int stage, GrStringBuilder* s) { s->appendInt(stage); } +static void normalized_texel_size_name(int stage, GrStringBuilder* s) { + *s = "uTexelSize"; + s->appendInt(stage); +} + static void sampler_name(int stage, GrStringBuilder* s) { *s = "uSampler"; s->appendInt(stage); @@ -172,8 +179,7 @@ void GrGLProgram::doGLPost() const { } } -void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, - const GrDrawTarget* target) const { +void GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const { ShaderCodeSegments segments; const uint32_t& layout = fProgramDesc.fVertexLayout; @@ -219,7 +225,7 @@ void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, // add texture coordinates that are used to the list of vertex attr decls GrTokenString texCoordAttrs[GrDrawTarget::kMaxTexCoords]; for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) { - if (target->VertexUsesTexCoordIdx(t, layout)) { + if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) { tex_attr_name(t, texCoordAttrs + t); segments.fVSAttrs += "attribute vec2 "; @@ -315,11 +321,11 @@ void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, ++stringCnt; #if PRINT_SHADERS - GrPrintf("%s%s%s%s\n", - segments.fVSUnis.cstr(), - segments.fVSAttrs.cstr(), - segments.fVaryings.cstr(), - segments.fVSCode.cstr()); + GrPrintf(segments.fVSUnis.cstr()); + GrPrintf(segments.fVSAttrs.cstr()); + GrPrintf(segments.fVaryings.cstr()); + GrPrintf(segments.fVSCode.cstr()); + GrPrintf("\n"); #endif programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER, stringCnt, @@ -350,11 +356,11 @@ void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, ++stringCnt; #if PRINT_SHADERS - GrPrintf("%s%s%s%s\n", - GR_SHADER_PRECISION, - segments.fFSUnis.cstr(), - segments.fVaryings.cstr(), - segments.fFSCode.cstr()); + GrPrintf(GrShaderPrecision()); + GrPrintf(segments.fFSUnis.cstr()); + GrPrintf(segments.fVaryings.cstr()); + GrPrintf(segments.fFSCode.cstr()); + GrPrintf("\n"); #endif programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER, stringCnt, @@ -464,6 +470,16 @@ void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, locations.fSamplerUni = -1; } + if (locations.fNormalizedTexelSizeUni) { + GrTokenString texelSizeName; + normalized_texel_size_name(s, &texelSizeName); + locations.fNormalizedTexelSizeUni = + GR_GL(GetUniformLocation(progID, texelSizeName.cstr())); + GrAssert(-1 != locations.fNormalizedTexelSizeUni); + } else { + locations.fNormalizedTexelSizeUni = -1; + } + if (locations.fRadial2Uni) { GrTokenString radial2ParamName; radial2_param_name(s, &radial2ParamName); @@ -478,6 +494,7 @@ void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, locations.fSamplerUni = -1; locations.fRadial2Uni = -1; locations.fTextureMatrixUni = -1; + locations.fNormalizedTexelSizeUni = -1; } } GR_GL(UseProgram(progID)); @@ -490,8 +507,11 @@ void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix(); programData->fRadial2CenterX1[s] = GR_ScalarMax; programData->fRadial2Radius0[s] = -GR_ScalarMax; + programData->fTextureWidth[s] = -1; + programData->fTextureHeight[s] = -1; } programData->fViewMatrix = GrMatrix::InvalidMatrix(); + programData->fColor = GrColor_ILLEGAL; } GrGLuint GrGLProgram::CompileShader(GrGLenum type, @@ -535,12 +555,12 @@ GrGLuint GrGLProgram::CompileShader(GrGLenum type, //============================================================================ void GrGLProgram::genStageCode(int stageNum, - const GrGLProgram::ProgramDesc::StageDesc& desc, - const char* fsInColor, // NULL means no incoming color - const char* fsOutColor, - const char* vsInCoord, - ShaderCodeSegments* segments, - StageUniLocations* locations) const { + const GrGLProgram::ProgramDesc::StageDesc& desc, + const char* fsInColor, // NULL means no incoming color + const char* fsOutColor, + const char* vsInCoord, + ShaderCodeSegments* segments, + StageUniLocations* locations) const { GrAssert(stageNum >= 0 && stageNum <= 9); @@ -585,6 +605,14 @@ void GrGLProgram::genStageCode(int stageNum, segments->fFSUnis += ";\n"; locations->fSamplerUni = 1; + GrTokenString texelSizeName; + if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) { + normalized_texel_size_name(stageNum, &texelSizeName); + segments->fFSUnis += "uniform vec2 "; + segments->fFSUnis += texelSizeName; + segments->fFSUnis += ";\n"; + } + segments->fVaryings += "varying "; segments->fVaryings += float_vector_type(varyingDims); segments->fVaryings += " "; @@ -661,14 +689,15 @@ void GrGLProgram::genStageCode(int stageNum, GrAssert(varyingDims == coordDims); fsCoordName = varyingName; } else { - // if we have to do some non-matrix op on the varyings to get + // if we have to do some special op on the varyings to get // our final tex coords then when in perspective we have to // do an explicit divide - if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) { + if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping && + ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) { texFunc += "Proj"; fsCoordName = varyingName; } else { - fsCoordName = "tCoord"; + fsCoordName = "inCoord"; fsCoordName.appendInt(stageNum); segments->fFSCode += "\t"; @@ -686,6 +715,7 @@ void GrGLProgram::genStageCode(int stageNum, } GrSStringBuilder<96> sampleCoords; + bool complexCoord = false; switch (desc.fCoordMapping) { case ProgramDesc::StageDesc::kIdentity_CoordMapping: sampleCoords = fsCoordName; @@ -696,11 +726,13 @@ void GrGLProgram::genStageCode(int stageNum, sampleCoords += ".y, -"; sampleCoords += fsCoordName; sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)"; + complexCoord = true; break; case ProgramDesc::StageDesc::kRadialGradient_CoordMapping: sampleCoords = "vec2(length("; sampleCoords += fsCoordName; sampleCoords += ".xy), 0.5)"; + complexCoord = true; break; case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: { GrTokenString cName = "c"; @@ -769,26 +801,85 @@ void GrGLProgram::genStageCode(int stageNum, sampleCoords += ") * "; sampleCoords += radial2ParamsName; sampleCoords += "[1], 0.5)\n"; + complexCoord = true; break;} }; - segments->fFSCode += "\t"; - segments->fFSCode += fsOutColor; - segments->fFSCode += " = "; - if (NULL != fsInColor) { - segments->fFSCode += fsInColor; - segments->fFSCode += " * "; - } - segments->fFSCode += texFunc; - segments->fFSCode += "("; - segments->fFSCode += samplerName; - segments->fFSCode += ", "; - segments->fFSCode += sampleCoords; - segments->fFSCode += ")"; - if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) { - segments->fFSCode += ".aaaa"; + if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) { + locations->fNormalizedTexelSizeUni = 1; + if (complexCoord) { + GrTokenString coordVar("tCoord"); + coordVar.appendInt(stageNum); + segments->fFSCode += "\t"; + segments->fFSCode += float_vector_type(coordDims); + segments->fFSCode += " "; + segments->fFSCode += coordVar; + segments->fFSCode += " = "; + segments->fFSCode += sampleCoords; + segments->fFSCode += ";\n"; + sampleCoords = coordVar; + } + static const char sign[] = {'-','+'}; + GrTokenString stageAccumVar("stage2x2Accum"); + stageAccumVar.appendInt(stageNum); + segments->fFSCode += "\tvec4 "; + segments->fFSCode += stageAccumVar; + segments->fFSCode += " = "; + GrAssert(2 == coordDims); + for (int y = 0; y < 2; ++y) { + for (int x = 0; x < 2; ++x) { + segments->fFSCode += texFunc; + segments->fFSCode += "("; + segments->fFSCode += samplerName; + segments->fFSCode += ", "; + segments->fFSCode += sampleCoords; + segments->fFSCode += " + vec2("; + segments->fFSCode += sign[x]; + segments->fFSCode += texelSizeName; + segments->fFSCode += ".x, "; + segments->fFSCode += sign[y]; + segments->fFSCode += texelSizeName; + segments->fFSCode += ".y))"; + if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) { + segments->fFSCode += ".aaaa"; + } + segments->fFSCode += ";\n"; + if (1 != x || 1 !=y ) { + segments->fFSCode += "\t"; + segments->fFSCode += stageAccumVar; + segments->fFSCode += " += "; + } + } + } + segments->fFSCode += "\t"; + segments->fFSCode += fsOutColor; + segments->fFSCode += " = "; + if (NULL != fsInColor) { + segments->fFSCode += fsInColor; + segments->fFSCode += " * "; + } + segments->fFSCode += stageAccumVar; + segments->fFSCode += " / 4;\n"; + } else { + segments->fFSCode += "\t"; + segments->fFSCode += fsOutColor; + segments->fFSCode += " = "; + if (NULL != fsInColor) { + segments->fFSCode += fsInColor; + segments->fFSCode += " * "; + } + + segments->fFSCode += texFunc; + segments->fFSCode += "("; + segments->fFSCode += samplerName; + segments->fFSCode += ", "; + segments->fFSCode += sampleCoords; + segments->fFSCode += ")"; + if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) { + segments->fFSCode += ".aaaa"; + } + segments->fFSCode += ";\n"; } - segments->fFSCode += ";\n"; if(fStageEffects[stageNum]) { fStageEffects[stageNum]->genShaderCode(segments); diff --git a/gpu/src/GrGLProgram.h b/gpu/src/GrGLProgram.h index bc740384df..4fc1d430cb 100644 --- a/gpu/src/GrGLProgram.h +++ b/gpu/src/GrGLProgram.h @@ -58,7 +58,7 @@ public: * The result of heavy init is not stored in datamembers of GrGLProgam, * but in a separate cacheable container. */ - void genProgram(CachedData* programData, const GrDrawTarget* target) const; + void genProgram(CachedData* programData) const; /** * Routine that is called before rendering. Sets-up all the state and @@ -107,20 +107,25 @@ private: kIdentityMatrix_OptFlagBit = 0x2 }; - unsigned fOptFlags : 8; - unsigned fEnabled : 8; + unsigned fOptFlags; + bool fEnabled; enum Modulation { kColor_Modulation, kAlpha_Modulation - } fModulation : 8; + } fModulation; + + enum FetchMode { + kSingle_FetchMode, + k2x2_FetchMode + } fFetchMode; enum CoordMapping { kIdentity_CoordMapping, kRadialGradient_CoordMapping, kSweepGradient_CoordMapping, kRadial2Gradient_CoordMapping - } fCoordMapping : 8; + } fCoordMapping; } fStages[GrDrawTarget::kNumStages]; } fProgramDesc; @@ -129,6 +134,7 @@ private: public: struct StageUniLocations { GrGLint fTextureMatrixUni; + GrGLint fNormalizedTexelSizeUni; GrGLint fSamplerUni; GrGLint fRadial2Uni; }; @@ -188,6 +194,9 @@ public: // (GL uniform values travel with program) GrColor fColor; GrMatrix fTextureMatrices[GrDrawTarget::kNumStages]; + // width and height used for normalized texel size + int fTextureWidth[GrDrawTarget::kNumStages]; + int fTextureHeight[GrDrawTarget::kNumStages]; GrScalar fRadial2CenterX1[GrDrawTarget::kNumStages]; GrScalar fRadial2Radius0[GrDrawTarget::kNumStages]; bool fRadial2PosRoot[GrDrawTarget::kNumStages]; diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp index 5fff20fae9..e18c4a4473 100644 --- a/gpu/src/GrGpu.cpp +++ b/gpu/src/GrGpu.cpp @@ -755,7 +755,7 @@ const GrSamplerState GrSamplerState::gClampNoFilter( GrSamplerState::kClamp_WrapMode, GrSamplerState::kNormal_SampleMode, GrMatrix::I(), - false); + GrSamplerState::kNearest_Filter); diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp index 721d084d12..c63c7669fe 100644 --- a/gpu/src/GrGpuGL.cpp +++ b/gpu/src/GrGpuGL.cpp @@ -1754,8 +1754,12 @@ bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) { nextTexture->getTexParams(); GrGLTexture::TexParams newTexParams; - newTexParams.fFilter = sampler.isFilter() ? GR_GL_LINEAR : - GR_GL_NEAREST; + if (GrSamplerState::kNearest_Filter == sampler.getFilter()) { + newTexParams.fFilter = GR_GL_NEAREST; + } else { + newTexParams.fFilter = GR_GL_LINEAR; + } + newTexParams.fWrapS = GrGLTexture::WrapMode2GLWrap()[sampler.getWrapX()]; newTexParams.fWrapT = diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp index 4440bcdd85..dbfac436c8 100644 --- a/gpu/src/GrGpuGLFixed.cpp +++ b/gpu/src/GrGpuGLFixed.cpp @@ -56,6 +56,7 @@ static const GrGLenum gMatrixMode2Enum[] = { /////////////////////////////////////////////////////////////////////////////// GrGpuGLFixed::GrGpuGLFixed() { + f4X4DownsampleFilterSupport = false; } GrGpuGLFixed::~GrGpuGLFixed() { diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp index d8f99bc4c1..c977ea4c7e 100644 --- a/gpu/src/GrGpuGLShaders.cpp +++ b/gpu/src/GrGpuGLShaders.cpp @@ -22,8 +22,8 @@ #include "GrMemory.h" #include "GrNoncopyable.h" #include "GrStringBuilder.h" +#include "GrRandom.h" -#define PRINT_SHADERS 0 #define SKIP_CACHE_CHECK true #define GR_UINT32_MAX static_cast<uint32_t>(-1) @@ -52,7 +52,7 @@ private: void copyAndTakeOwnership(Entry& entry) { fProgramData.copyAndTakeOwnership(entry.fProgramData); fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer - fLRUStamp = entry.fLRUStamp; + fLRUStamp = entry.fLRUStamp; } public: @@ -96,8 +96,7 @@ public: } } - GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc, - const GrDrawTarget* target) { + GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) { ProgramHashKey key; while (key.doPass()) { desc.buildKey(key); @@ -119,7 +118,7 @@ public: GrGpuGLShaders::DeleteProgram(&entry->fProgramData); } entry->fKey.copyAndTakeOwnership(key); - desc.genProgram(&entry->fProgramData, target); + desc.genProgram(&entry->fProgramData); fHashCache.insert(entry->fKey, entry); } @@ -142,13 +141,99 @@ void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) { GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));) } +void GrGpuGLShaders::ProgramUnitTest() { + + static const int STAGE_OPTS[] = { + 0, + GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit, + GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping + }; + static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = { + GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation, + GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation + }; + static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = { + GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping, + GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping, + GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping, + GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping + }; + static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = { + GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode, + GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode, + }; + GrGLProgram program; + GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc; + + static const int NUM_TESTS = 512; + + // GrRandoms nextU() values have patterns in the low bits + // So using nextU() % array_count might never take some values. + GrRandom random; + for (int t = 0; t < NUM_TESTS; ++t) { + + pdesc.fVertexLayout = 0; + pdesc.fEmitsPointSize = random.nextF() > .5f; + float colorType = random.nextF(); + if (colorType < 1.f / 3.f) { + pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType; + } else if (colorType < 2.f / 3.f) { + pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType; + } else { + pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType; + } + for (int s = 0; s < kNumStages; ++s) { + // enable the stage? + if (random.nextF() > .5f) { + // use separate tex coords? + if (random.nextF() > .5f) { + int t = (int)(random.nextF() * kMaxTexCoords); + pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t); + } else { + pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s); + } + } + // use text-formatted verts? + if (random.nextF() > .5f) { + pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit; + } + } + + for (int s = 0; s < kNumStages; ++s) { + int x; + pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout); + x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS)); + pdesc.fStages[s].fOptFlags = STAGE_OPTS[x]; + x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES)); + pdesc.fStages[s].fModulation = STAGE_MODULATES[x]; + x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS)); + pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[x]; + x = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES)); + pdesc.fStages[s].fFetchMode = FETCH_MODES[x]; + } + GrGLProgram::CachedData cachedData; + program.genProgram(&cachedData); + DeleteProgram(&cachedData); + bool again = false; + if (again) { + program.genProgram(&cachedData); + DeleteProgram(&cachedData); + } + } +} + GrGpuGLShaders::GrGpuGLShaders() { resetContext(); + f4X4DownsampleFilterSupport = true; fProgramData = NULL; fProgramCache = new ProgramCache(); + +#if 0 + ProgramUnitTest(); +#endif } GrGpuGLShaders::~GrGpuGLShaders() { @@ -217,59 +302,90 @@ void GrGpuGLShaders::flushViewMatrix() { #endif } -void GrGpuGLShaders::flushTextureMatrix(int stage) { - GrAssert(NULL != fCurrDrawState.fTextures[stage]); - - GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[stage]; - - GrMatrix m = getSamplerMatrix(stage); - GrSamplerState::SampleMode mode = - fCurrDrawState.fSamplerStates[stage].getSampleMode(); - AdjustTextureMatrix(texture, mode, &m); - - // ES doesn't allow you to pass true to the transpose param, - // so do our own transpose - GrScalar mt[] = { - m[GrMatrix::kScaleX], - m[GrMatrix::kSkewY], - m[GrMatrix::kPersp0], - m[GrMatrix::kSkewX], - m[GrMatrix::kScaleY], - m[GrMatrix::kPersp1], - m[GrMatrix::kTransX], - m[GrMatrix::kTransY], - m[GrMatrix::kPersp2] - }; -#if GR_GL_ATTRIBUTE_MATRICES - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0)); - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3)); - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6)); -#else - GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni, - 1, false, mt)); -#endif +void GrGpuGLShaders::flushTextureMatrix(int s) { + const int& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni; + GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; + if (NULL != texture) { + if (-1 != uni && + (((1 << s) & fDirtyFlags.fTextureChangedMask) || + getHWSamplerMatrix(s) != getSamplerMatrix(s))) { + + GrAssert(NULL != fCurrDrawState.fTextures[s]); + + GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; + + GrMatrix m = getSamplerMatrix(s); + GrSamplerState::SampleMode mode = + fCurrDrawState.fSamplerStates[s].getSampleMode(); + AdjustTextureMatrix(texture, mode, &m); + + // ES doesn't allow you to pass true to the transpose param, + // so do our own transpose + GrScalar mt[] = { + m[GrMatrix::kScaleX], + m[GrMatrix::kSkewY], + m[GrMatrix::kPersp0], + m[GrMatrix::kSkewX], + m[GrMatrix::kScaleY], + m[GrMatrix::kPersp1], + m[GrMatrix::kTransX], + m[GrMatrix::kTransY], + m[GrMatrix::kPersp2] + }; + #if GR_GL_ATTRIBUTE_MATRICES + GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0)); + GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3)); + GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6)); + #else + GR_GL(UniformMatrix3fv(uni, 1, false, mt)); + #endif + recordHWSamplerMatrix(s, getSamplerMatrix(s)); + } + } } -void GrGpuGLShaders::flushRadial2(int stage) { - - const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[stage]; - - GrScalar centerX1 = sampler.getRadial2CenterX1(); - GrScalar radius0 = sampler.getRadial2Radius0(); +void GrGpuGLShaders::flushRadial2(int s) { + + const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni; + const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; + if (-1 != uni && + (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() || + fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() || + fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) { + + GrScalar centerX1 = sampler.getRadial2CenterX1(); + GrScalar radius0 = sampler.getRadial2Radius0(); + + GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1; + + float values[6] = { + GrScalarToFloat(a), + 1 / (2.f * values[0]), + GrScalarToFloat(centerX1), + GrScalarToFloat(radius0), + GrScalarToFloat(GrMul(radius0, radius0)), + sampler.isRadial2PosRoot() ? 1.f : -1.f + }; + GR_GL(Uniform1fv(uni, 6, values)); + fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1(); + fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0(); + fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot(); + } +} - GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1; +void GrGpuGLShaders::flushTexelSize(int s) { + const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; + const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni; + if (-1 != uni) { + GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; + if (texture->allocWidth() != fProgramData->fTextureWidth[s] || + texture->allocHeight() != fProgramData->fTextureWidth[s]) { - float unis[6] = { - GrScalarToFloat(a), - 1 / (2.f * unis[0]), - GrScalarToFloat(centerX1), - GrScalarToFloat(radius0), - GrScalarToFloat(GrMul(radius0, radius0)), - sampler.isRadial2PosRoot() ? 1.f : -1.f - }; - GR_GL(Uniform1fv(fProgramData->fUniLocations.fStages[stage].fRadial2Uni, - 6, - unis)); + float texelSize[] = {1.f / texture->allocWidth(), + 1.f / texture->allocHeight()}; + GR_GL(Uniform2fv(uni, 1, texelSize)); + } + } } void GrGpuGLShaders::flushColor() { @@ -334,7 +450,7 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { } buildProgram(type); - fProgramData = fProgramCache->getProgramData(fCurrentProgram, this); + fProgramData = fProgramCache->getProgramData(fCurrentProgram); if (fHWProgramID != fProgramData->fProgramID) { GR_GL(UseProgram(fProgramData->fProgramID)); @@ -345,7 +461,7 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { return false; } - flushColor(); + this->flushColor(); #if GR_GL_ATTRIBUTE_MATRICES GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix; @@ -359,28 +475,11 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { } for (int s = 0; s < kNumStages; ++s) { - GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; - if (NULL != texture) { - if (-1 != fProgramData->fUniLocations.fStages[s].fTextureMatrixUni && - (((1 << s) & fDirtyFlags.fTextureChangedMask) || - getHWSamplerMatrix(s) != getSamplerMatrix(s))) { - flushTextureMatrix(s); - recordHWSamplerMatrix(s, getSamplerMatrix(s)); - } - } - - const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; - if (-1 != fProgramData->fUniLocations.fStages[s].fRadial2Uni && - (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() || - fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() || - fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) { + this->flushTextureMatrix(s); - flushRadial2(s); + this->flushRadial2(s); - fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1(); - fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0(); - fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot(); - } + this->flushTexelSize(s); } resetDirtyFlags(); return true; @@ -531,21 +630,36 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) { stage.fOptFlags = 0; } switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) { - case GrSamplerState::kNormal_SampleMode: - stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping; - break; - case GrSamplerState::kRadial_SampleMode: - stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping; - break; - case GrSamplerState::kRadial2_SampleMode: - stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping; - break; - case GrSamplerState::kSweep_SampleMode: - stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping; - break; - default: - GrAssert(!"Unexpected sample mode!"); - break; + case GrSamplerState::kNormal_SampleMode: + stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping; + break; + case GrSamplerState::kRadial_SampleMode: + stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping; + break; + case GrSamplerState::kRadial2_SampleMode: + stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping; + break; + case GrSamplerState::kSweep_SampleMode: + stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping; + break; + default: + GrCrash("Unexpected sample mode!"); + break; + } + + switch (fCurrDrawState.fSamplerStates[s].getFilter()) { + // these both can use a regular texture2D() + case GrSamplerState::kNearest_Filter: + case GrSamplerState::kBilinear_Filter: + stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode; + break; + // performs 4 texture2D()s + case GrSamplerState::k4x4Downsample_Filter: + stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode; + break; + default: + GrCrash("Unexpected filter!"); + break; } if (GrPixelConfigIsAlphaOnly(texture->config())) { diff --git a/gpu/src/GrGpuGLShaders.h b/gpu/src/GrGpuGLShaders.h index 92aab6ce44..a1bcaf08be 100644 --- a/gpu/src/GrGpuGLShaders.h +++ b/gpu/src/GrGpuGLShaders.h @@ -60,6 +60,9 @@ private: // flushes the parameters to two point radial gradient void flushRadial2(int stage); + // flushes the normalized texel size + void flushTexelSize(int stage); + static void DeleteProgram(GrGLProgram::CachedData* programData); void ProgramUnitTest(); diff --git a/gpu/src/GrGpuGLShaders2.cpp b/gpu/src/GrGpuGLShaders2.cpp index 6abfcdc758..171a031ee3 100644 --- a/gpu/src/GrGpuGLShaders2.cpp +++ b/gpu/src/GrGpuGLShaders2.cpp @@ -1135,6 +1135,7 @@ void GrGpuGLShaders2::DeleteProgram(Program* program) { GrGpuGLShaders2::GrGpuGLShaders2() { + f4X4DownsampleFilterSupport = false; fProgram = NULL; fProgramCache = new ProgramCache(); diff --git a/gpu/src/GrTextContext.cpp b/gpu/src/GrTextContext.cpp index 09113e0646..0222042b37 100644 --- a/gpu/src/GrTextContext.cpp +++ b/gpu/src/GrTextContext.cpp @@ -36,10 +36,15 @@ void GrTextContext::flushGlyphs() { GrDrawTarget::AutoStateRestore asr(fDrawTarget); // setup our sampler state for our text texture/atlas - + GrSamplerState::Filter filter; + if (fExtMatrix.isIdentity()) { + filter = GrSamplerState::kNearest_Filter; + } else { + filter = GrSamplerState::kBilinear_Filter; + } GrSamplerState sampler(GrSamplerState::kRepeat_WrapMode, GrSamplerState::kRepeat_WrapMode, - !fExtMatrix.isIdentity()); + filter); fDrawTarget->setSamplerState(TEXT_STAGE, sampler); GrAssert(GrIsALIGN4(fCurrVertex)); diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 9051f040fd..2a501776e0 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -423,7 +423,11 @@ bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint, return false; } grPaint->fSampler.setSampleMode(sampleMode); - grPaint->fSampler.setFilter(skPaint.isFilterBitmap()); + if (skPaint.isFilterBitmap()) { + grPaint->fSampler.setFilter(GrSamplerState::kBilinear_Filter); + } else { + grPaint->fSampler.setFilter(GrSamplerState::kNearest_Filter); + } grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0])); grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1])); if (GrSamplerState::kRadial2_SampleMode == sampleMode) { @@ -863,7 +867,12 @@ void SkGpuDevice::drawBitmap(const SkDraw& draw, if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) { return; } - grPaint.fSampler.setFilter(paint.isFilterBitmap()); + if (paint.isFilterBitmap()) { + grPaint.fSampler.setFilter(GrSamplerState::kBilinear_Filter); + } else { + grPaint.fSampler.setFilter(GrSamplerState::kNearest_Filter); + } + const int maxTextureDim = fContext->getMaxTextureDimension(); if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim && |