Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | /* |
michael@0 | 2 | * Copyright 2012 Google Inc. |
michael@0 | 3 | * |
michael@0 | 4 | * Use of this source code is governed by a BSD-style license that can be |
michael@0 | 5 | * found in the LICENSE file. |
michael@0 | 6 | */ |
michael@0 | 7 | |
michael@0 | 8 | #include "gl/GrGLShaderBuilder.h" |
michael@0 | 9 | #include "gl/GrGLProgram.h" |
michael@0 | 10 | #include "gl/GrGLUniformHandle.h" |
michael@0 | 11 | #include "GrCoordTransform.h" |
michael@0 | 12 | #include "GrDrawEffect.h" |
michael@0 | 13 | #include "GrGpuGL.h" |
michael@0 | 14 | #include "GrTexture.h" |
michael@0 | 15 | #include "SkRTConf.h" |
michael@0 | 16 | #include "SkTrace.h" |
michael@0 | 17 | |
michael@0 | 18 | #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X) |
michael@0 | 19 | #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X) |
michael@0 | 20 | |
michael@0 | 21 | // number of each input/output type in a single allocation block |
michael@0 | 22 | static const int kVarsPerBlock = 8; |
michael@0 | 23 | |
michael@0 | 24 | // except FS outputs where we expect 2 at most. |
michael@0 | 25 | static const int kMaxFSOutputs = 2; |
michael@0 | 26 | |
michael@0 | 27 | // ES2 FS only guarantees mediump and lowp support |
michael@0 | 28 | static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision; |
michael@0 | 29 | |
michael@0 | 30 | typedef GrGLUniformManager::UniformHandle UniformHandle; |
michael@0 | 31 | |
michael@0 | 32 | SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false, |
michael@0 | 33 | "Print the source code for all shaders generated."); |
michael@0 | 34 | |
michael@0 | 35 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 36 | |
michael@0 | 37 | namespace { |
michael@0 | 38 | |
michael@0 | 39 | inline const char* color_attribute_name() { return "aColor"; } |
michael@0 | 40 | inline const char* coverage_attribute_name() { return "aCoverage"; } |
michael@0 | 41 | inline const char* declared_color_output_name() { return "fsColorOut"; } |
michael@0 | 42 | inline const char* dual_source_output_name() { return "dualSourceOut"; } |
michael@0 | 43 | inline const char* sample_function_name(GrSLType type, GrGLSLGeneration glslGen) { |
michael@0 | 44 | if (kVec2f_GrSLType == type) { |
michael@0 | 45 | return glslGen >= k130_GrGLSLGeneration ? "texture" : "texture2D"; |
michael@0 | 46 | } else { |
michael@0 | 47 | SkASSERT(kVec3f_GrSLType == type); |
michael@0 | 48 | return glslGen >= k130_GrGLSLGeneration ? "textureProj" : "texture2DProj"; |
michael@0 | 49 | } |
michael@0 | 50 | } |
michael@0 | 51 | |
michael@0 | 52 | void append_texture_lookup(SkString* out, |
michael@0 | 53 | GrGpuGL* gpu, |
michael@0 | 54 | const char* samplerName, |
michael@0 | 55 | const char* coordName, |
michael@0 | 56 | uint32_t configComponentMask, |
michael@0 | 57 | const char* swizzle, |
michael@0 | 58 | GrSLType varyingType = kVec2f_GrSLType) { |
michael@0 | 59 | SkASSERT(NULL != coordName); |
michael@0 | 60 | |
michael@0 | 61 | out->appendf("%s(%s, %s)", |
michael@0 | 62 | sample_function_name(varyingType, gpu->glslGeneration()), |
michael@0 | 63 | samplerName, |
michael@0 | 64 | coordName); |
michael@0 | 65 | |
michael@0 | 66 | char mangledSwizzle[5]; |
michael@0 | 67 | |
michael@0 | 68 | // The swizzling occurs using texture params instead of shader-mangling if ARB_texture_swizzle |
michael@0 | 69 | // is available. |
michael@0 | 70 | if (!gpu->glCaps().textureSwizzleSupport() && |
michael@0 | 71 | (kA_GrColorComponentFlag == configComponentMask)) { |
michael@0 | 72 | char alphaChar = gpu->glCaps().textureRedSupport() ? 'r' : 'a'; |
michael@0 | 73 | int i; |
michael@0 | 74 | for (i = 0; '\0' != swizzle[i]; ++i) { |
michael@0 | 75 | mangledSwizzle[i] = alphaChar; |
michael@0 | 76 | } |
michael@0 | 77 | mangledSwizzle[i] ='\0'; |
michael@0 | 78 | swizzle = mangledSwizzle; |
michael@0 | 79 | } |
michael@0 | 80 | // For shader prettiness we omit the swizzle rather than appending ".rgba". |
michael@0 | 81 | if (memcmp(swizzle, "rgba", 4)) { |
michael@0 | 82 | out->appendf(".%s", swizzle); |
michael@0 | 83 | } |
michael@0 | 84 | } |
michael@0 | 85 | |
michael@0 | 86 | } |
michael@0 | 87 | |
michael@0 | 88 | static const char kDstCopyColorName[] = "_dstColor"; |
michael@0 | 89 | |
michael@0 | 90 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 91 | |
michael@0 | 92 | GrGLShaderBuilder::GrGLShaderBuilder(GrGpuGL* gpu, |
michael@0 | 93 | GrGLUniformManager& uniformManager, |
michael@0 | 94 | const GrGLProgramDesc& desc) |
michael@0 | 95 | : fGpu(gpu) |
michael@0 | 96 | , fUniformManager(uniformManager) |
michael@0 | 97 | , fFSFeaturesAddedMask(0) |
michael@0 | 98 | , fFSInputs(kVarsPerBlock) |
michael@0 | 99 | , fFSOutputs(kMaxFSOutputs) |
michael@0 | 100 | , fUniforms(kVarsPerBlock) |
michael@0 | 101 | , fSetupFragPosition(false) |
michael@0 | 102 | , fHasCustomColorOutput(false) |
michael@0 | 103 | , fHasSecondaryOutput(false) |
michael@0 | 104 | , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey) { |
michael@0 | 105 | |
michael@0 | 106 | const GrGLProgramDesc::KeyHeader& header = desc.getHeader(); |
michael@0 | 107 | |
michael@0 | 108 | // Emit code to read the dst copy textue if necessary. |
michael@0 | 109 | if (kNoDstRead_DstReadKey != header.fDstReadKey && |
michael@0 | 110 | GrGLCaps::kNone_FBFetchType == fGpu->glCaps().fbFetchType()) { |
michael@0 | 111 | bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKey); |
michael@0 | 112 | const char* dstCopyTopLeftName; |
michael@0 | 113 | const char* dstCopyCoordScaleName; |
michael@0 | 114 | uint32_t configMask; |
michael@0 | 115 | if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) { |
michael@0 | 116 | configMask = kA_GrColorComponentFlag; |
michael@0 | 117 | } else { |
michael@0 | 118 | configMask = kRGBA_GrColorComponentFlags; |
michael@0 | 119 | } |
michael@0 | 120 | fDstCopySamplerUniform = this->addUniform(kFragment_Visibility, |
michael@0 | 121 | kSampler2D_GrSLType, |
michael@0 | 122 | "DstCopySampler"); |
michael@0 | 123 | fDstCopyTopLeftUniform = this->addUniform(kFragment_Visibility, |
michael@0 | 124 | kVec2f_GrSLType, |
michael@0 | 125 | "DstCopyUpperLeft", |
michael@0 | 126 | &dstCopyTopLeftName); |
michael@0 | 127 | fDstCopyScaleUniform = this->addUniform(kFragment_Visibility, |
michael@0 | 128 | kVec2f_GrSLType, |
michael@0 | 129 | "DstCopyCoordScale", |
michael@0 | 130 | &dstCopyCoordScaleName); |
michael@0 | 131 | const char* fragPos = this->fragmentPosition(); |
michael@0 | 132 | this->fsCodeAppend("\t// Read color from copy of the destination.\n"); |
michael@0 | 133 | this->fsCodeAppendf("\tvec2 _dstTexCoord = (%s.xy - %s) * %s;\n", |
michael@0 | 134 | fragPos, dstCopyTopLeftName, dstCopyCoordScaleName); |
michael@0 | 135 | if (!topDown) { |
michael@0 | 136 | this->fsCodeAppend("\t_dstTexCoord.y = 1.0 - _dstTexCoord.y;\n"); |
michael@0 | 137 | } |
michael@0 | 138 | this->fsCodeAppendf("\tvec4 %s = ", kDstCopyColorName); |
michael@0 | 139 | append_texture_lookup(&fFSCode, |
michael@0 | 140 | fGpu, |
michael@0 | 141 | this->getUniformCStr(fDstCopySamplerUniform), |
michael@0 | 142 | "_dstTexCoord", |
michael@0 | 143 | configMask, |
michael@0 | 144 | "rgba"); |
michael@0 | 145 | this->fsCodeAppend(";\n\n"); |
michael@0 | 146 | } |
michael@0 | 147 | |
michael@0 | 148 | if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) { |
michael@0 | 149 | const char* name; |
michael@0 | 150 | fColorUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
michael@0 | 151 | kVec4f_GrSLType, "Color", &name); |
michael@0 | 152 | fInputColor = GrGLSLExpr4(name); |
michael@0 | 153 | } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fColorInput) { |
michael@0 | 154 | fInputColor = GrGLSLExpr4(1); |
michael@0 | 155 | } else if (GrGLProgramDesc::kTransBlack_ColorInput == header.fColorInput) { |
michael@0 | 156 | fInputColor = GrGLSLExpr4(0); |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) { |
michael@0 | 160 | const char* name; |
michael@0 | 161 | fCoverageUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
michael@0 | 162 | kVec4f_GrSLType, "Coverage", &name); |
michael@0 | 163 | fInputCoverage = GrGLSLExpr4(name); |
michael@0 | 164 | } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fCoverageInput) { |
michael@0 | 165 | fInputCoverage = GrGLSLExpr4(1); |
michael@0 | 166 | } else if (GrGLProgramDesc::kTransBlack_ColorInput == header.fCoverageInput) { |
michael@0 | 167 | fInputCoverage = GrGLSLExpr4(0); |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | if (k110_GrGLSLGeneration != fGpu->glslGeneration()) { |
michael@0 | 171 | fFSOutputs.push_back().set(kVec4f_GrSLType, |
michael@0 | 172 | GrGLShaderVar::kOut_TypeModifier, |
michael@0 | 173 | declared_color_output_name()); |
michael@0 | 174 | fHasCustomColorOutput = true; |
michael@0 | 175 | } |
michael@0 | 176 | } |
michael@0 | 177 | |
michael@0 | 178 | bool GrGLShaderBuilder::enableFeature(GLSLFeature feature) { |
michael@0 | 179 | switch (feature) { |
michael@0 | 180 | case kStandardDerivatives_GLSLFeature: |
michael@0 | 181 | if (!fGpu->glCaps().shaderDerivativeSupport()) { |
michael@0 | 182 | return false; |
michael@0 | 183 | } |
michael@0 | 184 | if (kGLES_GrGLStandard == fGpu->glStandard()) { |
michael@0 | 185 | this->addFSFeature(1 << kStandardDerivatives_GLSLFeature, |
michael@0 | 186 | "GL_OES_standard_derivatives"); |
michael@0 | 187 | } |
michael@0 | 188 | return true; |
michael@0 | 189 | default: |
michael@0 | 190 | GrCrash("Unexpected GLSLFeature requested."); |
michael@0 | 191 | return false; |
michael@0 | 192 | } |
michael@0 | 193 | } |
michael@0 | 194 | |
michael@0 | 195 | bool GrGLShaderBuilder::enablePrivateFeature(GLSLPrivateFeature feature) { |
michael@0 | 196 | switch (feature) { |
michael@0 | 197 | case kFragCoordConventions_GLSLPrivateFeature: |
michael@0 | 198 | if (!fGpu->glCaps().fragCoordConventionsSupport()) { |
michael@0 | 199 | return false; |
michael@0 | 200 | } |
michael@0 | 201 | if (fGpu->glslGeneration() < k150_GrGLSLGeneration) { |
michael@0 | 202 | this->addFSFeature(1 << kFragCoordConventions_GLSLPrivateFeature, |
michael@0 | 203 | "GL_ARB_fragment_coord_conventions"); |
michael@0 | 204 | } |
michael@0 | 205 | return true; |
michael@0 | 206 | case kEXTShaderFramebufferFetch_GLSLPrivateFeature: |
michael@0 | 207 | if (GrGLCaps::kEXT_FBFetchType != fGpu->glCaps().fbFetchType()) { |
michael@0 | 208 | return false; |
michael@0 | 209 | } |
michael@0 | 210 | this->addFSFeature(1 << kEXTShaderFramebufferFetch_GLSLPrivateFeature, |
michael@0 | 211 | "GL_EXT_shader_framebuffer_fetch"); |
michael@0 | 212 | return true; |
michael@0 | 213 | case kNVShaderFramebufferFetch_GLSLPrivateFeature: |
michael@0 | 214 | if (GrGLCaps::kNV_FBFetchType != fGpu->glCaps().fbFetchType()) { |
michael@0 | 215 | return false; |
michael@0 | 216 | } |
michael@0 | 217 | this->addFSFeature(1 << kNVShaderFramebufferFetch_GLSLPrivateFeature, |
michael@0 | 218 | "GL_NV_shader_framebuffer_fetch"); |
michael@0 | 219 | return true; |
michael@0 | 220 | default: |
michael@0 | 221 | GrCrash("Unexpected GLSLPrivateFeature requested."); |
michael@0 | 222 | return false; |
michael@0 | 223 | } |
michael@0 | 224 | } |
michael@0 | 225 | |
michael@0 | 226 | void GrGLShaderBuilder::addFSFeature(uint32_t featureBit, const char* extensionName) { |
michael@0 | 227 | if (!(featureBit & fFSFeaturesAddedMask)) { |
michael@0 | 228 | fFSExtensions.appendf("#extension %s: require\n", extensionName); |
michael@0 | 229 | fFSFeaturesAddedMask |= featureBit; |
michael@0 | 230 | } |
michael@0 | 231 | } |
michael@0 | 232 | |
michael@0 | 233 | void GrGLShaderBuilder::nameVariable(SkString* out, char prefix, const char* name) { |
michael@0 | 234 | if ('\0' == prefix) { |
michael@0 | 235 | *out = name; |
michael@0 | 236 | } else { |
michael@0 | 237 | out->printf("%c%s", prefix, name); |
michael@0 | 238 | } |
michael@0 | 239 | if (fCodeStage.inStageCode()) { |
michael@0 | 240 | if (out->endsWith('_')) { |
michael@0 | 241 | // Names containing "__" are reserved. |
michael@0 | 242 | out->append("x"); |
michael@0 | 243 | } |
michael@0 | 244 | out->appendf("_Stage%d", fCodeStage.stageIndex()); |
michael@0 | 245 | } |
michael@0 | 246 | } |
michael@0 | 247 | |
michael@0 | 248 | const char* GrGLShaderBuilder::dstColor() { |
michael@0 | 249 | if (fCodeStage.inStageCode()) { |
michael@0 | 250 | const GrEffectRef& effect = *fCodeStage.effectStage()->getEffect(); |
michael@0 | 251 | if (!effect->willReadDstColor()) { |
michael@0 | 252 | GrDebugCrash("GrGLEffect asked for dst color but its generating GrEffect " |
michael@0 | 253 | "did not request access."); |
michael@0 | 254 | return ""; |
michael@0 | 255 | } |
michael@0 | 256 | } |
michael@0 | 257 | static const char kFBFetchColorName[] = "gl_LastFragData[0]"; |
michael@0 | 258 | GrGLCaps::FBFetchType fetchType = fGpu->glCaps().fbFetchType(); |
michael@0 | 259 | if (GrGLCaps::kEXT_FBFetchType == fetchType) { |
michael@0 | 260 | SkAssertResult(this->enablePrivateFeature(kEXTShaderFramebufferFetch_GLSLPrivateFeature)); |
michael@0 | 261 | return kFBFetchColorName; |
michael@0 | 262 | } else if (GrGLCaps::kNV_FBFetchType == fetchType) { |
michael@0 | 263 | SkAssertResult(this->enablePrivateFeature(kNVShaderFramebufferFetch_GLSLPrivateFeature)); |
michael@0 | 264 | return kFBFetchColorName; |
michael@0 | 265 | } else if (fDstCopySamplerUniform.isValid()) { |
michael@0 | 266 | return kDstCopyColorName; |
michael@0 | 267 | } else { |
michael@0 | 268 | return ""; |
michael@0 | 269 | } |
michael@0 | 270 | } |
michael@0 | 271 | |
michael@0 | 272 | void GrGLShaderBuilder::appendTextureLookup(SkString* out, |
michael@0 | 273 | const GrGLShaderBuilder::TextureSampler& sampler, |
michael@0 | 274 | const char* coordName, |
michael@0 | 275 | GrSLType varyingType) const { |
michael@0 | 276 | append_texture_lookup(out, |
michael@0 | 277 | fGpu, |
michael@0 | 278 | this->getUniformCStr(sampler.samplerUniform()), |
michael@0 | 279 | coordName, |
michael@0 | 280 | sampler.configComponentMask(), |
michael@0 | 281 | sampler.swizzle(), |
michael@0 | 282 | varyingType); |
michael@0 | 283 | } |
michael@0 | 284 | |
michael@0 | 285 | void GrGLShaderBuilder::fsAppendTextureLookup(const GrGLShaderBuilder::TextureSampler& sampler, |
michael@0 | 286 | const char* coordName, |
michael@0 | 287 | GrSLType varyingType) { |
michael@0 | 288 | this->appendTextureLookup(&fFSCode, sampler, coordName, varyingType); |
michael@0 | 289 | } |
michael@0 | 290 | |
michael@0 | 291 | void GrGLShaderBuilder::fsAppendTextureLookupAndModulate( |
michael@0 | 292 | const char* modulation, |
michael@0 | 293 | const GrGLShaderBuilder::TextureSampler& sampler, |
michael@0 | 294 | const char* coordName, |
michael@0 | 295 | GrSLType varyingType) { |
michael@0 | 296 | SkString lookup; |
michael@0 | 297 | this->appendTextureLookup(&lookup, sampler, coordName, varyingType); |
michael@0 | 298 | fFSCode.append((GrGLSLExpr4(modulation) * GrGLSLExpr4(lookup)).c_str()); |
michael@0 | 299 | } |
michael@0 | 300 | |
michael@0 | 301 | GrGLShaderBuilder::DstReadKey GrGLShaderBuilder::KeyForDstRead(const GrTexture* dstCopy, |
michael@0 | 302 | const GrGLCaps& caps) { |
michael@0 | 303 | uint32_t key = kYesDstRead_DstReadKeyBit; |
michael@0 | 304 | if (GrGLCaps::kNone_FBFetchType != caps.fbFetchType()) { |
michael@0 | 305 | return key; |
michael@0 | 306 | } |
michael@0 | 307 | SkASSERT(NULL != dstCopy); |
michael@0 | 308 | if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->config())) { |
michael@0 | 309 | // The fact that the config is alpha-only must be considered when generating code. |
michael@0 | 310 | key |= kUseAlphaConfig_DstReadKeyBit; |
michael@0 | 311 | } |
michael@0 | 312 | if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) { |
michael@0 | 313 | key |= kTopLeftOrigin_DstReadKeyBit; |
michael@0 | 314 | } |
michael@0 | 315 | SkASSERT(static_cast<DstReadKey>(key) == key); |
michael@0 | 316 | return static_cast<DstReadKey>(key); |
michael@0 | 317 | } |
michael@0 | 318 | |
michael@0 | 319 | GrGLShaderBuilder::FragPosKey GrGLShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst, |
michael@0 | 320 | const GrGLCaps&) { |
michael@0 | 321 | if (kTopLeft_GrSurfaceOrigin == dst->origin()) { |
michael@0 | 322 | return kTopLeftFragPosRead_FragPosKey; |
michael@0 | 323 | } else { |
michael@0 | 324 | return kBottomLeftFragPosRead_FragPosKey; |
michael@0 | 325 | } |
michael@0 | 326 | } |
michael@0 | 327 | |
michael@0 | 328 | |
michael@0 | 329 | const GrGLenum* GrGLShaderBuilder::GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps) { |
michael@0 | 330 | if (caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(config)) { |
michael@0 | 331 | if (caps.textureRedSupport()) { |
michael@0 | 332 | static const GrGLenum gRedSmear[] = { GR_GL_RED, GR_GL_RED, GR_GL_RED, GR_GL_RED }; |
michael@0 | 333 | return gRedSmear; |
michael@0 | 334 | } else { |
michael@0 | 335 | static const GrGLenum gAlphaSmear[] = { GR_GL_ALPHA, GR_GL_ALPHA, |
michael@0 | 336 | GR_GL_ALPHA, GR_GL_ALPHA }; |
michael@0 | 337 | return gAlphaSmear; |
michael@0 | 338 | } |
michael@0 | 339 | } else { |
michael@0 | 340 | static const GrGLenum gStraight[] = { GR_GL_RED, GR_GL_GREEN, GR_GL_BLUE, GR_GL_ALPHA }; |
michael@0 | 341 | return gStraight; |
michael@0 | 342 | } |
michael@0 | 343 | } |
michael@0 | 344 | |
michael@0 | 345 | GrGLUniformManager::UniformHandle GrGLShaderBuilder::addUniformArray(uint32_t visibility, |
michael@0 | 346 | GrSLType type, |
michael@0 | 347 | const char* name, |
michael@0 | 348 | int count, |
michael@0 | 349 | const char** outName) { |
michael@0 | 350 | SkASSERT(name && strlen(name)); |
michael@0 | 351 | SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility); |
michael@0 | 352 | SkASSERT(0 == (~kVisibilityMask & visibility)); |
michael@0 | 353 | SkASSERT(0 != visibility); |
michael@0 | 354 | |
michael@0 | 355 | BuilderUniform& uni = fUniforms.push_back(); |
michael@0 | 356 | UniformHandle h = GrGLUniformManager::UniformHandle::CreateFromUniformIndex(fUniforms.count() - 1); |
michael@0 | 357 | SkDEBUGCODE(UniformHandle h2 =) |
michael@0 | 358 | fUniformManager.appendUniform(type, count); |
michael@0 | 359 | // We expect the uniform manager to initially have no uniforms and that all uniforms are added |
michael@0 | 360 | // by this function. Therefore, the handles should match. |
michael@0 | 361 | SkASSERT(h2 == h); |
michael@0 | 362 | uni.fVariable.setType(type); |
michael@0 | 363 | uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier); |
michael@0 | 364 | this->nameVariable(uni.fVariable.accessName(), 'u', name); |
michael@0 | 365 | uni.fVariable.setArrayCount(count); |
michael@0 | 366 | uni.fVisibility = visibility; |
michael@0 | 367 | |
michael@0 | 368 | // If it is visible in both the VS and FS, the precision must match. |
michael@0 | 369 | // We declare a default FS precision, but not a default VS. So set the var |
michael@0 | 370 | // to use the default FS precision. |
michael@0 | 371 | if ((kVertex_Visibility | kFragment_Visibility) == visibility) { |
michael@0 | 372 | // the fragment and vertex precisions must match |
michael@0 | 373 | uni.fVariable.setPrecision(kDefaultFragmentPrecision); |
michael@0 | 374 | } |
michael@0 | 375 | |
michael@0 | 376 | if (NULL != outName) { |
michael@0 | 377 | *outName = uni.fVariable.c_str(); |
michael@0 | 378 | } |
michael@0 | 379 | |
michael@0 | 380 | return h; |
michael@0 | 381 | } |
michael@0 | 382 | |
michael@0 | 383 | SkString GrGLShaderBuilder::ensureFSCoords2D(const TransformedCoordsArray& coords, int index) { |
michael@0 | 384 | if (kVec3f_GrSLType != coords[index].type()) { |
michael@0 | 385 | SkASSERT(kVec2f_GrSLType == coords[index].type()); |
michael@0 | 386 | return coords[index].getName(); |
michael@0 | 387 | } |
michael@0 | 388 | |
michael@0 | 389 | SkString coords2D("coords2D"); |
michael@0 | 390 | if (0 != index) { |
michael@0 | 391 | coords2D.appendf("_%i", index); |
michael@0 | 392 | } |
michael@0 | 393 | this->fsCodeAppendf("\tvec2 %s = %s.xy / %s.z;", |
michael@0 | 394 | coords2D.c_str(), coords[index].c_str(), coords[index].c_str()); |
michael@0 | 395 | return coords2D; |
michael@0 | 396 | } |
michael@0 | 397 | |
michael@0 | 398 | const char* GrGLShaderBuilder::fragmentPosition() { |
michael@0 | 399 | if (fCodeStage.inStageCode()) { |
michael@0 | 400 | const GrEffectRef& effect = *fCodeStage.effectStage()->getEffect(); |
michael@0 | 401 | if (!effect->willReadFragmentPosition()) { |
michael@0 | 402 | GrDebugCrash("GrGLEffect asked for frag position but its generating GrEffect " |
michael@0 | 403 | "did not request access."); |
michael@0 | 404 | return ""; |
michael@0 | 405 | } |
michael@0 | 406 | } |
michael@0 | 407 | // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers |
michael@0 | 408 | // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the |
michael@0 | 409 | // declaration varies in earlier GLSL specs. So it is simpler to omit it. |
michael@0 | 410 | if (fTopLeftFragPosRead) { |
michael@0 | 411 | fSetupFragPosition = true; |
michael@0 | 412 | return "gl_FragCoord"; |
michael@0 | 413 | } else if (fGpu->glCaps().fragCoordConventionsSupport()) { |
michael@0 | 414 | if (!fSetupFragPosition) { |
michael@0 | 415 | SkAssertResult(this->enablePrivateFeature(kFragCoordConventions_GLSLPrivateFeature)); |
michael@0 | 416 | fFSInputs.push_back().set(kVec4f_GrSLType, |
michael@0 | 417 | GrGLShaderVar::kIn_TypeModifier, |
michael@0 | 418 | "gl_FragCoord", |
michael@0 | 419 | GrGLShaderVar::kDefault_Precision, |
michael@0 | 420 | GrGLShaderVar::kUpperLeft_Origin); |
michael@0 | 421 | fSetupFragPosition = true; |
michael@0 | 422 | } |
michael@0 | 423 | return "gl_FragCoord"; |
michael@0 | 424 | } else { |
michael@0 | 425 | static const char* kCoordName = "fragCoordYDown"; |
michael@0 | 426 | if (!fSetupFragPosition) { |
michael@0 | 427 | // temporarily change the stage index because we're inserting non-stage code. |
michael@0 | 428 | CodeStage::AutoStageRestore csar(&fCodeStage, NULL); |
michael@0 | 429 | |
michael@0 | 430 | SkASSERT(!fRTHeightUniform.isValid()); |
michael@0 | 431 | const char* rtHeightName; |
michael@0 | 432 | |
michael@0 | 433 | fRTHeightUniform = this->addUniform(kFragment_Visibility, |
michael@0 | 434 | kFloat_GrSLType, |
michael@0 | 435 | "RTHeight", |
michael@0 | 436 | &rtHeightName); |
michael@0 | 437 | |
michael@0 | 438 | this->fFSCode.prependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, gl_FragCoord.zw);\n", |
michael@0 | 439 | kCoordName, rtHeightName); |
michael@0 | 440 | fSetupFragPosition = true; |
michael@0 | 441 | } |
michael@0 | 442 | SkASSERT(fRTHeightUniform.isValid()); |
michael@0 | 443 | return kCoordName; |
michael@0 | 444 | } |
michael@0 | 445 | } |
michael@0 | 446 | |
michael@0 | 447 | void GrGLShaderBuilder::fsEmitFunction(GrSLType returnType, |
michael@0 | 448 | const char* name, |
michael@0 | 449 | int argCnt, |
michael@0 | 450 | const GrGLShaderVar* args, |
michael@0 | 451 | const char* body, |
michael@0 | 452 | SkString* outName) { |
michael@0 | 453 | fFSFunctions.append(GrGLSLTypeString(returnType)); |
michael@0 | 454 | this->nameVariable(outName, '\0', name); |
michael@0 | 455 | fFSFunctions.appendf(" %s", outName->c_str()); |
michael@0 | 456 | fFSFunctions.append("("); |
michael@0 | 457 | for (int i = 0; i < argCnt; ++i) { |
michael@0 | 458 | args[i].appendDecl(this->ctxInfo(), &fFSFunctions); |
michael@0 | 459 | if (i < argCnt - 1) { |
michael@0 | 460 | fFSFunctions.append(", "); |
michael@0 | 461 | } |
michael@0 | 462 | } |
michael@0 | 463 | fFSFunctions.append(") {\n"); |
michael@0 | 464 | fFSFunctions.append(body); |
michael@0 | 465 | fFSFunctions.append("}\n\n"); |
michael@0 | 466 | } |
michael@0 | 467 | |
michael@0 | 468 | namespace { |
michael@0 | 469 | |
michael@0 | 470 | inline void append_default_precision_qualifier(GrGLShaderVar::Precision p, |
michael@0 | 471 | GrGLStandard standard, |
michael@0 | 472 | SkString* str) { |
michael@0 | 473 | // Desktop GLSL has added precision qualifiers but they don't do anything. |
michael@0 | 474 | if (kGLES_GrGLStandard == standard) { |
michael@0 | 475 | switch (p) { |
michael@0 | 476 | case GrGLShaderVar::kHigh_Precision: |
michael@0 | 477 | str->append("precision highp float;\n"); |
michael@0 | 478 | break; |
michael@0 | 479 | case GrGLShaderVar::kMedium_Precision: |
michael@0 | 480 | str->append("precision mediump float;\n"); |
michael@0 | 481 | break; |
michael@0 | 482 | case GrGLShaderVar::kLow_Precision: |
michael@0 | 483 | str->append("precision lowp float;\n"); |
michael@0 | 484 | break; |
michael@0 | 485 | case GrGLShaderVar::kDefault_Precision: |
michael@0 | 486 | GrCrash("Default precision now allowed."); |
michael@0 | 487 | default: |
michael@0 | 488 | GrCrash("Unknown precision value."); |
michael@0 | 489 | } |
michael@0 | 490 | } |
michael@0 | 491 | } |
michael@0 | 492 | } |
michael@0 | 493 | |
michael@0 | 494 | void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const { |
michael@0 | 495 | for (int i = 0; i < vars.count(); ++i) { |
michael@0 | 496 | vars[i].appendDecl(this->ctxInfo(), out); |
michael@0 | 497 | out->append(";\n"); |
michael@0 | 498 | } |
michael@0 | 499 | } |
michael@0 | 500 | |
michael@0 | 501 | void GrGLShaderBuilder::appendUniformDecls(ShaderVisibility visibility, |
michael@0 | 502 | SkString* out) const { |
michael@0 | 503 | for (int i = 0; i < fUniforms.count(); ++i) { |
michael@0 | 504 | if (fUniforms[i].fVisibility & visibility) { |
michael@0 | 505 | fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out); |
michael@0 | 506 | out->append(";\n"); |
michael@0 | 507 | } |
michael@0 | 508 | } |
michael@0 | 509 | } |
michael@0 | 510 | |
michael@0 | 511 | void GrGLShaderBuilder::createAndEmitEffects(GrGLProgramEffectsBuilder* programEffectsBuilder, |
michael@0 | 512 | const GrEffectStage* effectStages[], |
michael@0 | 513 | const EffectKey effectKeys[], |
michael@0 | 514 | int effectCnt, |
michael@0 | 515 | GrGLSLExpr4* fsInOutColor) { |
michael@0 | 516 | bool effectEmitted = false; |
michael@0 | 517 | |
michael@0 | 518 | GrGLSLExpr4 inColor = *fsInOutColor; |
michael@0 | 519 | GrGLSLExpr4 outColor; |
michael@0 | 520 | |
michael@0 | 521 | for (int e = 0; e < effectCnt; ++e) { |
michael@0 | 522 | SkASSERT(NULL != effectStages[e] && NULL != effectStages[e]->getEffect()); |
michael@0 | 523 | const GrEffectStage& stage = *effectStages[e]; |
michael@0 | 524 | |
michael@0 | 525 | CodeStage::AutoStageRestore csar(&fCodeStage, &stage); |
michael@0 | 526 | |
michael@0 | 527 | if (inColor.isZeros()) { |
michael@0 | 528 | SkString inColorName; |
michael@0 | 529 | |
michael@0 | 530 | // Effects have no way to communicate zeros, they treat an empty string as ones. |
michael@0 | 531 | this->nameVariable(&inColorName, '\0', "input"); |
michael@0 | 532 | this->fsCodeAppendf("\tvec4 %s = %s;\n", inColorName.c_str(), inColor.c_str()); |
michael@0 | 533 | inColor = inColorName; |
michael@0 | 534 | } |
michael@0 | 535 | |
michael@0 | 536 | // create var to hold stage result |
michael@0 | 537 | SkString outColorName; |
michael@0 | 538 | this->nameVariable(&outColorName, '\0', "output"); |
michael@0 | 539 | this->fsCodeAppendf("\tvec4 %s;\n", outColorName.c_str()); |
michael@0 | 540 | outColor = outColorName; |
michael@0 | 541 | |
michael@0 | 542 | |
michael@0 | 543 | programEffectsBuilder->emitEffect(stage, |
michael@0 | 544 | effectKeys[e], |
michael@0 | 545 | outColor.c_str(), |
michael@0 | 546 | inColor.isOnes() ? NULL : inColor.c_str(), |
michael@0 | 547 | fCodeStage.stageIndex()); |
michael@0 | 548 | |
michael@0 | 549 | inColor = outColor; |
michael@0 | 550 | effectEmitted = true; |
michael@0 | 551 | } |
michael@0 | 552 | |
michael@0 | 553 | if (effectEmitted) { |
michael@0 | 554 | *fsInOutColor = outColor; |
michael@0 | 555 | } |
michael@0 | 556 | } |
michael@0 | 557 | |
michael@0 | 558 | const char* GrGLShaderBuilder::getColorOutputName() const { |
michael@0 | 559 | return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor"; |
michael@0 | 560 | } |
michael@0 | 561 | |
michael@0 | 562 | const char* GrGLShaderBuilder::enableSecondaryOutput() { |
michael@0 | 563 | if (!fHasSecondaryOutput) { |
michael@0 | 564 | fFSOutputs.push_back().set(kVec4f_GrSLType, |
michael@0 | 565 | GrGLShaderVar::kOut_TypeModifier, |
michael@0 | 566 | dual_source_output_name()); |
michael@0 | 567 | fHasSecondaryOutput = true; |
michael@0 | 568 | } |
michael@0 | 569 | return dual_source_output_name(); |
michael@0 | 570 | } |
michael@0 | 571 | |
michael@0 | 572 | bool GrGLShaderBuilder::finish(GrGLuint* outProgramId) { |
michael@0 | 573 | SK_TRACE_EVENT0("GrGLShaderBuilder::finish"); |
michael@0 | 574 | |
michael@0 | 575 | GrGLuint programId = 0; |
michael@0 | 576 | GL_CALL_RET(programId, CreateProgram()); |
michael@0 | 577 | if (!programId) { |
michael@0 | 578 | return false; |
michael@0 | 579 | } |
michael@0 | 580 | |
michael@0 | 581 | SkTDArray<GrGLuint> shadersToDelete; |
michael@0 | 582 | |
michael@0 | 583 | if (!this->compileAndAttachShaders(programId, &shadersToDelete)) { |
michael@0 | 584 | GL_CALL(DeleteProgram(programId)); |
michael@0 | 585 | return false; |
michael@0 | 586 | } |
michael@0 | 587 | |
michael@0 | 588 | this->bindProgramLocations(programId); |
michael@0 | 589 | if (fUniformManager.isUsingBindUniform()) { |
michael@0 | 590 | fUniformManager.getUniformLocations(programId, fUniforms); |
michael@0 | 591 | } |
michael@0 | 592 | |
michael@0 | 593 | GL_CALL(LinkProgram(programId)); |
michael@0 | 594 | |
michael@0 | 595 | // Calling GetProgramiv is expensive in Chromium. Assume success in release builds. |
michael@0 | 596 | bool checkLinked = !fGpu->ctxInfo().isChromium(); |
michael@0 | 597 | #ifdef SK_DEBUG |
michael@0 | 598 | checkLinked = true; |
michael@0 | 599 | #endif |
michael@0 | 600 | if (checkLinked) { |
michael@0 | 601 | GrGLint linked = GR_GL_INIT_ZERO; |
michael@0 | 602 | GL_CALL(GetProgramiv(programId, GR_GL_LINK_STATUS, &linked)); |
michael@0 | 603 | if (!linked) { |
michael@0 | 604 | GrGLint infoLen = GR_GL_INIT_ZERO; |
michael@0 | 605 | GL_CALL(GetProgramiv(programId, GR_GL_INFO_LOG_LENGTH, &infoLen)); |
michael@0 | 606 | SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger |
michael@0 | 607 | if (infoLen > 0) { |
michael@0 | 608 | // retrieve length even though we don't need it to workaround |
michael@0 | 609 | // bug in chrome cmd buffer param validation. |
michael@0 | 610 | GrGLsizei length = GR_GL_INIT_ZERO; |
michael@0 | 611 | GL_CALL(GetProgramInfoLog(programId, |
michael@0 | 612 | infoLen+1, |
michael@0 | 613 | &length, |
michael@0 | 614 | (char*)log.get())); |
michael@0 | 615 | GrPrintf((char*)log.get()); |
michael@0 | 616 | } |
michael@0 | 617 | SkDEBUGFAIL("Error linking program"); |
michael@0 | 618 | GL_CALL(DeleteProgram(programId)); |
michael@0 | 619 | return false; |
michael@0 | 620 | } |
michael@0 | 621 | } |
michael@0 | 622 | |
michael@0 | 623 | if (!fUniformManager.isUsingBindUniform()) { |
michael@0 | 624 | fUniformManager.getUniformLocations(programId, fUniforms); |
michael@0 | 625 | } |
michael@0 | 626 | |
michael@0 | 627 | for (int i = 0; i < shadersToDelete.count(); ++i) { |
michael@0 | 628 | GL_CALL(DeleteShader(shadersToDelete[i])); |
michael@0 | 629 | } |
michael@0 | 630 | |
michael@0 | 631 | *outProgramId = programId; |
michael@0 | 632 | return true; |
michael@0 | 633 | } |
michael@0 | 634 | |
michael@0 | 635 | // Compiles a GL shader and attaches it to a program. Returns the shader ID if |
michael@0 | 636 | // successful, or 0 if not. |
michael@0 | 637 | static GrGLuint attach_shader(const GrGLContext& glCtx, |
michael@0 | 638 | GrGLuint programId, |
michael@0 | 639 | GrGLenum type, |
michael@0 | 640 | const SkString& shaderSrc) { |
michael@0 | 641 | const GrGLInterface* gli = glCtx.interface(); |
michael@0 | 642 | |
michael@0 | 643 | GrGLuint shaderId; |
michael@0 | 644 | GR_GL_CALL_RET(gli, shaderId, CreateShader(type)); |
michael@0 | 645 | if (0 == shaderId) { |
michael@0 | 646 | return 0; |
michael@0 | 647 | } |
michael@0 | 648 | |
michael@0 | 649 | const GrGLchar* sourceStr = shaderSrc.c_str(); |
michael@0 | 650 | GrGLint sourceLength = static_cast<GrGLint>(shaderSrc.size()); |
michael@0 | 651 | GR_GL_CALL(gli, ShaderSource(shaderId, 1, &sourceStr, &sourceLength)); |
michael@0 | 652 | GR_GL_CALL(gli, CompileShader(shaderId)); |
michael@0 | 653 | |
michael@0 | 654 | // Calling GetShaderiv in Chromium is quite expensive. Assume success in release builds. |
michael@0 | 655 | bool checkCompiled = !glCtx.isChromium(); |
michael@0 | 656 | #ifdef SK_DEBUG |
michael@0 | 657 | checkCompiled = true; |
michael@0 | 658 | #endif |
michael@0 | 659 | if (checkCompiled) { |
michael@0 | 660 | GrGLint compiled = GR_GL_INIT_ZERO; |
michael@0 | 661 | GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_COMPILE_STATUS, &compiled)); |
michael@0 | 662 | |
michael@0 | 663 | if (!compiled) { |
michael@0 | 664 | GrGLint infoLen = GR_GL_INIT_ZERO; |
michael@0 | 665 | GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_INFO_LOG_LENGTH, &infoLen)); |
michael@0 | 666 | SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger |
michael@0 | 667 | if (infoLen > 0) { |
michael@0 | 668 | // retrieve length even though we don't need it to workaround bug in Chromium cmd |
michael@0 | 669 | // buffer param validation. |
michael@0 | 670 | GrGLsizei length = GR_GL_INIT_ZERO; |
michael@0 | 671 | GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1, |
michael@0 | 672 | &length, (char*)log.get())); |
michael@0 | 673 | GrPrintf(shaderSrc.c_str()); |
michael@0 | 674 | GrPrintf("\n%s", log.get()); |
michael@0 | 675 | } |
michael@0 | 676 | SkDEBUGFAIL("Shader compilation failed!"); |
michael@0 | 677 | GR_GL_CALL(gli, DeleteShader(shaderId)); |
michael@0 | 678 | return 0; |
michael@0 | 679 | } |
michael@0 | 680 | } |
michael@0 | 681 | if (c_PrintShaders) { |
michael@0 | 682 | GrPrintf(shaderSrc.c_str()); |
michael@0 | 683 | GrPrintf("\n"); |
michael@0 | 684 | } |
michael@0 | 685 | |
michael@0 | 686 | // Attach the shader, but defer deletion until after we have linked the program. |
michael@0 | 687 | // This works around a bug in the Android emulator's GLES2 wrapper which |
michael@0 | 688 | // will immediately delete the shader object and free its memory even though it's |
michael@0 | 689 | // attached to a program, which then causes glLinkProgram to fail. |
michael@0 | 690 | GR_GL_CALL(gli, AttachShader(programId, shaderId)); |
michael@0 | 691 | |
michael@0 | 692 | return shaderId; |
michael@0 | 693 | } |
michael@0 | 694 | |
michael@0 | 695 | bool GrGLShaderBuilder::compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const { |
michael@0 | 696 | SkString fragShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo())); |
michael@0 | 697 | fragShaderSrc.append(fFSExtensions); |
michael@0 | 698 | append_default_precision_qualifier(kDefaultFragmentPrecision, |
michael@0 | 699 | fGpu->glStandard(), |
michael@0 | 700 | &fragShaderSrc); |
michael@0 | 701 | this->appendUniformDecls(kFragment_Visibility, &fragShaderSrc); |
michael@0 | 702 | this->appendDecls(fFSInputs, &fragShaderSrc); |
michael@0 | 703 | // We shouldn't have declared outputs on 1.10 |
michael@0 | 704 | SkASSERT(k110_GrGLSLGeneration != fGpu->glslGeneration() || fFSOutputs.empty()); |
michael@0 | 705 | this->appendDecls(fFSOutputs, &fragShaderSrc); |
michael@0 | 706 | fragShaderSrc.append(fFSFunctions); |
michael@0 | 707 | fragShaderSrc.append("void main() {\n"); |
michael@0 | 708 | fragShaderSrc.append(fFSCode); |
michael@0 | 709 | fragShaderSrc.append("}\n"); |
michael@0 | 710 | |
michael@0 | 711 | GrGLuint fragShaderId = attach_shader(fGpu->glContext(), programId, GR_GL_FRAGMENT_SHADER, fragShaderSrc); |
michael@0 | 712 | if (!fragShaderId) { |
michael@0 | 713 | return false; |
michael@0 | 714 | } |
michael@0 | 715 | |
michael@0 | 716 | *shaderIds->append() = fragShaderId; |
michael@0 | 717 | |
michael@0 | 718 | return true; |
michael@0 | 719 | } |
michael@0 | 720 | |
michael@0 | 721 | void GrGLShaderBuilder::bindProgramLocations(GrGLuint programId) const { |
michael@0 | 722 | if (fHasCustomColorOutput) { |
michael@0 | 723 | GL_CALL(BindFragDataLocation(programId, 0, declared_color_output_name())); |
michael@0 | 724 | } |
michael@0 | 725 | if (fHasSecondaryOutput) { |
michael@0 | 726 | GL_CALL(BindFragDataLocationIndexed(programId, 0, 1, dual_source_output_name())); |
michael@0 | 727 | } |
michael@0 | 728 | } |
michael@0 | 729 | |
michael@0 | 730 | const GrGLContextInfo& GrGLShaderBuilder::ctxInfo() const { |
michael@0 | 731 | return fGpu->ctxInfo(); |
michael@0 | 732 | } |
michael@0 | 733 | |
michael@0 | 734 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 735 | |
michael@0 | 736 | GrGLFullShaderBuilder::GrGLFullShaderBuilder(GrGpuGL* gpu, |
michael@0 | 737 | GrGLUniformManager& uniformManager, |
michael@0 | 738 | const GrGLProgramDesc& desc) |
michael@0 | 739 | : INHERITED(gpu, uniformManager, desc) |
michael@0 | 740 | , fDesc(desc) |
michael@0 | 741 | , fVSAttrs(kVarsPerBlock) |
michael@0 | 742 | , fVSOutputs(kVarsPerBlock) |
michael@0 | 743 | , fGSInputs(kVarsPerBlock) |
michael@0 | 744 | , fGSOutputs(kVarsPerBlock) { |
michael@0 | 745 | |
michael@0 | 746 | const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); |
michael@0 | 747 | |
michael@0 | 748 | fPositionVar = &fVSAttrs.push_back(); |
michael@0 | 749 | fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition"); |
michael@0 | 750 | if (-1 != header.fLocalCoordAttributeIndex) { |
michael@0 | 751 | fLocalCoordsVar = &fVSAttrs.push_back(); |
michael@0 | 752 | fLocalCoordsVar->set(kVec2f_GrSLType, |
michael@0 | 753 | GrGLShaderVar::kAttribute_TypeModifier, |
michael@0 | 754 | "aLocalCoords"); |
michael@0 | 755 | } else { |
michael@0 | 756 | fLocalCoordsVar = fPositionVar; |
michael@0 | 757 | } |
michael@0 | 758 | |
michael@0 | 759 | const char* viewMName; |
michael@0 | 760 | fViewMatrixUniform = this->addUniform(GrGLShaderBuilder::kVertex_Visibility, |
michael@0 | 761 | kMat33f_GrSLType, "ViewM", &viewMName); |
michael@0 | 762 | |
michael@0 | 763 | this->vsCodeAppendf("\tvec3 pos3 = %s * vec3(%s, 1);\n" |
michael@0 | 764 | "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n", |
michael@0 | 765 | viewMName, fPositionVar->c_str()); |
michael@0 | 766 | |
michael@0 | 767 | // we output point size in the GS if present |
michael@0 | 768 | if (header.fEmitsPointSize |
michael@0 | 769 | #if GR_GL_EXPERIMENTAL_GS |
michael@0 | 770 | && !header.fExperimentalGS |
michael@0 | 771 | #endif |
michael@0 | 772 | ) { |
michael@0 | 773 | this->vsCodeAppend("\tgl_PointSize = 1.0;\n"); |
michael@0 | 774 | } |
michael@0 | 775 | |
michael@0 | 776 | if (GrGLProgramDesc::kAttribute_ColorInput == header.fColorInput) { |
michael@0 | 777 | this->addAttribute(kVec4f_GrSLType, color_attribute_name()); |
michael@0 | 778 | const char *vsName, *fsName; |
michael@0 | 779 | this->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName); |
michael@0 | 780 | this->vsCodeAppendf("\t%s = %s;\n", vsName, color_attribute_name()); |
michael@0 | 781 | this->setInputColor(fsName); |
michael@0 | 782 | } |
michael@0 | 783 | |
michael@0 | 784 | if (GrGLProgramDesc::kAttribute_ColorInput == header.fCoverageInput) { |
michael@0 | 785 | this->addAttribute(kVec4f_GrSLType, coverage_attribute_name()); |
michael@0 | 786 | const char *vsName, *fsName; |
michael@0 | 787 | this->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName); |
michael@0 | 788 | this->vsCodeAppendf("\t%s = %s;\n", vsName, coverage_attribute_name()); |
michael@0 | 789 | this->setInputCoverage(fsName); |
michael@0 | 790 | } |
michael@0 | 791 | } |
michael@0 | 792 | |
michael@0 | 793 | bool GrGLFullShaderBuilder::addAttribute(GrSLType type, const char* name) { |
michael@0 | 794 | for (int i = 0; i < fVSAttrs.count(); ++i) { |
michael@0 | 795 | const GrGLShaderVar& attr = fVSAttrs[i]; |
michael@0 | 796 | // if attribute already added, don't add it again |
michael@0 | 797 | if (attr.getName().equals(name)) { |
michael@0 | 798 | SkASSERT(attr.getType() == type); |
michael@0 | 799 | return false; |
michael@0 | 800 | } |
michael@0 | 801 | } |
michael@0 | 802 | fVSAttrs.push_back().set(type, |
michael@0 | 803 | GrGLShaderVar::kAttribute_TypeModifier, |
michael@0 | 804 | name); |
michael@0 | 805 | return true; |
michael@0 | 806 | } |
michael@0 | 807 | |
michael@0 | 808 | bool GrGLFullShaderBuilder::addEffectAttribute(int attributeIndex, |
michael@0 | 809 | GrSLType type, |
michael@0 | 810 | const SkString& name) { |
michael@0 | 811 | if (!this->addAttribute(type, name.c_str())) { |
michael@0 | 812 | return false; |
michael@0 | 813 | } |
michael@0 | 814 | |
michael@0 | 815 | fEffectAttributes.push_back().set(attributeIndex, name); |
michael@0 | 816 | return true; |
michael@0 | 817 | } |
michael@0 | 818 | |
michael@0 | 819 | void GrGLFullShaderBuilder::addVarying(GrSLType type, |
michael@0 | 820 | const char* name, |
michael@0 | 821 | const char** vsOutName, |
michael@0 | 822 | const char** fsInName) { |
michael@0 | 823 | fVSOutputs.push_back(); |
michael@0 | 824 | fVSOutputs.back().setType(type); |
michael@0 | 825 | fVSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier); |
michael@0 | 826 | this->nameVariable(fVSOutputs.back().accessName(), 'v', name); |
michael@0 | 827 | |
michael@0 | 828 | if (vsOutName) { |
michael@0 | 829 | *vsOutName = fVSOutputs.back().getName().c_str(); |
michael@0 | 830 | } |
michael@0 | 831 | // input to FS comes either from VS or GS |
michael@0 | 832 | const SkString* fsName; |
michael@0 | 833 | #if GR_GL_EXPERIMENTAL_GS |
michael@0 | 834 | if (fDesc.getHeader().fExperimentalGS) { |
michael@0 | 835 | // if we have a GS take each varying in as an array |
michael@0 | 836 | // and output as non-array. |
michael@0 | 837 | fGSInputs.push_back(); |
michael@0 | 838 | fGSInputs.back().setType(type); |
michael@0 | 839 | fGSInputs.back().setTypeModifier(GrGLShaderVar::kVaryingIn_TypeModifier); |
michael@0 | 840 | fGSInputs.back().setUnsizedArray(); |
michael@0 | 841 | *fGSInputs.back().accessName() = fVSOutputs.back().getName(); |
michael@0 | 842 | fGSOutputs.push_back(); |
michael@0 | 843 | fGSOutputs.back().setType(type); |
michael@0 | 844 | fGSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier); |
michael@0 | 845 | this->nameVariable(fGSOutputs.back().accessName(), 'g', name); |
michael@0 | 846 | fsName = fGSOutputs.back().accessName(); |
michael@0 | 847 | } else |
michael@0 | 848 | #endif |
michael@0 | 849 | { |
michael@0 | 850 | fsName = fVSOutputs.back().accessName(); |
michael@0 | 851 | } |
michael@0 | 852 | this->fsInputAppend().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, *fsName); |
michael@0 | 853 | if (fsInName) { |
michael@0 | 854 | *fsInName = fsName->c_str(); |
michael@0 | 855 | } |
michael@0 | 856 | } |
michael@0 | 857 | |
michael@0 | 858 | const SkString* GrGLFullShaderBuilder::getEffectAttributeName(int attributeIndex) const { |
michael@0 | 859 | const AttributePair* attribEnd = fEffectAttributes.end(); |
michael@0 | 860 | for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) { |
michael@0 | 861 | if (attrib->fIndex == attributeIndex) { |
michael@0 | 862 | return &attrib->fName; |
michael@0 | 863 | } |
michael@0 | 864 | } |
michael@0 | 865 | |
michael@0 | 866 | return NULL; |
michael@0 | 867 | } |
michael@0 | 868 | |
michael@0 | 869 | GrGLProgramEffects* GrGLFullShaderBuilder::createAndEmitEffects( |
michael@0 | 870 | const GrEffectStage* effectStages[], |
michael@0 | 871 | const EffectKey effectKeys[], |
michael@0 | 872 | int effectCnt, |
michael@0 | 873 | GrGLSLExpr4* inOutFSColor) { |
michael@0 | 874 | |
michael@0 | 875 | GrGLVertexProgramEffectsBuilder programEffectsBuilder(this, effectCnt); |
michael@0 | 876 | this->INHERITED::createAndEmitEffects(&programEffectsBuilder, |
michael@0 | 877 | effectStages, |
michael@0 | 878 | effectKeys, |
michael@0 | 879 | effectCnt, |
michael@0 | 880 | inOutFSColor); |
michael@0 | 881 | return programEffectsBuilder.finish(); |
michael@0 | 882 | } |
michael@0 | 883 | |
michael@0 | 884 | bool GrGLFullShaderBuilder::compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const { |
michael@0 | 885 | const GrGLContext& glCtx = this->gpu()->glContext(); |
michael@0 | 886 | SkString vertShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo())); |
michael@0 | 887 | this->appendUniformDecls(kVertex_Visibility, &vertShaderSrc); |
michael@0 | 888 | this->appendDecls(fVSAttrs, &vertShaderSrc); |
michael@0 | 889 | this->appendDecls(fVSOutputs, &vertShaderSrc); |
michael@0 | 890 | vertShaderSrc.append("void main() {\n"); |
michael@0 | 891 | vertShaderSrc.append(fVSCode); |
michael@0 | 892 | vertShaderSrc.append("}\n"); |
michael@0 | 893 | GrGLuint vertShaderId = attach_shader(glCtx, programId, GR_GL_VERTEX_SHADER, vertShaderSrc); |
michael@0 | 894 | if (!vertShaderId) { |
michael@0 | 895 | return false; |
michael@0 | 896 | } |
michael@0 | 897 | *shaderIds->append() = vertShaderId; |
michael@0 | 898 | |
michael@0 | 899 | #if GR_GL_EXPERIMENTAL_GS |
michael@0 | 900 | if (fDesc.getHeader().fExperimentalGS) { |
michael@0 | 901 | SkASSERT(this->ctxInfo().glslGeneration() >= k150_GrGLSLGeneration); |
michael@0 | 902 | SkString geomShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo())); |
michael@0 | 903 | geomShaderSrc.append("layout(triangles) in;\n" |
michael@0 | 904 | "layout(triangle_strip, max_vertices = 6) out;\n"); |
michael@0 | 905 | this->appendDecls(fGSInputs, &geomShaderSrc); |
michael@0 | 906 | this->appendDecls(fGSOutputs, &geomShaderSrc); |
michael@0 | 907 | geomShaderSrc.append("void main() {\n"); |
michael@0 | 908 | geomShaderSrc.append("\tfor (int i = 0; i < 3; ++i) {\n" |
michael@0 | 909 | "\t\tgl_Position = gl_in[i].gl_Position;\n"); |
michael@0 | 910 | if (fDesc.getHeader().fEmitsPointSize) { |
michael@0 | 911 | geomShaderSrc.append("\t\tgl_PointSize = 1.0;\n"); |
michael@0 | 912 | } |
michael@0 | 913 | SkASSERT(fGSInputs.count() == fGSOutputs.count()); |
michael@0 | 914 | for (int i = 0; i < fGSInputs.count(); ++i) { |
michael@0 | 915 | geomShaderSrc.appendf("\t\t%s = %s[i];\n", |
michael@0 | 916 | fGSOutputs[i].getName().c_str(), |
michael@0 | 917 | fGSInputs[i].getName().c_str()); |
michael@0 | 918 | } |
michael@0 | 919 | geomShaderSrc.append("\t\tEmitVertex();\n" |
michael@0 | 920 | "\t}\n" |
michael@0 | 921 | "\tEndPrimitive();\n"); |
michael@0 | 922 | geomShaderSrc.append("}\n"); |
michael@0 | 923 | GrGLuint geomShaderId = attach_shader(glCtx, programId, GR_GL_GEOMETRY_SHADER, geomShaderSrc); |
michael@0 | 924 | if (!geomShaderId) { |
michael@0 | 925 | return false; |
michael@0 | 926 | } |
michael@0 | 927 | *shaderIds->append() = geomShaderId; |
michael@0 | 928 | } |
michael@0 | 929 | #endif |
michael@0 | 930 | |
michael@0 | 931 | return this->INHERITED::compileAndAttachShaders(programId, shaderIds); |
michael@0 | 932 | } |
michael@0 | 933 | |
michael@0 | 934 | void GrGLFullShaderBuilder::bindProgramLocations(GrGLuint programId) const { |
michael@0 | 935 | this->INHERITED::bindProgramLocations(programId); |
michael@0 | 936 | |
michael@0 | 937 | const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); |
michael@0 | 938 | |
michael@0 | 939 | // Bind the attrib locations to same values for all shaders |
michael@0 | 940 | SkASSERT(-1 != header.fPositionAttributeIndex); |
michael@0 | 941 | GL_CALL(BindAttribLocation(programId, |
michael@0 | 942 | header.fPositionAttributeIndex, |
michael@0 | 943 | fPositionVar->c_str())); |
michael@0 | 944 | if (-1 != header.fLocalCoordAttributeIndex) { |
michael@0 | 945 | GL_CALL(BindAttribLocation(programId, |
michael@0 | 946 | header.fLocalCoordAttributeIndex, |
michael@0 | 947 | fLocalCoordsVar->c_str())); |
michael@0 | 948 | } |
michael@0 | 949 | if (-1 != header.fColorAttributeIndex) { |
michael@0 | 950 | GL_CALL(BindAttribLocation(programId, |
michael@0 | 951 | header.fColorAttributeIndex, |
michael@0 | 952 | color_attribute_name())); |
michael@0 | 953 | } |
michael@0 | 954 | if (-1 != header.fCoverageAttributeIndex) { |
michael@0 | 955 | GL_CALL(BindAttribLocation(programId, |
michael@0 | 956 | header.fCoverageAttributeIndex, |
michael@0 | 957 | coverage_attribute_name())); |
michael@0 | 958 | } |
michael@0 | 959 | |
michael@0 | 960 | const AttributePair* attribEnd = fEffectAttributes.end(); |
michael@0 | 961 | for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) { |
michael@0 | 962 | GL_CALL(BindAttribLocation(programId, attrib->fIndex, attrib->fName.c_str())); |
michael@0 | 963 | } |
michael@0 | 964 | } |
michael@0 | 965 | |
michael@0 | 966 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 967 | |
michael@0 | 968 | GrGLFragmentOnlyShaderBuilder::GrGLFragmentOnlyShaderBuilder(GrGpuGL* gpu, |
michael@0 | 969 | GrGLUniformManager& uniformManager, |
michael@0 | 970 | const GrGLProgramDesc& desc) |
michael@0 | 971 | : INHERITED(gpu, uniformManager, desc) |
michael@0 | 972 | , fNumTexCoordSets(0) { |
michael@0 | 973 | |
michael@0 | 974 | SkASSERT(!desc.getHeader().fHasVertexCode); |
michael@0 | 975 | SkASSERT(gpu->glCaps().fixedFunctionSupport()); |
michael@0 | 976 | SkASSERT(gpu->glCaps().pathRenderingSupport()); |
michael@0 | 977 | SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorInput); |
michael@0 | 978 | SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverageInput); |
michael@0 | 979 | } |
michael@0 | 980 | |
michael@0 | 981 | int GrGLFragmentOnlyShaderBuilder::addTexCoordSets(int count) { |
michael@0 | 982 | int firstFreeCoordSet = fNumTexCoordSets; |
michael@0 | 983 | fNumTexCoordSets += count; |
michael@0 | 984 | SkASSERT(gpu()->glCaps().maxFixedFunctionTextureCoords() >= fNumTexCoordSets); |
michael@0 | 985 | return firstFreeCoordSet; |
michael@0 | 986 | } |
michael@0 | 987 | |
michael@0 | 988 | GrGLProgramEffects* GrGLFragmentOnlyShaderBuilder::createAndEmitEffects( |
michael@0 | 989 | const GrEffectStage* effectStages[], |
michael@0 | 990 | const EffectKey effectKeys[], |
michael@0 | 991 | int effectCnt, |
michael@0 | 992 | GrGLSLExpr4* inOutFSColor) { |
michael@0 | 993 | |
michael@0 | 994 | GrGLTexGenProgramEffectsBuilder texGenEffectsBuilder(this, effectCnt); |
michael@0 | 995 | this->INHERITED::createAndEmitEffects(&texGenEffectsBuilder, |
michael@0 | 996 | effectStages, |
michael@0 | 997 | effectKeys, |
michael@0 | 998 | effectCnt, |
michael@0 | 999 | inOutFSColor); |
michael@0 | 1000 | return texGenEffectsBuilder.finish(); |
michael@0 | 1001 | } |